CKEditor 4から5への移行で押さえるべきポイント
概要
CKEditor 4 はすでに公式のサポート終了(End of Life)を迎えており、セキュリティ更新を受け続けるには有償の延長サポートに頼るか、CKEditor 5 へ移行するかの二択になります。
ここで押さえておきたいのは、CKEditor 5 は「4 のメジャーバージョンアップ」ではなく、ゼロから書き直された別物だということです。設定を少し書き換えれば済む作業ではありません。この記事では、移行を設計するときに引っかかりやすいポイントを、アーキテクチャの違いから順に整理します。
なぜそのまま移行できないのか
CKEditor 4 の設定・プラグイン・保存済みデータをそのまま 5 に持ち込もうとすると、主に次の壁にぶつかります。
- 初期化 API が別物(
CKEDITOR.replaceは存在しない) - プラグイン体系・ツールバー設定の書式が違う
- ロードしていない機能に対応する HTML が「黙って消される」
- 画像・テーブルなど、出力される HTML の構造そのものが変わる
- 一部の機能が有償(プレミアム)に分類されている
- 近年のバージョンではライセンスキーの指定が必須
特に 3 番目は、移行時に最も事故が起きやすいポイントです。
アーキテクチャの根本的な違い
CKEditor 4 は、基本的に DOM / HTML を直接編集する 設計でした。Advanced Content Filter(ACF)はありましたが、思想としては「HTML を扱うエディタ」です。
CKEditor 5 は 独自のドキュメントモデル(data model) を内部に持ち、MVC 的なアーキテクチャで動きます。画面に表示される DOM は、このモデルを変換して描画した「ビュー」にすぎません。
この設計から、重要な帰結が生まれます。
> モデルに変換できない(=対応するプラグインがロードされていない)要素・属性は、読み込んだ時点で破棄される。
CKEditor 4 の感覚で既存 HTML を setData() で流し込むと、<table> や class 属性、インラインスタイルなどが静かに消え、保存し直した瞬間にデータが欠損する、という事故につながります。
対応方法
1. 初期化コードの書き換え
CKEditor 4:
CKEDITOR.replace('editor', {
toolbar: [
{ name: 'basicstyles', items: ['Bold', 'Italic'] },
{ name: 'links', items: ['Link', 'Unlink'] },
],
});
CKEditor 5(Promise ベースになる点に注意):
import { ClassicEditor, Essentials, Paragraph, Bold, Italic, Link } from 'ckeditor5';
import 'ckeditor5/ckeditor5.css';
ClassicEditor
.create(document.querySelector('#editor'), {
licenseKey: 'GPL',
plugins: [Essentials, Paragraph, Bold, Italic, Link],
toolbar: ['bold', 'italic', '|', 'link'],
})
.then(editor => { window.editor = editor; })
.catch(error => { console.error(error); });
ポイント:
create()は Promise を返す。初期化完了を待ってからeditorを触る設計にする。pluginsに 使う機能を明示的に列挙する。列挙しない機能は存在しない扱いになる。- 近年のバージョンでは
licenseKeyの指定が必須。無償利用でも'GPL'の明示が必要。
2. 既存コンテンツを守るなら General HTML Support(GHS)
CKEditor 4 時代に蓄積した HTML に、現状プラグイン化していない要素・属性が含まれる場合、GHS で「とりあえず残す」方針が現実的です。
import { ClassicEditor, GeneralHtmlSupport } from 'ckeditor5';
ClassicEditor.create(el, {
licenseKey: 'GPL',
plugins: [/* 通常のプラグイン群 */, GeneralHtmlSupport],
htmlSupport: {
allow: [
{ name: /.*/, attributes: true, classes: true, styles: true },
],
},
});
GHS は「編集機能を提供する」のではなく「データを保持する」ための仕組みです。残したいだけなのか、編集もさせたいのかで方針が分かれます。許可範囲は広げすぎず、既存データの実態に合わせて絞るのが安全です。
3. 画像アップロードはアダプタが必須
CKEditor 5 は標準では画像アップロードの通信先を知りません。用途に応じてアップロードアダプタを選びます。
import { SimpleUploadAdapter } from 'ckeditor5';
ClassicEditor.create(el, {
licenseKey: 'GPL',
plugins: [/* ... */, SimpleUploadAdapter],
simpleUpload: {
uploadUrl: '/api/upload',
headers: { 'X-CSRF-TOKEN': csrfToken },
},
});
Base64 埋め込みは手軽ですが本文 HTML が肥大化するため、サーバ保存型が無難です。
4. 出力 HTML の構造変化に備える
画像ひとつ取っても出力が変わります。
<!-- CKEditor 4 --> <p><img src="/img/a.png" alt="" /></p> <!-- CKEditor 5(キャプション機能あり等) --> <figure class="image"> <img src="/img/a.png" alt="" /> <figcaption>...</figcaption> </figure>
既存データを 5 で読み込み・再保存すると、こうした構造差が混在します。表示側(公開ページ)の CSS・パーサがこの差を吸収できるかを事前に確認してください。
移行前にやる「消失チェック」
既存 HTML を 5 に通したときに「何が消えるか」を把握しておくと事故を防げます。簡易には、setData() → getData() を往復させて差分を取るアプローチが有効です。
async function roundTrip(editor, html) {
editor.setData(html);
return editor.getData(); // 入力 html と比較し、消えた要素を洗い出す
}
本番データの代表サンプルを通し、消失・変形する要素をリスト化してから移行計画を立てます。
確認方法
- 代表的な既存コンテンツを
setData()→getData()で往復させ、差分を確認する - 画像・リンク・テーブルなど、機能ごとに新旧の出力 HTML を突き合わせる
- エディタ外での表示(コンテンツスタイル CSS の適用有無)を確認する
注意点
- コンテンツスタイル CSS: CKEditor 5 のコンテンツを編集画面の外で表示するには、エディタの content styles を別途読み込む必要がある。忘れると表示が崩れる。
- プレミアム機能: コメント、変更履歴、リアルタイム共同編集、PDF/Word エクスポートなどは有償。4 で OSS プラグインとして使えていたものが 5 では有償区分、というケースがある。
- ライセンスキー: 近年のバージョンでは無償利用でも
licenseKey指定が必須。CI・ビルドに組み込む前提で確認する。 - プラグイン等価性: 4 のサードパーティ製プラグインには 5 に直接の後継がないものが多い。機能要件の棚卸しを先に行う。
まとめ
CKEditor 4 → 5 は「アップグレード」ではなく「別エディタへの載せ替え」です。鍵は次の3点です。
- 独自データモデル — ロードしていない機能の HTML は消える。既存データ保持は GHS を検討
- 出力 HTML の構造変化 — 画像・テーブルなどの表示側を要確認
- ライセンスと機能区分 — ライセンスキー必須化・プレミアム機能の棚卸し
「設定の置き換え」ではなく「既存データをどう生かすか」を最初の論点に据えると、移行設計が一気に現実的になります。
