3

I try to load categories in the admin area with store specific values.

$this->categoryCollectionFactory->create()
    ->setStoreId($storeId)
    ->addAttributeToSelect(['name', 'url_key']);

This works so far, but I don't get the right base URL with $category->getUrl() if the given store has a different base URL than the admin store.

I checked the Category::getUrl() method and found out that the store ID is used to determine the correct URL rewrite, but when it's found,

$this->setData('url', $this->getUrlInstance()->getDirectUrl($rewrite->getRequestPath()));

The second argument $params of getDirectUrl() should receive the scope somehow but it doesn't. So when the base URL is determined, there is no informtion about the current store.

This looks like a bug to me, but is there any way to work around this?


bugfix attempt 1

I traced down the location where the base URL is determined and it's in Magento\Framework\Url::getRouteUrl:

return $this->getBaseUrl() . $routeParams['_direct'];

getBaseUrl() takes a $params argument where the store id can be passed with the _scope key, but here the argument is empty, so adding '_scope' => $storeId to the $params argument in the line from the category model above, would not help either.


bugfix attempt 2

I tried to pass the parameters along to getBaseUrl() in the line above:

return $this->getBaseUrl($routeParams) . $routeParams['_direct'];

And now getBaseUrl() sets its scope to the given store id:

$this->setScope($params['_scope']);

This loads the correct store model and assigns it to $this->data['scope']

But to my surprise, a few lines later in $this->_getScope()->getBaseUrl(), the scope was the admin store again. Why? _getScope() does not access $this->data['scope'] but $this->_scope ... this is special behavior of Magento\Backend\Model\Url because there is only one scope for backend URLs.

So here's the next problem: the category should not have been associated with a Backend URL model in the first place. But this apparently happens for any object that receives a \Magento\Framework\UrlInterface as constructor argument when created in admin area context.


bugfix attempt 3

I tried Magento\Framework\App\State::emulateAreaCode() around the category loading, but still the backend model is used. Found a similar question, Magento 2 get frontend store url for a path in admin, but the recommended solution is to inject a concrete frontend URL instance via preferences or constructor parameter. I don't know if this is a good idea for the core category model.

I tried it anyways, with the following in my module's etc/adminhtml/di.xml:

<type name="Magento\Catalog\Model\Category">
    <arguments>
        <argument name="url" xsi:type="object">Magento\Framework\Url</argument>
    </arguments>
</type>

And together with the two core hacks bugfixes from before, I'm getting the correct URLs.

So far, so good. Now I need a real solution :)

  • We are already getting $rewrite = $this->urlFinder->findOneByData([ UrlRewrite::ENTITY_ID => $this->getId(), UrlRewrite::ENTITY_TYPE => CategoryUrlRewriteGenerator::ENTITY_TYPE, UrlRewrite::STORE_ID => $this->getStoreId(), ]); if ($rewrite) { $this->setData('url', $this->getUrlInstance()->getDirectUrl($rewrite->getRequestPath())); Profiler::stop('REWRITE: ' . __METHOD__); return $this->getData('url'); } Store Wise URL. RIght? So – Ankit Shah Sep 27 '16 at 9:18
  • No. That line only returns the store specific request path without the base URL. – Fabian Schmengler Sep 27 '16 at 9:22
  • Any solution on this? – MadzQuestioning Feb 11 at 15:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.