J4.x

Cassiopeia Template Simplified - A Case Study

From Joomla! Documentation

Joomla! 
4.x

Introduction[edit]

The Joomla 4 Forums often contain questions or comments such as:

  • How can I customise Cassiopeia?
  • How can I make a simple template for Joomla 4?
  • I don't want to use Bootstrap!

This tutorial tackles the second of the items in the list above. So what is a template and what is a simple template? In many respects, Cassiopeia is a simple template designed for general purpose display of web content consisting of Articles and supplementary information in the form of Modules.

A simple template might be considered as one with fewer module positions and fewer variables than Cassiopeia. But beware, if your simple template is intended for general purposes it is likely to start really simple but grow until it is as not so simple and without the expertise and testing that has gone into making Cassiopeia reliable. So a simple template could be considered as one with a very well defined use case and not for general purposes.

To understand what follows you should be familiar with the Cassiopeia template structure: [Cassiopeia Template Explained]

A Real World Use Case[edit]

I have a site used for one purpose only: presenting volunteer opportunities and allowing online registration in countries with member organisations. It went live just as Joomla 1.6 was released in 2011(?) and has evolved through Joomla versions 2.x and 3.x to 4.x. It is multi-lingual (16 languages) but uses a non-standard language management system and serves member branches in the far east and far west from a server based in Europe.

The site uses two module positions for the Menu and Footer. The brand includes a logo and page title beneath the menu. The overall appearance was designed and/or approved by committee!

The first site template was based on Beez3 and the second on Protostar. The current template started out with an early version of Cassiopeia but there was so much other component code to revise for Joomla 4 that the site template was neglected until early 2022. The important point here is that there is a very well defined use case that has been stable for years and is likely to remain so for years to come.

Not so obvious is the choice of icon set. I have tried both Fontawesome and Bootstrap icons and decided that I prefer the latter. The component code actually contains mark-up for both so I can switch templates for easy comparison. Also, I am comfortable with Bootstrap and because of the international nature of the site believe use of the Bootstrap cdn repositories may have performance advantages.

A very well defined use-case! I think it is worth noting that it took me two hours to create a working custom template based on Cassiopeia and the rest of the day to fix some issues I had not previously noticed.

File Structure[edit]

I used Eclipse PDT for all of the code development. This is my PHP Project file structure:

File Structure

  • The css folder contains the user.css file copied from the previous template.
  • The html folder is initially empty except for an empty index.html file needed for installation.
  • The images folder contains the site favicons, the logo and one other image used by the template style.
  • The js folder is initially empty except for an empty index.html file needed for installation.
  • The language folder contains an en-GB subfolder initially containing cassiopeia.ini and cassiopeia.sys.ini copied from language/en-GB. They are renamed tpl_xxx.ini and tpl_xxx.sys.ini and the content modified. The language files will be copied to to the site/languages/en-GB folder on installation.
  • The scss folder is initially empty except for an empty index.html file needed for installation.
  • The php files were copied from the Cassiopeia template.
  • The joomla.asset.json file was copied from Cassiopeia.
  • The templateDetails file was copied from Cassiopeia

I don't actually need the empty folders. They are there in case I decide to use them at a later date.

In the rest of this tutorial xxx is a placeholder for your own template name.

The templateDetails.xml File[edit]

Changes:

  • Change the meta data at the top of the file to suit this new template.
  • Change all instances of lower case cassiopeia to xxx.
  • Change all instances of upper case cassiopeia to XXX.
  • Remove the positions you do not want to use.
  • Remove any configuration fields that you do not want to use.

I left in the positions and configuration fields for now. I can remove them later when I am sure I don't want them.

The joomla.assets.json File[edit]

Edit this file to include what you need. None of the original content is present other than the part before "assets".

{
  "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
  "name": "xxx",
  "version": "4.0.0",
  "description": "This file contains details of the assets of the Xxx site template.",
  "license": "GPL-2.0-or-later",
  "assets": [
    {
      "name": "bootstrap5",
      "type": "style",
      "uri": "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
    },
    {
      "name": "bootstrap5",
      "type": "script",
      "uri": "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
    },
    {
      "name": "bootstrapicons",
      "type": "style",
      "uri": "https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.0/font/bootstrap-icons.css"
    },
    {
      "name": "template.user",
      "type": "style",
      "uri": "user.css",
      "dependencies": [
      ]
    }]
}

The index.php file[edit]

This is my index.php file:

<?php

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;

$app = Factory::getApplication();
$wa  = $this->getWebAssetManager();
$wa->useScript('bootstrap5')
->useStyle('bootstrap5')
->useStyle('bootstrapicons')
->useStyle('template.user');

// Browsers support SVG favicons
$this->addHeadLink(HTMLHelper::_('image', 'joomla-favicon.svg', '', [], true, 1), 'icon', 'rel', ['type' => 'image/svg+xml']);
$this->addHeadLink(HTMLHelper::_('image', 'favicon.ico', '', [], true, 1), 'alternate icon', 'rel', ['type' => 'image/vnd.microsoft.icon']);
$this->addHeadLink(HTMLHelper::_('image', 'joomla-favicon-pinned.svg', '', [], true, 1), 'mask-icon', 'rel', ['color' => '#000']);

$language = $app->getUserState('com_xxx.ini.language_joomla_code', 'en-GB');

?>
<!DOCTYPE html>
<html lang="<?php echo $language; ?>" dir="<?php echo $this->direction; ?>">
<head>
	<jdoc:include type="metas" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<jdoc:include type="styles" />
	<jdoc:include type="scripts" />
</head>

<body>
	<div class="row">
		<div class="col">
			<jdoc:include type="message" />
			<main>
				<jdoc:include type="component" />
			</main>
		</div>
	</div>

</body>
</html>

Seems I left in the use Text and use URI statements by accident. And, if you wish, instead inserting the viewport metadata as html you can add it with:

$this->setMetaData('viewport', 'width=device-width, initial-scale=1');

The $language= line is specific to the site using this template. Usually that line is omitted and the html line has lang="<?php echo $this->language; ?>".

The component.php file[edit]

This is used to display information without the menu, brand and footer:

<?php

defined('_JEXEC') or die;

use Joomla\CMS\Factory;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;

$app = Factory::getApplication();
$wa  = $this->getWebAssetManager();
$wa->useScript('bootstrap5')
->useStyle('bootstrap5')
->useStyle('bootstrapicons')
->useStyle('template.user');

// Browsers support SVG favicons
$this->addHeadLink(HTMLHelper::_('image', 'joomla-favicon.svg', '', [], true, 1), 'icon', 'rel', ['type' => 'image/svg+xml']);
$this->addHeadLink(HTMLHelper::_('image', 'favicon.ico', '', [], true, 1), 'alternate icon', 'rel', ['type' => 'image/vnd.microsoft.icon']);
$this->addHeadLink(HTMLHelper::_('image', 'joomla-favicon-pinned.svg', '', [], true, 1), 'mask-icon', 'rel', ['color' => '#000']);

$language = $app->getUserState('com_xxx.ini.language_joomla_code', 'en-GB');

?>
<!DOCTYPE html>
<html lang="<?php echo $language; ?>" dir="<?php echo $this->direction; ?>">
<head>
	<jdoc:include type="metas" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<jdoc:include type="styles" />
	<jdoc:include type="scripts" />
</head>

<body>

	<div class="row">
		<div class="col">
			<jdoc:include type="message" />
			<main>
				<jdoc:include type="component" />
			</main>
		</div>
	</div>

</body>
</html>

The error.php and offline.php[edit]

These files have the same top lines as the other pages but pretty much the original content.

Conclusion[edit]

To see the template described here in use visit https://workcamps.sci.ngo/icamps/

Depending on where you are, you may see this site in English, German, French, Dutch and so on.

Further Information[edit]