├── Block
├── Adminhtml
│ └── System
│ │ └── Config
│ │ └── Form
│ │ └── Field
│ │ ├── Github.php
│ │ ├── Logo.php
│ │ ├── Marketplace.php
│ │ ├── Skype.php
│ │ └── Telegram.php
├── Copyright.php
└── Swatches
│ └── LayeredNavigation
│ └── RenderLayered.php
├── Controller
└── Index
│ └── Index.php
├── LICENSE.md
├── Model
├── Layer
│ ├── Filter
│ │ ├── Attribute.php
│ │ ├── Category.php
│ │ ├── Decimal.php
│ │ ├── Item.php
│ │ └── Price.php
│ └── ItemCollectionProvider.php
├── ResourceModel
│ └── Fulltext
│ │ └── Collection.php
└── Url
│ └── Builder.php
├── Observer
└── Copyright.php
├── Plugin
└── Model
│ └── Adapter
│ ├── Aggregation
│ └── Checker
│ │ └── Query
│ │ └── CatalogView.php
│ └── Mysql
│ └── Filter
│ └── Preprocessor.php
├── README.md
├── composer.json
├── etc
├── adminhtml
│ ├── menu.xml
│ └── system.xml
├── config.xml
├── di.xml
├── events.xml
├── frontend
│ └── routes.xml
└── module.xml
├── guidelines.pdf
├── registration.php
└── view
├── adminhtml
└── web
│ └── images
│ └── logo.png
└── frontend
├── layout
├── catalog_category_view_type_layered.xml
├── catalogsearch_result_index.xml
├── default.xml
└── slavayurthev_index_index.xml
├── templates
├── copyright.phtml
├── copyright
│ └── link.phtml
└── layer
│ └── filter.phtml
└── web
├── css
└── styles.css
└── img
├── checked.png
└── unchecked.png
/Block/Adminhtml/System/Config/Form/Field/Github.php:
--------------------------------------------------------------------------------
1 | '
16 | .$element->getEscapedValue()
17 | .'
';
18 | }
19 | }
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/Field/Logo.php:
--------------------------------------------------------------------------------
1 |
';
14 | }
15 | }
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/Field/Marketplace.php:
--------------------------------------------------------------------------------
1 | '
16 | .$element->getEscapedValue()
17 | .'';
18 | }
19 | }
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/Field/Skype.php:
--------------------------------------------------------------------------------
1 | '
16 | .$element->getEscapedValue()
17 | .'';
18 | }
19 | }
--------------------------------------------------------------------------------
/Block/Adminhtml/System/Config/Form/Field/Telegram.php:
--------------------------------------------------------------------------------
1 | '
16 | .$element->getEscapedValue()
17 | .'';
18 | }
19 | }
--------------------------------------------------------------------------------
/Block/Copyright.php:
--------------------------------------------------------------------------------
1 | urlBuilder = $urlBuilder;
20 | parent::__construct(
21 | $context,
22 | $eavAttribute,
23 | $layerAttribute,
24 | $swatchHelper,
25 | $mediaHelper,
26 | $data
27 | );
28 | }
29 | public function buildUrl($attributeCode, $optionId){
30 | if(in_array($optionId, $this->urlBuilder->getValuesFromUrl($attributeCode))){
31 | return $this->urlBuilder->getRemoveFilterUrl($attributeCode, $optionId);
32 | }
33 | else{
34 | return $this->urlBuilder->getFilterUrl($attributeCode, $optionId);
35 | }
36 | }
37 | }
--------------------------------------------------------------------------------
/Controller/Index/Index.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
18 | parent::__construct($context);
19 | }
20 | public function execute() {
21 | $resultPage = $this->resultPageFactory->create();
22 | $resultPage->getConfig()->getTitle()->set(__('Slava Yurthev Copyright'));
23 | $layout = $resultPage->getLayout();
24 | $layout->addBlock(
25 | 'SY\MultipleLayeredNavigation\Block\Copyright',
26 | 'sy_copyright',
27 | 'content'
28 | );
29 | $this->_eventManager->dispatch('sy_copyright', ['layout' => $layout]);
30 | return $resultPage;
31 | }
32 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Slava Yurthev
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Model/Layer/Filter/Attribute.php:
--------------------------------------------------------------------------------
1 | tagFilter = $tagFilter;
35 | $this->urlBuilder = $urlBuilder;
36 | $this->request = $request;
37 | $this->storeManager = $storeManager;
38 | $this->collectionProvider = $collectionProvider;
39 | }
40 | public function apply(\Magento\Framework\App\RequestInterface $request){
41 | $values = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
42 | if (!$values){
43 | return $this;
44 | }
45 | $productCollection = $this->getLayer()->getProductCollection();
46 | $this->applyToCollection($productCollection);
47 | foreach ($values as $value){
48 | $label = $this->getOptionText($value);
49 | $this->getLayer()->getState()->addFilter($this->_createItem($label, $value));
50 | }
51 | return $this;
52 | }
53 | public function applyToCollection($collection){
54 | $attribute = $this->getAttributeModel();
55 | $attributeValue = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
56 | if (empty($attributeValue)){
57 | return $this;
58 | }
59 | $collection->addFieldToFilter($attribute->getAttributeCode(), array('in' => $attributeValue));
60 | }
61 | protected function _getItemsData(){
62 | $values = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
63 | $productCollection = $this->getLayer()->getProductCollection();
64 | $collection = $this->collectionProvider->getCollection($this->getCurrentCategory());
65 | $collection->updateSearchCriteriaBuilder();
66 | $this->getLayer()->prepareProductCollection($collection);
67 | foreach ($productCollection->getAddedFilters() as $field => $condition) {
68 | if ($this->getAttributeModel()->getAttributeCode() == $field) {
69 | continue;
70 | }
71 | $collection->addFieldToFilter($field, $condition);
72 | }
73 | $attribute = $this->getAttributeModel();
74 | $optionsFacetedData = $this->getFacetedData();
75 | $options = $attribute->getFrontend()->getSelectOptions();
76 | foreach ($options as $option) {
77 | if(empty($option['value'])) {
78 | continue;
79 | }
80 | if(isset($optionsFacetedData[$option['value']])){
81 | $count = $this->getOptionItemsCount($optionsFacetedData, $option['value']);
82 | $this->itemDataBuilder->addItemData(
83 | $this->tagFilter->filter($option['label']),
84 | $option['value'],
85 | $count
86 | );
87 | }
88 | }
89 | return $this->itemDataBuilder->build();
90 | }
91 | private function getOptionItemsCount($faceted, $key){
92 | if(isset($faceted[$key]['count'])){
93 | return $faceted[$key]['count'];
94 | }
95 | return 0;
96 | }
97 | private function getFacetedData(){
98 | $collection = $this->collectionProvider->getCollection($this->getCurrentCategory());
99 | $collection->updateSearchCriteriaBuilder();
100 | $collection->addCategoryFilter($this->getCurrentCategory());
101 | if($this->getCurrentCategory()->getId() == $this->storeManager->getStore()->getRootCategoryId()){
102 | $collection->addSearchFilter($this->request->getParam('q'));
103 | }
104 | return $collection->getFacetedData($this->getAttributeModel()->getAttributeCode());
105 | }
106 | private function getCurrentCategory(){
107 | return $this->getLayer()->getCurrentCategory();
108 | }
109 | }
--------------------------------------------------------------------------------
/Model/Layer/Filter/Category.php:
--------------------------------------------------------------------------------
1 | escaper = $escaper;
36 | $this->dataProvider = $categoryDataProviderFactory->create(['layer' => $this->getLayer()]);
37 | $this->urlBuilder = $urlBuilder;
38 | $this->collectionProvider = $collectionProvider;
39 | }
40 | public function apply(\Magento\Framework\App\RequestInterface $request){
41 | $values = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
42 | if (!$values) {
43 | return $this;
44 | }
45 | $productCollection = $this->getLayer()->getProductCollection();
46 | $this->applyToCollection($productCollection);
47 | $categoryCollection = ObjectManager::getInstance()->create(
48 | \Magento\Catalog\Model\ResourceModel\Category\Collection::class
49 | );
50 | $categoryCollection->addAttributeToFilter('entity_id', ['in' => $values])->addAttributeToSelect('name');
51 | $categoryItems = $categoryCollection->getItems();
52 | foreach ($values as $value) {
53 | if (isset($categoryItems[$value])) {
54 | $category = $categoryItems[$value];
55 | $label = $category->getName();
56 | $this->getLayer()
57 | ->getState()
58 | ->addFilter($this->_createItem($label, $value));
59 | }
60 | }
61 | return $this;
62 | }
63 | protected function _getItemsData(){
64 | $values = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
65 | $productCollection = $this->getLayer()->getProductCollection();
66 | $collection = $this->collectionProvider->getCollection($this->getLayer()->getCurrentCategory());
67 | $collection->updateSearchCriteriaBuilder();
68 | $this->getLayer()->prepareProductCollection($collection);
69 | foreach ($productCollection->getAddedFilters() as $field => $condition) {
70 | if ($field === 'category_ids') {
71 | $collection->addFieldToFilter($field, $this->getLayer()->getCurrentCategory()->getId());
72 | continue;
73 | }
74 | $collection->addFieldToFilter($field, $condition);
75 | }
76 | $optionsFacetedData = $collection->getFacetedData('category');
77 | $category = $this->dataProvider->getCategory();
78 | $categories = $category->getChildrenCategories();
79 | if ($category->getIsActive()) {
80 | foreach ($categories as $category) {
81 | if ($category->getIsActive()) {
82 | if(isset($optionsFacetedData[$category->getId()])){
83 | $count = $this->getOptionItemsCount($optionsFacetedData, $category->getId());
84 | $this->itemDataBuilder->addItemData(
85 | $this->escaper->escapeHtml($category->getName()),
86 | $category->getId(),
87 | $count
88 | );
89 | }
90 | }
91 | }
92 | }
93 | return $this->itemDataBuilder->build();
94 | }
95 | public function applyToCollection($collection){
96 | $values = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
97 | if (empty($values)) {
98 | return $this;
99 | }
100 | $collection->addCategoriesFilter(['in' => $values]);
101 | return $this;
102 | }
103 | private function getOptionItemsCount($faceted, $key){
104 | if(isset($faceted[$key]['count'])){
105 | return $faceted[$key]['count'];
106 | }
107 | return 0;
108 | }
109 | }
--------------------------------------------------------------------------------
/Model/Layer/Filter/Decimal.php:
--------------------------------------------------------------------------------
1 | _url->getRemoveFilterUrl(
13 | $this->getFilter()->getRequestVar(),
14 | $this->getValue(),
15 | [$this->_htmlPagerBlock->getPageVarName() => null]
16 | );
17 | }
18 | public function getUrl(){
19 | return $this->_url->getFilterUrl(
20 | $this->getFilter()->getRequestVar(),
21 | $this->getValue(),
22 | [$this->_htmlPagerBlock->getPageVarName() => null],
23 | false
24 | );
25 | }
26 | public function isActive(){
27 | $values = ObjectManager::getInstance()->create(
28 | \SY\MultipleLayeredNavigation\Model\Url\Builder::class
29 | )
30 | ->getValuesFromUrl($this->getFilter()->getRequestVar());
31 | if(!empty($values)){
32 | return in_array($this->getValue(), $values);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Model/Layer/Filter/Price.php:
--------------------------------------------------------------------------------
1 | dataProvider = $dataProviderFactory->create(['layer' => $this->getLayer()]);
45 | $this->urlBuilder = $urlBuilder;
46 | $this->collectionProvider = $collectionProvider;
47 | $this->priceCurrency = $priceCurrency;
48 | }
49 | public function apply(\Magento\Framework\App\RequestInterface $request){
50 | $this->applyToCollection($this->getLayer()->getProductCollection(), true);
51 | return $this;
52 | }
53 | public function applyToCollection($collection, $addFilter = false){
54 | $values = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
55 | if (!$values){
56 | return $this;
57 | }
58 | if($addFilter) {
59 | foreach ($values as $value) {
60 | list($from, $to) = explode("-", $value);
61 | $label = $this->_renderRangeLabel($from, $to);
62 | $this->getLayer()->getState()->addFilter($this->_createItem($label, $value));
63 | }
64 | }
65 | $collection->addFieldToFilter(
66 | 'price',
67 | [
68 | 'from' => $this->getMin(),
69 | 'to' => $this->getMax()
70 | ]
71 | );
72 | return $this;
73 | }
74 | public function getMax(){
75 | return $this->getCollectionWithoutFilter()->getMaxPrice();
76 | }
77 | public function getMin(){
78 | return $this->getCollectionWithoutFilter()->getMinPrice();
79 | }
80 | protected function getTo($from){
81 | $to = '';
82 | $interval = $this->dataProvider->getInterval();
83 | if ($interval && is_numeric($interval[1]) && $interval[1] > $from) {
84 | $to = $interval[1];
85 | }
86 | return $to;
87 | }
88 | protected function getFrom($from){
89 | $to = '';
90 | $interval = $this->dataProvider->getInterval();
91 | if ($interval && is_numeric($interval[0]) && $interval[0] < $from) {
92 | $to = $interval[0];
93 | }
94 | return $to;
95 | }
96 | protected function _getItemsData(){
97 | $values = $this->urlBuilder->getValuesFromUrl($this->_requestVar);
98 | $attribute = $this->getAttributeModel();
99 | $productCollection = $this->getLayer()->getProductCollection();
100 | $facets = $this->getCollectionWithoutFilter()->getFacetedData($attribute->getAttributeCode());
101 | $data = [];
102 | if(!empty($facets)){
103 | $i=0;
104 | foreach ($facets as $key => $aggregation) {
105 | if (strpos($key, '_') === false) {
106 | continue;
107 | }
108 | list($from, $to) = explode('_', $key);
109 | if($from == '*') {
110 | $from = $this->getMin();
111 | }
112 | if($to == '*') {
113 | $to = $this->getMax();
114 | }
115 | $to -= self::PRICE_DELTA;
116 | // Improved price ranges
117 | if($from >= $to){
118 | if($i>0){
119 | if($from >= $data[$i-1]['to']){
120 | $merged = $data[$i-1];
121 | $merged['count'] += $aggregation['count'];
122 | $merged['to'] = $from;
123 | $merged['value'] = $merged['from'].'-'.$merged['to'];
124 | $merged['label'] = $this->_renderRangeLabel($merged['from'], $merged['to']);
125 | $data[$i-1] = $merged;
126 | }
127 | }
128 | continue;
129 | }
130 | $item = [
131 | 'label' => $this->_renderRangeLabel($from, $to),
132 | 'value' => $from.'-'.$to,
133 | 'count' => $aggregation['count'],
134 | 'from' => $from,
135 | 'to' => $to
136 | ];
137 | $data[$i] = $item;
138 | $i++;
139 | }
140 | }
141 | if(count($data) > 1) {
142 | foreach ($data as $item) {
143 | $this->itemDataBuilder->addItemData(
144 | $item['label'],
145 | $item['value'],
146 | $item['count']
147 | );
148 | }
149 | }
150 | return $this->itemDataBuilder->build();
151 | }
152 | protected function _renderRangeLabel($fromPrice, $toPrice){
153 | $fromPrice = empty($fromPrice) ? 0 : $fromPrice * $this->getCurrencyRate();
154 | $toPrice = empty($toPrice) ? $toPrice : $toPrice * $this->getCurrencyRate();
155 | $formattedFromPrice = $this->priceCurrency->format($fromPrice);
156 | if ($toPrice === '') {
157 | return __('%1 and above', $formattedFromPrice);
158 | } elseif ($fromPrice == $toPrice && $this->dataProvider->getOnePriceIntervalValue()) {
159 | return $formattedFromPrice;
160 | } else {
161 | return __('%1 - %2', $formattedFromPrice, $this->priceCurrency->format($toPrice));
162 | }
163 | }
164 | protected function getCollectionWithoutFilter(){
165 | if (!$this->emptyCollection) {
166 | $productCollection = $this->getLayer()->getProductCollection();
167 | $this->emptyCollection = $this->collectionProvider->getCollection(
168 | $this->getLayer()->getCurrentCategory()
169 | );
170 | $this->emptyCollection->updateSearchCriteriaBuilder();
171 | $this->getLayer()->prepareProductCollection($this->emptyCollection);
172 | foreach ($productCollection->getAddedFilters() as $field => $condition) {
173 | if ($this->getAttributeModel()->getAttributeCode() == $field) {
174 | continue;
175 | }
176 | $this->emptyCollection->addFieldToFilter($field, $condition);
177 | }
178 | }
179 | return $this->emptyCollection;
180 | }
181 | }
--------------------------------------------------------------------------------
/Model/Layer/ItemCollectionProvider.php:
--------------------------------------------------------------------------------
1 | storeManager = $storeManager;
17 | $this->collectionFactory = $collectionFactory;
18 | }
19 | public function getCollection(\Magento\Catalog\Model\Category $category){
20 | if ($category->getId() == $this->storeManager->getStore()->getRootCategoryId()) {
21 | $collection = $this->collectionFactory->create(['searchRequestName' => 'quick_search_container']);
22 | } else {
23 | $collection = $this->collectionFactory->create();
24 | $collection->addCategoryFilter($category);
25 | }
26 | return $collection;
27 | }
28 | }
--------------------------------------------------------------------------------
/Model/ResourceModel/Fulltext/Collection.php:
--------------------------------------------------------------------------------
1 | _addedFilters[$field] = $condition;
15 | }
16 | return parent::addFieldToFilter($field, $condition);
17 | }
18 | public function addCategoriesFilter(array $categoriesFilter){
19 | $this->addFieldToFilter('category_ids', $categoriesFilter);
20 | return $this;
21 | }
22 | public function getAddedFilters(){
23 | return $this->_addedFilters;
24 | }
25 | public function updateSearchCriteriaBuilder(){
26 | $searchCriteriaBuilder = ObjectManager::getInstance()
27 | ->create(\Magento\Framework\Api\Search\SearchCriteriaBuilder::class);
28 | $this->setSearchCriteriaBuilder($searchCriteriaBuilder);
29 | return $this;
30 | }
31 | protected function _prepareStatisticsData(){
32 | $this->_renderFilters();
33 | return parent::_prepareStatisticsData();
34 | }
35 | }
--------------------------------------------------------------------------------
/Model/Url/Builder.php:
--------------------------------------------------------------------------------
1 | true, '_use_rewrite' => true, '_query' => $query];
12 | $values = array_unique(
13 | array_merge(
14 | $this->getValuesFromUrl($code),
15 | [$value]
16 | )
17 | );
18 | $params['_query'][$code] = implode(',', $values);
19 | return urldecode($this->getUrl('*/*/*', $params));
20 | }
21 | public function getRemoveFilterUrl($code, $value, $query = []){
22 | $params = ['_current' => true, '_use_rewrite' => true, '_query' => $query, '_escape' => true];
23 | $values = $this->getValuesFromUrl($code);
24 | $key = array_search($value, $values);
25 | unset($values[$key]);
26 | $params['_query'][$code] = $values ? implode(',', $values) : null;
27 | return urldecode($this->getUrl('*/*/*', $params));
28 | }
29 | public function getValuesFromUrl($code){
30 | return array_filter(explode(',', $this->_getRequest()->getParam($code)));
31 | }
32 | }
--------------------------------------------------------------------------------
/Observer/Copyright.php:
--------------------------------------------------------------------------------
1 | getLayout()->addBlock(
11 | 'Magento\Framework\View\Element\Text',
12 | 'sy_copyright_multiple_layered_navigation',
13 | 'sy_copyright'
14 | )->setData(
15 | 'text',
16 | 'Magento 2 Multiple Layered Navigation Extension'
17 | );
18 | return $this;
19 | }
20 | }
--------------------------------------------------------------------------------
/Plugin/Model/Adapter/Aggregation/Checker/Query/CatalogView.php:
--------------------------------------------------------------------------------
1 | categoryRepository = $categoryRepository;
24 | $this->storeManager = $storeManager;
25 | }
26 | public function aroundIsApplicable(
27 | \Magento\CatalogSearch\Model\Adapter\Aggregation\Checker\Query\CatalogView $subject,
28 | \Closure $proceed,
29 | RequestInterface $request
30 | ){
31 | if ($request->getName() === 'catalog_view_container') {
32 | return $this->hasAnchorCategory($request);
33 | }
34 | return $proceed($request);
35 | }
36 | private function hasAnchorCategory(RequestInterface $request){
37 | $queryType = $request->getQuery()->getType();
38 | $result = false;
39 | if ($queryType === QueryInterface::TYPE_BOOL) {
40 | $categories = $this->getCategoriesFromQuery($request->getQuery());
41 | foreach ($categories as $category) {
42 | if ($category && $category->getIsAnchor()) {
43 | $result = true;
44 | break;
45 | }
46 | }
47 | }
48 | return $result;
49 | }
50 | private function getCategoriesFromQuery(QueryInterface $queryExpression){
51 | $categoryIds = $this->getCategoryIdsFromQuery($queryExpression);
52 | $categories = [];
53 | foreach ($categoryIds as $categoryId) {
54 | try {
55 | $categories[] = $this->categoryRepository
56 | ->get($categoryId, $this->storeManager->getStore()->getId());
57 | } catch (NoSuchEntityException $e) {}
58 | }
59 | return $categories;
60 | }
61 | private function getCategoryIdsFromQuery(QueryInterface $queryExpression){
62 | $queryFilterArray = [];
63 | $queryFilterArray[] = $queryExpression->getMust();
64 | $queryFilterArray[] = $queryExpression->getShould();
65 | $categoryIds = [];
66 | foreach ($queryFilterArray as $item) {
67 | if (!empty($item) && isset($item['category'])) {
68 | $queryFilter = $item['category'];
69 | $values = $queryFilter->getReference()->getValue();
70 | if (is_array($values)) {
71 | $categoryIds = array_merge($categoryIds, $values['in']);
72 | } else {
73 | $categoryIds[] = $values;
74 | }
75 | }
76 | }
77 | return $categoryIds;
78 | }
79 | }
--------------------------------------------------------------------------------
/Plugin/Model/Adapter/Mysql/Filter/Preprocessor.php:
--------------------------------------------------------------------------------
1 | urlBuilder = $urlBuilder;
15 | }
16 | public function aroundProcess(
17 | \Magento\CatalogSearch\Model\Adapter\Mysql\Filter\Preprocessor $subject,
18 | \Closure $proceed,
19 | \Magento\Framework\Search\Request\FilterInterface $filter,
20 | $isNegation,
21 | $query
22 | ){
23 | if($filter->getField() === 'price'){
24 | $values = $this->urlBuilder->getValuesFromUrl('price');
25 | if(!empty($values)){
26 | $statements = [];
27 | foreach ($values as $value) {
28 | list($from, $to) = explode("-", $value);
29 | $statement = [
30 | $this->getSqlStringByArray(
31 | [floatval($from)],
32 | 'final_price',
33 | '>='
34 | ),
35 | $this->getSqlStringByArray(
36 | [floatval($to)],
37 | 'final_price',
38 | '<='
39 | )
40 | ];
41 | $statements[] = '('.implode(" AND ", $statement).')';
42 | }
43 | return implode(" OR ", $statements);
44 | }
45 | }
46 | if($filter->getField() === 'category_ids'){
47 | if(is_array($filter->getValue())){
48 | if(isset($filter->getValue()['in'])){
49 | return $this->getSqlStringByArray($filter->getValue()['in']);
50 | }
51 | return $this->getSqlStringByArray($filter->getValue());
52 | }
53 | elseif(is_string($filter->getValue())){
54 | return $this->getSqlStringByArray([$filter->getValue()]);
55 | }
56 | }
57 | return $proceed($filter, $isNegation, $query);
58 | }
59 | private function getSqlStringByArray(
60 | $array = [],
61 | $field = 'category_ids_index.category_id',
62 | $operator = '=',
63 | $rule = 'OR'
64 | ){
65 | $statements = [];
66 | if(!empty($array)){
67 | foreach ($array as $value) {
68 | $statements[] = $field.' '.$operator.' '.$value;
69 | }
70 | }
71 | return implode(' '.$rule.' ', $statements);
72 | }
73 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Multiple Layered Navigation
2 |
3 | Multiple Layered Navigation Extension for Magento 2.x
4 |
5 | [GUIDE](https://github.com/SlavaYurthev/MultipleLayeredNavigation-M2/wiki)
6 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sy/multiple-layered-navigation",
3 | "description": "N/A",
4 | "license": "MIT",
5 | "type": "magento2-module",
6 | "version": "0.3.1",
7 | "minimum-stability": "dev",
8 | "require": {
9 | "php": "~5.6.0|7.0.2|7.0.4|~7.0.6|~7.1.0"
10 | },
11 | "authors": [
12 | {
13 | "name": "Slava Yurthev",
14 | "email": "slavik-iii@ukr.net",
15 | "homepage": "https://github.com/SlavaYurthev/",
16 | "role": "Developer"
17 | }
18 | ],
19 | "autoload": {
20 | "files": [ "registration.php" ],
21 | "psr-4": {
22 | "SY\\MultipleLayeredNavigation\\": ""
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/etc/adminhtml/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
30 |
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | separator-top
16 |
17 | slava_yurthev
18 | Magento_Backend::content
19 |
20 |
21 |
22 |
23 | SY\MultipleLayeredNavigation\Block\Adminhtml\System\Config\Form\Field\Logo
24 |
25 |
26 |
27 | SY\MultipleLayeredNavigation\Block\Adminhtml\System\Config\Form\Field\Skype
28 |
29 |
30 |
31 | SY\MultipleLayeredNavigation\Block\Adminhtml\System\Config\Form\Field\Telegram
32 |
33 |
34 |
35 | SY\MultipleLayeredNavigation\Block\Adminhtml\System\Config\Form\Field\Github
36 |
37 |
38 |
39 | SY\MultipleLayeredNavigation\Block\Adminhtml\System\Config\Form\Field\Marketplace
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 | darks_v1rus
14 | darks_virus
15 | SlavaYurthev
16 | Slava Yurthev
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Attribute
14 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Price
15 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Decimal
16 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Category
17 |
18 |
19 |
20 |
21 |
22 |
23 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Attribute
24 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Price
25 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Decimal
26 | - SY\MultipleLayeredNavigation\Model\Layer\Filter\Category
27 |
28 |
29 |
30 |
31 |
32 | SY\MultipleLayeredNavigation\Model\Layer\ItemCollectionProvider
33 |
34 |
35 |
36 |
37 | SY\MultipleLayeredNavigation\Model\Layer\ItemCollectionProvider
38 |
39 |
40 |
41 |
42 | SY\MultipleLayeredNavigation\Model\Url\Builder
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 | SY\MultipleLayeredNavigation\Model\Url\Builder
51 |
52 |
53 |
54 |
55 | SY\MultipleLayeredNavigation\Model\Layer\Filter\Item
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/etc/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/etc/frontend/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/guidelines.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SlavaYurthev/MultipleLayeredNavigation-M2/6e573c932149754742eb792744da83156c92022d/guidelines.pdf
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 | SY_MultipleLayeredNavigation::layer/filter.phtml
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/view/frontend/layout/catalogsearch_result_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 | SY_MultipleLayeredNavigation::layer/filter.phtml
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/view/frontend/layout/default.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/view/frontend/layout/slavayurthev_index_index.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/view/frontend/templates/copyright.phtml:
--------------------------------------------------------------------------------
1 |
2 |
3 | getChildNames() as $alias): ?>
4 | -
5 | getChildBlock($alias)->toHtml(); ?>
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/view/frontend/templates/copyright/link.phtml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/view/frontend/templates/layer/filter.phtml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 | -
11 | getCount() > 0): ?>
12 |
13 | getLabel(); ?>
14 | helper('\Magento\Catalog\Helper\Data')->shouldDisplayProductCountOnLayer()): ?>
15 | getCount() ?>getCount() == 1):?>
16 |
17 |
18 |
19 | getLabel(); ?>
20 | helper('\Magento\Catalog\Helper\Data')->shouldDisplayProductCountOnLayer()): ?>
21 | getCount() ?>getCount() == 1):?>
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/view/frontend/web/css/styles.css:
--------------------------------------------------------------------------------
1 | ol.sy-multiple-layered-navigation-items li a {
2 | display: inline-block;
3 | width: 100%;
4 | padding-left: 24px;
5 | margin-left: 0;
6 | margin-right: 0;
7 | min-height: 18px;
8 | box-sizing: border-box;
9 | background-image: url(../img/unchecked.png);
10 | background-repeat: no-repeat;
11 | background-position: left center;
12 | background-color: transparent !important;
13 | }
14 | ol.sy-multiple-layered-navigation-items li.active a {
15 | background-image: url(../img/checked.png);
16 | }
--------------------------------------------------------------------------------
/view/frontend/web/img/checked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SlavaYurthev/MultipleLayeredNavigation-M2/6e573c932149754742eb792744da83156c92022d/view/frontend/web/img/checked.png
--------------------------------------------------------------------------------
/view/frontend/web/img/unchecked.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SlavaYurthev/MultipleLayeredNavigation-M2/6e573c932149754742eb792744da83156c92022d/view/frontend/web/img/unchecked.png
--------------------------------------------------------------------------------