Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Category Attribute > Use in Search popup and Search Result #3427

Open
mahesh-makwana-web-vision opened this issue Oct 28, 2024 · 13 comments
Assignees
Labels

Comments

@mahesh-makwana-web-vision
Copy link

mahesh-makwana-web-vision commented Oct 28, 2024

Is there a way to use custom category attributes in the search popup and search page, similar to how they are used for products?

Screenshot 2024-10-28 at 16 28 57

I found this file, but I'm not sure how to modify it to include a custom attribute.

Path: Smile\ElasticsuiteCatalog\Model\ResourceModel\Category\Indexer\Fulltext\Action\Full

Can you please help me make categories searchable by their custom attribute?

The custom attribute is of the text datatype.

cc: @romainruaud @vahonc

Thanks.

@romainruaud
Copy link
Collaborator

Hi @mahesh-makwana-web-vision : the Search Result page is designed to display only products, so you'll not be able to get categories here easily.

But on the autocompletion box, you can easily have category results if you create your category attribute with "is_searchable=1" in your setup script.

This will tell the search engine to index it and to use it when building search results.

Regards

@mahesh-makwana-web-vision
Copy link
Author

Hello @romainruaud

So, basically, I need to create a new custom category attribute with the value "is_searchable=1," and that's it.

No other file changes are required, right?

Am I correct, or are there any additional steps needed?

Thanks

@romainruaud
Copy link
Collaborator

Yep, that's it. And after that, you run a full reindex of the "Elasticsuite Categories fulltext" indexer.

Regards

@mahesh-makwana-web-vision
Copy link
Author

Let me check and update you.

@mahesh-makwana-web-vision
Copy link
Author

Yes @romainruaud, The search works when a category custom attribute with "is_searchable=1" is added.

Now, we have a requirement: when typing a product name, we want the category containing that product to appear in the search results. Currently, only the product is showing, but not the associated category.

Is there a way to achieve this?

We planned to use a custom attribute to store all product names in a single field and make it searchable. However, this approach may create issues with synchronization when products are added or updated, as the product names would need to be kept in sync.

Do you have any suggestions for a more efficient solution?

cc: @vahonc

Thanks.

@mahesh-makwana-web-vision mahesh-makwana-web-vision changed the title Custom Category Attribute > Use in Search popup result Custom Category Attribute > Use in Search popup and Search Result Oct 29, 2024
@mahesh-makwana-web-vision
Copy link
Author

Hello @romainruaud

We created an indexer and stored the product name and SKU in that field. After reindexing, the related categories are not showing in the search results.

Can you please help us?

Thanks.

@romainruaud
Copy link
Collaborator

HI @mahesh-makwana-web-vision we do not provide support for custom development here.

Best regards

@mahesh-makwana-web-vision
Copy link
Author

mahesh-makwana-web-vision commented Oct 30, 2024

Hello @romainruaud and @vahonc

Below is the code for our custom attribute:

<?php
namespace VendoreName\SearchUpdate\Setup\Patch\Data;

use Magento\Eav\Setup\EavSetup;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;
use Magento\Framework\Setup\Patch\PatchRevertableInterface;
use Magento\Catalog\Model\Category;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;

/**
 * Class AddCategorySearchAttribute
 *
 */
class AddCategorySearchAttribute implements DataPatchInterface, PatchRevertableInterface
{
    /**
     * @var ModuleDataSetupInterface
     */
    private $moduleDataSetup;
    /**
     * @var EavSetupFactory
     */
    private $eavSetupFactory;

    /**
     * Constructor
     *
     * @param ModuleDataSetupInterface $moduleDataSetup
     * @param EavSetupFactory $eavSetupFactory
     */
    public function __construct(
        ModuleDataSetupInterface $moduleDataSetup,
        EavSetupFactory $eavSetupFactory
    ) {
        $this->moduleDataSetup = $moduleDataSetup;
        $this->eavSetupFactory = $eavSetupFactory;
    }

    /**
     * {@inheritdoc}
     */
    public function apply()
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $eavSetup->addAttribute(
            Category::ENTITY,
            'search_content',
            [
                'group' => 'general',
                'label' => 'Search Content',
                'type' => 'text',
                'input'  => 'textarea',
                'user_defined' => true,
                'is_user_defined' => true,
                'required' => false,
                'sort_order' => 30,
                'global' => ScopedAttributeInterface::SCOPE_STORE,
                'used_in_product_listing' => true,
                'backend' => '',
                'system' => false,
                'searchable' => true,
                'filterable' => true,
                'default' => null,
            ]
        );

        $this->moduleDataSetup->getConnection()->endSetup();
    }

    public function revert()
    {
        $this->moduleDataSetup->getConnection()->startSetup();
        /** @var EavSetup $eavSetup */
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);
        $eavSetup->removeAttribute(\Magento\Catalog\Model\Product::ENTITY, 'search_content');

        $this->moduleDataSetup->getConnection()->endSetup();
    }

    /**
     * {@inheritdoc}
     */
    public function getAliases()
    {
        return [];
    }

    /**
     * {@inheritdoc}
     */
    public static function getDependencies()
    {
        return [
        ];
    }
}

We’ve added the attribute to the Category page using the following form:

<?xml version="1.0" encoding="UTF-8"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
    <fieldset name="custom_content">
        <argument name="data" xsi:type="array">
            <item name="config" xsi:type="array">
                <item name="label" xsi:type="string">Extra Search Content</item>
                <item name="collapsible" xsi:type="boolean">true</item>
                <item name="sortOrder" xsi:type="number">9999</item>
            </item>
        </argument>
        <field name="search_content">
            <argument name="data" xsi:type="array">
                <item name="config" xsi:type="array">
                    <item name="sortOrder" xsi:type="number">100</item>
                    <item name="dataType" xsi:type="string">text</item>
                    <item name="label" xsi:type="string" translate="true">Product SKU + Name</item>
                    <item name="formElement" xsi:type="string">textarea</item>
                    <item name="disabled" xsi:type="boolean">true</item>
                    <item name="cols" xsi:type="number">10</item>
                    <item name="rows" xsi:type="number">5</item>
                </item>
            </argument>
        </field>
    </fieldset>
</form>

OUTPUT Category Page:

MZ-Analysentechnik-GmbH-ID-402-Categories-Inventory-Catalog-Magento-Admin-10-30-2024_08_57_AM

OUTPUT Catalog Search Index:
Screenshot 2024-10-30 at 08 49 57

Database Table Data:
Select-eav_attribute-Adminer-10-30-2024_09_14_AM

Select-catalog_eav_attribute-Adminer-10-30-2024_09_16_AM

Debug Log:

[2024-10-30T08:23:33.995178+00:00] main.INFO: Request Success: {"method":"HEAD","uri":"http://localhost:9200/xtz_de_catalog_product","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.00187} []
[2024-10-30T08:23:33.995583+00:00] main.INFO: curl -XHEAD 'http://localhost:9200/xtz_de_catalog_product?pretty=true' [] []
[2024-10-30T08:23:34.007846+00:00] main.INFO: Request Success: {"method":"POST","uri":"http://localhost:9200/xtz_de_thesaurus/_analyze","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.001145} []
[2024-10-30T08:23:34.008053+00:00] main.INFO: curl -XPOST 'http://localhost:9200/xtz_de_thesaurus/_analyze?pretty=true' -d '{"text":"5020 01802","analyzer":"synonym"}' [] []
[2024-10-30T08:23:34.008735+00:00] main.INFO: Request Success: {"method":"POST","uri":"http://localhost:9200/xtz_de_thesaurus/_analyze","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.000372} []
[2024-10-30T08:23:34.008898+00:00] main.INFO: curl -XPOST 'http://localhost:9200/xtz_de_thesaurus/_analyze?pretty=true' -d '{"text":"5020 01802","analyzer":"expansion"}' [] []
[2024-10-30T08:23:34.074397+00:00] main.INFO: Request Success: {"method":"GET","uri":"http://localhost/","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.000605} []
[2024-10-30T08:23:34.074609+00:00] main.INFO: curl -XGET 'http://localhost/?pretty=true' [] []
[2024-10-30T08:23:34.113484+00:00] main.INFO: Request Success: {"method":"POST","uri":"http://localhost:9200/xtz_de_catalog_product/_search","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.037828} []
[2024-10-30T08:23:34.113798+00:00] main.INFO: curl -XPOST 'http://localhost:9200/xtz_de_catalog_product/_search?pretty=true' -d '{"size":5,"sort":[{"search_query.position":{"order":"ASC","missing":"_last","unmapped_type":"keyword","nested":{"path":"search_query","filter":{"terms":{"search_query.query_id":["17707"],"boost":1}}},"mode":"min"}},{"_score":{"order":"desc"}},{"entity_id":{"order":"desc","missing":"_first","unmapped_type":"keyword"}}],"from":0,"query":{"bool":{"filter":{"bool":{"must":[{"term":{"stock.is_in_stock":{"value":true,"boost":1}}},{"terms":{"visibility":[3,4],"boost":1}},{"bool":{"must_not":[{"nested":{"path":"search_query","score_mode":"none","query":{"bool":{"must":[{"term":{"search_query.query_id":{"value":17707,"boost":1}}},{"term":{"search_query.is_blacklisted":{"value":true,"boost":1}}}],"must_not":[],"should":[],"boost":1}},"boost":1}}],"boost":1}}],"must_not":[],"should":[],"boost":1}},"must":{"bool":{"must":[],"must_not":[],"should":[{"bool":{"filter":{"multi_match":{"query":"5020-01802","fields":["search^1"],"minimum_should_match":"95%","tie_breaker":1,"boost":1,"type":"best_fields"}},"must":{"multi_match":{"query":"5020-01802","fields":["search^1","name.standard^5","sku.reference^10","description.standard^9","short_description.standard^9","option_text_manufacturer.standard^10","option_text_length.standard^8","option_text_inner_diameter.standard^8","option_text_packing_brand.standard^10","search.whitespace^10","name.whitespace^50","sku.whitespace^100","description.whitespace^90","short_description.whitespace^90","option_text_manufacturer.whitespace^100","option_text_length.whitespace^80","option_text_inner_diameter.whitespace^80","option_text_packing_brand.whitespace^100","name.sortable^100","sku.sortable^200","option_text_manufacturer.sortable^200","option_text_length.sortable^160","option_text_bet_surface_area_in_m2g.sortable^20","option_text_endcapping.sortable^20","option_text_carbon_load_in_percent_c.sortable^20"],"minimum_should_match":1,"tie_breaker":1.0,"boost":1,"type":"best_fields"}},"_name":"EXACT","boost":1}}],"minimum_should_match":1,"boost":1}},"boost":1}},"track_total_hits":0}' [] []
[2024-10-30T08:23:34.660982+00:00] main.INFO: Request Success: {"method":"HEAD","uri":"http://localhost:9200/xtz_de_catalog_category","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.000948} []
[2024-10-30T08:23:34.661192+00:00] main.INFO: curl -XHEAD 'http://localhost:9200/xtz_de_catalog_category?pretty=true' [] []
[2024-10-30T08:23:34.662509+00:00] main.INFO: Request Success: {"method":"POST","uri":"http://localhost:9200/xtz_de_thesaurus/_analyze","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.000667} []
[2024-10-30T08:23:34.662688+00:00] main.INFO: curl -XPOST 'http://localhost:9200/xtz_de_thesaurus/_analyze?pretty=true' -d '{"text":"5020 01802","analyzer":"synonym"}' [] []
[2024-10-30T08:23:34.663443+00:00] main.INFO: Request Success: {"method":"POST","uri":"http://localhost:9200/xtz_de_thesaurus/_analyze","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.000395} []
[2024-10-30T08:23:34.663605+00:00] main.INFO: curl -XPOST 'http://localhost:9200/xtz_de_thesaurus/_analyze?pretty=true' -d '{"text":"5020 01802","analyzer":"expansion"}' [] []
[2024-10-30T08:23:34.671286+00:00] main.INFO: Request Success: {"method":"POST","uri":"http://localhost:9200/xtz_de_catalog_category/_search","port":"9200","headers":{"Host":["localhost"],"Content-Type":["application/json"],"Accept":["application/json"],"User-Agent":["opensearch-php/2.3.1 (Linux 4.18.0; PHP 8.2.25)"]},"HTTP code":200,"duration":0.004866} []
[2024-10-30T08:23:34.671471+00:00] main.INFO: curl -XPOST 'http://localhost:9200/xtz_de_catalog_category/_search?pretty=true' -d '{"size":3,"sort":[{"_score":{"order":"desc"}},{"entity_id":{"order":"desc","missing":"_first","unmapped_type":"keyword"}}],"from":0,"query":{"bool":{"filter":{"terms":{"is_displayed_in_autocomplete":[true],"boost":1}},"must":{"bool":{"must":[],"must_not":[],"should":[{"bool":{"filter":{"multi_match":{"query":"5020-01802","fields":["search^1"],"minimum_should_match":"95%","tie_breaker":1,"boost":1,"type":"best_fields"}},"must":{"multi_match":{"query":"5020-01802","fields":["search^1","search.whitespace^10"],"minimum_should_match":1,"tie_breaker":1.0,"boost":1,"type":"best_fields"}},"_name":"EXACT","boost":1}},{"bool":{"filter":{"multi_match":{"query":"5020-01802","fields":["search^1"],"minimum_should_match":"95%","tie_breaker":1,"boost":1,"type":"best_fields"}},"must":{"multi_match":{"query":"5020-01802","fields":["search^1","search.whitespace^10"],"minimum_should_match":1,"tie_breaker":1.0,"boost":1,"type":"best_fields"}},"_name":"EXACT","boost":1}}],"minimum_should_match":1,"boost":1}},"boost":1}},"track_total_hits":100000}' [] []

ISSUE:

The content is visible on the Category page and is indexed, but when we perform a search, the related categories are not appear in the search results.

We are using Magento 2.4.7-p2 with ElasticSuite 2.11.9 on Elasticsearch 8.15.3. We’ve implemented the is_searchable=1 attribute as per your prior confirmation, but we’re still facing issues.

Could you please help us troubleshoot this?

Thank you.

@romainruaud romainruaud self-assigned this Nov 4, 2024
@romainruaud
Copy link
Collaborator

@mahesh-makwana-web-vision if you are willing to display Categories on the search result page, you'll have to implement this yourself :

  • add a Block on top of the search result page
  • this block should create a category collection and apply the search

@mahesh-makwana-web-vision
Copy link
Author

@romainruaud

When we search by SKU or product name, we want the related category to appear in the search results. Currently, if the search string matches, only the category name is displayed.

To address this, I added a custom attribute to the category and stored all product names and SKUs within this attribute. I also set this custom field to is_searchable=1, but the category name still doesn’t appear based on the custom attribute value.

I’ve added the code that was previously shared. Could you please guide me on where I might be going wrong?

Thanks.

@romainruaud
Copy link
Collaborator

Hi, I've explained what you should try to do.

You can take inspiration from this module : https://github.com/Smile-SA/magento2-module-elasticsuite-cms-search

Just replace the frontend part which is fetching "PageCollection" with a "CategoryCollection" and you should be all good.

Best regards

@mahesh-makwana-web-vision
Copy link
Author

Okay @romainruaud

Let me check and update you.

Thanks.

@mahesh-makwana-web-vision
Copy link
Author

Hello @romainruaud

I attempted to change the CMS page collection to a category collection, but it’s not as straightforward as it seems. The module currently functions based on a single table for CMS pages and CMS stores. However, category data comes from different tables, and modifying the Elasticsearch-related files is necessary. This makes the implementation more time-consuming and complex.

If you have any sample code available for implementing category custom attributes, I’d be happy to review it.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants