Naveed Abbas
Naveed Abbas

Reputation: 1187

Wordpress Swap Primary Menu from Menu

Scenario:

I want to faciliate the user to choose from two different menus to be used as his/her primary menu.

I created two menus, and an Entry in both menus to switch to each other (Switch to B) (Switch to A).

The idea is that when a menu item is pressed, a wordpress function is called to switch the menu. Since I have already created the menus, they have specific IDs to choose from. All I want to hook specific function on clicking the (menu entries created in each menu) to swap the primary menu.

------------ EDIT ------------

My Approach

My Approach so far is as follows.

  1. Created a template named Menu_Switch and created a wordpress page based on that template.

  2. Called a function in that template.

  3. I created the menu entry with that newly created page in both menus.

The function is as follows.

function switch_menu ( $args = '' ) {

    if( $args['theme_location'] == 'primary') {

        if ($args['menu'] == '45') {
            $args['menu'] = '65';
        }  else if ($args['menu'] == '65') {
            $args['menu'] = '45';
        }

        return $args;
    }

    $redirect = home_url();

}

AND then called the function in the template like this

<?php echo switch_menu(); ?>

Question

This code is not working as expected. Following is expected.

  1. If the ID of primary menu is 45, it should set it to 65 and vise-versa.
  2. (Since the switch template is blank) The page should redirect either to previous page or the Home page.

Upvotes: 1

Views: 1106

Answers (2)

Prafulla Kumar Sahu
Prafulla Kumar Sahu

Reputation: 9693

I think you are searching for a filter where you can toggle your main menu.

If you will go through wp_nav_menu() source code

There is a filter $args = apply_filters( 'wp_nav_menu_args', $args ); and this $args array structure is

$defaults = array(
        'menu'                 => '',
        'container'            => 'div',
        'container_class'      => '',
        'container_id'         => '',
        'container_aria_label' => '',
        'menu_class'           => 'menu',
        'menu_id'              => '',
        'echo'                 => true,
        'fallback_cb'          => 'wp_page_menu',
        'before'               => '',
        'after'                => '',
        'link_before'          => '',
        'link_after'           => '',
        'items_wrap'           => '<ul id="%1$s" class="%2$s">%3$s</ul>',
        'item_spacing'         => 'preserve',
        'depth'                => 0,
        'walker'               => '',
        'theme_location'       => '',
    );

You can notice there is one key menu_id, if you can set that and apply this filter your menu will change based on the menu_id given.

something like

add_filter('wp_nav_menu_args', function(){
    $args['menu_id'] = <desired_menu_id>
    return $args;
});

Upvotes: 0

Ivan Frolov
Ivan Frolov

Reputation: 476

I don't think if that possible to do with way what you want - I mean changing location on fly, due it affects to whole site for all users.
You could to do it with next logic:

  1. display both menus on front, one of them will be with display: none
  2. when user selected another menu - change some html class (it's good - in body element), apply CSS to hide one menu and display another
  3. store it's state in cookie for user will sees selected menu across all pages and when he back to site

UPDATE
I mean that you can to create two locations and display them next to each other on frontend - and in this case you can to create two different menus and to assign to different locations. Visually it will be like two menus in one place.

Please see example: enter image description here

enter image description here

And using cookie and CSS you can to display one or another menu.

UPDATE 2
Full solution(tested on real WordPress site):

  1. Create two locations for menus
register_nav_menus(
    array(
        'header_top_nav'        => __( 'Header Top Area', 'starter' ),
        'header_main_nav'       => __( 'Header Main Area', 'starter' )
    )
);
  1. Create two menus, assign for locations above. Add to menus trigger buttons with html classes js_btn_show_menu_a and js_btn_show_menu_b which will be used for handle click in js
  2. Display these menus on front:
<nav class="menu_a">
   <?php
       wp_nav_menu(
           array(
               'theme_location' => 'header_top_nav'
           )
       );
   ?>
</nav>
<nav class="menu_b">
   <?php
       wp_nav_menu(
           array(
               'theme_location' => 'header_main_nav'
           )
       );
   ?>
</nav>
  1. Add js for trigger classes and set cookie
$( document ).on( 'click', '.js_btn_show_menu_a', function ( e ) {
    e.preventDefault();
    $( 'html' ).addClass( 'show_menu_a' ).removeClass( 'show_menu_b' );
    Cookies.set( 'menu', 'show_menu_a' );
})
$( document ).on( 'click', '.js_btn_show_menu_b', function ( e ) {
    e.preventDefault();
    $( 'html' ).addClass( 'show_menu_b' ).removeClass( 'show_menu_a' );
    Cookies.set( 'menu', 'show_menu_b' );
})
  1. Get cookie on backend and setup it as html class on tag <html>
$menu_cookie = htmlspecialchars( $_COOKIE['menu'] ) ? htmlspecialchars( $_COOKIE['menu'] ) : 'show_menu_a';
<html class="<?php echo esc_attr( $menu_cookie ); ?>">
  1. Add css for display/hide menus based on css class
.show_menu_a .menu_a {display: block;}
.show_menu_a .menu_b {display: none;}
.show_menu_b .menu_b {display: block;}
.show_menu_b .menu_a {display: none;}

Upvotes: 1

Related Questions