Fix internal links
[GitHub/WoltLab/woltlab.github.io.git] / docs / view_templates.md
1 ---
2 title: Templates
3 sidebar: sidebar
4 permalink: view_templates.html
5 folder: view
6 parent: view
7 ---
8
9 Templates are responsible for the output a user sees when requesting a page (while the PHP code is responsible for providing the data that will be shown).
10 Templates are text files with `.tpl` as the file extension.
11 WoltLab Suite Core compiles the template files once into a PHP file that is executed when a user requests the page.
12 In subsequent request, as the PHP file containing the compiled template already exists, compiling the template is not necessary anymore.
13
14
15 ## Template Types and Conventions
16
17 WoltLab Suite Core supports two types of templates:
18 frontend templates (or simply *templates*) and backend templates (*ACP templates*).
19 Each type of template is only available in its respective domain, thus frontend templates cannot be included or used in the ACP and vice versa.
20
21 For pages and forms, the name of the template matches the unqualified name of the PHP class except for the `Page` or `Form` suffix:
22
23 - `RegisterForm.class.php` → `register.tpl`
24 - `UserPage.class.php` → `user.tpl`
25
26 If you follow this convention, WoltLab Suite Core will automatically determine the template name so that you do not have to explicitly set it.
27
28 {% include callout.html content="For forms that handle creating and editing objects, in general, there are two form classes: `FooAddForm` and `FooEditForm`. WoltLab Suite Core, however, generally only uses one template `fooAdd.tpl` and the template variable `$action` to distinguish between creating a new object (`$action = 'add'`) and editing an existing object (`$action = 'edit'`) as the differences between templates for adding and editing an object are minimal." type="info" %}
29
30
31
32 ## Installing Templates
33
34 Templates and ACP templates are installed by two different package installation plugins:
35 the [template PIP](package_pip_template.md) and the [ACP template PIP](package_pip_acp-template.md).
36 More information about installing templates can be found on those pages.
37
38
39 ## Base Templates
40
41 ### Frontend
42
43 ```smarty
44 {include file='header'}
45
46 {* content *}
47
48 {include file='footer'}
49 ```
50
51 ### Backend
52
53 ```smarty
54 {include file='header' pageTitle='foo.bar.baz'}
55
56 <header class="contentHeader">
57 <div class="contentHeaderTitle">
58 <h1 class="contentTitle">Title</h1>
59 </div>
60
61 <nav class="contentHeaderNavigation">
62 <ul>
63 {* your default content header navigation buttons *}
64
65 {event name='contentHeaderNavigation'}
66 </ul>
67 </nav>
68 </header>
69
70 {* content *}
71
72 {include file='footer'}
73 ```
74
75 `foo.bar.baz` is the language item that contains the title of the page.
76
77
78 ## Common Template Components
79
80 ### Forms
81
82 {% include callout.html content="For new forms, use the new [form builder API](php_api_form_builder.md) introduced with WoltLab Suite 5.2." type="info" %}
83
84 ```smarty
85 <form method="post" action="{link controller='FooBar'}{/link}">
86 <div class="section">
87 <dl{if $errorField == 'baz'} class="formError"{/if}>
88 <dt><label for="baz">{lang}foo.bar.baz{/lang}</label></dt>
89 <dd>
90 <input type="text" id="baz" name="baz" value="{$baz}" class="long" required autofocus>
91 {if $errorField == 'baz'}
92 <small class="innerError">
93 {if $errorType == 'empty'}
94 {lang}wcf.global.form.error.empty{/lang}
95 {else}
96 {lang}foo.bar.baz.error.{@$errorType}{/lang}
97 {/if}
98 </small>
99 {/if}
100 </dd>
101 </dl>
102
103 <dl>
104 <dt><label for="bar">{lang}foo.bar.bar{/lang}</label></dt>
105 <dd>
106 <textarea name="bar" id="bar" cols="40" rows="10">{$bar}</textarea>
107 {if $errorField == 'bar'}
108 <small class="innerError">{lang}foo.bar.bar.error.{@$errorType}{/lang}</small>
109 {/if}
110 </dd>
111 </dl>
112
113 {* other fields *}
114
115 {event name='dataFields'}
116 </div>
117
118 {* other sections *}
119
120 {event name='sections'}
121
122 <div class="formSubmit">
123 <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
124 {csrfToken}
125 </div>
126 </form>
127 ```
128
129 ### Tab Menus
130
131 ```smarty
132 <div class="section tabMenuContainer">
133 <nav class="tabMenu">
134 <ul>
135 <li><a href="{@$__wcf->getAnchor('tab1')}">Tab 1</a></li>
136 <li><a href="{@$__wcf->getAnchor('tab2')}">Tab 2</a></li>
137
138 {event name='tabMenuTabs'}
139 </ul>
140 </nav>
141
142 <div id="tab1" class="tabMenuContent">
143 <div class="section">
144 {* contents of first tab *}
145 </div>
146 </div>
147
148 <div id="tab2" class="tabMenuContainer tabMenuContent">
149 <nav class="menu">
150 <ul>
151 <li><a href="{@$__wcf->getAnchor('tab2A')}">Tab 2A</a></li>
152 <li><a href="{@$__wcf->getAnchor('tab2B')}">Tab 2B</a></li>
153
154 {event name='tabMenuTab2Subtabs'}
155 </ul>
156 </nav>
157
158 <div id="tab2A" class="tabMenuContent">
159 <div class="section">
160 {* contents of first subtab for second tab *}
161 </div>
162 </div>
163
164 <div id="tab2B" class="tabMenuContent">
165 <div class="section">
166 {* contents of second subtab for second tab *}
167 </div>
168 </div>
169
170 {event name='tabMenuTab2Contents'}
171 </div>
172
173 {event name='tabMenuContents'}
174 </div>
175 ```
176
177
178 ## Template Scripting
179
180 ### Template Variables
181
182 Template variables can be assigned via `WCF::getTPL()->assign('foo', 'bar')` and accessed in templates via `$foo`:
183
184 - `{$foo}` will result in the contents of `$foo` to be passed to `StringUtil::encodeHTML()` before being printed.
185 - `{#$foo}` will result in the contents of `$foo` to be passed to `StringUtil::formatNumeric()` before being printed.
186 Thus, this method is relevant when printing numbers and having them formatted correctly according the the user’s language.
187 - `{@$foo}` will result in the contents of `$foo` to be printed directly.
188 In general, this method should not be used for user-generated input.
189
190 Multiple template variables can be assigned by passing an array:
191
192 ```php
193 WCF::getTPL()->assign([
194 'foo' => 'bar',
195 'baz' => false
196 ]);
197 ```
198
199 #### Modifiers
200
201 If you want to call a function on a variable, you can use the modifier syntax:
202 `{@$foo|trim}`, for example, results in the trimmed contents of `$foo` to be printed.
203
204 #### System Template Variable
205
206 The template variable `$tpl` is automatically assigned and is an array containing different data:
207
208 - `$tpl[get]` contains `$_GET`.
209 - `$tpl[post]` contains `$_POST`.
210 - `$tpl[cookie]` contains `$_COOKIE`.
211 - `$tpl[server]` contains `$_SERVER`.
212 - `$tpl[env]` contains `$_ENV`.
213 - `$tpl[now]` contains `TIME_NOW` (current timestamp).
214
215 Furthermore, the following template variables are also automatically assigned:
216
217 - `$__wcf` contains the `WCF` object (or `WCFACP` object in the backend).
218
219 ### Comments
220
221 Comments are wrapped in `{*` and `*}` and can span multiple lines:
222
223 ```smarty
224 {* some
225 comment *}
226 ```
227
228 {% include callout.html content="The template compiler discards the comments, so that they not included in the compiled template." type="info" %}
229
230 ### Conditions
231
232 Conditions follow a similar syntax to PHP code:
233
234 ```smarty
235 {if $foo === 'bar'}
236 foo is bar
237 {elseif $foo === 'baz'}
238 foo is baz
239 {else}
240 foo is neither bar nor baz
241 {/if}
242 ```
243
244 The supported operators in conditions are `===`, `!==`, `==`, `!=`, `<=`, `<`, `>=`, `>`, `||`, `&&`, `!`, and `=`.
245
246 More examples:
247
248 ````smarty
249 {if $bar|isset}…{/if}
250
251 {if $bar|count > 3 && $bar|count < 100}…{/if}
252 ````
253
254 ### Foreach Loops
255
256 Foreach loops allow to iterate over arrays or iterable objects:
257
258 ```smarty
259 <ul>
260 {foreach from=$array key=key item=value}
261 <li>{$key}: {$value}</li>
262 {/foreach}
263 </ul>
264 ```
265
266 While the `from` attribute containing the iterated structure and the `item` attribute containg the current value are mandatory, the `key` attribute is optional.
267 If the foreach loop has a name assigned to it via the `name` attribute, the `$tpl` template variable provides additional data about the loop:
268
269 ```smarty
270 <ul>
271 {foreach from=$array key=key item=value name=foo}
272 {if $tpl[foreach][foo][first]}
273 something special for the first iteration
274 {elseif $tpl[foreach][foo][last]}
275 something special for the last iteration
276 {/if}
277
278 <li>iteration {#$tpl[foreach][foo][iteration]+1} out of {#$tpl[foreach][foo][total]} {$key}: {$value}</li>
279 {/foreach}
280 </ul>
281 ```
282
283 In contrast to PHP’s foreach loop, templates also support `foreachelse`:
284
285 ```smarty
286 {foreach from=$array item=value}
287
288 {foreachelse}
289 there is nothing to iterate over
290 {/foreach}
291 ```
292
293 ### Including Other Templates
294
295 To include template named `foo` from the same domain (frontend/backend), you can use
296
297 ```smarty
298 {include file='foo'}
299 ```
300
301 If the template belongs to an application, you have to specify that application using the `application` attribute:
302
303 ```smarty
304 {include file='foo' application='app'}
305 ```
306
307 Additional template variables can be passed to the included template as additional attributes:
308
309 ```smarty
310 {include file='foo' application='app' var1='foo1' var2='foo2'}
311 ```
312
313 ### Template Plugins
314
315 An overview of all available template plugins can be found [here](view_template-plugins.md).