diff --git a/includes/class-forum-abo.php b/includes/class-forum-abo.php new file mode 100644 index 0000000..a6d76ca --- /dev/null +++ b/includes/class-forum-abo.php @@ -0,0 +1,428 @@ +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 + +
+
+
+
+ + + +
+ + + + + + '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' ] ); \ No newline at end of file diff --git a/includes/class-forum-shortcodes.php b/includes/class-forum-shortcodes.php index 6d24a45..65db46a 100644 --- a/includes/class-forum-shortcodes.php +++ b/includes/class-forum-shortcodes.php @@ -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 { Sicherheit Käufe + + Abonnements + Verbindungen @@ -1280,8 +1283,24 @@ class WBF_Shortcodes { + + 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 '

Abo-Modul nicht verfügbar.

'; + } + ?> +