From a531606ee67845ee0c5a9e491d0a3c46748fe35d Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 20:42:09 +0200 Subject: [PATCH 1/9] Recreate legacy app when it doesn't exist --- yii2-adapter/src/Http/LegacyMiddleware.php | 15 ++++++ .../src/Http/PrepareLegacyCraftApp.php | 53 +++++++++++++++++++ yii2-adapter/src/Yii2ServiceProvider.php | 3 ++ 3 files changed, 71 insertions(+) create mode 100644 yii2-adapter/src/Http/PrepareLegacyCraftApp.php diff --git a/yii2-adapter/src/Http/LegacyMiddleware.php b/yii2-adapter/src/Http/LegacyMiddleware.php index 04606a26e06..8d73fcefcec 100644 --- a/yii2-adapter/src/Http/LegacyMiddleware.php +++ b/yii2-adapter/src/Http/LegacyMiddleware.php @@ -53,6 +53,8 @@ public function handle(Request $request, Closure $next): mixed $this->restoreEmptyStrings($request); try { + $this->ensureCraftApp(); + /** @var \craft\web\Request $yiiRequest */ $yiiRequest = Craft::createObject(App::webRequestConfig()); $yiiRequest->csrfCookie = Craft::cookieConfig([], $yiiRequest); @@ -128,6 +130,19 @@ public static function cleanup(): void }); } + private function ensureCraftApp(): void + { + if (class_exists(Craft::class, false) && Craft::$app) { + return; + } + + $craftApp = $this->app->make('Craft'); + + if (!Craft::$app) { + Craft::$app = $craftApp; + } + } + private function restoreEmptyStrings(Request $request): void { $parameters = $request->isJson() diff --git a/yii2-adapter/src/Http/PrepareLegacyCraftApp.php b/yii2-adapter/src/Http/PrepareLegacyCraftApp.php new file mode 100644 index 00000000000..50dc65a1505 --- /dev/null +++ b/yii2-adapter/src/Http/PrepareLegacyCraftApp.php @@ -0,0 +1,53 @@ +restoreCraftApp(); + $this->refreshRequestScopedComponents($request); + + return $next($request); + } + + private function restoreCraftApp(): void + { + if (class_exists(Craft::class, false) && Craft::$app) { + return; + } + + $craftApp = $this->app->make('Craft'); + + if (!Craft::$app) { + Craft::$app = $craftApp; + } + } + + private function refreshRequestScopedComponents(Request $request): void + { + $this->app->instance('request', $request); + + /** @var \craft\web\Request $yiiRequest */ + $yiiRequest = Craft::createObject(App::webRequestConfig()); + $yiiRequest->csrfCookie = Craft::cookieConfig([], $yiiRequest); + + Craft::$app->set('request', $yiiRequest); + Craft::$app->set('view', Craft::createObject(App::viewConfig())); + Craft::$app->set('user', Craft::createObject(App::userConfig())); + } +} diff --git a/yii2-adapter/src/Yii2ServiceProvider.php b/yii2-adapter/src/Yii2ServiceProvider.php index c1ff190021f..fcb9ac83d34 100644 --- a/yii2-adapter/src/Yii2ServiceProvider.php +++ b/yii2-adapter/src/Yii2ServiceProvider.php @@ -28,12 +28,14 @@ use CraftCms\Yii2Adapter\HtmlPurifier\LegacyHtmlPurifierConfigRegistrar; use CraftCms\Yii2Adapter\Http\CaptureOriginalActionRequestUri; use CraftCms\Yii2Adapter\Http\LegacyMiddleware; +use CraftCms\Yii2Adapter\Http\PrepareLegacyCraftApp; use CraftCms\Yii2Adapter\I18N\I18NCompatibility; use CraftCms\Yii2Adapter\Mail\TestToEmailAddressCompatibility; use CraftCms\Yii2Adapter\Mixins\CraftVariableMixin; use Illuminate\Contracts\Debug\ExceptionHandler; use Illuminate\Contracts\Http\Kernel as HttpKernel; use Illuminate\Foundation\Exceptions\Handler; +use Illuminate\Routing\Router; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Config; use Illuminate\Support\Facades\Event; @@ -182,6 +184,7 @@ private function toLegacyException(Throwable $exception): Throwable public function boot(): void { $this->app->make(HttpKernel::class)->prependMiddleware(CaptureOriginalActionRequestUri::class); + $this->app->make(Router::class)->pushMiddlewareToGroup('craft', PrepareLegacyCraftApp::class); $this->commands([ AddCategoriesSupportCommand::class, From ab1777943cdcb117a7e379f98a54ac0d31e862a2 Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 20:42:35 +0200 Subject: [PATCH 2/9] Register CP template roots in middleware --- src/Http/Middleware/HandleTemplateRequest.php | 19 +++++++++++++++ src/View/ViewServiceProvider.php | 23 ------------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/Http/Middleware/HandleTemplateRequest.php b/src/Http/Middleware/HandleTemplateRequest.php index 71d0cd981ce..42bc88f5975 100644 --- a/src/Http/Middleware/HandleTemplateRequest.php +++ b/src/Http/Middleware/HandleTemplateRequest.php @@ -10,7 +10,9 @@ use CraftCms\Cms\Route\DynamicRoute; use CraftCms\Cms\Site\Sites; use CraftCms\Cms\Twig\TemplateResolver; +use CraftCms\Cms\View\TemplateMode; use Illuminate\Http\Request; +use Illuminate\View\Factory as ViewFactory; use Symfony\Component\HttpFoundation\Response; readonly class HandleTemplateRequest @@ -18,10 +20,18 @@ public function __construct( private TemplateResolver $templateResolver, private Sites $sites, + private ViewFactory $views, ) {} public function handle(Request $request, Closure $next): mixed { + if ($request->isCpRequest()) { + TemplateMode::set(TemplateMode::Cp); + + $this->prependViewLocation(dirname(__DIR__, 3).'/resources/templates'); + $this->prependViewLocation(dirname(__DIR__, 3).'/resources/views'); + } + $response = $next($request); if ($request->isSiteRequest() && Cms::config()->headlessMode) { @@ -59,6 +69,15 @@ public function handle(Request $request, Closure $next): mixed return new DynamicRoute('templates/render', ['template' => $path])->handle($request); } + private function prependViewLocation(string $path): void + { + if (in_array($path, $this->views->getFinder()->getPaths(), true)) { + return; + } + + $this->views->prependLocation($path); + } + private function isPublicTemplatePath(Request $request, string $path): bool { // If privateTemplateTrigger is set to an empty value, disable all public template routing diff --git a/src/View/ViewServiceProvider.php b/src/View/ViewServiceProvider.php index 0e7e584d066..730797c678a 100644 --- a/src/View/ViewServiceProvider.php +++ b/src/View/ViewServiceProvider.php @@ -52,19 +52,6 @@ public function boot(TemplateHooks $hooks): void $hooks->register('cp.layouts.elementindex', PrepareElementIndexVariables::class); $hooks->register('cp.elements.toolbar', PrepareElementToolbarVariables::class); $hooks->register('cp.elements.sources', PrepareElementSourcesVariables::class); - - $this->app->booted(function () { - /** - * This ensures that when Laravel tries to find an error view, - * it will look in the CP templates for it as well. - */ - if (request()->isCpRequest()) { - config()->set('view.paths', array_merge( - config('view.paths'), - [dirname(__DIR__, 2).'/resources/templates'] - )); - } - }); } private function registerTemplateGlobals(): void @@ -82,16 +69,6 @@ private function registerTemplateRoots(): void /** @var Factory $factory */ $factory = $this->app->make(ViewFactory::class); - /** - * Prepend the Craft CMS Control panel views when - * we're in CP Template mode. This makes view() - * work without a 'craftcms::' prefix. - */ - if (TemplateMode::is(TemplateMode::Cp)) { - $factory->prependLocation("{$this->root}/resources/templates"); - $factory->prependLocation("{$this->root}/resources/views"); - } - foreach (TemplateMode::get()->templateRoots() as $namespace => $roots) { $factory->addNamespace($namespace, $roots); From 9a61a610051db2e7af0d0ca8fd2204751ce15468 Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 20:45:48 +0200 Subject: [PATCH 3/9] Register hooks in middleware --- src/Http/Middleware/HandleTemplateRequest.php | 14 ++++++++++++++ src/View/ViewServiceProvider.php | 8 +------- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/Http/Middleware/HandleTemplateRequest.php b/src/Http/Middleware/HandleTemplateRequest.php index 42bc88f5975..49e83c289b0 100644 --- a/src/Http/Middleware/HandleTemplateRequest.php +++ b/src/Http/Middleware/HandleTemplateRequest.php @@ -10,6 +10,10 @@ use CraftCms\Cms\Route\DynamicRoute; use CraftCms\Cms\Site\Sites; use CraftCms\Cms\Twig\TemplateResolver; +use CraftCms\Cms\View\Hooks\PrepareElementIndexVariables; +use CraftCms\Cms\View\Hooks\PrepareElementSourcesVariables; +use CraftCms\Cms\View\Hooks\PrepareElementToolbarVariables; +use CraftCms\Cms\View\TemplateHooks; use CraftCms\Cms\View\TemplateMode; use Illuminate\Http\Request; use Illuminate\View\Factory as ViewFactory; @@ -30,6 +34,7 @@ public function handle(Request $request, Closure $next): mixed $this->prependViewLocation(dirname(__DIR__, 3).'/resources/templates'); $this->prependViewLocation(dirname(__DIR__, 3).'/resources/views'); + $this->registerCpTemplateHooks(); } $response = $next($request); @@ -78,6 +83,15 @@ private function prependViewLocation(string $path): void $this->views->prependLocation($path); } + private function registerCpTemplateHooks(): void + { + $hooks = app(TemplateHooks::class); + + $hooks->register('cp.layouts.elementindex', PrepareElementIndexVariables::class); + $hooks->register('cp.elements.toolbar', PrepareElementToolbarVariables::class); + $hooks->register('cp.elements.sources', PrepareElementSourcesVariables::class); + } + private function isPublicTemplatePath(Request $request, string $path): bool { // If privateTemplateTrigger is set to an empty value, disable all public template routing diff --git a/src/View/ViewServiceProvider.php b/src/View/ViewServiceProvider.php index 730797c678a..87d386a4b74 100644 --- a/src/View/ViewServiceProvider.php +++ b/src/View/ViewServiceProvider.php @@ -5,9 +5,6 @@ namespace CraftCms\Cms\View; use CraftCms\Cms\View\Events\ViewAssetsRendering; -use CraftCms\Cms\View\Hooks\PrepareElementIndexVariables; -use CraftCms\Cms\View\Hooks\PrepareElementSourcesVariables; -use CraftCms\Cms\View\Hooks\PrepareElementToolbarVariables; use CraftCms\Cms\View\LegacyAssets\InternalAssetRegistry; use Illuminate\Contracts\View\Factory as ViewFactory; use Illuminate\Support\Facades\Event; @@ -33,7 +30,7 @@ public function register(): void ); } - public function boot(TemplateHooks $hooks): void + public function boot(): void { Event::listen(function (ViewAssetsRendering $event) { app(InternalAssetRegistry::class)->flush(); @@ -49,9 +46,6 @@ public function boot(TemplateHooks $hooks): void $this->registerTemplateRoots(); $this->registerTemplateGlobals(); - $hooks->register('cp.layouts.elementindex', PrepareElementIndexVariables::class); - $hooks->register('cp.elements.toolbar', PrepareElementToolbarVariables::class); - $hooks->register('cp.elements.sources', PrepareElementSourcesVariables::class); } private function registerTemplateGlobals(): void From 9fcee9c30b45cbe088a52851281d94aed427f4f8 Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 20:54:24 +0200 Subject: [PATCH 4/9] Fix phpstan --- src/Http/Middleware/HandleTemplateRequest.php | 5 ++++- yii2-adapter/legacy/mail/Mailer.php | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Http/Middleware/HandleTemplateRequest.php b/src/Http/Middleware/HandleTemplateRequest.php index 49e83c289b0..e94af3fb737 100644 --- a/src/Http/Middleware/HandleTemplateRequest.php +++ b/src/Http/Middleware/HandleTemplateRequest.php @@ -17,6 +17,7 @@ use CraftCms\Cms\View\TemplateMode; use Illuminate\Http\Request; use Illuminate\View\Factory as ViewFactory; +use Illuminate\View\FileViewFinder; use Symfony\Component\HttpFoundation\Response; readonly class HandleTemplateRequest @@ -76,7 +77,9 @@ public function handle(Request $request, Closure $next): mixed private function prependViewLocation(string $path): void { - if (in_array($path, $this->views->getFinder()->getPaths(), true)) { + $finder = $this->views->getFinder(); + + if ($finder instanceof FileViewFinder && in_array($path, $finder->getPaths(), true)) { return; } diff --git a/yii2-adapter/legacy/mail/Mailer.php b/yii2-adapter/legacy/mail/Mailer.php index 62b70309f55..a2ce066eadc 100644 --- a/yii2-adapter/legacy/mail/Mailer.php +++ b/yii2-adapter/legacy/mail/Mailer.php @@ -179,7 +179,12 @@ public function send($message): bool $message->language = $rendered->language; $message->setSubject($rendered->subject); - $message->setTextBody(view('mail.system-message-text', $formatted->viewData)->render()); + $textView = resource_path('views/mail/system-message-text.blade.php'); + if (!file_exists($textView)) { + throw new InvalidConfigException("The `$textView` view file does not exist."); + } + + $message->setTextBody(view()->file($textView, $formatted->viewData)->render()); $message->setHtmlBody($formatted->htmlBody); } From d23d7df423859bb027a2f1d485f401dfa557698d Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 20:59:28 +0200 Subject: [PATCH 5/9] Just add a phpstan-ignore --- yii2-adapter/legacy/mail/Mailer.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/yii2-adapter/legacy/mail/Mailer.php b/yii2-adapter/legacy/mail/Mailer.php index a2ce066eadc..b2319df0f0b 100644 --- a/yii2-adapter/legacy/mail/Mailer.php +++ b/yii2-adapter/legacy/mail/Mailer.php @@ -179,12 +179,7 @@ public function send($message): bool $message->language = $rendered->language; $message->setSubject($rendered->subject); - $textView = resource_path('views/mail/system-message-text.blade.php'); - if (!file_exists($textView)) { - throw new InvalidConfigException("The `$textView` view file does not exist."); - } - - $message->setTextBody(view()->file($textView, $formatted->viewData)->render()); + $message->setTextBody(view('mail.system-message-text', $formatted->viewData)->render()); // @phpstan-ignore argument.type $message->setHtmlBody($formatted->htmlBody); } From 0c4393fd062c45209d7e4181365d66b92c06bcef Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 21:38:51 +0200 Subject: [PATCH 6/9] Refactor --- src/Http/Middleware/HandleTemplateRequest.php | 36 ------------------- src/Http/Middleware/RequireCpRequest.php | 13 +++++++ src/View/TemplateMode.php | 21 +++++++++++ src/View/ViewServiceProvider.php | 1 - 4 files changed, 34 insertions(+), 37 deletions(-) diff --git a/src/Http/Middleware/HandleTemplateRequest.php b/src/Http/Middleware/HandleTemplateRequest.php index e94af3fb737..71d0cd981ce 100644 --- a/src/Http/Middleware/HandleTemplateRequest.php +++ b/src/Http/Middleware/HandleTemplateRequest.php @@ -10,14 +10,7 @@ use CraftCms\Cms\Route\DynamicRoute; use CraftCms\Cms\Site\Sites; use CraftCms\Cms\Twig\TemplateResolver; -use CraftCms\Cms\View\Hooks\PrepareElementIndexVariables; -use CraftCms\Cms\View\Hooks\PrepareElementSourcesVariables; -use CraftCms\Cms\View\Hooks\PrepareElementToolbarVariables; -use CraftCms\Cms\View\TemplateHooks; -use CraftCms\Cms\View\TemplateMode; use Illuminate\Http\Request; -use Illuminate\View\Factory as ViewFactory; -use Illuminate\View\FileViewFinder; use Symfony\Component\HttpFoundation\Response; readonly class HandleTemplateRequest @@ -25,19 +18,10 @@ public function __construct( private TemplateResolver $templateResolver, private Sites $sites, - private ViewFactory $views, ) {} public function handle(Request $request, Closure $next): mixed { - if ($request->isCpRequest()) { - TemplateMode::set(TemplateMode::Cp); - - $this->prependViewLocation(dirname(__DIR__, 3).'/resources/templates'); - $this->prependViewLocation(dirname(__DIR__, 3).'/resources/views'); - $this->registerCpTemplateHooks(); - } - $response = $next($request); if ($request->isSiteRequest() && Cms::config()->headlessMode) { @@ -75,26 +59,6 @@ public function handle(Request $request, Closure $next): mixed return new DynamicRoute('templates/render', ['template' => $path])->handle($request); } - private function prependViewLocation(string $path): void - { - $finder = $this->views->getFinder(); - - if ($finder instanceof FileViewFinder && in_array($path, $finder->getPaths(), true)) { - return; - } - - $this->views->prependLocation($path); - } - - private function registerCpTemplateHooks(): void - { - $hooks = app(TemplateHooks::class); - - $hooks->register('cp.layouts.elementindex', PrepareElementIndexVariables::class); - $hooks->register('cp.elements.toolbar', PrepareElementToolbarVariables::class); - $hooks->register('cp.elements.sources', PrepareElementSourcesVariables::class); - } - private function isPublicTemplatePath(Request $request, string $path): bool { // If privateTemplateTrigger is set to an empty value, disable all public template routing diff --git a/src/Http/Middleware/RequireCpRequest.php b/src/Http/Middleware/RequireCpRequest.php index 588576ce3bf..9cbe212343d 100644 --- a/src/Http/Middleware/RequireCpRequest.php +++ b/src/Http/Middleware/RequireCpRequest.php @@ -5,6 +5,10 @@ namespace CraftCms\Cms\Http\Middleware; use Closure; +use CraftCms\Cms\Support\Facades\TemplateHooks; +use CraftCms\Cms\View\Hooks\PrepareElementIndexVariables; +use CraftCms\Cms\View\Hooks\PrepareElementSourcesVariables; +use CraftCms\Cms\View\Hooks\PrepareElementToolbarVariables; use CraftCms\Cms\View\TemplateMode; use Illuminate\Http\Request; @@ -18,6 +22,15 @@ public function handle(Request $request, Closure $next): mixed TemplateMode::set(TemplateMode::Cp); + $this->registerCpTemplateHooks(); + return $next($request); } + + private function registerCpTemplateHooks(): void + { + TemplateHooks::register('cp.layouts.elementindex', PrepareElementIndexVariables::class); + TemplateHooks::register('cp.elements.toolbar', PrepareElementToolbarVariables::class); + TemplateHooks::register('cp.elements.sources', PrepareElementSourcesVariables::class); + } } diff --git a/src/View/TemplateMode.php b/src/View/TemplateMode.php index 4ba607d62e0..98dc8621531 100644 --- a/src/View/TemplateMode.php +++ b/src/View/TemplateMode.php @@ -31,6 +31,27 @@ public static function get(): self public static function set(self $mode): void { Context::addHidden(self::class, $mode); + + if ($mode === self::Cp) { + /** + * Prepend the Craft CMS Control panel views when + * we're in CP Template mode. This makes view() + * work without a 'craftcms::' prefix. + */ + if (TemplateMode::is(TemplateMode::Cp)) { + $templates = dirname(__DIR__, 2).'/resources/templates'; + $views = dirname(__DIR__, 2).'/resources/views'; + $finder = view()->getFinder(); + + if (! in_array($templates, $finder->getPaths())) { + $finder->prependLocation($templates); + } + + if (! in_array($views, $finder->getPaths())) { + $finder->prependLocation($views); + } + } + } } public static function is(self $mode): bool diff --git a/src/View/ViewServiceProvider.php b/src/View/ViewServiceProvider.php index 87d386a4b74..a3c91352c83 100644 --- a/src/View/ViewServiceProvider.php +++ b/src/View/ViewServiceProvider.php @@ -45,7 +45,6 @@ public function boot(): void $this->registerTemplateRoots(); $this->registerTemplateGlobals(); - } private function registerTemplateGlobals(): void From fad30ccf01e82e089210aa5b2cd7de6c715eba04 Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 21:41:42 +0200 Subject: [PATCH 7/9] Phpstan fixes (again) --- src/View/TemplateMode.php | 3 +++ yii2-adapter/legacy/mail/Mailer.php | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/View/TemplateMode.php b/src/View/TemplateMode.php index 98dc8621531..df7f7bf97f7 100644 --- a/src/View/TemplateMode.php +++ b/src/View/TemplateMode.php @@ -9,6 +9,7 @@ use CraftCms\Cms\View\Events\CpTemplateRootsResolving; use CraftCms\Cms\View\Events\SiteTemplateRootsResolving; use Illuminate\Support\Facades\Context; +use Illuminate\View\FileViewFinder; enum TemplateMode: string { @@ -41,6 +42,8 @@ public static function set(self $mode): void if (TemplateMode::is(TemplateMode::Cp)) { $templates = dirname(__DIR__, 2).'/resources/templates'; $views = dirname(__DIR__, 2).'/resources/views'; + + /** @var FileViewFinder $finder */ $finder = view()->getFinder(); if (! in_array($templates, $finder->getPaths())) { diff --git a/yii2-adapter/legacy/mail/Mailer.php b/yii2-adapter/legacy/mail/Mailer.php index b2319df0f0b..62b70309f55 100644 --- a/yii2-adapter/legacy/mail/Mailer.php +++ b/yii2-adapter/legacy/mail/Mailer.php @@ -179,7 +179,7 @@ public function send($message): bool $message->language = $rendered->language; $message->setSubject($rendered->subject); - $message->setTextBody(view('mail.system-message-text', $formatted->viewData)->render()); // @phpstan-ignore argument.type + $message->setTextBody(view('mail.system-message-text', $formatted->viewData)->render()); $message->setHtmlBody($formatted->htmlBody); } From 770a27950443f1e4756e9f9117f16331b537cbc7 Mon Sep 17 00:00:00 2001 From: Rias Date: Tue, 19 May 2026 21:49:59 +0200 Subject: [PATCH 8/9] Fix element index test --- src/Http/Middleware/RequireCpRequest.php | 2 +- tests/Feature/Cp/ElementIndexHtmlTest.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Http/Middleware/RequireCpRequest.php b/src/Http/Middleware/RequireCpRequest.php index 9cbe212343d..e5e50f83e82 100644 --- a/src/Http/Middleware/RequireCpRequest.php +++ b/src/Http/Middleware/RequireCpRequest.php @@ -27,7 +27,7 @@ public function handle(Request $request, Closure $next): mixed return $next($request); } - private function registerCpTemplateHooks(): void + public function registerCpTemplateHooks(): void { TemplateHooks::register('cp.layouts.elementindex', PrepareElementIndexVariables::class); TemplateHooks::register('cp.elements.toolbar', PrepareElementToolbarVariables::class); diff --git a/tests/Feature/Cp/ElementIndexHtmlTest.php b/tests/Feature/Cp/ElementIndexHtmlTest.php index 404a7b7efe7..781ea8c3461 100644 --- a/tests/Feature/Cp/ElementIndexHtmlTest.php +++ b/tests/Feature/Cp/ElementIndexHtmlTest.php @@ -4,12 +4,15 @@ use CraftCms\Cms\Cp\Html\ElementIndexHtml; use CraftCms\Cms\Entry\Elements\Entry; +use CraftCms\Cms\Http\Middleware\RequireCpRequest; use CraftCms\Cms\User\Elements\User; use function Pest\Laravel\actingAs; beforeEach(function () { actingAs(User::findOne()); + + app(RequireCpRequest::class)->registerCpTemplateHooks(); }); it('renders an element index shell with toolbar and elements container', function () { From a2513386945bc35a2b90880b9f33e17de7de7582 Mon Sep 17 00:00:00 2001 From: Rias Date: Wed, 20 May 2026 09:08:35 +0200 Subject: [PATCH 9/9] Changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dbf0d7fc36..079c7758985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Release Notes for Craft CMS 6 +## Unreleased + +- Fixed some errors that could occur when running Craft through Laravel Octane ([#18921](https://github.com/craftcms/cms/pull/18921)) + ## 6.0.0-alpha.4 - 2026-05-19 - Added support for plugins to register Laravel scheduled tasks that run via `php artisan schedule:run`.