4

I'm trying to generate the href links for our multilingual Magento 2 site, and as the category slug changes, I cannot simply replace the store code in the URL.

I've code is given below :

        $category = $this->_registry->registry('current_category');

        if (!$category->getId()) {
            throw new LocalizedException(__('Failed to initialize category'));
        }

        $categoryId = $category->getId();

        foreach ($this->_storeManager->getStores() as $store) {
            $locale = $this->_scopeConfig->getValue('general/locale/code', \Magento\Store\Model\ScopeInterface::SCOPE_STORE, $store->getStoreId());
            $category->setStoreId($store->getStoreId());
            $category->load($categoryId);

            if($category->getIsActive())
            {
                $output[$locale] = $category->getUrl();
            }
        }

It seems to work except that the $category->getUrl() always return the current store URL, even if I loaded the category from another store. Is it a bug or should I do something else?

So how get multiple store category URL ?

3 Answers 3

4

It seems to work except that the $category->getUrl() always return the current store URL, even if I loaded the category from another store. Is it a bug or should I do something else?

I've just encountered the same issue in Magento 2.3.3, It looks like an issue in the Category Model where the Url is loaded for a different store.

I ended up by setting the storeId on the UrlInstance before loading the url:

$category = $this->categoryRepository->get($categoryId, $storeId);
$category->getUrlInstance()->setScope($storeId);
$url = $category->getUrl();

// Exprienced issue : Fixed, Need to reset current store id so in page after this call, we will get proper store data
$category->getUrlInstance()->setScope($currentStoreId);

But I think this still should be fixed in the core model Category::getUrl().

Hope this will help.

3
  • Works like a charm, thank you. Commented May 28, 2020 at 18:44
  • @thedotwriter once get the store specific category URL after that we need to reset current store scope $category->getUrlInstance()->setScope($currentStoreId); so in page if some where we are using other data url from current store so we can proper data. Commented Jun 1, 2020 at 13:23
  • That's kind of an edge case but another issue with Category::getUrl() is that you cannot generate a URL for a category for two different stores in the same request, it will always return the first generated URL. That's because getUrl() uses getUrlInstance() (which is a \Magento\Framework\Url singleton) to cache generated URLs. To "fix" that I made a copy of Category::getUrl() inside my custom class and made sure my version of the function uses a fresh instance of getUrlInstance() each time my script changes store. Commented Jun 1, 2020 at 18:43
1

The best solution I found so far comes from the following GitHub Magento 2 Seo module: https://github.com/staempfli/magento2-module-seo/

Especially from this class: https://github.com/staempfli/magento2-module-seo/blob/develop/Service/HrefLang/CategoryUrlRetriever.php

/**
 * @param int $identifier the category ID
 * @param Store $store
 * @return string
 */
public function getUrl($identifier, $store)
{
    /** @var Category $category */
    $category = $this->registry->registry('category');
    if(!$category) {
        $category = $this->categoryRepository->get($identifier, $store->getId());
    }
    $path = $this->categoryUrlPathGenerator->getUrlPathWithSuffix($category);
    return $store->getBaseUrl() . $path;
}

Where $this->categoryUrlPathGenerator is the object of Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator

0

You should use the category repository to load the category for a specific store.

Inject the category repository in your constructor (alternative use the object manager):

\Magento\Catalog\Model\CategoryRepository $categoryRepository,

In your foreach loop replace the the category loading with the following:

$category = $this->categoryRepository->get($categoryId, $store->getStoreId());
3
  • The category gets loaded, but the url returned when I call getUrl on it is still the url on the current loaded store.
    – werfu
    Commented Mar 7, 2019 at 14:14
  • Can you check for a category for which you get the wrong url what's in the url_rewrite table? Run the following SQL: select * from url_rewrite where entity_type = 'category' and entity_id = [YOUR CATEGORY ID]?
    – HelgeB
    Commented Mar 7, 2019 at 14:28
  • There's a rewrite for each store, albeit the requested path seemingly not ok. However this doesn't explain why the returned URL contains the current store code in the URL instead of the one I've passed to the get call. I must say though that the rewrite system seems very broken on the site, some products having lost their rewrite and only being accessible through built-in route.
    – werfu
    Commented Mar 7, 2019 at 14:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.