Wordpress - Maintain "active" class on parent menu item - php

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.

Related

Add the term slug as a class to the product category div tag in Woocommerce

In Woocommerce, I'm trying to filter the output of wc_get_product_cat_class() function located in wc-template-functions.php core code:
function wc_get_product_cat_class( $class = '', $category = null ) {
$classes = is_array( $class ) ? $class : array_map( 'trim', explode( ' ', $class ) );
$classes[] = 'product-category';
$classes[] = 'product';
$classes[] = wc_get_loop_class();
$classes = apply_filters( 'product_cat_class', $classes, $class, $category );
return array_unique( array_filter( $classes ) );
}
I need it to add the cat slug as a class to each li tag on the category page.
It works fine when i edit the file directly and add this to the function :
$classes[] = $category->slug;
I then have <li class="product-category whatever-cat-slug product">
But obviously i am trying to find a better way to add it to my themes function file.
I have tried this, without success :
add_filter( 'product_cat_class' , 'add_class_to_category_list_element');
function add_class_to_category_list_element($classes) {
$classes[] = $category->slug;
return $classes;
}
Because $category has no meaning here.
Any help is welcome.
The product_cat_class filter hook manage 3 arguments $classes, $class and $category, so your code is just a bit incomplete. Also you should be sure that $category is a defined object before trying to get the slug on it.
Try this instead:
add_filter( 'product_cat_class' , 'add_class_to_category_list_element', 10, 3 );
function add_class_to_category_list_element( $classes, $class, $category ) {
if( is_object( $category ) )
$classes[] = $category->slug;
return $classes;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

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 Menu: Condition on Parent Item

I have a custom menu that is structured by a parent-child-subchild-and so on hierarchy. On each parent menu item (of which only six exist) there is a special picture I want to show in the corner of the website.
I now need a way to set a condition like this (this is fantasy-code of course):
if (current_parent_menu_item == "Home") : echo "Picture01"; endif;
if (current_parent_menu_item == "About") : echo "Picture02"; endif;
and so on...
I have no idea how I could access or ask for the current parent menu item.
Can anyone help?
Thanks a lot!
Sebastian
You should be using a walker class for this kind of stuff. Here is a simple walker class that you can use
class MyWalker extends Walker_Nav_Menu
{
function display_element ($element, &$children_elements, $max_depth, $depth = 0, $args, &$output)
{
// check, whether there are children for the given ID and append it to the element with a (new) ID
$element->hasChildren = isset($children_elements[$element->ID]) && !empty($children_elements[$element->ID]);
return parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
}
function start_el(&$output, $item, $depth, $args)
{
global $wp_query;
// you know can access $item->hasChildren to do anything you want..
}
}
If you just want to get over it, then you should use jquery to add the html to the parent element. You can do something like this.
jQuery(document).ready(){
jQuery('ul#id > li').prepend('<img src="#" alt="">');
}

Add Woocommerce parent category to WP 'body' class

I am trying to add a product's parent category from Woocommerce as a class to wordpress' body tag.
Every time I go within a child category the parent category is no longer within the body class.
Could something like below be edited to find the parent category and add within the body tag?
Maybe a term like "product_parent_cat"? Tried this and searched their API but no success..
function woo_custom_taxonomy_in_body_class( $classes ){
$custom_terms = get_the_terms(0, 'product_cat');
if ($custom_terms) {
foreach ($custom_terms as $custom_term) {
$classes[] = 'product_cat_' . $custom_term->slug;
}
}
return $classes;
}
add_filter( 'body_class', 'woo_custom_taxonomy_in_body_class' );
You can try this modification (untested):
function woo_custom_taxonomy_in_body_class( $classes ){
$custom_terms = get_the_terms(0, 'product_cat');
if ($custom_terms) {
foreach ($custom_terms as $custom_term) {
// Check if the parent category exists:
if( $custom_term->parent > 0 ) {
// Get the parent product category:
$parent = get_term( $custom_term->parent, 'product_cat' );
// Append the parent class:
if ( ! is_wp_error( $parent ) )
$classes[] = 'product_parent_cat_' . $parent->slug;
}
$classes[] = 'product_cat_' . $custom_term->slug;
}
}
return $classes;
}
add_filter( 'body_class', 'woo_custom_taxonomy_in_body_class' );
to add the parent product category slugs to the body class.
Here we use the parent property of the term object returned by the get_term() function.

"current" class on top level menu item with wp_nav_menu

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;
}

Categories