Make WordPress Core

Ticket #47872: 47872.diff

File 47872.diff, 45.3 KB (added by azaozz, 5 years ago)
  • src/js/_enqueues/vendor/plupload/handlers.js

     
    22var topWin = window.dialogArguments || opener || parent || top, uploader, uploader_init;
    33
    44// progress and success handlers for media multi uploads
    5 function fileQueued(fileObj) {
     5function fileQueued( fileObj ) {
    66        // Get rid of unused form
    7         jQuery('.media-blank').remove();
     7        jQuery( '.media-blank' ).remove();
    88
    9         var items = jQuery('#media-items').children(), postid = post_id || 0;
     9        var items = jQuery( '#media-items' ).children(), postid = post_id || 0;
    1010
    1111        // Collapse a single item
    1212        if ( items.length == 1 ) {
    13                 items.removeClass('open').find('.slidetoggle').slideUp(200);
     13                items.removeClass( 'open' ).find( '.slidetoggle' ).slideUp( 200 );
    1414        }
    1515        // Create a progress bar containing the filename
    16         jQuery('<div class="media-item">')
     16        jQuery( '<div class="media-item">' )
    1717                .attr( 'id', 'media-item-' + fileObj.id )
    18                 .addClass('child-of-' + postid)
    19                 .append('<div class="progress"><div class="percent">0%</div><div class="bar"></div></div>',
    20                         jQuery('<div class="filename original">').text( ' ' + fileObj.name ))
    21                 .appendTo( jQuery('#media-items' ) );
     18                .addClass( 'child-of-' + postid )
     19                .append( '<div class="progress"><div class="percent">0%</div><div class="bar"></div></div>',
     20                        jQuery( '<div class="filename original">' ).text( ' ' + fileObj.name ))
     21                .appendTo( jQuery( '#media-items' ) );
    2222
    2323        // Disable submit
    24         jQuery('#insert-gallery').prop('disabled', true);
     24        jQuery( '#insert-gallery' ).prop( 'disabled', true );
    2525}
    2626
    2727function uploadStart() {
    2828        try {
    2929                if ( typeof topWin.tb_remove != 'undefined' )
    30                         topWin.jQuery('#TB_overlay').unbind('click', topWin.tb_remove);
    31         } catch(e){}
     30                        topWin.jQuery( '#TB_overlay' ).unbind( 'click', topWin.tb_remove );
     31        } catch( e ){}
    3232
    3333        return true;
    3434}
    3535
    36 function uploadProgress(up, file) {
    37         var item = jQuery('#media-item-' + file.id);
     36function uploadProgress( up, file ) {
     37        var item = jQuery( '#media-item-' + file.id );
    3838
    39         jQuery('.bar', item).width( (200 * file.loaded) / file.size );
    40         jQuery('.percent', item).html( file.percent + '%' );
     39        jQuery( '.bar', item ).width( ( 200 * file.loaded ) / file.size );
     40        jQuery( '.percent', item ).html( file.percent + '%' );
    4141}
    4242
    4343// check to see if a large file failed to upload
     
    5858}
    5959
    6060function updateMediaForm() {
    61         var items = jQuery('#media-items').children();
     61        var items = jQuery( '#media-items' ).children();
    6262
    6363        // Just one file, no need for collapsible part
    6464        if ( items.length == 1 ) {
    65                 items.addClass('open').find('.slidetoggle').show();
    66                 jQuery('.insert-gallery').hide();
     65                items.addClass( 'open' ).find( '.slidetoggle' ).show();
     66                jQuery( '.insert-gallery' ).hide();
    6767        } else if ( items.length > 1 ) {
    68                 items.removeClass('open');
     68                items.removeClass( 'open' );
    6969                // Only show Gallery/Playlist buttons when there are at least two files.
    70                 jQuery('.insert-gallery').show();
     70                jQuery( '.insert-gallery' ).show();
    7171        }
    7272
    7373        // Only show Save buttons when there is at least one file.
    74         if ( items.not('.media-blank').length > 0 )
    75                 jQuery('.savebutton').show();
     74        if ( items.not( '.media-blank' ).length > 0 )
     75                jQuery( '.savebutton' ).show();
    7676        else
    77                 jQuery('.savebutton').hide();
     77                jQuery( '.savebutton' ).hide();
    7878}
    7979
    80 function uploadSuccess(fileObj, serverData) {
    81         var item = jQuery('#media-item-' + fileObj.id);
     80function uploadSuccess( fileObj, serverData ) {
     81        var item = jQuery( '#media-item-' + fileObj.id );
    8282
    8383        // on success serverData should be numeric, fix bug in html4 runtime returning the serverData wrapped in a <pre> tag
    84         serverData = serverData.replace(/^<pre>(\d+)<\/pre>$/, '$1');
     84        if ( typeof serverData === 'string' ) {
     85                serverData = serverData.replace( /^<pre>(\d+)<\/pre>$/, '$1' );
    8586
    86         // if async-upload returned an error message, place it in the media item div and return
    87         if ( serverData.match(/media-upload-error|error-div/) ) {
    88                 item.html(serverData);
    89                 return;
    90         } else {
    91                 jQuery('.percent', item).html( pluploadL10n.crunching );
     87                // if async-upload returned an error message, place it in the media item div and return
     88                if ( /media-upload-error|error-div/.test( serverData ) ) {
     89                        item.html( serverData );
     90                        return;
     91                }
    9292        }
    9393
    94         prepareMediaItem(fileObj, serverData);
     94        item.find( '.percent' ).html( pluploadL10n.crunching );
     95
     96        prepareMediaItem( fileObj, serverData );
    9597        updateMediaForm();
    9698
    9799        // Increment the counter.
    98         if ( post_id && item.hasClass('child-of-' + post_id) )
    99                 jQuery('#attachments-count').text(1 * jQuery('#attachments-count').text() + 1);
     100        if ( post_id && item.hasClass( 'child-of-' + post_id ) ) {
     101                jQuery( '#attachments-count' ).text( 1 * jQuery( '#attachments-count' ).text() + 1 );
     102        }
    100103}
    101104
    102105function setResize( arg ) {
     
    116119        }
    117120}
    118121
    119 function prepareMediaItem(fileObj, serverData) {
    120         var f = ( typeof shortform == 'undefined' ) ? 1 : 2, item = jQuery('#media-item-' + fileObj.id);
     122function prepareMediaItem( fileObj, serverData ) {
     123        var f = ( typeof shortform == 'undefined' ) ? 1 : 2, item = jQuery( '#media-item-' + fileObj.id );
    121124        if ( f == 2 && shortform > 2 )
    122125                f = shortform;
    123126
    124127        try {
    125128                if ( typeof topWin.tb_remove != 'undefined' )
    126                         topWin.jQuery('#TB_overlay').click(topWin.tb_remove);
    127         } catch(e){}
     129                        topWin.jQuery( '#TB_overlay' ).click( topWin.tb_remove );
     130        } catch( e ){}
    128131
    129         if ( isNaN(serverData) || !serverData ) { // Old style: Append the HTML returned by the server -- thumbnail and form inputs
    130                 item.append(serverData);
    131                 prepareMediaItemInit(fileObj);
     132        if ( isNaN( serverData ) || !serverData ) { // Old style: Append the HTML returned by the server -- thumbnail and form inputs
     133                item.append( serverData );
     134                prepareMediaItemInit( fileObj );
    132135        } else { // New style: server data is just the attachment ID, fetch the thumbnail and form html from the server
    133                 item.load('async-upload.php', {attachment_id:serverData, fetch:f}, function(){prepareMediaItemInit(fileObj);updateMediaForm();});
     136                item.load( 'async-upload.php', {attachment_id:serverData, fetch:f}, function(){prepareMediaItemInit( fileObj );updateMediaForm();});
    134137        }
    135138}
    136139
    137 function prepareMediaItemInit(fileObj) {
    138         var item = jQuery('#media-item-' + fileObj.id);
     140function prepareMediaItemInit( fileObj ) {
     141        var item = jQuery( '#media-item-' + fileObj.id );
    139142        // Clone the thumbnail as a "pinkynail" -- a tiny image to the left of the filename
    140         jQuery('.thumbnail', item).clone().attr('class', 'pinkynail toggle').prependTo(item);
     143        jQuery( '.thumbnail', item ).clone().attr( 'class', 'pinkynail toggle' ).prependTo( item );
    141144
    142145        // Replace the original filename with the new (unique) one assigned during upload
    143         jQuery('.filename.original', item).replaceWith( jQuery('.filename.new', item) );
     146        jQuery( '.filename.original', item ).replaceWith( jQuery( '.filename.new', item ) );
    144147
    145148        // Bind AJAX to the new Delete button
    146         jQuery('a.delete', item).click(function(){
     149        jQuery( 'a.delete', item ).click( function(){
    147150                // Tell the server to delete it. TODO: handle exceptions
    148151                jQuery.ajax({
    149152                        url: ajaxurl,
     
    152155                        error: deleteError,
    153156                        id: fileObj.id,
    154157                        data: {
    155                                 id : this.id.replace(/[^0-9]/g, ''),
     158                                id : this.id.replace(/[^0-9]/g, '' ),
    156159                                action : 'trash-post',
    157                                 _ajax_nonce : this.href.replace(/^.*wpnonce=/,'')
     160                                _ajax_nonce : this.href.replace(/^.*wpnonce=/,'' )
    158161                        }
    159162                });
    160163                return false;
     
    161164        });
    162165
    163166        // Bind AJAX to the new Undo button
    164         jQuery('a.undo', item).click(function(){
     167        jQuery( 'a.undo', item ).click( function(){
    165168                // Tell the server to untrash it. TODO: handle exceptions
    166169                jQuery.ajax({
    167170                        url: ajaxurl,
     
    168171                        type: 'post',
    169172                        id: fileObj.id,
    170173                        data: {
    171                                 id : this.id.replace(/[^0-9]/g,''),
     174                                id : this.id.replace(/[^0-9]/g,'' ),
    172175                                action: 'untrash-post',
    173                                 _ajax_nonce: this.href.replace(/^.*wpnonce=/,'')
     176                                _ajax_nonce: this.href.replace(/^.*wpnonce=/,'' )
    174177                        },
    175178                        success: function( ){
    176179                                var type,
    177                                         item = jQuery('#media-item-' + fileObj.id);
     180                                        item = jQuery( '#media-item-' + fileObj.id );
    178181
    179                                 if ( type = jQuery('#type-of-' + fileObj.id).val() )
    180                                         jQuery('#' + type + '-counter').text(jQuery('#' + type + '-counter').text()-0+1);
     182                                if ( type = jQuery( '#type-of-' + fileObj.id ).val() )
     183                                        jQuery( '#' + type + '-counter' ).text( jQuery( '#' + type + '-counter' ).text()-0+1 );
    181184
    182                                 if ( post_id && item.hasClass('child-of-'+post_id) )
    183                                         jQuery('#attachments-count').text(jQuery('#attachments-count').text()-0+1);
     185                                if ( post_id && item.hasClass( 'child-of-'+post_id ) )
     186                                        jQuery( '#attachments-count' ).text( jQuery( '#attachments-count' ).text()-0+1 );
    184187
    185                                 jQuery('.filename .trashnotice', item).remove();
    186                                 jQuery('.filename .title', item).css('font-weight','normal');
    187                                 jQuery('a.undo', item).addClass('hidden');
    188                                 jQuery('.menu_order_input', item).show();
    189                                 item.css( {backgroundColor:'#ceb'} ).animate( {backgroundColor: '#fff'}, { queue: false, duration: 500, complete: function(){ jQuery(this).css({backgroundColor:''}); } }).removeClass('undo');
     188                                jQuery( '.filename .trashnotice', item ).remove();
     189                                jQuery( '.filename .title', item ).css( 'font-weight','normal' );
     190                                jQuery( 'a.undo', item ).addClass( 'hidden' );
     191                                jQuery( '.menu_order_input', item ).show();
     192                                item.css( {backgroundColor:'#ceb'} ).animate( {backgroundColor: '#fff'}, { queue: false, duration: 500, complete: function(){ jQuery( this ).css({backgroundColor:''}); } }).removeClass( 'undo' );
    190193                        }
    191194                });
    192195                return false;
     
    193196        });
    194197
    195198        // Open this item if it says to start open (e.g. to display an error)
    196         jQuery('#media-item-' + fileObj.id + '.startopen').removeClass('startopen').addClass('open').find('slidetoggle').fadeIn();
     199        jQuery( '#media-item-' + fileObj.id + '.startopen' ).removeClass( 'startopen' ).addClass( 'open' ).find( 'slidetoggle' ).fadeIn();
    197200}
    198201
    199202// generic error message
    200 function wpQueueError(message) {
    201         jQuery('#media-upload-error').show().html( '<div class="error"><p>' + message + '</p></div>' );
     203function wpQueueError( message ) {
     204        jQuery( '#media-upload-error' ).show().html( '<div class="error"><p>' + message + '</p></div>' );
    202205}
    203206
    204207// file-specific error messages
    205 function wpFileError(fileObj, message) {
    206         itemAjaxError(fileObj.id, message);
     208function wpFileError( fileObj, message ) {
     209        itemAjaxError( fileObj.id, message );
    207210}
    208211
    209 function itemAjaxError(id, message) {
    210         var item = jQuery('#media-item-' + id), filename = item.find('.filename').text(), last_err = item.data('last-err');
     212function itemAjaxError( id, message ) {
     213        var item = jQuery( '#media-item-' + id ), filename = item.find( '.filename' ).text(), last_err = item.data( 'last-err' );
    211214
    212215        if ( last_err == id ) // prevent firing an error for the same file twice
    213216                return;
    214217
    215         item.html('<div class="error-div">' +
     218        item.html( '<div class="error-div">' +
    216219                                '<a class="dismiss" href="#">' + pluploadL10n.dismiss + '</a>' +
    217                                 '<strong>' + pluploadL10n.error_uploading.replace('%s', jQuery.trim(filename)) + '</strong> ' +
     220                                '<strong>' + pluploadL10n.error_uploading.replace( '%s', jQuery.trim( filename )) + '</strong> ' +
    218221                                message +
    219                                 '</div>').data('last-err', id);
     222                                '</div>' ).data( 'last-err', id );
    220223}
    221224
    222 function deleteSuccess(data) {
     225function deleteSuccess( data ) {
    223226        var type, id, item;
    224227        if ( data == '-1' )
    225                 return itemAjaxError(this.id, 'You do not have permission. Has your session expired?');
     228                return itemAjaxError( this.id, 'You do not have permission. Has your session expired?' );
    226229
    227230        if ( data == '0' )
    228                 return itemAjaxError(this.id, 'Could not be deleted. Has it been deleted already?');
     231                return itemAjaxError( this.id, 'Could not be deleted. Has it been deleted already?' );
    229232
    230233        id = this.id;
    231         item = jQuery('#media-item-' + id);
     234        item = jQuery( '#media-item-' + id );
    232235
    233236        // Decrement the counters.
    234         if ( type = jQuery('#type-of-' + id).val() )
    235                 jQuery('#' + type + '-counter').text( jQuery('#' + type + '-counter').text() - 1 );
     237        if ( type = jQuery( '#type-of-' + id ).val() )
     238                jQuery( '#' + type + '-counter' ).text( jQuery( '#' + type + '-counter' ).text() - 1 );
    236239
    237         if ( post_id && item.hasClass('child-of-'+post_id) )
    238                 jQuery('#attachments-count').text( jQuery('#attachments-count').text() - 1 );
     240        if ( post_id && item.hasClass( 'child-of-'+post_id ) )
     241                jQuery( '#attachments-count' ).text( jQuery( '#attachments-count' ).text() - 1 );
    239242
    240         if ( jQuery('form.type-form #media-items').children().length == 1 && jQuery('.hidden', '#media-items').length > 0 ) {
    241                 jQuery('.toggle').toggle();
    242                 jQuery('.slidetoggle').slideUp(200).siblings().removeClass('hidden');
     243        if ( jQuery( 'form.type-form #media-items' ).children().length == 1 && jQuery( '.hidden', '#media-items' ).length > 0 ) {
     244                jQuery( '.toggle' ).toggle();
     245                jQuery( '.slidetoggle' ).slideUp( 200 ).siblings().removeClass( 'hidden' );
    243246        }
    244247
    245248        // Vanish it.
    246         jQuery('.toggle', item).toggle();
    247         jQuery('.slidetoggle', item).slideUp(200).siblings().removeClass('hidden');
    248         item.css( {backgroundColor:'#faa'} ).animate( {backgroundColor:'#f4f4f4'}, {queue:false, duration:500} ).addClass('undo');
     249        jQuery( '.toggle', item ).toggle();
     250        jQuery( '.slidetoggle', item ).slideUp( 200 ).siblings().removeClass( 'hidden' );
     251        item.css( {backgroundColor:'#faa'} ).animate( {backgroundColor:'#f4f4f4'}, {queue:false, duration:500} ).addClass( 'undo' );
    249252
    250         jQuery('.filename:empty', item).remove();
    251         jQuery('.filename .title', item).css('font-weight','bold');
    252         jQuery('.filename', item).append('<span class="trashnotice"> ' + pluploadL10n.deleted + ' </span>').siblings('a.toggle').hide();
    253         jQuery('.filename', item).append( jQuery('a.undo', item).removeClass('hidden') );
    254         jQuery('.menu_order_input', item).hide();
     253        jQuery( '.filename:empty', item ).remove();
     254        jQuery( '.filename .title', item ).css( 'font-weight','bold' );
     255        jQuery( '.filename', item ).append( '<span class="trashnotice"> ' + pluploadL10n.deleted + ' </span>' ).siblings( 'a.toggle' ).hide();
     256        jQuery( '.filename', item ).append( jQuery( 'a.undo', item ).removeClass( 'hidden' ) );
     257        jQuery( '.menu_order_input', item ).hide();
    255258
    256259        return;
    257260}
    258261
    259262function deleteError() {
    260         // TODO
    261263}
    262264
    263265function uploadComplete() {
    264         jQuery('#insert-gallery').prop('disabled', false);
     266        jQuery( '#insert-gallery' ).prop( 'disabled', false );
    265267}
    266268
    267 function switchUploader(s) {
     269function switchUploader( s ) {
    268270        if ( s ) {
    269                 deleteUserSetting('uploader');
    270                 jQuery('.media-upload-form').removeClass('html-uploader');
     271                deleteUserSetting( 'uploader' );
     272                jQuery( '.media-upload-form' ).removeClass( 'html-uploader' );
    271273
    272                 if ( typeof(uploader) == 'object' )
     274                if ( typeof( uploader ) == 'object' )
    273275                        uploader.refresh();
    274276        } else {
    275                 setUserSetting('uploader', '1'); // 1 == html uploader
    276                 jQuery('.media-upload-form').addClass('html-uploader');
     277                setUserSetting( 'uploader', '1' ); // 1 == html uploader
     278                jQuery( '.media-upload-form' ).addClass( 'html-uploader' );
    277279        }
    278280}
    279281
    280 function uploadError(fileObj, errorCode, message, uploader) {
     282function uploadError( fileObj, errorCode, message, up ) {
    281283        var hundredmb = 100 * 1024 * 1024, max;
    282284
    283         switch (errorCode) {
     285        switch ( errorCode ) {
    284286                case plupload.FAILED:
    285                         wpFileError(fileObj, pluploadL10n.upload_failed);
     287                        wpFileError( fileObj, pluploadL10n.upload_failed );
    286288                        break;
    287289                case plupload.FILE_EXTENSION_ERROR:
    288                         wpFileExtensionError( uploader, fileObj, pluploadL10n.invalid_filetype );
     290                        wpFileExtensionError( up, fileObj, pluploadL10n.invalid_filetype );
    289291                        break;
    290292                case plupload.FILE_SIZE_ERROR:
    291                         uploadSizeError(uploader, fileObj);
     293                        uploadSizeError( up, fileObj );
    292294                        break;
    293295                case plupload.IMAGE_FORMAT_ERROR:
    294                         wpFileError(fileObj, pluploadL10n.not_an_image);
     296                        wpFileError( fileObj, pluploadL10n.not_an_image );
    295297                        break;
    296298                case plupload.IMAGE_MEMORY_ERROR:
    297                         wpFileError(fileObj, pluploadL10n.image_memory_exceeded);
     299                        wpFileError( fileObj, pluploadL10n.image_memory_exceeded );
    298300                        break;
    299301                case plupload.IMAGE_DIMENSIONS_ERROR:
    300                         wpFileError(fileObj, pluploadL10n.image_dimensions_exceeded);
     302                        wpFileError( fileObj, pluploadL10n.image_dimensions_exceeded );
    301303                        break;
    302304                case plupload.GENERIC_ERROR:
    303                         wpQueueError(pluploadL10n.upload_failed);
     305                        wpQueueError( pluploadL10n.upload_failed );
    304306                        break;
    305307                case plupload.IO_ERROR:
    306                         max = parseInt( uploader.settings.filters.max_file_size, 10 );
     308                        max = parseInt( up.settings.filters.max_file_size, 10 );
    307309
    308                         if ( max > hundredmb && fileObj.size > hundredmb )
    309                                 wpFileError( fileObj, pluploadL10n.big_upload_failed.replace('%1$s', '<a class="uploader-html" href="#">').replace('%2$s', '</a>') );
    310                         else
    311                                 wpQueueError(pluploadL10n.io_error);
     310                        if ( max > hundredmb && fileObj.size > hundredmb ) {
     311                                wpFileError( fileObj, pluploadL10n.big_upload_failed.replace( '%1$s', '<a class="uploader-html" href="#">' ).replace( '%2$s', '</a>' ) );
     312                        } else {
     313                                wpQueueError( pluploadL10n.io_error );
     314                        }
     315
    312316                        break;
    313317                case plupload.HTTP_ERROR:
    314                         wpQueueError(pluploadL10n.http_error);
     318                        wpQueueError( pluploadL10n.http_error );
    315319                        break;
    316320                case plupload.INIT_ERROR:
    317                         jQuery('.media-upload-form').addClass('html-uploader');
     321                        jQuery( '.media-upload-form' ).addClass( 'html-uploader' );
    318322                        break;
    319323                case plupload.SECURITY_ERROR:
    320                         wpQueueError(pluploadL10n.security_error);
     324                        wpQueueError( pluploadL10n.security_error );
    321325                        break;
    322326/*              case plupload.UPLOAD_ERROR.UPLOAD_STOPPED:
    323327                case plupload.UPLOAD_ERROR.FILE_CANCELLED:
    324                         jQuery('#media-item-' + fileObj.id).remove();
     328                        jQuery( '#media-item-' + fileObj.id ).remove();
    325329                        break;*/
    326330                default:
    327                         wpFileError(fileObj, pluploadL10n.default_error);
     331                        wpFileError( fileObj, pluploadL10n.default_error );
    328332        }
    329333}
    330334
     
    331335function uploadSizeError( up, file ) {
    332336        var message, errorDiv;
    333337
    334         message = pluploadL10n.file_exceeds_size_limit.replace('%s', file.name);
     338        message = pluploadL10n.file_exceeds_size_limit.replace( '%s', file.name );
    335339
    336340        // Construct the error div.
    337341        errorDiv = jQuery( '<div />' )
     
    345349                );
    346350
    347351        // Append the error.
    348         jQuery('#media-items').append( errorDiv );
    349         up.removeFile(file);
     352        jQuery( '#media-items' ).append( errorDiv );
     353        up.removeFile( file );
    350354}
    351355
    352356function wpFileExtensionError( up, file, message ) {
    353         jQuery('#media-items').append('<div id="media-item-' + file.id + '" class="media-item error"><p>' + message + '</p></div>');
    354         up.removeFile(file);
     357        jQuery( '#media-items' ).append( '<div id="media-item-' + file.id + '" class="media-item error"><p>' + message + '</p></div>' );
     358        up.removeFile( file );
    355359}
    356360
    357 jQuery(document).ready(function($){
    358         $('.media-upload-form').bind('click.uploader', function(e) {
    359                 var target = $(e.target), tr, c;
     361jQuery( document ).ready( function( $ ) {
     362        var tryAgainCount = {};
     363        var tryAgain;
    360364
    361                 if ( target.is('input[type="radio"]') ) { // remember the last used image size and alignment
    362                         tr = target.closest('tr');
     365        $( '.media-upload-form' ).bind( 'click.uploader', function( e ) {
     366                var target = $( e.target ), tr, c;
    363367
    364                         if ( tr.hasClass('align') )
    365                                 setUserSetting('align', target.val());
    366                         else if ( tr.hasClass('image-size') )
    367                                 setUserSetting('imgsize', target.val());
     368                if ( target.is( 'input[type="radio"]' ) ) { // remember the last used image size and alignment
     369                        tr = target.closest( 'tr' );
    368370
    369                 } else if ( target.is('button.button') ) { // remember the last used image link url
     371                        if ( tr.hasClass( 'align' ) )
     372                                setUserSetting( 'align', target.val() );
     373                        else if ( tr.hasClass( 'image-size' ) )
     374                                setUserSetting( 'imgsize', target.val() );
     375
     376                } else if ( target.is( 'button.button' ) ) { // remember the last used image link url
    370377                        c = e.target.className || '';
    371                         c = c.match(/url([^ '"]+)/);
     378                        c = c.match( /url([^ '"]+)/ );
    372379
    373380                        if ( c && c[1] ) {
    374                                 setUserSetting('urlbutton', c[1]);
    375                                 target.siblings('.urlfield').val( target.data('link-url') );
     381                                setUserSetting( 'urlbutton', c[1] );
     382                                target.siblings( '.urlfield' ).val( target.data( 'link-url' ) );
    376383                        }
    377                 } else if ( target.is('a.dismiss') ) {
    378                         target.parents('.media-item').fadeOut(200, function(){
    379                                 $(this).remove();
    380                         });
    381                 } else if ( target.is('.upload-flash-bypass a') || target.is('a.uploader-html') ) { // switch uploader to html4
    382                         $('#media-items, p.submit, span.big-file-warning').css('display', 'none');
    383                         switchUploader(0);
     384                } else if ( target.is( 'a.dismiss' ) ) {
     385                        target.parents( '.media-item' ).fadeOut( 200, function() {
     386                                $( this ).remove();
     387                        } );
     388                } else if ( target.is( '.upload-flash-bypass a' ) || target.is( 'a.uploader-html' ) ) { // switch uploader to html4
     389                        $( '#media-items, p.submit, span.big-file-warning' ).css( 'display', 'none' );
     390                        switchUploader( 0 );
    384391                        e.preventDefault();
    385                 } else if ( target.is('.upload-html-bypass a') ) { // switch uploader to multi-file
    386                         $('#media-items, p.submit, span.big-file-warning').css('display', '');
    387                         switchUploader(1);
     392                } else if ( target.is( '.upload-html-bypass a' ) ) { // switch uploader to multi-file
     393                        $( '#media-items, p.submit, span.big-file-warning' ).css( 'display', '' );
     394                        switchUploader( 1 );
    388395                        e.preventDefault();
    389                 } else if ( target.is('a.describe-toggle-on') ) { // Show
    390                         target.parent().addClass('open');
    391                         target.siblings('.slidetoggle').fadeIn(250, function(){
    392                                 var S = $(window).scrollTop(), H = $(window).height(), top = $(this).offset().top, h = $(this).height(), b, B;
     396                } else if ( target.is( 'a.describe-toggle-on' ) ) { // Show
     397                        target.parent().addClass( 'open' );
     398                        target.siblings( '.slidetoggle' ).fadeIn( 250, function() {
     399                                var S = $( window ).scrollTop(),
     400                                        H = $( window ).height(),
     401                                        top = $( this ).offset().top,
     402                                        h = $( this ).height(),
     403                                        b,
     404                                        B;
    393405
    394406                                if ( H && top && h ) {
    395407                                        b = top + h;
     
    397409
    398410                                        if ( b > B ) {
    399411                                                if ( b - B < top - S )
    400                                                         window.scrollBy(0, (b - B) + 10);
     412                                                        window.scrollBy( 0, ( b - B ) + 10 );
    401413                                                else
    402                                                         window.scrollBy(0, top - S - 40);
     414                                                        window.scrollBy( 0, top - S - 40 );
    403415                                        }
    404416                                }
    405                         });
     417                        } );
     418
    406419                        e.preventDefault();
    407                 } else if ( target.is('a.describe-toggle-off') ) { // Hide
    408                         target.siblings('.slidetoggle').fadeOut(250, function(){
    409                                 target.parent().removeClass('open');
    410                         });
     420                } else if ( target.is( 'a.describe-toggle-off' ) ) { // Hide
     421                        target.siblings( '.slidetoggle' ).fadeOut( 250, function() {
     422                                target.parent().removeClass( 'open' );
     423                        } );
     424
    411425                        e.preventDefault();
    412426                }
    413427        });
    414428
    415         // init and set the uploader
    416         uploader_init = function() {
    417                 var isIE = navigator.userAgent.indexOf('Trident/') != -1 || navigator.userAgent.indexOf('MSIE ') != -1;
     429        // Attempt to create image sub-sizes when an image was uploaded successfully
     430        // but the server responded with HTTP 500 error.
     431        tryAgain = function( up, error ) {
     432                var file = error.file;
     433                var times;
     434                var message;
    418435
    419                 // Make sure flash sends cookies (seems in IE it does whitout switching to urlstream mode)
    420                 if ( ! isIE && 'flash' === plupload.predictRuntime( wpUploaderInit ) &&
    421                         ( ! wpUploaderInit.required_features || ! wpUploaderInit.required_features.hasOwnProperty( 'send_binary_string' ) ) ) {
     436                if ( ! file || ! file.id ) {
     437                        wpQueueError( error.message || pluploadL10n.http_error );
     438                        return;
     439                }
    422440
    423                         wpUploaderInit.required_features = wpUploaderInit.required_features || {};
    424                         wpUploaderInit.required_features.send_binary_string = true;
     441                times = tryAgainCount[ file.id ];
     442
     443                if ( times && times > 3 ) {
     444                        wpQueueError( error.message || pluploadL10n.http_error );
     445                        return;
    425446                }
    426447
    427                 uploader = new plupload.Uploader(wpUploaderInit);
     448                if ( ! times ) {
     449                        tryAgainCount[ file.id ] = 1;
     450                } else {
     451                        tryAgainCount[ file.id ] = ++times;
     452                }
    428453
    429                 $('#image_resize').bind('change', function() {
    430                         var arg = $(this).prop('checked');
     454                // Try to create the missing image sizes three times.
     455                $.ajax({
     456                        type: 'post',
     457                        url: ajaxurl,
     458                        dataType: 'json',
     459                        data: {
     460                                action: 'media-create-image-subsizes',
     461                                _wpnonce: wpUploaderInit.multipart_params._wpnonce,
     462                                _wp_temp_image_ref: file.id,
     463                                _legasy_support: 'true',
     464                        }
     465                }).done( function( response ) {
     466                        var message;
    431467
     468                        if ( response.success ) {
     469                                uploadSuccess( file, response.data.id );
     470                        } else {
     471                                if ( response.data && response.data.message ) {
     472                                        message = response.data.message;
     473                                } else if ( _.isString( response ) ) {
     474                                        // Can be error message coming from PHP that may have few simple HTML tags. Remove them.
     475                                        message = response.replace( /<\/?[a-zA-Z][^>]*>/g, '' );
     476                                        message = _.escape( message );
     477                                }
     478
     479                                wpQueueError( message || pluploadL10n.http_error );
     480                        }
     481                }).fail( function( jqXHR ) {
     482                        // If another HTTP 500 error, try again up to 3 times.
     483                        if ( jqXHR.status === 500 ) {
     484                                tryAgain( up, error );
     485                                return;
     486                        }
     487
     488                        wpQueueError( jqXHR.responseText || pluploadL10n.http_error );
     489                });
     490        }
     491
     492        // init and set the uploader
     493        uploader_init = function() {
     494                uploader = new plupload.Uploader( wpUploaderInit );
     495
     496                $( '#image_resize' ).bind( 'change', function() {
     497                        var arg = $( this ).prop( 'checked' );
     498
    432499                        setResize( arg );
    433500
    434501                        if ( arg )
    435                                 setUserSetting('upload_resize', '1');
     502                                setUserSetting( 'upload_resize', '1' );
    436503                        else
    437                                 deleteUserSetting('upload_resize');
     504                                deleteUserSetting( 'upload_resize' );
    438505                });
    439506
    440                 uploader.bind('Init', function(up) {
    441                         var uploaddiv = $('#plupload-upload-ui');
     507                uploader.bind( 'Init', function( up ) {
     508                        var uploaddiv = $( '#plupload-upload-ui' );
    442509
    443                         setResize( getUserSetting('upload_resize', false) );
     510                        setResize( getUserSetting( 'upload_resize', false ) );
    444511
    445                         if ( up.features.dragdrop && ! $(document.body).hasClass('mobile') ) {
    446                                 uploaddiv.addClass('drag-drop');
    447                                 $('#drag-drop-area').on('dragover.wp-uploader', function(){ // dragenter doesn't fire right :(
    448                                         uploaddiv.addClass('drag-over');
    449                                 }).on('dragleave.wp-uploader, drop.wp-uploader', function(){
    450                                         uploaddiv.removeClass('drag-over');
     512                        if ( up.features.dragdrop && ! $( document.body ).hasClass( 'mobile' ) ) {
     513                                uploaddiv.addClass( 'drag-drop' );
     514
     515                                $( '#drag-drop-area' ).on( 'dragover.wp-uploader', function() { // dragenter doesn't fire right :(
     516                                        uploaddiv.addClass( 'drag-over' );
     517                                }).on( 'dragleave.wp-uploader, drop.wp-uploader', function() {
     518                                        uploaddiv.removeClass( 'drag-over' );
    451519                                });
    452520                        } else {
    453                                 uploaddiv.removeClass('drag-drop');
    454                                 $('#drag-drop-area').off('.wp-uploader');
     521                                uploaddiv.removeClass( 'drag-drop' );
     522                                $( '#drag-drop-area' ).off( '.wp-uploader' );
    455523                        }
    456524
    457525                        if ( up.runtime === 'html4' ) {
    458                                 $('.upload-flash-bypass').hide();
     526                                $( '.upload-flash-bypass' ).hide();
    459527                        }
    460528                });
    461529
     
    465533
    466534                uploader.init();
    467535
    468                 uploader.bind('FilesAdded', function( up, files ) {
    469                         $('#media-upload-error').empty();
     536                uploader.bind( 'FilesAdded', function( up, files ) {
     537                        $( '#media-upload-error' ).empty();
    470538                        uploadStart();
    471539
    472540                        plupload.each( files, function( file ) {
     
    477545                        up.start();
    478546                });
    479547
    480                 uploader.bind('UploadFile', function(up, file) {
    481                         fileUploading(up, file);
     548                uploader.bind( 'UploadFile', function( up, file ) {
     549                        fileUploading( up, file );
    482550                });
    483551
    484                 uploader.bind('UploadProgress', function(up, file) {
    485                         uploadProgress(up, file);
     552                uploader.bind( 'UploadProgress', function( up, file ) {
     553                        uploadProgress( up, file );
    486554                });
    487555
    488                 uploader.bind('Error', function(up, err) {
    489                         uploadError(err.file, err.code, err.message, up);
     556                uploader.bind( 'Error', function( up, error ) {
     557                        var isImage = error.file && error.file.type && error.file.type.indexOf( 'image/' ) === 0;
     558                        var status  = error && error.status;
     559
     560                        // If the file is an image and the error is HTTP 500 try to create sub-sizes again.
     561                        if ( status === 500 && isImage ) {
     562                                tryAgain( up, error );
     563                                return;
     564                        }
     565
     566                        uploadError( error.file, error.code, error.message, up );
    490567                        up.refresh();
    491568                });
    492569
    493                 uploader.bind('FileUploaded', function(up, file, response) {
    494                         uploadSuccess(file, response.response);
     570                uploader.bind( 'FileUploaded', function( up, file, response ) {
     571                        uploadSuccess( file, response.response );
    495572                });
    496573
    497                 uploader.bind('UploadComplete', function() {
     574                uploader.bind( 'UploadComplete', function() {
    498575                        uploadComplete();
    499576                });
     577
     578                /**
     579                 * When uploading images add a file reference used to retrieve the attachment_id
     580                 * if the uploading fails due to a server timeout of out of memoty error (HTTP 500 errors).
     581                 *
     582                 * @param {plupload.Uploader} up   Uploader instance.
     583                 * @param {plupload.File}     file File for uploading.
     584                 */
     585                uploader.bind( 'BeforeUpload', function( up, file ) {
     586                        if ( file.type && file.type.indexOf( 'image/' ) === 0 ) {
     587                                up.settings.multipart_params._wp_temp_image_ref = file.id;
     588                        } else {
     589                                unset( up.settings.multipart_params._wp_temp_image_ref );
     590                        }
     591                } );
    500592        };
    501593
    502         if ( typeof(wpUploaderInit) == 'object' ) {
     594        if ( typeof( wpUploaderInit ) == 'object' ) {
    503595                uploader_init();
    504596        }
    505597
  • src/js/_enqueues/vendor/plupload/wp-plupload.js

     
    3333         */
    3434        Uploader = function( options ) {
    3535                var self = this,
    36                         isIE = navigator.userAgent.indexOf('Trident/') != -1 || navigator.userAgent.indexOf('MSIE ') != -1,
     36                        isIE, // not used, back-compat
    3737                        elements = {
    3838                                container: 'container',
    3939                                browser:   'browse_button',
    4040                                dropzone:  'drop_element'
    4141                        },
    42                         key, error;
     42                        tryAgainCount = {},
     43                        tryAgain,
     44                        key,
     45                        error,
     46                        fileUploaded;
    4347
    4448                this.supports = {
    4549                        upload: Uploader.browser.supported
     
    9599                        return;
    96100                }
    97101
    98                 // Make sure flash sends cookies (seems in IE it does without switching to urlstream mode)
    99                 if ( ! isIE && 'flash' === plupload.predictRuntime( this.plupload ) &&
    100                         ( ! this.plupload.required_features || ! this.plupload.required_features.hasOwnProperty( 'send_binary_string' ) ) ) {
    101 
    102                         this.plupload.required_features = this.plupload.required_features || {};
    103                         this.plupload.required_features.send_binary_string = true;
    104                 }
    105 
    106102                // Initialize the plupload instance.
    107103                this.uploader = new plupload.Uploader( this.plupload );
    108104                delete this.plupload;
     
    112108                delete this.params;
    113109
    114110                /**
     111                 * Attempt to create image sub-sizes when an image was uploaded successfully
     112                 * but the server responded with HTTP 500 error.
     113                 *
     114                 * @since 5.3.0
     115                 *
     116                 * @param  {string}        message  Error message.
     117                 * @param  {object}        data     Error data from Plupload.
     118                 * @param  {plupload.File} file     File that was uploaded.
     119                 */
     120                tryAgain = function( message, data, file ) {
     121                        var times;
     122
     123                        if ( ! file || ! file.id ) {
     124                                error( message, data, file, false );
     125                                return;
     126                        }
     127
     128                        times = tryAgainCount[ file.id ];
     129
     130                        if ( times && times > 3 ) {
     131                                error( message, data, file, false );
     132                                return;
     133                        }
     134
     135                        if ( ! times ) {
     136                                tryAgainCount[ file.id ] = 1;
     137                        } else {
     138                                tryAgainCount[ file.id ] = ++times;
     139                        }
     140
     141                        // Another request to try to create the missing image sub-sizes.
     142                        $.ajax({
     143                                type: 'post',
     144                                url: ajaxurl,
     145                                dataType: 'json',
     146                                data: {
     147                                        action: 'media-create-image-subsizes',
     148                                        _wpnonce: _wpPluploadSettings.defaults.multipart_params._wpnonce,
     149                                        _wp_temp_image_ref: file.id, // Used to find the new attachment_id.
     150                                }
     151                        }).done( function( response ) {
     152                                var newMessage;
     153
     154                                if ( response.success ) {
     155                                        fileUploaded( self.uploader, file, response );
     156                                } else {
     157                                        if ( response.data && response.data.message ) {
     158                                                newMessage = response.data.message;
     159                                        } else if ( _.isString( response ) ) {
     160                                                // Can be error message coming from PHP that has few simple HTML tags. Remove them.
     161                                                newMessage = response.replace( /<\/?[a-zA-Z][^>]*>/g, '' );
     162                                                newMessage = _.escape( newMessage );
     163                                        }
     164
     165                                        if ( ! newMessage ) {
     166                                                newMessage = message;
     167                                        }
     168
     169                                        error( newMessage, data, file, false );
     170                                }
     171                        }).fail( function( jqXHR ) {
     172                                // If another HTTP 500 error, try again up to 3 times.
     173                                if ( jqXHR.status === 500 ) {
     174                                        tryAgain( message, data, file );
     175                                        return;
     176                                }
     177
     178                                error( message, data, file, false );
     179                        });
     180                }
     181
     182                /**
    115183                 * Custom error callback.
    116184                 *
    117185                 * Add a new error to the errors collection, so other modules can track
    118186                 * and display errors. @see wp.Uploader.errors.
    119187                 *
    120                  * @param  {string}        message
    121                  * @param  {object}        data
     188                 * @param  {string}        message  Error message.
     189                 * @param  {object}        data     Error data from Plupload.
    122190                 * @param  {plupload.File} file     File that was uploaded.
     191                 * @param  {boolean}       retry    Whether to try again to create image sub-sizes.
    123192                 */
    124                 error = function( message, data, file ) {
     193                error = function( message, data, file, retry ) {
     194                        var isImage = file.type && file.type.indexOf( 'image/' ) === 0;
     195                        var status  = data && data.status;
     196
     197                        // If the file is an image and the error is HTTP 500 try to create sub-sizes again.
     198                        if ( retry !== false && status === 500 && isImage ) {
     199                                tryAgain( message, data, file );
     200                                return;
     201                        }
     202
    125203                        if ( file.attachment ) {
    126204                                file.attachment.destroy();
    127205                        }
     
    136214                };
    137215
    138216                /**
     217                 * After a file is successfully uploaded, update its model.
     218                 *
     219                 * @param {plupload.Uploader} up       Uploader instance.
     220                 * @param {plupload.File}     file     File that was uploaded.
     221                 * @param {Object}            response Object with response properties.
     222                 */
     223                fileUploaded = function( up, file, response ) {
     224                        var complete;
     225
     226                        // Remove the "uploading" UI elements
     227                        _.each( ['file','loaded','size','percent'], function( key ) {
     228                                file.attachment.unset( key );
     229                        } );
     230
     231                        file.attachment.set( _.extend( response.data, { uploading: false } ) );
     232
     233                        wp.media.model.Attachment.get( response.data.id, file.attachment );
     234
     235                        complete = Uploader.queue.all( function( attachment ) {
     236                                return ! attachment.get('uploading');
     237                        });
     238
     239                        if ( complete ) {
     240                                Uploader.queue.reset();
     241                        }
     242
     243                        self.success( file.attachment );
     244                }
     245
     246                /**
    139247                 * After the Uploader has been initialized, initialize some behaviors for the dropzone.
    140248                 *
    141249                 * @param {plupload.Uploader} uploader Uploader instance.
     
    203311                }
    204312
    205313                /**
     314                 * When uploading images add a file reference used to retrieve the attachment_id
     315                 * if the uploading fails due to a server timeout of out of memoty (HTTP 500) error.
     316                 *
     317                 * @param {plupload.Uploader} up   Uploader instance.
     318                 * @param {plupload.File}     file File for uploading.
     319                 */
     320                this.uploader.bind( 'BeforeUpload', function( up, file ) {
     321                        if ( file.type && file.type.indexOf( 'image/' ) === 0 ) {
     322                                up.settings.multipart_params._wp_temp_image_ref = file.id;
     323                        } else {
     324                                unset( up.settings.multipart_params._wp_temp_image_ref );
     325                        }
     326                } );
     327
     328                /**
    206329                 * After files were filtered and added to the queue, create a model for each.
    207330                 *
    208                  * @param {plupload.Uploader} uploader Uploader instance.
    209                  * @param {Array}             files    Array of file objects that were added to queue by the user.
     331                 * @param {plupload.Uploader} up    Uploader instance.
     332                 * @param {Array}             files Array of file objects that were added to queue by the user.
    210333                 */
    211334                this.uploader.bind( 'FilesAdded', function( up, files ) {
    212335                        _.each( files, function( file ) {
     
    259382                /**
    260383                 * After a file is successfully uploaded, update its model.
    261384                 *
    262                  * @param {plupload.Uploader} uploader Uploader instance.
     385                 * @param {plupload.Uploader} up      Uploader instance.
    263386                 * @param {plupload.File}     file     File that was uploaded.
    264387                 * @param {Object}            response Object with response properties.
    265388                 * @return {mixed}
    266389                 */
    267390                this.uploader.bind( 'FileUploaded', function( up, file, response ) {
    268                         var complete;
    269391
    270392                        try {
    271393                                response = JSON.parse( response.response );
     
    273395                                return error( pluploadL10n.default_error, e, file );
    274396                        }
    275397
    276                         if ( ! _.isObject( response ) || _.isUndefined( response.success ) )
     398                        if ( ! _.isObject( response ) || _.isUndefined( response.success ) ) {
    277399                                return error( pluploadL10n.default_error, null, file );
    278                         else if ( ! response.success )
     400                        } else if ( ! response.success ) {
    279401                                return error( response.data && response.data.message, response.data, file );
     402                        }
    280403
    281                         _.each(['file','loaded','size','percent'], function( key ) {
    282                                 file.attachment.unset( key );
    283                         });
    284 
    285                         file.attachment.set( _.extend( response.data, { uploading: false }) );
    286                         wp.media.model.Attachment.get( response.data.id, file.attachment );
    287 
    288                         complete = Uploader.queue.all( function( attachment ) {
    289                                 return ! attachment.get('uploading');
    290                         });
    291 
    292                         if ( complete )
    293                                 Uploader.queue.reset();
    294 
    295                         self.success( file.attachment );
     404                        // Success. Update the UI with the new attachment.
     405                        fileUploaded( up, file, response );
    296406                });
    297407
    298408                /**
    299409                 * When plupload surfaces an error, send it to the error handler.
    300410                 *
    301                  * @param {plupload.Uploader} uploader Uploader instance.
    302                  * @param {Object}            error    Contains code, message and sometimes file and other details.
     411                 * @param {plupload.Uploader} up            Uploader instance.
     412                 * @param {Object}            pluploadError Contains code, message and sometimes file and other details.
    303413                 */
    304414                this.uploader.bind( 'Error', function( up, pluploadError ) {
    305415                        var message = pluploadL10n.default_error,
     
    338448                'IMAGE_DIMENSIONS_ERROR': pluploadL10n.image_dimensions_exceeded,
    339449                'GENERIC_ERROR':          pluploadL10n.upload_failed,
    340450                'IO_ERROR':               pluploadL10n.io_error,
    341                 'HTTP_ERROR':             pluploadL10n.http_error,
    342451                'SECURITY_ERROR':         pluploadL10n.security_error,
    343452
    344453                'FILE_SIZE_ERROR': function( file ) {
    345454                        return pluploadL10n.file_exceeds_size_limit.replace('%s', file.name);
     455                },
     456
     457                'HTTP_ERROR': function( file, pluploadError ) {
     458                        return pluploadError.response || pluploadL10n.http_error;
    346459                }
    347460        };
    348461
  • src/js/media/views/uploader/status.js

     
    111111         * @param {Backbone.Model} error
    112112         */
    113113        error: function( error ) {
    114                 this.views.add( '.upload-errors', new wp.media.view.UploaderStatusError({
    115                         filename: this.filename( error.get('file').name ),
    116                         message:  error.get('message')
    117                 }), { at: 0 });
     114                var statusError = new wp.media.view.UploaderStatusError( {
     115                        filename: this.filename( error.get( 'file' ).name ),
     116                        message:  error.get( 'message' )
     117                } );
     118
     119                // TBD: perhaps show additional info here while retrying to create image sub-sizes?
     120                this.views.add( '.upload-errors', statusError, { at: 0 } );
    118121        },
    119122
    120123        dismiss: function() {
  • src/wp-admin/admin-ajax.php

     
    105105        'send-link-to-editor',
    106106        'send-attachment-to-editor',
    107107        'save-attachment-order',
     108        'media-create-image-subsizes',
    108109        'heartbeat',
    109110        'get-revision-diffs',
    110111        'save-user-color-scheme',
  • src/wp-admin/includes/ajax-actions.php

     
    23172317}
    23182318
    23192319/**
     2320 * Ajax handler for creating missing image sub-sizes for just uploaded images.
     2321 *
     2322 * @since 5.3.0
     2323 */
     2324function wp_ajax_media_create_image_subsizes() {
     2325        check_ajax_referer( 'media-form' );
     2326
     2327        if ( ! current_user_can( 'upload_files' ) ) {
     2328                wp_send_json_error( array( 'message' => __( 'Sorry, you are not allowed to upload files.' ) ) );
     2329        }
     2330
     2331        // Using Plupload `file.id` as ref.
     2332        if ( ! empty( $_POST['_wp_temp_image_ref'] ) ) {
     2333                $image_ref = preg_replace( '/[^a-zA-Z0-9_]/', '', $_POST['_wp_temp_image_ref'] );
     2334        } else {
     2335                wp_send_json_error( array( 'message' => __( 'Invalid file reference.' ) ) );
     2336        }
     2337
     2338        // Uploading of images usually fails while creating the sub-sizes, either because of a timeout or out of memory.
     2339        // At this point the file has been uploaded and an attachment post created, but because of the PHP fatal error
     2340        // the cliend doesn't know the attachment ID yet.
     2341        // To be able to find the new attachment_id in these cases we temporarily store an upload reference sent by the client
     2342        // in the original upload request. It is used to save a transient with the attachment_id as value.
     2343        // That reference currently is Plupload's `file.id` but can be any sufficiently random alpha-numeric string.
     2344        $attachment_id = get_transient( '_wp_temp_image_ref:' . $image_ref );
     2345
     2346        if ( empty( $attachment_id ) ) {
     2347                wp_send_json_error( array( 'message' => __( 'Upload failed. Please reload and try again.' ) ) );
     2348        }
     2349
     2350        // This can still be pretty slow and cause timeout or out of memory errors.
     2351        // The js that handles the response would need to also handle HTTP 500 errors.
     2352        wp_update_image_subsizes( $attachment_id );
     2353
     2354        if ( ! empty( $_POST['_legasy_support'] ) ) {
     2355                // The old (inline) uploader. Only needs the attachment_id.
     2356                $response = array( 'id' => $attachment_id );
     2357        } else {
     2358                // Media modal and Media Library grid view.
     2359                $response = wp_prepare_attachment_for_js( $attachment_id );
     2360
     2361                if ( ! $response ) {
     2362                        wp_send_json_error( array( 'message' => __( 'Upload failed.' ) ) );
     2363                }
     2364        }
     2365
     2366        // At this point the image has been uploaded successfully.
     2367        delete_transient( '_wp_temp_image_ref:' . $image_ref );
     2368
     2369        wp_send_json_success( $response );
     2370}
     2371
     2372/**
    23202373 * Ajax handler for uploading attachments
    23212374 *
    23222375 * @since 3.3.0
  • src/wp-admin/includes/media.php

     
    288288
    289289        $time = current_time( 'mysql' );
    290290        $post = get_post( $post_id );
     291
    291292        if ( $post ) {
    292293                // The post date doesn't usually matter for pages, so don't backdate this upload.
    293294                if ( 'page' !== $post->post_type && substr( $post->post_date, 0, 4 ) > 0 ) {
     
    305306        $ext  = pathinfo( $name, PATHINFO_EXTENSION );
    306307        $name = wp_basename( $name, ".$ext" );
    307308
    308         $url     = $file['url'];
    309         $type    = $file['type'];
    310         $file    = $file['file'];
    311         $title   = sanitize_text_field( $name );
    312         $content = '';
    313         $excerpt = '';
     309        $url       = $file['url'];
     310        $type      = $file['type'];
     311        $file      = $file['file'];
     312        $title     = sanitize_text_field( $name );
     313        $content   = '';
     314        $excerpt   = '';
     315        $image_ref = false;
    314316
    315317        if ( preg_match( '#^audio#', $type ) ) {
    316318                $meta = wp_read_audio_metadata( $file );
     
    370372                }
    371373
    372374                // Use image exif/iptc data for title and caption defaults if possible.
    373         } elseif ( 0 === strpos( $type, 'image/' ) ) {
     375        } elseif ( strpos( $type, 'image/' ) === 0 ) {
     376                // Image file reference passed by the uploader.
     377                if ( ! empty( $_POST['_wp_temp_image_ref'] ) ) {
     378                        $image_ref = preg_replace( '/[^a-zA-Z0-9_]/', '', $_POST['_wp_temp_image_ref'] );
     379                }
     380
    374381                $image_meta = wp_read_image_metadata( $file );
     382
    375383                if ( $image_meta ) {
    376384                        if ( trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) {
    377385                                $title = $image_meta['title'];
     
    400408        unset( $attachment['ID'] );
    401409
    402410        // Save the data
    403         $id = wp_insert_attachment( $attachment, $file, $post_id, true );
    404         if ( ! is_wp_error( $id ) ) {
    405                 wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
     411        $attachment_id = wp_insert_attachment( $attachment, $file, $post_id, true );
     412
     413        if ( ! is_wp_error( $attachment_id ) ) {
     414                // If an image, keep the upload reference until all image sub-sizes are created.
     415                if ( $image_ref ) {
     416                        set_transient( '_wp_temp_image_ref:' . $image_ref, $attachment_id, 6 * HOUR_IN_SECONDS );
     417                }
     418
     419                // The image sub-sizes are created during wp_generate_attachment_metadata().
     420                // This is generally slow and may cause timeouts or out of memory errors.
     421                wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $file ) );
     422
     423                // At this point the image is uploaded successfully even if there were specific errors or some sub-sizes were not created.
     424                // The transient is not needed any more.
     425                if ( $image_ref ) {
     426                        delete_transient( '_wp_temp_image_ref:' . $image_ref );
     427                }
    406428        }
    407429
    408         return $id;
    409 
     430        return $attachment_id;
    410431}
    411432
    412433/**
  • src/wp-includes/script-loader.php

     
    11241124                'default_error'             => __( 'An error occurred in the upload. Please try again later.' ),
    11251125                'missing_upload_url'        => __( 'There was a configuration error. Please contact the server administrator.' ),
    11261126                'upload_limit_exceeded'     => __( 'You may only upload 1 file.' ),
    1127                 'http_error'                => __( 'HTTP error.' ),
     1127                'http_error'                => __( 'Unexpected response from the server. The file may have been uploaded successfully. Please check in the Media Library or reload the page.' ),
    11281128                'upload_failed'             => __( 'Upload failed.' ),
    11291129                /* translators: 1: Opening link tag, 2: Closing link tag */
    11301130                'big_upload_failed'         => __( 'Please try uploading this file with the %1$sbrowser uploader%2$s.' ),