diff --git a/block-hydration-experiments.php b/block-hydration-experiments.php
index 39e191be..6ed2656d 100644
--- a/block-hydration-experiments.php
+++ b/block-hydration-experiments.php
@@ -2,83 +2,110 @@
/**
* Plugin Name: block-hydration-experiments
* Version: 0.1.0
- * Requires at least: 5.9
- * Requires PHP: 7.0
+ * Requires at least: 6.0
+ * Requires PHP: 5.6
* Author: Gutenberg Team
* License: GPL-2.0-or-later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: block-hydration-experiments
*/
-function block_hydration_experiments_init() {
- register_block_type( plugin_dir_path( __FILE__ ) . 'build/blocks/block-hydration-experiments-child/' );
- register_block_type( plugin_dir_path( __FILE__ ) . 'build/blocks/block-hydration-experiments-parent/' );
+function block_hydration_experiments_init()
+{
+ register_block_type(
+ plugin_dir_path(__FILE__) . 'build/blocks/interactive-child/'
+ );
+ register_block_type(
+ plugin_dir_path(__FILE__) . 'build/blocks/interactive-parent/'
+ );
+ register_block_type(
+ plugin_dir_path(__FILE__) . 'build/blocks/non-interactive-parent/'
+ );
}
-add_action( 'init', 'block_hydration_experiments_init' );
+add_action('init', 'block_hydration_experiments_init');
-function bhe_block_wrapper( $block_content, $block, $instance ) {
+function bhe_block_wrapper($block_content, $block, $instance)
+{
// We might want to use a flag from block.json as the criterion here.
- if ( ! in_array(
- $block['blockName'],
- array(
- 'bhe/block-hydration-experiments-parent',
- 'bhe/block-hydration-experiments-child'
- ),
- true
- ) ) {
+ if (
+ !in_array(
+ $block['blockName'],
+ [
+ 'bhe/interactive-parent',
+ 'bhe/interactive-child',
+ 'bhe/non-interactive-parent',
+ ],
+ true
+ )
+ ) {
return $block_content;
}
$block_type = $instance->block_type;
$attr_definitions = $block_type->attributes;
- $attributes = array();
- $sourced_attributes = array();
- foreach( $attr_definitions as $attr => $definition ) {
- if ( ! empty( $definition['frontend'] ) ) {
- if ( ! empty( $definition['source'] ) ) {
- $sourced_attributes[ $attr ] = array(
- "selector" => $definition['selector'], // TODO: Guard against unset.
- "source" => $definition['source']
- );
+ $attributes = [];
+ $sourced_attributes = [];
+ foreach ($attr_definitions as $attr => $definition) {
+ if (!empty($definition['frontend'])) {
+ if (!empty($definition['source'])) {
+ $sourced_attributes[$attr] = [
+ 'selector' => $definition['selector'], // TODO: Guard against unset.
+ 'source' => $definition['source'],
+ ];
} else {
- if ( array_key_exists ( $attr, $block['attrs'] ) ) {
- $attributes[ $attr ] = $block['attrs'][$attr];
- } else if ( isset( $definition['default'] ) ) {
- $attributes[ $attr ] = $definition['default'];
+ if (array_key_exists($attr, $block['attrs'])) {
+ $attributes[$attr] = $block['attrs'][$attr];
+ } elseif (isset($definition['default'])) {
+ $attributes[$attr] = $definition['default'];
}
}
}
}
- $previous_block_to_render = WP_Block_Supports::$block_to_render;
- // TODO: The following is a bit hacky. If we stick with this technique, we might
+ // We might want to use a flag from block.json as the criterion here.
+ $hydration_technique = in_array(
+ $block['blockName'],
+ ['bhe/interactive-parent', 'bhe/interactive-child'],
+ true
+ )
+ ? 'idle'
+ : false;
+
+ // The following is a bit hacky. If we stick with this technique, we might
// want to change apply_block_supports() to accepts a block as its argument.
+ $previous_block_to_render = WP_Block_Supports::$block_to_render;
WP_Block_Supports::$block_to_render = $block;
- $block_supports_attributes = WP_Block_Supports::get_instance()->apply_block_supports();
+ $block_props = WP_Block_Supports::get_instance()->apply_block_supports();
WP_Block_Supports::$block_to_render = $previous_block_to_render;
- $block_wrapper = sprintf(
- '',
- esc_attr( $block['blockName'] ),
- esc_attr( json_encode( $block_type->uses_context ) ),
- esc_attr( json_encode( $block_type->provides_context ) ),
- esc_attr( json_encode( $attributes ) ),
- esc_attr( json_encode( $sourced_attributes ) ),
- esc_attr( json_encode( $block_supports_attributes ) )
- ) . '%1$s ';
+ $block_wrapper =
+ sprintf(
+ '',
+ esc_attr($block['blockName']),
+ esc_attr(json_encode($block_type->uses_context)),
+ esc_attr(json_encode($block_type->provides_context)),
+ esc_attr(json_encode($attributes)),
+ esc_attr(json_encode($sourced_attributes)),
+ esc_attr(json_encode($block_props)),
+ esc_attr($hydration_technique)
+ ) . '%1$s ';
- $template_wrapper = '%1$s ';
+ $template_wrapper =
+ '%1$s ';
- $empty_template = sprintf( $template_wrapper, '' );
- $template = sprintf( $template_wrapper, sprintf( $block_wrapper, $block_content . $empty_template ) );
- return sprintf( $block_wrapper, $block_content . $template );
+ $empty_template = sprintf($template_wrapper, '');
+ $template = sprintf(
+ $template_wrapper,
+ sprintf($block_wrapper, $block_content . $empty_template)
+ );
+ return sprintf($block_wrapper, $block_content);
}
-add_filter( 'render_block', 'bhe_block_wrapper', 10, 3 );
\ No newline at end of file
+add_filter('render_block', 'bhe_block_wrapper', 10, 3);
diff --git a/package-lock.json b/package-lock.json
index d2e747dc..78e43365 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2386,6 +2386,17 @@
"integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
"dev": true
},
+ "@prettier/plugin-php": {
+ "version": "0.18.9",
+ "resolved": "https://registry.npmjs.org/@prettier/plugin-php/-/plugin-php-0.18.9.tgz",
+ "integrity": "sha512-d1uE9v3JsQ9uBLWlssZhO02RLI8u8jRBFPCO5ud4VbveCpSZbDRnGpSuK3IqSWHdM/OnuySz0yWr5M9/9mINvw==",
+ "dev": true,
+ "requires": {
+ "linguist-languages": "^7.21.0",
+ "mem": "^8.0.0",
+ "php-parser": "3.1.0-beta.11"
+ }
+ },
"@sideway/address": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
@@ -11334,6 +11345,12 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true
},
+ "linguist-languages": {
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/linguist-languages/-/linguist-languages-7.21.0.tgz",
+ "integrity": "sha512-KrWJJbFOvlDhjlt5OhUipVlXg+plUfRurICAyij1ZVxQcqPt/zeReb9KiUVdGUwwhS/2KS9h3TbyfYLA5MDlxQ==",
+ "dev": true
+ },
"linkify-it": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz",
@@ -11481,6 +11498,15 @@
"tmpl": "1.0.5"
}
},
+ "map-age-cleaner": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
+ "dev": true,
+ "requires": {
+ "p-defer": "^1.0.0"
+ }
+ },
"map-obj": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz",
@@ -11628,6 +11654,24 @@
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true
},
+ "mem": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz",
+ "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==",
+ "dev": true,
+ "requires": {
+ "map-age-cleaner": "^0.1.3",
+ "mimic-fn": "^3.1.0"
+ },
+ "dependencies": {
+ "mimic-fn": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz",
+ "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==",
+ "dev": true
+ }
+ }
+ },
"memfs": {
"version": "3.4.3",
"resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.3.tgz",
@@ -12479,6 +12523,12 @@
"integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==",
"dev": true
},
+ "p-defer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
+ "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==",
+ "dev": true
+ },
"p-event": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz",
@@ -12659,6 +12709,12 @@
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
"dev": true
},
+ "php-parser": {
+ "version": "3.1.0-beta.11",
+ "resolved": "https://registry.npmjs.org/php-parser/-/php-parser-3.1.0-beta.11.tgz",
+ "integrity": "sha512-aKhWHXun6FKa0MX+GcJtEoLPSWuGQTiEkNgckVjT95OAnKG33c+zsDQEpXx4R74PQ030YZLNq9XV7odKapbOsg==",
+ "dev": true
+ },
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
diff --git a/package.json b/package.json
index ec9950df..04cff562 100644
--- a/package.json
+++ b/package.json
@@ -24,11 +24,13 @@
"bracketSameLine": false,
"bracketSpacing": true,
"semi": true,
- "arrowParens": "always"
+ "arrowParens": "always",
+ "phpVersion": "5.6"
},
"devDependencies": {
"@babel/core": "^7.17.10",
"@babel/preset-env": "^7.17.10",
+ "@prettier/plugin-php": "^0.18.9",
"@types/jest": "^27.5.1",
"@wordpress/blocks": "^11.7.0",
"@wordpress/element": "^4.3.0",
diff --git a/src/blocks/block-hydration-experiments-child/style.scss b/src/blocks/block-hydration-experiments-child/style.scss
deleted file mode 100644
index 608dce0d..00000000
--- a/src/blocks/block-hydration-experiments-child/style.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-.wp-block-bhe-block-hydration-experiments-child {
- padding: 15px 10px 15px 50px;
- background-color: rgb(238, 237, 237);
-}
-
-gutenberg-block,
-gutenberg-inner-blocks {
- display: contents;
-}
diff --git a/src/blocks/block-hydration-experiments-parent/edit.js b/src/blocks/block-hydration-experiments-parent/edit.js
deleted file mode 100644
index 0877b69c..00000000
--- a/src/blocks/block-hydration-experiments-parent/edit.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// This import is needed to ensure that the `wp.blockEditor` global is available
-// by the time this component gets loaded. The `Title` component consumes the
-// global but cannot import it because it shouldn't be loaded on the frontend of
-// the site.
-import '@wordpress/block-editor';
-
-import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
-import Button from './shared/button';
-import Title from './shared/title';
-
-export default function Edit({
- attributes: { counter, message },
- setAttributes,
-}) {
- const blockProps = useBlockProps();
- return (
- <>
-
-
setAttributes({ message: val })}
- placeholder="Enter the Title"
- />
-
- setAttributes({ counter: counter + 1 })}>
- {counter}
-
-
-
- >
- );
-}
diff --git a/src/blocks/block-hydration-experiments-parent/frontend/index.js b/src/blocks/block-hydration-experiments-parent/frontend/index.js
deleted file mode 100644
index f48994e4..00000000
--- a/src/blocks/block-hydration-experiments-parent/frontend/index.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import Counter from '../../../context/counter';
-import Theme from '../../../context/theme';
-import { useState } from '../../../gutenberg-packages/wordpress-element';
-import Button from '../shared/button';
-import Title from '../shared/title';
-
-const Frontend = ({
- blockProps: {
- className,
- style: { fontWeight, ...otherStyle },
- },
- attributes: { counter: initialCounter, message },
- children,
-}) => {
- const [show, setShow] = useState(true);
- const [counter, setCounter] = useState(initialCounter);
-
- return (
-
-
-
-
- setShow(!show)} />
- setCounter(counter + 1)}>
- {counter}
-
- {show && children}
-
-
-
- );
-};
-
-export default Frontend;
diff --git a/src/blocks/block-hydration-experiments-parent/shared/button.js b/src/blocks/block-hydration-experiments-parent/shared/button.js
deleted file mode 100644
index f5b4242a..00000000
--- a/src/blocks/block-hydration-experiments-parent/shared/button.js
+++ /dev/null
@@ -1,5 +0,0 @@
-const Button = ({ handler }) => {
- return Show ;
-};
-
-export default Button;
diff --git a/src/blocks/block-hydration-experiments-parent/style.scss b/src/blocks/block-hydration-experiments-parent/style.scss
deleted file mode 100644
index 9e2a2039..00000000
--- a/src/blocks/block-hydration-experiments-parent/style.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-.wp-block-bhe-block-hydration-experiments-parent {
- padding: 15px 10px 15px 50px;
- background-color: rgb(238, 237, 237);
-}
-
-gutenberg-block,
-gutenberg-inner-blocks {
- display: contents;
-}
diff --git a/src/blocks/block-hydration-experiments-child/block.json b/src/blocks/interactive-child/block.json
similarity index 66%
rename from src/blocks/block-hydration-experiments-child/block.json
rename to src/blocks/interactive-child/block.json
index 26d8385a..aee5271c 100644
--- a/src/blocks/block-hydration-experiments-child/block.json
+++ b/src/blocks/interactive-child/block.json
@@ -1,13 +1,13 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
- "name": "bhe/block-hydration-experiments-child",
+ "name": "bhe/interactive-child",
"version": "0.1.0",
- "title": "BHE - Child",
+ "title": "BHE - Interactive Child",
"category": "text",
"icon": "flag",
"description": "",
- "usesContext": ["bhe/title"],
+ "usesContext": ["bhe/interactive-title", "bhe/non-interactive-title"],
"supports": {
"color": {
"text": true
@@ -17,7 +17,7 @@
},
"html": true
},
- "textdomain": "block-hydration-experiments-child",
+ "textdomain": "block-hydration-experiments",
"editorScript": "file:./index.js",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
diff --git a/src/blocks/block-hydration-experiments-child/edit.js b/src/blocks/interactive-child/edit.js
similarity index 52%
rename from src/blocks/block-hydration-experiments-child/edit.js
rename to src/blocks/interactive-child/edit.js
index 62865646..ccad5926 100644
--- a/src/blocks/block-hydration-experiments-child/edit.js
+++ b/src/blocks/interactive-child/edit.js
@@ -5,15 +5,17 @@
import '@wordpress/block-editor';
import { useBlockProps } from '@wordpress/block-editor';
-const Edit = ({ context }) => {
- const blockProps = useBlockProps();
-
- return (
-
-
Child block
-
Block Context - "bhe/title": {context['bhe/title']}
-
- );
-};
+const Edit = ({ context }) => (
+
+
+ Block Context from interactive parent - "bhe/interactive-title":{' '}
+ {context['bhe/interactive-title']}
+
+
+ Block Context from non-interactive parent -
+ "bhe/non-interactive-title": {context['bhe/non-interactive-title']}
+
+
+);
export default Edit;
diff --git a/src/blocks/block-hydration-experiments-child/frontend.js b/src/blocks/interactive-child/frontend.js
similarity index 63%
rename from src/blocks/block-hydration-experiments-child/frontend.js
rename to src/blocks/interactive-child/frontend.js
index fe95b379..d738c420 100644
--- a/src/blocks/block-hydration-experiments-child/frontend.js
+++ b/src/blocks/interactive-child/frontend.js
@@ -8,8 +8,15 @@ const Frontend = ({ blockProps, context }) => {
return (
-
Child block
-
Block Context - "bhe/title": {context['bhe/title']}
+
+ Block Context from interactive parent - "bhe/interactive-title":{' '}
+ {context['bhe/interactive-title']}
+
+
+ Block Context from non-interactive parent -
+ "bhe/non-interactive-title":{' '}
+ {context['bhe/non-interactive-title']}
+
React Context - "counter": {counter}
React Context - "theme": {theme}
diff --git a/src/blocks/block-hydration-experiments-child/index.js b/src/blocks/interactive-child/index.js
similarity index 81%
rename from src/blocks/block-hydration-experiments-child/index.js
rename to src/blocks/interactive-child/index.js
index a9737d28..8c88ccbc 100644
--- a/src/blocks/block-hydration-experiments-child/index.js
+++ b/src/blocks/interactive-child/index.js
@@ -3,7 +3,7 @@ import Edit from './edit';
import Frontend from './frontend';
import './style.scss';
-registerBlockType('bhe/block-hydration-experiments-child', {
+registerBlockType('bhe/interactive-child', {
edit: Edit,
// The Save component is derived from the Frontend component.
frontend: Frontend,
diff --git a/src/blocks/interactive-child/style.scss b/src/blocks/interactive-child/style.scss
new file mode 100644
index 00000000..bd891aa0
--- /dev/null
+++ b/src/blocks/interactive-child/style.scss
@@ -0,0 +1,23 @@
+.wp-block-bhe-interactive-child {
+ padding: 15px 10px 15px 50px;
+ border: 1px solid rgb(255, 162, 0);
+ position: relative;
+}
+
+.wp-block-bhe-interactive-child::before {
+ position: absolute;
+ top: 0;
+ right: 0;
+ border: 1px solid rgb(255, 162, 0);
+ background-color: rgb(255, 162, 0);
+ color: white;
+ margin: -1px;
+ padding: 0px 5px;
+ font-size: 9px;
+ content: 'BHE - Interactive Child';
+}
+
+gutenberg-block,
+gutenberg-inner-blocks {
+ display: contents;
+}
diff --git a/src/blocks/block-hydration-experiments-child/view.js b/src/blocks/interactive-child/view.js
similarity index 78%
rename from src/blocks/block-hydration-experiments-child/view.js
rename to src/blocks/interactive-child/view.js
index b8fb70bc..cc7038be 100644
--- a/src/blocks/block-hydration-experiments-child/view.js
+++ b/src/blocks/interactive-child/view.js
@@ -3,6 +3,6 @@ import ThemeContext from '../../context/theme';
import { registerBlockType } from '../../gutenberg-packages/frontend';
import Frontend from './frontend';
-registerBlockType('bhe/block-hydration-experiments-child', Frontend, {
+registerBlockType('bhe/interactive-child', Frontend, {
usesContext: [ThemeContext, CounterContext],
});
diff --git a/src/blocks/block-hydration-experiments-parent/block.json b/src/blocks/interactive-parent/block.json
similarity index 60%
rename from src/blocks/block-hydration-experiments-parent/block.json
rename to src/blocks/interactive-parent/block.json
index 82ccfc6a..50a87993 100644
--- a/src/blocks/block-hydration-experiments-parent/block.json
+++ b/src/blocks/interactive-parent/block.json
@@ -1,9 +1,9 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
- "name": "bhe/block-hydration-experiments-parent",
+ "name": "bhe/interactive-parent",
"version": "0.1.0",
- "title": "BHE - Parent",
+ "title": "BHE - Interactive Parent",
"category": "text",
"icon": "flag",
"description": "",
@@ -13,11 +13,15 @@
"default": 0,
"frontend": true
},
- "message": {
+ "title": {
"type": "string",
"source": "text",
"selector": ".title",
"frontend": true
+ },
+ "secret": {
+ "type": "string",
+ "default": "fa4e3d47e4e0a38c5c57533391855013"
}
},
"supports": {
@@ -26,16 +30,17 @@
},
"typography": {
"fontSize": true,
- "__experimentalFontWeight": true
+ "__experimentalFontWeight": true,
+ "__experimentalLetterSpacing": true
},
"html": true
},
"providesContext": {
- "bhe/title": "message"
+ "bhe/interactive-title": "title"
},
- "textdomain": "block-hydration-experiments-parent",
+ "usesContext": ["bhe/non-interactive-title"],
+ "textdomain": "block-hydration-experiments",
"editorScript": "file:./index.js",
- "editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"viewScript": "file:./view.js"
}
diff --git a/src/blocks/interactive-parent/edit.js b/src/blocks/interactive-parent/edit.js
new file mode 100644
index 00000000..49a07e4b
--- /dev/null
+++ b/src/blocks/interactive-parent/edit.js
@@ -0,0 +1,33 @@
+// This import is needed to ensure that the `wp.blockEditor` global is available
+// by the time this component gets loaded. The `Title` component consumes the
+// global but cannot import it because it shouldn't be loaded on the frontend of
+// the site.
+import '@wordpress/block-editor';
+
+import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
+import Button from './shared/button';
+import Title from './shared/title';
+
+const Edit = ({ attributes: { counter, title, secret }, setAttributes }) => (
+ <>
+
+
setAttributes({ title: val })}
+ placeholder="This will be passed through context to child blocks"
+ >
+ {title}
+
+
Show
+
setAttributes({ counter: counter + 1 })}>
+ {counter}
+
+
+ This is a secret attribute that should not be serialized:{' '}
+ {secret}
+
+
+
+ >
+);
+
+export default Edit;
diff --git a/src/blocks/interactive-parent/frontend.js b/src/blocks/interactive-parent/frontend.js
new file mode 100644
index 00000000..632f99be
--- /dev/null
+++ b/src/blocks/interactive-parent/frontend.js
@@ -0,0 +1,42 @@
+import Counter from '../../context/counter';
+import Theme from '../../context/theme';
+import { useState } from '../../gutenberg-packages/wordpress-element';
+import Button from './shared/button';
+import Title from './shared/title';
+
+const Frontend = ({
+ blockProps: {
+ className,
+ style: { fontWeight, ...style },
+ },
+ attributes: { counter: initialCounter, title },
+ children,
+}) => {
+ const [show, setShow] = useState(true);
+ const [bold, setBold] = useState(true);
+ const [counter, setCounter] = useState(initialCounter);
+
+ return (
+
+
+
+
{title}
+ setShow(!show)}>Show
+ setBold(!bold)}>Bold
+ setCounter(counter + 1)}>
+ {counter}
+
+ {show && children}
+
+
+
+ );
+};
+
+export default Frontend;
diff --git a/src/blocks/block-hydration-experiments-parent/index.js b/src/blocks/interactive-parent/index.js
similarity index 81%
rename from src/blocks/block-hydration-experiments-parent/index.js
rename to src/blocks/interactive-parent/index.js
index eea543f6..a9f5db57 100644
--- a/src/blocks/block-hydration-experiments-parent/index.js
+++ b/src/blocks/interactive-parent/index.js
@@ -3,7 +3,7 @@ import Edit from './edit';
import Frontend from './frontend';
import './style.scss';
-registerBlockType('bhe/block-hydration-experiments-parent', {
+registerBlockType('bhe/interactive-parent', {
edit: Edit,
// The Save component is derived from the Frontend component.
frontend: Frontend,
diff --git a/src/blocks/interactive-parent/shared/button.js b/src/blocks/interactive-parent/shared/button.js
new file mode 100644
index 00000000..2384a54a
--- /dev/null
+++ b/src/blocks/interactive-parent/shared/button.js
@@ -0,0 +1,5 @@
+const Button = ({ handler, children }) => {
+ return {children} ;
+};
+
+export default Button;
diff --git a/src/blocks/block-hydration-experiments-parent/shared/title.js b/src/blocks/interactive-parent/shared/title.js
similarity index 75%
rename from src/blocks/block-hydration-experiments-parent/shared/title.js
rename to src/blocks/interactive-parent/shared/title.js
index 78bf7859..de3caf96 100644
--- a/src/blocks/block-hydration-experiments-parent/shared/title.js
+++ b/src/blocks/interactive-parent/shared/title.js
@@ -1,8 +1,8 @@
import { RichText } from '../../../gutenberg-packages/wordpress-blockeditor';
-const Title = ({ message, ...props }) => (
+const Title = ({ children, ...props }) => (
- {message}
+ {children}
);
diff --git a/src/blocks/interactive-parent/style.scss b/src/blocks/interactive-parent/style.scss
new file mode 100644
index 00000000..95cfe66a
--- /dev/null
+++ b/src/blocks/interactive-parent/style.scss
@@ -0,0 +1,23 @@
+.wp-block-bhe-interactive-parent {
+ padding: 15px 10px 15px 50px;
+ border: 1px solid rgb(31, 185, 64);
+ position: relative;
+}
+
+.wp-block-bhe-interactive-parent::before {
+ position: absolute;
+ top: 0;
+ right: 0;
+ background-color: rgb(31, 185, 64);
+ border: 1px solid rgb(31, 185, 64);
+ color: white;
+ margin: -1px;
+ padding: 0px 5px;
+ font-size: 10px;
+ content: 'BHE - Interactive Parent';
+}
+
+gutenberg-block,
+gutenberg-inner-blocks {
+ display: contents;
+}
diff --git a/src/blocks/block-hydration-experiments-parent/view.js b/src/blocks/interactive-parent/view.js
similarity index 78%
rename from src/blocks/block-hydration-experiments-parent/view.js
rename to src/blocks/interactive-parent/view.js
index 9fe91d25..6a65088e 100644
--- a/src/blocks/block-hydration-experiments-parent/view.js
+++ b/src/blocks/interactive-parent/view.js
@@ -3,6 +3,6 @@ import ThemeContext from '../../context/theme';
import { registerBlockType } from '../../gutenberg-packages/frontend';
import Frontend from './frontend';
-registerBlockType('bhe/block-hydration-experiments-parent', Frontend, {
+registerBlockType('bhe/interactive-parent', Frontend, {
providesContext: [ThemeContext, CounterContext],
});
diff --git a/src/blocks/non-interactive-parent/block.json b/src/blocks/non-interactive-parent/block.json
new file mode 100644
index 00000000..fa0ba0fc
--- /dev/null
+++ b/src/blocks/non-interactive-parent/block.json
@@ -0,0 +1,30 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 2,
+ "name": "bhe/non-interactive-parent",
+ "version": "0.1.0",
+ "title": "BHE - Non Interactive Parent",
+ "category": "text",
+ "icon": "flag",
+ "description": "",
+ "attributes": {
+ "title": {
+ "type": "string",
+ "source": "text",
+ "selector": ".title",
+ "frontend": true
+ }
+ },
+ "providesContext": {
+ "bhe/non-interactive-title": "title"
+ },
+ "supports": {
+ "color": {
+ "text": true
+ },
+ "html": true
+ },
+ "textdomain": "block-hydration-experiments",
+ "editorScript": "file:./index.js",
+ "style": "file:./style-index.css"
+}
diff --git a/src/blocks/non-interactive-parent/edit.js b/src/blocks/non-interactive-parent/edit.js
new file mode 100644
index 00000000..6871ad27
--- /dev/null
+++ b/src/blocks/non-interactive-parent/edit.js
@@ -0,0 +1,18 @@
+import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
+import { RichText } from '../../gutenberg-packages/wordpress-blockeditor';
+
+const Edit = ({ attributes, setAttributes }) => (
+
+ setAttributes({ title: val })}
+ placeholder="This will be passed through context to child blocks"
+ value={attributes.title}
+ >
+ {attributes.title}
+
+
+
+);
+export default Edit;
diff --git a/src/blocks/non-interactive-parent/frontend.js b/src/blocks/non-interactive-parent/frontend.js
new file mode 100644
index 00000000..70a54e0f
--- /dev/null
+++ b/src/blocks/non-interactive-parent/frontend.js
@@ -0,0 +1,8 @@
+const Frontend = ({ attributes, blockProps, children }) => (
+
+
{attributes.title}
+ {children}
+
+);
+
+export default Frontend;
diff --git a/src/blocks/non-interactive-parent/index.js b/src/blocks/non-interactive-parent/index.js
new file mode 100644
index 00000000..d7fdfae3
--- /dev/null
+++ b/src/blocks/non-interactive-parent/index.js
@@ -0,0 +1,9 @@
+import { registerBlockType } from '../../gutenberg-packages/wordpress-blocks';
+import metadata from './block.json';
+import edit from './edit';
+import frontend from './frontend';
+import './style.scss';
+
+const { name } = metadata;
+
+registerBlockType(name, { edit, frontend });
diff --git a/src/blocks/non-interactive-parent/style.scss b/src/blocks/non-interactive-parent/style.scss
new file mode 100644
index 00000000..c2c61eef
--- /dev/null
+++ b/src/blocks/non-interactive-parent/style.scss
@@ -0,0 +1,23 @@
+.wp-block-bhe-non-interactive-parent {
+ border: 1px solid rgb(34, 168, 235);
+ position: relative;
+ padding: 25px 10px;
+}
+
+.wp-block-bhe-non-interactive-parent::before {
+ content: 'BHE - Non Interactive Parent';
+ position: absolute;
+ top: 0;
+ right: 0;
+ border: 1px solid rgb(34, 168, 235);
+ background-color: rgb(34, 168, 235);
+ color: white;
+ margin: -1px;
+ padding: 0px 5px;
+ font-size: 10px;
+}
+
+gutenberg-block,
+gutenberg-inner-blocks {
+ display: contents;
+}
diff --git a/src/gutenberg-packages/frontend.js b/src/gutenberg-packages/frontend.js
index e3817b3a..74298fb6 100644
--- a/src/gutenberg-packages/frontend.js
+++ b/src/gutenberg-packages/frontend.js
@@ -27,9 +27,6 @@ const Wrappers = ({ wrappers, children }) => {
class GutenbergBlock extends HTMLElement {
connectedCallback() {
setTimeout(() => {
- const blockContext = {};
- const Providers = [];
-
// Get the block attributes.
const attributes = JSON.parse(
this.getAttribute('data-gutenberg-attributes')
@@ -46,6 +43,7 @@ class GutenbergBlock extends HTMLElement {
}
// Get the Block Context from their parents.
+ const blockContext = {};
const usesBlockContext = JSON.parse(
this.getAttribute('data-gutenberg-uses-block-context')
);
@@ -64,7 +62,7 @@ class GutenbergBlock extends HTMLElement {
);
}
- // Prepare to share the Block Context with their children.
+ // Share the Block Context with their children.
const providesBlockContext = JSON.parse(
this.getAttribute('data-gutenberg-provides-block-context')
);
@@ -83,102 +81,118 @@ class GutenbergBlock extends HTMLElement {
});
}
- // Get the block type, block props, inner blocks, frontend component and
- // options.
- const blockType = this.getAttribute('data-gutenberg-block-type');
- const { class: className, style: styleString } = JSON.parse(
- this.getAttribute('data-gutenberg-block-props')
- );
-
- const temporaryElement = document.createElement('div');
- temporaryElement.style.cssText = styleString;
+ // Hydrate the interactive blocks.
+ const hydration = this.getAttribute('data-gutenberg-hydration');
- const innerBlocks = this.querySelector('gutenberg-inner-blocks');
- const { Component, options } = blockTypes.get(blockType);
+ if (hydration) {
+ const Providers = [];
- // Get the React Context from their parents.
- options?.usesContext?.forEach((context) => {
- const event = new CustomEvent('gutenberg-react-context', {
- detail: { context },
- bubbles: true,
- cancelable: true,
+ // Get the block type, block props (class and style), inner blocks,
+ // frontend component and options.
+ const blockType = this.getAttribute(
+ 'data-gutenberg-block-type'
+ );
+ const innerBlocks = this.querySelector(
+ 'gutenberg-inner-blocks'
+ );
+ const { Component, options } = blockTypes.get(blockType);
+ const { class: className, style } = JSON.parse(
+ this.getAttribute('data-gutenberg-block-props')
+ );
+ // Temporary element to translate style strings to style objects.
+ const el = document.createElement('div');
+ el.style.cssText = style;
+ const blockProps = { className, style: el.style };
+ el.remove();
+
+ // Get the React Context from their parents.
+ options?.usesContext?.forEach((context) => {
+ const event = new CustomEvent('gutenberg-react-context', {
+ detail: { context },
+ bubbles: true,
+ cancelable: true,
+ });
+ this.dispatchEvent(event);
+ Providers.push(event.detail.Provider);
});
- this.dispatchEvent(event);
- Providers.push(event.detail.Provider);
- });
-
- // Prepare to share the React Context with their children.
- if (options?.providesContext?.length > 0) {
- this.addEventListener('gutenberg-react-context', (event) => {
- for (const context of options.providesContext) {
- // We compare the provided context with the received context.
- if (event.detail.context === context) {
- // If there's a match, we stop propagation.
- event.stopPropagation();
-
- // We return a Provider that is subscribed to the parent Provider.
- event.detail.Provider = createProvider({
- element: this,
- context,
- });
-
- // We can stop the iteration.
- break;
+
+ // Share the React Context with their children.
+ if (options?.providesContext?.length > 0) {
+ this.addEventListener(
+ 'gutenberg-react-context',
+ (event) => {
+ for (const context of options.providesContext) {
+ // We compare the provided context with the received context.
+ if (event.detail.context === context) {
+ // If there's a match, we stop propagation.
+ event.stopPropagation();
+
+ // We return a Provider that is subscribed to the parent Provider.
+ event.detail.Provider = createProvider({
+ element: this,
+ context,
+ });
+
+ // We can stop the iteration.
+ break;
+ }
+ }
}
- }
- });
- }
+ );
+ }
- // Get the hydration technique.
- const technique = this.getAttribute('data-gutenberg-hydrate');
- const media = this.getAttribute('data-gutenberg-media');
- const hydrationOptions = { technique, media };
-
- hydrate(
-
- {/* Wrap the component with all the React Providers */}
-
-
- {/* Update the value each time one of the React Contexts changes */}
- {options?.providesContext?.map((context, index) => (
-
- ))}
-
- {/* Render the inner blocks */}
- {innerBlocks && (
-
- )}
-
-
-
-
- ,
- this,
- hydrationOptions
- );
+ const media = this.getAttribute(
+ 'data-gutenberg-hydration-media'
+ );
+
+ hydrate(
+
+ {/* Wrap the component with all the React Providers */}
+
+
+ {/* Update the value each time one of the React Contexts changes */}
+ {options?.providesContext?.map(
+ (context, index) => (
+
+ )
+ )}
+
+ {/* Render the inner blocks */}
+ {innerBlocks && (
+
+ )}
+
+
+
+
+ ,
+ this,
+ { technique: hydration, media }
+ );
+ }
});
}
}
+// We need to wrap the element registration code in a conditional for the same
+// reason we assing `blockTypes` to window (see top of the file).
+//
// We need to ensure that the component registration code is only run once
// because it throws if you try to register an element with the same name twice.
-if (customElements.get('gutenberg-interactive-block') === undefined) {
- customElements.define('gutenberg-interactive-block', GutenbergBlock);
+if (customElements.get('gutenberg-block') === undefined) {
+ customElements.define('gutenberg-block', GutenbergBlock);
}
diff --git a/src/gutenberg-packages/wordpress-blocks.js b/src/gutenberg-packages/wordpress-blocks.js
index 5967bad3..9860ee54 100644
--- a/src/gutenberg-packages/wordpress-blocks.js
+++ b/src/gutenberg-packages/wordpress-blocks.js
@@ -1,31 +1,27 @@
import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
import { registerBlockType as gutenbergRegisterBlockType } from '@wordpress/blocks';
-const save =
+const Wrapper =
(Comp) =>
- ({ attributes }) => {
- const blockProps = useBlockProps.save();
- const innerBlocksProps = useInnerBlocksProps.save();
-
- return (
+ ({ attributes }) =>
+ (
<>
+ {/* Block Context is not available during save
+ https://wordpress.slack.com/archives/C02QB2JS7/p1649347999484329 */}
-
+
- {/* Render InnerBlocks inside a template, to avoid losing them
- if Comp doesn't render them. */}
-
>
);
- };
export const registerBlockType = (name, { frontend, edit, ...rest }) => {
- gutenbergRegisterBlockType(name, { edit, save: save(frontend), ...rest });
+ gutenbergRegisterBlockType(name, {
+ edit,
+ save: Wrapper(frontend),
+ ...rest,
+ });
};