Update from Git Manager GUI
This commit is contained in:
@@ -31,6 +31,7 @@ add_action( 'admin_menu', function() {
|
|||||||
add_submenu_page( 'wbf-admin', 'Wortfilter', 'Wortfilter', 'manage_options', 'wbf-wordfilter', 'wbf_admin_wordfilter' );
|
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', 'Export / Import','Export / Import','manage_options', 'wbf-export', 'wbf_admin_export' );
|
||||||
add_submenu_page( 'wbf-admin', '⚠️ Deinstallieren', '⚠️ Deinstallieren', 'manage_options', 'wbf-uninstall', 'wbf_admin_uninstall' );
|
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 );
|
}, 10 );
|
||||||
|
|
||||||
// Meldungs-Badge im Menü (separater Hook mit Priorität 999, läuft nach der Registrierung)
|
// Meldungs-Badge im Menü (separater Hook mit Priorität 999, läuft nach der Registrierung)
|
||||||
@@ -84,6 +85,7 @@ add_action( 'admin_init', function() {
|
|||||||
case 'settings':
|
case 'settings':
|
||||||
$data['settings'] = get_option('wbf_settings', []);
|
$data['settings'] = get_option('wbf_settings', []);
|
||||||
$data['profile_fields'] = get_option('wbf_profile_fields', []);
|
$data['profile_fields'] = get_option('wbf_profile_fields', []);
|
||||||
|
$data['reactions_cfg'] = get_option('wbf_reactions', []);
|
||||||
break;
|
break;
|
||||||
case 'roles':
|
case 'roles':
|
||||||
$data['roles'] = get_option('wbf_custom_roles', []);
|
$data['roles'] = get_option('wbf_custom_roles', []);
|
||||||
@@ -125,6 +127,16 @@ add_action( 'admin_init', function() {
|
|||||||
);
|
);
|
||||||
$data['subscriptions'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_subscriptions ORDER BY id ASC", ARRAY_A );
|
$data['subscriptions'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_subscriptions ORDER BY id ASC", ARRAY_A );
|
||||||
break;
|
break;
|
||||||
|
case 'polls':
|
||||||
|
$data['polls'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_polls ORDER BY id ASC", ARRAY_A );
|
||||||
|
$data['poll_votes'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_poll_votes ORDER BY id ASC", ARRAY_A );
|
||||||
|
break;
|
||||||
|
case 'bookmarks':
|
||||||
|
$data['bookmarks'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_bookmarks ORDER BY id ASC", ARRAY_A );
|
||||||
|
break;
|
||||||
|
case 'prefixes':
|
||||||
|
$data['prefixes'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_prefixes ORDER BY sort_order ASC", ARRAY_A );
|
||||||
|
break;
|
||||||
case 'interactions':
|
case 'interactions':
|
||||||
$data['likes'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_likes ORDER BY id ASC", ARRAY_A );
|
$data['likes'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_likes ORDER BY id ASC", ARRAY_A );
|
||||||
$data['reactions'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_reactions ORDER BY id ASC", ARRAY_A );
|
$data['reactions'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_reactions ORDER BY id ASC", ARRAY_A );
|
||||||
@@ -139,6 +151,9 @@ add_action( 'admin_init', function() {
|
|||||||
case 'invites':
|
case 'invites':
|
||||||
$data['invites'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_invites ORDER BY id ASC", ARRAY_A );
|
$data['invites'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_invites ORDER BY id ASC", ARRAY_A );
|
||||||
break;
|
break;
|
||||||
|
case 'ignore_list':
|
||||||
|
$data['ignore_list'] = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}forum_ignore_list ORDER BY id ASC", ARRAY_A );
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,6 +354,7 @@ function wbf_admin_page() {
|
|||||||
$online_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE last_active >= DATE_SUB(NOW(), INTERVAL 15 MINUTE)");
|
$online_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE last_active >= DATE_SUB(NOW(), INTERVAL 15 MINUTE)");
|
||||||
$invite_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_invites WHERE use_count < max_uses AND (expires_at IS NULL OR expires_at > NOW())");
|
$invite_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_invites WHERE use_count < max_uses AND (expires_at IS NULL OR expires_at > NOW())");
|
||||||
$banned_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE role='banned'");
|
$banned_count = (int)$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}forum_users WHERE role='banned'");
|
||||||
|
$update_info = wbf_update_available(); // null oder array mit Versionsdaten
|
||||||
|
|
||||||
// ── System ────────────────────────────────────────────────────────────────
|
// ── System ────────────────────────────────────────────────────────────────
|
||||||
$php_ver = PHP_VERSION;
|
$php_ver = PHP_VERSION;
|
||||||
@@ -537,6 +553,7 @@ function wbf_admin_page() {
|
|||||||
['wbf-trash', 'fas fa-trash-can', 'Papierkorb', $deleted_count>0?$deleted_count:0, true],
|
['wbf-trash', 'fas fa-trash-can', 'Papierkorb', $deleted_count>0?$deleted_count:0, true],
|
||||||
['wbf-export', 'fas fa-database', 'Export / Import'],
|
['wbf-export', 'fas fa-database', 'Export / Import'],
|
||||||
['wbf-settings', 'fas fa-gear', 'Einstellungen'],
|
['wbf-settings', 'fas fa-gear', 'Einstellungen'],
|
||||||
|
['wbf-updates', 'fas fa-arrow-up-from-bracket', '🔔 Updates', $update_info ? 1 : 0],
|
||||||
];
|
];
|
||||||
foreach ($nav as $n):
|
foreach ($nav as $n):
|
||||||
if ($n===null) { echo '<div class="wbf-nav__sep"></div>'; continue; }
|
if ($n===null) { echo '<div class="wbf-nav__sep"></div>'; continue; }
|
||||||
@@ -1201,6 +1218,65 @@ function wbf_admin_members() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ── Nutzer löschen (DSGVO Art. 17 / Hard Delete) ─────────────────────────
|
||||||
|
if ( isset( $_POST['wbf_delete_member'] ) && check_admin_referer( 'wbf_delete_member_nonce' ) ) {
|
||||||
|
$uid = (int) ( $_POST['user_id'] ?? 0 );
|
||||||
|
$mode = sanitize_key( $_POST['delete_mode'] ?? 'anonymize' );
|
||||||
|
if ( $uid ) {
|
||||||
|
$target = WBF_DB::get_user( $uid );
|
||||||
|
if ( ! $target ) {
|
||||||
|
echo '<div class="notice notice-error is-dismissible"><p>❌ Nutzer nicht gefunden.</p></div>';
|
||||||
|
} elseif ( $target->role === WBF_Roles::SUPERADMIN ) {
|
||||||
|
echo '<div class="notice notice-error is-dismissible"><p>❌ Der Superadmin kann nicht gelöscht werden.</p></div>';
|
||||||
|
} else {
|
||||||
|
global $wpdb;
|
||||||
|
$name = esc_html( $target->display_name );
|
||||||
|
|
||||||
|
if ( $mode === 'hard' ) {
|
||||||
|
// Alle nutzerbezogenen Daten entfernen
|
||||||
|
$dep_tables = [
|
||||||
|
'forum_messages' => [ 'from_id', 'to_id' ],
|
||||||
|
'forum_notifications' => [ 'user_id', 'actor_id' ],
|
||||||
|
'forum_subscriptions' => [ 'user_id' ],
|
||||||
|
'forum_bookmarks' => [ 'user_id' ],
|
||||||
|
'forum_likes' => [ 'user_id' ],
|
||||||
|
'forum_reactions' => [ 'user_id' ],
|
||||||
|
'forum_reports' => [ 'reporter_id' ],
|
||||||
|
'forum_poll_votes' => [ 'user_id' ],
|
||||||
|
'forum_remember_tokens' => [ 'user_id' ],
|
||||||
|
'forum_user_meta' => [ 'user_id' ],
|
||||||
|
'forum_ignore_list' => [ 'user_id', 'ignored_id' ],
|
||||||
|
];
|
||||||
|
foreach ( $dep_tables as $tbl => $cols ) {
|
||||||
|
$full = $wpdb->prefix . $tbl;
|
||||||
|
if ( $wpdb->get_var( "SHOW TABLES LIKE '$full'" ) !== $full ) continue;
|
||||||
|
foreach ( $cols as $col ) {
|
||||||
|
$wpdb->delete( $full, [ $col => $uid ], [ '%d' ] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Threads/Posts auf user_id=0 setzen (Inhalt bleibt)
|
||||||
|
$wpdb->update( "{$wpdb->prefix}forum_threads", [ 'user_id' => 0 ], [ 'user_id' => $uid ], [ '%d' ], [ '%d' ] );
|
||||||
|
$wpdb->update( "{$wpdb->prefix}forum_posts", [ 'user_id' => 0 ], [ 'user_id' => $uid ], [ '%d' ], [ '%d' ] );
|
||||||
|
// Nutzer-Datensatz hart loeschen
|
||||||
|
$wpdb->delete( "{$wpdb->prefix}forum_users", [ 'id' => $uid ], [ '%d' ] );
|
||||||
|
echo "<div class='notice notice-success is-dismissible'><p>🗑 Nutzer <strong>{$name}</strong> dauerhaft geloescht. Threads/Posts anonym gesetzt.</p></div>";
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// DSGVO Art. 17 Anonymisierung (Standard)
|
||||||
|
$ok = WBF_DB::delete_user_gdpr( $uid );
|
||||||
|
if ( $ok ) {
|
||||||
|
echo "<div class='notice notice-success is-dismissible'><p>✅ Nutzer <strong>{$name}</strong> anonymisiert (DSGVO Art. 17). Threads und Beitraege bleiben erhalten.</p></div>";
|
||||||
|
} else {
|
||||||
|
echo "<div class='notice notice-error is-dismissible'><p>❌ Anonymisierung fehlgeschlagen.</p></div>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete_transient( 'wbf_flood_' . $uid );
|
||||||
|
delete_transient( 'wbf_flood_ts_' . $uid );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── Profil bearbeiten ─────────────────────────────────────────────────────
|
// ── Profil bearbeiten ─────────────────────────────────────────────────────
|
||||||
if ( isset( $_POST['wbf_edit_user'] ) && check_admin_referer( 'wbf_edit_user_nonce' ) ) {
|
if ( isset( $_POST['wbf_edit_user'] ) && check_admin_referer( 'wbf_edit_user_nonce' ) ) {
|
||||||
$uid = (int) $_POST['user_id'];
|
$uid = (int) $_POST['user_id'];
|
||||||
@@ -1238,6 +1314,35 @@ function wbf_admin_members() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Admin: einzelnen Ignore-Eintrag entfernen ─────────────────────────────
|
||||||
|
if ( isset( $_POST['wbf_admin_remove_ignore'] ) && check_admin_referer( 'wbf_admin_ignore_nonce' ) ) {
|
||||||
|
if ( current_user_can('manage_options') ) {
|
||||||
|
$uid = (int) ( $_POST['user_id'] ?? 0 );
|
||||||
|
$ignored_id = (int) ( $_POST['ignored_id'] ?? 0 );
|
||||||
|
if ( $uid && $ignored_id ) {
|
||||||
|
global $wpdb;
|
||||||
|
$wpdb->delete(
|
||||||
|
"{$wpdb->prefix}forum_ignore_list",
|
||||||
|
[ 'user_id' => $uid, 'ignored_id' => $ignored_id ],
|
||||||
|
[ '%d', '%d' ]
|
||||||
|
);
|
||||||
|
echo '<div class="notice notice-success is-dismissible"><p>Ignore-Eintrag entfernt.</p></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Admin: gesamte Ignore-Liste eines Users leeren ────────────────────────
|
||||||
|
if ( isset( $_POST['wbf_admin_clear_ignores'] ) && check_admin_referer( 'wbf_admin_ignore_nonce' ) ) {
|
||||||
|
if ( current_user_can('manage_options') ) {
|
||||||
|
$uid = (int) ( $_POST['user_id'] ?? 0 );
|
||||||
|
if ( $uid ) {
|
||||||
|
global $wpdb;
|
||||||
|
$wpdb->delete( "{$wpdb->prefix}forum_ignore_list", [ 'user_id' => $uid ], [ '%d' ] );
|
||||||
|
echo '<div class="notice notice-success is-dismissible"><p>Ignore-Liste vollständig geleert.</p></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$members = WBF_DB::get_all_users( 200 );
|
$members = WBF_DB::get_all_users( 200 );
|
||||||
?>
|
?>
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
@@ -1350,6 +1455,11 @@ function wbf_admin_members() {
|
|||||||
onclick="var d=document.getElementById('wbf-edit-user-<?php echo (int)$m->id; ?>');d.style.display=d.style.display==='none'?'block':'none'">
|
onclick="var d=document.getElementById('wbf-edit-user-<?php echo (int)$m->id; ?>');d.style.display=d.style.display==='none'?'block':'none'">
|
||||||
Profil bearbeiten
|
Profil bearbeiten
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" class="button button-small"
|
||||||
|
style="color:#dc2626;border-color:#dc2626"
|
||||||
|
onclick="var d=document.getElementById('wbf-delete-user-<?php echo (int)$m->id; ?>');d.style.display=d.style.display==='none'?'block':'none'">
|
||||||
|
🗑️ Löschen
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="wbf-ban-reason" style="display:<?php echo $m->role === 'banned' ? 'block' : 'none'; ?>;margin-top:3px">
|
<div class="wbf-ban-reason" style="display:<?php echo $m->role === 'banned' ? 'block' : 'none'; ?>;margin-top:3px">
|
||||||
<input type="text" name="ban_reason" value="<?php echo $ban_reason; ?>"
|
<input type="text" name="ban_reason" value="<?php echo $ban_reason; ?>"
|
||||||
@@ -1472,6 +1582,128 @@ function wbf_admin_members() {
|
|||||||
<button type="submit" name="wbf_edit_user" class="button button-primary button-small">Änderungen speichern</button>
|
<button type="submit" name="wbf_edit_user" class="button button-primary button-small">Änderungen speichern</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
<!-- Ignore-Liste des Nutzers -->
|
||||||
|
<?php
|
||||||
|
$admin_ignore_list = WBF_DB::get_ignore_list( $m->id );
|
||||||
|
?>
|
||||||
|
<div style="margin-top:14px;border-top:1px solid #e0e0e0;padding-top:12px">
|
||||||
|
<strong style="font-size:12px;color:#555;text-transform:uppercase;letter-spacing:.04em">
|
||||||
|
<span class="dashicons dashicons-hidden" style="font-size:14px;width:14px;height:14px;vertical-align:-2px"></span>
|
||||||
|
Ignorierte Nutzer (<?php echo count($admin_ignore_list); ?>)
|
||||||
|
</strong>
|
||||||
|
<?php if ( empty($admin_ignore_list) ): ?>
|
||||||
|
<p style="font-size:12px;color:#999;margin:6px 0 0">Dieser Nutzer ignoriert niemanden.</p>
|
||||||
|
<?php else: ?>
|
||||||
|
<table style="width:100%;font-size:12px;margin-top:8px;border-collapse:collapse">
|
||||||
|
<thead>
|
||||||
|
<tr style="background:#f0f0f0">
|
||||||
|
<th style="padding:4px 6px;text-align:left;font-weight:600">Nutzer</th>
|
||||||
|
<th style="padding:4px 6px;text-align:left;font-weight:600">Ignoriert seit</th>
|
||||||
|
<th style="padding:4px 6px;text-align:center;font-weight:600">Entfernen</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach ( $admin_ignore_list as $ign ): ?>
|
||||||
|
<tr style="border-bottom:1px solid #eee">
|
||||||
|
<td style="padding:4px 6px">
|
||||||
|
<strong><?php echo esc_html($ign->display_name); ?></strong>
|
||||||
|
<span style="color:#999"> @<?php echo esc_html($ign->username); ?></span>
|
||||||
|
</td>
|
||||||
|
<td style="padding:4px 6px;color:#666">
|
||||||
|
<?php echo esc_html(date_i18n('d.m.Y H:i', strtotime($ign->ignored_since))); ?>
|
||||||
|
</td>
|
||||||
|
<td style="padding:4px 6px;text-align:center">
|
||||||
|
<form method="post" style="display:inline">
|
||||||
|
<?php wp_nonce_field('wbf_admin_ignore_nonce'); ?>
|
||||||
|
<input type="hidden" name="user_id" value="<?php echo (int)$m->id; ?>">
|
||||||
|
<input type="hidden" name="ignored_id" value="<?php echo (int)$ign->id; ?>">
|
||||||
|
<button type="submit" name="wbf_admin_remove_ignore"
|
||||||
|
class="button button-small"
|
||||||
|
style="color:#c00;border-color:#c00"
|
||||||
|
onclick="return confirm('Ignore-Eintrag für <?php echo esc_js($ign->display_name); ?> entfernen?')">
|
||||||
|
<span class="dashicons dashicons-no" style="font-size:13px;width:13px;height:13px;vertical-align:-2px"></span>
|
||||||
|
Entfernen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<form method="post" style="margin-top:8px">
|
||||||
|
<?php wp_nonce_field('wbf_admin_ignore_nonce'); ?>
|
||||||
|
<input type="hidden" name="user_id" value="<?php echo (int)$m->id; ?>">
|
||||||
|
<button type="submit" name="wbf_admin_clear_ignores"
|
||||||
|
class="button button-small"
|
||||||
|
style="color:#c00;border-color:#c00"
|
||||||
|
onclick="return confirm('Gesamte Ignore-Liste von <?php echo esc_js($m->display_name); ?> leeren?')">
|
||||||
|
<span class="dashicons dashicons-trash" style="font-size:13px;width:13px;height:13px;vertical-align:-2px"></span>
|
||||||
|
Alle Einträge löschen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div><!-- /#wbf-edit-user -->
|
||||||
|
|
||||||
|
<!-- Löschen-Dialog -->
|
||||||
|
<div id="wbf-delete-user-<?php echo (int)$m->id; ?>"
|
||||||
|
style="display:none;margin-top:8px;padding:14px 16px;background:#fff5f5;border:1px solid #fca5a5;border-radius:6px;max-width:480px">
|
||||||
|
<p style="margin:0 0 10px;font-weight:700;color:#dc2626;font-size:.9rem">
|
||||||
|
🗑️ Nutzer löschen: <?php echo esc_html($m->display_name); ?>
|
||||||
|
</p>
|
||||||
|
<p style="font-size:.82rem;color:#6b7280;margin:0 0 12px">
|
||||||
|
Wähle wie der Account behandelt werden soll:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<!-- Option A: DSGVO Anonymisierung -->
|
||||||
|
<form method="post" style="margin-bottom:8px">
|
||||||
|
<?php wp_nonce_field( 'wbf_delete_member_nonce' ); ?>
|
||||||
|
<input type="hidden" name="user_id" value="<?php echo (int)$m->id; ?>">
|
||||||
|
<input type="hidden" name="delete_mode" value="anonymize">
|
||||||
|
<div style="background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:10px 12px;margin-bottom:6px">
|
||||||
|
<label style="display:flex;align-items:flex-start;gap:8px;cursor:pointer">
|
||||||
|
<span>
|
||||||
|
<strong style="font-size:.83rem;color:#374151">📋 DSGVO Anonymisieren</strong>
|
||||||
|
<span style="display:block;font-size:.77rem;color:#9ca3af;margin-top:2px">
|
||||||
|
Account wird anonymisiert, Threads & Beiträge bleiben unter „Gelöschter Nutzer" erhalten.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="wbf_delete_member" class="button"
|
||||||
|
style="font-size:.8rem;height:28px;line-height:28px;background:#fff8f0;border-color:#f97316;color:#c2410c"
|
||||||
|
onclick="return confirm('Nutzer <?php echo esc_js($m->display_name); ?> anonymisieren?\n\nDer Account wird nach DSGVO Art. 17 anonymisiert. Alle Inhalte bleiben anonym erhalten.')">
|
||||||
|
📋 Anonymisieren
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<!-- Option B: Hard Delete -->
|
||||||
|
<form method="post">
|
||||||
|
<?php wp_nonce_field( 'wbf_delete_member_nonce' ); ?>
|
||||||
|
<input type="hidden" name="user_id" value="<?php echo (int)$m->id; ?>">
|
||||||
|
<input type="hidden" name="delete_mode" value="hard">
|
||||||
|
<div style="background:#fff;border:1px solid #fca5a5;border-radius:6px;padding:10px 12px;margin-bottom:6px">
|
||||||
|
<label style="display:flex;align-items:flex-start;gap:8px;cursor:pointer">
|
||||||
|
<span>
|
||||||
|
<strong style="font-size:.83rem;color:#dc2626">⚠️ Dauerhaft löschen</strong>
|
||||||
|
<span style="display:block;font-size:.77rem;color:#9ca3af;margin-top:2px">
|
||||||
|
Account + alle nutzerbezogenen Daten werden unwiderruflich gelöscht. Threads/Posts bleiben anonym erhalten.
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="wbf_delete_member" class="button"
|
||||||
|
style="font-size:.8rem;height:28px;line-height:28px;background:#fef2f2;border-color:#dc2626;color:#dc2626"
|
||||||
|
onclick="return confirm('⚠️ ACHTUNG: Nutzer <?php echo esc_js($m->display_name); ?> DAUERHAFT löschen?\n\nDieser Vorgang kann NICHT rückgängig gemacht werden!\n\nAlle persönlichen Daten, Nachrichten und Einstellungen werden unwiderruflich entfernt.')">
|
||||||
|
🗑️ Dauerhaft löschen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<button type="button" class="button" style="margin-top:8px;font-size:.78rem"
|
||||||
|
onclick="document.getElementById('wbf-delete-user-<?php echo (int)$m->id; ?>').style.display='none'">
|
||||||
|
Abbrechen
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</td>
|
</td>
|
||||||
@@ -2353,6 +2585,11 @@ function wbf_admin_export() {
|
|||||||
update_option('wbf_profile_fields', $data['profile_fields']);
|
update_option('wbf_profile_fields', $data['profile_fields']);
|
||||||
$imported[] = 'Profilfelder-Definitionen (' . count($data['profile_fields']) . ')';
|
$imported[] = 'Profilfelder-Definitionen (' . count($data['profile_fields']) . ')';
|
||||||
}
|
}
|
||||||
|
// Reaktionen-Konfiguration
|
||||||
|
if ( isset($data['reactions_cfg']) && is_array($data['reactions_cfg']) ) {
|
||||||
|
update_option('wbf_reactions', $data['reactions_cfg']);
|
||||||
|
$imported[] = 'Reaktionen-Konfiguration';
|
||||||
|
}
|
||||||
|
|
||||||
// ── Rollen ────────────────────────────────────────────────
|
// ── Rollen ────────────────────────────────────────────────
|
||||||
if ( ! empty($data['roles']) ) {
|
if ( ! empty($data['roles']) ) {
|
||||||
@@ -2378,8 +2615,21 @@ function wbf_admin_export() {
|
|||||||
if ( $existing === 0 || $force ) {
|
if ( $existing === 0 || $force ) {
|
||||||
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_categories");
|
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_categories");
|
||||||
foreach ($data['categories'] as $cat) {
|
foreach ($data['categories'] as $cat) {
|
||||||
unset($cat['id']);
|
// BUGFIX: Original-ID behalten! Threads zeigen direkt auf diese IDs.
|
||||||
$wpdb->insert("{$wpdb->prefix}forum_categories", $cat);
|
$wpdb->query( $wpdb->prepare(
|
||||||
|
"INSERT INTO {$wpdb->prefix}forum_categories
|
||||||
|
(id, parent_id, name, slug, description, icon, sort_order, thread_count, post_count, min_role, guest_visible)
|
||||||
|
VALUES (%d,%d,%s,%s,%s,%s,%d,%d,%d,%s,%d)
|
||||||
|
ON DUPLICATE KEY UPDATE parent_id=%d, name=%s, slug=%s, description=%s, icon=%s, sort_order=%d, thread_count=%d, post_count=%d, min_role=%s, guest_visible=%d",
|
||||||
|
(int)($cat['id']), (int)($cat['parent_id'] ?? 0), $cat['name'] ?? '', $cat['slug'] ?? '',
|
||||||
|
$cat['description'] ?? '', $cat['icon'] ?? 'fas fa-comments',
|
||||||
|
(int)($cat['sort_order'] ?? 0), (int)($cat['thread_count'] ?? 0),
|
||||||
|
(int)($cat['post_count'] ?? 0), $cat['min_role'] ?? 'member', (int)($cat['guest_visible'] ?? 1),
|
||||||
|
(int)($cat['parent_id'] ?? 0), $cat['name'] ?? '', $cat['slug'] ?? '',
|
||||||
|
$cat['description'] ?? '', $cat['icon'] ?? 'fas fa-comments',
|
||||||
|
(int)($cat['sort_order'] ?? 0), (int)($cat['thread_count'] ?? 0),
|
||||||
|
(int)($cat['post_count'] ?? 0), $cat['min_role'] ?? 'member', (int)($cat['guest_visible'] ?? 1)
|
||||||
|
) );
|
||||||
}
|
}
|
||||||
$imported[] = 'Kategorien (' . count($data['categories']) . ')';
|
$imported[] = 'Kategorien (' . count($data['categories']) . ')';
|
||||||
} else {
|
} else {
|
||||||
@@ -2439,11 +2689,17 @@ function wbf_admin_export() {
|
|||||||
if ( ! empty($data['threads']) ) {
|
if ( ! empty($data['threads']) ) {
|
||||||
$force = ! empty($_POST['import_force_threads']);
|
$force = ! empty($_POST['import_force_threads']);
|
||||||
if ($force) {
|
if ($force) {
|
||||||
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_posts");
|
// Alle abhängigen Tabellen mitbereinigen (verhindert verwaiste Einträge)
|
||||||
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_threads");
|
$wpdb->query("SET FOREIGN_KEY_CHECKS=0");
|
||||||
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_thread_tags");
|
foreach ([
|
||||||
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_tags");
|
'forum_posts', 'forum_threads', 'forum_thread_tags', 'forum_tags',
|
||||||
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_subscriptions");
|
'forum_subscriptions', 'forum_polls', 'forum_poll_votes',
|
||||||
|
'forum_bookmarks', 'forum_prefixes', 'forum_likes', 'forum_reactions',
|
||||||
|
'forum_notifications', 'forum_ignore_list',
|
||||||
|
] as $_tbl) {
|
||||||
|
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}$_tbl");
|
||||||
|
}
|
||||||
|
$wpdb->query("SET FOREIGN_KEY_CHECKS=1");
|
||||||
}
|
}
|
||||||
foreach ($data['threads'] ?? [] as $t) { $wpdb->insert("{$wpdb->prefix}forum_threads", $t); }
|
foreach ($data['threads'] ?? [] as $t) { $wpdb->insert("{$wpdb->prefix}forum_threads", $t); }
|
||||||
foreach ($data['posts'] ?? [] as $p) { $wpdb->insert("{$wpdb->prefix}forum_posts", $p); }
|
foreach ($data['posts'] ?? [] as $p) { $wpdb->insert("{$wpdb->prefix}forum_posts", $p); }
|
||||||
@@ -2478,6 +2734,61 @@ function wbf_admin_export() {
|
|||||||
$imported[] = 'Threads + Posts (' . count($data['threads']) . ' / ' . count($data['posts'] ?? []) . ')';
|
$imported[] = 'Threads + Posts (' . count($data['threads']) . ' / ' . count($data['posts'] ?? []) . ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Thread-Präfixe ────────────────────────────────────────
|
||||||
|
// ── Thread-Präfixe ────────────────────────────────────────
|
||||||
|
if ( ! empty($data['prefixes']) ) {
|
||||||
|
$force = ! empty($_POST['import_force_prefixes']);
|
||||||
|
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_prefixes");
|
||||||
|
$pc = 0;
|
||||||
|
foreach ($data['prefixes'] as $row) {
|
||||||
|
$wpdb->query( $wpdb->prepare(
|
||||||
|
"INSERT INTO {$wpdb->prefix}forum_prefixes (id, label, color, bg_color, sort_order)
|
||||||
|
VALUES (%d,%s,%s,%s,%d)
|
||||||
|
ON DUPLICATE KEY UPDATE label=%s, color=%s, bg_color=%s, sort_order=%d",
|
||||||
|
(int)$row['id'], $row['label'], $row['color'] ?? '#ffffff',
|
||||||
|
$row['bg_color'] ?? '#475569', (int)($row['sort_order'] ?? 0),
|
||||||
|
$row['label'], $row['color'] ?? '#ffffff',
|
||||||
|
$row['bg_color'] ?? '#475569', (int)($row['sort_order'] ?? 0)
|
||||||
|
) );
|
||||||
|
$pc++;
|
||||||
|
}
|
||||||
|
if ($pc) $imported[] = "Thread-Präfixe ($pc)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Umfragen + Abstimmungen ───────────────────────────────
|
||||||
|
if ( ! empty($data['polls']) ) {
|
||||||
|
$force = ! empty($_POST['import_force_polls']);
|
||||||
|
if ($force) {
|
||||||
|
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_poll_votes");
|
||||||
|
$wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_polls");
|
||||||
|
}
|
||||||
|
$pc = 0;
|
||||||
|
foreach ($data['polls'] as $row) {
|
||||||
|
$wpdb->query( $wpdb->prepare(
|
||||||
|
"INSERT INTO {$wpdb->prefix}forum_polls (id, thread_id, question, options, multi, ends_at, created_at)
|
||||||
|
VALUES (%d,%d,%s,%s,%d,%s,%s)
|
||||||
|
ON DUPLICATE KEY UPDATE thread_id=%d, question=%s, options=%s, multi=%d, ends_at=%s",
|
||||||
|
(int)$row['id'], (int)$row['thread_id'], $row['question'] ?? '',
|
||||||
|
$row['options'] ?? '[]', (int)($row['multi'] ?? 0),
|
||||||
|
$row['ends_at'] ?? null, $row['created_at'] ?? current_time('mysql'),
|
||||||
|
(int)$row['thread_id'], $row['question'] ?? '',
|
||||||
|
$row['options'] ?? '[]', (int)($row['multi'] ?? 0), $row['ends_at'] ?? null
|
||||||
|
) );
|
||||||
|
$pc++;
|
||||||
|
}
|
||||||
|
foreach ($data['poll_votes'] ?? [] as $row) { unset($row['id']); $wpdb->replace("{$wpdb->prefix}forum_poll_votes", $row); }
|
||||||
|
$imported[] = "Umfragen ($pc)";
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Lesezeichen ───────────────────────────────────────────
|
||||||
|
if ( ! empty($data['bookmarks']) ) {
|
||||||
|
$force = ! empty($_POST['import_force_bookmarks']);
|
||||||
|
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_bookmarks");
|
||||||
|
$bc = 0;
|
||||||
|
foreach ($data['bookmarks'] as $row) { unset($row['id']); $wpdb->replace("{$wpdb->prefix}forum_bookmarks", $row); $bc++; }
|
||||||
|
if ($bc) $imported[] = "Lesezeichen ($bc)";
|
||||||
|
}
|
||||||
|
|
||||||
// ── Likes, Reaktionen, Benachrichtigungen ─────────────────
|
// ── Likes, Reaktionen, Benachrichtigungen ─────────────────
|
||||||
if ( ! empty($data['likes']) ) {
|
if ( ! empty($data['likes']) ) {
|
||||||
$force = ! empty($_POST['import_force_threads']);
|
$force = ! empty($_POST['import_force_threads']);
|
||||||
@@ -2539,6 +2850,19 @@ function wbf_admin_export() {
|
|||||||
if ($count) $imported[] = "Einladungen ($count)";
|
if ($count) $imported[] = "Einladungen ($count)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Ignore-Liste ──────────────────────────────────────────
|
||||||
|
if ( ! empty($data['ignore_list']) ) {
|
||||||
|
$force = ! empty($_POST['import_force_ignore']);
|
||||||
|
if ($force) $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}forum_ignore_list");
|
||||||
|
$count = 0;
|
||||||
|
foreach ($data['ignore_list'] as $row) {
|
||||||
|
unset($row['id']);
|
||||||
|
$wpdb->replace("{$wpdb->prefix}forum_ignore_list", $row);
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
if ($count) $imported[] = "Ignore-Einträge ($count)";
|
||||||
|
}
|
||||||
|
|
||||||
if ( empty($imported) ) {
|
if ( empty($imported) ) {
|
||||||
$notice = ['warning', 'Nichts importiert — Datei enthielt keine gültigen Abschnitte.'];
|
$notice = ['warning', 'Nichts importiert — Datei enthielt keine gültigen Abschnitte.'];
|
||||||
} else {
|
} else {
|
||||||
@@ -2581,8 +2905,12 @@ function wbf_admin_export() {
|
|||||||
'categories' => ['📂', 'Kategorien', 'Alle Kategorien inkl. Hierarchie'],
|
'categories' => ['📂', 'Kategorien', 'Alle Kategorien inkl. Hierarchie'],
|
||||||
'users' => ['👥', 'Benutzer & Profilfelder', 'Accounts, Ban-Status, Profilfeld-Werte'],
|
'users' => ['👥', 'Benutzer & Profilfelder', 'Accounts, Ban-Status, Profilfeld-Werte'],
|
||||||
'threads' => ['💬', 'Threads, Posts & Abos', 'Alle Inhalte, Tags & Abonnements'],
|
'threads' => ['💬', 'Threads, Posts & Abos', 'Alle Inhalte, Tags & Abonnements'],
|
||||||
|
'polls' => ['📊', 'Umfragen', 'Alle Umfragen inkl. Abstimmungen'],
|
||||||
|
'bookmarks' => ['🔖', 'Lesezeichen', 'Alle gespeicherten Thread-Lesezeichen'],
|
||||||
|
'prefixes' => ['🏷️', 'Thread-Präfixe', 'Alle konfigurierten Präfix-Labels & Farben'],
|
||||||
'interactions' => ['❤️', 'Likes & Reaktionen', 'Likes, Reaktionen, Benachrichtigungen'],
|
'interactions' => ['❤️', 'Likes & Reaktionen', 'Likes, Reaktionen, Benachrichtigungen'],
|
||||||
'messages' => ['✉️', 'Privatnachrichten', 'Alle DM-Konversationen'],
|
'messages' => ['✉️', 'Privatnachrichten', 'Alle DM-Konversationen'],
|
||||||
|
'ignore_list' => ['🚫', 'Ignore-Liste', 'Alle Nutzer-Blockierungen'],
|
||||||
'reports' => ['🚩', 'Meldungen', 'Gemeldete Beiträge inkl. Status'],
|
'reports' => ['🚩', 'Meldungen', 'Gemeldete Beiträge inkl. Status'],
|
||||||
'invites' => ['📨', 'Einladungen', 'Alle Einladungscodes inkl. Nutzungsstand'],
|
'invites' => ['📨', 'Einladungen', 'Alle Einladungscodes inkl. Nutzungsstand'],
|
||||||
];
|
];
|
||||||
@@ -2644,6 +2972,10 @@ function wbf_admin_export() {
|
|||||||
'import_force_cats' => 'Kategorien überschreiben (löscht bestehende)',
|
'import_force_cats' => 'Kategorien überschreiben (löscht bestehende)',
|
||||||
'import_force_users' => 'Benutzer aktualisieren (bei gleichem Username) inkl. Profilfeld-Werte',
|
'import_force_users' => 'Benutzer aktualisieren (bei gleichem Username) inkl. Profilfeld-Werte',
|
||||||
'import_force_threads' => 'Threads, Posts, Likes, Reaktionen & Abonnements überschreiben',
|
'import_force_threads' => 'Threads, Posts, Likes, Reaktionen & Abonnements überschreiben',
|
||||||
|
'import_force_polls' => 'Umfragen & Abstimmungen überschreiben',
|
||||||
|
'import_force_bookmarks'=> 'Lesezeichen überschreiben',
|
||||||
|
'import_force_prefixes' => 'Thread-Präfixe überschreiben',
|
||||||
|
'import_force_ignore' => 'Ignore-Liste überschreiben',
|
||||||
'import_force_messages' => 'Privatnachrichten überschreiben',
|
'import_force_messages' => 'Privatnachrichten überschreiben',
|
||||||
'import_force_reports' => 'Meldungen überschreiben',
|
'import_force_reports' => 'Meldungen überschreiben',
|
||||||
'import_force_invites' => 'Einladungen überschreiben',
|
'import_force_invites' => 'Einladungen überschreiben',
|
||||||
@@ -2868,6 +3200,142 @@ function wbf_admin_profile_fields() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ── Deinstallations-Seite ─────────────────────────────────────────────────────
|
// ── Deinstallations-Seite ─────────────────────────────────────────────────────
|
||||||
|
// ── Update-Seite ──────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
function wbf_admin_updates() {
|
||||||
|
if ( ! current_user_can('manage_options') ) return;
|
||||||
|
|
||||||
|
$latest = wbf_get_latest_release();
|
||||||
|
$update = wbf_update_available();
|
||||||
|
$cur_ver = WBF_VERSION;
|
||||||
|
$admin_url = admin_url('admin.php?page=wbf-updates');
|
||||||
|
|
||||||
|
// Manuelles Refresh
|
||||||
|
$refresh_url = wp_nonce_url( add_query_arg('wbf_refresh_update', '1', $admin_url), 'wbf_refresh_update' );
|
||||||
|
?>
|
||||||
|
<div class="wrap" style="max-width:860px">
|
||||||
|
<h1 style="display:flex;align-items:center;gap:10px">
|
||||||
|
<span style="font-size:1.4rem">🔔</span> WP Business Forum — Updates
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<!-- ── Status-Karte ─────────────────────────────────── -->
|
||||||
|
<div style="margin-top:20px;background:#fff;border:1px solid #e5e7eb;border-radius:12px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,.06)">
|
||||||
|
|
||||||
|
<?php if ( $update ): ?>
|
||||||
|
<!-- UPDATE VERFÜGBAR -->
|
||||||
|
<div style="background:linear-gradient(135deg,#fffbeb,#fef3c7);border-bottom:2px solid #fcd34d;padding:18px 24px;display:flex;align-items:center;gap:14px">
|
||||||
|
<span style="font-size:2.2rem">📦</span>
|
||||||
|
<div>
|
||||||
|
<strong style="font-size:1.1rem;color:#92400e">Update verfügbar!</strong>
|
||||||
|
<p style="margin:.2rem 0 0;color:#78350f">
|
||||||
|
Version <strong><?php echo esc_html($update['version']); ?></strong> wurde veröffentlicht.
|
||||||
|
Du verwendest aktuell <strong><?php echo esc_html($cur_ver); ?></strong>.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<a href="<?php echo esc_url($update['url']); ?>" target="_blank" rel="noopener"
|
||||||
|
class="button button-primary"
|
||||||
|
style="margin-left:auto;background:#f59e0b;border-color:#d97706;white-space:nowrap;font-size:.9rem;padding:6px 16px">
|
||||||
|
📥 Zum Download
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<?php else: ?>
|
||||||
|
<!-- AKTUELL -->
|
||||||
|
<div style="background:linear-gradient(135deg,#f0fdf4,#dcfce7);border-bottom:2px solid #86efac;padding:18px 24px;display:flex;align-items:center;gap:14px">
|
||||||
|
<span style="font-size:2.2rem">✅</span>
|
||||||
|
<div>
|
||||||
|
<strong style="font-size:1.1rem;color:#166534">Du verwendest die neueste Version</strong>
|
||||||
|
<p style="margin:.2rem 0 0;color:#15803d">Version <?php echo esc_html($cur_ver); ?> ist aktuell.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div style="padding:22px 24px">
|
||||||
|
|
||||||
|
<!-- ── Versionen-Tabelle ──────────────────────── -->
|
||||||
|
<table style="width:100%;border-collapse:collapse;margin-bottom:20px">
|
||||||
|
<tr style="border-bottom:1px solid #f3f4f6">
|
||||||
|
<td style="padding:10px 0;color:#6b7280;font-size:.875rem;width:220px">Installierte Version</td>
|
||||||
|
<td style="padding:10px 0;font-weight:700"><?php echo esc_html($cur_ver); ?></td>
|
||||||
|
</tr>
|
||||||
|
<tr style="border-bottom:1px solid #f3f4f6">
|
||||||
|
<td style="padding:10px 0;color:#6b7280;font-size:.875rem">Neueste Version</td>
|
||||||
|
<td style="padding:10px 0;font-weight:700">
|
||||||
|
<?php if ($latest && !empty($latest['version'])): ?>
|
||||||
|
<?php echo esc_html($latest['version']); ?>
|
||||||
|
<?php if ($update): ?>
|
||||||
|
<span style="margin-left:6px;background:#fef3c7;color:#92400e;border:1px solid #fcd34d;border-radius:12px;padding:2px 8px;font-size:.75rem;font-weight:600">NEU</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php else: ?>
|
||||||
|
<span style="color:#9ca3af">Nicht abrufbar</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php if ($latest && !empty($latest['published'])): ?>
|
||||||
|
<tr style="border-bottom:1px solid #f3f4f6">
|
||||||
|
<td style="padding:10px 0;color:#6b7280;font-size:.875rem">Veröffentlicht am</td>
|
||||||
|
<td style="padding:10px 0"><?php echo esc_html(date_i18n('d.m.Y H:i', strtotime($latest['published']))); ?> Uhr</td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
<tr style="border-bottom:1px solid #f3f4f6">
|
||||||
|
<td style="padding:10px 0;color:#6b7280;font-size:.875rem">Update-Quelle</td>
|
||||||
|
<td style="padding:10px 0">
|
||||||
|
<a href="<?php echo esc_url(WBF_RELEASES_PAGE); ?>" target="_blank" rel="noopener"
|
||||||
|
style="color:#2563eb;text-decoration:none">
|
||||||
|
<i class="fas fa-code-branch" style="margin-right:5px"></i>
|
||||||
|
git.viper.ipv64.net — WP-Business-Forum
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding:10px 0;color:#6b7280;font-size:.875rem">Letzter Check</td>
|
||||||
|
<td style="padding:10px 0;display:flex;align-items:center;gap:12px">
|
||||||
|
<?php
|
||||||
|
$cached = get_transient(WBF_UPDATE_TRANSIENT);
|
||||||
|
echo ($cached !== false) ? '<span style="color:#059669">✔ Cache aktiv (12h)</span>' : '<span style="color:#9ca3af">—</span>';
|
||||||
|
?>
|
||||||
|
<a href="<?php echo esc_url($refresh_url); ?>"
|
||||||
|
style="color:#6b7280;font-size:.8rem;text-decoration:none;border:1px solid #e5e7eb;border-radius:5px;padding:3px 9px">
|
||||||
|
🔄 Jetzt prüfen
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php if ($latest && !empty($latest['body'])): ?>
|
||||||
|
<!-- ── Changelog ──────────────────────────────── -->
|
||||||
|
<div style="background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:16px 18px">
|
||||||
|
<h3 style="margin:0 0 10px;font-size:.9rem;color:#374151;display:flex;align-items:center;gap:7px">
|
||||||
|
<span>📋</span> Release Notes — v<?php echo esc_html($latest['version']); ?>
|
||||||
|
</h3>
|
||||||
|
<pre style="white-space:pre-wrap;font-family:inherit;font-size:.82rem;color:#4b5563;margin:0;line-height:1.6;max-height:300px;overflow-y:auto"><?php echo esc_html(mb_substr($latest['body'], 0, 3000)); ?></pre>
|
||||||
|
<div style="margin-top:12px;padding-top:10px;border-top:1px solid #e2e8f0">
|
||||||
|
<a href="<?php echo esc_url($latest['url']); ?>" target="_blank" rel="noopener"
|
||||||
|
class="button" style="font-size:.82rem">
|
||||||
|
Vollständige Release-Seite öffnen →
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<!-- ── Update-Anleitung ───────────────────────── -->
|
||||||
|
<div style="margin-top:18px;background:#eff6ff;border:1px solid #bfdbfe;border-radius:8px;padding:14px 16px">
|
||||||
|
<strong style="font-size:.85rem;color:#1e40af">📖 Update-Anleitung</strong>
|
||||||
|
<ol style="margin:.6rem 0 0 1.2rem;padding:0;font-size:.82rem;color:#1e3a8a;line-height:1.8">
|
||||||
|
<li>Lade die neue <code>.zip</code> von der <a href="<?php echo esc_url(WBF_RELEASES_PAGE); ?>" target="_blank" rel="noopener" style="color:#2563eb">Release-Seite</a> herunter.</li>
|
||||||
|
<li>Erstelle vorher ein Backup über <a href="<?php echo esc_url(admin_url('admin.php?page=wbf-export')); ?>" style="color:#2563eb">Export / Import</a>.</li>
|
||||||
|
<li>Lade die neue Version per FTP/SFTP hoch und überschreibe die alten Dateien — oder nutze den WP-Plugins-Bereich (Plugin deaktivieren → löschen → neu hochladen).</li>
|
||||||
|
<li>Aktiviere das Plugin. Das DB-Schema wird automatisch aktualisiert.</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Deinstallations-Seite ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
function wbf_admin_uninstall() {
|
function wbf_admin_uninstall() {
|
||||||
if ( ! current_user_can('manage_options') ) return;
|
if ( ! current_user_can('manage_options') ) return;
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,8 @@ if ( ! function_exists('wbf_get_settings') ) {
|
|||||||
'rules_accept_required' => '1',
|
'rules_accept_required' => '1',
|
||||||
'rules_title' => 'Forum-Regeln & Nutzungsbedingungen',
|
'rules_title' => 'Forum-Regeln & Nutzungsbedingungen',
|
||||||
'rules_content' => "**1. Respektvoller Umgang**\nBehandle alle Mitglieder freundlich und respektvoll. Beleidigungen, Mobbing und Diskriminierung sind nicht toleriert.\n\n**2. Keine Spam-Inhalte**\nWerbung, Spam und irrelevante Links sind verboten.\n\n**3. Keine illegalen Inhalte**\nJegliche Inhalte, die gegen geltendes Recht verstoßen, sind streng verboten.\n\n**4. Themenrelevanz**\nBeiträge sollten zur jeweiligen Kategorie passen.\n\n**5. Urheberrecht**\nVeröffentliche keine Inhalte, an denen du keine Rechte besitzt.\n\n**6. Datenschutz**\nTeile keine persönlichen Daten anderer Personen ohne deren Zustimmung.\n\n**7. Moderations-Entscheidungen**\nEntscheidungen der Moderatoren sind zu respektieren. Bei Fragen wende dich direkt ans Team.\n\nVerstöße können zur Verwarnung oder dauerhaften Sperrung führen.",
|
'rules_content' => "**1. Respektvoller Umgang**\nBehandle alle Mitglieder freundlich und respektvoll. Beleidigungen, Mobbing und Diskriminierung sind nicht toleriert.\n\n**2. Keine Spam-Inhalte**\nWerbung, Spam und irrelevante Links sind verboten.\n\n**3. Keine illegalen Inhalte**\nJegliche Inhalte, die gegen geltendes Recht verstoßen, sind streng verboten.\n\n**4. Themenrelevanz**\nBeiträge sollten zur jeweiligen Kategorie passen.\n\n**5. Urheberrecht**\nVeröffentliche keine Inhalte, an denen du keine Rechte besitzt.\n\n**6. Datenschutz**\nTeile keine persönlichen Daten anderer Personen ohne deren Zustimmung.\n\n**7. Moderations-Entscheidungen**\nEntscheidungen der Moderatoren sind zu respektieren. Bei Fragen wende dich direkt ans Team.\n\nVerstöße können zur Verwarnung oder dauerhaften Sperrung führen.",
|
||||||
|
// Ignore/Block-System: Rollen die nicht geblockt werden können (kommagetrennte Schlüssel)
|
||||||
|
'ignore_blocked_roles' => 'superadmin,admin,moderator',
|
||||||
];
|
];
|
||||||
|
|
||||||
$saved = get_option( 'wbf_settings', [] );
|
$saved = get_option( 'wbf_settings', [] );
|
||||||
@@ -63,6 +65,38 @@ if ( ! function_exists('wbf_get_settings') ) {
|
|||||||
|
|
||||||
// ── Admin-Seite ───────────────────────────────────────────────────────────────
|
// ── Admin-Seite ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gibt ein Array der Rollen-Keys zurück die nicht geblockt/ignoriert werden können.
|
||||||
|
* Superadmin ist immer enthalten — unabhängig von der Einstellung.
|
||||||
|
*
|
||||||
|
* @return string[] z.B. ['superadmin', 'admin', 'moderator']
|
||||||
|
*/
|
||||||
|
if ( ! function_exists('wbf_get_ignore_blocked_roles') ) {
|
||||||
|
function wbf_get_ignore_blocked_roles() {
|
||||||
|
$raw = wbf_get_settings()['ignore_blocked_roles'] ?? 'superadmin,admin,moderator';
|
||||||
|
$keys = array_filter( array_map( 'trim', explode( ',', $raw ) ) );
|
||||||
|
// superadmin immer schützen
|
||||||
|
if ( ! in_array('superadmin', $keys, true) ) {
|
||||||
|
$keys[] = 'superadmin';
|
||||||
|
}
|
||||||
|
return array_values( $keys );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prüft ob ein User ignoriert/geblockt werden darf.
|
||||||
|
*
|
||||||
|
* @param object $target Forum-User-Objekt
|
||||||
|
* @return bool true = darf ignoriert werden, false = nicht erlaubt
|
||||||
|
*/
|
||||||
|
if ( ! function_exists('wbf_can_be_ignored') ) {
|
||||||
|
function wbf_can_be_ignored( $target ) {
|
||||||
|
if ( ! $target ) return false;
|
||||||
|
$blocked_roles = wbf_get_ignore_blocked_roles();
|
||||||
|
return ! in_array( $target->role, $blocked_roles, true );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( ! function_exists('wbf_admin_settings') ) {
|
if ( ! function_exists('wbf_admin_settings') ) {
|
||||||
function wbf_admin_settings() {
|
function wbf_admin_settings() {
|
||||||
|
|
||||||
@@ -96,6 +130,18 @@ function wbf_admin_settings() {
|
|||||||
// rules_content separat (nicht in $fields, da textarea mit eigener Behandlung)
|
// rules_content separat (nicht in $fields, da textarea mit eigener Behandlung)
|
||||||
$settings['rules_content'] = sanitize_textarea_field( $_POST['rules_content'] ?? '' );
|
$settings['rules_content'] = sanitize_textarea_field( $_POST['rules_content'] ?? '' );
|
||||||
|
|
||||||
|
// ignore_blocked_roles: kommagetrennte Liste der gewählten Rollen-Keys
|
||||||
|
$all_role_keys = array_keys( WBF_Roles::get_all() );
|
||||||
|
$checked_roles = array_intersect(
|
||||||
|
array_map( 'sanitize_key', (array)( $_POST['ignore_blocked_roles'] ?? [] ) ),
|
||||||
|
$all_role_keys
|
||||||
|
);
|
||||||
|
// superadmin ist immer blockiert — kann nicht entfernt werden
|
||||||
|
if ( ! in_array('superadmin', $checked_roles, true) ) {
|
||||||
|
$checked_roles[] = 'superadmin';
|
||||||
|
}
|
||||||
|
$settings['ignore_blocked_roles'] = implode( ',', $checked_roles );
|
||||||
|
|
||||||
update_option( 'wbf_settings', $settings );
|
update_option( 'wbf_settings', $settings );
|
||||||
echo '<div class="notice notice-success is-dismissible"><p>✅ Einstellungen gespeichert!</p></div>';
|
echo '<div class="notice notice-success is-dismissible"><p>✅ Einstellungen gespeichert!</p></div>';
|
||||||
}
|
}
|
||||||
@@ -401,6 +447,51 @@ function wbf_admin_settings() {
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- ── Ignore / Block-System ────────────────────────── -->
|
||||||
|
<h2 style="border-bottom:1px solid #ddd;padding-bottom:.4rem;margin-top:1.5rem">
|
||||||
|
🚫 Ignore / Block-System
|
||||||
|
</h2>
|
||||||
|
<table class="form-table" role="presentation">
|
||||||
|
<tr>
|
||||||
|
<th scope="row"><label>Nicht blockierbare Rollen</label></th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
$blocked_roles = array_filter( array_map('trim', explode(',', $s['ignore_blocked_roles'] ?? 'superadmin,admin,moderator')) );
|
||||||
|
$all_roles = WBF_Roles::get_sorted();
|
||||||
|
foreach ( $all_roles as $key => $role ):
|
||||||
|
$is_superadmin = ($key === 'superadmin');
|
||||||
|
$is_checked = in_array($key, $blocked_roles, true);
|
||||||
|
$rc = esc_attr($role['color']);
|
||||||
|
$rb = esc_attr($role['bg_color']);
|
||||||
|
?>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;margin-bottom:7px;cursor:<?php echo $is_superadmin?'not-allowed':'pointer'; ?>">
|
||||||
|
<input type="checkbox"
|
||||||
|
name="ignore_blocked_roles[]"
|
||||||
|
value="<?php echo esc_attr($key); ?>"
|
||||||
|
<?php checked($is_checked, true); ?>
|
||||||
|
<?php echo $is_superadmin ? 'disabled' : ''; ?>
|
||||||
|
style="width:16px;height:16px;accent-color:<?php echo $rc; ?>">
|
||||||
|
<?php if ($is_superadmin): ?>
|
||||||
|
<!-- superadmin immer als hidden mitschicken da disabled nicht übermittelt wird -->
|
||||||
|
<input type="hidden" name="ignore_blocked_roles[]" value="superadmin">
|
||||||
|
<?php endif; ?>
|
||||||
|
<span style="display:inline-flex;align-items:center;gap:5px;padding:2px 9px;border-radius:20px;font-size:.78rem;font-weight:700;color:<?php echo $rc; ?>;background:<?php echo $rb; ?>;border:1px solid <?php echo $rc; ?>">
|
||||||
|
<i class="<?php echo esc_attr($role['icon'] ?? 'fas fa-user'); ?>"></i>
|
||||||
|
<?php echo esc_html($role['label']); ?>
|
||||||
|
</span>
|
||||||
|
<?php if ($is_superadmin): ?>
|
||||||
|
<span style="font-size:.72rem;color:#999">(immer geschützt)</span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</label>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<p class="description" style="margin-top:8px">
|
||||||
|
Nutzer mit diesen Rollen können von anderen Mitgliedern <strong>nicht</strong> geblockt oder ignoriert werden.
|
||||||
|
Superadmin ist permanent geschützt und kann nicht abgewählt werden.
|
||||||
|
</p>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
<?php submit_button(
|
<?php submit_button(
|
||||||
'💾 Einstellungen speichern',
|
'💾 Einstellungen speichern',
|
||||||
'primary',
|
'primary',
|
||||||
|
|||||||
Reference in New Issue
Block a user