GitHub で Merge すると WordPress に自動デプロイする設定をした

TL;DR (概要)

GitHub の Webhook を用いて、PullRequest が merge されたときに、WordPress の テーマを自動更新する設定です。

この設定をすることで、デザイナーが WordPressテーマを修正した際の、本番への反映の手間を大幅に削減でき、LPO等のサイトの改善がぐんぐん進むようになります。 ​

背景

​ 広報や採用担当でWebサイトを更新しやすくするために WordPress で、サイトを構築することがあります。この場合、サイトのデザインは、WordPress の テーマ を自作することで行います。 ​ スタメンでは、テーマは、社内のWebデザイナーが作り Github で管理していますが、WordPress への 反映は、WordPress のファイル管理のプラグインである File Managerを用いいて、更新したファイルを手動でアップデートしていました。 この方法は、手間もかかるし、ミスも起きやすく、スマートではありません。 ​​ WordPressGithub との連携は、WP Pusher のようなサービスで実現できますが、テーマを Github の Private repository で管理していることもあり、それなりに費用がかかることもあり、Github Webhook を用いて自作してみることにしました。 ​

Github で PulLRequest が Merge されたときに、WordPress に反映する手順

Git pull するための設定

​ まず、WordPress が稼働しているサーバーにて、Github リポジトリから git pull して、WordPress テーマを取得できるようにする必要があります。 ​ Wordpress が稼働するサーバーにて、 OpenSSH の 鍵をつくります。 ​

$ ssh-keygen -t rsa -f id_rsa_wordpress 

生成された公開鍵を Github の Deploy Keys に設定します。

​ ​ 次に、httpd サーバー の実行権限で、git pull できるようにします。 ​ これは、Github Webhook で WordPress が動作する PHP関数を呼び出しますが、WordPress は、apache ユーザーで動作しているため、apache ユーザーで git pull できないと テーマを更新することができないからです。 ​ 今回は、以下の内容の /home/apache/bin/git-ssh.sh をつくり、git pull 時に GIT_SSH 環境変数にて指定するようにしています。 ​

#!/bin/sh
ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -i /home/<user_name>/.ssh/id_rsa "$@"

​ git-ssh.sh では、下記の傾向メッセージが表示されて、git pull が失敗しないように、StrictHostKeyChecking を off にするなどのオプションをつけています。

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

​ ​ 以下のように、wordpress theme が存在する git repository で、git pull できれば準備は完了です。 ​

$ sudo -u apache GIT_SSH=/home/apache/bin/git-ssh.sh git pull origin master
From github.com:<theme repository>
 * branch              master     -> FETCH_HEAD
Already up-to-date.

WordPress に action を追加

​ ​ WordPress の wp_ajax_nopriv を利用することで、Github hook から任意のPHP関数を実行することができます。 ​ wp_ajax_nopriv{$REQUEST[‘action’]} | Hook | WordPress Developer Resources ​ 今回は、下記の関数を theme ディレクトリの functions.php に追加することで、https://your-wordpress-site/wp-admin/admin-ajax.php?action=wp_ajax_nopriv_update_theme にアクセスすれば、git pull されるようにします。 ​ ​

/**
 * Add deploy hook endpoint
 */
add_action('wp_ajax_nopriv_update_theme', 'update_theme_from_github');
function update_theme_from_github() {
  $secret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
  $posted = file_get_contents('php://input');
  if (empty($posted)) {
    return;
  }

  $signature = 'sha1='.hash_hmac('sha1', $posted, $secret);
  if ($_SERVER['HTTP_X_HUB_SIGNATURE'] !== $signature) {
    header('HTTP/1.1 403 Forbidden');
    error_log('Signatures didn\'t match... ');
    return;
  }

  $json = json_decode($posted);
  error_log(__FUNCTION__.": \n".var_export($json, true));
  if ($json->ref === 'refs/heads/master') {
    $git_root = dirname(__FILE__);
    exec("cd ${git_root} &amp;&amp; GIT_SSH=/home/apache/bin/git-ssh.sh git pull origin master 2>&amp;1", $out);

    error_log(join("\n", $out));
    echo join("\n", $out);
  } else {
    error_log(__FUNCTION__.": nothing for ".$json->ref);
  }
}

​ このとき、GitHub の Webhook の Secret 機能 を利用することで、GitHub の Webhook からのアクセス時のみ git pull するようにしています。 デバッグしやすいにように、 ​error_log で、webhook の payload を出力していますが、不要だったら消してください。

GitHub に Webhook を追加

​ あとは、テーマのリポジトリにて、Webhook を設定すれば、完成です。 ​

​ ​

まとめ

​ これまで、更新の際は、ファイルを一つ一つアップロードしていたのが、GitHub WebHook によって、git pull することで、PullRequest を Merge することで、WordPress に反映されるようになりました。 ​ これによって、WordPress の更新の手間が大幅に減ったため、LPO などの細かい改善がより進むようになりました。また、GitHub Flow で WordPress テーマを更新するフローが確立したことで、個々の修正に対して、チームレビューが定着し、ノウハウの共有やミスの低減を達成することができました。 ​ ほんと、嬉しいことだらけです! ​ ただし、httpd が動作する権限で、git pull をするため、レンタルサーバーなどの社外含めた複数のアカウントが共存する環境では、セキュリティと Webhook による git pull は、共存できないかもしれません。その場合は、WP Pusher などのプラグインを入れましょう。 ​ ​

参考にしたサイト

WordPress テーマを Git 管理して自動デプロイする - Qiita GitHubのWebhookをPHPで受け取る練習 - tanaka's Programming Memo GitHubのWebhookをPHPで自作する時に書く検証コード - Qiita WordPress Git deployments with WP Pusher