WordPress では、投稿本文の前後に「関連記事」や「シェアボタン」「広告」などを自動で差し込みたい場面がよくあります。テーマやプラグインを直接書き換えなくても、the_content フィルターフックを使えば、本文の出力内容をまとめて加工できます。この記事では、add_filter( 'the_content', ... ) で投稿本文($content)を受け取り、要素を追加したり置換したりして返す基本の書き方から、本文だけに適用するための条件分岐、そして本文が二重に出たり消えたりするトラブルの原因まで、初心者の方にも分かりやすく解説します。
目次
the_content フィルターでできること
the_content は、投稿本文を画面に出力する直前に通る「フィルター」です。テンプレートで the_content() を呼ぶと、WordPress は本文の文字列を一度 the_content フィルターに通してから出力します。このフィルターに自分の関数を登録しておくと、出力される本文を横取りして自由に加工できるわけです。
たとえば「すべての記事の末尾に著者プロフィールを付けたい」「本文中の特定の語句を別の表記に置き換えたい」といった要望を、本文を1記事ずつ手で編集することなく実現できます。WordPress 自身も、段落の自動整形(wpautop)やショートコードの展開(do_shortcode)をこのフィルター経由で行っています。the_content はそうした処理の集まる場所なので、ここに手を加えれば本文の表示を一括でコントロールできます。
基本の書き方:$content を受け取って return する
フィルターフックの基本は、加工対象の値を引数で受け取り、加工した値を return で返すことです。the_content の場合は、第1引数に投稿本文の文字列($content)が渡されます。これを受け取って、必要な処理をしてから必ず return します。次のコードは、本文の末尾に1文を追加するもっとも単純な例です。
function mytheme_append_text( $content ) {
// 本文の末尾に1文を追加する
$content .= '<p>最後までお読みいただきありがとうございました。</p>';
// 加工した本文を必ず return する
return $content;
}
add_filter( 'the_content', 'mytheme_append_text' );
ポイントは2つです。1つは、フィルター関数の第1引数で受け取った $content が「これまでに組み立てられた本文」だということ。もう1つは、加工後の文字列を return で返すことです。echo で出力するのではなく、あくまで「返した値」が本文として使われます。本文の前に何かを足したいなら $content の前に文字列を連結し、後ろに足したいなら後ろに連結します。
add_filter の優先度と引数の数
add_filter() には、フックする関数のほかに「優先度」と「受け取る引数の数」を指定できます。書式は add_filter( $hook_name, $callback, $priority, $accepted_args ) です。それぞれの引数の意味は次のとおりです。
| 引数 | 説明 |
|---|---|
$hook_name | フックの名前。本文を加工する場合は 'the_content' |
$callback | 登録する関数(コールバック)。本文を受け取り、加工して返す |
$priority | 実行順を決める数値。省略時は 10。小さいほど先に、大きいほど後に実行される |
$accepted_args | コールバックが受け取る引数の数。省略時は 1。the_content は $content の1つだけ渡される |
優先度は、複数のフィルターが同じ the_content に登録されているときの実行順を決めます。たとえば WordPress 標準の wpautop(改行を <p> に変換する処理)は優先度 10 で登録されています。自分の処理を wpautop よりも後に走らせたいなら優先度を 11 以上に、先に走らせたいなら 9 以下にします。整形済みの本文に対して要素を足したい場合は、既定の 10 のままか、それより大きい値を指定しておくと扱いやすくなります。
the_content フィルターがコールバックに渡すのは $content 1つだけなので、$accepted_args は基本的に指定不要です。省略すれば 1 として扱われます。本文に加えて追加の情報を扱いたい場合は、関数の中で get_the_ID() や get_post() などを使って現在の投稿情報を取得します。
本文の末尾に著者プロフィールや関連記事を差し込む
実際によくあるのが、記事末尾への「著者プロフィール」「関連記事」「シェアボタン」「広告」の自動挿入です。本文の文字列に対して追加したい HTML を連結すれば実現できますが、ここで重要なのが「どの画面で適用するか」を絞り込むことです。何も条件を付けないと、トップページの記事一覧や固定ページ、ウィジェット内など、思わぬ場所にまで差し込まれてしまいます。
そこで、個別記事の本文だけに適用するために is_single()、メインクエリの本文だけに限定するために is_main_query()、ループの中で呼ばれているかを確認する in_the_loop() を組み合わせます。次のコードは、個別投稿ページのメイン本文の末尾にだけ著者プロフィールを差し込む例です。
function mytheme_add_author_box( $content ) {
// 個別投稿のメイン本文だけに適用する
if ( is_single() && in_the_loop() && is_main_query() ) {
// 現在の投稿の著者情報を取得する
$author_name = get_the_author();
$author_bio = get_the_author_meta( 'description' );
// 差し込む HTML を組み立てる
$box = '<div class="author-box">';
$box .= '<h3>この記事を書いた人</h3>';
$box .= '<p class="author-name">' . esc_html( $author_name ) . '</p>';
$box .= '<p class="author-bio">' . esc_html( $author_bio ) . '</p>';
$box .= '</div>';
// 本文の後ろに連結する
$content .= $box;
}
return $content;
}
add_filter( 'the_content', 'mytheme_add_author_box' );
条件分岐の中に入らなかった場合(一覧ページなど)は、$content をそのまま return します。条件に合うときだけ HTML を連結し、合わないときは何も足さずに返す、という形にしておくと、適用範囲を安全にコントロールできます。差し込む HTML 内でユーザー入力やメタ情報を出力するときは、esc_html() などのエスケープ関数を通しておくと安心です。
「関連記事」や「広告」を入れたい場合も考え方は同じで、連結する HTML を差し替えるだけです。本文の前に差し込みたいときは $content = $box . $content; のように、本文より前で連結します。
本文中の文字列を置換する
本文の前後に足すだけでなく、本文そのものを書き換えることもできます。たとえば、記事内に登場する特定の語句に自動でリンクを張ったり、表記をそろえたりといった用途です。文字列の置換には PHP の str_replace() を使います。
function mytheme_replace_text( $content ) {
if ( is_singular() && in_the_loop() && is_main_query() ) {
// 本文中の「WordPress」を表記ゆれなくそろえる
$content = str_replace( 'ワードプレス', 'WordPress', $content );
}
return $content;
}
add_filter( 'the_content', 'mytheme_replace_text' );
置換を行うときは、the_content に渡ってくる $content がすでに HTML を含んでいる点に注意してください。単純な語句の置き換えなら str_replace() で十分ですが、タグの属性値など意図しない箇所まで一致してしまう恐れがある場合は、対象を慎重に選びましょう。複雑なパターンを扱う場合は preg_replace() を使う方法もありますが、HTML を正規表現で扱うのは壊れやすいため、必要最小限にとどめるのが安全です。
本文が二重に表示される・余計な場所に出るとき
the_content フィルターは便利な反面、適用範囲を意識しないと「思っていない場所にまで差し込まれる」「本文が増殖する」といった不具合が起きやすいフックです。代表的な原因を見ていきましょう。
一覧ページや固定ページにも差し込まれてしまう
条件分岐を付けずに $content へ HTML を連結すると、トップページの記事一覧、アーカイブ、固定ページなど、the_content() が呼ばれるあらゆる場所に同じ要素が差し込まれます。著者プロフィールやシェアボタンは個別記事にだけ出したいことが多いので、is_single() で投稿ページに、固定ページにも出したいなら is_singular() で個別表示全般に絞り込みます。前述のコードのように、is_main_query() と in_the_loop() も合わせて確認しておくと、想定外の場所での適用を防げます。
抜粋(get_the_excerpt)経由で二重に適用される
意外と気付きにくいのが、抜粋(excerpt)を生成する過程で the_content フィルターが間接的に呼ばれるケースです。投稿に手動の抜粋が設定されていないと、WordPress は本文から抜粋を自動生成しますが、その内部処理で本文がフィルターを通ることがあります。すると、一覧ページの抜粋にまで著者プロフィールなどが紛れ込むことがあります。is_main_query() と in_the_loop() を条件に加えておくと、こうした抜粋生成のための呼び出しを除外しやすくなります。心配な場合は、抜粋を出力する箇所では the_excerpt() を使い、本文の出力(the_content())と分けて扱うのも有効です。
本文中に同じ処理が重複して出力される
ページ内で the_content() が複数回呼ばれる構成だと、そのたびにフィルターも実行され、差し込んだ要素が何度も表示されてしまいます。プラグインとテーマの両方で同じような末尾要素を追加していて重複することもあります。差し込みは1か所だけにする、あるいは is_main_query() や in_the_loop() でメインの本文表示に限定することで、重複を避けられます。
本文が真っ白に消えてしまうとき
「フィルターを追加したら本文が表示されなくなった」という相談は非常に多いです。原因のほとんどは $content の返し忘れに集約されます。
return を書き忘れている
フィルター関数は「返した値」が本文として使われます。return を書かないと、関数は null を返したことになり、本文が空になって真っ白になります。本文を echo で出力してしまうのも同様の失敗で、echo した内容はフィルターが処理される前の予期しないタイミングで表示され、肝心の本文は空のまま返されてしまいます。フィルター関数では 必ず文字列を return する、と覚えてください。
条件分岐の外で return していない
if ( is_single() ) { ... return $content; } のように return を if の中だけに書いてしまうと、条件に当てはまらない一覧ページなどで return が実行されず、やはり本文が消えます。次の良い例と悪い例を見比べてみてください。
// 悪い例:条件に合わないと return されず本文が消える
function bad_filter( $content ) {
if ( is_single() ) {
$content .= '<p>追加テキスト</p>';
return $content; // ← if の中だけ
}
// ← ここで return がないため、一覧ページでは null が返る
}
add_filter( 'the_content', 'bad_filter' );
// 良い例:最後で必ず return する
function good_filter( $content ) {
if ( is_single() ) {
$content .= '<p>追加テキスト</p>';
}
return $content; // ← どの場合でも必ず返す
}
add_filter( 'the_content', 'good_filter' );
ポイントは、return $content; を関数の一番最後に1回置き、加工は if の中で $content に対して行うことです。こうしておけば、条件に合わないときも未加工の本文がそのまま返るので、本文が消える事故を防げます。
まとめ
the_content フィルターを使えば、投稿本文の前後への要素追加や本文の置換を、記事を1つずつ編集せずにまとめて行えます。最後に要点を振り返っておきましょう。
- フィルター関数は第1引数で本文
$contentを受け取り、加工して必ずreturnする。echoや return 忘れは本文が消える原因になる。 - 差し込み先を絞るには
is_single()/is_singular()、is_main_query()、in_the_loop()を組み合わせる。 add_filter()の第3引数(優先度)で実行順を、第4引数で受け取る引数の数を指定できる。本文だけ扱うなら既定のままでよい。- 抜粋の自動生成などで間接的にフィルターが呼ばれ、二重適用が起きることがある。条件分岐で除外する。
まずは本文末尾に1文を足す最小の例から試し、条件分岐と return の置き場所に慣れていくと、安全に本文をカスタマイズできるようになります。