Allow the 'Uploaded to this post' view to be sorted, saving the resulting order as menu_order.

This functionality is designed to be backwards compatible with manual querying for attachments by menu_order.

props koopersmith.
see #22607.



git-svn-id: http://core.svn.wordpress.org/trunk@22967 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Andrew Nacin 2012-12-02 16:06:31 +00:00
parent 3cfc81b328
commit 27bf82201b
5 changed files with 112 additions and 7 deletions

View File

@ -56,7 +56,7 @@ $core_actions_post = array(
'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post', 'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post',
'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment', 'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment',
'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor', 'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor',
'send-attachment-to-editor', 'send-attachment-to-editor', 'save-attachment-order',
); );
// Register core Ajax calls. // Register core Ajax calls.

View File

@ -1927,6 +1927,39 @@ function wp_ajax_save_attachment_compat() {
wp_send_json_success( $attachment ); wp_send_json_success( $attachment );
} }
function wp_ajax_save_attachment_order() {
if ( ! isset( $_REQUEST['post_id'] ) )
wp_send_json_error();
if ( ! $post_id = absint( $_REQUEST['post_id'] ) )
wp_send_json_error();
if ( empty( $_REQUEST['attachments'] ) )
wp_send_json_error();
check_ajax_referer( 'update-post_' . $post_id, 'nonce' );
$attachments = $_REQUEST['attachments'];
if ( ! current_user_can( 'edit_post', $post_id ) )
wp_send_json_error();
$post = get_post( $post_id, ARRAY_A );
foreach ( $attachments as $attachment_id => $menu_order ) {
if ( ! current_user_can( 'edit_post', $attachment_id ) )
continue;
if ( ! $attachment = get_post( $attachment_id ) )
continue;
if ( 'attachment' != $attachment->post_type )
continue;
wp_update_post( array( 'ID' => $attachment_id, 'menu_order' => $menu_order ) );
}
wp_send_json_success();
}
/** /**
* Generates the HTML to send an attachment to the editor. * Generates the HTML to send an attachment to the editor.
* Backwards compatible with the media_send_to_editor filter and the chain * Backwards compatible with the media_send_to_editor filter and the chain

View File

@ -523,6 +523,34 @@ window.wp = window.wp || {};
_requery: function() { _requery: function() {
if ( this.props.get('query') ) if ( this.props.get('query') )
this.mirror( Query.get( this.props.toJSON() ) ); this.mirror( Query.get( this.props.toJSON() ) );
},
// If this collection is sorted by `menuOrder`, recalculates and saves
// the menu order to the database.
saveMenuOrder: function() {
if ( 'menuOrder' !== this.props.get('orderby') )
return;
// Removes any uploading attachments, updates each attachment's
// menu order, and returns an object with an { id: menuOrder }
// mapping to pass to the request.
var attachments = this.chain().filter( function( attachment ) {
return ! _.isUndefined( attachment.id );
}).map( function( attachment, index ) {
// Indices start at 1.
index = index + 1;
attachment.set( 'menuOrder', index );
return [ attachment.id, index ];
}).object().value();
if ( _.isEmpty( attachments ) )
return;
return media.post( 'save-attachment-order', {
nonce: media.model.settings.updatePostNonce,
post_id: media.model.settings.postId,
attachments: attachments
});
} }
}, { }, {
comparator: function( a, b, options ) { comparator: function( a, b, options ) {

View File

@ -14,6 +14,7 @@
// Copy the `postId` setting over to the model settings. // Copy the `postId` setting over to the model settings.
media.model.settings.postId = media.view.settings.postId; media.model.settings.postId = media.view.settings.postId;
media.model.settings.updatePostNonce = media.view.settings.nonce.updatePost;
// Check if the browser supports CSS 3.0 transitions // Check if the browser supports CSS 3.0 transitions
$.support.transition = (function(){ $.support.transition = (function(){
@ -267,7 +268,8 @@
content: 'browse', content: 'browse',
searchable: true, searchable: true,
filterable: false, filterable: false,
uploads: true uploads: true,
sortable: true
}, },
initialize: function() { initialize: function() {
@ -2690,7 +2692,6 @@
this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value(); this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
this.initSortable(); this.initSortable();
this.collection.props.on( 'change:orderby', this.refreshSortable, this );
_.bindAll( this, 'css' ); _.bindAll( this, 'css' );
this.model.on( 'change:edge change:gutter', this.css, this ); this.model.on( 'change:edge change:gutter', this.css, this );
@ -2734,7 +2735,8 @@
}, },
initSortable: function() { initSortable: function() {
var collection = this.collection, var view = this,
collection = this.collection,
from; from;
if ( ! this.options.sortable || ! $.fn.sortable ) if ( ! this.options.sortable || ! $.fn.sortable )
@ -2760,14 +2762,30 @@
// Update the model's index in the collection. // Update the model's index in the collection.
// Do so silently, as the view is already accurate. // Do so silently, as the view is already accurate.
update: function( event, ui ) { update: function( event, ui ) {
var model = collection.at( from ); var model = collection.at( from ),
comparator = collection.comparator;
// Temporarily disable the comparator to prevent `add`
// from re-sorting.
delete collection.comparator;
// Silently shift the model to its new index.
collection.remove( model, { collection.remove( model, {
silent: true silent: true
}).add( model, { }).add( model, {
at: ui.item.index(), at: ui.item.index(),
silent: true silent: true
}); });
// Restore the comparator.
collection.comparator = comparator;
// If the collection is sorted by menu order,
// update the menu order.
view.saveMenuOrder();
// Make sure any menu-order-related callbacks are bound.
view.refreshSortable();
} }
}); });
@ -2776,6 +2794,9 @@
collection.props.on( 'change:orderby', function() { collection.props.on( 'change:orderby', function() {
this.$el.sortable( 'option', 'disabled', !! collection.comparator ); this.$el.sortable( 'option', 'disabled', !! collection.comparator );
}, this ); }, this );
this.collection.props.on( 'change:orderby', this.refreshSortable, this );
this.refreshSortable();
}, },
refreshSortable: function() { refreshSortable: function() {
@ -2783,7 +2804,29 @@
return; return;
// If the `collection` has a `comparator`, disable sorting. // If the `collection` has a `comparator`, disable sorting.
this.$el.sortable( 'option', 'disabled', !! this.collection.comparator ); var collection = this.collection,
orderby = collection.props.get('orderby'),
enabled = 'menuOrder' === orderby || ! collection.comparator,
hasMenuOrder;
this.$el.sortable( 'option', 'disabled', ! enabled );
// Check if any attachments have a specified menu order.
hasMenuOrder = this.collection.any( function( attachment ) {
return attachment.get('menuOrder');
});
// Always unbind the `saveMenuOrder` callback to prevent multiple
// callbacks stacking up.
this.collection.off( 'change:uploading', this.saveMenuOrder, this );
if ( hasMenuOrder )
this.collection.on( 'change:uploading', this.saveMenuOrder, this );
},
saveMenuOrder: function() {
this.collection.saveMenuOrder();
}, },
createAttachmentView: function( attachment ) { createAttachmentView: function( attachment ) {
@ -3049,7 +3092,7 @@
}).render() ); }).render() );
} }
if ( this.options.sortable ) { if ( this.options.sortable && ! this.options.filters ) {
this.toolbar.set( 'dragInfo', new media.View({ this.toolbar.set( 'dragInfo', new media.View({
el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0], el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
priority: -40 priority: -40

View File

@ -1433,6 +1433,7 @@ function wp_enqueue_media( $args = array() ) {
if ( isset( $args['post'] ) ) { if ( isset( $args['post'] ) ) {
$post = get_post( $args['post'] ); $post = get_post( $args['post'] );
$settings['postId'] = $post->ID; $settings['postId'] = $post->ID;
$settings['nonce']['updatePost'] = wp_create_nonce( 'update-post_' . $post->ID );
} }
$hier = $post && is_post_type_hierarchical( $post->post_type ); $hier = $post && is_post_type_hierarchical( $post->post_type );