Controllers
Plugins and modules can provide custom controllers to Craft installations.
Controllers should live within a controllers/
folder within the plugin or modules’s base source folder, and be named
in the format FooBarController.php
(the Controller
suffix is required).
For the most part, writing controllers for Craft is identical to writing controllers for Yii, so be sure to read the Yii documentation as a starting point.
Craft controllers should extend craft3:craft\web\Controller, which offers a few advantages over its parent,
- You can easily control whether the controller should allow anonymous access by overriding $allowAnonymous. (An active user session is required by default.)
- If an exception is thrown by a controller action and the request accepts a JSON response, the response will
automatically be formatted as JSON, with an
error
key. - It provides several helper methods that ease development.
If you’re writing a custom module and not a plugin, make sure your module’s $controllerNamespace property sets the right namespace for your controllers.
Request Validation Methods
request:
Method | Description
------ | -----------
requireLogin() | Requires that a user is logged in.
requireGuest() | Requires that the user is anonymous.
requireAdmin() | Requires that the user is logged in with an Admin account.
requirePermission() | Requires that the user is logged in with an account that has a given permission.
requireAuthorization() | Requires that the user has been granted authorization to do something (whether or not they are logged in).
requireElevatedSession() | Requires that the user has an elevated session.
requirePostRequest() | Requires that the request was sent as a POST request.
requireAcceptsJson() | Requires that the request was sent with an Accept: application/json
header.
requireToken() | Requires that the request was sent with a token.
requireCpRequest() | Requires that the request URI begins with the control panel trigger.
requireSiteRequest() | Requires that the request URI doesn’t begin with the control panel trigger.
public function actionFoo()
{
// This action should only be available to the control panel
$this->requireCpRequest();
// ...
}
Requesting Your Controller Action
There are several ways to access your controller action in a request.
action
Param
POST Provide an action
param set to your controller’s action path:
curl -d "action=plugin-handle/controller/action" \
-X POST https://my-project.tld/
Custom Route
Create your own endpoint for requests with a custom URL rule that resolves to your controller action.
For example, in config/routes.php
:
return [
'my/custom/endpoint' => 'plugin-handle/controller/action',
];
actions/<action-path>
Route
The By default, Craft makes an actions/
route available for appending any valid action path. This can be customized with the config3:actionTrigger config setting.
curl -X POST https://my-project.tld/actions/plugin-handle/controller/action
Default Route Format
Default plugin and module action routes follow the same pattern:
Action Trigger + Plugin/Module Handle + Controller Name + Action Method
Each URL segment follows Yii’s conventions and is lower-kebab-cased:
- Handle
my-plugin
(from composer.json) ormy-module
(from config/app.php) - Controller
SuperWidgetController
becomessuper-widget
- Action
SuperWidgetController::actionReticulateWidget()
becomesreticulate-widget
Handling Requests
A controller action’s primary job is to handle an incoming web request, and determine the response. There are a few ways an action could go about that, depending on the needs.
Rendering Templates
Controller actions can render and return Twig templates using craft3:craft\web\Controller::renderTemplate().
use yii\web\Response;
use craft\web\View;
public function actionFoo(): Response
{
// Render and return the plugin’s `foo.twig` template
return $this->renderTemplate(
'plugin-handle/foo.twig',
$variables,
View::TEMPLATE_MODE_CP
);
}
ensures all registered JS and CSS resources have been added to the rendered HTML, and then it will set the
Content-Type
header on the response, based on the MIME type of the template being rendered (using text/html
as the
default if the MIME type isn’t known).
Returning JSON
Controller actions can return JSON responses using yii2:yii\web\Controller::asJson().
use Craft;
use yii\web\Response;
public function actionFoo(): Response
{
if (Craft::$app->request->acceptsJson) {
return $this->asJson([
'foo' => true,
]);
}
// ...
}
You can call craft3:craft\web\Controller::asErrorJson() instead for an easy way to return a JSON response with an error
key.
Redirecting the Request
Controller actions can redirect the request using craft3:craft\web\Controller::redirect().
use yii\web\Response;
public function actionFoo(): Response
{
return $this->redirect('bar');
}
Or, if the request may contain a hashed redirect
param, you can redirect to that using craft3:craft\web\Controller::redirectToPostedUrl().
use yii\web\Response;
public function actionFoo(): Response
{
// Redirect the request based on a 'redirect' param
return $this->redirectToPostedUrl();
}
If the controller action is saving something, you may want to allow forms’ redirect
params to include dynamic tokens
such as {id}
, which should be replaced with the object’s attribute values. To support that, pass the object into
redirectToPostedUrl().
use yii\web\Response;
public function actionFoo(): Response
{
// ...
// Redirect the request based on a 'redirect' param,
// which can contain entry attribute tokens, such as {id}
return $this->redirectToPostedUrl($entry);
}