Question

Not sure if this is a bug in this project, or a Magento2 bug itself

The question is site is configured to use store code in urls, and that's working fine... but urls without any store code are loading too, causing SEO problems due to content duplicity

Example: "en" is the store code of default storeView

http://ourproject.com/home -> loads fine

http://ourproject.com/en/home -> loads fine

http://ourproject.com/home should redirect 301 to http://ourproject.com/en/home

Any ideas about how to force (in a clean way) any url to use store code of default storeView?

update

We use Apache as webserver

Was it helpful?

Solution

We finally solved this with a light module, using controller_action_predispatch event

This assumes a site with 2 store views, with following store codes

es <- default

en

etc / frontend / events.xml

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="controller_action_predispatch">
        <observer name="force_storecode_redirect" instance="Vendor\Module\Observer\ForceStorecodeRedirectObserver" shared="false" />
    </event>
</config>

Observer / ForceStorecodeRedirectObserver.php

<?php
namespace Vendor\Module\Observer;
use Magento\Framework\Event\ObserverInterface;

class ForceStorecodeRedirectObserver implements ObserverInterface
{
    protected $storeManager;
    protected $url;
    /** @var string $defaultStorecode */
    protected $defaultStorecode = 'es';
    /** @var array $storeCodes - array of existing storecodes*/
    protected $storeCodes = [];

    public function __construct(
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\UrlInterface $url
    ) {
       $this->storeManager = $storeManager;
       $this->url = $url;
       $this->storeCodes = array_keys($this->storeManager->getStores(false, true));
    }

    public function execute(\Magento\Framework\Event\Observer $observer)
    {
         $urlParts = parse_url($this->url->getCurrentUrl());
         $path = $urlParts['path'];

         // get storecode from URL
         $urlCode = trim(substr($path, 0, 4), '/');

         // If path does not already contain an existing storecode
         if (!in_array($urlCode, $this->storeCodes)) {
             $path = ltrim($path, '/');
             if ($path == 'en') {
                 $path = '';
             }

             // Redirect to URL including storecode
             header("HTTP/1.1 301 Moved Permanently");
             header("Location: " . $this->storeManager->getStore()->getBaseUrl() . $path);
             exit();
       }
    }
}

OTHER TIPS

You could to this through nginx:

## Redirect URLs without storecode to URLs with storecodes
set $storecode undefined;
if ( $http_host ~ ^(www\.)?ourproject.com ) {
    set $storecode en;
}

if ( $request_uri ~ ^/(skin|js|media|feeds|api|rest|index.php/admin|sitemaps)(|/$|/) ) {
    set $storecode reset;
}


if ( $request_uri ~ ^/(en)(|/$|/) ) {
    set $storecode reset;
}

if ( $storecode = en ) {
    rewrite ^(.*) http://$host/$storecode$1 permanent;
}

Let me know if you have any questions.

Simply go to backend Stores >> Configuration >> Web >> URL Options (set Add Store Code to Urls to Yes.) Clear cache and reindex.

Kudos if it works!

Licensed under: CC-BY-SA with attribution
Not affiliated with magento.stackexchange
scroll top