Skip to content
wiki.fftac.org

Admin Core

**Site relevance:** Spiralist.org

**Memory type:** plugin source memory

**Source path:** Spiralist/wp-content/plugins/ns12-manuscript/includes/admin-core.php

**Size:** 7.8 KB

Summary

if (!defined('ABSPATH'))

Source Preview

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

<?php

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

function spiralist_book_pages_admin_capability(): string
{
    return 'manage_options';
}

function spiralist_book_pages_admin_can_manage(): bool
{
    return current_user_can(spiralist_book_pages_admin_capability());
}

function spiralist_book_pages_admin_notice_key(): string
{
    return 'spiralist_book_pages_admin_notice_' . get_current_user_id();
}

function spiralist_book_pages_admin_set_notice(string $message, string $type = 'success', array $details = []): void
{
    set_transient(
        spiralist_book_pages_admin_notice_key(),
        [
            'message' => $message,
            'type' => $type,
            'details' => array_values(array_filter(array_map('strval', $details), 'strlen')),
        ],
        MINUTE_IN_SECONDS
    );
}

function spiralist_book_pages_admin_get_notice(): array
{
    $notice = get_transient(spiralist_book_pages_admin_notice_key());
    if (!is_array($notice)) {
        return [];
    }

    delete_transient(spiralist_book_pages_admin_notice_key());

    return $notice;
}

function spiralist_book_pages_admin_pages(): array
{
    return [
        'overview' => 'ns12-manuscript',
        'folios' => 'ns12-manuscript-folios',
        'prompts' => 'ns12-manuscript-prompts',
        'fragments' => 'ns12-manuscript-fragments',
        'community' => 'ns12-manuscript-community',
        'collaborators' => 'ns12-manuscript-collaborators',
    ];
}

function spiralist_book_pages_admin_page_slug(string $key): string
{
    $pages = spiralist_book_pages_admin_pages();

    return (string) ($pages[$key] ?? $pages['overview']);
}

function spiralist_book_pages_admin_normalize_page(string $page): string
{
    $page = sanitize_key($page);

    return in_array($page, spiralist_book_pages_admin_pages(), true)
        ? $page
        : spiralist_book_pages_admin_page_slug('overview');
}

function spiralist_book_pages_admin_url(string $page, array $args = []): string
{
    return add_query_arg(
        array_merge(
            [
                'page' => spiralist_book_pages_admin_normalize_page($page),
            ],
            $args
        ),
        admin_url('admin.php')
    );
}

function spiralist_book_pages_admin_redirect(string $page, array $args = []): void
{
    wp_safe_redirect(spiralist_book_pages_admin_url($page, $args));
    exit;
}

function spiralist_book_pages_admin_parse_list($value): array
{
    if (is_string($value)) {
        $value = preg_split('/[\r\n,]+/', $value) ?: [];
    }

    if (!is_array($value)) {
        return [];
    }

    $items = array_map(
        static function ($item): string {
            return trim((string) $item);
        },
        $value
    );

    return array_values(array_unique(array_values(array_filter($items, 'strlen'))));
}

function spiralist_book_pages_admin_parse_slug_list($value): array
{
    return array_values(
        array_filter(
            array_map('sanitize_title', spiralist_book_pages_admin_parse_list($value)),
            'strlen'
        )
    );
}

function spiralist_book_pages_admin_is_list(array $value): bool
{
    $expected = 0;

    foreach (array_keys($value) as $key) {
        if ($key !== $expected) {
            return false;
        }

        $expected++;
    }

    return true;
}

function spiralist_book_pages_admin_humanize(string $value): string
{
    $value = trim(str_replace(['_', '-'], ' ', $value));
    if ($value === '') {
        return '';
    }

    return ucwords(strtolower($value));
}

function spiralist_book_pages_admin_unique_slug(string $candidate, array $existing, string $fallback = 'item'): string
{
    $slug = sanitize_title($candidate);
    if ($slug === '') {
        $slug = sanitize_title($fallback);
    }

    if ($slug === '') {
        $slug = 'item';
    }

    $base = $slug;
    $suffix = 2;

    while (isset($existing[$slug])) {
        $slug = $base . '-' . $suffix;
        $suffix++;
    }

    return $slug;
}

function spiralist_book_pages_admin_badge(string $label, string $tone = 'neutral'): string
{
    $class = 'badge';
    if ($tone === 'good') {
        $class .= ' good';
    } elseif ($tone === 'warn') {
        $class .= ' warn';
    } elseif ($tone === 'bad') {
        $class .= ' bad';
    }

    return '<span class="' . esc_attr($class) . '">' . esc_html($label) . '</span>';
}

function spiralist_book_pages_admin_status_tone(string $variant): string
{
    if ($variant === 'fresh') {
        return 'good';
    }

    if ($variant === 'missing' || $variant === 'stale') {
        return 'warn';
    }

    return 'neutral';
}

function spiralist_book_pages_admin_render_styles(): void
{
    static $done = false;

    if ($done) {
        return;
    }

    $done = true;
    ?>
    <style>
        .spiralist-book-admin{max-width:1320px}
        .spiralist-book-admin .hero{display:grid;gap:18px;grid-template-columns:minmax(0,1.45fr) minmax(260px,.9fr);margin:18px 0 20px;padding:22px 24px;border:1px solid #dcdcde;border-radius:18px;background:linear-gradient(145deg,#fff 0%,#f7f2ea 100%);box-shadow:0 1px 2px rgba(15,23,42,.05)}
        .spiralist-book-admin .kicker{margin:0 0 6px;font-size:12px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:#6b7280}
        .spiralist-book-admin .actions,.spiralist-book-admin .inline,.spiralist-book-admin .tight-actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
        .spiralist-book-admin .actions{justify-content:flex-end}
        .spiralist-book-admin .grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}
        .spiralist-book-admin .dual{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}
        .spiralist-book-admin .stack{display:grid;gap:16px}
        .spiralist-book-admin .panel{padding:18px;border:1px solid #dcdcde;border-radius:16px;background:#fff;box-shadow:0 1px 2px rgba(15,23,42,.04)}
        .spiralist-book-admin .metric{display:grid;gap:8px}
        .spiralist-book-admin .metric strong{font-size:30px;line-height:1}
        .spiralist-book-admin .toolbar{display:flex;gap:12px;flex-wrap:wrap;justify-content:space-between;align-items:center;margin:18px 0}
        .spiralist-book-admin .search{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
        .spiralist-book-admin .search input[type="search"]{min-width:280px}
        .spiralist-book-admin .badge{display:inline-flex;align-items:center;padding:4px 10px;border-radius:999px;font-size:12px;font-weight:600;background:#eef2ff;color:#3730a3}
        .spiralist-book-admin .badge.good{background:#f0fdf4;color:#166534}
        .spiralist-book-admin .badge.warn{background:#fffbeb;color:#b45309}
        .spiralist-book-admin .badge.bad{background:#fef2f2;color:#b91c1c}
        .spiralist-book-admin .code{white-space:pre-wrap;overflow:auto;padding:14px 16px;border-radius:12px;background:#111827;color:#f9fafb;border:1px solid #dcdcde;font-family:Consolas,Monaco,monospace;font-size:12px;line-height:1.55}
        .spiralist-book-admin .empty{padding:24px;text-align:center;border:1px dashed #dcdcde;border-radius:16px;background:#f6f7f7}
        .spiralist-book-admin .fragment-list{display:grid;gap:10px;margin:0;padding:0;list-style:none}
        .spiralist-book-admin .fragment-list a{display:flex;justify-content:space-between;gap:12px;align-items:center;padding:12px 14px;border-radius:12px;border:1px solid #dcdcde;text-decoration:none;background:#fff}
        .spiralist-book-admin .fragment-list a.active{border-color:#93c5fd;background:#eff6ff}
        @media (max-width:960px){.spiralist-book-admin .hero{grid-template-columns:1fr}.spiralist-book-admin .actions{justify-content:flex-start}}
    </style>
    <?php
}