From 524a22e76ccb2b241606688f88431ce6aa86b98f Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 11 Oct 2023 11:43:27 -0500 Subject: [PATCH 1/4] adding blocks --- blocks/condition/block.json | 32 ++++++ blocks/condition/edit.tsx | 126 +++++++++++++++++++++++ blocks/condition/index.php | 200 ++++++++++++++++++++++++++++++++++++ blocks/condition/index.tsx | 16 +++ blocks/is-false/block.json | 13 +++ blocks/is-false/edit.tsx | 14 +++ blocks/is-false/index.php | 62 +++++++++++ blocks/is-false/index.tsx | 16 +++ blocks/is-true/block.json | 13 +++ blocks/is-true/edit.tsx | 14 +++ blocks/is-true/index.php | 62 +++++++++++ blocks/is-true/index.tsx | 16 +++ 12 files changed, 584 insertions(+) create mode 100644 blocks/condition/block.json create mode 100644 blocks/condition/edit.tsx create mode 100644 blocks/condition/index.php create mode 100644 blocks/condition/index.tsx create mode 100644 blocks/is-false/block.json create mode 100644 blocks/is-false/edit.tsx create mode 100644 blocks/is-false/index.php create mode 100644 blocks/is-false/index.tsx create mode 100644 blocks/is-true/block.json create mode 100644 blocks/is-true/edit.tsx create mode 100644 blocks/is-true/index.php create mode 100644 blocks/is-true/index.tsx diff --git a/blocks/condition/block.json b/blocks/condition/block.json new file mode 100644 index 0000000..de1bf2c --- /dev/null +++ b/blocks/condition/block.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "wp-conditional-blocks/condition", + "version": "0.1.0", + "title": "Condition", + "category": "theme", + "icon": "star-half", + "description": "Conditionally show is-true or is-false blocks", + "textdomain": "wp-conditional-blocks", + "editorScript": "file:index.ts", + "editorStyle": "file:index.css", + "render": "file:render.php", + "attributes": { + "condition": { + "type": "string" + }, + "custom": { + "type": "string" + }, + "post": { + "type": "string" + }, + "query": { + "type": "string" + }, + "index": { + "type": "object", + "default": { "": "" } + } + } +} diff --git a/blocks/condition/edit.tsx b/blocks/condition/edit.tsx new file mode 100644 index 0000000..8676ffa --- /dev/null +++ b/blocks/condition/edit.tsx @@ -0,0 +1,126 @@ +import { __ } from '@wordpress/i18n'; +import { InnerBlocks, InspectorControls, useBlockProps } from '@wordpress/block-editor'; +import { + PanelBody, PanelRow, SelectControl, TextControl, +} from '@wordpress/components'; + +import { useParentBlock } from '@alleyinteractive/block-editor-tools'; + +interface EditProps { + attributes: { + condition?: string; + custom?: string; + post?: string; + query?: string; + index?: object; + }; + setAttributes: (attributes: any) => void; + clientId: string; +} + +/** + * The wp-conditional-blocks/condition block edit function. + * + * @return {WPElement} Element to render. + */ +export default function Edit({ + attributes: { + condition = '', + custom = '', + post = '', + query = '', + index = { '': '' }, + }, + setAttributes, + clientId, +}: EditProps) { + const { name: parentBlock } = useParentBlock(clientId) as { name?: string } || {}; + const [operator, compared] = Object.entries(index)[0]; + + return ( + <> +
+ +
+ + + + + setAttributes({ query: next })} + value={query} + /> + + + + setAttributes({ post: next })} + value={post} + /> + + + + setAttributes({ custom: next })} + value={custom} + /> + + + + setAttributes({ condition: next })} + value={condition} + /> + + + + { parentBlock === 'wp-conditional-blocks/query' ? ( + +

{__('Checks the index of how many times the parent condition block has been rendered, ie "Equal to 0", "Greater than 5"', 'wp-conditional-blocks')}

+ + + ', label: __('Greater than', 'wp-conditional-blocks') }, + { value: '<', label: __('Less than', 'wp-conditional-blocks') }, + { value: '>=', label: __('Greater than or equal to', 'wp-conditional-blocks') }, + { value: '<=', label: __('Less than or equal to', 'wp-conditional-blocks') }, + ]} + onChange={(next: string) => setAttributes({ index: { [next]: compared } })} + /> + + + + setAttributes({ index: { [operator]: next } })} + type="number" + value={compared} + /> + +
+ ) : null} +
+ + ); +} diff --git a/blocks/condition/index.php b/blocks/condition/index.php new file mode 100644 index 0000000..38141b4 --- /dev/null +++ b/blocks/condition/index.php @@ -0,0 +1,200 @@ + fn ( $attributes, $content ) => $content, + ], + ); +} +add_action( 'init', 'wp_curate_condition_block_init' ); + +/** + * Evaluate the result of condition block attributes. + * + * @param array{ + * attrs?: array{ + * query?: string|array, + * post?: mixed[], + * custom?: mixed[], + * condition?: string[], + * index?: array + * } + * } $parsed_block Parsed condition block. + * @param array{'postId'?: int} $context Available context. + * @return bool + */ +function wp_curate_condition_block_result( array $parsed_block, array $context ): bool { + global $wp_query; + + $num_conditions = 0; + $num_true = 0; + + $conditions = []; + + if ( isset( $parsed_block['attrs'] ) ) { + $conditions = $parsed_block['attrs']; + } + + if ( isset( $conditions['query'] ) && $wp_query instanceof WP_Query ) { + // Map `{"query": "is_home"} to {"query": {"is_home": true}}`. + if ( is_string( $conditions['query'] ) ) { + $conditions['query'] = array_fill_keys( (array) $conditions['query'], true ); + } + + foreach ( $conditions['query'] as $condition => $expect ) { + $num_conditions++; + + switch ( true ) { + case 'is_singular' === $condition && ( is_string( $expect ) || is_array( $expect ) ): + $result = $wp_query->is_singular( $expect ); + break; + + case 'is_page' === $condition && ( is_string( $expect ) || is_array( $expect ) ): + $result = $wp_query->is_page( $expect ); + break; + + case 'is_tax' === $condition && ( is_string( $expect ) || is_array( $expect ) ): + $result = $wp_query->is_tax( $expect ); + break; + + case method_exists( $wp_query, $condition ) && is_callable( [ $wp_query, $condition ] ): + $result = call_user_func( [ $wp_query, $condition ] ) === $expect; // @phpstan-ignore-line + break; + + default: + $result = false; + break; + } + + if ( false === $result ) { + break; + } + + $num_true++; + } + } + + /* + * Checks the index of how many times the parent condition block has been rendered, like: + * + * {"index": {"===": 0}} + * {"index": {">": 2}} + * {"index": {">": 2, "<": 4}} + * + * @see \Alley\Validator\Comparison for the available operators. + * + * Note that this approach means that two identical conditions with two identical set of + * child blocks will use the same counter. + */ + if ( isset( $conditions['index'] ) ) { + $num_conditions++; + + $validator = new \Laminas\Validator\ValidatorChain(); + + foreach ( $conditions['index'] as $operator => $compared ) { + try { + $validator->attach( + validator: new \Alley\Validator\Comparison( + [ + 'operator' => $operator, + 'compared' => $compared, + ], + ), + breakChainOnFailure: true, + ); + } catch ( Exception $exception ) { + // Nothing yet. + unset( $exception ); + } + } + + if ( count( $validator ) > 0 ) { + if ( $validator->isValid( wp_curate_current_counter_block() ) ) { + $num_true++; + } + } + } + + if ( + isset( $conditions['post'] ) + && isset( $context['postId'] ) + && $context['postId'] > 0 + ) { + $conditions['post'] = (array) $conditions['post']; + + foreach ( $conditions['post'] as $condition ) { + $num_conditions++; + + if ( 'has_content' === $condition ) { + if ( '' !== get_the_content( null, false, $context['postId'] ) ) { + $num_true++; + } + + continue; + } + + /** + * Filters the condition block's result for the given post condition. + * + * @param bool $result Condition result. + * @param mixed $condition Condition name. + * @param int $post_id Post ID. + */ + if ( true === apply_filters( 'wp_curate_condition_block_post_condition', false, $condition, $context['postId'] ) ) { + $num_true++; + } + } + } + + if ( isset( $conditions['custom'] ) ) { + $conditions['custom'] = (array) $conditions['custom']; + + foreach ( $conditions['custom'] as $condition ) { + $num_conditions++; + } + } + + if ( isset( $conditions['condition'] ) ) { + $conditions['condition'] = (array) $conditions['condition']; + + foreach ( $conditions['condition'] as $name ) { + $num_conditions++; + + /** + * Filters the condition block's result for the given condition. + * + * @param bool $result Condition result. + * @param array $context Available context. + * @param WP_Query $wp_query Global query object. + */ + $result = apply_filters( "wp_curate_condition_block_{$name}_condition", false, $context, $wp_query ); + + if ( true === $result ) { + $num_true++; + } + } + } + + return $num_conditions > 0 && $num_conditions === $num_true; +} diff --git a/blocks/condition/index.tsx b/blocks/condition/index.tsx new file mode 100644 index 0000000..e615322 --- /dev/null +++ b/blocks/condition/index.tsx @@ -0,0 +1,16 @@ +import { registerBlockType } from '@wordpress/blocks'; +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; + +import edit from './edit'; +import metadata from './block.json'; + +/* @ts-expect-error Provided types are inaccurate to the actual plugin API. */ +registerBlockType(metadata, { + edit, + save: () => ( +
+ {/* @ts-ignore */} + +
+ ), +}); diff --git a/blocks/is-false/block.json b/blocks/is-false/block.json new file mode 100644 index 0000000..b01b275 --- /dev/null +++ b/blocks/is-false/block.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "wp-conditional-blocks/is-false", + "version": "0.1.0", + "title": "Is false", + "category": "theme", + "icon": "star-empty", + "description": "Displays when the condition is false.", + "textdomain": "wp-conditional-blocks", + "editorScript": "file:index.ts", + "parent": ["condition"] +} diff --git a/blocks/is-false/edit.tsx b/blocks/is-false/edit.tsx new file mode 100644 index 0000000..4a52574 --- /dev/null +++ b/blocks/is-false/edit.tsx @@ -0,0 +1,14 @@ +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; + +/** + * The wp-conditional-blocks/is-false block edit function. + * + * @return {WPElement} Element to render. + */ +export default function Edit() { + return ( +
+ +
+ ); +} diff --git a/blocks/is-false/index.php b/blocks/is-false/index.php new file mode 100644 index 0000000..72132ba --- /dev/null +++ b/blocks/is-false/index.php @@ -0,0 +1,62 @@ + fn ( $attributes, $content ) => $content, + ], + ); +} +add_action( 'init', 'wp_curate_is_false_block_init' ); + +/** + * Short-circuit the display of blocks inside if the outer condition isn't false. + * + * @param string|null $pre_render The pre-rendered content. Default null. + * @param WP_Block $parsed_block The block being rendered. + * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block. + */ +function wp_curate_pre_render_is_false_block( $pre_render, $parsed_block, $parent_block ): string|null { + /* + * Previously, the condition block added 'conditionResult' as context to this block. However, + * limitations in the context API meant that the context didn't get passed to child blocks when + * the condition block was itself a child block. We now pass the condition block back to a + * separate function that lives outside the context API and evaluates the result. + */ + if ( + isset( $parsed_block['blockName'] ) + && 'wp-conditional-blocks/is-false' === $parsed_block['blockName'] + && $parent_block instanceof WP_Block + && isset( $parent_block->parsed_block['blockName'] ) + && 'wp-conditional-blocks/condition' === $parent_block->parsed_block['blockName'] + ) { + $context = []; + + if ( isset( $parent_block->context['postId'] ) ) { + $context['postId'] = $parent_block->context['postId']; + } + + $result = wp_curate_condition_block_result( $parent_block->parsed_block, $context ); + + if ( false !== $result ) { + $pre_render = ''; + } + } + + return $pre_render; +} +add_filter( 'pre_render_block', 'wp_curate_pre_render_is_false_block', 10, 3 ); diff --git a/blocks/is-false/index.tsx b/blocks/is-false/index.tsx new file mode 100644 index 0000000..e615322 --- /dev/null +++ b/blocks/is-false/index.tsx @@ -0,0 +1,16 @@ +import { registerBlockType } from '@wordpress/blocks'; +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; + +import edit from './edit'; +import metadata from './block.json'; + +/* @ts-expect-error Provided types are inaccurate to the actual plugin API. */ +registerBlockType(metadata, { + edit, + save: () => ( +
+ {/* @ts-ignore */} + +
+ ), +}); diff --git a/blocks/is-true/block.json b/blocks/is-true/block.json new file mode 100644 index 0000000..76df2bf --- /dev/null +++ b/blocks/is-true/block.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "wp-conditional-blocks/is-true", + "version": "0.1.0", + "title": "Is true", + "category": "theme", + "icon": "star-filled", + "description": "Displays when the condition is true.", + "textdomain": "wp-conditional-blocks", + "editorScript": "file:index.ts", + "parent": ["condition"] +} diff --git a/blocks/is-true/edit.tsx b/blocks/is-true/edit.tsx new file mode 100644 index 0000000..e4ef8ce --- /dev/null +++ b/blocks/is-true/edit.tsx @@ -0,0 +1,14 @@ +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; + +/** + * The wp-conditional-blocks/is-true block edit function. + * + * @return {WPElement} Element to render. + */ +export default function Edit() { + return ( +
+ +
+ ); +} diff --git a/blocks/is-true/index.php b/blocks/is-true/index.php new file mode 100644 index 0000000..452d4e9 --- /dev/null +++ b/blocks/is-true/index.php @@ -0,0 +1,62 @@ + fn ( $attributes, $content ) => $content, + ], + ); +} +add_action( 'init', 'wp_curate_is_true_block_init' ); + +/** + * Short-circuit the display of blocks inside if the outer condition isn't true. + * + * @param string|null $pre_render The pre-rendered content. Default null. + * @param WP_Block $parsed_block The block being rendered. + * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block. + */ +function wp_curate_pre_render_is_true_block( $pre_render, $parsed_block, $parent_block ): string|null { + /* + * Previously, the condition block added 'conditionResult' as context to this block. However, + * limitations in the context API meant that the context didn't get passed to child blocks when + * the condition block was itself a child block. We now pass the condition block back to a + * separate function that lives outside the context API and evaluates the result. + */ + if ( + isset( $parsed_block['blockName'] ) + && 'wp-conditional-blocks/is-true' === $parsed_block['blockName'] + && $parent_block instanceof WP_Block + && isset( $parent_block->parsed_block['blockName'] ) + && 'wp-conditional-blocks/condition' === $parent_block->parsed_block['blockName'] + ) { + $context = []; + + if ( isset( $parent_block->context['postId'] ) ) { + $context['postId'] = $parent_block->context['postId']; + } + + $result = wp_curate_condition_block_result( $parent_block->parsed_block, $context ); + + if ( true !== $result ) { + $pre_render = ''; + } + } + + return $pre_render; +} +add_filter( 'pre_render_block', 'wp_curate_pre_render_is_true_block', 10, 3 ); diff --git a/blocks/is-true/index.tsx b/blocks/is-true/index.tsx new file mode 100644 index 0000000..e615322 --- /dev/null +++ b/blocks/is-true/index.tsx @@ -0,0 +1,16 @@ +import { registerBlockType } from '@wordpress/blocks'; +import { InnerBlocks, useBlockProps } from '@wordpress/block-editor'; + +import edit from './edit'; +import metadata from './block.json'; + +/* @ts-expect-error Provided types are inaccurate to the actual plugin API. */ +registerBlockType(metadata, { + edit, + save: () => ( +
+ {/* @ts-ignore */} + +
+ ), +}); From a122cbc808afcb82c3b70ba55e964023aac5af1f Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 11 Oct 2023 12:00:09 -0500 Subject: [PATCH 2/4] adding more stuff from wp-curation --- blocks/condition/index.php | 16 +-- blocks/counter/block.json | 11 +++ blocks/counter/edit.tsx | 17 ++++ blocks/counter/index.php | 145 ++++++++++++++++++++++++++++ blocks/counter/index.scss | 7 ++ blocks/counter/index.ts | 9 ++ blocks/counter/style.scss | 10 ++ blocks/is-false/index.php | 10 +- blocks/is-true/index.php | 10 +- composer.json | 3 +- src/class-block.php | 68 +++++++++++++ src/interface-serialized-blocks.php | 20 ++++ 12 files changed, 307 insertions(+), 19 deletions(-) create mode 100644 blocks/counter/block.json create mode 100644 blocks/counter/edit.tsx create mode 100644 blocks/counter/index.php create mode 100644 blocks/counter/index.scss create mode 100644 blocks/counter/index.ts create mode 100644 blocks/counter/style.scss create mode 100644 src/class-block.php create mode 100644 src/interface-serialized-blocks.php diff --git a/blocks/condition/index.php b/blocks/condition/index.php index 38141b4..7c95fb0 100644 --- a/blocks/condition/index.php +++ b/blocks/condition/index.php @@ -8,8 +8,8 @@ * phpcs:disable Squiz.Commenting.FunctionComment.MissingParamName */ -use Alley\WP\WP_Curate\Global_Post_Query; -use Alley\WP\WP_Curate\Validator\Slug_Is_In_Category; +use Alley\WP\WP_Conditional_Blocks\Global_Post_Query; +use Alley\WP\WP_Conditional_Blocks\Validator\Slug_Is_In_Category; /** * Registers the block using the metadata loaded from the `block.json` file. @@ -18,7 +18,7 @@ * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ -function wp_curate_condition_block_init(): void { +function wp_conditional_blocks_condition_block_init(): void { // Register the block by passing the location of block.json. register_block_type( __DIR__, @@ -27,7 +27,7 @@ function wp_curate_condition_block_init(): void { ], ); } -add_action( 'init', 'wp_curate_condition_block_init' ); +add_action( 'init', 'wp_conditional_blocks_condition_block_init' ); /** * Evaluate the result of condition block attributes. @@ -44,7 +44,7 @@ function wp_curate_condition_block_init(): void { * @param array{'postId'?: int} $context Available context. * @return bool */ -function wp_curate_condition_block_result( array $parsed_block, array $context ): bool { +function wp_conditional_blocks_condition_block_result( array $parsed_block, array $context ): bool { global $wp_query; $num_conditions = 0; @@ -130,7 +130,7 @@ function wp_curate_condition_block_result( array $parsed_block, array $context ) } if ( count( $validator ) > 0 ) { - if ( $validator->isValid( wp_curate_current_counter_block() ) ) { + if ( $validator->isValid( wp_conditional_blocks_current_counter_block() ) ) { $num_true++; } } @@ -161,7 +161,7 @@ function wp_curate_condition_block_result( array $parsed_block, array $context ) * @param mixed $condition Condition name. * @param int $post_id Post ID. */ - if ( true === apply_filters( 'wp_curate_condition_block_post_condition', false, $condition, $context['postId'] ) ) { + if ( true === apply_filters( 'wp_conditional_blocks_condition_block_post_condition', false, $condition, $context['postId'] ) ) { $num_true++; } } @@ -188,7 +188,7 @@ function wp_curate_condition_block_result( array $parsed_block, array $context ) * @param array $context Available context. * @param WP_Query $wp_query Global query object. */ - $result = apply_filters( "wp_curate_condition_block_{$name}_condition", false, $context, $wp_query ); + $result = apply_filters( "wp_conditional_blocks_condition_block_{$name}_condition", false, $context, $wp_query ); if ( true === $result ) { $num_true++; diff --git a/blocks/counter/block.json b/blocks/counter/block.json new file mode 100644 index 0000000..dc7d874 --- /dev/null +++ b/blocks/counter/block.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 2, + "name": "wp-conditional-blocks/counter", + "version": "0.1.0", + "title": "Counter", + "category": "theme", + "icon": "editor-ol", + "description": "Count template iterations", + "textdomain": "wp-conditional-blocks" +} diff --git a/blocks/counter/edit.tsx b/blocks/counter/edit.tsx new file mode 100644 index 0000000..69e2d51 --- /dev/null +++ b/blocks/counter/edit.tsx @@ -0,0 +1,17 @@ +import { __ } from '@wordpress/i18n'; +import { useBlockProps } from '@wordpress/block-editor'; + +import './index.scss'; + +/** + * The wp-conditional-blocks/counter block edit function. + * + * @return {WPElement} Element to render. + */ +export default function Edit() { + return ( +

+ { __('Block Title - hello from the editor!') } +

+ ); +} diff --git a/blocks/counter/index.php b/blocks/counter/index.php new file mode 100644 index 0000000..df12274 --- /dev/null +++ b/blocks/counter/index.php @@ -0,0 +1,145 @@ + 'wp_conditional_blocks_render_counter_block', + ], + ); +} +add_action( 'init', 'wp_conditional_blocks_counter_block_init' ); + +/** + * Inject a counter block into the post template block being rendered. + * + * @param array{ + * blockName?: string, + * innerBlocks?: mixed[], + * innerContent?: mixed[], + * } $parsed_block The block being rendered. + * @return array{ + * blockName?: string, + * innerBlocks?: mixed[], + * innerContent?: mixed[], + * } + */ +function wp_conditional_blocks_inject_counter_block( array $parsed_block ): array { + global $wp_conditional_blocks_template_stack; + + if ( isset( $parsed_block['blockName'] ) && 'core/post-template' === $parsed_block['blockName'] ) { + $wp_conditional_blocks_template_stack[] = -1; + + if ( ! isset( $parsed_block['innerBlocks'] ) || ! is_array( $parsed_block['innerBlocks'] ) ) { // @phpstan-ignore-line + $parsed_block['innerBlocks'] = []; + } + + array_unshift( + $parsed_block['innerBlocks'], + Block::create( 'wp-conditional-blocks/counter' )->parsed_block(), + ); + + if ( ! isset( $parsed_block['innerContent'] ) || ! is_array( $parsed_block['innerContent'] ) ) { // @phpstan-ignore-line + $parsed_block['innerContent'] = []; + } + + array_unshift( $parsed_block['innerContent'], null ); + } + + return $parsed_block; +} +add_filter( 'render_block_data', 'wp_conditional_blocks_inject_counter_block', 100 ); + +/** + * When the counter block renders, increase the count of the current template's iterations. + * + * @param array $attributes Block attributes. + * @param string $content Block default content. + * @param WP_Block $block Block instance. + * @return string Block output. + */ +function wp_conditional_blocks_render_counter_block( $attributes, $content, $block ): string { + global $wp_conditional_blocks_template_stack; + + if ( is_array( $wp_conditional_blocks_template_stack ) && count( $wp_conditional_blocks_template_stack ) > 0 ) { + $last = array_pop( $wp_conditional_blocks_template_stack ); + $wp_conditional_blocks_template_stack[] = $last + 1; + } + + return $content; +} + +/** + * Current iteration of the current template block. + * + * @return int + */ +function wp_conditional_blocks_current_counter_block(): int { + global $wp_conditional_blocks_template_stack; + + $current = -1; + + if ( is_array( $wp_conditional_blocks_template_stack ) && count( $wp_conditional_blocks_template_stack ) > 0 ) { + $key = array_key_last( $wp_conditional_blocks_template_stack ); + $current = $wp_conditional_blocks_template_stack[ $key ]; + } + + return $current; +} + +/** + * Remove the last iteration count from the top of the stack after the template block renders. + * + * @param string $block_content The block content. + * @param array{ + * name: string, + * attrs: array, + * innerBlocks: array, + * innerHTML: string, + * innerContent: array, + * } $block The full block, including name and attributes. + */ +function wp_conditional_blocks_after_counter_block( $block_content, $block ): void { + global $wp_conditional_blocks_template_stack; + + if ( is_array( $wp_conditional_blocks_template_stack ) && count( $wp_conditional_blocks_template_stack ) > 0 ) { + $inner_counter = match_block( + $block, + [ + 'name' => 'wp-conditional-blocks/counter', + 'flatten' => false, + ], + ); + + // Pop only if there was a counter in this template. + if ( null !== $inner_counter ) { + array_pop( $wp_conditional_blocks_template_stack ); + } + } +} +add_filter_side_effect( 'render_block_core/post-template', 'wp_conditional_blocks_after_counter_block', 10, 2 ); diff --git a/blocks/counter/index.scss b/blocks/counter/index.scss new file mode 100644 index 0000000..43f39b1 --- /dev/null +++ b/blocks/counter/index.scss @@ -0,0 +1,7 @@ +/** + * Editor styles for the wp-conditional-blocks/counter block. + */ + +.wp-block-wp-conditional-blocks-counter { + border: 1px dotted #f00; +} diff --git a/blocks/counter/index.ts b/blocks/counter/index.ts new file mode 100644 index 0000000..bb6869a --- /dev/null +++ b/blocks/counter/index.ts @@ -0,0 +1,9 @@ +import { registerBlockType } from '@wordpress/blocks'; + +import edit from './edit'; +import metadata from './block.json'; + +import './style.scss'; + +/* @ts-expect-error Provided types are inaccurate to the actual plugin API. */ +registerBlockType(metadata, { edit }); diff --git a/blocks/counter/style.scss b/blocks/counter/style.scss new file mode 100644 index 0000000..87639bb --- /dev/null +++ b/blocks/counter/style.scss @@ -0,0 +1,10 @@ +/** + * Styles for the wp-conditional-blocks/counter block that get applied on both on the front of your site + * and in the editor. + */ + +.wp-block-wp-conditional-blocks-counter { + background-color: #21759b; + color: #fff; + padding: 2px; +} diff --git a/blocks/is-false/index.php b/blocks/is-false/index.php index 72132ba..5aff1fb 100644 --- a/blocks/is-false/index.php +++ b/blocks/is-false/index.php @@ -12,7 +12,7 @@ * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ -function wp_curate_is_false_block_init(): void { +function wp_conditional_blocks_is_false_block_init(): void { // Register the block by passing the location of block.json. register_block_type( __DIR__, @@ -21,7 +21,7 @@ function wp_curate_is_false_block_init(): void { ], ); } -add_action( 'init', 'wp_curate_is_false_block_init' ); +add_action( 'init', 'wp_conditional_blocks_is_false_block_init' ); /** * Short-circuit the display of blocks inside if the outer condition isn't false. @@ -30,7 +30,7 @@ function wp_curate_is_false_block_init(): void { * @param WP_Block $parsed_block The block being rendered. * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block. */ -function wp_curate_pre_render_is_false_block( $pre_render, $parsed_block, $parent_block ): string|null { +function wp_conditional_blocks_pre_render_is_false_block( $pre_render, $parsed_block, $parent_block ): string|null { /* * Previously, the condition block added 'conditionResult' as context to this block. However, * limitations in the context API meant that the context didn't get passed to child blocks when @@ -50,7 +50,7 @@ function wp_curate_pre_render_is_false_block( $pre_render, $parsed_block, $paren $context['postId'] = $parent_block->context['postId']; } - $result = wp_curate_condition_block_result( $parent_block->parsed_block, $context ); + $result = wp_conditional_blocks_condition_block_result( $parent_block->parsed_block, $context ); if ( false !== $result ) { $pre_render = ''; @@ -59,4 +59,4 @@ function wp_curate_pre_render_is_false_block( $pre_render, $parsed_block, $paren return $pre_render; } -add_filter( 'pre_render_block', 'wp_curate_pre_render_is_false_block', 10, 3 ); +add_filter( 'pre_render_block', 'wp_conditional_blocks_pre_render_is_false_block', 10, 3 ); diff --git a/blocks/is-true/index.php b/blocks/is-true/index.php index 452d4e9..ef3847f 100644 --- a/blocks/is-true/index.php +++ b/blocks/is-true/index.php @@ -12,7 +12,7 @@ * * @see https://developer.wordpress.org/reference/functions/register_block_type/ */ -function wp_curate_is_true_block_init(): void { +function wp_conditional_blocks_is_true_block_init(): void { // Register the block by passing the location of block.json. register_block_type( __DIR__, @@ -21,7 +21,7 @@ function wp_curate_is_true_block_init(): void { ], ); } -add_action( 'init', 'wp_curate_is_true_block_init' ); +add_action( 'init', 'wp_conditional_blocks_is_true_block_init' ); /** * Short-circuit the display of blocks inside if the outer condition isn't true. @@ -30,7 +30,7 @@ function wp_curate_is_true_block_init(): void { * @param WP_Block $parsed_block The block being rendered. * @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block. */ -function wp_curate_pre_render_is_true_block( $pre_render, $parsed_block, $parent_block ): string|null { +function wp_conditional_blocks_pre_render_is_true_block( $pre_render, $parsed_block, $parent_block ): string|null { /* * Previously, the condition block added 'conditionResult' as context to this block. However, * limitations in the context API meant that the context didn't get passed to child blocks when @@ -50,7 +50,7 @@ function wp_curate_pre_render_is_true_block( $pre_render, $parsed_block, $parent $context['postId'] = $parent_block->context['postId']; } - $result = wp_curate_condition_block_result( $parent_block->parsed_block, $context ); + $result = wp_conditional_blocks_condition_block_result( $parent_block->parsed_block, $context ); if ( true !== $result ) { $pre_render = ''; @@ -59,4 +59,4 @@ function wp_curate_pre_render_is_true_block( $pre_render, $parsed_block, $parent return $pre_render; } -add_filter( 'pre_render_block', 'wp_curate_pre_render_is_true_block', 10, 3 ); +add_filter( 'pre_render_block', 'wp_conditional_blocks_pre_render_is_true_block', 10, 3 ); diff --git a/composer.json b/composer.json index a44aaf3..c9609b2 100644 --- a/composer.json +++ b/composer.json @@ -16,7 +16,8 @@ ], "require": { "php": "^8.0", - "alleyinteractive/composer-wordpress-autoloader": "^1.0" + "alleyinteractive/composer-wordpress-autoloader": "^1.0", + "alleyinteractive/wp-match-blocks": "^3.0" }, "require-dev": { "alleyinteractive/alley-coding-standards": "^2.0", diff --git a/src/class-block.php b/src/class-block.php new file mode 100644 index 0000000..5423646 --- /dev/null +++ b/src/class-block.php @@ -0,0 +1,68 @@ + $attrs Block attributes. + * @param string $inner_html Block inner HTML. + */ + private function __construct( + private readonly string $block_name, + private readonly array $attrs, + private readonly string $inner_html, + ) {} + + /** + * Create instance from a name or more. + * + * @param string $name Block name. + * @param array $attrs Block attributes. + * @param string $html Block inner HTML. + * @return self + */ + public static function create( string $name, array $attrs = [], string $html = '' ): self { + return new self( $name, $attrs, $html ); + } + + /** + * Parsed block instance. + * + * @return array{ + * blockName: string, + * attrs: array, + * innerBlocks?: mixed[], + * innerHTML?: string, + * innerContent?: string[], + * } + */ + public function parsed_block(): array { + return [ + 'blockName' => $this->block_name, + 'attrs' => $this->attrs, + 'innerBlocks' => [], + 'innerHTML' => $this->inner_html, + 'innerContent' => [ $this->inner_html ], + ]; + } + + /** + * Serialized block content. + * + * @return string + */ + public function serialize(): string { + return serialize_block( $this->parsed_block() ); + } +} diff --git a/src/interface-serialized-blocks.php b/src/interface-serialized-blocks.php new file mode 100644 index 0000000..78d2b7c --- /dev/null +++ b/src/interface-serialized-blocks.php @@ -0,0 +1,20 @@ + Date: Wed, 11 Oct 2023 13:01:33 -0500 Subject: [PATCH 3/4] phpcs --- blocks/counter/index.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/blocks/counter/index.php b/blocks/counter/index.php index df12274..4bb6d85 100644 --- a/blocks/counter/index.php +++ b/blocks/counter/index.php @@ -80,14 +80,13 @@ function wp_conditional_blocks_inject_counter_block( array $parsed_block ): arra * * @param array $attributes Block attributes. * @param string $content Block default content. - * @param WP_Block $block Block instance. * @return string Block output. */ -function wp_conditional_blocks_render_counter_block( $attributes, $content, $block ): string { +function wp_conditional_blocks_render_counter_block( $attributes, $content ): string { global $wp_conditional_blocks_template_stack; if ( is_array( $wp_conditional_blocks_template_stack ) && count( $wp_conditional_blocks_template_stack ) > 0 ) { - $last = array_pop( $wp_conditional_blocks_template_stack ); + $last = array_pop( $wp_conditional_blocks_template_stack ); $wp_conditional_blocks_template_stack[] = $last + 1; } From c52c8c9f53b5e5aa6672619463494ea9b301508a Mon Sep 17 00:00:00 2001 From: Greg Marshall Date: Wed, 11 Oct 2023 13:13:47 -0500 Subject: [PATCH 4/4] linting --- blocks/condition/edit.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/blocks/condition/edit.tsx b/blocks/condition/edit.tsx index 8676ffa..e6e51a9 100644 --- a/blocks/condition/edit.tsx +++ b/blocks/condition/edit.tsx @@ -46,11 +46,14 @@ export default function Edit({ + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} - + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} { parentBlock === 'wp-conditional-blocks/query' ? ( + /* @ts-ignore-next-line */

{__('Checks the index of how many times the parent condition block has been rendered, ie "Equal to 0", "Greater than 5"', 'wp-conditional-blocks')}

+ {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} + {/* @ts-ignore-next-line */} setAttributes({ index: { [operator]: next } })}