CKEditor 4から5への移行で押さえるべきポイント

概要

CKEditor 4 はすでに公式のサポート終了(End of Life)を迎えており、セキュリティ更新を受け続けるには有償の延長サポートに頼るか、CKEditor 5 へ移行するかの二択になります。

ここで押さえておきたいのは、CKEditor 5 は「4 のメジャーバージョンアップ」ではなく、ゼロから書き直された別物だということです。設定を少し書き換えれば済む作業ではありません。この記事では、移行を設計するときに引っかかりやすいポイントを、アーキテクチャの違いから順に整理します。

なぜそのまま移行できないのか

CKEditor 4 の設定・プラグイン・保存済みデータをそのまま 5 に持ち込もうとすると、主に次の壁にぶつかります。

  1. 初期化 API が別物(CKEDITOR.replace は存在しない)
  2. プラグイン体系・ツールバー設定の書式が違う
  3. ロードしていない機能に対応する HTML が「黙って消される」
  4. 画像・テーブルなど、出力される HTML の構造そのものが変わる
  5. 一部の機能が有償(プレミアム)に分類されている
  6. 近年のバージョンではライセンスキーの指定が必須

特に 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点です。

  1. 独自データモデル — ロードしていない機能の HTML は消える。既存データ保持は GHS を検討
  2. 出力 HTML の構造変化 — 画像・テーブルなどの表示側を要確認
  3. ライセンスと機能区分 — ライセンスキー必須化・プレミアム機能の棚卸し

「設定の置き換え」ではなく「既存データをどう生かすか」を最初の論点に据えると、移行設計が一気に現実的になります。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。