You simple need to override catalog_category_view.xml
file into your theme.
code for catalog_category_view.xml
file,
<?xml version="1.0"?>
<!--
/**
* Copyright © 2015 Magento. All rights reserved.
* See COPYING.txt for license details.
*/
-->
<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>
<head>
<script src="js/custom.js"/>
</head>
</body>
</page>
custom.js file path is app/design/frontend/{Vendor}/{theme}/web/js/custom.js
.
Call your custom.js file inside theme list.phtml file with below code,
<script>
require(['jquery','js/custom']);
</script>
Without need of declare requirejs-config.js
file you can directly call inside your category page.
I've been trying to achieve the same thing for a long time. I would really like if someone like Amit Bera could help us with this because there are many questions about "how to get layered navigation with custom collection" and not many usefull answers. Maybe this will help you a little and if you do succeed please share your answer.
I was able to get product collection by using layerResolver like this:
Vendor/Module/Controller/Index/Index.php
public function __construct(
\Magento\Framework\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $pageFactory,
\Magento\Catalog\Model\Layer\Resolver $layerResolver
) {
$this->layerResolver = $layerResolver;
$this->pageFactory = $pageFactory;
$this->context = $context;
parent::__construct($context);
}
public function execute()
{
$date = new \Zend_Date();
$result = $this->pageFactory->create();
$this->layerResolver->create('search');
$collection = $this->layerResolver->get()->getProductCollection();
$collection->('special_price', ['gt'=>0],'left');
$collection
->addAttributeToFilter(
'special_from_date',
[
'or' => [
0 => [
'date' => true,
'to' => $date->get('YYYY-MM-dd').' 23:59:59'],
1 => [
'is' => new \Zend_Db_Expr('null')
],
]
],
'left'
)->addAttributeToFilter(
'special_to_date',
[
'or' => [
0 => [
'date' => true,
'from' => $date->get('YYYY-MM-dd').' 00:00:00'],
1 => [
'is' => new \Zend_Db_Expr('null')
],
]
],
'left'
);
$list = $result->getLayout()->getBlock('custom.products.list');
$list->setProductCollection($collection);
return $result;
}
To avoid problems with aggregations and buckets I use this:
Vendor/Module/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">
<!-- To prepare the filterlist for our custom collection which would be passed to the left navigation we need below virtual types for our custom page navigation -->
<virtualType name="customFilterList" type="Vendor\Module\Model\Layer\FilterList">
<arguments>
<argument name="filterableAttributes" xsi:type="object">Vendor\Module\Model\Layer\FilterableAttributeList</argument>
<argument name="filters" xsi:type="array">
<item name="attribute" xsi:type="string">Vendor\Module\Model\Layer\Filter\Attribute</item>
<item name="category" xsi:type="string">Vendor\Module\Model\Layer\Filter\Category</item>
</argument>
</arguments>
</virtualType>
<!-- once the filter list virtual type is ready we can pass the same to our navigation , I have prepared the virtual type of the core navigation for my custom module and have passed the custom filter list to it -->
<virtualType name="Vendor\Module\Block\Navigation\Custnavigation" type="Magento\LayeredNavigation\Block\Navigation">
<arguments>
<argument name="filterList" xsi:type="object">customFilterList</argument>
</arguments>
</virtualType>
</config>
Vendor/Module/Model/Layer/FilterableAttributeList.php
namespace Vendor\Module\Model\Layer;
class FilterableAttributeList extends \Magento\Catalog\Model\Layer\Category\FilterableAttributeList
{
}
Vendor/Module/Model/Layer/FilterList.php
namespace Vendor\Module\Model\Layer;
class FilterList extends \Magento\Catalog\Model\Layer\FilterList
{
}
Vendor/Module/Model/Layer/Filter/Attribute.php
namespace Vendor\Module\Model\Layer\Filter;
class Attribute extends \Magento\Catalog\Model\Layer\Filter\Attribute
{
}
Vendor/Module/Model/Layer/Filter/Category.php
namespace Vendor\Module\Model\Layer\Filter;
class Category extends \Magento\CatalogSearch\Model\Layer\Filter\Category
{
}
Vendor/Module/view/frontend/layout/custompage_index_index.xml
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="2columns-left">
<body>
<attribute name="class" value="page-with-filter"/>
<referenceContainer name="sidebar.main">
<block class="Vendor\Module\Block\Navigation\Custnavigation" name="catalog.leftnav" before="-" template="Magento_LayeredNavigation::layer/view.phtml">
<block class="Magento\LayeredNavigation\Block\Navigation\State" name="catalog.navigation.state" as="state" />
<block class="Magento\LayeredNavigation\Block\Navigation\FilterRenderer" name="catalog.navigation.renderer" as="renderer" template="Magento_LayeredNavigation::layer/filter.phtml"/>
</block>
</referenceContainer>
<referenceContainer name="content">
<block class="Vendor\Module\Block\Product\CustomList" name="custom.products.list" as="product_list" template="Magento_Catalog::product/list.phtml">
<container name="category.product.list.additional" as="additional" />
<block class="Magento\Framework\View\Element\RendererList" name="category.product.type.details.renderers" as="details.renderers">
<block class="Magento\Framework\View\Element\Template" as="default"/>
</block>
<block class="Magento\Catalog\Block\Product\ProductList\Toolbar" name="product_list_toolbar" template="Magento_Catalog::product/list/toolbar.phtml">
<block class="Magento\Theme\Block\Html\Pager" name="product_list_toolbar_pager"/>
</block>
<action method="setToolbarBlockName">
<argument name="name" xsi:type="string">product_list_toolbar</argument>
</action>
</block>
</referenceContainer>
</body>
</page>
Vendor/Module/Block/Product/CustomList.php
namespace Vendor\Module\Block\Product;
use Magento\Catalog\Block\Product\ListProduct;
use Magento\Catalog\Model\ResourceModel\Collection\AbstractCollection;
class CustomList extends ListProduct
{
public function getLoadedProductCollection()
{
return $this->_productCollection;
}
public function setProductCollection(AbstractCollection $collection)
{
$this->_productCollection = $collection;
}
}
This will give you filtered collection on custompage via avaiable special price today. You will have attributes to filter but i still cant get category filter to work properly ( count number for products in collection and layered navigation doesnt match and not all categories are displayed ). If anyone can provide answer on how to make category filter to work with this or other solutions please help.
Most of this code i found here on stackexchange in questions with layered-navigation tag (believe me when i say i searched a lot).
Hope this will get you somewhere. :)
Best Answer
Yes this is possible and quite easy to do.
On the layered navigation template you have a data-mage-init attribute on the element that contains the accordion where you can filter by various product attributes.
You can see the call to accordion with options assigned to it. In this attribute, "accordion" is a requirejs mapping that points to the accordion file. You can find the actual mapping in
vendor/magento/module-theme/view/frontend/requirejs-config.js
.To create your own mapping you must create your own requirejs-config.js file in the view/[frontend|base|adminhtml] directory. That file will look like this:
If you wanted your widget to be used globally, you would simply change "fadeInAccordion" to "accordion" and your widget would be used everywhere an accordion was initialized using the "accordion" mapping. This should show you the power and flexibility using require-js mappings provide over requiring a script by path.
Now you must create the fade-in-accordion.js file that fadeInAccordion maps too. That file will look like this:
The first parameter in the $.widget() function is arbitrary but it must match the return statement. The second parameter is the object you are inheriting. The third parameter is where you can create new functions or override inherited functions. The activate and deactivate are both inherited from the collapsible widget so you can edit/override them in your own widget.
To use your new widget you must create or edit a template and reference your js file either using the path or the mapping. Here is an example of overriding the layered navigation element to use your new widget.
It is the same accordion as before but this one will fadein/out hidden containers instead of hide and show them.
This page on the Magento 2 devdocs will show you more info if needed: http://devdocs.magento.com/guides/v2.0/javascript-dev-guide/javascript/js_practice.html