828 lines
31 KiB
PHP
828 lines
31 KiB
PHP
<?php
|
|
namespace Sodino\Controllers;
|
|
|
|
use Sodino\Repositories\RuleRepository;
|
|
use Sodino\Repositories\UpsellRepository;
|
|
use Sodino\Repositories\BannerRepository;
|
|
use Sodino\Models\Rule;
|
|
use Sodino\Models\Upsell;
|
|
use Sodino\Models\Banner;
|
|
|
|
/**
|
|
* Admin Controller
|
|
*/
|
|
class AdminController {
|
|
private $ruleRepository;
|
|
private $upsellRepository;
|
|
private $bannerRepository;
|
|
private $allowedBannerContentTypes = ['image', 'html', 'shortcode'];
|
|
private $allowedBannerPositions = ['top', 'middle', 'bottom', 'product_page', 'cart'];
|
|
private $allowedBannerDisplayTypes = ['inline', 'popup', 'floating_bar'];
|
|
private $allowedBannerUserTargets = ['all', 'new', 'returning'];
|
|
private $allowedBannerDeviceTargets = ['all', 'desktop', 'mobile'];
|
|
private $allowedUpsellTriggerTypes = ['product', 'category', 'cart_total'];
|
|
private $allowedUpsellDiscountTypes = ['percentage', 'fixed', 'none'];
|
|
private $allowedRuleConditionTypes = ['user_type', 'product_category', 'product_ids', 'cart_total_min', 'cart_total_max', 'cart_item_count_min', 'cart_item_count_max'];
|
|
private $allowedRuleActionTypes = ['discount_percent', 'discount_fixed', 'set_price', 'free_shipping'];
|
|
private $allowedStrategies = ['priority', 'highest_discount', 'first_valid'];
|
|
|
|
public function __construct(RuleRepository $ruleRepository, UpsellRepository $upsellRepository, BannerRepository $bannerRepository) {
|
|
$this->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;
|
|
}
|
|
}
|