diff --git a/admin/forum-admin.php b/admin/forum-admin.php index ec6b2d4..3786939 100644 --- a/admin/forum-admin.php +++ b/admin/forum-admin.php @@ -21,8 +21,16 @@ add_action( 'admin_menu', function() { add_submenu_page( 'wbf-admin', 'Level', 'Level', 'manage_options', 'wbf-levels', 'wbf_admin_levels' ); add_submenu_page( 'wbf-admin', 'Mitglieder', 'Mitglieder', 'manage_options', 'wbf-members', 'wbf_admin_members' ); add_submenu_page( 'wbf-admin', 'Meldungen', 'Meldungen', 'manage_options', 'wbf-reports', 'wbf_admin_reports' ); + add_submenu_page( 'wbf-admin', 'Profilfelder', 'Profilfelder', 'manage_options', 'wbf-profile-fields', 'wbf_admin_profile_fields' ); add_submenu_page( 'wbf-admin', 'Einstellungen', 'Einstellungen', 'manage_options', 'wbf-settings', 'wbf_admin_settings' ); + add_submenu_page( 'wbf-admin', 'Reaktionen', 'Reaktionen', 'manage_options', 'wbf-reactions', 'wbf_admin_reactions' ); + add_submenu_page( 'wbf-admin', 'Einladungen', 'Einladungen', 'manage_options', 'wbf-invites', 'wbf_admin_invites' ); + add_submenu_page( 'wbf-admin', 'Statistiken', 'Statistiken', 'manage_options', 'wbf-stats', 'wbf_admin_stats' ); + add_submenu_page( 'wbf-admin', 'Papierkorb', 'Papierkorb', 'manage_options', 'wbf-trash', 'wbf_admin_trash' ); + add_submenu_page( 'wbf-admin', 'Thread-Präfixe','Thread-Präfixe','manage_options', 'wbf-prefixes', 'wbf_admin_prefixes' ); + add_submenu_page( 'wbf-admin', 'Wortfilter', 'Wortfilter', 'manage_options', 'wbf-wordfilter', 'wbf_admin_wordfilter' ); add_submenu_page( 'wbf-admin', 'Export / Import','Export / Import','manage_options', 'wbf-export', 'wbf_admin_export' ); + add_submenu_page( 'wbf-admin', '⚠️ Deinstallieren', '⚠️ Deinstallieren', 'manage_options', 'wbf-uninstall', 'wbf_admin_uninstall' ); }, 10 ); // Meldungs-Badge im Menü (separater Hook mit Priorität 999, läuft nach der Registrierung) @@ -39,6 +47,19 @@ add_action( 'admin_menu', function() { } }, 999 ); +// ── Wartungsmodus-Toggle via admin_init (läuft vor WordPress-Output/Headern) ── +add_action( 'admin_init', function() { + if ( ! isset( $_POST['wbf_dash_toggle_maint'] ) ) return; + if ( ! check_admin_referer( 'wbf_dash_maint_nonce' ) ) return; + if ( ! current_user_can( 'manage_options' ) ) return; + + $s = wbf_get_settings(); + $s['maintenance_mode'] = ( ( $s['maintenance_mode'] ?? '0' ) === '1' ) ? '0' : '1'; + update_option( 'wbf_settings', $s ); + wp_safe_redirect( add_query_arg( 'page', 'wbf-admin', admin_url( 'admin.php' ) ) ); + exit; +} ); + // ── Export via admin_init (läuft vor WordPress-Output/Headern) ──────────────── add_action( 'admin_init', function() { if ( ! isset( $_POST['wbf_do_export'] ) ) return; @@ -61,7 +82,8 @@ add_action( 'admin_init', function() { foreach ( $sections as $sec ) { switch ( $sec ) { case 'settings': - $data['settings'] = get_option('wbf_settings', []); + $data['settings'] = get_option('wbf_settings', []); + $data['profile_fields'] = get_option('wbf_profile_fields', []); break; case 'roles': $data['roles'] = get_option('wbf_custom_roles', []); @@ -81,10 +103,15 @@ add_action( 'admin_init', function() { case 'users': $data['users'] = $wpdb->get_results( "SELECT id, username, email, password, display_name, avatar_url, bio, signature, - role, post_count, registered, last_active, ban_reason + role, pre_ban_role, ban_reason, ban_until, post_count, + registered, last_active, profile_public FROM {$wpdb->prefix}forum_users ORDER BY id ASC", ARRAY_A ); + $data['user_meta'] = $wpdb->get_results( + "SELECT * FROM {$wpdb->prefix}forum_user_meta ORDER BY user_id ASC", + ARRAY_A + ); break; case 'threads': $data['threads'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_threads ORDER BY id ASC", ARRAY_A ); @@ -96,6 +123,7 @@ add_action( 'admin_init', function() { ORDER BY tt.thread_id ASC", ARRAY_A ); + $data['subscriptions'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_subscriptions ORDER BY id ASC", ARRAY_A ); break; case 'interactions': $data['likes'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_likes ORDER BY id ASC", ARRAY_A ); @@ -108,6 +136,9 @@ add_action( 'admin_init', function() { case 'reports': $data['reports'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_reports ORDER BY id ASC", ARRAY_A ); break; + case 'invites': + $data['invites'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_invites ORDER BY id ASC", ARRAY_A ); + break; } } @@ -128,306 +159,666 @@ add_action( 'admin_init', function() { add_action( 'admin_head', function() { if ( ! isset( $_GET['page'] ) || strpos( $_GET['page'], 'wbf-' ) === false ) return; echo ''; } ); // ── Dashboard ───────────────────────────────────────────────────────────────── function wbf_admin_page() { + + global $wpdb; $stats = WBF_DB::get_stats(); $roles = WBF_Roles::get_sorted(); $open_reports = WBF_DB::count_open_reports(); - $recent = WBF_DB::get_recent_threads(6); - $members = WBF_DB::get_all_users(5); - $newest = $stats['newest'] ?? '—'; + $recent = WBF_DB::get_recent_threads(8); + $members = WBF_DB::get_all_users(1); + $admin_url = admin_url('admin.php'); + $maint_active = ( wbf_get_settings()['maintenance_mode'] ?? '0' ) === '1'; + $furl = wbf_get_forum_url(); - $admin_url = admin_url('admin.php'); + // ── Counts ─────────────────────────────────────────────────────────────── + $tag_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_tags"); + $deleted_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_threads WHERE deleted_at IS NOT NULL") + + (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_posts WHERE deleted_at IS NOT NULL"); + $sub_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_subscriptions"); + $online_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE last_active >= DATE_SUB(NOW(), INTERVAL 15 MINUTE)"); + $invite_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_invites WHERE use_count < max_uses AND (expires_at IS NULL OR expires_at > NOW())"); + $banned_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE role='banned'"); + + // ── System ──────────────────────────────────────────────────────────────── + $php_ver = PHP_VERSION; + $php_rec = version_compare($php_ver,'8.0','>='); + $php_ok = version_compare($php_ver,'7.4','>='); + $mail_ok = function_exists('wp_mail'); + $mysql_ver = $wpdb->get_var('SELECT VERSION()') ?: '?'; + $exp_tables= ['forum_users','forum_categories','forum_threads','forum_posts','forum_likes','forum_reports','forum_tags','forum_thread_tags','forum_messages','forum_reactions','forum_remember_tokens','forum_subscriptions','forum_notifications']; + $existing = $wpdb->get_col("SHOW TABLES LIKE '{$wpdb->prefix}forum_%'"); + $missing = array_filter($exp_tables, fn($t) => !in_array($wpdb->prefix.$t, $existing)); + + // ── Trends ──────────────────────────────────────────────────────────────── + $pt = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_posts WHERE deleted_at IS NULL AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)"); + $pl = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_posts WHERE deleted_at IS NULL AND created_at BETWEEN DATE_SUB(NOW(), INTERVAL 14 DAY) AND DATE_SUB(NOW(), INTERVAL 7 DAY)"); + $tht = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_threads WHERE deleted_at IS NULL AND created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)"); + $thl = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_threads WHERE deleted_at IS NULL AND created_at BETWEEN DATE_SUB(NOW(), INTERVAL 14 DAY) AND DATE_SUB(NOW(), INTERVAL 7 DAY)"); + $ut = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE registered >= DATE_SUB(NOW(), INTERVAL 7 DAY)"); + $ul = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE registered BETWEEN DATE_SUB(NOW(), INTERVAL 14 DAY) AND DATE_SUB(NOW(), INTERVAL 7 DAY)"); + + $tr = function($now,$prev) { + if ($prev==0) return $now>0 ? ['+∞','wbf-tu','fa-arrow-trend-up'] : ['—','wbf-tf','fa-minus']; + $p=round(($now-$prev)/$prev*100); + if ($p>0) return ['+'.$p.'%','wbf-tu','fa-arrow-trend-up']; + if ($p<0) return [$p.'%','wbf-td','fa-arrow-trend-down']; + return ['±0%','wbf-tf','fa-minus']; + }; + [$pp,$pc,$pi] = $tr($pt,$pl); + [$tp,$tc,$ti] = $tr($tht,$thl); + [$up,$uc,$ui] = $tr($ut,$ul); + + // ── Top cats ────────────────────────────────────────────────────────────── + $top_cats = $wpdb->get_results("SELECT c.name,c.icon,COUNT(t.id) AS cnt FROM {$wpdb->prefix}forum_categories c LEFT JOIN {$wpdb->prefix}forum_threads t ON t.category_id=c.id AND t.deleted_at IS NULL GROUP BY c.id ORDER BY cnt DESC LIMIT 5"); + $max_cnt = $top_cats ? max(1,max(array_map(fn($c)=>(int)$c->cnt,$top_cats))) : 1; + + // ── Banned ──────────────────────────────────────────────────────────────── + $banned_users = $wpdb->get_results("SELECT display_name,avatar_url,ban_reason,ban_until FROM {$wpdb->prefix}forum_users WHERE role='banned' ORDER BY id DESC LIMIT 5"); + + // ── Activity ────────────────────────────────────────────────────────────── + $activity = $wpdb->get_results(" + (SELECT 'post' AS type,p.id AS oid,u.display_name,SUBSTRING(p.content,1,70) AS sub,p.created_at,u.avatar_url FROM {$wpdb->prefix}forum_posts p JOIN {$wpdb->prefix}forum_users u ON u.id=p.user_id WHERE p.deleted_at IS NULL ORDER BY p.created_at DESC LIMIT 6) + UNION ALL + (SELECT 'thread',t.id,u.display_name,t.title,t.created_at,u.avatar_url FROM {$wpdb->prefix}forum_threads t JOIN {$wpdb->prefix}forum_users u ON u.id=t.user_id WHERE t.deleted_at IS NULL ORDER BY t.created_at DESC LIMIT 5) + UNION ALL + (SELECT 'register',fu.id,fu.display_name,fu.username,fu.registered,fu.avatar_url FROM {$wpdb->prefix}forum_users fu ORDER BY fu.registered DESC LIMIT 4) + UNION ALL + (SELECT 'report',r.id,u.display_name,r.reason,r.created_at,u.avatar_url FROM {$wpdb->prefix}forum_reports r JOIN {$wpdb->prefix}forum_users u ON u.id=r.reporter_id WHERE r.status='open' ORDER BY r.created_at DESC LIMIT 3) + ORDER BY created_at DESC LIMIT 15 + "); + + // ── Open reports ────────────────────────────────────────────────────────── + $reports_preview = $wpdb->get_results(" + SELECT r.*,u.display_name AS rname,p.content AS pc,t.title AS tt,t.id AS tid + FROM {$wpdb->prefix}forum_reports r + LEFT JOIN {$wpdb->prefix}forum_users u ON u.id=r.reporter_id + LEFT JOIN {$wpdb->prefix}forum_posts p ON p.id=r.object_id AND r.object_type='post' + LEFT JOIN {$wpdb->prefix}forum_threads t ON t.id=p.thread_id + WHERE r.status='open' ORDER BY r.created_at DESC LIMIT 6 + "); + $rlabels = ['spam'=>'Spam','harassment'=>'Belästigung','inappropriate'=>'Unangemessen','misinformation'=>'Fehlinformation','off-topic'=>'Offtopic','other'=>'Sonstiges']; + $acfg = ['post'=>['fas fa-comment-dots','post','antwortete'],'thread'=>['fas fa-comments','thread','erstellte Thread:'],'register'=>['fas fa-user-plus','register','registrierte sich'],'report'=>['fas fa-flag','report','meldete Beitrag:']]; + + $nonce_url = fn($action,$id) => esc_url(wp_nonce_url(add_query_arg(['page'=>'wbf-reports','report_id'=>$id,'report_action'=>$action,'filter'=>'open'],admin_url('admin.php')),'wbf_report_action')); + $ago = function($t) { + $d=time()-strtotime($t); + if($d<60) return 'jetzt'; + if($d<3600) return (int)($d/60).' Min.'; + if($d<86400)return (int)($d/3600).' Std.'; + return date_i18n('d.m.',$d<604800?time()-$d:strtotime($t)); + }; ?> -
[business_forum] auf einer Seite ein, um das Forum anzuzeigen.
+