You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/5.x/extend/commands.md
+20-11
Original file line number
Diff line number
Diff line change
@@ -1,3 +1,7 @@
1
+
---
2
+
sidebarDepth: 2
3
+
---
4
+
1
5
# Console Commands
2
6
3
7
Plugins and modules can add additional [console commands](../reference/cli.md)
@@ -11,10 +15,9 @@ For the most part, writing console commands for Craft is identical to writing co
11
15
12
16
## Module Setup
13
17
14
-
If you are adding console commands to a custom module, make sure that your module class defines its root `controllerNamespace` for console requests:
18
+
Plugins are [automatically configured](plugin-guide.md#automatic-defaults)to locate web and console controllers. Modules, on the other hand, must explicitly define their root `controllerNamespace` for both request types:
15
19
16
-
```php{14,15}
17
-
<?php
20
+
```php{13-17}
18
21
namespace acme;
19
22
20
23
use Craft;
@@ -23,25 +26,25 @@ class Module extends \yii\base\Module
23
26
{
24
27
public function init()
25
28
{
26
-
// Define a custom alias named after the namespace
29
+
// Define a custom alias named after the namespace:
27
30
Craft::setAlias('@acme', __DIR__);
28
31
29
-
// Set the controllerNamespace based on whether this is a console or web request
32
+
// Set the controllerNamespace based on whether this is a console or web request:
30
33
if (Craft::$app->getRequest()->getIsConsoleRequest()) {
You’ll also need to make sure your module is getting [bootstrapped](guide:runtime-bootstrapping)
44
-
from `config/app.php` (or `config/app.console.php`):
47
+
You’ll also need to make sure your module is getting [bootstrapped](guide:runtime-bootstrapping) on every request from `config/app.php` (or `config/app.console.php`):
45
48
46
49
```php{2}
47
50
return [
@@ -59,8 +62,6 @@ Any classes within the folder corresponding to your [`controllerNamespace` setti
59
62
Create `GreetController.php` in `modules/console/controllers/`, with this content:
60
63
61
64
```php
62
-
<?php
63
-
64
65
namespace modules\console\controllers;
65
66
66
67
use craft\console\Controller;
@@ -112,7 +113,7 @@ class GreetController extends Controller
112
113
113
114
### Running Actions
114
115
115
-
Supposing your module ID or plugin handle was `acme`, you would access your controller like this:
116
+
Supposing your [module ID](module-guide.md#preparation) or plugin handle was `acme`, you would access your controller like this:
In the example, we’ve declared a public class property, and set up a mapping for the single _action ID_. Any [option](guide:tutorial-console#options) can be set using bash’s familiar `--kebab-case-option-name` syntax.
135
+
136
+
::: tip
137
+
Use the [`optionAliases()` method](guide:tutorial-console#options-aliases) to define shorthand options like `-m`.
138
+
:::
139
+
131
140
### Arguments
132
141
133
142
Actions can declare arguments that will be processed from the command’s input. Arguments are separated by spaces, and the values are processed according to their declared types:
Copy file name to clipboardExpand all lines: docs/5.x/extend/plugin-guide.md
+91-53
Original file line number
Diff line number
Diff line change
@@ -100,7 +100,7 @@ Create a `composer.json` file at the root of your plugin directory, and use this
100
100
}
101
101
```
102
102
103
-
Replace:
103
+
Review and replace the following values:
104
104
105
105
-`package/name` with your package name.
106
106
-`Developer Name` with your name, or the organization name that the plugin should be attributed to.
@@ -111,24 +111,22 @@ Replace:
111
111
-`namespace\\prefix\\` with your namespace prefix. (Use double-backslashes because this is JSON, and note this must end with `\\`.)
112
112
-`Plugin Name` with your plugin name.
113
113
-`my-plugin-handle` with your plugin handle.
114
-
-`MIT` with `proprietary` if you plan to use [Craft License](https://craftcms.github.io/license/) (see [Choose a License](plugin-store.md#choose-a-license) on the “Publishing to the Plugin Store” page).
114
+
-`MIT` with `proprietary` if you plan to use [Craft License](https://craftcms.github.io/license/). Read more about [choosing a license](plugin-store.md#choose-a-license).
115
115
116
-
In addition to `name` and `handle` (which are both required), there are a few other things you can include in that`extra`object:
116
+
In addition to `name` and `handle` (both of which are required), there are a few other things you can include under the`extra`key:
117
117
118
-
-`class`– The [Plugin class](#the-plugin-class) name. If not set, the installer will look for a `Plugin.php` file at each of the`autoload` path roots.
119
-
-`description`– The plugin description. If not set, the main `description` property will be used.
120
-
-`developer`– The developer name. If not set, the first author’s `name` will be used (via the `authors` property).
121
-
-`developerUrl`– The developer URL. If not set, the `homepage` property will be used, or the first author’s `homepage` (via the `authors` property).
122
-
-`developerEmail`– The support email. If not set, the `support.email` property will be used.
123
-
-`documentationUrl`– The plugin’s documentation URL. If not set, the `support.docs` property will be used.
118
+
-`class`— The [main plugin class](#the-plugin-class) name. If not set, the installer will look for a `Plugin.php` file at the root of each`autoload` path.
119
+
-`description`— A brief description of your plugin’s purpose. If not set, the main `description` property will be used.
120
+
-`developer`— The developer name. If not set, the first author’s `name` will be used (via the `authors` property).
121
+
-`developerUrl`— The developer URL. If not set, the `homepage` property will be used, or the first author’s `homepage` (via the `authors` property).
122
+
-`developerEmail`— The support email. If not set, the `support.email` property will be used.
123
+
-`documentationUrl`— The plugin’s documentation URL. If not set, the `support.docs` property will be used.
124
124
125
-
::: warning
126
-
If you’re updating a Craft 2 plugin, make sure to remove the `composer/installers` dependency if it has one.
127
-
:::
125
+
Some of these values are displayed in the Craft control panel (in <Journeypath="Settings, Plugins" />—[see below](#plugin-icons) for an example) and used to auto-populate a handful of fields when you begin the Plugin Store submission process. We encourage you to provide a more thorough description—or update its details any time thereafter—via [Craft Console](kb:what-is-craft-console)—descriptions and URLs are _not_ synchronized again.
128
126
129
127
## The Plugin Class
130
128
131
-
The `src/Plugin.php` file is your plugin’s entry point for the system. It will get instantiated at the beginning of every request. Its `init()` methodis the best place to register event listeners, and any other steps it needs to take to initialize itself.
129
+
The `src/Plugin.php` file is your plugin’s entry point for the system. Craft instantiates a singleton of your plugin class at the beginning of every request, [invoking its `init()` method](#initialization). This is the best place to register [event listeners](events.md), and perform any other setup steps.
132
130
133
131
Use this template as a starting point for your `Plugin.php` file:
134
132
@@ -146,6 +144,17 @@ class Plugin extends \craft\base\Plugin
146
144
}
147
145
```
148
146
147
+
::: warning
148
+
Don’t move or rename this class or file after [publishing](plugin-store.md) a plugin. Craft stores references to its fully-resolved class name in configuration, and
149
+
:::
150
+
151
+
### Automatic Defaults
152
+
153
+
Plugins are automatically given a few key features to simplify setup and provide a consistent developer experience:
154
+
155
+
- An [alias](../configure.md#aliases) is registered, corresponding to each autoloading namespace. If your plugin’s root namespace was `acmelabs\mousetrap`, Craft would create `@acmelabs\mousetrap`.
156
+
- The plugin’s `controllerNamespace` is configured such that web requests are served by [controllers](controllers.md) in a `controllers/` directory adjacent to the main plugin file, and [console commands](commands.md) are resolved using classes in `console/controllers/`.
157
+
149
158
### Initialization
150
159
151
160
Most initialization logic belongs in your plugin’s `init()` method. However, there are some situations in which parts of the application aren’t ready yet (like another plugin)—in particular, creating [element queries](../development/element-queries.md) or causing the [Twig environment](../development/twig.md) to be loaded prematurely can result in race conditions and incomplete initialization.
@@ -161,7 +170,10 @@ class Plugin extends \craft\base\Plugin
161
170
{
162
171
public function init(): void
163
172
{
164
-
// ...
173
+
// Always let the parent init() method run, first:
174
+
parent::init();
175
+
176
+
// Set up critical components + features...
165
177
166
178
// Defer some setup tasks until Craft is fully initialized:
167
179
Craft::$app->onInit(function() {
@@ -179,13 +191,55 @@ If Craft has already fully initialized, your callback will be invoked immediatel
179
191
180
192
Conversely, there are cases in which attaching [event listeners](events.md) in `onInit()` may be _too late_—by the time your callback is invoked, those events may have already happened.
181
193
194
+
### Accessing your Plugin
195
+
196
+
When you need a reference to your main plugin class (say, from a [controller](controllers.md) or [service](services.md)), use the static instance getter:
197
+
198
+
```php
199
+
use mynamespace\Plugin as MyPlugin;
200
+
201
+
$pluginInstance = MyPlugin::getInstance();
202
+
```
203
+
204
+
Each time you call this, the same “singleton” will be returned, so anything you’ve memoized on the class (say, as private properties) will be preserved.
205
+
206
+
::: warning
207
+
You should never need to create additional instances of your plugin!
208
+
:::
209
+
210
+
### Components and Getters
211
+
212
+
As your plugin’s capabilities grow, you may want to organize functionality into [services](services.md). Yii is able to resolve any services you configure via your plugin’s [setComponents()](yii2:yii\base\Component::setComponents()) method, but some [IDE](README.md#ide)s are aided by [`@property` docblock tags](https://docs.phpdoc.org/guide/references/phpdoc/tags/property.html) or explicit [component getters](services.md#component-getters).
213
+
182
214
## Loading your plugin into a Craft project
183
215
184
-
To get Craft to see your plugin, you will need to install it as a Composer dependency of your Craft project. There are multiple ways to do that:
216
+
When you scaffold a new plugin with the [generator](#scaffolding), Craft takes care of connecting the project’s `composer.json` to the new local directory using a [path repository](#path-repository). You are free to continue local development like this, indefinitely—but it’s important to understand how other developers might install your plugin, later!
217
+
218
+
Once published, other developers can [install your plugin via Packagist](#packagist). These steps are identical for any plugin in the [Plugin Store](plugin-store.md).
219
+
220
+
### Packagist
221
+
222
+
If you’re ready to [publicly release](plugin-store.md) your plugin, register it as a new Composer package on [Packagist](https://packagist.org/). Other developers can install it like any other package, by passing its name to Composer’s `require` command:
223
+
224
+
```bash
225
+
# go to the project directory
226
+
cd /path/to/my-project
227
+
228
+
# require the plugin package
229
+
composer require package/name
230
+
```
231
+
232
+
DDEV users have access to this shortcut when interacting with Composer:
233
+
234
+
```bash
235
+
ddev composer require package/name
236
+
```
237
+
238
+
<Seepath="plugin-store.md"label="Publishing to the Plugin Store"description="Get your plugin ready to publish in the official Plugin Store!" />
185
239
186
240
### Path Repository
187
241
188
-
During development, the easiest way to work on your plugin is with a [path repository][path], which will tell Composer to symlink your plugin into the `vendor/` folder right alongside other dependencies.
242
+
During development, the easiest way to work on your plugin is with a [path repository][path]. This allows Composer to _symbolically link_your plugin into the `vendor/` folder, right alongside other dependencies.
189
243
190
244
To set it up, open your Craft project’s `composer.json` file and make the following changes:
191
245
@@ -200,59 +254,52 @@ To set it up, open your Craft project’s `composer.json` file and make the foll
200
254
"repositories": [
201
255
{
202
256
"type": "path",
203
-
"url": "../my-plugin"
257
+
"url": "./local/my-plugin"
204
258
}
205
259
]
206
260
}
207
261
```
208
262
263
+
Set the `url` value to the absolute or relative path to your plugin’s source directory. The `./local/my-plugin` example above assumes that the plugin was cloned into a directory named `local/`, which exists alongside `composer.json`.
264
+
209
265
::: tip
210
-
Set the `url` value to the absolute or relative path to your plugin’s source directory. (The `../my-plugin` example value assumes that the plugin lives in a folder alongside the project’s folder.)
266
+
If you are using a containerized development environment like DDEV, Composer may not be able to see directories outside the current project! You can either clone another copy of the repository into the project, or configure a new mount by creating `./config/docker-compose.plugin-mount.yml`:
This will be merged with DDEV’s main web container config; you can then replace the path repository’s `url` with the absolute path `/home/shared/my-plugin`.
211
276
:::
212
277
213
-
In your terminal, go to your Craft project and tell Composer to require your plugin. (Use the same package name you gave your plugin in its `composer.json` file.)
278
+
In a terminal, go to your Craft project and require the plugin using the same package name you gave your plugin in its `composer.json` file:
214
279
215
280
```bash
216
-
# go to the project directory
217
-
cd /path/to/my-project
218
-
219
-
# require the plugin package
220
281
composer require package/name
221
282
```
222
283
223
-
Composer’s installation log should indicate that the package was installed via a symlink:
284
+
Composer’s output should show that the package was installed via a symlink:
224
285
225
286
```
226
-
- Installing package/name (X.Y.Z): Symlinking from ../my-plugin
287
+
- Installing package/name (X.Y.Z): Symlinking from ./local/my-plugin
227
288
```
228
289
229
290
::: warning
230
-
One caveat of `path` Composer repositories is that Composer may ignore `path`-based dependencies when you run `composer update`. So any time you change anything in `composer.json`, such as your plugin’s dependency requirements or its plugin information, you might need to completely remove and re-require your plugin in your project for those changes to take effect.
291
+
One caveat of `path` Composer repositories is that Composer may ignore `path`-based dependencies when you run `composer update`. So any time you change anything in a plugin’s `composer.json` (like its dependencies or [extras](#composer-json)), you may need to completely remove and re-require your plugin for those changes to take effect:
231
292
232
293
```bash
233
-
# go to the project directory
234
-
cd /path/to/my-project
235
-
236
-
# remove the plugin package
294
+
# Remove the plugin package from your project:
237
295
composer remove package/name
238
296
239
-
#re-require the plugin package
240
-
composer require package/name
297
+
# Re-require the plugin package, and allow updates to dependencies:
298
+
composer require package/name -w
241
299
```
242
-
243
300
:::
244
301
245
-
### Packagist
246
-
247
-
If you’re ready to publicly release your plugin, register it as a new Composer package on [Packagist](https://packagist.org/). Then you can install it like any other package, by just passing its package name to Composer’s `require` command.
248
-
249
-
```bash
250
-
# go to the project directory
251
-
cd /path/to/my-project
252
-
253
-
# require the plugin package
254
-
composer require package/name
255
-
```
302
+
This same process can be used to fork, clone, and contribute to any open-source or source-available plugin!
256
303
257
304
## Plugin Icons
258
305
@@ -262,19 +309,10 @@ Plugins can provide an icon, which will be visible on the **Settings** → **Plu
262
309
<img src="../images/plugin-index.png" alt="Screenshot of control panel Settings → Plugins">
263
310
</BrowserShot>
264
311
265
-
266
312
Plugin icons must be square SVG files, saved as `icon.svg` at the root of your plugin’s source directory (e.g `src/`).
267
313
268
314
If your plugin has a [control panel section](cp-section.md), you can also give its global nav item a custom icon by saving an `icon-mask.svg` file in the root of your plugin’s source directory. Note that this icon cannot contain strokes, and will always be displayed in a solid color (respecting alpha transparency).
0 commit comments