diff --git a/wp-ingame-shop/wp-ingame-shop.php b/wp-ingame-shop/wp-ingame-shop.php new file mode 100644 index 0000000..4bf46cb --- /dev/null +++ b/wp-ingame-shop/wp-ingame-shop.php @@ -0,0 +1,1619 @@ +prefix . 'wis_orders'; + $coupon_table_name = $wpdb->prefix . 'wis_coupons'; + $charset_collate = $wpdb->get_charset_collate(); + + $sql = "CREATE TABLE $table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + player_name varchar(100) NOT NULL, + server varchar(100) NOT NULL, + item_id varchar(100) NOT NULL, + item_title varchar(255) NOT NULL, + price int(11) NOT NULL, + quantity int(11) DEFAULT 1, + status varchar(20) DEFAULT 'pending', + response text, + created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id) + ) $charset_collate;"; + + $sql2 = "CREATE TABLE $coupon_table_name ( + id mediumint(9) NOT NULL AUTO_INCREMENT, + code varchar(50) NOT NULL, + value int(11) NOT NULL, + type varchar(10) DEFAULT 'fixed', + usage_limit int(11) DEFAULT 1, + used_count int(11) DEFAULT 0, + expiry date DEFAULT NULL, + created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, + PRIMARY KEY (id) + ) $charset_collate;"; + + require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); + dbDelta($sql); + dbDelta($sql2); + + // Alte Installationen updaten (type Spalte hinzufügen) + $existing_columns = $wpdb->get_col_info("SELECT * FROM $coupon_table_name LIMIT 1"); + if(!in_array('type', $existing_columns)) { + $wpdb->query("ALTER TABLE $coupon_table_name ADD COLUMN type varchar(10) DEFAULT 'fixed'"); + } + } + + public static function setup_daily_deal() { + // Initial setup beim ersten Aktivieren + } + + public static function run_daily_deal() { + if(get_option('wis_daily_deal_enabled') === '0') return; + + global $wpdb; + $discount_percent = intval(get_option('wis_daily_deal_discount', 20)); + + // 1. Aktuellen Daily Deal deaktivieren + $wpdb->update( + $wpdb->prefix.'postmeta', + ['meta_value' => 0], + ['meta_key' => '_wis_daily_deal', 'meta_value' => 1] + ); + + // 2. Zufälliges Item auswählen + $args = [ + 'post_type' => 'wis_item', + 'post_status' => 'publish', + 'posts_per_page' => 1, + 'meta_query' => [ + 'relation' => 'AND', + ['key' => '_wis_price', 'value' => 0, 'compare' => '>'], + ['key' => '_wis_daily_deal', 'compare' => 'NOT EXISTS'] // Eines holen, das noch kein Daily Deal ist + ] + ]; + $items = get_posts($args); + + if(!empty($items)) { + $item_id = $items[0]->ID; + $price = intval(get_post_meta($item_id, '_wis_price', true)); + + // Rabatt berechnen + $offer_price = max(0, floor($price - ($price * ($discount_percent / 100)))); + + // Flags setzen + update_post_meta($item_id, '_wis_daily_deal', 1); + update_post_meta($item_id, '_wis_is_offer', 1); + update_post_meta($item_id, '_wis_offer_price', $offer_price); + } + } +} + +// =========================================================== +// 2. ADMIN & CPT +// =========================================================== +class WIS_CPT { + public static function register_post_types() { + register_post_type('wis_item', [ + 'labels' => ['name' => 'Shop Items', 'singular_name' => 'Shop Item'], + 'public' => false, + 'show_ui' => true, + 'show_in_menu' => false, + 'show_in_admin_all_list' => true, + 'capability_type' => 'post', + 'capabilities' => [ + 'edit_post' => 'manage_options', + 'read_post' => 'manage_options', + 'delete_post' => 'manage_options', + 'edit_posts' => 'manage_options', + 'delete_posts' => 'manage_options', + 'delete_others_posts' => 'manage_options' + ], + 'supports' => ['title', 'editor'], + 'taxonomies' => ['wis_category'] + ]); + register_post_type('wis_server', [ + 'labels' => ['name' => 'Servers', 'singular_name' => 'Server'], + 'public' => false, + 'show_ui' => true, + 'show_in_menu' => false, + 'capability_type' => 'post', + 'supports' => ['title'] + ]); + register_post_type('wis_coupon', [ + 'labels' => ['name' => 'Gutscheine', 'singular_name' => 'Gutschein'], + 'public' => false, + 'show_ui' => true, + 'show_in_menu' => false, + 'capability_type' => 'post', + 'supports' => ['title'] + ]); + + // NEU: Kategorien Taxonomie + $labels = [ + 'name' => 'Kategorien', + 'singular_name' => 'Kategorie', + 'search_items' => 'Kategorien suchen', + 'all_items' => 'Alle Kategorien', + 'parent_item' => 'Übergeordnete Kategorie', + 'edit_item' => 'Kategorie bearbeiten', + 'update_item' => 'Kategorie aktualisieren', + 'add_new_item' => 'Neue Kategorie', + 'new_item_name' => 'Kategorie Name', + 'menu_name' => 'Kategorien', + 'popular_items' => 'Beliebte Kategorien', + 'separate_items_with_commas' => "Kategorien mit Kommas trennen", + 'add_or_remove_items' => 'Kategorien hinzufügen oder entfernen', + 'choose_from_most_used' => 'Häufigste Kategorien auswählen', + 'not_found' => 'Keine Kategorien gefunden' + ]; + $args = [ + 'hierarchical' => true, + 'labels' => $labels, + 'show_ui' => true, + 'show_in_menu' => true, // Erscheint als Menüpunkt + 'show_in_nav_menus' => false, + 'show_admin_column' => true, + 'public' => false, + 'rewrite' => false, + ]; + register_taxonomy('wis_category', 'wis_item', $args); + } + + public static function add_meta_boxes() { + add_meta_box('wis_item_meta', 'Item Einstellungen', [self::class, 'render_item_meta'], 'wis_item', 'normal', 'high'); + add_meta_box('wis_server_meta', 'Server Einstellungen', [self::class, 'render_server_meta'], 'wis_server', 'normal', 'high'); + add_meta_box('wis_coupon_meta', 'Gutschein Einstellungen', [self::class, 'render_coupon_meta'], 'wis_coupon', 'normal', 'high'); + } + + public static function render_item_meta($post) { + wp_nonce_field('wis_save_item', 'wis_item_nonce'); + $price = get_post_meta($post->ID,'_wis_price',true); + $item_id = get_post_meta($post->ID,'_wis_item_id',true); + $servers = get_post_meta($post->ID,'_wis_servers',true); + if(!is_array($servers)) $servers = []; + + $is_offer = get_post_meta($post->ID,'_wis_is_offer',true); + $is_daily_deal = get_post_meta($post->ID,'_wis_daily_deal',true); + $offer_price = get_post_meta($post->ID,'_wis_offer_price',true); + $manual_daily = get_post_meta($post->ID,'_wis_manual_daily_deal',true); + + $all_servers = get_posts(['post_type'=>'wis_server','numberposts'=>-1]); + $currency = get_option('wis_currency_name', 'Coins'); + $exclude_offers = get_option('wis_coupon_exclude_offers'); + + // NEU: Kategorien + $cats = wp_get_object_terms($post->ID, 'wis_category'); + $cat_ids = array_map(function($t) { return $t->term_id; }, $cats); + + $current_status = get_post_status($post->ID); + $is_active = ($current_status === 'publish') && ($price > 0); + $status_msg = $is_active ? '✅ Aktiv im Shop' : '⏸️ Inaktiv (Kein Preis oder Entwurf)'; + + echo '

'.$status_msg.'

'; + echo '

'; + echo '

Wird automatisch aus dem Post-Titel übernommen

'; + + echo '

'; + echo '

Wenn du hier einen Preis einträgst (>0), wird das Item automatisch aktiv.

'; + + echo '

'; + echo '

✅ Daraus wird automatisch das Bild generiert.

'; + + // NEU: Kategorie Auswahl + echo '

'; + $terms = get_terms([ + 'taxonomy' => 'wis_category', + 'hide_empty' => false, + ]); + echo '

'; + if(!empty($terms)) { + foreach($terms as $term) { + $selected = in_array($term->term_id, $cat_ids) ? 'checked' : ''; + echo ''; + } + } else { + echo 'Noch keine Kategorien erstellt.'; + } + echo '

'; + + echo '
'; + echo '

'; + echo '

'; + echo '
Überschreibt die Automatik bis Mitternacht. Praktisch zum Testen.'; + if($is_daily_deal) { + echo '
ℹ️ Info: Dieses Item ist aktuell das Angebot des Tages. '; + echo 'Der Rabatt wurde automatisch berechnet.'; + } + echo '

'; + + echo '
'; + echo '

'; + echo '

'; + + echo '
Hervorgehobenes Item im Shop (rot/gold Badge).'; + + if($exclude_offers) { + echo '
Hinweis: Gutscheine sind aktuell global für Angebote deaktiviert.'; + } + + echo '

'; + echo '

'; + echo ''; + echo '
Wenn ausgefüllt, wird der normale Preis durchgestrichen und dieser angezeigt.

'; + echo '
'; + + echo '

'; + echo '

Dies ist der lange Text, der unter dem Titel im Shop angezeigt wird.

'; + + echo '

'; + echo '

'; + if(empty($all_servers)) echo 'Noch keine Server erstellt.'; + foreach($all_servers as $s){ + $checked = in_array($s->post_name, $servers) ? 'checked' : ''; + echo ''; + } + echo '

'; + } + + public static function render_server_meta($post){ + echo '

'; + echo 'Info: Da keine RCON-Verbindung benötigt wird (Vault/Plugin bestätigt), sind hier keine weiteren Einstellungen nötig.
'; + echo 'Der Servername dient nur zur Identifikat im Shop-Frontend.'; + echo '

'; + } + + public static function render_coupon_meta($post) { + wp_nonce_field('wis_save_coupon', 'wis_coupon_nonce'); + $code = get_post_meta($post->ID,'_wis_code',true); + $value = get_post_meta($post->ID,'_wis_value',true); + $limit = get_post_meta($post->ID,'_wis_usage_limit',true); + $expiry = get_post_meta($post->ID,'_wis_expiry',true); + $type = get_post_meta($post->ID,'_wis_type',true); + $exclude_offers = get_option('wis_coupon_exclude_offers'); + + if(empty($type)) $type = 'fixed'; + + echo '

'; + echo ''; + + echo '

'; + echo ''; + + echo '

'; + echo ''; + + if($exclude_offers) { + echo '

'; + echo '⚠️ Achtung: In den Shop-Einstellungen ist aktiviert, dass Gutscheine nicht auf Angebot-Items (Sale) angewendet werden. Dieser Gutschein wirkt nur auf reguläre Items.'; + echo '

'; + } + + echo '

'; + echo ''; + + echo '

'; + echo ''; + } + + public static function save_meta($post_id){ + if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return; + + if(get_post_type($post_id)==='wis_item' && isset($_POST['wis_item_nonce']) && wp_verify_nonce($_POST['wis_item_nonce'],'wis_save_item')){ + update_post_meta($post_id,'_wis_price',intval($_POST['wis_price'])); + update_post_meta($post_id,'_wis_item_id',sanitize_text_field($_POST['wis_item_id'])); + + $is_offer = isset($_POST['wis_is_offer']) ? 1 : 0; + update_post_meta($post_id,'_wis_is_offer', $is_offer); + update_post_meta($post_id,'_wis_offer_price', intval($_POST['wis_offer_price'])); + + // NEU: Manual Daily Deal Logic + $manual_daily = isset($_POST['wis_manual_daily_deal']) ? 1 : 0; + if($manual_daily) { + update_post_meta($post_id,'_wis_daily_deal', 1); + update_post_meta($post_id,'_wis_is_offer', 1); + } else { + // Wenn manuell abgewählt, löschen wir das Flag, damit der Cron ran darf + // update_post_meta($post_id,'_wis_daily_deal', 0); // Optional: Reset flag + } + + $servers = isset($_POST['wis_servers']) && is_array($_POST['wis_servers']) ? array_map('sanitize_text_field', $_POST['wis_servers']) : []; + update_post_meta($post_id,'_wis_servers', $servers); + + $cats = isset($_POST['wis_cats']) ? array_map('intval', $_POST['wis_cats']) : []; + wp_set_object_terms($post_id, $cats, 'wis_category'); + } + if(get_post_type($post_id)==='wis_server' && isset($_POST['wis_server_nonce']) && wp_verify_nonce($_POST['wis_server_nonce'],'wis_save_server')){ + // Nichts zu tun + } + if(get_post_type($post_id)==='wis_coupon' && isset($_POST['wis_coupon_nonce']) && wp_verify_nonce($_POST['wis_coupon_nonce'],'wis_save_coupon')){ + $code = sanitize_text_field(strtoupper($_POST['wis_code'])); + $value = intval($_POST['wis_value']); + $limit = intval($_POST['wis_usage_limit']); + $expiry = sanitize_text_field($_POST['wis_expiry']); + $type = sanitize_text_field($_POST['wis_type']); + if(!in_array($type, ['fixed', 'percent'])) $type = 'fixed'; + + update_post_meta($post_id,'_wis_code', $code); + update_post_meta($post_id,'_wis_value', $value); + update_post_meta($post_id,'_wis_type', $type); + update_post_meta($post_id,'_wis_usage_limit', $limit); + update_post_meta($post_id,'_wis_expiry', $expiry); + + global $wpdb; + $table_name = $wpdb->prefix . 'wis_coupons'; + + $data = ['code' => $code, 'value' => $value, 'type' => $type, 'usage_limit' => $limit, 'expiry' => $expiry]; + + $existing = $wpdb->get_row($wpdb->prepare("SELECT id FROM $table_name WHERE code = %s", $code)); + + if($existing) { + $wpdb->update($table_name, $data, ['id' => $existing->id]); + } else { + $wpdb->insert($table_name, $data); + } + + $db_coupon = $wpdb->get_row($wpdb->prepare("SELECT used_count FROM $table_name WHERE code = %s", $code)); + if($db_coupon) { + update_post_meta($post_id, '_wis_used_count', $db_coupon->used_count); + } + } + } + + public static function auto_update_status($post_id) { + static $processing = []; + if (isset($processing[$post_id])) return; + $processing[$post_id] = true; + if (get_post_type($post_id) != 'wis_item') { + unset($processing[$post_id]); + return; + } + $price = get_post_meta($post_id, '_wis_price', true); + $current_status = get_post_status($post_id); + $new_status = ($price > 0) ? 'publish' : 'draft'; + if ($current_status !== $new_status) { + remove_action('save_post', [__CLASS__, 'auto_update_status'], 10); + wp_update_post(['ID' => $post_id, 'post_status' => $new_status]); + add_action('save_post', [__CLASS__, 'auto_update_status'], 10); + } + unset($processing[$post_id]); + } + + public static function delete_coupon_from_table($post_id) { + if(get_post_type($post_id) != 'wis_coupon') return; + $code = get_post_meta($post_id, '_wis_code', true); + if($code) { + global $wpdb; + $wpdb->delete($wpdb->prefix . 'wis_coupons', ['code' => $code]); + } + } +} + +// =========================================================== +// Bulk Delete Funktionalität +// =========================================================== +class WIS_Bulk_Actions { + public static function register_bulk_actions($bulk_actions) { + $bulk_actions['delete'] = __('Löschen', 'wis'); + return $bulk_actions; + } + public static function handle_bulk_actions($redirect_to, $action, $post_ids) { + if ($action !== 'delete') return $redirect_to; + $deleted = 0; + foreach ($post_ids as $post_id) { + if (current_user_can('delete_post', $post_id)) { + wp_delete_post($post_id, true); + $deleted++; + } + } + if ($deleted > 0) { + $redirect_to = add_query_arg([ + 'bulk_deleted' => $deleted, + 'post_type' => get_post_type($post_ids[0] ?? 0) + ], $redirect_to); + } + return $redirect_to; + } + public static function admin_notices() { + if (!empty($_GET['bulk_deleted'])) { + $count = intval($_GET['bulk_deleted']); + $msg = sprintf(_n('%d Eintrag gelöscht.', '%d Einträge gelöscht.', $count, 'wis'), $count); + echo '

✅ ' . esc_html($msg) . '

'; + } + } +} + +// =========================================================== +// 3. ADMIN MENU +// =========================================================== +class WIS_Admin { + public static function register_menu() { + add_menu_page('Ingame Shop', 'Ingame Shop', 'manage_options', 'wis_shop', [self::class, 'page_overview'], 'dashicons-cart', 6); + add_submenu_page('wis_shop', 'Bestellungen', 'Bestellungen', 'manage_options', 'wis_orders', [self::class, 'page_orders']); + add_submenu_page('wis_shop', 'Top Spender', 'Top Spender', 'manage_options', 'wis_top_spenders', [self::class, 'page_top_spenders']); + add_submenu_page('wis_shop', 'Items', 'Items', 'manage_options', 'edit.php?post_type=wis_item'); + add_submenu_page('wis_shop', 'Kategorien', 'Kategorien', 'manage_options', 'edit-tags.php?taxonomy=wis_category'); + add_submenu_page('wis_shop', 'Servers', 'Servers', 'manage_options', 'edit.php?post_type=wis_server'); + add_submenu_page('wis_shop', 'Gutscheine', 'Gutscheine', 'manage_options', 'edit.php?post_type=wis_coupon'); + } + + public static function page_overview() { + if(isset($_POST['wis_save_settings']) && check_admin_referer('wis_settings_nonce')) { + update_option('wis_currency_name', sanitize_text_field($_POST['wis_currency_name'])); + update_option('wis_image_base_url', sanitize_text_field($_POST['wis_image_base_url'])); + update_option('wis_header_text', sanitize_textarea_field($_POST['wis_header_text'])); + update_option('wis_coupon_exclude_offers', isset($_POST['wis_coupon_exclude_offers']) ? '1' : '0'); + + // NEU: Daily Deal Settings + update_option('wis_daily_deal_enabled', isset($_POST['wis_daily_deal_enabled']) ? '1' : '0'); + update_option('wis_daily_deal_discount', intval($_POST['wis_daily_deal_discount'])); + + echo '

✅ Einstellungen gespeichert!

'; + } + $currency = get_option('wis_currency_name', 'Coins'); + $img_base = get_option('wis_image_base_url', 'https://assets.minecraft-ids.com/1_21_10/'); + $header_text = get_option('wis_header_text', '✅ Auto-Bilder | 💰 Sicherer Checkout'); + $exclude_offers = get_option('wis_coupon_exclude_offers', '0'); + + // NEU: Daily Deal Settings + $daily_deal_enabled = get_option('wis_daily_deal_enabled', '0'); + $daily_deal_discount = get_option('wis_daily_deal_discount', '20'); + + echo '

🛒 Ingame Shop Pro v1.0.0

'; + + echo '

✅ Feature Übersicht

'; + + echo '
'; + echo '

⚙️ Globale Einstellungen

'; + echo '
'; + wp_nonce_field('wis_settings_nonce'); + echo ''; + + echo ''; + echo ''; + + echo ''; + echo ''; + + echo ''; + echo ''; + + echo ''; + echo ''; + + // NEU: Daily Deal Settings + echo ''; + echo ''; + + echo ''; + echo ''; + + echo '
'; + echo '

Der Text, der ganz oben im Shop angezeigt wird.
Hinweis: Wenn dieses Feld leer ist, wird auch kein grüner Balken im Shop angezeigt.

'; + echo '

Wird für die Bildgenerierung verwendet.

'; + echo '

Wenn aktiv, wird der Rabatt nur auf den Warenkorbwert der regulären Items berechnet. Angebote werden vollgezahlt.

'; + echo '

Wenn aktiv, wird jeden Tag um Mitternacht ein zufälliges Item als "Angebot des Tages" markiert mit einem Rabatt.

'; + echo '
'; + echo '

Der Prozentsatz, um den der Preis gesenkt wird (z.B. 20 für 20%).

'; + echo '

'; + echo '
'; + echo '
'; + + echo '
'; + echo '

🚀 Bulk Import

'; + echo '

Smart Import: Lädt Items in Paketen (20 pro Durchlauf). Vorhandene Items werden übersprungen.

'; + echo '
'; + echo ''; + echo ''; + echo '
'; + echo ''; + echo ''; + echo '
'; + echo ''; + echo '
'; + ?> + + '; + + } + + public static function page_top_spenders() { + global $wpdb; + $currency = get_option('wis_currency_name', 'Coins'); + + $results = $wpdb->get_results(" + SELECT player_name, SUM(price) as total_spent, COUNT(*) as order_count + FROM {$wpdb->prefix}wis_orders + WHERE status = 'completed' OR status = 'cancelled' + GROUP BY player_name + ORDER BY total_spent DESC + LIMIT 50 + "); + + echo '

🏆 Top Spender

'; + echo '

Hier siehst du die Spieler, die insgesamt am meisten in deinem Shop ausgegeben haben.

'; + + echo ''; + echo ''; + + if(empty($results)) { + echo ''; + } else { + $rank = 1; + foreach($results as $row) { + $total = intval($row->total_spent); + $count = intval($row->order_count); + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } + } + + echo '
RangSpielerAusgegeben (Total)Anzahl Bestellungen
Noch keine Statistiken vorhanden.
#' . esc_html($rank++) . '' . esc_html($row->player_name) . '' . esc_html($total) . ' ' . esc_html($currency) . '' . esc_html($count) . '
'; + echo '
'; + } + + public static function page_orders() { + global $wpdb; + $currency = get_option('wis_currency_name', 'Coins'); + + if(isset($_GET['action']) && isset($_GET['order_id']) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'wis_order_action')) { + $action = sanitize_text_field($_GET['action']); + $id = intval($_GET['order_id']); + if($action === 'delete') { $wpdb->delete($wpdb->prefix.'wis_orders', ['id' => $id]); echo '

✓ Bestellung gelöscht.

'; } + elseif($action === 'complete') { $wpdb->update($wpdb->prefix.'wis_orders', ['status' => 'completed'], ['id' => $id]); echo '

✓ Manuell erledigt.

'; } + } + + if(isset($_GET['order_id'])) { + $order = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wis_orders WHERE id = %d", intval($_GET['order_id']))); + if($order) { + $status_colors = ['pending' => '#ffc107', 'processing' => '#0073aa', 'completed' => 'green', 'cancelled' => 'red', 'failed' => 'red']; + $status_labels = ['pending' => 'Warte auf Ingame', 'processing' => 'In Bearbeitung', 'completed' => 'Erledigt', 'cancelled' => 'Abgebrochen', 'failed' => 'Fehler']; + $status_label = $status_labels[$order->status] ?? $order->status; + $status_color = $status_colors[$order->status] ?? 'red'; + + $items_list = 'Keine Daten'; + $coupon_row = 'Kein Gutschein'; + $json_data = $order->response; + $decoded = json_decode($json_data, true); + + if(is_array($decoded)) { + if(isset($decoded['items']) && is_array($decoded['items'])) { + $items_list = ''; + + if(isset($decoded['coupon']) && !empty($decoded['coupon']['code'])) { + $code = esc_html($decoded['coupon']['code']); + $disc = intval($decoded['coupon']['discount']); + $coupon_row = "{$code} (-{$disc} {$currency})"; + } + } elseif(!empty($decoded)) { + $items_list = ''; + } + } + + echo '

Bestellung #'.$order->id.' - Details

'; + echo '← Zurück

'; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo '
ID'.$order->id.'
Datum'.date('d.m.Y H:i', strtotime($order->created_at)).'
Spieler'.$order->player_name.'
Server'.$order->server.'
Zusammenfassung'.esc_html($order->item_title).'
Gutschein'.$coupon_row.'
Gekaufte Items'.$items_list.'
Gesamtpreis'.$order->price.' '.esc_html($currency).'
Status'.esc_html($status_label).'
JSON (Debug)'.esc_html($json_data).'
'; + echo '
'; + return; + } + } + + $orders = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wis_orders ORDER BY created_at DESC LIMIT 100"); + echo '

Bestellungen

'; + echo ''; + + if(empty($orders)) { echo ''; } + + foreach($orders as $o){ + $status_map = ['pending' => 'Warte', 'processing' => 'Geben...', 'completed' => 'Fertig', 'cancelled' => 'Abgebrochen', 'failed' => 'Fehler']; + $status_label = $status_map[$o->status] ?? $o->status; + $status_colors = ['pending' => '#ffc107', 'processing' => '#0073aa', 'completed' => 'green', 'cancelled' => 'red', 'failed' => 'red']; + $status_color = $status_colors[$o->status] ?? 'red'; + + $delete_url = wp_nonce_url(admin_url('admin.php?page=wis_orders&action=delete&order_id='.$o->id), 'wis_order_action'); + $details_url = admin_url('admin.php?page=wis_orders&order_id='.$o->id); + + $item_label = strlen($o->item_title) > 50 ? substr($o->item_title, 0, 50).'...' : $o->item_title; + + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } + echo '
DatumSpielerInhaltPreisStatusAktion
Noch keine Bestellungen vorhanden.
'.esc_html(date('d.m.Y H:i', strtotime($o->created_at))).''.esc_html($o->player_name).''.esc_html($item_label).''.esc_html($o->price).' '.esc_html($currency).''.esc_html($status_label).''; + echo '👁️ Details '; + echo '🗑️ Löschen'; + echo '
'; + } +} + +// =========================================================== +// 4. API - AUTOMATION & CONFIRMATION +// =========================================================== +class WIS_API { + public static function register_routes() { + register_rest_route('wis/v1','/order', ['methods'=>'POST','callback'=>[self::class,'create_order'],'permission_callback'=> '__return_true']); + register_rest_route('wis/v1','/pending_orders', ['methods'=>'GET','callback'=>[self::class,'get_pending_orders'],'permission_callback'=> '__return_true']); + register_rest_route('wis/v1','/execute_order', ['methods'=>'POST','callback'=>[self::class,'execute_order'],'permission_callback'=> '__return_true']); + register_rest_route('wis/v1','/complete_order', ['methods'=>'POST','callback'=>[self::class,'complete_order'],'permission_callback'=> '__return_true']); + register_rest_route('wis/v1','/cancel_order', ['methods'=>'POST','callback'=>[self::class,'cancel_order'],'permission_callback'=> '__return_true']); + register_rest_route('wis/v1','/fetch_remote_data', ['methods'=>'POST','callback'=>[self::class,'fetch_remote_data'],'permission_callback'=> '__return_true']); + register_rest_route('wis/v1','/import_batch', ['methods'=>'POST','callback'=>[self::class,'import_batch'],'permission_callback'=> '__return_true']); + register_rest_route('wis/v1','/validate_coupon', ['methods'=>'POST','callback'=>[self::class,'validate_coupon'],'permission_callback'=> '__return_true']); + } + + public static function create_order($request) { + global $wpdb; + $data = $request->get_json_params(); + $player = sanitize_text_field($data['player'] ?? ''); + $cart = $data['cart'] ?? []; + $server_slug = sanitize_text_field($data['server'] ?? ''); + $coupon_code = isset($data['coupon_code']) ? sanitize_text_field(strtoupper($data['coupon_code'])) : ''; + + if(!$player || empty($cart) || !$server_slug) { return new WP_REST_Response(['success'=>false,'message'=>'Fehlende Eingabedaten'], 400); } + + $exclude_offers_setting = get_option('wis_coupon_exclude_offers', '0'); + + $valid_cart = []; + $total_normal = 0; + $total_offer = 0; + + foreach($cart as $item) { + $post_id = intval($item['id'] ?? 0); + $qty = intval($item['quantity'] ?? 1); + if($post_id <= 0 || $qty <= 0) continue; + + $price = intval(get_post_meta($post_id, '_wis_price', true)); + $item_servers = get_post_meta($post_id, '_wis_servers', true); + $is_offer = get_post_meta($post_id, '_wis_is_offer', true); + + if(!is_array($item_servers)) $item_servers = []; + if($price <= 0) continue; + if(!in_array($server_slug, $item_servers)) continue; + + $offer_price = intval(get_post_meta($post_id, '_wis_offer_price', true)); + $display_price = ($offer_price > 0) ? $offer_price : $price; + + $real_item_id = get_post_meta($post_id, '_wis_item_id', true); + + $valid_cart[] = [ + 'id' => $post_id, + 'title' => get_the_title($post_id), + 'price' => $display_price, + 'qty' => $qty, + 'is_offer' => $is_offer, + 'real_item_id' => $real_item_id + ]; + + $item_total = $display_price * $qty; + + if($is_offer && $exclude_offers_setting) { + $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 im Warenkorb.'], 400); + + // Gutschein Logik + $coupon_discount = 0; + $coupon_msg = ''; + $coupon_applied = false; + $currency = get_option('wis_currency_name', 'Coins'); + + if(!empty($coupon_code)) { + $coupon = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wis_coupons WHERE code = %s", $coupon_code)); + + if($coupon) { + // Basis Checks + if($coupon->expiry && date('Y-m-d') > $coupon->expiry) { + $coupon_msg = 'Gutschein abgelaufen.'; + } elseif($coupon->used_count >= $coupon->usage_limit) { + $coupon_msg = 'Gutschein wurde zu oft verwendet.'; + } else { + // Prüfen ob Gutschein angewendet werden darf + $apply_coupon = false; + $calculate_discount = false; + + if($exclude_offers_setting === '1') { + if($total_normal > 0) { + $apply_coupon = true; + } + } else { + if($total_normal > 0 || $total_offer > 0) { + $apply_coupon = true; + } + } + + if($apply_coupon) { + $calculate_discount = true; + } + } + } else { + $coupon_msg = 'Ungültiger Gutscheincode.'; + } + } + + // Wenn angewendet, berechnen + if($calculate_discount) { + $coupon_type = $coupon->type; + if($coupon_type === 'percent') { + $coupon_discount = $total_normal * ($coupon->value / 100); + $coupon_msg = "Gutschein eingelöst: -{$coupon->value}% (-{$coupon_discount} {$currency})"; + } else { + $coupon_discount = $coupon->value; + $coupon_msg = "Gutschein eingelöst: -{$coupon_discount} {$currency}"; + } + + // Aufrunden + $coupon_discount = floor($coupon_discount); + + $wpdb->update($wpdb->prefix.'wis_coupons', ['used_count' => $coupon->used_count + 1], ['id' => $coupon->id]); + $coupon_applied = true; + } + + $final_normal = max(0, $total_normal - $coupon_discount); + $final_price = $final_normal + $total_offer; + + // Speichern in DB + $items_payload = []; + $title_parts = []; + + foreach($valid_cart as $item) { + $items_payload[] = [ + 'id' => $item['real_item_id'], + 'amount' => $item['qty'] + ]; + $title_parts[] = $item['qty'] . 'x ' . $item['title']; + } + + $readable_title = "Warenkorb: " . implode(', ', $title_parts); + if (strlen($readable_title) > 240) $readable_title = substr($readable_title, 0, 237) . '...'; + + $coupon_data = []; + if($coupon_applied) { + $coupon_data = [ + 'code' => $coupon_code, + 'discount' => $coupon_discount + ]; + } + + $json_payload = json_encode([ + 'items' => $items_payload, + 'coupon' => $coupon_data + ]); + + $inserted = $wpdb->insert($wpdb->prefix.'wis_orders', [ + 'player_name' => $player, + 'server' => $server_slug, + 'item_id' => 'multi_item_cart', + 'item_title' => $readable_title, + 'price' => $final_price, + 'quantity' => count($valid_cart), + 'status' => 'pending', + 'response' => $json_payload, + 'created_at' => current_time('mysql') + ]); + + if($inserted) { + $msg = '✅ Bestellung erfolgreich erstellt!'; + if($coupon_msg) $msg .= ' ('.$coupon_msg.')'; + return new WP_REST_Response(['success'=>true,'message'=>$msg], 200); + } else { + return new WP_REST_Response(['success'=>false,'message'=>'Fehler beim Speichern.'], 500); + } + } + + public static function validate_coupon($request) { + global $wpdb; + $data = $request->get_json_params(); + $code = sanitize_text_field(strtoupper($data['code'] ?? '')); + $cart = $data['cart'] ?? []; + $currency = get_option('wis_currency_name', 'Coins'); + + if(!$code) { + return new WP_REST_Response(['success'=>false, 'message'=>'Kein Code angegeben']); + } + $coupon = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wis_coupons WHERE code = %s", $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'=>'Dieser Gutschein wurde bereits maximal eingelöst']); + } + + $exclude_offers_setting = get_option('wis_coupon_exclude_offers', '0'); + + if($exclude_offers_setting === '1' && !empty($cart)) { + $has_normal_items = false; + foreach($cart as $item) { + $post_id = intval($item['id'] ?? 0); + $is_offer = get_post_meta($post_id, '_wis_is_offer', true); + if(empty($is_offer) || $is_offer == 0) { + $has_normal_items = true; + break; + } + } + + if(!$has_normal_items) { + return new WP_REST_Response(['success'=>false, 'message'=>'⚠️ Dieser Gutschein gilt nicht für Angebote.']); + } + } + + $message = ''; + if($coupon->type === 'percent') { + $message = "Gutschein gültig (-{$coupon->value}%)"; + } else { + $message = "Gutschein gültig (-{$coupon->value} {$currency})"; + } + + return new WP_REST_Response(['success'=>true, 'type'=>$coupon->type, 'value'=>$coupon->value, 'message'=>$message]); + } + + 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'=>[]]); + $results = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wis_orders WHERE player_name = %s AND status = 'pending' ORDER BY created_at ASC 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); + + $order = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wis_orders WHERE id = %d", $id)); + if($order) { + $wpdb->update($wpdb->prefix.'wis_orders', ['status' => 'processing'], ['id' => $id]); + return new WP_REST_Response(['success'=>true]); + } + return new WP_REST_Response(['success'=>false], 400); + } + + 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); + + $updated = $wpdb->update($wpdb->prefix.'wis_orders', ['status' => 'cancelled'], ['id' => $id]); + + if($updated !== false) { + return new WP_REST_Response(['success'=>true]); + } + return new WP_REST_Response(['success'=>false], 400); + } + + public static function fetch_remote_data($request) { + $url = esc_url_raw($request->get_json_params()['url']); + $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); + $data = json_decode($body, true); + $import_data = []; + if (isset($data['items']) && is_array($data['items'])) { $import_data = $data['items']; } elseif (is_array($data)) { $import_data = $data; } + if(empty($import_data)) return new WP_REST_Response(['success'=>false, 'message'=>'Keine gültigen Daten gefunden'], 400); + return new WP_REST_Response(['success'=>true, 'items' => $import_data]); + } + + public static function import_batch($request) { + $items = $request->get_json_params()['items'] ?? []; + if(!is_array($items) || empty($items)) return new WP_REST_Response(['success'=>false], 400); + set_time_limit(300); + $processed = 0; $skipped = 0; + foreach($items as $item) { + $item_id_val = $item['id'] ?? ''; $title_val = $item['name'] ?? 'Unbekannt'; + if(empty($item_id_val)) continue; + $exists = get_posts(['post_type' => 'wis_item', 'meta_key' => '_wis_item_id', 'meta_value' => $item_id_val, 'posts_per_page' => 1]); + if($exists) { $skipped++; continue; } + $new_post_id = wp_insert_post(['post_title' => $title_val, 'post_content' => '', 'post_type' => 'wis_item', 'post_status' => 'draft', 'meta_input' => ['_wis_item_id' => $item_id_val, '_wis_price' => 0]]); + if(!is_wp_error($new_post_id)) $processed++; + } + return new WP_REST_Response(['success'=>true, 'processed' => $processed, 'skipped' => $skipped]); + } +} + +// =========================================================== +// 5. SHORTCODE +// =========================================================== +class WIS_Shortcode { + public static function register_shortcode() { + add_shortcode('ingame_shop_form', [self::class, 'render_form']); + } + + public static function render_form() { + $servers = get_posts(['post_type'=>'wis_server','numberposts'=>-1]); + $items = get_posts(['post_type'=>'wis_item','numberposts'=>-1]); + $currency = get_option('wis_currency_name', 'Coins'); + $img_base = get_option('wis_image_base_url', 'https://assets.minecraft-ids.com/1_21_10/'); + $header_text = get_option('wis_header_text', '✅ Auto-Bilder | 💰 Sicherer Checkout'); + $exclude_offers = get_option('wis_coupon_exclude_offers', '0'); + + // NEU: Kategorien + $categories = get_terms(['taxonomy'=>'wis_category', 'hide_empty'=>true]); + + ob_start(); + ?> + +
+
+

🛒 Ingame Shop Pro

+ +
+ +
+ +
+
+ +
+
+ +
+ + +
+ + +
+ + + + +
+ +
+ +
Keine Items im Shop verfügbar.
+ + ID, '_wis_servers', true); + if(!is_array($item_servers)) $item_servers = []; + $price = get_post_meta($item->ID, '_wis_price', true); + $item_id_code = get_post_meta($item->ID, '_wis_item_id', true); + $item_desc = $item->post_content; + + $is_offer = get_post_meta($item->ID, '_wis_is_offer', true); + $is_daily_deal = get_post_meta($item->ID, '_wis_daily_deal', true); + $offer_price = get_post_meta($item->ID, '_wis_offer_price', true); + $display_price = ($offer_price > 0) ? $offer_price : $price; + $show_old_price = ($offer_price > 0 && $offer_price != $price); + + // NEU: Kategorien + $item_cats = wp_get_post_terms($item->ID, 'wis_category'); + $cat_ids = array_map(function($t) { return $t->term_id; }, $item_cats); + $cat_data = json_encode($cat_ids); + + $img_name = str_replace(':', '_', $item_id_code) . '.png'; + $full_img_url = $img_base . $img_name; + + $server_names = []; + foreach($item_servers as $slug) { + $srv = get_page_by_path($slug, OBJECT, 'wis_server'); + if($srv) $server_names[] = $srv->post_title; + } + $servers_display = !empty($server_names) ? implode(', ', $server_names) : 'Kein Server'; + $servers_data = json_encode($item_servers); + ?> +
+ +
🎁 Angebot des Tages
+
🔥 Angebot
+ +
+ <?=esc_attr($item->post_title)?> +
+
+

post_title)?>

+ +
+
+
+
+ +
📡
+ + +
⚠️ Gutschein ungültig
+ + +
+ + + +
+ + +
+
+ +
+
+ + +
+
+

🛒 Dein Warenkorb

+
+
Dein Warenkorb ist leer
+
+ +
+
+ + + \ No newline at end of file