[Ususama+WordPress連携] WordPressを更新するとGithub Actionsを利用して自動的にWPの記事を新着情報として静的サイトをデプロイする

手前味噌ですが、Github Actionsを使ってWordPressの記事を静的サイトにデプロイする仕組みを作ってみました。

1. 経緯

きっかけはWordCamp Tokyo 2019で以下のセッションを聞いたことと、スポンサーブースで「マネージドクラウド」や「静的サイトへの変換」のソリューションが印象に残ったことです。 これらの事項を見聞きして、「コンテンツの更新を簡単にできる管理画面のメリットを活かしつつ、WordPressのメンテナンスコストを抑える」方法を考えた結果、今回の改修に至りました。

2. Ususamaについて

Ususamaについては以下を参照。 改めてざっくり説明すると「中小規模の静的サイト用にあれこれを準備するフレームワーク」というところです。主な機能として以下が挙げられます。
  • Gulpでejs, Scssをコンパイル+minify、JSはminify、画像圧縮
  • Bootstrap4をテンプレートとして使用
  • 標準で新着情報管理の仕組みをサポート
特に今回関わってくるのは最後の新着情報の管理方法。通常は
  • 個別記事ページ: 1つのMarkdownファイルから1つのhtmlファイルをnews/articles/下に生成
  • 新着情報一覧ページ: bin/config/config.ymlparam.news.newscountで指定した件数を1ページ当たりの件数として、news/下に生成
という形になっています。

3. 改修内容・連携の全体像

今回は上述の新着情報をWordPressに託し、Github Actionをキックすることで自動ビルド・デプロイを行う仕組みとしました。大まかな流れを以下に記します。
  1. WordPressで記事を公開・更新する
  2. アクションフックを使って、プラグインに設定されたパラメータをGithub ActionsのAPIに投げ付け、repository_dispatchイベントを起こす
  3. Github ActionsでUsusamaの.github/workflows/build_deploy.ymlに記述されたワークフローが実行される(ビルドとFTPによるデプロイ)
  4. 3.の結果、指定されたサーバにビルドされた静的サイトがアップロードされ、閲覧できる状態になる
肝はGithub Actionsのワークフローを外部からキックできるrepository_dispatchイベントです。 なお、簡略化のためWordPressに対して以下の条件を設けました。
  • 利用方法:
    • 新着情報はWordPressの「投稿」を利用
      • WordPress自体はどこかのサーバにインストールして、通常と同じように使用
      • 「投稿」の1記事を1つのhtmlファイルとする
      • 一覧ページは上述と同じ設定情報で生成
  • 条件:
    • 連携できるのは「投稿」のみ
    • 画像はCDNを利用してWPサーバ外に配置するものとする(記事内に埋め込まれている画像の取得が上手くできなかったため)
    • サイト内リンクは置換しない(記事URLを上手く置換できなかったため)
    • Github Actionsとの連携のため、自前プラグインを1つインストール

4. 実験手順

a. Ususama

Ususamaをローカルにクローンして、以下の2つの設定を行います。
  • WPサイトのWP REST APIのURL(例: https://wpsite.example.com/wp-json/wp/v2/posts)をbin/config/config.ymlに記述
  • bin/config/plugins.ymlのWordPress連携のフラグをtrueにする
なお、.github/workflows/build_deploy.ymlの内容は以下の通りです。
.github/workflows/build_deploy.yml
name: BuildandDeploy

on: [repository_dispatch]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [12.x]

    steps:
    - uses: actions/checkout@v1
    - name: Run builds and deploys with ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - name: npm install, build, and deploy
      run: |
        npm i -D
        npm run build
        npm run tankai ${{ SECRETS.ftp_user }} ${{ SECRETS.ftp_password }} ${{ SECRETS.ftp_host }} ${{ SECRETS.ftp_remoteroot }}
上述した通り、肝はrepository_dispatchイベントでワークフローが実行されるようにon: [repository_dispatch]を記述しておくこと。単発なのでon: repository_dispatchでも良かったかもしれません。 このコードをGithubの公開リポジトリにプッシュします。

b. Github

次にGithubの設定。まずリポジトリに対してGithub Actionsを有効にし、次にシークレットの設定。「Settings」→「Secrets」と進み、上述のワークフローで使用する4つのキーを設定します(該当サーバのFTP情報)。
シークレットの設定
シークレットの設定
次にPersonal access tokensの設定をします。
Personal access tokensの設定
Personal access tokensの設定

Githubログイン状態で、右上のアカウントアイコンからメニューを開き、「Settings」を選択。
Personal access tokensの設定
Personal access tokensの設定

左側のサイドバーから「Developer settings」を選択。
Personal access tokensの設定
Personal access tokensの設定

続いて「Personal access tokens」を選択。
Personal access tokensの設定
Personal access tokensの設定

新規でトークンを発行してみたいと思います。「Generate new token」を選択。
Personal access tokensの設定
Personal access tokensの設定

トークンの権限を設定します。今回必要なのはrepoの権限なので、そこにチェックを入れて、下の方のボタンで保存。
Personal access tokensの設定
Personal access tokensの設定

新しくトークンが発行されたので、これを控えておきます。 次はWordPressに移りたいと思います。

c. WordPress

今回は実験のため、デモのWordPressを建てて適当なコンテンツ(最近のWeb、IT関係のニュースまとめ)を流し込んでおきました。
デモでWordPressサイトを構築
デモでWordPressサイトを構築

デモのWordPressサイトのトップ画面はこのような感じ。Twenty Twentyです。
WPに自前プラグインをインストール
WPに自前プラグインをインストール

このWordPressに自作のプラグインをzipをアップロードする形でインストールし、有効化します。 名前は利用するのがUsusamaなので仏教関係で、火をイメージさせ、かつ一説に「飲み込む」の単語から名前が付けられたのではないかとも言われている迦楼羅から「迦楼羅焔」。
プラグインにGithubアカウント、リポジトリ名、アクセストークンを設定
プラグインにGithubアカウント、リポジトリ名、アクセストークンを設定

プラグインを有効化するとサイドバーにメニュー(「迦楼羅焔設定」)が表示されるので、そこを選択。設定画面で該当リポジトリの情報(アカウント、リポジトリ名)と先ほど設定したPersonal access tokensを入力し、保存します。 これでWordPress側の準備も完了です。

5. 実験

以上の設定や改修を終えて、WordPressで記事を更新します。すると、想定通りGithub Actionsのワークフローが実行されます。
Github Actions実行ログ
Github Actions実行ログ

少し時間はかかりますが、暫く待っていると?Complete jobで完了しました。
自動ビルドの後FTPデプロイされたWebサイト
自動ビルドの後FTPデプロイされたWebサイト
シークレットで指定したサーバを閲覧すると……無事、WordPressの投稿データを新着情報として静的サイトがデプロイされました!

6. まとめ

以上の改修・手順で、無事に「Github Actionsを使ってWordPressの記事を静的サイトにデプロイ」という目標は達成できました。

課題

課題として以下の点が挙げられます。主にWordPress周りですね。
  • Githubリポジトリのデータは、repository_dispatchイベントの場合はブランチ指定ができない
    • 開発用ブランチ(masterにGithubのワークフロー設定YAMLファイルがないリポジトリ)でワークフローを記述しても上手く動かなかった
  • Github Actions自体がまだベータ的な機能らしいので、本格的なプロダクトに使用するのはもう少し後の方が良いと思われる
  • WordPressに制約が多い
    • 「投稿」のデータしか使えない
      • 固定ページの場合、テンプレートをどうするか?
      • カスタム投稿タイプまで踏み込むと複雑になりそう……
    • 画像はCDNにあることを前提としている
      • サムネイル画像は良いが、投稿内に埋め込まれた画像の取得が上手く行かなかった(srcsetの縮小画像までダウンロードする?など)
    • サイト内リンクは非対応
      • パーマリンクを「投稿名」にして日本語で入力されると、静的htmlファイルも日本語にせざるを得ない……
      • 現状は投稿ID+日付という形で回避
        • このため、サイト内リンクのURLとの対応付けを逐一行う必要がある
        • カテゴリ別アーカイブなど、個別記事以外のURLの場合は?
      • などなど、色々考えなければならない

7. 備考

上ではWordPressのプラグイン(「迦楼羅焔」)をさらっと流してしまいましたが、やっていることは以下の通り。
  • 必要なGithubの情報を保存
  • publish_postdelete_postのアクションフックを利用して、記事を更新したり削除したタイミングでGithub Actionsのrepository_dispatchイベントをキック
中身としては「JSONデータをPOSTする」だけですが、file_get_contents関数で上手く行かなかったのでHTTPクライアントライブラリのGuzzleを使いました。 guzzleという英単語も「暴飲する、がつがつ食べる」といった意味のようなので、偶然ですが「食べる、飲み込む」関係のそれっぽい単語でまとまることになりました。 そもそもUsusama自体Gulpを使っていることから「飲む」イメージでネーミングしていますし。

8. 参考

Github Actions, CI

Github, Personal access tokens

PHP, Guzzle

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。