(WordPress) メディアファイルを投稿に挿入する際にタイトルや代替テキストを自動で補完するプラグイン 1 (結果的に採用)

経緯

とあるサイトで、画像ファイルを投稿に挿入する際に定型句を代替テキスト・タイトル・キャプション・説明に挿入したい、と考えました。

毎回手動で入力するのは色々と不都合(面倒だし運用上抜け漏れがありそう)なので、自動で補完できないかと考えました。

調べてみるとできそうなので、実装してみることにしました。

実装 (PoC)

要件としてまとめると以下。

  • WordPress でメディア(画像その他)アップロード時に、自動的に以下の4つをプリセットとして自動補完する。
    • 代替テキスト
    • キャプション
    • 説明
    • タイトル
  • アップロード後の変更は許容する (逆に WordPress の仕組み上制限を設けることは権限設定やメディアファイルページを潰す等の方法になってしまい難しいと思いますが)。
  • 記事投稿時とメディアライブラリ直のアップロードの両方に対応する。
  • 設定画面を設け、埋めるテキストを決め打ちではなく任意のものとして設定可能とする。

これを実現させるために、先述の記事を参考にプラグインを作成しました。

本当はクラスで実装したり、定型句を設定する画面を管理画面に追加したりする処理も含まれているので諸々異なりますが、定型句を代替テキスト・タイトル・キャプション・説明に挿入する部分だけをシンプルに記述すると以下のような実装になりました。

<?php

function Gakutensoku($response, $attachment) {
    // 埋め込むテキスト (決め打ち)
    $preset = '画像の説明です。';
    if (empty($response['alt'])) {
        // 代替テキストが空ならば $preset で埋める。
        $response['alt'] = $preset;
    }
    if (empty($response['caption'])) {
        // キャプションが空ならば $preset で埋める。
        $response['caption'] = $preset;
    }
    if (empty($response['description'])) {
        // 説明が空ならば $preset で埋める。
        $response['description'] = $preset;
    }
    // タイトルを $preset で上書きする。
    $response['title'] = $preset;

    return $response;
}
add_filter('wp_prepare_attachment_for_js', 'Gakutensoku', 10, 2);

タイトルは問答無用で書き換え、他の3つの代替テキスト・キャプション・説明は該当項目が空欄だった場合に挿入する、というようなコードです。

これをプラグインとしてインストールして挙動を観察したところ、自分の意図した挙動とは異なる挙動をしたので深堀りすることにしました。

深堀り

今回は「画像等のメディアファイルをアップロードしたタイミング」で、「代替テキスト・タイトル・キャプション・説明を書き換える」ということを目標にしていました。

ところが、管理画面のメディアのページで直接メディアファイルをアップロードしても、上述4つのテキストは自動補完されませんでした。

メディアファイルもファイル実体は /wp-content/uploads/ 配下に入りますが、メディアファイルに関するデータは普通にブロックエディタで書く記事と同様に wp_posts テーブルへレコードとして1行追加されるだろう、ということは過去の経験から想定していました。 post_typeattachement として、言ってしまえばカスタム投稿タイプのように通常の posts とは異なる投稿タイプの記事データとして保存される、と。

また、サムネイルや各端末向けにリサイズされた画像等の情報は wp_postmeta テーブルでカスタムフィールドのように保存されるだろうな、とも推測していました。

しかし、この部分をきちんと見たことがなかったので、まずはこの部分について改めて確認しました。

メディアファイル関係のデータベース上のデータ

  • メディアをアップロードすると wp_posts テーブルへ post_typeattachement として1行レコードが追加される。
  • 併せて、 wp_postmeta テーブルへファイルパスや各デバイス向けにリサイズされた幅・高さの値、今回のメインテーマであるタイトルや代替テキスト等のメディアファイルに関するメタ情報が WordPress のシリアライズされたテキストデータとして、1行レコードが追加される。
    • meta_key_wp_attachment_metadata
  • 編集画面、ブロックエディタからメディアを呼び出す際に先述のシリアライズされたデータを元に画像ブロックにデータが入力される。
  • ブロックになってしまえば、 HTML タグに alt 等の属性として今回のテキストデータは記述されるので、その後は気にしなくて良い。
    • 実際にユーザが記事を閲覧する際はこのタグに記述された情報が参照されるわけですし。
    • 記事データは wp_posts の該当記事の post_content 列に HTML タグがベタで入っている状態。

今回のプラグインの挙動の観察

上述のデータベースでのデータの保存のされ方を確認したところで、今回のプラグインの挙動を観察した結果が以下です。

  • 上述の通り、今回はフィルターフック wp_prepare_attachement_for_js を使ったやり方を試した。
  • しかし、メディアページで直接メディアファイルをアップロードしてもタイトルや代替テキストは自動入力されなかった。
  • ブロックエディタでも、ドラッグアンドドロップで直接アップロードした際にタイトルや代替テキストは自動入力されなかった。
    • 一方、一度アップロードされた画像を画像ブロックから選択する際に、一覧で表示された画像 (80件) 全てが指定したテキストで自動補完されていた (空欄だった場合、等の条件を満たしている場合)。
  • フック呼び出し時にテキストファイルにログとしてテキストを出力するようにしたところ、大量にログが書き込まれた。
    • ざっくりしたカウントでは、一覧で画像が呼び出された(80件)分 × 2 に近い値

この結果から、 wp_prepare_attachement_for_js のフィルターフックが発火するタイミングは「メディアのファイルアップロード時」ではなく「アップロードされたメディアがブロックエディタからメディア一覧で呼び出された時」なのではないか、と推測しました。

そのタイミングで発火した際に、 wp_postmeta のシリアライズされたデータをベースに、フィルターフックで今回のプラグインの処理を追加 (自動補完) した結果をメディア一覧で表示、という挙動に見受けられます。

実際、プラグインで処理されて自動補完を適用した画像をブロックに挿入しても、元の wp_postmeta のデータは書き変わっていませんでした。

そのため、あくまでメディアファイルがブロックエディタ内でメディア一覧として出力された画面上のデータだけ操作しているようです。

そうであれば実体としてのメディアファイルに関するデータは元のまま保持される形になるので、元データを汚さないという点ではクリーンだと思いました。


ただし、この挙動だとメディアファイルをアップロードした後、一度メディア一覧を開いて再度画像を選択し直さなければ適用されないことになります。

実際、標準のギャラリーブロックをあらかじめ作っておいて、そこに複数枚の画像をドラッグアンドロップで追加すると、自動補完はされませんでした。そのため、複数枚のメディアファイルだろうと、一枚一枚また選び直す手間が発生することになります。

……うーん、そうなると今回想定していた運用では手間が残るので、正直使いづらいと感じてしまいました。

そのため、このやり方とは別の方法を模索することにしました。……が、その方法が思いの外詰まってしまったので結局こちらの方法に戻して採用することにしました。

参考

コンセプト

フィルターフック

アクションフックとフィルターフック

入力値バリデーションのための正規表現 (PHP)

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。