Magento Asked by Morison on January 22, 2021
Magento 2 product navigation (next and previous buttons) in the product details page are not working for me. I cannot find any settings to enable this feature. I explored the template to
magento_home/vendor/magento/module-catalog/view/frontend/templates/product/view/type/default.phtml
and found the following script:
<?php
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
// @codingStandardsIgnoreFile
?>
<?php /* @var $block MagentoCatalogBlockProductViewAbstractView */?>
<?php $_product = $block->getProduct() ?>
<?php if ($block->displayProductStockStatus()): ?>
<?php if ($_product->isAvailable()): ?>
<div class="stock available" title="<?php /* @escapeNotVerified */ echo __('Availability') ?>">
<span><?php /* @escapeNotVerified */ echo __('In stock') ?></span>
</div>
<?php else: ?>
<div class="stock unavailable" title="<?php /* @escapeNotVerified */ echo __('Availability') ?>">
<span><?php /* @escapeNotVerified */ echo __('Out of stock') ?></span>
</div>
<?php endif; ?>
<?php endif; ?>
However, it is taking me nowhere. How to enable Next, and Previous buttons to the product details page to explore next and previous products?
I have found few tutorials on it, as this and this but they are all for Magento 1.x. I am confused whether this feature is available for Magento 2. Please confirm if you have implemented this feature successfully.
Just improved circlesix's block code to handle first and last items in the category and name ordered navigation (instead of product ids)
namespace XXXXXXModulesBlock;
use MagentoFrameworkViewElementTemplate;
class ProductNextPrevious extends Template {
public function __construct(
TemplateContext $context,
MagentoCatalogBlockProductViewabstractView $product,
MagentoCatalogApiProductRepositoryInterface $productModel,
array $data = []
) {
parent::__construct($context, $data);
$this->_product = $product;
$this->_productModel = $productModel;
}
protected function _prepareLayout() {
return parent::_prepareLayout();
}
protected function _getCurrentProduct() {
return $this->_product->getProduct();
}
protected function _getCurrentCategory() {
$currentCategories = $this->_getCurrentProduct()->getCategoryCollection();
foreach ($currentCategories as $currentCategory) {
return $currentCategory;
}
}
protected function _getProductById($id) {
$_product = $this->_productModel->getById($id);
return $_product;
}
public function getPreviousProductId() {
$_categoryArray = $this->_getCurrentCategory();
$_productCollection = $this->_getCurrentCategory()->getProductCollection()
->addAttributeToSort('name')
->getData();
if ($_categoryArray) {
$_currentProductId = $this->_getCurrentProduct()->getId();
$_currentProductCollectionId = 0;
foreach ($_productCollection as $item) {
if ( $item['entity_id'] == $_currentProductId )
break;
$_currentProductCollectionId ++;
}
if ($_currentProductCollectionId == 0 )
return false;
$_previousProductId = $_productCollection[$_currentProductCollectionId - 1]['entity_id'];
if ($_previousProductId) {
return $_previousProductId;
}
return false;
}
return false;
}
public function getNextProductId() {
$_categoryArray = $this->_getCurrentCategory();
$_productCollection = $this->_getCurrentCategory()
->getProductCollection()
->addAttributeToSort('name')
->getData();
if ($_categoryArray) {
$_currentProductId = $this->_getCurrentProduct()->getId();
$_currentProductCollectionId = 0;
foreach ($_productCollection as $item) {
if ( $item['entity_id'] == $_currentProductId )
break;
$_currentProductCollectionId ++;
}
// last element
if ( $_currentProductCollectionId == ( count ( $_productCollection) - 1 ) )
return false;
$_nextProductId = $_productCollection[$_currentProductCollectionId + 1]['entity_id'];
$_product = $this->_productModel;
if ($_nextProductId) {
return $_nextProductId;
}
return false;
}
return false;
}
public function getPreviousProductUrl() {
if ( ! $productId = $this->getPreviousProductId() )
return false;
if (! $product = $this->_getProductById($productId) )
return false;
$_previousProductUrl = $product ->getProductUrl();
return $_previousProductUrl;
}
public function getNextProductUrl() {
if ( ! $productId = $this->getNextProductId() )
return false;
$_nextProductUrl = $this->_getProductById($productId)->getProductUrl();
return $_nextProductUrl;
}
public function getPreviousProductName() {
if ( ! $productId = $this->getPreviousProductId() )
return false;
$_previousProductName = $this->_getProductById($productId )->getName();
return $_previousProductName;
}
public function getNextProductName() {
if ( ! $productId = $this->getNextProductId() )
return false;
$_nextProductName = $this->_getProductById($productId)->getName();
return $_nextProductName;
}
public function getPreviousProductImage() {
if ( ! $productId = $this->getPreviousProductId() )
return false;
$_previousProductImage = $this->_getProductById($productId)->getImage();
return $_previousProductImage;
}
public function getNextProductImage() {
if ( ! $productId = $this->getNextProductId() )
return false;
$_nextProductImage = $this->_getProductById($productId )->getImage();
return $_nextProductImage;
}
}
Answered by Mike Bahar on January 22, 2021
Here is a way you could do this. The trick seems to be using the API instead of using the Object Manager. With the object manager you can call a 'create' method to pull in the product object and load the product with the product id, but so far most advise warns against this method. Using the API you can call the getById()
method on the object and get back a unique product object each time you call it. Theoretically with should preform better then using the object manager, and if the object manager goes away at some point, you aren't re-writing code (Alan Storm goes into the issues with the object manager here: Magento 2 Object Manager).
Doing it any other way you will run into Magento's automatic singleton design and will never be able to get the link url for each product, as the first product loaded by ID with set that value and it will persist in the page.
Here is the block (in a module you would put this in {{vender-namespace}}/{{module-name}}/Block/Product.php)
<?php
namespace {{vender-namespace}}/{{module-name}}Block;
use MagentoFrameworkViewElementTemplate;
class Product extends Template {
public function __construct(
TemplateContext $context,
MagentoCatalogBlockProductViewabstractView $product,
MagentoCatalogApiProductRepositoryInterface $productModel,
array $data = []
) {
parent::__construct($context, $data);
$this->_product = $product;
$this->_productModel = $productModel;
}
protected function _prepareLayout() {
return parent::_prepareLayout();
}
protected function _getCurrentProduct() {
return $this->_product->getProduct();
}
protected function _getCurrentCategory() {
$currentCategories = $this->_getCurrentProduct()->getCategoryCollection();
foreach ($currentCategories as $currentCategory) {
return $currentCategory;
}
}
protected function _getProductById($id) {
$_product = $this->_productModel->getById($id);
return $_product;
}
public function getPreviousProductId() {
$_categoryArray = $this->_getCurrentCategory();
$_productCollectionIds = $this->_getCurrentCategory()->getProductCollection()->getAllIds();
if ($_categoryArray) {
$_currentProductId = $this->_getCurrentProduct()->getId();
$_currentProductCollectionId = array_search($_currentProductId, $_productCollectionIds);
$_previousProductId = $_productCollectionIds[$_currentProductCollectionId - 1];
if ($_previousProductId) {
return $_previousProductId;
}
return false;
}
return false;
}
public function getNextProductId() {
$_categoryArray = $this->_getCurrentCategory();
$_productCollectionIds = $this->_getCurrentCategory()->getProductCollection()->getAllIds();
if ($_categoryArray) {
$_currentProductId = $this->_getCurrentProduct()->getId();
$_currentProductCollectionId = array_search($_currentProductId, $_productCollectionIds);
$_nextProductId = $_productCollectionIds[$_currentProductCollectionId + 1];
$_product = $this->_productModel;
if ($_nextProductId) {
return $_nextProductId;
}
return false;
}
return false;
}
public function getPreviousProductUrl() {
$_previousProductUrl = $this->_getProductById($this->getPreviousProductId())->getProductUrl();
return $_previousProductUrl;
}
public function getNextProductUrl() {
$_nextProductUrl = $this->_getProductById($this->getNextProductId())->getProductUrl();
return $_nextProductUrl;
}
public function getPreviousProductName() {
$_previousProductName = $this->_getProductById($this->getPreviousProductId())->getName();
return $_previousProductName;
}
public function getNextProductName() {
$_nextProductName = $this->_getProductById($this->getNextProductId())->getName();
return $_nextProductName;
}
public function getPreviousProductImage() {
$_previousProductImage = $this->_getProductById($this->getPreviousProductId())->getImage();
return $_previousProductImage;
}
public function getNextProductImage() {
$_nextProductImage = $this->_getProductById($this->getNextProductId())->getImage();
return $_nextProductImage;
}
}
For displaying this on the front end you need to make a .xml file that will display the template on the product page top (in a module you would put this in {{vender-namespace}}/{{module-name}}/view/frontend/layout/catalog_product_view.xml)
<?xml version="1.0"?>
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="{{vender-namespace}}/{{module-name}}BlockProduct" name="custom.product.pagination" template="{{vender-namespace}}/{{module-name}}/::product/product-pagination.phtml" before="-" />
</referenceContainer>
</body>
</page>
And then in your phtml file (in a module you would put this in {{vender-namespace}}/{{module-name}}/view/frontend/template/product/product-pagination.phtml)
<?php
$previousProductUrl = $block->getPreviousProductUrl();
$nextProductUrl = $block->getNextProductUrl();
$previousProductName = $block->getPreviousProductName();
$nextProductName = $block->getNextProductName();
$previousProductImage = $block->getPreviousProductImage();
$nextProductImage = $block->getNextProductImage();
$previousImage = $this->getBaseUrl() . 'pub/media/catalog/product' . $previousProductImage;
$nextImage = $this->getBaseUrl() . 'pub/media/catalog/product' . $nextProductImage;
?>
<div class="product-pagination">
<div class="previous-product" style="float: left;">
<a href="<?php echo $previousProductUrl; ?>">
<img src="<?php echo $previousImage; ?>" alt="<?php echo $previousProductName; ?>" height="75" width="75" />
<p><?php echo $previousProductName; ?></p>
<button type="submit" title="Previous Product" class="action primary to-prev-product">
<span>← prev</span>
</button>
</a>
</div>
<div class="next-product" style="float: right;">
<a href="<?php echo $nextProductUrl; ?>">
<img src="<?php echo $nextImage; ?>" alt="<?php echo $nextProductName; ?>" height="75" width="75" />
<p><?php echo $nextProductName; ?></p>
<button type="submit" title="Next Product" class="action primary to-next-product">
<span>next →</span>
</button>
</a>
</div>
</div>
Of course there is a lot more you can do with this as far as theme integration and styling. But for a proof of concept, this will get you there.
Answered by circlesix on January 22, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP