Edit on GitHub
Jump to docs navigation

Templating / Linking in Templates

Note: You are currently reading the documentation for Bolt 3.7. Looking for the documentation for Bolt 5.2 instead?

There are a number of Twig functions in Bolt that you can use to link to other pages, or to include assets like CSS and Javascript resources in your HTML. They are:

  • To link to assets, like CSS, Javascript or other files, use {{ asset() }}
  • To link to the 'current page', use {{ canonical() }} or {{ record.link() }}
  • To generate a relative or absolute path, use {{ path() }}
  • To generate a scheme-relative or absolute url, use {{ url() }}
  • To generate sensible links from user-provided input, use {{ relative_path() }}
  • To generate absolute links from relative links, use {{ absolute_url() }}

The following sections of this page will detail the different functions, and how to use them effectively.

Use the {{ asset() }} Twig function to create public link to the so-called assets in your theme, like JavaScript, CSS or other files.

The asset function definition is:

{{ asset(path, packageName) }}

The asset function takes two parameters:

Parameter Description
path The path, relative to the base of location of a package, of a file, where these paths can be found.
packageName This parameter needs to provide a package name containing.

Packages are analogous to locations of "groups of file assets". Bolt defines a few of these packages, that can be used to create links to files in specific areas of Bolt.

Defined package names are:

Packages Description
theme The path to the currently selected theme folder, as defined in your config.yml. Use this in your theme to transparently create links to your .js and .css files. Doing this ensures the links will still work, if your theme gets renamed, or if the site gets installed in a sub-folder.
files The path to the files/ folder where images and other files are uploaded by the Editors to be used in the content of the website.
bolt Used to link to Bolt's core asset files. Use of this package name is discouraged in your own theme, because there is no guarantee that these files that are shipped with Bolt will remain unchanged after an update of Bolt.
extensions The path to the publicly accessible assets of extensions. For example, if an extension requires a .js or .css file, it will use this, to ensure it gets included in the theme. As with bolt, it's usually not necessary to use these yourself if you're developing a theme.

Examples:

{# Include theme.css from the 'css' folder in your theme. #}
<link rel="stylesheet" href="{{ asset('css/theme.css', 'theme') }}">

{# Include jquery.min.js from the 'js' folder in your theme. #}
<script src="{{ asset('js/jquery.min.js', 'theme') }}"></script>

{# Display the kitten.jpg image, that was uploaded to the `files/` folder. #}
<img src="{{ asset('kitten.jpg', 'files') }}" />

This would produce, on an default install, the following output:

<link rel="stylesheet" href="/theme/base-2016/css/theme.css">

<script src="/theme/base-2016/js/jquery.min.js"></script>

<img src="/files/kitten.jpg">

Using asset and a JSON Manifest

Many build tools use a cache busting technique of outputting a hashed file (eg: styles.abc12b89asdd.css) along with a manifest referencing that file.

This is an example manifest file:

{
  "build/styles.css": "/dist/styles.abc12b89asdd.css",
  "build/app.js": "/dist/app.2fec6da74d584bcd9fd2.js"
}

To use this technique - like with Symfony's Webpack Encore - you'll need to add a configuration block with the appropriate keys to either your config.yml or your (preferred) config_local.yml like the following:

# using the asset package
assets:
   theme:
        json_manifest_path: "/dist/manifest.json"
        # the json_manifest is relative to your current theme.

The theme key is a mount point you want to access your assets from. In this instance we are using the "theme" mount point/package name defined above in "package names".

In your template you can now use your hashed assets by referencing the non-hashed file as follows:

<link rel="stylesheet" href="{{ asset('dist/css/styles.css', 'theme') }}">

This will produce on a default install:

<link rel="stylesheet" href="/theme/base-2018/dist/css/styles.bbad62558ef19da7e0ca.css"> 

For a more in-depth description of the asset function, see the Symfony documentation on assets.

Note: This function replaces the deprecated {{ paths }} template variable. As such, it's encouraged to use this function instead.

Linking to the current page

It is a very common task to make links to the "current page". For instance to use in a 'permalink' button, or to link to the current page from social media, email or some other external source. The easiest way to do this is by using the canonical Twig function:

<a href="{{ canonical() }}">Link to this</a>

{# -> <a href="http://example.org/page/lorum-ipsum">Link to this</a> #}

The canonical link is a fully specified link, which includes the scheme and domain name. It is defined dynamically by Bolt, and can be influenced using the canonical: setting in your config.yml.

Alternatively, if you want to create links to a specific page in a listing, or a record you've fetched using {% setcontent %}, you can use the .link() function to get the link. For example:

<a href="{{ record.link() }}">{{ record.title }}</a>

{# -> <a href="http://example.org/page/lorum-ipsum">Lorum Ipsum</a> #}

You can use the path and url Twig functions to create valid URI/URL strings to paths or routes in your site's configuration. The main difference between the two functions is that one will output a relative link, and the other one a fully specified URL.

The path and url function definitions are:

    {{ path(name, parameters = [], relative = false) }}
    {{ url(name, parameters = [], schemeRelative = false) }}

The path and url functions take three parameters:

Parameter Description
name Name of a registered path route
parameters A named array of parameters that can be either route function parameters, or query parameters to be appended to the generated URI.
relative Whether or not the URI will be relative to the current page (optional, defaults to false)
schemeRelative Whether or not the URL will include the current scheme (optional, defaults to false)

For example:

<a href="{{ path('homepage') }}">Home path</a> -
<a href="{{ url('homepage') }}">Home URL</a>

{# <a href="/">Home path</a> - <a href="http://example.org/">Home URL</a> #}

This will create a simple link to the homepage of the site. Bolt has a Route defined that's called 'homepage', and as such, Bolt can generate a link to that specific route. Note the difference in the output for the path and url functions.

In practice, you will most often use path to create links, and only use url in those cases where you specifically want to create a link with the scheme and domain name. For example, use url when you need the link to insert in an email, or to link to the page from an external source, like social media. In other cases you should just stick with path for simplicity.

You can also pass in extra parameters with these functions, that are used to generate the link. For example, to produce a link relative to the base of your site:

<a href="{{ path(
    'contentlink',
    {
        'contenttypeslug': link_content_type,
        'slug': link_slug,
        'section': query_section
    })
}}">
    Link to a absolute path of the ContentType "{{ link_content_type }}", with
    the slug of "{{ link_slug }}", and the query parameter `section` with the
    value of {{ query_section }}
</a>

This would produce, on an default install, the following output:

<a href="/pages/about?section=koala">
    Link to a absolute path of the ContentType "pages", with the slug of
    "about", and the query parameter `section` with the value of koala
</a>

Alternatively, if you wish to have the link relative to the current page or scheme, you can set the relative parameter to true. Unless you have a good reason, you should probably omit this parameter so it defaults to false. Doing so will give you absolute links, which are less error prone.

The different output for 'relative' illustrated:

{% set parameters = {'contenttypeslug': 'pages', 'slug': 'dicis-vicimus'} %}

{{ path('contentlink', parameters) }} => /pages/dicis-vicimus
{{ path('contentlink', parameters, true) }} => ../pages/dicis-vicimus
{{ url('contentlink', parameters) }} => http://example.org/pages/dicis-vicimus
{{ url('contentlink', parameters, true) }} => //example.org/pages/dicis-vicimus

Under the hood, these functions create links to routes defined in the Routing inside Bolt. This is the case for both Bolt core functionality, but extensions can also add paths that can be used with this function.

The most commonly used routes are:

Route Description
homepage Generate a link to the homepage of the site.
contentlisting Used for links to the listing view of a contenttype. For example: {{ path('contentlisting', {'contenttypeslug': 'pages'}) }} will generate a link like /pages.
contentlink Used for links to ContentTypes by ContentType name and slug
search Generate a link to the search results page of the site. Often used as the 'target' of a form that allows the user to perform a search, e.g.: <form method="get" action="{{ path('search') }}">

You can inspect the routing.yml file for more of the 'baked in' routes for the front end, as well as the "Routing" panel in the debug toolbar.

For more in-depth information about this function, see Linking to pages in the Symfony documentation.

As you've seen in the examples above, these mostly deal with paths and urls programmatically. Often you will find that a client or editor wants to have a field in content where they can "just put in a link". Of course you can create a regular field with type: text to handle this, and insert these in the templates, but you'll get quirky results if the editor isn't very strict in how they use the field. So, using <a href='{{ record.contentlink }}'>Link</a> isn't the best way to handle this.

You can do this in a better way, like is done in the default Blocks ContentType:

blocks:
    name: Blocks
    singular_name: Block
    fields:
        …
        contentlink:
            type: text
            label: Link
            placeholder: 'contenttype/slug or http://example.org/'
            postfix: "Use this to add a link for this Block. This could either be an 'internal' link like <tt>page/about</tt>, if you use a contenttype/slug combination. Otherwise use a proper URL, like `http://example.org`."

Then, in your templates you can insert the correct link, depending on what the editor provided:

{% if record.contentlink %}
    <a href="{{ relative_path(record.contentlink|e) }}">Read more</a>
{% endif %}

This way, the website will show a correct relative or absolute link, if the editor provided something like page/about or https://bolt.cm.

Often a link like /foo/bar is preferred over an absolute one which includes the scheme and the domain name. This is because it can prevent cross-domain quirks and other inconsistencies. Sometimes, however, you need absolute links. For example when generating a feed, an email or content that's consumed by a remote API.

For these cases, the absolute_url function is very useful. It takes a relative url, and transforms it into an absolute one. You can use it on links to content and file assets alike. For example:

{# Example use with a link to content #}
<a href="{{ absolute_url( record.link() ) }}" />

{# Example use with `asset` #}
<img src="{{ absolute_url( asset('kitten.jpg', 'files') ) }}" />

For more in-depth information about this function, see absolute_url in the Symfony documentation.



Edit this page on GitHub
Couldn't find what you were looking for? We are happy to help you in the forum, on Slack or on Github.