Setting plugins¶
Add per-site settings with a #[SiteSetting] plugin, map them to
configuration, and read their values in code.
What a setting plugin is¶
A setting plugin declares a group of setting keys. It gets a section on
each site whose type offers one of its keys, at
/admin/sites/{site}/settings/{plugin_id} (permission Manage site
settings), a row per key in every site type's matrix, and an entry in the
settings reference. How the layers of a value
combine is on Setting layers.
Keys share one namespace across all plugins; a plugin that computes its keys
prefixes them, as Roles does with per_site_role:{rid}.
plugin.manager.site_setting discovers the plugins in Plugin/SiteSetting;
hook_site_setting_info_alter() alters them.
Declare a plugin¶
namespace Drupal\my_module\Plugin\SiteSetting;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\sites\Attribute\SiteSetting;
use Drupal\sites\Plugin\SiteSetting\SiteSettingPluginBase;
use Drupal\sites\SiteSetting\SiteSettingValuesInterface;
#[SiteSetting(
id: 'my_module_support',
label: new TranslatableMarkup('Support'),
description: new TranslatableMarkup('Where visitors of the site get help.'),
weight: 60,
settings: [
'support_phone' => [
'label' => new TranslatableMarkup('Support phone'),
'default' => '',
'translatable' => TRUE,
],
'maintenance_message' => [
'label' => new TranslatableMarkup('Maintenance message'),
'default' => '',
'translatable' => TRUE,
'config_target' => 'system.maintenance:message',
],
],
)]
final class Support extends SiteSettingPluginBase implements SiteSettingValuesInterface {
public function buildSettingsForm(array $form, FormStateInterface $form_state): array {
$form['support_phone'] = [
'#type' => 'tel',
'#title' => $this->t('Support phone'),
'#default_value' => $this->settings['support_phone'],
];
$form['maintenance_message'] = [
'#type' => 'textarea',
'#title' => $this->t('Maintenance message'),
'#default_value' => $this->settings['maintenance_message'],
];
return $form;
}
public function validateValues(array $values): array {
return $this->typeErrors($values);
}
public function configOverrides(): array {
// An empty message keeps the platform's message.
$message = $this->resolvedSetting('maintenance_message');
return is_string($message) && trim($message) !== '' ? parent::configOverrides() : [];
}
}
The manager reads the key definitions in settings without instantiating
the plugin. Keys that depend on runtime state (bundles, roles, menus) come
from defineSettings() instead; sites call it while they resolve their
settings, so it must not load sites. section_of puts the form on another
plugin's section, after the key section_after names, as Sites path prefix
does on the identity section.
Definition keys¶
| Key | Default | Effect |
|---|---|---|
label |
Names the key in the site type's matrix and in token lists. | |
default |
The value when neither the site nor its type sets one. typeErrors() checks values against its type. |
|
translatable |
FALSE |
The value may differ per language. |
environment |
TRUE |
The value may differ per environment. |
locked |
FALSE |
Every site type offers the key, and each site stores its own value. |
config |
TRUE |
FALSE makes a structural key: outside the matrix, edited on the site's own layer only. A plugin of structural keys only has no section. |
config_target |
The configuration value the key is stored as, a per-site override. See below. | |
sensitive |
FALSE |
Redacted in output and tokens; sites.site_settings refuses to write it. |
file |
FALSE |
The value is a file URI; the site is registered as a user of the file. |
The site type decides per key whether the environment and language layers exist; these flags decide whether it may.
The section form¶
buildSettingsForm() builds one element per key, named after the key,
optionally inside details, fieldset or container groups, with values
from $this->settings. The same form edits the type's defaults and every
layer of a site: the section drops the elements of keys the layer does not
offer and stores only values that differ from the layer below.
settingsValueCallback() converts a submitted value into its stored shape.
SiteSettingValuesInterface::validateValues() receives values in their
stored shape and returns error messages keyed by setting key. The base
validateSettingsForm() shows them on the form; sites.site_settings
applies them to every write from an agent tool or your code, and refuses
plugins without the interface.
Config targets¶
config_target takes config.name:property.path or, in defineSettings(),
a Drupal\Core\Form\ConfigTarget with fromConfig and toConfig
callables. A site entity stores the value as a per-site configuration
override row per language and environment, not as a setting; a code site
derives it in configOverrides(). Configuration on the site's host returns
the value.
Every site carries a key's default, so a default becomes an override on
every site. To keep the platform's value, drop empty values in
configOverrides(), as the example, SitesRobotstxt and SystemSite do.
SitesAnalytics overrides it to compute overrides from several keys.
Configuration read while the overrides are built comes without site
overrides. See Config overrides.
Read settings¶
$phone = $this->currentSite->getSetting('support_phone');
$acme_phone = $this->siteManager->getSite('acme')?->getSetting('support_phone');
getSetting() returns the resolved value for the current language and
environment, with inheritance and settings.php applied.
sites.site_settings->read($plugin_id, SettingLayer::base($site_id))
returns one layer's values and the keys it stores itself (own);
writeErrors() and write() change it. Show resolved settings only through
plugin.manager.site_setting->redact($site, $settings).
settings.php¶
A server pins a value in settings.php, keyed by site ID, then setting key:
$settings['acme'] = [
'support_phone' => '+49 30 1234567',
'maintenance_message' => 'Acme is down for maintenance.',
];
- In
getSetting(), the value wins over every layer:SiteSettingsEvent::BUILDapplies it at priority 0, after main-site inheritance at priority 120. - For a key with a config target, it wins in configuration over the site's stored override.
- Core's
$configinsettings.phpwins over every site's overrides.
Keep hostnames out of settings.php; see
Setting layers.