wp/wp-includes/class-wp-customize-nav-menus.php
changeset 9 177826044cd9
parent 7 cf61fcea0001
child 16 a86126ab1dd4
equal deleted inserted replaced
8:c7c34916027a 9:177826044cd9
    40 	 * @since 4.3.0
    40 	 * @since 4.3.0
    41 	 *
    41 	 *
    42 	 * @param object $manager An instance of the WP_Customize_Manager class.
    42 	 * @param object $manager An instance of the WP_Customize_Manager class.
    43 	 */
    43 	 */
    44 	public function __construct( $manager ) {
    44 	public function __construct( $manager ) {
    45 		$this->manager = $manager;
    45 		$this->manager                     = $manager;
    46 		$this->original_nav_menu_locations = get_nav_menu_locations();
    46 		$this->original_nav_menu_locations = get_nav_menu_locations();
    47 
    47 
    48 		// See https://github.com/xwp/wp-customize-snapshots/blob/962586659688a5b1fd9ae93618b7ce2d4e7a421c/php/class-customize-snapshot-manager.php#L469-L499
    48 		// See https://github.com/xwp/wp-customize-snapshots/blob/962586659688a5b1fd9ae93618b7ce2d4e7a421c/php/class-customize-snapshot-manager.php#L469-L499
    49 		add_action( 'customize_register', array( $this, 'customize_register' ), 11 );
    49 		add_action( 'customize_register', array( $this, 'customize_register' ), 11 );
    50 		add_filter( 'customize_dynamic_setting_args', array( $this, 'filter_dynamic_setting_args' ), 10, 2 );
    50 		add_filter( 'customize_dynamic_setting_args', array( $this, 'filter_dynamic_setting_args' ), 10, 2 );
    73 	/**
    73 	/**
    74 	 * Adds a nonce for customizing menus.
    74 	 * Adds a nonce for customizing menus.
    75 	 *
    75 	 *
    76 	 * @since 4.5.0
    76 	 * @since 4.5.0
    77 	 *
    77 	 *
    78 	 * @param array $nonces Array of nonces.
    78 	 * @param string[] $nonces Array of nonces.
    79 	 * @return array $nonces Modified array of nonces.
    79 	 * @return string[] $nonces Modified array of nonces.
    80 	 */
    80 	 */
    81 	public function filter_nonces( $nonces ) {
    81 	public function filter_nonces( $nonces ) {
    82 		$nonces['customize-menus'] = wp_create_nonce( 'customize-menus' );
    82 		$nonces['customize-menus'] = wp_create_nonce( 'customize-menus' );
    83 		return $nonces;
    83 		return $nonces;
    84 	}
    84 	}
    93 
    93 
    94 		if ( ! current_user_can( 'edit_theme_options' ) ) {
    94 		if ( ! current_user_can( 'edit_theme_options' ) ) {
    95 			wp_die( -1 );
    95 			wp_die( -1 );
    96 		}
    96 		}
    97 
    97 
    98 		$all_items = array();
    98 		$all_items  = array();
    99 		$item_types = array();
    99 		$item_types = array();
   100 		if ( isset( $_POST['item_types'] ) && is_array( $_POST['item_types'] ) ) {
   100 		if ( isset( $_POST['item_types'] ) && is_array( $_POST['item_types'] ) ) {
   101 			$item_types = wp_unslash( $_POST['item_types'] );
   101 			$item_types = wp_unslash( $_POST['item_types'] );
   102 		} elseif ( isset( $_POST['type'] ) && isset( $_POST['object'] ) ) { // Back compat.
   102 		} elseif ( isset( $_POST['type'] ) && isset( $_POST['object'] ) ) { // Back compat.
   103 			$item_types[] = array(
   103 			$item_types[] = array(
   104 				'type' => wp_unslash( $_POST['type'] ),
   104 				'type'   => wp_unslash( $_POST['type'] ),
   105 				'object' => wp_unslash( $_POST['object'] ),
   105 				'object' => wp_unslash( $_POST['object'] ),
   106 				'page' => empty( $_POST['page'] ) ? 0 : absint( $_POST['page'] ),
   106 				'page'   => empty( $_POST['page'] ) ? 0 : absint( $_POST['page'] ),
   107 			);
   107 			);
   108 		} else {
   108 		} else {
   109 			wp_send_json_error( 'nav_menus_missing_type_or_object_parameter' );
   109 			wp_send_json_error( 'nav_menus_missing_type_or_object_parameter' );
   110 		}
   110 		}
   111 
   111 
   112 		foreach ( $item_types as $item_type ) {
   112 		foreach ( $item_types as $item_type ) {
   113 			if ( empty( $item_type['type'] ) || empty( $item_type['object'] ) ) {
   113 			if ( empty( $item_type['type'] ) || empty( $item_type['object'] ) ) {
   114 				wp_send_json_error( 'nav_menus_missing_type_or_object_parameter' );
   114 				wp_send_json_error( 'nav_menus_missing_type_or_object_parameter' );
   115 			}
   115 			}
   116 			$type = sanitize_key( $item_type['type'] );
   116 			$type   = sanitize_key( $item_type['type'] );
   117 			$object = sanitize_key( $item_type['object'] );
   117 			$object = sanitize_key( $item_type['object'] );
   118 			$page = empty( $item_type['page'] ) ? 0 : absint( $item_type['page'] );
   118 			$page   = empty( $item_type['page'] ) ? 0 : absint( $item_type['page'] );
   119 			$items = $this->load_available_items_query( $type, $object, $page );
   119 			$items  = $this->load_available_items_query( $type, $object, $page );
   120 			if ( is_wp_error( $items ) ) {
   120 			if ( is_wp_error( $items ) ) {
   121 				wp_send_json_error( $items->get_error_code() );
   121 				wp_send_json_error( $items->get_error_code() );
   122 			}
   122 			}
   123 			$all_items[ $item_type['type'] . ':' . $item_type['object'] ] = $items;
   123 			$all_items[ $item_type['type'] . ':' . $item_type['object'] ] = $items;
   124 		}
   124 		}
   177 						$posts[] = $auto_draft_post;
   177 						$posts[] = $auto_draft_post;
   178 					}
   178 					}
   179 				}
   179 				}
   180 			}
   180 			}
   181 
   181 
   182 			$posts = array_merge( $posts, get_posts( array(
   182 			$posts = array_merge(
   183 				'numberposts' => 10,
   183 				$posts,
   184 				'offset'      => 10 * $page,
   184 				get_posts(
   185 				'orderby'     => 'date',
   185 					array(
   186 				'order'       => 'DESC',
   186 						'numberposts' => 10,
   187 				'post_type'   => $object,
   187 						'offset'      => 10 * $page,
   188 			) ) );
   188 						'orderby'     => 'date',
       
   189 						'order'       => 'DESC',
       
   190 						'post_type'   => $object,
       
   191 					)
       
   192 				)
       
   193 			);
   189 
   194 
   190 			foreach ( $posts as $post ) {
   195 			foreach ( $posts as $post ) {
   191 				$post_title = $post->post_title;
   196 				$post_title = $post->post_title;
   192 				if ( '' === $post_title ) {
   197 				if ( '' === $post_title ) {
   193 					/* translators: %d: ID of a post */
   198 					/* translators: %d: ID of a post */
   202 					'object_id'  => intval( $post->ID ),
   207 					'object_id'  => intval( $post->ID ),
   203 					'url'        => get_permalink( intval( $post->ID ) ),
   208 					'url'        => get_permalink( intval( $post->ID ) ),
   204 				);
   209 				);
   205 			}
   210 			}
   206 		} elseif ( 'taxonomy' === $type ) {
   211 		} elseif ( 'taxonomy' === $type ) {
   207 			$terms = get_terms( $object, array(
   212 			$terms = get_terms(
   208 				'child_of'     => 0,
   213 				$object,
   209 				'exclude'      => '',
   214 				array(
   210 				'hide_empty'   => false,
   215 					'child_of'     => 0,
   211 				'hierarchical' => 1,
   216 					'exclude'      => '',
   212 				'include'      => '',
   217 					'hide_empty'   => false,
   213 				'number'       => 10,
   218 					'hierarchical' => 1,
   214 				'offset'       => 10 * $page,
   219 					'include'      => '',
   215 				'order'        => 'DESC',
   220 					'number'       => 10,
   216 				'orderby'      => 'count',
   221 					'offset'       => 10 * $page,
   217 				'pad_counts'   => false,
   222 					'order'        => 'DESC',
   218 			) );
   223 					'orderby'      => 'count',
       
   224 					'pad_counts'   => false,
       
   225 				)
       
   226 			);
   219 			if ( is_wp_error( $terms ) ) {
   227 			if ( is_wp_error( $terms ) ) {
   220 				return $terms;
   228 				return $terms;
   221 			}
   229 			}
   222 
   230 
   223 			foreach ( $terms as $term ) {
   231 			foreach ( $terms as $term ) {
   267 		$p = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 0;
   275 		$p = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 0;
   268 		if ( $p < 1 ) {
   276 		if ( $p < 1 ) {
   269 			$p = 1;
   277 			$p = 1;
   270 		}
   278 		}
   271 
   279 
   272 		$s = sanitize_text_field( wp_unslash( $_POST['search'] ) );
   280 		$s     = sanitize_text_field( wp_unslash( $_POST['search'] ) );
   273 		$items = $this->search_available_items_query( array( 'pagenum' => $p, 's' => $s ) );
   281 		$items = $this->search_available_items_query(
       
   282 			array(
       
   283 				'pagenum' => $p,
       
   284 				's'       => $s,
       
   285 			)
       
   286 		);
   274 
   287 
   275 		if ( empty( $items ) ) {
   288 		if ( empty( $items ) ) {
   276 			wp_send_json_error( array( 'message' => __( 'No results found.' ) ) );
   289 			wp_send_json_error( array( 'message' => __( 'No results found.' ) ) );
   277 		} else {
   290 		} else {
   278 			wp_send_json_success( array( 'items' => $items ) );
   291 			wp_send_json_success( array( 'items' => $items ) );
   291 	 */
   304 	 */
   292 	public function search_available_items_query( $args = array() ) {
   305 	public function search_available_items_query( $args = array() ) {
   293 		$items = array();
   306 		$items = array();
   294 
   307 
   295 		$post_type_objects = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' );
   308 		$post_type_objects = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' );
   296 		$query = array(
   309 		$query             = array(
   297 			'post_type'              => array_keys( $post_type_objects ),
   310 			'post_type'              => array_keys( $post_type_objects ),
   298 			'suppress_filters'       => true,
   311 			'suppress_filters'       => true,
   299 			'update_post_term_cache' => false,
   312 			'update_post_term_cache' => false,
   300 			'update_post_meta_cache' => false,
   313 			'update_post_meta_cache' => false,
   301 			'post_status'            => 'publish',
   314 			'post_status'            => 'publish',
   312 		$posts = array();
   325 		$posts = array();
   313 
   326 
   314 		// Prepend list of posts with nav_menus_created_posts search results on first page.
   327 		// Prepend list of posts with nav_menus_created_posts search results on first page.
   315 		$nav_menus_created_posts_setting = $this->manager->get_setting( 'nav_menus_created_posts' );
   328 		$nav_menus_created_posts_setting = $this->manager->get_setting( 'nav_menus_created_posts' );
   316 		if ( 1 === $args['pagenum'] && $nav_menus_created_posts_setting && count( $nav_menus_created_posts_setting->value() ) > 0 ) {
   329 		if ( 1 === $args['pagenum'] && $nav_menus_created_posts_setting && count( $nav_menus_created_posts_setting->value() ) > 0 ) {
   317 			$stub_post_query = new WP_Query( array_merge(
   330 			$stub_post_query = new WP_Query(
   318 				$query,
   331 				array_merge(
   319 				array(
   332 					$query,
   320 					'post_status' => 'auto-draft',
   333 					array(
   321 					'post__in' => $nav_menus_created_posts_setting->value(),
   334 						'post_status'    => 'auto-draft',
   322 					'posts_per_page' => -1,
   335 						'post__in'       => $nav_menus_created_posts_setting->value(),
       
   336 						'posts_per_page' => -1,
       
   337 					)
   323 				)
   338 				)
   324 			) );
   339 			);
   325 			$posts = array_merge( $posts, $stub_post_query->posts );
   340 			$posts           = array_merge( $posts, $stub_post_query->posts );
   326 		}
   341 		}
   327 
   342 
   328 		// Query posts.
   343 		// Query posts.
   329 		$get_posts = new WP_Query( $query );
   344 		$get_posts = new WP_Query( $query );
   330 		$posts = array_merge( $posts, $get_posts->posts );
   345 		$posts     = array_merge( $posts, $get_posts->posts );
   331 
   346 
   332 		// Create items for posts.
   347 		// Create items for posts.
   333 		foreach ( $posts as $post ) {
   348 		foreach ( $posts as $post ) {
   334 			$post_title = $post->post_title;
   349 			$post_title = $post->post_title;
   335 			if ( '' === $post_title ) {
   350 			if ( '' === $post_title ) {
   347 			);
   362 			);
   348 		}
   363 		}
   349 
   364 
   350 		// Query taxonomy terms.
   365 		// Query taxonomy terms.
   351 		$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'names' );
   366 		$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'names' );
   352 		$terms = get_terms( $taxonomies, array(
   367 		$terms      = get_terms(
   353 			'name__like' => $args['s'],
   368 			$taxonomies,
   354 			'number'     => 20,
   369 			array(
   355 			'offset'     => 20 * ($args['pagenum'] - 1),
   370 				'name__like' => $args['s'],
   356 		) );
   371 				'number'     => 20,
       
   372 				'offset'     => 20 * ( $args['pagenum'] - 1 ),
       
   373 			)
       
   374 		);
   357 
   375 
   358 		// Check if any taxonomies were found.
   376 		// Check if any taxonomies were found.
   359 		if ( ! empty( $terms ) ) {
   377 		if ( ! empty( $terms ) ) {
   360 			foreach ( $terms as $term ) {
   378 			foreach ( $terms as $term ) {
   361 				$items[] = array(
   379 				$items[] = array(
   370 			}
   388 			}
   371 		}
   389 		}
   372 
   390 
   373 		// Add "Home" link if search term matches. Treat as a page, but switch to custom on add.
   391 		// Add "Home" link if search term matches. Treat as a page, but switch to custom on add.
   374 		if ( isset( $args['s'] ) ) {
   392 		if ( isset( $args['s'] ) ) {
   375 			$title = _x( 'Home', 'nav menu home label' );
   393 			$title   = _x( 'Home', 'nav menu home label' );
   376 			$matches = function_exists( 'mb_stripos' ) ? false !== mb_stripos( $title, $args['s'] ) : false !== stripos( $title, $args['s'] );
   394 			$matches = function_exists( 'mb_stripos' ) ? false !== mb_stripos( $title, $args['s'] ) : false !== stripos( $title, $args['s'] );
   377 			if ( $matches ) {
   395 			if ( $matches ) {
   378 				$items[] = array(
   396 				$items[] = array(
   379 					'id'         => 'home',
   397 					'id'         => 'home',
   380 					'title'      => $title,
   398 					'title'      => $title,
   419 			$locations_description = sprintf( _n( 'Your theme can display menus in %s location.', 'Your theme can display menus in %s locations.', $num_locations ), number_format_i18n( $num_locations ) );
   437 			$locations_description = sprintf( _n( 'Your theme can display menus in %s location.', 'Your theme can display menus in %s locations.', $num_locations ), number_format_i18n( $num_locations ) );
   420 		}
   438 		}
   421 
   439 
   422 		// Pass data to JS.
   440 		// Pass data to JS.
   423 		$settings = array(
   441 		$settings = array(
   424 			'allMenus'             => wp_get_nav_menus(),
   442 			'allMenus'                 => wp_get_nav_menus(),
   425 			'itemTypes'            => $this->available_item_types(),
   443 			'itemTypes'                => $this->available_item_types(),
   426 			'l10n'                 => array(
   444 			'l10n'                     => array(
   427 				'untitled'               => _x( '(no label)', 'missing menu item navigation label' ),
   445 				'untitled'               => _x( '(no label)', 'missing menu item navigation label' ),
   428 				'unnamed'                => _x( '(unnamed)', 'Missing menu name.' ),
   446 				'unnamed'                => _x( '(unnamed)', 'Missing menu name.' ),
   429 				'custom_label'           => __( 'Custom Link' ),
   447 				'custom_label'           => __( 'Custom Link' ),
   430 				'page_label'             => get_post_type_object( 'page' )->labels->singular_name,
   448 				'page_label'             => get_post_type_object( 'page' )->labels->singular_name,
   431 				/* translators: %s:      menu location */
   449 				/* translators: %s:      menu location */
   454 				'reorderModeOn'          => __( 'Reorder mode enabled' ),
   472 				'reorderModeOn'          => __( 'Reorder mode enabled' ),
   455 				'reorderModeOff'         => __( 'Reorder mode closed' ),
   473 				'reorderModeOff'         => __( 'Reorder mode closed' ),
   456 				'reorderLabelOn'         => esc_attr__( 'Reorder menu items' ),
   474 				'reorderLabelOn'         => esc_attr__( 'Reorder menu items' ),
   457 				'reorderLabelOff'        => esc_attr__( 'Close reorder mode' ),
   475 				'reorderLabelOff'        => esc_attr__( 'Close reorder mode' ),
   458 			),
   476 			),
   459 			'settingTransport'     => 'postMessage',
   477 			'settingTransport'         => 'postMessage',
   460 			'phpIntMax'            => PHP_INT_MAX,
   478 			'phpIntMax'                => PHP_INT_MAX,
   461 			'defaultSettingValues' => array(
   479 			'defaultSettingValues'     => array(
   462 				'nav_menu'      => $temp_nav_menu_setting->default,
   480 				'nav_menu'      => $temp_nav_menu_setting->default,
   463 				'nav_menu_item' => $temp_nav_menu_item_setting->default,
   481 				'nav_menu_item' => $temp_nav_menu_item_setting->default,
   464 			),
   482 			),
   465 			'locationSlugMappedToName' => get_registered_nav_menus(),
   483 			'locationSlugMappedToName' => get_registered_nav_menus(),
   466 		);
   484 		);
   469 		wp_scripts()->add_data( 'customize-nav-menus', 'data', $data );
   487 		wp_scripts()->add_data( 'customize-nav-menus', 'data', $data );
   470 
   488 
   471 		// This is copied from nav-menus.php, and it has an unfortunate object name of `menus`.
   489 		// This is copied from nav-menus.php, and it has an unfortunate object name of `menus`.
   472 		$nav_menus_l10n = array(
   490 		$nav_menus_l10n = array(
   473 			'oneThemeLocationNoMenus' => null,
   491 			'oneThemeLocationNoMenus' => null,
   474 			'moveUp'       => __( 'Move up one' ),
   492 			'moveUp'                  => __( 'Move up one' ),
   475 			'moveDown'     => __( 'Move down one' ),
   493 			'moveDown'                => __( 'Move down one' ),
   476 			'moveToTop'    => __( 'Move to the top' ),
   494 			'moveToTop'               => __( 'Move to the top' ),
   477 			/* translators: %s: previous item name */
   495 			/* translators: %s: previous item name */
   478 			'moveUnder'    => __( 'Move under %s' ),
   496 			'moveUnder'               => __( 'Move under %s' ),
   479 			/* translators: %s: previous item name */
   497 			/* translators: %s: previous item name */
   480 			'moveOutFrom'  => __( 'Move out from under %s' ),
   498 			'moveOutFrom'             => __( 'Move out from under %s' ),
   481 			/* translators: %s: previous item name */
   499 			/* translators: %s: previous item name */
   482 			'under'        => __( 'Under %s' ),
   500 			'under'                   => __( 'Under %s' ),
   483 			/* translators: %s: previous item name */
   501 			/* translators: %s: previous item name */
   484 			'outFrom'      => __( 'Out from under %s' ),
   502 			'outFrom'                 => __( 'Out from under %s' ),
   485 			/* translators: 1: item name, 2: item position, 3: total number of items */
   503 			/* translators: 1: item name, 2: item position, 3: total number of items */
   486 			'menuFocus'    => __( '%1$s. Menu item %2$d of %3$d.' ),
   504 			'menuFocus'               => __( '%1$s. Menu item %2$d of %3$d.' ),
   487 			/* translators: 1: item name, 2: item position, 3: parent item name */
   505 			/* translators: 1: item name, 2: item position, 3: parent item name */
   488 			'subMenuFocus' => __( '%1$s. Sub item number %2$d under %3$s.' ),
   506 			'subMenuFocus'            => __( '%1$s. Sub item number %2$d under %3$s.' ),
   489 		);
   507 		);
   490 		wp_localize_script( 'nav-menu', 'menus', $nav_menus_l10n );
   508 		wp_localize_script( 'nav-menu', 'menus', $nav_menus_l10n );
   491 	}
   509 	}
   492 
   510 
   493 	/**
   511 	/**
   575 			/* translators: URL to the widgets panel of the customizer */
   593 			/* translators: URL to the widgets panel of the customizer */
   576 			$description .= '<p>' . sprintf( __( 'Menus can be displayed in locations defined by your theme or in <a href="%s">widget areas</a> by adding a &#8220;Navigation Menu&#8221; widget.' ), "javascript:wp.customize.panel( 'widgets' ).focus();" ) . '</p>';
   594 			$description .= '<p>' . sprintf( __( 'Menus can be displayed in locations defined by your theme or in <a href="%s">widget areas</a> by adding a &#8220;Navigation Menu&#8221; widget.' ), "javascript:wp.customize.panel( 'widgets' ).focus();" ) . '</p>';
   577 		} else {
   595 		} else {
   578 			$description .= '<p>' . __( 'Menus can be displayed in locations defined by your theme.' ) . '</p>';
   596 			$description .= '<p>' . __( 'Menus can be displayed in locations defined by your theme.' ) . '</p>';
   579 		}
   597 		}
   580 		$this->manager->add_panel( new WP_Customize_Nav_Menus_Panel( $this->manager, 'nav_menus', array(
   598 
   581 			'title'       => __( 'Menus' ),
   599 		/*
   582 			'description' => $description,
   600 		 * Once multiple theme supports are allowed in WP_Customize_Panel,
   583 			'priority'    => 100,
   601 		 * this panel can be restricted to themes that support menus or widgets.
   584 			// 'theme_supports' => 'menus|widgets', @todo allow multiple theme supports
   602 		 */
   585 		) ) );
   603 		$this->manager->add_panel(
       
   604 			new WP_Customize_Nav_Menus_Panel(
       
   605 				$this->manager,
       
   606 				'nav_menus',
       
   607 				array(
       
   608 					'title'       => __( 'Menus' ),
       
   609 					'description' => $description,
       
   610 					'priority'    => 100,
       
   611 				)
       
   612 			)
       
   613 		);
   586 		$menus = wp_get_nav_menus();
   614 		$menus = wp_get_nav_menus();
   587 
   615 
   588 		// Menu locations.
   616 		// Menu locations.
   589 		$locations     = get_registered_nav_menus();
   617 		$locations     = get_registered_nav_menus();
   590 		$num_locations = count( $locations );
   618 		$num_locations = count( $locations );
   598 		if ( current_theme_supports( 'widgets' ) ) {
   626 		if ( current_theme_supports( 'widgets' ) ) {
   599 			/* translators: URL to the widgets panel of the customizer */
   627 			/* translators: URL to the widgets panel of the customizer */
   600 			$description .= '<p>' . sprintf( __( 'If your theme has widget areas, you can also add menus there. Visit the <a href="%s">Widgets panel</a> and add a &#8220;Navigation Menu widget&#8221; to display a menu in a sidebar or footer.' ), "javascript:wp.customize.panel( 'widgets' ).focus();" ) . '</p>';
   628 			$description .= '<p>' . sprintf( __( 'If your theme has widget areas, you can also add menus there. Visit the <a href="%s">Widgets panel</a> and add a &#8220;Navigation Menu widget&#8221; to display a menu in a sidebar or footer.' ), "javascript:wp.customize.panel( 'widgets' ).focus();" ) . '</p>';
   601 		}
   629 		}
   602 
   630 
   603 		$this->manager->add_section( 'menu_locations', array(
   631 		$this->manager->add_section(
   604 			'title'       => 1 === $num_locations ? _x( 'View Location', 'menu locations' ) : _x( 'View All Locations', 'menu locations' ),
   632 			'menu_locations',
   605 			'panel'       => 'nav_menus',
   633 			array(
   606 			'priority'    => 30,
   634 				'title'       => 1 === $num_locations ? _x( 'View Location', 'menu locations' ) : _x( 'View All Locations', 'menu locations' ),
   607 			'description' => $description,
   635 				'panel'       => 'nav_menus',
   608 		) );
   636 				'priority'    => 30,
       
   637 				'description' => $description,
       
   638 			)
       
   639 		);
   609 
   640 
   610 		$choices = array( '0' => __( '&mdash; Select &mdash;' ) );
   641 		$choices = array( '0' => __( '&mdash; Select &mdash;' ) );
   611 		foreach ( $menus as $menu ) {
   642 		foreach ( $menus as $menu ) {
   612 			$choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '&hellip;' );
   643 			$choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '&hellip;' );
   613 		}
   644 		}
   632 			if ( $setting ) {
   663 			if ( $setting ) {
   633 				$setting->transport = 'postMessage';
   664 				$setting->transport = 'postMessage';
   634 				remove_filter( "customize_sanitize_{$setting_id}", 'absint' );
   665 				remove_filter( "customize_sanitize_{$setting_id}", 'absint' );
   635 				add_filter( "customize_sanitize_{$setting_id}", array( $this, 'intval_base10' ) );
   666 				add_filter( "customize_sanitize_{$setting_id}", array( $this, 'intval_base10' ) );
   636 			} else {
   667 			} else {
   637 				$this->manager->add_setting( $setting_id, array(
   668 				$this->manager->add_setting(
   638 					'sanitize_callback' => array( $this, 'intval_base10' ),
   669 					$setting_id,
   639 					'theme_supports'    => 'menus',
   670 					array(
   640 					'type'              => 'theme_mod',
   671 						'sanitize_callback' => array( $this, 'intval_base10' ),
   641 					'transport'         => 'postMessage',
   672 						'theme_supports'    => 'menus',
   642 					'default'           => 0,
   673 						'type'              => 'theme_mod',
   643 				) );
   674 						'transport'         => 'postMessage',
       
   675 						'default'           => 0,
       
   676 					)
       
   677 				);
   644 			}
   678 			}
   645 
   679 
   646 			// Override the assigned nav menu location if mapped during previewed theme switch.
   680 			// Override the assigned nav menu location if mapped during previewed theme switch.
   647 			if ( empty( $changeset[ $setting_id ] ) && isset( $mapped_nav_menu_locations[ $location ] ) ) {
   681 			if ( empty( $changeset[ $setting_id ] ) && isset( $mapped_nav_menu_locations[ $location ] ) ) {
   648 				$this->manager->set_post_value( $setting_id, $mapped_nav_menu_locations[ $location ] );
   682 				$this->manager->set_post_value( $setting_id, $mapped_nav_menu_locations[ $location ] );
   649 			}
   683 			}
   650 
   684 
   651 			$this->manager->add_control( new WP_Customize_Nav_Menu_Location_Control( $this->manager, $setting_id, array(
   685 			$this->manager->add_control(
   652 				'label'       => $description,
   686 				new WP_Customize_Nav_Menu_Location_Control(
   653 				'location_id' => $location,
   687 					$this->manager,
   654 				'section'     => 'menu_locations',
   688 					$setting_id,
   655 				'choices'     => $choices,
   689 					array(
   656 			) ) );
   690 						'label'       => $description,
       
   691 						'location_id' => $location,
       
   692 						'section'     => 'menu_locations',
       
   693 						'choices'     => $choices,
       
   694 					)
       
   695 				)
       
   696 			);
   657 		}
   697 		}
   658 
   698 
   659 		// Register each menu as a Customizer section, and add each menu item to each menu.
   699 		// Register each menu as a Customizer section, and add each menu item to each menu.
   660 		foreach ( $menus as $menu ) {
   700 		foreach ( $menus as $menu ) {
   661 			$menu_id = $menu->term_id;
   701 			$menu_id = $menu->term_id;
   662 
   702 
   663 			// Create a section for each menu.
   703 			// Create a section for each menu.
   664 			$section_id = 'nav_menu[' . $menu_id . ']';
   704 			$section_id = 'nav_menu[' . $menu_id . ']';
   665 			$this->manager->add_section( new WP_Customize_Nav_Menu_Section( $this->manager, $section_id, array(
   705 			$this->manager->add_section(
   666 				'title'     => html_entity_decode( $menu->name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
   706 				new WP_Customize_Nav_Menu_Section(
   667 				'priority'  => 10,
   707 					$this->manager,
   668 				'panel'     => 'nav_menus',
   708 					$section_id,
   669 			) ) );
   709 					array(
       
   710 						'title'    => html_entity_decode( $menu->name, ENT_QUOTES, get_bloginfo( 'charset' ) ),
       
   711 						'priority' => 10,
       
   712 						'panel'    => 'nav_menus',
       
   713 					)
       
   714 				)
       
   715 			);
   670 
   716 
   671 			$nav_menu_setting_id = 'nav_menu[' . $menu_id . ']';
   717 			$nav_menu_setting_id = 'nav_menu[' . $menu_id . ']';
   672 			$this->manager->add_setting( new WP_Customize_Nav_Menu_Setting( $this->manager, $nav_menu_setting_id, array(
   718 			$this->manager->add_setting(
   673 				'transport' => 'postMessage',
   719 				new WP_Customize_Nav_Menu_Setting(
   674 			) ) );
   720 					$this->manager,
       
   721 					$nav_menu_setting_id,
       
   722 					array(
       
   723 						'transport' => 'postMessage',
       
   724 					)
       
   725 				)
       
   726 			);
   675 
   727 
   676 			// Add the menu contents.
   728 			// Add the menu contents.
   677 			$menu_items = (array) wp_get_nav_menu_items( $menu_id );
   729 			$menu_items = (array) wp_get_nav_menu_items( $menu_id );
   678 
   730 
   679 			foreach ( array_values( $menu_items ) as $i => $item ) {
   731 			foreach ( array_values( $menu_items ) as $i => $item ) {
   685 				if ( empty( $value['post_title'] ) ) {
   737 				if ( empty( $value['post_title'] ) ) {
   686 					$value['title'] = '';
   738 					$value['title'] = '';
   687 				}
   739 				}
   688 
   740 
   689 				$value['nav_menu_term_id'] = $menu_id;
   741 				$value['nav_menu_term_id'] = $menu_id;
   690 				$this->manager->add_setting( new WP_Customize_Nav_Menu_Item_Setting( $this->manager, $menu_item_setting_id, array(
   742 				$this->manager->add_setting(
   691 					'value'     => $value,
   743 					new WP_Customize_Nav_Menu_Item_Setting(
   692 					'transport' => 'postMessage',
   744 						$this->manager,
   693 				) ) );
   745 						$menu_item_setting_id,
       
   746 						array(
       
   747 							'value'     => $value,
       
   748 							'transport' => 'postMessage',
       
   749 						)
       
   750 					)
       
   751 				);
   694 
   752 
   695 				// Create a control for each menu item.
   753 				// Create a control for each menu item.
   696 				$this->manager->add_control( new WP_Customize_Nav_Menu_Item_Control( $this->manager, $menu_item_setting_id, array(
   754 				$this->manager->add_control(
   697 					'label'    => $item->title,
   755 					new WP_Customize_Nav_Menu_Item_Control(
   698 					'section'  => $section_id,
   756 						$this->manager,
   699 					'priority' => 10 + $i,
   757 						$menu_item_setting_id,
   700 				) ) );
   758 						array(
       
   759 							'label'    => $item->title,
       
   760 							'section'  => $section_id,
       
   761 							'priority' => 10 + $i,
       
   762 						)
       
   763 					)
       
   764 				);
   701 			}
   765 			}
   702 
   766 
   703 			// Note: other controls inside of this section get added dynamically in JS via the MenuSection.ready() function.
   767 			// Note: other controls inside of this section get added dynamically in JS via the MenuSection.ready() function.
   704 		}
   768 		}
   705 
   769 
   706 		// Add the add-new-menu section and controls.
   770 		// Add the add-new-menu section and controls.
   707 		$this->manager->add_section( 'add_menu', array(
   771 		$this->manager->add_section(
   708 			'type'     => 'new_menu',
   772 			'add_menu',
   709 			'title'    => __( 'New Menu' ),
   773 			array(
   710 			'panel'    => 'nav_menus',
   774 				'type'     => 'new_menu',
   711 			'priority' => 20,
   775 				'title'    => __( 'New Menu' ),
   712 		) );
   776 				'panel'    => 'nav_menus',
   713 
   777 				'priority' => 20,
   714 		$this->manager->add_setting( new WP_Customize_Filter_Setting( $this->manager, 'nav_menus_created_posts', array(
   778 			)
   715 			'transport' => 'postMessage',
   779 		);
   716 			'type' => 'option', // To prevent theme prefix in changeset.
   780 
   717 			'default' => array(),
   781 		$this->manager->add_setting(
   718 			'sanitize_callback' => array( $this, 'sanitize_nav_menus_created_posts' ),
   782 			new WP_Customize_Filter_Setting(
   719 		) ) );
   783 				$this->manager,
       
   784 				'nav_menus_created_posts',
       
   785 				array(
       
   786 					'transport'         => 'postMessage',
       
   787 					'type'              => 'option', // To prevent theme prefix in changeset.
       
   788 					'default'           => array(),
       
   789 					'sanitize_callback' => array( $this, 'sanitize_nav_menus_created_posts' ),
       
   790 				)
       
   791 			)
       
   792 		);
   720 	}
   793 	}
   721 
   794 
   722 	/**
   795 	/**
   723 	 * Get the base10 intval.
   796 	 * Get the base10 intval.
   724 	 *
   797 	 *
   747 
   820 
   748 		$post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' );
   821 		$post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' );
   749 		if ( $post_types ) {
   822 		if ( $post_types ) {
   750 			foreach ( $post_types as $slug => $post_type ) {
   823 			foreach ( $post_types as $slug => $post_type ) {
   751 				$item_types[] = array(
   824 				$item_types[] = array(
   752 					'title'  => $post_type->labels->name,
   825 					'title'      => $post_type->labels->name,
   753 					'type_label' => $post_type->labels->singular_name,
   826 					'type_label' => $post_type->labels->singular_name,
   754 					'type' => 'post_type',
   827 					'type'       => 'post_type',
   755 					'object' => $post_type->name,
   828 					'object'     => $post_type->name,
   756 				);
   829 				);
   757 			}
   830 			}
   758 		}
   831 		}
   759 
   832 
   760 		$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'objects' );
   833 		$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'objects' );
   762 			foreach ( $taxonomies as $slug => $taxonomy ) {
   835 			foreach ( $taxonomies as $slug => $taxonomy ) {
   763 				if ( 'post_format' === $taxonomy && ! current_theme_supports( 'post-formats' ) ) {
   836 				if ( 'post_format' === $taxonomy && ! current_theme_supports( 'post-formats' ) ) {
   764 					continue;
   837 					continue;
   765 				}
   838 				}
   766 				$item_types[] = array(
   839 				$item_types[] = array(
   767 					'title' => $taxonomy->labels->name,
   840 					'title'      => $taxonomy->labels->name,
   768 					'type_label' => $taxonomy->labels->singular_name,
   841 					'type_label' => $taxonomy->labels->singular_name,
   769 					'type' => 'taxonomy',
   842 					'type'       => 'taxonomy',
   770 					'object' => $taxonomy->name,
   843 					'object'     => $taxonomy->name,
   771 				);
   844 				);
   772 			}
   845 			}
   773 		}
   846 		}
   774 
   847 
   775 		/**
   848 		/**
   791 	 * @since 4.7.0
   864 	 * @since 4.7.0
   792 	 *
   865 	 *
   793 	 * @param array $postarr {
   866 	 * @param array $postarr {
   794 	 *     Post array. Note that post_status is overridden to be `auto-draft`.
   867 	 *     Post array. Note that post_status is overridden to be `auto-draft`.
   795 	 *
   868 	 *
   796 	 *     @var string $post_title   Post title. Required.
   869 	 * @var string $post_title   Post title. Required.
   797 	 *     @var string $post_type    Post type. Required.
   870 	 * @var string $post_type    Post type. Required.
   798 	 *     @var string $post_name    Post name.
   871 	 * @var string $post_name    Post name.
   799 	 *     @var string $post_content Post content.
   872 	 * @var string $post_content Post content.
   800 	 * }
   873 	 * }
   801 	 * @return WP_Post|WP_Error Inserted auto-draft post object or error.
   874 	 * @return WP_Post|WP_Error Inserted auto-draft post object or error.
   802 	 */
   875 	 */
   803 	public function insert_auto_draft_post( $postarr ) {
   876 	public function insert_auto_draft_post( $postarr ) {
   804 		if ( ! isset( $postarr['post_type'] ) ) {
   877 		if ( ! isset( $postarr['post_type'] ) ) {
   823 		}
   896 		}
   824 		if ( ! isset( $postarr['meta_input'] ) ) {
   897 		if ( ! isset( $postarr['meta_input'] ) ) {
   825 			$postarr['meta_input'] = array();
   898 			$postarr['meta_input'] = array();
   826 		}
   899 		}
   827 		$postarr['meta_input']['_customize_draft_post_name'] = $postarr['post_name'];
   900 		$postarr['meta_input']['_customize_draft_post_name'] = $postarr['post_name'];
   828 		$postarr['meta_input']['_customize_changeset_uuid'] = $this->manager->changeset_uuid();
   901 		$postarr['meta_input']['_customize_changeset_uuid']  = $this->manager->changeset_uuid();
   829 		unset( $postarr['post_name'] );
   902 		unset( $postarr['post_name'] );
   830 
   903 
   831 		add_filter( 'wp_insert_post_empty_content', '__return_false', 1000 );
   904 		add_filter( 'wp_insert_post_empty_content', '__return_false', 1000 );
   832 		$r = wp_insert_post( wp_slash( $postarr ), true );
   905 		$r = wp_insert_post( wp_slash( $postarr ), true );
   833 		remove_filter( 'wp_insert_post_empty_content', '__return_false', 1000 );
   906 		remove_filter( 'wp_insert_post_empty_content', '__return_false', 1000 );
   855 
   928 
   856 		if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
   929 		if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) {
   857 			wp_send_json_error( 'missing_params', 400 );
   930 			wp_send_json_error( 'missing_params', 400 );
   858 		}
   931 		}
   859 
   932 
   860 		$params = wp_unslash( $_POST['params'] );
   933 		$params         = wp_unslash( $_POST['params'] );
   861 		$illegal_params = array_diff( array_keys( $params ), array( 'post_type', 'post_title' ) );
   934 		$illegal_params = array_diff( array_keys( $params ), array( 'post_type', 'post_title' ) );
   862 		if ( ! empty( $illegal_params ) ) {
   935 		if ( ! empty( $illegal_params ) ) {
   863 			wp_send_json_error( 'illegal_params', 400 );
   936 			wp_send_json_error( 'illegal_params', 400 );
   864 		}
   937 		}
   865 
   938 
   866 		$params = array_merge(
   939 		$params = array_merge(
   867 			array(
   940 			array(
   868 				'post_type' => '',
   941 				'post_type'  => '',
   869 				'post_title' => '',
   942 				'post_title' => '',
   870 			),
   943 			),
   871 			$params
   944 			$params
   872 		);
   945 		);
   873 
   946 
   896 			} else {
   969 			} else {
   897 				$singular_name = __( 'Post' );
   970 				$singular_name = __( 'Post' );
   898 			}
   971 			}
   899 
   972 
   900 			$data = array(
   973 			$data = array(
   901 				/* translators: %1$s is the post type name and %2$s is the error message. */
   974 				/* translators: 1: post type name, 2: error message */
   902 				'message' => sprintf( __( '%1$s could not be created: %2$s' ), $singular_name, $error->get_error_message() ),
   975 				'message' => sprintf( __( '%1$s could not be created: %2$s' ), $singular_name, $error->get_error_message() ),
   903 			);
   976 			);
   904 			wp_send_json_error( $data );
   977 			wp_send_json_error( $data );
   905 		} else {
   978 		} else {
   906 			$post = $r;
   979 			$post = $r;
   928 						<span class="item-type" aria-hidden="true">{{ data.type_label }}</span>
  1001 						<span class="item-type" aria-hidden="true">{{ data.type_label }}</span>
   929 						<span class="item-title" aria-hidden="true">
  1002 						<span class="item-title" aria-hidden="true">
   930 							<span class="menu-item-title<# if ( ! data.title ) { #> no-title<# } #>">{{ data.title || wp.customize.Menus.data.l10n.untitled }}</span>
  1003 							<span class="menu-item-title<# if ( ! data.title ) { #> no-title<# } #>">{{ data.title || wp.customize.Menus.data.l10n.untitled }}</span>
   931 						</span>
  1004 						</span>
   932 						<button type="button" class="button-link item-add">
  1005 						<button type="button" class="button-link item-add">
   933 							<span class="screen-reader-text"><?php
  1006 							<span class="screen-reader-text">
   934 								/* translators: 1: Title of a menu item, 2: Type of a menu item */
  1007 							<?php
       
  1008 								/* translators: 1: title of a menu item, 2: type of a menu item */
   935 								printf( __( 'Add to menu: %1$s (%2$s)' ), '{{ data.title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.type_label }}' );
  1009 								printf( __( 'Add to menu: %1$s (%2$s)' ), '{{ data.title || wp.customize.Menus.data.l10n.untitled }}', '{{ data.type_label }}' );
   936 							?></span>
  1010 							?>
       
  1011 							</span>
   937 						</button>
  1012 						</button>
   938 					</div>
  1013 					</div>
   939 				</div>
  1014 				</div>
   940 			</li>
  1015 			</li>
   941 		</script>
  1016 		</script>
   983 				<button type="button" class="button customize-add-menu-button">
  1058 				<button type="button" class="button customize-add-menu-button">
   984 					<?php _e( 'Create New Menu' ); ?>
  1059 					<?php _e( 'Create New Menu' ); ?>
   985 				</button>
  1060 				</button>
   986 			</h3>
  1061 			</h3>
   987 		</script>
  1062 		</script>
   988 	<?php
  1063 		<?php
   989 	}
  1064 	}
   990 
  1065 
   991 	/**
  1066 	/**
   992 	 * Print the html template used to render the add-menu-item frame.
  1067 	 * Print the html template used to render the add-menu-item frame.
   993 	 *
  1068 	 *
  1011 				</h3>
  1086 				</h3>
  1012 			</div>
  1087 			</div>
  1013 			<div id="available-menu-items-search" class="accordion-section cannot-expand">
  1088 			<div id="available-menu-items-search" class="accordion-section cannot-expand">
  1014 				<div class="accordion-section-title">
  1089 				<div class="accordion-section-title">
  1015 					<label class="screen-reader-text" for="menu-items-search"><?php _e( 'Search Menu Items' ); ?></label>
  1090 					<label class="screen-reader-text" for="menu-items-search"><?php _e( 'Search Menu Items' ); ?></label>
  1016 					<input type="text" id="menu-items-search" placeholder="<?php esc_attr_e( 'Search menu items&hellip;' ) ?>" aria-describedby="menu-items-search-desc" />
  1091 					<input type="text" id="menu-items-search" placeholder="<?php esc_attr_e( 'Search menu items&hellip;' ); ?>" aria-describedby="menu-items-search-desc" />
  1017 					<p class="screen-reader-text" id="menu-items-search-desc"><?php _e( 'The search results will be updated as you type.' ); ?></p>
  1092 					<p class="screen-reader-text" id="menu-items-search-desc"><?php _e( 'The search results will be updated as you type.' ); ?></p>
  1018 					<span class="spinner"></span>
  1093 					<span class="spinner"></span>
  1019 				</div>
  1094 				</div>
  1020 				<div class="search-icon" aria-hidden="true"></div>
  1095 				<div class="search-icon" aria-hidden="true"></div>
  1021 				<button type="button" class="clear-results"><span class="screen-reader-text"><?php _e( 'Clear Results' ); ?></span></button>
  1096 				<button type="button" class="clear-results"><span class="screen-reader-text"><?php _e( 'Clear Results' ); ?></span></button>
  1022 				<ul class="accordion-section-content available-menu-items-list" data-type="search"></ul>
  1097 				<ul class="accordion-section-content available-menu-items-list" data-type="search"></ul>
  1023 			</div>
  1098 			</div>
  1024 			<?php
  1099 			<?php
  1025 
  1100 
  1026 			// Ensure the page post type comes first in the list.
  1101 			// Ensure the page post type comes first in the list.
  1027 			$item_types = $this->available_item_types();
  1102 			$item_types     = $this->available_item_types();
  1028 			$page_item_type = null;
  1103 			$page_item_type = null;
  1029 			foreach ( $item_types as $i => $item_type ) {
  1104 			foreach ( $item_types as $i => $item_type ) {
  1030 				if ( isset( $item_type['object'] ) && 'page' === $item_type['object'] ) {
  1105 				if ( isset( $item_type['object'] ) && 'page' === $item_type['object'] ) {
  1031 					$page_item_type = $item_type;
  1106 					$page_item_type = $item_type;
  1032 					unset( $item_types[ $i ] );
  1107 					unset( $item_types[ $i ] );
  1041 			foreach ( $item_types as $item_type ) {
  1116 			foreach ( $item_types as $item_type ) {
  1042 				$this->print_post_type_container( $item_type );
  1117 				$this->print_post_type_container( $item_type );
  1043 			}
  1118 			}
  1044 			?>
  1119 			?>
  1045 		</div><!-- #available-menu-items -->
  1120 		</div><!-- #available-menu-items -->
  1046 	<?php
  1121 		<?php
  1047 	}
  1122 	}
  1048 
  1123 
  1049 	/**
  1124 	/**
  1050 	 * Print the markup for new menu items.
  1125 	 * Print the markup for new menu items.
  1051 	 *
  1126 	 *
  1063 			<h4 class="accordion-section-title" role="presentation">
  1138 			<h4 class="accordion-section-title" role="presentation">
  1064 				<?php echo esc_html( $available_item_type['title'] ); ?>
  1139 				<?php echo esc_html( $available_item_type['title'] ); ?>
  1065 				<span class="spinner"></span>
  1140 				<span class="spinner"></span>
  1066 				<span class="no-items"><?php _e( 'No items' ); ?></span>
  1141 				<span class="no-items"><?php _e( 'No items' ); ?></span>
  1067 				<button type="button" class="button-link" aria-expanded="false">
  1142 				<button type="button" class="button-link" aria-expanded="false">
  1068 					<span class="screen-reader-text"><?php
  1143 					<span class="screen-reader-text">
       
  1144 					<?php
  1069 						/* translators: %s: Title of a section with menu items */
  1145 						/* translators: %s: Title of a section with menu items */
  1070 						printf( __( 'Toggle section: %s' ), esc_html( $available_item_type['title'] ) ); ?></span>
  1146 						printf( __( 'Toggle section: %s' ), esc_html( $available_item_type['title'] ) );
       
  1147 					?>
       
  1148 						</span>
  1071 					<span class="toggle-indicator" aria-hidden="true"></span>
  1149 					<span class="toggle-indicator" aria-hidden="true"></span>
  1072 				</button>
  1150 				</button>
  1073 			</h4>
  1151 			</h4>
  1074 			<div class="accordion-section-content">
  1152 			<div class="accordion-section-content">
  1075 				<?php if ( 'post_type' === $available_item_type['type'] ) : ?>
  1153 				<?php if ( 'post_type' === $available_item_type['type'] ) : ?>
  1245 				if ( 'auto-draft' !== $current_status && 'draft' !== $current_status ) {
  1323 				if ( 'auto-draft' !== $current_status && 'draft' !== $current_status ) {
  1246 					continue;
  1324 					continue;
  1247 				}
  1325 				}
  1248 
  1326 
  1249 				$target_status = 'attachment' === get_post_type( $post_id ) ? 'inherit' : 'publish';
  1327 				$target_status = 'attachment' === get_post_type( $post_id ) ? 'inherit' : 'publish';
  1250 				$args = array(
  1328 				$args          = array(
  1251 					'ID' => $post_id,
  1329 					'ID'          => $post_id,
  1252 					'post_status' => $target_status,
  1330 					'post_status' => $target_status,
  1253 				);
  1331 				);
  1254 				$post_name = get_post_meta( $post_id, '_customize_draft_post_name', true );
  1332 				$post_name     = get_post_meta( $post_id, '_customize_draft_post_name', true );
  1255 				if ( $post_name ) {
  1333 				if ( $post_name ) {
  1256 					$args['post_name'] = $post_name;
  1334 					$args['post_name'] = $post_name;
  1257 				}
  1335 				}
  1258 
  1336 
  1259 				// Note that wp_publish_post() cannot be used because unique slugs need to be assigned.
  1337 				// Note that wp_publish_post() cannot be used because unique slugs need to be assigned.
  1267 	/**
  1345 	/**
  1268 	 * Keep track of the arguments that are being passed to wp_nav_menu().
  1346 	 * Keep track of the arguments that are being passed to wp_nav_menu().
  1269 	 *
  1347 	 *
  1270 	 * @since 4.3.0
  1348 	 * @since 4.3.0
  1271 	 * @see wp_nav_menu()
  1349 	 * @see wp_nav_menu()
  1272 	 * @see WP_Customize_Widgets_Partial_Refresh::filter_dynamic_sidebar_params()
  1350 	 * @see WP_Customize_Widgets::filter_dynamic_sidebar_params()
  1273 	 *
  1351 	 *
  1274 	 * @param array $args An array containing wp_nav_menu() arguments.
  1352 	 * @param array $args An array containing wp_nav_menu() arguments.
  1275 	 * @return array Arguments.
  1353 	 * @return array Arguments.
  1276 	 */
  1354 	 */
  1277 	public function filter_wp_nav_menu_args( $args ) {
  1355 	public function filter_wp_nav_menu_args( $args ) {
  1308 		$exported_args = $args;
  1386 		$exported_args = $args;
  1309 
  1387 
  1310 		// Empty out args which may not be JSON-serializable.
  1388 		// Empty out args which may not be JSON-serializable.
  1311 		if ( ! $can_partial_refresh ) {
  1389 		if ( ! $can_partial_refresh ) {
  1312 			$exported_args['fallback_cb'] = '';
  1390 			$exported_args['fallback_cb'] = '';
  1313 			$exported_args['walker'] = '';
  1391 			$exported_args['walker']      = '';
  1314 		}
  1392 		}
  1315 
  1393 
  1316 		/*
  1394 		/*
  1317 		 * Replace object menu arg with a term_id menu arg, as this exports better
  1395 		 * Replace object menu arg with a term_id menu arg, as this exports better
  1318 		 * to JS and is easier to compare hashes.
  1396 		 * to JS and is easier to compare hashes.
  1322 		}
  1400 		}
  1323 
  1401 
  1324 		ksort( $exported_args );
  1402 		ksort( $exported_args );
  1325 		$exported_args['args_hmac'] = $this->hash_nav_menu_args( $exported_args );
  1403 		$exported_args['args_hmac'] = $this->hash_nav_menu_args( $exported_args );
  1326 
  1404 
  1327 		$args['customize_preview_nav_menus_args'] = $exported_args;
  1405 		$args['customize_preview_nav_menus_args']                            = $exported_args;
  1328 		$this->preview_nav_menu_instance_args[ $exported_args['args_hmac'] ] = $exported_args;
  1406 		$this->preview_nav_menu_instance_args[ $exported_args['args_hmac'] ] = $exported_args;
  1329 		return $args;
  1407 		return $args;
  1330 	}
  1408 	}
  1331 
  1409 
  1332 	/**
  1410 	/**
  1342 	 * @param object $args             An object containing wp_nav_menu() arguments.
  1420 	 * @param object $args             An object containing wp_nav_menu() arguments.
  1343 	 * @return string Nav menu HTML with selective refresh attributes added if partial can be refreshed.
  1421 	 * @return string Nav menu HTML with selective refresh attributes added if partial can be refreshed.
  1344 	 */
  1422 	 */
  1345 	public function filter_wp_nav_menu( $nav_menu_content, $args ) {
  1423 	public function filter_wp_nav_menu( $nav_menu_content, $args ) {
  1346 		if ( isset( $args->customize_preview_nav_menus_args['can_partial_refresh'] ) && $args->customize_preview_nav_menus_args['can_partial_refresh'] ) {
  1424 		if ( isset( $args->customize_preview_nav_menus_args['can_partial_refresh'] ) && $args->customize_preview_nav_menus_args['can_partial_refresh'] ) {
  1347 			$attributes = sprintf( ' data-customize-partial-id="%s"', esc_attr( 'nav_menu_instance[' . $args->customize_preview_nav_menus_args['args_hmac'] . ']' ) );
  1425 			$attributes       = sprintf( ' data-customize-partial-id="%s"', esc_attr( 'nav_menu_instance[' . $args->customize_preview_nav_menus_args['args_hmac'] . ']' ) );
  1348 			$attributes .= ' data-customize-partial-type="nav_menu_instance"';
  1426 			$attributes      .= ' data-customize-partial-type="nav_menu_instance"';
  1349 			$attributes .= sprintf( ' data-customize-partial-placement-context="%s"', esc_attr( wp_json_encode( $args->customize_preview_nav_menus_args ) ) );
  1427 			$attributes      .= sprintf( ' data-customize-partial-placement-context="%s"', esc_attr( wp_json_encode( $args->customize_preview_nav_menus_args ) ) );
  1350 			$nav_menu_content = preg_replace( '#^(<\w+)#', '$1 ' . str_replace( '\\', '\\\\', $attributes ), $nav_menu_content, 1 );
  1428 			$nav_menu_content = preg_replace( '#^(<\w+)#', '$1 ' . str_replace( '\\', '\\\\', $attributes ), $nav_menu_content, 1 );
  1351 		}
  1429 		}
  1352 		return $nav_menu_content;
  1430 		return $nav_menu_content;
  1353 	}
  1431 	}
  1354 
  1432