Publishing Experience, WordPress Plugins, WP API

Custom Contact Forms Redux

In 2009-2010 Custom Contact Forms was one of the first WordPress plugins I wrote. The purpose of the plugin was to solve a simple problem: easy contact form building on the web.

As I was building the plugin, WordPress 3.0 had not yet been released, and therefore custom post types and other useful API’s did not yet exist. I wrote the plugin the best I could using custom database tables (ouch!). The plugin become decently popular. I continued development on the plugin for the next year or so. In the process I learned a lot about writing code for WordPress. Also in the process I landed a job at 10up where I learned (and continue to learn) more than I ever thought I would.

Years later in 2015, here I am an experienced WordPress developer and an avid open source contributor. I have used most of the popular WordPress form plugins: Gravity Forms, Ninja Forms, Formidable, etc. Using all these plugins, despite lots of great functionality, have left me with the nagging feeling that something is missing.

That something was the WordPress experience. With the release of the media manager in WordPress 3.5, we have all grown accustomed to a high quality media management experience through smooth JavaScript interactions. Form management should be no different; they should be built within a media manager-esque modal, no page reloads should be necessary, and we should get live previews of what we are building. Simple task right? 8 months later… :)

Detailed installation and usage instructions are on Github. Download the plugin from WordPress.org

For Users

Within the post edit screen, a simple “Add Form” button next to the “Add Media” button brings up the form manager modal:

insert-form

Within the form management modal, you can also see your existing forms and edit them if you choose:

View all your forms within the form management modal for easy access.

After inserting a form into a post, you see a nice preview within TinyMCE:

Form previews even show within TinyMCE.

While the meat of the plugin lies within the form manager, single form views exist. Within a single form view you can see a live form preview:

Live previews of your forms are generated on the fly. No more guess and test.

Also within the single form view lives the form submissions table. You can easily paginate through results and add/remove columns as you please:

Easily scroll through form submissions in tabular format. You can configure columns you would like to see to ensure an uncluttered view.

For Developers

Most of the plugin is written in JavaScript. Custom Backbone views, models, and collections are written to emulate and display forms and fields. The plugin is extremely extensible. You can easily hook in to modify existing fields and views as well as create your own.

The plugin includes the new JSON REST API for WordPress. Right now, it is included as a Composer dependency for various reasons until the API is added to WordPress core.

Note: While the plugin is suitable for production environments, version 6 is still somewhat in beta. Please let me know on Github if you experience any problems.

Command Line WordPress, Node.js, WordPress for Enterprise

Run WordPress Cron on Real Unix Cron with Node.js

WordPress cron is a confusing beast. Most people don’t understand it or intentionally use it. It is not the same technology as Unix cron. Scheduled post functionality actually depends on WordPress cron. By default on every page load, WordPress checks to see if any cron events are due to fire. If an event is due, it sends a request to wp-cron.php asynchronously to execute the event(s).

So what?

This system works great for small websites running simple theme and plugin setups. Often when building WordPress applications for enterprise, enough resource intensive events get setup on cron that HTTP requests timeout before completion. We can circumvent this problem by executing WordPress cron using actual cron.

wp-cron-node is a simple node command that runs WordPress cron events via PHP CLI and Unix cron. It will execute WordPress cron events that are due for execution. The command requires WP-CLI.

Let’s run our scheduled events using actual Unix cron and Node:

  1. Make sure npm and WP-CLI are installed.
  2. Run the following command:
    npm install -g wp-cron-node
  3. Disable WordPress cron. This will prevent HTTP requests from triggering cron events. Put this code in wp-config.php:
    define( 'DISABLE_WP_CRON', true );
  4. Finally, setup your crontab file to your liking. Edit your crontab with the following command:
    crontab -e

    Here is an example crontab entry that will check for scheduled events every 10 minutes.

    */10 * * * * wp-cron-node /path/to/wp

    Note: Running this every 10 minutes means cron events could fire up to 10 minutes late. Ten is a conservative number for performance reasons. Change this to whatever makes you comfortable.

Backbone, WordPress Code Techniques

Syncing Backbone Models and Collections to admin-ajax.php

Backbone is framed around the assumption that your models and collections are backed by RESTful API’s. If this isn’t the case, life becomes difficult. WordPress provides an AJAX API for backend AJAX requests. These requests are sent through admin-ajax.php which is not RESTful.

I’ve written some code to force Backbone models and collections to play nicely with admin-ajax.php. First I’ll show code, then provide explanation:

/**
 * A mixin for collections/models
 */
var adminAjaxSyncableMixin = {
	url: ajaxurl,

	sync: function( method, object, options ) {
		if ( typeof options.data === 'undefined' ) {
			options.data = {};
		}

		options.data.nonce = localizedSettings.nonce;
		options.data.action_type = method;
		options.data.action = 'myaction';

		var json = this.toJSON();
		var formattedJSON = {};

		if ( json instanceof Array ) {
			formattedJSON.models = json;
		} else {
			formattedJSON.model = json;
		}

		_.extend( options.data, formattedJSON );

		options.emulateJSON = true;

		return Backbone.sync.call( this, 'create', object, options );
	}
};

/**
 * A model for all your syncable models to extend
 */
var BaseModel = Backbone.Model.extend( _.defaults( {
	parse: function( response ) {
		// Implement me depending on your response from admin-ajax.php!

		return response
	}

}, adminAjaxSyncableMixin ));

/**
 * A collection for all your syncable collections to extend
 */
var BaseCollection = Backbone.Collection.extend( _.defaults( {
	parse: function( response ) {
		// Implement me depending on your response from admin-ajax.php!

		return response
	}

}, adminAjaxSyncableMixin ));

The bulk of the action happens in our mixin:

var adminAjaxSyncableMixin = {
	url: ajaxurl,

	sync: function( method, object, options ) {}
};

We will extend the defining objects passed to our base model and collection. Therefore BaseCollection and BaseModel will have this objects properties (unless they are overwritten — more on that later).

The url property defines the location to which syncing will occur. In this case we are using ajaxurl which is a variable localized from WordPress by default containing a full URL to admin-ajax.php.

The sync property defines a function that will be called in front of Backbone.sync. Backbone.sync is called whenever we call Backbone.Model.save, Backbone.Model.destroy, Backbone.Model.fetch, Backbone.Collection.save, and Backbone.Collection.fetch. By providing a sync property to our base model and collection, we are forcing our sync function to be called instead of Backbone.sync.

adminAjaxSyncableMixin.sync has a few parameters:

sync: function( method, object, options ) {

}

By default, method is set by the function called. For example, calling Backbone.Model.save or Backbone.Collection.save will call Backbone.sync where method is create or patch (possibly update). method ultimately defines the type of HTTP method used (GET, POST, DELETE, PATCH, PUT, or OPTIONS). object is the model or collection object being synced. options lets us send associative arguments to our sync destination among other things.

Let’s look at the body of this function.

if ( typeof options.data === 'undefined' ) {
	options.data = {};
}

Setting the data property in options lets us manually overwrite the representational data sent to the server. We are going to use this so we make sure it’s defined, if it isn’t.

options.data.nonce = localizedSettings.nonce;
options.data.action_type = method;
options.data.action = 'myaction';

Now we are just setting up information to pass to admin-ajax.php. By default we pass a nonce that has been localized to our script. options.data.action should contain the action slug registered within WordPress using the wp_ajax_ hook. We will force our request to be an HTTP POST so we send our method along inside action_type for later use.

var json = this.toJSON();
var formattedJSON = {};

if ( json instanceof Array ) {
	formattedJSON.models = json;
} else {
	formattedJSON.model = json;
}
_.extend( options.data, formattedJSON );

This code sets up our model or collection data to be passed to the server. If the toJSON() representation of the current object is an Array, we know we have a collection. We extend the options.data object with the formattedJSON object we create.

options.emulateJSON = true;

This sends our data as application/x-www-form-urlencoded (classic form style) instead of application/json preventing us from having to decode JSON in our endpoint.

return Backbone.sync.call( this, 'create', object, options );

Finally, we call Backbone.sync in the current object context. We pass create as the method (forcing a POST request). object is simply passed along. We pass options having extended it with our own data. Essentially, our sync function is an intermediary between Backbone save/fetch and Backbone.sync.

var BaseModel = Backbone.Model.extend( _.defaults( {
	idAttribute: 'ID',
	parse: function( response ) {
		// Implement me depending on your response from admin-ajax.php!

		return response
	}
}, adminAjaxSyncableMixin ));

var BaseCollection = Backbone.Collection.extend( _.defaults( {
	parse: function( response ) {
		// Implement me depending on your response from admin-ajax.php!

		return response
	}
}, adminAjaxSyncableMixin ));

We define BaseModel by extending Backbone.Model and mixing in adminAjaxSyncableMixin. _.defaults returns an object filling in undefined properties of the first parameter object with corresponding property in the second parameter object. We define BaseCollection the same way extending Backbone.Collection and mixing in adminAjaxSyncableMixin.

Backbone.Model.parse and Backbone.Collection.parse intercept sync responses before they are processed into models and model data. Depending on how you write your admin-ajax.php endpoints, you may need to write some parsing code.

Finally, we can define, instantiate, and utilize new models and collections based on BaseModel and BaseCollection:

var myModel = BaseModel.extend({});
var myCollection = BaseCollection.extend({});

var modelInstance = new myModel( { ID: 1 } );
modelInstance.fetch();
modelInstance.set( 'key', 'value' );
modelInstance.save();

var collectionInstance = new myCollection();
collectionInstance.fetch();
collectionInstance.at( 0 ).set( 'key', 'value' );
collectionInstance.save();
WordPress Core, WordPress Themes, WP API

A WordPress Starter Theme Based on JSON REST API’s Backbone Client

The past few months I’ve had the opportunity to work on the new JSON REST API for WordPres. My biggest contribution as a WP API team member has been the Backbone client.

The JSON REST API’s Backbone client let’s you interact with a WordPress installation using Backbone.js collections and models. The client is an extremely useful tool in creating reactive web applications (which seems to be where the web is heading).

As a proof of concept, I created a WordPress starter theme based on Automattic’s _s named _s_backbone. Loops (or post streams) in _s_backbone are driven by Backbone.js collections. This means that posts are grabbed on the fly without a page reload. Pagination is accomplished through a “more” button which, again, does not require a page reload. This is commonly referred to as “infinite scroll”.

Please download _s_backbone from Github. Any feedback is appreciated.

Edit: Check out the WP Tavern article on _s_backbone.

Node Module for Detecting Modified Core WordPress Files

Modifying core WordPress files is a quick way to introduce security vulnerabilities, break your site, and break future updates. From the perspective of a developer, nothing is worse than searching through a theme and plugins for a problem only to discover a previous developer modified a core WordPress file an introduced a bug.

I wrote a simple Node module that lets you easily check WordPress installations for modified or removed core files. Install the detect-wp-core-modifications npm package with the following shell command:

npm install -g detect-wp-core-modifications

You can run the command without any arguments from within the root of a WordPress installation with the following shell
command:

detect-wp-core-modifications

You can also specify a relative or absolute path to a WordPress installation:

detect-wp-core-modifications ../wordpress

Introducing Post Customizer

10up just released a new plugin called the Post Customizer. I, along with John James Jacoby, John Bloch, Drew Jaynes, and Carl Danley led the charge on the plugin. The idea of the plugin is to mimic the theme customizer for posts. The plugin adds functionality that displays an overlay when you click “Preview” within the post editor. The overlay has a sidebar allowing you to edit the excerpt and featured post. In the middle of the overlay is a frame that shows the front of the website. Within that frame you can edit the post title and content. This enables you to make “live” changes and to see how they look as you make them. There are other plugins that offer similar behavior. However, Post Customizer closely follows the Theme Customizer and thus WordPress standards.

We want to make this plugin super extensible, and we need all the help we can get. We would appreciate contributions! Fork the plugin on Github.