Functions
The following functions (opens new window) are available to Twig templates in Craft:
Function | Description |
---|---|
actionInput | Outputs a hidden action input. |
actionUrl | Generates a controller action URL. |
alias | Parses a string as an alias. |
attr | Generates HTML attributes. |
attribute (opens new window) | Accesses a dynamic attribute of a variable. |
beginBody | Outputs scripts and styles that were registered for the “begin body” position. |
block (opens new window) | Prints a block’s output. |
canCreateDrafts canDelete canDeleteForSite canDuplicate canSave canView | Check permissions for a given element. |
ceil | Rounds a number up. |
className | Returns the fully qualified class name of a given object. |
clone | Clones an object. |
collect | Returns a new collection. |
combine | Combines two arrays into one. |
configure | Sets attributes on the passed object. |
constant (opens new window) | Returns the constant value for a given string. |
cpUrl | Generates a control panel URL. |
create | Creates a new object. |
csrfInput | Returns a hidden CSRF token input. |
cycle (opens new window) | Cycles on an array of values. |
dataUrl | Outputs an asset or file as a base64-encoded data URL. |
date | Creates a date. |
dump | Dumps information about a variable. |
endBody | Outputs scripts and styles that were registered for the “end body” position. |
entryType | Gets an entry type definition by its handle. |
expression | Creates a database expression object. |
failMessageInput | Outputs a hidden failMessage input. |
fieldValueSql | Generates an SQL expression for accessing specific fields in elements’ JSON content column. |
floor | Rounds a number down. |
getenv | Returns the value of an environment variable. |
gql | Executes a GraphQL query against the full schema. |
head | Outputs scripts and styles that were registered for the “head” position. |
hiddenInput | Outputs a hidden input. |
include (opens new window) | Returns the rendered content of a template. |
input | Outputs an HTML input. |
max (opens new window) | Returns the biggest value in an array. |
min (opens new window) | Returns the lowest value in an array. |
ol | Outputs an array of items as an ordered list. |
parent (opens new window) | Returns the parent block’s output. |
parseBooleanEnv | Parses a string as an environment variable or alias having a boolean value. |
parseEnv | Parses a string as an environment variable or alias. |
plugin | Returns a plugin instance by its handle. |
random (opens new window) | Returns a random value. |
range (opens new window) | Returns a list containing an arithmetic progression of integers. |
raw | Wraps the given string in a Twig\Markup object to prevent it from getting HTML-encoded when output. |
redirectInput | Outputs a hidden redirect input. |
renderObjectTemplate | Renders an object template. |
seq | Outputs the next or current number in a sequence. |
shuffle | Randomizes the order of the items in an array. |
siteUrl | Generates a front-end URL. |
source | Returns the content of a template without rendering it. |
successMessageInput | Outputs a hidden successMessage input. |
svg | Outputs an SVG document. |
tag | Outputs an HTML tag. |
template_from_string (opens new window) | Loads a template from a string. |
ul | Outputs an array of items as an unordered list. |
url | Generates a URL. |
# actionInput
A shortcut for outputting a hidden input used to route a POST request to a particular controller action. This is effectively the same as writing <input type="hidden" name="action" value="controller/action/route">
directly into a template.
{{ actionInput('users/save-user') }}
You can optionally set additional attributes on the tag by passing an options
argument.
{{ actionInput('users/save-user', {
id: 'action-input'
}) }}
# actionUrl
Returns a controller action URL, automatically accounting for relative vs. absolute format and the active actionTrigger setting.
# Arguments
The actionUrl()
function has the following arguments:
path
– The path that the resulting URL should point to on your site. It will be appended to your base site URL.params
– Any query string parameters that should be appended to the URL. This can be either a string (e.g.'foo=1&bar=2'
) or a hash (e.g.{ foo: '1', bar: '2' }
).scheme
– Which scheme the URL should use ('http'
or'https'
). The default value depends on whether the current request is served over SSL or not. If not, then the scheme in your Site URL will be used; if so, thenhttps
will be used.
# alias
Passes a string through Craft::getAlias() (opens new window), which will check if the string begins with an alias (opens new window). (See Configuration for more info.)
<img src="{{ alias('@assetBaseUrl/images/logo.png') }}">
# attr
Generates a list of HTML attributes based on the given hash, using yii\helpers\BaseHtml::renderTagAttributes() (opens new window).
{% set myAttributes = {
class: ['one', 'two'],
disabled: true,
readonly: false,
data: {
baz: 'Escape this "',
qux: {
some: ['data', '"quoted"']
}
},
style: {
'background-color': 'red',
'font-size': '20px'
},
} %}
<div {{ attr(myAttributes) }}></div>
Attribute values are HTML-encoded automatically:
<div {{ attr({ title: 'Greetings & Salutations' }) }}></div>
{# Output: <div title="Greetings & Salutations"> #}
# beginBody
Outputs any scripts and styles that were registered for the “begin body” position. It should be placed right after your <body>
tag.
<body>
{{ beginBody() }}
<h1>{{ page.name }}</h1>
{{ page.body }}
</body>
# block
Prints a block’s output.
This works identically to Twig’s core block
(opens new window) function.
# canCreateDrafts
Checks whether the current user (or a specific user, when provided) can create drafts from the passed element.
{% if canCreateDrafts(entry) %}
<a href="{{ entry.getCpEditUrl() }}">Edit</a>
{% endif %}
# canDelete
Checks whether the current user (or a specific user, when provided) can delete the passed element.
{% if canDelete(entry) %}
<a href="{{ entry.getCpEditUrl() }}">Edit</a>
{% endif %}
# canDeleteForSite
Checks whether the current user (or a specific user, when provided) can delete the passed element from the site it was loaded in.
{% if canDeleteForSite(entry) %}
<a href="{{ entry.getCpEditUrl() }}">Edit</a>
{% endif %}
# canDuplicate
Checks whether the current user (or a specific user, when provided) can duplicate the passed element.
{% if canDuplicate(entry) %}
<a href="{{ entry.getCpEditUrl() }}">Edit</a>
{% endif %}
# canSave
Checks whether the current user (or a specific user, when provided) can save the passed element.
{% if canSave(entry) %}
<a href="{{ entry.getCpEditUrl() }}">Edit</a>
{% endif %}
# canView
Checks whether the current user (or a specific user, when provided) can view the passed element within the control panel.
{% if canView(entry) %}
<a href="{{ entry.getCpEditUrl() }}">Edit</a>
{% endif %}
# ceil
Rounds a number up.
{{ ceil(42.1) }}
{# Output: 43 #}
# className
Returns the fully qualified class name of a given object.
{% set class = className(entry) %}
{# Result: 'craft\\elements\\Entry' #}
# clone
Clones a given object.
{% set query = craft.entries().section('news') %}
{% set articles = clone(query).type('articles') %}
# collect
Returns a new collection.
{% set collection = collect(['a', 'b', 'c']) %}
# combine
Combines two arrays into one, using the first array to define the keys, and the second array to define the values.
{% set arr1 = ['a', 'b', 'c'] %}
{% set arr2 = ['foo', 'bar', 'baz'] %}
{% set arr3 = combine(arr1, arr2) %}
{# arr3 will now be `{a: 'foo', b: 'bar', c: 'baz'}` #}
# configure
Passes through the behavior of the Craft::configure()
method inherited from Yii::configure()
(opens new window). It’s similar to create
in that it applies attributes to an object, but instead of creating new instances it accepts an existing object and modifies it.
{# Modify an `EntryQuery` object set up by a relational field: #}
{% set myRelatedEntries = configure(entry.myEntriesField, {
section: 'blog'
}).all() %}
It can also be used instead of the merge
(opens new window) filter:
{% set myObject = { one: 'Original' } %}
{# With `merge`: #}
{% set myObject = myObject | merge({ one: 'Overridden', two: 'New' }) %}
{# With `configure`: #}
{% do configure(myObject, { one: 'Overridden', two: 'New' }) %}
It could technically even be used to set a model or element’s attributes, even though that’s not a great idea since templates generally present content rather than modify it:
{% do configure(entry, { title: 'New Title' }) %}
{% do craft.app.elements.saveElement(entry) %}
# constant
Returns the constant value for a given string.
This works identically to Twig’s core constant
(opens new window) function.
# cpUrl
Returns a control panel URL, automatically accounting for relative vs. absolute format and the active cpTrigger setting.
<a href="{{ cpUrl('settings') }}">Visit control panel settings</a>
# Arguments
The cpUrl()
function has the following arguments:
path
– The path that the resulting URL should point to on your site. It will be appended to your base site URL.params
– Any query string parameters that should be appended to the URL. This can be either a string (e.g.'foo=1&bar=2'
) or a hash (e.g.{foo:'1', bar:'2'}
).scheme
– Which scheme the URL should use ('http'
or'https'
). The default value depends on whether the current request is served over SSL or not. If not, then the scheme in your Site URL will be used; if so, thenhttps
will be used.
# create
Creates a new object instance based on a given class name or object configuration. See Yii::createObject() (opens new window) for a full explanation of supported arguments.
{# Pass in a class name #}
{% set cookie = create('yii\\web\\Cookie') %}
{# Or a full object configuration hash #}
{% set cookie = create({
class: 'yii\\web\\cookie',
name: 'foo',
value: 'bar'
}) %}
# csrfInput
Renders a CSRF token input
element for use in an HTML form. All sites that have CSRF protection enabled must include this in each form that makes a POST request.
You can set additional attributes on the rendered tag by passing an options
argument:
{{ csrfInput({
id: 'my-csrf-input',
}) }}
A special async
key in the passed object allows you to override the global asyncCsrfInputs setting
5.1.0+:
{{ csrfInput({
async: true,
}) }}
The output of csrfInput()
should not be cached—statically, or using template caches.
# dataUrl
Outputs an asset or file as a base64-encoded data URL (opens new window). You can pass it an craft\elements\Asset (opens new window) object or a file path (optionally using an alias).
{# Asset object `myLogoAsset` #}
<img src="{{ dataUrl(myLogoAsset) }}" />
{# File path, optionally using an alias #}
<img src="{{ dataUrl('@webroot/images/my-logo-asset.svg') }}" />
{# Output: <img src="data:image/svg+xml;base64,PHN2ZyBoZWlnaHQ9IjEwMCIgdmd(...)" /> #}
The dataUrl()
function has the following arguments:
file
- The asset or path to a file to be encoded.mimeType
- Optional MIME type. If omitted, the file’s MIME type will be determined automatically.
# date
Converts an argument to a date to allow comparison, like Twig’s date()
function (opens new window).
The argument can be one of PHP’s supported date and time formats (opens new window), or additionally a date
/time
array.
{% if date(asset.dateModified) < date('-2days') %}
{# asset is not new #}
{% endif %}
A null
or empty argument defaults to the current date:
{% if date() > date('2021/06/01') %}
{# today is past June 1, 2021 #}
{% endif %}
Craft additionally supports passing a date
/time
array:
{% set myDate = {
date: '2021-01-15',
timezone: 'America/Los_Angeles',
time: '10:57',
} %}
{% if now > date(myDate) %}
{# today is past January 15, 2021 #}
{% endif %}
# dump
Overrides Twig’s default dump()
(opens new window) function with one that is available in all contexts (not just when the Twig environment is in “debug” mode), and produces consistent output with the {% dd %}
tag.
{% set news = craft.entries()
.section('news')
.all() %}
{{ dump(news|column('title')) }}
# endBody
Outputs any scripts and styles that were registered for the “end body” position. It should be placed right before your </body>
tag.
<html>
<head>
{# ... #}
</head>
<body>
<h1>{{ page.name }}</h1>
{{ page.body }}
{{ endBody() }}
</body>
</html>
# entryType
Get a reference to an entry type, by its handle:
{% set type = entryType('post') %}
{{ type.name }}
This is equivalent to using the entries service, directly:
{% set type = craft.app.entries.getEntryTypeByHandle('post') %}
{{ type.name }}
When creating entries in a front-end form, you can use the entryType()
function to find the correct ID to submit (IDs can be unstable between environments, due to the way project config works):
<form method="post">
{{ csrfInput() }}
{{ actionInput('entries/save-entry') }}
{{ hiddenInput('typeId', entryType('post').id) }}
{# ... #}
</form>
# expression
Creates and returns a new yii\db\Expression (opens new window) object, for use in database queries.
{% set entries = craft.entries()
.andWhere(expression('[[authorId]] = :authorId', {authorId: currentUser.id}))
.all() %}
# failMessageInput
Shortcut for typing <input type="hidden" name="failMessage" value="{{ 'Custom fail message'|hash }}">
.
{{ failMessageInput('Custom fail message') }}
You can optionally set additional attributes on the tag by passing an options
argument.
{{ failMessageInput('Custom fail message', {
id: 'fail-message-input'
}) }}
# fieldValueSql
Generates a platform-specific SQL expression to extract a value from elements’ JSON content column.
{% set longestFilm = craft.entries()
.section('films')
.max(fieldValueSql(entryType('film'), 'runtimeMinutes')) %}
Craft automatically handles this for orderBy()
and select()
expressions, as well as when using field methods, directly:
{% set shortFilms = craft.entries()
.section('films')
.runtimeMinutes('<= 20')
.orderBy('runtimeMinutes DESC')
.all() %}
# Arguments
provider
— An object that implementscraft\base\FieldLayoutProviderInterface
, like an entry type or asset volume—basically anything that defines a field layout.{# Load a field layout provider: #} {# set volume = craft.app.volumes.getVolumeByHandle('photos') %} {% set longExposures = craft.assets() .volume('photos') .andWhere('between', (fieldValueSql(volume, 'shutterSpeed')), 0.17, 1) .all() %}
The provider can also be passed from an existing resource, like
entry.type
.fieldHandle
— The field’s handle in the given field layout. This may be different than the field’s global definition—especially if the field is present multiple times in the layout.
# floor
Rounds a number down.
{{ floor(42.9) }}
{# Output: 42 #}
# getenv
Returns the value of an environment variable, using craft\helpers\App::env() (opens new window).
{{ getenv('MAPS_API_KEY') }}
Take care to not leak sensitive environment variables into your HTML!
# gql
Executes a GraphQL query against the full schema.
{% set result = gql('{
entries (section: "news", limit: 2, orderBy: "dateCreated DESC") {
postDate @formatDateTime (format: "Y-m-d")
title
url
... on news_article_Entry {
shortDescription
featuredImage {
url @transform (width: 300)
altText
}
}
}
}') %}
{% for entry in result.data %}
<h3><a href="{{ entry.url }}">{{ entry.title }}</a></h3>
<p class="timestamp">{{ entry.postDate }}</p>
{% set image = entry.featuredImage[0] %}
<img class="thumb" src="{{ image.url }}" alt="{{ image.altText }}">
{{ entry.shortDescription|markdown }}
<p><a href="{{ entry.url }}">Continue reading…</a></p>
{% endfor %}
# head
Outputs any scripts and styles that were registered for the “head” position. It should be placed right before your </head>
tag.
<head>
<title>{{ siteName }}</title>
{{ head() }}
</head>
# hiddenInput
Generates an HTML input tag.
{{ hiddenInput('entryId', entry.id) }}
{# Output: <input type="hidden" name="entryId" value="100"> #}
You can optionally set additional attributes on the tag by passing an options
argument.
{{ hiddenInput('entryId', entry.id, {
id: 'entry-id-input'
}) }}
# include
Returns the rendered content of a template.
This works identically to Twig’s core include
(opens new window) function.
# input
Generates an HTML input tag.
{{ input('email', 'email-input', '') }}
{# Output: <input type="email" name="email-input" value=""> #}
You can optionally set additional attributes on the tag by passing an options
argument.
{{ input('email', 'email-input', '', {
id: 'custom-input'
}) }}
{# Output: <input type="email" id="custom-input" name="email-input" value=""> #}
# max
Returns the biggest value in an array.
This works identically to Twig’s core max
(opens new window) function.
# min
Returns the lowest value in an array.
This works identically to Twig’s core min
(opens new window) function.
# ol
Outputs an array of items as an ordered list.
{% set titles = craft.entries()
.section('news')
.select('title')
.column() %}
{{ ol(titles) }}
{# Output:
<ol>
<li>Shocking Foo</li>
<li>You Won’t Believe This Bar</li>
<li>Ten Baz You Can’t Live Without</li>
</ol>
#}
# Arguments
The ol()
function has the following arguments:
items
– An array of items to be wrapped in<li>
s. These will be HTML-encoded by default.params
– An attributes argument where each key+value will be set as attributes on the<ol>
, with the exception of two special options:encode: false
– Prevents the list items from being HTML-encoded.itemOptions: {...}
– Tag attributes to be applied to each of the<li>
s.
# parseBooleanEnv
Checks if a string references an environment variable ($VARIABLE_NAME
) and returns the referenced boolean value, or null
if a boolean value can’t be determined.
# parseEnv
Checks if a string references an environment variable ($VARIABLE_NAME
) and/or an alias (@aliasName
), and returns the referenced value.
If the string references an environment variable with a value of true
or false
, a boolean value will be returned.
# plugin
Returns a plugin instance by its handle, or null
if no plugin is installed and enabled with that handle.
{{ plugin('commerce').version }}
# raw
Wraps the given string in a Twig\Markup
object to prevent it from getting HTML-encoded when output.
{% set html = raw('<p>Don’t encode me.</p>') %}
{{ html }}
This works similarly to the raw (opens new window) filter, except that Twig will remember not to escape the HTML even if the variable is passed to another template/macro, whereas |raw
filters only have an effect if used directly in an output tag.
# redirectInput
Output an HTML input equivalent to <input type="hidden" name="redirect" value="{{ url|hash }}">
, for use in forms that POST data to Craft or a plugin.
{{ redirectInput(url) }}
The URL is typically parsed as an object template, meaning dynamic redirects are possible, based on the data being manipulated.
You can optionally set additional attributes on the resulting input
tag by passing an options
argument:
{{ redirectInput(url, {
id: 'redirect-input'
}) }}
Don’t include user-provided data in redirection URLs, directly (via interpolation in a template) or indirectly (rendered in an object template).
# renderObjectTemplate
Evaluates a string as an object template, using the provided element, model, or hash.
{{ renderObjectTemplate('👋 Hi, {fullName}!', currentUser) }}
{# Output: 👋 Hi, Oli! #}
{{ renderObjectTemplate('✨ {foo}', { foo: "I’m a made-up hash!" }) }}
{# Output: ✨ I’m a made-up hash! #}
Do not pass user-supplied templates to the renderObjectTemplate()
function!
# seq
Outputs the next or current number in a sequence, defined by name
:
<p>This entry has been read {{ seq('hits:' ~ entry.id) }} times.</p>
Each time the function is called, the given sequence will be automatically incremented.
You can optionally have the number be zero-padded to a certain length.
{{ now|date('Y') ~ '-' ~ seq('orderNumber:' ~ now|date('Y'), 5) }}
{# Output: 2018-00001 #}
To view the current number in the sequence without incrementing it, set the next
argument to false
.
<h5><a href="{{ entry.url }}">{{ entry.title }}</a></h5>
<p>{{ seq('hits:' ~ entry.id, next=false) }} views</p>
# shuffle
Randomizes the order of the elements within an array.
{% set promos = craft.entries().section('promos').all() %}
{% set shuffledPromos = shuffle(promos) %}
{% for promo in shuffledPromos %}
<div class="promo {{ promo.slug }}">
<h3>{{ promo.title }}</h3>
<p>{{ promo.description }}</p>
<a class="cta" href="{{ promo.ctaUrl }}">{{ promo.ctaLabel }}</a>
</div>
{% endfor %}
# siteUrl
Similar to url(), except only for creating URLs to pages on your site.
<a href="{{ siteUrl('company/contact') }}">Contact Us</a>
# Arguments
The siteUrl()
function has the following arguments:
path
– The path that the resulting URL should point to on your site. It will be appended to your base site URL.params
– Any query string parameters that should be appended to the URL. This can be either a string (e.g.'foo=1&bar=2'
) or a hash (e.g.{foo:'1', bar:'2'}
).scheme
– Which scheme the URL should use ('http'
or'https'
). The default value depends on whether the current request is served over SSL or not. If not, then the scheme in your Site URL will be used; if so, thenhttps
will be used.siteId
– The ID of the site that the URL should point to. By default the current site will be used.
# source
Returns the content of a template without rendering it.
This works identically to Twig’s core source
(opens new window) function.
# successMessageInput
Shortcut for typing <input type="hidden" name="successMessage" value="{{ 'Custom success message'|hash }}">
.
{{ successMessageInput('Custom success message') }}
You can optionally set additional attributes on the tag by passing an options
argument.
{{ successMessageInput('Custom success message', {
id: 'success-message-input'
}) }}
# svg
Outputs an SVG document.
You can pass the following things into it:
An SVG file path.
{{ svg('@webroot/icons/lemon.svg') }}
A craft\elements\Asset (opens new window) object, such as one pulled in from an Assets field.
{% set image = entry.myAssetsField.one() %} {% if image and image.extension == 'svg' %} {{ svg(image) }} {% endif %}
Raw SVG markup.
{% set image = include('_includes/icons/lemon.svg') %} {{ svg(image) }}
By default, if you pass an asset or raw markup into the function, the SVG will be sanitized of potentially malicious scripts using svg-sanitizer (opens new window), and any IDs or class names within the document will be namespaced so they don’t conflict with other IDs or class names in the DOM. You can disable those behaviors using the sanitize
and namespace
arguments:
{{ svg(image, sanitize=false, namespace=false) }}
Images passed via path/alias will not automatically be sanitized and namespaced.
You can also specify a custom class name that should be added to the root <svg>
node using the attr filter:
{{ svg('@webroot/icons/lemon.svg')|attr({ class: 'lemon-icon' }) }}
Consider caching the output, especially if you’re loading SVG files from remote volumes or URLs, so Craft doesn’t download the file each time your template is rendered.
# tag
Renders a complete HTML tag.
{{ tag('div', {
class: 'foo'
}) }}
{# Output: <div class="foo"></div> #}
If text
is included in the attributes argument, its value will be HTML-encoded and set as the text contents of the tag.
{{ tag('div', {
text: 'Hello'
}) }}
{# Output: <div>Hello</div> #}
If html
is included in the attributes argument (and text
isn’t), its value will be set as the inner HTML of the tag (without getting HTML-encoded).
Be sure you trust any input you provide via html
since it could be an XSS (cross-site scripting) attack vector. It’s safer to use text
wherever possible.
{{ tag('div', {
html: 'Hello<br>world'
}) }}
{# Output: <div>Hello<br>world</div> #}
All other keys passed to the second argument will be set as attributes on the tag, using yii\helpers\BaseHtml::renderTagAttributes() (opens new window).
If an attribute is set to true
, it will be added without a value.
{{ tag('input', {
id: 'foo',
name: 'bar',
required: true
}) }}
{# Output: <input id="foo" name="bar" required> #}
Any attribute set to null
or false
will be omitted.
Attribute values are HTML-encoded automatically:
{{ tag('input', {
name: 'bar',
value: 'Foobar & Baz',
}) }}
{# Output: <input name="bar" value="Foobar & Baz"> #}
# ul
Outputs an array of items as an unordered list.
{% set titles = craft.entries()
.section('news')
.select('title')
.column() %}
{{ ul(titles) }}
{# Output:
<ul>
<li>Shocking Foo</li>
<li>You Won’t Believe This Bar</li>
<li>Ten Baz You Can’t Live Without</li>
</ul>
#}
# Arguments
The ul()
function has the following arguments:
items
– An array of items to be wrapped in<li>
s. These will be HTML-encoded by default.params
– An attributes argument where each key+value will be set as attributes on the<ul>
, with the exception of two special options:encode: false
– Prevents the list items from being HTML-encoded.itemOptions: {...}
– Tag attributes to be applied to each of the<li>
s.
# url
Returns a URL.
<a href="{{ url('company/contact') }}">Contact Us</a>
# Arguments
The url()
function has the following arguments:
path
– The path that the resulting URL should point to on your site. It will be appended to your base site URL.params
– Any query string parameters that should be appended to the URL. This can be either a string (e.g.'foo=1&bar=2'
) or a hash (e.g.{foo:'1', bar:'2'}
).scheme
– Which scheme the URL should use ('http'
or'https'
). The default value depends on whether the current request is served over SSL or not. If not, then the scheme in your Site URL will be used; if so, thenhttps
will be used.mustShowScriptName
– If this is set totrue
, then the URL returned will include “index.php”, disregarding the omitScriptNameInUrls config setting. (This can be useful if the URL will be used by POST requests over Ajax, where the URL will not be shown in the browser’s address bar, and you want to avoid a possible collision with your site’s .htaccess file redirect.)
Using the url()
function has advantages over hard-coding URLs in your templates:
- Generated URLs will encourage consistency by respecting settings like addTrailingSlashesToUrls.
- Your site will be more portable, making it easier to do something like move to a new domain or subdomain.
- If the page has a
token
URL parameter, that token will automatically get appended to generated URLs to maintain preview context navigating around the site.
You can use the url()
function for appending query string parameters and/or enforcing a scheme on an absolute URL:
{{ url('http://my-project.tld', 'foo=1', 'https') }}
{# Output: "https://my-project.tld?foo=1" #}