4b9d6dc7 by Jeff Balicki

media fix

Signed-off-by: Jeff <jeff@gotenzing.com>
1 parent 8bf74f6c
1 /* This is based on jQuery UI */
2 #regenerate-thumbnails-app .ui-progressbar {
3 height: 2em;
4 text-align: center;
5 overflow: hidden;
6 }
7 #regenerate-thumbnails-app .ui-progressbar .ui-progressbar-value {
8 margin: -1px;
9 height: 100%;
10 transition-duration: 0.5s;
11 }
12 #regenerate-thumbnails-app .ui-widget.ui-widget-content {
13 border: 1px solid #c5dbec;
14 }
15 #regenerate-thumbnails-app .ui-widget-content {
16 border: 1px solid #a6c9e2;
17 background: #fcfdfd url("images/ui-bg_inset-hard_100_fcfdfd_1x100.png") 50% bottom repeat-x;
18 color: #222222;
19 }
20 #regenerate-thumbnails-app .ui-widget-header {
21 border: 1px solid #4297d7;
22 background: #5c9ccc url("images/ui-bg_gloss-wave_55_5c9ccc_500x100.png") 50% 50% repeat-x;
23 color: #ffffff;
24 font-weight: bold;
25 }
26 #regenerate-thumbnails-app .ui-corner-all {
27 border-radius: 5px;
28 }
29 #regenerate-thumbnails-app .ui-corner-left {
30 border-top-left-radius: 5px;
31 border-bottom-left-radius: 5px;
32 }
This diff could not be displayed because it is too large.
1 /*!
2 * Vue.js v2.6.11
3 * (c) 2014-2019 Evan You
4 * Released under the MIT License.
5 */
1 <?php
2 /**
3 * Regenerate Thumbnails: Attachment regenerator class
4 *
5 * @package RegenerateThumbnails
6 * @since 3.0.0
7 */
8
9 /**
10 * Regenerates the thumbnails for a given attachment.
11 *
12 * @since 3.0.0
13 */
14 class RegenerateThumbnails_Regenerator {
15
16 /**
17 * The WP_Post object for the attachment that is being operated on.
18 *
19 * @since 3.0.0
20 *
21 * @var WP_Post
22 */
23 public $attachment;
24
25 /**
26 * The full path to the original image so that it can be passed between methods.
27 *
28 * @since 3.0.0
29 *
30 * @var string
31 */
32 public $fullsizepath;
33
34 /**
35 * An array of thumbnail size(s) that were skipped during regeneration due to already existing.
36 * A class variable is used so that the data can later be used to merge the size(s) back in.
37 *
38 * @since 3.0.0
39 *
40 * @var array
41 */
42 public $skipped_thumbnails = array();
43
44 /**
45 * The metadata for the attachment before the regeneration process starts.
46 *
47 * @since 3.1.6
48 *
49 * @var array
50 */
51 private $old_metadata = array();
52
53 /**
54 * Generates an instance of this class after doing some setup.
55 *
56 * MIME type is purposefully not validated in order to be more future proof and
57 * to avoid duplicating a ton of logic that already exists in WordPress core.
58 *
59 * @since 3.0.0
60 *
61 * @param int $attachment_id Attachment ID to process.
62 *
63 * @return RegenerateThumbnails_Regenerator|WP_Error A new instance of RegenerateThumbnails_Regenerator on success, or WP_Error on error.
64 */
65 public static function get_instance( $attachment_id ) {
66 $attachment = get_post( $attachment_id );
67
68 if ( ! $attachment ) {
69 return new WP_Error(
70 'regenerate_thumbnails_regenerator_attachment_doesnt_exist',
71 __( 'No attachment exists with that ID.', 'regenerate-thumbnails' ),
72 array(
73 'status' => 404,
74 )
75 );
76 }
77
78 // We can only regenerate thumbnails for attachments.
79 if ( 'attachment' !== get_post_type( $attachment ) ) {
80 return new WP_Error(
81 'regenerate_thumbnails_regenerator_not_attachment',
82 __( 'This item is not an attachment.', 'regenerate-thumbnails' ),
83 array(
84 'status' => 400,
85 )
86 );
87 }
88
89 // Don't touch any attachments that are being used as a site icon. Their thumbnails are usually custom cropped.
90 if ( self::is_site_icon( $attachment ) ) {
91 return new WP_Error(
92 'regenerate_thumbnails_regenerator_is_site_icon',
93 __( "This attachment is a site icon and therefore the thumbnails shouldn't be touched.", 'regenerate-thumbnails' ),
94 array(
95 'status' => 415,
96 'attachment' => $attachment,
97 )
98 );
99 }
100
101 return new RegenerateThumbnails_Regenerator( $attachment );
102 }
103
104 /**
105 * The constructor for this class. Don't call this directly, see get_instance() instead.
106 * This is done so that WP_Error objects can be returned during class initiation.
107 *
108 * @since 3.0.0
109 *
110 * @param WP_Post $attachment The WP_Post object for the attachment that is being operated on.
111 */
112 private function __construct( WP_Post $attachment ) {
113 $this->attachment = $attachment;
114 }
115
116 /**
117 * Returns whether the attachment is or was a site icon.
118 *
119 * @since 3.0.0
120 *
121 * @param WP_Post $attachment The WP_Post object for the attachment that is being operated on.
122 *
123 * @return bool Whether the attachment is or was a site icon.
124 */
125 public static function is_site_icon( WP_Post $attachment ) {
126 return ( 'site-icon' === get_post_meta( $attachment->ID, '_wp_attachment_context', true ) );
127 }
128
129 /**
130 * Get the path to the fullsize attachment.
131 *
132 * @return string|WP_Error The path to the fullsize attachment, or a WP_Error object on error.
133 */
134 public function get_fullsizepath() {
135 if ( $this->fullsizepath ) {
136 return $this->fullsizepath;
137 }
138
139
140 $this->fullsizepath = get_attached_file( $this->attachment->ID );
141
142
143 if ( false === $this->fullsizepath || ! file_exists( $this->fullsizepath ) ) {
144 $error = new WP_Error(
145 'regenerate_thumbnails_regenerator_file_not_found',
146 sprintf(
147 /* translators: The relative upload path to the attachment. */
148 __( "The fullsize image file cannot be found in your uploads directory at <code>%s</code>. Without it, new thumbnail images can't be generated.", 'regenerate-thumbnails' ),
149 _wp_relative_upload_path( $this->fullsizepath )
150 ),
151 array(
152 'status' => 404,
153 'fullsizepath' => _wp_relative_upload_path( $this->fullsizepath ),
154 'attachment' => $this->attachment,
155 )
156 );
157
158 $this->fullsizepath = $error;
159 }
160
161 return $this->fullsizepath;
162 }
163
164 /**
165 * Regenerate the thumbnails for this instance's attachment.
166 *
167 * @since 3.0.0
168 *
169 * @param array|string $args {
170 * Optional. Array or string of arguments for thumbnail regeneration.
171 *
172 * @type bool $only_regenerate_missing_thumbnails Skip regenerating existing thumbnail files. Default true.
173 * @type bool $delete_unregistered_thumbnail_files Delete any thumbnail sizes that are no longer registered. Default false.
174 * }
175 *
176 * @return mixed|WP_Error Metadata for attachment (see wp_generate_attachment_metadata()), or WP_Error on error.
177 */
178 public function regenerate( $args = array() ) {
179 global $wpdb;
180
181 $args = wp_parse_args( $args, array(
182 'only_regenerate_missing_thumbnails' => true,
183 'delete_unregistered_thumbnail_files' => false,
184 ) );
185
186 $fullsizepath = $this->get_fullsizepath();
187 if ( is_wp_error( $fullsizepath ) ) {
188 $fullsizepath->add_data( array( 'attachment' => $this->attachment ) );
189
190 return $fullsizepath;
191 }
192
193 $this->old_metadata = wp_get_attachment_metadata( $this->attachment->ID );
194
195 if ( $args['only_regenerate_missing_thumbnails'] ) {
196 add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10, 2 );
197 }
198
199 require_once( ABSPATH . 'wp-admin/includes/admin.php' );
200 $new_metadata = wp_generate_attachment_metadata( $this->attachment->ID, $fullsizepath );
201
202 if ( $args['only_regenerate_missing_thumbnails'] ) {
203 // Thumbnail sizes that existed were removed and need to be added back to the metadata.
204 foreach ( $this->skipped_thumbnails as $skipped_thumbnail ) {
205 if ( ! empty( $this->old_metadata['sizes'][ $skipped_thumbnail ] ) ) {
206 $new_metadata['sizes'][ $skipped_thumbnail ] = $this->old_metadata['sizes'][ $skipped_thumbnail ];
207 }
208 }
209 $this->skipped_thumbnails = array();
210
211 remove_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10 );
212 }
213
214 $wp_upload_dir = dirname( $fullsizepath ) . DIRECTORY_SEPARATOR;
215
216 if ( $args['delete_unregistered_thumbnail_files'] ) {
217 // Delete old sizes that are still in the metadata.
218 $intermediate_image_sizes = get_intermediate_image_sizes();
219 foreach ( $this->old_metadata['sizes'] as $old_size => $old_size_data ) {
220 if ( in_array( $old_size, $intermediate_image_sizes ) ) {
221 continue;
222 }
223
224 wp_delete_file( $wp_upload_dir . $old_size_data['file'] );
225
226 unset( $new_metadata['sizes'][ $old_size ] );
227 }
228
229 $relative_path = dirname( $new_metadata['file'] ) . DIRECTORY_SEPARATOR;
230
231 // It's possible to upload an image with a filename like image-123x456.jpg and it shouldn't be deleted.
232 $whitelist = $wpdb->get_col( $wpdb->prepare( "
233 SELECT
234 meta_value
235 FROM
236 {$wpdb->postmeta}
237 WHERE
238 meta_key = '_wp_attached_file'
239 AND meta_value REGEXP %s
240 /* Regenerate Thumbnails */
241 ",
242 '^' . preg_quote( $relative_path ) . '[^' . preg_quote( DIRECTORY_SEPARATOR ) . ']+-[0-9]+x[0-9]+\.'
243 ) );
244 $whitelist = array_map( 'basename', $whitelist );
245
246 $filelist = array();
247 foreach ( scandir( $wp_upload_dir ) as $file ) {
248 if ( '.' == $file || '..' == $file || ! is_file( $wp_upload_dir . $file ) ) {
249 continue;
250 }
251
252 $filelist[] = $file;
253 }
254
255 $registered_thumbnails = array();
256 foreach ( $new_metadata['sizes'] as $size ) {
257 $registered_thumbnails[] = $size['file'];
258 }
259
260 $fullsize_parts = pathinfo( $fullsizepath );
261
262 foreach ( $filelist as $file ) {
263 if ( in_array( $file, $whitelist ) || in_array( $file, $registered_thumbnails ) ) {
264 continue;
265 }
266
267 if ( ! preg_match( '#^' . preg_quote( $fullsize_parts['filename'], '#' ) . '-[0-9]+x[0-9]+\.' . preg_quote( $fullsize_parts['extension'], '#' ) . '$#', $file ) ) {
268 continue;
269 }
270
271 wp_delete_file( $wp_upload_dir . $file );
272 }
273 } elseif ( ! empty( $this->old_metadata ) && ! empty( $this->old_metadata['sizes'] ) && is_array( $this->old_metadata['sizes'] ) ) {
274 // If not deleting, rename any size conflicts to avoid them being lost if the file still exists.
275 foreach ( $this->old_metadata['sizes'] as $old_size => $old_size_data ) {
276 if ( empty( $new_metadata['sizes'][ $old_size ] ) ) {
277 $new_metadata['sizes'][ $old_size ] = $this->old_metadata['sizes'][ $old_size ];
278 continue;
279 }
280
281 $new_size_data = $new_metadata['sizes'][ $old_size ];
282
283 if (
284 $new_size_data['width'] !== $old_size_data['width']
285 && $new_size_data['height'] !== $old_size_data['height']
286 && file_exists( $wp_upload_dir . $old_size_data['file'] )
287 ) {
288 $new_metadata['sizes'][ $old_size . '_old_' . $old_size_data['width'] . 'x' . $old_size_data['height'] ] = $old_size_data;
289 }
290 }
291 }
292
293 wp_update_attachment_metadata( $this->attachment->ID, $new_metadata );
294
295 return $new_metadata;
296 }
297
298 /**
299 * Filters the list of thumbnail sizes to only include those which have missing files.
300 *
301 * @since 3.0.0
302 *
303 * @param array $sizes An associative array of registered thumbnail image sizes.
304 * @param array $fullsize_metadata An associative array of fullsize image metadata: width, height, file.
305 *
306 * @return array An associative array of image sizes.
307 */
308 public function filter_image_sizes_to_only_missing_thumbnails( $sizes, $fullsize_metadata ) {
309 if ( ! $sizes ) {
310 return $sizes;
311 }
312
313 $fullsizepath = $this->get_fullsizepath();
314 if ( is_wp_error( $fullsizepath ) ) {
315 return $sizes;
316 }
317
318 $editor = wp_get_image_editor( $fullsizepath );
319 if ( is_wp_error( $editor ) ) {
320 return $sizes;
321 }
322
323 $metadata = $this->old_metadata;
324
325 // This is based on WP_Image_Editor_GD::multi_resize() and others.
326 foreach ( $sizes as $size => $size_data ) {
327 if ( empty( $metadata['sizes'][ $size ] ) ) {
328 continue;
329 }
330
331 if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) {
332 continue;
333 }
334
335 if ( ! isset( $size_data['width'] ) ) {
336 $size_data['width'] = null;
337 }
338 if ( ! isset( $size_data['height'] ) ) {
339 $size_data['height'] = null;
340 }
341
342 if ( ! isset( $size_data['crop'] ) ) {
343 $size_data['crop'] = false;
344 }
345
346 $thumbnail = $this->get_thumbnail(
347 $editor,
348 $fullsize_metadata['width'],
349 $fullsize_metadata['height'],
350 $size_data['width'],
351 $size_data['height'],
352 $size_data['crop']
353 );
354
355
356 // The false check filters out thumbnails that would be larger than the fullsize image.
357 // The size comparison makes sure that the size is also correct.
358 if (
359 false === $thumbnail
360 || (
361 $thumbnail['width'] === $metadata['sizes'][ $size ]['width']
362 && $thumbnail['height'] === $metadata['sizes'][ $size ]['height']
363 && file_exists( $thumbnail['filename'] )
364 )
365 ) {
366 $this->skipped_thumbnails[] = $size;
367 unset( $sizes[ $size ] );
368 }
369 }
370
371 /**
372 * Filters the list of missing thumbnail sizes if you want to add/remove any.
373 *
374 * @since 3.1.0
375 *
376 * @param array $sizes An associative array of image sizes that are missing.
377 * @param array $fullsize_metadata An associative array of fullsize image metadata: width, height, file.
378 * @param object $this The current instance of this class.
379 *
380 * @return array An associative array of image sizes.
381 */
382 return apply_filters( 'regenerate_thumbnails_missing_thumbnails', $sizes, $fullsize_metadata, $this );
383 }
384
385 /**
386 * Generate the thumbnail filename and dimensions for a given set of constraint dimensions.
387 *
388 * @since 3.0.0
389 *
390 * @param WP_Image_Editor|WP_Error $editor An instance of WP_Image_Editor, as returned by wp_get_image_editor().
391 * @param int $fullsize_width The width of the fullsize image.
392 * @param int $fullsize_height The height of the fullsize image.
393 * @param int $thumbnail_width The width of the thumbnail.
394 * @param int $thumbnail_height The height of the thumbnail.
395 * @param bool $crop Whether to crop or not.
396 *
397 * @return array|false An array of the filename, thumbnail width, and thumbnail height,
398 * or false on failure to resize such as the thumbnail being larger than the fullsize image.
399 */
400 public function get_thumbnail( $editor, $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop ) {
401 $dims = image_resize_dimensions( $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop );
402
403 if ( ! $dims ) {
404 return false;
405 }
406
407 list( , , , , $dst_w, $dst_h ) = $dims;
408
409 $suffix = "{$dst_w}x{$dst_h}";
410 $file_ext = strtolower( pathinfo( $this->get_fullsizepath(), PATHINFO_EXTENSION ) );
411
412 return array(
413 'filename' => $editor->generate_filename( $suffix, null, $file_ext ),
414 'width' => $dst_w,
415 'height' => $dst_h,
416 );
417 }
418
419 /**
420 * Update the post content of any public post types (posts and pages by default)
421 * that make use of this attachment.
422 *
423 * @since 3.0.0
424 *
425 * @param array|string $args {
426 * Optional. Array or string of arguments for controlling the updating.
427 *
428 * @type array $post_type The post types to update. Defaults to public post types (posts and pages by default).
429 * @type array $post_ids Specific post IDs to update as opposed to any that uses the attachment.
430 * @type int $posts_per_loop How many posts to query at a time to keep memory usage down. You shouldn't need to modify this.
431 * }
432 *
433 * @return array|WP_Error List of post IDs that were modified. The key is the post ID and the value is either the post ID again or a WP_Error object if wp_update_post() failed.
434 */
435 public function update_usages_in_posts( $args = array() ) {
436 // Temporarily disabled until it can be even better tested for edge cases
437 return array();
438
439 $args = wp_parse_args( $args, array(
440 'post_type' => array(),
441 'post_ids' => array(),
442 'posts_per_loop' => 10,
443 ) );
444
445 if ( empty( $args['post_type'] ) ) {
446 $args['post_type'] = array_values( get_post_types( array( 'public' => true ) ) );
447 unset( $args['post_type']['attachment'] );
448 }
449
450 $offset = 0;
451 $posts_updated = array();
452
453 while ( true ) {
454 $posts = get_posts( array(
455 'numberposts' => $args['posts_per_loop'],
456 'offset' => $offset,
457 'orderby' => 'ID',
458 'order' => 'ASC',
459 'include' => $args['post_ids'],
460 'post_type' => $args['post_type'],
461 's' => 'wp-image-' . $this->attachment->ID,
462
463 // For faster queries.
464 'update_post_meta_cache' => false,
465 'update_post_term_cache' => false,
466 ) );
467
468 if ( ! $posts ) {
469 break;
470 }
471
472 $offset += $args['posts_per_loop'];
473
474 foreach ( $posts as $post ) {
475 $content = $post->post_content;
476 $search = array();
477 $replace = array();
478
479 // Find all <img> tags for this attachment and update them.
480 preg_match_all(
481 '#<img [^>]+wp-image-' . $this->attachment->ID . '[^>]+/>#i',
482 $content,
483 $matches,
484 PREG_SET_ORDER
485 );
486 if ( $matches ) {
487 foreach ( $matches as $img_tag ) {
488 preg_match( '# class="([^"]+)?size-([^" ]+)#i', $img_tag[0], $thumbnail_size );
489
490 if ( $thumbnail_size ) {
491 $thumbnail = image_downsize( $this->attachment->ID, $thumbnail_size[2] );
492
493 if ( ! $thumbnail ) {
494 continue;
495 }
496
497 $search[] = $img_tag[0];
498
499 $img_tag[0] = preg_replace( '# src="[^"]+"#i', ' src="' . esc_url( $thumbnail[0] ) . '"', $img_tag[0] );
500 $img_tag[0] = preg_replace(
501 '# width="[^"]+" height="[^"]+"#i',
502 ' width="' . esc_attr( $thumbnail[1] ) . '" height="' . esc_attr( $thumbnail[2] ) . '"',
503 $img_tag[0]
504 );
505
506 $replace[] = $img_tag[0];
507 }
508 }
509 }
510 $content = str_replace( $search, $replace, $content );
511 $search = array();
512 $replace = array();
513
514 // Update the width in any [caption] shortcodes.
515 preg_match_all(
516 '#\[caption id="attachment_' . $this->attachment->ID . '"([^\]]+)? width="[^"]+"\]([^\[]+)size-([^" ]+)([^\[]+)\[\/caption\]#i',
517 $content,
518 $matches,
519 PREG_SET_ORDER
520 );
521 if ( $matches ) {
522 foreach ( $matches as $match ) {
523 $thumbnail = image_downsize( $this->attachment->ID, $match[3] );
524
525 if ( ! $thumbnail ) {
526 continue;
527 }
528
529 $search[] = $match[0];
530 $replace[] = '[caption id="attachment_' . $this->attachment->ID . '"' . $match[1] . ' width="' . esc_attr( $thumbnail[1] ) . '"]' . $match[2] . 'size-' . $match[3] . $match[4] . '[/caption]';
531 }
532 }
533 $content = str_replace( $search, $replace, $content );
534
535 $updated_post_object = (object) array(
536 'ID' => $post->ID,
537 'post_content' => $content,
538 );
539
540 $posts_updated[ $post->ID ] = wp_update_post( $updated_post_object, true );
541 }
542 }
543
544 return $posts_updated;
545 }
546
547 /**
548 * Returns information about the current attachment for use in the REST API.
549 *
550 * @since 3.0.0
551 *
552 * @return array|WP_Error The attachment name, fullsize URL, registered thumbnail size status, and any unregistered sizes, or WP_Error on error.
553 */
554 public function get_attachment_info() {
555 $fullsizepath = $this->get_fullsizepath();
556 if ( is_wp_error( $fullsizepath ) ) {
557 $fullsizepath->add_data( array( 'attachment' => $this->attachment ) );
558
559 return $fullsizepath;
560 }
561
562 $editor = wp_get_image_editor( $fullsizepath );
563 if ( is_wp_error( $editor ) ) {
564 // Display a more helpful error message.
565 if ( 'image_no_editor' === $editor->get_error_code() ) {
566 $editor = new WP_Error( 'image_no_editor', __( 'The current image editor cannot process this file type.', 'regenerate-thumbnails' ) );
567 }
568
569 $editor->add_data( array(
570 'attachment' => $this->attachment,
571 'status' => 415,
572 ) );
573
574 return $editor;
575 }
576
577 $metadata = wp_get_attachment_metadata( $this->attachment->ID );
578
579 if ( false === $metadata || ! is_array( $metadata ) ) {
580 return new WP_Error(
581 'regenerate_thumbnails_regenerator_no_metadata',
582 __( 'Unable to load the metadata for this attachment.', 'regenerate-thumbnails' ),
583 array(
584 'status' => 404,
585 'attachment' => $this->attachment,
586 )
587 );
588 }
589
590 if ( ! isset( $metadata['sizes'] ) ) {
591 $metadata['sizes'] = array();
592 }
593
594 // PDFs don't have width/height set.
595 $width = ( isset( $metadata['width'] ) ) ? $metadata['width'] : null;
596 $height = ( isset( $metadata['height'] ) ) ? $metadata['height'] : null;
597
598 require_once( ABSPATH . '/wp-admin/includes/image.php' );
599
600 $preview = false;
601 if ( file_is_displayable_image( $fullsizepath ) ) {
602 $preview = wp_get_attachment_url( $this->attachment->ID );
603 } elseif (
604 is_array( $metadata['sizes'] ) &&
605 is_array( $metadata['sizes']['full'] ) &&
606 ! empty( $metadata['sizes']['full']['file'] )
607 ) {
608 $preview = str_replace(
609 wp_basename( $fullsizepath ),
610 $metadata['sizes']['full']['file'],
611 wp_get_attachment_url( $this->attachment->ID )
612 );
613
614 if ( ! file_exists( $preview ) ) {
615 $preview = false;
616 }
617 }
618
619 $response = array(
620 'name' => ( $this->attachment->post_title ) ? $this->attachment->post_title : sprintf( __( 'Attachment %d', 'regenerate-thumbnails' ), $this->attachment->ID ),
621 'preview' => $preview,
622 'relative_path' => _wp_get_attachment_relative_path( $fullsizepath ) . DIRECTORY_SEPARATOR . wp_basename( $fullsizepath ),
623 'edit_url' => get_edit_post_link( $this->attachment->ID, 'raw' ),
624 'width' => $width,
625 'height' => $height,
626 'registered_sizes' => array(),
627 'unregistered_sizes' => array(),
628 );
629
630 $wp_upload_dir = dirname( $fullsizepath ) . DIRECTORY_SEPARATOR;
631
632 $registered_sizes = RegenerateThumbnails()->get_thumbnail_sizes();
633
634 if ( 'application/pdf' === get_post_mime_type( $this->attachment ) ) {
635 $registered_sizes = array_intersect_key(
636 $registered_sizes,
637 array(
638 'thumbnail' => true,
639 'medium' => true,
640 'large' => true,
641 )
642 );
643 }
644
645 // Check the status of all currently registered sizes.
646 foreach ( $registered_sizes as $size ) {
647 // Width and height are needed to generate the thumbnail filename.
648 if ( $width && $height ) {
649 $thumbnail = $this->get_thumbnail( $editor, $width, $height, $size['width'], $size['height'], $size['crop'] );
650
651 if ( $thumbnail ) {
652 $size['filename'] = wp_basename( $thumbnail['filename'] );
653 $size['fileexists'] = file_exists( $thumbnail['filename'] );
654 } else {
655 $size['filename'] = false;
656 $size['fileexists'] = false;
657 }
658 } elseif ( ! empty( $metadata['sizes'][ $size['label'] ]['file'] ) ) {
659 $size['filename'] = wp_basename( $metadata['sizes'][ $size['label'] ]['file'] );
660 $size['fileexists'] = file_exists( $wp_upload_dir . $metadata['sizes'][ $size['label'] ]['file'] );
661 } else {
662 $size['filename'] = false;
663 $size['fileexists'] = false;
664 }
665
666 $response['registered_sizes'][] = $size;
667 }
668
669 if ( ! $width && ! $height && is_array( $metadata['sizes']['full'] ) ) {
670 $response['registered_sizes'][] = array(
671 'label' => 'full',
672 'width' => $metadata['sizes']['full']['width'],
673 'height' => $metadata['sizes']['full']['height'],
674 'filename' => $metadata['sizes']['full']['file'],
675 'fileexists' => file_exists( $wp_upload_dir . $metadata['sizes']['full']['file'] ),
676 );
677 }
678
679 // Look at the attachment metadata and see if we have any extra files from sizes that are no longer registered.
680 foreach ( $metadata['sizes'] as $label => $size ) {
681 if ( ! file_exists( $wp_upload_dir . $size['file'] ) ) {
682 continue;
683 }
684
685 // An unregistered size could match a registered size's dimensions. Ignore these.
686 foreach ( $response['registered_sizes'] as $registered_size ) {
687 if ( $size['file'] === $registered_size['filename'] ) {
688 continue 2;
689 }
690 }
691
692 if ( ! empty( $registered_sizes[ $label ] ) ) {
693 /* translators: Used for listing old sizes of currently registered thumbnails */
694 $label = sprintf( __( '%s (old)', 'regenerate-thumbnails' ), $label );
695 }
696
697 $response['unregistered_sizes'][] = array(
698 'label' => $label,
699 'width' => $size['width'],
700 'height' => $size['height'],
701 'filename' => $size['file'],
702 'fileexists' => true,
703 );
704 }
705
706 return $response;
707 }
708 }
1 <?php
2 /**
3 * Regenerate Thumbnails: REST API controller class
4 *
5 * @package RegenerateThumbnails
6 * @since 3.0.0
7 */
8
9 /**
10 * Registers new REST API endpoints.
11 *
12 * @since 3.0.0
13 */
14 class RegenerateThumbnails_REST_Controller extends WP_REST_Controller {
15 /**
16 * The namespace for the REST API routes.
17 *
18 * @since 3.0.0
19 *
20 * @var string
21 */
22 public $namespace = 'regenerate-thumbnails/v1';
23
24 /**
25 * Register the new routes and endpoints.
26 *
27 * @since 3.0.0
28 */
29 public function register_routes() {
30 register_rest_route( $this->namespace, '/regenerate/(?P<id>[\d]+)', array(
31 array(
32 'methods' => WP_REST_Server::ALLMETHODS,
33 'callback' => array( $this, 'regenerate_item' ),
34 'permission_callback' => array( $this, 'permissions_check' ),
35 'args' => array(
36 'only_regenerate_missing_thumbnails' => array(
37 'description' => __( "Whether to only regenerate missing thumbnails. It's faster with this enabled.", 'regenerate-thumbnails' ),
38 'type' => 'boolean',
39 'default' => true,
40 ),
41 'delete_unregistered_thumbnail_files' => array(
42 'description' => __( 'Whether to delete any old, now unregistered thumbnail files.', 'regenerate-thumbnails' ),
43 'type' => 'boolean',
44 'default' => false,
45 ),
46 'update_usages_in_posts' => array(
47 'description' => __( 'Whether to update the image tags in any posts that make use of this attachment.', 'regenerate-thumbnails' ),
48 'type' => 'boolean',
49 'default' => true,
50 ),
51 'update_usages_in_posts_post_type' => array(
52 'description' => __( 'The types of posts to update. Defaults to all public post types.', 'regenerate-thumbnails' ),
53 'type' => 'array',
54 'default' => array(),
55 'validate_callback' => array( $this, 'is_array' ),
56 ),
57 'update_usages_in_posts_post_ids' => array(
58 'description' => __( 'Specific post IDs to update rather than any posts that use this attachment.', 'regenerate-thumbnails' ),
59 'type' => 'array',
60 'default' => array(),
61 'validate_callback' => array( $this, 'is_array' ),
62 ),
63 'update_usages_in_posts_posts_per_loop' => array(
64 'description' => __( "Posts to process per loop. This is to control memory usage and you likely don't need to adjust this.", 'regenerate-thumbnails' ),
65 'type' => 'integer',
66 'default' => 10,
67 'sanitize_callback' => 'absint',
68 ),
69 ),
70 ),
71 ) );
72
73 register_rest_route( $this->namespace, '/attachmentinfo/(?P<id>[\d]+)', array(
74 array(
75 'methods' => WP_REST_Server::READABLE,
76 'callback' => array( $this, 'attachment_info' ),
77 'permission_callback' => array( $this, 'permissions_check' ),
78 ),
79 ) );
80
81 register_rest_route( $this->namespace, '/featuredimages', array(
82 array(
83 'methods' => WP_REST_Server::READABLE,
84 'callback' => array( $this, 'featured_images' ),
85 'permission_callback' => array( $this, 'permissions_check' ),
86 'args' => $this->get_paging_collection_params(),
87 ),
88 ) );
89 }
90
91 /**
92 * Register a filter to allow excluding site icons via a query parameter.
93 *
94 * @since 3.0.0
95 */
96 public function register_filters() {
97 add_filter( 'rest_attachment_query', array( $this, 'maybe_filter_out_site_icons' ), 10, 2 );
98 add_filter( 'rest_attachment_query', array( $this, 'maybe_filter_mimes_types' ), 10, 2 );
99 }
100
101 /**
102 * If the exclude_site_icons parameter is set on a media (attachment) request,
103 * filter out any attachments that are or were being used as a site icon.
104 *
105 * @param array $args Key value array of query var to query value.
106 * @param WP_REST_Request $request The request used.
107 *
108 * @return array Key value array of query var to query value.
109 */
110 public function maybe_filter_out_site_icons( $args, $request ) {
111 if ( empty( $request['exclude_site_icons'] ) ) {
112 return $args;
113 }
114
115 if ( ! isset( $args['meta_query'] ) ) {
116 $args['meta_query'] = array();
117 }
118
119 $args['meta_query'][] = array(
120 'key' => '_wp_attachment_context',
121 'value' => 'site-icon',
122 'compare' => 'NOT EXISTS',
123 );
124
125 return $args;
126 }
127
128 /**
129 * If the is_regeneratable parameter is set on a media (attachment) request,
130 * filter results to only include images and PDFs.
131 *
132 * @param array $args Key value array of query var to query value.
133 * @param WP_REST_Request $request The request used.
134 *
135 * @return array Key value array of query var to query value.
136 */
137 public function maybe_filter_mimes_types( $args, $request ) {
138 if ( empty( $request['is_regeneratable'] ) ) {
139 return $args;
140 }
141
142 $args['post_mime_type'] = array();
143 foreach ( get_allowed_mime_types() as $mime_type ) {
144 if ( 'image/svg+xml' === $mime_type ) {
145 continue;
146 }
147
148 if ( 'application/pdf' == $mime_type || 'image/' == substr( $mime_type, 0, 6 ) ) {
149 $args['post_mime_type'][] = $mime_type;
150 }
151 }
152
153 return $args;
154 }
155
156 /**
157 * Retrieves the paging query params for the collections.
158 *
159 * @since 3.0.0
160 *
161 * @return array Query parameters for the collection.
162 */
163 public function get_paging_collection_params() {
164 return array_intersect_key(
165 parent::get_collection_params(),
166 array_flip( array( 'page', 'per_page' ) )
167 );
168 }
169
170 /**
171 * Regenerate the thumbnails for a specific media item.
172 *
173 * @since 3.0.0
174 *
175 * @param WP_REST_Request $request Full data about the request.
176 *
177 * @return true|WP_Error True on success, otherwise a WP_Error object.
178 */
179 public function regenerate_item( $request ) {
180 $regenerator = RegenerateThumbnails_Regenerator::get_instance( $request->get_param( 'id' ) );
181
182 if ( is_wp_error( $regenerator ) ) {
183 return $regenerator;
184 }
185
186 $result = $regenerator->regenerate( array(
187 'only_regenerate_missing_thumbnails' => $request->get_param( 'only_regenerate_missing_thumbnails' ),
188 'delete_unregistered_thumbnail_files' => $request->get_param( 'delete_unregistered_thumbnail_files' ),
189 ) );
190
191 if ( is_wp_error( $result ) ) {
192 return $result;
193 }
194
195 if ( $request->get_param( 'update_usages_in_posts' ) ) {
196 $posts_updated = $regenerator->update_usages_in_posts( array(
197 'post_type' => $request->get_param( 'update_usages_in_posts_post_type' ),
198 'post_ids' => $request->get_param( 'update_usages_in_posts_post_ids' ),
199 'posts_per_loop' => $request->get_param( 'update_usages_in_posts_posts_per_loop' ),
200 ) );
201
202 // If wp_update_post() failed for any posts, return that error.
203 foreach ( $posts_updated as $post_updated_result ) {
204 if ( is_wp_error( $post_updated_result ) ) {
205 return $post_updated_result;
206 }
207 }
208 }
209
210 return $this->attachment_info( $request );
211 }
212
213 /**
214 * Return a bunch of information about the current attachment for use in the UI
215 * including details about the thumbnails.
216 *
217 * @since 3.0.0
218 *
219 * @param WP_REST_Request $request Full data about the request.
220 *
221 * @return array|WP_Error The data array or a WP_Error object on error.
222 */
223 public function attachment_info( $request ) {
224 $regenerator = RegenerateThumbnails_Regenerator::get_instance( $request->get_param( 'id' ) );
225
226 if ( is_wp_error( $regenerator ) ) {
227 return $regenerator;
228 }
229
230 return $regenerator->get_attachment_info();
231 }
232
233 /**
234 * Return attachment IDs that are being used as featured images.
235 *
236 * @since 3.0.0
237 *
238 * @param WP_REST_Request $request Full data about the request.
239 *
240 * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
241 */
242 public function featured_images( $request ) {
243 global $wpdb;
244
245 $page = $request->get_param( 'page' );
246 $per_page = $request->get_param( 'per_page' );
247
248 if ( 0 == $per_page ) {
249 $per_page = 10;
250 }
251
252 $featured_image_ids = $wpdb->get_results( $wpdb->prepare(
253 "SELECT SQL_CALC_FOUND_ROWS meta_value AS id FROM {$wpdb->postmeta} WHERE meta_key = '_thumbnail_id' GROUP BY meta_value ORDER BY MIN(meta_id) LIMIT %d OFFSET %d",
254 $per_page,
255 ( $per_page * $page ) - $per_page
256 ) );
257
258 $total = $wpdb->get_var( "SELECT FOUND_ROWS()" );
259 $max_pages = ceil( $total / $per_page );
260
261 if ( $page > $max_pages && $total > 0 ) {
262 return new WP_Error( 'rest_post_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) );
263 }
264
265 $response = rest_ensure_response( $featured_image_ids );
266
267 $response->header( 'X-WP-Total', (int) $total );
268 $response->header( 'X-WP-TotalPages', (int) $max_pages );
269
270 $request_params = $request->get_query_params();
271 $base = add_query_arg( $request_params, rest_url( $this->namespace . '/featuredimages' ) );
272
273 if ( $page > 1 ) {
274 $prev_page = $page - 1;
275
276 if ( $prev_page > $max_pages ) {
277 $prev_page = $max_pages;
278 }
279
280 $prev_link = add_query_arg( 'page', $prev_page, $base );
281 $response->link_header( 'prev', $prev_link );
282 }
283
284 if ( $max_pages > $page ) {
285 $next_page = $page + 1;
286 $next_link = add_query_arg( 'page', $next_page, $base );
287
288 $response->link_header( 'next', $next_link );
289 }
290
291 return $response;
292 }
293
294 /**
295 * Check to see if the current user is allowed to use this endpoint.
296 *
297 * @since 3.0.0
298 *
299 * @param WP_REST_Request $request Full data about the request.
300 *
301 * @return bool Whether the current user has permission to regenerate thumbnails.
302 */
303 public function permissions_check( $request ) {
304 return current_user_can( RegenerateThumbnails()->capability );
305 }
306
307 /**
308 * Returns whether a variable is an array or not. This is needed because 3 arguments are
309 * passed to validation callbacks but is_array() only accepts one argument.
310 *
311 * @since 3.0.0
312 *
313 * @see https://core.trac.wordpress.org/ticket/34659
314 *
315 * @param mixed $param The parameter value to validate.
316 * @param WP_REST_Request $request The REST request.
317 * @param string $key The parameter name.
318 *
319 * @return bool Whether the parameter is an array or not.
320 */
321 public function is_array( $param, $request, $key ) {
322 return is_array( $param );
323 }
324 }
1 !function(a){function b(a){return a=b.buildAjaxOptions(a),b.transport(a)}var c=window.wpApiSettings;b.buildAjaxOptions=function(b){var d,e,f,g,h,i=b.url,j=b.path;if("string"==typeof b.namespace&&"string"==typeof b.endpoint&&(d=b.namespace.replace(/^\/|\/$/g,""),e=b.endpoint.replace(/^\//,""),j=e?d+"/"+e:d),"string"==typeof j&&(i=c.root+j.replace(/^\//,"")),g=!(b.data&&b.data._wpnonce),f=b.headers||{},g)for(h in f)if(f.hasOwnProperty(h)&&"x-wp-nonce"===h.toLowerCase()){g=!1;break}return g&&(f=a.extend({"X-WP-Nonce":c.nonce},f)),b=a.extend({},b,{headers:f,url:i}),delete b.path,delete b.namespace,delete b.endpoint,b},b.transport=a.ajax,window.wp=window.wp||{},window.wp.apiRequest=b}(jQuery);
...\ No newline at end of file ...\ No newline at end of file
1 === Regenerate Thumbnails ===
2 Contributors: Viper007Bond
3 Tags: thumbnail, thumbnails, post thumbnail, post thumbnails
4 Requires at least: 4.7
5 Tested up to: 6.3
6 Requires PHP: 5.2.4
7 Stable tag: 3.1.6
8 License: GPLv2 or later
9 License URI: https://www.gnu.org/licenses/gpl-2.0.html
10
11 Regenerate the thumbnails for one or more of your image uploads. Useful when changing their sizes or your theme.
12
13 == Description ==
14
15 Regenerate Thumbnails allows you to regenerate all thumbnail sizes for one or more images that have been uploaded to your Media Library.
16
17 This is useful for situations such as:
18
19 * A new thumbnail size has been added and you want past uploads to have a thumbnail in that size.
20 * You've changed the dimensions of an existing thumbnail size, for example via Settings → Media.
21 * You've switched to a new WordPress theme that uses featured images of a different size.
22
23 It also offers the ability to delete old, unused thumbnails in order to free up server space.
24
25 = In Memory of Alex Mills =
26
27 In February 2019 Alex Mills, the author of this plugin, [passed away](https://alex.blog/2019/02/27/from-alexs-family/). He leaves behind a number of plugins which will be maintained by Automattic and members of the WordPress community. If this plugin is useful to you please consider donating to the Oregon Health and Science University. You can find more information [here](https://alex.blog/2019/03/13/in-memory-of-alex-donation-link-update/).
28
29 = Alternatives =
30
31 **WP-CLI**
32
33 If you have command line access to your server, I highly recommend using [WP-CLI](https://wp-cli.org/) instead of this plugin as it's faster (no HTTP requests overhead) and can be run inside of a `screen` for those with many thumbnails. For details, see the documentation of its [`media regenerate` command](https://developer.wordpress.org/cli/commands/media/regenerate/).
34
35 **Jetpack's Photon Module**
36
37 [Jetpack](https://jetpack.com/) is a plugin by Automattic, makers of WordPress.com. It gives your self-hosted WordPress site some of the functionality that is available to WordPress.com-hosted sites.
38
39 [The Photon module](https://jetpack.com/support/photon/) makes the images on your site be served from WordPress.com's global content delivery network (CDN) which should speed up the loading of images. Importantly though it can create thumbnails on the fly which means you'll never need to use this plugin.
40
41 I personally use Photon on my own website.
42
43 *Disclaimer: I work for Automattic but I would recommend Photon even if I didn't.*
44
45 = Need Help? Found A Bug? Want To Contribute Code? =
46
47 Support for this plugin is provided via the [WordPress.org forums](https://wordpress.org/support/plugin/regenerate-thumbnails).
48
49 The source code for this plugin is available on [GitHub](https://github.com/automattic/regenerate-thumbnails).
50
51 == Installation ==
52
53 1. Go to your admin area and select Plugins → Add New from the menu.
54 2. Search for "Regenerate Thumbnails".
55 3. Click install.
56 4. Click activate.
57 5. Navigate to Tools → Regenerate Thumbnails.
58
59 == Frequently Asked Questions ==
60
61 = Is this plugin [GDPR](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) compliant? =
62
63 This plugin does not log nor transmit any user data. Infact it doesn't even do anything on the user-facing part of your website, only in the admin area. This means it should be compliant but I'm not a lawyer.
64
65 == Screenshots ==
66
67 1. The main plugin interface.
68 2. Regenerating in progress.
69 3. Interface for regenerating a single attachment.
70 4. Individual images can be regenerated from the media library in list view.
71 5. They can also be regenerated from the edit attachment screen.
72
73 == ChangeLog ==
74
75 = Version 3.1.6 =
76
77 * Fix: Respect "Skip regenerating existing correctly sized thumbnails" setting.
78 * Fix: Don't delete all thumbnails when deleting old unregistered thumbnails size.
79
80 = Version 3.1.5 =
81
82 * Fix: Don't overwrite 'All X Attachment' button label with featured images count.
83 * Tested successfully with PHP 8.1.
84 * Tested successfully with PHP 8.2.
85
86 = Version 3.1.4 =
87
88 * Fix: Don't attempt to regenerate SVG's.
89 * Bump tested version.
90 * Update dependencies.
91
92 = Version 3.1.3 =
93
94 * Update plugin dependencies to the latest version.
95
96 = Version 3.1.2 =
97 * Use wp_get_original_image_path() in WordPress 5.3
98
99 = Version 3.1.1 =
100
101 * Minor fix to avoid a divide by zero error when displaying thumbnail filenames.
102
103 = Version 3.1.0 =
104
105 * Bring back the ability to delete old, unregistered thumbnail sizes. Support for updating post contents is still disabled (too buggy).
106 * Various code improvements including string localization disambiguation.
107
108 = Version 3.0.2 =
109
110 * Fix slowdown in certain cases in the media library.
111 * Fix not being able to regenerate existing thumbnails for single images. Props @idofri.
112 * Fix JavaScript error that could occur if the REST API response was unexpected (empty or PHP error).
113 * Fix bug related to multibyte filenames.
114 * If an image is used as the featured image on multiple posts, only regenerate it once instead of once per post.
115
116 = Version 3.0.1 =
117
118 * Temporarily disable the update post functionality. I tested it a lot but it seems there's still some bugs.
119 * Temporarily disable the delete old thumbnails functionality. It seems to work fine but without the update post functionality, it's not as useful.
120 * Try to more gracefully handle cases where there's missing metadata for attachments.
121 * Wait until `init` to initialize the plugin so themes can filter the plugin's capability. `plugins_loaded` is too early.
122 * Fix a JavaScript error that would cause the whole regeneration process to stop if an individual image returned non-JSON, such as a 500 error code.
123 * Accept GET requests for the regenerate REST API endpoint instead of just POSTs. For some reasons some people's sites are using GET despite the code saying use POST.
124 * Make the attachment ID clickable in error messages.
125 * Fetch 25 attachments at a time instead of 5. I was using 5 for testing.
126 * PHP notice fixes.
127
128 = Version 3.0.0 =
129
130 * Complete rewrite from scratch using Vue.js and the WordPress REST API.
131
132 = Version 2.2.4 =
133
134 * Better AJAX response error handling in the JavaScript. This should fix a long-standing bug in this plugin. Props Hew Sutton.
135
136 = Version 2.2.3 =
137
138 * Make the capability required to use this plugin filterable so themes and other plugins can change it. Props [Jackson Whelan](http://jacksonwhelan.com/).
139
140 = Version 2.2.2 =
141
142 * Don't check the nonce until we're sure that the action called was for this plugin. Fixes lots of "Are you sure you want to do this?" error messages.
143
144 = Version 2.2.1 =
145
146 * Fix the bottom bulk action dropdown. Thanks Stefan for pointing out the issue!
147
148 = Version 2.2.0 =
149
150 * Changes to the Bulk Action functionality were made shortly before the release of WordPress 3.1 which broke the way I implemented the specific multiple image regeneration feature. This version adds to the Bulk Action menu using Javascript as that's the only way to do it currently.
151
152 = Version 2.1.3 =
153
154 * Move the `error_reporting()` call in the AJAX handler to the beginning so that we're more sure that no PHP errors are outputted. Some hosts disable usage of `set_time_limit()` and calling it was causing a PHP warning to be outputted.
155
156 = Version 2.1.2 =
157
158 * When regenerating all images, newest images are done first rather than the oldest.
159 * Fixed a bug with regeneration error reporting in some browsers. Thanks to pete-sch for reporting the error.
160 * Supress PHP errors in the AJAX handler to avoid sending an invalid JSON response. Thanks to pete-sch for reporting the error.
161 * Better and more detailed error reporting for when `wp_generate_attachment_metadata()` fails.
162
163 = Version 2.1.1 =
164
165 * Clean up the wording a bit to better match the new features and just be easier to understand.
166 * Updated screenshots.
167
168 = Version 2.1.0 =
169
170 Lots of new features!
171
172 * Thanks to a lot of jQuery help from [Boris Schapira](http://borisschapira.com/), a failed image regeneration will no longer stop the whole process.
173 * The results of each image regeneration is now outputted. You can easily see which images were successfully regenerated and which failed. Was inspired by a concept by Boris.
174 * There is now a button on the regeneration page that will allow you to abort resizing images for any reason. Based on code by Boris.
175 * You can now regenerate single images from the Media page. The link to do so will show up in the actions list when you hover over the row.
176 * You can now bulk regenerate multiple from the Media page. Check the boxes and then select "Regenerate Thumbnails" form the "Bulk Actions" dropdown. WordPress 3.1+ only.
177 * The total time that the regeneration process took is now displayed in the final status message.
178 * jQuery UI Progressbar version upgraded.
179
180 = Version 2.0.3 =
181
182 * Switch out deprecated function call.
183
184 = Version 2.0.2 =
185
186 * Directly query the database to only fetch what the plugin needs (the attachment ID). This will reduce the memory required as it's not storing the whole row for each attachment.
187
188 = Version 2.0.1 =
189
190 * I accidentally left a `check_admin_referer()` (nonce check) commented out.
191
192 = Version 2.0.0 =
193
194 * Recoded from scratch. Now uses an AJAX request per attachment to do the resizing. No more PHP maximum execution time errors or anything like that. Also features a pretty progress bar to let the user know how it's going.
195
196 = Version 1.1.0 =
197
198 * WordPress 2.7 updates -- code + UI. Thanks to jdub and Patrick F.
199
200 = Version 1.0.0 =
201
202 * Initial release.
203
204 = Upgrade Notice =
205 Support for WordPress 5.3
1 <?php /*
2
3 **************************************************************************
4
5 Plugin Name: Regenerate Thumbnails
6 Description: Regenerate the thumbnails for one or more of your image uploads. Useful when changing their sizes or your theme.
7 Plugin URI: https://alex.blog/wordpress-plugins/regenerate-thumbnails/
8 Version: 3.1.6
9 Author: Alex Mills (Viper007Bond)
10 Author URI: https://alex.blog/
11 Text Domain: regenerate-thumbnails
12 License: GPL2
13 License URI: https://www.gnu.org/licenses/gpl-2.0.html
14
15 **************************************************************************
16
17 Regenerate Thumbnails is free software: you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation, either version 2 of the License, or
20 any later version.
21
22 Regenerate Thumbnails is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with Regenerate Thumbnails. If not, see https://www.gnu.org/licenses/gpl-2.0.html.
29
30 **************************************************************************/
31
32 /**
33 * Main plugin class.
34 *
35 * @since 1.0.0
36 */
37 class RegenerateThumbnails {
38 /**
39 * This plugin's version number. Used for busting caches.
40 *
41 * @var string
42 */
43 public $version = '3.1.6';
44
45 /**
46 * The menu ID of this plugin, as returned by add_management_page().
47 *
48 * @var string
49 */
50 public $menu_id;
51
52 /**
53 * The capability required to use this plugin.
54 * Please don't change this directly. Use the "regenerate_thumbs_cap" filter instead.
55 *
56 * @var string
57 */
58 public $capability = 'manage_options';
59
60 /**
61 * The instance of the REST API controller class used to extend the REST API.
62 *
63 * @var RegenerateThumbnails_REST_Controller
64 */
65 public $rest_api;
66
67 /**
68 * The single instance of this plugin.
69 *
70 * @see RegenerateThumbnails()
71 *
72 * @access private
73 * @var RegenerateThumbnails
74 */
75 private static $instance;
76
77 /**
78 * Constructor. Doesn't actually do anything as instance() creates the class instance.
79 */
80 private function __construct() {}
81
82 /**
83 * Prevents the class from being cloned.
84 */
85 public function __clone() {
86 wp_die( "Please don't clone RegenerateThumbnails" );
87 }
88
89 /**
90 * Prints the class from being unserialized and woken up.
91 */
92 public function __wakeup() {
93 wp_die( "Please don't unserialize/wakeup RegenerateThumbnails" );
94 }
95
96 /**
97 * Creates a new instance of this class if one hasn't already been made
98 * and then returns the single instance of this class.
99 *
100 * @return RegenerateThumbnails
101 */
102 public static function instance() {
103 if ( ! isset( self::$instance ) ) {
104 self::$instance = new RegenerateThumbnails;
105 self::$instance->setup();
106 }
107
108 return self::$instance;
109 }
110
111 /**
112 * Register all of the needed hooks and actions.
113 */
114 public function setup() {
115 // Prevent fatals on old versions of WordPress
116 if ( ! class_exists( 'WP_REST_Controller' ) ) {
117 return;
118 }
119
120 require dirname( __FILE__ ) . '/includes/class-regeneratethumbnails-regenerator.php';
121 require dirname( __FILE__ ) . '/includes/class-regeneratethumbnails-rest-controller.php';
122
123 // Allow people to change what capability is required to use this plugin.
124 $this->capability = apply_filters( 'regenerate_thumbs_cap', $this->capability );
125
126 // Initialize the REST API routes.
127 add_action( 'rest_api_init', array( $this, 'rest_api_init' ) );
128
129 // Add a new item to the Tools menu in the admin menu.
130 add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
131
132 // Load the required JavaScript and CSS.
133 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueues' ) );
134
135 // For the bulk action dropdowns.
136 add_action( 'admin_head-upload.php', array( $this, 'add_bulk_actions_via_javascript' ) );
137 add_action( 'admin_action_bulk_regenerate_thumbnails', array( $this, 'bulk_action_handler' ) ); // Top drowndown.
138 add_action( 'admin_action_-1', array( $this, 'bulk_action_handler' ) ); // Bottom dropdown.
139
140 // Add a regenerate button to the non-modal edit media page.
141 add_action( 'attachment_submitbox_misc_actions', array( $this, 'add_button_to_media_edit_page' ), 99 );
142
143 // Add a regenerate button to the list of fields in the edit media modal.
144 // Ideally this would with the action links but I'm not good enough with JavaScript to do it.
145 add_filter( 'attachment_fields_to_edit', array( $this, 'add_button_to_edit_media_modal_fields_area' ), 99, 2 );
146
147 // Add a regenerate link to actions list in the media list view.
148 add_filter( 'media_row_actions', array( $this, 'add_regenerate_link_to_media_list_view' ), 10, 2 );
149 }
150
151 /**
152 * Initialize the REST API routes.
153 */
154 public function rest_api_init() {
155 $this->rest_api = new RegenerateThumbnails_REST_Controller();
156 $this->rest_api->register_routes();
157 $this->rest_api->register_filters();
158 }
159
160 /**
161 * Adds a the new item to the admin menu.
162 */
163 public function add_admin_menu() {
164 $this->menu_id = add_management_page(
165 _x( 'Regenerate Thumbnails', 'admin page title', 'regenerate-thumbnails' ),
166 _x( 'Regenerate Thumbnails', 'admin menu entry title', 'regenerate-thumbnails' ),
167 $this->capability,
168 'regenerate-thumbnails',
169 array( $this, 'regenerate_interface' )
170 );
171
172 add_action( 'admin_head-' . $this->menu_id, array( $this, 'add_admin_notice_if_resizing_not_supported' ) );
173 }
174
175 /**
176 * Enqueues the requires JavaScript file and stylesheet on the plugin's admin page.
177 *
178 * @param string $hook_suffix The current page's hook suffix as provided by admin-header.php.
179 */
180 public function admin_enqueues( $hook_suffix ) {
181 if ( $hook_suffix != $this->menu_id ) {
182 return;
183 }
184
185 // Pre-4.9 compatibility.
186 if ( ! wp_script_is( 'wp-api-request', 'registered' ) ) {
187 wp_register_script(
188 'wp-api-request',
189 plugins_url( 'js/api-request.min.js', __FILE__ ),
190 array( 'jquery' ),
191 '4.9',
192 true
193 );
194
195 wp_localize_script( 'wp-api-request', 'wpApiSettings', array(
196 'root' => esc_url_raw( get_rest_url() ),
197 'nonce' => ( wp_installing() && ! is_multisite() ) ? '' : wp_create_nonce( 'wp_rest' ),
198 'versionString' => 'wp/v2/',
199 ) );
200 }
201
202 wp_enqueue_script(
203 'regenerate-thumbnails',
204 plugins_url( 'dist/build.js', __FILE__ ),
205 array( 'wp-api-request' ),
206 ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? filemtime( dirname( __FILE__ ) . '/dist/build.js' ) : $this->version,
207 true
208 );
209
210 // phpcs:disable WordPress.Arrays.MultipleStatementAlignment
211 $script_data = array(
212 'data' => array(
213 'thumbnailSizes' => $this->get_thumbnail_sizes(),
214 'genericEditURL' => admin_url( 'post.php?action=edit&post=' ),
215 ),
216 'options' => array(
217 'onlyMissingThumbnails' => apply_filters( 'regenerate_thumbnails_options_onlymissingthumbnails', true ),
218 'updatePostContents' => apply_filters( 'regenerate_thumbnails_options_updatepostcontents', false ),
219 'deleteOldThumbnails' => apply_filters( 'regenerate_thumbnails_options_deleteoldthumbnails', false ),
220 ),
221 'l10n' => array(
222 'common' => array(
223 'loading' => __( 'Loading…', 'regenerate-thumbnails' ),
224 'onlyRegenerateMissingThumbnails' => __( 'Skip regenerating existing correctly sized thumbnails (faster).', 'regenerate-thumbnails' ),
225 'deleteOldThumbnails' => __( "Delete thumbnail files for old unregistered sizes in order to free up server space. This may result in broken images in your posts and pages.", 'regenerate-thumbnails' ),
226 'thumbnailSizeItemWithCropMethodNoFilename' => __( '<strong>{label}:</strong> {width}×{height} pixels ({cropMethod})', 'regenerate-thumbnails' ),
227 'thumbnailSizeItemWithCropMethod' => __( '<strong>{label}:</strong> {width}×{height} pixels ({cropMethod}) <code>{filename}</code>', 'regenerate-thumbnails' ),
228 'thumbnailSizeItemWithoutCropMethod' => __( '<strong>{label}:</strong> {width}×{height} pixels <code>{filename}</code>', 'regenerate-thumbnails' ),
229 'thumbnailSizeBiggerThanOriginal' => __( '<strong>{label}:</strong> {width}×{height} pixels (thumbnail would be larger than original)', 'regenerate-thumbnails' ),
230 'thumbnailSizeItemIsCropped' => __( 'cropped to fit', 'regenerate-thumbnails' ),
231 'thumbnailSizeItemIsProportional' => __( 'proportionally resized to fit inside dimensions', 'regenerate-thumbnails' ),
232 ),
233 'Home' => array(
234 'intro1' => sprintf(
235 /* translators: %s: Media options URL */
236 __( 'When you change WordPress themes or change the sizes of your thumbnails at <a href="%s">Settings → Media</a>, images that you have previously uploaded to you media library will be missing thumbnail files for those new image sizes. This tool will allow you to create those missing thumbnail files for all images.', 'regenerate-thumbnails' ),
237 esc_url( admin_url( 'options-media.php' ) )
238 ),
239 'intro2' => sprintf(
240 /* translators: %s: Media library URL */
241 __( 'To process a specific image, visit your media library and click the &quot;Regenerate Thumbnails&quot; link or button. To process multiple specific images, make sure you\'re in the <a href="%s">list view</a> and then use the Bulk Actions dropdown after selecting one or more images.', 'regenerate-thumbnails' ),
242 esc_url( admin_url( 'upload.php?mode=list' ) )
243 ),
244 'updatePostContents' => __( 'Update the content of posts to use the new sizes.', 'regenerate-thumbnails' ),
245 'RegenerateThumbnailsForAllAttachments' => __( 'Regenerate Thumbnails For All Attachments', 'regenerate-thumbnails' ),
246 'RegenerateThumbnailsForAllXAttachments' => __( 'Regenerate Thumbnails For All {attachmentCount} Attachments', 'regenerate-thumbnails' ),
247 'RegenerateThumbnailsForFeaturedImagesOnly' => __( 'Regenerate Thumbnails For Featured Images Only', 'regenerate-thumbnails' ),
248 'RegenerateThumbnailsForXFeaturedImagesOnly' => __( 'Regenerate Thumbnails For The {attachmentCount} Featured Images Only', 'regenerate-thumbnails' ),
249 'thumbnailSizes' => __( 'Thumbnail Sizes', 'regenerate-thumbnails' ),
250 'thumbnailSizesDescription' => __( 'These are all of the thumbnail sizes that are currently registered:', 'regenerate-thumbnails' ),
251 'alternatives' => __( 'Alternatives', 'regenerate-thumbnails' ),
252 'alternativesText1' => __( 'If you have <a href="{url-cli}">command-line</a> access to your site\'s server, consider using <a href="{url-wpcli}">WP-CLI</a> instead of this tool. It has a built-in <a href="{url-wpcli-regenerate}">regenerate command</a> that works similarly to this tool but should be significantly faster since it has the advantage of being a command-line tool.', 'regenerate-thumbnails' ),
253 'alternativesText2' => __( 'Another alternative is to use the <a href="{url-photon}">Photon</a> functionality that comes with the <a href="{url-jetpack}">Jetpack</a> plugin. It generates thumbnails on-demand using WordPress.com\'s infrastructure. <em>Disclaimer: The author of this plugin, Regenerate Thumbnails, is an employee of the company behind WordPress.com and Jetpack but I would recommend it even if I wasn\'t.</em>', 'regenerate-thumbnails' ),
254 ),
255 'RegenerateSingle' => array(
256 'regenerateThumbnails' => _x( 'Regenerate Thumbnails', 'action for a single image', 'regenerate-thumbnails' ),
257 /* translators: single image sdmin page title */
258 'title' => __( 'Regenerate Thumbnails: {name} — WordPress', 'regenerate-thumbnails' ),
259 'errorWithMessage' => __( '<strong>ERROR:</strong> {error}', 'regenerate-thumbnails' ),
260 'filenameAndDimensions' => __( '<code>{filename}</code> {width}×{height} pixels', 'regenerate-thumbnails' ),
261 'preview' => __( 'Preview', 'regenerate-thumbnails' ),
262 'updatePostContents' => __( 'Update the content of posts that use this attachment to use the new sizes.', 'regenerate-thumbnails' ),
263 'regenerating' => __( 'Regenerating…', 'regenerate-thumbnails' ),
264 'done' => __( 'Done! Click here to go back.', 'regenerate-thumbnails' ),
265 'errorRegenerating' => __( 'Error Regenerating', 'regenerate-thumbnails' ),
266 'errorRegeneratingMessage' => __( 'There was an error regenerating this attachment. The error was: <em>{message}</em>', 'regenerate-thumbnails' ),
267 'registeredSizes' => __( 'These are the currently registered thumbnail sizes, whether they exist for this attachment, and their filenames:', 'regenerate-thumbnails' ),
268 'unregisteredSizes' => __( 'The attachment says it also has these thumbnail sizes but they are no longer in use by WordPress. You can probably safely have this plugin delete them, especially if you have this plugin update any posts that make use of this attachment.', 'regenerate-thumbnails' ),
269 ),
270 'RegenerateMultiple' => array(
271 'errorsEncountered' => __( 'Errors Encountered', 'regenerate-thumbnails' ),
272 'regenerationLog' => __( 'Regeneration Log', 'regenerate-thumbnails' ),
273 'pause' => __( 'Pause', 'regenerate-thumbnails' ),
274 'resume' => __( 'Resume', 'regenerate-thumbnails' ),
275 'logRegeneratedItem' => __( 'Regenerated {name}', 'regenerate-thumbnails' ),
276 'logSkippedItem' => __( 'Skipped Attachment ID {id} ({name}): {reason}', 'regenerate-thumbnails' ),
277 'logSkippedItemNoName' => __( 'Skipped Attachment ID {id}: {reason}', 'regenerate-thumbnails' ),
278 'duration' => __( 'All done in {duration}.', 'regenerate-thumbnails' ),
279 'hours' => __( '{count} hours', 'regenerate-thumbnails' ),
280 'minutes' => __( '{count} minutes', 'regenerate-thumbnails' ),
281 'seconds' => __( '{count} seconds', 'regenerate-thumbnails' ),
282 'error' => __( "Unable to fetch a list of attachment IDs to process from the WordPress REST API. You can check your browser's console for details.", 'regenerate-thumbnails' ),
283 ),
284 ),
285 );
286 // phpcs:enable
287
288 // Bulk regeneration
289 // phpcs:disable WordPress.Security.NonceVerification
290 if ( ! empty( $_GET['ids'] ) ) {
291 $script_data['data']['thumbnailIDs'] = array_map( 'intval', explode( ',', $_GET['ids'] ) );
292
293 $script_data['l10n']['Home']['RegenerateThumbnailsForXAttachments'] = sprintf(
294 __( 'Regenerate Thumbnails For The %d Selected Attachments', 'regenerate-thumbnails' ),
295 count( $script_data['data']['thumbnailIDs'] )
296 );
297 }
298 // phpcs:enable
299
300 wp_localize_script( 'regenerate-thumbnails', 'regenerateThumbnails', $script_data );
301
302 wp_enqueue_style(
303 'regenerate-thumbnails-progressbar',
304 plugins_url( 'css/progressbar.css', __FILE__ ),
305 array(),
306 ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? filemtime( dirname( __FILE__ ) . '/css/progressbar.css' ) : $this->version
307 );
308 }
309
310 /**
311 * The main Regenerate Thumbnails interface, as displayed at Tools → Regenerate Thumbnails.
312 */
313 public function regenerate_interface() {
314 global $wp_version;
315
316 echo '<div class="wrap">';
317 echo '<h1>' . esc_html_x( 'Regenerate Thumbnails', 'admin page title', 'regenerate-thumbnails' ) . '</h1>';
318
319 if ( version_compare( $wp_version, '4.7', '<' ) ) {
320 echo '<p>' . sprintf(
321 __( 'This plugin requires WordPress 4.7 or newer. You are on version %1$s. Please <a href="%2$s">upgrade</a>.', 'regenerate-thumbnails' ),
322 esc_html( $wp_version ),
323 esc_url( admin_url( 'update-core.php' ) )
324 ) . '</p>';
325 } else {
326
327 ?>
328
329 <div id="regenerate-thumbnails-app">
330 <div class="notice notice-error hide-if-js">
331 <p><strong><?php esc_html_e( 'This tool requires that JavaScript be enabled to work.', 'regenerate-thumbnails' ); ?></strong></p>
332 </div>
333
334 <router-view><p class="hide-if-no-js"><?php esc_html_e( 'Loading…', 'regenerate-thumbnails' ); ?></p></router-view>
335 </div>
336
337 <?php
338
339 } // version_compare()
340
341 echo '</div>';
342 }
343
344 /**
345 * If the image editor doesn't support image resizing (thumbnailing), then add an admin notice
346 * warning the user of this.
347 */
348 public function add_admin_notice_if_resizing_not_supported() {
349 if ( ! wp_image_editor_supports( array( 'methods' => array( 'resize' ) ) ) ) {
350 add_action( 'admin_notices', array( $this, 'admin_notices_resizing_not_supported' ) );
351 }
352 }
353
354 /**
355 * Outputs an admin notice stating that image resizing (thumbnailing) is not supported.
356 */
357 public function admin_notices_resizing_not_supported() {
358 ?>
359 <div class="notice notice-error">
360 <p><strong><?php esc_html_e( "This tool won't be able to do anything because your server doesn't support image editing which means that WordPress can't create thumbnail images. Please ask your host to install the Imagick or GD PHP extensions.", 'regenerate-thumbnails' ); ?></strong></p>
361 </div>
362 <?php
363 }
364
365 /**
366 * Helper function to create a URL to regenerate a single image.
367 *
368 * @param int $id The attachment ID that should be regenerated.
369 *
370 * @return string The URL to the admin page.
371 */
372 public function create_page_url( $id ) {
373 return add_query_arg( 'page', 'regenerate-thumbnails', admin_url( 'tools.php' ) ) . '#/regenerate/' . $id;
374 }
375
376 /**
377 * Determines whether an attachment can have its thumbnails regenerated.
378 *
379 * This includes checking to see if non-images, such as PDFs, are supported
380 * by the current image editor.
381 *
382 * @param WP_Post $post An attachment's post object.
383 *
384 * @return bool Whether the given attachment can have its thumbnails regenerated.
385 */
386 public function is_regeneratable( $post ) {
387 if ( 'site-icon' === get_post_meta( $post->ID, '_wp_attachment_context', true ) ) {
388 return false;
389 }
390
391 if ( wp_attachment_is_image( $post ) ) {
392 return true;
393 }
394
395 if ( function_exists( 'wp_get_original_image_path' ) ) {
396 $fullsize = wp_get_original_image_path( $post->ID );
397 } else {
398 $fullsize = get_attached_file( $post->ID );
399 }
400
401 if ( ! $fullsize || ! file_exists( $fullsize ) ) {
402 return false;
403 }
404
405 $image_editor_args = array(
406 'path' => $fullsize,
407 'methods' => array( 'resize' )
408 );
409
410 $file_info = wp_check_filetype( $image_editor_args['path'] );
411 // If $file_info['type'] is false, then we let the editor attempt to
412 // figure out the file type, rather than forcing a failure based on extension.
413 if ( isset( $file_info ) && $file_info['type'] ) {
414 $image_editor_args['mime_type'] = $file_info['type'];
415 }
416
417 return (bool) _wp_image_editor_choose( $image_editor_args );
418 }
419
420 /**
421 * Adds "Regenerate Thumbnails" below each image in the media library list view.
422 *
423 * @param array $actions An array of current actions.
424 * @param WP_Post $post The current attachment's post object.
425 *
426 * @return array The new list of actions.
427 */
428 public function add_regenerate_link_to_media_list_view( $actions, $post ) {
429 if ( ! current_user_can( $this->capability ) || ! $this->is_regeneratable( $post ) ) {
430 return $actions;
431 }
432
433 $actions['regenerate_thumbnails'] = '<a href="' . esc_url( $this->create_page_url( $post->ID ) ) . '" title="' . esc_attr( __( 'Regenerate the thumbnails for this single image', 'regenerate-thumbnails' ) ) . '">' . _x( 'Regenerate Thumbnails', 'action for a single image', 'regenerate-thumbnails' ) . '</a>';
434
435 return $actions;
436 }
437
438 /**
439 * Add a "Regenerate Thumbnails" button to the submit box on the non-modal "Edit Media" screen for an image attachment.
440 */
441 public function add_button_to_media_edit_page() {
442 global $post;
443
444 if ( ! current_user_can( $this->capability ) || ! $this->is_regeneratable( $post ) ) {
445 return;
446 }
447
448 echo '<div class="misc-pub-section misc-pub-regenerate-thumbnails">';
449 echo '<a href="' . esc_url( $this->create_page_url( $post->ID ) ) . '" class="button-secondary button-large" title="' . esc_attr( __( 'Regenerate the thumbnails for this single image', 'regenerate-thumbnails' ) ) . '">' . _x( 'Regenerate Thumbnails', 'action for a single image', 'regenerate-thumbnails' ) . '</a>';
450 echo '</div>';
451 }
452
453 /**
454 * Adds a "Regenerate Thumbnails" button to the edit media modal view.
455 *
456 * Ideally it would be down with the actions but I'm not good enough at JavaScript
457 * in order to be able to do it, so instead I'm adding it to the bottom of the list
458 * of media fields. Pull requests to improve this are welcome!
459 *
460 * @param array $form_fields An array of existing form fields.
461 * @param WP_Post $post The current media item, as a post object.
462 *
463 * @return array The new array of form fields.
464 */
465 public function add_button_to_edit_media_modal_fields_area( $form_fields, $post ) {
466 if ( ! current_user_can( $this->capability ) || ! $this->is_regeneratable( $post ) ) {
467 return $form_fields;
468 }
469
470 $form_fields['regenerate_thumbnails'] = array(
471 'label' => '',
472 'input' => 'html',
473 'html' => '<a href="' . esc_url( $this->create_page_url( $post->ID ) ) . '" class="button-secondary button-large" title="' . esc_attr( __( 'Regenerate the thumbnails for this single image', 'regenerate-thumbnails' ) ) . '">' . _x( 'Regenerate Thumbnails', 'action for a single image', 'regenerate-thumbnails' ) . '</a>',
474 'show_in_modal' => true,
475 'show_in_edit' => false,
476 );
477
478 return $form_fields;
479 }
480
481 /**
482 * Add "Regenerate Thumbnails" to the bulk actions dropdown on the media list using Javascript.
483 */
484 public function add_bulk_actions_via_javascript() {
485 if ( ! current_user_can( $this->capability ) ) {
486 return;
487 }
488
489 ?>
490 <script type="text/javascript">
491 jQuery(document).ready(function ($) {
492 $('select[name^="action"] option:last-child').before(
493 $('<option/>')
494 .attr('value', 'bulk_regenerate_thumbnails')
495 .text('<?php echo esc_js( _x( 'Regenerate Thumbnails', 'bulk actions dropdown', 'regenerate-thumbnails' ) ); ?>')
496 );
497 });
498 </script>
499 <?php
500 }
501
502 /**
503 * Handles the submission of the new bulk actions entry and redirects to the admin page with the selected attachment IDs.
504 */
505 public function bulk_action_handler() {
506 if (
507 empty( $_REQUEST['action'] ) ||
508 empty( $_REQUEST['action2'] ) ||
509 ( 'bulk_regenerate_thumbnails' != $_REQUEST['action'] && 'bulk_regenerate_thumbnails' != $_REQUEST['action2'] ) ||
510 empty( $_REQUEST['media'] ) ||
511 ! is_array( $_REQUEST['media'] )
512 ) {
513 return;
514 }
515
516 check_admin_referer( 'bulk-media' );
517
518 wp_safe_redirect(
519 add_query_arg(
520 array(
521 'page' => 'regenerate-thumbnails',
522 'ids' => rawurlencode( implode( ',', array_map( 'intval', $_REQUEST['media'] ) ) ),
523 ),
524 admin_url( 'tools.php' )
525 )
526 );
527
528 exit();
529 }
530
531 /**
532 * Returns an array of all thumbnail sizes, including their label, size, and crop setting.
533 *
534 * @return array An array, with the thumbnail label as the key and an array of thumbnail properties (width, height, crop).
535 */
536 public function get_thumbnail_sizes() {
537 global $_wp_additional_image_sizes;
538
539 $thumbnail_sizes = array();
540
541 foreach ( get_intermediate_image_sizes() as $size ) {
542 $thumbnail_sizes[ $size ]['label'] = $size;
543 if ( in_array( $size, array( 'thumbnail', 'medium', 'medium_large', 'large' ) ) ) {
544 $thumbnail_sizes[ $size ]['width'] = (int) get_option( $size . '_size_w' );
545 $thumbnail_sizes[ $size ]['height'] = (int) get_option( $size . '_size_h' );
546 $thumbnail_sizes[ $size ]['crop'] = ( 'thumbnail' == $size ) ? (bool) get_option( 'thumbnail_crop' ) : false;
547 } elseif ( ! empty( $_wp_additional_image_sizes ) && ! empty( $_wp_additional_image_sizes[ $size ] ) ) {
548 $thumbnail_sizes[ $size ]['width'] = (int) $_wp_additional_image_sizes[ $size ]['width'];
549 $thumbnail_sizes[ $size ]['height'] = (int) $_wp_additional_image_sizes[ $size ]['height'];
550 $thumbnail_sizes[ $size ]['crop'] = (bool) $_wp_additional_image_sizes[ $size ]['crop'];
551 }
552 }
553
554 return $thumbnail_sizes;
555 }
556 }
557
558 /**
559 * Returns the single instance of this plugin, creating one if needed.
560 *
561 * @return RegenerateThumbnails
562 */
563 function RegenerateThumbnails() {
564 return RegenerateThumbnails::instance();
565 }
566
567 /**
568 * Initialize this plugin once all other plugins have finished loading.
569 */
570 add_action( 'init', 'RegenerateThumbnails' );
...@@ -94,3 +94,20 @@ function set_exclude_from_search() ...@@ -94,3 +94,20 @@ function set_exclude_from_search()
94 } 94 }
95 } 95 }
96 } 96 }
97
98 add_action('init','delete_exclude_from_search');
99 function delete_exclude_from_search()
100 {
101 if ($_GET['var'] =='delete_wpml_from_search') {
102 $args = array( 'posts_per_page' => -1, 'post_type' => 'attachment');
103 $pages = get_posts( $args );
104 foreach ( $pages as $page ){
105 $exclude_from_search = get_post_meta($page->ID, 'exclude_from_search', true);
106 if($exclude_from_search == '0'){
107 wp_delete_attachment( $page->ID, true );
108 //error_log($page->ID);
109 }
110 }
111 }
112
113 }
...\ No newline at end of file ...\ No newline at end of file
......