roots/acorn

Bug: AcfFields View Composer Trait not working with block previews

davidwebca opened this issue · 1 comments

Terms

Description

First, I'd like to apologize because I went into a hypnotic deep dive into ACF and WP's code to try to figure out a way to solve this without the need to change the end user's code, but I don't think it's possible right now.

What's wrong?

AcfFields View Composer traits uses "get_fields" to get all the field values, but blocks "example" data can't be fetched with this.

What insights have you gained?

ACF is able to retrieve the example fields with "get_field" only (not "get_fields"), because "get_fields" only fetches metadata about fields that have previously been saved. Since this check internally doesn't happen against example data, and uses field keys instead of field names, it fails.

Possible solutions

Create another trait, (AcfBlockFields?) specifically for blocks.

Temporary workarounds

Since the only way to get the proper data all the time, either from the block's saved values or from the example data, is to pass through "get_field", we need to get all the fields assigned to the block with another method than "get_fields". Here's what I ended up with.

<?php

namespace Roots\Acorn\View\Composers\Concerns;

use Illuminate\Support\Fluent;
use Illuminate\Support\Str;

trait AcfBlockFields
{
    /**
     * ACF data to be passed to the view before rendering.
     *
     * @param  int $post_id
     * @return array
     */
    protected function fields($name)
    {
        $data = [];
        $field_groups = acf_get_field_groups([
            'block' => $name
        ]);
        foreach ($field_groups as $fg_key => $field_group) {
            $fields = acf_get_fields($field_group['key']);
            foreach ($fields as $f_key => $field) {
                $data[$field['name']]=get_field($field['key']);
            }
        }
        return $data;
    }
}

Notes

As mentionned at the beginning, I tried to create a patch on the current trait that would work for both posts and blocks without changing much of the code as I was trying to avoid needing the end users to change their local code, but the problem arises when we need to get the current block's field name. Once we're inside a block rendering loop, there's nothing passing down the current block data, it doesn't seem to be saved by WP in a global(?). The only way to get the current block's name is by passing it down ourselves. I went down the rabbithole of trying to find how ACF stores / re-instates get_the_ID and I found acf_get_instance( 'ACF_Local_Meta' )->post_id which is the current block's ID or the current post's id, for field data retrieval purposes. That being said... nothing allows us to link the block id to the block's name since now the block ids are generated non absolute values. I feel like I'm going insane because it should be easy to detect wether or not we are currently rendering a block and get the block's data / name so that we can shortcircuit the trait's method ``ìf(is_block()) { $this->get_blocks_data(); }```.

On the other hand, creating another trait would probably be the best solution since changing the code in the trait could result in unexpected data changes in previews if people are using sub-views with the existing trait.

Steps To Reproduce

  1. Add a block rendered with a view composer
  2. Pass example data when registering the block
  3. Look at the example previews the block editor pops up in the blocks list when hovering the mouse on the block's names, or previewing a block style

Expected Behavior

Data passed as "example" in acf_register_block_type should be rendered

Actual Behavior

No preview can be generated because example data is not passed down by "get_fields".

Relevant Log Output

No response

Versions

2.1.2