Frontendcontroller - Source Excerpt 06
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/spiralist-workspace/includes/Web/FrontendController.php so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Web/FrontendController.php
$prompt['last_run_utc'] = (string) ($stat['last_run_utc'] ?? '');
$records[] = $prompt;
}
if (count($records) >= $limit) {
return array_slice($records, 0, $limit);
}
foreach ($this->public_prompts($limit) as $prompt) {
if (count($records) >= $limit) {
break;
}
$already_added = array_filter(
$records,
static fn(array $record): bool => (int) ($record['id'] ?? 0) === (int) ($prompt['id'] ?? 0)
);
if (!empty($already_added)) {
continue;
}
$prompt['run_count'] = 0;
$records[] = $prompt;
}
return array_slice($records, 0, $limit);
}
/**
* Returns category counts for public prompt discovery.
*/
public function popular_categories(int $limit = 10): array
{
return $this->popular_categories_from_prompts($this->public_prompts(100), $limit);
}
/**
* Returns a prompt creation/edit form seed.
*/
public function default_prompt_seed(): array
{
return [
'title' => '',
'summary' => '',
'category' => 'Writing & Content',
'subcategory' => 'Blog Writing',
'structured_prompt' => [
'instruction' => '',
'context' => '',
'constraints' => '',
'examples' => '',
'output_format' => '',
],
'instructions' => '',
'system_prompt' => '',
'developer_prompt' => '',
'user_prompt_template' => '',
'system_steps' => [],
'system_steps_json' => '[]',
'spiral_script_source' => '',
'spiral_script' => [],
'spiral_script_validation' => [],
'spiral_script_status' => 'none',
'model' => $this->settings->get_allowed_models()[0],
'provider' => 'prompt_art_only',
'credential_preference' => 'site_only',
'temperature' => 0.7,
'max_output_tokens' => 1200,
'visibility' => $this->settings->get('default_visibility', 'private'),
'tags' => [],
'prompt_type' => 'prompt',
'language' => 'en',
'prompt_status' => 'draft',
'moderation_status' => 'draft',
'publication_lane' => 'community_library',
'provenance' => 'community',
'risk_labels' => [],
'function_tags' => [],
'maturity_level' => 'structured_prompt',
'license' => 'spiralist_contributor',
'editorial_note' => '',
'expected_output_notes' => '',
'failure_modes' => '',
'related_symbols' => [],
'related_axioms' => [],
'related_manuscripts' => [],
'sample_output' => '',
'is_forkable' => true,
'allow_comments' => false,
'allow_ratings' => false,
];
}
/**
* Returns whether conversation sharing is enabled.
*/
public function allows_conversation_sharing(): bool
{
return $this->settings->get('conversation_sharing_enabled', '0') === '1';
}
/**
* Returns the model allowlist.
*/
public function allowed_models(): array
{
return $this->settings->get_allowed_models();
}
/**
* Renders a JSON response and exits.
*/
private function render_json($payload, int $status): void
{
status_header($status);
nocache_headers();
header('Content-Type: application/json; charset=' . get_bloginfo('charset'));
echo wp_json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
exit;
}
/**
* Forces a front-end 404 response.
*/
private function force_404(): void
{
global $wp_query;
if ($wp_query instanceof \WP_Query) {
$wp_query->set_404();
}
status_header(404);
nocache_headers();
$template = get_query_template('404');
if (is_string($template) && $template !== '' && file_exists($template)) {
include $template;
}
exit;
}
/**
* Returns public prompt records.
*/
private function public_prompts(int $limit): array
{
$query_limit = max($limit, 120);
if ($this->public_prompt_cache_limit < $query_limit || empty($this->public_prompt_cache)) {
$records = $this->prompts->list_public(['limit' => $query_limit], get_current_user_id());
if (empty($records) && !$this->public_prompt_sync_attempted) {
$this->maybe_sync_system_prompts();
$this->public_prompt_sync_attempted = true;
$records = $this->prompts->list_public(['limit' => $query_limit], get_current_user_id());
}
$public = array_values(
array_filter(
$records,
fn(array $prompt): bool => $this->is_public_library_prompt($prompt)
)
);
usort(
$public,
static function (array $left, array $right): int {
$featured_compare = ((int) !empty($right['featured'])) <=> ((int) !empty($left['featured']));
if ($featured_compare !== 0) {
return $featured_compare;
}
return strcmp((string) ($right['updated_utc'] ?? ''), (string) ($left['updated_utc'] ?? ''));
}
);
$this->public_prompt_cache = $public;
$this->public_prompt_cache_limit = $query_limit;
}
return array_slice($this->public_prompt_cache, 0, $limit);
}
/**
* Returns public prompts for one publication lane from a preloaded record set.
*/
private function public_prompts_for_lane(array $records, string $lane, int $limit = 6): array
{
$normalized_lane = PromptMetaRegistry::normalize_publication_lane($lane);
$matches = array_values(
array_filter(
$records,
static fn(array $prompt): bool => (string) ($prompt['publication_lane'] ?? 'community_library') === $normalized_lane
)
);
return array_slice($matches, 0, $limit);
}
/**
* Returns category counts for a public prompt collection.
*/
private function popular_categories_from_prompts(array $records, int $limit = 10): array
{
$counts = [];
foreach ($records as $prompt) {
$category = (string) ($prompt['category'] ?? 'Writing & Content');
$subcategory = (string) ($prompt['subcategory'] ?? 'Blog Writing');
$key = $category . '|' . $subcategory;
if (!isset($counts[$key])) {
$counts[$key] = [
'category' => $category,
'subcategory' => $subcategory,
'count' => 0,
];
}
$counts[$key]['count']++;
}
usort(
$counts,
static fn(array $left, array $right): int => ((int) $right['count']) <=> ((int) $left['count'])
);
if (empty($counts)) {
foreach (array_slice(PromptCategoryRegistry::for_api(), 0, $limit) as $category) {
$counts[] = [
'category' => (string) ($category['category'] ?? ''),
'subcategory' => (string) (($category['subcategories'] ?? [])[0] ?? ''),
'count' => 0,
];
}
}
return array_slice($counts, 0, $limit);
}
/**
* Returns reviewer-facing queue data for public prompts that need community action.
*
* @return array{items:array<int,array<string,mixed>>,counts:array<string,int>}
*/
private function review_queue_context(int $user_id, int $limit = 10): array
{
$empty = [
'items' => [],
'counts' => [
'provisional_public' => 0,
'restricted_review' => 0,
'reverted' => 0,
'stale' => 0,
'urgent' => 0,
'total' => 0,
],
];
if ($user_id <= 0 || !$this->permissions->can_review_prompts($user_id)) {
return $empty;
}
$records = array_values(
array_filter(
$this->prompts->list(['limit' => 80], $user_id),