From eb40b2e36004c8b5f77c3dcb367b13bc5c5489eb Mon Sep 17 00:00:00 2001 From: M_Viper Date: Sat, 10 Jan 2026 16:21:26 +0000 Subject: [PATCH] Dateien nach "/" hochladen --- wp-litebans-manager.php | 998 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 998 insertions(+) create mode 100644 wp-litebans-manager.php diff --git a/wp-litebans-manager.php b/wp-litebans-manager.php new file mode 100644 index 0000000..f9428d5 --- /dev/null +++ b/wp-litebans-manager.php @@ -0,0 +1,998 @@ +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(); \ No newline at end of file