Wordpress上のメディアをcloudinaryに自動アップロードして管理する

herokuでwordpressを使用した場合、通常ではアップロードした画像は
heorkuの再起動のタイミングで全て消えてしまいます。

なので、そうならないようにクラウド上のストレージサービスである、cloudinaryに保存させたりします。
cloudinaryには公式でwordpressのプラグインが用意されています。
WordPress › Cloudinary – Image management and manipulation in the cloud + CDN « WordPress Plugins

これを利用することでwordpress上の画像をcloudinaryで管理できるようになるのですが、
アップロードした画像を手動でcloudinaryに反映させてやらねばなりません。
それをなんとか自動でアップされるようにしてみました。

cloudinaryへのアップロード手順(通常)

通常と同じようにメディアライブラリ上から画像をアップロードします。
一覧表示で、詳細まで表示される、テーブル表示に切り替えます。
この時の右端に、Upload to Cloudinaryというリンクがあるのでそれをクリックします。

するとアップロードされ、表記がアップロード済に変わります。

この時に内部では何をしているかと言うと、
cloudinaryにアップロードし、アップ先のURLを使ってメタデータを書き換え、
cloudinaryへアップした、というフラグを立てています。
このフラグを立てているところがポイントになります。

メタデータ

wordpressでは画像は投稿データとして管理されています。
データ構造は以下が詳しいのですが、画像部分だけを引用させてもらうとこんな感じです。
WordPress データ登録機構を知ってもっと自由で効率的なフローを | hijiriworld Web

wp_postsテーブル

post_title post_status post_name guid post_type post_mine_type
{$file_name} inherit {$file_name} {$guid} attachment {$mine_type}

wp_postmetaテーブル

post_id meta_key meta_value
{$attachment_id} _wp_attached_file {$file_name}
{$attachment_id} _wp_attachment_metadata シリアライズされたメタデータ

wp_postsの方は特に変更する必要はありません。
重要なのはwp_postmetaのメタデータの方です。

今回、変更する具体的な箇所は以下の2箇所です。
_wp_attached_fileをファイル名からcloudinaryのURLへ変更。
_wp_attachment_metadataの中にcloudinaryフラグを立てる。

メディア管理とプラグインの仕組み

wordpressのメディアは都度URLを動的に生成しています。
メイン画像の場合は以下。

ブログのパス + _wp_attached_fileの$file_name

サムネイルの場合は以下。

ブログのパス + _wp_attachment_metadataの指定サイズのファイル名

なのでファイル名にcloudinaryの絶対パスを入れてしまうとURLが2重になってしまいます。

で。
これが、cloudinaryのフラグが立っているものに関しては、cloudinaryのプラグイン側でURLをうまい具合に置き換えて表示してくれます。
なので、こちらとしてはフラグを立てるだけ、で大丈夫。

実作業

処理の流れは以下のように。

  1. 画像をアップロード
  2. メタデータ作成のフック内で画像URLを取得
  3. 取得したURLでcloudinaryにアップロード
  4. cloudinaryのURLでDBのファイル名を更新
  5. メタデータにフラグを立てる

wp_generate_attachment_metadataで、アップされたファイルのメタデータを作成する処理にフックをかけられるのでそれを使用します。

functions.phpに以下を記述。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function cldnry_wp_generate_attachment_metadata($metadata, $postid){
    $imgPath = get_attached_file( $postid );

    //ファイル形式のチェック
    $info = pathinfo($imgPath);
    $public_id = $info["filename"];
    $mime_types = array("png"=>"image/png", "jpg"=>"image/jpeg", "pdf"=>"application/pdf", "gif"=>"image/gif", "bmp"=>"image/bmp");
    $extension = $info["extension"];
    $type = @$mime_types[$extension];
    //画像以外はcloudinaryにアップしない
    if($type === null){
        $stderr = fopen( 'php://stderr', 'w' );
        fwrite( $stderr, 'アップロードされたファイルが画像ではありません。file-type:'.$extension );
        return $metadata;
    }

    //Cloudinaryへアップ
    $cl_upload = new CloudinaryUploader();
    $uploaded = $cl_upload->upload($imgPath, array(
    ));
    $public_id = $uploaded['public_id'];

    //DBへ保存
    update_attached_file($postid, $uploaded['secure_url']);
    $metadata['cloudinary'] = true; //cloudinaryからアップしたことを記録

    return $metadata;
}
add_filter( "wp_generate_attachment_metadata" , "cldnry_wp_generate_attachment_metadata",10 ,2 );

※2015/08/21追記
cloudinaryへアップする際にpublic_idを指定してしまうと画像が次々と上書きされてしまうので、その部分を削除しました。

“public_id” => $public_id,

まず、get_attached_file( $postid )でアップされたファイルのURLを取得。
そのファイルが画像かどうかを一応チェックしている。
で、cloudinaryへアップロード。
cloudinaryはプラグインのファイルから利用するので公式で解説されているコードとは少し異なります。
で、アップされたらURLをファイル名として保存。
最後にポイントとなる、フラグを立てて終了。

これだけであとの表示周りの処理はcloudinaryがやってくれます。

結果

通常と同じように画像をアップすると、アップ完了時点でcloudinaryへ保存されます。
以下のようにURLがcloudinaryになっている事が確認できるかと思います。

一覧でテーブル表示にすると、cloudinaryにはすでにアップロード済の表記となっています。

まとめ

herokuでwordpressを扱う場合、この画像問題がネックの一つとなっているのですが、
herokuにはcloudinaryのアドオンがあるので、これでとりあえずは解消したのではないでしょうか。
この解消は自分の中ではかなり大きいです。

使用の際の注意点としては、wordpress上でデータを削除してもcloudinary上からは削除されない、という点です。
cloudinaryのアップロード容量が決まっているため、メンテナンスが必要かもしれません。

あとはアップデートの問題が解決すればすっきり出来るのですが。。

   このエントリーをはてなブックマークに追加