10

I have someone issue in api magento 2. I need get layer navigation data available in product collection ( current category , search product ) but I don't know magento 2 api available it or not . I have create new custom api using Magento\Catalog\Model\Layer\Resolver but it not work . Any one can help me ?

i need get this data in rest api

thanks guys

1
  • @Nguyen Can we add additional filter in it for example : if someone clicked on a particular brand then other brand should be remove from layer navigation?
    – Kanika
    Mar 5, 2020 at 13:27

3 Answers 3

16

There are 2 methods to achieve this

First one

Filter.php (api model)

    public function __construct(\Magento\Framework\Webapi\Rest\Request 
        $request){
            
                $this->_request         = $request;
        }


/**
     * Retrieve filterlist
     *
     * @api
     * @return array
     */
    public function retrieve(){     

        $category = $this->_request->getParam('categoryId');

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();

        $filterableAttributes = $objectManager->getInstance()->get(\Magento\Catalog\Model\Layer\Category\FilterableAttributeList::class);

        $appState = $objectManager->getInstance()->get(\Magento\Framework\App\State::class);
        $layerResolver = $objectManager->getInstance()->get(\Magento\Catalog\Model\Layer\Resolver::class);
        $filterList = $objectManager->getInstance()->create(
            \Magento\Catalog\Model\Layer\FilterList::class,
                [
                    'filterableAttributes' => $filterableAttributes
                ]
            );      

            $layer = $layerResolver->get();
            $layer->setCurrentCategory($category);
            $filters = $filterList->getFilters($layer);
            $maxPrice = $layer->getProductCollection()->getMaxPrice();
            $minPrice = $layer->getProductCollection()->getMinPrice();  

        $i = 0;
       foreach($filters as $filter)
       {
           //$availablefilter = $filter->getRequestVar(); //Gives the request param name such as 'cat' for Category, 'price' for Price
           $availablefilter = (string)$filter->getName(); //Gives Display Name of the filter such as Category,Price etc.
           $items = $filter->getItems(); //Gives all available filter options in that particular filter
           $filterValues = array();
           $j = 0;
           foreach($items as $item)
           {
               

               $filterValues[$j]['display'] = strip_tags($item->getLabel());
               $filterValues[$j]['value']   = $item->getValue();
               $filterValues[$j]['count']   = $item->getCount(); //Gives no. of products in each filter options
               $j++;
           }
           if(!empty($filterValues) && count($filterValues)>1)
           {
               $filterArray['availablefilter'][$availablefilter] =  $filterValues;
           }
           $i++;
       }  

       
        echo json_encode($filterArray);
        exit;

    }

Sample out put of this code will be:

{
    "availablefilter": {
        "Climate": [
            {
                "display": "All-Weather",
                "value": "202",
                "count": "1"
            },
            {
                "display": "Cool",
                "value": "204",
                "count": "1"
            }
        ],
        "Manufacturer": [
            {
                "display": "Azzedine Alaïa",
                "value": "216",
                "count": "1"
            },
            {
                "display": "Balenciaga",
                "value": "217",
                "count": "1"
            }
        ],
        "Material": [
            {
                "display": "Cotton",
                "value": "33",
                "count": "1"
            },
            {
                "display": "Nylon",
                "value": "37",
                "count": "1"
            }
        ],

Second method

public function __construct(
        \Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory $productAttributeCollectionFactory
    ) {
        $this->productAttributeCollectionFactory = $productAttributeCollectionFactory;
    }
 
    public function getFilterableAttributes()
    {
        /** @var \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection $productAttributes */
        $productAttributes = $this->productAttributeCollectionFactory->create();
        $productAttributes->addFieldToFilter(
            ['is_filterable', 'is_filterable_in_search'],
            [[1, 2], 1]
        );
 
        return $productAttributes;
    }
17
  • 1
    Can you explain the 2nd method? How can it filter product within CategoryId. May 22, 2019 at 5:45
  • 1
    @NamTrung You can get all the filterable attribute list by Magento\Catalog\Model\ResourceModel\Product\Attribute\CollectionFactory class. The result will be all those attributes which have, Use in Layered Navigation status are Filterable (with results) or Filterable (no results). You need to create __construct( ) function for define dependency of Class.
    – NID
    May 22, 2019 at 7:16
  • Now call a function in template file by iterating over a loop to fetch each attribute code, $getAttributes = $block->getFilterableAttributes(); foreach ($getAttributes as $attribute) { echo $attribute->getAttributeCode();echo "<br>"; }
    – NID
    May 22, 2019 at 7:16
  • Result would be something like this: manufacturer color activity style_bags material strap_bags features_bags gender category_gear size eco_collection performance_fabric erin_recommends new sale format style_bottom style_general sleeve collar pattern climate
    – NID
    May 22, 2019 at 7:16
  • 1
    if you are writing a api i would suggest you to go with first method. I have been following frst method for a while and its working. I haven't tried second method with api.
    – NID
    May 22, 2019 at 7:33
3

Unless your email address ends in '@magento.com', you should not be using Object Manager in your code. No ifs, no buts. This is how I went about achieving this:

<?php
namespace Vendor\Module\Model;

use Magento\Catalog\Model\Layer\Category\FilterableAttributeList;
use Magento\Catalog\Model\Layer\FilterListFactory;
use Magento\Catalog\Model\Layer\Resolver as layerResolver;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Catalog\Model\Product\Visibility;

class YourClass
{
    /**
     * @var \Magento\Catalog\Model\Layer\Category\FilterableAttributeList
     */
    protected $filterableAttributes;
    /**
     * @var \Magento\Catalog\Model\Layer\Resolver
     */
    protected $layerResolver;
    /**
     * @var \Magento\Catalog\Model\Layer\FilterListFactory
     */
    protected $filterListFactory;

    /**
     * Your constructor.
     * @param \Magento\Catalog\Model\Layer\Category\FilterableAttributeList $filterableAttributes
     * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver
     * @param FilterListFactory $filterListFactory
     */
    public function __construct(
        FilterableAttributeList $filterableAttributes,
        layerResolver $layerResolver,
        FilterListFactory $filterListFactory
    ) {
        $this->filterableAttributes = $filterableAttributes;
        $this->layerResolver = $layerResolver;
        $this->filterListFactory = $filterListFactory;
    }

    /**
     * Get filters for a category page.
     * @param string $category_id
     * @return array
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getCategoryFilters(string $category_id): array
    {
        $returnFilters = [];
        $filterableAttributes = $this->filterableAttributes;
        $layerResolver = $this->layerResolver;
        $filterList = $this->filterListFactory->create(['filterableAttributes' => $filterableAttributes]);
        $layer = $layerResolver->get();
        $layer->setCurrentCategory($category_id);
        $layer->getProductCollection()
            ->addAttributeToFilter("visibility", ["neq" => Visibility::VISIBILITY_NOT_VISIBLE])
            //optional to exclude product attributes of non visible products
            ->addAttributeToFilter("status", ["eq" => Status::STATUS_ENABLED]);
            //optional to exclude product attributes of disabled products
        foreach ($filterList->getFilters($layer) as $filter) {
            $values = [];
            foreach ($filter->getItems() as $item) {
                $values[] = [
                    "display" => strip_tags($item->getLabel()), //strip_tags is optional, but there's HTML in some of my labels
                    "value" => $item->getValue(),
                    "count" => $item->getCount()
                ];
            }
            if (!empty($values)) {
                $returnFilters[] = [
                    "attr_code" => $filter->getRequestVar(),
                    "attr_label" => $filter->getName(),
                    "values" => $values
                ];
            }
        }
        return $returnFilters;
    }
}
5
  • 1
    Thanks for this amazing answer. Sep 16, 2021 at 17:26
  • 2
    Unless your email address ends in '@magento.com', :D
    – BornCoder
    Oct 6, 2021 at 10:59
  • 1
    This answer is according to Magento standard approach & it's working fine!!! Dec 31, 2021 at 14:59
  • Thanks for this answer, it works fine, but it is also counting the products with visibility hidden, even added the line addAttributeToFilter("visibility", ["neq" => Visibility::VISIBILITY_NOT_VISIBLE]) Please let me know if you have any solution for this issue. Dec 12, 2022 at 7:12
  • If I were you @KishorThummar I'd check the visibility of $item as it's being looped through in the foreach - I'd be surprised if it were Visibility::VISIBILITY_NOT_VISIBLE though
    – John
    Dec 13, 2022 at 12:39
2

Get request value in json format like below

{
        "category_id":"36" //pass category which you want
}

below is the Filterattributes.php (api model)

<?php
    namespace HIT\Customer\Model;
    use HIT\Customer\Api\FilterAttributesInterface;
    use Magento\Framework\Encryption\EncryptorInterface;
    
    class FilterAttributes extends \Magento\Framework\Model\AbstractModel implements FilterAttributesInterface
    {
        
    
    
        public function __construct(
           
        ){
           
        }
    
        /**
         * Returns greeting message to user
         *
         * @api
         * @param string $name Users name.
         * @return string Greeting message with users name.
         */
        public function filterAttributes() {
           
            $json = file_get_contents('php://input');
            $post = json_decode($json);
            
            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
            $category = $objectManager->create('Magento\Catalog\Model\Category')->load($this->_request->getParam($post->category_id));
            $filterableAttributes = $objectManager->getInstance()->get(\Magento\Catalog\Model\Layer\Category\FilterableAttributeList::class);
    
            $appState = $objectManager->getInstance()->get(\Magento\Framework\App\State::class);
            $layerResolver = $objectManager->getInstance()->get(\Magento\Catalog\Model\Layer\Resolver::class);
            $filterList = $objectManager->getInstance()->create(
                \Magento\Catalog\Model\Layer\FilterList::class,
                    [
                        'filterableAttributes' => $filterableAttributes
                    ]
                );      
    
                $layer = $layerResolver->get();
                $layer->setCurrentCategory($category);
                $filters = $filterList->getFilters($layer);
                $maxPrice = $layer->getProductCollection()->getMaxPrice();
                $minPrice = $layer->getProductCollection()->getMinPrice();  
    
            $i = 0;
            $filterAttrs = [];
           foreach($filters as $filter)
           {
                $values = [];
                $attr_code = (string)$filter->getRequestVar();
                $attr_label = (string)$filter->getName();
                $items = $filter->getItems(); //Gives all available filter options in that particular filter
               foreach($items as $item)
               {
    
                    $values[] = array("display"=>strip_tags($item->getLabel()),
                                        "value"=>$item->getValue(),
                                        "count"=>$item->getCount());
               }
               if(!empty($values) && count($values)>1)
               {
                   $filterAttrs[]=array("attr_code"=>$attr_code,
                                    "attr_label"=>$attr_label,
                                    "values"=>$values);
               }
    
           }  
    
    
           if(count($filters)>0){
            $data['status'] = "true";
            $data['filters'] = $filterAttrs;
           }else{
            $data['status'] = "false";
            $data['msg'] = "No Filters Found";
           }
     
       
    
             echo json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT );// str_replace('\/','/',json_encode($data)); 
            exit();
        }
    
    
    
    }
1
  • Can we add additional filter in it for example : if someone clicked on a particular brand then other brand should be remove from layer navigation?
    – Kanika
    Mar 5, 2020 at 13:26

Your Answer

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

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