Faiz Ali
Faiz Ali

Reputation: 133

How to automatically add Categories & Sub Categories in Wordpress nav menu

i have a long list of categories and sub categories and even a sub categories of sub categories and it take so much time to pick one by one in menu section of wordpress and then re-arrange the hierarchy of categories and their sub categories

I search about it and i did not find anything helping about this so I was wondering if any of your guys can help me with any function or suggest me any plugin which can add these categories in menu automatically

Thanks

Upvotes: 6

Views: 13285

Answers (3)

A. D'Alfonso
A. D'Alfonso

Reputation: 789

If someone is still looking for a solution without a plugin, I got this working version using the wp_nav_menu walker.

Basically, I place only first level category in my Appearence > Menu and I loop through posts of those categories in my start_el function.

Here my walker function:

class AWP_Menu_Walker extends Walker_Nav_Menu {

    function start_el(&$output, $item, $depth=0, $args=[], $id=0) {
        $open = '';
        $current = '';
        $sub_menu = '';
        $menuItemFont = 'font-sans text-sm font-light ';
        $subMenuItemFont = 'text-sm font-sans font-light ';
        $current_element_array = array( 'current-menu-item' );
        $current_element_markers = array( 'current-menu-item', 'current-menu-parent', 'current-menu-ancestor' );
        $current_class = array_intersect( $current_element_markers, $item->classes );
        $current_element = array_intersect( $current_element_array, $item->classes );

        if ($item->object == 'category') {
            $category_slug = get_category($item->object_id);
            $args = array(
                'tag' => get_queried_object()->slug,
                'post_status' => 'publish',
                'posts_per_page' => -1,
                'orderby' => 'menu_order',
                'order' => 'ASC',
                'tax_query' => array(
                    array(
                            'taxonomy' => 'category',
                            'field'    => 'slug',
                            'terms'    => $category_slug->slug, // here I get the slug of indexed category 
                    ),
                )
            );
            $posts = get_posts( $args );
            $current_url = get_permalink();
            foreach ($posts as $post) :
                $post_url = get_permalink($post->ID);
                if ($post_url == $current_url) {
                    $current = 'text-red-500 ';
                }
                $sub_menu .= '<li class="select-none my-2 truncate- leading-tight ' . $current . $subMenuItemFont . ' px-4 pl-6"><a title="' . esc_html($post->post_title) . '" href="' . $post_url . '">' . esc_html($post->post_title) . '</a></li>';
            endforeach;
        }

        // conditional styles for menu items
        if (!empty($current_element)) {
            $menuItemFont .= 'text-red-500 ';
            $subMenuItemFont .= 'text-red-500 ';
        } else {
            $menuItemFont .= 'text-zinc-800 ';
            $subMenuItemFont .= 'text-zinc-600 ';
        }

        // This set the <details> open if current item is whitin
        if (!empty($current_class)) {
            $open = 'open';
        }

        if (!$args->walker->has_children) {
            if ($item->menu_item_parent == 0){
                if ($item->object == 'category') {
                    $output .= '<details ' . $open . ' class="' . $menuItemFont . ' pl-4">';
                    $output .= '<summary class="select-none cursor-pointer truncate- ' . $menuItemFont . $color . $current . '"><span class="pl-4">' . esc_html($item->title) . '</span></summary>';
                    $output .= $sub_menu;
                } else {
                    $output .= '<li class="select-none truncate- ' . $current . $menuItemFont . $color . ' pl-8 pr-2"><a title="' . esc_html($item->title) . '" href="' . esc_url($item->url) . '">' . esc_html($item->title) . '</a></li>';
                }
            }
        } else {
            $output .= '<details ' . $open . ' class="' . $menuItemFont . ' pl-4">';
            $output .= '<summary class="select-none cursor-pointer truncate- ' . $menuItemFont . $color . $current . '"><span class="pl-4">' . esc_html($item->title) . '</span></summary>';
        }
    }

    function end_el(&$output, $item, $depth = 0, $args = Array()){ // closing li a span
        if ($item->menu_item_parent == 0){
            $output .= '</details>';
        }
        if ($args->walker->has_children) {
            $output .= '</details>';
        }
    }
}
/* Walker nav menu */

Then I call this in my template:

    wp_nav_menu(
    array(
        'theme_location' => 'menu-1',
        'menu_id'        => 'primary-menu',
        'items_wrap'     => '<ul id="%1$s" class="%2$s font-display flex flex-col gap-1" aria-label="submenu">%3$s</ul>',
        'walker'         => new AWP_Menu_Walker(),
    )
);

I set my categories in the menu:

I set my categories in the menu

This is the result:

This is the result

Upvotes: 0

Roman Potashkin
Roman Potashkin

Reputation: 41

I confirm a solution with a JC Submenu plugin. Works perfect. I used the Astra theme and add a filter in theme functions.php to work on it.

//Enable compatibility with theme custom menu walkers

add_filter('jcs/enable_public_walker', 'jc_disable_public_walker');

function jc_disable_public_walker($default){
    return false;
}

Upvotes: 4

SandeepTete
SandeepTete

Reputation: 315

There's a plugin: https://wordpress.org/plugins/jc-submenu/

Its old but still works in some themes.

Upvotes: 4

Related Questions