Bridging the Customizer and the WP REST API

Authored by

Update 2017-01-03: This post and associated plugins have been updated for WordPress 4.7.

There’s a lot of excitement in the WordPress community about the WP REST API. We’ll be sending a couple representatives to the Day of REST conference coming up at the end of January, and I’ve been long-overdue to do a deep-dive in to the REST API: preparing for the conference is a great excuse. With a couple weeks off over the holidays, I took the opportunity to build something with the REST API. Naturally with the parallel excitement (and mandate) for JavaScript, I wanted to build something for WordPress’s single page application: the customizer. Inspired in part by Daniel Bachhuber’s A more RESTful WP-CLI project, I set out to make a more RESTful customizer and came up with the Customize REST Resources plugin.

A more RESTful WP-CLI seeks “unlock the potential of the WP REST API at the command line” in that “all WP REST API endpoints registered via plugins and themes will automagically be usable as WP-CLI commands”. In the same way, Customize REST Resources begins to unlock the potential of the WP REST API in the customizer by automatically creating settings and controls for all REST resources that are used on a given page. In this way, anything developed for the REST API should automatically be available in the customizer.

Customize REST Resources

The WP REST API provides a rich machine-readable interface for programmatically making changes to WordPress. The changes made, however, cannot be previewed. The customizer is WordPress’s framework for live previewing changes, and this can include changes made to REST resources. The REST endpoints provide a uniform abstraction layer on top of a diverse array of WordPress API calls. Implementing customizer settings for all of WordPress’s object types would require creating a new WP_Customize_Setting subclass for each type with unique implementations for the update, value, sanitize, and preview methods. With the REST API, however, we have a uniform input (request) and output (response) interface that a single customizer setting can be implemented to interact with. Each REST (non-collection) resource is represented by a customizer setting. Since each endpoint (should) provide a schema for describing what the resources at those endpoints look like, the customizer can read from this schema to sanitize and validate the REST resource prior to being sent along for update. Implementing preview for a REST resource involves filtering the REST server response. The rest_resource[$route] settings are simply the JSON strings. (Any any _embedded gets omitted and the REST resources must include a valid self URL among its _links to be registered as a setting.)

The Customize REST Resources plugin allows you to edit any REST resource that is loaded into the customizer preview via an Ajax request, such as via the core WP API Backbone JS client. (It intercepts Ajax requests via jQuery ajaxPrefilter and inspects responses via jQuery ajaxSuccess). All REST API requests made in the customizer will automatically get upgraded to use the edit context (if possible) so that all fields are available for manipulation. The moment a REST resource is fetched from the API, a corresponding control is added to a “REST Resources” panel in the customizer.

Customize REST Resources items added via Ajax

Expanding the customizer control reveals input fields that correspond to the properties in the REST resource, fields which are automatically created based off the schema for the given endpoint:

  • Boolean fields get represented as checkboxes.
  • Enumerated values get represented as select dropdowns.
  • Numbers, integers, URLs, and emails get represented as their appropriate HTML5 inputs.
  • Date-time fields ending with “_gmt” in their field ID will automatically be read-only if they have a corresponding non-GMT field. Any date-time fields can also be represented as calendar pickers, but this isn’t implemented yet.
  • JSON schema validation constraints (e.g. maximum, minimum, pattern) are added as their corresponding HTML5 input validation attributes.
  • Fields marked as read-only in the schema get presented as readonly inputs.
  • Object fields that contain a raw property get flattened so that this raw property is used as the field, and any modifications to this field get propagated into any corresponding rendered as well. (More on this below in Validation and Rendering.)
  • Other unknown objects get represented as textareas for manipulating the raw JSON string for that field.

The field IDs become the input labels and the field descriptions from the schema get added as tooltips for each input. The REST resource’s route is used as the control title, but this can easily be change to be more user friendly. The more richly defined the schema, the better the automatically-generated customizer control can be.

Customize REST Resources fields

Nevertheless, no matter how rich the schema is, there’s always going to be aspects of the control that need to be defined manually. Maybe some of this information can be exposed in the the schema, but rest_resource control extensions could provide additional refinements to the UI, such as:

  • List the fields in a more natural order, such as having the title and content fields appear at the top.
  • Use a TinyMCE editor or textarea as opposed to plain text inputs for strings.
  • Display a post selector instead of an integer number field.

Live Preview

When the WP API JS client is used, where REST resources get encapsulated in Backbone models, the plugin will opt-in the relevant REST resource setting for postMessage transport. Assuming that the Backbone JS app is developed in a way where the view will be re-rendered in response to model changes (as it should), when the customizer syncs a setting change for a REST resource into the preview, the model can likewise be updated when the setting is changed in the preview, resulting in a live preview of a JS application in the customizer without any full-page refresh or even a selective refresh (#27355). Implementing a postMessage sync of settings into non-Backbone models is also possible, as long as the model registers itself as an instance of a given REST resource setting and then sends along a rest-resource-setting-postmessage-transport-eligible message to the customizer pane.

Customize REST Resources postMessage update

Changesets

The Customize REST Resources plugin is closely related to the Customize Changesets feature in 4.7 in that Ajax requests made to the REST API in the customizer preview will have customizations applied in their responses.

With changesets in Core, I’m also planning for the customizer to be more RESTful internally. In its current architecture, the customizer state (the dirty settings) do not get persisted to the database at all. Each change to a setting (with a refresh transport) results in a POST Ajax request to pass all of the dirty settings back to the URL being previewed so that the dirty setting values can be available for the preview filters. With the changesets feature, each setting change can be persisted to the database in a customize_changeset post with an assigned UUID. With REST API endpoints, each change to a setting could then perform a RESTful PATCH request to update the changeset post at an endpoint such as /wp/v2/customize-changesets/9b92e182-29a5-45c1-b1c6-2aacbe133b54.

Validation and Rendering

The plugin works best with the Customize Setting Validation feature plugin also activated. This proposed core feature allows setting validation errors to be exposed to the client as opposed to failing silently, so here any WP_Error returned by a REST endpoint’s validate_callback will be displayed. Additionally, the Customize Setting Validation plugin returns the new values for the settings that have been saved and then ensures that the settings in the client get updated to reflect how they have actually been saved with sanitization. This ensures, for example, that the modified_date field for posts will be be kept up to date, as normally it is a read-only property. This also allows the GMT date fields to e made read-only in the UI so that the non-GMT date fields can be recognized as canonical/primary.

As noted above, when the REST API has a text field which is broken down as a compound object with raw and rendered properties, only the raw field is exposed as an editable input field. When the raw field is modified, the new value will also be copied rendered field in the JS setting. This is not ideal because the rendered field is specifically for representing the raw field with any PHP-based transformations applied (e.g. wptexturize).

What is really needed here is to send the raw value to the server in order to get the actual rendered value from PHP. This is actually how widget instances get sanitized in the customizer, where each change to a widget results in the instance getting sent in an update-widget Ajax request to be sent through the widget’s update method, without being persisted to the DB. In the same way, there should be a way for the REST API to provide a way to “dry-run” requests to update a given resource. From looking at the WP API plugin, the best candidate seems to be WP_REST_Controller::prepare_item_for_database(), but this is a protected method. For posts specifically, I suppose it could be implemented by adding a filter for rest_pre_insert_{$this->post_type} which could capture the $prepared_post and then return a WP_Error to short-circuit the call to WP_REST_Posts_Controller::create_item() and WP_REST_Posts_Controller::update_item() when such a dry-run request is being made. This implementation, of course, is ugly; it is also specific to posts, with no general mechanism currently available as far as I can see.

Here’s a quick demo of an alpha state of this plugin when used with Next Recent Posts widget:

Next Steps

At the moment the plugin is intended as a prototype for developers, not something polished for end users. There are several issues filed in the GitHub project. Improvements to the plugin will come as the REST API plugin is improved for Core inclusion. Pull requests welcome.

3 thoughts on “Bridging the Customizer and the WP REST API”

  1. This is interesting on so many levels. Thanks, Weston. Makes me wonder if it is theoretically possible to have custom/fields and meta boxes inside the Customizer. Thinking of your trac ticket about Posts/Pages in the customzier. What if we could do the same for meta data.

    1. Thanks, Ahmad. Yes, custom fields and metaboxes for post meta are definitely doable in the Customizer. In fact, the Customize Posts plugin implements the raw “Custom Fields” editing interface. The next step would be to make it extensible to allow metabox-tailored forms to present the appropriate fields to manipulate the post meta. It’s actually issue 1 on that GitHub project. It’s on my todo list to make a demo of this!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.