{"id":5510,"date":"2026-02-12T20:44:39","date_gmt":"2026-02-13T01:44:39","guid":{"rendered":"https:\/\/chubes.net\/?documentation=block-bindings"},"modified":"2026-03-13T03:27:49","modified_gmt":"2026-03-13T07:27:49","slug":"block-bindings","status":"publish","type":"documentation","link":"https:\/\/chubes.net\/docs\/wordpress-core\/block-development\/block-bindings\/","title":{"rendered":"Block Bindings"},"content":{"rendered":"<p>Block bindings connect block attributes to external data sources like post meta, site options, or custom sources.<\/p><h2 class=\"wp-block-heading\">Overview<\/h2><p>Block bindings allow:<\/p><ul class=\"wp-block-list\"><li>Displaying post meta in blocks<\/li><li>Connecting blocks to site options<\/li><li>Creating dynamic content without custom blocks<\/li><li>Pattern-based templates with dynamic data<\/li><\/ul><h2 class=\"wp-block-heading\">Supported Blocks and Attributes<\/h2><p>WordPress 6.5+ supports bindings on these core blocks:<\/p><figure class=\"wp-block-table\"><table><thead><tr><th>Block<\/th><th>Bindable Attributes<\/th><\/tr><\/thead><tbody><tr><td><code>core\/paragraph<\/code><\/td><td><code>content<\/code><\/td><\/tr><tr><td><code>core\/heading<\/code><\/td><td><code>content<\/code><\/td><\/tr><tr><td><code>core\/image<\/code><\/td><td><code>url<\/code>, <code>alt<\/code>, <code>title<\/code><\/td><\/tr><tr><td><code>core\/button<\/code><\/td><td><code>url<\/code>, <code>text<\/code>, <code>linkTarget<\/code>, <code>rel<\/code><\/td><\/tr><\/tbody><\/table><\/figure><h2 class=\"wp-block-heading\">Using Bindings<\/h2><h3 class=\"wp-block-heading\">In Block Markup<\/h3><p>Bindings are specified in the block&#8217;s HTML comment:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">html<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-html\"><code class=\"language-html\">&lt;!-- wp:paragraph {\n    &quot;metadata&quot;: {\n        &quot;bindings&quot;: {\n            &quot;content&quot;: {\n                &quot;source&quot;: &quot;core\/post-meta&quot;,\n                &quot;args&quot;: {\n                    &quot;key&quot;: &quot;custom_excerpt&quot;\n                }\n            }\n        }\n    }\n} --&gt;\n&lt;p&gt;&lt;\/p&gt;\n&lt;!-- \/wp:paragraph --&gt;<\/code><\/pre><\/div><h3 class=\"wp-block-heading\">In Patterns<\/h3><p>Create patterns with bound blocks:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_block_pattern(\n    &#039;my-plugin\/product-card&#039;,\n    [\n        &#039;title&#039;   =&gt; __( &#039;Product Card&#039;, &#039;my-plugin&#039; ),\n        &#039;content&#039; =&gt; &#039;\n            &lt;!-- wp:group {&quot;layout&quot;:{&quot;type&quot;:&quot;constrained&quot;}} --&gt;\n            &lt;div class=&quot;wp-block-group&quot;&gt;\n                &lt;!-- wp:heading {\n                    &quot;metadata&quot;: {\n                        &quot;bindings&quot;: {\n                            &quot;content&quot;: {\n                                &quot;source&quot;: &quot;core\/post-meta&quot;,\n                                &quot;args&quot;: {&quot;key&quot;: &quot;product_name&quot;}\n                            }\n                        }\n                    }\n                } --&gt;\n                &lt;h2 class=&quot;wp-block-heading&quot;&gt;&lt;\/h2&gt;\n                &lt;!-- \/wp:heading --&gt;\n                \n                &lt;!-- wp:image {\n                    &quot;metadata&quot;: {\n                        &quot;bindings&quot;: {\n                            &quot;url&quot;: {\n                                &quot;source&quot;: &quot;core\/post-meta&quot;,\n                                &quot;args&quot;: {&quot;key&quot;: &quot;product_image_url&quot;}\n                            },\n                            &quot;alt&quot;: {\n                                &quot;source&quot;: &quot;core\/post-meta&quot;,\n                                &quot;args&quot;: {&quot;key&quot;: &quot;product_name&quot;}\n                            }\n                        }\n                    }\n                } --&gt;\n                &lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img src=&quot;&quot; alt=&quot;&quot;\/&gt;&lt;\/figure&gt;\n                &lt;!-- \/wp:image --&gt;\n                \n                &lt;!-- wp:paragraph {\n                    &quot;metadata&quot;: {\n                        &quot;bindings&quot;: {\n                            &quot;content&quot;: {\n                                &quot;source&quot;: &quot;core\/post-meta&quot;,\n                                &quot;args&quot;: {&quot;key&quot;: &quot;product_description&quot;}\n                            }\n                        }\n                    }\n                } --&gt;\n                &lt;p&gt;&lt;\/p&gt;\n                &lt;!-- \/wp:paragraph --&gt;\n            &lt;\/div&gt;\n            &lt;!-- \/wp:group --&gt;\n        &#039;,\n    ]\n);<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Built-in Binding Sources<\/h2><h3 class=\"wp-block-heading\">core\/post-meta<\/h3><p>Bind to post meta fields:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">html<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-html\"><code class=\"language-html\">&lt;!-- wp:paragraph {\n    &quot;metadata&quot;: {\n        &quot;bindings&quot;: {\n            &quot;content&quot;: {\n                &quot;source&quot;: &quot;core\/post-meta&quot;,\n                &quot;args&quot;: {\n                    &quot;key&quot;: &quot;my_meta_key&quot;\n                }\n            }\n        }\n    }\n} --&gt;\n&lt;p&gt;&lt;\/p&gt;\n&lt;!-- \/wp:paragraph --&gt;<\/code><\/pre><\/div><p><strong>Requirements:<\/strong><\/p><p>The meta field must be registered with <code>show_in_rest<\/code>:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_post_meta( &#039;post&#039;, &#039;my_meta_key&#039;, [\n    &#039;type&#039;         =&gt; &#039;string&#039;,\n    &#039;single&#039;       =&gt; true,\n    &#039;show_in_rest&#039; =&gt; true,\n    &#039;default&#039;      =&gt; &#039;&#039;,\n] );<\/code><\/pre><\/div><p>For images (URL from meta):<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_post_meta( &#039;post&#039;, &#039;featured_video_thumbnail&#039;, [\n    &#039;type&#039;         =&gt; &#039;string&#039;,\n    &#039;single&#039;       =&gt; true,\n    &#039;show_in_rest&#039; =&gt; true,\n] );<\/code><\/pre><\/div><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">html<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-html\"><code class=\"language-html\">&lt;!-- wp:image {\n    &quot;metadata&quot;: {\n        &quot;bindings&quot;: {\n            &quot;url&quot;: {\n                &quot;source&quot;: &quot;core\/post-meta&quot;,\n                &quot;args&quot;: {&quot;key&quot;: &quot;featured_video_thumbnail&quot;}\n            }\n        }\n    }\n} --&gt;\n&lt;figure class=&quot;wp-block-image&quot;&gt;&lt;img src=&quot;&quot; alt=&quot;&quot;\/&gt;&lt;\/figure&gt;\n&lt;!-- \/wp:image --&gt;<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Custom Binding Sources<\/h2><p>Register your own data sources:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">add_action( &#039;init&#039;, function() {\n    register_block_bindings_source(\n        &#039;my-plugin\/user-data&#039;,\n        [\n            &#039;label&#039;              =&gt; __( &#039;User Data&#039;, &#039;my-plugin&#039; ),\n            &#039;get_value_callback&#039; =&gt; &#039;my_plugin_get_user_binding_value&#039;,\n            &#039;uses_context&#039;       =&gt; [ &#039;postId&#039; ],\n        ]\n    );\n} );\n\nfunction my_plugin_get_user_binding_value( $source_args, $block_instance, $attribute_name ) {\n    $field = $source_args[&#039;field&#039;] ?? &#039;&#039;;\n    \n    \/\/ Get current user or post author\n    $user_id = get_current_user_id();\n    if ( isset( $block_instance-&gt;context[&#039;postId&#039;] ) ) {\n        $user_id = get_post_field( &#039;post_author&#039;, $block_instance-&gt;context[&#039;postId&#039;] );\n    }\n    \n    if ( ! $user_id ) {\n        return null;\n    }\n    \n    $user = get_userdata( $user_id );\n    \n    switch ( $field ) {\n        case &#039;display_name&#039;:\n            return $user-&gt;display_name;\n        case &#039;email&#039;:\n            return $user-&gt;user_email;\n        case &#039;bio&#039;:\n            return $user-&gt;description;\n        case &#039;avatar_url&#039;:\n            return get_avatar_url( $user_id );\n        default:\n            return null;\n    }\n}<\/code><\/pre><\/div><p>Using the custom source:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">html<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-html\"><code class=\"language-html\">&lt;!-- wp:paragraph {\n    &quot;metadata&quot;: {\n        &quot;bindings&quot;: {\n            &quot;content&quot;: {\n                &quot;source&quot;: &quot;my-plugin\/user-data&quot;,\n                &quot;args&quot;: {\n                    &quot;field&quot;: &quot;display_name&quot;\n                }\n            }\n        }\n    }\n} --&gt;\n&lt;p&gt;&lt;\/p&gt;\n&lt;!-- \/wp:paragraph --&gt;<\/code><\/pre><\/div><h3 class=\"wp-block-heading\">Source Registration Options<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_block_bindings_source(\n    &#039;my-plugin\/custom-source&#039;,\n    [\n        \/\/ Display name in editor\n        &#039;label&#039; =&gt; __( &#039;Custom Source&#039;, &#039;my-plugin&#039; ),\n        \n        \/\/ Callback to get value\n        &#039;get_value_callback&#039; =&gt; &#039;my_callback&#039;,\n        \n        \/\/ Context values needed\n        &#039;uses_context&#039; =&gt; [ &#039;postId&#039;, &#039;postType&#039; ],\n    ]\n);<\/code><\/pre><\/div><h3 class=\"wp-block-heading\">Callback Parameters<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">function my_binding_callback( $source_args, $block_instance, $attribute_name ) {\n    \/\/ $source_args - Arguments from the binding (e.g., {&quot;key&quot;: &quot;my_field&quot;})\n    \/\/ $block_instance - WP_Block instance\n    \/\/ $attribute_name - Which attribute is being bound (e.g., &quot;content&quot;, &quot;url&quot;)\n    \n    \/\/ Access block context\n    $post_id = $block_instance-&gt;context[&#039;postId&#039;] ?? null;\n    \n    \/\/ Return the value for this attribute\n    return &#039;bound value&#039;;\n}<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Site Option Binding<\/h2><p>Create a binding source for site options:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_block_bindings_source(\n    &#039;my-plugin\/site-option&#039;,\n    [\n        &#039;label&#039;              =&gt; __( &#039;Site Option&#039;, &#039;my-plugin&#039; ),\n        &#039;get_value_callback&#039; =&gt; function( $source_args ) {\n            $option_name = $source_args[&#039;option&#039;] ?? &#039;&#039;;\n            \n            if ( ! $option_name ) {\n                return null;\n            }\n            \n            \/\/ Whitelist allowed options for security\n            $allowed_options = [\n                &#039;blogname&#039;,\n                &#039;blogdescription&#039;,\n                &#039;admin_email&#039;,\n                &#039;my_plugin_custom_option&#039;,\n            ];\n            \n            if ( ! in_array( $option_name, $allowed_options, true ) ) {\n                return null;\n            }\n            \n            return get_option( $option_name );\n        },\n    ]\n);<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Computed Bindings<\/h2><p>Create bindings that compute values:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_block_bindings_source(\n    &#039;my-plugin\/computed&#039;,\n    [\n        &#039;label&#039;              =&gt; __( &#039;Computed Value&#039;, &#039;my-plugin&#039; ),\n        &#039;uses_context&#039;       =&gt; [ &#039;postId&#039; ],\n        &#039;get_value_callback&#039; =&gt; function( $source_args, $block_instance ) {\n            $compute = $source_args[&#039;compute&#039;] ?? &#039;&#039;;\n            $post_id = $block_instance-&gt;context[&#039;postId&#039;] ?? get_the_ID();\n            \n            switch ( $compute ) {\n                case &#039;reading_time&#039;:\n                    $content = get_post_field( &#039;post_content&#039;, $post_id );\n                    $word_count = str_word_count( wp_strip_all_tags( $content ) );\n                    $minutes = ceil( $word_count \/ 200 );\n                    return sprintf( _n( &#039;%d min read&#039;, &#039;%d min read&#039;, $minutes, &#039;my-plugin&#039; ), $minutes );\n                    \n                case &#039;word_count&#039;:\n                    $content = get_post_field( &#039;post_content&#039;, $post_id );\n                    return number_format( str_word_count( wp_strip_all_tags( $content ) ) );\n                    \n                case &#039;comment_count&#039;:\n                    return get_comments_number( $post_id );\n                    \n                default:\n                    return null;\n            }\n        },\n    ]\n);<\/code><\/pre><\/div><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">html<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-html\"><code class=\"language-html\">&lt;!-- wp:paragraph {\n    &quot;metadata&quot;: {\n        &quot;bindings&quot;: {\n            &quot;content&quot;: {\n                &quot;source&quot;: &quot;my-plugin\/computed&quot;,\n                &quot;args&quot;: {&quot;compute&quot;: &quot;reading_time&quot;}\n            }\n        }\n    }\n} --&gt;\n&lt;p&gt;&lt;\/p&gt;\n&lt;!-- \/wp:paragraph --&gt;<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Editor Integration<\/h2><h3 class=\"wp-block-heading\">JavaScript Source Registration (Experimental)<\/h3><p>For editor-side binding support:<\/p><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">js<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-js\"><code class=\"language-js\">import { registerBlockBindingsSource } from &#039;@wordpress\/blocks&#039;;\n\nregisterBlockBindingsSource( {\n    name: &#039;my-plugin\/js-source&#039;,\n    label: &#039;JavaScript Source&#039;,\n    getValues( { bindings } ) {\n        const values = {};\n        \n        for ( const [ attributeName, binding ] of Object.entries( bindings ) ) {\n            \/\/ Return value for each bound attribute\n            values[ attributeName ] = `Value for ${ binding.args?.key }`;\n        }\n        \n        return values;\n    },\n    setValues( { bindings, dispatch } ) {\n        \/\/ Handle saving values back (if supported)\n    },\n    canUserEditValue( { binding } ) {\n        \/\/ Can this binding be edited in the editor?\n        return true;\n    },\n} );<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Complete Example: Product Block Bindings<\/h2><h3 class=\"wp-block-heading\">Register Meta Fields<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">add_action( &#039;init&#039;, function() {\n    $product_meta = [\n        &#039;product_name&#039;        =&gt; [ &#039;type&#039; =&gt; &#039;string&#039; ],\n        &#039;product_price&#039;       =&gt; [ &#039;type&#039; =&gt; &#039;number&#039; ],\n        &#039;product_description&#039; =&gt; [ &#039;type&#039; =&gt; &#039;string&#039; ],\n        &#039;product_image_url&#039;   =&gt; [ &#039;type&#039; =&gt; &#039;string&#039; ],\n        &#039;product_buy_url&#039;     =&gt; [ &#039;type&#039; =&gt; &#039;string&#039; ],\n    ];\n    \n    foreach ( $product_meta as $key =&gt; $args ) {\n        register_post_meta( &#039;product&#039;, $key, [\n            &#039;type&#039;         =&gt; $args[&#039;type&#039;],\n            &#039;single&#039;       =&gt; true,\n            &#039;show_in_rest&#039; =&gt; true,\n        ] );\n    }\n} );<\/code><\/pre><\/div><h3 class=\"wp-block-heading\">Custom Binding for Formatted Price<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_block_bindings_source(\n    &#039;my-plugin\/product&#039;,\n    [\n        &#039;label&#039;              =&gt; __( &#039;Product Data&#039;, &#039;my-plugin&#039; ),\n        &#039;uses_context&#039;       =&gt; [ &#039;postId&#039; ],\n        &#039;get_value_callback&#039; =&gt; function( $source_args, $block_instance ) {\n            $field = $source_args[&#039;field&#039;] ?? &#039;&#039;;\n            $post_id = $block_instance-&gt;context[&#039;postId&#039;] ?? get_the_ID();\n            \n            if ( get_post_type( $post_id ) !== &#039;product&#039; ) {\n                return null;\n            }\n            \n            switch ( $field ) {\n                case &#039;formatted_price&#039;:\n                    $price = get_post_meta( $post_id, &#039;product_price&#039;, true );\n                    return $price ? &#039;$&#039; . number_format( $price, 2 ) : null;\n                    \n                case &#039;availability&#039;:\n                    $stock = get_post_meta( $post_id, &#039;product_stock&#039;, true );\n                    return $stock &gt; 0 ? __( &#039;In Stock&#039;, &#039;my-plugin&#039; ) : __( &#039;Out of Stock&#039;, &#039;my-plugin&#039; );\n                    \n                default:\n                    return null;\n            }\n        },\n    ]\n);<\/code><\/pre><\/div><h3 class=\"wp-block-heading\">Pattern Using Bindings<\/h3><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">register_block_pattern(\n    &#039;my-plugin\/product-card&#039;,\n    [\n        &#039;title&#039;      =&gt; __( &#039;Product Card&#039;, &#039;my-plugin&#039; ),\n        &#039;categories&#039; =&gt; [ &#039;my-plugin-products&#039; ],\n        &#039;content&#039;    =&gt; &#039;\n&lt;!-- wp:group {&quot;className&quot;:&quot;product-card&quot;,&quot;layout&quot;:{&quot;type&quot;:&quot;constrained&quot;}} --&gt;\n&lt;div class=&quot;wp-block-group product-card&quot;&gt;\n\n    &lt;!-- wp:image {\n        &quot;className&quot;:&quot;product-image&quot;,\n        &quot;metadata&quot;:{\n            &quot;bindings&quot;:{\n                &quot;url&quot;:{&quot;source&quot;:&quot;core\/post-meta&quot;,&quot;args&quot;:{&quot;key&quot;:&quot;product_image_url&quot;}},\n                &quot;alt&quot;:{&quot;source&quot;:&quot;core\/post-meta&quot;,&quot;args&quot;:{&quot;key&quot;:&quot;product_name&quot;}}\n            }\n        }\n    } --&gt;\n    &lt;figure class=&quot;wp-block-image product-image&quot;&gt;&lt;img src=&quot;&quot; alt=&quot;&quot;\/&gt;&lt;\/figure&gt;\n    &lt;!-- \/wp:image --&gt;\n\n    &lt;!-- wp:heading {\n        &quot;level&quot;:3,\n        &quot;metadata&quot;:{\n            &quot;bindings&quot;:{\n                &quot;content&quot;:{&quot;source&quot;:&quot;core\/post-meta&quot;,&quot;args&quot;:{&quot;key&quot;:&quot;product_name&quot;}}\n            }\n        }\n    } --&gt;\n    &lt;h3 class=&quot;wp-block-heading&quot;&gt;&lt;\/h3&gt;\n    &lt;!-- \/wp:heading --&gt;\n\n    &lt;!-- wp:paragraph {\n        &quot;className&quot;:&quot;product-price&quot;,\n        &quot;metadata&quot;:{\n            &quot;bindings&quot;:{\n                &quot;content&quot;:{&quot;source&quot;:&quot;my-plugin\/product&quot;,&quot;args&quot;:{&quot;field&quot;:&quot;formatted_price&quot;}}\n            }\n        }\n    } --&gt;\n    &lt;p class=&quot;product-price&quot;&gt;&lt;\/p&gt;\n    &lt;!-- \/wp:paragraph --&gt;\n\n    &lt;!-- wp:paragraph {\n        &quot;metadata&quot;:{\n            &quot;bindings&quot;:{\n                &quot;content&quot;:{&quot;source&quot;:&quot;core\/post-meta&quot;,&quot;args&quot;:{&quot;key&quot;:&quot;product_description&quot;}}\n            }\n        }\n    } --&gt;\n    &lt;p&gt;&lt;\/p&gt;\n    &lt;!-- \/wp:paragraph --&gt;\n\n    &lt;!-- wp:button {\n        &quot;metadata&quot;:{\n            &quot;bindings&quot;:{\n                &quot;url&quot;:{&quot;source&quot;:&quot;core\/post-meta&quot;,&quot;args&quot;:{&quot;key&quot;:&quot;product_buy_url&quot;}},\n                &quot;text&quot;:{&quot;source&quot;:&quot;my-plugin\/product&quot;,&quot;args&quot;:{&quot;field&quot;:&quot;availability&quot;}}\n            }\n        }\n    } --&gt;\n    &lt;div class=&quot;wp-block-button&quot;&gt;&lt;a class=&quot;wp-block-button__link wp-element-button&quot;&gt;&lt;\/a&gt;&lt;\/div&gt;\n    &lt;!-- \/wp:button --&gt;\n\n&lt;\/div&gt;\n&lt;!-- \/wp:group --&gt;\n        &#039;,\n    ]\n);<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Security Considerations<\/h2><ol class=\"wp-block-list\"><li><p><strong>Whitelist accessible data:<\/strong> Don&#8217;t expose sensitive meta or options.<\/p><\/li><li><p><strong>Validate source args:<\/strong> Check that requested fields are allowed.<\/p><\/li><li><p><strong>Escape output:<\/strong> Values are auto-escaped, but be careful with HTML.<\/p><\/li><li><p><strong>Consider user permissions:<\/strong> Some data may be user-specific.<\/p><\/li><\/ol><div class=\"code-block-wrapper\"><div class=\"code-block-header\"><span class=\"code-block-language\">php<\/span><button class=\"code-copy-btn\" aria-label=\"Copy code\"><svg><use href=\"https:\/\/chubes.net\/wp-content\/themes\/chubes\/assets\/icons\/chubes.svg#icon-copy\"><\/use><\/svg><\/button><\/div><pre data-chubes-enhanced class=\"wp-block-code language-php\"><code class=\"language-php\">function secure_binding_callback( $source_args, $block_instance ) {\n    $allowed_keys = [ &#039;public_field&#039;, &#039;display_name&#039; ];\n    $key = $source_args[&#039;key&#039;] ?? &#039;&#039;;\n    \n    if ( ! in_array( $key, $allowed_keys, true ) ) {\n        return null; \/\/ Don&#039;t expose unauthorized data\n    }\n    \n    return get_post_meta( $post_id, $key, true );\n}<\/code><\/pre><\/div><h2 class=\"wp-block-heading\">Best Practices<\/h2><ol class=\"wp-block-list\"><li><p><strong>Register meta properly:<\/strong> Always use <code>show_in_rest =&gt; true<\/code>.<\/p><\/li><li><p><strong>Provide fallbacks:<\/strong> Handle missing data gracefully.<\/p><\/li><li><p><strong>Use context:<\/strong> Access postId from block context when available.<\/p><\/li><li><p><strong>Document your sources:<\/strong> Help users understand available bindings.<\/p><\/li><li><p><strong>Consider caching:<\/strong> Cache expensive computations.<\/p><\/li><li><p><strong>Test in editor:<\/strong> Verify bindings work in the block editor.<\/p><\/li><li><p><strong>Security first:<\/strong> Never expose sensitive data through bindings.<\/p><\/li><\/ol>","protected":false},"excerpt":{"rendered":"<p>Block bindings connect block attributes to external data sources like post meta, site options, or custom sources. Overview Block bindings allow: Displaying post meta in blocks Connecting blocks to site&#8230;<\/p>\n","protected":false},"featured_media":0,"template":"","meta":{"footnotes":""},"tags":[],"project":[600],"project_type":[749],"class_list":["post-5510","documentation","type-documentation","status-publish","hentry","project-block-development","project_type-wordpress-reference"],"project_info":{"id":589,"name":"WordPress Core","slug":"wordpress-core"},"project_type_info":{"id":749,"name":"WordPress Reference","slug":"wordpress-reference"},"_links":{"self":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation\/5510","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation"}],"about":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/types\/documentation"}],"version-history":[{"count":3,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation\/5510\/revisions"}],"predecessor-version":[{"id":9006,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/documentation\/5510\/revisions\/9006"}],"wp:attachment":[{"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/media?parent=5510"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/tags?post=5510"},{"taxonomy":"project","embeddable":true,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/project?post=5510"},{"taxonomy":"project_type","embeddable":true,"href":"https:\/\/chubes.net\/wp-json\/wp\/v2\/project_type?post=5510"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}