I run a multi website setup where there is only one store and store view per website.
In this scenario the store switcher won't work, so I'd like to implement a website switcher instead.
I'd like to use this [article][1] to implement it,
Based on Daniels solution below, I did the following.
Created a module
/app/code/{vendor}/{module}/ViewModel/StoreSwitchModel.php
With the following code
<?php
namespace [Vendor]\{Module}\ViewModel;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Locale\TranslatedLists;
use Magento\Framework\Url\EncoderInterface;
use Magento\Framework\UrlInterface;
use Magento\Store\Api\Data\StoreInterface;
use Magento\Store\Model\ResourceModel\Website\Collection as WebsiteCollection;
use Magento\Store\Model\ResourceModel\Website\CollectionFactory as WebsiteCollectionFactory;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Store\ViewModel\SwitcherUrlProvider;
class StoreSwitchModel extends SwitcherUrlProvider
{
const LOCALE_CONFIG_PATH = 'general/locale/code';
const DEFAULT_COUNTRY_CONFIG_PATH = 'general/country/default';
private $websiteCollectionFactory;
private $scopeConfig;
private $translatedLists;
private $storeManager;
public function __construct(
EncoderInterface $encoder,
StoreManagerInterface $storeManager,
UrlInterface $urlBuilder,
WebsiteCollectionFactory $websiteCollectionFactory,
ScopeConfigInterface $scopeConfig,
TranslatedLists $translatedLists
) {
parent::__construct($encoder, $storeManager, $urlBuilder);
$this->websiteCollectionFactory = $websiteCollectionFactory;
$this->scopeConfig = $scopeConfig;
$this->translatedLists = $translatedLists;
$this->storeManager = $storeManager;
}
public function getWebsite()
{
return $this->storeManager->getWebsite();
}
public function getWebsites(): WebsiteCollection
{
return $this->websiteCollectionFactory->create();
}
public function getStoreLocale(StoreInterface $store): string
{
$locale = $this->scopeConfig->getValue(self::LOCALE_CONFIG_PATH, ScopeInterface::SCOPE_STORE, $store->getId());
return $locale;
}
public function getStoreCountryCode(StoreInterface $store): string
{
return $this->scopeConfig->getValue(
self::DEFAULT_COUNTRY_CONFIG_PATH,
ScopeInterface::SCOPE_STORE,
$store->getId()
);
}
}
Created the following file at
/app/code/{vendor}/{module}/etc/frontend/di.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Store\ViewModel\SwitcherUrlProvider" type="[Vendor]\{Module}\ViewModel\StoreSwitchModel" />
</config>
And updated the child_theme languages.phtml at
{vendor}/{child_theme}/Magento_Store/templates/switch/languages.phtml
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
// @codingStandardsIgnoreFile
/** @var \Magento\Store\Block\Switcher $block */
?>
<?php
/** @var \Magento\Store\Block\Switcher $block */
$viewModel = $block->getData('view_model');
$websites = $viewModel->getWebsites();
$websiteid = $viewModel->getWebsite()->getWebsiteId();
?>
<div class="switcher store switcher-store" id="switcher-store">
<strong class="label switcher-label"><span><?php echo __('Select Store') ?></span></strong>
<div class="actions dropdown options switcher-options">
<?php foreach ($websites as $website): ?>
<?php if ($websiteid == $website->getId()): ?>
<div class="action toggle switcher-trigger"
role="button"
tabindex="0"
data-mage-init='{"dropdown":{}}'
data-toggle="dropdown"
data-trigger-keypress-button="true"
id="switcher-store-trigger">
<strong>
<span><?php echo $block->escapeHtml($website->getName()) ?></span>
</strong>
</div>
<?php endif; ?>
<?php endforeach; ?>
<ul class="dropdown switcher-dropdown" data-target="dropdown">
<?php foreach ($websites as $website): ?>
<?php if (!($websiteid == $website->getId())): ?>
<li class="switcher-option view">
<a href='<?php echo $website->getDefaultStore()->getBaseUrl() ?>'>
<?php echo $block->escapeHtml($website->getName()) ?>
</a>
</li>
<?php endif; ?>
<?php endforeach; ?>
</ul>
</div>
</div>
This shows the website switcher instead of a store switcher.
Best Answer
Yes there is you can use a view model for this. The view model will come in handy for your second question too.
You can declare your view model like this:
In your template languages.phtml you can use the folloing code:
In your module you'll have to set a preference for
\Magento\Store\ViewModel\SwitcherUrlProvider
:app/code/[Vendor]/[Module]/etc/frontend/di.xml
We did not implement this but we are displaying the language and the country in the switcher. By having the according images you could use either the store locale or the store country code to determine the country or language you want to display and adjust the template as needed.
In
ViewModel
from above you can use the functionsgetStoreLocale()
andgetStoreCountryCode()
for that.Update:
The Problem why it didn't work before was that Magento already passes a view model. You can extend the StoreSwitchModel by Magentos and set a preference to use yours. With this approach you don't need to pass the view_model in
default.xml
.I tested this code on a fresh Magento 2.3.2 install.
Update 2:
Yes it is. I didn't take that into account. This is what
\Magento\Store\ViewModel\SwitcherUrlProvider
is there for. I updated the code onlanguages.phtml
and on the<a>
is now$viewModel->getTargetStoreRedirectUrl($website->getDefaultStore())
used to retrieve the correct redirect url based on the current page.