Recently I had a request from a customer asking to randomize the product listing in all the categories. The goal was to give the illusion of “freshness” or frequent changes in the categories.
To achieve this the product collection created when a category is called needed to be sorted in a random order. I created an extension to override the Toolbar class which is responsible to create that product collection based on the Toolbar options.
To override a class in magento 2 in a custom module we need to set a preference for that class in the di.xml
file located in the /etc
folder of the extension.
<?xml version="1.0" encoding="UTF-8"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> <preference for="Magento\Catalog\Block\Product\ProductList\Toolbar" type="Webguru\RandomProductList\Block\Product\ProductList\Toolbar" /> </config>
The preference statement tells magento to replace the Magento\Catalog\Block\Product\ProductList\Toolbar
class with our custom class build in this module which is called Webguru\RandomProductList\Block\Product\ProductList\Toolbar
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace Webguru\RandomProductList\Block\Product\ProductList; /** * Product list * @api * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @since 100.0.2 */ class Toolbar extends \Magento\Catalog\Block\Product\ProductList\Toolbar { /** * Set collection to pager * * @param \Magento\Framework\Data\Collection $collection * @return $this */ public function setCollection($collection) { $this->_collection = $collection; $this->_collection->setCurPage($this->getCurrentPage()); // we need to set pagination only if passed value integer and more that 0 $limit = (int)$this->getLimit(); if ($limit) { $this->_collection->setPageSize($limit); } if ($this->getCurrentOrder()) { if (($this->getCurrentOrder()) == 'position') { $this->_collection->addAttributeToSort( $this->getCurrentOrder(), $this->getCurrentDirection() ); } else { $this->_collection->setOrder($this->getCurrentOrder(), $this->getCurrentDirection()); } } // RANDOMIZE using a seed that changes every day $seed = date("Ymd"); $this->_collection->getSelect()->order('rand('.$seed.')'); // END of RANDOMIZE code return $this; } }
The override is done by extending the magento Toolbar
class with our custom build Toolbar
class. By implementing the method setCollection
in our custom Toolbar class we are replacing the original code, meaning that whenever magento call this method anywhere in the application, our customer setCollection
method will be called instead of the original setCollection
method implemented in the magento Toolbar class.
The code in the setCollection
for the custom Toolbar
class is a copy of the original method with some additional statements at the end to implement the randomization.
// RANDOMIZE using a seed that changes every day $seed = date("Ymd"); $this->_collection->getSelect()->order('rand('.$seed.')'); // END of RANDOMIZE code
These 2 lines create a seed for the random generation process and use it to set the order for the product collection. In the above example the seed is being create using the date php function that returns a number by concatenating the current year, month and day. This way, the seed changes everyday making the product collection order to be changed every 24h.
You can download the extension for free for my GitHub repository.
Although I used the preference method to override this same result could have also been implemented using a plugin. Which one do you think is best?