April 20, 2017
by Serhey Dolgushev
We at Contextual Code were keen to see eZ Platform in action, and decided that updating our own website / blog would provide a perfect opportunity to get deeper into it. During testing of the new admin interface we discovered that a completely new WYSIWYG editor is now being used, but there is currently no easy way to develop eZ XML custom tags. That was the main reason why we decided to spend some time investigating eZ Platform’s rich text field type, looking to find possible ways of extending it.
The basic flow for the RichText field type “lifecycle” is as follows:
Alloy Editor has replaced the eZ XML Editor, and it is used for editing the content of RichText type fields. It comes with some built-in features like object embeds, images, text styles and so on. It receives HTML code from eZ Publish, provides an interface for it’s editing and sends edited HTML code back to the eZ Publish REST API. It is possible to extend it with new functionality (new UI buttons) and in this blog post I will provide an example of doing that. It is also possible to modify the HTML content before it is sent to the eZ Publish REST API using editor content processors. This is useful because we do not really need to send the exact same HTML which is used internally by Alloy Editor to eZ Publish REST API - for example we can remove empty tags, and unnecessary attributes which are used only by the editor and which have no affect on displayed content.
When RichText field content is submitted to the eZ Publish REST API it goes through following steps:
All these steps are pretty straightforward and you can replace them with your own custom services.
Again the main reason for this process is to transform Alloy Editor HTML input to XML. For example a
div element with a
data-ezelement="ezembed" attribute is used by Alloy Edtior for embed objects, but it need to be converted to an
embed XML element (with all it’s attributes).
Each time a RichText field is edited in Alloy Editor, content stored in eZ Publish as XML need to be converted to HTML that Alloy can understand. The
ezpublish_rest.field_type_processor.ezrichtext service is responsible for it. It uses
ezpublish.fieldType.ezrichtext.converter.edit.xhtml5 service (https://github.com/ezsystems/ezpublish-kernel/blob/master/eZ/Bundle/EzPublishCoreBundle/FieldType/RichText/Converter/Html5Edit.php) for performing XSLT processing of XML to HTML. In order to customize it, you can use your own service instead of any services listed above or just use custom XSL template.
For generating final front-end HTML the
ezpublish.fieldType.ezrichtext.converter.output.xhtml5.core service is used (https://github.com/ezsystems/ezpublish-kernel/blob/master/eZ/Bundle/EzPublishCoreBundle/FieldType/RichText/Converter/Html5.php). It works in a very similar way to the
ezpublish.fieldType.ezrichtext.converter.edit.xhtml5 service. For customization purposes you can implement your own service, or just modify the
fieldtypes.ezrichtext.output_custom_xsl parameter, which should be an easier solution. Again, it should be clearly stated that these services/XSL templates are completely independent of the Alloy Editor and they are only used to transform content stored as XML in eZ Publish to the HTML which will be displayed on front-end.
Let’s have a look at a simple RichText editor extension, which allows for the insertion of a “mark” HTML tag (
<mark>...some text…</mark>) into RichText field contents.
First of all we need to create a new bundle. You can create your own or grab it from https://gitlab.com/contextualcode/RichTextEditorCustomTagsBundle. This bundle need to be enabled in your kernel, and it is important to enable it before the Platform UI Assets bundle to avoid problems with adding custom CSS later on. So your app/AppKernel.php file should look like:
Then we need to add a new “Marked” button to the Alloy Editor toolbar. In order to do it we need to:
divelement with a
data-ezelement=”marked”attribute in the editable area:
ez-richtext-editviewYUI module: https://gitlab.com/contextualcode/RichTextEditorCustomTagsBundle/blob/master/Resources/config/yui.yml#L50
ez-richtext-editviewYUI module (https://gitlab.com/contextualcode/RichTextEditorCustomTagsBundle/blob/master/Resources/config/yui.yml#L51)
After completing this steps, there should be a new “Marked” button in Alloy Editor:
And a new editable
div element with a
data-ezelement=”marked” attribute will be injected into the editable area after it’s clicked. Next we need to add some XSL rules to convert this div to a valid XML element when our input is submitted during the publishing process (submitting HTML to eZ Publish), and convert this XML element back to our div when the eZ Publish REST API returns it for future editing in the editor (editing stored XML).To do that we need to use the
fieldtypes.ezrichtext.edit_custom_xsl parameters accordingly. Needless to say,
fieldtypes.ezrichtext.input_custom_xsl contains our custom XSL template: https://gitlab.com/contextualcode/RichTextEditorCustomTagsBundle/blob/master/Resources/xsl/input_custom.xsl. But in the case of
fieldtypes.ezrichtext.edit_custom_xsl we need to copy the default file and add our custom template in it.
Now it will be possible to submit/edit a new “Marked” tag to eZ Publish for storage.
The final part is displaying our new tag on the front-end. To do that we need to change
fieldtypes.ezrichtext.output_custom_xsl parameter. It works in a similar way to
fieldtypes.ezrichtext.edit_custom_xsl, so we need to copy default file and add our custom template to it.
Now our new “Marked” tag will be displayed as a
<mark> HTML element on the front-end.
Extending the RichText field type is a bit harder than creating eZ Publish 4.x custom tags. But we really hope, that this blog post will help you with this task and it brought some shine on this topic. Please don’t hesitate to ask any questions in the comments, or correct us if we were wrong on some points.
This post covers simple example, when you are adding the root tag. Nested tags case is a bit more complicated and requires additional development. It will be covered in further posts. Stay tuned!