Skip to content

[Issue] Do not trigger url rewrites re-generation for all store views #32954

Closed
@m2-assistant

Description

@m2-assistant

This issue is automatically created based on existing pull request: #32808: Do not trigger url rewrites re-generation for all store views


Description (*)

During creating a new website, Store Group and Store view using php bin/magento setup:upgrade - we noticed that some URL rewrites for categories on different stores were re-generated in DB, that's absolutely not obvious and for sure not expected behavior. Such behavior, especially for us changed URLs for some categories w/o creating any redirect from old -> new URL (for some reason, we had incorrect url_path values in DB, that's another story).
As a result of this issue - some advertised categories started returning 404 pages, and we basically started burning our money.

Root cause analyze

Investigation showed, that app/code/Magento/CatalogUrlRewrite/Model/Category/Plugin/Store/Group.php plugin was executed due to 2 step saving of group:

  • at first, we just creating a new group
  • later we're assigning it to a website
    private function createGroups(array $items, array $data)
    {
    foreach ($items as $groupData) {
    $websiteId = $groupData['website_id'];
    unset(
    $groupData['group_id'],
    $groupData['website_id']
    );
    $website = $this->detectWebsiteById(
    $data,
    $websiteId
    );
    $group = $this->groupFactory->create();
    if (!isset($groupData['root_category_id'])) {
    $groupData['root_category_id'] = 0;
    }
    $group->setData($groupData);
    $group->getResource()->save($group);
    $group->getResource()->addCommitCallback(function () use ($data, $group, $website) {
    $store = $this->detectStoreById($data, (int)$group->getDefaultStoreId());
    $group->setDefaultStoreId($store->getStoreId());
    $group->setWebsite($website);
    $group->getResource()->save($group);
    });
    }
    }

As a store group still don't have any store IDs assigned (the store will be created on the next step) - $group->getStoreIds() returns an empty array, we're setting this value to the category and trying to generate URL rewrites

$category->setStoreId(Store::DEFAULT_STORE_ID);
$category->setStoreIds($storeIds);
$urls[] = $this->categoryUrlRewriteGenerator->generate($category);

Then it goes to this method, which tries to fetch a list of store Ids:

/**
* Generate list of urls for global scope
*
* @param \Magento\Catalog\Model\Category|null $category
* @param bool $overrideStoreUrls
* @param int|null $rootCategoryId
* @return \Magento\UrlRewrite\Service\V1\Data\UrlRewrite[]
*/
protected function generateForGlobalScope(
Category $category = null,
$overrideStoreUrls = false,
$rootCategoryId = null
) {
$mergeDataProvider = clone $this->mergeDataProviderPrototype;
$categoryId = $category->getId();
foreach ($category->getStoreIds() as $storeId) {
if (!$this->isGlobalScope($storeId)
&& $this->isOverrideUrlsForStore($storeId, $categoryId, $overrideStoreUrls)
) {
$category = clone $category; // prevent undesired side effects on original object
$category->setStoreId($storeId);
$this->updateCategoryUrlForStore($storeId, $category);
$mergeDataProvider->merge($this->generateForSpecificStoreView($storeId, $category, $rootCategoryId));
}
}
$result = $mergeDataProvider->getData();
return $result;
}

Here we don't have any saved store_ids, so it fetches the list of stores where this category used as a root.

public function getStoreIds()
{
if ($this->getInitialSetupFlag()) {
return [];
}
$storeIds = $this->getData('store_ids');
if ($storeIds) {
return $storeIds;
}
if (!$this->getId()) {
return [];
}
$nodes = [];
foreach ($this->getPathIds() as $id) {
$nodes[] = $id;
}
$storeIds = [];
$storeCollection = $this->_storeCollectionFactory->create()->loadByCategoryIds($nodes);
foreach ($storeCollection as $store) {
$storeIds[$store->getId()] = $store->getId();
}
$entityStoreId = $this->getStoreId();
if (!in_array($entityStoreId, $storeIds)) {
array_unshift($storeIds, $entityStoreId);
}
if (!in_array(0, $storeIds)) {
array_unshift($storeIds, 0);
}
$this->setData('store_ids', $storeIds);
return $storeIds;
}

As a result - we're re-generating category URL rewrites for all store views with the same root category ID.

Related Pull Requests

Fixed Issues (if relevant)

  1. Fixes magento/magento2#<issue_number>

Manual testing scenarios (*)

  1. Install magento, so you'll have 1 website, 1 store group, 1 store view
  2. Create some categories structure
  3. Run php bin/magento app:config:dump scopes to dump all the stores data into the config.php
  4. Create a DB dump
  5. Go to Admin, and create a new website, store group and a store view (re-use the same root category for that)
  6. Run php bin/magento app:config:dump scopes to dump all the stores data into the config.php, save the file
  7. Apply the DB dump from the step 4 in order to emulate the case, when we didn't have 2nd website, store group, etc
  8. Run php bin/magento setup:upgrade or php bin/magento app:config:import to create a new website, store group, store view
  9. Compare data in the url_rewrites table with a backup file for the store 1.

Expected result:
✔ URL rewrites for store 1 shouldn't be touched when we creating a new website / store group / store view

Actual result:
❌ URL rewrites for store 1 are re-generated when we creating a new website / store group / store view

Questions or comments

Contribution checklist (*)

  • Pull request has a meaningful description of its purpose
  • All commits are accompanied by meaningful commit messages
  • All new or changed code is covered with unit/integration tests (if applicable)
  • README.md files for modified modules are updated and included in the pull request if any README.md predefined sections require an update
  • All automated tests passed successfully (all builds are green)

Metadata

Metadata

Assignees

Labels

Area: CatalogComponent: CatalogUrlRewriteFixed in 2.4.xThe issue has been fixed in 2.4-develop branchIssue: ConfirmedGate 3 Passed. Manual verification of the issue completed. Issue is confirmedPriority: P2A defect with this priority could have functionality issues which are not to expectations.Progress: doneReported on 2.4.xIndicates original Magento version for the Issue report.Reproduced on 2.4.xThe issue has been reproduced on latest 2.4-develop branchSeverity: S1Affects critical data or functionality and forces users to employ a workaround.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions