Search code examples
wordpresstwigadvanced-custom-fieldstimber

How can i prevent a flexible content field to only render the last item?


I'm working on this flexible field where I have set it up so that the user in wp-admin can change the order of the content and also add new content modules. But if one module is used more than one time it's only the last one that will work. I believe its something I have made wrong in my loop. You can see the code below:

Basically, if the user adds two of the "overview_layout" the last one will work, the first one won't render. How would you solve this?

My ACF: https://pastebin.com/xAuqEtma

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

$context['layout'] = get_field('cancer_type_layout');

if(have_rows('cancer_type_layout')):
  while(have_rows('cancer_type_layout') ): the_row();
    if(get_row_layout() == 'overview_layout'):
      $context['overview'] = array (
        'title' => get_sub_field('ct_overview_title'),
        'text' => get_sub_field('ct_overview_text'),
        'image' => get_sub_field('ct_overview_picture'),
        'class' => 'bg-gray-100',
        'gradient' => true
      );
    elseif(get_row_layout() == 'video_layout'):
      $context['video'] = get_sub_field('ct_video_url');
    elseif(get_row_layout() == 'statlist_layout'):
      $context['statlist'] = array (
        'title' => get_sub_field('ct_statlist_title'),
        'text' => get_sub_field('ct_statlist_text'),
        'list' => get_sub_field('ct_statlist_statlist'),
        'button' => get_sub_field('ct_statlist_button'),
        'buttontext' => get_sub_field('ct_statlist_button_text'),
        'buttonlink' => get_sub_field('ct_statlist_button_link'),
        'buttonfile' => get_sub_field('ct_statlist_button_file')
      );
    elseif(get_row_layout() == 'text_layout'):
      $context['text'] = array (
        'text' => get_sub_field('ct_text_text'),
        'button' => get_sub_field('ct_text_button'),
        'buttontext' => get_sub_field('ct_text_button_text'),
        'buttlink' => get_sub_field('ct_text_button_link')
      );
    elseif(get_row_layout() == 'image_layout'):
      $context['image'] = get_sub_field('ct_image_image');
    elseif(get_row_layout() == 'qoutelist_layout'):
      $context['quotelist'] = get_sub_field('ct_quotelist_quotes');
    elseif(get_row_layout() == 'postlist_layout'):
      $context['postlist'] = get_sub_field('ct_postlist_posts');
    endif;
  endwhile;
endif;

Solution

  • The main problem is that you overwrite variables in your context in each loop. When you set $context['overview] inside a loop, the content you set is not added to the existing content, but it overwrites what you already have. If you wanted that to work, you’d have to use an array and add your data there.

    $context['overview'] = array();
    
    if ( have_rows( 'cancer_type_layout' ) ):
        while ( have_rows( 'cancer_type_layout' ) ): the_row();
            if ( get_row_layout() == 'overview_layout' ):
                $context['overview'][] = array(
                    'title'    => get_sub_field( 'ct_overview_title' ),
                    'text'     => get_sub_field( 'ct_overview_text' ),
                    'image'    => get_sub_field( 'ct_overview_picture' ),
                    'class'    => 'bg-gray-100',
                    'gradient' => true
                );
    

    By using $context['overview'][], you add the data to your existing array, instead overwriting it. However, if you do that for every single layout you have, you end up writing a lot of code. And you split the data into different variables. This will break the order of your layouts, because you only grouped the same Flexible Content layouts into on array.

    I’d recommend to use a different approach, where you don’t have to prepare all the data in PHP and reduce the amount of code you have to write.

    First, when you use get_field(), then you’re not making use of Timber’s functionality. You can use $post->meta() instead.

    $context['layout'] = $post->meta( 'cancer_type_layout' );
    

    Then, in your Twig file, you can loop over the layouts and include a file that displays the block:

    {% if layout is not empty %}
        {% for block in layout %}
            {% include 'block/' ~ block.acf_fc_layout ~ '.twig' ignore missing %}
        {% endfor %}
    {% endif %}
    

    For each of the layouts you have, you can now create a new Twig file with the name of the layout. In that file, all your data in the layout is available under the block variable.

    block/overview_layout.twig

    {{ block.title }}
    {{ block.text }}
    {# … #}
    

    block/statlist_layout.twig

    {{ block.title }}
    {{ block.text }}
    {{ block.list }}
    <a href="{{ block.buttonlink }}">{{ block.buttontext }}</a>
    {# … #}