diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index adf6b7f2a5..72a6fa3240 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -1812,7 +1812,13 @@ function wp_ajax_get_attachment() { if ( ! $id = absint( $_REQUEST['id'] ) ) wp_send_json_error(); - if ( ! current_user_can( 'read_post', $id ) ) + if ( ! $post = get_post( $id ) ) + wp_send_json_error(); + + if ( 'attachment' != $post->post_type ) + wp_send_json_error(); + + if ( ! current_user_can( 'upload_files' ) ) wp_send_json_error(); if ( ! $attachment = wp_prepare_attachment_for_js( $id ) ) @@ -1827,6 +1833,9 @@ function wp_ajax_get_attachment() { * @since 3.5.0 */ function wp_ajax_query_attachments() { + if ( ! current_user_can( 'upload_files' ) ) + wp_send_json_error(); + $query = isset( $_REQUEST['query'] ) ? (array) $_REQUEST['query'] : array(); $query = array_intersect_key( $query, array_flip( array( 's', 'order', 'orderby', 'posts_per_page', 'paged', 'post_mime_type', @@ -1988,15 +1997,14 @@ function wp_ajax_send_attachment_to_editor() { if ( ! $post = get_post( $id ) ) wp_send_json_error(); - if ( ! current_user_can( 'edit_post', $id ) ) - wp_send_json_error(); - if ( 'attachment' != $post->post_type ) wp_send_json_error(); - // If this attachment is unattached, attach it. Primarily a back compat thing. - if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) { - wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) ); + if ( current_user_can( 'edit_post', $id ) ) { + // If this attachment is unattached, attach it. Primarily a back compat thing. + if ( 0 == $post->post_parent && $insert_into_post_id = intval( $_POST['post_id'] ) ) { + wp_update_post( array( 'ID' => $id, 'post_parent' => $insert_into_post_id ) ); + } } $rel = $url = ''; diff --git a/wp-includes/css/media-views.css b/wp-includes/css/media-views.css index 14f7ad3ca3..3e2f9fcdb6 100644 --- a/wp-includes/css/media-views.css +++ b/wp-includes/css/media-views.css @@ -61,6 +61,13 @@ border-color: #dfdfdf; } +.media-frame input:disabled, +.media-frame textarea:disabled, +.media-frame input[readonly], +.media-frame textarea[readonly] { + background-color: #eee; +} + .media-frame input[type="search"] { -webkit-appearance: textfield; } diff --git a/wp-includes/js/media-models.js b/wp-includes/js/media-models.js index 332fe0e0fa..120e1e5529 100644 --- a/wp-includes/js/media-models.js +++ b/wp-includes/js/media-models.js @@ -219,7 +219,7 @@ window.wp = window.wp || {}; // If the attachment does not yet have an `id`, return an instantly // rejected promise. Otherwise, all of our requests will fail. if ( _.isUndefined( this.id ) ) - return $.Deferred().reject().promise(); + return $.Deferred().rejectWith( this ).promise(); // Overload the `read` request so Attachment.fetch() functions correctly. if ( 'read' === method ) { @@ -233,8 +233,9 @@ window.wp = window.wp || {}; // Overload the `update` request so properties can be saved. } else if ( 'update' === method ) { - if ( ! this.get('nonces') ) - return $.Deferred().resolveWith( this ).promise(); + // If we do not have the necessary nonce, fail immeditately. + if ( ! this.get('nonces') || ! this.get('nonces').update ) + return $.Deferred().rejectWith( this ).promise(); options = options || {}; options.context = this; @@ -286,6 +287,10 @@ window.wp = window.wp || {}; saveCompat: function( data, options ) { var model = this; + // If we do not have the necessary nonce, fail immeditately. + if ( ! this.get('nonces') || ! this.get('nonces').update ) + return $.Deferred().rejectWith( this ).promise(); + return media.post( 'save-attachment-compat', _.defaults({ id: this.id, nonce: this.get('nonces').update, diff --git a/wp-includes/js/media-views.js b/wp-includes/js/media-views.js index af38825f0d..b330a6bcaf 100644 --- a/wp-includes/js/media-views.js +++ b/wp-includes/js/media-views.js @@ -2756,8 +2756,7 @@ }, render: function() { - var attachment = this.model.toJSON(), - options = _.defaults( this.model.toJSON(), { + var options = _.defaults( this.model.toJSON(), { orientation: 'landscape', uploading: false, type: '', @@ -2779,6 +2778,12 @@ if ( 'image' === options.type ) options.size = this.imageSize(); + options.can = {}; + if ( options.nonces ) { + options.can.remove = !! options.nonces['delete']; + options.can.save = !! options.nonces.update; + } + this.views.detach(); this.$el.html( this.template( options ) ); @@ -2967,12 +2972,12 @@ this.updateSave('waiting'); save.requests = requests; - requests.done( function() { + requests.always( function() { // If we've performed another request since this one, bail. if ( save.requests !== requests ) return; - view.updateSave('complete'); + view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' ); save.savedTimer = setTimeout( function() { view.updateSave('ready'); delete save.savedTimer; diff --git a/wp-includes/media.php b/wp-includes/media.php index 42db6d3415..d2ae63341a 100644 --- a/wp-includes/media.php +++ b/wp-includes/media.php @@ -1334,11 +1334,17 @@ function wp_prepare_attachment_for_js( $attachment ) { 'icon' => wp_mime_type_icon( $attachment->ID ), 'dateFormatted' => mysql2date( get_option('date_format'), $attachment->post_date ), 'nonces' => array( - 'update' => wp_create_nonce( 'update-post_' . $attachment->ID ), - 'delete' => wp_create_nonce( 'delete-post_' . $attachment->ID ), + 'update' => false, + 'delete' => false, ), ); + if ( current_user_can( 'edit_post', $attachment->ID ) ) + $response['nonces']['update'] = wp_create_nonce( 'update-post_' . $attachment->ID ); + + if ( current_user_can( 'delete_post', $attachment->ID ) ) + $response['nonces']['delete'] = wp_create_nonce( 'delete-post_' . $attachment->ID ); + if ( $meta && 'image' === $type ) { $sizes = array(); $possible_sizes = apply_filters( 'image_size_names_choose', array( @@ -1690,7 +1696,7 @@ function wp_print_media_templates() { <# if ( 'image' === data.type && ! data.uploading && data.width && data.height ) { #>
{{ data.width }} × {{ data.height }}
<# } #> - <# if ( ! data.uploading ) { #> + <# if ( ! data.uploading && data.can.remove ) { #>