WordPressはそのお手軽さと拡張性の高さで、BlogやCMSとして重宝されていますが、単純に入力フォームとして見た場合も有用だったりします。WordPressを入力フォームとしてのみ利用し、FirebaseへPOST/連携させるという、少々ニッチな仕組みを作ったので、そのノウハウと手順を紹介します。
入力画面にWordPressを使う理由
WordPressの選定ポイント
長期的に運用していくサービスへの導入を検討していく上で、他のCMSと比較して、以下のポイントが決め手となりました。
- 汎用性:LAMP環境下ならほとんどのサーバで動作する汎用性の高さ
- 信頼性:運用実績が多数あり、信頼性が高い
- 拡張性:拡張性が高く、カスタマイズが容易、膨大なプラグイン資産が使える
- 情報量:コミュニティが活発で情報量が多く、エラーが発生した際や開発時に解決できる可能性が高い
Advanced Custom Field Pro(ACF Pro)
WordPressの入力画面としての優秀さを際立たせるのがカスタムフィールドを拡張するAdvanced Custom Field Proです。有料ですがDeveloperライセンスを買えば制限なく他の案件に使えます。
とくに優秀な機能として、Repeater Field(繰り返し入力フィールド)、Flexible Content(柔軟コンテンツ)は、他の入力システムと一線を画す優秀な機能です。このプラグインがあるからWordPressを使っているんだ!といっても過言ではありません。
セキュリティリスクについて
WordPressのウィークポイントとして、オープンソースで普及率が高いため、利用にはある程度のセキュリティリスクが伴います。しかし、あくまで入力フォームとして使う構成とし、WordPressをインストールしているサーバとフロントエンドを表示するサーバとを分ければ問題ないと判断しました。ベーシック認証で担当者以外のアクセスを弾く、WAFを導入するなどの対策をした上で運用することを推奨します。
構成
構成は図にするとこんな感じです。WordPressで作成したデータ(商品データや記事データなどの不変データ)を一方通行でFirebaseに受け渡すフローとなります。ユーザデータやフロントエンドで生成されたデータはFireabaseと双方向で連携させています。
役割 | ソフトウェア・サービス |
---|---|
記事入力画面 | WordPress / LAMP環境サーバ |
画像格納 | Firebase Storage |
データベース | Firebase Realtime Database |
フロントエンド | Firebase Hosting(htmlが表示できるサーバならなんでも) |
WordPress->Firebaseのためのコード作成
1.データ作成処理(WordPress)
WordPressのお作法に習い、themeフォルダー内またはwp-loadを使って記事のデータ生成を行います。今回はデータベースへの登録と同時に、記事内で登録された画像もStorageに登録させる必要があったので、Storageも対応しているkreait/firebase-phpライブラリの利用を前提とした実装になります。Composer経由でダウンロードするか、gitから直接ダウンロードして読み込ませます。
セットアップ
equire '/xxx/autoload.php';
require_once '/xxx/wp-load.php';
// firebase-phpのnamespace設定
use Kreait\Firebase;
use Kreait\Firebase\Factory;
use Kreait\Firebase\ServiceAccount;
/*
* Firebase Admin SDKのサービスアカウントを登録
* https://firebase.google.com/docs/admin/setup?hl=ja
*/
$serviceAccount = ServiceAccount::fromJsonFile(__DIR__.'/fireabase-admin-json/xxxxxxx-adminsdk-xxxxxxxxx.json');
ループ処理によるデータ生成
Databaseへ登録するデータの生成と同時にStorageアップロード用の画像を格納した配列を作成します。どちらの配列も連想配列にしているのは、重複データを弾くためです。
$partsQueryKey = array(
'post_status' => 'publish',
'order' => 'DESC',
'post_type' => 'xxxx',
'posts_per_page' => 999
);
$query = new WP_Query($partsQueryKey);
$databaseArray = []; // Firebase Databaseへ登録する連想配列
$storageArray = []; // Firebase Storageへ登録する画像データ用連想配列
$num = 0;
/*
* WordPressのループ処理でデータ作成
*/
while($query->have_posts()){
$query->the_post();
$id = get_the_ID();
// Database登録用データ
$databaseArray[$id]['id'] = $id;
$databaseArray[$id]['name'] = get_the_title();
$databaseArray[$id]['mainImage'] = get_field('mainImage')['filename'];
// Storage登録用データ
$storageArray[$brandsData[$id]['mainImage']] = array(
'modified' => get_field('mainImage')['modified'], // 画像更新日付を取得
'src' => get_field('mainImage')['url'] // 画像URLを取得
);
$num++;
}
2. データ加工・アップロード(Firebase)
データ生成が終わったら、データの加工処理(必要であれば)とfirebase-phpを使ったデータアップロード処理を行います。
DatabaseへはgetReference
を使うことで簡単にPOSTできますが、StorageはFlysystemというComposerライブラリで定義されている、Filesystem APIに則り操作する必要があります。ここではput
とlistContents
のみしか使っていませんので、より詳しく知りたい場合は以下のリンクから確認してください。
なにも工夫しないで実装した場合、投稿や同期時に、すべての画像がアップロードされてしまいますが、今回のコードではアップロードさせたい画像の連想配列にmodified(画像の更新日時)
を含めて、すでにFirebase StorageへPOSTしている画像のmodified
と比較して、差分配列を作成し、必要のない画像を投稿しないようにしています。
※このサンプルでは、Databaseはitem
配下に、Storageはimg
配下にPOSTされるように設定しています。
$firebase = (new Factory)
->withServiceAccount($serviceAccount)
->create(); // firebaseインスタンス作成
$database = $firebase->getDatabase();
$storage = $firebase->getStorage();
$filesystem = $storage->getFilesystem();
$firebaseImageList = $filesystem->listContents('img/'); //アップロードしたいfirebase storageのディレクトリ内画像一覧を取得
// アップロードする画像のみを抽出
foreach ($storageArray as $key => $value) {
$fimename = $key;
$timestamp = strtotime($value['modified']);
foreach ($firebaseImageList as $value) {
if($fimename == $value['basename'] && $timestamp <= $value['timestamp']) { // 差分抽出
unset($storageArray[$fimename]);
}
}
}
// Storageへの画像アップロード処理(差分処理)
foreach ($storageArray as $key => $value) {
if($key != null && $key != '') {
$filename = $key;
$src = file_get_contents($value['src'], false, stream_context_create($options));
$filesystem->put('img/' . $filename, $src);
}
}
// Databaseへのアップロード処理
$database->getReference('items')->set($itemsData);
最終コードはgistにアップしています。
https://gist.github.com/kgsi/e86123a9e5c6d841ad7c0e153d6358de
所感
あまり参考記事もなく、一風変わった構成となった気がしますが、WordPressを使い慣れている自分にとって、知識のない他のCMSを使うよりも実装がしやすく、お手軽感がありました。投稿毎にFirebaseへPOSTするのかどうか、全体の書き換えを行わないよう工夫をする必要があったりと、少々手間がかかる部分もありますが、WordPressのカスタム仕様を理解していれば実装は容易かと思います。
自分の場合は、投稿の度にイベントフックして投稿させるよりも、一括してデータを同期させる方法を選びました。以下のようなWidgetを登録し、簡単に同期できるようにしています。