├── CHANGELOG.md
├── Helper
├── Data.php
└── Settings.php
├── Plugin
├── Magento
│ ├── Store
│ │ └── App
│ │ │ └── Request
│ │ │ └── StorePathInfoValidator.php
│ └── UrlRewrite
│ │ └── Model
│ │ └── StoreSwitcher
│ │ └── RewriteUrl.php
└── Store
│ ├── App
│ └── Request
│ │ └── PathInfoProcessor.php
│ └── Model
│ └── Store.php
├── README.md
├── composer.json
├── etc
├── adminhtml
│ └── system.xml
├── config.xml
├── di.xml
└── module.xml
└── registration.php
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 2.1.1 (2020-04-29)
2 |
3 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.1.1)
4 |
5 | * [BUGFIX] Solved issue with api incorrect redirect because it requires the original storecode *(Lewis Voncken)*
6 |
7 |
8 | ## 2.1.0 (2020-04-24)
9 |
10 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.1.0)
11 |
12 | * [BUGFIX] Made the Store Plugin Global to solve issue invalid urls in the sitemap.xml *(Lewis Voncken)*
13 | * [FEATURE] Force redirect from original store code to the stripped store code *(Lewis Voncken)*
14 |
15 |
16 | ## 2.0.5 (2020-03-16)
17 |
18 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.0.5)
19 |
20 | * [BUGFIX] Solved invalid issue when using www in domain *(Mr. Lewis)*
21 |
22 |
23 | ## 2.0.4 (2020-03-04)
24 |
25 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.0.4)
26 |
27 | * [BUGFIX] Modified website matching by stripping schema and www. *(Egor Dmitriev)*
28 |
29 |
30 | ## 2.0.3 (2020-03-02)
31 |
32 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.0.3)
33 |
34 | * [BUGFIX] Fixed direct links to an aliased storeview. *(Egor Dmitriev)*
35 |
36 |
37 | ## 2.0.2 (2020-02-24)
38 |
39 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.0.2)
40 |
41 | * [BUGFIX] Fixed fallback such that urls with code in form of website_code still work. *(Egor Dmitriev)*
42 |
43 |
44 | ## 2.0.1 (2019-12-18)
45 |
46 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.0.1)
47 |
48 | * [BUGFIX] fixed storeswitcher functionality. Fixed issue with navigating on a non default store. Before all pages would load the default store in de back. Now the correct store *(thomas mondeel)*
49 | * Update README.md *(thokiller)*
50 | * [BUGFIX] fixed switching from homepage *(thomas mondeel)*
51 |
52 |
53 | ## 2.0.0 (2019-12-11)
54 |
55 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/2.0.0)
56 |
57 | * [FEATURE/BUGFIX] made module compatible with Magento 2.3.* *(thokiller)*
58 |
59 |
60 | ## 1.0.3 (2018-05-11)
61 |
62 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/1.0.3)
63 |
64 | * [BUGFIX] Solved fatal php error Call to a member function getCode on a boolean *(Lewis Voncken)*
65 |
66 |
67 | ## 1.0.2 (2017-08-24)
68 |
69 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/1.0.2)
70 |
71 | * [BUGFIX] Solved error in composer .json because of wrong name *(Bart Lubbersen)*
72 |
73 |
74 | ## 1.0.1 (2017-08-24)
75 |
76 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/1.0.1)
77 |
78 | * [TASK] Add license to composer *(Bart Lubbersen)*
79 |
80 |
81 | ## 1.0.0 (2017-08-24)
82 |
83 | [View Release](git@github.com:experius/Magento2-Module-Multiple-Website-Store-Code-Url.git/commits/tag/1.0.0)
84 |
85 | * [TASK] Initial commit *(Bart Lubbersen)*
86 | * [TASK] Make configuration only available on default level because url param plugin wont know store yet [TASK] Make module independent on Core module [TASK] Add composer and readme file *(Bart Lubbersen)*
87 |
88 |
89 |
--------------------------------------------------------------------------------
/Helper/Data.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 |
22 | namespace Experius\MultipleWebsiteStoreCodeUrl\Helper;
23 |
24 | use Magento\Config\Model\Config\Backend\Admin\Custom;
25 | use Magento\Framework\App\Helper\AbstractHelper;
26 | use Magento\Store\Model\StoreManagerInterface;
27 |
28 | /**
29 | * Class Data
30 | * @package Experius\MultipleWebsiteStoreCodeUrl\Helper
31 | */
32 | class Data extends AbstractHelper
33 | {
34 | /**
35 | * @var StoreManagerInterface
36 | */
37 | protected $storeManager;
38 |
39 | /** @var \Magento\Framework\App\ResourceConnection */
40 | protected $resource;
41 |
42 | protected $currentWebsite = null;
43 |
44 | /**
45 | * Data constructor.
46 | * @param StoreManagerInterface $storeManager
47 | * @param \Magento\Framework\App\ResourceConnection $resource
48 | */
49 | public function __construct(
50 | StoreManagerInterface $storeManager,
51 | \Magento\Framework\App\ResourceConnection $resource
52 | ) {
53 | $this->storeManager = $storeManager;
54 | $this->resource = $resource;
55 | }
56 |
57 | /**
58 | * @param string $websiteCode
59 | * @param string $path
60 | * @param bool $isUrl
61 | * @return string
62 | */
63 | public function setCorrectWebsiteCodeUrl($websiteCode, $path, $isUrl = false)
64 | {
65 | $element = ($isUrl) ? 3 : 0;
66 | $pathParts = explode('/', ltrim($path, '/'), 5);
67 | $storeCode = "{$websiteCode}_{$pathParts[$element]}";
68 |
69 | if ($this->validateStore($storeCode)) {
70 | $pathParts[$element] = $storeCode;
71 | $path = implode('/', $pathParts);
72 | return $path;
73 | }
74 | //returns the original path if request havenot a valid store
75 | return $path;
76 | }
77 |
78 | /**
79 | * @param string $storeCode
80 | * @return bool
81 | */
82 | public function validateStore($storeCode)
83 | {
84 | try {
85 | /** @var \Magento\Store\Api\Data\StoreInterface $store */
86 | $this->storeManager->getStore($storeCode);
87 | return true;
88 | } catch (\Exception $e) {
89 | return false;
90 | }
91 | return false;
92 | }
93 |
94 | /**
95 | * @param \Magento\Framework\App\Request\Http $request
96 | * @return int|null
97 | */
98 | public function getRequestToWebsiteId($request)
99 | {
100 | $baseUrl = str_replace('www.', '', $request->getDistroBaseUrl());
101 | // Strip schemas
102 | $baseUrl = str_replace(['https://', 'http://'], '', $baseUrl);
103 |
104 | $connection = $this->resource->getConnection();
105 | $table = $connection->getTableName('core_config_data');
106 | $websiteFilter = $connection->select()->from($table, ['scope_id'])
107 | ->where('scope = ?', 'websites')
108 | ->where('path in (?)', [Custom::XML_PATH_SECURE_BASE_URL, Custom::XML_PATH_UNSECURE_BASE_URL])
109 | ->where('value like ?', "%$baseUrl");
110 | $match = $connection->fetchCol($websiteFilter);
111 |
112 | return count($match) > 0 ? (int)$match[0] : null;
113 | }
114 |
115 | /**
116 | * Warning: Caches result
117 | * @param \Magento\Framework\App\Request\Http $request
118 | * @return \Magento\Store\Api\Data\WebsiteInterface|null
119 | * @throws \Magento\Framework\Exception\LocalizedException
120 | */
121 | public function getRequestToWebsite($request)
122 | {
123 | if (!$this->currentWebsite) {
124 | $websiteId = $this->getRequestToWebsiteId($request);
125 | $this->currentWebsite = $websiteId ? $this->storeManager->getWebsite($websiteId) : null;
126 | }
127 | return $this->currentWebsite;
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/Helper/Settings.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 | namespace Experius\MultipleWebsiteStoreCodeUrl\Helper;
22 |
23 | use Magento\Framework\App\Helper\AbstractHelper;
24 |
25 | class Settings extends AbstractHelper
26 | {
27 |
28 | const CONFIG_PATH_REMOVE_WEBSITE_CODE_FROM_STORE_URL = 'remove_website_code_from_store_url';
29 |
30 | public $configPathModule = 'web/url';
31 |
32 | public function shouldRemoveWebsiteCodeFromStoreUrl()
33 | {
34 | return $this->scopeConfig->isSetFlag(
35 | $this->configPathModule . "/" . self::CONFIG_PATH_REMOVE_WEBSITE_CODE_FROM_STORE_URL
36 | );
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Plugin/Magento/Store/App/Request/StorePathInfoValidator.php:
--------------------------------------------------------------------------------
1 | storeManager = $storeManager;
67 | $this->settings = $settings;
68 | $this->helper = $helper;
69 | $this->storeCookieManager = $storeCookieManager;
70 | $this->pathInfo = $pathInfo;
71 | $this->responseFactory = $responseFactory;
72 | }
73 |
74 | /**
75 | * @param \Magento\Store\App\Request\StorePathInfoValidator $subject
76 | * @param $result
77 | * @param $request
78 | * @param string $pathInfo
79 | * @return string
80 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
81 | */
82 | public function afterGetValidStoreCode(
83 | \Magento\Store\App\Request\StorePathInfoValidator $subject,
84 | $result,
85 | $request,
86 | $pathInfo = ''
87 | ) {
88 | if (!$this->settings->shouldRemoveWebsiteCodeFromStoreUrl()) {
89 | return $result;
90 | }
91 | if (empty($pathInfo)) {
92 | $pathInfo = $this->pathInfo->getPathInfo(
93 | $request->getRequestUri(),
94 | $request->getBaseUrl()
95 | );
96 | }
97 | $pathParts = explode('/', ltrim($pathInfo, '/'), 2);
98 | if ($result) {
99 | if (strpos($pathParts[0], '_') === false) {
100 | return $result;
101 | }
102 |
103 | }
104 | $websiteCode = $this->storeCookieManager->getStoreCodeFromCookie();
105 |
106 | if(!$websiteCode && $website = $this->helper->getRequestToWebsite($request)) {
107 | $websiteCode = $website->getCode();
108 | }
109 | if (!$websiteCode) {
110 | return $result;
111 | }
112 |
113 | if ($result && strpos($request->getRequestUri(), "/{$websiteCode}_") === 0) {
114 | $requestUri = str_replace("/{$websiteCode}_", "", $request->getRequestUri());
115 | $response = $this->responseFactory->create();
116 | $response->setRedirect($request->getDistroBaseUrl() . $requestUri, 301);
117 | $response->sendResponse();
118 | return ''; // This should never be reached because of the function above.
119 | }
120 |
121 | $storeCode = "{$websiteCode}_{$pathParts[0]}";
122 | try {
123 | /** @var \Magento\Store\Api\Data\StoreInterface $store */
124 | $this->storeManager->getStore($storeCode);
125 | } catch (\Exception $e) {
126 | return $result;
127 | }
128 | return $storeCode;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Plugin/Magento/UrlRewrite/Model/StoreSwitcher/RewriteUrl.php:
--------------------------------------------------------------------------------
1 | storeManager = $storeManager;
42 | $this->settings = $settings;
43 | $this->data = $data;
44 | }
45 |
46 | /**
47 | * @param \Magento\UrlRewrite\Model\StoreSwitcher\RewriteUrl $subject
48 | * @param $fromStore
49 | * @param $targetStore
50 | * @param $redirectUrl
51 | * @return array
52 | * @throws \Magento\Framework\Exception\LocalizedException
53 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
54 | */
55 | public function beforeSwitch(
56 | \Magento\UrlRewrite\Model\StoreSwitcher\RewriteUrl $subject,
57 | $fromStore,
58 | $targetStore,
59 | $redirectUrl
60 | ) {
61 | $return = [$fromStore,$targetStore,$redirectUrl];
62 | if (!$this->settings->shouldRemoveWebsiteCodeFromStoreUrl()) {
63 | return $return;
64 | }
65 |
66 | // to prevent a 404 when used on a home page
67 | $redirectUrlTemp = rtrim($redirectUrl,'/');
68 | $temp = explode('/',$redirectUrlTemp,5);
69 | if (rtrim($temp[3],'/') == rtrim(end($temp),'/'))
70 | {
71 | if (strpos(rtrim($redirectUrl, '/'), rtrim($targetStore->getBaseUrl(),'/')) === false) {
72 | $redirectUrl = $targetStore->getBaseUrl();
73 | return [$fromStore,$targetStore,$redirectUrl];
74 | }
75 | return $return;
76 | }
77 | unset($temp);
78 | unset($redirectUrlTemp);
79 |
80 | $website = $this->storeManager->getWebsite();
81 | if (!$website) {
82 | return $return;
83 | }
84 | $websiteCode = $website->getCode();
85 | $redirectUrl = $this->data->setCorrectWebsiteCodeUrl($websiteCode,$redirectUrl,true);
86 |
87 | return [$fromStore,$targetStore,$redirectUrl];
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Plugin/Store/App/Request/PathInfoProcessor.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 | namespace Experius\MultipleWebsiteStoreCodeUrl\Plugin\Store\App\Request;
22 |
23 | use Experius\MultipleWebsiteStoreCodeUrl\Helper\Data;
24 | use Experius\MultipleWebsiteStoreCodeUrl\Helper\Settings;
25 | use Magento\Framework\App\RequestInterface;
26 | use Magento\Framework\Exception\NoSuchEntityException;
27 | use Magento\Store\Model\StoreManagerInterface;
28 |
29 | class PathInfoProcessor
30 | {
31 |
32 | /**
33 | * @var \Magento\Store\Model\StoreManagerInterface
34 | */
35 | private $storeManager;
36 |
37 | /**
38 | * @var \Experius\MultipleWebsiteStoreCodeUrl\Helper\Settings
39 | */
40 | private $settings;
41 |
42 | /**
43 | * @var Data
44 | */
45 | protected $data;
46 |
47 | /**
48 | * PathInfoProcessor constructor.
49 | * @param \Magento\Store\Model\StoreManagerInterface $storeManager
50 | * @param \Experius\MultipleWebsiteStoreCodeUrl\Helper\Settings $settings
51 | * @param \Experius\MultipleWebsiteStoreCodeUrl\Helper\Data $data
52 | */
53 | public function __construct(
54 | StoreManagerInterface $storeManager,
55 | Settings $settings,
56 | Data $data
57 | ) {
58 | $this->storeManager = $storeManager;
59 | $this->settings = $settings;
60 | $this->data = $data;
61 | }
62 |
63 | /**
64 | * @param \Magento\Store\App\Request\PathInfoProcessor $subject
65 | * @param callable $proceed
66 | * @param RequestInterface $request
67 | * @param $pathInfo
68 | * @return mixed
69 | * @throws \Magento\Framework\Exception\LocalizedException
70 | * @SuppressWarnings(PHPMD.UnusedFormalParameter)
71 | */
72 | public function aroundProcess(
73 | \Magento\Store\App\Request\PathInfoProcessor $subject,
74 | callable $proceed,
75 | RequestInterface $request,
76 | $pathInfo
77 | ) {
78 | if (!$this->settings->shouldRemoveWebsiteCodeFromStoreUrl()) {
79 | return $proceed($request, $pathInfo);
80 | }
81 | $website = $this->storeManager->getWebsite();
82 | if (!$website) {
83 | return $proceed($request, $pathInfo);
84 | }
85 | $websiteCode = $website->getCode();
86 | $newPath = $this->data->setCorrectWebsiteCodeUrl($websiteCode,$pathInfo,false);
87 | return $proceed($request, "/" . ltrim($newPath, '/'));
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Plugin/Store/Model/Store.php:
--------------------------------------------------------------------------------
1 | .
20 | */
21 | namespace Experius\MultipleWebsiteStoreCodeUrl\Plugin\Store\Model;
22 |
23 | use Experius\MultipleWebsiteStoreCodeUrl\Helper\Settings;
24 | use Magento\Framework\UrlInterface;
25 |
26 | class Store
27 | {
28 |
29 | /**
30 | * @var \Experius\MultipleWebsiteStoreCodeUrl\Helper\Settings
31 | */
32 | private $settings;
33 |
34 | /**
35 | * PathInfoProcessor constructor.
36 | * @param \Experius\MultipleWebsiteStoreCodeUrl\Helper\Settings $settings
37 | */
38 | public function __construct(
39 | Settings $settings
40 | ) {
41 | $this->settings = $settings;
42 | }
43 |
44 | public function aroundGetBaseUrl(\Magento\Store\Model\Store $subject, callable $proceed, $type = UrlInterface::URL_TYPE_LINK, $secure = null)
45 | {
46 | $url = $proceed($type, $secure);
47 | if (!$this->settings->shouldRemoveWebsiteCodeFromStoreUrl()) {
48 | return $url;
49 | }
50 | if ($type != UrlInterface::URL_TYPE_LINK) {
51 | return $url;
52 | }
53 | $storeCode = $subject->getCode();
54 | $website = $subject->getWebsite();
55 | if (!$website) {
56 | return $proceed($type, $secure);
57 | }
58 | $websiteCode = $website->getCode();
59 | $storeUrlCode = str_replace("{$websiteCode}_", "", $storeCode);
60 | $url = str_replace($storeCode, $storeUrlCode, $url);
61 | return $url;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Multiple website store code url
2 | This module enabled you to use the same store_code multiple times for different websites in the url by removing the website_code from the store_code before adding it to the url. So "example.com/website_en/", will become "example.com/en/".
3 |
4 | The module has configuration to enable/disable it in the web/url section.
5 |
6 | **Important: the store code should include the website code otherwise it won't do anything.**
7 |
8 | # Configuration
9 | In order for direct links to work, you must set base urls on website level.
10 |
11 | In "Stores -> Configuration -> General -> Web -> Base Urls", "web/unsecure/base_url" or "web/secure/base_url" or both must be filled.
12 | The values must be present at website level.
13 |
14 | # Changelog:
15 | - 2.0.0 added compatibility for magento 2.3.*.
16 | - 2.0.1 fixed issues with not being able to navigate on a not default store + fixed storeswitcher url redirect
17 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "experius/module-multiplewebsitestorecodeurl",
3 | "description": "This module enabled you to use the same store_code multiple times for different websites in the url.",
4 | "authors": [
5 | {
6 | "name": "Experius",
7 | "email": "info@experius.nl"
8 | }
9 | ],
10 | "license": "GPL-3.0",
11 | "autoload": {
12 | "files": [
13 | "registration.php"
14 | ],
15 | "psr-4": {
16 | "Experius\\MultipleWebsiteStoreCodeUrl\\": ""
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/etc/adminhtml/system.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Magento\Config\Model\Config\Source\Yesno
9 |
10 | 1
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/etc/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 1
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/etc/module.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |