Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Release Notes for Craft CMS 6

## Unreleased

> [!CAUTION]
> Breaking for current 6.x updated plugins:
> - Updated the plugin lifecycle to register and boot enabled `CraftCms\Cms\Plugin\Plugin` instances through the `CraftCms\Cms\Plugin\Plugins` service, allowing plugins to define normal Laravel `register()` and `boot()` methods.
> - Removed the previous overridable plugin lifecycle hooks (`CraftCms\Cms\Plugin\Plugin::registerPlugin()` and `CraftCms\Cms\Plugin\Plugin::bootPlugin()`), automatic plugin trait lifecycle hooks, and the `CraftCms\Cms\Plugin\Events\PluginUnregistered` event.
>
> For legacy plugins, the yii2-adapter should keep things working.

## 6.0.0-alpha.13 - 2026-07-16

- Updated logout routes to require CSRF-protected POST requests. ([#19252](https://github.com/craftcms/cms/pull/19252/changes/ff6f20717a48e7ede5fbbe47487e7bb8ef71da78))
Expand Down
7 changes: 5 additions & 2 deletions src/Console/Commands/Setup/PublishCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace CraftCms\Cms\Console\Commands\Setup;

use CraftCms\Cms\Console\CraftCommand;
use CraftCms\Cms\Plugin\Plugins;
use CraftCms\Cms\Support\File;
use Illuminate\Console\Command;
use Override;
Expand All @@ -18,18 +19,20 @@ class PublishCommand extends Command
protected $signature = 'craft:setup:publish';

#[Override]
protected $description = 'Publish Craft\'s assets and configuration files to your project.';
protected $description = 'Publish Craft and plugin assets and configuration files to your project.';

#[Override]
protected $aliases = ['setup/publish'];

public function handle(): void
public function handle(Plugins $plugins): void
{
$this->deletePublishedAssets();

$this->call('vendor:publish', ['--tag' => 'craftcms-assets', '--force' => true]);
$this->call('vendor:publish', ['--tag' => 'craftcms-config']);
$this->call('vendor:publish', ['--tag' => 'craftcms-console']);

$plugins->publishPluginAssets();
}

private function deletePublishedAssets(): void
Expand Down
3 changes: 1 addition & 2 deletions src/Plugin/Commands/InstallCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,7 @@ private function installAll(): int

private function switchEdition(string $handle, ?string $edition): int
{
/** @var PluginInterface $plugin */
$plugin = $this->plugins->getPlugin($handle);
$plugin = $this->plugins->getPlugin($handle) ?? throw new InvalidPluginException($handle);

if ($edition === null || $edition === $plugin->edition) {
$this->components->warn(sprintf(
Expand Down
32 changes: 6 additions & 26 deletions src/Plugin/Concerns/HasFrontendAssets.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,10 @@
namespace CraftCms\Cms\Plugin\Concerns;

use CraftCms\Cms\Plugin\Contracts\PluginInterface;
use CraftCms\Cms\Plugin\Events\PluginDisabling;
use CraftCms\Cms\Plugin\Events\PluginEnabling;
use CraftCms\Cms\Plugin\Events\PluginEvent;
use CraftCms\Cms\Plugin\Events\PluginInstalling;
use CraftCms\Cms\Plugin\Events\PluginUninstalling;
use CraftCms\Cms\Plugin\Plugin;
use CraftCms\Cms\Support\Arr;
use CraftCms\Cms\Support\File;
use CraftCms\Cms\Support\Str;
use Illuminate\Support\Facades\Event;

/**
* @mixin Plugin
Expand All @@ -39,29 +33,15 @@ trait HasFrontendAssets

protected array $scripts = [];

public function registerHasFrontendAssets(): void
public function publishFrontendAssets(): void
{
Event::listen([PluginEnabling::class, PluginInstalling::class], function (PluginEvent $event) {
if (! $event->plugin instanceof static) {
return;
}
if ($this->vite) {
[$source, $target] = $this->getSourceAndTarget($this, $this->vite);

if ($config = $event->plugin->vite) {
[$source, $target] = $this->getSourceAndTarget($event->plugin, $config);

File::copyDirectory($source, $this->app->publicPath($target));
}

$event->plugin->copyPublishableFiles($event->plugin->frontendAssetPublishPaths());
});

Event::listen([PluginDisabling::class, PluginUninstalling::class], function (PluginEvent $event) {
if (! $event->plugin instanceof static) {
return;
}
File::copyDirectory($source, $this->app->publicPath($target));
}

File::deleteDirectory(public_path("vendor/{$event->plugin->packageName}"));
});
$this->copyPublishableFiles($this->frontendAssetPublishPaths());
}

public function bootHasFrontendAssets(): void
Expand Down
25 changes: 2 additions & 23 deletions src/Plugin/Concerns/PublishesFiles.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,8 @@

namespace CraftCms\Cms\Plugin\Concerns;

use CraftCms\Cms\Plugin\Events\PluginDisabling;
use CraftCms\Cms\Plugin\Events\PluginEnabling;
use CraftCms\Cms\Plugin\Events\PluginEvent;
use CraftCms\Cms\Plugin\Events\PluginInstalling;
use CraftCms\Cms\Plugin\Events\PluginUninstalling;
use CraftCms\Cms\Plugin\Plugin;
use CraftCms\Cms\Support\File;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Event;

/**
* @mixin Plugin
Expand All @@ -29,23 +22,9 @@ trait PublishesFiles
*/
protected array $publishables = [];

public function registerPublishesFiles(): void
public function publishConfiguredFiles(): void
{
Event::listen([PluginEnabling::class, PluginInstalling::class], function (PluginEvent $event) {
if (! $event->plugin instanceof static) {
return;
}

$event->plugin->copyPublishableFiles($event->plugin->publishableFilePaths());
});

Event::listen([PluginDisabling::class, PluginUninstalling::class], function (PluginEvent $event) {
if (! $event->plugin instanceof static) {
return;
}

File::deleteDirectory(public_path("vendor/{$event->plugin->packageName}"));
});
$this->copyPublishableFiles($this->publishableFilePaths());
}

public function bootPublishesFiles(): void
Expand Down
10 changes: 10 additions & 0 deletions src/Plugin/Contracts/PluginInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use CraftCms\Cms\Cp\Navigation;
use CraftCms\Cms\Database\Migrator;
use CraftCms\Cms\Edition;
use CraftCms\Cms\Plugin\Plugins;
use CraftCms\Cms\Validation\Contracts\Validatable;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
Expand Down Expand Up @@ -154,6 +155,15 @@ public function install(): void;

public function uninstall(): void;

/** @internal */
public function bootPlugin(Plugins $plugins): void;

/** @internal */
public function publishAssets(): void;

/** @internal */
public function removeAssets(): void;

/**
* @return Migrator The plugin’s migrator
*/
Expand Down
14 changes: 0 additions & 14 deletions src/Plugin/Events/PluginUnregistered.php

This file was deleted.

76 changes: 34 additions & 42 deletions src/Plugin/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use CraftCms\Cms\Support\File;
use Illuminate\Contracts\Config\Repository;
use Illuminate\Support\ServiceProvider;
use LogicException;
use Override;
use ReflectionClass;

Expand Down Expand Up @@ -99,59 +100,50 @@ abstract class Plugin extends ServiceProvider implements PluginInterface

protected ?Plugins $pluginsService = null;

/**
* @internal
*/
#[Override]
public function register(): void
{
$this->setupTraits('register');
$this->registerPlugin();
}

/**
* @internal
*/
public function boot(Plugins $plugins): void
/** @internal */
final public function bootPlugin(Plugins $plugins): void
{
$this->pluginsService = $plugins;

$handle = $this->pluginsService->getPluginHandleByClass(static::class);

if (! $handle) {
return;
}

if (! $this->pluginsService->isPluginInstalled($handle)) {
return;
}
$this->bootHasCommands();
$this->bootHasConfig();
$this->bootHasElementTypes();
$this->bootHasFieldTypes();
$this->bootHasFrontendAssets();
$this->bootHasListeners();
$this->bootHasPermissions();
$this->bootHasRoutes();
$this->bootHasScheduling();
$this->bootHasTranslations();
$this->bootHasUtilities();
$this->bootHasViews();
$this->bootHasWidgets();
$this->bootPublishesFiles();
}

if (! $this->pluginsService->isPluginEnabled($handle)) {
return;
}
/** @internal */
final public function publishAssets(): void
{
$this->ensurePackageNameIsSet();

$this->setupTraits('boot');
$this->bootPlugin();
$this->publishFrontendAssets();
$this->publishConfiguredFiles();
}

private function setupTraits(string $method): void
/** @internal */
final public function removeAssets(): void
{
$usesRecursive = once(fn () => class_uses_recursive(static::class));
$this->ensurePackageNameIsSet();

collect($usesRecursive)
->map(fn (string $trait) => class_basename($trait))
->each(function (string $trait) use ($method) {
if (! method_exists($this, $method = "{$method}{$trait}")) {
return;
}

$this->$method();
});
File::deleteDirectory(public_path("vendor/{$this->packageName}"));
}

public function registerPlugin(): void {}

public function bootPlugin(): void {}
private function ensurePackageNameIsSet(): void
{
if ($this->packageName === null) {
throw new LogicException("Plugin [{$this->handle}] does not define a package name.");
}
}

protected function copyPublishableFiles(array $paths): void
{
Expand Down
75 changes: 0 additions & 75 deletions src/Plugin/PluginPackageManifest.php

This file was deleted.

Loading
Loading