baserCMS Markdownエディタ プラグインを作ってみました。
- 2026/6/28 追記
プラグイン名を「MdEditor」に変更し、新たなプラグインとして公開しました。以前公開していた「MDEditor」を利用していた方は、BaserCMSの管理画面から削除し、あらためて「MdEditor」をインストールしてご利用ください。
- 2026/6/22 追記
最後まで手こずった固定ページへの実装が、やっと目処が立ちました。公開時は、プラグイン名を変更し、新たなプラグインとして近日公開予定です。- 2026/6/20 追記
フロント画面、固定ページの外部アセットファイルの扱いについて、根本的に扱いを考え直さないといけないようなので、いったん公開を中止します。ずっと、(誰かが作ってくれるのを)待っていたMarkdownエディタプラグインでしたが、とうとう自分で作ってみることにしました。といっても、素敵な外部ライブラリをお借りしただけですが。
では、いつもの通りreadme.mdの写し。あと、またまた4系ですいません。
MdEditor for baserCMS 4
baserCMS 4系(CakePHP 2系ベース)の管理画面に、高機能な Markdown エディタ EasyMDE を導入するプラグインです。
標準の CKEditor と置き換える、または出し分ける形で、ブログ記事や固定ページを快適な Markdown 記法で執筆できるようになります。
主な特徴
-
安心のデータ保存・プレビュー設計(PHPタグ自動保護)
固定ページの保存時やプレビュー時に発生しやすい、baserCMSコア側とのシステム衝突を完全に回避します。 文章の中にPHPコードの解説(<?php ... ?>などの記述)が含まれていたり、閉じ忘れなどの不完全な構文があっても、システムが裏側で自動的に安全なコードへと一時変換して保護。サイト内検索のインデックス更新時など、バックグラウンドの処理を巻き込んで画面が真っ白(システム停止)になるトラブルを未然に防ぎます。 -
管理画面でのスムーズな再編集 & 「HTML混じりMarkdown」の安全なパース
管理画面を開いた際には、保護されていたコードが自動的に元のクリーンな記述へと復元されるため、ストレスなくそのまま再編集が可能です。 また、Markdown内に生の<br>や装飾用の<div>、YouTubeの<iframe>などのHTMLタグが混在していても無理なく調和してパース・出力します。 -
XSS(クロスサイトスクリプティング)防御とカプセル化の両立
フロント画面の表示時には、記事全体のHTMLから「Markdownで書かれた本文詳細エリア」だけをシステムがピンポイントで正確に切り抜き(隔離カプセル化)、コメント欄やその他のテーマ部品をパース対象に巻き込まないようにしています。 さらに、出力の最終段でPHPのDOM解析(DOMDocument)を用いたHTMLサニタイザーで、安全な許可タグ(ホワイトリスト)の利便性はそのまま活かしつつ、悪意ある<script>や、巧妙に仕込まれたイベント属性(onclick,onerror等)、危険なプロトコル(javascript:等)の脆弱性トリガーだけを分解して削除、無害化します。 -
認可制御付きの画像非同期アップロード
EasyMDE の標準機能と連動し、エディタへの画像ドラッグ&ドロップまたはペーストによって、プラグイン固有のカスタムエンドポイント(MdEditorUploadsController)を介した非同期画像アップロード及びエディタへのパス自動挿入が可能です。 セキュリティ面ではセッション認証に加え、許可された所属ユーザーグループIDのみに厳格なアップロード権限を付与する認可機構を搭載しています。 -
外部CSSの干渉を遮断するユニバーサル・リスト制御
既存テーマやコアが持つ強力なスタイルシート(editor.cssの3重クラスお化けなど)からの意図しないスタイル汚染を防止する「詳細度最大化シールド(クラス3連打構造)」を実装。 リスト(ul/ol)の複雑な入れ子(ネスト)構造における「0埋めバグ(01, 02表記)」や「疑似要素(::before)の絶対配置ドット乱入」を封じ込め、Markdown標準の美しい箇条書きと連番数字を描画します。 -
多軸固定スクロール & 配色自動同化のコードブロック
フロントエンド表示用にHighlight.js(atom-one-lightテーマ)および専用のコアスクリプト・CSSを自動注入。プログラミングのコードブロック(```)内の技術解説用タグは、サニタイザーに消去されることなく安全な文字列として保護されて出力されます。 さらに、縦スクロール時はコードと行番号が完全に1対1で連動し、横スクロール時だけ行番号が左端に固定される「X軸限定 sticky 吸着構造」を採用。ユーザーが最下部にどのような配色テーマ(GitHub Dark等)を貼り付けても、行番号・言語ヘッダー・コピーボタンのすべての色彩ルールを美しく同化させるコードブロック設計です。
フォルダ構成
app/Plugin/MdEditor/
├── config.php # プラグイン基本定義 & 設定常時ロード
├── README.md # 本ドキュメント
├── VERSION.txt
├── Config/
│ └── setting.php # ユーザー専用ツールバー拡張設定
├── Controller/
│ └── MdEditorUploadsController.php # ドラッグ&ドロップ用セキュア画像アップロード(API)
├── Event/
│ └── MdEditorControllerEventListener.php # データ送信時のPHPタグ変換保護 & プレビューエラー自動回避
├── View/
│ └── Helper/
│ └── MdEditorHelper.php # カプセル化切り出し、Markdown変換、及びDOMサニタイズ(XSS防御)の統合制御
├── Vendor/
│ ├── Parsedown.php # Markdownパースエンジン (v1.8.0)
│ └── CustomParsedown.php # ファイル名言語ヘッダー対応の拡張パースエンジン
└── webroot/
├── css/
│ ├── easymde.min.css # EasyMDE スタイルシート (v2.18.0)
│ ├── atom-one-light.min.css # @highlightjs スタイルテーマ
│ ├── mde-preview.css # 管理側エディタ表示・プレビュー調整用
│ └── mde-add.css # コードブロック表示 & デザイン干渉防止用
└── js/
├── easymde.min.js # EasyMDE コアスクリプト (v2.18.0)
├── highlight.min.js # highlight.js スクリプト (v11.9.0)
└── mde-core.js # 行番号の追加 & コピーボタン機能用
インストール要件
- CMS本体: baserCMS 4.7.x以上(admin-second / admin-third テーマ対応)
- 動作環境: PHP 7.x 以上(PHP 8.x 対応)
インストール方法・設定
- 本リポジトリをダウンロードし、フォルダ名を
MdEditorに変更します。 - baserCMS の
app/Plugin/ディレクトリ配下に配置します。 - baserCMS 管理画面の「プラグイン管理」より、MdEditor を有効化します。
- baserCMS 管理画面の「サイト基本設定」→「エディタ設定」より、Markdownエディタを選択します。
使い方
標準エディタからの切り替え
baserCMS 4系の標準エディタ(CKEditor)と競合を避けるため、システム設定、または各固定ページ・ブログの設定等で「エディタタイプ」を調整するか、特定の入力欄のみに適用されるよう出し分けを行ってください。
画像のアップロード・挿入仕様について
本プラグインは、システムの堅牢性と超軽量・高安定な動作を最優先するため、baserCMSコアや標準のUploaderプラグインに対する無理なハック処理を排除し、機能を完全に独立(カプセル化)させた安全な設計を採用しています。
-
ドラッグ&ドロップ / ペーストによる非同期アップロード(推奨)
エディタ(EasyMDE)上に画像を直接ドラッグ&ドロップ、またはクリップボードからペースト(Ctrl+V/Cmd+V)するだけで、本プラグイン専用のセキュアAPIを介して自動的にサーバーへ非同期アップロードされ、エディタ上へMarkdownの画像タグ(パス)が即座に自動挿入されます。 ※セキュリティ保護のため、初期状態では「システム管理者(ユーザーグループID: 1)」のみにこの非同期アップロード権限が認可されています。 -
標準UploaderプラグインのURL利用
baserCMS標準のUploaderプラグインも、管理画面の「アップロード管理」から通常通り併用可能です。既にアップロード済みのファイルがある場合は、そのURLをコピーし、EasyMDEのツールバーにある「画像ボタン」の入力プロパティへペーストして挿入することもできます。
カスタマイズ設定
ツールバーの表示項目や初期配置は、Config/setting.php の配列定義より自由に変更・拡張が可能です。
デフォルトでは以下の主要ツールのほか、独自拡張構文である「補足情報ボックス(info-box)」をワンクリックで挿入できるカスタムアイコンボタンがあらかじめ組み込まれています:
["bold", "italic", "strikethrough", "heading", "|", "quote", "code", "table", "horizontal-rule", "|", "unordered-list", "ordered-list", "|", "link", "image", "|", "preview", "side-by-side", "fullscreen", "|", "guide"]
ブログ記事一覧やサイト内検索結果での記述露出について(重要)
ブログの一覧ページ(インデックス/アーカイブ)、サイト内検索結果ページ、各種ウィジェット等では、テーマの設計やbaserCMSコアの仕様により、「概要(content)」だけでなくEasyMDEで記述した「本文詳細(detail)」から一律に文字数を切り出して出力するケースがあります。
そのため、対策を行わない場合は一覧や検索結果の画面に以下の記述がそのまま露出、あるいはレイアウトが崩れる原因となる場合があります。
- 生の Markdown 記法(
###や```などの特殊構文) - 本プラグイン専用のアンカーマーカー
※なお、今回のアップデートにより、保存時の文章破損の原因となっていたシステム保護用の独自コード(<?php等のシールドトークン)の一律強制保存は完全に撤廃したため、データロスリスクはありません。
【推奨される運用ルール】
ブログ記事を作成される際は、本文詳細とは別にある 「概要(説明文)」欄への要約テキストの入力 を推奨(できれば必須化)します。
概要欄を活用するメリットは以下:
- 出力の最適化とクリーン化
Markdown記号や隠しマーカーが一切混ざらない、クリーンな日本語の抜粋文で一覧および検索結果画面を統一できます。 - SEO・SNSシェアの自動最適化
概要欄のテキストは、検索エンジンのメタディスクリプションや SNS シェア時の OGP 紹介文として自動的に再利用されるため、サイトの評価向上に直結します。
コアロジック(技術的アプローチ)
本プラグインは、baserCMS 4系における自動クレンジングや検索インデックス作成時のバックグラウンド割り込み処理による干渉を回避し、かつテーマ全体のレイアウト構造への影響を隔離するため、以下のライフサイクルタイミングでデータの調整とフィルタリングを行っています。
-
データ送信・保存時(
Controller.initialize)
管理画面での保存・プレビュー(POST/PUT)を最上流タイミングでフックした段階で、文章内の実行用 PHP タグ(<?phpや<?=)を対象に、バックトラック制限による文字漏れリスクのない高速な文字列置換(str_replace)を用いて<?phpなどの独自シールドトークンへと一時的に変換(無害化)。 さらにブログ記事(detail)の保存時には、前後の他の要素と連続しない完全な独立行として、カプセル化(隔離)の絶対的な目印となる専用のアンカーマーカー(<!--MDE_BODY_START-->/<!--MDE_BODY_END-->)を付与してデータベースへ保存します。 -
管理画面のエディタフォーム描画時(
Controller.beforeRender)
フォーム描画直前のタイミング(beforeRender)をフック。無害化されていた独自シールドトークンを元のクリーンな PHP タグへと正確に復元してからビュー(フォーム変数)に渡すことで、管理画面(EasyMDE)上でのスムーズな再編集を可能にします。 -
フロント公開画面の最終出力時(
Helper.beforeLayout➔ DOMサニタイズ・パイプライン)
ビューの組み立てが行われ、テーマの全レイアウトコンポーネント(ヘッダー、フッター、コメント欄など)が結合された直前のレンダリングバッファ(Blocks->get('content'))をフックします。- 固定ページ(Pages): 独自シールドトークンの安全性を維持したまま、拡張パースエンジン(
CustomParsedown)へ引き渡してページ全体をHTML化し、新設されたDOMサニタイザーを通過させた後、専用の防衛コンテナ(.mde-parsed-body)で包んでバッファへ書き戻します。 - ブログ詳細ページ(archives): 処理負荷の高い正規表現を排除し、PHP標準の高速なインデックス検索(
strpos/substr)を採用。データベースに保存されたアンカーマーカーの間(=純粋な本文詳細領域のみ)を安全に切り出します(スライス)。
- 固定ページ(Pages): 独自シールドトークンの安全性を維持したまま、拡張パースエンジン(
-
HTML混じり許容 & 最終段DOMサニタイズ
切り出された領域に対してCustomParsedownによる解析を実行。<br>や<iframe>などのHTML混じりMarkdownを素直にパースさせます。 その後、画面へ再結合する最終段階で、PHPのDOM解析(DOMDocument)を用いた高性能HTMLサニタイザーが自動稼働。この際、DOMエンジンがHTMLコメント(アンカー)や解説用の生PHPタグを 「DOM解析時のみ特殊なシールドで文字を一時退避させ、クレンジング完了後に復元する」という着脱式サンドイッチシールドを行います。 安全な許可タグの利便性を活かしながらXSS脆弱性(onclickなどのイベント属性やjavascript:プロトコル)だけを構造分解・排除し、ファイル名言語ヘッダーおよび多軸固定スクロール仕様のHTMLとしてカプセル化(隔離)出力します。
ライセンス条項
本プラグインおよび同梱されているすべてのコンポーネントは MIT License のもとで公開・配布されています。
MITライセンスの再配布規約を遵守するため、内包されている外部ライブラリのコード内ヘッダー(著作権表記および許諾表示コメント)は一切変更・上書きせず、そのままの状態で同梱しています。各コンポーネントの原著作者および帰属情報は以下の通りです。
1. MDEditor (本プラグイン本体)
- License: MIT License
- Copyright: (c) 2026 HATTA, HATTANTOCO
2. EasyMDE (Easy Markdown Editor)
- Source: Ionaru/easy-markdown-editor
- License: MIT License
- Copyright: (c) 2017 Jeroen Ionaru, (c) 2015 NextStepWebs
3. Parsedown
- Source: erusev/parsedown
- License: MIT License
- Copyright: (c) 2013-2018 Emanuil Rusev
4. highlight.js
- Source: highlightjs/highlight.js
- License: BSD 3-Clause License
- Copyright: (c) Ivan Sagalaev, highlight.js team
HATTANTOCO