diff --git a/wp-litebans-manager.php b/wp-litebans-manager.php
index f9428d5..6a689aa 100644
--- a/wp-litebans-manager.php
+++ b/wp-litebans-manager.php
@@ -1,998 +1,1006 @@
-post_type ) && $screen->post_type === 'unban_request' ) {
- $load = true;
- }
- }
-
- if ( $load ) {
- wp_enqueue_style( 'litebans-pro-admin', plugins_url( 'css/admin.css', __FILE__ ), array(), '6.4.7' );
- wp_enqueue_style( 'litebans-pro-frontend-css', plugins_url( 'css/style.css', __FILE__ ), array(), '6.4.7' );
- }
- }
-
- /**
- * Inject CSS/JS to visually mark locked rows in the CPT list (edit.php?post_type=unban_request)
- * We collect locked post IDs server-side and output a small script that adds a CSS class and badge.
- */
- public function inject_locked_row_styles() {
- if ( ! is_admin() ) return;
- if ( ! function_exists( 'get_current_screen' ) ) return;
-
- $screen = get_current_screen();
- if ( ! $screen ) return;
- if ( $screen->id !== 'edit-unban_request' ) return;
-
- // Query for locked posts (status or admin note locked)
- $locked_posts = get_posts(array(
- 'post_type' => 'unban_request',
- 'posts_per_page' => -1,
- 'fields' => 'ids',
- 'meta_query' => array(
- 'relation' => 'OR',
- array(
- 'key' => '_lb_status_locked',
- 'value' => '1',
- 'compare' => '='
- ),
- array(
- 'key' => '_lb_admin_note_locked',
- 'value' => '1',
- 'compare' => '='
- )
- )
- ));
-
- if ( empty( $locked_posts ) ) return;
-
- // Prepare JSON array for JS
- $ids_json = wp_json_encode( array_map( 'intval', $locked_posts ) );
-
- // Output inline CSS + JS
- echo '';
-
- echo '';
- }
-
- public function hide_default_editor() {
- global $post;
- if ( $post && $post->post_type === 'unban_request' ) {
- echo '';
- }
- }
-
- // --- 1. CPT SYSTEM ---
- public function register_cpt_unban_request() {
- $labels = array(
- 'name' => 'Entbannungsanträge',
- 'singular_name' => 'Entbannungsantrag',
- 'menu_name' => 'Entbannungen',
- 'add_new' => 'Neu erstellen',
- 'edit_item' => 'Antrag bearbeiten',
- );
- $args = array(
- 'labels' => $labels,
- 'public' => false,
- 'show_ui' => true,
- 'show_in_menu' => 'litebans-manager',
- 'capability_type' => 'post',
- 'supports' => array(''),
- 'menu_icon' => 'dashicons-forms',
- );
- register_post_type( 'unban_request', $args );
- }
-
- public function set_unban_columns($columns) {
- if ( isset($columns['title']) ) unset($columns['title']);
- if ( isset($columns['date']) ) unset($columns['date']);
- $columns['player'] = 'Spieler';
- $columns['status'] = 'Status';
- $columns['date'] = 'Datum';
- return $columns;
- }
-
- public function fill_unban_columns($column, $post_id) {
- if ($column == 'player') {
- echo esc_html(get_post_meta($post_id, '_lb_player', true));
- }
- if ($column == 'status') {
- $s = get_post_meta($post_id, '_lb_status', true);
- $label = $s === 'approved' ? 'Angenommen' : ($s === 'rejected' ? 'Abgelehnt' : 'Wartend');
- echo ''.esc_html($label).' ';
- }
- }
-
- public function add_unban_meta_box() {
- // Primary ticket box
- add_meta_box(
- 'lb_unban_ticket', 'Unban Ticket Verwaltung',
- array( $this, 'render_unban_meta_box' ),
- 'unban_request', 'normal', 'high'
- );
-
- // Admin Note sidebox
- add_meta_box(
- 'lb_admin_note_box', 'Admin Notiz',
- array( $this, 'render_admin_note_box' ),
- 'unban_request', 'side', 'high'
- );
- }
-
- public function render_unban_meta_box( $post ) {
- wp_nonce_field( 'lb_unban_save', 'lb_unban_nonce' );
- $player = get_post_meta( $post->ID, '_lb_player', true );
- $reason = get_post_meta( $post->ID, '_lb_reason', true );
- $message = $post->post_content;
- $status = get_post_meta( $post->ID, '_lb_status', true );
- if ( empty($status) ) $status = 'pending';
- $status_locked = get_post_meta( $post->ID, '_lb_status_locked', true );
- $admin_name = get_post_meta( $post->ID, '_lb_admin_name', true );
-
- ?>
-
- ID, '_lb_admin_note', true );
- $admin = get_post_meta( $post->ID, '_lb_admin_name', true );
- $locked = get_post_meta( $post->ID, '_lb_admin_note_locked', true );
-
- echo '';
- if ( $locked ) {
- echo '
Gesperrt von: ' . esc_html( $admin ) . '
';
- echo '
';
- echo nl2br( esc_html( $note ) );
- echo '
';
- echo '
Diese Notiz wurde gesperrt und kann nicht mehr verändert werden.
';
- } else {
- echo '
Admin Notiz (wird beim Annehmen/Ablehnen gesperrt)
';
- echo '
';
- echo '
Bitte begründe kurz deine Entscheidung. Nach dem Speichern bei Annahme/Ablehnung wird diese Notiz dauerhaft gesperrt.
';
- }
- echo '
';
- }
-
- /**
- * save_unban_meta_box
- * - speichert Meta
- * - sperrt Status und Admin-Notiz bei finaler Entscheidung (approved/rejected)
- * - verhindert nachträgliche Änderungen am Status/Notiz, wenn gesperrt
- */
- public function save_unban_meta_box( $post_id, $post ) {
- // Nonce + capability checks
- if ( ! isset( $_POST['lb_unban_nonce'] ) || ! wp_verify_nonce( $_POST['lb_unban_nonce'], 'lb_unban_save' ) ) return;
- if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
- if ( ! current_user_can( 'edit_post', $post_id ) ) return;
-
- // Existing flags
- $old_status = get_post_meta( $post_id, '_lb_status', true );
- $status_locked = get_post_meta( $post_id, '_lb_status_locked', true );
- $note_locked = get_post_meta( $post_id, '_lb_admin_note_locked', true );
-
- // Incoming sanitized values
- $incoming_status = isset( $_POST['lb_status'] ) ? sanitize_text_field( $_POST['lb_status'] ) : $old_status;
- $incoming_note = isset( $_POST['lb_admin_note'] ) ? sanitize_textarea_field( wp_kses_post( $_POST['lb_admin_note'] ) ) : '';
-
- $current_user = wp_get_current_user();
- $timestamp = current_time( 'd.m.Y H:i' );
-
- // ---- STATUS HANDLING ----
- // If status is already locked, deny changing it.
- if ( ! empty( $status_locked ) ) {
- // keep old status; ignore incoming value
- $status_to_store = $old_status;
- } else {
- // Accept incoming status and if it's final, lock it.
- $status_to_store = $incoming_status;
- if ( in_array( $status_to_store, array( 'approved', 'rejected' ), true ) ) {
- update_post_meta( $post_id, '_lb_status_locked', 1 );
- }
- }
-
- // Always store the status meta (either unchanged or new allowed value)
- update_post_meta( $post_id, '_lb_status', $status_to_store );
-
- // ---- ADMIN NOTE HANDLING ----
- // If note already locked, do not overwrite.
- if ( ! empty( $note_locked ) ) {
- // do nothing for admin note
- } else {
- // If note is not locked yet:
- if ( in_array( $status_to_store, array( 'approved', 'rejected' ), true ) ) {
- // Final status: write note + admin name + lock (even if note is empty)
- $admin_label = ( $current_user->display_name ? $current_user->display_name : $current_user->user_login ) . ' · ' . $timestamp;
- update_post_meta( $post_id, '_lb_admin_note', $incoming_note );
- update_post_meta( $post_id, '_lb_admin_name', $admin_label );
- update_post_meta( $post_id, '_lb_admin_note_locked', 1 );
- } else {
- // Non-final: save incoming note (editable)
- if ( isset( $_POST['lb_admin_note'] ) ) {
- update_post_meta( $post_id, '_lb_admin_note', $incoming_note );
- }
- }
- }
-
- // ---- ACTION: wenn gerade auf approved gesetzt (und war nicht approved vorher) -> unban ingame ----
- if ( $old_status !== 'approved' && $status_to_store === 'approved' ) {
- $player = get_post_meta( $post_id, '_lb_player', true );
- if ( $player ) {
- $lbdb = $this->get_litebans_db();
- if ( is_wp_error( $lbdb ) ) {
- add_settings_error( 'lb', 'db_error', 'LiteBans DB nicht konfiguriert: Unban nicht ausgeführt.', 'error' );
- } else {
- $res = $this->unban_by_player( $lbdb, $player, $current_user );
- if ( $res['updated'] > 0 ) {
- add_settings_error( 'lb', 'unban_ok', sprintf( '%d Eintrag(e) für %s wurden ingame aufgehoben.', $res['updated'], esc_html($player) ), 'updated' );
- } else {
- add_settings_error( 'lb', 'unban_none', 'Keine aktive Strafe in LiteBans gefunden für ' . esc_html($player) . '.', 'notice' );
- }
- }
- }
- }
-
- // If status changed to rejected and was not rejected previously, add a notice
- if ( $old_status !== 'rejected' && $status_to_store === 'rejected' ) {
- add_settings_error( 'lb', 'rejected', 'Antrag abgelehnt. Notiz gesperrt.', 'updated' );
- }
- }
-
- // --- 2. ADMIN MENÜ ---
- public function add_admin_menu() {
- add_menu_page(
- 'LiteBans Manager',
- 'LiteBans Manager',
- 'manage_options',
- 'litebans-manager',
- array( $this, 'render_admin_dashboard' ),
- 'dashicons-dismiss',
- 30
- );
- add_submenu_page( 'litebans-manager', 'Einstellungen', 'Einstellungen', 'manage_options', 'litebans-settings', array( $this, 'render_settings_page' ) );
- }
-
- public function register_settings() {
- register_setting( $this->option_name, $this->option_name );
- }
-
- public function handle_admin_actions() {
- // Actions handled in dashboard
- }
-
- public function render_settings_page() {
- if ( isset( $_POST['save_settings'] ) && check_admin_referer( 'lb_save_settings' ) ) {
- update_option( $this->option_name, $_POST['lb_settings'] );
- echo 'Einstellungen gespeichert!
';
- }
-
- $settings = get_option( $this->option_name );
- $fields = array(
- 'db_host' => array('label'=>'Host', 'type'=>'text', 'default'=>'localhost'),
- 'db_name' => array('label'=>'Datenbank Name', 'type'=>'text', 'default'=>'litebans'),
- 'db_user' => array('label'=>'User', 'type'=>'text'),
- 'db_pass' => array('label'=>'Passwort', 'type'=>'password'),
- 'table_prefix' => array('label'=>'Prefix', 'type'=>'text', 'default'=>'litebans_'),
- 'theme_mode' => array('label'=>'Frontend Theme', 'type'=>'select', 'default'=>'light', 'options'=>['light'=>'Light Mode', 'dark'=>'Dark Mode'])
- );
- ?>
-
-
LiteBans Einstellungen
-
-
- db) return $this->db;
- $s = get_option( $this->option_name );
- if ( empty( $s['db_name'] ) ) return new WP_Error( 'no_config', 'LiteBans nicht konfiguriert.' );
- $this->db = new wpdb( $s['db_user'], $s['db_pass'], $s['db_name'], $s['db_host'] );
- if ( $this->db->last_error ) return new WP_Error( 'db_error', 'DB Fehler: ' . $this->db->last_error );
- $this->db->prefix = isset($s['table_prefix']) ? $s['table_prefix'] : 'litebans_';
- return $this->db;
- }
-
- private function get_avatar($name) {
- return " ";
- }
-
- private function clean($t) {
- if(!$t) return "-";
- $t = preg_replace("/(?i)(\x{00a7}|&)[0-9A-FK-OR]/u", "", $t);
- return esc_html($t);
- }
-
- private function millis_to_date($m) { return $m ? date("d.m.Y H:i", $m/1000) : "-"; }
-
- // KORRIGIERTE BADGE LOGIK
- private function get_badge($r, $type) {
- $now = (int) ( microtime(true) * 1000 );
-
- // entfernte Einträge (aufgehoben)
- if (!empty($r->removed_by_name) && $r->removed_by_name !== "#expired") {
- return "Aufgehoben ";
- }
-
- // Warnings & Kicks - keine Ablauf/Perm-Logik nötig
- if ($type === 'warnings') {
- return "Verwarnt ";
- }
- if ($type === 'kicks') {
- return "Gekickt ";
- }
-
- // Bans / Mutes: prüfen Ablauf
- if (!empty($r->until) && (int)$r->until > 0 && $now > (int)$r->until) {
- return "Abgelaufen ";
- }
-
- if ( empty($r->until) || (int)$r->until <= 0 ) {
- $label = ($type === 'mutes') ? "Permanent Mute" : "Permanent Ban";
- return "".esc_html($label)." ";
- }
-
- // aktiv
- $label = ($type === 'mutes') ? "Gemutet" : "Gebannt";
- $class = ($type === 'mutes') ? "muted" : "active";
- return "".esc_html($label)." ";
- }
-
- private function get_theme_script($default_theme) {
- ob_start();
- ?>
-
- 'Unban: ' . sanitize_text_field($_POST['lb_player']),
- 'post_content' => sanitize_textarea_field($_POST['lb_message']),
- 'post_status' => 'pending',
- 'post_type' => 'unban_request',
- );
- $post_id = wp_insert_post( $post_data );
- if( $post_id ) {
- update_post_meta( $post_id, '_lb_player', sanitize_text_field($_POST['lb_player']) );
- update_post_meta( $post_id, '_lb_reason', sanitize_text_field($_POST['lb_reason']) );
- update_post_meta( $post_id, '_lb_status', 'pending' );
- $msg = 'Antrag erfolgreich eingereicht!
';
- $player = ''; $reason = '';
- }
- }
-
- ob_start();
- ?>
-
- option_name );
- $default_theme = $settings['theme_mode'] ?? 'light';
-
- if ( isset($_GET['lb_player']) ) {
- $player = sanitize_text_field($_GET['lb_player']);
- $reason = isset($_GET['lb_reason']) ? sanitize_textarea_field($_GET['lb_reason']) : '';
- $content = $this->render_unban_logic($player, $reason);
- $content .= $this->get_theme_script($default_theme);
- return $content;
- }
-
- $lbdb = $this->get_litebans_db();
- if(is_wp_error($lbdb)) return 'Datenbank Fehler: Bitte Einstellungen überprüfen.
';
-
- $current_url = get_permalink();
-
- // robustes render_tab: COALESCE für optionale Felder, stellt sicher dass kicks/warnings sichtbar sind
- $render_tab = function($t) use($lbdb, $current_url) {
- $table = esc_sql($lbdb->prefix . $t);
- $limit = 20;
-
- // FIX: Kicks haben keine removed_by_name Spalte in der DB
- $select_removed = ($t === 'kicks') ? "''" : "COALESCE(l.removed_by_name, '')";
-
- $q = $lbdb->prepare(
- "SELECT l.id, l.uuid, l.reason, l.banned_by_name, l.time,
- COALESCE(l.until, 0) as until,
- COALESCE(l.active, 0) as active,
- " . $select_removed . " as removed_by_name,
- h.name
- FROM {$table} l
- LEFT JOIN {$lbdb->prefix}history h ON l.uuid = h.uuid
- WHERE (l.uuid IS NOT NULL OR h.name IS NOT NULL)
- GROUP BY l.id
- ORDER BY l.time DESC LIMIT %d",
- $limit
- );
- $rows = $lbdb->get_results($q);
- if(!$rows) return "Keine Daten
";
-
- $html = 'Spieler Status Grund Datum Aktion ';
-
- foreach($rows as $r) {
- $playerName = !empty($r->name) ? $r->name : (!empty($r->banned_by_name) ? $r->banned_by_name : '-');
- // active kann 0/1 oder NULL sein -> COALESCE stellt sicher: 1=aktiv
- $is_active = (isset($r->active) && intval($r->active) == 1) && empty($r->removed_by_name);
-
- $html .= '';
- $html .= ''.$this->get_avatar($playerName);
- $html .= ''.esc_html($playerName).'
';
-
- $html .= ''.$this->get_badge($r, $t).' ';
-
- $html .= ''.$this->clean($r->reason).' ';
-
- $html .= ''.$this->millis_to_date($r->time).' ';
-
- // BUTTON LOGIK: nur für bans/mutes und nur wenn aktiv
- $html .= '';
- if ($is_active && ($t === 'bans' || $t === 'mutes')) {
- $unban_link = add_query_arg( array('lb_player' => $playerName, 'lb_reason' => rawurlencode($r->reason)), $current_url );
- $html .= 'Antrag ';
- } else {
- $html .= '- ';
- }
- $html .= ' ';
- $html .= ' ';
- }
- return $html.'
';
- };
-
- ob_start();
- ?>
-
-
-
-
- Bans
- Mutes
- Warnings
- Kicks
-
-
-
-
-
-
-
- get_theme_script($default_theme); ?>
-
- render_unban_logic('', '');
- }
-
- // --- 4. ADMIN BACKEND MIT TABS ---
- public function render_admin_dashboard() {
- // Tabs
- $current_tab = isset($_GET['lb_tab']) ? sanitize_text_field($_GET['lb_tab']) : 'bans';
- $valid_tabs = array('bans', 'mutes', 'warnings', 'kicks');
- if(!in_array($current_tab, $valid_tabs, true)) $current_tab = 'bans';
-
- $lbdb = $this->get_litebans_db();
- if ( is_wp_error( $lbdb ) ) {
- echo '' . esc_html( $lbdb->get_error_message() ) . '
';
- return;
- }
-
- // Actions verarbeiten (Unban/Delete)
- if ( isset( $_POST['lb_action'] ) && isset( $_POST['lb_id'] ) && check_admin_referer( 'lb_admin_action_' . $_POST['lb_id'] ) ) {
- $this->process_admin_action($lbdb, sanitize_text_field($_POST['lb_type']));
- }
-
- settings_errors( 'lb' );
-
- // Pagination
- $search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : '';
- $limit = 20;
- $paged = isset( $_GET['paged'] ) ? max(1, intval($_GET['paged'])) : 1;
- $offset = ( $paged - 1 ) * $limit;
-
- $table = esc_sql($lbdb->prefix . $current_tab);
- $search_sql = $search ? $lbdb->prepare(" AND h.name LIKE %s", "%$search%") : "";
-
- // FIX: Kicks haben keine removed_by_name Spalte in der DB
- $select_removed = ($current_tab === 'kicks') ? "''" : "COALESCE(l.removed_by_name, '')";
-
- // Robust select for admin listing as well
- $query = "SELECT l.id, l.uuid, l.reason, l.banned_by_name, l.time,
- COALESCE(l.until,0) AS until,
- COALESCE(l.active,0) AS active,
- " . $select_removed . " AS removed_by_name,
- h.name
- FROM $table l LEFT JOIN {$lbdb->prefix}history h ON l.uuid = h.uuid
- WHERE (l.uuid IS NOT NULL OR h.name IS NOT NULL) $search_sql GROUP BY l.id ORDER BY l.time DESC LIMIT %d OFFSET %d";
-
- $results = $lbdb->get_results( $lbdb->prepare( $query, $limit, $offset ) );
- $total = $lbdb->get_var("SELECT COUNT(*) FROM $table l WHERE l.uuid IS NOT NULL");
-
- ?>
-
-
LiteBans Manager
-
-
-
-
-
-
-
-
-
- Suchen
-
-
-
-
-
- ID Spieler Grund Von Status Aktion
-
-
- Keine Einträge. '; ?>
- active) && $row->active == 1) && empty($row->removed_by_name);
- }
- ?>
-
- id); ?>
- name ?? $row->banned_by_name); ?>
- clean($row->reason); ?>
- banned_by_name); ?>
-
- Verwarnung';
- } elseif ($current_tab === 'kicks') {
- echo 'Kick ';
- } else {
- echo '';
- echo $active ? 'Aktiv' : 'Inaktiv';
- echo ' ';
- }
- ?>
-
-
-
- id ); ?>
-
-
-
-
- Aufheben
-
-
- Löschen
-
-
-
-
-
-
-
-
-
- max(1, ceil($total/$limit)),
- 'current' => $paged,
- 'base' => add_query_arg('paged', '%#%')
- ));
- ?>
-
-
- prefix . $type);
- $now = (int) ( microtime(true) * 1000 );
-
- // Disallow unban action for warnings/kicks
- if ( ($type === 'warnings' || $type === 'kicks') && $action === 'unban' ) {
- add_settings_error( 'lb', 'invalid_action', 'Diese Sanktion kann nicht aufgehoben werden.', 'error' );
- return;
- }
-
- if ( $action === 'unban' ) {
- // Nur Bans / Mutes
- if ( ! in_array( $type, array('bans','mutes'), true ) ) {
- add_settings_error( 'lb', 'invalid_type', 'Ungültiger Typ für Aufhebung.', 'error' );
- return;
- }
-
- $data = array(
- 'active' => 0,
- 'removed_by_name' => 'WebAdmin: ' . $current_user->display_name,
- 'removed_by_uuid' => 'CONSOLE',
- 'removed_by_date' => $now
- );
-
- $where = array( 'id' => $id );
- $formats = array( '%d', '%s', '%s', '%d' );
- $where_formats = array( '%d' );
-
- $result = $lbdb->update( $table, $data, $where, $formats, $where_formats );
-
- if ( $result !== false ) {
- // additionally, try to update any other rows with same uuid (defensive)
- $uuid = $lbdb->get_var( $lbdb->prepare( "SELECT uuid FROM {$table} WHERE id = %d LIMIT 1", $id ) );
- if ( $uuid ) {
- $lbdb->update( esc_sql($lbdb->prefix . 'bans'), $data, array('uuid' => $uuid, 'active' => 1), $formats, array('%s','%d'));
- $lbdb->update( esc_sql($lbdb->prefix . 'mutes'), $data, array('uuid' => $uuid, 'active' => 1), $formats, array('%s','%d'));
- }
-
- add_settings_error( 'lb', 'success', "Eintrag #$id erfolgreich aufgehoben und ingame entfernt.", 'updated' );
- } else {
- add_settings_error( 'lb', 'dbfail', "Datenbank Update fehlgeschlagen.", 'error' );
- }
- } elseif ( $action === 'delete' ) {
- $result = $lbdb->delete( $table, array( 'id' => $id ), array( '%d' ) );
- if ( $result ) add_settings_error( 'lb', 'success', "Eintrag #$id gelöscht.", 'updated' );
- else add_settings_error( 'lb', 'dbfail', "Löschen fehlgeschlagen.", 'error' );
- }
- }
-
- /**
- * unban_by_player
- * - versucht UUID aus history zu holen und active Bans/Mutes aufzuheben
- * - returns array('updated' => int)
- */
- private function unban_by_player( $lbdb, $player, $current_user ) {
- $updated = 0;
- $now = (int) ( microtime(true) * 1000 );
-
- // find latest uuid from history
- $uuid = $lbdb->get_var( $lbdb->prepare( "SELECT uuid FROM {$lbdb->prefix}history WHERE name = %s ORDER BY id DESC LIMIT 1", $player ) );
-
- if ( ! $uuid ) {
- // Kein Eintrag in history gefunden => nicht zuverlässig aufhebbar
- return array('updated' => 0);
- }
-
- $data = array(
- 'active' => 0,
- 'removed_by_name' => 'WebAdmin: ' . $current_user->display_name,
- 'removed_by_uuid' => 'CONSOLE',
- 'removed_by_date' => $now
- );
- $formats = array('%d','%s','%s','%d');
-
- foreach ( array('bans','mutes') as $t ) {
- $table = esc_sql( $lbdb->prefix . $t );
- // Update only active entries with this uuid
- $where = array( 'uuid' => $uuid, 'active' => 1 );
- $where_formats = array('%s','%d');
-
- $res = $lbdb->update( $table, $data, $where, $formats, $where_formats );
- if ( $res !== false ) {
- $updated += (int) $res;
- }
- }
-
- return array('updated' => $updated);
- }
-
- /**
- * Inject tabs into the CPT listing screen (edit.php?post_type=unban_request)
- * This displays the same tabs as the plugin dashboard and links to the plugin page.
- */
- public function inject_tabs_into_unban_cpt() {
- if ( ! is_admin() ) return;
- if ( ! function_exists( 'get_current_screen' ) ) return;
-
- $screen = get_current_screen();
- if ( ! $screen ) return;
-
- // Only show on the CPT list screen for unban_request
- if ( $screen->id !== 'edit-unban_request' ) return;
-
- $valid_tabs = array( 'bans', 'mutes', 'warnings', 'kicks' );
- $current = isset( $_GET['lb_tab'] ) ? sanitize_text_field( $_GET['lb_tab'] ) : 'bans';
- if ( ! in_array( $current, $valid_tabs, true ) ) $current = 'bans';
-
- echo '';
- echo '
';
-
- foreach ( $valid_tabs as $t ) {
- $active = $current === $t ? 'active' : '';
- $url = add_query_arg( array( 'page' => 'litebans-manager', 'lb_tab' => $t ), admin_url( 'admin.php' ) );
- echo '' . esc_html( ucfirst( $t ) ) . ' ';
- }
-
- echo ' ';
- echo '
';
- }
-
- public function filter_unban_cpt_by_tab( $query ) {
- if ( ! is_admin() || ! $query->is_main_query() ) return;
- if ( $query->get('post_type') !== 'unban_request' ) return;
-
- if ( isset( $_GET['lb_tab'] ) ) {
- $tab = sanitize_text_field( $_GET['lb_tab'] );
- $allowed = array( 'bans', 'mutes', 'warnings', 'kicks' );
- if ( in_array( $tab, $allowed, true ) ) {
- // apply meta_query only if meta exists; harmless otherwise
- $query->set( 'meta_query', array(
- array(
- 'key' => '_lb_type',
- 'value' => $tab,
- 'compare' => '='
- )
- ) );
- }
- }
- }
-
- /**
- * Remove inline Quick Edit when admin note is locked (prevents sneaky quick edits).
- */
- public function filter_post_row_actions( $actions, $post ) {
- if ( $post->post_type !== 'unban_request' ) return $actions;
-
- $locked_note = get_post_meta( $post->ID, '_lb_admin_note_locked', true );
- $locked_status = get_post_meta( $post->ID, '_lb_status_locked', true );
- if ( $locked_note || $locked_status ) {
- if ( isset( $actions['inline hide-if-no-js'] ) ) {
- unset( $actions['inline hide-if-no-js'] );
- }
- if ( isset( $actions['inline'] ) ) {
- unset( $actions['inline'] );
- }
- }
-
- return $actions;
- }
-}
-
+post_type ) && $screen->post_type === 'unban_request' ) {
+ $load = true;
+ }
+ }
+
+ if ( $load ) {
+ wp_enqueue_style( 'litebans-pro-admin', plugins_url( 'css/admin.css', __FILE__ ), array(), '6.4.7' );
+ wp_enqueue_style( 'litebans-pro-frontend-css', plugins_url( 'css/style.css', __FILE__ ), array(), '6.4.7' );
+ }
+ }
+
+ /**
+ * Inject CSS/JS to visually mark locked rows in the CPT list (edit.php?post_type=unban_request)
+ * We collect locked post IDs server-side and output a small script that adds a CSS class and badge.
+ */
+ public function inject_locked_row_styles() {
+ if ( ! is_admin() ) return;
+ if ( ! function_exists( 'get_current_screen' ) ) return;
+
+ $screen = get_current_screen();
+ if ( ! $screen ) return;
+ if ( $screen->id !== 'edit-unban_request' ) return;
+
+ // Query for locked posts (status or admin note locked)
+ $locked_posts = get_posts(array(
+ 'post_type' => 'unban_request',
+ 'posts_per_page' => -1,
+ 'fields' => 'ids',
+ 'meta_query' => array(
+ 'relation' => 'OR',
+ array(
+ 'key' => '_lb_status_locked',
+ 'value' => '1',
+ 'compare' => '='
+ ),
+ array(
+ 'key' => '_lb_admin_note_locked',
+ 'value' => '1',
+ 'compare' => '='
+ )
+ )
+ ));
+
+ if ( empty( $locked_posts ) ) return;
+
+ // Prepare JSON array for JS
+ $ids_json = wp_json_encode( array_map( 'intval', $locked_posts ) );
+
+ // Output inline CSS + JS
+ echo '';
+
+ echo '';
+ }
+
+ public function hide_default_editor() {
+ global $post;
+ if ( $post && $post->post_type === 'unban_request' ) {
+ echo '';
+ }
+ }
+
+ // --- 1. CPT SYSTEM ---
+ public function register_cpt_unban_request() {
+ $labels = array(
+ 'name' => 'Entbannungsanträge',
+ 'singular_name' => 'Entbannungsantrag',
+ 'menu_name' => 'Entbannungen',
+ 'add_new' => 'Neu erstellen',
+ 'edit_item' => 'Antrag bearbeiten',
+ );
+ $args = array(
+ 'labels' => $labels,
+ 'public' => false,
+ 'show_ui' => true,
+ 'show_in_menu' => 'litebans-manager',
+ 'capability_type' => 'post',
+ 'supports' => array(''),
+ 'menu_icon' => 'dashicons-forms',
+ );
+ register_post_type( 'unban_request', $args );
+ }
+
+ public function set_unban_columns($columns) {
+ if ( isset($columns['title']) ) unset($columns['title']);
+ if ( isset($columns['date']) ) unset($columns['date']);
+ $columns['player'] = 'Spieler';
+ $columns['status'] = 'Status';
+ $columns['date'] = 'Datum';
+ return $columns;
+ }
+
+ public function fill_unban_columns($column, $post_id) {
+ if ($column == 'player') {
+ echo esc_html(get_post_meta($post_id, '_lb_player', true));
+ }
+ if ($column == 'status') {
+ $s = get_post_meta($post_id, '_lb_status', true);
+ $label = $s === 'approved' ? 'Angenommen' : ($s === 'rejected' ? 'Abgelehnt' : 'Wartend');
+ echo ''.esc_html($label).' ';
+ }
+ }
+
+ public function add_unban_meta_box() {
+ // Primary ticket box
+ add_meta_box(
+ 'lb_unban_ticket', 'Unban Ticket Verwaltung',
+ array( $this, 'render_unban_meta_box' ),
+ 'unban_request', 'normal', 'high'
+ );
+
+ // Admin Note sidebox
+ add_meta_box(
+ 'lb_admin_note_box', 'Admin Notiz',
+ array( $this, 'render_admin_note_box' ),
+ 'unban_request', 'side', 'high'
+ );
+ }
+
+ public function render_unban_meta_box( $post ) {
+ wp_nonce_field( 'lb_unban_save', 'lb_unban_nonce' );
+ $player = get_post_meta( $post->ID, '_lb_player', true );
+ $reason = get_post_meta( $post->ID, '_lb_reason', true );
+ $message = $post->post_content;
+ $status = get_post_meta( $post->ID, '_lb_status', true );
+ if ( empty($status) ) $status = 'pending';
+ $status_locked = get_post_meta( $post->ID, '_lb_status_locked', true );
+ $admin_name = get_post_meta( $post->ID, '_lb_admin_name', true );
+
+ ?>
+
+ ID, '_lb_admin_note', true );
+ $admin = get_post_meta( $post->ID, '_lb_admin_name', true );
+ $locked = get_post_meta( $post->ID, '_lb_admin_note_locked', true );
+
+ echo '';
+ if ( $locked ) {
+ echo '
Gesperrt von: ' . esc_html( $admin ) . '
';
+ echo '
';
+ echo nl2br( esc_html( $note ) );
+ echo '
';
+ echo '
Diese Notiz wurde gesperrt und kann nicht mehr verändert werden.
';
+ } else {
+ echo '
Admin Notiz (wird beim Annehmen/Ablehnen gesperrt)
';
+ echo '
' . esc_textarea( $note ) . ' ';
+ echo '
Bitte begründe kurz deine Entscheidung. Nach dem Speichern bei Annahme/Ablehnung wird diese Notiz dauerhaft gesperrt.
';
+ }
+ echo '
';
+ }
+
+ /**
+ * save_unban_meta_box
+ * - speichert Meta
+ * - sperrt Status und Admin-Notiz bei finaler Entscheidung (approved/rejected)
+ * - verhindert nachträgliche Änderungen am Status/Notiz, wenn gesperrt
+ */
+ public function save_unban_meta_box( $post_id, $post ) {
+ // Nonce + capability checks
+ if ( ! isset( $_POST['lb_unban_nonce'] ) || ! wp_verify_nonce( $_POST['lb_unban_nonce'], 'lb_unban_save' ) ) return;
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
+ if ( ! current_user_can( 'edit_post', $post_id ) ) return;
+
+ // Existing flags
+ $old_status = get_post_meta( $post_id, '_lb_status', true );
+ $status_locked = get_post_meta( $post_id, '_lb_status_locked', true );
+ $note_locked = get_post_meta( $post_id, '_lb_admin_note_locked', true );
+
+ // Incoming sanitized values
+ $incoming_status = isset( $_POST['lb_status'] ) ? sanitize_text_field( $_POST['lb_status'] ) : $old_status;
+ $incoming_note = isset( $_POST['lb_admin_note'] ) ? sanitize_textarea_field( wp_kses_post( $_POST['lb_admin_note'] ) ) : '';
+
+ $current_user = wp_get_current_user();
+ $timestamp = current_time( 'd.m.Y H:i' );
+
+ // ---- STATUS HANDLING ----
+ // If status is already locked, deny changing it.
+ if ( ! empty( $status_locked ) ) {
+ // keep old status; ignore incoming value
+ $status_to_store = $old_status;
+ } else {
+ // Accept incoming status and if it's final, lock it.
+ $status_to_store = $incoming_status;
+ if ( in_array( $status_to_store, array( 'approved', 'rejected' ), true ) ) {
+ update_post_meta( $post_id, '_lb_status_locked', 1 );
+ }
+ }
+
+ // Always store the status meta (either unchanged or new allowed value)
+ update_post_meta( $post_id, '_lb_status', $status_to_store );
+
+ // ---- ADMIN NOTE HANDLING ----
+ // If note already locked, do not overwrite.
+ if ( ! empty( $note_locked ) ) {
+ // do nothing for admin note
+ } else {
+ // If note is not locked yet:
+ if ( in_array( $status_to_store, array( 'approved', 'rejected' ), true ) ) {
+ // Final status: write note + admin name + lock (even if note is empty)
+ $admin_label = ( $current_user->display_name ? $current_user->display_name : $current_user->user_login ) . ' · ' . $timestamp;
+ update_post_meta( $post_id, '_lb_admin_note', $incoming_note );
+ update_post_meta( $post_id, '_lb_admin_name', $admin_label );
+ update_post_meta( $post_id, '_lb_admin_note_locked', 1 );
+ } else {
+ // Non-final: save incoming note (editable)
+ if ( isset( $_POST['lb_admin_note'] ) ) {
+ update_post_meta( $post_id, '_lb_admin_note', $incoming_note );
+ }
+ }
+ }
+
+ // ---- ACTION: wenn gerade auf approved gesetzt (und war nicht approved vorher) -> unban ingame ----
+ if ( $old_status !== 'approved' && $status_to_store === 'approved' ) {
+ $player = get_post_meta( $post_id, '_lb_player', true );
+ if ( $player ) {
+ $lbdb = $this->get_litebans_db();
+ if ( is_wp_error( $lbdb ) ) {
+ add_settings_error( 'lb', 'db_error', 'LiteBans DB nicht konfiguriert: Unban nicht ausgeführt.', 'error' );
+ } else {
+ $res = $this->unban_by_player( $lbdb, $player, $current_user );
+ if ( $res['updated'] > 0 ) {
+ add_settings_error( 'lb', 'unban_ok', sprintf( '%d Eintrag(e) für %s wurden ingame aufgehoben.', $res['updated'], esc_html($player) ), 'updated' );
+ } else {
+ add_settings_error( 'lb', 'unban_none', 'Keine aktive Strafe in LiteBans gefunden für ' . esc_html($player) . '.', 'notice' );
+ }
+ }
+ }
+ }
+
+ // If status changed to rejected and was not rejected previously, add a notice
+ if ( $old_status !== 'rejected' && $status_to_store === 'rejected' ) {
+ add_settings_error( 'lb', 'rejected', 'Antrag abgelehnt. Notiz gesperrt.', 'updated' );
+ }
+ }
+
+ // --- 2. ADMIN MENÜ ---
+ public function add_admin_menu() {
+ add_menu_page(
+ 'LiteBans Manager',
+ 'LiteBans Manager',
+ 'manage_options',
+ 'litebans-manager',
+ array( $this, 'render_admin_dashboard' ),
+ 'dashicons-dismiss',
+ 30
+ );
+ add_submenu_page( 'litebans-manager', 'Einstellungen', 'Einstellungen', 'manage_options', 'litebans-settings', array( $this, 'render_settings_page' ) );
+ }
+
+ public function register_settings() {
+ register_setting( $this->option_name, $this->option_name );
+ }
+
+ public function handle_admin_actions() {
+ // Actions handled in dashboard
+ }
+
+ public function render_settings_page() {
+ if ( isset( $_POST['save_settings'] ) && check_admin_referer( 'lb_save_settings' ) ) {
+ update_option( $this->option_name, $_POST['lb_settings'] );
+ echo 'Einstellungen gespeichert!
';
+ }
+
+ $settings = get_option( $this->option_name );
+ $fields = array(
+ 'db_host' => array('label'=>'Host', 'type'=>'text', 'default'=>'localhost'),
+ 'db_port' => array('label'=>'Port', 'type'=>'number', 'default'=>'3306'),
+ 'db_name' => array('label'=>'Datenbank Name', 'type'=>'text', 'default'=>'litebans'),
+ 'db_user' => array('label'=>'User', 'type'=>'text'),
+ 'db_pass' => array('label'=>'Passwort', 'type'=>'password'),
+ 'table_prefix' => array('label'=>'Prefix', 'type'=>'text', 'default'=>'litebans_'),
+ 'theme_mode' => array('label'=>'Frontend Theme', 'type'=>'select', 'default'=>'light', 'options'=>['light'=>'Light Mode', 'dark'=>'Dark Mode'])
+ );
+ ?>
+
+
LiteBans Einstellungen
+
+
+
+
+
+
+ db) return $this->db;
+ $s = get_option( $this->option_name );
+ if ( empty( $s['db_name'] ) ) return new WP_Error( 'no_config', 'LiteBans nicht konfiguriert.' );
+
+ // Host und Port zusammenfügen
+ $db_host = $s['db_host'];
+ if ( ! empty( $s['db_port'] ) ) {
+ $db_host .= ':' . intval( $s['db_port'] );
+ }
+
+ $this->db = new wpdb( $s['db_user'], $s['db_pass'], $s['db_name'], $db_host );
+ if ( $this->db->last_error ) return new WP_Error( 'db_error', 'DB Fehler: ' . $this->db->last_error );
+ $this->db->prefix = isset($s['table_prefix']) ? $s['table_prefix'] : 'litebans_';
+ return $this->db;
+ }
+
+ private function get_avatar($name) {
+ return " ";
+ }
+
+ private function clean($t) {
+ if(!$t) return "-";
+ $t = preg_replace("/(?i)(\x{00a7}|&)[0-9A-FK-OR]/u", "", $t);
+ return esc_html($t);
+ }
+
+ private function millis_to_date($m) { return $m ? date("d.m.Y H:i", $m/1000) : "-"; }
+
+ // KORRIGIERTE BADGE LOGIK
+ private function get_badge($r, $type) {
+ $now = (int) ( microtime(true) * 1000 );
+
+ // entfernte Einträge (aufgehoben)
+ if (!empty($r->removed_by_name) && $r->removed_by_name !== "#expired") {
+ return "Aufgehoben ";
+ }
+
+ // Warnings & Kicks - keine Ablauf/Perm-Logik nötig
+ if ($type === 'warnings') {
+ return "Verwarnt ";
+ }
+ if ($type === 'kicks') {
+ return "Gekickt ";
+ }
+
+ // Bans / Mutes: prüfen Ablauf
+ if (!empty($r->until) && (int)$r->until > 0 && $now > (int)$r->until) {
+ return "Abgelaufen ";
+ }
+
+ if ( empty($r->until) || (int)$r->until <= 0 ) {
+ $label = ($type === 'mutes') ? "Permanent Mute" : "Permanent Ban";
+ return "".esc_html($label)." ";
+ }
+
+ // aktiv
+ $label = ($type === 'mutes') ? "Gemutet" : "Gebannt";
+ $class = ($type === 'mutes') ? "muted" : "active";
+ return "".esc_html($label)." ";
+ }
+
+ private function get_theme_script($default_theme) {
+ ob_start();
+ ?>
+
+ 'Unban: ' . sanitize_text_field($_POST['lb_player']),
+ 'post_content' => sanitize_textarea_field($_POST['lb_message']),
+ 'post_status' => 'pending',
+ 'post_type' => 'unban_request',
+ );
+ $post_id = wp_insert_post( $post_data );
+ if( $post_id ) {
+ update_post_meta( $post_id, '_lb_player', sanitize_text_field($_POST['lb_player']) );
+ update_post_meta( $post_id, '_lb_reason', sanitize_text_field($_POST['lb_reason']) );
+ update_post_meta( $post_id, '_lb_status', 'pending' );
+ $msg = 'Antrag erfolgreich eingereicht!
';
+ $player = ''; $reason = '';
+ }
+ }
+
+ ob_start();
+ ?>
+
+ option_name );
+ $default_theme = $settings['theme_mode'] ?? 'light';
+
+ if ( isset($_GET['lb_player']) ) {
+ $player = sanitize_text_field($_GET['lb_player']);
+ $reason = isset($_GET['lb_reason']) ? sanitize_textarea_field($_GET['lb_reason']) : '';
+ $content = $this->render_unban_logic($player, $reason);
+ $content .= $this->get_theme_script($default_theme);
+ return $content;
+ }
+
+ $lbdb = $this->get_litebans_db();
+ if(is_wp_error($lbdb)) return 'Datenbank Fehler: Bitte Einstellungen überprüfen.
';
+
+ $current_url = get_permalink();
+
+ // robustes render_tab: COALESCE für optionale Felder, stellt sicher dass kicks/warnings sichtbar sind
+ $render_tab = function($t) use($lbdb, $current_url) {
+ $table = esc_sql($lbdb->prefix . $t);
+ $limit = 20;
+
+ // FIX: Kicks haben keine removed_by_name Spalte in der DB
+ $select_removed = ($t === 'kicks') ? "''" : "COALESCE(l.removed_by_name, '')";
+
+ $q = $lbdb->prepare(
+ "SELECT l.id, l.uuid, l.reason, l.banned_by_name, l.time,
+ COALESCE(l.until, 0) as until,
+ COALESCE(l.active, 0) as active,
+ " . $select_removed . " as removed_by_name,
+ h.name
+ FROM {$table} l
+ LEFT JOIN {$lbdb->prefix}history h ON l.uuid = h.uuid
+ WHERE (l.uuid IS NOT NULL OR h.name IS NOT NULL)
+ GROUP BY l.id
+ ORDER BY l.time DESC LIMIT %d",
+ $limit
+ );
+ $rows = $lbdb->get_results($q);
+ if(!$rows) return "Keine Daten
";
+
+ $html = 'Spieler Status Grund Datum Aktion ';
+
+ foreach($rows as $r) {
+ $playerName = !empty($r->name) ? $r->name : (!empty($r->banned_by_name) ? $r->banned_by_name : '-');
+ // active kann 0/1 oder NULL sein -> COALESCE stellt sicher: 1=aktiv
+ $is_active = (isset($r->active) && intval($r->active) == 1) && empty($r->removed_by_name);
+
+ $html .= '';
+ $html .= ''.$this->get_avatar($playerName);
+ $html .= ''.esc_html($playerName).'
';
+
+ $html .= ''.$this->get_badge($r, $t).' ';
+
+ $html .= ''.$this->clean($r->reason).' ';
+
+ $html .= ''.$this->millis_to_date($r->time).' ';
+
+ // BUTTON LOGIK: nur für bans/mutes und nur wenn aktiv
+ $html .= '';
+ if ($is_active && ($t === 'bans' || $t === 'mutes')) {
+ $unban_link = add_query_arg( array('lb_player' => $playerName, 'lb_reason' => rawurlencode($r->reason)), $current_url );
+ $html .= 'Antrag ';
+ } else {
+ $html .= '- ';
+ }
+ $html .= ' ';
+ $html .= ' ';
+ }
+ return $html.'
';
+ };
+
+ ob_start();
+ ?>
+
+
+
+
+ Bans
+ Mutes
+ Warnings
+ Kicks
+
+
+
+
+
+
+
+ get_theme_script($default_theme); ?>
+
+ render_unban_logic('', '');
+ }
+
+ // --- 4. ADMIN BACKEND MIT TABS ---
+ public function render_admin_dashboard() {
+ // Tabs
+ $current_tab = isset($_GET['lb_tab']) ? sanitize_text_field($_GET['lb_tab']) : 'bans';
+ $valid_tabs = array('bans', 'mutes', 'warnings', 'kicks');
+ if(!in_array($current_tab, $valid_tabs, true)) $current_tab = 'bans';
+
+ $lbdb = $this->get_litebans_db();
+ if ( is_wp_error( $lbdb ) ) {
+ echo '' . esc_html( $lbdb->get_error_message() ) . '
';
+ return;
+ }
+
+ // Actions verarbeiten (Unban/Delete)
+ if ( isset( $_POST['lb_action'] ) && isset( $_POST['lb_id'] ) && check_admin_referer( 'lb_admin_action_' . $_POST['lb_id'] ) ) {
+ $this->process_admin_action($lbdb, sanitize_text_field($_POST['lb_type']));
+ }
+
+ settings_errors( 'lb' );
+
+ // Pagination
+ $search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : '';
+ $limit = 20;
+ $paged = isset( $_GET['paged'] ) ? max(1, intval($_GET['paged'])) : 1;
+ $offset = ( $paged - 1 ) * $limit;
+
+ $table = esc_sql($lbdb->prefix . $current_tab);
+ $search_sql = $search ? $lbdb->prepare(" AND h.name LIKE %s", "%$search%") : "";
+
+ // FIX: Kicks haben keine removed_by_name Spalte in der DB
+ $select_removed = ($current_tab === 'kicks') ? "''" : "COALESCE(l.removed_by_name, '')";
+
+ // Robust select for admin listing as well
+ $query = "SELECT l.id, l.uuid, l.reason, l.banned_by_name, l.time,
+ COALESCE(l.until,0) AS until,
+ COALESCE(l.active,0) AS active,
+ " . $select_removed . " AS removed_by_name,
+ h.name
+ FROM $table l LEFT JOIN {$lbdb->prefix}history h ON l.uuid = h.uuid
+ WHERE (l.uuid IS NOT NULL OR h.name IS NOT NULL) $search_sql GROUP BY l.id ORDER BY l.time DESC LIMIT %d OFFSET %d";
+
+ $results = $lbdb->get_results( $lbdb->prepare( $query, $limit, $offset ) );
+ $total = $lbdb->get_var("SELECT COUNT(*) FROM $table l WHERE l.uuid IS NOT NULL");
+
+ ?>
+
+
LiteBans Manager
+
+
+
+
+
+
+
+
+
+ Suchen
+
+
+
+
+
+ ID Spieler Grund Von Status Aktion
+
+
+ Keine Einträge. '; ?>
+ active) && $row->active == 1) && empty($row->removed_by_name);
+ }
+ ?>
+
+ id); ?>
+ name ?? $row->banned_by_name); ?>
+ clean($row->reason); ?>
+ banned_by_name); ?>
+
+ Verwarnung';
+ } elseif ($current_tab === 'kicks') {
+ echo 'Kick ';
+ } else {
+ echo '';
+ echo $active ? 'Aktiv' : 'Inaktiv';
+ echo ' ';
+ }
+ ?>
+
+
+
+ id ); ?>
+
+
+
+
+ Aufheben
+
+
+ Löschen
+
+
+
+
+
+
+
+
+
+ max(1, ceil($total/$limit)),
+ 'current' => $paged,
+ 'base' => add_query_arg('paged', '%#%')
+ ));
+ ?>
+
+
+ prefix . $type);
+ $now = (int) ( microtime(true) * 1000 );
+
+ // Disallow unban action for warnings/kicks
+ if ( ($type === 'warnings' || $type === 'kicks') && $action === 'unban' ) {
+ add_settings_error( 'lb', 'invalid_action', 'Diese Sanktion kann nicht aufgehoben werden.', 'error' );
+ return;
+ }
+
+ if ( $action === 'unban' ) {
+ // Nur Bans / Mutes
+ if ( ! in_array( $type, array('bans','mutes'), true ) ) {
+ add_settings_error( 'lb', 'invalid_type', 'Ungültiger Typ für Aufhebung.', 'error' );
+ return;
+ }
+
+ $data = array(
+ 'active' => 0,
+ 'removed_by_name' => 'WebAdmin: ' . $current_user->display_name,
+ 'removed_by_uuid' => 'CONSOLE',
+ 'removed_by_date' => $now
+ );
+
+ $where = array( 'id' => $id );
+ $formats = array( '%d', '%s', '%s', '%d' );
+ $where_formats = array( '%d' );
+
+ $result = $lbdb->update( $table, $data, $where, $formats, $where_formats );
+
+ if ( $result !== false ) {
+ // additionally, try to update any other rows with same uuid (defensive)
+ $uuid = $lbdb->get_var( $lbdb->prepare( "SELECT uuid FROM {$table} WHERE id = %d LIMIT 1", $id ) );
+ if ( $uuid ) {
+ $lbdb->update( esc_sql($lbdb->prefix . 'bans'), $data, array('uuid' => $uuid, 'active' => 1), $formats, array('%s','%d'));
+ $lbdb->update( esc_sql($lbdb->prefix . 'mutes'), $data, array('uuid' => $uuid, 'active' => 1), $formats, array('%s','%d'));
+ }
+
+ add_settings_error( 'lb', 'success', "Eintrag #$id erfolgreich aufgehoben und ingame entfernt.", 'updated' );
+ } else {
+ add_settings_error( 'lb', 'dbfail', "Datenbank Update fehlgeschlagen.", 'error' );
+ }
+ } elseif ( $action === 'delete' ) {
+ $result = $lbdb->delete( $table, array( 'id' => $id ), array( '%d' ) );
+ if ( $result ) add_settings_error( 'lb', 'success', "Eintrag #$id gelöscht.", 'updated' );
+ else add_settings_error( 'lb', 'dbfail', "Löschen fehlgeschlagen.", 'error' );
+ }
+ }
+
+ /**
+ * unban_by_player
+ * - versucht UUID aus history zu holen und active Bans/Mutes aufzuheben
+ * - returns array('updated' => int)
+ */
+ private function unban_by_player( $lbdb, $player, $current_user ) {
+ $updated = 0;
+ $now = (int) ( microtime(true) * 1000 );
+
+ // find latest uuid from history
+ $uuid = $lbdb->get_var( $lbdb->prepare( "SELECT uuid FROM {$lbdb->prefix}history WHERE name = %s ORDER BY id DESC LIMIT 1", $player ) );
+
+ if ( ! $uuid ) {
+ // Kein Eintrag in history gefunden => nicht zuverlässig aufhebbar
+ return array('updated' => 0);
+ }
+
+ $data = array(
+ 'active' => 0,
+ 'removed_by_name' => 'WebAdmin: ' . $current_user->display_name,
+ 'removed_by_uuid' => 'CONSOLE',
+ 'removed_by_date' => $now
+ );
+ $formats = array('%d','%s','%s','%d');
+
+ foreach ( array('bans','mutes') as $t ) {
+ $table = esc_sql( $lbdb->prefix . $t );
+ // Update only active entries with this uuid
+ $where = array( 'uuid' => $uuid, 'active' => 1 );
+ $where_formats = array('%s','%d');
+
+ $res = $lbdb->update( $table, $data, $where, $formats, $where_formats );
+ if ( $res !== false ) {
+ $updated += (int) $res;
+ }
+ }
+
+ return array('updated' => $updated);
+ }
+
+ /**
+ * Inject tabs into the CPT listing screen (edit.php?post_type=unban_request)
+ * This displays the same tabs as the plugin dashboard and links to the plugin page.
+ */
+ public function inject_tabs_into_unban_cpt() {
+ if ( ! is_admin() ) return;
+ if ( ! function_exists( 'get_current_screen' ) ) return;
+
+ $screen = get_current_screen();
+ if ( ! $screen ) return;
+
+ // Only show on the CPT list screen for unban_request
+ if ( $screen->id !== 'edit-unban_request' ) return;
+
+ $valid_tabs = array( 'bans', 'mutes', 'warnings', 'kicks' );
+ $current = isset( $_GET['lb_tab'] ) ? sanitize_text_field( $_GET['lb_tab'] ) : 'bans';
+ if ( ! in_array( $current, $valid_tabs, true ) ) $current = 'bans';
+
+ echo '';
+ echo '
';
+
+ foreach ( $valid_tabs as $t ) {
+ $active = $current === $t ? 'active' : '';
+ $url = add_query_arg( array( 'page' => 'litebans-manager', 'lb_tab' => $t ), admin_url( 'admin.php' ) );
+ echo '' . esc_html( ucfirst( $t ) ) . ' ';
+ }
+
+ echo ' ';
+ echo '
';
+ }
+
+ public function filter_unban_cpt_by_tab( $query ) {
+ if ( ! is_admin() || ! $query->is_main_query() ) return;
+ if ( $query->get('post_type') !== 'unban_request' ) return;
+
+ if ( isset( $_GET['lb_tab'] ) ) {
+ $tab = sanitize_text_field( $_GET['lb_tab'] );
+ $allowed = array( 'bans', 'mutes', 'warnings', 'kicks' );
+ if ( in_array( $tab, $allowed, true ) ) {
+ // apply meta_query only if meta exists; harmless otherwise
+ $query->set( 'meta_query', array(
+ array(
+ 'key' => '_lb_type',
+ 'value' => $tab,
+ 'compare' => '='
+ )
+ ) );
+ }
+ }
+ }
+
+ /**
+ * Remove inline Quick Edit when admin note is locked (prevents sneaky quick edits).
+ */
+ public function filter_post_row_actions( $actions, $post ) {
+ if ( $post->post_type !== 'unban_request' ) return $actions;
+
+ $locked_note = get_post_meta( $post->ID, '_lb_admin_note_locked', true );
+ $locked_status = get_post_meta( $post->ID, '_lb_status_locked', true );
+ if ( $locked_note || $locked_status ) {
+ if ( isset( $actions['inline hide-if-no-js'] ) ) {
+ unset( $actions['inline hide-if-no-js'] );
+ }
+ if ( isset( $actions['inline'] ) ) {
+ unset( $actions['inline'] );
+ }
+ }
+
+ return $actions;
+ }
+}
+
new WP_LiteBans_Pro();
\ No newline at end of file