Magento2 multistore - redirect url without store code to default storeView url
-
07-01-2021 - |
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
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!