bobbingwide / oik-testimonials

better by far testimonials
https://www.oik-plugins.com/oik-plugins/oik-testimonials/
GNU General Public License v2.0
1 stars 0 forks source link

Add generic ACF block to display any field #7

Closed bobbingwide closed 1 year ago

bobbingwide commented 1 year ago

The Author name block developed for #6 is a rather trivial block. Suppose I wanted to add an _author_image field to display next to the author name. I'd have to develop a new block similar to the first one. It wouldn't take much effort to copy and cobble the first block, but it would become laborious if I had to do this for lots of fields.

Wouldn't it be better to create a generic acf-field block that could display the value / values of any field registered to ACF?

Requirement

Proposed solution

Note: I've not use the_field() for anything other than a text field so this is an opportunity for me to try each of the field types. Starting with an image.

bobbingwide commented 1 year ago

Oh nuts, the string "field_" may not be used at the start of a field name. That's OK though - I can use the hyphen as originally planned: field-name

bobbingwide commented 1 year ago

Looks like there's already a Meta Field Block plugin! https://wordpress.org/plugins/display-a-meta-field-as-block

bobbingwide commented 1 year ago

I was having difficulty getting ACF to display a new field added to the Testimonials group.

I believe this was because the plugin is calling acf_add_local_field_group() which must be overriding the definition I'd updated using the ACF Field groups. I'll have to look at the documentation for this API.

bobbingwide commented 1 year ago

I'll have to look at the documentation for this API.

I've looked at the documentation and raised an request on ACF Slack #help channel. Had a reply but I'm none the wiser really. I can't yet see why my definition is allowed to override the user defined fields.

I can see a use for local fields when it comes to ACF blocks. Once the fields for a block have been defined they can be registered in response to acf/include_fields and the Field Group can be manually removed from the admin.

BTW. In s.b/wordpress I've now created the acf-json folder in the current theme ( Fizzie ). See https://www.advancedcustomfields.com/resources/local-json/

bobbingwide commented 1 year ago

In s.b/wordpress and s.b/cwiccer, having added the field group for Testimonials to the acf-json folder in the Fizzie theme, in both environments there are two almost identical meta boxes for Testimonials.

One note of interest is that the placeholder for an empty field is the same in both meta boxes.

bobbingwide commented 1 year ago

Had a reply but I'm none the wiser really.

I've made some more progress. Rather than doing manual database queries, I've used acf_get_raw_field_groups() which will use the local JSON solution if configured, or access the acf-field-group posts to return an array of field groups. This can be done in response to either acf/include_fields or acf/init.

When the local JSON files aren't in use then the query performed is

        [6] => Array

            [0] => (string) "
            SELECT   wp_posts.*
            FROM wp_posts 
            WHERE 1=1  AND wp_posts.post_type = 'acf-field-group' AND ((wp_posts.post_status = 'publish' OR wp_posts.post_status = 'acf-disabled'))

            ORDER BY wp_posts.menu_order ASC, wp_posts.post_title ASC

        "
            [1] => (double) 0.00053000450134277
            [2] => (string) "require_once('wp-admin/admin.php'), require_once('wp-load.php'), require_once('wp-config.php'), require_once('wp-settings.php'), do_action('init'), WP_Hook->do_action, WP_Hook->apply_filters, ACF->init, do_action('acf/include_fields'), WP_Hook->do_action, WP_Hook->apply_filters, oik_testimonials_acf_include_fields, oik_maybe_register_testimonials, acf_get_raw_field_groups, acf_get_raw_internal_post_type_posts, ACF_Internal_Post_Type->get_raw_posts, get_posts, WP_Query->query, WP_Query->get_posts"
            [3] => (double) 1684169380.2613
            [4] => Array 

If the $raw_field_groups array returned includes a group called Testimonials then we don't try to register it using acf_add_local_field_group().

[0] => Array

        [location] => Array

            [0] => Array

                [0] => Array

                    [param] => (string) "post_type"
                    [operator] => (string) "=="
                    [value] => (string) "oik_testimonials"

        [position] => (string) "normal"
        [style] => (string) "default"
        [label_placement] => (string) "top"
        [instruction_placement] => (string) "label"
        [hide_on_screen] => (string) ""
        [description] => (string) ""
        [show_in_rest] => (integer) 1
        [ID] => (integer) 3972
        [title] => (string) "Testimonials"
        [key] => (string) "group_6461f5c4cde96"
        [menu_order] => (integer) 0
        [active] => (boolean) 1

This solution enables the user to define the fields to be associated to the oik_testimonials CPT and display whichever fields are needed using the generic ACF field block #7

bobbingwide commented 1 year ago

I can't yet see why my definition is allowed to override the user defined fields.

I haven't dug any deeper into this problem. Basically, when the field was empty then the default value being displayed was the same even if the user defined default was different from the hardcoded version.

bobbingwide commented 1 year ago

The prototype logic in dddc26e should be reworked:

  1. Remove the unnecessary code.
  2. Change oik_maybe_register_testimonials() to oik_maybe_add_local_field_group()
  3. Pass the array for the local field group to the renamed function and call acf_add_local_field_group() within the function when the field group's not already registered.
  4. Consider improving the logic to check the location as well as the title.
bobbingwide commented 1 year ago

Duplicating the ACF Field block and changing the Field name attribute leaves unwanted data values

Original block with field-name set to author-image

<!-- wp:oik-testimonials/acf-field {"name":"oik-testimonials/acf-field",
"data":{"field-name":"author_image","_field-name":"field_645f589a88304"},
"mode":"preview"} /-->

After duplicating and changing the field name to author-image-id the _field-name attribute was unchanged. In the block editor the original image was still being displayed.

<!-- wp:oik-testimonials/acf-field {"name":"oik-testimonials/acf-field",
"data":{"field-name":"author_image_id","_field-name":"field_645f589a88304"},
"mode":"preview"} /-->

After changing the field name to _oik_testimonial_name it became

<!-- wp:oik-testimonials/acf-field {"name":"oik-testimonials/acf-field",
"data":{"field_645f589a88304":"_oik_testimonial_name"},
"mode":"preview"} /-->

Then, later on, the value disappeared

<!-- wp:oik-testimonials/acf-field {"name":"oik-testimonials/acf-field",
"data":{"field_645f589a88304":""},
"mode":"preview"} /-->
bobbingwide commented 1 year ago

Front end rendering of fields of type image needs to take into account the Return format of the image:

For some reason the image is already displayed in the block. Not sure why.

bobbingwide commented 1 year ago

Requirement

Solution

I've refactored again.

In edit mode the block currently looks like this.

image

Now I have to eliminate fields which are only registered for blocks. In this example they're the first 6 in the drop down.

bobbingwide commented 1 year ago

I changed the select list to only display the internal field name & key when SCRIPT_DEBUG is true and I improved the select list to eliminate fields which are only registered for blocks.

The logic includes fields for which the param value is post_type.

image

But the Field group name after the field name can be misleading... the Block Count field is associated with post type Plugin.

It would be better to list one or more post types for which the field is applicable. eg.

bobbingwide commented 1 year ago

This is the ACF Field block in edit mode with SCRIPT_DEBUG true image

bobbingwide commented 1 year ago

I haven't converted the post_type to the post type name. Nor have a catered for Not equals to

I have now. image

In this example I added a Location Rule of Post Type is not equal to Posts

Implementation

bobbingwide commented 1 year ago

The logic to display a WYSIWYG field is to display the content ASIS. No esc_html(). The logic to display an oEmbed field is similar.

But there's are a couple of problems:

  1. Unwanted paragraph tags are being created.... probably wpautop().
  2. There's a style attribute for the iframe which hides the embedded content.
    [value] => (string) "<blockquote class="wp-embedded-content" data-secret="KnIp5reDKa">
<a href="https://herbmiller.me/about/">About</a></blockquote>
<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" 
style="position: absolute; clip: rect(1px, 1px, 1px, 1px);" 
title="&#8220;About&#8221; &#8212; herb miller" 
src="https://herbmiller.me/about/embed/#?secret=fUKEQ6mMbA#?secret=KnIp5reDKa" data-secret="KnIp5reDKa" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no">
</iframe>"

The style attribute is added in wp_filter_oembed_result, in wp-includes/embed.php by the following code. This was part of work to oEmbed: Add extra hardening around allowed HTML for improved sandboxing.

if ( ! empty( $content[1] ) ) {
        // We have a blockquote to fall back on. Hide the iframe by default.
        $html = str_replace( '<iframe', '<iframe style="position: absolute; clip: rect(1px, 1px, 1px, 1px);"', $html );
        $html = str_replace( '<blockquote', '<blockquote class="wp-embedded-content"', $html );
    }

Note: The oembed works in the editor - I can see the iframe. I suspect it's a JavaScript problem with wp-embed.js not being enqueued.

bobbingwide commented 1 year ago

Now adding support for gallery but not sure exactly what HTML to generate. Q: Should it be like the WordPress core/gallery block?

bobbingwide commented 1 year ago

When I added support for the link type field I needed to implement similar logic to that of the Meta Field Block plugin. This required the post_id parameter to be passed to the implementing function.

For improved extensibility I should do the following:

bobbingwide commented 1 year ago

For ACF extensions see https://www.awesomeacf.com/

bobbingwide commented 1 year ago

The acf-field block's enclosing div should include the usuals suspects for a WordPress block in the class attribute.

Q: Does get_block_wrapper_attributes() automatically add the anchor ID? A: No, apparently not, though the documentation does suggest this is done automatically by this function. See https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/

bobbingwide commented 1 year ago

The block.json file should be updated to include several of the more useful supports attributes.

bobbingwide commented 1 year ago

Now that the acf-field-block plugin has been developed it's time to disable the generic field block logic in oik-testimonials.

I need to do this soon since I've twice encountered problems where the logic in oik-testimonials overrides the logic in acf-field-block.

  1. The first was when attempting to prevent tab field types from being listed in the select list of field names.
  2. Today I had problems when trying to internationalize / localize the block.

Both of these were due to oik-testimonials trumping the output of acf-field-blocks. Although part of the reason for the second problem was how I was hooking into the actions and filters. I'd naively assumed that since that since the acf/include_fields hook is called within init then I could call load_text_domain() within my own action hook for init. But this didn't take into account that ACF hooks into init with a lower priority ( 5 ) than the default ( 10 ). Therefore, ACF invokes acf/include_fields before other plugins have had a chance to respond to init. One solution is to hook into init with a lower priority, another is to call load_plugin_text_domain() in the action hook response to acf/include_fields. I chose the second solution.

bobbingwide commented 1 year ago

Closing in favour of #8