I am trying to use a custom menu on my landingpage.
I used this code:
<?php
function change_wp_nav_menu_args($args = ''){
$pageID = get_the_id();
if($pageID == '63') //custom menu for site with id 63
{
$args['menu'] = 'homepage';
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'change_wp_nav_menu_args' );
?>
It works fine, but not only the main menu changes.
The footer menu changes also.
But the footer menu should be the same on every page.
How can I affect this?
This code fixed my problem:
<?php
add_filter( 'wp_nav_menu_args', 'bb_wp_nav_menu_args' );
function bb_wp_nav_menu_args( $args = '' ) {
// change the menu in the Header menu position
if( $args['theme_location'] == 'primary' && is_page('63') ) {
$args['menu'] = '6'; // 32 is the ID of the menu we want to use here
}
return $args;
}
?>
Its great that you find your answer, but it's a suggestion to make the code dynamic rather set the menu value as static [ $args['menu']='6' ].
Suggestion :
Create a Meta Box [ Dropdown with list of menu ] for Page with the Label Menu. And use the Menu Id for the wp_nav_menu .
For Dropdown [ listing Menus ]
function your_menus()
{
$menu_arr=NULL;
$menus=get_terms( 'nav_menu', array( 'hide_empty' => true ) );
$menu_arr['your-nomenu']='Default';
foreach ( $menus as $menu ){
$menu_arr[$menu->slug]=$menu->name;
}
return $menu_arr;
}//end of function
For Nav Menus : [ _your_page_menu : meta name ]. You can place the code inside a function and called it in Header or you can place this code directly into the header.
$page_menu_name=get_post_meta(get_the_ID(),'_your_page_menu',true)==''?'your-nomenu':get_post_meta(get_the_ID(),'_your_page_menu',true);
if($page_menu_name==='your-nomenu')
{
wp_nav_menu(array('theme_location' => 'primary','menu_id'=> 'main-menu','container'=>false,'fallback_cb'=>'','menu_class'=>'main-navigation'));
}
else
{
wp_nav_menu(array('menu_id'=> 'main-menu' , 'container'=>false, 'menu'=>$page_
menu_name,'fallback_cb'=>'','menu_class'=>'main-navigation'));
}
Hope it helps you.
Related
I've got a script that works.... a bit too well. It's supposed to be when you login to the site, the main nav reflects that switch. It works, but it's only supposed to occur on the nav in the header. Instead, it changes all nav elements, no matter where they are. So I have three other menus in the footer but they all change to the same menu.
How can I just target the main nav in my header alone?
Here's the code:
function my_wp_nav_menu_args( $args = '' ) {
if( is_user_logged_in() ) {
// Logged in menu to display
$args['menu'] = 80;
} else {
// Non-logged-in menu to display
$args['menu'] = 25;
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'my_wp_nav_menu_args' );
If you check the docs for that filter you will see that the $args that come have an index 'theme_location' where you can indicate, precisely in which menus your code should run.
You need the identifier for that menu, which can be something like 'primary' or 'main_menu' - whatever the theme author(s) decided to identify the theme location for the menu.
Log/check the $args variable to obtain the ones available in your theme, and identify the one you need.
So, if your header nav's id is, 'primary', your snippet should be updated to this, to check that it only runs for that menu and leaves the others alone:
function my_wp_nav_menu_args( $args = '' ) {
//If it is not the header nav menu, don't do anything
if( $args['theme_location'] !== 'primary' ){
return $args;
}
if( is_user_logged_in() ) {
// Logged in menu to display
$args['menu'] = 80;
} else {
// Non-logged-in menu to display
$args['menu'] = 25;
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'my_wp_nav_menu_args' );
This should work but let me know if you need more help.
My website is built with WordPress and I currently have 3 nav menus
The main menu - "Main"
A secondary top menu - "Player Logged-in"
Another secondary top menu - "Player Logged-out"
Ive added the script below to my functions.php
function my_wp_nav_menu_args( $args = '' ) {
if( is_user_logged_in() ) {
$args['menu'] = "Player Logged-in";
} else {
$args['menu'] = "Player Logged-out";
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'my_wp_nav_menu_args' );
It is working, the only problem is it replaces my "Main" menu with one of the secondary menus.
How would I go about it if I wanted the 2 secondary top menus to alternate if a user is logged in/out AND I wanted the "Main" menu to stay regardless of whether the user is logged in or not?
Thanks
I came right with this problem.
I looked for the specific menu locations (top_navigation) for my theme (Avada) and used this
function wpc_wp_nav_menu_args( $args = '' ) {
if( is_user_logged_in()) {
if( 'top_navigation' == $args['theme_location'] ) {
//top_navigation is specific to Avada in my case
$args['menu'] = 'Player Logged-in';
}
} else {
if( 'top_navigation' == $args['theme_location'] ) {
//again, top_navigation is specific to Avada in my case
$args['menu'] = 'Player Logged-out';
}
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'wpc_wp_nav_menu_args' );
the question is just on the title, but well here's the problem i tried this code on my function.php which at first works fine, but suddenly i realized that the menus on footer changed to be the same as the header menus.
here is the code :
function wpc_wp_nav_menu_args( $args = '' ) {
if( is_user_logged_in() ) {
$args['menu'] = 'logged-out';
} else {
$args['menu'] = 'Main Menu';
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'wpc_wp_nav_menu_args' );
What i want is to have a different header menus for user when they log in and log out, but the footer menus stays the same. i am currently learning how to add the conditional logic on the functions.php atm, but if there are other ways please let me know, thx in advance
Probably a bit late for a reply but I just did this in the Astra theme today, so thought I would share the know-how for others who might need it. It can easily be adjusted for any WordPress theme actually:
You can check the location of the menu and only change the menu in the location(s) you decide (in this example 'primary' and 'mobile_menu' which is what Astra theme calls the the main nav locations for desktop and mobile) :
function custom_wp_nav_menu_args( $args = '' ) {
if( $args['theme_location'] == 'primary' || $args['theme_location'] == 'mobile_menu' ) {
if( ! is_user_logged_in() ) {
$args['menu'] = 'logged-out';
}
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'custom_wp_nav_menu_args' );
If you dont want to use the explicit position of the menu (in my case the nav was in a widget in the footer and not a set theme location), you can also do the same thing by using the id, name or slug of the menu. For example if you want to change the menu 'test-menu' for 'test-menu-logged-out' if the user is logged out, you can use this:
function custom_2_wp_nav_menu_args ( $args = '' ) {
$menu_slug = $args['menu']->slug;
if ( ! is_user_logged_in() && $menu_slug == 'test-menu' ){
$args['menu'] = 'test-menu-logged-out';
}
return $args;
}
add_filter( 'wp_nav_menu_args', 'custom_2_wp_nav_menu_args' );
I develop my first plugin, which creates some pages programatically by this method:
$page_id = wp_insert_post(
array(
'comment_status' => 'close',
'ping_status' => 'close',
'post_author' => 1,
'post_title' => 'HSN Form',
'post_name' => strtolower(str_replace(' ', '-', trim('hsn-form'))),
'post_status' => 'publish',
'post_type' => 'page',
)
);
And I set template file for it:
add_filter( 'page_template', 'hsn_service_form_page_template', 10, 1 );
function hsn_service_form_page_template( $page_template ){
if ( is_page( 'hsn-form' ) ) {
$page_template = plugin_dir_path(__DIR__) . 'service-form/form-template.php';
}
return $page_template;
}
After I would like to hide it completely from wordpress dashboard, but those have to available following way:
wwww.example.com/hsn-form.
I can hide it following code from Pages menu:
add_filter( 'parse_query', 'ts_hide_pages_in_wp_admin' );
function ts_hide_pages_in_wp_admin($query) {
global $pagenow,$post_type;
$page = get_page_by_path('hsn-form');
if (is_admin() && $pagenow=='edit.php' && $post_type =='page') {
$query->query_vars['post__not_in'] = array($page->ID);
}
}
It's ok, but it's still available in Appereance->Menu, where you can create nav menus.
I searched for it, but I can't find complete solution for my problem:
My plugin has to create some pages which are available this way: www.example.com/hsn-form
I need to hide this pages completely from admin dashboard
I would like to apply templates for these pages to add some custom php code.
So If somebody should know a complete solution for it, that should be great.
Thank you in advance!
change parse_query to pre_get_posts
In order to remove a page from the admin nav menu, you can hook into the admin_menu action, then manipulate the global $submenu variable.
add_action('admin_menu', function(){
global $submenu;
array_walk($submenu, function(&$child, $parent){
if( $parent != 'edit.php' )
return;
foreach($child as $key=>$submenu){
if( $submenu[2] == 'post-new.php' ) {
unset($child[$key]);
break;
}
}
});
});
In that example, we are looking for a subpage with the slug of post-new.php
underneath the top level page with the slug edit.php. If found, it gets altogether removed from the navigation menu.
The $submenu[2] part is looking for the slug element in the array. If you want to match by the submenu name instead, you can replace it with $submenu[0].
I have a custom field associated with all posts and pages. It's a dropdown of all the navigation menus.
here is how I'm populating the custom field drop-down: (the field name is custom_menu...)
function acf_load_menu_field_choices( $field ) {
// reset choices
$field['choices'] = array();
$menus = get_terms( 'nav_menu', array( 'hide_empty' => true ) );
$blank_list = json_encode(array( "name" => "Select Menu", "slug" => ""));
$blank_list = json_decode($blank_list);
array_unshift($menus, $blank_list);
foreach ( $menus as $val ) {
$value = $val->slug;
$label = $val->name;
$field['choices'][ $value ] = $label;
}
// return the field
return $field;
}
add_filter('acf/load_field/name=custom_menu', 'acf_load_menu_field_choices');
Here is a common menu location that I'm using on each page:
function register_custom_menu() { //function to register new menu
register_nav_menu('custom-menu',__( 'Custom Menu' ));
}
add_action( 'init', 'register_custom_menu' );
And then I'm assigning a menu dynamically to the location custom-menu based on the custom field menu on each page.
and here is the function the fires on each page when it's loaded:
add_action("wp_ajax_load_custom_menu", "load_custom_menu");
add_action("wp_ajax_nopriv_load_custom_menu", "load_custom_menu");
function load_custom_menu(){
$post_id = $_POST['page_id'];
$page_custom_menu = get_field('custom_menu', $post_id);
if(empty($page_custom_menu) || $page_custom_menu == "primary") return;
$locations = get_theme_mod( 'nav_menu_locations' );
if(!empty($locations)) {
foreach($locations as $locationId => $menuValue) {
if($locationId == "custom-menu") $menu = get_term_by('slug', $page_custom_menu, 'nav_menu');
if(isset($menu)) { $locations[$locationId] = $menu->term_id; }
}
}
set_theme_mod('nav_menu_locations', $locations);
wp_nav_menu( array(
'theme_location' => 'custom-menu',
'menu_id' => 'primary-menu',
'menu_class' => 'main-nav underline-decoration l-to-r-line level-arrows-on outside-item-remove-margin',
'container' => false
)
);
wp_die();
}
This ajax function fires on ready event and recieves a POST value called page_id. This function checks the custom field value of the given page_id for custom-menu and assign that menu to the menu location called custom-menu.
Here's my JavaScript in case you need to have a look on it:
jQuery(document).ready( function($){
let customMenu;
let page_id = script_vars.postID;
$.post(dtLocal.ajaxurl, { action: "load_custom_menu", page_id: page_id }, resp => customMenu = resp);
$(window).scroll(() => {
if(customMenu !== "0"){
$("#phantom .main-nav").remove();
$("#phantom .menu-box").html(customMenu);
}
})
})
This is how my code is working, And everything works fine up to this point.
Now here is the problem
Whenever I delete a Navigation menu from Appearence>Menus>Delete Menu My custom Menu starts behaving unexpectedly because the custom field value is still pointing to the deleted Menu.
What I want to do here is, I want to Delete the Custom Field whenever a menu is deleted. First I want to get the slug of a deleted menu and then find the custom field value with that slug and then finally, delete or reset that custom field.
Menus in WordPress are just terms in a taxonomy. So you can use all of the term hooks.
In particular the pre_delete_term hook.
add_action( 'pre_delete_term', 'my_func' );
function my_func($term, $taxonomy){
// Check the taxonomy is really 'menu', then check term
}
You are looking for action wp_delete_nav_menu that will take one argument - menu id. The problem that at that point your nav menu will be deleted, so you won't be able to take it slug.
If it is possible that you can store nav menu ID instead of slug, that would simplify things greatly.
In acf_load_menu_field_choices replace:
foreach ( $menus as $val ) {
$value = $val->term_id;
$label = $val->name;
$field['choices'][ $value ] = $label;
}
And in load_custom_menu:
$page_custom_menu = get_field('custom_menu', $post_id);
if(empty($page_custom_menu) || $page_custom_menu == /* Should be your primary menu ID */) return;
$locations = get_theme_mod( 'nav_menu_locations' );
if(!empty($locations)) {
foreach($locations as $locationId => $menuValue) {
if($locationId == "custom-menu") $menu = get_term_by('id', $page_custom_menu, 'nav_menu');
if(isset($menu)) { $locations[$locationId] = $menu->term_id; }
}
}
After those changes you will need to rewrite custom_menu in all posts\pages.
After that, following function will remove all related fields when you delete menu. It has been tested only on typical ACF field (string) instead of custom, but should work just fine with your code as well.
add_action('wp_delete_nav_menu', 'delete_all_acf_fields_with_menu', 10, 1);
function delete_all_acf_fields_with_menu($term_id) {
$args = array(
'post_type' => array('post', 'page'),
'posts_per_page' => -1,
'meta_key' => 'custom_menu',
'meta_value' => $term_id,
);
$posts = get_posts($args);
if( $posts ) {
foreach( $posts as $p ) {
delete_field('custom_menu', $p->ID);
}
}
}