So I'm trying to add some related products and up-sell products from admin, but as soon as I add one the page gets broken.
In the page I see a full html template with some scripts and this error in the end:
Error: Call to a member function getAlternativeImages() on null in /var/www/html/app/design/frontend/Vendor/theme/Magento_Catalog/templates/product/list/item.phtml:58
So my item.phtml
is this:
<?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
*/
declare(strict_types=1);
use Hyva\Theme\Model\ViewModelRegistry;
use Hyva\Theme\ViewModel\HeroiconsOutline;
use Hyva\Theme\ViewModel\HeroiconsSolid;
use Hyva\Theme\ViewModel\ProductCompare;
use Hyva\Theme\ViewModel\ProductListItem;
use Hyva\Theme\ViewModel\ProductPage;
use Hyva\Theme\ViewModel\Wishlist;
use Magento\Catalog\Block\Product\AbstractProduct;
use Magento\Catalog\Helper\Output as CatalogOutputHelper;
use Magento\Framework\Escaper;
// phpcs:disable Magento2.Templates.ThisInTemplate
// phpcs:disable Generic.Files.LineLength.TooLong
/** @var AbstractProduct $block */
/** @var Escaper $escaper */
/** @var ViewModelRegistry $viewModels */
/** @var ProductPage $productViewModel */
$productViewModel = $viewModels->require(ProductPage::class);
/** @var ProductListItem $productListItemViewModel */
$productListItemViewModel = $viewModels->require(ProductListItem::class);
/** @var CatalogOutputHelper $catalogOutputHelper */
$catalogOutputHelper = $this->helper(CatalogOutputHelper::class);
/** @var ProductCompare $compareViewModel */
$compareViewModel = $viewModels->require(ProductCompare::class);
/** @var Wishlist $wishlistViewModel */
$wishlistViewModel = $viewModels->require(Wishlist::class);
/** @var HeroiconsOutline $heroiconsOutline */
$heroiconsOutline = $viewModels->require(HeroiconsOutline::class);
/** @var HeroiconsSolid $heroiconsSolid */
$heroiconsSolid = $viewModels->require(HeroiconsSolid::class);
/** @var Magento\Catalog\Model\Product $product */
$product = $block->getData('product');
$imageDisplayArea = $block->getData('image_display_area');
$templateType = $block->getData('template_type');
$viewMode = $block->getData('view_mode');
$showDescription = $block->getData('show_description');
$showAddToWishlist = $wishlistViewModel->isEnabled();
$showAddToCompare = $compareViewModel->showInProductList();
$viewIsGrid = $viewMode === 'grid';
$_backImageHelper = $block->getData('image_alternative_product_list');
if($_backImageHelper->getAlternativeImages($product)) {
$productAlternativeImages = $_backImageHelper->getAlternativeImages($product);
} else {
$productAlternativeImages = [];
}
if (!$product) {
return '';
}
$productId = $product->getId();
$uniqueId = '_' . uniqid();
?>
<?php if ($product->isSaleable()): ?>
<form method="post"
action="<?= $escaper->escapeUrl($productViewModel->getAddToCartUrl($product)) ?>"
class="item product product-item product_addtocart_form flex flex-col mb-10 lg:mb-24 relative <?= $viewIsGrid ? '' : '' ?>"
x-data="{ active: 0 }"
<?php if ($product->getOptions()): ?>
enctype="multipart/form-data"
<?php endif; ?>
>
<?= /** @noEscape */ $block->getBlockHtml('formkey') ?>
<input type="hidden" name="product" value="<?= (int)$productId ?>"/>
<?php else: ?>
<div class="item product product-item flex flex-col relative <?= $viewIsGrid ? '' : '' ?>">
<?php endif; ?>
<?php
$productImage = $block->getImage($product, $imageDisplayArea);
?>
<?php // Product Image ?>
<div class="flex items-center gap-1 z-40">
<span class="cursor-pointer h-1.5 w-1/3"
@click.prevent="active = 0"
:class="{'bg-secondary' : active === 0, 'bg-container-darker' : active !== 0}">
</span>
<?php foreach($productAlternativeImages as $key => $alternativeImg): ?>
<span :class="{'bg-secondary' : active === <?= $key+1 ?>, 'bg-container-darker' : active !== <?= $key+1 ?>}"
class="cursor-pointer bg-primary h-1.5 w-1/3"
@click.prevent="active = <?= $key+1 ?>"></span>
<?php endforeach; ?>
</div>
<button class="transform rotate-180 w-10 h-10 absolute right-3 top-3 z-40"
@click.prevent="active >= 0 && active < <?= count($productAlternativeImages) ?> ? active = active+1 : active = 0" >
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16 8.94434L2 8.94433" stroke="black" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9 15.8887L2 8.94433L9 2" stroke="black" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<a href="<?= $escaper->escapeUrl($product->getProductUrl()) ?>"
class="product pt-full relative photo product-item-photo block mb-3 <?= $viewIsGrid ? '' : 'md:mb-0' ?>"
tabindex="-1">
<img class="hover:shadow-sm object-contain"
x-show="active === 0"
loading="lazy"
@update-gallery-<?= (int)$productId ?>.window="$el.src = event.detail"
alt="<?= $escaper->escapeHtmlAttr($productImage->getLabel()) ?>"
title="<?= $escaper->escapeHtmlAttr($productImage->getLabel()) ?>"
src="<?= $escaper->escapeUrl($productImage->getImageUrl()) ?>"
width="100%"
height="<?= $escaper->escapeHtmlAttr($productImage->getHeight()) ?>"
/>
<?php foreach($productAlternativeImages as $key => $alternativeImg): ?>
<img class="hover:shadow-sm object-contain aspect-square"
x-show = "active === <?= $key+1 ?> "
src="<?= $alternativeImg->getData('image_url') ?>"
width="<?= $escaper->escapeHtmlAttr($productImage->getWidth()) ?>"
height="<?= $escaper->escapeHtmlAttr($productImage->getHeight()) ?>"
alt="<?= $escaper->escapeHtmlAttr($productImage->getLabel()) ?>"
/>
<?php endforeach; ?>
</a>
<div class="product-info flex flex-col flex-grow">
<?php $productNameStripped = $block->stripTags($product->getName(), null, true); ?>
<div class="mt-2 items-center justify-center text-primary text-lg lg:text-3xl <?= $viewIsGrid ? '' : 'md:text-left' ?>">
<a class="product-item-link"
href="<?= $escaper->escapeUrl($product->getProductUrl()) ?>">
<?= /* @noEscape */
$catalogOutputHelper->productAttribute($product, $product->getName(), 'name') ?>
</a>
</div>
<div class="py-1 mx-auto hidden w-6/12 <?= $viewIsGrid ? '' : 'md:mx-0 md:w-auto' ?>">
<?= $block->getReviewsSummaryHtml($product, 'short') ?>
</div>
<?php if ($product->isAvailable()):?>
<?= $block->getProductDetailsHtml($product) ?>
<?php endif; ?>
<script>
function initPriceBox_<?= /** @noEscape */ $uniqueId ?>()
{
return {
updatePrice(priceData) {
const regularPriceLabel = this.$el.querySelector('.normal-price .price-label');
const regularPriceElement = this.$el.querySelector('.normal-price .price-wrapper .price');
if (priceData.finalPrice.amount < priceData.oldPrice.amount) {
regularPriceLabel.classList.add('hidden');
} else {
regularPriceLabel.classList.remove('hidden');
}
regularPriceElement.innerText = hyva.formatPrice(priceData.finalPrice.amount);
}
}
}
</script>
<div class="lg:pt-1 text-xs lg:text-2xl"
x-data="initPriceBox_<?= /** @noEscape */ $uniqueId ?>()"
@update-prices-<?= (int)$productId ?>.window="updatePrice(event.detail);"
>
<?= /* @noEscape */ $productListItemViewModel->getProductPriceHtml($product) ?>
</div>
<div class=" mt-auto pt-3 flex flex-wrap justify-center items-center">
<?php if ($product->isSaleable()): ?>
<button class="hidden w-auto btn btn-primary justify-center text-sm mr-auto
<?= $viewIsGrid ? 'mr-auto' : 'mr-auto md:mr-0' ?>"
aria-label="<?= $escaper->escapeHtmlAttr(__('Add to Cart')) ?>"
>
<?= $heroiconsOutline->shoppingCartHtml("h-6 w-6 border-current inline", 25, 25) ?>
<span class="ml-2 inline <?= $viewIsGrid ? 'md:ml-0 md:hidden lg:ml-2 lg:inline' : '' ?>">
<?= $escaper->escapeHtml(__('Add to Cart')) ?>
</span>
</button>
<?php endif; ?>
<?php if ($showAddToWishlist): ?>
<script>
function initWishlist() {
return {
addToWishlist(productId) {
var formKey = document.querySelector('input[name=form_key]').value;
var postUrl = BASE_URL+"wishlist/index/add/";
fetch(postUrl, {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
"body": "form_key="+ formKey + "&product="+productId+"&uenc="+btoa(window.location.href),
"method": "POST",
"mode": "cors",
"credentials": "include"
}).then(function (response) {
if (response.redirected) {
window.location.href = response.url;
} else if (response.ok) {
return response.json();
} else {
typeof window.dispatchMessages !== "undefined" && window.dispatchMessages(
[{
type: "warning",
text: "<?= $escaper->escapeHtml(__('Could not add item to wishlist.')) ?>"
}], 5000
);
}
}).then(function (response) {
if(!response) { return }
typeof window.dispatchMessages !== "undefined" && window.dispatchMessages(
[{
type: (response.success) ? "success" : "error",
text: (response.success)
? "<?= $escaper->escapeHtml(__("%1 has been added to your Wish List.", __("Product"))) ?>"
: response.error_message
}], 5000
);
var reloadCustomerDataEvent = new CustomEvent("reload-customer-section-data");
window.dispatchEvent(reloadCustomerDataEvent);
}).catch(function (error) {
typeof window.dispatchMessages !== "undefined" && window.dispatchMessages(
[{
type: "error",
text: error
}], 5000
);
});
}
}
}
</script>
<button x-data="initWishlist()"
@click.prevent="addToWishlist(<?= (int)$productId ?>)"
aria-label="<?= $escaper->escapeHtmlAttr(__('Add to Wish List')) ?>"
type="button"
class="absolute left-3 top-3 z-20 w-9 h-9 p-0 border-0 inline-flex flex-shrink-0 items-center justify-center text-grayLight hover:text-red-600">
<svg class="w-5 h-5 lg:w-7 lg:h-7" width="29" height="26" viewBox="0 0 29 26" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
<path d="M21.4955 0C15.8084 0 14.4976 5.56033 14.4976 5.56033C14.4976 5.56033 13.185 0 7.49795 0C1.81086 0 -1.34769 6.06631 0.554216 10.7863C2.45612 15.5064 6.59019 23.0075 14.501 26C22.4117 23.0075 26.5543 15.5046 28.4494 10.7863C30.3445 6.06811 27.1826 0 21.4955 0Z"
fill=""/>
</svg>
</button>
<?php endif; ?>
<?php if ($showAddToCompare): ?>
<script>
function initCompare() {
return {
addToCompare(productId) {
const formKey = document.querySelector('input[name=form_key]').value;
const postUrl = BASE_URL + 'catalog/product_compare/add/';
fetch(postUrl, {
"headers": {
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
},
"body": "form_key="+ formKey + "&product="+productId+"&uenc="+btoa(window.location.href),
"method": "POST",
"mode": "cors",
"credentials": "include"
}).then(function (response) {
if (response.redirected) {
window.location.href = response.url;
}
}).catch(function (error) {
typeof window.dispatchMessages !== "undefined" && window.dispatchMessages(
[{
type: "error",
text: error
}], 5000
);
});
}
};
}
</script>
<button x-data="initCompare()"
@click.prevent="addToCompare(<?= (int)$productId ?>)"
aria-label="<?= $escaper->escapeHtmlAttr(__('Add to Compare')) ?>"
type="button"
class="rounded-full w-9 h-9 bg-gray-200 p-0 border-0 inline-flex flex-shrink-0 items-center justify-center text-gray-500 hover:text-yellow-500 ml-2">
<?= $heroiconsOutline->scaleHtml("w-5 h-5", 25, 25) ?>
</button>
<?php endif; ?>
</div>
</div>
<?php if ($product->isSaleable()): ?>
</form>
<?php else: ?>
</div>
<?php endif; ?>
and that function getAlternativeImages()
, in item.phtml
is used here:
if($_backImageHelper->getAlternativeImages($product)) {
$productAlternativeImages = $_backImageHelper->getAlternativeImages($product);
} else {
$productAlternativeImages = [];
}
I'm not understanding why this is happening, it seems that $product
is null, but still I can see the product page correctly except for when adding related products or up-sell ones.
If you guys could help it would be awesome, save my day for sure.
if($_backImageHelper->getAlternativeImages($product))
toif($_backImageHelper && $_backImageHelper->getAlternativeImages($product))