J3.x

Difference between revisions of "JLayout Improvements for Joomla!"

From Joomla! Documentation

(Phrasing, capitalization and markup changes.)
 
Line 1: Line 1:
 
<noinclude><languages /></noinclude>
 
<noinclude><languages /></noinclude>
 
<translate><!--T:1-->
 
<translate><!--T:1-->
This article introduces you to the new <code>JLayouts</code> features in [http://www.joomla.org/ Joomla! 3.2.]</translate>
+
This article introduces you to the new ''JLayouts'' features in Joomla! 3.2.</translate>
  
 
<translate><!--T:2-->
 
<translate><!--T:2-->
Most of the changes are focused in improve the flexibility of the system for third party developers.</translate>
+
Most of the changes are focused on improving the flexibility of the system for third party developers.</translate>
  
 
__TOC__
 
__TOC__
 
[[Image:JLayout-image.jpg]]
 
[[Image:JLayout-image.jpg]]
  
<translate>== A bit of History == <!--T:3--></translate>
+
<translate>== A Bit of History == <!--T:3--></translate>
  
 
<translate><!--T:4-->
 
<translate><!--T:4-->
Let's use an example: you have articles that have tags, but also contacts have tags, but also categories have tags....</translate>
+
Let's use an example: you have articles that have tags, but also contacts have tags, but also categories have tags...</translate>
  
 
<translate><!--T:5-->
 
<translate><!--T:5-->
In the old template system previous to <code>JLayouts</code> (basically what we still use for views) render that would require to copy paste the same HTML rendering in as many places as you wanted to display your tags. Well, that's not so hard no? Ok but then we have a bug, someone fixes it for content but forgets to do it for categories, and then someone adds a cool feature but only for contacts..... Problems start and the system becomes harder to maintain.</translate>
+
In the old template system previous to ''JLayouts'' (what we still use for views) rendering that would require you to copy and paste the same HTML rendering in as many places as you wanted to display your tags. That's not so hard is it? Okay but then we have a bug, someone fixes it for content but forgets to do it for categories, and then someone adds a cool feature but only for contacts... The system becomes difficult to maintain.</translate>
  
 
<translate><!--T:6-->
 
<translate><!--T:6-->
[https://github.com/shumisha Yannick Gaultier] contributed <code>JLayouts</code> to solve this issue. An awesome simple system behind the concept of reusable pieces of code that allows you to render HTML from objects/arrays of data.</translate>
+
[https://github.com/shumisha Yannick Gaultier] contributed ''JLayouts'' to solve this issue. An awesome, simple system behind the concept of reusable pieces of code that allows you to render HTML from objects/arrays of data.</translate>
  
<translate>== Benefits of using layouts == <!--T:7--></translate>
+
<translate>== Benefits of Using Layouts == <!--T:7--></translate>
  
 
<translate><!--T:8-->
 
<translate><!--T:8-->
 
Thanks to the JLayout system you can render the tags of an item with:</translate>
 
Thanks to the JLayout system you can render the tags of an item with:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
echo JLayoutHelper::render('joomla.content.tags', $itemTags);</source>
+
echo JLayoutHelper::render('joomla.content.tags', $itemTags);</syntaxhighlight>
  
 
<translate><!--T:9-->
 
<translate><!--T:9-->
That will basically echo the output of the file in <code>/layouts/joomla/content/tags.php</code> passing <code>$itemTags</code> as parameter for internal use. What we were doing in modules but in a standard way. The only requirement is that <code>$itemTags</code> object shares the same structure for all the items.</translate>
+
That will echo the output of the file in ''/layouts/joomla/content/tags.php'' passing ''$itemTags'' as parameter for internal use. What we were doing in modules but in a standard way. The only requirement is that ''$itemTags'' object shares the same structure for all the items.</translate>
  
 
<translate><!--T:10-->
 
<translate><!--T:10-->
Line 39: Line 39:
 
We only have to maintain one layout. Designers only have to customise a layout.</translate>
 
We only have to maintain one layout. Designers only have to customise a layout.</translate>
  
<translate>=== Untie data &amp; design === <!--T:13--></translate>
+
<translate>=== Untie Data and Design === <!--T:13--></translate>
  
 
<translate><!--T:14-->
 
<translate><!--T:14-->
Another of the cool benefits of <code>JLayouts</code> is to become another tool for devs to untie HTML code from PHP code. In an ideal world 100% of the markup in a page should be overridable by a designer/developer without touching Joomla! core. That means that if you load a JS file you should do it in a place that a designer can override it if he decides to not use your JS but replace it with another library. This is actually one of the most important problems we have in Joomla! and the reason why most designers run scared after trying to collaborate for some time.</translate>
+
Another of the benefits of ''JLayouts'' is to become another tool for developers to untie HTML code from PHP code. In an ideal world 100% of the markup in a page should be overridable by a designer/developer without touching the Joomla! core. If you load a JavaScript file you should do it in a place that a designer can override it if they decide to not use your JavaScript but replace it with another library. This is one of the most important problems we have in Joomla! and the reason most designers run scared after trying to collaborate for some time.</translate>
  
<translate>=== Easy integration with 2.5.x === <!--T:15--></translate>
+
<translate>=== Easy Integration with 2.5.x === <!--T:15--></translate>
  
 
<translate><!--T:16-->
 
<translate><!--T:16-->
All the layout system is just 4 files. You can include them in your library for 2.5 support and/or extend them in your own classes.</translate>
+
All the layout system is just four files. You can include them in your library for 2.5 support and/or extend them in your own classes.</translate>
  
<translate>== Previous JLayout system == <!--T:17--></translate>
+
<translate>== Previous JLayout System == <!--T:17--></translate>
  
 
<translate><!--T:18-->
 
<translate><!--T:18-->
With the previous JLayout system a call like this:</translate>
+
With the previous JLayout system a call like:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$layout = new JLayoutFile('joomla.content.tags');
 
$layout = new JLayoutFile('joomla.content.tags');
$layout->render($itemTags);</source>
+
$layout->render($itemTags);</syntaxhighlight>
  
 
<translate><!--T:19-->
 
<translate><!--T:19-->
Line 68: Line 68:
 
Cool! That means that I can override it. But also you could force the folder where you wanted to load layouts with:</translate>
 
Cool! That means that I can override it. But also you could force the folder where you wanted to load layouts with:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$layout = new JLayoutFile('joomla.content.tags', JPATH_SITE . '/components/com_mycomponent/layouts');
 
$layout = new JLayoutFile('joomla.content.tags', JPATH_SITE . '/components/com_mycomponent/layouts');
$layout->render($itemTags);</source>
+
$layout->render($itemTags);</syntaxhighlight>
  
 
<translate><!--T:21-->
 
<translate><!--T:21-->
Line 82: Line 82:
 
Nice because it's still overridable!</translate>
 
Nice because it's still overridable!</translate>
  
<translate>== New requirements == <!--T:23--></translate>
+
<translate>== New Requirements == <!--T:23--></translate>
  
 
<translate><!--T:24-->
 
<translate><!--T:24-->
Line 92: Line 92:
 
* What happens if a designer wants to show tags differently in the blog view than in the category view?</translate>
 
* What happens if a designer wants to show tags differently in the blog view than in the category view?</translate>
 
<translate><!--T:27-->
 
<translate><!--T:27-->
* How can a designer customise the way that he wants to render a field for one specific component?</translate>
+
* How can a designer customise the way that they want to render a field for one specific component?</translate>
  
 
<translate><!--T:28-->
 
<translate><!--T:28-->
 
I faced those problems in my job and that's where I started to improve the system. Some of them had a "hard" solution using the old system but I wanted an easy automatic system that also works for complex solutions.</translate>
 
I faced those problems in my job and that's where I started to improve the system. Some of them had a "hard" solution using the old system but I wanted an easy automatic system that also works for complex solutions.</translate>
  
<translate>== New features == <!--T:29--></translate>
+
<translate>== New Features == <!--T:29--></translate>
  
 
<translate><!--T:30-->
 
<translate><!--T:30-->
After my [https://github.com/joomla/joomla-cms/pull/1419 initial proposal] Joomla! magic started and people came with more suggestions. The final result is a cool system much better that my initial proposal. The magic of open source.</translate>
+
After my [https://github.com/joomla/joomla-cms/pull/1419 initial proposal] Joomla! magic started and people came with more suggestions. The final result is a system much better that my initial proposal. The magic of open source.</translate>
  
 
<translate><!--T:31-->
 
<translate><!--T:31-->
As a clue of the new improvements this can be sample call to layouts now:</translate>
+
As a clue of the new improvements this is a sample call to layouts now:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
$layout = new JLayoutFile('joomla.content.tags', null, array('debug' => true, 'client' => 1, 'component' => 'com_tags'));</source>
+
$layout = new JLayoutFile('joomla.content.tags', null, array('debug' => true, 'client' => 1, 'component' => 'com_tags'));</syntaxhighlight>
  
<translate>=== Component layout override === <!--T:32--></translate>
+
<translate>=== Component Layout Override === <!--T:32--></translate>
  
 
<translate><!--T:33-->
 
<translate><!--T:33-->
Line 116: Line 116:
 
Now the same call that we used before:</translate>
 
Now the same call that we used before:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$layout = new JLayoutFile('joomla.content.tags');
 
$layout = new JLayoutFile('joomla.content.tags');
$layout->render($itemTags);</source>
+
$layout->render($itemTags);</syntaxhighlight>
  
 
<translate><!--T:35-->
 
<translate><!--T:35-->
Line 135: Line 135:
 
In our example a developer can customise the way that tags are shown in his component and a designer can override the way that tags are shown in that component.</translate>
 
In our example a developer can customise the way that tags are shown in his component and a designer can override the way that tags are shown in that component.</translate>
  
<translate>=== Force component === <!--T:38--></translate>
+
<translate>=== Force Component === <!--T:38--></translate>
  
 
<translate><!--T:39-->
 
<translate><!--T:39-->
The previous example automatically detects the component when the layout has been called. But what happens if I want to render my tags the same way they are rendered in com_tags? This is also covered with this sample call:</translate>
+
The previous example automatically detects the component when the layout has been called. What happens if I want to render my tags the same way they are rendered in ''com_tags''? This is also covered with this sample call:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
$layout = new JLayoutFile('joomla.content.tags', null, array('component' => 'com_tags'));</source>
+
$layout = new JLayoutFile('joomla.content.tags', null, array('component' => 'com_tags'));</syntaxhighlight>
  
<translate>=== Force client === <!--T:40--></translate>
+
<translate>=== Force Client === <!--T:40--></translate>
  
 
<translate><!--T:41-->
 
<translate><!--T:41-->
Other of the things that the system now automatically detects is the client from where it's called. That means that if you are in frontend it will search for layouts in frontend.</translate>
+
Other of the things that the system now automatically detects is the client from where it's called. That means that if you are in Frontend it will search for layouts in Frontend.</translate>
  
 
<translate><!--T:42-->
 
<translate><!--T:42-->
But I want to render my tags in backend in the same way that com_tags renders them in the frontend! This is covered with this sample call:</translate>
+
But I want to render my tags in Backend in the same way that com_tags renders them in the Frontend! This is covered with this sample call:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
$layout = new JLayoutFile('joomla.content.tags', null, array('client' => 0, 'component' => 'com_tags'));</source>
+
$layout = new JLayoutFile('joomla.content.tags', null, array('client' => 0, 'component' => 'com_tags'));</syntaxhighlight>
  
 
<translate><!--T:43-->
 
<translate><!--T:43-->
Line 160: Line 160:
 
* 1, 'admin' > backend
 
* 1, 'admin' > backend
  
<translate>=== Adding include paths === <!--T:44--></translate>
+
<translate>=== Adding Include Paths === <!--T:44--></translate>
  
 
<translate><!--T:45-->
 
<translate><!--T:45-->
Let's say that you end having a custom folder for layouts but you don't want to store all of them. You just want to, for example, add a folder where joomla has to search for layouts and if it doesn't find them load the standard ones. For example in my company we have a library that contains our shared custom layouts for all our components.</translate>
+
Let's say that you have a custom folder for layouts but don't want to store all of them. You just want to, for example, add a folder where Joomla has to search for layouts and if it doesn't find them, load the standard ones. For example in my company we have a library that contains our shared custom layouts for all our components.</translate>
  
 
<translate><!--T:46-->
 
<translate><!--T:46-->
 
This is done with the new call:</translate>
 
This is done with the new call:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$layout = new JLayoutFile('joomla.content.tags');
 
$layout = new JLayoutFile('joomla.content.tags');
$layout->addIncludePaths(JPATH_LIBRARIES . '/hacknsa');</source>
+
$layout->addIncludePaths(JPATH_LIBRARIES . '/hacknsa');</syntaxhighlight>
  
 
<translate><!--T:47-->
 
<translate><!--T:47-->
That will add /libraries/hacknsa in the top level to search for layouts (maximum priority). This method also supports an array of paths. In an array remember that the latest will have the highest priority.</translate>
+
That will add ''/libraries/hacknsa'' in the top level to search for layouts (maximum priority). This method also supports an array of paths. In an array, remember that the latest will have the highest priority.</translate>
  
 
<translate>=== Suffixes === <!--T:48--></translate>
 
<translate>=== Suffixes === <!--T:48--></translate>
Line 180: Line 180:
 
Another of the proposals (in this case from [https://twitter.com/rdeutz Robert Deutz]) was to be able to specify suffixes of the layout. The original idea was to allow extensions to load search a layout specific active Joomla! version or use the default one. Example:</translate>
 
Another of the proposals (in this case from [https://twitter.com/rdeutz Robert Deutz]) was to be able to specify suffixes of the layout. The original idea was to allow extensions to load search a layout specific active Joomla! version or use the default one. Example:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25')));
 
$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25')));
echo $layout->render($this->item->tags->itemTags);</source>
+
echo $layout->render($this->item->tags->itemTags);</syntaxhighlight>
  
 
<translate><!--T:50-->
 
<translate><!--T:50-->
But that's only one of the uses. Imagine that you need a different layout for RTL (Right To Left) languages. You can add it to all the searches to always look for it in case of active RTL language enabled. Or imagine a customer address whose zip code, is shown in different places/formats depending on the country. You can add a check for a specific layout for the customer country.</translate>
+
But that's only one of the uses. Imagine that you need a different layout for RTL (Right To Left) languages. You can add it to all the searches to always look for it in case of active RTL language enabled. Or imagine a customer address whose zip code is shown in different places/formats depending on the country. You can add a check for a specific layout for the customer country.</translate>
  
 
<translate>=== Sublayouts === <!--T:51--></translate>
 
<translate>=== Sublayouts === <!--T:51--></translate>
  
 
<translate><!--T:52-->
 
<translate><!--T:52-->
One of the things I found bad in JLayouts is that you cannot inherit the settings of a layout and use them to render another small part of code without having to specify again all the options. Let's see another example: customisable invoices. This way you can have a global call like:</translate>
+
One of the things I found bad in JLayouts is that you cannot inherit the settings of a layout and use them to render another small part of code without having to specify all the options again. Let's see another example: customisable invoices. This way you can have a global call:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
echo JLayoutHelper::render('invoice', $invoiceData);</source>
+
echo JLayoutHelper::render('invoice', $invoiceData);</syntaxhighlight>
  
 
<translate><!--T:53-->
 
<translate><!--T:53-->
And then inside the layout something like:</translate>
+
And then inside the layout:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
<div class="invoice">
 
<div class="invoice">
 
<div class="customer">
 
<div class="customer">
Line 212: Line 212:
 
<?php echo $this->sublayout('footer', $displayData); ?>
 
<?php echo $this->sublayout('footer', $displayData); ?>
 
</div>
 
</div>
</div></source>
+
</div></syntaxhighlight>
  
 
<translate><!--T:54-->
 
<translate><!--T:54-->
Which is a main invoice layout calling sublayouts. So users can just override the header of the invoice without dealing with the rest of the system.</translate>
+
Which is a main invoice layout calling sublayouts. Users can just override the header of the invoice without dealing with the rest of the system.</translate>
  
 
<translate><!--T:55-->
 
<translate><!--T:55-->
When calling a sublayout the systems tries to find a folder called like this layout with the sublayouts inside. In this example we would have a main layout <code>invoice.php</code> and in the same folder a folder called <code>invoice</code> containing the sublayouts (<code>shopper.php</code>, <code>header.php</code>, <code>products.php</code> &amp; <code>footer.php</code>).</translate>
+
When calling a sublayout, the systems tries to find a layout folder with the sublayouts inside. In this example we would have a main layout ''invoice.php'' and in the same folder a folder called ''invoice'' containing the sublayouts (''shopper.php'', ''header.php'', ''products.php'' and ''footer.php'').</translate>
  
 
<translate><!--T:56-->
 
<translate><!--T:56-->
Sublayouts will inherit any setting passed to the parent layout. So they search in the same include paths, in the same client, in the same component and for the same suffixes.</translate>
+
Sublayouts will inherit any setting passed to the parent layout. They search in the same include paths, in the same client, in the same component and for the same suffixes.</translate>
  
<translate>=== Debug mode === <!--T:57--></translate>
+
<translate>=== Debug Mode === <!--T:57--></translate>
  
 
<translate><!--T:58-->
 
<translate><!--T:58-->
When you start dealing with layouts in various include paths, clients, components... You can easily end not knowing where is the system loading the layouts from. This is why I included a UBU (Useful But Ugly :D ) debug system. To enable it you only have to pass the option <code>debug</code> to true like:</translate>
+
When you start dealing with layouts in various include paths, clients, components, you can easily end not knowing where the system is loading the layouts from. This is why I included a UBU (Useful But Ugly) debug system. To enable it you only have to pass the ''debug'' option as true:</translate>
  
<source lang="php">
+
<syntaxhighlight lang="php">
 
$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25'), 'debug' => true));
 
$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25'), 'debug' => true));
echo $layout->render($this->item->tags->itemTags);</source>
+
echo $layout->render($this->item->tags->itemTags);</syntaxhighlight>
  
 
<translate><!--T:59-->
 
<translate><!--T:59-->
Line 237: Line 237:
 
[[Image:jlayouts-debug.png|JLayout new debug mode]]
 
[[Image:jlayouts-debug.png|JLayout new debug mode]]
  
<translate>== Where do not use layouts? == <!--T:60--></translate>
+
<translate>== Where Not To Use Layouts? == <!--T:60--></translate>
  
 
<translate><!--T:61-->
 
<translate><!--T:61-->
Layouts are a cool thing when used properly but a terrible thing when used in the wrong places. And now everybody wants to convert everything to layouts. This is why you can easily find layouts that are used by articles, banners, contacts, clients, weblinks, newsfeeds. You would say "but that's cool no? We are saving code!". No! We are just creating a single layout with tons of if statements inside it to deal with all the differences between components.</translate>
+
Layouts are a cool thing when used properly but a terrible thing when used in the wrong places. And now everybody wants to convert everything to layouts. This is why you can easily find layouts that are used by articles, banners, contacts, clients, weblinks, newsfeeds. You would say "but that's cool no? We are saving code!" No! We are just creating a single layout with tons of ''if'' statements inside it to deal with all the differences between components.</translate>
  
 
<translate><!--T:62-->
 
<translate><!--T:62-->
In my opinion there are no benefits in using a layout to render 4 fields. That's something that has to be done in the template and is not going to be ever reused outside the core. And that's my advice: if it can be reused outside the core then it makes sense as layout. Examples of layouts: render a list, a button, a menu, a field, pagination.... Another good advice: if it cannot be overriden is better in a layout.</translate>
+
In my opinion there are no benefits in using a layout to render four fields. That's something that has to be done in the template and is not going to ever be reused outside the core. My advice: if it can be reused outside the core then it makes sense as layout. Examples of layouts: render a list, a button, a menu, a field, pagination. Another good piece of advice: if it cannot be overridden it is better in a layout.</translate>
  
 
<translate><!--T:63-->
 
<translate><!--T:63-->
 
Layouts are not the solution for everything.</translate>
 
Layouts are not the solution for everything.</translate>
  
<translate>== Other uses == <!--T:64--></translate>
+
<translate>== Other Uses == <!--T:64--></translate>
  
 
<translate><!--T:65-->
 
<translate><!--T:65-->
Imagine the current jQuery loading in core. This is done from JHtml classes. Why not make JHtml search for a overrides automatically in the component folder? So I can have my own custom jQuery version tested with the other libraries in my component. Yes, it can conflict with other module requirements but isn't that what we already have? At least we will avoid loading jQuery multiple times. This is not really a task for layouts but to apply the same concept to JHtml.</translate>
+
Imagine the current jQuery loading in core. This is done from JHtml classes. Why not make JHtml search for a overrides automatically in the component folder? I can have my own custom jQuery version tested with the other libraries in my component. Yes, it can conflict with other module requirements but isn't that what we already have? At least we will avoid loading jQuery multiple times. This is not really a task for layouts but to apply the same concept to JHtml.</translate>
  
 
<translate><!--T:66-->
 
<translate><!--T:66-->
Line 262: Line 262:
  
 
<translate><!--T:69-->
 
<translate><!--T:69-->
Layouts are a really powerful tool and is one of those things that can help us to improve the relations between coders vs desginers. There are a lot of places to use layouts. Some of them still not discovered, some of them waiting there for someone to do the job. [[S:MyLanguage/Bug_Squad|Do you want to help us?]]</translate>
+
Layouts are a really powerful tool and is one of those things that can help us to improve the relations between coders vs designers. There are a lot of places to use layouts. Some of them still not discovered, some of them waiting there for someone to do the job. [[S:MyLanguage/Bug_Squad|Do you want to help us?]]</translate>
  
 
<noinclude>
 
<noinclude>

Latest revision as of 12:03, 6 November 2022

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

This article introduces you to the new JLayouts features in Joomla! 3.2.

Most of the changes are focused on improving the flexibility of the system for third party developers.

JLayout-image.jpg

A Bit of History[edit]

Let's use an example: you have articles that have tags, but also contacts have tags, but also categories have tags...

In the old template system previous to JLayouts (what we still use for views) rendering that would require you to copy and paste the same HTML rendering in as many places as you wanted to display your tags. That's not so hard is it? Okay but then we have a bug, someone fixes it for content but forgets to do it for categories, and then someone adds a cool feature but only for contacts... The system becomes difficult to maintain.

Yannick Gaultier contributed JLayouts to solve this issue. An awesome, simple system behind the concept of reusable pieces of code that allows you to render HTML from objects/arrays of data.

Benefits of Using Layouts[edit]

Thanks to the JLayout system you can render the tags of an item with:

echo JLayoutHelper::render('joomla.content.tags', $itemTags);

That will echo the output of the file in /layouts/joomla/content/tags.php passing $itemTags as parameter for internal use. What we were doing in modules but in a standard way. The only requirement is that $itemTags object shares the same structure for all the items.

So what are the benefits of that?

Reusability[edit]

We only have to maintain one layout. Designers only have to customise a layout.

Untie Data and Design[edit]

Another of the benefits of JLayouts is to become another tool for developers to untie HTML code from PHP code. In an ideal world 100% of the markup in a page should be overridable by a designer/developer without touching the Joomla! core. If you load a JavaScript file you should do it in a place that a designer can override it if they decide to not use your JavaScript but replace it with another library. This is one of the most important problems we have in Joomla! and the reason most designers run scared after trying to collaborate for some time.

Easy Integration with 2.5.x[edit]

All the layout system is just four files. You can include them in your library for 2.5 support and/or extend them in your own classes.

Previous JLayout System[edit]

With the previous JLayout system a call like:

$layout = new JLayoutFile('joomla.content.tags');
$layout->render($itemTags);

Would search for the layout in:

[0] => templates/mytemplate/html/layouts
[1] => layouts

Cool! That means that I can override it. But also you could force the folder where you wanted to load layouts with:

$layout = new JLayoutFile('joomla.content.tags', JPATH_SITE . '/components/com_mycomponent/layouts');
$layout->render($itemTags);

That would search layouts in:

[0] => templates/mytemplate/html/layouts
[1] => components/com_mycomponent/layouts

Nice because it's still overridable!

New Requirements[edit]

With the previous layout system we still have some problems:

  • Developers that want to use layouts inside their components have to specify the path of the layouts in each call or create their own extended classes.
  • What happens if a designer wants to show tags differently in the blog view than in the category view?
  • How can a designer customise the way that they want to render a field for one specific component?

I faced those problems in my job and that's where I started to improve the system. Some of them had a "hard" solution using the old system but I wanted an easy automatic system that also works for complex solutions.

New Features[edit]

After my initial proposal Joomla! magic started and people came with more suggestions. The final result is a system much better that my initial proposal. The magic of open source.

As a clue of the new improvements this is a sample call to layouts now:

$layout = new JLayoutFile('joomla.content.tags', null, array('debug' => true, 'client' => 1, 'component' => 'com_tags'));

Component Layout Override[edit]

One of the modifications is that now the system automatically searches for layouts in the component loaded.

Now the same call that we used before:

$layout = new JLayoutFile('joomla.content.tags');
$layout->render($itemTags);

Will search automatically for layouts in these folders (ordered by priority):

[0] => templates/mytemplate/html/layouts/com_mycomponent
[1] => components/com_mycomponent/layouts
[2] => templates/mytemplate/html/layouts
[3] => layouts

That means that you can use the standard layouts, override them at component level and override the component override at template level.

In our example a developer can customise the way that tags are shown in his component and a designer can override the way that tags are shown in that component.

Force Component[edit]

The previous example automatically detects the component when the layout has been called. What happens if I want to render my tags the same way they are rendered in com_tags? This is also covered with this sample call:

$layout = new JLayoutFile('joomla.content.tags', null, array('component' => 'com_tags'));

Force Client[edit]

Other of the things that the system now automatically detects is the client from where it's called. That means that if you are in Frontend it will search for layouts in Frontend.

But I want to render my tags in Backend in the same way that com_tags renders them in the Frontend! This is covered with this sample call:

$layout = new JLayoutFile('joomla.content.tags', null, array('client' => 0, 'component' => 'com_tags'));

Client parameter supports these values:

  • 0, 'site' > frontend
  • 1, 'admin' > backend

Adding Include Paths[edit]

Let's say that you have a custom folder for layouts but don't want to store all of them. You just want to, for example, add a folder where Joomla has to search for layouts and if it doesn't find them, load the standard ones. For example in my company we have a library that contains our shared custom layouts for all our components.

This is done with the new call:

$layout = new JLayoutFile('joomla.content.tags');
$layout->addIncludePaths(JPATH_LIBRARIES . '/hacknsa');

That will add /libraries/hacknsa in the top level to search for layouts (maximum priority). This method also supports an array of paths. In an array, remember that the latest will have the highest priority.

Suffixes[edit]

Another of the proposals (in this case from Robert Deutz) was to be able to specify suffixes of the layout. The original idea was to allow extensions to load search a layout specific active Joomla! version or use the default one. Example:

$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25')));
echo $layout->render($this->item->tags->itemTags);

But that's only one of the uses. Imagine that you need a different layout for RTL (Right To Left) languages. You can add it to all the searches to always look for it in case of active RTL language enabled. Or imagine a customer address whose zip code is shown in different places/formats depending on the country. You can add a check for a specific layout for the customer country.

Sublayouts[edit]

One of the things I found bad in JLayouts is that you cannot inherit the settings of a layout and use them to render another small part of code without having to specify all the options again. Let's see another example: customisable invoices. This way you can have a global call:

echo JLayoutHelper::render('invoice', $invoiceData);

And then inside the layout:

<div class="invoice">
	<div class="customer">
		<?php echo $this->sublayout('shopper', $displayData['shopper']); ?>
	</div>
	<div class="header">
		<?php echo $this->sublayout('header', $displayData); ?>
	</div>
	<div class="products">
		<?php echo $this->sublayout('products', $displayData['products']); ?>
	</div>
	<div class="footer">
		<?php echo $this->sublayout('footer', $displayData); ?>
	</div>
</div>

Which is a main invoice layout calling sublayouts. Users can just override the header of the invoice without dealing with the rest of the system.

When calling a sublayout, the systems tries to find a layout folder with the sublayouts inside. In this example we would have a main layout invoice.php and in the same folder a folder called invoice containing the sublayouts (shopper.php, header.php, products.php and footer.php).

Sublayouts will inherit any setting passed to the parent layout. They search in the same include paths, in the same client, in the same component and for the same suffixes.

Debug Mode[edit]

When you start dealing with layouts in various include paths, clients, components, you can easily end not knowing where the system is loading the layouts from. This is why I included a UBU (Useful But Ugly) debug system. To enable it you only have to pass the debug option as true:

$layout = new JLayoutFile('joomla.content.tags', null, array('suffixes' => array('j3x', 'j25'), 'debug' => true));
echo $layout->render($this->item->tags->itemTags);

You will see something like:

JLayout new debug mode

Where Not To Use Layouts?[edit]

Layouts are a cool thing when used properly but a terrible thing when used in the wrong places. And now everybody wants to convert everything to layouts. This is why you can easily find layouts that are used by articles, banners, contacts, clients, weblinks, newsfeeds. You would say "but that's cool no? We are saving code!" No! We are just creating a single layout with tons of if statements inside it to deal with all the differences between components.

In my opinion there are no benefits in using a layout to render four fields. That's something that has to be done in the template and is not going to ever be reused outside the core. My advice: if it can be reused outside the core then it makes sense as layout. Examples of layouts: render a list, a button, a menu, a field, pagination. Another good piece of advice: if it cannot be overridden it is better in a layout.

Layouts are not the solution for everything.

Other Uses[edit]

Imagine the current jQuery loading in core. This is done from JHtml classes. Why not make JHtml search for a overrides automatically in the component folder? I can have my own custom jQuery version tested with the other libraries in my component. Yes, it can conflict with other module requirements but isn't that what we already have? At least we will avoid loading jQuery multiple times. This is not really a task for layouts but to apply the same concept to JHtml.

Now imagine that top menu contains a bug on a button or in something that is inside a layout. You can fix it inside a layout override on your own component and wait until the core fixes it. Same if you have a library that conflicts with core. Lot of support saved explaining that the issue is a core bug.

This are only some of the ideas behind the concept.

Conclusion[edit]

Layouts are a really powerful tool and is one of those things that can help us to improve the relations between coders vs designers. There are a lot of places to use layouts. Some of them still not discovered, some of them waiting there for someone to do the job. Do you want to help us?