|
/** |
|
* Gist Name: Highlight CPT Archive and wp_nav_menu parents |
|
* Author: VlooMan |
|
* Author URI: http://ishyoboy.com |
|
* |
|
* Highlight the CPT (Custom Post Type) Archive & its Parents ("current-menu-parent") |
|
* & its Ancestors ("current-menu-ancestor") in the WordPress Navigation wp_nav_menu() when viewing the Archive itself |
|
* or a single detail page of the CPT. |
|
* |
|
* Let's say you have CPT called "projects" and you have a WordPress menu set as |
|
* "My Work (link to a page) > Projects (CPT Archive)". If you visit the CPT Archive the "My Work" item would not be |
|
* originally highlighted, only the "Projects" would be. If you visit the detail of a given project nothing would be |
|
* highlighted in the navigation (neither "My Work" nor "Projects"). The code below solves the problem. |
|
* |
|
* The code uses a WordPress hook and 99% of the code is copied from the original WordPress function which for some |
|
* reason does not do this highlighting. Please let me know if the code helped in the comments below. |
|
* |
|
* Simply copy this code to your theme's or child-theme's functions.php file. |
|
* |
|
* P.S. Just make sure to add the nav menu item as "CPT Archive" and not a "Custom Link". |
|
* |
|
* @param array $menu_items - All Navigation Menu Items |
|
* @param array $args - some arguments we do not use right now |
|
* |
|
* @return array $menu_items |
|
*/ |
|
|
|
function my_highlight_cpt_archive_and_ancestors_in_menu( $menu_items, $args ) { |
|
global $wp_query, $wp_rewrite; |
|
|
|
$queried_object = $wp_query->get_queried_object(); |
|
|
|
$active_object = ''; |
|
$active_ancestor_item_ids = array(); |
|
$active_parent_item_ids = array(); |
|
$active_parent_object_ids = array(); |
|
$possible_taxonomy_ancestors = array(); |
|
|
|
// Highligh the current post's archive & prepare parents for highlighting |
|
foreach ( (array) $menu_items as $key => $menu_item ) { |
|
|
|
if ( |
|
( 'post_type_archive' == $menu_item->type && is_post_type_archive( array( $menu_item->object ) ) ) || |
|
( 'post_type_archive' == $menu_item->type && is_singular( array( $menu_item->object ) ) ) |
|
) { |
|
$allow_highlight = true; |
|
|
|
// This filter can be used to add some additional logic if needed. E.g. not highlight in some special cases |
|
$allow_highlight = apply_filters( 'my_allow_menu_highlight', $allow_highlight, $menu_item, $queried_object, $args ); |
|
|
|
if ( $allow_highlight ) { |
|
$menu_item->classes[] = 'current-menu-item'; |
|
$menu_items[ $key ]->current = true; |
|
|
|
$_anc_id = (int) $menu_item->db_id; |
|
|
|
while ( |
|
( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) && |
|
! in_array( $_anc_id, $active_ancestor_item_ids ) |
|
) { |
|
$active_ancestor_item_ids[] = $_anc_id; |
|
} |
|
|
|
$active_parent_item_ids[] = (int) $menu_item->menu_item_parent; |
|
$active_parent_object_ids[] = (int) $menu_item->post_parent; |
|
$active_object = $menu_item->object; |
|
} |
|
} |
|
} |
|
|
|
// Make sure the IDs are not present multiple times |
|
$active_ancestor_item_ids = array_filter( array_unique( $active_ancestor_item_ids ) ); |
|
$active_parent_item_ids = array_filter( array_unique( $active_parent_item_ids ) ); |
|
$active_parent_object_ids = array_filter( array_unique( $active_parent_object_ids ) ); |
|
|
|
|
|
// set parent's class |
|
foreach ( (array) $menu_items as $key => $parent_item ) { |
|
$classes = (array) $parent_item->classes; |
|
$menu_items[$key]->current_item_ancestor = false; |
|
$menu_items[$key]->current_item_parent = false; |
|
|
|
if ( |
|
isset( $parent_item->type ) && |
|
( |
|
// ancestral post object |
|
( |
|
'post_type' == $parent_item->type && |
|
! empty( $queried_object->post_type ) && |
|
is_post_type_hierarchical( $queried_object->post_type ) && |
|
in_array( $parent_item->object_id, $queried_object->ancestors ) && |
|
$parent_item->object != $queried_object->ID |
|
) || |
|
|
|
// ancestral term |
|
( |
|
'taxonomy' == $parent_item->type && |
|
isset( $possible_taxonomy_ancestors[ $parent_item->object ] ) && |
|
in_array( $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ] ) && |
|
( |
|
! isset( $queried_object->term_id ) || |
|
$parent_item->object_id != $queried_object->term_id |
|
) |
|
) |
|
) |
|
) { |
|
$classes[] = empty( $queried_object->taxonomy ) ? 'current-' . $queried_object->post_type . '-ancestor' : 'current-' . $queried_object->taxonomy . '-ancestor'; |
|
} |
|
|
|
if ( in_array( intval( $parent_item->db_id ), $active_ancestor_item_ids ) ) { |
|
$classes[] = 'current-menu-ancestor'; |
|
$menu_items[$key]->current_item_ancestor = true; |
|
} |
|
if ( in_array( $parent_item->db_id, $active_parent_item_ids ) ) { |
|
$classes[] = 'current-menu-parent'; |
|
$menu_items[$key]->current_item_parent = true; |
|
} |
|
if ( in_array( $parent_item->object_id, $active_parent_object_ids ) ) |
|
$classes[] = 'current-' . $active_object . '-parent'; |
|
|
|
if ( 'post_type' == $parent_item->type && 'page' == $parent_item->object ) { |
|
// Back compat classes for pages to match wp_page_menu() |
|
if ( in_array('current-menu-parent', $classes) ) |
|
$classes[] = 'current_page_parent'; |
|
if ( in_array('current-menu-ancestor', $classes) ) |
|
$classes[] = 'current_page_ancestor'; |
|
} |
|
|
|
$menu_items[$key]->classes = array_unique( $classes ); |
|
} |
|
|
|
|
|
return $menu_items; |
|
} |
|
add_filter( 'wp_nav_menu_objects', 'my_highlight_cpt_archive_and_ancestors_in_menu', 10, 2 ); |
Hi @VlooMan, any advice on how to highlight also the custom taxonomies registered for the CPT?
Currently I have a menu which contains the link to the CPT archive.
If I'm in the CPT archive -> CPT archive link highlighted
If I'm in a CPT taxonomy -> CPT archive link NOT highlighted
If I'm in a CPT single post -> CPT archive link highlighted