'aije-lite', 'tab' => 'aivisits' ), admin_url( 'tools.php' ) ); // ── Hinweise nach Aktion ───────────────────────────────────────────────── $msg = isset( $_GET['aije_msg'] ) ? sanitize_key( $_GET['aije_msg'] ) : ''; if ( 'saved' === $msg ) { echo '

✓ ' . esc_html__( 'Einstellungen gespeichert.', 'ai-json-extractor-auto-embed-lite' ) . '

'; } elseif ( 'cleared' === $msg ) { echo '

✓ ' . esc_html__( 'Protokoll geleert.', 'ai-json-extractor-auto-embed-lite' ) . '

'; } elseif ( 'debug_on' === $msg ) { echo '

' . esc_html__( 'Debug-Modus läuft 15 Minuten. Schicke jetzt die KI auf deine Seite und lade diesen Tab danach neu.', 'ai-json-extractor-auto-embed-lite' ) . '

'; } elseif ( 'debug_off' === $msg || 'debug_cleared' === $msg ) { echo '

✓ ' . esc_html__( 'Debug-Modus beendet.', 'ai-json-extractor-auto-embed-lite' ) . '

'; } // ── Tabelle vorhanden? ─────────────────────────────────────────────────── if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) !== $table ) { echo '

' . esc_html__( 'Die Protokoll-Tabelle wird gerade angelegt. Bitte Seite neu laden.', 'ai-json-extractor-auto-embed-lite' ) . '

'; return; } // ── Filter ─────────────────────────────────────────────────────────────── $days = isset( $_GET['days'] ) ? (int) $_GET['days'] : 30; $days = in_array( $days, array( 1, 7, 30, 90, 365 ), true ) ? $days : 30; $f_bot = isset( $_GET['bot'] ) ? sanitize_text_field( wp_unslash( $_GET['bot'] ) ) : ''; $f_purp = isset( $_GET['purpose'] ) ? sanitize_key( $_GET['purpose'] ) : ''; $f_purp = isset( $labels[ $f_purp ] ) ? $f_purp : ''; $since = gmdate( 'Y-m-d H:i:s', current_time( 'timestamp' ) - $days * DAY_IN_SECONDS ); $where = "visited_at >= %s AND purpose <> 'referral'"; $params = array( $since ); if ( '' !== $f_bot ) { $where .= ' AND bot = %s'; $params[] = $f_bot; } if ( '' !== $f_purp ) { $where .= ' AND purpose = %s'; $params[] = $f_purp; } // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table/$where sind intern gebaut, Werte laufen über prepare(). $kpi = $wpdb->get_row( $wpdb->prepare( "SELECT COUNT(*) AS total, COUNT(DISTINCT bot) AS bots, COUNT(DISTINCT url) AS pages, MAX(visited_at) AS last_visit FROM {$table} WHERE {$where}", $params ) ); $by_bot = $wpdb->get_results( $wpdb->prepare( "SELECT bot, vendor, purpose, COUNT(*) AS hits, COUNT(DISTINCT url) AS pages, MAX(visited_at) AS last_visit FROM {$table} WHERE {$where} GROUP BY bot, vendor, purpose ORDER BY hits DESC", $params ) ); $top_pages = $wpdb->get_results( $wpdb->prepare( "SELECT url, MAX(post_id) AS post_id, COUNT(*) AS hits, MAX(visited_at) AS last_visit FROM {$table} WHERE {$where} GROUP BY url ORDER BY hits DESC LIMIT 25", $params ) ); $matrix = array(); if ( $top_pages ) { $urls = wp_list_pluck( $top_pages, 'url' ); $ph = implode( ',', array_fill( 0, count( $urls ), '%s' ) ); $rows = $wpdb->get_results( $wpdb->prepare( "SELECT url, bot, COUNT(*) AS hits FROM {$table} WHERE {$where} AND url IN ({$ph}) GROUP BY url, bot", array_merge( $params, $urls ) ) ); foreach ( $rows as $r ) { $matrix[ $r->url ][ $r->bot ] = (int) $r->hits; } } $daily = $wpdb->get_results( $wpdb->prepare( "SELECT DATE(visited_at) AS d, COUNT(*) AS hits FROM {$table} WHERE {$where} GROUP BY DATE(visited_at) ORDER BY d ASC", $params ), OBJECT_K ); $recent = $wpdb->get_results( $wpdb->prepare( "SELECT visited_at, bot, vendor, purpose, post_id, url, status FROM {$table} WHERE {$where} ORDER BY id DESC LIMIT 50", $params ) ); $all_bots = $wpdb->get_col( "SELECT DISTINCT bot FROM {$table} WHERE purpose <> 'referral' ORDER BY bot ASC" ); // ── Besucher aus KI-Chats (nur Zeitraum-Filter) ────────────────────────── $ref_where = "visited_at >= %s AND purpose = 'referral'"; $ref_kpi = $wpdb->get_row( $wpdb->prepare( "SELECT COUNT(*) AS total, COUNT(DISTINCT bot) AS sources, COUNT(DISTINCT url) AS pages FROM {$table} WHERE {$ref_where}", $since ) ); $ref_by_src = $wpdb->get_results( $wpdb->prepare( "SELECT bot, vendor, COUNT(*) AS hits, COUNT(DISTINCT url) AS pages, MAX(visited_at) AS last_visit FROM {$table} WHERE {$ref_where} GROUP BY bot, vendor ORDER BY hits DESC", $since ) ); $ref_pages = $wpdb->get_results( $wpdb->prepare( "SELECT url, MAX(post_id) AS post_id, COUNT(*) AS hits, GROUP_CONCAT(DISTINCT bot ORDER BY bot SEPARATOR ', ') AS sources FROM {$table} WHERE {$ref_where} GROUP BY url ORDER BY hits DESC LIMIT 25", $since ) ); // phpcs:enable $matrix_bots = wp_list_pluck( $by_bot, 'bot' ); $matrix_bots = array_values( array_unique( $matrix_bots ) ); // ── Helfer ─────────────────────────────────────────────────────────────── $purpose_badge = function ( $p ) use ( $labels ) { $c = array( 'training' => 'background:#f3f4f6;color:#374151;border-color:#e5e7eb;', 'search' => 'background:#eff6ff;color:#1d4ed8;border-color:#bfdbfe;', 'user' => 'background:#fff7ed;color:#c2410c;border-color:#fed7aa;', ); $style = isset( $c[ $p ] ) ? $c[ $p ] : $c['training']; $label = isset( $labels[ $p ] ) ? $labels[ $p ] : $p; return '' . esc_html( $label ) . ''; }; $page_label = function ( $url, $post_id ) { $title = $post_id ? get_the_title( (int) $post_id ) : ''; $out = ''; if ( $title ) { $edit = get_edit_post_link( (int) $post_id ); $out .= $edit ? '' . esc_html( $title ) . '
' : '' . esc_html( $title ) . '
'; } $out .= '' . esc_html( $url ) . ' ↗'; return $out; }; $fmt_date = function ( $mysql ) { return $mysql ? esc_html( mysql2date( get_option( 'date_format' ) . ' H:i', $mysql ) ) : '–'; }; $card = 'background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:20px 22px;margin-bottom:20px;'; $th = 'text-align:left;padding:8px 10px;font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:#6b7280;border-bottom:1px solid #e5e7eb;'; $td = 'padding:8px 10px;font-size:13px;border-bottom:1px solid #f3f4f6;vertical-align:top;'; ?>

🤖

total ) ), array( __( 'Verschiedene KI-Bots', 'ai-json-extractor-auto-embed-lite' ), number_format_i18n( (int) $kpi->bots ) ), array( __( 'Besuchte Seiten', 'ai-json-extractor-auto-embed-lite' ), number_format_i18n( (int) $kpi->pages ) ), array( __( 'Letzter Besuch', 'ai-json-extractor-auto-embed-lite' ), $kpi->last_visit ? mysql2date( get_option( 'date_format' ) . ' H:i', $kpi->last_visit ) : '–' ), ); foreach ( $kpis as $k ) { echo '
' . esc_html( $k[0] ) . '
' . esc_html( $k[1] ) . '
'; } ?>
total ) : ?>

hits ); } $span = min( $days, 90 ); ?>

= 0; $i-- ) { $day = gmdate( 'Y-m-d', current_time( 'timestamp' ) - $i * DAY_IN_SECONDS ); $hits = isset( $daily[ $day ] ) ? (int) $daily[ $day ]->hits : 0; $h = $hits ? max( 3, round( $hits / $max * 90 ) ) : 1; $tip = mysql2date( get_option( 'date_format' ), $day ) . ': ' . $hits; echo '
'; } ?>

bot ); ?> vendor ); ?> purpose ); // phpcs:ignore WordPress.Security.EscapeOutput -- intern escaped ?> hits ) ); ?> pages ) ); ?> last_visit ); // phpcs:ignore WordPress.Security.EscapeOutput ?>

url ][ $mb ] ) ? $matrix[ $p->url ][ $mb ] : 0; ?>
url, $p->post_id ); // phpcs:ignore WordPress.Security.EscapeOutput ?> hits ) ); ?>

visited_at ); // phpcs:ignore WordPress.Security.EscapeOutput ?> bot ); ?> vendor ); ?> purpose ); // phpcs:ignore WordPress.Security.EscapeOutput ?> url, $r->post_id ); // phpcs:ignore WordPress.Security.EscapeOutput ?> status ? '404' : '200'; ?>

👤

total ) ), array( __( 'KI-Quellen', 'ai-json-extractor-auto-embed-lite' ), number_format_i18n( (int) $ref_kpi->sources ) ), array( __( 'Einstiegsseiten', 'ai-json-extractor-auto-embed-lite' ), number_format_i18n( (int) $ref_kpi->pages ) ), ); foreach ( $rkpis as $k ) { echo '
' . esc_html( $k[0] ) . '
' . esc_html( $k[1] ) . '
'; } ?>
total ) : ?>

bot ); ?> vendor ); ?> hits ) ); ?> pages ) ); ?> last_visit ); // phpcs:ignore ?>

url, $p->post_id ); // phpcs:ignore ?> sources ); ?> hits ) ); ?>
time(); $dbg_log = get_option( 'aije_ai_debug_log', array() ); $dbg_log = is_array( $dbg_log ) ? $dbg_log : array(); $dbg_groups = array(); foreach ( $dbg_log as $e ) { $key = $e['ua']; if ( ! isset( $dbg_groups[ $key ] ) ) { $dbg_groups[ $key ] = array( 'ua' => $e['ua'], 'bot' => $e['bot'], 'n' => 0, 'last' => '', 'path' => '' ); } $dbg_groups[ $key ]['n']++; $dbg_groups[ $key ]['last'] = $e['t']; $dbg_groups[ $key ]['path'] = $e['path']; } uasort( $dbg_groups, function ( $a, $b ) { return strcmp( $b['last'], $a['last'] ); } ); ?>

🔍

●


✓