Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am building a simple website with a number of pages, each of which is grouped.

Let's say my website has roughly 20 pages, grouped into 5 categories. So I want my navbar to display the 5 categories, and each category, on rollover, displays the pages created under it.

Now since I am creating my pages as pages and not posts, I understand that "categories" are not available. So I am creating them as sub-pages. And I am creating each "category" as a page.

My problem: I only created these "pages" for the purpose of grouping the "sub-pages" in the navbar. But none of these "pages" are actual pages, so I don't want any of them to be clickable. What I want is if someone clicks on the "page" itself in the navbar, they should be taken to the first sub-page of that category (or page).

I would be grateful for any solutions.

(Side note: This seems like an extremely common situation, and yet, after hunting around for quite a while, I see nothing addressing the issue. I'm a web programmer with over a decade experience, but a relative newbie to wp, and I find this kind of situation repeating itself over and over.)

share|improve this question
add comment

4 Answers

In response to Matt, here is what I've done:

  1. I delete all of the pages that I had created just for the sake of grouping the sub-pages.
  2. All of the pages that were sub-pages are now regular pages, not sub-pages.
  3. I created a new menu.
  4. For each menu group, I created a custom link, and assigned as its url the url of what will be its first child.
  5. Within the menu, I created a hierarchy of these custom links and their respective children.

Matt, is this what you meant? It seems to suit my needs.

Actually, I believe it is a bit simpler than your solution, in that I don't need to edit WP_Nav_Menu or WP_Nav_Plus.

The main disadvantage that I can see is that every time the first child of a group changes, I will need to manually change the url of its parent custom link. (Perhaps this is an advantage in your solution? For me, the advantage that I don't need to edit any php outweighs this disadvantage.)

Not too bad, but it seems to me that there ought to be a way to not have to create a custom menu to accomplish this. Perhaps what I'm saying is that there should be a feature called "Page Category" that would automatically accomplish this. I'm sure I'm the first person to make such a suggestion!

(I understand that I'm supposed to enter this as a comment to Matt's comment, but it wouldn't let me due to the length of my post.)

share|improve this answer
add comment

I upvoted @MattKey's answer because the back-end configurable menu system is a good way to deal with things like this, and also keeps the menus editable from the back-end.

However... that answer does not directly answer the question of how you would do this based on the page structure alone. The answer I came up with is a custom Walker for wp_list_pages.

class No_Top_Link_Walker extends Walker_Page {
  static $parent = false;

  function start_lvl( &$output, $depth = 0, $args = array() ) {
    $indent = str_repeat("\t", $depth);
    $output .= "\n$indent%s<ul class='children'>\n";
  }

  function start_el( &$output, $page, $depth, $args, $current_page = 0 ) {
    if ( $depth ) {
      $indent = str_repeat("\t", $depth);
    } else {
      $indent = '';
    }

    extract($args, EXTR_SKIP);
    $css_class = array('page_item', 'page-item-'.$page->ID);
    if ( !empty($current_page) ) {
      $_current_page = get_post( $current_page );
    if ( in_array( $page->ID, $_current_page->ancestors ) )
      $css_class[] = 'current_page_ancestor';
    if ( $page->ID == $current_page )
      $css_class[] = 'current_page_item';
    elseif ( $_current_page && $page->ID == $_current_page->post_parent )
      $css_class[] = 'current_page_parent';
    } elseif ( $page->ID == get_option('page_for_posts') ) {
      $css_class[] = 'current_page_parent';
    }

    $css_class = implode( ' ', apply_filters( 'page_css_class', $css_class, $page, $depth, $args, $current_page ) );

    $href = (0 === $depth && $args['has_children']) ? '%s' : get_permalink($page->ID);

    $tli = '';
    if (false !== static::$parent) {
      $tli = sprintf(static::$parent,get_permalink($page->ID));
      static::$parent = false;
    }

    $output = sprintf($output,$tli);

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

    if ( !empty($show_date) ) {
      if ( 'modified' == $show_date )
    $time = $page->post_modified;
      else
    $time = $page->post_date;

      $li .= " " . mysql2date($date_format, $time);
    }

    if (0 === $depth && $args['has_children']) {
      static::$parent = $li;
    } else {
      $output .= $li;
    }
  }

  function end_el( &$output, $page, $depth = 0, $args = array() ) {
    if (false === static::$parent) {
      $output .= "</li>\n";
    }
  }

}
$args = array(
  'walker' => new No_Top_Link_Walker,
  'title_li' => 'Pages'
);
echo '<ul>';
wp_list_pages($args);     
echo '</ul>';

The walker extends Walker_Page and replaces several methods. The code above is essentially a copy of that walker's methods except where where I had make changes, not counting some trivial formatting and syntax changes.

The walker doesn't know what the child URL is until it gets there so I saved the markup for the top level menus without children and inserted them before beginning the markup for the child.

I have tested it a bit during development and it appears to work and validator.w3.org gives it a "green". However, no promises. I just made it up.

share|improve this answer
add comment

I would use the built in Wordpress Menu Manager (Appearance -> Menus) to create my menu structure.

For each of the 'dummy' parent pages you can just use a second link to that pages first child page, and rename it to read however you want.

So if your structure is:

-Parent A

  • Child A

  • Child B

  • Child C

And you want to make it so that clicking on Parent A will take people to the Child A page, just insert a link to Child A as your top-level page, and then rename it to read "Parent A".

Once you have this structure created how you like it, you can use WP_Nav_Menu (http://codex.wordpress.org/Function_Reference/wp_nav_menu) to display the menu in your header.

If on your interior pages you need to show only the child pages of the current section, you can use a plugin I wrote called WP Nav Plus to set your starting depth and only show the children pages (https://mattkeys.me/products/wp-nav-plus/).

I hope this helps.

share|improve this answer
    
Matt, please see the response I posted below and give me your reaction to it, so that I can decide whether to accept your answer. Thank you. –  oyvey May 21 '13 at 14:01
    
This is very close to what I meant, and serves about the same purpose. Where you used a 'custom' menu item, you could have also just added the same page (the first child) to the menu twice, setting one of them as the parent and the second one as the first child. You can then rename the 'parent' link to be named more appropriately –  Matt Keys May 23 '13 at 22:15
add comment

Here is the code for menu with sub-menu from pages and child pages.

<ul>
<?php 
$parents = array();
$args = array(
                'post_type' => 'page',
                'parent' => -1,
                'number' => '',
             );
$pages = get_pages($args);
foreach( $pages as $page){
    $childs = get_pages('child_of='.$page->ID);
    if( count( $childs ) > 0 ){
        echo '<li><a href="#">' . $page->post_title . '</a>';

        if( count( $childs ) > 0 ){
            echo '<ul>';
            foreach( $childs as $child ){
                echo '<li><a href="' . get_permalink($child->ID) . '">' . $child->post_title . '</a></li>';
            }
            echo '</ul>';
        }
    }
}
?>
</ul>

Now, check this code for pure CSS menu and sub menu and customize it to your needs.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.