3

Sometimes during import products we receive issue: The URL key for the selected store already exists.

We have found one website with solution:

https://www.human-element.com/url-key-specified-store-already-exists-magento-2/

but I see this path: not be compatible with versions of Magento 2.1.8 and above

our version magento is 2.2.5

Can anyone check it for us if this solution will work on our version?

@update

We try install this path but during setup:di:compile issue:

 [Exception]
  Warning: Declaration of HE\UrlkeyRewrite\Model\ProductUrlRewriteGenerator::
  generateForGlobalScope($productCategories) should be compatible with Magent
  o\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator::generateForGlobalScop
  e($productCategories, $product = NULL, $rootCategoryId = NULL) in /home/user/domains/website.com/public_html/app/code/HE/UrlkeyRewrite/Model/ProductU
  rlRewriteGenerator.php on line 50

code producturlrewritegenertor.php

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace HE\UrlkeyRewrite\Model;

use Magento\Catalog\Model\Product;
use Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\Product\CategoriesUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator;
use Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Service\V1\StoreViewService;
use Magento\Store\Model\Store;
use Magento\Catalog\Model\Product\Visibility;

class ProductUrlRewriteGenerator extends \Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator
{

    /**
     * Generate list of urls for global scope
     *
     * Update adds in a clone of the collection and setting the storeId
     * Variation of this post:
     * https://magento.stackexchange.com/questions/169352/magento-2-url-key-for-specified-store-already-exists
     *
     * @param \Magento\Framework\Data\Collection $productCategories
     * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
     */
    protected function generateForGlobalScope($productCategories)
    {
        $urls = [];
        $productId = $this->product->getEntityId();
        foreach ($this->product->getStoreIds() as $id) {
            if (!$this->isGlobalScope($id)
                && !$this->storeViewService->doesEntityHaveOverriddenUrlKeyForStore($id, $productId, Product::ENTITY)
            ) {
                // Default: $urls = array_merge($urls, $this->generateForSpecificStoreView($id, $productCategories));
                // before loading the category collection by looping it, clone it and set the correct store id,
                // so we get the correct url_path & url_key for that specific store id
                $storeSpecificProductCategories = clone $productCategories;
                $storeSpecificProductCategories->setStoreId($id);

                $urls = array_merge($urls, $this->generateForSpecificStoreView($id, $storeSpecificProductCategories));
            }
        }
        return $urls;
    }

}

2 Answers 2

1

You have change function generateForGlobalScope in file ProductUrlRewriteGenerator.php as below . It is working for me with Magento 2.3.2

<?php
/**
 * Copyright © 2015 Magento. All rights reserved.
 * See COPYING.txt for license details.
 */
namespace HE\UrlkeyRewrite\Model;

use Magento\Catalog\Model\Product;
use Magento\CatalogUrlRewrite\Model\Product\CanonicalUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\Product\CategoriesUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Model\Product\CurrentUrlRewritesRegenerator;
use Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator;
use Magento\CatalogUrlRewrite\Service\V1\StoreViewService;
use Magento\Store\Model\Store;
use Magento\Catalog\Model\Product\Visibility;

class ProductUrlRewriteGenerator extends \Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator
{

    /**
     * Generate list of urls for global scope
     *
     * Update adds in a clone of the collection and setting the storeId
     * Variation of this post:
     * https://magento.stackexchange.com/questions/169352/magento-2-url-key-for-specified-store-already-exists
     *
     * @param \Magento\Framework\Data\Collection $productCategories
     * @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
     */
    protected function generateForGlobalScope($productCategories,$product = null, $rootCategoryId = null)
    {
        $urls = [];
        $productId = $product->getEntityId();
        foreach ($product->getStoreIds() as $id) {
            if (!$this->isGlobalScope($id)
                && !$this->storeViewService->doesEntityHaveOverriddenUrlKeyForStore($id, $productId, Product::ENTITY)
            ) {
                // Default: $urls = array_merge($urls, $this->generateForSpecificStoreView($id, $productCategories));
                // before loading the category collection by looping it, clone it and set the correct store id,
                // so we get the correct url_path & url_key for that specific store id
                $storeSpecificProductCategories = clone $productCategories;
                $storeSpecificProductCategories->setStoreId($id);

                $urls = array_merge($urls, $this->generateForSpecificStoreView($id, $storeSpecificProductCategories,$product,$rootCategoryId));
            }
        }
        return $urls;
    }

}
1

I have fixed this issue in more than 3-4 projects.

If you want to resolve this issue, you can upgrade your version with latest one or try below code logic:

Try this solution by overriding below function in your custom module :)

Path: vendor/magento/module-url-rewrite/Model/Storage

protected function doReplace(array $urls){ 
    $this->deleteOldUrls($urls); 
    $data = [];
    $storeId_requestPaths = [];
    foreach ($urls as $url) {
        $storeId = $url->getStoreId();
        $requestPath = $url->getRequestPath();
        $sql = "SELECT * FROM url_rewrite where store_id = $storeId and request_path = '$requestPath'";
        $exists = $this->connection->fetchOne($sql); 
        if ($exists) continue;
        $storeId_requestPaths[] = $storeId . '-' . $requestPath;
        $data[] = $url->toArray();
    }

    // Remove duplication data;
    $n = count($storeId_requestPaths);
    for ($i = 0; $i < $n - 1; $i++) {
        for ($j = $i + 1; $j < $n; $j++) {
            if ($storeId_requestPaths[$i] == $storeId_requestPaths[$j]) {
                unset($data[$j]);
            }
        }
    }
    try {
        $this->insertMultiple($data);
    } catch (\Magento\Framework\Exception\AlreadyExistsException $e) {
        /** @var \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[] $urlConflicted */
        $urlConflicted = [];
        foreach ($urls as $url) {
            $urlFound = $this->doFindOneByData(
                [
                    UrlRewriteData::REQUEST_PATH => $url->getRequestPath(),
                    UrlRewriteData::STORE_ID => $url->getStoreId(),
                ]
            );
            if (isset($urlFound[UrlRewriteData::URL_REWRITE_ID])) {
                $urlConflicted[$urlFound[UrlRewriteData::URL_REWRITE_ID]] = $url->toArray();
            }
        }
        if ($urlConflicted) {
            throw new \Magento\UrlRewrite\Model\Exception\UrlAlreadyExistsException(
                __('URL key for specified store already exists.'),
                $e,
                $e->getCode(),
                $urlConflicted
            );
        } else {
            throw $e->getPrevious() ?: $e;
        }
    }

    return $urls;
}

Happy Coding :)

Thanks,

Ketan T.

1
  • worked for me in 2.3.4
    – bill.gates
    Apr 29, 2020 at 5:38

Your Answer

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

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