Skip to content
wiki.fftac.org

Plugin - Source Excerpt 01

Back to Plugin

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/includes/Plugin.php so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Plugin.php

<?php

namespace SpiralistWorkspace;

use SpiralistWorkspace\Admin\ManagedPromptAdmin;
use SpiralistWorkspace\Auth\Permissions;
use SpiralistWorkspace\Auth\Roles;
use SpiralistWorkspace\Config\Settings;
use SpiralistWorkspace\Domain\AuditRepository;
use SpiralistWorkspace\Domain\AppealRepository;
use SpiralistWorkspace\Domain\ConversationRepository;
use SpiralistWorkspace\Domain\FavoriteRepository;
use SpiralistWorkspace\Domain\PermissionRepository;
use SpiralistWorkspace\Domain\PromptRepository;
use SpiralistWorkspace\Domain\ReputationRepository;
use SpiralistWorkspace\Domain\ReviewRepository;
use SpiralistWorkspace\Domain\RunRepository;
use SpiralistWorkspace\Domain\TestRepository;
use SpiralistWorkspace\Domain\VersionRepository;
use SpiralistWorkspace\Privacy\Privacy;
use SpiralistWorkspace\Http\RestController;
use SpiralistWorkspace\Services\PlaceholderService;
use SpiralistWorkspace\Services\PromptRunner;
use SpiralistWorkspace\Services\GovernanceMaintenance;
use SpiralistWorkspace\Services\RateLimiter;
use SpiralistWorkspace\Support\SystemPromptRegistry;
use SpiralistWorkspace\Web\FrontendController;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Boots plugin services and WordPress hooks.
 */
class Plugin
{
    private const SCHEMA_HEALTH_TRANSIENT = 'spiralist_workspace_schema_health_checked';

    private Settings $settings;
    private Roles $roles;
    private PromptRepository $prompts;
    private VersionRepository $versions;
    private PermissionRepository $permission_repository;
    private RunRepository $runs;
    private TestRepository $tests;
    private ConversationRepository $conversations;
    private AuditRepository $audit;
    private FavoriteRepository $favorites;
    private ReviewRepository $reviews;
    private AppealRepository $appeals;
    private ReputationRepository $reputation;
    private Permissions $permissions;
    private PlaceholderService $placeholders;
    private RateLimiter $rate_limiter;
    private PromptRunner $runner;
    private GovernanceMaintenance $governance_maintenance;
    private RestController $rest;
    private FrontendController $frontend;
    private SystemPromptRegistry $system_prompts;
    private ManagedPromptAdmin $managed_prompt_admin;
    private Privacy $privacy;
    private bool $booted = false;

    /**
     * Registers WordPress hooks once.
     */
    public function boot(): void
    {
        if ($this->booted) {
            return;
        }

        $this->settings = new Settings();
        $this->roles = new Roles();
        $this->audit = new AuditRepository();
        $this->versions = new VersionRepository();
        $this->permission_repository = new PermissionRepository();
        $this->favorites = new FavoriteRepository();
        $this->reviews = new ReviewRepository();
        $this->appeals = new AppealRepository();
        $prompt_reader = new PromptRepository($this->versions, $this->permission_repository, $this->favorites);
        $this->reputation = new ReputationRepository($prompt_reader, $this->reviews);
        $this->prompts = new PromptRepository($this->versions, $this->permission_repository, $this->favorites, $this->reputation);
        $this->runs = new RunRepository();
        $this->tests = new TestRepository();
        $this->conversations = new ConversationRepository();
        $this->permissions = new Permissions($this->permission_repository, $this->settings, $this->reputation);
        $this->placeholders = new PlaceholderService();
        $this->rate_limiter = new RateLimiter($this->settings, $this->runs, $this->conversations, $this->audit);
        $this->runner = new PromptRunner(
            $this->prompts,
            $this->permissions,
            $this->runs,
            $this->conversations,
            $this->audit,
            $this->placeholders,
            $this->rate_limiter,
            $this->settings
        );
        $this->governance_maintenance = new GovernanceMaintenance(
            $this->prompts,
            $this->reviews,
            $this->appeals,
            $this->reputation,
            $this->audit
        );
        $this->rest = new RestController(
            $this->prompts,
            $this->permissions,
            $this->permission_repository,
            $this->versions,
            $this->runs,
            $this->tests,
            $this->conversations,
            $this->favorites,
            $this->reviews,
            $this->appeals,
            $this->reputation,
            $this->audit,
            $this->runner,
            $this->governance_maintenance,
            $this->settings
        );
        $this->system_prompts = new SystemPromptRegistry($this->prompts, $this->settings);
        $this->managed_prompt_admin = new ManagedPromptAdmin($this->settings, $this->system_prompts);
        $this->settings->set_managed_prompt_admin($this->managed_prompt_admin);
        $this->privacy = new Privacy($this->prompts, $this->settings);
        $this->frontend = new FrontendController(
            $this->prompts,
            $this->permissions,
            $this->permission_repository,
            $this->versions,
            $this->runs,
            $this->tests,
            $this->conversations,
            $this->favorites,
            $this->reviews,
            $this->appeals,
            $this->reputation,
            $this->audit,
            $this->settings
        );

        add_action('init', [Roles::class, 'register'], 5);
        add_action('init', [$this->prompts, 'register_content_types'], 10);
        add_action('init', [$this->frontend, 'register_routes'], 11);
        add_action('init', [$this->frontend, 'maybe_flush_rewrite_rules'], 100);
        add_action('admin_menu', [$this->settings, 'register_admin_page']);
        add_action('admin_init', [$this->settings, 'register_settings']);
        add_action('admin_init', [$this->privacy, 'add_privacy_policy_content']);
        add_action('rest_api_init', [$this->rest, 'register_routes']);
        add_action('add_meta_boxes', [$this->prompts, 'register_meta_boxes']);
        add_action('save_post', [$this->prompts, 'handle_post_save'], 10, 3);
        add_action('wp_enqueue_scripts', [$this->frontend, 'enqueue_assets']);
        add_action('admin_enqueue_scripts', [$this->settings, 'enqueue_admin_assets']);
        add_action('admin_post_spiralist_workspace_sync_system_prompts', [$this, 'handle_sync_system_prompts']);
        add_action('admin_post_spiralist_workspace_bulk_image_upload', [$this->managed_prompt_admin, 'handle_bulk_image_upload']);
        add_action('admin_post_spiralist_workspace_import_prompt_files', [$this->managed_prompt_admin, 'handle_prompt_import']);
        add_action('admin_post_spiralist_workspace_download_prompt_template', [$this->managed_prompt_admin, 'handle_download_template']);
        add_action('admin_post_spiralist_workspace_save_managed_prompt', [$this->managed_prompt_admin, 'handle_save_prompt']);
        add_filter('query_vars', [$this->frontend, 'register_query_vars']);
        add_filter('template_include', [$this->frontend, 'template_include']);
        add_filter('wp_privacy_personal_data_exporters', [$this->privacy, 'register_exporters']);
        add_filter('wp_privacy_personal_data_erasers', [$this->privacy, 'register_erasers']);
        add_action('template_redirect', [$this->frontend, 'handle_api_alias'], 1);
        add_action('init', [$this, 'maybe_upgrade'], 2);
        if ($this->should_auto_sync_system_prompts()) {
            add_action('init', [$this->system_prompts, 'maybe_sync'], 12);
        }
        add_action('init', [$this->governance_maintenance, 'schedule'], 20);
        add_action(GovernanceMaintenance::HOOK, [$this->governance_maintenance, 'run']);

        $this->booted = true;
    }

    /**
     * Upgrades tables when the schema version changes.
     */
    public function maybe_upgrade(): void
    {
        $stored = (string) get_option('spiralist_workspace_schema_version', '');

        if ($stored === Installer::SCHEMA_VERSION) {
            if ((string) get_transient(self::SCHEMA_HEALTH_TRANSIENT) === Installer::SCHEMA_VERSION) {
                return;
            }

            if ($this->has_required_schema_tables()) {
                set_transient(self::SCHEMA_HEALTH_TRANSIENT, Installer::SCHEMA_VERSION, HOUR_IN_SECONDS);
                return;
            }
        }

        Installer::create_schema();
        PromptRepository::migrate_content_types();
        update_option('spiralist_workspace_schema_version', Installer::SCHEMA_VERSION, false);
        set_transient(self::SCHEMA_HEALTH_TRANSIENT, Installer::SCHEMA_VERSION, HOUR_IN_SECONDS);
    }