Repository navigation
Craft 6 support - #641
Merged
Merged
Craft 6 support#641
Conversation
- Require Craft 6, PHP 8.5, craftcms/yii2-adapter and the Craft 6 branch of craftcms/html-field - Port the field and its data classes to native Craft 6 APIs on top of CraftCms\HtmlField\HtmlField; the CP input and settings UI still render through the adapter's legacy HTML bridge - Replace HTML Purifier with Craft's HTML sanitizers - Register the field type through the native field type registries - Start UPGRADE.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Extend CraftCms\Cms\Plugin\Plugin and move initialization to boot() - Move to the CraftCms\Ckeditor namespace and Laravel-style folders, keeping the old class names loadable as aliases - Port the settings to PluginSettings with a settingsUi() page - Port the controllers to plain Laravel controllers routed from routes/actions.php, keeping the existing action URLs - Move templates, translations and the icon to resources/ and lang/ - Remove CKEditor's own reference tracking in favor of Craft's field references, with a migration that copies existing references and renames the stored field type - Document the changes in UPGRADE.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Replace the Yii-style EVENT_MODIFY_CONFIG and EVENT_DEFINE_LINK_OPTIONS events with EditorConfigResolving and LinkOptionsResolving Laravel events - Add HtmlSanitizerConfigResolving to replace the removed HTML Purifier config event, and build each field's sanitizer only once - Port the GraphQL types to CraftCms\Ckeditor\Gql on native APIs - Bind the plugin settings in the container - Stop implementing EagerLoadingFieldInterface, matching Craft 5, so GraphQL resolves the field value instead of eager-loaded entries - Document the changes in UPGRADE.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Replace the Yii console controller with ckeditor:convert:redactor and ckeditor:convert:matrix Artisan commands, keeping the old names as aliases; the Matrix conversion now generates a Laravel content migration - Replace the Yii asset bundles with published files and a CkeditorAssets service, and add CkeditorPackage for registering CKEditor packages from other plugins - Move the front-end sources and builds to resources/assets/ - Render the field input and settings with HtmlStack, InputNamespace and template() instead of the legacy view - Remove craft.app and view usage from the templates - Update the README and UPGRADE.md for Craft 6 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Add CkeditorControl (`ckeditor:editor`) and a Vue component that loads the editor's assets, imports the field's editor setup module, and emits the editor data as the control value on every change - Replace the adapter's legacy field HTML bridge with uiControl(); the field settings still use the adapter for now - Add an owner bridge so nested entries and image entries are created for the owner's draft, and existing nested entries are edited in a native slideout that saves into the owner's draft - Pass the layout element UID through the editor config, and use Craft 6 element class names in the editor JS - Use a system icon for the field type Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Replace the legacy settings template with settingsUi(), using core controls for entry types, heading levels, link fields, limits, assets, sanitizing and GraphQL settings - Add EditorConfigControl (`ckeditor:editor-config`), which mounts the toolbar builder, config options and custom styles, starts craft-code-editor's Monaco editors, and emits their values together - Add a "Show as separate buttons" setting in place of the per-entry-type expanded toggle - Remove the legacy settings template, entry type select input and field settings controller actions - Drop the remaining Yii 2 adapter classes from the field Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Drop craftcms/yii2-adapter from composer.json; the plugin now runs on native Craft 6 APIs only, and offers category links only when the adapter's Category element type is installed - Update composer.lock for Craft 6 - Accept a delimiter in ConvertRedactorCommand::split() - Finish UPGRADE.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Replace craftcms/phpstan with phpstan/phpstan ^2.1 and larastan/larastan ^3.13, and orchestra/testbench ^11.0 so Larastan can boot Laravel - Replace craftcms/rector (Craft 4 to 5 upgrade rules, which pinned PHPStan 1) with rector/rector ^2.3 and driftingly/rector-laravel ^2.6.2 - Point phpstan.neon at Larastan and PHP 8.5 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plugin uses Craft 6 APIs (like CraftCms\Cms\Ui) that aren't in a tagged release yet, so load craftcms/cms from ../cms for development. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Return null for entry type configs without an ID or UID, instead of catching the exception getEntryType() throws for them - Annotate nested entries when rendering cards - Remove incorrect @var tags and a redundant array_values() call - Ignore the adapter-only Craft class in the category link sources - Pass booleans to abort_unless() - Fix the return types of EntryType::getUsageConfig() and CkeditorConfigSchema::interface2ref() Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Render the JSON/JavaScript/File and CSS/File toggles with Craft 6's craft-button-group and craft-button elements, and fix the "keep JavaScript" path when switching to JSON with the native Listbox. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replace craftcms/ecs (Craft 5 coding standard) with laravel/pint ^1.22, as Craft 6 uses, and point the check-cs and fix-cs scripts at it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop src/legacy-aliases.php and the craft\ckeditor\ autoload root, so the Craft 5 class names are no longer loadable. The upgrade migration renames the stored field type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Hide the toolbar builder's used items, since Craft 6's layered `.hidden` utility loses to the item's display rule - Give every Craft 5 CSS variable a Craft 6 design token fallback, so the editor and field settings render correctly without the legacy control panel styles (this also restores the separator's width) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds the Expand to a separate button / Collapse to a dropdown chip action and the Show as a separate button indicator on the field settings' entry type chips, keeping the expanded value via EntryTypeSelect::extraValueKeys(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The toolbar builder, config options and custom styles are now separate settings controls, with their labels and instructions coming from the settings UI. Config Options and Custom Styles are listed under the Advanced group, as in Craft 5. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moves the CKEditor UI controls to Vue single-file components under resources/js, bundled through the plugin's $vite input and registered from resources/js/cp.ts, following Commerce. Upgrades Vite to 8 for laravel-vite-plugin, and rebuilds the editor and field settings bundles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds declare(strict_types=1) to the PHP files in src/ and routes/, matching Craft 6 core. Casts the values strict types would otherwise reject, so behavior stays the same: empty config option and custom style values, nested entry HTML, and the encoded config options JSON. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drops the yii2 keyword and the yiisoft/yii2-composer plugin allowance, and points the docs, RSS and documentation URLs at the 6.x branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Excludes the JS sources and build configs from the Composer archive, marks the built assets in resources/assets/*/dist and public/build as generated, and removes entries for files that don't exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the forms.select macro shim with core's select component, so the editor config template no longer imports _includes/forms.twig. The file option maps are converted to the label/value list it expects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Whitespace only. Matches core's Twig templates, and removes the extra indentation left over from the removed field wrappers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Uses core's <craft-icon> instead of Craft.ui.icon(), which fetched the SVG through an action request and left the indicator empty for a moment after the page loaded. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
craft-field lays its input row out with flexbox, so the container needs to grow to fill it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Vite copies publicDir (the package's public/ folder, now home to the cp build) into outDir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use ElementHtml::elementCardData() and fill craft-card's header, content, footer and thumbnail slots, and update the fallback error card markup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The control panel's CSS reset removes block margins and list styles, and the editable area's padding was too big. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Identify the entry by its owner and field in the slideout URL, and only move it into the owner's draft when it isn't already there, like Matrix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refresh the card after every slideout save, including autosaves, by replacing its HTML in place, and render it with the user's provisional draft. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Replaces the progress bar under the field, which duplicated what the upload notification already reports. The placeholder goes in at the drop position and its source is swapped for the asset's once the upload lands; creating the owner's draft replaces the editor's value, so pending placeholders are put back after a reload.
This was referenced Nov 4, 2026
Keeps the Craft.* and Garnish.* shape at the call sites, so the diff stays close to the original and CKEditor's own locale `t` is no longer shadowed. The generated editor module keeps a named import, since a namespace called Craft there would shadow the global for a field's custom config JS.
Remove upload placeholders and their restoration hooks. Fix canceled toolbar animations, respect reduced motion, cache configuration lookups, and clone toolbar components directly. Repair corrupted strings and trim unused module declarations and dev exports. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
resources/assets/fieldsettings/vite/ held the output of the first Vite builds, from before outDir was switched to dist/. Nothing loads it, and it still contained the old jQuery/Velocity ToolbarBuilder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lock file still listed jQuery as a root peer dependency after it was removed from package.json. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing reads window.Craft any more, and the global const would hide a missing `import * as Craft from '@craftcms/cp'` from type-checking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Web Animations API doesn't write in-between values to the inline style the way Velocity did, so releasing a source item mid-collapse snapped it back to full width. Read the margin from the computed style instead, which includes running animations. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each modal mounts its own Vue app into a host element on <body>, which only the handle's destroy() removes, so every image or element link selection left one behind. Also stop passing closeOtherModals to the link selector, since the modal ignores it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The element editor panel never triggers beforeClose, so the cursor and focus weren't restored after creating an entry from the toolbar. Use the onClose setting instead, and place the cursor after the new card, adding a paragraph when no text block follows it. Canceling still returns the cursor to where it was. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every name used from @craftcms/cp in the TypeScript bundle has to be declared in craftcms-cp.d.ts and listed in vite.config.mts, and one missing from the Vite list is only noticed under the dev server. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The row relied on Craft 5's .flex for its gap and wrapping, so in Craft 6 its items sat flush against each other and the sites dropdown stayed on the same line instead of breaking onto its own. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without one, addActionsToChip() had nowhere to put the Replace and Remove actions, and its jQuery fallback no longer runs. Request the chip with its action menu, limited to the View and Edit actions, and add Replace and Remove to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Craft 6 replaced the “Copy value from site” field action with the Compare screen and removed CrossSiteCopyableFieldInterface, so update craftcms/cms and drop the interface and copyCrossSiteValue(). The CKEditor control is now readable and writable, so its value (with the nested entries’ card HTML) can be copied between sites, drafts and revisions. As the Compare screen copies the HTML as is, the field now duplicates any nested entries the element doesn’t own in its site when it’s saved, and points the value at the duplicates. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
[6.x] Move CKEditor off jQuery and the Craft globals
Add a persistent Craft 6 development workbench
…ed without the field posted The editor only posts changed values, so after the first autosave the CKEditor field isn't dirty, but propagateAll still copies its content (with this site's nested entry IDs) to the other sites. Mark the field dirty in that case, so NestedElementManager duplicates the nested entries and adjusts the other sites' values. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e” field actions Craft 6 added “Copy value” and “Paste value” field actions for controls that can be read and written, which the CKEditor control is. Update craftcms/cms and handle them the way core’s controls do: - Only copy values between controls that allow the same entry types, via `CkeditorControl::getValueScope()`, as Table does for its money columns. - Preview copied values in the “copied” card as their first lines of text, with nested entries as badges, registered with `Cp.$ui.registerValuePreview()` in `Cp.booting()`. Register the controls in `Cp.booting()` too, as the docs say. - When saving, duplicate nested entries owned through another field into this one, and leave out ones of entry types the field doesn’t allow. - Keep read-only values’ nested entries as `<craft-entry>` elements, with their cards sent alongside, so values copied from read-only fields keep them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Amp-Thread-ID: https://ampcode.com/threads/T-01a1c0e7-8a79-7453-8b37-8dc2cd14333a Co-authored-by: Amp <amp@ampcode.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports CKEditor to Craft 6: native plugin class, controllers, events, field and settings UI, with no Yii 2 adapter.
Requires
EntryTypeSelect::extraValueKeys(), which keeps the entry types' "expanded" settingHtmlSanitizerManager::config(), which lets CKEditor extend the field's selected sanitizerWhat's changed
Port
ckeditor:editor), and the field settings use Craft 6 UI controlsCraft.uuid(),Craft.trim(),Craft.escapeHtml()and jQuery are replaced with native APIs where that's straightforwardField settings
nystudio107/craft-code-editoris no longer required, since it doesn't support Craft 6 yet. The config options (JSON/JavaScript) and custom styles (CSS) settings are plain text areas, without syntax highlighting, validation or autocomplete. The Monaco code is commented out and taggedTODO(code-editor), so it can be restored once there's a Craft 6 release.HTML sanitizing
symfony/html-sanitizer). Existing Purify HTML / HTML Purifier Config settings are mapped onto Sanitize HTML / HTML Sanitizer bycraftcms/html-fieldHtmlSanitizerConfigResolving, as v5 did for every HTML Purifier config. Sanitizers registered as instances are used as-istargetandrelattributes are only allowed when the field's link options or advanced link fields can add them, as in v5Nested entries
ElementHtml::elementCardData())data-card-html)Security
ckeditor/entry-card-htmlnow requires view access to the entry, and integer IDsdata-entry-idcould triggerBreaking changes
See
UPGRADE.md.Known gaps
SelectableCardList.vueslot layoutcraft:nested-owner-editor-requesteventElementCardHtmlResolvingno longer fires for CKEditor cards, unless [6.x] Fire ElementCardPartsResolving for every element card cms#20335 (or something similar) gets approved and merged for the corenystudio107/craft-code-editorsupports Craft 6. Restoring it means re-adding"nystudio107/craft-code-editor"tocomposer.jsonand uncommenting theTODO(code-editor)blocksHtmlSanitizers::config()as undefined, and the field tests fail, until [6.x] Add HtmlSanitizerManager::config() cms#20328 is merged into6.xconfig/craft/htmlpurifier/*.jsonconfigs (only loaded with the Yii 2 adapter) aren't extended with CKEditor's markup, so they strip nested entries and other markup they don't allow on save. The README andUPGRADE.mdtell people to recreate them inconfig/craft/sanitizers/Base,DragDrop) and jQuery, because Craft doesn't share@craftcms/garnishwith plugins yetcrypto.randomUUID(), which browsers only provide over HTTPS or on localhost, the same as Craft 6's own Vue code🤖 Generated with Claude Code