2026年8月31日
2026年8月31日
WordPressのthe_post_thumbnail()にカスタムHTMLラッパーを追加する方法
the_post_thumbnail() が出力するアイキャッチ画像を <figure> やリンク付きの <div> で囲みたい場合、方法は「テンプレートで囲む」「post_thumbnail_html フィルターで全体に適用する」「専用の関数を作る」の3つです。この記事では、それぞれの使いどころと、レスポンシブ画像(srcset)や遅延読み込みを壊さず、レイアウトのずれ(CLS)も起こさないラッパーの書き方を解説します。
先に結論を書くと、影響範囲を自分で管理しやすいのは「専用の関数を作る」方法です。フィルターは手軽ですが、プラグインやウィジェットが出すアイキャッチにまで適用される点に注意が必要です。
the_post_thumbnail()が出力するもの
the_post_thumbnail( $size, $attr ) は get_the_post_thumbnail() の結果を echo する関数で、内部では wp_get_attachment_image() を使って <img> タグを作ります。そのため出力には次の属性が自動で付きます。
widthとheight(画像サイズに応じた値)srcsetとsizes(登録済みの画像サイズから生成)loading="lazy"やfetchpriority="high"、decoding="async"(WordPressが位置などから判断して付与)
ラッパーを自作するときに <img> を文字列で組み立て直すと、これらが失われて表示速度やCLSが悪化します。ラッパーは「<img> の外側に足す」だけにし、画像タグそのものはWordPressに作らせるのが基本方針です。
また、アイキャッチが設定されていない投稿では空文字が返ります。ラッパーだけが出力されて空の枠が残る、というのがよくある失敗なので、has_post_thumbnail() での確認を忘れないようにします。
作業前にはテーマファイルをバックアップし、子テーマで編集してください。親テーマを直接編集すると、更新時に上書きされます。
方法1:テンプレートで直接囲む
特定のテンプレート(例:single.php や template-parts/content.php)だけ変えたいなら、テンプレートで囲むのが最も分かりやすい方法です。
<?php if ( has_post_thumbnail() ) : ?>
<figure class="post-thumb">
<?php the_post_thumbnail( 'large', array( 'class' => 'post-thumb__img' ) ); ?>
<?php
$caption = wp_get_attachment_caption( get_post_thumbnail_id() );
if ( $caption ) :
?>
<figcaption class="post-thumb__caption"><?php echo esc_html( $caption ); ?></figcaption>
<?php endif; ?>
</figure>
<?php endif; ?>
第2引数の $attr で <img> にクラスや alt を足せます。alt を指定しない場合は、メディアライブラリで画像に設定した代替テキストが使われます。キャプションはメディアライブラリの「キャプション」欄の値で、esc_html() を通して出力しています。
方法2:post_thumbnail_htmlフィルターでまとめて囲む
テーマ内のあちこちで the_post_thumbnail() を呼んでいて、すべてに同じラッパーを付けたい場合は post_thumbnail_html フィルターを使います。このフィルターは $html, $post_id, $post_thumbnail_id, $size, $attr の5つの引数を受け取ります。
<?php
add_filter( 'post_thumbnail_html', function ( $html, $post_id, $thumbnail_id, $size, $attr ) {
if ( '' === $html || is_admin() || is_feed() ) {
return $html; // 画像なし・管理画面・フィードはそのまま
}
if ( ! in_the_loop() || ! is_main_query() ) {
return $html; // メインループ以外(ウィジェット等)には付けない
}
if ( false !== strpos( $html, 'post-thumb-wrap' ) ) {
return $html; // 二重に囲まない
}
return '<div class="post-thumb-wrap">' . $html . '</div>';
}, 10, 5 );
add_filter() の第4引数に 5 を指定しないと、2番目以降の引数は受け取れません。条件を付けずにすべてを囲むと、関連記事プラグインや最近の投稿ウィジェットなどにもラッパーが付き、CSSが崩れることがあります。上の例のように、対象をメインループに絞るのが無難です。ただし in_the_loop() と is_main_query() はグローバルのメインクエリを見ているため、メインループの内側で別のクエリを回す箇所(記事下の関連記事など)は除外しきれません。その場合は $size や $attr に渡したクラス名で判定するなど、条件を足してください。
<img> 自体の属性だけを変えたいなら、ラッパーではなく wp_get_attachment_image_attributes フィルター(引数は $attr, $attachment, $size)を使うほうが目的に合っています。
方法3:専用のテンプレートタグを作る
再利用しやすく、影響範囲も読みやすいのが専用関数です。子テーマの functions.php に定義し、テンプレートから呼び出します。
<?php
/**
* リンク付きのアイキャッチをfigureで囲んで出力する
*/
function my_post_thumbnail( $size = 'post-thumbnail', $post = null ) {
$post = get_post( $post );
if ( ! $post || ! has_post_thumbnail( $post ) ) {
return;
}
$img = get_the_post_thumbnail( $post, $size, array(
'class' => 'post-thumb__img',
) );
printf(
'<figure class="post-thumb"><a class="post-thumb__link" href="%1$s" aria-hidden="true" tabindex="-1">%2$s</a></figure>',
esc_url( get_permalink( $post ) ),
$img // wp_get_attachment_image() が生成した安全なHTML
);
}
一覧ページで「画像」と「タイトル」の両方が同じ記事へのリンクになっている場合、この例のように画像側のリンクに aria-hidden="true" と tabindex="-1" を付けると、スクリーンリーダーやキーボード操作で同じリンクを2回たどる手間を減らせます。画像だけがリンクになるデザインなら、この2つの属性は付けず、代わりに画像の alt かリンクのテキストで行き先が分かるようにしてください。
テンプレート側は <?php my_post_thumbnail( 'medium_large' ); ?> と書くだけになります。
CLSを防ぐCSS
ラッパーに固定の高さを付けたり、画像の height を消したりすると、読み込み時にレイアウトがずれます。width/height 属性は残したまま、CSSで比率を管理するのが安全です。
.post-thumb {
margin: 0 0 1.5em;
}
.post-thumb__img {
display: block;
width: 100%;
height: auto;
}
/* カードの画像比率をそろえたい場合 */
.post-thumb--card .post-thumb__img {
aspect-ratio: 16 / 9;
object-fit: cover;
}
height: auto を指定しておくと、ブラウザーは width/height 属性から比率を計算して領域を先に確保します。比率をそろえるなら aspect-ratio と object-fit: cover を組み合わせます。CSSはテーマのスタイルシートに書くか、wp_enqueue_style() で読み込み、<style> をテンプレートに直接書くのは避けてください。
ブロックテーマの場合
ブロックテーマでは、テンプレート内の「アイキャッチ画像」ブロック(core/post-featured-image)が画像を出力し、the_post_thumbnail() はテンプレートから呼ばれません。ブロックの設定でリンクの有無や比率を変えられるほか、PHPで囲みたい場合は render_block_core/post-featured-image フィルターでブロックの出力HTMLを加工できます。ブロックの設定項目はWordPressのバージョンで増減するため(2026年10月現在)、まずエディター側で実現できないか確認してから、フィルターでの加工を検討するのがよいでしょう。
確認方法
- アイキャッチ未設定の投稿で、空のラッパーが出ていないか
- ブラウザーの開発者ツールで、
srcset・sizes・width・heightが残っているか - 一覧ページとウィジェット、関連記事など、意図しない場所にラッパーが付いていないか
- PageSpeed Insights などで、レイアウトシフトの指摘が増えていないか
- キーボードのTabキーで移動したとき、同じリンクを不自然に2回たどらないか
まとめ
the_post_thumbnail()はwp_get_attachment_image()で<img>を作るため、ラッパーは外側に足すだけにする- 一部のテンプレートだけならテンプレートで囲み、
has_post_thumbnail()で空の枠を防ぐ - 全体に適用するなら
post_thumbnail_html(引数5つ)を使い、対象をメインループなどに絞る - 再利用と影響範囲の管理には専用のテンプレートタグが向いている
width/heightを残し、height: autoやaspect-ratioでCLSを防ぐ