diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php
index 6c9fdd2680..26d7e4770d 100644
--- a/src/wp-admin/includes/ajax-actions.php
+++ b/src/wp-admin/includes/ajax-actions.php
@@ -2267,6 +2267,9 @@ function wp_ajax_save_attachment() {
if ( 'attachment' != $post['post_type'] )
wp_send_json_error();
+ if ( isset( $changes['parent'] ) )
+ $post['post_parent'] = $changes['parent'];
+
if ( isset( $changes['title'] ) )
$post['post_title'] = $changes['title'];
diff --git a/src/wp-admin/includes/class-wp-media-list-table.php b/src/wp-admin/includes/class-wp-media-list-table.php
index 483421b527..0401c61fae 100644
--- a/src/wp-admin/includes/class-wp-media-list-table.php
+++ b/src/wp-admin/includes/class-wp-media-list-table.php
@@ -139,6 +139,9 @@ class WP_Media_List_Table extends WP_List_Table {
if ( isset( $_REQUEST['found_post_id'] ) && isset( $_REQUEST['media'] ) )
return 'attach';
+ if ( isset( $_REQUEST['parent_post_id'] ) && isset( $_REQUEST['media'] ) )
+ return 'detach';
+
if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
return 'delete_all';
@@ -406,7 +409,16 @@ foreach ( $columns as $column_name => $column_display_name ) {
} else {
echo $title;
} ?>,
-
+
+ $post->post_parent,
+ 'media[]' => $post->ID,
+ '_wpnonce' => wp_create_nonce( 'bulk-' . $this->_args['plural'] )
+ ), 'upload.php' ); ?>
+
+
query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $ids_string )", $parent_id ) );
+ } else {
+ $result = $wpdb->query( "UPDATE $wpdb->posts SET post_parent = 0 WHERE post_type = 'attachment' AND ID IN ( $ids_string )" );
+ }
+
+ foreach ( $ids as $att_id ) {
+ clean_attachment_cache( $att_id );
+ }
+ }
+
+ if ( isset( $result ) ) {
+ $location = 'upload.php';
+ if ( $referer = wp_get_referer() ) {
+ if ( false !== strpos( $referer, 'upload.php' ) ) {
+ $location = remove_query_arg( array( 'attached', 'detached' ), $referer );
+ }
+ }
+
+ $key = 'attach' === $action ? 'attached' : 'detached';
+ $location = add_query_arg( array( $key => $result ), $location );
+ wp_redirect( $location );
+ exit;
+ }
+}
\ No newline at end of file
diff --git a/src/wp-admin/upload.php b/src/wp-admin/upload.php
index 5408395dc7..e25b887175 100644
--- a/src/wp-admin/upload.php
+++ b/src/wp-admin/upload.php
@@ -113,45 +113,14 @@ if ( $doaction ) {
}
switch ( $doaction ) {
- case 'attach':
- $parent_id = (int) $_REQUEST['found_post_id'];
- if ( !$parent_id )
- return;
-
- $parent = get_post( $parent_id );
- if ( !current_user_can( 'edit_post', $parent_id ) )
- wp_die( __( 'You are not allowed to edit this post.' ) );
-
- $attach = array();
- foreach ( (array) $_REQUEST['media'] as $att_id ) {
- $att_id = (int) $att_id;
-
- if ( !current_user_can( 'edit_post', $att_id ) )
- continue;
-
- $attach[] = $att_id;
- }
-
- if ( ! empty( $attach ) ) {
- $attach_string = implode( ',', $attach );
- $attached = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $attach_string )", $parent_id ) );
- foreach ( $attach as $att_id ) {
- clean_attachment_cache( $att_id );
- }
- }
-
- if ( isset( $attached ) ) {
- $location = 'upload.php';
- if ( $referer = wp_get_referer() ) {
- if ( false !== strpos( $referer, 'upload.php' ) )
- $location = $referer;
- }
-
- $location = add_query_arg( array( 'attached' => $attached ) , $location );
- wp_redirect( $location );
- exit;
- }
+ case 'detach':
+ wp_media_attach_action( $_REQUEST['parent_post_id'], 'detach' );
break;
+
+ case 'attach':
+ wp_media_attach_action( $_REQUEST['found_post_id'] );
+ break;
+
case 'trash':
if ( !isset( $post_ids ) )
break;
@@ -256,7 +225,12 @@ if ( ! empty( $_GET['posted'] ) ) {
if ( ! empty( $_GET['attached'] ) && $attached = absint( $_GET['attached'] ) ) {
$message = sprintf( _n('Reattached %d attachment.', 'Reattached %d attachments.', $attached), $attached );
- $_SERVER['REQUEST_URI'] = remove_query_arg(array('attached'), $_SERVER['REQUEST_URI']);
+ $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'detached', 'attached' ), $_SERVER['REQUEST_URI'] );
+}
+
+if ( ! empty( $_GET['detached'] ) && $detached = absint( $_GET['detached'] ) ) {
+ $message = sprintf( _n( 'Detached %d attachment.', 'Detached %d attachments.', $detached ), $detached );
+ $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'detached', 'attached' ), $_SERVER['REQUEST_URI'] );
}
if ( ! empty( $_GET['deleted'] ) && $deleted = absint( $_GET['deleted'] ) ) {
diff --git a/src/wp-includes/js/media/views.js b/src/wp-includes/js/media/views.js
index 7964cdc147..0ef4b5150d 100644
--- a/src/wp-includes/js/media/views.js
+++ b/src/wp-includes/js/media/views.js
@@ -2656,6 +2656,7 @@ Attachment = View.extend({
this.listenTo( this.model, 'change', this.render );
} else {
this.listenTo( this.model, 'change:percent', this.progress );
+ this.listenTo( this.model, 'change:parent', this.render );
}
this.listenTo( this.model, 'change:title', this._syncTitle );
this.listenTo( this.model, 'change:caption', this._syncCaption );
@@ -3195,7 +3196,8 @@ Details = Attachment.extend({
'click .untrash-attachment': 'untrashAttachment',
'click .edit-attachment': 'editAttachment',
'click .refresh-attachment': 'refreshAttachment',
- 'keydown': 'toggleSelectionHandler'
+ 'keydown': 'toggleSelectionHandler',
+ 'click .detach-from-parent': 'detachFromParent'
},
initialize: function() {
@@ -3294,6 +3296,20 @@ Details = Attachment.extend({
this.controller.trigger( 'attachment:keydown:arrow', event );
return;
}
+ },
+
+ /**
+ * @param {Object} event
+ */
+ detachFromParent: function( event ) {
+ event.preventDefault();
+
+ this.model.save({
+ 'parent' : 0,
+ 'uploadedTo' : 0,
+ 'uploadedToLink' : '',
+ 'uploadedToTitle' : ''
+ });
}
});
diff --git a/src/wp-includes/js/media/views/attachment.js b/src/wp-includes/js/media/views/attachment.js
index 535f689e24..768477a04f 100644
--- a/src/wp-includes/js/media/views/attachment.js
+++ b/src/wp-includes/js/media/views/attachment.js
@@ -52,6 +52,7 @@ Attachment = View.extend({
this.listenTo( this.model, 'change', this.render );
} else {
this.listenTo( this.model, 'change:percent', this.progress );
+ this.listenTo( this.model, 'change:parent', this.render );
}
this.listenTo( this.model, 'change:title', this._syncTitle );
this.listenTo( this.model, 'change:caption', this._syncCaption );
diff --git a/src/wp-includes/js/media/views/attachment/details.js b/src/wp-includes/js/media/views/attachment/details.js
index f7a2ed9c1e..4e77fd6a3c 100644
--- a/src/wp-includes/js/media/views/attachment/details.js
+++ b/src/wp-includes/js/media/views/attachment/details.js
@@ -35,7 +35,8 @@ Details = Attachment.extend({
'click .untrash-attachment': 'untrashAttachment',
'click .edit-attachment': 'editAttachment',
'click .refresh-attachment': 'refreshAttachment',
- 'keydown': 'toggleSelectionHandler'
+ 'keydown': 'toggleSelectionHandler',
+ 'click .detach-from-parent': 'detachFromParent'
},
initialize: function() {
@@ -134,6 +135,20 @@ Details = Attachment.extend({
this.controller.trigger( 'attachment:keydown:arrow', event );
return;
}
+ },
+
+ /**
+ * @param {Object} event
+ */
+ detachFromParent: function( event ) {
+ event.preventDefault();
+
+ this.model.save({
+ 'parent' : 0,
+ 'uploadedTo' : 0,
+ 'uploadedToLink' : '',
+ 'uploadedToTitle' : ''
+ });
}
});
diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php
index 76b2d32af4..c7ec89acfc 100644
--- a/src/wp-includes/media-template.php
+++ b/src/wp-includes/media-template.php
@@ -418,6 +418,9 @@ function wp_print_media_templates() {
<# } else { #>
{{ data.uploadedToTitle }}
<# } #>
+ <# if ( data.nonces.edit ) { #>
+ ()
+ <# } #>
<# } #>