From 3f571c01b5e42a907ec527bb40f15847d297ac49 Mon Sep 17 00:00:00 2001 From: David Arenas Date: Fri, 24 May 2024 18:13:09 +0200 Subject: [PATCH] Catch throwables when evaluating state callbacks --- .../class-wp-interactivity-api.php | 16 ++++++++++++- .../interactivity-api/wpInteractivityAPI.php | 23 ++++++++++++++++--- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/interactivity-api/class-wp-interactivity-api.php b/src/wp-includes/interactivity-api/class-wp-interactivity-api.php index 42a219342eda8..eabb4cc563f57 100644 --- a/src/wp-includes/interactivity-api/class-wp-interactivity-api.php +++ b/src/wp-includes/interactivity-api/class-wp-interactivity-api.php @@ -485,7 +485,21 @@ private function evaluate( $directive_value ) { } if ( $current instanceof Closure ) { - $current = $current(); + try { + $current = $current(); + } catch ( Throwable $e ) { + _doing_it_wrong( + __METHOD__, + sprintf( + /* translators: 1: Path pointing to an Interactivity API state property, 2: Namespace for an Interactivity API store. */ + __( 'Uncaught error executing a derived state callback with path "%1$s" and namespace "%2$s".' ), + $path, + $ns + ), + '6.6.0' + ); + return null; + } } // Returns the opposite if it contains a negation operator (!). diff --git a/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php index 8a8ab79225a53..b0aef950bcf0b 100644 --- a/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php +++ b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php @@ -994,9 +994,9 @@ public function test_process_directives_does_not_change_inner_html_in_math() { private function evaluate( $directive_value ) { $generate_state = function ( $name ) { return array( - 'key' => $name, - 'nested' => array( 'key' => $name . '-nested' ), - 'derived' => function () { + 'key' => $name, + 'nested' => array( 'key' => $name . '-nested' ), + 'derived' => function () { $state = wp_interactivity_state(); $context = wp_interactivity_get_context(); return 'Derived state: ' . @@ -1005,6 +1005,9 @@ private function evaluate( $directive_value ) { 'Derived context: ' . $context['key']; }, + 'derivedThatThrows' => function () { + throw new Error( 'Something bad happened.' ); + }, ); }; $this->interactivity->state( 'myPlugin', $generate_state( 'myPlugin-state' ) ); @@ -1142,6 +1145,20 @@ public function test_evaluate_derived_state() { $this->assertEquals( "Derived state: myPlugin-state\nDerived context: myPlugin-context", $result ); } + + /** + * Tests the `evaluate` method for derived state functions. + * + * @ticket 61037 + * + * @covers ::evaluate + * @expectedIncorrectUsage WP_Interactivity_API::evaluate + */ + public function test_evaluate_derived_state_that_throws() { + $result = $this->evaluate( 'state.derivedThatThrows' ); + $this->assertEquals( null, $result ); + } + /** * Tests the `kebab_to_camel_case` method. *