';
+
+ foreach ( $tabs as $tab ) {
+ $tab_title = $tab['title'] ?? 'Allgemein';
+ $rule_count = ! empty( $tab['rules'] ) ? count( $tab['rules'] ) : 0;
+ // Trigger: "regeln:Minecraft"
+ $query = 'regeln:' . $tab_title;
+ $html .= ''
+ . '📂 ' . esc_html( $tab_title )
+ . ' (' . $rule_count . ') '
+ . ' ';
+ }
+
+ $html .= '
';
+ $html .= ''
+ . esc_html( mb_substr( $content_plain, 0, 300 ) ) . '…
';
+ } else {
+ $rendered = ''
+ . wp_kses_post( $content )
+ . '
';
+ }
+
+ $html .= '';
+ foreach ( $tabs as $tab ) {
+ $tab_title = $tab['title'] ?? 'Allgemein';
+ $html .= ''
+ . '📂 ' . esc_html( $tab_title ) . ' ';
+ }
+ $html .= '
';
+
+ return array(
+ 'source' => 'rules',
+ 'title' => '📜 Regelwerk',
+ 'content' => $html,
+ );
+ }
+
+ usort( $matches, function( $a, $b ) { return $b['score'] - $a['score']; } );
+ $top = array_slice( $matches, 0, 3 );
+ $html = '';
+
+ foreach ( $top as $r ) {
+ $content_plain = wp_strip_all_tags( $r['content'] );
+ if ( mb_strlen( $content_plain ) > 300 ) {
+ $rendered = ''
+ . esc_html( mb_substr( $content_plain, 0, 300 ) ) . '…
';
+ } else {
+ $rendered = ''
+ . wp_kses_post( $r['content'] )
+ . '
';
+ }
+
+ $html .= '';
+
+ // ── Tagesaktion nur anzeigen, wenn KEINE Preisabfrage ─────────────────
+ $is_price_query = false;
+ $search = $q_lc;
+ if (preg_match('/\b(was kostet|preis von|wie teuer|wie viel kostet|kosten von|preis für|preis)\b/i', $search)) {
+ $is_price_query = true;
+ }
+ if (!$is_price_query) {
+ $deal = $wpdb->get_row( "SELECT * FROM $t_items WHERE is_daily_deal = 1 AND status = 'publish' LIMIT 1" );
+ if ( $deal ) {
+ $offer = isset( $deal->offer_price ) && $deal->offer_price > 0 ? $deal->offer_price : $deal->price;
+ $img = $img_base . str_replace(':', '_', $deal->item_id) . '.png';
+ $item_link = $shop_url ? esc_url($shop_url) . '#item-' . urlencode($deal->item_id) : '';
+ $lines[] = '
'
+ . '🔥
Tagesaktion: '
+ . '
'
+ . '
' . esc_html( $deal->name ) . '
'
+ . '
'
+ . '' . esc_html( (string) $offer ) . ' ' . esc_html( $currency ) . ' '
+ . ( $deal->price != $offer ? ' ' . esc_html( (string) $deal->price ) . ' ' : '' )
+ . ' '
+ . ( $item_link ? '
→
Zum Item im Shop ' : '' )
+ . '
';
+ }
+ }
+
+ // ── Suchbegriff extrahieren (auch für Preisabfragen) ────────────────
+ // (is_price_query wurde oben schon gesetzt)
+ $search = $q_lc;
+ if ($is_price_query) {
+ // Nur das Item extrahieren
+ $search = preg_replace('/\b(shop|kaufen|kosten|preis|items?|angebot|tagesaktion|daily deal|kategorie|rang|was gibt|zeig|liste|was kostet|preis von|wie teuer|wie viel kostet|kosten von|preis für)\b/i', '', $search);
+ } else {
+ $search = preg_replace('/\b(shop|kaufen|kosten|preis|items?|angebot|tagesaktion|daily deal|kategorie|rang|was gibt|zeig|liste)\b/i', '', $search);
+ }
+ $search = trim(preg_replace('/\s+/', ' ', $search));
+ // Satzzeichen am Anfang/Ende entfernen
+ $search = preg_replace('/^[^\p{L}\p{N}]+|[^\p{L}\p{N}]+$/u', '', $search);
+
+ if (strlen($search) >= 3) {
+ mm_debug_log('Suchbegriff nach Extraktion: ' . $search);
+ // Spezifische Suche (auch für Preisabfragen)
+ $items = $wpdb->get_results($wpdb->prepare(
+ "SELECT * FROM $t_items
+ WHERE status = 'publish' AND (item_title LIKE %s OR name LIKE %s OR item_id LIKE %s)
+ ORDER BY price ASC LIMIT 8",
+ '%' . $wpdb->esc_like($search) . '%',
+ '%' . $wpdb->esc_like($search) . '%',
+ '%' . $wpdb->esc_like($search) . '%'
+ ));
+ mm_debug_log('LIKE-Query: ' . $search . ' | Treffer: ' . count($items));
+
+ if (!empty($items)) {
+ mm_debug_log('LIKE-Query erstes Item: ' . (isset($items[0]) ? json_encode($items[0]) : 'n/a'));
+ // Preisabfrage: Nur das erste Item als Preisantwort
+ if ($is_price_query) {
+ $item = $items[0];
+ $img = $img_base . str_replace(':', '_', $item->item_id) . '.png';
+ $item_link = $shop_url ? esc_url($shop_url) . '#item-' . urlencode($item->item_id) : '';
+ $item_display_name = $item->name ?: ($item->item_title ?: $item->item_id);
+ // Serverliste aufbereiten
+ $server_list = '';
+ if (!empty($item->servers)) {
+ $servers = json_decode($item->servers, true);
+ if (is_array($servers) && count($servers) > 0) {
+ $server_list = '
Verfügbar auf: ' . esc_html(implode(', ', $servers)) . '
';
+ }
+ }
+ $lines[] = '
'
+ . '
🛒 Shop-Item:
'
+ . '
'
+ . '
' . esc_html($item_display_name) . '
'
+ . '
' . esc_html((string)$item->price) . ' ' . esc_html($currency) . '
'
+ . $server_list
+ . '
';
+ } else {
+ $lines[] = '🛒
Gefundene Items: ';
+ foreach ($items as $item) {
+ $img = $img_base . str_replace(':', '_', $item->item_id) . '.png';
+ $item_link = $shop_url ? esc_url($shop_url) . '#item-' . urlencode($item->item_id) : '';
+ $lines[] = '
'
+ . '
' . esc_html($item->item_title) . ' '
+ . ' – ' . esc_html((string)$item->price) . ' ' . esc_html($currency)
+ . ($item_link ? '
[Shop] ' : '');
+ }
+ }
+ } else {
+ // Exakte Suche, falls LIKE nichts findet
+ $item = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM $t_items WHERE status = 'publish' AND (name = %s OR item_id = %s OR item_title = %s) LIMIT 1",
+ $search, $search, $search
+ ));
+ mm_debug_log('Exakte Suche: ' . ($item ? json_encode($item) : 'kein Treffer'));
+ // Case-insensitive Fallback, falls nötig
+ if (!$item && !empty($search)) {
+ $item = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM $t_items WHERE status = 'publish' AND (name COLLATE utf8_general_ci = %s COLLATE utf8_general_ci OR item_id COLLATE utf8_general_ci = %s COLLATE utf8_general_ci OR item_title COLLATE utf8_general_ci = %s COLLATE utf8_general_ci) LIMIT 1",
+ $search, $search, $search
+ ));
+ mm_debug_log('Case-insensitive Suche: ' . ($item ? json_encode($item) : 'kein Treffer'));
+ }
+ // Fallback: Suchbegriff als Minecraft-ID mit Prefix testen
+ if (!$item && !empty($search) && strpos($search, 'minecraft:') === false) {
+ $mc_id = 'minecraft:' . strtolower(str_replace([' ', '_'], ['_', '_'], $search));
+ $item = $wpdb->get_row($wpdb->prepare(
+ "SELECT * FROM $t_items WHERE status = 'publish' AND (item_id = %s OR item_id COLLATE utf8_general_ci = %s COLLATE utf8_general_ci) LIMIT 1",
+ $mc_id, $mc_id
+ ));
+ mm_debug_log('MC-ID Fallback: ' . $mc_id . ' | ' . ($item ? json_encode($item) : 'kein Treffer'));
+ }
+ if ($item) {
+ mm_debug_log('Gefundenes Item (exakt/fallback): ' . json_encode($item));
+ $img = $img_base . str_replace(':', '_', $item->item_id) . '.png';
+ $item_link = $shop_url ? esc_url($shop_url) . '#item-' . urlencode($item->item_id) : '';
+ $lines[] = '
'
+ . '
'
+ . '
' . esc_html($item->name) . ' '
+ . 'Preis:
' . esc_html((string)$item->price) . ' ' . esc_html($currency) . ' '
+ . ($item_link ? '
[Shop] ' : '')
+ . '
';
+ } else {
+ // Aggressive Fuzzy-Suche als letzter Versuch
+ $all_items = $wpdb->get_results("SELECT * FROM $t_items WHERE status = 'publish'");
+ mm_debug_log('Fuzzy-Suche über alle Items (' . count($all_items) . '): ' . $search);
+ $search_lc = mb_strtolower($search);
+ $fuzzy = null;
+ foreach ($all_items as $it) {
+ if (strpos(mb_strtolower($it->name), $search_lc) !== false
+ || strpos(mb_strtolower($it->item_title), $search_lc) !== false
+ || strpos(mb_strtolower($it->item_id), $search_lc) !== false) {
+ $fuzzy = $it;
+ break;
+ }
+ }
+ mm_debug_log('Fuzzy-Suche Treffer: ' . ($fuzzy ? json_encode($fuzzy) : 'kein Treffer'));
+ if ($fuzzy) {
+ $img = $img_base . str_replace(':', '_', $fuzzy->item_id) . '.png';
+ $item_link = $shop_url ? esc_url($shop_url) . '#item-' . urlencode($fuzzy->item_id) : '';
+ $item_display_name = $fuzzy->name ?: ($fuzzy->item_title ?: $fuzzy->item_id);
+ // Serverliste aufbereiten
+ $server_list = '';
+ if (!empty($fuzzy->servers)) {
+ $servers = json_decode($fuzzy->servers, true);
+ if (is_array($servers) && count($servers) > 0) {
+ $server_list = '
Verfügbar auf: ' . esc_html(implode(', ', $servers)) . '
';
+ }
+ }
+ $lines[] = '
'
+ . '
🛒 Shop-Item:
'
+ . '
'
+ . '
' . esc_html($item_display_name) . '
'
+ . '
' . esc_html((string)$fuzzy->price) . ' ' . esc_html($currency) . '
'
+ . $server_list
+ . '
';
+ } else {
+ $lines[] = 'Kein Item mit „' . esc_html($search) . '“ gefunden.';
+ }
+ }
+ }
+ } else {
+ // Übersicht: Kategorien + Item-Anzahl
+ $total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $t_items WHERE status = 'publish'" );
+ $lines[] = '🛒
Shop-Übersicht: ' . $total . ' Items verfügbar.';
+
+ $cats = $wpdb->get_results(
+ "SELECT c.name, COUNT(i.id) as cnt
+ FROM $t_cats c
+ LEFT JOIN $t_items i ON i.category_id = c.id AND i.status = 'publish'
+ GROUP BY c.id ORDER BY cnt DESC LIMIT 8"
+ );
+ if ( ! empty( $cats ) ) {
+ $lines[] = '📂
Kategorien: ';
+ foreach ( $cats as $cat ) {
+ $lines[] = ' • ' . esc_html( $cat->name ) . ' (' . intval( $cat->cnt ) . ' Items)';
+ }
+ }
+
+ // Günstigste & teuerste Items
+ $cheapest = $wpdb->get_row( "SELECT item_title, price FROM $t_items WHERE status = 'publish' AND price > 0 ORDER BY price ASC LIMIT 1" );
+ $priciest = $wpdb->get_row( "SELECT item_title, price FROM $t_items WHERE status = 'publish' ORDER BY price DESC LIMIT 1" );
+ if ( $cheapest ) $lines[] = '💚 Günstigstes:
' . esc_html( $cheapest->item_title ) . ' – ' . esc_html( (string) $cheapest->price ) . ' ' . esc_html( $currency );
+ if ( $priciest ) $lines[] = '💎 Teuerstes:
' . esc_html( $priciest->item_title ) . ' – ' . esc_html( (string) $priciest->price ) . ' ' . esc_html( $currency );
+ }
+
+ if ( $shop_url ) {
+ $lines[] = "
";
+ }
+
+ return [
+ 'source' => 'shop',
+ 'title' => '🛒 Shop',
+ 'content' => implode( '
', $lines ),
+ ];
+}
+
+// ============================================================
+// INTENT: TICKET (WP Multi Ticket Pro)
+// ============================================================
+
+function mm_intent_ticket( $q, $bot ) {
+ global $wpdb;
+ $table = $wpdb->prefix . 'wmt_tickets';
+ $table_msg = $wpdb->prefix . 'wmt_messages';
+ $exists = $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) === $table;
+
+ // ── Ticket per Nummer nachschlagen ────────────────────────
+ if ( preg_match( '/#?(\d{3,6})\b/', $q, $m ) && $exists ) {
+ $ticket_id = intval( $m[1] );
+ $ticket = $wpdb->get_row( $wpdb->prepare(
+ "SELECT id, subject, status, category, department, created_at, guest_name, guest_email
+ FROM $table WHERE id = %d",
+ $ticket_id
+ ) );
+
+ if ( $ticket ) {
+ // Letzte Nachricht
+ $last_msg = '';
+ if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_msg'" ) === $table_msg ) {
+ $msg = $wpdb->get_row( $wpdb->prepare(
+ "SELECT message, created_at FROM $table_msg WHERE ticket_id = %d ORDER BY created_at DESC LIMIT 1",
+ $ticket_id
+ ) );
+ if ( $msg ) {
+ $last_msg = '
💬 Letzte Nachricht:
'
+ . esc_html( wp_trim_words( $msg->message, 20, '…' ) )
+ . ' (' . wp_date( 'd.m.Y H:i', strtotime( $msg->created_at ) ) . ') ';
+ }
+ }
+
+ $lines = [
+ '🎫 Ticket
#' . $ticket->id . ' ',
+ '📋 Betreff:
' . esc_html( $ticket->subject ) . ' ',
+ '📌 Status:
' . esc_html( $ticket->status ) . ' ',
+ '🏷️ Kategorie: ' . esc_html( $ticket->category ?: '–' ),
+ ];
+ if ( ! empty( $ticket->department ) ) {
+ $lines[] = '🏢 Abteilung: ' . esc_html( $ticket->department );
+ }
+ if ( ! empty( $ticket->guest_name ) ) {
+ $lines[] = '👤 Von: ' . esc_html( $ticket->guest_name );
+ }
+ $lines[] = '📅 Erstellt: ' . wp_date( 'd.m.Y \u\m H:i', strtotime( $ticket->created_at ) );
+ if ( $last_msg ) $lines[] = $last_msg;
+
+ return [
+ 'source' => 'ticket',
+ 'title' => '🎫 Ticket #' . $ticket->id,
+ 'content' => implode( '
', $lines ),
+ ];
+ } else {
+ return [
+ 'source' => 'ticket',
+ 'title' => '🎫 Ticket nicht gefunden',
+ 'content' => 'Ticket
#' . $ticket_id . ' existiert nicht.',
+ ];
+ }
+ }
+
+ // ── Allgemeine Ticket-Übersicht ────────────────────────────
+ $lines = [];
+
+ if ( $exists ) {
+ $open = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table WHERE status NOT LIKE %s", '%Geschlossen%' ) );
+ $closed = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $table WHERE status LIKE %s", '%Geschlossen%' ) );
+ $total = $open + $closed;
+
+ $lines[] = '📊 Gesamt:
' . $total . ' Tickets · Offen:
' . $open . ' · Geschlossen:
' . $closed . ' ';
+
+ // Kategorien anzeigen
+ $cats = $wpdb->get_results(
+ "SELECT COALESCE(category, 'Keine Kategorie') as cat, COUNT(*) as cnt
+ FROM $table GROUP BY category ORDER BY cnt DESC LIMIT 5"
+ );
+ if ( ! empty( $cats ) ) {
+ $cat_parts = [];
+ foreach ( $cats as $c ) {
+ $cat_parts[] = esc_html( $c->cat ) . ' (' . intval( $c->cnt ) . ')';
+ }
+ $lines[] = '📂
Kategorien: ' . implode( ' · ', $cat_parts );
+ }
+ }
+
+ $ticket_url = $bot['url_tickets'] ?? '';
+ if ( $ticket_url ) {
+ $lines[] = "→
Neues Ticket erstellen ";
+ $lines[] = '
Oder gib eine Ticket-Nummer ein, z.B.: #1234 ';
+ } else {
+ $lines[] = 'Bitte nutze das Support-Formular auf unserer Website.';
+ }
+
+ return [
+ 'source' => 'ticket',
+ 'title' => '🎫 Support-Ticket',
+ 'content' => implode( '
', $lines ),
+ ];
+}
+
+// ============================================================
+// INTENT: FORUM (WP Business Forum)
+// ============================================================
+
+function mm_intent_forum( $q ) {
+ // Nur aktiv wenn WBF installiert UND URL im Backend gesetzt
+ $bot = get_option( 'mm_bot_data', [] );
+ if ( ! class_exists( 'WBF_DB' ) ) return null;
+ if ( empty( $bot['url_forum'] ) ) return null;
+
+ global $wpdb;
+
+ $forum_url = esc_url( $bot['url_forum'] );
+ $q_lc = mb_strtolower( $q );
+
+ // Tabellen prüfen — fehlen sie, früh abbrechen statt hängen
+ $t_tbl = $wpdb->prefix . 'forum_threads';
+ $p_tbl = $wpdb->prefix . 'forum_posts';
+ $u_tbl = $wpdb->prefix . 'forum_users';
+ $c_tbl = $wpdb->prefix . 'forum_categories';
+
+ $tables_ok = (
+ $wpdb->get_var( "SHOW TABLES LIKE '$t_tbl'" ) === $t_tbl &&
+ $wpdb->get_var( "SHOW TABLES LIKE '$u_tbl'" ) === $u_tbl &&
+ $wpdb->get_var( "SHOW TABLES LIKE '$c_tbl'" ) === $c_tbl
+ );
+
+ // ── Sub-Intent: Registrierung ─────────────────────────────
+ if ( preg_match( '/\b(registrier(en|ung)?|konto erstellen|account erstellen|sign.?up|einschreiben)\b/i', $q ) ) {
+ $lines = [];
+ if ( $tables_ok ) {
+ try {
+ $reg_mode = get_option( 'wbf_settings', [] )['registration_mode'] ?? 'open';
+ $member_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $u_tbl WHERE role != 'banned'" );
+
+ $lines[] = '📝
Registrierung: ';
+ if ( $reg_mode === 'disabled' ) {
+ $lines[] = '❌ Die Registrierung ist derzeit
deaktiviert .';
+ } elseif ( $reg_mode === 'invite' ) {
+ $lines[] = '🔒 Das Forum nutzt
Einladungscodes . Du benötigst einen gültigen Code.';
+ } else {
+ $lines[] = '✅ Die Registrierung ist
offen — jederzeit möglich.';
+ }
+ if ( $member_count > 0 ) {
+ $lines[] = '
👥 Bereits ' . $member_count . ' Mitglieder dabei. ';
+ }
+ } catch ( \Throwable $e ) {
+ $lines[] = '📝 Registrierung verfügbar.';
+ }
+ } else {
+ $lines[] = '📝
Registrierung: ';
+ $lines[] = 'Erstelle deinen Account direkt im Forum.';
+ }
+ $lines[] = "→
Zum Forum & Registrierung ";
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Forum-Registrierung',
+ 'content' => implode( '
', $lines ),
+ ];
+ }
+
+ // ── Sub-Intent: Login / Passwort ──────────────────────────
+ if ( preg_match( '/\b(login|einloggen|passwort vergessen|passwort.?reset|zugangsdaten)\b/i', $q ) ) {
+ $lines = [];
+ $lines[] = '🔑
Forum-Login: ';
+ $lines[] = "→
Zum Forum & Login ";
+ if ( preg_match( '/passwort/i', $q ) ) {
+ $lines[] = '
🔓
Passwort vergessen? ';
+ $lines[] = 'Klicke auf der Login-Seite auf
„Passwort vergessen" .';
+ }
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Forum-Login',
+ 'content' => implode( '
', $lines ),
+ ];
+ }
+
+ // ── Sub-Intent: Profil ────────────────────────────────────
+ if ( preg_match( '/\b(profil|mein konto|mein account|avatar|signatur|forum rang|forum level)\b/i', $q ) ) {
+ $lines = [];
+ $lines[] = '👤
Dein Forum-Profil enthält:';
+ $lines[] = ' • Anzeigename, Avatar & Signatur';
+ if ( class_exists( 'WBF_Levels' ) && WBF_Levels::is_enabled() ) {
+ $lines[] = ' • Level-System (basiert auf Beitragsanzahl)';
+ }
+ $lines[] = ' • Rollen-Badge, Beitragsanzahl & Registrierungsdatum';
+ $lines[] = "→
Zum Forum → Profil öffnen ";
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Forum-Profil',
+ 'content' => implode( '
', $lines ),
+ ];
+ }
+
+ // ── Sub-Intent: Nachrichten / DM ──────────────────────────
+ if ( preg_match( '/\b(direktnachricht|forum nachricht|forum inbox|pn schreiben|privat.?nachricht)\b/i', $q ) ) {
+ $lines = [];
+ $lines[] = '✉️
Direktnachrichten im Forum:';
+ $lines[] = 'Du kannst eingeloggten Mitgliedern direkt Nachrichten schreiben.';
+ $lines[] = "→
Forum öffnen → Postfach ";
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Forum-Nachrichten',
+ 'content' => implode( '
', $lines ),
+ ];
+ }
+
+ // ── Sub-Intent: Thread erstellen ──────────────────────────
+ if ( preg_match( '/\b(neuen thread|thread erstellen|beitrag erstellen|topic erstellen|im forum schreiben|im forum posten)\b/i', $q ) ) {
+ $lines = [];
+ $lines[] = '✏️
Neuen Thread erstellen: ';
+ $lines[] = '① Melde dich im Forum an.';
+ $lines[] = '② Wähle die passende Kategorie.';
+ $lines[] = '③ Klicke auf
„Neuen Thread" und fülle Titel & Inhalt aus.';
+ $lines[] = "→
Forum öffnen ";
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Thread erstellen',
+ 'content' => implode( '
', $lines ),
+ ];
+ }
+
+ // ── Suchbegriff extrahieren ────────────────────────────────
+ $search = preg_replace( '/\b(forum|diskussion|thread|thema|beitrag|post|kategorie|suche?)\b/i', '', $q );
+ $search = trim( preg_replace( '/\s+/', ' ', $search ) );
+
+ // ── Thread-Suche ──────────────────────────────────────────
+ if ( strlen( $search ) >= 3 && $tables_ok ) {
+ try {
+ $threads = $wpdb->get_results( $wpdb->prepare(
+ "SELECT t.id, t.title, t.slug, t.reply_count, t.view_count, t.is_pinned,
+ c.name as cat_name
+ FROM {$t_tbl} t
+ LEFT JOIN {$c_tbl} c ON t.category_id = c.id
+ WHERE t.title LIKE %s AND t.deleted_at IS NULL
+ ORDER BY t.is_pinned DESC, t.created_at DESC LIMIT 5",
+ '%' . $wpdb->esc_like( $search ) . '%'
+ ) );
+
+ if ( ! empty( $threads ) ) {
+ $html = '';
+ foreach ( $threads as $t ) {
+ $t_url = $forum_url . '?thread=' . esc_attr( $t->slug );
+ $pin = $t->is_pinned ? '📌 ' : '';
+ $meta = [];
+ if ( $t->reply_count > 0 ) $meta[] = $t->reply_count . ' Antworten';
+ if ( $t->view_count > 0 ) $meta[] = $t->view_count . ' Aufrufe';
+ $title_short = mb_strlen( $t->title ) > 50 ? mb_substr( $t->title, 0, 50 ) . '…' : $t->title;
+ $html .= '
';
+ $html .= $pin . '
' . esc_html( $title_short ) . ' ';
+ if ( $t->cat_name ) $html .= '
· ' . esc_html( $t->cat_name ) . ' ';
+ if ( ! empty( $meta ) ) $html .= '
' . implode( ' · ', $meta ) . ' ';
+ $html .= '
';
+ }
+ $html .= "
→
Alle Threads im Forum ";
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Forum – ' . count( $threads ) . ' Treffer',
+ 'content' => $html,
+ ];
+ }
+
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Forum',
+ 'content' => 'Kein Thread zu
' . esc_html( $search ) . ' gefunden.
'
+ . "→
Forum öffnen & selbst suchen ",
+ ];
+ } catch ( \Throwable $e ) {
+ // Bei DB-Fehler: einfach Übersicht zeigen
+ }
+ }
+
+ // ── Allgemeine Übersicht mit Live-Statistiken ──────────────
+ $lines = [];
+
+ if ( $tables_ok ) {
+ try {
+ $total_threads = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $t_tbl WHERE deleted_at IS NULL" );
+ $total_posts = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $p_tbl WHERE deleted_at IS NULL" );
+ $total_members = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $u_tbl WHERE role != 'banned'" );
+ $online_count = (int) $wpdb->get_var(
+ "SELECT COUNT(*) FROM $u_tbl WHERE last_active >= DATE_SUB(NOW(), INTERVAL 5 MINUTE)"
+ );
+
+ $stat_parts = [];
+ if ( $total_threads > 0 ) $stat_parts[] = '
' . $total_threads . ' Threads';
+ if ( $total_posts > 0 ) $stat_parts[] = '
' . $total_posts . ' Beiträge';
+ if ( $total_members > 0 ) $stat_parts[] = '
' . $total_members . ' Mitglieder';
+ if ( ! empty( $stat_parts ) ) {
+ $lines[] = '📊 ' . implode( ' · ', $stat_parts );
+ }
+
+ $online_icon = $online_count > 0 ? '🟢' : '⚫';
+ $lines[] = $online_icon . ' ' . ( $online_count > 0
+ ? '
' . $online_count . ' Mitglied' . ( $online_count > 1 ? 'er' : '' ) . ' gerade online'
+ : 'Aktuell niemand aktiv' );
+
+ // Kategorien
+ $cats = $wpdb->get_results(
+ "SELECT c.name, c.slug, COUNT(t.id) as thread_count
+ FROM {$c_tbl} c
+ LEFT JOIN {$t_tbl} t ON t.category_id = c.id AND t.deleted_at IS NULL
+ WHERE c.parent_id = 0
+ GROUP BY c.id ORDER BY c.sort_order ASC LIMIT 6"
+ );
+ if ( ! empty( $cats ) ) {
+ $lines[] = '
📂
Kategorien: ';
+ foreach ( $cats as $cat ) {
+ $c_url = $forum_url . '?cat=' . esc_attr( $cat->slug );
+ $count = $cat->thread_count > 0 ? '
(' . (int) $cat->thread_count . ') ' : '';
+ $lines[] = ' →
'
+ . esc_html( $cat->name ) . ' ' . $count;
+ }
+ }
+
+ // Neueste Threads
+ $recent = $wpdb->get_results(
+ "SELECT t.title, t.slug, t.reply_count
+ FROM {$t_tbl} t
+ WHERE t.deleted_at IS NULL AND t.is_pinned = 0
+ ORDER BY t.created_at DESC LIMIT 3"
+ );
+ if ( ! empty( $recent ) ) {
+ $lines[] = '
🆕
Neueste Threads: ';
+ foreach ( $recent as $r ) {
+ $t_url = $forum_url . '?thread=' . esc_attr( $r->slug );
+ $title_short = mb_strlen( $r->title ) > 50 ? mb_substr( $r->title, 0, 50 ) . '…' : $r->title;
+ $replies = $r->reply_count > 0 ? '
(' . (int) $r->reply_count . ' Antw.) ' : '';
+ $lines[] = ' →
'
+ . esc_html( $title_short ) . ' ' . $replies;
+ }
+ }
+ } catch ( \Throwable $e ) {
+ $lines[] = '⚠️ Forum-Daten konnten nicht geladen werden.';
+ }
+ }
+
+ $lines[] = ( ! empty( $lines ) ? '
' : '' )
+ . "→
Forum öffnen ";
+
+ return [
+ 'source' => 'forum',
+ 'title' => '💬 Forum',
+ 'content' => implode( '
', $lines ),
+ ];
+}
+
+// ============================================================
+// INTENT: GALERIE (MC MultiServer Gallery PRO)
+// ============================================================
+
+function mm_intent_gallery( $bot, $q_lc = '' ) {
+ $gallery_url = ! empty( $bot['url_gallery'] ) ? $bot['url_gallery'] : home_url( '/galerie' );
+
+ // ── Erkennen ob Upload-Frage ──────────────────────────────
+ $is_upload_query = (bool) preg_match(
+ '/hochlad|upload|uploaden|verifizier|verify|token|bild teilen|bilder teilen|wie.*bild|anleitung.*galerie/i',
+ $q_lc
+ );
+
+ $lines = [];
+
+ // ── 1. Galerie-Link ──────────────────────────────────────
+ $lines[] = "📷 →
Galerie öffnen ";
+
+ // ── 2. Upload-Anleitung (bei Upload-Frage oder allgemein) ─
+ if ( $is_upload_query ) {
+ $lines[] = '
';
+ $lines[] = '📤
Bilder hochladen – so geht\'s: ';
+ $lines[] = '①
Galerie öffnen und auf
„Bilder hochladen" klicken.';
+ $lines[] = '② Deinen
Minecraft-Namen eingeben und den Server wählen →
Session starten .';
+ $lines[] = '③ Im Spiel den Befehl
/verify [token] eingeben, um dich zu verifizieren.';
+ $lines[] = '④
Screenshots auswählen (optional Album anlegen) → hochladen ✓';
+ $lines[] = '
💡 Der Verify-Token ist 5 Minuten gültig. Du musst dazu online auf dem Server sein. ';
+ } else {
+ // Kurz-Hinweis auf Upload auch bei allgemeiner Galerie-Frage
+ $lines[] = "🖼️ Du kannst eigene Screenshots direkt auf der Galerie-Seite hochladen.";
+ }
+
+ // ── 3. Bild des Tages ────────────────────────────────────
+ if ( post_type_exists( 'mc_gallery' ) ) {
+ $today_key = 'mc_daily_image_' . gmdate( 'Y-m-d' );
+ $image_id = get_transient( $today_key );
+
+ if ( $image_id && wp_attachment_is_image( $image_id ) ) {
+ $img = wp_get_attachment_image_src( $image_id, 'medium' );
+ $full = wp_get_attachment_image_src( $image_id, 'full' );
+ $meta = get_post( $image_id );
+ $uploader = '';
+
+ // Spielername aus Galerie-Post-Meta holen
+ if ( $meta && $meta->post_parent ) {
+ $player = get_post_meta( $meta->post_parent, 'mc_player', true );
+ if ( $player ) {
+ $uploader = '
von ' . esc_html( $player ) . ' ';
+ }
+ }
+
+ if ( $img ) {
+ $lines[] = '
';
+ $lines[] = '🌟
Bild des Tages' . $uploader . ': ';
+ $lines[] = "
"
+ . " "
+ . " ";
+ }
+ } else {
+ // Kein Tagesbild gecacht → Hinweis
+ $lines[] = '
📅 Heute noch kein Bild des Tages verfügbar. ';
+ }
+
+ // Galerie-Statistik
+ $count = wp_count_posts( 'mc_gallery' );
+ if ( $count && $count->publish > 0 ) {
+ $lines[] = '
📁 ' . intval( $count->publish ) . ' Galerie(n) auf dem Server. ';
+ }
+ }
+
+ return [
+ 'source' => 'gallery',
+ 'title' => $is_upload_query ? '📤 Galerie & Upload' : '📷 Galerie',
+ 'content' => implode( '
', $lines ),
+ ];
+}
+
+// ============================================================
+// INTENT: FAQ (Custom Post Type 'faq')
+// ============================================================
+
+function mm_intent_faq( $q ) {
+ if ( ! post_type_exists( 'faq' ) ) return null;
+
+ $search = preg_replace( '/\b(faq|häufig|frage|oft gefragt)\b/i', '', $q );
+ $search = trim( $search );
+
+ $results = get_posts( [
+ 'post_type' => 'faq',
+ 'post_status' => 'publish',
+ 's' => strlen( $search ) >= 3 ? $search : '',
+ 'posts_per_page' => 4,
+ 'orderby' => 'relevance',
+ ] );
+
+ if ( empty( $results ) ) return null;
+
+ $html = [];
+ foreach ( $results as $post ) {
+ $excerpt = get_the_excerpt( $post->ID );
+ $html[] = '❓
' . esc_html( $post->post_title ) . ' '
+ . ( $excerpt ? '
' . wp_trim_words( $excerpt, 40, '…' ) : '' );
+ }
+
+ return [
+ 'source' => 'faq',
+ 'title' => '❓ FAQ',
+ 'content' => implode( '
', $html ),
+ ];
+}
+
+// ============================================================
+// SPIELER-NAME EXTRAHIEREN
+// ============================================================
+
+function mm_extract_player_name( $q ) {
+ // Explizit: "von Steve", "spieler Steve", "für Steve"
+ if ( preg_match( '/(?:von|spieler|name|für|player|ban.*?von|bann.*?von)[:\s]+([A-Za-z0-9_]{3,16})/iu', $q, $m ) ) {
+ return $m[1];
+ }
+ // "Steve ist gebannt", "ist Steve gebannt"
+ if ( preg_match( '/\b([A-Za-z0-9_]{3,16})\s+ist\s+(gebannt|gesperrt|online|offline)/i', $q, $m ) ) {
+ return $m[1];
+ }
+ // "bin ich" → kein Name (eingeloggter User, kein Minecraft-Login hier)
+ if ( preg_match( '/\b(bin ich|ich bin|mein ban|mein status)\b/i', $q ) ) {
+ return '';
+ }
+ // Allgemein: letztes kapitalisiertes Wort als Spielername (MC-Namen beginnen meist groß)
+ if ( preg_match_all( '/\b([A-Z][A-Za-z0-9_]{2,15})\b/', $q, $m ) ) {
+ $stop = [ 'Minecraft', 'Wiki', 'Forum', 'FAQ', 'Shop', 'Discord', 'Ban', 'Mute',
+ 'Kick', 'Warn', 'Spielzeit', 'Playtime', 'Galerie', 'Ticket', 'Support' ];
+ foreach ( array_reverse( $m[1] ) as $candidate ) {
+ if ( ! in_array( $candidate, $stop, true ) ) {
+ return $candidate;
+ }
+ }
+ }
+ return '';
+}
+
+// ============================================================
+// FALLBACK
+// ============================================================
+
+function mm_fallback_response( $bot ) {
+ $hints = [
+ '🖥️
Server – z.B. "Wie ist die Server-IP?"',
+ ];
+ if ( ! empty( $bot['url_rules'] ) ) $hints[] = '📜
Regeln – z.B. "Ist PvP erlaubt?"';
+ if ( ! empty( $bot['url_player_history'] ) ) $hints[] = '👤
Spieler-Info – z.B. "Spielzeit von Steve"';
+ if ( ! empty( $bot['litebans_dashboard_url'] ) || ! empty( get_option( 'wp_litebans_pro_settings', [] )['db_name'] ) )
+ $hints[] = '🔨
Ban-Status – z.B. "Ist Steve gebannt?"';
+ if ( ! empty( $bot['url_wiki'] ) ) $hints[] = '📖
Wiki – z.B. "Wiki Befehle"';
+ if ( ! empty( $bot['url_gallery'] ) ) $hints[] = '📷
Galerie – z.B. "Zeig die Galerie"';
+ if ( ! empty( $bot['url_shop'] ) ) $hints[] = '🛒
Shop – z.B. "Was kostet ein Diamantschwert?"';
+ if ( ! empty( $bot['url_tickets'] ) ) $hints[] = '🎫
Ticket – z.B. "Ticket erstellen"';
+
+ return [
+ 'source' => 'fallback',
+ 'title' => '❓ Ich habe dazu keine Antwort',
+ 'content' => 'Versuche es mit einem dieser Themen:
' . implode( '
', $hints ),
+ ];
+}
+
+// ============================================================
+// RESPONSE BUILDER
+// Alle Part-Arrays zu einem einzigen formatierten HTML-String
+// zusammenführen.
+// ============================================================
+
+function mm_build_response( $parts ) {
+ if ( count( $parts ) === 1 ) {
+ $p = $parts[0];
+ return [
+ 'reply' => isset( $p['title'] )
+ ? "
{$p['title']} {$p['content']}"
+ : $p['content'],
+ 'parts' => $parts,
+ ];
+ }
+
+ $blocks = [];
+ foreach ( $parts as $p ) {
+ $block = isset( $p['title'] ) ? "
{$p['title']} " : '';
+ $block .= $p['content'];
+ $blocks[] = $block;
+ }
+
+ return [
+ 'reply' => implode( '
', $blocks ),
+ 'parts' => $parts,
+ ];
+}
\ No newline at end of file
diff --git a/Minecraft-Modern-Theme/inc/assistant-widget.php b/Minecraft-Modern-Theme/inc/assistant-widget.php
new file mode 100644
index 0000000..5142cb4
--- /dev/null
+++ b/Minecraft-Modern-Theme/inc/assistant-widget.php
@@ -0,0 +1,854 @@
+ 'mm_bot_sanitize_settings',
+ ] );
+} );
+
+function mm_bot_sanitize_settings( $input ) {
+ $clean = [];
+
+ $text_fields = [ 'server_ip', 'server_ver', 'server_specs', 'bot_name', 'welcome' ];
+ $url_fields = [
+ 'url_wiki', 'url_rules', 'url_tickets', 'url_faq',
+ 'url_team', 'url_shop', 'url_gallery', 'url_player_history',
+ 'url_forum', 'link_discord', 'litebans_dashboard_url',
+ ];
+
+ foreach ( $text_fields as $f ) {
+ $clean[ $f ] = isset( $input[ $f ] ) ? sanitize_text_field( $input[ $f ] ) : '';
+ }
+ foreach ( $url_fields as $f ) {
+ $clean[ $f ] = isset( $input[ $f ] ) ? esc_url_raw( $input[ $f ] ) : '';
+ }
+
+ $clean['qa'] = [];
+ if ( ! empty( $input['qa'] ) && is_array( $input['qa'] ) ) {
+ foreach ( $input['qa'] as $item ) {
+ if ( empty( $item['keys'] ) ) continue;
+ $clean['qa'][] = [
+ 'keys' => sanitize_text_field( $item['keys'] ),
+ 'val' => wp_kses_post( $item['val'] ),
+ ];
+ }
+ }
+
+ return $clean;
+}
+
+// =========================================================================
+// 2. ADMIN-SEITE
+// =========================================================================
+
+function mm_render_bot_admin() {
+ $data = get_option( 'mm_bot_data', [] );
+ ?>
+
+
+
+ '🖥️ Server-Status', 'q' => 'server status' ];
+ }
+
+ // Regeln – nur wenn URL im Backend gesetzt
+ if ( ! empty( $data['url_rules'] ) ) {
+ $quick[] = [ 'label' => '📜 Regelwerk', 'q' => 'regeln' ];
+ }
+
+ // Wiki – nur wenn URL im Backend gesetzt
+ if ( ! empty( $data['url_wiki'] ) ) {
+ $quick[] = [ 'label' => '📖 Wiki', 'q' => 'wiki' ];
+ }
+
+ // Shop – nur wenn URL im Backend gesetzt
+ global $wpdb;
+ if ( ! empty( $data['url_shop'] ) ) {
+ $quick[] = [ 'label' => '🛒 Shop', 'q' => 'shop' ];
+ }
+
+ // Ticket / Support – nur wenn URL im Backend gesetzt
+ if ( ! empty( $data['url_tickets'] ) ) {
+ $quick[] = [ 'label' => '🎫 Support-Ticket', 'q' => 'ticket erstellen' ];
+ }
+
+ // Forum
+ if ( class_exists( 'WBF_DB' ) && ! empty( $data['url_forum'] ) ) {
+ $quick[] = [ 'label' => '💬 Forum', 'q' => 'forum' ];
+ }
+
+ // Galerie – nur wenn URL im Backend gesetzt
+ if ( ! empty( $data['url_gallery'] ) ) {
+ $quick[] = [ 'label' => '📷 Galerie', 'q' => 'galerie' ];
+ }
+
+ // Ban-Status
+ $lb = get_option( 'wp_litebans_pro_settings', [] );
+ if ( ! empty( $lb['db_name'] ) ) {
+ $quick[] = [ 'label' => '🔨 Strafen prüfen', 'q' => 'meine strafen' ];
+ }
+
+ // Spieler-History – nur wenn URL im Backend gesetzt
+ if ( ! empty( $data['url_player_history'] ) ) {
+ $quick[] = [ 'label' => '⏱️ Spielzeit', 'q' => 'spielzeit' ];
+ }
+
+ // Discord
+ if ( ! empty( $data['link_discord'] ) ) {
+ $quick[] = [ 'label' => '💬 Discord', 'q' => 'discord' ];
+ }
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ➤
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+ 📦 Was wird gesichert:
+ ✓ Customizer-Einstellungen (Farben, Social Links, Menü-Design, etc.)
+ ✓ Livestream API Keys (YouTube, Twitch)
+ ✓ Homepage-Seite (Titel, Inhalt, Highlight-Bild)
+ ✓ Navigation Menüs inkl. aller Items & Struktur
+ ✓ Widget-Konfigurationen
+ ✓ Team-Mitglieder (mit UUID, Avatar, Banner)
+ ✓ FAQ-Einträge & Kategorien
+ ✓ Custom CSS
+ ✓ Announcement-Bar Einstellungen
+
+
@@ -87,6 +100,33 @@ endif;
// Customizer Register
// =========================================================================
function minecraft_modern_customize_register( $wp_customize ) {
+ // =========================================================================
+ // 9. Virtueller Assistent
+ // =========================================================================
+ $wp_customize->add_section( 'assistant_settings', array(
+ 'title' => __('Virtueller Assistent', 'minecraft-modern-theme'),
+ 'priority' => 80,
+ 'description' => __('Steuert den virtuellen Assistenten im Frontend. Avatar basiert auf Minecraft-UUID.', 'minecraft-modern-theme'),
+ ) );
+ $wp_customize->add_setting( 'assistant_enabled', array(
+ 'default' => false,
+ 'sanitize_callback' => 'wp_validate_boolean',
+ ) );
+ $wp_customize->add_control( 'assistant_enabled', array(
+ 'label' => __('Virtuellen Assistenten aktivieren', 'minecraft-modern-theme'),
+ 'section' => 'assistant_settings',
+ 'type' => 'checkbox',
+ ) );
+ $wp_customize->add_setting( 'assistant_minecraft_uuid', array(
+ 'default' => '',
+ 'sanitize_callback' => 'sanitize_text_field',
+ ) );
+ $wp_customize->add_control( 'assistant_minecraft_uuid', array(
+ 'label' => __('Minecraft UUID für Avatar', 'minecraft-modern-theme'),
+ 'section' => 'assistant_settings',
+ 'type' => 'text',
+ 'description' => __('Gib die Minecraft-UUID für den Avatar des Assistenten ein.', 'minecraft-modern-theme'),
+ ) );
// =========================================================================
// 1. HEADER SLIDER
@@ -235,18 +275,18 @@ function minecraft_modern_customize_register( $wp_customize ) {
// =========================================================================
$wp_customize->add_section( 'social_links', array( 'title' => __('Social Media Links', 'minecraft-modern-theme'), 'priority' => 40 ) );
$social_platforms = array(
- 'discord' => 'Discord', 'youtube' => 'YouTube', 'twitter' => 'Twitter (X)',
+ 'bluesky' => 'BlueSky', 'discord' => 'Discord', 'youtube' => 'YouTube', 'twitter' => 'Twitter (X)',
'facebook' => 'Facebook', 'instagram' => 'Instagram', 'tiktok' => 'TikTok',
'twitch' => 'Twitch', 'steam' => 'Steam', 'github' => 'GitHub',
'linkedin' => 'LinkedIn', 'pinterest' => 'Pinterest', 'reddit' => 'Reddit',
- 'teamspeak' => 'Teamspeak', 'spotify' => 'Spotify',
+ 'mastodon' => 'Mastodon', 'threads' => 'Threads', 'kickstarter' => 'Kickstarter',
+ 'teamspeak' => 'Teamspeak', 'spotify' => 'Spotify', 'stoat' => 'Stoat',
);
foreach ( $social_platforms as $key => $label ) {
$wp_customize->add_setting( 'social_' . $key, array( 'sanitize_callback' => 'esc_url_raw' ) );
$wp_customize->add_control( 'social_' . $key, array( 'label' => $label . ' URL', 'section' => 'social_links', 'type' => 'url' ) );
}
-
// =========================================================================
// 6. FOOTER
// =========================================================================
@@ -311,6 +351,60 @@ function minecraft_modern_customize_register( $wp_customize ) {
) );
+ // =========================================================================
+ // 8.5. VIDEO / LIVESTREAM EINSTELLUNGEN
+ // =========================================================================
+ $wp_customize->add_section( 'video_livestream_settings', array(
+ 'title' => __('Video & Livestream', 'minecraft-modern-theme'),
+ 'description' => __('Einstellungen für YouTube Livestream-Erkennung. Hauptmethode: Livestream-Posts unter "Livestreams" erstellen. Optional: Zusätzlichen Hauptkanal hier eintragen.', 'minecraft-modern-theme'),
+ 'priority' => 75,
+ ) );
+
+ $wp_customize->add_setting( 'youtube_api_key', array(
+ 'default' => '',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'transport' => 'refresh',
+ ) );
+ $wp_customize->add_control( 'youtube_api_key', array(
+ 'label' => __('YouTube API Key', 'minecraft-modern-theme'),
+ 'description' => __('Erforderlich für automatische YouTube Live-Erkennung. Hier API Key erstellen ', 'minecraft-modern-theme'),
+ 'section' => 'video_livestream_settings',
+ 'type' => 'text',
+ 'input_attrs' => array(
+ 'placeholder' => 'AIzaSyD...',
+ ),
+ ) );
+
+ $wp_customize->add_setting( 'twitch_client_id', array(
+ 'default' => '',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'transport' => 'refresh',
+ ) );
+ $wp_customize->add_control( 'twitch_client_id', array(
+ 'label' => __('Twitch Client ID', 'minecraft-modern-theme'),
+ 'description' => __('Erforderlich für Twitch Live-Erkennung.
Hier App erstellen ', 'minecraft-modern-theme'),
+ 'section' => 'video_livestream_settings',
+ 'type' => 'text',
+ 'input_attrs' => array(
+ 'placeholder' => 'xxxxxxxxxxxxxx',
+ ),
+ ) );
+
+ $wp_customize->add_setting( 'twitch_client_secret', array(
+ 'default' => '',
+ 'sanitize_callback' => 'sanitize_text_field',
+ 'transport' => 'refresh',
+ ) );
+ $wp_customize->add_control( 'twitch_client_secret', array(
+ 'label' => __('Twitch Client Secret', 'minecraft-modern-theme'),
+ 'description' => __('Nur für Live-Prüfung. Wird serverseitig genutzt.', 'minecraft-modern-theme'),
+ 'section' => 'video_livestream_settings',
+ 'type' => 'text',
+ 'input_attrs' => array(
+ 'placeholder' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
+ ),
+ ) );
+
// =========================================================================
// 9. EXPORT / IMPORT
// =========================================================================
diff --git a/Minecraft-Modern-Theme/inc/theme-updater.php b/Minecraft-Modern-Theme/inc/theme-updater.php
index dbad110..1863f67 100644
--- a/Minecraft-Modern-Theme/inc/theme-updater.php
+++ b/Minecraft-Modern-Theme/inc/theme-updater.php
@@ -1,7 +1,8 @@
theme_slug = get_template();
+
+ add_action( 'admin_notices', [ $this, 'display_update_notice' ] );
add_action( 'wp_dashboard_setup', [ $this, 'add_dashboard_widget' ] );
-
- // Refresh Logik
- add_action( 'admin_init', [ $this, 'handle_refresh_request' ] );
+ add_action( 'admin_init', [ $this, 'handle_refresh_request' ] );
}
/**
- * Holt die API-Daten von Gitea
+ * Holt die API-Daten von Gitea (mit Transient-Cache).
*/
private function get_latest_release() {
$update_data = get_transient( $this->transient_key );
if ( false === $update_data ) {
- $api_url = "https://git.viper.ipv64.net/api/v1/repos/{$this->repo}/releases/latest";
+ $api_url = "https://git.viper.ipv64.net/api/v1/repos/{$this->repo}/releases/latest";
$response = wp_remote_get( $api_url, [ 'timeout' => 10 ] );
if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
@@ -41,12 +42,12 @@ class Minecraft_Modern_Theme_Manager {
return [ 'error' => true ];
}
- $data = json_decode( wp_remote_retrieve_body( $response ) );
+ $data = json_decode( wp_remote_retrieve_body( $response ) );
$new_version = ltrim( $data->tag_name, 'vV' );
-
+
$update_data = [
'version' => $new_version,
- 'url' => "https://git.viper.ipv64.net/{$this->repo}/releases"
+ 'url' => "https://git.viper.ipv64.net/{$this->repo}/releases",
];
set_transient( $this->transient_key, $update_data, 12 * HOUR_IN_SECONDS );
@@ -56,7 +57,7 @@ class Minecraft_Modern_Theme_Manager {
}
/**
- * Zeigt die gelbe Info-Box oben im Admin-Bereich
+ * Zeigt die gelbe Info-Box oben im Admin-Bereich an, wenn ein Update verfügbar ist.
*/
public function display_update_notice() {
if ( ! current_user_can( 'update_themes' ) ) return;
@@ -65,14 +66,18 @@ class Minecraft_Modern_Theme_Manager {
if ( isset( $latest['error'] ) ) return;
$current_version = wp_get_theme( $this->theme_slug )->get( 'Version' );
+ if ( ! $current_version ) return;
if ( version_compare( $current_version, $latest['version'], '<' ) ) {
?>
- Minecraft Modern Update verfügbar: Version ist bereit zum Download.
- Zum Download →
+ Minecraft Modern Update verfügbar:
+ Version ist bereit zum Download.
+
+ Zum Download →
+
theme_slug )->get( 'Version' );
- $latest = $this->get_latest_release();
-
+ $latest = $this->get_latest_release();
+
echo '