Ticket #34923: 34923.7.diff
File 34923.7.diff, 26.6 KB (added by , 9 years ago) |
---|
-
src/wp-admin/css/customize-controls.css
diff --git src/wp-admin/css/customize-controls.css src/wp-admin/css/customize-controls.css index d2eef49..af62e5e 100644
body.cheatin p { 1219 1219 } 1220 1220 1221 1221 .add-new-widget:before, 1222 .add-new-menu-item:before { 1222 .add-new-menu-item:before, 1223 #available-menu-items .new-content-item .add-content:before { 1223 1224 content: "\f132"; 1224 1225 display: inline-block; 1225 1226 position: relative; -
src/wp-admin/css/customize-nav-menus.css
diff --git src/wp-admin/css/customize-nav-menus.css src/wp-admin/css/customize-nav-menus.css index afe0cbc..f234fef 100644
61 61 text-align: right; 62 62 } 63 63 64 .customize-control-nav_menu_item.has-notifications .menu-item-handle { 65 border-left: 4px solid #00a0d2; 66 } 67 64 68 .wp-customizer .menu-item-settings { 65 69 max-width: 100%; 66 70 overflow: hidden; … … 497 501 color: #23282d; 498 502 } 499 503 500 #available-menu-items .a ccordion-section-content {504 #available-menu-items .available-menu-items-list { 501 505 overflow-y: auto; 502 506 max-height: 200px; /* This gets set in JS to fit the screen size, and based on # of sections. */ 503 507 background: transparent; … … 534 538 } 535 539 536 540 #available-menu-items .accordion-section-content { 537 padding: 1px 15px 15px 15px;538 margin: 0;539 541 max-height: 290px; 542 margin: 0; 543 padding: 0; 544 position: relative; 545 background: transparent; 546 } 547 548 #available-menu-items .accordion-section-content .available-menu-items-list { 549 margin: 0 0 45px 0; 550 padding: 1px 15px 15px 15px; 551 } 552 553 #available-menu-items .accordion-section-content .available-menu-items-list:only-child { /* Types that do not support new items for the current user */ 554 margin-bottom: 0; 555 } 556 557 #new-custom-menu-item .accordion-section-content { 558 padding: 0 15px 15px 15px; 559 } 560 561 #available-menu-items .accordion-section-content .new-content-item { 562 width: calc(100% - 30px); 563 padding: 8px 15px; 564 position: absolute; 565 bottom: 0; 566 z-index: 10; 567 background: #eee; 568 display: -webkit-box; 569 display: -moz-box; 570 display: -ms-flexbox; 571 display: -webkit-flex; 572 display: flex; 573 } 574 575 #available-menu-items .new-content-item .create-item-input { 576 -webkit-flex-grow: 10; 577 -moz-box-flex: 10; 578 -ms-flex: 10; 579 flex-grow: 10; 580 margin-left: 5px; 581 } 582 #available-menu-items .new-content-item .add-content { 583 padding-left: 6px; 584 -webkit-flex-grow: 1; 585 -moz-box-flex: 1; 586 -ms-flex: 1; 587 flex-grow: 1; 540 588 } 541 589 542 590 #available-menu-items .menu-item-tpl { … … 546 594 #custom-menu-item-name.invalid, 547 595 #custom-menu-item-url.invalid, 548 596 .menu-name-field.invalid, 549 .menu-name-field.invalid:focus { 597 .menu-name-field.invalid:focus, 598 #available-menu-items .new-content-item .create-item-input.invalid, 599 #available-menu-items .new-content-item .create-item-input.invalid:focus { 550 600 border: 1px solid #f00; 551 601 } 552 602 -
src/wp-admin/js/customize-nav-menus.js
diff --git src/wp-admin/js/customize-nav-menus.js src/wp-admin/js/customize-nav-menus.js index 25495fe..67e29fc 100644
80 80 }); 81 81 api.Menus.availableMenuItems = new api.Menus.AvailableItemCollection( api.Menus.data.availableMenuItems ); 82 82 83 api.Menus.insertedAutoDrafts = []; 84 85 /** 86 * Insert a new `auto-draft` post. 87 * 88 * @param {object} params - Parameters for the draft post to create. 89 * @param {string} params.post_type - Post type to add. 90 * @param {number} params.title - Post title to use. 91 * @return {jQuery.promise} Promise resolved with the added post. 92 */ 93 api.Menus.insertAutoDraftPost = function insertAutoDraftPost( params ) { 94 var request, deferred = $.Deferred(); 95 96 request = wp.ajax.post( 'customize-nav-menus-insert-auto-draft', { 97 'customize-menus-nonce': api.settings.nonce['customize-menus'], 98 'wp_customize': 'on', 99 'params': params 100 } ); 101 102 request.done( function( response ) { 103 if ( response.postId ) { 104 deferred.resolve( response ); 105 api.Menus.insertedAutoDrafts.push( response.postId ); 106 api( 'nav_menus_created_posts' ).set( _.clone( api.Menus.insertedAutoDrafts ) ); 107 } 108 } ); 109 110 request.fail( function( response ) { 111 var error = response || ''; 112 113 if ( 'undefined' !== typeof response.message ) { 114 error = response.message; 115 } 116 117 console.error( error ); 118 deferred.rejectWith( error ); 119 } ); 120 121 return deferred.promise(); 122 }; 123 83 124 /** 84 125 * wp.customize.Menus.AvailableMenuItemsPanelView 85 126 * … … 100 141 'click .menu-item-tpl': '_submit', 101 142 'click #custom-menu-item-submit': '_submitLink', 102 143 'keypress #custom-menu-item-name': '_submitLink', 144 'click .new-content-item .add-content': '_submitNew', 145 'keypress .create-item-input': '_submitNew', 103 146 'keydown': 'keyboardAccessible' 104 147 }, 105 148 … … 115 158 pages: {}, 116 159 sectionContent: '', 117 160 loading: false, 161 addingNew: false, 118 162 119 163 initialize: function() { 120 164 var self = this; … … 124 168 } 125 169 126 170 this.$search = $( '#menu-items-search' ); 127 this.sectionContent = this.$el.find( '.a ccordion-section-content' );171 this.sectionContent = this.$el.find( '.available-menu-items-list' ); 128 172 129 173 this.debounceSearch = _.debounce( self.search, 500 ); 130 174 … … 160 204 161 205 // Load more items. 162 206 this.sectionContent.scroll( function() { 163 var totalHeight = self.$el.find( '.accordion-section.open .a ccordion-section-content' ).prop( 'scrollHeight' ),207 var totalHeight = self.$el.find( '.accordion-section.open .available-menu-items-list' ).prop( 'scrollHeight' ), 164 208 visibleHeight = self.$el.find( '.accordion-section.open' ).height(); 165 209 166 210 if ( ! self.loading && $( this ).scrollTop() > 3 / 4 * totalHeight - visibleHeight ) { … … 337 381 } 338 382 items = new api.Menus.AvailableItemCollection( items ); // @todo Why is this collection created and then thrown away? 339 383 self.collection.add( items.models ); 340 typeInner = availableMenuItemContainer.find( '.a ccordion-section-content' );384 typeInner = availableMenuItemContainer.find( '.available-menu-items-list' ); 341 385 items.each(function( menuItem ) { 342 386 typeInner.append( itemTemplate( menuItem.attributes ) ); 343 387 }); … … 356 400 357 401 // Adjust the height of each section of items to fit the screen. 358 402 itemSectionHeight: function() { 359 var sections, totalHeight, accordionHeight, diff;403 var sections, lists, totalHeight, accordionHeight, diff; 360 404 totalHeight = window.innerHeight; 361 405 sections = this.$el.find( '.accordion-section:not( #available-menu-items-search ) .accordion-section-content' ); 362 accordionHeight = 46 * ( 2 + sections.length ) - 13; // Magic numbers. 406 lists = this.$el.find( '.accordion-section:not( #available-menu-items-search ) .available-menu-items-list:not(":only-child")' ); 407 accordionHeight = 46 * ( 1 + sections.length ) + 14; // Magic numbers. 363 408 diff = totalHeight - accordionHeight; 364 409 if ( 120 < diff && 290 > diff ) { 365 410 sections.css( 'max-height', diff ); 411 lists.css( 'max-height', ( diff - 60 ) ); 366 412 } 367 413 }, 368 414 … … 456 502 itemName.val( '' ); 457 503 }, 458 504 505 // Submit handler for keypress (enter) on field and click on button. 506 _submitNew: function( event ) { 507 var container; 508 509 // Only proceed with keypress if it is Enter. 510 if ( 'keypress' === event.type && 13 !== event.which ) { 511 return; 512 } 513 514 if ( this.addingNew ) { 515 return; 516 } 517 518 container = $( event.target ).closest( '.accordion-section' ); 519 520 this.submitNew( container ); 521 }, 522 523 // Creates a new object and adds an associated menu item to the menu. 524 submitNew: function( container ) { 525 var panel = this, 526 itemName = container.find( '.create-item-input' ), 527 title = itemName.val(), 528 dataContainer = container.find( '.available-menu-items-list' ), 529 itemType = dataContainer.data( 'type' ), 530 itemObject = dataContainer.data( 'object' ), 531 itemTypeLabel = dataContainer.data( 'type_label' ), 532 promise; 533 534 if ( ! this.currentMenuControl ) { 535 return; 536 } 537 538 // Only posts are supported currently. 539 if ( 'post_type' !== itemType ) { 540 return; 541 } 542 543 if ( '' === $.trim( itemName.val() ) ) { 544 itemName.addClass( 'invalid' ); 545 itemName.focus(); 546 return; 547 } else { 548 itemName.removeClass( 'invalid' ); 549 container.find( '.accordion-section-title' ).addClass( 'loading' ); 550 } 551 552 panel.addingNew = true; 553 itemName.attr( 'disabled', 'disabled' ); 554 promise = api.Menus.insertAutoDraftPost( { 555 post_title: title, 556 post_type: itemObject, 557 post_status: 'publish' 558 } ); 559 promise.done( function( data ) { 560 var menuItem = { 561 'title': itemName.val(), 562 'type': itemType, 563 'type_label': itemTypeLabel, 564 'object': itemObject, 565 'object_id': data.postId, 566 'url': data.url 567 }, availableItems, $content, itemTemplate; 568 569 // Add new item to menu. 570 panel.currentMenuControl.addItemToMenu( menuItem ); 571 572 // Add the new item to the list of available items. 573 menuItem.id = 'post-' + data.postId; // `id` is used for available menu item Backbone models. 574 availableItems = new api.Menus.AvailableItemCollection( [ menuItem ] ); 575 api.Menus.availableMenuItemsPanel.collection.add( availableItems.models ); 576 $content = container.find( '.available-menu-items-list' ), 577 itemTemplate = wp.template( 'available-menu-item' ); 578 $content.prepend( itemTemplate( menuItem ) ); 579 $content.scrollTop(); 580 581 // Reset the create content form. 582 itemName.val( '' ).removeAttr( 'disabled' ); 583 panel.addingNew = false; 584 container.find( '.accordion-section-title' ).removeClass( 'loading' ); 585 } ); 586 }, 587 459 588 // Opens the panel. 460 589 open: function( menuControl ) { 461 590 this.currentMenuControl = menuControl; … … 2545 2674 if ( data.nav_menu_updates || data.nav_menu_item_updates ) { 2546 2675 api.Menus.applySavedData( data ); 2547 2676 } 2677 2678 // Reset list of inserted auto draft post IDs. 2679 api.Menus.insertedAutoDrafts = []; 2548 2680 } ); 2549 2681 2550 2682 // Open and focus menu control. -
src/wp-includes/class-wp-customize-manager.php
diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php index 5ee3b6d..6c96995 100644
final class WP_Customize_Manager { 1535 1535 <script type="text/html" id="tmpl-customize-control-notifications"> 1536 1536 <ul> 1537 1537 <# _.each( data.notifications, function( notification ) { #> 1538 <li class="notice notice-{{ notification.type || 'info' }} {{ data.altNotice ? 'notice-alt' : '' }}" data-code="{{ notification.code }}" data-type="{{ notification.type }}">{{ notification.message || notification.code}}</li>1538 <li class="notice notice-{{ notification.type || 'info' }} {{ data.altNotice ? 'notice-alt' : '' }}" data-code="{{ notification.code }}" data-type="{{ notification.type }}">{{{ notification.message || notification.code }}}</li> 1539 1539 <# } ); #> 1540 1540 </ul> 1541 1541 </script> -
src/wp-includes/class-wp-customize-nav-menus.php
diff --git src/wp-includes/class-wp-customize-nav-menus.php src/wp-includes/class-wp-customize-nav-menus.php index f9832a6..08eda6c 100644
final class WP_Customize_Nav_Menus { 56 56 add_filter( 'customize_refresh_nonces', array( $this, 'filter_nonces' ) ); 57 57 add_action( 'wp_ajax_load-available-menu-items-customizer', array( $this, 'ajax_load_available_items' ) ); 58 58 add_action( 'wp_ajax_search-available-menu-items-customizer', array( $this, 'ajax_search_available_items' ) ); 59 add_action( 'wp_ajax_customize-nav-menus-insert-auto-draft', array( $this, 'ajax_insert_auto_draft_post' ) ); 59 60 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 60 61 // Needs to run after core Navigation section is set up.62 61 add_action( 'customize_register', array( $this, 'customize_register' ), 11 ); 63 64 62 add_filter( 'customize_dynamic_setting_args', array( $this, 'filter_dynamic_setting_args' ), 10, 2 ); 65 63 add_filter( 'customize_dynamic_setting_class', array( $this, 'filter_dynamic_setting_class' ), 10, 3 ); 66 64 add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_templates' ) ); 67 65 add_action( 'customize_controls_print_footer_scripts', array( $this, 'available_items_template' ) ); 68 66 add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ) ); 67 add_action( 'customize_preview_init', array( $this, 'make_auto_draft_status_previewable' ) ); 68 add_action( 'customize_save_nav_menus_created_posts', array( $this, 'save_nav_menus_created_posts' ) ); 69 69 70 70 // Selective Refresh partials. 71 71 add_filter( 'customize_dynamic_partial_args', array( $this, 'customize_dynamic_partial_args' ), 10, 2 ); … … final class WP_Customize_Nav_Menus { 626 626 'section' => 'add_menu', 627 627 'settings' => array(), 628 628 ) ) ); 629 630 $this->manager->add_setting( new WP_Customize_Filter_Setting( $this->manager, 'nav_menus_created_posts', array( 631 'transport' => 'postMessage', 632 'default' => array(), 633 'sanitize_callback' => array( $this, 'sanitize_nav_menus_created_posts' ), 634 ) ) ); 629 635 } 630 636 631 637 /** … … final class WP_Customize_Nav_Menus { 648 654 * Return an array of all the available item types. 649 655 * 650 656 * @since 4.3.0 657 * @since 4.7.0 Each array item now includes a `$type_label` in in addition to `$title`, `$type`, and `$object`. 651 658 * @access public 652 659 * 653 660 * @return array The available menu item types. … … final class WP_Customize_Nav_Menus { 660 667 foreach ( $post_types as $slug => $post_type ) { 661 668 $item_types[] = array( 662 669 'title' => $post_type->labels->name, 663 'type' => 'post_type', 670 'type_label' => $post_type->labels->singular_name, 671 'type' => 'post_type', 664 672 'object' => $post_type->name, 665 673 ); 666 674 } … … final class WP_Customize_Nav_Menus { 673 681 continue; 674 682 } 675 683 $item_types[] = array( 676 'title' => $taxonomy->labels->name, 677 'type' => 'taxonomy', 684 'title' => $taxonomy->labels->name, 685 'type_label' => $taxonomy->labels->singular_name, 686 'type' => 'taxonomy', 678 687 'object' => $taxonomy->name, 679 688 ); 680 689 } … … final class WP_Customize_Nav_Menus { 684 693 * Filters the available menu item types. 685 694 * 686 695 * @since 4.3.0 696 * @since 4.7.0 Each array item now includes a `$type_label` in in addition to `$title`, `$type`, and `$object`. 687 697 * 688 698 * @param array $item_types Custom menu item types. 689 699 */ … … final class WP_Customize_Nav_Menus { 693 703 } 694 704 695 705 /** 706 * Add a new `auto-draft` post. 707 * 708 * @access public 709 * @since 4.7.0 710 * 711 * @param string $post_type The post type. 712 * @param string $title The post title. 713 * @return WP_Post|WP_Error 714 */ 715 public function insert_auto_draft_post( $post_type, $title ) { 716 717 $post_type_obj = get_post_type_object( $post_type ); 718 if ( ! $post_type_obj ) { 719 return new WP_Error( 'unknown_post_type', __( 'Unknown post type' ) ); 720 } 721 722 add_filter( 'wp_insert_post_empty_content', '__return_false' ); 723 $args = array( 724 'post_status' => 'auto-draft', 725 'post_type' => $post_type, 726 'post_title' => $title, 727 'post_name' => sanitize_title( $title ), // Auto-drafts are allowed to have empty post_names, so we need to explicitly set it. 728 ); 729 $r = wp_insert_post( wp_slash( $args ), true ); 730 remove_filter( 'wp_insert_post_empty_content', '__return_false' ); 731 732 if ( is_wp_error( $r ) ) { 733 return $r; 734 } else { 735 return get_post( $r ); 736 } 737 } 738 739 /** 740 * Ajax handler for adding a new auto-draft post. 741 * 742 * @access public 743 * @since 4.7.0 744 */ 745 public function ajax_insert_auto_draft_post() { 746 if ( ! check_ajax_referer( 'customize-menus', 'customize-menus-nonce' ) ) { 747 status_header( 400 ); 748 wp_send_json_error( 'bad_nonce' ); 749 } 750 751 if ( ! current_user_can( 'customize' ) ) { 752 status_header( 403 ); 753 wp_send_json_error( 'customize_not_allowed' ); 754 } 755 756 if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) { 757 status_header( 400 ); 758 wp_send_json_error( 'missing_params' ); 759 } 760 761 $params = wp_unslash( $_POST['params'] ); 762 763 if ( empty( $params['post_type'] ) ) { 764 status_header( 400 ); 765 wp_send_json_error( 'missing_post_type_param' ); 766 } 767 768 $post_type_object = get_post_type_object( $params['post_type'] ); 769 if ( ! $post_type_object || ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) { 770 status_header( 403 ); 771 wp_send_json_error( 'insufficient_post_permissions' ); 772 } 773 774 if ( ! $params['title'] ) { 775 $params['title'] = ''; 776 } 777 778 $r = $this->insert_auto_draft_post( $post_type_object->name, $params['post_title'] ); 779 if ( is_wp_error( $r ) ) { 780 $error = $r; 781 if ( ! empty( $post_type_object->labels->singular_name ) ) { 782 $singular_name = $post_type_object->labels->singular_name; 783 } else { 784 $singular_name = __( 'Post' ); 785 } 786 787 $data = array( 788 /* translators: %1$s is the post type name and %2$s is the error message. */ 789 'message' => sprintf( __( '%1$s could not be created: %2$s' ), $singular_name, $error->get_error_message() ), 790 ); 791 wp_send_json_error( $data ); 792 } else { 793 $post = $r; 794 $data = array( 795 'postId' => $post->ID, 796 'url' => get_permalink( $post->ID ), 797 ); 798 wp_send_json_success( $data ); 799 } 800 } 801 802 /** 696 803 * Print the JavaScript templates used to render Menu Customizer components. 697 804 * 698 805 * Templates are imported into the JS use wp.template. … … final class WP_Customize_Nav_Menus { 768 875 <span class="spinner"></span> 769 876 </div> 770 877 <button type="button" class="clear-results"><span class="screen-reader-text"><?php _e( 'Clear Results' ); ?></span></button> 771 <ul class="accordion-section-content " data-type="search"></ul>878 <ul class="accordion-section-content available-menu-items-list" data-type="search"></ul> 772 879 </div> 773 880 <div id="new-custom-menu-item" class="accordion-section"> 774 881 <h4 class="accordion-section-title" role="presentation"> … … final class WP_Customize_Nav_Menus { 797 904 </div> 798 905 </div> 799 906 <?php 800 // Containers for per-post-type item browsing; items added with JS. 907 /** 908 * Filter the content types that do not allow new items to be created from nav menus. 909 * 910 * Types are formatted as 'post_type'|'taxonomy' _ post_type_name; for example, 'taxonomy_post_format'. 911 * Taxonomies are not yet supported by this UI but will be in the future. Post types are only available 912 * here if `show_in_nav_menus` is true. 913 * 914 * @since 4.7.0 915 * 916 * @param array $types Array of disallowed types. 917 */ 918 $disallowed_new_content_types = apply_filters( 'customize_nav_menus_disallow_new_content_types', array( 'taxonomy_post_format' ) ); 919 920 // Containers for per-post-type item browsing; items are added with JS. 801 921 foreach ( $this->available_item_types() as $available_item_type ) { 802 922 $id = sprintf( 'available-menu-items-%s-%s', $available_item_type['type'], $available_item_type['object'] ); 803 923 ?> … … final class WP_Customize_Nav_Menus { 813 933 <span class="toggle-indicator" aria-hidden="true"></span> 814 934 </button> 815 935 </h4> 816 <ul class="accordion-section-content" data-type="<?php echo esc_attr( $available_item_type['type'] ); ?>" data-object="<?php echo esc_attr( $available_item_type['object'] ); ?>"></ul> 936 <div class="accordion-section-content"> 937 <?php if ( 'post_type' === $available_item_type['type'] && ! in_array( $available_item_type['type'] . '_' . $available_item_type['object'], $disallowed_new_content_types, true ) ) : ?> 938 <?php $post_type_obj = get_post_type_object( $available_item_type['object'] ); ?> 939 <?php if ( current_user_can( $post_type_obj->cap->create_posts ) && current_user_can( $post_type_obj->cap->publish_posts ) ) : ?> 940 <div class="new-content-item"> 941 <input type="text" class="create-item-input" placeholder="<?php 942 /* translators: %s: Singular title of post type or taxonomy */ 943 printf( __( 'Create New %s' ), $post_type_obj->labels->singular_name ); ?>"> 944 <button type="button" class="button add-content"><?php _e( 'Add' ); ?></button> 945 </div> 946 <?php endif; ?> 947 <?php endif; ?> 948 <ul class="available-menu-items-list" data-type="<?php echo esc_attr( $available_item_type['type'] ); ?>" data-object="<?php echo esc_attr( $available_item_type['object'] ); ?>" data-type_label="<?php echo esc_attr( isset( $available_item_type['type_label'] ) ? $available_item_type['type_label'] : $available_item_type['type'] ); ?>"></ul> 949 </div> 817 950 </div> 818 951 <?php 819 952 } … … final class WP_Customize_Nav_Menus { 881 1014 } 882 1015 883 1016 /** 1017 * Make the auto-draft status protected so that it can be queried. 1018 * 1019 * @since 4.7.0 1020 * @access public 1021 */ 1022 public function make_auto_draft_status_previewable() { 1023 global $wp_post_statuses; 1024 $wp_post_statuses['auto-draft']->protected = true; 1025 } 1026 1027 /** 1028 * Sanitize post IDs for auto-draft posts created for nav menu items to be published. 1029 * 1030 * @since 4.7.0 1031 * @access public 1032 * 1033 * @param array $value Post IDs. 1034 * @returns array Post IDs. 1035 */ 1036 public function sanitize_nav_menus_created_posts( $value ) { 1037 $post_ids = array(); 1038 foreach ( wp_parse_id_list( $value ) as $post_id ) { 1039 if ( empty( $post_id ) ) { 1040 continue; 1041 } 1042 $post = get_post( $post_id ); 1043 if ( 'auto-draft' !== $post->post_status ) { 1044 continue; 1045 } 1046 $post_type_obj = get_post_type_object( $post->post_type ); 1047 if ( ! $post_type_obj ) { 1048 continue; 1049 } 1050 if ( ! current_user_can( $post_type_obj->cap->publish_posts ) ) { 1051 continue; 1052 } 1053 $post_ids[] = $post->ID; 1054 } 1055 return $post_ids; 1056 } 1057 1058 /** 1059 * Publish the auto-draft posts that were created for nav menu items. 1060 * 1061 * The post IDs will have been sanitized by already by 1062 * `WP_Customize_Nav_Menu_Items::sanitize_nav_menus_created_posts()` to 1063 * remove any post IDs for which the user cannot publish or for which the 1064 * post is not an auto-draft. 1065 * 1066 * @since 4.7.0 1067 * @access public 1068 * 1069 * @param WP_Customize_Setting $setting Customizer setting object. 1070 */ 1071 public function save_nav_menus_created_posts( $setting ) { 1072 $post_ids = $setting->post_value(); 1073 if ( ! empty( $post_ids ) ) { 1074 foreach ( $post_ids as $post_id ) { 1075 wp_publish_post( $post_id ); 1076 } 1077 } 1078 } 1079 1080 /** 884 1081 * Keep track of the arguments that are being passed to wp_nav_menu(). 885 1082 * 886 1083 * @since 4.3.0 -
src/wp-includes/class-wp-customize-setting.php
diff --git src/wp-includes/class-wp-customize-setting.php src/wp-includes/class-wp-customize-setting.php index a0d04d3..a16b100 100644
class WP_Customize_Setting { 498 498 /** 499 499 * Fetch and sanitize the $_POST value for the setting. 500 500 * 501 * During a save request prior to save, post_value() provides the new value while value() does not. 502 * 501 503 * @since 3.4.0 502 504 * 503 505 * @param mixed $default A default value which is used as a fallback. Default is null. -
tests/phpunit/tests/customize/nav-menus.php
diff --git tests/phpunit/tests/customize/nav-menus.php tests/phpunit/tests/customize/nav-menus.php index f5d56b6..57257a7 100644
class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 45 45 */ 46 46 function filter_item_types( $items ) { 47 47 $items[] = array( 48 'title' 49 'type' 48 'title' => 'Custom', 49 'type' => 'custom_type', 50 50 'object' => 'custom_object', 51 'type_label' => 'Custom Type', 51 52 ); 52 53 53 54 return $items; … … class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 479 480 $menus = new WP_Customize_Nav_Menus( $this->wp_customize ); 480 481 481 482 $expected = array( 482 array( 'title' => 'Posts', 'type' => 'post_type', 'object' => 'post' ),483 array( 'title' => 'Pages', 'type' => 'post_type', 'object' => 'page' ),484 array( 'title' => 'Categories', 'type' => 'taxonomy', 'object' => 'category' ),485 array( 'title' => 'Tags', 'type' => 'taxonomy', 'object' => 'post_tag' ),483 array( 'title' => 'Posts', 'type' => 'post_type', 'object' => 'post', 'type_label' => __( 'Post' ) ), 484 array( 'title' => 'Pages', 'type' => 'post_type', 'object' => 'page', 'type_label' => __( 'Page' ) ), 485 array( 'title' => 'Categories', 'type' => 'taxonomy', 'object' => 'category', 'type_label' => __( 'Category' ) ), 486 array( 'title' => 'Tags', 'type' => 'taxonomy', 'object' => 'post_tag', 'type_label' => __( 'Tag' ) ), 486 487 ); 487 488 488 489 if ( current_theme_supports( 'post-formats' ) ) { 489 $expected[] = array( 'title' => 'Format', 'type' => 'taxonomy', 'object' => 'post_format' );490 $expected[] = array( 'title' => 'Format', 'type' => 'taxonomy', 'object' => 'post_format', 'type_label' => __( 'Format' ) ); 490 491 } 491 492 492 493 $this->assertEquals( $expected, $menus->available_item_types() ); 493 494 494 495 register_taxonomy( 'wptests_tax', array( 'post' ), array( 'labels' => array( 'name' => 'Foo' ) ) ); 495 $expected[] = array( 'title' => 'Foo', 'type' => 'taxonomy', 'object' => 'wptests_tax' );496 $expected[] = array( 'title' => 'Foo', 'type' => 'taxonomy', 'object' => 'wptests_tax', 'type_label' => 'Foo' ); 496 497 497 498 $this->assertEquals( $expected, $menus->available_item_types() ); 498 499 499 $expected[] = array( 'title' => 'Custom', 'type' => 'custom_type', 'object' => 'custom_object' );500 $expected[] = array( 'title' => 'Custom', 'type' => 'custom_type', 'object' => 'custom_object', 'type_label' => 'Custom Type' ); 500 501 501 502 add_filter( 'customize_nav_menu_available_item_types', array( $this, 'filter_item_types' ) ); 502 503 $this->assertEquals( $expected, $menus->available_item_types() ); … … class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 553 554 $this->assertRegExp( '#<h4 class="accordion-section-title".*>\s*' . esc_html( $type->labels->name ) . '#', $template ); 554 555 $this->assertContains( 'data-type="post_type"', $template ); 555 556 $this->assertContains( 'data-object="' . esc_attr( $type->name ) . '"', $template ); 557 $this->assertContains( 'data-type_label="' . esc_attr( $type->labels->singular_name ) . '"', $template ); 556 558 } 557 559 } 558 560 … … class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 563 565 $this->assertRegExp( '#<h4 class="accordion-section-title".*>\s*' . esc_html( $tax->labels->name ) . '#', $template ); 564 566 $this->assertContains( 'data-type="taxonomy"', $template ); 565 567 $this->assertContains( 'data-object="' . esc_attr( $tax->name ) . '"', $template ); 568 $this->assertContains( 'data-type_label="' . esc_attr( $tax->labels->singular_name ) . '"', $template ); 566 569 } 567 570 } 568 571 … … class Test_WP_Customize_Nav_Menus extends WP_UnitTestCase { 570 573 $this->assertRegExp( '#<h4 class="accordion-section-title".*>\s*Custom#', $template ); 571 574 $this->assertContains( 'data-type="custom_type"', $template ); 572 575 $this->assertContains( 'data-object="custom_object"', $template ); 576 $this->assertContains( 'data-type_label="Custom Type"', $template ); 573 577 } 574 578 575 579 /**