'Cache erfolgreich geleert!']);
}
// Prüfe auf Updates (läuft im Admin-Hintergrund)
public static function check_for_update() {
$update_data = get_transient(self::$transient_name);
if (false === $update_data) {
$response = wp_remote_get(self::$api_url, ['timeout' => 10]);
if (is_wp_error($response)) {
return; // Fehler beim Abrufen, nichts tun
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body);
if (isset($data->tag_name) && isset($data->html_url)) {
// Entferne 'v' vom Tag (z.B. v2.1.3 -> 2.1.3)
$remote_version = ltrim($data->tag_name, 'v');
$update_data = [
'new_version' => $remote_version,
'url' => self::$update_url,
'package_url' => isset($data->assets[0]->browser_download_url) ? $data->assets[0]->browser_download_url : '',
'changelog' => isset($data->body) ? substr($data->body, 0, 200) . '...' : ''
];
// Speichere für 12 Stunden
set_transient(self::$transient_name, $update_data, 12 * HOUR_IN_SECONDS);
}
}
}
// Zeige Admin Notice wenn Update verfügbar
public static function show_update_notice() {
$update_data = get_transient(self::$transient_name);
if ($update_data && version_compare(WIS_VERSION, $update_data['new_version'], '<')) {
?>
🚀 WP Ingame Shop Pro Update verfügbar!
Neue Version: (Du hast ) Hier im Git Repository ansehen oder unten im Widget Details prüfen.
$wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wis_items WHERE status = 'publish'"),
'orders' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wis_orders WHERE status = 'completed'"),
'pending' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wis_orders WHERE status IN ('pending', 'claimed')"),
'revenue' => $wpdb->get_var("SELECT SUM(price) FROM {$wpdb->prefix}wis_orders WHERE status = 'completed'"),
];
$currency = get_option('wis_currency_name', 'Coins');
// Update Status bestimmen
$update_html = '✅ Aktuell (v' . WIS_VERSION . ')';
if ($update_data && version_compare(WIS_VERSION, $update_data['new_version'], '<')) {
$update_html = '⚠️ Update verfügbar!';
}
?>
Generiere eine JSON-Datei mit allen deinen Items für Gitea.
⚡ Quick-Import von Gitea
Importiert direkt von deinem Gitea Repository!
📥 JSON Import (Manuelle URL)
Importiere Items aus einer beliebigen JSON-URL.
✅ Shop wurde komplett zurückgesetzt!
';
}
?>
🔄 Shop Reset
⚠️ WARNUNG
Diese Aktion löscht ALLE Daten:
❌ Alle Items
❌ Alle Bestellungen
❌ Alle Gutscheine
❌ Alle Server
❌ Alle Kategorien
Diese Aktion kann NICHT rückgängig gemacht werden!
get_results("
SELECT player_name, SUM(price) as total_spent, COUNT(*) as order_count
FROM {$wpdb->prefix}wis_orders
WHERE status = 'completed'
GROUP BY player_name
ORDER BY total_spent DESC
LIMIT 50
");
?>
🏆 Top Spender
Spieler mit den höchsten Gesamtausgaben
Rang
Spieler
Ausgegeben
Bestellungen
Noch keine Statistiken vorhanden.
#
player_name); ?>
total_spent)); ?>
order_count); ?>
'POST',
'callback' => [self::class, 'import_json'],
'permission_callback' => '__return_true',
]);
register_rest_route('wis/v1', '/order', [
'methods' => 'POST',
'callback' => [self::class, 'create_order'],
'permission_callback' => '__return_true',
]);
register_rest_route('wis/v1', '/validate_coupon', [
'methods' => 'POST',
'callback' => [self::class, 'validate_coupon'],
'permission_callback' => '__return_true',
]);
register_rest_route('wis/v1', '/shop_items', [
'methods' => 'GET',
'callback' => [self::class, 'get_shop_items'],
'permission_callback' => '__return_true',
]);
register_rest_route('wis/v1', '/pending_orders', [
'methods' => 'GET',
'callback' => [self::class, 'get_pending_orders'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/execute_order', [
'methods' => 'POST',
'callback' => [self::class, 'execute_order'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/complete_order', [
'methods' => 'POST',
'callback' => [self::class, 'complete_order'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/cancel_order', [
'methods' => 'POST',
'callback' => [self::class, 'cancel_order'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/pending_offline', [
'methods' => 'GET',
'callback' => [self::class, 'get_pending_offline'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
register_rest_route('wis/v1', '/orders_history', [
'methods' => 'GET',
'callback' => [self::class, 'get_orders_history'],
'permission_callback' => [WIS_Activator::class, 'spigot_permission'],
]);
}
public static function get_shop_items($request) {
$page = max(1, intval($request->get_param('page') ?? 1));
$per_page = 24;
$category = sanitize_text_field($request->get_param('category') ?? '');
$search = sanitize_text_field($request->get_param('search') ?? '');
global $wpdb;
$table = $wpdb->prefix . 'wis_items';
$where_parts = ["status = 'publish'"];
if (!empty($category)) {
$search_pattern = '%"' . $category . '"%';
$where_parts[] = $wpdb->prepare("categories LIKE %s", $search_pattern);
}
if (!empty($search)) {
$search_like = '%' . $wpdb->esc_like($search) . '%';
$where_parts[] = $wpdb->prepare("(name LIKE %s OR item_id LIKE %s)", $search_like, $search_like);
}
$where_sql = implode(" AND ", $where_parts);
$total = (int) $wpdb->get_var("SELECT COUNT(*) FROM $table WHERE $where_sql");
$offset = ($page - 1) * $per_page;
$items = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table WHERE $where_sql ORDER BY name ASC LIMIT %d OFFSET %d",
$per_page, $offset
));
$img_base = get_option('wis_image_base_url', '');
$currency = get_option('wis_currency_name', 'Coins');
$result = [];
foreach ($items as $item) {
$img_name = str_replace(':', '_', $item->item_id) . '.png';
$result[] = [
'id' => $item->id,
'item_id' => $item->item_id,
'name' => $item->name,
'description' => $item->description,
'price' => intval($item->price),
'offer_price' => intval($item->offer_price),
'is_offer' => (bool) $item->is_offer,
'is_daily_deal' => (bool) $item->is_daily_deal,
'servers' => json_decode($item->servers, true) ?: [],
'categories' => json_decode($item->categories, true) ?: [],
'image' => $img_base . $img_name,
];
}
return new WP_REST_Response([
'items' => $result,
'total' => $total,
'page' => $page,
'per_page' => $per_page,
'total_pages' => max(1, (int) ceil($total / $per_page)),
'currency' => $currency,
]);
}
public static function get_pending_orders($request) {
global $wpdb;
$player = sanitize_text_field($request->get_param('player'));
if (!$player) {
return new WP_REST_Response(['orders' => []]);
}
$table = $wpdb->prefix . 'wis_orders';
$results = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table
WHERE player_name = %s AND status = 'pending'
ORDER BY created_at ASC LIMIT 5",
$player
));
if (!empty($results)) {
$ids = implode(',', array_map(fn($o) => intval($o->id), $results));
$wpdb->query("UPDATE $table SET status = 'claimed' WHERE id IN ($ids) AND status = 'pending'");
}
return new WP_REST_Response(['orders' => $results]);
}
public static function get_pending_offline($request) {
if (get_option('wis_offline_queue_enabled', '0') !== '1') {
return new WP_REST_Response(['orders' => [], 'message' => 'Offline-Queue deaktiviert']);
}
global $wpdb;
$player = sanitize_text_field($request->get_param('player'));
if (!$player) {
return new WP_REST_Response(['orders' => []]);
}
$table = $wpdb->prefix . 'wis_orders';
$results = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table
WHERE player_name = %s AND status = 'pending'
ORDER BY created_at ASC LIMIT 10",
$player
));
if (!empty($results)) {
$ids = implode(',', array_map(fn($o) => intval($o->id), $results));
$wpdb->query("UPDATE $table SET status = 'claimed' WHERE id IN ($ids) AND status = 'pending'");
}
return new WP_REST_Response(['orders' => $results]);
}
public static function get_orders_history($request) {
global $wpdb;
$player = sanitize_text_field($request->get_param('player'));
if (!$player) {
return new WP_REST_Response(['orders' => []]);
}
$results = $wpdb->get_results($wpdb->prepare(
"SELECT id, item_title, price, status, created_at
FROM {$wpdb->prefix}wis_orders
WHERE player_name = %s
ORDER BY created_at DESC LIMIT 10",
$player
));
return new WP_REST_Response(['orders' => $results]);
}
public static function execute_order($request) {
global $wpdb;
$data = $request->get_json_params();
$id = intval($data['id'] ?? 0);
if (!$id) return new WP_REST_Response(['success' => false], 400);
$wpdb->query($wpdb->prepare(
"UPDATE {$wpdb->prefix}wis_orders SET status = 'processing'
WHERE id = %d AND status IN ('pending','claimed')",
$id
));
return new WP_REST_Response(['success' => true]);
}
public static function complete_order($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' => 'completed'],
['id' => $id]
);
return new WP_REST_Response(['success' => true]);
}
public static function cancel_order($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();
$url = esc_url_raw($data['url'] ?? '');
if (!$url) {
return new WP_REST_Response(['success' => false, 'message' => 'Keine URL angegeben'], 400);
}
$response = wp_remote_get($url, ['timeout' => 30]);
if (is_wp_error($response)) {
return new WP_REST_Response(['success' => false, 'message' => $response->get_error_message()], 400);
}
$body = wp_remote_retrieve_body($response);
$json = json_decode($body, true);
if (!isset($json['items']) || !is_array($json['items'])) {
return new WP_REST_Response(['success' => false, 'message' => 'Ungültiges JSON Format'], 400);
}
$imported = 0;
$skipped = 0;
foreach ($json['items'] as $item) {
$item_id = sanitize_text_field($item['id'] ?? '');
$name = sanitize_text_field($item['name'] ?? 'Unbekannt');
if (empty($item_id)) continue;
$exists = WIS_DB::get_item_by_item_id($item_id);
if ($exists) {
$skipped++;
continue;
}
WIS_DB::insert_item([
'item_id' => $item_id,
'name' => $name,
'description' => sanitize_textarea_field($item['description'] ?? ''),
'price' => intval($item['price'] ?? 0),
'status' => intval($item['price'] ?? 0) > 0 ? 'publish' : 'draft',
'servers' => '[]',
'categories' => '[]'
]);
$imported++;
}
return new WP_REST_Response(['success' => true, 'imported' => $imported, 'skipped' => $skipped]);
}
public static function create_order($request) {
global $wpdb;
$data = $request->get_json_params();
$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'])) : '';
if (!$player || empty($cart) || !$server) {
return new WP_REST_Response(['success' => false, 'message' => 'Fehlende Daten'], 400);
}
$exclude_offers = get_option('wis_coupon_exclude_offers', '0');
$currency = get_option('wis_currency_name', 'Coins');
$valid_cart = [];
$total_normal = 0;
$total_offer = 0;
foreach ($cart as $item_data) {
$item = WIS_DB::get_item(intval($item_data['id'] ?? 0));
if (!$item || $item->status !== 'publish') continue;
$qty = intval($item_data['quantity'] ?? 1);
if ($qty <= 0) continue;
$servers = json_decode($item->servers, true);
if (!in_array($server, $servers ?: [])) continue;
$price = $item->offer_price > 0 ? $item->offer_price : $item->price;
$valid_cart[] = [
'id' => $item->item_id,
'title' => $item->name,
'price' => $price,
'qty' => $qty,
'is_offer' => $item->is_offer
];
$item_total = $price * $qty;
if ($item->is_offer && $exclude_offers === '1') {
$total_offer += $item_total;
} else {
$total_normal += $item_total;
}
}
if (empty($valid_cart)) {
return new WP_REST_Response(['success' => false, 'message' => 'Keine gültigen Items'], 400);
}
$coupon_discount = 0;
$coupon_msg = '';
$coupon_applied = false;
if (!empty($coupon_code)) {
$coupon = WIS_DB::get_coupon_by_code($coupon_code);
if ($coupon) {
if ($coupon->expiry && date('Y-m-d') > $coupon->expiry) {
$coupon_msg = 'Gutschein abgelaufen';
} elseif ($coupon->used_count >= $coupon->usage_limit) {
$coupon_msg = 'Gutschein bereits aufgebraucht';
} else {
if ($exclude_offers === '1' && $total_normal <= 0) {
$coupon_msg = 'Gutschein gilt nicht für Angebote';
} else {
if ($coupon->type === 'percent') {
$coupon_discount = floor($total_normal * ($coupon->value / 100));
} else {
$coupon_discount = $coupon->value;
}
WIS_DB::update_coupon($coupon->id, ['used_count' => $coupon->used_count + 1]);
$coupon_applied = true;
$coupon_msg = "Gutschein eingelöst: -{$coupon_discount} {$currency}";
}
}
} else {
$coupon_msg = 'Ungültiger Code';
}
}
$final_price = max(0, $total_normal - $coupon_discount) + $total_offer;
$items_payload = [];
$title_parts = [];
foreach ($valid_cart as $item) {
$items_payload[] = [
'id' => $item['id'],
'amount' => $item['qty']
];
$title_parts[] = $item['qty'] . 'x ' . $item['title'];
}
$title = "Warenkorb: " . implode(', ', $title_parts);
if (strlen($title) > 240) $title = substr($title, 0, 237) . '...';
$payload = [
'items' => $items_payload,
'coupon' => $coupon_applied ? ['code' => $coupon_code, 'discount' => $coupon_discount] : []
];
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)
]);
$msg = '✅ Bestellung erfolgreich!';
if ($coupon_msg) $msg .= ' (' . $coupon_msg . ')';
return new WP_REST_Response(['success' => true, 'message' => $msg]);
}
public static function validate_coupon($request) {
$data = $request->get_json_params();
$code = sanitize_text_field(strtoupper($data['code'] ?? ''));
$cart = $data['cart'] ?? [];
if (!$code) {
return new WP_REST_Response(['success' => false, 'message' => 'Kein Code']);
}
$coupon = WIS_DB::get_coupon_by_code($code);
if (!$coupon) {
return new WP_REST_Response(['success' => false, 'message' => 'Gutschein nicht gefunden']);
}
if ($coupon->expiry && date('Y-m-d') > $coupon->expiry) {
return new WP_REST_Response(['success' => false, 'message' => 'Gutschein abgelaufen']);
}
if ($coupon->used_count >= $coupon->usage_limit) {
return new WP_REST_Response(['success' => false, 'message' => 'Bereits aufgebraucht']);
}
$exclude_offers = get_option('wis_coupon_exclude_offers', '0');
if ($exclude_offers === '1' && !empty($cart)) {
$has_normal = false;
foreach ($cart as $item_data) {
$item = WIS_DB::get_item(intval($item_data['id'] ?? 0));
if ($item && !$item->is_offer) {
$has_normal = true;
break;
}
}
if (!$has_normal) {
return new WP_REST_Response(['success' => false, 'message' => 'Gutschein gilt nicht für Angebote']);
}
}
$currency = get_option('wis_currency_name', 'Coins');
$msg = $coupon->type === 'percent'
? "Gutschein gültig (-{$coupon->value}%)"
: "Gutschein gültig (-{$coupon->value} {$currency})";
return new WP_REST_Response([
'success' => true,
'type' => $coupon->type,
'value' => $coupon->value,
'message' => $msg
]);
}
}
// ===========================================================
// SHORTCODE - FRONTEND SHOP
// ===========================================================
class WIS_Shortcode {
public static function register() {
add_shortcode('ingame_shop_form', [self::class, 'render']);
}
public static function render() {
$servers = WIS_DB::get_servers();
$categories = WIS_DB::get_categories();
$currency = get_option('wis_currency_name', 'Coins');
$header_text = get_option('wis_header_text', '');
$exclude_offers = get_option('wis_coupon_exclude_offers', '0');
$first_category = !empty($categories) ? $categories[0]->slug : '';
ob_start();
?>
🛒 Ingame Shop
Lade Items…
🛒 Dein Warenkorb
Dein Warenkorb ist leer
Gesamt:0
'Zeigt Daily Deal oder Angebot an']
);
}
public function widget($args, $instance) {
echo $args['before_widget'];
if (!empty($instance['title'])) {
echo $args['before_title'] . apply_filters('widget_title', $instance['title']) . $args['after_title'];
}
global $wpdb;
$currency = get_option('wis_currency_name', 'Coins');
$img_base = get_option('wis_image_base_url', '');
$item = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}wis_items WHERE is_daily_deal = 1 AND status = 'publish' LIMIT 1");
if (!$item) {
$item = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}wis_items WHERE is_offer = 1 AND status = 'publish' ORDER BY updated_at DESC LIMIT 1");
}
if ($item) {
$price = $item->offer_price > 0 ? $item->offer_price : $item->price;
$show_old = $item->offer_price > 0 && $item->offer_price != $item->price;
$img_name = str_replace(':', '_', $item->item_id) . '.png';
$img_url = $img_base . $img_name;
$target_url = !empty($instance['shop_url']) ? $instance['shop_url'] : home_url();
?>