*/ function novasira_help_steps(): array { return [ [ 'title' => __('Connect an agent', 'novasira'), 'detail' => __('One endpoint and one application password. The Connect screen shows both, checks that this site can serve them, and gives you a prompt that proves the connection works before you trust it.', 'novasira'), 'url' => novasira_page_url('novasira-connect'), 'cta' => __('Open Connect', 'novasira'), ], [ 'title' => __('Scan the site', 'novasira'), 'detail' => __('Ask the agent for a full audit, or run it from the dashboard. The scan reads the database rather than the published pages, so the first result usually includes things no crawler had ever reported.', 'novasira'), 'url' => novasira_page_url('novasira'), 'cta' => __('Open the dashboard', 'novasira'), ], [ 'title' => __('Work one area', 'novasira'), 'detail' => __('Pick the worst finding and open the area it belongs to. Each area carries the method, the findings, and a prompt that hands the whole thing to the agent. One area at a time beats one enormous audit nobody acts on.', 'novasira'), 'url' => novasira_page_url('novasira-areas'), 'cta' => __('Open SEO areas', 'novasira'), ], ]; } /** Is the MCP endpoint actually being served? */ function novasira_help_server_up(): bool { if (function_exists('novasira_settings_bool') && !novasira_settings_bool('novasira_mcp_enabled')) { return false; } return novasira_is_connectable(); } /** The MCP endpoint for this site. */ function novasira_help_endpoint(): string { // Preferring the Connect screen's own accessor keeps the two screens from // ever quoting different URLs, but this screen has to work on a request // where that file was not loaded. if (function_exists('novasira_mcp_endpoint')) { return (string) novasira_mcp_endpoint(); } return rest_url('mcp/novasira'); } /** * The block somebody pastes into a support request. * * Deliberately short. The Status screen builds a full diagnostic; this is the * eight lines that answer most questions without anybody having to find that * screen first. Nothing here is a secret: no password, no token, no client id. */ function novasira_help_support_block(): string { $registered = 0; $names = novasira_ability_names(); foreach ($names as $name) { if (novasira_has_ability($name)) { ++$registered; } } $lines = []; $lines[] = 'Novasira ' . (defined('NOVASIRA_VERSION') ? NOVASIRA_VERSION : 'unknown'); $lines[] = 'WordPress ' . get_bloginfo('version') . ' | PHP ' . PHP_VERSION; $lines[] = 'Site: ' . home_url(); $lines[] = 'Endpoint: ' . novasira_help_endpoint(); $lines[] = 'MCP server: ' . (novasira_help_server_up() ? 'up' : 'not answering'); $lines[] = 'Abilities API: ' . (function_exists('wp_register_ability') ? 'present' : 'missing'); $lines[] = 'MCP adapter: ' . (class_exists('WP\\MCP\\Core\\McpAdapter') ? 'present' : 'missing'); $lines[] = 'Scan engine: ' . (function_exists('novasira_scan_all') ? 'loaded' : 'not loaded'); $lines[] = 'Tools registered: ' . $registered . ' of ' . count($names); $lines[] = 'Permalinks: ' . (get_option('permalink_structure') === '' ? 'plain' : 'pretty'); return implode("\n", $lines); } /** A code block with a copy button, in the shell's own markup. */ function novasira_help_echo_code(string $code): void { echo '
' . esc_html($code) . ''; echo ''; echo '
' . esc_html__( 'Each area is a discipline with its own method, its own checks and its own prompt. Open one and the method is on the screen next to what this site actually looks like.', 'novasira' ) . '
'; echo '| ' . esc_html__('Area', 'novasira') . ' | ' . '' . esc_html__('Group', 'novasira') . ' | ' . '' . esc_html__('What it covers', 'novasira') . ' | ' . '' . esc_html__('Data', 'novasira') . ' | ' . '
|---|---|---|---|
'
. esc_html((string) ($area['name'] ?? $slug)) . '';
echo '' . esc_html((string) $slug) . ' | ';
echo '' . esc_html((string) ($groups[$group] ?? $group)) . ' | '; echo '' . esc_html((string) ($area['summary'] ?? '')) . ' | '; echo '' . esc_html($live ? __('This site', 'novasira') : __('Elsewhere', 'novasira')) . ' | '; echo '
' . esc_html__( 'Most support requests this plugin will ever get are about something it deliberately does not have. So, plainly:', 'novasira' ) . '
'; $limits = [ __('It makes no outbound requests.', 'novasira') => __('Nothing in this plugin calls another server. There is no update check of its own, no analytics, no error reporting, and no "anonymous usage data". The build is tested for it: anything that would phone home fails the check before a release is made.', 'novasira'), __('There is no account and no key.', 'novasira') => __('No sign-up, no licence, no trial, nothing to activate and nothing to expire. It is GPL, and it works the same on the day you install it as on any other day.', 'novasira'), __('It does not crawl your site.', 'novasira') => __('It reads the database directly. That is the point — it sees drafts, scheduled posts, private pages and empty alt attributes that a crawler never reaches. It also means it reports what is stored, not what a visitor is served after a theme, a cache and a CDN have had their turn.', 'novasira'), __('It changes almost nothing on its own.', 'novasira') => __('Two of the nine tools can write, both only when asked, and both check that the calling user may edit that specific post first. Everything else reads.', 'novasira'), ]; echo '' . esc_html__( 'Impressions, positions, who links to you, what a competitor published, keyword volumes, a Maps profile — none of that is in WordPress, and Novasira ships no API key and no crawler to go and get it. These areas carry the method and the prompt instead, and say so on their own screens. The agent brings the numbers; a panel that invented them would be worse than one that admits it cannot.', 'novasira' ) . '
'; echo '' . esc_html__( 'Novasira is open source. Bugs, questions and feature requests all go to the support forum, where they are public and searchable — which means the next person with your problem finds the answer instead of asking again.', 'novasira' ) . '
'; echo '' . '' . esc_html__('Report a problem or ask a question', 'novasira') . '' . ' · ' . '' . esc_html__('Read the source', 'novasira') . '' . '
'; echo '' . esc_html__( 'Versions, whether the server is answering, and how many tools registered. No password, no token and no client id is in it.', 'novasira' ) . '
'; novasira_help_echo_code(novasira_help_support_block()); echo '' . sprintf( /* translators: %s: a link to the Status screen. */ esc_html__('%s runs the full set of checks and explains each failure, if the ten lines above are not enough.', 'novasira'), '' . esc_html__('Status', 'novasira') . '' ) . '
'; if (!$up) { echo '' . esc_html__( 'The MCP server is not answering on this request, so an agent cannot reach this site. Status will say which of the three reasons it is.', 'novasira' ) . '
' . esc_html__('You do not have permission to view Novasira.', 'novasira') . '