301 Redirect vs Canonical: Understanding the Difference in Magento

Posted on: 17 Feb 2020 by Admin

This is an ultimate guide on 301 redirect vs canonical links in Magento

What can you do to prevent duplicated content of products from different stores?
Recently we’ve received one inquiry to optimize an existing Magento website. Shortly, there are 2 stores with codes: store1 and store2. Store code is included in the URL.

While we were working on the optimization, the client has reported that some of the products show in both: store1 and store2 but they should be visible only in one of those stores (imagine that you’re on store1 and you see there some related products but from store2).
An additional problem in our case was that there were 2 categories, store1 and store2 (same names for categories as for store codes).
Shortly, when you’re on one product you could manually change URL from /store1/ to /store2/ and you were able to see the same product, but now in different stores (with different themes).
Because search engine could see the same product in store1 and store2 (2 same pages but with different URL – with the same content) it might think that you’re “cheating” and it could position you lower in search results. What search engine could do is to index all products on all stores – duplicated content.
To avoid that we needed to “find” proper solution for that. Basically what we could do here is:
a) 301 redirects or
b) use canonical URLs.
So we needed to ensure for some products from store1 not to be visible in store2.
At the end what we did is that we added 301 redirects for products that should be only visible in one store (if you try somehow to change URL), but if product exists in both stores we added canonical URLs to be on store1 (store1 in our case is more important).
Note: we’ve worked on CE ver.: 1.7.0.1. Don’t change the core files! But, because of simplicity, I’ll show you the solution by modifying core files.
Open file app/code/core/Mage/Catalog/controllers/ProductController.php and replace viewAction() with the following content:

 

public function viewAction()

    {

        // Get initial data from request

        $categoryId = (int) $this->getRequest()->getParam('category', false);

        $productId  = (int) $this->getRequest()->getParam('id');

        $specifyOptions = $this->getRequest()->getParam('options');

        /////////////////////////////////////// START WITH 301 REDIRECT

        $redirectURL =     Mage::getUrl('', array(

                '_current' => true,

                '_use_rewrite' => true,

        ));

        if ($productId) {

            $product = Mage::getModel('catalog/product')->load($productId);

        }

        $tmpStoreCode = false;

        $tmpStoreCode =  Mage::app()->getStore()->getCode();

        $expCatIdStore= false;

        switch ($tmpStoreCode) {

            case 'store1':

                $expCatIdStore = 1;

                break;

            case 'store2':

                $expCatIdStore = 100;

                break;

        }

        if ($expCatIdStore && $productId) {

            $catIds = array();

            try {

                $catIds = $product->getCategoryIds();

            } catch (Exception $e) {

                //Mage::log or similar

            }

            $productIsInStore1 = false;

            $productIsInStore2 = false;

            // imagine that store code store1 represents category_id=1 and

            // store with code store2 represents category_id=100

            if (in_array(1, $catIds)) {

                $productIsInStore1 = true;

            }

            if (in_array(100, $catIds)) {

                $productIsInStore2 = true;

            }

            // if product should be in both stores don't do any redirect

            if ( !($productIsInStore1 && $productIsInStore2) ) {

                if ($productIsInStore2 && $tmpStoreCode === 'store1') {

                    $redirectURL = str_replace('example.com/store1/', 'example.com/store2/', $redirectURL);

                    header ('HTTP/1.1 301 Moved Permanently');

                    header ('Location: ' . $redirectURL);

                    exit;

                } elseif ($productIsInStore1 && $tmpStoreCode === 'store2') {

                    $redirectURL = str_replace('example.com/store2/', 'example.com/store1/', $redirectURL);

                    header ('HTTP/1.1 301 Moved Permanently');

                    header ('Location: ' . $redirectURL);

                    exit;

                }

            }

        }

        /////////////////////////////////////// END WITH 301 REDIRECT

        // Prepare helper and params

        $viewHelper = Mage::helper('catalog/product_view');

        $params = new Varien_Object();

        $params->setCategoryId($categoryId);

        $params->setSpecifyOptions($specifyOptions);

        // Render page

        try {

            $viewHelper->prepareAndRender($productId, $this, $params);

        } catch (Exception $e) {

            if ($e->getCode() == $viewHelper->ERR_NO_PRODUCT_LOADED) {

                if (isset($_GET['store'])  && !$this->getResponse()->isRedirect()) {

                    $this->_redirect('');

                } elseif (!$this->getResponse()->isRedirect()) {

                    $this->_forward('noRoute');

                }

            } else {

                Mage::logException($e);

                $this->_forward('noRoute');

            }

        }

    }

Additionally, to use canonical URLs for products that should be in both categories but, perhaps, show to search engine that it’s in only one (for example store1) category change _prepareLayout() method with the following content.
Open file app/code/core/Mage/Catalog/Block/Product/View.php

protected function _prepareLayout()

{

 $this->getLayout()->createBlock('catalog/breadcrumbs');

 $headBlock = $this->getLayout()->getBlock('head');

if ($headBlock) {

 $product = $this->getProduct();

 $title = $product->getMetaTitle();

if ($title) {

 $headBlock->setTitle($title);

}

 $keyword = $product->getMetaKeyword();

 $currentCategory = Mage::registry('current_category');

if ($keyword) {

 $headBlock->setKeywords($keyword);

} elseif($currentCategory) {

 $headBlock->setKeywords($product->getName());

}

 $description = $product->getMetaDescription();

if ($description) {

 $headBlock->setDescription( ($description) );

} else {

 $headBlock->setDescription(Mage::helper('core/string')->substr($product->getDescription(), 0, 255));

}

if ($this->helper('catalog/product')->canUseCanonicalTag()) {

 $params = array('_ignore_category'=>true);

 /////////////////////////////////////// START WITH CANONICAL

 $cannURL = $product->getUrlModel()->getUrl($product, $params);

 $productId = (int) $this->getRequest()->getParam('id');

 $tmpStoreCode = false;

 $tmpStoreCode = Mage::app()->getStore()->getCode();

 $expCatIdStore = false;

switch ($tmpStoreCode) {

 case 'store1':

 $expCatIdStore = 1;

 break;

 case 'store2':

 $expCatIdStore = 100;

 break;

}

if ($expCatIdStore && $productId) {

 $catIds = array();

 try {

 $catIds = $product->getCategoryIds();

} catch (Exception $e) {

 //die silently

}

 $productIsInBoth = false;

if ( in_array(1, $catIds) && in_array(100, $catIds) ) {

 $productIsInBoth = true;

}

if ($productIsInBoth && $tmpStoreCode === 'store2') {

 $cannURL = str_replace('example.com/store2/', 'example.com/store1/', $cannURL);

}

}

 $headBlock->addLinkRel('canonical', $cannURL);

 //////////////////////////////////// END WITH CANONICAL

 //$headBlock->addLinkRel('canonical', $product->getUrlModel()->getUrl($product, $params));

}
}
 return parent::_prepareLayout();
}

Source : http://inchoo.net/ecommerce/magento/301vscanonicals/#more-17337

With these simple steps, we have learnt about 301 redirect vs canonical links in Magento. I hope this tutorial is worthy!