ruleRepository = $ruleRepository; $this->upsellRepository = $upsellRepository; $this->bannerRepository = $bannerRepository; } /** * 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'), __('قوانین قیمت‌گذاری', 'sodino'), 'manage_options', 'sodino-rules', [$this, 'rulesPage'] ); add_submenu_page( 'sodino-rules', __('افزودن قانون', 'sodino'), __('افزودن قانون', 'sodino'), '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-banners', [$this, 'bannersPage'] ); add_submenu_page( 'sodino-rules', __('افزودن بنر', 'sodino'), __('افزودن بنر', 'sodino'), 'manage_options', 'sodino-add-banner', [$this, 'addBannerPage'] ); add_submenu_page( 'sodino-rules', __('ابزارها و سلامت', 'sodino'), __('ابزارها و سلامت', 'sodino'), 'manage_options', 'sodino-tools', [$this, 'toolsPage'] ); add_submenu_page( 'sodino-rules', __('داشبورد سودینو', 'sodino'), __('داشبورد سودینو', 'sodino'), 'manage_options', 'sodino-dashboard', [$this, 'dashboardPage'] ); add_submenu_page( 'sodino-rules', __('تنظیمات', 'sodino'), __('تنظیمات', 'sodino'), 'manage_options', 'sodino-settings', [$this, 'settingsPage'] ); } private function redirectWithNotice($url, $message, $type = 'error') { $notice = [ 'type' => $type, 'message' => $message, ]; set_transient('sodino_admin_notice_' . get_current_user_id(), $notice, 60); set_transient('sodino_admin_notice', $notice, 60); if ($type === 'error' && $_SERVER['REQUEST_METHOD'] === 'POST') { $oldInput = wp_unslash($_POST); $oldInput['_sodino_page'] = isset($_GET['page']) ? sanitize_key($_GET['page']) : ''; set_transient('sodino_old_input_' . get_current_user_id(), $oldInput, 120); } else { delete_transient('sodino_old_input_' . get_current_user_id()); } wp_safe_redirect($url); exit; } private function getBackUrl($fallbackPage) { return wp_get_referer() ?: admin_url('admin.php?page=' . $fallbackPage); } private function requireValue($value, $message, $fallbackPage) { if (is_string($value)) { $value = trim($value); } if ($value === '' || $value === null) { $this->redirectWithNotice($this->getBackUrl($fallbackPage), $message, 'error'); } return $value; } private function normalizeDatetime($value) { $value = trim((string) $value); if ($value === '') { return null; } $timestamp = strtotime($value); return $timestamp ? date('Y-m-d H:i:s', $timestamp) : null; } /** * 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'; } } /** * Banners list page */ public function bannersPage() { $this->listBannersPage(); } /** * Add or edit banner page */ public function addBannerPage() { if (isset($_GET['action']) && $_GET['action'] === 'edit') { return $this->editBannerPage(); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->saveBanner(); } else { $banner = new Banner(); include SODINO_PLUGIN_DIR . 'admin/views/banner-form.php'; } } /** * Tools and health page */ public function toolsPage() { $toolsData = $this->getToolsData(); include SODINO_PLUGIN_DIR . 'admin/views/tools.php'; } public function handleToolsActions() { if (!current_user_can('manage_options')) { return; } if (($_GET['page'] ?? '') !== 'sodino-tools' || empty($_GET['tool_action'])) { return; } $action = sanitize_key($_GET['tool_action']); if (!isset($_GET['_wpnonce']) || !wp_verify_nonce($_GET['_wpnonce'], 'sodino_tools_' . $action)) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } if ($action === 'clear_cache') { \Sodino\Core\Cache::getInstance()->clearAll(); $this->redirectWithNotice(admin_url('admin.php?page=sodino-tools'), __('کش سودینو با موفقیت پاک شد.', 'sodino'), 'success'); } if ($action === 'run_migrations') { require_once SODINO_PLUGIN_DIR . 'database/migrations.php'; sodino_create_tables(); $this->redirectWithNotice(admin_url('admin.php?page=sodino-tools'), __('ساختار دیتابیس سودینو بررسی و به‌روزرسانی شد.', 'sodino'), 'success'); } if ($action === 'prune_events') { $deleted = $this->deleteOldEvents(90); $this->redirectWithNotice( admin_url('admin.php?page=sodino-tools'), sprintf(__('پاک‌سازی انجام شد. %d رویداد قدیمی حذف شد.', 'sodino'), $deleted), 'success' ); } wp_safe_redirect(admin_url('admin.php?page=sodino-tools')); exit; } 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 listBannersPage() { require_once SODINO_PLUGIN_DIR . 'admin/class-banner-list-table.php'; $bannerTable = new \Sodino_Banner_List_Table($this->bannerRepository); $bannerTable->prepare_items(); include SODINO_PLUGIN_DIR . 'admin/views/banner-list.php'; } private function editBannerPage() { $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; $banner = $this->bannerRepository->getById($id); if (!$banner) { wp_die(__('بنر پیدا نشد', 'sodino')); } if ($_SERVER['REQUEST_METHOD'] === 'POST') { $this->saveBanner($banner); } else { include SODINO_PLUGIN_DIR . 'admin/views/banner-form.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 (!current_user_can('manage_options')) { wp_die(__('دسترسی کافی ندارید.', 'sodino')); } if (!isset($_POST['sodino_upsell_nonce']) || !wp_verify_nonce($_POST['sodino_upsell_nonce'], 'sodino_save_upsell')) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } if (!$upsell) { $upsell = new Upsell(); } $triggerType = sanitize_key($_POST['trigger_type'] ?? 'product'); if (!in_array($triggerType, $this->allowedUpsellTriggerTypes, true)) { $triggerType = 'product'; } $triggerValues = isset($_POST['trigger_values']) && is_array($_POST['trigger_values']) ? wp_unslash($_POST['trigger_values']) : []; $triggerValue = sanitize_text_field($triggerValues[$triggerType] ?? ''); $targetProductId = max(0, intval($_POST['target_product_id'] ?? 0)); $discountType = sanitize_key($_POST['discount_type'] ?? 'percentage'); if (!in_array($discountType, $this->allowedUpsellDiscountTypes, true)) { $discountType = 'percentage'; } $title = sanitize_text_field($_POST['title'] ?? ''); $this->requireValue($title, __('عنوان آپسل الزامی است.', 'sodino'), 'sodino-add-upsell'); $this->requireValue($triggerValue, __('مقدار شرط آپسل را انتخاب یا وارد کنید.', 'sodino'), 'sodino-add-upsell'); if ($targetProductId <= 0) { $this->redirectWithNotice($this->getBackUrl('sodino-add-upsell'), __('محصول پیشنهادی آپسل الزامی است.', 'sodino'), 'error'); } $upsell->title = $title; $upsell->trigger_type = $triggerType; $upsell->trigger_value = $triggerValue; $upsell->target_product_id = max(0, intval($_POST['target_product_id'] ?? 0)); $upsell->discount_type = $discountType; $upsell->discount_value = max(0, floatval($_POST['discount_value'] ?? 0)); if ($discountType === 'percentage') { $upsell->discount_value = min(100, $upsell->discount_value); } $upsell->priority = max(1, intval($_POST['priority'] ?? 10)); $upsell->status = isset($_POST['status']) ? 1 : 0; $id = $this->upsellRepository->save($upsell); if (!$id) { $this->redirectWithNotice($this->getBackUrl('sodino-add-upsell'), __('ذخیره آپسل انجام نشد. لطفا مقادیر فرم را بررسی کنید.', 'sodino'), 'error'); } $this->redirectWithNotice(admin_url('admin.php?page=sodino-upsells'), __('آپسل با موفقیت ذخیره شد.', 'sodino'), 'success'); } private function saveBanner($banner = null) { if (!current_user_can('manage_options')) { wp_die(__('دسترسی کافی ندارید.', 'sodino')); } if (!isset($_POST['sodino_banner_nonce']) || !wp_verify_nonce($_POST['sodino_banner_nonce'], 'sodino_save_banner')) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } if (!$banner) { $banner = new Banner(); } $contentType = sanitize_key($_POST['content_type'] ?? 'image'); if (!in_array($contentType, $this->allowedBannerContentTypes, true)) { $contentType = 'image'; } $contentValues = isset($_POST['content_values']) && is_array($_POST['content_values']) ? wp_unslash($_POST['content_values']) : []; $contentValue = $contentValues[$contentType] ?? ''; $contentValue = $contentType === 'image' ? esc_url_raw($contentValue) : wp_kses_post($contentValue); $title = sanitize_text_field($_POST['title'] ?? ''); $this->requireValue($title, __('عنوان بنر الزامی است.', 'sodino'), 'sodino-add-banner'); $this->requireValue($contentValue, __('محتوای بنر الزامی است.', 'sodino'), 'sodino-add-banner'); if ($contentType === 'image' && !filter_var($contentValue, FILTER_VALIDATE_URL)) { $this->redirectWithNotice($this->getBackUrl('sodino-add-banner'), __('آدرس تصویر بنر معتبر نیست.', 'sodino'), 'error'); } $startTime = $this->normalizeDatetime($_POST['start_time'] ?? ''); $endTime = $this->normalizeDatetime($_POST['end_time'] ?? ''); if ($startTime && $endTime && strtotime($endTime) < strtotime($startTime)) { $this->redirectWithNotice($this->getBackUrl('sodino-add-banner'), __('تاریخ پایان بنر نباید قبل از تاریخ شروع باشد.', 'sodino'), 'error'); } $position = sanitize_key($_POST['position'] ?? 'top'); $displayType = sanitize_key($_POST['display_type'] ?? 'inline'); $userTarget = sanitize_key($_POST['user_target'] ?? 'all'); $deviceTarget = sanitize_key($_POST['device_target'] ?? 'all'); $banner->title = $title; $banner->content_type = $contentType; $banner->content_value = $contentValue; $banner->link_url = esc_url_raw($_POST['link_url'] ?? ''); $banner->position = in_array($position, $this->allowedBannerPositions, true) ? $position : 'top'; $banner->display_type = in_array($displayType, $this->allowedBannerDisplayTypes, true) ? $displayType : 'inline'; $banner->start_time = $startTime; $banner->end_time = $endTime; $banner->user_target = in_array($userTarget, $this->allowedBannerUserTargets, true) ? $userTarget : 'all'; $banner->device_target = in_array($deviceTarget, $this->allowedBannerDeviceTargets, true) ? $deviceTarget : 'all'; $banner->priority = max(1, intval($_POST['priority'] ?? 10)); $banner->status = isset($_POST['status']) ? 1 : 0; $id = $this->bannerRepository->save($banner); if (!$id) { $this->redirectWithNotice($this->getBackUrl('sodino-add-banner'), __('ذخیره بنر انجام نشد. لطفا مقادیر فرم را بررسی کنید.', 'sodino'), 'error'); } $this->redirectWithNotice(admin_url('admin.php?page=sodino-banners'), __('بنر با موفقیت ذخیره شد.', 'sodino'), 'success'); } public function handleUpsellActions() { if (!current_user_can('manage_options')) { return; } 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 handleBannerActions() { if (!current_user_can('manage_options')) { return; } if (!isset($_GET['_wpnonce']) || !in_array($_GET['action'], ['delete_banner', 'toggle_banner_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_banner') { $this->bannerRepository->delete($id); wp_safe_redirect(admin_url('admin.php?page=sodino-banners')); exit; } if ($_GET['action'] === 'toggle_banner_status') { $banner = $this->bannerRepository->getById($id); if ($banner) { $banner->status = $banner->status ? 0 : 1; $this->bannerRepository->save($banner); } wp_safe_redirect(admin_url('admin.php?page=sodino-banners')); exit; } } public function searchProductsAjax() { if (!current_user_can('manage_options')) { wp_send_json([]); } 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 getToolsData() { global $wpdb; $tables = [ 'rules' => [ 'label' => __('قوانین قیمت‌گذاری', 'sodino'), 'name' => $wpdb->prefix . 'sodino_rules', ], 'upsells' => [ 'label' => __('آپسل‌ها', 'sodino'), 'name' => $wpdb->prefix . 'sodino_upsells', ], 'banners' => [ 'label' => __('بنرها', 'sodino'), 'name' => $wpdb->prefix . 'sodino_banners', ], 'events' => [ 'label' => __('رویدادهای تحلیلی', 'sodino'), 'name' => $wpdb->prefix . 'sodino_events', ], 'analytics_cache' => [ 'label' => __('کش تحلیلی', 'sodino'), 'name' => $wpdb->prefix . 'sodino_analytics_cache', ], ]; foreach ($tables as $key => $table) { $exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $table['name'])); $tables[$key]['exists'] = (bool) $exists; $tables[$key]['count'] = $exists ? (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table['name']}") : 0; } $eventsTable = $tables['events']['name']; $oldEventCount = 0; $oldestEvent = ''; if ($tables['events']['exists']) { $cutoff = date('Y-m-d H:i:s', current_time('timestamp') - (90 * DAY_IN_SECONDS)); $oldEventCount = (int) $wpdb->get_var( $wpdb->prepare("SELECT COUNT(*) FROM {$eventsTable} WHERE created_at < %s", $cutoff) ); $oldestEvent = (string) $wpdb->get_var("SELECT MIN(created_at) FROM {$eventsTable}"); } return [ 'db_version' => get_option('sodino_db_version', '0'), 'expected_db_version' => defined('SODINO_DB_VERSION') ? SODINO_DB_VERSION : SODINO_VERSION, 'settings' => $this->getSettings(), 'tables' => $tables, 'old_event_count' => $oldEventCount, 'oldest_event' => $oldestEvent, 'actions' => [ 'clear_cache' => wp_nonce_url(admin_url('admin.php?page=sodino-tools&tool_action=clear_cache'), 'sodino_tools_clear_cache'), 'run_migrations' => wp_nonce_url(admin_url('admin.php?page=sodino-tools&tool_action=run_migrations'), 'sodino_tools_run_migrations'), 'prune_events' => wp_nonce_url(admin_url('admin.php?page=sodino-tools&tool_action=prune_events'), 'sodino_tools_prune_events'), ], ]; } private function deleteOldEvents($days) { global $wpdb; $days = max(1, (int) $days); $eventsTable = $wpdb->prefix . 'sodino_events'; $exists = $wpdb->get_var($wpdb->prepare('SHOW TABLES LIKE %s', $eventsTable)); if (!$exists) { return 0; } $cutoff = date('Y-m-d H:i:s', current_time('timestamp') - ($days * DAY_IN_SECONDS)); $deleted = $wpdb->query($wpdb->prepare("DELETE FROM {$eventsTable} WHERE created_at < %s", $cutoff)); return $deleted === false ? 0 : (int) $deleted; } private function getSettingsDefaults() { return [ 'plugin_enabled' => 1, 'pricing_enabled' => 1, 'upsell_enabled' => 1, 'banner_enabled' => 1, 'allow_multiple_rules' => 0, 'strategy' => 'priority', 'max_discount_percent' => 100, 'min_product_price' => 0, 'cache_enabled' => 1, 'cache_duration' => 3600, 'ab_testing_enabled' => 0, 'cart_pricing_enabled' => 1, 'scheduled_campaigns_enabled' => 1, 'debug_mode' => 0, ]; } 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')); } $strategy = sanitize_key($_POST['strategy'] ?? 'priority'); if (!in_array($strategy, $this->allowedStrategies, true)) { $strategy = 'priority'; } $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, 'banner_enabled' => isset($_POST['banner_enabled']) ? 1 : 0, 'allow_multiple_rules' => isset($_POST['allow_multiple_rules']) ? 1 : 0, 'strategy' => $strategy, 'max_discount_percent' => max(0, min(100, floatval($_POST['max_discount_percent'] ?? 100))), 'min_product_price' => max(0, floatval($_POST['min_product_price'] ?? 0)), 'cache_enabled' => isset($_POST['cache_enabled']) ? 1 : 0, 'cache_duration' => max(60, intval($_POST['cache_duration'] ?? 3600)), '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, 'debug_mode' => isset($_POST['debug_mode']) ? 1 : 0, ]; update_option('sodino_settings', $settings); \Sodino\Core\Cache::getInstance()->clearAll(); $this->redirectWithNotice(add_query_arg('updated', 'true', admin_url('admin.php?page=sodino-settings')), __('تنظیمات با موفقیت ذخیره شد.', 'sodino'), 'success'); } /** * 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 (!current_user_can('manage_options')) { wp_die(__('دسترسی کافی ندارید.', 'sodino')); } if (!isset($_POST['sodino_rule_nonce']) || !wp_verify_nonce($_POST['sodino_rule_nonce'], 'sodino_save_rule')) { wp_die(__('خطای امنیتی رخ داد.', 'sodino')); } if (!$rule) { $rule = new Rule(); } $name = sanitize_text_field($_POST['name'] ?? ''); $this->requireValue($name, __('عنوان قانون الزامی است.', 'sodino'), 'sodino-add-rule'); $conditionType = sanitize_key($_POST['condition_type'] ?? 'user_type'); if (!in_array($conditionType, $this->allowedRuleConditionTypes, true)) { $conditionType = 'user_type'; } $conditionValue = sanitize_text_field($_POST['condition_value'] ?? ''); $this->requireValue($conditionValue, __('مقدار شرط قانون الزامی است.', 'sodino'), 'sodino-add-rule'); $actionType = sanitize_key($_POST['action_type'] ?? 'discount_percent'); if (!in_array($actionType, $this->allowedRuleActionTypes, true)) { $actionType = 'discount_percent'; } $actionValue = sanitize_text_field($_POST['action_value'] ?? '0'); if ($actionType !== 'free_shipping' && floatval($actionValue) <= 0) { $this->redirectWithNotice($this->getBackUrl('sodino-add-rule'), __('مقدار عملیات باید بزرگ‌تر از صفر باشد.', 'sodino'), 'error'); } $rule->name = $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->conditions = [ [ 'type' => $conditionType, 'value' => $conditionValue, ], ]; $rule->actions = [ [ 'type' => $actionType, 'value' => $actionValue, ], ]; $rule->syncLegacyFields(); $rule->enabled = isset($_POST['enabled']) ? 1 : 0; $id = $this->ruleRepository->save($rule); if (!$id) { $this->redirectWithNotice($this->getBackUrl('sodino-add-rule'), __('ذخیره قانون انجام نشد. لطفا مقادیر فرم را بررسی کنید.', 'sodino'), 'error'); } $this->redirectWithNotice(admin_url('admin.php?page=sodino-rules'), __('قانون با موفقیت ذخیره شد.', 'sodino'), 'success'); } /** * 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_safe_redirect(admin_url('admin.php?page=sodino-rules')); exit; } }