From ae96143ac825b079cd9a2b8836b798914e74147c Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sun, 14 Apr 2024 20:34:17 +0200 Subject: [PATCH 1/3] Bits: Introduce the ability to store and render bits --- src/wp-includes/blocks.php | 2 + src/wp-includes/html-api/class-wp-bits.php | 77 ++++++++++++++++++++++ src/wp-settings.php | 1 + 3 files changed, 80 insertions(+) create mode 100644 src/wp-includes/html-api/class-wp-bits.php diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index decc4896c378a..032e08ffc7502 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -2057,6 +2057,8 @@ function render_block( $parsed_block ) { * } */ function parse_blocks( $content ) { + $content = wp_replace_bits( $content ); + /** * Filter to allow plugins to replace the server-side block parser. * diff --git a/src/wp-includes/html-api/class-wp-bits.php b/src/wp-includes/html-api/class-wp-bits.php new file mode 100644 index 0000000000000..a7652bf64da1c --- /dev/null +++ b/src/wp-includes/html-api/class-wp-bits.php @@ -0,0 +1,77 @@ +set_bookmark( 'here' ); + $here = $this->bookmarks['here']; + + $this->deferred_updates[] = new WP_HTML_Text_Replacement( + $here->start, + $here->length, + $new_content + ); + } + + public function flush_updates() { + foreach ( $this->deferred_updates as $update ) { + $this->lexical_updates[] = $update; + } + } + }; + + while ( $processor->next_token() ) { + switch ( $processor->get_token_type() ) { + case '#funky-comment': + $processor->replace_token( 'blarg' ); + break; + + case '#tag': + foreach ( $processor->get_attribute_names_with_prefix( '' ) ?? [] as $name ) { + $value = $processor->get_attribute( $name ); + if ( is_string( $value ) ) { + $new_value = preg_replace_callback( + '~]+)>~', + static function ( $bit ) { + return 'blarg'; + }, + $value + ); + + if ( $new_value !== $value ) { + $processor->set_attribute( $name, $new_value ); + } + } + } + break; + + case '#comment': + if ( WP_HTML_Tag_Processor::COMMENT_AS_HTML_COMMENT !== $processor->get_comment_type() ) { + break; + } + + $text = $processor->get_modifiable_text(); + if ( 1 === preg_match( '~^]+)>$~', $text ) ) { + $processor->replace_token( 'Blarg!' ); + break; + } + + $new_value = preg_replace_callback( + '~]+)>~', + static function ( $bit ) { + return 'blarg'; + }, + $text + ); + + $processor->replace_token( "" ); + break; + } + } + $processor->flush_updates(); + $content = $processor->get_updated_html(); + + return $content; +} diff --git a/src/wp-settings.php b/src/wp-settings.php index a682c2a50380a..2e343f5d6ac06 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -262,6 +262,7 @@ require ABSPATH . WPINC . '/html-api/class-wp-html-stack-event.php'; require ABSPATH . WPINC . '/html-api/class-wp-html-processor-state.php'; require ABSPATH . WPINC . '/html-api/class-wp-html-processor.php'; +require ABSPATH . WPINC . '/html-api/class-wp-bits.php'; require ABSPATH . WPINC . '/class-wp-http.php'; require ABSPATH . WPINC . '/class-wp-http-streams.php'; require ABSPATH . WPINC . '/class-wp-http-curl.php'; From 667d6144a5680dd01a01de55b6d09e4ebeb97bf1 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Wed, 12 Jun 2024 13:06:21 +0200 Subject: [PATCH 2/3] Add Hello Dolly Bit --- src/wp-includes/bits.php | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 src/wp-includes/bits.php diff --git a/src/wp-includes/bits.php b/src/wp-includes/bits.php new file mode 100644 index 0000000000000..7e982c1addd97 --- /dev/null +++ b/src/wp-includes/bits.php @@ -0,0 +1,50 @@ +` produces `array( 'year' => '2024' )`. + * @param mixed $context Context passed into the Bit from the surrounding system. + * This argument is not yet specified and will always be `null`. + * + * @return mixed An HTML template for rendering into the page, either as a plain string or in array form. + */ +function core_bit_hello_dolly( string $name, string $output_type, ?array $attributes, mixed $context ): mixed { + static $vocalists = array( + 'Julie Dahle Aagård', + 'Mindi Abair', + 'Lorez Alexandria', + 'Karrin Allyson', + 'Michelle Amato', + 'Ernestine Anderson', + 'Ivie Anderson', + ); + + $vocalist = $vocalists[ wp_rand( 0, count( $vocalists ) - 1 ) ]; + + switch ( $output_type ) { + case 'plaintext': + return $vocalist; + + case 'rich-text': + return array( + '', + array( 'name' => $vocalist ), + ); + } +} + From 0993cc192b4d9c0e91f8c1f5283d21af6fc35e66 Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Sat, 15 Jun 2024 17:36:40 +0200 Subject: [PATCH 3/3] Explore different ways of providing Bit renderers. --- src/wp-includes/bits.php | 75 +++++++++++++++++++ .../html-api/class-wp-html-template.php | 48 ++++++++++++ src/wp-settings.php | 1 + 3 files changed, 124 insertions(+) create mode 100644 src/wp-includes/html-api/class-wp-html-template.php diff --git a/src/wp-includes/bits.php b/src/wp-includes/bits.php index 7e982c1addd97..a4edd2dea0dc1 100644 --- a/src/wp-includes/bits.php +++ b/src/wp-includes/bits.php @@ -8,6 +8,8 @@ * @since {WP_VERSION} */ +declare( strict_types=1 ); + /** * Hello Dolly Bit Rendering function. * @@ -48,3 +50,76 @@ function core_bit_hello_dolly( string $name, string $output_type, ?array $attrib } } +class WP_Hello_Dolly_Bit extends BitProvider { + /** + * @inheritDoc + */ + public function handle_plaintext( string $bit_name, ?array $attributes ): string { + return self::get_random_vocalist(); + } + + /** + * @inheritDoc + */ + public function handle_richtext( string $bit_name, ?array $attributes ): WP_HTML_Template { + $name = self::get_random_vocalist(); + + return new WP_HTML_Template( + '', + array( 'name' => $name ) + ); + } + + /** + * Returns the name of a random Jazz vocalist. + * + * @return string + */ + private function get_random_vocalist(): string { + static $vocalists = array( + 'Julie Dahle Aagård', + 'Mindi Abair', + 'Lorez Alexandria', + 'Karrin Allyson', + 'Michelle Amato', + 'Ernestine Anderson', + 'Ivie Anderson', + ); + + return $vocalists[ wp_rand( 0, count( $vocalists ) - 1 ) ]; + } +} + +abstract class BitProvider { + /** + * Performs initialize of Bit Provider during WordPress bootup. + */ + public function register(): void { + // This is optional. + }; + + /** + * Called to source content in plaintext contexts. For example, when a + * Bit is found within an HTML attribute, or inside a `TITLE` element. + * + * @see WP_HTML_Template + * + * @param string $bit_name Full name with namespace of matched Bit, e.g. "core/post-author". + * @param array|null $attributes Configured attributes found on Bit, if found, otherwise `null`. + * + * @return string Plaintext value for provided content. + */ + abstract public function handle_plaintext( string $bit_name, ?array $attributes ): string; + + /** + * Called to source content in Rich Text (HTML Markup) contexts. For example, + * when a Bit is found within the inner content of an HTML tag. + * + * @see WP_HTML_Template + * + * @param string $bit_name Full name with namespace of matched Bit, e.g. "core/post-author". + * @param array|null $attributes Configured attributes found on Bit, if found, otherwise `null`. + * @return WP_HTML_Template HTML template for provided content: a string or array. + */ + abstract public function handle_richtext( string $bit_name, ?array $attributes ): WP_HTML_Template; +} diff --git a/src/wp-includes/html-api/class-wp-html-template.php b/src/wp-includes/html-api/class-wp-html-template.php new file mode 100644 index 0000000000000..f181478e41e63 --- /dev/null +++ b/src/wp-includes/html-api/class-wp-html-template.php @@ -0,0 +1,48 @@ +Hello, World!

' ); + * + * // Placeholders for simple substitution. + * new WP_HTML_Template( '

Hello, !

', array( 'name' => $name ) ); + * + * // Spread-operator for sets of attributes. + * new WP_HTML_Template( + * '', + * array( + * 'data-wp-text="context.buttonLabel"', + * 'data-wp-click="actions.clickButton", + * ) + * ); + * + * @param string $template Static HTML template, possibly including placeholders. + * @param array|null $data Optional. Data provided for placeholders, if any. + */ + public function __construct( string $template, array $data = null ) { + $this->template = $template; + $this->data = $data; + } +} diff --git a/src/wp-settings.php b/src/wp-settings.php index 2e343f5d6ac06..2071922cd2da0 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -262,6 +262,7 @@ require ABSPATH . WPINC . '/html-api/class-wp-html-stack-event.php'; require ABSPATH . WPINC . '/html-api/class-wp-html-processor-state.php'; require ABSPATH . WPINC . '/html-api/class-wp-html-processor.php'; +require ABSPATH . WPINC . '/html-api/class-wp-html-template.php'; require ABSPATH . WPINC . '/html-api/class-wp-bits.php'; require ABSPATH . WPINC . '/class-wp-http.php'; require ABSPATH . WPINC . '/class-wp-http-streams.php';