Upload folder via GUI - includes

This commit is contained in:
Git Manager GUI
2026-04-05 12:40:36 +02:00
parent cf42b89332
commit 764f760b61
4 changed files with 607 additions and 364 deletions

View File

@@ -932,11 +932,12 @@ class WBF_Shortcodes {
$shop_tab_id = 'shop';
$allowed_tabs = [1,2,3,4];
if ($is_own && $shop_active) $allowed_tabs[] = $shop_tab_id;
if ($is_own) $allowed_tabs[] = 'plugins';
$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') {
if (!is_int($active_tab) && $active_tab !== $shop_tab_id && $active_tab !== 'mc' && $active_tab !== 'plugins') {
$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)
@@ -951,207 +952,177 @@ class WBF_Shortcodes {
<span>/</span><span>Profil</span>
</nav>
<div class="wbf-profile-layout">
<!-- ══ NEW PROFILE LAYOUT v4 ══ -->
<div class="wbf-pv">
<!-- ── SIDEBAR ─────────────────────────────────────────── -->
<aside class="wbf-profile-sidebar">
<!-- ── HERO CARD ────────────────────────────────────────────── -->
<div class="wbf-pv-hero">
<!-- 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>
<div class="wbf-pv-banner" id="wbfProfileBannerWrap">
<?php if (!empty($profile->banner_url)): ?>
<img src="<?php echo esc_url($profile->banner_url); ?>" alt="" id="wbfProfileBanner" class="wbf-pv-banner__img">
<?php else: ?>
<div class="wbf-pv-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">
<div class="wbf-pv-banner__overlay"></div>
<?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 class="wbf-pv-banner__upload" title="Banner ändern">
<i class="fas fa-image"></i> Banner ändern
<input type="file" id="wbfBannerFile" name="banner" 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>
<!-- Identity row -->
<div class="wbf-pv-identity-row">
<!-- Avatar -->
<div class="wbf-pv-avatar-wrap">
<?php $profile_online = WBF_DB::is_online($profile->id, 15); ?>
<div class="wbf-pv-avatar-ring">
<img src="<?php echo esc_url($profile->avatar_url); ?>"
alt="<?php echo esc_attr($profile->display_name); ?>"
id="wbfProfileAvatar" class="wbf-pv-avatar">
</div>
<?php if ($profile_online): ?>
<span class="wbf-pv-online-dot" title="Online"></span>
<?php endif; ?>
<?php if ($is_own): ?>
<label class="wbf-pv-avatar-cam" title="Avatar ändern">
<i class="fas fa-camera"></i>
<input type="file" id="wbfAvatarFile" accept="image/*" style="display:none">
</label>
<?php endif; ?>
</div>
<!-- Name + role + username + status -->
<div class="wbf-pv-identity">
<h1 class="wbf-pv-name"><?php echo esc_html($profile->display_name); ?></h1>
<div class="wbf-pv-meta">
<?php echo self::role_badge($profile->role); ?>
<span class="wbf-pv-username">@<?php echo esc_html($profile->username); ?></span>
<?php if ($profile_online): ?>
<span class="wbf-pv-online-badge"><span class="wbf-pv-online-pulse"></span> Online</span>
<?php else:
$last = $profile->last_active ?? null;
if ($last && $last !== '0000-00-00 00:00:00'): ?>
<span class="wbf-pv-lastseen"><i class="fas fa-clock"></i> <?php echo self::time_ago($last); ?></span>
<?php endif; endif; ?>
</div>
<div class="wbf-pv-stats-row">
<div class="wbf-pv-stat"><span><?php echo number_format((int)$profile->post_count); ?></span><em>Beiträge</em></div>
<div class="wbf-pv-stat-sep"></div>
<div class="wbf-pv-stat"><span><?php echo date_i18n('m/Y', strtotime($profile->registered)); ?></span><em>Dabei seit</em></div>
</div>
</div>
<?php if ($current && !$is_own && WBF_Roles::level($profile->role) >= 0): ?>
<div class="wbf-pv-actions">
<a href="?forum_dm=inbox&with=<?php echo (int)$profile->id; ?>" class="wbf-btn wbf-btn--primary wbf-btn--sm">
<i class="fas fa-envelope"></i> Nachricht
</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':'Ignorieren'; ?>
</button>
<?php endif; ?>
</div>
<?php endif; ?>
</div><!-- /.wbf-pv-identity-row -->
</div><!-- /.wbf-pv-hero -->
<!-- ── TABS ──────────────────────────────────────────────────── -->
<div class="wbf-pv-tabs-bar">
<?php if ($is_own): ?>
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=1" class="wbf-pv-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-pv-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-pv-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-pv-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-pv-tab<?php echo $active_tab==='shop'?' active':''; ?>"><i class="fas fa-shopping-cart"></i> Käufe</a>
<?php endif; ?>
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=mc" class="wbf-pv-tab<?php echo $active_tab==='mc'?' active':''; ?>"><i class="fas fa-plug"></i> Verbindungen</a>
<?php if ( function_exists('vmcp_bridge_is_available') && vmcp_bridge_is_available() ) : ?>
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=plugins" class="wbf-pv-tab<?php echo $active_tab==='plugins'?' active':''; ?>"><i class="fas fa-puzzle-piece"></i> Plugins</a>
<?php endif; ?>
<?php else: ?>
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=2" class="wbf-pv-tab active"><i class="fas fa-comments"></i> Aktivität</a>
<?php endif; ?>
</div><!-- /.wbf-pv-tabs-bar -->
<!-- ── BODY ──────────────────────────────────────────────────── -->
<div class="wbf-pv-body">
<!-- Sidebar: Level + Bio + Sig + Custom Fields -->
<aside class="wbf-pv-sidebar">
<?php $level_bar = WBF_Levels::progress_bar((int)$profile->post_count); if ($level_bar): ?>
<div class="wbf-pv-sb-section">
<span class="wbf-pv-sb-label"><i class="fas fa-trophy"></i> Level</span>
<?php echo $level_bar; ?>
</div>
<?php endif; ?>
<?php if (!empty($profile->bio)): ?>
<div class="wbf-pv-sb-section">
<span class="wbf-pv-sb-label"><i class="fas fa-align-left"></i> Bio</span>
<div class="wbf-pv-sb-text"><?php echo WBF_BBCode::render($profile->bio); ?></div>
</div>
<?php endif; ?>
<?php if (!empty($profile->signature)): ?>
<div class="wbf-pv-sb-section wbf-pv-sb-section--sig">
<span class="wbf-pv-sb-label"><i class="fas fa-pen-nib"></i> Signatur</span>
<div class="wbf-pv-sb-sig"><?php echo WBF_BBCode::render($profile->signature); ?></div>
</div>
<?php endif; ?>
<?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;
$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 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); ?>
<div class="wbf-pv-sb-section">
<span class="wbf-pv-sb-label">
<?php if(!empty($scat_sb['icon'])): ?><span><?php echo esc_html($scat_sb['icon']); ?></span><?php endif; ?>
<?php echo esc_html($scat_sb['name']); ?>
</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; ?>
<?php foreach ($cf_by_cat_sb[$scid_sb] as $cf_e):
$def_sb=$cf_e['def']; $val_sb=$cf_e['val'];
$k_sb=strtolower($def_sb['key']);
$is_tg=strpos($k_sb,'telegram')!==false;
$is_dc=strpos($k_sb,'discord')!==false; ?>
<div class="wbf-pv-cf-row">
<span class="wbf-pv-cf-lbl"><?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" class="wbf-pv-cf-val wbf-pv-cf-val--link"><?php echo esc_html(mb_strtolower(preg_replace('#^https?://#i','',$val_sb))); ?></a>
<?php elseif($is_tg): $tu=ltrim(trim($val_sb),'@'); ?>
<a href="https://t.me/<?php echo rawurlencode($tu); ?>" target="_blank" rel="noopener noreferrer" style="color:#29b6f6">@<?php echo esc_html($tu); ?></a>
<?php elseif($is_dc): ?>
<span style="color:#7289da"><?php echo esc_html($val_sb); ?></span>
<?php elseif($def_sb['type']==='textarea'): ?>
<span><?php echo nl2br(esc_html($val_sb)); ?></span>
<?php elseif($def_sb['type']==='date'): $as=self::calc_age($val_sb); ?>
<span><?php echo $as!==null?esc_html((string)$as).' Jahre':'—'; ?></span>
<?php else: ?>
<span class="wbf-pv-cf-val"><?php echo esc_html($val_sb); ?></span>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
</aside>
</aside><!-- /.wbf-pv-sidebar -->
<!-- ── 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; ?>
<!-- Content: tab output -->
<div class="wbf-pv-content">
<!-- ══════════════════════════════════════════════════
TAB SHOP — Käufe (Shop-Plugin)
══════════════════════════════════════════════════ -->
@@ -1799,125 +1770,114 @@ class WBF_Shortcodes {
Neue Integrationen: einfach weiteres .wbf-connection-card-Block
via apply_filters('wbf_profile_connections', ...) hinzufügen.
══════════════════════════════════════════════════ -->
<?php
/* ── PLUGINS TAB ── direkt in wbf-pv-content, gleiche Ebene wie Shop/Tab1/2/3 */
if ( $is_own && $active_tab === 'plugins' && function_exists('wbf_render_plugin_watch_tab') ) :
wbf_render_plugin_watch_tab( $profile, $current );
endif;
?>
<?php if ( $is_own && $active_tab === 'mc' ) : ?>
<?php
// ── Gallerie Bridge ──
$has_gallery = class_exists('MC_Gallery_Forum_Bridge');
$mc_gallery_content = $has_gallery ? apply_filters('wbf_profile_tab_content', '', 'minecraft', $profile) : '';
// ── StatusAPI Bridge ──
$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);
// ── Discord ──
$discord_meta = WBF_DB::get_user_meta($profile->id);
$discord_current = trim($discord_meta['discord_username'] ?? '');
$discord_connected = $discord_current !== '';
$s_cfg = wbf_get_settings();
$discord_bot_configured = !empty(trim($s_cfg['discord_bot_token'] ?? ''));
?>
<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">
<div class="wbf-svc-list">
<?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; ?>
<!-- ── GALLERIE ─────────────────────────────────── -->
<?php if ($has_gallery): ?>
<div class="wbf-svc-card">
<div class="wbf-svc-card__row">
<div class="wbf-svc-icon wbf-svc-icon--mc">
<i class="fas fa-images"></i>
</div>
<div class="wbf-svc-info">
<span class="wbf-svc-name">Gallerie</span>
<span class="wbf-svc-desc">Minecraft-Account verknüpfen um Bilder ohne Token hochzuladen</span>
</div>
<div class="wbf-svc-actions wbf-svc-gallery-actions">
<?php echo $mc_gallery_content; ?>
</div>
</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>
<!-- ── MINECRAFT INGAME ──────────────────────────── -->
<div class="wbf-svc-card">
<div class="wbf-svc-card__row">
<div class="wbf-svc-icon wbf-svc-icon--mc">
<i class="fas fa-cubes"></i>
</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 &nbsp;→&nbsp;
Schritt 2: <code>/forumlink &lt;token&gt;</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 class="wbf-svc-info">
<div class="wbf-svc-info__top">
<span class="wbf-svc-name">Minecraft</span>
<?php if (!$mc_enabled): ?>
<span class="wbf-svc-badge wbf-svc-badge--off"><i class="fas fa-circle-xmark"></i> Nicht konfiguriert</span>
<?php elseif ($mc_linked): ?>
<span class="wbf-svc-badge wbf-svc-badge--on"><i class="fas fa-check-circle"></i> Verbunden</span>
<div class="wbf-svc-linked-user">
<img src="https://mc-heads.net/avatar/<?php echo urlencode($mc_name ?: $mc_uuid); ?>/24" width="24" height="24" style="border-radius:3px;image-rendering:pixelated">
<strong><?php echo esc_html($mc_name ?: $mc_uuid); ?></strong>
</div>
<?php else: ?>
<span class="wbf-svc-badge wbf-svc-badge--off"><i class="fas fa-circle-xmark"></i> Nicht verbunden</span>
<?php endif; ?>
</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>
<span class="wbf-svc-desc">Ingame-Benachrichtigungen bei Antworten, Erwähnungen &amp; PNs</span>
</div>
<div class="wbf-svc-actions">
<?php if (!$mc_enabled): ?>
<!-- nothing -->
<?php elseif ($mc_linked): ?>
<div id="wbf-mc-msg" class="wbf-svc-msg"></div>
<button type="button" id="wbf-mc-unlink-btn" onclick="wbfMcUnlink()" style="height:34px;padding:0 14px;font-size:.79rem;font-weight:600;display:inline-flex;align-items:center;gap:5px;border-radius:6px;background:var(--c-surface2);color:var(--c-text-dim);border:1.5px solid var(--c-border-d);white-space:nowrap;cursor:pointer;font-family:inherit;box-sizing:border-box;line-height:1">
<i class="fas fa-unlink"></i> Trennen
</button>
<?php else: ?>
<div id="wbf-mc-msg" class="wbf-svc-msg"></div>
<button type="button" id="wbf-mc-gen-btn" onclick="wbfMcGenerateToken()" style="height:34px;padding:0 14px;font-size:.79rem;font-weight:600;display:inline-flex;align-items:center;gap:5px;border-radius:6px;background:var(--c-primary);color:#fff;border:1.5px solid var(--c-primary);white-space:nowrap;cursor:pointer;font-family:inherit;box-sizing:border-box;line-height:1">
<i class="fas fa-key"></i> Verknüpfen
</button>
<?php endif; ?>
</div>
</div>
<?php if ($mc_enabled && !$mc_linked): ?>
<div class="wbf-svc-card__form" id="wbf-mc-token-box" style="display:none">
<div class="wbf-svc-token-box">
<div class="wbf-svc-token-box__header">
<span><i class="fas fa-terminal"></i> Ingame eingeben: <code id="wbf-mc-cmd-value">/forumlink ...</code></span>
<div style="display:flex;align-items:center;gap:.5rem">
<span id="wbf-mc-token-timer" style="font-size:.75rem;color:#f97316;font-weight:600"></span>
<button type="button" class="wbf-btn wbf-btn--sm" id="wbf-mc-copy-btn" onclick="wbfMcCopyToken()"><i class="fas fa-copy"></i></button>
</div>
</div>
<code id="wbf-mc-token-value" class="wbf-svc-token-code"></code>
<div style="margin-top:.6rem;height:3px;border-radius:2px;background:var(--c-border);overflow:hidden">
<div id="wbf-mc-token-progress" style="height:100%;background:var(--c-primary);transition:width 1s linear;width:100%"></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>
<?php endif; ?>
</div>
<script>
<script>
(function(){
var _pollInterval = null;
var _timerInterval = null;
@@ -2018,84 +1978,79 @@ class WBF_Shortcodes {
})();
</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>
<!-- ── DISCORD ──────────────────────────────────── -->
<div class="wbf-svc-card wbf-svc-card--last">
<div class="wbf-svc-card__row">
<div class="wbf-svc-icon wbf-svc-icon--discord">
<i class="fab fa-discord"></i>
</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 class="wbf-svc-info">
<div class="wbf-svc-info__top">
<span class="wbf-svc-name">Discord</span>
<?php if ($discord_connected): ?>
<span class="wbf-svc-badge wbf-svc-badge--on"><i class="fas fa-check-circle"></i> Verbunden</span>
<div class="wbf-svc-linked-user wbf-svc-linked-user--discord">
<i class="fab fa-discord"></i>
<strong><?php echo esc_html($discord_current); ?></strong>
</div>
<?php else: ?>
<span class="wbf-svc-badge wbf-svc-badge--off"><i class="fas fa-circle-xmark"></i> Nicht verbunden</span>
<?php endif; ?>
</div>
<span class="wbf-svc-desc">Discord-Account mit deinem Profil verknüpfen</span>
</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>
<div class="wbf-svc-actions">
<?php if ($discord_connected): ?>
<button type="button" id="wbf-discord-relink" style="height:34px;padding:0 14px;font-size:.79rem;font-weight:600;display:inline-flex;align-items:center;gap:5px;border-radius:6px;background:var(--c-primary);color:#fff;border:1.5px solid var(--c-primary);white-space:nowrap;cursor:pointer;font-family:inherit;box-sizing:border-box;line-height:1"><i class="fas fa-rotate"></i> Neu verknüpfen</button>
<button type="button" id="wbf-discord-disconnect" style="height:34px;padding:0 14px;font-size:.79rem;font-weight:600;display:inline-flex;align-items:center;gap:5px;border-radius:6px;background:var(--c-surface2);color:var(--c-text-dim);border:1.5px solid var(--c-border-d);white-space:nowrap;cursor:pointer;font-family:inherit;box-sizing:border-box;line-height:1"><i class="fas fa-unlink"></i> Trennen</button>
<?php else: ?>
<!-- Step 1 inline: input + send button -->
<?php if ($discord_bot_configured): ?>
<div class="wbf-svc-discord-inline" id="wbf-dc-step1-inline">
<input type="text" id="wbf-discord-input" placeholder="Discord-Username" maxlength="40" autocomplete="off" style="height:34px;padding:0 10px;font-size:.82rem;font-family:inherit;background:var(--c-bg2);border:1.5px solid var(--c-border-d);border-radius:6px;color:var(--c-text);width:155px;box-sizing:border-box">
<button type="button" id="wbf-discord-send-code" style="height:34px;padding:0 14px;font-size:.79rem;font-weight:600;display:inline-flex;align-items:center;gap:5px;border-radius:6px;background:var(--c-primary);color:#fff;border:1.5px solid var(--c-primary);white-space:nowrap;cursor:pointer;font-family:inherit;box-sizing:border-box;line-height:1">
<i class="fab fa-discord"></i> Code senden
</button>
</div>
<?php else: ?>
<span style="font-size:.75rem;color:var(--c-muted)"><i class="fas fa-triangle-exclamation"></i> Bot nicht konfiguriert</span>
<?php endif; ?>
<?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>
<!-- Step 2: code verification (expands below) -->
<?php if (!$discord_connected && $discord_bot_configured): ?>
<div id="wbf-dc-step2" style="display:none">
<div class="wbf-svc-card__form">
<div class="wbf-svc-discord-step2-row">
<label style="font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--c-text-dim);margin-bottom:.3rem;display:block">Bestätigungs-Code (aus Discord-DM)</label>
<div style="display:flex;align-items:center;gap:.4rem;flex-wrap:wrap">
<input type="text" id="wbf-discord-code-input" placeholder="A1B2C3" maxlength="6" autocomplete="off"
style="font-family:monospace;letter-spacing:.15em;text-transform:uppercase;width:120px">
<button type="button" class="wbf-btn wbf-btn--sm wbf-btn--primary" id="wbf-discord-verify">
<i class="fas fa-check"></i> Bestätigen
</button>
<button type="button" class="wbf-btn wbf-btn--sm" id="wbf-discord-code-back">
<i class="fas fa-arrow-left"></i> Zurück
</button>
</div>
<p style="font-size:.75rem;color:var(--c-muted);margin:.35rem 0 0"><i class="fas fa-clock"></i> Code ist 10 Minuten gültig.</p>
</div>
</div>
</div>
<?php endif; ?>
<!-- Connected: re-link form (hidden by default) -->
<?php if ($discord_connected): ?>
<div id="wbf-discord-form" style="display:none">
<div class="wbf-svc-card__form">
<?php self::render_discord_form($discord_bot_configured); ?>
</div>
</div>
<?php endif; ?>
<div id="wbf-discord-msg" class="wbf-svc-msg"></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);
?>
<?php echo apply_filters('wbf_profile_connections', '', $profile); ?>
</div>
</div>
@@ -2104,6 +2059,9 @@ class WBF_Shortcodes {
</div><!-- /.wbf-profile-main -->
</div><!-- /.wbf-profile-layout -->
</div><!-- /.wbf-pv-content -->
</div><!-- /.wbf-pv-body -->
</div><!-- /.wbf-pv -->
</div>
</div>
<?php self::render_auth_modal(); ?>