eureka

【WordPress】Advanced Custom Fields PROで入力したデータをChart.jsのグラフに使用して、ショートコード化したついでにクイックタグ化する

2

またひとつWordPressで賢くなった

タイトルてんこ盛りすぎるじゃろ

WordPressの記事にレーダーチャートを埋め込むみたいなことをしました。
レーダーチャートとはこんな感じのグラフですね。

レーダーチャートの例

PHP(WordPress関数)はあまりやらないので、次に似たような実装をする自分のためにもノウハウを残します、、笑

グラフには動的なグラフの描画で人気のChart.jsを使用しているので、レーダーチャート以外のグラフでも応用が可能です。
似たようなことでお困りの方がいればぜひ参考にしてみてください。

また、ACFを使用しない実装であれば下記の記事も参考になりますので、良ければ。
【Chart.js】ワードプレスの記事にグラフを入れる方法!(コピペでOK)

バージョン

WordPress 4.9.10
Chart.js 2.8.0
Advanced Custom Fields PRO 5.8.5

グラフのUIを作成

まずはグラフの見た目を作成していきます。

CDNを読み込む

今回Chart.jsはCDNを利用するのでheadで読み込みます。
ロード時間が気になるのでscriptタグにasync属性を追加しました。

<!doctype html>
<head>
  ...略
  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js" async></script>
</head>

チャートのデータを作成

bodyの終了タグの直前にscriptタグを挿入して仮のグラフデータを生成します。
グラフタイプをradar以外にするとデータの書き方も若干変わるので、Chart.js公式などを見て入れていきます。設定はお好みで。

  <script>
  var radarChart = document.getElementById("radarChart").getContext('2d');
  var chart = new Chart(radarChart, {
    type: 'radar',
    data: {
      labels: ['項目1', '項目2', '項目3'],
      datasets: [{
        data: [4.0, 5, 3.2],
        backgroundColor: 'RGBA(181,217,253, 0.5)',
        borderColor: 'RGBA(72,128,247, 1)',
        borderWidth: 1,
        pointBackgroundColor: 'RGB(72,128,247)'
      }]
    },
    options: {
      legend: {
        display: false,
      },
      scale:{
        ticks:{
          suggestedMin: 0,
          suggestedMax: 5,
          stepSize: 1,
          callback: function(value, index, values){
            return value
          }
        }
      }
    },
  });
  </script>
</body>

この設定で、HTML側の任意の場所に下記のコードを追加するとグラフが表示されるようになります。

<canvas id="radarChart"></canvas>

グラフ表示はとても簡単ですね。

Advanced Custom Fields PROの設定

続いてAdvanced Custom Fields PRO(以下ACF PRO)の設定をしていきます。

ACFで入力する意図としては下記を目的としています。

  • JSのコードが分からない人でも分かりやすく入力できる。
  • 運用ミスが減る

また、今回は『記事ごとに項目数を限定しない』という実装要件があったため、繰り返しフィールドが利用できるACF PROを利用しています。

繰り返しフィールドを使用した投稿記事での入力画面

項目数が記事ごとに固定で良いのであればPRO版でなくても十分です。

ACF PRO(またはACF)のインストール等はしてある前提で進めます。まだの方はインストールしておいてください。

では設定していきましょう。

フィールドの設定

PRO版の設定です。

WordPress管理画面サイドバーのカスタムフィールドから入り、新規追加でフィールドを下記のように設定します。

設定項目設定値備考
フィールドラベルチャート投稿画面のフィールドタイトル。
フィールド名chart
フィールドタイプ繰り返しフィールド
サブフィールド下記別表を参照項目と点数の二つを登録。
Collapsed項目名サブフィールド入力後に選択可能。
レイアウト入力画面の見た目。お好みで。

繰り返しフィールドにすることでサブフィールド(繰り返す内容)を設定できるので項目名と点数で二つ設定します。

サブフィールド①(項目名)

下記以外の項目に関してはお好みで入力してください。

サブフィールド設定項目サブフィールド設定値備考
フィールドラベル項目名必須
フィールド名label必須
フィールドタイプテキスト必須

サブフィールド②(点数)

入力側で意図しないデータを入れられないように、点数には最小値と最大値も入れておきます。
ステップサイズを小数点にすることで0.1刻みで点数入力ができます。

下記以外の項目に関してはお好みで入力してください。

サブフィールド設定項目サブフィールド設定値備考
フィールドラベル点数必須
フィールド名point必須
フィールドタイプ数値必須
デフォルト値3.0任意
最小値0任意
最大値5.0任意
ステップサイズ0.1任意

公開設定

フィールドの表示位置のルールは投稿ページに表示させたいので下記とします。
『投稿タイプ』『等しい』『投稿』

位置のルール設定

最終的にこんな感じになっていればOKです。公開ボタンを押して確定させます。

ACFの設定内容

カスタムフィールドの設定を公開すると投稿ページの下部に下記のような入力フィールドが出現して、自分で設定した内容に沿ってグラフ用のデータを複数個設定できるようになりました。

投稿ページ下部に表示されたグラフ用の入力フィールド

入力したデータからグラフを表示させる

実際に入力したデータをグラフに反映させる作業を行います。

データを入力して公開する

投稿ページにてグラフ用のデータを入力、エディタにグラフを表示させるためのタグを入力して投稿を公開します。

グラフデータを入力する
<canvas id="radarChart"></canvas>

公開したらブラウザ側で仮データのグラフが表示されていることを確認します。

PHPでデータを取得する

投稿ページで入力したデータを直接JavaScriptで受け取ることができないので、一旦PHPで取得してからJavaScriptに渡します。
段階を踏んでコードを書いていくので、まずはPHPで取得することろから。

Chart.js用に追加したscriptタグ(bodyの終了タグの直前)の上にPHPのコードを追加していきます。

  <?php if(get_field('chart')): ?>
  	<!-- レーダーチャート データ取得 -->
  	<?php
      $chartLabels = array();
      $chartPoints = array();

      while(the_repeater_field('chart')) {
        array_push($chartLabels, get_sub_field('label'));
        array_push($chartPoints, get_sub_field('point'));
      }
    ?>
    <!-- // レーダーチャート データ取得 -->

  	<script>
  	var radarChart = document.getElementById("radarChart").getContext('2d');
    ...略
    </script>
  <?php endif; ?>
</body>

簡単にコードの説明をします。

<?php if(get_field('chart')): ?>
  <?php ... ?>
  <script>...</script>
<?php endif; ?>

投稿画面でグラフデータの入力がない場合には処理させないようにしたいので、if文でデータの取得処理とJavaScriptの処理を囲っています。

  	<?php
      $chartLabels = array();
      $chartPoints = array();

      while(the_repeater_field('chart')) {
        array_push($chartLabels, get_sub_field('label'));
        array_push($chartPoints, get_sub_field('point'));
      }
    ?>

ここでACFのデータを取得してJS側に渡すための配列データを作成しています。
the_repeater_field()で配列になっている繰り返しフィールドの値を取得できます。
また、点数はACFの設定で数値のバリデーションをしていますが、念のためintval()で数値化します。 intval()を使用すると小数点を無視して整数になってしまうのでやめました。

PHPで取得したデータをJavaScriptに渡す

PHPでデータを取得できたのでJavaScriptに渡す処理を書きます。

  <?php if(get_field('chart')): ?>
    <!-- レーダーチャート データ取得 -->
    <?php
      $chartLabels = array();
      $chartPoints = array();

      while(the_repeater_field('chart')) {
        array_push($chartLabels, get_sub_field('label'));
        array_push($chartPoints, get_sub_field('point'));
      }

      $jsonLabelArray = json_encode($chartLabels); // 追加
      $jsonPointArray = json_encode($chartPoints); // 追加
    ?>
    <!-- // レーダーチャート データ取得 -->

    <script>
    var $labelArray = <?php echo $jsonLabelArray; ?>; // 追加
    var $pointArray = <?php echo $jsonPointArray; ?>; // 追加

    var radarChart = document.getElementById("radarChart").getContext('2d');
    var chart = new Chart(radarChart, {
      type: 'radar',
      data: {
        labels: $labelArray, // 修正
        datasets: [{
          data: $pointArray, // 修正
          backgroundColor: 'RGBA(181,217,253, 0.5)',
          borderColor: 'RGBA(72,128,247, 1)',
          borderWidth: 1,
          pointBackgroundColor: 'RGB(72,128,247)'
        }]
      },
      ...略
    </script>
  <?php endif; ?>

こちらも説明していきます。

まずはPHP側で追加したコード2行です。
PHP側の処理で作成した配列をjsonデータに置き換えました。

$jsonLabelArray = json_encode($chartLabels);
$jsonPointArray = json_encode($chartPoints);

続いてこの置換されたデータをJavaScriptで受け取ります。

var $labelArray = <?php echo $jsonLabelArray; ?>;
var $pointArray = <?php echo $jsonPointArray; ?>;

そしてこの変数をグラフのデータに入れます。

type: 'radar',
  data: {
    labels: $labelArray,
    datasets: [{
      data: $pointArray,
      backgroundColor: 'RGBA(181,217,253, 0.5)',
      borderColor: 'RGBA(72,128,247, 1)',
      borderWidth: 1,
      pointBackgroundColor: 'RGB(72,128,247)'
    }]
  },

これでデータの連携ができました。
問題なければ入力したデータでグラフが表示されているはずです。やったね!

ショートコード化する

ついでなのでショートコード化もしようと思います。

ショートコードはfunctions.phpに処理を追加します。

function chart_shortcode_func( $atts ) {
  return '<div class="chart"><canvas id="radarChart"></canvas></div>';
}
add_shortcode( 'chart', 'chart_shortcode_func' );

これでエディタ内で下記のように呼び出すことができるようになりました。

[chart]

// ブラウザでの表示
<div class="chart"><canvas id="radarChart"></canvas></div>

関数を含めたい

phpやWordPressの関数をショートコードに含めることも可能です。

function chart_shortcode_func( $atts ) {
  $a = shortcode_atts(array(
    'value' => 3,
  ), $atts);

  return '<dl class="chartWrapper">
    <dt class="chartHeader">総合評価:
      <span id="js-fill-star" class="stars">
        <img src="' . (1 <= esc_attr($a['value']) ? esc_url(get_theme_file_uri()) . '/icons/icon_star_filled.png' : esc_url(get_theme_file_uri()) . '/icons/icon_star.png') . '" alt="star">
        <img src="' . (2 <= esc_attr($a['value']) ? esc_url(get_theme_file_uri()) . '/icons/icon_star_filled.png' : esc_url(get_theme_file_uri()) . '/icons/icon_star.png') . '" alt="star">
        <img src="' . (3 <= esc_attr($a['value']) ? esc_url(get_theme_file_uri()) . '/icons/icon_star_filled.png' : esc_url(get_theme_file_uri()) . '/icons/icon_star.png') . '" alt="star">
        <img src="' . (4 <= esc_attr($a['value']) ? esc_url(get_theme_file_uri()) . '/icons/icon_star_filled.png' : esc_url(get_theme_file_uri()) . '/icons/icon_star.png') . '" alt="star">
        <img src="' . (5 <= esc_attr($a['value']) ? esc_url(get_theme_file_uri()) . '/icons/icon_star_filled.png' : esc_url(get_theme_file_uri()) . '/icons/icon_star.png') . '" alt="star">
      </span>
      <b class="number">' . esc_attr(number_format($a['value'], 1)) . '</b>
    </dt>
    <dd class="chartBody"><canvas id="radarChart"></canvas></dd>
  </dl>';
}
add_shortcode( 'chart', 'chart_shortcode_func' );

果たしてこれがパフォーマンス的に良いかどうかは置いておいて・・与えられたパラメータから三項演算子を使用して動的に画像を変更した例です。
valueの値によって色付き星マークの画像を動的に表示するグラフのショートコードができました。

[chart value="3.5"]

while文を使用したい

繰り返しフィールドなどで入力したデータの数だけ一部のHTMLを生成したい、ということも出てきます。
データの数だけliの要素を生成したい、みたいな感じですね。

こんな感じで書けます。

function hoge_shortcode_func( $atts ) {
  $code = '';
  $code .= '<ul>';
  while (the_repeater_field('chart')) {
    $code .= '<li><dl><dt>' . get_sub_field('label') . '</dt><dd>【<img src="' . esc_url(get_theme_file_uri()) . '/icons/icon_star_filled.png" alt="star">' . number_format(get_sub_field('point'), 1) . '】</dd></dl></li>';
  }
  $code .= '</ul>';

  return $code;
}
add_shortcode( 'hoge', 'evaluation_shortcode_func' );

変数$code.=でHTMLを付け足して返り値としています。
こちらのショートコードはこのようになります。(見やすいように改行しています。)

[hoge]

// ブラウザでの表示
<ul>
  <li>
    <dl>
      <dt>データ</dt>
      <dd>【<img src="https://〜/icons/icon_star_filled.png" alt="star">3.0】</dd>
    </dl>
  </li>
  <!-- データの数だけ li を出力 -->
  <li></li>
  ...
</ul>

やり方分からなくて結構ハマったのは秘密です。

ついでにクイックタグ化する

クイックタグとはWordPressのv4以下でテキストエディタに搭載されていたボタンです。

クイックタグの例

WordPress v5.0.0からはエディタが変わったので最近始めたばかりの人はあまり見かけることはないと思いますが、企業ではまだまだv4以下のところで運用している企業も少なくはないです。

こちらもfunctions.phpに書いていきます。

function chart_quicktags() {
  if ( wp_script_is( 'quicktags' ) ) {
  ?>
  <script type="text/javascript">
    QTags.addButton( 'chart', 'レーダーチャート', '[chart]', '');
  </script>
  <?php
  }
}
add_action( 'admin_print_footer_scripts', 'chart_quicktags' );

これでテキストエディタのボタンに『レーダーチャート』というボタンが配置されました。
ボタンをクリックすると[chart]というショートコードが挿入されます。

これで完成です!

ちなみにビジュアルエディタのほうにボタンを追加するとなると別の方法になりますのでお気をつけて。

参考にしたサイト

2