Create a Black & White Thumbnail in WordPress
by c.bavota | Posted in Tutorials | 44 comments
A while back I worked on a site that required a hover effect where a black and white image faded into a color image. I wrote a tutorial called Creating a Mouseover Fade Effect with jQuery on the jQuery technique I used for the hover. That effect no longer requires jQuery since we can now use CSS3 transitions (see A Simple Fade with CSS3) but the real issue was with having to upload two separate images to get the effect to work, which required an image editing software like Photoshop. Thankfully, Otto just wrote a great article on a way that you can use some built in WordPress functions and a little PHP to automatically create a black and white thumbnail when you upload an image.
First we need to create a new thumbnail using add_image_size(). We’ll use the same thumbnail settings from the WordPress Media page in the wp-admin. Add this to your functions.php file within the PHP tags:
add_action('after_setup_theme','bw_images_size');
function bw_images_size() {
$crop = get_option('thumbnail_crop')==1 ? true : false;
add_image_size('thumbnail-bw', get_option('thumbnail_size_w'), get_option('thumbnail_size_h'), $crop);
}
With that in place, we can now add the following function which will automatically create a black and white thumbnail:
add_filter('wp_generate_attachment_metadata','bw_images_filter');
function bw_images_filter($meta) {
$file = wp_upload_dir();
$file = trailingslashit($file['path']).$meta['sizes']['thumbnail-bw']['file'];
list($orig_w, $orig_h, $orig_type) = @getimagesize($file);
$image = wp_load_image($file);
imagefilter($image, IMG_FILTER_GRAYSCALE);
//imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);
switch ($orig_type) {
case IMAGETYPE_GIF:
$file = str_replace(".gif", "-bw.gif", $file);
imagegif( $image, $file );
break;
case IMAGETYPE_PNG:
$file = str_replace(".png", "-bw.png", $file);
imagepng( $image, $file );
break;
case IMAGETYPE_JPEG:
$file = str_replace(".jpg", "-bw.jpg", $file);
imagejpeg( $image, $file );
break;
}
return $meta;
}
Whenever you upload an image, this function will create a new black and white thumbnail automatically. I also added a Gaussian Blur but commented it out. Remove those two slashes “//” to add a Gaussian Blur to your new black and white thumbnail. See other available filters.
Once you’ve added the above code, you can use get_post_thumbnail() within your WordPress loop to display the two images for the effect:
if(function_exists('has_post_thumbnail') && has_post_thumbnail()) {
echo '<a href="'.get_permalink().'" class="fade-image">';
the_post_thumbnail('thumbnail-bw', array('class'=>'fade-image-a'));
the_post_thumbnail('thumbnail', array('class'=>'fade-image-b'));
echo '</a>';
}
This displays both images and surrounds them by an anchor tag. All we need is a little CSS3 to get our fade working:
.fade-image {
display: block;
position: relative;
width: 150px;
height: 150px;
}
.fade-image-a,
.fade-image b {
position: absolute;
left: 0;
top: 0;
}
.fade-image-a {
z-index: 5;
opacity: 1;
transition: opacity .25s ease-in-out;
-moz-transition: opacity .25s ease-in-out;
-webkit-transition: opacity .25s ease-in-out;
}
.fade-image-a:hover {
opacity: 0;
}
The fade will only work in browsers that support CSS3 transitions but everything else should work on any server that supports the latest release of WordPress.





You can even make it sepia by adding this line of code right underneath the first
imagefilter():Thanks for sharing this code! Except I’m runing into a weird issue when trying to implement it. It’s related to the uploaded image’s size (pixel size, meaning its dimensions). Copied the code literally to my theme’s functions.php, and it works a charm with images larger than the size specified in the add_image_size call. But when using an image smaller than or equal to the size specified, the uploader in WordPress gives me errors and doesn’t process the image size (either from the media section of the admin environment, of from a specific post or page). The error:
Warning: imagefilter() expects parameter 1 to be resource, string given.
Any idea what’s causing this? The only real difference between my situation and a clean install is that I’ve also added a few other add_image_size calls for other purposes in my site. I’m also adding the same size twice (one black/white, one regular), but that doesn’t seem to be a problem with the larger images.
You can’t actually add two images with the same size. It breaks everything. The code above works by duplicating the thumbnail size but it changes the naming convention by adding the “-bw”. That is the only way it will work but I actually haven’t tried it with two new image sizes.
The codes did work and I got it all now up and running. Thanks to you!
Thanks! Been looking for this. It works like a charm! THanks a ton for sharing!
Just to add on to this, if the uploaded image meets the size requirements that you’ve set as your thumbnail, WordPress will use the full size image instead of referencing it through the new image size you’ve added. For example, if you set your thumbnail to be 188 x 188, hard crop:
set_post_thumbnail_size(188, 188, true); add_image_size('thumbnail-bw', 188, 188, true); // To reference the black&white thumbnail in the template filesand then upload an image that is 188 x 188, WordPress will not create an entry for it as thumbnail-bw in the image sizes in the meta array. It will instead reference it through the original size in the ‘file’ index of the meta array. I’ve modified this function in the code below to cope with that case, hope it helps someone!
function bw_images_filter($meta) { $file = wp_upload_dir(); // Need to check to see if their was even a generated 'thumb-m' in case the image uploaded was the appropriate size // and therefore will be used in it's largest form if (isset($meta['sizes']['thumbnail-bw'])) { $file = trailingslashit($file['path']).$meta['sizes']['thumbnail-bw']['file']; // The thumbnail didn't get created because the uploaded image was the correct size before scaling / cropping. // Need to get base directory instead of path here because the original file already has the year/month structure in it's file attribute. } else { $file = trailingslashit($file['basedir']).$meta['file']; $explodedPath = explode("/", $meta['file']); // Manually insert the thumbnail-bw that didn't get created upon upload and append '-bw' to the filename $explodedFileName = explode(".", $exploded[2]); $updatedFileName = $explodedFileName[0] . '-bw.' . $explodedFileName[1]; $meta['sizes']['thumbnail-bw']['file'] = $updatedFileName; $meta['sizes']['thumbnail-bw']['width'] = 188; // Set these dimensions to match the dimensions for the add_image_size above $meta['sizes']['thumbnail-bw']['height'] = 188; } list($orig_w, $orig_h, $orig_type) = @getimagesize($file); $image = wp_load_image($file); imagefilter($image, IMG_FILTER_GRAYSCALE); //imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR); switch ($orig_type) { case IMAGETYPE_GIF: $file = str_replace(".gif", "-bw.gif", $file); imagegif($image, $file); break; case IMAGETYPE_PNG: $file = str_replace(".png", "-bw.png", $file); imagepng($image, $file); break; case IMAGETYPE_JPEG: $file = str_replace(".jpg", "-bw.jpg", $file); imagejpeg($image, $file); break; } return $meta; } add_filter('wp_generate_attachment_metadata','bw_images_filter');When I found your post I was so excited to find precisely what I was looking for… it’s been several hours since I found it originally, though, and I keep running into the same problem. The B&W image file is being made and saved alongside the color “feature image”, but the HTML that comes up shows two copies of the color version right next to each other. The fade in/out functionality works, and I receive no errors, but the src attribute of the tag points to the color version of the file. Any ideas? Help for a WP beginner would be greatly appreciated, and thank you for the very helpful tutorial!
Thanx for the tut, the B&W thumbs are properly created but the “-bw” suffix is not written in the code. I’ve got twice the same file with a different class
This is a part my function.php file :
if ( function_exists( 'add_theme_support' ) ) { add_theme_support( 'post-thumbnails' ); } //Debut noir et blanc add_action('after_setup_theme','bw_images_size'); function bw_images_size() { $crop = get_option('thumbnail_crop')==1 ? true : false; add_image_size('thumbnail-bw', get_option('thumbnail_size_w'), get_option('thumbnail_size_h'), $crop); } add_filter('wp_generate_attachment_metadata','bw_images_filter'); function bw_images_filter($meta) { $file = wp_upload_dir(); $file = trailingslashit($file['path']).$meta['sizes']['thumbnail-bw']['file']; list($orig_w, $orig_h, $orig_type) = @getimagesize($file); $image = wp_load_image($file); imagefilter($image, IMG_FILTER_GRAYSCALE); //imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR); switch ($orig_type) { case IMAGETYPE_GIF: $file = str_replace(".gif", "-bw.gif", $file); imagegif( $image, $file ); break; case IMAGETYPE_PNG: $file = str_replace(".png", "-bw.png", $file); imagepng( $image, $file ); break; case IMAGETYPE_JPEG: $file = str_replace(".jpg", "-bw.jpg", $file); imagejpeg( $image, $file ); break; } return $meta; } //fin noir et blanc function get_post_thumbnail(){ if(function_exists('has_post_thumbnail') && has_post_thumbnail()) { echo '<a href="'.get_permalink().'">'; the_post_thumbnail('thumbnail-bw', array('class'=>'fade-image-a')); the_post_thumbnail('thumbnail', array('class'=>'fade-image-b')); echo '</a>'; } }and this is the call within the loop in page.php
Last words didn’t get published, this is the call within the loop
Thx for your help !
I just noticed an issue where this code will not work on older posts. It is a problem that also occurs in Otto’s plugin. I just started a discussion in the WordPress forum:
http://wordpress.org/support/topic/plugin-imagefx-doesnt-work-on-older-posts
Hopefully a solution will present itself.
Hi there, thanks for the post.
Sadly I’ve got the same problem as Titifrim and Phil, the thumbnails are getting duplicated, modified and renamed but the original color image gets returned for both thumbnail and thumbnail-bw. Any ideas?
Oh, if it’s helpful the sit eI’m building is on WordPress 3.3 beta1. I have a few other custom thumbnail sizes all working fine.
I made a plugin to make this simpler.
http://wordpress.org/extend/plugins/imagefx/
o my goodness, thank you, thank you, thank you otto because html codes are my weakness
Awesome. Thanks Otto.
Great plugin Otto !… Unfortunately I still have the same problem with the thumbnail within the loop. Not exactly the same one, I must admit it cause two different files are called this time : the thumbnail (../filename-150×150-sepia.jpg” class=”fade-image-a wp-post-image” alt=”filename” title=”filename” />) and the medium one (../filename.jpg” class=”fade-image-b wp-post-image” alt=”filename” title=”filename” />) ??? I don’t understand… so close !
Hey Great post, Thanks!
My site theme has thumbnail rollovers built in.. does this make things allot more complicated? How can I replace my current setup with this one?
Cheers,
Simon
I’ve run into the same problem as some of the other commenters – I’m just getting the colour thumbnail displayed twice, even though the black and white version exists. For some reason calling ‘thumbnail-bw’ isn’t recognised. Any suggestions?
Ok, I’ve done a little Googling and found a solution to the duplicate colour image issue that works for me.
First, here’s a function to get the URL of the post thumbnail. Put it in your functions.php file:
Then you can display your two thumbnails (hopefully one colour and one black and white now) on your page using this slightly updated code:
<?php $thumb = post_thumb_url(); $thumb_bw = str_replace(".jpg", "-bw.jpg", $thumb); if( function_exists( 'has_post_thumbnail' ) && has_post_thumbnail() ) { echo '<a href="'.get_permalink().'">'; echo ''; //the_post_thumbnail( 'thumbnail-bw', array( 'class'=>'fade-image-a' ) ); the_post_thumbnail('thumbnail', array( 'class'=>'fade-image-b' ) ); echo '</a>'; } ?>It might not be the cleanest way to do it, but it works. Hope it helps someone.
Hmmm, not sure why the code isn’t displaying correctly. Let’s try again:
function post_thumb_url() { global $post, $posts; $thumbnail = ''; ob_start(); the_post_thumbnail(); $toparse = ob_get_contents(); ob_end_clean(); preg_match_all('/src=("[^"]*")/i', $toparse, $img_src); $thumbnail = str_replace("\"", "", $img_src[1][0]); return $thumbnail; }<?php $thumb = post_thumb_url(); $thumb_bw = str_replace(".jpg", "-bw.jpg", $thumb); if( function_exists( 'has_post_thumbnail' ) && has_post_thumbnail() ) { echo '<a href="'.get_permalink().'">'; echo ''; //the_post_thumbnail( 'thumbnail-bw', array( 'class'=>'fade-image-a' ) ); the_post_thumbnail('thumbnail', array( 'class'=>'fade-image-b' ) ); echo '</a>'; } ?>Sorry folks, the blog is converting some of the characters so you’ll have to clean it up if you want to use it – it’s fairly obvious what you need to do though…
Hi! i’m having a problem.
With Matt’s code i solved the problem uploading the thumbnails, but now I don’t know why, in the loop are displaying the same thumbnail twice. But I know that thumbnail-bw.jpg exist in uploads folder!
Thanks!
the loop:
<?php $thumb = post_thumb_url(); $thumb_bw = str_replace(".jpg", "-bw.jpg", $thumb); if( function_exists( 'has_post_thumbnail' ) && has_post_thumbnail() ) { echo '<a href="'.get_permalink().'">'; echo ''; the_post_thumbnail( 'thumbnail-bw', array( 'class'=>'fade-image-a' ) ); the_post_thumbnail('thumbnail', array( 'class'=>'fade-image-b' ) ); echo '</a>'; } ?>the blog is converting some of the characters
Hmm. Sounds like the image is being created but then thumbnail-bw might somehow be registering the wrong image in the db. I would have to try to recreate this somehow in order to figure it out. Let me do some testing.
oh! thanks! I’m not a developer and it’s being dificult to me understand some codes!
With firebug i can see that it’s calling 2 imatges:
image 1: my_thumbnail_145x145.jpg
image 2: my_thumbnail_145x145.jpg
and I need:
image 1: my_thumbnail_145x145.jpg
image 2: my_thumbnail_145x145-bw.jpg
Thank you again!!!
Hey Great post, Thanks!
My site theme has thumbnail flash built in.. How can I replace current setup, for this does anyone know this?
Greets,
I’ve just noticed that the bw_images_filter function throws up error messages if the file type I’m uploading is not an image (such as a video for example).
I’ve managed to stop the function from creating the thumbnails if the filetype isn’t an image using the following code:
$image = wp_load_image($file); $ext = pathinfo($image, PATHINFO_EXTENSION); if ( $ext == ".gif" || $ext == ".png" || $ext == ".jpg" ) {… but I’m still getting the following error message, so I guess I need to do the file type check at a ‘higher’ level:
Warning: imagecreatefromstring() [function.imagecreatefromstring]: Empty string or invalid image in /home/ [...] /wp-includes/media.php on line 254
Any suggestions?
Ah ok, the code above just needed a bit of re-jigging like so:
list($orig_w, $orig_h, $orig_type) = @getimagesize($file); //$image = wp_load_image($file); $image = $file; $ext = pathinfo($image, PATHINFO_EXTENSION); if ( $ext == ".gif" || $ext == ".png" || $ext == ".jpg" ) { $image = wp_load_image($file); imagefilter($image, IMG_FILTER_GRAYSCALE); imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);… and so on.
Actually nope, using any of my code above breaks the B&W thumbnail creation. So, my question still stands – is there a way to stop the error messages showing if I try and upload a video?
Just to point out – the videos do upload ok, but just throw up this error message which is not going to look good when my client tries to use it
What is the error message?
The one I mentioned above (see below). Sorry, I wasn’t very clear
Warning: imagecreatefromstring() [function.imagecreatefromstring]: Empty string or invalid image in /home/ [...] /wp-includes/media.php on line 254
Basically all the edits I’ve tried on the code stop the B&W thumbnails from being created. What I want to do is to allow other file type uploads through the Media Uploader other than just images (I have clients who use it to upload video, PDFs etc.)
Thanks.
Hi,
can you help me with this issue when I try to upload a new thumb?:
Warning: imagefilter() expects parameter 1 to be resource, string given in /web/htdocs/www.riscovo.com/home/wordpress/wp-content/themes/riscovo2011/functions.php on line 45
Note that line 45 in my functions.php is:
imagefilter($image, IMG_FILTER_GRAYSCALE);
I get this warning when I give a new featured image to a existing post.
I dont get this warning when I work on a brand new post…. but in this case the b/w image will still not work: I only get a coloured standard result. =(
I have trying to figure out this one. Can’t seem to find the reason.
Anyone figure out the issue with the code calling the color image twice when it should call the black and white version?
Would be awesome if I could get this working.
I see a lot of people having the same response. No fix posted though.