posted on:January 19, 2009

WordPress Hack Bulletproof Page Menu Labels


I am not a WordPress expert by any standards. However, I did quite a few WP projects and got to know it well enough to try to hack things up here and there. I’d like to share my latest "hack" with you although there is a big possibility that you already know to how to handle situation mentioned in todays post or that there is a better solution out there.

The Problem

The problem is common and I encounter it on every site that I work on. What I need is to have menu label different than page’s title. So, one phrase for menu list, and other for page title. As you know, by default WP will use the page title in the menu. If you want to add a longer title, something like "What can we do for you" it will not suitable for navigation. Not only for it’s length but the context is wrong too. Navigation must use short, straight to the point words or phrases. In this case the word would be "Services".

"Wait, there is a plugin for that" – you’ll say. Yes there is and I used it many times. The plugin is called Page Menu Editor, created by SarahG. You can find it here.

So, why am I not using it now and what’s the purpose of this article? Well, on this particular project I wanted to use SPANs nested inside anchors so I can have rounded corners (using sliding doors technique).

<li><a href="#"><span>Home</span></a></li>

I used 2.7’s link_before and link_after parameters

<ul id="nav">
	<?php wp_list_pages('include=2,3,7,9&link_before=<span>&link_after=</span>&title_li='); ?>
</ul>

For some reason the Sarah’s plugin didn’t work. I am not going into searching for the reason why it didn’t work, it just refused to display the values I provided as page menu labels. When I removed link_before and link_after parameters I had no problems and the plugin worked fine, but with those parameters included I had no luck.

I came up with my own short ‘n’ sweet solution.

The Solution

I call this solution a "hack" because, in order to get this done, we need to update a file outside your theme’s directory, directly in WP’s core – classes.php (/wp-includes/classes.php) For that reason alone I suggest you be very careful when applying this hack. 🙂

The idea behind this is to use WP’s custom fields. On each page with long title (or a title you just wish to replace) add a custom field called "menutext" and add a desired value. We are going to use that for navigation item.

Now, carefuly open classes.php file 🙂 (/wp-includes/classes-php) and search for the class named Walker_Page. In it you’ll find a function called start_el. Search for this line (1175th line in my classes.php):

$output .= $indent . '<li class="' . $css_class . '"><a href="' . get_page_link($page->ID) . '" title="' . attribute_escape(apply_filters('the_title', $page->post_title)) . '">' . $link_before . apply_filters('the_title', $page->post_title) . $link_after . '</a>';

Immediately before that line put:

$menutext = get_post_meta($page->ID,"menutext",true);
if(empty($menutext)) $menutext = apply_filters('the_title', $page->post_title);

and modify the line itself by replacing:

apply_filters('the_title', $page->post_title)

with:

$menutext

So, the code should now look like this:

$menutext = get_post_meta($page->ID,"menutext",true);
if(empty($menutext)) $menutext = apply_filters('the_title', $page->post_title);

$output .= $indent . '<li class="' . $css_class . '"><a href="' . get_page_link($page->ID) . '" title="' . attribute_escape(apply_filters('the_title', $page->post_title)) . '">' . $link_before . $menutext . $link_after . '</a>';

What we did just now is searched for value of a custom field named "menutext" for each item in the navigation and placed the value in the newly created variable. If the page has that custom field defined it will use it. Otherwise it will use the default value – page’s title.
Ok, now, publish the file and that’s it!

As I said, I am not an expert and at this moment I am not aware if there is a better solution, so let us all know if you have a better one.

Enjoyed the article?

Then don't miss our next one! Subscribe to our RSS feed or share it with your friends.

DeliciousStumbleUpon RedditSubscribe

Comments (17 Comments)

  1. Fouad Masoud
    January 19, 2009

    very nice thank u for this.
  2. Sam Benson
    January 19, 2009

    Excellent, I love hacks! There's something very personal about tearing open your favourite software and adding your own gooey-bits! Thanks for this.
  3. Hassan
    January 19, 2009

    I hate to use hacks, cause when you update your wp, there is a high chance to break your website. I don't think this is a good solution at all. Thanks for your informations.
  4. Bill Kracke
    January 19, 2009

    @Hassan: I completely agree with you: Hacks are a sure fire way to insure you have to do it again later when a code update breaks your hack. (Think about all the CSS hacks that later messed up a new version of the browser) However, this isn't "that kind of hack". Wordpress gives us custom fields for uses like this. They allow us to add data to posts & pages and recall that data later in our code. Just like this. @Alen: This is a brilliant use of the custom field. Simple. Elegant. I wish I had thought of it!
  5. cssglobe
    January 19, 2009

    Thanks Bill. It works really fine for me and I will use it until something like this becomes integral part of WP.
  6. zinni
    January 19, 2009

    I think that a less hacky version of this example could be easily created if you just look at the solution from the opposite side of the problem. The problem is not actually the navigation, it is the page titles. I would instead set a custom field for the titles, if it is not null then you use it instead of wp_title(); this would also require editing the header.php file, however you are not changing core files...
  7. cssglobe
    January 19, 2009

    @zinni: good point. But it's more natural for less savvy end-user to edit the title field for actual page titles.
  8. Chris McMahon
    January 19, 2009

    If you're comfortable editing themes you could edit page.php so titles aren't displayed and then just type the title in the textarea and change it to a headline.
  9. cssglobe
    January 20, 2009

    @Chris: We re talking about end-users here. I am never the one editing the content. I pass it on to client when I'm done and he/she takes over. So, you can't rely on them to follow the structure pattern, you need to make things - bulletproof.
  10. Martin
    January 21, 2009

    Hello, I did a similar hack, but due to my coding background realized it as a separate plugin. This plugin offers a new function - my_list_pages_short with the very same usage as wp_list_pages. So, there is no need to modify standard wp code. If anyone is interested, I can make it publicly available.
  11. Andrzej Stacherski
    January 26, 2009

    If you have small number of pages you can use templates for all of them. In the template file just remove the line where the title is fethed from wp database (<?php the_title(); ?>) and replace with your own. eg. Create Page called Services and assign template Services to it. In the template replace the title with your own "My own way to call Services" and you're sorted. No messing with wp code outside your template. And your menus will be called whatever you want.
  12. Ben Tupper
    February 4, 2009

    Do you know a way you can assign a unique class to an individual menu item? I have a navigation where I have a list of items (page names). One of the page names I am trying to use FLIR to replace the font. I can do that no problem. But I have 1 page name in my menu that I want to use 2 different fonts on. FLIR replaces text by html element or css element name. I want to be able to assign a class to my page name on the first word only of this page name which has 2 words. Any ideas? Your article here seems to be hinting at this, but it's not quite the same, is it? :| Any help is greatly appreciated. Thanks!
  13. Martin
    February 6, 2009

    @Ben: wp_list_pages assignes following classes to items: <li class="page_item page-item-4 current_page_ancestor current_page_parent"> and, of course current_page_item, for the current item. In my example above, page-item-4 is assigned to a page with an id 4. In order to assign different styles, you only have to define a style for a specific id. Cheers, M.
  14. Sneha Gupta
    February 12, 2009

    Hello, Every post then this might be a tutorial for you. Function have come up with a great tutorial for creating your own custom write panels in wordpress. Well worth a look if you use custom fields a lot in your wordpress. I am also interested in latest news, sometimes i posted on <a href = "http://www.wildnettechnologies.com/web-development-services.htm"> Web Development</a>
  15. Mick Thompson
    March 4, 2009

    I took your "hack" here and put it into a plugin, so no more upgrade fears :) http://davidmichaelthompson.com/?p=43
  16. chi
    April 28, 2009

    thank for this
  17. nomad-one
    May 30, 2009

    I tried some like this in order to create those nice menu's which have subtext underneath each menu link. So far no success, also been trying to create something which does not break on upgrade. Does anyone know of a way to use custom field data inside the link_after parameter?

Sorry, the comment form is closed at this time.