Skip to content

Instantly share code, notes, and snippets.

@taotiwordpress
Last active February 14, 2024 16:31
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save taotiwordpress/266fd95513f97f3c17748288579c56b9 to your computer and use it in GitHub Desktop.
Save taotiwordpress/266fd95513f97f3c17748288579c56b9 to your computer and use it in GitHub Desktop.
Twig Cheatsheet #twig #timber #wordpress #cheatsheet #images #wp-query #wp_query #the_loop

Timber Bag of Tools Cheat Sheet

Useful Variables

Remember, there are 'TWIG' tools and then there are 'Timber' tools.

The second is WordPress specific.

Twig-based Variables

TWIG supports a rather verbose set of variables, but they are all either arrays or strings when it comes down to it.

See https://twig.symfony.com/doc/1.x/tags/set.html for more information.

Note: Variables are all scoped. If you need a variable outside of a loop (or subtemplate), declare it outside of the loop (or subtemplate).

{# Create a Basic Variable #}
{% set foo = 'bar' %}

{# Display the Basic Variable #}
{{ foo }}

There's some flexibility with variables, such as assigning arrays to them or even declaring more than one in a single block:

{% set foo = [1, 2] %}
{% set foo = {'foo': 'bar'} %}
{% set foo = 'foo' ~ 'bar' %}

One of the most useful (and abused by Timber) tools of set is to capture chunks of text as a string:

{% set foo %}
    <div id="pagination">
        ...
    </div>
{% endset %}

Timber-based Variables

Gutenberg Blocks and ACF Fields

When built correctly, the <template>.php file will load:

  • $block
    • The block settings and attributes from $block.
    • See https://developer.wordpress.org/block-editor/reference-guides/block-api/block-attributes/ for available attributes to load.
    • Available Block Settings
      • Useful
        • block.id - Unique 'id' for the block (used in the id="" wrapper).
        • block.align - The set 'alignment' for the block, can be configurable via ACF.
        • block.supports - Array of configurable field-settings.
        • block.className - The user-set 'Additional CSS classes'.
      • Example Content
        • block.data - Array of optional content. Requires usage of example data-set. Otherwise is just the Administrative instructions for the block.
      • Administrative
        • block.name
        • block.title
        • block.category
        • block.icon
        • block.keywords
        • block.post_types - Available post types.
        • block.enqueue_script / block.enqueue_assets - Defaults to 'false', if not set.
  • $fields (Look for $content)
    • The ACF fields from get_fields().
    • (We at Taoti tend to also use $content instead.)
  • $is_preview
    • The Editor 'example' view of the block, for users to select from.
{{ block.id }}
{{ block.title }}

Filters

Filters are used to 'rewrite' the output of "content" on page load.

For example, the |date() filter allows you to display a date, whereas the |towebp filter changes an Image() from its current format to a .webp file.

Its important to note that there are both TWIG-specific and Timber-created filters, so you'll want to check both the Timber Documentation and the TWIG Documentation for details.

Its also important to remember that TWIG loads content ONE WAY. If it reaches the .twig file, it will not be altered in the database.

  • https://twig.symfony.com/doc/1.x/filters/index.html

  • https://timber.github.io/docs/guides/filters/

  • WordPress 'Auto-paragraph' filter

    • <p class="content">{{ post.my_custom_text|wpautop }}</p>
  • Execute Shortcode

    • <p class="content">{{ post.my_custom_text|shortcodes }}</p>
    • Note: See the upcoming 'Shortcodes' section for more usage of shortcodes.
  • Code Samples

    • <div class="code-sample">{{ post.code_samples|pretags }}</div>
  • Executing PHP

    • <p class="entry-meta">{{ function('twentytwelve_entry_meta') }}</p>
    • See 'Functions' on the other Cheatsheet for more details.
  • Date Filters

    • Note: There are various methods of writing the date.
    • <span class="date">{{ post.post_date|date('F j, Y') }}</span>
    • <p class="copyright">&copy; {{ now|date('Y') }} by {{ bloginfo('name') }}</p>
    • <p class="entry-meta">Posted: <time>{{post.post_date_gmt|time_ago}}</time></p>
    • If you need something stronger, see https://timber.github.io/docs/v2/guides/date-time/.
  • Image Filters

    • Note: See the separate 'Image Cheatsheet' for more details.
  • Relative

    • Convert an absolute URL into a relative one.
    • {{ 'http://example.org/2015/08/my-blog-post' | relative }}
  • Sanitize

    • Converts spaces in titles to dashes.
    • This is VERY useful for creating id= tags and such!
    • {{post.title|sanitize}}
  • Excerpt

    • Trim text to locked down length.
    • Note: I would recommend be careful using this, as ACFs tend to allow character limits and it can be confusing at times.
    • <p class="intro">{{post.post_content|excerpt(30)}}...</p>
  • List

    • Allows you to skip creating a 'loop' when displaying an array of items.
    • Note the missing Oxford comma though.
    • Template: Contributions made by {{contributors|list(',','&')}}
    • Output: Contributions made by Item 1, Item 2 & Item 3

TWIG Cheat Sheet

Note: There will be a separate 'Image Cheatsheet' that goes into how best to setup, render, and display images in Timber and a 'Layout Cheatsheet' about building the Template files, once the below variables exist.

PHP versus Template

The goal behind TWIG was to completely separate the "data" and "data processing" side of getting content and the "content layout" side of --no-configuration tests nonExistingFile.php

This can be seen with the simplest iteration of 'adding' Timber(TWIG) support to a <template>.php file:

/* Get the initial post credentials. */
/* This loads parts like wp_head(), wp_footer(), various menus, etc. into the Timber object. */
$context     = Timber::get_context();

/* Add all of the details for the CURRENT 'post' as a subvariable named 'post' */
/* This approach could, for example, also be used to grab WP_Query items, if $args are provided */
$context['post']     = new TimberPost();

/* Now, SEND all of the aggregated $context added variables to the template */
/* THIS command can even be expanded with a third number: length of page cache lifetime (shouldn't be used in development or on 'active' pages) */
Timber::render( 'single.twig', $context );

TWIG Commands

Timber was built on top of TWIG, so there are a lot of useful commands available.

Note: If browsing the documentation, the current iteration is using TWIG 1.x, not 2.x or 3.x.

Timber Commands

These are WordPress Specific commands, as opposed TWIG specific commands.

Variables

There are a number of variables and/or 'WordPress Methods' to get content from WordPress.

Timber actually adds a number of these automatically to the theme engine for usage.

Question: Where's the navigation/menus? Answer: TWIG breaks out

Blog Info

blog_info('charset')       => {{ site.charset }}
blog_info('description')   => {{ site.description }}
blog_info('sitename')      => {{ site.name }}
blog_info('url')           => {{ site.url }}

Body Classes

implode(' ', get_body_class())      => <body class="{{ body_class }}">

Default WordPress Post Functions (which are variables)

the_content()         => {{ post.content }}
the_permalink()      => {{ post.link }}
the_title()          => {{ post.title }}
get_the_tags()       => {{ post.tags }}  

Theme Variables

In WordPress parlance, stylesheet_directory = child theme, template directory = parent theme. Both WP and Timber functions safely return the current theme info if there's no parent/child going on.

get_template_directory_uri()   => {{ theme.link }} (Parent Themes)
get_template_directory_uri()   => {{ theme.parent.link }} (Child Themes)
get_stylesheet_directory_uri() => {{ theme.link }}
get_template_directory()       => {{ theme.parent.path }}
get_stylesheet_directory()     => {{ theme.path }}

Header, Footer, and Custom Functions

Note: It is not uncommon (and quite easy) to actually SKIP using wp_head() or wp_footer() and just add something like header.twig into base.twig or hardcoding the common wp_head() content.

wp_footer()                    => {{ wp_footer }}
wp_head()                      => {{ wp_head }}

Custom Functions use the Timber function() ...function.

There are a few 'gotcha' cases, so if you run into issues, see https://timber.github.io/docs/guides/functions/#function.

<!-- No Argument Function Call -->
<div class="posted-on">{{function("twentyeleven_posted_on")}}</div>

<!-- Function Call WITH Arguments -->
{# single.twig #}
<div class="admin-tools">
    {{function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>')}}
</div>

Content (eg: the_content )

When working from Gutenberg blocks with ACFs, you'll actually usually have something like this: {{ content.acf_field }}.

<div class="my-article">
   {{post.content}}
</div>

<!-- This differs from {{post.post_content}} which is the raw text stored in your database -->

Custom Actions

In the TWIG File:

{% do action('my_action') %}
{% do action('my_action_with_args', 'foo', 'bar') %}

From the <template>.php file:

add_action('my_action', 'my_function');

function my_function($context){
    //$context stores the template context in case you need to reference it
    echo $context['post']->post_title; //outputs title of yr post
}
add_action('my_action_with_args', 'my_function_with_args', 10, 2);

function my_function_with_args($foo, $bar){
    echo 'I say '.$foo.' and '.$bar;
}
You can still get the context object when passing args, it's always the last argument...

add_action('my_action_with_args', 'my_function_with_args', 10, 3);

function my_function_with_args($foo, $bar, $context){
    echo 'I say '.$foo.' and '.$bar;
    echo 'For the post with title '.$context['post']->post_title;
}

Hooks

JUST DON'T.

If you have to use hooks, there's a full documentation page at: https://timber.github.io/docs/v2/hooks/filters/

The problem is, you're now doing data-processing within the theme-engine, which is the exact opposite goal behind Timber/TWIG.

Timber Image Cheat Sheet

Background

Timber adds a lot functionality and 'extra' tooling on top of base TWIG to work with images.

Note: Much of this Cheatsheet was adapated 'as-is' from Timber's Image Cookbook.

--> WARNING <-- If NOT on Pantheon or AWS, some of this functionality may not work as expected depending on how the Client's CDN is setup and configured. See https://timber.github.io/docs/v2/guides/cookbook-images/#limitations-when-working-with-a-cdn if issues arise.

Loading Images

If loading a default WordPress image, no extra steps are needed.

<img src="{{ post.thumbnail.src }}" class="my-thumb-class" alt="Image for {{ post.title }}" />

In contrast, if loading images from ACF, the Image() function needs to be triggered to properly prepare the image.

{% set image = Image(post.hero_image) %}

<img src="{{ image.src }}" alt="{{ image.alt }}" />

Converting Images

A really cool feature of Timber is to arbitrarily convert images between different image formats on page load.

Filter Options: |tojpg and |towebp.

<picture>
   <source srcset="{{ post.thumbnail.src|towebp }}" type="image/webp">
   <source srcset="{{ post.thumbnail.src|tojpg }}" type="image/jpeg">
   <img src="{{ post.thumbnail.src|tojpg }}" alt="{{ post.title }}">
</picture>

This is very useful to use and abuse WordPress's built-in support for WebP. It can also be seamlessly combined with the arbitrary image resizing feature too.

<img src="{{ post.thumbnail.src|tojpg|resize(300, 300) }}" />

Image Sizing & Layout

Timber supports three different approachs for image layout:

  • WordPress "Image Sizes"
  • Letterboxing
  • Retina Images

The, arguably, most useful feature however is the ability to arbitrarily resize images!

Arbitrary Image resizing

Okay, so I'm going to list is backwards here, because this part is cool. The height is optional and will only contrain the image to scale proportionally to the space provided. I cannot stress enough how useful this feature can be, when used properly.

<img src="{{ post.thumbnail.src|resize(640) }}" />

Alternatively, you can provide width and height for an exact cropping.

<img src="{{ post.thumbnail.src|resize(300, 200) }}" />

WordPress Image Sizes

These would obviously be the default image styles or custom-loaded sizes.

Default Image Sizes:

  • Thumbnail: 150px width and height | thumbnail
  • Medium: 300px width and height | medium
  • Large: 1024px width and height | large
  • Full: The original image | N/A - Just call the image.

Note: Taoti places custom image styles at inc/image-sizes.php

--> WARNING <-- If the called size has not been generated, an empty string ('') will be returned.

Letterboxing

This is useful when, for example, the image must load on a 400 x 400 'box', but you do not want the image actually cropped. This instead loads a background (hex-code only) that the image sits on.

Note: height and width are required when using the |letterbox filter. The background hex-color is optional (and would be transparent, if not in use).

<img src="{{ post.thumbnail.src|letterbox(400, 400, '#FFFFFF') }}" />

Retina Images

Fairly straightforward, but does not work with arbitrary resizing of images (see |resize() above).

<img src="{{ post.thumbnail.src }}" srcset="{{ post.thumbnail.src|retina(1) }} 1x,
    {{ post.thumbnail.src|retina(2) }} 2x,
    {{ post.thumbnail.src|retina(3) }} 3x,
    {{ post.thumbnail.src|retina(4) }} 4x">

--> Warning <-- This may or may not play well with the |towebp and |tojpg filters. Probably better to ensure the correct image is being loaded, if converting to WebP.

TWIG & Timber & Custom Queries

Okay, so Taoti hasn't really leveraged this functionality yet, but it can still be showcased here.

See "TWIG - Example CPT Archive" for an example implementation of these references.

Where's WP_Query()?

Timber fully supports WP_Query(), but intead requires that you instead Timber::get_posts().

Timber Documentation:

These instructions pull heavily from the Timber documentation, with some additional observations and anectotes.

Other get_posts() features

Timber only mostly replaces WP_Query() with get_posts() though.

Because it is an 'in-use' query, it supports calling posts by specific IDs, by traditional query $args, or even by a query-string retrieved from the browser!

If you want to see all of the things the PostQuery does, they go over the 2.x version unde 'Types of Post Collections' (the 1.x version we use may not match exactly, however).

Note: We use $context['posts'] here, but (just like default WordPress), you can have as many queries as you want under whatever name you want. By adding it to the $context[''] it will load as a child under that context. (e.g.: A block, a page, an archive, etc.)

Second Note: The examples below expect you're on the <template>.php page and would end with the normal Timber::render() on the associated template.

Example Code:

Use a WP_Query array

<?php
$args = array(
    'post_type' => 'post',
    'tax_query' => array(
        'relation' => 'AND',
        array(
            'taxonomy' => 'movie_genre',
            'field' => 'slug',
            'terms' => array( 'action', 'comedy' )
        ),
        array(
            'taxonomy' => 'actor',
            'field' => 'id',
            'terms' => array( 103, 115, 206 ),
            'operator' => 'NOT IN'
        )
    )
);

$context['posts'] = Timber::get_posts( $args );

Use a WP_Query string

This might be custom generated or retrieved from the browser using $_GET(), or $_SERVER['QUERY_STRING'], $_SERVER['REQUEST_URI'], or similar.

<?php
$args = 'post_type=movies&numberposts=8&orderby=rand';

$context['posts'] = Timber::get_posts( $args );

Use Post ID Numbers

<?php
$ids = array( 14, 123, 234, 421, 811, 6 );

$context['posts'] = Timber::get_posts( $ids );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment