angelovcom.net

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

nav-menu.php (46748B)


      1 <?php
      2 /**
      3  * Core Navigation Menu API
      4  *
      5  * @package WordPress
      6  * @subpackage Nav_Menus
      7  * @since 3.0.0
      8  */
      9 
     10 /** Walker_Nav_Menu_Edit class */
     11 require_once ABSPATH . 'wp-admin/includes/class-walker-nav-menu-edit.php';
     12 
     13 /** Walker_Nav_Menu_Checklist class */
     14 require_once ABSPATH . 'wp-admin/includes/class-walker-nav-menu-checklist.php';
     15 
     16 /**
     17  * Prints the appropriate response to a menu quick search.
     18  *
     19  * @since 3.0.0
     20  *
     21  * @param array $request The unsanitized request values.
     22  */
     23 function _wp_ajax_menu_quick_search( $request = array() ) {
     24 	$args            = array();
     25 	$type            = isset( $request['type'] ) ? $request['type'] : '';
     26 	$object_type     = isset( $request['object_type'] ) ? $request['object_type'] : '';
     27 	$query           = isset( $request['q'] ) ? $request['q'] : '';
     28 	$response_format = isset( $request['response-format'] ) ? $request['response-format'] : '';
     29 
     30 	if ( ! $response_format || ! in_array( $response_format, array( 'json', 'markup' ), true ) ) {
     31 		$response_format = 'json';
     32 	}
     33 
     34 	if ( 'markup' === $response_format ) {
     35 		$args['walker'] = new Walker_Nav_Menu_Checklist;
     36 	}
     37 
     38 	if ( 'get-post-item' === $type ) {
     39 		if ( post_type_exists( $object_type ) ) {
     40 			if ( isset( $request['ID'] ) ) {
     41 				$object_id = (int) $request['ID'];
     42 				if ( 'markup' === $response_format ) {
     43 					echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( get_post( $object_id ) ) ), 0, (object) $args );
     44 				} elseif ( 'json' === $response_format ) {
     45 					echo wp_json_encode(
     46 						array(
     47 							'ID'         => $object_id,
     48 							'post_title' => get_the_title( $object_id ),
     49 							'post_type'  => get_post_type( $object_id ),
     50 						)
     51 					);
     52 					echo "\n";
     53 				}
     54 			}
     55 		} elseif ( taxonomy_exists( $object_type ) ) {
     56 			if ( isset( $request['ID'] ) ) {
     57 				$object_id = (int) $request['ID'];
     58 				if ( 'markup' === $response_format ) {
     59 					echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( get_term( $object_id, $object_type ) ) ), 0, (object) $args );
     60 				} elseif ( 'json' === $response_format ) {
     61 					$post_obj = get_term( $object_id, $object_type );
     62 					echo wp_json_encode(
     63 						array(
     64 							'ID'         => $object_id,
     65 							'post_title' => $post_obj->name,
     66 							'post_type'  => $object_type,
     67 						)
     68 					);
     69 					echo "\n";
     70 				}
     71 			}
     72 		}
     73 	} elseif ( preg_match( '/quick-search-(posttype|taxonomy)-([a-zA-Z_-]*\b)/', $type, $matches ) ) {
     74 		if ( 'posttype' === $matches[1] && get_post_type_object( $matches[2] ) ) {
     75 			$post_type_obj = _wp_nav_menu_meta_box_object( get_post_type_object( $matches[2] ) );
     76 			$args          = array_merge(
     77 				$args,
     78 				array(
     79 					'no_found_rows'          => true,
     80 					'update_post_meta_cache' => false,
     81 					'update_post_term_cache' => false,
     82 					'posts_per_page'         => 10,
     83 					'post_type'              => $matches[2],
     84 					's'                      => $query,
     85 				)
     86 			);
     87 			if ( isset( $post_type_obj->_default_query ) ) {
     88 				$args = array_merge( $args, (array) $post_type_obj->_default_query );
     89 			}
     90 			$search_results_query = new WP_Query( $args );
     91 			if ( ! $search_results_query->have_posts() ) {
     92 				return;
     93 			}
     94 			while ( $search_results_query->have_posts() ) {
     95 				$post = $search_results_query->next_post();
     96 				if ( 'markup' === $response_format ) {
     97 					$var_by_ref = $post->ID;
     98 					echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( get_post( $var_by_ref ) ) ), 0, (object) $args );
     99 				} elseif ( 'json' === $response_format ) {
    100 					echo wp_json_encode(
    101 						array(
    102 							'ID'         => $post->ID,
    103 							'post_title' => get_the_title( $post->ID ),
    104 							'post_type'  => $matches[2],
    105 						)
    106 					);
    107 					echo "\n";
    108 				}
    109 			}
    110 		} elseif ( 'taxonomy' === $matches[1] ) {
    111 			$terms = get_terms(
    112 				array(
    113 					'taxonomy'   => $matches[2],
    114 					'name__like' => $query,
    115 					'number'     => 10,
    116 					'hide_empty' => false,
    117 				)
    118 			);
    119 			if ( empty( $terms ) || is_wp_error( $terms ) ) {
    120 				return;
    121 			}
    122 			foreach ( (array) $terms as $term ) {
    123 				if ( 'markup' === $response_format ) {
    124 					echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', array( $term ) ), 0, (object) $args );
    125 				} elseif ( 'json' === $response_format ) {
    126 					echo wp_json_encode(
    127 						array(
    128 							'ID'         => $term->term_id,
    129 							'post_title' => $term->name,
    130 							'post_type'  => $matches[2],
    131 						)
    132 					);
    133 					echo "\n";
    134 				}
    135 			}
    136 		}
    137 	}
    138 }
    139 
    140 /**
    141  * Register nav menu meta boxes and advanced menu items.
    142  *
    143  * @since 3.0.0
    144  */
    145 function wp_nav_menu_setup() {
    146 	// Register meta boxes.
    147 	wp_nav_menu_post_type_meta_boxes();
    148 	add_meta_box( 'add-custom-links', __( 'Custom Links' ), 'wp_nav_menu_item_link_meta_box', 'nav-menus', 'side', 'default' );
    149 	wp_nav_menu_taxonomy_meta_boxes();
    150 
    151 	// Register advanced menu items (columns).
    152 	add_filter( 'manage_nav-menus_columns', 'wp_nav_menu_manage_columns' );
    153 
    154 	// If first time editing, disable advanced items by default.
    155 	if ( false === get_user_option( 'managenav-menuscolumnshidden' ) ) {
    156 		$user = wp_get_current_user();
    157 		update_user_meta(
    158 			$user->ID,
    159 			'managenav-menuscolumnshidden',
    160 			array(
    161 				0 => 'link-target',
    162 				1 => 'css-classes',
    163 				2 => 'xfn',
    164 				3 => 'description',
    165 				4 => 'title-attribute',
    166 			)
    167 		);
    168 	}
    169 }
    170 
    171 /**
    172  * Limit the amount of meta boxes to pages, posts, links, and categories for first time users.
    173  *
    174  * @since 3.0.0
    175  *
    176  * @global array $wp_meta_boxes
    177  */
    178 function wp_initial_nav_menu_meta_boxes() {
    179 	global $wp_meta_boxes;
    180 
    181 	if ( get_user_option( 'metaboxhidden_nav-menus' ) !== false || ! is_array( $wp_meta_boxes ) ) {
    182 		return;
    183 	}
    184 
    185 	$initial_meta_boxes = array( 'add-post-type-page', 'add-post-type-post', 'add-custom-links', 'add-category' );
    186 	$hidden_meta_boxes  = array();
    187 
    188 	foreach ( array_keys( $wp_meta_boxes['nav-menus'] ) as $context ) {
    189 		foreach ( array_keys( $wp_meta_boxes['nav-menus'][ $context ] ) as $priority ) {
    190 			foreach ( $wp_meta_boxes['nav-menus'][ $context ][ $priority ] as $box ) {
    191 				if ( in_array( $box['id'], $initial_meta_boxes, true ) ) {
    192 					unset( $box['id'] );
    193 				} else {
    194 					$hidden_meta_boxes[] = $box['id'];
    195 				}
    196 			}
    197 		}
    198 	}
    199 
    200 	$user = wp_get_current_user();
    201 	update_user_meta( $user->ID, 'metaboxhidden_nav-menus', $hidden_meta_boxes );
    202 }
    203 
    204 /**
    205  * Creates meta boxes for any post type menu item..
    206  *
    207  * @since 3.0.0
    208  */
    209 function wp_nav_menu_post_type_meta_boxes() {
    210 	$post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'object' );
    211 
    212 	if ( ! $post_types ) {
    213 		return;
    214 	}
    215 
    216 	foreach ( $post_types as $post_type ) {
    217 		/**
    218 		 * Filters whether a menu items meta box will be added for the current
    219 		 * object type.
    220 		 *
    221 		 * If a falsey value is returned instead of an object, the menu items
    222 		 * meta box for the current meta box object will not be added.
    223 		 *
    224 		 * @since 3.0.0
    225 		 *
    226 		 * @param WP_Post_Type|false $post_type The current object to add a menu items
    227 		 *                                      meta box for.
    228 		 */
    229 		$post_type = apply_filters( 'nav_menu_meta_box_object', $post_type );
    230 		if ( $post_type ) {
    231 			$id = $post_type->name;
    232 			// Give pages a higher priority.
    233 			$priority = ( 'page' === $post_type->name ? 'core' : 'default' );
    234 			add_meta_box( "add-post-type-{$id}", $post_type->labels->name, 'wp_nav_menu_item_post_type_meta_box', 'nav-menus', 'side', $priority, $post_type );
    235 		}
    236 	}
    237 }
    238 
    239 /**
    240  * Creates meta boxes for any taxonomy menu item.
    241  *
    242  * @since 3.0.0
    243  */
    244 function wp_nav_menu_taxonomy_meta_boxes() {
    245 	$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'object' );
    246 
    247 	if ( ! $taxonomies ) {
    248 		return;
    249 	}
    250 
    251 	foreach ( $taxonomies as $tax ) {
    252 		/** This filter is documented in wp-admin/includes/nav-menu.php */
    253 		$tax = apply_filters( 'nav_menu_meta_box_object', $tax );
    254 		if ( $tax ) {
    255 			$id = $tax->name;
    256 			add_meta_box( "add-{$id}", $tax->labels->name, 'wp_nav_menu_item_taxonomy_meta_box', 'nav-menus', 'side', 'default', $tax );
    257 		}
    258 	}
    259 }
    260 
    261 /**
    262  * Check whether to disable the Menu Locations meta box submit button and inputs.
    263  *
    264  * @since 3.6.0
    265  * @since 5.3.1 The `$echo` parameter was added.
    266  *
    267  * @global bool $one_theme_location_no_menus to determine if no menus exist
    268  *
    269  * @param int|string $nav_menu_selected_id ID, name, or slug of the currently selected menu.
    270  * @param bool       $echo                 Whether to echo or just return the string.
    271  * @return string|false Disabled attribute if at least one menu exists, false if not.
    272  */
    273 function wp_nav_menu_disabled_check( $nav_menu_selected_id, $echo = true ) {
    274 	global $one_theme_location_no_menus;
    275 
    276 	if ( $one_theme_location_no_menus ) {
    277 		return false;
    278 	}
    279 
    280 	return disabled( $nav_menu_selected_id, 0, $echo );
    281 }
    282 
    283 /**
    284  * Displays a meta box for the custom links menu item.
    285  *
    286  * @since 3.0.0
    287  *
    288  * @global int        $_nav_menu_placeholder
    289  * @global int|string $nav_menu_selected_id
    290  */
    291 function wp_nav_menu_item_link_meta_box() {
    292 	global $_nav_menu_placeholder, $nav_menu_selected_id;
    293 
    294 	$_nav_menu_placeholder = 0 > $_nav_menu_placeholder ? $_nav_menu_placeholder - 1 : -1;
    295 
    296 	?>
    297 	<div class="customlinkdiv" id="customlinkdiv">
    298 		<input type="hidden" value="custom" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-type]" />
    299 		<p id="menu-item-url-wrap" class="wp-clearfix">
    300 			<label class="howto" for="custom-menu-item-url"><?php _e( 'URL' ); ?></label>
    301 			<input id="custom-menu-item-url" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-url]" type="text"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="code menu-item-textbox form-required" placeholder="https://" />
    302 		</p>
    303 
    304 		<p id="menu-item-name-wrap" class="wp-clearfix">
    305 			<label class="howto" for="custom-menu-item-name"><?php _e( 'Link Text' ); ?></label>
    306 			<input id="custom-menu-item-name" name="menu-item[<?php echo $_nav_menu_placeholder; ?>][menu-item-title]" type="text"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="regular-text menu-item-textbox" />
    307 		</p>
    308 
    309 		<p class="button-controls wp-clearfix">
    310 			<span class="add-to-menu">
    311 				<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-custom-menu-item" id="submit-customlinkdiv" />
    312 				<span class="spinner"></span>
    313 			</span>
    314 		</p>
    315 
    316 	</div><!-- /.customlinkdiv -->
    317 	<?php
    318 }
    319 
    320 /**
    321  * Displays a meta box for a post type menu item.
    322  *
    323  * @since 3.0.0
    324  *
    325  * @global int        $_nav_menu_placeholder
    326  * @global int|string $nav_menu_selected_id
    327  *
    328  * @param string $object Not used.
    329  * @param array  $box {
    330  *     Post type menu item meta box arguments.
    331  *
    332  *     @type string       $id       Meta box 'id' attribute.
    333  *     @type string       $title    Meta box title.
    334  *     @type callable     $callback Meta box display callback.
    335  *     @type WP_Post_Type $args     Extra meta box arguments (the post type object for this meta box).
    336  * }
    337  */
    338 function wp_nav_menu_item_post_type_meta_box( $object, $box ) {
    339 	global $_nav_menu_placeholder, $nav_menu_selected_id;
    340 
    341 	$post_type_name = $box['args']->name;
    342 	$post_type      = get_post_type_object( $post_type_name );
    343 	$tab_name       = $post_type_name . '-tab';
    344 
    345 	// Paginate browsing for large numbers of post objects.
    346 	$per_page = 50;
    347 	$pagenum  = isset( $_REQUEST[ $tab_name ] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
    348 	$offset   = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
    349 
    350 	$args = array(
    351 		'offset'                 => $offset,
    352 		'order'                  => 'ASC',
    353 		'orderby'                => 'title',
    354 		'posts_per_page'         => $per_page,
    355 		'post_type'              => $post_type_name,
    356 		'suppress_filters'       => true,
    357 		'update_post_term_cache' => false,
    358 		'update_post_meta_cache' => false,
    359 	);
    360 
    361 	if ( isset( $box['args']->_default_query ) ) {
    362 		$args = array_merge( $args, (array) $box['args']->_default_query );
    363 	}
    364 
    365 	/*
    366 	 * If we're dealing with pages, let's prioritize the Front Page,
    367 	 * Posts Page and Privacy Policy Page at the top of the list.
    368 	 */
    369 	$important_pages = array();
    370 	if ( 'page' === $post_type_name ) {
    371 		$suppress_page_ids = array();
    372 
    373 		// Insert Front Page or custom Home link.
    374 		$front_page = 'page' === get_option( 'show_on_front' ) ? (int) get_option( 'page_on_front' ) : 0;
    375 
    376 		$front_page_obj = null;
    377 		if ( ! empty( $front_page ) ) {
    378 			$front_page_obj                = get_post( $front_page );
    379 			$front_page_obj->front_or_home = true;
    380 
    381 			$important_pages[]   = $front_page_obj;
    382 			$suppress_page_ids[] = $front_page_obj->ID;
    383 		} else {
    384 			$_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? (int) $_nav_menu_placeholder - 1 : -1;
    385 			$front_page_obj        = (object) array(
    386 				'front_or_home' => true,
    387 				'ID'            => 0,
    388 				'object_id'     => $_nav_menu_placeholder,
    389 				'post_content'  => '',
    390 				'post_excerpt'  => '',
    391 				'post_parent'   => '',
    392 				'post_title'    => _x( 'Home', 'nav menu home label' ),
    393 				'post_type'     => 'nav_menu_item',
    394 				'type'          => 'custom',
    395 				'url'           => home_url( '/' ),
    396 			);
    397 
    398 			$important_pages[] = $front_page_obj;
    399 		}
    400 
    401 		// Insert Posts Page.
    402 		$posts_page = 'page' === get_option( 'show_on_front' ) ? (int) get_option( 'page_for_posts' ) : 0;
    403 
    404 		if ( ! empty( $posts_page ) ) {
    405 			$posts_page_obj             = get_post( $posts_page );
    406 			$posts_page_obj->posts_page = true;
    407 
    408 			$important_pages[]   = $posts_page_obj;
    409 			$suppress_page_ids[] = $posts_page_obj->ID;
    410 		}
    411 
    412 		// Insert Privacy Policy Page.
    413 		$privacy_policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' );
    414 
    415 		if ( ! empty( $privacy_policy_page_id ) ) {
    416 			$privacy_policy_page = get_post( $privacy_policy_page_id );
    417 			if ( $privacy_policy_page instanceof WP_Post && 'publish' === $privacy_policy_page->post_status ) {
    418 				$privacy_policy_page->privacy_policy_page = true;
    419 
    420 				$important_pages[]   = $privacy_policy_page;
    421 				$suppress_page_ids[] = $privacy_policy_page->ID;
    422 			}
    423 		}
    424 
    425 		// Add suppression array to arguments for WP_Query.
    426 		if ( ! empty( $suppress_page_ids ) ) {
    427 			$args['post__not_in'] = $suppress_page_ids;
    428 		}
    429 	}
    430 
    431 	// @todo Transient caching of these results with proper invalidation on updating of a post of this type.
    432 	$get_posts = new WP_Query;
    433 	$posts     = $get_posts->query( $args );
    434 
    435 	// Only suppress and insert when more than just suppression pages available.
    436 	if ( ! $get_posts->post_count ) {
    437 		if ( ! empty( $suppress_page_ids ) ) {
    438 			unset( $args['post__not_in'] );
    439 			$get_posts = new WP_Query;
    440 			$posts     = $get_posts->query( $args );
    441 		} else {
    442 			echo '<p>' . __( 'No items.' ) . '</p>';
    443 			return;
    444 		}
    445 	} elseif ( ! empty( $important_pages ) ) {
    446 		$posts = array_merge( $important_pages, $posts );
    447 	}
    448 
    449 	$num_pages = $get_posts->max_num_pages;
    450 
    451 	$page_links = paginate_links(
    452 		array(
    453 			'base'               => add_query_arg(
    454 				array(
    455 					$tab_name     => 'all',
    456 					'paged'       => '%#%',
    457 					'item-type'   => 'post_type',
    458 					'item-object' => $post_type_name,
    459 				)
    460 			),
    461 			'format'             => '',
    462 			'prev_text'          => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '&laquo;' ) . '</span>',
    463 			'next_text'          => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '&raquo;' ) . '</span>',
    464 			'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ',
    465 			'total'              => $num_pages,
    466 			'current'            => $pagenum,
    467 		)
    468 	);
    469 
    470 	$db_fields = false;
    471 	if ( is_post_type_hierarchical( $post_type_name ) ) {
    472 		$db_fields = array(
    473 			'parent' => 'post_parent',
    474 			'id'     => 'ID',
    475 		);
    476 	}
    477 
    478 	$walker = new Walker_Nav_Menu_Checklist( $db_fields );
    479 
    480 	$current_tab = 'most-recent';
    481 
    482 	if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array( 'all', 'search' ), true ) ) {
    483 		$current_tab = $_REQUEST[ $tab_name ];
    484 	}
    485 
    486 	if ( ! empty( $_REQUEST[ 'quick-search-posttype-' . $post_type_name ] ) ) {
    487 		$current_tab = 'search';
    488 	}
    489 
    490 	$removed_args = array(
    491 		'action',
    492 		'customlink-tab',
    493 		'edit-menu-item',
    494 		'menu-item',
    495 		'page-tab',
    496 		'_wpnonce',
    497 	);
    498 
    499 	$most_recent_url = '';
    500 	$view_all_url    = '';
    501 	$search_url      = '';
    502 	if ( $nav_menu_selected_id ) {
    503 		$most_recent_url = esc_url( add_query_arg( $tab_name, 'most-recent', remove_query_arg( $removed_args ) ) );
    504 		$view_all_url    = esc_url( add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ) );
    505 		$search_url      = esc_url( add_query_arg( $tab_name, 'search', remove_query_arg( $removed_args ) ) );
    506 	}
    507 	?>
    508 	<div id="posttype-<?php echo $post_type_name; ?>" class="posttypediv">
    509 		<ul id="posttype-<?php echo $post_type_name; ?>-tabs" class="posttype-tabs add-menu-item-tabs">
    510 			<li <?php echo ( 'most-recent' === $current_tab ? ' class="tabs"' : '' ); ?>>
    511 				<a class="nav-tab-link" data-type="tabs-panel-posttype-<?php echo esc_attr( $post_type_name ); ?>-most-recent" href="<?php echo $most_recent_url; ?>#tabs-panel-posttype-<?php echo $post_type_name; ?>-most-recent">
    512 					<?php _e( 'Most Recent' ); ?>
    513 				</a>
    514 			</li>
    515 			<li <?php echo ( 'all' === $current_tab ? ' class="tabs"' : '' ); ?>>
    516 				<a class="nav-tab-link" data-type="<?php echo esc_attr( $post_type_name ); ?>-all" href="<?php echo $view_all_url; ?>#<?php echo $post_type_name; ?>-all">
    517 					<?php _e( 'View All' ); ?>
    518 				</a>
    519 			</li>
    520 			<li <?php echo ( 'search' === $current_tab ? ' class="tabs"' : '' ); ?>>
    521 				<a class="nav-tab-link" data-type="tabs-panel-posttype-<?php echo esc_attr( $post_type_name ); ?>-search" href="<?php echo $search_url; ?>#tabs-panel-posttype-<?php echo $post_type_name; ?>-search">
    522 					<?php _e( 'Search' ); ?>
    523 				</a>
    524 			</li>
    525 		</ul><!-- .posttype-tabs -->
    526 
    527 		<div id="tabs-panel-posttype-<?php echo $post_type_name; ?>-most-recent" class="tabs-panel <?php echo ( 'most-recent' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php _e( 'Most Recent' ); ?>" tabindex="0">
    528 			<ul id="<?php echo $post_type_name; ?>checklist-most-recent" class="categorychecklist form-no-clear">
    529 				<?php
    530 				$recent_args    = array_merge(
    531 					$args,
    532 					array(
    533 						'orderby'        => 'post_date',
    534 						'order'          => 'DESC',
    535 						'posts_per_page' => 15,
    536 					)
    537 				);
    538 				$most_recent    = $get_posts->query( $recent_args );
    539 				$args['walker'] = $walker;
    540 
    541 				/**
    542 				 * Filters the posts displayed in the 'Most Recent' tab of the current
    543 				 * post type's menu items meta box.
    544 				 *
    545 				 * The dynamic portion of the hook name, `$post_type_name`, refers to the post type name.
    546 				 *
    547 				 * Possible hook names include:
    548 				 *
    549 				 *  - `nav_menu_items_post_recent`
    550 				 *  - `nav_menu_items_page_recent`
    551 				 *
    552 				 * @since 4.3.0
    553 				 * @since 4.9.0 Added the `$recent_args` parameter.
    554 				 *
    555 				 * @param WP_Post[] $most_recent An array of post objects being listed.
    556 				 * @param array     $args        An array of `WP_Query` arguments for the meta box.
    557 				 * @param array     $box         Arguments passed to `wp_nav_menu_item_post_type_meta_box()`.
    558 				 * @param array     $recent_args An array of `WP_Query` arguments for 'Most Recent' tab.
    559 				 */
    560 				$most_recent = apply_filters( "nav_menu_items_{$post_type_name}_recent", $most_recent, $args, $box, $recent_args );
    561 
    562 				echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $most_recent ), 0, (object) $args );
    563 				?>
    564 			</ul>
    565 		</div><!-- /.tabs-panel -->
    566 
    567 		<div class="tabs-panel <?php echo ( 'search' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" id="tabs-panel-posttype-<?php echo $post_type_name; ?>-search" role="region" aria-label="<?php echo $post_type->labels->search_items; ?>" tabindex="0">
    568 			<?php
    569 			if ( isset( $_REQUEST[ 'quick-search-posttype-' . $post_type_name ] ) ) {
    570 				$searched       = esc_attr( $_REQUEST[ 'quick-search-posttype-' . $post_type_name ] );
    571 				$search_results = get_posts(
    572 					array(
    573 						's'         => $searched,
    574 						'post_type' => $post_type_name,
    575 						'fields'    => 'all',
    576 						'order'     => 'DESC',
    577 					)
    578 				);
    579 			} else {
    580 				$searched       = '';
    581 				$search_results = array();
    582 			}
    583 			?>
    584 			<p class="quick-search-wrap">
    585 				<label for="quick-search-posttype-<?php echo $post_type_name; ?>" class="screen-reader-text"><?php _e( 'Search' ); ?></label>
    586 				<input type="search"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="quick-search" value="<?php echo $searched; ?>" name="quick-search-posttype-<?php echo $post_type_name; ?>" id="quick-search-posttype-<?php echo $post_type_name; ?>" />
    587 				<span class="spinner"></span>
    588 				<?php submit_button( __( 'Search' ), 'small quick-search-submit hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-posttype-' . $post_type_name ) ); ?>
    589 			</p>
    590 
    591 			<ul id="<?php echo $post_type_name; ?>-search-checklist" data-wp-lists="list:<?php echo $post_type_name; ?>" class="categorychecklist form-no-clear">
    592 			<?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
    593 				<?php
    594 				$args['walker'] = $walker;
    595 				echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $search_results ), 0, (object) $args );
    596 				?>
    597 			<?php elseif ( is_wp_error( $search_results ) ) : ?>
    598 				<li><?php echo $search_results->get_error_message(); ?></li>
    599 			<?php elseif ( ! empty( $searched ) ) : ?>
    600 				<li><?php _e( 'No results found.' ); ?></li>
    601 			<?php endif; ?>
    602 			</ul>
    603 		</div><!-- /.tabs-panel -->
    604 
    605 		<div id="<?php echo $post_type_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php echo ( 'all' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo $post_type->labels->all_items; ?>" tabindex="0">
    606 			<?php if ( ! empty( $page_links ) ) : ?>
    607 				<div class="add-menu-item-pagelinks">
    608 					<?php echo $page_links; ?>
    609 				</div>
    610 			<?php endif; ?>
    611 			<ul id="<?php echo $post_type_name; ?>checklist" data-wp-lists="list:<?php echo $post_type_name; ?>" class="categorychecklist form-no-clear">
    612 				<?php
    613 				$args['walker'] = $walker;
    614 
    615 				if ( $post_type->has_archive ) {
    616 					$_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? (int) $_nav_menu_placeholder - 1 : -1;
    617 					array_unshift(
    618 						$posts,
    619 						(object) array(
    620 							'ID'           => 0,
    621 							'object_id'    => $_nav_menu_placeholder,
    622 							'object'       => $post_type_name,
    623 							'post_content' => '',
    624 							'post_excerpt' => '',
    625 							'post_title'   => $post_type->labels->archives,
    626 							'post_type'    => 'nav_menu_item',
    627 							'type'         => 'post_type_archive',
    628 							'url'          => get_post_type_archive_link( $post_type_name ),
    629 						)
    630 					);
    631 				}
    632 
    633 				/**
    634 				 * Filters the posts displayed in the 'View All' tab of the current
    635 				 * post type's menu items meta box.
    636 				 *
    637 				 * The dynamic portion of the hook name, `$post_type_name`, refers
    638 				 * to the slug of the current post type.
    639 				 *
    640 				 * Possible hook names include:
    641 				 *
    642 				 *  - `nav_menu_items_post`
    643 				 *  - `nav_menu_items_page`
    644 				 *
    645 				 * @since 3.2.0
    646 				 * @since 4.6.0 Converted the `$post_type` parameter to accept a WP_Post_Type object.
    647 				 *
    648 				 * @see WP_Query::query()
    649 				 *
    650 				 * @param object[]     $posts     The posts for the current post type. Mostly `WP_Post` objects, but
    651 				 *                                can also contain "fake" post objects to represent other menu items.
    652 				 * @param array        $args      An array of `WP_Query` arguments.
    653 				 * @param WP_Post_Type $post_type The current post type object for this menu item meta box.
    654 				 */
    655 				$posts = apply_filters( "nav_menu_items_{$post_type_name}", $posts, $args, $post_type );
    656 
    657 				$checkbox_items = walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $posts ), 0, (object) $args );
    658 
    659 				echo $checkbox_items;
    660 				?>
    661 			</ul>
    662 			<?php if ( ! empty( $page_links ) ) : ?>
    663 				<div class="add-menu-item-pagelinks">
    664 					<?php echo $page_links; ?>
    665 				</div>
    666 			<?php endif; ?>
    667 		</div><!-- /.tabs-panel -->
    668 
    669 		<p class="button-controls wp-clearfix" data-items-type="posttype-<?php echo esc_attr( $post_type_name ); ?>">
    670 			<span class="list-controls hide-if-no-js">
    671 				<input type="checkbox"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> id="<?php echo esc_attr( $tab_name ); ?>" class="select-all" />
    672 				<label for="<?php echo esc_attr( $tab_name ); ?>"><?php _e( 'Select All' ); ?></label>
    673 			</span>
    674 
    675 			<span class="add-to-menu">
    676 				<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-post-type-menu-item" id="<?php echo esc_attr( 'submit-posttype-' . $post_type_name ); ?>" />
    677 				<span class="spinner"></span>
    678 			</span>
    679 		</p>
    680 
    681 	</div><!-- /.posttypediv -->
    682 	<?php
    683 }
    684 
    685 /**
    686  * Displays a meta box for a taxonomy menu item.
    687  *
    688  * @since 3.0.0
    689  *
    690  * @global int|string $nav_menu_selected_id
    691  *
    692  * @param string $object Not used.
    693  * @param array  $box {
    694  *     Taxonomy menu item meta box arguments.
    695  *
    696  *     @type string   $id       Meta box 'id' attribute.
    697  *     @type string   $title    Meta box title.
    698  *     @type callable $callback Meta box display callback.
    699  *     @type object   $args     Extra meta box arguments (the taxonomy object for this meta box).
    700  * }
    701  */
    702 function wp_nav_menu_item_taxonomy_meta_box( $object, $box ) {
    703 	global $nav_menu_selected_id;
    704 
    705 	$taxonomy_name = $box['args']->name;
    706 	$taxonomy      = get_taxonomy( $taxonomy_name );
    707 	$tab_name      = $taxonomy_name . '-tab';
    708 
    709 	// Paginate browsing for large numbers of objects.
    710 	$per_page = 50;
    711 	$pagenum  = isset( $_REQUEST[ $tab_name ] ) && isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 1;
    712 	$offset   = 0 < $pagenum ? $per_page * ( $pagenum - 1 ) : 0;
    713 
    714 	$args = array(
    715 		'taxonomy'     => $taxonomy_name,
    716 		'child_of'     => 0,
    717 		'exclude'      => '',
    718 		'hide_empty'   => false,
    719 		'hierarchical' => 1,
    720 		'include'      => '',
    721 		'number'       => $per_page,
    722 		'offset'       => $offset,
    723 		'order'        => 'ASC',
    724 		'orderby'      => 'name',
    725 		'pad_counts'   => false,
    726 	);
    727 
    728 	$terms = get_terms( $args );
    729 
    730 	if ( ! $terms || is_wp_error( $terms ) ) {
    731 		echo '<p>' . __( 'No items.' ) . '</p>';
    732 		return;
    733 	}
    734 
    735 	$num_pages = ceil(
    736 		wp_count_terms(
    737 			array_merge(
    738 				$args,
    739 				array(
    740 					'number' => '',
    741 					'offset' => '',
    742 				)
    743 			)
    744 		) / $per_page
    745 	);
    746 
    747 	$page_links = paginate_links(
    748 		array(
    749 			'base'               => add_query_arg(
    750 				array(
    751 					$tab_name     => 'all',
    752 					'paged'       => '%#%',
    753 					'item-type'   => 'taxonomy',
    754 					'item-object' => $taxonomy_name,
    755 				)
    756 			),
    757 			'format'             => '',
    758 			'prev_text'          => '<span aria-label="' . esc_attr__( 'Previous page' ) . '">' . __( '&laquo;' ) . '</span>',
    759 			'next_text'          => '<span aria-label="' . esc_attr__( 'Next page' ) . '">' . __( '&raquo;' ) . '</span>',
    760 			'before_page_number' => '<span class="screen-reader-text">' . __( 'Page' ) . '</span> ',
    761 			'total'              => $num_pages,
    762 			'current'            => $pagenum,
    763 		)
    764 	);
    765 
    766 	$db_fields = false;
    767 	if ( is_taxonomy_hierarchical( $taxonomy_name ) ) {
    768 		$db_fields = array(
    769 			'parent' => 'parent',
    770 			'id'     => 'term_id',
    771 		);
    772 	}
    773 
    774 	$walker = new Walker_Nav_Menu_Checklist( $db_fields );
    775 
    776 	$current_tab = 'most-used';
    777 
    778 	if ( isset( $_REQUEST[ $tab_name ] ) && in_array( $_REQUEST[ $tab_name ], array( 'all', 'most-used', 'search' ), true ) ) {
    779 		$current_tab = $_REQUEST[ $tab_name ];
    780 	}
    781 
    782 	if ( ! empty( $_REQUEST[ 'quick-search-taxonomy-' . $taxonomy_name ] ) ) {
    783 		$current_tab = 'search';
    784 	}
    785 
    786 	$removed_args = array(
    787 		'action',
    788 		'customlink-tab',
    789 		'edit-menu-item',
    790 		'menu-item',
    791 		'page-tab',
    792 		'_wpnonce',
    793 	);
    794 
    795 	$most_used_url = '';
    796 	$view_all_url  = '';
    797 	$search_url    = '';
    798 	if ( $nav_menu_selected_id ) {
    799 		$most_used_url = esc_url( add_query_arg( $tab_name, 'most-used', remove_query_arg( $removed_args ) ) );
    800 		$view_all_url  = esc_url( add_query_arg( $tab_name, 'all', remove_query_arg( $removed_args ) ) );
    801 		$search_url    = esc_url( add_query_arg( $tab_name, 'search', remove_query_arg( $removed_args ) ) );
    802 	}
    803 	?>
    804 	<div id="taxonomy-<?php echo $taxonomy_name; ?>" class="taxonomydiv">
    805 		<ul id="taxonomy-<?php echo $taxonomy_name; ?>-tabs" class="taxonomy-tabs add-menu-item-tabs">
    806 			<li <?php echo ( 'most-used' === $current_tab ? ' class="tabs"' : '' ); ?>>
    807 				<a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-pop" href="<?php echo $most_used_url; ?>#tabs-panel-<?php echo $taxonomy_name; ?>-pop">
    808 					<?php echo esc_html( $taxonomy->labels->most_used ); ?>
    809 				</a>
    810 			</li>
    811 			<li <?php echo ( 'all' === $current_tab ? ' class="tabs"' : '' ); ?>>
    812 				<a class="nav-tab-link" data-type="tabs-panel-<?php echo esc_attr( $taxonomy_name ); ?>-all" href="<?php echo $view_all_url; ?>#tabs-panel-<?php echo $taxonomy_name; ?>-all">
    813 					<?php _e( 'View All' ); ?>
    814 				</a>
    815 			</li>
    816 			<li <?php echo ( 'search' === $current_tab ? ' class="tabs"' : '' ); ?>>
    817 				<a class="nav-tab-link" data-type="tabs-panel-search-taxonomy-<?php echo esc_attr( $taxonomy_name ); ?>" href="<?php echo $search_url; ?>#tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>">
    818 					<?php _e( 'Search' ); ?>
    819 				</a>
    820 			</li>
    821 		</ul><!-- .taxonomy-tabs -->
    822 
    823 		<div id="tabs-panel-<?php echo $taxonomy_name; ?>-pop" class="tabs-panel <?php echo ( 'most-used' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo $taxonomy->labels->most_used; ?>" tabindex="0">
    824 			<ul id="<?php echo $taxonomy_name; ?>checklist-pop" class="categorychecklist form-no-clear" >
    825 				<?php
    826 				$popular_terms  = get_terms(
    827 					array(
    828 						'taxonomy'     => $taxonomy_name,
    829 						'orderby'      => 'count',
    830 						'order'        => 'DESC',
    831 						'number'       => 10,
    832 						'hierarchical' => false,
    833 					)
    834 				);
    835 				$args['walker'] = $walker;
    836 				echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $popular_terms ), 0, (object) $args );
    837 				?>
    838 			</ul>
    839 		</div><!-- /.tabs-panel -->
    840 
    841 		<div id="tabs-panel-<?php echo $taxonomy_name; ?>-all" class="tabs-panel tabs-panel-view-all <?php echo ( 'all' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" role="region" aria-label="<?php echo $taxonomy->labels->all_items; ?>" tabindex="0">
    842 			<?php if ( ! empty( $page_links ) ) : ?>
    843 				<div class="add-menu-item-pagelinks">
    844 					<?php echo $page_links; ?>
    845 				</div>
    846 			<?php endif; ?>
    847 			<ul id="<?php echo $taxonomy_name; ?>checklist" data-wp-lists="list:<?php echo $taxonomy_name; ?>" class="categorychecklist form-no-clear">
    848 				<?php
    849 				$args['walker'] = $walker;
    850 				echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $terms ), 0, (object) $args );
    851 				?>
    852 			</ul>
    853 			<?php if ( ! empty( $page_links ) ) : ?>
    854 				<div class="add-menu-item-pagelinks">
    855 					<?php echo $page_links; ?>
    856 				</div>
    857 			<?php endif; ?>
    858 		</div><!-- /.tabs-panel -->
    859 
    860 		<div class="tabs-panel <?php echo ( 'search' === $current_tab ? 'tabs-panel-active' : 'tabs-panel-inactive' ); ?>" id="tabs-panel-search-taxonomy-<?php echo $taxonomy_name; ?>" role="region" aria-label="<?php echo $taxonomy->labels->search_items; ?>" tabindex="0">
    861 			<?php
    862 			if ( isset( $_REQUEST[ 'quick-search-taxonomy-' . $taxonomy_name ] ) ) {
    863 				$searched       = esc_attr( $_REQUEST[ 'quick-search-taxonomy-' . $taxonomy_name ] );
    864 				$search_results = get_terms(
    865 					array(
    866 						'taxonomy'     => $taxonomy_name,
    867 						'name__like'   => $searched,
    868 						'fields'       => 'all',
    869 						'orderby'      => 'count',
    870 						'order'        => 'DESC',
    871 						'hierarchical' => false,
    872 					)
    873 				);
    874 			} else {
    875 				$searched       = '';
    876 				$search_results = array();
    877 			}
    878 			?>
    879 			<p class="quick-search-wrap">
    880 				<label for="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" class="screen-reader-text"><?php _e( 'Search' ); ?></label>
    881 				<input type="search" class="quick-search" value="<?php echo $searched; ?>" name="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" id="quick-search-taxonomy-<?php echo $taxonomy_name; ?>" />
    882 				<span class="spinner"></span>
    883 				<?php submit_button( __( 'Search' ), 'small quick-search-submit hide-if-js', 'submit', false, array( 'id' => 'submit-quick-search-taxonomy-' . $taxonomy_name ) ); ?>
    884 			</p>
    885 
    886 			<ul id="<?php echo $taxonomy_name; ?>-search-checklist" data-wp-lists="list:<?php echo $taxonomy_name; ?>" class="categorychecklist form-no-clear">
    887 			<?php if ( ! empty( $search_results ) && ! is_wp_error( $search_results ) ) : ?>
    888 				<?php
    889 				$args['walker'] = $walker;
    890 				echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $search_results ), 0, (object) $args );
    891 				?>
    892 			<?php elseif ( is_wp_error( $search_results ) ) : ?>
    893 				<li><?php echo $search_results->get_error_message(); ?></li>
    894 			<?php elseif ( ! empty( $searched ) ) : ?>
    895 				<li><?php _e( 'No results found.' ); ?></li>
    896 			<?php endif; ?>
    897 			</ul>
    898 		</div><!-- /.tabs-panel -->
    899 
    900 		<p class="button-controls wp-clearfix" data-items-type="taxonomy-<?php echo esc_attr( $taxonomy_name ); ?>">
    901 			<span class="list-controls hide-if-no-js">
    902 				<input type="checkbox"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> id="<?php echo esc_attr( $tab_name ); ?>" class="select-all" />
    903 				<label for="<?php echo esc_attr( $tab_name ); ?>"><?php _e( 'Select All' ); ?></label>
    904 			</span>
    905 
    906 			<span class="add-to-menu">
    907 				<input type="submit"<?php wp_nav_menu_disabled_check( $nav_menu_selected_id ); ?> class="button submit-add-to-menu right" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-taxonomy-menu-item" id="<?php echo esc_attr( 'submit-taxonomy-' . $taxonomy_name ); ?>" />
    908 				<span class="spinner"></span>
    909 			</span>
    910 		</p>
    911 
    912 	</div><!-- /.taxonomydiv -->
    913 	<?php
    914 }
    915 
    916 /**
    917  * Save posted nav menu item data.
    918  *
    919  * @since 3.0.0
    920  *
    921  * @param int     $menu_id   The menu ID for which to save this item. Value of 0 makes a draft, orphaned menu item. Default 0.
    922  * @param array[] $menu_data The unsanitized POSTed menu item data.
    923  * @return int[] The database IDs of the items saved
    924  */
    925 function wp_save_nav_menu_items( $menu_id = 0, $menu_data = array() ) {
    926 	$menu_id     = (int) $menu_id;
    927 	$items_saved = array();
    928 
    929 	if ( 0 == $menu_id || is_nav_menu( $menu_id ) ) {
    930 
    931 		// Loop through all the menu items' POST values.
    932 		foreach ( (array) $menu_data as $_possible_db_id => $_item_object_data ) {
    933 			if (
    934 				// Checkbox is not checked.
    935 				empty( $_item_object_data['menu-item-object-id'] ) &&
    936 				(
    937 					// And item type either isn't set.
    938 					! isset( $_item_object_data['menu-item-type'] ) ||
    939 					// Or URL is the default.
    940 					in_array( $_item_object_data['menu-item-url'], array( 'https://', 'http://', '' ), true ) ||
    941 					// Or it's not a custom menu item (but not the custom home page).
    942 					! ( 'custom' === $_item_object_data['menu-item-type'] && ! isset( $_item_object_data['menu-item-db-id'] ) ) ||
    943 					// Or it *is* a custom menu item that already exists.
    944 					! empty( $_item_object_data['menu-item-db-id'] )
    945 				)
    946 			) {
    947 				// Then this potential menu item is not getting added to this menu.
    948 				continue;
    949 			}
    950 
    951 			// If this possible menu item doesn't actually have a menu database ID yet.
    952 			if (
    953 				empty( $_item_object_data['menu-item-db-id'] ) ||
    954 				( 0 > $_possible_db_id ) ||
    955 				$_possible_db_id != $_item_object_data['menu-item-db-id']
    956 			) {
    957 				$_actual_db_id = 0;
    958 			} else {
    959 				$_actual_db_id = (int) $_item_object_data['menu-item-db-id'];
    960 			}
    961 
    962 			$args = array(
    963 				'menu-item-db-id'       => ( isset( $_item_object_data['menu-item-db-id'] ) ? $_item_object_data['menu-item-db-id'] : '' ),
    964 				'menu-item-object-id'   => ( isset( $_item_object_data['menu-item-object-id'] ) ? $_item_object_data['menu-item-object-id'] : '' ),
    965 				'menu-item-object'      => ( isset( $_item_object_data['menu-item-object'] ) ? $_item_object_data['menu-item-object'] : '' ),
    966 				'menu-item-parent-id'   => ( isset( $_item_object_data['menu-item-parent-id'] ) ? $_item_object_data['menu-item-parent-id'] : '' ),
    967 				'menu-item-position'    => ( isset( $_item_object_data['menu-item-position'] ) ? $_item_object_data['menu-item-position'] : '' ),
    968 				'menu-item-type'        => ( isset( $_item_object_data['menu-item-type'] ) ? $_item_object_data['menu-item-type'] : '' ),
    969 				'menu-item-title'       => ( isset( $_item_object_data['menu-item-title'] ) ? $_item_object_data['menu-item-title'] : '' ),
    970 				'menu-item-url'         => ( isset( $_item_object_data['menu-item-url'] ) ? $_item_object_data['menu-item-url'] : '' ),
    971 				'menu-item-description' => ( isset( $_item_object_data['menu-item-description'] ) ? $_item_object_data['menu-item-description'] : '' ),
    972 				'menu-item-attr-title'  => ( isset( $_item_object_data['menu-item-attr-title'] ) ? $_item_object_data['menu-item-attr-title'] : '' ),
    973 				'menu-item-target'      => ( isset( $_item_object_data['menu-item-target'] ) ? $_item_object_data['menu-item-target'] : '' ),
    974 				'menu-item-classes'     => ( isset( $_item_object_data['menu-item-classes'] ) ? $_item_object_data['menu-item-classes'] : '' ),
    975 				'menu-item-xfn'         => ( isset( $_item_object_data['menu-item-xfn'] ) ? $_item_object_data['menu-item-xfn'] : '' ),
    976 			);
    977 
    978 			$items_saved[] = wp_update_nav_menu_item( $menu_id, $_actual_db_id, $args );
    979 
    980 		}
    981 	}
    982 	return $items_saved;
    983 }
    984 
    985 /**
    986  * Adds custom arguments to some of the meta box object types.
    987  *
    988  * @since 3.0.0
    989  *
    990  * @access private
    991  *
    992  * @param object $object The post type or taxonomy meta-object.
    993  * @return object The post type or taxonomy object.
    994  */
    995 function _wp_nav_menu_meta_box_object( $object = null ) {
    996 	if ( isset( $object->name ) ) {
    997 
    998 		if ( 'page' === $object->name ) {
    999 			$object->_default_query = array(
   1000 				'orderby'     => 'menu_order title',
   1001 				'post_status' => 'publish',
   1002 			);
   1003 
   1004 			// Posts should show only published items.
   1005 		} elseif ( 'post' === $object->name ) {
   1006 			$object->_default_query = array(
   1007 				'post_status' => 'publish',
   1008 			);
   1009 
   1010 			// Categories should be in reverse chronological order.
   1011 		} elseif ( 'category' === $object->name ) {
   1012 			$object->_default_query = array(
   1013 				'orderby' => 'id',
   1014 				'order'   => 'DESC',
   1015 			);
   1016 
   1017 			// Custom post types should show only published items.
   1018 		} else {
   1019 			$object->_default_query = array(
   1020 				'post_status' => 'publish',
   1021 			);
   1022 		}
   1023 	}
   1024 
   1025 	return $object;
   1026 }
   1027 
   1028 /**
   1029  * Returns the menu formatted to edit.
   1030  *
   1031  * @since 3.0.0
   1032  *
   1033  * @param int $menu_id Optional. The ID of the menu to format. Default 0.
   1034  * @return string|WP_Error The menu formatted to edit or error object on failure.
   1035  */
   1036 function wp_get_nav_menu_to_edit( $menu_id = 0 ) {
   1037 	$menu = wp_get_nav_menu_object( $menu_id );
   1038 
   1039 	// If the menu exists, get its items.
   1040 	if ( is_nav_menu( $menu ) ) {
   1041 		$menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'post_status' => 'any' ) );
   1042 		$result     = '<div id="menu-instructions" class="post-body-plain';
   1043 		$result    .= ( ! empty( $menu_items ) ) ? ' menu-instructions-inactive">' : '">';
   1044 		$result    .= '<p>' . __( 'Add menu items from the column on the left.' ) . '</p>';
   1045 		$result    .= '</div>';
   1046 
   1047 		if ( empty( $menu_items ) ) {
   1048 			return $result . ' <ul class="menu" id="menu-to-edit"> </ul>';
   1049 		}
   1050 
   1051 		/**
   1052 		 * Filters the Walker class used when adding nav menu items.
   1053 		 *
   1054 		 * @since 3.0.0
   1055 		 *
   1056 		 * @param string $class   The walker class to use. Default 'Walker_Nav_Menu_Edit'.
   1057 		 * @param int    $menu_id ID of the menu being rendered.
   1058 		 */
   1059 		$walker_class_name = apply_filters( 'wp_edit_nav_menu_walker', 'Walker_Nav_Menu_Edit', $menu_id );
   1060 
   1061 		if ( class_exists( $walker_class_name ) ) {
   1062 			$walker = new $walker_class_name;
   1063 		} else {
   1064 			return new WP_Error(
   1065 				'menu_walker_not_exist',
   1066 				sprintf(
   1067 					/* translators: %s: Walker class name. */
   1068 					__( 'The Walker class named %s does not exist.' ),
   1069 					'<strong>' . $walker_class_name . '</strong>'
   1070 				)
   1071 			);
   1072 		}
   1073 
   1074 		$some_pending_menu_items = false;
   1075 		$some_invalid_menu_items = false;
   1076 		foreach ( (array) $menu_items as $menu_item ) {
   1077 			if ( isset( $menu_item->post_status ) && 'draft' === $menu_item->post_status ) {
   1078 				$some_pending_menu_items = true;
   1079 			}
   1080 			if ( ! empty( $menu_item->_invalid ) ) {
   1081 				$some_invalid_menu_items = true;
   1082 			}
   1083 		}
   1084 
   1085 		if ( $some_pending_menu_items ) {
   1086 			$result .= '<div class="notice notice-info notice-alt inline"><p>' . __( 'Click Save Menu to make pending menu items public.' ) . '</p></div>';
   1087 		}
   1088 
   1089 		if ( $some_invalid_menu_items ) {
   1090 			$result .= '<div class="notice notice-error notice-alt inline"><p>' . __( 'There are some invalid menu items. Please check or delete them.' ) . '</p></div>';
   1091 		}
   1092 
   1093 		$result .= '<ul class="menu" id="menu-to-edit"> ';
   1094 		$result .= walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $menu_items ), 0, (object) array( 'walker' => $walker ) );
   1095 		$result .= ' </ul> ';
   1096 		return $result;
   1097 	} elseif ( is_wp_error( $menu ) ) {
   1098 		return $menu;
   1099 	}
   1100 
   1101 }
   1102 
   1103 /**
   1104  * Returns the columns for the nav menus page.
   1105  *
   1106  * @since 3.0.0
   1107  *
   1108  * @return string[] Array of column titles keyed by their column name.
   1109  */
   1110 function wp_nav_menu_manage_columns() {
   1111 	return array(
   1112 		'_title'          => __( 'Show advanced menu properties' ),
   1113 		'cb'              => '<input type="checkbox" />',
   1114 		'link-target'     => __( 'Link Target' ),
   1115 		'title-attribute' => __( 'Title Attribute' ),
   1116 		'css-classes'     => __( 'CSS Classes' ),
   1117 		'xfn'             => __( 'Link Relationship (XFN)' ),
   1118 		'description'     => __( 'Description' ),
   1119 	);
   1120 }
   1121 
   1122 /**
   1123  * Deletes orphaned draft menu items
   1124  *
   1125  * @access private
   1126  * @since 3.0.0
   1127  *
   1128  * @global wpdb $wpdb WordPress database abstraction object.
   1129  */
   1130 function _wp_delete_orphaned_draft_menu_items() {
   1131 	global $wpdb;
   1132 	$delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
   1133 
   1134 	// Delete orphaned draft menu items.
   1135 	$menu_items_to_delete = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts AS p LEFT JOIN $wpdb->postmeta AS m ON p.ID = m.post_id WHERE post_type = 'nav_menu_item' AND post_status = 'draft' AND meta_key = '_menu_item_orphaned' AND meta_value < %d", $delete_timestamp ) );
   1136 
   1137 	foreach ( (array) $menu_items_to_delete as $menu_item_id ) {
   1138 		wp_delete_post( $menu_item_id, true );
   1139 	}
   1140 }
   1141 
   1142 /**
   1143  * Saves nav menu items
   1144  *
   1145  * @since 3.6.0
   1146  *
   1147  * @param int|string $nav_menu_selected_id    ID, slug, or name of the currently-selected menu.
   1148  * @param string     $nav_menu_selected_title Title of the currently-selected menu.
   1149  * @return array The menu updated message
   1150  */
   1151 function wp_nav_menu_update_menu_items( $nav_menu_selected_id, $nav_menu_selected_title ) {
   1152 	$unsorted_menu_items = wp_get_nav_menu_items(
   1153 		$nav_menu_selected_id,
   1154 		array(
   1155 			'orderby'     => 'ID',
   1156 			'output'      => ARRAY_A,
   1157 			'output_key'  => 'ID',
   1158 			'post_status' => 'draft,publish',
   1159 		)
   1160 	);
   1161 
   1162 	$messages   = array();
   1163 	$menu_items = array();
   1164 
   1165 	// Index menu items by DB ID.
   1166 	foreach ( $unsorted_menu_items as $_item ) {
   1167 		$menu_items[ $_item->db_id ] = $_item;
   1168 	}
   1169 
   1170 	$post_fields = array(
   1171 		'menu-item-db-id',
   1172 		'menu-item-object-id',
   1173 		'menu-item-object',
   1174 		'menu-item-parent-id',
   1175 		'menu-item-position',
   1176 		'menu-item-type',
   1177 		'menu-item-title',
   1178 		'menu-item-url',
   1179 		'menu-item-description',
   1180 		'menu-item-attr-title',
   1181 		'menu-item-target',
   1182 		'menu-item-classes',
   1183 		'menu-item-xfn',
   1184 	);
   1185 
   1186 	wp_defer_term_counting( true );
   1187 
   1188 	// Loop through all the menu items' POST variables.
   1189 	if ( ! empty( $_POST['menu-item-db-id'] ) ) {
   1190 		foreach ( (array) $_POST['menu-item-db-id'] as $_key => $k ) {
   1191 
   1192 			// Menu item title can't be blank.
   1193 			if ( ! isset( $_POST['menu-item-title'][ $_key ] ) || '' === $_POST['menu-item-title'][ $_key ] ) {
   1194 				continue;
   1195 			}
   1196 
   1197 			$args = array();
   1198 			foreach ( $post_fields as $field ) {
   1199 				$args[ $field ] = isset( $_POST[ $field ][ $_key ] ) ? $_POST[ $field ][ $_key ] : '';
   1200 			}
   1201 
   1202 			$menu_item_db_id = wp_update_nav_menu_item( $nav_menu_selected_id, ( $_POST['menu-item-db-id'][ $_key ] != $_key ? 0 : $_key ), $args );
   1203 
   1204 			if ( is_wp_error( $menu_item_db_id ) ) {
   1205 				$messages[] = '<div id="message" class="error"><p>' . $menu_item_db_id->get_error_message() . '</p></div>';
   1206 			} else {
   1207 				unset( $menu_items[ $menu_item_db_id ] );
   1208 			}
   1209 		}
   1210 	}
   1211 
   1212 	// Remove menu items from the menu that weren't in $_POST.
   1213 	if ( ! empty( $menu_items ) ) {
   1214 		foreach ( array_keys( $menu_items ) as $menu_item_id ) {
   1215 			if ( is_nav_menu_item( $menu_item_id ) ) {
   1216 				wp_delete_post( $menu_item_id );
   1217 			}
   1218 		}
   1219 	}
   1220 
   1221 	// Store 'auto-add' pages.
   1222 	$auto_add        = ! empty( $_POST['auto-add-pages'] );
   1223 	$nav_menu_option = (array) get_option( 'nav_menu_options' );
   1224 
   1225 	if ( ! isset( $nav_menu_option['auto_add'] ) ) {
   1226 		$nav_menu_option['auto_add'] = array();
   1227 	}
   1228 
   1229 	if ( $auto_add ) {
   1230 		if ( ! in_array( $nav_menu_selected_id, $nav_menu_option['auto_add'], true ) ) {
   1231 			$nav_menu_option['auto_add'][] = $nav_menu_selected_id;
   1232 		}
   1233 	} else {
   1234 		$key = array_search( $nav_menu_selected_id, $nav_menu_option['auto_add'], true );
   1235 		if ( false !== $key ) {
   1236 			unset( $nav_menu_option['auto_add'][ $key ] );
   1237 		}
   1238 	}
   1239 
   1240 	// Remove non-existent/deleted menus.
   1241 	$nav_menu_option['auto_add'] = array_intersect( $nav_menu_option['auto_add'], wp_get_nav_menus( array( 'fields' => 'ids' ) ) );
   1242 	update_option( 'nav_menu_options', $nav_menu_option );
   1243 
   1244 	wp_defer_term_counting( false );
   1245 
   1246 	/** This action is documented in wp-includes/nav-menu.php */
   1247 	do_action( 'wp_update_nav_menu', $nav_menu_selected_id );
   1248 
   1249 	$messages[] = '<div id="message" class="updated notice is-dismissible"><p>' .
   1250 		sprintf(
   1251 			/* translators: %s: Nav menu title. */
   1252 			__( '%s has been updated.' ),
   1253 			'<strong>' . $nav_menu_selected_title . '</strong>'
   1254 		) . '</p></div>';
   1255 
   1256 	unset( $menu_items, $unsorted_menu_items );
   1257 
   1258 	return $messages;
   1259 }
   1260 
   1261 /**
   1262  * If a JSON blob of navigation menu data is in POST data, expand it and inject
   1263  * it into `$_POST` to avoid PHP `max_input_vars` limitations. See #14134.
   1264  *
   1265  * @ignore
   1266  * @since 4.5.3
   1267  * @access private
   1268  */
   1269 function _wp_expand_nav_menu_post_data() {
   1270 	if ( ! isset( $_POST['nav-menu-data'] ) ) {
   1271 		return;
   1272 	}
   1273 
   1274 	$data = json_decode( stripslashes( $_POST['nav-menu-data'] ) );
   1275 
   1276 	if ( ! is_null( $data ) && $data ) {
   1277 		foreach ( $data as $post_input_data ) {
   1278 			// For input names that are arrays (e.g. `menu-item-db-id[3][4][5]`),
   1279 			// derive the array path keys via regex and set the value in $_POST.
   1280 			preg_match( '#([^\[]*)(\[(.+)\])?#', $post_input_data->name, $matches );
   1281 
   1282 			$array_bits = array( $matches[1] );
   1283 
   1284 			if ( isset( $matches[3] ) ) {
   1285 				$array_bits = array_merge( $array_bits, explode( '][', $matches[3] ) );
   1286 			}
   1287 
   1288 			$new_post_data = array();
   1289 
   1290 			// Build the new array value from leaf to trunk.
   1291 			for ( $i = count( $array_bits ) - 1; $i >= 0; $i-- ) {
   1292 				if ( count( $array_bits ) - 1 == $i ) {
   1293 					$new_post_data[ $array_bits[ $i ] ] = wp_slash( $post_input_data->value );
   1294 				} else {
   1295 					$new_post_data = array( $array_bits[ $i ] => $new_post_data );
   1296 				}
   1297 			}
   1298 
   1299 			$_POST = array_replace_recursive( $_POST, $new_post_data );
   1300 		}
   1301 	}
   1302 }