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 ); |
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 } |
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 ) { |
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( |
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 “Navigation Menu” 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 “Navigation Menu” 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 “Navigation Menu widget” 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 “Navigation Menu widget” 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' => __( '— Select —' ) ); |
641 $choices = array( '0' => __( '— Select —' ) ); |
611 foreach ( $menus as $menu ) { |
642 foreach ( $menus as $menu ) { |
612 $choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '…' ); |
643 $choices[ $menu->term_id ] = wp_html_excerpt( $menu->name, 40, '…' ); |
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' ); |
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 |
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> |
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…' ) ?>" aria-describedby="menu-items-search-desc" /> |
1091 <input type="text" id="menu-items-search" placeholder="<?php esc_attr_e( 'Search menu items…' ); ?>" 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 ] ); |
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'] ) : ?> |
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 |