Skip to content
wiki.fftac.org

Promptcategoryregistry

**Site relevance:** Spiralist.org

**Memory type:** plugin source memory

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

**Size:** 8.6 KB

Summary

namespace SpiralistWorkspace\Support;

Source Preview

This source file is short enough to preview directly on its source-memory page.

<?php

namespace SpiralistWorkspace\Support;

use SpiralistWorkspace\Domain\PromptRepository;

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

/**
 * Canonical prompt category hierarchy for the Spiralist prompt platform.
 */
class PromptCategoryRegistry
{
    /**
     * Returns the intent-first Level 1 domains and Level 2 subcategories.
     *
     * @return array<string,string[]>
     */
    public static function hierarchy(): array
    {
        return [
            'Onboarding & Study' => [
                'First Session',
                'Spiralism Explainers',
                'Symbol Study',
                'Teaching Aids',
                'Study Pathways',
            ],
            'Companion & Reflection' => [
                'Bounded Companions',
                'Recursive Check-ins',
                'Journaling',
                'Wellness Reframes',
                'Social Rehearsal',
            ],
            'AI Personality & Memory' => [
                'Working Agreements',
                'Memory Checkpoints',
                'Session Briefs',
                'Chatbot Design',
                'AI Agents',
            ],
            'Safety & Governance' => [
                'Boundary & Reality Safeguards',
                'Prompt Safety',
                'Calibrant Review',
                'Safe Seed Rewrites',
                'Identity & Dependency Review',
                'Provenance Review',
                'Peer Moderation',
            ],
            'Research & Archive' => [
                'Prompt Ecology Archive',
                'Calibrant Analysis',
                'Critical Analysis',
                'Cultural Lineage',
                'Market & Trend Research',
                'Scientific Research',
            ],
            'Visual Design' => [
                'Manuscript Plates',
                'Vibrant Spiralism',
                'Image Prompting',
                'UI/UX Design',
                'Worldbuilding',
            ],
            'Writing & Content' => [
                'Blog Writing',
                'Copywriting',
                'Technical Writing',
                'Story Generation',
                'Editing & Proofreading',
            ],
            'Programming & Development' => [
                'Code Generation',
                'Debugging',
                'Refactoring',
                'API Design',
                'System Architecture',
            ],
            'Business & Productivity' => [
                'Task Automation',
                'Project Management',
                'Meeting Summaries',
                'Document Generation',
                'Decision Support',
            ],
            'Marketing & SEO' => [
                'SEO Optimization',
                'Ad Copy',
                'Social Media Content',
                'Email Campaigns',
                'Market Research',
            ],
            'Education & Learning' => [
                'Onboarding',
                'Tutoring',
                'Course Creation',
                'Explanations',
                'Quiz Generation',
                'Study Plans',
            ],
            'Creative & Design' => [
                'Image Prompting',
                'UI/UX Design',
                'Branding',
                'Game Design',
                'Worldbuilding',
            ],
            'Data & Analysis' => [
                'Data Cleaning',
                'Data Visualization',
                'SQL Generation',
                'Reporting',
                'Forecasting',
            ],
            'Personal & Lifestyle' => [
                'Journaling',
                'Goal Setting',
                'Health Guidance',
                'Financial Planning',
                'Habit Tracking',
            ],
            'AI & Automation' => [
                'AI Agents',
                'Workflow Automation',
                'Chatbot Design',
                'Prompt Engineering',
                'Multi-step Systems',
                'Memory & Continuity',
            ],
            'Specialized & Niche' => [
                'Legal Assistance',
                'Medical Assistance',
                'Scientific Research',
                'Philosophy & Systems Thinking',
                'Experimental / Spiralism',
            ],
        ];
    }

    /**
     * Returns API-ready category records.
     *
     * @return array<int,array{category:string,subcategories:string[]}>
     */
    public static function for_api(): array
    {
        $records = [];

        foreach (self::hierarchy() as $category => $subcategories) {
            $records[] = [
                'category' => $category,
                'subcategories' => array_values($subcategories),
            ];
        }

        return $records;
    }

    /**
     * Returns all domain labels.
     *
     * @return string[]
     */
    public static function categories(): array
    {
        return array_keys(self::hierarchy());
    }

    /**
     * Returns all subcategory labels.
     *
     * @return string[]
     */
    public static function subcategories(): array
    {
        $subcategories = [];

        foreach (self::hierarchy() as $items) {
            foreach ($items as $subcategory) {
                $subcategories[] = $subcategory;
            }
        }

        return $subcategories;
    }

    /**
     * Normalizes a category label to one of the canonical domains.
     */
    public static function normalize_category(string $category): string
    {
        return self::normalize_label($category, self::categories(), 'Writing & Content');
    }

    /**
     * Normalizes a subcategory label, keeping it inside the chosen domain.
     */
    public static function normalize_subcategory(string $category, string $subcategory): string
    {
        $category = self::normalize_category($category);
        $subcategories = self::hierarchy()[$category] ?? [];

        return self::normalize_label($subcategory, $subcategories, $subcategories[0] ?? 'Blog Writing');
    }

    /**
     * Returns the parent domain for a subcategory label.
     */
    public static function category_for_subcategory(string $subcategory): string
    {
        $wanted = sanitize_title($subcategory);

        foreach (self::hierarchy() as $category => $subcategories) {
            foreach ($subcategories as $candidate) {
                if (sanitize_title($candidate) === $wanted) {
                    return $category;
                }
            }
        }

        return 'Writing & Content';
    }

    /**
     * Seeds the WordPress taxonomy terms that mirror this hierarchy.
     */
    public static function ensure_terms(): void
    {
        if (!taxonomy_exists(PromptRepository::CATEGORY_TAXONOMY)) {
            return;
        }

        foreach (self::hierarchy() as $category => $subcategories) {
            $parent_term = term_exists($category, PromptRepository::CATEGORY_TAXONOMY);

            if (!$parent_term) {
                $parent_term = wp_insert_term(
                    $category,
                    PromptRepository::CATEGORY_TAXONOMY,
                    ['slug' => sanitize_title($category)]
                );
            }

            if (is_wp_error($parent_term)) {
                continue;
            }

            $parent_id = is_array($parent_term) ? (int) ($parent_term['term_id'] ?? 0) : (int) $parent_term;

            foreach ($subcategories as $subcategory) {
                if (term_exists($subcategory, PromptRepository::CATEGORY_TAXONOMY)) {
                    continue;
                }

                $child_term = wp_insert_term(
                    $subcategory,
                    PromptRepository::CATEGORY_TAXONOMY,
                    [
                        'slug' => sanitize_title($subcategory),
                        'parent' => $parent_id,
                    ]
                );

                if (is_wp_error($child_term)) {
                    continue;
                }
            }
        }
    }

    /**
     * Finds a canonical label by slug-insensitive comparison.
     *
     * @param string[] $allowed
     */
    private static function normalize_label(string $value, array $allowed, string $fallback): string
    {
        $slug = sanitize_title($value);

        foreach ($allowed as $candidate) {
            if (sanitize_title($candidate) === $slug) {
                return $candidate;
            }
        }

        return $fallback;
    }
}