Contribute to this guideReport an issue

guideIntegrating Plugins with Advanced Content Filter

Advanced Content Filter was introduced in CKEditor 4.1.

CKEditor 4 consists of a number of editor features like commands, buttons, drop-down lists, or dialog windows. The role of plugins is to extend the set of available features. However, since the introduction of Advanced Content Filter, features, and the content they generate, are subject to filtering.

The introduction of Advanced Content Filter (ACF) have impacted the plugin development process and slightly changed the data processing model of CKEditor 4. With Advanced Content Filter plugins can take control over the content available in the editor and adaptively adjust the user interface when allowed content changes. Of all the feature properties the following are crucial for correct plugin integration with ACF:

  • allowedContent – determines the type of content that is allowed by the feature to enter the editor. In most cases this is the content that this feature generates.
  • requiredContent – defines a minimal set of content types that must be enabled to let the feature work.
  • contentForms – defines markup transformations for code consistency and correctness.

This guide is based on the Simple Plugin (Part 2) tutorial and explains all code adjustments that are required to make it compatible with Advanced Content Filter.

You can download the entire plugin folder used in the Simple Plugin (Part 2) tutorial to follow the changes introduced in this guide.

# Integrating with ACF to Introduce a New Content Type

If you start with the code created for Simple Plugin (Part 2) but without specifying the allowedContent or requiredContent options you may notice that the plugin is working, however, incoming abbreviations are filtered out as soon as possible. Try setting this HTML code in source mode and switch back to WYSIWYG view (you may need to do this twice) to see that the <abbr> tag is gone:

<p>What is <abbr title="Advanced Content Filter">ACF</abbr>?</p>

Why is it so? The editor does not know that since the Abbreviation feature is enabled (the button is added to the toolbar), it should accept the <abbr> tag as allowed content. Without allowedContent property specified, <abbr> tags will always be discarded and the button itself will not guarantee that the feature is actually useable for the end-user.

To add the <abbr> tag to the editor contents in a correct and automatic way, you need to extend the abbrDialog command definition when calling the CKEDITOR.dialogCommand constructor:

new CKEDITOR.dialogCommand( 'abbrDialog', {
    allowedContent: 'abbr'
} );

Try inserting the test HTML code again and check what happens when you switch between the source and WYSIWYG modes. This is what you will see:

<p>What is <abbr>ACF</abbr>?</p>

But where is the title attribute? It was removed by the editor. And the same would happen to the id attribute that is supported by the Advanced Settings tab.

In order to avoid this, you will have to specify which attributes are allowed, too. This was not done when setting allowedContent above, so will have to be fixed now:

new CKEDITOR.dialogCommand( 'abbrDialog', {
    allowedContent: 'abbr[title,id]'
} );

The title and id attributes will now be accepted for any <abbr> tag. Loading the Abbreviation button will automatically extend filtering rules to accept a new content type and let the new feature work as planned.

# What is an Editor Feature?

What does it mean that “a feature is enabled”? Why did we define the allowedContent property for the Abbreviation command definition and not for the button or the entire plugin?

The first thing to keep in mind is that one plugin can introduce multiple features. For example the basicstyles plugin adds numerous buttons and each one constitutes a single feature. So it looks like a button is more likely to be a feature.

However, in most cases a button just triggers a command — for example the Abbreviation button has a related abbrDialog command. This command may also be triggered by a keystroke (see keystrokes) or directly from code (by execCommand). Therefore, usually a command is the “root” of a feature. Please note that this is not always the case — for example the Format drop-down list does not have a related command, so the allowedContent property is defined directly for it.

The most typical way of enabling a feature is by adding its button to the toolbar. The editor handles features activated in this way automatically, and:

  1. It checks if a button has the allowedContent property (is a feature itself). If yes, then its allowed content rule is registered in the filter which is responsible for all main ACF functions.
  2. If a button is not a feature itself, but has a related command, then that command is registered as a feature.

If you need to register a feature manually from your plugin, you can use the addFeature method. It accepts an object implementing the feature interface. Refer to the API documentation for more details.

# Integrating with ACF to Activate Editor Features

Once the editor was configured to work with the new content type, it is a good moment to check what would happen if the Abbreviation plugin was enabled, but the allowedContent option deliberately omitted the <abbr> tag:

CKEDITOR.replace( 'editor1', {
    extraPlugins: 'abbr',
    allowedContent: 'p'    // Only paragraphs will be accepted.
});

You may notice that many features like formatting buttons, text alignment, and many others are gone. The content that they produce (<strong>, text-align, etc.) is simply invalid within this configuration environment.

This is not the case with the Abbreviation button which shows up, but in fact no longer makes any sense because the user configuration overwrites any rules automatically added by this feature.

By specifying the requiredContent property in the command definition we make sure that the Abbreviation button will adaptively adjust to filtering rules set by the user:

new CKEDITOR.dialogCommand( 'abbrDialog', {
    allowedContent: 'abbr[title,id]',
    requiredContent: 'abbr'
} );

The requiredContent: 'abbr' rule means that the Abbreviation button requires the <abbr> tag to be enabled to work. Otherwise, the feature will be disabled. This makes sense because inserting and managing abbreviations in an editor that discards this kind of content is pointless.

Let us consider another configuration setting that brings our plugin back to life by accepting <abbr> back again:

CKEDITOR.replace( 'editor1', {
    extraPlugins: 'abbr',
    allowedContent: 'p abbr'
});

The allowedContent: 'p abbr' rule means that all attributes will be striped out from the <abbr> tag, including title and id. The Abbreviation plugin, however, still provides a dialog window for editing both abbreviations (tag contents) and explanations (title) as well as the Advanced Settings tab for setting the id. It turns out that the Explanation field and the second tab are no longer necessary since the title and id attributes will be discarded.

With Advanced Content Filter we can specify which dialog window fields and tabs are enabled and which are not, depending on filtering rules set in the configuration. This can be done by modifying the Explanation field in the dialog window definition (plugins/abbr/dialogs/abbr.js):

elements: [
    ...
    {
        type: 'text',
        id: 'title',
        label: 'Explanation',
        requiredContent: 'abbr[title]',	// Title must be allowed to enable this field.
        ...
    }
    ...
]

The dialog window also contains the Advanced Settings tab that can be used for setting the id attribute. However, our current configuration (allowedContent: 'p abbr') means: “only paragraphs and abbreviations are allowed, not attributes”. The Abbreviation plugin should take this fact into account and disable the Advanced Settings tab unless the id attribute is allowed:

contents: [
    ...
    {
        id: 'tab-adv',
        label: 'Advanced Settings',
        requiredContent: 'abbr[id]',	// ID must be allowed to enable this field.
        elements: [
            ...
        ]
    }
    ...
]

To sum it up, let us see how the Abbreviation dialog window changes with different config.allowedContent settings:

allowedContent = 'p abbr' allowedContent = 'p abbr[id]' allowedContent = 'p abbr[title,id]'

# Integrating with ACF for Content Transformations

Advanced Content Filter also introduces content transformations that help clean up HTML code and make it consistent. This functionality can be used automatically in the Abbreviation feature to convert the invalid <acronym> tag into an <abbr>. In order to achieve this, we will need to define the contentForms property that determines which tag is correct and accepted by the editor with the highest priority:

new CKEDITOR.dialogCommand( 'abbrDialog', {
    allowedContent: 'abbr[title,id]',
    requiredContent: 'abbr',
    contentForms: [
        'abbr',
        'acronym'
    ]
} );

This configuration causes the following code transformation:

// HTML before
<p>What is <acronym title="Advanced Content Filter">ACF</acronym>?</p>

// HTML after
<p>What is <abbr title="Advanced Content Filter">ACF</abbr>?</p>

The editor will automatically convert <acronym> tags into <abbr> tags when pasting content and editing source code.

Read more about contentForms in CKEditor 4 JavaScript API.

You can also download the entire modified plugin folder inluding the icon and the fully commented source code.

# Abbreviation Plugin Demo

See the working “Abbreviation (Custom Plugin with Dialog, Context Menu and ACF Support)” sample that shows the final version of the Abbreviation plugin integrated with an editor instance.

# Further Reading

Refer to the following resources for more information about creating CKEditor 4 plugins:

Refer to the following resources for more information about content filtering: