refactor(Core): optimize admin panel and refactor
This commit is contained in:
@@ -15,6 +15,16 @@ 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;
|
||||
@@ -39,7 +49,7 @@ class AdminController {
|
||||
add_submenu_page(
|
||||
'sodino-rules',
|
||||
__('قوانین قیمتگذاری', 'sodino'),
|
||||
__('قوانین قیمتگذاری', 'sودino'),
|
||||
__('قوانین قیمتگذاری', 'sodino'),
|
||||
'manage_options',
|
||||
'sodino-rules',
|
||||
[$this, 'rulesPage']
|
||||
@@ -47,8 +57,8 @@ class AdminController {
|
||||
|
||||
add_submenu_page(
|
||||
'sodino-rules',
|
||||
__('افزودن قانون', 'sودino'),
|
||||
__('افزودن قانون', 'sودino'),
|
||||
__('افزودن قانون', 'sodino'),
|
||||
__('افزودن قانون', 'sodino'),
|
||||
'manage_options',
|
||||
'sodino-add-rule',
|
||||
[$this, 'addRulePage']
|
||||
@@ -101,7 +111,7 @@ class AdminController {
|
||||
|
||||
add_submenu_page(
|
||||
'sodino-rules',
|
||||
__('داشبورد سودینو', 'sودino'),
|
||||
__('داشبورد سودینو', 'sodino'),
|
||||
__('داشبورد سودینو', 'sodino'),
|
||||
'manage_options',
|
||||
'sodino-dashboard',
|
||||
@@ -110,14 +120,61 @@ class AdminController {
|
||||
|
||||
add_submenu_page(
|
||||
'sodino-rules',
|
||||
__('تنظیمات', 'sودino'),
|
||||
__('تنظیمات', 'sودینو'),
|
||||
__('تنظیمات', '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
|
||||
*/
|
||||
@@ -289,6 +346,10 @@ class AdminController {
|
||||
}
|
||||
|
||||
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'));
|
||||
}
|
||||
@@ -297,22 +358,49 @@ class AdminController {
|
||||
$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'] ?? '');
|
||||
$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 = sanitize_text_field($_POST['discount_type'] ?? 'percentage');
|
||||
$upsell->discount_type = $discountType;
|
||||
$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);
|
||||
$id = $this->upsellRepository->save($upsell);
|
||||
if (!$id) {
|
||||
$this->redirectWithNotice($this->getBackUrl('sodino-add-upsell'), __('ذخیره آپسل انجام نشد. لطفا مقادیر فرم را بررسی کنید.', 'sodino'), 'error');
|
||||
}
|
||||
|
||||
wp_safe_redirect(admin_url('admin.php?page=sodino-upsells'));
|
||||
exit;
|
||||
$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'));
|
||||
}
|
||||
@@ -321,26 +409,60 @@ class AdminController {
|
||||
$banner = new Banner();
|
||||
}
|
||||
|
||||
$banner->title = sanitize_text_field($_POST['title'] ?? '');
|
||||
$banner->content_type = sanitize_text_field($_POST['content_type'] ?? 'image');
|
||||
$banner->content_value = isset($_POST['content_value']) ? wp_kses_post($_POST['content_value']) : '';
|
||||
$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 = sanitize_text_field($_POST['position'] ?? 'top');
|
||||
$banner->display_type = sanitize_text_field($_POST['display_type'] ?? 'inline');
|
||||
$banner->start_time = sanitize_text_field($_POST['start_time'] ?? '');
|
||||
$banner->end_time = sanitize_text_field($_POST['end_time'] ?? '');
|
||||
$banner->user_target = sanitize_text_field($_POST['user_target'] ?? 'all');
|
||||
$banner->device_target = sanitize_text_field($_POST['device_target'] ?? 'all');
|
||||
$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;
|
||||
|
||||
$this->bannerRepository->save($banner);
|
||||
$id = $this->bannerRepository->save($banner);
|
||||
if (!$id) {
|
||||
$this->redirectWithNotice($this->getBackUrl('sodino-add-banner'), __('ذخیره بنر انجام نشد. لطفا مقادیر فرم را بررسی کنید.', 'sodino'), 'error');
|
||||
}
|
||||
|
||||
wp_safe_redirect(admin_url('admin.php?page=sodino-banners'));
|
||||
exit;
|
||||
$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;
|
||||
}
|
||||
@@ -368,6 +490,10 @@ class AdminController {
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -395,6 +521,10 @@ class AdminController {
|
||||
}
|
||||
|
||||
public function searchProductsAjax() {
|
||||
if (!current_user_can('manage_options')) {
|
||||
wp_send_json([]);
|
||||
}
|
||||
|
||||
if (!check_ajax_referer('sodino_search_products', 'security', false)) {
|
||||
wp_send_json([]);
|
||||
}
|
||||
@@ -426,13 +556,17 @@ class AdminController {
|
||||
'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,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -449,23 +583,31 @@ class AdminController {
|
||||
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' => sanitize_text_field($_POST['strategy'] ?? 'priority'),
|
||||
'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);
|
||||
|
||||
wp_safe_redirect(add_query_arg('updated', 'true', admin_url('admin.php?page=sodino-settings')));
|
||||
exit;
|
||||
$this->redirectWithNotice(add_query_arg('updated', 'true', admin_url('admin.php?page=sodino-settings')), __('تنظیمات با موفقیت ذخیره شد.', 'sodino'), 'success');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -490,7 +632,11 @@ class AdminController {
|
||||
* Save rule
|
||||
*/
|
||||
private function saveRule($rule = null) {
|
||||
if (!isset($_POST['gheymatyar_rule_nonce']) || !wp_verify_nonce($_POST['gheymatyar_rule_nonce'], 'gheymatyar_save_rule')) {
|
||||
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'));
|
||||
}
|
||||
|
||||
@@ -498,20 +644,53 @@ class AdminController {
|
||||
$rule = new Rule();
|
||||
}
|
||||
|
||||
$rule->name = sanitize_text_field($_POST['name'] ?? '');
|
||||
$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->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->conditions = [
|
||||
[
|
||||
'type' => $conditionType,
|
||||
'value' => $conditionValue,
|
||||
],
|
||||
];
|
||||
$rule->actions = [
|
||||
[
|
||||
'type' => $actionType,
|
||||
'value' => $actionValue,
|
||||
],
|
||||
];
|
||||
$rule->syncLegacyFields();
|
||||
$rule->enabled = isset($_POST['enabled']) ? 1 : 0;
|
||||
|
||||
$this->ruleRepository->save($rule);
|
||||
$id = $this->ruleRepository->save($rule);
|
||||
if (!$id) {
|
||||
$this->redirectWithNotice($this->getBackUrl('sodino-add-rule'), __('ذخیره قانون انجام نشد. لطفا مقادیر فرم را بررسی کنید.', 'sodino'), 'error');
|
||||
}
|
||||
|
||||
wp_safe_redirect(admin_url('admin.php?page=sodino-rules'));
|
||||
exit;
|
||||
$this->redirectWithNotice(admin_url('admin.php?page=sodino-rules'), __('قانون با موفقیت ذخیره شد.', 'sodino'), 'success');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -525,7 +704,7 @@ class AdminController {
|
||||
$id = isset($_GET['id']) ? (int) $_GET['id'] : 0;
|
||||
$this->ruleRepository->delete($id);
|
||||
|
||||
wp_redirect(admin_url('admin.php?page=sodino-rules'));
|
||||
wp_safe_redirect(admin_url('admin.php?page=sodino-rules'));
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +166,6 @@ class RuleController extends BaseController {
|
||||
$rule->end_date = !empty($_POST['end_date']) ? sanitize_text_field($_POST['end_date']) : null;
|
||||
$rule->enabled = isset($_POST['enabled']) ? 1 : 0;
|
||||
|
||||
// Parse conditions
|
||||
if (isset($_POST['conditions']) && is_array($_POST['conditions'])) {
|
||||
$rule->conditions = array_map(function($condition) {
|
||||
return [
|
||||
@@ -174,9 +173,15 @@ class RuleController extends BaseController {
|
||||
'value' => sanitize_text_field($condition['value'] ?? '')
|
||||
];
|
||||
}, $_POST['conditions']);
|
||||
} else {
|
||||
$rule->conditions = [
|
||||
[
|
||||
'type' => sanitize_text_field($_POST['condition_type'] ?? 'user_type'),
|
||||
'value' => sanitize_text_field($_POST['condition_value'] ?? 'new'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
// Parse actions
|
||||
if (isset($_POST['actions']) && is_array($_POST['actions'])) {
|
||||
$rule->actions = array_map(function($action) {
|
||||
return [
|
||||
@@ -184,6 +189,15 @@ class RuleController extends BaseController {
|
||||
'value' => sanitize_text_field($action['value'] ?? '')
|
||||
];
|
||||
}, $_POST['actions']);
|
||||
} else {
|
||||
$rule->actions = [
|
||||
[
|
||||
'type' => sanitize_text_field($_POST['action_type'] ?? 'discount_percent'),
|
||||
'value' => sanitize_text_field($_POST['action_value'] ?? '0'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
$rule->syncLegacyFields();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ class Rule {
|
||||
public $enabled;
|
||||
public $created_at;
|
||||
public $updated_at;
|
||||
public $condition_type;
|
||||
public $condition_value;
|
||||
public $action_type;
|
||||
public $action_value;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -36,6 +40,7 @@ class Rule {
|
||||
$this->enabled = isset($data['enabled']) ? (int) $data['enabled'] : 1;
|
||||
$this->created_at = $data['created_at'] ?? null;
|
||||
$this->updated_at = $data['updated_at'] ?? null;
|
||||
$this->syncLegacyFields();
|
||||
}
|
||||
|
||||
private function parseJsonField($value) {
|
||||
@@ -59,6 +64,16 @@ class Rule {
|
||||
return array_filter(array_map('trim', explode(',', $value)));
|
||||
}
|
||||
|
||||
public function syncLegacyFields() {
|
||||
$condition = $this->conditions[0] ?? [];
|
||||
$action = $this->actions[0] ?? [];
|
||||
|
||||
$this->condition_type = $condition['type'] ?? 'user_type';
|
||||
$this->condition_value = $condition['value'] ?? 'new';
|
||||
$this->action_type = $action['type'] ?? 'discount_percent';
|
||||
$this->action_value = $action['value'] ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to array
|
||||
*/
|
||||
|
||||
@@ -46,12 +46,20 @@ class BannerRepository {
|
||||
unset($data['id'], $data['created_at']);
|
||||
|
||||
if ($banner->id) {
|
||||
$wpdb->update($this->table_name, $data, ['id' => $banner->id]);
|
||||
$result = $wpdb->update($this->table_name, $data, ['id' => $banner->id]);
|
||||
if ($result === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->clearCache();
|
||||
return $banner->id;
|
||||
}
|
||||
|
||||
$wpdb->insert($this->table_name, $data);
|
||||
$result = $wpdb->insert($this->table_name, $data);
|
||||
if ($result === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->clearCache();
|
||||
return $wpdb->insert_id;
|
||||
}
|
||||
@@ -76,6 +84,12 @@ class BannerRepository {
|
||||
}
|
||||
|
||||
public function clearCache() {
|
||||
wp_cache_flush();
|
||||
$version = microtime(true);
|
||||
update_option('sodino_banners_cache_version', $version, false);
|
||||
wp_cache_set('version', $version, 'sodino_banners');
|
||||
|
||||
if (function_exists('wp_cache_flush_group')) {
|
||||
wp_cache_flush_group('sodino_banners');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,10 +87,18 @@ class RuleRepository {
|
||||
unset($data['id'], $data['created_at'], $data['updated_at']);
|
||||
|
||||
if ($rule->id) {
|
||||
$wpdb->update($this->table_name, $data, ['id' => $rule->id]);
|
||||
$result = $wpdb->update($this->table_name, $data, ['id' => $rule->id]);
|
||||
if ($result === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $rule->id;
|
||||
} else {
|
||||
$wpdb->insert($this->table_name, $data);
|
||||
$result = $wpdb->insert($this->table_name, $data);
|
||||
if ($result === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $wpdb->insert_id;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,11 +46,19 @@ class UpsellRepository {
|
||||
unset($data['id'], $data['created_at'], $data['updated_at']);
|
||||
|
||||
if ($upsell->id) {
|
||||
$wpdb->update($this->table_name, $data, ['id' => $upsell->id]);
|
||||
$result = $wpdb->update($this->table_name, $data, ['id' => $upsell->id]);
|
||||
if ($result === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $upsell->id;
|
||||
}
|
||||
|
||||
$wpdb->insert($this->table_name, $data);
|
||||
$result = $wpdb->insert($this->table_name, $data);
|
||||
if ($result === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $wpdb->insert_id;
|
||||
}
|
||||
|
||||
|
||||
@@ -106,6 +106,12 @@ class BannerService {
|
||||
}
|
||||
|
||||
private function getCacheKey($position, array $context) {
|
||||
return 'sodino_active_banners_' . md5($position . '|' . serialize($context));
|
||||
$version = wp_cache_get('version', 'sodino_banners');
|
||||
if ($version === false) {
|
||||
$version = get_option('sodino_banners_cache_version', 1);
|
||||
wp_cache_set('version', $version, 'sodino_banners');
|
||||
}
|
||||
|
||||
return 'sodino_active_banners_' . md5($version . '|' . $position . '|' . serialize($context));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ class PricingService {
|
||||
private $trackingService;
|
||||
private $settings;
|
||||
private $cache;
|
||||
private $trackedApplications = [];
|
||||
|
||||
public function __construct(RuleRepository $ruleRepository, TrackingService $trackingService) {
|
||||
$this->ruleRepository = $ruleRepository;
|
||||
@@ -51,8 +52,7 @@ class PricingService {
|
||||
$price = $this->applyRuleActions($rule, $price);
|
||||
|
||||
if ($price < $oldPrice) {
|
||||
$this->trackingService->recordDiscountApplied($product, $oldPrice, $price, $rule->id);
|
||||
$this->ruleRepository->incrementUsage($rule->id);
|
||||
$this->trackDiscountOnce($product, $oldPrice, $price, $rule->id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ class PricingService {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) array_intersect($product_cats, array_map('intval', $categories));
|
||||
return (bool) array_intersect($product_cats, $this->normalizeIdList($categories));
|
||||
}
|
||||
|
||||
private function productIsInIds($product, $ids) {
|
||||
@@ -214,7 +214,23 @@ class PricingService {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array($product->get_id(), array_map('intval', $ids), true);
|
||||
return in_array($product->get_id(), $this->normalizeIdList($ids), true);
|
||||
}
|
||||
|
||||
private function normalizeIdList($value) {
|
||||
$values = is_array($value) ? $value : [$value];
|
||||
$ids = [];
|
||||
|
||||
foreach ($values as $item) {
|
||||
foreach (explode(',', (string) $item) as $id) {
|
||||
$id = absint(trim($id));
|
||||
if ($id > 0) {
|
||||
$ids[] = $id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values(array_unique($ids));
|
||||
}
|
||||
|
||||
private function applyRuleActions($rule, $price) {
|
||||
@@ -273,4 +289,17 @@ class PricingService {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function trackDiscountOnce($product, $oldPrice, $price, $ruleId) {
|
||||
$productId = $product ? $product->get_id() : 0;
|
||||
$key = implode(':', [$productId, (int) $ruleId, round($oldPrice, 4), round($price, 4)]);
|
||||
|
||||
if (isset($this->trackedApplications[$key])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->trackedApplications[$key] = true;
|
||||
$this->trackingService->recordDiscountApplied($product, $oldPrice, $price, $ruleId);
|
||||
$this->ruleRepository->incrementUsage($ruleId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user