2

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 \Magento\Catalog\Block\Product\View\AbstractView */?>
<?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.

4
  • which version are you using? in the current 2.0 Branch this is not present: github.com/magento/magento2/blob/2.0/app/code/Magento/Catalog/…. Maybe this feature never made it into the stable release (yet?) Commented May 11, 2016 at 17:13
  • I am using Magento-CE-2.0.2. It has this code.
    – Morison
    Commented May 11, 2016 at 17:19
  • thats weird. This is the file in version 2.0.2 from the github repo: github.com/magento/magento2/blob/2.0.2/app/code/Magento/Catalog/…. It's still possible that there is different code in the composer repo (maybe due to a bug in the build process from magento) but its most likely that this feature did not (yet) make it into the final release. Commented May 11, 2016 at 17:25
  • I copy-paste the whole code from magento_2.0.2/vendor/magento/module-catalog/view/frontend/templates/product/view/type/default.phtml . I downloaded the Magento-CE-2.0.2+sample_data-2016-01-28-02-53-25.tar.bz2 version from Magento site.
    – Morison
    Commented May 11, 2016 at 17:34

2 Answers 2

0

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   Magento\Framework\View\Element\Template;

class Product extends Template {

    public function __construct(
        Template\Context $context,
        \Magento\Catalog\Block\Product\View\abstractView $product,
        \Magento\Catalog\Api\ProductRepositoryInterface $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}}\Block\Product" 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>&larr; 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 &rarr;</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.

0

Just improved circlesix's block code to handle first and last items in the category and name ordered navigation (instead of product ids)

namespace XXXXXX\Modules\Block;
    use   Magento\Framework\View\Element\Template;

class ProductNextPrevious extends Template {

public function __construct(
    Template\Context $context,
    \Magento\Catalog\Block\Product\View\abstractView $product,
    \Magento\Catalog\Api\ProductRepositoryInterface $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;
}

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.