Joomla! has capability of creating and parsing URLs as SEF (Search Engine Friendly) URLs. The SEF URLs follow a certain fixed pattern. User can define a short descriptive text (known as alias) for each segment of the URL.

In Joomla, the local part of a SEF URL (the part after the domain name) is called a route. Creating and processing SEF URLs is referred to as routing, and the relevant code is called a router. Each component is responsible for handling its own SEF URLs. So, you have to create your own router to allow your component to use SEF URLs.

SEF Concept in Joomla

Joomla system URLs look like this:

http://www.example.com/index.php?option=com_yourcomponent&view=article&id=1&catid=20&Itemid=50

Your goal is to transform this into SEF URL like this:

 http://www.example.com/example-menu-item/example-category/example-article

You have two tasks: Signalling the system that certain pieces of text are URLs and need to be transformed, and explaining the system how to transform URLs.

JRoute::_

It is difficult for Joomla system to figure out which parts of the component's output are URLs. To support SEF URLs, you need to change URL-generating code. For example,

JRoute::_('index.php?view=article&id=1&catid=20');

You can leave out the parameters option and Itemid. option defaults to the name of the component currently being executed, and Itemid defaults to the current menu item's ID.

Router

Router is a single file containing a class with three functions that convert system URLs to and from SEF URLs. This file needs to be placed at site part of the component:

/components/com_componentname/router.php

The class is called [componentname]Router

For example for com_content, ContentRouter, and must implement Joomla\CMS\Component\Router\RouterInterface

First Function: build(&$query)

It transforms an array of URL parameters into an array of segments that will form the SEF URL. It converts system URLs to SEF URLs. 

Second Function: parse($segments)

It transforms an array of segments back into an array of URL parameters. It converts SEF URLs to system URLs.

The two functions must cooperate in such a way that the original URL can be reconstructed. Any URL format needs to contain some kind of information that identifies the data you want to show. Generally, in the system URLs, this information is stored in the id URL parameter (for example, id=1). You can also use SEF URLs to contain a textual description of the data they point to. In Joomla, this is done by giving your users a way to enter an alias to be used in the URL.

Third Function: preprocess($query)

It is a preparation method for URLs. This method is executed on each URL, regardless of SEF mode switched on or not.

Slug

A slug is used to minimise the amount of code you need to support SEF URLs. Slug consists of the numerical identifier (id), a colon (:), and the alias.

For example, consider a SEF URL for an article with

  • id - 1
  • title - Welcome to Earth
  • automatically generated alias - welcome-to-earth
  • slug - 1­:welcome­-to­-earth

The two elements (id and alias) can be combined during the database query in the model like this:

$query = 'SELECT a.*, '.
'CASE WHEN CHAR_LENGTH(a.alias) THEN CONCAT_WS(":", a.id, a.alias) ELSE a.id END as slug,'
/*...*/;

The advantage of this method of creating a slug is that you can simply use the slug as a drop-in replacement for the id in most places. For example, you don't need to check for and remove the colon and the alias from the request data manually: if you use JInput's int (integer) filter, it will do that automatically.

The building process of \Joomla\CMS\Router\Router is divided into two steps:

1. Create the application route: The application route is fully handled by \Joomla\CMS\Router\Router and the component developer doesn’t have to do anything to make it work.

2. Create the component route. To create the component route, \Joomla\CMS\Router\Router looks for the router.php in the component directory which is responsible for building the route for the component.

Component Router

In general, there can be three views:

  1. The first is a categories overview (view=categories)
  2. The second is a single category (view=category)
  3. The third is a single article (view=article)

URL Structures

When viewing an article:

http://www.example.com/[menualias]/[category]/[article]

The link to the article would look like this:

index.php?view=article&catid=' . $row-­>catslug . '&id='.$row-­>slug

When viewing a category:

http://www.example.com/[menualias]/[category]

he Link to the category would look like this:

index.php?view=category&id=' . $row->catslug

When viewing the categories overview:

http://www.example.com/[menualias]

BuildRoute Function

JRouter passes a $query array to the [componentname]BuildRoute function. This function adds the relevant parts of the array to the $segments array in the right order and returns the properly ordered array. The content of the $query array needs to be unset, otherwise JRouter will add it to the URL in the form of a query string.

For example, $query array is something like this:

$query = array('view' => 'article', 'id' => 1, 'catid' => 20)

The function is like:

function [componentname]BuildRoute(&$query)
{
$segments = array();
if (isset($query['view']))
{
$segments[] = $query['view'];
unset($query['view']);
}
if (isset($query['id']))
{
$segments[] = $query['id'];
unset($query['id']);
};
return $segments;
}

ParseRoute Function

The function is like this:

function [componentname]ParseRoute($segments)
{
$vars = array();
switch($segments[0])
{
case 'categories':
$vars['view'] = 'categories';
break;
case 'category':
$vars['view'] = 'category';
$id = explode(':', $segments[1]);
$vars['id'] = (int) $id[0];
break;
case 'article':
$vars['view'] = 'article';
$id = explode(':', $segments[1]);
$vars['id'] = (int) $id[0];
break;
}
return $vars;
}

from the BuildRoute function, you know that the view is first and the id is second in the array. By reading $segments[0], you can access the name of the view. Then, you set the right view and identifier (if applicable) and finally return the $vars array to JRouter. 

The generated URL contains the name of the view and doesn't reflect the content hierarchy:

http://www.example.com/[menualias]/[view]/[slug]