WordPress: Style Top Level Pages Differently

Recently, I needed to figure out how to apply different styles to the top level pages on a WordPress site than those applied to child pages. After a little digging, I figured out a fairly easy way to determine which is which.

Granted, I could easily create a custom page template and assign it to each of my top level pages, but that would require anyone creating new pages to recognize whether or not the custom template is supposed to be applied, and that change would have to be made any time a page is moved.

Instead, I wrote some simple functions to check whether or not a page is a child page or not. I then use that function to assign a specific class to the elements that need to be styled differently.

If you copy and paste the following functions into the functions.php file for the theme you’re using.

function has_children() {
	global $post;
	$children = wp_list_pages("title_li=&child_of=".$post->ID."&echo=0");
	return ($children) ? true : false;
}

function is_child() {
	global $post;
	return ($post->post_parent) ? true : false;
}

The first function is developed to check whether or not a page has any children. If it does, it returns true; if not, it returns false. You would use that function wherever you want to display something different for pages that have subpages and for pages that don’t.

The second function checks to see if the page has a parent. If it’s a subpage of some other page on your site; the function will return true. If it’s not a subpage (if it’s a top-level page), the function will return false. The second function is really the one we’ll be using for the purposes of this post, but I wanted to include the first function in the event that you find a use for it.

To use the second function, you might do something similar to the following.

<h1 class="<?php echo (is_child()) ? 'child' : 'topLevel'; ?>"><?php the_title(); ?></h1>

The code example above will check to see whether or not this is a top-level page. If it is, we assign a class of “topLevel” to the h1 tag. If it’s not a top-level page, we assign a class of “child” to the h1 tag. You can use this function on a simple item like an h1 tag as shown above, you could use it to assign a class to the entire post or you could even use it (or the other function I included above) to add extra content based on whether or not the page is a top-level page, if it is a child page, if it has children or not.

5 Responses

  • Leo

    Hey,
    I have come across this post and was wondering if you could possibly help me. I am not a php guru but am trying to achieve something which is along similar lines to what you have posted here.
    I am wanting to build a menu for my site which outputs different markup to the wp_list_pages function.

    instead of the usual unordered list markup output i would like to output:

    instead of the usual unordered list markup output i would like to output:
    //this markup for each parent page that has no children

    <a href="$page_link" title="$title" rel="nofollow">$link_text</a>
    //this markup for each parent page with children
    <a href="$page_link" title="$title" rel="nofollow">$link_text
    <!--[if gte IE 7]><!--></a><!--<![endif]-->
    <!--[if lte IE 6]><table><tr><td><![endif]-->
    ($child_page markup)
    <!--[if lte IE 6]></td></tr></table></a><![endif]-->
    //this markup for each child page and has no children
    <a href="$page_link" title="$title" rel="nofollow">$link_text</a>
    //this markup for each child page with children
    <a href=" $page_link" title="$title" rel="nofollow">$link_text
    <!--[if gte IE 7]><!--></a><!--<![endif]-->
    <!--[if lte IE 6]><table><tr><td><![endif]-->
    ($child_page markup)
    <!--[if lte IE 6]></td></tr></table></a><![endif]-->

    But I have no idea how to go about writing some code to achieve this (at the moment I have achieved this by constructing the menu in plain old static html however ideally i would like this to be dynamic so that it updates automatically without me needing to write the html everytime I add a new page.
    I have thought about using preg_replace with the wp_list_pages function. Any ideas or help would be greatly appreciated!

    • To begin with, copy the two functions I provided in the post above into your theme’s functions.php file.

      Then, you would use code similar to:

      
      <?php if(!has_children()) { ?>
      <a href="$page_link" title="$title" rel="nofollow">$link_text</a>
      <?php } else { ?>
      <a href="$page_link" title="$title" rel="nofollow">$link_text
      <!--[if gte IE 7]><!--></a><!--<![endif]-->
      <!--[if lte IE 6]><table><tr><td><![endif]-->
      ($child_page markup)
      <!--[if lte IE 6]></td></tr></table></a><![endif]-->
      <?php } ?>
      <?php if(is_child() && !has_children()) { ?>
      <a href="$page_link" title="$title" rel="nofollow">$link_text</a>
      <?php } elseif(is_child() && has_children()) { ?>
      <a href=" $page_link" title="$title" rel="nofollow">$link_text
      <!--[if gte IE 7]><!--></a><!--<![endif]-->
      <!--[if lte IE 6]><table><tr><td><![endif]-->
      ($child_page markup)
      <!--[if lte IE 6]></td></tr></table></a><![endif]-->
      <?php } ?>
      

      There’s probably a simpler way to do it, and it’s possible I’ve slightly misunderstood your request, but that should at least get you started.

  • David

    I’m looking for a way to return the Top Level Page’s Slug from any page your on. So far your code here is the closest I’ve found. Good Job too!

    • David – I’m actually getting ready to do something extremely similar for a site on which I’m working (I actually need to retrieve and display the full title of the top-level parent page, but it will be an extremely similar process). I’ll be sure to post a new article about doing that once I get the functions written and working later this week. Thanks.

  • […] a week ago, someone commented on my post about styling top-level pages differently in WordPress, asking how to get the slug for a top-level page while one of its descendant pages is being […]

Post Your Comment

Your email address will not be published.