Files
newwalls.pl/modules/project_pro_news/project_pro_news.php
Roman Pyrih f62521a504 Test module
2026-02-20 12:00:32 +01:00

405 lines
15 KiB
PHP

<?php
if (!defined('_PS_VERSION_')) {
exit;
}
use PrestaShop\PrestaShop\Adapter\Image\ImageRetriever;
use PrestaShop\PrestaShop\Adapter\Product\PriceFormatter;
use PrestaShop\PrestaShop\Adapter\Product\ProductColorsRetriever;
use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductPresenterFactory;
use PrestaShop\PrestaShop\Adapter\Product\ProductAssembler;
use PrestaShop\PrestaShop\Adapter\Presenter\Product\ProductListingPresenter;
class Project_Pro_News extends Module
{
const CFG_CATEGORY_ID = 'PROJECT_PRO_NEWS_CATEGORY_ID';
const CFG_MAX_PRODUCTS = 'PROJECT_PRO_NEWS_MAX_PRODUCTS';
const CFG_TITLE = 'PROJECT_PRO_NEWS_TITLE';
const CFG_SUBTITLE = 'PROJECT_PRO_NEWS_SUBTITLE';
const CFG_BUTTON_LABEL = 'PROJECT_PRO_NEWS_BUTTON_LABEL';
const CFG_BUTTON_URL = 'PROJECT_PRO_NEWS_BUTTON_URL';
const CFG_PRICE_SUFFIX = 'PROJECT_PRO_NEWS_PRICE_SUFFIX';
public function __construct()
{
$this->name = 'project_pro_news';
$this->tab = 'front_office_features';
$this->version = '1.0.1';
$this->author = 'RomekDev';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
$this->displayName = $this->l('Project Pro: News slider (category products)');
$this->description = $this->l('Shows products from selected category as a slider with configurable title, subtitle and button (multilanguage).');
$this->ps_versions_compliancy = ['min' => '1.7.0.0', 'max' => _PS_VERSION_];
}
public function install()
{
return parent::install()
&& $this->registerHook('displayHome')
&& $this->registerHook('displayHeader')
&& $this->setDefaultConfig();
}
public function uninstall()
{
$this->deleteConfig();
return parent::uninstall();
}
private function setDefaultConfig()
{
$langs = Language::getLanguages(false);
$title = [];
$subtitle = [];
$btn = [];
$suffix = [];
foreach ($langs as $lang) {
$id = (int)$lang['id_lang'];
$title[$id] = 'Nowości';
$subtitle[$id] = 'znajdź swoją inspirację';
$btn[$id] = 'Zobacz więcej';
$suffix[$id] = ''; // наприклад: '/m²'
}
Configuration::updateValue(self::CFG_CATEGORY_ID, 0);
Configuration::updateValue(self::CFG_MAX_PRODUCTS, 12);
Configuration::updateValue(self::CFG_BUTTON_URL, '');
Configuration::updateValue(self::CFG_TITLE, $title, true);
Configuration::updateValue(self::CFG_SUBTITLE, $subtitle, true);
Configuration::updateValue(self::CFG_BUTTON_LABEL, $btn, true);
Configuration::updateValue(self::CFG_PRICE_SUFFIX, $suffix, true);
return true;
}
private function deleteConfig()
{
Configuration::deleteByName(self::CFG_CATEGORY_ID);
Configuration::deleteByName(self::CFG_MAX_PRODUCTS);
Configuration::deleteByName(self::CFG_TITLE);
Configuration::deleteByName(self::CFG_SUBTITLE);
Configuration::deleteByName(self::CFG_BUTTON_LABEL);
Configuration::deleteByName(self::CFG_BUTTON_URL);
Configuration::deleteByName(self::CFG_PRICE_SUFFIX);
}
public function getContent()
{
$output = '';
if (Tools::isSubmit('submitProjectProNews')) {
try {
$categoryId = (int)Tools::getValue(self::CFG_CATEGORY_ID);
$max = (int)Tools::getValue(self::CFG_MAX_PRODUCTS);
$buttonUrl = trim((string)Tools::getValue(self::CFG_BUTTON_URL));
if ($max <= 0) {
$max = 12;
}
$langs = Language::getLanguages(false);
$title = [];
$subtitle = [];
$btn = [];
$suffix = [];
foreach ($langs as $lang) {
$id = (int)$lang['id_lang'];
$title[$id] = (string)Tools::getValue(self::CFG_TITLE . '_' . $id);
$subtitle[$id] = (string)Tools::getValue(self::CFG_SUBTITLE . '_' . $id);
$btn[$id] = (string)Tools::getValue(self::CFG_BUTTON_LABEL . '_' . $id);
$suffix[$id] = (string)Tools::getValue(self::CFG_PRICE_SUFFIX . '_' . $id);
// на всяк випадок обрізаємо (щоб не вбити конфіг через дуже довгий текст)
$title[$id] = Tools::substr($title[$id], 0, 255);
$subtitle[$id] = Tools::substr($subtitle[$id], 0, 255);
$btn[$id] = Tools::substr($btn[$id], 0, 255);
$suffix[$id] = Tools::substr($suffix[$id], 0, 64);
}
if (!Configuration::updateValue(self::CFG_CATEGORY_ID, $categoryId)) {
throw new Exception('Cannot save category id');
}
if (!Configuration::updateValue(self::CFG_MAX_PRODUCTS, $max)) {
throw new Exception('Cannot save max products');
}
if (!Configuration::updateValue(self::CFG_BUTTON_URL, $buttonUrl)) {
throw new Exception('Cannot save button url');
}
if (!Configuration::updateValue(self::CFG_TITLE, $title, true)) {
throw new Exception('Cannot save title');
}
if (!Configuration::updateValue(self::CFG_SUBTITLE, $subtitle, true)) {
throw new Exception('Cannot save subtitle');
}
if (!Configuration::updateValue(self::CFG_BUTTON_LABEL, $btn, true)) {
throw new Exception('Cannot save button label');
}
if (!Configuration::updateValue(self::CFG_PRICE_SUFFIX, $suffix, true)) {
throw new Exception('Cannot save price suffix');
}
$output .= $this->displayConfirmation($this->l('Settings saved.'));
} catch (Exception $e) {
$output .= $this->displayError('Save error: ' . $e->getMessage());
}
}
return $output . $this->renderForm();
}
private function renderForm()
{
$defaultLang = (int)Configuration::get('PS_LANG_DEFAULT');
$categories = Category::getCategories($defaultLang, true, false);
$categoryOptions = $this->flattenCategoriesForSelect($categories);
$fieldsForm = [
'form' => [
'legend' => [
'title' => $this->l('Project Pro News: settings'),
'icon' => 'icon-cogs',
],
'input' => [
[
'type' => 'select',
'label' => $this->l('Category (source products)'),
'name' => self::CFG_CATEGORY_ID,
'options' => [
'query' => $categoryOptions,
'id' => 'id',
'name' => 'name',
],
'required' => true,
'desc' => $this->l('Select category that contains the products (e.g. Nowości).'),
],
[
'type' => 'text',
'label' => $this->l('Max products'),
'name' => self::CFG_MAX_PRODUCTS,
'class' => 'fixed-width-sm',
'required' => true,
],
[
'type' => 'text',
'label' => $this->l('Title'),
'name' => self::CFG_TITLE,
'lang' => true,
],
[
'type' => 'text',
'label' => $this->l('Subtitle'),
'name' => self::CFG_SUBTITLE,
'lang' => true,
],
[
'type' => 'text',
'label' => $this->l('Button label'),
'name' => self::CFG_BUTTON_LABEL,
'lang' => true,
],
[
'type' => 'text',
'label' => $this->l('Button URL'),
'name' => self::CFG_BUTTON_URL,
'desc' => $this->l('Leave empty to link to selected category automatically.'),
],
[
'type' => 'text',
'label' => $this->l('Price suffix (optional)'),
'name' => self::CFG_PRICE_SUFFIX,
'lang' => true,
'desc' => $this->l('Example: /m²'),
],
],
'submit' => [
'title' => $this->l('Save'),
'name' => 'submitProjectProNews',
],
],
];
$helper = new HelperForm();
$helper->show_toolbar = false;
$helper->table = $this->table;
$helper->module = $this;
$helper->default_form_language = $defaultLang;
$helper->allow_employee_form_lang = (int)Configuration::get('PS_BO_ALLOW_EMPLOYEE_FORM_LANG');
$helper->identifier = $this->identifier;
$helper->submit_action = 'submitProjectProNews';
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->languages = $this->context->controller->getLanguages();
$helper->id_language = (int)$this->context->language->id;
$helper->fields_value[self::CFG_CATEGORY_ID] = (int)Configuration::get(self::CFG_CATEGORY_ID);
$helper->fields_value[self::CFG_MAX_PRODUCTS] = (int)Configuration::get(self::CFG_MAX_PRODUCTS);
$helper->fields_value[self::CFG_BUTTON_URL] = (string)Configuration::get(self::CFG_BUTTON_URL);
$langs = Language::getLanguages(false);
foreach ($langs as $lang) {
$id = (int)$lang['id_lang'];
$helper->fields_value[self::CFG_TITLE][$id] = (string)Configuration::get(self::CFG_TITLE, $id);
$helper->fields_value[self::CFG_SUBTITLE][$id] = (string)Configuration::get(self::CFG_SUBTITLE, $id);
$helper->fields_value[self::CFG_BUTTON_LABEL][$id] = (string)Configuration::get(self::CFG_BUTTON_LABEL, $id);
$helper->fields_value[self::CFG_PRICE_SUFFIX][$id] = (string)Configuration::get(self::CFG_PRICE_SUFFIX, $id);
}
return $helper->generateForm([$fieldsForm]);
}
private function flattenCategoriesForSelect($categoriesTree, $depth = 0, &$out = [])
{
foreach ($categoriesTree as $node) {
if (!isset($node['id_category'], $node['name'])) {
continue;
}
$prefix = str_repeat('—', max(0, $depth));
$out[] = [
'id' => (int)$node['id_category'],
'name' => trim($prefix . ' ' . $node['name']),
];
if (!empty($node['children'])) {
$this->flattenCategoriesForSelect($node['children'], $depth + 1, $out);
}
}
return $out;
}
public function hookDisplayHeader()
{
$this->context->controller->registerStylesheet(
'project_pro_news_swiper_css',
'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.css',
['media' => 'all', 'priority' => 150]
);
$this->context->controller->registerStylesheet(
'project_pro_news_css',
'modules/' . $this->name . '/views/css/project_pro_news.css',
['media' => 'all', 'priority' => 151]
);
$this->context->controller->registerJavascript(
'project_pro_news_swiper_js',
'modules/' . $this->name . '/views/lib/swiper/swiper-bundle.min.js',
['position' => 'bottom', 'priority' => 150]
);
$this->context->controller->registerJavascript(
'project_pro_news_js',
'modules/' . $this->name . '/views/js/project_pro_news.js',
['position' => 'bottom', 'priority' => 151]
);
}
public function hookDisplayHome($params)
{
return $this->renderWidget('displayHome', []);
}
public function renderWidget($hookName = null, array $configuration = [])
{
$categoryId = (int)Configuration::get(self::CFG_CATEGORY_ID);
$max = (int)Configuration::get(self::CFG_MAX_PRODUCTS);
if ($max <= 0) {
$max = 12;
}
if ($categoryId <= 0) {
return '';
}
$idLang = (int)$this->context->language->id;
$title = (string)Configuration::get(self::CFG_TITLE, $idLang);
$subtitle = (string)Configuration::get(self::CFG_SUBTITLE, $idLang);
$buttonLabel = (string)Configuration::get(self::CFG_BUTTON_LABEL, $idLang);
$buttonUrl = trim((string)Configuration::get(self::CFG_BUTTON_URL));
$priceSuffix = (string)Configuration::get(self::CFG_PRICE_SUFFIX, $idLang);
$category = new Category($categoryId, $idLang);
if (!Validate::isLoadedObject($category)) {
return '';
}
if ($buttonUrl === '') {
$buttonUrl = $this->context->link->getCategoryLink($category);
}
$products = $this->getCategoryProductsPresented($categoryId, $max);
$this->context->smarty->assign([
'ppn_title' => $title,
'ppn_subtitle' => $subtitle,
'ppn_button_label' => $buttonLabel,
'ppn_button_url' => $buttonUrl,
'ppn_price_suffix' => $priceSuffix,
'ppn_products' => $products,
]);
return $this->fetch('module:' . $this->name . '/views/templates/hook/project_pro_news.tpl');
}
public function getWidgetVariables($hookName = null, array $configuration = [])
{
return [];
}
private function getCategoryProductsPresented($categoryId, $limit)
{
$idLang = (int)$this->context->language->id;
$rawProducts = Category::getProducts(
(int)$categoryId,
$idLang,
1,
(int)$limit,
'position',
'asc'
);
if (empty($rawProducts)) {
return [];
}
$assembler = new ProductAssembler($this->context);
$presenterFactory = new ProductPresenterFactory($this->context);
$presentationSettings = $presenterFactory->getPresentationSettings();
$imageRetriever = new ImageRetriever($this->context->link);
$priceFormatter = new PriceFormatter();
$colorsRetriever = new ProductColorsRetriever();
$listingPresenter = new ProductListingPresenter(
$imageRetriever,
$this->context->link,
$priceFormatter,
$colorsRetriever,
$this->getTranslator()
);
$products = [];
foreach ($rawProducts as $raw) {
$assembled = $assembler->assembleProduct($raw);
$products[] = $listingPresenter->present(
$presentationSettings,
$assembled,
$this->context->language
);
}
return $products;
}
}