Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To add a dynamic sidebar, register a named widget area on the widgets_init hook, render it with dynamic_sidebar(), and load the matching sidebar template with get_sidebar(). Check is_active_sidebar() before outputting layout markup so an unused area does not leave an empty column.

This implementation applies to classic WordPress themes. Block themes use the Site Editor and block-based template parts instead of this PHP sidebar workflow.

How the classic-theme sidebar flow works

A widget-ready sidebar has three parts:

  1. Registration: the theme declares a widget area and gives it a stable ID, admin-facing name, description, and wrapper markup.
  2. Rendering: a sidebar template calls dynamic_sidebar() with that ID.
  3. Inclusion: the page template calls get_sidebar() to load the sidebar file.

After registration, the area appears in the WordPress Widgets administration screen, where an administrator can assign available widgets. The official overview is in the WordPress Theme Handbook’s Sidebars documentation.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

1. Register a sidebar in functions.php

Add the registration to your theme’s setup code, normally in functions.php, and hook it to widgets_init. Use a descriptive name that tells site owners where the area appears, rather than labels such as “Sidebar 1.”

<?php
function mytheme_widgets_init() {
    register_sidebar(
        array(
            'name'          => __( 'Primary Sidebar', 'mytheme' ),
            'id'            => 'primary',
            'description'   => __( 'Widgets shown beside the main content.', 'mytheme' ),
            'before_widget' => '<aside id="%1$s" class="widget %2$s">',
            'after_widget'  => '</aside>',
            'before_title'  => '<h2 class="widget-title">',
            'after_title'   => '</h2>',
        )
    );
}
add_action( 'widgets_init', 'mytheme_widgets_init' );

Why the ID must be explicit

primary is the internal identifier used by the theme. Keep it lowercase, stable, and unchanged after the area is in use. If you omit the ID, WordPress can generate one from an incrementing value; the register_sidebar() reference warns that this generated value can change when themes or plugins add or remove registered areas. Changing an ID can make existing assignments appear to disappear from the expected location.

What the wrapper arguments do

  • before_widget and after_widget surround every widget.
  • before_title and after_title surround a widget title when that widget outputs one.
  • %1$s must remain in the widget wrapper’s id attribute, and %2$s must remain in its class attribute. WordPress substitutes widget-specific values, allowing CSS and plugins to target each instance.

Choose elements and classes that match your theme’s semantic structure and stylesheet. The Widgets section of the Theme Handbook explains how registration controls this markup.

2. Create the sidebar template

Create sidebar-primary.php in the theme directory. The suffix after sidebar- matches the argument passed to get_sidebar().

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php if ( is_active_sidebar( 'primary' ) ) : ?>
    <aside class="primary-sidebar">
        <?php dynamic_sidebar( 'primary' ); ?>
    </aside>
<?php endif; ?>

Why check whether it is active

is_active_sidebar( 'primary' ) checks whether widgets are assigned to the registered area. The conditional prevents an empty <aside> or grid column from creating unwanted whitespace or changing the page structure.

dynamic_sidebar() accepts a sidebar ID, name, or numeric index, but an explicit ID is clearer and remains tied to the intended area. Its documented return value indicates whether a registered sidebar was found and called; see the dynamic_sidebar() reference.

Choosing an empty state

The example omits the entire wrapper when no widgets are assigned. That is usually best for optional side columns. If your design requires a permanent panel, replace the conditional with deliberate fallback content—such as a navigation prompt or a default call to action—instead of leaving an unexplained blank region.

3. Include the sidebar where it belongs

In the template that controls the page layout—often single.php, page.php, or an appropriate archive template—call:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php get_sidebar( 'primary' ); ?>

WordPress looks for sidebar-primary.php. Calling get_sidebar() without an argument instead looks for the general sidebar.php template. The Theme Handbook’s partial and miscellaneous template-file guidance documents this naming convention and active-area pattern.

Place the call inside the layout

Put the call next to the main content in the markup that defines your columns. For example, the main template can contain a content element followed by get_sidebar( 'primary' ); your CSS then controls the two-column layout. Because the sidebar template suppresses its wrapper when inactive, the layout should also define how the content column expands when no sidebar is present.

4. Assign and verify widgets

  1. Open the WordPress admin area and go to Appearance → Widgets.
  2. Find Primary Sidebar, the name supplied during registration.
  3. Add one or more widgets and configure their titles and settings.
  4. Visit a front-end page that includes get_sidebar( 'primary' ).
  5. Inspect the generated HTML if styling is wrong: each widget should use the registered wrapper, including its substituted widget ID and class.

If the area does not appear in Widgets, check that the registration function is loaded, the widgets_init hook is spelled correctly, and the theme is active. If widgets are assigned but nothing renders, verify that the ID is exactly primary in registration, is_active_sidebar(), and dynamic_sidebar().

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Registering one area or several

Use separate register_sidebar() calls when each location needs its own descriptive name, markup, or behavior.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Approach Best use Trade-off
register_sidebar() Distinct areas such as Primary Sidebar, Footer Widgets, or Header Widgets More code, but each area has clear settings and an independent stable ID
register_sidebars() Repeated areas with the same general configuration Less repetitive registration, but automatically numbered areas are less descriptive unless you provide suitable naming and IDs

WordPress documents both APIs in the classic-theme sidebar guidance. Whichever approach you choose, keep IDs consistent with the templates that render them.

Optional registration settings

Customizer selective refresh

If the theme supports Customizer selective refresh for widgets, add add_theme_support( 'customize-selective-refresh-widgets' ) during theme setup. The widget wrapper must retain the widget ID placeholder so WordPress can refresh that instance without reloading the whole preview. The Theme Handbook’s selective-refresh documentation describes this requirement and the default wrapper pattern.

REST visibility

register_sidebar() also accepts show_in_rest. Its default is limited to administrator users, and the function reference records that the argument was added in WordPress 5.9.0. Set it only when your theme’s integration needs REST exposure, and choose the visibility deliberately. The same reference documents before_sidebar and after_sidebar, added in WordPress 5.6.0: register_sidebar() arguments and changelog.

Common mistakes and fixes

  • Using different IDs: primary-sidebar and primary are different areas. Copy the same explicit ID everywhere.
  • Dropping %1$s or %2$s: this removes WordPress’s per-widget identifiers and can break styling or selective refresh.
  • Always printing the outer column: wrap it in is_active_sidebar() unless an intentional fallback is present.
  • Calling the wrong template: get_sidebar( 'primary' ) loads sidebar-primary.php; it does not load an arbitrarily named file.
  • Registering too late or not at all: registration belongs on widgets_init, not inside a template that may run after widgets are initialized.
  • Changing an ID after launch: existing widget assignments are associated with the old ID; preserve it or plan a deliberate migration.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.