Using Text Attributes as Klevu Facets
The Klevu Indexing functionality respects and uses core Magento settings wherever possible. When defining Klevu attributes from Magento data, we reference the “Use In Layered Navigation” field when setting the Filterable property. Unfortunately, there are types of Magento attributes which cannot be defined for use in layered navigation which are still valid Klevu facets - for example, Text attributes (as Klevu generates its own enumerated index as part of the indexing process)


Where changes to automatically populated Klevu attribute properties is required, we need to extend the core Klevu functionality with a small bespoke module.
These changes can also be incorporated into existing customisation modules, though we recommend keeping customisations separate to allow easier maintenance, debugging, and removal if required.
Building The Extension
This guide assumes you are familiar with creating a Magento 2 extension.
If you work better with code in front of you to reference, there is an example module at the end of the article
IMPORTANT This example module is not production-ready and should not be used. It is for reference and illustration purposes only and no guarantee is made to its reliability.
We strongly recommend testing it in your own environment before deploying it to production.
We will use the module name Vendor_KlevuIndexingAttributeDefinitions; you should choose a namespace (and module name) suited to your installation.
Dependencies
We will reference the Klevu Indexing Products and PHP-SDK packages, so ensure you include the following in the extension’s composer.json file
"require": {
"php": "~8.1.0|~8.2.0|~8.3.0|~8.4.0",
"klevu/module-m2-indexing-products": "^3.0.0",
"klevu/php-sdk": "^1.1.0"
},and the following in the extension’s etc/module.xml file
<sequence>
<module name="Klevu_IndexingProducts"/>
<module name="Klevu_PhpSDK"/>
</sequence>Overriding the Attribute Definition
To implement our changes, we need to modify the Klevu\IndexingProducts\Service\AttributeIndexingRecordCreatorService return; this is the service responsible for converting a Magento EAV Attribute into an object which can be used by the SDK to register attributes in Klevu.
Reference: klevu/module-m2-indexing-products
We’re simply going to take the SDK Attribute and update its properties before it’s used by other parts of the system. As such, we need to add an after plugin on the execute method, using the following di.xml code (while you could add this to the adminhtml area, it’s safest to add it globally to ensure future compatibility)
<type name="Klevu\IndexingProducts\Service\AttributeIndexingRecordCreatorService">
<plugin name="Vendor_KlevuIndexingAttributeDefinitions::IndexingProducts_UpdateAttributeDefinitionPlugin"
type="Vendor\KlevuIndexingAttributeDefinitions\Plugin\IndexingProducts\Service\AttributeIndexingRecordCreatorService\UpdateAttributeDefinitionPlugin"/>
</type>Our plugin will then need an afterExecute method to receive and modify the data; that class' skeleton should look something like
<?php
/**
* This is a demonstration module provided by Klevu with no guarantees, active support, or planned updates
* It should be used as a base to create your own extension implementing the specific functionality
* required for your installation, rather than being directly installed as an out-of-the-box solution
*/
declare(strict_types=1);
namespace Vendor\KlevuIndexingAttributeDefinitions\Plugin\IndexingProducts\Service\AttributeIndexingRecordCreatorService;
use Klevu\IndexingProducts\Service\AttributeIndexingRecordCreatorService;
use Klevu\PhpSDK\Api\Model\Indexing\AttributeInterface as SdkAttributeInterface;
use Magento\Eav\Api\Data\AttributeInterface;
class UpdateAttributeDefinitionPlugin
{
/**
* @param AttributeIndexingRecordCreatorService $subject
* @param SdkAttributeInterface $result
* @param AttributeInterface $attribute
* @param string $apiKey
*
* @return SdkAttributeInterface
*/
public function afterExecute(
AttributeIndexingRecordCreatorService $subject,
SdkAttributeInterface $result,
AttributeInterface $attribute,
string $apiKey, // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
): SdkAttributeInterface {
// Your modifications here
return $result
}
}
Unless you want to change every registered attribute (bad idea), you will need a way of identifying which attribute you are currently dealing with. The easiest and most reliable way is to use the Magento attribute code, available via the $attribute variable; eg
switch ($attribute->getAttributeCode()) {
case 'my_text_attribute':
case 'another_text_attribute':
// changes here
break;
}Alternatively, you can retrieve the attribute code as it will be registered in Klevu (ie, what you see in KMC)
This value is usually the same as the Magento attribute code, however it will differ if mapping has been performed Reference: Klevu\IndexingApi\Service\Mapper\MagentoToKlevuAttributeMapperInterface::get called in AttributeIndexingRecordCreatorService::getAttributeName
switch ($attribute->getAttributeCode()) {
case 'klv_text_attribute':
case 'klv_text_attribute2':
// changes here
break;
}To modify the SDK Attribute’s data (in this case, we will target the filterable property, but you can modify any SDK attribute property supported by the SDK), you need to set the value on $return prior to returning it back to the calling code.
While we should be able to rely on receiving an instance of the SDK Indexing Attribute model, we only stipulate the AttributeInterface which does not mandate setters for properties. As such, we should feature sniff before setting any values Reference: Klevu\PhpSDK\Api\Model\Indexing\AttributeInterface
Example - preferred method
public function afterExecute(
AttributeIndexingRecordCreatorService $subject,
SdkAttributeInterface $result,
AttributeInterface $attribute,
string $apiKey, // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
): SdkAttributeInterface {
switch ($result->getAttributeName()) {
case 'klv_text_attribute':
case 'klv_text_attribute2':
if (method_exists($result, 'setFilterable')) {
// You could log if the method doesn't exist, but that should be
// pretty obvious during development
$result->setFilterable(true);
}
break;
}
return $return;
}If you are dealing with an implementation of the SDK AttributeInterface which does not have setters - including trying to set Attribute Name or Data Type on Klevu\PhpSDK\Model\Indexing\Attribute - you will need to replace $return with a new instance and return that instance.
Example 2 - Alternative implementation, using setters is preferred
use Klevu\PhpSDK\Model\Indexing\Attribute as SdkAttribute;
use Klevu\PhpSDK\Model\Indexing\AttributeFactory as SdkAttributeFactory;
use Klevu\PhpSDK\Model\Indexing\DataType;
class UpdateAttributeDefinitionPlugin
{
private readonly SdkAttributeFactory $attributeFactory;
public function afterExecute(
AttributeIndexingRecordCreatorService $subject,
SdkAttributeInterface $result,
AttributeInterface $attribute,
string $apiKey, // phpcs:ignore SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
): SdkAttributeInterface {
switch ($result->getAttributeName()) {
case 'klv_text_attribute':
case 'klv_text_attribute2':
$result = $this->attributeFactory->create(
data: [
// You can change any of the attributes used to register the attribute
SdkAttribute::FIELD_ATTRIBUTE_NAME => $result->getAttributeName(),
// including the data type
SdkAttribute::FIELD_DATATYPE => DataType::NUMBER,
// and just set any you don't wish to change to the existing value
SdkAttribute::FIELD_LABEL => $result->getLabel(),
SdkAttribute::FIELD_SEARCHABLE => false,
SdkAttribute::FIELD_FILTERABLE => true,
SdkAttribute::FIELD_RETURNABLE => $result->isReturnable(),
SdkAttribute::FIELD_ABBREVIATE => $result->isAbbreviate(),
SdkAttribute::FIELD_RANGEABLE => true,
],
);
break;
}
}
}
And that should be all the required changes, and you can recompile your Magento installation.
At this point, the next time an attribute is modified and the Attribute Discovery process runs, your changes will be applied. You can force this by either changing something in the attribute in the Magento admin, or running an attribute update for all or some attributes via CLI.
For example, to update product attributes with Magento ids 1, 2, and 3 run
/var/www/html$ php bin/magento klevu:indexing:attribute-update --attribute-ids 1,2,3 --attribute-type KLEVU_PRODUCTExample Module
Further Reading
- Klevu Custom Attributes (Indexing APIs)
- Registering Attributes that are not Magento Attributes (Klevu Magento v4)
- Attributes (Klevu Magento v4)
- Add, Update, or Delete Indexing Attributes (Klevu PHP SDK)
- Managing Attributes (Klevu PHP SDK)