CUEBiC TEC BLOG

キュービックTECチームの技術ネタを投稿しております。

RESTAPIを使って記事一覧を作ってみた

地味に逃げ続けていたGASと格闘してましたmikihoです
今回はWordPressスプレッドシートの連携をRESTAPIを使って実現した方法について説明していきます。

わざわざスプレッドシートに一覧を作る必要があるのか、という疑問もありますが、意外と需要があるのです。
運用側からしたら、わざわざWordPressにログインして、必要な情報によっては投稿などの中に入って一つ一つ確認しなくてはいけないのは手間だそうで。
小規模なメディアならともかく、長く運用を続けていると正直確認だけで工数が…と言うことで、REST APIを使って自動化してみたのです。

今回は方法を大きく2つに分けて解説していきます。

基本的な情報のみの一覧

ここでいう基本的な情報とは、投稿の基本情報「ID」「タイトル」「投稿日」「更新日」などなどを示します。
ここにはカスタムフィールドの値は含んでおりません。

GASのコードとしては下記のような形になります

var SITE = "取得したいサイトURL";
function getArticles() {
var sheetArticleList = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('一覧を吐き出したいシート名');
// WP REST APIでカテゴリを取得する
var categories = getCategories();
// WP REST APIで記事を取得する
var jsonArticleInfo = UrlFetchApp.fetch(SITE + '/wp-json/wp/v2/posts?order=asc&per_page=100', {'method':'get'});
var articleInfos = JSON.parse(jsonArticleInfo.getContentText());
 // 総ページ数
var totalPages = jsonArticleInfo.getHeaders()["x-wp-totalpages"];
// 取得した記事情報から出力するデータを作成
 var output = makeOutputData(articleInfos, categories);
 // シートの2行目から出力する
sheetArticleList.getRange(2, 1, output.length, output[0].length).setValues(output);
// 記事数が2ページ以上ある場合は、総ページ数分、繰り返し処理する
if (totalPages > 1) {
for (var index = 2; index <= totalPages; index++) {
// 最終行
var lastRow = sheetArticleList.getRange('A:A').getValues().filter(String).length;
// WP REST APIで記事を取得する
jsonArticleInfo = UrlFetchApp.fetch(SITE + '/wp-json/wp/v2/posts?order=asc&per_page=100&page=' + index, {'method':'get'});
articleInfos = JSON.parse(jsonArticleInfo.getContentText());
// 取得した記事情報から出力するデータを作成
 output = makeOutputData(articleInfos, categories);
// シート最終行の次の行から出力する
sheetArticleList.getRange(lastRow+1, 1, output.length, output[0].length).setValues(output);
}
}
}  
function getCategories() {
// WP REST APIでカテゴリを取得する
var jsonCategoryInfo = UrlFetchApp.fetch(SITE + '/wp-json/wp/v2/categories?orderby=id&per_page=100', {'method':'get'}); 
var categoryInfos = JSON.parse(jsonCategoryInfo.getContentText());
var categories = [];
for(var index = 0; index < categoryInfos.length; index++){
var categoryInfo = categoryInfos[index];
var row = [];
// ID
row.push(categoryInfo["id"]);
// 名前
row.push(categoryInfo["name"]);
categories.push(row);
}
return categories;
}
function makeOutputData(articleInfos, categories) {
var output = [];
for(var index = 0; index < articleInfos.length; index++){
var articleInfo = articleInfos[index];
var row = [];
// 公開日
row.push(Utilities.formatDate(new Date(articleInfo["date"]), 'JST', 'yyyy/M/d'));
// 更新日
row.push(Utilities.formatDate(new Date(articleInfo["modified"]), 'JST', 'yyyy/M/d'));
// カテゴリ
var articleCategories = articleInfo["categories"];
var category = "";
 for (var articleCategoryIndex = 0; articleCategoryIndex < articleCategories.length; articleCategoryIndex++) {
if (category.length != 0) {
category += ",";
}
category += getCategoryName(categories, articleCategories[articleCategoryIndex]);
}
row.push(category);
 // タイトル
row.push(articleInfo["title"]["rendered"]);   
// 記事ID
row.push(articleInfo["id"]);
// URL
row.push(articleInfo["link"]);
// パス
row.push(articleInfo["link"].replace(SITE, ""));
output.push(row);
}
return output;
}
function getCategoryName(categories, articleCategoryId) {
var ret = "";
for (var index = 0; index < categories.length; index++) {
var category = categories[index];
if (articleCategoryId == category[0]) {
ret = category[1];
break;
}
}
 return ret;
}

これで基本的な情報は取得できます。
ちなみに、あえて本文は取得させておりません。
本文も取得できますが、今回はあくまで記事一覧が欲しいというお話をいただいて作っていたものなので。

※ちなみに、本文の文字数がセルの最大文字数を超える可能性もあるので、必要なければ取得しないことをお勧めいたします...

定期実行させるためのトリガーを設定すれば簡単に自動化が完了するのです。

カスタムフィールドの情報を含ませたい

一覧にカスタムフィールドの情報も表示させたい、となると少し改良が必要になります。
RESTAPIではデフォルトでカスタムフィールドの中身は取得できないので、functions.phpなどに追加するためのコードが必要になるからです。

WordPress側に追加するコードは下記のような形になります

<?php
add_action( 'rest_api_init', 'api_add_custom_fields' );
    function api_add_custom_fields() {
      register_rest_field(
        'post', //カスタムフィールドの情報を追加したいpost_type名
        'custom_field', //取得した際の名前
        array(
          'get_callback'    => 'add_get_custom_field', //カスタムフィールドを取得するための関数名
          'update_callback' => null,
          'schema'          => null,
          )
        );
      }
    
      function add_get_custom_field($object, $field_name, $request) {
        $meta_fields = array(
          'custom_field1',//カスタムフィールド名
          'custom_field2'
          );
          $meta = array();
          foreach ( $meta_fields as $field ) {
            $meta[$field] = get_post_meta( $object[ 'id' ], $field, true );
          }
          return $meta;
      }
?>

排出する内容は自分で整形する必要があるので、そこら辺の処理も一緒に追加しておくことをお勧めします。
GASはコード管理が難しいので、管理がしやすいテーマ側に処理を寄せた方が後々のトラブルを回避できるでしょう。

これでEST APIにカスタムフィールドの値が追加されました。
あとはタイトルなどと変わらない方法で書き出すためのコードをGAS側に追加するだけで完成します。

補足

REST APIはデフォルトではたくさんの情報を取得します。
が、その分重くなりがちなので必要のない情報は取得しない形にまとめておくことが理想です。
functions.phpにて、下記のようなコードでRESTAPI上から情報を消しておきましょう

<?php
    //いらない取得データの削除
      function remove_post_data($response, $post, $request) {
        unset($response->data['id']);
        unset($response->data['slug']);
        unset($response->data['excerpt']);
        unset($response->data['status']);
        unset($response->data['content']);
        unset($response->data['type']);
        unset($response->data['menu_order']);
        unset($response->data['comment_status']);
        unset($response->data['ping_status']);
        return $response;
    }   
    add_filter('rest_prepare_page','remove_post_data' , 10, 3);
?>

応用編

今回紹介したのはあくまで投稿一覧ですが、カスタム投稿の一覧も作ることが可能です。
URLの一部をカスタム投稿のpost_typeに変更するだけで、ほとんどコードを変更する必要なく取得ができます。 ですが、注意しなくてはいけないのは、show_in_resttrueにしておくこと。
カスタム投稿はデフォルトでは、show_in_restfalseのため、REST APIを叩いても404が返ってきてしまいますのでそこだけ注意が必要です。

そして、アクセス先のURLも当然変わってきます。
具体例を挙げると下記のような形になりますね。

    /wp-json/wp/v2/posts

ここを

    /wp-json/wp/v2/pages

などのような形でpost_type名に変更するだけです。
例では固定ページのpost_typeを入れていますが、カスタム投稿のpost_typeを入れれば取得が可能になります!

注意点

REST APIは基本的にドメイン/wp-json/wp/v2/〜という形式ですが、パーマリンクの構造をデフォルト設定にしている場合この形式ではなく別の形式になります。
その場合はドメイン/?rest_route=wp/v2/〜という形式で書かなくてはいけなくなるのです。
パーマリンクの構造を変えてもいい場合は変更してもいいかと思いますが、そうでない場合の方が多いと思いますので、取得の形式が違う、というのは覚えておきましょう。