Upgrading my site from CKEditor 4 to CKEditor 5

Matt Glaman
5 min readMay 9, 2023

My site runs on Drupal 9.5. I started preparing to upgrade to Drupal 10 right after 10.0.0 was released, but then I got hit with CKEditor 4 to CKEditor 5 blockers. The Linkit, CodeSnippet, and Entity Embed modules supported Drupal 10 but didn’t support CKEditor 5. I could have updated to Drupal 10 and leveraged the CKEditor 4 contributed module, but I wanted to wait.

I will say, though. As we approach Drupal 10.1.0, more users will find a much easier upgrade path to Drupal 10 and CKEditor 5.

Linkit module is Drupal 10 / CKEditor 5 ready!

First, the Linkit module is ready! On 5 March 2023, 6.0.0-beta4 was released. I missed this and found the 6.1.0-rc1 release from 9 April 2023. I had to fix my composer.json requirement and then run composer update drupal/linkit.

diff --git a/composer.json b/composer.json
index d35fb20c..051b9037 100644
--- a/composer.json
+++ b/composer.json

- "drupal/linkit": "^5.0@beta",
+ "drupal/linkit": "^6.0@rc",

CodeSnippet — now in Drupal core 10.1.0!

Well, it turns out CodeSnippet is coming to Drupal core! Drupal core has supported CKEditor 5 code blocks since 9.3.x and a migration path from the CKEditor CodeTag module. But, the code block configuration was not exposed. Drupal 10.1.0 will now provide this functionality out of the box, mostly deprecating the CodeSnippet module! I say “mostly” because no code-highlighting libraries are provided (like Highlight.js or Prism.) There is also an issue currently RTBC’d, and I am sure to land, which provides the migration path from CodeSnippet to the CKEditor 5 code blocks plugin: https://www.drupal.org/project/drupal/issues/3356929.

There was just one problem. I don’t want to wait for 10.1.0 to be released in June. I want to ensure everything works fine now without upgrading Drupal to 10. Luckily, both of the patches for CKEditor 5 apply to 9.5! I could add the patches to my composer.json and have the code blocks with CodeSnippet migration.

diff --git a/composer.json b/composer.json
index d35fb20c..051b9037 100644
--- a/composer.json
+++ b/composer.json

"extra": {
+ "composer-exit-on-patch-failure": true,
+ "patchLevel": {
+ "drupal/core": "-p2"
+ },
"patches": {
+ "drupal/core": {
+ "CKE5 configure code block": "https://git.drupalcode.org/project/drupal/-/commit/0c59ee88d4e22da61d6eea02f232a7cb519824d9.patch",
+ "CKE5 codesnippet": "https://www.drupal.org/files/issues/2023-04-27/3356929-2.patch"
+ }
},
"drupal-scaffold": {
"locations": {

The only downside is that CodeSnippet provided Highlight.js integration out of the box. So now I need to add that for myself. I will write a filter plugin that checks for any code[class^="language-"] instances to attach the proper libraries. I'll share that once done!

Entity Embed, a time before Media Library

My site is old. The oldest timestamp I can find is 1305360870. That is May 14, 2011. I'm unsure if that's correct because this site has been migrated from WordPress to Drupal 7 and then to Drupal 8. Either way, I've collected some technical debt along the way. When I migrated from Drupal 7 to Drupal 8, I created a filter plugin to keep Drupal 7 media embed tokens working. I then started to use Entity Embed for placing media in my content. Then the Media Library module was released, and I stopped using Entity Embed. I never migrated anything because it just worked.

However, CKEditor 5 finally forced me to address this technical debt. Entity Embed isn’t Drupal 10 ready. It almost is (see #3309747 and #3272732.) Since I don’t use it, I didn’t want it to be a blocker. So I finally wrote a migration to update 60 blog posts away from Entity Embed.

Luckily Entity Embed and Media work nearly the same.

// entity_embed
<drupal-entity data-entity-uuid=" data-entity-type="" data-embed-button="" data-entity-embed-display="">

// media
<drupal-media data-entity-uuid=" data-entity-type="" data-view-mode="">

That’s an easy upgrade path!

  • Replace drupal-entity with drupal-media.
  • Drop data-embed-button
  • Replace data-entity-embed-display with data-view-mode

Here is the update hook I wrote to migrate the blog posts using Entity Embed in batches of 5 at a time.

/**
* @param array{'#finished': bool, ids: ?array<int, int[]>} $sandbox
*/
function mglaman_dev_update_9003(array &$sandbox): void {
$storage = \Drupal::entityTypeManager()->getStorage('node');
if (!isset($sandbox['ids'])) {
$query = $storage->getQuery()->accessCheck(FALSE)->condition('body.value', '%drupal-entity%', 'LIKE');
$ids = $query->execute();
$sandbox['ids'] = array_chunk($ids, 5);
}
$batch = array_shift($sandbox['ids']);
if (is_array($batch)) {
/** @var \Drupal\node\NodeInterface[] $nodes */
$nodes = $storage->loadMultiple($batch);
foreach ($nodes as $node) {
$body_field = $node->get('body')->first();
assert($body_field instanceof FieldItemInterface);
// @phpstan-ignore-next-line
$text = $body_field->value;
$search = [
'drupal-entity',
'data-embed-button="media_entity_embed"',
'data-entity-embed-display',
'view_mode:media.',
];
$replace = [
'drupal-media',
'',
'data-view-mode',
'',
];
$text = str_replace($search, $replace, $text);
// @phpstan-ignore-next-line
$body_field->value = $text;
$node->save();
}
}

$sandbox['#finished'] = count($sandbox['ids']) === 0;
}

Then I could uninstall Entity Embed and the Embed module from my site!

Lost functionality with Editor Advanced Link

I am using the Editor Advanced link module to allow setting custom data attributes on links within CKEditor. That approach is now broken. I don't think it'd be possible for that module to provide a fix. So I will write a custom CKEditor 5 plugin to add my custom link data attributes.

What else am I looking forward to with CKEditor 5?

Auto formatting was just committed for Drupal 10.1.0’s release! This allows typing ` and automatically getting code formatting. It's the Markdown-in-WYSIWYG formatting in Confluence, Notion, Slack, and other editors.

Add support for ckeditor5-autoformat

Problem/Motivation Drupal 10.0.0 will ship with CKEditor 5. The CKEditor contrib ecosystem is trending in the right direction, with 2 of the 4 modules with >50K sites using them already having stable releases, a third being ready for testing and the fourth well on its way. So … it seems the time is right to start making CKEditor 5 better in Drupal core than CKEditor 4 ever was. So, we propose this: This feature is the #1 that comes to mind. It’s not intrusive. It empowers power users. Try the demo.

Add support for ckeditor5-autoformat

--

--

Matt Glaman
Matt Glaman

Written by Matt Glaman

PHP software engineer, open source contributor, and speaker

No responses yet