phpwordpressloopswp-nav-menu-item

Wordpress - Showing custom menu links while showing child pages


I have this loop that simply shows all child pages of the current page:

<?php 
  $args = array(
        'parent' => $post->ID,
        'post_type' => 'page',
        'sort_order' => 'ASC'
  ); 
  $pages = get_pages($args);  ?>

<?php foreach( $pages as $page ) { ?>

        <div>
            <p><?php echo $page->post_title; ?></p>
        </div>

<?php } ?>

The Nav for this page looks like this:

Parent Page
 - Child page
 - Child page
 - Child page
 - Custom Link (added in appearance > menus) 
 - Custom link (added in appearance > menus)
 - Page which has another parent (added in appearance > menus)

The code above correctly shows all of the direct child pages, but I would like it to show the custom links and other page I have added to the menu dropdown.

Ive tried playing with wp_get_nav_menu_items in place of get_pages and also using 'post_type' => 'page' but I can't seem to get this working correctly. I can either show a full list of all pages or just the direct child pages.

Can anyone tell me where I'm going wrong please? I seems like it should be a really easy thing to do...


Solution

  • Ok, I've found a way to get this to work using a custom walker class inside the functions.php file, like so:

    class Selective_Walker extends Walker_Nav_Menu
    {
        function walk( $elements, $max_depth) {
    
            $args = array_slice(func_get_args(), 2);
            $output = '';
    
            if ($max_depth < -1) //invalid parameter
                return $output;
    
            if (empty($elements)) //nothing to walk
                return $output;
    
            $id_field = $this->db_fields['id'];
            $parent_field = $this->db_fields['parent'];
    
            // flat display
            if ( -1 == $max_depth ) {
                $empty_array = array();
                foreach ( $elements as $e )
                    $this->display_element( $e, $empty_array, 1, 0, $args, $output );
                return $output;
            }
    
            /*
             * need to display in hierarchical order
             * separate elements into two buckets: top level and children elements
             * children_elements is two dimensional array, eg.
             * children_elements[10][] contains all sub-elements whose parent is 10.
             */
            $top_level_elements = array();
            $children_elements  = array();
            foreach ( $elements as $e) {
                if ( 0 == $e->$parent_field )
                    $top_level_elements[] = $e;
                else
                    $children_elements[ $e->$parent_field ][] = $e;
            }
    
            /*
             * when none of the elements is top level
             * assume the first one must be root of the sub elements
             */
            if ( empty($top_level_elements) ) {
    
                $first = array_slice( $elements, 0, 1 );
                $root = $first[0];
    
                $top_level_elements = array();
                $children_elements  = array();
                foreach ( $elements as $e) {
                    if ( $root->$parent_field == $e->$parent_field )
                        $top_level_elements[] = $e;
                    else
                        $children_elements[ $e->$parent_field ][] = $e;
                }
            }
    
            $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );  //added by continent7
            foreach ( $top_level_elements as $e ){  //changed by continent7
                // descend only on current tree
                $descend_test = array_intersect( $current_element_markers, $e->classes );
                if ( !empty( $descend_test ) ) 
                    $this->display_element( $e, $children_elements, 2, 0, $args, $output );
            }
    
            /*
             * if we are displaying all levels, and remaining children_elements is not empty,
             * then we got orphans, which should be displayed regardless
             */
             /* removed by continent7
            if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
                $empty_array = array();
                foreach ( $children_elements as $orphans )
                    foreach( $orphans as $op )
                        $this->display_element( $op, $empty_array, 1, 0, $args, $output );
             }
            */
             return $output;
        }
    }
    

    Then using this to my template page to simply the menu:

    <?php
    
    $menuParameters = array(
        'theme_location'    =>'primary',
        'walker'=>new Selective_Walker()
    );
    
    echo wp_nav_menu( $menuParameters );
    
    ?>
    

    This helpfully shows the current page title as well as ALL of the sub nav items, not just the page items.