Upload via Git Manager GUI

This commit is contained in:
Git Manager GUI
2026-04-30 09:33:35 +02:00
parent 30427f7bb3
commit d6ed6544db

View File

@@ -243,6 +243,18 @@ class WIS_Activator {
$wpdb->query("ALTER TABLE $table ADD COLUMN sell_price_value int(11) NOT NULL DEFAULT 80 AFTER sell_price_mode");
}
// Gift-Spalte nachrüsten (ab v6.5-gift)
$orders_table = $wpdb->prefix . 'wis_orders';
$col_gift = $wpdb->get_var("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '$orders_table' AND COLUMN_NAME = 'gift_recipient'");
if (!$col_gift) {
$wpdb->query("ALTER TABLE $orders_table ADD COLUMN gift_recipient varchar(100) DEFAULT NULL AFTER player_name");
}
// Auto-Expire Cron registrieren (7-Tage-Ablauf für unbestätigte Orders)
if (!wp_next_scheduled('wis_auto_expire_orders')) {
wp_schedule_event(time(), 'hourly', 'wis_auto_expire_orders');
}
// Sell-Log-Tabelle anlegen
$wpdb->query("CREATE TABLE IF NOT EXISTS {$wpdb->prefix}wis_sell_log (
id mediumint(9) NOT NULL AUTO_INCREMENT,
@@ -278,6 +290,7 @@ class WIS_Activator {
public static function deactivate() {
wp_clear_scheduled_hook('wis_daily_deal_event');
wp_clear_scheduled_hook('wis_abo_renewal_event');
wp_clear_scheduled_hook('wis_auto_expire_orders');
flush_rewrite_rules();
}
@@ -312,6 +325,7 @@ class WIS_Activator {
$tables[] = "CREATE TABLE {$wpdb->prefix}wis_orders (
id mediumint(9) NOT NULL AUTO_INCREMENT,
player_name varchar(100) NOT NULL,
gift_recipient varchar(100) DEFAULT NULL,
server varchar(100) NOT NULL,
item_id varchar(100) NOT NULL,
item_title varchar(255) NOT NULL,
@@ -322,6 +336,7 @@ class WIS_Activator {
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY player_name (player_name),
KEY gift_recipient (gift_recipient),
KEY status (status)
) $charset_collate;";
@@ -2717,7 +2732,10 @@ class WIS_Admin {
<table class="widefat" style="max-width:800px; margin-top:20px;">
<tr><th>ID</th><td><?php echo esc_html($order->id); ?></td></tr>
<tr><th>Datum</th><td><?php echo esc_html(date('d.m.Y H:i', strtotime($order->created_at))); ?></td></tr>
<tr><th>Spieler</th><td><strong><?php echo esc_html($order->player_name); ?></strong></td></tr>
<tr><th>Käufer</th><td><strong><?php echo esc_html($order->player_name); ?></strong></td></tr>
<?php if (!empty($order->gift_recipient)): ?>
<tr><th>🎁 Geschenk für</th><td style="color:#9b59b6; font-weight:bold;"><?php echo esc_html($order->gift_recipient); ?></td></tr>
<?php endif; ?>
<tr><th>Server</th><td><?php echo esc_html($order->server); ?></td></tr>
<tr><th>Zusammenfassung</th><td><?php echo esc_html($order->item_title); ?></td></tr>
<tr><th>Preis</th><td><?php echo esc_html($order->price); ?> <?php echo esc_html($currency); ?></td></tr>
@@ -2742,7 +2760,8 @@ class WIS_Admin {
<thead>
<tr>
<th style="width:140px;">Datum</th>
<th style="width:150px;">Spieler</th>
<th style="width:130px;">Käufer</th>
<th style="width:130px;">Empfänger</th>
<th>Inhalt</th>
<th style="width:100px;">Preis</th>
<th style="width:120px;">Status</th>
@@ -2775,6 +2794,7 @@ class WIS_Admin {
<tr>
<td><?php echo esc_html(date('d.m.Y H:i', strtotime($order->created_at))); ?></td>
<td><strong><?php echo esc_html($order->player_name); ?></strong></td>
<td><?php if (!empty($order->gift_recipient)): ?><span title="Geschenk" style="color:#9b59b6;">🎁 <?php echo esc_html($order->gift_recipient); ?></span><?php else: ?><span style="color:#aaa;"></span><?php endif; ?></td>
<td><?php echo esc_html(substr($order->item_title, 0, 50)) . (strlen($order->item_title) > 50 ? '...' : ''); ?></td>
<td><?php echo esc_html($order->price); ?> <?php echo esc_html($currency); ?></td>
<td style="color:<?php echo $status_colors[$order->status] ?? 'black'; ?>; font-weight:bold;"><?php echo $status_map[$order->status] ?? $order->status; ?></td>
@@ -3086,6 +3106,22 @@ class WIS_API {
'callback' => [self::class, 'cancel_order'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
// Gift-System Endpunkte (ab v6.5-gift)
register_rest_route('wis/v1', '/pending_gifts', [
'methods' => 'GET',
'callback' => [self::class, 'get_pending_gifts'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/gift_accept', [
'methods' => 'POST',
'callback' => [self::class, 'gift_accept'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/gift_decline', [
'methods' => 'POST',
'callback' => [self::class, 'gift_decline'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/pending_offline', [
'methods' => 'GET',
'callback' => [self::class, 'get_pending_offline'],
@@ -3327,6 +3363,9 @@ class WIS_API {
$table = $wpdb->prefix . 'wis_orders';
// Gift-Orders werden genauso wie normale Orders für Spieler A gepollt.
// Spieler A muss zuerst ingame bestätigen (Geld abbuchen), erst dann
// bekommt Spieler B die Gift-Anfrage.
$results = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table
WHERE player_name = %s AND status = 'pending'
@@ -3436,6 +3475,74 @@ class WIS_API {
return new WP_REST_Response(['success' => true]);
}
// ── Gift-System Endpoints ─────────────────────────────────────────────
/**
* GET /wis/v1/pending_gifts?recipient={player}
* Gibt ausstehende Geschenk-Orders zurück, die an diesen Empfänger gerichtet sind.
*/
public static function get_pending_gifts($request) {
global $wpdb;
$recipient = sanitize_text_field($request->get_param('recipient'));
if (!$recipient) {
return new WP_REST_Response(['orders' => []]);
}
$table = $wpdb->prefix . 'wis_orders';
// Status NICHT auf 'claimed' setzen bleibt 'pending' bis der Empfänger
// ingame annimmt (gift_accept) oder ablehnt (gift_decline).
// Das Spigot-Plugin prüft pendingGiftRequests intern gegen Duplikate.
$results = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table
WHERE gift_recipient = %s AND status IN ('pending', 'processing')
ORDER BY created_at ASC LIMIT 1",
$recipient
));
return new WP_REST_Response(['orders' => $results]);
}
/**
* POST /wis/v1/gift_accept { "id": 123 }
* Wird aufgerufen wenn Empfänger das Geschenk annimmt.
* Setzt Status auf 'processing' der Spigot-Server liefert dann die Ware aus.
*/
public static function gift_accept($request) {
global $wpdb;
$data = $request->get_json_params();
$id = intval($data['id'] ?? 0);
if (!$id) return new WP_REST_Response(['success' => false], 400);
$wpdb->update(
$wpdb->prefix . 'wis_orders',
['status' => 'processing'],
['id' => $id]
);
return new WP_REST_Response(['success' => true]);
}
/**
* POST /wis/v1/gift_decline { "id": 123, "sender": "SpielerA", "price": 500 }
* Empfänger lehnt ab → Order stornieren.
* Rückerstattung erfolgt auf Spigot-Seite via Vault direkt.
*/
public static function gift_decline($request) {
global $wpdb;
$data = $request->get_json_params();
$id = intval($data['id'] ?? 0);
if (!$id) return new WP_REST_Response(['success' => false], 400);
$wpdb->update(
$wpdb->prefix . 'wis_orders',
['status' => 'cancelled'],
['id' => $id]
);
return new WP_REST_Response(['success' => true]);
}
public static function import_json($request) {
$data = $request->get_json_params();
@@ -3494,14 +3601,21 @@ class WIS_API {
global $wpdb;
$data = $request->get_json_params();
$player = sanitize_text_field($data['player'] ?? '');
$cart = $data['cart'] ?? [];
$server = sanitize_text_field($data['server'] ?? '');
$player = sanitize_text_field($data['player'] ?? '');
$cart = $data['cart'] ?? [];
$server = sanitize_text_field($data['server'] ?? '');
$coupon_code = isset($data['coupon_code']) ? sanitize_text_field(strtoupper($data['coupon_code'])) : '';
// Gift: optionaler Empfänger-Spielername
$gift_recipient = isset($data['gift_recipient'])
? sanitize_text_field(trim($data['gift_recipient'])) : '';
if (!$player || empty($cart) || !$server) {
return new WP_REST_Response(['success' => false, 'message' => 'Fehlende Daten'], 400);
}
// Gift-Validierung: Spieler kann sich nicht selbst beschenken
if ($gift_recipient !== '' && strcasecmp($gift_recipient, $player) === 0) {
return new WP_REST_Response(['success' => false, 'message' => 'Selbst-Geschenk nicht erlaubt'], 400);
}
$exclude_offers = get_option('wis_coupon_exclude_offers', '0');
$currency = get_option('wis_currency_name', 'Coins');
@@ -3702,14 +3816,15 @@ class WIS_API {
];
WIS_DB::insert_order([
'player_name' => $player,
'server' => $server,
'item_id' => 'cart',
'item_title' => $title,
'price' => $final_price,
'quantity' => count($valid_cart),
'status' => 'pending',
'response' => json_encode($payload)
'player_name' => $player,
'gift_recipient' => $gift_recipient !== '' ? $gift_recipient : null,
'server' => $server,
'item_id' => 'cart',
'item_title' => $title,
'price' => $final_price,
'quantity' => count($valid_cart),
'status' => 'pending',
'response' => json_encode($payload)
]);
// Fly-Abo Abonnements registrieren / verlängern
@@ -3758,7 +3873,9 @@ class WIS_API {
}
}
$msg = '✅ Bestellung erfolgreich!';
$msg = $gift_recipient !== ''
? "🎁 Geschenk-Bestellung für {$gift_recipient} erfolgreich!"
: '✅ Bestellung erfolgreich!';
if ($coupon_msg) $msg .= ' (' . $coupon_msg . ')';
return new WP_REST_Response(['success' => true, 'message' => $msg]);
@@ -3900,6 +4017,12 @@ class WIS_Shortcode {
.wis-coupon-input { flex-grow: 1; padding: 10px; border: 1px solid #ddd; border-radius: 6px; }
.wis-coupon-btn { padding: 10px 15px; background: #6f42c1; color: white; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; }
.wis-coupon-msg { font-size: 0.85rem; color: #e67e22; margin-top: 5px; min-height: 20px; }
.wis-gift-toggle { display: flex; align-items: center; gap: 10px; margin-bottom: 15px; cursor: pointer; font-weight: 600; color: #6f42c1; user-select: none; }
.wis-gift-toggle input[type=checkbox] { width: 18px; height: 18px; cursor: pointer; accent-color: #9b59b6; }
.wis-gift-field { display: none; background: #f3eeff; border: 1px solid #c39bd3; border-radius: 8px; padding: 14px 16px; margin-bottom: 15px; }
.wis-gift-field label { display: block; font-weight: 600; color: #6f42c1; margin-bottom: 6px; font-size: 0.9rem; }
.wis-gift-input { width: 100%; padding: 10px 14px; border: 1px solid #c39bd3; border-radius: 6px; font-size: 1rem; box-sizing: border-box; background: #fff; }
.wis-gift-hint { font-size: 0.8rem; color: #888; margin-top: 6px; }
.wis-alert { margin-top: 15px; padding: 12px; border-radius: 5px; display: none; }
.wis-alert.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
.wis-alert.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
@@ -3993,6 +4116,17 @@ class WIS_Shortcode {
<input type="text" id="checkout-player" class="wis-modal-input" placeholder="Dein Spielername">
<!-- Gift-System -->
<label class="wis-gift-toggle">
<input type="checkbox" id="wis-gift-toggle">
🎁 Als Geschenk für einen anderen Spieler kaufen
</label>
<div class="wis-gift-field" id="wis-gift-field">
<label for="wis-gift-recipient">Empfänger-Spielername</label>
<input type="text" id="wis-gift-recipient" class="wis-gift-input" placeholder="z.B. Steve123" autocomplete="off">
<div class="wis-gift-hint">⚠️ Der Empfänger muss das Geschenk ingame annehmen. Bei Ablehnung erhältst du dein Geld zurück.</div>
</div>
<div class="wis-modal-actions">
<button class="wis-modal-btn wis-btn-confirm" id="wis-checkout-btn">💰 Kauf abschließen</button>
<button class="wis-modal-btn wis-btn-cancel" id="wis-close-cart-btn">Abbrechen</button>
@@ -4131,6 +4265,18 @@ class WIS_Shortcode {
// ---- Kauf abschließen ----
var checkoutBtn = document.getElementById('wis-checkout-btn');
if (checkoutBtn) checkoutBtn.addEventListener('click', checkout);
// ---- Gift-Toggle ----
var giftToggle = document.getElementById('wis-gift-toggle');
var giftField = document.getElementById('wis-gift-field');
if (giftToggle && giftField) {
giftToggle.addEventListener('change', function() {
giftField.style.display = giftToggle.checked ? 'block' : 'none';
if (!giftToggle.checked) {
document.getElementById('wis-gift-recipient').value = '';
}
});
}
}
if (document.readyState === 'loading') {
@@ -4344,6 +4490,11 @@ class WIS_Shortcode {
if (cart.length === 0) {
content.innerHTML = '<div style="text-align:center;padding:40px;color:#999;">Dein Warenkorb ist leer</div>';
checkout.style.display = 'none';
// Gift-Feld zurücksetzen wenn Warenkorb leer
var gt = document.getElementById('wis-gift-toggle');
var gf = document.getElementById('wis-gift-field');
if (gt) gt.checked = false;
if (gf) gf.style.display = 'none';
return;
}
content.innerHTML = cart.map(function(item, idx) {
@@ -4416,19 +4567,41 @@ class WIS_Shortcode {
var alertEl = document.getElementById('cart-alert');
var btn = document.getElementById('wis-checkout-btn');
// Gift-Feld auslesen
var giftToggle = document.getElementById('wis-gift-toggle');
var giftRecipient = '';
if (giftToggle && giftToggle.checked) {
giftRecipient = (document.getElementById('wis-gift-recipient').value || '').trim();
}
if (!player) { alertEl.textContent = 'Bitte Spielername eingeben!'; alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return; }
if (!server) { alertEl.textContent = 'Bitte Server auswählen!'; alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return; }
// Gift-Validierungen im Frontend
if (giftToggle && giftToggle.checked) {
if (!giftRecipient) {
alertEl.textContent = '🎁 Bitte den Empfänger-Spielernamen eingeben!';
alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return;
}
if (giftRecipient.toLowerCase() === player.toLowerCase()) {
alertEl.textContent = '🎁 Du kannst dir nicht selbst etwas schenken!';
alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return;
}
}
var invalid = cart.filter(function(i){ return i.servers.indexOf(server) === -1; });
if (invalid.length) { alertEl.textContent = 'Einige Items sind nicht für diesen Server!'; alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return; }
btn.disabled = true;
btn.textContent = '⏳ Speichere…';
var payload = {player: player, cart: cart, server: server, coupon_code: couponCode};
if (giftRecipient) payload.gift_recipient = giftRecipient;
fetch(apiBase + '/order', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({player: player, cart: cart, server: server, coupon_code: couponCode})
body: JSON.stringify(payload)
})
.then(function(r){ return r.json(); })
.then(function(data) {
@@ -4437,6 +4610,11 @@ class WIS_Shortcode {
alertEl.className = 'wis-alert success';
alertEl.style.display = 'block';
cart = []; couponData = {};
// Gift-Feld zurücksetzen
if (giftToggle) { giftToggle.checked = false; }
var giftField = document.getElementById('wis-gift-field');
if (giftField) giftField.style.display = 'none';
document.getElementById('wis-gift-recipient').value = '';
updateCartBadge();
setTimeout(function(){ closeCart(); location.reload(); }, 2000);
} else {
@@ -4579,4 +4757,22 @@ add_action('widgets_init', function() {
register_widget('WIS_Sidebar_Widget');
});
add_action('wis_daily_deal_event', [WIS_Activator::class, 'run_daily_deal']);
add_action('wis_abo_renewal_event', [WIS_Activator::class, 'run_abo_renewal']);
add_action('wis_abo_renewal_event', [WIS_Activator::class, 'run_abo_renewal']);
// ── Auto-Expire: Orders nach 7 Tagen ohne Ingame-Bestätigung stornieren ──
add_action('wis_auto_expire_orders', function () {
global $wpdb;
$table = $wpdb->prefix . 'wis_orders';
// Alle Orders die seit > 7 Tagen pending/claimed sind → cancelled
$affected = $wpdb->query(
"UPDATE {$table}
SET status = 'cancelled'
WHERE status IN ('pending', 'claimed')
AND created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)"
);
if ($affected > 0) {
error_log("[WIS] Auto-Expire: {$affected} Order(s) nach 7 Tagen storniert.");
}
});