';
echo Ui::header(__('Help', 'aipcf-ai-provider-for-cloudflare'), __('Check that everything works, see what happened, and find out more.', 'aipcf-ai-provider-for-cloudflare'), SettingsPage::connectionPillUi()); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ui escapes
echo '
';
echo '
';
echo self::checks(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ui escapes
echo self::errors(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ui escapes
echo self::report(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ui escapes
$cards = Ui::grid(
Ui::card(__('Activity', 'aipcf-ai-provider-for-cloudflare'), Ui::actions([['label' => __('Open the activity log', 'aipcf-ai-provider-for-cloudflare'), 'url' => ActivityPage::pageUrl()]]), [
'text' => __('What people did in AIPCF, and what it did on its own.', 'aipcf-ai-provider-for-cloudflare'),
])
. Ui::card(__('Setup', 'aipcf-ai-provider-for-cloudflare'), Ui::actions([['label' => __('Run the setup again', 'aipcf-ai-provider-for-cloudflare'), 'url' => Wizard::url('goals')]]), [
'text' => __('Choose features, the content index and the budget again, step by step.', 'aipcf-ai-provider-for-cloudflare'),
])
);
echo $cards; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ui escapes
echo self::about(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Ui escapes
echo '
';
}
/**
* The last "Run all checks" results; until then, the quick Site Health tests.
*/
private static function checks(): string
{
$last = Checks::last();
$body = '';
if ($last !== null) {
foreach ($last['results'] as $r) {
$body .= self::checkLine($r['state'], $r['label'], $r['detail'], $r['fix']);
}
/* translators: %s: time since, e.g. "5 mins" */
$text = sprintf(__('Last run %s ago. The chat and content index checks are real, tiny requests.', 'aipcf-ai-provider-for-cloudflare'), human_time_diff((int) $last['at']));
} else {
$results = [SiteHealth::runTest()];
if (EmbeddingSettings::enabled()) {
$results[] = SiteHealth::runEmbeddingsTest();
}
foreach ($results as $r) {
$state = ['good' => 'ok', 'recommended' => 'warn', 'critical' => 'bad'][(string) ($r['status'] ?? '')] ?? '';
$body .= self::checkLine($state, (string) ($r['label'] ?? ''), $state === 'ok' ? '' : trim(wp_strip_all_tags((string) ($r['description'] ?? ''))), null);
}
$text = __('A quick look. Run all checks to try each part for real.', 'aipcf-ai-provider-for-cloudflare');
}
$body .= Ui::actions([
[
'label' => __('Run all checks', 'aipcf-ai-provider-for-cloudflare'),
'url' => wp_nonce_url(admin_url('admin-post.php?action=aipcf_diagnostics_run'), 'aipcf_diagnostics_run'),
'kind' => 'primary',
'busy' => __('Checking...', 'aipcf-ai-provider-for-cloudflare'),
],
['label' => __('Site Health', 'aipcf-ai-provider-for-cloudflare'), 'url' => admin_url('site-health.php'), 'kind' => 'link'],
]);
return Ui::card(__('Checks', 'aipcf-ai-provider-for-cloudflare'), $body, ['id' => 'aipcf-checks', 'text' => $text]);
}
/**
* @param array{0: string, 1: string}|null $fix
*/
private static function checkLine(string $state, string $label, string $detail, ?array $fix): string
{
$words = [
'ok' => __('OK', 'aipcf-ai-provider-for-cloudflare'),
'warn' => __('Check', 'aipcf-ai-provider-for-cloudflare'),
'bad' => __('Problem', 'aipcf-ai-provider-for-cloudflare'),
'skip' => __('Skipped', 'aipcf-ai-provider-for-cloudflare'),
];
$out = '
';
}
/**
* The last failed requests to Cloudflare and the content index.
*/
private static function errors(): string
{
$all = ErrorLog::all();
if ($all === []) {
return Ui::card(__('Recent errors', 'aipcf-ai-provider-for-cloudflare'), '', ['text' => __('None in the last 7 days.', 'aipcf-ai-provider-for-cloudflare'), 'id' => 'aipcf-errors']);
}
$rows = [];
foreach (array_slice($all, 0, 20) as $e) {
$what = $e['service'] . ($e['model'] !== '' ? ' · ' . $e['model'] : '');
$result = trim(($e['status'] > 0 ? 'HTTP ' . $e['status'] : '') . ' ' . $e['code']) . ($e['message'] !== '' ? ': ' . $e['message'] : '');
$rows[] = [
/* translators: %s: time since, e.g. "5 mins" */
esc_html(sprintf(__('%s ago', 'aipcf-ai-provider-for-cloudflare'), human_time_diff((int) $e['time']))),
esc_html($e['feature'] !== '' ? task_label($e['feature']) : '-'),
esc_html($what),
esc_html($result),
'' . esc_html($e['ray'] !== '' ? $e['ray'] : '-') . '',
];
}
$body = Ui::table([__('When', 'aipcf-ai-provider-for-cloudflare'), __('Feature', 'aipcf-ai-provider-for-cloudflare'), __('What', 'aipcf-ai-provider-for-cloudflare'), __('Result', 'aipcf-ai-provider-for-cloudflare'), __('Request ID', 'aipcf-ai-provider-for-cloudflare')], $rows);
$body .= Ui::actions([[
'label' => __('Clear the list', 'aipcf-ai-provider-for-cloudflare'),
'url' => wp_nonce_url(admin_url('admin-post.php?action=aipcf_errors_clear'), 'aipcf_errors_clear'),
'kind' => 'link',
'confirm' => __('Clear the list of recent errors?', 'aipcf-ai-provider-for-cloudflare'),
]]);
return Ui::card(__('Recent errors', 'aipcf-ai-provider-for-cloudflare'), $body, [
'id' => 'aipcf-errors',
/* translators: %d: number of failed requests */
'text' => sprintf(_n('%d failed request in the last 7 days. The request ID helps Cloudflare find it.', '%d failed requests in the last 7 days. The request ID helps Cloudflare find them.', count($all), 'aipcf-ai-provider-for-cloudflare'), count($all)),
]);
}
/**
* The diagnostics report: copy, download, and where to send it.
*/
private static function report(): string
{
$text = Report::text();
$body = '
'
. ''
. '' . esc_html__('Download', 'aipcf-ai-provider-for-cloudflare') . ''
. '' . Ui::external(__('Report a problem', 'aipcf-ai-provider-for-cloudflare'), add_query_arg(['title' => rawurlencode('Problem: '), 'body' => rawurlencode("What happened:\n\nWhat I expected:\n\nDiagnostics report (AIPCF > Help > Copy the report):\n\n```\n(paste it here)\n```\n")], self::ISSUES))
. '·' . Ui::external(__('Support forum', 'aipcf-ai-provider-for-cloudflare'), 'https://wordpress.org/support/plugin/aipcf-ai-provider-for-cloudflare/') . ''
. '
';
$body .= Ui::more(__('What the report contains', 'aipcf-ai-provider-for-cloudflare'), '
' . esc_html($text) . '
');
return Ui::card(__('Diagnostics report', 'aipcf-ai-provider-for-cloudflare'), $body, [
'id' => 'aipcf-report-card',
'text' => __('For support: versions, settings and recent errors. No tokens, account ID, addresses or content.', 'aipcf-ai-provider-for-cloudflare'),
]);
}
public static function handleRun(): void
{
self::guard('aipcf_diagnostics_run');
Checks::run();
wp_safe_redirect(self::url() . '#aipcf-checks');
exit;
}
public static function handleDownload(): void
{
self::guard('aipcf_diagnostics_download');
nocache_headers();
header('Content-Type: text/plain; charset=utf-8');
header('Content-Disposition: attachment; filename="aipcf-diagnostics-' . gmdate('Y-m-d') . '.txt"');
echo Report::text(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- a plain-text download, redacted
exit;
}
public static function handleClear(): void
{
self::guard('aipcf_errors_clear');
ErrorLog::clear();
wp_safe_redirect(self::url() . '#aipcf-errors');
exit;
}
private static function guard(string $action): void
{
if (!current_user_can('manage_options')) {
wp_die(esc_html__('You do not have permission to do this.', 'aipcf-ai-provider-for-cloudflare'), 403);
}
check_admin_referer($action);
}
private static function about(): string
{
$body = Ui::status(sprintf(
/* translators: %s: plugin version */
__('Version %s.', 'aipcf-ai-provider-for-cloudflare'),
\AIPCF_VERSION
));
$body .= Ui::actions([
['label' => __('Plugin page', 'aipcf-ai-provider-for-cloudflare'), 'url' => 'https://wordpress.org/plugins/aipcf-ai-provider-for-cloudflare/', 'kind' => 'link'],
['label' => __('Support forum', 'aipcf-ai-provider-for-cloudflare'), 'url' => 'https://wordpress.org/support/plugin/aipcf-ai-provider-for-cloudflare/', 'kind' => 'link'],
[
'label' => __('Reset AIPCF', 'aipcf-ai-provider-for-cloudflare'),
'url' => wp_nonce_url(admin_url('admin-post.php?action=aipcf_reset'), 'aipcf_reset'),
'kind' => 'link',
'confirm' => __('Reset AIPCF? This deletes its settings, saved credentials, prompt edits, usage history, Backfill progress, caches, logged searches and related lists. It keeps the meta descriptions, alt text and images it added to posts, and the posts you left out. You will connect again afterwards.', 'aipcf-ai-provider-for-cloudflare'),
],
]);
return Ui::card(Brand::FULL, $body, [
'text' => __('An independent community plugin, not an official Cloudflare or WordPress product. Built so every small site gets useful AI without a bill.', 'aipcf-ai-provider-for-cloudflare'),
]);
}
}