2

I am using Magento 2.3.0

I have migrated products from Magento 1 to Magento 2. I can see related products in product detail page in the front end and it is proper and also I can find related products entry in the database as well but when I checked related products in admin I found that there are some related products missing in some of the products

For Ex. When I checked one product in the front end. I saw three related products there as well as in the database but I can find only 2 products in admin there is one product missing in admin.

I checked two tables in database for related products: "catalog_product_link" and "catalog_product_link_attribute_int".

I have found some values in the "value" column in "catalog_product_link_attribute_int" table which represents the position of the related products in admin and in front end but I found value 0 in "value" column of this table for some of the products and when I checked these products I found that only those products which do have only 0 in "value" column in "catalog_product_link_attribute_int" table are missing related products in admin.

So, How can I solve this issue?

Check my below question as well:

How to override product model files in Magento 2?

I have created a new module to solve the related product issue which I mentioned in this question but I got an error.

1 Answer 1

2

Why it happens

This happens when there are inconsistent positions for the related products. This might happen after a migration from magento 1. It was the case for me also.

The problem is cause by the method Magento\Catalog\Model\ProductLink\CollectionProvider::getCollection().
That's the one responsible for retrieving the products.

The part that does not behave as expected is this:

    foreach ($output as $item) {
        $itemPosition = $item['position'];
        if (!isset($sorterItems[$itemPosition])) {
            $sorterItems[$itemPosition] = $item;
        } else {
            $newPosition = $itemPosition + 1;
            $sorterItems[$newPosition] = $item;
        }
    }

Let's take 2 cases.
THe one that works:

Let's say

$output = [
     ['position' => 0],
     ['position' => 2],
     ['position' => 1],

];

(I ignored the other values for the related items as they are not important).
After running the code above this results in

Array
(
    [0] => Array
        (
            [position] => 0
        )

    [2] => Array
        (
            [position] => 2
        )

    [1] => Array
        (
            [position] => 1
        )

)

which is later sorted by the ksort function.
So 3 items on input, 3 on output. So far so good.

But let's take this case:

$output = [
    ['position' => 0], // or null
    ['position' => 1],
    ['position' => 0], // or null
];

The same piece of code returns:

Array
(
    [0] => Array
        (
            [position] => 0
        )

    [1] => Array
        (
            [position] => 0
        )

)

So 3 items in, 2 out.

Solution

I solve this by rewriting the method mentioned above and ensuring there are no position clashes.

To override it, add this in the di.xml file in one of your custom modules

<preference for="Magento\Catalog\Model\ProductLink\CollectionProvider" type="[Vendor]\[Module]\Model\ProductLink\CollectionProvider" />

Then create the class [Vendor]\[Module]\Model\ProductLink\CollectionProvider in the file [Vendor]/[Module]/Model/ProductLink/CollectionProvider.php

The class should look like this:

<?php
namespace [Vendor]\[Module]\Model\ProductLink;

use Magento\Framework\Exception\NoSuchEntityException;

class CollectionProvider extends \Magento\Catalog\Model\ProductLink\CollectionProvider
{
    /**
     * Get product collection by link type
     *
     * @param \Magento\Catalog\Model\Product $product
     * @param string $type
     * @return array
     * @throws NoSuchEntityException
     */
    public function getCollection(\Magento\Catalog\Model\Product $product, $type)
    {
        if (!isset($this->providers[$type])) {
            throw new NoSuchEntityException(__('Collection provider is not registered'));
        }
        $products = $this->providers[$type]->getLinkedProducts($product);
        $converter = $this->converterPool->getConverter($type);
        $output = [];
        $sorterItems = [];
        foreach ($products as $item) {
            $output[$item->getId()] = $converter->convert($item);
        }
        foreach ($output as $item) {
            $itemPosition = (int)$item['position'];
            while (isset($sorterItems[$itemPosition])) {
                $itemPosition++;
            }
            $sorterItems[$itemPosition] = $item;
        }
        ksort($sorterItems);
        return $sorterItems;
    }
}
2
  • How can I rewrite this method. Can I change the method directly in the vendor file? Commented Apr 11, 2019 at 7:43
  • I've updated the answer to include the full solution.
    – Marius
    Commented Apr 11, 2019 at 7:46

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.