Settings + Config

You are viewing documentation for an unreleased version of Craft CMS. Please be aware that the material is changing frequently and may be incomplete or inaccurate, and links may point back to older versions.

As mentioned in the base plugin class section, the return type for your createSettingsModel() function has changed.

#Config Files

If you want a user-space config file, add a config/my-plugin-handle.php to the root of your package and it will be published by the CraftCms\Cms\Plugin\Concerns\HasConfig plugin trait, automatically.

The final config map your plugin’s settings model is initialized with will be composed from multiple sources:

  1. Settings model properties: The class you instantiate in createSettingsModel() can have default property values. You may also set properties on it before returning.
  2. Project config: Values stored in config/craft/project/project.yaml under the plugins.{plugin-handle}.settings key. Craft takes care of updating this for you, whenever your plugin’s settings are saved in the control panel.
  3. Local config file: Settings in a project’s published config/craft/{plugin-handle}.php file override everything.

This process also applies to settings as they’re committed to project config.

#Environmental Config

To support environment variable overrides on your settings class (or any model, for that matter), call Env::config($class, 'MY_PLUGIN_NS_').

Plugin settings that support environment variables or aliases should wrap their validation rules in the special CraftCms\Cms\Validation\Rules\EnvValueRule class to check the parsed values, without replacing those properties on the actual model. You do not need to juggle the submitted values before they’re sent to project config.

#Initialization

Yii’s system was heavily configuration-driven: objects were initialized with a config map that would cascade down through any nested objects. Places you’d use Craft::createObject() can be mostly replaced with app()->make($class, [...]).

#Settings Form

The CraftCms\Cms\Plugin\Concerns\HasSettings trait gives your plugin a hasCpSettings property; set this to true to give your plugin a tile in the Settings screen of the control panel, and a dedicated settings page. Craft handles all the routing, so you only need to implement a settingsHtml() method:

#[\Override]
protected function settingsHtml(): string
{
    return template('plugin-handle/_settings', [
        'settings' => $this->getSettings(),
    ]);
}

The markup you return is wrapped in a normal control panel layout, so your template does not need to extend any internal views. Your only responsibility is to provide inputs that send the expected “shape” of data to the CraftCms\Cms\Http\Controllers\PluginsController::saveSettings() action.

While your validation setup needs to account for what part of the request it is looking at, your settings form is automatically placed within the settings namespace, and should use plain name attributes (like mySetting, not settings[mySetting]).

Only plugin settings defined in a published config file are pushed into the global configuration repository, accessible through config('craft.plugin-handle.[...]'). This means that the presence of a key in craft.plugin-handle is an indication that the setting is controlled from a config file:

#[\Override]
protected function settingsHtml(): string
{
    // Get the whole static config array (so `nulls` are significant):
    $overrides = config(sprintf('craft.%s', $this->handle));

    return template('plugin-handle/_settings', [
        'settings' => $this->getSettings(),
        'overrides' => array_keys($overrides),
    ]);
}

#Validation

The new settings model will be compatible for most plugins, but you will need to adopt new validation patterns to drop the adapter:

// Remove:
public function defineRules(): array
{}

// Add...
public function getRules(): array
{
    return array_merge(parent::getRules(), [
        'adminNotificationAddress' => ['required', 'email:rfc'],
    ]);
}

// ...or:
public function rulesClass(): string
{
    return MyPluginSettingsRuleset::class;
}

You may also tag the settings model with the #[Ruleset(MyPluginSettingsRuleset::class)] attribute. For more control over how your settings data is normalized, return your own form request class from getSettingsRequestClass().

When using a custom FormRequest, your rules are evaluated against the entire request, not just the nested settings key that Craft ordinarily assigns to your settings model. The example above (validating adminNotificationsAddress on the settings model) would need to be updated to settings.adminNotificationsAddress if returned from FormRequest::rules().

See our Guest Entries (opens new window) plugin for an example of these new techniques.