今回の施策の発端(プラグインのXO Featured Imageが機能しなくなった)
現在、WordPressの運用にはコンソールからWordPressを制御できるwp-cliを利用している。そしてこれまではwp-cliで記事内で画像URLを定義していれば"XO Featured Image"がサムネイルを自動生成してくれたのだが、記事数が1万件を超えたあたりから画像ファイル名の処理が正常に機能しなくなって誤ったファイル名をサムネイルに抽出するようになってしまった。
※ 本稿の例は投稿データ(post)を対象としている。固定ページ(page)で同じ処理を実現したい場合は、post_typeをpageとすれば実現できる
- wp-cliで記事を投稿するサンプル
wp post create --post_type=post --post_title=【タイトル文字列】 --post_content=【投稿記事(※画像URLを含める)】 --post_category=【カテゴリの指定】 --tags_input=【タグの指定】 --path=【WordPressのインストールディレクトリ】 --user=【投稿ユーザー名】 --porcelain --post_status=publish
具体的な対策を検討
- 【1案】 XO Featured Imageの不具合を調査して解決する(却下)
- 【2案】 他のプラグインを使う(却下)
- 【3案】 WordPressテーマのCocoonのサムネイル自動生成を使う(wp-cliの投稿ではCocoonの機能は動作せず)
- 【4案】 自前で実装(手間は掛かるが最も確実に解決できる)
【1案】は「XO Featured Image」が正常に機能するように復旧できれば手軽なのだが、導入時に調査したときにもタグの位置によってプラグインが機能したりしなかったり、不明瞭な挙動が発生したので時間を割くのはリスクが高い、却下。
【2案】も自前の開発は不要なので手軽だが、「XO Featured Image」以外のサムネイル処理用のプラグインは殆ど全て有料版のアップグレードを要求する。そして有料で契約しても1案と同様の不具合が発生する恐れがあるので却下。
【3案】は「Cocoon」というWordPressテーマに標準で備わっている機能に「アイキャッチ自動設定を有効にする」というオプションがあり、有効にすると記事中に掲載された画像からサムネイルを自動生成してくれる。これが使えないか期待したのだが同機能は手作業で記事を登録するUIをクリックした場合のみ機能するようで、WP-cliのようにAPI経由で記事を登録した場合はサムネイルは自動登録されなかった。
【4案】はできれば避けたかったのだが、WordPressの機能としてphpで実装するとアップデートや脆弱性対策の度に見直しが必要になるので、wp-cliで実現することにした。
結論としては4案でサムネイル登録を実現することができた。
しかし、ネットで検索しても該当する情報が乏しくて、wp-cliのリファレンス通りに設定してもオプションの組み合わせによって動かない場合もあるので、備忘録としてブログに残すことにした。(※具体的な手順は後述)
wp-cliを利用する前提条件として、記事名と投稿内容はサニタイジングを事前処理してcliでクオート等を正しく囲っているか確認して、画像URLの情報も明確にしておくことも重要。
WordPressでプラグインを使わずにサムネイルを投稿する手順
手順1: 下書き(draft)で記事を投稿する
記事投稿後にサムネイルを設定する必要があるため、post_statusをdraft設定とする。
この後ですぐにサムネイル設定するので、publishで公開した
wp post create --post_type=post --post_title=【記事タイトル】 --post_content=【投稿記事(※画像URLを含める)】 --post_category=【カテゴリの指定】 --tags_input=【タグの指定】 --path=【WordPressのインストールディレクトリ】 --user=【投稿ユーザー名】 --porcelain --post_status=draft
このとき、記事タイトルや記事本文の文字列はサニタイズとエスケープをして投稿エラーにならないように前準備しておく。
"wp post create"のコマンドでpost_idを取得する方法
"wp post create"の実行時にpost_idを取得したい場合は、標準出力から情報を得ることができる。
Success: Created post 【post_id】.
正常に取得できれば手順2でPOST_IDを取得する手間が省けるのだが、正常処理のメッセージがこれだけなのか不明瞭であり、結果をjsonで取得するオプションも指定できなかったので、エラー処理も考慮して後述の処理(手順2)でpost_idを取得することにした。
手順2: 投稿した記事のPOST_IDを取得する
「手順1」で設定した記事データを抽出するためには、SQLでwhere句を使えば確実なのだが、wp-cliでは「wp db query」というサブコマンドでSQLを呼び出すことでwhere句を指定できる。
しかし、SQLのエラー処理や0件だった時の処理が手間になるので、今回は投稿した記事を「wp post list」というサブコマンドで、「--orderby=desc」オプションを指定することでPOST_IDの降順からデータを出力してjsonフォーマットで取得した。
wp post list --posts_per_page=50 --post_status=draft --post_typ1 --post --orderby=desc --fields=ID,post_title --path=【WordPressのインストールディレクトリ】 --format=json
※ オプションのposts_per_pageについて
posts_per_pageはlimit句の代わりに抽出上限を制限するもので50件を取得している。WordPressの処理が1件だけで確定していれば"posts_per_page=1"でよいのだが、バッチ処理等で別の更新処理が発生しているとorder順が変わるので50件から抽出している。
上のコマンドで取得したjsonデータ処理
- jsonの定義(参考)
{ { "ID": int, "post_title": string }[] }
手順3: 投稿した記事タイトルとjsonのpost_titleが合致するデータを検索
手順2で出力したjsonデータの中から記事タイトルが合致するID(=post_id)を抽出する。
-
bashやzshで処理する場合
標準出力をjq等につっこんで、配列で格納されているIDとpost_titleを抽出する。 -
pythonやphp等のプログラムで処理する場合
辞書型≒連想配列やjson型定義で標準出力を読み込んで、forループで展開すると辞書型keyを"ID"と"post_title"として値を取り出せる。
手順4: wp-cliからpost_idの記事へサムネイル画像を登録する
wp media import 【WordPressへ登録する画像URL or ディレクトリ】 --path=【WordPressのインストールディレクトリ】 --post_id=【取得したPOST_ID】 --title=【記事タイトル】 --featured_image
手順5: 対象の記事を公開(publish)にする
wp-cliの"wp post update"を指定することで、draftの記事をpublish(公開)することができる。
wp post update 【取得したPOST_ID】 --post_status=publish --path=【WordPressのインストールディレクトリ】
以上でwp-cliだけでdraftで記事を投稿、その記事にサムネイルを設定して、公開設定するまでの流れを処理することができようになります。
wp-cliはWordPressの構築から運用まで幅広く便利なのですが、具体的な事例になる資料が少ないので参考になれば幸いです。
参考記事
- Useful WP-CLI commands and scripts
- Managing WordPress posts using WP-CLI
- wordpress.org公式 wp-cli コマンドリファレンス