ダッシュボードの「クイックドラフト」を「CodeMirror」に変更してみた

説明

管理ページの「テーマエディター」では4.9以降「CodeMirror」が利用されている。今回はこの「CodeMirror」をプラグインで活用できないか調べた話である。

ソースコードを眺める

「テーマエディター」のページを開くと、テーマのstyles.cssの内容を表示し、少し間をおいて行番号を表示しなおしている。このことからJavaScriptを使用していることが予想でき、そのあたりに着目して/wp-admin/theme-editor.phpを見ていくと、wp_enqueue_code_editor関数が見つかった。

さらにwp_enqueue_code_editor関数の中を見てみると、 wp_enqueue_script関数と wp_enqueue_style関数を使って'code-editor'を出力用のキューに入れている。この'code-editor'は/wp-includes/script-loader.phpで次のように指定されている。

$scripts->add( 'wp-codemirror', '/wp-includes/js/codemirror/codemirror.min.js', array(), '5.29.1-alpha-ee20357' );
$scripts->add( 'csslint', '/wp-includes/js/codemirror/csslint.js', array(), '1.0.5' );
$scripts->add( 'esprima', '/wp-includes/js/codemirror/esprima.js', array(), '4.0.0' );
$scripts->add( 'jshint', '/wp-includes/js/codemirror/fakejshint.js', array( 'esprima' ), '2.9.5' );
$scripts->add( 'jsonlint', '/wp-includes/js/codemirror/jsonlint.js', array(), '1.6.2' );
$scripts->add( 'htmlhint', '/wp-includes/js/codemirror/htmlhint.js', array(), '0.9.14-xwp' );
$scripts->add( 'htmlhint-kses', '/wp-includes/js/codemirror/htmlhint-kses.js', array( 'htmlhint' ) );
$scripts->add( 'code-editor', "/wp-admin/js/code-editor$suffix.js", array( 'jquery', 'wp-codemirror', 'underscore' ) );
$scripts->add( 'wp-theme-plugin-editor', "/wp-admin/js/theme-plugin-editor$suffix.js", array( 'wp-util', 'wp-sanitize', 'jquery', 'jquery-ui-core', 'wp-a11y', 'underscore' ) );

どうやら'wp-codemirror'の名前で定義されている「CodeMirror」がエディターの本体で、関連するスクリプトも定義されているようだ。

「CodeMirror」はfromTextAreaメソッドを使用してエディターの初期化を行う。「テーマエディター」では/wp-admin/js/code-editor.jsで以下のように指定している。

codemirror = wp.CodeMirror.fromTextArea( $textarea[0], instanceSettings.codemirror );

WordPressの管理ページ内にあるtextarea要素を変更する場合、wp_enqueue_code_editor関数を使用するのが手っ取り早いが、今回は下位レベルの'wp-codemirror'として登録されているものを使用して基本的な使い方を理解しようと思う。

「クイックドラフト」のtextarea要素を変更

最終的には自身のプラグインで「CodeMirror」を使いたいのだが、まずは身近にあるダッシュボードの「クイックドラフト」で試してみる。

ダッシュボードの「クイックドラフト」ウィジェット

「クイックドラフト」のtextarea要素を「CodeMirror」に変更するため、スクリプトとスタイルの組み込みには'admin_enqueue_scripts'アクションを使用するのだが、その前段階として'wp_dashboard_setup'アクションを使用し、ほかのページに影響を与えないようにする。

add_action( 'wp_dashboard_setup', 'textarea2_setup' );

function textarea2_setup() {
	add_action( 'admin_enqueue_scripts', 'textarea2_enqueue' );
}

実際にスクリプトとスタイルを組み込むtextarea2_enqueue関数の内容は次の通り。'wp-codemirror'の名前で登録されているものを、それぞれwp_enqueue_script関数とwp_enqueue_style関数を使って出力キューに入れる。

function textarea2_enqueue() {
	wp_enqueue_script( 'wp-codemirror' );
	$inline_script = <<<EOT
window.addEventListener( 'load', function () {
	const textarea2_editor = wp.CodeMirror.fromTextArea( document.getElementById( 'content' ), {
		lineNumbers   : true,
		lineWrapping  : true,
		extraKeys     : { 'Ctrl-F': 'findPersistent', 'Cmd-F': 'findPersistent' },
	} );
	textarea2_editor.display.input.getField().addEventListener( 'blur', function () {
		textarea2_editor.save();
	} );
} );
EOT;
	wp_add_inline_script( 'wp-codemirror', $inline_script );

	wp_enqueue_style( 'wp-codemirror' );
	$inline_style = <<<EOT
.CodeMirror {
	width         : 100%;
	height        : 5.75rem;
	border        : 1px solid #ddd;
	box-sizing    : border-box;
	margin-bottom : 8px;
}
EOT;
	wp_add_inline_style( 'wp-codemirror', $inline_style );
}

wp_add_inline_script関数で追加しているスクリプトでは、loadイベントを使用し、CodeMirrorインスタンスを生成する。連想配列で指定しているパラメータは多いため、ここでは主なパラメータのみを紹介する(あくまで主観的)。

キー値の意味デフォルト値
lineNumbers行番号を表示する場合はtrue、非表示はfalsefalse
firstLineNumber先頭の行番号1
lineWrapping1行の文字数がエディターの幅を超えた際に折り返す場合はtrue、スクロールする場合はfalsefalse
extraKeys特別なキーアサインを指定なし
dragDropドラッグ&ドロップを許可する場合はtruetrue
tabSizeタブ文字の幅4
modeモード(協調表示しない場合はnullを指定)'css'
themeテーマ名(ラッパーとなるdiv要素のclass名の一部)を指定(cm-s-〇〇〇〇)'default'
readOnly読み込み専用の場合はtruefalse

extraKeysにはキーの組み合わせとそのアクションを複数指定できる。上記の指定は、Ctrl+Fキーおよびcommand+Fキー押下時にエディター内のワード検索ボックスを表示する指定となる。

CodeMirrorインスタンスを生成した後にblurイベントについて記述している。これはCodeMirrorインスタンスで編集した内容と元のtextarea要素を同期するための「おまじない」で、フォーカスが外れたタイミングで同期を行い、「下書きとして保存」ボタンをクリックした際に正しく保存できるようにした。

wp_add_inline_style関数で追加したスタイルは、CodeMirrorエディターの外観用である。標準では少し高すぎるので、ここで高さと下マージンなどを調整している。実際に上記のコードを適用した画面がこちらである。

変更した「クイックドラフト」ウィジェット

もとのtextarea要素のプレースホルダーが引き継がれ、行番号が表示されている。

まとめ・雑感

最後に「CodeMirror」を使ってみて気づいたことを1つ紹介。それは非表示のtextarea要素に対してCodeMirrorインスタンスを生成すると、行番号の表示が乱れてしまうことだ(この症状はブラウザ依存かもしれない)。これはtextarea要素が非表示の場合、行番号部分を表示する幅を正しく取得できないことが原因。対象のtextarea要素を表示状態に変更してからCodeMirrorインスタンスを生成することでこの問題は回避できる。

さて「CodeMirror」はcssやJavaScriptのLINT機能も備えており、必要に応じて追加可能である。今回はお試しということで基本機能のみを使ってみたが、実際に実装する際はそれらも検討したい。


最終更新 : 2019年11月05日 09:59


お勧め

wp_insert_user(2019年5月29日 更新)

mixed wp_insert_user( mixed $userdata )
ユーザーを登録する。

fetch_feed(2018年5月27日 更新)

mixed fetch_feed( mixed $url )
RSSまたはAtom形式のフィードデータを読み込む。

is_tag(2018年5月27日 更新)

bool is_tag( [ mixed $slug = '' ] )
要求されているページが、タグアーカイブページか調べる。

esc_js(2019年1月24日 更新)

string esc_js( string $text )
文字列をインラインJavaScript向けにエスケープ処理する。

wp_list_pages(2015年4月28日 更新)

string wp_list_pages( [ mixed $args = '' ] )
固定ページを一覧表示する。