コピペでOK!a-blog cmsで使える校正オプション


この記事は、a-blog cms Advent Calendar 2020 の17日目の記事です。

a-blog cmsでは変数の出力に対して 校正オプション を設定することで、変数を加工することができます。(Movable Typeでいうグローバルモディファイア、VueやBladeなどのテンプレートエンジンでいうフィルタのようなものですね。)

あらかじめ便利な校正オプションが定義されていますが、 extension/acms/Corrector.php にメソッドを定義することで、新たに校正オプションを追加することができます。今回は私がよく使う校正オプションの拡張例をご紹介したいと思います。

文字列を加工する

文字を置換する

変数の中から文字列を検索し、指定したものに置換する校正オプションです。

例えば、カテゴリ名の表示をラベルだけ「○○の導入事例」→「○○」にしたい場合に {fieldCategoryName}[replace('導入事例', '')]、カッコの前では改行を入れたい場合に {caption}[replace('(','<br>(')] のように使います。str_replaceからpreg_replaceにすることで正規表現を使用することもできます。

    /**
     * replace
     * 文字列を置換する
     *
     * @param  string $txt  - 置換対象の文字列
     * @param  array  $args - {var}[replace('検索する文字列','置換後の文字列')]
     * @return string       - 置換後の文字列
     */
    function replace($txt, $args = array())
    {
        return str_replace($args[0], $args[1], $txt);
    }

文字を改行ごとにspanで囲む

1行ごとにマーカーで塗られたようなデザインを加える場合、1行ごとにspan要素で囲むなどの実装を行います。カスタムフィールドなどから入力するタイトルに対し、1行ごとにspan要素で囲む校正オプションです。

  /**
   * nl2span
   * 改行ごとに<span>で囲む
   *
   * @param  string $txt  - 校正オプションが適用されている文字列
   * @return string       - 校正後の文字列
   */
  function nl2span($input)
  {
      $output = "";
      $input = str_replace( array( "\r\n", "\r", "\n" ), "\n", $input);
      $rows = explode( "\n", $input );
      foreach ($rows as $value) {
        $output .= "<span>{$value}</span>";
      }
      return $output;
  }

記事の公開状態を加工する

Entry_Summary や Entry_Body での記事の公開状態 {status} を「open」「draft」「close」のような文字列から「【下書き】」「【非公開】」のような文字列に変換する校正オプションです。

Entry_Summary や Entry_Body では {title} で記事のタイトルを表示することができますが、記事のステータスに応じて「【公開予定】記事タイトル」「【下書き】記事タイトル」「【非公開】記事タイトル」のようにステータスが表記されます。

ただし、記事のタイトルを改行付きで掲載したい、複数の変数を組み合わせて表示したいなどの理由で、カスタムフィールドで運用している場合は、記事のステータスが表記されません。そこで {status} を使用するのですが、「open」「draft」「close」のような文字列になっているので、{status}[status2Name] とすることで 「【下書き】」「【非公開】」のような文字列に変換します。

※2021/05/17以降のa-blog cmsで同様の校正オプション {eid}[entryStatusLabel] が追加されました。

    /**
     * status2Name
     * 記事の公開状況を日本語で返す
     *
     * @param  string $status - Entry_Summary等の{status}の値
     * @return string         - 校正後の文字列
     */
     public function status2Name($status)
     {
        switch ($status) {
          case 'draft':
            return "【下書き】";
          case 'close':
            return "【非公開】";
          default:
            return "";
        }
     }

カスタムフィールドの変数の値を置換する

カスタムフィールドでチェックボックスやセレクトボックスを使用する際に、valueに英語を利用していると、/field/event_type/conference/のような英語のURLを利用できますが、ページに日本語の項目名を出力したいときは、<!-- BEGIN_IF [{event_type}/eq/conference] -->会議<!-- END_IF --><!-- BEGIN_IF [{event_type}/eq/seminar] -->セミナー<!-- END_IF --> のように項目ごとにIFブロックを使う必要があります。これはスマートではありません。

そこで、valueの値を日本語に置換する校正オプションを用意することで、IFブロックを使わなくても良いようにする校正オプションです。{event_type}[value2Lavel('event_type')] のように使います。

    /**
     * value2Label
     * 値(value)から項目名(label)を返す
     *
     * @param  string $value - valueの値
     * @param  array  $args  - labelの変数名 {var}[label('')]
     * @return string        - label
     */
    public static function value2Label($value, $args = array())
    {
        $suffix = isset($args[0]) ? $args[0] : null;
        $label['event_type'] = array(
          "conference" => "会議",
          "seminar"    => "セミナー",
          "exhibition" => "展示会",
          "concert"    => "コンサート",
          "musical"    => "ミュージカル",
          "art"        => "アート展",
          "limited"    => "関係者のみ",
        );
        if( array_key_exists($value, $label[$suffix]) ){
          return $label[$suffix][$value];
        } else {
          return "";
        }
    }

リンクを設定する

テキスト中のURLに対してテキストリンクを貼る

コメント欄などでリンクが貼られた場合に、自動的にリンクが貼られるようにする校正オプションです。{body}[url2link] のように使います。

    /**
     * url2link
     * テキスト中のURLにリンクを貼る
     *
     * @param  string $txt - 本文
     * @return string      - 校正後の文字列
     */
    public function url2link($text)
    {
      $pattern = '/((?:https?|ftp):\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+)/';
      $replace = '<a href="$1" class="link">$1</a>';
      $text    = preg_replace( $pattern, $replace, $text );
      return $text;
    }

テキスト中のURLをOGP付きのリンクに変換する

同じくコメント欄などでリンクが貼られた場合に、自動的にURLからOGPを取得してサムネイル付きのリンクを出力するようにする校正オプションです。 {body}[url2ogp] のように使います。

    /**
     * url2ogp
     * テキスト中のURLにリンクを貼る
     *
     * @param  string $txt - 本文
     * @return string      - 校正後の文字列
     */
    public function url2ogp($text)
    {
      preg_match_all('/((?:https?|ftp):\/\/[-_.!~*\'()a-zA-Z0-9;\/?:@&=+$,%#]+)/', $text, $result, PREG_PATTERN_ORDER);
      $ogp_pattern = $result[0];
      $ogp_replace = array();
      foreach ($ogp_pattern as $val) {
        $graph = OpenGraph::fetch($val);
        $description = str_replace(PHP_EOL, '', $graph->description);
        if ( $graph->title ){
          $html  = "<a class=\"ogp\" href=\"{$val}\" target=\"_blank\" rel=\"noopener noreferrer\">";
          $html .= $graph->image ? "<span class=\"thumbnail\"><img src=\"{$graph->image}\" alt=\"\"></span>" : "";
          $html .= "<span class=\"content\">";
          $html .= $graph->title ? "<span class=\"title\">{$graph->title}</span>" : "";
          $html .= $graph->site_name ? "<span class=\"site-name\">{$graph->site_name}</span>" : "";
          $html .= $graph->description ? "<span class=\"description\">{$description}</span>" : "";
          $html .= "</body>";
          $html .= "</a>";
          $ogp_replace[] = $html;
        } else {
          $ogp_replace[] = "<a href=\"{$val}\" rel=\"noopener noreferrer\">{$val}</a>";
        }
      }
      $text    = str_replace($ogp_pattern, $ogp_replace, $text);
      $text    = str_replace("</a> \n<a class=\"ogp\"", "</a><a class=\"ogp\"", $text);
      $text    = preg_replace($pattern, $replace, $text);
      return $text;
    }

データを取得する

親カテゴリーのコードを取得する

カテゴリーIDを渡すと、親カテゴリーやルートカテゴリーのIDやコードを返す校正オプションです。

例えば、Entry_Summaryなどの記事一覧を取得する際に、カテゴリーごとにラベルを色分けしている場合に、<span class="category-{fieldCategoryId}[rccd]"> のようにすると、親カテゴリーのコードをclassに出力することができます。

    /**
     * pccd
     * 親カテゴリのコードを返す
     *
     * @param  string $cid  - カテゴリーID({fieldCategoryId}など)
     * @return string       - 校正後の文字列
     */
    public function pccd($cid)
    {
        if( ACMS_RAM::categoryParent($cid) ){
          return ACMS_RAM::categoryCode(ACMS_RAM::categoryParent($cid));
        } else {
          return ACMS_RAM::categoryCode($cid);
        }
    }
    /**
     * rccd
     * ルートカテゴリのコードを返す
     *
     * @param  string $cid  - カテゴリーID({fieldCategoryId}など)
     * @return string       - 校正後の文字列
     */
    public function rccd($cid)
    {
         while(1){
           $pcid = ACMS_RAM::categoryParent($cid);
           if( !$pcid ){
             return ACMS_RAM::categoryCode($cid);
           } else {
             $cid = ACMS_RAM::categoryParent($cid);
           }
         }
    }
    /**
     * pcid
     * 親カテゴリのIDを返す
     *
     * @param  string $cid  - カテゴリーID({fieldCategoryId}など)
     * @return string       - 校正後の文字列
     */
    public function pcid($cid)
    {
        if( ACMS_RAM::categoryParent($cid) ){
          return ACMS_RAM::categoryParent($cid);
        } else {
          return $cid;
        }
    }
    /**
     * rcid
     * ルートカテゴリのIDを返す
     *
     * @param  string $cid  - カテゴリーID({fieldCategoryId}など)
     * @return string       - 校正後の文字列
     */
    public function rcid($cid)
    {
         while(1){
           $pcid = ACMS_RAM::categoryParent($cid);
           if( !$pcid ){
             return $cid;
           } else {
             $cid = ACMS_RAM::categoryParent($cid);
           }
         }
    }

カスタムフィールドの値を取得する

記事のカスタムフィールドを取得する校正オプションです。

例えばEntry_Bodyの前後リンク(serialNavi)ではURLとタイトルを出力することはできますが、カスタムフィールドの値は出力できません。そこでカスタムフィールドをentry_outline という名前で定義したとしたら、 {eid}[customField('entry_outline')] のようにエントリーIDと変数名を指定することでカスタムフィールドを出力するようにします。

    /**
     * customField
     * カスタムフィールドを取得
     *
     * @param  integer $eid  - エントリーID
     * @param  array   $args - カスタムフィールドのname値 {eid}[customField('ここの値')]
     * @return string       - 校正後の文字列
     */
    public function customField($eid, $args = array())
    {
        $name  = isset($args[0]) ? $args[0] : null;
        $field = loadEntryField($eid);
        foreach ($field->_aryField as $key => $value) {
          if( $name == $key ){
            return implode($value);
          }
        }
        return '';
    }
<!-- BEGIN serialNavi:veil -->
<ul class="entry-nav">
  <!-- BEGIN nextLink -->
  <li class="next">
    <a href="{url}">
      <span class="title">{name}</span>
      <span class="name">{eid}[customField('entry_outline')]</span>
    </a>
  </li>
  <!-- END nextLink -->
  <!-- BEGIN prevLink -->
  <li class="previous">
    <a href="{url}">
      <span class="title">{name}</span>
      <span class="name">{eid}[customField('entry_outline')]</span>
    </a>
  </li>
  <!-- END prevLink -->
</ul>
<!-- END serialNavi:veil -->

パスからエントリーIDを取得する

Api_GoogleAnalytics_Rankingモジュールで使用しますが、{path} からエントリーIDを取得します。エントリーIDを取得することで、Entry_Summaryに引数を渡してサムネイルの表示などが可能になります。

    /**
     * path2eid
     * Api_GoogleAnalytics_Rankingモジュールの {path} から eid を取得する
     *
     * @param  string $path -
     * @return string       - eid
     */
    public function path2eid($path)
    {
        $path = basename($path);
        $DB = DB::singleton(dsn());
        $SQL = SQL::newSelect('entry');
        $SQL->addSelect('entry_id');
        $SQL->addWhereOpr('entry_code', $path, '=');
        $q = $SQL->get(dsn());
        $eid = $DB->query($q, 'one');
        if( $eid ){
          return $eid;
        } else {
          return NULL;
        }
    }
<!-- BEGIN_MODULE Api_GoogleAnalytics_Ranking id="{{module_id}}" -->
<ul class="ranking-list">
  <!-- BEGIN ranking:loop -->
  <!-- BEGIN_IF [{path}[path2eid]/nem] -->
  <!-- BEGIN_MODULE\ Entry_Summary ctx="bid/1/eid/{path}[path2eid]" -->
  <!-- BEGIN\ unit:loop -->
  <!-- BEGIN\ entry:loop -->
  <li class="item">
    <a href="\{url\}" class="ranking-card">
      <figure class="thumbnail">
        <!-- BEGIN_IF [\{entry_thumbnail@path\}/nem] -->
        <img src="%{ARCHIVES_DIR}\{entry_rthumbnail@path\}[resizeImg(200,133)|png2jpg]" alt="">
        <!-- ELSE -->
        <!-- BEGIN image:veil -->
        <img src="%{ROOT_DIR}\{path\}[resizeImg(200,133)|png2jpg]" alt="">
        <!-- END image:veil -->
        <!-- BEGIN noimage -->
        <img src="/images/nophoto.png" alt="">
        <!-- END noimage -->
        <!-- END_IF -->
      </figure>
      <dl class="body">
        <dt class="title"><span>\{title\}</span></dt>
        <dd class="meta">
          <span class="date">\{date#Y\}.\{date#m\}.\{date#d\}</span>
          <span class="pageview">{views}[number_format]</span>
        </dd>
      </dl>
    </a>
  </li>
  <!-- END\ entry:loop -->
  <!-- END\ unit:loop -->
  <!-- END_MODULE\ Entry_Summary -->
  <!-- END_IF -->
  <!-- END ranking:loop -->
</ul>
<p><a href="" class="ranking-more"></a></p>
<!-- END_MODULE Api_GoogleAnalytics_Ranking -->

ユニットの有無を調べる

ユニットの有無を調べる

エントリーにユニットがあるかどうか調べて、ユニットがあればユニットの数、ユニットがなければ0を返します。これによりユニットがなければ、カスタムフィールドの値を出すなどの条件分岐が可能になります。

    /**
     * unitExists
     * エントリーにユニット(本文)があるかどうか調べる
     *
     * @param  string $eid  - エントリーID({entry:loop.eid}など)
     * @return string       - ユニットがあればユニット数を返す、なければ0を返す
     */
    public static function unitExists($eid)
    {
        $DB  = DB::singleton(dsn());
        $q   = "SELECT COUNT(*) FROM `acms_column` WHERE `column_entry_id` = '$eid'";
        $one = $DB->query($q, 'one');
        return $one;
    }
<!-- BEGIN_MODULE Entry_Summary -->
<!-- BEGIN unit:loop -->
<ul class="entry-list">
  <!-- BEGIN entry:loop -->
  <!-- BEGIN_IF [{eid}[unitExists]/neq/0] --> 
  <li><a href="{url}">{title}</a></li>
  <!-- ELSE -->
  <li>記事がありません</li>
  <!-- END_IF -->
  <!-- END entry:loop -->
</ul>
<!-- END unit:loop -->
<!-- END_MODULE Entry_Summary -->

特定のユニットの有無を調べる

エントリーに特定のユニットがあるかどうか調べて、ユニットがあればユニットの数、ユニットがなければ0を返します。動画ユニットがある場合は、サムネイルに動画再生マークを表示するなどが可能になります。

    /**
     * hasVideoUnit
     * ビデオユニットがある場合は件数を返す
     *
     * @param  string $txt  - 校正オプションが適用されている文字列
     * @return string       - 校正後の文字列
     */
    public function videoUnitExists($eid)
    {
      if( $eid ){
        $DB = DB::singleton(dsn());
        $SQL = SQL::newSelect('column');
        $SQL->addSelect('count(*)');
        $SQL->addWhereOpr('column_type', 'custom_video', '=');
        $SQL->addWhereOpr('column_entry_id', $eid, '=');
        $q = $SQL->get(dsn());
        $one = $DB->query($q, 'one');
        return $one;
      } else {
        return 0;
      }
    }
<!-- BEGIN_MODULE Entry_Summary -->
<!-- BEGIN unit:loop -->
<ul class="entry-list">
  <!-- BEGIN entry:loop -->
  <li><a href="{url}" <!-- BEGIN_IF [{eid}[videoUnitExists]/neq/0] -->class="video"<!-- END_IF -->>{title}</a></li>
  <!-- END entry:loop -->
</ul>
<!-- END unit:loop -->
<!-- END_MODULE Entry_Summary -->

色の変換

ブログやカテゴリーごとにカラーコードを設定し、見出しやナビゲーションなどに適用されるようにします。このときに設定した色を明るくする、暗くすることで、Sassのlighten、darkenのようなことができれば良いと思い、校正オプションを作成しました。

カテゴリーごとに設定したカラーコードをコンテンツ枠に適用

<!-- BEGIN_MODULE Category_List id="rootCategoryList" -->
<!-- BEGIN category:loop -->
<!-- BEGIN_IF [{ccd}/nem/_and_/{category_color}/nem] -->
<style>
.{ccd} .container\{ border-top: 3px solid bottom {category_color}; \}
</style>
<!-- END_IF -->
<!-- END category:loop -->
<!-- END_MODULE Category_List -->

カテゴリーごとに設定したカラーコードを、Sassのligthen()のようなことをして適用する

設定したカラーコードに対して、CSSのrgba()により透明度を加算することで明るくします。rgbaではカラーコードはそのまま使えず、赤、青、緑の値をそれぞれ指定する必要があるため、校正オプションでカンマ区切りの文字列に変換します。

    /**
     *  hex2rgb
     * 16進数からrgbに変換
     *
     * @param  string hex  - 16進数
     * @return string       - rgb
     */
    public function hex2rgb($hex)
    {
        if ( substr( $hex, 0, 1 ) == "#" ) $hex = substr( $hex, 1 ) ;
        if ( strlen( $hex ) == 3 ) $hex = substr( $hex, 0, 1 ) . substr( $hex, 0, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 2, 1 ) . substr( $hex, 2, 1 ) ;
        $rgb = array_map( "hexdec", [ substr( $hex, 0, 2 ), substr( $hex, 2, 2 ), substr( $hex, 4, 2 ) ] ) ;
        return $rgb[0] . ', ' . $rgb[1] . ', ' . $rgb[2];
    }   
<!-- BEGIN_MODULE Category_List id="rootCategoryList" -->
<!-- BEGIN category:loop -->
<!-- BEGIN_IF [{ccd}/nem/_and_/{category_color}/nem] -->
<style>
.{ccd} .h2\{ background-color: rgba({category_color}[hex2rgb], 0.1); \}
</style>
<!-- END_IF -->
<!-- END category:loop -->
<!-- END_MODULE Category_List -->

カテゴリーごとに設定した色を、Sassのdarken()のようなことをして適用する

設定したカラーコードに対して、赤、青、緑の値を指定した%分減らすことで、暗くします。

    /**
     *  hex2rgb_darken
     * 16進数からdarkenを取得
     *
     * @param  string hex  - 16進数
     * @param  string args  - どれくらい暗くするか
     * @return string       - rgb
     */
     public function hex2rgb_darken($hex,  $args = array() )
    {
        $percent = isset($args[0]) ? $args[0] : 0;
        if ( substr( $hex, 0, 1 ) == "#" ) $hex = substr( $hex, 1 ) ;
        if ( strlen( $hex ) == 3 ) $hex = substr( $hex, 0, 1 ) . substr( $hex, 0, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 1, 1 ) . substr( $hex, 2, 1 ) . substr( $hex, 2, 1 ) ;
        $rgb = array_map( "hexdec", [ substr( $hex, 0, 2 ), substr( $hex, 2, 2 ), substr( $hex, 4, 2 ) ] ) ;
        return intval($rgb[0]*(1-($percent/100))) . ',' . intval($rgb[1]*(1-($percent/100))) . ',' . intval($rgb[2]*(1-($percent/100)));
    }
<!-- BEGIN_MODULE Category_List id="rootCategoryList" -->
<!-- BEGIN category:loop -->
<!-- BEGIN_IF [{ccd}/nem/_and_/{category_color}/nem] -->
<style>
.{ccd} .button\{ background: {category_color}; border: 1px solid {category_color}[hex2rgb_darken(30)]; border-width: 0 2px 2px 0; \}
</style>
<!-- END_IF -->
<!-- END category:loop -->
<!-- END_MODULE Category_List -->

PHP関数

PHPで使える関数をa-blog cmsでも利用したいことがあります。その場合は校正オプションに定義します。

JSONエンコードする

JSONファイルでは改行やクォーテーションなど使用できない文字列があるため、JSONエンコードすることで使用できるようにします。

    /**
     * json_encode
     * 文字列をJSONエンコードする
     *
     * @param  string $txt  - 校正オプションが適用されている文字列
     * @return string       - 校正後の文字列
     */
    public function json_encode($txt)
    {
        return json_encode($txt);
    }

文字列の先頭と末尾にある空白文字を取り除く

校正オプションの trim は文字列を切り取るもの(PHPでいうsubstr)なので、空白を取り除きたい場合は独自に定義します。

    /**
     * php_trim
     * 文字列から前後の空白を削除する
     *
     * @param  string $txt  - 校正オプションが適用されている文字列
     * @return string       - 校正後の文字列
     */
    function php_trim($txt)
    {
       return trim($txt);
    }

ファイル名から拡張子を取得する

<a href="%{ARCHIVES_DIR}{filename@path}" class="icon-{filename@path}[ext]"> のようにアイコンのclass名などに使用できます。

    /**
     * ext
     * 拡張子を返す
     *
     * @param  string $txt - ファイル名
     * @return string      - 校正後の文字列
     */
    public function ext($path)
    {
      return pathinfo($path, PATHINFO_EXTENSION);
    }

以上、a-blog cmsのフォームの校正オプションのカスタマイズ事例をご紹介しました。一部使用イメージがつきにくいものもあるかもしれあませんが、どれか使えそうなものがあれば嬉しいです。


関連記事

この記事のハッシュタグ から関連する記事を表示しています。

a-blog cmsでmp4ファイルのサムネイルを作成する校正オプション

a-blog cmsでPNGからJPGに変換する校正オプション