Smarty - the compiling PHP template engine MonteOhrt
monte@ispi.net
AndreiZmievski
andrei@ispi.net
2001ispi, Inc.
Overview It is undoubtedly one of the most asked questions on the PHP mailing lists: how do I make my PHP scripts independent of the layout? While PHP is billed as "HTML embedded scripting language", after writing a couple of projects that mixed PHP and HTML freely one comes up with the idea that separation of form and content is a Good Thing [TM]. In addition, in many companies the roles of layout designer and programmer are separate. Consequently, the search for a templating solution ensues. In our company for example, the development of an application goes on as follows: After the requirements docs are done, the interface designer makes mockups of the interface and gives them to the programmer. The programmer implements business logic in PHP and uses interface mockups to create skeleton templates. The project is then handed off to the HTML designer/web page layout person who brings the templates up to their full glory. The project may go back and forth between programming/HTML a couple of times. Thus, it's important to have good template support because programmers don't want anything to do with HTML and don't want HTML designers mucking around with PHP code. Designers need support for config files, dynamic blocks and other stuff, but they don't want to have to deal with intricacies of the PHP programming language. Looking at many templating solutions available for PHP today, most of them provide a rudimentary way of substituting variables into templates and do a limited form of dynamic block functionality. But our needs required a bit more than that. We didn't want programmers to be dealing with HTML layout at ALL, but this was almost inevitable. For instance, if a designer wanted background colors to alternate on dynamic blocks, this had to be worked out with the programmer in advance. We also needed designers to be able to use their own configuration files, and pull variables from them into the templates. The list goes on. We started out writing out a spec for a template engine about a year ago. After finishing the spec, we began to work on a template engine written in C that would hopefully be accepted for inclusion with PHP. Not only did we run into many complicated technical barriers, but there was also much heated debate about exactly what a template engine should and should not do. From this experience, we decided that the template engine should be written in PHP as a class, for anyone to use as they see fit. So we wrote an engine that did just that and SmartTemplate came into existence (note: this class was never submitted to the public). It was a class that did almost everything we wanted: regular variable substitution, supported including other templates, integration with config files, embedding PHP code, limited 'if' statement functionality and much more robust dynamic blocks which could be multiply nested. It did all this with regular expressions and the code turned out to be rather, shall we say, impenetrable. It was also noticably slow in large applications from all the parsing and regular expression work it had to do on each invocation. The biggest problem from a programmer's point of view was all the necessary work in the PHP script to setup and process templates and dynamic blocks. How do we make this easier? Then came the vision of what ultimately became Smarty. We know how fast PHP code is without the overhead of template parsing. We also know how meticulous and overbearing the PHP language may look to the average designer, and this could be masked with a much simpler templating syntax. So what if we combined the two strengths? Thus, Smarty was born... What is Smarty? Smarty is a template engine for PHP. One of the unique aspects about Smarty that sets it apart from other templating solutions is that it compiles the templates into native PHP scripts upon the first invocation. After that, it merely executes the compiled PHP scripts. Therefore, there is no costly template file parsing for each request. Some of Smarty's features: It is extremely fast. It is efficient since the PHP parser does the dirty work. No template parsing overhead, only compiles once. It is smart about recompiling only the template files that have changed. You can make custom functions and custom variable modifiers, so the template language is extremely extensible. Configurable template delimiter tag syntax, so you can use {}, {{}}, <!--{}-->, or whatever you like. The if/elseif/else/endif constructs are passed to the PHP parser, so the if expression syntax can be as simple or as complex as you like. Unlimited nesting of sections, ifs, etc. allowed. It is possible to embed PHP code right in your template files, although this may not be needed (nor recommended) since the engine is so customizable. How Smarty works Compiling Smarty compiles the templates into native PHP code on-the-fly. The actual PHP scripts that are generated are created implicitly, so theoretically you should never have to worry about touching these files, or even know of their existence. The exception to this is debugging Smarty template syntax errors, discussed later in this document. Caching Our initial intention was to build caching into Smarty. However, since the template engine is actually executing PHP scripts instead of parsing template files, the need for a cache was dramatically reduced. We may implement this in a future version of Smarty as the need arises. Installation Requirements Smarty requires PHP 4.0.2 or later. See the BUGS section for caveats. Installing Smarty Installing Smarty is fairly straightforward, there is just one thing you must be aware of. Remember that Smarty creates compiled versions of the template code. This usually means allowing user "nobody" (or whomever the web server runs as) to have permission to write the files. Each installation of a Smarty application minimally needs a templates directory and a compiled templates directory. If you use configuration files you will also need a directory for those. By default these are named "templates", and "templates_c" and "configs" respectively. Copy the Smarty.class.php, Smarty.addons.php and Config_File.class.php scripts to a directory that is in your PHP include_path. NOTE: PHP will try to create a directory alongside the executing script called "templates_c". Be sure that directory permissions allow this to happen. You will see PHP error messages if this fails. You can also create the directory yourself before hand, and change the file ownership accordingly. See below. Example of installing Smarty # be sure you are in the web server document tree # this assumes your web server runs as user "nobody" # and you are in a unix environment gtar -zxvf Smarty-1.0.tar.gz mkdir templates_c chown nobody:nobody templates_c Next, try running the index.php script from your web browser. Setting up Smarty There are several variables that are at the top of the Smarty.class.php file. You can usually get away with leaving these at their default settings. This is a list of them and what each one does. Configuration variables $compile_check Upon each invocation of the PHP application, Smarty recursively traverses the template directory and its subdirectories and searches for all the files with the template extension that have changed (later time stamp) since the last time they were compiled. For each one that has changed, it recompiles that template. By default this variable is set to true. The compile check has very minimal impact on the application performance. However, once an application is put into production and it is initially compiled, the compile_check step is no longer needed. You may set this to "false" *after* the initial compile. Then Smarty will no longer check for changed template files. Note that if you change this to "false" and a template file is changed, you will *not* see the change since the template will not get recompiled. Set it to "true", invoke the application, then set it back to "false". $template_dir This is the directory where template files are located. $compile_dir_ext This is the extension used for the name of the directory where compiled templates are located. By default this is "_c". Therefore if your template directory is named "templates", then the compiled templates directory will be named "templates_c". $tpl_file_ext This is the extention used for template files. By default this is ".tpl". All other files in the template directory are ignored. $allow_php Whether or not to allow PHP code in the templates. If set to false, PHP code is escaped and not interpreted. Embedding PHP code into templates is highly discouraged. Use custom functions or modifiers instead. Default is "false". $left_delimiter This is the left delimiter used by the template language. Default is "{". $right_delimiter This is the right delimiter used by the template language. Default is "}". $config_dir This is the directory used to store config files used in the templates. Default is "configs". $custom_funcs This is a mapping of the names of custom functions in the template to the names of functions in PHP. These are usually kept in Smarty.addons.php. $custom_mods This is a mapping of the names of variable modifiers in the template to the names of functions in PHP. These are usually kept in Smarty.addons.php. $global_assign This is a list of variables that are always implicitly assigned to the template engine. This is usually handy for making global variables or server variables available to the template without having to manually assign them to the template every time. Smarty API These functions are used in the PHP portion of your application. Smarty API Functions assign void assign mixed var void assign string varname mixed var This is used to assign values to the templates. This is usually data gathered from database queries or other sources of data. append void append mixed var void append string varname mixed var This is used to append data to existing variables in the template. clear_assign void clear_assign string var This clears the value of an assigned variable. clear_all_assign void clear_all_assign This clears the values of all assigned variables. get_template_vars array get_template_vars This gets an array of the currently assigned template vars. display void display string template This displays the template. fetch string fetch string template This returns the template output. Using Smarty API Example use of Smarty API include("Smarty.class.php"); $smarty = new Smarty; // dummy up some data $address = "245 N 50th"; $db_data = array( "City" => "Lincoln", "State" => "Nebraska", "Zip" = > "68502" ); $smarty->assign("Name","Fred"); $smarty->assign("Address",$address); $smarty->assign($db_data); // display the output $smarty->display("./templates/index.tpl"); // alternatively capture the output $output = $smarty->fetch("./templates/index.tpl"); Smarty Templates The templates are the heart of Smarty. These are the files that the designers work with. They're basically pages made up of static content interspersed with template markup tags. These tags are placeholders for variables or blocks of logic. Syntax For these examples, we will assume that you are using the default template tag delimiters, which are "{" and "}". In Smarty, all content outside of delimiter tags is displayed as static content, or unchanged. When Smarty encounters template tags {}, it attempts to interpret what is between the tags, and displays the appropriate output in place of them. Variables There are three basic types of variables in Smarty, each with their own unique syntax. Variables assigned from PHP Variables that are assigned from PHP are displayed by preceeding them with a dollar sign ($) and enclosing the variable in delimiters like so: {$varname} Template example of displaying assigned variables Hello {$firstname}, glad to see you could make it. <p> Your last login was on {$lastLoginDate}. OUTPUT: Hello Doug, glad to see you could make it. <p> Your last login was on January 11th, 2001. There are also variables within looping sections that are displayed a bit differently. Those are exaplained later in this document under Built-in Functions. Variables passed from config files Variables that are passed in from config files are displayed by enclosing them with hash marks (#) and enclosing the variable in delimiters like so: {#varname#} Template example of displaying config variables <html> <title>{#pageTitle#}</title> <body bgcolor="{#bodyBgColor#}"> <table border="{#tableBorderSize#}" bgcolor="{#tableBgColor#}"> <tr bgcolor="{#rowBgColor#}"> <td>First</td> <td>Last</td> <td>Address</td> </tr> </table> </body> </html> Config file variables cannot be displayed until after they are loaded in from a config file. This procedure is explained later in this document under config_load. Variables internal to template Variables that are internal to the templates are displayed by enclosing them with percent signs (%) and enclosing the variable in delimiters like so: {%varname%} So far, section properties are the only internal variables used in Smarty, which can be found later in this document under section. Functions Functions are processed and displayed by enclosing the function and its attributes into delimiters like so: {funcname attr1="val" attr2="val"} Template example of function syntax {config_load file="colors.conf"} {include file="header.tpl"} {if $name eq "Fred"} You are not allowed here {else} Welcome, <font color="{#fontColor#}">{$name}!</font> {/if} {include file="footer.tpl"} Both built-in functions and custom functions have the same syntax in the templates. Attributes Attributes to functions are much like HTML attributes. Static values don't have to be enclosed in quotes, but it is recommended for literal strings. If not quoted, you may use a syntax that Smarty may confuse with another function, such as a boolean value. Variables may also be used, and should not be in quotes. Template example of function attribute syntax {include file="header.tpl"} {include file=$includeFile} {include file=#includeFile#} <SELECT name=company> {html_options values=$vals selected=$selected output=$output} </SELECT> Comments Template comments are surrounded by asterisks, and that is surrounded by the delimiter tags like so: {* this is a comment *} Smarty comments are not displayed in the final output of the template. They are used mainly for making the templates more understandable. Template example of Comments {* Smarty *} {* include the header file here *} {include file="header.tpl"} {include file=$includeFile} {include file=#includeFile#} {* display dropdown lists *} <SELECT name=company> {html_options values=$vals selected=$selected output=$output} </SELECT> Config Files Config files are handy for designers to manage global template variables from one file. One example is template colors. Normally if you wanted to change the color scheme of an application, you would have to go through each and every template file and change the colors. With a config file, the colors can be kept in one place, and only one file needs to be updated. Note that to use config files, you must include the Config_File.class.php In your PHP include path. Config_File.class.php comes bundled with Smarty. Smarty will implicitly include the file if you don't already include it in your application. Example of config file syntax # global variables pageTitle = "Main Menu" bodyBgColor = #000000 tableBgColor = #000000 rowBgColor = #00ff00 [Customer] pageTitle = "Customer Info" [Login] pageTitle = "Login" focus = "username" Intro = """This is a value that spans more than one line. you must enclose it in triple quotes.""" Values of config file variables can be in qoutes, but not necessary. You can use either single or double quotes. If you have a value that spans more than one line, enclose the entire value with triple quotes ("""). You can put comments into config files by any syntax that is not a valid config file syntax. We recommend using a hashmark (#) at the beginning of the line. This config file example has two sections. Section names are enclosed in brackets []. The four variables at the top are global variables, or variables not within a section. These variables are always loaded from the config file. If a particular section is loaded, then the global variables and the variables from that section are loaded. If a variable exists both as a global and in a section, the section variable is used. If you name two variables the same within a section, the last one will be used. Config files are loaded into templates with the built-in function called config_load. Built-in Functions Smarty comes with several built-in functions. Built-in functions are integral to the template language. You cannot create custom functions with the same names, nor can you modify built-in functions. config_load This function is used for loading in variables from a configuration file into the template. You must have the Config_file.class.php file somewhere in your PHP include path for config_load to work properly. See Config Files for more info. Template example of function config_load {config_load file="colors.conf"} <html> <title>{#pageTitle#}</title> <body bgcolor="{#bodyBgColor#}"> <table border="{#tableBorderSize#}" bgcolor="{#tableBgColor#}"> <tr bgcolor="{#rowBgColor#}"> <td>First</td> <td>Last</td> <td>Address</td> </tr> </table> </body> </html> Config files may also contain sections. You can load variables from within a section with the added attribute "section". Template example of function config_load with section {config_load file="colors.conf" section="Customer"} <html> <title>{#pageTitle#}</title> <body bgcolor="{#bodyBgColor#}"> <table border="{#tableBorderSize#}" bgcolor="{#tableBgColor#}"> <tr bgcolor="{#rowBgColor#}"> <td>First</td> <td>Last</td> <td>Address</td> </tr> </table> </body> </html> include Include tags are used for including other templates into the current template. When a template is included, it inherits all the variables available to the current template. The include tag must have the attribute "file", which contains the path to the included template file relative to the template directory. Template example of function include {include file="header.tpl"} {* body of template goes here *} {include file="footer.tpl"} You can also pass variables to included templates as attributes. These will be passed to the template along with the current template variables. Attribute variables override template variables, in the case they are named alike. You can pass either static values or variables to included templates (although it doesn't make much sense to pass anything other than static values since variables are inherited anyways). Template example of function include passing variables {include file="header.tpl" title="Main Menu" table_bgcolor="#c0c0c0"} {* body of template goes here *} {include file="footer.tpl" logo="http://my.domain.com/logo.gif"} insert The insert tag in Smarty serves a special purpose. You may run into the situation where it is impossible to pass data to a template before the template is executed because there is info in the template needed to aquire the data, kind of a catch 22. The insert tag is a way to callback a function in PHP during runtime of the template. (This is much like the functionality of Server Side Includes in a static html page.) Let's say you have a template with a banner slot at the top of the page. The banner can contain any mixture of HTML, images, flash, etc. so we can't just use a static link here. In comes the insert tag: the template knows #banner_location_id# and #site_id# values (gathered from a config file), and needs to call a function to get the banner's contents. Template example of function insert {* example of fetching a banner *} {insert name="getBanner" lid=#banner_location_id# sid=#site_id#} In this example, we are using the name "getBanner" and passing the parameters #banner_location_id# and #site_id#. Smarty will look for a function named insert_getBanner() in your PHP application, passing the values of #banner_location_id# and #site_id# as the first argument in an associative array. All insert function names in your application must be prepended with "insert_" to remedy possible function name-space conflicts. Your insert_getBanner() function should do something with the passed values and return the results. These results are then displayed in the template in place of the insert tag. In this example, Smarty would call this function: insert_getBanner(array("banner_id" => "12345","page_id" => "67890")); and display the returned results in place of the insert tag. Another thing to keep in mind for the insert tag is caching. Smarty does not currently support caching but if that is eventually implemented, insert tags will not be cached. They will run dynamically every time the page is created. This works good for things like banners, polls, live weather, user feedback areas, etc. if,elseif,else if statements in Smarty have much the same flexability as php if statements, with a few added features for the template engine. Every if must be paired with /if. else and elseif are also permitted. "eq", "ne","neq", "gt", "lt", "lte", "le", "gte" "ge","is even","is odd", "is not even","is not odd","not","mod","div by","even by","odd by","==","!=",">", "<","<=",">=" are all valid conditional qualifiers. Template example of if statements {if $name eq "Fred"} Welcome Sir. {elseif $name eq "Wilma"} Welcome Ma'am. {else} Welcome, whatever you are. {/if} {* an example with "or" logic *} {if $name eq "Fred" or $name eq "Wilma"} ... {/if} {* parenthesis are allowed *} {if ( $amount < 0 or $amount > 1000 ) and $volume >= #minVolAmt#} ... {/if} {* you can also imbed php function calls *} {if count($var) gt 0} ... {/if} {* test if values are even or odd *} {if $var is even} ... {/if} {if $var is odd} ... {/if} {if $var is not odd} ... {/if} {* test if var is divisable by 4 *} {if $var is div by 4} ... {/if} {* same as previous example *} {if $var is mod 4} ... {/if} {* test if var is even, grouped by two. i.e., 0=even, 1=even, 2=odd, 3=odd, 4=even, 5=even, etc. *} {if $var is even by 2} ... {/if} {* 0=even, 1=even, 2=even, 3=odd, 4=odd, 5=odd, etc. *} {if $var is even by 3} ... {/if} ldelim,rdelim ldelim and rdelim are used for displaying the literal delimiter, in our case "{" or "}". The template engine always tries to interpret delimiters, so this is the way around that. Template example of ldelim, rdelim {* this will print literal delimiters out of the template *} {ldelim}funcname{rdelim} is how functions look in Smarty! OUTPUT: {funcname} is how functions look in Smarty! literal Literal tags allow a block of data to be taken literally, not being interpreted by the Smarty engine. This is handy for things like javascript sections, where there maybe curly braces and such things that would confuse the template parser. Anything within {literal}{/literal} tags is not interpreted, but displayed as-is. Template example of literal tags {literal} <script language=javascript> <!-- function isblank(field) { if (field.value == '') { return false; } else { document.loginform.submit(); return true; } } // --> </script> {/literal} section,sectionelse Template sections are used for looping over arrays of data. All section tags must be paired with /section tags. Required parameters are "name" and "loop". The name of the section can be anything you like, made up of letters, numbers and underscores. Sections can be nested, and the nested section names must be unique from each other. The loop variable determines the number of times the section will loop. When printing a variable within a section, the section name must be prepended to the variable name, separated by a slash (/). sectionelse is executed when there are no values in the loop variable. example: section {* this example will print out all the values of the $custid array *} {section name=customer loop=$custid} id: {$customer/custid}<br> {/section} OUTPUT: id: 1000<br> id: 1001<br> id: 1002<br> example: section loop variable {* the loop variable only determines the number of times to loop. you can access any variable from the template within the section. This example assumes that $custid, $name and $address are all arrays containing the same number of values *} {section name=customer loop=$custid} id: {$customer/custid}<br> name: {$customer/name}<br> address: {$customer/address}<br> <p> {/section} OUTPUT: id: 1000<br> name: John Smith<br> address: 253 N 45th <p> id: 1001<br> name: Jack Jones<br> address: 417 Mulberry ln <p> id: 1002<br> name: Jane Munson address: 5605 apple st <p> example: section names {* the name of the section can be anything you like, and it is used to reference the data within the section *} {section name=mydata loop=$custid} id: {$mydata/custid}<br> name: {$mydata/name}<br> address: {$mydata/address}<br> <p> {/section} example: nested sections {* sections can be nested as deep as you like. With nested sections, you can access complex data structures, such as multi-dimensional arrays. In this example, $customer/contact_type is an array of contact types for the current customer. *} {section name=customer loop=$custid} id: {$customer/custid}<br> name: {$customer/name}<br> address: {$customer/address}<br> {section name=contact loop=$customer/contact_type} {$customer/contact/contact_type}: {$customer/contact/contact_info}<br> {/section} <p> {/section} OUTPUT: id: 1000<br> name: John Smith<br> address: 253 N 45th home phone: 555-555-5555 cell phone: 555-555-5555 e-mail: john@mydomain.com <p> id: 1001<br> name: Jack Jones<br> address: 417 Mulberry ln home phone: 555-555-5555 cell phone: 555-555-5555 e-mail: jack@mydomain.com <p> id: 1002<br> name: Jane Munson address: 5605 apple st home phone: 555-555-5555 cell phone: 555-555-5555 e-mail: jane@mydomain.com <p> example: sectionelse {* sectionelse will execute in the case there are no $custid values *} {section name=customer loop=$custid} id: {$customer/custid}<br> {sectionelse} there are no values in $custid. {/section} Sections also have their own variables that handle section properties. These are indicated by percent signs around the variable name, like so: %sectionname.varname% index index is used to display the current loop iteration, starting with zero. example: section property index {section name=customer loop=$custid} {%customer.index%} id: {$customer/custid}<br> {/section} OUTPUT: 0 id: 1000<br> 1 id: 1001<br> 2 id: 1002<br> rownum rownum is used to display the current loop iteration, starting with one. example: section property rownum {section name=customer loop=$custid} {%customer.rownum%} id: {$customer/custid}<br> {/section} OUTPUT: 1 id: 1000<br> 2 id: 1001<br> 3 id: 1002<br> loop loop is used to display the total number of iterations this section is looped. This can be used inside or after the section. example: section property index {section name=customer loop=$custid} {%customer.index%} id: {$customer/custid}<br> {/section} There were {%customer.loop%} customers shown above. OUTPUT: 0 id: 1000<br> 1 id: 1001<br> 2 id: 1002<br> There were 3 customers shown above. show show is used both as a parameter to section, as well as displaying its value. show is a boolean value, true or false. If false, the section will not be displayed. If there is a sectionelse present, that will be alternately displayed. example: section property rownum {* $show_customer_info may have been passed from the PHP application, to regulate whether or not this section shows *} {section name=customer loop=$custid show=$show_customer_info} {%customer.rownum%} id: {$customer/custid}<br> {/section} {if %customer.show%} the section was shown. {else} the section was not shown. {/if} OUTPUT: 1 id: 1000<br> 2 id: 1001<br> 3 id: 1002<br> the section was shown. strip Many times web designers run into the issue where white space and carriage returns affect the output of the rendered HTML (browser "features"), so you must run all your tags together in the template to get the desired results. This usually ends up in unreadable or unmanagable templates. Anything within {strip}{/strip} tags in Smarty are stripped of the extra spaces or carriage returns at the beginnings and ends of the lines before they are displayed. This way you can keep your templates readable, and not worry about extra white space causing problems. Template example of strip tags {* the following will be all run into one line upon output *} {strip} <table border=0> <tr> <td> <A HREF="{$url}"> <font color="red">This is a test</font> </A> </td> </tr> </table> {/strip} OUTPUT: <table border=0><tr><td><A HREF="http://my.domain.com"><font color="red">This is a test</font></A></td></tr></table> Notice that in the above example, all the lines begin and end with HTML tags. Be aware that all the lines are run together. If you have plain text at the beginning or end of any line, they will be run together, and may not be desired results. Custom Functions Custom functions in Smarty work much the same as the built-in functions syntactically. Two custom functions come bundled with Smarty. You can also write your own. html_options html_options is a custom function that creates html option lists with provided data. It takes care of which item is selected by default as well. Template example of html_options {* assume that $cust_ids, and $cust_names are arrays of values, and $customer_id may or may not be set to a value *} <select name=customer_id> {html_options values=$cust_ids selected=$customer_id output=$cust_names} </select> OUTPUT: <select name=customer_id> <option value="1000">Joe Schmoe<option> <option value="1001" selected>Jack Smith<option> <option value="1002">Jane Johnson<option> <option value="1003">Charlie Brown<option> </select> This will create an option dropdown list using the values of the variables supplied in the template. html_select_date html_select_date is a custom function that creates date dropdowns for you. It can display any or all of year, month, and day. Possible attributes are (attr name, type, default val): prefix,string,"Date_" time,timestamp,(current time) start_year,int,(current year) end_year int (same as start_year) display_days, boolean, true display_months, boolean, true display_years, boolean, true month_format, strftime, "%B" day_format, strftime, "%02d" year_as_text, boolean, true Template example of html_select_date {html_select_date} OUTPUT: <select name="Date_Month"> <option value="1">January</option> <option value="2">February</option> <option value="3">March</option> <option value="4">April</option> <option value="5">May</option> <option value="6">June</option> <option value="7">July</option> <option value="8">August</option> <option value="9">September</option> <option value="10">October</option> <option value="11">November</option> <option value="12" selected>December</option> </select> <select name="Date_Day"> <option value="1">01</option> <option value="2">02</option> <option value="3">03</option> <option value="4">04</option> <option value="5">05</option> <option value="6">06</option> <option value="7">07</option> <option value="8">08</option> <option value="9">09</option> <option value="10">10</option> <option value="11">11</option> <option value="12">12</option> <option value="13" selected>13</option> <option value="14">14</option> <option value="15">15</option> <option value="16">16</option> <option value="17">17</option> <option value="18">18</option> <option value="19">19</option> <option value="20">20</option> <option value="21">21</option> <option value="22">22</option> <option value="23">23</option> <option value="24">24</option> <option value="25">25</option> <option value="26">26</option> <option value="27">27</option> <option value="28">28</option> <option value="29">29</option> <option value="30">30</option> <option value="31">31</option> </select> <select name="Date_Year"> <option value="2001" selected>2001</option> </select> Template example of html_select_date {html_select_date prefix="StartDate" time=$time start_year=1995 end_year=2001 display_days=false} <select name="StartDateMonth"> <option value="1">January</option> <option value="2">February</option> <option value="3">March</option> <option value="4">April</option> <option value="5">May</option> <option value="6">June</option> <option value="7">July</option> <option value="8">August</option> <option value="9">September</option> <option value="10">October</option> <option value="11">November</option> <option value="12" selected>December</option> </select> <select name="StartDateYear"> <option value="1999">1995</option> <option value="1999">1996</option> <option value="1999">1997</option> <option value="1999">1998</option> <option value="1999">1999</option> <option value="2000" selected>2000</option> <option value="2001">2001</option> </select> Creating your own Custom Functions Creating your own functions is a fairly straight forward process. The best way is to look at the ones that come with Smarty as examples. The function names begin with smarty_func_ and they are located in the Smarty.addons.php file. add your function to the Smarty.addons.php file. It is recommended that you prepend your function name with smarty_func_ map a template function name to your PHP function. This is done at the top of the Smarty.class.php file in the $custom_funcs array. Thats it! you can now call that function from within Smarty. All attributes passed to custom functions are passed into the first argument as an associative array. One way to get to those values is to call extract(func_get_arg(0)); at the top of your function. Anything that the function returns gets displayed in place of the tag in the template. Variable Modifiers Variable modifiers are a bit different than custom functions. They do just what they sound like, they modify variables before they are displayed to the template. The best way to explain these are by example. Template example of variable modifiers {* this displays a variable, unmodified *} {$articleTitle} OUTPUT: Burger King fire leaves seven pregnant teenagers <jobless> {* this displays the variable in all upper case *} {$articleTitle|upper} OUTPUT: BURGER KING FIRE LEAVES SEVEN PREGNANT TEENAGERS <JOBLESS> {* this displays the variable html escaped *} {$articleTitle|escape} OUTPUT: Burger King fire leaves seven pregnant teenagers &lt;jobless&gt; {* this displays the variable uppercased AND html escaped *} {$articleTitle|upper|escape} OUTPUT: BURGER KING FIRE LEAVES SEVEN PREGNANT TEENAGERS &lt;JOBLESS&gt; {* an example of passing a parameter to a modifier: this displays the variable url escaped *} {$articleTitle|escape:"url"} OUTPUT: Burger+King+fire+leaves+seven+pregnant+teenagers+%3Cjobless%3e {* print the first 24 characters of this variable, and follow with ... if it was longer *} {$articleTitle|truncate:24:"..."} OUTPUT: Burger King fire... {* print the date in default format *} {$startTime|date_format} OUTPUT: Dec 13, 2000 {* print the hour, minute and second portion of a date *} {$startTime|date_format:"%h:%m:%s"} OUTPUT: 10:33:02 {* print a number to the first two decimals *} {$amount|string_format:"%.2f"} OUTPUT: 24.02 {* print "Home Page" if $title is empty *} {$title|default:"Home Page"} OUTPUT: Home Page All modifiers will get the value of the variable as the first argument, and must return a single value. Modifier parameters are separated by colons. Any additional parameters passed to a modifier are passed as-is positionally, much like calling a PHP function. You can also use native PHP functions as modifiers, but only if they expect the correct arguments. If they do not, you can always write a wrapper function in Smarty to get what you want (date_format is a wrapper function to strftime() for example.) You can chain as many modifiers together on a variable as you like, separating each with a vertical pipe "|". NOTE: if you apply a modifier to an array instead of a single value variable, the modifier will be applied to every value in that array. If you really want the entire array passed to the modifier, you must prepend it with an "@" sign like so: {$articleTitle|@count} (this will print out the number of elements in the $articleTitle array.) capitalize This is used to capitalize the first letter of all words in a variable. date_format This formats a date into the given strftime() format. All dates should be passed to Smarty as a timestamp so that the template designer has full control of how this date is formatted. The default format is "%b %e, %Y", or "Jan 4, 2001" for example. These are the possible conversion specifiers: date_format conversion specifiers %a - abbreviated weekday name according to the current locale %A - full weekday name according to the current locale %b - abbreviated month name according to the current locale %B - full month name according to the current locale %c - preferred date and time representation for the current locale %C - century number (the year divided by 100 and truncated to an integer, range 00 to 99) %d - day of the month as a decimal number (range 00 to 31) %D - same as %m/%d/%y %e - day of the month as a decimal number, a single digit is preceded by a space (range ' 1' to '31') %h - same as %b %H - hour as a decimal number using a 24-hour clock (range 00 to 23) %I - hour as a decimal number using a 12-hour clock (range 01 to 12) %j - day of the year as a decimal number (range 001 to 366) %m - month as a decimal number (range 01 to 12) %M - minute as a decimal number %n - newline character %p - either `am' or `pm' according to the given time value, or the corresponding strings for the current locale %r - time in a.m. and p.m. notation %R - time in 24 hour notation %S - second as a decimal number %t - tab character %T - current time, equal to %H:%M:%S %u - weekday as a decimal number [1,7], with 1 representing Monday %U - week number of the current year as a decimal number, starting with the first Sunday as the first day of the first week %V - The ISO 8601:1988 week number of the current year as a decimal number, range 01 to 53, where week 1 is the first week that has at least 4 days in the current year, and with Monday as the first day of the week. %W - week number of the current year as a decimal number, starting with the first Monday as the first day of the first week %w - day of the week as a decimal, Sunday being 0 %x - preferred date representation for the current locale without the time %X - preferred time representation for the current locale without the date %y - year as a decimal number without a century (range 00 to 99) %Y - year as a decimal number including the century %Z - time zone or name or abbreviation %% - a literal `%' character default This is used to set a default value for a variable. If the variable is empty or unset, the given default value is printed instead. Default takes one argument, the value to use as the default value. escape This is used to html or url escape a variable. By default, the variable is html escaped. possible arguments are "url" or "html". lower This is used to lowercase a variable. replace A simple search and replace on a variable. The first argument is what to search for, the second argument is what to replace it with. spacify spacify is a way to insert spaces between every character of a variable. You can optionally pass a different character (or string) to insert. string_format This is a way to format strings, such as decimal numbers and such. Use the syntax for sprintf for the formatting. strip_tags This strips out markup tags, basically anything between < and >. truncate This truncates a variable to a character length, default is 80. As an optional second parameter, you can specify a string of text to display at the end if the variable was truncated. The characters in the string are included with the original truncation length. By default, truncate will attempt to cut off at a word boundary. If you want to cut off at the exact character length, pass the optional third parameter of true. upper This is used to uppercase a variable. Creating your own Variable Modifiers Creating your own modifiers is a fairly straight forward process. The best way is to look at the ones that come with Smarty as examples. The function names begin with smarty_mod_ and they are located in the Smarty.addons.php file. add your modifier to the Smarty.addons.php file. It is recommended that you prepend your function name with smarty_mod_ map a template modifier name to your PHP function. This is done at the top of the Smarty.class.php file in the $custom_mods array. Thats it! you can now use that modifier from within Smarty. Troubleshooting Smarty/PHP errors As of now, Smarty is not a validating template parser. This means that the parser will blindly convert the template to PHP scripts, irregardless of any syntax errors in the markup tags that may be present in the template. Smarty can catch certain template errors like missing attributes to functions, but not syntax errors like missing close tags. These types of errors can end up in PHP compile-time errors. When you encounter a PHP error when attempting to display the template in a browser, the error line number will correspond to the compiled PHP script, not the template itself. This may be a bit confusing or for the template designer. Our experience is to tell the designers to check their work often, and ask the programmers for help if they are really stuck. Usually you can look at the template and spot the syntax error. Here are some common things to look for: missing close tags for {if}{/if} or {section}{/section}, missing end variable delimiters like {%sec.var} instead of {%sec.var%}, or {#var} instead of {#var#}. If you can't find the error, you must open the compiled PHP file and go to the line number to figure out where the corresponding error is in the template. BUGS Check the BUGS file that comes with the latest distribution of Smarty, or check the website. PEAR Smarty uses the PEAR libraries for some of its error handling routines. PEAR libraries come with the distribution of PHP. Be sure that the path to these libraries is included in your php include_path. Unix users check /usr/local/lib/php. Windows users check C:/php/pear. CREDITS Monte Ohrt <monte@ispi.net>: Original idea and initial implementation, documentation. Andrei Zmievski <andrei@ispi.net>: Rewrote parser from scratch, added much functionality.