Changeset 38436
- Timestamp:
- 08/29/2016 10:58:32 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/css/customize-controls.css
r38152 r38436 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; -
trunk/src/wp-admin/css/customize-nav-menus.css
r38207 r38436 60 60 float: right; 61 61 text-align: right; 62 } 63 64 .customize-control-nav_menu_item.has-notifications .menu-item-handle { 65 border-left: 4px solid #00a0d2; 62 66 } 63 67 … … 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. */ … … 535 539 536 540 #available-menu-items .accordion-section-content { 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; 537 550 padding: 1px 15px 15px 15px; 538 margin: 0; 539 max-height: 290px; 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-box-flex: 10; 577 -webkit-flex-grow: 10; 578 -moz-box-flex: 10; 579 -ms-flex-positive: 10; 580 -ms-flex: 10; 581 flex-grow: 10; 582 margin-left: 5px; 583 padding: 4.5px; 584 } 585 #available-menu-items .new-content-item .add-content { 586 padding-left: 6px; 587 -webkit-box-flex: 10; 588 -webkit-flex-grow: 10; 589 -moz-box-flex: 10; 590 -ms-flex-positive: 10; 591 -ms-flex: 10; 592 flex-grow: 1; 540 593 } 541 594 … … 547 600 #custom-menu-item-url.invalid, 548 601 .menu-name-field.invalid, 549 .menu-name-field.invalid:focus { 602 .menu-name-field.invalid:focus, 603 #available-menu-items .new-content-item .create-item-input.invalid, 604 #available-menu-items .new-content-item .create-item-input.invalid:focus { 550 605 border: 1px solid #f00; 551 606 } -
trunk/src/wp-admin/js/customize-nav-menus.js
r38301 r38436 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 {string} params.post_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.post_id ) { 104 deferred.resolve( response ); 105 api.Menus.insertedAutoDrafts.push( response.post_id ); 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 … … 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 }, … … 116 159 sectionContent: '', 117 160 loading: false, 161 addingNew: false, 118 162 119 163 initialize: function() { … … 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 ); … … 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 … … 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 ) ); … … 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 }, … … 455 501 itemUrl.val( 'http://' ); 456 502 itemName.val( '' ); 503 }, 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 } ); 558 promise.done( function( data ) { 559 var availableItem, $content, itemTemplate; 560 availableItem = new api.Menus.AvailableItemModel( { 561 'id': 'post-' + data.post_id, // Used for available menu item Backbone models. 562 'title': itemName.val(), 563 'type': itemType, 564 'type_label': itemTypeLabel, 565 'object': itemObject, 566 'object_id': data.post_id, 567 'url': data.url 568 } ); 569 570 // Add new item to menu. 571 panel.currentMenuControl.addItemToMenu( availableItem.attributes ); 572 573 // Add the new item to the list of available items. 574 api.Menus.availableMenuItemsPanel.collection.add( availableItem ); 575 $content = container.find( '.available-menu-items-list' ); 576 itemTemplate = wp.template( 'available-menu-item' ); 577 $content.prepend( itemTemplate( availableItem.attributes ) ); 578 $content.scrollTop(); 579 580 // Reset the create content form. 581 itemName.val( '' ).removeAttr( 'disabled' ); 582 panel.addingNew = false; 583 container.find( '.accordion-section-title' ).removeClass( 'loading' ); 584 } ); 457 585 }, 458 586 … … 2546 2674 api.Menus.applySavedData( data ); 2547 2675 } 2676 2677 // Reset list of inserted auto draft post IDs. 2678 api.Menus.insertedAutoDrafts = []; 2548 2679 } ); 2549 2680 -
trunk/src/wp-includes/class-wp-customize-nav-menus.php
r37900 r38436 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 ); … … 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. … … 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 … … 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 * … … 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 ); … … 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 ); … … 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. … … 691 701 692 702 return $item_types; 703 } 704 705 /** 706 * Add a new `auto-draft` post. 707 * 708 * @access public 709 * @since 4.7.0 710 * 711 * @param array $postarr { 712 * Abbreviated post array. 713 * 714 * @var string $post_title Post title. 715 * @var string $post_type Post type. 716 * } 717 * @return WP_Post|WP_Error Inserted auto-draft post object or error. 718 */ 719 public function insert_auto_draft_post( $postarr ) { 720 if ( ! isset( $postarr['post_type'] ) || ! post_type_exists( $postarr['post_type'] ) ) { 721 return new WP_Error( 'unknown_post_type', __( 'Unknown post type' ) ); 722 } 723 if ( ! isset( $postarr['post_title'] ) ) { 724 $postarr['post_title'] = ''; 725 } 726 727 add_filter( 'wp_insert_post_empty_content', '__return_false', 1000 ); 728 $args = array( 729 'post_status' => 'auto-draft', 730 'post_type' => $postarr['post_type'], 731 'post_title' => $postarr['post_title'], 732 'post_name' => sanitize_title( $postarr['post_title'] ), // Auto-drafts are allowed to have empty post_names, so we need to explicitly set it. 733 ); 734 $r = wp_insert_post( wp_slash( $args ), true ); 735 remove_filter( 'wp_insert_post_empty_content', '__return_false', 1000 ); 736 737 if ( is_wp_error( $r ) ) { 738 return $r; 739 } else { 740 return get_post( $r ); 741 } 742 } 743 744 /** 745 * Ajax handler for adding a new auto-draft post. 746 * 747 * @access public 748 * @since 4.7.0 749 */ 750 public function ajax_insert_auto_draft_post() { 751 if ( ! check_ajax_referer( 'customize-menus', 'customize-menus-nonce', false ) ) { 752 status_header( 400 ); 753 wp_send_json_error( 'bad_nonce' ); 754 } 755 756 if ( ! current_user_can( 'customize' ) ) { 757 status_header( 403 ); 758 wp_send_json_error( 'customize_not_allowed' ); 759 } 760 761 if ( empty( $_POST['params'] ) || ! is_array( $_POST['params'] ) ) { 762 status_header( 400 ); 763 wp_send_json_error( 'missing_params' ); 764 } 765 766 $params = wp_array_slice_assoc( 767 array_merge( 768 array( 769 'post_type' => '', 770 'post_title' => '', 771 ), 772 wp_unslash( $_POST['params'] ) 773 ), 774 array( 'post_type', 'post_title' ) 775 ); 776 777 if ( empty( $params['post_type'] ) || ! post_type_exists( $params['post_type'] ) ) { 778 status_header( 400 ); 779 wp_send_json_error( 'missing_post_type_param' ); 780 } 781 782 $post_type_object = get_post_type_object( $params['post_type'] ); 783 if ( ! current_user_can( $post_type_object->cap->create_posts ) || ! current_user_can( $post_type_object->cap->publish_posts ) ) { 784 status_header( 403 ); 785 wp_send_json_error( 'insufficient_post_permissions' ); 786 } 787 788 $params['post_title'] = trim( $params['post_title'] ); 789 if ( '' === $params['post_title'] ) { 790 status_header( 400 ); 791 wp_send_json_error( 'missing_post_title' ); 792 } 793 794 $r = $this->insert_auto_draft_post( $params ); 795 if ( is_wp_error( $r ) ) { 796 $error = $r; 797 if ( ! empty( $post_type_object->labels->singular_name ) ) { 798 $singular_name = $post_type_object->labels->singular_name; 799 } else { 800 $singular_name = __( 'Post' ); 801 } 802 803 $data = array( 804 /* translators: %1$s is the post type name and %2$s is the error message. */ 805 'message' => sprintf( __( '%1$s could not be created: %2$s' ), $singular_name, $error->get_error_message() ), 806 ); 807 wp_send_json_error( $data ); 808 } else { 809 $post = $r; 810 $data = array( 811 'post_id' => $post->ID, 812 'url' => get_permalink( $post->ID ), 813 ); 814 wp_send_json_success( $data ); 815 } 693 816 } 694 817 … … 769 892 </div> 770 893 <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>894 <ul class="accordion-section-content available-menu-items-list" data-type="search"></ul> 772 895 </div> 773 896 <div id="new-custom-menu-item" class="accordion-section"> … … 798 921 </div> 799 922 <?php 800 // Containers for per-post-type item browsing; items added with JS. 923 924 // Containers for per-post-type item browsing; items are added with JS. 801 925 foreach ( $this->available_item_types() as $available_item_type ) { 802 926 $id = sprintf( 'available-menu-items-%s-%s', $available_item_type['type'], $available_item_type['object'] ); … … 814 938 </button> 815 939 </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> 940 <div class="accordion-section-content"> 941 <?php if ( 'post_type' === $available_item_type['type'] ) : ?> 942 <?php $post_type_obj = get_post_type_object( $available_item_type['object'] ); ?> 943 <?php if ( current_user_can( $post_type_obj->cap->create_posts ) && current_user_can( $post_type_obj->cap->publish_posts ) ) : ?> 944 <div class="new-content-item"> 945 <input type="text" class="create-item-input" placeholder="<?php 946 /* translators: %s: Singular title of post type or taxonomy */ 947 printf( __( 'Create New %s' ), $post_type_obj->labels->singular_name ); ?>"> 948 <button type="button" class="button add-content"><?php _e( 'Add' ); ?></button> 949 </div> 950 <?php endif; ?> 951 <?php endif; ?> 952 <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> 953 </div> 817 954 </div> 818 955 <?php … … 879 1016 add_filter( 'wp_footer', array( $this, 'export_preview_data' ), 1 ); 880 1017 add_filter( 'customize_render_partials_response', array( $this, 'export_partial_rendered_nav_menu_instances' ) ); 1018 } 1019 1020 /** 1021 * Make the auto-draft status protected so that it can be queried. 1022 * 1023 * @since 4.7.0 1024 * @access public 1025 */ 1026 public function make_auto_draft_status_previewable() { 1027 global $wp_post_statuses; 1028 $wp_post_statuses['auto-draft']->protected = true; 1029 } 1030 1031 /** 1032 * Sanitize post IDs for auto-draft posts created for nav menu items to be published. 1033 * 1034 * @since 4.7.0 1035 * @access public 1036 * 1037 * @param array $value Post IDs. 1038 * @returns array Post IDs. 1039 */ 1040 public function sanitize_nav_menus_created_posts( $value ) { 1041 $post_ids = array(); 1042 foreach ( wp_parse_id_list( $value ) as $post_id ) { 1043 if ( empty( $post_id ) ) { 1044 continue; 1045 } 1046 $post = get_post( $post_id ); 1047 if ( 'auto-draft' !== $post->post_status ) { 1048 continue; 1049 } 1050 $post_type_obj = get_post_type_object( $post->post_type ); 1051 if ( ! $post_type_obj ) { 1052 continue; 1053 } 1054 if ( ! current_user_can( $post_type_obj->cap->publish_posts ) || ! current_user_can( $post_type_obj->cap->edit_post, $post_id ) ) { 1055 continue; 1056 } 1057 $post_ids[] = $post->ID; 1058 } 1059 return $post_ids; 1060 } 1061 1062 /** 1063 * Publish the auto-draft posts that were created for nav menu items. 1064 * 1065 * The post IDs will have been sanitized by already by 1066 * `WP_Customize_Nav_Menu_Items::sanitize_nav_menus_created_posts()` to 1067 * remove any post IDs for which the user cannot publish or for which the 1068 * post is not an auto-draft. 1069 * 1070 * @since 4.7.0 1071 * @access public 1072 * 1073 * @param WP_Customize_Setting $setting Customizer setting object. 1074 */ 1075 public function save_nav_menus_created_posts( $setting ) { 1076 $post_ids = $setting->post_value(); 1077 if ( ! empty( $post_ids ) ) { 1078 foreach ( $post_ids as $post_id ) { 1079 wp_publish_post( $post_id ); 1080 } 1081 } 881 1082 } 882 1083 -
trunk/src/wp-includes/class-wp-customize-setting.php
r38411 r38436 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 * -
trunk/tests/phpunit/tests/ajax/CustomizeMenus.php
r35244 r38436 527 527 ); 528 528 } 529 530 /** 531 * Testing successful ajax_insert_auto_draft_post() call. 532 * 533 * @covers WP_Customize_Nav_Menus::ajax_insert_auto_draft_post() 534 */ 535 function test_ajax_insert_auto_draft_post_success() { 536 $_POST = wp_slash( array( 537 'customize-menus-nonce' => wp_create_nonce( 'customize-menus' ), 538 'params' => array( 539 'post_type' => 'post', 540 'post_title' => 'Hello World', 541 ), 542 ) ); 543 $this->_last_response = ''; 544 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 545 $response = json_decode( $this->_last_response, true ); 546 547 $this->assertTrue( $response['success'] ); 548 $this->assertArrayHasKey( 'post_id', $response['data'] ); 549 $this->assertArrayHasKey( 'url', $response['data'] ); 550 } 551 552 /** 553 * Testing unsuccessful ajax_insert_auto_draft_post() call. 554 * 555 * @covers WP_Customize_Nav_Menus::ajax_insert_auto_draft_post() 556 */ 557 function test_ajax_insert_auto_draft_failures() { 558 // No nonce. 559 $_POST = array(); 560 $this->_last_response = ''; 561 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 562 $response = json_decode( $this->_last_response, true ); 563 $this->assertFalse( $response['success'] ); 564 $this->assertEquals( 'bad_nonce', $response['data'] ); 565 566 // Bad nonce. 567 $_POST = wp_slash( array( 568 'customize-menus-nonce' => 'bad', 569 ) ); 570 $this->_last_response = ''; 571 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 572 $response = json_decode( $this->_last_response, true ); 573 $this->assertFalse( $response['success'] ); 574 $this->assertEquals( 'bad_nonce', $response['data'] ); 575 576 // Bad nonce. 577 wp_set_current_user( $this->factory()->user->create( array( 'role' => 'subscriber' ) ) ); 578 $_POST = wp_slash( array( 579 'customize-menus-nonce' => wp_create_nonce( 'customize-menus' ), 580 ) ); 581 $this->_last_response = ''; 582 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 583 $response = json_decode( $this->_last_response, true ); 584 $this->assertFalse( $response['success'] ); 585 $this->assertEquals( 'customize_not_allowed', $response['data'] ); 586 587 // Missing params. 588 wp_set_current_user( $this->factory()->user->create( array( 'role' => 'administrator' ) ) ); 589 $_POST = wp_slash( array( 590 'customize-menus-nonce' => wp_create_nonce( 'customize-menus' ), 591 ) ); 592 $this->_last_response = ''; 593 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 594 $response = json_decode( $this->_last_response, true ); 595 $this->assertFalse( $response['success'] ); 596 $this->assertEquals( 'missing_params', $response['data'] ); 597 598 // insufficient_post_permissions. 599 register_post_type( 'privilege', array( 'capability_type' => 'privilege' ) ); 600 $_POST = wp_slash( array( 601 'customize-menus-nonce' => wp_create_nonce( 'customize-menus' ), 602 'params' => array( 603 'post_type' => 'privilege', 604 ), 605 ) ); 606 $this->_last_response = ''; 607 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 608 $response = json_decode( $this->_last_response, true ); 609 $this->assertFalse( $response['success'] ); 610 $this->assertEquals( 'insufficient_post_permissions', $response['data'] ); 611 612 // insufficient_post_permissions. 613 $_POST = wp_slash( array( 614 'customize-menus-nonce' => wp_create_nonce( 'customize-menus' ), 615 'params' => array( 616 'post_type' => 'non-existent', 617 ), 618 ) ); 619 $this->_last_response = ''; 620 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 621 $response = json_decode( $this->_last_response, true ); 622 $this->assertFalse( $response['success'] ); 623 $this->assertEquals( 'missing_post_type_param', $response['data'] ); 624 625 // missing_post_title. 626 $_POST = wp_slash( array( 627 'customize-menus-nonce' => wp_create_nonce( 'customize-menus' ), 628 'params' => array( 629 'post_type' => 'post', 630 'post_title' => ' ', 631 ), 632 ) ); 633 $this->_last_response = ''; 634 $this->make_ajax_call( 'customize-nav-menus-insert-auto-draft' ); 635 $response = json_decode( $this->_last_response, true ); 636 $this->assertFalse( $response['success'] ); 637 $this->assertEquals( 'missing_post_title', $response['data'] ); 638 } 529 639 } -
trunk/tests/phpunit/tests/customize/nav-menus.php
r36889 r38436 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 … … 85 86 $menus = new WP_Customize_Nav_Menus( $this->wp_customize ); 86 87 $this->assertInstanceOf( 'WP_Customize_Manager', $menus->manager ); 88 89 $this->assertEquals( 10, add_filter( 'customize_refresh_nonces', array( $menus, 'filter_nonces' ) ) ); 90 $this->assertEquals( 10, add_action( 'wp_ajax_load-available-menu-items-customizer', array( $menus, 'ajax_load_available_items' ) ) ); 91 $this->assertEquals( 10, add_action( 'wp_ajax_search-available-menu-items-customizer', array( $menus, 'ajax_search_available_items' ) ) ); 92 $this->assertEquals( 10, add_action( 'wp_ajax_customize-nav-menus-insert-auto-draft', array( $menus, 'ajax_insert_auto_draft_post' ) ) ); 93 $this->assertEquals( 10, add_action( 'customize_controls_enqueue_scripts', array( $menus, 'enqueue_scripts' ) ) ); 94 $this->assertEquals( 11, add_action( 'customize_register', array( $menus, 'customize_register' ) ) ); 95 $this->assertEquals( 10, add_filter( 'customize_dynamic_setting_args', array( $menus, 'filter_dynamic_setting_args' ) ) ); 96 $this->assertEquals( 10, add_filter( 'customize_dynamic_setting_class', array( $menus, 'filter_dynamic_setting_class' ) ) ); 97 $this->assertEquals( 10, add_action( 'customize_controls_print_footer_scripts', array( $menus, 'print_templates' ) ) ); 98 $this->assertEquals( 10, add_action( 'customize_controls_print_footer_scripts', array( $menus, 'available_items_template' ) ) ); 99 $this->assertEquals( 10, add_action( 'customize_preview_init', array( $menus, 'customize_preview_init' ) ) ); 100 $this->assertEquals( 10, add_action( 'customize_preview_init', array( $menus, 'make_auto_draft_status_previewable' ) ) ); 101 $this->assertEquals( 10, add_action( 'customize_save_nav_menus_created_posts', array( $menus, 'save_nav_menus_created_posts' ) ) ); 102 $this->assertEquals( 10, add_filter( 'customize_dynamic_partial_args', array( $menus, 'customize_dynamic_partial_args' ) ) ); 87 103 } 88 104 … … 445 461 'menu-item-status' => 'publish', 446 462 ) ); 447 $setting = new WP_Customize_Nav_Menu_Item_Setting( $this->wp_customize, "nav_menu_item[$item_id]");448 do_action( 'customize_register', $this->wp_customize);463 do_action( 'customize_register', $this->wp_customize ); 464 $this->assertInstanceOf( 'WP_Customize_Nav_Menu_Item_Setting', $this->wp_customize->get_setting( "nav_menu_item[$item_id]" ) ); 449 465 $this->assertEquals( 'Primary', $this->wp_customize->get_section( "nav_menu[$menu_id]" )->title ); 450 466 $this->assertEquals( 'Hello World', $this->wp_customize->get_control( "nav_menu_item[$item_id]" )->label ); 467 468 $nav_menus_created_posts_setting = $this->wp_customize->get_setting( 'nav_menus_created_posts' ); 469 $this->assertInstanceOf( 'WP_Customize_Filter_Setting', $nav_menus_created_posts_setting ); 470 $this->assertEquals( 'postMessage', $nav_menus_created_posts_setting->transport ); 471 $this->assertEquals( array(), $nav_menus_created_posts_setting->default ); 472 $this->assertEquals( array( $this->wp_customize->nav_menus, 'sanitize_nav_menus_created_posts' ), $nav_menus_created_posts_setting->sanitize_callback ); 451 473 } 452 474 … … 480 502 481 503 $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' ),504 array( 'title' => 'Posts', 'type' => 'post_type', 'object' => 'post', 'type_label' => __( 'Post' ) ), 505 array( 'title' => 'Pages', 'type' => 'post_type', 'object' => 'page', 'type_label' => __( 'Page' ) ), 506 array( 'title' => 'Categories', 'type' => 'taxonomy', 'object' => 'category', 'type_label' => __( 'Category' ) ), 507 array( 'title' => 'Tags', 'type' => 'taxonomy', 'object' => 'post_tag', 'type_label' => __( 'Tag' ) ), 486 508 ); 487 509 488 510 if ( current_theme_supports( 'post-formats' ) ) { 489 $expected[] = array( 'title' => 'Format', 'type' => 'taxonomy', 'object' => 'post_format' );511 $expected[] = array( 'title' => 'Format', 'type' => 'taxonomy', 'object' => 'post_format', 'type_label' => __( 'Format' ) ); 490 512 } 491 513 … … 493 515 494 516 register_taxonomy( 'wptests_tax', array( 'post' ), array( 'labels' => array( 'name' => 'Foo' ) ) ); 495 $expected[] = array( 'title' => 'Foo', 'type' => 'taxonomy', 'object' => 'wptests_tax' );517 $expected[] = array( 'title' => 'Foo', 'type' => 'taxonomy', 'object' => 'wptests_tax', 'type_label' => 'Foo' ); 496 518 497 519 $this->assertEquals( $expected, $menus->available_item_types() ); 498 520 499 $expected[] = array( 'title' => 'Custom', 'type' => 'custom_type', 'object' => 'custom_object' );521 $expected[] = array( 'title' => 'Custom', 'type' => 'custom_type', 'object' => 'custom_object', 'type_label' => 'Custom Type' ); 500 522 501 523 add_filter( 'customize_nav_menu_available_item_types', array( $this, 'filter_item_types' ) ); … … 503 525 remove_filter( 'customize_nav_menu_available_item_types', array( $this, 'filter_item_types' ) ); 504 526 527 } 528 529 /** 530 * Test insert_auto_draft_post method. 531 * 532 * @covers WP_Customize_Nav_Menus::insert_auto_draft_post() 533 */ 534 public function test_insert_auto_draft_post() { 535 $menus = new WP_Customize_Nav_Menus( $this->wp_customize ); 536 537 $r = $menus->insert_auto_draft_post( array() ); 538 $this->assertInstanceOf( 'WP_Error', $r ); 539 $this->assertEquals( 'unknown_post_type', $r->get_error_code() ); 540 541 $r = $menus->insert_auto_draft_post( array( 'post_type' => 'fake' ) ); 542 $this->assertInstanceOf( 'WP_Error', $r ); 543 $this->assertEquals( 'unknown_post_type', $r->get_error_code() ); 544 545 $r = $menus->insert_auto_draft_post( array( 'post_title' => 'Hello World', 'post_type' => 'post' ) ); 546 $this->assertInstanceOf( 'WP_Post', $r ); 547 $this->assertEquals( 'Hello World', $r->post_title ); 548 $this->assertEquals( 'post', $r->post_type ); 549 $this->assertEquals( sanitize_title( $r->post_title ), $r->post_name ); 505 550 } 506 551 … … 554 599 $this->assertContains( 'data-type="post_type"', $template ); 555 600 $this->assertContains( 'data-object="' . esc_attr( $type->name ) . '"', $template ); 601 $this->assertContains( 'data-type_label="' . esc_attr( $type->labels->singular_name ) . '"', $template ); 556 602 } 557 603 } … … 564 610 $this->assertContains( 'data-type="taxonomy"', $template ); 565 611 $this->assertContains( 'data-object="' . esc_attr( $tax->name ) . '"', $template ); 612 $this->assertContains( 'data-type_label="' . esc_attr( $tax->labels->singular_name ) . '"', $template ); 566 613 } 567 614 } … … 571 618 $this->assertContains( 'data-type="custom_type"', $template ); 572 619 $this->assertContains( 'data-object="custom_object"', $template ); 620 $this->assertContains( 'data-type_label="Custom Type"', $template ); 573 621 } 574 622 … … 608 656 $this->assertEquals( 1000, has_filter( 'wp_nav_menu_args', array( $menus, 'filter_wp_nav_menu_args' ) ) ); 609 657 $this->assertEquals( 10, has_filter( 'wp_nav_menu', array( $menus, 'filter_wp_nav_menu' ) ) ); 658 } 659 660 /** 661 * Test make_auto_draft_status_previewable. 662 * 663 * @covers WP_Customize_Nav_Menus::make_auto_draft_status_previewable() 664 */ 665 function test_make_auto_draft_status_previewable() { 666 global $wp_post_statuses; 667 $menus = new WP_Customize_Nav_Menus( $this->wp_customize ); 668 $menus->make_auto_draft_status_previewable(); 669 $this->assertTrue( $wp_post_statuses['auto-draft']->protected ); 670 } 671 672 /** 673 * Test sanitize_nav_menus_created_posts. 674 * 675 * @covers WP_Customize_Nav_Menus::sanitize_nav_menus_created_posts() 676 */ 677 function test_sanitize_nav_menus_created_posts() { 678 $menus = new WP_Customize_Nav_Menus( $this->wp_customize ); 679 $contributor_user_id = $this->factory()->user->create( array( 'role' => 'contributor' ) ); 680 $author_user_id = $this->factory()->user->create( array( 'role' => 'author' ) ); 681 $administrator_user_id = $this->factory()->user->create( array( 'role' => 'administrator' ) ); 682 683 $contributor_post_id = $this->factory()->post->create( array( 684 'post_status' => 'auto-draft', 685 'post_title' => 'Contributor Post', 686 'post_type' => 'post', 687 'post_author' => $contributor_user_id, 688 ) ); 689 $author_post_id = $this->factory()->post->create( array( 690 'post_status' => 'auto-draft', 691 'post_title' => 'Author Post', 692 'post_type' => 'post', 693 'post_author' => $author_user_id, 694 ) ); 695 $administrator_post_id = $this->factory()->post->create( array( 696 'post_status' => 'auto-draft', 697 'post_title' => 'Admin Post', 698 'post_type' => 'post', 699 'post_author' => $administrator_user_id, 700 ) ); 701 702 $value = array( 703 'bad', 704 $contributor_post_id, 705 $author_post_id, 706 $administrator_post_id, 707 ); 708 709 wp_set_current_user( $contributor_user_id ); 710 $sanitized = $menus->sanitize_nav_menus_created_posts( $value ); 711 $this->assertEquals( array(), $sanitized ); 712 713 wp_set_current_user( $author_user_id ); 714 $sanitized = $menus->sanitize_nav_menus_created_posts( $value ); 715 $this->assertEquals( array( $author_post_id ), $sanitized ); 716 717 wp_set_current_user( $administrator_user_id ); 718 $sanitized = $menus->sanitize_nav_menus_created_posts( $value ); 719 $this->assertEquals( array( $contributor_post_id, $author_post_id, $administrator_post_id ), $sanitized ); 720 } 721 722 /** 723 * Test save_nav_menus_created_posts. 724 * 725 * @covers WP_Customize_Nav_Menus::save_nav_menus_created_posts() 726 */ 727 function test_save_nav_menus_created_posts() { 728 $menus = new WP_Customize_Nav_Menus( $this->wp_customize ); 729 do_action( 'customize_register', $this->wp_customize ); 730 731 $post_ids = $this->factory()->post->create_many( 3, array( 732 'post_status' => 'auto-draft', 733 'post_type' => 'post', 734 ) ); 735 $pre_published_post_id = $this->factory()->post->create( array( 'post_status' => 'publish' ) ); 736 737 $setting_id = 'nav_menus_created_posts'; 738 $this->wp_customize->set_post_value( $setting_id, array_merge( $post_ids, array( $pre_published_post_id ) ) ); 739 $setting = $this->wp_customize->get_setting( $setting_id ); 740 $this->assertInstanceOf( 'WP_Customize_Filter_Setting', $setting ); 741 $this->assertEquals( array( $menus, 'sanitize_nav_menus_created_posts' ), $setting->sanitize_callback ); 742 $this->assertEquals( $post_ids, $setting->post_value() ); 743 foreach ( $post_ids as $post_id ) { 744 $this->assertEquals( 'auto-draft', get_post_status( $post_id ) ); 745 } 746 747 $save_action_count = did_action( 'customize_save_nav_menus_created_posts' ); 748 $setting->save(); 749 $this->assertEquals( $save_action_count + 1, did_action( 'customize_save_nav_menus_created_posts' ) ); 750 foreach ( $post_ids as $post_id ) { 751 $this->assertEquals( 'publish', get_post_status( $post_id ) ); 752 } 610 753 } 611 754
Note: See TracChangeset
for help on using the changeset viewer.