PHPackages                             craftcms/ckeditor - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. craftcms/ckeditor

ActiveCraft-plugin[Utility &amp; Helpers](/categories/utility)

craftcms/ckeditor
=================

Edit rich text content in Craft CMS using CKEditor.

5.6.1(3w ago)47390.0k↓27.3%32[19 PRs](https://github.com/craftcms/ckeditor/pulls)20GPL-3.0-or-laterPHPPHP ^8.2CI passing

Since Dec 4Pushed 3w ago5 watchersCompare

[ Source](https://github.com/craftcms/ckeditor)[ Packagist](https://packagist.org/packages/craftcms/ckeditor)[ RSS](/packages/craftcms-ckeditor/feed)WikiDiscussions 5.x Synced 1w ago

READMEChangelog (10)Dependencies (24)Versions (120)Used By (20)

[![CKEditor icon](./src/icon.svg)](./src/icon.svg)

CKEditor
========

[](#ckeditor)

This plugin adds a “CKEditor” field type to Craft CMS, which provides a deeply-integrated rich text and longform content editor, powered by [CKEditor 5](https://ckeditor.com/).

[![A CKEditor field with example content filled in.](images/field.png)](images/field.png)

**Table of Contents:**

- [Requirements](#requirements)
- [Installation](#installation)
- [Configuration](#configuration)
    - [Registering Custom Styles](#registering-custom-styles)
    - [HTML Purifier Configs](#html-purifier-configs)
    - [Embedding Media](#embedding-media)
- [Longform Content with Nested Entries](#longform-content-with-nested-entries)
    - [Setup](#setup)
    - [Rendering Nested Entries on the Front End](#rendering-nested-entries-on-the-front-end)
- [Converting Redactor Fields](#converting-redactor-fields)
- [Converting Matrix Fields](#converting-matrix-fields)
- [Adding CKEditor Plugins](#adding-ckeditor-plugins)

Requirements
------------

[](#requirements)

This plugin requires Craft CMS 5.9.0 or later.

Installation
------------

[](#installation)

You can install this plugin from Craft’s in-app Plugin Store or with Composer.

**From the Plugin Store:**

Go to the Plugin Store in your project’s Control Panel and search for “CKEditor,” then click on the “Install” button in the sidebar.

**With Composer:**

Open your terminal and run the following commands:

```
# go to the project directory
cd /path/to/my-project

# tell Composer to load the plugin
composer require craftcms/ckeditor

# tell Craft to install the plugin
php craft plugin/install ckeditor
```

Configuration
-------------

[](#configuration)

Each CKEditor field allows you to choose the available toolbar buttons, as well as any custom [config options](https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html) and CSS styles that should be registered with the field.

Once you have selected which toolbar buttons should be available, additional settings may be applied via **Config options**. Options can be defined as static JSON, or a dynamically-evaluated JavaScript snippet; the latter is used as the body of an [immediately-invoked function expression](https://developer.mozilla.org/en-US/docs/Glossary/IIFE), and does not receive any arguments.

Note

Available options can be found in the [CKEditor's documentation](https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html). Craft will auto-complete config properties for most bundled CKEditor extensions.

### Examples

[](#examples)

#### Table Features

[](#table-features)

Suppose we wanted to give editors more control over the layout and appearance of in-line tables. Whenever you add the “Insert table” button to an editor, inline controls are exposed for *Table Row*, *Table Column*, and *Merge*. These can be supplemented with *Table Properties*, *Table Cell Properties*, and *Table Caption* buttons by adding them in the field’s **Config options** section:

```
{
  "table": {
    "contentToolbar": [
      "tableRow",
      "tableColumn",
      "mergeTableCells",
      "toggleTableCaption",
      "tableProperties",
      "tableCellProperties"
    ]
  }
}
```

Some of these additional buttons can be customized further. For example, to modify the colors available for a cell’s background (within the “[Table Cell Properties](https://ckeditor.com/docs/ckeditor5/latest/api/module_table_tableconfig-TableConfig.html#member-tableCellProperties)” balloon), you would provide an array compatible with the [`TableColorConfig` schema](https://ckeditor.com/docs/ckeditor5/latest/api/module_table_tableconfig-TableColorConfig.html) under `table.tableCellProperties.backgroundColors`.

#### Font Colors

[](#font-colors)

Multiple configuration concerns can coexist in one **Config options** object! You might have a `table` key at the top level to customize table controls (as we've done above), as well as a `fontColor` key that lets you control a pre-defined set of available font colors:

```
{
  "table": { /* ... */ },
  "fontColor": {
    "colors": [
      {
        "color": "#181818",
        "label": "Black"
      },
      {
        "color": "#d64036",
        "label": "Red"
      },
      {
        "color": "#24b559",
        "label": "Green"
      },
      {
        "color": "#4fa0b0",
        "label": "Blue"
      }
    ]
  }
}
```

#### External Links

[](#external-links)

You no longer have to use the `link` configuration concern to allow authors to choose whether links should open in new tabs. The manual decorator that added this option can now be made available simply by checking a relevant checkbox under “Advanced Link Fields”.

Tip

An automatic version of this feature is available natively, via the [`link.addTargetToExternalLinks`](https://ckeditor.com/docs/ckeditor5/latest/api/module_link_linkconfig-LinkConfig.html#member-addTargetToExternalLinks) option.

### Registering Custom Styles

[](#registering-custom-styles)

CKEditor’s [Styles](https://ckeditor.com/docs/ckeditor5/latest/features/style.html) plugin makes it easy to apply custom styles to your content via CSS classes.

You can define custom styles using the [`style`](https://ckeditor.com/docs/ckeditor5/latest/api/module_core_editor_editorconfig-EditorConfig.html#member-style) config option:

```
return {
  style: {
    definitions: [
      {
        name: 'Tip',
        element: 'p',
        classes: ['note']
      },
      {
        name: 'Warning',
        element: 'p',
        classes: ['note', 'note--warning']
      },
    ]
  }
}
```

You can then register custom CSS styles that should be applied within the editor when those styles are selected:

```
.ck.ck-content p.note {
    border-left: 4px solid #4a7cf6;
    padding-left: 1rem;
    color: #4a7cf6;
}

.ck.ck-content p.note--warning {
    border-left-color: #e5422b;
    color: #e5422b;
}
```

### HTML Purifier Configs

[](#html-purifier-configs)

CKEditor fields pass input through [HTML Purifier](http://htmlpurifier.org) to avoid saving malicious code to the database. This helps prevent XSS attacks and other vulnerabilities.

HTML Purifier is configured primarily via JSON files in your `config/htmlpurifier/` folder. New Craft projects (based on [`craftcms/craft`](https://github.com/craftcms/craft)) come with a single [`Default.json` config](https://github.com/craftcms/craft/blob/5.x/config/htmlpurifier/Default.json), which you can modify or supplement with your own configurations. Each CKEditor field with **Advanced** → **Purify HTML** enabled uses its selected HTML Purifier config. See the [HTML Purifier documentation](http://htmlpurifier.org/live/configdoc/plain.html) for a complete list of options!

This behavior is independent of CKEditor’s own HTML sanitization engine—the client-side editor automatically strips out any markup that isn’t supported by an enabled feature or plugin. If you [install additional plugins](#adding-ckeditor-plugins) or add [custom styles](#registering-custom-styles), you may need to relax associated HTML Purifier rules to ensure the markup is not removed by the server when saved.

Warning

*Disabling HTML Purifier entirely can expose your site to significant security risks, even if you don’t accept input from anonymous users.*
HTML Purifier provides a layer of security, while CKEditor is primarily concerned with hygiene.

The `HTMLPurifier_Config` object can be modified directly, using the `craft\ckeditor\Field::EVENT_MODIFY_PURIFIER_CONFIG` [event](https://craftcms.com/docs/5.x/extend/events.html).

```
use craft\htmlfield\events\ModifyPurifierConfigEvent;
use craft\ckeditor\Field;
use HTMLPurifier_Config;
use yii\base\Event;

Event::on(
    Field::class,
    Field::EVENT_MODIFY_PURIFIER_CONFIG,
    function(ModifyPurifierConfigEvent $event) {
        /** @var HTMLPurifier_Config $config */
        $config = $event->config;
        // ...
    }
);
```

CKEditor also makes its [general HTML support](https://ckeditor.com/docs/ckeditor5/latest/features/html/general-html-support.html) rules configurable, for situations where the source editor is used, or when authors expect some formatting from pasted content to be preserved:

```
return {
  // ...
  htmlSupport: {
    allow: [
      {
        name: 'abbr',
        attributes: ['title'],
        classes: false,
        styles: false
      }
    ],
    disallow: [
      // ...
    ].
  },
};
```

Adding a rule to the `disallow` array does not guarantee that matching HTML is stripped from the markup! CKEditor always ensures that the editor’s enabled features and plugins continue to work—for example, disabling all `style` attributes in an editor that supports lists will still permit `style="list-style-type: upper-roman;"`.

### Embedding Media

[](#embedding-media)

CKEditor 5 stores references to embedded media embeds using `oembed` tags. Craft CMS configures HTML Purifier to support these tags, however you will need to ensure that the `URI.SafeIframeRegexp` [HTML Purifier](#html-purifier-configs) setting is set to allow any domains you wish to embed content from.

```
{
  "URI.SafeIframeRegexp": "%^(https?:)?//(www\\.youtube\\.com/|youtu\\.be|player\\.vimeo\\.com/)%"
}
```

To automatically replace `oembed` tags with the media provider’s embed HTML, enable the field’s **Parse embeds** setting. Alternatively, see CKEditor’s [media embed documentation](https://ckeditor.com/docs/ckeditor5/latest/features/media-embed.html#displaying-embedded-media-on-your-website) for examples of how to show the embedded media on your front end.

Note

Be sure to cache your front-end output if you enable the “Parse embeds” setting (e.g. by using a `{% cache %}` tag). Otherwise, there will be a slight performance hit on each request while CKEditor fetches the embed HTML from the provider.

Longform Content with Nested Entries
------------------------------------

[](#longform-content-with-nested-entries)

CKEditor fields can be configured to manage nested entries, which will be displayed as [cards](https://craftcms.com/docs/5.x/system/elements.html#chips-cards) within your rich text content, and edited via [slideouts](https://craftcms.com/docs/5.x/system/control-panel.html#slideouts).

[![A CKEditor field with a nested entry’s slideout open.](images/nested-entry.png)](images/nested-entry.png)

Nested entries can be created anywhere within your content, and they can be moved, copied, and deleted, just like images and embedded media.

### Setup

[](#setup)

To configure a CKEditor field to manage nested entries, follow these steps:

1. Go to **Settings** → **Fields** and click on the field you wish to edit (or create a new one).
2. Drag the “+” menu button into the toolbar.
3. Select one or more entry types which should be available within the field.
4. And save.

Now the field is set up to manage nested entries! The next time you edit an element with that CKEditor field, the “+” button will be shown in the toolbar, and when you choose an entry type from its menu, a slideout will open where you can enter content for the nested entry.

An entry card will appear within the rich text content after you press **Save** within the slideout. The card can be moved via drag-n-drop or cut/paste from there.

Tip

You can choose which entry types should show as individual toolbar buttons and which should be nested under the “+” button. The ones selected to show as individual buttons will be displayed as an icon if the entry type is configured to have one and as text if no icon is specified. Use the 3-dots (actions) menu to toggle this behavior.

You can also copy/paste the card to duplicate the nested entry.

To delete the nested entry, simply select it and press the **Delete** key.

Note

Copy/pasting entry cards across separate CKEditor fields is supported, providing both fields allow the entry type of the copied nested entry.

### Rendering Nested Entries on the Front End

[](#rendering-nested-entries-on-the-front-end)

On the front end, nested entries will be rendered automatically via their [partial templates](https://craftcms.com/docs/5.x/system/elements.html#rendering-elements).

For each entry type selected by your CKEditor field, create a `_partials/entry/.twig` file within your `templates/` folder, and place your template code for the entry type within it.

An `entry` variable will be available to the template, which references the entry being rendered.

Tip

If your nested entries contain any relational fields, you can eager-load the related elements using [`eagerly()`](https://craftcms.com/docs/5.x/development/eager-loading.html#lazy-eager-loading).

```
{# Within an element partial... #}
{% for image in entry.myAssetsField.eagerly().all() %}
  {# ... #}
{% endfor %}
```

### Rendering Chunks

[](#rendering-chunks)

CKEditor field content is represented by an object that can be output as a string (`{{ entry.myCkeditorField }}`), or used like an array:

```
{% for chunk in entry.myCkeditorField %}

    {{ chunk }}

{% endfor %}
```

“Chunks” have two `type`s: `markup`, containing CKEditor HTML; and `entry`, representing a single nested entry. Adjacent `markup` chunks are collapsed into one another in cases where an intervening nested entry is disabled.

The example above treats both chunk types as strings. For entry chunks, this is equivalent to calling `{{ entry.render() }}`. If you would like to customize the data passed to the element partial, or use a different representation of the entry entirely, you have access to the nested entry via `chunk.entry`:

```
{% for chunk in entry.myCkeditorField %}
  {% if chunk.type == 'markup' %}

      {{ chunk }}

  {% else %}

      {# Call the render() method with custom params... #}
      {{ chunk.entry.render({
        isRss: true,
      }) }}

      {# ...or provide completely custom HTML for each supported entry type! #}
      {% switch chunk.entry.type.handle %}
        {% case 'gallery' %}
          {% set slides = chunk.entry.slides.eagerly().all() %}
          {% for slide in slides %}

              {# ... #}

        {% case 'document' %}
          {% set doc = chunk.entry.attachment.eagerly().one() %}

          Download {{ doc.filename }} ({{ doc.size|filesize }})
        {% default %}
          {# For anything else: #}
          {{ chunk.entry.render() }}
      {% endswitch %}

  {% endif %}
{% endfor %}
```

Converting Redactor Fields
--------------------------

[](#converting-redactor-fields)

You can use the `ckeditor/convert/redactor` command to convert any existing Redactor fields over to CKEditor.

The command will make changes to your project config. You should commit them, and run `craft up` on other environments for the changes to take effect.

```
php craft ckeditor/convert/redactor
```

Converting Matrix Fields
------------------------

[](#converting-matrix-fields)

You can use the `ckeditor/convert/matrix` command to convert a Matrix field over to CKEditor. Each of the Matrix field’s entry types will be assigned to the CKEditor field, and field values will be a mix of HTML content extracted from one of the nested entry types of your choosing (if desired) combined with nested entries.

```
php craft ckeditor/convert/matrix
```

The command will generate a new content migration, which will need to be run on other environments (via `craft up`) in order to update existing elements’ field values.

Adding CKEditor Plugins
-----------------------

[](#adding-ckeditor-plugins)

### First Party plugins

[](#first-party-plugins)

If you'd like to include any of the [first party packages](https://github.com/ckeditor/ckeditor5/tree/master/packages) from CKEditor not [already included](https://github.com/craftcms/ckeditor/blob/5.2.1/src/helpers/CkeditorConfig.php#L26), you can call `CkeditorConfig::registerFirstPartyPackage()` in the `init` function of a custom module.

```
use craft\ckeditor\helpers\CkeditorConfig;

class Site extends BaseModule
{
    public function init(): void
    {
        parent::init();

        // Register a package with toolbar items and multiple plugins
        CkeditorConfig::registerFirstPartyPackage(['SpecialCharacters', 'SpecialCharactersEssentials'], ['specialCharacters']);

        // Register a package with a single plugin.
        CkeditorConfig::registerFirstPartyPackage(['ImageResize']);
    }
}
```

### Custom plugins

[](#custom-plugins)

- If you’re creating a custom CKEditor plugin, use [CKEditor’s package generator](https://ckeditor.com/docs/ckeditor5/latest/framework/plugins/package-generator/using-package-generator.html) to scaffold it.

Tip

Check out CKEditor’s [Creating a basic plugin](https://ckeditor.com/docs/ckeditor5/latest/framework/tutorials/creating-simple-plugin-timestamp.html) tutorial for an in-depth look at how to create a custom CKEditor plugin.

Once the CKEditor package is in place in your Craft plugin, create an [asset bundle](https://craftcms.com/docs/4.x/extend/asset-bundles.html) which extends [`BaseCkeditorPackageAsset`](src/web/assets/BaseCkeditorPackageAsset.php). The asset bundle defines the package’s build directory, filename, namespace, a list of CKEditor plugin names provided by the package, and any toolbar items that should be made available via the plugin.

For example, here’s an asset bundle which defines a “Tokens” plugin:

```
