Changeset 39137
- Timestamp:
- 11/04/2016 06:03:51 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-admin/js/customize-nav-menus.js
r39002 r39137 236 236 } 237 237 } else { 238 self.loadItems( type, object ); 238 self.loadItems( [ 239 { type: type, object: object } 240 ] ); 239 241 } 240 242 } … … 361 363 _.each( api.Menus.data.itemTypes, function( itemType ) { 362 364 self.pages[ itemType.type + ':' + itemType.object ] = 0; 363 self.loadItems( itemType.type, itemType.object ); // @todo we need to combine these Ajax requests.364 365 } ); 365 }, 366 367 // Load available menu items. 368 loadItems: function( type, object ) { 369 var self = this, params, request, itemTemplate, availableMenuItemContainer; 366 self.loadItems( api.Menus.data.itemTypes ); 367 }, 368 369 /** 370 * Load available nav menu items. 371 * 372 * @since 4.3.0 373 * @since 4.7.0 Changed function signature to take list of item types instead of single type/object. 374 * @access private 375 * 376 * @param {Array.<object>} itemTypes List of objects containing type and key. 377 * @param {string} deprecated Formerly the object parameter. 378 * @returns {void} 379 */ 380 loadItems: function( itemTypes, deprecated ) { 381 var self = this, _itemTypes, requestItemTypes = [], request, itemTemplate, availableMenuItemContainers = {}; 370 382 itemTemplate = wp.template( 'available-menu-item' ); 371 383 372 if ( -1 === self.pages[ type + ':' + object ] ) { 384 if ( _.isString( itemTypes ) && _.isString( deprecated ) ) { 385 _itemTypes = [ { type: itemTypes, object: deprecated } ]; 386 } else { 387 _itemTypes = itemTypes; 388 } 389 390 _.each( _itemTypes, function( itemType ) { 391 var container, name = itemType.type + ':' + itemType.object; 392 if ( -1 === self.pages[ name ] ) { 393 return; // Skip types for which there are no more results. 394 } 395 container = $( '#available-menu-items-' + itemType.type + '-' + itemType.object ); 396 container.find( '.accordion-section-title' ).addClass( 'loading' ); 397 availableMenuItemContainers[ name ] = container; 398 399 requestItemTypes.push( { 400 object: itemType.object, 401 type: itemType.type, 402 page: self.pages[ name ] 403 } ); 404 } ); 405 406 if ( 0 === requestItemTypes.length ) { 373 407 return; 374 408 } 375 availableMenuItemContainer = $( '#available-menu-items-' + type + '-' + object ); 376 availableMenuItemContainer.find( '.accordion-section-title' ).addClass( 'loading' ); 409 377 410 self.loading = true; 378 params ={411 request = wp.ajax.post( 'load-available-menu-items-customizer', { 379 412 'customize-menus-nonce': api.settings.nonce['customize-menus'], 380 413 'wp_customize': 'on', 381 'type': type, 382 'object': object, 383 'page': self.pages[ type + ':' + object ] 384 }; 385 request = wp.ajax.post( 'load-available-menu-items-customizer', params ); 414 'item_types': requestItemTypes 415 } ); 386 416 387 417 request.done(function( data ) { 388 var items, typeInner; 389 items = data.items; 390 if ( 0 === items.length ) { 391 if ( 0 === self.pages[ type + ':' + object ] ) { 392 availableMenuItemContainer 393 .addClass( 'cannot-expand' ) 394 .removeClass( 'loading' ) 395 .find( '.accordion-section-title > button' ) 396 .prop( 'tabIndex', -1 ); 397 } 398 self.pages[ type + ':' + object ] = -1; 399 return; 400 } else if ( ( 'page' === object ) && ( ! availableMenuItemContainer.hasClass( 'open' ) ) ) { 401 availableMenuItemContainer.find( '.accordion-section-title > button' ).click(); 402 } 403 items = new api.Menus.AvailableItemCollection( items ); // @todo Why is this collection created and then thrown away? 404 self.collection.add( items.models ); 405 typeInner = availableMenuItemContainer.find( '.available-menu-items-list' ); 406 items.each(function( menuItem ) { 407 typeInner.append( itemTemplate( menuItem.attributes ) ); 418 var typeInner; 419 _.each( data.items, function( typeItems, name ) { 420 if ( 0 === typeItems.length ) { 421 if ( 0 === self.pages[ name ] ) { 422 availableMenuItemContainers[ name ].find( '.accordion-section-title' ) 423 .addClass( 'cannot-expand' ) 424 .removeClass( 'loading' ) 425 .find( '.accordion-section-title > button' ) 426 .prop( 'tabIndex', -1 ); 427 } 428 self.pages[ name ] = -1; 429 return; 430 } else if ( ( 'post_type:page' === name ) && ( ! availableMenuItemContainers[ name ].hasClass( 'open' ) ) ) { 431 availableMenuItemContainers[ name ].find( '.accordion-section-title > button' ).click(); 432 } 433 typeItems = new api.Menus.AvailableItemCollection( typeItems ); // @todo Why is this collection created and then thrown away? 434 self.collection.add( typeItems.models ); 435 typeInner = availableMenuItemContainers[ name ].find( '.available-menu-items-list' ); 436 typeItems.each( function( menuItem ) { 437 typeInner.append( itemTemplate( menuItem.attributes ) ); 438 } ); 439 self.pages[ name ] += 1; 408 440 }); 409 self.pages[ type + ':' + object ] += 1;410 441 }); 411 442 request.fail(function( data ) { … … 415 446 }); 416 447 request.always(function() { 417 availableMenuItemContainer.find( '.accordion-section-title' ).removeClass( 'loading' ); 448 _.each( availableMenuItemContainers, function( container ) { 449 container.find( '.accordion-section-title' ).removeClass( 'loading' ); 450 } ); 418 451 self.loading = false; 419 452 }); -
trunk/src/wp-includes/class-wp-customize-nav-menus.php
r39038 r39137 101 101 } 102 102 103 if ( empty( $_POST['type'] ) || empty( $_POST['object'] ) ) { 103 $all_items = array(); 104 $item_types = array(); 105 if ( isset( $_POST['item_types'] ) && is_array( $_POST['item_types'] ) ) { 106 $item_types = wp_unslash( $_POST['item_types'] ); 107 } elseif ( isset( $_POST['type'] ) && isset( $_POST['object'] ) ) { // Back compat. 108 $item_types[] = array( 109 'type' => wp_unslash( $_POST['type'] ), 110 'object' => wp_unslash( $_POST['object'] ), 111 'page' => empty( $_POST['page'] ) ? 0 : absint( $_POST['page'] ), 112 ); 113 } else { 104 114 wp_send_json_error( 'nav_menus_missing_type_or_object_parameter' ); 105 115 } 106 116 107 $type = sanitize_key( $_POST['type'] ); 108 $object = sanitize_key( $_POST['object'] ); 109 $page = empty( $_POST['page'] ) ? 0 : absint( $_POST['page'] ); 110 $items = $this->load_available_items_query( $type, $object, $page ); 111 112 if ( is_wp_error( $items ) ) { 113 wp_send_json_error( $items->get_error_code() ); 114 } else { 115 wp_send_json_success( array( 'items' => $items ) ); 116 } 117 foreach ( $item_types as $item_type ) { 118 if ( empty( $item_type['type'] ) || empty( $item_type['object'] ) ) { 119 wp_send_json_error( 'nav_menus_missing_type_or_object_parameter' ); 120 } 121 $type = sanitize_key( $item_type['type'] ); 122 $object = sanitize_key( $item_type['object'] ); 123 $page = empty( $item_type['page'] ) ? 0 : absint( $item_type['page'] ); 124 $items = $this->load_available_items_query( $type, $object, $page ); 125 if ( is_wp_error( $items ) ) { 126 wp_send_json_error( $items->get_error_code() ); 127 } 128 $all_items[ $item_type['type'] . ':' . $item_type['object'] ] = $items; 129 } 130 131 wp_send_json_success( array( 'items' => $all_items ) ); 117 132 } 118 133 -
trunk/tests/phpunit/tests/ajax/CustomizeMenus.php
r39038 r39137 175 175 array( 176 176 array( 177 'type' => 'post_type', 178 'object' => '', 179 ), 180 array( 181 'success' => false, 182 'data' => 'nav_menus_missing_type_or_object_parameter', 183 ), 184 ), 185 // Testing empty type. 186 array( 187 array( 177 188 'type' => '', 178 189 'object' => 'post', … … 183 194 ), 184 195 ), 185 // Testing empty type. 186 array( 187 array( 188 'type' => '', 189 'object' => 'post', 196 // Testing empty type of a bulk request. 197 array( 198 array( 199 'item_types' => array( 200 array( 201 'type' => 'post_type', 202 'object' => 'post', 203 ), 204 array( 205 'type' => 'post_type', 206 'object' => '', 207 ), 208 ), 190 209 ), 191 210 array( … … 274 293 'type' => 'taxonomy', 275 294 'object' => 'post_tag', 295 ), 296 true, 297 ), 298 // Testing a bulk request. 299 array( 300 array( 301 'item_types' => array( 302 array( 303 'type' => 'post_type', 304 'object' => 'post', 305 ), 306 array( 307 'type' => 'post_type', 308 'object' => 'page', 309 ), 310 ), 276 311 ), 277 312 true, … … 314 349 $response = json_decode( $this->_last_response, true ); 315 350 316 $this->assertNotEmpty( $response['data']['items']);351 $this->assertNotEmpty( current( $response['data']['items'] ) ); 317 352 318 353 // Get the second index to avoid the home page edge case. 319 $test_item = $response['data']['items'][1]; 354 $first_prop = current( $response['data']['items'] ); 355 $test_item = $first_prop[1]; 320 356 321 357 foreach ( $expected_keys as $key ) { … … 326 362 // Special test for the home page. 327 363 if ( 'page' === $test_item['object'] ) { 328 $home = $response['data']['items'][0]; 364 $first_prop = current( $response['data']['items'] ); 365 $home = $first_prop[0]; 329 366 foreach ( $expected_keys as $key ) { 330 367 if ( 'object_id' !== $key ) {
Note: See TracChangeset
for help on using the changeset viewer.