Update from Git Manager GUI
This commit is contained in:
@@ -18,6 +18,9 @@ class WBF_Ajax {
|
||||
'wbf_create_poll',
|
||||
'wbf_toggle_bookmark',
|
||||
'wbf_set_thread_prefix',
|
||||
'wbf_toggle_ignore',
|
||||
'wbf_change_email',
|
||||
'wbf_save_notification_prefs',
|
||||
];
|
||||
foreach ($actions as $action) {
|
||||
add_action('wp_ajax_nopriv_' . $action, [__CLASS__, str_replace('wbf_','handle_',$action)]);
|
||||
@@ -411,9 +414,37 @@ class WBF_Ajax {
|
||||
if (empty($_FILES['avatar'])) wp_send_json_error(['message'=>'Keine Datei.']);
|
||||
|
||||
$allowed_types = ['image/jpeg','image/png','image/gif','image/webp'];
|
||||
$mime = $_FILES['avatar']['type'] ?? '';
|
||||
if (!in_array($mime, $allowed_types)) wp_send_json_error(['message'=>'Nur JPG, PNG, GIF und WebP erlaubt.']);
|
||||
if ($_FILES['avatar']['size'] > 2 * 1024 * 1024) wp_send_json_error(['message'=>'Maximale Dateigröße: 2 MB.']);
|
||||
|
||||
// Dateigröße vor dem MIME-Check prüfen
|
||||
if ( $_FILES['avatar']['size'] > 2 * 1024 * 1024 ) {
|
||||
wp_send_json_error(['message'=>'Maximale Dateigröße: 2 MB.']);
|
||||
}
|
||||
|
||||
// Server-seitige MIME-Typ-Prüfung — $_FILES['type'] kommt vom Client
|
||||
// und ist beliebig fälschbar (z.B. PHP-Datei als image/jpeg getarnt).
|
||||
// finfo_file() liest den echten Magic-Byte der temporären Datei.
|
||||
$tmp = $_FILES['avatar']['tmp_name'] ?? '';
|
||||
if ( ! $tmp || ! is_uploaded_file( $tmp ) ) {
|
||||
wp_send_json_error(['message'=>'Ungültiger Datei-Upload.']);
|
||||
}
|
||||
if ( function_exists('finfo_open') ) {
|
||||
$finfo = finfo_open( FILEINFO_MIME_TYPE );
|
||||
$real_mime = finfo_file( $finfo, $tmp );
|
||||
finfo_close( $finfo );
|
||||
} else {
|
||||
// Fallback: exif_imagetype() wenn finfo nicht verfügbar
|
||||
$et_map = [
|
||||
IMAGETYPE_JPEG => 'image/jpeg',
|
||||
IMAGETYPE_PNG => 'image/png',
|
||||
IMAGETYPE_GIF => 'image/gif',
|
||||
IMAGETYPE_WEBP => 'image/webp',
|
||||
];
|
||||
$et = @exif_imagetype( $tmp );
|
||||
$real_mime = $et_map[$et] ?? '';
|
||||
}
|
||||
if ( ! in_array( $real_mime, $allowed_types, true ) ) {
|
||||
wp_send_json_error(['message'=>'Nur JPG, PNG, GIF und WebP erlaubt.']);
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
@@ -468,16 +499,36 @@ class WBF_Ajax {
|
||||
|
||||
// Nur Bilder erlauben
|
||||
$allowed_types = ['image/jpeg','image/png','image/gif','image/webp'];
|
||||
$mime = $_FILES['image']['type'] ?? '';
|
||||
if ( ! in_array($mime, $allowed_types) ) {
|
||||
wp_send_json_error(['message' => 'Nur JPG, PNG, GIF und WebP erlaubt.']);
|
||||
}
|
||||
|
||||
// Max 5 MB
|
||||
// Max 5 MB — Größe zuerst prüfen bevor teure MIME-Erkennung läuft
|
||||
if ( $_FILES['image']['size'] > 5 * 1024 * 1024 ) {
|
||||
wp_send_json_error(['message' => 'Maximale Dateigröße: 5 MB.']);
|
||||
}
|
||||
|
||||
// Server-seitige MIME-Typ-Prüfung — $_FILES['type'] ist client-kontrolliert
|
||||
// und kann beliebig auf 'image/jpeg' gesetzt werden, auch für .php-Dateien.
|
||||
$tmp = $_FILES['image']['tmp_name'] ?? '';
|
||||
if ( ! $tmp || ! is_uploaded_file( $tmp ) ) {
|
||||
wp_send_json_error(['message' => 'Ungültiger Datei-Upload.']);
|
||||
}
|
||||
if ( function_exists('finfo_open') ) {
|
||||
$finfo = finfo_open( FILEINFO_MIME_TYPE );
|
||||
$real_mime = finfo_file( $finfo, $tmp );
|
||||
finfo_close( $finfo );
|
||||
} else {
|
||||
$et_map = [
|
||||
IMAGETYPE_JPEG => 'image/jpeg',
|
||||
IMAGETYPE_PNG => 'image/png',
|
||||
IMAGETYPE_GIF => 'image/gif',
|
||||
IMAGETYPE_WEBP => 'image/webp',
|
||||
];
|
||||
$et = @exif_imagetype( $tmp );
|
||||
$real_mime = $et_map[$et] ?? '';
|
||||
}
|
||||
if ( ! in_array( $real_mime, $allowed_types, true ) ) {
|
||||
wp_send_json_error(['message' => 'Nur JPG, PNG, GIF und WebP erlaubt.']);
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/media.php';
|
||||
@@ -588,6 +639,18 @@ class WBF_Ajax {
|
||||
$is_mod = WBF_DB::can($user, 'delete_post');
|
||||
if ( ! $is_own && ! $is_mod ) wp_send_json_error(['message' => 'Keine Berechtigung.']);
|
||||
|
||||
// Post-Bearbeitungslimit prüfen — gilt auch für Thread-Erstbeiträge
|
||||
// (spiegelt identisches Verhalten zu handle_edit_post() wider)
|
||||
if ( $is_own && ! $is_mod ) {
|
||||
$limit_min = (int)( wbf_get_settings()['post_edit_limit'] ?? 30 );
|
||||
if ( $limit_min > 0 ) {
|
||||
$age_min = ( time() - strtotime( $thread->created_at ) ) / 60;
|
||||
if ( $age_min > $limit_min ) {
|
||||
wp_send_json_error(['message' => "Bearbeitung nur innerhalb von {$limit_min} Minuten nach dem Erstellen möglich."]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$wpdb->update(
|
||||
"{$wpdb->prefix}forum_threads",
|
||||
@@ -682,6 +745,11 @@ class WBF_Ajax {
|
||||
if ($to_id === (int)$user->id) wp_send_json_error(['message'=>'Du kannst dir nicht selbst schreiben.']);
|
||||
if (!WBF_DB::get_user($to_id)) wp_send_json_error(['message'=>'Empfänger nicht gefunden.']);
|
||||
|
||||
// DM-Blockierung: Empfänger hat Sender ignoriert
|
||||
if ( WBF_DB::is_ignored( $to_id, $user->id ) ) {
|
||||
wp_send_json_error(['message' => 'Diese Person akzeptiert keine Nachrichten von dir.']);
|
||||
}
|
||||
|
||||
$id = WBF_DB::send_message($user->id, $to_id, $content);
|
||||
// Notify recipient
|
||||
WBF_DB::create_notification($to_id, 'message', $id, $user->id);
|
||||
@@ -739,14 +807,22 @@ class WBF_Ajax {
|
||||
// ── User-Autocomplete (für @Erwähnungen + DM) ─────────────────────────────
|
||||
|
||||
public static function handle_user_suggest() {
|
||||
// Nur eingeloggte Nutzer dürfen die User-Suche nutzen
|
||||
// (verhindert Enumeration aller Usernamen + Rollendaten durch Gäste)
|
||||
if ( ! WBF_Auth::is_forum_logged_in() ) {
|
||||
wp_send_json_success(['users'=>[]]);
|
||||
}
|
||||
$q = sanitize_text_field($_POST['q'] ?? $_GET['q'] ?? '');
|
||||
if (mb_strlen($q) < 1) wp_send_json_success(['users'=>[]]);
|
||||
global $wpdb;
|
||||
$like = $wpdb->esc_like($q) . '%';
|
||||
// Rolle wird bewusst NICHT zurückgegeben — nicht für Autocomplete nötig
|
||||
// und verhindert Informationsleck über Rollen-Verteilung im Forum.
|
||||
$users = $wpdb->get_results($wpdb->prepare(
|
||||
"SELECT id, username, display_name, avatar_url, role
|
||||
"SELECT id, username, display_name, avatar_url
|
||||
FROM {$wpdb->prefix}forum_users
|
||||
WHERE username LIKE %s OR display_name LIKE %s
|
||||
WHERE (username LIKE %s OR display_name LIKE %s)
|
||||
AND role != 'banned'
|
||||
ORDER BY display_name ASC LIMIT 8",
|
||||
$like, $like
|
||||
));
|
||||
@@ -817,6 +893,13 @@ class WBF_Ajax {
|
||||
private static function send_notification_email( $to_user, $type, $actor_name, $extra = [] ) {
|
||||
if ( ! $to_user || empty($to_user->email) ) return;
|
||||
|
||||
// Prüfen ob der User diesen Benachrichtigungstyp aktiviert hat
|
||||
// Standard: alle aktiviert (1). User kann im Profil deaktivieren (0).
|
||||
$pref_key = 'notify_' . $type; // notify_reply, notify_mention, notify_message
|
||||
$meta = WBF_DB::get_user_meta( $to_user->id );
|
||||
// Nur deaktivieren wenn explizit auf '0' gesetzt — Standard ist aktiviert
|
||||
if ( isset($meta[$pref_key]) && $meta[$pref_key] === '0' ) return;
|
||||
|
||||
$blog_name = get_bloginfo('name');
|
||||
$forum_url = wbf_get_forum_url();
|
||||
$from_email = get_option('admin_email');
|
||||
@@ -897,6 +980,17 @@ class WBF_Ajax {
|
||||
$email = sanitize_email( $_POST['email'] ?? '' );
|
||||
if ( ! is_email($email) ) wp_send_json_error(['message'=>'Ungültige E-Mail-Adresse.']);
|
||||
|
||||
// ── Rate-Limiting: max. 1 Reset-Mail pro E-Mail-Adresse alle 15 Minuten ──
|
||||
// Verhindert, dass ein Angreifer tausende Reset-Mails pro Sekunde
|
||||
// für beliebige Adressen triggert und den Mail-Server überlastet.
|
||||
$rate_key = 'wbf_pwreset_' . md5( strtolower( $email ) );
|
||||
if ( get_transient( $rate_key ) !== false ) {
|
||||
// Immer Erfolg melden — kein Leak ob Rate-Limit oder kein Account
|
||||
wp_send_json_success(['message'=>'Falls diese E-Mail registriert ist, wurde eine E-Mail gesendet.']);
|
||||
}
|
||||
// Cooldown setzen — 15 Minuten
|
||||
set_transient( $rate_key, 1, 15 * MINUTE_IN_SECONDS );
|
||||
|
||||
$user = WBF_DB::get_user_by('email', $email);
|
||||
// Immer Erfolg melden (kein User-Enumeration)
|
||||
if ( ! $user ) {
|
||||
@@ -922,7 +1016,13 @@ class WBF_Ajax {
|
||||
}
|
||||
|
||||
public static function handle_reset_password() {
|
||||
self::verify();
|
||||
// Kein self::verify() hier — Gäste haben keine Forum-Session.
|
||||
// Das Reset-Token selbst authentifiziert die Anfrage.
|
||||
// Wir prüfen trotzdem den WP-Nonce als CSRF-Schutz; dieser wird
|
||||
// von wp_localize_script für alle Besucher (auch Gäste) generiert.
|
||||
if ( ! check_ajax_referer( 'wbf_nonce', 'nonce', false ) ) {
|
||||
wp_send_json_error(['message' => 'Sicherheitsfehler.']);
|
||||
}
|
||||
$token = sanitize_text_field( $_POST['token'] ?? '' );
|
||||
$password = $_POST['password'] ?? '';
|
||||
$password2= $_POST['password2'] ?? '';
|
||||
@@ -1207,6 +1307,90 @@ class WBF_Ajax {
|
||||
wp_send_json_success(['prefix' => $prefix]);
|
||||
}
|
||||
|
||||
// ── E-Mail-Adresse ändern ─────────────────────────────────────────────────
|
||||
|
||||
public static function handle_change_email() {
|
||||
self::verify();
|
||||
$user = WBF_Auth::get_current_user();
|
||||
if ( ! $user ) wp_send_json_error(['message' => 'Nicht eingeloggt.']);
|
||||
|
||||
$new_email = sanitize_email( $_POST['new_email'] ?? '' );
|
||||
$password = $_POST['password'] ?? '';
|
||||
|
||||
if ( ! is_email($new_email) ) {
|
||||
wp_send_json_error(['message' => 'Ungültige E-Mail-Adresse.']);
|
||||
}
|
||||
if ( empty($password) ) {
|
||||
wp_send_json_error(['message' => 'Bitte aktuelles Passwort zur Bestätigung eingeben.']);
|
||||
}
|
||||
if ( ! password_verify($password, $user->password) ) {
|
||||
wp_send_json_error(['message' => 'Falsches Passwort.']);
|
||||
}
|
||||
if ( strtolower($new_email) === strtolower($user->email) ) {
|
||||
wp_send_json_error(['message' => 'Das ist bereits deine aktuelle E-Mail-Adresse.']);
|
||||
}
|
||||
|
||||
// Prüfen ob E-Mail bereits vergeben
|
||||
$existing = WBF_DB::get_user_by('email', $new_email);
|
||||
if ( $existing && (int)$existing->id !== (int)$user->id ) {
|
||||
wp_send_json_error(['message' => 'Diese E-Mail-Adresse ist bereits registriert.']);
|
||||
}
|
||||
|
||||
WBF_DB::update_user($user->id, ['email' => $new_email]);
|
||||
wp_send_json_success(['message' => 'E-Mail-Adresse erfolgreich geändert.']);
|
||||
}
|
||||
|
||||
// ── Benachrichtigungs-Einstellungen speichern ─────────────────────────────
|
||||
|
||||
public static function handle_save_notification_prefs() {
|
||||
self::verify();
|
||||
$user = WBF_Auth::get_current_user();
|
||||
if ( ! $user ) wp_send_json_error(['message' => 'Nicht eingeloggt.']);
|
||||
|
||||
$allowed = ['notify_reply', 'notify_mention', 'notify_message'];
|
||||
foreach ( $allowed as $key ) {
|
||||
// 1 wenn Checkbox aktiviert, 0 wenn deaktiviert
|
||||
$val = isset($_POST[$key]) && $_POST[$key] === '1' ? '1' : '0';
|
||||
WBF_DB::set_user_meta($user->id, $key, $val);
|
||||
}
|
||||
|
||||
wp_send_json_success(['message' => 'Benachrichtigungs-Einstellungen gespeichert.']);
|
||||
}
|
||||
|
||||
// ── User ignorieren / Ignorierung aufheben ────────────────────────────────
|
||||
|
||||
public static function handle_toggle_ignore() {
|
||||
self::verify();
|
||||
$user = WBF_Auth::get_current_user();
|
||||
if ( ! $user ) wp_send_json_error( ['message' => 'Nicht eingeloggt.'] );
|
||||
|
||||
$ignored_id = (int)( $_POST['ignored_id'] ?? 0 );
|
||||
if ( ! $ignored_id ) wp_send_json_error( ['message' => 'Ungültiger Nutzer.'] );
|
||||
if ( $ignored_id === (int)$user->id ) {
|
||||
wp_send_json_error( ['message' => 'Du kannst dich nicht selbst ignorieren.'] );
|
||||
}
|
||||
|
||||
$target = WBF_DB::get_user( $ignored_id );
|
||||
if ( ! $target ) wp_send_json_error( ['message' => 'Nutzer nicht gefunden.'] );
|
||||
|
||||
// Prüfen ob diese Rolle geblockt werden darf (konfigurierbar in den Einstellungen)
|
||||
if ( ! wbf_can_be_ignored( $target ) ) {
|
||||
$role_label = WBF_Roles::get($target->role)['label'] ?? $target->role;
|
||||
wp_send_json_error( ['message' => 'Nutzer mit der Rolle "' . $role_label . '" können nicht ignoriert werden.'] );
|
||||
}
|
||||
|
||||
$now_ignored = WBF_DB::toggle_ignore( $user->id, $ignored_id );
|
||||
|
||||
wp_send_json_success( [
|
||||
'ignored' => $now_ignored,
|
||||
'ignored_id' => $ignored_id,
|
||||
'display_name' => $target->display_name,
|
||||
'message' => $now_ignored
|
||||
? esc_html( $target->display_name ) . ' wird jetzt ignoriert.'
|
||||
: 'Ignorierung von ' . esc_html( $target->display_name ) . ' aufgehoben.',
|
||||
] );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_action( 'init', [ 'WBF_Ajax', 'init' ] );
|
||||
@@ -279,6 +279,18 @@ class WBF_DB {
|
||||
) $charset;";
|
||||
dbDelta( $sql_bookmarks );
|
||||
|
||||
// ── Ignore-Liste ──────────────────────────────────────────────────────
|
||||
$sql_ignore = "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}forum_ignore_list (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
ignored_id BIGINT UNSIGNED NOT NULL,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY user_ignored (user_id, ignored_id),
|
||||
KEY ignored_id (ignored_id)
|
||||
) $charset;";
|
||||
dbDelta( $sql_ignore );
|
||||
|
||||
// ── prefix_id zu threads ──────────────────────────────────────────────
|
||||
self::maybe_add_column( "{$wpdb->prefix}forum_threads", 'prefix_id',
|
||||
"ALTER TABLE {$wpdb->prefix}forum_threads ADD COLUMN prefix_id BIGINT UNSIGNED DEFAULT NULL" );
|
||||
@@ -623,7 +635,8 @@ class WBF_DB {
|
||||
FROM {$wpdb->prefix}forum_threads t
|
||||
JOIN {$wpdb->prefix}forum_users u ON u.id = t.user_id
|
||||
JOIN {$wpdb->prefix}forum_categories c ON c.id = t.category_id
|
||||
AND t.status != 'archived' ORDER BY t.created_at DESC LIMIT %d", $limit
|
||||
WHERE t.status != 'archived' AND t.deleted_at IS NULL
|
||||
ORDER BY t.created_at DESC LIMIT %d", $limit
|
||||
));
|
||||
}
|
||||
|
||||
@@ -1207,13 +1220,18 @@ class WBF_DB {
|
||||
global $wpdb;
|
||||
$token = bin2hex( random_bytes(32) );
|
||||
$hash = hash( 'sha256', $token );
|
||||
// Alte Tokens löschen
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_users", [] ); // nur placeholder
|
||||
// Altes Token dieses Users zurücksetzen bevor ein neues gesetzt wird
|
||||
$wpdb->query( $wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}forum_users
|
||||
SET reset_token=NULL, reset_token_expires=NULL
|
||||
WHERE id=%d",
|
||||
(int) $user_id
|
||||
) );
|
||||
$wpdb->query( $wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}forum_users
|
||||
SET reset_token=%s, reset_token_expires=DATE_ADD(NOW(), INTERVAL 1 HOUR)
|
||||
WHERE id=%d",
|
||||
$hash, $user_id
|
||||
$hash, (int) $user_id
|
||||
) );
|
||||
return $token; // Klartext-Token → per E-Mail senden
|
||||
}
|
||||
@@ -1689,6 +1707,128 @@ class WBF_DB {
|
||||
));
|
||||
}
|
||||
|
||||
// ── Ignore-Liste ──────────────────────────────────────────────────────────
|
||||
|
||||
public static function toggle_ignore( $user_id, $ignored_id ) {
|
||||
global $wpdb;
|
||||
$user_id = (int) $user_id;
|
||||
$ignored_id = (int) $ignored_id;
|
||||
if ( self::is_ignored( $user_id, $ignored_id ) ) {
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_ignore_list", [
|
||||
'user_id' => $user_id,
|
||||
'ignored_id' => $ignored_id,
|
||||
] );
|
||||
return false;
|
||||
}
|
||||
$wpdb->replace( "{$wpdb->prefix}forum_ignore_list", [
|
||||
'user_id' => $user_id,
|
||||
'ignored_id' => $ignored_id,
|
||||
] );
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function is_ignored( $user_id, $ignored_id ) {
|
||||
global $wpdb;
|
||||
$table = "{$wpdb->prefix}forum_ignore_list";
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) !== $table ) return false;
|
||||
return (bool) $wpdb->get_var( $wpdb->prepare(
|
||||
"SELECT id FROM {$wpdb->prefix}forum_ignore_list WHERE user_id=%d AND ignored_id=%d",
|
||||
(int) $user_id, (int) $ignored_id
|
||||
) );
|
||||
}
|
||||
|
||||
/** Gibt alle ignorierten User-IDs als int-Array zurück */
|
||||
public static function get_ignored_ids( $user_id ) {
|
||||
global $wpdb;
|
||||
$table = "{$wpdb->prefix}forum_ignore_list";
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) !== $table ) return [];
|
||||
$ids = $wpdb->get_col( $wpdb->prepare(
|
||||
"SELECT ignored_id FROM {$wpdb->prefix}forum_ignore_list WHERE user_id=%d",
|
||||
(int) $user_id
|
||||
) );
|
||||
return array_map( 'intval', $ids );
|
||||
}
|
||||
|
||||
/** Vollständige Ignore-Liste mit User-Daten */
|
||||
public static function get_ignore_list( $user_id ) {
|
||||
global $wpdb;
|
||||
$table = "{$wpdb->prefix}forum_ignore_list";
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table'" ) !== $table ) return [];
|
||||
return $wpdb->get_results( $wpdb->prepare(
|
||||
"SELECT u.id, u.username, u.display_name, u.avatar_url, u.role,
|
||||
il.created_at AS ignored_since
|
||||
FROM {$wpdb->prefix}forum_ignore_list il
|
||||
JOIN {$wpdb->prefix}forum_users u ON u.id = il.ignored_id
|
||||
WHERE il.user_id = %d
|
||||
ORDER BY il.created_at DESC",
|
||||
(int) $user_id
|
||||
) );
|
||||
}
|
||||
|
||||
// ── DSGVO Art. 17: Konto vollständig löschen ──────────────────────────────
|
||||
|
||||
public static function delete_user_gdpr( $user_id ) {
|
||||
global $wpdb;
|
||||
$user_id = (int) $user_id;
|
||||
$user = self::get_user( $user_id );
|
||||
if ( ! $user ) return false;
|
||||
if ( $user->role === 'superadmin' ) return false;
|
||||
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_messages", [ 'from_id' => $user_id ] );
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_messages", [ 'to_id' => $user_id ] );
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_remember_tokens", [ 'user_id' => $user_id ] );
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_notifications", [ 'user_id' => $user_id ] );
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_notifications", [ 'actor_id' => $user_id ] );
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_subscriptions", [ 'user_id' => $user_id ] );
|
||||
|
||||
$table_bm = "{$wpdb->prefix}forum_bookmarks";
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_bm'" ) === $table_bm ) {
|
||||
$wpdb->delete( $table_bm, [ 'user_id' => $user_id ] );
|
||||
}
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_likes", [ 'user_id' => $user_id ] );
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_reactions", [ 'user_id' => $user_id ] );
|
||||
$wpdb->delete( "{$wpdb->prefix}forum_reports", [ 'reporter_id' => $user_id ] );
|
||||
|
||||
$table_pv = "{$wpdb->prefix}forum_poll_votes";
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_pv'" ) === $table_pv ) {
|
||||
$wpdb->delete( $table_pv, [ 'user_id' => $user_id ] );
|
||||
}
|
||||
|
||||
// Ignore-Liste beidseitig bereinigen
|
||||
$table_il = "{$wpdb->prefix}forum_ignore_list";
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '$table_il'" ) === $table_il ) {
|
||||
$wpdb->delete( $table_il, [ 'user_id' => $user_id ] );
|
||||
$wpdb->delete( $table_il, [ 'ignored_id' => $user_id ] );
|
||||
}
|
||||
|
||||
delete_transient( 'wbf_flood_' . $user_id );
|
||||
delete_transient( 'wbf_flood_ts_' . $user_id );
|
||||
|
||||
self::delete_user_meta_all( $user_id );
|
||||
|
||||
$anon_hash = substr( hash( 'sha256', $user_id . wp_salt() . microtime( true ) ), 0, 12 );
|
||||
$wpdb->update(
|
||||
"{$wpdb->prefix}forum_users",
|
||||
[
|
||||
'username' => 'deleted_' . $anon_hash,
|
||||
'email' => 'deleted_' . $anon_hash . '@deleted.invalid',
|
||||
'password' => '',
|
||||
'display_name' => 'Gelöschter Nutzer',
|
||||
'avatar_url' => '',
|
||||
'bio' => '',
|
||||
'signature' => '',
|
||||
'ban_reason' => '',
|
||||
'reset_token' => null,
|
||||
'reset_token_expires' => null,
|
||||
'pre_ban_role' => '',
|
||||
'ban_until' => null,
|
||||
'role' => 'banned',
|
||||
],
|
||||
[ 'id' => $user_id ]
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ── Wortfilter ────────────────────────────────────────────────────────────
|
||||
|
||||
public static function get_word_filter() {
|
||||
@@ -1711,25 +1851,29 @@ class WBF_DB {
|
||||
// ── Flood Control ─────────────────────────────────────────────────────────
|
||||
|
||||
public static function check_flood( $user_id ) {
|
||||
$user_id = (int) $user_id;
|
||||
if ( $user_id <= 0 ) return true; // kein eingeloggter User — kein Flood-Check
|
||||
$interval = (int)( wbf_get_settings()['flood_interval'] ?? 0 );
|
||||
if ( $interval <= 0 ) return true; // deaktiviert
|
||||
$key = 'wbf_flood_' . (int)$user_id;
|
||||
$key = 'wbf_flood_' . (int)$user_id;
|
||||
$ts_key = 'wbf_flood_ts_' . (int)$user_id;
|
||||
$last = get_transient( $key );
|
||||
if ( $last !== false ) {
|
||||
return false; // noch gesperrt
|
||||
}
|
||||
set_transient( $key, time(), $interval );
|
||||
set_transient( $key, 1, $interval );
|
||||
set_transient( $ts_key, time(), $interval + 5 );
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function flood_remaining( $user_id ) {
|
||||
$interval = (int)( wbf_get_settings()['flood_interval'] ?? 0 );
|
||||
if ( $interval <= 0 ) return 0;
|
||||
$key = 'wbf_flood_' . (int)$user_id;
|
||||
$last = get_transient( $key );
|
||||
if ( $last === false ) return 0;
|
||||
// Transients speichern keine genaue Restzeit — wir schätzen über $interval
|
||||
return $interval;
|
||||
$ts_key = 'wbf_flood_ts_' . (int)$user_id;
|
||||
$sent = get_transient( $ts_key );
|
||||
if ( $sent === false ) return 0;
|
||||
$remaining = $interval - ( time() - (int)$sent );
|
||||
return max( 0, $remaining );
|
||||
}
|
||||
|
||||
}
|
||||
1202
includes/class-forum-export.php
Normal file
1202
includes/class-forum-export.php
Normal file
File diff suppressed because it is too large
Load Diff
@@ -15,7 +15,7 @@ class WBF_Roles {
|
||||
private static function default_roles() {
|
||||
return [
|
||||
'superadmin' => [
|
||||
'label' => 'Superadmin',
|
||||
'label' => 'Admin',
|
||||
'level' => 100,
|
||||
'color' => '#e11d48',
|
||||
'bg_color' => 'rgba(225,29,72,.15)',
|
||||
|
||||
@@ -341,9 +341,9 @@ class WBF_Shortcodes {
|
||||
<?php endif; ?>
|
||||
</aside>
|
||||
</div>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
</div>
|
||||
<?php self::render_new_thread_modal(WBF_DB::get_categories_flat(), $current); ?>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
</div>
|
||||
<?php return ob_get_clean();
|
||||
@@ -500,9 +500,9 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; endif; ?>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
|
||||
<?php self::render_new_thread_modal(WBF_DB::get_categories_flat(),$current,$cat->id); ?>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
</div>
|
||||
<?php return ob_get_clean();
|
||||
@@ -731,6 +731,23 @@ class WBF_Shortcodes {
|
||||
<i class="fas fa-pen"></i> Bearbeiten
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// Ignore-Button: nur wenn der Thread-Autor nicht der eingeloggte User ist
|
||||
// und die Rolle blockiert werden darf (konfigurierbar in Einstellungen)
|
||||
$op_author = WBF_DB::get_user((int)$thread->user_id);
|
||||
if ($current && (int)$current->id !== (int)$thread->user_id && wbf_can_be_ignored($op_author)):
|
||||
$op_is_ignored = WBF_DB::is_ignored($current->id, (int)$thread->user_id);
|
||||
?>
|
||||
<button class="wbf-ignore-btn"
|
||||
data-id="<?php echo (int)$thread->user_id; ?>"
|
||||
data-name="<?php echo esc_attr($thread->display_name); ?>"
|
||||
data-ignored="<?php echo $op_is_ignored ? '1' : '0'; ?>"
|
||||
title="<?php echo $op_is_ignored ? 'Ignorierung aufheben' : 'Nutzer ignorieren'; ?>"
|
||||
style="background:none;border:none;cursor:pointer;color:var(--c-muted,#94a3b8);padding:2px 6px;border-radius:4px;font-size:.82rem">
|
||||
<i class="fas fa-<?php echo $op_is_ignored ? 'eye' : 'eye-slash'; ?>"></i>
|
||||
<?php echo $op_is_ignored ? 'Entblocken' : 'Ignorieren'; ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -774,8 +791,8 @@ class WBF_Shortcodes {
|
||||
<?php else: ?>
|
||||
<div class="wbf-notice wbf-notice--warning"><i class="fas fa-lock"></i> Dieser Thread ist geschlossen.</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
</div>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
<?php self::render_report_modal(); ?>
|
||||
<?php if (WBF_DB::can($current,'manage_cats')): self::render_move_modal(WBF_DB::get_categories_flat(), $id); endif; ?>
|
||||
@@ -843,6 +860,22 @@ class WBF_Shortcodes {
|
||||
<i class="fas fa-pen"></i> Bearbeiten
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php
|
||||
// Ignore-Button im Post-Footer
|
||||
$post_author = WBF_DB::get_user((int)$post->user_id);
|
||||
if ($current && (int)$current->id !== (int)$post->user_id && wbf_can_be_ignored($post_author)):
|
||||
$post_is_ignored = WBF_DB::is_ignored($current->id, (int)$post->user_id);
|
||||
?>
|
||||
<button class="wbf-ignore-btn"
|
||||
data-id="<?php echo (int)$post->user_id; ?>"
|
||||
data-name="<?php echo esc_attr($post->display_name); ?>"
|
||||
data-ignored="<?php echo $post_is_ignored ? '1' : '0'; ?>"
|
||||
title="<?php echo $post_is_ignored ? 'Ignorierung aufheben' : 'Nutzer ignorieren'; ?>"
|
||||
style="background:none;border:none;cursor:pointer;color:var(--c-muted,#94a3b8);padding:2px 6px;border-radius:4px;font-size:.82rem">
|
||||
<i class="fas fa-<?php echo $post_is_ignored ? 'eye' : 'eye-slash'; ?>"></i>
|
||||
<?php echo $post_is_ignored ? 'Entblocken' : 'Ignorieren'; ?>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php echo self::mod_tools_post($post->id,$current); ?>
|
||||
</div>
|
||||
</div>
|
||||
@@ -870,14 +903,23 @@ class WBF_Shortcodes {
|
||||
</div></div>
|
||||
<?php return ob_get_clean();
|
||||
}
|
||||
$user_posts = WBF_DB::get_user_posts( $profile->id, 50 );
|
||||
$user_posts = WBF_DB::get_user_posts( $profile->id, 50 );
|
||||
$bookmarks = $is_own ? WBF_DB::get_user_bookmarks($current->id, 50) : [];
|
||||
$ignore_list = $is_own ? WBF_DB::get_ignore_list($current->id) : [];
|
||||
$cf_defs = WBF_DB::get_profile_field_defs();
|
||||
$cf_vals = WBF_DB::get_user_meta( $profile->id );
|
||||
// Aktiven Tab aus URL lesen (tab=1|2|3), Standard: 1 für eigenes, 2 für fremdes
|
||||
$active_tab = (int)($_GET['ptab'] ?? ($is_own ? 1 : 2));
|
||||
$active_tab = in_array($active_tab, [1,2,3]) ? $active_tab : ($is_own ? 1 : 2);
|
||||
// Tab 1 + 3 nur für eigenes Profil
|
||||
if (!$is_own && $active_tab !== 2) $active_tab = 2;
|
||||
|
||||
ob_start(); ?>
|
||||
<div class="wbf-wrap">
|
||||
<?php self::render_topbar($current); ?>
|
||||
<div class="wbf-container wbf-mt">
|
||||
<nav class="wbf-breadcrumb">
|
||||
<a href="<?php echo esc_url(remove_query_arg('forum_profile')); ?>"><i class="fas fa-home"></i> Forum</a>
|
||||
<a href="<?php echo esc_url(remove_query_arg(['forum_profile', 'ptab'])); ?>"><i class="fas fa-home"></i> Forum</a>
|
||||
<span>/</span><span>Profil</span>
|
||||
</nav>
|
||||
|
||||
@@ -885,8 +927,6 @@ class WBF_Shortcodes {
|
||||
|
||||
<!-- ── SIDEBAR ─────────────────────────────────────────── -->
|
||||
<aside class="wbf-profile-sidebar">
|
||||
|
||||
<!-- Avatar -->
|
||||
<div class="wbf-profile-sidebar__avatar-wrap">
|
||||
<img src="<?php echo esc_url($profile->avatar_url); ?>"
|
||||
alt="<?php echo esc_attr($profile->display_name); ?>"
|
||||
@@ -898,15 +938,24 @@ class WBF_Shortcodes {
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Name + Badge + Username -->
|
||||
<div class="wbf-profile-sidebar__identity">
|
||||
<h2><?php echo esc_html($profile->display_name); ?></h2>
|
||||
<?php echo self::role_badge($profile->role); ?>
|
||||
<span class="wbf-profile-sidebar__username">@<?php echo esc_html($profile->username); ?></span>
|
||||
<?php
|
||||
$profile_online = WBF_DB::is_online($profile->id, 15);
|
||||
if ($profile_online): ?>
|
||||
<span class="wbf-profile-online-badge">
|
||||
<span class="wbf-profile-online-dot"></span> Online
|
||||
</span>
|
||||
<?php else:
|
||||
$last = $profile->last_active ?? null;
|
||||
if ($last && $last !== '0000-00-00 00:00:00'): ?>
|
||||
<span class="wbf-profile-lastseen">
|
||||
<i class="fas fa-clock"></i> Zuletzt aktiv: <?php echo self::time_ago($last); ?>
|
||||
</span>
|
||||
<?php endif; endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Stats -->
|
||||
<div class="wbf-profile-sidebar__stats">
|
||||
<div class="wbf-profile-sidebar__stat">
|
||||
<span><?php echo (int)$profile->post_count; ?></span>
|
||||
@@ -917,65 +966,94 @@ class WBF_Shortcodes {
|
||||
<em>Dabei seit</em>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Level-Fortschritt -->
|
||||
<?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>
|
||||
<div class="wbf-profile-sidebar__section"><?php echo $level_bar; ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Bio -->
|
||||
<?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>
|
||||
<p><?php echo nl2br(esc_html($profile->bio)); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Signatur -->
|
||||
<?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>
|
||||
<p class="wbf-profile-sidebar__sig"><?php echo nl2br(esc_html($profile->signature)); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Benutzerdefinierte Profilfelder (öffentliche) -->
|
||||
<?php
|
||||
$cf_defs_pub = WBF_DB::get_profile_field_defs();
|
||||
$cf_vals_pub = WBF_DB::get_user_meta( $profile->id );
|
||||
foreach ( $cf_defs_pub as $def ):
|
||||
if ( ! $is_own && empty($def['public']) ) continue;
|
||||
$val = trim( $cf_vals_pub[ $def['key'] ] ?? '' );
|
||||
if ( $val === '' ) continue;
|
||||
?>
|
||||
<!-- Öffentliche Custom Fields -->
|
||||
<?php foreach ($cf_defs as $def):
|
||||
if (!$is_own && empty($def['public'])) continue;
|
||||
$val = trim($cf_vals[$def['key']] ?? '');
|
||||
if ($val === '') continue; ?>
|
||||
<div class="wbf-profile-sidebar__section">
|
||||
<span class="wbf-profile-sidebar__section-label">
|
||||
<i class="fas fa-<?php echo $def['type']==='url'?'link':($def['type']==='number'?'hashtag':'tag'); ?>"></i>
|
||||
<?php echo esc_html($def['label']); ?>
|
||||
</span>
|
||||
<?php if ( $def['type'] === 'url' ): ?>
|
||||
<?php if ($def['type'] === 'url'): ?>
|
||||
<a href="<?php echo esc_url($val); ?>" target="_blank" rel="noopener noreferrer"
|
||||
style="color:var(--c-primary);font-size:.85rem;word-break:break-all">
|
||||
<?php echo esc_html( mb_strtolower( preg_replace('#^https?://#i','',$val) ) ); ?>
|
||||
<?php echo esc_html(mb_strtolower(preg_replace('#^https?://#i','',$val))); ?>
|
||||
</a>
|
||||
<?php elseif ( $def['type'] === 'textarea' ): ?>
|
||||
<?php elseif ($def['type'] === 'textarea'): ?>
|
||||
<p style="font-size:.85rem"><?php echo nl2br(esc_html($val)); ?></p>
|
||||
<?php else: ?>
|
||||
<p style="font-size:.85rem"><?php echo esc_html($val); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
</aside>
|
||||
|
||||
<!-- ── MAIN ────────────────────────────────────────────── -->
|
||||
<div class="wbf-profile-main">
|
||||
|
||||
<!-- Profil bearbeiten (nur eigenes) -->
|
||||
<!-- 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-card"> <div class="wbf-profile-card__header">
|
||||
<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>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
TAB 1 — Profil bearbeiten + Weitere Profilangaben
|
||||
══════════════════════════════════════════════════ -->
|
||||
<?php if ($is_own && $active_tab === 1): ?>
|
||||
|
||||
<!-- Profil bearbeiten -->
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-sliders"></i> Profil bearbeiten
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
@@ -995,7 +1073,10 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
<div class="wbf-form-row">
|
||||
<label>Signatur <small>(max. 300 Zeichen)</small></label>
|
||||
<div class="wbf-form-row" style="display:flex;align-items:center;gap:.75rem;margin-bottom:.75rem">
|
||||
<textarea id="wbfEditSignature" rows="2" maxlength="300" placeholder="Deine Signatur…"><?php echo esc_textarea($profile->signature ?? ''); ?></textarea>
|
||||
<div class="wbf-sig-counter"><span id="wbfSigCount"><?php echo mb_strlen($profile->signature??''); ?></span>/300</div>
|
||||
</div>
|
||||
<div class="wbf-form-row" style="display:flex;align-items:center;gap:.75rem">
|
||||
<label style="font-size:.82rem;color:var(--c-muted)">Profil öffentlich sichtbar</label>
|
||||
<?php $pub = (int)($profile->profile_public ?? 1); ?>
|
||||
<button type="button" id="wbfToggleProfileVis"
|
||||
@@ -1005,9 +1086,6 @@ class WBF_Shortcodes {
|
||||
<?php echo $pub?'Öffentlich':'Privat'; ?>
|
||||
</button>
|
||||
</div>
|
||||
<textarea id="wbfEditSignature" rows="2" maxlength="300" placeholder="Deine Signatur…"><?php echo esc_textarea($profile->signature ?? ''); ?></textarea>
|
||||
<div class="wbf-sig-counter"><span id="wbfSigCount"><?php echo mb_strlen($profile->signature??''); ?></span>/300</div>
|
||||
</div>
|
||||
<div class="wbf-profile-card__footer">
|
||||
<button class="wbf-btn wbf-btn--primary" id="wbfSaveProfile">
|
||||
<i class="fas fa-save"></i> Speichern
|
||||
@@ -1017,43 +1095,67 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Benutzerdefinierte Profilfelder ──────────────── -->
|
||||
<?php
|
||||
$cf_defs = WBF_DB::get_profile_field_defs();
|
||||
$cf_vals = WBF_DB::get_user_meta( $profile->id );
|
||||
if ( ! empty( $cf_defs ) ):
|
||||
?>
|
||||
<!-- E-Mail-Adresse ändern -->
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-envelope"></i> E-Mail-Adresse
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
<p style="font-size:.82rem;color:var(--c-muted);margin-bottom:1rem">
|
||||
Aktuelle Adresse: <strong style="color:var(--c-text)"><?php echo esc_html($profile->email); ?></strong>
|
||||
</p>
|
||||
<div class="wbf-profile-edit-grid">
|
||||
<div class="wbf-form-row">
|
||||
<label>Neue E-Mail-Adresse</label>
|
||||
<input type="email" id="wbfNewEmail" placeholder="neue@email.de" autocomplete="off">
|
||||
</div>
|
||||
<div class="wbf-form-row">
|
||||
<label>Aktuelles Passwort <small>(zur Bestätigung)</small></label>
|
||||
<input type="password" id="wbfEmailPassword" placeholder="••••••" autocomplete="current-password">
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbf-profile-card__footer">
|
||||
<button class="wbf-btn wbf-btn--primary" id="wbfSaveEmail">
|
||||
<i class="fas fa-envelope"></i> E-Mail ändern
|
||||
</button>
|
||||
<span class="wbf-msg" id="wbfEmailMsg"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Weitere Profilangaben -->
|
||||
<?php if (!empty($cf_defs)): ?>
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-sliders"></i> Weitere Profilangaben
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
<div class="wbf-profile-edit-grid">
|
||||
<?php foreach ( $cf_defs as $def ):
|
||||
$k = esc_attr( $def['key'] );
|
||||
$lbl = esc_html( $def['label'] );
|
||||
$ph = esc_attr( $def['placeholder'] ?? '' );
|
||||
$val = esc_attr( $cf_vals[ $def['key'] ] ?? '' );
|
||||
$req = ! empty($def['required']) ? 'required' : '';
|
||||
<?php foreach ($cf_defs as $def):
|
||||
$k = esc_attr($def['key']);
|
||||
$lbl = esc_html($def['label']);
|
||||
$ph = esc_attr($def['placeholder'] ?? '');
|
||||
$val = esc_attr($cf_vals[$def['key']] ?? '');
|
||||
$req = !empty($def['required']) ? 'required' : '';
|
||||
?>
|
||||
<div class="wbf-form-row">
|
||||
<label><?php echo $lbl; ?><?php if($req): ?> <span style="color:var(--c-danger)">*</span><?php endif; ?></label>
|
||||
<?php if ( $def['type'] === 'textarea' ): ?>
|
||||
<?php if ($def['type'] === 'textarea'): ?>
|
||||
<textarea class="wbf-cf-input" data-field="cf_<?php echo $k; ?>"
|
||||
rows="2" placeholder="<?php echo $ph; ?>"
|
||||
<?php echo $req; ?>><?php echo esc_textarea( $cf_vals[$def['key']] ?? '' ); ?></textarea>
|
||||
<?php elseif ( $def['type'] === 'select' ):
|
||||
$opts = array_filter( array_map('trim', explode("\n", $def['options'] ?? '')) );
|
||||
<?php echo $req; ?>><?php echo esc_textarea($cf_vals[$def['key']] ?? ''); ?></textarea>
|
||||
<?php elseif ($def['type'] === 'select'):
|
||||
$opts = array_filter(array_map('trim', explode("\n", $def['options'] ?? '')));
|
||||
?>
|
||||
<select class="wbf-cf-input" data-field="cf_<?php echo $k; ?>">
|
||||
<option value="">— Bitte wählen —</option>
|
||||
<?php foreach ( $opts as $opt ): ?>
|
||||
<?php foreach ($opts as $opt): ?>
|
||||
<option value="<?php echo esc_attr($opt); ?>"
|
||||
<?php selected( $cf_vals[$def['key']] ?? '', $opt ); ?>><?php echo esc_html($opt); ?></option>
|
||||
<?php selected($cf_vals[$def['key']] ?? '', $opt); ?>><?php echo esc_html($opt); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php else: ?>
|
||||
<input type="<?php echo $def['type'] === 'url' ? 'url' : ($def['type'] === 'number' ? 'number' : 'text'); ?>"
|
||||
<input type="<?php echo $def['type']==='url'?'url':($def['type']==='number'?'number':'text'); ?>"
|
||||
class="wbf-cf-input"
|
||||
data-field="cf_<?php echo $k; ?>"
|
||||
value="<?php echo $val; ?>"
|
||||
@@ -1073,95 +1175,15 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ── DSGVO: Konto löschen ──────────────────────────── -->
|
||||
<div class="wbf-profile-card" style="border-color:rgba(240,82,82,.25)">
|
||||
<div class="wbf-profile-card__header" style="color:var(--c-danger);background:rgba(240,82,82,.06);border-bottom-color:rgba(240,82,82,.15)">
|
||||
<i class="fas fa-shield-halved"></i> Datenschutz & Konto löschen
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
<p style="font-size:.85rem;color:var(--c-text-dim);margin-bottom:1rem;line-height:1.6">
|
||||
Gemäß <strong>DSGVO Art. 17</strong> (Recht auf Vergessenwerden) kannst du die vollständige Löschung deines Kontos und aller personenbezogenen Daten beantragen.<br>
|
||||
<span style="color:var(--c-muted);font-size:.8rem">Deine Beiträge bleiben anonymisiert sichtbar. Direktnachrichten, Likes, Profilinformationen und alle persönlichen Daten werden dauerhaft gelöscht.</span>
|
||||
</p>
|
||||
<div id="wbfGdprBox" style="background:rgba(240,82,82,.06);border:1px solid rgba(240,82,82,.2);border-radius:var(--radius-sm);padding:1.1rem;display:none">
|
||||
<p style="font-size:.82rem;font-weight:700;color:var(--c-danger);margin-bottom:.9rem"><i class="fas fa-triangle-exclamation"></i> Diese Aktion ist unwiderruflich.</p>
|
||||
<div class="wbf-form-row">
|
||||
<label style="font-size:.72rem">Passwort zur Bestätigung</label>
|
||||
<input type="password" id="wbfGdprPassword" placeholder="Dein aktuelles Passwort" autocomplete="current-password">
|
||||
</div>
|
||||
<label style="display:flex;align-items:center;gap:.6rem;font-size:.82rem;color:var(--c-text-dim);cursor:pointer;margin-bottom:1rem">
|
||||
<input type="checkbox" id="wbfGdprConfirm" style="width:15px;height:15px;accent-color:var(--c-danger);cursor:pointer">
|
||||
Ich verstehe, dass mein Konto und alle persönlichen Daten unwiderruflich gelöscht werden.
|
||||
</label>
|
||||
<div style="display:flex;gap:.75rem;align-items:center;flex-wrap:wrap">
|
||||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprCancel" onclick="document.getElementById('wbfGdprBox').style.display='none';document.getElementById('wbfGdprToggle').style.display=''">
|
||||
<i class="fas fa-xmark"></i> Abbrechen
|
||||
</button>
|
||||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprSubmit"
|
||||
style="background:rgba(240,82,82,.15);color:var(--c-danger);border-color:rgba(240,82,82,.4)">
|
||||
<i class="fas fa-trash-can"></i> Konto endgültig löschen
|
||||
</button>
|
||||
<span class="wbf-msg" id="wbfGdprMsg"></span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprToggle"
|
||||
style="background:rgba(240,82,82,.08);color:var(--c-danger);border-color:rgba(240,82,82,.3)"
|
||||
onclick="document.getElementById('wbfGdprBox').style.display='';document.getElementById('wbfGdprToggle').style.display='none'">
|
||||
<i class="fas fa-trash-can"></i> Konto löschen (DSGVO Art. 17)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; /* end Tab 1 */ ?>
|
||||
|
||||
<?php endif; /* end $is_own */ ?>
|
||||
|
||||
<!-- Beiträge -->
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-comments"></i> Beiträge
|
||||
<span class="wbf-profile-card__count"><?php echo count($user_posts); ?></span>
|
||||
</div>
|
||||
<div class="wbf-profile-card__body wbf-profile-card__body--posts">
|
||||
<?php if (empty($user_posts)): ?>
|
||||
<p class="wbf-profile-empty">Noch keine Beiträge.</p>
|
||||
<?php else:
|
||||
foreach ($user_posts as $up):
|
||||
$preview = esc_html( mb_substr( strip_tags($up->content), 0, 130 ) );
|
||||
$more = mb_strlen( strip_tags($up->content) ) > 130 ? '…' : '';
|
||||
$is_thread = isset($up->entry_type) && $up->entry_type === 'thread';
|
||||
$anchor = $is_thread
|
||||
? '?forum_thread=' . (int)$up->thread_id
|
||||
: '?forum_thread=' . (int)$up->thread_id . '#post-' . (int)$up->id;
|
||||
?>
|
||||
<div class="wbf-profile-post-item">
|
||||
<div class="wbf-profile-post-item__top">
|
||||
<?php if ($is_thread): ?>
|
||||
<span class="wbf-profile-post-item__type wbf-profile-post-item__type--thread">
|
||||
<i class="fas fa-layer-group"></i> Thread
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="wbf-profile-post-item__type wbf-profile-post-item__type--reply">
|
||||
<i class="fas fa-reply"></i> Antwort
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo esc_url($anchor); ?>" class="wbf-profile-post-item__title">
|
||||
<?php echo esc_html( mb_substr($up->thread_title, 0, 60) ); ?>
|
||||
</a>
|
||||
<span class="wbf-profile-post-item__cat">
|
||||
<i class="fas fa-folder"></i> <?php echo esc_html($up->cat_name); ?>
|
||||
</span>
|
||||
<span class="wbf-profile-post-item__time"><?php echo self::time_ago($up->created_at); ?></span>
|
||||
</div>
|
||||
<?php if ($preview): ?>
|
||||
<p class="wbf-profile-post-item__preview"><?php echo $preview . $more; ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
TAB 2 — Lesezeichen + Beiträge
|
||||
══════════════════════════════════════════════════ -->
|
||||
<?php if ($active_tab === 2): ?>
|
||||
|
||||
<!-- Lesezeichen (nur eigenes Profil) -->
|
||||
<?php if ($is_own):
|
||||
$bookmarks = WBF_DB::get_user_bookmarks($current->id, 50); ?>
|
||||
<?php if ($is_own): ?>
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-bookmark"></i> Lesezeichen
|
||||
@@ -1186,6 +1208,192 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Beiträge -->
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-comments"></i> Beiträge
|
||||
<span class="wbf-profile-card__count"><?php echo count($user_posts); ?></span>
|
||||
</div>
|
||||
<div class="wbf-profile-card__body wbf-profile-card__body--posts">
|
||||
<?php if (empty($user_posts)): ?>
|
||||
<p class="wbf-profile-empty">Noch keine Beiträge.</p>
|
||||
<?php else:
|
||||
foreach ($user_posts as $up):
|
||||
$preview = esc_html(mb_substr(strip_tags($up->content), 0, 130));
|
||||
$more = mb_strlen(strip_tags($up->content)) > 130 ? '…' : '';
|
||||
$is_thread = isset($up->entry_type) && $up->entry_type === 'thread';
|
||||
$anchor = $is_thread
|
||||
? '?forum_thread=' . (int)$up->thread_id
|
||||
: '?forum_thread=' . (int)$up->thread_id . '#post-' . (int)$up->id;
|
||||
?>
|
||||
<div class="wbf-profile-post-item">
|
||||
<div class="wbf-profile-post-item__top">
|
||||
<?php if ($is_thread): ?>
|
||||
<span class="wbf-profile-post-item__type wbf-profile-post-item__type--thread">
|
||||
<i class="fas fa-layer-group"></i> Thread
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="wbf-profile-post-item__type wbf-profile-post-item__type--reply">
|
||||
<i class="fas fa-reply"></i> Antwort
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo esc_url($anchor); ?>" class="wbf-profile-post-item__title">
|
||||
<?php echo esc_html(mb_substr($up->thread_title, 0, 60)); ?>
|
||||
</a>
|
||||
<span class="wbf-profile-post-item__cat">
|
||||
<i class="fas fa-folder"></i> <?php echo esc_html($up->cat_name); ?>
|
||||
</span>
|
||||
<span class="wbf-profile-post-item__time"><?php echo self::time_ago($up->created_at); ?></span>
|
||||
</div>
|
||||
<?php if ($preview): ?>
|
||||
<p class="wbf-profile-post-item__preview"><?php echo $preview . $more; ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endforeach; endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php endif; /* end Tab 2 */ ?>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
TAB 3 — Ignorierte Nutzer + Datenschutz
|
||||
══════════════════════════════════════════════════ -->
|
||||
<?php if ($is_own && $active_tab === 3): ?>
|
||||
|
||||
<!-- Ignorierte Nutzer -->
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-bell"></i> E-Mail-Benachrichtigungen
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
<?php
|
||||
$notif_meta = WBF_DB::get_user_meta($current->id);
|
||||
$n_reply = ($notif_meta['notify_reply'] ?? '1') !== '0';
|
||||
$n_mention = ($notif_meta['notify_mention'] ?? '1') !== '0';
|
||||
$n_message = ($notif_meta['notify_message'] ?? '1') !== '0';
|
||||
?>
|
||||
<p style="font-size:.82rem;color:var(--c-muted);margin-bottom:1rem">
|
||||
Lege fest bei welchen Ereignissen du eine E-Mail erhältst.
|
||||
</p>
|
||||
<div class="wbf-notif-pref-list">
|
||||
<label class="wbf-notif-pref">
|
||||
<div class="wbf-notif-pref__info">
|
||||
<span><i class="fas fa-reply"></i> Antworten auf meine Threads</span>
|
||||
<small>Wenn jemand in einem deiner Threads antwortet</small>
|
||||
</div>
|
||||
<div class="wbf-toggle<?php echo $n_reply?' wbf-toggle--on':''; ?>"
|
||||
id="wbfNotifReply" data-key="notify_reply" data-state="<?php echo $n_reply?'1':'0'; ?>">
|
||||
<div class="wbf-toggle__knob"></div>
|
||||
</div>
|
||||
</label>
|
||||
<label class="wbf-notif-pref">
|
||||
<div class="wbf-notif-pref__info">
|
||||
<span><i class="fas fa-at"></i> @Erwähnungen</span>
|
||||
<small>Wenn dich jemand in einem Beitrag erwähnt</small>
|
||||
</div>
|
||||
<div class="wbf-toggle<?php echo $n_mention?' wbf-toggle--on':''; ?>"
|
||||
id="wbfNotifMention" data-key="notify_mention" data-state="<?php echo $n_mention?'1':'0'; ?>">
|
||||
<div class="wbf-toggle__knob"></div>
|
||||
</div>
|
||||
</label>
|
||||
<label class="wbf-notif-pref">
|
||||
<div class="wbf-notif-pref__info">
|
||||
<span><i class="fas fa-envelope"></i> Privatnachrichten</span>
|
||||
<small>Wenn du eine neue Direktnachricht erhältst</small>
|
||||
</div>
|
||||
<div class="wbf-toggle<?php echo $n_message?' wbf-toggle--on':''; ?>"
|
||||
id="wbfNotifMessage" data-key="notify_message" data-state="<?php echo $n_message?'1':'0'; ?>">
|
||||
<div class="wbf-toggle__knob"></div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="wbf-profile-card__footer" style="margin-top:1rem">
|
||||
<button class="wbf-btn wbf-btn--primary" id="wbfSaveNotifPrefs">
|
||||
<i class="fas fa-save"></i> Einstellungen speichern
|
||||
</button>
|
||||
<span class="wbf-msg" id="wbfNotifPrefsMsg"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ignorierte Nutzer -->
|
||||
<div class="wbf-profile-card">
|
||||
<div class="wbf-profile-card__header">
|
||||
<i class="fas fa-eye-slash"></i> Ignorierte Nutzer
|
||||
<span class="wbf-profile-card__count" id="wbfIgnoreCount"><?php echo count($ignore_list); ?></span>
|
||||
</div>
|
||||
<div class="wbf-profile-card__body" id="wbfIgnoreListWrap">
|
||||
<?php if (empty($ignore_list)): ?>
|
||||
<p class="wbf-profile-empty" id="wbfIgnoreEmpty">Du ignorierst niemanden.</p>
|
||||
<?php else: ?>
|
||||
<div class="wbf-ignore-list" id="wbfIgnoreList">
|
||||
<?php foreach ($ignore_list as $ign): ?>
|
||||
<div class="wbf-ignore-item" id="wbf-ignore-item-<?php echo (int)$ign->id; ?>">
|
||||
<a href="?forum_profile=<?php echo (int)$ign->id; ?>" class="wbf-ignore-item__avatar">
|
||||
<?php echo self::avatar($ign->avatar_url, $ign->display_name, 36); ?>
|
||||
</a>
|
||||
<div class="wbf-ignore-item__info">
|
||||
<a href="?forum_profile=<?php echo (int)$ign->id; ?>" class="wbf-ignore-item__name">
|
||||
<?php echo esc_html($ign->display_name); ?>
|
||||
</a>
|
||||
<span class="wbf-ignore-item__since">Ignoriert seit <?php echo self::time_ago($ign->ignored_since); ?></span>
|
||||
</div>
|
||||
<button class="wbf-ignore-btn wbf-btn wbf-btn--sm"
|
||||
data-id="<?php echo (int)$ign->id; ?>"
|
||||
data-name="<?php echo esc_attr($ign->display_name); ?>"
|
||||
data-ignored="1"
|
||||
style="margin-left:auto">
|
||||
<i class="fas fa-eye"></i> Entblocken
|
||||
</button>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Datenschutz & Konto löschen -->
|
||||
<div class="wbf-profile-card" style="border-color:rgba(240,82,82,.25)">
|
||||
<div class="wbf-profile-card__header" style="color:var(--c-danger);background:rgba(240,82,82,.06);border-bottom-color:rgba(240,82,82,.15)">
|
||||
<i class="fas fa-shield-halved"></i> Datenschutz & Konto löschen
|
||||
</div>
|
||||
<div class="wbf-profile-card__body">
|
||||
<p style="font-size:.85rem;color:var(--c-text-dim);margin-bottom:1rem;line-height:1.6">
|
||||
Gemäß <strong>DSGVO Art. 17</strong> (Recht auf Vergessenwerden) kannst du die vollständige Löschung deines Kontos und aller personenbezogenen Daten beantragen.<br>
|
||||
<span style="color:var(--c-muted);font-size:.8rem">Deine Beiträge bleiben anonymisiert sichtbar. Direktnachrichten, Likes, Profilinformationen und alle persönlichen Daten werden dauerhaft gelöscht.</span>
|
||||
</p>
|
||||
<div id="wbfGdprBox" style="background:rgba(240,82,82,.06);border:1px solid rgba(240,82,82,.2);border-radius:var(--radius-sm);padding:1.1rem;display:none">
|
||||
<p style="font-size:.82rem;font-weight:700;color:var(--c-danger);margin-bottom:.9rem"><i class="fas fa-triangle-exclamation"></i> Diese Aktion ist unwiderruflich.</p>
|
||||
<div class="wbf-form-row">
|
||||
<label style="font-size:.72rem">Passwort zur Bestätigung</label>
|
||||
<input type="password" id="wbfGdprPassword" placeholder="Dein aktuelles Passwort" autocomplete="current-password">
|
||||
</div>
|
||||
<label style="display:flex;align-items:center;gap:.6rem;font-size:.82rem;color:var(--c-text-dim);cursor:pointer;margin-bottom:1rem">
|
||||
<input type="checkbox" id="wbfGdprConfirm" style="width:15px;height:15px;accent-color:var(--c-danger);cursor:pointer">
|
||||
Ich verstehe, dass mein Konto und alle persönlichen Daten unwiderruflich gelöscht werden.
|
||||
</label>
|
||||
<div style="display:flex;gap:.75rem;align-items:center;flex-wrap:wrap">
|
||||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprCancel"
|
||||
onclick="document.getElementById('wbfGdprBox').style.display='none';document.getElementById('wbfGdprToggle').style.display=''">
|
||||
<i class="fas fa-xmark"></i> Abbrechen
|
||||
</button>
|
||||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprSubmit"
|
||||
style="background:rgba(240,82,82,.15);color:var(--c-danger);border-color:rgba(240,82,82,.4)">
|
||||
<i class="fas fa-trash-can"></i> Konto endgültig löschen
|
||||
</button>
|
||||
<span class="wbf-msg" id="wbfGdprMsg"></span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="wbf-btn wbf-btn--sm" id="wbfGdprToggle"
|
||||
style="background:rgba(240,82,82,.08);color:var(--c-danger);border-color:rgba(240,82,82,.3)"
|
||||
onclick="document.getElementById('wbfGdprBox').style.display='';document.getElementById('wbfGdprToggle').style.display='none'">
|
||||
<i class="fas fa-trash-can"></i> Konto löschen (DSGVO Art. 17)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php endif; /* end Tab 3 */ ?>
|
||||
|
||||
</div><!-- /.wbf-profile-main -->
|
||||
</div><!-- /.wbf-profile-layout -->
|
||||
</div>
|
||||
@@ -1193,6 +1401,7 @@ class WBF_Shortcodes {
|
||||
<?php return ob_get_clean();
|
||||
}
|
||||
|
||||
|
||||
// ── TAG PAGE ─────────────────────────────────────────────────────────────
|
||||
|
||||
private static function view_tag() {
|
||||
@@ -1274,8 +1483,8 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
</div>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
</div>
|
||||
<?php return ob_get_clean();
|
||||
@@ -1355,8 +1564,8 @@ class WBF_Shortcodes {
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
</div>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
<?php self::render_dm_compose_modal(); ?>
|
||||
</div>
|
||||
@@ -1443,8 +1652,8 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
<p style="color:var(--c-muted);font-size:.82rem;margin-top:1rem"><?php echo count($results); ?> Ergebnis(se) gefunden.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
</div>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
</div>
|
||||
<?php return ob_get_clean();
|
||||
@@ -2080,8 +2289,8 @@ class WBF_Shortcodes {
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
<?php self::render_forum_footer(); ?>
|
||||
</div>
|
||||
<?php self::render_auth_modal(); ?>
|
||||
</div>
|
||||
<?php return ob_get_clean();
|
||||
@@ -2120,7 +2329,7 @@ class WBF_Shortcodes {
|
||||
if ( ( wbf_get_settings()['rules_enabled'] ?? '1' ) !== '1' ) return;
|
||||
$rules_url = esc_url( wbf_get_forum_url() . '?forum_rules=1' );
|
||||
?>
|
||||
<div style="border-top:1px solid var(--c-border);margin-top:3rem;padding:1.25rem 1.5rem;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.75rem;background:var(--c-bg2)">
|
||||
<div style="border:1px solid var(--c-border);border-radius:var(--radius);margin-top:2rem;padding:1rem 1.25rem;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.75rem;background:var(--c-surface)">
|
||||
<span style="font-size:.78rem;color:var(--c-muted)">
|
||||
<i class="fas fa-shield-halved" style="color:var(--c-primary);margin-right:.35rem"></i>
|
||||
Durch die Nutzung des Forums stimmst du unseren Regeln zu.
|
||||
|
||||
Reference in New Issue
Block a user