WYSIWYG Extension Points
This topic goes over the extension points for Magento entities. You can use these connection points to integrate Magento entities into third-party WYSIWYG editors.
See Add a third-party editor for instructions on how to add a third-party WYSIWYG editor to Magento.
Entity Integration
The specific steps needed to create an editor plugin vary between different editors, but for most editors, it usually involves creating an icon or button for the plugin and executing JavaScript code when clicked.
Use the following steps as a starting point for integrating entities into your custom WYSIWYG editor.
Step 1. Create plugin directory structure
Create the appropriate plugin directory structure for the entity inside your editor’s directory.
For example, both TinyMCE3 and CKEditor editors both have a plugins
directory that holds all available plugins.
This folder should be inside your module’s /view/<area>
directory so it will be published to the pub/static
directory.
Step 2. Copy editor icon
Copy the appropriate icon file into your plugin’s specific icon or image directory:
Variable: lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentovariable/img/icon.png
Widget: lib/web/mage/adminhtml/wysiwyg/tiny_mce/plugins/magentowidget/img/icon.png
Media Gallery: No icon needed.
For example, in a CKEditor4 plugin, these icons would be found copied to the following locations:
app/code/CKEditor/CKEditor4/view/base/web/js/ckeditor4/plugins/variable/icons/variable.png
app/code/CKEditor/CKEditor4/view/base/web/js/ckeditor4/plugins/widget/icons/widget.png
Step 3. Implement plugin functionality
Variable Entity
Use the MagentovariablePlugin
object to implement the plugin functionality for the variable entity.
Example: editor_plugin.js
for magentovariable
in the TinyMCE3 module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @param {tinymce.Editor} ed - Editor instance that the plugin is initialized in.
* @param {String} url - Absolute URL to where the plugin is located.
*/
init: function (ed, url) {
ed.addCommand('mceMagentovariable', function () {
var pluginSettings = ed.settings.magentoPluginsOptions.get('magentovariable');
MagentovariablePlugin.setEditor(ed);
MagentovariablePlugin.loadChooser(pluginSettings.url, ed.settings.elements);
});
// Register Widget plugin button
ed.addButton('magentovariable', {
title: 'magentovariable.insert_variable',
cmd: 'mceMagentovariable',
image: url + '/img/icon.gif'
});
},
Example: plugin.js
for variable
plugin for CKEditor4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
/* global CKEDITOR, MagentovariablePlugin, varienGlobalEvents, Base64 */
/* eslint-disable strict */
CKEDITOR.plugins.add('variable', {
icons: 'variable',
/**
* Initialize editor plugin.
*/
init: function (editor) {
/**
* Add new command to open variables selector slideout.
*/
editor.addCommand('openVariablesSlideout', {
exec: function (editor) {
require([
'CKEditor_CKEditor4/js/ckeditor4/ckeditor'
], function (ckeditor) {
//we need this code to transfer config
var pluginSettings = ckeditor.settings.magentoPluginsOptions.get('variable');
MagentovariablePlugin.setEditor(editor);
MagentovariablePlugin.loadChooser(pluginSettings.url, ckeditor.settings.elements);
});
}
});
/**
* Add button to the editor toolbar.
*/
editor.ui.addButton('variable', {
label: jQuery.mage.__('Insert Variable'),
command: 'openVariablesSlideout',
toolbar: 'insert'
});
},
});
To integrate the default Magento UI for variable, you must have access to the following data:
- backend URL to load the
variable_modal
Example: method that returns this url
1
2
3
4
public function getVariablesWysiwygActionUrl()
{
return $this->_url->getUrl('mui/index/render', ['namespace' => 'variables_modal']);
}
- htmlId of the WYSIWYG editor.
For CKEditor4, you can get this by calling
editor.element.getId()
.
Widget Entity
Use the global widgetTools
object to implement the plugin functionality for the widget entity.
Example: editor_plugin.js
for magentowidget
in the TinyMCE3 module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* @param {tinymceDeprecated.Editor} ed - Editor instance that the plugin is initialized in.
* @param {String} url - Absolute URL to where the plugin is located.
*/
init: function (ed, url) {
ed.addCommand('mceMagentowidget', function () {
widgetTools.openDialog(
ed.settings['magentowidget_url'] + 'widget_target_id/' + ed.getElement().id + '/'
);
});
// Register Widget plugin button
ed.addButton('magentowidget', {
title: 'magentowidget.insert_widget',
cmd: 'mceMagentowidget',
image: url + '/img/icon.gif'
});
// Add a node change handler, selects the button in the UI when a image is selected
ed.onNodeChange.add(function (edi, cm, n) {
var widgetCode;
widgetTools.setEditMode(false);
cm.setActive('magentowidget', false);
if (n.id && n.nodeName == 'IMG') { //eslint-disable-line eqeqeq
widgetCode = Base64.idDecode(n.id);
if (widgetCode.indexOf('{{widget') !== -1) {
widgetTools.setEditMode(true);
cm.setActive('magentowidget', true);
}
}
});
// Add a widget placeholder image double click callback
ed.onDblClick.add(function (edi, e) {
var n = e.target,
widgetCode;
if (n.id && n.nodeName == 'IMG') { //eslint-disable-line eqeqeq
widgetCode = Base64.idDecode(n.id);
if (widgetCode.indexOf('{{widget') !== -1) {
widgetTools.setEditMode(true);
edi.execCommand('mceMagentowidget');
}
}
});
},
Example: plugin.js
for widget
plugin for CKEditor4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
/* global CKEDITOR, MagentovariablePlugin, varienGlobalEvents, Base64 */
/* eslint-disable strict */
CKEDITOR.plugins.add('widget', {
icons: 'widget',
/**
* Initialize editor plugin.
*
* @param {tinymce.editor} editor - Editor instance that the plugin is initialized in.
* @param {String} url - Absolute URL to where the plugin is located.
*/
init: function (editor) {
var self = this;
require([
'Magento_Variable/js/config-directive-generator',
'Magento_Variable/js/custom-directive-generator'
], function (configDirectiveGenerator, customDirectiveGenerator) {
self.configDirectiveGenerator = configDirectiveGenerator;
self.customDirectiveGenerator = customDirectiveGenerator;
});
/**
* Add new command to open variables selector slideout.
*/
editor.addCommand('mceMagentowidget', {
exec: function (editor) {
require([
'CKEditor_CKEditor4/js/ckeditor4/ckeditor'
], function (ckeditor) {
widgetTools.openDialog(
ckeditor.settings['widget_window_url'] + 'widget_target_id/' + editor.element.getId()+ '/'
);
});
}
});
/**
* Add button to the editor toolbar.
*/
editor.ui.addButton('widget', {
label: jQuery.mage.__('Insert Widget'),
command: 'mceMagentowidget',
toolbar: 'insert'
});
}
});
To integrate the default Magento UI for widgets, you need access to the following data:
- The backend
widget_window_url
(\Magento\Widget\Model\Widget\Config::getWidgetWindowUrl
) - htmlId of the WYSIWYG editor.
For CKEditor4, you can get this by calling
editor.element.getId()
.
Media Gallery Entity
Use the global MediabrowserUtility
object to implement or override image browsing functionality in the editor.
Example: tinymce3Adapter.js
in the TinyMCE3 module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* @param {Object} o
*/
openFileBrowser: function (o) {
var typeTitle = this.translate('Select Images'),
storeId = this.config['store_id'] !== null ? this.config['store_id'] : 0,
frameDialog = jQuery(o.win.frameElement).parents('[role="dialog"]'),
wUrl = this.config['files_browser_window_url'] +
'target_element_id/' + this.getId() + '/' +
'store/' + storeId + '/';
this.mediaBrowserOpener = o.win;
this.mediaBrowserTargetElementId = o.field;
if (typeof o.type != 'undefined' && o.type != '') { //eslint-disable-line eqeqeq
wUrl = wUrl + 'type/' + o.type + '/';
}
frameDialog.hide();
jQuery('#mceModalBlocker').hide();
require(['mage/adminhtml/browser'], function () {
MediabrowserUtility.openDialog(wUrl, false, false, typeTitle, {
/**
* Closed.
*/
closed: function () {
frameDialog.show();
jQuery('#mceModalBlocker').show();
}
});
});
},
Step 4. Register plugin
Use the editor specific command or steps needed to register your plugin with the editor.
For example, TinyMCE3 has a PluginManager.add()
method while CKEditor requires you to modify a configuration file.
Configuration
Configuration for the WYSIWYG editor and available entities is implemented in the following class:
Magento\Cms\Model\Wysiwyg\Config
This class has a getConfig()
method that returns the all available configurations as an array.
The class that aggregates the data in the array is the configuration provider class:
Magento\Cms\Model\Wysiwyg\CompositeConfigProvider
In your module’s di.xml
file, you can define a virtual type of this class to substitute or modify the following configuration providers:
Argument name | Description |
---|---|
variablePluginConfigProvider |
Provider for variable plugin configuration |
widgetPluginConfigProvider |
Provider for widget plugin configuration |
galleryConfigProvider |
Provider for the media gallery configuration |
wysiwygConfigPostProcessor |
Provider for WYSIWYG editor configuration |
If your implementation does not require any modifications to the configuration, you can use the default implementation:
Magento\Cms\Model\WysiwygDefaultConfig
Example di.xml file entry for TinyMCE3 editor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<type name="Magento\Cms\Model\Wysiwyg\CompositeConfigProvider">
<arguments>
<argument name="wysiwygConfigPostProcessor" xsi:type="array">
<item name="Magento_Tinymce3/tinymce3Adapter" xsi:type="string">Magento\Tinymce3\Model\Config\Wysiwyg\Config</item>
</argument>
<argument name="variablePluginConfigProvider" xsi:type="array">
<item name="Magento_Tinymce3/tinymce3Adapter" xsi:type="string">Magento\Tinymce3\Model\Config\Variable\Config</item>
</argument>
<argument name="widgetPluginConfigProvider" xsi:type="array">
<item name="Magento_Tinymce3/tinymce3Adapter" xsi:type="string">Magento\Tinymce3\Model\Config\Widget\Config</item>
</argument>
<argument name="galleryConfigProvider" xsi:type="array">
<item name="Magento_Tinymce3/tinymce3Adapter" xsi:type="string">Magento\Cms\Model\WysiwygDefaultConfig</item>
</argument>
</arguments>
</type>
Configuration providers
Configuration providers are classes with a getConfig()
method that returns the configuration for a specific entity.
These classes are implementations of the following interface:
Magento\Framework\Data\Wysiwyg\ConfigProviderInterface
The name
attribute for the configuration provider in the di.xml
entry must match the editor’s registered option value.
In the example provided, this value is Magento_Tinymce3/tinymce3Adapter
defined in:
Magento\Tinymce3\Model\Config\Source\Wysiwyg\Editor