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(); ?>
📋

Du hast derzeit keine aktiven Abonnements.

Zum Shop
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)'); ?>
/ Monat
Gekündigt Aktiv Abgelaufen
Aktiv bis
Nächste Abbuchung
Fly heute /  (noch )
% verbrauchtLimit: /Tag
Bleibt bis aktiv
Kündigung vorgemerkt – Fly-Abo bleibt bis aktiv.
Erneut abonnieren
📦
+ Slots · /Monat
Zahlung fehlgeschlagen Gekündigt Aktiv
Aktiv bis
Nächste Abbuchung
Bleibt bis aktiv
Kündigung vorgemerkt – Plot-Abo bleibt bis aktiv.
0 || $plot_abo): ?>
🗺️
Plot-Slots Übersicht
Citybuild
0): ?>
Permanent gekauft + Slots
Abo-Slots + Slots
Gesamt Zusatz-Slots + Slots