WordPressの本文で、画像の直後に閉じタグだけの</p>が勝手に入っていました。
原因は、本文を自動で整形するWordPressの機能、wpautopです。
書き方を変えても直らず、最終的にはテーマ側で出力を直しました。
🎥 この記事の内容は動画でも解説しています。
このブログをオリジナルテーマに移行したときに見つかりました。
Claude Codeに全ページのHTMLをチェックしてもらったところ、5記事で</p>が余っていました。
どの記事にも、猫と私が会話する「マスコットのセリフ」が入っていました。
本文の書き方と実際の出力
セリフ部分は、本文にこう書いています。
アイコン画像と吹き出しの<p>を別々の行に置いています。
<div class="c-mascot-dialogue">
<img class="c-mascot-dialogue__icon" src="cat.png" alt="">
<p class="c-mascot-dialogue__bubble">セリフです</p>
</div>
ところが、表示時にはこうなっていました。
<div class="c-mascot-dialogue">
<img class="c-mascot-dialogue__icon" src="cat.png" alt=""></p>
<p class="c-mascot-dialogue__bubble">セリフです</p>
</div>
画像の直後に、開きタグのない</p>が入っています。
本文には書いていない閉じタグです。
余計な</p>はブラウザで空の段落になる
開きタグのない</p>も、ブラウザは無視しません。
HTMLのルールでは、対応する開きタグがない</p>は、空の段落として補って読むことになっています。
実際にChromeで読み込ませると、空の段落<p></p>になっていました。
<img class="c-mascot-dialogue__icon" src="cat.png" alt=""><p></p>
段落に余白を付けているテーマだと、セリフの間に余計なすき間ができます。
HTMLチェックでもタグの崩れとして引っかかります。
wpautopは本文を自動で段落に整える
wpautopは、本文の改行を見て<p>や<br>を自動で足すWordPressの標準機能です。
クラシックエディタや、HTMLを直接書いた本文で働きます。
ブロックエディタのブロックを含む本文では、WordPress本体の処理でwpautopが外されます(今回の5記事はどれも当てはまりません)。
今回の記事は、どれもHTMLを直接書いた本文でした。
その本文をwpautop()に通すと、画像の直後に</p>が追加されていました。
書き方を変えて試した結果
本文の書き方を変えて直せないか、Claude Codeにローカル環境(WordPress 7.1.2)でwpautop()を直接実行して確かめてもらいました。
- 画像と吹き出しを1行にまとめる →
</p>が入る - 吹き出しを
<p>から<div>に変える →</p>が入る - 画像を
<figure>で包む → 入らない
改行をなくしても、吹き出し側を変えても直りませんでした。
変化があったのは、画像を<figure>で包んだときだけです。
<div class="c-mascot-dialogue">
<figure><img class="c-mascot-dialogue__icon" src="cat.png" alt=""></figure>
<p class="c-mascot-dialogue__bubble">セリフです</p>
</div>
WordPress本体のwpautop()には、段落で包まない「ブロック要素」の一覧があります。figureはこの一覧に入っていて、imgは入っていません。
そのため、<figure>で包むとwpautopが段落として閉じようとしなくなります。
本文は直さず、テーマ側で直してもらった
ただ、<figure>で包む方法では、過去の5記事の本文を書き換える必要があります。
これから書く記事でも、毎回忘れずに包まなければなりません。
そこでClaude Codeは、テーマのfunctions.phpから読み込んでいるファイルに、表示時だけ余計な</p>を取り除くフィルターを追加しました。
add_filter( 'the_content', function ( $content ) {
return preg_replace( '#(<img[^>]*class="c-mascot-dialogue__icon"[^>]*>)s*</p>#', '$1', $content );
}, 11 );
このフィルターで気をつけたのは2つです。
- 対象を
c-mascot-dialogue__iconクラスが付いた画像に絞っています。ほかの画像の後ろにある</p>には触れません - 優先度を
11にしています。wpautopは優先度10で動くため、整形後に取り除けます
自分のサイトで使うときは、c-mascot-dialogue__iconの部分を、余計な</p>が付く画像のクラス名に置き換えてください。
コードは子テーマかオリジナルテーマのfunctions.php(またはそこから読み込むファイル)に入れます。
親テーマに直接書くと、テーマの更新で消えてしまいます。
また、この正規表現はclass="c-mascot-dialogue__icon"とクラスが1つだけの画像に合わせています。
クラスが複数付いている画像では一致しないので、先に表示されたHTMLで画像のタグを確かめてから調整してください。
本文は書き換えていないので、過去の記事もこれからの記事も、同じ書き方のまま直ります。
remove_filter( 'the_content', 'wpautop' );でwpautop自体を止める方法もあります。
ただし、ほかの記事にも段落が付かなくなるため、今回は選びませんでした。
画像の後ろに</p>が入るときの確認順
- ブラウザの「ページのソースを表示」で、本文に書いていない
</p>がないか見る(開発者ツールの要素画面だと、ブラウザが直したあとの空の<p></p>で表示される) - その要素を
<figure>などのブロック要素で包めるなら、本文側で直す - 同じ書き方の記事が多いなら、対象を絞った
the_contentフィルターで出力側を直す
wpautopの整形は、エディタの画面では見えません。
テーマを変えたときなどに一度、表示されたHTMLを確かめておくと安心です。