2019-09-10

Craft CMS で会員コンテンツの表示制御の方法と自動でやる場合の懸念とかとか

Craft CMS に限らない話ではあると思うのだけど。。。

会員向け(有料)コンテンツの表示制御 | bit part 合同会社
https://bit-part.net/craftcms/...

というのをかいて、コンテンツの一部をログインしているかどうか?というのをもとに制御するようなサンプルを書いた。

どこまで表示させるか?というパターンはいくつかあるとおもう。

特定のフィールドを出すパターン

特定のフィールドだけを出す、というパターンは実装としてはそこまで難しくはない。

運用上そのフィールドにデータを入れないといけないということが若干手間に感じられる可能性がある、というところかな、と。

この赤枠の方のフィールドに都度入れてもらうような感じ。

運用として回せるならこれはこれでありだと思う。

基本的にどこまで自動でやるか、どこまで自由にやりたいか、という話になってくるところではあると思うのだけど。

最初の段落だけを表示する

最初の段落を表示させる、というのは @tinybeans に教えてもらった方法ではあるのだけど。

richtext - Is there a way to output only the first paragraph of a Rich Text field? - Craft CMS Stack Exchange
https://craftcms.stackexchange...

entrybodyall にリッチエディタやマトリックスのブロックの内容がセット済み、という前提でこんな感じで p タグの閉じタグで

{% set entrybody %}
  {% set paragraphs = entrybodyall|split('</p>') %}
  {% set firstParagraph = paragraphs|first ~ '</p>' %}
  {{ firstParagraph|raw }}
{% endset %}

配列の最初だけを取り出した上で、 p タグの閉じタグをくっつけて出力するパターン。

これはだいぶスマートなやり方だと思う。

指定の文字数を越えたらその段落まで表示

文字数を決めたい場合があるだろうなぁと思ってとりあえずそれを考えてみる。

とりあえずざっくり書いただけだから冗長だけどコードとしてはこんな感じかな、、、

{% set entrybody %}

  {% set paragraph_array_text = [] %}
  {% set show_count = 200 %}
  {% set char_count = '0' %}
  {% set trim_count = '0' %}
  {% set trim_paragraph_count = '0' %}
  {% set paragraph_count = '' %}
  
  {% set paragraphs = entrybodyall | replace('/<p>/', '') %}
  {% set paragraph_array = paragraphs|split('</p>') %}
  {% for paragraph_text in paragraph_array %}
    {% set paragraph_text_st %}{{ paragraph_text | striptags }}{% endset %}
    {% set paragraph_array_text = paragraph_array_text | merge([paragraph_text_st]) %}
  {% endfor %}
  {# 指定の文字数を超えるまでループする #}
  {% for text in paragraph_array_text %}
    {% if char_count < show_count %}
    {% set trim_paragraph_count = text|length %}
    {% set char_count = char_count + text|length %}
    {% set paragraph_count = loop.index0 %}
    {% endif %}
  {% endfor %}

  {% for i in 0..paragraph_count %}
    <p>{{ paragraph_array[i]|raw }}</p>
  {% endfor %}
{% endset %}

この部分

{% set paragraphs = entrybodyall | replace('/<p>/', '') %}
  {% set paragraph_array = paragraphs|split('</p>') %}
  {% for paragraph_text in paragraph_array %}
    {% set paragraph_text_st %}{{ paragraph_text | striptags }}{% endset %}
    {% set paragraph_array_text = paragraph_array_text | merge([paragraph_text_st]) %}
  {% endfor %}

はとりあえずさっきの最初の段落と同じ感じでpタグ単位で分けて配列にセットするってのをやりつつ。

配列をループさせながら一旦タグを削除して文字数をカウントしたのを文字数用の配列にセットしている。
ここ配列まとめちゃってよかったな、と書きながら思う。

あとは単純に指定の文字数を超えるまでループを回して配列のどこまでが必要かを計算して、 paragraph_count にセットする。

{# 指定の文字数を超えるまでループする #}
  {% for text in paragraph_array_text %}
    {% if char_count < show_count %}
    {% set trim_paragraph_count = text|length %}
    {% set char_count = char_count + text|length %}
    {% set paragraph_count = loop.index0 %}
    {% endif %}
  {% endfor %}

それがおわったらあとは元々セットしてある配列から、必要なだけループするという感じ。

{% for i in 0..paragraph_count %}
    <p>{{ paragraph_array[i]|raw }}</p>
  {% endfor %}

とりあえずざっくりとはこんな感じかな、と。

指定の文字数で区切って表示させる

文字数決め打ちとなった場合どうするか?というのがあり少し考えてみたけど、あまりいい感じにはできなかった。

できているといえばできているのだけど、、、いい感じにテキストだけ抜き出すというのが難しいな、、、と。

{% set trim_count = char_count - show_count %}
{% set trim_count = trim_paragraph_count - trim_count %}

{% for i in 0..paragraph_count %}
{% if loop.last %}
  {% set p %}{{ paragraph_array[i]}}{% endset %}
  <p>{{ p[0:trim_count]}}...</p>
{% else %}
  <p>{{ paragraph_array[i]|raw }}</p>
{% endif %}
{% endfor %}

大体はさっきの段落で区切るコードと同じではあるのだけど。

指定の文字数をオーバーする前の段落(配列)までが何文字で、次の段落は頭から何文字切り出すか?を計算する。

そこまでは問題ないのだけど、pタグを取った配列から単純に切り出してしまうと、p タグ以外の img タグとかがはいってるときにそれが途中で切り出されてしまいそうな気がする。

結果として文字数途中で切り分けるところはテキストしかはいっていない想定でやるしかないんじゃないのかなぁ、、、と。

{% if loop.last %}
  {% set p %}{{ paragraph_array[i]}}{% endset %}
  <p>{{ p[0:trim_count]}}...</p>
{% else %}
  <p>{{ paragraph_array[i]|raw }}</p>
{% endif %}

ということで、ループの最後はそういう感じの処理にしておいた。

なんかその辺 Twig にフィルタあるのかな。。。

これやってて [0:20] みたいに書いてslice出来るのを知った。

新聞社のサイトの文字数制御

こういうニュースサイトの文字数切ってるのは、コンテンツを管理している仕様として、テキストはテキスト、画像は画像(とキャプション)、という感じで管理されているのかなぁというのが気になった。

それであればイレギュラーなことは発生しなそうだからどうにでもなるかな、という気はするのだけど。

MTタグだと MTEntryExcerpt が似たようなことやってくれるはずなんだけど、あれの処理はどうなってるんだろうな。

MTEntryExcerpt - テンプレートタグリファレンス | CMSプラットフォーム Movable Type ドキュメントサイト
https://www.movabletype.jp/doc...

と思ったけど、

その場合、本来の記事本文の内容から HTML タグが取り除かれ、最後に「...」が付加されます。

ってことだからさっきので言うと striptags してテキスト取り出してるだけだから同じような話か。


指定したMatrixのブロックの数や段落数とかであれば問題ないけど。

テキスト以外の要素も入ってくるリッチエディタを使っている中での指定文字数というのはあまり現実的ではないんだろうな、、、