feat: Implement upsell functionality with repository and service layers
This commit is contained in:
@@ -2,16 +2,20 @@
|
||||
namespace Sodino\Controllers;
|
||||
|
||||
use Sodino\Repositories\RuleRepository;
|
||||
use Sodino\Repositories\UpsellRepository;
|
||||
use Sodino\Models\Rule;
|
||||
use Sodino\Models\Upsell;
|
||||
|
||||
/**
|
||||
* Admin Controller
|
||||
*/
|
||||
class AdminController {
|
||||
private $ruleRepository;
|
||||
private $upsellRepository;
|
||||
|
||||
public function __construct(RuleRepository $ruleRepository) {
|
||||
public function __construct(RuleRepository $ruleRepository, UpsellRepository $upsellRepository) {
|
||||
$this->ruleRepository = $ruleRepository;
|
||||
$this->upsellRepository = $upsellRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -19,8 +23,8 @@ class AdminController {
|
||||
*/
|
||||
public function addMenu() {
|
||||
add_menu_page(
|
||||
__('قیمتیار', 'sodino'),
|
||||
__('قیمتیار', 'sodino'),
|
||||
__('سودینو', 'sodino'),
|
||||
__('سودینو', 'sodino'),
|
||||
'manage_options',
|
||||
'sodino-rules',
|
||||
[$this, 'rulesPage'],
|
||||
@@ -48,7 +52,43 @@ class AdminController {
|
||||
|
||||
add_submenu_page(
|
||||
'sodino-rules',
|
||||
__('تنظیمات', 'sodino'),
|
||||
__('آپسل (پیشنهاد فروش)', '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',
|
||||
@@ -63,6 +103,32 @@ class AdminController {
|
||||
$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
|
||||
*/
|
||||
@@ -95,9 +161,191 @@ class AdminController {
|
||||
* 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
|
||||
*/
|
||||
@@ -129,6 +377,9 @@ class AdminController {
|
||||
}
|
||||
|
||||
$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');
|
||||
|
||||
Reference in New Issue
Block a user