# Plugin settings

A plugin that needs configuration declares its settings rather than inventing its own storage.

## Declaring

Settings are declared in `plugin.json`. Each declared setting has a key, a type, a default, and a label. Keys are namespaced under the plugin's own slug so two plugins cannot collide:

```
plugins.my-plugin.api_endpoint
plugins.my-plugin.enabled_locales
```

## Reading and writing

Settings are read through the settings repository, the same store the core uses. Values are typed on read — an integer setting comes back as an integer.

Write settings from an admin action, not from a public request. A public page that writes settings is a page that a visitor can use to reconfigure your site.

## Types

| Type | Notes |
|---|---|
| string | Trimmed; length-limited |
| integer | Cast and range-checked |
| boolean | Stored as 0/1 |
| json | Structured value; validated on write |

## Secrets

If a setting holds a credential:

- never render it back into the page after saving
- never write it to a log line
- never include it in an export, a manifest or a release package

The core follows this rule for the SMTP password, the Telegram token and the Turnstile secret. Plugins are expected to follow it too.

## Translations

Every label and description shown to an administrator needs a key in both `resources/lang/ar.php` and `resources/lang/en.php`, or the plugin's own equivalent. A raw key rendered in the panel is a bug, not a placeholder.

## Uninstalling

Removing a plugin's files stops its code from running. It does not delete its settings rows. Keeping them means a reinstall restores the previous configuration; if a plugin wants a clean uninstall it must provide an explicit admin action for it.

See [Plugins](PLUGINS.md) and [Plugin migrations](PLUGIN-MIGRATIONS.md).
