Magento 2 Category URL – Fixing ‘URL Key for Specified Store Already Exists’ Error

magento-2.1magento2

I have 3 storeviews in multiple languages (English, Dutch and German).
The all have the same categories but the english names must be translated.
So i select a storeview in the categorie editor in the backend.
But when I rename a category in let's say 'kitchen' to 'Küchen' in german (or to any other name) I get the following error:

"URL key for specified store already exists."

So and i can't change the name to anything whithout getting this error.
I tried to manually add a random url key lets say 'foo1234' but still not working. so i changed the category name and url key to random text. but there is no way i get it changed

I have no idea why i keep getting this error.

Best Answer

I've fixed this issue. And I have 2 solutions for that.

The first one: Clean up your database in table url_rewrite (Change the url_key of all category). You can write UpgradeData script for this solution.

The second one: Remove the duplication data when saving category. This data is throw in method doReplace($urls) in \vendor\magento\module-url-rewrite\Model\Storage\DbStorage.php file.

protected function doReplace($urls)
    {
        foreach ($this->createFilterDataBasedOnUrls($urls) as $type => $urlData) {
            $urlData[UrlRewrite::ENTITY_TYPE] = $type;
            $this->deleteByData($urlData);
        }
        $data = [];
        foreach ($urls as $url) {
            $data[] = $url->toArray();
        }
        $this->insertMultiple($data);
    } 

After debugging, I found out $data variable has a duplicate record. If you want this method to work without any errors. Rewrite this method above to:

protected function doReplace($urls)
{
    foreach ($this->createFilterDataBasedOnUrls($urls) as $type => $urlData) {
        $urlData[UrlRewrite::ENTITY_TYPE] = $type;
        $this->deleteByData($urlData);
    }
    $data = [];
    $storeId_requestPaths = [];
    foreach ($urls as $url) {
        $storeId = $url->getStoreId();
        $requestPath = $url->getRequestPath();
        // Skip if is exist in the database
        $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]);
            }
        }
    }
    $this->insertMultiple($data);
}

If you want to get more details. Please, read my comment in

https://github.com/magento/magento2/issues/7298

Hope this will help you.