GAS

GASでブログ記事一覧を取得してスプレッドシートに記録する方法

n-mukineer
にゃーミ
にゃーミ

WordPress REST APIを使えるようになったのはいいけど、実際GASを使って記事一覧を取得するにはどうプログラムを書いたらいいかわからないニャ…

こういった悩みを解決するため、本記事では「GASでWordPress REST APIを使用して記事一覧の情報を取得するプログラム」をサンプルコードを付けて解説します。

本記事のテーマ

GASでWordPressの記事一覧の情報を取得するプログラムが使えるようになる

WordPress REST APIを有効化する方法は以下の記事で解説しましたので、まだ準備ができていない場合はお読みください。

あわせて読みたい
WordPress REST APIの有効化方法
WordPress REST APIの有効化方法

GASでブログ記事一覧を取得してスプレッドシートに記録する方法

ここからはGASスクリプトを公開して説明していきます。より理解を深めたい方はWordPress REST APIの公式ドキュメントを参照しつつ読んでください。

GASで実現したいこと

すでに公開済みの記事一覧を取得し、スプレッドシートに各記事の下記の情報を記録する

  • 記事ID
  • 作成日
  • 最終更新日
  • スラッグ(URL)
  • 状態(公開済みならpublish, 下書きならdraftなど)
  • リンク
  • タイトル
  • アイキャッチ画像のID

GASプロジェクトとスプレッドシートの準備

GASの新規プロジェクトを作成し、スプレッドシートも新規作成しておきます。

スプレッドシートを開いて、ブラウザのアドレスバーからスプレッドシートのID(以下の部分)をコピーし、GASのスクリプトに貼り付けます。

GASスクリプト(コード.gs)には、以下のように定数を書いておきます。

const PASSWORD = "xxxx xxxx xxxx xxxx xxxx xxxx"; // 4文字 * 6ブロック = 24文字(途中のスペースはあってもなくてもよい)
const SPREADSHEET_ID = "スプレッドシートID"; // スプレッドシートIDを入れる
const USER_ID = "WordPressのユーザーID"; // WordPressのユーザーIDを入れる
const BASE_URL = "https://hogefugapiyo.com"; // ブログのURL
const ENDPOINT = { // REST APIのエンドポイント
  posts: "/wp-json/wp/v2/posts",
}

基本:1つのシートにすべて羅列する場合

まずは、「記事一覧情報を取得して、1つのシートにすべて羅列する」場合のスクリプトを作成していきます。

手っ取り早く使用したい場合は、以下の「+」ボタンを押してコードを表示してコピペして使ってください。

Q
(コピペ用)公開記事一覧を取得して、スプレッドシートの”all”というシートに出力するGASスクリプト
const PASSWORD = "xxxx xxxx xxxx xxxx xxxx xxxx"; // 4文字 * 6ブロック = 24文字(途中のスペースはあってもなくてもよい)
const SPREADSHEET_ID = "スプレッドシートID"; // スプレッドシートIDを入れる
const USER_ID = "WordPressのユーザーID"; // WordPressのユーザーIDを入れる
const BASE_URL = "https://hogefugapiyo.com"; // ブログのURL
const ENDPOINT = { // REST APIのエンドポイント
  posts: "/wp-json/wp/v2/posts",
}

// 実行用関数
function main() {
  setAllPublishedArticlesToSS();
}

// 公開済み記事一覧を"all"シートに全部記録
function setAllPublishedArticlesToSS() { 
  const activeSheet = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheetNames = activeSheet.getSheets().map(sheet => sheet.getName());

  const newSheetName = "all";

  if(!sheetNames.includes(newSheetName)) {
    let newSheet = activeSheet.insertSheet();
    newSheet.setName(newSheetName);
    console.log(`シート【${newSheetName}】を作成しました`);
  }
  
  const sheet = activeSheet.getSheetByName(newSheetName);
  
  // すべての公開記事一覧を取得
  const articles = getPublishedArticles();
  
  console.log(`${articles.length}件の公開済記事を取得しました`)
  articles.forEach(art => {
    const row = [
        art.id,
        art.date,
        art.modified,
        art.slug,
        art.status,
        art.link,
        art.title.rendered,
        art.featured_media
      ];
    sheet.appendRow(row);
    console.log(`【${row[6]}】を${newSheetName}に追加しました`);
  });
}

// 公開済みの記事一覧を取得
function getPublishedArticles() {
  return _recursiveGet(ENDPOINT.posts, [], null, null);
}

// ============================直接は呼ばないメソッド=============================
// 再帰的呼び出しを関数にしておく(いろんなところから呼び出せるように)
function _recursiveGet(endpoint, tookOvers, pageNum, totalPages) {
  let pageQuery;
  let currentPage;
  if(pageNum === null) {
    pageQuery = "?page=1"
    currentPage = 1;
  } else {
    pageQuery = `?page=${pageNum}`;
    currentPage = pageNum;
  }

  const options = {
    "method": "GET",
    "contentType": "application/json",
    "headers": { "Authorization": "Basic " + Utilities.base64Encode(USER_ID + ":" + PASSWORD) }
  };
  const response = UrlFetchApp.fetch(BASE_URL + endpoint + pageQuery, options);

  let newTotalPages = null;
  if(totalPages === null) {
    // トータルページ数を取得する
    newTotalPages = response.getAllHeaders()["x-wp-totalpages"];
  }
  const partials = JSON.parse(response);

  // 最終ページかどうかで分岐
  if(totalPages == currentPage) {
    // 最終ページまで来たらおわり
    return [...tookOvers, ...partials];
  } else {
    // 最終ページではない場合は、再帰的に取得していく
    return [...tookOvers, ..._recursiveGet(endpoint, partials, currentPage + 1, totalPages || newTotalPages)];
  }
}

このスクリプトのmain関数を実行すると、以下の画像のようにスプレッドシートの「all」というシートが作成され、一覧の情報が書き込まれます。

スプレッドシートの「all」シートに情報が書き込まれる

以下は、スクリプトの解説です。大きく分けて、

  1. 公開記事一覧を取得する
  2. スプレッドシートに記録する

という2つの要素から構成されていますので、順に説明していきます。

公開記事一覧を取得するスクリプト

まずは「公開記事一覧の情報を取得する」部分のスクリプトを解説します。

// 公開済みの記事一覧を取得
function getPublishedArticles() {
  return _recursiveGet(ENDPOINT.posts, [], null, null);
}

// ============================直接は呼ばないメソッド=============================
// 再帰的呼び出しを関数にしておく(いろんなところから呼び出せるように)
function _recursiveGet(endpoint, tookOvers, pageNum, totalPages) {
  let pageQuery;
  let currentPage;
  if(pageNum === null) {
    pageQuery = "?page=1"
    currentPage = 1;
  } else {
    pageQuery = `?page=${pageNum}`;
    currentPage = pageNum;
  }

  const options = {
    "method": "GET",
    "contentType": "application/json",
    "headers": { "Authorization": "Basic " + Utilities.base64Encode(USER_ID + ":" + PASSWORD) }
  };
  const response = UrlFetchApp.fetch(BASE_URL + endpoint + pageQuery, options);

  let newTotalPages = null;
  if(totalPages === null) {
    // トータルページ数を取得する
    newTotalPages = response.getAllHeaders()["x-wp-totalpages"];
  }
  const partials = JSON.parse(response);

  // 最終ページかどうかで分岐
  if(totalPages == currentPage) {
    // 最終ページまで来たらおわり
    return [...tookOvers, ...partials];
  } else {
    // 最終ページではない場合は、再帰的に取得していく
    return [...tookOvers, ..._recursiveGet(endpoint, partials, currentPage + 1, totalPages || newTotalPages)];
  }
}
  • _recursiveGet()関数

ここで実行するための関数はgetPublishedArticles()ですが、直接ロジックを書かずに、_recursiveGet()という関数を別で用意して呼び出しています。

これは、後述する「カテゴリ一覧の取得」においてもほぼ同じ書き方(エンドポイントだけ変えるだけ)ができるようにするためです。

ちなみに_recursiveGet()の先頭の_(アンダースコア)「main関数から直接この関数を呼ぶことはない」というのを明示するために付けています。特につけなくても問題ありません。

_recursiveGet()関数は、再帰的(recursive)に実行していく関数であり、今回の場合はエンドポイントにGETメソッドを実行した際に、複数のページにまたがって(1ページあたり10件取得できる)データを取得する必要があります。

  • 取得するページの指定

ページの指定は、URLにクエリパラメータで?page=1のように指定することで可能です。1回目の読み出しの時は1ページ目を取得するように、以下のコードを書いています。

  let pageQuery;
  let currentPage;
  if(pageNum === null) {
    pageQuery = "?page=1"
    currentPage = 1;
  } else {
    pageQuery = `?page=${pageNum}`;
    currentPage = pageNum;
  }
  • REST APIをGETメソッドで実行

REST APIを実行する部分のコードはこのようになっています。ヘッダーには、ユーザーIDとパスワードをBase64エンコードした情報を付加しています。

  const options = {
    "method": "GET",
    "contentType": "application/json",
    "headers": { "Authorization": "Basic " + Utilities.base64Encode(USER_ID + ":" + PASSWORD) }
  };
  const response = UrlFetchApp.fetch(BASE_URL + endpoint + pageQuery, options);

「公開済みである」というのは特にパラメータには入っていません。クエリパラメータにstatusを指定することができますが、そのデフォルト値がpublished(公開済み)となっているためです。もし、下書き状態の記事のみを取得したいという場合はpageQuery+"&status=draft"のように指定してください。

  • 記事の情報が何ページ目まであるか

記事の情報が最大何ページ目まであるかは、この部分でレスポンスのヘッダー部分から読み出しています。(このコードは1ページ目を取得したときだけ実行され、2ページ目以降の取得では再帰呼び出しの際に引き継がれていきます)

  let newTotalPages = null;
  if(totalPages === null) {
    // トータルページ数を取得する
    newTotalPages = response.getAllHeaders()["x-wp-totalpages"];
  }
  • 再帰呼び出し

最後に、再帰的に処理を呼び出します。最後のページでの実行である場合は再帰呼び出しはせず、結果をreturnするようになっています。

  // 最終ページかどうかで分岐
  if(totalPages == currentPage) {
    // 最終ページまで来たらおわり
    return [...tookOvers, ...partials];
  } else {
    // 最終ページではない場合は、再帰的に取得していく
    return [...tookOvers, ..._recursiveGet(endpoint, partials, currentPage + 1, totalPages || newTotalPages)];
  }

スプレッドシートに記録していく処理

次に、「取得した記事一覧の情報を、スプレッドシートに記録していく」部分を解説します。

// 公開済み記事一覧を"all"シートに全部記録
function setAllPublishedArticlesToSS() { 
  const activeSheet = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheetNames = activeSheet.getSheets().map(sheet => sheet.getName());

  const newSheetName = "all";

  if(!sheetNames.includes(newSheetName)) {
    let newSheet = activeSheet.insertSheet();
    newSheet.setName(newSheetName);
    console.log(`シート【${newSheetName}】を作成しました`);
  }
  
  const sheet = activeSheet.getSheetByName(newSheetName);
  
  // すべての公開記事一覧を取得
  const articles = getPublishedArticles();
  
  console.log(`${articles.length}件の公開済記事を取得しました`)
  articles.forEach(art => {
    const row = [
        art.id,
        art.date,
        art.modified,
        art.slug,
        art.status,
        art.link,
        art.title.rendered,
        art.featured_media
      ];
    sheet.appendRow(row);
    console.log(`【${row[6]}】を${newSheetName}に追加しました`);
  });
}
  • スプレッドシートのシート名をすべて取得

スプレッドシートをID指定して読み込みます。そしてsheetNamesという変数に、「今スプレッドシートにあるシート名すべて」を読み込んでおきます。

const activeSheet = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheetNames = activeSheet.getSheets().map(sheet => sheet.getName());
  • シートを作成

「all」という名前のシートを作成します。ただし、すでに存在しているかどうかを前述のsheetNamesの中身から確認します。既に存在している場合は作成しません。

const newSheetName = "all";

if(!sheetNames.includes(newSheetName)) {
  let newSheet = activeSheet.insertSheet();
  newSheet.setName(newSheetName);
  console.log(`シート【${newSheetName}】を作成しました`);
}

const sheet = activeSheet.getSheetByName(newSheetName);
  • 記事情報を取得してスプレッドシートに書き込み

getPublishedArticles()関数を呼び出してすべての記事情報を取得します。そして、forEachを使ってappendRow()関数によりスプレッドシートに所望の情報を追加していきます。

 // すべての公開記事一覧を取得
  const articles = getPublishedArticles();
  
  console.log(`${articles.length}件の公開済記事を取得しました`)
  articles.forEach(art => {
    const row = [
        art.id,
        art.date,
        art.modified,
        art.slug,
        art.status,
        art.link,
        art.title.rendered,
        art.featured_media
      ];
    sheet.appendRow(row);
    console.log(`【${row[6]}】を${newSheetName}に追加しました`);
  });

応用:カテゴリ別にシートを分けたい場合

記事数が増えてくると、カテゴリ別にシートを分けて管理したくなることがあります。その場合、カテゴリ名でシートを分けて、そのカテゴリに該当する記事の情報を一覧として記録できるようにすると便利です。

Q
(コピペ用)公開記事一覧を取得して、スプレッドシートにカテゴリ別にシートを分けて出力するGASスクリプト
const PASSWORD = "xxxx xxxx xxxx xxxx xxxx xxxx"; // 4文字 * 6ブロック = 24文字(途中のスペースはあってもなくてもよい)
const SPREADSHEET_ID = "スプレッドシートID"; // スプレッドシートIDを入れる
const USER_ID = "WordPressのユーザーID"; // WordPressのユーザーIDを入れる
const BASE_URL = "https://hogefugapiyo.com"; // ブログのURL
const ENDPOINT = { // REST APIのエンドポイント
  posts: "/wp-json/wp/v2/posts",
}

// 実行用関数
function main() {
  setAllPublishedArticlesToSSByCategories()
}

// 公開済み記事一覧をスプレッドシートにカテゴリごとにシートを分けて記録
function setAllPublishedArticlesToSSByCategories() {
  const activeSheet = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheetNames = activeSheet.getSheets().map(sheet => sheet.getName());
  const categories = getCategories();
  categories.forEach(cat => {
    if(sheetNames.includes(cat.name)) {
      // すでにシートが存在する場合は何もしない
      return;
    }
    // カテゴリ名をシート名としてシート作成
    let newSheet = activeSheet.insertSheet();
    newSheet.setName(cat.name);
    console.log(`シート【${cat.name}】を作成しました`);
  });

  // すべての公開記事一覧を取得
  const articles = getPublishedArticles();
  
  // すべてのカテゴリについて、該当する記事をスプレッドシートに記載していく
  // カテゴリが複数設定されていたら、複数のシートに記載される
  categories.forEach(cat => {
    const sheet = activeSheet.getSheetByName(cat.name);
    articles.forEach(art => {
      if(art.categories.includes(cat.id)) {
        const row = [
            art.id,
            art.date,
            art.modified,
            art.slug,
            art.status,
            art.link,
            art.title.rendered,
            art.featured_media
          ];
        sheet.appendRow(row);
        console.log(`【${row[6]}】を${cat.name}に追加しました`);
      }
    });
  });
}

// 公開済みの記事一覧を取得
function getPublishedArticles() {
  return _recursiveGet(ENDPOINT.posts, [], null, null);
}

// カテゴリ一覧を取得
function getCategories() {
  return _recursiveGet(ENDPOINT.categories, [], null, null);
}


// ============================直接は呼ばないメソッド=============================

// 再帰的呼び出しを関数にしておく(いろんなところから呼び出せるように)
function _recursiveGet(endpoint, tookOvers, pageNum, totalPages) {
  let pageQuery;
  let currentPage;
  if(pageNum === null) {
    pageQuery = "?page=1"
    currentPage = 1;
  } else {
    pageQuery = `?page=${pageNum}`;
    currentPage = pageNum;
  }

  const options = {
    "method": "GET",
    "contentType": "application/json",
    "headers": { "Authorization": "Basic " + Utilities.base64Encode(USER_ID + ":" + PASSWORD) }
  };
  const response = UrlFetchApp.fetch(BASE_URL + endpoint + pageQuery, options);

  let newTotalPages = null;
  if(totalPages === null) {
    newTotalPages = response.getAllHeaders()["x-wp-totalpages"];
  }
  const partials = JSON.parse(response);

  // 最終ページかどうかで分岐
  if(totalPages == currentPage) {
    // 最終ページまで来たらおわり
    return [...tookOvers, ...partials];
  } else {
    // 最終ページではない場合は、再帰的に取得していく
    return [...tookOvers, ..._recursiveGet(endpoint, partials, currentPage + 1, totalPages || newTotalPages)];
  }
}

カテゴリー一覧を取得

カテゴリー一覧を取得するには、作成しておいた_recursiveGet()関数を使えば下記のように1行で済ませることができます。

// カテゴリ一覧を取得
function getCategories() {
  return _recursiveGet(ENDPOINT.categories, [], null, null);
}

公開記事一覧をカテゴリごとにシートを分けてスプレッドシートに記録

上で紹介したsetAllPublishedArticlesToSS()関数と似ています。違う部分は、「カテゴリごとにシートを分ける」という部分です。コード内にコメントで解説を入れました。

// 公開済み記事一覧をスプレッドシートにカテゴリごとにシートを分けて記録
function setAllPublishedArticlesToSSByCategories() {
  const activeSheet = SpreadsheetApp.openById(SPREADSHEET_ID);
  const sheetNames = activeSheet.getSheets().map(sheet => sheet.getName());
  // カテゴリ一覧を取得
  const categories = getCategories();
  categories.forEach(cat => {
    if(sheetNames.includes(cat.name)) {
      // すでにシートが存在する場合は何もしない
      return;
    }
    // カテゴリ名をシート名としてシート作成
    let newSheet = activeSheet.insertSheet();
    newSheet.setName(cat.name);
    console.log(`シート【${cat.name}】を作成しました`);
  });

  // すべての公開記事一覧を取得
  const articles = getPublishedArticles();
  
  // すべてのカテゴリについて、該当する記事をスプレッドシートに記載していく
  // カテゴリが複数設定されていたら、複数のシートに記載される
  categories.forEach(cat => {
    const sheet = activeSheet.getSheetByName(cat.name);
    articles.forEach(art => {
      // ここで記事がいま対象としているカテゴリに該当しているかを見ている
      if(art.categories.includes(cat.id)) {
        const row = [
            art.id,
            art.date,
            art.modified,
            art.slug,
            art.status,
            art.link,
            art.title.rendered,
            art.featured_media
          ];
        sheet.appendRow(row);
        console.log(`【${row[6]}】を${cat.name}に追加しました`);
      }
    });
  });
}

WordPress REST APIを使えばGASで記事投稿もできる

本記事では記事一覧の「取得」をするスクリプトを紹介しましたが、WordPress REST APIを使えば記事を「投稿」したり、「編集」したりすることが可能です。

以下の記事では、テンプレート化した記事を下書きとして投稿する方法を紹介していますので、是非読んでみてください。

ブログ投稿をGASで行う
GASでテンプレート化したブログ記事を下書き投稿する方法
GASでテンプレート化したブログ記事を下書き投稿する方法

まとめ

本記事では、「GASとWordPress REST APIを使ってブログ記事一覧を取得してスプレッドシートに記録する」方法を紹介しました。まだまだWordPress REST APIを使えばできることは幅広くありますので、引き続きいろいろと使ってみようと思います。

このブログを書いている人
えぬ
えぬ
N日後にムキムキになるエンジニア
WebアプリエンジニアとしてIoTシステムを開発中。30代折り返し。 趣味(モノづくり、プログラミング、筋トレ)や子育てのことを主に記事にします。 TOEIC: 900点/第一級陸上無線技術士/第3種電気主任技術者/技術士一次試験合格/基本情報技術者/第2種電気工事士/デジタル技術検定2級(情報・制御)
記事URLをコピーしました