14

I have a menu item for a specific view in a custom component. Attached to this menu item I have another Template Style selected, not the standard template. Accessing the view via the menu works well, as it's attaching to the URL the Itemid.

Now I want to link, using JRoute, a view with another one, however JRoute is not generating the desired URL.

echo JRoute::_('index.php?option=com_example&view=reporting');

/index.php?option=com_example&view=reporting

JRoute will not append the Itemid to the URL, causing the selected template style for the menu item not to work.

Is there a way to "calculate" the Itemid (apart from doing a query in the table jos_menu on the column link) and to attach it to JRoute?

1
  • if u know the itemid than do , reporting&Itemid=123. I dont advise this procedure since your custom component should do this automatically if it is already published.
    – Dan
    May 7, 2014 at 12:11

4 Answers 4

20

Here is a technique I used (cannot remember where I found it).

$app = JFactory::getApplication(); 
$menu = $app->getMenu();
$menuItem = $menu->getItems( 'link', 'index.php?option=com_example&view=reporting', true );
echo JRoute::_('index.php?Itemid='.$menuItem->id);

This has worked wonders for me.

4

the output from JRoute will depend on what you feed it.

JRoute::_("index.php?option=com_content&view=article&id=10"); 

might return something else than

JRoute::_("index.php?option=com_content&view=article&id=10&catid=5"); 

In fact if you have a menu item category blog listing for catid=5, the latter might give you the menu-url (I have not tested this exact url). Try with different get-parameters to get different results (sometimes very wrong, like @Fedik said)

3

The key here is to set up your components router.php file (which should be found in the root folder of your component on the front end) with logic that will search for and select the appropriate menu item. I would love to see this automatically happen, but as far as I know this isn't the case.

It would probably be best to work this block of code in to some type of helper function that can be used to automatically find the best fit menu item for the content.

Here is the code that I have used in several of my custom components to get the best fit menu item:

// I use this first empty array to avoid having unset properties in my query
$base_array = array('Itemid'=>'', 'option'=>'', 'view'=>'', 'layout'=>'', 'id'=>'');

$app =& JFactory::getApplication();
$menu       = $app->getMenu();
$active = $menu->getActive();

// hack to protect the actual current item as well as the search module or other places that use JRoute::_('index.php');
if (count($query)==2 && isset($query['option']) && isset($query['Itemid']) && $query['option'] && $query['Itemid']) {
    return $segments;
}

// start with no match found
$match = false;
$match_level = 0;

$query += $base_array;

// we want to find a menu item for this if possible. If the active menu item is the current menu item then we should see if there is a better match.
if (empty($query['Itemid']) || ($query['Itemid'] == $active->id && empty($query['task']))) {
    // load all menu items
    $items = $menu->getMenu();

    // use the current item over others if it ties for the best match
    if ($active->query['option'] == $query['option']) {
        $match_level = 1;
        $match = $active;
        if ($active->query['view'] == $query['view']) {
            $match_level = 2;
            if ($active->query['layout'] == $query['layout'] || ($query['layout']=='default' && !$active->query['layout'])) {
                $match_level = 3;
                if ($active->query['id'] == $query['id']) {
                    $match_level = 4;
                }
            }
        }
    }

    // loop through each menu item in order
    foreach ($items as $item) {
        $item->query += $base_array;
        // base check is that it is for this component
        // then cycle through each possibility finding it's match level
        if ($item->query['option'] == $query['option']) {
            $item_match = 1;
            if ($item->query['view'] == $query['view']) {
                $item_match = 2;
                if (!$query['layout'] && $item->query['layout']) {
                    $query['layout'] = 'default';
                }
                if ($item->query['layout'] == $query['layout'] || ($query['layout']=='default' && !$item->query['layout'])) {
                    $item_match = 3;
                    if ($item->query['id'] == $query['id']) {
                        $item_match = 4;
                    }
                }
            }
        }

        // if this item is a better match than our current match, set it as the best match
        if ($item_match > $match_level) {
            $match = $item;
            $match_level = $item_match;
        }

    }

    // if there is a match update Itemid to match that menu item
    if ($match) {
        $query['Itemid'] = $match->id;
        $menuItem = $menu->getItem($match->id);
    } else {
        $menuItem = $menu->getActive();
    }
}

All of this is kind of a mess (and I would love improvements if anyone has them!), but it gets the job done. If the current menu item is the best match, it will always stick with that.

Otherwise it should find the best match based on Component name -> view name -> layout name -> id value. The further to the right it matches, the better I deem the match!

2

Afaik JRoute will take the active Itemid (and also the active option) if none is provided. If that doesn't work, it means that the call to your code comes without Itemid to begin with. If so, the easiest thing would be to add the Itemid to the intial call.

If you need to look up the menu item, I would not do a direct query but use JMenu instead.

1
  • I noticed that in some cases JRouter can return some crazy URL, if try provide own Itemid, example for JRoute::_('index.php?option=com_example&view=reporting&Itemid=10') JRouter can return /current-path?view=reporting&Itemid=10 ... is there some specific things?
    – Fedik
    May 7, 2014 at 12:48

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.