Upload folder via GUI - includes
This commit is contained in:
428
includes/class-forum-abo.php
Normal file
428
includes/class-forum-abo.php
Normal file
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
/**
|
||||
* WBF_Abo — Abo-Verwaltung im Forum-Profil
|
||||
* Fly-Abo: WordPress DB (wp_wis_fly_abo_subs)
|
||||
* Plot-Abo/Slots: Spigot MySQL (optional)
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) exit;
|
||||
|
||||
class WBF_Abo {
|
||||
|
||||
private static function get_spigot_db(): ?mysqli {
|
||||
$s = function_exists('wbf_get_settings') ? wbf_get_settings() : [];
|
||||
$host = $s['spigot_mysql_host'] ?? '';
|
||||
$port = (int)($s['spigot_mysql_port'] ?? 3306);
|
||||
$db = $s['spigot_mysql_database'] ?? '';
|
||||
$user = $s['spigot_mysql_username'] ?? '';
|
||||
$pass = $s['spigot_mysql_password'] ?? '';
|
||||
if ( empty($db) || empty($user) ) return null;
|
||||
$conn = @new mysqli($host, $user, $pass, $db, $port);
|
||||
if ( $conn->connect_errno ) return null;
|
||||
$conn->set_charset('utf8mb4');
|
||||
return $conn;
|
||||
}
|
||||
|
||||
public static function get_all_abos( string $mc_name ): array {
|
||||
global $wpdb;
|
||||
$result = ['fly_used_sec' => 0, 'plot_extra' => 0];
|
||||
|
||||
// Fly-Abo aus WordPress DB
|
||||
$fly = $wpdb->get_row( $wpdb->prepare(
|
||||
"SELECT label, price, status, cancelled, cancelled_at, expires_at, renewal_count
|
||||
FROM {$wpdb->prefix}wis_fly_abo_subs
|
||||
WHERE player_name = %s ORDER BY id DESC LIMIT 1",
|
||||
$mc_name
|
||||
), ARRAY_A );
|
||||
|
||||
if ( $fly ) {
|
||||
$expires = new DateTime( $fly['expires_at'] );
|
||||
$cancelled = (int)$fly['cancelled'] === 1;
|
||||
$is_active = $fly['status'] === 'active' && $expires > new DateTime();
|
||||
$result['fly_abo'] = [
|
||||
'label' => $fly['label'],
|
||||
'monthly_price' => (int)$fly['price'],
|
||||
'cancelled' => $cancelled ? 1 : 0,
|
||||
'cancellation_reason' => $cancelled ? 'user' : null,
|
||||
'next_billing' => ( new DateTime('first day of next month') )->format('d.m.Y'),
|
||||
'period_end' => $expires->format('d.m.Y'),
|
||||
'is_active' => $is_active,
|
||||
];
|
||||
}
|
||||
|
||||
// Spigot MySQL für Fly-Usage + Plot-Daten
|
||||
$conn = self::get_spigot_db();
|
||||
if ( $conn ) {
|
||||
foreach ([
|
||||
["SELECT used_sec FROM wis_fly_abo_usage WHERE player_name = ? AND usage_date = CURDATE()", 'fly_used_sec', 'used_sec'],
|
||||
] as [$sql, $key, $field]) {
|
||||
$stmt = $conn->prepare($sql);
|
||||
if ($stmt) { $stmt->bind_param('s', $mc_name); $stmt->execute();
|
||||
$r = $stmt->get_result()->fetch_assoc();
|
||||
$result[$key] = $r ? (int)$r[$field] : 0; $stmt->close(); }
|
||||
}
|
||||
$stmt = $conn->prepare(
|
||||
"SELECT label, abo_slots, monthly_price, cancelled, cancellation_reason,
|
||||
DATE_FORMAT(next_billing_date,'%d.%m.%Y') AS next_billing,
|
||||
DATE_FORMAT(period_end,'%d.%m.%Y') AS period_end
|
||||
FROM wis_plot_abos WHERE player_name = ? AND period_end >= CURDATE()"
|
||||
);
|
||||
if ($stmt) { $stmt->bind_param('s', $mc_name); $stmt->execute();
|
||||
$r = $stmt->get_result()->fetch_assoc();
|
||||
if ($r) $result['plot_abo'] = $r; $stmt->close(); }
|
||||
$stmt = $conn->prepare("SELECT extra_slots FROM wis_plot_extra_slots WHERE player_name = ?");
|
||||
if ($stmt) { $stmt->bind_param('s', $mc_name); $stmt->execute();
|
||||
$r = $stmt->get_result()->fetch_assoc();
|
||||
$result['plot_extra'] = $r ? (int)$r['extra_slots'] : 0; $stmt->close(); }
|
||||
$conn->close();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function cancel_abo( string $mc_name, string $type ): bool {
|
||||
global $wpdb;
|
||||
if ( $type === 'fly_abo' ) {
|
||||
$rows = $wpdb->update(
|
||||
$wpdb->prefix . 'wis_fly_abo_subs',
|
||||
['cancelled' => 1, 'cancelled_at' => current_time('mysql')],
|
||||
['player_name' => $mc_name, 'status' => 'active', 'cancelled' => 0]
|
||||
);
|
||||
return $rows > 0;
|
||||
}
|
||||
if ( $type === 'plot_abo' ) {
|
||||
$conn = self::get_spigot_db();
|
||||
if (!$conn) return false;
|
||||
$stmt = $conn->prepare("UPDATE wis_plot_abos SET cancelled=1, cancellation_reason='user', period_end=LAST_DAY(CURDATE()) WHERE player_name=? AND period_end>=CURDATE() AND cancelled=0");
|
||||
if (!$stmt) { $conn->close(); return false; }
|
||||
$stmt->bind_param('s', $mc_name); $stmt->execute();
|
||||
$a = $stmt->affected_rows; $stmt->close(); $conn->close();
|
||||
return $a > 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function format_seconds( int $sec ): string {
|
||||
if ($sec >= 3600) { $h = intdiv($sec,3600); $m = intdiv($sec%3600,60); return $h.'h'.($m>0?' '.$m.'min':''); }
|
||||
if ($sec >= 60) { return intdiv($sec,60).'min'; }
|
||||
return $sec.'s';
|
||||
}
|
||||
|
||||
public static function render_tab( string $mc_name, int $profile_id ): string {
|
||||
$abos = self::get_all_abos($mc_name);
|
||||
$fly_abo = $abos['fly_abo'] ?? null;
|
||||
$plot_abo = $abos['plot_abo'] ?? null;
|
||||
$plot_extra = (int)($abos['plot_extra'] ?? 0);
|
||||
$fly_used = (int)($abos['fly_used_sec'] ?? 0);
|
||||
$fly_max = (int) get_option('wis_fly_abo_max_daily_hours', 6) * 3600;
|
||||
$currency = esc_html(get_option('wis_currency_name', '$'));
|
||||
$shop_url = esc_url(get_option('wis_shop_url', home_url('/ingame-shop/')));
|
||||
$nonce = wp_create_nonce('wbf_nonce');
|
||||
$ajax_url = admin_url('admin-ajax.php');
|
||||
$has_any = $fly_abo || $plot_abo || $plot_extra > 0;
|
||||
|
||||
ob_start(); ?>
|
||||
<style>
|
||||
.wbf-abo-wrap { display:flex; flex-direction:column; gap:1rem; }
|
||||
.wbf-abo-empty { text-align:center; padding:2.5rem 1rem; color:var(--c-muted); }
|
||||
.wbf-abo-empty__icon { font-size:2.5rem; margin-bottom:.5rem; }
|
||||
.wbf-abo-item { border-radius:12px; overflow:hidden; border:1px solid var(--c-border); background:var(--c-bg); }
|
||||
.wbf-abo-item--active { border-left:4px solid var(--c-success); }
|
||||
.wbf-abo-item--cancelled { border-left:4px solid var(--c-danger); opacity:.9; }
|
||||
.wbf-abo-item--info { border-left:4px solid var(--c-primary); }
|
||||
.wbf-abo-item__head { display:flex; align-items:center; gap:.9rem; padding:.85rem 1.1rem; background:var(--c-bg-alt); border-bottom:1px solid var(--c-border); }
|
||||
.wbf-abo-item__icon-wrap { flex-shrink:0; width:2.4rem; height:2.4rem; border-radius:50%; background:var(--c-border); display:flex; align-items:center; justify-content:center; font-size:1.15rem; }
|
||||
.wbf-abo-item__info { flex:1; min-width:0; }
|
||||
.wbf-abo-item__name { font-weight:700; font-size:.95rem; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
||||
.wbf-abo-item__price { font-size:.8rem; color:var(--c-muted); margin-top:.1rem; }
|
||||
.wbf-abo-badge { display:inline-flex; align-items:center; gap:.3rem; font-size:.75rem; font-weight:600; padding:.22rem .65rem; border-radius:20px; white-space:nowrap; }
|
||||
.wbf-abo-badge--active { background:rgba(34,197,94,.15); color:var(--c-success); }
|
||||
.wbf-abo-badge--cancelled { background:rgba(239,68,68,.13); color:var(--c-danger); }
|
||||
.wbf-abo-badge--expired { background:rgba(100,100,100,.15); color:var(--c-muted); }
|
||||
.wbf-abo-item__body { padding:.85rem 1.1rem; }
|
||||
.wbf-abo-grid { display:grid; grid-template-columns:1fr 1fr; gap:.45rem .9rem; }
|
||||
.wbf-abo-grid__item--full { grid-column:1/-1; }
|
||||
.wbf-abo-grid__label { display:block; font-size:.78rem; color:var(--c-muted); margin-bottom:.15rem; }
|
||||
.wbf-abo-grid__value { font-size:.88rem; font-weight:500; }
|
||||
.wbf-abo-grid__value--warn { color:var(--c-danger); }
|
||||
.wbf-abo-progress { margin-top:.75rem; }
|
||||
.wbf-abo-progress__track { height:6px; background:var(--c-border); border-radius:3px; overflow:hidden; }
|
||||
.wbf-abo-progress__fill { height:100%; border-radius:3px; transition:width .4s; }
|
||||
.wbf-abo-progress__labels { display:flex; justify-content:space-between; font-size:.73rem; color:var(--c-muted); margin-top:.25rem; }
|
||||
.wbf-abo-item__foot { display:flex; align-items:center; gap:.75rem; flex-wrap:wrap; padding:.7rem 1.1rem; border-top:1px solid var(--c-border); background:var(--c-bg-alt); }
|
||||
.wbf-abo-item__foot--cancelled { background:transparent; }
|
||||
.wbf-abo-item__hint { font-size:.78rem; color:var(--c-muted); }
|
||||
.wbf-abo-notice { display:flex; align-items:flex-start; gap:.45rem; font-size:.83rem; padding:.5rem .75rem; border-radius:8px; width:100%; }
|
||||
.wbf-abo-notice--info { background:rgba(99,102,241,.1); color:var(--c-primary); }
|
||||
/* Modal */
|
||||
.wbf-abo-modal-overlay { position:fixed; inset:0; z-index:9999; display:flex; align-items:center; justify-content:center; background:rgba(0,0,0,.55); backdrop-filter:blur(3px); }
|
||||
.wbf-abo-modal { background:var(--c-bg); border:1px solid var(--c-border); border-radius:14px; width:min(420px,90vw); box-shadow:0 12px 40px rgba(0,0,0,.35); overflow:hidden; }
|
||||
.wbf-abo-modal__head { display:flex; align-items:center; gap:.5rem; padding:.9rem 1.2rem; background:var(--c-bg-alt); border-bottom:1px solid var(--c-border); font-weight:700; color:var(--c-danger); }
|
||||
.wbf-abo-modal__body { padding:1.1rem 1.2rem; line-height:1.6; }
|
||||
.wbf-abo-modal__sub { font-size:.87rem; color:var(--c-muted); margin-top:.5rem; }
|
||||
.wbf-abo-modal__foot { display:flex; justify-content:flex-end; gap:.6rem; padding:.8rem 1.2rem; background:var(--c-bg-alt); border-top:1px solid var(--c-border); }
|
||||
@media(max-width:540px) { .wbf-abo-grid { grid-template-columns:1fr; } .wbf-abo-grid__item--full { grid-column:1; } }
|
||||
</style>
|
||||
|
||||
<div class="wbf-abo-wrap">
|
||||
<?php if (!$has_any): ?>
|
||||
<div class="wbf-abo-empty">
|
||||
<div class="wbf-abo-empty__icon">📋</div>
|
||||
<p>Du hast derzeit keine aktiven Abonnements.</p>
|
||||
<a href="<?php echo $shop_url; ?>" target="_blank" class="wbf-btn wbf-btn--primary wbf-btn--sm">
|
||||
<i class="fas fa-shopping-cart"></i> Zum Shop
|
||||
</a>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
|
||||
<?php /* FLY-ABO */ if ($fly_abo):
|
||||
$fa = $fly_abo;
|
||||
$fcancelled = (int)($fa['cancelled'] ?? 0) === 1;
|
||||
$factive = !empty($fa['is_active']) && !$fcancelled;
|
||||
$fly_rem = max(0, $fly_max - $fly_used);
|
||||
$fly_pct = $fly_max > 0 ? min(100, round(($fly_used / $fly_max) * 100)) : 0;
|
||||
$pbar_col = $fly_pct >= 90 ? 'var(--c-danger)' : ($fly_pct >= 60 ? '#f59e0b' : 'var(--c-success)');
|
||||
?>
|
||||
<div class="wbf-abo-item <?php echo $fcancelled ? 'wbf-abo-item--cancelled' : 'wbf-abo-item--active'; ?>" id="wbf-abo-fly">
|
||||
<div class="wbf-abo-item__head">
|
||||
<div class="wbf-abo-item__icon-wrap">✈</div>
|
||||
<div class="wbf-abo-item__info">
|
||||
<div class="wbf-abo-item__name"><?php echo esc_html($fa['label']); ?></div>
|
||||
<div class="wbf-abo-item__price"><?php echo number_format((int)$fa['monthly_price']); ?> <?php echo $currency; ?> / Monat</div>
|
||||
</div>
|
||||
<div class="wbf-abo-item__status">
|
||||
<?php if ($fcancelled): ?>
|
||||
<span class="wbf-abo-badge wbf-abo-badge--cancelled"><i class="fas fa-clock"></i> Gekündigt</span>
|
||||
<?php elseif ($factive): ?>
|
||||
<span class="wbf-abo-badge wbf-abo-badge--active"><i class="fas fa-circle-check"></i> Aktiv</span>
|
||||
<?php else: ?>
|
||||
<span class="wbf-abo-badge wbf-abo-badge--expired"><i class="fas fa-ban"></i> Abgelaufen</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbf-abo-item__body">
|
||||
<div class="wbf-abo-grid">
|
||||
<div class="wbf-abo-grid__item">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-calendar-day"></i> Aktiv bis</span>
|
||||
<span class="wbf-abo-grid__value <?php echo $fcancelled ? 'wbf-abo-grid__value--warn' : ''; ?>"><?php echo esc_html($fa['period_end']); ?></span>
|
||||
</div>
|
||||
<?php if ($factive): ?>
|
||||
<div class="wbf-abo-grid__item">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-rotate"></i> Nächste Abbuchung</span>
|
||||
<span class="wbf-abo-grid__value"><?php echo esc_html($fa['next_billing']); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="wbf-abo-grid__item wbf-abo-grid__item--full">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-clock"></i> Fly heute</span>
|
||||
<span class="wbf-abo-grid__value">
|
||||
<?php echo self::format_seconds($fly_used); ?> / <?php echo self::format_seconds($fly_max); ?>
|
||||
<span style="color:<?php echo $fly_rem > 0 ? 'var(--c-success)' : 'var(--c-danger)'; ?>;font-weight:600">(noch <?php echo self::format_seconds($fly_rem); ?>)</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbf-abo-progress">
|
||||
<div class="wbf-abo-progress__track">
|
||||
<div class="wbf-abo-progress__fill" style="width:<?php echo $fly_pct; ?>%;background:<?php echo $pbar_col; ?>"></div>
|
||||
</div>
|
||||
<div class="wbf-abo-progress__labels"><span><?php echo $fly_pct; ?>% verbraucht</span><span>Limit: <?php echo self::format_seconds($fly_max); ?>/Tag</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if ($factive): ?>
|
||||
<div class="wbf-abo-item__foot">
|
||||
<button class="wbf-btn wbf-btn--danger wbf-btn--sm wbf-abo-cancel-btn"
|
||||
data-type="fly_abo" data-nonce="<?php echo $nonce; ?>"
|
||||
data-label="<?php echo esc_attr($fa['label']); ?>"
|
||||
data-period="<?php echo esc_attr($fa['period_end']); ?>">
|
||||
<i class="fas fa-xmark"></i> Zum Monatsende kündigen
|
||||
</button>
|
||||
<span class="wbf-abo-item__hint">Bleibt bis <?php echo esc_html($fa['period_end']); ?> aktiv</span>
|
||||
</div>
|
||||
<?php elseif ($fcancelled): ?>
|
||||
<div class="wbf-abo-item__foot wbf-abo-item__foot--cancelled">
|
||||
<div class="wbf-abo-notice wbf-abo-notice--info">
|
||||
<i class="fas fa-circle-info"></i>
|
||||
Kündigung vorgemerkt – Fly-Abo bleibt bis <strong><?php echo esc_html($fa['period_end']); ?></strong> aktiv.
|
||||
</div>
|
||||
<a href="<?php echo $shop_url; ?>" target="_blank" class="wbf-btn wbf-btn--primary wbf-btn--sm" style="white-space:nowrap">
|
||||
<i class="fas fa-rotate-right"></i> Erneut abonnieren
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; // fly_abo ?>
|
||||
|
||||
<?php /* PLOT-ABO */ if ($plot_abo):
|
||||
$pa = $plot_abo;
|
||||
$pcancelled = (int)($pa['cancelled'] ?? 0) === 1;
|
||||
$ppayfail = ($pa['cancellation_reason'] ?? '') === 'payment_failed';
|
||||
?>
|
||||
<div class="wbf-abo-item <?php echo $pcancelled ? 'wbf-abo-item--cancelled' : 'wbf-abo-item--active'; ?>" id="wbf-abo-plot">
|
||||
<div class="wbf-abo-item__head">
|
||||
<div class="wbf-abo-item__icon-wrap">📦</div>
|
||||
<div class="wbf-abo-item__info">
|
||||
<div class="wbf-abo-item__name"><?php echo esc_html($pa['label']); ?></div>
|
||||
<div class="wbf-abo-item__price">+<?php echo (int)$pa['abo_slots']; ?> Slots · <?php echo (int)$pa['monthly_price']; ?> <?php echo $currency; ?>/Monat</div>
|
||||
</div>
|
||||
<div class="wbf-abo-item__status">
|
||||
<?php if ($pcancelled && $ppayfail): ?>
|
||||
<span class="wbf-abo-badge wbf-abo-badge--cancelled"><i class="fas fa-exclamation-triangle"></i> Zahlung fehlgeschlagen</span>
|
||||
<?php elseif ($pcancelled): ?>
|
||||
<span class="wbf-abo-badge wbf-abo-badge--cancelled"><i class="fas fa-clock"></i> Gekündigt</span>
|
||||
<?php else: ?>
|
||||
<span class="wbf-abo-badge wbf-abo-badge--active"><i class="fas fa-circle-check"></i> Aktiv</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbf-abo-item__body">
|
||||
<div class="wbf-abo-grid">
|
||||
<div class="wbf-abo-grid__item">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-calendar-day"></i> Aktiv bis</span>
|
||||
<span class="wbf-abo-grid__value"><?php echo esc_html($pa['period_end']); ?></span>
|
||||
</div>
|
||||
<?php if (!$pcancelled): ?>
|
||||
<div class="wbf-abo-grid__item">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-rotate"></i> Nächste Abbuchung</span>
|
||||
<span class="wbf-abo-grid__value"><?php echo esc_html($pa['next_billing']); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!$pcancelled): ?>
|
||||
<div class="wbf-abo-item__foot">
|
||||
<button class="wbf-btn wbf-btn--danger wbf-btn--sm wbf-abo-cancel-btn"
|
||||
data-type="plot_abo" data-nonce="<?php echo $nonce; ?>"
|
||||
data-label="<?php echo esc_attr($pa['label']); ?>"
|
||||
data-period="<?php echo esc_attr($pa['period_end']); ?>">
|
||||
<i class="fas fa-xmark"></i> Zum Monatsende kündigen
|
||||
</button>
|
||||
<span class="wbf-abo-item__hint">Bleibt bis <?php echo esc_html($pa['period_end']); ?> aktiv</span>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="wbf-abo-item__foot wbf-abo-item__foot--cancelled">
|
||||
<div class="wbf-abo-notice wbf-abo-notice--info">
|
||||
<i class="fas fa-circle-info"></i>
|
||||
Kündigung vorgemerkt – Plot-Abo bleibt bis <strong><?php echo esc_html($pa['period_end']); ?></strong> aktiv.
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; // plot_abo ?>
|
||||
|
||||
<?php if ($plot_extra > 0 || $plot_abo): ?>
|
||||
<div class="wbf-abo-item wbf-abo-item--info">
|
||||
<div class="wbf-abo-item__head">
|
||||
<div class="wbf-abo-item__icon-wrap">🗺️</div>
|
||||
<div class="wbf-abo-item__info">
|
||||
<div class="wbf-abo-item__name">Plot-Slots Übersicht</div>
|
||||
<div class="wbf-abo-item__price">Citybuild</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="wbf-abo-item__body">
|
||||
<div class="wbf-abo-grid">
|
||||
<?php if ($plot_extra > 0): ?>
|
||||
<div class="wbf-abo-grid__item">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-infinity"></i> Permanent gekauft</span>
|
||||
<span class="wbf-abo-grid__value">+<?php echo $plot_extra; ?> Slots</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($plot_abo): ?>
|
||||
<div class="wbf-abo-grid__item">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-rotate"></i> Abo-Slots</span>
|
||||
<span class="wbf-abo-grid__value <?php echo $pcancelled ? 'wbf-abo-grid__value--warn' : ''; ?>">
|
||||
+<?php echo (int)$pa['abo_slots']; ?> Slots<?php echo $pcancelled ? ' (läuft aus)' : ''; ?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="wbf-abo-grid__item wbf-abo-grid__item--full" style="border-top:1px solid var(--c-border);margin-top:.4em;padding-top:.6em">
|
||||
<span class="wbf-abo-grid__label"><i class="fas fa-layer-group"></i> Gesamt Zusatz-Slots</span>
|
||||
<span class="wbf-abo-grid__value" style="color:var(--c-success);font-weight:700;font-size:1.05em">
|
||||
+<?php echo $plot_extra + ($plot_abo ? (int)$pa['abo_slots'] : 0); ?> Slots
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php endif; // has_any ?>
|
||||
</div><!-- .wbf-abo-wrap -->
|
||||
|
||||
<!-- Bestätigungs-Modal -->
|
||||
<div id="wbf-abo-modal" class="wbf-abo-modal-overlay" style="display:none" role="dialog" aria-modal="true">
|
||||
<div class="wbf-abo-modal">
|
||||
<div class="wbf-abo-modal__head"><i class="fas fa-triangle-exclamation"></i> Abo kündigen</div>
|
||||
<div class="wbf-abo-modal__body">
|
||||
<p>Möchtest du <strong id="wbf-abo-modal-label"></strong> wirklich zum Monatsende kündigen?</p>
|
||||
<p class="wbf-abo-modal__sub">Das Abo bleibt bis <strong id="wbf-abo-modal-period"></strong> aktiv. Danach werden die Vorteile automatisch deaktiviert.</p>
|
||||
</div>
|
||||
<div class="wbf-abo-modal__foot">
|
||||
<button class="wbf-btn wbf-btn--ghost wbf-btn--sm" id="wbf-abo-modal-no">Abbrechen</button>
|
||||
<button class="wbf-btn wbf-btn--danger wbf-btn--sm" id="wbf-abo-modal-yes"><i class="fas fa-xmark"></i> Ja, kündigen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var AJAX = <?php echo json_encode($ajax_url); ?>;
|
||||
var p = {type:null, nonce:null, btn:null};
|
||||
var modal = document.getElementById('wbf-abo-modal');
|
||||
var yesBtn = document.getElementById('wbf-abo-modal-yes');
|
||||
var noBtn = document.getElementById('wbf-abo-modal-no');
|
||||
|
||||
document.querySelectorAll('.wbf-abo-cancel-btn').forEach(function(b) {
|
||||
b.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
p = {type:b.dataset.type, nonce:b.dataset.nonce, btn:b};
|
||||
document.getElementById('wbf-abo-modal-label').textContent = b.dataset.label || 'dieses Abo';
|
||||
document.getElementById('wbf-abo-modal-period').textContent = b.dataset.period || '';
|
||||
modal.style.display = 'flex';
|
||||
yesBtn.disabled = false;
|
||||
yesBtn.innerHTML = '<i class="fas fa-xmark"></i> Ja, kündigen';
|
||||
});
|
||||
});
|
||||
|
||||
function closeModal() { modal.style.display = 'none'; }
|
||||
noBtn.addEventListener('click', closeModal);
|
||||
modal.addEventListener('click', function(e) { if(e.target===modal) closeModal(); });
|
||||
|
||||
yesBtn.addEventListener('click', function() {
|
||||
yesBtn.disabled = true;
|
||||
yesBtn.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Kündigen…';
|
||||
closeModal();
|
||||
|
||||
fetch(AJAX, {
|
||||
method:'POST',
|
||||
headers:{'Content-Type':'application/x-www-form-urlencoded'},
|
||||
body: new URLSearchParams({action:'wbf_cancel_abo', nonce:p.nonce, type:p.type}).toString()
|
||||
})
|
||||
.then(function(r){return r.json();})
|
||||
.then(function(res) {
|
||||
if (res.success) {
|
||||
var card = document.getElementById(p.type==='fly_abo'?'wbf-abo-fly':'wbf-abo-plot');
|
||||
if (card) {
|
||||
card.classList.replace('wbf-abo-item--active','wbf-abo-item--cancelled');
|
||||
var badge = card.querySelector('.wbf-abo-badge');
|
||||
if (badge) { badge.className='wbf-abo-badge wbf-abo-badge--cancelled'; badge.innerHTML='<i class="fas fa-clock"></i> Gekündigt'; }
|
||||
var foot = card.querySelector('.wbf-abo-item__foot');
|
||||
if (foot) {
|
||||
foot.className = 'wbf-abo-item__foot wbf-abo-item__foot--cancelled';
|
||||
foot.innerHTML = '<div class="wbf-abo-notice wbf-abo-notice--info"><i class="fas fa-circle-info"></i> Kündigung vorgemerkt – Abo bleibt bis <strong>'+(p.btn?p.btn.dataset.period:'')+'</strong> aktiv.</div>';
|
||||
}
|
||||
card.querySelectorAll('.wbf-abo-grid__item').forEach(function(row){
|
||||
if(row.textContent.includes('Abbuchung')) row.style.display='none';
|
||||
});
|
||||
}
|
||||
} else {
|
||||
alert((res.data&&res.data.message)?res.data.message:'Fehler beim Kündigen.\nAlternativ: /flyabocancel confirm ingame');
|
||||
}
|
||||
yesBtn.disabled=false;
|
||||
yesBtn.innerHTML='<i class="fas fa-xmark"></i> Ja, kündigen';
|
||||
p={type:null,nonce:null,btn:null};
|
||||
})
|
||||
.catch(function(){ alert('Verbindungsfehler. Bitte ingame kündigen.'); yesBtn.disabled=false; p={type:null,nonce:null,btn:null}; });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ class WBF_Ajax {
|
||||
'wbf_2fa_setup_verify',
|
||||
'wbf_2fa_disable',
|
||||
'wbf_2fa_verify_login',
|
||||
'wbf_cancel_abo',
|
||||
];
|
||||
foreach ($actions as $action) {
|
||||
add_action('wp_ajax_nopriv_' . $action, [__CLASS__, str_replace('wbf_','handle_',$action)]);
|
||||
@@ -1833,6 +1834,47 @@ class WBF_Ajax {
|
||||
] );
|
||||
}
|
||||
|
||||
// ── Abo kündigen ──────────────────────────────────────────────────────────
|
||||
|
||||
public static function handle_cancel_abo() {
|
||||
self::verify();
|
||||
|
||||
$current = WBF_Auth::get_current_user();
|
||||
if ( ! $current ) {
|
||||
wp_send_json_error(['message' => 'Nicht eingeloggt.']);
|
||||
return;
|
||||
}
|
||||
|
||||
$type = sanitize_key($_POST['type'] ?? '');
|
||||
if ( ! in_array($type, ['fly_abo', 'plot_abo'], true) ) {
|
||||
wp_send_json_error(['message' => 'Ungültiger Abo-Typ.']);
|
||||
return;
|
||||
}
|
||||
|
||||
// MC-Name ermitteln (Spielername = Forum-Username oder verknüpfter MC-Name)
|
||||
$mc_name = '';
|
||||
if ( class_exists('WBF_MC_Bridge') ) {
|
||||
$mc_name = WBF_MC_Bridge::get_mc_name($current->id) ?: '';
|
||||
}
|
||||
if ( empty($mc_name) ) {
|
||||
// Fallback: Forum-Username = Minecraft-Name
|
||||
$mc_name = $current->username;
|
||||
}
|
||||
|
||||
if ( ! class_exists('WBF_Abo') ) {
|
||||
wp_send_json_error(['message' => 'Abo-Modul nicht geladen.']);
|
||||
return;
|
||||
}
|
||||
|
||||
$ok = WBF_Abo::cancel_abo($mc_name, $type);
|
||||
|
||||
if ($ok) {
|
||||
wp_send_json_success(['message' => 'Abo erfolgreich gekündigt.']);
|
||||
} else {
|
||||
wp_send_json_error(['message' => 'Kein aktives Abo gefunden oder bereits gekündigt.']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
add_action( 'init', [ 'WBF_Ajax', 'init' ] );
|
||||
@@ -937,7 +937,7 @@ class WBF_Shortcodes {
|
||||
if (is_int($active_tab) && !in_array($active_tab, [1,2,3,4])) {
|
||||
$active_tab = $is_own ? 1 : 2;
|
||||
}
|
||||
if (!is_int($active_tab) && $active_tab !== $shop_tab_id && $active_tab !== 'mc' && $active_tab !== 'plugins') {
|
||||
if (!is_int($active_tab) && $active_tab !== $shop_tab_id && $active_tab !== 'mc' && $active_tab !== 'plugins' && $active_tab !== 'abos') {
|
||||
$active_tab = $is_own ? 1 : 2;
|
||||
}
|
||||
// Tab 1, 3, 4, "shop" und String-Tabs nur für eigenes Profil (außer Tab 2 = Aktivität)
|
||||
@@ -1041,6 +1041,9 @@ class WBF_Shortcodes {
|
||||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=4" class="wbf-pv-tab<?php echo $active_tab===4?' active':''; ?>"><i class="fas fa-lock"></i> Sicherheit</a>
|
||||
<?php if ($shop_active): ?>
|
||||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=shop" class="wbf-pv-tab<?php echo $active_tab==='shop'?' active':''; ?>"><i class="fas fa-shopping-cart"></i> Käufe</a>
|
||||
<?php if ($is_own): ?>
|
||||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=abos" class="wbf-pv-tab<?php echo $active_tab==='abos'?' active':''; ?>"><i class="fas fa-receipt"></i> Abonnements</a>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<a href="?forum_profile=<?php echo (int)$profile->id; ?>&ptab=mc" class="wbf-pv-tab<?php echo $active_tab==='mc'?' active':''; ?>"><i class="fas fa-plug"></i> Verbindungen</a>
|
||||
<?php if ( function_exists('vmcp_bridge_is_available') && vmcp_bridge_is_available() ) : ?>
|
||||
@@ -1280,8 +1283,24 @@ class WBF_Shortcodes {
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- ══════════════════════════════════════════════════
|
||||
TAB 1 — Profil bearbeiten + Weitere Profilangaben
|
||||
TAB ABOS — Abonnement-Verwaltung
|
||||
══════════════════════════════════════════════════ -->
|
||||
<?php if ($is_own && $active_tab === 'abos'): ?>
|
||||
<?php
|
||||
// MC-Namen ermitteln: verknüpfter Name (MC-Bridge) oder Forum-Username
|
||||
$abo_mc_name = '';
|
||||
if ($mc_enabled && class_exists('WBF_MC_Bridge')) {
|
||||
$abo_mc_name = WBF_MC_Bridge::get_mc_name($profile->id) ?: '';
|
||||
}
|
||||
if (empty($abo_mc_name)) $abo_mc_name = $profile->username;
|
||||
|
||||
if (class_exists('WBF_Abo')) {
|
||||
echo WBF_Abo::render_tab($abo_mc_name, $profile->id);
|
||||
} else {
|
||||
echo '<p class="wbf-notice">Abo-Modul nicht verfügbar.</p>';
|
||||
}
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<?php if ($is_own && $active_tab === 1): ?>
|
||||
|
||||
<!-- Profil bearbeiten -->
|
||||
|
||||
Reference in New Issue
Block a user