Sharing layouts across views or extensions with JLayout

Other languages:
English 100% • ‎español 100% • ‎français 100%

It is common that parts of pages are replicated across several views inside an extension, or even across several extensions. Examples might be:

  • an extension sharing some display layouts between front-end and backend views, or with one or more modules
  • backend extensions that have some common settings, and thus have to replicate common display layouts to allow users to change them

Up until Joomla! 3.0, the loading (and template overriding) of layout files was restricted to a given view. The JLayout interface and set of classes was added to Joomla! 3.0 to help solve this very problem. It encapsulates a layout and the data required to display it so that they can be reused across views and extensions. At the time of writing, JLayout is used by the JHtmlSidebar class to display the submenu and filters found in most backend extensions pages.

JLayout consists in an interface and 2 classes:

  • JLayout interface defines escape and render methods, much like the JView class of Joomla! platform
  • JLayoutBase implements a basic layout class, where layout may be hardcoded in the class itself for instance
  • JLayoutFile, the most commonly used class, wraps and render a layout stored in a file, checking for overrides in template before doing so.

Here is a basic usage example of JLayoutFile:

// Create a layout object and ask it to render the sidebar
$layout      = new JLayoutFile('joomla.sidebars.submenu', $basePath = null);
$sidebarHtml = $layout->render($data);

Executing this code creates a JLayoutFile object, wrapping a layout file, and passing in a $data structure that may be required for the display itself.

The first parameter, 'joomla.sidebars.submenu' is the file identifier. The last part ('submenu')is the file name, everything before ('joomla.sidebars') is the relative path. An optional $basePath parameter can be prepended to the relative path. If $basePath is missing, layout files will be searched inside the /layouts directory.

Our example:

new JLayoutFile('joomla.sidebars.submenu', $basePath = null)

will result in the 'submenu.php' layout file being loaded from the '/layouts/joomla/sidebars' directory.

Passing in a non-empty base path allows accessing and storing layout files anywhere on the site directory structure, for instance:

$layout = new JLayoutFile('my_layout', $basePath = JPATH_ROOT .'/components/com_something/layouts');
$html = $layout->render($data);

will load and render the 'my_layout.php' layout file found in JPATH_ROOT .'/components/com_something/layouts' directory.

Template overrides:

When executing the render() method, that is actually loading the layout file, JLayoutFile will check for the existence of an override in the currently selected template, inside a 'layouts' directory. Looking back at our initial example, should you want to override the sidebar layout of all backend Joomla! extensions, you should place a 'submenu.php' file under: /administrator/templates/{currently_selected_template}/html/layouts/joomla/sidebars/

Note: JLayoutFile will check the currently selected template for overrides. As layouts can be shared across both front end and backend side, if you need to override a layout file in both cases, you'll have to put an override file in both backend and front end template.

Storing layouts:

Layouts files can basically be stored anywhere, as a full base path can be specified when using them (and still allow template override). However, for consistency and to avoid name clashes, we would recommend the following:

  • default to storing layout files in your extension own admin layouts folder. For instance: /administrator/components/com_example/layouts
  • if your extension doesn't have an administrative folder (front-end only component, module, plugin), then use a layouts folder such as:
    • /components/com_example/layouts
    • /plugins/content/example/layouts
    • /modules/mod_example/layouts

In addition, note that the folder itself MUST be named layouts. Using the root /layouts folder is normally reserved for Joomla! itself, and possibly other "official" applications in the future such as the installer for instance. Lastly, though not mandatory, I advise you put all your layout files under an additional "com_example" or "mod_example" sub folder inside the main "layouts" folder. This serves no purpose for your extension, however, should a template override layouts for several extensions, this would avoid possible name collisions. For instance, if 2 extensions use the "filters.search_all" JLayout, then a template cannot provide a separate override for each. A single override will be used for both extension, which may not be desirable. Using "com_example_1.filters.search_all" and "com_example_2.filters.search_all" allows templates to provide overrides for layouts, even if they have the same id.


Here is a very simple example.

Create a file, /layouts/joomla/content/helloworld.php:

defined('JPATH_BASE') or die;
<div id="helloworld">
  <h1>Hello World!</h1>

Then in any layout file, such as components/com_content/views/article/tmpl/default.php add:

$layout      = new JLayoutFile('joomla.content.helloworld');
echo $layout->render();

View an article on the front end and you will see Hello World!. Of course often you will want to pass some data via the render() method.

A simple example of that might be:

defined('JPATH_BASE') or die;
<div id="helloworld">
  <h1>Hello <?php echo $displayData['name']; ?>!</h1>

(Note that the variable passed in to the layout is called $displayData)

With the corresponding PHP

$layout      = new JLayoutFile('joomla.content.helloworld');
$data = array('name' => 'Bob');
echo $layout->render($data);

Now when you view your article you should see: Hello Bob!.

For additional information, you can also read this article on the Joomla! Community Magazine™: JLayout Improvements for Joomla! 3.2 by Roberto Segura.