diff --git a/config/allowed_files.php b/config/allowed_files.php index 553def5..fa1363b 100644 --- a/config/allowed_files.php +++ b/config/allowed_files.php @@ -334,6 +334,10 @@ 'views/templates/hook/prettyblocks/prettyblock_login.tpl', 'views/templates/hook/prettyblocks/prettyblock_lookbook.tpl', 'views/templates/hook/prettyblocks/prettyblock_masonry_gallery.tpl', + 'views/templates/hook/prettyblocks/prettyblock_megamenu_column.tpl', + 'views/templates/hook/prettyblocks/prettyblock_megamenu_item.tpl', + 'views/templates/hook/prettyblocks/prettyblock_megamenu_item_image.tpl', + 'views/templates/hook/prettyblocks/prettyblock_megamenu_item_link.tpl', 'views/templates/hook/prettyblocks/prettyblock_modal.tpl', 'views/templates/hook/prettyblocks/prettyblock_mystery_boxes.tpl', 'views/templates/hook/prettyblocks/prettyblock_latest_guides.tpl', diff --git a/everblock.php b/everblock.php index 636a774..1ce0bde 100644 --- a/everblock.php +++ b/everblock.php @@ -645,6 +645,13 @@ public function checkHooks() $hook->description = 'This hook triggers before special event block is rendered'; $hook->save(); } + if (!Hook::getIdByName('beforeRenderingEverblockMegamenuItem')) { + $hook = new Hook(); + $hook->name = 'beforeRenderingEverblockMegamenuItem'; + $hook->title = 'Before rendering mega menu item block'; + $hook->description = 'This hook triggers before mega menu item block is rendered'; + $hook->save(); + } $this->registerHook('beforeRenderingEverblockProductHighlight'); $this->registerHook('beforeRenderingEverblockCategoryTabs'); $this->registerHook('beforeRenderingEverblockCategoryPrice'); @@ -653,6 +660,7 @@ public function checkHooks() $this->registerHook('beforeRenderingEverblockCategoryProducts'); $this->registerHook('beforeRenderingEverblockSpecialEvent'); $this->registerHook('beforeRenderingEverblockEverblock'); + $this->registerHook('beforeRenderingEverblockMegamenuItem'); } else { $this->unregisterHook('beforeRenderingEverblockProductHighlight'); $this->unregisterHook('beforeRenderingEverblockCategoryTabs'); @@ -662,6 +670,7 @@ public function checkHooks() $this->unregisterHook('beforeRenderingEverblockCategoryProducts'); $this->unregisterHook('beforeRenderingEverblockSpecialEvent'); $this->unregisterHook('beforeRenderingEverblockEverblock'); + $this->unregisterHook('beforeRenderingEverblockMegamenuItem'); } // Vérifier si l'onglet "AdminEverBlockParent" existe déjà $id_tab = Tab::getIdFromClassName('AdminEverBlockParent'); @@ -5865,6 +5874,136 @@ public function hookBeforeRenderingEverblockCategoryProducts($params) return ['products' => $products]; } + public function hookBeforeRenderingEverblockMegamenuItem($params) + { + $menuId = (int) ($params['block']['id_prettyblocks'] ?? 0); + if ($menuId <= 0) { + return ['columns' => []]; + } + + $idLang = (int) $this->context->language->id; + $idShop = (int) $this->context->shop->id; + + $columns = $this->getPrettyblocksByCode('megamenu_column', $idLang, $idShop); + $links = $this->getPrettyblocksByCode('megamenu_item_link', $idLang, $idShop); + $images = $this->getPrettyblocksByCode('megamenu_item_image', $idLang, $idShop); + + $columns = array_filter($columns, function (array $column) use ($menuId): bool { + $parentId = $this->normalizePrettyblocksRelationId($column['settings']['parent_menu'] ?? null); + return $parentId === $menuId; + }); + + $linksByColumn = []; + foreach ($links as $link) { + $parentId = $this->normalizePrettyblocksRelationId($link['settings']['parent_column'] ?? null); + if ($parentId <= 0) { + continue; + } + $link['settings']['url'] = $this->normalizePrettyblocksLink($link['settings']['url'] ?? ''); + $linksByColumn[$parentId][] = $link; + } + + $imagesByColumn = []; + foreach ($images as $image) { + $parentId = $this->normalizePrettyblocksRelationId($image['settings']['parent_column'] ?? null); + if ($parentId <= 0) { + continue; + } + $image['settings']['url'] = $this->normalizePrettyblocksLink($image['settings']['url'] ?? ''); + $imagesByColumn[$parentId][] = $image; + } + + foreach ($columns as &$column) { + $columnId = (int) $column['id_prettyblocks']; + $column['settings']['title_url'] = $this->normalizePrettyblocksLink( + $column['settings']['title_url'] ?? '' + ); + $column['links'] = $this->sortPrettyblocksByOrder($linksByColumn[$columnId] ?? []); + $column['images'] = $this->sortPrettyblocksByOrder($imagesByColumn[$columnId] ?? []); + } + unset($column); + + $columns = $this->sortPrettyblocksByOrder(array_values($columns)); + + return ['columns' => $columns]; + } + + private function getPrettyblocksByCode(string $code, int $idLang, int $idShop): array + { + $query = 'SELECT id_prettyblocks, config, position' + . ' FROM ' . _DB_PREFIX_ . 'prettyblocks' + . ' WHERE code = "' . pSQL($code) . '"' + . ' AND id_lang = ' . $idLang + . ' AND id_shop = ' . $idShop; + + $rows = Db::getInstance()->executeS($query); + if (!is_array($rows)) { + return []; + } + + $blocks = []; + foreach ($rows as $row) { + $settings = json_decode((string) ($row['config'] ?? ''), true); + if (!is_array($settings)) { + $settings = []; + } + $blocks[] = [ + 'id_prettyblocks' => (int) ($row['id_prettyblocks'] ?? 0), + 'settings' => $settings, + 'position' => (int) ($row['position'] ?? 0), + ]; + } + + return $blocks; + } + + private function normalizePrettyblocksRelationId($value): int + { + if (is_array($value)) { + if (isset($value['id'])) { + return (int) $value['id']; + } + if (isset($value['value'])) { + return (int) $value['value']; + } + } + + return (int) $value; + } + + private function normalizePrettyblocksLink($value): string + { + if (is_array($value)) { + if (isset($value['url'])) { + return (string) $value['url']; + } + if (isset($value['link'])) { + return (string) $value['link']; + } + if (isset($value['href'])) { + return (string) $value['href']; + } + } + + return (string) $value; + } + + private function sortPrettyblocksByOrder(array $items): array + { + usort($items, function (array $left, array $right): int { + $leftOrder = isset($left['settings']['order']) ? (int) $left['settings']['order'] : 0; + $rightOrder = isset($right['settings']['order']) ? (int) $right['settings']['order'] : 0; + + if ($leftOrder === $rightOrder) { + return ($left['position'] ?? 0) <=> ($right['position'] ?? 0); + } + + return $leftOrder <=> $rightOrder; + }); + + return $items; + } + public function hookDisplayReassurance($params) { if (!isset($this->context->controller) || !is_object($this->context->controller)) { diff --git a/src/Service/EverblockPrettyBlocks.php b/src/Service/EverblockPrettyBlocks.php index 6c89b50..167e0b9 100644 --- a/src/Service/EverblockPrettyBlocks.php +++ b/src/Service/EverblockPrettyBlocks.php @@ -22,6 +22,7 @@ use Configuration; use Context; +use Db; use EverBlockClass; use Everblock\Tools\Service\EverblockCache; use EverblockShortcode; @@ -52,6 +53,7 @@ class EverblockPrettyBlocks 'beforeRenderingEverblockGuidedSelector', 'beforeRenderingEverblockLookbook', 'beforeRenderingEverblockCategoryProducts', + 'beforeRenderingEverblockMegamenuItem', ]; public function registerBlockToZone($zone_name, $code, $id_lang, $id_shop) @@ -137,6 +139,43 @@ private static function getEverblockPageChoices(Context $context, Module $module return $choices; } + private static function getPrettyblocksChoicesByCode( + Context $context, + Module $module, + string $code, + string $labelField + ): array { + $choices = [ + '' => $module->l('Select an item'), + ]; + + $query = 'SELECT id_prettyblocks, config' + . ' FROM ' . _DB_PREFIX_ . 'prettyblocks' + . ' WHERE code = "' . pSQL($code) . '"' + . ' AND id_lang = ' . (int) $context->language->id + . ' AND id_shop = ' . (int) $context->shop->id; + + $rows = Db::getInstance()->executeS($query); + if (!is_array($rows)) { + return $choices; + } + + foreach ($rows as $row) { + $id = (int) ($row['id_prettyblocks'] ?? 0); + $config = json_decode((string) ($row['config'] ?? ''), true); + $label = ''; + if (is_array($config)) { + $label = (string) ($config[$labelField] ?? ''); + } + if ($label === '') { + $label = $module->l('Item') . ' #' . $id; + } + $choices[$id] = $id . ' - ' . $label; + } + + return $choices; + } + public static function getEverPrettyBlocks($context) { $cacheId = 'EverblockPrettyBlocks_getEverPrettyBlocks_' @@ -209,6 +248,10 @@ public static function getEverPrettyBlocks($context) $pagesGuideTemplate = 'module:' . $module->name . '/views/templates/hook/prettyblocks/prettyblock_pages_guide.tpl'; $guidesSelectionTemplate = 'module:' . $module->name . '/views/templates/hook/prettyblocks/prettyblock_guides_selection.tpl'; $latestGuidesTemplate = 'module:' . $module->name . '/views/templates/hook/prettyblocks/prettyblock_latest_guides.tpl'; + $megamenuItemTemplate = 'module:' . $module->name . '/views/templates/hook/prettyblocks/prettyblock_megamenu_item.tpl'; + $megamenuColumnTemplate = 'module:' . $module->name . '/views/templates/hook/prettyblocks/prettyblock_megamenu_column.tpl'; + $megamenuItemLinkTemplate = 'module:' . $module->name . '/views/templates/hook/prettyblocks/prettyblock_megamenu_item_link.tpl'; + $megamenuItemImageTemplate = 'module:' . $module->name . '/views/templates/hook/prettyblocks/prettyblock_megamenu_item_image.tpl'; $slotMachineDefaultStartDate = date('Y-m-d 00:00:00'); $slotMachineDefaultEndDate = date('Y-m-d 23:59:59', strtotime('+30 days')); $slotMachineDefaultWinningCombinations = json_encode( @@ -261,6 +304,18 @@ public static function getEverPrettyBlocks($context) $everblockChoices[$eblock['id_everblock']] = $eblock['id_everblock'] . ' - ' . $eblock['name']; } $everblockPageChoices = self::getEverblockPageChoices($context, $module); + $megamenuParentChoices = self::getPrettyblocksChoicesByCode( + $context, + $module, + 'megamenu_item', + 'label' + ); + $megamenuColumnChoices = self::getPrettyblocksChoicesByCode( + $context, + $module, + 'megamenu_column', + 'title' + ); $allHooks = Hook::getHooks(false, true); $prettyBlocksHooks = []; foreach ($allHooks as $hook) { @@ -368,6 +423,192 @@ public static function getEverPrettyBlocks($context) ], $module), ], ]; + $blocks[] = [ + 'name' => $module->l('Mega menu item'), + 'description' => $module->l('Top-level mega menu entry'), + 'code' => 'megamenu_item', + 'tab' => 'general', + 'icon_path' => $defaultLogo, + 'need_reload' => true, + 'templates' => [ + 'default' => $megamenuItemTemplate, + ], + 'config' => [ + 'fields' => [ + 'label' => [ + 'type' => 'text', + 'label' => $module->l('Label'), + 'default' => '', + ], + 'url' => [ + 'type' => 'text', + 'label' => $module->l('Link (optional)'), + 'default' => '', + ], + 'is_mega' => [ + 'type' => 'switch', + 'label' => $module->l('Enable mega menu'), + 'default' => true, + ], + 'full_width' => [ + 'type' => 'switch', + 'label' => $module->l('Full width dropdown'), + 'default' => false, + ], + 'position' => [ + 'type' => 'text', + 'label' => $module->l('Position'), + 'default' => '0', + ], + 'active' => [ + 'type' => 'switch', + 'label' => $module->l('Active'), + 'default' => true, + ], + ], + ], + ]; + $blocks[] = [ + 'name' => $module->l('Mega menu column'), + 'description' => $module->l('Column for a mega menu'), + 'code' => 'megamenu_column', + 'tab' => 'general', + 'icon_path' => $defaultLogo, + 'need_reload' => true, + 'templates' => [ + 'default' => $megamenuColumnTemplate, + ], + 'config' => [ + 'fields' => [ + 'parent_menu' => [ + 'type' => 'select', + 'label' => $module->l('Parent menu'), + 'choices' => $megamenuParentChoices, + 'default' => '', + ], + 'title' => [ + 'type' => 'text', + 'label' => $module->l('Column title'), + 'default' => '', + ], + 'title_url' => [ + 'type' => 'text', + 'label' => $module->l('Title link (optional)'), + 'default' => '', + ], + 'width' => [ + 'type' => 'select', + 'label' => $module->l('Column width'), + 'choices' => [ + '3' => $module->l('3 columns'), + '4' => $module->l('4 columns'), + '6' => $module->l('6 columns'), + '12' => $module->l('12 columns'), + ], + 'default' => '3', + ], + 'order' => [ + 'type' => 'text', + 'label' => $module->l('Order'), + 'default' => '0', + ], + ], + ], + ]; + $blocks[] = [ + 'name' => $module->l('Mega menu link'), + 'description' => $module->l('Link item inside a mega menu column'), + 'code' => 'megamenu_item_link', + 'tab' => 'general', + 'icon_path' => $defaultLogo, + 'need_reload' => true, + 'templates' => [ + 'default' => $megamenuItemLinkTemplate, + ], + 'config' => [ + 'fields' => [ + 'parent_column' => [ + 'type' => 'select', + 'label' => $module->l('Parent column'), + 'choices' => $megamenuColumnChoices, + 'default' => '', + ], + 'label' => [ + 'type' => 'text', + 'label' => $module->l('Label'), + 'default' => '', + ], + 'url' => [ + 'type' => 'text', + 'label' => $module->l('Link'), + 'default' => '', + ], + 'icon' => [ + 'type' => 'text', + 'label' => $module->l('Icon (optional)'), + 'default' => '', + ], + 'highlight' => [ + 'type' => 'switch', + 'label' => $module->l('Highlight'), + 'default' => false, + ], + 'order' => [ + 'type' => 'text', + 'label' => $module->l('Order'), + 'default' => '0', + ], + ], + ], + ]; + $blocks[] = [ + 'name' => $module->l('Mega menu image'), + 'description' => $module->l('Image item inside a mega menu column'), + 'code' => 'megamenu_item_image', + 'tab' => 'general', + 'icon_path' => $defaultLogo, + 'need_reload' => true, + 'templates' => [ + 'default' => $megamenuItemImageTemplate, + ], + 'config' => [ + 'fields' => [ + 'parent_column' => [ + 'type' => 'select', + 'label' => $module->l('Parent column'), + 'choices' => $megamenuColumnChoices, + 'default' => '', + ], + 'image' => [ + 'type' => 'fileupload', + 'label' => $module->l('Image'), + 'default' => [ + 'url' => '', + ], + ], + 'title' => [ + 'type' => 'text', + 'label' => $module->l('Title'), + 'default' => '', + ], + 'url' => [ + 'type' => 'text', + 'label' => $module->l('Link'), + 'default' => '', + ], + 'cta_label' => [ + 'type' => 'text', + 'label' => $module->l('CTA label'), + 'default' => '', + ], + 'order' => [ + 'type' => 'text', + 'label' => $module->l('Order'), + 'default' => '0', + ], + ], + ], + ]; $blocks[] = [ 'name' => $module->l('Title'), 'description' => $module->l('Display a customizable heading'), diff --git a/views/templates/hook/prettyblocks/prettyblock_megamenu_column.tpl b/views/templates/hook/prettyblocks/prettyblock_megamenu_column.tpl new file mode 100644 index 0000000..fe0c0aa --- /dev/null +++ b/views/templates/hook/prettyblocks/prettyblock_megamenu_column.tpl @@ -0,0 +1,21 @@ +{* + * 2019-2025 Team Ever + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author Team Ever + * @copyright 2019-2025 Team Ever + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +*} +{* + This block is a data-only child for megamenu_item. + It is rendered inside the parent block template. +*} diff --git a/views/templates/hook/prettyblocks/prettyblock_megamenu_item.tpl b/views/templates/hook/prettyblocks/prettyblock_megamenu_item.tpl new file mode 100644 index 0000000..b11e5ca --- /dev/null +++ b/views/templates/hook/prettyblocks/prettyblock_megamenu_item.tpl @@ -0,0 +1,148 @@ +{* + * 2019-2025 Team Ever + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author Team Ever + * @copyright 2019-2025 Team Ever + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +*} +{include file='module:everblock/views/templates/hook/prettyblocks/_partials/visibility_class.tpl'} + +{if !isset($block.settings.active) || $block.settings.active} + {assign var='menu_label' value=$block.settings.label|default:''} + {assign var='menu_url' value=$block.settings.url|default:''} + {assign var='menu_toggle_id' value="everblock-megamenu-toggle-`$block.id_prettyblocks`"} + + + +{/if} diff --git a/views/templates/hook/prettyblocks/prettyblock_megamenu_item_image.tpl b/views/templates/hook/prettyblocks/prettyblock_megamenu_item_image.tpl new file mode 100644 index 0000000..fe0c0aa --- /dev/null +++ b/views/templates/hook/prettyblocks/prettyblock_megamenu_item_image.tpl @@ -0,0 +1,21 @@ +{* + * 2019-2025 Team Ever + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author Team Ever + * @copyright 2019-2025 Team Ever + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +*} +{* + This block is a data-only child for megamenu_item. + It is rendered inside the parent block template. +*} diff --git a/views/templates/hook/prettyblocks/prettyblock_megamenu_item_link.tpl b/views/templates/hook/prettyblocks/prettyblock_megamenu_item_link.tpl new file mode 100644 index 0000000..fe0c0aa --- /dev/null +++ b/views/templates/hook/prettyblocks/prettyblock_megamenu_item_link.tpl @@ -0,0 +1,21 @@ +{* + * 2019-2025 Team Ever + * + * NOTICE OF LICENSE + * + * This source file is subject to the Academic Free License (AFL 3.0) + * that is bundled with this package in the file LICENSE.txt. + * It is also available through the world-wide-web at this URL: + * http://opensource.org/licenses/afl-3.0.php + * If you did not receive a copy of the license and are unable to + * obtain it through the world-wide-web, please send an email + * to license@prestashop.com so we can send you a copy immediately. + * + * @author Team Ever + * @copyright 2019-2025 Team Ever + * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) +*} +{* + This block is a data-only child for megamenu_item. + It is rendered inside the parent block template. +*}