3385 lines
168 KiB
PHP
3385 lines
168 KiB
PHP
<?php
|
||
/*
|
||
Plugin Name: WP Ingame Shop Pro
|
||
Plugin URI: https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro
|
||
Description: Vollautomatischer Shop mit Warenkorb + eigener DB-Struktur (SPIGOT COMPATIBLE)
|
||
Version: 2.1.2
|
||
Author: M_Viper
|
||
Author URI: https://m-viper.de
|
||
Requires at least: 6.9.1
|
||
Tested up to: 6.9.1
|
||
Requires PHP: 7.4
|
||
License: GPL-2.0-or-later
|
||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||
Text Domain: WP-Ingame-Shop-Pro
|
||
Tags: shop, items, minecraft, coupons, deals, categories
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) exit;
|
||
|
||
// Plugin Constants
|
||
define('WIS_VERSION', '2.1.2');
|
||
define('WIS_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||
define('WIS_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||
|
||
// ===========================================================
|
||
// ACTIVATION & DATABASE
|
||
// ===========================================================
|
||
class WIS_Activator {
|
||
public static function activate() {
|
||
self::create_tables();
|
||
self::set_default_options();
|
||
self::create_default_categories();
|
||
|
||
if (!wp_next_scheduled('wis_daily_deal_event')) {
|
||
wp_schedule_event(time(), 'daily', 'wis_daily_deal_event');
|
||
}
|
||
flush_rewrite_rules();
|
||
}
|
||
|
||
public static function deactivate() {
|
||
wp_clear_scheduled_hook('wis_daily_deal_event');
|
||
flush_rewrite_rules();
|
||
}
|
||
|
||
private static function create_tables() {
|
||
global $wpdb;
|
||
$charset_collate = $wpdb->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 '<div class="updated"><p>✅ Einstellungen gespeichert!</p></div>';
|
||
}
|
||
|
||
if (isset($_POST['wis_regen_key']) && check_admin_referer('wis_regen_key')) {
|
||
update_option('wis_api_key', bin2hex(random_bytes(24)));
|
||
echo '<div class="updated"><p>🔑 Neuer API-Key generiert! Bitte in der config.yml des Spigot-Plugins aktualisieren.</p></div>';
|
||
}
|
||
|
||
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")
|
||
];
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1>🛒 WP Ingame Shop Pro <span style="color:#28a745;">v<?php echo WIS_VERSION; ?></span></h1>
|
||
|
||
<div class="card" style="max-width:800px; margin-top:20px;">
|
||
<h2>📊 Statistiken</h2>
|
||
<table class="widefat">
|
||
<tr><th>Items im Shop:</th><td><strong><?php echo $stats['items']; ?></strong></td></tr>
|
||
<tr><th>Bestellungen:</th><td><strong><?php echo $stats['orders']; ?></strong></td></tr>
|
||
<tr><th>Server:</th><td><strong><?php echo $stats['servers']; ?></strong></td></tr>
|
||
<tr><th>Gutscheine:</th><td><strong><?php echo $stats['coupons']; ?></strong></td></tr>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="card" style="max-width:800px; margin-top:20px; padding:20px;">
|
||
<h2>⚙️ Einstellungen</h2>
|
||
<form method="post">
|
||
<?php wp_nonce_field('wis_settings'); ?>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th><label for="header_text">Shop Header Text</label></th>
|
||
<td>
|
||
<textarea id="header_text" name="wis_header_text" class="large-text" rows="2"><?php echo esc_textarea(get_option('wis_header_text')); ?></textarea>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="currency">Währungsname</label></th>
|
||
<td>
|
||
<input type="text" id="currency" name="wis_currency_name" value="<?php echo esc_attr(get_option('wis_currency_name')); ?>" class="regular-text">
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="image_url">Bilder Basis-URL</label></th>
|
||
<td>
|
||
<input type="text" id="image_url" name="wis_image_base_url" value="<?php echo esc_attr(get_option('wis_image_base_url')); ?>" class="large-text code">
|
||
<p class="description">Muss mit / enden! Z.B.: https://git.viper.ipv64.net/.../images/</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>Gutscheine bei Angeboten</th>
|
||
<td>
|
||
<label>
|
||
<input type="checkbox" name="wis_coupon_exclude_offers" value="1" <?php checked(get_option('wis_coupon_exclude_offers'), '1'); ?>>
|
||
Gutscheine NICHT auf Angebote anwenden
|
||
</label>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>Daily Deal</th>
|
||
<td>
|
||
<label>
|
||
<input type="checkbox" name="wis_daily_deal_enabled" value="1" <?php checked(get_option('wis_daily_deal_enabled'), '1'); ?>>
|
||
Automatisches Tagesangebot aktivieren
|
||
</label>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="discount">Daily Deal Rabatt (%)</label></th>
|
||
<td>
|
||
<input type="number" id="discount" name="wis_daily_deal_discount" value="<?php echo esc_attr(get_option('wis_daily_deal_discount', 20)); ?>" min="1" max="99">
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>Offline-Queue</th>
|
||
<td>
|
||
<label>
|
||
<input type="checkbox" name="wis_offline_queue_enabled" value="1" <?php checked(get_option('wis_offline_queue_enabled', '0'), '1'); ?>>
|
||
Items auch an offline Spieler liefern (beim nächsten Login)
|
||
</label>
|
||
<p class="description">Erfordert Spigot-Plugin v6.3+ mit Offline-Queue-Unterstützung</p>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<p class="submit">
|
||
<input type="submit" name="wis_save_settings" class="button button-primary" value="Einstellungen speichern">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card" style="max-width:800px; margin-top:20px; padding:20px; border-left:4px solid #0073aa;">
|
||
<h2>🔑 Spigot API-Key</h2>
|
||
<p>Dieser Key muss in der <code>config.yml</code> des Spigot-Plugins als <code>api-key</code> eingetragen werden.</p>
|
||
<div style="display:flex; align-items:center; gap:10px; margin:10px 0;">
|
||
<input type="text"
|
||
id="wis-api-key-field"
|
||
value="<?php echo esc_attr(get_option('wis_api_key', '')); ?>"
|
||
class="large-text code"
|
||
readonly
|
||
style="font-family:monospace; background:#f0f4f8;">
|
||
<button type="button" class="button" onclick="
|
||
const f = document.getElementById('wis-api-key-field');
|
||
f.type='text'; f.select();
|
||
document.execCommand('copy');
|
||
this.textContent='✅ Kopiert!';
|
||
setTimeout(()=>this.textContent='📋 Kopieren',2000);
|
||
">📋 Kopieren</button>
|
||
</div>
|
||
<form method="post" onsubmit="return confirm('Neuen Key generieren? Das Spigot-Plugin muss danach neu konfiguriert werden!');">
|
||
<?php wp_nonce_field('wis_regen_key'); ?>
|
||
<input type="submit" name="wis_regen_key" class="button button-secondary" value="🔄 Neuen Key generieren">
|
||
</form>
|
||
<p class="description" style="margin-top:10px;">
|
||
Geschützte Endpunkte: <code>pending_orders</code>, <code>execute_order</code>, <code>complete_order</code>, <code>cancel_order</code>, <code>pending_offline</code>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
public static function page_items() {
|
||
if (isset($_POST['wis_bulk_save']) && check_admin_referer('wis_bulk_edit')) {
|
||
$ids = isset($_POST['item_ids']) ? array_map('intval', $_POST['item_ids']) : [];
|
||
$action = sanitize_text_field($_POST['bulk_action_type']);
|
||
|
||
if (!empty($ids) && !empty($action)) {
|
||
$count = 0;
|
||
foreach ($ids as $id) {
|
||
$data = [];
|
||
|
||
switch ($action) {
|
||
case 'price':
|
||
if (isset($_POST['item_prices'][$id])) {
|
||
$new_price = intval($_POST['item_prices'][$id]);
|
||
if ($new_price >= 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 '<div class="updated"><p>✅ ' . $count . ' Items erfolgreich aktualisiert!</p></div>';
|
||
}
|
||
}
|
||
|
||
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]);
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1>📦 Mehrfachbearbeitung</h1>
|
||
<p><strong>Aktion:</strong> <?php echo esc_html(ucfirst($action)); ?> für <?php echo count($selected_ids); ?> Items.</p>
|
||
|
||
<div class="card" style="max-width:2000px; padding:20px; margin-top:20px;">
|
||
<form method="post">
|
||
<?php wp_nonce_field('wis_bulk_edit'); ?>
|
||
<input type="hidden" name="bulk_action_type" value="<?php echo esc_attr($action); ?>">
|
||
|
||
<?php foreach ($selected_ids as $id): ?>
|
||
<input type="hidden" name="item_ids[]" value="<?php echo $id; ?>">
|
||
<?php endforeach; ?>
|
||
|
||
<table class="form-table">
|
||
<?php if ($action === 'price'): ?>
|
||
<tr>
|
||
<th colspan="2"><h3>Preis pro Item festlegen</h3></th>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="2" style="padding:0;">
|
||
<div style="max-height:800px; overflow-y:auto; border:1px solid #ddd; padding:10px;">
|
||
<table class="widefat striped">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:50%">Item Name</th>
|
||
<th style="width:25%">Aktueller Preis</th>
|
||
<th style="width:25%">Neuer Preis (<?php echo esc_html($currency); ?>)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach($items_to_edit as $item): ?>
|
||
<tr>
|
||
<td>
|
||
<strong><?php echo esc_html($item->name); ?></strong><br>
|
||
<small style="color:#666"><?php echo esc_html($item->item_id); ?></small>
|
||
</td>
|
||
<td><?php echo esc_html($item->price); ?> <?php echo esc_html($currency); ?></td>
|
||
<td>
|
||
<input type="number"
|
||
name="item_prices[<?php echo $item->id; ?>]"
|
||
value="<?php echo esc_attr($item->price); ?>"
|
||
min="0"
|
||
style="width:100%; padding:5px;">
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
|
||
<?php elseif ($action === 'offer'): ?>
|
||
<tr>
|
||
<th colspan="2"><h3>Angebot pro Item festlegen</h3></th>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="2" style="padding:0;">
|
||
<div style="max-height:800px; overflow-y:auto; border:1px solid #ddd; padding:10px;">
|
||
<table class="widefat striped">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:40%">Item Name</th>
|
||
<th style="width:20%">Normalpreis</th>
|
||
<th style="width:20%">Als Angebot?</th>
|
||
<th style="width:20%">Angebotspreis</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach($items_to_edit as $item): ?>
|
||
<tr>
|
||
<td>
|
||
<strong><?php echo esc_html($item->name); ?></strong><br>
|
||
<small style="color:#666"><?php echo esc_html($item->item_id); ?></small>
|
||
</td>
|
||
<td><?php echo esc_html($item->price); ?> <?php echo esc_html($currency); ?></td>
|
||
<td>
|
||
<input type="checkbox"
|
||
name="item_offers[<?php echo $item->id; ?>]"
|
||
value="1"
|
||
<?php checked($item->is_offer, 1); ?>
|
||
onchange="toggleOfferPrice(this, <?php echo $item->id; ?>)">
|
||
</td>
|
||
<td>
|
||
<input type="number"
|
||
name="item_offer_prices[<?php echo $item->id; ?>]"
|
||
id="offer_price_<?php echo $item->id; ?>"
|
||
value="<?php echo esc_attr($item->offer_price); ?>"
|
||
min="0"
|
||
style="width:100%; padding:5px;"
|
||
<?php if(!$item->is_offer): ?>disabled<?php endif; ?>>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<script>
|
||
function toggleOfferPrice(checkbox, itemId) {
|
||
const input = document.getElementById('offer_price_' + itemId);
|
||
input.disabled = !checkbox.checked;
|
||
}
|
||
</script>
|
||
</td>
|
||
</tr>
|
||
|
||
<?php elseif ($action === 'status'): ?>
|
||
<tr>
|
||
<th><label>Neuer Status für alle ausgewählten Items</label></th>
|
||
<td>
|
||
<select name="bulk_status">
|
||
<option value="publish">Aktivieren (Publish)</option>
|
||
<option value="draft">Deaktivieren (Draft)</option>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
|
||
<?php elseif ($action === 'server'): ?>
|
||
<tr>
|
||
<th colspan="2"><h3>Server pro Item zuweisen</h3></th>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="2" style="padding:0;">
|
||
<?php if (empty($all_servers)): ?>
|
||
<p>Keine Server vorhanden.</p>
|
||
<?php else: ?>
|
||
<div style="max-height:800px; overflow-y:auto; border:1px solid #ddd; padding:10px;">
|
||
<table class="widefat striped">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:40%">Item Name</th>
|
||
<th style="width:60%">Server (Mehrfachauswahl möglich)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach($items_to_edit as $item):
|
||
$current_servers = json_decode($item->servers, true) ?: [];
|
||
?>
|
||
<tr>
|
||
<td>
|
||
<strong><?php echo esc_html($item->name); ?></strong><br>
|
||
<small style="color:#666"><?php echo esc_html($item->item_id); ?></small>
|
||
</td>
|
||
<td>
|
||
<?php foreach ($all_servers as $s):
|
||
$checked = in_array($s->slug, $current_servers) ? 'checked' : '';
|
||
?>
|
||
<label style="display:inline-block; margin-right:15px; margin-bottom:5px;">
|
||
<input type="checkbox"
|
||
name="item_servers[<?php echo $item->id; ?>][]"
|
||
value="<?php echo esc_attr($s->slug); ?>"
|
||
<?php echo $checked; ?>>
|
||
<?php echo esc_html($s->name); ?>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
|
||
<?php elseif ($action === 'category'): ?>
|
||
<tr>
|
||
<th colspan="2"><h3>Kategorien pro Item zuweisen</h3></th>
|
||
</tr>
|
||
<tr>
|
||
<td colspan="2" style="padding:0;">
|
||
<div style="max-height:800px; overflow-y:auto; border:1px solid #ddd; padding:10px;">
|
||
<?php if(empty($items_to_edit)): ?>
|
||
<p>Fehler beim Laden der Items.</p>
|
||
<?php else: ?>
|
||
<table class="widefat striped">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:35%">Item Name</th>
|
||
<th style="width:65%">Kategorie (Mehrfachauswahl mit STRG+Klick)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php foreach($items_to_edit as $item):
|
||
$current_cats = json_decode($item->categories, true) ?: [];
|
||
?>
|
||
<tr>
|
||
<td>
|
||
<strong><?php echo esc_html($item->name); ?></strong><br>
|
||
<small style="color:#666"><?php echo esc_html($item->item_id); ?></small>
|
||
</td>
|
||
<td>
|
||
<select name="item_cat_assignments[<?php echo $item->id; ?>][]" multiple style="height:250px; width:100%; font-size:14px; padding:5px;">
|
||
<?php foreach($all_categories as $cat):
|
||
$selected = in_array($cat->slug, $current_cats) ? 'selected' : '';
|
||
?>
|
||
<option value="<?php echo esc_attr($cat->slug); ?>" <?php echo $selected; ?>>
|
||
<?php echo esc_html($cat->name); ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
</tbody>
|
||
</table>
|
||
<?php endif; ?>
|
||
</div>
|
||
</td>
|
||
</tr>
|
||
<?php endif; ?>
|
||
</table>
|
||
|
||
<p class="submit">
|
||
<a href="<?php echo admin_url('admin.php?page=wis_items'); ?>" class="button">Abbrechen</a>
|
||
<input type="submit" name="wis_bulk_save" class="button button-primary" value="Jetzt ändern">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
return;
|
||
}
|
||
|
||
if (isset($_GET['action'], $_GET['id'], $_GET['_wpnonce'])) {
|
||
if (!wp_verify_nonce($_GET['_wpnonce'], 'wis_item_action')) {
|
||
wp_die('Security check failed');
|
||
}
|
||
|
||
$id = intval($_GET['id']);
|
||
|
||
if ($_GET['action'] === 'delete') {
|
||
WIS_DB::delete_item($id);
|
||
echo '<div class="updated"><p>✅ Item gelöscht!</p></div>';
|
||
} 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 '<div class="updated"><p>✅ Status geändert!</p></div>';
|
||
}
|
||
}
|
||
|
||
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 '<div class="updated"><p>✅ Item gespeichert!</p></div>';
|
||
} else {
|
||
WIS_DB::insert_item($data);
|
||
echo '<div class="updated"><p>✅ Item erstellt!</p></div>';
|
||
}
|
||
}
|
||
|
||
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 = [];
|
||
}
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1><?php echo $item ? 'Item bearbeiten' : 'Neues Item'; ?></h1>
|
||
<a href="<?php echo admin_url('admin.php?page=wis_items'); ?>" class="button">← Zurück zur Liste</a>
|
||
|
||
<form method="post" style="max-width:800px; margin-top:20px;">
|
||
<?php wp_nonce_field('wis_item_form'); ?>
|
||
|
||
<table class="form-table">
|
||
<tr>
|
||
<th><label for="name">Name *</label></th>
|
||
<td><input type="text" id="name" name="name" value="<?php echo $item ? esc_attr($item->name) : ''; ?>" class="regular-text" required></td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="item_id">Item ID *</label></th>
|
||
<td>
|
||
<input type="text" id="item_id" name="item_id" value="<?php echo $item ? esc_attr($item->item_id) : ''; ?>" class="regular-text" placeholder="minecraft:diamond" required>
|
||
<p class="description">Z.B.: minecraft:diamond (Kategorien werden automatisch zugewiesen)</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="description">Beschreibung</label></th>
|
||
<td><textarea id="description" name="description" rows="3" class="large-text"><?php echo $item ? esc_textarea($item->description) : ''; ?></textarea></td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="price">Preis (<?php echo esc_html($currency); ?>) *</label></th>
|
||
<td><input type="number" id="price" name="price" value="<?php echo $item ? esc_attr($item->price) : '0'; ?>" min="0" required></td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="offer_price">Angebotspreis</label></th>
|
||
<td>
|
||
<input type="number" id="offer_price" name="offer_price" value="<?php echo $item ? esc_attr($item->offer_price) : '0'; ?>" min="0">
|
||
<p class="description">Optional: Wenn gesetzt, wird der normale Preis durchgestrichen</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>Markierungen</th>
|
||
<td>
|
||
<label>
|
||
<input type="checkbox" name="is_offer" value="1" <?php echo ($item && $item->is_offer) ? 'checked' : ''; ?>>
|
||
Als Angebot markieren
|
||
</label>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>Server</th>
|
||
<td>
|
||
<?php if (empty($servers)): ?>
|
||
<p>Keine Server vorhanden. <a href="<?php echo admin_url('admin.php?page=wis_servers'); ?>">Server erstellen</a></p>
|
||
<?php else: ?>
|
||
<?php foreach ($servers as $server): ?>
|
||
<label style="display:block; margin:5px 0;">
|
||
<input type="checkbox" name="servers[]" value="<?php echo esc_attr($server->slug); ?>" <?php echo in_array($server->slug, $item_servers ?: []) ? 'checked' : ''; ?>>
|
||
<?php echo esc_html($server->name); ?>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th>Kategorien</th>
|
||
<td>
|
||
<?php if (empty($categories)): ?>
|
||
<p>Keine Kategorien vorhanden.</p>
|
||
<?php else: ?>
|
||
<?php foreach ($categories as $cat): ?>
|
||
<label style="display:block; margin:5px 0;">
|
||
<input type="checkbox" name="categories[]" value="<?php echo esc_attr($cat->slug); ?>" <?php echo in_array($cat->slug, $item_cats ?: []) ? 'checked' : ''; ?>>
|
||
<?php echo esc_html($cat->name); ?>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
<p class="description">Bei neuem Item werden Kategorien automatisch basierend auf der Item-ID gesetzt</p>
|
||
<?php endif; ?>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
|
||
<p class="submit">
|
||
<input type="submit" name="wis_save_item" class="button button-primary" value="Speichern">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
return;
|
||
}
|
||
|
||
// Liste mit Suche + Pagination
|
||
$categories = WIS_DB::get_categories();
|
||
$current_category = isset($_GET['wis_category']) ? sanitize_text_field($_GET['wis_category']) : '';
|
||
$search_query = isset($_GET['wis_search']) ? sanitize_text_field($_GET['wis_search']) : '';
|
||
$per_page = 24;
|
||
$current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
|
||
|
||
$fetch_args = ['status' => '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);
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Items
|
||
<a href="<?php echo admin_url('admin.php?page=wis_items&add=1'); ?>" class="page-title-action">Neu erstellen</a>
|
||
</h1>
|
||
|
||
<div style="margin:10px 0 15px; display:flex; align-items:center; gap:10px; flex-wrap:wrap;">
|
||
<form method="get" style="display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
|
||
<input type="hidden" name="page" value="wis_items">
|
||
<?php if (!empty($current_category)): ?>
|
||
<input type="hidden" name="wis_category" value="<?php echo esc_attr($current_category); ?>">
|
||
<?php endif; ?>
|
||
<input
|
||
type="search"
|
||
name="wis_search"
|
||
value="<?php echo esc_attr($search_query); ?>"
|
||
placeholder="🔍 Item suchen (Name oder ID)…"
|
||
class="regular-text"
|
||
style="min-width:280px; padding:6px 10px;">
|
||
<input type="submit" class="button" value="Suchen">
|
||
<?php if (!empty($search_query)): ?>
|
||
<a href="<?php echo esc_url(admin_url('admin.php?page=wis_items' . (!empty($current_category) ? '&wis_category=' . urlencode($current_category) : ''))); ?>" class="button">✕ Zurücksetzen</a>
|
||
<?php endif; ?>
|
||
</form>
|
||
<span style="color:#666; font-size:13px;">
|
||
<?php echo $total_items; ?> Item(s) gefunden
|
||
<?php if (!empty($search_query)): ?>
|
||
– Suche: <strong><?php echo esc_html($search_query); ?></strong>
|
||
<?php endif; ?>
|
||
</span>
|
||
</div>
|
||
|
||
<nav class="nav-tab-wrapper">
|
||
<a href="<?php echo admin_url('admin.php?page=wis_items' . (!empty($search_query) ? '&wis_search=' . urlencode($search_query) : '')); ?>" class="nav-tab <?php echo $current_category === '' ? 'nav-tab-active' : ''; ?>">
|
||
Alle
|
||
</a>
|
||
<?php foreach ($categories as $cat): ?>
|
||
<a href="<?php echo admin_url('admin.php?page=wis_items&wis_category=' . $cat->slug . (!empty($search_query) ? '&wis_search=' . urlencode($search_query) : '')); ?>" class="nav-tab <?php echo $current_category === $cat->slug ? 'nav-tab-active' : ''; ?>">
|
||
<?php echo esc_html($cat->name); ?>
|
||
</a>
|
||
<?php endforeach; ?>
|
||
</nav>
|
||
<br>
|
||
|
||
<form method="post">
|
||
<div class="tablenav top">
|
||
<div class="alignleft actions bulkactions">
|
||
<label for="bulk-action-selector-top" class="screen-reader-text">Massenaktionen wählen</label>
|
||
<select name="wis_bulk_action" id="bulk-action-selector-top">
|
||
<option value="">Massenaktionen</option>
|
||
<option value="price">Preis ändern</option>
|
||
<option value="offer">Angebot ändern</option>
|
||
<option value="server">Server zuweisen</option>
|
||
<option value="category">Kategorie zuweisen</option>
|
||
<option value="status">Aktivieren/Deaktivieren</option>
|
||
</select>
|
||
<input type="submit" name="wis_bulk_apply" class="button action" value="Anwenden">
|
||
</div>
|
||
|
||
<div class="tablenav-pages" style="float:right; margin-top:4px;">
|
||
<?php if ($total_pages > 1): ?>
|
||
<span class="displaying-num"><?php echo $total_items; ?> Einträge</span>
|
||
<span class="pagination-links">
|
||
<?php if ($current_page > 1): ?>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=1'); ?>">«</a>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=' . ($current_page - 1)); ?>">‹</a>
|
||
<?php endif; ?>
|
||
<span class="paging-input" style="margin:0 6px;">
|
||
Seite <strong><?php echo $current_page; ?></strong> von <strong><?php echo $total_pages; ?></strong>
|
||
</span>
|
||
<?php if ($current_page < $total_pages): ?>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=' . ($current_page + 1)); ?>">›</a>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=' . $total_pages); ?>">»</a>
|
||
<?php endif; ?>
|
||
</span>
|
||
<?php else: ?>
|
||
<span class="displaying-num"><?php echo $total_items; ?> Einträge</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<br class="clear">
|
||
</div>
|
||
|
||
<table class="widefat fixed striped">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:40px;" class="manage-column column-cb check-column">
|
||
<input type="checkbox" id="cb-select-all-1">
|
||
</th>
|
||
<th>ID</th>
|
||
<th>Name</th>
|
||
<th>Item ID</th>
|
||
<th>Preis</th>
|
||
<th>Status</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (empty($items)): ?>
|
||
<tr><td colspan="7" style="text-align:center; padding:40px;">
|
||
<?php echo !empty($search_query) ? 'Keine Items für diese Suche gefunden.' : 'Keine Items in dieser Kategorie gefunden.'; ?>
|
||
</td></tr>
|
||
<?php else: ?>
|
||
<?php foreach ($items as $item): ?>
|
||
<tr>
|
||
<th class="check-column">
|
||
<input type="checkbox" name="item_ids[]" id="cb-select-<?php echo $item->id; ?>" value="<?php echo $item->id; ?>">
|
||
</th>
|
||
<td><?php echo esc_html($item->id); ?></td>
|
||
<td><strong><?php echo esc_html($item->name); ?></strong></td>
|
||
<td><code><?php echo esc_html($item->item_id); ?></code></td>
|
||
<td><?php echo esc_html($item->price); ?> <?php echo esc_html($currency); ?></td>
|
||
<td>
|
||
<?php if ($item->status === 'publish'): ?>
|
||
<span style="color:green;">✅ Aktiv</span>
|
||
<?php else: ?>
|
||
<span style="color:orange;">📝 Entwurf</span>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td>
|
||
<a href="<?php echo wp_nonce_url(admin_url('admin.php?page=wis_items&edit=' . $item->id), 'wis_item_action', '_wpnonce'); ?>" class="button button-small">Bearbeiten</a>
|
||
<a href="<?php echo wp_nonce_url(admin_url('admin.php?page=wis_items&action=delete&id=' . $item->id), 'wis_item_action', '_wpnonce'); ?>" class="button button-small" onclick="return confirm('Wirklich löschen?');" style="color:red;">Löschen</a>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
|
||
<?php if ($total_pages > 1): ?>
|
||
<div class="tablenav bottom">
|
||
<div class="tablenav-pages" style="float:right; margin-top:8px;">
|
||
<span class="displaying-num"><?php echo $total_items; ?> Einträge</span>
|
||
<span class="pagination-links">
|
||
<?php if ($current_page > 1): ?>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=1'); ?>">«</a>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=' . ($current_page - 1)); ?>">‹</a>
|
||
<?php endif; ?>
|
||
<span class="paging-input" style="margin:0 6px;">
|
||
Seite <strong><?php echo $current_page; ?></strong> von <strong><?php echo $total_pages; ?></strong>
|
||
</span>
|
||
<?php if ($current_page < $total_pages): ?>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=' . ($current_page + 1)); ?>">›</a>
|
||
<a class="button" href="<?php echo esc_url($base_url . '&paged=' . $total_pages); ?>">»</a>
|
||
<?php endif; ?>
|
||
</span>
|
||
</div>
|
||
<br class="clear">
|
||
</div>
|
||
<?php endif; ?>
|
||
</form>
|
||
</div>
|
||
|
||
<script>
|
||
(function() {
|
||
const mainCb = document.getElementById('cb-select-all-1');
|
||
if(mainCb) {
|
||
mainCb.addEventListener('change', function(e) {
|
||
const cbs = document.querySelectorAll('input[name="item_ids[]"]');
|
||
cbs.forEach(cb => cb.checked = e.target.checked);
|
||
});
|
||
}
|
||
})();
|
||
</script>
|
||
<?php
|
||
}
|
||
|
||
public static function page_servers() {
|
||
if (isset($_POST['wis_add_server'])) {
|
||
check_admin_referer('wis_server_form');
|
||
WIS_DB::insert_server($_POST['slug'], $_POST['name']);
|
||
echo '<div class="updated"><p>✅ Server erstellt!</p></div>';
|
||
}
|
||
|
||
if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'delete') {
|
||
check_admin_referer('wis_server_action', '_wpnonce');
|
||
WIS_DB::delete_server(intval($_GET['id']));
|
||
echo '<div class="updated"><p>✅ Server gelöscht!</p></div>';
|
||
}
|
||
|
||
$servers = WIS_DB::get_servers();
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Server</h1>
|
||
|
||
<div class="card" style="max-width:600px; padding:20px; margin-top:20px;">
|
||
<h2>Neuen Server erstellen</h2>
|
||
<form method="post">
|
||
<?php wp_nonce_field('wis_server_form'); ?>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th><label for="name">Name *</label></th>
|
||
<td><input type="text" id="name" name="name" class="regular-text" required></td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="slug">Slug *</label></th>
|
||
<td>
|
||
<input type="text" id="slug" name="slug" class="regular-text" placeholder="survival" required>
|
||
<p class="description">Kleinbuchstaben ohne Leerzeichen</p>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<p class="submit">
|
||
<input type="submit" name="wis_add_server" class="button button-primary" value="Server erstellen">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
|
||
<h2 style="margin-top:40px;">Vorhandene Server</h2>
|
||
<table class="widefat fixed striped">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Name</th>
|
||
<th>Slug</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (empty($servers)): ?>
|
||
<tr><td colspan="4" style="text-align:center; padding:40px;">Noch keine Server vorhanden.</td></tr>
|
||
<?php else: ?>
|
||
<?php foreach ($servers as $server): ?>
|
||
<tr>
|
||
<td><?php echo esc_html($server->id); ?></td>
|
||
<td><strong><?php echo esc_html($server->name); ?></strong></td>
|
||
<td><code><?php echo esc_html($server->slug); ?></code></td>
|
||
<td>
|
||
<a href="<?php echo wp_nonce_url(admin_url('admin.php?page=wis_servers&action=delete&id=' . $server->id), 'wis_server_action', '_wpnonce'); ?>" class="button button-small" onclick="return confirm('Wirklich löschen?');" style="color:red;">Löschen</a>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
public static function page_categories() {
|
||
if (isset($_POST['wis_add_category'])) {
|
||
check_admin_referer('wis_category_form');
|
||
WIS_DB::insert_category($_POST['name']);
|
||
echo '<div class="updated"><p>✅ Kategorie erstellt!</p></div>';
|
||
}
|
||
|
||
if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'delete') {
|
||
check_admin_referer('wis_category_action', '_wpnonce');
|
||
WIS_DB::delete_category(intval($_GET['id']));
|
||
echo '<div class="updated"><p>✅ Kategorie gelöscht!</p></div>';
|
||
}
|
||
|
||
$categories = WIS_DB::get_categories();
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Kategorien</h1>
|
||
|
||
<div class="card" style="max-width:600px; padding:20px; margin-top:20px;">
|
||
<h2>Neue Kategorie erstellen</h2>
|
||
<form method="post">
|
||
<?php wp_nonce_field('wis_category_form'); ?>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th><label for="name">Name *</label></th>
|
||
<td><input type="text" id="name" name="name" class="regular-text" required></td>
|
||
</tr>
|
||
</table>
|
||
<p class="submit">
|
||
<input type="submit" name="wis_add_category" class="button button-primary" value="Kategorie erstellen">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
|
||
<h2 style="margin-top:40px;">Vorhandene Kategorien</h2>
|
||
<table class="widefat fixed striped">
|
||
<thead>
|
||
<tr>
|
||
<th>ID</th>
|
||
<th>Name</th>
|
||
<th>Slug</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (empty($categories)): ?>
|
||
<tr><td colspan="4" style="text-align:center; padding:40px;">Noch keine Kategorien vorhanden.</td></tr>
|
||
<?php else: ?>
|
||
<?php foreach ($categories as $cat): ?>
|
||
<tr>
|
||
<td><?php echo esc_html($cat->id); ?></td>
|
||
<td><strong><?php echo esc_html($cat->name); ?></strong></td>
|
||
<td><code><?php echo esc_html($cat->slug); ?></code></td>
|
||
<td>
|
||
<a href="<?php echo wp_nonce_url(admin_url('admin.php?page=wis_categories&action=delete&id=' . $cat->id), 'wis_category_action', '_wpnonce'); ?>" class="button button-small" onclick="return confirm('Wirklich löschen?');" style="color:red;">Löschen</a>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
public static function page_coupons() {
|
||
if (isset($_POST['wis_save_coupon'])) {
|
||
check_admin_referer('wis_coupon_form');
|
||
|
||
$data = [
|
||
'code' => 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 '<div class="updated"><p>✅ Gutschein gespeichert!</p></div>';
|
||
} else {
|
||
$data['used_count'] = 0;
|
||
WIS_DB::insert_coupon($data);
|
||
echo '<div class="updated"><p>✅ Gutschein erstellt!</p></div>';
|
||
}
|
||
}
|
||
|
||
if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'delete') {
|
||
check_admin_referer('wis_coupon_action', '_wpnonce');
|
||
WIS_DB::delete_coupon(intval($_GET['id']));
|
||
echo '<div class="updated"><p>✅ Gutschein gelöscht!</p></div>';
|
||
}
|
||
|
||
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');
|
||
?>
|
||
<div class="wrap">
|
||
<h1><?php echo $coupon ? 'Gutschein bearbeiten' : 'Neuer Gutschein'; ?></h1>
|
||
<a href="<?php echo admin_url('admin.php?page=wis_coupons'); ?>" class="button">← Zurück zur Liste</a>
|
||
|
||
<form method="post" style="max-width:600px; margin-top:20px;">
|
||
<?php wp_nonce_field('wis_coupon_form'); ?>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th><label for="code">Code *</label></th>
|
||
<td>
|
||
<input type="text" id="code" name="code" value="<?php echo $coupon ? esc_attr($coupon->code) : ''; ?>" class="regular-text" style="text-transform:uppercase;" required>
|
||
<p class="description">Z.B.: SUMMER20</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="type">Typ *</label></th>
|
||
<td>
|
||
<select id="type" name="type" required>
|
||
<option value="fixed" <?php echo ($coupon && $coupon->type === 'fixed') ? 'selected' : ''; ?>>Festbetrag (z.B. 100 <?php echo esc_html($currency); ?> Rabatt)</option>
|
||
<option value="percent" <?php echo ($coupon && $coupon->type === 'percent') ? 'selected' : ''; ?>>Prozentual (z.B. 20% Rabatt)</option>
|
||
</select>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="value">Wert *</label></th>
|
||
<td>
|
||
<input type="number" id="value" name="value" value="<?php echo $coupon ? esc_attr($coupon->value) : ''; ?>" min="1" required>
|
||
<p class="description">Bei Festbetrag: Betrag in <?php echo esc_html($currency); ?>. Bei Prozent: Zahl ohne %</p>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="usage_limit">Nutzungslimit *</label></th>
|
||
<td>
|
||
<input type="number" id="usage_limit" name="usage_limit" value="<?php echo $coupon ? esc_attr($coupon->usage_limit) : '1'; ?>" min="1" required>
|
||
</td>
|
||
</tr>
|
||
<tr>
|
||
<th><label for="expiry">Ablaufdatum</label></th>
|
||
<td>
|
||
<input type="date" id="expiry" name="expiry" value="<?php echo $coupon && $coupon->expiry ? esc_attr($coupon->expiry) : ''; ?>">
|
||
<p class="description">Optional</p>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<p class="submit">
|
||
<input type="submit" name="wis_save_coupon" class="button button-primary" value="Speichern">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
return;
|
||
}
|
||
|
||
$coupons = WIS_DB::get_coupons();
|
||
$currency = get_option('wis_currency_name', 'Coins');
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Gutscheine <a href="<?php echo admin_url('admin.php?page=wis_coupons&add=1'); ?>" class="page-title-action">Neu erstellen</a></h1>
|
||
|
||
<table class="widefat fixed striped">
|
||
<thead>
|
||
<tr>
|
||
<th>Code</th>
|
||
<th>Rabatt</th>
|
||
<th>Genutzt</th>
|
||
<th>Gültig bis</th>
|
||
<th>Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (empty($coupons)): ?>
|
||
<tr><td colspan="5" style="text-align:center; padding:40px;">Noch keine Gutscheine vorhanden.</td></tr>
|
||
<?php else: ?>
|
||
<?php foreach ($coupons as $coupon): ?>
|
||
<tr>
|
||
<td><strong><?php echo esc_html($coupon->code); ?></strong></td>
|
||
<td>
|
||
<?php if ($coupon->type === 'percent'): ?>
|
||
<?php echo esc_html($coupon->value); ?>%
|
||
<?php else: ?>
|
||
<?php echo esc_html($coupon->value); ?> <?php echo esc_html($currency); ?>
|
||
<?php endif; ?>
|
||
</td>
|
||
<td><?php echo esc_html($coupon->used_count); ?> / <?php echo esc_html($coupon->usage_limit); ?></td>
|
||
<td><?php echo $coupon->expiry ? esc_html(date('d.m.Y', strtotime($coupon->expiry))) : '∞'; ?></td>
|
||
<td>
|
||
<a href="<?php echo admin_url('admin.php?page=wis_coupons&edit=' . $coupon->id); ?>" class="button button-small">Bearbeiten</a>
|
||
<a href="<?php echo wp_nonce_url(admin_url('admin.php?page=wis_coupons&action=delete&id=' . $coupon->id), 'wis_coupon_action', '_wpnonce'); ?>" class="button button-small" onclick="return confirm('Wirklich löschen?');" style="color:red;">Löschen</a>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
public static function page_orders() {
|
||
if (isset($_GET['action'], $_GET['id']) && $_GET['action'] === 'delete') {
|
||
check_admin_referer('wis_order_action', '_wpnonce');
|
||
WIS_DB::delete_order(intval($_GET['id']));
|
||
echo '<div class="updated"><p>✅ Bestellung gelöscht!</p></div>';
|
||
}
|
||
|
||
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 '<div class="updated"><p>✅ Status geändert!</p></div>';
|
||
}
|
||
|
||
if (isset($_GET['view'])) {
|
||
$order = WIS_DB::get_order(intval($_GET['view']));
|
||
if (!$order) {
|
||
echo '<div class="error"><p>Bestellung nicht gefunden.</p></div>';
|
||
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'
|
||
];
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Bestellung #<?php echo $order->id; ?> - Details</h1>
|
||
<a href="<?php echo admin_url('admin.php?page=wis_orders'); ?>" class="button">← Zurück</a>
|
||
|
||
<table class="widefat" style="max-width:800px; margin-top:20px;">
|
||
<tr><th>ID</th><td><?php echo esc_html($order->id); ?></td></tr>
|
||
<tr><th>Datum</th><td><?php echo esc_html(date('d.m.Y H:i', strtotime($order->created_at))); ?></td></tr>
|
||
<tr><th>Spieler</th><td><strong><?php echo esc_html($order->player_name); ?></strong></td></tr>
|
||
<tr><th>Server</th><td><?php echo esc_html($order->server); ?></td></tr>
|
||
<tr><th>Zusammenfassung</th><td><?php echo esc_html($order->item_title); ?></td></tr>
|
||
<tr><th>Preis</th><td><?php echo esc_html($order->price); ?> <?php echo esc_html($currency); ?></td></tr>
|
||
<tr><th>Status</th><td style="color:<?php echo $status_colors[$order->status] ?? 'black'; ?>; font-weight:bold;"><?php echo $status_labels[$order->status] ?? $order->status; ?></td></tr>
|
||
<tr>
|
||
<th>Details (JSON)</th>
|
||
<td><code style="display:block; background:#eee; padding:10px; font-size:11px; overflow-x:auto;"><?php echo esc_html($order->response); ?></code></td>
|
||
</tr>
|
||
</table>
|
||
</div>
|
||
<?php
|
||
return;
|
||
}
|
||
|
||
$orders = WIS_DB::get_orders();
|
||
$currency = get_option('wis_currency_name', 'Coins');
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Bestellungen</h1>
|
||
|
||
<table class="widefat fixed striped">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:140px;">Datum</th>
|
||
<th style="width:150px;">Spieler</th>
|
||
<th>Inhalt</th>
|
||
<th style="width:100px;">Preis</th>
|
||
<th style="width:120px;">Status</th>
|
||
<th style="width:200px;">Aktionen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (empty($orders)): ?>
|
||
<tr><td colspan="6" style="text-align:center; padding:40px;">Noch keine Bestellungen vorhanden.</td></tr>
|
||
<?php else: ?>
|
||
<?php foreach ($orders as $order): ?>
|
||
<?php
|
||
$status_map = [
|
||
'pending' => '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'
|
||
];
|
||
?>
|
||
<tr>
|
||
<td><?php echo esc_html(date('d.m.Y H:i', strtotime($order->created_at))); ?></td>
|
||
<td><strong><?php echo esc_html($order->player_name); ?></strong></td>
|
||
<td><?php echo esc_html(substr($order->item_title, 0, 50)) . (strlen($order->item_title) > 50 ? '...' : ''); ?></td>
|
||
<td><?php echo esc_html($order->price); ?> <?php echo esc_html($currency); ?></td>
|
||
<td style="color:<?php echo $status_colors[$order->status] ?? 'black'; ?>; font-weight:bold;"><?php echo $status_map[$order->status] ?? $order->status; ?></td>
|
||
<td>
|
||
<a href="<?php echo admin_url('admin.php?page=wis_orders&view=' . $order->id); ?>" class="button button-small">👁️ Details</a>
|
||
<a href="<?php echo wp_nonce_url(admin_url('admin.php?page=wis_orders&action=delete&id=' . $order->id), 'wis_order_action', '_wpnonce'); ?>" class="button button-small" onclick="return confirm('Wirklich löschen?');" style="color:red;">🗑️ Löschen</a>
|
||
</td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
public static function page_json() {
|
||
if (isset($_POST['wis_generate_json'])) {
|
||
check_admin_referer('wis_json_export');
|
||
|
||
$items = WIS_DB::get_items(['status' => '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 '<div class="wrap"><h1>📦 JSON Export</h1>';
|
||
echo '<div class="updated"><p>✅ JSON erfolgreich generiert!</p></div>';
|
||
echo '<textarea style="width:100%; height:400px; font-family:monospace; font-size:12px;">'.esc_textarea($json_output).'</textarea>';
|
||
echo '<p><button onclick="downloadJSON()" class="button button-primary">💾 Als items.json herunterladen</button></p>';
|
||
echo '<script>
|
||
function downloadJSON() {
|
||
const text = document.querySelector("textarea").value;
|
||
const blob = new Blob([text], {type: "application/json"});
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement("a");
|
||
a.href = url;
|
||
a.download = "items.json";
|
||
a.click();
|
||
}
|
||
</script>';
|
||
echo '<h3>📤 Nächste Schritte:</h3>';
|
||
echo '<ol>';
|
||
echo '<li>Lade die JSON-Datei herunter</li>';
|
||
echo '<li>Gehe zu deinem Gitea Repository</li>';
|
||
echo '<li>Lade die <code>items.json</code> hoch unter: <code>https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro</code></li>';
|
||
echo '<li>Klicke dann auf den <strong>Quick-Import</strong> Button unten!</li>';
|
||
echo '</ol>';
|
||
echo '</div>';
|
||
return;
|
||
}
|
||
|
||
$default_url = 'https://git.viper.ipv64.net/M_Viper/WP-Ingame-Shop-Pro/raw/branch/main/items.json';
|
||
?>
|
||
<div class="wrap">
|
||
<h1>📦 JSON Export/Import</h1>
|
||
|
||
<div class="card" style="max-width:800px; padding:20px; margin-top:20px;">
|
||
<h2>📤 JSON Export</h2>
|
||
<p>Generiere eine JSON-Datei mit allen deinen Items für Gitea.</p>
|
||
<form method="post">
|
||
<?php wp_nonce_field('wis_json_export'); ?>
|
||
<p class="submit">
|
||
<input type="submit" name="wis_generate_json" class="button button-primary button-large" value="📦 JSON Generieren">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
|
||
<div class="card" style="max-width:800px; padding:20px; margin-top:20px; background:#e8f5e9;">
|
||
<h2>⚡ Quick-Import von Gitea</h2>
|
||
<p><strong>Importiert direkt von deinem Gitea Repository!</strong></p>
|
||
<p style="margin:10px 0; padding:10px; background:#fff; border-left:4px solid #28a745; font-family:monospace; font-size:12px; word-break:break-all;">
|
||
<?php echo esc_html($default_url); ?>
|
||
</p>
|
||
<button type="button" id="btn-quick-import" class="button button-primary button-large" style="background:#28a745; border-color:#28a745;">
|
||
⚡ Quick-Import starten
|
||
</button>
|
||
<div id="quick-import-result" style="margin-top:15px;"></div>
|
||
</div>
|
||
|
||
<div class="card" style="max-width:800px; padding:20px; margin-top:20px;">
|
||
<h2>📥 JSON Import (Manuelle URL)</h2>
|
||
<p>Importiere Items aus einer beliebigen JSON-URL.</p>
|
||
|
||
<div id="wis-import-form">
|
||
<input type="text" id="import-url" class="large-text code" value="<?php echo esc_attr($default_url); ?>" style="margin-bottom:15px;">
|
||
<br>
|
||
<button type="button" id="btn-import" class="button button-primary button-large">📥 Importieren</button>
|
||
<div id="import-result" style="margin-top:15px;"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
document.getElementById('btn-quick-import').addEventListener('click', function() {
|
||
const url = '<?php echo esc_js($default_url); ?>';
|
||
const resultDiv = document.getElementById('quick-import-result');
|
||
const btn = this;
|
||
|
||
btn.disabled = true;
|
||
btn.textContent = '⏳ Importiere von Gitea...';
|
||
resultDiv.innerHTML = '<div style="padding:10px; background:#fff3cd; border-left:4px solid #ffc107; margin-top:10px;">⏳ Lade Items von Gitea...</div>';
|
||
|
||
fetch('<?php echo rest_url('wis/v1/import_json'); ?>', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type':'application/json',
|
||
'X-WP-Nonce': '<?php echo wp_create_nonce('wp_rest'); ?>'
|
||
},
|
||
body: JSON.stringify({url: url})
|
||
})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
resultDiv.innerHTML = '<div class="updated" style="margin-top:10px;"><p><strong>✅ Erfolgreich!</strong><br>' + data.imported + ' Items importiert! (' + data.skipped + ' übersprungen)</p></div>';
|
||
setTimeout(() => {
|
||
window.location.href = '<?php echo admin_url('admin.php?page=wis_items'); ?>';
|
||
}, 2000);
|
||
} else {
|
||
resultDiv.innerHTML = '<div class="error" style="margin-top:10px;"><p><strong>❌ Fehler:</strong><br>' + data.message + '</p></div>';
|
||
}
|
||
})
|
||
.catch(e => {
|
||
resultDiv.innerHTML = '<div class="error" style="margin-top:10px;"><p><strong>❌ Netzwerkfehler:</strong><br>' + e.message + '</p></div>';
|
||
})
|
||
.finally(() => {
|
||
btn.disabled = false;
|
||
btn.textContent = '⚡ Quick-Import starten';
|
||
});
|
||
});
|
||
|
||
document.getElementById('btn-import').addEventListener('click', function() {
|
||
const url = document.getElementById('import-url').value.trim();
|
||
const resultDiv = document.getElementById('import-result');
|
||
|
||
if (!url) {
|
||
resultDiv.innerHTML = '<div class="error"><p>Bitte URL eingeben!</p></div>';
|
||
return;
|
||
}
|
||
|
||
this.disabled = true;
|
||
this.textContent = '⏳ Importiere...';
|
||
|
||
fetch('<?php echo rest_url('wis/v1/import_json'); ?>', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type':'application/json',
|
||
'X-WP-Nonce': '<?php echo wp_create_nonce('wp_rest'); ?>'
|
||
},
|
||
body: JSON.stringify({url: url})
|
||
})
|
||
.then(r => r.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
resultDiv.innerHTML = '<div class="updated"><p>✅ ' + data.imported + ' Items importiert! (' + data.skipped + ' übersprungen)</p></div>';
|
||
setTimeout(() => {
|
||
window.location.href = '<?php echo admin_url('admin.php?page=wis_items'); ?>';
|
||
}, 2000);
|
||
} else {
|
||
resultDiv.innerHTML = '<div class="error"><p>❌ Fehler: ' + data.message + '</p></div>';
|
||
}
|
||
})
|
||
.catch(e => {
|
||
resultDiv.innerHTML = '<div class="error"><p>❌ Netzwerkfehler: ' + e.message + '</p></div>';
|
||
})
|
||
.finally(() => {
|
||
this.disabled = false;
|
||
this.textContent = '📥 Importieren';
|
||
});
|
||
});
|
||
</script>
|
||
<?php
|
||
}
|
||
|
||
public static function page_reset() {
|
||
if (isset($_POST['wis_confirm_reset'])) {
|
||
check_admin_referer('wis_reset');
|
||
WIS_Activator::reset_shop();
|
||
echo '<div class="updated"><p>✅ Shop wurde komplett zurückgesetzt!</p></div>';
|
||
}
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1>🔄 Shop Reset</h1>
|
||
|
||
<div class="card" style="max-width:800px; padding:20px; background:#fff3cd;">
|
||
<h2 style="color:#856404;">⚠️ WARNUNG</h2>
|
||
<p><strong>Diese Aktion löscht ALLE Daten:</strong></p>
|
||
<ul>
|
||
<li>❌ Alle Items</li>
|
||
<li>❌ Alle Bestellungen</li>
|
||
<li>❌ Alle Gutscheine</li>
|
||
<li>❌ Alle Server</li>
|
||
<li>❌ Alle Kategorien</li>
|
||
</ul>
|
||
<p style="color:red; font-weight:bold;">Diese Aktion kann NICHT rückgängig gemacht werden!</p>
|
||
|
||
<form method="post" onsubmit="return confirm('WIRKLICH ALLE DATEN LÖSCHEN? Dies kann nicht rückgängig gemacht werden!');">
|
||
<?php wp_nonce_field('wis_reset'); ?>
|
||
<p class="submit">
|
||
<input type="submit" name="wis_confirm_reset" class="button button-secondary button-large" value="🗑️ Shop jetzt zurücksetzen">
|
||
</p>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
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'
|
||
GROUP BY player_name
|
||
ORDER BY total_spent DESC
|
||
LIMIT 50
|
||
");
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1>🏆 Top Spender</h1>
|
||
<p>Spieler mit den höchsten Gesamtausgaben</p>
|
||
|
||
<table class="widefat fixed striped">
|
||
<thead>
|
||
<tr>
|
||
<th style="width:80px;">Rang</th>
|
||
<th>Spieler</th>
|
||
<th style="width:150px;">Ausgegeben</th>
|
||
<th style="width:150px;">Bestellungen</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<?php if (empty($results)): ?>
|
||
<tr><td colspan="4" style="text-align:center; padding:40px;">Noch keine Statistiken vorhanden.</td></tr>
|
||
<?php else: ?>
|
||
<?php $rank = 1; foreach ($results as $row): ?>
|
||
<tr>
|
||
<td><strong>#<?php echo $rank++; ?></strong></td>
|
||
<td><?php echo esc_html($row->player_name); ?></td>
|
||
<td><?php echo esc_html(number_format($row->total_spent)); ?> <?php echo esc_html($currency); ?></td>
|
||
<td><?php echo esc_html($row->order_count); ?></td>
|
||
</tr>
|
||
<?php endforeach; ?>
|
||
<?php endif; ?>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<?php
|
||
}
|
||
}
|
||
|
||
// ===========================================================
|
||
// REST API
|
||
// ===========================================================
|
||
class WIS_API {
|
||
public static function register_routes() {
|
||
register_rest_route('wis/v1', '/import_json', [
|
||
'methods' => '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();
|
||
?>
|
||
<style>
|
||
.wis-shop { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; max-width: 1400px; margin: 40px auto; background: #f4f6f8; padding: 20px; border-radius: 10px; position: relative; }
|
||
.wis-header { text-align: center; margin-bottom: 30px; }
|
||
.wis-header h2 { color: #333; margin-bottom: 10px; }
|
||
.wis-status { background: #d4edda; color: #155724; padding: 15px; border-radius: 8px; border-left: 4px solid #c3e6cb; margin-bottom: 20px; font-weight: 500; }
|
||
.wis-control-bar { display: flex; flex-wrap: wrap; gap: 15px; margin-bottom: 30px; align-items: center; justify-content: space-between; background: #fff; padding: 15px; border-radius: 8px; border: 1px solid #ddd; }
|
||
.wis-search-input { padding: 10px 15px; border: 1px solid #ddd; border-radius: 6px; font-size: 16px; width: 100%; max-width: 300px; }
|
||
.wis-filter-select { padding: 12px 20px; font-size: 16px; border: 2px solid #ddd; border-radius: 8px; background: white; cursor: pointer; min-width: 200px; }
|
||
.wis-cart-btn { padding: 12px 30px; background: linear-gradient(135deg, #28a745 0%, #20c997 100%); color: white; border: none; border-radius: 8px; font-weight: bold; font-size: 1rem; cursor: pointer; transition: all 0.3s; position: relative; display: flex; align-items: center; gap: 10px; }
|
||
.wis-cart-btn:hover { transform: scale(1.05); box-shadow: 0 5px 15px rgba(40, 167, 69, 0.4); }
|
||
.wis-cart-badge { position: absolute; top: -8px; right: -8px; background: #dc3545; color: white; border-radius: 50%; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center; font-size: 0.8rem; font-weight: bold; }
|
||
.wis-cat-tabs { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 20px; justify-content: center; }
|
||
.wis-cat-btn { padding: 8px 16px; border: 1px solid #ddd; background: #fff; border-radius: 20px; cursor: pointer; transition: all 0.2s; }
|
||
.wis-cat-btn:hover, .wis-cat-btn.active { background: #667eea; color: white; border-color: #667eea; }
|
||
.wis-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 320px)); gap: 15px; justify-content: center; margin: 0 auto; min-height: 200px; }
|
||
.wis-card { background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 6px rgba(0,0,0,0.05); transition: transform 0.2s, box-shadow 0.2s; display: flex; flex-direction: column; border: 1px solid #eee; position: relative; width: 100%; }
|
||
.wis-card.offer { border: 2px solid #ffc107; }
|
||
.wis-card:hover { transform: translateY(-5px); box-shadow: 0 10px 20px rgba(0,0,0,0.1); }
|
||
.wis-card-img { width: 100%; height: 180px; background: #2d2d2d; display: flex; align-items: center; justify-content: center; position: relative; padding: 20px; }
|
||
.wis-card-img img { width: 100px !important; height: 100px !important; object-fit: contain; filter: drop-shadow(0 6px 8px rgba(0,0,0,0.7)); transition: transform 0.3s; image-rendering: pixelated; image-rendering: -moz-crisp-edges; image-rendering: crisp-edges; }
|
||
.wis-card:hover .wis-card-img img { transform: scale(1.15) rotate(5deg); }
|
||
.wis-offer-badge, .wis-daily-badge { position: absolute; top: 10px; left: 10px; background: linear-gradient(135deg, #ff416c, #ff4b2b); color: white; padding: 6px 12px; border-radius: 20px; font-size: 0.75rem; font-weight: bold; box-shadow: 0 2px 5px rgba(0,0,0,0.3); z-index: 2; }
|
||
.wis-daily-badge { background: linear-gradient(135deg, #6f42c1, #8e44ad); border: 1px solid #fff; }
|
||
.wis-card-body { padding: 15px; flex-grow: 1; display: flex; flex-direction: column; }
|
||
.wis-card-title { font-size: 1.1rem; font-weight: 700; margin: 0 0 10px 0; color: #333; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
||
.wis-card-desc { font-size: 0.85rem; color: #666; margin-bottom: 10px; line-height: 1.4; height: 40px; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
|
||
.wis-card-price-container { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }
|
||
.wis-card-price { font-size: 1.2rem; color: #e67e22; font-weight: 800; }
|
||
.wis-card-price-old { font-size: 0.9rem; color: #999; text-decoration: line-through; }
|
||
.wis-card-servers { font-size: 0.85rem; color: #666; margin-bottom: 15px; }
|
||
.wis-quantity-control { display: flex; align-items: center; gap: 10px; margin-bottom: 15px; }
|
||
.wis-quantity-btn { width: 35px; height: 35px; border: 2px solid #667eea; background: white; color: #667eea; border-radius: 6px; font-weight: bold; cursor: pointer; transition: all 0.2s; }
|
||
.wis-quantity-btn:hover { background: #667eea; color: white; }
|
||
.wis-quantity-input { width: 60px; text-align: center; border: 2px solid #ddd; border-radius: 6px; padding: 8px; font-weight: bold; }
|
||
.wis-btn-add { margin-top: auto; width: 100%; padding: 12px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; transition: all 0.3s; }
|
||
.wis-btn-add:hover { transform: scale(1.05); box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4); }
|
||
.wis-pagination { display: flex; justify-content: center; align-items: center; gap: 8px; margin: 30px 0 10px; flex-wrap: wrap; }
|
||
.wis-page-btn { padding: 8px 14px; border: 2px solid #ddd; background: #fff; border-radius: 6px; cursor: pointer; font-size: 14px; font-weight: 600; transition: all 0.2s; color: #333; }
|
||
.wis-page-btn:hover { border-color: #667eea; color: #667eea; }
|
||
.wis-page-btn.active { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-color: #667eea; color: #fff; }
|
||
.wis-page-btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
||
.wis-page-info { font-size: 14px; color: #666; margin: 0 8px; }
|
||
.wis-loading { text-align: center; padding: 60px 20px; color: #888; font-size: 1.1rem; }
|
||
.wis-loading-spinner { display: inline-block; width: 36px; height: 36px; border: 4px solid #ddd; border-top-color: #667eea; border-radius: 50%; animation: wis-spin 0.8s linear infinite; margin-bottom: 12px; }
|
||
@keyframes wis-spin { to { transform: rotate(360deg); } }
|
||
.wis-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); z-index: 2147483647; display: none; align-items: center; justify-content: center; transform: translateZ(0); }
|
||
.wis-modal { background: white; width: 90%; max-width: 600px; max-height: 80vh; padding: 30px; border-radius: 15px; box-shadow: 0 15px 30px rgba(0,0,0,0.3); overflow-y: auto; position: relative; z-index: 2147483648; }
|
||
.wis-cart-item { display: flex; justify-content: space-between; align-items: center; padding: 15px; border-bottom: 1px solid #eee; }
|
||
.wis-cart-item-title { font-weight: bold; color: #333; }
|
||
.wis-cart-item-price { color: #e67e22; font-weight: 600; }
|
||
.wis-cart-item-remove { background: #dc3545; color: white; border: none; padding: 8px 15px; border-radius: 6px; cursor: pointer; }
|
||
.wis-cart-total { border-top: 2px solid #333; padding: 20px 0; margin-top: 15px; font-size: 1.3rem; font-weight: bold; display: flex; justify-content: space-between; }
|
||
.wis-modal-input { width: 100%; padding: 15px; margin: 20px 0; border: 2px solid #ddd; border-radius: 8px; font-size: 1.1rem; box-sizing: border-box; }
|
||
.wis-modal-actions { display: flex; gap: 10px; }
|
||
.wis-modal-btn { flex: 1; padding: 12px; border: none; border-radius: 8px; font-weight: bold; cursor: pointer; font-size: 1rem; }
|
||
.wis-btn-confirm { background: linear-gradient(135deg, #28a745 0%, #20c997 100%); color: white; }
|
||
.wis-btn-cancel { background: #6c757d; color: white; }
|
||
.wis-coupon-input-group { display: flex; gap: 10px; margin-bottom: 20px; }
|
||
.wis-coupon-input { flex-grow: 1; padding: 10px; border: 1px solid #ddd; border-radius: 6px; }
|
||
.wis-coupon-btn { padding: 10px 15px; background: #6f42c1; color: white; border: none; border-radius: 6px; font-weight: bold; cursor: pointer; }
|
||
.wis-coupon-msg { font-size: 0.85rem; color: #e67e22; margin-top: 5px; min-height: 20px; }
|
||
.wis-alert { margin-top: 15px; padding: 12px; border-radius: 5px; display: none; }
|
||
.wis-alert.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
|
||
.wis-alert.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
|
||
</style>
|
||
|
||
<div class="wis-shop">
|
||
<div class="wis-header">
|
||
<h2>🛒 Ingame Shop</h2>
|
||
<?php if (!empty(trim($header_text))): ?>
|
||
<div class="wis-status"><?php echo esc_html($header_text); ?></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
<div class="wis-control-bar">
|
||
<input type="text" id="wis-search" class="wis-search-input" placeholder="🔍 Suche Item...">
|
||
|
||
<select id="server-filter" class="wis-filter-select">
|
||
<option value="">Alle Server</option>
|
||
<?php foreach ($servers as $s): ?>
|
||
<option value="<?php echo esc_attr($s->slug); ?>"><?php echo esc_html($s->name); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
|
||
<button class="wis-cart-btn" id="wis-open-cart-btn">
|
||
🛒 Warenkorb
|
||
<span class="wis-cart-badge" id="cart-count">0</span>
|
||
</button>
|
||
</div>
|
||
|
||
<?php if (!empty($categories)): ?>
|
||
<div class="wis-cat-tabs">
|
||
<?php $is_first = true; ?>
|
||
<?php foreach ($categories as $cat): ?>
|
||
<button class="wis-cat-btn <?php echo $is_first ? 'active' : ''; ?>"
|
||
data-cat="<?php echo esc_attr($cat->slug); ?>">
|
||
<?php echo esc_html($cat->name); ?>
|
||
</button>
|
||
<?php $is_first = false; ?>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div class="wis-grid" id="wis-grid">
|
||
<div class="wis-loading" style="grid-column:1/-1;">
|
||
<div class="wis-loading-spinner"></div><br>Lade Items…
|
||
</div>
|
||
</div>
|
||
|
||
<div class="wis-pagination" id="wis-pagination"></div>
|
||
</div>
|
||
|
||
<!-- Warenkorb Modal -->
|
||
<div class="wis-modal-overlay" id="cart-modal">
|
||
<div class="wis-modal">
|
||
<h2>🛒 Dein Warenkorb</h2>
|
||
<div id="cart-content">
|
||
<div style="text-align:center; padding:40px; color:#999;">Dein Warenkorb ist leer</div>
|
||
</div>
|
||
<div id="cart-checkout" style="display:none;">
|
||
<div style="margin-bottom:20px; background:#f8f9fa; padding:15px; border-radius:8px;">
|
||
<label style="display:block; font-weight:bold; margin-bottom:5px;">🎫 Gutscheincode</label>
|
||
<div class="wis-coupon-input-group">
|
||
<input type="text" id="coupon-code" class="wis-coupon-input" placeholder="CODE">
|
||
<button class="wis-coupon-btn" id="wis-coupon-btn">Einlösen</button>
|
||
</div>
|
||
<div id="coupon-msg" class="wis-coupon-msg"></div>
|
||
</div>
|
||
|
||
<div class="wis-cart-total">
|
||
<span>Gesamt:</span>
|
||
<span id="cart-total">0 <?php echo esc_html($currency); ?></span>
|
||
</div>
|
||
|
||
<select id="checkout-server" class="wis-modal-input">
|
||
<option value="">-- Server wählen --</option>
|
||
<?php foreach ($servers as $s): ?>
|
||
<option value="<?php echo esc_attr($s->slug); ?>"><?php echo esc_html($s->name); ?></option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
|
||
<input type="text" id="checkout-player" class="wis-modal-input" placeholder="Dein Spielername">
|
||
|
||
<div class="wis-modal-actions">
|
||
<button class="wis-modal-btn wis-btn-confirm" id="wis-checkout-btn">💰 Kauf abschließen</button>
|
||
<button class="wis-modal-btn wis-btn-cancel" id="wis-close-cart-btn">Abbrechen</button>
|
||
</div>
|
||
|
||
<div id="cart-alert" class="wis-alert"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
(function() {
|
||
const shopCurrency = <?php echo json_encode($currency); ?>;
|
||
const shopExcludeOffers = <?php echo $exclude_offers === '1' ? 'true' : 'false'; ?>;
|
||
const apiBase = <?php echo json_encode(rest_url('wis/v1')); ?>;
|
||
const serverList = <?php echo json_encode(array_map(function($s){ return ['slug'=>$s->slug,'name'=>$s->name]; }, $servers)); ?>;
|
||
|
||
let cart = [];
|
||
let couponData = {};
|
||
let currentCat = <?php echo json_encode($first_category); ?>;
|
||
let currentSearch = '';
|
||
let currentPage = 1;
|
||
let totalPages = 1;
|
||
let searchTimer = null;
|
||
let allItems = [];
|
||
let itemMap = {}; // id (int) -> item object
|
||
|
||
// -------------------------------------------------------
|
||
// INIT
|
||
// -------------------------------------------------------
|
||
function init() {
|
||
// Modal an <body> hängen damit z-index korrekt greift
|
||
const modal = document.getElementById('cart-modal');
|
||
if (modal && document.body) document.body.appendChild(modal);
|
||
|
||
// Erste Items laden
|
||
loadItems(1);
|
||
|
||
// ---- Event Delegation: Warenkorb-Buttons im Grid ----
|
||
document.getElementById('wis-grid').addEventListener('click', function(e) {
|
||
|
||
// "In den Warenkorb" Button
|
||
const addBtn = e.target.closest('.wis-btn-add');
|
||
if (addBtn) {
|
||
const card = addBtn.closest('.wis-card');
|
||
const id = parseInt(addBtn.getAttribute('data-item-id'), 10);
|
||
const item = itemMap[id];
|
||
if (!item || !card) return;
|
||
const qtyInput = card.querySelector('.wis-quantity-input');
|
||
const qty = parseInt(qtyInput ? qtyInput.value : '1', 10) || 1;
|
||
addToCartItem(item, qty, addBtn, card);
|
||
return;
|
||
}
|
||
|
||
// Mengen-Buttons
|
||
const qtyBtn = e.target.closest('.wis-quantity-btn');
|
||
if (qtyBtn) {
|
||
const delta = parseInt(qtyBtn.getAttribute('data-delta'), 10);
|
||
const ctrl = qtyBtn.closest('.wis-quantity-control');
|
||
if (!ctrl) return;
|
||
const input = ctrl.querySelector('.wis-quantity-input');
|
||
if (input) input.value = Math.max(1, Math.min(999, (parseInt(input.value, 10) || 1) + delta));
|
||
}
|
||
});
|
||
|
||
// ---- Kategorie-Tabs ----
|
||
document.querySelectorAll('.wis-cat-btn').forEach(function(btn) {
|
||
btn.addEventListener('click', function() {
|
||
document.querySelectorAll('.wis-cat-btn').forEach(function(b){ b.classList.remove('active'); });
|
||
btn.classList.add('active');
|
||
currentCat = btn.getAttribute('data-cat');
|
||
currentPage = 1;
|
||
loadItems(1);
|
||
});
|
||
});
|
||
|
||
// ---- Suche ----
|
||
var searchInput = document.getElementById('wis-search');
|
||
if (searchInput) {
|
||
searchInput.addEventListener('input', function() {
|
||
clearTimeout(searchTimer);
|
||
searchTimer = setTimeout(function() {
|
||
currentSearch = searchInput.value.trim();
|
||
currentPage = 1;
|
||
loadItems(1);
|
||
}, 350);
|
||
});
|
||
}
|
||
|
||
// ---- Server-Filter ----
|
||
var serverSelect = document.getElementById('server-filter');
|
||
if (serverSelect) {
|
||
serverSelect.addEventListener('change', function() {
|
||
renderGrid(allItems);
|
||
});
|
||
}
|
||
|
||
// ---- Warenkorb öffnen ----
|
||
var openBtn = document.getElementById('wis-open-cart-btn');
|
||
if (openBtn) openBtn.addEventListener('click', openCart);
|
||
|
||
// ---- Warenkorb schließen ----
|
||
var closeBtn = document.getElementById('wis-close-cart-btn');
|
||
if (closeBtn) closeBtn.addEventListener('click', closeCart);
|
||
|
||
// ---- Modal-Overlay klick ----
|
||
var cartModal = document.getElementById('cart-modal');
|
||
if (cartModal) {
|
||
cartModal.addEventListener('click', function(e) {
|
||
if (e.target === cartModal) closeCart();
|
||
});
|
||
}
|
||
|
||
// ---- Gutschein einlösen ----
|
||
var couponBtn = document.getElementById('wis-coupon-btn');
|
||
if (couponBtn) couponBtn.addEventListener('click', validateCoupon);
|
||
|
||
// ---- Kauf abschließen ----
|
||
var checkoutBtn = document.getElementById('wis-checkout-btn');
|
||
if (checkoutBtn) checkoutBtn.addEventListener('click', checkout);
|
||
}
|
||
|
||
if (document.readyState === 'loading') {
|
||
document.addEventListener('DOMContentLoaded', init);
|
||
} else {
|
||
init();
|
||
}
|
||
|
||
// -------------------------------------------------------
|
||
// ITEMS LADEN
|
||
// -------------------------------------------------------
|
||
function loadItems(page) {
|
||
currentPage = page;
|
||
var grid = document.getElementById('wis-grid');
|
||
grid.innerHTML = '<div class="wis-loading" style="grid-column:1/-1;"><div class="wis-loading-spinner"></div><br>Lade Items…</div>';
|
||
document.getElementById('wis-pagination').innerHTML = '';
|
||
|
||
var url = apiBase + '/shop_items?page=' + page;
|
||
if (currentCat) url += '&category=' + encodeURIComponent(currentCat);
|
||
if (currentSearch) url += '&search=' + encodeURIComponent(currentSearch);
|
||
|
||
fetch(url)
|
||
.then(function(r){ return r.json(); })
|
||
.then(function(data) {
|
||
allItems = data.items || [];
|
||
totalPages = data.total_pages || 1;
|
||
itemMap = {};
|
||
allItems.forEach(function(i){ itemMap[i.id] = i; });
|
||
renderGrid(allItems);
|
||
renderPagination(data.page, data.total_pages, data.total);
|
||
})
|
||
.catch(function() {
|
||
grid.innerHTML = '<div class="wis-loading" style="grid-column:1/-1; color:#dc3545;">Fehler beim Laden der Items.</div>';
|
||
});
|
||
}
|
||
|
||
// -------------------------------------------------------
|
||
// GRID RENDERN — KEIN INLINE-ONCLICK, nur data-item-id
|
||
// -------------------------------------------------------
|
||
function renderGrid(items) {
|
||
var grid = document.getElementById('wis-grid');
|
||
var serverSlug = document.getElementById('server-filter').value;
|
||
|
||
var filtered = serverSlug
|
||
? items.filter(function(i){ return i.servers.indexOf(serverSlug) !== -1; })
|
||
: items;
|
||
|
||
if (filtered.length === 0) {
|
||
grid.innerHTML = '<div style="grid-column:1/-1; text-align:center; padding:40px; background:#fff; border-radius:10px; color:#888;">Keine Items gefunden.</div>';
|
||
return;
|
||
}
|
||
|
||
grid.innerHTML = filtered.map(function(item) {
|
||
var price = item.offer_price > 0 ? item.offer_price : item.price;
|
||
var showOld = item.offer_price > 0 && item.offer_price !== item.price;
|
||
var serverNames = item.servers
|
||
.map(function(slug) {
|
||
var s = serverList.find(function(x){ return x.slug === slug; });
|
||
return s ? s.name : slug;
|
||
})
|
||
.join(', ') || 'Kein Server';
|
||
|
||
var badge = item.is_daily_deal
|
||
? '<div class="wis-daily-badge">🎁 Angebot des Tages</div>'
|
||
: (item.is_offer ? '<div class="wis-offer-badge">🔥 Angebot</div>' : '');
|
||
|
||
var oldPrice = showOld
|
||
? '<div class="wis-card-price-old">' + item.price + ' ' + shopCurrency + '</div>'
|
||
: '';
|
||
|
||
var desc = item.description
|
||
? '<div class="wis-card-desc">' + escHtml(item.description) + '</div>'
|
||
: '';
|
||
|
||
// Wichtig: data-item-id statt onclick mit JSON
|
||
return '<div class="wis-card' + (item.is_offer ? ' offer' : '') + '">'
|
||
+ badge
|
||
+ '<div class="wis-card-img">'
|
||
+ '<img src="' + escHtml(item.image) + '" alt="' + escHtml(item.name) + '" loading="lazy"'
|
||
+ ' onerror="this.onerror=null;this.src=\'https://via.placeholder.com/100/333/fff?text=?\';">'
|
||
+ '</div>'
|
||
+ '<div class="wis-card-body">'
|
||
+ '<h3 class="wis-card-title" title="' + escHtml(item.name) + '">' + escHtml(item.name) + '</h3>'
|
||
+ desc
|
||
+ '<div class="wis-card-price-container">'
|
||
+ oldPrice
|
||
+ '<div class="wis-card-price">' + price + ' ' + shopCurrency + '</div>'
|
||
+ '</div>'
|
||
+ '<div class="wis-card-servers">📡 ' + escHtml(serverNames) + '</div>'
|
||
+ '<div class="wis-quantity-control">'
|
||
+ '<button class="wis-quantity-btn" data-delta="-1" type="button">-</button>'
|
||
+ '<input type="number" class="wis-quantity-input" value="1" min="1" max="999">'
|
||
+ '<button class="wis-quantity-btn" data-delta="1" type="button">+</button>'
|
||
+ '</div>'
|
||
+ '<button class="wis-btn-add" data-item-id="' + item.id + '" type="button">➕ In den Warenkorb</button>'
|
||
+ '</div>'
|
||
+ '</div>';
|
||
}).join('');
|
||
}
|
||
|
||
// -------------------------------------------------------
|
||
// PAGINATION
|
||
// -------------------------------------------------------
|
||
function renderPagination(page, pages, total) {
|
||
var el = document.getElementById('wis-pagination');
|
||
if (pages <= 1) { el.innerHTML = ''; return; }
|
||
|
||
var html = '';
|
||
html += '<button class="wis-page-btn" ' + (page <= 1 ? 'disabled' : '') + ' data-page="' + (page - 1) + '">‹ Zurück</button>';
|
||
|
||
var start = Math.max(1, page - 2);
|
||
var end = Math.min(pages, page + 2);
|
||
if (start > 1) {
|
||
html += '<button class="wis-page-btn" data-page="1">1</button>';
|
||
if (start > 2) html += '<span style="color:#999">…</span>';
|
||
}
|
||
for (var p = start; p <= end; p++) {
|
||
html += '<button class="wis-page-btn' + (p === page ? ' active' : '') + '" data-page="' + p + '">' + p + '</button>';
|
||
}
|
||
if (end < pages) {
|
||
if (end < pages - 1) html += '<span style="color:#999">…</span>';
|
||
html += '<button class="wis-page-btn" data-page="' + pages + '">' + pages + '</button>';
|
||
}
|
||
html += '<button class="wis-page-btn" ' + (page >= pages ? 'disabled' : '') + ' data-page="' + (page + 1) + '">Weiter ›</button>';
|
||
html += '<span class="wis-page-info">' + total + ' Items</span>';
|
||
el.innerHTML = html;
|
||
|
||
// Pagination-Buttons via Event Delegation
|
||
el.querySelectorAll('.wis-page-btn:not([disabled])').forEach(function(btn) {
|
||
btn.addEventListener('click', function() {
|
||
var p = parseInt(btn.getAttribute('data-page'), 10);
|
||
if (p) {
|
||
loadItems(p);
|
||
document.querySelector('.wis-shop').scrollIntoView({behavior: 'smooth', block: 'start'});
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
// -------------------------------------------------------
|
||
// WARENKORB LOGIK
|
||
// -------------------------------------------------------
|
||
function addToCartItem(item, qty, btn, card) {
|
||
var price = item.offer_price > 0 ? item.offer_price : item.price;
|
||
var existing = cart.find(function(i){ return i.id === item.id; });
|
||
if (existing) {
|
||
existing.quantity += qty;
|
||
} else {
|
||
cart.push({
|
||
id: item.id,
|
||
name: item.name,
|
||
price: price,
|
||
quantity: qty,
|
||
servers: item.servers,
|
||
is_offer: !!item.is_offer
|
||
});
|
||
}
|
||
updateCartBadge();
|
||
btn.textContent = '✅ Hinzugefügt';
|
||
btn.style.background = '#28a745';
|
||
setTimeout(function() {
|
||
btn.textContent = '➕ In den Warenkorb';
|
||
btn.style.background = '';
|
||
}, 1500);
|
||
var qtyInput = card.querySelector('.wis-quantity-input');
|
||
if (qtyInput) qtyInput.value = 1;
|
||
}
|
||
|
||
function updateCartBadge() {
|
||
var total = cart.reduce(function(s, i){ return s + i.quantity; }, 0);
|
||
document.getElementById('cart-count').textContent = total;
|
||
}
|
||
|
||
function openCart() {
|
||
renderCart();
|
||
document.getElementById('cart-modal').style.display = 'flex';
|
||
}
|
||
|
||
function closeCart() {
|
||
document.getElementById('cart-modal').style.display = 'none';
|
||
}
|
||
|
||
function calculateTotal() {
|
||
var normal = 0, offer = 0;
|
||
cart.forEach(function(item) {
|
||
var t = item.price * item.quantity;
|
||
if (shopExcludeOffers && item.is_offer) offer += t; else normal += t;
|
||
});
|
||
var discount = 0;
|
||
if (couponData && typeof couponData.value !== 'undefined') {
|
||
discount = couponData.type === 'percent'
|
||
? Math.floor(normal * couponData.value / 100)
|
||
: couponData.value;
|
||
}
|
||
return Math.max(0, normal - discount) + offer;
|
||
}
|
||
|
||
function renderCart() {
|
||
var content = document.getElementById('cart-content');
|
||
var checkout = document.getElementById('cart-checkout');
|
||
if (cart.length === 0) {
|
||
content.innerHTML = '<div style="text-align:center;padding:40px;color:#999;">Dein Warenkorb ist leer</div>';
|
||
checkout.style.display = 'none';
|
||
return;
|
||
}
|
||
content.innerHTML = cart.map(function(item, idx) {
|
||
return '<div class="wis-cart-item">'
|
||
+ '<div>'
|
||
+ '<div class="wis-cart-item-title">' + escHtml(item.name) + '</div>'
|
||
+ '<div class="wis-cart-item-price">' + item.quantity + 'x × ' + item.price + ' = ' + (item.price * item.quantity) + ' ' + shopCurrency + '</div>'
|
||
+ '</div>'
|
||
+ '<button class="wis-cart-item-remove" data-cart-idx="' + idx + '" type="button">🗑️</button>'
|
||
+ '</div>';
|
||
}).join('');
|
||
|
||
// Remove-Buttons
|
||
content.querySelectorAll('.wis-cart-item-remove').forEach(function(btn) {
|
||
btn.addEventListener('click', function() {
|
||
var idx = parseInt(btn.getAttribute('data-cart-idx'), 10);
|
||
cart.splice(idx, 1);
|
||
updateCartBadge();
|
||
renderCart();
|
||
});
|
||
});
|
||
|
||
document.getElementById('cart-total').textContent = calculateTotal() + ' ' + shopCurrency;
|
||
checkout.style.display = 'block';
|
||
}
|
||
|
||
function validateCoupon() {
|
||
var code = document.getElementById('coupon-code').value.trim().toUpperCase();
|
||
var msgEl = document.getElementById('coupon-msg');
|
||
if (!code) { couponData = {}; msgEl.textContent = ''; renderCart(); return; }
|
||
msgEl.textContent = 'Prüfe…';
|
||
msgEl.style.color = '#0073aa';
|
||
fetch(apiBase + '/validate_coupon', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({code: code, cart: cart})
|
||
})
|
||
.then(function(r){ return r.json(); })
|
||
.then(function(data) {
|
||
if (data.success) {
|
||
couponData = {type: data.type, value: data.value};
|
||
msgEl.textContent = '✅ ' + data.message;
|
||
msgEl.style.color = 'green';
|
||
} else {
|
||
couponData = {};
|
||
msgEl.textContent = '❌ ' + data.message;
|
||
msgEl.style.color = 'red';
|
||
}
|
||
renderCart();
|
||
});
|
||
}
|
||
|
||
function checkout() {
|
||
var player = document.getElementById('checkout-player').value.trim();
|
||
var server = document.getElementById('checkout-server').value;
|
||
var couponCode = document.getElementById('coupon-code').value.trim();
|
||
var alertEl = document.getElementById('cart-alert');
|
||
var btn = document.getElementById('wis-checkout-btn');
|
||
|
||
if (!player) { alertEl.textContent = 'Bitte Spielername eingeben!'; alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return; }
|
||
if (!server) { alertEl.textContent = 'Bitte Server auswählen!'; alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return; }
|
||
|
||
var invalid = cart.filter(function(i){ return i.servers.indexOf(server) === -1; });
|
||
if (invalid.length) { alertEl.textContent = 'Einige Items sind nicht für diesen Server!'; alertEl.className = 'wis-alert error'; alertEl.style.display = 'block'; return; }
|
||
|
||
btn.disabled = true;
|
||
btn.textContent = '⏳ Speichere…';
|
||
|
||
fetch(apiBase + '/order', {
|
||
method: 'POST',
|
||
headers: {'Content-Type': 'application/json'},
|
||
body: JSON.stringify({player: player, cart: cart, server: server, coupon_code: couponCode})
|
||
})
|
||
.then(function(r){ return r.json(); })
|
||
.then(function(data) {
|
||
if (data.success) {
|
||
alertEl.textContent = data.message;
|
||
alertEl.className = 'wis-alert success';
|
||
alertEl.style.display = 'block';
|
||
cart = []; couponData = {};
|
||
updateCartBadge();
|
||
setTimeout(function(){ closeCart(); location.reload(); }, 2000);
|
||
} else {
|
||
alertEl.textContent = data.message;
|
||
alertEl.className = 'wis-alert error';
|
||
alertEl.style.display = 'block';
|
||
}
|
||
})
|
||
.finally(function() {
|
||
btn.disabled = false;
|
||
btn.textContent = '💰 Kauf abschließen';
|
||
});
|
||
}
|
||
|
||
// -------------------------------------------------------
|
||
// HILFSFUNKTIONEN
|
||
// -------------------------------------------------------
|
||
function escHtml(str) {
|
||
return String(str)
|
||
.replace(/&/g, '&')
|
||
.replace(/</g, '<')
|
||
.replace(/>/g, '>')
|
||
.replace(/"/g, '"')
|
||
.replace(/'/g, ''');
|
||
}
|
||
|
||
})();
|
||
</script>
|
||
<?php
|
||
return ob_get_clean();
|
||
}
|
||
}
|
||
|
||
// ===========================================================
|
||
// SIDEBAR WIDGET
|
||
// ===========================================================
|
||
class WIS_Sidebar_Widget extends WP_Widget {
|
||
public function __construct() {
|
||
parent::__construct(
|
||
'wis_sidebar_offer',
|
||
'WIS Shop Angebot',
|
||
['description' => '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();
|
||
|
||
?>
|
||
<div style="background:#fff; border-radius:10px; padding:0; overflow:hidden; box-shadow:0 4px 10px rgba(0,0,0,0.05); text-align:center;">
|
||
<div style="position:relative; background:#2d2d2d; padding:15px; height:160px; display:flex; align-items:center; justify-content:center;">
|
||
<?php if ($item->is_daily_deal): ?>
|
||
<div style="position:absolute; top:10px; left:10px; background:linear-gradient(135deg, #6f42c1, #8e44ad); color:#fff; padding:4px 10px; font-size:10px; border-radius:20px; font-weight:bold; z-index:2;">🎁 DAILY DEAL</div>
|
||
<?php elseif ($item->is_offer): ?>
|
||
<div style="position:absolute; top:10px; left:10px; background:linear-gradient(135deg, #ff416c, #ff4b2b); color:#fff; padding:4px 10px; font-size:10px; border-radius:20px; font-weight:bold; z-index:2;">🔥 ANGEBOT</div>
|
||
<?php endif; ?>
|
||
<img src="<?php echo esc_url($img_url); ?>" alt="<?php echo esc_attr($item->name); ?>" style="max-width:90%; max-height:90%; object-fit:contain; filter:drop-shadow(0 4px 8px rgba(0,0,0,0.6));">
|
||
</div>
|
||
<div style="padding:15px;">
|
||
<h4 style="margin:0 0 8px 0; font-size:15px; color:#333; font-weight:700;"><?php echo esc_html($item->name); ?></h4>
|
||
<div style="margin-bottom:12px;">
|
||
<?php if ($show_old): ?>
|
||
<span style="text-decoration:line-through; color:#999; font-size:11px;"><?php echo esc_html($item->price); ?> <?php echo esc_html($currency); ?></span>
|
||
<?php endif; ?>
|
||
<span style="font-size:20px; font-weight:800; color:#28a745;"><?php echo esc_html($price); ?> <span style="font-size:12px; font-weight:400; color:#666;"><?php echo esc_html($currency); ?></span></span>
|
||
</div>
|
||
<a href="<?php echo esc_url($target_url); ?>" style="display:block; padding:10px 0; background:linear-gradient(135deg, #667eea 0%, #764ba2 100%); color:#fff; text-decoration:none; border-radius:6px; font-weight:bold; font-size:13px;">
|
||
<?php echo esc_html($instance['btn_text'] ?? 'Zum Shop'); ?> 🛒
|
||
</a>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
} else {
|
||
echo '<div style="background:#f8f9fa; border:1px dashed #ddd; border-radius:8px; padding:20px; text-align:center;"><p style="margin:0; color:#888; font-size:13px;">Kein Angebot verfügbar.</p></div>';
|
||
}
|
||
|
||
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'] : '';
|
||
?>
|
||
<p>
|
||
<label for="<?php echo $this->get_field_id('title'); ?>">Titel:</label>
|
||
<input class="widefat" id="<?php echo $this->get_field_id('title'); ?>" name="<?php echo $this->get_field_name('title'); ?>" type="text" value="<?php echo esc_attr($title); ?>">
|
||
</p>
|
||
<p>
|
||
<label for="<?php echo $this->get_field_id('btn_text'); ?>">Button Text:</label>
|
||
<input class="widefat" id="<?php echo $this->get_field_id('btn_text'); ?>" name="<?php echo $this->get_field_name('btn_text'); ?>" type="text" value="<?php echo esc_attr($btn_text); ?>">
|
||
</p>
|
||
<p>
|
||
<label for="<?php echo $this->get_field_id('shop_url'); ?>">Shop URL:</label>
|
||
<input class="widefat" id="<?php echo $this->get_field_id('shop_url'); ?>" name="<?php echo $this->get_field_name('shop_url'); ?>" type="text" value="<?php echo esc_attr($shop_url); ?>">
|
||
</p>
|
||
<?php
|
||
}
|
||
|
||
public function update($new_instance, $old_instance) {
|
||
$instance = [];
|
||
$instance['title'] = !empty($new_instance['title']) ? sanitize_text_field($new_instance['title']) : '';
|
||
$instance['btn_text'] = !empty($new_instance['btn_text']) ? sanitize_text_field($new_instance['btn_text']) : 'Zum Shop';
|
||
$instance['shop_url'] = !empty($new_instance['shop_url']) ? esc_url_raw($new_instance['shop_url']) : '';
|
||
return $instance;
|
||
}
|
||
}
|
||
|
||
// ===========================================================
|
||
// INITIALIZATION
|
||
// ===========================================================
|
||
register_activation_hook(__FILE__, [WIS_Activator::class, 'activate']);
|
||
register_deactivation_hook(__FILE__, [WIS_Activator::class, 'deactivate']);
|
||
|
||
add_action('admin_menu', [WIS_Admin::class, 'register_menu']);
|
||
add_action('rest_api_init',[WIS_API::class, 'register_routes']);
|
||
add_action('init', [WIS_Shortcode::class, 'register']);
|
||
add_action('widgets_init', function() {
|
||
register_widget('WIS_Sidebar_Widget');
|
||
});
|
||
add_action('wis_daily_deal_event', [WIS_Activator::class, 'run_daily_deal']);
|