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 ); ?>
Skin

Eingereicht am:
Gesperrt von:

⏳ Ausstehend = In Bearbeitung, kann noch geändert werden
✅ Annehmen = Bann/Mute wird aufgehoben, Admin-Notiz gesperrt
❌ Ablehnen = Status bleibt bestehen, Admin-Notiz gesperrt

Banngrund
Spieler Nachricht
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

$f): ?>
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(); ?>

Entbannungsantrag

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 = ''; 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 .= ''; $html .= ''; $html .= ''; $html .= ''; // BUTTON LOGIK: nur für bans/mutes und nur wenn aktiv $html .= ''; $html .= ''; } return $html.'
SpielerStatusGrundDatumAktion
'.$this->get_avatar($playerName); $html .= ''.esc_html($playerName).'
'.$this->get_badge($r, $t).''.$this->clean($r->reason).''.$this->millis_to_date($r->time).''; 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 .= '
'; }; ob_start(); ?>

Sanktionen

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

'; ?> active) && $row->active == 1) && empty($row->removed_by_name); } ?>
IDSpielerGrundVonStatusAktion
Keine Einträge.
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 ); ?>
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 ''; 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();