From 9e4022f64856082fffa7a0264949373319cdf9ff Mon Sep 17 00:00:00 2001 From: Nikita Kiselev Date: Wed, 24 Sep 2025 14:02:13 +0300 Subject: [PATCH] feat(categories): add options to select what categories to show on front page --- .../controller/extension/module/tgshop.php | 28 ++++++++++++++ .../ru-ru/extension/module/tgshop.php | 2 + .../template/extension/module/tgshop.twig | 37 +++++++++++++++++++ .../controller/extension/tgshop/handle.php | 2 + .../src/Handlers/CategoriesHandler.php | 25 ++++++++++++- spa/src/stores/CategoriesStore.js | 2 +- 6 files changed, 93 insertions(+), 3 deletions(-) diff --git a/module/oc_telegram_shop/upload/admin/controller/extension/module/tgshop.php b/module/oc_telegram_shop/upload/admin/controller/extension/module/tgshop.php index f06f393..f420165 100755 --- a/module/oc_telegram_shop/upload/admin/controller/extension/module/tgshop.php +++ b/module/oc_telegram_shop/upload/admin/controller/extension/module/tgshop.php @@ -82,6 +82,7 @@ class ControllerExtensionModuleTgshop extends Controller $this->load->model('setting/setting'); $this->load->model('tool/image'); $this->load->model('catalog/product'); + $this->load->model('catalog/category'); $this->load->model('localisation/order_status'); $this->load->model('customer/customer_group'); } @@ -149,6 +150,17 @@ class ControllerExtensionModuleTgshop extends Controller 'name' => $productItem['name'], ]; } + } elseif ($config['type'] === 'categories') { + $categories = $this->request->post[$key] ?? $this->config->get($key) ?? []; + + $data[$key] = []; + foreach ($categories as $categoryId) { + $categoryItem = $this->model_catalog_category->getCategory($categoryId); + $data[$key][] = [ + 'category_id' => $categoryId, + 'name' => $categoryItem['name'], + ]; + } } elseif (isset($this->request->post[$key])) { $data[$key] = $this->request->post[$key]; } else { @@ -326,6 +338,7 @@ TEXT, 'module_tgshop_order_customer_group_id' => 1, 'module_tgshop_order_default_status_id' => 1, 'module_tgshop_mini_app_url' => rtrim(HTTPS_CATALOG, '/') . '/image/catalog/tgshopspa/#/', + 'module_tgshop_mainpage_categories' => 'latest10' ]; } @@ -438,6 +451,21 @@ HTML, 'type' => 'products', 'help' => 'На главной странице будут отображаться избранные товары, если вы выберете этот вариант в настройке “Товары на главной”.', ], + + 'module_tgshop_mainpage_categories' => [ + 'type' => 'select', + 'options' => [ + 'no_categories' => 'Отображать только кнопку "Каталог"', + 'latest10' => 'Последние 10 категорий', + 'featured' => 'Избранные категории (задать в поле ниже)', + ], + 'help' => 'Выберите, какие категории показывать на главной странице магазина в Telegram. Это влияет на первую видимую секцию каталога для пользователя.', + ], + + 'module_tgshop_featured_categories' => [ + 'type' => 'categories', + 'help' => 'На главной странице будут отображаться эти категории, если вы выберете этот вариант в настройке “Категории на главной”.', + ], ], 'orders' => [ diff --git a/module/oc_telegram_shop/upload/admin/language/ru-ru/extension/module/tgshop.php b/module/oc_telegram_shop/upload/admin/language/ru-ru/extension/module/tgshop.php index f417181..ef78821 100755 --- a/module/oc_telegram_shop/upload/admin/language/ru-ru/extension/module/tgshop.php +++ b/module/oc_telegram_shop/upload/admin/language/ru-ru/extension/module/tgshop.php @@ -27,6 +27,8 @@ $_['lbl_module_tgshop_featured_products'] = 'Избранные товары'; $_['lbl_module_tgshop_order_customer_group_id'] = 'Группа покупателей'; $_['lbl_module_tgshop_order_default_status_id'] = 'Статус заказов'; $_['lbl_module_tgshop_mini_app_url'] = 'Ссылка на Telegram Mini App'; +$_['lbl_module_tgshop_mainpage_categories'] = 'Категории на главной'; +$_['lbl_module_tgshop_featured_categories'] = 'Избранные категории'; // Entry $_['entry_status'] = 'Статус'; diff --git a/module/oc_telegram_shop/upload/admin/view/template/extension/module/tgshop.twig b/module/oc_telegram_shop/upload/admin/view/template/extension/module/tgshop.twig index 5e2cca0..04f181c 100755 --- a/module/oc_telegram_shop/upload/admin/view/template/extension/module/tgshop.twig +++ b/module/oc_telegram_shop/upload/admin/view/template/extension/module/tgshop.twig @@ -144,6 +144,43 @@ }); + {% elseif item['type'] == 'categories' %} + +
+ {% for category in attribute(_context, settingKey) %} +
+ {{ category.name }} + +
+ {% endfor %} +
+ {# ChatID #} {% elseif item['type'] == 'chatid' %} {% if module_tgshop_bot_token %} diff --git a/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php b/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php index 7b18d22..3c70c43 100755 --- a/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php +++ b/module/oc_telegram_shop/upload/catalog/controller/extension/tgshop/handle.php @@ -59,6 +59,8 @@ class ControllerExtensionTgshopHandle extends Controller 'theme_dark' => $this->config->get('module_tgshop_theme_dark'), 'mainpage_products' => $this->config->get('module_tgshop_mainpage_products'), 'featured_products' => $this->config->get('module_tgshop_featured_products'), + 'mainpage_categories' => $this->config->get('module_tgshop_mainpage_categories'), + 'featured_categories' => $this->config->get('module_tgshop_featured_categories'), 'base_url' => HTTPS_SERVER, 'ya_metrika_enabled' => ! empty(trim($this->config->get('module_tgshop_yandex_metrika'))), 'telegram' => [ diff --git a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php index ea344b4..05b43c1 100755 --- a/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php +++ b/module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers/CategoriesHandler.php @@ -4,7 +4,9 @@ declare(strict_types=1); namespace App\Handlers; +use Openguru\OpenCartFramework\Config\Settings; use Openguru\OpenCartFramework\Http\JsonResponse; +use Openguru\OpenCartFramework\Http\Request; use Openguru\OpenCartFramework\ImageTool\ImageToolInterface; use Openguru\OpenCartFramework\QueryBuilder\Builder; use Openguru\OpenCartFramework\QueryBuilder\JoinClause; @@ -15,17 +17,28 @@ class CategoriesHandler private Builder $queryBuilder; private ImageToolInterface $ocImageTool; + private Settings $settings; - public function __construct(Builder $queryBuilder, ImageToolInterface $ocImageTool) + public function __construct(Builder $queryBuilder, ImageToolInterface $ocImageTool, Settings $settings) { $this->queryBuilder = $queryBuilder; $this->ocImageTool = $ocImageTool; + $this->settings = $settings; } - public function index(): JsonResponse + public function index(Request $request): JsonResponse { $languageId = 1; + $perPage = $request->get('perPage', 10); + $forMainPage = filter_var($request->get('forMainPage', false), FILTER_VALIDATE_BOOLEAN); + $featuredCategories = $this->settings->get('featured_categories'); + $mainpageCategories = $this->settings->get('mainpage_categories'); + + if ($forMainPage && $mainpageCategories === 'no_categories') { + return new JsonResponse(['data' => []]); + } + $categoriesFlat = $this->queryBuilder->newQuery() ->select([ 'categories.category_id' => 'id', @@ -43,12 +56,20 @@ class CategoriesHandler } ) ->where('categories.status', '=', 1) + ->when( + $forMainPage && $mainpageCategories === 'featured' && $featuredCategories, + function (Builder $query) use ($featuredCategories) { + $query->whereIn('categories.category_id', $featuredCategories); + } + ) ->orderBy('parent_id') ->orderBy('sort_order') ->get(); $categories = $this->buildCategoryTree($categoriesFlat); + $categories = array_slice($categories, 0, $perPage); + return new JsonResponse([ 'data' => array_map(static function ($category) { return [ diff --git a/spa/src/stores/CategoriesStore.js b/spa/src/stores/CategoriesStore.js index 93e9a57..caa6f45 100644 --- a/spa/src/stores/CategoriesStore.js +++ b/spa/src/stores/CategoriesStore.js @@ -27,7 +27,7 @@ export const useCategoriesStore = defineStore('categories', { try { this.isLoading = true; const response = await ftch('categoriesList', { - perPage: 7, + forMainPage: true, }); this.topCategories = response.data; } catch (error) {