4

XML Sitemap contains a lot of non-canonical URLs in Magento 2.0.2. It's not good practice from SEO perspective and and worth fixing.

Here is my config:

  • Use Categories Path for Product URLs is set to "No"
  • Use Canonical Link Meta Tag For Products is set to "Yes"

And few lines from my sitemap:

http://example.com/women/tops-women/tanks-women/erica-evercool-sports-bra.html  (category path, Non-Canonical)
http://example.com/nora-practice-tank.html (Canonical)
...

All sitemap links should be equal to canonical links.

Could someone please have a look at it. Appreciate any help.

2 Answers 2

0

I noticed the same thing when I first generated my sitemap. I ended up making a short extension module and tweaking the sitemap query for products.

The class that needs to be extended: Magento\Sitemap\Model\ResourceModel\Catalog\Product

The function that needs to be overridden: public function getCollection($storeId)

Change the parameter in the joinLeft of the query from:

'e.entity_id = url_rewrite.entity_id AND url_rewrite.is_autogenerated = 1'

To the following:

'e.entity_id = url_rewrite.entity_id AND url_rewrite.is_autogenerated = 1 AND url_rewrite.metadata is null'

This works for me. I'm obviously not doing a check for the canonical configuration setting and just scoping on the meta-data field in the query. This HAS NOT been thoroughly tested, so I make no promises that this won't exclude products for some reason.

I hope this helps. Maybe there will be an official patch for this later, but for now this is my solution.

0

Rajeev's answer requires overwriting the entire getCollection function, which is 50+ lines of concrete, specific code that might change in an upgrade.

I think a plugin is more upgrade proof, though slightly less efficient in terms of performance.

plugin declaration:

<type name="Magento\Sitemap\Model\ResourceModel\Catalog\Product">
    <plugin name="Vendor_SitemapProductUrlFix" type="Vendor\SitemapUrlFix\Plugin\Product"/>
</type>

and plugin file:

<?php
namespace Vendor\SitemapUrlFix\Plugin;

class Product
{

/**
 * @var \Magento\Store\Model\StoreManagerInterface
 */
protected $_storeManager;

/**
 * @var \Magento\Catalog\Model\Resource\Product\CollectionFactory
 */
protected $collectionFactory;

/**
 * @var \Magento\Catalog\Model\Product\Attribute\Source\Status
 */
protected $productStatus;

/**
 * @var \Magento\Catalog\Model\Product\Visibility
 */
protected $productVisibility;


public function __construct(
    \Magento\Store\Model\StoreManagerInterface $storeManager,
    \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory,
    \Magento\Catalog\Model\Product\Attribute\Source\Status $productStatus,
    \Magento\Catalog\Model\Product\Visibility $productVisibility
) {
    $this->_storeManager = $storeManager;
    $this->collectionFactory = $collectionFactory;
    $this->productStatus = $productStatus;
    $this->productVisibility = $productVisibility;
}

public function afterGetCollection(\Magento\Sitemap\Model\ResourceModel\Catalog\Product $subject, $result, $storeId)
{

    // create product url array (key = productId, value = product url)
        $productUrls = [];
        $productCollection = $this->collectionFactory->create()
                            ->setStore($storeId)
                            ->addAttributeToSelect('product_url')
                            ->addAttributeToSelect('id')
                            ->addAttributeToFilter('status', ['in' => $this->productStatus->getVisibleStatusIds()])
                            ->setVisibility($this->productVisibility->getVisibleInSiteIds())
        ;


        foreach ($productCollection as $product){
            $productId = (string) $product->getId();
            $storeUrl = $this->_storeManager->getStore($storeId)->getBaseUrl();

            $fullProductUrl = $product->getProductUrl();
            $productUrlPath = str_replace($storeUrl,"", $fullProductUrl);

            $productUrls[$productId] = $productUrlPath;
        }

    // replace sitemap collection item's 'url' property with product's "product_url" attribute
        $collection = $result;
        foreach ($collection AS $item){
            $productId = (string) $item->getId();
            if ($replacementUrl = $productUrls[$productId]){
                $item->setUrl($replacementUrl);
            }
        }


    return $result;
}

}

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.