time()), false); set_transient('citami_setup_redirect', 1, 60); } }); add_action('admin_init', function () { if (!get_transient('citami_setup_redirect') || wp_doing_ajax() || !current_user_can('manage_options')) { return; } delete_transient('citami_setup_redirect'); if (isset($_GET['activate-multi'])) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read only: WordPress's own bulk-activation flag return; // bulk activation: never hijack the screen } wp_safe_redirect(citami_setup_url(1)); exit; }); // Notice until done or skipped (not on the wizard itself). add_action('admin_notices', function () { if (!current_user_can('manage_options') || citami_setup_is_done()) { return; } if (isset($_GET['page'], $_GET['tab']) && $_GET['page'] === 'citami-connector' && $_GET['tab'] === 'setup') { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read only: already on the setup screen return; } $skip = citami_setup_skip_url(); echo '

' . esc_html(citami_brand_name()) . ' · ' . esc_html(citami_t('Cinque minuti per dire alle AI chi sei: scheda dei fatti, pagina Chi siamo, crawler.', 'Five minutes to tell the AI who you are: fact sheet, About page, crawlers.')) . ' ' . esc_html(citami_t('Inizia', 'Start')) . ' ' . esc_html(citami_t('Non ora', 'Not now')) . '

'; }); /* ---------------------------------------------------------------- */ /* Prefill */ /* ---------------------------------------------------------------- */ function citami_setup_business_types() { return array('LocalBusiness', 'Dentist', 'MedicalClinic', 'Physician', 'LegalService', 'Attorney', 'AccountingService', 'RealEstateAgent', 'Restaurant', 'Store', 'HomeAndConstructionBusiness', 'AutoRepair', 'BeautySalon', 'HealthAndBeautyBusiness', 'SportsActivityLocation', 'LodgingBusiness', 'TravelAgency', 'ProfessionalService', 'Organization'); } /** The sheet as it stands, with WordPress and entity data filling the gaps. */ function citami_setup_prefill_sheet() { $s = citami_truth_sheet(); $e = function_exists('citami_schema_settings') ? citami_schema_settings()['entity'] : array(); $get = function ($k) use ($e) { return isset($e[$k]) && is_string($e[$k]) ? $e[$k] : ''; }; if ($s['name'] === '') $s['name'] = $get('name') !== '' ? $get('name') : (string) get_bloginfo('name'); if ($s['type'] === '') $s['type'] = $get('type') !== '' ? $get('type') : 'LocalBusiness'; if ($s['description'] === '') $s['description'] = $get('description') !== '' ? $get('description') : (string) get_bloginfo('description'); if ($s['phone'] === '') $s['phone'] = $get('telephone'); if ($s['email'] === '') $s['email'] = $get('email') !== '' ? $get('email') : (string) get_option('admin_email', ''); if ($s['website'] === '') $s['website'] = home_url('/'); foreach (array('street', 'city', 'postal', 'region', 'country') as $k) { if ($s['address'][$k] === '' && $get($k) !== '') $s['address'][$k] = $get($k); } if ($s['address']['country'] === '') $s['address']['country'] = stripos((string) get_locale(), 'it') === 0 ? 'IT' : (preg_match('/^de_(DE|AT|CH)/i', (string) get_locale(), $m) ? strtoupper($m[1]) : ''); if (empty($s['sameas']) && !empty($e['sameas']) && is_array($e['sameas'])) $s['sameas'] = array_values(array_filter($e['sameas'], 'is_string')); if (function_exists('citami_locations')) { $locs = citami_locations(); if (!empty($locs[0]) && $s['address']['city'] === '') { $l = $locs[0]; $s['address']['street'] = isset($l['street']) ? $l['street'] : ''; $s['address']['city'] = isset($l['city']) ? $l['city'] : ''; $s['address']['postal'] = isset($l['postal']) ? $l['postal'] : ''; if ($s['phone'] === '' && !empty($l['telephone'])) $s['phone'] = $l['telephone']; } } return $s; } /* ---------------------------------------------------------------- */ /* About page draft from the sheet */ /* ---------------------------------------------------------------- */ function citami_setup_about_draft_content(array $s) { $it = stripos((string) get_locale(), 'it') === 0; $L = function ($a, $b) { return citami_t($a, $b); }; $p = array(); $intro = $s['description'] !== '' ? $s['description'] : sprintf($L('%s è %s%s.', '%s is %s%s.'), $s['name'], $s['type'] !== '' ? $L('un\'attività di tipo ', 'a ') . $s['type'] : $L('un\'attività', 'a business'), $s['address']['city'] !== '' ? $L(' a ', ' in ') . $s['address']['city'] : ''); $p[] = '

' . esc_html($intro) . '

'; if ($s['founded'] !== '' || !empty($s['founders'])) { $p[] = '

' . esc_html($L('La nostra storia', 'Our story')) . '

'; $p[] = '

' . esc_html(sprintf($L('%s nasce nel %s%s.', '%s was founded in %s%s.'), $s['name'], $s['founded'] !== '' ? substr($s['founded'], 0, 4) : '____', !empty($s['founders']) ? $L(' da ', ' by ') . implode(', ', $s['founders']) : '')) . ' ' . esc_html($L('[Aggiungi due righe: perché è nata, cosa è cambiato da allora.]', '[Add two lines: why it started, what changed since.]')) . '

'; } if (!empty($s['services'])) { $p[] = '

' . esc_html($L('Cosa facciamo', 'What we do')) . '

'; } if (!empty($s['people'])) { $p[] = '

' . esc_html($L('Chi siamo', 'The team')) . '

'; } $addr = array_filter(array($s['address']['street'], trim($s['address']['postal'] . ' ' . $s['address']['city']), $s['address']['region'])); $p[] = '

' . esc_html($L('Dove siamo e come contattarci', 'Where we are and how to reach us')) . '

'; $p[] = '

' . esc_html(implode(', ', $addr)) . ($s['phone'] !== '' ? '
' . esc_html($L('Telefono: ', 'Phone: ') . $s['phone']) : '') . ($s['email'] !== '' ? '
Email: ' . esc_html($s['email']) : '') . '

'; $p[] = '

' . esc_html($L('[Bozza creata da Citami dalla scheda dei fatti. Completa le parti tra parentesi, poi pubblica: i motori AI leggono questa pagina per capire chi sei.]', '[Draft created by Citami from the fact sheet. Complete the bracketed parts, then publish: AI engines read this page to learn who you are.]')) . '

'; return implode("\n", $p); } function citami_setup_create_about_draft($improve = false) { $s = citami_truth_sheet(); $it = stripos((string) get_locale(), 'it') === 0; $id = wp_insert_post(array( // 2.56.1 — next to an existing About page the draft is a separate page to copy from. 'post_title' => $improve ? citami_t('Chi siamo (bozza dalla scheda)', 'About us (draft from the fact sheet)') : citami_t('Chi siamo', 'About us'), // 2.73 — the slug follows the site language (German: ueber-uns). 'post_name' => $improve ? ($it ? 'chi-siamo-bozza' : (citami_lang() === 'de' ? 'ueber-uns-entwurf' : 'about-draft')) : ($it ? 'chi-siamo' : (citami_lang() === 'de' ? 'ueber-uns' : 'about')), 'post_type' => 'page', 'post_status' => 'draft', 'post_content' => citami_setup_about_draft_content($s), ), true); if (is_wp_error($id)) { return 0; } if ($improve) { update_option('citami_setup_about_draft', (int) $id, false); return (int) $id; } // 2.59 — remembered so step 3 shows "open the draft" instead of creating it again. update_option('citami_setup_about_new', (int) $id, false); if (defined('CITAMI_META_SCHEMA_TYPE')) { update_post_meta((int) $id, CITAMI_META_SCHEMA_TYPE, 'AboutPage'); } delete_transient(CITAMI_DETECTED_SLUGS_TRANSIENT); delete_transient(CITAMI_TRUTH_SCAN_TRANSIENT); return (int) $id; } /* ---------------------------------------------------------------- */ /* Handler */ /* ---------------------------------------------------------------- */ function citami_setup_mark($key) { $s = citami_setup_state(); $s[$key] = time(); update_option(CITAMI_SETUP_OPT, $s, false); } function citami_setup_handle() { if (!current_user_can('manage_options')) { wp_die('Permesso negato.', '', array('response' => 403)); } $nonce = isset($_REQUEST['_citami_setup_nonce']) ? sanitize_text_field(wp_unslash($_REQUEST['_citami_setup_nonce'])) : ''; if (!wp_verify_nonce($nonce, 'citami_setup')) { wp_die('Nonce non valido.', '', array('response' => 403)); } $do = isset($_REQUEST['do']) ? sanitize_key((string) $_REQUEST['do']) : ''; $next = 1; $notice = null; switch ($do) { case 'skip': citami_setup_mark('skipped_at'); set_transient('citami_action_notice', array('type' => 'info', 'message' => citami_t('Primo avvio guidato nascosto. Lo riapri quando vuoi con "Primo avvio guidato" in alto.', 'Guided first run hidden. Reopen it any time with "Guided first run" at the top.')), 30); wp_safe_redirect(admin_url('admin.php?page=citami-connector')); exit; case 'connect': $key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash((string) $_POST['api_key'])) : ''; // A key preloaded in the package is accepted here, by the owner's own "Connect". if ($key === '') $key = citami_preloaded_api_key(); if ($key === '') { // 2.60 — an empty key never moves on silently: say what works // without it and let the owner continue on purpose. set_transient('citami_action_notice', array('type' => 'warning', 'message' => citami_t('Nessuna chiave inserita. Senza chiave il plugin funziona per la parte SEO; collegalo quando vuoi.', 'No key entered. Without a key the plugin works for the SEO part; connect it whenever you like.')), 30); wp_safe_redirect(citami_setup_url(1) . '&nokey=1'); exit; } if ($key !== '') { update_option('citami_api_key', $key); if (function_exists('citami_health_ping')) { citami_health_ping(); } $health = get_option(CITAMI_HEALTH_OPT, array()); $ok = is_array($health) && !empty($health['ok']); $notice = array('type' => $ok ? 'success' : 'warning', 'message' => $ok ? citami_t('Collegato a Citami.', 'Connected to Citami.') : citami_t('Chiave salvata, ma il collegamento non ha risposto: controlla la chiave nella dashboard Citami. Puoi continuare.', 'Key saved, but the connection did not answer: check the key in the Citami dashboard. You can continue.')); } $next = 2; break; case 'business': $in = isset($_POST['sheet']) && is_array($_POST['sheet']) ? wp_kses_post_deep(wp_unslash($_POST['sheet'])) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- array, sanitised right here with wp_kses_post_deep (recursive wp_kses_post), which the sniff does not list $current = citami_truth_sheet(); unset($current['source'], $current['received_at']); $merged = array_merge($current, $in); if (isset($in['address']) && is_array($in['address'])) { $merged['address'] = array_merge($current['address'], $in['address']); } $merged['updated_at'] = gmdate('c'); citami_truth_store($merged, 'local'); // 2.60 — the two side effects are listed next to the button, each // with a checkbox (ticked by default). Without the "opts" marker // (old form) both run, as before. $has_opts = !empty($_POST['opts']); $do_align = !$has_opts || !empty($_POST['align_entity']); // 2.62 — /ai-info is opt-in: only when ticked. $do_ai_info = !empty($_POST['ai_info_on']); $done = array(citami_t('Scheda salvata', 'Sheet saved')); if ($do_align && function_exists('citami_truth_align_entity')) { citami_truth_align_entity(); $done[] = citami_t('schema dell\'organizzazione aggiornato', 'organisation schema updated'); } if ($do_ai_info) { $ts = citami_truth_settings(); $ts['ai_info'] = 'on'; update_option(CITAMI_TRUTH_SETTINGS_OPT, $ts, false); $done[] = citami_t('/ai-info pubblicata', '/ai-info published'); } // 2.77.0 — connected: the facts reach the dashboard profile now, not at the next hourly sync. if (citami_get_api_key() !== '' && function_exists('citami_sync_pull_handler')) { $sync = citami_sync_pull_handler(); if (!empty($sync['ok'])) $done[] = citami_t('inviata anche alla dashboard', 'sent to the dashboard too'); } $notice = array('type' => 'success', 'message' => implode(', ', $done) . '.'); $next = 3; break; case 'about_create': $id = citami_setup_create_about_draft(!empty($_POST['improve'])); $notice = $id > 0 ? array('type' => 'success', 'message' => citami_t('Bozza "Chi siamo" creata: completala e pubblicala.', 'Draft "About us" created: complete and publish it.')) : array('type' => 'error', 'message' => citami_t('Non sono riuscito a creare la bozza.', 'Could not create the draft.')); $next = 3; break; case 'about_next': $next = 4; break; case 'engines': $preset = isset($_POST['preset']) ? sanitize_key((string) $_POST['preset']) : 'allow_search_block_training'; // 2.59 — "keep" leaves custom per-bot rules alone when the wizard is run again. if ($preset !== 'keep' && function_exists('citami_bots_preset') && in_array($preset, array('allow_search_block_training', 'allow_all', 'block_all'), true)) { $policy = citami_bots_policy(); $policy['rules'] = citami_bots_preset($preset); update_option(CITAMI_BOTS_POLICY_OPT, $policy, false); } if (defined('CITAMI_INDEXNOW_SETTINGS_OPT')) { $ix = get_option(CITAMI_INDEXNOW_SETTINGS_OPT, array()); $ix = is_array($ix) ? $ix : array(); $ix['enabled'] = !empty($_POST['indexnow']) ? 'on' : 'off'; update_option(CITAMI_INDEXNOW_SETTINGS_OPT, $ix, false); } $ts = citami_truth_settings(); $ts['footer_link'] = ($ts['ai_info'] === 'on' && !empty($_POST['footer_link'])) ? 'on' : 'off'; update_option(CITAMI_TRUTH_SETTINGS_OPT, $ts, false); $notice = array('type' => 'success', 'message' => citami_t('Regole per i crawler, IndexNow e link salvati.', 'Crawler rules, IndexNow and link saved.')); $next = 5; citami_setup_mark('engines_at'); citami_setup_mark('done_at'); break; default: $next = 1; } if ($notice) { set_transient('citami_action_notice', $notice, 30); } wp_safe_redirect(citami_setup_url($next)); exit; } add_action('admin_post_citami_setup_action', 'citami_setup_handle'); /* ---------------------------------------------------------------- */ /* Screens */ /* ---------------------------------------------------------------- */ function citami_setup_field($name, $value, $placeholder = '', $class = 'regular-text', $type = 'text', $id = '') { return ''; } function citami_render_setup_tab() { $step = isset($_GET['step']) ? max(1, min(CITAMI_SETUP_STEPS, (int) $_GET['step'])) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display only: which step to show $labels = array(1 => citami_t('Collega', 'Connect'), 2 => citami_t('La tua attività', 'Your business'), 3 => citami_t('Chi siamo', 'About page'), 4 => citami_t('Motori AI', 'AI engines'), 5 => citami_t('Fatto', 'Done')); ?>
    $label): ?>
  1. .

>


false, 'missing' => array('exists'), 'score' => 0, 'url' => '', 'edit' => ''); ?>

0) ? get_post($new_id) : null; ?> post_status, array('draft', 'pending', 'future'), true)): ?>

· /100 ·

0 ? get_post($draft_id) : null; ?> post_status === 'draft'): ?>

'auto'); ?>