3183 lines
197 KiB
PHP
3183 lines
197 KiB
PHP
<?php
|
||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||
|
||
class WBF_Shortcodes {
|
||
|
||
public static function init() {
|
||
add_shortcode('business_forum', [__CLASS__, 'forum_main']);
|
||
}
|
||
|
||
// ── Helpers ───────────────────────────────────────────────────────────────
|
||
|
||
/** Alter aus Geburtsdatum berechnen */
|
||
public static function calc_age( $date_str ) {
|
||
if ( ! $date_str || ! preg_match('/^\d{4}-\d{2}-\d{2}$/', $date_str) ) return null;
|
||
$birth = new DateTime( $date_str );
|
||
$today = new DateTime();
|
||
if ( $birth > $today ) return null;
|
||
return (int) $birth->diff($today)->y;
|
||
}
|
||
|
||
public static function time_ago( $datetime ) {
|
||
$diff = time() - strtotime($datetime);
|
||
if ($diff < 60) return 'Gerade eben';
|
||
if ($diff < 3600) return floor($diff/60) . ' Min. ago';
|
||
if ($diff < 86400) return floor($diff/3600) . ' Std. ago';
|
||
if ($diff < 604800) return floor($diff/86400). ' Tage ago';
|
||
return date_i18n('d.m.Y', strtotime($datetime));
|
||
}
|
||
|
||
public static function avatar( $url, $name, $size = 40, $online = false ) {
|
||
$src = esc_url($url ?: 'https://www.gravatar.com/avatar/0?d=identicon&s='.$size);
|
||
$img = "<img src=\"$src\" alt=\"".esc_attr($name)."\" class=\"wbf-avatar\" width=\"$size\" height=\"$size\">";
|
||
if (!$online) return $img;
|
||
return "<span class=\"wbf-avatar-wrap\">$img<span class=\"wbf-online-dot\"></span></span>";
|
||
}
|
||
|
||
public static function role_badge( $role ) {
|
||
// Dynamisch aus WBF_Roles — deckt alle Rollen inkl. superadmin ab
|
||
return WBF_Roles::badge( $role );
|
||
}
|
||
|
||
public static function render_prefix( $thread ) {
|
||
if ( empty($thread->prefix_label) ) return '';
|
||
$label = esc_html($thread->prefix_label);
|
||
$color = esc_attr($thread->prefix_color ?? '#fff');
|
||
$bg = esc_attr($thread->prefix_bg ?? '#475569');
|
||
return "<span class=\"wbf-prefix-badge\" style=\"color:{$color};background:{$bg}\">{$label}</span>";
|
||
}
|
||
|
||
public static function render_tags( $tags, $small = false ) {
|
||
if ( empty($tags) ) return '';
|
||
$cls = $small ? 'wbf-tag wbf-tag--sm' : 'wbf-tag';
|
||
$out = '<div class="wbf-tag-list">';
|
||
foreach ( $tags as $tag ) {
|
||
$out .= '<a href="?forum_tag=' . esc_attr($tag->slug) . '" class="' . $cls . '">'
|
||
. '<i class="fas fa-hashtag"></i>' . esc_html($tag->name) . '</a>';
|
||
}
|
||
return $out . '</div>';
|
||
}
|
||
|
||
private static function like_btn( $object_id, $type, $count, $liked = false ) {
|
||
// Keep for thread likes (header area)
|
||
$cls = $liked ? ' wbf-liked' : '';
|
||
return sprintf(
|
||
'<button class="wbf-like-btn%s" data-id="%d" data-type="%s">
|
||
<i class="fas fa-thumbs-up"></i>
|
||
<span class="wbf-like-count">%d</span>
|
||
</button>',
|
||
$cls, $object_id, $type, $count
|
||
);
|
||
}
|
||
|
||
private static function reaction_bar( $object_id, $object_type, $current_user ) {
|
||
$emojis = WBF_DB::get_allowed_reactions();
|
||
$user_id = $current_user ? (int)$current_user->id : 0;
|
||
$data = WBF_DB::get_reactions($object_id, $object_type, $user_id);
|
||
$counts = $data['counts'];
|
||
$mine = $data['mine'];
|
||
$total = array_sum($counts);
|
||
|
||
$out = '<div class="wbf-reaction-bar" data-id="' . $object_id . '" data-type="' . esc_attr($object_type) . '">';
|
||
|
||
// Summary of existing reactions (clickable)
|
||
if ($total > 0) {
|
||
$out .= '<div class="wbf-reaction-summary">';
|
||
foreach ($emojis as $e) {
|
||
if (!empty($counts[$e])) {
|
||
$active = ($mine === $e) ? ' wbf-reaction-active' : '';
|
||
$out .= '<button class="wbf-reaction-pill' . $active . '" data-reaction="' . esc_attr($e) . '">'
|
||
. $e . '<span>' . (int)$counts[$e] . '</span></button>';
|
||
}
|
||
}
|
||
$out .= '</div>';
|
||
}
|
||
|
||
// Picker trigger (only for logged-in users with 'like' perm)
|
||
if ($current_user && WBF_DB::can($current_user, 'like')) {
|
||
$out .= '<div class="wbf-reaction-wrap">'
|
||
. '<button class="wbf-reaction-trigger" title="Reaktion hinzufügen">😊 <i class="fas fa-plus" style="font-size:.55rem"></i></button>'
|
||
. '<div class="wbf-reaction-picker">';
|
||
foreach ($emojis as $e) {
|
||
$active = ($mine === $e) ? ' wbf-reaction-active' : '';
|
||
$out .= '<button class="wbf-reaction-btn' . $active . '" data-reaction="' . esc_attr($e) . '" title="' . esc_attr($e) . '">' . $e . '</button>';
|
||
}
|
||
$out .= '</div></div>';
|
||
}
|
||
|
||
$out .= '</div>';
|
||
return $out;
|
||
}
|
||
|
||
private static function mod_tools_thread( $thread, $current ) {
|
||
if (!$current) return '';
|
||
// Only show mod bar to users who have at least one mod-level permission
|
||
$can_pin = WBF_DB::can($current, 'pin_thread');
|
||
$can_close = WBF_DB::can($current, 'close_thread');
|
||
$can_delete = WBF_DB::can($current, 'delete_thread');
|
||
$can_move = WBF_DB::can($current, 'manage_cats');
|
||
if ( !$can_pin && !$can_close && !$can_delete && !$can_move ) return '';
|
||
|
||
$is_archived = $thread->status === 'archived';
|
||
$pin_label = $thread->pinned ? '<i class="fas fa-thumbtack-slash"></i> Entpinnen' : '<i class="fas fa-thumbtack"></i> Pinnen';
|
||
$pin_action = $thread->pinned ? 'unpin_thread' : 'pin_thread';
|
||
$arch_action = $is_archived ? 'unarchive_thread' : 'archive_thread';
|
||
$arch_label = $is_archived
|
||
? '<i class="fas fa-box-open"></i> Wiederherstellen'
|
||
: '<i class="fas fa-box-archive"></i> Archivieren';
|
||
|
||
// Close/Open only makes sense on non-archived threads
|
||
$cls_btn = '';
|
||
if ( !$is_archived && $can_close ) {
|
||
$cls_action = $thread->status==='closed' ? 'open_thread' : 'close_thread';
|
||
$cls_label = $thread->status==='closed' ? '<i class="fas fa-lock-open"></i> Öffnen' : '<i class="fas fa-lock"></i> Schließen';
|
||
$cls_btn = '<button class="wbf-mod-btn" data-action="'.$cls_action.'" data-id="'.esc_attr($thread->id).'">'.$cls_label.'</button>';
|
||
}
|
||
$move_btn = $can_move
|
||
? '<button class="wbf-mod-btn wbf-mod-btn--move" data-action="open_move" data-id="'.esc_attr($thread->id).'"><i class="fas fa-right-left"></i> Verschieben</button>'
|
||
: '';
|
||
$del_btn = $can_delete
|
||
? '<button class="wbf-mod-btn wbf-mod-btn--danger" data-action="delete_thread" data-id="'.esc_attr($thread->id).'"><i class="fas fa-trash"></i> Löschen</button>'
|
||
: '';
|
||
|
||
return '<div class="wbf-mod-bar">
|
||
<span class="wbf-mod-bar__label"><i class="fas fa-shield-halved"></i> Mod</span>
|
||
'.( $can_pin ? '<button class="wbf-mod-btn" data-action="'.$pin_action.'" data-id="'.esc_attr($thread->id).'">'.$pin_label.'</button>' : '').'
|
||
'.$cls_btn.'
|
||
'.( $can_close ? '<button class="wbf-mod-btn wbf-mod-btn--archive" data-action="'.$arch_action.'" data-id="'.esc_attr($thread->id).'">'.$arch_label.'</button>' : '').'
|
||
'.$move_btn.'
|
||
'.$del_btn.'
|
||
</div>';
|
||
}
|
||
|
||
private static function mod_tools_post( $post_id, $current ) {
|
||
if (!$current || !WBF_DB::can($current,'delete_post')) return '';
|
||
return '<button class="wbf-mod-btn wbf-mod-btn--danger wbf-mod-btn--sm" data-action="delete_post" data-id="'.esc_attr($post_id).'"><i class="fas fa-trash"></i></button>';
|
||
}
|
||
|
||
// ── Router ────────────────────────────────────────────────────────────────
|
||
|
||
public static function forum_main( $atts ) {
|
||
// Server-seitiger Logout-Fallback — Nonce-Schutz gegen CSRF
|
||
if (isset($_GET['wbf_do_logout'])) {
|
||
if ( ! isset($_GET['_wpnonce']) || ! wp_verify_nonce( sanitize_text_field($_GET['_wpnonce']), 'wbf_logout' ) ) {
|
||
wp_redirect( wbf_get_forum_url() );
|
||
exit;
|
||
}
|
||
WBF_Auth::logout();
|
||
wp_redirect( wbf_get_forum_url() );
|
||
exit;
|
||
}
|
||
|
||
// ── Wartungsmodus — zentraler Check vor allem anderen ────────────────
|
||
$wbf_current_user = WBF_Auth::get_current_user();
|
||
$wbf_maint = wbf_get_settings()['maintenance_mode'] ?? '0';
|
||
if ( $wbf_maint === '1' ) {
|
||
$is_staff = $wbf_current_user && WBF_Roles::level($wbf_current_user->role) >= 50;
|
||
if ( ! $is_staff ) {
|
||
return self::view_maintenance();
|
||
}
|
||
}
|
||
|
||
if (isset($_GET['forum_members'])) return self::view_members();
|
||
// Einladungscode aus URL vorausfüllen
|
||
if (isset($_GET['wbf_invite'])) {
|
||
$inv_code = strtoupper(sanitize_text_field($_GET['wbf_invite']));
|
||
if (!WBF_DB::verify_invite($inv_code)) {
|
||
// Ungültiger Code — zeige Meldung
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap"><?php self::render_topbar(null); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<div class="wbf-notice wbf-notice--warning">
|
||
<i class="fas fa-exclamation-triangle"></i>
|
||
Dieser Einladungslink ist ungültig oder bereits abgelaufen.
|
||
</div>
|
||
<div style="margin-top:1rem">
|
||
<a href="<?php echo esc_url(wbf_get_forum_url()); ?>" class="wbf-btn wbf-btn--sm">← Zurück zum Forum</a>
|
||
</div>
|
||
</div></div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
}
|
||
if (isset($_GET['wbf_reset_token'])) return self::view_reset_password();
|
||
if (isset($_GET['forum_rules'])) return self::view_rules();
|
||
if (isset($_GET['forum_thread'])) return self::view_thread();
|
||
if (isset($_GET['forum_cat'])) return self::view_category();
|
||
if (isset($_GET['forum_profile'])) return self::view_profile();
|
||
if (isset($_GET['forum_search'])) return self::view_search();
|
||
if (isset($_GET['forum_tag'])) return self::view_tag();
|
||
if (isset($_GET['forum_dm'])) return self::view_dm();
|
||
return self::view_home();
|
||
}
|
||
|
||
|
||
/** Darf der Nutzer diese Kategorie sehen? */
|
||
private static function can_see_category( $user, $cat ) {
|
||
// Gäste: guest_visible prüfen
|
||
if ( ! $user && (int)($cat->guest_visible ?? 1) === 0 ) return false;
|
||
// Min-Rolle: Nutzer muss mindestens diese Rolle haben um die Kategorie zu sehen
|
||
if ( $cat->min_role && $cat->min_role !== 'member' ) {
|
||
if ( ! $user ) return false; // nicht eingeloggt → versteckt wenn min_role > member
|
||
if ( WBF_Roles::level($user->role) < WBF_Roles::level($cat->min_role) ) return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// ── HOME ──────────────────────────────────────────────────────────────────
|
||
|
||
private static function view_home() {
|
||
$current = WBF_Auth::get_current_user();
|
||
$tree = WBF_DB::get_categories_tree();
|
||
$stats = WBF_DB::get_stats();
|
||
$recent = WBF_DB::get_recent_threads(5);
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-hero">
|
||
<div class="wbf-hero__inner">
|
||
<h1 class="wbf-hero__title"><i class="fas fa-comments"></i> <?php echo esc_html(wbf_get_settings()['hero_title']); ?></h1>
|
||
<p class="wbf-hero__sub"><?php echo esc_html(wbf_get_settings()['hero_subtitle']); ?></p>
|
||
</div>
|
||
<div class="wbf-stats">
|
||
<div class="wbf-stat"><span class="wbf-stat__num"><?php echo number_format((int)$stats['threads']); ?></span><span><?php echo esc_html(wbf_get_settings()['stat_threads']); ?></span></div>
|
||
<div class="wbf-stat"><span class="wbf-stat__num"><?php echo number_format((int)$stats['posts']); ?></span><span><?php echo esc_html(wbf_get_settings()['stat_posts']); ?></span></div>
|
||
<div class="wbf-stat">
|
||
<?php if ($current): ?>
|
||
<a href="?forum_members=1" style="text-decoration:none;color:inherit">
|
||
<span class="wbf-stat__num wbf-stat__num--link"><?php echo number_format((int)$stats['members']); ?></span>
|
||
<span><?php echo esc_html(wbf_get_settings()['stat_members']); ?></span>
|
||
</a>
|
||
<?php else: ?>
|
||
<span class="wbf-stat__num"><?php echo number_format((int)$stats['members']); ?></span>
|
||
<span><?php echo esc_html(wbf_get_settings()['stat_members']); ?></span>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="wbf-container">
|
||
<div class="wbf-grid">
|
||
<main class="wbf-main">
|
||
<div class="wbf-section-header">
|
||
<h2><?php echo esc_html(wbf_get_settings()['section_cats']); ?></h2>
|
||
<?php if (WBF_DB::can($current,'create_thread')): ?>
|
||
<div style="display:flex;gap:.5rem;flex-wrap:wrap">
|
||
<button class="wbf-btn wbf-btn--outline-poll" onclick="wbfShowNewPoll()"><i class="fas fa-chart-bar"></i> Neue Umfrage</button>
|
||
<button class="wbf-btn wbf-btn--primary" onclick="wbfShowNewThread()"><i class="fas fa-plus"></i> <?php echo esc_html(wbf_get_settings()['btn_new_thread']); ?></button>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="wbf-cat-group-list">
|
||
<?php foreach ($tree as $parent):
|
||
if (!self::can_see_category($current, $parent)) continue; ?>
|
||
<div class="wbf-cat-group">
|
||
<div class="wbf-cat-parent">
|
||
<div class="wbf-cat-parent__icon"><i class="<?php echo esc_attr($parent->icon); ?>"></i></div>
|
||
<div class="wbf-cat-parent__body">
|
||
<a href="?forum_cat=<?php echo esc_attr($parent->slug); ?>" class="wbf-cat-parent__name"><?php echo esc_html($parent->name); ?></a>
|
||
<p class="wbf-cat-parent__desc"><?php echo esc_html($parent->description); ?></p>
|
||
</div>
|
||
<div class="wbf-cat-parent__stats">
|
||
<span><i class="fas fa-layer-group"></i> <?php echo (int)$parent->thread_count; ?></span>
|
||
<span><i class="fas fa-comment"></i> <?php echo (int)$parent->post_count; ?></span>
|
||
<?php if (($parent->min_role??'member') !== 'member'): ?>
|
||
<span class="wbf-cat-lock"><i class="fas fa-lock"></i> <?php echo esc_html(ucfirst($parent->min_role)); ?>+</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php if (!empty($parent->children)): ?>
|
||
<div class="wbf-cat-children">
|
||
<?php foreach ($parent->children as $child):
|
||
if (!self::can_see_category($current, $child)) continue; ?>
|
||
<div class="wbf-cat-child">
|
||
<div class="wbf-cat-child__icon"><i class="<?php echo esc_attr($child->icon); ?>"></i></div>
|
||
<div class="wbf-cat-child__body">
|
||
<a href="?forum_cat=<?php echo esc_attr($child->slug); ?>" class="wbf-cat-child__name"><?php echo esc_html($child->name); ?></a>
|
||
<span class="wbf-cat-child__desc"><?php echo esc_html($child->description); ?></span>
|
||
</div>
|
||
<div class="wbf-cat-child__meta">
|
||
<span><i class="fas fa-layer-group"></i> <?php echo (int)$child->thread_count; ?></span>
|
||
<span><i class="fas fa-comment"></i> <?php echo (int)$child->post_count; ?></span>
|
||
<?php if ($child->last_thread_title): ?>
|
||
<a href="?forum_thread=<?php echo (int)$child->last_thread_id; ?>" class="wbf-cat-child__last"><i class="fas fa-clock"></i> <?php echo esc_html(substr($child->last_thread_title,0,30)); ?>…</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</main>
|
||
<aside class="wbf-sidebar">
|
||
<div class="wbf-section-header"><h2><?php echo $current ? '<i class="fas fa-user-circle"></i> '.esc_html(wbf_get_settings()['sidebar_profile']) : '<i class="fas fa-sign-in-alt"></i> '.esc_html(wbf_get_settings()['sidebar_login']); ?></h2></div>
|
||
<?php if (!$current): ?>
|
||
<div class="wbf-widget"><?php self::render_auth_forms(); ?></div>
|
||
<?php else: ?>
|
||
<div class="wbf-widget wbf-profile-widget">
|
||
<div class="wbf-profile-widget__avatar"><?php echo self::avatar($current->avatar_url, $current->display_name, 60); ?></div>
|
||
<div class="wbf-profile-widget__info">
|
||
<strong><?php echo esc_html($current->display_name); ?></strong>
|
||
<?php echo self::role_badge($current->role); ?>
|
||
<span class="wbf-profile-widget__posts"><?php echo (int)$current->post_count; ?> Beiträge</span>
|
||
</div>
|
||
<div class="wbf-profile-widget__actions">
|
||
<a href="?forum_profile=<?php echo (int)$current->id; ?>" class="wbf-btn wbf-btn--sm">Profil</a>
|
||
<a href="<?php echo esc_url(wp_nonce_url(wbf_get_forum_url() . '?wbf_do_logout=1', 'wbf_logout')); ?>" class="wbf-btn wbf-btn--sm wbf-btn--outline"><?php echo esc_html(wbf_get_settings()['btn_logout']); ?></a>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<div class="wbf-section-header" style="margin-top:1.25rem"><h2><i class="fas fa-clock"></i> <?php echo esc_html(wbf_get_settings()['section_recent']); ?></h2></div>
|
||
<div class="wbf-widget">
|
||
<ul class="wbf-recent-list">
|
||
<?php foreach ($recent as $r): ?>
|
||
<li><a href="?forum_thread=<?php echo (int)$r->id; ?>"><?php echo esc_html(substr($r->title,0,45)); ?></a>
|
||
<span><?php echo esc_html($r->cat_name); ?> · <?php echo self::time_ago($r->created_at); ?></span></li>
|
||
<?php endforeach; ?>
|
||
<?php if (empty($recent)): ?><li style="color:var(--c-muted);font-size:.8rem">Noch keine Threads.</li><?php endif; ?>
|
||
</ul>
|
||
</div>
|
||
<?php $pop_tags = WBF_DB::get_popular_tags(20); if (!empty($pop_tags)): ?>
|
||
<div class="wbf-section-header" style="margin-top:1.25rem">
|
||
<h2><i class="fas fa-tags"></i> Tags</h2>
|
||
</div>
|
||
<div class="wbf-widget">
|
||
<div class="wbf-tag-cloud">
|
||
<?php foreach ($pop_tags as $pt): ?>
|
||
<a href="?forum_tag=<?php echo esc_attr($pt->slug); ?>" class="wbf-tag wbf-tag--sm">
|
||
<i class="fas fa-hashtag"></i><?php echo esc_html($pt->name); ?>
|
||
<span class="wbf-tag__count"><?php echo (int)$pt->use_count; ?></span>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
</aside>
|
||
</div>
|
||
<?php self::render_forum_footer(); ?>
|
||
</div>
|
||
<?php self::render_new_thread_modal(WBF_DB::get_categories_flat(), $current); ?>
|
||
<?php self::render_auth_modal(); ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
// ── CATEGORY ──────────────────────────────────────────────────────────────
|
||
|
||
private static function view_category() {
|
||
$slug = sanitize_key($_GET['forum_cat'] ?? '');
|
||
$cat = WBF_DB::get_category($slug);
|
||
if (!$cat) return '<p class="wbf-notice">Kategorie nicht gefunden.</p>';
|
||
|
||
$current = WBF_Auth::get_current_user();
|
||
|
||
// Zugang prüfen — Gäste + Min-Rolle
|
||
if (!self::can_see_category($current, $cat)) {
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap"><?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<div class="wbf-notice wbf-notice--warning">
|
||
<i class="fas fa-lock"></i>
|
||
<?php if (!$current): ?>
|
||
Diese Kategorie ist nur für eingeloggte Mitglieder sichtbar.
|
||
<a href="#" class="wbf-login-link" style="margin-left:.5rem;font-weight:700">Jetzt einloggen</a>
|
||
<?php else: ?>
|
||
Du hast keine Berechtigung um diese Kategorie zu sehen.
|
||
<?php endif; ?>
|
||
</div>
|
||
</div></div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
$page = max(1,(int)($_GET['fp']??1));
|
||
$threads = WBF_DB::get_threads($cat->id, $page);
|
||
$total = WBF_DB::count_threads($cat->id);
|
||
$pages = ceil($total / 20) ?: 1;
|
||
$children = WBF_DB::get_child_categories($cat->id);
|
||
$crumbs = WBF_DB::get_category_breadcrumb($cat);
|
||
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_cat','fp'])); ?>"><i class="fas fa-home"></i> Forum</a>
|
||
<?php foreach ($crumbs as $c): ?>
|
||
<span>/</span>
|
||
<?php if ($c->id===$cat->id): ?><span><?php echo esc_html($c->name); ?></span>
|
||
<?php else: ?><a href="?forum_cat=<?php echo esc_attr($c->slug); ?>"><?php echo esc_html($c->name); ?></a><?php endif; ?>
|
||
<?php endforeach; ?>
|
||
</nav>
|
||
<div class="wbf-section-header">
|
||
<div><h2><i class="<?php echo esc_attr($cat->icon); ?>"></i> <?php echo esc_html($cat->name); ?></h2>
|
||
<p class="wbf-muted"><?php echo esc_html($cat->description); ?></p></div>
|
||
<?php if (WBF_DB::can($current,'create_thread') && WBF_DB::can_post_in($current,$cat)): ?>
|
||
<div style="display:flex;gap:.5rem;flex-wrap:wrap">
|
||
<button class="wbf-btn wbf-btn--outline-poll" onclick="wbfShowNewPoll(<?php echo $cat->id; ?>)"><i class="fas fa-chart-bar"></i> Neue Umfrage</button>
|
||
<button class="wbf-btn wbf-btn--primary" onclick="wbfShowNewThread(<?php echo $cat->id; ?>)"><i class="fas fa-plus"></i> <?php echo esc_html(wbf_get_settings()['btn_new_thread']); ?></button>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php if (!empty($children)): ?>
|
||
<div class="wbf-subcat-list">
|
||
<?php foreach ($children as $child):
|
||
if (!self::can_see_category($current, $child)) continue; ?>
|
||
<a href="?forum_cat=<?php echo esc_attr($child->slug); ?>" class="wbf-subcat-card">
|
||
<div class="wbf-subcat-card__icon"><i class="<?php echo esc_attr($child->icon); ?>"></i></div>
|
||
<div class="wbf-subcat-card__body">
|
||
<span class="wbf-subcat-card__name"><?php echo esc_html($child->name); ?></span>
|
||
<span class="wbf-subcat-card__desc"><?php echo esc_html($child->description); ?></span>
|
||
</div>
|
||
<div class="wbf-subcat-card__stats"><span><?php echo (int)$child->thread_count; ?> Threads</span></div>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if (empty($threads)): ?>
|
||
<div class="wbf-empty"><i class="fas fa-inbox"></i><p>Noch keine Threads. Starte die Diskussion!</p></div>
|
||
<?php else: ?>
|
||
<div class="wbf-thread-list">
|
||
<?php foreach ($threads as $t):
|
||
$liked = $current ? WBF_DB::has_liked($current->id,$t->id,'thread') : false; ?>
|
||
<div class="wbf-thread-row<?php echo $t->pinned?' wbf-thread-row--pinned':''; ?>"
|
||
data-thread-id="<?php echo (int)$t->id; ?>"
|
||
data-last-reply="<?php echo esc_attr($t->last_reply_at); ?>"
|
||
data-preview="<?php echo esc_attr(mb_substr(strip_tags(WBF_BBCode::render($t->content)),0,160)); ?>">
|
||
<div class="wbf-thread-row__avatar"><?php echo self::avatar($t->avatar_url,$t->display_name); ?></div>
|
||
<div class="wbf-thread-row__body">
|
||
<div class="wbf-thread-row__top">
|
||
<?php if ($t->pinned): ?><span class="wbf-pin"><i class="fas fa-thumbtack"></i></span><?php endif; ?>
|
||
<?php if ($t->status==='closed'): ?><span class="wbf-badge wbf-badge--closed"><i class="fas fa-lock"></i> Geschlossen</span><?php endif; ?>
|
||
<?php echo self::render_prefix($t); ?>
|
||
<a href="?forum_thread=<?php echo (int)$t->id; ?>" class="wbf-thread-row__title"><?php echo esc_html($t->title); ?></a>
|
||
<span class="wbf-new-badge" style="display:none"><i class="fas fa-circle-dot"></i> Neu</span>
|
||
</div>
|
||
<div class="wbf-thread-row__meta">
|
||
<span>von <strong><?php echo esc_html($t->display_name); ?></strong></span>
|
||
<?php echo self::role_badge($t->author_role); ?>
|
||
<span><?php echo self::time_ago($t->created_at); ?></span>
|
||
</div>
|
||
<?php $row_tags = WBF_DB::get_thread_tags($t->id); echo self::render_tags($row_tags, true); ?>
|
||
</div>
|
||
<div class="wbf-thread-row__stats">
|
||
<span><i class="fas fa-comment-dots"></i> <?php echo (int)$t->reply_count; ?></span>
|
||
<span><i class="fas fa-eye"></i> <?php echo (int)$t->views; ?></span>
|
||
<?php echo self::like_btn($t->id,'thread',$t->like_count,$liked); ?>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php if ($pages>1): ?>
|
||
<div class="wbf-pagination">
|
||
<?php for ($i=1;$i<=$pages;$i++): ?>
|
||
<a href="?forum_cat=<?php echo esc_attr($slug); ?>&fp=<?php echo $i; ?>" class="wbf-page-btn<?php echo ($i==$page)?' active':''; ?>"><?php echo $i; ?></a>
|
||
<?php endfor; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php
|
||
// Archived threads section (only for mods)
|
||
if (WBF_DB::can($current,'close_thread')):
|
||
$archived = WBF_DB::get_archived_threads($cat->id, 1, 50);
|
||
$arch_count = WBF_DB::count_archived_threads($cat->id);
|
||
if ($arch_count > 0):
|
||
?>
|
||
<div class="wbf-archive-section" id="wbfArchiveSection" style="margin-top:2rem">
|
||
<div class="wbf-archive-section__toggle" onclick="document.getElementById('wbfArchiveList').classList.toggle('open');this.classList.toggle('open')">
|
||
<i class="fas fa-box-archive"></i>
|
||
Archivierte Threads
|
||
<span class="wbf-archive-section__count"><?php echo (int)$arch_count; ?></span>
|
||
<i class="fas fa-chevron-down" style="margin-left:auto"></i>
|
||
</div>
|
||
<div class="wbf-archive-list" id="wbfArchiveList">
|
||
<?php foreach ($archived as $at): ?>
|
||
<div class="wbf-thread-row wbf-thread-row--archived">
|
||
<div class="wbf-thread-row__avatar"><?php echo self::avatar($at->avatar_url,$at->display_name); ?></div>
|
||
<div class="wbf-thread-row__body">
|
||
<div class="wbf-thread-row__top">
|
||
<span class="wbf-badge wbf-badge--archived"><i class="fas fa-box-archive"></i> Archiviert</span>
|
||
<a href="?forum_thread=<?php echo (int)$at->id; ?>" class="wbf-thread-row__title"><?php echo esc_html($at->title); ?></a>
|
||
</div>
|
||
<div class="wbf-thread-row__meta">
|
||
<span>von <strong><?php echo esc_html($at->display_name); ?></strong></span>
|
||
<?php echo self::role_badge($at->author_role); ?>
|
||
<span><?php echo self::time_ago($at->created_at); ?></span>
|
||
</div>
|
||
</div>
|
||
<div class="wbf-thread-row__stats">
|
||
<span><i class="fas fa-comment-dots"></i> <?php echo (int)$at->reply_count; ?></span>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; endif; ?>
|
||
<?php self::render_forum_footer(); ?>
|
||
|
||
<?php self::render_new_thread_modal(WBF_DB::get_categories_flat(),$current,$cat->id); ?>
|
||
<?php self::render_auth_modal(); ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
// ── THREAD ────────────────────────────────────────────────────────────────
|
||
|
||
private static function view_thread() {
|
||
// Wartungsmodus
|
||
$maint6 = wbf_get_settings()['maintenance_mode'] ?? '0';
|
||
$cur6 = WBF_Auth::get_current_user();
|
||
if ( $maint6 === '1' && ( !$cur6 || WBF_Roles::level($cur6->role) < 50 ) ) {
|
||
return self::view_maintenance();
|
||
}
|
||
$id = (int)($_GET['forum_thread'] ?? 0);
|
||
$thread = WBF_DB::get_thread($id);
|
||
if (!$thread) return '<p class="wbf-notice">Thread nicht gefunden.</p>';
|
||
// Kategorie-Zugang prüfen (Gäste + Min-Rolle)
|
||
$cat6 = WBF_DB::get_category($thread->category_id);
|
||
if ($cat6 && !self::can_see_category($cur6, $cat6)) {
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap"><?php self::render_topbar($cur6); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<div class="wbf-notice wbf-notice--warning">
|
||
<i class="fas fa-lock"></i>
|
||
<?php if (!$cur6): ?>
|
||
Dieser Thread ist nur für eingeloggte Mitglieder sichtbar.
|
||
<a href="#" class="wbf-login-link" style="margin-left:.5rem;font-weight:700">Jetzt einloggen</a>
|
||
<?php else: ?>
|
||
Du hast keine Berechtigung um diesen Thread zu sehen.
|
||
<?php endif; ?>
|
||
</div>
|
||
</div></div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
global $wpdb;
|
||
$wpdb->query($wpdb->prepare("UPDATE {$wpdb->prefix}forum_threads SET views=views+1 WHERE id=%d",$id));
|
||
|
||
$page = max(1,(int)($_GET['tp']??1));
|
||
$posts = WBF_DB::get_posts($id,$page,15);
|
||
$total = WBF_DB::count_posts($id);
|
||
$pages = ceil($total/15) ?: 1;
|
||
$current = WBF_Auth::get_current_user();
|
||
$cat = WBF_DB::get_category($thread->category_id);
|
||
$crumbs = $cat ? WBF_DB::get_category_breadcrumb($cat) : [];
|
||
$t_liked = $current ? WBF_DB::has_liked($current->id,$id,'thread') : false;
|
||
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt" data-thread-view="<?php echo (int)$id; ?>">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_thread','tp'])); ?>"><i class="fas fa-home"></i> Forum</a>
|
||
<?php foreach ($crumbs as $c): ?>
|
||
<span>/</span><a href="?forum_cat=<?php echo esc_attr($c->slug); ?>"><?php echo esc_html($c->name); ?></a>
|
||
<?php endforeach; ?>
|
||
<span>/</span><span><?php echo esc_html(substr($thread->title,0,40)); ?>…</span>
|
||
</nav>
|
||
|
||
<?php echo self::mod_tools_thread($thread,$current); ?>
|
||
|
||
<div class="wbf-thread-header">
|
||
<h1 class="wbf-thread-title">
|
||
<?php if ($thread->pinned): ?><i class="fas fa-thumbtack wbf-pin-icon"></i><?php endif; ?>
|
||
<?php if ($thread->status==='closed'): ?><i class="fas fa-lock" style="color:var(--c-muted);font-size:1rem;margin-right:.35rem"></i><?php endif; ?>
|
||
<?php if ($thread->status==='archived'): ?><span class="wbf-badge wbf-badge--archived"><i class="fas fa-box-archive"></i> Archiviert</span><?php endif; ?>
|
||
<?php echo self::render_prefix($thread); ?>
|
||
<?php echo esc_html($thread->title); ?>
|
||
</h1>
|
||
<div class="wbf-thread-header-meta">
|
||
<?php echo self::like_btn($id,'thread',$thread->like_count,$t_liked); ?>
|
||
<?php if ($current): $is_bm = WBF_DB::is_bookmarked($current->id,$id); ?>
|
||
<button class="wbf-bookmark-btn<?php echo $is_bm?' wbf-bookmarked':''; ?>" data-thread="<?php echo $id; ?>" title="<?php echo $is_bm?'Lesezeichen entfernen':'Lesezeichen hinzufügen'; ?>">
|
||
<i class="fa<?php echo $is_bm?'s':'r'; ?> fa-bookmark"></i>
|
||
</button>
|
||
<?php endif; ?>
|
||
<span><i class="fas fa-comment-dots"></i> <?php echo (int)$thread->reply_count; ?> Antworten</span>
|
||
<span><i class="fas fa-eye"></i> <?php echo (int)$thread->views; ?> Views</span>
|
||
</div>
|
||
<?php $thread_tags = WBF_DB::get_thread_tags($id); echo self::render_tags($thread_tags); ?>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wbf-posts" id="wbfPosts">
|
||
<!-- Poll (optional) -->
|
||
<?php
|
||
$poll = WBF_DB::get_poll($id);
|
||
$can_add_poll = $current && (int)$current->id === (int)$thread->user_id && !$poll && $thread->status === 'open';
|
||
if ($can_add_poll): ?>
|
||
<div style="margin-bottom:1rem">
|
||
<button class="wbf-btn wbf-btn--sm wbf-btn--outline" id="wbfOpenPollModal">
|
||
<i class="fas fa-chart-bar"></i> Umfrage hinzufügen
|
||
</button>
|
||
</div>
|
||
<?php endif;
|
||
if ($poll):
|
||
$results = WBF_DB::get_poll_results($poll->id);
|
||
$my_votes = $current ? WBF_DB::get_user_votes($poll->id, $current->id) : [];
|
||
$total = array_sum($results);
|
||
$voted = !empty($my_votes);
|
||
$expired = $poll->ends_at && strtotime($poll->ends_at) < time();
|
||
$show_results = $voted || $expired || !$current;
|
||
?>
|
||
<div class="wbf-poll" id="wbfPoll-<?php echo (int)$poll->id; ?>" data-poll-id="<?php echo (int)$poll->id; ?>" data-multi="<?php echo (int)$poll->multi; ?>">
|
||
<div class="wbf-poll__header">
|
||
<i class="fas fa-chart-bar"></i>
|
||
<span class="wbf-poll__title"><?php echo esc_html($poll->question); ?></span>
|
||
<?php if ($poll->multi): ?><span class="wbf-poll__badge">Mehrfachauswahl</span><?php endif; ?>
|
||
<?php if ($expired): ?><span class="wbf-poll__badge wbf-poll__badge--ended">Beendet</span><?php endif; ?>
|
||
</div>
|
||
<div class="wbf-poll__body">
|
||
<?php if ($show_results): ?>
|
||
<!-- Ergebnisse -->
|
||
<?php foreach ($poll->options as $i => $opt):
|
||
$votes = $results[$i] ?? 0;
|
||
$pct = $total > 0 ? round($votes / $total * 100) : 0;
|
||
$mine = in_array($i, $my_votes);
|
||
?>
|
||
<div class="wbf-poll__result<?php echo $mine?' wbf-poll__result--mine':''; ?>">
|
||
<div class="wbf-poll__result-bar" style="width:<?php echo $pct; ?>%"></div>
|
||
<div class="wbf-poll__result-content">
|
||
<span class="wbf-poll__result-label"><?php if($mine): ?><i class="fas fa-check-circle" style="color:var(--c-primary)"></i> <?php endif; ?><?php echo esc_html($opt); ?></span>
|
||
<span class="wbf-poll__result-pct"><?php echo $pct; ?>% <span style="color:var(--c-muted);font-size:.75em">(<?php echo $votes; ?>)</span></span>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
<div class="wbf-poll__footer">
|
||
<i class="fas fa-users"></i> <?php echo $total; ?> Stimme<?php echo $total!=1?'n':''; ?>
|
||
<?php if ($poll->ends_at && !$expired): ?>
|
||
· <i class="fas fa-clock"></i> Endet <?php echo esc_html(date_i18n('d.m.Y \u\m H:i \U\h\r', strtotime($poll->ends_at))); ?>
|
||
<?php elseif ($expired): ?>
|
||
· <i class="fas fa-flag-checkered"></i> Abgestimmt
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php else: ?>
|
||
<!-- Abstimmung -->
|
||
<form class="wbf-poll__form" data-poll-id="<?php echo (int)$poll->id; ?>">
|
||
<?php foreach ($poll->options as $i => $opt): ?>
|
||
<label class="wbf-poll__option">
|
||
<input type="<?php echo $poll->multi?'checkbox':'radio'; ?>"
|
||
name="wbf_poll_option" value="<?php echo $i; ?>"
|
||
style="accent-color:var(--c-primary)">
|
||
<?php echo esc_html($opt); ?>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
<div style="display:flex;align-items:center;gap:.75rem;margin-top:.75rem">
|
||
<button type="submit" class="wbf-btn wbf-btn--sm wbf-btn--primary">
|
||
<i class="fas fa-vote-yea"></i> Abstimmen
|
||
</button>
|
||
<span class="wbf-poll__msg wbf-msg"></span>
|
||
</div>
|
||
</form>
|
||
<?php if ($poll->ends_at): ?>
|
||
<div class="wbf-poll__footer">
|
||
<i class="fas fa-clock"></i> Endet <?php echo esc_html(date_i18n('d.m.Y \u\m H:i \U\h\r', strtotime($poll->ends_at))); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php
|
||
$op_reported = $current ? WBF_DB::has_reported($current->id, $id, 'thread') : false;
|
||
$op_can_edit = $current && ((int)$current->id === (int)$thread->user_id || WBF_DB::can($current,'delete_post'));
|
||
?>
|
||
<div class="wbf-post wbf-post--op">
|
||
<div class="wbf-post__sidebar">
|
||
<?php $op_online = WBF_DB::is_online((int)$thread->user_id); echo self::avatar($thread->avatar_url,$thread->display_name,52,$op_online); ?>
|
||
<strong><?php echo esc_html($thread->display_name); ?></strong>
|
||
<?php echo self::role_badge($thread->author_role); ?>
|
||
<?php echo WBF_Levels::badge((int)$thread->author_posts); ?>
|
||
<span class="wbf-post__meta-small"><?php echo (int)$thread->author_posts; ?> Beiträge</span>
|
||
<span class="wbf-post__meta-small"><?php echo date_i18n('d.m.Y', strtotime($thread->author_registered)); ?></span>
|
||
</div>
|
||
<div class="wbf-post__body">
|
||
<div class="wbf-post__content" id="wbf-thread-content-<?php echo (int)$id; ?>"><?php echo WBF_BBCode::render($thread->content); ?></div>
|
||
<div id="wbf-thread-edit-<?php echo (int)$id; ?>" style="display:none;margin-top:.75rem">
|
||
<input type="text" class="wbf-edit-title-input" value="<?php echo esc_attr($thread->title); ?>"
|
||
style="width:100%;padding:.6rem;border:1px solid var(--c-border,rgba(255,255,255,.14));border-radius:6px;font-size:.95rem;font-weight:700;margin-bottom:.5rem;box-sizing:border-box;background:var(--c-bg2,#161a22);color:var(--c-text,#e8eaf0)">
|
||
<textarea class="wbf-edit-textarea" rows="7"
|
||
style="width:100%;padding:.6rem;border:1px solid var(--c-border,#e2e8f0);border-radius:6px;font-size:.9rem;resize:vertical;box-sizing:border-box"><?php echo esc_textarea($thread->content); ?></textarea>
|
||
<div style="display:flex;gap:.6rem;margin-top:.5rem;align-items:center">
|
||
<button class="wbf-btn wbf-btn--primary wbf-btn--sm wbf-save-thread-btn" data-id="<?php echo (int)$id; ?>">
|
||
<i class="fas fa-save"></i> Speichern
|
||
</button>
|
||
<button class="wbf-btn wbf-btn--sm wbf-cancel-thread-btn" data-id="<?php echo (int)$id; ?>">Abbrechen</button>
|
||
<span class="wbf-edit-msg" style="font-size:.85rem"></span>
|
||
</div>
|
||
</div>
|
||
<?php if (!empty($thread->signature)): ?>
|
||
<div class="wbf-signature"><div class="wbf-signature__divider"></div><?php echo WBF_BBCode::render($thread->signature); ?></div>
|
||
<?php endif; ?>
|
||
<div class="wbf-post__footer">
|
||
<span class="wbf-post__date"><?php echo self::time_ago($thread->created_at); ?></span>
|
||
<div style="display:flex;gap:.5rem;align-items:center;flex-wrap:wrap">
|
||
<?php if ($current): ?>
|
||
<?php $is_subbed = WBF_DB::is_subscribed($current->id, $id); ?>
|
||
<button class="wbf-subscribe-btn wbf-btn wbf-btn--sm<?php echo $is_subbed?' wbf-btn--primary':''; ?>"
|
||
data-thread="<?php echo (int)$id; ?>"
|
||
title="<?php echo $is_subbed?'Abonnement entfernen':'Thread abonnieren'; ?>">
|
||
<i class="fas fa-bell<?php echo $is_subbed?'':'-slash'; ?>"></i>
|
||
<?php echo $is_subbed?'Abonniert':'Abonnieren'; ?>
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php if ($current && WBF_DB::can($current,'post') && $thread->status !== 'closed'): ?>
|
||
<button class="wbf-quote-btn"
|
||
data-source="wbf-thread-content-<?php echo (int)$id; ?>"
|
||
data-author="<?php echo esc_attr($thread->display_name); ?>"
|
||
title="Zitieren">
|
||
<i class="fas fa-quote-left"></i> Zitieren
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php if ($current && !$op_reported): ?>
|
||
<button class="wbf-report-btn" data-id="<?php echo (int)$id; ?>" data-type="thread" title="Thread melden">
|
||
<i class="fas fa-flag"></i>
|
||
</button>
|
||
<?php elseif ($op_reported): ?>
|
||
<span class="wbf-reported-label" title="Bereits gemeldet"><i class="fas fa-flag"></i></span>
|
||
<?php endif; ?>
|
||
<?php if ($op_can_edit): ?>
|
||
<button class="wbf-edit-thread-btn"
|
||
data-id="<?php echo (int)$id; ?>"
|
||
style="display:inline-flex;align-items:center;gap:.3rem;background:none;border:1.5px solid var(--c-border,#e2e8f0);cursor:pointer;color:var(--c-muted,#94a3b8);padding:3px 8px;border-radius:4px;font-size:.82rem"
|
||
title="Thread bearbeiten">
|
||
<i class="fas fa-pen"></i> Bearbeiten
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php
|
||
// Ignore-Button: nur wenn der Thread-Autor nicht der eingeloggte User ist
|
||
// und die Rolle blockiert werden darf (konfigurierbar in Einstellungen)
|
||
$op_author = WBF_DB::get_user((int)$thread->user_id);
|
||
if ($current && (int)$current->id !== (int)$thread->user_id && wbf_can_be_ignored($op_author)):
|
||
$op_is_ignored = WBF_DB::is_ignored($current->id, (int)$thread->user_id);
|
||
?>
|
||
<button class="wbf-ignore-btn"
|
||
data-id="<?php echo (int)$thread->user_id; ?>"
|
||
data-name="<?php echo esc_attr($thread->display_name); ?>"
|
||
data-ignored="<?php echo $op_is_ignored ? '1' : '0'; ?>"
|
||
title="<?php echo $op_is_ignored ? 'Ignorierung aufheben' : 'Nutzer ignorieren'; ?>"
|
||
style="background:none;border:none;cursor:pointer;color:var(--c-muted,#94a3b8);padding:2px 6px;border-radius:4px;font-size:.82rem">
|
||
<i class="fas fa-<?php echo $op_is_ignored ? 'eye' : 'eye-slash'; ?>"></i>
|
||
<?php echo $op_is_ignored ? 'Entblocken' : 'Ignorieren'; ?>
|
||
</button>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<?php foreach ($posts as $post):
|
||
$p_liked = $current ? WBF_DB::has_liked($current->id,$post->id,'post') : false;
|
||
self::render_single_post($post,$current,$p_liked);
|
||
endforeach; ?>
|
||
</div>
|
||
|
||
<?php if ($pages>1): ?>
|
||
<div class="wbf-pagination">
|
||
<?php for ($i=1;$i<=$pages;$i++): ?>
|
||
<a href="?forum_thread=<?php echo $id; ?>&tp=<?php echo $i; ?>" class="wbf-page-btn<?php echo ($i==$page)?' active':''; ?>"><?php echo $i; ?></a>
|
||
<?php endfor; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($thread->status==='open'): ?>
|
||
<div class="wbf-reply-box" id="wbfReplyBox">
|
||
<h3 class="wbf-reply-box__title"><i class="fas fa-reply"></i> Antworten</h3>
|
||
<?php if (WBF_DB::can($current,'post')): ?>
|
||
<div class="wbf-reply-form">
|
||
<div class="wbf-reply-form__avatar"><?php echo self::avatar($current->avatar_url,$current->display_name,44); ?></div>
|
||
<div class="wbf-reply-form__input">
|
||
<?php self::render_editor_toolbar('wbfReplyContent'); ?>
|
||
<textarea id="wbfReplyContent" placeholder="Deine Antwort…" rows="5"></textarea>
|
||
<div class="wbf-reply-form__actions">
|
||
<span class="wbf-reply-counter" id="wbfReplyCounter">0 Zeichen</span>
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSubmitReply" data-thread="<?php echo $id; ?>"><i class="fas fa-paper-plane"></i> Senden</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php else: ?>
|
||
<div class="wbf-notice wbf-notice--info"><i class="fas fa-info-circle"></i>
|
||
<a href="#" class="wbf-login-link">Einloggen</a> oder <a href="#" class="wbf-register-link">Registrieren</a> um zu antworten.
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php else: ?>
|
||
<div class="wbf-notice wbf-notice--warning"><i class="fas fa-lock"></i> Dieser Thread ist geschlossen.</div>
|
||
<?php endif; ?>
|
||
<?php self::render_forum_footer(); ?>
|
||
</div>
|
||
<?php self::render_auth_modal(); ?>
|
||
<?php self::render_report_modal(); ?>
|
||
<?php if (WBF_DB::can($current,'manage_cats')): self::render_move_modal(WBF_DB::get_categories_flat(), $id); endif; ?>
|
||
<?php if ($can_add_poll): self::render_poll_modal($id); endif; ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
public static function render_single_post( $post, $current = null, $liked = false ) {
|
||
$already_reported = $current ? WBF_DB::has_reported($current->id, $post->id, 'post') : false;
|
||
?>
|
||
<div class="wbf-post" id="post-<?php echo (int)$post->id; ?>"
|
||
data-created="<?php echo esc_attr($post->created_at); ?>">
|
||
<div class="wbf-post__sidebar">
|
||
<?php $p_online = WBF_DB::is_online((int)$post->user_id); echo self::avatar($post->avatar_url,$post->display_name,52,$p_online); ?>
|
||
<strong><?php echo esc_html($post->display_name); ?></strong>
|
||
<?php echo self::role_badge($post->author_role); ?>
|
||
<?php echo WBF_Levels::badge((int)$post->author_posts); ?>
|
||
<span class="wbf-post__meta-small"><?php echo (int)$post->author_posts; ?> Beiträge</span>
|
||
<span class="wbf-post__meta-small"><?php echo date_i18n('d.m.Y', strtotime($post->author_registered)); ?></span>
|
||
</div>
|
||
<div class="wbf-post__body">
|
||
<div class="wbf-post__new-label"><i class="fas fa-circle-dot"></i> Neu</div>
|
||
<div class="wbf-post__content" id="wbf-post-content-<?php echo (int)$post->id; ?>"><?php echo WBF_BBCode::render($post->content); ?></div>
|
||
<div class="wbf-post__edit-wrap" id="wbf-post-edit-<?php echo (int)$post->id; ?>" style="display:none;margin-top:.75rem">
|
||
<textarea class="wbf-edit-textarea" rows="6"
|
||
style="width:100%;padding:.6rem;border:1px solid var(--c-border,#e2e8f0);border-radius:6px;font-size:.9rem;resize:vertical;box-sizing:border-box"
|
||
><?php echo esc_textarea($post->content); ?></textarea>
|
||
<div style="display:flex;gap:.6rem;margin-top:.5rem;align-items:center">
|
||
<button class="wbf-btn wbf-btn--primary wbf-btn--sm wbf-save-edit-btn"
|
||
data-id="<?php echo (int)$post->id; ?>">
|
||
<i class="fas fa-save"></i> Speichern
|
||
</button>
|
||
<button class="wbf-btn wbf-btn--sm wbf-cancel-edit-btn" data-id="<?php echo (int)$post->id; ?>">Abbrechen</button>
|
||
<span class="wbf-edit-msg" style="font-size:.85rem"></span>
|
||
</div>
|
||
</div>
|
||
<?php if (!empty($post->signature)): ?>
|
||
<div class="wbf-signature"><div class="wbf-signature__divider"></div><?php echo WBF_BBCode::render($post->signature); ?></div>
|
||
<?php endif; ?>
|
||
<div class="wbf-post__footer">
|
||
<span class="wbf-post__date"><?php echo self::time_ago($post->created_at); ?></span>
|
||
<div style="display:flex;gap:.5rem;align-items:center;flex-wrap:wrap">
|
||
<?php echo self::reaction_bar($post->id, 'post', $current); ?>
|
||
<?php if ($current && WBF_DB::can($current,'post')): ?>
|
||
<button class="wbf-quote-btn"
|
||
data-source="wbf-post-content-<?php echo (int)$post->id; ?>"
|
||
data-author="<?php echo esc_attr($post->display_name); ?>"
|
||
title="Zitieren">
|
||
<i class="fas fa-quote-left"></i> Zitieren
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php if ($current && !$already_reported): ?>
|
||
<button class="wbf-report-btn" data-id="<?php echo (int)$post->id; ?>" data-type="post" title="Beitrag melden">
|
||
<i class="fas fa-flag"></i>
|
||
</button>
|
||
<?php elseif ($already_reported): ?>
|
||
<span class="wbf-reported-label" title="Bereits gemeldet"><i class="fas fa-flag"></i></span>
|
||
<?php endif; ?>
|
||
<?php if ($current && ((int)$current->id === (int)$post->user_id || WBF_DB::can($current,'delete_post'))): ?>
|
||
<button class="wbf-edit-post-btn"
|
||
data-id="<?php echo (int)$post->id; ?>"
|
||
style="background:none;border:none;cursor:pointer;color:var(--c-muted,#94a3b8);padding:2px 6px;border-radius:4px;font-size:.82rem"
|
||
title="Beitrag bearbeiten">
|
||
<i class="fas fa-pen"></i> Bearbeiten
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php
|
||
// Ignore-Button im Post-Footer
|
||
$post_author = WBF_DB::get_user((int)$post->user_id);
|
||
if ($current && (int)$current->id !== (int)$post->user_id && wbf_can_be_ignored($post_author)):
|
||
$post_is_ignored = WBF_DB::is_ignored($current->id, (int)$post->user_id);
|
||
?>
|
||
<button class="wbf-ignore-btn"
|
||
data-id="<?php echo (int)$post->user_id; ?>"
|
||
data-name="<?php echo esc_attr($post->display_name); ?>"
|
||
data-ignored="<?php echo $post_is_ignored ? '1' : '0'; ?>"
|
||
title="<?php echo $post_is_ignored ? 'Ignorierung aufheben' : 'Nutzer ignorieren'; ?>"
|
||
style="background:none;border:none;cursor:pointer;color:var(--c-muted,#94a3b8);padding:2px 6px;border-radius:4px;font-size:.82rem">
|
||
<i class="fas fa-<?php echo $post_is_ignored ? 'eye' : 'eye-slash'; ?>"></i>
|
||
<?php echo $post_is_ignored ? 'Entblocken' : 'Ignorieren'; ?>
|
||
</button>
|
||
<?php endif; ?>
|
||
<?php echo self::mod_tools_post($post->id,$current); ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
// ── PROFILE ───────────────────────────────────────────────────────────────
|
||
|
||
private static function view_profile() {
|
||
$profile_id = (int)($_GET['forum_profile'] ?? 0);
|
||
$current = WBF_Auth::get_current_user();
|
||
$profile = $profile_id ? WBF_DB::get_user($profile_id) : $current;
|
||
if (!$profile) return '<p class="wbf-notice">Profil nicht gefunden.</p>';
|
||
$is_own = $current && $current->id == $profile->id;
|
||
$is_staff = $current && WBF_Roles::level($current->role) >= 50;
|
||
// Profil-Sichtbarkeit prüfen
|
||
// profile_public NULL = Spalte fehlt noch = als öffentlich (1) behandeln
|
||
$profile_public = isset($profile->profile_public) ? (int)$profile->profile_public : 1;
|
||
if (!$is_own && !$is_staff && $profile_public === 0) {
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap"><?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<div class="wbf-notice wbf-notice--warning">
|
||
<i class="fas fa-user-lock"></i> Dieses Profil ist nicht öffentlich.
|
||
</div>
|
||
</div></div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
$user_posts = WBF_DB::get_user_posts( $profile->id, 50 );
|
||
$bookmarks = $is_own ? WBF_DB::get_user_bookmarks($current->id, 50) : [];
|
||
$ignore_list = $is_own ? WBF_DB::get_ignore_list($current->id) : [];
|
||
$cf_defs = WBF_DB::get_profile_field_defs();
|
||
$cf_cats = WBF_DB::get_profile_field_categories();
|
||
$cf_cat_map = array_column( $cf_cats, null, 'id' );
|
||
$cf_vals = WBF_DB::get_user_meta( $profile->id );
|
||
// Aktiven Tab aus URL lesen (tab=1|2|3), Standard: 1 für eigenes, 2 für fremdes
|
||
// Tab-ID: numerisch (1–4) oder String-Slug (z.B. 'mc' von der Forum-Bridge)
|
||
$ptab_raw = $_GET['ptab'] ?? ($is_own ? 1 : 2);
|
||
$shop_active = class_exists('WIS_DB');
|
||
$shop_tab_id = 'shop';
|
||
$allowed_tabs = [1,2,3,4];
|
||
if ($is_own && $shop_active) $allowed_tabs[] = $shop_tab_id;
|
||
$active_tab = ctype_digit( (string) $ptab_raw ) ? (int) $ptab_raw : sanitize_key( $ptab_raw );
|
||
if (is_int($active_tab) && !in_array($active_tab, [1,2,3,4])) {
|
||
$active_tab = $is_own ? 1 : 2;
|
||
}
|
||
if (!is_int($active_tab) && $active_tab !== $shop_tab_id && $active_tab !== 'mc') {
|
||
$active_tab = $is_own ? 1 : 2;
|
||
}
|
||
// Tab 1, 3, 4, "shop" und String-Tabs nur für eigenes Profil (außer Tab 2 = Aktivität)
|
||
if (!$is_own && $active_tab !== 2) $active_tab = 2;
|
||
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_profile', 'ptab'])); ?>"><i class="fas fa-home"></i> Forum</a>
|
||
<span>/</span><span>Profil</span>
|
||
</nav>
|
||
|
||
<div class="wbf-profile-layout">
|
||
|
||
<!-- ── SIDEBAR ─────────────────────────────────────────── -->
|
||
<aside class="wbf-profile-sidebar">
|
||
<!-- Banner -->
|
||
<div class="wbf-profile-banner" id="wbfProfileBannerWrap">
|
||
<?php if ( ! empty($profile->banner_url) ) : ?>
|
||
<img src="<?php echo esc_url($profile->banner_url); ?>"
|
||
alt="" id="wbfProfileBanner" class="wbf-profile-banner__img">
|
||
<?php else : ?>
|
||
<div class="wbf-profile-banner__placeholder"></div>
|
||
<?php endif; ?>
|
||
<?php if ($is_own) : ?>
|
||
<label class="wbf-banner-upload-btn" title="Banner ändern">
|
||
<i class="fas fa-image"></i>
|
||
<input type="file" id="wbfBannerFile" accept="image/*" style="display:none">
|
||
</label>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="wbf-profile-sidebar__avatar-wrap">
|
||
<img src="<?php echo esc_url($profile->avatar_url); ?>"
|
||
alt="<?php echo esc_attr($profile->display_name); ?>"
|
||
id="wbfProfileAvatar"
|
||
class="wbf-profile-sidebar__avatar">
|
||
<?php if ($is_own): ?>
|
||
<label class="wbf-avatar-upload-btn" title="Avatar ändern">
|
||
<i class="fas fa-camera"></i>
|
||
<input type="file" id="wbfAvatarFile" accept="image/*" style="display:none">
|
||
</label>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="wbf-profile-sidebar__identity">
|
||
<h2><?php echo esc_html($profile->display_name); ?></h2>
|
||
<?php echo self::role_badge($profile->role); ?>
|
||
<span class="wbf-profile-sidebar__username">@<?php echo esc_html($profile->username); ?></span>
|
||
<?php
|
||
$profile_online = WBF_DB::is_online($profile->id, 15);
|
||
if ($profile_online): ?>
|
||
<span class="wbf-profile-online-badge">
|
||
<span class="wbf-profile-online-dot"></span> Online
|
||
</span>
|
||
<?php else:
|
||
$last = $profile->last_active ?? null;
|
||
if ($last && $last !== '0000-00-00 00:00:00'): ?>
|
||
<span class="wbf-profile-lastseen">
|
||
<i class="fas fa-clock"></i> Zuletzt aktiv: <?php echo self::time_ago($last); ?>
|
||
</span>
|
||
<?php endif; endif; ?>
|
||
</div>
|
||
<div class="wbf-profile-sidebar__stats">
|
||
<div class="wbf-profile-sidebar__stat">
|
||
<span><?php echo (int)$profile->post_count; ?></span>
|
||
<em>Beiträge</em>
|
||
</div>
|
||
<div class="wbf-profile-sidebar__stat">
|
||
<span><?php echo date_i18n('m/Y', strtotime($profile->registered)); ?></span>
|
||
<em>Dabei seit</em>
|
||
</div>
|
||
</div>
|
||
<?php $level_bar = WBF_Levels::progress_bar((int)$profile->post_count); if ($level_bar): ?>
|
||
<div class="wbf-profile-sidebar__section"><?php echo $level_bar; ?></div>
|
||
<?php endif; ?>
|
||
<?php if (!empty($profile->bio)): ?>
|
||
<div class="wbf-profile-sidebar__section">
|
||
<span class="wbf-profile-sidebar__section-label"><i class="fas fa-align-left"></i> Bio</span>
|
||
<div class="wbf-profile-sidebar__bio-text"><?php echo WBF_BBCode::render($profile->bio); ?></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if (!empty($profile->signature)): ?>
|
||
<div class="wbf-profile-sidebar__section">
|
||
<span class="wbf-profile-sidebar__section-label"><i class="fas fa-pen-nib"></i> Signatur</span>
|
||
<div class="wbf-profile-sidebar__sig"><?php echo WBF_BBCode::render($profile->signature); ?></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<!-- Öffentliche Custom Fields — nach Kategorie gruppiert -->
|
||
<?php
|
||
$cf_by_cat_sb = [];
|
||
foreach ( $cf_defs as $def_sb ) {
|
||
if (!$is_own && empty($def_sb['public'])) continue;
|
||
$val_sb = trim($cf_vals[$def_sb['key']] ?? '');
|
||
if ($val_sb === '') continue;
|
||
$cid_sb = $def_sb['category_id'] ?? '';
|
||
if (!$cid_sb || !isset($cf_cat_map[$cid_sb])) $cid_sb = '__none__';
|
||
$cf_by_cat_sb[$cid_sb][] = ['def'=>$def_sb,'val'=>$val_sb];
|
||
}
|
||
$sb_sections = $cf_cats;
|
||
if (isset($cf_by_cat_sb['__none__'])) {
|
||
$sb_sections[] = ['id'=>'__none__','name'=>'Weitere Infos','icon'=>''];
|
||
}
|
||
foreach ($sb_sections as $scat_sb):
|
||
$scid_sb = $scat_sb['id'];
|
||
if (empty($cf_by_cat_sb[$scid_sb])) continue;
|
||
?>
|
||
<div class="wbf-profile-sidebar__section">
|
||
<span class="wbf-profile-sidebar__section-label" style="display:flex;align-items:center;gap:5px;margin-bottom:4px">
|
||
<?php if(!empty($scat_sb['icon'])): ?>
|
||
<span style="font-size:.9rem"><?php echo esc_html($scat_sb['icon']); ?></span>
|
||
<?php endif; ?>
|
||
<?php echo esc_html($scat_sb['name']); ?>
|
||
</span>
|
||
<?php foreach ($cf_by_cat_sb[$scid_sb] as $cf_entry_sb):
|
||
$def_sb = $cf_entry_sb['def'];
|
||
$val_sb = $cf_entry_sb['val'];
|
||
// Auto-Link für Telegram und Discord anhand des Feld-Keys erkennen
|
||
$key_sb = strtolower($def_sb['key']);
|
||
$is_telegram = strpos($key_sb, 'telegram') !== false;
|
||
$is_discord = strpos($key_sb, 'discord') !== false;
|
||
?>
|
||
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:6px;margin-bottom:4px;font-size:.85rem">
|
||
<span style="color:var(--c-muted,#94a3b8);flex-shrink:0"><?php echo esc_html($def_sb['label']); ?></span>
|
||
<?php if ($def_sb['type'] === 'url'): ?>
|
||
<a href="<?php echo esc_url($val_sb); ?>" target="_blank" rel="noopener noreferrer"
|
||
style="color:var(--c-primary);word-break:break-all;text-align:right">
|
||
<?php echo esc_html(mb_strtolower(preg_replace('#^https?://#i','',$val_sb))); ?>
|
||
</a>
|
||
<?php elseif ($is_telegram):
|
||
// Username bereinigen: @ und Leerzeichen entfernen
|
||
$tg_user = ltrim(trim($val_sb), '@');
|
||
$tg_url = 'https://t.me/' . rawurlencode($tg_user);
|
||
?>
|
||
<a href="<?php echo esc_url($tg_url); ?>" target="_blank" rel="noopener noreferrer"
|
||
style="color:#29b6f6;text-align:right;font-size:inherit">
|
||
@<?php echo esc_html($tg_user); ?>
|
||
</a>
|
||
<?php elseif ($is_discord): ?>
|
||
<span style="color:#7289da;text-align:right;font-size:inherit">
|
||
<?php echo esc_html($val_sb); ?>
|
||
</span>
|
||
<?php elseif ($def_sb['type'] === 'textarea'): ?>
|
||
<span style="text-align:right"><?php echo nl2br(esc_html($val_sb)); ?></span>
|
||
<?php elseif ($def_sb['type'] === 'date'):
|
||
$age_sb = self::calc_age($val_sb); ?>
|
||
<span><?php echo $age_sb !== null ? esc_html((string)$age_sb) . ' Jahre' : '—'; ?></span>
|
||
<?php else: ?>
|
||
<span style="text-align:right"><?php echo esc_html($val_sb); ?></span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</aside>
|
||
|
||
<!-- ── MAIN ────────────────────────────────────────────── -->
|
||
<div class="wbf-profile-main">
|
||
|
||
<!-- DM-Button + Ignorieren-Button (nur auf fremden Profilen) -->
|
||
<?php if ($current && !$is_own && WBF_Roles::level($profile->role) >= 0): ?>
|
||
<div style="display:flex;justify-content:flex-end;gap:.5rem;margin-bottom:.75rem;flex-wrap:wrap">
|
||
<a href="?forum_dm=inbox&with=<?php echo (int)$profile->id; ?>"
|
||
class="wbf-btn wbf-btn--sm wbf-btn--primary">
|
||
<i class="fas fa-envelope"></i> Nachricht senden
|
||
</a>
|
||
<?php if ( wbf_can_be_ignored($profile) ):
|
||
$viewer_ignores = WBF_DB::is_ignored($current->id, $profile->id); ?>
|
||
<button class="wbf-ignore-btn wbf-btn wbf-btn--sm<?php echo $viewer_ignores?' wbf-btn--primary':''; ?>"
|
||
data-id="<?php echo (int)$profile->id; ?>"
|
||
data-name="<?php echo esc_attr($profile->display_name); ?>"
|
||
data-ignored="<?php echo $viewer_ignores?'1':'0'; ?>">
|
||
<i class="fas fa-<?php echo $viewer_ignores?'eye':'eye-slash'; ?>"></i>
|
||
<?php echo $viewer_ignores?'Ignorierung aufheben':'Nutzer ignorieren'; ?>
|
||
</button>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<!-- ── TAB-NAVIGATION ─────────────────────────────── -->
|
||
<?php if ($is_own): ?>
|
||
<div class="wbf-profile-tabs">
|
||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=1"
|
||
class="wbf-profile-tab<?php echo $active_tab===1?' active':''; ?>">
|
||
<i class="fas fa-sliders"></i> Profil
|
||
</a>
|
||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=2"
|
||
class="wbf-profile-tab<?php echo $active_tab===2?' active':''; ?>">
|
||
<i class="fas fa-comments"></i> Aktivität
|
||
</a>
|
||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=3"
|
||
class="wbf-profile-tab<?php echo $active_tab===3?' active':''; ?>">
|
||
<i class="fas fa-shield-halved"></i> Privatsphäre
|
||
</a>
|
||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=4"
|
||
class="wbf-profile-tab<?php echo $active_tab===4?' active':''; ?>">
|
||
<i class="fas fa-lock"></i> Sicherheit
|
||
</a>
|
||
<?php if ($shop_active): ?>
|
||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=shop"
|
||
class="wbf-profile-tab<?php echo $active_tab==='shop'?' active':''; ?>">
|
||
<i class="fas fa-shopping-cart"></i> Käufe
|
||
</a>
|
||
<?php endif; ?>
|
||
<?php
|
||
// „Verbindungen" Tab — immer sichtbar (Discord eingebaut, MC optional)
|
||
$wbf_has_connections = true;
|
||
if ( $wbf_has_connections ) : ?>
|
||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=mc"
|
||
class="wbf-profile-tab<?php echo $active_tab==='mc'?' active':''; ?>">
|
||
<i class="fas fa-plug"></i> Verbindungen
|
||
</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<!-- ══════════════════════════════════════════════════
|
||
TAB SHOP — Käufe (Shop-Plugin)
|
||
══════════════════════════════════════════════════ -->
|
||
<?php if ($is_own && $active_tab === 'shop' && $shop_active): ?>
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-shopping-cart"></i> Deine Käufe
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<?php
|
||
$orders = [];
|
||
if (class_exists('WIS_DB')) {
|
||
global $wpdb;
|
||
$username = $profile->username;
|
||
$orders = $wpdb->get_results($wpdb->prepare(
|
||
"SELECT * FROM {$wpdb->prefix}wis_orders WHERE player_name = %s ORDER BY created_at DESC",
|
||
$username
|
||
));
|
||
}
|
||
?>
|
||
<?php if (empty($orders)): ?>
|
||
<p class="wbf-profile-empty">Du hast noch keine Käufe getätigt.</p>
|
||
<?php else: ?>
|
||
<div class="wbf-shop-orders-list">
|
||
<table class="wbf-shop-orders-table">
|
||
<thead>
|
||
<tr>
|
||
<th style="text-align:left">Datum</th>
|
||
<th style="text-align:center">Anzahl</th>
|
||
<th style="text-align:right">Gesamtpreis</th>
|
||
<th></th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach ($orders as $i => $order):
|
||
$is_cancelled = strtolower($order->status) === 'cancelled' || strtolower($order->status) === 'storniert';
|
||
$row_class = $is_cancelled ? 'wbf-shop-order-cancelled' : '';
|
||
?>
|
||
<tr class="wbf-shop-order-row <?php echo $row_class; ?>" data-idx="<?php echo $i; ?>">
|
||
<td><?php echo date_i18n('d.m.Y H:i', strtotime($order->created_at)); ?></td>
|
||
<td style="text-align:center"><?php echo (int)$order->quantity; ?></td>
|
||
<td style="text-align:right"><?php echo number_format($order->price * $order->quantity); ?> <?php echo esc_html(get_option('wis_currency_name', 'Coins')); ?></td>
|
||
<td style="text-align:center">
|
||
<button class="wbf-btn wbf-btn--sm wbf-shop-order-toggle" data-idx="<?php echo $i; ?>"><i class="fas fa-chevron-down"></i></button>
|
||
</td>
|
||
</tr>
|
||
<tr class="wbf-shop-order-details" id="wbf-shop-order-details-<?php echo $i; ?>" style="display:none">
|
||
<td colspan="4">
|
||
<div class="wbf-shop-order-details-inner">
|
||
<?php /* Artikel-Zeile entfernt, da Item-Liste folgt */ ?>
|
||
<strong>Einzelpreis:</strong> <?php echo number_format($order->price); ?> <?php echo esc_html(get_option('wis_currency_name', 'Coins')); ?><br>
|
||
<strong>Status:</strong> <?php echo esc_html(ucfirst($order->status)); ?><br>
|
||
<?php if (!empty($order->server)): ?><strong>Server:</strong> <?php echo esc_html($order->server); ?><br><?php endif; ?>
|
||
<?php
|
||
// Antwort als JSON-Items/Coupon anzeigen
|
||
$response = $order->response;
|
||
$decoded = null;
|
||
if (!empty($response)) {
|
||
$decoded = json_decode($response, true);
|
||
}
|
||
if (is_array($decoded) && isset($decoded['items'])) {
|
||
echo '<strong>Gekaufte Items:</strong><ul style="margin:.3em 0 .7em 1.2em">';
|
||
foreach ($decoded['items'] as $item) {
|
||
$item_id = isset($item['id']) ? $item['id'] : '';
|
||
$item_id = preg_replace('/^minecraft:/', '', $item_id);
|
||
$amount = isset($item['amount']) ? (int)$item['amount'] : 1;
|
||
echo '<li><span style="color:var(--c-primary)">' . esc_html($item_id) . '</span> <span style="color:var(--c-muted)">x' . $amount . '</span></li>';
|
||
}
|
||
echo '</ul>';
|
||
if (isset($decoded['coupon']['code'])) {
|
||
$c = $decoded['coupon'];
|
||
echo '<div style="margin:.2em 0 .5em 0"><strong>Coupon:</strong> <span style="color:var(--c-success)">' . esc_html($c['code']) . '</span>';
|
||
if (isset($c['discount'])) echo ' <span style="color:var(--c-muted)">(' . intval($c['discount']) . '% Rabatt)</span>';
|
||
echo '</div>';
|
||
}
|
||
} elseif (!empty($response)) {
|
||
echo '<strong>Antwort:</strong> ' . esc_html($response) . '<br>';
|
||
}
|
||
?>
|
||
<span style="font-size:.85em;color:var(--c-muted)">Bestell-ID: <?php echo (int)$order->id; ?></span>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
document.querySelectorAll('.wbf-shop-order-toggle').forEach(function(btn) {
|
||
btn.addEventListener('click', function() {
|
||
var idx = btn.getAttribute('data-idx');
|
||
var details = document.getElementById('wbf-shop-order-details-' + idx);
|
||
if (details.style.display === 'none') {
|
||
details.style.display = '';
|
||
btn.querySelector('i').classList.remove('fa-chevron-down');
|
||
btn.querySelector('i').classList.add('fa-chevron-up');
|
||
} else {
|
||
details.style.display = 'none';
|
||
btn.querySelector('i').classList.remove('fa-chevron-up');
|
||
btn.querySelector('i').classList.add('fa-chevron-down');
|
||
}
|
||
});
|
||
});
|
||
});
|
||
</script>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<!-- ══════════════════════════════════════════════════
|
||
TAB 1 — Profil bearbeiten + Weitere Profilangaben
|
||
══════════════════════════════════════════════════ -->
|
||
<?php if ($is_own && $active_tab === 1): ?>
|
||
|
||
<!-- Profil bearbeiten -->
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-sliders"></i> Profil bearbeiten
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<div class="wbf-form-row">
|
||
<label>Anzeigename</label>
|
||
<input type="text" id="wbfEditName" value="<?php echo esc_attr($profile->display_name); ?>">
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Bio</label>
|
||
<?php self::render_editor_toolbar('wbfEditBio'); ?>
|
||
<textarea id="wbfEditBio" rows="2"><?php echo esc_textarea($profile->bio); ?></textarea>
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Signatur <small>(max. 300 Zeichen)</small></label>
|
||
<?php self::render_editor_toolbar('wbfEditSignature'); ?>
|
||
<textarea id="wbfEditSignature" rows="2" maxlength="300" placeholder="Deine Signatur…"><?php echo esc_textarea($profile->signature ?? ''); ?></textarea>
|
||
<div class="wbf-sig-counter"><span id="wbfSigCount"><?php echo mb_strlen($profile->signature??''); ?></span>/300</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Weitere Profilangaben — nach Kategorie gruppiert (ohne eigene Speichern-Buttons) -->
|
||
<?php
|
||
$cf_edit_by_cat = [];
|
||
foreach ( $cf_defs as $def_e ) {
|
||
$cid_e = $def_e['category_id'] ?? '';
|
||
if (!$cid_e || !isset($cf_cat_map[$cid_e])) $cid_e = '__none__';
|
||
$cf_edit_by_cat[$cid_e][] = $def_e;
|
||
}
|
||
$edit_sections = $cf_cats;
|
||
if (isset($cf_edit_by_cat['__none__'])) {
|
||
$edit_sections[] = ['id'=>'__none__','name'=>'Weitere Angaben','icon'=>'📋'];
|
||
}
|
||
if (!empty($cf_defs)):
|
||
foreach ($edit_sections as $ecat):
|
||
$ecid = $ecat['id'];
|
||
if (empty($cf_edit_by_cat[$ecid])) continue;
|
||
?>
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<?php if(!empty($ecat['icon'])): ?>
|
||
<span style="margin-right:5px"><?php echo esc_html($ecat['icon']); ?></span>
|
||
<?php else: ?><i class="fas fa-sliders"></i><?php endif; ?>
|
||
<?php echo esc_html($ecat['name']); ?>
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<div class="wbf-profile-edit-grid">
|
||
<?php foreach ($cf_edit_by_cat[$ecid] as $def):
|
||
$k = esc_attr($def['key']);
|
||
$lbl = esc_html($def['label']);
|
||
$ph = esc_attr($def['placeholder'] ?? '');
|
||
$val = esc_attr($cf_vals[$def['key']] ?? '');
|
||
$req = !empty($def['required']) ? 'required' : '';
|
||
?>
|
||
<div class="wbf-form-row">
|
||
<label><?php echo $lbl; ?><?php if($req): ?> <span style="color:var(--c-danger)">*</span><?php endif; ?></label>
|
||
<?php if ($def['type'] === 'textarea'): ?>
|
||
<textarea class="wbf-cf-input" data-field="cf_<?php echo $k; ?>"
|
||
rows="2" placeholder="<?php echo $ph; ?>"
|
||
<?php echo $req; ?>><?php echo esc_textarea($cf_vals[$def['key']] ?? ''); ?></textarea>
|
||
<?php elseif ($def['type'] === 'select'):
|
||
$opts = array_filter(array_map('trim', explode("\n", $def['options'] ?? '')));
|
||
?>
|
||
<select class="wbf-cf-input" data-field="cf_<?php echo $k; ?>">
|
||
<option value="">— Bitte wählen —</option>
|
||
<?php foreach ($opts as $opt): ?>
|
||
<option value="<?php echo esc_attr($opt); ?>"
|
||
<?php selected($cf_vals[$def['key']] ?? '', $opt); ?>><?php echo esc_html($opt); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
<?php elseif ($def['type'] === 'date'): ?>
|
||
<input type="date"
|
||
class="wbf-cf-input"
|
||
data-field="cf_<?php echo $k; ?>"
|
||
value="<?php echo esc_attr($cf_vals[$def['key']] ?? ''); ?>"
|
||
max="<?php echo date('Y-m-d'); ?>"
|
||
<?php echo $req; ?>>
|
||
<?php else: ?>
|
||
<input type="<?php echo $def['type']==='url'?'url':($def['type']==='number'?'number':'text'); ?>"
|
||
class="wbf-cf-input"
|
||
data-field="cf_<?php echo $k; ?>"
|
||
value="<?php echo $val; ?>"
|
||
placeholder="<?php echo $ph; ?>"
|
||
<?php echo $req; ?>>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; endif; ?>
|
||
|
||
<!-- Globaler Speichern-Button für Tab 1 -->
|
||
<div style="display:flex;align-items:center;gap:1rem;padding:.25rem 0 .5rem">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSaveProfile" style="min-width:160px">
|
||
<i class="fas fa-save"></i> Alles speichern
|
||
</button>
|
||
<span class="wbf-msg" id="wbfProfileMsg"></span>
|
||
</div>
|
||
|
||
<?php endif; /* end Tab 1 */ ?>
|
||
|
||
<!-- ══════════════════════════════════════════════════
|
||
TAB 2 — Lesezeichen + Beiträge
|
||
══════════════════════════════════════════════════ -->
|
||
<?php if ($active_tab === 2): ?>
|
||
|
||
<!-- Lesezeichen (nur eigenes Profil) -->
|
||
<?php if ($is_own): ?>
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-bookmark"></i> Lesezeichen
|
||
<span class="wbf-profile-card__count"><?php echo count($bookmarks); ?></span>
|
||
</div>
|
||
<div class="wbf-profile-card__body wbf-profile-card__body--posts">
|
||
<?php if (empty($bookmarks)): ?>
|
||
<p class="wbf-profile-empty">Noch keine Lesezeichen.</p>
|
||
<?php else: foreach ($bookmarks as $bm): ?>
|
||
<div class="wbf-profile-post-item">
|
||
<div class="wbf-profile-post-item__top">
|
||
<?php echo self::render_prefix($bm); ?>
|
||
<a href="?forum_thread=<?php echo (int)$bm->id; ?>" class="wbf-profile-post-item__title">
|
||
<?php echo esc_html(mb_substr($bm->title,0,60)); ?>
|
||
</a>
|
||
<span class="wbf-profile-post-item__cat"><i class="fas fa-folder"></i> <?php echo esc_html($bm->cat_name); ?></span>
|
||
<span class="wbf-profile-post-item__time"><i class="fas fa-bookmark" style="font-size:.65rem"></i> <?php echo self::time_ago($bm->bookmarked_at); ?></span>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<!-- Beiträge -->
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-comments"></i> Beiträge
|
||
<span class="wbf-profile-card__count"><?php echo count($user_posts); ?></span>
|
||
</div>
|
||
<div class="wbf-profile-card__body wbf-profile-card__body--posts">
|
||
<?php if (empty($user_posts)): ?>
|
||
<p class="wbf-profile-empty">Noch keine Beiträge.</p>
|
||
<?php else:
|
||
foreach ($user_posts as $up):
|
||
$preview = esc_html(mb_substr(strip_tags($up->content), 0, 130));
|
||
$more = mb_strlen(strip_tags($up->content)) > 130 ? '…' : '';
|
||
$is_thread = isset($up->entry_type) && $up->entry_type === 'thread';
|
||
$anchor = $is_thread
|
||
? '?forum_thread=' . (int)$up->thread_id
|
||
: '?forum_thread=' . (int)$up->thread_id . '#post-' . (int)$up->id;
|
||
?>
|
||
<div class="wbf-profile-post-item">
|
||
<div class="wbf-profile-post-item__top">
|
||
<?php if ($is_thread): ?>
|
||
<span class="wbf-profile-post-item__type wbf-profile-post-item__type--thread">
|
||
<i class="fas fa-layer-group"></i> Thread
|
||
</span>
|
||
<?php else: ?>
|
||
<span class="wbf-profile-post-item__type wbf-profile-post-item__type--reply">
|
||
<i class="fas fa-reply"></i> Antwort
|
||
</span>
|
||
<?php endif; ?>
|
||
<a href="<?php echo esc_url($anchor); ?>" class="wbf-profile-post-item__title">
|
||
<?php echo esc_html(mb_substr($up->thread_title, 0, 60)); ?>
|
||
</a>
|
||
<span class="wbf-profile-post-item__cat">
|
||
<i class="fas fa-folder"></i> <?php echo esc_html($up->cat_name); ?>
|
||
</span>
|
||
<span class="wbf-profile-post-item__time"><?php echo self::time_ago($up->created_at); ?></span>
|
||
</div>
|
||
<?php if ($preview): ?>
|
||
<p class="wbf-profile-post-item__preview"><?php echo $preview . $more; ?></p>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endforeach; endif; ?>
|
||
</div>
|
||
</div>
|
||
|
||
<?php endif; /* end Tab 2 */ ?>
|
||
|
||
<!-- ══════════════════════════════════════════════════
|
||
TAB 3 — Ignorierte Nutzer + Datenschutz
|
||
══════════════════════════════════════════════════ -->
|
||
<?php if ($is_own && $active_tab === 3): ?>
|
||
|
||
<!-- Profil-Sichtbarkeit -->
|
||
<?php $pub = (int)($profile->profile_public ?? 1); ?>
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-eye"></i> Profil-Sichtbarkeit
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<div class="wbf-form-row" style="display:flex;align-items:center;gap:1rem">
|
||
<div>
|
||
<div style="font-size:.9rem;font-weight:600;margin-bottom:3px">Profil öffentlich sichtbar</div>
|
||
<div style="font-size:.8rem;color:var(--c-muted)">Wenn deaktiviert, können nur du selbst und Moderatoren dein Profil sehen.</div>
|
||
</div>
|
||
<button type="button" id="wbfToggleProfileVis"
|
||
class="wbf-btn wbf-btn--sm<?php echo $pub?' wbf-btn--primary':''; ?>"
|
||
data-state="<?php echo $pub; ?>"
|
||
style="margin-left:auto;white-space:nowrap">
|
||
<i class="fas fa-<?php echo $pub?'eye':'eye-slash'; ?>"></i>
|
||
<?php echo $pub?'Öffentlich':'Privat'; ?>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ignorierte Nutzer -->
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-bell"></i> E-Mail-Benachrichtigungen
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<?php
|
||
$notif_meta = WBF_DB::get_user_meta($current->id);
|
||
$n_reply = ($notif_meta['notify_reply'] ?? '1') !== '0';
|
||
$n_mention = ($notif_meta['notify_mention'] ?? '1') !== '0';
|
||
$n_message = ($notif_meta['notify_message'] ?? '1') !== '0';
|
||
?>
|
||
<p style="font-size:.82rem;color:var(--c-muted);margin-bottom:1rem">
|
||
Lege fest bei welchen Ereignissen du eine E-Mail erhältst.
|
||
</p>
|
||
<div class="wbf-notif-pref-list">
|
||
<label class="wbf-notif-pref">
|
||
<div class="wbf-notif-pref__info">
|
||
<span><i class="fas fa-reply"></i> Antworten auf meine Threads</span>
|
||
<small>Wenn jemand in einem deiner Threads antwortet</small>
|
||
</div>
|
||
<div class="wbf-toggle<?php echo $n_reply?' wbf-toggle--on':''; ?>"
|
||
id="wbfNotifReply" data-key="notify_reply" data-state="<?php echo $n_reply?'1':'0'; ?>">
|
||
<div class="wbf-toggle__knob"></div>
|
||
</div>
|
||
</label>
|
||
<label class="wbf-notif-pref">
|
||
<div class="wbf-notif-pref__info">
|
||
<span><i class="fas fa-at"></i> @Erwähnungen</span>
|
||
<small>Wenn dich jemand in einem Beitrag erwähnt</small>
|
||
</div>
|
||
<div class="wbf-toggle<?php echo $n_mention?' wbf-toggle--on':''; ?>"
|
||
id="wbfNotifMention" data-key="notify_mention" data-state="<?php echo $n_mention?'1':'0'; ?>">
|
||
<div class="wbf-toggle__knob"></div>
|
||
</div>
|
||
</label>
|
||
<label class="wbf-notif-pref">
|
||
<div class="wbf-notif-pref__info">
|
||
<span><i class="fas fa-envelope"></i> Privatnachrichten</span>
|
||
<small>Wenn du eine neue Direktnachricht erhältst</small>
|
||
</div>
|
||
<div class="wbf-toggle<?php echo $n_message?' wbf-toggle--on':''; ?>"
|
||
id="wbfNotifMessage" data-key="notify_message" data-state="<?php echo $n_message?'1':'0'; ?>">
|
||
<div class="wbf-toggle__knob"></div>
|
||
</div>
|
||
</label>
|
||
</div>
|
||
<div class="wbf-profile-card__footer" style="margin-top:1rem">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSaveNotifPrefs">
|
||
<i class="fas fa-save"></i> Einstellungen speichern
|
||
</button>
|
||
<span class="wbf-msg" id="wbfNotifPrefsMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ignorierte Nutzer -->
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-eye-slash"></i> Ignorierte Nutzer
|
||
<span class="wbf-profile-card__count" id="wbfIgnoreCount"><?php echo count($ignore_list); ?></span>
|
||
</div>
|
||
<div class="wbf-profile-card__body" id="wbfIgnoreListWrap">
|
||
<?php if (empty($ignore_list)): ?>
|
||
<p class="wbf-profile-empty" id="wbfIgnoreEmpty">Du ignorierst niemanden.</p>
|
||
<?php else: ?>
|
||
<div class="wbf-ignore-list" id="wbfIgnoreList">
|
||
<?php foreach ($ignore_list as $ign): ?>
|
||
<div class="wbf-ignore-item" id="wbf-ignore-item-<?php echo (int)$ign->id; ?>">
|
||
<a href="?forum_profile=<?php echo (int)$ign->id; ?>" class="wbf-ignore-item__avatar">
|
||
<?php echo self::avatar($ign->avatar_url, $ign->display_name, 36); ?>
|
||
</a>
|
||
<div class="wbf-ignore-item__info">
|
||
<a href="?forum_profile=<?php echo (int)$ign->id; ?>" class="wbf-ignore-item__name">
|
||
<?php echo esc_html($ign->display_name); ?>
|
||
</a>
|
||
<span class="wbf-ignore-item__since">Ignoriert seit <?php echo self::time_ago($ign->ignored_since); ?></span>
|
||
</div>
|
||
<button class="wbf-ignore-btn wbf-btn wbf-btn--sm"
|
||
data-id="<?php echo (int)$ign->id; ?>"
|
||
data-name="<?php echo esc_attr($ign->display_name); ?>"
|
||
data-ignored="1"
|
||
style="margin-left:auto">
|
||
<i class="fas fa-eye"></i> Entblocken
|
||
</button>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Datenschutz & Konto löschen -->
|
||
<div class="wbf-profile-card" style="border-color:rgba(240,82,82,.25)">
|
||
<div class="wbf-profile-card__header" style="color:var(--c-danger);background:rgba(240,82,82,.06);border-bottom-color:rgba(240,82,82,.15)">
|
||
<i class="fas fa-shield-halved"></i> Datenschutz & Konto löschen
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<p style="font-size:.85rem;color:var(--c-text-dim);margin-bottom:1rem;line-height:1.6">
|
||
Gemäß <strong>DSGVO Art. 17</strong> (Recht auf Vergessenwerden) kannst du die vollständige Löschung deines Kontos und aller personenbezogenen Daten beantragen.<br>
|
||
<span style="color:var(--c-muted);font-size:.8rem">Deine Beiträge bleiben anonymisiert sichtbar. Direktnachrichten, Likes, Profilinformationen und alle persönlichen Daten werden dauerhaft gelöscht.</span>
|
||
</p>
|
||
<div id="wbfGdprBox" style="background:rgba(240,82,82,.06);border:1px solid rgba(240,82,82,.2);border-radius:var(--radius-sm);padding:1.1rem;display:none">
|
||
<p style="font-size:.82rem;font-weight:700;color:var(--c-danger);margin-bottom:.9rem"><i class="fas fa-triangle-exclamation"></i> Diese Aktion ist unwiderruflich.</p>
|
||
<div class="wbf-form-row">
|
||
<label style="font-size:.72rem">Passwort zur Bestätigung</label>
|
||
<input type="password" id="wbfGdprPassword" placeholder="Dein aktuelles Passwort" autocomplete="current-password">
|
||
</div>
|
||
<label style="display:flex;align-items:center;gap:.6rem;font-size:.82rem;color:var(--c-text-dim);cursor:pointer;margin-bottom:1rem">
|
||
<input type="checkbox" id="wbfGdprConfirm" style="width:15px;height:15px;accent-color:var(--c-danger);cursor:pointer">
|
||
Ich verstehe, dass mein Konto und alle persönlichen Daten unwiderruflich gelöscht werden.
|
||
</label>
|
||
<div style="display:flex;gap:.75rem;align-items:center;flex-wrap:wrap">
|
||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprCancel"
|
||
onclick="document.getElementById('wbfGdprBox').style.display='none';document.getElementById('wbfGdprToggle').style.display=''">
|
||
<i class="fas fa-xmark"></i> Abbrechen
|
||
</button>
|
||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprSubmit"
|
||
style="background:rgba(240,82,82,.15);color:var(--c-danger);border-color:rgba(240,82,82,.4)">
|
||
<i class="fas fa-trash-can"></i> Konto endgültig löschen
|
||
</button>
|
||
<span class="wbf-msg" id="wbfGdprMsg"></span>
|
||
</div>
|
||
</div>
|
||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprToggle"
|
||
style="background:rgba(240,82,82,.08);color:var(--c-danger);border-color:rgba(240,82,82,.3)"
|
||
onclick="document.getElementById('wbfGdprBox').style.display='';document.getElementById('wbfGdprToggle').style.display='none'">
|
||
<i class="fas fa-trash-can"></i> Konto löschen (DSGVO Art. 17)
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<?php endif; /* end Tab 3 */ ?>
|
||
|
||
<!-- ══════════════════════════════════════════════════
|
||
TAB 4 — Sicherheit (Passwort & E-Mail)
|
||
══════════════════════════════════════════════════ -->
|
||
<?php if ($is_own && $active_tab === 4): ?>
|
||
|
||
<!-- Passwort ändern -->
|
||
<div class="wbf-profile-card" style="border-color:rgba(0,180,216,.25)">
|
||
<div class="wbf-profile-card__header" style="background:rgba(0,180,216,.07);border-bottom-color:rgba(0,180,216,.18)">
|
||
<i class="fas fa-lock" style="color:var(--c-primary)"></i> Passwort ändern
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<div class="wbf-form-row">
|
||
<label>Aktuelles Passwort</label>
|
||
<input type="password" id="wbfCurrentPassword" placeholder="Dein aktuelles Passwort" autocomplete="current-password">
|
||
</div>
|
||
<div class="wbf-profile-edit-grid">
|
||
<div class="wbf-form-row">
|
||
<label>Neues Passwort <small>(min. 6 Zeichen)</small></label>
|
||
<input type="password" id="wbfNewPassword" placeholder="Neues Passwort" autocomplete="new-password">
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Neues Passwort wiederholen</label>
|
||
<input type="password" id="wbfNewPassword2" placeholder="Passwort bestätigen" autocomplete="new-password">
|
||
</div>
|
||
</div>
|
||
<div class="wbf-profile-card__footer">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSavePassword">
|
||
<i class="fas fa-key"></i> Passwort ändern
|
||
</button>
|
||
<span class="wbf-msg" id="wbfPasswordMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- E-Mail-Adresse ändern -->
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-envelope"></i> E-Mail-Adresse
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
<p style="font-size:.82rem;color:var(--c-muted);margin-bottom:1rem">
|
||
Aktuelle Adresse: <strong style="color:var(--c-text)"><?php echo esc_html($profile->email); ?></strong>
|
||
</p>
|
||
<div class="wbf-profile-edit-grid">
|
||
<div class="wbf-form-row">
|
||
<label>Neue E-Mail-Adresse</label>
|
||
<input type="email" id="wbfNewEmail" placeholder="neue@email.de" autocomplete="off">
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Aktuelles Passwort <small>(zur Bestätigung)</small></label>
|
||
<input type="password" id="wbfEmailPassword" placeholder="••••••" autocomplete="current-password">
|
||
</div>
|
||
</div>
|
||
<div class="wbf-profile-card__footer">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSaveEmail">
|
||
<i class="fas fa-envelope"></i> E-Mail ändern
|
||
</button>
|
||
<span class="wbf-msg" id="wbfEmailMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
<!-- ══════════════════════════════════════════════════
|
||
2FA — Zwei-Faktor-Authentifizierung (TOTP)
|
||
══════════════════════════════════════════════════ -->
|
||
<?php if ( class_exists('WBF_TOTP') ) :
|
||
$wbf_2fa_active = WBF_TOTP::is_enabled_for($current->id);
|
||
?>
|
||
<div class="wbf-profile-card wbf-2fa-card" id="wbf2faCard">
|
||
<div class="wbf-profile-card__header" style="background:rgba(234,179,8,.07);border-bottom-color:rgba(234,179,8,.2)">
|
||
<i class="fas fa-shield-halved" style="color:#eab308"></i>
|
||
Zwei-Faktor-Authentifizierung (2FA)
|
||
<?php if ( $wbf_2fa_active ): ?>
|
||
<span class="wbf-2fa-badge wbf-2fa-badge--on"><i class="fas fa-check-circle"></i> Aktiv</span>
|
||
<?php else: ?>
|
||
<span class="wbf-2fa-badge wbf-2fa-badge--off"><i class="fas fa-circle-xmark"></i> Inaktiv</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="wbf-profile-card__body">
|
||
|
||
<!-- ── 2FA bereits aktiv: Deaktivierungs-Formular ── -->
|
||
<?php if ( $wbf_2fa_active ): ?>
|
||
<div id="wbf2faActive">
|
||
<p style="color:var(--c-muted);font-size:.85rem;margin-bottom:1rem">
|
||
<i class="fas fa-info-circle"></i>
|
||
Dein Account ist mit einem Authenticator gesichert.
|
||
Zum Deaktivieren Passwort und aktuellen Code eingeben.
|
||
</p>
|
||
<div class="wbf-profile-edit-grid">
|
||
<div class="wbf-form-row">
|
||
<label>Aktuelles Passwort</label>
|
||
<input type="password" id="wbf2faDisablePw" placeholder="••••••" autocomplete="current-password">
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Authenticator-Code</label>
|
||
<input type="text" id="wbf2faDisableCode" placeholder="123456"
|
||
maxlength="6" inputmode="numeric" autocomplete="one-time-code"
|
||
style="letter-spacing:.2em;font-size:1.15rem;font-family:monospace">
|
||
</div>
|
||
</div>
|
||
<div class="wbf-profile-card__footer">
|
||
<button class="wbf-btn" id="wbf2faDisableBtn"
|
||
style="background:rgba(220,38,38,.1);color:#dc2626;border-color:rgba(220,38,38,.3)">
|
||
<i class="fas fa-shield-xmark"></i> 2FA deaktivieren
|
||
</button>
|
||
<span class="wbf-msg" id="wbf2faDisableMsg"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<?php else: ?>
|
||
|
||
<!-- ── 2FA noch nicht aktiv: Setup-Wizard ── -->
|
||
<div id="wbf2faInactive">
|
||
<p style="color:var(--c-muted);font-size:.85rem;margin-bottom:1rem">
|
||
<i class="fas fa-info-circle"></i>
|
||
Schütze deinen Account zusätzlich mit einer Authenticator-App
|
||
(Google Authenticator, Aegis, Bitwarden, Authy, 2FAS…).
|
||
</p>
|
||
<button class="wbf-btn wbf-btn--primary" id="wbf2faStartBtn">
|
||
<i class="fas fa-shield-halved"></i> 2FA einrichten
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Schritt 1: QR-Code scannen -->
|
||
<div id="wbf2faStep1" style="display:none">
|
||
<p style="font-size:.85rem;color:var(--c-muted);margin-bottom:.75rem">
|
||
<strong>Schritt 1:</strong> Scanne diesen QR-Code mit deiner Authenticator-App.
|
||
</p>
|
||
<div id="wbf2faQr" style="display:inline-block;padding:10px;background:#fff;border-radius:8px;margin-bottom:.75rem"></div>
|
||
<p style="font-size:.8rem;color:var(--c-muted);margin-bottom:.5rem">
|
||
Kein QR-Scanner? Gib diesen Code manuell ein:
|
||
</p>
|
||
<code id="wbf2faSecret" style="font-size:.9rem;letter-spacing:.1em;background:var(--c-bg-2);padding:4px 10px;border-radius:4px;user-select:all"></code>
|
||
<div class="wbf-profile-card__footer" style="margin-top:1rem">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbf2faToStep2">
|
||
Weiter <i class="fas fa-arrow-right"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Schritt 2: Code bestätigen -->
|
||
<div id="wbf2faStep2" style="display:none">
|
||
<p style="font-size:.85rem;color:var(--c-muted);margin-bottom:.75rem">
|
||
<strong>Schritt 2:</strong> Gib den 6-stelligen Code aus deiner App ein.
|
||
</p>
|
||
<div class="wbf-form-row" style="max-width:220px">
|
||
<label>Bestätigungs-Code</label>
|
||
<input type="text" id="wbf2faVerifyCode" placeholder="123456"
|
||
maxlength="6" inputmode="numeric" autocomplete="one-time-code"
|
||
style="letter-spacing:.25em;font-size:1.3rem;text-align:center;font-family:monospace">
|
||
</div>
|
||
<div class="wbf-profile-card__footer">
|
||
<button class="wbf-btn" id="wbf2faBackBtn" style="opacity:.7">
|
||
<i class="fas fa-arrow-left"></i> Zurück
|
||
</button>
|
||
<button class="wbf-btn wbf-btn--primary" id="wbf2faVerifyBtn">
|
||
<i class="fas fa-check"></i> Bestätigen & aktivieren
|
||
</button>
|
||
<span class="wbf-msg" id="wbf2faVerifyMsg"></span>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Schritt 3: Erfolg -->
|
||
<div id="wbf2faStep3" style="display:none;text-align:center;padding:1.5rem 0">
|
||
<div style="font-size:2.5rem;margin-bottom:.5rem">🔒</div>
|
||
<strong style="font-size:1rem;color:var(--c-text)">2FA erfolgreich aktiviert!</strong>
|
||
<p style="font-size:.85rem;color:var(--c-muted);margin:.5rem 0 0">
|
||
Ab jetzt wird beim Login ein Code aus deiner App abgefragt.
|
||
</p>
|
||
</div>
|
||
|
||
<?php endif; // 2fa_active ?>
|
||
|
||
</div>
|
||
</div>
|
||
<?php endif; // class_exists WBF_TOTP ?>
|
||
|
||
<?php endif; /* end Tab 4 */ ?>
|
||
|
||
<!-- ══════════════════════════════════════════════════
|
||
TAB MC — Verbindungen (Externe Dienste verknüpfen)
|
||
Wird nur gerendert wenn mind. eine Integration aktiv ist.
|
||
Neue Integrationen: einfach weiteres .wbf-connection-card-Block
|
||
via apply_filters('wbf_profile_connections', ...) hinzufügen.
|
||
══════════════════════════════════════════════════ -->
|
||
<?php if ( $is_own && $active_tab === 'mc' ) : ?>
|
||
|
||
<div class="wbf-profile-card">
|
||
<div class="wbf-profile-card__header">
|
||
<i class="fas fa-plug"></i> Verbundene Dienste
|
||
</div>
|
||
<div class="wbf-profile-card__body wbf-connections-body">
|
||
|
||
<?php if ( class_exists('MC_Gallery_Forum_Bridge') ) :
|
||
$mc_content = apply_filters('wbf_profile_tab_content', '', 'minecraft', $profile);
|
||
?>
|
||
<div class="wbf-connection-card">
|
||
<div class="wbf-connection-card__icon" style="background:rgba(101,163,13,.15);border-color:rgba(101,163,13,.3)">
|
||
<i class="fas fa-cubes" style="color:#65a30d"></i>
|
||
</div>
|
||
<div class="wbf-connection-card__head">
|
||
<span class="wbf-connection-card__title">Gallerie Verbindung</span>
|
||
</div>
|
||
<div class="wbf-connection-card__content">
|
||
<?php echo $mc_content; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ── StatusAPI Bridge: Account-Verknüpfung & Ingame-Benachrichtigungen ──
|
||
$mc_enabled = class_exists( 'WBF_MC_Bridge' ) && WBF_MC_Bridge::is_enabled();
|
||
$mc_uuid = $mc_enabled ? WBF_MC_Bridge::get_mc_uuid( $profile->id ) : '';
|
||
$mc_name = $mc_enabled ? WBF_MC_Bridge::get_mc_name( $profile->id ) : '';
|
||
$mc_linked = ! empty( $mc_uuid );
|
||
?>
|
||
<div class="wbf-connection-card">
|
||
<div class="wbf-connection-card__icon" style="background:rgba(101,163,13,.15);border-color:rgba(101,163,13,.3)">
|
||
<i class="fas fa-cubes" style="color:#65a30d"></i>
|
||
</div>
|
||
<div class="wbf-connection-card__head">
|
||
<span class="wbf-connection-card__title">Minecraft InGame Verbindung</span>
|
||
<?php if ( ! $mc_enabled ) : ?>
|
||
<span class="wbf-connection-badge" style="color:#9ca3af;background:rgba(156,163,175,.1);border-color:rgba(156,163,175,.3)">
|
||
<i class="fas fa-circle-xmark"></i> Nicht konfiguriert
|
||
</span>
|
||
<?php elseif ( $mc_linked ) : ?>
|
||
<span class="wbf-connection-badge wbf-connection-badge--connected">
|
||
<i class="fas fa-check-circle"></i> Verbunden
|
||
</span>
|
||
<?php else : ?>
|
||
<span class="wbf-connection-badge wbf-connection-badge--disconnected">
|
||
<i class="fas fa-circle-xmark"></i> Nicht verbunden
|
||
</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="wbf-connection-card__content">
|
||
<?php if ( ! $mc_enabled ) : ?>
|
||
<p class="wbf-connection-card__desc" style="color:var(--c-muted)">
|
||
<i class="fas fa-info-circle"></i>
|
||
Die Minecraft Bridge ist noch nicht eingerichtet.
|
||
Ein Admin muss sie zuerst in den Forum-Einstellungen aktivieren.
|
||
</p>
|
||
<?php elseif ( $mc_linked ) : ?>
|
||
<div class="wbf-mc-linked-info" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.75rem">
|
||
<img src="https://mc-heads.net/avatar/<?php echo urlencode( $mc_name ?: $mc_uuid ); ?>/40"
|
||
alt="" width="40" height="40"
|
||
style="border-radius:4px;image-rendering:pixelated">
|
||
<div>
|
||
<strong style="color:var(--c-text)"><?php echo esc_html( $mc_name ?: $mc_uuid ); ?></strong><br>
|
||
<small style="color:var(--c-muted);font-size:.75rem"><?php echo esc_html( $mc_uuid ); ?></small>
|
||
</div>
|
||
</div>
|
||
<p style="font-size:.82rem;color:var(--c-muted);margin:.25rem 0 .75rem">
|
||
<i class="fas fa-bell" style="color:#65a30d"></i>
|
||
Du erhältst Ingame-Benachrichtigungen bei Antworten, Erwähnungen und PNs.
|
||
</p>
|
||
<div id="wbf-mc-msg" style="font-size:.82rem;margin-bottom:.5rem"></div>
|
||
<button type="button" class="wbf-btn wbf-btn--ghost" id="wbf-mc-unlink-btn"
|
||
onclick="wbfMcUnlink()">
|
||
<i class="fas fa-unlink"></i> Verknüpfung aufheben
|
||
</button>
|
||
<?php else : ?>
|
||
<p class="wbf-connection-card__desc">
|
||
Verknüpfe deinen Minecraft-Account für Ingame-Benachrichtigungen
|
||
bei neuen Antworten, Erwähnungen und Privatnachrichten.
|
||
</p>
|
||
<p style="font-size:.82rem;color:var(--c-muted);margin-bottom:.75rem">
|
||
<i class="fas fa-terminal"></i>
|
||
Schritt 1: Token generieren →
|
||
Schritt 2: <code>/forumlink <token></code> ingame eingeben
|
||
</p>
|
||
<div id="wbf-mc-token-box" style="display:none;background:var(--c-surface);border:1px solid var(--c-border);border-radius:8px;padding:.85rem 1rem;margin-bottom:.75rem">
|
||
<div style="display:flex;align-items:center;justify-content:space-between;gap:.5rem;margin-bottom:.4rem">
|
||
<span style="font-size:.75rem;color:var(--c-muted);text-transform:uppercase;letter-spacing:.05em">Dein Token</span>
|
||
<span id="wbf-mc-token-timer" style="font-size:.75rem;color:#f97316;font-weight:600"></span>
|
||
</div>
|
||
<div style="display:flex;align-items:center;gap:.5rem">
|
||
<code id="wbf-mc-token-value"
|
||
style="font-size:1.4rem;letter-spacing:.25em;font-weight:700;color:var(--c-accent);flex:1"></code>
|
||
<button type="button" class="wbf-btn wbf-btn--sm" id="wbf-mc-copy-btn"
|
||
onclick="wbfMcCopyToken()" title="Befehl kopieren">
|
||
<i class="fas fa-copy"></i>
|
||
</button>
|
||
</div>
|
||
<div style="margin-top:.5rem;font-size:.8rem;color:var(--c-muted)">
|
||
Ingame eingeben: <code id="wbf-mc-cmd-value">/forumlink </code>
|
||
</div>
|
||
<div style="margin-top:.5rem">
|
||
<div style="height:4px;border-radius:2px;background:var(--c-border);overflow:hidden">
|
||
<div id="wbf-mc-token-progress"
|
||
style="height:100%;background:#65a30d;transition:width 1s linear;width:100%"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="wbf-mc-msg" style="font-size:.82rem;margin-bottom:.5rem"></div>
|
||
<button type="button" class="wbf-btn wbf-btn--primary" id="wbf-mc-gen-btn"
|
||
onclick="wbfMcGenerateToken()">
|
||
<i class="fas fa-key"></i> Token generieren
|
||
</button>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<script>
|
||
(function(){
|
||
var _pollInterval = null;
|
||
var _timerInterval = null;
|
||
var _expiry = 0;
|
||
|
||
window.wbfMcGenerateToken = function() {
|
||
var btn = document.getElementById('wbf-mc-gen-btn');
|
||
var msg = document.getElementById('wbf-mc-msg');
|
||
btn.disabled = true;
|
||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Generiere...';
|
||
msg.textContent = '';
|
||
jQuery.post(WBF.ajax_url, { action: 'wbf_mc_generate_token', nonce: WBF.nonce }, function(r) {
|
||
btn.disabled = false;
|
||
btn.innerHTML = '<i class="fas fa-rotate"></i> Neuen Token generieren';
|
||
if (r.success) {
|
||
var token = r.data.token;
|
||
_expiry = Math.floor(Date.now() / 1000) + ((r.data.expires_in || 15) * 60);
|
||
document.getElementById('wbf-mc-token-value').textContent = token;
|
||
document.getElementById('wbf-mc-cmd-value').textContent = '/forumlink ' + token;
|
||
document.getElementById('wbf-mc-token-box').style.display = 'block';
|
||
wbfMcStartTimer((r.data.expires_in || 15) * 60);
|
||
wbfMcStartPolling();
|
||
} else {
|
||
if (r.data && r.data.linked) {
|
||
msg.innerHTML = '<span style="color:#16a34a"><i class="fas fa-check-circle"></i> ' + (r.data.message || 'Bereits verknüpft.') + '</span>';
|
||
setTimeout(function(){ location.reload(); }, 1500);
|
||
} else {
|
||
msg.innerHTML = '<span style="color:#dc2626"><i class="fas fa-circle-xmark"></i> ' + (r.data && r.data.message ? r.data.message : 'Fehler') + '</span>';
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
function wbfMcStartTimer(seconds) {
|
||
clearInterval(_timerInterval);
|
||
var timerEl = document.getElementById('wbf-mc-token-timer');
|
||
var progressEl = document.getElementById('wbf-mc-token-progress');
|
||
var total = seconds;
|
||
_timerInterval = setInterval(function() {
|
||
var remaining = _expiry - Math.floor(Date.now() / 1000);
|
||
if (remaining <= 0) {
|
||
clearInterval(_timerInterval); clearInterval(_pollInterval);
|
||
if (timerEl) timerEl.textContent = 'Abgelaufen';
|
||
if (progressEl) progressEl.style.width = '0%';
|
||
var msg = document.getElementById('wbf-mc-msg');
|
||
if (msg) msg.innerHTML = '<span style="color:#f97316"><i class="fas fa-clock"></i> Token abgelaufen — bitte neuen generieren.</span>';
|
||
return;
|
||
}
|
||
var m = Math.floor(remaining / 60), s = remaining % 60;
|
||
if (timerEl) timerEl.textContent = m + ':' + (s < 10 ? '0' : '') + s;
|
||
if (progressEl) {
|
||
progressEl.style.width = Math.max(0, (remaining / total) * 100) + '%';
|
||
progressEl.style.background = remaining < 60 ? '#dc2626' : remaining < 180 ? '#f97316' : '#65a30d';
|
||
}
|
||
}, 1000);
|
||
}
|
||
|
||
function wbfMcStartPolling() {
|
||
clearInterval(_pollInterval);
|
||
_pollInterval = setInterval(function() {
|
||
jQuery.post(WBF.ajax_url, { action: 'wbf_mc_link_status', nonce: WBF.nonce }, function(r) {
|
||
if (r.success && r.data && r.data.linked) {
|
||
clearInterval(_pollInterval); clearInterval(_timerInterval);
|
||
var msg = document.getElementById('wbf-mc-msg');
|
||
if (msg) msg.innerHTML = '<span style="color:#16a34a"><i class="fas fa-check-circle"></i> ✓ Verknüpft mit <strong>' + (r.data.mc_name || r.data.mc_uuid) + '</strong>! Seite lädt neu...</span>';
|
||
setTimeout(function(){ location.reload(); }, 1800);
|
||
}
|
||
});
|
||
}, 5000);
|
||
}
|
||
|
||
window.wbfMcCopyToken = function() {
|
||
var cmd = document.getElementById('wbf-mc-cmd-value').textContent;
|
||
var btn = document.getElementById('wbf-mc-copy-btn');
|
||
var done = function() { btn.innerHTML = '<i class="fas fa-check"></i>'; btn.style.color = '#16a34a'; setTimeout(function(){ btn.innerHTML = '<i class="fas fa-copy"></i>'; btn.style.color = ''; }, 2000); };
|
||
if (navigator.clipboard) { navigator.clipboard.writeText(cmd).then(done); }
|
||
else { var ta = document.createElement('textarea'); ta.value = cmd; document.body.appendChild(ta); ta.select(); document.execCommand('copy'); document.body.removeChild(ta); done(); }
|
||
};
|
||
|
||
window.wbfMcUnlink = function() {
|
||
if (!confirm('Minecraft-Verknüpfung wirklich aufheben?')) return;
|
||
var btn = document.getElementById('wbf-mc-unlink-btn');
|
||
btn.disabled = true;
|
||
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Trenne...';
|
||
jQuery.post(WBF.ajax_url, { action: 'wbf_mc_unlink', nonce: WBF.nonce }, function(r) {
|
||
if (r.success) {
|
||
var msg = document.getElementById('wbf-mc-msg');
|
||
if (msg) msg.innerHTML = '<span style="color:#16a34a"><i class="fas fa-check"></i> ' + (r.data.message || 'Verknüpfung aufgehoben.') + '</span>';
|
||
setTimeout(function(){ location.reload(); }, 1200);
|
||
} else {
|
||
btn.disabled = false;
|
||
btn.innerHTML = '<i class="fas fa-unlink"></i> Verknüpfung aufheben';
|
||
var msg = document.getElementById('wbf-mc-msg');
|
||
if (msg) msg.innerHTML = '<span style="color:#dc2626">Fehler: ' + (r.data && r.data.message ? r.data.message : 'Unbekannt') + '</span>';
|
||
}
|
||
});
|
||
};
|
||
})();
|
||
</script>
|
||
|
||
<?php
|
||
// ── Discord-Card (eingebaut, kein extra Plugin nötig) ──────────────
|
||
$discord_meta = WBF_DB::get_user_meta( $profile->id );
|
||
$discord_current = trim( $discord_meta['discord_username'] ?? '' );
|
||
$discord_connected = $discord_current !== '';
|
||
?>
|
||
<?php
|
||
$s = wbf_get_settings();
|
||
$discord_bot_configured = ! empty( trim( $s['discord_bot_token'] ?? '' ) );
|
||
?>
|
||
<div class="wbf-connection-card wbf-connection-card--discord">
|
||
<div class="wbf-connection-card__icon">
|
||
<i class="fab fa-discord"></i>
|
||
</div>
|
||
<div class="wbf-connection-card__head">
|
||
<span class="wbf-connection-card__title">Discord</span>
|
||
<?php if ( $discord_connected ) : ?>
|
||
<span class="wbf-connection-badge wbf-connection-badge--connected">
|
||
<i class="fas fa-check-circle"></i> Verbunden
|
||
</span>
|
||
<?php else : ?>
|
||
<span class="wbf-connection-badge wbf-connection-badge--disconnected">
|
||
<i class="fas fa-circle-xmark"></i> Nicht verbunden
|
||
</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<div class="wbf-connection-card__content">
|
||
|
||
<?php if ( $discord_connected ) : ?>
|
||
<!-- ── Bereits verbunden ── -->
|
||
<div class="wbf-discord-connected-info">
|
||
<span class="wbf-discord-linked-name">
|
||
<i class="fab fa-discord" style="color:#5865f2"></i>
|
||
<?php echo esc_html( $discord_current ); ?>
|
||
</span>
|
||
</div>
|
||
<div class="wbf-connect-row" style="margin-top:.75rem">
|
||
<button type="button" class="wbf-btn wbf-btn--primary" id="wbf-discord-relink">
|
||
<i class="fas fa-rotate"></i> Neu verknüpfen
|
||
</button>
|
||
<button type="button" class="wbf-btn wbf-btn--ghost" id="wbf-discord-disconnect">
|
||
<i class="fas fa-unlink"></i> Trennen
|
||
</button>
|
||
</div>
|
||
<div id="wbf-discord-msg" style="margin-top:.5rem;font-size:.82rem"></div>
|
||
|
||
<!-- Formular (standardmäßig ausgeblendet, bei "Neu verknüpfen" sichtbar) -->
|
||
<div id="wbf-discord-form" style="display:none;margin-top:1rem">
|
||
<?php self::render_discord_form( $discord_bot_configured ); ?>
|
||
</div>
|
||
|
||
<?php else : ?>
|
||
<!-- ── Noch nicht verbunden ── -->
|
||
<p class="wbf-connection-card__desc">
|
||
Verknüpfe deinen Discord-Account mit deinem Profil.
|
||
<?php if ( $discord_bot_configured ) : ?>
|
||
Ein Bestätigungs-Code wird dir per Discord-DM zugeschickt.
|
||
<?php else : ?>
|
||
<em style="color:var(--c-muted)">(Bot noch nicht konfiguriert – wende dich an einen Admin.)</em>
|
||
<?php endif; ?>
|
||
</p>
|
||
<div id="wbf-discord-msg" style="margin-top:.3rem;font-size:.82rem"></div>
|
||
<div id="wbf-discord-form">
|
||
<?php self::render_discord_form( $discord_bot_configured ); ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<?php
|
||
// Hook für weitere Verbindungen (z.B. Steam, Twitch, …)
|
||
// Nutzung: add_filter('wbf_profile_connections', function($html, $profile) {
|
||
// return $html . '<div class="wbf-connection-card">…</div>';
|
||
// }, 10, 2);
|
||
echo apply_filters('wbf_profile_connections', '', $profile);
|
||
?>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<?php endif; /* end Tab MC */ ?>
|
||
|
||
</div><!-- /.wbf-profile-main -->
|
||
</div><!-- /.wbf-profile-layout -->
|
||
</div>
|
||
</div>
|
||
<?php self::render_auth_modal(); ?>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
|
||
// ── TAG PAGE ─────────────────────────────────────────────────────────────
|
||
|
||
// ── Discord Verifikations-Formular (3-Schritt) ────────────────────────────
|
||
|
||
private static function render_discord_form( $bot_configured ) { ?>
|
||
<?php if ( ! $bot_configured ) : ?>
|
||
<p style="color:var(--c-muted);font-size:.83rem;margin:0">
|
||
<i class="fas fa-triangle-exclamation"></i>
|
||
Discord-Bot noch nicht eingerichtet. Bitte Admin kontaktieren.
|
||
</p>
|
||
<?php else : ?>
|
||
<!-- Schritt 1: Benutzername eingeben -->
|
||
<div id="wbf-dc-step1">
|
||
<label>DISCORD-BENUTZERNAME</label>
|
||
<div class="wbf-connect-row">
|
||
<input type="text"
|
||
id="wbf-discord-input"
|
||
placeholder="z. B. MvViper"
|
||
maxlength="40"
|
||
autocomplete="off">
|
||
<button type="button" class="wbf-btn wbf-btn--primary" id="wbf-discord-send-code">
|
||
<i class="fab fa-discord"></i> Code senden
|
||
</button>
|
||
</div>
|
||
<p style="font-size:.78rem;color:var(--c-muted);margin:.45rem 0 0">
|
||
<i class="fas fa-info-circle"></i>
|
||
Du musst Mitglied unseres Discord-Servers sein und DMs erlauben.
|
||
</p>
|
||
</div>
|
||
|
||
<!-- Schritt 2: Code eingeben (zunächst ausgeblendet) -->
|
||
<div id="wbf-dc-step2" style="display:none;margin-top:.9rem">
|
||
<label>BESTÄTIGUNGS-CODE (aus Discord-DM)</label>
|
||
<div class="wbf-connect-row">
|
||
<input type="text"
|
||
id="wbf-discord-code-input"
|
||
placeholder="A1B2C3"
|
||
maxlength="6"
|
||
autocomplete="off"
|
||
style="font-family:monospace;letter-spacing:.15em;text-transform:uppercase;max-width:140px">
|
||
<button type="button" class="wbf-btn wbf-btn--primary" id="wbf-discord-verify">
|
||
<i class="fas fa-check"></i> Bestätigen
|
||
</button>
|
||
<button type="button" class="wbf-btn wbf-btn--ghost" id="wbf-discord-code-back">
|
||
<i class="fas fa-arrow-left"></i> Zurück
|
||
</button>
|
||
</div>
|
||
<p style="font-size:.78rem;color:var(--c-muted);margin:.45rem 0 0">
|
||
<i class="fas fa-clock"></i> Code ist 10 Minuten gültig.
|
||
</p>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php }
|
||
|
||
private static function view_tag() {
|
||
$slug = sanitize_title( $_GET['forum_tag'] ?? '' );
|
||
$tag = WBF_DB::get_tag($slug);
|
||
if (!$tag) return '<p class="wbf-notice">Tag nicht gefunden.</p>';
|
||
|
||
$current = WBF_Auth::get_current_user();
|
||
$page = max(1,(int)($_GET['fp']??1));
|
||
$threads = WBF_DB::get_threads_by_tag($slug, $page, 20);
|
||
$total = WBF_DB::count_threads_by_tag($slug);
|
||
$pages = ceil($total/20) ?: 1;
|
||
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_tag','fp'])); ?>"><i class="fas fa-home"></i> Forum</a>
|
||
<span>/</span><span><i class="fas fa-hashtag"></i> <?php echo esc_html($tag->name); ?></span>
|
||
</nav>
|
||
<div class="wbf-section-header">
|
||
<h2><i class="fas fa-hashtag"></i> <?php echo esc_html($tag->name); ?>
|
||
<span style="font-size:.85rem;font-weight:400;color:var(--c-muted)"><?php echo (int)$total; ?> Thread<?php echo $total!=1?'s':''; ?></span>
|
||
</h2>
|
||
</div>
|
||
<?php if (empty($threads)): ?>
|
||
<div class="wbf-empty"><i class="fas fa-hashtag"></i><p>Keine Threads mit diesem Tag.</p></div>
|
||
<?php else: ?>
|
||
<div class="wbf-thread-list">
|
||
<?php foreach ($threads as $t):
|
||
$liked = $current ? WBF_DB::has_liked($current->id,$t->id,'thread') : false;
|
||
$t_tags = WBF_DB::get_thread_tags($t->id); ?>
|
||
<div class="wbf-thread-row" data-thread-id="<?php echo (int)$t->id; ?>" data-last-reply="<?php echo esc_attr($t->last_reply_at); ?>">
|
||
<div class="wbf-thread-row__avatar"><?php echo self::avatar($t->avatar_url,$t->display_name); ?></div>
|
||
<div class="wbf-thread-row__body">
|
||
<div class="wbf-thread-row__top">
|
||
<a href="?forum_thread=<?php echo (int)$t->id; ?>" class="wbf-thread-row__title"><?php echo esc_html($t->title); ?></a>
|
||
<span class="wbf-muted" style="font-size:.75rem">in <a href="?forum_cat=<?php echo esc_attr($t->cat_slug); ?>" style="color:var(--c-primary)"><?php echo esc_html($t->cat_name); ?></a></span>
|
||
</div>
|
||
<div class="wbf-thread-row__meta">
|
||
<span>von <strong><?php echo esc_html($t->display_name); ?></strong></span>
|
||
<?php echo self::role_badge($t->author_role); ?>
|
||
<span><?php echo self::time_ago($t->created_at); ?></span>
|
||
</div>
|
||
<?php echo self::render_tags($t_tags, true); ?>
|
||
</div>
|
||
<div class="wbf-thread-row__stats">
|
||
<span><i class="fas fa-comment-dots"></i> <?php echo (int)$t->reply_count; ?></span>
|
||
<span><i class="fas fa-eye"></i> <?php echo (int)$t->views; ?></span>
|
||
<?php echo self::like_btn($t->id,'thread',$t->like_count,$liked); ?>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php if ($pages>1): ?>
|
||
<div class="wbf-pagination">
|
||
<?php for ($i=1;$i<=$pages;$i++): ?>
|
||
<a href="?forum_tag=<?php echo esc_attr($slug); ?>&fp=<?php echo $i; ?>" class="wbf-page-btn<?php echo ($i==$page)?' active':''; ?>"><?php echo $i; ?></a>
|
||
<?php endfor; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php endif; ?>
|
||
|
||
<!-- Popular Tags Cloud -->
|
||
<?php $pop_tags = WBF_DB::get_popular_tags(40); if (!empty($pop_tags)): ?>
|
||
<div style="margin-top:2rem">
|
||
<h3 style="font-size:.82rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--c-text-dim);margin-bottom:.75rem">
|
||
<i class="fas fa-tags"></i> Alle Tags
|
||
</h3>
|
||
<div class="wbf-tag-cloud">
|
||
<?php foreach ($pop_tags as $pt): ?>
|
||
<a href="?forum_tag=<?php echo esc_attr($pt->slug); ?>"
|
||
class="wbf-tag<?php echo $pt->slug===$slug?' wbf-tag--active':''; ?>">
|
||
<i class="fas fa-hashtag"></i><?php echo esc_html($pt->name); ?>
|
||
<span class="wbf-tag__count"><?php echo (int)$pt->use_count; ?></span>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php self::render_forum_footer(); ?>
|
||
</div>
|
||
<?php self::render_auth_modal(); ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
// ── PRIVATE NACHRICHTEN ──────────────────────────────────────────────────
|
||
|
||
private static function view_dm() {
|
||
$current = WBF_Auth::get_current_user();
|
||
if (!$current) {
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar(null); ?>
|
||
<div class="wbf-container wbf-mt" style="display:flex;justify-content:center;padding:3rem 1rem">
|
||
<div style="width:100%;max-width:460px;background:var(--c-surface);border:1px solid rgba(0,180,216,.25);border-radius:var(--radius);padding:2rem;position:relative;overflow:hidden;box-shadow:0 24px 60px rgba(0,0,0,.6)">
|
||
<div style="position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,#00b4d8,transparent)"></div>
|
||
<div style="text-align:center;margin-bottom:1.5rem">
|
||
<div style="font-size:2.2rem;margin-bottom:.6rem">🔒</div>
|
||
<h2 style="font-size:1.1rem;font-weight:700;color:var(--c-text);margin-bottom:.3rem">Bitte einloggen</h2>
|
||
<p style="font-size:.85rem;color:var(--c-muted)">Um Nachrichten lesen zu können, musst du eingeloggt sein.</p>
|
||
</div>
|
||
<?php self::render_auth_forms(); ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
$partner_id = (int)($_GET['with'] ?? 0);
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_dm','with'])); ?>"><i class="fas fa-home"></i> Forum</a>
|
||
<span>/</span><span><i class="fas fa-envelope"></i> Nachrichten</span>
|
||
</nav>
|
||
<div class="wbf-dm-layout">
|
||
<aside class="wbf-dm-sidebar">
|
||
<div class="wbf-dm-sidebar__header">
|
||
<span><i class="fas fa-inbox"></i> Posteingang</span>
|
||
<div style="display:flex;align-items:center;gap:.4rem">
|
||
<button class="wbf-btn wbf-btn--primary wbf-btn--sm" id="wbfNewDmBtn"><i class="fas fa-pen-to-square"></i> Neu</button>
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_dm','with'])); ?>" class="wbf-dm-close-btn" title="Nachrichten schließen"><i class="fas fa-xmark"></i></a>
|
||
</div>
|
||
</div>
|
||
<div class="wbf-dm-inbox" id="wbfDmInbox">
|
||
<div style="padding:1.5rem;text-align:center;color:var(--c-muted)"><i class="fas fa-spinner fa-spin"></i></div>
|
||
</div>
|
||
</aside>
|
||
<div class="wbf-dm-main">
|
||
<?php if ($partner_id): ?>
|
||
<div class="wbf-dm-conversation" id="wbfDmConversation" data-partner="<?php echo $partner_id; ?>">
|
||
<div class="wbf-dm-header" id="wbfDmHeader">
|
||
<div style="text-align:center;padding:.5rem;color:var(--c-muted)"><i class="fas fa-spinner fa-spin"></i></div>
|
||
</div>
|
||
<div class="wbf-dm-load-more-wrap" id="wbfDmLoadMoreWrap" style="display:none;text-align:center;padding:.5rem">
|
||
<button class="wbf-btn wbf-btn--sm" id="wbfDmLoadMore" data-offset="0" data-partner="<?php echo $partner_id; ?>">
|
||
<i class="fas fa-clock-rotate-left"></i> Ältere Nachrichten laden
|
||
</button>
|
||
</div>
|
||
<div class="wbf-dm-messages" id="wbfDmMessages">
|
||
<div style="text-align:center;padding:2rem;color:var(--c-muted)"><i class="fas fa-spinner fa-spin"></i></div>
|
||
</div>
|
||
<div class="wbf-dm-compose">
|
||
<textarea id="wbfDmReplyText" placeholder="Antwort schreiben…" rows="2"></textarea>
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfDmSendReply" data-to="<?php echo $partner_id; ?>">
|
||
<i class="fas fa-paper-plane"></i>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<?php else: ?>
|
||
<div class="wbf-dm-empty">
|
||
<i class="fas fa-envelope-open-text"></i>
|
||
<p>Wähle eine Konversation aus oder starte eine neue Nachricht.</p>
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfNewDmBtn2"><i class="fas fa-pen-to-square"></i> Neue Nachricht</button>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
<?php self::render_forum_footer(); ?>
|
||
</div>
|
||
<?php self::render_auth_modal(); ?>
|
||
<?php self::render_dm_compose_modal(); ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
private static function render_dm_compose_modal() { ?>
|
||
<div class="wbf-modal" id="wbfDmComposeModal">
|
||
<div class="wbf-modal__box">
|
||
<button class="wbf-modal__close" onclick="document.getElementById('wbfDmComposeModal').classList.remove('active')">×</button>
|
||
<h3 style="margin-bottom:1.2rem"><i class="fas fa-pen-to-square" style="color:var(--c-primary)"></i> Neue Nachricht</h3>
|
||
<div class="wbf-form-row">
|
||
<label>Empfänger</label>
|
||
<div class="wbf-tag-input-wrap" id="wbfDmRecipientWrap">
|
||
<input type="text" id="wbfDmRecipientInput" placeholder="@Benutzername suchen…" autocomplete="off">
|
||
<input type="hidden" id="wbfDmToId" value="">
|
||
<div class="wbf-tag-suggest" id="wbfDmSuggest" style="display:none"></div>
|
||
</div>
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Nachricht</label>
|
||
<textarea id="wbfDmComposeText" rows="5" placeholder="Deine Nachricht…" maxlength="2000"></textarea>
|
||
</div>
|
||
<div style="display:flex;gap:1rem;align-items:center;margin-top:.5rem">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfDmComposeSend"><i class="fas fa-paper-plane"></i> Senden</button>
|
||
<span class="wbf-msg" id="wbfDmComposeMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
// ── PARTIALS ──────────────────────────────────────────────────────────────
|
||
|
||
|
||
// ── SEARCH ────────────────────────────────────────────────────────────────
|
||
|
||
private static function view_search() {
|
||
$cur_s = WBF_Auth::get_current_user();
|
||
$maint_s = wbf_get_settings()['maintenance_mode'] ?? '0';
|
||
if ($maint_s === '1' && (!$cur_s || WBF_Roles::level($cur_s->role) < 50)) return self::view_maintenance();
|
||
$query = sanitize_text_field($_GET['q'] ?? '');
|
||
$current = WBF_Auth::get_current_user();
|
||
$results = mb_strlen($query) >= 2 ? WBF_DB::search($query, 40, $current) : [];
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_search'])); ?>"><i class="fas fa-home"></i> Forum</a>
|
||
<span>/</span><span>Suche</span>
|
||
</nav>
|
||
<div class="wbf-section-header">
|
||
<h2><i class="fas fa-search"></i> Suchergebnisse
|
||
<?php if ($query): ?>
|
||
<span style="font-size:.9rem;font-weight:400;color:var(--c-muted)"> für „<?php echo esc_html($query); ?>“</span>
|
||
<?php endif; ?>
|
||
</h2>
|
||
</div>
|
||
<?php if (empty($results)): ?>
|
||
<div class="wbf-empty"><i class="fas fa-search"></i><p>Keine Ergebnisse<?php echo $query ? ' für „'.esc_html($query).'“' : ''; ?>.</p></div>
|
||
<?php else: ?>
|
||
<div class="wbf-search-results">
|
||
<?php foreach ($results as $r):
|
||
$is_thread = $r->result_type === 'thread';
|
||
$url = $is_thread ? '?forum_thread='.(int)$r->id : '?forum_thread='.(int)$r->id;
|
||
$preview = esc_html(mb_substr(strip_tags($r->content), 0, 200));
|
||
$more = mb_strlen(strip_tags($r->content)) > 200 ? '…' : '';
|
||
?>
|
||
<div class="wbf-search-result-item">
|
||
<div class="wbf-search-result__meta">
|
||
<?php if ($is_thread): ?>
|
||
<span class="wbf-search-result__type wbf-search-result__type--thread"><i class="fas fa-layer-group"></i> Thread</span>
|
||
<?php else: ?>
|
||
<span class="wbf-search-result__type wbf-search-result__type--post"><i class="fas fa-comment"></i> Antwort</span>
|
||
<?php endif; ?>
|
||
<span class="wbf-search-result__cat"><i class="fas fa-folder"></i> <?php echo esc_html($r->cat_name); ?></span>
|
||
<span class="wbf-search-result__author"><?php echo self::avatar($r->avatar_url, $r->display_name, 18); ?> <?php echo esc_html($r->display_name); ?></span>
|
||
<span class="wbf-search-result__date"><?php echo self::time_ago($r->created_at); ?></span>
|
||
</div>
|
||
<a href="<?php echo esc_url($url); ?>" class="wbf-search-result__title"><?php echo esc_html(mb_substr($r->title, 0, 80)); ?></a>
|
||
<p class="wbf-search-result__preview"><?php echo $preview.$more; ?></p>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<p style="color:var(--c-muted);font-size:.82rem;margin-top:1rem"><?php echo count($results); ?> Ergebnis(se) gefunden.</p>
|
||
<?php endif; ?>
|
||
<?php self::render_forum_footer(); ?>
|
||
</div>
|
||
<?php self::render_auth_modal(); ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
private static function render_topbar( $current ) {
|
||
$unread = $current ? WBF_DB::count_unread_notifications($current->id) : 0;
|
||
?>
|
||
<div class="wbf-topbar">
|
||
<div class="wbf-topbar__inner">
|
||
<a href="<?php echo esc_url(wbf_get_forum_url()); ?>" class="wbf-topbar__brand">
|
||
<i class="fas fa-comments"></i> <?php echo esc_html(wbf_get_settings()['topbar_brand']); ?>
|
||
</a>
|
||
<!-- Suchfeld -->
|
||
<form class="wbf-search-form" id="wbfSearchForm" onsubmit="return false">
|
||
<div class="wbf-search-input-wrap">
|
||
<i class="fas fa-search wbf-search-icon"></i>
|
||
<input type="text" id="wbfSearchInput" placeholder="Forum durchsuchen" autocomplete="off">
|
||
</div>
|
||
<div class="wbf-search-dropdown" id="wbfSearchDropdown" style="display:none"></div>
|
||
</form>
|
||
<div class="wbf-topbar__right">
|
||
<?php if ($current): ?>
|
||
<!-- DM-Button -->
|
||
<?php $unread_dm = WBF_DB::count_unread_messages($current->id); ?>
|
||
<a href="?forum_dm=inbox" class="wbf-notif-btn wbf-dm-btn" title="Nachrichten" style="position:relative;text-decoration:none">
|
||
<i class="fas fa-envelope"></i>
|
||
<?php if ($unread_dm > 0): ?>
|
||
<span class="wbf-notif-badge" style="background:#22c55e"><?php echo min($unread_dm,99); ?></span>
|
||
<?php endif; ?>
|
||
</a>
|
||
|
||
<!-- Benachrichtigungs-Glocke -->
|
||
<div class="wbf-notif-wrap" id="wbfNotifWrap">
|
||
<button class="wbf-notif-btn" id="wbfNotifBtn" title="Benachrichtigungen">
|
||
<i class="fas fa-bell"></i>
|
||
<?php if ($unread > 0): ?>
|
||
<span class="wbf-notif-badge" id="wbfNotifBadge"><?php echo min($unread,99); ?></span>
|
||
<?php else: ?>
|
||
<span class="wbf-notif-badge" id="wbfNotifBadge" style="display:none">0</span>
|
||
<?php endif; ?>
|
||
</button>
|
||
<div class="wbf-notif-dropdown" id="wbfNotifDropdown" style="display:none">
|
||
<div class="wbf-notif-header">
|
||
<span><i class="fas fa-bell"></i> Benachrichtigungen</span>
|
||
<button class="wbf-notif-mark-read" id="wbfMarkAllRead">Alle gelesen</button>
|
||
</div>
|
||
<div class="wbf-notif-list" id="wbfNotifList">
|
||
<div class="wbf-notif-loading"><i class="fas fa-spinner fa-spin"></i></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<a href="?forum_profile=<?php echo (int)$current->id; ?>" class="wbf-topbar__user">
|
||
<?php echo self::avatar($current->avatar_url,$current->display_name,28); ?>
|
||
<?php echo esc_html($current->display_name); ?>
|
||
<?php echo self::role_badge($current->role); ?>
|
||
</a>
|
||
<a href="<?php echo esc_url(wp_nonce_url(wbf_get_forum_url() . '?wbf_do_logout=1', 'wbf_logout')); ?>" class="wbf-btn wbf-btn--sm wbf-btn--outline"><?php echo esc_html(wbf_get_settings()['btn_logout']); ?></a>
|
||
<?php else: ?>
|
||
<button class="wbf-btn wbf-btn--sm" id="wbfOpenLogin"><?php echo esc_html(wbf_get_settings()['btn_login']); ?></button>
|
||
<button class="wbf-btn wbf-btn--sm wbf-btn--primary" id="wbfOpenRegister"><?php echo esc_html(wbf_get_settings()['btn_register']); ?></button>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
private static function render_auth_forms() {
|
||
$reg_mode = wbf_get_settings()['registration_mode'] ?? 'open';
|
||
$invite_msg = wbf_get_settings()['invite_message'] ?? 'Registrierung ist aktuell nur auf Einladung möglich.';
|
||
?>
|
||
<div class="wbf-auth-box">
|
||
<div class="wbf-auth-tabs">
|
||
<button class="wbf-auth-tab active" data-tab="login">Login</button>
|
||
<?php if ($reg_mode === 'open'): ?>
|
||
<button class="wbf-auth-tab" data-tab="register">Registrieren</button>
|
||
<?php elseif ($reg_mode === 'invite'): ?>
|
||
<button class="wbf-auth-tab wbf-auth-tab--muted" disabled title="<?php echo esc_attr($invite_msg); ?>">Registrieren <i class="fas fa-lock" style="font-size:.7em"></i></button>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="wbf-auth-panel active" data-panel="login">
|
||
<div class="wbf-form-row"><input type="text" class="wbf-field-username" placeholder="Benutzername oder E-Mail"></div>
|
||
<div class="wbf-form-row"><input type="password" class="wbf-field-password" placeholder="Passwort"></div>
|
||
<div class="wbf-form-row" style="display:flex;align-items:center;gap:.5rem;margin-bottom:.6rem">
|
||
<input type="checkbox" class="wbf-field-remember" style="width:16px;height:16px;cursor:pointer;accent-color:var(--c-primary,#00b4d8)">
|
||
<label style="font-size:.82rem;color:var(--c-muted);cursor:pointer;margin:0">30 Tage eingeloggt bleiben</label>
|
||
</div>
|
||
<button class="wbf-btn wbf-btn--primary wbf-btn--full wbf-login-submit-btn"><i class="fas fa-sign-in-alt"></i> Einloggen</button>
|
||
<div style="text-align:right;margin-top:.4rem"><a href="#" class="wbf-forgot-link" style="font-size:.78rem;color:var(--c-muted)">Passwort vergessen?</a></div>
|
||
<span class="wbf-login-msg wbf-msg"></span>
|
||
</div>
|
||
<!-- Registrierung gesperrt/invite -->
|
||
<?php if ($reg_mode === 'invite'): ?>
|
||
<div class="wbf-auth-panel" data-panel="register">
|
||
<div class="wbf-notice" style="margin:.5rem 0;font-size:.85rem;text-align:center">
|
||
<i class="fas fa-lock"></i> <?php echo esc_html($invite_msg); ?>
|
||
</div>
|
||
</div>
|
||
<?php elseif ($reg_mode === 'disabled'): ?>
|
||
<div class="wbf-auth-panel" data-panel="register">
|
||
<div class="wbf-notice wbf-notice--warning" style="margin:.5rem 0;font-size:.85rem;text-align:center">
|
||
<i class="fas fa-ban"></i> Registrierung ist deaktiviert.
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
<!-- Passwort vergessen -->
|
||
<div class="wbf-auth-panel" data-panel="forgot">
|
||
<p style="font-size:.82rem;color:var(--c-text-dim);margin-bottom:.75rem">Gib deine E-Mail ein — wir schicken dir einen Reset-Link.</p>
|
||
<div class="wbf-form-row"><input type="email" class="wbf-field-forgot-email" placeholder="deine@email.de"></div>
|
||
<button class="wbf-btn wbf-btn--primary wbf-btn--full wbf-forgot-submit-btn"><i class="fas fa-paper-plane"></i> Reset-Link senden</button>
|
||
<div style="text-align:center;margin-top:.6rem"><a href="#" class="wbf-show-login" style="font-size:.78rem;color:var(--c-muted)">← Zurück zum Login</a></div>
|
||
<span class="wbf-forgot-msg wbf-msg"></span>
|
||
</div>
|
||
<div class="wbf-auth-panel" data-panel="register">
|
||
<?php
|
||
$inv_code_prefill = '';
|
||
if (isset($_GET['wbf_invite'])) $inv_code_prefill = strtoupper(sanitize_text_field($_GET['wbf_invite']));
|
||
$reg_mode_now = wbf_get_settings()['registration_mode'] ?? 'open';
|
||
if ($reg_mode_now === 'invite'): ?>
|
||
<div class="wbf-form-row">
|
||
<input type="text" class="wbf-field-invite-code"
|
||
placeholder="Einladungscode"
|
||
value="<?php echo esc_attr($inv_code_prefill); ?>"
|
||
style="text-transform:uppercase;letter-spacing:.1em;font-weight:700">
|
||
</div>
|
||
<?php endif; ?>
|
||
<!-- Spam: Honeypot (versteckt) + Zeitstempel -->
|
||
<input type="text" name="wbf_website" class="wbf-hp-field" tabindex="-1" autocomplete="off" style="display:none!important;visibility:hidden;position:absolute;left:-9999px">
|
||
<input type="hidden" class="wbf-field-form-time" value="<?php echo time(); ?>">
|
||
<div class="wbf-form-row"><input type="text" class="wbf-field-reg-user" placeholder="Benutzername"></div>
|
||
<div class="wbf-form-row"><input type="text" class="wbf-field-reg-name" placeholder="Anzeigename"></div>
|
||
<div class="wbf-form-row"><input type="email" class="wbf-field-reg-email" placeholder="E-Mail"></div>
|
||
<div class="wbf-form-row"><input type="password" class="wbf-field-reg-pass" placeholder="Passwort (min. 6 Zeichen)"></div>
|
||
<?php
|
||
$rules_required = ( wbf_get_settings()['rules_accept_required'] ?? '1' ) === '1';
|
||
$rules_enabled = ( wbf_get_settings()['rules_enabled'] ?? '1' ) === '1';
|
||
if ( $rules_enabled ):
|
||
?>
|
||
<label style="display:flex;align-items:center;gap:.5rem;font-size:.82rem;color:var(--c-text-dim);cursor:pointer;margin-bottom:.75rem;line-height:1.4;flex-wrap:wrap">
|
||
<input type="checkbox" class="wbf-field-rules-accept"
|
||
style="width:15px;height:15px;accent-color:var(--c-primary);cursor:pointer;flex-shrink:0"
|
||
<?php echo $rules_required ? 'required' : ''; ?>>
|
||
<span>Ich akzeptiere die <a href="<?php echo esc_url(wbf_get_forum_url().'?forum_rules=1'); ?>" target="_blank" style="color:var(--c-primary);font-weight:600;white-space:nowrap">Forum-Regeln</a><?php echo $rules_required ? ' <span style="color:var(--c-danger)">*</span>' : ''; ?></span>
|
||
</label>
|
||
<?php endif; ?>
|
||
<button class="wbf-btn wbf-btn--primary wbf-btn--full wbf-reg-submit-btn"><i class="fas fa-user-plus"></i> Konto erstellen</button>
|
||
<span class="wbf-reg-msg wbf-msg"></span>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
private static function render_auth_modal() { ?>
|
||
<div class="wbf-modal" id="wbfAuthModal">
|
||
<div class="wbf-modal__box">
|
||
<button class="wbf-modal__close" onclick="document.getElementById('wbfAuthModal').classList.remove('active')">×</button>
|
||
<h3 style="margin-bottom:1rem"><i class="fas fa-user-circle"></i> Forum Zugang</h3>
|
||
<?php self::render_auth_forms(); ?>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
private static function render_move_modal( $categories, $thread_id ) {
|
||
$parents = array_filter($categories, fn($c) => (int)$c->parent_id === 0);
|
||
$children_map = [];
|
||
foreach ($categories as $c) { if ((int)$c->parent_id > 0) $children_map[$c->parent_id][] = $c; }
|
||
?>
|
||
<div class="wbf-modal" id="wbfMoveModal">
|
||
<div class="wbf-modal__box">
|
||
<button class="wbf-modal__close" onclick="document.getElementById('wbfMoveModal').classList.remove('active')">×</button>
|
||
<h3 style="margin-bottom:1.2rem"><i class="fas fa-right-left" style="color:var(--c-primary)"></i> Thread verschieben</h3>
|
||
<input type="hidden" id="wbfMoveThreadId" value="<?php echo (int)$thread_id; ?>">
|
||
<div class="wbf-form-row">
|
||
<label>Ziel-Kategorie</label>
|
||
<select id="wbfMoveCatSelect">
|
||
<?php foreach ($parents as $p): ?>
|
||
<optgroup label="<?php echo esc_attr($p->name); ?>">
|
||
<option value="<?php echo (int)$p->id; ?>"><?php echo esc_html($p->name); ?> (Allgemein)</option>
|
||
<?php foreach (($children_map[$p->id]??[]) as $child): ?>
|
||
<option value="<?php echo (int)$child->id; ?>"> ↳ <?php echo esc_html($child->name); ?></option>
|
||
<?php endforeach; ?>
|
||
</optgroup>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div style="display:flex;gap:1rem;align-items:center;margin-top:1rem">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSubmitMove">
|
||
<i class="fas fa-right-left"></i> Verschieben
|
||
</button>
|
||
<span class="wbf-msg" id="wbfMoveMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
private static function render_report_modal() { ?>
|
||
<div class="wbf-modal" id="wbfReportModal">
|
||
<div class="wbf-modal__box">
|
||
<button class="wbf-modal__close" onclick="document.getElementById('wbfReportModal').classList.remove('active')">×</button>
|
||
<h3 style="margin-bottom:1rem"><i class="fas fa-flag" style="color:var(--c-danger)"></i> Beitrag melden</h3>
|
||
<input type="hidden" id="wbfReportId" value="">
|
||
<input type="hidden" id="wbfReportType" value="post">
|
||
<div class="wbf-form-row">
|
||
<label>Grund <span style="color:var(--c-danger)">*</span></label>
|
||
<select id="wbfReportReason">
|
||
<option value="">— Grund auswählen —</option>
|
||
<option value="spam">Spam / Werbung</option>
|
||
<option value="harassment">Belästigung / Beleidigung</option>
|
||
<option value="inappropriate">Unangemessener Inhalt</option>
|
||
<option value="misinformation">Fehlinformation</option>
|
||
<option value="off-topic">Offtopic / Irrelevant</option>
|
||
<option value="other">Sonstiges</option>
|
||
</select>
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Zusätzliche Notiz <small>(optional)</small></label>
|
||
<textarea id="wbfReportNote" rows="3" placeholder="Beschreibe das Problem genauer…" maxlength="500"></textarea>
|
||
</div>
|
||
<div style="display:flex;gap:1rem;align-items:center;margin-top:.5rem">
|
||
<button class="wbf-btn wbf-btn--danger" id="wbfSubmitReport"><i class="fas fa-paper-plane"></i> Melden</button>
|
||
<span class="wbf-msg" id="wbfReportMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
private static function render_editor_toolbar( $target_id ) {
|
||
$emojis = [
|
||
'😊','😂','😍','🥰','😎','😅','😆','🙃','😇','🤩',
|
||
'😏','😒','😔','😢','😭','😡','😱','🤯','🥳','😴',
|
||
'🤔','🤗','😘','😜','🤪','😬','🙄','😤','🥺','🤭',
|
||
'👍','👎','❤️','🔥','💯','🎉','🙏','👏','💪','✨',
|
||
'✅','❌','⭐','💡','❓','❗','💬','📌','🏆','🎯',
|
||
];
|
||
?>
|
||
<div class="wbf-editor-toolbar" data-target="<?php echo esc_attr($target_id); ?>">
|
||
|
||
<!-- Formatierung -->
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="b" title="Fett [b]"><b>B</b></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="i" title="Kursiv [i]"><i>I</i></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="u" title="Unterstrichen [u]" style="text-decoration:underline">U</button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="s" title="Durchgestrichen [s]" style="text-decoration:line-through">S</button>
|
||
<span class="wbf-tb-divider"></span>
|
||
|
||
<!-- Überschriften -->
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="h2" title="Überschrift [h2]" style="font-weight:700">H2</button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="h3" title="Überschrift [h3]" style="font-weight:700;font-size:.72rem">H3</button>
|
||
<span class="wbf-tb-divider"></span>
|
||
|
||
<!-- Farbe + Größe (Dropdowns) -->
|
||
<div class="wbf-tb-dropdown" style="position:relative">
|
||
<button type="button" class="wbf-tb-btn" data-action="dropdown" data-target="color" title="Textfarbe">
|
||
<i class="fas fa-palette"></i> <i class="fas fa-caret-down" style="font-size:.55rem"></i>
|
||
</button>
|
||
<div class="wbf-tb-dropdown__panel" id="wbf-color-panel-<?php echo esc_attr($target_id); ?>" style="display:none">
|
||
<div class="wbf-tb-color-grid">
|
||
<?php foreach ([
|
||
'red'=>'#ef4444','orange'=>'#f97316','gold'=>'#fbbf24',
|
||
'lime'=>'#84cc16','green'=>'#22c55e','teal'=>'#14b8a6',
|
||
'cyan'=>'#00b4d8','blue'=>'#3b82f6','purple'=>'#a78bfa',
|
||
'pink'=>'#ec4899','gray'=>'#94a3b8','white'=>'#f1f5f9',
|
||
] as $name => $hex): ?>
|
||
<button type="button" class="wbf-tb-color-swatch"
|
||
data-action="bb-color" data-color="<?php echo esc_attr($name); ?>"
|
||
title="<?php echo esc_attr($name); ?>"
|
||
style="background:<?php echo esc_attr($hex); ?>"></button>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wbf-tb-dropdown" style="position:relative">
|
||
<button type="button" class="wbf-tb-btn" data-action="dropdown" data-target="size" title="Textgröße">
|
||
<i class="fas fa-text-height"></i> <i class="fas fa-caret-down" style="font-size:.55rem"></i>
|
||
</button>
|
||
<div class="wbf-tb-dropdown__panel" id="wbf-size-panel-<?php echo esc_attr($target_id); ?>" style="display:none">
|
||
<button type="button" class="wbf-tb-dropdown__item" data-action="bb-size" data-size="small">Klein</button>
|
||
<button type="button" class="wbf-tb-dropdown__item" data-action="bb-size" data-size="large">Groß</button>
|
||
<button type="button" class="wbf-tb-dropdown__item" data-action="bb-size" data-size="xlarge">Sehr groß</button>
|
||
</div>
|
||
</div>
|
||
<span class="wbf-tb-divider"></span>
|
||
|
||
<!-- Listen -->
|
||
<button type="button" class="wbf-tb-btn" data-action="bb-list" data-ordered="0" title="Liste [list]"><i class="fas fa-list-ul"></i></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb-list" data-ordered="1" title="Geordnete Liste [list=1]"><i class="fas fa-list-ol"></i></button>
|
||
<span class="wbf-tb-divider"></span>
|
||
|
||
<!-- Sonderblöcke -->
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="quote" title="Zitat [quote]"><i class="fas fa-quote-left"></i></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="code" title="Code-Block [code]"><i class="fas fa-code"></i></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="icode" title="Inline-Code [icode]"><i class="fas fa-terminal" style="font-size:.72rem"></i></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb-spoiler" title="Spoiler [spoiler]"><i class="fas fa-eye-slash"></i></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb-url" title="Link [url]"><i class="fas fa-link"></i></button>
|
||
<span class="wbf-tb-divider"></span>
|
||
|
||
<!-- Medien -->
|
||
<button type="button" class="wbf-tb-btn" data-action="img-upload" title="Bild hochladen">
|
||
<i class="fas fa-image"></i>
|
||
<input type="file" class="wbf-img-file-input" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none">
|
||
</button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb-img" title="Bild-URL [img]"><i class="fas fa-photo-film"></i></button>
|
||
<button type="button" class="wbf-tb-btn" data-action="bb" data-bb="hr" title="Trennlinie [hr]" data-wrap="0">—</button>
|
||
<span class="wbf-tb-divider"></span>
|
||
|
||
<!-- Emoji -->
|
||
<button type="button" class="wbf-tb-btn wbf-tb-btn--emoji" data-action="emoji" title="Emojis">😊 <i class="fas fa-caret-down" style="font-size:.6rem;opacity:.6"></i></button>
|
||
<div class="wbf-emoji-picker" style="display:none">
|
||
<div class="wbf-emoji-picker__grid">
|
||
<?php foreach ($emojis as $e): ?>
|
||
<button type="button" class="wbf-emoji-item" data-emoji="<?php echo esc_attr($e); ?>"><?php echo $e; ?></button>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
// ── UMFRAGE-MODAL ─────────────────────────────────────────────────────────
|
||
|
||
private static function render_poll_modal( $thread_id ) { ?>
|
||
<div class="wbf-modal" id="wbfPollModal">
|
||
<div class="wbf-modal__box">
|
||
<button class="wbf-modal__close" onclick="document.getElementById('wbfPollModal').classList.remove('active')">×</button>
|
||
<h3 style="margin-bottom:1.25rem"><i class="fas fa-chart-bar" style="color:var(--c-primary)"></i> Umfrage erstellen</h3>
|
||
<input type="hidden" id="wbfPollThreadId" value="<?php echo (int)$thread_id; ?>">
|
||
|
||
<div class="wbf-form-row">
|
||
<label>Frage <span style="color:var(--c-danger)">*</span></label>
|
||
<input type="text" id="wbfPollQuestion" placeholder="Was ist deine Meinung zu…?" maxlength="200">
|
||
</div>
|
||
|
||
<div class="wbf-form-row">
|
||
<label>Antwortmöglichkeiten <small>(min. 2, max. 10)</small></label>
|
||
<div id="wbfPollOptions">
|
||
<div class="wbf-poll-opt-row">
|
||
<input type="text" class="wbf-poll-opt" placeholder="Option 1" maxlength="100">
|
||
<button type="button" class="wbf-btn wbf-btn--sm" style="background:rgba(240,82,82,.1);color:var(--c-danger);border-color:rgba(240,82,82,.3);min-width:32px;flex-shrink:0" onclick="wbfRemovePollOpt(this)">✕</button>
|
||
</div>
|
||
<div class="wbf-poll-opt-row">
|
||
<input type="text" class="wbf-poll-opt" placeholder="Option 2" maxlength="100">
|
||
<button type="button" class="wbf-btn wbf-btn--sm" style="background:rgba(240,82,82,.1);color:var(--c-danger);border-color:rgba(240,82,82,.3);min-width:32px;flex-shrink:0" onclick="wbfRemovePollOpt(this)">✕</button>
|
||
</div>
|
||
</div>
|
||
<button type="button" id="wbfPollAddOpt" class="wbf-btn wbf-btn--sm" style="margin-top:.5rem">
|
||
<i class="fas fa-plus"></i> Option hinzufügen
|
||
</button>
|
||
</div>
|
||
|
||
<div style="display:flex;gap:1.25rem;flex-wrap:wrap;align-items:flex-end;margin-bottom:1rem">
|
||
<label style="display:flex;align-items:center;gap:.4rem;font-size:.82rem;color:var(--c-text-dim);cursor:pointer">
|
||
<input type="checkbox" id="wbfPollMulti" style="accent-color:var(--c-primary);width:15px;height:15px">
|
||
Mehrfachauswahl erlauben
|
||
</label>
|
||
<div class="wbf-form-row" style="margin:0;flex:1;min-width:180px">
|
||
<label style="font-size:.72rem">Endet am <small style="color:var(--c-muted)">(optional)</small></label>
|
||
<input type="datetime-local" id="wbfPollEndsAt" min="<?php echo date('Y-m-d\TH:i'); ?>">
|
||
</div>
|
||
</div>
|
||
|
||
<div style="display:flex;gap:.75rem;align-items:center">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSubmitPoll">
|
||
<i class="fas fa-chart-bar"></i> Umfrage erstellen
|
||
</button>
|
||
<span class="wbf-msg" id="wbfPollMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
private static function render_new_thread_modal( $categories, $current, $preselect = 0 ) {
|
||
if (!$current) return;
|
||
$parents = array_filter($categories, fn($c) => (int)$c->parent_id === 0);
|
||
$children_map = [];
|
||
foreach ($categories as $c) { if ((int)$c->parent_id > 0) $children_map[$c->parent_id][] = $c; }
|
||
?>
|
||
<div class="wbf-modal" id="wbfNewThreadModal">
|
||
<div class="wbf-modal__box wbf-modal__box--lg">
|
||
<button class="wbf-modal__close" onclick="document.getElementById('wbfNewThreadModal').classList.remove('active')">×</button>
|
||
<h3 id="wbfModalTitle" style="margin-bottom:1.2rem"><i class="fas fa-plus-circle"></i> Neuen Thread erstellen</h3>
|
||
<div class="wbf-form-row"><label>Kategorie</label>
|
||
<select id="wbfThreadCat">
|
||
<?php foreach ($parents as $p): ?>
|
||
<optgroup label="<?php echo esc_attr($p->name); ?>">
|
||
<option value="<?php echo (int)$p->id; ?>" <?php selected($p->id,$preselect); ?>><?php echo esc_html($p->name); ?> (Allgemein)</option>
|
||
<?php foreach (($children_map[$p->id]??[]) as $child): ?>
|
||
<option value="<?php echo (int)$child->id; ?>" <?php selected($child->id,$preselect); ?>> ↳ <?php echo esc_html($child->name); ?></option>
|
||
<?php endforeach; ?>
|
||
</optgroup>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="wbf-form-row"><label id="wbfTitleLabel">Titel</label><input type="text" id="wbfThreadTitle" placeholder="Titel deines Threads"></div>
|
||
<?php $prefixes = WBF_DB::get_prefixes(); if (!empty($prefixes)): ?>
|
||
<div class="wbf-form-row" id="wbfPrefixRow">
|
||
<label>Präfix <small>(optional)</small></label>
|
||
<select id="wbfThreadPrefix">
|
||
<option value="">— Kein Präfix —</option>
|
||
<?php foreach ($prefixes as $px): ?>
|
||
<option value="<?php echo (int)$px->id; ?>"
|
||
data-color="<?php echo esc_attr($px->color); ?>"
|
||
data-bg="<?php echo esc_attr($px->bg_color); ?>">
|
||
<?php echo esc_html($px->label); ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<?php endif; ?>
|
||
<div class="wbf-form-row" id="wbfContentRow">
|
||
<label>Inhalt</label>
|
||
<?php self::render_editor_toolbar('wbfThreadContent'); ?>
|
||
<textarea id="wbfThreadContent" rows="7" placeholder="Was möchtest du besprechen?"></textarea>
|
||
</div>
|
||
<div class="wbf-form-row" id="wbfTagsRow">
|
||
<label>Tags <small>(kommagetrennt, max. 10 — z.B. php, wordpress, tipps)</small></label>
|
||
<div class="wbf-tag-input-wrap" id="wbfTagInputWrap">
|
||
<div class="wbf-tag-pills" id="wbfTagPills"></div>
|
||
<input type="text" id="wbfTagInput" placeholder="#tag hinzufügen…" autocomplete="off">
|
||
<input type="hidden" id="wbfThreadTags" value="">
|
||
<div class="wbf-tag-suggest" id="wbfTagSuggest" style="display:none"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Thread Submit Row -->
|
||
<div id="wbfThreadSubmitRow" style="display:flex;gap:1rem;align-items:center;margin-top:.25rem">
|
||
<button class="wbf-btn wbf-btn--primary" id="wbfSubmitThread"><i class="fas fa-paper-plane"></i> Thread erstellen</button>
|
||
<button type="button" id="wbfShowPollSection" class="wbf-btn wbf-btn--sm wbf-btn--outline-poll">
|
||
<i class="fas fa-chart-bar"></i> Umfrage hinzufügen
|
||
</button>
|
||
<span class="wbf-msg" id="wbfThreadMsg"></span>
|
||
</div>
|
||
|
||
<!-- Poll Section -->
|
||
<div id="wbfPollSection" style="margin-top:1.25rem;border-top:1px solid var(--c-border);padding-top:1.1rem;display:none">
|
||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:.9rem">
|
||
<span style="font-size:.85rem;font-weight:700;color:#fbbf24"><i class="fas fa-chart-bar"></i> Umfrage</span>
|
||
<button type="button" id="wbfRemovePollSection" class="wbf-btn wbf-btn--sm" style="background:rgba(240,82,82,.1);color:var(--c-danger);border-color:rgba(240,82,82,.3);padding:.25rem .6rem;font-size:.72rem"><i class="fas fa-xmark"></i> Entfernen</button>
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Frage <span style="color:var(--c-danger)">*</span></label>
|
||
<input type="text" id="wbfNewThreadPollQuestion" placeholder="Was ist deine Meinung zu…?" maxlength="200">
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Antwortmöglichkeiten <small>(min. 2, max. 10)</small></label>
|
||
<div id="wbfNewThreadPollOptions">
|
||
<div class="wbf-poll-opt-row" style="display:flex;gap:.5rem;margin-bottom:.4rem">
|
||
<input type="text" class="wbf-nt-poll-opt" placeholder="Option 1" maxlength="100">
|
||
<button type="button" class="wbf-btn wbf-btn--sm" style="background:rgba(240,82,82,.1);color:var(--c-danger);border-color:rgba(240,82,82,.3);min-width:32px;flex-shrink:0" onclick="wbfRemoveNTPollOpt(this)">✕</button>
|
||
</div>
|
||
<div class="wbf-poll-opt-row" style="display:flex;gap:.5rem;margin-bottom:.4rem">
|
||
<input type="text" class="wbf-nt-poll-opt" placeholder="Option 2" maxlength="100">
|
||
<button type="button" class="wbf-btn wbf-btn--sm" style="background:rgba(240,82,82,.1);color:var(--c-danger);border-color:rgba(240,82,82,.3);min-width:32px;flex-shrink:0" onclick="wbfRemoveNTPollOpt(this)">✕</button>
|
||
</div>
|
||
</div>
|
||
<button type="button" id="wbfNTPollAddOpt" class="wbf-btn wbf-btn--sm" style="margin-top:.5rem">
|
||
<i class="fas fa-plus"></i> Option hinzufügen
|
||
</button>
|
||
</div>
|
||
<label style="display:flex;align-items:center;gap:.4rem;font-size:.82rem;color:var(--c-text-dim);cursor:pointer;margin-bottom:.75rem">
|
||
<input type="checkbox" id="wbfNTPollMulti" style="accent-color:var(--c-primary);width:15px;height:15px">
|
||
Mehrfachauswahl erlauben
|
||
</label>
|
||
<div class="wbf-form-row" style="margin-bottom:1rem">
|
||
<label style="font-size:.78rem;font-weight:600;color:var(--c-text-dim)">Endet am <small style="font-weight:400;color:var(--c-muted)">(optional)</small></label>
|
||
<input type="datetime-local" id="wbfNTPollEndsAt" min="<?php echo date('Y-m-d\TH:i'); ?>" style="width:100%;box-sizing:border-box">
|
||
</div>
|
||
<div style="display:flex;gap:1rem;align-items:center">
|
||
<button class="wbf-btn wbf-btn--outline-poll" id="wbfSubmitPollThread"><i class="fas fa-chart-bar"></i> Umfrage erstellen</button>
|
||
<span class="wbf-msg" id="wbfPollThreadMsg"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php }
|
||
|
||
// ── Passwort zurücksetzen (via Token-Link) ────────────────────────────────
|
||
|
||
private static function view_reset_password() {
|
||
$token = sanitize_text_field($_GET['wbf_reset_token'] ?? '');
|
||
$valid = $token ? WBF_DB::verify_reset_token($token) : false;
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar(null); ?>
|
||
<div class="wbf-container wbf-mt" style="max-width:480px;margin-left:auto;margin-right:auto">
|
||
<div class="wbf-widget" style="padding:2rem">
|
||
<h2 style="font-size:1.1rem;font-weight:700;color:var(--c-text);margin-bottom:1.25rem">
|
||
<i class="fas fa-lock-open" style="color:var(--c-primary)"></i> Passwort zurücksetzen
|
||
</h2>
|
||
<?php if (!$valid): ?>
|
||
<div class="wbf-notice wbf-notice--warning">
|
||
<i class="fas fa-exclamation-triangle"></i>
|
||
Dieser Link ist ungültig oder abgelaufen. Bitte fordere einen neuen an.
|
||
</div>
|
||
<a href="<?php echo esc_url(wbf_get_forum_url()); ?>" class="wbf-btn wbf-btn--primary" style="margin-top:1rem;display:inline-block">
|
||
<i class="fas fa-home"></i> Zurück zum Forum
|
||
</a>
|
||
<?php else: ?>
|
||
<div class="wbf-form-row">
|
||
<label>Neues Passwort</label>
|
||
<input type="password" id="wbfResetPass1" placeholder="Mindestens 6 Zeichen">
|
||
</div>
|
||
<div class="wbf-form-row">
|
||
<label>Passwort wiederholen</label>
|
||
<input type="password" id="wbfResetPass2" placeholder="Passwort bestätigen">
|
||
</div>
|
||
<input type="hidden" id="wbfResetToken" value="<?php echo esc_attr($token); ?>">
|
||
<button class="wbf-btn wbf-btn--primary wbf-btn--full" id="wbfResetSubmit">
|
||
<i class="fas fa-check"></i> Passwort ändern
|
||
</button>
|
||
<span class="wbf-msg" id="wbfResetMsg" style="display:block;margin-top:.75rem"></span>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
|
||
|
||
// ── Mitglieder-Liste ──────────────────────────────────────────────────────
|
||
|
||
private static function view_members() {
|
||
$current = WBF_Auth::get_current_user();
|
||
$maint_m = wbf_get_settings()['maintenance_mode'] ?? '0';
|
||
if ($maint_m === '1' && (!$current || WBF_Roles::level($current->role) < 50)) return self::view_maintenance();
|
||
if ( ! $current ) {
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap"><?php self::render_topbar(null); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<div class="wbf-notice wbf-notice--info"><i class="fas fa-lock"></i>
|
||
Bitte <a href="#" class="wbf-login-link">einloggen</a> um die Mitgliederliste zu sehen.
|
||
</div>
|
||
</div></div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
$page = max(1, (int)($_GET['mp'] ?? 1));
|
||
$per_page = 24;
|
||
$offset = ($page - 1) * $per_page;
|
||
$search = sanitize_text_field($_GET['ms'] ?? '');
|
||
$sort = in_array($_GET['msort'] ?? '', ['registered','post_count','display_name']) ? $_GET['msort'] : 'registered';
|
||
|
||
global $wpdb;
|
||
$where = $search
|
||
? $wpdb->prepare("WHERE (display_name LIKE %s OR username LIKE %s)", '%'.$search.'%', '%'.$search.'%')
|
||
: '';
|
||
$order = $sort === 'display_name' ? 'ASC' : 'DESC';
|
||
|
||
$total = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users $where");
|
||
$members = $wpdb->get_results($wpdb->prepare(
|
||
"SELECT id, username, display_name, avatar_url, role, post_count, registered, last_active
|
||
FROM {$wpdb->prefix}forum_users $where
|
||
ORDER BY $sort $order
|
||
LIMIT %d OFFSET %d",
|
||
$per_page, $offset
|
||
));
|
||
$pages = ceil($total / $per_page) ?: 1;
|
||
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(remove_query_arg(['forum_members','mp','ms','msort'])); ?>">
|
||
<i class="fas fa-home"></i> Forum
|
||
</a>
|
||
<span>/</span><span><i class="fas fa-users"></i> Mitglieder</span>
|
||
</nav>
|
||
|
||
<div class="wbf-section-header" style="margin-bottom:1.25rem">
|
||
<h2><i class="fas fa-users"></i> Mitglieder (<?php echo number_format($total); ?>)</h2>
|
||
</div>
|
||
|
||
<!-- Suche & Sortierung -->
|
||
<form method="get" class="wbf-members-filter">
|
||
<input type="hidden" name="forum_members" value="1">
|
||
<input type="text" name="ms" value="<?php echo esc_attr($search); ?>"
|
||
placeholder="Mitglied suchen…" class="wbf-members-search">
|
||
<select name="msort" class="wbf-members-sort" onchange="this.form.submit()">
|
||
<option value="registered" <?php selected($sort,'registered'); ?>>Neueste zuerst</option>
|
||
<option value="post_count" <?php selected($sort,'post_count'); ?>>Aktivste zuerst</option>
|
||
<option value="display_name"<?php selected($sort,'display_name'); ?>>Alphabetisch</option>
|
||
</select>
|
||
<button type="submit" class="wbf-btn wbf-btn--primary wbf-btn--sm">
|
||
<i class="fas fa-search"></i> Suchen
|
||
</button>
|
||
<?php if ($search): ?>
|
||
<a href="?forum_members=1" class="wbf-btn wbf-btn--sm">
|
||
<i class="fas fa-xmark"></i> Zurücksetzen
|
||
</a>
|
||
<?php endif; ?>
|
||
</form>
|
||
|
||
<!-- Mitglieder-Grid -->
|
||
<div class="wbf-members-grid">
|
||
<?php foreach ($members as $m):
|
||
$role = WBF_Roles::get($m->role);
|
||
$is_online = WBF_DB::is_online($m->id);
|
||
?>
|
||
<a href="?forum_profile=<?php echo (int)$m->id; ?>" class="wbf-member-card">
|
||
<div class="wbf-member-card__avatar-wrap">
|
||
<?php echo self::avatar($m->avatar_url, $m->display_name, 64); ?>
|
||
<?php if ($is_online): ?>
|
||
<span class="wbf-member-card__online-dot" title="Online"></span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="wbf-member-card__name"><?php echo esc_html($m->display_name); ?></div>
|
||
<div class="wbf-member-card__username">@<?php echo esc_html($m->username); ?></div>
|
||
<div class="wbf-member-card__badge"><?php echo self::role_badge($m->role); ?></div>
|
||
<div class="wbf-member-card__stats">
|
||
<span><i class="fas fa-comment-dots"></i> <?php echo number_format((int)$m->post_count); ?></span>
|
||
<span><i class="fas fa-calendar"></i> <?php echo date_i18n('d.m.Y', strtotime($m->registered)); ?></span>
|
||
</div>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
|
||
<?php if (empty($members)): ?>
|
||
<div class="wbf-empty" style="grid-column:1/-1">
|
||
<i class="fas fa-users-slash"></i>
|
||
<p>Keine Mitglieder gefunden.</p>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<!-- Pagination -->
|
||
<?php if ($pages > 1): ?>
|
||
<div class="wbf-pagination">
|
||
<?php for ($i = 1; $i <= $pages; $i++): ?>
|
||
<a href="?forum_members=1<?php echo $search ? '&ms='.urlencode($search) : ''; ?>&msort=<?php echo esc_attr($sort); ?>&mp=<?php echo $i; ?>"
|
||
class="wbf-page-btn<?php echo ($i === $page) ? ' active' : ''; ?>">
|
||
<?php echo $i; ?>
|
||
</a>
|
||
<?php endfor; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<?php self::render_forum_footer(); ?>
|
||
</div>
|
||
<?php self::render_auth_modal(); ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
|
||
|
||
// ── Wartungsmodus ─────────────────────────────────────────────────────────
|
||
|
||
private static function view_maintenance() {
|
||
$s = wbf_get_settings();
|
||
$title = esc_html($s['maintenance_title'] ?? 'Wartungsarbeiten');
|
||
$msg = esc_html($s['maintenance_message'] ?? 'Das Forum wird gerade gewartet. Bitte versuche es später erneut.');
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<div style="min-height:60vh;display:flex;align-items:center;justify-content:center;text-align:center;padding:2rem">
|
||
<div style="max-width:480px">
|
||
<div style="font-size:4rem;margin-bottom:1.5rem">🔧</div>
|
||
<h1 style="font-size:1.6rem;font-weight:800;color:var(--c-text);margin-bottom:1rem"><?php echo $title; ?></h1>
|
||
<p style="color:var(--c-text-dim);font-size:1rem;line-height:1.7"><?php echo $msg; ?></p>
|
||
<p style="margin-top:2rem">
|
||
<a href="#" class="wbf-login-link wbf-btn wbf-btn--sm wbf-btn--outline" style="font-size:.85rem">
|
||
<i class="fas fa-lock"></i> Als Admin einloggen
|
||
</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<?php self::render_auth_modal(); ?>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
// ── FORUM-FOOTER ──────────────────────────────────────────────────────────
|
||
|
||
private static function render_forum_footer() {
|
||
if ( ( wbf_get_settings()['rules_enabled'] ?? '1' ) !== '1' ) return;
|
||
$rules_url = esc_url( wbf_get_forum_url() . '?forum_rules=1' );
|
||
?>
|
||
<div style="border:1px solid var(--c-border);border-radius:var(--radius);margin-top:2rem;padding:1rem 1.25rem;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.75rem;background:var(--c-surface)">
|
||
<span style="font-size:.78rem;color:var(--c-muted)">
|
||
<i class="fas fa-shield-halved" style="color:var(--c-primary);margin-right:.35rem"></i>
|
||
Durch die Nutzung des Forums stimmst du unseren Regeln zu.
|
||
</span>
|
||
<a href="<?php echo $rules_url; ?>"
|
||
style="display:inline-flex;align-items:center;gap:.4rem;font-size:.78rem;font-weight:700;color:#0d1117;background:var(--c-primary);padding:.35rem .9rem;border-radius:6px;text-decoration:none;transition:opacity .15s"
|
||
onmouseover="this.style.opacity='.85'" onmouseout="this.style.opacity='1'">
|
||
<i class="fas fa-scroll"></i> Forum-Regeln lesen
|
||
</a>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
// ── FORUM-REGELN ──────────────────────────────────────────────────────────
|
||
|
||
private static function view_rules() {
|
||
$current = WBF_Auth::get_current_user();
|
||
$s = wbf_get_settings();
|
||
if ( ( $s['rules_enabled'] ?? '1' ) !== '1' ) {
|
||
return '<p class="wbf-notice">Diese Seite ist nicht verfügbar.</p>';
|
||
}
|
||
$title = esc_html( $s['rules_title'] ?? 'Forum-Regeln & Nutzungsbedingungen' );
|
||
$raw = $s['rules_content'] ?? '';
|
||
ob_start(); ?>
|
||
<div class="wbf-wrap">
|
||
<?php self::render_topbar($current); ?>
|
||
<div class="wbf-container wbf-mt" style="max-width:820px">
|
||
<nav class="wbf-breadcrumb">
|
||
<a href="<?php echo esc_url(wbf_get_forum_url()); ?>"><i class="fas fa-home"></i> Forum</a>
|
||
<span>/</span><span><i class="fas fa-shield-halved"></i> Regeln</span>
|
||
</nav>
|
||
|
||
<div style="background:var(--c-surface);border:1px solid var(--c-border);border-radius:var(--radius);overflow:hidden;margin-bottom:2rem">
|
||
<div style="background:linear-gradient(135deg,rgba(0,180,216,.12),rgba(99,102,241,.08));border-bottom:1px solid var(--c-border);padding:1.75rem 2rem;display:flex;align-items:center;gap:1rem">
|
||
<div style="width:48px;height:48px;border-radius:12px;background:rgba(0,180,216,.15);border:1px solid rgba(0,180,216,.25);display:flex;align-items:center;justify-content:center;font-size:1.3rem;flex-shrink:0">📜</div>
|
||
<div>
|
||
<h1 style="font-size:1.3rem;font-weight:800;color:var(--c-text);margin:0 0 .2rem"><?php echo $title; ?></h1>
|
||
<p style="font-size:.8rem;color:var(--c-muted);margin:0">
|
||
<i class="fas fa-clock"></i> Zuletzt aktualisiert: <?php echo date_i18n('d. F Y'); ?>
|
||
· <i class="fas fa-eye"></i> Bitte sorgfältig lesen
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<div class="wbf-rules-body" style="padding:2rem">
|
||
<?php echo self::render_rules_content( $raw ); ?>
|
||
</div>
|
||
<div style="border-top:1px solid var(--c-border);padding:1.25rem 2rem;background:rgba(0,0,0,.12);display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.75rem">
|
||
<span style="font-size:.82rem;color:var(--c-muted)">
|
||
<i class="fas fa-info-circle"></i> Mit der Nutzung des Forums stimmst du diesen Regeln zu.
|
||
</span>
|
||
<a href="<?php echo esc_url(wbf_get_forum_url()); ?>" class="wbf-btn wbf-btn--sm wbf-btn--primary" style="color:#0d1117;font-weight:700">
|
||
<i class="fas fa-arrow-left"></i> Zurück zum Forum
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<?php return ob_get_clean();
|
||
}
|
||
|
||
private static function render_rules_content( $raw ) {
|
||
if ( empty( $raw ) ) {
|
||
return '<p style="color:var(--c-muted)">Noch keine Regeln hinterlegt.</p>';
|
||
}
|
||
$paragraphs = preg_split( '/\n{2,}/', trim( $raw ) );
|
||
$out = '';
|
||
foreach ( $paragraphs as $para ) {
|
||
$para = trim( $para );
|
||
if ( $para === '' ) continue;
|
||
if ( preg_match( '/^\*\*(\d+\.\s*.+?)\*\*$/', $para, $m ) ) {
|
||
preg_match('/^(\d+)\.\s*(.+)$/', $m[1], $parts);
|
||
$num = esc_html($parts[1] ?? '');
|
||
$text = esc_html($parts[2] ?? $m[1]);
|
||
$out .= '<div class="wbf-rules-section">'
|
||
. '<span class="wbf-rules-num">' . $num . '</span>'
|
||
. '<h2 class="wbf-rules-heading">' . $text . '</h2>'
|
||
. '</div>';
|
||
} else {
|
||
$para = htmlspecialchars( $para, ENT_QUOTES, 'UTF-8' );
|
||
$para = preg_replace( '/\*\*(.+?)\*\*/s', '<strong>$1</strong>', $para );
|
||
$para = nl2br( $para );
|
||
$out .= '<p class="wbf-rules-para">' . $para . '</p>';
|
||
}
|
||
}
|
||
return $out;
|
||
}
|
||
|
||
}
|
||
|
||
WBF_Shortcodes::init();
|