Magento 2 Category page add custom view mode
-
19-02-2021 - |
Solution
I have tried to find solution to create custom view mode on category page. But no luck :(
So, I have check core files of magento 2. From where the view mode add, and I got idea how to create new mode. Below are the steps I have performed to create module.
Step #1: Created a module registration file app/code/Darsh/Expandmode/registration.php
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE, 'Darsh_Expandmode', __DIR__
);
Step #2: Created a composer.json file app/code/Darsh/Expandmode/composer.json
{
"name": "darsh/magento2-expandmode",
"description": "Category page custom view mode",
"version": "1.0.0",
"require": {
"magento/module-backend": "~100.0.0"
},
"type": "magento2-module",
"extra": {
"map": [
[
"*",
"Darsh/Expandmode"
]
]
}
}
Step #3: Created a module.xml file app/code/Darsh/Expandmode/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Darsh_Expandmode" setup_version="1.0.0" >
</module>
</config>
Step #4: Created a di.xml file to overwrite core magento functionality. app/code/Darsh/Expandmode/etc/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Catalog\Model\Config\Source\ListMode" type="Darsh\Expandmode\Model\Config\Source\ListMode" />
<preference for="Magento\Catalog\Helper\Product\ProductList" type="Darsh\Expandmode\Helper\Product\ProductList" />
</config>
Step #5: Created a ListMode.php file to overwrite core magento functionality. app/code/Darsh/Expandmode/Model/Config/Source/ListMode.php
<?php
namespace Darsh\Expandmode\Model\Config\Source;
class ListMode extends \Magento\Catalog\Model\Config\Source\ListMode
{
/**
* {@inheritdoc}
*
* @codeCoverageIgnore
*/
public function toOptionArray()
{
return [
['value' => 'grid', 'label' => __('Grid Only')],
['value' => 'list', 'label' => __('List Only')],
['value' => 'grid-list', 'label' => __('Grid (default) / List')],
['value' => 'list-grid', 'label' => __('List (default) / Grid')],
['value' => 'list-grid-expand', 'label' => __('Expand (default) / List / Grid')]
];
}
}
Step #6: Created a ProductList.php file to overwrite core magento functionality. app/code/Darsh/Expandmode/Helper/Product/ProductList.php
<?php
namespace Darsh\Expandmode\Helper\Product;
class ProductList extends \Magento\Catalog\Helper\Product\ProductList
{
/**
* List mode configuration path
*/
const XML_PATH_LIST_MODE = 'catalog/frontend/list_mode';
const VIEW_MODE_LIST = 'list';
const VIEW_MODE_GRID = 'grid';
const DEFAULT_SORT_DIRECTION = 'asc';
/**
* @var \Magento\Framework\App\Config\ScopeConfigInterface
*/
protected $scopeConfig;
/**
* @var \Magento\Framework\Registry
*/
private $coreRegistry;
/**
* Default limits per page
*
* @var array
*/
protected $_defaultAvailableLimit = [10 => 10,20 => 20,50 => 50];
/**
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
*/
public function __construct(
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Framework\Registry $coreRegistry = null
) {
$this->scopeConfig = $scopeConfig;
$this->coreRegistry = $coreRegistry ?: \Magento\Framework\App\ObjectManager::getInstance()->get(
\Magento\Framework\Registry::class
);
}
/**
* Returns available mode for view
*
* @return array|null
*/
public function getAvailableViewMode()
{
$value = $this->scopeConfig->getValue(
self::XML_PATH_LIST_MODE,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
switch ($value) {
case 'grid':
$availableMode = ['grid' => __('Grid')];
break;
case 'list':
$availableMode = ['list' => __('List')];
break;
case 'grid-list':
$availableMode = ['grid' => __('Grid'), 'list' => __('List')];
break;
case 'list-grid':
$availableMode = ['list' => __('List'), 'grid' => __('Grid')];
break;
case 'list-grid-expand':
$availableMode = ['expand' => __('Expand'), 'list' => __('List'), 'grid' => __('Grid')];
break;
default:
$availableMode = null;
break;
}
return $availableMode;
}
/**
* Returns default view mode
*
* @param array $options
* @return string
*/
public function getDefaultViewMode($options = [])
{
if (empty($options)) {
$options = $this->getAvailableViewMode();
}
return current(array_keys($options));
}
/**
* Get default sort field
*
* @return null|string
*/
public function getDefaultSortField()
{
$currentCategory = $this->coreRegistry->registry('current_category');
if ($currentCategory) {
return $currentCategory->getDefaultSortBy();
}
return $this->scopeConfig->getValue(
\Magento\Catalog\Model\Config::XML_PATH_LIST_DEFAULT_SORT_BY,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
}
/**
* Retrieve available limits for specified view mode
*
* @param string $mode
* @return array
*/
public function getAvailableLimit($mode)
{
if (!in_array($mode, [self::VIEW_MODE_GRID, self::VIEW_MODE_LIST])) {
return $this->_defaultAvailableLimit;
}
$perPageConfigKey = 'catalog/frontend/' . $mode . '_per_page_values';
$perPageValues = (string)$this->scopeConfig->getValue(
$perPageConfigKey,
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
$perPageValues = explode(',', $perPageValues);
$perPageValues = array_combine($perPageValues, $perPageValues);
if ($this->scopeConfig->isSetFlag(
'catalog/frontend/list_allow_all',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
)) {
return ($perPageValues + ['all' => __('All')]);
} else {
return $perPageValues;
}
}
/**
* Retrieve default per page values
*
* @param string $viewMode
* @return string (comma separated)
*/
public function getDefaultLimitPerPageValue($viewMode)
{
if ($viewMode == self::VIEW_MODE_LIST) {
return $this->scopeConfig->getValue(
'catalog/frontend/list_per_page',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
} elseif ($viewMode == self::VIEW_MODE_GRID) {
return $this->scopeConfig->getValue(
'catalog/frontend/grid_per_page',
\Magento\Store\Model\ScopeInterface::SCOPE_STORE
);
}
return 0;
}
}
Step #7: Applied changes in layout section app/code/Darsh/Expandmode/view/frontend/layout/catalog_category_view.xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="category.products.list" template="Darsh_Expandmode::product/list.phtml" />
</body>
</page>
Step #8: Applied changes in layout section app/code/Darsh/Expandmode/view/frontend/templates/product/list.phtml
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
use Magento\Framework\App\Action\Action;
// @codingStandardsIgnoreFile
?>
<?php
/**
* Product list template
*
* @var $block \Magento\Catalog\Block\Product\ListProduct
*/
?>
<?php
$_productCollection = $block->getLoadedProductCollection();
$_helper = $this->helper('Magento\Catalog\Helper\Output');
?>
<?php if (!$_productCollection->count()): ?>
<div class="message info empty"><div><?= /* @escapeNotVerified */ __('We can\'t find products matching the selection.') ?></div></div>
<?php else: ?>
<?= $block->getToolbarHtml() ?>
<?= $block->getAdditionalHtml() ?>
<?php
if ($block->getMode() == 'grid') {
$viewMode = 'grid';
$imageDisplayArea = 'category_page_grid';
$showDescription = false;
$templateType = \Magento\Catalog\Block\Product\ReviewRendererInterface::SHORT_VIEW;
} elseif ($block->getMode() == 'expand') {
$viewMode = 'expand';
$imageDisplayArea = 'category_page_list';
$showDescription = true;
$templateType = \Magento\Catalog\Block\Product\ReviewRendererInterface::FULL_VIEW;
}else{
$viewMode = 'list';
$imageDisplayArea = 'category_page_list';
$showDescription = true;
$templateType = \Magento\Catalog\Block\Product\ReviewRendererInterface::FULL_VIEW;
}
/**
* Position for actions regarding image size changing in vde if needed
*/
$pos = $block->getPositioned();
?>
<div class="products wrapper <?= /* @escapeNotVerified */ $viewMode ?> products-<?= /* @escapeNotVerified */ $viewMode ?>">
<ol class="products list items product-items">
<?php /** @var $_product \Magento\Catalog\Model\Product */ ?>
<?php foreach ($_productCollection as $_product): ?>
<li class="item product product-item">
<div class="product-item-info" data-container="product-<?= /* @escapeNotVerified */ $viewMode ?>">
<?php
$productImage = $block->getImage($_product, $imageDisplayArea);
if ($pos != null) {
$position = ' style="left:' . $productImage->getWidth() . 'px;'
. 'top:' . $productImage->getHeight() . 'px;"';
}
?>
<?php // Product Image ?>
<a href="<?= /* @escapeNotVerified */ $_product->getProductUrl() ?>" class="product photo product-item-photo" tabindex="-1">
<?= $productImage->toHtml() ?>
</a>
<div class="product details product-item-details">
<?php
$_productNameStripped = $block->stripTags($_product->getName(), null, true);
?>
<strong class="product name product-item-name">
<a class="product-item-link"
href="<?= /* @escapeNotVerified */ $_product->getProductUrl() ?>">
<?= /* @escapeNotVerified */ $_helper->productAttribute($_product, $_product->getName(), 'name') ?>
</a>
</strong>
<?= $block->getReviewsSummaryHtml($_product, $templateType) ?>
<?= /* @escapeNotVerified */ $block->getProductPrice($_product) ?>
<?= $block->getProductDetailsHtml($_product) ?>
<div class="product-item-inner">
<div class="product actions product-item-actions"<?= strpos($pos, $viewMode . '-actions') ? $position : '' ?>>
<div class="actions-primary"<?= strpos($pos, $viewMode . '-primary') ? $position : '' ?>>
<?php if ($_product->isSaleable()): ?>
<?php $postParams = $block->getAddToCartPostParams($_product); ?>
<form data-role="tocart-form" data-product-sku="<?= $block->escapeHtml($_product->getSku()) ?>" action="<?= /* @NoEscape */ $postParams['action'] ?>" method="post">
<input type="hidden" name="product" value="<?= /* @escapeNotVerified */ $postParams['data']['product'] ?>">
<input type="hidden" name="<?= /* @escapeNotVerified */ Action::PARAM_NAME_URL_ENCODED ?>" value="<?= /* @escapeNotVerified */ $postParams['data'][Action::PARAM_NAME_URL_ENCODED] ?>">
<?= $block->getBlockHtml('formkey') ?>
<button type="submit"
title="<?= $block->escapeHtml(__('Add to Cart')) ?>"
class="action tocart primary">
<span><?= /* @escapeNotVerified */ __('Add to Cart') ?></span>
</button>
</form>
<?php else: ?>
<?php if ($_product->isAvailable()): ?>
<div class="stock available"><span><?= /* @escapeNotVerified */ __('In stock') ?></span></div>
<?php else: ?>
<div class="stock unavailable"><span><?= /* @escapeNotVerified */ __('Out of stock') ?></span></div>
<?php endif; ?>
<?php endif; ?>
</div>
<div data-role="add-to-links" class="actions-secondary"<?= strpos($pos, $viewMode . '-secondary') ? $position : '' ?>>
<?php if ($addToBlock = $block->getChildBlock('addto')): ?>
<?= $addToBlock->setProduct($_product)->getChildHtml() ?>
<?php endif; ?>
</div>
</div>
<?php if ($showDescription):?>
<div class="product description product-item-description">
<?= /* @escapeNotVerified */ $_helper->productAttribute($_product, $_product->getShortDescription(), 'short_description') ?>
<a href="<?= /* @escapeNotVerified */ $_product->getProductUrl() ?>" title="<?= /* @escapeNotVerified */ $_productNameStripped ?>"
class="action more"><?= /* @escapeNotVerified */ __('Learn More') ?></a>
</div>
<?php endif; ?>
</div>
</div>
</div>
</li>
<?php endforeach; ?>
</ol>
</div>
<?= $block->getToolbarHtml() ?>
<?php if (!$block->isRedirectToCartEnabled()) : ?>
<script type="text/x-magento-init">
{
"[data-role=tocart-form], .form.map.checkout": {
"catalogAddToCart": {
"product_sku": "<?= /* @NoEscape */ $_product->getSku() ?>"
}
}
}
</script>
<?php endif; ?>
<?php endif; ?>
As per my requirment I have made changes on above files, but basic idea you will get to create new custom view mode on category page.
Thanks :)