The online editor on TinyMCE 8 (opt-in, next to TinyMCE 3)
This page is for editors who want a modern rich text editor, and for administrators who decide which editor a site uses. Exponential 6.0.15 ships TinyMCE 8.9.2 as a second engine of the eZ Online Editor. TinyMCE 3.5.12 stays the default, and nothing changes for existing installations. The new engine writes the same XHTML that the ezoe input handler reads, so stored XML is identical with both engines and editors can switch back and forth. Added 2026-10-02. Reference: ezoe and TinyMCE 8.
Try it in one minute
For yourself, without touching settings:
- Open
/user/preferences/set/ezoe_engine/tinymce8. - Edit any article. The editor is TinyMCE 8.
- To go back, open
/user/preferences/set/ezoe_engine/tinymce3.
Editors can also choose on the page /ezoe/engine.
For a whole siteaccess, in settings/siteaccess/<name>/ezoe.ini.append.php:
[EditorSettings]
EditorEngine=tinymce8
EngineSwitch=enabledEngineSwitch=enabled shows the engine switch below the editor: one group named "Editor" with every available engine
in the order of Engines[] (for example "TinyMCE 3 | TinyMCE 8") as toggle buttons, the engine in use pressed (aria-pressed), each
other one a button. A click stores the draft with the text typed so far and switches; the choice is stored as the user
preference ezoe_engine. admin4 draws the group as a segmented control at the control height; other designs show the
label, the name of the engine in use and the buttons. The template is
content/datatype/edit/ezxmltext_ezoe_engine_switch.tpl, its list the input handler's engine_switch_options
(expOEEditor::switchOptions(); engine_switch_choices, the other engines only, stays for overrides).
What the TinyMCE 8 engine does
| Content | Dialogs and behaviour (like TinyMCE 3) |
|---|---|
| Embed and embed-inline | Search via ezjsc::search with the class filter and a preview column; Upload tab to upload and embed a new object; edit an existing embed (view, class, size for images, align, inline, custom attributes); double click and context toolbar |
| Links | ezoe dialog with Browse, Search and Bookmarks tabs (the user's own bookmarks, paged, with a preview column) to choose a node or object; anchors saved as <a name> like TinyMCE 3 |
| Custom tags | Insert, edit, remove with the tag's custom attributes (text, textarea, int, number, email, select, checkbox, color, hidden); validation of required and numeric values |
| Literal tags | Dialog like the TinyMCE 3 general tag dialog |
| Tables, rows, cells | Classes and custom attributes (content.ini [table] Defaults for the size of new tables). Insert table / Table properties open the TinyMCE 3 dialog design by default (size grid, width and border with px / %, class, summary, caption); TableDialog=modern in [Engine_tinymce8] selects the plain TinyMCE 8 form |
| Paragraphs, headings, lists, strong, emphasize | The general tag dialog for class and custom attributes |
| Status bar | The ezxml tag path, for example "Path: paragraph » embed"; clicking an element opens its dialog |
| Look | With Skin=o2k7 the editor and its dialogs look like the TinyMCE 3 o2k7 skin |
Settings
All keys are in extension/ezoe/settings/ezoe.ini, block EditorSettings. Scope: user preference, siteaccess or
global. Resolution order: user preference ezoe_engine, siteaccess, global, then tinymce3.
| Key | Default | Meaning |
|---|---|---|
EditorEngine | tinymce3 | Engine for users without a preference |
EngineSwitch | disabled | Show the engine switch below the editor |
Engines[<id>] | tinymce3=expOETinyMCE3Engine, tinymce8=expOETinyMCE8Engine | Registry of classes implementing expOEEditorEngine; an extension adds a third engine with one class and one line |
UploadExtensionCheck | engine | Server-side file type check: engine (non-TinyMCE-3), always, disabled |
UploadFileExtensions[] | images, documents, media | File types of the Upload tab |
UploadFromUrl | enabled | enabled / disabled: the "From a URL" choice on the Upload tab (both editors) |
UploadFromUrlMaxSize | 145M | Largest file fetched from a URL (K, M, G). Only this applies, not PHP's upload_max_filesize |
UploadFromUrlTimeout | 300 | Total seconds a fetch may take (connecting must succeed within 5 seconds) |
Check the shipped values:
grep -n 'EditorEngine\|EngineSwitch\|Engines\[' extension/ezoe/settings/ezoe.iniThe registry classes are extension/ezoe/classes/expoeeditorengine.php, expoetinymce3engine.php and
expoetinymce8engine.php; the engine page is the view engine of the ezoe module.
Link checks when the text is saved
Both engines send HTML that eZOEInputParser turns into the stored XML. Each link is checked there, and what it
finds goes to the validation log shown above the edit form ("The draft was only partially stored"):
| Link | What happens | Message |
|---|---|---|
eznode://<id> or eznode://<path> to a node that is gone | the link is kept, the message says how to repair it | names the link by its text (70 characters at most, else its address); when the target is in the trash: its name, class, old place and since when, shown only to a user who may read it (otherwise only "is in the trash"); for a link by id: restoring does not repair it, because the restored object gets a new location |
ezobject://<id> to an object that no longer exists | as above | "no longer exists, not even in the trash" |
a script link: javascript:, vbscript:, livescript:, data: other than a plain image, in any spelling a browser follows (character references, :, tabs or line breaks in the scheme, leading spaces, any case) | the address is removed, the input is marked invalid (isValid() false) | "Using scripts in links is not allowed, '...' has been removed" |
mailto: with an invalid address (each of several, before ?, percent-decoded; internationalized domains accepted) | the address is removed, the input is marked invalid | "Invalid e-mail address: '...'" |
The trash is looked up only for a link whose target is gone, so a link to a live target costs no query. The messages
are plain text; every design prints them with |wash, once (expOEValidationMessagesEscapedOnceTest). A design of
your own that overrides content/edit_validation.tpl does the same. Tests: expOEDeadLinkMessageTest,
expOEInputValidFlagTest, expOELinkAddressCheckTest.
Security
ezoe/upload refuses a file whose last extension is not in UploadFileExtensions[], and any name with an executable
extension anywhere in it (shell.php.jpg), because a request can skip the dialog. An engine change is recorded in the
audit trail as content.ezoe.engine.change.
Upload from a URL
The Upload tab of the embed dialog (TinyMCE 8 and TinyMCE 3) offers "From your computer" or "From a URL". The server
fetches the address and creates the object like a browser upload: same class choice (upload.ini), location, name and
description fields, same embed afterwards, same permission checks and form token. The fetch is a server-side request
for a user, so:
- only
httpandhttps; no credentials in the URL; the host is resolved once, every address must be public (no loopback, private, link-local, multicast, reserved, carrier-grade NAT, IPv4-mapped or NAT64 IPv6 variants) and the connection is made to the checked address, so DNS rebinding cannot swap it; - redirects are followed by hand, at most 3, every target checked again;
- connect timeout 5 s, total timeout
UploadFromUrlTimeout; the size limit is enforced while the body streams to a temporary file undervar/tmp/ezoe_url/(never held in memory) and the file is deleted after the request; - the name comes from Content-Disposition or the URL path and is sanitized; the extension must pass
UploadFileExtensions[](whateverUploadExtensionChecksays), executable names are refused, and the content (finfo) must agree with the extension, executables and web pages are refused whatever the name; - a successful fetch is recorded as
content.ezoe.upload.urlin the audit trail.
Tests
extension/ezoe/tests/tinymce8holds browser tests (puppeteer-core with Firefox or Chrome, real mouse clicks) that can be run against an installation at any time.- PHPUnit tests in
tests/tests/extension/ezoe/cover the registry, engine configuration, upload rules, JSON answers, views and the XHTML round trip. The count was 267 when written (not re-counted for this page). Run them withphp vendor/bin/phpunit tests/tests/extension/ezoe/.
The bundled TinyMCE 8.9.2 is used under the GPL (version 2 or later); its README states the licences and where the corresponding source is.
Related pages
- ezoe and TinyMCE 8 (bc guide)
- Remote services
expeditorand the expservices specification - ezoe, ezautosave
- Upgrade checklist of 1-2 October 2026
- 6.0.15 changelog
- October 2026 chronicle
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.