WordPress Post Thumbnails with Caption

This is a tidying up of a WordPress support forum topic – nothing really that I came up with myself.

The question is how to post the caption with a post thumbnail, aka featured image, in an ordered way.

This code below is tested in wp3.3.

(code version for wp4.1 to remove warning messages related to undefined variables, etc – see pastebin http://pastebin.com/ciLUSeJ4 )

//POST THUMBNAIL AND CAPTION STYLED SIMILAR TO .wp-caption//
function the_post_thumbnail_and_caption($size = '', $attr = '') {
global $post;
$thumb_id = get_post_thumbnail_id($post->ID);
	$args = array(
		'post_type' => 'attachment',
		'post_status' => null,
		'parent' => $post->ID,
		'include'  => $thumb_id
	);

$thumbnail_image = get_posts($args);

if ($thumb_id && $thumbnail_image && isset($thumbnail_image[0])) {
	$image = wp_get_attachment_image_src( $thumb_id, $size );
	$image_width = $image[1];

	if($attr) $attr_class = $attr['class'];
	$attr['class'] = ''; //move any 'class' attributes to the outer div, and remove from the thumbnail

	$output = '<div class="thumbnail-caption attachment-'.$size.($attr?' '.$attr_class:'').'" style="width: ' . ($image_width) . 'px">';

	$output .= get_the_post_thumbnail($post->ID, $size, $attr);

	/* to show the thumbnail caption */
	$caption = $thumbnail_image[0]->post_excerpt;
	if($caption) {
		$output .= '<p class="thumbnail-caption-text">';
		$output .= $caption;
		$output .= '</p>';
	}

	/* //Uncomment to show thumbnail title
	$title = $thumbnail_image[0]->post_title;
	if($title) {
		$output .= '<p class="thumbnail-title-text">';
		$output .= $title;
		$output .= '</p>';
	} */

	/* //Uncomment to show the thumbnail description
	$descr = $thumbnail_image[0]->post_content;
	if($descr) {
		$output .= '<p class="thumbnail-description-text">';
		$output .= $descr;
		$output .= '</p>';
	} */

	/* //Uncomment to show the thumbnail alt field
	$alt = get_post_meta($thumb_id, '_wp_attachment_image_alt', true);
	if(count($alt)) {
		$output .= '<p class="thumbnail-alt-text">';
		$output .= $alt;
		$output .= '</p>';
	} */

	$output .= '</div>';
	}
echo $output;
}

(above code edited Oct 2012)

Possible styles for that to make it look like an ordinary wp caption:

.thumbnail-caption { padding: 5px; background: #f5f5f5; border: 1px solid #ddd; }
.thumbnail-caption-text { text-align: center; margin-bottom: 5px; font-size: 90%; }
/*
.thumbnail-title-text { text-align: center; margin-bottom: 5px; font-size: 90%; }
.thumbnail-description-text { text-align: center; margin-bottom: 5px; font-size: 90%; }
.thumbnail-alt-text { text-align: center; margin-bottom: 5px; font-size: 90%; }
*/

Use the code in the template, for instance in single.php, with one of the registered thumbnail sizes as parameter; example:

<?php the_post_thumbnail_and_caption('large',array('class' => 'alignleft')); ?>

A huge ‘thank you’ to all the contributers to this topic in the forum.

PS

my personal extension of the idea –
to add the functionality using a filter function:

// dec 17 2016 @alchymyth
// filter to show caption, if available, on thumbnail, wrapped with '.wp-caption thumb-caption' div;
// show just the thumbnail otherwise

add_filter( 'post_thumbnail_html', 'add_post_thumbnail_caption',10,5 );

function add_post_thumbnail_caption($html, $post_id, $post_thumbnail_id, $size, $attr) {

if( $html == '' ) { 
 
	return $html;
 
} else {
 
	$out = '';
 
	$thumbnail_image = get_posts(array('p' => $post_thumbnail_id, 'post_type' => 'attachment'));
 
	if ($thumbnail_image && isset($thumbnail_image[0])) {
 
		$image = wp_get_attachment_image_src($post_thumbnail_id, $size);

		if($thumbnail_image[0]->post_excerpt) 
			$out .= '<div class="wp-caption thumb-caption">';
 
		$out .= $html;
 
		if($thumbnail_image[0]->post_excerpt) 
			$out .= '<p class="wp-caption-text thumb-caption-text">'.$thumbnail_image[0]->post_excerpt.'</p></div>';
  
	}

	return $out;
  
}
}

Simply use

the_post_thumbnail()

as usual.
The minor ‘downside’ of this approach is that the post thumbnail will get the caption added in any location it is used, which might not always be desired.

Here, for instance, is some css that will whow the caption only on ‘hover’:

.wp-caption.thumb-caption {
  padding:0;border:none; position:relative;
  }
.wp-caption.thumb-caption img {
  margin: 0;
}
.wp-caption.thumb-caption .wp-caption-text {
  position:absolute; bottom:10px; left: 0;
  background: #111; color: #fff; font-weight: bold; text-align: left;
  display:block; padding:3px 3%; width:94%;
}
.wp-caption.thumb-caption:hover .wp-caption-text {
  visibility: hidden;
} 

Styling the First Post Different

How to style the first / last / latest / newest post in a WordPress site different?

The default advice usually is to use a counter variable and a conditional statement to check for the first post in the loop; that approach obviously works fine, however requires a few lines of extra code before and in the loop.

A more condensed approach is to use $wp_query->current_post which returns the current post number in the loop, starting with 0 (zero) for the first post.

This can be combined with a check, if the page is really the first page, and not one of the paginated pages, using !is_paged().

If the goal is just to apply different css styles to the first post, it is best to add a unique css class to the post_class() which is used in most recent themes; like so: post_class($extra); to add the extra class to post_class.

All combined might look like (based on the code of content.php in Twenty Eleven):

<article id="post-<?php the_ID(); ?>" <?php $extra = ( $wp_query->current_post == 0 && !is_paged() ) ? 'specialclass' : ''; post_class($extra); ?>>

If the goal is to have a totally different output for the first post, then a conditional structure is needed (within the loop, wrapping the post output):

<?php if( $wp_query->current_post == 0 && !is_paged() ) : ?>
/*the output of the first post*?
<?php else : ?>
/*the output of all other posts*/
<?php endif; ?>

Posts in Columns – A New Twist on an Old Problem

To organize posts into three columns (edit: semantically more correct would be to call it ‘three posts per row’ as this is the way the posts are organized), you first need to generate a column dependant css class for each post; this will be added to the post div within the loop.

The core trick to generate different css classes for posts in the first coliumn, the second column, and the last column:

<?php $column = ($column == '') ? 'first' : (($column == 'first') ? 'middle' : (($column == 'middle') ? 'last' : 'first' )); ?>

This line of code needs to be within the loop, just before the post div.

To achieve more or less the same, you could obviously also use a counter variable and the modulus operator, as i have elaborated on in my earlier article ‘More-Than-Zebra style WordPress loop’. However, the above method is simpler and easier to apply within a single line of code.

The second step is to add this as a css class to the post div:

a – assume a theme without the use of ‘post_class()’; the typical opening div would look like:

<div class="post" id="post-<?php the_ID(); ?>">

This is changed into:

<div class="post <?php echo $column; ?>" id="post-<?php the_ID(); ?>">

b – in a theme using the ‘post_class()’, the new code would look like:

<div <?php post_class($column); ?> id="post-<?php the_ID(); ?>">

Third and last step: to tell the browser what to do with the new css classes, add some styles to style.css of the theme:

/* .first, .middle, .last styling of posts on home page for three column */
.first, .middle, .last { width: 32%; float:left; clear:none!important; }
.first { margin-right: 2%; clear:both!important; }
.middle { margin-right: 2%; }

Final details depend on the existing theme.

edit & ps:
if you just want to mark the first post in each row – for instance to add the ‘clear:both;’ and a different margin there – try to work with:
(example for 5 columns)

<div <?php $column = ($wp_query->current_post%5 == 0) ? 'first' : ''; post_class($column); ?> id="post-<?php the_ID(); ?>">

The Death of Mystery Man

Are you fed up with the little grey mystery man or his little weird monster brothers and sisters?

You know what i mean – showing up in your comments for all those without a gravatar?

Give them the push and create your own design, supporting your own branding.

Here is how it is done:

add_filter( 'avatar_defaults', 'newgravatar' );
function newgravatar ($avatar_defaults) {
    $myavatar = get_bloginfo('template_directory') . '/images/own-gravatar.jpg';
    $avatar_defaults[$myavatar] = "Own";
    return $avatar_defaults;
}

Add the code to functions.php of your theme; get creative with your graphic; upload it into the images folder of your theme (you might need to adjust the code, if your theme images are in a different folder), and activate it as the new default comment avatar.

Life without Mystery Man will never be the same …

add_filter( 'avatar_defaults', 'newgravatar' );
function newgravatar ($avatar_defaults) {
    $myavatar = get_bloginfo('template_directory') . '/images/own-gravatar.jpg';
    $avatar_defaults[$myavatar] = "Own";
    return $avatar_defaults;
}