' . (int) $count . '';
break;
}
}
}, 999 );
// ── Export via admin_init (läuft vor WordPress-Output/Headern) ────────────────
add_action( 'admin_init', function() {
if ( ! isset( $_POST['wbf_do_export'] ) ) return;
if ( ! check_admin_referer( 'wbf_export_nonce' ) ) return;
if ( ! current_user_can( 'manage_options' ) ) return;
$sections = array_keys( array_filter( $_POST['export_sections'] ?? [] ) );
$data = [
'_meta' => [
'plugin' => 'WP Business Forum',
'version' => WBF_VERSION,
'exported' => date('c'),
'site' => get_bloginfo('url'),
'sections' => $sections,
],
];
global $wpdb;
foreach ( $sections as $sec ) {
switch ( $sec ) {
case 'settings':
$data['settings'] = get_option('wbf_settings', []);
break;
case 'roles':
$data['roles'] = get_option('wbf_custom_roles', []);
break;
case 'levels':
$data['levels'] = [
'config' => get_option('wbf_level_config', []),
'enabled' => get_option('wbf_levels_enabled', true),
];
break;
case 'categories':
$data['categories'] = $wpdb->get_results(
"SELECT * FROM {$wpdb->prefix}forum_categories ORDER BY parent_id ASC, sort_order ASC",
ARRAY_A
);
break;
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
FROM {$wpdb->prefix}forum_users ORDER BY id ASC",
ARRAY_A
);
break;
case 'threads':
$data['threads'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_threads ORDER BY id ASC", ARRAY_A );
$data['posts'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_posts ORDER BY id ASC", ARRAY_A );
$data['thread_tags'] = $wpdb->get_results(
"SELECT tt.*, t.name, t.slug, t.use_count
FROM {$wpdb->prefix}forum_thread_tags tt
JOIN {$wpdb->prefix}forum_tags t ON t.id = tt.tag_id
ORDER BY tt.thread_id ASC",
ARRAY_A
);
break;
case 'interactions':
$data['likes'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_likes ORDER BY id ASC", ARRAY_A );
$data['reactions'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_reactions ORDER BY id ASC", ARRAY_A );
$data['notifications'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_notifications ORDER BY id ASC", ARRAY_A );
break;
case 'messages':
$data['messages'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_messages ORDER BY id ASC", ARRAY_A );
break;
case 'reports':
$data['reports'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_reports ORDER BY id ASC", ARRAY_A );
break;
}
}
$json = wp_json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
$filename = 'wbf-backup-' . date('Y-m-d-His') . '.json';
header( 'Content-Type: application/json; charset=utf-8' );
header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
header( 'Content-Length: ' . strlen( $json ) );
header( 'Cache-Control: no-cache, no-store, must-revalidate' );
echo $json;
exit;
} );
// ── Inline Styles ─────────────────────────────────────────────────────────────
add_action( 'admin_head', function() {
if ( ! isset( $_GET['page'] ) || strpos( $_GET['page'], 'wbf-' ) === false ) return;
echo '';
} );
// ── Dashboard ─────────────────────────────────────────────────────────────────
function wbf_admin_page() {
$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'] ?? '—';
$admin_url = admin_url('admin.php');
?>
Business Forum — Dashboard
Forum-Shortcode
Füge [business_forum] auf einer Seite ein, um das Forum anzuzeigen.
'fas fa-comments', 'color'=>'#eff6ff','icolor'=>'#3b82f6', 'val'=>$stats['threads'], 'label'=>'Threads'],
['icon'=>'fas fa-comment-dots','color'=>'#f0fdf4','icolor'=>'#22c55e', 'val'=>$stats['posts'], 'label'=>'Beiträge'],
['icon'=>'fas fa-users', 'color'=>'#fdf4ff','icolor'=>'#a855f7', 'val'=>$stats['members'], 'label'=>'Mitglieder'],
['icon'=>'fas fa-flag', 'color'=>'#fff7ed','icolor'=>'#f97316', 'val'=>$open_reports, 'label'=>'Meldungen offen'],
['icon'=>'fas fa-tags', 'color'=>'#f0fdfa','icolor'=>'#14b8a6', 'val'=>0, 'label'=>'Tags gesamt'],
];
// Get tag count
global $wpdb;
$stat_items[4]['val'] = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_tags");
foreach ( $stat_items as $si ):
$link = '';
if ($si['label']==='Offene Meldungen') $link = esc_url(add_query_arg(['page'=>'wbf-reports'], $admin_url));
if ($si['label']==='Mitglieder') $link = esc_url(add_query_arg(['page'=>'wbf-members'], $admin_url));
?>
$role ):
$color = esc_attr($role['color']); $bg = esc_attr($role['bg_color']); ?>
Lvl
Superadmin ist automatisch an den WordPress-Administrator gebunden.
'wbf-categories', 'icon'=>'fas fa-folder-open', 'label'=>'Kategorien verwalten'],
['page'=>'wbf-roles', 'icon'=>'fas fa-shield-halved','label'=>'Rollen bearbeiten'],
['page'=>'wbf-levels', 'icon'=>'fas fa-star', 'label'=>'Level-System'],
['page'=>'wbf-members', 'icon'=>'fas fa-users', 'label'=>'Mitglieder'],
['page'=>'wbf-reports', 'icon'=>'fas fa-flag', 'label'=>'Meldungen',
'badge'=> $open_reports > 0 ? $open_reports : 0],
['page'=>'wbf-settings', 'icon'=>'fas fa-gear', 'label'=>'Einstellungen'],
];
foreach ($links as $ln):
$href = esc_url(add_query_arg(['page'=>$ln['page']], $admin_url));
?>
Noch keine Threads vorhanden.
Noch keine Mitglieder.
role);
$col = esc_attr($role['color']);
$bg = esc_attr($role['bg_color']);
?>
-
post_count; ?> Beitr.
$label ) {
if ( ! empty( $_POST['perm_' . $p] ) ) $perms[] = $p;
}
WBF_Roles::save( $key, [
'label' => sanitize_text_field( $_POST['role_label'] ),
'level' => max( -1, min( 99, (int) $_POST['role_level'] ) ),
'color' => sanitize_hex_color( $_POST['role_color'] ) ?: '#94a3b8',
'bg_color' => sanitize_text_field( $_POST['role_bg'] ) ?: 'rgba(148,163,184,.1)',
'icon' => sanitize_text_field( $_POST['role_icon'] ) ?: 'fas fa-user',
'permissions' => $perms,
'locked' => false,
'description' => sanitize_textarea_field( $_POST['role_desc'] ),
] );
echo '';
}
}
if ( isset( $_POST['wbf_create_role'] ) && check_admin_referer( 'wbf_role_create_nonce' ) ) {
$new_key = sanitize_key( $_POST['new_role_key'] ?? '' );
if ( $new_key && $new_key !== WBF_Roles::SUPERADMIN ) {
$perms = [];
foreach ( $all_perms as $p => $label ) {
if ( ! empty( $_POST['new_perm_' . $p] ) ) $perms[] = $p;
}
WBF_Roles::save( $new_key, [
'label' => sanitize_text_field( $_POST['new_role_label'] ?: ucfirst( $new_key ) ),
'level' => max( 1, min( 79, (int) ( $_POST['new_role_level'] ?? 10 ) ) ),
'color' => sanitize_hex_color( $_POST['new_role_color'] ) ?: '#94a3b8',
'bg_color' => 'rgba(148,163,184,.1)',
'icon' => sanitize_text_field( $_POST['new_role_icon'] ) ?: 'fas fa-user',
'permissions' => $perms,
'locked' => false,
'description' => sanitize_textarea_field( $_POST['new_role_desc'] ),
] );
echo '';
}
}
if ( isset( $_GET['delete_role'] ) && check_admin_referer( 'delete_role_' . $_GET['delete_role'] ) ) {
$del = sanitize_key( $_GET['delete_role'] );
if ( WBF_Roles::delete( $del ) ) {
echo 'Rolle gelöscht. Nutzer auf "member" gesetzt.
';
} else {
echo 'Diese Rolle kann nicht gelöscht werden.
';
}
}
$roles = WBF_Roles::get_sorted();
$edit_key = isset( $_GET['edit_role'] ) ? sanitize_key( $_GET['edit_role'] ) : null;
$edit_role = $edit_key ? WBF_Roles::get( $edit_key ) : null;
echo '';
echo '
| Rolle | Level | Permissions | Beschreibung | Aktionen |
';
foreach ( $roles as $key => $role ) {
$color = esc_attr( $role['color'] ); $bg = esc_attr( $role['bg_color'] );
$badge = "
" . esc_html( $role['label'] ) . "";
$perms = implode( ', ', array_map( fn($p) => esc_html( $all_perms[$p] ?? $p ), $role['permissions'] ?? [] ) );
if ( in_array( 'all', $role['permissions'] ?? [] ) ) $perms = 'Alle Rechte';
$actions = '';
if ( $key !== WBF_Roles::SUPERADMIN ) {
$actions .= "Bearbeiten";
if ( ! in_array( $key, ['member'] ) ) {
$del_url = wp_nonce_url( "?page=wbf-roles&delete_role={$key}", "delete_role_{$key}" );
$actions .= " | Löschen";
}
} else {
$actions = 'Systemrolle — unveränderlich';
}
echo "
| $badge " . ( ( $role['locked'] ?? false ) ? '(🔒)' : '' ) . " |
" . esc_html( $role['level'] ) . " |
$perms |
" . esc_html( $role['description'] ?? '' ) . " |
$actions |
";
}
echo '
';
if ( $edit_role && $edit_key !== WBF_Roles::SUPERADMIN ) {
echo '
Bearbeiten: ' . esc_html( $edit_role['label'] ) . '
';
echo '
';
}
echo '
Neue Rolle erstellen
';
}
function wbf_role_form_fields( $role, $all_perms, $prefix ) {
$v = fn($k, $d = '') => esc_attr( $role[$k] ?? $d );
$perms = $role['permissions'] ?? [];
echo "
| Anzeigename * | |
| Level |
Superadmin=100, Admin≤80, Mod≤50, Member=10, Banned=-1
|
| Farbe |
|
| Icon |
FontAwesome 6, z.B. fas fa-crown
|
| Beschreibung | |
| Permissions | ";
foreach ( $all_perms as $p => $label ) {
$checked = in_array( $p, $perms ) ? 'checked' : '';
echo "";
}
echo " |
";
}
// ── Kategorien ────────────────────────────────────────────────────────────────
function wbf_admin_categories() {
global $wpdb;
$roles = WBF_Roles::get_sorted();
// ── Reihenfolge verschieben ──────────────────────────────────────────────
if ( isset( $_POST['wbf_reorder_cat'] ) && check_admin_referer( 'wbf_reorder_nonce' ) ) {
$move_id = (int) $_POST['cat_id'];
$dir = ( $_POST['direction'] ?? '' ) === 'up' ? 'up' : 'down';
$parent = (int) $_POST['parent_id'];
$siblings = $wpdb->get_results( $wpdb->prepare(
"SELECT id, sort_order FROM {$wpdb->prefix}forum_categories WHERE parent_id=%d ORDER BY sort_order ASC, id ASC",
$parent
) );
$ids = array_column( (array) $siblings, 'id' );
$pos = array_search( $move_id, $ids );
if ( $dir === 'up' && $pos > 0 ) {
$swap_id = $ids[ $pos - 1 ];
} elseif ( $dir === 'down' && $pos !== false && $pos < count($ids) - 1 ) {
$swap_id = $ids[ $pos + 1 ];
}
if ( isset( $swap_id ) ) {
$so_a = $siblings[$pos]->sort_order;
$so_b = $siblings[ $dir === 'up' ? $pos - 1 : $pos + 1 ]->sort_order;
if ( $so_a === $so_b ) { $so_b = $dir === 'up' ? $so_a - 1 : $so_a + 1; }
$wpdb->update( "{$wpdb->prefix}forum_categories", ['sort_order' => $so_b], ['id' => $move_id] );
$wpdb->update( "{$wpdb->prefix}forum_categories", ['sort_order' => $so_a], ['id' => $swap_id] );
}
// Gleiche Seite neu laden (kein redirect_to nötig)
$tree = WBF_DB::get_categories_tree();
}
if ( isset( $_POST['wbf_save_cat'] ) && check_admin_referer( 'wbf_cat_nonce' ) ) {
$data = [
'parent_id' => (int) ( $_POST['parent_id'] ?? 0 ),
'name' => sanitize_text_field( $_POST['name'] ),
'slug' => sanitize_title( $_POST['name'] ),
'description' => sanitize_textarea_field( $_POST['description'] ),
'icon' => sanitize_text_field( $_POST['icon'] ),
'sort_order' => (int) ( $_POST['sort_order'] ?? 0 ),
'min_role' => sanitize_key( $_POST['min_role'] ?? 'member' ),
];
if ( ! empty( $_POST['cat_id'] ) ) {
$wpdb->update( "{$wpdb->prefix}forum_categories", $data, ['id' => (int) $_POST['cat_id']] );
echo '';
} else {
$wpdb->insert( "{$wpdb->prefix}forum_categories", $data );
echo '';
}
}
if ( isset( $_GET['delete_cat'] ) && current_user_can( 'manage_options' ) ) {
check_admin_referer( 'delete_cat_' . (int) $_GET['delete_cat'] );
$wpdb->delete( "{$wpdb->prefix}forum_categories", ['id' => (int) $_GET['delete_cat']] );
}
$tree = WBF_DB::get_categories_tree();
$all = WBF_DB::get_categories_flat();
$edit = isset( $_GET['edit'] ) ? WBF_DB::get_category( (int) $_GET['edit'] ) : null;
echo '';
echo '
| Kategorie | Threads | Min. Rolle | Aktionen |
';
foreach ( $tree as $p ) {
$d = wp_nonce_url( "?page=wbf-categories&delete_cat={$p->id}", "delete_cat_{$p->id}" );
$role = WBF_Roles::get( $p->min_role ?? 'member' );
$lockbadge = ( $p->min_role ?? 'member' ) !== 'member'
? " 🔒 " . esc_html( $role['label'] ) . "" : '';
$reorder_p =
''
. '';
echo "
| " . esc_html( $p->name ) . "$lockbadge |
" . esc_html( $p->thread_count ) . " |
" . esc_html( $role['label'] ) . " |
{$reorder_p} Bearbeiten | Löschen |
";
foreach ( $p->children as $c ) {
$cd = wp_nonce_url( "?page=wbf-categories&delete_cat={$c->id}", "delete_cat_{$c->id}" );
$crole = WBF_Roles::get( $c->min_role ?? 'member' );
$reorder_c =
''
. '';
echo "
| ↳ " . esc_html( $c->name ) . " |
" . esc_html( $c->thread_count ) . " |
" . esc_html( $crole['label'] ) . " |
{$reorder_c} Bearbeiten | Löschen |
";
}
}
echo '
';
$parent_opts = '
';
foreach ( $all as $c ) {
if ( $edit && $c->id == $edit->id ) continue;
$sel = ( $edit && (int) $edit->parent_id === (int) $c->id ) ? ' selected' : '';
$indent = (int) $c->parent_id > 0 ? ' ↳ ' : '';
$parent_opts .= "
";
}
$role_opts = '';
foreach ( $roles as $k => $r ) {
if ( $k === 'banned' || $k === WBF_Roles::SUPERADMIN ) continue;
$sel = ( $edit && ( $edit->min_role ?? 'member' ) === $k ) ? ' selected' : '';
$role_opts .= "
";
}
echo '
' . ( $edit ? 'Bearbeiten: ' . esc_html( $edit->name ) : 'Neue Kategorie' ) . '
';
echo '
';
}
// ── Mitglieder ────────────────────────────────────────────────────────────────
function wbf_admin_members() {
$roles = WBF_Roles::get_sorted();
// ── Rolle ändern ──────────────────────────────────────────────────────────
if ( isset( $_POST['wbf_change_role'] ) && check_admin_referer( 'wbf_member_role_nonce' ) ) {
$uid = (int) $_POST['user_id'];
$role = sanitize_key( $_POST['new_role'] );
if ( $uid && $role !== WBF_Roles::SUPERADMIN && array_key_exists( $role, WBF_Roles::get_all() ) ) {
$update = ['role' => $role];
if ( $role === 'banned' ) {
$update['ban_reason'] = sanitize_textarea_field( $_POST['ban_reason'] ?? '' );
} else {
$update['ban_reason'] = '';
}
WBF_DB::update_user( $uid, $update );
echo '';
}
}
// ── Profil bearbeiten ─────────────────────────────────────────────────────
if ( isset( $_POST['wbf_edit_user'] ) && check_admin_referer( 'wbf_edit_user_nonce' ) ) {
$uid = (int) $_POST['user_id'];
$display_name = sanitize_text_field( $_POST['display_name'] ?? '' );
$email = sanitize_email( $_POST['email'] ?? '' );
$new_password = $_POST['new_password'] ?? '';
if ( $uid && $uid !== 0 ) {
$user = WBF_DB::get_user( $uid );
if ( $user && $user->role !== WBF_Roles::SUPERADMIN ) {
$update = [];
if ( ! empty($display_name) ) $update['display_name'] = $display_name;
if ( is_email($email) ) $update['email'] = $email;
if ( strlen($new_password) >= 6 ) {
$update['password'] = password_hash( $new_password, PASSWORD_DEFAULT );
}
if ( ! empty($update) ) {
WBF_DB::update_user( $uid, $update );
echo 'Profil von ' . esc_html($user->display_name) . ' aktualisiert!
';
}
}
}
}
$members = WBF_DB::get_all_users( 200 );
?>
Mitglieder
| # | Nutzer | E-Mail |
Aktuelle Rolle | Beiträge |
Registriert | Rolle ändern |
role );
$color = esc_attr( $role['color'] );
$bg = esc_attr( $role['bg_color'] );
$icon = esc_attr( $role['icon'] ?? 'fas fa-user' );
$is_sa = ( $m->role === WBF_Roles::SUPERADMIN );
$ban_reason = esc_attr( $m->ban_reason ?? '' );
$opts = '';
foreach ( $roles as $k => $r ) {
if ( $k === WBF_Roles::SUPERADMIN ) continue;
$sel = $m->role === $k ? ' selected' : '';
$opts .= '';
}
?>
| id ); ?> |
display_name ); ?>
@username ); ?>
|
email ); ?> |
(WP-Admin)
|
post_count ); ?> |
registered ) ) ); ?> |
Automatisch (WP-Admin)
Profil bearbeiten: display_name); ?>
|
Meldung aktualisiert.
';
}
}
$filter = sanitize_key( $_GET['filter'] ?? 'open' );
$reports = WBF_DB::get_reports( $filter, 100 );
$count = WBF_DB::count_open_reports();
echo 'Meldungen ' . ( $count > 0 ? '' . (int) $count . '' : '' ) . '
';
$tabs = ['open' => 'Offen', 'resolved' => 'Erledigt', 'dismissed' => 'Verworfen', 'all' => 'Alle'];
echo '
';
foreach ( $tabs as $k => $label ) {
$url = esc_url( add_query_arg( ['page' => 'wbf-reports', 'filter' => $k] ) );
$active = ( $filter === $k ) ? ' class="current"' : '';
echo "- $label |
";
}
echo '
';
if ( empty( $reports ) ) {
echo '
Keine Meldungen vorhanden.
';
return;
}
$reason_labels = [
'spam' => 'Spam / Werbung', 'harassment' => 'Belästigung',
'inappropriate' => 'Unangemessen', 'misinformation' => 'Fehlinformation',
'off-topic' => 'Offtopic', 'other' => 'Sonstiges',
];
$status_colors = ['open' => '#f59e0b', 'resolved' => '#56cf7e', 'dismissed' => '#6b7a99'];
echo '
| # | Gemeldet von | Grund | Vorschau | Thread | Datum | Status | Aktionen |
';
foreach ( $reports as $r ) {
$reason_label = esc_html( $reason_labels[ $r->reason ] ?? $r->reason );
$preview = esc_html( mb_substr( strip_tags( $r->post_content ?? '' ), 0, 80 ) );
$sc = $status_colors[ $r->status ] ?? '#999';
$status_badge = "" . esc_html( ucfirst( $r->status ) ) . "";
$note_cell = $r->note ? '
' . esc_html( $r->note ) . '' : '';
$base = ['page' => 'wbf-reports', 'report_id' => $r->id, 'filter' => $filter];
if ( $r->status === 'open' ) {
$res_url = esc_url( wp_nonce_url( add_query_arg( array_merge( $base, ['report_action' => 'resolved'] ), admin_url('admin.php') ), 'wbf_report_action' ) );
$dis_url = esc_url( wp_nonce_url( add_query_arg( array_merge( $base, ['report_action' => 'dismissed'] ), admin_url('admin.php') ), 'wbf_report_action' ) );
$actions = "✔ Erledigt ";
$actions .= "✖ Verwerfen";
} else {
$reopen_url = esc_url( wp_nonce_url( add_query_arg( array_merge( $base, ['report_action' => 'open'] ), admin_url('admin.php') ), 'wbf_report_action' ) );
$actions = "↩ Wieder öffnen";
}
echo "
| " . esc_html( $r->id ) . " |
" . esc_html( $r->reporter_name ?? '—' ) . " @" . esc_html( $r->reporter_username ?? '' ) . " |
$reason_label$note_cell |
$preview…
→ Zum Beitrag |
" . ( $r->thread_id ? esc_html( mb_substr( $r->thread_title ?? '', 0, 35 ) ) : '—' ) . " |
" . esc_html( date( 'd.m.Y H:i', strtotime( $r->created_at ) ) ) . " |
$status_badge |
$actions |
";
}
echo '
';
}
// ── Level-System ──────────────────────────────────────────────────────────────
function wbf_admin_levels() {
// ── Toggle on/off ────────────────────────────────────────────────────────
if ( isset( $_POST['wbf_toggle_levels'] ) && check_admin_referer( 'wbf_levels_toggle_nonce' ) ) {
WBF_Levels::set_enabled( ! empty( $_POST['levels_enabled'] ) );
echo '';
}
// ── Reset ────────────────────────────────────────────────────────────────
if ( isset( $_POST['wbf_reset_levels'] ) && check_admin_referer( 'wbf_levels_reset_nonce' ) ) {
WBF_Levels::reset_to_defaults();
echo 'Level auf Standard zurückgesetzt.
';
}
// ── Level löschen ────────────────────────────────────────────────────────
if ( isset( $_GET['delete_level'] ) && check_admin_referer( 'delete_level_' . (int) $_GET['delete_level'] ) ) {
$idx = (int) $_GET['delete_level'];
$levels = WBF_Levels::get_all();
if ( count($levels) > 1 ) {
unset( $levels[$idx] );
WBF_Levels::save( array_values($levels) );
echo '';
} else {
echo 'Mindestens ein Level muss vorhanden sein.
';
}
}
// ── Level speichern (Bearbeiten) ─────────────────────────────────────────
if ( isset( $_POST['wbf_save_level'] ) && check_admin_referer( 'wbf_levels_edit_nonce' ) ) {
$idx = (int) $_POST['level_index'];
$levels = WBF_Levels::get_all();
$levels[$idx] = [
'min' => max( 0, (int) $_POST['level_min'] ),
'label' => sanitize_text_field( $_POST['level_label'] ),
'icon' => sanitize_text_field( $_POST['level_icon'] ),
'color' => sanitize_hex_color( $_POST['level_color'] ) ?: '#94a3b8',
];
WBF_Levels::save( array_values($levels) );
echo '';
}
// ── Neues Level erstellen ────────────────────────────────────────────────
if ( isset( $_POST['wbf_create_level'] ) && check_admin_referer( 'wbf_levels_create_nonce' ) ) {
$levels = WBF_Levels::get_all();
$levels[] = [
'min' => max( 0, (int) $_POST['new_level_min'] ),
'label' => sanitize_text_field( $_POST['new_level_label'] ),
'icon' => sanitize_text_field( $_POST['new_level_icon'] ),
'color' => sanitize_hex_color( $_POST['new_level_color'] ) ?: '#94a3b8',
];
WBF_Levels::save( $levels );
echo '';
}
$levels = WBF_Levels::get_all();
$enabled = WBF_Levels::is_enabled();
$edit_i = isset( $_GET['edit_level'] ) ? (int) $_GET['edit_level'] : null;
$edit_l = ( $edit_i !== null && isset( $levels[$edit_i] ) ) ? $levels[$edit_i] : null;
echo '';
echo '
⭐ Level-System
';
// ── Status-Toggle ────────────────────────────────────────────────────────
$status_color = $enabled ? '#56cf7e' : '#f05252';
$status_label = $enabled ? '✅ Aktiviert' : '❌ Deaktiviert';
echo "
Level-System ist:
{$status_label}
Wenn deaktiviert, werden keine Level-Badges im Forum angezeigt.
";
// ── Level-Tabelle ────────────────────────────────────────────────────────
echo '
Aktuelle Level
';
echo '
| # |
Badge-Vorschau |
Ab Beiträgen |
Icon |
Aktionen |
';
foreach ( $levels as $i => $l ) {
$color = esc_attr( $l['color'] );
$icon = esc_attr( $l['icon'] );
$label = esc_html( $l['label'] );
$del_url = wp_nonce_url( "?page=wbf-levels&delete_level={$i}", "delete_level_{$i}" );
$badge_html = "
{$label}
";
echo "
| " . ( $i + 1 ) . " |
{$badge_html} |
≥ " . esc_html( $l['min'] ) . " Beiträge |
{$icon} |
Bearbeiten
" . ( count($levels) > 1 ? " | Löschen" : '' ) . "
|
";
}
echo '
';
// ── Reset-Button ─────────────────────────────────────────────────────────
echo "
";
// ── Bearbeiten-Formular ──────────────────────────────────────────────────
if ( $edit_l !== null ) {
echo '
Level bearbeiten: ' . esc_html( $edit_l['label'] ) . '
';
echo '
';
}
// ── Neues Level erstellen ────────────────────────────────────────────────
echo '
Neues Level erstellen
';
echo '
';
echo '
';
}
// ── Hilfsformular für Level-Felder ────────────────────────────────────────────
function wbf_level_form_fields( $level, $prefix ) {
$min = esc_attr( $level['min'] ?? '' );
$label = esc_attr( $level['label'] ?? '' );
$icon = esc_attr( $level['icon'] ?? 'fas fa-star' );
$color = esc_attr( $level['color'] ?? '#94a3b8' );
return "
| Ab Beiträgen * |
Level ab dieser Beitragsanzahl (0 = für alle).
|
| Bezeichnung * |
|
| Farbe |
|
| Icon |
FontAwesome 6, z.B. fas fa-crown, fas fa-fire, fas fa-seedling
|
";
}
// ── Export / Import ───────────────────────────────────────────────────────────
function wbf_admin_export() {
if ( ! current_user_can('manage_options') ) return;
$notice = '';
// Export wird von admin_init verarbeitet (vor HTTP-Header-Output)
// ── IMPORT ────────────────────────────────────────────────────────────────
if ( isset( $_POST['wbf_do_import'] ) && check_admin_referer('wbf_import_nonce') ) {
if ( empty( $_FILES['import_file']['tmp_name'] ) ) {
$notice = ['error', 'Keine Datei hochgeladen.'];
} else {
$raw = file_get_contents( $_FILES['import_file']['tmp_name'] );
$data = json_decode( $raw, true );
if ( ! $data || ! isset($data['_meta']) ) {
$notice = ['error', 'Ungültige Datei — kein gültiges WBF-Backup.'];
} else {
global $wpdb;
$imported = [];
$sections = $data['_meta']['sections'] ?? array_keys($data);
if ( ! empty($data['settings']) ) {
update_option('wbf_settings', $data['settings']);
$imported[] = 'Einstellungen';
}
if ( ! empty($data['roles']) ) {
// Superadmin-Schutz: niemals überschreiben
$roles = $data['roles'];
unset($roles['superadmin']);
$current = get_option('wbf_custom_roles', []);
$current['superadmin'] = WBF_Roles::get('superadmin');
update_option('wbf_custom_roles', array_merge($current, $roles));
$imported[] = 'Rollen';
}
if ( ! empty($data['levels']) ) {
if ( isset($data['levels']['config']) ) update_option('wbf_level_config', $data['levels']['config']);
if ( isset($data['levels']['enabled']) ) update_option('wbf_levels_enabled', $data['levels']['enabled']);
$imported[] = 'Level';
}
if ( ! empty($data['categories']) ) {
// Nur importieren wenn Tabelle leer oder Force-Flag gesetzt
$force = ! empty($_POST['import_force_cats']);
$existing = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_categories");
if ( $existing === 0 || $force ) {
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_categories");
foreach ($data['categories'] as $cat) {
unset($cat['id']); // auto-increment
$wpdb->insert("{$wpdb->prefix}forum_categories", $cat);
}
$imported[] = 'Kategorien (' . count($data['categories']) . ')';
} else {
$imported[] = 'Kategorien übersprungen (bereits vorhanden — „Überschreiben" aktivieren)';
}
}
if ( ! empty($data['users']) ) {
$force = ! empty($_POST['import_force_users']);
$count = 0;
foreach ($data['users'] as $u) {
$exists = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}forum_users WHERE username=%s OR email=%s",
$u['username'], $u['email']
));
if ($exists && !$force) continue;
if ($exists && $force) {
unset($u['id']);
$wpdb->update("{$wpdb->prefix}forum_users", $u, ['id'=>$exists]);
} else {
unset($u['id']);
$u['role'] = ($u['role'] === 'superadmin') ? 'member' : $u['role'];
$wpdb->insert("{$wpdb->prefix}forum_users", $u);
}
$count++;
}
$imported[] = "Benutzer ($count importiert)";
}
if ( ! empty($data['threads']) ) {
$force = ! empty($_POST['import_force_threads']);
if ($force) {
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_posts");
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_threads");
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_thread_tags");
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_tags");
}
foreach ($data['threads'] ?? [] as $t) { $wpdb->insert("{$wpdb->prefix}forum_threads", $t); }
foreach ($data['posts'] ?? [] as $p) { $wpdb->insert("{$wpdb->prefix}forum_posts", $p); }
// Re-import tags
if (!empty($data['thread_tags'])) {
$tag_map = [];
foreach ($data['thread_tags'] as $tt) {
if (!isset($tag_map[$tt['slug']])) {
$existing_tag = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}forum_tags WHERE slug=%s", $tt['slug']
));
if (!$existing_tag) {
$wpdb->insert("{$wpdb->prefix}forum_tags", [
'name'=>$tt['name'],'slug'=>$tt['slug'],'use_count'=>$tt['use_count']
]);
$tag_map[$tt['slug']] = $wpdb->insert_id;
} else {
$tag_map[$tt['slug']] = $existing_tag;
}
}
$wpdb->replace("{$wpdb->prefix}forum_thread_tags", [
'thread_id'=>$tt['thread_id'], 'tag_id'=>$tag_map[$tt['slug']]
]);
}
}
$imported[] = 'Threads + Posts (' . count($data['threads']) . ' / ' . count($data['posts'] ?? []) . ')';
}
if ( ! empty($data['likes']) ) {
$force = ! empty($_POST['import_force_threads']);
if ($force) $wpdb->query("DELETE FROM {$wpdb->prefix}forum_likes");
$count = 0;
foreach ($data['likes'] as $row) {
unset($row['id']);
$existing = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}forum_likes WHERE user_id=%d AND object_id=%d AND object_type=%s",
$row['user_id'], $row['object_id'], $row['object_type']
));
if (!$existing) { $wpdb->insert("{$wpdb->prefix}forum_likes", $row); $count++; }
}
$imported[] = "Likes ($count)";
}
if ( ! empty($data['reactions']) ) {
$force = ! empty($_POST['import_force_threads']);
if ($force) $wpdb->query("DELETE FROM {$wpdb->prefix}forum_reactions");
foreach ($data['reactions'] as $row) {
unset($row['id']);
$wpdb->replace("{$wpdb->prefix}forum_reactions", $row);
}
$imported[] = 'Reaktionen (' . count($data['reactions']) . ')';
}
if ( ! empty($data['notifications']) ) {
$force = ! empty($_POST['import_force_threads']);
if ($force) $wpdb->query("DELETE FROM {$wpdb->prefix}forum_notifications");
$count = 0;
foreach ($data['notifications'] as $row) {
unset($row['id']);
$wpdb->insert("{$wpdb->prefix}forum_notifications", $row);
$count++;
}
$imported[] = "Benachrichtigungen ($count)";
}
if ( ! empty($data['messages']) ) {
$force = ! empty($_POST['import_force_messages']);
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_messages");
$count = 0;
foreach ($data['messages'] as $row) {
unset($row['id']);
$wpdb->insert("{$wpdb->prefix}forum_messages", $row);
$count++;
}
$imported[] = "Nachrichten ($count)";
}
if ( ! empty($data['reports']) ) {
$force = ! empty($_POST['import_force_reports']);
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_reports");
$count = 0;
foreach ($data['reports'] as $row) {
unset($row['id']);
$wpdb->insert("{$wpdb->prefix}forum_reports", $row);
$count++;
}
$imported[] = "Meldungen ($count)";
}
if ( empty($imported) ) {
$notice = ['warning', 'Nichts importiert — Datei enthielt keine gültigen Abschnitte.'];
} else {
$notice = ['success', '✅ Importiert: ' . implode(', ', $imported) . '. Erstellt: ' . $data['_meta']['exported'] . ' · Site: ' . esc_html($data['_meta']['site'] ?? '?')];
}
}
}
}
// ── UI ─────────────────────────────────────────────────────────────────────
?>
Export / Import
Export
Wähle was exportiert werden soll. Die Datei wird als .json heruntergeladen.
Import
Lade eine zuvor exportierte .json-Datei hoch.
⚠️ Hinweis: Benutzer-Import enthält Passwort-Hashes. Threads-Import kann bestehende Daten überschreiben. Mache vorher ein Backup.
Export-Inhalte im Überblick