You’ve seen how you can inherit, consume, and replace functionality in an Interactivity API store. Now we get to the final lesson, you can also do the same with Context and State.
This tutorial will not delve into the differences between Context and State. Context will be referred to as “local state.” State will be referred to as “global state.” This is to make it easier to understand the relationships at play.
Context (Local State) Inheritance
Let’s say we have a parent block that has a standard default button text in it’s context, like so:
<div data-wp-interactive="prc-quiz/controller" data-wp-context="<?php echo wp_json_encode( array(
'buttonText' => 'Submit',
) ); ?>">
<button data-wp-on--click="onSubmit" data-wp-text="context.buttonText"></div>
</div>
This will, of course, set the button’s text therein to be “Submit”. Easy. Now let’s imagine some additional blocks inside this block that also have buttons.
<div data-wp-interactive="prc-quiz/controller" data-wp-context="<?php echo wp_json_encode( array(
'buttonText' => 'Submit',
) ); ?>">
<button data-wp-on--click="actions.onButtonClick" data-wp-text="context.buttonText"></div>
<div class="some-other-block" data-wp-context="<?php echo wp_json_encode( array(
'buttonText' => 'Go back',
) ); ?>">
<button data-wp-on--click="actions.onButtonClick" data-wp-text="context.buttonText"></button>
</div>
</div>
Now the additional button uses the same action from the store. However, the child block using the button provides its own button text. The parent’s button text is not affected.
State (Global State) Inheritance
Unlike Context, State is global; meaning a change here effects all consumers of the iAPI state. So you could imagine a dynamic state getter like so:
const { state, actions } = store('prc-quiz/controller', {
state: {
get items() {
// Do something to get items...
return [];
}
}
});
If a child block also adds a state.items function it will REPLACE what is in the global state.
However, when using global state on the server things get more extensible. By using wp_interactivity_state we can get, replace, or add to state before anything is even rendered client side. Let’s take a look at an example. Imagine a series of answers in a quiz. We want to dynamically add unique IDs for each answer. We also need to make sure that the ID is not already used.
// Get the current state.
$state = wp_interactivity_state( 'prc-quiz/controller', array() );
// Create a new ID.
$id = 'item-a';
// Check if the ID exists in the state.
if ( isset( $state[ $id ] ) ) {
// The ID exists in the state.
// Generate a new ID.
$id = 'item-b';
}
$state[ $id ] = array(
'title' => 'Item ' . $id,
);
// Update the state.
wp_interactivity_state( 'prc-quiz/controller', $state );
Bonus: Using WP_HTML_Tag_Processor with Context
Going one step further, you can interact with local state, or Context, in the same manner on the server. This is done before rendering to the client. You achieve this all by utilizing the WP_HTML_Tag_Processor.
$tag = new WP_HTML_Tag_Processor( $block_markup );
$existing_context = $tag->get_attribute( 'data-wp-context' );
while ( $tag->next_tag(
array(
'class_name' => 'my-targeted-element-classname',
)
) ) {
if ( $existing_context ) {
$new_context = wp_json_encode( array(
'oldValue' => 'new value',
) );
$tag->set_attribute( 'data-wp-context', $new_context );
}
}