WordPressのメディアライブラリ

WordPressにはメディアライブラリという画像や動画などのメディアファイルを管理する機能があります。WordPressのバージョンが上がる度に益々使いやすくなっており、画像のトリミングや縮尺変更などWordPress内である程度の加工もできるようになりました。
このメディアライブラリに保存されている画像を投稿などで挿入する時、「メディアを追加」というボタンが準備されています。この機能をプラグインで使いたいなと思って調べてみたら、昔?のやり方(リロードが走るタイプ)と今(WordPress4.7.2)のメディアライブラリのやり方(Ajaxで動作するタイプ)があるみたいなので、それぞれまとめてみようと思います。今回はリロードウインドウ編。

実装したい機能

実装したい機能は以下の3つ。

  1. テキストボックスの近くにボタンを設置
  2. ボタンクリックでメディアアップローダーのウインドウをポップアップ
  3. 画像を選択してテキストボックスに画像のURLを取得。その画像を表示。

という機能を実装したい。これを実現する方法を書いていきます。

使用するJavaScriptやCSSの読み込み

JavaScript:media-upload/thickbox

まず必要なライブラリを読み込みます。WordPressでは既にwp_register_script()関数で$handle登録されているものがあるので、それをwp_enqueue_script()関数でキューに入れます。
プラグインに組み込む予定なので、サンプルもプラグインの形式で作ります。

class Media_Uploader_Load {
	public function __construct () {
		add_action( 'admin_menu', array( $this, 'admin_menu' ) );
	}

	public function admin_menu () {
		$page = add_menu_page(
			'Uploader Load Sample',
			'Uploader Load Sample',
			'manage_options',
			plugin_basename( __FILE__ ),
			array( $this, 'page_render' )
		);

		add_action( 'admin_print_scripts-' . $page, array( $this, 'admin_scripts') );
	}

	public function admin_scripts () {
		wp_enqueue_script( 'media-upload' );
		wp_enqueue_script( 'thickbox' );
	}

	public function page_render () {

	}
}

とりあえず基本型。管理メニューに「Uploader Load Sample」という名前のメニューを追加して、そのメニューで表示された画面内で使用するJavaScript、media-uploadthickboxをキューに入れました。

CSS:thickbox

thickboxライブラリで使用するCSSファイルも読み込みます。JavaScriptと同様に登録済みのCSSですので、画面表示のタイミングでキューに入れます。

public function admin_menu () {
	// 省略

	add_action( 'admin_print_styles-'  . $page, array( $this, 'add_style' ) );
	add_action( 'admin_print_scripts-' . $page, array( $this, 'admin_scripts') );
}

public function add_style () {
	wp_enqueue_style( 'thickbox' );
}

これでCSSもOK。wp_enqueue_style()関数の仕様はCodexを参照してください。

オリジナルのJavaScriptを読み込み

ライブラリ関係は読み込む準備ができたので、そのライブラリを操作する用のJavaScriptも準備しておきます。作成したadmin_script関数内に読み込みたいJavaScriptを以下のように追記します。(2行目)

public function admin_scripts () {
	wp_enqueue_script( 'media-uploader-main-js', plugins_url( 'js/media-uploader-main.js', __FILE__ ), array( 'jquery' ) );
	wp_enqueue_script( 'media-upload' );
	wp_enqueue_script( 'thickbox' );
}

プラグインのjsフォルダ内にmedia-uploader-main.jsというファイルを作成します。このJavaScriptファイルの中に実装したい内容を記述していきます。jQueryを使用するので、jQuery依存関係の設定も忘れずに。

HTMLの準備

テスト用のHTMLの準備をします。イメージは以下のような感じ。

メディアアップロード画面完成イメージ

要素は3つ。img要素・input[type=”text”]要素・button要素でそれぞれJavaScriptから操作するので、それぞれid属性を設定。これらの要素を出力する関数を作ります。管理メニューを追加した時に設定したコールバック関数page_renderに以下のようなコードを書きました。

public function page_render () {
	echo '<div class="wrap">';
	echo '<h1>Media Uploader ( Load Type )</h1>';
	echo '<p><img id="image-view" src="' . plugins_url( 'images/no-image.gif', __FILE__ ) . '" width="260"></p>';
	echo '<p><input id="image-url" type="text" class="large-text"></p>';
	echo '<button id="media-upload">Choose Image</button>';
	echo '</div>';
}

media-uploader-main.js

ウインドウ表示

ボタンをクリックしたときにメディアウインドウを表示します。jQueryでボタンのid属性にクリックイベントを紐付け。

(function($) {
	$(function() {
		$("#media-upload").on("click", function(e) {
			e.preventDefault();
			tb_show(null, "media-upload.php?post_id=0&type=image&TB_iframe=true");
		})
	});
})(jQuery);

たったこれだけでウインドウが表示されます。ポイントは4行目のtb_show()でthickbox.jsの中に定義されている関数です。第二引数に、wp-admin直下に存在するmedia-upload.phpファイルを指定してパラメータをセットして動作させているだけです。
「コンピューターから」「URLから」「メディアライブラリ」の3つのタブがあるウインドウが開きます。

コンピューターから
コンピューターから
URLから
URLから
メディアライブラリ
メディアライブラリ

管理メニューのメディアでできるようにその場で画像の新規追加などができます。「メディアライブラリ」の画像を表示して「投稿に挿入」ボタンをクリックして値を返します。

ウインドウから値を返す処理

「投稿に挿入」ボタンが押された時にその値を受取る処理が必要です。先程のJavaScriptに、media-upload.js内に定義されているsend_to_editorがトリガーになるので、その中で受取る処理を追記します。

window.send_to_editor = function(html) {
	var imgUrl = $("img", html).attr("src");

	if (imgUrl === undefined) {
		imgUrl = $(html).attr("src");
	}

	$("#image-url").val(imgUrl);
	$("#image-view").attr("src", imgUrl);
};

htmlに選択した画像がimg要素に整形された状態で文字列でそのまま返ってきます。

<img src="http://vccw.dev/wp-content/uploads/2017/02/kinoko-300x199.jpg" alt="" width="300" height="199" class="alignnone size-medium wp-image-2259" />

これをjQueryでオブジェクトにして、src属性の値をimgUrl変数に取得しているのが5行目の処理です。自分もひっかかったのですが、実はこれだけではダメで画像に「リンクURL」がセットされている場合、img要素をa要素でラップした文字列が返ってきます。

リンクURLをセットした場合
<a href="http://vccw.dev/wp-content/uploads/2017/02/kinoko.jpg"><img src="http://vccw.dev/wp-content/uploads/2017/02/kinoko-300x199.jpg" alt="" width="300" height="199" class="alignnone size-medium wp-image-2259" /></a>

これをjQueryでまるごとオブジェクトにすることはできないので、2行目のように文字列からimg要素を抜き出してオブジェクトにしてから、src属性の値を取得しています。もしimg要素だけなら、2行目の処理は失敗してundefinedが返ってくるので、あらためてhtmlをまるごとオブジェクトにしています。これでほしい情報を取得できるので、それぞれ画像やテキストボックスの値にセットしてあげます。

ウインドウを閉じる

最後に開いているウインドウを閉じる処理を書きます。tb_remove()という関数が準備されているのでその関数をコールするだけでOKです。

window.send_to_editor = function(html) {
	var imgUrl = $("img", html).attr("src");

	if (imgUrl === undefined) {
		imgUrl = $(html).attr("src");
	}

	$("#image-url").val(imgUrl);
	$("#image-view").attr("src", imgUrl);
	tb_remove();
};

できた!\(^o^)/

メディアライブラリから取得結果

これで完成です。ウインドウのタブをクリックする度にロードがかかるので、サクサク感がない。ということで次回はAjaxウインドウ版でサクサク動作させるぞ編です。

サンプルソース(GitHub)

以下のURLにサンプルソースのリポジトリがあります。
プラグイン形式で作成しているので、WordPressの環境の wp-content/plugins にディレクトリを作ってクローンすれば動きます。(プラグインを有効にしてください)

GitHub