0
votes

I'm creating a page with Chapters and Subchapters, all subchapters are displayed on the chapter page, while each Subchapter can be commented. For better understanding I will describe the structure:

I have the following pages structure:

- Chapter 1
- Chapter 2
- Chapter 3

For each Chapter there is a hierarchical custom post type 'sub_chapters' with multiple entries (posts):

- Subchapter 1
  - Subchapter 1.1
  - Subchapter 1.2
- Subchapter 2
- Subchapter 3

The Page Chapter 1 acts like an Overview page and gets the content from all subchapters. Like this:

Chapter 1 Title

- Subchapter 1 Content
- Subchapter 1 Comments
- Subchapter 1.1 Content
- Subchapter 1.1 Comments
- Subchapter 1.2 Content
- Subchapter 1.2 Comments
- Subchapter 2 Content
- Subchapter 2 Comments
- Subchapter 3 Content
- Subchapter 2 Comments

That's working fine so far, but now I would like to automatically append these subchapters in to the wordpress menu with anchor links.

automatic appending

In my template each subchapter gets an id, which is build from the slug of this entry. (eg. id="subchapter-1-introduction")

My wp_nav_menu consists only of the 3 pages:

- Chapter 1
- Chapter 2
- Chapter 3

And I would like to create a menu link this (url in parenthesis) :

- Chapter 1 (/chapter1/)
  - Subchapter 1 Introduction (/chapter1/#subchapter1-introduction)
    - Subchapter 1.1 (/chapter1/#subchapter1-1)
  - Subchapter 2 (/chapter1/#subchapter2)
  - Subchapter 3 (/chapter1/#subchapter3)
- Chapter 2 (/chapter1/)
  ...
- Chapter 3 (/chapter1/)

Now I tried to build this structure by using the filter wp_get_nav_menu_items and alter the WP nav menu structure. But I was only able to build 1 level below the page. I was not able to build the hierarchical structure.

no automatic appending

So then I thought okay, we don't wan't automatic menu appending and it would be better to use a custom walker. Because I also need the wordpress menu classes like current-menu-item and so on.

I added the page/cpt structure in the Wordpress Backend Menu Section. And this gives me a nice menu, but now the permalinks are not working like expecting with anchor tags (described above)

I tried to alter the start_el function from Walker_Nav_Menu like this:

  if ( $depth > 0) {
    // create link to page with anchor
    $atts['href'] = $permalinkFromParentPage . '/#' $slugFromSubChapter .        
  } else {
    // were on level 0, only the page link
    $atts['href'] = ! empty( $item->url ) ? $item->url : '';
  }

But in this case, I don't know to get the $permalinkFromParentPage, because in start_el I only have informations about the actual menu item.

How could I fix this, or is there a better solution? I know that I can use custom links, but there are too many subchapters, so I would prefer the "automatic" menu appending with wordpress menu classes.

1

1 Answers

1
votes

Add these functions to your theme's 'functions.php' (assuming 'chapter' as your custom post type).

class Walker_Dynamic_Submenu extends Walker_Nav_Menu {
    function end_el(&$output, $item, $depth=0, $args=array()) { // function for first level posts
        if( 100 == $item->ID ){ // replace with your menu item ID
            global $post;
            $chapters = get_posts(array('post_type'=>'chapter','posts_per_page'=>-1, 'post_parent' => 0));
            if(!empty($chapters)) {
                $output .= '<ul class="sub-menu">';
                foreach($chapters as $post): setup_postdata($post);
                    $output .= '<li><a href="'.get_permalink().'">'.get_the_title().'</a>';
                    $output .= get_child_posts(get_the_ID());
                    $output .= '</li>';
                endforeach; wp_reset_postdata();
                $output .= '</ul>';
            }           
        }
        $output .= "</li>\n";
    }
}

function get_child_posts($parent = 0) { // function to retrieve child posts
    global $post;
    $chapterschild = get_posts(array('post_type'=>'chapter','posts_per_page'=>-1, 'post_parent' => $parent));
    if(!empty($chapterschild)) {
        $outputchild .= '<ul class="sub-menu">';
        foreach($chapterschild as $post): setup_postdata($post);
            $outputchild .= '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
            $outputchild .= get_child_posts(get_the_ID());
        endforeach; wp_reset_postdata();
        $outputchild .= '</ul>';
    }   
    return $outputchild;
}

and append this to your wp_nav_menu() - , 'walker' => new Walker_Dynamic_Submenu like wp_nav_menu( array( 'theme_location' => 'top', 'menu_id' => 'top-menu', 'walker' => new Walker_Dynamic_Submenu ) );.