Skip to content

Instantly share code, notes, and snippets.

@Langmans
Created August 21, 2018 16:59
Show Gist options
  • Save Langmans/ac9ccf53861a06721c26e88b3b855924 to your computer and use it in GitHub Desktop.
Save Langmans/ac9ccf53861a06721c26e88b3b855924 to your computer and use it in GitHub Desktop.
<?php
class Menu extends \Timber\Menu {
public $MenuItemClass = 'MenuItem';
}
class MenuItem extends \Timber\MenuItem {
/** @var MenuItem */
public $parent;
/**
* @param MenuItem $item
*/
public function add_child( $item ) {
if ( $item === $this || $item->id == $this->id ) {
throw new \InvalidArgumentException( 'recursion error??' );
}
parent::add_child( $item );
$item->set_parent( $this );
}
/**
* @return MenuItem
*/
public function get_parents() {
$parent = $this;
$parents = [];
while ( $parent = $parent->get_parent() ) {
$parents[] = $parent;
}
return $parent;
}
/**
* @return MenuItem|bool
*/
public function get_parent() {
return $this->parent ?: false;
}
public function set_parent( MenuItem $parent ) {
// if ( $this->parent ) {
// $this->parent->remove_child( $parent );
// }
$this->parent = $parent;
}
}
add_filter('timber_context', function( array $context ) {
$ancestor_links = [];
if ( is_post_type_hierarchical( get_post_type() ) ) {
// For pages or any post type with hierarchy.
// We use this if a page is 5 levels deep and the menu only has one level of dropdowns.
$ancestor_links = get_post_ancestors( get_the_ID() );
} elseif ( get_post_type() === 'post' && get_option( 'show_on_front' ) === 'page' && ( $page_for_posts = get_option( 'page_for_posts' ) ) ) {
// we selected a page for a news article. So use that as selected menu item if it's available, or any of the ancestors.
$ancestor_links = get_post_ancestors( $page_for_posts );
$ancestor_links [] = $page_for_posts;
}
if ( $ancestor_links ) {
$ancestor_links = array_map( 'get_permalink', $ancestor_links );
}
foreach ( get_nav_menu_locations() as $location => $menu_id ) {
$context['menus'][ $location ] = $menu = new Menu( $menu_id );
if ( $ancestor_links ) {
// Check if the menu has an item active.
$has_active_item = false;
/** @var MenuItem $item */
foreach ( $menu->get_items() as $item ) {
if ( $item->current || $item->current_item_ancestor || $item->current_item_parent ) {
$has_active_item = true;
break;
}
}
if ( ! $has_active_item ) {
/** @var MenuItem $selected_menu_item */
$selected_menu_item = null;
/** @var MenuItem[] $items */
$items = [];
$stack = [ $menu->get_items() ];
while ( $stack_items = array_pop( $stack ) ) {
/** @var MenuItem $item */
foreach ( $stack_items as $item ) {
if ( strtok( $item->link(), '#' ) ) {
$items[] = $item;
}
$children = $item->children();
if ( $children ) {
// loop the children too!
$stack[] = $children;
}
}
}
// we have all the links in the menu now.
// search for a menu item in reverse order. We dont want to highlight the ancestors first.
while ( $item = array_pop( $items ) ) {
// strip hashtags, ie page.html#bladiebla
$link = strtok( $item->link(), '#' );
if ( in_array( $link, $ancestor_links, false ) ) {
$item->current = true;
$item->add_class( 'current-menu-item' );
if ( $parent = $item->parent ) {
$parent->current_item_parent = true;
$parent->current_item_ancestor = true;
$parent->add_class( 'current-menu-parent' );
$parent->add_class( 'current-menu-ancestor' );
while ( $parent = $parent->parent ) {
$parent->current_item_ancestor = true;
$parent->add_class( 'current-menu-ancestor' );
}
}
}
}
}
}
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment