WordPressの一覧と記事ページを分ける「<!--more-->」タグ。ブログ文化の遺産みたいになっていますが、きちんと設計しないと不思議な挙動に見えるので少しまとめてみます。
結論から書くとmoreタグを使わない設計が一番よさそうです。複数の人で運用する場合は特に。
moreタグについて
まず簡単に「<!--more-->」タグの説明。
ブログは一つの記事から「一覧」ページと「記事」ページの2階層が作られます。
記事の途中にmoreタグを入れると、それより上に書いたものが「一覧」ページに表示され、moreタグがあった位置に「READ MORE(続きを読む)ボタン」が置かれます。
このmoreタグの問題点を二つほど。
問題点1:出力されるHTMLが予測しづらい
moreタグの置き場所によって、HTMLの構造が変化します。
変化といっても単にWordPress特有の変換処理(wpautop)が入るだけなんですが、前後関係によってHTMLが変わるため、CSSでのスタイル設計が難しくなります。
問題点2:リンク先が記事ページの途中
一覧で「READ MOREボタン」を押すと記事ページの「途中」へリンクします。
音声ブラウザなど文脈の維持がどうしても必要な場合は別だと思いますが、遷移先がページの途中というのは視覚的にやはり混乱します。
この点だけ解決したい場合は、Codexに回避方法があります。
https://wpdocs.osdn.jp/「続きを読む」のカスタマイズ
解決方法
一応断っておくと上記は不具合ではなくWordPressの仕様なので、以下は解決方法というより設計方針。
方針1:moreタグは使わない
WordPressのテンプレートをカスタマイズできる場合は、moreタグを使わない設計が良いと思います。下の条件で「抜粋」欄をうまく使うと運用も楽になります。
- 一覧に「抜粋」欄をそのまま表示
抜粋の有無は「has_excerpt()」が利用できます。 - 「抜粋」欄に入力がない場合は本文の冒頭から一定文字数を表示
文字数はHTMLタグを取り除いてから数えます。
この場合、一覧ページで文章が途切れますが、文章を書きながら区切りを意識しなくて良いというのは大きなメリット。一覧の文章をきれいにしたい場合は「抜粋」欄を使います。
方針2:moreタグを慎重に設置する
テンプレートのカスタマイズができない場合は日々気をつけるしかありません。妥当と思われる例を一つ。
まずビジュアルエディタはNG。テキストエディタでHTMLが見えるようにします。具体的には「段落の先頭にmoreタグを入れる」というもの。
一覧向けの文章
<!--more-->記事だけで表示される文章
こうすると「一覧」では下記のようになり、
<p>一覧向けの文章</p>
<p><a href=”#” class=”more-link”>READ MORE</a></p>
記事ページでは下記のようになります。空のspanタグも無害です。
<p>一覧向けの文章</p>
<p><span id=”#”></span>記事だけで表示される文章</p>
ただし、この方法ではmoreタグの直後に見出しタグ(h1〜h6)が置けません。見出しを置くと記事ページで「空」の段落が作られます。ここだけネック。
方針3:独自にカスタマイズする
既存サイトでmoreタグを既に利用している場合や、むしろ積極的に利用したい場合はカスタマイズしておくと便利です。
仕組みは簡単で「moreタグ」を「READ MOREボタン」に変換しないだけです。こうするとmoreタグをどのように配置してもよく、過去の記事にも影響しません。moreタグが単に区切り位置として機能します。
- 一覧での表示は「the_content(”);」などとしてmoreリンクを非表示に
- 本文の中に「<!--more-->」があることを条件に、独自の「READ MOREボタン」を作る
- 記事ページでは「<!--more-->」を削除してから、WordPressの変換処理を通す
一覧と記事ページが同じファイルの場合はこんな感じ。
$my_content = $post->post_content;
if ( is_home() || is_archive() || is_search() ) {
the_content('');
if ( preg_match('/<!--more(.*?)?-->//', $my_content ) )
echo '<a href="' . get_the_permalink() . '">READ MORE</a>';
} else {
$my_content = preg_replace('/<!--more(.*?)?-->//', '', $my_content );
echo apply_filters('the_content', $my_content);
}
(このコードあまり確認していないので間違ってたらすいません。方針だけ参考にしてください)