How to create unique widget areas for individual posts in WordPress

Here’s a cool little trick for adding widget areas that are unique to posts, but without cluttering up Appearance->Widgets in the admin. Instead, we utilize the Customizer, which is perfect for this sort of thing.

First thing, we need to hook a function into init where we register our widget area.

PHP

1

2

3

4

5

add_action('init','my_namespaced_widgets_area');

functionmy_namespaced_widgets_area(){

// Our code goes here.

}

We are using init rather than widgets_init here because widgets_init fires in too high of a priority I found for this to work, and init is just fine for our needs. Anyway, let’s start writing this function.

PHP

1

2

3

4

5

6

7

8

9

10

functionmy_namespaced_widgets_area(){

if(!isset($_GET['url'])){

$url=home_url($_SERVER['REQUEST_URI']);

}else{

$url=$_GET['url'];

}

if($post_id=url_to_postid(esc_url_raw($url))){

// More to come...

}

}

So this first bit of the function either grabs the query string stored in $_GET['url'], or the URL itself. The former we use for registering the widget area with the customizer, as the URL of the post is passed as a query string; the latter we use for the actual post itself. The reason we are using the URL is because we are very early in the page load, and are limited in ways of obtaining the $post_id or $post.

Now some of you might notice I’m using url_to_postid() function to obtain the $post_id. If you’re on a small site, this is probably fine. However, url_to_postid() is an uncached function and should be avoided if you are working on a larger site where performance could be greatly effected. If you have access to WordPress.com functions, you can use wpcom_vip_url_to_postid() to do the same thing (but cached), or you can find another clever way to get the $post_id (or the $post), as this is the objective.

Now that we have the $post, we have everything we need to register our widget area. This is the complete code that you can place into functions.php.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

add_action('init','my_namespaced_widgets_area');

functionmy_namespaced_widgets_area(){

if(!isset($_GET['url'])){

$url=home_url($_SERVER['REQUEST_URI']);

}else{

$url=$_GET['url'];

}

if($post_id=url_to_postid(esc_url_raw($url))){

$post=get_post($post_id);

if($post){

register_sidebar(array(

'name'=>$post->post_title,

'id'=>$post->post_name.'-widget-area',

'description'=>$post->post_title.' widget area',

'before_widget'=>'<li id="%1$s" class="widget %2$s">',

'after_widget'=>'</li>',

'before_title'=>'<h2 class="widgettitle">',

'after_title'=>'</h2>'

);

}

}

}

Here we are using the post_title and post_name from the $post object. We use post_title for the “nice name” of naming the widget area and the post_name for the widget area’s ID. This now registers this widget area on both the customizer view and the single post view.

One last thing before we move on, you can add an && to the if ( $post ) statement and also check $post->post_type if you only want to register your widget area on a particular post type (post, page, or a custom post type).

Now that our widget area is registered, we need to add it to a template to render. So within single.php or the like, you can add in your new widget area like so:

PHP

1

2

3

4

$widget_area=$post->post_name.'-widget-area';

if(is_active_sidebar($widget_area)){

dynamic_sidebar($widget_area);

}

From the URL of the post, we registered a widget area specifically for this post. Now, if you are logged in, click on “Customize” in the admin bar. Under “Widgets,” you should see your widget area made specifically for this post, and you can now add some widgets to it.

Another cool thing you can do is have a global fallback widget area. To do that, let’s say we register a widget area called sidebar-2 globally. We can then use is_active_sidebar with an added else:

PHP

1

2

3

4

5

6

$widget_area=$post->post_name.'-widget-area';

if(is_active_sidebar($widget_area)){

dynamic_sidebar($widget_area);

}else{

dynamic_sidebar('sidebar-2');

}

Now if we have added widgets to this post, they will display. If we haven’t, the widgets in sidebar-2 will display.

Hope you found this post useful. Please let me know in the comments if you have any feedback or interesting ways to improve this code.