diff --git a/website_sale_aplicoop/controllers/website_sale.py b/website_sale_aplicoop/controllers/website_sale.py
index 058472f..ce2fde2 100644
--- a/website_sale_aplicoop/controllers/website_sale.py
+++ b/website_sale_aplicoop/controllers/website_sale.py
@@ -847,6 +847,12 @@ class AplicoopWebsiteSale(WebsiteSale):
product_display_info,
filtered_products_dict,
) = self._prepare_products_maps(products, pricelist)
+ # Whether the tags row needs to be reserved on every card: if nothing in
+ # this batch has a published tag, the row is skipped entirely instead of
+ # leaving an empty aria-hidden gap on every product (see product-card.css).
+ any_product_has_tags = any(
+ v["published_tags"] for v in filtered_products_dict.values()
+ )
# Inject draft sale demand context so ribbons/is_out_of_stock use forecasted net qty
products, product_max_qty = self._prepare_draft_stock_data(products)
@@ -876,6 +882,7 @@ class AplicoopWebsiteSale(WebsiteSale):
"group_order": group_order,
"products": products,
"filtered_product_tags": filtered_products_dict,
+ "any_product_has_tags": any_product_has_tags,
"cart": cart,
"available_categories": available_categories,
"category_hierarchy": category_hierarchy,
@@ -986,6 +993,10 @@ class AplicoopWebsiteSale(WebsiteSale):
"product": product,
"published_tags": published_tags,
}
+ # See eskaera_shop for why this decides whether to reserve the tags row.
+ any_product_has_tags = any(
+ v["published_tags"] for v in filtered_products_dict.values()
+ )
product_display_info = {}
for product in products_page:
@@ -1004,6 +1015,7 @@ class AplicoopWebsiteSale(WebsiteSale):
"group_order": group_order,
"products": products_page,
"filtered_product_tags": filtered_products_dict,
+ "any_product_has_tags": any_product_has_tags,
"product_supplier_info": product_supplier_info,
"product_price_info": product_price_info,
"product_display_info": product_display_info,
@@ -1112,6 +1124,10 @@ class AplicoopWebsiteSale(WebsiteSale):
}
for product in products_page
}
+ # See eskaera_shop for why this decides whether to reserve the tags row.
+ any_product_has_tags = any(
+ v["published_tags"] for v in filtered_products_dict.values()
+ )
# Inject draft demand context for ribbons/stock flags
products_page, product_max_qty = self._prepare_draft_stock_data(products_page)
@@ -1126,6 +1142,7 @@ class AplicoopWebsiteSale(WebsiteSale):
"group_order": group_order,
"products": products_page,
"filtered_product_tags": filtered_products_dict,
+ "any_product_has_tags": any_product_has_tags,
"product_supplier_info": product_supplier_info,
"product_price_info": product_price_info,
"product_display_info": product_display_info,
diff --git a/website_sale_aplicoop/views/website_templates.xml b/website_sale_aplicoop/views/website_templates.xml
index a4f4e39..08cc8e0 100644
--- a/website_sale_aplicoop/views/website_templates.xml
+++ b/website_sale_aplicoop/views/website_templates.xml
@@ -661,23 +661,29 @@
-
-
-
-
-
-
+ regardless of which optional fields a given product has. The
+ tags row itself is only reserved when at least one product in
+ this batch actually has a tag (any_product_has_tags, computed
+ controller-side) — otherwise it would add a permanent empty
+ gap to every card for a feature nobody in the list uses. -->
+
+
+