Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/js/media/views/attachments/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
}).render() );
}

this.addCustomBulkActions();

} else if ( this.options.date ) {
// DateFilter is a <select>, a label element needs to be rendered before.
this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
Expand Down Expand Up @@ -409,6 +411,89 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro
}
},

/**
* Adds custom bulk action buttons registered via the PHP-side
* `bulk_actions-upload` filter to the grid view toolbar.
*
* @since x.x.x
*
* @return {void}
*/
addCustomBulkActions: function() {
var toolbar = this.toolbar,
controller = this.controller,
settings = window._wpMediaGridSettings || {},
bulkActions = settings.bulkActions || {},
nonce = settings.bulkActionNonce || '';

var BulkActionButton = wp.media.view.Button.extend( {
initialize: function() {
wp.media.view.Button.prototype.initialize.apply( this, arguments );
this.controller.on( 'selection:toggle', this.toggleDisabled, this );
this.controller.on( 'select:activate', this.toggleDisabled, this );
this.controller.on( 'select:deactivate', this.toggleDisabled, this );
},

toggleDisabled: function() {
this.model.set( 'disabled', ! this.controller.state().get( 'selection' ).length );
},

render: function() {
wp.media.view.Button.prototype.render.apply( this, arguments );
if ( this.controller.isModeActive( 'select' ) ) {
this.$el.addClass( 'delete-selected-button' );
} else {
this.$el.addClass( 'delete-selected-button hidden' );
}
this.toggleDisabled();
return this;
},

click: function() {
var ids = this.controller.state().get( 'selection' ).map( function( model ) {
return model.get( 'id' );
} );

if ( ! ids.length ) {
return;
}

this.model.set( 'disabled', true );

wp.media.ajax( {
data: {
action: 'media-grid-bulk-action',
bulk_action: this.options.bulkAction,
ids: ids,
nonce: nonce
},
success: _.bind( function( response ) {
if ( response && response.redirect && response.redirect.length ) {
window.location.href = response.redirect;
} else {
this.controller.trigger( 'selection:action:done' );
}
}, this ),
error: _.bind( function() {
this.model.set( 'disabled', false );
this.controller.trigger( 'selection:action:done' );
}, this )
} );
}
} );

_.each( bulkActions, function( label, action ) {
toolbar.set( 'bulkAction-' + action, new BulkActionButton( {
text: label,
disabled: true,
style: 'secondary',
priority: -75,
controller: controller,
bulkAction: action
} ).render() );
} );
},

updateContent: function() {
var view = this,
noItemsView;
Expand Down
1 change: 1 addition & 0 deletions src/wp-admin/admin-ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
'send-link-to-editor',
'send-attachment-to-editor',
'save-attachment-order',
'media-grid-bulk-action',
'media-create-image-subsizes',
'heartbeat',
'get-revision-diffs',
Expand Down
50 changes: 50 additions & 0 deletions src/wp-admin/includes/ajax-actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -3308,6 +3308,56 @@ function wp_ajax_save_attachment_order() {
wp_send_json_success();
}

/**
* Handles a custom bulk action from the Media Library grid view via AJAX.
*
* @since x.x.x
*/
function wp_ajax_media_grid_bulk_action() {
check_ajax_referer( 'media-grid-bulk-action', 'nonce' );

if ( ! current_user_can( 'upload_files' ) ) {
wp_send_json_error( array( 'message' => __( 'Sorry, you are not allowed to do that.' ) ) );
}

$action = isset( $_REQUEST['bulk_action'] ) ? sanitize_key( wp_unslash( $_REQUEST['bulk_action'] ) ) : '';
$post_ids = isset( $_REQUEST['ids'] ) ? array_map( 'absint', wp_unslash( (array) $_REQUEST['ids'] ) ) : array();

if ( ! $action || empty( $post_ids ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid request.' ) ) );
}

// Reject built-in actions handled natively by the grid view JS.
$built_in = array( 'delete', 'trash', 'untrash' );
if ( in_array( $action, $built_in, true ) ) {
wp_send_json_error( array( 'message' => __( 'Invalid bulk action.' ) ) );
}

// Verify each ID is a real attachment the current user can edit.
$post_ids = array_filter(
$post_ids,
function ( $id ) {
return 'attachment' === get_post_type( $id )
&& current_user_can( 'edit_post', $id );
}
);

if ( empty( $post_ids ) ) {
wp_send_json_error( array( 'message' => __( 'No valid attachments found.' ) ) );
}

// Re-index after filtering.
$post_ids = array_values( $post_ids );

/** This action is documented in wp-admin/upload.php */
$redirect_url = apply_filters( 'handle_bulk_actions-upload', '', $action, $post_ids ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores

// Sanitize redirect to prevent open redirects from plugin filter callbacks.
$redirect_url = wp_validate_redirect( $redirect_url, '' );

wp_send_json_success( array( 'redirect' => esc_url_raw( $redirect_url ) ) );
}

/**
* Handles sending an attachment to the editor via AJAX.
*
Expand Down
19 changes: 17 additions & 2 deletions src/wp-admin/upload.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,27 @@ function () {
}
}

/*
* Collect custom bulk actions registered via the `bulk_actions-upload`
* filter so they can be surfaced in the grid view toolbar alongside
* the built-in Delete button.
*/
$base_actions = MEDIA_TRASH
? array( 'trash' => __( 'Move to Trash' ) )
: array( 'delete' => __( 'Delete permanently' ) );

$bulk_actions = apply_filters( 'bulk_actions-upload', $base_actions ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
$built_in_actions = array( 'delete', 'trash', 'untrash' );
$custom_bulk_actions = array_diff_key( $bulk_actions, array_flip( $built_in_actions ) );

wp_localize_script(
'media-grid',
'_wpMediaGridSettings',
array(
'adminUrl' => parse_url( self_admin_url(), PHP_URL_PATH ),
'queryVars' => (object) $query_vars,
'adminUrl' => parse_url( self_admin_url(), PHP_URL_PATH ),
'queryVars' => (object) $query_vars,
'bulkActions' => (object) $custom_bulk_actions,
'bulkActionNonce' => wp_create_nonce( 'media-grid-bulk-action' ),
)
);

Expand Down
Loading