edit pages
This commit is contained in:
@ -0,0 +1,710 @@
|
||||
<?php
|
||||
/**
|
||||
* Regenerate Thumbnails: Attachment regenerator class
|
||||
*
|
||||
* @package RegenerateThumbnails
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Regenerates the thumbnails for a given attachment.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class RegenerateThumbnails_Regenerator {
|
||||
|
||||
/**
|
||||
* The WP_Post object for the attachment that is being operated on.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @var WP_Post
|
||||
*/
|
||||
public $attachment;
|
||||
|
||||
/**
|
||||
* The full path to the original image so that it can be passed between methods.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $fullsizepath;
|
||||
|
||||
/**
|
||||
* An array of thumbnail size(s) that were skipped during regeneration due to already existing.
|
||||
* A class variable is used so that the data can later be used to merge the size(s) back in.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $skipped_thumbnails = array();
|
||||
|
||||
/**
|
||||
* The metadata for the attachment before the regeneration process starts.
|
||||
*
|
||||
* @since 3.1.6
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $old_metadata = array();
|
||||
|
||||
/**
|
||||
* Generates an instance of this class after doing some setup.
|
||||
*
|
||||
* MIME type is purposefully not validated in order to be more future proof and
|
||||
* to avoid duplicating a ton of logic that already exists in WordPress core.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param int $attachment_id Attachment ID to process.
|
||||
*
|
||||
* @return RegenerateThumbnails_Regenerator|WP_Error A new instance of RegenerateThumbnails_Regenerator on success, or WP_Error on error.
|
||||
*/
|
||||
public static function get_instance( $attachment_id ) {
|
||||
$attachment = get_post( $attachment_id );
|
||||
|
||||
if ( ! $attachment ) {
|
||||
return new WP_Error(
|
||||
'regenerate_thumbnails_regenerator_attachment_doesnt_exist',
|
||||
__( 'No attachment exists with that ID.', 'regenerate-thumbnails' ),
|
||||
array(
|
||||
'status' => 404,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// We can only regenerate thumbnails for attachments.
|
||||
if ( 'attachment' !== get_post_type( $attachment ) ) {
|
||||
return new WP_Error(
|
||||
'regenerate_thumbnails_regenerator_not_attachment',
|
||||
__( 'This item is not an attachment.', 'regenerate-thumbnails' ),
|
||||
array(
|
||||
'status' => 400,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Don't touch any attachments that are being used as a site icon. Their thumbnails are usually custom cropped.
|
||||
if ( self::is_site_icon( $attachment ) ) {
|
||||
return new WP_Error(
|
||||
'regenerate_thumbnails_regenerator_is_site_icon',
|
||||
__( "This attachment is a site icon and therefore the thumbnails shouldn't be touched.", 'regenerate-thumbnails' ),
|
||||
array(
|
||||
'status' => 415,
|
||||
'attachment' => $attachment,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new RegenerateThumbnails_Regenerator( $attachment );
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor for this class. Don't call this directly, see get_instance() instead.
|
||||
* This is done so that WP_Error objects can be returned during class initiation.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param WP_Post $attachment The WP_Post object for the attachment that is being operated on.
|
||||
*/
|
||||
private function __construct( WP_Post $attachment ) {
|
||||
$this->attachment = $attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the attachment is or was a site icon.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param WP_Post $attachment The WP_Post object for the attachment that is being operated on.
|
||||
*
|
||||
* @return bool Whether the attachment is or was a site icon.
|
||||
*/
|
||||
public static function is_site_icon( WP_Post $attachment ) {
|
||||
return ( 'site-icon' === get_post_meta( $attachment->ID, '_wp_attachment_context', true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path to the fullsize attachment.
|
||||
*
|
||||
* @return string|WP_Error The path to the fullsize attachment, or a WP_Error object on error.
|
||||
*/
|
||||
public function get_fullsizepath() {
|
||||
if ( $this->fullsizepath ) {
|
||||
return $this->fullsizepath;
|
||||
}
|
||||
|
||||
if ( function_exists( 'wp_get_original_image_path' ) ) {
|
||||
$this->fullsizepath = wp_get_original_image_path( $this->attachment->ID );
|
||||
} else {
|
||||
$this->fullsizepath = get_attached_file( $this->attachment->ID );
|
||||
}
|
||||
|
||||
if ( false === $this->fullsizepath || ! file_exists( $this->fullsizepath ) ) {
|
||||
$error = new WP_Error(
|
||||
'regenerate_thumbnails_regenerator_file_not_found',
|
||||
sprintf(
|
||||
/* translators: The relative upload path to the attachment. */
|
||||
__( "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' ),
|
||||
_wp_relative_upload_path( $this->fullsizepath )
|
||||
),
|
||||
array(
|
||||
'status' => 404,
|
||||
'fullsizepath' => _wp_relative_upload_path( $this->fullsizepath ),
|
||||
'attachment' => $this->attachment,
|
||||
)
|
||||
);
|
||||
|
||||
$this->fullsizepath = $error;
|
||||
}
|
||||
|
||||
return $this->fullsizepath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate the thumbnails for this instance's attachment.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array|string $args {
|
||||
* Optional. Array or string of arguments for thumbnail regeneration.
|
||||
*
|
||||
* @type bool $only_regenerate_missing_thumbnails Skip regenerating existing thumbnail files. Default true.
|
||||
* @type bool $delete_unregistered_thumbnail_files Delete any thumbnail sizes that are no longer registered. Default false.
|
||||
* }
|
||||
*
|
||||
* @return mixed|WP_Error Metadata for attachment (see wp_generate_attachment_metadata()), or WP_Error on error.
|
||||
*/
|
||||
public function regenerate( $args = array() ) {
|
||||
global $wpdb;
|
||||
|
||||
$args = wp_parse_args( $args, array(
|
||||
'only_regenerate_missing_thumbnails' => true,
|
||||
'delete_unregistered_thumbnail_files' => false,
|
||||
) );
|
||||
|
||||
$fullsizepath = $this->get_fullsizepath();
|
||||
if ( is_wp_error( $fullsizepath ) ) {
|
||||
$fullsizepath->add_data( array( 'attachment' => $this->attachment ) );
|
||||
|
||||
return $fullsizepath;
|
||||
}
|
||||
|
||||
$this->old_metadata = wp_get_attachment_metadata( $this->attachment->ID );
|
||||
|
||||
if ( $args['only_regenerate_missing_thumbnails'] ) {
|
||||
add_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10, 2 );
|
||||
}
|
||||
|
||||
require_once( ABSPATH . 'wp-admin/includes/admin.php' );
|
||||
$new_metadata = wp_generate_attachment_metadata( $this->attachment->ID, $fullsizepath );
|
||||
|
||||
if ( $args['only_regenerate_missing_thumbnails'] ) {
|
||||
// Thumbnail sizes that existed were removed and need to be added back to the metadata.
|
||||
foreach ( $this->skipped_thumbnails as $skipped_thumbnail ) {
|
||||
if ( ! empty( $this->old_metadata['sizes'][ $skipped_thumbnail ] ) ) {
|
||||
$new_metadata['sizes'][ $skipped_thumbnail ] = $this->old_metadata['sizes'][ $skipped_thumbnail ];
|
||||
}
|
||||
}
|
||||
$this->skipped_thumbnails = array();
|
||||
|
||||
remove_filter( 'intermediate_image_sizes_advanced', array( $this, 'filter_image_sizes_to_only_missing_thumbnails' ), 10 );
|
||||
}
|
||||
|
||||
$wp_upload_dir = dirname( $fullsizepath ) . DIRECTORY_SEPARATOR;
|
||||
|
||||
if ( $args['delete_unregistered_thumbnail_files'] ) {
|
||||
// Delete old sizes that are still in the metadata.
|
||||
$intermediate_image_sizes = get_intermediate_image_sizes();
|
||||
foreach ( $this->old_metadata['sizes'] as $old_size => $old_size_data ) {
|
||||
if ( in_array( $old_size, $intermediate_image_sizes ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wp_delete_file( $wp_upload_dir . $old_size_data['file'] );
|
||||
|
||||
unset( $new_metadata['sizes'][ $old_size ] );
|
||||
}
|
||||
|
||||
$relative_path = dirname( $new_metadata['file'] ) . DIRECTORY_SEPARATOR;
|
||||
|
||||
// It's possible to upload an image with a filename like image-123x456.jpg and it shouldn't be deleted.
|
||||
$whitelist = $wpdb->get_col( $wpdb->prepare( "
|
||||
SELECT
|
||||
meta_value
|
||||
FROM
|
||||
{$wpdb->postmeta}
|
||||
WHERE
|
||||
meta_key = '_wp_attached_file'
|
||||
AND meta_value REGEXP %s
|
||||
/* Regenerate Thumbnails */
|
||||
",
|
||||
'^' . preg_quote( $relative_path ) . '[^' . preg_quote( DIRECTORY_SEPARATOR ) . ']+-[0-9]+x[0-9]+\.'
|
||||
) );
|
||||
$whitelist = array_map( 'basename', $whitelist );
|
||||
|
||||
$filelist = array();
|
||||
foreach ( scandir( $wp_upload_dir ) as $file ) {
|
||||
if ( '.' == $file || '..' == $file || ! is_file( $wp_upload_dir . $file ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filelist[] = $file;
|
||||
}
|
||||
|
||||
$registered_thumbnails = array();
|
||||
foreach ( $new_metadata['sizes'] as $size ) {
|
||||
$registered_thumbnails[] = $size['file'];
|
||||
}
|
||||
|
||||
$fullsize_parts = pathinfo( $fullsizepath );
|
||||
|
||||
foreach ( $filelist as $file ) {
|
||||
if ( in_array( $file, $whitelist ) || in_array( $file, $registered_thumbnails ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! preg_match( '#^' . preg_quote( $fullsize_parts['filename'], '#' ) . '-[0-9]+x[0-9]+\.' . preg_quote( $fullsize_parts['extension'], '#' ) . '$#', $file ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
wp_delete_file( $wp_upload_dir . $file );
|
||||
}
|
||||
} elseif ( ! empty( $this->old_metadata ) && ! empty( $this->old_metadata['sizes'] ) && is_array( $this->old_metadata['sizes'] ) ) {
|
||||
// If not deleting, rename any size conflicts to avoid them being lost if the file still exists.
|
||||
foreach ( $this->old_metadata['sizes'] as $old_size => $old_size_data ) {
|
||||
if ( empty( $new_metadata['sizes'][ $old_size ] ) ) {
|
||||
$new_metadata['sizes'][ $old_size ] = $this->old_metadata['sizes'][ $old_size ];
|
||||
continue;
|
||||
}
|
||||
|
||||
$new_size_data = $new_metadata['sizes'][ $old_size ];
|
||||
|
||||
if (
|
||||
$new_size_data['width'] !== $old_size_data['width']
|
||||
&& $new_size_data['height'] !== $old_size_data['height']
|
||||
&& file_exists( $wp_upload_dir . $old_size_data['file'] )
|
||||
) {
|
||||
$new_metadata['sizes'][ $old_size . '_old_' . $old_size_data['width'] . 'x' . $old_size_data['height'] ] = $old_size_data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wp_update_attachment_metadata( $this->attachment->ID, $new_metadata );
|
||||
|
||||
return $new_metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the list of thumbnail sizes to only include those which have missing files.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array $sizes An associative array of registered thumbnail image sizes.
|
||||
* @param array $fullsize_metadata An associative array of fullsize image metadata: width, height, file.
|
||||
*
|
||||
* @return array An associative array of image sizes.
|
||||
*/
|
||||
public function filter_image_sizes_to_only_missing_thumbnails( $sizes, $fullsize_metadata ) {
|
||||
if ( ! $sizes ) {
|
||||
return $sizes;
|
||||
}
|
||||
|
||||
$fullsizepath = $this->get_fullsizepath();
|
||||
if ( is_wp_error( $fullsizepath ) ) {
|
||||
return $sizes;
|
||||
}
|
||||
|
||||
$editor = wp_get_image_editor( $fullsizepath );
|
||||
if ( is_wp_error( $editor ) ) {
|
||||
return $sizes;
|
||||
}
|
||||
|
||||
$metadata = $this->old_metadata;
|
||||
|
||||
// This is based on WP_Image_Editor_GD::multi_resize() and others.
|
||||
foreach ( $sizes as $size => $size_data ) {
|
||||
if ( empty( $metadata['sizes'][ $size ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset( $size_data['width'] ) && ! isset( $size_data['height'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset( $size_data['width'] ) ) {
|
||||
$size_data['width'] = null;
|
||||
}
|
||||
if ( ! isset( $size_data['height'] ) ) {
|
||||
$size_data['height'] = null;
|
||||
}
|
||||
|
||||
if ( ! isset( $size_data['crop'] ) ) {
|
||||
$size_data['crop'] = false;
|
||||
}
|
||||
|
||||
$thumbnail = $this->get_thumbnail(
|
||||
$editor,
|
||||
$fullsize_metadata['width'],
|
||||
$fullsize_metadata['height'],
|
||||
$size_data['width'],
|
||||
$size_data['height'],
|
||||
$size_data['crop']
|
||||
);
|
||||
|
||||
|
||||
// The false check filters out thumbnails that would be larger than the fullsize image.
|
||||
// The size comparison makes sure that the size is also correct.
|
||||
if (
|
||||
false === $thumbnail
|
||||
|| (
|
||||
$thumbnail['width'] === $metadata['sizes'][ $size ]['width']
|
||||
&& $thumbnail['height'] === $metadata['sizes'][ $size ]['height']
|
||||
&& file_exists( $thumbnail['filename'] )
|
||||
)
|
||||
) {
|
||||
$this->skipped_thumbnails[] = $size;
|
||||
unset( $sizes[ $size ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the list of missing thumbnail sizes if you want to add/remove any.
|
||||
*
|
||||
* @since 3.1.0
|
||||
*
|
||||
* @param array $sizes An associative array of image sizes that are missing.
|
||||
* @param array $fullsize_metadata An associative array of fullsize image metadata: width, height, file.
|
||||
* @param object $this The current instance of this class.
|
||||
*
|
||||
* @return array An associative array of image sizes.
|
||||
*/
|
||||
return apply_filters( 'regenerate_thumbnails_missing_thumbnails', $sizes, $fullsize_metadata, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the thumbnail filename and dimensions for a given set of constraint dimensions.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param WP_Image_Editor|WP_Error $editor An instance of WP_Image_Editor, as returned by wp_get_image_editor().
|
||||
* @param int $fullsize_width The width of the fullsize image.
|
||||
* @param int $fullsize_height The height of the fullsize image.
|
||||
* @param int $thumbnail_width The width of the thumbnail.
|
||||
* @param int $thumbnail_height The height of the thumbnail.
|
||||
* @param bool $crop Whether to crop or not.
|
||||
*
|
||||
* @return array|false An array of the filename, thumbnail width, and thumbnail height,
|
||||
* or false on failure to resize such as the thumbnail being larger than the fullsize image.
|
||||
*/
|
||||
public function get_thumbnail( $editor, $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop ) {
|
||||
$dims = image_resize_dimensions( $fullsize_width, $fullsize_height, $thumbnail_width, $thumbnail_height, $crop );
|
||||
|
||||
if ( ! $dims ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list( , , , , $dst_w, $dst_h ) = $dims;
|
||||
|
||||
$suffix = "{$dst_w}x{$dst_h}";
|
||||
$file_ext = strtolower( pathinfo( $this->get_fullsizepath(), PATHINFO_EXTENSION ) );
|
||||
|
||||
return array(
|
||||
'filename' => $editor->generate_filename( $suffix, null, $file_ext ),
|
||||
'width' => $dst_w,
|
||||
'height' => $dst_h,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the post content of any public post types (posts and pages by default)
|
||||
* that make use of this attachment.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param array|string $args {
|
||||
* Optional. Array or string of arguments for controlling the updating.
|
||||
*
|
||||
* @type array $post_type The post types to update. Defaults to public post types (posts and pages by default).
|
||||
* @type array $post_ids Specific post IDs to update as opposed to any that uses the attachment.
|
||||
* @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.
|
||||
* }
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public function update_usages_in_posts( $args = array() ) {
|
||||
// Temporarily disabled until it can be even better tested for edge cases
|
||||
return array();
|
||||
|
||||
$args = wp_parse_args( $args, array(
|
||||
'post_type' => array(),
|
||||
'post_ids' => array(),
|
||||
'posts_per_loop' => 10,
|
||||
) );
|
||||
|
||||
if ( empty( $args['post_type'] ) ) {
|
||||
$args['post_type'] = array_values( get_post_types( array( 'public' => true ) ) );
|
||||
unset( $args['post_type']['attachment'] );
|
||||
}
|
||||
|
||||
$offset = 0;
|
||||
$posts_updated = array();
|
||||
|
||||
while ( true ) {
|
||||
$posts = get_posts( array(
|
||||
'numberposts' => $args['posts_per_loop'],
|
||||
'offset' => $offset,
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'include' => $args['post_ids'],
|
||||
'post_type' => $args['post_type'],
|
||||
's' => 'wp-image-' . $this->attachment->ID,
|
||||
|
||||
// For faster queries.
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
) );
|
||||
|
||||
if ( ! $posts ) {
|
||||
break;
|
||||
}
|
||||
|
||||
$offset += $args['posts_per_loop'];
|
||||
|
||||
foreach ( $posts as $post ) {
|
||||
$content = $post->post_content;
|
||||
$search = array();
|
||||
$replace = array();
|
||||
|
||||
// Find all <img> tags for this attachment and update them.
|
||||
preg_match_all(
|
||||
'#<img [^>]+wp-image-' . $this->attachment->ID . '[^>]+/>#i',
|
||||
$content,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
if ( $matches ) {
|
||||
foreach ( $matches as $img_tag ) {
|
||||
preg_match( '# class="([^"]+)?size-([^" ]+)#i', $img_tag[0], $thumbnail_size );
|
||||
|
||||
if ( $thumbnail_size ) {
|
||||
$thumbnail = image_downsize( $this->attachment->ID, $thumbnail_size[2] );
|
||||
|
||||
if ( ! $thumbnail ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$search[] = $img_tag[0];
|
||||
|
||||
$img_tag[0] = preg_replace( '# src="[^"]+"#i', ' src="' . esc_url( $thumbnail[0] ) . '"', $img_tag[0] );
|
||||
$img_tag[0] = preg_replace(
|
||||
'# width="[^"]+" height="[^"]+"#i',
|
||||
' width="' . esc_attr( $thumbnail[1] ) . '" height="' . esc_attr( $thumbnail[2] ) . '"',
|
||||
$img_tag[0]
|
||||
);
|
||||
|
||||
$replace[] = $img_tag[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
$content = str_replace( $search, $replace, $content );
|
||||
$search = array();
|
||||
$replace = array();
|
||||
|
||||
// Update the width in any [caption] shortcodes.
|
||||
preg_match_all(
|
||||
'#\[caption id="attachment_' . $this->attachment->ID . '"([^\]]+)? width="[^"]+"\]([^\[]+)size-([^" ]+)([^\[]+)\[\/caption\]#i',
|
||||
$content,
|
||||
$matches,
|
||||
PREG_SET_ORDER
|
||||
);
|
||||
if ( $matches ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$thumbnail = image_downsize( $this->attachment->ID, $match[3] );
|
||||
|
||||
if ( ! $thumbnail ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$search[] = $match[0];
|
||||
$replace[] = '[caption id="attachment_' . $this->attachment->ID . '"' . $match[1] . ' width="' . esc_attr( $thumbnail[1] ) . '"]' . $match[2] . 'size-' . $match[3] . $match[4] . '[/caption]';
|
||||
}
|
||||
}
|
||||
$content = str_replace( $search, $replace, $content );
|
||||
|
||||
$updated_post_object = (object) array(
|
||||
'ID' => $post->ID,
|
||||
'post_content' => $content,
|
||||
);
|
||||
|
||||
$posts_updated[ $post->ID ] = wp_update_post( $updated_post_object, true );
|
||||
}
|
||||
}
|
||||
|
||||
return $posts_updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns information about the current attachment for use in the REST API.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @return array|WP_Error The attachment name, fullsize URL, registered thumbnail size status, and any unregistered sizes, or WP_Error on error.
|
||||
*/
|
||||
public function get_attachment_info() {
|
||||
$fullsizepath = $this->get_fullsizepath();
|
||||
if ( is_wp_error( $fullsizepath ) ) {
|
||||
$fullsizepath->add_data( array( 'attachment' => $this->attachment ) );
|
||||
|
||||
return $fullsizepath;
|
||||
}
|
||||
|
||||
$editor = wp_get_image_editor( $fullsizepath );
|
||||
if ( is_wp_error( $editor ) ) {
|
||||
// Display a more helpful error message.
|
||||
if ( 'image_no_editor' === $editor->get_error_code() ) {
|
||||
$editor = new WP_Error( 'image_no_editor', __( 'The current image editor cannot process this file type.', 'regenerate-thumbnails' ) );
|
||||
}
|
||||
|
||||
$editor->add_data( array(
|
||||
'attachment' => $this->attachment,
|
||||
'status' => 415,
|
||||
) );
|
||||
|
||||
return $editor;
|
||||
}
|
||||
|
||||
$metadata = wp_get_attachment_metadata( $this->attachment->ID );
|
||||
|
||||
if ( false === $metadata || ! is_array( $metadata ) ) {
|
||||
return new WP_Error(
|
||||
'regenerate_thumbnails_regenerator_no_metadata',
|
||||
__( 'Unable to load the metadata for this attachment.', 'regenerate-thumbnails' ),
|
||||
array(
|
||||
'status' => 404,
|
||||
'attachment' => $this->attachment,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! isset( $metadata['sizes'] ) ) {
|
||||
$metadata['sizes'] = array();
|
||||
}
|
||||
|
||||
// PDFs don't have width/height set.
|
||||
$width = ( isset( $metadata['width'] ) ) ? $metadata['width'] : null;
|
||||
$height = ( isset( $metadata['height'] ) ) ? $metadata['height'] : null;
|
||||
|
||||
require_once( ABSPATH . '/wp-admin/includes/image.php' );
|
||||
|
||||
$preview = false;
|
||||
if ( file_is_displayable_image( $fullsizepath ) ) {
|
||||
$preview = wp_get_attachment_url( $this->attachment->ID );
|
||||
} elseif (
|
||||
is_array( $metadata['sizes'] ) &&
|
||||
is_array( $metadata['sizes']['full'] ) &&
|
||||
! empty( $metadata['sizes']['full']['file'] )
|
||||
) {
|
||||
$preview = str_replace(
|
||||
wp_basename( $fullsizepath ),
|
||||
$metadata['sizes']['full']['file'],
|
||||
wp_get_attachment_url( $this->attachment->ID )
|
||||
);
|
||||
|
||||
if ( ! file_exists( $preview ) ) {
|
||||
$preview = false;
|
||||
}
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'name' => ( $this->attachment->post_title ) ? $this->attachment->post_title : sprintf( __( 'Attachment %d', 'regenerate-thumbnails' ), $this->attachment->ID ),
|
||||
'preview' => $preview,
|
||||
'relative_path' => _wp_get_attachment_relative_path( $fullsizepath ) . DIRECTORY_SEPARATOR . wp_basename( $fullsizepath ),
|
||||
'edit_url' => get_edit_post_link( $this->attachment->ID, 'raw' ),
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
'registered_sizes' => array(),
|
||||
'unregistered_sizes' => array(),
|
||||
);
|
||||
|
||||
$wp_upload_dir = dirname( $fullsizepath ) . DIRECTORY_SEPARATOR;
|
||||
|
||||
$registered_sizes = RegenerateThumbnails()->get_thumbnail_sizes();
|
||||
|
||||
if ( 'application/pdf' === get_post_mime_type( $this->attachment ) ) {
|
||||
$registered_sizes = array_intersect_key(
|
||||
$registered_sizes,
|
||||
array(
|
||||
'thumbnail' => true,
|
||||
'medium' => true,
|
||||
'large' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Check the status of all currently registered sizes.
|
||||
foreach ( $registered_sizes as $size ) {
|
||||
// Width and height are needed to generate the thumbnail filename.
|
||||
if ( $width && $height ) {
|
||||
$thumbnail = $this->get_thumbnail( $editor, $width, $height, $size['width'], $size['height'], $size['crop'] );
|
||||
|
||||
if ( $thumbnail ) {
|
||||
$size['filename'] = wp_basename( $thumbnail['filename'] );
|
||||
$size['fileexists'] = file_exists( $thumbnail['filename'] );
|
||||
} else {
|
||||
$size['filename'] = false;
|
||||
$size['fileexists'] = false;
|
||||
}
|
||||
} elseif ( ! empty( $metadata['sizes'][ $size['label'] ]['file'] ) ) {
|
||||
$size['filename'] = wp_basename( $metadata['sizes'][ $size['label'] ]['file'] );
|
||||
$size['fileexists'] = file_exists( $wp_upload_dir . $metadata['sizes'][ $size['label'] ]['file'] );
|
||||
} else {
|
||||
$size['filename'] = false;
|
||||
$size['fileexists'] = false;
|
||||
}
|
||||
|
||||
$response['registered_sizes'][] = $size;
|
||||
}
|
||||
|
||||
if ( ! $width && ! $height && is_array( $metadata['sizes']['full'] ) ) {
|
||||
$response['registered_sizes'][] = array(
|
||||
'label' => 'full',
|
||||
'width' => $metadata['sizes']['full']['width'],
|
||||
'height' => $metadata['sizes']['full']['height'],
|
||||
'filename' => $metadata['sizes']['full']['file'],
|
||||
'fileexists' => file_exists( $wp_upload_dir . $metadata['sizes']['full']['file'] ),
|
||||
);
|
||||
}
|
||||
|
||||
// Look at the attachment metadata and see if we have any extra files from sizes that are no longer registered.
|
||||
foreach ( $metadata['sizes'] as $label => $size ) {
|
||||
if ( ! file_exists( $wp_upload_dir . $size['file'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// An unregistered size could match a registered size's dimensions. Ignore these.
|
||||
foreach ( $response['registered_sizes'] as $registered_size ) {
|
||||
if ( $size['file'] === $registered_size['filename'] ) {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $registered_sizes[ $label ] ) ) {
|
||||
/* translators: Used for listing old sizes of currently registered thumbnails */
|
||||
$label = sprintf( __( '%s (old)', 'regenerate-thumbnails' ), $label );
|
||||
}
|
||||
|
||||
$response['unregistered_sizes'][] = array(
|
||||
'label' => $label,
|
||||
'width' => $size['width'],
|
||||
'height' => $size['height'],
|
||||
'filename' => $size['file'],
|
||||
'fileexists' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
/**
|
||||
* Regenerate Thumbnails: REST API controller class
|
||||
*
|
||||
* @package RegenerateThumbnails
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Registers new REST API endpoints.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
class RegenerateThumbnails_REST_Controller extends WP_REST_Controller {
|
||||
/**
|
||||
* The namespace for the REST API routes.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $namespace = 'regenerate-thumbnails/v1';
|
||||
|
||||
/**
|
||||
* Register the new routes and endpoints.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function register_routes() {
|
||||
register_rest_route( $this->namespace, '/regenerate/(?P<id>[\d]+)', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::ALLMETHODS,
|
||||
'callback' => array( $this, 'regenerate_item' ),
|
||||
'permission_callback' => array( $this, 'permissions_check' ),
|
||||
'args' => array(
|
||||
'only_regenerate_missing_thumbnails' => array(
|
||||
'description' => __( "Whether to only regenerate missing thumbnails. It's faster with this enabled.", 'regenerate-thumbnails' ),
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
),
|
||||
'delete_unregistered_thumbnail_files' => array(
|
||||
'description' => __( 'Whether to delete any old, now unregistered thumbnail files.', 'regenerate-thumbnails' ),
|
||||
'type' => 'boolean',
|
||||
'default' => false,
|
||||
),
|
||||
'update_usages_in_posts' => array(
|
||||
'description' => __( 'Whether to update the image tags in any posts that make use of this attachment.', 'regenerate-thumbnails' ),
|
||||
'type' => 'boolean',
|
||||
'default' => true,
|
||||
),
|
||||
'update_usages_in_posts_post_type' => array(
|
||||
'description' => __( 'The types of posts to update. Defaults to all public post types.', 'regenerate-thumbnails' ),
|
||||
'type' => 'array',
|
||||
'default' => array(),
|
||||
'validate_callback' => array( $this, 'is_array' ),
|
||||
),
|
||||
'update_usages_in_posts_post_ids' => array(
|
||||
'description' => __( 'Specific post IDs to update rather than any posts that use this attachment.', 'regenerate-thumbnails' ),
|
||||
'type' => 'array',
|
||||
'default' => array(),
|
||||
'validate_callback' => array( $this, 'is_array' ),
|
||||
),
|
||||
'update_usages_in_posts_posts_per_loop' => array(
|
||||
'description' => __( "Posts to process per loop. This is to control memory usage and you likely don't need to adjust this.", 'regenerate-thumbnails' ),
|
||||
'type' => 'integer',
|
||||
'default' => 10,
|
||||
'sanitize_callback' => 'absint',
|
||||
),
|
||||
),
|
||||
),
|
||||
) );
|
||||
|
||||
register_rest_route( $this->namespace, '/attachmentinfo/(?P<id>[\d]+)', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'attachment_info' ),
|
||||
'permission_callback' => array( $this, 'permissions_check' ),
|
||||
),
|
||||
) );
|
||||
|
||||
register_rest_route( $this->namespace, '/featuredimages', array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'featured_images' ),
|
||||
'permission_callback' => array( $this, 'permissions_check' ),
|
||||
'args' => $this->get_paging_collection_params(),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a filter to allow excluding site icons via a query parameter.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function register_filters() {
|
||||
add_filter( 'rest_attachment_query', array( $this, 'maybe_filter_out_site_icons' ), 10, 2 );
|
||||
add_filter( 'rest_attachment_query', array( $this, 'maybe_filter_mimes_types' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* If the exclude_site_icons parameter is set on a media (attachment) request,
|
||||
* filter out any attachments that are or were being used as a site icon.
|
||||
*
|
||||
* @param array $args Key value array of query var to query value.
|
||||
* @param WP_REST_Request $request The request used.
|
||||
*
|
||||
* @return array Key value array of query var to query value.
|
||||
*/
|
||||
public function maybe_filter_out_site_icons( $args, $request ) {
|
||||
if ( empty( $request['exclude_site_icons'] ) ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
if ( ! isset( $args['meta_query'] ) ) {
|
||||
$args['meta_query'] = array();
|
||||
}
|
||||
|
||||
$args['meta_query'][] = array(
|
||||
'key' => '_wp_attachment_context',
|
||||
'value' => 'site-icon',
|
||||
'compare' => 'NOT EXISTS',
|
||||
);
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the is_regeneratable parameter is set on a media (attachment) request,
|
||||
* filter results to only include images and PDFs.
|
||||
*
|
||||
* @param array $args Key value array of query var to query value.
|
||||
* @param WP_REST_Request $request The request used.
|
||||
*
|
||||
* @return array Key value array of query var to query value.
|
||||
*/
|
||||
public function maybe_filter_mimes_types( $args, $request ) {
|
||||
if ( empty( $request['is_regeneratable'] ) ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$args['post_mime_type'] = array();
|
||||
foreach ( get_allowed_mime_types() as $mime_type ) {
|
||||
if ( 'image/svg+xml' === $mime_type ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 'application/pdf' == $mime_type || 'image/' == substr( $mime_type, 0, 6 ) ) {
|
||||
$args['post_mime_type'][] = $mime_type;
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the paging query params for the collections.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @return array Query parameters for the collection.
|
||||
*/
|
||||
public function get_paging_collection_params() {
|
||||
return array_intersect_key(
|
||||
parent::get_collection_params(),
|
||||
array_flip( array( 'page', 'per_page' ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Regenerate the thumbnails for a specific media item.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return true|WP_Error True on success, otherwise a WP_Error object.
|
||||
*/
|
||||
public function regenerate_item( $request ) {
|
||||
$regenerator = RegenerateThumbnails_Regenerator::get_instance( $request->get_param( 'id' ) );
|
||||
|
||||
if ( is_wp_error( $regenerator ) ) {
|
||||
return $regenerator;
|
||||
}
|
||||
|
||||
$result = $regenerator->regenerate( array(
|
||||
'only_regenerate_missing_thumbnails' => $request->get_param( 'only_regenerate_missing_thumbnails' ),
|
||||
'delete_unregistered_thumbnail_files' => $request->get_param( 'delete_unregistered_thumbnail_files' ),
|
||||
) );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ( $request->get_param( 'update_usages_in_posts' ) ) {
|
||||
$posts_updated = $regenerator->update_usages_in_posts( array(
|
||||
'post_type' => $request->get_param( 'update_usages_in_posts_post_type' ),
|
||||
'post_ids' => $request->get_param( 'update_usages_in_posts_post_ids' ),
|
||||
'posts_per_loop' => $request->get_param( 'update_usages_in_posts_posts_per_loop' ),
|
||||
) );
|
||||
|
||||
// If wp_update_post() failed for any posts, return that error.
|
||||
foreach ( $posts_updated as $post_updated_result ) {
|
||||
if ( is_wp_error( $post_updated_result ) ) {
|
||||
return $post_updated_result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->attachment_info( $request );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a bunch of information about the current attachment for use in the UI
|
||||
* including details about the thumbnails.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return array|WP_Error The data array or a WP_Error object on error.
|
||||
*/
|
||||
public function attachment_info( $request ) {
|
||||
$regenerator = RegenerateThumbnails_Regenerator::get_instance( $request->get_param( 'id' ) );
|
||||
|
||||
if ( is_wp_error( $regenerator ) ) {
|
||||
return $regenerator;
|
||||
}
|
||||
|
||||
return $regenerator->get_attachment_info();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return attachment IDs that are being used as featured images.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function featured_images( $request ) {
|
||||
global $wpdb;
|
||||
|
||||
$page = $request->get_param( 'page' );
|
||||
$per_page = $request->get_param( 'per_page' );
|
||||
|
||||
if ( 0 == $per_page ) {
|
||||
$per_page = 10;
|
||||
}
|
||||
|
||||
$featured_image_ids = $wpdb->get_results( $wpdb->prepare(
|
||||
"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",
|
||||
$per_page,
|
||||
( $per_page * $page ) - $per_page
|
||||
) );
|
||||
|
||||
$total = $wpdb->get_var( "SELECT FOUND_ROWS()" );
|
||||
$max_pages = ceil( $total / $per_page );
|
||||
|
||||
if ( $page > $max_pages && $total > 0 ) {
|
||||
return new WP_Error( 'rest_post_invalid_page_number', __( 'The page number requested is larger than the number of pages available.' ), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$response = rest_ensure_response( $featured_image_ids );
|
||||
|
||||
$response->header( 'X-WP-Total', (int) $total );
|
||||
$response->header( 'X-WP-TotalPages', (int) $max_pages );
|
||||
|
||||
$request_params = $request->get_query_params();
|
||||
$base = add_query_arg( $request_params, rest_url( $this->namespace . '/featuredimages' ) );
|
||||
|
||||
if ( $page > 1 ) {
|
||||
$prev_page = $page - 1;
|
||||
|
||||
if ( $prev_page > $max_pages ) {
|
||||
$prev_page = $max_pages;
|
||||
}
|
||||
|
||||
$prev_link = add_query_arg( 'page', $prev_page, $base );
|
||||
$response->link_header( 'prev', $prev_link );
|
||||
}
|
||||
|
||||
if ( $max_pages > $page ) {
|
||||
$next_page = $page + 1;
|
||||
$next_link = add_query_arg( 'page', $next_page, $base );
|
||||
|
||||
$response->link_header( 'next', $next_link );
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the current user is allowed to use this endpoint.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @param WP_REST_Request $request Full data about the request.
|
||||
*
|
||||
* @return bool Whether the current user has permission to regenerate thumbnails.
|
||||
*/
|
||||
public function permissions_check( $request ) {
|
||||
return current_user_can( RegenerateThumbnails()->capability );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a variable is an array or not. This is needed because 3 arguments are
|
||||
* passed to validation callbacks but is_array() only accepts one argument.
|
||||
*
|
||||
* @since 3.0.0
|
||||
*
|
||||
* @see https://core.trac.wordpress.org/ticket/34659
|
||||
*
|
||||
* @param mixed $param The parameter value to validate.
|
||||
* @param WP_REST_Request $request The REST request.
|
||||
* @param string $key The parameter name.
|
||||
*
|
||||
* @return bool Whether the parameter is an array or not.
|
||||
*/
|
||||
public function is_array( $param, $request, $key ) {
|
||||
return is_array( $param );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user