Hello,
I'm using WP 4.0 and I see that my Media Library loads full size attachments in grid view, this is really slow.
I know how to customize image format in list view and there are a lot of free plugins that do this (like //wordpress.org/plugins/media-thumbnail-enlarger/screenshots/).
I need to know how to set image format for <strong>grid view</strong> <em>without modifying wp core files</em>.
To reproduce my situation open a WordPress 4 dashboard and go to Media screen (/wp-admin/upload.php) then look at the attached image:
1) The Grid view is selected.
2) The thumbnails are just the original file resized via CSS, I want to load the "thumbnail" size or any of my custom image size.
Dbranes answers:
The grid view uses a Backbone micro template and fetches the data via ajax.
<strong>Why medium or full size in the grid view?:</strong>
The grid view is rendered with:
if ( 'image' === options.type ) {
options.size = this.imageSize();
}
in the <em>media-view.js</em> file.
In the <em>imageSize()</em> method you can see that <em>medium</em> size is used and if that size doesn't exists the <em>actual/full</em> size is used instead:
/**
* @param {string} size
* @returns {Object}
*/
imageSize: function( size ) {
var sizes = this.model.get('sizes');
size = size || 'medium';
// Use the provided image size if possible.
if ( sizes && sizes[ size ] ) {
return _.clone( sizes[ size ] );
} else {
return {
url: this.model.get('url'),
width: this.model.get('width'),
height: this.model.get('height'),
orientation: this.model.get('orientation')
};
}
},
If your <em>medium</em> size is missing, this could be easily solved with for example:
if ( 'image' === options.type ) {
options.size = this.imageSize( 'thumbnail' );
}
or some other image size, but we don't want to modify the core files.
<strong>A workaround:</strong>
Here's a workaround to add the missing <em>medium</em> size with another image size:
/**
* Media Grid View: Replace the "medium" image size with "replace_this_image_size" image size, when the former doesn't exists.
*
* @see http://www.wpquestions.com/question/showChronoLoggedIn/id/9941
*/
add_filter( 'wp_prepare_attachment_for_js', function( $response, $attachment, $meta ) {
$use_size = 'some_image_size'; // Edit this to your needs.
if( 'image' === $response['type'] && ! isset( $response['sizes']['medium'] ) ) {
if( isset( $response['sizes'][$use_size] ) ) {
$response['sizes']['medium'] = $response['sizes'][$use_size];
} else {
$response['sizes']['medium'] = wp_get_attachment_image_src( $response['id'], $use_size );
}
}
return $response;
}, 10, 3 );
<strong>Another workaround:</strong>
Another drastic approach would be to override (from a plugin code without modifying the core files) the Backbone micro template to your needs, for example with a check like:
<# if ( data.sizes.medium ) { #>
<img src="{{ data.sizes.medium.url }}" draggable="false" alt="" />
<# } else if ( data.sizes.replace_this_image_size) { #>
<img src="{{ data.sizes.replace_this_image_size.url }}" draggable="false" alt="" />
<# } else { #>
<img src="{{ data.size.url }}" draggable="false" alt="" />
<# } #>
but I'm not sure how frequently these micro templates are changing between WordPress versions.
Professore comments:
Thank you Dbranes, your answer definitely gave me the right direction, here is my working, perfect fitting solution:
add_filter( 'wp_prepare_attachment_for_js', function( $response, $attachment, $meta ) {
if (!empty($response)) {
$sizes_list = array(
'FOUR',
'THREE',
'TWO',
'ONE'
);
while ( !isset( $response['sizes']['medium'] ) && count( $sizes_list ) > 0 ) {
$cur_size = array_pop( $sizes_list );
if ( isset( $response['sizes'][$cur_size] ) ) {
$response['sizes']['medium'] = $response['sizes'][$cur_size];
}
}
}
return $response;
}, 999, 3 );
add_filter( 'image_size_names_choose', function( $sizes ) {
return array_merge( $sizes, array(
'ONE' => __('One'),
'TWO' => __('Two'),
'THREE' => __('Three'),
'FOUR' => __('Four')
) );
}, 10, 1 );
I needed to filter "image_size_names_choose" to get my sizes, then "wp_prepare_attachment_for_js", as you suggested, to set "medium" size.
Thank you.
Dbranes comments:
Glad to hear it worked out for you.
Good idea to reuse the image sizes set by <em>image_size_names_choose</em>.
In general it would be better to have not too many image sizes in <em>image_size_names_choose</em>, to limit the number of database calls. (just like you did in your solution by using few sizes).
Remy answers:
Are you sure there is no plugin in play here, or a missing setting ? Because on my own website, images in grid view are resized to the medium size specified in "Settings -> Medias"
Professore comments:
You are true, I'm missing the medium size.
Now my problem is that I have 300k+ images and a complete regeneration of every medium thumbnail is unthinkable.
There is a way to use one of my other thumbnail size for this screen?
Remy comments:
I don't think there is a filter available for that. Are any of the regenerate thumbnails plugins out of the question ?
Professore comments:
I have 300000 uploaded images and 22 sizes for each of them, I dont't want to generate 300000 more images, I should use one of my (already existing) 22 custom sizes.
Now I'm going to fix this issue modifying one or more wp core files, but i hope to find a non-destructive solution.
Remy comments:
Maybe if you set the medium size in the settings to one of your custom sizes, it will work
John Cotton answers:
Why don't you want to regenerate all the images? Because you think it has to be done by hand, or that it will take too long to run the code?
If the former, here's the code that will regenerate the images to the new sizes:
function regenerate_thumbs() {
require_once( ABSPATH.'/wp-admin/includes/file.php');
require_once( ABSPATH.'/wp-admin/includes/media.php');
require_once( ABSPATH.'/wp-admin/includes/image.php');
if( current_user_can('administrator') ) {
@set_time_limit( 0 ); // ...this could take a while
$images = get_posts( array('post_type' => 'attachment', 'post_status' => 'any' ) );
foreach( $images as $img ) {
if ( substr( $img->post_mime_type, 0, 6 ) == 'image/' ) {
$fullsizepath = get_attached_file( $img->ID );
if( file_exists( $fullsizepath ) ) {
$metadata = wp_generate_attachment_metadata( $img->ID, $fullsizepath );
if( !is_wp_error( $metadata ) && !empty( $metadata ) ) {
wp_update_attachment_metadata( $img->ID, $metadata );
}
}
}
}
}
}
It is going to take a while to run with your number of images/sizes, but it's an easy thing to do if it has to be done.