先日リリースした tam-attachment という WordPress プラグインを作る過程で、WordPress がアップロードされたファイルをどう管理しているかということについていろいろと調べました。その説明をしてなかったので、あのプラグインが何をするものなのか良くわからん、という人も多かったんじゃないかと思いますが、今日は僕が調べたことのまとめを書いてみたいと思います。
話はここからはじまります。

見慣れた WordPress の標準のファイルアップローダですが、ここで2つの疑問が生じました。
- アップロードの際にタイトルと説明を一緒に入力できるけれど、そのテキストはどこに保存されるのか
- Browse と Browse All に区別されているけど、これは何が違っていて、どこを見て区別しているのか
このページの HTML ソースを見てみたところ、このファイルアップローダの部分だけは別のファイルを iframe で埋め込んで表示していることがわかりました。inline-uploading.php という wp-admin フォルダにあるファイルです。そのコードを見ていると仕組みがわかってきました。
まず、タイトルや説明は DB の posts テーブルに独立したレコードとして保存されていました。posts テーブルに格納されるのは Post や Page だけだと僕はその時まで認識していたので、アップロードファイルのための特別なレコードがあることを知って驚きました。
アップロードファイルにつけたタイトルは post_title カラムに、説明は post_content カラムに保存されます。ちょうど Post や Page のタイトルと本文と同じです。
アップロードファイルのレコードと、Post と Page を分ける違いは、基本的には posts テーブルの post_status カラムの内容だけです。このカラムの値が publish, draft, private のいずれか場合は Post になり、static の場合は Page に、そしてこの値が attachment の場合はアップロードファイルになります。
そこで、以後はアップロードファイルのレコードやそれで表されるモノのことをアタッチメントと呼ぶことにしました。
2つ目の疑問、Browse と Browse All の区別はこの posts レコード間の親子関係に基づいていました。posts テーブルの post_parent カラムにはそのレコードの親に相当する posts レコードの ID が保存されていて、Page の親子関係を表現するのにも使われています。Post や Page とアタッチメントの間にも同様の親子関係があり、アタッチメントの post_parent カラムには、そのアタッチメントのファイルをアップロードした Post または Page の ID が保存されています。
ID post_content post_title post_status post_parent -------------------------------------------------------------------------- 1 これはテストです。 ポストのテスト publish 0 2 海の写真です。 海 attachment 1 3 山の写真です。 山 attachment 1
Post や Page から見れば、その編集画面からアップロードしたファイルのアタッチメントはすべて自分の子供になるということです。自分の子供は Browse にリストアップして、Browse All にはそれ以外を表示するというわけです。
ついでにいえば post_parent カラムの値を書き換えれば親子関係の付け替えが可能になるはずで、tam-attachment ではそういうこともできるようにしています。
さて、ここで新たな疑問が湧いてきました。アタッチメントが posts テーブルのレコードだとわかりましたが、アタッチメントとファイルは別物です。アタッチメント自体にはファイルのデータもファイルシステム上のパスも含まれていません。アタッチメントとファイルの間にはまだ何かあるようです。
inline-uploading.php やその周辺を調べてわかったのは、アタッチメントに紐付けられた postmeta テーブル上のレコードの存在でした。
- _wp_attached_file
- _wp_attachment_metadata
この2つのキーを持つメタデータの中で、ファイルパスなどの情報が保存されていました。
まとめるとこんな感じになっています。
_wp_attached_file の値には文字列が1つだけ含まれていて、ファイルのフルパスが保存されています。
_wp_attachment_metadata の値は配列になっていて、以下のキーを持つ値を含んでいます。
- width
- height
- hwstring_small
- file
- thumb
width, height はイメージの横幅と縦の長さです。
hwstring_small には <img> タグの height= 属性と width= 属性の指定部分の文字列が収められていて、縮小表示する場合に使うためのもののようですが、現バージョン(v2.0.3)ではこのデータは使われていないようです。
file はファイルのフルパスで、_wp_attached_file の値と内容は同じものです。_wp_attached_file の値がよく使われるのでこのデータも今は使われていないようです。
thumb にはサムネイルのファイル名が含まれています。フルパスではなくファイル名だけです。サムネイルのフルパスを得るためには、_wp_attached_file に含まれた元ファイルのフルパスと、サムネイルのファイル名を掛け合わせる処理をしています。サムネイルファイルは元ファイルと同じディレクトリに存在することが前提になっているようです。
ちなみに、ファイルの URL はアタッチメントの posts レコードの guid カラムに記録されています。サムネイルファイルの URL はファイルパスの時と同様に、この guid と _wp_attachment_metadata のファイル名が掛け合わされます。
なお、_wp_attachment_metadata のデータはいずれも対象のファイルが画像ファイルの場合のみ意味を持つので、ファイルが画像以外の場合は _wp_attachment_metadata には空の配列が収められます。
このような具合で、Post » アタッチメント » メタデータ » ファイル、という連環が形成されて、WordPress のアップロードファイル管理は成り立っているというわけです。
tam-attachment は標準のファイル管理のやり方を踏襲しているといっているのは、この一連の仕組みにはいっさい手を入れずに機能を実現しているという意味です。
tam-attachment が編集しているのはつまりここでいうアタッチメントやメタデータなわけですよ。

