Repository navigation
mediaEmbed.previewsInData ignored server-side when Config Options come from a JSON file #636
Description
Description
Hey folks 👋 We hit this on a site that moved from Redactor to CKEditor, and it took a while to track down, so here's what we found.
Since 5.3.0, a field's Config Options can come from a JSON file in config/ckeditor/ (Advanced → Config Options → File). That works great in the editor itself. But _normalizeFigures() reads mediaEmbed.previewsInData from $this->options, and that only gets filled from the file inside configJs():
private function configJs(): string
{
if (isset($this->jsFile) && strtolower(pathinfo($this->jsFile, PATHINFO_EXTENSION)) === 'json') {
$this->options = self::jsonFileContents($this->jsFile);
}
// ...configJs() only runs when the field's input is rendered. So when an element is saved without the editor (craft resave/*, resave queue jobs, revision reverts, imports, programmatic saves), previewsInData comes back as false. Redactor-style <figure><iframe> then gets rewritten into a bare <oembed>, even though the JSON file sets previewsInData: true.
Why it matters
In #605, the advice for Redactor-era videos was to set mediaEmbed.previewsInData: true, because Parse Embeds can't handle the youtube.com/embed/<id> URLs that Redactor stored. That's what we did. Then the 5.3.0 migration moved our config into config/ckeditor/Standard.json for us, and the setting stopped applying to anything saved outside the editor.
The result is videos that look fine in the CP but render as an empty <oembed> on the front end. Restoring an old revision brings it back too, because the revision still has the Redactor markup and gets re-normalised on save. On our (statically built) site it went unnoticed for months.
Steps to reproduce
- Create
config/ckeditor/Test.json:{ "mediaEmbed": { "previewsInData": true } } - Create a CKEditor field with Media Embed in the toolbar. Under Advanced → Config Options, choose File →
Test.json. Add the field to an entry type. - Set Redactor-style markup on an entry without the editor:
php craft resave/entries --element-id=<id> --set=<fieldHandle> --to='=<figure><iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ"></iframe></figure>'
- Check the stored value.
Actual:
<figure class="media"><oembed url="https://www.youtube.com/embed/dQw4w9WgXcQ"></oembed></figure>Expected:
<figure class="media"><div data-oembed-url="https://www.youtube.com/embed/dQw4w9WgXcQ"><iframe src="https://www.youtube.com/embed/dQw4w9WgXcQ"></iframe></div></figure>If you switch the field to JSON with the exact same options and run step 3 again, you get the expected output. So it's only the file-based config that's affected.
Suggested fix
Resolve the options in one place, so they're available whether or not the input has been rendered:
private function resolvedOptions(): ?array
{
if (isset($this->jsFile) && strtolower(pathinfo($this->jsFile, PATHINFO_EXTENSION)) === 'json') {
return self::jsonFileContents($this->jsFile);
}
return $this->options;
}Then in _normalizeFigures():
$previewsInData = $this->resolvedOptions()['mediaEmbed']['previewsInData'] ?? false;Thanks! 🙏
Additional info
- Craft version: 5.10.14
- PHP version: 8.4
- Database driver & version: MySQL 8.0
- Plugins & versions: CKEditor 5.7.0 (the code is unchanged in 5.9.0), HTML Field 3.6.0
Activity
linear-code commentedon Oct 12, 2026
SUP-761