One of the cooler ideas for a new WordPress default Theme that’s come up has been the idea of including a not-so-blog-ish custom home page template with the Theme. Something optional that you could use if wanted your home page to look a little different. Maybe more of a traditional web site look (whatever that is) or a magazine look. Simply create a new page, assign this custom template to it, set it as your home page, and boom! New look.
I thought this was a great idea too. Especially if that custom page template was totally widgetized. Load up whatever dynamic content you want there with the Query Posts Widget or just use Text Widgets. The default styles of the new 2010 Theme can decide which of several widget areas is the ‘featured’ area and if you want something different—without wanting to change the markup—you can move things around with a Child Theme.
Great, right? Wrong.
You’d have to register new widget areas. Widget areas that would be confusingly unavailable if you weren’t using the custom home page template. Unless …
Here’s a really nifty function written up by Chris Gossmann that’ll check to see if a particular custom page template is active. Chris had to write a SQL query to get this to work so be thankful that he survived to tell us about it.
function is_pagetemplate_active($pagetemplate = '') { global $wpdb; $sql = "select meta_key from $wpdb->postmeta where meta_key like '_wp_page_template' and meta_value like '" . $pagetemplate . "'"; $result = $wpdb->query($sql); if ($result) { return TRUE; } else { return FALSE; } } // is_pagetemplate_active()
OK. Even by itself that function is kinda cool. There’s a few neat things you can do with it. Here’s one. Combine it with the following code for registering a new sidebar in the functions.php
file of your WordPress Theme:
function test_template_widgets_init() { if(is_pagetemplate_active('template-active.php')) { register_sidebar( array ( 'name' => 'Test Widget Area', 'id' => 'test-widget-area', 'before_widget' => '<li id="%1$s" class="widget-container %2$s">', 'after_widget' => "</li>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); } // end test for active template } // test_template_widgets_init() add_action ( 'init' , 'test_template_widgets_init' );
Can you guess what that does? Using our new conditional function, is_pagetemplate_active()
, we’re registering a new widget area only if, in this case, template-active.php
is being used by one of our pages. Completely bypassing our earlier problem of widget areas potentially hanging around without a page for them to be displayed on.
What do you think? Pretty cool, huh? I see lots of really neat possibilities here for custom page templates in WordPress Themes and in Child Themes.
Hi. I gave this process a try and although it works beautifully, I found one small thing may be irritating to some users. Not sure how important this is, but I thought that I would bring it up for the sake of discussion. Here’s what I did and what happened:
1. I change the page template of a page to one containing 3 widgetized areas.
2. I navigate to /wp-admin/widgets.php and set up a widget for each area.
3. I change the page template to one that has no widgetized areas.
4. I change the page template back to one I chose in step 1.
5. All of my widgets have been removed from the widgetized areas.
I was wondering if you had an idea on how to keep all ‘sidebars’ registered, yet hide them from widgets.php if they are not being used in a page template. I hacked around this for a bit, but found no viable solution
That’s a good question. I’d have to hack around myself. It’d also be nice to have a notification when you publish pages with a custom page template, reminding you that there are widget areas to configure with a link to the widgets page.
Right on. Please post back if you find a solution. I will do the same. The notification idea is great too. It may be pretty easy to hook into the
admin_notices
action and using theis_active_sidebar()
function.@Ian, I got a few minutes to play around with this again this afternoon and I think I may be on to something. I have tested the following code with 2.9 using the same process I outlined above. Unfortunately, this is not the cleanest solution due to the fact that I had to add a custom item to the array passed to register_sidebar(). The key is “page_templates” and its value is a numerically indexed array of page template file names.
register_sidebar( array(
'name' => __( 'Frontpage 1', PLATYPUS_LOCALE ),
'id' => __( 'frontpage_1' ),
'page_templates' => array( 't-frontpage-1.php' )
) );
I created this function and hooked it into admin_head:
add_action( 'admin_head', 'maybe_hide_sidebar_from_admin' );
function maybe_hide_sidebar_from_admin( $pagetemplate = '' ) {
global $wpdb, $wp_registered_sidebars;
$templates = array();
$active_templates = $wpdb->get_col( "SELECT DISTINCT( `meta_value` ) FROM `$wpdb->postmeta` WHERE `meta_key` = '_wp_page_template';" );
if( $active_templates ) {
foreach( $wp_registered_sidebars as $name => $data ) {
if( isset( $data['page_templates'] ) && is_array( $data['page_templates'] ) ) {
foreach( $data['page_templates'] as $template_name ) {
$templates[] = $template_name;
}
}
foreach( $templates as $template ) {
if( !in_array( $template, $active_templates ) ) {
unset( $wp_registered_sidebars[$name] );
}
}
}
}
}
@Michael Fields – I was dealing with the same problem for my custom theme that has something like 27 widgetized areas… it gets worse when you test a lot and keep changing templates that activate/deactivate different widget areas and dozens of widgets need to be re-placed into their sidebars over and over again. So what I did, I added a widget backup to the theme options – it basically saves the array of the widgets and the sidebars they assigned to. I also have a “restore” button. So, initially, when I place all my widgets in all the sidebars, I go to the theme settings and back them up. Then I can mess with templates and sidebars as much as I want because I can restore all the widgets with a single click of a mouse 🙂
Hope this helps.
This is very helpful. One of my Thematic child themes has a custom home page with nine widget areas:
1. Home Top
2. Home Left Top
3. Home Left Left
4. Home Left Right
5. Home Left Bottom
6. Home Right Tab Labels
7. Home Right Tabs
8. Home Below Tabs
9. Home Bottom
And they’ve worked very well, but occasionally I’ve gone to the home page to find it empty. And I suppose that turns out to be because the custom home page template somehow got disabled. Now I just need to figure out how to make the that template always available even when for some reason it’s not.
The idea is nice but one thing that jumped out to me is the “like”s in the SQL. Why use Like instead of “=”? It’s going to be a lot slower and there’s no benefit.
Hi Ben,
I did some tests here on my local system and can’t confirm your statement. The script using ‘like’ took between 0,0027 and 0,0036 seconds. A script using ‘=’ took between 0,0036 and 0,0042 seconds. Might be my test method or my system.
Could you please guide me to a source that explains why using ‘=’ is faster than using ‘like’?
Chris
Forgot about this, but there’s some interesting reading on this topic here : http://stackoverflow.com/questions/543580/equals-vs-like
I’ve subscribed to notifications so I can see if you respond this time 🙂
Whats the point of registering it at the cost of 1 more SQL query?
The even smartest way would be to use
is_page_template()
template tag. It would avoid 1 database query and 1 function (and its maintability).Anyway, that’s a good idea 🙂
PS : the best way, keeping your SQL query, would have to eitheir add a LIMIT 1 in the query (especially as the meta table can contains lots of rows) or even better, doing a COUNT.
is_page_template()
is a different thing altogether. It only tells you if you’re in any page template, or a particular one, not whether or not a particular page template is active.Hell yay, I understood the subtle difference. Once a theme is registered/updated, ALL page templates should be stored in an option field. It’s not the thing changing all the time, without a version change.
It would still avoid the, for me, useless query (hence it’s not cached).
Using count is to slow because it would run through all rows in WP_POSTMETA.
An additionl parameter ‘limit 0, 1’ makes sense (take the first and display 1 — as far as I understood this parameter — sorry, I’m still learning SQL)
The code should be:
$sql = "select meta_key from $wpdb->postmeta where meta_key like '_wp_page_template' and meta_value like '" . $pagetemplate . "' limit 0, 1";
Chris
@Chris – The first offset argument in your limit clause is actually not necessary. Usually, in queries like these, it will be expressed as “LIMIT 1”.
MySql says this about it:
Related to the page template subject, can someone please tell me how to add a different style sheet to a page template in the thematicfeaturesite child theme?
Hi Ian, Thanks alot for the info. It’s very usful and I’m almost there. So here’s the speed bump I’d really like to use different widgets on my home page sidebar than on the other sidebars of other pages of my site. So here’s what I’ve done I’ve copied the above code into functions file, create the “template-active.php file from the index.php file…and nothing happens, the sidebars remain the same on all pages, and even-though the “test_widget_area” shows up in the widget module page none of the widgets I place in to the “test_widget_area” show up on my home page which has the template-active.php template option checked.
I thank you in advanced, If you could give me a solution or point me to one. 🙂
Best,
LB
It would be so great if I could get your help. I hope you’re doing well and are enjoying the long holiday weekend.
function is_pagetemplate_active($pagetemplate = '') {
global $wpdb;
$sql = "select meta_key from $wpdb->postmeta where meta_key like '_wp_page_template' and meta_value like '" . $pagetemplate . "'";
$result = $wpdb->query($sql);
if ($result) {
return TRUE;
} else {
return FALSE;
}
} // is_pagetemplate_active()
function test_template_widgets_init() {
if(is_pagetemplate_active('template-active.php')) {
register_sidebar( array (
'name' => 'Test Widget Area',
'id' => 'test-widget-area',
'before_widget' => '',
'after_widget' => "",
'before_title' => '',
'after_title' => '',
) );
} // end test for active template
} // test_template_widgets_init()
add_action ( 'init' , 'test_template_widgets_init' );
the best way, keeping your SQL query, would have to eitheir add a LIMIT 1 in the query (especially as the meta table can contains lots of rows) or even better, doing a COUNT.