Automatic Column Layout in Smarty

The Problem: You have a list of X items of information that you want to lay out in rows. Each row must contain X columns. It's easy to lay-out things in two columns, but when you want to use a large or indeterminate number of columns in your layout you need to write some more flexible smarty code. This is my solution.

Solution for three columns

Line 2: Causes this entire block to be ignored if the source variable is not present.

Lines 5-25: Loop through the input variable.

Line 6: We capture the value which indicates the column number.

Line 26-29: We need to make sure that the table is properly closed otherwise this will cause a bug in the HTML.

<!-- lc_horizontalIcons.html -->
{if $horizontal_icons != null}
{include file="lc/lc_sausage.html" sausage_heading="Activities" sausage_anchor="Activities"}

{foreach from=$horizontal_icons item=datum key=key}
{capture name="column"}{math equation="x % 3" x=$key}{/capture}
{if $smarty.capture.column == "0"}
<table border="0" cellpadding="0" cellspacing="0" class="sectionTable">
		<td width="33%" align="center" valign="middle">
		{include file="lc/lc_linked_img.html}
{elseif  $smarty.capture.column == "1"}
		<td width="33%" align="center" valign="middle">
		{include file="lc/lc_linked_img.html}
{elseif $smarty.capture.column == "2"}
		<td width="33%" align="center" valign="middle">
		{include file="lc/lc_linked_img.html}

{if $smarty.capture.column != 2}
<!-- Close the table! -->

<!-- end lc_centreAbout.html -->

If you want to see an example of this effect in use, take a look at the home page of the new [Leisure Connection] website when it launches in March 2003.

Alternate Solution for X columns where X > 2

Here's another one:

{* columnsExample.tpl                        *}
{* ----------------------------------------- *}
{* Example for using column layout in Smarty *}

{* First we check if there are some entries to display *}
{if count($entries) > 0}
  {* begin of table *}

    {* $lastcol will be needed to check if we are outputting the last column *}
    {math assign="lastcol" equation="x-1" x=$columns}

    {* $width is the column width *}
    {math assign="width" equation="100 / x" x=$columns}
    {* now loop through all entries *}
    {section name="idx" loop=$entries}
      {* $col is the current column *}
      {math assign="col" equation="x % y" x=$smarty.section.idx.rownum y=$columns}
      {if $col == 0}<tr>{/if} {* begin of new row *}

      <td width="{$width}%">
        {* Output cell content here *}

      {if $col == $lastcol || $smarty.section.idx.index_last == true }</tr>{/if} {* end of row *}
  {* close table *}
   * columnsExample.php
   * Example for using column layout in Smarty
  $entries = array("a","b","c","d","e","f","g","h","i","j","k","l","m","n");
  $columns = 7;
  $smarty = new Smarty();
  $smarty->assign("entries", $entries); // Assign the table entries
  $smarty->assign("columns", $columns); // Assign the number of columns we want to display

Simple Solution for any number of columns

This is for any number of columns, and its short and painless:

{* Monte Möhrt March 4, 2002 *}
{* $cols is the number of columns you want *}
<TABLE border=1>
    {section name=numloop loop=$data}
        {* see if we should go to the next row *}
        {if not ($smarty.section.numloop.rownum mod $cols)}
                {if not $smarty.section.numloop.last}
        {if $smarty.section.numloop.last}
                {* pad the cells not yet created *}
                {math equation = "n - a % n" n=$cols a=$data|@count assign="cells"}
                {if $cells ne $cols}
                {section name=pad loop=$cells}

FYI, Smarty 2.5.0 will have an html_table function that will help automate this process.

Simpler Solution Using Smarty 2.6 Embedded Math

This is also for any number of columns, but made easier by using a new feature of Smarty version 2.6.0: using math expressions directly in templates.

{* Requires Smarty 2.6.0 or later *}
{* $data is the array you want to display *}
{* $numCols is the number of columns *}
    {assign var="col" value="0"}
    {section name=element loop=$data}
        {if $col == $numCols}
            </tr><tr>{assign var="col" value="0"}
        {assign var="col" value="`$col+1`"}
    {assign var="remainder" value="`$numCols-$col`"}
    {section name=emptyElement loop=$remainder}

Plugin solution Without Embedded Math

Because I saw that Embedded Math can be hard to deal because it uses php function eval()

I tried another solution. I created a plugin that can jump next record in a section so

I can print as many itens as I want in 1 loop thru the {section} I will post it at the

website in the scripts section. Here you will have the source of the plugin

and two example files.

save this as function.section_next.php in your smarty/plugins folder
 * Smarty plugin
 * @package Smarty
 * @subpackage plugins

 * Smarty {section_next} function plugin
 * Type:     function<br>
 * Name:     section_next<br>
 * Author:   Tadeu Ferreira Oliveira 
 * Contact:
 * Purpose:  jump to the next element in a section
 * @param array parameters
 * @param Smarty
 * @return null
function smarty_function_section_next($params, &$smarty)

    if (!isset($smarty->_sections[$params["name"]])){
		$smarty->trigger_error("section_next: section '".$params["name"]."' not found");
	$smarty->_sections[$params["name"]]['index'] 		+= $smarty->_sections[$params["name"]]['step'];
	$smarty->_sections[$params["name"]]['rownum'] 		= $smarty->_sections[$params["name"]]['iteration'];
	$smarty->_sections[$params["name"]]['index_prev'] 	= $smarty->_sections[$params["name"]]['index'] - $smarty->_sections[$params["name"]]['step'];
	$smarty->_sections[$params["name"]]['index_next'] 	= $smarty->_sections[$params["name"]]['index'] + $smarty->_sections[$params["name"]]['step'];
	$smarty->_sections[$params["name"]]['first']      	= ($smarty->_sections[$params["name"]]['iteration'] == 1);
	$smarty->_sections[$params["name"]]['last']       	= ($smarty->_sections[$params["name"]]['iteration'] == $smarty->_sections[$params["name"]]['total']);

         (* Mais de uma coluna por linha agora facinho facinho*)
         <table border="1">
         {section name=cont loop=$teste}
               <td>{$teste[cont]}</td> (* Uma Coluna*)
               {section_next name=cont}
               <td>{$teste[cont]}</td> (* Duas Colunas*)

            $teste[0] = "Zero";
            $teste[1] = "Um";
            $teste[2] = "Dois";
            $teste[3] = "Tres";
            $teste[4] = "Quatro";
            $teste[5] = "Cinco";
            $teste[6] = "Seis";
            $teste[7] = "Sete";

            $smarty = new Smarty();