2026年11月13日

2026年11月13日

WordPress Sidebar Not Showing: Causes and Fixes (register_sidebar, dynamic_sidebar)

This article is a localized edition of the Japanese original. Read the Japanese original

Problems like "the sidebar does not show", "I added widgets but nothing appears" or "the widget area is missing from the Widgets screen" in WordPress usually come down to a mismatch somewhere between registering the widget area (sidebar), calling it, and placing widgets in it.

This article explains how to narrow down the cause and the code for registering and displaying sidebars correctly in a theme. The behavior of the functions was checked against the WordPress 6.9 source and the developer.wordpress.org reference (as of October 2026).

First: check what kind of theme you use

Block themes such as Twenty Twenty-Four and Twenty Twenty-Five do not use widget areas registered with register_sidebar(); their sidebars are template parts built in the Site Editor. In a theme that registers no widget areas, the "Widgets" item does not appear under "Appearance" in the admin at all.

  • "Appearance" has "Editor" but no "Widgets" → it is a block theme. Add a sidebar by editing templates under "Appearance" → "Editor". The steps below do not apply.
  • "Appearance" has "Widgets" → it is a classic theme (or a theme that registers widget areas). Check with the steps below.

Symptoms and causes

Symptom Main cause
The widget area you expect is missing from the Widgets screen register_sidebar() is not running (wrong hook name, inside a conditional, written in another theme's functions.php)
Widgets are placed but not displayed The ID passed to dynamic_sidebar() in the template does not match the id used at registration
The whole sidebar block is missing The template does not call get_sidebar(), there is no sidebar.php, or is_active_sidebar() is false
Widgets disappeared after switching themes The new theme's areas have different IDs, so the widgets are not assigned to any area

Check the state with WP-CLI

If you can use WP-CLI, you can list the registered areas and the widgets placed in them.

# registered widget areas (name, id, description)
wp sidebar list

# widgets placed in an area (main-sidebar is the ID of the area to check)
wp widget list main-sidebar

# whether the area contains widgets (true / false)
wp eval 'var_dump( is_active_sidebar( "main-sidebar" ) );'

# whether the theme has sidebar.php (prints the path if it exists)
wp eval 'echo locate_template( "sidebar.php" ), PHP_EOL;'

If the area is missing from wp sidebar list, it is a registration problem; if the area exists but wp widget list is empty, no widgets are placed; if widgets exist but are not displayed, the problem is in how the template calls the sidebar.

Register the sidebar

Register widget areas with register_sidebar() in your theme's functions.php. As in the reference examples, the standard approach is to call it inside the widgets_init action.

<?php
// functions.php
add_action( 'widgets_init', 'my_theme_register_sidebars' );

function my_theme_register_sidebars() {
	register_sidebar( array(
		'name'          => 'Main Sidebar',
		'id'            => 'main-sidebar', // must match the ID passed to dynamic_sidebar()
		'description'   => 'Shown on the right of posts and pages.',
		'before_widget' => '<section id="%1$s" class="widget %2$s">',
		'after_widget'  => '</section>',
		'before_title'  => '<h2 class="widget-title">',
		'after_title'   => '</h2>',
	) );

	register_sidebar( array(
		'name'          => 'Shop Sidebar',
		'id'            => 'shop-sidebar',
		'description'   => 'For WooCommerce shop pages.',
		'before_widget' => '<div id="%1$s" class="widget %2$s">',
		'after_widget'  => '</div>',
		'before_title'  => '<h3 class="widget-title">',
		'after_title'   => '</h3>',
	) );
}

Points to keep in mind when registering:

  • Calling register_sidebar() directly at the top level of functions.php still registers the area (it runs before widgets_init, so it is not "too late"). However, widgets_init is the hook provided for running widget-related setup together, so it is the safer place.
  • If you register inside a template file (such as sidebar.php), that file is not loaded in the admin, so the area does not appear on the Widgets screen.
  • If you omit id, it becomes a sequential ID like sidebar-1, and since WordPress 4.2 a notice asks you to set the ID. If the numbering shifts when areas are added or removed, widget assignments break, so always set id explicitly, using lowercase letters, digits and hyphens with no spaces.
  • Calling register_sidebar() automatically registers theme support for widgets, which makes the "Widgets" item appear under "Appearance".

Display the sidebar in templates

Registering alone does not display anything. Call get_sidebar() in the theme's templates, and call dynamic_sidebar() inside sidebar.php.

sidebar.php is a file in the theme folder like this:

<?php
/**
 * sidebar.php
 */
if ( ! is_active_sidebar( 'main-sidebar' ) ) {
	return; // output nothing if there are no widgets
}
?>
<aside id="secondary" class="widget-area">
	<?php dynamic_sidebar( 'main-sidebar' ); ?>
</aside>

Call it like this from the templates that should show the sidebar, such as single.php or page.php:

<?php
get_sidebar();         // loads sidebar.php
get_sidebar( 'shop' ); // loads sidebar-shop.php (or sidebar.php if it does not exist)

get_sidebar( 'shop' ) looks for sidebar-shop.php, then sidebar.php, and if neither exists it loads nothing and returns false. No error is shown, so check the spelling of the file name.

When you add comments around HTML, do not write PHP comments (//) outside <?php ?>. Text outside PHP tags is output to the page as is, which makes a string starting with // appear above the sidebar.

Switch sidebars by page

To use a different area depending on the type of page, add a function that returns the ID and use it from sidebar.php.

<?php
// functions.php
function my_theme_sidebar_id() {
	if ( function_exists( 'is_woocommerce' ) && is_woocommerce() ) {
		return 'shop-sidebar';
	}
	return 'main-sidebar';
}
<?php
/**
 * sidebar.php (when switching)
 */
$sidebar_id = my_theme_sidebar_id();
if ( ! is_active_sidebar( $sidebar_id ) ) {
	return;
}
?>
<aside id="secondary" class="widget-area">
	<?php dynamic_sidebar( $sidebar_id ); ?>
</aside>

is_woocommerce() only exists when WooCommerce is active, so check with function_exists() before calling it.

Create a custom widget

Build your own widget by extending WP_Widget, and pass it to register_widget() on widgets_init.

<?php
// functions.php
class My_Recent_Posts_Widget extends WP_Widget {

	public function __construct() {
		parent::__construct(
			'my_recent_posts',
			'Recent Posts (Custom)',
			array( 'description' => 'Recent posts list with a configurable count' )
		);
	}

	// like the parent class, do not add types to the parameters
	public function widget( $args, $instance ) {
		$title = ! empty( $instance['title'] ) ? $instance['title'] : 'Recent Posts';
		$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
		$count = ! empty( $instance['count'] ) ? absint( $instance['count'] ) : 5;

		$posts = get_posts( array(
			'numberposts' => $count,
			'post_status' => 'publish',
		) );

		echo $args['before_widget'];
		if ( $title ) {
			echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
		}
		if ( $posts ) {
			echo '<ul>';
			foreach ( $posts as $p ) {
				printf(
					'<li><a href="%s">%s</a></li>',
					esc_url( get_permalink( $p ) ),
					esc_html( get_the_title( $p ) )
				);
			}
			echo '</ul>';
		}
		echo $args['after_widget'];
	}

	// settings form in the admin
	public function form( $instance ) {
		$title = isset( $instance['title'] ) ? $instance['title'] : '';
		$count = isset( $instance['count'] ) ? absint( $instance['count'] ) : 5;
		?>
		<p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">Title:</label>
			<input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>">
		</p>
		<p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>">Number of posts:</label>
			<input class="tiny-text" id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>" type="number" min="1" max="20" value="<?php echo esc_attr( $count ); ?>">
		</p>
		<?php
		return '';
	}

	// clean up values on save
	public function update( $new_instance, $old_instance ) {
		return array(
			'title' => sanitize_text_field( $new_instance['title'] ?? '' ),
			'count' => max( 1, min( 20, absint( $new_instance['count'] ?? 5 ) ) ),
		);
	}
}

add_action( 'widgets_init', function () {
	register_widget( 'My_Recent_Posts_Widget' );
} );

widget(), form() and update() in WP_Widget are defined in the parent class without parameter types. If you add types to the parameters in the child class, as in widget( array $args, array $instance ), PHP 8 throws a fatal error saying the method is not compatible with the parent, and the site stops loading. Without form(), the widget's settings panel only shows a note that there are no options, and you cannot enter a title or count.

Widgets when you switch themes

Widget placement is saved in the sidebars_widgets option, per area ID. When you switch themes, WordPress tries to move widgets to areas with the same ID or a similar role, but widgets it cannot move end up assigned to no area and stop showing (the widgets themselves are not deleted and can be placed again from the Widgets screen).

When you rebuild your own theme, registering the areas with the same id as before keeps the placement as is. Saving the placement before switching themes makes it easier to restore.

# save the widget placement to a file
wp option get sidebars_widgets --format=json > sidebars_widgets_backup.json

If the block widget editor does not suit you

Since WordPress 5.8, the Widgets screen of classic themes also uses the block editor. To use the old widget settings screen, activate the official Classic Widgets plugin, or disable it in your theme like this:

<?php
// functions.php
add_action( 'after_setup_theme', function () {
	remove_theme_support( 'widgets-block-editor' );
} );

Summary

  • Block themes have no Widgets screen. Build sidebars in the Site Editor.
  • Use wp sidebar list and wp widget list to separate registration problems from widget placement problems.
  • Call register_sidebar() on widgets_init, set id explicitly, and use the same value in dynamic_sidebar().
  • Use get_sidebar() in templates, and is_active_sidebar() with dynamic_sidebar() in sidebar.php. Do not write PHP comments outside PHP tags.
  • Do not add parameter types to custom widget methods, and implement form() and update() too.

Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)

お気軽にご相談ください

お見積りへ お問い合わせへ
▲