sybrew / the-seo-framework

The SEO Framework WordPress plugin.
https://theseoframework.com/
GNU General Public License v3.0
425 stars 47 forks source link

Supports Bricks Builder Dynamic Data (DD). #683

Open datgausaigon opened 4 months ago

datgausaigon commented 4 months ago

I currently use Bricks Builder and The SEO Framework (TSF) for many of my Websites. Bricks Builder, TFS both have very good api support and documentation.

Therefore, I have no difficulty creating Dynamic Data (DD) links between Bricks Builder and TFS.

One of the DDs I find very necessary and use is to call The social image URL (_social_image_url), The social image ID (_social_image_id). My Post/Page/CPT will have the Featured Image as a square and the Social Image as a horizontal rectangle. It will be very convenient for me to reuse Social Image for display on PC, Desktop, Featured Image for Mobile, or somewhere it will be Social Image or Featured Image in a flexible way.

I created this Feature Request to ask for your feedback on Bricks Builder Dynamic Data (DD) for TSF? It is very useful. Like my Social Image DD as an example.

https://kb.theseoframework.com/kb/data-stored-in-your-database/

https://academy.bricksbuilder.io/article/dynamic-data/

https://academy.bricksbuilder.io/article/create-your-own-dynamic-data-tag/

Thanks 🐻

sybrew commented 4 months ago

We currently have no intention to expose TSF's data for display other than aimed at search engines. The breadcrumbs shortcode was postponed by a few years for this reason.

Bricks's Dynamic Data could interpret existing meta fields, for example, via {term_meta:my_term_meta_key}. However, because we use a key-value store, the data we store is an array. So, you cannot call {term_meta:autodescription-term-settings}, for you'll get an array-to-string conversion error.

For now, the same doesn't apply to TSF's post metadata (their documentation doesn't say how to access post meta). But I'm planning to convert this data to a key-value store as well: https://github.com/sybrew/the-seo-framework/issues/185. Bricks does have something to access array values; however, it is unclear to me if this could be applied to what we currently offer.

I think if we were to implement this, we'd indeed need to create custom dynamic data. Here's an example (untested, based on their documentation):

add_filter(
    'bricks/dynamic_tags_list',
    /**
     * @param array $tags
     */
    function ( $tags ) {

        $tags[] = [
            'name'  => '{tsf_post_meta}',
            'label' => 'The SEO Framework post metadata',
            'group' => 'The SEO Framework',
        ];

        return $tags;
    },
);

add_filter(
    'bricks/dynamic_data/render_tag',
    /**
     * @param string $tag
     * @param WP_Post $post
     */
    function ( $tag, $post ) {

        if ( ! str_starts_with( $tag, 'tsf_post_meta:' ) )
            return $tag;

        if ( ! function_exists( 'tsf' ) )
            return '';

        $tag_parts = explode( ':', $tag );

        switch ( $tag_parts[1] ?? '' ) {
            case 'title':
                return tsf()->get_title( [ 'id' => $tag_parts[2] ?? $post->ID ] );
            case 'description':
                return tsf()->get_description( [ 'id' => $tag_parts[2] ?? $post->ID ] );
            case 'canonical_url':
                return tsf()->get_canonical_url( [ 'id' => $tag_parts[2] ?? $post->ID ] );
        }

        return '';
    },
    10,
    2,
);

(Where do I place filters?)

With that, here's how you get the title for post ID 42:

{tsf_post_meta:title:42}

You can also omit the :42 part to get it for the current page. For example, here's how to get the description for the current page:

{tsf_post_meta:description}

I hope this helps :)

datgausaigon commented 4 months ago

Hi @sybrew ,

Thank you very much for your attention to my request. ❤️

I'm currently very interested in the fact that TSF has Bricks Dynamic Data that are single data fields stored in _postmeta. Like "Social Image" is one of the things I'm most interested in today. Could you please prioritize Bricks DD development for the single data fields (not arrays) of the TSF stored in _postmeta first?

I'm trying to create a plugin to make calling TFS's Social Image via Bricks DD easy and in accordance with Bricks' code standards. I followed the Bricks instructions and documentation but I'm having problems. This is my code.

<?php
/**
 * Plugin Name: @Dev - TSF and Bricks DD
 * Version: 1.0.1
 */

add_filter( 'bricks/dynamic_tags_list', 'tsf_dynamic_data_tags_list', 10, 1 );
add_filter( 'bricks/dynamic_data/render_tag', 'tsf_social_image_render_tag', 10, 3 );
add_filter( 'bricks/dynamic_data/render_content', 'tsf_social_image_render_content', 10, 3 );
add_filter( 'bricks/frontend/render_data', 'tsf_social_image_render_content', 10, 2 );

function tsf_dynamic_data_tags_list( $tags ) {

    $tags[] = [
        'name'  => '{tsf_social_image}',
        'label' => 'Social Image',
        'group' => 'The SEO Framework',
    ];

    return $tags;
}

function tsf_social_image_render_tag( $tag, $post, $context = 'text' ) {
    if ( $tag !== 'tsf_social_image' ) {
        return $tag;
    }

    $post_id = $post->ID;

    $social_image_data = tsf_social_image_tag_logic( $post_id, $context );

    return $social_image_data;
}

function tsf_social_image_render_content( $content, $post, $context = 'text' ) {

    if ( ! str_contains( $content, '{tsf_social_image}' ) ) {
        return $content;
    }

    $post_id = $post->ID;

    $social_image_data = tsf_social_image_tag_logic( $post_id, $context );

    $content = str_replace( '{tsf_social_image}', $social_image_data, $content );

    return $content;
}

function tsf_social_image_tag_logic( $post_id, $context ) {

    $social_image_id = get_post_meta( $post_id, '_social_image_id', true );

    $social_image_id = ! empty( $social_image_id ) ? $social_image_id : '';

    $social_image_data = $social_image_id;

    if ( $context === 'image' ) {
        $social_image_data = ( ! empty( $social_image_id ) ) ? [ $social_image_id ] : [];
    }

    return $social_image_data;
}

Bricks DD displays fine in Builder like my Screenshot:

Screenshot 2024-07-25 at 12 39 13

If I call Dynamic Data Tag {tsf_social_image} in "Heading Element" I get "_social_image_id" as I expected. But if I call {tsf_social_image} on an "IMAGE" Element I get an error message. According to Bricks' instructions, when we want to Render Image Dynamic Data for Image Element, we need to return an array of image IDs. Here is a link related to that issue.

https://forum.bricksbuilder.io/t/dynamic-data-not-rendered-correctly-on-image-element/22641/

I have tried many ways but still stuck here. This is the error message.

Fatal error: Uncaught TypeError: strpos(): Argument #1 ($haystack) must be of type string, array given in /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/integrations/dynamic-data/providers.php:305 Stack trace: #0 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/integrations/dynamic-data/providers.php(305): strpos() #1 /usr/local/lsws/domain.dev/html/wp-includes/class-wp-hook.php(324): Bricks\Integrations\Dynamic_Data\Providers->get_tag_value() #2 /usr/local/lsws/domain.dev/html/wp-includes/plugin.php(205): WP_Hook->apply_filters() #3 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/integrations/dynamic-data/providers.php(362): apply_filters() #4 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/elements/base.php(3573): Bricks\Integrations\Dynamic_Data\Providers::render_tag() #5 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/elements/image.php(625): Bricks\Element->render_dynamic_data_tag() #6 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/elements/image.php(658): Bricks\Element_Image->get_normalized_image_settings() #7 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/elements/base.php(2324): Bricks\Element_Image->render() #8 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/frontend.php(557): Bricks\Element->init() #9 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/frontend.php(656): Bricks\Frontend::render_element() #10 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/frontend.php(906): Bricks\Frontend::render_data() #11 /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/page.php(7): Bricks\Frontend::render_content() #12 /usr/local/lsws/domain.dev/html/wp-includes/template-loader.php(106): include('...') #13 /usr/local/lsws/domain.dev/html/wp-blog-header.php(19): require_once('...') #14 /usr/local/lsws/domain.dev/html/index.php(17): require('...') #15 {main} thrown in /usr/local/lsws/domain.dev/html/wp-content/themes/bricks/includes/integrations/dynamic-data/providers.php on line 305

There has been a critical error on this website.

Can you assist me in correcting this issue? If you need a dev site for this issue with Bricks License, please message me.

Looking forward to your help

🐻

touchdowntech commented 2 months ago

I'm also very interested about using dynamic data in TSF but I'd primarily like to use dynamic data from custom fields (for example price or driving_distance) in the TSF meta description.

sybrew commented 2 months ago

I parked this issue for reconsideration, but I didn't see the part where you asked for help with the filters. Sorry about that, @datgausaigon. It appears your code is mixing arrays and strings. The return value to the filters should be a string. Basically, change all instances of [ $image_id ] to $image_id (without the square brackets), and the error should disappear.

@touchdowntech Your request is covered in https://github.com/sybrew/the-seo-framework/issues/140. At https://github.com/sybrew/the-seo-framework/issues/140#issuecomment-462597715, you can see an example filter. I just updated its syntax for TSF v5.0+.