Magento – How to filter product collection with default graphql products query

attributesfiltergraphqllayered-navigationmagento2

I am using Magento 2 Graphql to get product collection based on category id.

I want to apply filter by color, size, material etc.

I have checked the graphql available filters and those are not mentioned as input.

I am executing below query.

{
    products(
      filter:{category_id: {eq: "23"}, material: {eq: "cotton"}}
      currentPage: 1
      pageSize: 5
    ){
    items{
      name
    }
    total_count
  }
}

I have checked following file.

vendor/magento/module-catalog-graph-ql/etc/schema.graphqls

input ProductFilterInput @doc(description: "ProductFilterInput defines the filters to be used in the search. A filter contains at least one attribute, a comparison operator, and the value that is being searched for.") {
    name: FilterTypeInput @doc(description: "The product name. Customers use this name to identify the product.")
    sku: FilterTypeInput @doc(description: "A number or code assigned to a product to identify the product, options, price, and manufacturer")
    description: FilterTypeInput @doc(description: "Detailed information about the product. The value can include simple HTML tags.")
    short_description: FilterTypeInput @doc(description: "A short description of the product. Its use depends on the theme.")
    price: FilterTypeInput @doc(description: "The price of an item")
    special_price: FilterTypeInput @doc(description: "The discounted price of the product. Do not include the currency code.")
    special_from_date: FilterTypeInput @doc(description: "The beginning date that a product has a special price")
    special_to_date: FilterTypeInput @doc(description: "The end date that a product has a special price")
    weight: FilterTypeInput @doc(description: "The weight of the item, in units defined by the store")
    manufacturer: FilterTypeInput @doc(description: "A number representing the product's manufacturer")
    meta_title: FilterTypeInput @doc(description: "A string that is displayed in the title bar and tab of the browser and in search results lists")
    meta_keyword: FilterTypeInput @doc(description: "A comma-separated list of keywords that are visible only to search engines")
    meta_description: FilterTypeInput @doc(description: "A brief overview of the product for search results listings, maximum 255 characters")
    image: FilterTypeInput @doc(description: "The relative path to the main image on the product page")
    small_image: FilterTypeInput @doc(description: "The relative path to the small image, which is used on catalog pages")
    thumbnail: FilterTypeInput @doc(description: "The relative path to the product's thumbnail image")
    tier_price: FilterTypeInput @doc(description: "The price when tier pricing is in effect and the items purchased threshold has been reached")
    news_from_date: FilterTypeInput @doc(description: "The beginning date for new product listings, and determines if the product is featured as a new product")
    news_to_date: FilterTypeInput @doc(description: "The end date for new product listings")
    custom_layout_update: FilterTypeInput @doc(description: "XML code that is applied as a layout update to the product page")
    min_price: FilterTypeInput @doc(description:"The numeric minimal price of the product. Do not include the currency code.")
    max_price: FilterTypeInput @doc(description:"The numeric maximal price of the product. Do not include the currency code.")
    category_id: FilterTypeInput @doc(description: "Category ID the product belongs to")
    options_container: FilterTypeInput @doc(description: "If the product has multiple options, determines where they appear on the product page")
    required_options: FilterTypeInput @doc(description: "Indicates whether the product has required options")
    has_options: FilterTypeInput @doc(description: "Indicates whether additional attributes have been created for the product")
    image_label: FilterTypeInput @doc(description: "The label assigned to a product image")
    small_image_label: FilterTypeInput @doc(description: "The label assigned to a product's small image")
    thumbnail_label: FilterTypeInput @doc(description: "The label assigned to a product's thumbnail image")
    created_at: FilterTypeInput @doc(description: "Timestamp indicating when the product was created")
    updated_at: FilterTypeInput @doc(description: "Timestamp indicating when the product was updated")
    country_of_manufacture: FilterTypeInput @doc(description: "The product's country of origin")
    custom_layout: FilterTypeInput @doc(description: "The name of a custom layout")
    gift_message_available: FilterTypeInput @doc(description: "Indicates whether a gift message is available")
    or: ProductFilterInput @doc(description: "The keyword required to perform a logical OR comparison")
}

Here i am not able to see color, size, material etc. I added them using a custom extension but still, filtering with them, gives me 0 results.

Anyone having any idea about it ?

Best Answer

I Have done the same in my recent project.For this i created a custom module.

1.Create custom module.

2.Define the attributes in di.xml.

3.Add the attributes to ProductFilterInput.

4.Create the ProductAttributeFilter.php file in the relevant directory as defined in di.xml.

5.Run the graphql query to get the result.

My di.xml file looks like below

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<virtualType name="Magento\Catalog\Model\Api\SearchCriteria\CollectionProcessor\ProductFilterProcessor" type="Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor\FilterProcessor">
    <arguments>
        <argument name="customFilters" xsi:type="array">
            <item name="color" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
            <item name="size" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
            <item name="region" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
            <item name="language" xsi:type="object">
                Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor\ProductAttributeFilter
            </item>
        </argument>
    </arguments>
</virtualType>

Add the attributes to ProductFilterInput

input ProductFilterInput {
category_url_key: FilterTypeInput @doc(description: "Category url_key the product belongs to")
category_url_path: FilterTypeInput @doc(description: "Category url_path the product belongs to")
color: FilterTypeInput @doc(description: "Product color")
size: FilterTypeInput @doc(description: "Product size")
region: FilterTypeInput @doc(description: "Product Region")
language: FilterTypeInput @doc(description: "Product Language")
url_key: FilterTypeInput @doc(description: "Product url")
}

Create the ProductAttributeFilter.php file in the relevant directory as defined in di.xml.

<?php
declare(strict_types=1);
namespace Ayakil\CatalogGraphQl\Model\Resolver\Products\SearchCriteria\CollectionProcessor\FilterProcessor;
use Magento\Catalog\Model\Product\Attribute\Source\Status;
use Magento\Framework\Api\SearchCriteria\CollectionProcessor\FilterProcessor\CustomFilterInterface;
use Magento\Framework\Data\Collection\AbstractDb;
use Magento\Framework\Api\Filter;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable;
use Magento\Framework\Registry;
/**
* Category filter allows to filter products collection using custom defined filters from search criteria.
*/
class ProductAttributeFilter implements CustomFilterInterface
{ 
protected $configurable;
protected $collectionFactory;
protected $registry;

public function __construct(
    Configurable $configurable,
    CollectionFactory $collectionFactory,
    \Psr\Log\LoggerInterface $logger,
    Registry $registry
) {
    $this->registry = $registry;
    $this->configurable = $configurable;
    $this->logger = $logger;
    $this->collectionFactory = $collectionFactory;
}

public function apply(Filter $filter, AbstractDb $collection)
{
    $conditionType = $filter->getConditionType();
    $attributeName = $filter->getField();
    $attributeValue = $filter->getValue();
    $category = $this->registry->registry('current_category');


    if($attributeName == 'language'){
        $conditions = [];
        foreach ($attributeValue as $value){
            $conditions[] = ['attribute'=>$attributeName, 'finset'=>$value];
        }
        $simpleSelect = $this->collectionFactory->create()
                        ->addAttributeToFilter($conditions);

    }else{
        $simpleSelect = $this->collectionFactory->create()
            ->addAttributeToFilter($attributeName, [$conditionType => $attributeValue]);
    }

    $simpleSelect->addAttributeToFilter('status', Status::STATUS_ENABLED);
    if ($category) {
        $simpleSelect->addCategoriesFilter(['in' => (int)$category->getId()]);
    }


    $arr =  $simpleSelect;
    $entity_ids = [];
    foreach ($arr->getData() as $a){
        $entity_ids[] = $a['entity_id'];
    }

    $collection->getSelect()->where($collection->getConnection()->prepareSqlCondition(
        'e.entity_id', ['in' => $entity_ids]
    ));

    return true;
}
}

After this want to pass the added attribute to products graphQl query to get the result. I have written an article How to filter product collection with default graphql products query? Hope this will help you to build up your task.

My query and answer as images enter image description here

enter image description here

You may read more articles about create graphql module in magento 2 by visiting this.

Related Topic