It’s not uncommon for a website to want to have different sidebars on different pages, different “sections” of the site. When you use a traditional WordPress theme this is easy to accomplish, just create a new page template and away you go.
The Thesis theme for WordPress doesn’t work like that, you don’t have page templates in the same sense. You can create custom page templates in code, in the custom_functions.php
file, but that’s relatively heavyweight for something that seems so simple, just changing the sidebars for certain pages of the site. And if Thesis is so powerful, shouldn’t it be easy?
When I was working on the problem for Aldosoft I read through a few different tutorials for “doing dynamic sidebars the easy way”, and thought that the methods described were far from easy. All of them involve copying and pasting code from other parts of Thesis, which is a code smell for something that is likely to be a maintenance or compatibility problem down the road. Even the tutorial in the Thesis User’s Guide seemed like it was trouble!
Defining the Ideal Solution
I had a few important criteria for my own solution:
- Widget-based — I wanted to use the built-in WordPress widgets feature for building my sidebars, no PHP code for the sidebar content.
- Minimal HTML in my code — A lot of the solutions I read had you copying the whole chunk of HTML for the sidebar from a Thesis file into a template file. This is a terrible idea, because it means you’ll need to do this every time Thesis updates that HTML. It’s not common, but who wants to add it to their list of upgrade tasks?
- Minimal PHP code in
custom_functions.php
— The less code you write, the less code you have to maintain. So wherever possible, use built-in features of Thesis or WordPress, rather than writing my own code.
Where Thesis Gets in the Way
Digging into the solution, I discovered that I had to fight against some biases coded into WordPress and Thesis. Both use the term “sidebar” instead of the more general-purpose “widget area”, and they often use the term literally. Certainly, the widget areas built into Thesis are intended to be sidebars (except in single column mode), and can’t be moved. Worse, Thesis, for all its hooks and filters, gives you no way to conditionally replace or alter the built-in sidebars.
The Simplest, Most Powerful Solution
The solution turned out to be stupid simple: Leave the built-in Thesis sidebars empty, completely blank, and create two (or more) new widget areas. Then use the thesis_hook_before_sidebar_1
hook to insert the right widget into the sidebar position, based on whatever conditions you’re using to change them dynamically.
The Thesis built-in sidebars are still there on every page, but because they’re empty, they collapse and have no visual effect. So only your new sidebars appear, and inside your hook method you have full control over which of them to display. Simple to implement, easy to customize, and very powerful.
Implementing Dynamic Widget-Based Sidebars in Thesis
Updated 4-Sept-2012 Thanks to a suggestion from the always-insightful kristarella, I improved the code in this article. It’s now easier to implement and lower maintenance. The important changes are using a different Thesis hook method, and a much shorter mysite_do_sidebar()
method. The code below has been updated.
There are three easy steps to implementing this solution. Let’s start with the “hard” part: the code.
1. Create New Widget Areas for WordPress
The first thing to do is to create two or more new widget areas, by registering them with WordPress. Add this to custom_functions.php
:
// Define the different possible sidebars.
// This registers them with WordPress, so they'll show up in
// Appearance > Widgets, so you can edit them directly in WordPress.
register_sidebar(array(
'name' => 'My Site Main Sidebar',
'id' => 'my-site-default',
'before_widget' => '<li class="widget %2$s" id="%1$s">',
'after_widget' => '</li>',
'before_title' => '<h3>',
'after_title' => '</h3>'
));
register_sidebar(array(
'name' => 'My Home Page Sidebar',
'id' => 'my-site-home-page',
'before_widget' => '<li class="widget %2$s" id="%1$s">',
'after_widget' => '</li>',
'before_title' => '<h3>',
'after_title' => '</h3>'
));
This is standard WordPress code, generic for any theme that wants to have widget areas. The only part you need to change in your own code is the name
and id
items. The name
is what you’ll see in the WordPress admin console when you go to customize your widget areas, and the id
is an identifier used behind the scenes. Make sure both are unique for each sidebar you create.
2. Create the Sidebar Switching Hook Method
Now create a method that will decide which sidebar to show on a given page. Here’s a simple version that chooses one sidebar for the home page, and another for the rest of the site. Again, this goes into custom_functions.php
:
// Here's the hook method to decide which sidebar to use
function mysite_dynamic_sidebars() {
if(is_home()) {
mysite_do_sidebar('my-site-home-page');
}
else {
mysite_do_sidebar('my-site-default');
}
}
// Activate the hook method in Thesis by adding it to a Thesis hook
add_action('thesis_hook_before_sidebar_1', 'mysite_dynamic_sidebars');
The argument you pass into mysite_do_sidebar()
is the id
for a sidebar you created in step 1.
You can choose between as many sidebars as you care to create, and make your logic as complex as necessary; whatever you can put in an if()
or elseif()
statement. Definitely make sure you have an else
clause at the end, with a default sidebar.
mysite_do_sidebar()
is a utility method to consolidate any static HTML used for the sidebar. Currently, because the sidebars are being inserted inside Sidebar 1’s HTML wrapper, there’s no extra HTML at all (yay, goal #2!), but keeping this part in a separate method makes it easy to do so, if things change.
function mysite_do_sidebar($sidebar) {
if ( ! dynamic_sidebar($sidebar)) {
echo "ttttt<li>missing widget area: $sidebar</li>n";
}
}
3. Customize Your Widgets
This is the fun part! Go into Appearance > Widgets in the WordPress admin console. You should see both the built-in Thesis sidebars (Sidebar 1 and Sidebar 2) and your new widget areas. Move widgets from the built-in widget areas to your new sidebars by dragging them. You should end up with completely empty Sidebar 1 and Sidebar 2 blocks, as shown.
Once you’ve filled in your new sidebars with their customized contents, you should be able to tour your site and see the different sidebars appear in the different areas. If you’re not seeing the right sidebar where you expect, the problem is most likely in your hook method’s switching logic. Add a text widget to the top of each custom sidebar with the name of where you think it ought to show up. That will help you debug your hook method from step 2. Make sure you’re using the right sidebar id
for the right logical condition.
Extra Credit
You can get as advanced and creative with your switching method as you need to achieve the effect you’re after. You’re not limited to just the built-in Thesis or WordPress functions. Here’s some code that I use on a site to decide if I’m in a “section” that is made up of static pages. It checks to see if the page requested is the section’s “parent” page, or any of the descendent “child” pages below it.
function aldoblog_dynamic_sidebars() {
// Get an array of page IDs for the Audiobooks section
$audiobook_pages = aldoblog_get_family_page_ids(503, 2);
// If we're in Audiobooks, show that sidebar
if(is_page($audiobook_pages)) {
aldoblog_do_sidebar('aldo-on-audiobooks');
}
// Otherwise, use the site-wide sidebar
else {
aldoblog_do_sidebar('aldoblog-default');
}
}
Getting all the page IDs for the section is done in a helper method. There’s currently no simple way in WordPress to get all of the page IDs for a page and its children, so this method gets all of the pages themselves, and then extracts their IDs into an array:
function aldoblog_get_family_page_ids($parent_page_id, $depth = 0) {
$ids = array($parent_page_id);
$pages = get_pages(array('child_of' => $parent_page_id, 'depth' => $depth));
foreach($pages as $p) {
$ids[] = $p->ID;
}
return($ids);
}
get_pages()
is the WordPress function that does all the real work. My helper method simply assembles an array with the IDs I need to define a section that’s based on pages, rather than categories, tags, or some other built-in WordPress feature.
Or instead of “letting the sidebars collapse” you could use their HTML and just insert new widget areas inside the sidebars (eg thesis_hook_before_sidebar_1) and not have extra HTML floating around.
@Kristarella: You’re absolutely right! I’m not sure how I missed this, those hooks have been there forever. I think I went down one road that didn’t pan out, and when I backtracked, I didn’t go far enough.
The great news is that while the overall approach remains sound, it makes the code even simpler, and removes all of the static HTML. I’ll have to revise the code presented here, but the changes are remarkably small. Thanks for the pointer!
No worries ;-)
Beyond that little change this is something that hadn’t really occured to me before. It’s a great idea!
This tutorial seems awesome and EXACTLY what I need. I’ve been searching around for a few hours,, now I’m going to give it a try, wish me luck.
My case: I don’t want to wreck the home page as it is, I just want to have different sized sidebars (only 1 on every page) and different content in those sidebars depending on the pages ,,, wish me luck, giving your method a go right now, cheers!
well, I’m definitely a php novice, gave it a try and all I get is ‘missing widget area’ at the top of the sidebar area that didn’t collapse.
Am I supposed to replace $sidebar with one of the id names?
Also, how can I determine the width of the sidebar areas, assuming this may work?
@Stephen: If you’re getting the “missing widget area” text, it means you didn’t pass the ID of one of your new sidebars that you defined in Step 1 into the mysite_do_sidebar() method as illustrated in Step 2. Look at the code samples in those two steps, and see how the sidebar “my-site-home-page” is defined in the first step, and used in the second step. You need to appropriately pair your sidebars in the same way. HTH!
I copied your code just as it is, keeping your structure exactly, and that is what I got.
What other things are there to watch out for? I’m trying turning off and on everything from multimedia boxes to custom page templates to no avail. I really spent hours with this trying to get it right,, just seems like it should work but it doesn’t.
Just tried it from scratch and it’s working, awesome! Don’t know what the difference between then and know is,,, :-)
Any tips on customizing and changing the width of the new sidebar areas?
Super thanks for your awesome info here.
@Stephen: Glad you were able to figure it out! Regarding the width, that’s controlled by the CSS for your site, not anything in the code here. You can adjust the width of (up to) all three columns for your site in the Thesis > Design Options control panel, or play with your CSS directly in your custom folder. (Recommendation: use the control panel. :-)
Ok, so this tut seems super appropriate to what I need, but I have debugged and short of cut and pasting the code to the custom.php file I think it’s pristine. But something is amiss where I click the big ass save button and my whole site goes blank. Help?
Hmmm. It’s hard to know what’s going wrong with this little information. If you’re getting the white screen of death, it probably means there’s a syntax error in your PHP somewhere. Or possibly some other parse error, like a stray or missing PHP close tag, that kind of thing. But without seeing the actual thing you changed, that’s all I can suggest…
Alderete, thanks for taking the time to answer my email. As for right now I’m still getting the white screen of death. Debugging I go!
The white screen of death sucks. I’ve seen it a lot, some days PHP sucks. Turn on debug mode, though, and you’ll get a lot more information about what’s going wrong. It helps a lot!
I’m going to embark on this today (it seems to be exactly what I need). Just 2 quick questions:
(1) They changes I’m making are to a site that is live and currently has a widget that needs to stay up until the last possible moment (it has an AWeber form in it and we are in the midst of a promotion that is driving lots of traffic) – is it possible to leave this widget up while I’m getting the others ready to go and then just take it down once everything is set?
(2) regarding this info in the first step (and forgive me if this is a dumb question…but I know just enough to be dangerous): “The name is what you’ll see in the WordPress admin console when you go to customize your widget areas, and the id is an identifier used behind the scenes. Make sure both are unique for each sidebar you create.” Where do I find the exact name and id??
@LeeAnn: First off, I would recommend implementing on a test or offline version of your site, before implementing on your live site. There’s a lot that can go wrong when you “know just enough to be dangerous” and I’d hate for you to knock yourself offline while an important promotion is going on. Any PHP syntax error will most likely give you the “white screen of death”, so if you do attempt it, make sure you’ve got a backup of your custom_functions.php file you can paste back in in a hurry.
Second, once you’ve got everything lined up in custom_functions.php, I believe it’s possible to migrate your sidebar contents from the built-in sidebars to your new ones without it ever being visible to visitors to the site. I didn’t test this specifically (I work with a locally-hosted test version of my site, and deploy using rsync when it’s right), but since you’re just moving widgets from one sidebar to another, the change should be instantaneous.
Last, for the names and IDs of your new sidebars, you make them up yourself. I would change “mysite” in my sample code to the name of your site (or a shortened version of it) as a poor man’s “namespacing”, and then use the rest of the text to give the sidebars meaningful names, so you’ll recognize them both in the WordPress sidebar editor and in your own code. HTH!
Thanks! This is my afternoon project – I will keep you posted on my progress!
Ok – I’ve been playing with this and feel like I’m getting close..but now my widgets keep disappearing. I move them into the designated box, click save, then do another one. But when I leave the page and go back, the boxes are empty again :-( So it’s giving me an error on the page “missing widget area: Video 1”
Also, when doing the if/then/else statement, what is the best way to reference the page? I tried if (is_page5) etc but it did not like that.
BTW – per your earlier suggestion, I’ve been testing this out on http://www.firsthalfmarathon.com since it’s not getting traffic (I’ll move it to my live site once I get this stuff figured out).
@LeeAnn: Hmmm. The “missing widget area” is a sure sign that you’ve passed an ID to yoursite_do_sidebar() that wasn’t actually created with a register_sidebar() call. Check and make sure that the ID you’re using for the sidebar named Video 1 is the same in both places.
For referencing pages, I think the best way to do it is with the page slug, which is the custom URL that you define when you create the page. You just need the end part, so ‘video-intro’, not ‘http://mysite.com/video-intro/’. You can also use the page ID, which you can find in the address bar of your browser when you’re editing the page. It’ll be a simple integer. HTH!
ARGH…I’m still having the same problems…and I just can’t figure out what to do. (1) my widgets keep disappearing – I’m using the “text” widget to put code (or even just words) in – I drag it over to my custom sidebar boxes (just like it looks on your example), save it and then close. When I leave the page and go back, it’s gone. This kept happening yesterday. Today they magically reappeared in the “inactive widgets” section, but I still can’t get them to stick in the sidebar.
(2) I still can’t get the page thing to make sense. I’ve tried using numbers and I’ve tried using the page name (from the permalink) and I keep getting errors. To simplify I copied your code exactly #2 and dropped it in (trying to get just one page to work…I can add the rest once I get it going), but now I’m getting this error:
I think it doesn’t recognize my home page, but I’ve tried the page number, home and leaving it blank….I keep getting this error. Any ideas for either one would be great. We are in the middle of a massive launch and I need to get these sidebars figured out asap.
@LeeAnn: I can take a _quick_ look at this, if you post your code for custom_functions.php. Ideally post it in a GitHub Gist and then post the URL here. Or a pastie, or any of the other code snippet pasting services. Or post it here, but that might require reformatting to get it to read right.
You are awesome! I’ve never heard of github, but I think I was able to post the code here:
https://gist.github.com/89552c6144975078c93f
Note that in the first part of the “if” statement I have a blank right now – because there is no “name” for the home page (if you look at the permalink it’s blank). I’ve also tried “home” “5” and “#5” (it’s page #5) and those always give me a reference error.
BTW – my widgets are still disappearing :-(
Thanks!!
OK, a couple of obvious problems:
1. Sidebar IDs can’t have spaces or funky characters in them. Stick with letters, numbers, dashes and underscores. I prefer all lower case. So instead of “Video 1” use “video-1”.
2. Not required, but a good idea, adding a site name string before each ID to namespace it is good. Adding to the previous change, use “marry-video-1”.
3. Your dynamic sidebars method needs to have a valid function in the if statement; that will get you every time. There’s a variety of built-in WordPress functions you can call, like is_home(), that will get you special pages or conditions.
The following gist applies all of these to your code, give it a try: https://gist.github.com/433ba0a90e00a9af1d07
You are awesome! I copied your code as is (good news…the widgets are back and seem to be staying…at least for now…)
BUT…I’m getting this error message:
Fatal error: Call to undefined function mysite_do_sidebar() in /home/content/37/7665037/html/firsthalfmarathon/wp-content/themes/thesis_185/custom/custom_functions.php on line 50
thoughts??
Your code is missing the utility method that I provided in the blog post. Find that method in the article, and paste it in.
We’re cooking now!! This works great. BTW – this is the best coding for the page numbers that I couldn’t figure out:
if(is_page(‘5’)) {
mysite_do_sidebar(‘marry-opt-in’);
}
NOW…just 2 more tweaks…it’s adding the sidebar from the “else” statement – so it’s putting what I want first (per the “if” statement) but ALSO adding what’s in the “else” statement. Also, it still has the green “default widget” box at the very bottom of the sidebar.
My code is here: https://gist.github.com/3724412
I can’t thank you enough for all of your help – I know I’m being a pain in the arse!
One last message – I thought you’d be happy to know that I figured everything out. I created a “default” sidebar that is blank and referenced it in the “else” part of the code. Then I added a blank textbox to the WordPress sidebar – this got rid of that pesky green box. It’s probably not the most direct route, but it works like a charm. The finished product is up and running at:
http://www.howtomeetandmarryyourman.com
and the first video page (with my fancy sidebar) is:
http://howtomeetandmarryyourman.com/how-to-attract-a-quality-man-in-less-than-6-seconds/
Thanks so much for all your help!!
LeeAnn
It’s me again :-) I’m building another site for a different client. I’m still using Thesis, but this time we are using the 3-column format. How do I direct the widgets to either the left (Sidebar1) area or the right (Sidebar2) area. I’m guessing it has something to do with the hook, but I’m not sure. Have you run across this before? The website above is the homepage for the new site. All the widgets are currently going to the left side (Sidebar1).
Thanks!
LeeAnn — If you’re developing on Thesis you should definitely check out the documentation; it includes a hook list that is very useful. http://diythemes.com/thesis/rtfm/hooks/
Thanks so much! I found the right hook, am just trying to figure out where to add it with the code above. I’m playing with this now…
Still can’t figure out how to get the hook to work with what I’ve already created based on the above. Any ideas? Is there a tutorial somewhere on how to use hooks? I can usually figure things out and I’m sure there is an easy fix to this given how far I am down the road….
Hello,
Thank you very much for this post. It’s helping me a lot, although I am having a hard time coding for more than 3 sidebars. For now I have:
function mysite_dynamic_sidebars() {
if(is_home()) {mysite_do_sidebar(‘home-page’);}
elseif(is_page(1550)) {mysite_do_sidebar(‘public-speaking’);}
else {mysite_do_sidebar(‘default-page’);}
}
and it works. Now I would like to add many more sidebars, one per post. How can I do that?
Thanks so much for your help.
@Jose: Hmmm. While I suppose you could do this if you really wanted to, the sidebars mechanism isn’t really designed to scale up to that kind of usage. It would almost certainly be better to either (a) add a custom field to each post, and display that using some custom code in your sidebar, or (b) create a custom post type for your sidebar content, and link the custom post to the associated regular post. Option A works better if the unique content for each sidebar is short-ish, and option B works better if each sidebar’s content will be elaborate. HTH!