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:サーバーに置いて動作を確かめる

  1. prosemirror-note.php と build フォルダーを、wp-content/plugins/prosemirror-note/ に置きます。
  2. 管理画面の「プラグイン」で「ProseMirror Note」を有効化します。
  3. 投稿の編集画面を開くと、本文の下に「補足メモ(ProseMirror)」の欄が表示されます。メニューバーから太字・見出し・箇条書きなどを使って入力し、投稿を保存します。
  4. 画面を再読み込みして、入力した内容が残っていれば保存できています。

保存した内容をテーマで表示するときは、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を整えます。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲