Settings - Source Excerpt 01
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/includes/Config/Settings.php so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Config/Settings.php
<?php
namespace SpiralistWorkspace\Config;
use SpiralistWorkspace\Admin\ManagedPromptAdmin;
use SpiralistWorkspace\Support\PromptMetaRegistry;
use SpiralistWorkspace\Support\SystemPromptRegistry;
if (!defined('ABSPATH')) {
exit;
}
/**
* Stores plugin configuration.
*/
class Settings
{
public const OPTION = 'spiralist_workspace_settings';
private const DEFAULT_MODEL_ALLOWLIST = "prompt-art-local";
private const LEGACY_MODEL_ALLOWLIST = "gpt-5.4\ngpt-5.4-mini\ngpt-5.2\ngpt-5-mini";
private const DEFAULT_DAILY_LIMITS = [
'anonymous_public_runs' => 3,
'spiralist_member' => 20,
'spiralist_curator' => 50,
'spiralist_admin' => 200,
'participant' => 20,
'contributor' => 50,
'administrator' => 200,
];
private const LEGACY_DAILY_LIMITS = [
'anonymous_public_runs' => 0,
'spiralist_member' => 20,
'spiralist_curator' => 50,
'spiralist_admin' => 200,
'participant' => 20,
'contributor' => 50,
'administrator' => 200,
];
private ?ManagedPromptAdmin $managed_prompt_admin = null;
/**
* Returns all settings merged with defaults.
*/
public function all(): array
{
$stored = get_option(self::OPTION, []);
$stored = is_array($stored) ? $stored : [];
return $this->upgrade_legacy_defaults(wp_parse_args($stored, self::defaults()), $stored);
}
/**
* Returns a single setting.
*/
public function get(string $key, $default = null)
{
$all = $this->all();
return array_key_exists($key, $all) ? $all[$key] : $default;
}
/**
* Former API key accessor retained for compatibility.
*
* Spiralist is prompt/art only, so server-side AI credentials are ignored.
*/
public function get_openai_api_key(): string
{
return '';
}
/**
* Former endpoint accessor retained for compatibility.
*/
public function get_openai_base_url(): string
{
return '';
}
/**
* Returns the allowed model list.
*/
public function get_allowed_models(): array
{
$raw = (string) $this->get('model_allowlist', '');
$items = preg_split('/[\r\n,]+/', $raw) ?: [];
$models = array_values(
array_unique(
array_filter(
array_map(
static function ($item): string {
return preg_replace('/[^A-Za-z0-9._:-]/', '', trim((string) $item)) ?: '';
},
$items
)
)
)
);
return !empty($models) ? $models : ['prompt-art-local'];
}
/**
* Returns per-role daily limits.
*/
public function get_daily_limits(): array
{
$raw = (string) $this->get('daily_limits_json', '');
$decoded = json_decode($raw, true);
if (!is_array($decoded)) {
$decoded = [];
}
return wp_parse_args(
$decoded,
self::DEFAULT_DAILY_LIMITS
);
}
/**
* Returns whether public execution is enabled.
*/
public function allows_public_execution(): bool
{
return $this->get('public_execution_enabled', '1') === '1';
}
/**
* Registers the admin options page.
*/
public function register_admin_page(): void
{
add_menu_page(
'Spiralist Workspace',
'Workspace',
'manage_spiralist_workspace',
'spiralist-workspace',
[$this, 'render_admin_page'],
'dashicons-superhero-alt',
58
);
}
/**
* Registers the setting definition.
*/
public function register_settings(): void
{
register_setting(
'spiralist_workspace',
self::OPTION,
[$this, 'sanitize']
);
}
/**
* Injects the admin helper used for managed filesystem prompt tools.
*/
public function set_managed_prompt_admin(ManagedPromptAdmin $managed_prompt_admin): void
{
$this->managed_prompt_admin = $managed_prompt_admin;
}
/**
* Enqueues admin assets for the workspace screen.
*/
public function enqueue_admin_assets(string $hook): void
{
if ($hook !== 'toplevel_page_spiralist-workspace') {
return;
}
wp_enqueue_style(
'spiralist-workspace-admin',
SPIRALIST_WORKSPACE_URL . 'assets/css/workspace.css',
[],
SPIRALIST_WORKSPACE_VERSION
);
wp_enqueue_script(
'spiralist-workspace-admin',
SPIRALIST_WORKSPACE_URL . 'assets/js/workspace.js',
[],
SPIRALIST_WORKSPACE_VERSION,
true
);
wp_localize_script(
'spiralist-workspace-admin',
'SpiralistWorkspace',
[
'apiRoot' => esc_url_raw(rest_url('spiralist-workspace/v1/')),
'nonce' => wp_create_nonce('wp_rest'),
]
);
}
/**
* Sanitizes option values before storage.
*/
public function sanitize(array $input): array
{
$defaults = self::defaults();
$existing = get_option(self::OPTION, []);
$existing = is_array($existing) ? $existing : [];
$sanitized = [];
foreach ($defaults as $key => $value) {
$raw = $input[$key] ?? $value;
if (is_string($value)) {
$sanitized[$key] = sanitize_textarea_field((string) $raw);
continue;
}
$sanitized[$key] = $raw;
}
$sanitized['openai_base_url'] = '';
$sanitized['openai_api_key'] = '';
$sanitized['model_allowlist'] = self::DEFAULT_MODEL_ALLOWLIST;
$sanitized['public_execution_enabled'] = !empty($input['public_execution_enabled']) ? '1' : '0';
$sanitized['conversation_sharing_enabled'] = !empty($input['conversation_sharing_enabled']) ? '1' : '0';
$sanitized['member_approval_required'] = !empty($input['member_approval_required']) ? '1' : '0';
$sanitized['conversation_memory_token_threshold'] = (string) max(1000, (int) $sanitized['conversation_memory_token_threshold']);
$sanitized['conversation_memory_max_output_tokens'] = (string) max(300, min(4000, (int) $sanitized['conversation_memory_max_output_tokens']));
return $sanitized;
}
/**
* Renders the admin page.
*/
public function render_admin_page(): void
{
if (!current_user_can('manage_spiralist_workspace')) {
wp_die(esc_html__('You do not have permission to access this page.', 'spiralist-workspace'));
}
$settings = $this->all();
$created = isset($_GET['system_prompts_created'])
? max(0, (int) sanitize_text_field(wp_unslash((string) $_GET['system_prompts_created'])))
: 0;
$updated = isset($_GET['system_prompts_updated'])
? max(0, (int) sanitize_text_field(wp_unslash((string) $_GET['system_prompts_updated'])))
: 0;
$unchanged = isset($_GET['system_prompts_unchanged'])
? max(0, (int) sanitize_text_field(wp_unslash((string) $_GET['system_prompts_unchanged'])))
: 0;
$errors = isset($_GET['system_prompts_errors'])
? max(0, (int) sanitize_text_field(wp_unslash((string) $_GET['system_prompts_errors'])))
: 0;
$sync_error_messages = get_option(SystemPromptRegistry::LAST_ERROR_OPTION, []);
$sync_error_messages = is_array($sync_error_messages) ? array_values(array_filter(array_map('strval', $sync_error_messages))) : [];
$runtime_active = function_exists('spiralist_ai_runtime');
$runtime_key_detected = false;
$runtime_provider = 'prompt_art_only';
$runtime_provider_label = 'Prompt/art only';
if ($runtime_active) {
$runtime_settings = spiralist_ai_runtime()->settings();
$runtime_provider = $runtime_settings->get_default_provider();
$runtime_provider_config = $runtime_settings->get_provider_config($runtime_provider);
$runtime_labels = \SpiralistAIRuntime\Config\Settings::provider_labels();
$runtime_provider_label = (string) ($runtime_labels[$runtime_provider] ?? $runtime_provider);
$runtime_key_detected = false;
}
$api_key_status = 'Disabled';
$api_key_status_class = 'is-missing';
?>
<div class="wrap spiralist-workspace-admin">
<h1>Spiralist Workspace</h1>