From e978cba1e5cf6395e1ca2ed113a574bc26936bf1 Mon Sep 17 00:00:00 2001 From: gziolo Date: Tue, 4 Jun 2024 07:18:17 +0000 Subject: [PATCH] Interactivity API: Print debug warning when server directives processing encounters errors Aims to improve the developer experience of the Interactivity API server directives processing. Props cbravobernal, jonsurrell, westonruter, darerodz, czapla, gziolo. Fixes #61044. Built from https://develop.svn.wordpress.org/trunk@58321 git-svn-id: http://core.svn.wordpress.org/trunk@57778 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- ...interactivity-api-directives-processor.php | 21 ++++++++------ .../class-wp-interactivity-api.php | 28 +++++++++++++++---- wp-includes/version.php | 2 +- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php b/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php index b12dcb4b3b..590cf967cf 100644 --- a/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php +++ b/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php @@ -198,16 +198,19 @@ final class WP_Interactivity_API_Directives_Processor extends WP_HTML_Tag_Proces public function skip_to_tag_closer(): bool { $depth = 1; $tag_name = $this->get_tag(); - while ( $depth > 0 && $this->next_tag( - array( - 'tag_name' => $tag_name, - 'tag_closers' => 'visit', - ) - ) ) { - if ( $this->has_self_closing_flag() ) { - continue; + + while ( $depth > 0 && $this->next_tag( array( 'tag_closers' => 'visit' ) ) ) { + if ( ! $this->is_tag_closer() && $this->get_attribute_names_with_prefix( 'data-wp-' ) ) { + /* translators: 1: SVG or MATH HTML tag. */ + $message = sprintf( __( 'Interactivity directives were detected inside an incompatible %1$s tag. These directives will be ignored in the server side render.' ), $tag_name ); + _doing_it_wrong( __METHOD__, $message, '6.6.0' ); + } + if ( $this->get_tag() === $tag_name ) { + if ( $this->has_self_closing_flag() ) { + continue; + } + $depth += $this->is_tag_closer() ? -1 : 1; } - $depth += $this->is_tag_closer() ? -1 : 1; } return 0 === $depth; diff --git a/wp-includes/interactivity-api/class-wp-interactivity-api.php b/wp-includes/interactivity-api/class-wp-interactivity-api.php index 23675a9683..77abe19244 100644 --- a/wp-includes/interactivity-api/class-wp-interactivity-api.php +++ b/wp-includes/interactivity-api/class-wp-interactivity-api.php @@ -272,6 +272,7 @@ final class WP_Interactivity_API { * it returns null if the HTML contains unbalanced tags. * * @since 6.5.0 + * @since 6.6.0 The function displays a warning message when the HTML contains unbalanced tags or a directive appears in a MATH or SVG tag. * * @param string $html The HTML content to process. * @param array $context_stack The reference to the array used to keep track of contexts during processing. @@ -295,6 +296,11 @@ final class WP_Interactivity_API { * We still process the rest of the HTML. */ if ( 'SVG' === $tag_name || 'MATH' === $tag_name ) { + if ( $p->get_attribute_names_with_prefix( 'data-wp-' ) ) { + /* translators: 1: SVG or MATH HTML tag, 2: Namespace of the interactive block. */ + $message = sprintf( __( 'Interactivity directives were detected on an incompatible %1$s tag when processing "%2$s". These directives will be ignored in the server side render.' ), $tag_name, end( $namespace_stack ) ); + _doing_it_wrong( __METHOD__, $message, '6.6.0' ); + } $p->skip_to_tag_closer(); continue; } @@ -382,13 +388,21 @@ final class WP_Interactivity_API { } } } - /* * It returns null if the HTML is unbalanced because unbalanced HTML is * not safe to process. In that case, the Interactivity API runtime will - * update the HTML on the client side during the hydration. + * update the HTML on the client side during the hydration. It will also + * display a notice to the developer to inform them about the issue. */ - return $unbalanced || 0 < count( $tag_stack ) ? null : $p->get_updated_html(); + if ( $unbalanced || 0 < count( $tag_stack ) ) { + $tag_errored = 0 < count( $tag_stack ) ? end( $tag_stack )[0] : $tag_name; + /* translators: %1s: Namespace processed, %2s: The tag that caused the error; could be any HTML tag. */ + $message = sprintf( __( 'Interactivity directives failed to process in "%1$s" due to a missing "%2$s" end tag.' ), end( $namespace_stack ), $tag_errored ); + _doing_it_wrong( __METHOD__, $message, '6.6.0' ); + return null; + } + + return $p->get_updated_html(); } /** @@ -396,17 +410,21 @@ final class WP_Interactivity_API { * store namespace, state and context. * * @since 6.5.0 + * @since 6.6.0 The function now adds a warning when the namespace is null, falsy, or the directive value is empty. * * @param string|true $directive_value The directive attribute value string or `true` when it's a boolean attribute. * @param string $default_namespace The default namespace to use if none is explicitly defined in the directive * value. * @param array|false $context The current context for evaluating the directive or false if there is no * context. - * @return mixed|null The result of the evaluation. Null if the reference path doesn't exist. + * @return mixed|null The result of the evaluation. Null if the reference path doesn't exist or the namespace is falsy. */ private function evaluate( $directive_value, string $default_namespace, $context = false ) { list( $ns, $path ) = $this->extract_directive_value( $directive_value, $default_namespace ); - if ( empty( $path ) ) { + if ( ! $ns || ! $path ) { + /* translators: %s: The directive value referenced. */ + $message = sprintf( __( 'Namespace or reference path cannot be empty. Directive value referenced: %s' ), $directive_value ); + _doing_it_wrong( __METHOD__, $message, '6.6.0' ); return null; } diff --git a/wp-includes/version.php b/wp-includes/version.php index 07673682a0..0eab75c5c5 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.6-alpha-58320'; +$wp_version = '6.6-alpha-58321'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.