written on:19 Jan, 2009 by Alen Grakalic

WordPress Hack: Bulletproof Page Menu Labels

Delicious StumbleUpon Reddit Subscribe

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.

About the author

cssglobe's image

Designer, developer and a passionate standardista. Long time web professional with huge experience in all types of front-end work. Founder of Css Globe and creator of Easy front-end framework.
To get in touch, visit Alen's personal page, follow Alen on Twitter or become a Facebook friend.

Enjoyed the article?

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

Delicious StumbleUpon Reddit Subscribe

Read more! Here are our most recent articles:

View All Articles

Comments

  1. Fouad Masoud 19 Jan, 2009

    very nice thank u for this.
  2. Sam Benson 19 Jan, 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 19 Jan, 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 19 Jan, 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 19 Jan, 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 19 Jan, 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 19 Jan, 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 19 Jan, 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 20 Jan, 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 21 Jan, 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 26 Jan, 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 4 Feb, 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 6 Feb, 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 12 Feb, 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 4 Mar, 2009

    I took your "hack" here and put it into a plugin, so no more upgrade fears :)

    http://davidmichaelthompson.com/?p=43
  16. chi 28 Apr, 2009

    thank for this
  17. nomad-one 30 May, 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, further comments are disabled for this post.

CSS Globe is a web design magazine brought to you by Alen Grakalic and kept fresh with member contributed news and exlusive articles.

CSSG Ads

Useful Links

Friends