# Skill: Settings Management

Skill ID: `settings-management`

Rules
- Option keys use `presszone_translate_*`.
- Sensitive options (`api_key`, webhook secret) use `autoload = false`.
- Settings writes require `manage_options` and nonce verification.
- Verify nonces for all settings form submissions.
- Register sanitization callbacks per option.
- Sanitize all settings input with appropriate functions.
- Prefer WordPress Settings API for registration/render/save.
- Validate model/tone/language/status values with allowlists.
- Validate URL settings against SSRF/private-network targets.
- Never log secrets or decrypted values.
- Use secure validation calls for API credentials.
- Encrypt sensitive values at rest when feasible (`openssl_encrypt` / `openssl_decrypt`).
- Encryption is recommended for sensitive settings at rest.
- Error logging in encrypt/decrypt methods MUST be behind `if (defined('WP_DEBUG') && WP_DEBUG)` — never unconditional.
- `uninstall.php` MUST delete every option the plugin creates — cross-reference ALL `update_option()`/`add_option()` calls. Include: `presszone_translate_site_id`, `presszone_translate_license_key`, `presszone_migration_status`, `presszone_translate_site_deregistered`, bulk result transients, and any other runtime options.
- Settings forms: explicit labels, help text, fieldsets, ARIA-linked errors.
- Keep an audit trail for high-impact settings changes.
- Optional abuse guard: prevent self-targeted moderation/report actions when applicable.

Mistakes to avoid
| Mistake | Fix |
|---|---|
| Unprefixed option names | Use `presszone_translate_*` |
| Secrets with autoload enabled | Save with `autoload = false` |
| Missing nonce/capability checks | Enforce both before write |
| Missing allowlists | Validate enum-like fields explicitly |
| Logging API keys | Log metadata only |
| Ungrouped complex forms | Use `<fieldset>` + `<legend>` |
| Insecure user-defined regex | Use `preg_quote()` before wildcard conversion |
| Hardcoded operational durations | Use constants or setting values |
| No save feedback | Return clear success/error status for UI |
| Unconditional `error_log` in encrypt/decrypt | Wrap in `if (defined('WP_DEBUG') && WP_DEBUG)` |
| Incomplete `uninstall.php` | Audit every `update_option`/`add_option` call and include all keys |
