2

Is it possible to add a sidebar to navigation menu?

I'd like to be able to add sidebars in Appearance > Menus, like I add pages.

I have a way of creating extra sidebars, so that's not an issue (I could also just register several dedicated sidebars if need be).

Basically I need a way to display widgets in menu, without using any extra plugins.

Is something like that possible? Do I need to extend Walker_Nav_Menu?

EDIT

My menu_walker.php looks like this:

// Allow HTML descriptions in WordPress Menu
remove_filter( 'nav_menu_description', 'strip_tags' );

function my_plugin_wp_setup_nav_menu_item( $menu_item ) {
    if ( isset( $menu_item->post_type ) && 'nav_menu_item' == $menu_item->post_type) {
        $menu_item->description = apply_filters( 'nav_menu_description', $menu_item->post_content );
    }

    return $menu_item;
}

add_filter( 'wp_setup_nav_menu_item', 'my_plugin_wp_setup_nav_menu_item' );

// Menu without icons
class theme_walker_nav_menu extends Walker_Nav_Menu {

    public function display_element($el, &$children, $max_depth, $depth = 0, $args, &$output){
        $id = $this->db_fields['id'];

        if(isset($children[$el->$id])){
            $el->classes[] = 'has_children';
        }

        parent::display_element($el, $children, $max_depth, $depth, $args, $output);
    }

    // add classes to ul sub-menus
    function start_lvl( &$output, $depth = 0, $args = array() ) {
        // depth dependent classes
        $indent = ( $depth > 0  ? str_repeat( "\t", $depth ) : '' ); // code indent
        $display_depth = ( $depth + 1); // because it counts the first submenu as 0
        $classes = array(
            'navi',
            ( $display_depth ==1 ? 'first' : '' ),
            ( $display_depth >=2 ? 'navi' : '' ),
            'menu-depth-' . $display_depth
            );
        $class_names = implode( ' ', $classes );

        // build html
        $output .= "\n" . $indent . '<ul class="' . esc_attr($class_names) . '">' . "\n";
    }

    // add main/sub classes to li's and links
     function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        global $wp_query;
        $indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent

        static $is_first;
        $is_first++;
        // depth dependent classes
        $depth_classes = array(
            ( $depth == 0 ? 'main-menu-item' : '' ),
            ( $depth >=2 ? 'navi' : '' ),
            ( $is_first ==1 ? 'menu-first' : '' ),
            'menu-item-depth-' . $depth
        );
        $depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
        // passed classes
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );

        $is_mega_menu = (strpos($class_names,'mega') !== false) ? true : false;
        $use_desc = (strpos($class_names,'use_desc') !== false) ? true : false;
        $no_title = (strpos($class_names,'no_title') !== false) ? true : false;

        if(!$is_mega_menu){
            $class_names .= ' normal_menu_item';
        }

        // build html
        $output .= $indent . '<li id="nav-menu-item-'. esc_attr($item->ID) . '" class="' . esc_attr($depth_class_names) . ' ' . esc_attr($class_names) . '">';
        // link attributes
        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' href="' . (($item->url[0] == "#" && !is_front_page()) ? home_url() : '') . esc_attr($item->url) .'"' : '';

        $attributes .= ' class="menu-link '.((strpos($item->url,'#') === false) ? '' : 'scroll').' ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';

        $html_output = ($use_desc) ? '<div class="description_menu_item">'.wp_kses($item->description, allowed_tags()).'</div>' : '';
        $item_output = (!$no_title) ? '<a ' . $attributes . '><span>' . apply_filters( 'the_title', $item->title, $item->ID ) . '</span></a>'.$html_output : $html_output;
        // build html
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ).(($is_mega_menu)?'<div class="sf-mega"><div class="sf-mega-inner clearfix">':'');
    }

    function end_el( &$output, $item, $depth = 0, $args = array() ) {

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );

        $is_mega_menu = (strpos($class_names,'mega') !== false) ? true : false;

        $output .= (($is_mega_menu)?'</div></div>':'') . "</li>\n";
    }

}

I also have jquery code that will add the dropdown menu for choosing how many columns I have in megamenu:

jQuery(document).ready(function($) {
    "use strict";

    var $depth_zero = $('#menu-to-edit').find('.menu-item-depth-0');
    var $depth_one = $('#menu-to-edit').find('.menu-item-depth-1');

    var i = 0;
    $depth_zero.find('.field-description').each(function(){
        i++;
        $(this).before('<p class="field-additional description-wide"><label for="add_mega'+i+'">Menu Type<br><select id="add_mega'+i+'" class="additional_input add_mega"><option value="">Default Standard Menu</option><option value="mega1">Mega Menu - Single Column</option><option value="mega2">Mega Menu - 2 Columns</option><option value="mega3">Mega Menu - 3 Columns</option><option value="mega4">Mega Menu - 4 Columns</option><option value="mega5">Mega Menu - 5 Columns</option><option value="mega6">Mega Menu - 6 Columns</option><option value="mega7">Mega Menu - 7 Columns</option></select></p>');
        var classes = $(this).siblings('.field-css-classes').find('input').val();
        var current_c;
        for (var c = 1; c <= 7; c++) {
            current_c = 'mega'+c;
            if(classes.indexOf(current_c) >= 0) {
                $(this).siblings('.field-additional').find('select').val(current_c);
            }
        }
    });

    $depth_one.find('.field-description').each(function(){
        i++;
        var use_desc_state = ($(this).siblings('.field-css-classes').find('input').val().indexOf('use_desc') >= 0) ? ' checked' : '';
        var no_title_state = ($(this).siblings('.field-css-classes').find('input').val().indexOf('no_title') >= 0) ? ' checked' : '';
        $(this).before('<p class="field-additional description-wide"><br><label for="use_desc'+i+'"><input type="checkbox" id="use_desc'+i+'" class="additional_input use_desc" value="use_desc"'+use_desc_state+'>Use description field as HTML content<br></label><label for="no_title'+i+'"><input type="checkbox" id="no_title'+i+'" class="additional_input no_title" value="no_title"'+no_title_state+'>Hide title</label></p>');
    });

    $('.additional_input, .edit-menu-item-classes').change(function() {
        var $parent_item = $(this).closest('.menu-item');
        define_classes($parent_item);
    });

    function define_classes($item){
        var $class_field = $item.find('.field-css-classes input');
        var current_class_value = $class_field.val().replace('use_desc','').replace('no_title','').replace('mega1','').replace('mega2','').replace('mega3','').replace('mega4','').replace('mega5','').replace('mega6','').replace('mega7','').replace('  ',' ');

        var new_class_value = [];

        new_class_value.push(current_class_value.trim());

        if($item.find('.add_mega').length > 0 && $item.find('.add_mega').val() !== ''){
            new_class_value.push($item.find('.add_mega').val());
        }

        if($item.find('.use_desc').length > 0 && $item.find('.use_desc').is(':checked')){
            new_class_value.push('use_desc');
        }

        if($item.find('.no_title').length > 0 && $item.find('.no_title').is(':checked')){
            new_class_value.push('no_title');
        }

        $class_field.val(new_class_value.join(' ').trim());

    }


});

I tried adding this code to extend my memgamenu, but nothing happens.

If I can't show sidebars here, would it be possible to just add shortcodes in my description field? How would I do this?

When I put the shortcode in the description field, nothing happens. Any help is appereciated.

EDIT

Found a different way. I've added a metabox to Menus page that lists all my sidebars, and then I put the content of the sidebars in the descreption field (you need to disable or edit the wp_kses() function on the description field so that it doesn't strip everything). The function looks like this:

<?php

if ( !class_exists('sidebars_custom_menu')) {
    class sidebars_custom_menu {
        public function add_nav_menu_meta_boxes() {
            add_meta_box(
                'sidebar_menu_add',
                esc_html__('Add Sidebar', 'theme'),
                array( $this, 'nav_menu_link'),
                'nav-menus',
                'side',
                'low'
            );
        }

        public function nav_menu_link() {?>
            <div id="posttype-sidebars" class="posttypediv">
                <div id="tabs-panel-sidebars" class="tabs-panel tabs-panel-active">
                    <ul id ="sidebars-checklist" class="categorychecklist form-no-clear">
                    <?php $i = 0; ?>
                    <?php foreach ( $GLOBALS['wp_registered_sidebars'] as $sidebar ) { ?>
                    <?php
                        $i++;
                        ob_start();
                        dynamic_sidebar($sidebar['id']);
                        $sidebar_html = ob_get_contents();
                        ob_end_clean();
                    ?>
                        <li>
                            <label class="menu-item-title">
                                <input type="checkbox" class="menu-item-checkbox" name="menu-item[-<?php echo $i; ?>][menu-item-object-id]" value="<?php echo $sidebar['id']; ?>"> <?php echo ucwords( $sidebar['name'] ); ?>
                            </label>
                            <input type="hidden" class="menu-item-type" name="menu-item[-<?php echo $i; ?>][menu-item-type]" value="custom">
                            <input type="hidden" class="menu-item-title" name="menu-item[-<?php echo $i; ?>][menu-item-title]" value="<?php echo ucwords( $sidebar['name'] ); ?>">
                            <input type="hidden" class="menu-item-url" name="menu-item[-<?php echo $i; ?>][menu-item-url]" value="">
                            <input type="hidden" class="menu-item-classes" name="menu-item[-<?php echo $i; ?>][menu-item-classes]" value="menu_sidebar use_desc">
                            <input type="hidden" class="menu-item-description" name="menu-item[-<?php echo $i; ?>][menu-item-description]" value="<?php echo htmlentities($sidebar_html); ?>">
                        </li>
                    <?php } ?>
                    </ul>
                </div>
                <p class="button-controls">
                    <span class="list-controls">
                        <a href="/wordpress/wp-admin/nav-menus.php?page-tab=all&amp;selectall=1#posttype-page" class="select-all"><?php esc_html_e('Select All', 'theme'); ?></a>
                    </span>
                    <span class="add-to-menu">
                        <input type="submit" class="button-secondary submit-add-to-menu right" value="<?php esc_html_e('Add to Menu', 'theme');?>" name="add-post-type-menu-item" id="submit-posttype-sidebars">
                        <span class="spinner"></span>
                    </span>
                </p>
            </div>
        <?php }
    }
}

$custom_nav = new sidebars_custom_menu;

add_action('admin_init', array($custom_nav, 'add_nav_menu_meta_boxes'));

Original code from here

3
  • Hello, If you don't add it as a plugin, how do you intend to do it? Your menu-walker.php is already a plugin?
    – pSyToR
    Jun 9, 2015 at 9:05
  • My menu walker.php is just an extension of a Walker_Nav_Menu. I've found a way to add a sidebar list in my Menus page, now I only need to find out how to output html of a sidebar in a description field, and I think that should be it. I'm working on it atm :)
    – dingo_d
    Jun 9, 2015 at 9:20
  • The only thing that is bothering me is that when I update the sidebar (or widget in the sidebar) I don't get updated widget in the menu...
    – dingo_d
    Jun 9, 2015 at 10:50

4 Answers 4

1

might it can help you for your query :

Basically I need a way to display widgets in menu, without using any extra plugins.

place the code in your theme’s functions.php

<?php

register_sidebar( array(
    'name' => 'Page Menu',
    'id' => 'page-menu',
    'before_widget' => '<div id="page-nav">',
    'after_widget' => '</div>',
    'before_title' => false,
    'after_title' => false
) );

add_filter( 'wp_page_menu', 'my_page_menu' );

function my_page_menu( $menu ) {
    dynamic_sidebar( 'page-menu' );
}

?>

for reference Placing widget to menu and

http://justintadlock.com/archives/2009/04/15/how-to-widgetize-your-page-menu-in-wordpress

1
  • 1
    Yeah I tried this, but with no luck. I've found a way how to do it, now it's just the matter of question how to correctly output it. Still tweaking it, when I'm done I'll post the answer :)
    – dingo_d
    Jun 9, 2015 at 10:25
1

The solution I've wanted looks like this:

<?php


// Allow HTML descriptions in WordPress Menu
remove_filter( 'nav_menu_description', 'strip_tags' );

function my_plugin_wp_setup_nav_menu_item( $menu_item ) {
    if ( isset( $menu_item->post_type ) && 'nav_menu_item' == $menu_item->post_type) {
        $menu_item->description = apply_filters( 'nav_menu_description', $menu_item->post_content );
    }

    return $menu_item;
}

add_filter( 'wp_setup_nav_menu_item', 'my_plugin_wp_setup_nav_menu_item' );

// Menu
class my_theme_walker_nav_menu extends Walker_Nav_Menu {

    public function display_element($el, &$children, $max_depth, $depth = 0, $args, &$output){
        $id = $this->db_fields['id'];

        if(isset($children[$el->$id])){
            $el->classes[] = 'has_children';
        }

        parent::display_element($el, $children, $max_depth, $depth, $args, $output);
    }

    // add classes to ul sub-menus
    function start_lvl( &$output, $depth = 0, $args = array() ) {
        // depth dependent classes
        $indent = ( $depth > 0  ? str_repeat( "\t", $depth ) : '' ); // code indent
        $display_depth = ( $depth + 1); // because it counts the first submenu as 0
        $classes = array(
            'navi',
            ( $display_depth == 1 ? 'first' : '' ),
            ( $display_depth >= 2 ? 'navi' : '' ),
            'menu-depth-' . $display_depth
            );
        $class_names = implode( ' ', $classes );

        // build html
        $output .= "\n" . $indent . '<ul class="' . esc_attr($class_names) . '">' . "\n";
    }

    // add main/sub classes to li's and links
     function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
        global $wp_query;
        $indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent

        static $is_first;
        $is_first++;
        // depth dependent classes
        $depth_classes = array(
            ( $depth == 0 ? 'main-menu-item' : '' ),
            ( $depth >= 2 ? 'navi' : '' ),
            ( $is_first == 1 ? 'menu-first' : '' ),
            'menu-item-depth-' . $depth
        );
        $depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
        // passed classes
        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );

        $is_mega_menu = (strpos($class_names,'mega') !== false) ? true : false;
        $use_desc = (strpos($class_names,'use_desc') !== false) ? true : false;
        $is_sidebar = (strpos($class_names,'menu_sidebar') !== false) ? true : false;
        $no_title = (strpos($class_names,'no_title') !== false) ? true : false;

        if(!$is_mega_menu){
            $class_names .= ' normal_menu_item';
        }

        // build html
        $output .= $indent . '<li id="nav-menu-item-'. esc_attr($item->ID) . '" class="' . esc_attr($depth_class_names) . ' ' . esc_attr($class_names) . '">';
        // link attributes
        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' href="' . (($item->url[0] == "#" && !is_front_page()) ? home_url() : '') . esc_attr($item->url) .'"' : '';

        $attributes .= ' class="menu-link '.((strpos($item->url,'#') === false) ? '' : 'scroll').' ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';

        $html_output = ($use_desc) ? '<div class="description_menu_item">'.wp_kses($item->description, allowed_tags()).'</div>' : '';



        if ($is_sidebar) {
            ob_start();
            dynamic_sidebar($item->description);
            $sidebar_html = ob_get_clean();

            $sidebar_output = '<div class="sidebar_menu_item">'.$sidebar_html.'</div>';

            $item_output = $sidebar_output;

        } else{
            $item_output = (!$no_title) ? '<a ' . $attributes . '><span>' . apply_filters( 'the_title', $item->title, $item->ID ) . '</span></a>'. $html_output : $html_output;
        }


        // build html
        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args ).(($is_mega_menu)?'<div class="sf-mega"><div class="sf-mega-inner clearfix">':'');
    }

    function end_el( &$output, $item, $depth = 0, $args = array() ) {

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );

        $is_mega_menu = (strpos($class_names,'mega') !== false) ? true : false;

        $output .= (($is_mega_menu)?'</div></div>':'') . "</li>\n";
    }

}

//Sidebars in Menu

if ( !class_exists('sidebars_custom_menu')) {
    class sidebars_custom_menu {
        public function add_nav_menu_meta_boxes() {
            add_meta_box(
                'sidebar_menu_add',
                esc_html__('Add Sidebar', 'theme'),
                array( $this, 'nav_menu_link'),
                'nav-menus',
                'side',
                'low'
            );
        }

        public function nav_menu_link() {?>
            <div id="posttype-sidebars" class="posttypediv">
                <div id="tabs-panel-sidebars" class="tabs-panel tabs-panel-active">
                    <ul id ="sidebars-checklist" class="categorychecklist form-no-clear">
                        <?php
                        $i = -1;
                        foreach ( $GLOBALS['wp_registered_sidebars'] as $sidebar ) {
                            ob_start();
                            dynamic_sidebar($sidebar['id']);
                            $sidebar_html = ob_get_clean();
                            ?>
                            <li>
                                <label class="menu-item-title">
                                    <input type="checkbox" class="menu-item-checkbox" name="menu-item[<?php echo esc_attr($i); ?>][menu-item-object-id]" value="<?php echo $sidebar['id']; ?>"> <?php echo ucwords( $sidebar['name'] ); ?>
                                </label>
                                <input type="hidden" class="menu-item-type" name="menu-item[<?php echo esc_attr($i); ?>][menu-item-type]" value="custom">
                                <input type="hidden" class="menu-item-attr-title" name="menu-item[<?php echo esc_attr($i); ?>][menu-item-attr-title]" value="<?php echo ucwords( $sidebar['name'] ); ?>">
                                <input type="hidden" class="menu-item-title" name="menu-item[<?php echo esc_attr( $i ); ?>][menu-item-title]" value="&nbsp;" />
                                <input type="hidden" class="menu-item-url" name="menu-item[<?php echo esc_attr($i); ?>][menu-item-url]" value="">
                                <input type="hidden" class="menu-item-classes" name="menu-item[<?php echo esc_attr($i); ?>][menu-item-classes]" value="menu_sidebar">
                                <input type="hidden" class="menu-item-description" name="menu-item[<?php echo esc_attr($i); ?>][menu-item-description]" value="<?php echo $sidebar['id']; ?>">
                            </li>
                            <?php
                            $i --;
                        }
                        ?>
                    </ul>
                </div>
                <p class="button-controls">
                    <span class="list-controls">
                        <a href="<?php echo admin_url( 'nav-menus.php?page-tab=all&amp;selectall=1#posttype-sidebars' ); ?>" class="select-all"><?php esc_html_e('Select All', 'theme'); ?></a>
                    </span>
                    <span class="add-to-menu">
                        <input type="submit" class="button-secondary submit-add-to-menu right" value="<?php esc_html_e('Add to Menu', 'theme');?>" name="add-post-type-menu-item" id="submit-posttype-sidebars">
                        <span class="spinner"></span>
                    </span>
                </p>
            </div>
        <?php }
    }
}

$custom_nav = new sidebars_custom_menu;

add_action('admin_init', array($custom_nav, 'add_nav_menu_meta_boxes'));

This will create a list of sidebars that you can put in the menu, and they will have a class menu_sidebar that you can use to style your widgets if you want.

Hope this helps someone who wants the same.

1

In response to whether it is possible to add shortcodes in the description field. This is what worked for me. Add this to functions.php and then shortcodes should work.

add_filter( 'term_description', 'do_shortcode' );
-1
add_filter( 'wp_nav_menu_items', 'add_sidebar_output_to_menu998722', 10, 2 );
function add_sidebar_output_to_menu998722( $items, $args ) {
   if ($args->theme_location == 'nav-location') {
         $items .= dynamic_sidebar($sidebar['id']);

    }
}
1
  • 2
    Answers should be more than a code snippet. Please file an edit and explain why this would work.
    – Gabriel
    Jun 13, 2015 at 4:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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