(……きこえますか…きこえますか…WPerの…みなさん… 高橋文樹です… 今… あなたの…心に…直接… 呼びかけています…WordPressでファイルを取り込むときは…file_put_contentsを…使っている場合では…ありません…あなたが…使うべき…APIは…fwrite某でも…ありません…WP_FileSystemです…WP_FileSystemを…使うのです…WP_FileSystemを使うのです…)
というわけで、直接呼びかけてみましたが、ほとんどの方には関係ないネタです。テーマファイルやプラグインを配布しており、なおかつ追加ファイルのようなものを自由に配置できたらなーと考えている方にのみ関係のあるお話です。
WordPressではテーマやプラグインの公式リポジトリがあり、ある程度の要件を満たせばそこで配布することができます。で、そこまではなんの問題もないのですが、ビジネスを展開している場合、テーマやプラグインを無料で配布し続けるだけではなく、なんらかの収益ポイントを設ける必要があります。
この課題に対する回答の一つとしては、AkismetやJetpackのようにAPIキーの入力やOAuthによるアカウント接続を求めるというものです。プラグインやテーマのインストール自体は行えるけれども、APIキーを入力しないとフル機能使えないよというパターンですね。この場合、キーとユーザーの紐付けは自前のサーバなりなんなりで行う必要があります。
で、それとは別に、テーマファイル販売の場合がわかりやすいのですが、公式リポジトリとは別に購入したユーザーだけに自分で配布したい場合というのがあります。もちろん、公式リポジトリ+API方式でがんばればできますし、アップデートも「新バージョンはSFTPでアップロードしてね☆」で済むと言えば済むのですが、管理画面からポチッと自動アップデートできたら素敵やんというわけで、WP_FileSystemを紹介します。
WP_FileSystemとは?
WordPressはPHPのアプリケーションなので、パーミッションさえ許せばお好きなファイルを配置することができます。ただし、このパーミッションさえ許せばというのがミソで、サーバがセーフモードだったりしてファイルを書き込むことができないという場合があります。
だいたいのユーザーは1枚ぐらい画像をアップロードするはずなので、/wp-content/uploadsフォルダぐらいは書き込み可能にしていると思いますが、wp-contentフォルダやwp-content/themes、wp-content/pluginsフォルダはPHPから書き込みができなかったりします。
もちろんWordPressはそこらへんへの配慮もあり、プラグインやテーマをインストールする場合はこんな感じにFTP情報の入力を求める画面があったりします。
前置きが大変長くなりましたが、ようするにこの「ユーザーのサーバ環境がなんであれ精一杯ファイル書き込みのための努力をする」というのがWP_FileSystemです。
PHPにできるファイル操作の方法は、PHPによる直接操作のほか、FTP拡張やSSH拡張など色々あります。もちろん、「サーバにその機能がインストールされているか」という条件の他、「秘密鍵持ってる奴しかアップロードしちゃ駄目」など、セキュリティ上の理由で厳しくしたりすることもあるわけで、ここら辺の設定はwp-config.phpの設定次第で幾つか変えることができます。
WP_FileSystemというのは、そうした大人の事情を鑑みつつファイルを操作できる素敵な機能なわけです。
WP_FileSystemの使い方
さて、今回はわかりやすくするために、「自分で配布しているテーマのアップデート」を行うとしましょう。基本的にはwp-content/themes/my-themeというフォルダをどこかからダウンロードしてきたzipファイルを解凍してそれを既存のテーマフォルダと入れ替えるという手順です。ちょうどLiterally WordPressにXML-RPCのエンドポイントを設けたので、それと連携します。細かく書くとこんな感じです。
- 管理画面に管理者が入ったら、テーマの最新情報を取得する
- 新しいテーマがあったら更新メッセージを出し、更新用画面を表示できるようにする
- 更新画面で管理者が「アップデート」ボタンを押したら更新処理開始
- まずは必要なファイル(zip)をダウンロードする。この時点ではPHPでのダウンロードなので、PHPが自由にファイルを書き込めるディレクトリ(tmpとか)に一時ファイルとして保存する
- 続いて、zipファイルをwpcontent/upgradeフォルダに移動して展開する
- 材料は揃ったので、メンテナンスモードに移行しつつ既存のテーマを削除し、展開した新しいテーマフォルダをwp-content/themesフォルダに移動する
- メンテナンスモードを解除する
この場合、ファイルの書き込み権限が保証されているかどうかわからないのはステップ5の「wp-content/updgradeフォルダへの移動」です。ここでWP_FileSystemの出番です。
WP_FileSystemとは、WordPressがサポートしてるファイル書き込み形式(FTP拡張とかSSH拡張とか)のラッパークラスで、どの方式を使おうが、共通のメソッドでファイルの移動/削除/コピー/書き込みができるものです。
ただし一口にラッパークラスといっても、サーバ設定によっては認証情報(FTPのユーザー名・パスワード)が必要だったり、逆にwp-config.phpの設定によって選択できるファイル操作手法が制限されていたり(ex. サーバ要件としてはすべての機能を持っていても、秘密鍵によるSFTP以外はセキュリティ上許可しない)するので、PHPによる書き込みが許可されている場合(さくらとかロリポップとかのCGIでPHPを動かしているのは基本OKなんですが)を除き、入力フォームを挟むようにします。
で、なんとこの入力フォームをまるごと出力する関数が用意されています。
request_filesystem_credentials($action, '', false, false, '')
$actionにはフォームの送信先URL(aciton属性)を入力します。細かい引数についてはすみませんがソースを見てください。なお、この関数は元々管理画面で1つの画面を作成するためのものらしく、カスタマイズの余地がまったくありません。要素を追加したい場合はob_start 〜 ob_get_contents 〜 ob_end_cleanなどでがんばるしかないようです。
で、このフォームを受け取った先で、$_POSTをこの関数に突っ込みます。
WP_Filesystem($_REQUEST);
この関数は$wp_filesystemオブジェクトを初期化するもので、認証情報が間違っていた場合はfalseを返します。エラー処理は適宜行っていただくこととして、この関数がtrueだった場合はグローバル変数の$wp_filesystemが有効になります。
あとは何も気にせず好きなようにファイルをうごかせます。メソッドは色々あります。各メソッドについては、/wp-admin/includes/class-wp-filesystem-*.phpを見てください。
if(WP_Filesystem($_REQUEST)){ //この時点でファイルシステムが有効に global $wp_filesystem; //WordPressをメンテナンスモードに移行 //これ以降画面遷移するとメンテナンスモードに入るので注意 $maintenance_string = '<?php $upgrading = ' . time() . '; ?>'; $maintenance_file = $wp_filesystem->abspath() . '.maintenance'; $wp_filesystem->put_contents($maintenance_file, $maintenance_string, FS_CHMOD_FILE); //古いテーマディレクトリを消す $wp_filesystem->delete($theme_dir, true); //新しいテーマディレクトリを移動する $wp_filesystem->move($new_dir, $theme_dir, true); //メンテナンスモード解除 $wp_filesystem->delete($maintenance_file); }
というわけで、必要としている人はほとんどいないと思いますが、日本語情報が皆無だったので、書いてみました。参考になれば幸いです。
※元ネタ
(……きこえますか…きこえますか…視聴者の…みなさん… TBSです… 今… あなたの…心に…直接… 呼びかけています…年末は…某歌合戦を…見る場合では…ありません…あなたが…見る…番組は…笑ってはいけない某でも…ありません…TBSです…TBSを…見るのです…TBSを見るのです…)
— TBS (@tbs_pr) November 26, 2012