JavaScriptでWordPress内のPHPファイルにAjax通信を試みる

実装する機会があったので、改めて調べてみました。WordPressのCodexに書いてあるwp_ajax(action)の説明を参考にしています。

会社のオフィシャルサイトのホームページの下部でAjaxを使用していました、InstagramのAPIをコールしてJavaScriptでAjax通信を行って、Instagramの写真を表示しています。

functions.phpにAjax通信の準備

まずは、functions.phpにAjax通信を行うための準備を行います。以下のようなコードを追加しました。

function ajax_scripts() {
  $handle = 'instagram';
  $file   = get_template_directory_uri() . '/js/' . $handle . '.js';

  wp_register_script( $handle, $file, array( 'jquery' ) );

  $action = 'instagram-action';

  wp_localize_script( $handle, 'INSTAGRAM_AJAX', [
      'api'    => admin_url( 'admin-ajax.php' ),
      'action' => $action,
      'nonce'  => wp_create_nonce( $action )
  ]);
  wp_enqueue_script( $handle );
}
add_action( 'wp_enqueue_scripts', 'ajax_scripts' );

5行目の処理は、Ajax通信を行うためのJavaScriptファイルをキューに登録します。

9~14行目で、JavaScriptのグローバル変数の定義をしています。10行目のコードは、WordPressが用意しているajaxのファイルを指定しています。11行目は、ajaxのアクション名(任意)。12行目は参照元の正当性を保つためのnonce指定。このコードを実行すると、ソースコード上に以下のようなJavaScriptが展開されます。(本来は1行で出力されますが、見やすく改行を入れています。)

<script type='text/javascript'>
/* <![CDATA[ */
var INSTAGRAM_AJAX = {
  "api":"http:\/\/localhost\/wordpress\/wp-admin\/admin-ajax.php",
  "action":"instagram-action",
  "nonce":"ca7be0469f"
};
/* ]]> */
</script>

確認ができたら、functions.phpに今度はAjax通信した先に動く処理を追記します。以下のようなコードを書きました。

function ajax_instagram_call () {
  $action = 'instagram-action';
  $data   = '';

  if( check_ajax_referer( $action, 'nonce', false ) ) {
    if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) {
      $access_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
      $data = @file_get_contents("https://api.instagram.com/v1/users/self/media/recent/?access_token={$access_token}&count=16");
    }
  } else {
    status_header( '403' );
    $data = 'Forbidden';
  }
  header( 'Content-Type: application/json; charset=UTF-8' );
  echo $data;

  die();
}
add_action( 'wp_ajax_instagram-action',        'ajax_instagram_call' );
add_action( 'wp_ajax_nopriv_instagram-action', 'ajax_instagram_call' );

19・20行目のフックポイントの書き方がポイント。「wp_ajax_」「wp_ajax_nopriv_」の後ろに動作させるAjaxのaction名を指定します。noprivの方はログアウト中、noprivがついてない方はログイン中のみ動作するフックポイントになります。

あとは、InstagramのAPIをCallする記述をPHPで書いて、JSON形式でJavaScriptに返してあげます。

JavaScriptでAjax呼び出し

WordPress側で出力したグローバル変数を利用してAjax通信を行います。8・12・13行目で指定しているのがグローバル変数です。

jQuery(function($) {
  $(function () {
    let
      container = $("#js-list-instagram"),
      html = "";

    $.ajax({
      url: INSTAGRAM_AJAX.api,
      type: "POST",
      dataType: "json",
      data: {
        action: INSTAGRAM_AJAX.action,
        nonce: INSTAGRAM_AJAX.nonce
      }
    }).done(function (data) {
      $.each(data.data, function (i, item) {
        let
          imgUrl = item.images.low_resolution.url,
          link = item.link;

        html += "<li><a href='" + link + "' target='_blank'><img src='" + imgUrl + "' alt='manabito Corp instagram photo " + (i + 1) + "'></a></li>";
      });
    }).fail(function () {
      html = "<li>画像を取得できませんでした。</li>";
    }).always(function () {
      container.html(html);
    });
  });
});

Ajax通信する際に、dataとしてactionとnonceを渡してあげます。動作させるAjax処理と参照元の正当性を保つnonceをセットしてAjax通信を行います。done()でAjax通信の成功確認して取得したデータを使用してInstagramの画像を表示します。

instagramのAPIで画像取得した結果

取得できた!\(^o^)/
複雑そうだけど、わかればそうでもないですね。グローバル変数を定義するのに若干の抵抗はありますが……