' . seolok_brand() . '

' . esc_html($title) . '

'; } /** A panel with an icon, a title, small print and an optional "see all" link. */ function seolok_ui_panel_open($icon, $title, $lead = '', $more_url = '', $more_label = '', $badge = 'info', $id = '') { $o = '
' . seolok_ui_icon($icon) . '

' . esc_html($title) . '

' . ($lead !== '' ? '

' . esc_html($lead) . '

' : '') . '
'; if ($more_url !== '') { $o .= '' . esc_html($more_label !== '' ? $more_label : seolok_s('ov_all')) . ' →'; } return $o . '
'; } /** One small number tile (label, value, line under it). */ function seolok_ui_stat($icon, $tone, $label, $value, $sub = '') { return '
' . seolok_ui_icon($icon) . '' . esc_html($label) . '' . esc_html($value) . '' . esc_html($sub) . '
'; } /** A number SEOLOK may not have: "—" for null. */ function seolok_maybe_num($v, $decimals = 0) { if (!is_numeric($v)) { return '—'; } return $decimals > 0 ? number_format((float) $v, $decimals, seolok_is_tr() ? ',' : '.', seolok_is_tr() ? '.' : ',') : seolok_num($v); } /** Draws one insight screen: top bar, SEOLOK's answer (or why there is none), the site note. */ function seolok_insight_page($name) { if (!current_user_can('manage_options') || !in_array($name, SEOLOK_INSIGHT_SCREENS, true)) { return; } $force = isset($_GET['seolok_refresh']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- a read-only "fetch again" flag $data = seolok_is_configured() ? seolok_insight_data($name, $force) : new WP_Error('seolok_not_configured', 'Not configured'); $panel = !is_wp_error($data) ? seolok_panel_url(isset($data['panel']) ? $data['panel'] : '') : ''; $o = seolok_screen_open(); $o .= seolok_ui_topbar(seolok_s('menu_' . $name), add_query_arg(array('page' => seolok_insight_slug($name), 'seolok_refresh' => '1'), admin_url('admin.php')), $panel); $o .= '

' . esc_html(seolok_s('in_lead_' . $name)) . '

'; if (is_wp_error($data)) { $o .= seolok_render_problem($data); } else { $render = 'seolok_insight_' . $name; $o .= $render(seolok_arr(isset($data['data']) ? $data['data'] : null)); } $o .= seolok_site_note() . ''; echo wp_kses($o, seolok_allowed_html()); } /** A pill for a rank change: "▲ 3" better, "▼ 2" worse, "—" none. */ function seolok_rank_change($change) { if (!is_numeric($change) || (int) $change === 0) { return '—'; } return seolok_delta((string) abs((int) $change), (int) $change > 0); } /** An empty state: an icon, one sentence, and what to do (optional link to SEOLOK). */ function seolok_ui_empty($text, $url = '', $label = '') { return '
' . seolok_ui_icon('search') . '' . esc_html($text) . '' . ($url !== '' ? '' . esc_html($label) . '' : '') . '
'; } /* ------------------------------------------------------------- Site analysis */ function seolok_insight_audit($d) { if (empty($d['scanned'])) { return '
' . seolok_ui_empty(seolok_s('in_audit_never')) . '
'; } $counts = seolok_arr(isset($d['counts']) ? $d['counts'] : null); $score = isset($d['score']) && is_numeric($d['score']) ? (int) $d['score'] : null; $crit = isset($counts['critical']) ? (int) $counts['critical'] : 0; $warn = isset($counts['warning']) ? (int) $counts['warning'] : 0; $info = isset($counts['info']) ? (int) $counts['info'] : 0; $o = '
'; $o .= seolok_ui_stat('chart', $score === null ? 'muted' : ($score >= 80 ? 'ok' : ($score >= 60 ? 'warn' : 'bad')), seolok_s('ov_score'), $score === null ? '—' : $score . ' / 100', sprintf(seolok_s('ov_score_sub'), seolok_str(isset($d['crawledAt']) ? $d['crawledAt'] : ''))); $o .= seolok_ui_stat('file', 'info', seolok_s('ov_pages'), seolok_maybe_num(isset($d['pages']) ? $d['pages'] : null), sprintf(seolok_s('in_healthy'), seolok_maybe_num(isset($d['healthy']) ? $d['healthy'] : null))); $o .= seolok_ui_stat('warn', $crit > 0 ? 'bad' : 'ok', seolok_s('in_critical'), seolok_num($crit), seolok_s('in_critical_sub')); $o .= seolok_ui_stat('bell', $warn > 0 ? 'warn' : 'ok', seolok_s('in_warnings'), seolok_num($warn), sprintf(seolok_s('in_info'), seolok_num($info))); $o .= '
'; $issues = seolok_arr(isset($d['issues']) ? $d['issues'] : null); $o .= seolok_ui_panel_open('list', seolok_s('in_issues'), seolok_s('in_issues_lead')); if (!$issues) { $o .= seolok_ui_note('ok', seolok_s('in_no_issues')); } else { $o .= ''; } return $o . ''; } /* ------------------------------------------------------------- Content opportunities */ function seolok_insight_opportunities($d) { $items = seolok_arr(isset($d['items']) ? $d['items'] : null); $o = '
'; foreach (seolok_arr(isset($d['byType']) ? $d['byType'] : null) as $type => $t) { $t = seolok_arr($t); $o .= seolok_ui_stat($type === 'content_gap' ? 'file' : ($type === 'ctr_gap' ? 'eye' : ($type === 'cannibalization' ? 'chain' : 'chart')), 'info', seolok_str(isset($t['label']) ? $t['label'] : ''), seolok_maybe_num(isset($t['count']) ? $t['count'] : 0), ''); } $o .= '
' . seolok_ui_panel_open('star', seolok_s('ov_opps'), seolok_str(isset($d['lastScanAt']) ? sprintf(seolok_s('in_scanned'), $d['lastScanAt']) : ''), '', '', 'warn'); if (!$items) { return $o . seolok_ui_empty(seolok_s('ov_opps_none')) . ''; } $o .= '
'; foreach ($items as $i) { $i = seolok_arr($i); $o .= ''; } return $o . '
' . esc_html(seolok_s('in_col_search')) . '' . esc_html(seolok_s('in_col_kind')) . '' . esc_html(seolok_s('al_col_page')) . '' . esc_html(seolok_s('ov_impressions')) . '' . esc_html(seolok_s('ov_position')) . '
' . esc_html(seolok_str(isset($i['query']) ? $i['query'] : '')) . '' . (!empty($i['inProgress']) ? ' ' . seolok_pill('info', seolok_s('in_in_progress')) : '') . '' . seolok_pill('muted', seolok_str(isset($i['typeLabel']) ? $i['typeLabel'] : '')) . '' . (!empty($i['page']) ? '' . esc_html(seolok_str($i['page'])) . '' : '—') . '' . esc_html(seolok_maybe_num(isset($i['impressions']) ? $i['impressions'] : null)) . '' . esc_html(seolok_maybe_num(isset($i['position']) ? $i['position'] : null, 1)) . '
'; } /* ------------------------------------------------------------- Keywords */ function seolok_insight_keywords($d) { $items = seolok_arr(isset($d['items']) ? $d['items'] : null); $top3 = 0; $top10 = 0; $up = 0; $down = 0; foreach ($items as $k) { $r = isset($k['rank']) && is_numeric($k['rank']) ? (int) $k['rank'] : null; $top3 += $r !== null && $r <= 3 ? 1 : 0; $top10 += $r !== null && $r <= 10 ? 1 : 0; $c = isset($k['change']) && is_numeric($k['change']) ? (int) $k['change'] : 0; $up += $c > 0 ? 1 : 0; $down += $c < 0 ? 1 : 0; } $o = '
'; $o .= seolok_ui_stat('search', 'info', seolok_s('in_tracked'), seolok_maybe_num(isset($d['tracked']) ? $d['tracked'] : count($items)), sprintf(seolok_s('in_cap'), seolok_maybe_num(isset($d['cap']) ? $d['cap'] : null))); $o .= seolok_ui_stat('star', 'ok', seolok_s('in_top3'), seolok_num($top3), ''); $o .= seolok_ui_stat('chart', 'ok', seolok_s('in_top10'), seolok_num($top10), ''); $o .= seolok_ui_stat('refresh', $down > $up ? 'warn' : 'ok', seolok_s('in_moves'), '▲ ' . $up . ' ▼ ' . $down, seolok_s('in_moves_sub')); $o .= '
' . seolok_ui_panel_open('search', seolok_s('menu_keywords'), seolok_s('in_kw_lead')); if (!$items) { return $o . seolok_ui_empty(seolok_s('in_kw_none')) . ''; } $o .= '
'; foreach ($items as $k) { $k = seolok_arr($k); $rank = isset($k['rank']) && is_numeric($k['rank']) ? (int) $k['rank'] : null; $o .= ''; } return $o . '
' . esc_html(seolok_s('in_col_keyword')) . '' . esc_html(seolok_s('in_col_rank')) . '' . esc_html(seolok_s('in_col_change')) . '' . esc_html(seolok_s('in_col_volume')) . '' . esc_html(seolok_s('in_col_gsc')) . '' . esc_html(seolok_s('al_col_page')) . '
' . esc_html(seolok_str(isset($k['keyword']) ? $k['keyword'] : '')) . ' ' . esc_html(seolok_s(isset($k['device']) && $k['device'] === 'desktop' ? 'in_desktop' : 'in_mobile')) . '' . (!empty($k['unverified']) ? ' ' . seolok_pill('warn', seolok_s('in_unverified')) : '') . '' . esc_html($rank === null ? seolok_s('in_not_found') : (string) $rank) . '' . seolok_rank_change(isset($k['change']) ? $k['change'] : null) . '' . esc_html(seolok_maybe_num(isset($k['volume']) ? $k['volume'] : null)) . '' . esc_html(seolok_maybe_num(isset($k['gsc']) ? $k['gsc'] : null, 1)) . '' . (!empty($k['url']) ? '' . esc_html(seolok_str($k['url'])) . '' : '—') . '
'; } /* ------------------------------------------------------------- Competitors */ function seolok_insight_competitors($d) { $items = seolok_arr(isset($d['items']) ? $d['items'] : null); $o = seolok_ui_panel_open('chart', seolok_s('menu_competitors'), seolok_s('in_comp_lead')); if (!$items) { return $o . seolok_ui_empty(seolok_s('in_comp_none')) . ''; } $o .= '
'; foreach ($items as $c) { $c = seolok_arr($c); $wins = isset($c['wins']) ? (int) $c['wins'] : 0; $losses = isset($c['losses']) ? (int) $c['losses'] : 0; $o .= ''; } return $o . '
' . esc_html(seolok_s('in_col_site')) . '' . esc_html(seolok_s('in_col_shared')) . '' . esc_html(seolok_s('in_col_top10')) . '' . esc_html(seolok_s('in_col_avg')) . '' . esc_html(seolok_s('in_col_wins')) . '
' . esc_html(seolok_str(isset($c['domain']) ? $c['domain'] : '')) . '' . (!empty($c['added']) ? ' ' . seolok_pill('info', seolok_s('in_added')) : '') . '' . esc_html(seolok_maybe_num(isset($c['shared']) ? $c['shared'] : null)) . '' . esc_html(seolok_maybe_num(isset($c['top10']) ? $c['top10'] : null)) . '' . esc_html(seolok_maybe_num(isset($c['avgPosition']) ? $c['avgPosition'] : null, 1)) . '' . esc_html(sprintf(seolok_s('in_you_ahead'), $wins)) . ' · ' . esc_html(sprintf(seolok_s('in_they_ahead'), $losses)) . '
'; } /* ------------------------------------------------------------- Backlinks */ function seolok_insight_backlinks($d) { // incoming links are measured for the Agency and Agency Pro plans only: SEOLOK sends no data for the others if (!empty($d['locked'])) { return seolok_ui_panel_open('chain', seolok_s('in_bl_list'), seolok_s('in_bl_lead')) . seolok_ui_empty(seolok_s('in_bl_locked')) . ''; } $pct = function ($now, $prev) { return is_numeric($now) && is_numeric($prev) && (int) $prev > 0 && (int) $now !== (int) $prev ? sprintf(seolok_s('in_since_last'), ((int) $now > (int) $prev ? '+' : '') . seolok_num((int) $now - (int) $prev)) : ''; }; $o = '
'; $o .= seolok_ui_stat('shield', 'info', seolok_s('in_domain_score'), isset($d['score']) && is_numeric($d['score']) ? (int) $d['score'] . ' / 100' : '—', seolok_str(isset($d['checkedAt']) ? sprintf(seolok_s('in_checked'), $d['checkedAt']) : seolok_s('in_bl_never'))); $o .= seolok_ui_stat('chain', 'ok', seolok_s('in_ref_domains'), seolok_maybe_num(isset($d['referringDomains']) ? $d['referringDomains'] : null), $pct(isset($d['referringDomains']) ? $d['referringDomains'] : null, isset($d['referringPrev']) ? $d['referringPrev'] : null)); $o .= seolok_ui_stat('link', 'ok', seolok_s('in_backlinks'), seolok_maybe_num(isset($d['backlinks']) ? $d['backlinks'] : null), $pct(isset($d['backlinks']) ? $d['backlinks'] : null, isset($d['backlinksPrev']) ? $d['backlinksPrev'] : null)); $o .= seolok_ui_stat('warn', isset($d['lost30d']) && (int) $d['lost30d'] > 0 ? 'warn' : 'ok', seolok_s('in_lost'), seolok_maybe_num(isset($d['lost30d']) ? $d['lost30d'] : null), seolok_s('in_lost_sub')); $o .= '
'; $items = seolok_arr(isset($d['items']) ? $d['items'] : null); $o .= seolok_ui_panel_open('chain', seolok_s('in_bl_list'), seolok_s('in_bl_lead')) . seolok_sparkline(isset($d['trend']) ? $d['trend'] : array(), 'info'); if (!$items) { return $o . seolok_ui_empty(seolok_s('in_bl_none')) . ''; } $o .= '
'; foreach ($items as $b) { $b = seolok_arr($b); $source = seolok_str(isset($b['source']) ? $b['source'] : ''); $host = wp_parse_url($source, PHP_URL_HOST); $o .= ''; } return $o . '
' . esc_html(seolok_s('in_col_from')) . '' . esc_html(seolok_s('in_col_anchor')) . '' . esc_html(seolok_s('al_col_page')) . '' . esc_html(seolok_s('in_col_strength')) . '' . esc_html(seolok_s('in_col_first')) . '
' . esc_html($host ? $host : $source) . '' . (isset($b['dofollow']) && $b['dofollow'] === false ? ' ' . seolok_pill('muted', 'nofollow') : '') . '' . esc_html(seolok_str(isset($b['anchor']) ? $b['anchor'] : '')) . '' . esc_html(seolok_str(isset($b['target']) ? $b['target'] : '')) . '' . esc_html(seolok_maybe_num(isset($b['strength']) ? $b['strength'] : null)) . '' . esc_html(seolok_str(isset($b['firstSeen']) ? $b['firstSeen'] : '')) . '
'; } /* ------------------------------------------------------------- Reports */ function seolok_insight_reports($d) { $items = seolok_arr(isset($d['items']) ? $d['items'] : null); $o = seolok_ui_panel_open('file', seolok_s('menu_reports'), seolok_s('in_rep_lead')); if (!$items) { return $o . seolok_ui_empty(seolok_s('in_rep_none')) . ''; } $o .= '

' . esc_html(seolok_s('in_rep_open')) . '

'; }