WP_Interactivity_API::evaluate()privateWP 6.5.0

Evaluates the reference path passed to a directive based on the current store namespace, state and context.

Method of the class: WP_Interactivity_API{}

No Hooks.

Returns

Mixed|null. The result of the evaluation. Null if the reference path doesn't exist or the namespace is falsy.

Usage

// private - for code of main (parent) class only
$result = $this->evaluate( $directive_value );
$directive_value(string|true) (required)
The directive attribute value string or true when it's a boolean attribute.

Changelog

Since 6.5.0 Introduced.
Since 6.6.0 The function now adds a warning when the namespace is null, falsy, or the directive value is empty.
Since 6.6.0 Removed default_namespace and context arguments.
Since 6.6.0 Add support for derived state.

WP_Interactivity_API::evaluate() code WP 6.8.1

private function evaluate( $directive_value ) {
	$default_namespace = end( $this->namespace_stack );
	$context           = end( $this->context_stack );

	list( $ns, $path ) = $this->extract_directive_value( $directive_value, $default_namespace );
	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;
	}

	$store = array(
		'state'   => $this->state_data[ $ns ] ?? array(),
		'context' => $context[ $ns ] ?? array(),
	);

	// Checks if the reference path is preceded by a negation operator (!).
	$should_negate_value = '!' === $path[0];
	$path                = $should_negate_value ? substr( $path, 1 ) : $path;

	// Extracts the value from the store using the reference path.
	$path_segments = explode( '.', $path );
	$current       = $store;
	foreach ( $path_segments as $path_segment ) {
		/*
		 * Special case for numeric arrays and strings. Add length
		 * property mimicking JavaScript behavior.
		 *
		 * @since 6.8.0
		 */
		if ( 'length' === $path_segment ) {
			if ( is_array( $current ) && array_is_list( $current ) ) {
				$current = count( $current );
				break;
			}

			if ( is_string( $current ) ) {
				/*
				 * Differences in encoding between PHP strings and
				 * JavaScript mean that it's complicated to calculate
				 * the string length JavaScript would see from PHP.
				 * `strlen` is a reasonable approximation.
				 *
				 * Users that desire a more precise length likely have
				 * more precise needs than "bytelength" and should
				 * implement their own length calculation in derived
				 * state taking into account encoding and their desired
				 * output (codepoints, graphemes, bytes, etc.).
				 */
				$current = strlen( $current );
				break;
			}
		}

		if ( ( is_array( $current ) || $current instanceof ArrayAccess ) && isset( $current[ $path_segment ] ) ) {
			$current = $current[ $path_segment ];
		} elseif ( is_object( $current ) && isset( $current->$path_segment ) ) {
			$current = $current->$path_segment;
		} else {
			$current = null;
			break;
		}

		if ( $current instanceof Closure ) {
			/*
			 * This state getter's namespace is added to the stack so that
			 * `state()` or `get_config()` read that namespace when called
			 * without specifying one.
			 */
			array_push( $this->namespace_stack, $ns );
			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;
			} finally {
				// Remove the property's namespace from the stack.
				array_pop( $this->namespace_stack );
			}
		}
	}

	// Returns the opposite if it contains a negation operator (!).
	return $should_negate_value ? ! $current : $current;
}