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.
This commit is contained in:
2026-05-05 01:03:05 +03:30
parent 5930c1ad6f
commit 32c065e4b6
15 changed files with 1350 additions and 4 deletions

View File

@@ -3,8 +3,10 @@ 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
@@ -12,10 +14,12 @@ use Sodino\Models\Upsell;
class AdminController {
private $ruleRepository;
private $upsellRepository;
private $bannerRepository;
public function __construct(RuleRepository $ruleRepository, UpsellRepository $upsellRepository) {
public function __construct(RuleRepository $ruleRepository, UpsellRepository $upsellRepository, BannerRepository $bannerRepository) {
$this->ruleRepository = $ruleRepository;
$this->upsellRepository = $upsellRepository;
$this->bannerRepository = $bannerRepository;
}
/**
@@ -68,6 +72,24 @@ class AdminController {
[$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'),
@@ -192,6 +214,29 @@ class AdminController {
}
}
/**
* 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
*/
@@ -206,6 +251,28 @@ class AdminController {
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);
@@ -245,6 +312,34 @@ class AdminController {
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;
@@ -272,6 +367,33 @@ class AdminController {
}
}
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([]);