Files
sodino/app/Controllers/AdminController.php
soheil khaledabadi 32c065e4b6 feat: Add banner management functionality
- Implemented a new Banner model to represent banner data.
- Created a BannerRepository for database interactions related to banners.
- Developed a BannerService to handle business logic for banners.
- Added admin views for listing and adding banners.
- Integrated banner hooks for frontend rendering and click tracking.
- Created frontend styles and scripts for banner display and interaction.
- Updated database migrations to include a new banners table.
- Enhanced AdminController to manage banner actions and pages.
2026-05-05 01:03:05 +03:30

531 lines
18 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;
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'),
__('قوانین قیمت‌گذاری', '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-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-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';
}
}
/**
* 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';
}
}
/**
* 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 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 (!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;
}
private function saveBanner($banner = null) {
if (!isset($_POST['sodino_banner_nonce']) || !wp_verify_nonce($_POST['sodino_banner_nonce'], 'sodino_save_banner')) {
wp_die(__('خطای امنیتی رخ داد.', 'sodino'));
}
if (!$banner) {
$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']) : '';
$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->priority = max(1, intval($_POST['priority'] ?? 10));
$banner->status = isset($_POST['status']) ? 1 : 0;
$this->bannerRepository->save($banner);
wp_safe_redirect(admin_url('admin.php?page=sodino-banners'));
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 handleBannerActions() {
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 (!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;
}
}