The error shows up for me using a custom front end component that is a simple menu item displaying a list of records with a simple URI to edit each record that has the &Itemid=
suffixed to each URI by SiteRouter.php
as the page is created.
Without the &Itemid in the link a Save or Cancel when editing the record returns to the default Menu as the default because it doesn't know the Id of the current or active menu.
Links on the page to edit the first record under Joomla 3
/index.php?option=com_sales&task=order.editNC&id=1&Itemid=156
Links on the page to edit the first record under Joomla 4
/index.php?option=com_sales&task=order.editNC&id=1
Joomla 4.0.4
PHP 7.4
Local Development Environment
Default installation plus my custom components only.
This may not be an issue but a feature of the Joomla 4 routing but I can't find anything that explains the alternative or why, however the bits of code that do exists suggest that it might just be an over sight.
In Joomla 4 the /library/src/Router/SiteRouter.php
has a new method, buildInit
, that replaces the createInit
method of Joomla 3. In appearance they do the same thing, suffix the URL with the Itemid=(the value of the current/active menu item) to links on the page, however the logic has changed and it no longer handles a missing ItemId= correctly or at least in the same way as Joomla 3.
public function buildInit(&$router, &$uri)
{
$itemid = $uri->getVar('Itemid');
// If no Itemid and option given, merge in the current requests data
if (!$itemid && !$uri->getVar('option'))
{
$uri->setQuery(array_merge($this->getVars(), $uri->getQuery(true)));
}
// If Itemid is given, but no option, set the option from the menu item
if ($itemid && !$uri->getVar('option'))
{
if ($item = $this->menu->getItem($itemid))
{
$uri->setVar('option', $item->component);
}
}
}
In the above code if $itemid is Null or not set AND the $uri contains an valid Option param then it will never meet either of the first level IF statements and the method will complete without ever getting the $itemid.
Compared to the Joomla 3 version posted below there seems to be a block of code missing that would at least get to this statement to get the active menu id
$item = $this->menu->getItem($this->getVar('Itemid'));
and set the $itemid
$uri->setVar('Itemid', $item->id);
In /libraries/src/Router/SiteRouter.php
for Joomla 3 the createInit
method where I have highlighted, <===, the lines that are missing in Joomla 4.
protected function createUri($url)
{
// Create the URI
$uri = parent::createUri($url);
// Get the itemid form the URI
$itemid = $uri->getVar('Itemid');
if ($itemid === null) <==
{
if ($option = $uri->getVar('option'))
{
$item = $this->menu->getItem($this->getVar('Itemid')); <==
if ($item !== null && $item->component === $option) <==
{
$uri->setVar('Itemid', $item->id); <==
}
}
else
{
if ($option = $this->getVar('option'))
{
$uri->setVar('option', $option);
}
if ($itemid = $this->getVar('Itemid'))
{
$uri->setVar('Itemid', $itemid);
}
}
}
else
{
if (!$uri->getVar('option'))
{
if ($item = $this->menu->getItem($itemid))
{
$uri->setVar('option', $item->component);
}
}
}
return $uri;
}
This issue on JSE is impacted by the same code, https://joomla.stackexchange.com/questions/31422/retrieve-active-menu-link-in-controller-frontend-joomla4, and one issue on Joomla Issue Tracker show similar symptoms and maybe related to this code.
Labels |
Removed:
?
|
Labels |
Added:
No Code Attached Yet
|
Is this the closest thing to up to date information about the router in Joomla 4? I see a few other issues in the past year or so pointing people to this documentation, is it still current?
@Fedik, I don't have my own router I am using what I believe to be the default one, Joomla\CMS\Router\Route.
The current behavior is the expected behavior. There are serious issues with defaulting to the current Itemid for any given URL. It is one of the big reasons for "duplicate content" in Joomla among other things.
Status | New | ⇒ | Expected Behaviour |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2021-10-28 20:24:43 |
Closed_By | ⇒ | richard67 |
Closing as expected behaviour. Feel free to re-open if you think this is wrong.
Please re-open. The duplicate content issue is bs. At a minimum this expected behaviour must be documented somewhere other than in one persons head.
Status | Expected Behaviour | ⇒ | New |
Closed_Date | 2021-10-28 20:24:43 | ⇒ | |
Closed_By | richard67 | ⇒ |
Re-opening due to previous comment.
Title |
|
It is not is expected behaviour to me as the backward compatibility page for J4 makes no mention to the extent of changes you have to make to an existing component to overcome the removal of this default behaviour that a lot of existing code relies on. Any documentation on the 'modern' router seems to be updated J3.x articles but still no mention that $Itemid was no longer going to be handled and there is noting other than a few comments I have seen that says MenuRules class will now handle it.
I want to move sites to Joomla 4 so I can start developing new code with Joomla 4 therefore I have a choice of either spending days or weeks reworking a lot code to make it work under both Joomla 4 and Joomla 3 just to get around this issue, sorry expected behaviour, or I put these few lines of code into SiteRouter.php so I can move sites to Joomla 4 and deal with the older code as more useful documentation becomes availabletime and budget allows.
` if (!$itemid)
{
$item = $this->menu->getItem($this->getVar('Itemid'));
if ($item !== null && $item->component === $uri->getVar('option'))
{
$uri->setVar('Itemid', $item->id);
}
}
`
I don't mind whether you close this issue or leave it open, however I have unfortunately spent too many days already getting to this point to waste any more time on it, I know enough now to proceed to Joomla 4 and hopefully this issue will assist others that find their way here looking for an answer why $Itemid is missing in Joomla 4.
I don't have my own router
How do you build your URLs then?
It is not is expected behaviour to me as the backward compatibility page for J4 makes no mention to the extent of changes you have to make to an existing component to overcome the removal of this default behaviour that a lot of existing code relies on.
It is expected for J4.
You have to set Itemid in preprocess()
in your router. (Or use new router rule Joomla\CMS\Component\Router\Rules\MenuRules
), look my previous comment. It not a "big change".
@Fedik My apologies, I do have a router.php that extends Joomla\CMS\Component\Router\RouterBase with a build and parse method that in their comments says they only come into play when SEF is on, which in this case it is not.
I now understand where your suggested preprocess method gets placed. I will report back when I have had a chance to play with it.
Thank you.
their comments says they only come into play when SEF is on
In new router the preprocess()
method will be called no mater if SEF On or Off.
If I right remember.
@Fedik, I was unable to get 'preprocess()' to work correctly using your sample in the other issue you mentioned without breaking some other links in the menu so I am just going to have to manage the extra lines of code I have added to buildInit until I can move to the newer router approach while running it under J4. Not ideal, but that is where I am at if I want to use Joomla 4.
I was able to find this reference to the change, #12168, back in 2016 and there it is acknowledged it will cause a B/C issue but that hasn't made it through to the more recent documentation available.
I am okay with this being closed as expected behaviour.
I was unable to get 'preprocess()' to work correctly using your sample in the other issue you mentioned without breaking some other links
I think for your case, to mimic old behavior it need more simple than in my example.
Kind of this:
public function preprocess(&$query)
{
if (!isset($query['Itemid']))
{
$query['Itemid'] = Factory::getApplication()->input->getInt('Itemid');
}
}
It will always add current Itemid
if there no one exists.
It not a right way to do routing, but may help for your case.
closed as expected
Status | New | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2021-11-03 10:21:38 |
Closed_By | ⇒ | Fedik |
you have to implement
preprocess(
) in your router, where assign correctItemid
,see discussion #35621