Issues (4967)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/wp-includes/nav-menu-template.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Nav Menu API: Template functions
4
 *
5
 * @package WordPress
6
 * @subpackage Nav_Menus
7
 * @since 3.0.0
8
 */
9
10
/** Walker_Nav_Menu class */
11
require_once ABSPATH . WPINC . '/class-walker-nav-menu.php';
12
13
/**
14
 * Displays a navigation menu.
15
 *
16
 * @since 3.0.0
17
 * @since 4.7.0 Added the `item_spacing` argument.
18
 *
19
 * @staticvar array $menu_id_slugs
20
 *
21
 * @param array $args {
22
 *     Optional. Array of nav menu arguments.
23
 *
24
 *     @type int|string|WP_Term $menu            Desired menu. Accepts (matching in order) id, slug, name, menu object. Default empty.
25
 *     @type string             $menu_class      CSS class to use for the ul element which forms the menu. Default 'menu'.
26
 *     @type string             $menu_id         The ID that is applied to the ul element which forms the menu.
27
 *                                               Default is the menu slug, incremented.
28
 *     @type string             $container       Whether to wrap the ul, and what to wrap it with. Default 'div'.
29
 *     @type string             $container_class Class that is applied to the container. Default 'menu-{menu slug}-container'.
30
 *     @type string             $container_id    The ID that is applied to the container. Default empty.
31
 *     @type callable|bool      $fallback_cb     If the menu doesn't exists, a callback function will fire.
32
 *                                               Default is 'wp_page_menu'. Set to false for no fallback.
33
 *     @type string             $before          Text before the link markup. Default empty.
34
 *     @type string             $after           Text after the link markup. Default empty.
35
 *     @type string             $link_before     Text before the link text. Default empty.
36
 *     @type string             $link_after      Text after the link text. Default empty.
37
 *     @type bool               $echo            Whether to echo the menu or return it. Default true.
38
 *     @type int                $depth           How many levels of the hierarchy are to be included. 0 means all. Default 0.
39
 *     @type object             $walker          Instance of a custom walker class. Default empty.
40
 *     @type string             $theme_location  Theme location to be used. Must be registered with register_nav_menu()
41
 *                                               in order to be selectable by the user.
42
 *     @type string             $items_wrap      How the list items should be wrapped. Default is a ul with an id and class.
43
 *                                               Uses printf() format with numbered placeholders.
44
 *     @type string             $item_spacing    Whether to preserve whitespace within the menu's HTML. Accepts 'preserve' or 'discard'. Default 'preserve'.
45
 * }
46
 * @return string|false|void Menu output if $echo is false, false if there are no items or no menu was found.
47
 */
48
function wp_nav_menu( $args = array() ) {
49
	static $menu_id_slugs = array();
50
51
	$defaults = array( 'menu' => '', 'container' => 'div', 'container_class' => '', 'container_id' => '', 'menu_class' => 'menu', 'menu_id' => '',
52
	'echo' => true, 'fallback_cb' => 'wp_page_menu', 'before' => '', 'after' => '', 'link_before' => '', 'link_after' => '', 'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>', 'item_spacing' => 'preserve',
53
	'depth' => 0, 'walker' => '', 'theme_location' => '' );
54
55
	$args = wp_parse_args( $args, $defaults );
56
57 View Code Duplication
	if ( ! in_array( $args['item_spacing'], array( 'preserve', 'discard' ), true ) ) {
58
		// invalid value, fall back to default.
59
		$args['item_spacing'] = $defaults['item_spacing'];
60
	}
61
62
	/**
63
	 * Filters the arguments used to display a navigation menu.
64
	 *
65
	 * @since 3.0.0
66
	 *
67
	 * @see wp_nav_menu()
68
	 *
69
	 * @param array $args Array of wp_nav_menu() arguments.
70
	 */
71
	$args = apply_filters( 'wp_nav_menu_args', $args );
72
	$args = (object) $args;
73
74
	/**
75
	 * Filters whether to short-circuit the wp_nav_menu() output.
76
	 *
77
	 * Returning a non-null value to the filter will short-circuit
78
	 * wp_nav_menu(), echoing that value if $args->echo is true,
79
	 * returning that value otherwise.
80
	 *
81
	 * @since 3.9.0
82
	 *
83
	 * @see wp_nav_menu()
84
	 *
85
	 * @param string|null $output Nav menu output to short-circuit with. Default null.
86
	 * @param stdClass    $args   An object containing wp_nav_menu() arguments.
87
	 */
88
	$nav_menu = apply_filters( 'pre_wp_nav_menu', null, $args );
89
90
	if ( null !== $nav_menu ) {
91
		if ( $args->echo ) {
92
			echo $nav_menu;
93
			return;
94
		}
95
96
		return $nav_menu;
97
	}
98
99
	// Get the nav menu based on the requested menu
100
	$menu = wp_get_nav_menu_object( $args->menu );
101
102
	// Get the nav menu based on the theme_location
103
	if ( ! $menu && $args->theme_location && ( $locations = get_nav_menu_locations() ) && isset( $locations[ $args->theme_location ] ) )
104
		$menu = wp_get_nav_menu_object( $locations[ $args->theme_location ] );
105
106
	// get the first menu that has items if we still can't find a menu
107
	if ( ! $menu && !$args->theme_location ) {
108
		$menus = wp_get_nav_menus();
109
		foreach ( $menus as $menu_maybe ) {
110
			if ( $menu_items = wp_get_nav_menu_items( $menu_maybe->term_id, array( 'update_post_term_cache' => false ) ) ) {
111
				$menu = $menu_maybe;
112
				break;
113
			}
114
		}
115
	}
116
117
	if ( empty( $args->menu ) ) {
118
		$args->menu = $menu;
119
	}
120
121
	// If the menu exists, get its items.
122
	if ( $menu && ! is_wp_error($menu) && !isset($menu_items) )
123
		$menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'update_post_term_cache' => false ) );
124
125
	/*
126
	 * If no menu was found:
127
	 *  - Fall back (if one was specified), or bail.
128
	 *
129
	 * If no menu items were found:
130
	 *  - Fall back, but only if no theme location was specified.
131
	 *  - Otherwise, bail.
132
	 */
133
	if ( ( !$menu || is_wp_error($menu) || ( isset($menu_items) && empty($menu_items) && !$args->theme_location ) )
134
		&& isset( $args->fallback_cb ) && $args->fallback_cb && is_callable( $args->fallback_cb ) )
135
			return call_user_func( $args->fallback_cb, (array) $args );
136
137
	if ( ! $menu || is_wp_error( $menu ) )
138
		return false;
139
140
	$nav_menu = $items = '';
141
142
	$show_container = false;
143
	if ( $args->container ) {
144
		/**
145
		 * Filters the list of HTML tags that are valid for use as menu containers.
146
		 *
147
		 * @since 3.0.0
148
		 *
149
		 * @param array $tags The acceptable HTML tags for use as menu containers.
150
		 *                    Default is array containing 'div' and 'nav'.
151
		 */
152
		$allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav' ) );
153
		if ( is_string( $args->container ) && in_array( $args->container, $allowed_tags ) ) {
154
			$show_container = true;
155
			$class = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-'. $menu->slug .'-container"';
156
			$id = $args->container_id ? ' id="' . esc_attr( $args->container_id ) . '"' : '';
157
			$nav_menu .= '<'. $args->container . $id . $class . '>';
158
		}
159
	}
160
161
	// Set up the $menu_item variables
162
	_wp_menu_item_classes_by_context( $menu_items );
0 ignored issues
show
It seems like $menu_items can also be of type false; however, _wp_menu_item_classes_by_context() does only seem to accept array, did you maybe forget to handle an error condition?
Loading history...
163
164
	$sorted_menu_items = $menu_items_with_children = array();
165
	foreach ( (array) $menu_items as $menu_item ) {
166
		$sorted_menu_items[ $menu_item->menu_order ] = $menu_item;
167
		if ( $menu_item->menu_item_parent )
168
			$menu_items_with_children[ $menu_item->menu_item_parent ] = true;
169
	}
170
171
	// Add the menu-item-has-children class where applicable
172
	if ( $menu_items_with_children ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $menu_items_with_children of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
173
		foreach ( $sorted_menu_items as &$menu_item ) {
174
			if ( isset( $menu_items_with_children[ $menu_item->ID ] ) )
175
				$menu_item->classes[] = 'menu-item-has-children';
176
		}
177
	}
178
179
	unset( $menu_items, $menu_item );
180
181
	/**
182
	 * Filters the sorted list of menu item objects before generating the menu's HTML.
183
	 *
184
	 * @since 3.1.0
185
	 *
186
	 * @param array    $sorted_menu_items The menu items, sorted by each menu item's menu order.
187
	 * @param stdClass $args              An object containing wp_nav_menu() arguments.
188
	 */
189
	$sorted_menu_items = apply_filters( 'wp_nav_menu_objects', $sorted_menu_items, $args );
190
191
	$items .= walk_nav_menu_tree( $sorted_menu_items, $args->depth, $args );
192
	unset($sorted_menu_items);
193
194
	// Attributes
195
	if ( ! empty( $args->menu_id ) ) {
196
		$wrap_id = $args->menu_id;
197
	} else {
198
		$wrap_id = 'menu-' . $menu->slug;
199
		while ( in_array( $wrap_id, $menu_id_slugs ) ) {
200
			if ( preg_match( '#-(\d+)$#', $wrap_id, $matches ) )
201
				$wrap_id = preg_replace('#-(\d+)$#', '-' . ++$matches[1], $wrap_id );
202
			else
203
				$wrap_id = $wrap_id . '-1';
204
		}
205
	}
206
	$menu_id_slugs[] = $wrap_id;
207
208
	$wrap_class = $args->menu_class ? $args->menu_class : '';
209
210
	/**
211
	 * Filters the HTML list content for navigation menus.
212
	 *
213
	 * @since 3.0.0
214
	 *
215
	 * @see wp_nav_menu()
216
	 *
217
	 * @param string   $items The HTML list content for the menu items.
218
	 * @param stdClass $args  An object containing wp_nav_menu() arguments.
219
	 */
220
	$items = apply_filters( 'wp_nav_menu_items', $items, $args );
221
	/**
222
	 * Filters the HTML list content for a specific navigation menu.
223
	 *
224
	 * @since 3.0.0
225
	 *
226
	 * @see wp_nav_menu()
227
	 *
228
	 * @param string   $items The HTML list content for the menu items.
229
	 * @param stdClass $args  An object containing wp_nav_menu() arguments.
230
	 */
231
	$items = apply_filters( "wp_nav_menu_{$menu->slug}_items", $items, $args );
232
233
	// Don't print any markup if there are no items at this point.
234
	if ( empty( $items ) )
235
		return false;
236
237
	$nav_menu .= sprintf( $args->items_wrap, esc_attr( $wrap_id ), esc_attr( $wrap_class ), $items );
238
	unset( $items );
239
240
	if ( $show_container )
241
		$nav_menu .= '</' . $args->container . '>';
242
243
	/**
244
	 * Filters the HTML content for navigation menus.
245
	 *
246
	 * @since 3.0.0
247
	 *
248
	 * @see wp_nav_menu()
249
	 *
250
	 * @param string   $nav_menu The HTML content for the navigation menu.
251
	 * @param stdClass $args     An object containing wp_nav_menu() arguments.
252
	 */
253
	$nav_menu = apply_filters( 'wp_nav_menu', $nav_menu, $args );
254
255
	if ( $args->echo )
256
		echo $nav_menu;
257
	else
258
		return $nav_menu;
259
}
260
261
/**
262
 * Add the class property classes for the current context, if applicable.
263
 *
264
 * @access private
265
 * @since 3.0.0
266
 *
267
 * @global WP_Query   $wp_query
268
 * @global WP_Rewrite $wp_rewrite
269
 *
270
 * @param array $menu_items The current menu item objects to which to add the class property information.
271
 */
272
function _wp_menu_item_classes_by_context( &$menu_items ) {
273
	global $wp_query, $wp_rewrite;
274
275
	$queried_object = $wp_query->get_queried_object();
276
	$queried_object_id = (int) $wp_query->queried_object_id;
277
278
	$active_object = '';
279
	$active_ancestor_item_ids = array();
280
	$active_parent_item_ids = array();
281
	$active_parent_object_ids = array();
282
	$possible_taxonomy_ancestors = array();
283
	$possible_object_parents = array();
284
	$home_page_id = (int) get_option( 'page_for_posts' );
285
286
	if ( $wp_query->is_singular && ! empty( $queried_object->post_type ) && ! is_post_type_hierarchical( $queried_object->post_type ) ) {
287
		foreach ( (array) get_object_taxonomies( $queried_object->post_type ) as $taxonomy ) {
288
			if ( is_taxonomy_hierarchical( $taxonomy ) ) {
289
				$term_hierarchy = _get_term_hierarchy( $taxonomy );
290
				$terms = wp_get_object_terms( $queried_object_id, $taxonomy, array( 'fields' => 'ids' ) );
291
				if ( is_array( $terms ) ) {
292
					$possible_object_parents = array_merge( $possible_object_parents, $terms );
293
					$term_to_ancestor = array();
294
					foreach ( (array) $term_hierarchy as $anc => $descs ) {
295
						foreach ( (array) $descs as $desc )
296
							$term_to_ancestor[ $desc ] = $anc;
297
					}
298
299
					foreach ( $terms as $desc ) {
300 View Code Duplication
						do {
301
							$possible_taxonomy_ancestors[ $taxonomy ][] = $desc;
302
							if ( isset( $term_to_ancestor[ $desc ] ) ) {
303
								$_desc = $term_to_ancestor[ $desc ];
304
								unset( $term_to_ancestor[ $desc ] );
305
								$desc = $_desc;
306
							} else {
307
								$desc = 0;
308
							}
309
						} while ( ! empty( $desc ) );
310
					}
311
				}
312
			}
313
		}
314
	} elseif ( ! empty( $queried_object->taxonomy ) && is_taxonomy_hierarchical( $queried_object->taxonomy ) ) {
315
		$term_hierarchy = _get_term_hierarchy( $queried_object->taxonomy );
316
		$term_to_ancestor = array();
317
		foreach ( (array) $term_hierarchy as $anc => $descs ) {
318
			foreach ( (array) $descs as $desc )
319
				$term_to_ancestor[ $desc ] = $anc;
320
		}
321
		$desc = $queried_object->term_id;
322 View Code Duplication
		do {
323
			$possible_taxonomy_ancestors[ $queried_object->taxonomy ][] = $desc;
324
			if ( isset( $term_to_ancestor[ $desc ] ) ) {
325
				$_desc = $term_to_ancestor[ $desc ];
326
				unset( $term_to_ancestor[ $desc ] );
327
				$desc = $_desc;
328
			} else {
329
				$desc = 0;
330
			}
331
		} while ( ! empty( $desc ) );
332
	}
333
334
	$possible_object_parents = array_filter( $possible_object_parents );
335
336
	$front_page_url = home_url();
337
	$front_page_id  = (int) get_option( 'page_on_front' );
338
339
	foreach ( (array) $menu_items as $key => $menu_item ) {
340
341
		$menu_items[$key]->current = false;
342
343
		$classes = (array) $menu_item->classes;
344
		$classes[] = 'menu-item';
345
		$classes[] = 'menu-item-type-' . $menu_item->type;
346
		$classes[] = 'menu-item-object-' . $menu_item->object;
347
348
		// This menu item is set as the 'Front Page'.
349
		if ( 'post_type' === $menu_item->type && $front_page_id === (int) $menu_item->object_id ) {
350
			$classes[] = 'menu-item-home';
351
		}
352
353
		// if the menu item corresponds to a taxonomy term for the currently-queried non-hierarchical post object
354
		if ( $wp_query->is_singular && 'taxonomy' == $menu_item->type && in_array( $menu_item->object_id, $possible_object_parents ) ) {
355
			$active_parent_object_ids[] = (int) $menu_item->object_id;
356
			$active_parent_item_ids[] = (int) $menu_item->db_id;
357
			$active_object = $queried_object->post_type;
358
359
		// if the menu item corresponds to the currently-queried post or taxonomy object
360
		} elseif (
361
			$menu_item->object_id == $queried_object_id &&
362
			(
363
				( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && $wp_query->is_home && $home_page_id == $menu_item->object_id ) ||
364
				( 'post_type' == $menu_item->type && $wp_query->is_singular ) ||
365
				( 'taxonomy' == $menu_item->type && ( $wp_query->is_category || $wp_query->is_tag || $wp_query->is_tax ) && $queried_object->taxonomy == $menu_item->object )
366
			)
367
		) {
368
			$classes[] = 'current-menu-item';
369
			$menu_items[$key]->current = true;
370
			$_anc_id = (int) $menu_item->db_id;
371
372 View Code Duplication
			while(
373
				( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) &&
374
				! in_array( $_anc_id, $active_ancestor_item_ids )
375
			) {
376
				$active_ancestor_item_ids[] = $_anc_id;
377
			}
378
379
			if ( 'post_type' == $menu_item->type && 'page' == $menu_item->object ) {
380
				// Back compat classes for pages to match wp_page_menu()
381
				$classes[] = 'page_item';
382
				$classes[] = 'page-item-' . $menu_item->object_id;
383
				$classes[] = 'current_page_item';
384
			}
385
386
			$active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
387
			$active_parent_object_ids[] = (int) $menu_item->post_parent;
388
			$active_object = $menu_item->object;
389
390
		// if the menu item corresponds to the currently-queried post type archive
391
		} elseif (
392
			'post_type_archive' == $menu_item->type &&
393
			is_post_type_archive( array( $menu_item->object ) )
394
		) {
395
			$classes[] = 'current-menu-item';
396
			$menu_items[$key]->current = true;
397
		// if the menu item corresponds to the currently-requested URL
398
		} elseif ( 'custom' == $menu_item->object && isset( $_SERVER['HTTP_HOST'] ) ) {
399
			$_root_relative_current = untrailingslashit( $_SERVER['REQUEST_URI'] );
400
401
			//if it is the customize page then it will strips the query var off the url before entering the comparison block.
402
			if ( is_customize_preview() ) {
403
				$_root_relative_current = strtok( untrailingslashit( $_SERVER['REQUEST_URI'] ), '?' );
404
			}
405
			$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_root_relative_current );
406
			$raw_item_url = strpos( $menu_item->url, '#' ) ? substr( $menu_item->url, 0, strpos( $menu_item->url, '#' ) ) : $menu_item->url;
407
			$item_url = set_url_scheme( untrailingslashit( $raw_item_url ) );
408
			$_indexless_current = untrailingslashit( preg_replace( '/' . preg_quote( $wp_rewrite->index, '/' ) . '$/', '', $current_url ) );
409
410
			if ( $raw_item_url && in_array( $item_url, array( $current_url, $_indexless_current, $_root_relative_current ) ) ) {
411
				$classes[] = 'current-menu-item';
412
				$menu_items[$key]->current = true;
413
				$_anc_id = (int) $menu_item->db_id;
414
415 View Code Duplication
				while(
416
					( $_anc_id = get_post_meta( $_anc_id, '_menu_item_menu_item_parent', true ) ) &&
417
					! in_array( $_anc_id, $active_ancestor_item_ids )
418
				) {
419
					$active_ancestor_item_ids[] = $_anc_id;
420
				}
421
422
				if ( in_array( home_url(), array( untrailingslashit( $current_url ), untrailingslashit( $_indexless_current ) ) ) ) {
423
					// Back compat for home link to match wp_page_menu()
424
					$classes[] = 'current_page_item';
425
				}
426
				$active_parent_item_ids[] = (int) $menu_item->menu_item_parent;
427
				$active_parent_object_ids[] = (int) $menu_item->post_parent;
428
				$active_object = $menu_item->object;
429
430
			// give front page item current-menu-item class when extra query arguments involved
431
			} elseif ( $item_url == $front_page_url && is_front_page() ) {
432
				$classes[] = 'current-menu-item';
433
			}
434
435
			if ( untrailingslashit($item_url) == home_url() )
436
				$classes[] = 'menu-item-home';
437
		}
438
439
		// back-compat with wp_page_menu: add "current_page_parent" to static home page link for any non-page query
440
		if ( ! empty( $home_page_id ) && 'post_type' == $menu_item->type && empty( $wp_query->is_page ) && $home_page_id == $menu_item->object_id )
441
			$classes[] = 'current_page_parent';
442
443
		$menu_items[$key]->classes = array_unique( $classes );
444
	}
445
	$active_ancestor_item_ids = array_filter( array_unique( $active_ancestor_item_ids ) );
446
	$active_parent_item_ids = array_filter( array_unique( $active_parent_item_ids ) );
447
	$active_parent_object_ids = array_filter( array_unique( $active_parent_object_ids ) );
448
449
	// set parent's class
450
	foreach ( (array) $menu_items as $key => $parent_item ) {
451
		$classes = (array) $parent_item->classes;
452
		$menu_items[$key]->current_item_ancestor = false;
453
		$menu_items[$key]->current_item_parent = false;
454
455
		if (
456
			isset( $parent_item->type ) &&
457
			(
458
				// ancestral post object
459
				(
460
					'post_type' == $parent_item->type &&
461
					! empty( $queried_object->post_type ) &&
462
					is_post_type_hierarchical( $queried_object->post_type ) &&
463
					in_array( $parent_item->object_id, $queried_object->ancestors ) &&
464
					$parent_item->object != $queried_object->ID
465
				) ||
466
467
				// ancestral term
468
				(
469
					'taxonomy' == $parent_item->type &&
470
					isset( $possible_taxonomy_ancestors[ $parent_item->object ] ) &&
471
					in_array( $parent_item->object_id, $possible_taxonomy_ancestors[ $parent_item->object ] ) &&
472
					(
473
						! isset( $queried_object->term_id ) ||
474
						$parent_item->object_id != $queried_object->term_id
475
					)
476
				)
477
			)
478
		) {
479
			$classes[] = empty( $queried_object->taxonomy ) ? 'current-' . $queried_object->post_type . '-ancestor' : 'current-' . $queried_object->taxonomy . '-ancestor';
480
		}
481
482
		if ( in_array(  intval( $parent_item->db_id ), $active_ancestor_item_ids ) ) {
483
			$classes[] = 'current-menu-ancestor';
484
			$menu_items[$key]->current_item_ancestor = true;
485
		}
486
		if ( in_array( $parent_item->db_id, $active_parent_item_ids ) ) {
487
			$classes[] = 'current-menu-parent';
488
			$menu_items[$key]->current_item_parent = true;
489
		}
490
		if ( in_array( $parent_item->object_id, $active_parent_object_ids ) )
491
			$classes[] = 'current-' . $active_object . '-parent';
492
493
		if ( 'post_type' == $parent_item->type && 'page' == $parent_item->object ) {
494
			// Back compat classes for pages to match wp_page_menu()
495
			if ( in_array('current-menu-parent', $classes) )
496
				$classes[] = 'current_page_parent';
497
			if ( in_array('current-menu-ancestor', $classes) )
498
				$classes[] = 'current_page_ancestor';
499
		}
500
501
		$menu_items[$key]->classes = array_unique( $classes );
502
	}
503
}
504
505
/**
506
 * Retrieve the HTML list content for nav menu items.
507
 *
508
 * @uses Walker_Nav_Menu to create HTML list content.
509
 * @since 3.0.0
510
 *
511
 * @param array    $items The menu items, sorted by each menu item's menu order.
512
 * @param int      $depth Depth of the item in reference to parents.
513
 * @param stdClass $r     An object containing wp_nav_menu() arguments.
514
 * @return string The HTML list content for the menu items.
515
 */
516
function walk_nav_menu_tree( $items, $depth, $r ) {
517
	$walker = ( empty($r->walker) ) ? new Walker_Nav_Menu : $r->walker;
518
	$args = array( $items, $depth, $r );
519
520
	return call_user_func_array( array( $walker, 'walk' ), $args );
521
}
522
523
/**
524
 * Prevents a menu item ID from being used more than once.
525
 *
526
 * @since 3.0.1
527
 * @access private
528
 *
529
 * @staticvar array $used_ids
530
 * @param string $id
531
 * @param object $item
532
 * @return string
533
 */
534
function _nav_menu_item_id_use_once( $id, $item ) {
535
	static $_used_ids = array();
536
	if ( in_array( $item->ID, $_used_ids ) ) {
537
		return '';
538
	}
539
	$_used_ids[] = $item->ID;
540
	return $id;
541
}
542