wp/wp-includes/nav-menu-template.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    13 /**
    13 /**
    14  * Displays a navigation menu.
    14  * Displays a navigation menu.
    15  *
    15  *
    16  * @since 3.0.0
    16  * @since 3.0.0
    17  * @since 4.7.0 Added the `item_spacing` argument.
    17  * @since 4.7.0 Added the `item_spacing` argument.
    18  *
    18  * @since 5.5.0 Added the `container_aria_label` argument.
    19  * @staticvar array $menu_id_slugs
       
    20  *
    19  *
    21  * @param array $args {
    20  * @param array $args {
    22  *     Optional. Array of nav menu arguments.
    21  *     Optional. Array of nav menu arguments.
    23  *
    22  *
    24  *     @type int|string|WP_Term $menu            Desired menu. Accepts a menu ID, slug, name, or object. Default empty.
    23  *     @type int|string|WP_Term $menu                 Desired menu. Accepts a menu ID, slug, name, or object.
    25  *     @type string             $menu_class      CSS class to use for the ul element which forms the menu. Default 'menu'.
    24  *                                                    Default empty.
    26  *     @type string             $menu_id         The ID that is applied to the ul element which forms the menu.
    25  *     @type string             $menu_class           CSS class to use for the ul element which forms the menu.
    27  *                                               Default is the menu slug, incremented.
    26  *                                                    Default 'menu'.
    28  *     @type string             $container       Whether to wrap the ul, and what to wrap it with. Default 'div'.
    27  *     @type string             $menu_id              The ID that is applied to the ul element which forms the menu.
    29  *     @type string             $container_class Class that is applied to the container. Default 'menu-{menu slug}-container'.
    28  *                                                    Default is the menu slug, incremented.
    30  *     @type string             $container_id    The ID that is applied to the container. Default empty.
    29  *     @type string             $container            Whether to wrap the ul, and what to wrap it with.
    31  *     @type callable|bool      $fallback_cb     If the menu doesn't exists, a callback function will fire.
    30  *                                                    Default 'div'.
    32  *                                               Default is 'wp_page_menu'. Set to false for no fallback.
    31  *     @type string             $container_class      Class that is applied to the container.
    33  *     @type string             $before          Text before the link markup. Default empty.
    32  *                                                    Default 'menu-{menu slug}-container'.
    34  *     @type string             $after           Text after the link markup. Default empty.
    33  *     @type string             $container_id         The ID that is applied to the container. Default empty.
    35  *     @type string             $link_before     Text before the link text. Default empty.
    34  *     @type string             $container_aria_label The aria-label attribute that is applied to the container
    36  *     @type string             $link_after      Text after the link text. Default empty.
    35  *                                                    when it's a nav element. Default empty.
    37  *     @type bool               $echo            Whether to echo the menu or return it. Default true.
    36  *     @type callable|bool      $fallback_cb          If the menu doesn't exist, a callback function will fire.
    38  *     @type int                $depth           How many levels of the hierarchy are to be included. 0 means all. Default 0.
    37  *                                                    Default is 'wp_page_menu'. Set to false for no fallback.
    39  *     @type object             $walker          Instance of a custom walker class. Default empty.
    38  *     @type string             $before               Text before the link markup. Default empty.
    40  *     @type string             $theme_location  Theme location to be used. Must be registered with register_nav_menu()
    39  *     @type string             $after                Text after the link markup. Default empty.
    41  *                                               in order to be selectable by the user.
    40  *     @type string             $link_before          Text before the link text. Default empty.
    42  *     @type string             $items_wrap      How the list items should be wrapped. Default is a ul with an id and class.
    41  *     @type string             $link_after           Text after the link text. Default empty.
    43  *                                               Uses printf() format with numbered placeholders.
    42  *     @type bool               $echo                 Whether to echo the menu or return it. Default true.
    44  *     @type string             $item_spacing    Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'preserve'.
    43  *     @type int                $depth                How many levels of the hierarchy are to be included.
       
    44  *                                                    0 means all. Default 0.
       
    45  *                                                    Default 0.
       
    46  *     @type object             $walker               Instance of a custom walker class. Default empty.
       
    47  *     @type string             $theme_location       Theme location to be used. Must be registered with
       
    48  *                                                    register_nav_menu() in order to be selectable by the user.
       
    49  *     @type string             $items_wrap           How the list items should be wrapped. Uses printf() format with
       
    50  *                                                    numbered placeholders. Default is a ul with an id and class.
       
    51  *     @type string             $item_spacing         Whether to preserve whitespace within the menu's HTML.
       
    52  *                                                    Accepts 'preserve' or 'discard'. Default 'preserve'.
    45  * }
    53  * }
    46  * @return string|false|void Menu output if $echo is false, false if there are no items or no menu was found.
    54  * @return void|string|false Void if 'echo' argument is true, menu output if 'echo' is false.
       
    55  *                           False if there are no items or no menu was found.
    47  */
    56  */
    48 function wp_nav_menu( $args = array() ) {
    57 function wp_nav_menu( $args = array() ) {
    49 	static $menu_id_slugs = array();
    58 	static $menu_id_slugs = array();
    50 
    59 
    51 	$defaults = array(
    60 	$defaults = array(
    52 		'menu'            => '',
    61 		'menu'                 => '',
    53 		'container'       => 'div',
    62 		'container'            => 'div',
    54 		'container_class' => '',
    63 		'container_class'      => '',
    55 		'container_id'    => '',
    64 		'container_id'         => '',
    56 		'menu_class'      => 'menu',
    65 		'container_aria_label' => '',
    57 		'menu_id'         => '',
    66 		'menu_class'           => 'menu',
    58 		'echo'            => true,
    67 		'menu_id'              => '',
    59 		'fallback_cb'     => 'wp_page_menu',
    68 		'echo'                 => true,
    60 		'before'          => '',
    69 		'fallback_cb'          => 'wp_page_menu',
    61 		'after'           => '',
    70 		'before'               => '',
    62 		'link_before'     => '',
    71 		'after'                => '',
    63 		'link_after'      => '',
    72 		'link_before'          => '',
    64 		'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
    73 		'link_after'           => '',
    65 		'item_spacing'    => 'preserve',
    74 		'items_wrap'           => '<ul id="%1$s" class="%2$s">%3$s</ul>',
    66 		'depth'           => 0,
    75 		'item_spacing'         => 'preserve',
    67 		'walker'          => '',
    76 		'depth'                => 0,
    68 		'theme_location'  => '',
    77 		'walker'               => '',
       
    78 		'theme_location'       => '',
    69 	);
    79 	);
    70 
    80 
    71 	$args = wp_parse_args( $args, $defaults );
    81 	$args = wp_parse_args( $args, $defaults );
    72 
    82 
    73 	if ( ! in_array( $args['item_spacing'], array( 'preserve', 'discard' ), true ) ) {
    83 	if ( ! in_array( $args['item_spacing'], array( 'preserve', 'discard' ), true ) ) {
    74 		// invalid value, fall back to default.
    84 		// Invalid value, fall back to default.
    75 		$args['item_spacing'] = $defaults['item_spacing'];
    85 		$args['item_spacing'] = $defaults['item_spacing'];
    76 	}
    86 	}
    77 
    87 
    78 	/**
    88 	/**
    79 	 * Filters the arguments used to display a navigation menu.
    89 	 * Filters the arguments used to display a navigation menu.
    88 	$args = (object) $args;
    98 	$args = (object) $args;
    89 
    99 
    90 	/**
   100 	/**
    91 	 * Filters whether to short-circuit the wp_nav_menu() output.
   101 	 * Filters whether to short-circuit the wp_nav_menu() output.
    92 	 *
   102 	 *
    93 	 * Returning a non-null value to the filter will short-circuit
   103 	 * Returning a non-null value from the filter will short-circuit wp_nav_menu(),
    94 	 * wp_nav_menu(), echoing that value if $args->echo is true,
   104 	 * echoing that value if $args->echo is true, returning that value otherwise.
    95 	 * returning that value otherwise.
       
    96 	 *
   105 	 *
    97 	 * @since 3.9.0
   106 	 * @since 3.9.0
    98 	 *
   107 	 *
    99 	 * @see wp_nav_menu()
   108 	 * @see wp_nav_menu()
   100 	 *
   109 	 *
   110 		}
   119 		}
   111 
   120 
   112 		return $nav_menu;
   121 		return $nav_menu;
   113 	}
   122 	}
   114 
   123 
   115 	// Get the nav menu based on the requested menu
   124 	// Get the nav menu based on the requested menu.
   116 	$menu = wp_get_nav_menu_object( $args->menu );
   125 	$menu = wp_get_nav_menu_object( $args->menu );
   117 
   126 
   118 	// Get the nav menu based on the theme_location
   127 	// Get the nav menu based on the theme_location.
   119 	if ( ! $menu && $args->theme_location && ( $locations = get_nav_menu_locations() ) && isset( $locations[ $args->theme_location ] ) ) {
   128 	$locations = get_nav_menu_locations();
       
   129 	if ( ! $menu && $args->theme_location && $locations && isset( $locations[ $args->theme_location ] ) ) {
   120 		$menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
   130 		$menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
   121 	}
   131 	}
   122 
   132 
   123 	// get the first menu that has items if we still can't find a menu
   133 	// Get the first menu that has items if we still can't find a menu.
   124 	if ( ! $menu && ! $args->theme_location ) {
   134 	if ( ! $menu && ! $args->theme_location ) {
   125 		$menus = wp_get_nav_menus();
   135 		$menus = wp_get_nav_menus();
   126 		foreach ( $menus as $menu_maybe ) {
   136 		foreach ( $menus as $menu_maybe ) {
   127 			if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) {
   137 			$menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) );
       
   138 			if ( $menu_items ) {
   128 				$menu = $menu_maybe;
   139 				$menu = $menu_maybe;
   129 				break;
   140 				break;
   130 			}
   141 			}
   131 		}
   142 		}
   132 	}
   143 	}
   155 
   166 
   156 	if ( ! $menu || is_wp_error( $menu ) ) {
   167 	if ( ! $menu || is_wp_error( $menu ) ) {
   157 		return false;
   168 		return false;
   158 	}
   169 	}
   159 
   170 
   160 	$nav_menu = $items = '';
   171 	$nav_menu = '';
       
   172 	$items    = '';
   161 
   173 
   162 	$show_container = false;
   174 	$show_container = false;
   163 	if ( $args->container ) {
   175 	if ( $args->container ) {
   164 		/**
   176 		/**
   165 		 * Filters the list of HTML tags that are valid for use as menu containers.
   177 		 * Filters the list of HTML tags that are valid for use as menu containers.
   166 		 *
   178 		 *
   167 		 * @since 3.0.0
   179 		 * @since 3.0.0
   168 		 *
   180 		 *
   169 		 * @param array $tags The acceptable HTML tags for use as menu containers.
   181 		 * @param string[] $tags The acceptable HTML tags for use as menu containers.
   170 		 *                    Default is array containing 'div' and 'nav'.
   182 		 *                       Default is array containing 'div' and 'nav'.
   171 		 */
   183 		 */
   172 		$allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );
   184 		$allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );
   173 		if ( is_string( $args->container ) && in_array( $args->container, $allowed_tags ) ) {
   185 
       
   186 		if ( is_string( $args->container ) && in_array( $args->container, $allowed_tags, true ) ) {
   174 			$show_container = true;
   187 			$show_container = true;
   175 			$class          = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-' . $menu->slug . '-container"';
   188 			$class          = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-' . $menu->slug . '-container"';
   176 			$id             = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
   189 			$id             = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
   177 			$nav_menu      .= '<' . $args->container . $id . $class . '>';
   190 			$aria_label     = ( 'nav' === $args->container && $args->container_aria_label ) ? ' aria-label="' . esc_attr( $args->container_aria_label ) . '"' : '';
   178 		}
   191 			$nav_menu      .= '<' . $args->container . $id . $class . $aria_label . '>';
   179 	}
   192 		}
   180 
   193 	}
   181 	// Set up the $menu_item variables
   194 
       
   195 	// Set up the $menu_item variables.
   182 	_wp_menu_item_classes_by_context( $menu_items );
   196 	_wp_menu_item_classes_by_context( $menu_items );
   183 
   197 
   184 	$sorted_menu_items = $menu_items_with_children = array();
   198 	$sorted_menu_items        = array();
       
   199 	$menu_items_with_children = array();
   185 	foreach ( (array) $menu_items as $menu_item ) {
   200 	foreach ( (array) $menu_items as $menu_item ) {
   186 		$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
   201 		$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
   187 		if ( $menu_item->menu_item_parent ) {
   202 		if ( $menu_item->menu_item_parent ) {
   188 			$menu_items_with_children[ $menu_item->menu_item_parent ] = true;
   203 			$menu_items_with_children[ $menu_item->menu_item_parent ] = true;
   189 		}
   204 		}
   190 	}
   205 	}
   191 
   206 
   192 	// Add the menu-item-has-children class where applicable
   207 	// Add the menu-item-has-children class where applicable.
   193 	if ( $menu_items_with_children ) {
   208 	if ( $menu_items_with_children ) {
   194 		foreach ( $sorted_menu_items as &$menu_item ) {
   209 		foreach ( $sorted_menu_items as &$menu_item ) {
   195 			if ( isset( $menu_items_with_children[ $menu_item->ID ] ) ) {
   210 			if ( isset( $menu_items_with_children[ $menu_item->ID ] ) ) {
   196 				$menu_item->classes[] = 'menu-item-has-children';
   211 				$menu_item->classes[] = 'menu-item-has-children';
   197 			}
   212 			}
   211 	$sorted_menu_items = apply_filters( 'wp_nav_menu_objects', $sorted_menu_items, $args );
   226 	$sorted_menu_items = apply_filters( 'wp_nav_menu_objects', $sorted_menu_items, $args );
   212 
   227 
   213 	$items .= walk_nav_menu_tree( $sorted_menu_items, $args->depth, $args );
   228 	$items .= walk_nav_menu_tree( $sorted_menu_items, $args->depth, $args );
   214 	unset( $sorted_menu_items );
   229 	unset( $sorted_menu_items );
   215 
   230 
   216 	// Attributes
   231 	// Attributes.
   217 	if ( ! empty( $args->menu_id ) ) {
   232 	if ( ! empty( $args->menu_id ) ) {
   218 		$wrap_id = $args->menu_id;
   233 		$wrap_id = $args->menu_id;
   219 	} else {
   234 	} else {
   220 		$wrap_id = 'menu-' . $menu->slug;
   235 		$wrap_id = 'menu-' . $menu->slug;
   221 		while ( in_array( $wrap_id, $menu_id_slugs ) ) {
   236 
       
   237 		while ( in_array( $wrap_id, $menu_id_slugs, true ) ) {
   222 			if ( preg_match( '#-(\d+)$#', $wrap_id, $matches ) ) {
   238 			if ( preg_match( '#-(\d+)$#', $wrap_id, $matches ) ) {
   223 				$wrap_id = preg_replace( '#-(\d+)$#', '-' . ++$matches[1], $wrap_id );
   239 				$wrap_id = preg_replace( '#-(\d+)$#', '-' . ++$matches[1], $wrap_id );
   224 			} else {
   240 			} else {
   225 				$wrap_id = $wrap_id . '-1';
   241 				$wrap_id = $wrap_id . '-1';
   226 			}
   242 			}
   283 		return $nav_menu;
   299 		return $nav_menu;
   284 	}
   300 	}
   285 }
   301 }
   286 
   302 
   287 /**
   303 /**
   288  * Add the class property classes for the current context, if applicable.
   304  * Adds the class property classes for the current context, if applicable.
   289  *
   305  *
   290  * @access private
   306  * @access private
   291  * @since 3.0.0
   307  * @since 3.0.0
   292  *
   308  *
   293  * @global WP_Query   $wp_query
   309  * @global WP_Query   $wp_query   WordPress Query object.
   294  * @global WP_Rewrite $wp_rewrite
   310  * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
   295  *
   311  *
   296  * @param array $menu_items The current menu item objects to which to add the class property information.
   312  * @param array $menu_items The current menu item objects to which to add the class property information.
   297  */
   313  */
   298 function _wp_menu_item_classes_by_context( &$menu_items ) {
   314 function _wp_menu_item_classes_by_context( &$menu_items ) {
   299 	global $wp_query, $wp_rewrite;
   315 	global $wp_query, $wp_rewrite;
   382 		// This menu item is set as the 'Privacy Policy Page'.
   398 		// This menu item is set as the 'Privacy Policy Page'.
   383 		if ( 'post_type' === $menu_item->type && $privacy_policy_page_id === (int) $menu_item->object_id ) {
   399 		if ( 'post_type' === $menu_item->type && $privacy_policy_page_id === (int) $menu_item->object_id ) {
   384 			$classes[] = 'menu-item-privacy-policy';
   400 			$classes[] = 'menu-item-privacy-policy';
   385 		}
   401 		}
   386 
   402 
   387 		// if the menu item corresponds to a taxonomy term for the currently-queried non-hierarchical post object
   403 		// If the menu item corresponds to a taxonomy term for the currently queried non-hierarchical post object.
   388 		if ( $wp_query->is_singular && 'taxonomy' == $menu_item->type && in_array( $menu_item->object_id, $possible_object_parents ) ) {
   404 		if ( $wp_query->is_singular && 'taxonomy' === $menu_item->type
       
   405 			&& in_array( (int) $menu_item->object_id, $possible_object_parents, true )
       
   406 		) {
   389 			$active_parent_object_ids[] = (int) $menu_item->object_id;
   407 			$active_parent_object_ids[] = (int) $menu_item->object_id;
   390 			$active_parent_item_ids[]   = (int) $menu_item->db_id;
   408 			$active_parent_item_ids[]   = (int) $menu_item->db_id;
   391 			$active_object              = $queried_object->post_type;
   409 			$active_object              = $queried_object->post_type;
   392 
   410 
   393 			// if the menu item corresponds to the currently-queried post or taxonomy object
   411 			// If the menu item corresponds to the currently queried post or taxonomy object.
   394 		} elseif (
   412 		} elseif (
   395 			$menu_item->object_id == $queried_object_id &&
   413 			$menu_item->object_id == $queried_object_id
   396 			(
   414 			&& (
   397 				( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && $wp_query->is_home && $home_page_id == $menu_item->object_id ) ||
   415 				( ! empty( $home_page_id ) && 'post_type' === $menu_item->type
   398 				( 'post_type' == $menu_item->type && $wp_query->is_singular ) ||
   416 					&& $wp_query->is_home && $home_page_id == $menu_item->object_id )
   399 				( 'taxonomy' == $menu_item->type && ( $wp_query->is_category || $wp_query->is_tag || $wp_query->is_tax ) && $queried_object->taxonomy == $menu_item->object )
   417 				|| ( 'post_type' === $menu_item->type && $wp_query->is_singular )
       
   418 				|| ( 'taxonomy' === $menu_item->type
       
   419 					&& ( $wp_query->is_category || $wp_query->is_tag || $wp_query->is_tax )
       
   420 					&& $queried_object->taxonomy == $menu_item->object )
   400 			)
   421 			)
   401 		) {
   422 		) {
   402 			$classes[]                   = 'current-menu-item';
   423 			$classes[]                   = 'current-menu-item';
   403 			$menu_items[ $key ]->current = true;
   424 			$menu_items[ $key ]->current = true;
   404 			$_anc_id                     = (int) $menu_item->db_id;
   425 			$_anc_id                     = (int) $menu_item->db_id;
   405 
   426 
   406 			while (
   427 			while (
   407 				( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) &&
   428 				( $_anc_id = (int) get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) )
   408 				! in_array( $_anc_id, $active_ancestor_item_ids )
   429 				&& ! in_array( $_anc_id, $active_ancestor_item_ids, true )
   409 			) {
   430 			) {
   410 				$active_ancestor_item_ids[] = $_anc_id;
   431 				$active_ancestor_item_ids[] = $_anc_id;
   411 			}
   432 			}
   412 
   433 
   413 			if ( 'post_type' == $menu_item->type && 'page' == $menu_item->object ) {
   434 			if ( 'post_type' === $menu_item->type && 'page' === $menu_item->object ) {
   414 				// Back compat classes for pages to match wp_page_menu()
   435 				// Back compat classes for pages to match wp_page_menu().
   415 				$classes[] = 'page_item';
   436 				$classes[] = 'page_item';
   416 				$classes[] = 'page-item-' . $menu_item->object_id;
   437 				$classes[] = 'page-item-' . $menu_item->object_id;
   417 				$classes[] = 'current_page_item';
   438 				$classes[] = 'current_page_item';
   418 			}
   439 			}
   419 
   440 
   420 			$active_parent_item_ids[]   = (int) $menu_item->menu_item_parent;
   441 			$active_parent_item_ids[]   = (int) $menu_item->menu_item_parent;
   421 			$active_parent_object_ids[] = (int) $menu_item->post_parent;
   442 			$active_parent_object_ids[] = (int) $menu_item->post_parent;
   422 			$active_object              = $menu_item->object;
   443 			$active_object              = $menu_item->object;
   423 
   444 
   424 			// if the menu item corresponds to the currently-queried post type archive
   445 			// If the menu item corresponds to the currently queried post type archive.
   425 		} elseif (
   446 		} elseif (
   426 			'post_type_archive' == $menu_item->type &&
   447 			'post_type_archive' === $menu_item->type
   427 			is_post_type_archive( array( $menu_item->object ) )
   448 			&& is_post_type_archive( array( $menu_item->object ) )
   428 		) {
   449 		) {
   429 			$classes[]                   = 'current-menu-item';
   450 			$classes[]                   = 'current-menu-item';
   430 			$menu_items[ $key ]->current = true;
   451 			$menu_items[ $key ]->current = true;
   431 			$_anc_id                     = (int) $menu_item->db_id;
   452 			$_anc_id                     = (int) $menu_item->db_id;
   432 
   453 
   433 			while (
   454 			while (
   434 				( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) &&
   455 				( $_anc_id = (int) get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) )
   435 				! in_array( $_anc_id, $active_ancestor_item_ids )
   456 				&& ! in_array( $_anc_id, $active_ancestor_item_ids, true )
   436 			) {
   457 			) {
   437 				$active_ancestor_item_ids[] = $_anc_id;
   458 				$active_ancestor_item_ids[] = $_anc_id;
   438 			}
   459 			}
   439 
   460 
   440 			$active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
   461 			$active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
   441 
   462 
   442 			// if the menu item corresponds to the currently-requested URL
   463 			// If the menu item corresponds to the currently requested URL.
   443 		} elseif ( 'custom' == $menu_item->object && isset( $_SERVER['HTTP_HOST'] ) ) {
   464 		} elseif ( 'custom' === $menu_item->object && isset( $_SERVER['HTTP_HOST'] ) ) {
   444 			$_root_relative_current = untrailingslashit( $_SERVER['REQUEST_URI'] );
   465 			$_root_relative_current = untrailingslashit( $_SERVER['REQUEST_URI'] );
   445 
   466 
   446 			//if it is the customize page then it will strips the query var off the url before entering the comparison block.
   467 			// If it's the customize page then it will strip the query var off the URL before entering the comparison block.
   447 			if ( is_customize_preview() ) {
   468 			if ( is_customize_preview() ) {
   448 				$_root_relative_current = strtok( untrailingslashit( $_SERVER['REQUEST_URI'] ), '?' );
   469 				$_root_relative_current = strtok( untrailingslashit( $_SERVER['REQUEST_URI'] ), '?' );
   449 			}
   470 			}
   450 
   471 
   451 			$current_url        = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_root_relative_current );
   472 			$current_url        = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_root_relative_current );
   460 				urldecode( $_indexless_current ),
   481 				urldecode( $_indexless_current ),
   461 				$_root_relative_current,
   482 				$_root_relative_current,
   462 				urldecode( $_root_relative_current ),
   483 				urldecode( $_root_relative_current ),
   463 			);
   484 			);
   464 
   485 
   465 			if ( $raw_item_url && in_array( $item_url, $matches ) ) {
   486 			if ( $raw_item_url && in_array( $item_url, $matches, true ) ) {
   466 				$classes[]                   = 'current-menu-item';
   487 				$classes[]                   = 'current-menu-item';
   467 				$menu_items[ $key ]->current = true;
   488 				$menu_items[ $key ]->current = true;
   468 				$_anc_id                     = (int) $menu_item->db_id;
   489 				$_anc_id                     = (int) $menu_item->db_id;
   469 
   490 
   470 				while (
   491 				while (
   471 					( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) &&
   492 					( $_anc_id = (int) get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) )
   472 					! in_array( $_anc_id, $active_ancestor_item_ids )
   493 					&& ! in_array( $_anc_id, $active_ancestor_item_ids, true )
   473 				) {
   494 				) {
   474 					$active_ancestor_item_ids[] = $_anc_id;
   495 					$active_ancestor_item_ids[] = $_anc_id;
   475 				}
   496 				}
   476 
   497 
   477 				if ( in_array( home_url(), array( untrailingslashit( $current_url ), untrailingslashit( $_indexless_current ) ) ) ) {
   498 				if ( in_array( home_url(), array( untrailingslashit( $current_url ), untrailingslashit( $_indexless_current ) ), true ) ) {
   478 					// Back compat for home link to match wp_page_menu()
   499 					// Back compat for home link to match wp_page_menu().
   479 					$classes[] = 'current_page_item';
   500 					$classes[] = 'current_page_item';
   480 				}
   501 				}
   481 				$active_parent_item_ids[]   = (int) $menu_item->menu_item_parent;
   502 				$active_parent_item_ids[]   = (int) $menu_item->menu_item_parent;
   482 				$active_parent_object_ids[] = (int) $menu_item->post_parent;
   503 				$active_parent_object_ids[] = (int) $menu_item->post_parent;
   483 				$active_object              = $menu_item->object;
   504 				$active_object              = $menu_item->object;
   484 
   505 
   485 				// give front page item current-menu-item class when extra query arguments involved
   506 				// Give front page item the 'current-menu-item' class when extra query arguments are involved.
   486 			} elseif ( $item_url == $front_page_url && is_front_page() ) {
   507 			} elseif ( $item_url == $front_page_url && is_front_page() ) {
   487 				$classes[] = 'current-menu-item';
   508 				$classes[] = 'current-menu-item';
   488 			}
   509 			}
   489 
   510 
   490 			if ( untrailingslashit( $item_url ) == home_url() ) {
   511 			if ( untrailingslashit( $item_url ) == home_url() ) {
   491 				$classes[] = 'menu-item-home';
   512 				$classes[] = 'menu-item-home';
   492 			}
   513 			}
   493 		}
   514 		}
   494 
   515 
   495 		// back-compat with wp_page_menu: add "current_page_parent" to static home page link for any non-page query
   516 		// Back-compat with wp_page_menu(): add "current_page_parent" to static home page link for any non-page query.
   496 		if ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id ) {
   517 		if ( ! empty( $home_page_id ) && 'post_type' === $menu_item->type
       
   518 			&& empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id
       
   519 		) {
   497 			$classes[] = 'current_page_parent';
   520 			$classes[] = 'current_page_parent';
   498 		}
   521 		}
   499 
   522 
   500 		$menu_items[ $key ]->classes = array_unique( $classes );
   523 		$menu_items[ $key ]->classes = array_unique( $classes );
   501 	}
   524 	}
   502 	$active_ancestor_item_ids = array_filter( array_unique( $active_ancestor_item_ids ) );
   525 	$active_ancestor_item_ids = array_filter( array_unique( $active_ancestor_item_ids ) );
   503 	$active_parent_item_ids   = array_filter( array_unique( $active_parent_item_ids ) );
   526 	$active_parent_item_ids   = array_filter( array_unique( $active_parent_item_ids ) );
   504 	$active_parent_object_ids = array_filter( array_unique( $active_parent_object_ids ) );
   527 	$active_parent_object_ids = array_filter( array_unique( $active_parent_object_ids ) );
   505 
   528 
   506 	// set parent's class
   529 	// Set parent's class.
   507 	foreach ( (array) $menu_items as $key => $parent_item ) {
   530 	foreach ( (array) $menu_items as $key => $parent_item ) {
   508 		$classes                                   = (array) $parent_item->classes;
   531 		$classes                                   = (array) $parent_item->classes;
   509 		$menu_items[ $key ]->current_item_ancestor = false;
   532 		$menu_items[ $key ]->current_item_ancestor = false;
   510 		$menu_items[ $key ]->current_item_parent   = false;
   533 		$menu_items[ $key ]->current_item_parent   = false;
   511 
   534 
   512 		if (
   535 		if (
   513 			isset( $parent_item->type ) &&
   536 			isset( $parent_item->type )
   514 			(
   537 			&& (
   515 				// ancestral post object
   538 				// Ancestral post object.
   516 				(
   539 				(
   517 					'post_type' == $parent_item->type &&
   540 					'post_type' === $parent_item->type
   518 					! empty( $queried_object->post_type ) &&
   541 					&& ! empty( $queried_object->post_type )
   519 					is_post_type_hierarchical( $queried_object->post_type ) &&
   542 					&& is_post_type_hierarchical( $queried_object->post_type )
   520 					in_array( $parent_item->object_id, $queried_object->ancestors ) &&
   543 					&& in_array( (int) $parent_item->object_id, $queried_object->ancestors, true )
   521 					$parent_item->object != $queried_object->ID
   544 					&& $parent_item->object != $queried_object->ID
   522 				) ||
   545 				) ||
   523 
   546 
   524 				// ancestral term
   547 				// Ancestral term.
   525 				(
   548 				(
   526 					'taxonomy' == $parent_item->type &&
   549 					'taxonomy' === $parent_item->type
   527 					isset( $possible_taxonomy_ancestors[ $parent_item->object ] ) &&
   550 					&& isset( $possible_taxonomy_ancestors[ $parent_item->object ] )
   528 					in_array( $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ] ) &&
   551 					&& in_array( (int) $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ], true )
   529 					(
   552 					&& (
   530 						! isset( $queried_object->term_id ) ||
   553 						! isset( $queried_object->term_id ) ||
   531 						$parent_item->object_id != $queried_object->term_id
   554 						$parent_item->object_id != $queried_object->term_id
   532 					)
   555 					)
   533 				)
   556 				)
   534 			)
   557 			)
   535 		) {
   558 		) {
   536 			$classes[] = empty( $queried_object->taxonomy ) ? 'current-' . $queried_object->post_type . '-ancestor' : 'current-' . $queried_object->taxonomy . '-ancestor';
   559 			if ( ! empty( $queried_object->taxonomy ) ) {
   537 		}
   560 				$classes[] = 'current-' . $queried_object->taxonomy . '-ancestor';
   538 
   561 			} else {
   539 		if ( in_array( intval( $parent_item->db_id ), $active_ancestor_item_ids ) ) {
   562 				$classes[] = 'current-' . $queried_object->post_type . '-ancestor';
   540 			$classes[]                                 = 'current-menu-ancestor';
   563 			}
       
   564 		}
       
   565 
       
   566 		if ( in_array( (int) $parent_item->db_id, $active_ancestor_item_ids, true ) ) {
       
   567 			$classes[] = 'current-menu-ancestor';
       
   568 
   541 			$menu_items[ $key ]->current_item_ancestor = true;
   569 			$menu_items[ $key ]->current_item_ancestor = true;
   542 		}
   570 		}
   543 		if ( in_array( $parent_item->db_id, $active_parent_item_ids ) ) {
   571 		if ( in_array( (int) $parent_item->db_id, $active_parent_item_ids, true ) ) {
   544 			$classes[]                               = 'current-menu-parent';
   572 			$classes[] = 'current-menu-parent';
       
   573 
   545 			$menu_items[ $key ]->current_item_parent = true;
   574 			$menu_items[ $key ]->current_item_parent = true;
   546 		}
   575 		}
   547 		if ( in_array( $parent_item->object_id, $active_parent_object_ids ) ) {
   576 		if ( in_array( (int) $parent_item->object_id, $active_parent_object_ids, true ) ) {
   548 			$classes[] = 'current-' . $active_object . '-parent';
   577 			$classes[] = 'current-' . $active_object . '-parent';
   549 		}
   578 		}
   550 
   579 
   551 		if ( 'post_type' == $parent_item->type && 'page' == $parent_item->object ) {
   580 		if ( 'post_type' === $parent_item->type && 'page' === $parent_item->object ) {
   552 			// Back compat classes for pages to match wp_page_menu()
   581 			// Back compat classes for pages to match wp_page_menu().
   553 			if ( in_array( 'current-menu-parent', $classes ) ) {
   582 			if ( in_array( 'current-menu-parent', $classes, true ) ) {
   554 				$classes[] = 'current_page_parent';
   583 				$classes[] = 'current_page_parent';
   555 			}
   584 			}
   556 			if ( in_array( 'current-menu-ancestor', $classes ) ) {
   585 			if ( in_array( 'current-menu-ancestor', $classes, true ) ) {
   557 				$classes[] = 'current_page_ancestor';
   586 				$classes[] = 'current_page_ancestor';
   558 			}
   587 			}
   559 		}
   588 		}
   560 
   589 
   561 		$menu_items[ $key ]->classes = array_unique( $classes );
   590 		$menu_items[ $key ]->classes = array_unique( $classes );
   562 	}
   591 	}
   563 }
   592 }
   564 
   593 
   565 /**
   594 /**
   566  * Retrieve the HTML list content for nav menu items.
   595  * Retrieves the HTML list content for nav menu items.
   567  *
   596  *
   568  * @uses Walker_Nav_Menu to create HTML list content.
   597  * @uses Walker_Nav_Menu to create HTML list content.
   569  * @since 3.0.0
   598  * @since 3.0.0
   570  *
   599  *
   571  * @param array    $items The menu items, sorted by each menu item's menu order.
   600  * @param array    $items The menu items, sorted by each menu item's menu order.
   573  * @param stdClass $r     An object containing wp_nav_menu() arguments.
   602  * @param stdClass $r     An object containing wp_nav_menu() arguments.
   574  * @return string The HTML list content for the menu items.
   603  * @return string The HTML list content for the menu items.
   575  */
   604  */
   576 function walk_nav_menu_tree( $items, $depth, $r ) {
   605 function walk_nav_menu_tree( $items, $depth, $r ) {
   577 	$walker = ( empty( $r->walker ) ) ? new Walker_Nav_Menu : $r->walker;
   606 	$walker = ( empty( $r->walker ) ) ? new Walker_Nav_Menu : $r->walker;
   578 	$args   = array( $items, $depth, $r );
   607 
   579 
   608 	return $walker->walk( $items, $depth, $r );
   580 	return call_user_func_array( array( $walker, 'walk' ), $args );
       
   581 }
   609 }
   582 
   610 
   583 /**
   611 /**
   584  * Prevents a menu item ID from being used more than once.
   612  * Prevents a menu item ID from being used more than once.
   585  *
   613  *
   586  * @since 3.0.1
   614  * @since 3.0.1
   587  * @access private
   615  * @access private
   588  *
   616  *
   589  * @staticvar array $used_ids
       
   590  * @param string $id
   617  * @param string $id
   591  * @param object $item
   618  * @param object $item
   592  * @return string
   619  * @return string
   593  */
   620  */
   594 function _nav_menu_item_id_use_once( $id, $item ) {
   621 function _nav_menu_item_id_use_once( $id, $item ) {
   595 	static $_used_ids = array();
   622 	static $_used_ids = array();
   596 	if ( in_array( $item->ID, $_used_ids ) ) {
   623 
       
   624 	if ( in_array( $item->ID, $_used_ids, true ) ) {
   597 		return '';
   625 		return '';
   598 	}
   626 	}
       
   627 
   599 	$_used_ids[] = $item->ID;
   628 	$_used_ids[] = $item->ID;
       
   629 
   600 	return $id;
   630 	return $id;
   601 }
   631 }