2026年8月6日
2026年8月6日
WordPressでProseMirrorを使う方法:自作プラグインで編集欄に組み込む手順
ProseMirrorは、ブラウザ上で動くリッチテキストエディターを作るためのJavaScriptライブラリです。WordPressにそのまま入れて使う「ProseMirrorプラグイン」はありません(2026年11月時点で、WordPress.orgのプラグインディレクトリにも該当するものは見当たりません)。WordPressで使うには、npmでライブラリを取り込み、自分のプラグインやテーマからJavaScriptとして読み込みます。
この記事では、投稿の編集画面に「補足メモ」欄を追加し、そこをProseMirrorのエディターにする小さなプラグインを例に、組み込みの手順を説明します。
ProseMirrorを使う場面と使わない場面
本文の編集は、WordPress標準のブロックエディターが担っています。ブロックエディターの見た目や機能を変えたい場合は、ProseMirrorを持ち込むよりも、ブロックやブロックエディターの拡張機能を使うほうが素直です。
ProseMirrorが向いているのは、次のようにブロックエディターの外で、HTMLを書ける入力欄が必要な場合です。
- 投稿編集画面に、本文とは別の書式付きの入力欄(カスタムフィールド)を追加したい
- 独自の管理画面や、ログインした会員向けのフロント側フォームに、見出しや箇条書きを使える入力欄を置きたい
- 使える書式(太字・リンク・箇条書きなど)を、スキーマで厳密に絞りたい
用意するもの
- Node.js と npm(JavaScriptのビルドに使います。サーバーではなく手元のパソコンで構いません)
- 自作プラグインを置ける WordPress 環境(まずは検証用サイトで試します)
できあがるプラグインのフォルダー構成は次のとおりです。src と node_modules は開発用で、サーバーに上げるのは prosemirror-note.php と build フォルダーです。
prosemirror-note/
├── prosemirror-note.php … プラグイン本体(PHP)
├── src/editor.js … エディターのソース
├── build/editor.js … ビルド結果(サーバーに上げる)
├── build/editor.css … ビルド結果(サーバーに上げる)
├── package.json
└── node_modules/
手順1:ProseMirrorのパッケージを入れる
ProseMirrorは機能ごとに小さなパッケージに分かれています。公式サイトの基本例(Basic example)と同じ組み合わせを入れ、ビルド用に esbuild も入れます。
mkdir prosemirror-note
cd prosemirror-note
npm init -y
npm install prosemirror-state prosemirror-view prosemirror-model prosemirror-schema-basic prosemirror-schema-list prosemirror-example-setup prosemirror-menu
npm install --save-dev esbuild
| パッケージ | 役割 |
|---|---|
prosemirror-model |
文書の構造(スキーマ)と、HTMLとの変換 |
prosemirror-state |
エディターの状態 |
prosemirror-view |
画面への表示と入力の受け付け |
prosemirror-schema-basic |
段落・見出し・引用・太字・リンクなどの基本スキーマ |
prosemirror-schema-list |
箇条書き・番号付きリスト |
prosemirror-example-setup |
メニューバーやキー操作をまとめて付ける設定例 |
prosemirror-menu |
メニューバー(CSSを読み込むために直接入れておく) |
手順2:エディターのJavaScriptを書く
src/editor.js を作ります。編集欄を表示する場所(#pm-note-editor)と、保存用の隠しテキストエリア(#pm-note-content)はPHP側で出力します。文書が変わるたびにHTMLへ変換してテキストエリアに書き戻すので、通常のフォーム送信と同じ流れで保存できます。
import { EditorState } from 'prosemirror-state';
import { EditorView } from 'prosemirror-view';
import { Schema, DOMParser, DOMSerializer } from 'prosemirror-model';
import { schema } from 'prosemirror-schema-basic';
import { addListNodes } from 'prosemirror-schema-list';
import { exampleSetup } from 'prosemirror-example-setup';
import 'prosemirror-view/style/prosemirror.css';
import 'prosemirror-menu/style/menu.css';
import 'prosemirror-example-setup/style/style.css';
const mount = document.getElementById('pm-note-editor');
const field = document.getElementById('pm-note-content');
if (mount && field) {
const mySchema = new Schema({
nodes: addListNodes(schema.spec.nodes, 'paragraph block*', 'block'),
marks: schema.spec.marks,
});
const serializer = DOMSerializer.fromSchema(mySchema);
const toHTML = (doc) => {
const wrap = document.createElement('div');
wrap.appendChild(serializer.serializeFragment(doc.content));
return wrap.innerHTML;
};
const initial = document.createElement('div');
initial.innerHTML = field.value;
const view = new EditorView(mount, {
state: EditorState.create({
doc: DOMParser.fromSchema(mySchema).parse(initial),
plugins: exampleSetup({ schema: mySchema }),
}),
dispatchTransaction(tr) {
const next = view.state.apply(tr);
view.updateState(next);
if (tr.docChanged) {
field.value = toHTML(next.doc);
}
},
});
}
ポイントは次の3つです。
DOMParser.fromSchema(...).parse()で、保存済みのHTMLをProseMirrorの文書に読み込みます。スキーマに無い要素(たとえば<table>)は読み込まれません。DOMSerializer.fromSchema(...).serializeFragment()で、文書をHTMLに戻します。- CSSは3つとも必要です。ProseMirrorの公式の基本例でも、
prosemirror-view・prosemirror-menu・prosemirror-example-setupのCSSを読み込むよう案内されています。
手順3:ビルドする
esbuild で1つのJavaScriptファイルにまとめます。JavaScriptの中で読み込んだCSSは、同じ名前の .css ファイルとして出力されます。
npx esbuild src/editor.js --bundle --minify --outfile=build/editor.js
build/editor.js と build/editor.css ができていれば成功です。src/editor.js を直したら、そのたびにこのコマンドを実行し直します。
手順4:プラグイン本体(PHP)を書く
prosemirror-note.php を作ります。投稿の編集画面にメタボックスを追加し、保存時にHTMLを wp_kses_post() で整えてからカスタムフィールド(_pm_note)に入れます。JavaScriptとCSSは、投稿の編集画面のときだけ読み込みます。
<?php
/**
* Plugin Name: ProseMirror Note
* Description: 投稿の編集画面に、ProseMirror で書く「補足メモ」欄を追加する例。
* Version: 0.1.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// 投稿の編集画面にメタボックスを追加する。
add_action( 'add_meta_boxes', function () {
add_meta_box( 'pm-note', '補足メモ(ProseMirror)', 'pm_note_render', 'post', 'normal' );
} );
function pm_note_render( $post ) {
wp_nonce_field( 'pm_note_save', 'pm_note_nonce' );
$html = get_post_meta( $post->ID, '_pm_note', true );
echo '<div id="pm-note-editor"></div>';
echo '<textarea id="pm-note-content" name="pm_note" hidden>' . esc_textarea( $html ) . '</textarea>';
}
// 保存時に HTML を整えてカスタムフィールドに入れる。
add_action( 'save_post_post', function ( $post_id ) {
if ( ! isset( $_POST['pm_note_nonce'] )
|| ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['pm_note_nonce'] ) ), 'pm_note_save' ) ) {
return;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
if ( isset( $_POST['pm_note'] ) ) {
update_post_meta( $post_id, '_pm_note', wp_kses_post( wp_unslash( $_POST['pm_note'] ) ) );
}
} );
// 投稿の編集画面だけでビルド済みの JS と CSS を読み込む。
add_action( 'admin_enqueue_scripts', function ( $hook ) {
if ( 'post.php' !== $hook && 'post-new.php' !== $hook ) {
return;
}
if ( 'post' !== get_current_screen()->post_type ) {
return;
}
$dir = plugin_dir_path( __FILE__ ) . 'build/';
$url = plugin_dir_url( __FILE__ ) . 'build/';
wp_enqueue_style( 'pm-note', $url . 'editor.css', array(), filemtime( $dir . 'editor.css' ) );
wp_enqueue_script( 'pm-note', $url . 'editor.js', array(), filemtime( $dir . 'editor.js' ), array( 'in_footer' => true ) );
} );
wp_enqueue_script()の5番目の引数に配列でin_footerを渡す書き方は、WordPress 6.3 以降で使えます。それより古い環境ではtrueを渡します。- バージョン番号に
filemtime()を使っているので、ビルドし直すとブラウザのキャッシュが切り替わります。 - 投稿以外(固定ページやカスタム投稿タイプ)で使う場合は、
add_meta_box()の4番目の引数、save_post_postのフック名、post_typeの判定を合わせて変えます。
手順5:サーバーに置いて動作を確かめる
prosemirror-note.phpとbuildフォルダーを、wp-content/plugins/prosemirror-note/に置きます。- 管理画面の「プラグイン」で「ProseMirror Note」を有効化します。
- 投稿の編集画面を開くと、本文の下に「補足メモ(ProseMirror)」の欄が表示されます。メニューバーから太字・見出し・箇条書きなどを使って入力し、投稿を保存します。
- 画面を再読み込みして、入力した内容が残っていれば保存できています。
保存した内容をテーマで表示するときは、wp_kses_post() を通してから出力します。
<?php
$note = get_post_meta( get_the_ID(), '_pm_note', true );
if ( $note ) {
echo '<div class="pm-note">' . wp_kses_post( $note ) . '</div>';
}
うまく動かないときの確認ポイント
- 編集欄が表示されない:ブラウザの開発者ツールで、
build/editor.jsが404になっていないか、コンソールにエラーが出ていないかを確認します。フォルダー名やファイル名がPHPの記述と合っているかも見ます。 - メニューバーが崩れる・表示されない:
build/editor.cssが読み込まれているか確認します。CSSを読み込まないと、メニューや選択範囲の表示が正しくなりません。 - 保存しても内容が消える:隠しテキストエリアの
name="pm_note"とPHPの$_POST['pm_note']が一致しているか、nonce の名前がwp_nonce_field()とwp_verify_nonce()で一致しているかを確認します。 - 貼り付けた表や画像が消える:この例のスキーマ(
prosemirror-schema-basicと箇条書き)に無い要素は読み込まれません。必要な要素はスキーマに追加します。 - 保存後に一部のタグが消える:
wp_kses_post()が投稿本文で許可されていないタグや属性を取り除いています。
注意点
- 入力されたHTMLは、保存時と出力時の両方で
wp_kses_post()などを通します。ブラウザ側のスキーマで書式を絞っていても、送信内容は書き換えられるため、サーバー側での確認が必要です。 - ProseMirrorとesbuildは更新が続いています。
npm updateのあとはビルドし直し、編集・保存・表示の一連の動きを検証用サイトで確かめてから本番に上げます。 - この例のビルド結果は、圧縮しても数百KBになります。編集画面だけで読み込むようにし、公開ページでは読み込まないようにしています。
まとめ
- ProseMirrorはWordPressのプラグインではなく、エディターを作るためのJavaScriptライブラリです。WordPressの本文編集を置き換えるものではありません。
- npmでパッケージを入れ、esbuildでJavaScriptとCSSにまとめ、
admin_enqueue_scriptsで必要な画面だけに読み込みます。 - 文書の変更をHTMLに変換して隠しテキストエリアに書き戻せば、メタボックスの通常の保存処理でカスタムフィールドに保存できます。
- 保存時と表示時には
wp_kses_post()でHTMLを整えます。