Update from Git Manager GUI
This commit is contained in:
@@ -30,6 +30,7 @@ add_action( 'admin_menu', function() {
|
||||
add_submenu_page( 'wbf-admin', 'Thread-Präfixe','Thread-Präfixe','manage_options', 'wbf-prefixes', 'wbf_admin_prefixes' );
|
||||
add_submenu_page( 'wbf-admin', 'Wortfilter', 'Wortfilter', 'manage_options', 'wbf-wordfilter', 'wbf_admin_wordfilter' );
|
||||
add_submenu_page( 'wbf-admin', 'Export / Import','Export / Import','manage_options', 'wbf-export', 'wbf_admin_export' );
|
||||
add_submenu_page( 'wbf-admin', '🎮 Discord', '🎮 Discord', 'manage_options', 'wbf-discord', 'wbf_admin_discord' );
|
||||
add_submenu_page( 'wbf-admin', '⚠️ Deinstallieren', '⚠️ Deinstallieren', 'manage_options', 'wbf-uninstall', 'wbf_admin_uninstall' );
|
||||
add_submenu_page( 'wbf-admin', '🔔 Updates', '🔔 Updates', 'manage_options', 'wbf-updates', 'wbf_admin_updates' );
|
||||
}, 10 );
|
||||
@@ -1346,14 +1347,46 @@ function wbf_admin_members() {
|
||||
}
|
||||
}
|
||||
|
||||
$members = WBF_DB::get_all_users( 200 );
|
||||
$members = WBF_DB::get_all_users( 200 );
|
||||
$s_discord = wbf_get_settings();
|
||||
$dc_sync_on = ( $s_discord['discord_role_sync'] ?? '0' ) === '1' && trim( $s_discord['discord_bot_token'] ?? '' );
|
||||
|
||||
// Discord-Meta aller User vorladen (1 Query statt N)
|
||||
$dc_meta = [];
|
||||
if ( $dc_sync_on ) {
|
||||
global $wpdb;
|
||||
$rows = $wpdb->get_results(
|
||||
"SELECT user_id,
|
||||
MAX(CASE WHEN meta_key='discord_user_id' THEN meta_value END) AS discord_uid,
|
||||
MAX(CASE WHEN meta_key='discord_username' THEN meta_value END) AS discord_name
|
||||
FROM {$wpdb->prefix}forum_user_meta
|
||||
WHERE meta_key IN ('discord_user_id','discord_username')
|
||||
GROUP BY user_id"
|
||||
);
|
||||
foreach ( $rows as $r ) {
|
||||
$dc_meta[ (int)$r->user_id ] = $r;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1 style="display:flex;align-items:center;justify-content:space-between">
|
||||
<h1 style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px">
|
||||
<span>Mitglieder</span>
|
||||
<button type="button" class="button button-primary" onclick="document.getElementById('wbf-create-user-box').style.display=document.getElementById('wbf-create-user-box').style.display==='none'?'block':'none'">
|
||||
+ Neuen Nutzer anlegen
|
||||
</button>
|
||||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
|
||||
<?php if ( $dc_sync_on ): ?>
|
||||
<button type="button" id="wbf-discord-sync-all-btn" class="button"
|
||||
style="background:#5865f2;color:#fff;border-color:#4752c4;display:inline-flex;align-items:center;gap:5px"
|
||||
title="Synchronisiert Discord-Rollen aller verknüpften Nutzer (Discord → Forum)">
|
||||
<span class="dashicons dashicons-update" id="wbf-sync-icon" style="margin-top:3px"></span>
|
||||
Discord-Rollen synchronisieren
|
||||
</button>
|
||||
<span id="wbf-discord-sync-result" style="font-weight:600;font-size:.85rem"></span>
|
||||
<?php endif; ?>
|
||||
<button type="button" class="button button-primary"
|
||||
onclick="document.getElementById('wbf-create-user-box').style.display=
|
||||
document.getElementById('wbf-create-user-box').style.display==='none'?'block':'none'">
|
||||
+ Neuen Nutzer anlegen
|
||||
</button>
|
||||
</div>
|
||||
</h1>
|
||||
|
||||
<!-- Neuen Nutzer anlegen -->
|
||||
@@ -1409,6 +1442,7 @@ function wbf_admin_members() {
|
||||
<th>#</th><th>Nutzer</th><th>E-Mail</th>
|
||||
<th>Aktuelle Rolle</th><th>Beiträge</th>
|
||||
<th>Registriert</th><th>Rolle ändern</th>
|
||||
<?php if ( $dc_sync_on ): ?><th style="color:#5865f2"><i class="fab fa-discord"></i> Discord</th><?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -1417,9 +1451,17 @@ function wbf_admin_members() {
|
||||
$color = esc_attr( $role['color'] );
|
||||
$bg = esc_attr( $role['bg_color'] );
|
||||
$icon = esc_attr( $role['icon'] ?? 'fas fa-user' );
|
||||
$is_sa = ( $m->role === WBF_Roles::SUPERADMIN );
|
||||
// Nur sperren wenn dieser Forum-User wirklich dem WP-Superadmin (ID 1) entspricht.
|
||||
// Reine Rollen-Prüfung reicht nicht — sonst kann man versehentlich
|
||||
// zugewiesene superadmin-Rollen nicht mehr korrigieren.
|
||||
$wp_sa_data = get_userdata( WBF_Roles::get_wp_superadmin_id() );
|
||||
$is_sa = ( $m->role === WBF_Roles::SUPERADMIN )
|
||||
&& $wp_sa_data
|
||||
&& ( strtolower($m->email) === strtolower($wp_sa_data->user_email) );
|
||||
$ban_reason = esc_attr( $m->ban_reason ?? '' );
|
||||
$opts = '';
|
||||
$dc_user = $dc_meta[ (int)$m->id ] ?? null;
|
||||
$has_dc = $dc_sync_on && $dc_user && ! empty( $dc_user->discord_uid );
|
||||
foreach ( $roles as $k => $r ) {
|
||||
if ( $k === WBF_Roles::SUPERADMIN ) continue;
|
||||
$sel = $m->role === $k ? ' selected' : '';
|
||||
@@ -1438,13 +1480,13 @@ function wbf_admin_members() {
|
||||
<span class="wbf-role-preview" style="color:<?php echo $color; ?>;background:<?php echo $bg; ?>;border-color:<?php echo $color; ?>">
|
||||
<i class="<?php echo $icon; ?>"></i> <?php echo esc_html( $role['label'] ); ?>
|
||||
</span>
|
||||
<?php if ( $is_sa ) : ?><em style="color:#999;font-size:.8em">(WP-Admin)</em><?php endif; ?>
|
||||
<?php if ( $is_sa ) : ?><em style="color:#999;font-size:.8em">(Haupt-Admin)</em><?php endif; ?>
|
||||
</td>
|
||||
<td><?php echo esc_html( $m->post_count ); ?></td>
|
||||
<td><?php echo esc_html( date( 'd.m.Y', strtotime( $m->registered ) ) ); ?></td>
|
||||
<td>
|
||||
<?php if ( $is_sa ) : ?>
|
||||
<em style="color:#999">Automatisch (WP-Admin)</em>
|
||||
<em style="color:#999">Gesperrt — Haupt-Superadmin (WP User ID <?php echo (int) WBF_Roles::get_wp_superadmin_id(); ?>)</em>
|
||||
<?php else : ?>
|
||||
<form method="post" style="display:flex;flex-direction:column;gap:5px">
|
||||
<?php wp_nonce_field( 'wbf_member_role_nonce' ); ?>
|
||||
@@ -1711,11 +1753,127 @@ function wbf_admin_members() {
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
|
||||
<?php if ( $dc_sync_on ) : ?>
|
||||
<td style="white-space:nowrap;min-width:140px;vertical-align:top;padding-top:8px">
|
||||
<?php if ( $has_dc ) : ?>
|
||||
<div style="display:flex;flex-direction:column;gap:5px">
|
||||
<span style="font-size:.8rem;color:#5865f2;font-weight:600">
|
||||
<i class="fab fa-discord"></i>
|
||||
<?php echo esc_html( $dc_user->discord_name ?: $dc_user->discord_uid ); ?>
|
||||
</span>
|
||||
<button type="button"
|
||||
class="button button-small wbf-dc-sync-user"
|
||||
data-uid="<?php echo (int)$m->id; ?>"
|
||||
data-nonce="<?php echo wp_create_nonce('wbf_nonce'); ?>"
|
||||
style="color:#5865f2;border-color:#5865f2;font-size:.75rem;height:24px;line-height:22px">
|
||||
<span class="dashicons dashicons-update" style="font-size:12px;width:12px;height:12px;margin-top:5px"></span>
|
||||
Sync
|
||||
</button>
|
||||
<span class="wbf-dc-user-result" style="font-size:.75rem;font-weight:600"></span>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<span style="font-size:.78rem;color:#9ca3af">Nicht verknüpft</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<?php if ( $dc_sync_on ) : ?>
|
||||
<style>
|
||||
@keyframes wbf-spin { from { transform:rotate(0deg); } to { transform:rotate(360deg); } }
|
||||
.wbf-spinning { animation: wbf-spin .8s linear infinite; display:inline-block; }
|
||||
</style>
|
||||
<script>
|
||||
(function(){
|
||||
var nonce = '<?php echo wp_create_nonce("wbf_nonce"); ?>';
|
||||
|
||||
// ── Bulk-Sync ──────────────────────────────────────────────────────────
|
||||
var allBtn = document.getElementById('wbf-discord-sync-all-btn');
|
||||
var allRes = document.getElementById('wbf-discord-sync-result');
|
||||
var allIcon = document.getElementById('wbf-sync-icon');
|
||||
|
||||
if (allBtn) {
|
||||
allBtn.addEventListener('click', function() {
|
||||
allBtn.disabled = true;
|
||||
if (allIcon) allIcon.classList.add('wbf-spinning');
|
||||
allRes.style.color = '#374151';
|
||||
allRes.textContent = '⏳ Sync läuft…';
|
||||
|
||||
fetch(ajaxurl, {
|
||||
method : 'POST',
|
||||
headers : {'Content-Type':'application/x-www-form-urlencoded'},
|
||||
body : 'action=wbf_manual_discord_sync&nonce=' + nonce
|
||||
})
|
||||
.then(function(r){ return r.json(); })
|
||||
.then(function(d) {
|
||||
allBtn.disabled = false;
|
||||
if (allIcon) allIcon.classList.remove('wbf-spinning');
|
||||
if (d.success) {
|
||||
allRes.style.color = '#16a34a';
|
||||
allRes.textContent = '✅ ' + (d.data.message || 'Fertig!');
|
||||
// Seite neu laden damit neue Rollen sichtbar werden
|
||||
setTimeout(function(){ location.reload(); }, 1800);
|
||||
} else {
|
||||
allRes.style.color = '#dc2626';
|
||||
allRes.textContent = '❌ ' + ((d.data && d.data.message) || 'Fehler');
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
allBtn.disabled = false;
|
||||
if (allIcon) allIcon.classList.remove('wbf-spinning');
|
||||
allRes.style.color = '#dc2626';
|
||||
allRes.textContent = '❌ Netzwerkfehler';
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ── Pro-Nutzer-Sync ───────────────────────────────────────────────────
|
||||
document.querySelectorAll('.wbf-dc-sync-user').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
var uid = btn.dataset.uid;
|
||||
var icon = btn.querySelector('.dashicons');
|
||||
var result = btn.closest('div').querySelector('.wbf-dc-user-result');
|
||||
|
||||
btn.disabled = true;
|
||||
if (icon) icon.classList.add('wbf-spinning');
|
||||
if (result) { result.style.color='#374151'; result.textContent='⏳'; }
|
||||
|
||||
fetch(ajaxurl, {
|
||||
method : 'POST',
|
||||
headers : {'Content-Type':'application/x-www-form-urlencoded'},
|
||||
body : 'action=wbf_discord_sync_user&nonce=' + nonce + '&user_id=' + uid
|
||||
})
|
||||
.then(function(r){ return r.json(); })
|
||||
.then(function(d) {
|
||||
btn.disabled = false;
|
||||
if (icon) icon.classList.remove('wbf-spinning');
|
||||
if (d.success) {
|
||||
if (result) { result.style.color='#16a34a'; result.textContent='✅ OK'; }
|
||||
// Rollenbadge in dieser Zeile nach 1s aktualisieren (Seitenreload)
|
||||
setTimeout(function(){ location.reload(); }, 1200);
|
||||
} else {
|
||||
if (result) {
|
||||
result.style.color = '#dc2626';
|
||||
result.textContent = '❌ ' + ((d.data && d.data.message) || 'Fehler');
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
btn.disabled = false;
|
||||
if (icon) icon.classList.remove('wbf-spinning');
|
||||
if (result) { result.style.color='#dc2626'; result.textContent='❌ Netzwerkfehler'; }
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
}
|
||||
|
||||
@@ -3191,6 +3349,8 @@ function wbf_admin_profile_fields() {
|
||||
|
||||
<!-- ── Felder je Kategorie ───────────────────────────────── -->
|
||||
<?php
|
||||
// Globaler Feld-Index — synchronisiert Checkboxen mit den sequentiellen []‑Arrays
|
||||
$wbf_fidx = 0;
|
||||
// Alle Kategorien + "Ohne Kategorie" am Ende ausgeben
|
||||
$all_sections = $cats;
|
||||
if ( isset($by_cat['__none__']) ) {
|
||||
@@ -3234,7 +3394,8 @@ function wbf_admin_profile_fields() {
|
||||
<?php
|
||||
endif;
|
||||
foreach ( $c_fields as $i_f => $f ):
|
||||
$fi = 'fi_' . $f['key'];
|
||||
$fi = $wbf_fidx;
|
||||
$wbf_fidx++;
|
||||
?>
|
||||
<tr class="wbf-field-row" style="background:#fff">
|
||||
<td style="padding:6px 8px">
|
||||
@@ -3268,9 +3429,11 @@ function wbf_admin_profile_fields() {
|
||||
<span class="wbf-options-placeholder" style="color:#ccc;font-size:.75rem;<?php echo ($f['type']??'text')==='select'?'display:none':''; ?>">—</span>
|
||||
</td>
|
||||
<td style="text-align:center;padding:6px 8px">
|
||||
<input type="hidden" name="field_required[<?php echo $fi; ?>]" value="0">
|
||||
<input type="checkbox" name="field_required[<?php echo $fi; ?>]" value="1" <?php checked($f['required']??0,1); ?>>
|
||||
</td>
|
||||
<td style="text-align:center;padding:6px 8px">
|
||||
<input type="hidden" name="field_public[<?php echo $fi; ?>]" value="0">
|
||||
<input type="checkbox" name="field_public[<?php echo $fi; ?>]" value="1" <?php checked($f['public']??1,1); ?>>
|
||||
</td>
|
||||
<td style="padding:6px 8px">
|
||||
@@ -3318,7 +3481,7 @@ function wbf_admin_profile_fields() {
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var wbfRowCount = <?php echo count($fields) + 100; ?>;
|
||||
var wbfRowCount = <?php echo $wbf_fidx; ?>;
|
||||
|
||||
function wbfRemoveRow(btn) {
|
||||
var tr = btn.closest('tr');
|
||||
@@ -3359,8 +3522,8 @@ function wbf_admin_profile_fields() {
|
||||
'<textarea name="field_options[]" rows="2" placeholder="Option 1\nOption 2" style="width:100%;font-size:.78rem;display:none" class="wbf-options-field"></textarea>' +
|
||||
'<span class="wbf-options-placeholder" style="color:#ccc;font-size:.75rem">—</span>' +
|
||||
'</td>' +
|
||||
'<td style="text-align:center;padding:6px 8px"><input type="checkbox" name="field_required[new_' + i + ']" value="1"></td>' +
|
||||
'<td style="text-align:center;padding:6px 8px"><input type="checkbox" name="field_public[new_' + i + ']" value="1" checked></td>' +
|
||||
'<td style="text-align:center;padding:6px 8px"><input type="hidden" name="field_required[' + i + ']" value="0"><input type="checkbox" name="field_required[' + i + ']" value="1"></td>' +
|
||||
'<td style="text-align:center;padding:6px 8px"><input type="hidden" name="field_public[' + i + ']" value="0"><input type="checkbox" name="field_public[' + i + ']" value="1" checked></td>' +
|
||||
'<td style="padding:6px 8px"><select name="field_category[]" style="width:100%;font-size:.82rem">' + catOpts + '</select></td>' +
|
||||
'<td style="padding:6px 8px"><button type="button" class="button" onclick="wbfRemoveRow(this)" style="color:#dc2626;border-color:#fca5a5;padding:2px 7px">✕</button></td>';
|
||||
tbody.appendChild(tr);
|
||||
@@ -3837,4 +4000,232 @@ function wbf_admin_wordfilter() {
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// ── Discord-Bot-Verbindungstest (Admin AJAX) ──────────────────────────────────
|
||||
add_action('wp_ajax_wbf_discord_test', function() {
|
||||
if ( ! current_user_can('manage_options') ) wp_send_json_error(['message' => 'Keine Berechtigung.']);
|
||||
check_ajax_referer('wbf_discord_test', 'nonce');
|
||||
|
||||
$s = wbf_get_settings();
|
||||
$token = trim($s['discord_bot_token'] ?? '');
|
||||
$guild = trim($s['discord_guild_id'] ?? '');
|
||||
|
||||
if ( ! $token ) {
|
||||
wp_send_json_error(['message' => 'Kein Bot-Token gespeichert.']);
|
||||
}
|
||||
|
||||
// Bot-Info abrufen (@me)
|
||||
$res = wp_remote_get('https://discord.com/api/v10/users/@me', [
|
||||
'timeout' => 8,
|
||||
'headers' => [
|
||||
'Authorization' => 'Bot ' . $token,
|
||||
'Content-Type' => 'application/json',
|
||||
],
|
||||
]);
|
||||
|
||||
if ( is_wp_error($res) ) {
|
||||
wp_send_json_error(['message' => 'HTTP-Fehler: ' . $res->get_error_message()]);
|
||||
}
|
||||
|
||||
$code = wp_remote_retrieve_response_code($res);
|
||||
$body = json_decode(wp_remote_retrieve_body($res), true);
|
||||
|
||||
if ( $code !== 200 || empty($body['id']) ) {
|
||||
$err = $body['message'] ?? 'Unbekannter Fehler (HTTP ' . $code . ')';
|
||||
wp_send_json_error(['message' => 'Discord API: ' . $err]);
|
||||
}
|
||||
|
||||
$bot_name = ($body['username'] ?? 'Unbekannt') . '#' . ($body['discriminator'] ?? '0');
|
||||
|
||||
// Guild-Prüfung falls Guild-ID angegeben
|
||||
$guild_info = '';
|
||||
if ( $guild ) {
|
||||
$gr = wp_remote_get("https://discord.com/api/v10/guilds/{$guild}", [
|
||||
'timeout' => 6,
|
||||
'headers' => ['Authorization' => 'Bot ' . $token],
|
||||
]);
|
||||
if ( ! is_wp_error($gr) && wp_remote_retrieve_response_code($gr) === 200 ) {
|
||||
$gd = json_decode(wp_remote_retrieve_body($gr), true);
|
||||
$guild_info = ' | Server: ' . ($gd['name'] ?? $guild);
|
||||
} else {
|
||||
$guild_info = ' | ⚠️ Server nicht gefunden oder Bot kein Mitglied';
|
||||
}
|
||||
}
|
||||
|
||||
wp_send_json_success(['message' => 'Bot: ' . $bot_name . $guild_info]);
|
||||
});
|
||||
|
||||
// ── Discord-Cron: Rollen synchronisieren ──────────────────────────────────────
|
||||
add_action('wbf_discord_role_sync', 'wbf_run_discord_role_sync');
|
||||
|
||||
if ( ! wp_next_scheduled('wbf_discord_role_sync') ) {
|
||||
wp_schedule_event(time(), 'hourly', 'wbf_discord_role_sync');
|
||||
}
|
||||
|
||||
function wbf_run_discord_role_sync() {
|
||||
$s = wbf_get_settings();
|
||||
if ( ($s['discord_role_sync'] ?? '0') !== '1' ) return;
|
||||
$token = trim($s['discord_bot_token'] ?? '');
|
||||
$guild = trim($s['discord_guild_id'] ?? '');
|
||||
$role_map = json_decode($s['discord_role_map'] ?? '{}', true) ?: [];
|
||||
if ( ! $token || ! $guild || empty($role_map) ) return;
|
||||
|
||||
global $wpdb;
|
||||
// Alle verifizierten Discord-User holen (discord_user_id in user_meta gesetzt)
|
||||
$rows = $wpdb->get_results(
|
||||
"SELECT um.user_id, um.meta_value AS discord_user_id
|
||||
FROM {$wpdb->prefix}forum_user_meta um
|
||||
WHERE um.meta_key = 'discord_user_id' AND um.meta_value != ''"
|
||||
);
|
||||
|
||||
foreach ( $rows as $row ) {
|
||||
wbf_sync_discord_role_for_user((int)$row->user_id, $row->discord_user_id, $token, $guild, $role_map);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronisiert die Discord-Serverrolle eines einzelnen Nutzers mit der Forum-Rolle.
|
||||
*/
|
||||
function wbf_sync_discord_role_for_user($forum_user_id, $discord_user_id, $token, $guild, $role_map) {
|
||||
// Guild-Member-Info abrufen
|
||||
$res = wp_remote_get("https://discord.com/api/v10/guilds/{$guild}/members/{$discord_user_id}", [
|
||||
'timeout' => 6,
|
||||
'headers' => ['Authorization' => 'Bot ' . $token],
|
||||
]);
|
||||
if ( is_wp_error($res) || wp_remote_retrieve_response_code($res) !== 200 ) return;
|
||||
|
||||
$member = json_decode(wp_remote_retrieve_body($res), true);
|
||||
$user_roles = $member['roles'] ?? [];
|
||||
|
||||
// Rollen-Map prüfen — erster Treffer gewinnt (Reihenfolge = Priorität)
|
||||
foreach ( $role_map as $dc_role_id => $forum_role ) {
|
||||
if ( in_array((string)$dc_role_id, array_map('strval', $user_roles), true) ) {
|
||||
$forum_user = WBF_DB::get_user($forum_user_id);
|
||||
if ( $forum_user && $forum_user->role !== 'superadmin' && $forum_user->role !== $forum_role ) {
|
||||
WBF_DB::update_user($forum_user_id, ['role' => $forum_role]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ── Discord-Admin-Seite ───────────────────────────────────────────────────────
|
||||
if ( ! function_exists('wbf_admin_discord') ) {
|
||||
function wbf_admin_discord() {
|
||||
if ( ! current_user_can('manage_options') ) return;
|
||||
$s = wbf_get_settings();
|
||||
?>
|
||||
<div class="wrap">
|
||||
<h1>🎮 Discord-Integration</h1>
|
||||
<p>Konfiguriere den Discord-Bot und die Rollen-Synchronisation.
|
||||
Einstellungen werden in <a href="admin.php?page=wbf-settings">Einstellungen → Discord-Integration</a> gespeichert.</p>
|
||||
|
||||
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px;max-width:900px;margin-top:1.5rem">
|
||||
|
||||
<!-- Status-Panel -->
|
||||
<div style="background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:20px">
|
||||
<h3 style="margin-top:0">🔌 Bot-Status</h3>
|
||||
<?php
|
||||
$token = trim($s['discord_bot_token'] ?? '');
|
||||
$guild = trim($s['discord_guild_id'] ?? '');
|
||||
if (!$token): ?>
|
||||
<p style="color:#dc2626"><i class="dashicons dashicons-warning"></i> Kein Bot-Token konfiguriert.</p>
|
||||
<a href="admin.php?page=wbf-settings#discord" class="button button-primary">Jetzt einrichten</a>
|
||||
<?php else: ?>
|
||||
<p style="color:#16a34a;font-weight:600">✅ Bot-Token gespeichert</p>
|
||||
<p style="color:<?php echo $guild ? '#16a34a' : '#f59e0b'; ?>">
|
||||
<?php echo $guild ? '✅ Guild-ID: <code>' . esc_html($guild) . '</code>' : '⚠️ Keine Guild-ID gesetzt'; ?>
|
||||
</p>
|
||||
<p style="color:<?php echo ($s['discord_role_sync']??'0')==='1' ? '#16a34a' : '#9ca3af'; ?>">
|
||||
Rollen-Sync: <strong><?php echo ($s['discord_role_sync']??'0')==='1' ? 'Aktiv' : 'Deaktiviert'; ?></strong>
|
||||
</p>
|
||||
<button type="button" class="button button-secondary" id="wbf-discord-test-btn2">
|
||||
🔌 Verbindung testen
|
||||
</button>
|
||||
<span id="wbf-discord-test-result2" style="margin-left:10px;font-weight:600"></span>
|
||||
<script>
|
||||
document.getElementById('wbf-discord-test-btn2').addEventListener('click', function(){
|
||||
var btn = this, res = document.getElementById('wbf-discord-test-result2');
|
||||
btn.disabled = true; res.textContent = '⏳ Teste…';
|
||||
fetch(ajaxurl,{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
body:'action=wbf_discord_test&nonce=<?php echo wp_create_nonce("wbf_discord_test"); ?>'
|
||||
}).then(r=>r.json()).then(function(d){
|
||||
res.style.color = d.success ? '#16a34a' : '#dc2626';
|
||||
res.textContent = d.success ? '✅ '+(d.data.message||'OK') : '❌ '+((d.data&&d.data.message)||'Fehler');
|
||||
btn.disabled = false;
|
||||
}).catch(function(){ res.style.color='#dc2626'; res.textContent='❌ Netzwerkfehler'; btn.disabled=false; });
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Rollen-Map-Übersicht -->
|
||||
<div style="background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:20px">
|
||||
<h3 style="margin-top:0">🔗 Aktive Rollen-Zuordnungen</h3>
|
||||
<?php
|
||||
$role_map = json_decode($s['discord_role_map'] ?? '{}', true) ?: [];
|
||||
$all_roles = WBF_Roles::get_all();
|
||||
if (empty($role_map)): ?>
|
||||
<p style="color:#9ca3af">Keine Zuordnungen konfiguriert.</p>
|
||||
<a href="admin.php?page=wbf-settings" class="button">Jetzt einrichten</a>
|
||||
<?php else: ?>
|
||||
<table class="widefat striped" style="font-size:.85rem">
|
||||
<thead><tr><th>Discord Rollen-ID</th><th>Forum-Rolle</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($role_map as $dc_id => $fr_key):
|
||||
$fr_label = $all_roles[$fr_key]['label'] ?? $fr_key; ?>
|
||||
<tr>
|
||||
<td><code><?php echo esc_html($dc_id); ?></code></td>
|
||||
<td><?php echo WBF_Roles::badge($fr_key); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<a href="admin.php?page=wbf-settings" class="button" style="margin-top:.75rem">Bearbeiten</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Verknüpfte Discord-Nutzer -->
|
||||
<div style="background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:20px;max-width:900px;margin-top:20px">
|
||||
<h3 style="margin-top:0">👥 Verknüpfte Forum-Nutzer</h3>
|
||||
<?php
|
||||
global $wpdb;
|
||||
$linked = $wpdb->get_results(
|
||||
"SELECT fu.id, fu.username, fu.display_name, fu.role,
|
||||
MAX(CASE WHEN um.meta_key='discord_username' THEN um.meta_value END) AS discord_name,
|
||||
MAX(CASE WHEN um.meta_key='discord_user_id' THEN um.meta_value END) AS discord_uid
|
||||
FROM {$wpdb->prefix}forum_users fu
|
||||
JOIN {$wpdb->prefix}forum_user_meta um ON um.user_id = fu.id
|
||||
WHERE um.meta_key IN ('discord_username','discord_user_id')
|
||||
GROUP BY fu.id
|
||||
HAVING discord_name != '' AND discord_name IS NOT NULL
|
||||
ORDER BY fu.username"
|
||||
);
|
||||
if (empty($linked)): ?>
|
||||
<p style="color:#9ca3af">Noch keine verknüpften Nutzer.</p>
|
||||
<?php else: ?>
|
||||
<table class="widefat striped" style="font-size:.85rem">
|
||||
<thead><tr><th>Forum-Nutzer</th><th>Rolle</th><th>Discord-Name</th><th>Discord-ID</th></tr></thead>
|
||||
<tbody>
|
||||
<?php foreach ($linked as $u): ?>
|
||||
<tr>
|
||||
<td><strong><?php echo esc_html($u->display_name); ?></strong>
|
||||
<span style="color:#9ca3af"> @<?php echo esc_html($u->username); ?></span></td>
|
||||
<td><?php echo WBF_Roles::badge($u->role); ?></td>
|
||||
<td><i class="fab fa-discord" style="color:#5865f2"></i> <?php echo esc_html($u->discord_name ?: '–'); ?></td>
|
||||
<td><code style="font-size:.78rem"><?php echo esc_html($u->discord_uid ?: '–'); ?></code></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user