This guide explains how to implement Flexible Sized Grid Items in a Magento 2 store running Hyvä Themes. By following these steps, products and visuals in your category and search result pages will respect the colspan and rowspan values configured in the Tweakwise Merchandising Builder.
Note: This article is an implementation suggestion based on the Magento2TweakwiseHyva module. The actual implementation depends on the specifications and requirements of your platform. Use this as a starting point and adapt it to your specific project setup.
Prerequisites
Before you begin, make sure you have:
- Magento 2 with Hyvä Themes installed
- Tweakwise Magento 2 module v8.1.0 or higher
- Tweakwise Hyvä compatibility module v4.1.0 or higher
- Flexible Sized Grid Items configured in the Tweakwise Merchandising Builder
How it works
When Flexible Sized Grid Items are enabled in the Merchandising Builder, the Tweakwise API returns visualproperties for each item in the response:
<item>
<itemno>100012674</itemno>
<type>product</type>
<title>Example Product</title>
<visualproperties>
<colspan>2</colspan>
<rowspan>1</rowspan>
</visualproperties>
</item>The Magento 2 Tweakwise module parses these values and attaches them to the product object in the collection. Your frontend template is then responsible for translating colspan and rowspan into CSS Grid properties (grid-column: span X and grid-row: span Y).
Implementation
The implementation consists of two parts:
- Layout XML — Override the product list template for category and search pages.
- Product list template — A custom
.phtmltemplate that reads visual properties and applies CSS Grid spanning.
Step 1: Create the layout XML overrides
Create or modify the layout XML files in your theme or custom module to point the product list blocks to your custom template.
Category pages — add to view/frontend/layout/hyva_catalog_category_view.xml:
<referenceBlock name="category.products.list">
<action method="setTemplate">
<argument name="template" xsi:type="string">Tweakwise_TweakwiseHyva::product/list.phtml</argument>
</action>
</referenceBlock>Search results page — add to view/frontend/layout/hyva_catalogsearch_result_index.xml:
<referenceBlock name="search_result_list">
<action method="setTemplate">
<argument name="template" xsi:type="string">Tweakwise_TweakwiseHyva::product/list.phtml</argument>
</action>
</referenceBlock>Step 2: Create the product list template
Create the template file at view/frontend/templates/product/list.phtml. This template is based on the default Hyvä product list template but adds visual property support for grid spanning. The example below is taken from the Magento2TweakwiseHyva module.
<?php
/**
* Hyvä Themes - https://hyva.io
* Copyright © Hyvä Themes 2020-present. All rights reserved.
* This product is licensed per Magento install
* See https://hyva.io/license
*/
use Hyva\Theme\Model\ViewModelRegistry;
use Hyva\Theme\ViewModel\CurrentCategory;
use Hyva\Theme\ViewModel\ProductListItem;
use Hyva\Theme\ViewModel\ProductPage;
use Magento\Catalog\Block\Product\ListProduct;
use Magento\Framework\Escaper;
use Tweakwise\Magento2Tweakwise\Model\Client\Type\ItemType;
/** @var ListProduct $block */
/** @var Escaper $escaper */
/** @var ViewModelRegistry $viewModels */
/** @var ProductPage $productViewModel */
/** @var CurrentCategory $currentCategoryViewModel */
$productViewModel = $viewModels->require(ProductPage::class);
$productListItemViewModel = $viewModels->require(ProductListItem::class);
$currentCategoryViewModel = $viewModels->require(CurrentCategory::class);
$eagerLoadImagesCount = (int) ($block->getData('eager_load_images_count') ?? 3);
$productCollection = $block->getLoadedProductCollection();
?>
<?php if (!$productCollection->count()): ?>
<div class="message info empty">
<div>
<?= $escaper->escapeHtml(__('We can\'t find products matching the selection.')) ?>
</div>
</div>
<?php else: ?>
<section class="py-8" id="product-list" aria-label="<?= $escaper->escapeHtmlAttr(__('Product list')) ?>" tabindex="-1">
<?= $block->getToolbarHtml() ?>
<?= $block->getAdditionalHtml() ?>
<?php
if ($block->getMode() == 'grid') {
$viewMode = 'grid';
$imageDisplayArea = 'category_page_grid';
$showDescription = false;
$templateType = \Magento\Catalog\Block\Product\ReviewRendererInterface::SHORT_VIEW;
} else {
$viewMode = 'list';
$imageDisplayArea = 'category_page_list';
$showDescription = true;
$templateType = \Magento\Catalog\Block\Product\ReviewRendererInterface::FULL_VIEW;
}
?>
<div class="products wrapper mode-<?= /* @noEscape */$viewMode ?> products-<?= /* @noEscape */$viewMode ?>">
<ul
role="list"
class="mx-auto pt-4 pb-12 grid gap-4 grid-cols-1 <?= /* @noEscape */$viewMode === 'grid'
? 'sm:grid-cols-2 xl:grid-cols-3'
: '' ?>"
>
<?php
/** @var \Magento\Catalog\Model\Product $product */
foreach (array_values($productCollection->getItems()) as $i => $product):
if ($i < $eagerLoadImagesCount) {
$product->setData('image_custom_attributes', ['loading' => 'eager', 'fetchpriority' => 'high']);
}
$colspan = (int) ($product->getData(ItemType::COLSPAN) ?? 0);
$rowspan = (int) ($product->getData(ItemType::ROWSPAN) ?? 0);
$visualProperties = $product->getData(ItemType::VISUAL_PROPERTIES);
if (is_array($visualProperties)) {
$colspan = max($colspan, (int) ($visualProperties[ItemType::COLSPAN] ?? 0));
$rowspan = max($rowspan, (int) ($visualProperties[ItemType::ROWSPAN] ?? 0));
}
if (method_exists($product, 'getColspan')) {
$colspan = max($colspan, (int) $product->getColspan());
}
if (method_exists($product, 'getRowspan')) {
$rowspan = max($rowspan, (int) $product->getRowspan());
}
$gridStyle = '';
if ($colspan > 1) {
$gridStyle .= 'grid-column: span ' . $colspan . ';';
}
if ($rowspan > 1) {
$gridStyle .= 'grid-row: span ' . $rowspan . ';';
}
?>
<li<?= $gridStyle ? ' style="' . $escaper->escapeHtmlAttr($gridStyle) . '"' : '' ?>>
<?= $productListItemViewModel->getItemHtml(
$product,
$block,
$viewMode,
$templateType,
$imageDisplayArea,
$showDescription
); ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?= $block->getChildBlock('toolbar')->setIsBottom(true)->toHtml() ?>
</section>
<?php endif; ?>How the template reads visual properties
The Tweakwise module stores visual properties on each product in the collection. The values can come from multiple sources, so the template checks all of them and takes the maximum value:
- Direct data attributes —
$product->getData(ItemType::COLSPAN)and$product->getData(ItemType::ROWSPAN) - Nested visual properties array —
$product->getData(ItemType::VISUAL_PROPERTIES)which containscolspanandrowspankeys - Getter methods —
$product->getColspan()and$product->getRowspan()if available on the object
The resulting colspan and rowspan values are then translated to inline CSS Grid styles on each <li> element:
<li style="grid-column: span 2; grid-row: span 1;">
<!-- product card -->
</li>