diff --git a/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminChangeSeoUrlKeyForSubCategoryWithoutRedirectActionGroup.xml b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminChangeSeoUrlKeyForSubCategoryWithoutRedirectActionGroup.xml
new file mode 100644
index 0000000000000..fc010cec4cb65
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Mftf/ActionGroup/AdminChangeSeoUrlKeyForSubCategoryWithoutRedirectActionGroup.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+ Requires navigation to subcategory creation/edit. Updates the Search Engine Optimization with uncheck Redirect Checkbox .
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml b/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml
index 6ffb4e1902424..e766a233c401c 100644
--- a/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml
+++ b/app/code/Magento/Catalog/Test/Mftf/Data/CategoryData.xml
@@ -110,6 +110,22 @@
false
false
+
+ SimpleCategory
+ simplecategory
+ true
+ default-simplecategory
+ custom-simplecategory
+
+
+ SimpleSubCategory
+ simplesubcategory
+ true
+ default-simplesubcategory
+ custom-simplesubcategory
+ true
+
+
Gear
diff --git a/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php b/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php
index 5d08ea33ff8a1..a6589c6062846 100644
--- a/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php
+++ b/app/code/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGenerator.php
@@ -67,7 +67,7 @@ public function generate($storeId, Product $product, ObjectRegistry $productCate
$anchorCategoryIds = $category->getAnchorsAbove();
if ($anchorCategoryIds) {
foreach ($anchorCategoryIds as $anchorCategoryId) {
- $anchorCategory = $this->categoryRepository->get($anchorCategoryId);
+ $anchorCategory = $this->categoryRepository->get($anchorCategoryId, $storeId);
if ((int)$anchorCategory->getParentId() === Category::TREE_ROOT_ID) {
continue;
}
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/ActionGroup/AssertStorefrontProductRewriteUrlSubCategoryActionGroup.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/ActionGroup/AssertStorefrontProductRewriteUrlSubCategoryActionGroup.xml
new file mode 100644
index 0000000000000..4675d3b2669a4
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/ActionGroup/AssertStorefrontProductRewriteUrlSubCategoryActionGroup.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+ Validates that the provided Product Title is present on the Rewrite URL with a subcategory page.
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Data/GenerateCategoryProductUrlRewriteConfigData.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Data/GenerateCategoryProductUrlRewriteConfigData.xml
index 10d2213b64717..9ce6d397a551b 100644
--- a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Data/GenerateCategoryProductUrlRewriteConfigData.xml
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Data/GenerateCategoryProductUrlRewriteConfigData.xml
@@ -19,4 +19,12 @@
No
0
+
+ catalog/seo/product_use_categories
+ 1
+
+
+ catalog/seo/product_use_categories
+ 0
+
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminRewriteProductWithTwoStoreTest.xml b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminRewriteProductWithTwoStoreTest.xml
new file mode 100644
index 0000000000000..db4811273a5cc
--- /dev/null
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Mftf/Test/AdminRewriteProductWithTwoStoreTest.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/AnchorUrlRewriteGeneratorTest.php b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/AnchorUrlRewriteGeneratorTest.php
index 662e156b8f100..d8fec2de0e46e 100644
--- a/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/AnchorUrlRewriteGeneratorTest.php
+++ b/app/code/Magento/CatalogUrlRewrite/Test/Unit/Model/Product/AnchorUrlRewriteGeneratorTest.php
@@ -3,53 +3,67 @@
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
+declare(strict_types=1);
+
namespace Magento\CatalogUrlRewrite\Test\Unit\Model\Product;
+use Magento\Catalog\Api\CategoryRepositoryInterface;
+use Magento\Catalog\Model\Product;
+use Magento\CatalogUrlRewrite\Model\ObjectRegistry;
+use Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator;
+use Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator;
use Magento\CatalogUrlRewrite\Model\ProductUrlRewriteGenerator;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\UrlRewrite\Service\V1\Data\UrlRewrite;
+use Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory;
+use PHPUnit\Framework\TestCase;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
-class AnchorUrlRewriteGeneratorTest extends \PHPUnit\Framework\TestCase
+class AnchorUrlRewriteGeneratorTest extends TestCase
{
- /** @var \Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator */
+ /** @var AnchorUrlRewriteGenerator */
protected $anchorUrlRewriteGenerator;
- /** @var \Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var ProductUrlPathGenerator|MockObject */
protected $productUrlPathGenerator;
- /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var Product|MockObject */
protected $product;
- /** @var \Magento\Catalog\Api\CategoryRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var CategoryRepositoryInterface|MockObject */
private $categoryRepositoryInterface;
- /** @var \Magento\CatalogUrlRewrite\Model\ObjectRegistry|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var ObjectRegistry|MockObject */
protected $categoryRegistry;
- /** @var \Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var UrlRewriteFactory|MockObject */
protected $urlRewriteFactory;
- /** @var \Magento\UrlRewrite\Service\V1\Data\UrlRewrite|\PHPUnit_Framework_MockObject_MockObject */
+ /** @var UrlRewrite|MockObject */
protected $urlRewrite;
+ /**
+ * @inheritDoc
+ */
protected function setUp()
{
- $this->urlRewriteFactory = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewriteFactory::class)
+ $this->urlRewriteFactory = $this->getMockBuilder(UrlRewriteFactory::class)
->setMethods(['create'])
->disableOriginalConstructor()->getMock();
- $this->urlRewrite = $this->getMockBuilder(\Magento\UrlRewrite\Service\V1\Data\UrlRewrite::class)
+ $this->urlRewrite = $this->getMockBuilder(UrlRewrite::class)
->disableOriginalConstructor()->getMock();
- $this->product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+ $this->product = $this->getMockBuilder(Product::class)
->disableOriginalConstructor()->getMock();
$this->categoryRepositoryInterface = $this->getMockBuilder(
- \Magento\Catalog\Api\CategoryRepositoryInterface::class
+ CategoryRepositoryInterface::class
)->disableOriginalConstructor()->getMock();
- $this->categoryRegistry = $this->getMockBuilder(\Magento\CatalogUrlRewrite\Model\ObjectRegistry::class)
+ $this->categoryRegistry = $this->getMockBuilder(ObjectRegistry::class)
->disableOriginalConstructor()->getMock();
$this->productUrlPathGenerator = $this->getMockBuilder(
- \Magento\CatalogUrlRewrite\Model\ProductUrlPathGenerator::class
+ ProductUrlPathGenerator::class
)->disableOriginalConstructor()->getMock();
$this->anchorUrlRewriteGenerator = (new ObjectManager($this))->getObject(
- \Magento\CatalogUrlRewrite\Model\Product\AnchorUrlRewriteGenerator::class,
+ AnchorUrlRewriteGenerator::class,
[
'productUrlPathGenerator' => $this->productUrlPathGenerator,
'urlRewriteFactory' => $this->urlRewriteFactory,
@@ -58,7 +72,12 @@ protected function setUp()
);
}
- public function testGenerateEmpty()
+ /**
+ * Verify generate if category registry list is empty.
+ *
+ * @return void
+ */
+ public function testGenerateEmpty(): void
{
$this->categoryRegistry->expects($this->any())->method('getList')->will($this->returnValue([]));
@@ -68,7 +87,12 @@ public function testGenerateEmpty()
);
}
- public function testGenerateCategories()
+ /**
+ * Verify generate product rewrites for anchor categories.
+ *
+ * @return void
+ */
+ public function testGenerateCategories(): void
{
$urlPathWithCategory = 'category1/category2/category3/simple-product.html';
$storeId = 10;
@@ -100,9 +124,9 @@ public function testGenerateCategories()
->expects($this->any())
->method('get')
->withConsecutive(
- [ 'category_id' => $categoryIds[0]],
- [ 'category_id' => $categoryIds[1]],
- [ 'category_id' => $categoryIds[2]]
+ [$categoryIds[0], $storeId],
+ [$categoryIds[1], $storeId],
+ [$categoryIds[2], $storeId]
)
->will($this->returnValue($category));
$this->categoryRegistry->expects($this->any())->method('getList')
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGeneratorTest.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGeneratorTest.php
new file mode 100644
index 0000000000000..446b423e17187
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/Model/Product/AnchorUrlRewriteGeneratorTest.php
@@ -0,0 +1,92 @@
+objectManager = Bootstrap::getObjectManager();
+ $this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class);
+ $this->objectRegistryFactory = $this->objectManager->create(ObjectRegistryFactory::class);
+ }
+
+ /**
+ * Verify correct generate of the relative "StoreId"
+ *
+ * @param string $expect
+ * @return void
+ * @throws \Magento\Framework\Exception\LocalizedException
+ * @throws \Magento\Framework\Exception\NoSuchEntityException
+ * @magentoDataFixture Magento/CatalogUrlRewrite/_files/product_with_stores.php
+ * @magentoDbIsolation disabled
+ * @dataProvider getConfigGenerate
+ */
+ public function testGenerate(string $expect): void
+ {
+ $product = $this->productRepository->get('simple');
+ $categories = $product->getCategoryCollection();
+ $productCategories = $this->objectRegistryFactory->create(['entities' => $categories]);
+
+ /** @var AnchorUrlRewriteGenerator $generator */
+ $generator = $this->objectManager->get(AnchorUrlRewriteGenerator::class);
+
+ /** @var $store Store */
+ $store = Bootstrap::getObjectManager()->get(Store::class);
+ $store->load('fixture_second_store', 'code');
+
+ $urls = $generator->generate($store->getId(), $product, $productCategories);
+
+ $this->assertEquals($expect, $urls[0]->getRequestPath());
+ }
+
+ /**
+ * Data provider for testGenerate
+ *
+ * @return array
+ */
+ public function getConfigGenerate(): array
+ {
+ return [
+ [
+ 'expect' => 'category-1-custom/simple-product.html'
+ ]
+ ];
+ }
+}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/categories_with_stores.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/categories_with_stores.php
new file mode 100644
index 0000000000000..5fc9d75598da6
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/categories_with_stores.php
@@ -0,0 +1,80 @@
+loadArea(FrontNameResolver::AREA_CODE);
+
+$store = Bootstrap::getObjectManager()->get(Store::class);
+$store->load('fixture_second_store', 'code');
+
+/** @var $category Category */
+$category = Bootstrap::getObjectManager()->create(Category::class);
+$category->isObjectNew(true);
+$category->setId(3)
+ ->setName('Category 1')
+ ->setParentId(2)
+ ->setPath('1/2/3')
+ ->setLevel(2)
+ ->setAvailableSortBy('name')
+ ->setDefaultSortBy('name')
+ ->setUrlPath('category-1-default')
+ ->setUrlKey('category-1-default')
+ ->setIsActive(true)
+ ->setPosition(1)
+ ->save();
+
+$category = Bootstrap::getObjectManager()->create(Category::class);
+$category->isObjectNew(true);
+$category->setId(4)
+ ->setName('Category 1.1')
+ ->setParentId(3)
+ ->setPath('1/2/3/4')
+ ->setLevel(3)
+ ->setAvailableSortBy('name')
+ ->setDefaultSortBy('name')
+ ->setUrlPath('category-1-1-default')
+ ->setUrlKey('category-1-1-default')
+ ->setIsActive(true)
+ ->setPosition(1)
+ ->save();
+
+$category = Bootstrap::getObjectManager()->create(Category::class);
+$category->isObjectNew(true);
+$category->setId(3)
+ ->setName('Category 1')
+ ->setParentId(2)
+ ->setPath('1/2/3')
+ ->setLevel(2)
+ ->setAvailableSortBy('name')
+ ->setDefaultSortBy('name')
+ ->setStoreId($store->getId())
+ ->setUrlPath('category-1-custom')
+ ->setUrlKey('category-1-custom')
+ ->setIsActive(true)
+ ->setPosition(1)
+ ->save();
+
+$category = Bootstrap::getObjectManager()->create(Category::class);
+$category->isObjectNew(true);
+$category->setId(4)
+ ->setName('Category 1.1')
+ ->setParentId(3)
+ ->setPath('1/2/3/4')
+ ->setLevel(3)
+ ->setAvailableSortBy('name')
+ ->setDefaultSortBy('name')
+ ->setStoreId($store->getId())
+ ->setUrlPath('category-1-1-custom')
+ ->setUrlKey('category-1-1-custom')
+ ->setIsActive(true)
+ ->setPosition(1)
+ ->save();
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/categories_with_stores_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/categories_with_stores_rollback.php
new file mode 100644
index 0000000000000..a89c80a61ccbc
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/categories_with_stores_rollback.php
@@ -0,0 +1,23 @@
+get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */
+$collection = $objectManager->create(\Magento\Catalog\Model\ResourceModel\Category\Collection::class);
+$collection
+ ->addAttributeToFilter('level', 2)
+ ->load()
+ ->delete();
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_with_stores.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_with_stores.php
new file mode 100644
index 0000000000000..84fa9b3044af9
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_with_stores.php
@@ -0,0 +1,45 @@
+create(
+ \Magento\Catalog\Setup\CategorySetup::class
+);
+
+require __DIR__ . '/categories_with_stores.php';
+
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+$categoryLinkRepository = $objectManager->create(
+ \Magento\Catalog\Api\CategoryLinkRepositoryInterface::class,
+ [
+ 'productRepository' => $productRepository
+ ]
+);
+
+/** @var Magento\Catalog\Api\CategoryLinkManagementInterface $linkManagement */
+$categoryLinkManagement = $objectManager->create(
+ \Magento\Catalog\Api\CategoryLinkManagementInterface::class,
+ [
+ 'productRepository' => $productRepository,
+ 'categoryLinkRepository' => $categoryLinkRepository
+ ]
+);
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+ ->setAttributeSetId($installer->getAttributeSetId('catalog_product', 'Default'))
+ ->setName('Simple Product')
+ ->setSku('simple')
+ ->setPrice(10)
+ ->setWeight(18)
+ ->setStockData(['use_config_manage_stock' => 0])
+ ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+ ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+ ->save();
+$categoryLinkManagement->assignProductToCategories($product->getSku(), [4]);
diff --git a/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_with_stores_rollback.php b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_with_stores_rollback.php
new file mode 100644
index 0000000000000..86f0ce34af00c
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogUrlRewrite/_files/product_with_stores_rollback.php
@@ -0,0 +1,29 @@
+getInstance()->reinitialize();
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\Registry::class);
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */
+$productRepository = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+ ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class);
+try {
+ $product = $productRepository->get('simple', true);
+ if ($product->getId()) {
+ $productRepository->delete($product);
+ }
+} catch (NoSuchEntityException $e) {
+}
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);