Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
079a582
DOMMVP-245 magento 2.4.9 fix interface
kzaworski-ironplane May 29, 2026
453092d
DOMMVP-245 magento 2.4.9 fix interface
kzaworski-ironplane May 29, 2026
7973daf
Merge branch 'feature/DOMMVP-245' into feature/SMM-99
jpereira-ironplane Aug 19, 2026
ac9eacc
SMM-99 - adjust utility class to make possible to compile theme on 2.4.9
jpereira-ironplane Aug 19, 2026
aa53db4
SMM-99 - fix color declaration to prevent errors
jpereira-ironplane Aug 19, 2026
2bbe33c
Bump js-yaml from 4.1.1 to 4.3.2
dependabot[bot] Sep 13, 2026
15d6112
SMM-59 - Fix Custom URL field keeping the previous node type content
jpereira-ironplane Sep 14, 2026
ddb726e
SMM-99 Remove topmenu-desktop from checkout
Sep 15, 2026
ba1be5a
SMM-99 Adjust positioning in mobile
kruchy8 Sep 15, 2026
075280d
SMM-99 Remove menu-footer from checkout
kruchy8 Sep 15, 2026
12226d4
Setting the title after autocomplete selection now checks it it's emp…
Oct 10, 2025
6d34383
Merge branch 'dependabot/npm_and_yarn/js-yaml-4.3.2' into feature/SMM-91
jpereira-ironplane Sep 18, 2026
ae6d9ee
Merge branch 'feature/SMM-99' into release/2.30.0
jpereira-ironplane Sep 18, 2026
834e320
Merge branch 'feature/SMM-91' into release/2.30.0
jpereira-ironplane Sep 18, 2026
566433d
Merge branch 'feature/SMM-61' into release/2.30.0
jpereira-ironplane Sep 18, 2026
2771224
SMM-83 - Making possible to add category child templates
jpereira-ironplane Sep 21, 2026
65e923f
Merge branch 'feature/SMM-83' into release/2.30.0
jpereira-ironplane Sep 23, 2026
8f35075
Merge branch 'feature/SMM-59' into release/2.30.0
jpereira-ironplane Sep 23, 2026
c4050af
Merge remote-tracking branch 'origin/feature/SMM-99' into release/2.30.0
jpereira-ironplane Sep 23, 2026
7359829
SMM-58 - Fix Hyva footer menu CSP compatibility and checkout navigation
kruchy8 Oct 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Block/NodeType/CategoryChild.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,18 @@
use Magento\Catalog\Api\CategoryRepositoryInterface;
use Snowdog\Menu\Model\TemplateResolver;
use Snowdog\Menu\Model\NodeType\Category as ModelCategory;
use Snowdog\Menu\Model\NodeType\CategoryChild as ModelCategoryChild;

class CategoryChild extends Category
{
/**
* @var string
*/
protected $defaultTemplate = 'menu/node_type/category_child.phtml';
/**
* @var string
*/
protected $customTemplateFolder = 'menu/custom/category_child/';
/**
* @var string
*/
Expand All @@ -22,6 +27,10 @@ class CategoryChild extends Category
* @var CategoryRepositoryInterface
*/
protected $categoryRepository;
/**
* @var ModelCategoryChild
*/
private $categoryChildModel;

/**
* Category constructor.
Expand All @@ -31,6 +40,7 @@ class CategoryChild extends Category
* @param ModelCategory $categoryModel
* @param TemplateResolver $templateResolver
* @param CategoryRepositoryInterface $categoryRepository
* @param ModelCategoryChild $categoryChildModel
* @param array $data
*/
public function __construct(
Expand All @@ -39,10 +49,12 @@ public function __construct(
ModelCategory $categoryModel,
TemplateResolver $templateResolver,
CategoryRepositoryInterface $categoryRepository,
ModelCategoryChild $categoryChildModel,
array $data = []
) {
parent::__construct($context, $coreRegistry, $categoryModel, $templateResolver, $data);
$this->categoryRepository = $categoryRepository;
$this->categoryChildModel = $categoryChildModel;
}

/**
Expand All @@ -58,6 +70,14 @@ public function getNodeCacheKeyInfo()
];
}

/**
* @inheritDoc
*/
public function getJsonConfig()
{
return $this->categoryChildModel->fetchConfigData();
}

/**
* @return \Magento\Framework\Phrase
*/
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.


## [Unreleased]
### Fixed
- Hyvä footer menu compatibility with Alpine CSP and cached menu HTML (SMM-58)
- Mobile top menu remaining visible in Hyvä Checkout (SMM-58)
- Custom URL field keeping the previous node type's content after changing a node's type (SMM-59)
### Updated
- Bump minimatch from 3.1.2 to 3.1.5 ([#395](https://github.com/SnowdogApps/magento2-menu/pull/395))
- Bump lodash from 4.17.21 to 4.17.23 ([#390](https://github.com/SnowdogApps/magento2-menu/pull/390))
Expand Down
4 changes: 2 additions & 2 deletions Console/Command/NodesValidatorCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function __construct(
/**
* {@inheritdoc}
*/
protected function configure()
protected function configure(): void
{
$description = 'It will loop all menu nodes and return the IDs and description of invalid menu nodes.'
. PHP_EOL
Expand All @@ -72,7 +72,7 @@ protected function configure()
parent::configure();
}

public function execute(InputInterface $input, OutputInterface $output)
public function execute(InputInterface $input, OutputInterface $output): int
{
$this->setAreaCode();
$invalidNodeIds = [];
Expand Down
48 changes: 48 additions & 0 deletions Model/NodeType/CategoryChild.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,58 @@

namespace Snowdog\Menu\Model\NodeType;

use Magento\Framework\Profiler;
use Snowdog\Menu\Model\Menu\Node\Image\File as NodeImage;
use Snowdog\Menu\Model\NodeType\AbstractNode;
use Snowdog\Menu\Model\TemplateResolver;

class CategoryChild extends AbstractNode
{
/**
* @var TemplateResolver
*/
private $templateResolver;

/**
* @param Profiler $profiler
* @param NodeImage $nodeImage
* @param TemplateResolver $templateResolver
*/
public function __construct(
Profiler $profiler,
NodeImage $nodeImage,
TemplateResolver $templateResolver
) {
$this->templateResolver = $templateResolver;

parent::__construct($profiler, $nodeImage);
}

/**
* @inheritDoc
*/
public function fetchConfigData()
{
$this->profiler->start(__METHOD__);

$data = [
'snowMenuNodeCustomTemplates' => [
'defaultTemplate' => 'category_child',
'options' => $this->templateResolver->getCustomTemplateOptions('category_child'),
'message' => __('Template not found'),
],
'snowMenuSubmenuCustomTemplates' => [
'defaultTemplate' => 'sub_menu',
'options' => $this->templateResolver->getCustomTemplateOptions('sub_menu'),
'message' => __('Template not found'),
],
];

$this->profiler->stop(__METHOD__);

return $data;
}

/**
* @inheritDoc
*/
Expand Down
2 changes: 1 addition & 1 deletion Service/Menu/SaveRequestProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public function processNodeObject(
$nodeObject->setClasses($nodeData['classes']);
}

if (isset($nodeData['content'])) {
if (array_key_exists('content', $nodeData)) {
$nodeObject->setContent($nodeData['content']);
}

Expand Down
4 changes: 3 additions & 1 deletion view/adminhtml/web/vue/field-type/autocomplete-lazy.vue
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@
}
else if (option && typeof option === 'string') {
this.$set(this.item, this.itemKey, option);
this.$set(this.item, 'title', this.options.find(item => item.value === option)?.label);
if (!this.item.title) {
this.$set(this.item, 'title', this.options.find(item => item.value === option)?.label);
}
}
else {
this.$set(this.item, this.itemKey, this.defaultSelectedOption ? this.defaultSelectedOption.value.toString() : '');
Expand Down
8 changes: 6 additions & 2 deletions view/adminhtml/web/vue/field-type/autocomplete.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@

<script>
define(['Vue'], function(Vue) {
Vue.component('autocomplete', {

Check warning on line 53 in view/adminhtml/web/vue/field-type/autocomplete.vue

View workflow job for this annotation

GitHub Actions / Code Lint Analysis

Component name "autocomplete" should always be multi-word

Check warning on line 53 in view/adminhtml/web/vue/field-type/autocomplete.vue

View workflow job for this annotation

GitHub Actions / Code Lint Analysis

Component name "autocomplete" should always be multi-word
name: 'autocomplete',

Check warning on line 54 in view/adminhtml/web/vue/field-type/autocomplete.vue

View workflow job for this annotation

GitHub Actions / Code Lint Analysis

Component name "autocomplete" should always be multi-word

Check warning on line 54 in view/adminhtml/web/vue/field-type/autocomplete.vue

View workflow job for this annotation

GitHub Actions / Code Lint Analysis

Component name "autocomplete" should always be multi-word
props: {
label: {
type: String,
Expand Down Expand Up @@ -131,11 +131,15 @@
if (option && typeof option === 'object') {
this.$set(this.item, this.itemKey, option.value.toString());
this.$set(this.item, this.itemIdKey, option.id.toString());
this.$set(this.item, 'title', option.label);
if (!this.item.title) {
this.$set(this.item, 'title', option.label);
}
}
else if (option && typeof option === 'string') {
this.$set(this.item, this.itemKey, option);
this.$set(this.item, 'title', this.options.find(item => item.value === option)?.label);
if (!this.item.title) {
this.$set(this.item, 'title', this.options.find(item => item.value === option)?.label);
}
}
else {
this.$set(this.item, this.itemKey, this.defaultSelectedOption ? this.defaultSelectedOption.value.toString() : '');
Expand Down
5 changes: 5 additions & 0 deletions view/frontend/layout/default_hyva.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
</referenceBlock>

<referenceBlock name="script-alpine-js">
<block
name="snowdog-menu-footer-js"
class="Magento\Framework\View\Element\Template"
template="Snowdog_Menu::page/js/menu-footer.phtml"
/>
<block
name="alpine-plugin-collapse"
template="Snowdog_Menu::page/js/plugins/collapse.phtml"
Expand Down
9 changes: 9 additions & 0 deletions view/frontend/layout/hyva_checkout_index_index.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="topmenu-desktop" remove="true"/>
<referenceBlock name="topmenu-mobile" remove="true"/>
<referenceBlock name="menu-footer" remove="true"/>
</body>
</page>
6 changes: 2 additions & 4 deletions view/frontend/tailwind/tailwind-source.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
@layer utilities {
.snowdog-menu-text-hover {
@apply text-blue-700;
}
@utility snowdog-menu-text-hover {
color: var(--color-blue-700);
}

[x-cloak="tablet"] {
Expand Down
56 changes: 15 additions & 41 deletions view/frontend/templates/hyva-menu-footer/menu.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,22 @@ use Snowdog\Menu\Block\Menu;
/** @var ViewModelRegistry $viewModels */

$menu = $block->getMenu();
$uniqueId = '_' . uniqid();

$heroicons = $viewModels->require(HeroiconsOutline::class);
?>

<?php if ($menu): ?>
<script>
'use strict';

const initMenuFooter<?= $escaper->escapeHtml($uniqueId) ?> = () => ({
isDesktop: true,
checkIsDesktopResolution() {
this.isDesktop = window.matchMedia('(min-width: 1024px)').matches
},
toggleSubmenu(event, index) {
const focusableElements = 'button:not([disabled]), a[href]:not([tabindex="-1"]), [tabindex]:not([tabindex="-1"])'

event.stopPropagation()
this[index] = !this[index]

if (this[index]) {
this.$nextTick(() => {
this.$refs['submenu-' + index]?.querySelector(focusableElements)?.focus()
})
} else {
this.$nextTick(() => {
this.$refs['submenu-toggle-' + index]?.focus()
})
}
},
})
</script>
<div
class="
<?= $escaper->escapeHtmlAttr($menu->getCssClass()) ?>
snowdog-menu-footer w-full flex flex-wrap text-primary-darker
"
x-data="initMenuFooter<?= $escaper->escapeHtml($uniqueId) ?>()"
x-data="snowdogMenuFooter"
>
<ul class="w-full flex flex-col flex-wrap lg:flex-row lg:justify-between lg:gap-6 divide-y divide-container lg:divide-y-0"
x-init="checkIsDesktopResolution()"
@resize.window.debounce="checkIsDesktopResolution()"
@visibilitychange.window.debounce="checkIsDesktopResolution()"
x-init="checkIsDesktopResolution"
@resize.window.debounce="checkIsDesktopResolution"
@visibilitychange.window.debounce="checkIsDesktopResolution"
>
<?php foreach ($block->getNodes() as $node): ?>
<?php
Expand All @@ -64,44 +37,45 @@ $heroicons = $viewModels->require(HeroiconsOutline::class);
$nodeType = $node->getType();
$nodeClasses = $node->getClasses();
?>
<li x-data="{'<?= /* @noEscape */ (string) $indexId ?>': false }"
<li x-data="snowdogMenuFooterNode"
data-node-id="<?= $escaper->escapeHtmlAttr($indexId) ?>"
class="flex-1"
>
<?php if ($node->getIsParent() && !$node->getIsViewAllLink()): ?>
<div @keydown.escape="(event) => !isDesktop && toggleSubmenu(event, '<?= /* @noEscape */ (string) $indexId ?>')">
<div @keydown.escape="handleEscape">
<span x-show="isDesktop"
x-cloak="tablet"
class="block font-bold mb-6"
>
<?= $escaper->escapeHtml($title) ?>
</span>
<button x-show="!isDesktop"
<button x-show="isMobile"
x-cloak="desktop"
x-ref="submenu-toggle-<?= /* @noEscape */ (string) $indexId ?>"
x-ref="submenu-toggle-<?= $escaper->escapeHtmlAttr($indexId) ?>"
class="
w-full py-4 font-bold
"
@click="(event) => toggleSubmenu(event, '<?= /* @noEscape */ (string) $indexId ?>')"
:aria-expanded="<?= /* @noEscape */ (string) $indexId ?> === true"
@click="toggleSubmenu"
:aria-expanded="open"
type="button"
>
<div class="flex items-center justify-between">
<span>
<?= $escaper->escapeHtml($title) ?>
</span>
<div class="transition-transform"
:class="{'rotate-180' : <?= /* @noEscape */ (string) $indexId ?> === true}"
:class="chevronClasses"
>
<?= $heroicons->chevronDownHtml('text-gray-500', 20, 20, ['aria-hidden' => 'true']); ?>
</div>
</div>
</button>
<div x-show="isDesktop || !!<?= /* @noEscape */ (string) $indexId ?>"
<div x-show="submenuVisible"
x-cloak="tablet"
x-ref="submenu-<?= /* @noEscape */ (string) $indexId ?>"
x-ref="submenu-<?= $escaper->escapeHtmlAttr($indexId) ?>"
x-collapse
class="pb-2"
:aria-hidden="!isDesktop && <?= /* @noEscape */ (string) $indexId ?> === false ? 'true' : 'false'"
:aria-hidden="submenuHidden"
>
<?= /* @noEscape */ $block->renderSubmenu($children, $node, $childrenLevel) ?>
</div>
Expand Down
2 changes: 1 addition & 1 deletion view/frontend/templates/hyva-topmenu-mobile/menu.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ $uniqueId = '_' . uniqid();
<nav
class="
<?= $escaper->escapeHtmlAttr($menu->getCssClass()) ?>
snowdog-topmenu-mobile z-20 order-2 text-primary-darker sm:order-1 navigation lg:hidden
snowdog-topmenu-mobile flex z-20 order-1 text-primary-darker sm:-order-1 navigation lg:hidden
"
x-data="initMenuMobile<?= $escaper->escapeHtml($uniqueId) ?>()"
@keydown.escape="open && closeMenu"
Expand Down
Loading
Loading