2019-11-18 05:58:33 +01:00
---
2014-12-08 21:03:02 +01:00
title: Rich-text editing (WYSIWYG)
2019-11-18 05:58:33 +01:00
summary: Silverstripe CMS's use and configuration of TinyMCE html editor.
icon: file-code
---
2012-02-14 00:49:34 +01:00
2014-12-08 21:03:02 +01:00
# Rich-text editing (WYSIWYG)
2012-02-14 00:49:34 +01:00
2021-06-30 11:48:52 +02:00
Editing and formatting content is the bread and butter of every content management system, which is why Silverstripe CMS
2014-10-22 12:47:56 +02:00
has a tight integration with our preferred editor library, [TinyMCE ](http://tinymce.com ).
2012-02-14 00:49:34 +01:00
2014-10-22 12:47:56 +02:00
On top of the base functionality, we use our own insertion dialogs to ensure you can effectively select and upload
2016-01-14 11:59:53 +01:00
files. In addition to the markup managed by TinyMCE, we use [shortcodes ](/developer_guides/extending/shortcodes ) to store
2014-10-22 12:47:56 +02:00
information about inserted images or media elements.
2012-02-14 00:49:34 +01:00
2017-07-03 03:22:12 +02:00
The framework comes with a [HTMLEditorField ](api:SilverStripe\Forms\HTMLEditor\HTMLEditorField ) form field class which encapsulates most of the required
functionality. It is usually added through the [DataObject::getCMSFields() ](api:SilverStripe\ORM\DataObject::getCMSFields( )) method:
2012-02-14 00:49:34 +01:00
2021-10-07 10:13:26 +02:00
**app/src/MyObject.php**
2014-10-22 12:47:56 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\ORM\DataObject;
2017-08-07 05:11:17 +02:00
2017-10-27 04:38:27 +02:00
class MyObject extends DataObject
{
private static $db = [
'Content' => 'HTMLText'
];
public function getCMSFields()
2017-08-07 05:11:17 +02:00
{
2017-10-27 04:38:27 +02:00
return new FieldList(
new HTMLEditorField('Content')
);
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
2012-02-14 00:49:34 +01:00
2015-06-09 02:01:21 +02:00
### Specify which configuration to use
2017-07-03 03:22:12 +02:00
By default, a config named 'cms' is used in any new [HTMLEditorField ](api:SilverStripe\Forms\HTMLEditor\HTMLEditorField ).
2015-06-09 02:01:21 +02:00
2017-07-03 03:22:12 +02:00
If you have created your own [HtmlEditorConfig ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig ) and would like to use it,
you can call `HtmlEditorConfig::set_active('myConfig')` and all subsequently created [HTMLEditorField ](api:SilverStripe\Forms\HTMLEditor\HTMLEditorField )
2015-06-09 02:01:21 +02:00
will use the configuration with the name 'myConfig'.
2017-07-03 03:22:12 +02:00
You can also specify which [HtmlEditorConfig ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig ) to use on a per field basis via the construct argument.
This is particularly useful if you need different configurations for multiple [HTMLEditorField ](api:SilverStripe\Forms\HTMLEditor\HTMLEditorField ) on the same page or form.
2015-06-09 02:01:21 +02:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\ORM\DataObject;
class MyObject extends DataObject
{
private static $db = [
'Content' => 'HTMLText',
'OtherContent' => 'HTMLText'
];
public function getCMSFields()
2017-08-07 05:11:17 +02:00
{
2017-10-27 04:38:27 +02:00
return new FieldList([
new HTMLEditorField('Content'),
new HTMLEditorField('OtherContent', 'Other content', $this->OtherContent, 'myConfig')
]);
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 05:35:09 +02:00
2017-08-03 02:51:32 +02:00
```
2015-06-09 02:01:21 +02:00
In the above example, the 'Content' field will use the default 'cms' config while 'OtherContent' will be using 'myConfig'.
2012-02-14 00:49:34 +01:00
## Configuration
2014-10-22 12:47:56 +02:00
To keep the JavaScript editor configuration manageable and extensible, we've wrapped it in a PHP class called
2017-07-03 03:22:12 +02:00
[HtmlEditorConfig ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig ). The class comes with its own defaults, which are extended through the [Configuration API ](../../configuration )
2013-03-27 12:06:57 +01:00
in the framework (and the `cms` module in case you've got that installed).
2014-10-22 12:47:56 +02:00
2017-07-03 03:22:12 +02:00
There can be multiple configs, which should always be created / accessed using [HtmlEditorConfig::get() ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig::get( )). You can
2014-10-22 12:47:56 +02:00
then set the currently active config using `set_active()` .
2019-11-18 05:58:33 +01:00
[info]
[/info]
2012-02-14 00:49:34 +01:00
2019-11-18 05:58:33 +01:00
[notice]
2014-10-22 12:47:56 +02:00
Currently the order in which the `_config.php` files are executed depends on the module directory names. Execution
order is alphabetical, so if you set a TinyMCE option in the `aardvark/_config.php` , this will be overridden in
2017-10-06 17:00:32 +02:00
`vendor/silverstripe/framework/admin/_config.php` and your modification will disappear.
2019-11-18 05:58:33 +01:00
[/notice]
2013-01-23 21:53:33 +01:00
2014-10-22 12:47:56 +02:00
## Adding and removing capabilities
2013-01-23 21:53:33 +01:00
In its simplest form, the configuration of the editor includes adding and removing buttons and plugins.
2017-07-03 03:22:12 +02:00
You can add plugins to the editor using the Framework's [HtmlEditorConfig::enablePlugins() ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig::enablePlugins( )) method. This will
2013-01-23 21:53:33 +01:00
transparently generate the relevant underlying TinyMCE code.
2012-02-14 00:49:34 +01:00
2018-06-25 00:39:53 +02:00
**app/_config.php**
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\Forms\HTMLEditor\HtmlEditorConfig;
2017-10-26 02:22:02 +02:00
2017-10-27 04:38:27 +02:00
HtmlEditorConfig::get('cms')->enablePlugins('media');
2017-08-03 02:51:32 +02:00
```
2012-02-14 00:49:34 +01:00
2019-11-18 05:58:33 +01:00
[notice]
2014-10-22 12:47:56 +02:00
This utilities the TinyMCE's `PluginManager::load` function under the hood (check the
[TinyMCE documentation on plugin loading ](http://www.tinymce.com/wiki.php/API3:method.tinymce.AddOnManager.load ) for
details).
2019-11-18 05:58:33 +01:00
[/notice]
2013-01-23 21:53:33 +01:00
Plugins and advanced themes can provide additional buttons that can be added (or removed) through the
configuration. Here is an example of adding a `ssmacron` button after the `charmap` button:
2018-06-25 00:39:53 +02:00
**app/_config.php**
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
HtmlEditorConfig::get('cms')->insertButtonsAfter('charmap', 'ssmacron');
2017-08-03 02:51:32 +02:00
```
2013-01-23 21:53:33 +01:00
Buttons can also be removed:
2012-02-14 00:49:34 +01:00
2018-06-25 00:39:53 +02:00
**app/_config.php**
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
HtmlEditorConfig::get('cms')->removeButtons('tablecontrols', 'blockquote', 'hr');
2017-08-03 02:51:32 +02:00
```
2012-02-14 00:49:34 +01:00
2019-11-18 05:58:33 +01:00
[notice]
2017-07-03 03:22:12 +02:00
Internally [HtmlEditorConfig ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig ) uses the TinyMCE's `theme_advanced_buttons` option to configure these. See the
2014-10-22 12:47:56 +02:00
[TinyMCE documentation of this option ](http://www.tinymce.com/wiki.php/Configuration:theme_advanced_buttons_1_n )
2013-01-23 21:53:33 +01:00
for more details.
2019-11-18 05:58:33 +01:00
[/notice]
2013-01-23 21:53:33 +01:00
### Setting options
TinyMCE behaviour can be affected through its [configuration options ](http://www.tinymce.com/wiki.php/Configuration ).
These options will be passed straight to the editor.
One example of the usage of this capability is to redefine the TinyMCE's [whitelist of HTML
tags](http://www.tinymce.com/wiki.php/Configuration:extended_valid_elements) - the tags that will not be stripped
from the HTML source by the editor.
2018-06-25 00:39:53 +02:00
**app/_config.php**
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
// Add start and type attributes for < ol > , add < object > and < embed > with all attributes.
HtmlEditorConfig::get('cms')->setOption(
'extended_valid_elements',
'img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|usemap],' .
'iframe[src|name|width|height|title|align|allowfullscreen|frameborder|marginwidth|marginheight|scrolling],' .
'object[classid|codebase|width|height|data|type],' .
'embed[src|type|pluginspage|width|height|autoplay],' .
'param[name|value],' .
'map[class|name|id],' .
'area[shape|coords|href|target|alt],' .
'ol[start|type]'
);
2017-08-03 02:51:32 +02:00
```
2013-01-23 21:53:33 +01:00
2019-11-18 05:58:33 +01:00
[notice]
2014-10-22 12:47:56 +02:00
The default setting for the CMS's `extended_valid_elements` we are overriding here can be found in
2019-04-02 00:49:12 +02:00
`vendor/silverstripe/admin/_config.php` .
2019-11-18 05:58:33 +01:00
[/notice]
2013-01-23 21:53:33 +01:00
2014-10-22 12:47:56 +02:00
## Writing custom plugins
2013-01-23 21:53:33 +01:00
2016-05-27 03:08:22 +02:00
It is also possible to add custom plugins to TinyMCE, for example toolbar buttons.
2017-07-03 03:22:12 +02:00
You can enable them through [HtmlEditorConfig::enablePlugins() ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig::enablePlugins( )):
2013-01-23 21:53:33 +01:00
2018-06-25 00:39:53 +02:00
**app/_config.php**
2017-08-03 02:51:32 +02:00
```php
2018-06-25 00:39:53 +02:00
HtmlEditorConfig::get('cms')->enablePlugins(['myplugin' => '../../../app/javascript/myplugin/editor_plugin.js']);
2017-08-03 02:51:32 +02:00
```
2013-01-23 21:53:33 +01:00
2016-05-27 03:08:22 +02:00
You can learn how to [create a plugin ](http://www.tinymce.com/wiki.php/Creating_a_plugin ) from the TinyMCE documentation.
2013-01-23 21:53:33 +01:00
2014-12-08 21:03:02 +01:00
## Image and media insertion
2012-06-08 18:30:31 +02:00
2017-07-03 03:22:12 +02:00
The [HtmlEditorField ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorField ) API also handles inserting images and media files into the managed HTML content. It can be
used both for referencing files on the webserver filesystem (through the [File ](api:SilverStripe\Assets\File ) and [Image ](api:SilverStripe\Assets\Image ) APIs), as well
2014-10-22 12:47:56 +02:00
as hotlinking files from the web.
2013-04-16 14:01:04 +02:00
2016-01-14 11:59:53 +01:00
We use [shortcodes ](/developer_guides/extending/shortcodes ) to store information about inserted images or media elements. The
2017-07-03 03:22:12 +02:00
[ShortcodeParser ](api:SilverStripe\View\Parsers\ShortcodeParser ) API post-processes the HTML content on rendering, and replaces the shortcodes accordingly. It also
2014-10-22 12:47:56 +02:00
takes care of care of placing the shortcode replacements relative to its surrounding markup (e.g. left/right alignment).
2012-06-08 18:30:31 +02:00
2019-10-22 00:50:28 +02:00
### Image size pre-sets
2021-06-30 11:48:52 +02:00
Silverstripe CMS will suggest pre-set image size in the HTMLEditor. Editors can quickly switch between the pre-set size when interacting with images in the HTMLEditorField.
2019-10-22 00:50:28 +02:00
The default values are "Best fit" (600 pixels width) and original size. Developers can customise the pre-set sizes by altering their HTMLEditorConfig.
You can alter the defaults for all HTMLEditor in your YML configuration.
```yaml
SilverStripe\Forms\HTMLEditor\TinyMCEConfig:
image_size_presets:
- name: widesize
i18n: SilverStripe\Forms\HTMLEditor\TinyMCEConfig.WIDE_SIZE
text: Wide size
width: 900
```
You can edit the image size pre-sets for an individual configuration with this code snippet.
```php
< ?php
use SilverStripe\Forms\HTMLEditor\HtmlEditorConfig;
use SilverStripe\Forms\HTMLEditor\TinyMCEConfig;
HtmlEditorConfig::get('cms')->setOption('image_size_presets', [
[
'width' => 300,
'text' => 'Small fit',
'name' => 'smallfit',
'default' => true
],
[
'width' => 600,
'i18n' => TinyMCEConfig::class . '.BEST_FIT',
'text' => 'Best fit',
'name' => 'bestfit'
],
[
'i18n' => TinyMCEConfig::class . '.ORIGINAL_SIZE',
'text' => 'Original size',
'name' => 'originalsize'
]
]);
```
2012-06-08 18:30:31 +02:00
## oEmbed: Embedding media through external services
2014-10-22 12:47:56 +02:00
The ["oEmbed" standard ](http://www.oembed.com/ ) is implemented by many media services around the web, allowing easy
representation of files just by referencing a website URL. For example, a content author can insert a playable youtube
video just by knowing its URL, as opposed to dealing with manual HTML code.
2012-06-08 18:30:31 +02:00
2018-04-10 05:54:57 +02:00
oEmbed powers the "Insert from web" feature available through
[HtmlEditorField ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorField ). Internally this service is provided
by the [embed ](https://github.com/oscarotero/Embed ) library.
To disable oembed you will need to follow the below to remove the plugin from tinymce, as well
as disabling the internal service via yml:
```yaml
---
Name: oembed-disable
---
SilverStripe\AssetAdmin\Forms\RemoteFileFormFactory:
enabled: false
```
2012-06-08 18:30:31 +02:00
2018-04-10 05:54:57 +02:00
```php
HtmlEditorConfig::get('cms')->disablePlugins('ssembed');
```
2012-06-08 18:30:31 +02:00
2015-11-12 22:51:13 +01:00
## Limiting oembed URLs
HtmlEditorField can have whitelists set on both the scheme (default http & https) and domains allowed when
inserting files for use with oembed.
2018-04-10 05:54:57 +02:00
This is performed through the config variables on the
[RemoteFileFormFactory ](api:SilverStripe\AssetAdmin\Forms\RemoteFileFormFactory ) class:
```yaml
---
Name: oembed-restrictions
---
SilverStripe\AssetAdmin\Forms\RemoteFileFormFactory:
fileurl_scheme_whitelist:
- https
- http
fileurl_scheme_blacklist:
- ftp
fileurl_domain_whitelist:
- google.com
fileurl_domain_blacklist:
- localhost
fileurl_port_whitelist:
- 80
- 443
fileurl_port_blacklist:
- 23
```
This allows a white or blacklist to be applied to schema, domain, or port (if provided). Note that
both blacklist and whitelist need to match, and are only ignored if the rules are empty for any
of the above values.
2015-11-12 22:51:13 +01:00
2018-04-10 05:54:57 +02:00
By default live sites (SS_ENVIRONMENT_TYPE="live") will not attempt to resolve oembed urls that
point to localhost to protect your site from cross site request forgery.
2015-11-12 22:51:13 +01:00
2013-04-16 14:01:04 +02:00
### Doctypes
2014-10-22 12:47:56 +02:00
Since TinyMCE generates markup, it needs to know which doctype your documents will be rendered in. You can set this
through the [element_format ](http://www.tinymce.com/wiki.php/Configuration:element_format ) configuration variable. It
defaults to the stricter 'xhtml' setting, for example rendering self closing tags like `<br/>` instead of `<br>` .
2013-04-16 14:01:04 +02:00
In case you want to adhere to HTML4 instead, use the following configuration:
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
HtmlEditorConfig::get('cms')->setOption('element_format', 'html');
2017-08-03 02:51:32 +02:00
```
2013-04-16 14:01:04 +02:00
2021-06-30 11:48:52 +02:00
By default, TinyMCE and Silverstripe CMS will generate valid HTML5 markup, but it will strip out HTML5 tags like
2014-10-22 12:47:56 +02:00
`<article>` or `<figure>` . If you plan to use those, add them to the
[valid_elements ](http://www.tinymce.com/wiki.php/Configuration:valid_elements ) configuration setting.
2013-04-16 14:01:04 +02:00
2017-07-03 03:22:12 +02:00
Also, the [HTMLValue ](api:SilverStripe\View\Parsers\HTMLValue ) API underpinning the HTML processing parses the markup into a temporary object tree
2014-10-22 12:47:56 +02:00
which can be traversed and modified before saving. The built-in parser only supports HTML4 and XHTML syntax. In order
to successfully process HTML5 tags, please use the
2013-04-16 14:01:04 +02:00
['silverstripe/html5' module ](https://github.com/silverstripe/silverstripe-html5 ).
2012-02-14 00:49:34 +01:00
## Recipes
2014-12-08 21:03:02 +01:00
### Customising the "Insert" panels
2012-02-14 00:49:34 +01:00
In the standard installation, you can insert links (internal/external/anchor/email),
images as well as flash media files. The forms used for preparing the new content element
2021-06-30 11:48:52 +02:00
are rendered by Silverstripe CMS, but there's some JavaScript involved to transfer
2012-02-14 00:49:34 +01:00
back and forth between a content representation the editor can understand, present and save.
Example: Remove field for "image captions"
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\Core\Extension;
2017-08-07 05:11:17 +02:00
2021-10-07 10:13:26 +02:00
// File: app/src/MyToolbarExtension.php
2017-10-27 04:38:27 +02:00
class MyToolbarExtension extends Extension
{
public function updateFieldsForImage(& $fields, $url, $file)
2017-08-07 05:11:17 +02:00
{
2017-10-27 04:38:27 +02:00
$fields->removeByName('CaptionText');
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
```php
2018-06-25 00:39:53 +02:00
// File: app/_config.php
2017-10-27 04:38:27 +02:00
use SilverStripe\Admin\ModalController;
ModalController::add_extension('MyToolbarExtension');
2017-08-03 02:51:32 +02:00
```
2012-02-14 00:49:34 +01:00
Adding functionality is a bit more advanced, you'll most likely
need to add some fields to the PHP forms, as well as write some
JavaScript to ensure the values from those fields make it into the content
elements (and back out in case an existing element gets edited).
2017-07-03 03:22:12 +02:00
There's lots of extension points in the [ModalController ](api:SilverStripe\Admin\ModalController ) class
2012-02-14 00:49:34 +01:00
to get you started.
### Security groups with their own editor configuration
Different groups of authors can be assigned their own config,
e.g. a more restricted rule set for content reviewers (see the "Security" )
2017-07-03 03:22:12 +02:00
The config is available on each user record through [Member::getHtmlEditorConfigForCMS() ](api:SilverStripe\Security\Member::getHtmlEditorConfigForCMS( )).
The group assignment is done through the "Security" interface for each [Group ](api:SilverStripe\Security\Group ) record.
2012-02-14 00:49:34 +01:00
Note: The dropdown is only available if more than one config exists.
### Using the editor outside of the CMS
Each interface can have multiple fields of this type, each with their own toolbar to set formatting
and insert HTML elements. They do share one common set of dialogs for inserting links and other media though,
2017-07-03 03:22:12 +02:00
encapsulated in the [ModalController ](api:SilverStripe\Admin\ModalController ) class.
2014-12-08 21:03:02 +01:00
In the CMS, those dialogs are automatically instantiate, but in your own interfaces outside
of the CMS you have to take care of instantiate yourself:
2012-02-14 00:49:34 +01:00
2017-08-03 02:51:32 +02:00
```php
2017-10-27 04:38:27 +02:00
use SilverStripe\Admin\ModalController;
use SilverStripe\Control\Controller;
2017-08-07 05:11:17 +02:00
2021-10-07 10:13:26 +02:00
// File: app/src/MyController.php
2017-10-27 04:38:27 +02:00
class MyObjectController extends Controller
{
public function Modals()
2017-08-07 05:11:17 +02:00
{
2017-10-27 04:38:27 +02:00
return ModalController::create($this, "Modals");
2017-08-07 05:11:17 +02:00
}
2017-10-27 04:38:27 +02:00
}
2017-08-03 02:51:32 +02:00
```
2012-02-14 00:49:34 +01:00
Note: The dialogs rely on CMS-access, e.g. for uploading and browsing files,
so this is considered advanced usage of the field.
2017-08-03 02:51:32 +02:00
```php
2018-06-25 00:39:53 +02:00
// File: app/_config.php
2017-10-27 04:38:27 +02:00
HtmlEditorConfig::get('cms')->disablePlugins('ssbuttons');
HtmlEditorConfig::get('cms')->removeButtons('sslink', 'ssmedia');
HtmlEditorConfig::get('cms')->addButtonsToLine(2, 'link', 'media');
2017-08-03 02:51:32 +02:00
```
2012-02-14 00:49:34 +01:00
### Developing a wrapper to use a different WYSIWYG editors with HTMLEditorField
WYSIWYG editors are complex beasts, so replacing it completely is a difficult task.
The framework provides a wrapper implementation for the basic required functionality,
mainly around selecting and inserting content into the editor view.
Have a look in `HtmlEditorField.js` and the `ss.editorWrapper` object to get you started
2017-07-03 03:22:12 +02:00
on your own editor wrapper. Note that the [HtmlEditorConfig ](api:SilverStripe\Forms\HTMLEditor\HtmlEditorConfig ) is currently hardwired to support TinyMCE,
2012-02-14 00:49:34 +01:00
so its up to you to either convert existing configuration as applicable,
2017-10-27 04:38:27 +02:00
or start your own configuration.