0
votes

For example, I may have a flexible content field that gives you the option of either pulling content automatically from a post type or manually defining the content.

Say a slider block that would ask you if you want to display title and thumbnail of posts in a post type, or manually define a title and image for each slide with a repeater.

The context for the slides changes according to the chosen option. On one hand, you have to fetch posts and display the wanted information, on the other you simply use the manually defined content.


Here's what my files (basically) look like so far:

index.php

$context = Timber::get_context();
$context['post'] = ( is_front_page() ) ? new Timber\Post( get_option( 'page_on_front' ) ) : new Timber\Post();

Timber::render( 'page.twig', $context );

page.twig

{% extends 'base.twig' %}

{% block content %}

    {% for bloc in post.meta('blocs') %}

        {% include 'blocs/' ~ bloc.acf_fc_layout ~ '.twig' ignore missing %}

    {% endfor %}

{% endblock %}

So twig files for each flexible layout are automatically included and I can access the fields just fine. However in my slider example the context for the slides changes depending on the selected options, and I'm trying to keep as much logic out of the twig files as possible.


Fetching posts inside the twig template and setting variables seems messy and counter to the goal of using twig in the first place. Is there a better way to handle this?

1

1 Answers

2
votes

A common way to solve this task is to use a custom class that extends Timber\Post. You can read more about this in the Extending Timber Guide.

In your case, that class could look something like this:

class PostFlexible extends Timber\Post {
    public function dynamic_context( $args ) {
        return $something;
    }
}

Then, instead of using Timber\Post() in your PHP template, you would use the new class:

$context = Timber::get_context();
$context['post'] = ( is_front_page() )
    ? new PostFlexible( get_option( 'page_on_front' ) )
    : new PostFlexible();

Timber::render( 'page.twig', $context );

And in your Twig template, you could call that method that does something:

{{ post.dynamic_context }}

The question is, what exactly do you want to do? You could render or compile another Twig template inside that method. You could fetch the data you need for that template inside your new method in PHP that you would then pass on to the Twig template. This is one approach.

Another approach is to use this method to loop over the flexible fields and extend the data that you need in your Twig template:

{% for bloc in post.blocks %}
    {% include 'blocs/' ~ bloc.acf_fc_layout ~ '.twig' ignore missing %}
{% endfor %}

Now, you could define post.blocks like this:

class PostFlexible extends Timber\Post {
    public function blocks() {
        $blocks = array();

        foreach ( $this->meta( 'bloc' ) as $block ) {
            switch ( $block['acf_fc_layout'] ) {
                case 'slider':
                    // Fetch the data you need for each slider.
                    $block['my_slider_data'] = 'something';
                    break;
            }

            $blocks[ $block ];
        }

        return $blocks;
    }
}

The method fetches the meta data, loops through the flexible fields and adds the data you need depending on the layout name (acf_fc_layout). This way, you still define most of the logic in PHP, and in Twig, you would only display the data.