prefix . 'wheel_spins'; wheel_of_fortune_debug_log("add_spins: Attempting to add $spins spins for user $user_id to wheel $wheel_id."); // Preveri, ali zapis že obstaja $existing_id = $wpdb->get_var($wpdb->prepare( "SELECT id FROM $table_spins WHERE user_id = %d AND wheel_id = %d", $user_id, $wheel_id )); if ($existing_id) { // Zapis obstaja, posodobi spine $result = $wpdb->query($wpdb->prepare( "UPDATE $table_spins SET spins_available = spins_available + %d WHERE id = %d", $spins, $existing_id )); wheel_of_fortune_debug_log("add_spins: Updated existing record. Result: $result"); } else { // Zapis ne obstaja, ustvari novega $result = $wpdb->insert( $table_spins, [ 'user_id' => $user_id, 'wheel_id' => $wheel_id, 'spins_available' => $spins, 'last_spin_date' => null ], ['%d', '%d', '%d', '%s'] ); wheel_of_fortune_debug_log("add_spins: Inserted new record. Result: $result"); } return $result !== false; } /** * Main plugin class */ class WheelOfFortune { private static $instance = null; public static function get_instance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } private function __construct() { // Register hooks add_action('init', array($this, 'init')); add_action('plugins_loaded', array($this, 'load_textdomain')); register_activation_hook(WHEEL_OF_FORTUNE_PLUGIN_FILE, array($this, 'activate')); register_deactivation_hook(WHEEL_OF_FORTUNE_PLUGIN_FILE, array($this, 'deactivate')); add_action('admin_menu', array($this, 'admin_menu')); add_action('rest_api_init', array($this, 'register_rest_routes')); add_shortcode('wheel_of_fortune', array($this, 'shortcode')); if ($this->is_woocommerce_active()) { add_action('woocommerce_order_status_processing', array($this, 'assign_spins_on_purchase')); add_action('woocommerce_order_status_completed', array($this, 'assign_spins_on_purchase')); } add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets')); add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets')); add_action('wp_ajax_wheel_get_prize_details', array($this, 'ajax_get_prize_details')); add_action('wp_ajax_wheel_save_prize', array($this, 'ajax_save_prize')); add_action('wp_ajax_wheel_delete_prize', array($this, 'ajax_delete_prize')); add_action('wp_ajax_wheel_search_users', array($this, 'ajax_search_users')); add_action('wp_ajax_wheel_add_spins', array($this, 'ajax_add_spins')); add_action('wp_ajax_wheel_reset_all_spins', array($this, 'ajax_reset_all_spins')); add_action('wp_ajax_wheel_get_product', array($this, 'ajax_get_product')); add_action('wp_ajax_wheel_test_email', array($this, 'ajax_test_email')); add_action('wp_ajax_wheel_get_prizes', array($this, 'ajax_get_prizes')); add_action('wp_ajax_wof_delete_wheel_product', array($this, 'ajax_delete_wheel_product')); add_action('wp_ajax_wof_update_wheel_product_spins', array($this, 'ajax_update_wheel_product_spins')); // Vključi testno skripto za kupone if (is_admin()) { require_once WHEEL_OF_FORTUNE_PLUGIN_DIR . 'admin/coupon-test.php'; } } /** * Assigns spins to a user upon a completed WooCommerce purchase. * This method is hooked to 'woocommerce_order_status_processing' and 'woocommerce_order_status_completed'. * * @param int $order_id The ID of the WooCommerce order. */ public function assign_spins_on_purchase($order_id) { wheel_of_fortune_debug_log("=== SPIN ASSIGNMENT START ==="); wheel_of_fortune_debug_log("Hook triggered for order ID: $order_id"); if (!$order_id) { wheel_of_fortune_debug_log("No order ID provided. Exiting."); return; } $order = wc_get_order($order_id); if (!$order) { wheel_of_fortune_debug_log("Could not get order object for ID: $order_id. Exiting."); return; } $user_id = $order->get_user_id(); if (!$user_id) { wheel_of_fortune_debug_log("Order #$order_id has no associated user ID. Exiting."); return; } wheel_of_fortune_debug_log("Processing for User ID: $user_id"); global $wpdb; $wheel_products_table = $wpdb->prefix . 'wheel_of_fortune_products'; $total_spins_to_add_by_wheel = []; foreach ($order->get_items() as $item) { $product_id = $item->get_product_id(); $quantity = $item->get_quantity(); wheel_of_fortune_debug_log("Checking product ID: $product_id (Quantity: $quantity)"); $wheel_product = $wpdb->get_row($wpdb->prepare( "SELECT wheel_id, spins_per_purchase FROM $wheel_products_table WHERE product_id = %d", $product_id ), ARRAY_A); if ($wheel_product) { $wheel_id = (int)$wheel_product['wheel_id']; $spins_per_item = (int)$wheel_product['spins_per_purchase']; $spins_for_this_item = $spins_per_item * $quantity; wheel_of_fortune_debug_log("Product ID $product_id is a wheel product for Wheel ID: $wheel_id. Grants $spins_per_item spin(s) per purchase. Total for this item: $spins_for_this_item"); if (!isset($total_spins_to_add_by_wheel[$wheel_id])) { $total_spins_to_add_by_wheel[$wheel_id] = 0; } $total_spins_to_add_by_wheel[$wheel_id] += $spins_for_this_item; } else { wheel_of_fortune_debug_log("Product ID $product_id is not a wheel product."); } } if (!empty($total_spins_to_add_by_wheel)) { // Prepreci veckratno dodeljevanje spinov if (get_post_meta($order_id, '_wheel_spins_assigned', true)) { wheel_of_fortune_debug_log("Spins for order #$order_id have already been assigned. Exiting."); return; } wheel_of_fortune_debug_log("Total spins to add: " . print_r($total_spins_to_add_by_wheel, true)); $notes = []; foreach ($total_spins_to_add_by_wheel as $wheel_id => $spins) { if ($spins > 0) { wheel_of_fortune_debug_log("Adding $spins spin(s) to user $user_id for wheel $wheel_id."); if(wheel_of_fortune_add_spins($user_id, $spins, $wheel_id)){ $notes[] = sprintf(__('%d spin(s) for wheel #%d', 'wheel-of-fortune'), $spins, $wheel_id); } } } // Dodaj opombo k narocilu if(!empty($notes)){ $order->add_order_note(sprintf(__('User awarded Wheel of Fortune spins: %s.', 'wheel-of-fortune'), implode(', ', $notes))); update_post_meta($order_id, '_wheel_spins_assigned', true); } } else { wheel_of_fortune_debug_log("No wheel products found in order #$order_id."); } wheel_of_fortune_debug_log("=== SPIN ASSIGNMENT END ==="); } public function init() { // Initialization code can go here } public function activate() { error_log("Wheel of Fortune: Aktivacija plugina..."); $this->create_database_tables(); $this->run_migration(); $this->set_default_options(); $this->add_default_prizes(); // Debug: Preveri, ali se tabela za kolesa ustvari global $wpdb; $wheels_table = $wpdb->prefix . 'wof_wheels'; $wheel_products_table = $wpdb->prefix . 'wheel_of_fortune_products'; $wheels_exists = $wpdb->get_var("SHOW TABLES LIKE '$wheels_table'") == $wheels_table; $products_exists = $wpdb->get_var("SHOW TABLES LIKE '$wheel_products_table'") == $wheel_products_table; error_log("=== ACTIVATION DEBUG ==="); error_log("Wheels table exists: " . ($wheels_exists ? 'YES' : 'NO')); error_log("Products table exists: " . ($products_exists ? 'YES' : 'NO')); if (!$wheels_exists) { error_log('Wheel of Fortune: Wheels table was not created properly during activation.'); } else { error_log('Wheel of Fortune: Wheels table created successfully.'); } flush_rewrite_rules(); error_log("Wheel of Fortune: Aktivacija končana."); } public function deactivate() { flush_rewrite_rules(); } public function load_textdomain() { load_plugin_textdomain('wheel-of-fortune', false, dirname(plugin_basename(__FILE__)) . '/languages'); } private function create_database_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // Ustvari tabelo za kolesa $wheels_table = $wpdb->prefix . 'wof_wheels'; $wheel_products_table = $wpdb->prefix . 'wheel_of_fortune_products'; // Debug informacije za tabelo error_log("=== TABLE DEBUG ==="); error_log("Wheels table: " . $wheels_table); error_log("Products table: " . $wheel_products_table); // Preveri, ali tabela obstaja $wheels_table_exists = $wpdb->get_var("SHOW TABLES LIKE '$wheels_table'") == $wheels_table; error_log("Wheels table exists: " . ($wheels_table_exists ? 'YES' : 'NO')); $products_table_exists = $wpdb->get_var("SHOW TABLES LIKE '$wheel_products_table'") == $wheel_products_table; error_log("Products table exists: " . ($products_table_exists ? 'YES' : 'NO')); if ($wheels_table_exists) { $wheels_table_structure = $wpdb->get_results("DESCRIBE $wheels_table"); error_log("Wheels table structure: " . print_r($wheels_table_structure, true)); } if ($products_table_exists) { $products_table_structure = $wpdb->get_results("DESCRIBE $wheel_products_table"); error_log("Products table structure: " . print_r($products_table_structure, true)); } $sql_wheels = "CREATE TABLE $wheels_table ( id mediumint(9) NOT NULL AUTO_INCREMENT, name varchar(255) NOT NULL, slug varchar(100) NOT NULL, created_at datetime DEFAULT '0000-00-00 00:00:00' NOT NULL, PRIMARY KEY (id), UNIQUE KEY slug (slug) ) $charset_collate;"; $sql_products = "CREATE TABLE $wheel_products_table ( id mediumint(9) NOT NULL AUTO_INCREMENT, wheel_id mediumint(9) NOT NULL, product_id bigint(20) NOT NULL, spins_per_purchase int(11) NOT NULL DEFAULT 1, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY wheel_product (wheel_id, product_id) ) $charset_collate;"; // --- 2. Posodobljena tabela za nagrade --- $table_prizes = $wpdb->prefix . 'wheel_prizes'; $sql_prizes = "CREATE TABLE $table_prizes ( id mediumint(9) NOT NULL AUTO_INCREMENT, wheel_id mediumint(9) NOT NULL DEFAULT 1, name varchar(255) NOT NULL, description text DEFAULT '', probability float NOT NULL, is_active tinyint(1) NOT NULL DEFAULT 1, image_url varchar(255) DEFAULT '', email_subject varchar(255) DEFAULT '', email_template text DEFAULT '', redemption_code varchar(100) DEFAULT '', is_discount tinyint(1) NOT NULL DEFAULT 0, discount_value float DEFAULT 0, PRIMARY KEY (id), KEY wheel_id (wheel_id) ) $charset_collate;"; // --- 3. Posodobljena tabela za spine (NOVO - spini po kolesih) --- $table_spins = $wpdb->prefix . 'wheel_spins'; $sql_spins = "CREATE TABLE $table_spins ( id mediumint(9) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, wheel_id mediumint(9) NOT NULL DEFAULT 1, spins_available int(11) NOT NULL DEFAULT 0, last_spin_date datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY user_wheel (user_id, wheel_id), KEY user_id (user_id), KEY wheel_id (wheel_id) ) $charset_collate;"; // --- 4. Posodobljena tabela za log (NOVO - log po kolesih) --- $table_log = $wpdb->prefix . 'wheel_log'; $sql_log = "CREATE TABLE $table_log ( id mediumint(9) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, wheel_id mediumint(9) NOT NULL DEFAULT 1, prize_id mediumint(9) NOT NULL, spin_date datetime NOT NULL, redeemed tinyint(1) NOT NULL DEFAULT 0, redemption_code varchar(100) DEFAULT '', PRIMARY KEY (id), KEY user_id (user_id), KEY wheel_id (wheel_id), KEY prize_id (prize_id) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql_wheels); // Dodajanje nove tabele dbDelta($sql_products); dbDelta($sql_prizes); dbDelta($sql_spins); dbDelta($sql_log); // Debug: preveri, ali so se tabele ustvarile $wheels_after = $wpdb->get_var("SHOW TABLES LIKE '$wheels_table'") == $wheels_table; $products_after = $wpdb->get_var("SHOW TABLES LIKE '$wheel_products_table'") == $wheel_products_table; error_log("After dbDelta - Wheels table exists: " . ($wheels_after ? 'YES' : 'NO')); error_log("After dbDelta - Products table exists: " . ($products_after ? 'YES' : 'NO')); if (!$wheels_after) { error_log("Wheel of Fortune: Tabela $wheels_table se ni ustvarila!"); } else { error_log("Wheel of Fortune: Tabela $wheels_table uspešno ustvarjena."); } if (!$products_after) { error_log("Wheel of Fortune: Tabela $wheel_products_table se ni ustvarila!"); } else { error_log("Wheel of Fortune: Tabela $wheel_products_table uspešno ustvarjena."); } } private function run_migration() { global $wpdb; $wheels_table = $wpdb->prefix . 'wof_wheels'; $prizes_table = $wpdb->prefix . 'wheel_prizes'; $spins_table = $wpdb->prefix . 'wheel_spins'; $log_table = $wpdb->prefix . 'wheel_log'; // Debug informacije error_log("=== MIGRATION DEBUG ==="); error_log("Wheels table: " . $wheels_table); error_log("Prizes table: " . $prizes_table); error_log("Spins table: " . $spins_table); error_log("Log table: " . $log_table); // 1. Preveri, če "Default" kolo že obstaja $default_wheel_exists = $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $wheels_table WHERE id = %d", 1)); error_log("Default wheel exists: " . $default_wheel_exists); // 2. Če ne obstaja, ga ustvari if (!$default_wheel_exists) { error_log("Creating default wheel..."); $result = $wpdb->insert( $wheels_table, [ 'id' => 1, 'name' => __('Default Wheel', 'wheel-of-fortune'), 'slug' => 'default', 'created_at' => current_time('mysql') ], ['%d', '%s', '%s', '%s'] ); error_log("Insert result: " . $result); error_log("Last SQL query: " . $wpdb->last_query); error_log("Last SQL error: " . $wpdb->last_error); } // 3. Posodobi obstoječe nagrade, da pripadajo privzetemu kolesu $prizes_updated = $wpdb->query("UPDATE $prizes_table SET wheel_id = 1 WHERE wheel_id = 0 OR wheel_id IS NULL"); error_log("Prizes updated: " . $prizes_updated); // 4. Migriraj obstoječe spine v novo strukturo $existing_spins = $wpdb->get_results("SELECT user_id, meta_value as spins FROM {$wpdb->usermeta} WHERE meta_key = '_wheel_spins' AND meta_value > 0"); error_log("Existing spins found: " . count($existing_spins)); foreach ($existing_spins as $spin_data) { // Preveri, če zapis že obstaja $existing_record = $wpdb->get_var($wpdb->prepare( "SELECT id FROM $spins_table WHERE user_id = %d AND wheel_id = 1", $spin_data->user_id )); if (!$existing_record) { $result = $wpdb->insert( $spins_table, [ 'user_id' => $spin_data->user_id, 'wheel_id' => 1, 'spins_available' => intval($spin_data->spins), 'last_spin_date' => current_time('mysql') ], ['%d', '%d', '%d', '%s'] ); error_log("Migrated spins for user {$spin_data->user_id}: " . $result); } } // 5. Migriraj obstoječi log (če obstaja) $log_updated = $wpdb->query("UPDATE $log_table SET wheel_id = 1 WHERE wheel_id = 0 OR wheel_id IS NULL"); error_log("Log updated: " . $log_updated); // 6. Dodaj privzete nagrade, če jih ni $existing_prizes = $wpdb->get_var("SELECT COUNT(*) FROM $prizes_table WHERE wheel_id = 1"); if ($existing_prizes == 0) { $this->add_default_prizes(); } } private function set_default_options() { $default_options = array( 'wheel_cooldown_minutes' => 0, 'wheel_max_spins' => 0, 'wheel_send_emails' => true, // E-pošta se vedno pošlje 'wheel_spin_products' => array(), 'wheel_smtp_enabled' => false, 'wheel_smtp_host' => '', 'wheel_smtp_port' => '587', 'wheel_smtp_username' => '', 'wheel_smtp_password' => '', 'wheel_smtp_encryption' => 'tls', 'wheel_email_from_name' => get_bloginfo('name'), 'wheel_email_from_email' => get_bloginfo('admin_email'), ); foreach ($default_options as $option => $value) { if (get_option($option) === false) { add_option($option, $value); } } $this->add_default_prizes(); } private function add_default_prizes() { global $wpdb; $table_name = $wpdb->prefix . 'wheel_prizes'; $count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name"); if ($count == 0) { // Default prizes with wheel_id $default_prizes = array( ['wheel_id' => 1, 'name' => '200k FTMO', 'description' => '200k FTMO voucher', 'probability' => 0.05, 'is_active' => 1], ['wheel_id' => 1, 'name' => '20% OFF', 'description' => '20% discount on your next purchase', 'probability' => 0.15, 'is_active' => 1], ['wheel_id' => 1, 'name' => '50k Funded7', 'description' => '50k Funded7 voucher', 'probability' => 0.10, 'is_active' => 1], ['wheel_id' => 1, 'name' => '15% OFF', 'description' => '15% discount on your next purchase', 'probability' => 0.20, 'is_active' => 1], ['wheel_id' => 1, 'name' => '100k TugeTrade', 'description' => '100k TugeTrade voucher', 'probability' => 0.10, 'is_active' => 1], ['wheel_id' => 1, 'name' => '5k Alpicap', 'description' => '5k Alpicap voucher', 'probability' => 0.15, 'is_active' => 1], ['wheel_id' => 1, 'name' => '30% OFF', 'description' => '30% discount on your next purchase', 'probability' => 0.10, 'is_active' => 1], ['wheel_id' => 1, 'name' => '200k FundedNext', 'description' => '200k FundedNext voucher', 'probability' => 0.05, 'is_active' => 1], ['wheel_id' => 1, 'name' => '75% OFF', 'description' => '75% discount on your next purchase', 'probability' => 0.05, 'is_active' => 1], ['wheel_id' => 1, 'name' => '200k FundingPips', 'description' => '200k FundingPips voucher', 'probability' => 0.05, 'is_active' => 1] ); foreach ($default_prizes as $prize) { $wpdb->insert($table_name, $prize); } } } public function admin_menu() { add_menu_page( __('Wheels of Fortune', 'wheel-of-fortune'), __('Wheels', 'wheel-of-fortune'), 'manage_options', 'wof-wheels', // slug array($this, 'wheels_page'), // callback 'dashicons-marker', 30 ); // Stran za urejanje posameznega kolesa (skrita iz glavnega menija, dostopna preko linkov) add_submenu_page( 'wof-wheels', // parent slug __('Edit Wheel', 'wheel-of-fortune'), __('Edit Wheel', 'wheel-of-fortune'), 'manage_options', 'wof-edit-wheel', array($this, 'edit_wheel_page') ); // Statistika in uporabniki add_submenu_page('wof-wheels', __('Statistics', 'wheel-of-fortune'), __('Statistics', 'wheel-of-fortune'), 'manage_options', 'wof-stats', array($this, 'stats_page')); add_submenu_page('wof-wheels', __('Users & Spins', 'wheel-of-fortune'), __('Users & Spins', 'wheel-of-fortune'), 'manage_options', 'wof-users', array($this, 'users_page')); } public function wheels_page() { require_once WHEEL_OF_FORTUNE_PLUGIN_DIR . 'admin/wheels-page.php'; } public function edit_wheel_page() { require_once WHEEL_OF_FORTUNE_PLUGIN_DIR . 'admin/edit-wheel-page.php'; } public function prizes_page() { // Ta stran ni več v uporabi, saj so nagrade urejene pod vsakim kolesom // Pustimo jo zaenkrat prazno ali preusmerimo echo "

" . __("This page is deprecated. Please manage prizes under a specific wheel.", "wheel-of-fortune") . "

"; } public function stats_page() { include WHEEL_OF_FORTUNE_PLUGIN_DIR . 'admin/stats-page.php'; } public function users_page() { include WHEEL_OF_FORTUNE_PLUGIN_DIR . 'admin/users-page.php'; } public function register_rest_routes() { register_rest_route('wheel-of-fortune/v1', '/spin', array('methods' => 'POST', 'callback' => array($this, 'process_wheel_spin'), 'permission_callback' => 'is_user_logged_in')); register_rest_route('wheel-of-fortune/v1', '/test', array('methods' => 'GET', 'callback' => function() { return new WP_REST_Response(['success' => true, 'message' => 'REST API endpoint is working correctly.'], 200); }, 'permission_callback' => '__return_true')); } public function process_wheel_spin(WP_REST_Request $request) { $user_id = get_current_user_id(); if ($user_id === 0) { return new WP_Error('not_logged_in', __('You must be logged in to spin the wheel.', 'wheel-of-fortune'), ['status' => 401]); } $wheel_id = $request->get_param('wheel_id'); if (empty($wheel_id)) { return new WP_Error('no_wheel_id', __('Wheel ID is missing.', 'wheel-of-fortune'), ['status' => 400]); } global $wpdb; $spins_table = $wpdb->prefix . 'wheel_spins'; $user_spins = $wpdb->get_row($wpdb->prepare("SELECT spins_available FROM $spins_table WHERE user_id = %d AND wheel_id = %d", $user_id, $wheel_id)); $spins = $user_spins ? intval($user_spins->spins_available) : 0; if ($spins <= 0) { return new WP_Error('no_spins', __('You have no spins left.', 'wheel-of-fortune'), ['status' => 403]); } $prizes = $this->get_wheel_prizes($wheel_id); if (empty($prizes)) { return new WP_Error('no_prizes', __('No prizes available.', 'wheel-of-fortune'), ['status' => 500]); } // Uporabi delujočo logiko za izbiro nagrade $prize = $this->select_random_prize($prizes); $new_spins = $spins - 1; $wpdb->update($spins_table, ['spins_available' => $new_spins, 'last_spin_date' => current_time('mysql')], ['user_id' => $user_id, 'wheel_id' => $wheel_id]); $log_table = $wpdb->prefix . 'wheel_log'; $wpdb->insert($log_table, ['user_id' => $user_id, 'wheel_id' => $wheel_id, 'prize_id' => $prize['id'], 'spin_date' => current_time('mysql'), 'redeemed' => 0]); $log_id = $wpdb->insert_id; // Uporabi delujočo logiko za izračun kota $degree = $this->calculate_prize_degree($prize['id'], $prizes); $redemption_code = !empty($prize['redemption_code']) ? $prize['redemption_code'] : ''; $user = get_userdata($user_id); if ($prize['is_discount'] && $prize['discount_value'] > 0 && class_exists('WooCommerce')) { $coupon_code = 'WOF-' . uniqid() . '-' . $user->ID; $coupon_id = $this->create_coupon_with_best_method($coupon_code, $user, $prize['discount_value']); if ($coupon_id) { $redemption_code = $coupon_code; $wpdb->update($log_table, ['redemption_code' => $redemption_code], ['id' => $log_id]); $prize['redemption_code'] = $redemption_code; } } if (get_option('wheel_send_emails', true)) { $this->send_prize_email($user_id, $prize); } $response_data = [ 'prize' => $prize, 'degree' => $degree, 'remaining_spins' => $new_spins, 'discount_code' => $redemption_code ]; return new WP_REST_Response(['success' => true, 'data' => $response_data], 200); } public function get_wheel_prizes($wheel_id = 1) { global $wpdb; $table_name = $wpdb->prefix . 'wheel_prizes'; return $wpdb->get_results($wpdb->prepare("SELECT * FROM $table_name WHERE wheel_id = %d AND is_active = 1 ORDER BY id ASC", $wheel_id), ARRAY_A); } private function select_random_prize($prizes) { // Filter out prizes with 0 probability $winnable_prizes = array_filter($prizes, function($prize) { return isset($prize['probability']) && $prize['probability'] > 0; }); // If no winnable prizes, return null or handle as an error if (empty($winnable_prizes)) { return end($prizes); // Or null, depending on desired behavior for no-win scenario } // Recalculate total probability for winnable prizes $total_probability = array_sum(wp_list_pluck($winnable_prizes, 'probability')); // Normalize probabilities if they don't sum to 1 if ($total_probability > 0) { foreach ($winnable_prizes as &$prize) { $prize['probability'] = $prize['probability'] / $total_probability; } unset($prize); } $rand = mt_rand(1, 10000) / 10000; // Increased precision $cumulative = 0; foreach ($winnable_prizes as $prize) { $cumulative += $prize['probability']; if ($rand <= $cumulative) { return $prize; } } return end($winnable_prizes); // Fallback to the last winnable prize } private function calculate_prize_degree($prize_id, $prizes) { $prize_index = -1; foreach ($prizes as $index => $prize) { if ($prize['id'] == $prize_id) { $prize_index = $index; break; } } if ($prize_index === -1) return 0; $num_prizes = count($prizes); $cx = 350; $cy = 350; $outer_radius = 330; $inner_radius = 70; $angle = 360 / $num_prizes; $segment_size = $angle; $prize_angle = $prize_index * $segment_size + ($segment_size / 2); $target_stop_angle = 270 - $prize_angle; $variation_range = $segment_size * 0.20; $random_variation = mt_rand(-$variation_range, $variation_range); $final_angle = $target_stop_angle + $random_variation; $final_angle = fmod($final_angle, 360); return ($final_angle < 0) ? $final_angle + 360 : $final_angle; } public function shortcode($atts) { $atts = shortcode_atts(array( 'id' => '1', // Default to wheel ID 1 or slug 'default' ), $atts, 'wheel_of_fortune'); global $wpdb; $wheels_table = $wpdb->prefix . 'wof_wheels'; $wheel_id_or_slug = $atts['id']; if (is_numeric($wheel_id_or_slug)) { $wheel = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wheels_table WHERE id = %d", $wheel_id_or_slug), ARRAY_A); } else { $wheel = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wheels_table WHERE slug = %s", $wheel_id_or_slug), ARRAY_A); } if (!$wheel) { $wheel = $wpdb->get_row($wpdb->prepare("SELECT * FROM $wheels_table WHERE id = 1"), ARRAY_A); if (!$wheel) { return ''; } } $wheel_id = $wheel['id']; if (!is_user_logged_in()) { return '
' . sprintf(__('You need to log in to participate in this game.', 'wheel-of-fortune'), wp_login_url(get_permalink())) . '
'; } $prizes = $this->get_wheel_prizes($wheel_id); if (empty($prizes)) { return ''; } $this->enqueue_frontend_assets(); $user_id = get_current_user_id(); $spins_table = $wpdb->prefix . 'wheel_spins'; $spins_left = $wpdb->get_var($wpdb->prepare("SELECT spins_available FROM $spins_table WHERE user_id = %d AND wheel_id = %d", $user_id, $wheel_id)); $spins_left = ($spins_left === null) ? 0 : (int)$spins_left; // Definiramo polje za prevode, da bo dostopno v PHP in JS $l10n = [ 'spin_button' => __('SPIN', 'wheel-of-fortune'), 'spinning' => __('Spinning...', 'wheel-of-fortune'), 'no_spins_left' => __('No More Spins', 'wheel-of-fortune'), 'congratulations' => __('Congratulations!', 'wheel-of-fortune'), 'you_won' => __('You won:', 'wheel-of-fortune'), 'close' => __('Close', 'wheel-of-fortune'), 'error' => __('Error', 'wheel-of-fortune'), 'discount_code_sent' => __('Your discount code has been sent to your email.', 'wheel-of-fortune'), ]; wp_localize_script('wheel-of-fortune-js', 'wof_data', array( 'ajax_url' => admin_url('admin-ajax.php'), 'rest_url' => get_rest_url(null, 'wheel-of-fortune/v1/spin'), 'nonce' => wp_create_nonce('wp_rest'), 'wheel_id' => $wheel_id, 'spins_left' => $spins_left, 'prizes' => $prizes, 'l10n' => $l10n // Uporabimo definirano polje )); ob_start(); // Pass variables to the template include(WHEEL_OF_FORTUNE_PLUGIN_DIR . 'public/shortcode-template.php'); return ob_get_clean(); } public function enqueue_frontend_assets() { wp_enqueue_style('wheel-of-fortune-css', WHEEL_OF_FORTUNE_PLUGIN_URL . 'assets/css/wheel.css', [], WHEEL_OF_FORTUNE_VERSION); wp_enqueue_script('wheel-of-fortune-js', WHEEL_OF_FORTUNE_PLUGIN_URL . 'assets/js/wheel.js', ['jquery'], WHEEL_OF_FORTUNE_VERSION, true); } public function enqueue_admin_assets($hook) { // Preveri, ali je trenutna stran ena od naših admin strani if (strpos($hook, 'wof-') !== false || strpos($hook, 'wheel-') !== false) { wp_enqueue_style('wheel-of-fortune-admin-css', WHEEL_OF_FORTUNE_PLUGIN_URL . 'assets/css/admin.css', [], WHEEL_OF_FORTUNE_VERSION); wp_enqueue_script('wheel-of-fortune-admin-js', WHEEL_OF_FORTUNE_PLUGIN_URL . 'admin/js/admin.js', ['jquery'], WHEEL_OF_FORTUNE_VERSION, true); wp_localize_script('wheel-of-fortune-admin-js', 'wheel_admin_nonce', array('_ajax_nonce' => wp_create_nonce('wheel_admin_nonce'))); wp_localize_script('wheel-of-fortune-admin-js', 'wheel_admin_i18n', [ 'select_user' => __('Select a user', 'wheel-of-fortune'), 'select_user_and_spins' => __('Please select a user and enter the number of spins.', 'wheel-of-fortune'), 'confirm_reset_all_spins' => __('Are you sure you want to reset the spins for all users? This cannot be undone!', 'wheel-of-fortune'), 'enter_product_id_and_spins' => __('Please enter the product ID and number of spins.', 'wheel-of-fortune'), 'remove' => __('Remove', 'wheel-of-fortune'), 'no_products' => __('No products have been configured.', 'wheel-of-fortune'), 'product_not_found' => __('Product not found.', 'wheel-of-fortune'), 'error_finding_product' => __('Error finding product.', 'wheel-of-fortune'), 'active' => __('Active', 'wheel-of-fortune'), 'inactive' => __('Inactive', 'wheel-of-fortune'), 'confirm_delete_prize' => __('Are you sure you want to delete this prize?', 'wheel-of-fortune'), 'sending' => __('Sending...', 'wheel-of-fortune'), 'sending_test_email' => __('Sending test email...', 'wheel-of-fortune'), 'send_test_email' => __('Send Test Email', 'wheel-of-fortune'), 'error_sending_email' => __('Error sending email.', 'wheel-of-fortune'), 'enter_recipient_email' => __('Please enter a recipient email address.', 'wheel-of-fortune'), ]); } } private function is_woocommerce_active() { return in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins'))); } /** * Generates the SVG for the wheel with visible, curved, and auto-adjusting text. * This version uses for superior text rendering on segments. * * @param array $prizes The array of prizes. * @return string The generated SVG string. */ public function generate_wheel_svg($prizes) { $num_prizes = count($prizes); if ($num_prizes === 0) { return '
' . esc_html__('No prizes available.', 'wheel-of-fortune') . '
'; } // SVG dimensions and parameters $cx = 350; $cy = 350; $outer_radius = 330; $inner_radius = 70; $angle = 360 / $num_prizes; // Initialize SVG parts $defs = ''; $segments_paths = ''; $text_paths = ''; // Generate segments and text paths $segment_colors = ['#00dfe9', '#ff00c4', '#0cf101']; for ($i = 0; $i < $num_prizes; $i++) { $prize = $prizes[$i]; $start_angle = $i * $angle; $end_angle = ($i + 1) * $angle; // --- 1. Draw the visible segment path --- $start_rad = deg2rad($start_angle); $end_rad = deg2rad($end_angle); $x1 = $cx + $outer_radius * cos($start_rad); $y1 = $cy + $outer_radius * sin($start_rad); $x2 = $cx + $outer_radius * cos($end_rad); $y2 = $cy + $outer_radius * sin($end_rad); $x3 = $cx + $inner_radius * cos($end_rad); $y3 = $cy + $inner_radius * sin($end_rad); $x4 = $cx + $inner_radius * cos($start_rad); $y4 = $cy + $inner_radius * sin($start_rad); $large_arc = ($end_angle - $start_angle > 180) ? 1 : 0; $path_data = "M{$x1},{$y1} A{$outer_radius},{$outer_radius} 0 {$large_arc},1 {$x2},{$y2} L{$x3},{$y3} A{$inner_radius},{$inner_radius} 0 {$large_arc},0 {$x4},{$y4} Z"; // Barva segmenta - ciklično, a če je nagrad 10, zadnji segment ne sme biti enak prvemu $color_index = $i % count($segment_colors); if ($num_prizes === 10 && $i === $num_prizes - 1 && $segment_colors[$color_index] === $segment_colors[0]) { $color_index = ($color_index + 1) % count($segment_colors); } $segment_color = $segment_colors[$color_index]; $segments_paths .= ""; // --- 2. Draw dividers and pegs --- $divider_x1 = $cx + $inner_radius * cos($start_rad); $divider_y1 = $cy + $inner_radius * sin($start_rad); $divider_x2 = $cx + $outer_radius * cos($start_rad); $divider_y2 = $cy + $outer_radius * sin($start_rad); $segments_paths .= ""; $segments_paths .= ""; // --- 3. Draw text vertically (rotated to segment center) --- $text_angle = $start_angle + ($angle / 2); $text_rad = deg2rad($text_angle); $text_radius = ($inner_radius + $outer_radius) / 2; $text_x = $cx + $text_radius * cos($text_rad); $text_y = $cy + $text_radius * sin($text_rad); $rotate = $text_angle; // Da je vedno navzven (ne na glavo) if ($rotate > 90 && $rotate < 270) { $rotate += 180; } $text_paths .= "{$prize['name']}"; } $defs .= ''; // Assemble the final SVG $svg = ''; $svg .= $defs; // Add definitions first $svg .= ''; $svg .= ''; $svg .= $segments_paths; // Add all segments, dividers, and pegs $svg .= ''; $svg .= ''; $svg .= $text_paths; // Add all text paths on top of segments $svg .= ''; $svg .= "SPIN"; $svg .= ''; return $svg; } public function ajax_get_prize_details() { check_ajax_referer('wheel_admin_nonce', '_ajax_nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); } $prize_id = isset($_POST['prize_id']) ? intval($_POST['prize_id']) : 0; if (!$prize_id) { wp_send_json_error(['message' => __('Prize ID was not provided.', 'wheel-of-fortune')]); } global $wpdb; $prize = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}wheel_prizes WHERE id = %d", $prize_id), ARRAY_A); if (!$prize) { wp_send_json_error(['message' => __('Prize not found.', 'wheel-of-fortune')]); } wp_send_json_success($prize); } public function ajax_save_prize() { check_ajax_referer('wheel_admin_nonce', '_ajax_nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); } // Dodamo wheel_id $wheel_id = isset($_POST['wheel_id']) ? intval($_POST['wheel_id']) : 0; $prize_id = isset($_POST['prize_id']) ? intval($_POST['prize_id']) : 0; $name = isset($_POST['name']) ? sanitize_text_field($_POST['name']) : ''; $description = isset($_POST['description']) ? sanitize_textarea_field($_POST['description']) : ''; $probability = isset($_POST['probability']) ? floatval($_POST['probability']) : 0; $is_active = isset($_POST['is_active']) ? intval($_POST['is_active']) : 0; $redemption_code = isset($_POST['redemption_code']) ? sanitize_text_field($_POST['redemption_code']) : ''; $is_discount = isset($_POST['is_discount']) ? intval($_POST['is_discount']) : 0; $email_subject = isset($_POST['email_subject']) ? sanitize_text_field($_POST['email_subject']) : ''; $email_template = isset($_POST['email_template']) ? wp_kses_post($_POST['email_template']) : ''; $discount_value = isset($_POST['discount_value']) ? floatval($_POST['discount_value']) : 0; if (empty($name)) { wp_send_json_error(['message' => __('Prize name is required.', 'wheel-of-fortune')]); } if ($wheel_id === 0) { wp_send_json_error(['message' => __('Wheel ID is missing.', 'wheel-of-fortune')]); } if ($probability < 0 || $probability > 1) { wp_send_json_error(['message' => __('Probability must be between 0 and 1.', 'wheel-of-fortune')]); } global $wpdb; $table_name = $wpdb->prefix . 'wheel_prizes'; $data = [ 'wheel_id' => $wheel_id, 'name' => $name, 'description' => $description, 'probability' => $probability, 'is_active' => $is_active, 'redemption_code' => $redemption_code, 'is_discount' => $is_discount, 'email_subject' => $email_subject, 'email_template' => $email_template, 'discount_value' => $discount_value, ]; $format = ['%d', '%s', '%s', '%f', '%d', '%s', '%d', '%s', '%s', '%f']; if ($prize_id > 0) { $result = $wpdb->update($table_name, $data, ['id' => $prize_id], $format, ['%d']); } else { $result = $wpdb->insert($table_name, $data, $format); $prize_id = $wpdb->insert_id; } if ($result === false) { wp_send_json_error(['message' => $wpdb->last_error]); } else { wp_send_json_success(['message' => __('Prize saved successfully!', 'wheel-of-fortune'), 'prize_id' => $prize_id]); } } public function ajax_delete_prize() { check_ajax_referer('wheel_admin_nonce', '_ajax_nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); } $prize_id = isset($_POST['prize_id']) ? intval($_POST['prize_id']) : 0; if (!$prize_id) { wp_send_json_error(['message' => __('Prize ID was not provided.', 'wheel-of-fortune')]); } global $wpdb; $table_name = $wpdb->prefix . 'wheel_prizes'; $result = $wpdb->delete($table_name, ['id' => $prize_id]); if ($result !== false) { wp_send_json_success(['message' => __('Prize deleted successfully.', 'wheel-of-fortune')]); } else { wp_send_json_error(['message' => __('Failed to delete the prize.', 'wheel-of-fortune')]); } } public function ajax_search_users() { check_ajax_referer('wheel_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); } $search = isset($_POST['search']) ? sanitize_text_field($_POST['search']) : ''; if (empty($search)) { wp_send_json_error(['message' => __('Search term is required.', 'wheel-of-fortune')]); } $users = get_users([ 'search' => '*' . $search . '*', 'search_columns' => ['user_login', 'user_email', 'display_name'], 'number' => 10 ]); $results = []; foreach ($users as $user) { $results[] = [ 'id' => $user->ID, 'name' => $user->display_name, 'email' => $user->user_email ]; } wp_send_json_success($results); } public function ajax_add_spins() { check_ajax_referer('wheel_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); } $user_id = isset($_POST['user_id']) ? intval($_POST['user_id']) : 0; $spins = isset($_POST['spins']) ? intval($_POST['spins']) : 0; if (!$user_id || $spins <= 0) { wp_send_json_error(['message' => __('Invalid user ID or number of spins.', 'wheel-of-fortune')]); } if (wheel_of_fortune_add_spins($user_id, $spins)) { wp_send_json_success(['message' => sprintf(__('Successfully added %d spins to user ID %d.', 'wheel-of-fortune'), $spins, $user_id)]); } else { wp_send_json_error(['message' => __('Failed to add spins to user.', 'wheel-of-fortune')]); } } public function ajax_reset_all_spins() { check_ajax_referer('wheel_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); } global $wpdb; $table_name = $wpdb->prefix . 'wheel_spins'; $result = $wpdb->update( $table_name, ['spins_available' => 0], [], ['%d'], [] ); if ($result !== false) { // Reset user meta fields too $users = get_users(['fields' => 'ID']); foreach ($users as $user_id) { update_user_meta($user_id, '_wheel_spins', 0); } wp_send_json_success(['message' => __('All spins have been reset to 0.', 'wheel-of-fortune')]); } else { wp_send_json_error(['message' => __('Failed to reset spins.', 'wheel-of-fortune')]); } } public function ajax_get_product() { check_ajax_referer('wheel_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); } if (!$this->is_woocommerce_active()) { wp_send_json_error(['message' => __('WooCommerce is not active.', 'wheel-of-fortune')]); } $product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0; if (!$product_id) { wp_send_json_error(['message' => __('Product ID is required.', 'wheel-of-fortune')]); } $product = wc_get_product($product_id); if (!$product) { wp_send_json_error(['message' => __('Product not found.', 'wheel-of-fortune')]); } wp_send_json_success([ 'id' => $product->get_id(), 'name' => $product->get_name() ]); } public function ajax_test_email() { check_ajax_referer('wheel_admin_nonce', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(['message' => __('You do not have permission to perform this action.', 'wheel-of-fortune')]); return; } $recipient_email = isset($_POST['recipient_email']) ? sanitize_email($_POST['recipient_email']) : ''; if (empty($recipient_email) || !is_email($recipient_email)) { wp_send_json_error(['message' => __('Please provide a valid recipient email address.', 'wheel-of-fortune')]); return; } // Get settings from the form, passed via AJAX $smtp_enabled = isset($_POST['smtp_enabled']) && $_POST['smtp_enabled'] === '1'; $smtp_host = isset($_POST['smtp_host']) ? sanitize_text_field($_POST['smtp_host']) : ''; $smtp_port = isset($_POST['smtp_port']) ? intval($_POST['smtp_port']) : 587; $smtp_encryption = isset($_POST['smtp_encryption']) ? sanitize_text_field($_POST['smtp_encryption']) : 'tls'; $smtp_username = isset($_POST['smtp_username']) ? sanitize_text_field($_POST['smtp_username']) : ''; $smtp_password = isset($_POST['smtp_password']) ? wp_unslash($_POST['smtp_password']) : ''; $from_name = isset($_POST['from_name']) ? sanitize_text_field($_POST['from_name']) : get_bloginfo('name'); $from_email = isset($_POST['from_email']) ? sanitize_email($_POST['from_email']) : get_bloginfo('admin_email'); $user = wp_get_current_user(); // Prepare email content $subject = __('Wheel of Fortune - Test Email', 'wheel-of-fortune'); $message_body = sprintf( __('Hello %1$s,

This is a test email from the Wheel of Fortune plugin.

If you received this message, your email settings seem to be working.

Current Settings Used for This Test:

Best regards,
The Wheel of Fortune Plugin', 'wheel-of-fortune'), $user->display_name, $smtp_enabled ? __('Yes', 'wheel-of-fortune') : __('No (using default wp_mail)', 'wheel-of-fortune'), esc_html($smtp_host), esc_html($smtp_port), esc_html(strtoupper($smtp_encryption)), esc_html($smtp_username), esc_html($from_name), esc_html($from_email) ); if (!$smtp_enabled) { // Use standard wp_mail if SMTP is disabled $headers = ['Content-Type: text/html; charset=UTF-8']; if (!empty($from_email) && !empty($from_name)) { $headers[] = 'From: ' . $from_name . ' <' . $from_email . '>'; } $result = wp_mail($recipient_email, $subject, $message_body, $headers); if ($result) { wp_send_json_success(['message' => sprintf(__('Test email successfully sent to %s using the standard WordPress mail function.', 'wheel-of-fortune'), esc_html($recipient_email))]); } else { global $phpmailer; $error_info = (isset($phpmailer) && is_object($phpmailer) && !empty($phpmailer->ErrorInfo)) ? $phpmailer->ErrorInfo : 'Please check your server\'s PHP mail logs.'; wp_send_json_error(['message' => sprintf(__('Failed to send email using wp_mail(). Error: %s', 'wheel-of-fortune'), esc_html($error_info))]); } return; } // --- Use a dedicated PHPMailer instance for SMTP test --- require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php'; require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php'; require_once ABSPATH . WPINC . '/PHPMailer/Exception.php'; $mail = new PHPMailer\PHPMailer\PHPMailer(true); try { // Server settings $mail->isSMTP(); $mail->Host = $smtp_host; $mail->SMTPAuth = !empty($smtp_username); $mail->Username = $smtp_username; $mail->Password = $smtp_password; if ($smtp_encryption === 'ssl') { $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS; } elseif ($smtp_encryption === 'tls') { $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS; } $mail->Port = $smtp_port; // Recipients $mail->setFrom($from_email, $from_name); $mail->addAddress($recipient_email); // Content $mail->isHTML(true); $mail->CharSet = 'UTF-8'; $mail->Subject = $subject; $mail->Body = $message_body; $mail->AltBody = wp_strip_all_tags($message_body); // Send the email $mail->send(); wp_send_json_success(['message' => sprintf(__('SMTP test email successfully sent to %s.', 'wheel-of-fortune'), esc_html($recipient_email))]); } catch (PHPMailer\PHPMailer\Exception $e) { // PHPMailer exception wp_send_json_error(['message' => sprintf(__('Failed to send email. Error: %s', 'wheel-of-fortune'), esc_html($mail->ErrorInfo))]); } catch (Exception $e) { // Other exceptions wp_send_json_error(['message' => sprintf(__('An unexpected error occurred: %s', 'wheel-of-fortune'), esc_html($e->getMessage()))]); } } public function ajax_get_prizes() { check_ajax_referer('wheel_public_nonce', 'nonce'); $wheel_id = isset($_POST['wheel_id']) ? intval($_POST['wheel_id']) : 1; $prizes = $this->get_wheel_prizes($wheel_id); wp_send_json_success($prizes); } /** * Ustvari kupon z uporabo najboljše metode, določene s testiranjem * * @param string $code Koda kupona * @param WP_User $user Uporabnik, za katerega se ustvari kupon * @param float $discount_value Vrednost popusta (v odstotkih) * @return int|bool ID kupona ali false v primeru napake */ private function create_coupon_with_best_method($code, $user, $discount_value) { // Pridobi najboljšo metodo iz nastavitev $best_method = get_option('wheel_best_coupon_method', 'standard_api'); wheel_of_fortune_debug_log("Creating coupon using method: {$best_method}"); switch ($best_method) { case 'programmatic': // Metoda 2: Programsko ustvarjanje kupona try { $coupon_data = array( 'post_title' => $code, 'post_content' => '', 'post_status' => 'publish', 'post_author' => $user->ID, 'post_type' => 'shop_coupon' ); $coupon_id = wp_insert_post($coupon_data); if (!is_wp_error($coupon_id)) { // Dodaj meta podatke za kupon update_post_meta($coupon_id, 'discount_type', 'percent'); update_post_meta($coupon_id, 'coupon_amount', $discount_value); update_post_meta($coupon_id, 'individual_use', 'yes'); update_post_meta($coupon_id, 'usage_limit', '1'); update_post_meta($coupon_id, 'usage_limit_per_user', '1'); update_post_meta($coupon_id, 'customer_email', array($user->user_email)); update_post_meta($coupon_id, 'description', __('Wheel of Fortune', 'wheel-of-fortune')); return $coupon_id; } } catch (Exception $e) { wheel_of_fortune_debug_log("Error in programmatic method: " . $e->getMessage()); } break; case 'wc_coupon_extended': // Metoda 3: Uporaba WC_Coupon z dodatnimi preverjanji try { // Preveri, ali koda že obstaja $existing_id = wc_get_coupon_id_by_code($code); if ($existing_id) { wheel_of_fortune_debug_log("Coupon code already exists: {$code}"); return false; } // Ustvari nov kupon z dodatnimi preverjanji $coupon = new WC_Coupon(); $coupon->set_code($code); $coupon->set_description(__('Wheel of Fortune', 'wheel-of-fortune')); $coupon->set_discount_type('percent'); $coupon->set_amount($discount_value); $coupon->set_individual_use(true); $coupon->set_usage_limit(1); $coupon->set_usage_limit_per_user(1); $coupon->set_email_restrictions(array($user->user_email)); // Dodatna nastavitev $coupon->set_date_expires(strtotime('+30 days')); $coupon_id = $coupon->save(); // Preveri, ali je kupon res ustvarjen if ($coupon_id) { $verification_id = wc_get_coupon_id_by_code($code); if ($verification_id && $verification_id == $coupon_id) { return $coupon_id; } } } catch (Exception $e) { wheel_of_fortune_debug_log("Error in wc_coupon_extended method: " . $e->getMessage()); } break; case 'direct_db': // Metoda 4: Neposredno vstavljanje v podatkovno bazo try { global $wpdb; // Ustvari nov post tipa shop_coupon $wpdb->insert( $wpdb->posts, array( 'post_title' => $code, 'post_name' => sanitize_title($code), 'post_content' => '', 'post_status' => 'publish', 'post_author' => $user->ID, 'post_type' => 'shop_coupon', 'post_date' => current_time('mysql'), 'post_date_gmt' => current_time('mysql', 1) ) ); $coupon_id = $wpdb->insert_id; if ($coupon_id) { // Dodaj meta podatke za kupon $meta_data = array( 'discount_type' => 'percent', 'coupon_amount' => $discount_value, 'individual_use' => 'yes', 'usage_limit' => '1', 'usage_limit_per_user' => '1', 'customer_email' => serialize(array($user->user_email)), 'description' => __('Wheel of Fortune', 'wheel-of-fortune') ); foreach ($meta_data as $meta_key => $meta_value) { $wpdb->insert( $wpdb->postmeta, array( 'post_id' => $coupon_id, 'meta_key' => $meta_key, 'meta_value' => $meta_value ) ); } return $coupon_id; } } catch (Exception $e) { wheel_of_fortune_debug_log("Error in direct_db method: " . $e->getMessage()); } break; case 'standard_api': default: // Metoda 1: Standardna WooCommerce API metoda (privzeta) try { $coupon = new WC_Coupon(); $coupon->set_code($code); $coupon->set_description(__('Wheel of Fortune', 'wheel-of-fortune')); $coupon->set_discount_type('percent'); $coupon->set_amount($discount_value); $coupon->set_individual_use(true); $coupon->set_usage_limit(1); $coupon->set_usage_limit_per_user(1); $coupon->set_email_restrictions(array($user->user_email)); $coupon_id = $coupon->save(); if ($coupon_id) { return $coupon_id; } } catch (Exception $e) { wheel_of_fortune_debug_log("Error in standard_api method: " . $e->getMessage()); } break; } // Če pridemo do sem, je prišlo do napake pri ustvarjanju kupona return false; } /** * Sends an email notification to the user upon winning a prize. * * @param int $user_id The ID of the user who won. * @param array $prize The prize details array. */ public function send_prize_email($user_id, $prize) { $user = get_userdata($user_id); if (!$user) { wheel_of_fortune_debug_log("send_prize_email: Uporabnik z ID {$user_id} ni bil najden."); return; } // Določi vsebino emaila - uporabi specifično predlogo za nagrado, če obstaja, sicer splošno $subject = !empty($prize['email_subject']) ? $prize['email_subject'] : sprintf(__('Congratulations! You won a prize on the Wheel of Fortune - %s', 'wheel-of-fortune'), get_bloginfo('name')); $body = !empty($prize['email_template']) ? $prize['email_template'] : file_get_contents(WHEEL_OF_FORTUNE_PLUGIN_DIR . 'templates/emails/default-prize-email.html'); // Pripravi nadomestne oznake (placeholders) $replacements = [ '{user_name}' => $user->display_name, '{user_email}' => $user->user_email, '{prize_name}' => $prize['name'], '{prize_description}' => $prize['description'], '{redemption_code}' => !empty($prize['redemption_code']) ? $prize['redemption_code'] : __('N/A', 'wheel-of-fortune'), '{site_name}' => get_bloginfo('name'), '{site_url}' => home_url(), '{date}' => date_i18n(get_option('date_format')), '{time}' => date_i18n(get_option('time_format')), ]; // Zamenjaj oznake v vsebini in zadevi $final_subject = str_replace(array_keys($replacements), array_values($replacements), $subject); $final_body = str_replace(array_keys($replacements), array_values($replacements), $body); // Pridobi nastavitve pošiljatelja $from_name = get_option('wheel_email_from_name', get_bloginfo('name')); $from_email = get_option('wheel_email_from_email', get_bloginfo('admin_email')); $headers = [ 'Content-Type: text/html; charset=UTF-8', 'From: ' . $from_name . ' <' . $from_email . '>' ]; // Preveri, ali je omogočen SMTP if (get_option('wheel_smtp_enabled', false)) { // Pošlji preko SMTP z uporabo PHPMailer require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php'; require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php'; require_once ABSPATH . WPINC . '/PHPMailer/Exception.php'; $mail = new PHPMailer\PHPMailer\PHPMailer(true); try { $mail->isSMTP(); $mail->Host = get_option('wheel_smtp_host'); $mail->SMTPAuth = !empty(get_option('wheel_smtp_username')); $mail->Username = get_option('wheel_smtp_username'); $mail->Password = get_option('wheel_smtp_password'); $mail->Port = get_option('wheel_smtp_port', 587); $smtp_encryption = get_option('wheel_smtp_encryption', 'tls'); if ($smtp_encryption === 'ssl') { $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_SMTPS; } elseif ($smtp_encryption === 'tls') { $mail->SMTPSecure = PHPMailer\PHPMailer\PHPMailer::ENCRYPTION_STARTTLS; } $mail->setFrom($from_email, $from_name); $mail->addAddress($user->user_email, $user->display_name); $mail->isHTML(true); $mail->CharSet = 'UTF-8'; $mail->Subject = $final_subject; $mail->Body = $final_body; $mail->AltBody = wp_strip_all_tags($final_body); $mail->send(); wheel_of_fortune_debug_log("Email uspešno poslan preko SMTP na {$user->user_email}."); } catch (Exception $e) { wheel_of_fortune_debug_log("Napaka pri pošiljanju emaila preko SMTP: {$mail->ErrorInfo}"); } } else { // Pošlji preko standardne wp_mail() funkcije if (wp_mail($user->user_email, $final_subject, $final_body, $headers)) { wheel_of_fortune_debug_log("Email uspešno poslan preko wp_mail() na {$user->user_email}."); } else { wheel_of_fortune_debug_log("Napaka pri pošiljanju emaila preko wp_mail()."); } } } public function ajax_update_wheel_product_spins() { check_ajax_referer('wof_update_wheel_product_spins'); if (!current_user_can('manage_options')) { wp_send_json_error(__('Nimaš dovoljenja.', 'wheel-of-fortune')); } global $wpdb; $id = isset($_POST['id']) ? intval($_POST['id']) : 0; $spins = isset($_POST['spins']) ? intval($_POST['spins']) : 1; // Debug informacije error_log("=== AJAX UPDATE WHEEL PRODUCT SPINS DEBUG ==="); error_log("POST data: " . print_r($_POST, true)); error_log("ID: " . $id); error_log("Spins: " . $spins); if ($id > 0 && $spins > 0) { $table = $wpdb->prefix . 'wheel_of_fortune_products'; error_log("Table: " . $table); $result = $wpdb->update($table, ['spins_per_purchase' => $spins], ['id' => $id], ['%d'], ['%d']); error_log("Update result: " . $result); error_log("Last SQL query: " . $wpdb->last_query); error_log("Last SQL error: " . $wpdb->last_error); if ($result !== false) { wp_send_json_success(); } } wp_send_json_error(__('Napaka pri shranjevanju.', 'wheel-of-fortune')); } public function ajax_delete_wheel_product() { check_ajax_referer('wof_delete_wheel_product'); if (!current_user_can('manage_options')) { wp_send_json_error(__('Nimaš dovoljenja.', 'wheel-of-fortune')); } global $wpdb; $id = isset($_POST['id']) ? intval($_POST['id']) : 0; // Debug informacije error_log("=== AJAX DELETE WHEEL PRODUCT DEBUG ==="); error_log("POST data: " . print_r($_POST, true)); error_log("ID to delete: " . $id); if ($id > 0) { $table = $wpdb->prefix . 'wheel_of_fortune_products'; error_log("Table: " . $table); $result = $wpdb->delete($table, ['id' => $id], ['%d']); error_log("Delete result: " . $result); error_log("Last SQL query: " . $wpdb->last_query); error_log("Last SQL error: " . $wpdb->last_error); if ($result !== false) { wp_send_json_success(); } } wp_send_json_error(__('Napaka pri brisanju.', 'wheel-of-fortune')); } } // Initialize plugin function wheel_of_fortune() { return WheelOfFortune::get_instance(); } wheel_of_fortune(); wheel_of_fortune();