WordPress TinyMCE ビジュアルエディタカスタマイズの例

#### **2015.07.26 投稿**
やることが多いのでコードベースで淡々とその方法を書きます。今回の要件は以下を想定

* TinyMCE ビジュアルエディタに「テキストボックスを吐き出す」ボタンを追加
* ボタンを押すとダイアログが開く
* ダイアログはこんな感じ

![スクリーンショット 2015-07-26 1.40.40.png](https://qiita-image-store.s3.amazonaws.com/0/9988/47009199-8ad2-8889-f504-f783ea3baf65.png)


## バージョン

* WordPress 4.2.3 


## functions.php の編集

TinyMCE にオリジナルのボタンを追加するにあたっては、(WordPressではなく)TinyMCE のプラグインを作成する必要があるようです。ちなみにプラグインは js で作ります。

プラグインを WordPress に対応させるにあたってまずは、add_filter 'mce_buttons' でボタンを追加。add_filter 'mce_external_plugins' でプラグインとなる js を登録することになります。

```php:functions.php

<?php

function register_button($buttons)
{
	$buttons[] = 'input_text';
	return $buttons;
}
add_filter('mce_buttons', 'register_button');

function mce_plugin($plugin_array)
{
	$plugin_array['custom_button_script'] = get_template_directory_uri() . '/editor_plugin.js';
	return $plugin_array;
}
add_filter('mce_external_plugins', 'mce_plugin');

?>
```

## editor_plugin.js の編集

プラグインの追加と登録をする js の編集をするよ

```js:editor_plugin.js

(function($, document, window){

	var path = $('#templateDirectory').val();

	tinymce.create(
		'tinymce.plugins.MyButtons',
		{
			init: function(ed, url)
			{
				ed.addButton(
					'input_text',
					{
						title: 'input text',
						image: path + '/path/to/image.png',
						cmd: 'input_text_cmd'
					}
				);

				ed.addCommand( 'input_text_cmd', function()
				{
					ed.windowManager.open(
					{
						url: path + '/path/to/view.html',
						width: 480,
						height: 270,
						title: 'テキストボックス名とラベル名をご入力ください'
					},
					{
						custom_param: 1	
					});
				});
			},
			createControl: function(n,cm)
			{
				return null;	
			}
		}
	);
	tinymce.PluginManager.add(
		'custom_button_script',
		tinymce.plugins.MyButtons
	);
})(jQuery, document, window);

```

この js での注目する点は、「addButton」「addCommand」の２つです。複数のボタンを同時に作る場合は先に挙げた functions.php の register_button で追加したいボタンを定義し、addButtonとaddCommand を追加したい分だけ羅列していきます。


またこの js の先頭で

```js

var path = $('#templateDirectory').val();

```

とありますが、js からテーマディレクトリのパスを取得するためのコードです。そのために functions.php ではそのためのコードを用意しています。

```php:function.php

function addHidden()
{
	$path = get_bloginfo( 'template_directory' );
	echo '<input type="hidden" id="templateDirectory" value='."{$path}".' />';
}
add_action('admin_menu', 'addHidden');

```

これで js からのパスの心配はなくなります。


## ダイアログ画面の作成

View はこんな感じで。

```html:view.html

<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Input Component Name</title>
	<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
	<link href="../css/styles.css" rel="stylesheet">
	<script src="https://code.jquery.com/jquery-1.11.3.min.js"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
	<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
	<script src="../javascripts/common.js"></script>
</head>
<body id="innerBody">
<p>テキストボックス名・ラベル名をご入力ください。両項目とも必須となります。また、テキストボックス名は半角英数とアンダースコアのみを利用できます。</p>
<table id="tb_input">
	<tr>
		<td>テキストボックス名</td>
		<td><input type="text" id="ComponentName" class="form-control" /></td>
	</tr>
	<tr>
		<td>ラベル名</td>
		<td><input type="text" id="LavelName" class="form-control" /></td>
	</tr>
</table>
<p id="ui"><input type="button" id="cancel" class="btn btn-danger" value="Cancel" onclick="return false;" />&nbsp;<input type="button" class="btn btn-primary" id="submit" value="OK" onclick="return false;" /></p>
<div id="errText"></div>
</body>
</html>

```

スタイルはこんな感じで

```sass
@import "bootstrap-compass";
@import "bootstrap-variables";
@import "bootstrap";

#innerBody {
	padding: 10px;
	#tb_input {
		td {
			padding: 10px;	
		}
	}
	#errText {
		color: #FF0000;
		font-size: 0.8em;
	}
	#ui {
		text-align: center;
	}
}
```

最後に js はこんな感じです。

```js:common.js

(function($, window, document, _){
	
	$(document).on('click','#submit',function(){
		$('#errText').empty();
		var nameValue = _.escape($('#ComponentName').val());
		var labelName = _.escape($('#LavelName').val());
		if(!(nameValue && labelName))
		{
			$('#errText').empty().text('テキストボックス名及びラベル名は必須です');
			return false;
		}

		if(!(/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(nameValue)))
		{
			$('#errText').empty().text('テキストボックス名に利用できる文字は半角英数字です。また先頭文字には数字を使うことができません');
			return false;
		}
		//var args = top.tinymce.activeEditor.windowManager.getParams();
		var inputTag = '<div id="inputTextDiv"><p><label for="'+ nameValue +'">'+labelName+'</label></p><p><input type="text" name="' + nameValue + '" id="' + nameValue + '" class="form-control"></p></div>';
		top.tinymce.activeEditor.selection.setContent(inputTag);
		top.tinymce.activeEditor.windowManager.close();
		return false;
	});

	$(document).on('click','#cancel',function(){
		$('#ComponentName').val('');
		$('#LavelName').val('');
		$('#errText').empty();
		top.tinymce.activeEditor.windowManager.close();
		return false;
	});

})(jQuery, window, document, _);
```

注目すべきコードはこちら

```js

top.tinymce.activeEditor.selection.setContent(inputTag);
top.tinymce.activeEditor.windowManager.close();

```

top.tinymce.activeEditor.selection.setContent() でアクティブになっているエディタの現在のカーソル位置に引数で渡した文字列が挿入されます。

top.tinymce.activeEditor.windowManager.close() でカスタムダイアログを閉じます。


## 最後に

ビジュアルエディタには以下のアイコンを用意

![input.png](https://qiita-image-store.s3.amazonaws.com/0/9988/ddafc67e-789a-d15b-1ac0-c2eefd9b6e53.png)

こんな感じで表示されます

![スクリーンショット 2015-07-26 11.51.11.png](https://qiita-image-store.s3.amazonaws.com/0/9988/73e731fb-d3f6-0f5b-308a-9e5a8173817b.png)

このアイコンは、editor_plugin.js の addButton() のパラメータでパスを指定してます。

```js

ed.addButton(
	'input_text',
	{
		title: 'input text',
		image: path + '/inc/assets/images/input.png',
		cmd: 'input_text_cmd'
	}
);

```

実際にテキストボックスを追加してみます。まずはビジュアルエディタ側。

![スクリーンショット 2015-07-26 12.14.40.png](https://qiita-image-store.s3.amazonaws.com/0/9988/c8a1a89f-94ce-2af2-cda8-c8be82665b3d.png)

HTMLはこんな感じになります。

![スクリーンショット 2015-07-26 12.14.52.png](https://qiita-image-store.s3.amazonaws.com/0/9988/f00281ef-80cc-fde2-5d55-aab57dff0ac8.png)
　
以上でカスタマイズの流れとなります。カスタムダイアログに関する情報が少なめだったので、[TinyMCEの本家サイト](http://www.tinymce.com/wiki.php/api4:index)でコードを漁りました。
　
慣れればカスタムのボタンをガンガン追加して、AddQuickTagなどのプラグインが無くてもよりインタラクティブなUIを提供できるようになります。
　
## おまけ

ビジュアルエディタにオリジナルのCSSを適用させるには、functions.phpに以下のコードを書きテーマファイル直下に editor-style.css を置いてください。

```php:functions.php

add_editor_style('editor-style.css');

```

bootstrap の内容をごっそりコピーしてあげれば、ビジュアルエディタの中身がごっそり bootstrap の CSS に置き換わります。

以上です。おつかれさまでした