Subscribe to changes in the Interactivity API state and context on client-side navigation in 6.7

Interactivity APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. offers a region-based navigation feature that dynamically replaces a part of the page without a full page reload. In fact, the Query blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. natively supports this feature when the “Force page reload” toggle is disabled. Developers can use the same functionality in custom blocks by calling action.navigate from the @wordpress/interactivity-router script module. In WordPress 6.7, several changes were introduced to improve the developer experience by making the behavior fully predictable.

During WordPress 6.7 development, we found an issue with the client-side navigation feature the @wordpress/interactivity-router provides: interactive blocks outside of interactive regions could be updated as a result of an actions.navigate call if they depended on state properties. The main problem was that the state properties were always overwritten with the values from the new HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers. page, leading to unexpected updates.

Moreover, the same issue affected blocks using the data-wp-context directive, making them work differently depending on whether they were placed inside a router region. In that case, the context was overwritten anytime the HTML was updated with an actions.navigate call.

As a result, this “overwrite behavior” was turned off for both the Interactivity API state and context. Calling actions.navigate will now only add new properties to the state or context and will never overwrite existing properties.

However, updating blocks based on state/context changes is still a legitimate use case. Since WordPress 6.7, a new API is available to subscribe to those changes, exposed from the @wordpress/interactivity module: getServerState() and getServerContext().

These functions return an object that is analogous to the state/context returned by store()/getContext(), with a couple of differences:

  • The object returned is read-only.
  • The object is updated after actions.navigate() calls, using the values defined in the HTML of the page loaded by actions.navigate().
  • Developers cannot directly use its properties in directives, but they can use callbacks to subscribe to changes in its properties and update the usual state/context.

The following example is incomplete but explains how to use the new API. Let’s say we want to develop an interactive Quiz block that updates the question on the screen every time the user submits the answer. Below is a simplified HTML snippet for such a block.

<form
  class="wp-block-quiz-question"
  data-wp-interactive="example/quiz"
  data-wp-router-region="quiz-question"
  data-wp-on--submit="actions.goToNextQuestion"
  data-wp-watch="callbacks.updateQuestion"
  data-wp-context='
    {
      "question": "What is the capital of France?",
      "answers": ["Paris", "London", "Rome", "Berlin"],
      "correctAnswer": 0,
      "nextQuestion": "/link-to-next-question"
    }
  '
>
  <fieldset>
    <legend data-wp-text="context.question"></legend>
    <template data-wp-each--answer="context.answers">
      <div>
        <input
          type="radio"
          data-wp-bind--id="context.answer"
          data-wp-bind--value="context.answer"
        />
        <label
          data-wp-bind--for="context.answer"
          data-wp-text="context.answer"
        ></label>
      </div>
    </template>
    <button type="submit">Submit</button>
  </fieldset>
</form>


As we can see, the <form> element contains the following directives:

  • data-wp-namespace, with value example/quiz.
  • data-wp-router-region, defining a region that should update on navigation.
  • data-wp-context, with all the data relative to a single question. On the HTML inside the <fieldset> element, we can see all the directives that depend on the context.
  • data-wp-on—submit, which assigns the actions.goToNextQuestion function to navigate to the next question.
  • data-wp-watch, with callbacks.updateQuestion to update the context. This one is important, as it will run every time any read properties inside change, including properties from getServerContext().

Next is a reduced implementation of these functions:

import {
  store,
  getContext,
  getServerContext,
} from "@wordpress/interactivity";

store("example/quiz", {
	actions: {
    *goToNextQuestion(event) {
      event.preventDefault();
      const { actions } =
        yield import("@wordpress/interactivity-router");
      yield actions.navigate(getContext().nextQuestion);
    },
  },
  callbacks: {
    updateQuestion() {
      const clientContext = getContext();
      const serverContext = getServerContext();
      clientContext.question = serverContext.question;
      clientContext.answers = serverContext.answers;
      clientContext.correctAnswer = serverContext.correctAnswer;
      clientContext.nextQuestion = serverContext.nextQuestion;
    },
  },
});


Now, imagine we click “submit” and navigate to the next question, and the Interactivity API runtime receives the HTML below. As we can see, the data-wp-context data has changed in the server. That will trigger the data-wp-watch directive using callbacks.updateQuestion, and the context will be updated in the client, making all the HTML inside <fieldset> to be modified accordingly.

<form
  class="wp-block-quiz-question"
  data-wp-interactive="example/quiz"
  data-wp-router-region="quiz-question"
  data-wp-on--submit="actions.goToNextQuestion"
  data-wp-watch="callbacks.updateQuestion"
  data-wp-context='
    {
      "question": "Which is the closest planet to the Sun?",
      "answers": ["Mercury", "Venus", "Earth", "Mars"],
      "correctAnswer": 0,
      "nextQuestion": "/link-to-another-question"
    }
  '
>
	<fieldset>
		<!-- The fieldset element's content remains the same. -->
	</fieldset>
</form>


In order not to extend too much, suffice it to say that the example would be similar for getServerState(), with the difference that the data is defined in the current page with the wp_interactivity_state() function in PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher, instead of the data-wp-context directive.

GitHubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged be the repository owner. https://github.com/ Pull Request: #65151

#6-7, #dev-notes, #dev-notes-6-7