Using Joomla Custom Fields to Add Canonical URLs

Joomla Logo

In this article, we are going to add a new field to the article editor screen and use the content of the field to output a canonical link in the head of the page on the article view.

At some point, Joomla's automatically added canonical links were removed as they didn't work correctly, so this is a manual workaround to put them back.

NOTE: As this is a manual process, if you ever change the URL of your page then you NEED to update the canonical field to match. If you have canonical links that point to a 404 page or another page with different content then this could do more damage than it fixes.

OK, so Joomla has added custom fields in 3.7 which makes it easy to add new fields to the admin area and store the data without having to create a plugin. We start by creating the field.

There are 2 areas for custom fields, 'Fields' and 'Field Groups'. Both can be found under the content menu in the top bar.

Joomla custom fields menu

I've started in the 'Field Groups' area and created a new group called 'SEO'. The only field that is needed here is the title. This creates a new tab area above the article editor.

Joomla new custom field group edit screen

Now we have the group, it's time to add the field.

Add a New Field

In the fields listing screen, click the new button to create a new field.

The General Tab

Joomla custom field settings for canonical URL

I'm naming my field 'Canonical URL' and filling in the description with a brief note about what it's for 'Adds a canonical link to the head of the document.'.

We could leave the field type as the default 'text' field, but using 'URL' will give us some validation before the field is saved to avoid any easy mistakes. After changing the field, a few more options will appear, which you can see in the screenshot above.

In this case the label is the same as the title, but you can make that whatever you want.

Required is set to no so that people can save an article without being forced to fill in the field (You may not even know what the url should be when writing the article or draft).

'Default value' is left blank as we don't want anything saved if the field is empty.

In 'Schemes', select 'http' and 'https'. Since this is a web application, pages will always be one of these 2 protocols.

Set relative to no as canonical links should always be a full valid page URI.

On the right, select the new 'SEO' field group we just created and either leave the category set to all or change it to only show on the categories where you want the field available..

The Options Tab

Joomla custom field options tab

You can fill in the placeholder field or just leave it blank. This adds placeholder text in the field input on supported browsers (Anything modern).

'Show on' is set to both so the field can be edited in the backend and when using frontend editing.

Make sure that 'Automatic Display' is set to 'No'. If this is set to anything else then Joomla will insert the content of the field into the article which is not what we want to happen. We only want to use the field to create the head link.

And that's it for the field, save it and then take a look at an article edit screen.

Joomla field group in article edit screen

If all went well, you should see a new 'SEO' tab in the editor area with our new url field.

Using the Field on the Frontend

Now we can save our canonical URLs, we need to get that information back on the frontend of the site so that we can use it to create our link.

The first thing we need to do is create an override for the article layout so our changes don't get wiped on an update.

NOTE: Make sure that your template doesn't already have an override in place before using the admin area as it may overwrite it. If you do have an override already, you can use that file or you can create an alternative layout so that the file isn't changed when you update your theme. To create an alternative layout, see this article for a practical example.

You can find more information about Joomla template overrides here: https://docs.joomla.org/Understanding_Output_Overrides

You can create the overrides manually but Joomla also has a way to add them in the administration area in 'Extensions' >Templates > Templates > Click on the title of your template > 'Create Overrides' tab.

Create template override in Joomla template manager

To manually create the override, in your template folder, if the following directory doesn't exist then create it:

html/com_content/article/

Then copy the file from the following location and move it into that folder:

components/com_content/views/article/tmpl/default.php

This is the file that we are going to use to check for the contents of the field and add our new link.  Open up the file in a code editor or notepad (Or your operating systems equivalent program).

You can find the Joomla documentation about how to get the field values here: https://docs.joomla.org/J3.x:Adding_custom_fields/Overrides

The docs basically say that the custom fields are attached to the $item variable and then goes on to explain another way to render the fields directly. This isn't strictly true as $item doesn't exist and if you try and use it you will get an error, but like the other information in the default.php file, it is available in $this->item.

If we dump $this->item, we can see the field even if it is blank:

 ["jcfields"]=>
  array(1) {
    [1]=>
    object(stdClass)#457 (31) {
      ["id"]=>
      string(1) "1"
      ["title"]=>
      string(13) "Canonical URL"
      ["name"]=>
      string(13) "canonical-url"

I won't add the full content here, but if you want to see what's available you can add

var_dump($this->item);

into the file and then load a page to see the content.

Since we only want to check for the value, we can ignore the part in the docs about using the render helper and just check for the field content directly.

As jcfields contains a keyed array of objects, the easiest way to get the field content is going to be by looping over the fields to find the one we want.

The following code will loop through all of the fields until it finds one with a title of 'Canonical URL', if it finds one then it will echo the value of the field where ever you place the code in the article override. After we've found the field, we add a continue statement to break out of the loop and ignore all the other fields in the array.

foreach ($this->item->jcfields as $field) {
	if ($field->title === 'Canonical URL') {
		echo $field->rawvalue;
		// Break out of the loop when we have what we need
		continue;
	}
};

Joomla basic custom field output

Now we can get the content of the field we can check if it is an empty string or if it has a value. If it has a value then we add the link to the head of the document.

To add the link, we use Joomla's 'custom tag' code which we can copy pretty much directly from the documentation here: https://docs.joomla.org/J3.x:Adding_JavaScript_and_CSS_to_the_page#Add_Custom_Tag

The following snippet can go anywhere in the default.php file after the line:

defined('_JEXEC') or die;

Full Snippet

//Check custom fields for canonical link
foreach ($this->item->jcfields as $field) {
	if ($field->title === 'Canonical URL') {
		//Make sure the field isn't empty
		if ($field->rawvalue !== '') {
			$canonicalLink = '<link rel="canonical" href="' . $field->rawvalue . '" />';
			$document = JFactory::getDocument();
			$document->addCustomTag($canonicalLink);
		}
		continue;
	}
};

You can make this a little more robust by checking for if ($field->id === 1) { and change the 1 to match the id of your field. That way it won't matter if the title of the field changes in the future, the code will still work without needing to be edited.

And voila, we have a canonical link in the head of the document:

Joomla custom canonical field result

Another Word of Warning

To reiterate the point, if you change the url of a page then you NEED to update the content of the field to match or you could do your site more damage than good.

If you do something like change the site's protocol from http to https or change domain name then you would need to either manually update all the fields, run a database query to change them, or use a search and replace script/extension to change all the urls to the right protocol/domain.

If you have users of your site who shouldn't be touching this option then you can use the permissions parameters in the field configuration screen to only allow certain users to edit the field.

Make sure you have your site registered with sites like Google webmaster tools and the equivalent with other search engines which can warn you if they notice anything wrong with the canonicals.