'string', 'sanitize_callback' => 'citami_sanitize_api_key', 'default' => '', )); register_setting('citami_settings', 'citami_endpoint', array( 'type' => 'string', 'sanitize_callback' => 'citami_sanitize_endpoint', 'default' => citami_default_endpoint(), )); register_setting('citami_settings', CITAMI_REVIEW_ONLY_OPT, array( 'type' => 'string', 'sanitize_callback' => 'citami_sanitize_review_only', 'default' => '1', )); // v2.11.0 — CONFIGURABLE-SLUGS (gap M2): slug extra per il // rilevamento pagine about/faq, fusi con i default hardcoded. register_setting('citami_settings', CITAMI_ABOUT_SLUGS_OPT, array( 'type' => 'string', 'sanitize_callback' => 'citami_sanitize_slug_list', 'default' => '', )); register_setting('citami_settings', CITAMI_FAQ_SLUGS_OPT, array( 'type' => 'string', 'sanitize_callback' => 'citami_sanitize_slug_list', 'default' => '', )); }); function citami_settings_page() { if (!current_user_can('manage_options')) return; // ?tab=… picks the screen; default = overview (2.38). $active_tab = isset($_GET['tab']) ? sanitize_key((string) $_GET['tab']) : 'overview'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display only: which screen to show if (!in_array($active_tab, citami_ui_tab_ids(), true)) { $active_tab = 'overview'; } $queue = get_option(CITAMI_FIX_QUEUE_OPT, array()); $queue_array = is_array($queue) ? $queue : array(); $pending_count = 0; foreach ($queue_array as $fix) { $status = is_array($fix) && isset($fix['status']) ? (string) $fix['status'] : 'pending'; if ($status === 'pending') $pending_count++; } // Connection state at a glance (2.46 — one state, with the reason as tooltip and a link to fix it). $conn = citami_connection_state(); $pill_class = 'citami-pill--' . $conn['class']; $pill_text = $conn['label']; $nav = citami_ui_nav_items($pending_count); $labels = array(); foreach ($nav as $it) { $labels[$it['id']] = $it['label']; } $labels['setup'] = citami_t('Primo avvio guidato', 'Guided first run'); $dashboard_url = citami_lang_url(citami_brand_site() . '/dashboard'); ?>
v

' . esc_html(citami_t('Impostazioni salvate.', 'Settings saved.')) . '

'; } $action_notice = get_transient('citami_action_notice'); if (is_array($action_notice) && !empty($action_notice['message'])) { $type = !empty($action_notice['type']) ? $action_notice['type'] : 'info'; printf( '

%s

', esc_attr($type), wp_kses(citami_notice_text_html($action_notice), citami_kses_allowed()) ); delete_transient('citami_action_notice'); } ?>

Impostazioni → Plugin → bottone «Mostra API key» → Copia.", 'Connect this site to your Citami dashboard. If you downloaded the ZIP from the dashboard, the key is already preloaded — no need to paste it. Otherwise: Settings → Plugin → "Show API key" button → Copy.' )); ?>

0 ? wp_date(get_option('date_format') . ' ' . get_option('time_format'), $citami_health_ts) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display only: which line to highlight $citami_health_focus = isset($_GET['focus']) && (string) $_GET['focus'] === 'health'; $citami_health_notice = $citami_health_focus ? get_transient('citami_health_check_notice') : null; if (is_array($citami_health_notice) && !empty($citami_health_notice['message'])) { delete_transient('citami_health_check_notice'); } else { $citami_health_notice = null; } $citami_pending_n = 0; foreach ($queue as $citami_fix) { if (is_array($citami_fix) && (!isset($citami_fix['status']) || $citami_fix['status'] === 'pending')) { $citami_pending_n++; } } $citami_update = defined('CITAMI_UPDATE_TRANSIENT') ? get_transient(CITAMI_UPDATE_TRANSIENT) : false; $citami_update_version = is_array($citami_update) && !empty($citami_update['version']) && version_compare((string) $citami_update['version'], CITAMI_PLUGIN_VERSION, '>') ? (string) $citami_update['version'] : ''; $citami_has_key = citami_get_api_key() !== ''; $citami_conn = citami_connection_state(); $citami_silence = citami_cron_silence(); $citami_cron_dot = $citami_conn['state'] === 'cron' ? 'warn' : ($citami_silence === null ? 'muted' : 'good'); ?> ", 'Meta tags in the '); case 'robots_txt': return citami_t('Regole robots.txt', 'robots.txt rules'); case 'llms_txt': return citami_t('File llms.txt', 'llms.txt file'); case 'schema_injection': case 'schema_markup': return citami_t('Dati strutturati (JSON-LD)', 'Structured data (JSON-LD)'); case 'faq_page': return citami_t('Pagina FAQ', 'FAQ page'); } return citami_t('Da fare a mano', 'To do by hand'); } /** 2.60 — an ISO date of the queue, in the site's date and time format ('' when empty). */ function citami_fix_when($iso) { $iso = (string) $iso; if ($iso === '') { return ''; } $ts = strtotime($iso); if (!$ts) { return $iso; } $df = (string) get_option('date_format'); $tf = (string) get_option('time_format'); return wp_date(($df !== '' ? $df : 'd/m/Y') . ' ' . ($tf !== '' ? $tf : 'H:i'), $ts); } /** 2.60 — status of a queue row: array(pill class, label). 2.61 — design-system pills. */ function citami_fix_status_label($status) { switch ((string) $status) { case 'pending': return array('citami-pill--warn', citami_t('Da approvare', 'To approve')); case 'applied': return array('citami-pill--ok', citami_t('Applicato', 'Applied')); case 'rejected': return array('citami-pill--bad', citami_t('Rifiutato', 'Rejected')); case 'failed': return array('citami-pill--bad', citami_t('Non riuscito', 'Failed')); case 'rolled_back': return array('citami-pill--muted', citami_t('Revocato', 'Revoked')); case 'manual': return array('citami-pill--warn', citami_t('Da fare a mano', 'To do by hand')); } return array('citami-pill--muted', ucfirst((string) $status)); } /** 2.60 — the pages a JSON-LD payload lands on: home | about | faq (router of citami_store_schema_payload). */ function citami_fix_schema_targets($code) { $decoded = json_decode((string) $code, true); $targets = array(); if (is_array($decoded)) { $nodes = (isset($decoded['@graph']) && is_array($decoded['@graph'])) ? $decoded['@graph'] : array($decoded); foreach ($nodes as $node) { if (is_array($node)) { $targets[citami_schema_target($node)] = true; } } } $out = array(); foreach (array('home', 'about', 'faq') as $k) { if (isset($targets[$k])) { $out[] = $k; } } return $out ? $out : array('home'); } /** 2.60 — where an applied fix can be seen on the site ('' for manual types). */ function citami_fix_site_url($fix_type) { switch ((string) $fix_type) { case 'robots_txt': return home_url('/robots.txt'); case 'llms_txt': return home_url('/llms.txt'); case 'faq_page': $ours = function_exists('get_posts') ? get_posts(array( 'post_type' => 'page', 'post_status' => array('publish'), 'meta_key' => '_citami_faq_page', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- one flag on at most a handful of pages 'meta_value' => '1', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value 'numberposts' => 1, )) : array(); if (!empty($ours) && is_object($ours[0]) && function_exists('get_permalink')) { $link = (string) get_permalink($ours[0]); if ($link !== '') { return $link; } } return home_url('/faq/'); case 'meta_tags': case 'schema_injection': case 'schema_markup': return home_url('/'); } return ''; } /** 2.60 — the confirm asked before an approval that rewrites a public file or page ('' = no confirm). */ function citami_fix_approve_confirm($fix_type, $code) { switch ((string) $fix_type) { case 'robots_txt': return sprintf(citami_t('Aggiungo queste righe al robots.txt del sito (%s): cambia cosa possono leggere i crawler. Continuare?', 'These lines will be added to the site robots.txt (%s): it changes what crawlers may read. Continue?'), home_url('/robots.txt')); case 'llms_txt': return sprintf(citami_t('Il file %s del sito viene sostituito con questo contenuto. Continuare?', 'The site file %s will be replaced with this content. Continue?'), home_url('/llms.txt')); case 'faq_page': return sprintf(citami_t('Creo o aggiorno la pagina pubblica /faq con %d domande e risposte, visibile a tutti. Continuare?', 'The public /faq page will be created or updated with %d questions and answers, visible to everyone. Continue?'), count(citami_faq_pairs_from_jsonld((string) $code))); } return ''; } /** * 2.60 — the "what changes / where" line of a queue row, by type. FAQ * pages list their questions and answers here, not only as raw code. */ function citami_fix_effect_html($fix_type, $code) { $link = function ($url, $text) { return '' . esc_html($text) . ''; }; $extra = ''; switch ((string) $fix_type) { case 'meta_tags': $line = esc_html(citami_t("Aggiunge questi tag nell' di ogni pagina del sito (invisibili ai visitatori, letti da motori e AI).", 'Adds these tags to the of every page of the site (invisible to visitors, read by search engines and AI).')); break; case 'robots_txt': $line = esc_html(citami_t('Aggiunge queste righe a robots.txt:', 'Adds these lines to robots.txt:')) . ' ' . $link(home_url('/robots.txt'), '/robots.txt'); break; case 'llms_txt': $line = esc_html(citami_t('Sostituisce il file', 'Replaces the file')) . ' ' . $link(home_url('/llms.txt'), '/llms.txt') . ' ' . esc_html(citami_t('con il contenuto qui sotto.', 'with the content below.')); break; case 'schema_injection': case 'schema_markup': $names = array( 'home' => citami_t('home page', 'home page'), 'about' => citami_t('pagina Chi siamo', 'About page'), 'faq' => citami_t('pagina FAQ', 'FAQ page'), ); $where = array(); foreach (citami_fix_schema_targets($code) as $k) { $where[] = $names[$k]; } $line = esc_html(sprintf(citami_t('Aggiunge dati strutturati (JSON-LD, invisibili ai visitatori) a: %s.', 'Adds structured data (JSON-LD, invisible to visitors) to: %s.'), implode(', ', $where))); break; case 'faq_page': $line = esc_html(citami_t('Crea o aggiorna la pagina pubblica', 'Creates or updates the public page')) . ' ' . $link(home_url('/faq/'), '/faq') . ' ' . esc_html(citami_t('con queste domande e risposte (più il loro schema FAQPage).', 'with these questions and answers (plus their FAQPage schema).')); $pairs = citami_faq_pairs_from_jsonld((string) $code); if ($pairs) { $extra = '
    '; foreach ($pairs as $pair) { $extra .= '
  1. ' . esc_html(wp_strip_all_tags($pair['q'])) . '
    ' . esc_html(wp_strip_all_tags($pair['a'])) . '
  2. '; } $extra .= '
'; } else { $extra = '

' . esc_html(citami_t('Nessuna domanda/risposta leggibile nel codice: l\'approvazione non andrebbe a buon fine.', 'No readable question/answer in the code: the approval would fail.')) . '

'; } break; default: $line = esc_html(citami_t('Non cambia nulla da solo: va fatto a mano, seguendo il codice qui sotto.', 'Changes nothing on its own: it is done by hand, following the code below.')); } return '

' . esc_html(citami_t('Cosa cambia:', 'What changes:')) . ' ' . $line . '

' . $extra; } /** 2.60 — HTML id of a queue row (queue ids look like fix_6523….1234). */ function citami_fix_anchor($id) { return 'citami-fix-' . preg_replace('/[^A-Za-z0-9_\-]/', '-', (string) $id); } /** 2.60 — transient holding the one-shot outcome shown inside a queue row. */ function citami_fix_notice_key($id) { return 'citami_fix_notice_' . md5((string) $id); } /** * Render the Pending Fixes review table. Approve/Reject submit to * admin-post.php?action=citami_fix_action which routes to * citami_handle_fix_action(); every action comes back to its row. */ function citami_render_pending_fixes_tab(array $queue) { $review_only = citami_is_review_only(); if (empty($queue) && citami_get_api_key() === '') { echo wp_kses(citami_connect_card_html('pending'), citami_kses_allowed()); return; } if (empty($queue) && citami_is_free_account()) { echo wp_kses('
' . esc_html(citami_t('Account gratuito', 'Free account')) . '

' . esc_html(citami_t('Correzioni dall\'audit', 'Fixes from the audit')) . '

' . esc_html(citami_upgrade_line('fixes')) . '

' . citami_upgrade_link_html('pending_fixes', citami_t('Vedi i piani', 'See the plans')) . '

', citami_kses_allowed()); return; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display only: which row to highlight $focus = isset($_GET['focus']) ? sanitize_text_field(wp_unslash((string) $_GET['focus'])) : ''; $counts = array('pending' => 0, 'manual' => 0, 'applied' => 0, 'closed' => 0, 'failed' => 0); foreach ($queue as $fix) { if (!is_array($fix)) continue; $st = isset($fix['status']) ? (string) $fix['status'] : 'pending'; if ($st === 'pending' || $st === 'manual' || $st === 'applied' || $st === 'failed') { $counts[$st]++; } elseif ($st === 'rejected' || $st === 'rolled_back') { $counts['closed']++; } } ?>

Approva per applicarlo al sito (JSON-LD, meta tag, llms.txt, robots.txt) o Rifiuta per scartarlo. Un fix applicato si toglie dal sito con Revoca. La coda mantiene gli ultimi 50.', 'Every fix received from Citami is queued here. Click Approve to apply it to your site (JSON-LD, meta tags, llms.txt, robots.txt) or Reject to discard it. An applied fix comes off the site with Revoke. The queue keeps the latest 50.' )); ?>

Auto-apply attivo: i fix arrivano già applicati al sito e questa lista ne è lo storico. Per toglierne uno dal sito usa Revoca sulla sua riga: rimuove quello che il fix aveva aggiunto (blocco nel <head>, regole di robots.txt, llms.txt, pagina FAQ).", 'Auto-apply enabled: fixes arrive already applied to your site and this list is their history. To take one off the site use Revoke on its row: it removes what the fix had added (<head> block, robots.txt rules, llms.txt, FAQ page).' )); ?>

0): ?>
0): ?>

—
' . esc_html(citami_t('(nessun codice associato)', '(no code attached)')) . ''; } switch ($fix_type) { case 'schema_injection': case 'schema_markup': // Pretty-print JSON if parsable; otherwise show raw. $decoded = json_decode($code, true); if (json_last_error() === JSON_ERROR_NONE) { $pretty = wp_json_encode($decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); return '
' . esc_html($pretty) . '
'; } return '
' . esc_html($code) . '

' . esc_html(citami_t('JSON non leggibile: così com\'è non si può applicare.', 'Unreadable JSON: it cannot be applied as it is.')) . '

'; case 'meta_tags': case 'llms_txt': case 'robots_txt': default: return '
' . esc_html($code) . '
'; } } /** * Apply a queued fix's code to the site. Mirrors the auto-apply branches * of citami_rest_apply_fix but operates on a stored queue entry. Returns * array('ok' => bool, 'message' => string). */ function citami_apply_queued_fix(array $fix) { $fix_type = isset($fix['fix_type']) ? (string) $fix['fix_type'] : ''; $title = isset($fix['title']) ? (string) $fix['title'] : ''; $code = isset($fix['code_snippet']) ? (string) $fix['code_snippet'] : ''; $fix_id = isset($fix['fix_id']) ? (string) $fix['fix_id'] : ''; if (!in_array($fix_type, array('llms_txt', 'robots_txt', 'schema_injection', 'schema_markup', 'meta_tags', 'faq_page'), true)) { // Manual-only fix types (bio_author, content_restructure, etc.) // — record approval but no auto-application is possible. Operator must // edit the site manually using the code preview. return array( 'ok' => true, 'manual' => true, 'message' => citami_t('Da fare a mano: questo tipo di fix non si applica da solo. Usa il codice qui sotto.', 'To do by hand: this fix type does not apply itself. Use the code below.'), ); } // 2.59 — the same routine as the platform push, title and fix id included, // so Revoke finds what this approval wrote (robots rules, llms.txt, FAQ page). $res = citami_apply_fix_now($fix_type, $title, $code, $fix_id); if (is_wp_error($res)) { return array('ok' => false, 'message' => $res->get_error_message()); } $data = (array) $res->get_data(); return array('ok' => !empty($data['success']), 'message' => isset($data['message']) ? (string) $data['message'] : ''); } /** * 2.60 — back to the queue row that was acted on, with its outcome inside * the row (shown once) and the row highlighted. */ function citami_fix_redirect_to_row($fix_id, array $notice) { set_transient(citami_fix_notice_key($fix_id), $notice, 120); wp_safe_redirect(citami_admin_url('pending', array('focus' => (string) $fix_id)) . '#' . citami_fix_anchor($fix_id)); exit; } /** * Admin-post handler for Approve/Reject/Revoke. Validates capability + * nonce, routes to citami_apply_queued_fix on approve, marks rejected on * reject, rolls back on revoke. Comes back to the row (2.60). */ function citami_handle_fix_action() { if (!current_user_can('manage_options')) { wp_die(esc_html(citami_t('Permesso negato.', 'Permission denied.')), '', array('response' => 403)); } $fix_id = isset($_POST['fix_id']) ? sanitize_text_field(wp_unslash($_POST['fix_id'])) : ''; $decision = isset($_POST['decision']) ? sanitize_key((string) $_POST['decision']) : ''; $nonce = isset($_POST['_citami_fix_nonce']) ? sanitize_text_field(wp_unslash($_POST['_citami_fix_nonce'])) : ''; if ($fix_id === '' || !in_array($decision, array('approve', 'reject', 'revoke'), true)) { wp_die(esc_html(citami_t('Parametri mancanti.', 'Missing parameters.')), '', array('response' => 400)); } if (!wp_verify_nonce($nonce, 'citami_fix_action_' . $fix_id)) { wp_die(esc_html(citami_t('Nonce non valido o scaduto. Ricarica la pagina e riprova.', 'Invalid or expired nonce. Reload the page and try again.')), '', array('response' => 403)); } $queue = get_option(CITAMI_FIX_QUEUE_OPT, array()); if (!is_array($queue)) $queue = array(); $target = null; foreach ($queue as $fix) { if (is_array($fix) && isset($fix['id']) && $fix['id'] === $fix_id) { $target = $fix; break; } } if (!$target) { // No row to come back to: the message goes on top of the tab. set_transient('citami_action_notice', array( 'type' => 'error', 'message' => citami_t('Fix non trovato (potrebbe essere uscito dalla coda dei 50 più recenti).', 'Fix not found (it may have dropped out of the 50 most recent).'), ), 30); wp_safe_redirect(citami_admin_url('pending')); exit; } $current_status = isset($target['status']) ? (string) $target['status'] : 'pending'; $title = isset($target['title']) && (string) $target['title'] !== '' ? (string) $target['title'] : citami_t('(senza titolo)', '(untitled)'); // v2.13.0 — 'revoke' undoes an APPLIED fix (rollback by fix id / title). if ($decision === 'revoke') { if ($current_status !== 'applied') { citami_fix_redirect_to_row($fix_id, array( 'type' => 'warning', 'message' => citami_t('Solo un fix applicato può essere revocato.', 'Only an applied fix can be revoked.'), )); } $removed = citami_rollback_fix( isset($target['fix_id']) ? (string) $target['fix_id'] : '', isset($target['title']) ? (string) $target['title'] : '' ); $n_removed = array_sum($removed) - $removed['queue']; if ($n_removed === 0) { // 2.59 — nothing found to remove: say so instead of a green "(0)". citami_fix_redirect_to_row($fix_id, array( 'type' => 'warning', 'message' => citami_t('Non ho trovato sul sito niente da rimuovere per questo fix (forse è già stato tolto a mano). Il fix resta segnato come applicato.', 'Nothing to remove was found on the site for this fix (it may have been removed by hand). The fix stays marked as applied.'), )); } citami_update_fix_in_queue($fix_id, array( 'status' => 'rolled_back', 'actioned_at' => gmdate('c'), 'actioned_by' => wp_get_current_user()->user_login ?? 'unknown', 'action_message' => citami_t('Revocato dall\'admin: rimosso dal sito.', 'Revoked by admin: removed from the site.'), )); // WP25 — the platform learns the fix is no longer live. citami_sync_report(isset($target['fix_id']) ? (string) $target['fix_id'] : $fix_id, false, citami_t('Revocato dall\'admin in WordPress: rimosso dal sito.', 'Revoked by the admin in WordPress: removed from the site.'), 'revoked'); citami_fix_redirect_to_row($fix_id, array( 'type' => 'success', 'message' => sprintf(citami_t('Fix rimosso dal sito: %d elementi tolti.', 'Fix removed from the site: %d items taken out.'), $n_removed), )); } if ($current_status !== 'pending') { list(, $status_label) = citami_fix_status_label($current_status); citami_fix_redirect_to_row($fix_id, array( 'type' => 'warning', 'message' => sprintf(citami_t('Fix già gestito (stato: %s).', 'Fix already handled (status: %s).'), $status_label), )); } $user = wp_get_current_user(); $actor = $user && !empty($user->ID) && isset($user->user_login) ? (string) $user->user_login : 'unknown'; if ($decision === 'reject') { citami_update_fix_in_queue($fix_id, array( 'status' => 'rejected', 'actioned_at' => gmdate('c'), 'actioned_by' => $actor, 'action_message' => citami_t("Rifiutato dall'admin.", 'Rejected by admin.'), )); // WP25 — the platform stops waiting for it. citami_sync_report(isset($target['fix_id']) ? (string) $target['fix_id'] : $fix_id, false, citami_t("Rifiutato dall'admin in WordPress.", 'Rejected by the admin in WordPress.'), 'rejected'); citami_fix_redirect_to_row($fix_id, array( 'type' => 'success', 'message' => sprintf(citami_t('Fix rifiutato: «%s». Sul sito non è cambiato nulla.', 'Fix rejected: "%s". Nothing changed on the site.'), $title), )); } $result = citami_apply_queued_fix($target); $manual = !empty($result['manual']); citami_update_fix_in_queue($fix_id, array( 'status' => $manual ? 'manual' : ($result['ok'] ? 'applied' : 'failed'), 'actioned_at' => gmdate('c'), 'actioned_by' => $actor, 'action_message' => $result['message'], )); // WP25 — approving in wp-admin is an application too: report it like the sync pull does. // 2.65 — a manual-only fix approved here is not live: nothing to report. if (!$manual) { citami_sync_report(isset($target['fix_id']) ? (string) $target['fix_id'] : $fix_id, (bool) $result['ok'], (string) $result['message'], $result['ok'] ? 'applied' : 'failed'); } if ($manual) { $notice = array('type' => 'warning', 'message' => (string) $result['message']); } elseif ($result['ok']) { $notice = array('type' => 'success', 'message' => citami_t('Fix applicato: ', 'Fix applied: ') . $result['message']); } else { $notice = array('type' => 'error', 'message' => citami_t('Errore applicazione: ', 'Could not apply: ') . $result['message']); } citami_fix_redirect_to_row($fix_id, $notice); } add_action('admin_post_citami_fix_action', 'citami_handle_fix_action'); /** * 2.60 — Settings tab actions. do=check runs the connection check on * demand (the page itself only reads the last stored result) and comes * back to the Status line with the outcome there. */ function citami_handle_settings_action() { if (!current_user_can('manage_options')) { wp_die(esc_html(citami_t('Permesso negato.', 'Permission denied.')), '', array('response' => 403)); } $nonce = isset($_POST['_citami_settings_nonce']) ? sanitize_text_field(wp_unslash($_POST['_citami_settings_nonce'])) : ''; if (!wp_verify_nonce($nonce, 'citami_settings_action')) { wp_die(esc_html(citami_t('Nonce non valido o scaduto. Ricarica la pagina e riprova.', 'Invalid or expired nonce. Reload the page and try again.')), '', array('response' => 403)); } $do = isset($_POST['do']) ? sanitize_key((string) $_POST['do']) : ''; if ($do === 'check') { if (citami_get_api_key() === '') { $notice = array('type' => 'warning', 'message' => citami_t('Prima inserisci e salva la API key, poi verifica la connessione.', 'Enter and save the API key first, then check the connection.')); } else { $health = citami_health_ping(); $ok = is_array($health) && !empty($health['ok']); $msg = is_array($health) && isset($health['message']) ? (string) $health['message'] : ''; $notice = $ok ? array('type' => 'success', 'message' => sprintf(citami_t('Connessione verificata ora: %s.', 'Connection checked just now: %s.'), $msg)) : array('type' => 'error', 'message' => sprintf(citami_t('Connessione non riuscita: %s. Controlla chiave ed endpoint qui sopra.', 'Connection failed: %s. Check the key and endpoint above.'), $msg)); } set_transient('citami_health_check_notice', $notice, 120); wp_safe_redirect(citami_admin_url('general', array('focus' => 'health')) . '#citami-health'); exit; } wp_safe_redirect(citami_admin_url('general')); exit; } add_action('admin_post_citami_settings_action', 'citami_handle_settings_action'); /** * 2.56.1 — links on the Plugins screen: Settings always, "Get started" * (the guided first run) until the site is connected. */ function citami_plugin_action_links($links) { $links = is_array($links) ? $links : array(); $own = array('' . esc_html(citami_t('Impostazioni', 'Settings')) . ''); if (citami_get_api_key() === '' && function_exists('citami_setup_url')) { $own[] = '' . esc_html(citami_t('Inizia', 'Get started')) . ''; } return array_merge($own, $links); } if (defined('CITAMI_PLUGIN_FILE') && function_exists('plugin_basename')) { add_filter('plugin_action_links_' . plugin_basename(CITAMI_PLUGIN_FILE), 'citami_plugin_action_links'); }