CNR: Server/Client Communication

By Sol in Lab

Today was focused primarily on Cornerstone, and the development of the last few weeks (1 day per week) finally paid off in a much more robust and flexible system for communicating effectively between the server and the client-side.

The Task

The original task that started this current vein of development was to enable the post permalink preview on the post edit screen to update when a post’s section is changed.  In the current (beta) release, the section is only added to the permalink preview after the post is saved as a draft or is published.  This can lead to confusion simply because it’s not clear what effect an action will have (in this case, how changing the section a post is in will affect the post’s permalink).

Making this happen turns out to be pretty simple, but there was still a fair bit of work to be done before I could even work on the original task.

The Work

Since the actual updating of the permalink preview was handled on the client-side via JavaScript, much of the work had to do with optimizing communication (i.e. passing of data) between the server backend (PHP) and the client-side (JavaScript).

I used this as an opportunity to optimize the JS libraries used in Cornerstone so that now all libraries are modular and are grouped as members of a single JS object (CNR).  For example, the server-side code that manages post permalinks and other aspects of a site structure are abstracted into the CNR_Structure class and instantiated as a member of the global Cornerstone object ($cnr->structure).  So on the client-side, all JS code that focuses on the site’s structure is grouped under the cnr.structure JS object.  Other aspects of Cornerstone now work the same way, with complementary object members in PHP and JS (server and client).

Modular Loading

In addition, JS libraries are fully modular and loaded automatically.  Building upon WP’s dependency methodology of adding scripts to the client, JS code is loaded (along with the libraries it is dependent on) based on the current request’s context.

A request can have multiple contexts, from broad to very narrow.  For example, a request for the page, /wp-admin/post-new.php, will have the following contexts:

  • admin
  • admin_page_post-new
  • admin_action_item-add
  • admin_page_post-new_action_item-add

A JS library can be loaded based on any of these contexts.  Code can be loaded based on a very broad context (e.g. admin so that it is loaded on all admin pages), all the way to a very specific context (down to the page name and action of the current request).  This allows a very large degree of flexibility to determine when and where a particular JS library will be loaded on the client-side.

Server to Client

Another piece of the puzzle was passing data from the server to the client so that information gathered on the server can be used by JS on the client-side.  Using the above example of contexts, we also want to be able to evaluate and run code based on the current request’s context, so we need to send this data to the client as well.

Using one of Cornerstone’s utility methods (extend_client_object()) and the ever-useful json_encode() (thank you PHP 5), we can easily send the array of contexts (see above) to the client side as a member of the CNR JS object.

Coming Together

Today, all of the pieces finally came together.  The bulk of the work is done by existing JS code, with properties and values from the current request that are passed from the server to the client being used where necessary.  Now that all of the various JS modules were being loaded automatically (and in the right order based on their dependencies) and the necessary properties were accessible, it was a pretty simple task to update the permalink preview whenever the section is changed (about 30 lines of code including comments).

It’s always hard to take the longer road and work on the foundation before you get cracking on the cool functionality, but I’ve found that always saves a lot of time in the long run.  This is especially true in this case as new JS modules can be easily added and everything will stay in order and automated thanks to each module’s dependencies and contexts.