wp/wp-includes/nav-menu-template.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
   196 	_wp_menu_item_classes_by_context( $menu_items );
   196 	_wp_menu_item_classes_by_context( $menu_items );
   197 
   197 
   198 	$sorted_menu_items        = array();
   198 	$sorted_menu_items        = array();
   199 	$menu_items_with_children = array();
   199 	$menu_items_with_children = array();
   200 	foreach ( (array) $menu_items as $menu_item ) {
   200 	foreach ( (array) $menu_items as $menu_item ) {
       
   201 		/*
       
   202 		 * Fix invalid `menu_item_parent`. See: https://core.trac.wordpress.org/ticket/56926.
       
   203 		 * Compare as strings. Plugins may change the ID to a string.
       
   204 		 */
       
   205 		if ( (string) $menu_item->ID === (string) $menu_item->menu_item_parent ) {
       
   206 			$menu_item->menu_item_parent = 0;
       
   207 		}
       
   208 
   201 		$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
   209 		$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
   202 		if ( $menu_item->menu_item_parent ) {
   210 		if ( $menu_item->menu_item_parent ) {
   203 			$menu_items_with_children[ $menu_item->menu_item_parent ] = true;
   211 			$menu_items_with_children[ $menu_item->menu_item_parent ] = true;
   204 		}
   212 		}
   205 	}
   213 	}
   331 				$term_hierarchy = _get_term_hierarchy( $taxonomy );
   339 				$term_hierarchy = _get_term_hierarchy( $taxonomy );
   332 				$terms          = wp_get_object_terms( $queried_object_id, $taxonomy, array( 'fields' => 'ids' ) );
   340 				$terms          = wp_get_object_terms( $queried_object_id, $taxonomy, array( 'fields' => 'ids' ) );
   333 				if ( is_array( $terms ) ) {
   341 				if ( is_array( $terms ) ) {
   334 					$possible_object_parents = array_merge( $possible_object_parents, $terms );
   342 					$possible_object_parents = array_merge( $possible_object_parents, $terms );
   335 					$term_to_ancestor        = array();
   343 					$term_to_ancestor        = array();
   336 					foreach ( (array) $term_hierarchy as $anc => $descs ) {
   344 					foreach ( (array) $term_hierarchy as $ancestor => $descendents ) {
   337 						foreach ( (array) $descs as $desc ) {
   345 						foreach ( (array) $descendents as $desc ) {
   338 							$term_to_ancestor[ $desc ] = $anc;
   346 							$term_to_ancestor[ $desc ] = $ancestor;
   339 						}
   347 						}
   340 					}
   348 					}
   341 
   349 
   342 					foreach ( $terms as $desc ) {
   350 					foreach ( $terms as $desc ) {
   343 						do {
   351 						do {
   355 			}
   363 			}
   356 		}
   364 		}
   357 	} elseif ( ! empty( $queried_object->taxonomy ) && is_taxonomy_hierarchical( $queried_object->taxonomy ) ) {
   365 	} elseif ( ! empty( $queried_object->taxonomy ) && is_taxonomy_hierarchical( $queried_object->taxonomy ) ) {
   358 		$term_hierarchy   = _get_term_hierarchy( $queried_object->taxonomy );
   366 		$term_hierarchy   = _get_term_hierarchy( $queried_object->taxonomy );
   359 		$term_to_ancestor = array();
   367 		$term_to_ancestor = array();
   360 		foreach ( (array) $term_hierarchy as $anc => $descs ) {
   368 		foreach ( (array) $term_hierarchy as $ancestor => $descendents ) {
   361 			foreach ( (array) $descs as $desc ) {
   369 			foreach ( (array) $descendents as $desc ) {
   362 				$term_to_ancestor[ $desc ] = $anc;
   370 				$term_to_ancestor[ $desc ] = $ancestor;
   363 			}
   371 			}
   364 		}
   372 		}
   365 		$desc = $queried_object->term_id;
   373 		$desc = $queried_object->term_id;
   366 		do {
   374 		do {
   367 			$possible_taxonomy_ancestors[ $queried_object->taxonomy ][] = $desc;
   375 			$possible_taxonomy_ancestors[ $queried_object->taxonomy ][] = $desc;
   408 			$active_parent_item_ids[]   = (int) $menu_item->db_id;
   416 			$active_parent_item_ids[]   = (int) $menu_item->db_id;
   409 			$active_object              = $queried_object->post_type;
   417 			$active_object              = $queried_object->post_type;
   410 
   418 
   411 			// If the menu item corresponds to the currently queried post or taxonomy object.
   419 			// If the menu item corresponds to the currently queried post or taxonomy object.
   412 		} elseif (
   420 		} elseif (
   413 			$menu_item->object_id == $queried_object_id
   421 			(int) $menu_item->object_id === $queried_object_id
   414 			&& (
   422 			&& (
   415 				( ! empty( $home_page_id ) && 'post_type' === $menu_item->type
   423 				( ! empty( $home_page_id ) && 'post_type' === $menu_item->type
   416 					&& $wp_query->is_home && $home_page_id == $menu_item->object_id )
   424 					&& $wp_query->is_home && $home_page_id === (int) $menu_item->object_id )
   417 				|| ( 'post_type' === $menu_item->type && $wp_query->is_singular )
   425 				|| ( 'post_type' === $menu_item->type && $wp_query->is_singular )
   418 				|| ( 'taxonomy' === $menu_item->type
   426 				|| ( 'taxonomy' === $menu_item->type
   419 					&& ( $wp_query->is_category || $wp_query->is_tag || $wp_query->is_tax )
   427 					&& ( $wp_query->is_category || $wp_query->is_tag || $wp_query->is_tax )
   420 					&& $queried_object->taxonomy == $menu_item->object )
   428 					&& $queried_object->taxonomy === $menu_item->object )
   421 			)
   429 			)
   422 		) {
   430 		) {
   423 			$classes[]                   = 'current-menu-item';
   431 			$classes[]                   = 'current-menu-item';
   424 			$menu_items[ $key ]->current = true;
   432 			$menu_items[ $key ]->current = true;
   425 			$_anc_id                     = (int) $menu_item->db_id;
   433 			$ancestor_id                 = (int) $menu_item->db_id;
   426 
   434 
   427 			while (
   435 			while (
   428 				( $_anc_id = (int) get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) )
   436 				( $ancestor_id = (int) get_post_meta( $ancestor_id, '_menu_item_menu_item_parent', true ) )
   429 				&& ! in_array( $_anc_id, $active_ancestor_item_ids, true )
   437 				&& ! in_array( $ancestor_id, $active_ancestor_item_ids, true )
   430 			) {
   438 			) {
   431 				$active_ancestor_item_ids[] = $_anc_id;
   439 				$active_ancestor_item_ids[] = $ancestor_id;
   432 			}
   440 			}
   433 
   441 
   434 			if ( 'post_type' === $menu_item->type && 'page' === $menu_item->object ) {
   442 			if ( 'post_type' === $menu_item->type && 'page' === $menu_item->object ) {
   435 				// Back compat classes for pages to match wp_page_menu().
   443 				// Back compat classes for pages to match wp_page_menu().
   436 				$classes[] = 'page_item';
   444 				$classes[] = 'page_item';
   447 			'post_type_archive' === $menu_item->type
   455 			'post_type_archive' === $menu_item->type
   448 			&& is_post_type_archive( array( $menu_item->object ) )
   456 			&& is_post_type_archive( array( $menu_item->object ) )
   449 		) {
   457 		) {
   450 			$classes[]                   = 'current-menu-item';
   458 			$classes[]                   = 'current-menu-item';
   451 			$menu_items[ $key ]->current = true;
   459 			$menu_items[ $key ]->current = true;
   452 			$_anc_id                     = (int) $menu_item->db_id;
   460 			$ancestor_id                 = (int) $menu_item->db_id;
   453 
   461 
   454 			while (
   462 			while (
   455 				( $_anc_id = (int) get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) )
   463 				( $ancestor_id = (int) get_post_meta( $ancestor_id, '_menu_item_menu_item_parent', true ) )
   456 				&& ! in_array( $_anc_id, $active_ancestor_item_ids, true )
   464 				&& ! in_array( $ancestor_id, $active_ancestor_item_ids, true )
   457 			) {
   465 			) {
   458 				$active_ancestor_item_ids[] = $_anc_id;
   466 				$active_ancestor_item_ids[] = $ancestor_id;
   459 			}
   467 			}
   460 
   468 
   461 			$active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
   469 			$active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
   462 
   470 
   463 			// If the menu item corresponds to the currently requested URL.
   471 			// If the menu item corresponds to the currently requested URL.
   484 			);
   492 			);
   485 
   493 
   486 			if ( $raw_item_url && in_array( $item_url, $matches, true ) ) {
   494 			if ( $raw_item_url && in_array( $item_url, $matches, true ) ) {
   487 				$classes[]                   = 'current-menu-item';
   495 				$classes[]                   = 'current-menu-item';
   488 				$menu_items[ $key ]->current = true;
   496 				$menu_items[ $key ]->current = true;
   489 				$_anc_id                     = (int) $menu_item->db_id;
   497 				$ancestor_id                 = (int) $menu_item->db_id;
   490 
   498 
   491 				while (
   499 				while (
   492 					( $_anc_id = (int) get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) )
   500 					( $ancestor_id = (int) get_post_meta( $ancestor_id, '_menu_item_menu_item_parent', true ) )
   493 					&& ! in_array( $_anc_id, $active_ancestor_item_ids, true )
   501 					&& ! in_array( $ancestor_id, $active_ancestor_item_ids, true )
   494 				) {
   502 				) {
   495 					$active_ancestor_item_ids[] = $_anc_id;
   503 					$active_ancestor_item_ids[] = $ancestor_id;
   496 				}
   504 				}
   497 
   505 
   498 				if ( in_array( home_url(), array( untrailingslashit( $current_url ), untrailingslashit( $_indexless_current ) ), true ) ) {
   506 				if ( in_array( home_url(), array( untrailingslashit( $current_url ), untrailingslashit( $_indexless_current ) ), true ) ) {
   499 					// Back compat for home link to match wp_page_menu().
   507 					// Back compat for home link to match wp_page_menu().
   500 					$classes[] = 'current_page_item';
   508 					$classes[] = 'current_page_item';
   502 				$active_parent_item_ids[]   = (int) $menu_item->menu_item_parent;
   510 				$active_parent_item_ids[]   = (int) $menu_item->menu_item_parent;
   503 				$active_parent_object_ids[] = (int) $menu_item->post_parent;
   511 				$active_parent_object_ids[] = (int) $menu_item->post_parent;
   504 				$active_object              = $menu_item->object;
   512 				$active_object              = $menu_item->object;
   505 
   513 
   506 				// Give front page item the 'current-menu-item' class when extra query arguments are involved.
   514 				// Give front page item the 'current-menu-item' class when extra query arguments are involved.
   507 			} elseif ( $item_url == $front_page_url && is_front_page() ) {
   515 			} elseif ( $item_url === $front_page_url && is_front_page() ) {
   508 				$classes[] = 'current-menu-item';
   516 				$classes[] = 'current-menu-item';
   509 			}
   517 			}
   510 
   518 
   511 			if ( untrailingslashit( $item_url ) == home_url() ) {
   519 			if ( untrailingslashit( $item_url ) === home_url() ) {
   512 				$classes[] = 'menu-item-home';
   520 				$classes[] = 'menu-item-home';
   513 			}
   521 			}
   514 		}
   522 		}
   515 
   523 
   516 		// Back-compat with wp_page_menu(): add "current_page_parent" to static home page link for any non-page query.
   524 		// Back-compat with wp_page_menu(): add "current_page_parent" to static home page link for any non-page query.
   517 		if ( ! empty( $home_page_id ) && 'post_type' === $menu_item->type
   525 		if ( ! empty( $home_page_id ) && 'post_type' === $menu_item->type
   518 			&& empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id
   526 			&& empty( $wp_query->is_page ) && $home_page_id === (int) $menu_item->object_id
   519 		) {
   527 		) {
   520 			$classes[] = 'current_page_parent';
   528 			$classes[] = 'current_page_parent';
   521 		}
   529 		}
   522 
   530 
   523 		$menu_items[ $key ]->classes = array_unique( $classes );
   531 		$menu_items[ $key ]->classes = array_unique( $classes );
   539 				(
   547 				(
   540 					'post_type' === $parent_item->type
   548 					'post_type' === $parent_item->type
   541 					&& ! empty( $queried_object->post_type )
   549 					&& ! empty( $queried_object->post_type )
   542 					&& is_post_type_hierarchical( $queried_object->post_type )
   550 					&& is_post_type_hierarchical( $queried_object->post_type )
   543 					&& in_array( (int) $parent_item->object_id, $queried_object->ancestors, true )
   551 					&& in_array( (int) $parent_item->object_id, $queried_object->ancestors, true )
   544 					&& $parent_item->object != $queried_object->ID
   552 					&& (int) $parent_item->object_id !== $queried_object->ID
   545 				) ||
   553 				) ||
   546 
   554 
   547 				// Ancestral term.
   555 				// Ancestral term.
   548 				(
   556 				(
   549 					'taxonomy' === $parent_item->type
   557 					'taxonomy' === $parent_item->type
   550 					&& isset( $possible_taxonomy_ancestors[ $parent_item->object ] )
   558 					&& isset( $possible_taxonomy_ancestors[ $parent_item->object ] )
   551 					&& in_array( (int) $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ], true )
   559 					&& in_array( (int) $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ], true )
   552 					&& (
   560 					&& (
   553 						! isset( $queried_object->term_id ) ||
   561 						! isset( $queried_object->term_id ) ||
   554 						$parent_item->object_id != $queried_object->term_id
   562 						(int) $parent_item->object_id !== $queried_object->term_id
   555 					)
   563 					)
   556 				)
   564 				)
   557 			)
   565 			)
   558 		) {
   566 		) {
   559 			if ( ! empty( $queried_object->taxonomy ) ) {
   567 			if ( ! empty( $queried_object->taxonomy ) ) {
   601  * @param int      $depth Depth of the item in reference to parents.
   609  * @param int      $depth Depth of the item in reference to parents.
   602  * @param stdClass $args  An object containing wp_nav_menu() arguments.
   610  * @param stdClass $args  An object containing wp_nav_menu() arguments.
   603  * @return string The HTML list content for the menu items.
   611  * @return string The HTML list content for the menu items.
   604  */
   612  */
   605 function walk_nav_menu_tree( $items, $depth, $args ) {
   613 function walk_nav_menu_tree( $items, $depth, $args ) {
   606 	$walker = ( empty( $args->walker ) ) ? new Walker_Nav_Menu : $args->walker;
   614 	$walker = ( empty( $args->walker ) ) ? new Walker_Nav_Menu() : $args->walker;
   607 
   615 
   608 	return $walker->walk( $items, $depth, $args );
   616 	return $walker->walk( $items, $depth, $args );
   609 }
   617 }
   610 
   618 
   611 /**
   619 /**
   627 
   635 
   628 	$_used_ids[] = $item->ID;
   636 	$_used_ids[] = $item->ID;
   629 
   637 
   630 	return $id;
   638 	return $id;
   631 }
   639 }
       
   640 
       
   641 /**
       
   642  * Remove the `menu-item-has-children` class from bottom level menu items.
       
   643  *
       
   644  * This runs on the {@see 'nav_menu_css_class'} filter. The $args and $depth
       
   645  * parameters were added after the filter was originally introduced in
       
   646  * WordPress 3.0.0 so this needs to allow for cases in which the filter is
       
   647  * called without them.
       
   648  *
       
   649  * @see https://core.trac.wordpress.org/ticket/56926
       
   650  *
       
   651  * @since 6.2.0
       
   652  *
       
   653  * @param string[]       $classes   Array of the CSS classes that are applied to the menu item's `<li>` element.
       
   654  * @param WP_Post        $menu_item The current menu item object.
       
   655  * @param stdClass|false $args      An object of wp_nav_menu() arguments. Default false ($args unspecified when filter is called).
       
   656  * @param int|false      $depth     Depth of menu item. Default false ($depth unspecified when filter is called).
       
   657  * @return string[] Modified nav menu classes.
       
   658  */
       
   659 function wp_nav_menu_remove_menu_item_has_children_class( $classes, $menu_item, $args = false, $depth = false ) {
       
   660 	/*
       
   661 	 * Account for the filter being called without the $args or $depth parameters.
       
   662 	 *
       
   663 	 * This occurs when a theme uses a custom walker calling the `nav_menu_css_class`
       
   664 	 * filter using the legacy formats prior to the introduction of the $args and
       
   665 	 * $depth parameters.
       
   666 	 *
       
   667 	 * As both of these parameters are required for this function to determine
       
   668 	 * both the current and maximum depth of the menu tree, the function does not
       
   669 	 * attempt to remove the `menu-item-has-children` class if these parameters
       
   670 	 * are not set.
       
   671 	 */
       
   672 	if ( false === $depth || false === $args ) {
       
   673 		return $classes;
       
   674 	}
       
   675 
       
   676 	// Max-depth is 1-based.
       
   677 	$max_depth = isset( $args->depth ) ? (int) $args->depth : 0;
       
   678 	// Depth is 0-based so needs to be increased by one.
       
   679 	$depth = $depth + 1;
       
   680 
       
   681 	// Complete menu tree is displayed.
       
   682 	if ( 0 === $max_depth ) {
       
   683 		return $classes;
       
   684 	}
       
   685 
       
   686 	/*
       
   687 	 * Remove the `menu-item-has-children` class from bottom level menu items.
       
   688 	 * -1 is used to display all menu items in one level so the class should
       
   689 	 * be removed from all menu items.
       
   690 	 */
       
   691 	if ( -1 === $max_depth || $depth >= $max_depth ) {
       
   692 		$classes = array_diff( $classes, array( 'menu-item-has-children' ) );
       
   693 	}
       
   694 
       
   695 	return $classes;
       
   696 }