Practical example

ISBNを入力して
書籍情報を自動取得

WordPressの投稿編集画面でISBN番号を入力すると、楽天Books API から書籍名、著者、出版社、価格、表紙画像などの書籍情報を取得し、atshift Fieldsの入力欄へ自動入力する実装例です。

01

処理の流れ

  1. 投稿編集画面で「書籍紹介」用のフィールドグループを表示します。
  2. isbn フィールドへ13桁のISBN番号を入力します。
    • 管理画面のJavaScriptがWordPressのAjaxへISBNを送ります。
    • WordPressがサーバー側から楽天Books APIへ問い合わせます。
    • 結果を自動で atshift Fieldsの各入力欄へ反映します。
  3. 内容を確認して、通常どおり投稿を保存します。
ポイント

楽天APIの認証情報はPHP側だけで使用します。ブラウザから楽天APIへ直接アクセスさせないため、HTMLやJavaScriptへキーが露出しません。

02

楽天 Books Search API を登録して固有のID/キーを取得する

  1. 楽天ウェブサービスの公式API仕様 (英語) を開いて、上部の New App をクリックします(未ログインの場合はログインしてください)。
  2. 登録フォームの各項目
    • Application Name (名称):例 Rakuten Books など
    • Application URL (URL):WebサイトのURL
    • Application Type (種別):Web Application を選択
    • Allowed websites (APIを許可するサイト):WebサイトのURLから https:// などを省いたもの。プレイスホルダに表示された入力例を参考にしてください。
    • Application description (説明文):どの様な目的で使うか日本語で説明文を書きます。
    • Purpose of data usage (利用目的):個人ブログの記事作成時に、ISBNをもとに楽天Books APIから書籍情報を取得し、書籍紹介ページへ掲載するために使用します。取得した情報の販売や第三者への提供は行いません。
    • Expected QPS (想定リクエスト数):1 を入力
    • Rakuten Books API にチェック
  3. CAPCHA を入力して Agree to the term of service をクリック
  4. 取得した Application ID と Access Key をメモします。
03

atshift Fieldsでフィールドを用意する

フィールド名はJavaScriptの対応表と一致させます。必要な項目だけ作成しても構いません。

isbn
単一行テキスト/ISBN-13
bookname
単一行テキスト/書籍タイトル
subtitle
単一行テキスト/サブタイトル
caption
テキストエリア/商品説明
author
単一行テキスト/著者名
size
単一行テキスト/判型
bookurl
URL/楽天Booksの商品URL
fee
数値/販売価格
buyday
単一行テキスト/発売日
publisher
単一行テキスト/出版社
bookimage
URL/書籍表紙
APIによってISBNから10種の情報が得られます。
また、配置ルールで対象の投稿タイプやカテゴリーを限定すると、書籍以外の投稿編集画面にはこのフィールドグループを表示せずに運用できます。
04

API認証情報を定義する

wp-config.php にあなたの Application IDとAccess keyを追加します。wp-config.php は WordPress の第一階層にある WordPress の設定ファイルです。
ご自身の認証情報は、サンプルの該当箇所に置き換えてください。

wp-config.php

PHP設定
define( 'MY_RAKUTEN_APPLICATION_ID', 'your-application-id' );
define( 'MY_RAKUTEN_ACCESS_KEY', 'your-access-key' );
05

楽天Books API と連携する

テーマの functions.php へ以下のPHPコードを追加します。管理画面用スクリプトを読み込み、Ajaxの受け口を作ります。

functions.php

PHP
<?php
add_action( 'admin_enqueue_scripts', 'my_books_admin_assets' );
function my_books_admin_assets( $hook ) {
  if ( ! in_array( $hook, array( 'post.php', 'post-new.php' ), true ) ) {
    return;
  }

  wp_enqueue_script(
    'my-cfs-rakuten-books',
    get_stylesheet_directory_uri() . '/js/cfs-rakuten-books.js',
    array( 'jquery' ),
    '1.0.0',
    true
  );

  wp_localize_script( 'my-cfs-rakuten-books', 'myBooksApi', array(
    'ajaxUrl' => admin_url( 'admin-ajax.php' ),
    'nonce'   => wp_create_nonce( 'my_fetch_rakuten_book' ),
  ) );
}

add_action( 'wp_ajax_my_fetch_rakuten_book', 'my_fetch_rakuten_book' );
function my_fetch_rakuten_book() {
  check_ajax_referer( 'my_fetch_rakuten_book', 'nonce' );

  if ( ! current_user_can( 'edit_posts' ) ) {
    wp_send_json_error( array( 'message' => '権限がありません。' ), 403 );
  }

  $isbn = preg_replace( '/\D+/', '', wp_unslash( $_POST['isbn'] ?? '' ) );
  if ( 13 !== strlen( $isbn ) ) {
    wp_send_json_error( array( 'message' => 'ISBNは13桁で入力してください。' ), 400 );
  }

  if ( ! defined( 'MY_RAKUTEN_APPLICATION_ID' ) ||
       ! defined( 'MY_RAKUTEN_ACCESS_KEY' ) ) {
    wp_send_json_error( array( 'message' => 'API設定がありません。' ), 500 );
  }

  $url = add_query_arg( array(
    'format'        => 'json',
    'applicationId' => MY_RAKUTEN_APPLICATION_ID,
    'isbn'          => $isbn,
  ), 'https://openapi.rakuten.co.jp/services/api/BooksBook/Search/20170404' );

  $response = wp_safe_remote_get( $url, array(
    'timeout' => 10,
    'headers' => array( 'accessKey' => MY_RAKUTEN_ACCESS_KEY ),
  ) );
  if ( is_wp_error( $response ) ||
       200 !== wp_remote_retrieve_response_code( $response ) ) {
    wp_send_json_error( array( 'message' => '書籍情報を取得できませんでした。' ), 502 );
  }

  $json = json_decode( wp_remote_retrieve_body( $response ), true );
  $book = $json['Items'][0]['Item'] ?? array();
  if ( ! $book ) {
    wp_send_json_error( array( 'message' => '該当する書籍がありません。' ), 404 );
  }

  $image_url = remove_query_arg( '_ex', $book['largeImageUrl'] ?? '' );

  wp_send_json_success( array(
    'bookname'  => sanitize_text_field( $book['title'] ?? '' ),
    'subtitle'  => sanitize_text_field( $book['subTitle'] ?? '' ),
    'caption'   => sanitize_textarea_field( $book['itemCaption'] ?? '' ),
    'author'    => sanitize_text_field( $book['author'] ?? '' ),
    'size'      => sanitize_text_field( $book['size'] ?? '' ),
    'bookurl'   => esc_url_raw( $book['itemUrl'] ?? '' ),
    'fee'       => absint( $book['itemPrice'] ?? 0 ),
    'buyday'    => sanitize_text_field( $book['salesDate'] ?? '' ),
    'publisher' => sanitize_text_field( $book['publisherName'] ?? '' ),
    'bookimage' => esc_url_raw( $image_url ),
  ) );
}
05

atshift Fields の入力欄と連携する

テーマに以下のスクリプトを cfs-rakuten-books.js として js/ 内に保存します。CFSの data-name 属性を使うため、画面上の表示名を変更してもフィールド名が同じなら動作します。

js/cfs-rakuten-books.js

JavaScript
(function ($) {
  'use strict';

  var isbnSelector = '.cfs_input .field[data-name="isbn"] input';
  var fields = {
    bookname:  'input',
    subtitle:  'input',
    caption:   'textarea, input',
    author:    'input',
    size:      'input',
    bookurl:   'input',
    fee:       'input',
    buyday:    'input',
    publisher: 'input',
    bookimage: 'input'
  };

  function setField(name, value) {
    var control = fields[name] || 'input';
    $('.cfs_input .field[data-name="' + name + '"] ' + control)
      .first().val(value || '').trigger('change');
  }

  $(document).on('change', isbnSelector, function () {
    var isbn = String($(this).val()).replace(/\D/g, '');
    var $status = $('#rakuten-book-status');

    if (!$status.length) {
      $status = $('<p id="rakuten-book-status"></p>').insertAfter(this);
    }
    if (isbn.length !== 13) {
      $status.text('ISBNは13桁で入力してください。');
      return;
    }

    $status.text('楽天Booksから取得中…');
    $.post(myBooksApi.ajaxUrl, {
      action: 'my_fetch_rakuten_book',
      nonce: myBooksApi.nonce,
      isbn: isbn
    }).done(function (response) {
      if (!response.success) {
        $status.text(response.data.message || '取得できませんでした。');
        return;
      }

      $.each(response.data, setField);
      $status.text('書籍情報を反映しました。保存前に内容を確認してください。');
    }).fail(function (xhr) {
      var data = xhr.responseJSON && xhr.responseJSON.data;
      $status.text((data && data.message) || '取得できませんでした。');
    });
  });
}(jQuery));
投稿タイトルも自動入力したい場合

書籍名をCFSフィールドへ入れた後、投稿タイトル欄にも同じ値を設定できます。ただし既存タイトルを誤って上書きしないよう、空欄のときだけ反映する設計がおすすめです。

06

出力する

取得時のサニタイズとは別に、表示する場所に合わせて出力時にもエスケープします。

テンプレートで出力

PHP / HTML
<?php
$title     = CFS()->get( 'bookname' );
$author    = CFS()->get( 'author' );
$book_url  = CFS()->get( 'bookurl' );
$image_url = CFS()->get( 'bookimage' );
?>

<article class="book">
  <h2><?php echo esc_html( $title ); ?></h2>
  <p><?php echo esc_html( $author ); ?></p>

  <?php if ( $image_url ) : ?>
    <img src="<?php echo esc_url( $image_url ); ?>"
         alt="<?php echo esc_attr( $title ); ?>の表紙">
  <?php endif; ?>

  <?php if ( $book_url ) : ?>
    <a href="<?php echo esc_url( $book_url ); ?>" rel="sponsored noopener">
      楽天Booksで見る
    </a>
  <?php endif; ?>
</article>

フィールド種別ごとの出力方法は、出力リファレンスも参照してください。

07

運用前の確認

  • Application IDとAccess keyをHTMLやJavaScriptへ書かない。
  • Ajaxでnonceと編集権限を確認する。
  • ISBNは数字だけに整形し、13桁か検証する。
  • 外部APIにはタイムアウトを設定し、失敗時の表示を用意する。
  • 取得値を無条件に信用せず、保存・返却時にサニタイズする。
  • CFSの値は、HTML・URL・属性など出力先に合わせてエスケープする。
  • 自動入力後は内容を人が確認してから投稿を保存する。
API仕様は変更されることがあります。

エンドポイント、必須パラメータ、認証方法、表示条件は楽天ウェブサービスの公式資料を優先してください。