XF 2.1 XF template "functions"?

frm

Well-known member
I know that most template conditional statements are in the docs, but there's no mention of "functions" that exist here. However, I see one in many templates and learned of another on these forums.

Am I to understand that only dump() and link() are the only ones that exist? If not, what else is there and what is a quick synopsis of what they do?

Specifically, I'm looking to replace a comma in a string/array (something along the lines of PHP str_replace). But, I would like to know if anything else exists as a reference for later.

The developer documentation makes no note of these (and lacks some tags too).
 
Solution
Have a look in src/XF/Template/Templater.php

PHP:
protected $defaultFilters = [
        'default'          => 'filterDefault',
        'censor'           => 'filterCensor',
        'count'            => 'filterCount',
        'currency'         => 'filterCurrency',
        'emoji'            => 'filterEmoji',
        'escape'           => 'filterEscape',
        'for_attr'         => 'filterForAttr',
        'file_size'        => 'filterFileSize',
        'first'            => 'filterFirst',
        'format'           => 'filterFormat',
        'hex'              => 'filterHex',
        'host'             => 'filterHost',
        'htmlspecialchars' => 'filterHtmlspecialchars',
        'ip'               => 'filterIp',
        'join'...
Have a look in src/XF/Template/Templater.php

PHP:
protected $defaultFilters = [
        'default'          => 'filterDefault',
        'censor'           => 'filterCensor',
        'count'            => 'filterCount',
        'currency'         => 'filterCurrency',
        'emoji'            => 'filterEmoji',
        'escape'           => 'filterEscape',
        'for_attr'         => 'filterForAttr',
        'file_size'        => 'filterFileSize',
        'first'            => 'filterFirst',
        'format'           => 'filterFormat',
        'hex'              => 'filterHex',
        'host'             => 'filterHost',
        'htmlspecialchars' => 'filterHtmlspecialchars',
        'ip'               => 'filterIp',
        'join'             => 'filterJoin',
        'json'             => 'filterJson',
        'last'             => 'filterLast',
        'nl2br'            => 'filterNl2Br',
        'nl2nl'            => 'filterNl2Nl',
        'number'           => 'filterNumber',
        'number_short'     => 'filterNumberShort',
        'numeric_keys_only' => 'filterNumericKeysOnly',
        'pad'              => 'filterPad',
        'parens'           => 'filterParens',
        'pluck'            => 'filterPluck',
        'preescaped'       => 'filterPreEscaped',
        'raw'              => 'filterRaw',
        'replace'          => 'filterReplace',
        'split'            => 'filterSplit',
        'split_long'       => 'filterSplitLong',
        'strip_tags'       => 'filterStripTags',
        'to_lower'         => 'filterToLower',
        'to_upper'         => 'filterToUpper',
        'de_camel'         => 'filterDeCamel',
        'substr'           => 'filterSubstr',
        'url'              => 'filterUrl',
        'urlencode'        => 'filterUrlencode',
        'zerofill'         => 'filterZeroFill',
    ];

    protected $defaultFunctions = [
        'anchor_target'         => 'fnAnchorTarget',
        'array_keys'            => 'fnArrayKeys',
        'array_merge'           => 'fnArrayMerge',
        'array_values'          => 'fnArrayValues',
        'asset'                 => 'fnAsset',
        'attributes'            => 'fnAttributes',
        'avatar'                => 'fnAvatar',
        'base_url'              => 'fnBaseUrl',
        'bb_code'               => 'fnBbCode',
        'bb_code_snippet'       => 'fnBbCodeSnippet',
        'bb_code_type'          => 'fnBbCodeType',
        'bb_code_type_snippet'  => 'fnBbCodeTypeSnippet',
        'button_icon'           => 'fnButtonIcon',
        'cache_key'             => 'fnCacheKey',
        'call_macro'            => 'fnCallMacro',
        'callable'              => 'fnCallable',
        'captcha'               => 'fnCaptcha',
        'ceil'                  => 'fnCeil',
        'contains'              => 'fnContains',
        'copyright'             => 'fnCopyright',
        'core_js'               => 'fnCoreJs',
        'count'                 => 'fnCount',
        'csrf_input'            => 'fnCsrfInput',
        'csrf_token'            => 'fnCsrfToken',
        'css_url'               => 'fnCssUrl',
        'date'                  => 'fnDate',
        'date_from_format'      => 'fnDateFromFormat',
        'date_dynamic'          => 'fnDateDynamic',
        'date_time'             => 'fnDateTime',
        'debug_url'             => 'fnDebugUrl',
        'display_totals'        => 'fnDisplayTotals',
        'dump'                  => 'fnDump',
        'dump_simple'           => 'fnDumpSimple',
        'duration'              => 'fnDuration',
        'empty'                 => 'fnEmpty',
        'fa_weight'             => 'fnFaWeight',
        'file_size'             => 'fnFileSize',
        'floor'                 => 'fnFloor',
        'gravatar_url'          => 'fnGravatarUrl',
        'highlight'             => 'fnHighlight',
        'in_array'              => 'fnInArray',
        'is_array'              => 'fnIsArray',
        'is_scalar'             => 'fnIsScalar',
        'is_addon_active'       => 'fnIsAddonActive',
        'is_editor_capable'     => 'fnIsEditorCapable',
        'is_toggled'            => 'fnIsToggled',
        'js_url'                => 'fnJsUrl',
        'key_exists'            => 'fnKeyExists',
        'last_pages'            => 'fnLastPages',
        'likes'                 => 'fnLikes',
        'likes_content'         => 'fnLikesContent',
        'link'                  => 'fnLink',
        'link_type'             => 'fnLinkType',
        'min'                   => 'fnMin',
        'max'                   => 'fnMax',
        'max_length'            => 'fnMaxLength',
        'media_sites'           => 'fnMediaSites',
        'mustache'              => 'fnMustache',
        'number'                => 'fnNumber',
        'number_short'          => 'fnNumberShort',
        'named_colors'          => 'fnNamedColors',
        'page_description'      => 'fnPageDescription',
        'page_h1'               => 'fnPageH1',
        'page_nav'              => 'fnPageNav',
        'page_param'            => 'fnPageParam',
        'page_title'            => 'fnPageTitle',
        'parens'                => 'fnParens',
        'parse_less_color'      => 'fnParseLessColor',
        'phrase_dynamic'        => 'fnPhraseDynamic',
        'prefix'                => 'fnPrefix',
        'prefix_group'          => 'fnPrefixGroup',
        'prefix_title'          => 'fnPrefixTitle',
        'prefix_description'    => 'fnPrefixDescription',
        'prefix_usage_help'     => 'fnPrefixUsageHelp',
        'profile_banner'        => 'fnProfileBanner',
        'property'              => 'fnProperty',
        'rand'                  => 'fnRand',
        'range'                 => 'fnRange',
        'react'                 => 'fnReact',
        'alert_reaction'        => 'fnAlertReaction',
        'reaction'              => 'fnReaction',
        'reaction_title'        => 'fnReactionTitle',
        'reactions'             => 'fnReactions',
        'reactions_content'     => 'fnReactionsContent',
        'reactions_summary'     => 'fnReactionsSummary',
        'redirect_input'        => 'fnRedirectInput',
        'repeat'                => 'fnRepeat',
        'repeat_raw'            => 'fnRepeatRaw',
        'short_to_emoji'        => 'fnShortToEmoji',
        'show_ignored'          => 'fnShowIgnored',
        'smilie'                => 'fnSmilie',
        'snippet'               => 'fnSnippet',
        'strlen'                => 'fnStrlen',
        'structured_text'       => 'fnStructuredText',
        'templater'             => 'fnTemplater',
        'time'                  => 'fnTime',
        'transparent_img'       => 'fnTransparentImg',
        'trim'                  => 'fnTrim',
        'unique_id'             => 'fnUniqueId',
        'user_activity'         => 'fnUserActivity',
        'user_banners'          => 'fnUserBanners',
        'user_blurb'            => 'fnUserBlurb',
        'user_title'            => 'fnUserTitle',
        'username_link'         => 'fnUsernameLink',
        'username_link_email'   => 'fnUsernameLinkEmail',
        'widget_data'           => 'fnWidgetData'
    ];

    protected $defaultTests = [
        'empty' => 'testEmpty'
    ];

    protected $overlayClickOptions = [
        'data-cache',
        'data-overlay-config',
        'data-force-flash-message',
        'data-follow-redirects'
    ];
 
  • Like
Reactions: frm
Solution
About the function 'replace' => 'filterReplace',
How could I use it on the template code?

I want to replace all ' .' with '.'? (I mean to replace space and full stop with only full stop).
I'm looking something like <xf:something> but replace seems to be used on variables like $var|replace.

PS: I have some proposals inside a template where I use xf:if conditionals to make the output. So some useless spaces are added and I want to fix it. I need to wrap this template code with a function to do the above replace.
 
Trim is used for trimming whitespace but it doesn't help if the unwanted whitespace is in the middle of a string. It only trims leading and trailing whitespace from the string.

Maybe some context would help. Why do you actually want to do this?
 
I have a template with some proposals which has <xf:if> to show the final text on the public,
Example
<xf:if is="$gender == 'male'">something<xf:else />something else</xf:if>.
Lots of conditionals like the above. In some points the proposal gets full stop and a new proposal is starting etc.

This has the result some unwanted whitespaces like '{space}.' and '{space},{space}' which I want to replace them with '.{space}' and ',{space}'.

Does it make sense?
 
I might be wrong, but I think there is currently no straightforward way to achieve this.

But smth. like this (if a trim is okay) might work:
Code:
<xf:set var="$html">
some .
code , test
here
</xf:set>
<pre>{{ trim($html)|replace({' .': '. ', ' , ': ', '}) }}</pre>

Another approach (which "abuses" substr to workaround replace not processing preescaped data):
Code:
<pre>{$html|substr(0)|replace({' .': '. ', ' , ': ', '})}</pre>
 
Last edited:
I might be wrong, but I think there is currently no straightforward way to achieve this.

But smth. like this (if a trim is okay) might work:
Code:
<xf:set var="$html">
some .
code , test
here
</xf:set>
<pre>{{ trim($html)|replace({' .': '. ', ' , ': ', '}) }}</pre>
oh yes, this is what I was looking for. :)

But trim seems not working.
For example, the result on the browser console is the following (due to the lots <xf:if>), but for some reason the browser shows it as one white space to the visitor / final page. So the replacement list cannot detected since in reality there are more than one whitespaces.


I thought that {{ trim($html) }} should keep only one whitespace from all the $html, but in reality did not do it.

In browser development console:
HTML:
<div class="message_userDetails_desc">
    Peter is
                <strong>
                    online at the moment.
                </strong>    
             
                     
                     
                            He is
                         
                                <strong>32</strong> years old
                                    ,
                                 
                             
                         
                         
                             
                                    <strong>Student</strong>
                                 
                                 
                                     
                                                                     
                                 
                             
                         
                            and he
                     
                        writes us from <strong>Greece</strong>.
                                 
             
             
                    He has
                 
                        <a href="/isxf22/search/member?user_id=304"><strong>11,729</strong></a> posts.
</div>
 
ok I was able to fix :)

Solution:
1. Extend the Templater class as follows:
PHP:
class Templater extends XFCP_Templater
{
    public function __construct(App $app, Language $language, $compiledPath)
    {
        $this->defaultFunctions['sctrim'] = 'fnScTrim';
        return parent::__construct($app, $language, $compiledPath);
    }

    public function fnScTrim($templater, &$escape, $str, $charlist = " \t\n\r\0\x0B")
    {
        return preg_replace('/\s+/', ' ', trim($str, $charlist));
    }
}
Use this on the template:
Code:
{{ sctrim($user_text)|replace({' .': '. ', ' , ': ', '})|raw }}
 
While I don't envisage any particular issues with the approach it isn't our recommended approach to adding new templater functions.

You should create a code event listener for the templater_setup event which looks like:

PHP:
public static function templaterSetup(\XF\Container $container, \XF\Template\Templater &$templater)
{
   $templater->addFunction('sctrim', function($templater, &$escape, $str, $charlist = " \t\n\r\0\x0B")
   {
      return preg_replace('/\s+/', ' ', trim($str, $charlist));
   });
}

Generally speaking the rule is if there is a code event listener to achieve something that should be used instead before doing a class extension. In some cases you might need a class extension to do other stuff (applies a lot to Entity class extensions) but for the Templater this approach would trump a class extension in the sheer majority of cases.
 
Why not use the regular expression '/\s([.,])/', '\1' on the results of the first call to collapse white space?

There is a way to do it all at once, but i tend to go with a couple simple regexs
 
I have a template with some proposals which has <xf:if> to show the final text on the public,
Example
<xf:if is="$gender == 'male'">something<xf:else />something else</xf:if>.
Lots of conditionals like the above. In some points the proposal gets full stop and a new proposal is starting etc.

This has the result some unwanted whitespaces like '{space}.' and '{space},{space}' which I want to replace them with '.{space}' and ',{space}'.

Does it make sense?

Pretty much as I said in my previous post, wrap the conditionals in an <xf:trim> tag, anything else is unnecessary.
Code:
<xf:trim>
<xf:if is="true">
a
<xf:else />
b
</xf:if>
</xf:trim>.

Will result in a final template output
Code:
a.

More ideally, if you're building sentences like that, you should set the values as variables instead and feed them into phrases, so they can be translated.
Code:
<xf:set var="$x"><xf:trim>
<xf:trim>
<xf:if is="true">
a
<xf:else />
b
</xf:if>
</xf:trim>
</xf:set>

{{ phrase('my_phrase', {'x': $x}) }}
 
Have a look in src/XF/Template/Templater.php

PHP:
protected $defaultFilters = [
        'default'          => 'filterDefault',
        'censor'           => 'filterCensor',
        'count'            => 'filterCount',
        'currency'         => 'filterCurrency',
        'emoji'            => 'filterEmoji',
        'escape'           => 'filterEscape',
        'for_attr'         => 'filterForAttr',
        'file_size'        => 'filterFileSize',
        'first'            => 'filterFirst',
        'format'           => 'filterFormat',
        'hex'              => 'filterHex',
        'host'             => 'filterHost',
        'htmlspecialchars' => 'filterHtmlspecialchars',
        'ip'               => 'filterIp',
        'join'             => 'filterJoin',
        'json'             => 'filterJson',
        'last'             => 'filterLast',
        'nl2br'            => 'filterNl2Br',
        'nl2nl'            => 'filterNl2Nl',
        'number'           => 'filterNumber',
        'number_short'     => 'filterNumberShort',
        'numeric_keys_only' => 'filterNumericKeysOnly',
        'pad'              => 'filterPad',
        'parens'           => 'filterParens',
        'pluck'            => 'filterPluck',
        'preescaped'       => 'filterPreEscaped',
        'raw'              => 'filterRaw',
        'replace'          => 'filterReplace',
        'split'            => 'filterSplit',
        'split_long'       => 'filterSplitLong',
        'strip_tags'       => 'filterStripTags',
        'to_lower'         => 'filterToLower',
        'to_upper'         => 'filterToUpper',
        'de_camel'         => 'filterDeCamel',
        'substr'           => 'filterSubstr',
        'url'              => 'filterUrl',
        'urlencode'        => 'filterUrlencode',
        'zerofill'         => 'filterZeroFill',
    ];

    protected $defaultFunctions = [
        'anchor_target'         => 'fnAnchorTarget',
        'array_keys'            => 'fnArrayKeys',
        'array_merge'           => 'fnArrayMerge',
        'array_values'          => 'fnArrayValues',
        'asset'                 => 'fnAsset',
        'attributes'            => 'fnAttributes',
        'avatar'                => 'fnAvatar',
        'base_url'              => 'fnBaseUrl',
        'bb_code'               => 'fnBbCode',
        'bb_code_snippet'       => 'fnBbCodeSnippet',
        'bb_code_type'          => 'fnBbCodeType',
        'bb_code_type_snippet'  => 'fnBbCodeTypeSnippet',
        'button_icon'           => 'fnButtonIcon',
        'cache_key'             => 'fnCacheKey',
        'call_macro'            => 'fnCallMacro',
        'callable'              => 'fnCallable',
        'captcha'               => 'fnCaptcha',
        'ceil'                  => 'fnCeil',
        'contains'              => 'fnContains',
        'copyright'             => 'fnCopyright',
        'core_js'               => 'fnCoreJs',
        'count'                 => 'fnCount',
        'csrf_input'            => 'fnCsrfInput',
        'csrf_token'            => 'fnCsrfToken',
        'css_url'               => 'fnCssUrl',
        'date'                  => 'fnDate',
        'date_from_format'      => 'fnDateFromFormat',
        'date_dynamic'          => 'fnDateDynamic',
        'date_time'             => 'fnDateTime',
        'debug_url'             => 'fnDebugUrl',
        'display_totals'        => 'fnDisplayTotals',
        'dump'                  => 'fnDump',
        'dump_simple'           => 'fnDumpSimple',
        'duration'              => 'fnDuration',
        'empty'                 => 'fnEmpty',
        'fa_weight'             => 'fnFaWeight',
        'file_size'             => 'fnFileSize',
        'floor'                 => 'fnFloor',
        'gravatar_url'          => 'fnGravatarUrl',
        'highlight'             => 'fnHighlight',
        'in_array'              => 'fnInArray',
        'is_array'              => 'fnIsArray',
        'is_scalar'             => 'fnIsScalar',
        'is_addon_active'       => 'fnIsAddonActive',
        'is_editor_capable'     => 'fnIsEditorCapable',
        'is_toggled'            => 'fnIsToggled',
        'js_url'                => 'fnJsUrl',
        'key_exists'            => 'fnKeyExists',
        'last_pages'            => 'fnLastPages',
        'likes'                 => 'fnLikes',
        'likes_content'         => 'fnLikesContent',
        'link'                  => 'fnLink',
        'link_type'             => 'fnLinkType',
        'min'                   => 'fnMin',
        'max'                   => 'fnMax',
        'max_length'            => 'fnMaxLength',
        'media_sites'           => 'fnMediaSites',
        'mustache'              => 'fnMustache',
        'number'                => 'fnNumber',
        'number_short'          => 'fnNumberShort',
        'named_colors'          => 'fnNamedColors',
        'page_description'      => 'fnPageDescription',
        'page_h1'               => 'fnPageH1',
        'page_nav'              => 'fnPageNav',
        'page_param'            => 'fnPageParam',
        'page_title'            => 'fnPageTitle',
        'parens'                => 'fnParens',
        'parse_less_color'      => 'fnParseLessColor',
        'phrase_dynamic'        => 'fnPhraseDynamic',
        'prefix'                => 'fnPrefix',
        'prefix_group'          => 'fnPrefixGroup',
        'prefix_title'          => 'fnPrefixTitle',
        'prefix_description'    => 'fnPrefixDescription',
        'prefix_usage_help'     => 'fnPrefixUsageHelp',
        'profile_banner'        => 'fnProfileBanner',
        'property'              => 'fnProperty',
        'rand'                  => 'fnRand',
        'range'                 => 'fnRange',
        'react'                 => 'fnReact',
        'alert_reaction'        => 'fnAlertReaction',
        'reaction'              => 'fnReaction',
        'reaction_title'        => 'fnReactionTitle',
        'reactions'             => 'fnReactions',
        'reactions_content'     => 'fnReactionsContent',
        'reactions_summary'     => 'fnReactionsSummary',
        'redirect_input'        => 'fnRedirectInput',
        'repeat'                => 'fnRepeat',
        'repeat_raw'            => 'fnRepeatRaw',
        'short_to_emoji'        => 'fnShortToEmoji',
        'show_ignored'          => 'fnShowIgnored',
        'smilie'                => 'fnSmilie',
        'snippet'               => 'fnSnippet',
        'strlen'                => 'fnStrlen',
        'structured_text'       => 'fnStructuredText',
        'templater'             => 'fnTemplater',
        'time'                  => 'fnTime',
        'transparent_img'       => 'fnTransparentImg',
        'trim'                  => 'fnTrim',
        'unique_id'             => 'fnUniqueId',
        'user_activity'         => 'fnUserActivity',
        'user_banners'          => 'fnUserBanners',
        'user_blurb'            => 'fnUserBlurb',
        'user_title'            => 'fnUserTitle',
        'username_link'         => 'fnUsernameLink',
        'username_link_email'   => 'fnUsernameLinkEmail',
        'widget_data'           => 'fnWidgetData'
    ];

    protected $defaultTests = [
        'empty' => 'testEmpty'
    ];

    protected $overlayClickOptions = [
        'data-cache',
        'data-overlay-config',
        'data-force-flash-message',
        'data-follow-redirects'
    ];
Hi @Brogan
Is there a place that explains what each of these functions do?
I'm looking for a function that adds commas to numbers (i.e 1,000 instead of 1000).
(I have a way with JS)

EDIT: number() does just that! :D
 
Last edited:
Top Bottom