"current" class on top level menu item with wp_nav_menu - php

I've created a wordpress menu with wp_nav_menu.
my structure looks like:
Page
Category
Page
Page
Page
If I open a post in "Category", there is no "current" class on the top level of the menu – only on "Category". Nesting only with pages works fine on multi level menus.
Is there a way to fix that?

1) Either write a custom walker http://codex.wordpress.org/Function_Reference/wp_nav_menu#Using_a_Custom_Walker_Function to add a current class when that category is called;
2) Or, (not the most elegant): find your page ID for the menu item you want - 1000 in the example below - to highlight as current, select that category - is_category - and then add the current class - addClass - with jQuery:
<?php if (is_category('my-category')) { ?>
<script type="text/javascript">
jQuery(function($) {
$(document).ready(function() {
$('#menu-main-menu li.menu-item-1000').addClass('current-menu-item');
}); });
</script>
<?php } ?>

ahh... found the solution in the wordpress codex. this works fine for me:
add_filter( 'wp_nav_menu_objects', 'add_menu_parent_class' );
function add_menu_parent_class( $items ) {
$parents = array();
foreach ( $items as $item ) {
if ( $item->menu_item_parent && $item->menu_item_parent > 0 ) {
$parents[] = $item->menu_item_parent;
}
}
foreach ( $items as $item ) {
if ( in_array( $item->ID, $parents ) ) {
$item->classes[] = 'menu-parent-item';
}
}
return $items;
}

Related

Set specific number of columns for top level term on product category archives

I’m trying to make category page to show 7 columns , but it modifies subcategories too. Is there any way to modify only the main category page without applying it to subcategories?
https://www.prospecs.lt/?post_type=product
my code :
add_filter('loop_shop_columns', 'loop_columns', 999);
if (!function_exists('loop_columns')) {
function loop_columns() {
return 7; // 3 products per row
}
}
Note that in your code, the main filter argument is missing for your function. Now you can use the following to define the main product category loop columns:
add_filter('loop_shop_columns', 'main_product_category_loop_columns', 999);
function main_product_category_loop_columns( $columns ) {
if( ! is_product_category() )
return $columns;
$term = get_queried_object();
if( $term && is_a($term, 'WP_Term') ) {
return $term->parent > 0 ? $columns : 7;
}
return $columns;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
You can apply the condition and separated the templates for the category and subcategory page.
$cat = get_the_terms( $product->ID, 'product_cat' );
foreach ($cat as $categoria) {
if($categoria->parent == 0){
// Use here parent categories template
}
}
You can check if it the current page is a subcategory with this function.
function is_subcategory($cat_id = null) {
if (is_tax('product_cat')) {
if (empty($cat_id)){
$cat_id = get_queried_object_id();
}
$cat = get_term(get_queried_object_id(), 'product_cat');
if ( empty($cat->parent) ){
return false;
}else{
return true;
}
}
return false;
}
You can then use it in your if statement
add_filter('loop_shop_columns', 'loop_columns', 999);
if (!function_exists('loop_columns') && !is_subcategory()) {
function loop_columns() {
return 7;
}
}

Hide in Woocommerce Dashboard, for specific User Role 'Order' sub-menu from Woocommerce

if (!current_user_can('administrator')) {
function remove_admin_menus () {
global $menu;
$removed = array(
__('WooCommerce'),
);
end ($menu);
while (prev($menu)){
$value = explode(
' ',
$menu[key($menu)][0]);
if(in_array($value[0] != NULL?$value[0]:"" , $removed)){
unset($menu[key($menu)]);
}
}
}
}
add_action('admin_menu', 'remove_admin_menus');
This code hide the whole Woocommerce item from Wordpress dashboard, if you are Administrator, but i didn't fiind a solution to hide only Orders sub-menu, not the whole item.
Who has an idea?
You were taking global $menu instead $submenu. Then you will get a list of all submenus registered. You can add the following code. Also it is better to check if user is admin inside the function call
function remove_admin_menus(){
global $submenu;
if(current_user_can('administrator')){
unset($submenu['woocommerce']['1']);
}
}
add_action('admin_menu', 'remove_admin_menus');
UPDATE
Even if the menu is hidden, one can access the page if he knows the url. So inorder to block the access to url, add the following
function restrict_woo_submenu_userrole(){
$current_screen = get_current_screen();
$p_id = $current_screen->id;
if($p_id == 'edit-shop_order' && current_user_can('administrator')){
wp_die('Restricted Access.');
}
}
add_filter( 'current_screen', 'restrict_woo_submenu_userrole' );

wordpress custom menu for different page

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.

Displaying Logged-In User Name in Wordpress Menu

I'm using Wordpress with UserPro, and want my menu to display the logged-in user's first name, linked to the user profile page.
The problem is that in my menu structure, the "Profile" menu option is supposed to have a sub-menu containing "edit profile", "submit", and "logout".
This is my current code:
/*earlier code, currently commented out, for function to
display username in menu using #profile_name# placeholder
function give_profile_name($atts){
echo userpro_profile_data('first_name', get_current_user_id());
}
add_shortcode('profile_name', 'give_profile_name');
add_filter( 'wp_nav_menu_objects', 'my_dynamic_menu_items' );
function my_dynamic_menu_items( $menu_items ) {
foreach ( $menu_items as $menu_item ) {
if ( '#profile_name#' == $menu_item->title ) {
global $shortcode_tags;
if ( isset( $shortcode_tags['profile_name'] ) ) {
// Or do_shortcode(), if you must.
$menu_item->title = call_user_func( $shortcode_tags['profile_name'] );
}
}
}
return $menu_items;
}
end of earlier code */
//currently in use, unlinked code
add_filter( 'wp_nav_menu_items', 'my_custom_menu_item');
function my_custom_menu_item($items)
{
if(is_user_logged_in())
{
$user=wp_get_current_user();
$name=$user->user_firstname;
$items .= '<li>'.$name.'';
}
return $items;
}
?>
I can fiddle around and try to add the sub-menu under the menu by fiddling with the code from Firebug, but that would mean manual edits to all the links in the functions.php, which would be tedious.
I want to be able to add, edit, remove, and redirect the sub-menu items easily via the Wordpress menu.
Please advise.
Okay, I found a solution (and it can be used for any theme, with any plugin as it only uses core WordPress functions).
In the menu, name the menu item where you want the user's name to appear with a place-holder (such as: #profile_name#, #user#, #random#, etc.)
Now, add the following code to the your child-theme's functions.php:
function give_profile_name($atts){
$user=wp_get_current_user();
$name=$user->user_firstname;
return $name;
}
add_shortcode('profile_name', 'give_profile_name');
add_filter( 'wp_nav_menu_objects', 'my_dynamic_menu_items' );
function my_dynamic_menu_items( $menu_items ) {
foreach ( $menu_items as $menu_item ) {
if ( '#profile_name#' == $menu_item->title ) {
global $shortcode_tags;
if ( isset( $shortcode_tags['profile_name'] ) ) {
// Or do_shortcode(), if you must.
$menu_item->title = call_user_func( $shortcode_tags['profile_name'] );
}
}
}
return $menu_items;
}
In case you're using your own place-holder, remember to replace #profile_name# with the name of your custom place-holder in the code above.
Apologies in case I've misused the term 'place-holder'.

Wordpress - Maintain "active" class on parent menu item

I am implementing a theme in Wordpress. This theme has a top navigation menu with horizontal sub menus under each parent item. It puts an "active" class on current parent items currently been viewed (otherwise it won't show it's children sub menu items). I have somehow managed to maintain "active" class on current parent items by using these two function in functions.php.
/**
* Wp Nav Menu Customizer.
*/
function special_nav_class($classes, $item){
if( in_array('current-menu-item', $classes) ){
$classes[] = 'active ';
}
return $classes;
}
add_filter('nav_menu_css_class' , 'special_nav_class' , 10 , 2);
class SH_Last_Walker extends Walker_Nav_Menu{
function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
$id_field = $this->db_fields['id'];
//If the current element has children, add class 'sub-menu'
if( isset($children_elements[$element->$id_field]) ) {
$classes = empty( $element->classes ) ? array() : (array) $element->classes;
$classes[] = 'has-sub-menu';
$element->classes =$classes;
}
// We don't want to do anything at the 'top level'.
if( 0 == $depth )
return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
//Get the siblings of the current element
$parent_id_field = $this->db_fields['parent'];
$parent_id = $element->$parent_id_field;
$siblings = $children_elements[ $parent_id ] ;
//No Siblings??
if( ! is_array($siblings) )
return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
//Get the 'last' of the siblings.
$last_child = array_pop($siblings);
$id_field = $this->db_fields['id'];
//If current element is the last of the siblings, add class 'last'
if( $element->$id_field == $last_child->$id_field ){
$classes = empty( $element->classes ) ? array() : (array) $element->classes;
$classes[] = 'last';
$element->classes =$classes;
}
return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
}
But now my problem is that when i click on sub menu or child of any parent menu item it successfully takes me to the child page but removes "active" class from parent and puts it on children (because it is the currently viewed page). I don't want it to put this class to children, i want it to be there (on parent item) whenever it's children are being viewed.
Any help would be much appreciated.
if you want to the dropdown grand-grand parent to be active when child menu item is active, then you can check for current-menu-ancestor or current-page-ancestor.. in your case, i think current-menu-ancestor check is most favorable.
function special_nav_class($classes, $item){
if( in_array('current-menu-item', $classes) || in_array('current-menu-ancestor', $classes) ){
$classes[] = 'active ';
}
return $classes;
}
I hope this would help, have a nice day :)
If all you want is to add some style or other properties by targeting the parent element then WordPress Provides you built-in classes for it for example:
when you are on a child page you can see classes like current-menu-parent current-page-parent current_page_parent current_page_ancestor these added to the parent page by WordPress you can choose any of these to target the parent element.
When you click on sub menu item WordPress will add .current-menu-item class to that sub menu item and .current-menu-parent class to the parent menu item of that sub menu item. You can style those specific classes according to your needs.

Categories