This website uses cookies to allow us to see how the site is used. If you continue to use this site, we assume that you are okay with this. If you want to use the sites without cookies, please see our privacy policy.

Automatically Add Child Pages to Menus

To create a menu in WordPress, you have to create your pages, and then hop over to Appearance->Menus to set up your menu hierarchy. I’ve always wondered why menus are not intrinsically tied to page hierarchies. There is a ‘Parent Page’ setting on the Page Edit screen, so why not use it for your menu hierarchy? If the parent page is in your menu, child pages could be automatically added to the menu. Doing so has the added bonus of setting your hierarchy for things like Yoast breadcrumbs and menus in the same place so they always match, and changes don’t need to be made in two places.

To automatically add child pages to a menu, we can use the filter hook: nav_menu_item_args. The filter is called for each top level page added to the menu you are displaying with WordPress’ wp_nav_menu() function. We’ll check each top level page to see if it has children, get the children with wp_list_pages(), and add them to the unordered list.

if ( ! function_exists( 'aacpm_add_sub_pages_toggles_to_main_menu' ) ) {
    function aacpm_add_sub_pages_toggles_to_main_menu( $args, $item, $depth ) {
        
        //You could check the $args->theme_location to determine if child pages should be automatically added to this menu or not.
        // if ( $args->theme_location == 'primary' ) {
            $children = null;
            
            $args2 = array('depth'   => 1, //only 1 level of children
                'child_of'           => $item->object_id, // Note $object->ID is menu id and not post id
                'echo'               => 0,
                'title_li'           => '',
                'sort_column' => 'menu_order' //you'll need https://wordpress.org/plugins/simple-page-ordering/ to order your child pages
            );
            $children = wp_list_pages($args2);                            

            if ( $children ) {
                //You might want to add additional markup to your menus to add things like toggles to open/close submenus, etc. Add with $args->before or $args->after                

                //Child pages are added to the menu with this line
                $args->after = '<ul class="sub-menu">' . $children . '</ul>';
            }  
        //} // end theme_location check
        return $args;
    }

    //add function to the nav_menu_item_args filter
    add_filter( 'nav_menu_item_args', 'aacpm_add_sub_pages_toggles_to_main_menu', 999, 3 );

}

In the wp_list_pages() $args2, I used ‘sort_column’ => ‘menu_order’. To set the menu_order, you’ll need a plugin. I use the ‘Simple Page Ordering’ plugin: https://wordpress.org/plugins/simple-page-ordering/ The ‘Simple Page Ordering’ plugin adds the ability to reorder your pages by drag and drop in the Admin Pages List (/wp-admin/edit.php?post_type=page). Now your editors can set the menu hierarchy and order sub pages without hopping over to Appearance -> Menus.

Using the code above, the CSS classes on the child list items are different from the default Appearance-> Menus submenu classes. For example, active child menus get the class ‘current_page_item’ only instead of both ‘current-menu-item current_page_item’. You might need to edit your CSS to highlight active child pages in the menu.

If you want to add a class to the parent list item to match the ‘menu-item-has-children’ class added with the default Appearance->Menus, hook into the nav_menu_css_class filter:

if ( ! function_exists( 'aacpm_add_parent_class_to_menu' ) ) {

    function aacpm_add_parent_class_to_menu($classes, $item, $args, $depth){
        if($depth != 1 ){ //if depth == 1 don't display child pages
            $children = get_pages( array( 'child_of' => $item->object_id ) );
            if($children){
                $classes[] = 'menu-item-has-children';
            }
        }
        return $classes;
    }

    add_filter( 'nav_menu_css_class', 'aacpm_add_parent_class_to_menu', 999, 4);
}

You can add this code to your functions.php or create a plugin. I put together a small plugin you can download here. The plugin also adds the ability for Editors to access the Appearance menu ( edit_theme_options ) so they can change/reorder the top level menu pages, edit widgets, and change theme settings. Changing menus and editing widget content are things I usually want Editors to be able to do, but I don’t want to give them Administrator access to change/add plugins or site settings.

With this code, your Editors only need to set the top level pages in their Menu. Child pages (pages with a ‘Parent Page’ set to a top level page in the Menu) will automatically be added to their menus.