get_charset_collate(); $tables = []; // Items $tables[] = "CREATE TABLE {$wpdb->prefix}wis_items ( id mediumint(9) NOT NULL AUTO_INCREMENT, item_id varchar(100) NOT NULL, name varchar(255) NOT NULL, description text, price int(11) DEFAULT 0, offer_price int(11) DEFAULT 0, is_offer tinyint(1) DEFAULT 0, is_daily_deal tinyint(1) DEFAULT 0, servers text, categories text, status varchar(20) DEFAULT 'draft', created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY item_id (item_id), KEY status (status) ) $charset_collate;"; // Orders $tables[] = "CREATE TABLE {$wpdb->prefix}wis_orders ( 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, PRIMARY KEY (id), KEY player_name (player_name), KEY status (status) ) $charset_collate;"; // Coupons $tables[] = "CREATE TABLE {$wpdb->prefix}wis_coupons ( 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, PRIMARY KEY (id), UNIQUE KEY code (code) ) $charset_collate;"; // Servers $tables[] = "CREATE TABLE {$wpdb->prefix}wis_servers ( id mediumint(9) NOT NULL AUTO_INCREMENT, slug varchar(100) NOT NULL, name varchar(255) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY slug (slug) ) $charset_collate;"; // Categories $tables[] = "CREATE TABLE {$wpdb->prefix}wis_categories ( id mediumint(9) NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, slug varchar(100) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY slug (slug) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); foreach ($tables as $sql) { dbDelta($sql); } } private static function set_default_options() { $defaults = [ 'wis_currency_name' => 'Coins', 'wis_image_base_url' => 'https://git.viper.ipv64.net/M_Viper/minecraft-items/raw/branch/main/images/', 'wis_header_text' => '✅ Auto-Bilder | 💰 Sicherer Checkout | 🎮 Ingame-Bestätigung', 'wis_coupon_exclude_offers' => '0', 'wis_daily_deal_enabled' => '0', 'wis_daily_deal_discount' => '20', 'wis_api_key' => bin2hex(random_bytes(24)), ]; foreach ($defaults as $key => $value) { if (get_option($key) === false) { add_option($key, $value); } } } public static function check_api_key($request) { $key = $request->get_header('X-WIS-Key'); if (empty($key)) { $key = $request->get_param('api_key'); } $stored = get_option('wis_api_key', ''); return ($stored !== '' && hash_equals($stored, (string) $key)); } public static function spigot_permission($request) { if (!self::check_api_key($request)) { return new WP_Error('wis_unauthorized', 'Ungültiger oder fehlender API-Key.', ['status' => 401]); } return true; } private static function create_default_categories() { $default_categories = [ ['name' => 'Baublöcke', 'slug' => 'baublocke'], ['name' => 'Dekorationsblöcke', 'slug' => 'dekorationsblocke'], ['name' => 'Redstone', 'slug' => 'redstone'], ['name' => 'Transport', 'slug' => 'transport'], ['name' => 'Natur', 'slug' => 'natur'], ['name' => 'Werkzeuge & Hilfsmittel', 'slug' => 'werkzeuge-hilfsmittel'], ['name' => 'Kampf', 'slug' => 'kampf'], ['name' => 'Nahrung & Tränke', 'slug' => 'nahrung-tranke'], ['name' => 'Zutaten', 'slug' => 'zutaten'], ['name' => 'Spawn-Eier', 'slug' => 'spawn-eier'] ]; global $wpdb; foreach ($default_categories as $cat) { $exists = $wpdb->get_var($wpdb->prepare( "SELECT id FROM {$wpdb->prefix}wis_categories WHERE slug = %s", $cat['slug'] )); if (!$exists) { $wpdb->insert($wpdb->prefix . 'wis_categories', [ 'name' => $cat['name'], 'slug' => $cat['slug'] ]); } } } public static function run_daily_deal() { if (get_option('wis_daily_deal_enabled') !== '1') return; global $wpdb; $table = $wpdb->prefix . 'wis_items'; $discount = intval(get_option('wis_daily_deal_discount', 20)); $wpdb->update($table, ['is_daily_deal' => 0], ['is_daily_deal' => 1]); $item = $wpdb->get_row("SELECT * FROM $table WHERE status = 'publish' AND price > 0 ORDER BY RAND() LIMIT 1"); if ($item) { $offer_price = max(0, floor($item->price - ($item->price * ($discount / 100)))); $wpdb->update($table, [ 'is_daily_deal' => 1, 'is_offer' => 1, 'offer_price' => $offer_price ], ['id' => $item->id]); } } public static function reset_shop() { global $wpdb; $tables = [ 'wis_items', 'wis_orders', 'wis_coupons', 'wis_servers', 'wis_categories' ]; foreach ($tables as $table) { $wpdb->query("TRUNCATE TABLE {$wpdb->prefix}$table"); } self::set_default_options(); self::create_default_categories(); return true; } } // =========================================================== // ITEM CATEGORIZER // =========================================================== class WIS_Item_Categorizer { public static function auto_categorize($item_id) { $item_id = strtolower($item_id); $item_id = str_replace('minecraft:', '', $item_id); if (strpos($item_id, 'spawn_egg') !== false) { return ['spawn-eier']; } if (preg_match('/(wooden|stone|iron|golden|diamond|netherite|copper)_(pickaxe|axe|shovel|hoe)/', $item_id)) { return ['werkzeuge-hilfsmittel']; } if (in_array($item_id, [ 'shears', 'fishing_rod', 'flint_and_steel', 'bucket', 'water_bucket', 'lava_bucket', 'milk_bucket', 'powder_snow_bucket', 'axolotl_bucket', 'cod_bucket', 'pufferfish_bucket', 'salmon_bucket', 'tadpole_bucket', 'tropical_fish_bucket', 'compass', 'recovery_compass', 'clock', 'spyglass', 'map', 'filled_map', 'brush', 'lead', 'name_tag', 'saddle', 'carrot_on_a_stick', 'warped_fungus_on_a_stick' ])) { return ['werkzeuge-hilfsmittel']; } if (preg_match('/(wooden|stone|iron|golden|diamond|netherite|copper)_(sword|spear)/', $item_id)) { return ['kampf']; } if (preg_match('/(leather|chainmail|iron|golden|diamond|netherite|copper|turtle)_(helmet|chestplate|leggings|boots|cap|tunic|pants|shell)/', $item_id)) { return ['kampf']; } if (in_array($item_id, [ 'bow', 'crossbow', 'arrow', 'spectral_arrow', 'tipped_arrow', 'shield', 'trident', 'mace', 'totem_of_undying', 'elytra', 'horse_armor', 'iron_horse_armor', 'golden_horse_armor', 'diamond_horse_armor', 'wolf_armor' ]) || strpos($item_id, 'horse_armor') !== false) { return ['kampf']; } if (preg_match('/(raw_|cooked_)?(beef|porkchop|mutton|chicken|rabbit|cod|salmon)/', $item_id)) { return ['nahrung-tranke']; } if (in_array($item_id, [ 'apple', 'golden_apple', 'enchanted_golden_apple', 'melon_slice', 'glow_berries', 'sweet_berries', 'chorus_fruit', 'carrot', 'golden_carrot', 'potato', 'baked_potato', 'poisonous_potato', 'beetroot', 'bread', 'cookie', 'cake', 'pumpkin_pie', 'dried_kelp', 'tropical_fish', 'pufferfish', 'rotten_flesh', 'spider_eye' ])) { return ['nahrung-tranke']; } if (strpos($item_id, '_stew') !== false || strpos($item_id, '_soup') !== false) { return ['nahrung-tranke']; } if (strpos($item_id, 'potion') !== false || in_array($item_id, [ 'honey_bottle', 'milk_bucket', 'glass_bottle', 'dragon_breath', 'experience_bottle', 'ominous_bottle' ])) { return ['nahrung-tranke']; } if (strpos($item_id, '_boat') !== false || strpos($item_id, '_raft') !== false) { return ['transport']; } if (strpos($item_id, 'minecart') !== false) { return ['transport']; } if (in_array($item_id, ['elytra', 'saddle', 'lead'])) { return ['transport']; } if (strpos($item_id, 'redstone') !== false && $item_id !== 'redstone_ore') { return ['redstone']; } if (in_array($item_id, [ 'repeater', 'comparator', 'observer', 'piston', 'sticky_piston', 'dispenser', 'dropper', 'hopper', 'lever', 'tripwire_hook', 'daylight_detector', 'tnt', 'target', 'lightning_rod' ]) || strpos($item_id, 'button') !== false || strpos($item_id, 'pressure_plate') !== false) { return ['redstone']; } if (strpos($item_id, '_rail') !== false || $item_id === 'rail') { return ['redstone']; } $pure_materials = [ 'stick', 'coal', 'charcoal', 'diamond', 'emerald', 'lapis_lazuli', 'iron_ingot', 'gold_ingot', 'copper_ingot', 'netherite_ingot', 'iron_nugget', 'gold_nugget', 'copper_nugget', 'raw_iron', 'raw_gold', 'raw_copper', 'netherite_scrap', 'netherite_upgrade', 'amethyst_shard', 'prismarine_shard', 'prismarine_crystals', 'quartz', 'nether_quartz', 'echo_shard', 'disc_fragment', 'string', 'feather', 'leather', 'rabbit_hide', 'slimeball', 'ender_pearl', 'ender_eye', 'blaze_rod', 'blaze_powder', 'magma_cream', 'ghast_tear', 'nether_star', 'nether_brick', 'nautilus_shell', 'heart_of_the_sea', 'scute', 'turtle_scute', 'armadillo_scute', 'bone', 'bone_meal', 'gunpowder', 'glowstone_dust', 'sugar', 'phantom_membrane', 'ink_sac', 'glow_ink_sac', 'paper', 'book', 'flint', 'fermented_spider_eye', 'glistering_melon_slice', 'rabbit_foot', 'nether_wart', 'breeze_rod', 'clay_ball', 'brick', 'firework_star', 'shulker_shell', 'popped_chorus_fruit' ]; if (in_array($item_id, $pure_materials)) { return ['zutaten']; } if (strpos($item_id, '_pottery_sherd') !== false || strpos($item_id, '_armor_trim') !== false) { return ['zutaten']; } if (in_array($item_id, [ 'dirt', 'coarse_dirt', 'rooted_dirt', 'grass_block', 'podzol', 'mycelium', 'farmland', 'dirt_path', 'sand', 'red_sand', 'gravel', 'clay', 'suspicious_sand', 'suspicious_gravel' ])) { return ['natur']; } if (strpos($item_id, '_leaves') !== false || strpos($item_id, '_sapling') !== false || strpos($item_id, 'azalea') !== false) { return ['natur']; } $flowers = [ 'dandelion', 'poppy', 'blue_orchid', 'allium', 'azure_bluet', 'red_tulip', 'orange_tulip', 'white_tulip', 'pink_tulip', 'oxeye_daisy', 'cornflower', 'lily_of_the_valley', 'wither_rose', 'sunflower', 'lilac', 'rose_bush', 'peony', 'pitcher_plant', 'pitcher_pod', 'torchflower', 'torchflower_seeds', 'pink_petals', 'spore_blossom' ]; if (in_array($item_id, $flowers)) { return ['natur']; } if (strpos($item_id, 'mushroom') !== false || strpos($item_id, 'fungus') !== false || in_array($item_id, ['short_grass', 'tall_grass', 'fern', 'large_fern', 'dead_bush'])) { return ['natur']; } if (in_array($item_id, [ 'seagrass', 'tall_seagrass', 'kelp', 'dried_kelp', 'sea_pickle', 'vine', 'weeping_vines', 'twisting_vines', 'cave_vines', 'glow_lichen', 'hanging_roots', 'mangrove_roots', 'muddy_mangrove_roots' ])) { return ['natur']; } if (strpos($item_id, '_seeds') !== false || in_array($item_id, [ 'wheat', 'beetroot', 'carrot', 'potato', 'melon', 'pumpkin', 'carved_pumpkin', 'sugar_cane', 'bamboo', 'cocoa_beans', 'sweet_berries', 'glow_berries', 'sweet_berry_bush', 'nether_wart', 'cactus', 'mangrove_propagule' ])) { return ['natur']; } if (in_array($item_id, [ 'crimson_roots', 'warped_roots', 'nether_sprouts', 'crimson_nylium', 'warped_nylium' ])) { return ['natur']; } if (in_array($item_id, [ 'moss_block', 'moss_carpet', 'big_dripleaf', 'small_dripleaf', 'lily_pad', 'bee_nest', 'honeycomb', 'honeycomb_block', 'snow', 'snowball', 'powder_snow' ])) { return ['natur']; } if (strpos($item_id, 'glass') !== false && strpos($item_id, '_pane') === false) { return ['dekorationsblocke']; } if (strpos($item_id, 'glass_pane') !== false || strpos($item_id, 'stained_glass_pane') !== false) { return ['dekorationsblocke']; } if (strpos($item_id, '_door') !== false || strpos($item_id, '_trapdoor') !== false || strpos($item_id, '_fence_gate') !== false) { return ['dekorationsblocke']; } if ((strpos($item_id, '_fence') !== false && strpos($item_id, '_fence_gate') === false) || (strpos($item_id, '_wall') !== false && !in_array($item_id, ['wall_banner', 'wall_sign', 'wall_torch'])) || $item_id === 'iron_bars') { return ['dekorationsblocke']; } if (strpos($item_id, '_stairs') !== false || strpos($item_id, '_slab') !== false) { return ['dekorationsblocke']; } if (strpos($item_id, '_carpet') !== false) { return ['dekorationsblocke']; } if (in_array($item_id, [ 'torch', 'soul_torch', 'lantern', 'soul_lantern', 'campfire', 'soul_campfire', 'end_rod', 'shroomlight', 'froglight', 'sea_lantern' ]) || strpos($item_id, '_candle') !== false || $item_id === 'candle') { return ['dekorationsblocke']; } if (in_array($item_id, [ 'crafting_table', 'furnace', 'blast_furnace', 'smoker', 'chest', 'trapped_chest', 'ender_chest', 'barrel', 'enchanting_table', 'anvil', 'chipped_anvil', 'damaged_anvil', 'grindstone', 'smithing_table', 'cartography_table', 'fletching_table', 'loom', 'stonecutter', 'brewing_stand', 'cauldron', 'composter', 'lectern', 'bookshelf', 'chiseled_bookshelf', 'bell', 'beacon', 'conduit', 'lodestone', 'respawn_anchor' ]) || strpos($item_id, '_bed') !== false || strpos($item_id, 'shulker_box') !== false) { return ['dekorationsblocke']; } if (strpos($item_id, '_sign') !== false || strpos($item_id, '_hanging_sign') !== false || strpos($item_id, '_banner') !== false || in_array($item_id, ['item_frame', 'glow_item_frame', 'painting', 'armor_stand'])) { return ['dekorationsblocke']; } if (in_array($item_id, [ 'ladder', 'scaffolding', 'chain', 'flower_pot', 'decorated_pot', 'dragon_egg', 'dragon_head', 'note_block', 'jukebox' ]) || strpos($item_id, '_head') !== false || strpos($item_id, '_skull') !== false || strpos($item_id, 'coral') !== false) { return ['dekorationsblocke']; } if (in_array($item_id, [ 'stone', 'cobblestone', 'mossy_cobblestone', 'granite', 'polished_granite', 'diorite', 'polished_diorite', 'andesite', 'polished_andesite', 'calcite', 'tuff', 'smooth_stone' ]) || strpos($item_id, 'stone_brick') !== false) { return ['baublocke']; } if (strpos($item_id, 'deepslate') !== false) { return ['baublocke']; } if (strpos($item_id, 'brick') !== false && $item_id !== 'brick' && $item_id !== 'nether_brick') { return ['baublocke']; } if (strpos($item_id, 'sandstone') !== false) { return ['baublocke']; } if (strpos($item_id, 'quartz_') !== false && strpos($item_id, 'nether_quartz') === false) { return ['baublocke']; } if (strpos($item_id, 'prismarine') !== false || strpos($item_id, 'purpur') !== false) { return ['baublocke']; } if (strpos($item_id, 'concrete') !== false || strpos($item_id, 'terracotta') !== false) { return ['baublocke']; } if (strpos($item_id, '_wool') !== false) { return ['baublocke']; } if (strpos($item_id, '_planks') !== false || (strpos($item_id, '_log') !== false && strpos($item_id, 'stripped') === false) || (strpos($item_id, '_wood') !== false && strpos($item_id, 'stripped') === false)) { return ['baublocke']; } if (strpos($item_id, 'stripped_') !== false) { return ['baublocke']; } if (in_array($item_id, ['bamboo_block', 'bamboo_mosaic', 'crimson_stem', 'warped_stem', 'crimson_hyphae', 'warped_hyphae'])) { return ['baublocke']; } if (strpos($item_id, 'copper_') !== false && strpos($item_id, '_ingot') === false && strpos($item_id, '_nugget') === false && $item_id !== 'copper_door' && $item_id !== 'copper_trapdoor') { return ['baublocke']; } if (strpos($item_id, '_block') !== false) { return ['baublocke']; } if (in_array($item_id, [ 'netherrack', 'soul_sand', 'soul_soil', 'basalt', 'polished_basalt', 'smooth_basalt', 'end_stone', 'obsidian', 'crying_obsidian' ]) || strpos($item_id, 'blackstone') !== false || strpos($item_id, 'end_stone_brick') !== false) { return ['baublocke']; } if (in_array($item_id, [ 'glowstone', 'sponge', 'wet_sponge', 'ice', 'packed_ice', 'blue_ice', 'magma_block', 'slime_block', 'honey_block', 'hay_block', 'dried_kelp_block', 'mud', 'packed_mud', 'mud_bricks', 'dripstone_block', 'amethyst_block', 'budding_amethyst' ])) { return ['baublocke']; } return ['baublocke']; } } // =========================================================== // DATABASE HELPER // =========================================================== class WIS_DB { public static function get_items($args = []) { global $wpdb; $table = $wpdb->prefix . 'wis_items'; $where_parts = ["1=1"]; if (isset($args['status'])) { $where_parts[] = $wpdb->prepare("status = %s", $args['status']); } if (isset($args['category_slug']) && !empty($args['category_slug'])) { $search_pattern = '%"' . $args['category_slug'] . '"%'; $where_parts[] = $wpdb->prepare("categories LIKE %s", $search_pattern); } if (isset($args['ids']) && is_array($args['ids']) && !empty($args['ids'])) { $ids = array_map('intval', $args['ids']); $placeholders = implode(',', array_fill(0, count($ids), '%d')); $where_parts[] = sprintf("id IN ($placeholders)", ...$ids); } if (isset($args['search']) && !empty($args['search'])) { $search_like = '%' . $wpdb->esc_like($args['search']) . '%'; $where_parts[] = $wpdb->prepare("(name LIKE %s OR item_id LIKE %s)", $search_like, $search_like); } $where = implode(" AND ", $where_parts); $limit = isset($args['limit']) ? "LIMIT " . intval($args['limit']) : ""; $orderby = isset($args['orderby']) ? "ORDER BY " . sanitize_text_field($args['orderby']) : "ORDER BY name ASC"; return $wpdb->get_results("SELECT * FROM $table WHERE $where $orderby $limit"); } public static function count_items($args = []) { global $wpdb; $table = $wpdb->prefix . 'wis_items'; $where_parts = ["1=1"]; if (isset($args['status'])) { $where_parts[] = $wpdb->prepare("status = %s", $args['status']); } if (isset($args['category_slug']) && !empty($args['category_slug'])) { $search_pattern = '%"' . $args['category_slug'] . '"%'; $where_parts[] = $wpdb->prepare("categories LIKE %s", $search_pattern); } if (isset($args['search']) && !empty($args['search'])) { $search_like = '%' . $wpdb->esc_like($args['search']) . '%'; $where_parts[] = $wpdb->prepare("(name LIKE %s OR item_id LIKE %s)", $search_like, $search_like); } $where = implode(" AND ", $where_parts); return (int) $wpdb->get_var("SELECT COUNT(*) FROM $table WHERE $where"); } public static function get_item($id) { global $wpdb; return $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wis_items WHERE id = %d", $id )); } public static function get_item_by_item_id($item_id) { global $wpdb; return $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wis_items WHERE item_id = %s", $item_id )); } public static function insert_item($data) { global $wpdb; if (empty($data['categories']) || $data['categories'] === '[]') { $auto_cats = WIS_Item_Categorizer::auto_categorize($data['item_id']); $data['categories'] = json_encode($auto_cats); } return $wpdb->insert($wpdb->prefix . 'wis_items', $data); } public static function update_item($id, $data) { global $wpdb; return $wpdb->update($wpdb->prefix . 'wis_items', $data, ['id' => $id]); } public static function delete_item($id) { global $wpdb; return $wpdb->delete($wpdb->prefix . 'wis_items', ['id' => $id]); } public static function get_servers() { global $wpdb; return $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wis_servers ORDER BY name ASC"); } public static function insert_server($slug, $name) { global $wpdb; return $wpdb->insert($wpdb->prefix . 'wis_servers', [ 'slug' => sanitize_title($slug), 'name' => sanitize_text_field($name) ]); } public static function delete_server($id) { global $wpdb; return $wpdb->delete($wpdb->prefix . 'wis_servers', ['id' => $id]); } public static function get_categories() { global $wpdb; return $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wis_categories ORDER BY name ASC"); } public static function insert_category($name) { global $wpdb; return $wpdb->insert($wpdb->prefix . 'wis_categories', [ 'name' => sanitize_text_field($name), 'slug' => sanitize_title($name) ]); } public static function delete_category($id) { global $wpdb; return $wpdb->delete($wpdb->prefix . 'wis_categories', ['id' => $id]); } public static function get_coupons() { global $wpdb; return $wpdb->get_results("SELECT * FROM {$wpdb->prefix}wis_coupons ORDER BY created_at DESC"); } public static function get_coupon_by_code($code) { global $wpdb; return $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wis_coupons WHERE code = %s", strtoupper($code) )); } public static function insert_coupon($data) { global $wpdb; $data['code'] = strtoupper($data['code']); return $wpdb->insert($wpdb->prefix . 'wis_coupons', $data); } public static function update_coupon($id, $data) { global $wpdb; if (isset($data['code'])) { $data['code'] = strtoupper($data['code']); } return $wpdb->update($wpdb->prefix . 'wis_coupons', $data, ['id' => $id]); } public static function delete_coupon($id) { global $wpdb; return $wpdb->delete($wpdb->prefix . 'wis_coupons', ['id' => $id]); } public static function get_orders($limit = 100) { global $wpdb; return $wpdb->get_results($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wis_orders ORDER BY created_at DESC LIMIT %d", $limit )); } public static function get_order($id) { global $wpdb; return $wpdb->get_row($wpdb->prepare( "SELECT * FROM {$wpdb->prefix}wis_orders WHERE id = %d", $id )); } public static function insert_order($data) { global $wpdb; return $wpdb->insert($wpdb->prefix . 'wis_orders', $data); } public static function update_order_status($id, $status) { global $wpdb; return $wpdb->update( $wpdb->prefix . 'wis_orders', ['status' => $status], ['id' => $id] ); } public static function delete_order($id) { global $wpdb; return $wpdb->delete($wpdb->prefix . 'wis_orders', ['id' => $id]); } } // =========================================================== // ADMIN PAGES // =========================================================== 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', 'Einstellungen', 'Einstellungen', 'manage_options', 'wis_shop'); add_submenu_page('wis_shop', 'Items', 'Items', 'manage_options', 'wis_items', [self::class, 'page_items']); add_submenu_page('wis_shop', 'Bestellungen', 'Bestellungen', 'manage_options', 'wis_orders', [self::class, 'page_orders']); add_submenu_page('wis_shop', 'Server', 'Server', 'manage_options', 'wis_servers', [self::class, 'page_servers']); add_submenu_page('wis_shop', 'Kategorien', 'Kategorien', 'manage_options', 'wis_categories', [self::class, 'page_categories']); add_submenu_page('wis_shop', 'Gutscheine', 'Gutscheine', 'manage_options', 'wis_coupons', [self::class, 'page_coupons']); add_submenu_page('wis_shop', 'JSON Export/Import', 'JSON Tools', 'manage_options', 'wis_json', [self::class, 'page_json']); add_submenu_page('wis_shop', 'Shop Reset', '🔄 Reset', 'manage_options', 'wis_reset', [self::class, 'page_reset']); add_submenu_page('wis_shop', 'Top Spender', 'Top Spender', 'manage_options', 'wis_top_spenders', [self::class, 'page_top_spenders']); } public static function page_overview() { if (isset($_POST['wis_save_settings']) && check_admin_referer('wis_settings')) { update_option('wis_currency_name', sanitize_text_field($_POST['wis_currency_name'])); update_option('wis_image_base_url', esc_url_raw($_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'); 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'])); update_option('wis_offline_queue_enabled', isset($_POST['wis_offline_queue_enabled']) ? '1' : '0'); echo '

✅ Einstellungen gespeichert!

'; } if (isset($_POST['wis_regen_key']) && check_admin_referer('wis_regen_key')) { update_option('wis_api_key', bin2hex(random_bytes(24))); echo '

🔑 Neuer API-Key generiert! Bitte in der config.yml des Spigot-Plugins aktualisieren.

'; } global $wpdb; $stats = [ 'items' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wis_items"), 'orders' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wis_orders"), 'servers' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wis_servers"), 'coupons' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}wis_coupons") ]; ?>

🛒 WP Ingame Shop Pro v

📊 Statistiken

Items im Shop:
Bestellungen:
Server:
Gutscheine:

⚙️ Einstellungen

Muss mit / enden! Z.B.: https://git.viper.ipv64.net/.../images/

Gutscheine bei Angeboten
Daily Deal
Offline-Queue

Erfordert Spigot-Plugin v6.3+ mit Offline-Queue-Unterstützung

🔑 Spigot API-Key

Dieser Key muss in der config.yml des Spigot-Plugins als api-key eingetragen werden.

Geschützte Endpunkte: pending_orders, execute_order, complete_order, cancel_order, pending_offline

= 0) { $data['price'] = $new_price; } } break; case 'offer': $is_offer = isset($_POST['item_offers'][$id]) ? 1 : 0; $data['is_offer'] = $is_offer; if (isset($_POST['item_offer_prices'][$id])) { $offer_price = intval($_POST['item_offer_prices'][$id]); $data['offer_price'] = $is_offer ? $offer_price : 0; } else if (!$is_offer) { $data['offer_price'] = 0; } break; case 'status': $new_status = sanitize_text_field($_POST['bulk_status']); if (in_array($new_status, ['publish', 'draft'])) { $data['status'] = $new_status; } break; case 'server': if (isset($_POST['item_servers'][$id])) { $data['servers'] = json_encode($_POST['item_servers'][$id]); } else { $data['servers'] = '[]'; } break; case 'category': if (isset($_POST['item_cat_assignments'][$id])) { $data['categories'] = json_encode($_POST['item_cat_assignments'][$id]); } break; } if (!empty($data)) { WIS_DB::update_item($id, $data); $count++; } } echo '

✅ ' . $count . ' Items erfolgreich aktualisiert!

'; } } if (isset($_POST['wis_bulk_apply']) && !empty($_POST['wis_bulk_action']) && isset($_POST['item_ids'])) { $action = sanitize_text_field($_POST['wis_bulk_action']); $selected_ids = array_map('intval', $_POST['item_ids']); $all_servers = WIS_DB::get_servers(); $all_categories = WIS_DB::get_categories(); $currency = get_option('wis_currency_name', 'Coins'); $items_to_edit = WIS_DB::get_items(['ids' => $selected_ids]); ?>

📦 Mehrfachbearbeitung

Aktion: für Items.

Preis pro Item festlegen

Item Name Aktueller Preis Neuer Preis ()
name); ?>
item_id); ?>
price); ?>

Angebot pro Item festlegen

Item Name Normalpreis Als Angebot? Angebotspreis
name); ?>
item_id); ?>
price); ?> is_offer, 1); ?> onchange="toggleOfferPrice(this, id; ?>)"> is_offer): ?>disabled>

Server pro Item zuweisen

Keine Server vorhanden.

servers, true) ?: []; ?>
Item Name Server (Mehrfachauswahl möglich)
name); ?>
item_id); ?>
slug, $current_servers) ? 'checked' : ''; ?>

Kategorien pro Item zuweisen

Fehler beim Laden der Items.

categories, true) ?: []; ?>
Item Name Kategorie (Mehrfachauswahl mit STRG+Klick)
name); ?>
item_id); ?>

Abbrechen

✅ Item gelöscht!

'; } elseif ($_GET['action'] === 'toggle_status') { $item = WIS_DB::get_item($id); $new_status = ($item->status === 'publish') ? 'draft' : 'publish'; WIS_DB::update_item($id, ['status' => $new_status]); echo '

✅ Status geändert!

'; } } if (isset($_POST['wis_save_item'])) { check_admin_referer('wis_item_form'); $data = [ 'item_id' => sanitize_text_field($_POST['item_id']), 'name' => sanitize_text_field($_POST['name']), 'description' => sanitize_textarea_field($_POST['description']), 'price' => intval($_POST['price']), 'offer_price' => intval($_POST['offer_price']), 'is_offer' => isset($_POST['is_offer']) ? 1 : 0, 'servers' => isset($_POST['servers']) ? json_encode($_POST['servers']) : '[]', 'categories' => isset($_POST['categories']) ? json_encode($_POST['categories']) : '[]', 'status' => intval($_POST['price']) > 0 ? 'publish' : 'draft' ]; if (isset($_GET['edit'])) { WIS_DB::update_item(intval($_GET['edit']), $data); echo '

✅ Item gespeichert!

'; } else { WIS_DB::insert_item($data); echo '

✅ Item erstellt!

'; } } if (isset($_GET['edit']) || isset($_GET['add'])) { $item = isset($_GET['edit']) ? WIS_DB::get_item(intval($_GET['edit'])) : null; $servers = WIS_DB::get_servers(); $categories = WIS_DB::get_categories(); $currency = get_option('wis_currency_name', 'Coins'); $item_servers = $item ? json_decode($item->servers, true) : []; $item_cats = $item ? json_decode($item->categories, true) : []; if (!$item && isset($_GET['add'])) { $item_cats = []; } ?>

← Zurück zur Liste

Z.B.: minecraft:diamond (Kategorien werden automatisch zugewiesen)

Optional: Wenn gesetzt, wird der normale Preis durchgestrichen

Markierungen
Server

Keine Server vorhanden. Server erstellen

Kategorien

Keine Kategorien vorhanden.

Bei neuem Item werden Kategorien automatisch basierend auf der Item-ID gesetzt

'publish']; if (!empty($current_category)) $fetch_args['category_slug'] = $current_category; if (!empty($search_query)) $fetch_args['search'] = $search_query; $total_items = WIS_DB::count_items($fetch_args); $total_pages = max(1, (int) ceil($total_items / $per_page)); $current_page = min($current_page, $total_pages); $offset = ($current_page - 1) * $per_page; global $wpdb; $table_items = $wpdb->prefix . 'wis_items'; $where_parts = ["status = 'publish'"]; if (!empty($current_category)) { $search_pattern = '%"' . $current_category . '"%'; $where_parts[] = $wpdb->prepare("categories LIKE %s", $search_pattern); } if (!empty($search_query)) { $search_like = '%' . $wpdb->esc_like($search_query) . '%'; $where_parts[] = $wpdb->prepare("(name LIKE %s OR item_id LIKE %s)", $search_like, $search_like); } $where_sql = implode(" AND ", $where_parts); $items = $wpdb->get_results($wpdb->prepare( "SELECT * FROM $table_items WHERE $where_sql ORDER BY name ASC LIMIT %d OFFSET %d", $per_page, $offset )); $currency = get_option('wis_currency_name', 'Coins'); $base_url = admin_url('admin.php?page=wis_items'); if (!empty($current_category)) $base_url .= '&wis_category=' . urlencode($current_category); if (!empty($search_query)) $base_url .= '&wis_search=' . urlencode($search_query); ?>

Items Neu erstellen

✕ Zurücksetzen
Item(s) gefunden – Suche:

1): ?> Einträge 1): ?> « Seite von » Einträge

ID Name Item ID Preis Status Aktionen
id); ?> name); ?> item_id); ?> price); ?> status === 'publish'): ?> ✅ Aktiv 📝 Entwurf Bearbeiten Löschen
1): ?>
Einträge 1): ?> « Seite von »

✅ Server erstellt!

'; } if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'delete') { check_admin_referer('wis_server_action', '_wpnonce'); WIS_DB::delete_server(intval($_GET['id'])); echo '

✅ Server gelöscht!

'; } $servers = WIS_DB::get_servers(); ?>

Server

Neuen Server erstellen

Kleinbuchstaben ohne Leerzeichen

Vorhandene Server

ID Name Slug Aktionen
Noch keine Server vorhanden.
id); ?> name); ?> slug); ?> Löschen

✅ Kategorie erstellt!

'; } if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'delete') { check_admin_referer('wis_category_action', '_wpnonce'); WIS_DB::delete_category(intval($_GET['id'])); echo '

✅ Kategorie gelöscht!

'; } $categories = WIS_DB::get_categories(); ?>

Kategorien

Neue Kategorie erstellen

Vorhandene Kategorien

ID Name Slug Aktionen
Noch keine Kategorien vorhanden.
id); ?> name); ?> slug); ?> Löschen
sanitize_text_field($_POST['code']), 'value' => intval($_POST['value']), 'type' => sanitize_text_field($_POST['type']), 'usage_limit' => intval($_POST['usage_limit']), 'expiry' => !empty($_POST['expiry']) ? sanitize_text_field($_POST['expiry']) : null ]; if (isset($_GET['edit'])) { unset($data['used_count']); WIS_DB::update_coupon(intval($_GET['edit']), $data); echo '

✅ Gutschein gespeichert!

'; } else { $data['used_count'] = 0; WIS_DB::insert_coupon($data); echo '

✅ Gutschein erstellt!

'; } } if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'delete') { check_admin_referer('wis_coupon_action', '_wpnonce'); WIS_DB::delete_coupon(intval($_GET['id'])); echo '

✅ Gutschein gelöscht!

'; } if (isset($_GET['add']) || isset($_GET['edit'])) { global $wpdb; $coupon = isset($_GET['edit']) ? $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wis_coupons WHERE id = %d", intval($_GET['edit']))) : null; $currency = get_option('wis_currency_name', 'Coins'); ?>

← Zurück zur Liste

Z.B.: SUMMER20

Bei Festbetrag: Betrag in . Bei Prozent: Zahl ohne %

Optional

Gutscheine Neu erstellen

Code Rabatt Genutzt Gültig bis Aktionen
Noch keine Gutscheine vorhanden.
code); ?> type === 'percent'): ?> value); ?>% value); ?> used_count); ?> / usage_limit); ?> expiry ? esc_html(date('d.m.Y', strtotime($coupon->expiry))) : '∞'; ?> Bearbeiten Löschen

✅ Bestellung gelöscht!

'; } if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'complete') { check_admin_referer('wis_order_action', '_wpnonce'); WIS_DB::update_order_status(intval($_GET['id']), 'completed'); echo '

✅ Status geändert!

'; } if (isset($_GET['view'])) { $order = WIS_DB::get_order(intval($_GET['view'])); if (!$order) { echo '

Bestellung nicht gefunden.

'; return; } $currency = get_option('wis_currency_name', 'Coins'); $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' ]; ?>

Bestellung #id; ?> - Details

← Zurück
IDid); ?>
Datumcreated_at))); ?>
Spielerplayer_name); ?>
Serverserver); ?>
Zusammenfassungitem_title); ?>
Preisprice); ?>
Statusstatus] ?? $order->status; ?>
Details (JSON) response); ?>

Bestellungen

'Warte', 'claimed' => '📡 Abgeholt', 'processing' => 'Geben...', 'completed' => 'Fertig', 'cancelled' => 'Abgebrochen', 'failed' => 'Fehler' ]; $status_colors = [ 'pending' => '#ffc107', 'claimed' => '#17a2b8', 'processing' => '#0073aa', 'completed' => 'green', 'cancelled' => 'red', 'failed' => 'red' ]; ?>
Datum Spieler Inhalt Preis Status Aktionen
Noch keine Bestellungen vorhanden.
created_at))); ?> player_name); ?> item_title, 0, 50)) . (strlen($order->item_title) > 50 ? '...' : ''); ?> price); ?> status] ?? $order->status; ?> 👁️ Details 🗑️ Löschen
'publish']); $img_base = get_option('wis_image_base_url', ''); $json_data = ['items' => []]; foreach ($items as $item) { $img_name = str_replace(':', '_', $item->item_id) . '.png'; $json_data['items'][] = [ 'id' => $item->item_id, 'name' => $item->name, 'description' => $item->description, 'price' => intval($item->price), 'image' => $img_base . $img_name ]; } $json_output = json_encode($json_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); echo '

📦 JSON Export

'; echo '

✅ JSON erfolgreich generiert!

'; echo ''; echo '

'; echo ''; echo '

📤 Nächste Schritte:

'; echo '
    '; echo '
  1. Lade die JSON-Datei herunter
  2. '; echo '
  3. Gehe zu deinem Gitea Repository
  4. '; echo '
  5. Lade die items.json hoch unter: https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro
  6. '; echo '
  7. Klicke dann auf den Quick-Import Button unten!
  8. '; echo '
'; echo '
'; return; } $default_url = 'https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro/raw/branch/main/items.json'; ?>

📦 JSON Export/Import

📤 JSON Export

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:

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
'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(); ?>
is_daily_deal): ?>
🎁 DAILY DEAL
is_offer): ?>
🔥 ANGEBOT
<?php echo esc_attr($item->name); ?>

name); ?>

price); ?>
🛒

Kein Angebot verfügbar.

'; } echo $args['after_widget']; } public function form($instance) { $title = !empty($instance['title']) ? $instance['title'] : '🔥 Angebot des Tages'; $btn_text = !empty($instance['btn_text']) ? $instance['btn_text'] : 'Zum Shop'; $shop_url = !empty($instance['shop_url']) ? $instance['shop_url'] : ''; ?>