0

My issue is quite simple to resume :

I have 2 products attribute. One of them is already appearing in my filter front panel. The other is not.

I have almost the same configuration for both of them. What's tilting me is that I think the configuration is kind of ignored (indeed with that configuration I don't think neither of these attributes should be added to the filter panel) but one is.

As you can see here is what I have under Product Attributes

product attributes

The first one is already appearing in filter, but not the second one.

front filter

Inside their configuration everything is the same

So my issue is : Why the second one isn't appearing (I have enought data to make it appear, so it's not because I don't have any products with that attributes). Is there some place in the code where I can check what is going on ?

First attributes properties (the second one is the exact same except he has system values).

properties part 1

properties part 2

properties storefront

Attributes creation :

$eavSetup = $this->eavSetupFactory->create(['setup' => $setup]);  

$eavSetup->addAttribute(
        \Magento\Catalog\Model\Product::ENTITY, 'longueur_tasse_vertuo', [
            'type'  => 'text',
            'backend' => 'Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend',
            'frontend' => '',
            'label' => 'Longueur de tasse Vertuo',
            'input' => 'multiselect',
            'class' => '',
            'source' => 'Cpy\Catalog\Model\Config\Product\CupSizeVertuooption',
            'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE,
            'visible' => true,
            'required' => false,
            'group' => '',
            'sort_order' => 203,
            'searchable' => false,
            'filterable' => true,
            'comparable' => false,
            'used_in_product_listing' => true,
            'visible_on_front' => true
        ]
    );

The sources file defines (which are the default system values.

public function getAllOptions()
{
    $this->_options = [];
    $this->_options[] = ['label' => 'Espresso', 'value' => '1'];
    $this->_options[] = ['label' => 'Double Espresso', 'value' => '2'];
    $this->_options[] = ['label' => 'Gran Lungo', 'value' => '3'];
    $this->_options[] = ['label' => 'Mug', 'value' => '4'];
    $this->_options[] = ['label' => 'Alto', 'value' => '5'];

    return $this->_options;
}

I can't find any setup for the first one that is already appearing.

Also if It can help I have this in a 'product_cofee.xml' layout

<block class="Magento\Catalog\Block\Product\View\Description" name="product.info.cafe.cupsize" template="Magento_Catalog::product/view/cafe/cup-size.phtml" before="product.info.price" >
    <arguments>
        <argument name="at_call" xsi:type="string">getLongueurTasse</argument>
        <argument name="at_code" xsi:type="string">longueur_tasse</argument>
        <argument name="at_type" xsi:type="string">text</argument>
        <argument name="css_class" xsi:type="string">product-nespresso-cupsize</argument>
        <argument name="at_label" xsi:type="string">Taille des tasses :</argument>
        <argument name="add_attribute" xsi:type="string">itemprop="nespresso-cupsize"</argument>
    </arguments>
</block>

<block class="Magento\Catalog\Block\Product\View\Description" name="product.info.cafe.cupsize.vertuo" template="Magento_Catalog::product/view/cafe/vertuo/cup-size.phtml" before="product.info.price" >
    <arguments>
        <argument name="at_call" xsi:type="string">getLongueurTasseVertuo</argument>
        <argument name="at_code" xsi:type="string">longueur_tasse_vertuo</argument>
        <argument name="css_class" xsi:type="string">product-nespresso-cupsize-vertuo</argument>
        <argument name="at_label" xsi:type="string">Taille des tasses :</argument>
        <argument name="add_attribute" xsi:type="string">itemprop="nespresso-cupsize"</argument>
    </arguments>
</block>

#EDIT

My query

2020-07-24T08:37:17+00:00 INFO (6): SELECT `main_table`.`entity_type_id`, `main_table`.`attribute_code`, `main_table`.`attribute_model`, `main_table`.`backend_model`, `main_table`.`backend_type`, `main_table`.`backend_table`, `main_table`.`frontend_model`, `main_table`.`frontend_input`, `main_table`.`frontend_label`, `main_table`.`frontend_class`, `main_table`.`source_model`, `main_table`.`is_required`, `main_table`.`is_user_defined`, `main_table`.`default_value`, `main_table`.`is_unique`, `main_table`.`note`, `additional_table`.*, IFNULL(al.value, main_table.frontend_label) AS `store_label` FROM `eav_attribute` AS `main_table`
 INNER JOIN `catalog_eav_attribute` AS `additional_table` ON additional_table.attribute_id = main_table.attribute_id
 LEFT JOIN `eav_attribute_label` AS `al` ON al.attribute_id = main_table.attribute_id AND al.store_id = 7 WHERE (main_table.entity_type_id = 4) AND (`additional_table`.`is_filterable` > 0) ORDER BY position ASC

#EDIT Add second request

2020-07-24T13:19:40+00:00 INFO (6): longueur_tasse
2020-07-24T13:19:40+00:00 INFO (6): SELECT `e`.*, `cat_index`.`position` AS `cat_index_position`, `price_index`.`price`, `price_index`.`tax_class_id`, `price_index`.`final_price`, IF(price_index.tier_price IS NOT NULL, LEAST(price_index.min_price, price_index.tier_price), price_index.min_price) AS `minimal_price`, `price_index`.`min_price`, `price_index`.`max_price`, `price_index`.`tier_price`, `stock_status_index`.`is_salable` FROM `catalog_product_entity` AS `e`
 INNER JOIN `catalog_category_product_index_store7` AS `cat_index` ON cat_index.product_id=e.entity_id AND cat_index.store_id=7 AND cat_index.visibility IN(2, 4) AND cat_index.category_id=43
 INNER JOIN `catalog_product_index_price` AS `price_index` ON price_index.entity_id = e.entity_id AND price_index.website_id = '8' AND price_index.customer_group_id = 0
 INNER JOIN `catalog_product_entity` AS `product` ON product.entity_id = e.entity_id
 INNER JOIN `inventory_stock_8` AS `stock_status_index` ON product.sku = stock_status_index.sku
 INNER JOIN `search_tmp_5f1adfebb39791_19171320` AS `search_result` ON e.entity_id = search_result.entity_id ORDER BY `cat_index`.`position` asc, `e`.`entity_id` DESC, `cat_index`.`position` asc
 LIMIT 10

2020-07-24T13:19:40+00:00 INFO (6): longueur_tasse_vertuo
2020-07-24T13:19:40+00:00 INFO (6): SELECT `e`.*, `cat_index`.`position` AS `cat_index_position`, `price_index`.`price`, `price_index`.`tax_class_id`, `price_index`.`final_price`, IF(price_index.tier_price IS NOT NULL, LEAST(price_index.min_price, price_index.tier_price), price_index.min_price) AS `minimal_price`, `price_index`.`min_price`, `price_index`.`max_price`, `price_index`.`tier_price`, `stock_status_index`.`is_salable` FROM `catalog_product_entity` AS `e`
 INNER JOIN `catalog_category_product_index_store7` AS `cat_index` ON cat_index.product_id=e.entity_id AND cat_index.store_id=7 AND cat_index.visibility IN(2, 4) AND cat_index.category_id=43
 INNER JOIN `catalog_product_index_price` AS `price_index` ON price_index.entity_id = e.entity_id AND price_index.website_id = '8' AND price_index.customer_group_id = 0
 INNER JOIN `catalog_product_entity` AS `product` ON product.entity_id = e.entity_id
 INNER JOIN `inventory_stock_8` AS `stock_status_index` ON product.sku = stock_status_index.sku
 INNER JOIN `search_tmp_5f1adfebb39791_19171320` AS `search_result` ON e.entity_id = search_result.entity_id ORDER BY `cat_index`.`position` asc, `e`.`entity_id` DESC, `cat_index`.`position` asc
 LIMIT 10

EDIT 18/08 :

I've been finding the class responsible for the missing data It's Magento\Framework\Search\Adapter\Mysql\Aggregation\Builder

And here is the method

public function build(
    DataProviderInterface $dataProvider,
    array $dimensions,
    RequestBucketInterface $bucket,
    Table $entityIdsTable
) {
    $metrics = $this->metricsBuilder->build($bucket);

    $select = $dataProvider->getDataSet($bucket, $dimensions, $entityIdsTable);
    $select->columns($metrics);
    $select->group(RequestBucketInterface::FIELD_VALUE);

    if($bucket->getName() === 'longueur_tasse_vertuo_bucket' || $bucket->getName() === 'longueur_tasse_bucket'){
        var_dump($bucket->getName());
        var_dump($dataProvider->execute($select));
    }
    return $dataProvider->execute($select);
}

With longueur_tasse_bucket I'll have the result while with longueur_tasse_vertuo_bucket I won't have anything

  • one is system whilst the other is not.. just to be picky. We don't see their type, is one dropdown and the other now, you might want to add 2 screenshot of the attributes' details – Herve Tribouilloy Jul 23 at 18:38
  • Is it possible to send the setup script that creates them, then I'd be able to imitate this and simulate on my local? – Herve Tribouilloy Jul 24 at 7:31
  • @HerveTribouilloy I've been adding as much info as I can found about these two attributes. Hope it can help. – Claims Jul 24 at 7:45
  • the temp table is there because you use the search, I was under the impression we do want category layer? – Herve Tribouilloy Jul 24 at 13:27
  • 1
    magento.stackexchange.com/questions/143420/….. I ma now a bit short in the day to help more, but this do.. if you want more help, look like bounty will come next, no doubt you will receive a lot of feedback as it is quite common subject – Herve Tribouilloy Jul 24 at 13:48
2

The main issue belongs to the class vendor/magento/module-catalog/Model/ResourceModel/Product/Indexer/Eav/Source.php

The method

protected function _getIndexableAttributes($multiSelect)
{
    $select = $this->getConnection()->select()->from(
        ['ca' => $this->getTable('catalog_eav_attribute')],
        'attribute_id'
    )->join(
        ['ea' => $this->getTable('eav_attribute')],
        'ca.attribute_id = ea.attribute_id',
        []
    )->where(
        $this->_getIndexableAttributesCondition()
    );

    if ($multiSelect == true) {
        $select->where('ea.backend_type = ?', 'varchar')->where('ea.frontend_input = ?', 'multiselect');
    } else {
        $select->where('ea.backend_type = ?', 'int')->where('ea.frontend_input IN( ? )', ['select', 'boolean']);
    }
    return $this->getConnection()->fetchCol($select);
}

For multiselect, the required type was varchar while my attribute had a type text.

So all we have to do is to change the attribute type to varchar and then play the indexer once again to get the association geing written in the table catalog_product_index_eav making it possible to be appearing in the filter.

This is for the quick and immediate fix. In the same time, I send the issue to magento to make this multiselect where condition be able to read both text and varchar type, feel free to check it : https://github.com/magento/magento2/issues/29676

| improve this answer | |
  • good stamina @Claims, you've deserved a thumb up. – Herve Tribouilloy Aug 19 at 19:48
1

It does seem the one that is product attribute that is system does not want to be in the layer.

I will look into it now. Having said that, one would think it might be worth creating a new product attribute identical to the no system one and then 'do assign your data to the new attribute and refresh index..'

that should be a quick win, if you want to do this and you miss a script to update the attribute, I surely can provide you with this script

| improve this answer | |
  • Sadly the system attributes is already appearing in too much code to make such a change at this moment, but indeed it would do the trick I guess. Still I want to find a way to get the system attribute to be added to the layout. – Claims Jul 24 at 8:01
  • np, let's give it a go as it is – Herve Tribouilloy Jul 24 at 8:02
  • I've been investigating a little more. Looks like in my LayerredNavigation view template I have this condition if($filter->getItemsCount()) and for the specific attribute items count return 0 (while it shouldn't) may be there is an issue on the setup script which do not add the corresponding items. – Claims Jul 24 at 9:59
1

You need to put some log at the function \Magento\Catalog\Model\Layer\Category\FilterableAttributeList::getList

this is temporary and therefore can be in the vendor folder directly.

The log we want to use is to know what query runs when the layer filters are pulled in the block \Magento\LayeredNavigation\Block\Navigation

put the lines below just above the line $collection->load();

$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layerdebug.log');
$logger = new \Zend\Log\Logger();
$logger->addWriter($writer);
$logger->info($collection->getSelect()->__toString());

My query on my system is:

SELECT `main_table`.`entity_type_id`, `main_table`.`attribute_code`, `main_table`.`attribute_model`, `main_table`.`backend_model`, `main_table`.`backend_type`, `main_table`.`backend_table`, `main_table`.`frontend_model`, `main_table`.`frontend_input`, `main_table`.`frontend_label`, `main_table`.`frontend_class`, `main_table`.`source_model`, `main_table`.`is_required`, `main_table`.`is_user_defined`, `main_table`.`default_value`, `main_table`.`is_unique`, `main_table`.`note`, `additional_table`.*, IFNULL(al.value, main_table.frontend_label) AS `store_label` FROM `eav_attribute` AS `main_table`
 INNER JOIN `catalog_eav_attribute` AS `additional_table` ON additional_table.attribute_id = main_table.attribute_id
 LEFT JOIN `eav_attribute_label` AS `al` ON al.attribute_id = main_table.attribute_id AND al.store_id = 1 WHERE (main_table.entity_type_id = 4) AND (`additional_table`.`is_filterable` > 0)

Once we will know your query, it is likely we will understand why your first system product attribute is not with us.

Step 2: if the above returns the attribute, at this point we want to check if the attributes has some options to render:

same process as above can apply to troubleshoot, you may go to the function \Magento\CatalogSearch\Model\Layer\Filter\Attribute::_getItemsData

and put the log just above this line

$isAttributeFilterable =
            $this->getAttributeIsFilterable($attribute) === static::ATTRIBUTE_OPTIONS_ONLY_WITH_RESULTS;



$writer = new \Zend\Log\Writer\Stream(BP . '/var/log/layerdebug.log');
    $logger = new \Zend\Log\Logger();
    $logger->addWriter($writer);
    $logger->info($productCollection->getSelect()->__toString());

then at this point, everything should come together. Of course, the query may be big but essentially, you are within the bone of the feature.. and then there is nothing deeper.. so we better have to find from here

| improve this answer | |
  • I've been adding my query at the end of the issue. Looks like the query is the same as your except I am on a different store – Claims Jul 24 at 8:41
  • can't see any mention of backend_type anywhere in your question? – Herve Tribouilloy Jul 24 at 10:55
  • 1
    just updated my answer. Do think of removing your comments once we are done with this as otherwise it wastes time of people who review stackexchange content – Herve Tribouilloy Jul 24 at 13:10
  • Issue updated with the request from both attributes, but the table is I think some kind of temp view wich no longer exists outside the code execution. So I can't really check by myself what this is returning. – Claims Jul 24 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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