github craftcms/cms 6.0.0-beta.1

pre-releaseone hour ago

Control Panel

  • Added a command palette, opened from the search button in the global header or with Command/Ctrl + K. It finds fields, tabs, and Matrix blocks on the current page, control panel pages and settings, entries, assets, users, and releases, and runs actions such as creating entries and settings, publishing releases, clearing caches, and changing preferences, with the same permission checks as the screens they stand in for. It also searches the Craft CMS documentation, and lists recently visited pages when nothing has been typed. (#20081)
  • Added Ask AI, an AI assistant chat beside every control panel screen, opened from the sparkles button in the global header, with Command/Ctrl + I, or from the command palette. It answers with Craft’s MCP tools as the signed-in user, works with the element being edited, shows elements, settings, and fields in its replies, asks questions with answers to choose from, and proposes changes that users review and apply to the form. MCP tools that change anything need the user’s approval, and chats are saved for each user. Users can add fields, elements, and other items to a message as context, or mention them by typing @ or {. (#20109)
  • Links to fields, such as those in Ask AI’s replies, now open the tab or details panel the field is in. (#20109)
  • Readable text, such as Ask AI’s replies, now styles ordered lists, task lists, blockquotes, and inline code. (#20109)
  • Modified fields on drafts and revisions now have a “Compare changes” action, which shows how the field’s value differs from the current entry or the previous revision. Matrix fields that show their entries as cards or in an index show them as cards, with the edited and new ones marked, and each card can be opened in a new tab. (#8135, #20307)
  • Entries now have a Compare screen, at compare/{id}, which shows two versions side by side: a draft and the current entry, two revisions, the user’s unsaved changes and the entry as it’s saved, or the entry in two sites. Two separate entries can be compared too, at compare/{fromId}/{toId}, from element indexes’ “Compare” action, which is offered when two elements with the same field layout are selected, with the heading “Compare [entry] with [entry]” and each side’s own version menu. It’s opened from the Versions panel (formerly “Revisions”), which has a compare button beside each draft and revision, from the Sites panel, from the “Compare changes” item atop the editor’s action menu, and from the “Showing your unsaved changes” notice. The two versions are shown as editor panes with their fields lined up in their tabs, including sidebar tabs, and changed fields are marked on the side that made the change, or on both when neither did. Selecting a tab on either side selects it on both. Either version, or both, can be edited in place when the user can save it, with autosave and its own Save button, unless it’s a revision, and fields are marked as they’re edited. Arrow buttons between the panes copy a field’s value from one version into the other, with an “Undo” option. Each pane has a menu for choosing another version or another site, for whichever differs between the two panes, and a button between them swaps the two sides. On narrow screens, each field’s two versions are stacked, marked A and B. Between sites, translatable fields are marked when their values differ, and fields that aren’t translated aren’t. Nested and related elements, such as Matrix entries and relations, keep each version’s own order, with faint lines connecting the elements that moved, which are highlighted when either end is hovered or focused, and that follow the element when it’s reordered on the editable side. “Compare changes” draws the same lines. (#20384, #20474)
  • Removed the “Copy value from site” field action. Field values can be copied between sites from the Compare screen instead. (#20384)
  • Fields whose values can be copied between versions on the Compare screen, such as text, number, date, option, relation, Link, Table, and Color fields, now have a “Copy value” action while they have a value, which copies the field’s value to the clipboard and shows a preview of it, such as the related elements’ chips, the table’s first rows, the selected options with their icons and colors, a color’s swatch, the icon, or color-coded JSON and Markdown. Other apps get it as text, with tables as rows that spreadsheets split into cells, links as their URLs (linked from their labels in apps that take rich text), amounts with their currency, and dates as the user’s locale writes them. Fields that can take the copied value then have a “Paste value” action, which fills them with it. Values are only pasted into fields that could have been given them by hand, such as text within the field’s length limit and without line breaks for single-line fields, or options the field has, and relations only into the same field, such as on another entry. Pressing Ctrl/Command + V within a field that takes the value, outside its text inputs, pastes it too, as long as the clipboard still holds what was copied. (#20449)
  • Element cards can now be cover cards, where the thumbnail image fills the card, with the header and content laid over it on a blurred bar, backing, or scrim that keeps them legible over any image: white on black, or black on white over light images. Cover cards’ attribute previews are limited to one line. Card view designers have a new “Thumb Style” setting, with “Normal”, “Cover”, and “Auto” options, which defaults to “Auto” for asset volumes. Other element types’ cards can be covered too, when their thumbnail is an asset’s image, such as a user’s photo, or an image from the first of their “Thumb Sources” that has a thumbnail, including fields within Content Blocks and related elements’ own thumbnails. Only images from assets can cover a card. With “Auto”, images smaller than 480×360, narrower than 3:4, wider than 2:1, or possibly transparent keep the normal card. (#20148, #20152, #20181)
  • Element cards whose header has no label, such as asset cards, now show just their checkbox and action button over the card, without a header bar, and cards whose header has nothing in it no longer show one at all. Entry cards keep their header bar, with their entry type’s label and icon. (#20148)
  • Plain links to control panel pages, such as those in elements’ metadata and other server-rendered HTML, now open with Inertia rather than reloading the page. (#20118)
  • Added a “Theme” user preference, with “Light”, “Dark”, and “System” options. “System” is the default. Pages shown to logged-out users, such as the login page, always follow the system’s light or dark setting. (#19966)
  • Added a control panel notification center.
  • Added flyout menus to the global control panel nav, for accessing sub-pages of non-selected sections. (#19648)
  • Added Settings → System → CP Navigation, where administrators can customize the control panel’s navigation: reorder items and move them between sections, rename them, change their icons, hide them, and add sections and links, such as links straight to a single’s entry, which can be limited to users who match a condition. (#20247)
  • User groups can now have their own control panel navigations, which build on the default navigation and save only what they change, so changes to the default carry through to them. People in more than one group get the first of their groups’ navigations, in the order administrators put them in. (Craft Pro and Enterprise only.) (#20247)
  • Control panel success, notice, and error messages now stack, newest first, and can be swiped away. Errors and messages with actions stay until dismissed.
  • Admin table links and create actions can now open in a slideout with a custom width, via the slideoutWidth link option and new slideout and slideoutWidth arguments on CraftCms\Cms\Ui\Nodes\Table::createAction().
  • Double-clicking an admin table row now opens its link's slideout, if it has one.
  • Sortable checkbox selects, such as “Card Attributes”, “Table Columns”, and “Default Table Columns”, now list only the selected options, with an “Add item” menu for the rest. (#20001, #20036)
  • Slideouts can now be resized horizontally, and remember their width. (#19978)
  • Slideouts’ details panes that were folded away for lack of room now reopen once the slideout is wide enough again. (#19978)
  • Content within black cards, chips, and badges, such as buttons, badges, and links, is now styled as in the dark theme.
  • Card view designers now preview users with a sample user’s name, default avatar, and active status.
  • The control panel now warns users a couple of minutes before their session expires, with options to stay signed in or sign out, and lets them sign back in without leaving the page once it has. (#20086)
  • The global nav now groups Entries and Assets under a “Content” heading, and Users, GraphQL, Utilities, Settings, and Plugin Store under an “Administration” heading. (#19903)
  • The Plugin Store is now part of the control panel rather than a standalone app, with the store’s categories in the secondary nav, plugin pages whose Overview, Reviews, Editions, and Changelog tabs each have their own URL, and a cart that opens in a dialog from the store’s toolbar.
  • Plugins in the Plugin Store whose latest compatible release requires or suggests craftcms/yii2-adapter now show a “Requires the Yii2 adapter” notice, and installing them also installs the adapter, unless composer.json already requires it.
  • Dates are now shown in the calendar of the user’s formatting locale, such as the Persian calendar for Persian or the Buddhist calendar for Thai. Named and ICU date formats in Twig, such as |date('short'), follow the site locale’s calendar too. (#8741, #20085)
  • Element editor slideouts now have the full Save menu, including “Save and continue editing”, as well as an action menu and an “Open in a new tab” button. (#19748, #19854)
  • Modals, including the Customize Sources modal and element selection modals, can now be resized. (#20008)
  • Pressing Ctrl/Command + Return in a text input or textarea now submits its form. (#20025)
  • The control panel now uses the Inter typeface, bundled with Craft, rather than the operating system’s UI font, so it looks the same on every platform. Languages whose scripts Inter doesn’t cover, such as Arabic, Hebrew, Thai, Chinese, Japanese, and Korean, still use the system font for those characters.
  • Control panel text is now drawn with grayscale antialiasing on macOS, figures in tables and times line up in columns, shadows have a cool tint that matches the interface, and keyboard shortcuts share one keycap style. (#20544)
  • Refreshed the control panel’s styling, including modals, buttons, form inputs, editable tables, chips, Matrix blocks, status badges, and file and folder icons. (#19942, #20008, #20085)
  • Updated the control panel’s icons to Font Awesome 7. Parts of some icons now extend a little beyond their icon’s box, rather than being clipped. (#20520)
  • Icons that Font Awesome 7 renamed, such as user-large, film-simple, and grid-horizontal (now user, film, and grip), no longer show when referenced by their Font Awesome 6 names, including in Icon field values, entry type and option icons, and plugins’ icon names. (#20520)
  • “Pending” statuses are now blue rather than orange, and “Edited” badges and modified-field indicators are now violet rather than blue. (#20258)
  • Link and Email field values in element indexes and cards now stay on one line, cut off with an ellipsis, after a button that shows the full address with options to open or copy it. Hovering over the link shows the same details. (#20123)
  • The “View Mode” (Matrix, relation, Addresses, and Content Block fields), “Thumb Style”, “Section Type”, and image transforms’ “Mode” settings now show their options as joined, illustrated buttons, with each option’s label inside the button, below its illustration, and the selected option’s illustration drawn in blue. When there isn’t room for them in one row, they wrap as separate buttons. (#20233, #20285)
  • Dashboard widgets, such as Recent Entries and My Drafts, now update when elements are saved, in the same browser tab or another one. (#20485)
  • Fixed a bug where date pickers within slideouts could open far away from their inputs at some browser zoom and display scaling levels. (#20399)

Workflows

  • Added publishing workflows, which control when drafts may be applied to entries. Workflows are configured from Settings → Workflows and assigned to sections. (Craft Pro and Enterprise only.) (#19667)
  • Changes to enabled entries in sections with a workflow are now saved as drafts, which must be submitted for review and approved by each workflow stage before they can be applied. (#19667)
  • Added a “Workflow” element details tab, for submitting drafts for review, reviewing them, and viewing workflow activity history. (#19667)
  • Added the “User Review” workflow stage type, which supports per-group approval requirements, carried-over approvals, change requests, and email notifications for reviewers. (#19667)
  • Added releases, which group saved drafts of entries and other top-level elements so they can be scheduled and published together, atomically. A release’s drafts can be stepped through in a Live Preview–style view, opened from the release screen’s Preview button, with warnings on any drafts that are blocking the release, and edited beside their preview. Drafts in a release can be queried with the releaseId element query param and GraphQL argument, and the “Query for releases” GraphQL schema permission adds releases and release queries.

Elements

  • Added Markdown comments to element activity timelines, with support for editing, removing, structured user mentions, syntax-highlighted code blocks, and email notifications.
  • Element index searches now update results as users type. (#19754)
  • Clicking anywhere on an element index table row or card (other than an interactive control) now selects it. (#19351)
  • Element index selections now carry across pages, and bulk actions apply to all of them. Selections are cleared when the search, status, filters, source, or site change. (#10295, #20262)
  • Selecting every result on an element index page now shows a banner under the header that offers to select all of the index’s results, on every page. Bulk actions apply to them all, other than any deselected afterwards. The page controls now stay in the element index footer while elements are selected. (#10295, #11833, #20262)
  • Bulk element actions on more than 100 elements now run from a queue job. Actions that can’t, such as downloads and duplicating with descendants, are hidden once more than 100 elements are selected. (#11833, #20262)
  • Element index View menus now have a “Thumb Size” setting in table, structure, and thumbnail views, with “Small”, “Medium”, and “Large” options, plus “XL” and “2XL” in thumbnail view. Each view remembers its own size, and chips take a size to suit their thumbnails. (#20083, #20124)
  • Element indexes now show placeholders while their results load, rather than a spinner. Placeholders match the view mode and thumbnail size the results will be shown at, and the source’s card thumbnail style and alignment, so results no longer show at the default thumbnail size before switching to the chosen one. (#20199, #20142)
  • Thumbnail views in element indexes and relational fields now show each element as a chip, with its thumbnail above its label. (#20083, #20124)
  • Element index sources can now show a count of their elements in the control panel nav, via a new “Show count” setting in the “Customize sources” modal. Entries, assets, and users support it.
  • Apps can now manage their own Eloquent models as elements in the control panel, with an element index and nav item, an element editor, permissions or model policies, search, activity history, relation fields, and Twig element queries. Elements are kept in sync with their models in both directions, and the models and their tables are left unchanged. (#19971)
  • Element edit pages now have a “Sites” pane in their details sidebars on multi-site installs, in place of the “Status” pane. It lists the sites the element is saved to, with status toggles and links to the element in each site, and lets authors add the element to other sites, or remove it from them. Element editor slideouts can be switched to other sites from it. (#20061)
  • Deleting an element for the only site it exists in now soft-deletes it, unless it’s a draft or nested element. (#20060)
  • Element editor slideouts now have a “Preview” button, which opens Live Preview with the slideout’s editor beside the preview. (#14298, #19964)
  • Live Preview no longer flickers when it reloads. The updated page loads behind the current one and is swapped in once it’s ready, keeping the scroll position. (#19964)
  • Live Preview now fades between device sizes, rather than re-laying out the previewed page throughout the animation. (#19964)
  • Live Preview now reloads once after a run of quick edits, rather than after every autosave. (#19964)
  • Live Preview no longer uses iFrame Resizer. The previewed page always scrolls within its iframe.
  • Live Preview’s editor is now docked to the right of the preview, with the element’s details panels beside it. Slideouts opened from the editor now cover it as nested views, with a Back button.
  • Entries and assets can no longer be deleted for the only site they exist in, via the elements/delete-for-site action or the “Delete for site” element action, and “Delete for this site” is no longer offered for provisional drafts whose canonical entry only exists in that site.
  • Field values submitted for nested entries, Content Block fields, and addresses are now ignored if the user isn’t permitted to see or edit the fields, per their field layout conditions. (#20391)
  • Fixed an error that occurred when editing an address within a draft, if the owner element wasn’t saved in the primary site. (#20413)
  • United Kingdom administrative areas (counties) now come from commerceguys/addressing, and are stored by their ISO codes rather than their names. Existing UK addresses are migrated automatically, and Administrative Area condition rules that reference county names are normalized to the new codes. (#19488)

Entries

  • Added support for disabling Matrix entries for individual sites. (#19686)
  • Added the “Show the Post Date field” and “Show the Expiry Date field” entry type settings. Single and nested entries now have Post Date and Expiry Date fields too, unless their entry type hides them. (#17675)
  • Added support for controller actions and named Laravel routes in section and Matrix site settings, via a single “Route To” setting in place of Craft 5’s template setting, which suggests the app’s named routes and controller actions as well as templates. (#19762, #19942)
  • Collapsed Matrix blocks are now remembered per site, like their enabled status. (#20119)
  • Nested entry cards in revisions now have a violet “modified” bar when the entry was edited or added in that revision, as they already did in drafts.
  • “New entry” buttons now only offer the entry types and sections that CraftCms\Cms\Entry\Events\EntryTypesResolving listeners leave available for the site, instead of ones that then fail with a 400 error. (#20322)

Assets

  • Assets in more than one site can be compared between sites from the Sites panel, on the Compare screen, where field values can be copied from one site to the other. (#20384)
  • Added background uploads in the Assets index, which continue during control panel navigation, with persistent progress, retry, cancellation, and filename-conflict controls.
  • Images uploaded from the Assets index that look like copies of images that are already uploaded, even resized or recompressed, now wait within their upload notification, which shows the existing images’ chips and offers to cancel the upload, keep both, or replace the existing image’s file, like filename conflicts. (#20113)
  • Added Undo/Redo support and a “Revert to original” button to the image editor. (#19600)
  • The image editor now asks for confirmation in a dialog before discarding unsaved changes when it’s closed or reset to the original. (#20466)
  • Image thumbnails and previews in the control panel now show a blurred placeholder based on the image’s colors while they load. (#19750)
  • Asset previews now have “Download” and “Close” buttons, and text file previews have a “Copy” button. Image previews’ focal point toggle is now a “Focal Point” toggle button beside them, rather than a button laid over the image that only appeared on hover. (#20229)
  • Volumes now have a “Propagation Method” setting, which can be set to “Let each asset choose which sites it should be saved to”. New volumes default to it, as do existing volumes on single-site installs, while existing volumes on multi-site installs continue to save assets to all sites. Assets are now initially saved to the site they were uploaded from, and can be deleted for individual sites. (#20060)
  • Added the trashedAssetDisk config setting. When it’s set, soft-deleting an asset moves its file to that disk, and restoring the asset moves it back. Otherwise, soft-deleting an asset deletes its file, and the asset can’t be restored, unless it was deleted along with its volume. (#8745, #20093)
  • Images now keep the metadata embedded in their files when they’re uploaded, replaced, or indexed, such as their title, description, alt text, creator, copyright notice, keywords, date taken, camera, and location. Uploaded images are titled and given alt text from it, in each site’s language when the file has alt text in several, embedded keywords and descriptions are searchable, and asset edit pages’ Info panels show it along with the image’s type, its main colors, and a map of where it was taken. (#20103)
  • Asset indexes can now show “Image Type”, “Colors”, “Creator”, “Credit”, “Copyright”, “Date Taken”, “Camera”, and “Embedded Keywords” columns and card attributes. Asset indexes’ “Location” column and card attribute, which show an asset’s folder, are now “Folder”. (#20103)
  • Images uploaded straight to a remote filesystem, such as an S3 bucket, are no longer downloaded to be sampled, and uploads staged on an S3 disk are copied into their volume within S3 when the disks share credentials and an endpoint. (#20103)
  • Asset conditions, such as for index filters and Assets fields’ sources, now have an “Orientation” rule, which filters images by whether they’re landscape, portrait, or square. Images whose width and height differ by up to 2% count as square. (#20114)
  • Assets fields’ selector modals now list Temporary Uploads after the field’s restricted location, including when it’s a subfolder. (#20521)
  • Removed Craft-managed filesystems and their control panel settings. Volumes now reference Laravel filesystem disks configured in config/filesystems.php, and each defines whether its assets have public URLs. Existing filesystem references are migrated to matching disks automatically, with an actionable error if a disk isn’t configured, which suggests an equivalent disk for Local, Amazon S3, Google Cloud Storage, Azure Blob Storage, DigitalOcean Spaces, Linode Object Storage, and Cloudflare R2 filesystems. (#19650, #20471)
  • Added asset transformers, which are chosen per filesystem disk with an asset_transformer key on disks in config/filesystems.php, set to a transform driver name such as craft, or to an array with a driver key and inline settings. Disks without the key use the craft transformer, and scoped disks without it use the disk they wrap.
  • The craft asset transformer’s output disk, whether transforms have public URLs, and whether transforms are generated before page load can be set per disk, with output_disk, has_urls, and generate_transforms_before_page_load keys in its asset_transformer array. To store transforms below a path, set output_disk to a scoped disk. Without output_disk, transforms are stored at the root of the volume’s disk rather than below the volume’s subpath. Volumes’ “Transform Filesystem” and “Transform Subpath” settings aren’t carried over, so after upgrading from Craft 5, transforms are stored on the volume’s own disk unless its asset_transformer sets output_disk. Upgrading also clears the transform index, so transforms are generated again as they’re requested. Transform files generated by Craft 5 aren’t reused or deleted.
  • Moved the generateTransformsBeforePageLoad config setting to the craft asset transformer’s generate_transforms_before_page_load disk setting.
  • Added support for the libvips image driver via the optional intervention/image-driver-vips package.
  • Added BMP, HEIC, ICO, JPEG 2000, JPEG XL, and TIFF image transform formats, when supported by the active image driver.
  • Added the uploadSessionDisk config setting, which determines the disk used to stage upload sessions. (#19650)
  • Renamed the tempAssetUploadFs config setting to tempAssetUploadDisk, which now references a Laravel filesystem disk. (#19650)
  • Image assets now have BlurHash strings, available via asset.blurhash in templates. (#19755)
  • <img> tags returned by asset.getImg() now have a blurred placeholder as their background, unless the image has transparent regions. (#19750)
  • Added the blurhash, analysis, and placeholderDataUrl fields to assets in GraphQL queries. analysis holds what was found in an image, such as its colors, embedded metadata, and type. (#19740, #19750, #19755, #20103)
  • Images can now be queried by orientation via the orientation asset query param and GraphQL argument, and image assets’ orientations are available via asset.orientation in templates and the orientation GraphQL field. (#20114)
  • Fixed a bug where files uploaded to Assets fields when saving an element, such as from front-end forms, weren’t held to the maxUploadFileSize config setting, and were left behind as assets when the element couldn’t be saved because a file wasn’t allowed in the field.
  • Users can now save their own assets in their temporary upload folder.
  • Uploads to Assets fields with selection conditions are now checked against the asset’s final filename and location, and keep their custom field values once moved to the upload location.

Users & Auth

  • Users can now connect their accounts to one or more Laravel Socialite providers, which are listed on the login page. (#19202)
  • Added the authGuard and authPasswordBroker config settings, allowing Craft authentication to use a dedicated Laravel guard, provider, and password broker. (#19598)
  • The loginPath config setting is now false by default.
  • Added a My Account → Tokens screen, where users can create Laravel Passport personal access tokens with the scopes they choose from any of the APIs offered, behind an elevated session, rename them, and revoke them along with the apps they’ve authorized. It’s shown when an API offers personal access token scopes the user may grant, or when the user has authorized an app.
  • The My Account → Tokens screen is now only shown to admins when OAuth signing keys haven’t been set up yet, and explains how to set them up, rather than failing with a server error when a token is created. Requests to create tokens are rejected with a 400 error until the keys are set up. (#20357)
  • Fixed a bug where revoking the last token or authorized app on the My Account → Tokens screen led to a 403 error when the screen was no longer available, such as when GraphQL was disabled. (#20531)
  • Fixed a bug where password reset and email verification URLs generated from the console, such as with users/password-reset-url, always pointed to the front end, even for users with control panel access. (#16340)

Conditions

  • Added support for nested condition groups. (#19587)

Fields & Field Layouts

  • Added sidebar field layout tabs, whose fields are shown in element edit forms’ details sidebar. (#20005)
  • Field layout tabs can now have icons. (#20005)
  • Added a new core Markdown field type. (#18960)
  • Added a “Selectable {Type} Condition” setting to Link and Markdown fields’ Entry and Asset link types. (#19622)
  • Added a “Default Row Values” setting to Table fields. (#3621)
  • Table field columns are now configured with cell settings forms rather than JSON option inputs.
  • Table fields now have a “Link” column type, with the same settings as Link fields. Link cells return CraftCms\Cms\Field\Data\LinkData objects, and Table fields now track the elements they link to. (#16009, #19998)
  • Table field column settings now open in a slideout. (#19998)
  • Table fields’ Lightswitch, Checkbox, and Dropdown columns now take values pasted from a spreadsheet, and spreadsheet cells containing line breaks or tabs are pasted into a single cell.
  • Table cell validation errors now name the column. (#19998)
  • Table columns with invalid settings are now flagged in the Table field’s settings, and link setting validation errors in Link, Markdown, and Table fields now name the setting. (#19998)
  • Added support for configuring field layout field instruction positions.
  • Field layouts with a card view designer now show it and the content tab designer in “Content” and “Appearance” tabs, with Generated Fields in the Content tab. (#20001), (#20003)
  • Generated fields and entry title formats now show dates in their site’s locale, the way element cards show them, when their template outputs a date directly, such as {postDate} or a Date field’s {startDate}. Entry types’ UI label formats now show those dates the same way, in the user’s locale. Filters still get the date, so {startDate|date('Y')} works as before. Generated fields are now also rendered in their site’s language, like entry title formats. (#20467, #20526, #20527)
  • Entry types’ Icon and Color settings are now in their field layout designer’s Appearance tab, above Card Attributes. (#20001)
  • Card view designers’ previews now reflect the owner’s color, icon, and name, such as an entry type’s, as they’re edited. (#20001)
  • Entry type and user group descriptions, fields’ default instructions, tips, and warnings, and field layout elements’ instructions, tips, and warnings now have Markdown inputs. (#20001)
  • Removed the “Show unpermitted entries” setting from Entries, Link, and Markdown fields, in favor of the “Viewable” condition rule in the “Selectable Entries Condition” setting. (#19611, #19622)
  • Removed the “Show unpermitted files” and “Allowed File Types” settings from Assets, Link, and Markdown fields, in favor of “Viewable” and “File Type” condition rules in the “Selectable Assets Condition” setting. (#19611, #19622)
  • Card view designers’ “Thumbnail Source” setting is now “Thumb Sources”, where several fields can be chosen and ordered. Chips and cards show the thumbnail from the first one that has one. (#20156, #20181)
  • Entry types with an icon can now use it as a thumb source, by choosing “Entry type icon” in their “Thumb Sources” setting. The icon is shown faintly, in the entry type’s color if it has one, and sits beside the card’s content even when “Thumb Style” is set to “Cover”. (#20208, #20227)
  • Custom fields now have “Default Tip” and “Default Warning” settings. (#19976)
  • Relational fields now have a “Paste” button when the clipboard holds elements they could relate.
  • Copied elements are now put on the system clipboard as their titles, and links to their URLs in apps that take rich text, like copied relational field values. The “Copied” notification now matches copied field values’, with the elements’ chips side by side, and copying elements replaces a copied field value, and the reverse. Pressing Ctrl/Command + V within a relational or nested element field that can take the copied elements pastes them, as long as the clipboard still holds what was copied. (#20449)
  • Relational fields now have a “Thumb Size” setting, like element index View menus, with “Small”, “Medium”, and “Large” options for the List and Inline list view modes, plus “XL” and “2XL” for the Thumbs view mode. (#20257)
  • Read-only Markdown fields’ values can now be focused, selected, and scrolled, rather than being disabled. (#20109)
  • Markdown field layout elements’ content is now translated. (#20408)

Mail

  • Removed legacy projectConfig.email mail settings and mail transport adapter configuration in favor of Laravel's mail config and drivers.
  • With the Yii adapter installed, email is still sent through the mail transport adapter saved in the project config, including ones provided by plugins such as Mailgun and Postmark, until a Laravel mailer is selected in Settings → Email, set with MAIL_MAILER, or made the default in config/mail.php. It’s available as the craft-transport mailer, and is listed in the Yii2 Loose Ends utility while it’s in use. (#20502)
  • With the Yii adapter installed, Craft::$app->mailer now sends email from the sender in Settings → Email by default, rather than Laravel’s mail.from config. (#20504)

Accessibility

  • Links to other sites now show an external-link icon and tell screen readers that they open in a new window. (#20306)
  • Improved the accessibility of the control panel, including element indexes, element edit screens, and the login page. (#19025, #19520, #19699, #19749, #19785)
  • Added a “Skip to messages” link, and errors are now announced to screen readers immediately.
  • Action menu buttons no longer announce a menu pop-up.
  • Menu buttons without text or a label, such as the arrow half of split Save buttons on plugin screens, are now named “More actions” for screen readers. (#20576)
  • Error summaries now receive focus when a form fails validation, and each error links to its field, switching tabs if needed. (#20044)
  • The current user’s own First Name and Last Name fields, and the Full Name, First Name, Last Name, and Organization fields of their own addresses, now have autocomplete tokens, so browsers and password managers can fill them in. (#20407)

Administration

AI

  • Added Settings → Extend → Connections, where administrators choose the providers and models that plugins’ AI features use. Providers come from the ai.providers config, with keys set through environment variables. AI features stay off until a provider is chosen. (#20006)
  • Added the “AI assistant” and “Generate chat titles” AI tasks, and the “Use the AI assistant” user permission. Ask AI is available to users with the permission, once the “AI assistant” task has a provider. (#20109)
  • Added AI guidance: instructions the AI assistant and MCP clients follow when they work with content. Guidance for every site and for each site is edited in the new “AI Guidance & Skills” utility, and users can add their own on their account’s “AI Assistant” screen. (#20109)
  • The AI assistant can now see the image of an asset open in the editor, when its model supports vision. (#20109)
  • Added AI assistant skills: instructions for kinds of tasks, which are managed in the “AI Guidance & Skills” utility. The assistant follows a skill when a request matches it, or when the user chooses it by typing / in the chat. (#20109)
  • Added command palette actions for creating, editing, and deleting AI skills, for users who can use the AI Guidance & Skills utility. (#20109)
  • Added image analysis AI tasks: “Generate alt text”, “Generate titles”, “Detect focal points”, “Tag images”, and “Classify images”. Images are analyzed by the tasks that are set up when they’re uploaded or replaced, or when asset indexing finds a new or changed file, filling in only what they’re missing. Alt text that’s missing in some of an image’s sites is written as a translation of the alt text it already has. (#20103)
  • Added the “Analyze images” asset action, and an “Analyze images” option to the Asset Indexes utility and index-assets commands, which queue images to be analyzed. (#20103)
  • Alternative Text fields now have a “Generate alt text” action, which fills in suggested alt text for editors to review before saving. (#20103)
  • Assets can now be filtered by what kind of image they are, as found by the “Classify images” AI task, with the “Image Type” asset condition rule. (#20103)

MCP

  • Added authenticated and public Model Context Protocol (MCP) servers for inspecting and managing Craft sites, content, assets, users, plugins, and project config. Each can be enabled and given its own endpoint in Settings → MCP, and any active user can use the authenticated server. (#19846)
  • Added the mcp:read, mcp:write, and mcp:admin OAuth scopes for the authenticated MCP server. Users choose an access level when they authorize an MCP client, and it defaults to read only. (#20080)
  • MCP clients that users have authorized are listed on their My Account → Tokens screen, where they can be revoked. (#20291)
  • The OAuth authorization page now shows where the user will be redirected, and can no longer be displayed in a frame. (#20105)
  • The OAuth authorization page now names the client in its title, and shows the host the user will be redirected to. (#20296)
  • Names of dynamically-registered OAuth clients are now limited to 64 characters, with invisible, private-use, and unassigned characters removed, and names that look like “Craft”, “Craft CMS”, the system name, or a site name are rejected. (#20296)
  • Dynamic OAuth client registration is now limited to 10 clients per IP address per hour, via the oauth-registration rate limiter. (#20303)
  • Garbage collection now deletes expired and revoked OAuth authorization codes and tokens, and registered OAuth clients that were revoked or never authorized. (#20303)
  • The HTTP MCP servers are discoverable via /.well-known/ai-catalog.json and a Server Card at <endpoint>/server-card, per SEP-2127. Servers on control panel URLs are never advertised, and the authenticated server is only advertised when public registration is enabled. Discovery requests are subject to the defaultRateLimit config setting. (#20283)
  • Added the mcp:serve command, which serves the authenticated MCP server over stdio as a named user. (#19846)
  • Added the guidance_get, skills_list, and skills_get MCP tools, which return the AI guidance and skills. (#20109)
  • Added the guidance_update, skills_create, skills_update, and skills_delete MCP tools, which save the AI guidance for the sites the user can edit and manage skills, for users who can use the AI Guidance & Skills utility. (#20109)
  • Added the guidance_update_personal MCP tool, which saves the user’s own AI guidance. (#20109)
  • The MCP server’s elements_field_schema tool now says that Markdown fields take Markdown, rather than HTML. (#20109)
  • The elements_* MCP tools no longer list draft, revision, or structure criteria and attributes for element types that don’t support them, such as structure params for assets and users. (#20254)
  • MCP tools that set Matrix field values now add new entries after the existing ones when sortOrder is omitted, and reject a sortOrder that doesn’t list every new entry. (#20292)
  • MCP tools now accept times of day for Time fields within nested entries, and reject times they can’t parse. (#20319)
  • MCP tool input schemas now declare the items of relatedTo and notRelatedTo element query criteria, so strict MCP clients such as VS Code accept the search_query tool. (#20329)
  • The MCP server’s configuration tools can now manage control panel navigations, via the cp-navigations configuration type, which reads and writes each navigation as the tree the navigation builder edits. (#20247)
  • Added the user_permissions_user_update and user_permissions_group_update MCP tools, which add and remove specific permissions without resending complete lists. (#20437)
  • The configuration_get, configuration_list, configuration_create, and configuration_update MCP tools now return each record’s revision, and configuration_update and configuration_delete accept it as expectedRevision, failing without changing anything if the record has changed since it was read. Without expectedRevision, they can still overwrite changes made since the read. (#20438)
  • The assets_create and assets_replace MCP tools accept base64-encoded file data and local file paths (stdio server only, limited to project directories where a local volume could be located), in addition to download URLs. Download URLs don’t require a file_id, and follow up to 3 redirects, each validated against SSRF.
  • The assets_create and assets_upload_prepare MCP tools can upload files to an Assets field’s default upload location, via their fieldId and elementId arguments.
  • The assets_upload_prepare MCP tool is now available over stdio. Its uploads go to action URLs on APP_URL, authorized by a token returned for each upload, so stdio clients can upload files the server can’t read, such as files on the host of a container it runs in. (#20493)
  • The configuration_update MCP tool accepts field settings in the form that configuration_get returns them, such as Matrix fields’ entry types. (#20406)
  • MCP tools now return CKEditor field values, rather than empty arrays. Fields can implement CraftCms\Cms\Field\Contracts\McpOutputFieldInterface to control how their values are returned by MCP tools.
  • MCP clients can now sign in when the control panel has its own domain and no cpTrigger. (#20353)
  • MCP fields arguments accept dot paths, such as blocks.innerBlocks, which include nested fields of nested elements as {type, id, status} summaries. (#20415)
  • MCP tools return users’ addresses when addresses is included in fields. (#20415)
  • The elements_list, drafts_list, revisions_list, search_query, and craft_query MCP tools return all non-nested custom fields when fields is null. (#20463)
  • The asset_folders_list MCP tool accepts null for criteria.parentId, which lists volumes’ root folders. (#20464)
  • The authenticated MCP server returns an OAuth challenge to requests without an access token when OAuth signing keys haven’t been set up, so MCP clients can tell that it requires signing in, and Settings → MCP explains how to set up the keys. (#20455)
  • Updated mcp/sdk to 0.9. MCP tools that declare an outputSchema now return an error if their structured content doesn’t match it.

General

  • Replaced Craft’s system status with Laravel maintenance mode, including an admin-only Maintenance Mode control in General Settings.
  • Added support for Markdown-based custom Dashboard widgets in the application's resources/widgets/ directory. (#19319)
  • Added support for SQLite databases, including backups and restores. (#18803, #19149)
  • Added support for configuring the system time zone during installation. (#18794)
  • Added the Yii2 Loose Ends utility, which the Yii adapter registers. It lists what in the project still depends on the adapter, including configuration, content, project code that has run the adapter’s compatibility features, and plugins and packages that require or suggest it, along with any updates that no longer need it. Items can be fixed in place, updated, or copied as a prompt for an AI agent, and once nothing is left, the utility lists the steps to uninstall the adapter. (#20501)
  • Added the autoEagerLoadElements config setting (true by default), which determines whether element queries should be automatically lazy eager-loaded. (#19637)
  • Added the compiledTemplatesPath config setting. (#18861)
  • Added the defaultRateLimit and defaultRateLimitDuration config settings, which configure the rate limits for login, password reset, and two-step verification requests. (#20054)
  • Environment variable and alias settings fields now show suggestions after typing $ or @.
  • Terminal commands shown in the control panel and console output for the current environment now use the local development environment’s wrappers: ddev craft and ddev composer in DDEV, and valet php craft and valet composer for Laravel Valet sites isolated to a PHP version. This includes the Plugin Store’s installation instructions, which no longer have separate “Shell” and “DDEV” tabs, and the OAuth signing key instructions on the Settings → MCP and My Account → Tokens screens. (#20492)
  • The “Assets” settings nav item is now listed under “Content”, and “Globals”, “Categories”, and “Tags” are now listed under a new “Deprecated” heading, if those concepts are supported for the project. (#19670)
  • The System Messages utility now shows each message in a card, and edits messages in a slideout with a Markdown editor. Typing {{ in a message’s subject or body suggests the Twig variables it can use. (#19946)
  • Removed the isSystemLive config setting. Laravel maintenance mode should be used instead. With the Yii adapter installed, the deprecated craft:on and craft:off commands still work, and run up and down.
  • Removed the allowedGraphqlOrigins, disableGraphqlTransformDirective, enableBasicHttpAuth, enableTwigSandbox, omitScriptNameInUrls, pathParam, permissionsPolicyHeader, previewIframeResizerOptions, purgeStaleUserSessionDuration, requireMatchingUserAgentForSession, requireUserAgentAndIpForSession, useFileLocks, useIframeResizer, and usePathInfo config settings, which no longer have any effect.
  • Craft 5 config settings that were deprecated or removed are still accepted when the Yii adapter is installed, including from array-based general configs and environment variables, and are listed in the Yii2 Loose Ends utility when they’re set.

Development

Routing & URLs

  • Logging out now requires a CSRF-protected POST request. (#19252)
  • Base site URLs, including url(''), siteUrl(''), and homepage URLs, now respect the addTrailingSlashesToUrls config setting, so they no longer end with a trailing slash by default. The siteUrl Twig variable still always ends with a trailing slash. (#19723)
  • Updated paginated requests to resolve the current page from the configured pageTrigger query parameter rather than path-style pagination segments.
  • Craft no longer supports routes defined in a routes.php config file. Register routes using Laravel's routing instead. With the Yii adapter installed, site routes in config/craft/routes.php still work, but are deprecated.
  • Routes outside the craft middleware group can now use Route::allowDuringMaintenance() to stay reachable during maintenance mode. (#20095)
  • Requests to Craft’s site routes no longer start a session or send laravel_session and XSRF-TOKEN cookies for visitors without one, unless something writes to the session or puts its CSRF token in the response. Responses that don't need a session can then be stored by shared caches, such as CDNs. Requests that arrive with a session cookie are unaffected. For visitors without a session, back() and url()->previous() rely on the Referer header, so sites should send a Referrer-Policy such as same-origin or strict-origin-when-cross-origin (the browser default), not no-referrer.
  • Added Route::withLazySession(), which gives any route, such as a plugin’s or the host app’s own, the same lazy session as Craft’s site routes. Middleware that reads the session must come after StartSession in the middleware priority list, as lazy routes run their session middleware at that position rather than at its place in the web group. A StartSession subclass in the web group is still used.

Templates

  • It’s now possible to load Blade views within Twig templates. (#19148)
  • Craft now registers several Blade directives, bringing near feature parity with Twig templating. (#19148)
  • Improved Twig attribute access on Eloquent models to resolve missing and null attributes, casts, accessors, and relations through Eloquent property access, while preserving explicit method calls. (#20165)
  • Reference tags now support fallback values when no attribute is specified. (#17688)
  • Added the craftCommand() Twig function, which returns a Craft console command as it should be run for the current environment, such as ddev craft. (#20492)
  • Elements no longer include custom field values when iterated over. (#19004)
  • Element queries’ orderBy(), select(), and groupBy() now quote strings as column names, except rand() and random(), which use the database’s random function on MySQL, PostgreSQL, and SQLite alike. Any other SQL expression must be passed with expression() in Twig or DB::raw() in PHP; strings containing ( throw an exception explaining this. (#20190)
  • Element save requests no longer enable the element when no status is posted. Craft 5 resolved the status as enabled ?? (setEnabled ? true : null), so a POST carrying none of enabled, setEnabled, or enabledForSite force-enabled the element, and posting setEnabled=0 was how a request opted out of that. A posted status now decides on its own, and a save that doesn’t carry one leaves the element’s status untouched — which is what lets partial/delta saves keep a disabled element disabled. The setEnabled param has nothing left to suppress and is ignored.
  • Updated Twig {% paginate %} queries to use Laravel paginators and generate query-string pagination URLs based on the pageTrigger general config setting.
  • Added the |hexdec Twig filter, which converts a hexadecimal string to a decimal number. It replaces the Hexdec plugin, which can be uninstalled.
  • Added the |anchors Twig filter and @anchors GraphQL directive, which add linkable anchors to HTML headings, and the anchors config setting. They replace the Anchors plugin, which keeps working with the Yii adapter installed. To switch to core, uninstall the plugin, then remove its craftcms/anchors package. With the Yii adapter installed, the plugin’s config/craft/anchors.php file and craft\anchors\Plugin::getInstance()->parser API keep working afterward, but are deprecated.
  • Added |sanitize Twig filter for sanitizing HTML with CraftCms\Cms\Support\Facades\HtmlSanitizers.
  • Renamed the |money Twig filter’s formatLocale argument to locale.
  • Added the {% render %} Twig tag. {% render %} tags and render() methods are allowed within the Twig sandbox. (#19988)
  • Dates can now be output and passed to filters such as |date within the Twig sandbox.
  • Templates can now choose white or black text for legibility over an image or one of its edges, with asset.analysis.colors.textColor(), which also gives the text’s contrast ratio. (#20103)

GraphQL

  • GraphQL schemas can now include read-only components for sites, sections, entry types, volumes, and user groups, which add site fields to elements, volume fields to assets, and groups fields to users. (#20055)
  • Added the hasUrls field to volumes in GraphQL queries.
  • The GraphQL API now accepts Passport access tokens with the graphql:read or graphql:write scope, from personal access tokens created on My Account → Tokens or OAuth clients that users authorize. Requests made with them can query and change only the content that the token’s user has permission to access, and graphql:read tokens can’t run mutations. (#20231)
  • OAuth clients can discover and register for the GraphQL API on their own, and users choose “Read only” or “Read and write” access when they authorize one. (#20231)
  • Added the currentUser GraphQL query, which returns the user that authenticated the request with an access token. (#20231)
  • The level GraphQL argument is now a [QueryArgument], so it accepts the same values as the level element query param, such as ">= 2" or [1, 2]. Queries that pass it from an Int variable must declare the variable as [QueryArgument]. (#20209)
  • Address queries in GraphQL now accept the addressLine1, addressLine2, addressLine3, dependentLocality, field, fieldId, firstName, fullName, lastName, locality, organization, organizationTaxId, postalCode, primaryOwnerId, and sortingCode arguments, like the matching address query params. (#20251)
  • Added the canonicalId, canonicalUid, draftId, draftName, draftNotes, fieldId, isDraft, isUnpublishedDraft, ownerId, and sortOrder fields to addresses, and the sortOrder field to content blocks, in GraphQL queries. (#20251)
  • Element query argument descriptions in GraphQL, and the elements_* MCP tools’ query criteria descriptions, now name the element type, such as “the entries’ statuses”, rather than referring to “elements”. (#20250)
  • GraphQL mutations now return an error when new Matrix entries aren’t listed in sortOrder, rather than ignoring them, and each Matrix entry input can only specify one entry type. (#19965)
  • Authenticated GraphQL requests now respect field layout conditions. Fields that are hidden from the user are excluded from the schema, or resolve to null when their conditions are element-specific. Fields the user can’t edit are excluded from mutation arguments, or result in an error when set if their conditions are element-specific. (#20391)
  • OAuth discovery metadata for the GraphQL API no longer includes the request’s site token.

Debugging

  • Removed support for the Debug Toolbar. Laravel Debugbar can be used instead. (#18812)
  • Added “Elements” and “Deprecations” panels to Laravel Debugbar. (#18897)

Migrations

  • Craft and Yii's migrations have been removed in favor of Laravel migrations.
  • The php craft fields:merge and php craft entry-types:merge commands will now generate Laravel migrations.
  • Added CraftCms\Cms\Database\Migration::archiveTableIfExists(), the native equivalent of craft\db\Migration::archiveTableIfExists(). It also renames the archived table’s indexes and PostgreSQL sequence, and drops its foreign keys on MySQL, so install migrations can create the table again. Archived names are kept within the database’s identifier length limit, including the table prefix.
  • craft\db\Migration::archiveTableIfExists() no longer truncates archived table names to 10 characters, such as webhoo_old instead of webhookgroups_old.

Deprecations

  • Deprecated support for categories, global sets, and tags. (#18009)
  • Deprecated the elevatedSessionDuration general config setting. The auth.password_timeout config value should be used instead. To disable password confirmation (elevated sessions), you now set this value to -1 instead of 0.
  • Deprecated the errorTemplatePrefix general config setting. Error templates now go in an errors/ folder within the site templates, such as errors/404.twig, errors/_404.twig, or errors/404.blade.php, with errors/offline and errors/error as fallbacks, and a site’s own template folder takes precedence, such as resources/views/siteHandle/errors/404.twig. (#20448)
  • Deprecated the testToEmailAddress general config setting. Illuminate\Support\Facades\Mail::alwaysTo() should be used instead.
  • Deprecated the blowfishHashCost general config setting in favor of Laravel's hashing.bcrypt.rounds config or the BCRYPT_ROUNDS environment variable.
  • Deprecated the csrfTokenName, enableCsrfCookie, and enableCsrfProtection general config settings. (#18806)
  • Deprecated the defaultCookieDomain, phpSessionName, sameSiteCookieValue, useSecureCookies, and userSessionDuration general config settings. Laravel’s session config should be used instead.
  • Deprecated the rememberedUserSessionDuration and verificationCodeDuration general config settings. Laravel’s auth.guards.craft.remember and auth.passwords.craft.expire config values should be used instead.
  • Deprecated the secureHeaders, secureProtocolHeaders, and trustedHosts general config settings. Laravel’s trusted proxies should be configured instead.
  • Deprecated the devMode and securityKey general config settings. Laravel’s app.debug and app.key config values should be used instead.
  • Deprecated craft.app.config.general in Twig. app.config.craft.general should be used instead.
  • Deprecated craft.app.userPermissions. craft.userPermissions should be used instead.
  • Deprecated asset.setTransform(). asset.transform() should be used instead. With the Yii adapter installed, setTransform() still works on assets returned by Assets fields and asset queries, but the transform only applies to the asset’s URL, not its width, height, or getImg() output. (#20191)

System

  • The database table prefix is now set with the DB_PREFIX environment variable. When craftcms/yii2-adapter is installed, Craft 5’s CRAFT_DB_TABLE_PREFIX and DB_TABLE_PREFIX environment variables are still applied, with a trailing underscore. (#20192)
  • Replaced pixelandtonic/imagine with intervention/image for image manipulation.
  • Image assets now store color data sampled from their file when it’s uploaded, replaced, or indexed, including the image’s dominant color, a grid of the average colors of its regions, its main colors and how much of the image each covers, and how light its regions are. Control panel uploads sample it in the browser. (#19740, #19750, #20103)
  • Control panel resources are now provided by a craftcms/cms-assets package. (#19162)
  • Login attempts are now rate limited.
  • Two-factor authentication recovery codes are now encrypted at rest. (#19252)
  • MySQL database backups and restores now carry over SSL/TLS settings from the system’s MySQL option files, if the database connection doesn’t have any PDO::MYSQL_ATTR_SSL_* attributes set, and respect the PDO::MYSQL_ATTR_SSL_CAPATH and PDO::MYSQL_ATTR_SSL_CIPHER attributes. (#19366)
  • Fixed a bug where multi-instance fields’ search keywords were indexed per field rather than per instance, so searching by one instance’s handle could match other instances’ values. (#13991)
  • Garbage collection now always re-enables foreign key checks, even if it doesn’t finish. (#20386)
  • Fixed a bug where the PostgreSQL password could be included in the error message when a database backup or restore command failed. (#20503)
  • Fixed a bug where a failed project config YAML write left the config/project/ folder empty. Existing files are now only replaced as new ones are written, and the error now includes its underlying cause. (#20519)

Don't miss a new cms release

NewReleases is sending notifications on new releases.