1

How to add swatch data in Layered navigation aggregations in Graphql? Magento provides swatch data to filters [LayerFilter] but this is DEPRECATED so we use aggregations for the filter.

Below query is working

{
  products(filter: {category_id: {eq: "4"}}) {
    filters {
      name
      filter_items_count
      filter_items{
        label
        value_string
        items_count
        ... on SwatchLayerFilterItemInterface {
            swatch_data {
               type
               value
        }
      }
    }
  }
}
}

For Aggregation filter layered navigation not working(Swatch Data)

{
  products(filter: {category_id: {eq: "4"}}) {
  aggregations {
    attribute_code
    count
    label
    options {
    label
    value
    count
      ...on SwatchLayerFilterItemInterface {
        swatch_data {
          type
          value
        }
      }
    }
  }
  }
} 

Anyone idea about this? Can anyone help me with this?

2 Answers 2

6

I have override aggregations GraphQL API. Below code is working for me

File:-Custom/Module/registration.php

use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(
    ComponentRegistrar::MODULE, 
    'Custom_Module', 
    __DIR__);

File:-Custom/Module/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="Custom_Module" setup_version="1.0.0">
        <sequence>
            <module name="Magento_Store"/>
            <module name="Magento_Catalog"/>
            <module name="Magento_CatalogInventory"/>
        </sequence>
    </module>
</config>

File: Custom/Module/etc/schema.graphqls

interface AggregationOptionInterface {
    swatch_data: SwatchData @doc(description: "Data required to render swatch filter item")
}
type SwatchData {
    type: String @doc(description: "Type of swatch filter item: 1 - text, 2 - image")
    value: String @doc(description: "Value for swatch item (text or image link)")
}

File:-Custom/Module/etc/graphql/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\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilder" type="Custom\Module\DataProvider\Product\LayeredNavigation\DataProviderAggregationPlugin"/>
</config>

File:-Custom/Module/DataProvider/Product/LayeredNavigation/DataProviderAggregationPlugin.php

<?php

namespace Custom\Module\DataProvider\Product\LayeredNavigation;

use Magento\Eav\Model\Config;
use Magento\Framework\Api\Search\AggregationInterface;
use Magento\Swatches\Block\LayeredNavigation\RenderLayered;
use Magento\Swatches\Helper\Data;
use Psr\Log\LoggerInterface;
use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilder;
use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilderInterface;
use Magento\Framework\Exception\LocalizedException;

class DataProviderAggregationPlugin extends LayerBuilder implements LayerBuilderInterface
{

    private $builders;
    protected $_logger;
    protected $eavConfig;
    private $swatchHelper;
    private $renderLayered;

    public function __construct(
        array $builders,
        LoggerInterface $logger,
        Config $eavConfig,
        Data $swatchHelper,
        RenderLayered $renderLayered
    )
    {
        $this->builders = $builders;
        $this->_logger = $logger;
        $this->eavConfig = $eavConfig;
        $this->swatchHelper = $swatchHelper;
        $this->renderLayered = $renderLayered;
    }

    public function build(
        AggregationInterface $aggregation,
        ?int $storeId
    ): array
    {
        $layers = [];
        foreach ($this->builders as $builder) {
            $layers[] = $builder->build($aggregation, $storeId);
        }
        $layers = \array_merge(...$layers);
        foreach ($layers as $key => $value) {
            $attribute = $this->eavConfig->getAttribute('catalog_product', $layers[$key]['attribute_code']);
            if ($this->swatchHelper->isSwatchAttribute($attribute)) {
                for ($i = 0; $i < count($layers[$key]['options']); $i++) {
                    $hashcodeData = $this->swatchHelper->getSwatchesByOptionsId([$layers[$key]['options'][$i]['value']]);
                    $typeName = $this->getswatchType($hashcodeData[$layers[$key]['options'][$i]['value']]['type']);

                    $temp = [
                        'type' => $typeName,
                        'value' => $hashcodeData[$layers[$key]['options'][$i]['value']]['value']
                    ];

                    $layers[$key]['options'][$i]['swatch_data'] = $temp;
                }
            }
        }

        return \array_filter($layers);
    }

    public function getswatchType($valueType)
    {
        switch ($valueType) {
            case 0:
                return 'TextSwatchData';
            case 1:
                return 'ColorSwatchData';
            case 2:
                return 'ImageSwatchData';
            break;
        }
    }
}

GraphQL Request:-

{
  products(filter: {category_id: {eq: "2"}}) {
    aggregations {
      attribute_code
      count
      label
      options {
        label
        value
        count
        swatch_data{
          value
          type
        }
      }
    }
  }
}

GraphQL Response:

{
  "data": {
    "products": {
      "aggregations": [
        {
          "attribute_code": "color",
          "count": 7,
          "label": "Color",
          "options": [
            {
              "label": "Red",
              "value": "5437",
              "count": 5,
              "swatch_data": {
                "value": "#eb0c0c",
                "type": "ColorSwatchData"
              }
            },
            {
              "label": "Blue",
              "value": "5438",
              "count": 3,
              "swatch_data": {
                "value": "#0d4aff",
                "type": "ColorSwatchData"
              }
            }
          ]
        },
        {
          "attribute_code": "texture",
          "count": 6,
          "label": "Texture",
          "options": [
            {
              "label": "model2",
              "value": "5432",
              "count": 5,
              "swatch_data": {
                "value": "/t/1/t1.jpeg",
                "type": "ImageSwatchData"
              }
            },
            {
              "label": "model3",
              "value": "5433",
              "count": 2,
              "swatch_data": {
                "value": "/t/3/t30.jpeg",
                "type": "ImageSwatchData"
              }
            }
          ]
        }
      ]
    }
  }
}
0

Use the below solution you will get the full path of a visual swatch of the image

app/code/Vendor/ModuleName/etc/graphql/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">
    <type name="Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilder">
        <plugin name="data-provider-aggregation-plugin"
                type="Vendor\ModuleName\Plugin\DataProviderAggregationPlugin"
                sortOrder="10"/>
    </type>
</config>

app/code/Vendor/ModuleName/Plugin/DataProviderAggregationPlugin.php

<?php
namespace Vendor\ModuleName\Plugin;

use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilder;
use Magento\CatalogGraphQl\DataProvider\Product\LayeredNavigation\LayerBuilderInterface;
use Magento\Eav\Model\Config;
use Magento\Framework\Api\Search\AggregationInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Swatches\Block\LayeredNavigation\RenderLayered;
use Magento\Swatches\Helper\Data;
use Magento\Swatches\Model\Swatch;
use Psr\Log\LoggerInterface;
use Magento\Swatches\Helper\Media as SwatchesMedia;

class DataProviderAggregationPlugin extends LayerBuilder implements LayerBuilderInterface
{
    /**
     * @var LoggerInterface
     */
    protected LoggerInterface $_logger;

    /**
     * @var Config
     */
    protected Config $eavConfig;

    /**
     * @var array
     */
    private array $builders;

    /**
     * @var Data
     */
    private Data $swatchHelper;

    /**
     * @var RenderLayered
     */
    private RenderLayered $renderLayered;

    /**
     * @var SwatchesMedia
     */
    private SwatchesMedia $swatchMediaHelper;

    /**
     * @param array $builders
     * @param LoggerInterface $logger
     * @param Config $eavConfig
     * @param Data $swatchHelper
     * @param RenderLayered $renderLayered
     * @param SwatchesMedia $swatchMediaHelper
     */
    public function __construct(
        array           $builders,
        LoggerInterface $logger,
        Config          $eavConfig,
        Data            $swatchHelper,
        RenderLayered   $renderLayered,
        SwatchesMedia   $swatchMediaHelper

    ) {
        parent::__construct($builders);
        $this->_logger = $logger;
        $this->eavConfig = $eavConfig;
        $this->swatchHelper = $swatchHelper;
        $this->renderLayered = $renderLayered;
        $this->builders = $builders;
        $this->swatchMediaHelper = $swatchMediaHelper;
    }

    /**
     * @param LayerBuilder $subject
     * @param $result
     * @param AggregationInterface $aggregation
     * @param int|null $storeId
     * @return array
     * @throws LocalizedException
     */
    public function afterBuild(
        LayerBuilder         $subject,
        $result,
        AggregationInterface $aggregation,
        ?int                 $storeId
    ) {
        // Apply your custom logic here
        foreach ($result as $key => $value) {
            $attribute = $this->eavConfig->getAttribute('catalog_product', $result[$key]['attribute_code']);
            if ($this->swatchHelper->isSwatchAttribute($attribute)) {
                for ($i = 0; $i < count($result[$key]['options']); $i++) {
                    $optionId = [$result[$key]['options'][$i]['value']];
                    $hashcodeData = $this->swatchHelper->getSwatchesByOptionsId($optionId);
                    $type = $hashcodeData[$result[$key]['options'][$i]['value']]['type'];
                    $value = $hashcodeData[$result[$key]['options'][$i]['value']]['value'];
                    $typeName = $this->getSwatchType($type);
                    $temp = ['type' => $typeName, 'value' => $value];
                    if ($type == Swatch::SWATCH_TYPE_VISUAL_IMAGE) {
                        $temp = [
                            'type' => $typeName,
                            'value' => $this->swatchMediaHelper->getSwatchAttributeImage(
                                Swatch::SWATCH_THUMBNAIL_NAME,
                                $value
                            )
                        ];
                    }
                    $result[$key]['options'][$i]['swatch_data'] = $temp;
                }
            }
        }
        return \array_filter($result);
    }


    /**
     * @param int $valueType
     * @return string
     * @throws LocalizedException
     */
    public function getSwatchType(int $valueType): string
    {
        return match ($valueType) {
            Swatch::SWATCH_TYPE_TEXTUAL => 'TextSwatchData',
            Swatch::SWATCH_TYPE_VISUAL_COLOR => 'ColorSwatchData',
            Swatch::SWATCH_TYPE_VISUAL_IMAGE => 'ImageSwatchData',
            default => throw new LocalizedException(__('Unsupported swatch type')),
        };
    }
}

app/code/Vendor/ModuleName/etc/schema.graphqls

interface AggregationOptionInterface {
    swatch_data: SwatchData @doc(description: "Data required to render swatch filter item")
}
type SwatchData {
    type: String @doc(description: "Type of swatch filter item: 1 - text, 2 - image")
    value: String @doc(description: "Value for swatch item (text or image link)")
}

Output

{
  "attribute_code": "color",
  "label": "Color",
  "count": 6,
  "options": [
    {
      "count": 1,
      "label": "Red",
      "value": "58",
      "swatch_data": {
        "value": "#ff0000",
        "type": "ColorSwatchData"
      }
    },
    {
      "count": 1,
      "label": "Shirt",
      "value": "219",
      "swatch_data": {
        "value": "https://test.com/media/attribute/swatch/swatch_thumb/110x90/m/b/Shirt.jpg",
        "type": "ImageSwatchData"
      }
    }
  ]
}

Your Answer

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

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