Sidebar Generator

Register widget areas with register_sidebar() and generate the template call, including the wrapper markup and the guard for an empty area.

Live output

Enable JavaScript to customise; default output below.

Widget areas

Each area is a drop zone in the Widgets screen. The ID is what your template asks for.

Live preview sidebars.php
<?php
/**
 * Widget areas for the theme.
 */

/**
 * Registers the widget areas.
 *
 * The markup here is what wraps every widget dropped into the area, so it is
 * worth getting right once rather than fighting it in CSS later.
 */
function my_theme_register_sidebars() {
	register_sidebar(
		array(
			'id'            => 'sidebar-1',
			'name'          => __( 'Main Sidebar', 'my-theme' ),
			'description'   => __( 'Shown beside posts and pages.', 'my-theme' ),
			'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(
			'id'            => 'footer-1',
			'name'          => __( 'Footer Column One', 'my-theme' ),
			'before_widget' => '<section id="%1$s" class="widget %2$s">',
			'after_widget'  => '</section>',
			'before_title'  => '<h2 class="widget-title">',
			'after_title'   => '</h2>',
		)
	);
}
add_action( 'widgets_init', 'my_theme_register_sidebars' );

/*
 * Output. Put this in sidebar.php, or wherever the column belongs.
 */
if ( is_active_sidebar( 'sidebar-1' ) ) {
	echo '<div class="' . esc_attr( 'sidebar widget-area' ) . '">';

	dynamic_sidebar( 'sidebar-1' );

	echo '</div>';
}

Output is valid and updates as you type.

Name the widget areas your theme offers, decide the markup that wraps each widget, and the generator writes the registration and the template call that skips an empty area.

How to use

  1. Add one area per drop zone. Three footer columns is three areas, not one area you style into columns.
  2. Keep the IDs stable. Widgets are stored against the area ID, so renaming it strands everything an editor already placed there.
  3. Set the wrapper and title tag to fit the page outline. Every widget title at h2 on a page that already has an h2 is a heading order problem.
  4. Leave the empty check on. is_active_sidebar() keeps an empty column from leaving a gap in the layout.
  5. Put the registration in functions.php and the output in the template that shows the column.

Example

One area and the output that goes with it:

function acme_register_sidebars() {
	register_sidebar(
		array(
			'id'            => 'sidebar-1',
			'name'          => __( 'Main Sidebar', 'acme' ),
			'description'   => __( 'Shown beside posts and pages.', 'acme' ),
			'before_widget' => '<section id="%1$s" class="widget %2$s">',
			'after_widget'  => '</section>',
			'before_title'  => '<h2 class="widget-title">',
			'after_title'   => '</h2>',
		)
	);
}
add_action( 'widgets_init', 'acme_register_sidebars' );

if ( is_active_sidebar( 'sidebar-1' ) ) {
	echo '<div class="' . esc_attr( 'sidebar widget-area' ) . '">';

	dynamic_sidebar( 'sidebar-1' );

	echo '</div>';
}

%1$s and %2$s are filled in by WordPress with the widget ID and its classes. Dropping them breaks widget specific styling and any plugin that targets it.

Pitfalls

  • register_sidebar() belongs on widgets_init. On any other hook the area may not exist when the Widgets screen is built.
  • Leaving out the id makes WordPress generate one such as sidebar-1, which changes as areas are added and moves everyone’s widgets.
  • before_widget without %1$s and %2$s strips the per widget ID and classes. Themes that do this are the reason widget CSS often does not work.
  • dynamic_sidebar() prints nothing for an empty area, but your wrapper markup still prints. That is the gap is_active_sidebar() exists to prevent.
  • Unbalanced tags between before_widget and after_widget break the page layout for every widget at once.
  • Widget areas are stored per theme. Switching themes and back can leave widgets in the Inactive box.
  • In a block theme the Widgets screen is replaced by template parts, so a registered sidebar may never be seen.
  • A title tag chosen for looks rather than for the outline is an accessibility problem that CSS cannot fix.

Compatibility

register_sidebar(), dynamic_sidebar() and is_active_sidebar() have been stable since WordPress 2.2, and the block based Widgets screen arrived in 5.8 without changing them. Block themes use template parts instead of widget areas. The generated code targets PHP 7.0 and up, and the tool runs entirely in your browser.

Frequently asked questions

Why is my sidebar empty on the front end?
Either no widgets are assigned to that ID, or the ID in dynamic_sidebar() does not match the registered one. Both fail silently.
What are %1$s and %2$s for?
WordPress replaces them with the widget’s ID and its classes. Keep them in before_widget or per widget styling stops working.
Do widget areas work in a block theme?
Registered areas still exist, but a block theme shows template parts in place of the Widgets screen, so editors may never find them.
Can I have several footer columns?
Register one area per column. That is what lets an editor fill two and leave the third empty.
How do I remove a default sidebar from a parent theme?
unregister_sidebar() on widgets_init with a later priority than the parent’s registration.

From the people who built this tool

WP Adminify

The WordPress admin, rebuilt: a dashboard worth looking at, menu and column control, a real file manager and the login page your client sees.

See WP Adminify Free version on WordPress.org

Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.