Files
Minecraft-Modern-Theme/Minecraft-Modern-Theme/inc/assistant-widget.php
2026-03-30 20:42:44 +02:00

913 lines
38 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
// BUG-FIX: Das 'assistant_position' Setting wurde hier in einem eigenen
// customize_register-Hook registriert, BEVOR customizer.php die Section
// 'assistant_settings' anlegt. Das führte dazu, dass das Control keiner
// sichtbaren Section zugeordnet war.
// Die Registrierung wurde in inc/customizer.php verschoben (direkt nach
// den anderen assistant_*-Controls). Dieser Hook-Block kann daher entfallen.
/**
* Assistant Widget Virtueller Support-Assistent
*
* Vollständig integriert mit allen Plugins:
* → LiteBans Manager
* → MC Player History
* → BungeeCord Status
* → Multi Rules
* → WP Multi Wiki
* → WP Ingame Shop Pro
* → WP Multi Ticket Pro
* → WP Business Forum
* → MC MultiServer Gallery PRO
* → FAQ (Custom Post Type)
*
* @version 3.1
* @author M_Viper
*
* WICHTIG: Die eigentliche Antwort-Logik liegt in assistant-ajax.php.
* Diese Datei enthält nur: Admin-Backend, Widget-Frontend, JS.
*/
if ( ! defined( 'ABSPATH' ) ) exit;
// =========================================================================
// AJAX-Handler laden (assistant-ajax.php)
// =========================================================================
$mm_ajax_file = get_template_directory() . '/inc/assistant-ajax.php';
if ( file_exists( $mm_ajax_file ) ) {
require_once $mm_ajax_file;
}
// =========================================================================
// 1. ADMIN-BACKEND BOT-ZENTRALE
// =========================================================================
add_action( 'admin_menu', function () {
// Dashicon für Chatbot verwenden (z.B. dashicons-format-chat)
add_menu_page(
'Bot Setup',
'Bot Setup',
'manage_options',
'bot-setup',
'mm_render_bot_admin',
'dashicons-format-chat',
65
);
} );
add_action( 'admin_init', function () {
register_setting( 'mm_bot_settings', 'mm_bot_data', [
'sanitize_callback' => '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
// =========================================================================
// BUG-FIX: Funktion außerhalb von mm_render_bot_admin() definieren.
// Innerhalb einer Funktion definierte benannte Funktionen erzeugen einen
// Fatal Error "Cannot redeclare", wenn die äußere Funktion jemals ein
// zweites Mal ausgeführt wird (z.B. durch AJAX, REST, bestimmte Plugins).
if ( ! function_exists( 'mm_find_page_by_shortcode' ) ) :
function mm_find_page_by_shortcode( $shortcodes ) {
global $wpdb;
$conditions = [];
foreach ( (array) $shortcodes as $sc ) {
$conditions[] = $wpdb->prepare( 'post_content LIKE %s', '%[' . $wpdb->esc_like( $sc ) . '%' );
}
if ( empty( $conditions ) ) return '';
$where = implode( ' OR ', $conditions );
$page = $wpdb->get_row(
"SELECT ID FROM {$wpdb->posts}
WHERE post_status = 'publish'
AND post_type IN ('page','post')
AND ({$where})
LIMIT 1"
);
return $page ? get_permalink( $page->ID ) : '';
}
endif;
function mm_render_bot_admin() {
$data = get_option( 'mm_bot_data', [] );
?>
<div class="wrap">
<h1><span class="dashicons dashicons-robot"></span> Bot-Zentrale</h1>
<style>
.bot-card { background:#fff; padding:20px; border:1px solid #ccd0d4; border-radius:8px; margin-top:20px; box-shadow:0 2px 4px rgba(0,0,0,.05); }
.bot-card h2 { margin-top:0; color:#0073aa; border-bottom:1px solid #eee; padding-bottom:12px; }
.bot-card p.description { color:#666; font-style:italic; margin-top:4px; }
.badge { display:inline-block; background:#0099ff; color:#fff; font-size:11px; padding:1px 7px; border-radius:10px; margin-left:6px; vertical-align:middle; }
.badge.inactive { background:#999; }
</style>
<form method="post" action="options.php">
<?php settings_fields( 'mm_bot_settings' ); ?>
<!-- KARTE 1: Server -->
<div class="bot-card">
<h2>1. Server-Infos</h2>
<table class="form-table">
<tr>
<th><label>Server-IP / Adresse</label></th>
<td>
<input type="text" name="mm_bot_data[server_ip]" value="<?php echo esc_attr( $data['server_ip'] ?? '' ); ?>" class="regular-text" placeholder="play.example.net">
<p class="description">Wird bei Fragen nach der Server-IP angezeigt.</p>
</td>
</tr>
<tr>
<th><label>Minecraft-Version</label></th>
<td><input type="text" name="mm_bot_data[server_ver]" value="<?php echo esc_attr( $data['server_ver'] ?? '' ); ?>" class="small-text" placeholder="1.21.1"></td>
</tr>
<tr>
<th><label>Hardware / Specs</label></th>
<td>
<input type="text" name="mm_bot_data[server_specs]" value="<?php echo esc_attr( $data['server_specs'] ?? '' ); ?>" class="large-text" placeholder="z.B. Ryzen 9, 64 GB RAM, NVMe SSD">
<p class="description">Wird bei Fragen nach der Server-Hardware angezeigt.</p>
</td>
</tr>
</table>
</div>
<!-- KARTE 2: Bot-Einstellungen -->
<div class="bot-card">
<h2>2. Bot-Einstellungen</h2>
<table class="form-table">
<tr>
<th><label>Bot-Name</label></th>
<td><input type="text" name="mm_bot_data[bot_name]" value="<?php echo esc_attr( $data['bot_name'] ?? '' ); ?>" class="regular-text" placeholder="Viper-Bot"></td>
</tr>
<tr>
<th><label>Minecraft-UUID / Name (Avatar)</label></th>
<td>
<?php
$uuid = get_theme_mod( 'assistant_minecraft_uuid', 'Steve' );
?>
<input type="text" name="assistant_mc_uuid_preview" value="<?php echo esc_attr( $uuid ); ?>" class="regular-text" disabled>
<p class="description">UUID / Name wird im Theme-Customizer unter "Assistent" gesetzt.</p>
</td>
</tr>
<tr>
<th><label>Begrüßungstext</label></th>
<td>
<textarea name="mm_bot_data[welcome]" rows="3" class="large-text"><?php echo esc_textarea( $data['welcome'] ?? '' ); ?></textarea>
<p class="description">Erster Text der beim Öffnen des Assistenten angezeigt wird.</p>
</td>
</tr>
</table>
</div>
<!-- KARTE 3: Links -->
<div class="bot-card">
<h2>3. Wichtige Links</h2>
<p class="description" style="margin-bottom:12px;">
💡 Wenn eine Seite mit dem passenden Shortcode gefunden wird, erscheint ein <strong>„Vorschlag übernehmen"</strong>-Button.
</p>
<?php
$autodetect = [
'url_wiki' => mm_find_page_by_shortcode( ['wmw_wiki', 'wmw_search', 'wmw_article'] ),
'url_rules' => mm_find_page_by_shortcode( ['mrp_rules', 'mc_rules', 'multi_rules'] ),
'url_tickets' => mm_find_page_by_shortcode( ['wmtp_tickets', 'wm_tickets', 'multi_ticket'] ),
'url_shop' => mm_find_page_by_shortcode( ['wis_shop', 'ingame_shop', 'wis_items'] ),
'url_gallery' => mm_find_page_by_shortcode( ['mc_gallery', 'mc_gallery_overview', 'mc_gallery_upload', 'mc_gallery_all_albums'] ),
'url_faq' => mm_find_page_by_shortcode( ['faq_list', 'faq', 'faq_page'] ),
'url_player_history' => mm_find_page_by_shortcode( ['mc_player_history', 'mc_players', 'player_history'] ),
'url_forum' => mm_find_page_by_shortcode( ['business_forum'] ),
'litebans_dashboard_url' => mm_find_page_by_shortcode( ['litebans_dashboard', 'litebans', 'wp_litebans'] ),
];
$links = [
'url_wiki' => [ 'label' => '📖 Wiki-URL', 'plugin' => 'WP Multi Wiki', 'active' => post_type_exists( 'wmw_article' ) ],
'url_rules' => [ 'label' => '📜 Regelwerk-URL', 'plugin' => 'Multi Rules', 'active' => function_exists( 'mrp_get_plugin_version' ) ],
'url_tickets' => [ 'label' => '🎫 Ticket/Support-URL', 'plugin' => 'WP Multi Ticket Pro', 'active' => class_exists( 'WP_Multi_Ticket_Pro' ) ],
'url_shop' => [ 'label' => '🛒 Shop-URL', 'plugin' => 'WP Ingame Shop Pro', 'active' => class_exists( 'WIS_Activator' ) ],
'url_gallery' => [ 'label' => '📷 Galerie-URL', 'plugin' => 'MC MultiServer Gallery PRO', 'active' => post_type_exists( 'mc_gallery' ) ],
'url_faq' => [ 'label' => '❓ FAQ-URL', 'plugin' => 'FAQ Post Type', 'active' => post_type_exists( 'faq' ) ],
'url_player_history' => [ 'label' => '👤 Spieler-History-URL', 'plugin' => 'MC Player History', 'active' => function_exists( 'mcph_get_plugin_version' ) ],
'url_forum' => [ 'label' => '💬 Forum-URL', 'plugin' => 'WP Business Forum', 'active' => class_exists( 'WBF_DB' ) ],
'url_team' => [ 'label' => '👥 Team-URL', 'plugin' => '', 'active' => true ],
'link_discord' => [ 'label' => '💬 Discord-Einladung', 'plugin' => '', 'active' => true ],
'litebans_dashboard_url' => [ 'label' => '🔨 LiteBans Dashboard-URL', 'plugin' => 'LiteBans Manager', 'active' => class_exists( 'WP_LiteBans_Pro' ) ],
];
?>
<style>
.mm-url-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.mm-url-row input.large-text { flex: 1; min-width: 200px; }
.mm-suggest-btn {
background: #e8f5e9; color: #2e7d32; border: 1px solid #a5d6a7;
border-radius: 4px; padding: 5px 10px; font-size: 12px;
cursor: pointer; white-space: nowrap; line-height: 1.4;
transition: background .2s;
}
.mm-suggest-btn:hover { background: #c8e6c9; }
.mm-suggest-url { font-size: 11px; color: #666; max-width: 260px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
display: inline-block; vertical-align: middle; }
.mm-autofill-all {
margin-bottom: 12px; background: #0073aa; color: #fff;
border: none; border-radius: 4px; padding: 7px 16px;
cursor: pointer; font-size: 13px;
}
.mm-autofill-all:hover { background: #005f8d; }
</style>
<?php
$has_any_suggestion = ! empty( array_filter( $autodetect ) );
if ( $has_any_suggestion ) : ?>
<button type="button" class="mm-autofill-all" id="mm-autofill-all">
⚡ Alle erkannten URLs automatisch übernehmen
</button>
<?php endif; ?>
<table class="form-table">
<?php foreach ( $links as $key => $cfg ) :
$badge = '';
if ( $cfg['plugin'] ) {
$cls = $cfg['active'] ? 'badge' : 'badge inactive';
$txt = $cfg['active'] ? 'aktiv' : 'inaktiv';
$badge = '<span class="' . $cls . '">' . esc_html( $cfg['plugin'] ) . ' ' . $txt . '</span>';
}
$saved = $data[ $key ] ?? '';
$suggested = $autodetect[ $key ] ?? '';
$show_suggest = $suggested && $suggested !== $saved;
?>
<tr>
<th><label for="mm_link_<?php echo esc_attr( $key ); ?>"><?php echo $cfg['label'] . $badge; ?></label></th>
<td>
<div class="mm-url-row">
<input type="url"
id="mm_link_<?php echo esc_attr( $key ); ?>"
name="mm_bot_data[<?php echo esc_attr( $key ); ?>]"
value="<?php echo esc_url( $saved ); ?>"
class="large-text"
data-key="<?php echo esc_attr( $key ); ?>">
<?php if ( $show_suggest ) : ?>
<button type="button"
class="mm-suggest-btn"
data-target="mm_link_<?php echo esc_attr( $key ); ?>"
data-url="<?php echo esc_url( $suggested ); ?>">
✓ Vorschlag übernehmen
</button>
<span class="mm-suggest-url" title="<?php echo esc_attr( $suggested ); ?>">
<?php echo esc_html( $suggested ); ?>
</span>
<?php elseif ( $saved && $suggested && $suggested === $saved ) : ?>
<span style="color:#2e7d32;font-size:12px;">✔ Erkannt &amp; gesetzt</span>
<?php endif; ?>
</div>
</td>
</tr>
<?php endforeach; ?>
</table>
</div>
<!-- KARTE 4: Individuelle Q&A -->
<div class="bot-card">
<h2>4. Individuelle Q&A</h2>
<p class="description">
Schlüsselwörter (kommagetrennt) → Antwort. Hat höchste Priorität vor allen Plugin-Abfragen.
</p>
<table class="form-table" style="width:100%;">
<tr>
<th style="width:200px;">Schlüsselwörter</th>
<th>Antwort (HTML erlaubt)</th>
<th style="width:50px;"></th>
</tr>
</table>
<div id="mm-qa-rows">
<?php
$qa = $data['qa'] ?? [];
foreach ( $qa as $i => $item ) :
if ( empty( $item['keys'] ) ) continue;
?>
<div class="qa-item" style="display:flex;gap:10px;margin-bottom:10px;align-items:center;">
<input type="text" name="mm_bot_data[qa][<?php echo $i; ?>][keys]"
value="<?php echo esc_attr( $item['keys'] ); ?>"
style="flex:1;" placeholder="discord, invite, join discord">
<input type="text" name="mm_bot_data[qa][<?php echo $i; ?>][val]"
value="<?php echo esc_attr( $item['val'] ); ?>"
style="flex:2;" placeholder="Antworttext oder HTML">
<button type="button" class="button remove-qa" title="Entfernen">✕</button>
</div>
<?php endforeach; ?>
</div>
<button type="button" id="add-qa" class="button button-primary">+ Neue Q&amp;A-Zeile</button>
</div>
<?php submit_button( 'Einstellungen speichern' ); ?>
</form>
</div>
<script>
jQuery(function($){
// Q&A Zeilen
$('#add-qa').on('click', function(){
var i = Date.now();
$('#mm-qa-rows').append(
'<div class="qa-item" style="display:flex;gap:10px;margin-bottom:10px;align-items:center;">' +
'<input type="text" name="mm_bot_data[qa]['+i+'][keys]" style="flex:1;" placeholder="discord, invite">' +
'<input type="text" name="mm_bot_data[qa]['+i+'][val]" style="flex:2;" placeholder="Antwort...">' +
'<button type="button" class="button remove-qa" title="Entfernen">✕</button>' +
'</div>'
);
});
$(document).on('click', '.remove-qa', function(){
$(this).closest('.qa-item').remove();
});
// Einzelnen Vorschlag übernehmen
$(document).on('click', '.mm-suggest-btn', function(){
var $btn = $(this);
var target = $btn.data('target');
var url = $btn.data('url');
$('#' + target).val(url);
$btn.replaceWith('<span style="color:#2e7d32;font-size:12px;">✔ Übernommen</span>');
$(this).siblings('.mm-suggest-url').remove();
});
// Alle auf einmal übernehmen
$('#mm-autofill-all').on('click', function(){
$('.mm-suggest-btn').each(function(){
var $btn = $(this);
var target = $btn.data('target');
var url = $btn.data('url');
if ( url && ! $('#' + target).val() ) {
$('#' + target).val(url);
$btn.closest('.mm-url-row').find('.mm-suggest-url').remove();
$btn.replaceWith('<span style="color:#2e7d32;font-size:12px;">✔ Übernommen</span>');
}
});
$(this).prop('disabled', true).text('✔ Fertig bitte speichern');
});
});
</script>
<?php
}
// =========================================================================
// 3. ASSETS LADEN
// =========================================================================
add_action( 'wp_enqueue_scripts', function () {
// CSS aus Theme-Ordner (falls vorhanden), sonst Inline-Fallback
$css_file = get_template_directory() . '/css/assistant-widget.css';
if ( file_exists( $css_file ) ) {
wp_enqueue_style(
'mm-assistant-widget',
get_template_directory_uri() . '/css/assistant-widget.css',
[],
'3.1'
);
}
} );
// =========================================================================
// 4. FRONTEND WIDGET
// =========================================================================
add_action( 'wp_footer', 'mm_bot_render_widget', 50 );
function mm_bot_render_widget() {
// Sichtbarkeit prüfen: Assistent nur anzeigen, wenn im Customizer aktiviert
// BUG-FIX: Early return MUSS als erstes kommen, bevor andere Variablen gelesen werden.
if ( ! get_theme_mod( 'assistant_enabled', false ) ) {
return;
}
$data = get_option( 'mm_bot_data', [] );
$uuid = sanitize_text_field( trim( get_theme_mod( 'assistant_minecraft_uuid', 'Steve' ) ) );
// BUG-FIX: $avatar_view muss VOR $body_offset definiert werden.
$avatar_view = get_theme_mod( 'assistant_avatar_view', 'head' );
// Offset für Chat-Fenster, wenn Ganzkörper-Avatar aktiv ist
$body_offset = ( $avatar_view === 'body' ) ? 'margin-right: 60px;' : '';
$name = ! empty( $data['bot_name'] ) ? esc_html( $data['bot_name'] ) : 'Viper-Bot';
$welcome = ! empty( $data['welcome'] ) ? $data['welcome'] : 'Hallo! Wie kann ich dir helfen? 👋';
$nonce = wp_create_nonce( 'mm_bot_nonce' );
$ajax = admin_url( 'admin-ajax.php' );
// ── Quick-Buttons: nur anzeigen wenn Plugin aktiv + URL gesetzt ──────
$quick = [];
// Server-Status (immer wenn IP konfiguriert oder BungeeCord-Plugin aktiv)
$servers = get_option( 'mcss_servers', [] );
if ( ! empty( $data['server_ip'] ) || ! empty( $servers ) ) {
$quick[] = [ 'label' => '🖥️ 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' ];
}
?>
<?php
$assistant_position = get_theme_mod( 'assistant_position', 'bottom_right' );
$pos_class = 'mm-bot-pos-' . esc_attr( $assistant_position );
?>
<div id="mm-bot-root" class="<?php echo $pos_class; ?>">
<!-- Chat-Fenster -->
<div id="mm-bot-chat" style="display:none;<?php echo $body_offset; ?>" aria-label="Assistent" role="dialog">
<!-- Header -->
<div class="mm-bot-header">
<div class="mm-bot-status" title="Online"></div>
<?php
// Avatar-URL je nach Ansicht
if ($avatar_view === 'body') {
$avatar_url = 'https://mc-heads.net/body/' . rawurlencode($uuid) . '/32';
} elseif ($avatar_view === '3dhead') {
$avatar_url = 'https://visage.surgeplay.com/head/48/' . rawurlencode($uuid);
} else {
$avatar_url = 'https://mc-heads.net/avatar/' . rawurlencode($uuid) . '/32';
}
?>
<img class="mm-bot-avatar-small" src="<?php echo esc_url($avatar_url); ?>" alt="<?php echo $name; ?>">
<span class="mm-bot-title"><?php echo $name; ?></span>
<button id="mm-bot-close" aria-label="Schließen">&times;</button>
</div>
<!-- Nachrichten -->
<div id="mm-bot-content" role="log" aria-live="polite">
<div class="mm-msg bot">
<?php echo nl2br( wp_kses_post( $welcome ) ); ?>
</div>
<?php if ( ! empty( $quick ) ) : ?>
<div class="mm-bot-quick">
<?php foreach ( $quick as $btn ) : ?>
<button class="mm-quick-btn"
data-q="<?php echo esc_attr( $btn['q'] ); ?>"
type="button">
<?php echo esc_html( $btn['label'] ); ?>
</button>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<!-- Eingabe -->
<div class="mm-bot-input-area">
<input type="text"
id="mm-bot-field"
placeholder="Deine Frage eingeben…"
autocomplete="off"
maxlength="300"
aria-label="Nachricht eingeben">
<button id="mm-bot-send" type="button" aria-label="Senden">➤</button>
</div>
</div>
<!-- Launcher-Button -->
<button id="mm-bot-launcher" type="button" aria-label="Assistenten öffnen" title="<?php echo $name; ?>" style="background:transparent;border:none;box-shadow:none;width:auto;height:auto;padding:0;display:flex;align-items:center;justify-content:center;overflow:visible;">
<?php
// Launcher-Avatar-URL je nach Ansicht (größer)
if ($avatar_view === 'body') {
$launcher_url = 'https://mc-heads.net/body/' . rawurlencode($uuid) . '/144';
$img_style = 'width:72px;height:144px;object-fit:contain;';
if ($assistant_position === 'bottom_right' || $assistant_position === 'top_right') {
$img_style .= 'transform:scaleX(-1);';
}
} elseif ($avatar_view === '3dhead') {
$launcher_url = 'https://visage.surgeplay.com/head/80/' . rawurlencode($uuid);
$img_style = 'width:60px;height:60px;object-fit:cover;';
if ($assistant_position === 'bottom_left' || $assistant_position === 'top_left') {
$img_style .= 'transform:scaleX(-1);';
}
} else {
$launcher_url = 'https://mc-heads.net/avatar/' . rawurlencode($uuid) . '/60';
$img_style = 'width:60px;height:60px;object-fit:cover;';
}
?>
<img src="<?php echo esc_url($launcher_url); ?>" alt="<?php echo $name; ?>" style="<?php echo $img_style; ?>border-radius:8px;background:none;box-shadow:none;">
</button>
</div>
<script>
(function($){
'use strict';
var $chat = $('#mm-bot-chat');
var $field = $('#mm-bot-field');
var $content = $('#mm-bot-content');
var nonce = <?php echo wp_json_encode( $nonce ); ?>;
var ajaxUrl = <?php echo wp_json_encode( $ajax ); ?>;
var isLoading = false;
// ── Öffnen / Schließen ────────────────────────────────────
$('#mm-bot-launcher').on('click', function(){
$chat.fadeToggle(200);
if ($chat.is(':visible')) {
$field.trigger('focus');
scrollBottom();
}
});
$('#mm-bot-close').on('click', function(){
$chat.fadeOut(200);
});
// ── Quick-Buttons ─────────────────────────────────────────
$(document).on('click', '.mm-quick-btn', function(){
sendMessage( $(this).data('q') );
});
// ── Senden ────────────────────────────────────────────────
$('#mm-bot-send').on('click', function(){ sendMessage(); });
$field.on('keydown', function(e){
if (e.which === 13 && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
function sendMessage(forceText) {
if (isLoading) return;
var val = forceText !== undefined
? String(forceText).trim()
: $field.val().trim();
if (!val) return;
// Nutzernachricht anzeigen
appendMsg('user', $('<span>').text(val).html());
if (forceText === undefined) $field.val('');
// Loader
isLoading = true;
var $loader = $('<div class="mm-msg bot mm-loading" aria-label="Lädt">···</div>');
$content.append($loader);
scrollBottom();
$.ajax({
url: ajaxUrl,
method: 'POST',
dataType: 'json',
data: {
action: 'mm_assistant_query', // ← Neuer Action-Name
q: val,
nonce: nonce
},
success: function(res){
$loader.remove();
isLoading = false;
var text;
if (res && res.success && res.data && res.data.reply) {
// Neues Format: {reply: '...', parts: [...]}
text = res.data.reply;
} else if (res && res.success && typeof res.data === 'string') {
// Altes Format: direkter String (Fallback)
text = res.data;
} else {
text = '⚠️ Keine Antwort erhalten.';
}
appendMsg('bot', text);
},
error: function(){
$loader.remove();
isLoading = false;
appendMsg('bot', '⚠️ Verbindungsfehler. Bitte versuche es erneut.');
}
});
}
function appendMsg(type, html) {
var $msg = $('<div class="mm-msg ' + type + '">').html(html);
$content.append($msg);
scrollBottom();
}
function scrollBottom() {
$content.scrollTop($content[0].scrollHeight);
}
})(jQuery);
</script>
<style>
/* ── Wrapper ── */
#mm-bot-root {
position: fixed;
z-index: 999999;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
/* Positionsklassen */
#mm-bot-root.mm-bot-pos-bottom_right { bottom: 30px; right: 100px; }
#mm-bot-root.mm-bot-pos-bottom_left { bottom: 90px; left: 30px; }
#mm-bot-root.mm-bot-pos-top_right { top: 30px; right: 30px; }
#mm-bot-root.mm-bot-pos-top_left { top: 30px; left: 30px; }
/* Chat-Fenster dynamisch positionieren */
#mm-bot-root.mm-bot-pos-bottom_right #mm-bot-chat { bottom: 78px; right: 0; left: auto; top: auto; }
#mm-bot-root.mm-bot-pos-bottom_left #mm-bot-chat { bottom: 78px; left: 0; right: auto; top: auto; }
#mm-bot-root.mm-bot-pos-top_right #mm-bot-chat { top: 78px; right: 0; left: auto; bottom: auto; }
#mm-bot-root.mm-bot-pos-top_left #mm-bot-chat { top: 78px; left: 0; right: auto; bottom: auto; }
/* ── Launcher ── */
#mm-bot-launcher {
background: transparent !important;
border: none !important;
box-shadow: none !important;
width: auto !important;
height: auto !important;
padding: 0 !important;
display: flex;
align-items: center;
justify-content: center;
overflow: visible;
border-radius: 0 !important;
cursor: pointer;
transition: none;
}
#mm-bot-launcher img {
width: 60px;
height: 60px;
border-radius: 8px;
background: none !important;
box-shadow: none !important;
}
/* ── Chat-Fenster ── */
#mm-bot-chat {
position: absolute;
bottom: 78px;
right: 0;
width: 350px;
background: #1e2124;
border-radius: 16px;
box-shadow: 0 16px 48px rgba(0,0,0,.55);
display: flex;
flex-direction: column;
overflow: hidden;
border: 1px solid #2a2d31;
}
/* ── Header ── */
.mm-bot-header {
background: #2f3136;
color: #fff;
padding: 12px 16px;
display: flex;
align-items: center;
gap: 10px;
border-bottom: 1px solid #1a1a1a;
}
.mm-bot-status {
width: 10px;
height: 10px;
background: #43b581;
border-radius: 50%;
box-shadow: 0 0 8px #43b581;
flex-shrink: 0;
}
.mm-bot-avatar-small {
width: 28px;
height: 28px;
border-radius: 4px;
}
.mm-bot-title {
font-weight: 700;
font-size: 15px;
flex: 1;
}
#mm-bot-close {
background: none;
border: none;
color: #888;
font-size: 22px;
cursor: pointer;
line-height: 1;
padding: 0 2px;
transition: color .2s;
}
#mm-bot-close:hover { color: #fff; }
/* ── Nachrichten ── */
#mm-bot-content {
height: 340px;
padding: 14px 14px 6px;
overflow-y: auto;
background: #36393f;
display: flex;
flex-direction: column;
gap: 10px;
scroll-behavior: smooth;
}
.mm-msg {
padding: 10px 14px;
border-radius: 14px;
font-size: 13.5px;
line-height: 1.55;
max-width: 90%;
word-break: break-word;
}
.mm-msg.bot {
background: #40444b;
color: #dcddde;
align-self: flex-start;
border-bottom-left-radius: 4px;
}
.mm-msg.user {
background: #0099ff;
color: #fff;
align-self: flex-end;
border-bottom-right-radius: 4px;
}
.mm-msg a {
color: #5bc0eb;
text-decoration: none;
font-weight: 600;
}
.mm-msg a:hover { text-decoration: underline; }
.mm-msg code {
background: #1a1a1a;
color: #ffa500;
padding: 2px 6px;
border-radius: 4px;
font-family: monospace;
font-size: 12.5px;
}
.mm-msg hr {
border: 0;
border-top: 1px solid rgba(255,255,255,.12);
margin: 8px 0;
}
.mm-msg img {
max-width: 100%;
border-radius: 6px;
margin-top: 6px;
display: block;
}
.mm-msg small { opacity: .75; font-size: 12px; }
.mm-msg b { color: #fff; }
.mm-msg.bot b { color: #e3e4e6; }
/* TinyMCE Regelwerk-Inhalt im Chat */
.mm-msg p { margin: 4px 0; }
.mm-msg ul, .mm-msg ol {
margin: 4px 0 4px 16px;
padding: 0;
}
.mm-msg li { margin-bottom: 2px; list-style: disc; }
.mm-msg ol li { list-style: decimal; }
.mm-msg strong, .mm-msg b { font-weight: 700; }
.mm-msg em { font-style: italic; }
.mm-msg h1, .mm-msg h2, .mm-msg h3,
.mm-msg h4, .mm-msg h5, .mm-msg h6 {
margin: 6px 0 4px;
font-size: 14px;
color: #e3e4e6;
}
.mm-loading {
opacity: .55;
font-size: 22px;
letter-spacing: 5px;
padding: 6px 14px;
}
/* ── Quick-Buttons ── */
.mm-bot-quick {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 2px;
}
.mm-quick-btn {
background: #2f3136;
color: #b9bbbe;
border: 1px solid #3f4147;
border-radius: 20px;
padding: 5px 12px;
font-size: 12px;
cursor: pointer;
transition: background .2s, color .2s, border-color .2s;
white-space: nowrap;
}
.mm-quick-btn:hover {
background: #0099ff;
color: #fff;
border-color: #0099ff;
}
/* ── Eingabe ── */
.mm-bot-input-area {
padding: 10px 12px;
background: #2f3136;
display: flex;
gap: 8px;
border-top: 1px solid #1a1a1a;
}
#mm-bot-field {
flex: 1;
background: #40444b;
border: 1px solid #1a1a1a;
border-radius: 8px;
color: #fff;
padding: 9px 12px;
outline: none;
font-size: 13.5px;
transition: border-color .2s;
}
#mm-bot-field::placeholder { color: #72767d; }
#mm-bot-field:focus { border-color: #0099ff; }
#mm-bot-send {
background: #0099ff;
border: none;
color: #fff;
border-radius: 8px;
padding: 0 16px;
cursor: pointer;
font-size: 16px;
transition: background .2s;
flex-shrink: 0;
}
#mm-bot-send:hover { background: #00b0f4; }
/* ── Responsive ── */
@media (max-width: 420px) {
#mm-bot-root { bottom: 16px; right: 12px; }
#mm-bot-chat { width: calc(100vw - 24px); right: -12px; }
}
</style>
<?php
}