Skip to content

Commit

Permalink
Merge pull request #426 from WoltLab/unsafe-prefix
Browse files Browse the repository at this point in the history
Document the unsafe prefix
  • Loading branch information
BurntimeX authored Apr 30, 2024
2 parents f1cd366 + 1b532b5 commit 365f614
Show file tree
Hide file tree
Showing 32 changed files with 113 additions and 99 deletions.
6 changes: 3 additions & 3 deletions docs/javascript/general-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ and thus avoid outdated caches by relying on a unique value, without invalidatin
the cache more often that it needs to be.

```html
<script data-relocate="true" src="{$__wcf->getPath('app')}js/App.js?t={@LAST_UPDATE_TIME}"></script>
<script data-relocate="true" src="{$__wcf->getPath('app')}js/App.js?t={LAST_UPDATE_TIME}"></script>
```

For small scripts you can simply serve the full, non-minified version to the user
Expand All @@ -80,7 +80,7 @@ the minified and optimized file to the average visitor. You should use the
`ENABLE_DEBUG_MODE` constant to decide which version should be loaded.

```html
<script data-relocate="true" src="{$__wcf->getPath('app')}js/App{if !ENABLE_DEBUG_MODE}.min{/if}.js?t={@LAST_UPDATE_TIME}"></script>
<script data-relocate="true" src="{$__wcf->getPath('app')}js/App{if !ENABLE_DEBUG_MODE}.min{/if}.js?t={LAST_UPDATE_TIME}"></script>
```

### The Accelerated Guest View ("Tiny Builds")
Expand All @@ -91,7 +91,7 @@ The “Accelerated Guest View” aims to decrease page size and to improve respo
If you are providing a separate compiled build for this mode, you'll need to include yet another switch to serve the right version to the visitor.

```html
<script data-relocate="true" src="{$__wcf->getPath('app')}js/App{if !ENABLE_DEBUG_MODE}{if VISITOR_USE_TINY_BUILD}.tiny{/if}.min{/if}.js?t={@LAST_UPDATE_TIME}"></script>
<script data-relocate="true" src="{$__wcf->getPath('app')}js/App{if !ENABLE_DEBUG_MODE}{if VISITOR_USE_TINY_BUILD}.tiny{/if}.min{/if}.js?t={LAST_UPDATE_TIME}"></script>
```

### The `{js}` Template Plugin
Expand Down
13 changes: 13 additions & 0 deletions docs/migration/wsc60/templates.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Migrating from WoltLab Suite 6.0 - Templates

## `unsafe` Prefix

The `unsafe` prefix is intended as a replacement for the `@` prefix in order to output the content of a variable unfiltered. The new prefix offers better readability and makes it easier to find places where the prefix is used unintentionally. The old `@` prefix is still supported, but we recommend using the new prefix for new code.

Usage:

```smarty
Old: {@$foo}
New: {unsafe:$foo}
```

The code listed above outputs the raw content of the variable `$foo`.

## Shared Templates

Shared templates, applicable both in the frontend and the backend, are now standardized to begin with the
Expand Down
2 changes: 1 addition & 1 deletion docs/php/api/form_builder/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ Form fields that have a default id have to use `TDefaultIdFormField` and have to
The only thing to do in a template to display the **whole** form including all of the necessary JavaScript is to put

```smarty
{@$form->getHtml()}
{unsafe:$form->getHtml()}
```

into the template file at the relevant position.
2 changes: 1 addition & 1 deletion docs/tutorial/series/part_1.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ Because of using form builder, we only have to set up the two form fields for en
We will now only concentrate on the new parts compared to `personList.tpl`:

1. We use the `$action` variable to distinguish between the languages items used for adding a person and for creating a person.
1. Because of form builder, we only have to call `{@$form->getHtml()}` to generate all relevant output for the form.
1. Because of form builder, we only have to call `{unsafe:$form->getHtml()}` to generate all relevant output for the form.

### Person Edit Form

Expand Down
4 changes: 2 additions & 2 deletions docs/tutorial/series/part_2.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,13 @@ As the relevant template codes are only one line each, we will simply put them d
The code for the table head is similar to the other `th` elements:

```smarty
<th class="columnDate columnBirthday{if $sortField == 'birthday'} active {$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=birthday&sortOrder={if $sortField == 'birthday' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.birthday{/lang}</a></th>
<th class="columnDate columnBirthday{if $sortField == 'birthday'} active {$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=birthday&sortOrder={if $sortField == 'birthday' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.birthday{/lang}</a></th>
```

For the table body’s column, we need to make sure that the birthday is only show if it is actually set:

```smarty
<td class="columnDate columnBirthday">{if $person->birthday}{@$person->birthday|strtotime|date}{/if}</td>
<td class="columnDate columnBirthday">{if $person->birthday}{$person->birthday|strtotime|date}{/if}</td>
```


Expand Down
6 changes: 3 additions & 3 deletions docs/view/template-modifiers.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ A modifier may accept additional parameters that affect its behavior. These para

```smarty
<script>
var foo = '{@$foo|encodeJS}';
var foo = '{unsafe:$foo|encodeJS}';
</script>
```

Expand All @@ -63,7 +63,7 @@ A modifier may accept additional parameters that affect its behavior. These para
`escapeCDATA` encodes a string to be used in a `CDATA` element by replacing `]]>` with `]]]]><![CDATA[>`.

```smarty
<![CDATA[{@$foo|encodeCDATA}]]>
<![CDATA[{unsafe:$foo|encodeCDATA}]]>
```


Expand Down Expand Up @@ -98,7 +98,7 @@ A modifier may accept additional parameters that affect its behavior. These para

```smarty
<script>
let data = { "title": {@$foo->getTitle()|json} };
let data = { "title": {unsafe:$foo->getTitle()|json} };
</script>
```

Expand Down
6 changes: 3 additions & 3 deletions docs/view/template-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ For detailed information on its usage, we refer to the extensive documentation i
```smarty
{pages controller='FooList' link="pageNo=%d" print=true assign=pagesLinks} {* prints pagination *}
{@$pagesLinks} {* prints same pagination again *}
{unsafe:$pagesLinks} {* prints same pagination again *}
```

| Attribute | Description |
Expand Down Expand Up @@ -611,7 +611,7 @@ Examples:
generates

```smarty
<a href="{$user->getLink()}" data-object-id="{$user->userID}" class="userLink">{@$user->getFormattedUsername()}</a>
<a href="{$user->getLink()}" data-object-id="{$user->userID}" class="userLink">{unsafe:$user->getFormattedUsername()}</a>
```

and
Expand All @@ -623,5 +623,5 @@ and
generates

```smarty
<a href="{$user->getLink()}" foo="bar">{@$object->getAvatar()->getImageTag(48)}</a>
<a href="{$user->getLink()}" foo="bar">{unsafe:$object->getAvatar()->getImageTag(48)}</a>
```
9 changes: 5 additions & 4 deletions docs/view/templates.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ More information about installing templates can be found on those pages.
{if $errorType == 'empty'}
{lang}wcf.global.form.error.empty{/lang}
{else}
{lang}foo.bar.baz.error.{@$errorType}{/lang}
{lang}foo.bar.baz.error.{$errorType}{/lang}
{/if}
</small>
{/if}
Expand All @@ -99,7 +99,7 @@ More information about installing templates can be found on those pages.
<dd>
<textarea name="bar" id="bar" cols="40" rows="10">{$bar}</textarea>
{if $errorField == 'bar'}
<small class="innerError">{lang}foo.bar.bar.error.{@$errorType}{/lang}</small>
<small class="innerError">{lang}foo.bar.bar.error.{$errorType}{/lang}</small>
{/if}
</dd>
</dl>
Expand Down Expand Up @@ -178,8 +178,9 @@ Template variables can be assigned via `WCF::getTPL()->assign('foo', 'bar')` and
- `{$foo}` will result in the contents of `$foo` to be passed to `StringUtil::encodeHTML()` before being printed.
- `{#$foo}` will result in the contents of `$foo` to be passed to `StringUtil::formatNumeric()` before being printed.
Thus, this method is relevant when printing numbers and having them formatted correctly according the the user’s language.
- `{@$foo}` will result in the contents of `$foo` to be printed directly.
In general, this method should not be used for user-generated input.
- `{unsafe:$foo}` will result in the contents of `$foo` to be printed directly.
This method should only be used if you want to output the content of the variable directly and unfiltered.
Never use this method for user-generated input that has not already been sanitized by other means.

Multiple template variables can be assigned by passing an array:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
</nav>
</header>

{@$form->getHtml()}
{unsafe:$form->getHtml()}

{include file='footer'}
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
<table class="table jsObjectActionContainer" data-object-action-class-name="wcf\data\person\PersonAction">
<thead>
<tr>
<th class="columnID columnPersonID{if $sortField == 'personID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=personID&sortOrder={if $sortField == 'personID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
<th class="columnTitle columnFirstName{if $sortField == 'firstName'} active {@$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=firstName&sortOrder={if $sortField == 'firstName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.firstName{/lang}</a></th>
<th class="columnTitle columnLastName{if $sortField == 'lastName'} active {@$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=lastName&sortOrder={if $sortField == 'lastName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.lastName{/lang}</a></th>
<th class="columnID columnPersonID{if $sortField == 'personID'} active {$sortOrder}{/if}" colspan="2"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=personID&sortOrder={if $sortField == 'personID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
<th class="columnTitle columnFirstName{if $sortField == 'firstName'} active {$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=firstName&sortOrder={if $sortField == 'firstName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.firstName{/lang}</a></th>
<th class="columnTitle columnLastName{if $sortField == 'lastName'} active {$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=lastName&sortOrder={if $sortField == 'lastName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.lastName{/lang}</a></th>

{event name='columnHeads'}
</tr>
</thead>

<tbody class="jsReloadPageWhenEmpty">
{foreach from=$objects item=person}
<tr class="jsObjectActionObject" data-object-id="{@$person->getObjectID()}">
<tr class="jsObjectActionObject" data-object-id="{$person->getObjectID()}">
<td class="columnIcon">
<a href="{link controller='PersonEdit' object=$person}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a>
{objectAction action="delete" objectTitle=$person->getTitle()}
Expand All @@ -56,7 +56,7 @@
<footer class="contentFooter">
{hascontent}
<div class="paginationBottom">
{content}{@$pagesLinks}{/content}
{content}{unsafe:$pagesLinks}{/content}
</div>
{/hascontent}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

{capture assign='headContent'}
{if $pageNo < $pages}
<link rel="next" href="{link controller='PersonList'}pageNo={@$pageNo+1}{/link}">
<link rel="next" href="{link controller='PersonList'}pageNo={$pageNo+1}{/link}">
{/if}
{if $pageNo > 1}
<link rel="prev" href="{link controller='PersonList'}{if $pageNo > 2}pageNo={@$pageNo-1}{/if}{/link}">
<link rel="prev" href="{link controller='PersonList'}{if $pageNo > 2}pageNo={$pageNo-1}{/if}{/link}">
{/if}
<link rel="canonical" href="{link controller='PersonList'}{if $pageNo > 1}pageNo={@$pageNo}{/if}{/link}">
<link rel="canonical" href="{link controller='PersonList'}{if $pageNo > 1}pageNo={$pageNo}{/if}{/link}">
{/capture}

{capture assign='sidebarRight'}
Expand Down Expand Up @@ -86,7 +86,7 @@
<footer class="contentFooter">
{hascontent}
<div class="paginationBottom">
{content}{@$pagesLinks}{/content}
{content}{unsafe:$pagesLinks}{/content}
</div>
{/hascontent}

Expand Down
4 changes: 2 additions & 2 deletions snippets/tutorial/tutorial-series/part-2/templateListener.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
<templatelistener name="personListBirthdayColumnHead">
<eventname>columnHeads</eventname>
<environment>admin</environment>
<templatecode><![CDATA[<th class="columnDate columnBirthday{if $sortField == 'birthday'} active {@$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=birthday&sortOrder={if $sortField == 'birthday' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.birthday{/lang}</a></th>]]></templatecode>
<templatecode><![CDATA[<th class="columnDate columnBirthday{if $sortField == 'birthday'} active {$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=birthday&sortOrder={if $sortField == 'birthday' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.birthday{/lang}</a></th>]]></templatecode>
<templatename>personList</templatename>
</templatelistener>
<templatelistener name="personListBirthdayColumn">
<eventname>columns</eventname>
<environment>admin</environment>
<templatecode><![CDATA[<td class="columnDate columnBirthday">{if $person->birthday}{@$person->birthday|strtotime|date}{/if}</td>]]></templatecode>
<templatecode><![CDATA[<td class="columnDate columnBirthday">{if $person->birthday}{$person->birthday|strtotime|date}{/if}</td>]]></templatecode>
<templatename>personList</templatename>
</templatelistener>
<!-- /admin -->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{if $person->birthday}
<dt>{lang}wcf.person.birthday{/lang}</dt>
<dd>{@$person->birthday|strtotime|date}</dd>
<dd>{$person->birthday|strtotime|date}</dd>
{/if}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
</nav>
</header>

{@$form->getHtml()}
{unsafe:$form->getHtml()}

{include file='footer'}
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
<table class="table jsObjectActionContainer" data-object-action-class-name="wcf\data\person\PersonAction">
<thead>
<tr>
<th class="columnID columnPersonID{if $sortField == 'personID'} active {@$sortOrder}{/if}" colspan="2"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=personID&sortOrder={if $sortField == 'personID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
<th class="columnTitle columnFirstName{if $sortField == 'firstName'} active {@$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=firstName&sortOrder={if $sortField == 'firstName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.firstName{/lang}</a></th>
<th class="columnTitle columnLastName{if $sortField == 'lastName'} active {@$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={@$pageNo}&sortField=lastName&sortOrder={if $sortField == 'lastName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.lastName{/lang}</a></th>
<th class="columnID columnPersonID{if $sortField == 'personID'} active {$sortOrder}{/if}" colspan="2"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=personID&sortOrder={if $sortField == 'personID' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.global.objectID{/lang}</a></th>
<th class="columnTitle columnFirstName{if $sortField == 'firstName'} active {$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=firstName&sortOrder={if $sortField == 'firstName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.firstName{/lang}</a></th>
<th class="columnTitle columnLastName{if $sortField == 'lastName'} active {$sortOrder}{/if}"><a href="{link controller='PersonList'}pageNo={$pageNo}&sortField=lastName&sortOrder={if $sortField == 'lastName' && $sortOrder == 'ASC'}DESC{else}ASC{/if}{/link}">{lang}wcf.person.lastName{/lang}</a></th>

{event name='columnHeads'}
</tr>
</thead>

<tbody class="jsReloadPageWhenEmpty">
{foreach from=$objects item=person}
<tr class="jsObjectActionObject" data-object-id="{@$person->getObjectID()}">
<tr class="jsObjectActionObject" data-object-id="{$person->getObjectID()}">
<td class="columnIcon">
<a href="{link controller='PersonEdit' object=$person}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a>
{objectAction action="delete" objectTitle=$person->getTitle()}
Expand All @@ -56,7 +56,7 @@
<footer class="contentFooter">
{hascontent}
<div class="paginationBottom">
{content}{@$pagesLinks}{/content}
{content}{unsafe:$pagesLinks}{/content}
</div>
{/hascontent}

Expand Down
8 changes: 4 additions & 4 deletions snippets/tutorial/tutorial-series/part-3/templates/person.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
<div class="personComments">
<ul id="personCommentList" class="commentList containerList" {*
*}data-can-add="{if $commentCanAdd}true{else}false{/if}" {*
*}data-object-id="{@$person->personID}" {*
*}data-object-type-id="{@$commentObjectTypeID}" {*
*}data-comments="{if $person->comments}{@$commentList->countObjects()}{else}0{/if}" {*
*}data-last-comment-time="{@$lastCommentTime}" {*
*}data-object-id="{$person->personID}" {*
*}data-object-type-id="{$commentObjectTypeID}" {*
*}data-comments="{if $person->comments}{$commentList->countObjects()}{else}0{/if}" {*
*}data-last-comment-time="{$lastCommentTime}" {*
*}>
{include file='commentListAddComment' wysiwygSelector='personCommentListAddComment'}
{include file='commentList'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

{capture assign='headContent'}
{if $pageNo < $pages}
<link rel="next" href="{link controller='PersonList'}pageNo={@$pageNo+1}{/link}">
<link rel="next" href="{link controller='PersonList'}pageNo={$pageNo+1}{/link}">
{/if}
{if $pageNo > 1}
<link rel="prev" href="{link controller='PersonList'}{if $pageNo > 2}pageNo={@$pageNo-1}{/if}{/link}">
<link rel="prev" href="{link controller='PersonList'}{if $pageNo > 2}pageNo={$pageNo-1}{/if}{/link}">
{/if}
<link rel="canonical" href="{link controller='PersonList'}{if $pageNo > 1}pageNo={@$pageNo}{/if}{/link}">
<link rel="canonical" href="{link controller='PersonList'}{if $pageNo > 1}pageNo={$pageNo}{/if}{/link}">
{/capture}

{capture assign='sidebarRight'}
Expand Down Expand Up @@ -93,7 +93,7 @@
<footer class="contentFooter">
{hascontent}
<div class="paginationBottom">
{content}{@$pagesLinks}{/content}
{content}{unsafe:$pagesLinks}{/content}
</div>
{/hascontent}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@
</nav>
</header>

{@$form->getHtml()}
{unsafe:$form->getHtml()}

{include file='footer'}
Loading

0 comments on commit 365f614

Please sign in to comment.