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; } }