WordPressテーマのCocoonで、記事の抜粋をカスタマイズ(全角スペースを取り去る)した

 このブログでは、行の先頭を字下げするために、全角スペースを行頭へ入れるようにしています。
 当初はp(段落)タグのスタイル設定で字下げをしようかとも思ったんですけど、字下げしたいのは段落だけではなくbrで強制改行した時も同様だったので、スタイル側で変な強制力を持たせるのはやめました。手で字下げ文字として全角スペースを入れておけばいいかと割り切って入力をしていたわけです。

 ただ、それだと本文に、当然ですけど全角スペースが文字として組み込まれていることになります。

 これが微妙に困るんですよね。下記のようにサイトのフロントページでインデックスとして並べているエントリーカードや……

 関連記事を参考に貼り付ける用途のブログカードなど、「どんな記事か」を示す要約文(抜粋)が差し込まれる箇所で全角スペースが混じってきてしまうのです。抜粋の中では改行は省かれているから、これが微妙に見映えが悪い。

 なんとなーく気になったままずっと放置していたこの問題。
 重い腰をあげて対処してみることにしました。

スポンサーリンク

抜粋は get_the_snippet 関数で作られている

 このサイトに適用している親テーマのCocoonを確認していくと、どうも抜粋を生成している箇所は lib/seo.php の下記関数が該当するようです。

//本文抜粋を取得する関数
if ( !function_exists( 'get_the_snippet' ) ):
function get_the_snippet($content, $length = 70) {
  global $post;

  //抜粋(投稿編集画面)の取得
  $description = $post->post_excerpt;

  //SEO設定のディスクリプション取得
  if (!$description) {
    $description = get_the_page_meta_description($post->ID);
  }

  //SEO設定のディスクリプションがない場合は「All in One SEO Packの値」を取得
  if (!$description) {
    $description = get_the_all_in_one_seo_pack_meta_description();
  }

  //SEO設定のディスクリプションがない場合は「抜粋」を取得
  if (!$description) {
    $description = get_content_excerpt($content, $length);
    $description = str_replace('<', '&lt;', $description);
    $description = str_replace('>', '&gt;', $description);
  }
  return apply_filters( 'get_the_snippet', $description, $post );
}
endif;

 関数の最後に get_the_snippet というフィルターフックが設けられているので、これ用に自テーマの functions.php でコールバック関数を定義して処理すればいいはず。

add_filter('get_the_snippet', 'oiio_delete_zenkaku_spaces');
function oiio_delete_zenkaku_spaces($text) {
    return str_replace(' ', '', $text);
}

 get_the_snippet のコールバック関数として oiio_delete_zenkaku_spaces を functions.php 内に設けてみました。中身は受け取った抜粋データ($text)に含まれる全角スペースを空文字に置換して送り返すだけです。

 よし完成!……と思ったんですが、これが機能してくれません。何も起きない……。

処理が間違えているのか、はたまたフックできていないのか……

 WordPressはたまにしかいじらないし、PHPも以下同文なので、このあたりの処理を自分がちゃんと理解しているとは言いがたいものがあります。なので、「PHPで書いた処理が間違えてる」のか、「そもそもコールバック関数の定義が間違えていて処理が呼ばれていない」なのかがハッキリしません。

 まずはそこから確認ということで、return ”; として、単に空っぽの文字列を返す処理に書き換えてみます。やっぱり何も起きてくれないので、「PHPで書いた処理が間違えてる」可能性は排除。処理を元に戻しておきます。

 じゃあコールバック関数の定義が間違えているのか? 書式としては間違えてないはずなので、フィルターフックの名前を「get_the_snippet」以外にあれこれ変えて試すことにします。
「the_excerpt」駄目、「get_the_excerpt」駄目。「cocoon_internal_blogcard_snippet」を使ったらブログカードは全角スペースが排除できるようになりました。でもこれだとフロントページのエントリーカードは変更されません。もっと上流で変更できないと駄目です。

 WordPressが元から持っているフックは駄目で親テーマで定義したフィルターフック名しか拾えないなんてことはないよなあと「the_content」にしてみたら、本文から綺麗に全角スペースが消えました。ってことは、やっぱり全部拾えるはずです。

 となると考えられるのは、フィルターフックで上記コールバック関数が呼ばれて内容を書き換えてはいるんだけど、その後親テーマのCocoon側で、なんらかの処理が走って元の文字列に書き戻されちゃってる感じかなあ。

上流にさかのぼることにした

 よくわからないので、もうちょっと処理をさかのぼりながら、使えそうなフィルターフックがあったら片っ端から試してみればいいやーということにしました。
 というわけで本文から抜粋を生成しているらしき get_content_excerpt 関数を覗いてみると……

//本文部分の冒頭を綺麗に抜粋する
if ( !function_exists( 'get_content_excerpt' ) ):
function get_content_excerpt($content, $length = 120){
  $content = apply_filters( 'content_excerpt_before', $content);
  $content = cancel_blog_card_deactivation($content, false);
  $content = preg_replace('/<!--more-->.+/is', '', $content); //moreタグ以降削除
  $content = strip_tags($content);//タグの除去
  $content = strip_shortcodes($content);//ショートコード削除
  $content = str_replace('&nbsp;', '', $content);//特殊文字の削除(今回はスペースのみ)
  $content = preg_replace('/\[.+?\]/i', '', $content); //ショートコードを取り除く
  $content = preg_replace(URL_REG, '', $content); //URLを取り除く

  //$lengthが整数じゃなかった場合の処理
  if (!is_int($length)) {
    $length = 120;
  }

  $over    = intval(mb_strlen($content)) > $length;
  $content = mb_substr($content, 0, $length);//文字列を指定した長さで切り取る
  if ( $over && $more = get_entry_card_excerpt_more() ) {
    $content = $content.$more;
  }
  $content = esc_html($content);

  $content = apply_filters( 'content_excerpt_after', $content);

  return $content;
}
endif;

 使えそうなフィルターフックがさっそくありましたよ。関数最後の「content_excerpt_after」をフィルターフック名として使ってみたら、求めていた結果を得ることができました。

add_filter('content_excerpt_after', 'oiio_delete_zenkaku_spaces');
function oiio_delete_zenkaku_spaces($text) {
    return str_replace(' ', '', $text);
}

 微妙~に気になるけど、気にしないようにすれば気にならないって問題だったので、ささやかな変化ではありますが、思った通りの結果を得ることができたので大満足です。

コメント

スポンサーリンク