Skip to content
wiki.fftac.org

Roadmap Surfaces - Source Excerpt 02

Back to Roadmap Surfaces

Summary

This source excerpt preserves a bounded section of Spiralist/wp-content/themes/spiralist/inc/roadmap-surfaces.php so readers can inspect the evidence without opening the full source file.

**Source path:** Spiralist/wp-content/themes/spiralist/inc/roadmap-surfaces.php

function spiralist_register_contribution_content_types(): void
{
    register_post_type(
        'spiralist_contribution',
        [
            'labels' => [
                'name' => 'Spiralist Contributions',
                'singular_name' => 'Spiralist Contribution',
                'menu_name' => 'Contributions',
                'add_new_item' => 'Add Contribution',
                'edit_item' => 'Edit Contribution',
                'view_item' => 'View Contribution',
            ],
            'public' => false,
            'show_ui' => true,
            'show_in_menu' => true,
            'show_in_rest' => false,
            'supports' => ['title', 'editor', 'author', 'excerpt'],
            'menu_icon' => 'dashicons-feedback',
            'rewrite' => false,
        ]
    );

    register_taxonomy(
        'spiralist_contribution_type',
        ['spiralist_contribution'],
        [
            'label' => 'Contribution Types',
            'public' => false,
            'show_ui' => true,
            'show_in_rest' => false,
            'hierarchical' => true,
        ]
    );

    foreach (
        [
            'bug' => 'Bug',
            'symbol-suggestion' => 'Symbol Suggestion',
            'prompt-improvement' => 'Prompt Improvement',
            'manuscript-annotation' => 'Manuscript Annotation',
        ] as $slug => $label
    ) {
        if (!term_exists($slug, 'spiralist_contribution_type')) {
            wp_insert_term($label, 'spiralist_contribution_type', ['slug' => $slug]);
        }
    }
}
add_action('init', 'spiralist_register_contribution_content_types', 9);

function spiralist_get_roadmap_endpoint_catalog(): array
{
    $nonce = is_user_logged_in() ? wp_create_nonce('wp_rest') : '';

    return [
        [
            'id' => 'manuscript-folio',
            'label' => 'Unified Manuscript Folio',
            'method' => 'GET',
            'url' => rest_url('uaix/v1/manuscript-folio?slug=creation'),
            'auth' => 'none',
            'purpose' => 'Fetch one folio with image, transcript, symbols, glossary terms, and related prompts.',
        ],
        [
            'id' => 'prompt-draft-save',
            'label' => 'Save Prompt Draft',
            'method' => 'POST',
            'url' => rest_url('uaix/v1/prompts/save'),
            'auth' => 'wordpress_nonce',
            'nonce' => $nonce,
            'purpose' => 'Save a signed-in user prompt cockpit draft as a private Workspace prompt.',
        ],
        [
            'id' => 'contribute',
            'label' => 'Structured Contribution',
            'method' => 'POST',
            'url' => rest_url('uaix/v1/contribute'),
            'auth' => is_user_logged_in() ? 'wordpress_nonce' : 'rate_limited_public',
            'nonce' => $nonce,
            'purpose' => 'Submit structured bug, symbol, prompt, or manuscript feedback into the contribution queue.',
        ],
    ];
}

function spiralist_rest_get_builder_endpoints(): WP_REST_Response
{
    return new WP_REST_Response(
        [
            'site' => home_url('/'),
            'generated_at' => gmdate('c'),
            'logged_in' => is_user_logged_in(),
            'nonce' => is_user_logged_in() ? wp_create_nonce('wp_rest') : '',
            'endpoints' => spiralist_get_roadmap_endpoint_catalog(),
        ]
    );
}

function spiralist_find_folio_for_rest(WP_REST_Request $request): array
{
    $slug = sanitize_title((string) $request->get_param('slug'));
    $sequence = (int) $request->get_param('sequence');

    if ($slug !== '' && function_exists('spiralist_book_pages_get_manuscript_page_asset_by_slug')) {
        $page = spiralist_book_pages_get_manuscript_page_asset_by_slug($slug);
        if (!empty($page)) {
            return $page;
        }
    }

    if ($slug !== '' && function_exists('spiralist_get_manuscript_page_asset_by_slug')) {
        $page = spiralist_get_manuscript_page_asset_by_slug($slug);
        if (!empty($page)) {
            return $page;
        }
    }

    if ($sequence > 0 && function_exists('spiralist_book_pages_get_manuscript_page_asset_by_sequence')) {
        $page = spiralist_book_pages_get_manuscript_page_asset_by_sequence($sequence);
        if (!empty($page)) {
            return $page;
        }
    }

    if ($sequence > 0 && function_exists('spiralist_get_manuscript_page_asset_by_sequence')) {
        $page = spiralist_get_manuscript_page_asset_by_sequence($sequence);
        if (!empty($page)) {
            return $page;
        }
    }

    $pages = function_exists('spiralist_book_pages_get_manuscript_page_assets')
        ? spiralist_book_pages_get_manuscript_page_assets()
        : (function_exists('spiralist_get_manuscript_page_assets') ? spiralist_get_manuscript_page_assets() : []);

    return is_array($pages) && !empty($pages[0]) && is_array($pages[0]) ? $pages[0] : [];
}

function spiralist_get_folio_sources_for_rest(array $page): array
{
    if (function_exists('spiralist_book_pages_get_book_page_asset_source_urls')) {
        return spiralist_book_pages_get_book_page_asset_source_urls($page, true);
    }

    $url = (string) ($page['url'] ?? '');
    return [
        'thumbnail_url' => $url,
        'large_url' => $url,
        'interactive_url' => $url,
        'original_url' => $url,
    ];
}

function spiralist_match_symbols_for_folio(array $page): array
{
    $keywords = array_values(array_filter(array_map('strval', (array) ($page['keywords'] ?? [])), 'strlen'));
    $haystack = strtolower(
        implode(
            ' ',
            array_filter(
                [
                    (string) ($page['title'] ?? ''),
                    (string) ($page['summary'] ?? ''),
                    (string) ($page['caption'] ?? ''),
                    implode(' ', $keywords),
                ]
            )
        )
    );
    $records = function_exists('spiralist_get_symbol_detail_records') ? spiralist_get_symbol_detail_records() : [];
    $matches = [];

    foreach ($records as $record) {
        if (!is_array($record)) {
            continue;
        }

        $terms = array_values(
            array_filter(
                array_map(
                    'strtolower',
                    [
                        (string) ($record['label'] ?? ''),
                        (string) ($record['canonicalId'] ?? ''),
                        (string) ($record['meaning'] ?? ''),
                        (string) ($record['category'] ?? ''),
                    ]
                ),
                'strlen'
            )
        );

        $matched = false;
        foreach ($terms as $term) {
            if (strlen($term) >= 4 && strpos($haystack, $term) !== false) {
                $matched = true;
                break;
            }
        }

        if (!$matched && count($matches) >= 5) {
            continue;
        }

        if ($matched || count($matches) < 3) {
            $matches[] = [
                'id' => (string) ($record['canonicalId'] ?? ''),
                'label' => (string) ($record['label'] ?? ''),
                'meaning' => (string) ($record['meaning'] ?? ''),
                'definition' => (string) ($record['definition'] ?? ''),
                'url' => (string) ($record['url'] ?? ''),
            ];
        }

        if (count($matches) >= 8) {
            break;
        }
    }

    return $matches;
}

function spiralist_get_folio_related_prompts_for_rest(array $page): array
{
    $records = function_exists('spiralist_get_manuscript_related_prompt_records')
        ? spiralist_get_manuscript_related_prompt_records($page)
        : [];
    $prompts = [];

    foreach ($records as $record) {
        if (!is_array($record)) {
            continue;
        }
        $prompts[] = [
            'id' => (int) ($record['id'] ?? 0),
            'slug' => (string) ($record['slug'] ?? ''),
            'title' => (string) ($record['title'] ?? 'Related prompt'),
            'summary' => (string) ($record['summary'] ?? ''),
            'url' => (string) ($record['url'] ?? ''),
            'moderation_status' => (string) ($record['moderation_status'] ?? ''),
        ];
    }

    return $prompts;
}

function spiralist_rest_get_manuscript_folio(WP_REST_Request $request)
{
    $page = spiralist_find_folio_for_rest($request);
    if (empty($page)) {
        return new WP_Error('spiralist_folio_not_found', 'No manuscript folio could be resolved.', ['status' => 404]);
    }

    $sources = spiralist_get_folio_sources_for_rest($page);
    $symbols = spiralist_match_symbols_for_folio($page);
    $route_url = function_exists('spiralist_book_pages_get_manuscript_folio_url')
        ? spiralist_book_pages_get_manuscript_folio_url($page)