Information exchange is vital for making the world a better place.
The Internet must grow and I'm here to help.

Link separator for wp_list_pages()

Meta data: posted by Rares on 3 February 2010. Categories: Articles, WordPress. 13 comments.

The Problem

A common problem with the WordPress built-in function for page navigation is the lack of anchor text separator support.

In version 2.7 two more arguments for wp_list_pages() were added to mitigate this inconvenience: link_before and link_after. When using these, the function prepends or appends the specified strings to the generated anchor text. This works well for styling vertical menus.

However, for horizontal menus like the one below, you want the separator to appear between consecutive links and both options become unsuitable:

  • link_before would produce extra markup before the first link
  • link_after would produce extra markup after the last link

Horizontal Menu Example

The solution

The solution I came up with for a recent project involves using regular expressions to inject the page separator. Basically, you want to alter the structure of all links except the last one. This can be accomplished by searching for all list elements that are followed by an extra list element.

The code

$args = array(
  'sort_column' => 'menu_order',
  'title_li' => '',
  'depth' => '1',
  'echo' => 0
);
$separator = ' | ';
$pattern = '/(<\\/a>).*?(<\\/li>).*?(<li)/is';
$replace = '</a>' . $separator . '</li><li';
$subnav = preg_replace($pattern,$replace,wp_list_pages($args));
echo $subnav;

You can specify the separator string in the $separator variable and alter its appearance position by changing the $replace variable.

Resources

Comments

  • [...] Link separator for wp_list_pages [...]

  • Capn My Way
    wrote on June 1, 2010, 20:41

    One question: Where does this code go? (Meaning, where do I paste it?)

    Thanks for the code, and the explanation!

    • Rares
      wrote on June 2, 2010, 11:31

      Wherever you output the navigation code in your templates.
      This article assumes you’re building the nav menu with the wp_list_pages() function.
      You have to find out where this function is called. (most probably header.php)

      There’s an alternative solution to this problem, if you don’t mind a little bit of client side processing (jQuery).
      If the nav menu list element has an id of #nav:

      $(document).ready(function(){
      	$("ul#nav li:not(:last-child)").append(" | ");
      });
      
  • Capn My Way
    wrote on June 2, 2010, 15:37

    Thanks! I just didnt understand that code went inside the <?php tag.

    Works like a charm!

  • Bizim Oyun Sitesi
    wrote on June 3, 2010, 10:58

    I will use this solution at my site. thank you.

  • Chris Boggs
    wrote on December 13, 2010, 17:43

    Thanks for sharing this code, I appreciate it. I have a question or two. I implemented the PHP version (not the js) and it works but with two problems:
    1. The seperators come before each nav li, not after, so there is a “|” before the first nav element and not one before the last. How do I alter this output?
    2. The “|” seperators are showing up 30 to 40 pixels BELOW the menu items, as if they are on a seperate line. How do I control their placement?

    Any suggestions would be greatly appreciated and, once again, thanks for posting this solution.

    • Rares
      wrote on December 14, 2010, 14:42

      You’re welcome. ;-)

      #1: Did you take a look at the source code of the page to confirm the right position of the separators?
      #2: This sounds more like a styling problem. Can you provide me with a link to the site in question?

  • [...] note: I got this code from Rares Comes (very nice lavalamp menu [...]

  • Matt
    wrote on September 16, 2011, 19:16

    preg_replace is expensive and you should always try to do the code right from the sever if possible and not just fix it using jQuery. The best way is looping through get_pages(). You can then format it any way you want.

    $pages = get_pages( array('parent' => 0, 'sort_column' => 'menu_order, post_title') );
    for ($x = 0; $x < count($pages); $x++) {
        if ($x != 0)
            echo " | ";
        echo "<a href='" . get_permalink( $pages[$x]->ID ) . ">" . $pages[$x]->post_title . "</a>";
    }
    
  • David Cunniffe
    wrote on October 7, 2011, 15:53

    Cool. I had spent ages trying to figure that out. Just one question. How do I include a link to the home page?

    • Rares
      wrote on October 7, 2011, 16:02

      David,

      You could try to replace the wp_list_pages() call with wp_page_menu(). Then you can pass in the 'show_home' => 1 parameter (add it to the $args array).

  • David Cunniffe
    wrote on October 7, 2011, 22:49

    Great, Thanks. That did the trick.

  • Marcus
    wrote on December 1, 2011, 20:40

    Worked perfectly. Thanks a million!

By all means, contribute