WordPress Tutorial : A unique dynamic sidebar for each page - or not!

The last few websites I've built have had sidebars that the client *may* or *may not* need to customize on every page. Some pages don't require a unique sidebar, some do. The client should have the option of a cascading sidebar.

Let's say you have a Blog, an "About" section, and your homepage. In the "About" section, you have the obligatory "About" and "Management Team" pages, and under that you'd like a bio for contacting each of your team members. You would like one sidebar throughout that section with your social widgets and Twitter feeds, but on the "Management Team" page you'd like a contact form instead. On the bio pages, you'd like to include direct contact information for certain members and their personal social links, instead of the generic contact form. The members who do not wish to provide contact information would like to default to the generic contact form.

Your page hierarchy might look something like this:

To create a dynamic sidebar for each of these pages with content that cascades 3 levels deep into the page hierarchy, we will simply loop through the pages in a query and register a sidebar for each page or content type that we pull. This is a simple example, set up for pages that have been published (not drafts) but it can be customized for custom post types or any other content that you can loop through. Remember that there will be a sidebar box added to your Widget Admin for every content that you pull; if you have 200 unique pages this might not be the right approach.

Add this to your functions.php file:

  if (function_exists('register_sidebar')){
    register_sidebar(array('name'=>'Single Post Sidebar',
      'id' => 'sidebar-single',
      'before_widget' => '<div id="%1$s" class="widget-area %2$s">',
      'after_widget' => '</div>',
      'before_title' => '<h3>',
      'after_title' => '</h3>'
    ));
 
    // Dynamic Widgets
    $myPages = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'page' AND post_status = 'publish'"); 
 
    foreach ($myPages as $q ){
      $id = 'sidebar-'.$q->ID;
      $namePref = "Parent - ";
      if ($q->post_parent != 0){ 
        $namePref = "Child - ";
      } 
      $sbtitle = $namePref . $q->post_title;
      if ($sbtitle && function_exists('register_sidebar')){
        register_sidebar(array(
          'id' => $id, 
          'name'          => $sbtitle ,
          'before_widget' => '<div id="%1$s" class="widget-area %2$s">', 
          'after_widget' => '</div>', 
          'before_title' => '<h3>', 
          'after_title' => '</h3>'
        ));
      }
    }
  }

Ta-da, all your sidebars should be appearing in the Admin > Appearance > Widgets view, with titles that make it obvious which sidebars are for Parent pages, and which are for Child pages and can safely be ignored, as they inherit content.

To make them appear on the website we need to do some work to sidebar.php. This code has conditionals for the blog single, the main blog page and the page view.

  1. If it's a single post it sets the $sid var for the static sidebar we configured.
  2. If it's a page it checks for a sidebar for that page specifically, then for the parent page, and then for the parent or the parent's parent page if the previous are not found.
  3. If it's the blog page it sets the $sid var for the blog sidebar id. Since the $post array is full of the blog posts and no longer referencing the Blog page, we will get the ID for this page by calling get_option('page_for_posts').

Then it displays the sidebar using the $sid var.

<?php 
  $sid = "";
  $pref = "sidebar-";
 
  if (is_single()){
    // sidebar explicitly defined for single blog post
    $sid = "sidebar-single"; 
  } elseif (is_page()){
    if ($post->post_parent == 0 || is_active_sidebar('sidebar-'.$post->ID)){
      // no parent to inherit, or not necessary because the sidebar has been set
      $sid = $pref.$post->ID;
    } else {
      if (is_active_sidebar('sidebar-'.$post->post_parent)){
        // parent exists and has a sidebar
        $sid = $pref.$post->post_parent;
      } else {
        // parent doesn't exist, check all for sidebars
        foreach (get_post_ancestors($post) as $ancestor => $id){
          if (is_active_sidebar($pref.$id)){
            $sid = $pref.$id;
            break;
          }
        }
      }
    }
  } elseif (is_home()){
     // sidebar for blog list page
    $sid = $pref.get_option('page_for_posts');
  }
?>
 
  <?php if (!empty($sid) && function_exists('is_dynamic_sidebar') && is_active_sidebar($sid)){ ?>
    <div id="sidebar">  
      <?php if (!function_exists('dynamic_sidebar') || !dynamic_sidebar($sid)): ?><?php endif; ?>
    </div>
  <?php } ?>

Calling get_sidebar() from your template files will display whichever sidebar content is available, 3 levels deep. New sidebars are created whenever new pages are created and inherit their parent page's content unless they are otherwise overridden. You might also define a generic sidebar to use in case the topmost page's sidebar hasn't been customized, for completely foolproof publishing.

Comments

In PHP, I have coded dynamic bar through loop and if block but after reading this blog tutorial, now i can do code easily through using your get_sidebar() function.

I'm using dynamic sidebars for the first time, but it seems that the first sidebar, when I ad specific category post links, automatically change the 'page/blog' content are on my static home page. I don't want it to do that. Any tips?

This is some very helpful code. Thank you so much! I ended up using the single post but for a static homepage and switched it to is_front_page() and it works.

I don't have anything for the single blog posts now, and I don't quite have this code all figured out.

There is no need for a blog on this site right now, so this works great. If you had a code version that allowed for a custom homepage and single post sidebar as well as these that would be awesome.

I had to use different a different class and id for the homepage to style it uniquely. That is why I had to do all this, and switch it up. I unregistered the sidebar for home that was auto pulled in. The n I changed the name so you would know that this was the Homepage sidebar.

The only thing I was not sure of was whether I should omit some of the code from sidebar.php or just leave it. So far everything is working well so I am not worried about doing anything further.

Again, great stuff! I will have to see what else you have on this website/blog. Very helpful thanks,

Jordan

I need to have your code come up on my HomePage..
My HomePage does Not display any BLOG POSTs only EVENT POSTs... It is an EVENT Wordpress template
this is my sidebar.php

==========
<div id="sidebar">
	<?php
	/* DEFINING WIDGET AREAS FOR SIDEBARS */
	global $post;
	if(is_archive() || is_tag())
	{
		global $wp_query;
		$current_term = $wp_query->get_queried_object();
		if($current_term->taxonomy==CUSTOM_CATEGORY_TYPE1 || is_tag())
		{
			dynamic_sidebar('event_listing_sidebar');
		}else
		{
			dynamic_sidebar('blog_listing_sidebar');
		}
	}else
	if(is_single())
	{
		if($post->post_type==CUSTOM_POST_TYPE1)
		{
			dynamic_sidebar('event_detail_sidebar'); 
		}else
		{
			dynamic_sidebar('blog_detail_sidebar');
		}
	}else
	if(is_page())
	{
		dynamic_sidebar('content_sidebar');
	}else
	{
		dynamic_sidebar('add_event_sidebar');
	}?>
</div> <!-- sidebar right--> 
=======================

This has helped me with a new project where I decided I didn't want to keep using custom field templates for sidebars. What a clever bit of code. Thanks so much for sharing.

This is exactly what I was looking for. Your code is clear and easy to follow. Thank you for sharing it.

Code is very clean i love it i want to ask one thing . how to exclude some pages to creating sidebar how can i set filter for pages.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Ready for transformation?