(deprecated) CKEditor 4 API (Drupal 8 and 9)
Documentation for the deprecated CKEditor 4 API in Drupal 8 and 9. For Drupal 10, refer to the CKEditor 5 API documentation.
The CKEditor 5 API is new in Drupal 9.4.
Note this is only covering the CKEditor Drupal 9 module API, not the CKEditor JavaScript library API — for that, see https://ckeditor.com/docs/ckeditor5/latest/index.html.
For high-level information on what this module does, see the Text Editor module documentation.
API features
Ordered by most to least frequently used APIs:
CKEditor 5 CSS
CKEditor 5 does not run in an iframe, unlike CKEditor 4. This means that any CSS file loaded on a page can in theory affect a CKEditor 5 instance. No worries though: CKEditor 5 itself has plenty of CSS resets to prevent unintentional overrides.
For intentional overrides, for example to make the content edited with CKEditor 5 match the styling of your front-end theme, the
ckeditor5-stylesheetsproperty can be specified inTHEMENAME.info.yml. See the change record for details.CKEditor 5 Plugin plugins
Add more functionality to CKEditor!
\Drupal\ckeditor5\Plugin\CKEditor5PluginInterface: Drupal plugins that correspond 1:1 to CKEditor 5 plugins, to make Drupal aware of the available CKEditor plugins. Hence the — at first sight — confusing name: CKEditor 5 Plugin plugins, but it actually makes sense!For CKEditor 4, it was required to create a CKEditor 4 plugin definition: a PHP file. No longer with CKEditor 5. With CKEditor 5, all you need is a
MODULENAME.ckeditor5.ymlfile, which contains CKEditor 5 plugin definitions. It can be as simple as:
ckeditor5_code: ckeditor5: plugins: [basicStyles.Code] drupal: label: Code library: core/ckeditor5.basic admin_library: ckeditor5/admin.basic toolbar_items: code: label: Code elements: - <code>You can distinguish two clear sections:
ckeditor5(which contains the CKEditor 5 JS plugin-specific aspects) anddrupal(which contains the CKEditor 5 Drupal plugin-specific aspects).See "CKEditor 5 architecture" for more details.
A more complex example would be:
ckeditor5_imageCaption: ckeditor5: plugins: - image.ImageCaption config: image: toolbar: [toggleImageCaption] drupal: label: Image caption elements: - <img data-caption> conditions: toolbarItem: uploadImage filter: filter_captionHere, we can see more nuance for both aspects:
- a
configkey-value pair in theckeditor5key, to pass on configuration to the CKEditor 5 JS plugin a
conditionskey-value pair in thedrupalkey, to indicate to Drupal which conditions have to be met for this CKEditor 5 plugin to be loaded. Also note the absence of a toolbar item! That's because this CKEditor 5 plugin provides a UX that enhances the image functionality in CKEditor 5 whenever thefilter_captionfilter is enabled (and theuploadImagetoolbar item is enabled). This removes the need for complex configuration forms, and allows the CKEditor 5 plugins to detail when exactly they should be enabled.If the currently supported conditions are inadequate, please create a new Drupal core issue against the
ckeditor5.modulecomponent and tag itContributed project blocker.
- a
Debugging
Drupal 9 includes a customized, optimized build of CKEditor. See "CKEditor 5 development" for how to swap this for a build that is optimized for development and debugging.
Plugin definition updates: post-update hook
When plugin definitions are updated, it's important to understand when which aspects of plugin definitions are evaluated:
- Changes to
conditionsautomatically get re-evaluated, because these are evaluated at runtime. For example, a CKEditor 5 plugin that was previously explicitly enabled thanks to a toolbar item that has been enabled will not show up anymore if the plugin definition was modified to also have afiltercondition and that filter is not enabled. - Changes to
elementsdo not get automatically synced tofilter_html's allowed HTML tags, because that requires changes to the correspondingFilterFormatconfig entity's data. - Generally speaking all plugin definition changes are applied immediately, with the sole exception of
elements, because that requires those same elements to also be allowed byfilter_html(if enabled), and that cannot be automatically updated.
You can ensure that elements changes are propagated automatically to each text format/editor that uses this CKEditor 5 plugin: it's possible to update filter_html automatically. This can be done through a MODULENAME.post_update.php file that looks like this:
<?php
use Drupal\editor\Entity\Editor;
/**
* Your description here.
*/
function MYMODULE_post_update_DESCRIPTION() {
_ckeditor5_plugin_supports_more_elements_append_to_filter_html_settings('mymodule_myplugin', '<span data-test>');
}
/**
* Expands filter_html allowed tags for CKE5 plugin that supports more HTML.
*
* @param string $cke5_plugin_id
* The CKEditor 5 plugin ID which supports more HTML after an update.
* @param string $allowed_html_to_append
* The string to append to `filter_html`'s `allowed_html` setting.
*/
function _ckeditor5_plugin_supports_more_elements_append_to_filter_html_settings(string $cke5_plugin_id, string $allowed_html_to_append) {
$cke5_plugin_manager = \Drupal::service('plugin.manager.ckeditor5.plugin');
assert($cke5_plugin_manager instanceof \Drupal\ckeditor5\Plugin\CKEditor5PluginManagerInterface);
// 1. Determine which text editors use the updated CKEditor 5 plugin.
$affected_editors = [];
foreach (Editor::loadMultiple() as $editor) {
// Text editors not using CKEditor 5 cannot be affected.
if ($editor->getEditor() !== 'ckeditor5') {
continue;
}
// Ask the plugin manager which CKEditor 5 plugins are enabled; this works
// for every plugin, no matter if they have toolbar items or not, conditions
// or not, et cetera.
$enabled_cke5_plugin_ids = array_keys($cke5_plugin_manager->getEnabledDefinitions($editor));
if (in_array($cke5_plugin_id, $enabled_cke5_plugin_ids, TRUE)) {
$affected_editors[] = $editor;
}
}
// 2. Update the corresponding text formats' `filter_html` configuration, if
// they are using that filter plugin.
foreach ($affected_editors as $editor) {
$format = $editor->getFilterFormat();
// Text formats not using `filter_html` filter do not need to be updated.
if (!$format->filters('filter_html')->status) {
continue;
}
// Append to "Allowed HTML tags" setting.
$filter_html_config = $format->filters('filter_html')->getConfiguration();
$filter_html_config['settings']['allowed_html'] .= ' ' . trim($allowed_html_to_append);
$format->setFilterConfig('filter_html', $filter_html_config);
// Save updated text format.
$format->save();
}
}The _ckeditor5_plugin_supports_more_elements_append_to_filter_html_settings() helper does all the work for you. All you should need to do is update MYMODULE_post_update_DESCRIPTION() to match your module name, plugin ID, etc.