ruleRepository = $ruleRepository; $this->upsellRepository = $upsellRepository; } /** * Handle admin menu */ public function addMenu() { add_menu_page( __('سودینو', 'sodino'), __('سودینو', 'sodino'), 'manage_options', 'sodino-rules', [$this, 'rulesPage'], 'dashicons-money-alt', 56 ); add_submenu_page( 'sodino-rules', __('قوانین قیمت‌گذاری', 'sodino'), __('قوانین قیمت‌گذاری', 'sودino'), 'manage_options', 'sodino-rules', [$this, 'rulesPage'] ); add_submenu_page( 'sodino-rules', __('افزودن قانون', 'sودino'), __('افزودن قانون', 'sودino'), 'manage_options', 'sodino-add-rule', [$this, 'addRulePage'] ); add_submenu_page( 'sodino-rules', __('آپسل (پیشنهاد فروش)', 'sodino'), __('آپسل (پیشنهاد فروش)', 'sodino'), 'manage_options', 'sodino-upsells', [$this, 'upsellsPage'] ); add_submenu_page( 'sodino-rules', __('افزودن آپسل', 'sodino'), __('افزودن آپسل', 'sodino'), 'manage_options', 'sodino-add-upsell', [$this, 'addUpsellPage'] ); add_submenu_page( 'sodino-rules', __('قیمت رقبا (به‌زودی)', 'sodino'), __('قیمت رقبا (به‌زودی)', 'sodino'), 'manage_options', 'sodino-competitor-price', [$this, 'competitorPricePage'] ); add_submenu_page( 'sodino-rules', __('داشبورد سودینو', 'sودino'), __('داشبورد سودینو', 'sodino'), 'manage_options', 'sodino-dashboard', [$this, 'dashboardPage'] ); add_submenu_page( 'sodino-rules', __('تنظیمات', 'sودino'), __('تنظیمات', 'sودینو'), 'manage_options', 'sodino-settings', [$this, 'settingsPage'] ); } /** * Rules admin page */ public function rulesPage() { $this->listRulesPage(); } /** * Dashboard page */ public function dashboardPage() { $settings = $this->getSettings(); $analyticsService = new \Sodino\Services\AnalyticsService(new \Sodino\Repositories\EventRepository(), $this->ruleRepository); $filters = [ 'range' => isset($_GET['range']) ? sanitize_text_field($_GET['range']) : '7d', 'start_date' => isset($_GET['start_date']) ? sanitize_text_field($_GET['start_date']) : '', 'end_date' => isset($_GET['end_date']) ? sanitize_text_field($_GET['end_date']) : '', 'product_id' => isset($_GET['product_id']) ? intval($_GET['product_id']) : 0, 'category_id' => isset($_GET['category_id']) ? intval($_GET['category_id']) : 0, ]; if (!empty($filters['product_id'])) { $filters['product_ids'] = [$filters['product_id']]; } $dashboardData = $analyticsService->getDashboardData($filters); $productOptions = $analyticsService->getProductOptions(); $categoryOptions = $analyticsService->getCategoryOptions(); include SODINO_PLUGIN_DIR . 'admin/views/dashboard.php'; } /** * List rules page */ private function listRulesPage() { require_once SODINO_PLUGIN_DIR . 'admin/class-rules-list-table.php'; $rulesTable = new \Sodino_Rules_List_Table($this->ruleRepository); $rulesTable->prepare_items(); include SODINO_PLUGIN_DIR . 'admin/views/rules-list.php'; } /** * Add or edit rule page */ public function addRulePage() { if (isset($_GET['action']) && $_GET['action'] === 'edit') { return $this->editRulePage(); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->saveRule(); } else { $rule = new Rule(); include SODINO_PLUGIN_DIR . 'admin/views/rule-form.php'; } } /** * Settings page */ public function settingsPage() { if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->saveSettings(); } $settings = $this->getSettings(); include SODINO_PLUGIN_DIR . 'admin/views/settings.php'; } /** * Upsell list page */ public function upsellsPage() { $this->listUpsellsPage(); } /** * Add or edit upsell page */ public function addUpsellPage() { if (isset($_GET['action']) && $_GET['action'] === 'edit') { return $this->editUpsellPage(); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->saveUpsell(); } else { $upsell = new Upsell(); include SODINO_PLUGIN_DIR . 'admin/views/upsell-form.php'; } } /** * Competitor price page */ public function competitorPricePage() { include SODINO_PLUGIN_DIR . 'admin/views/competitor-price.php'; } private function listUpsellsPage() { require_once SODINO_PLUGIN_DIR . 'admin/class-upsell-list-table.php'; $upsellTable = new \Sodino_Upsell_List_Table($this->upsellRepository); $upsellTable->prepare_items(); include SODINO_PLUGIN_DIR . 'admin/views/upsell-list.php'; } private function editUpsellPage() { $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; $upsell = $this->upsellRepository->getById($id); if (!$upsell) { wp_die(__('Upsell not found', 'sodino')); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->saveUpsell($upsell); } else { include SODINO_PLUGIN_DIR . 'admin/views/upsell-form.php'; } } private function saveUpsell($upsell = null) { if (!isset($_POST['sodino_upsell_nonce']) || !wp_verify_nonce($_POST['sodino_upsell_nonce'], 'sodino_save_upsell')) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } if (!$upsell) { $upsell = new Upsell(); } $upsell->title = sanitize_text_field($_POST['title'] ?? ''); $upsell->trigger_type = sanitize_text_field($_POST['trigger_type'] ?? 'product'); $upsell->trigger_value = sanitize_text_field($_POST['trigger_value'] ?? ''); $upsell->target_product_id = max(0, intval($_POST['target_product_id'] ?? 0)); $upsell->discount_type = sanitize_text_field($_POST['discount_type'] ?? 'percentage'); $upsell->discount_value = max(0, floatval($_POST['discount_value'] ?? 0)); $upsell->priority = max(1, intval($_POST['priority'] ?? 10)); $upsell->status = isset($_POST['status']) ? 1 : 0; $this->upsellRepository->save($upsell); wp_safe_redirect(admin_url('admin.php?page=sodino-upsells')); exit; } public function handleUpsellActions() { if (!isset($_GET['_wpnonce']) || !in_array($_GET['action'], ['delete_upsell', 'toggle_upsell_status'], true) || !wp_verify_nonce($_GET['_wpnonce'], $_GET['action'])) { return; } $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; if (!$id) { return; } if ($_GET['action'] === 'delete_upsell') { $this->upsellRepository->delete($id); wp_safe_redirect(admin_url('admin.php?page=sodino-upsells')); exit; } if ($_GET['action'] === 'toggle_upsell_status') { $upsell = $this->upsellRepository->getById($id); if ($upsell) { $upsell->status = $upsell->status ? 0 : 1; $this->upsellRepository->save($upsell); } wp_safe_redirect(admin_url('admin.php?page=sodino-upsells')); exit; } } public function searchProductsAjax() { if (!check_ajax_referer('sodino_search_products', 'security', false)) { wp_send_json([]); } $term = sanitize_text_field($_POST['term'] ?? ''); if (empty($term) || !function_exists('wc_get_products')) { wp_send_json([]); } $products = wc_get_products([ 'limit' => 10, 'status' => 'publish', 'search' => $term, ]); $results = []; foreach ($products as $product) { $results[] = [ 'id' => $product->get_id(), 'label' => $product->get_name(), ]; } wp_send_json($results); } private function getSettingsDefaults() { return [ 'plugin_enabled' => 1, 'pricing_enabled' => 1, 'upsell_enabled' => 1, 'allow_multiple_rules' => 0, 'strategy' => 'priority', 'max_discount_percent' => 100, 'min_product_price' => 0, 'ab_testing_enabled' => 0, 'cart_pricing_enabled' => 1, 'scheduled_campaigns_enabled' => 1, ]; } private function getSettings() { return wp_parse_args(get_option('sodino_settings', []), $this->getSettingsDefaults()); } private function saveSettings() { if (!current_user_can('manage_options')) { wp_die(__('دسترسی کافی ندارید.', 'sodino')); } if (!isset($_POST['sodino_settings_nonce']) || !wp_verify_nonce($_POST['sodino_settings_nonce'], 'sodino_save_settings')) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } $settings = [ 'plugin_enabled' => isset($_POST['plugin_enabled']) ? 1 : 0, 'pricing_enabled' => isset($_POST['pricing_enabled']) ? 1 : 0, 'upsell_enabled' => isset($_POST['upsell_enabled']) ? 1 : 0, 'allow_multiple_rules' => isset($_POST['allow_multiple_rules']) ? 1 : 0, 'strategy' => sanitize_text_field($_POST['strategy'] ?? 'priority'), 'max_discount_percent' => max(0, min(100, floatval($_POST['max_discount_percent'] ?? 100))), 'min_product_price' => max(0, floatval($_POST['min_product_price'] ?? 0)), 'ab_testing_enabled' => isset($_POST['ab_testing_enabled']) ? 1 : 0, 'cart_pricing_enabled' => isset($_POST['cart_pricing_enabled']) ? 1 : 0, 'scheduled_campaigns_enabled' => isset($_POST['scheduled_campaigns_enabled']) ? 1 : 0, ]; update_option('sodino_settings', $settings); wp_safe_redirect(add_query_arg('updated', 'true', admin_url('admin.php?page=sodino-settings'))); exit; } /** * Edit rule page */ private function editRulePage() { $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; $rule = $this->ruleRepository->getById($id); if (!$rule) { wp_die(__('Rule not found', 'sodino')); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->saveRule($rule); } else { include SODINO_PLUGIN_DIR . 'admin/views/rule-form.php'; } } /** * Save rule */ private function saveRule($rule = null) { if (!isset($_POST['gheymatyar_rule_nonce']) || !wp_verify_nonce($_POST['gheymatyar_rule_nonce'], 'gheymatyar_save_rule')) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } if (!$rule) { $rule = new Rule(); } $rule->name = sanitize_text_field($_POST['name'] ?? ''); $rule->priority = max(1, intval($_POST['priority'] ?? 10)); $rule->usage_limit = max(0, intval($_POST['usage_limit'] ?? 0)); $rule->user_roles = array_map('sanitize_text_field', (array) ($_POST['user_roles'] ?? [])); $rule->condition_type = sanitize_text_field($_POST['condition_type'] ?? 'user_type'); $rule->condition_value = sanitize_text_field($_POST['condition_value'] ?? 'new'); $rule->action_type = sanitize_text_field($_POST['action_type'] ?? 'discount_percent'); $rule->action_value = sanitize_text_field($_POST['action_value'] ?? '0'); $rule->enabled = isset($_POST['enabled']) ? 1 : 0; $this->ruleRepository->save($rule); wp_safe_redirect(admin_url('admin.php?page=sodino-rules')); exit; } /** * Handle delete action */ public function handleDelete() { if (!isset($_GET['_wpnonce']) || !wp_verify_nonce($_GET['_wpnonce'], 'delete_rule')) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; $this->ruleRepository->delete($id); wp_redirect(admin_url('admin.php?page=sodino-rules')); exit; } }