6

I am having a very strange issue where I have a menu item called /foo which loads article Item 1. Now if I do /foo/2, I would expect this to generate a 404 page since I don't have a sub menu item '2' under the parent menu item /foo. Yet instead of showing a 404 page it is somehow loading the content of Article 2 under the same menu item.

I have checked the .htaccess and it is just the normal one that came with Joomla and can't figure out why this could be happening. If I try to put any article ID that does not exist in the database, then it shows the 404. Any pointers would be great!

1 Answer 1

2

Ahhh the joys of the current routing system in Joomla. (I thought I heard that someone was doing a Google Summer of Code project to update the routing system, but haven't seen anything else on that.)

So my understanding of the routing is that Joomla will try to parse as much of the request uri (ie. foo/2) to a menu item as possible. In your case, this would match on just foo.

Next, the rest of the pieces are passed to the router.php file for the component that matches that menu item. In your case, I'm guessing that this is the com_content router at components/com_content/router.php.

This will call the parse function in this class and pass in the segments (which in this case will just be 2.

The router has code (which you can look through if you would like) to try to parse the segments in the uri into article ids and such. The core piece that affects you is what happens if there is only one segment piece:

/*
     * If there is only one segment, then it points to either an article or a category.
     * We test it first to see if it is a category.  If the id and alias match a category,
     * then we assume it is a category.  If they don't we assume it is an article
     */
    if ($count == 1)
    {
        // We check to see if an alias is given.  If not, we assume it is an article
        if (strpos($segments[0], ':') === false)
        {
            $vars['view'] = 'article';
            $vars['id'] = (int) $segments[0];

            return $vars;
        }

        list($id, $alias) = explode(':', $segments[0], 2);

        // First we check if it is a category
        $category = JCategories::getInstance('Content')->get($id);

        if ($category && $category->alias == $alias)
        {
            $vars['view'] = 'category';
            $vars['id'] = $id;

            return $vars;
        }
        else
        {
            $query = $db->getQuery(true)
                ->select($db->quoteName(array('alias', 'catid')))
                ->from($db->quoteName('#__content'))
                ->where($db->quoteName('id') . ' = ' . (int) $id);
            $db->setQuery($query);
            $article = $db->loadObject();

            if ($article)
            {
                if ($article->alias == $alias)
                {
                    $vars['view'] = 'article';
                    $vars['catid'] = (int) $article->catid;
                    $vars['id'] = (int) $id;

                    return $vars;
                }
            }
        }
    }

Basically, it checks to see if it is a category id or an article id. Since you have an article with the id 2, it passes and thus we now move forward with that as the id instead of whatever you sent in the menu id.

This is exactly what com_content was coded to do, for better or worse... :/

2
  • Thank you David for the detailed explanation. Makes sense although as I found out, even with a small mistake; it's a total SEO hazard since if someone has a link like foo.com/1; it loads article id 1's title yet still loading the homepage (/). While there is rel=canonical /id=1, since the content is the same, it created a whole load of duplicate content issue. But in any case, marking it as an answer since the explanation adequately explains why it happens.
    – sifu
    Sep 12, 2014 at 16:34
  • Yeah, it is definitely not ideal, but I have yet to see a system as flexible as the current one that can be more precise. It would be a big boost to get one integrated in the core! Sep 12, 2014 at 17:09

Your Answer

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

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