Wheel_of_Fortune_Plugin/wheel-of-fortune.php

1561 lines
70 KiB
PHP

<?php
/**
* Plugin Name: Wheel of Fortune
* Plugin URI: https://example.com/wheel-of-fortune
* Description: A Wheel of Fortune for WooCommerce that allows users to spin a wheel for prizes.
* Version: 1.0.1
* Author: Mark Poljansek
* Author URI: https://example.com
* Text Domain: wheel-of-fortune
* Domain Path: /languages
* Requires at least: 5.6
* Requires PHP: 7.2
* WC requires at least: 4.0
* WC tested up to: 6.0
* License: GPL v2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
// Plugin constants
define('WHEEL_OF_FORTUNE_VERSION', '1.0.1');
define('WHEEL_OF_FORTUNE_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WHEEL_OF_FORTUNE_PLUGIN_URL', plugin_dir_url(__FILE__));
define('WHEEL_OF_FORTUNE_PLUGIN_FILE', __FILE__);
define('WHEEL_OF_FORTUNE_DEBUG', true); // OBVEZNO NASTAVITE NA true
/**
* Helper function for debug logging
*/
function wheel_of_fortune_debug_log($message) {
if (defined('WHEEL_OF_FORTUNE_DEBUG') && WHEEL_OF_FORTUNE_DEBUG) {
if (is_array($message) || is_object($message)) {
error_log('Wheel of Fortune Debug: ' . print_r($message, true));
} else {
error_log('Wheel of Fortune Debug: ' . $message);
}
}
}
/**
* Helper function to manually add spins to a user
*/
function wheel_of_fortune_add_spins($user_id, $spins, $wheel_id = 1) { // Privzeto kolo je 1
if (!$user_id || !is_numeric($spins) || $spins <= 0 || !is_numeric($wheel_id)) {
wheel_of_fortune_debug_log("add_spins: Invalid parameters provided. User: $user_id, Spins: $spins, Wheel: $wheel_id");
return false;
}
global $wpdb;
$table_spins = $wpdb->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 "<h2>" . __("This page is deprecated. Please manage prizes under a specific wheel.", "wheel-of-fortune") . "</h2>";
}
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 of Fortune: Default wheel not found. -->';
}
}
$wheel_id = $wheel['id'];
if (!is_user_logged_in()) {
return '<div class="wheel-login-required">' . sprintf(__('You need to <a href="%s">log in</a> to participate in this game.', 'wheel-of-fortune'), wp_login_url(get_permalink())) . '</div>';
}
$prizes = $this->get_wheel_prizes($wheel_id);
if (empty($prizes)) {
return '<!-- Wheel of Fortune: No prizes available for this wheel. -->';
}
$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 <textPath> 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 '<div class="wheel-error">' . esc_html__('No prizes available.', 'wheel-of-fortune') . '</div>';
}
// SVG dimensions and parameters
$cx = 350;
$cy = 350;
$outer_radius = 330;
$inner_radius = 70;
$angle = 360 / $num_prizes;
// Initialize SVG parts
$defs = '<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 .= "<path d='{$path_data}' class='wheel-segment' fill='{$segment_color}' />";
// --- 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 .= "<line x1='{$divider_x1}' y1='{$divider_y1}' x2='{$divider_x2}' y2='{$divider_y2}' class='wheel-divider' />";
$segments_paths .= "<circle cx='" . ($cx + ($outer_radius - 5) * cos($start_rad)) . "' cy='" . ($cy + ($outer_radius - 5) * sin($start_rad)) . "' r='5' class='wheel-peg' />";
// --- 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 .= "<text class='wheel-text' dominant-baseline='middle' x='{$text_x}' y='{$text_y}' transform='rotate({$rotate},{$text_x},{$text_y})'>{$prize['name']}</text>";
}
$defs .= '</defs>';
// Assemble the final SVG
$svg = '<svg viewBox="0 0 700 700" class="wheel">';
$svg .= $defs; // Add definitions first
$svg .= '<circle cx="' . $cx . '" cy="' . $cy . '" r="' . $outer_radius . '" class="wheel-frame" />';
$svg .= '<circle cx="' . $cx . '" cy="' . $cy . '" r="' . ($outer_radius - 10) . '" class="wheel-light-track" />';
$svg .= $segments_paths; // Add all segments, dividers, and pegs
$svg .= '<circle cx="' . $cx . '" cy="' . $cy . '" r="' . $inner_radius . '" class="wheel-hub-outer" />';
$svg .= '<circle cx="' . $cx . '" cy="' . $cy . '" r="' . ($inner_radius - 8) . '" class="wheel-hub-inner" />';
$svg .= $text_paths; // Add all text paths on top of segments
$svg .= '<circle cx="' . $cx . '" cy="' . $cy . '" r="' . ($inner_radius - 16) . '" class="wheel-hub-button" />';
$svg .= "<text x='{$cx}' y='" . ($cy + 8) . "' class='wheel-hub-text' text-anchor='middle'>SPIN</text>";
$svg .= '</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,<br><br>This is a test email from the Wheel of Fortune plugin.<br><br>If you received this message, your email settings seem to be working.<br><br><strong>Current Settings Used for This Test:</strong><br><ul><li><strong>Use SMTP:</strong> %2$s</li><li><strong>Host:</strong> %3$s</li><li><strong>Port:</strong> %4$s</li><li><strong>Encryption:</strong> %5$s</li><li><strong>Username:</strong> %6$s</li><li><strong>Sender Name:</strong> %7$s</li><li><strong>Sender Email:</strong> %8$s</li></ul><br>Best regards,<br>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();