VVV Multitenant update✌️✌️✌️ 🏢🔼

In the past few years, I’ve given a few talks about using a multitenant WordPress install for local development. I just finished doing some major updates, most significantly switching to VVV’s built-in certificate for HTTPS, and pushed the updates to the Github repo for the project.

Feel free to give it a try if you’re a WordPress Theme or Plugin developer. I’ve found that it makes my development process much easier as I can test plugins across themes easily and quickly.

If you try it, please reach out and let me know what you think.

Ordering items in HTML forms

Recently, I was working on a plugin to convert ACF fields to the post content for a custom post type we use. The custom post type is used by another plugin I wrote that has per-site fields for the custom post type, varying from 3 fields to 37 fields. Since I wanted to make this conversion plugin useful for all sites I decided to allow the user to choose the order in which the custom fields were inserted to the post content.

I knew that I could use an HTML form and Pippin’s method for beach processing to prevent hitting any memory limits, but I wasn’t quite sure how to order the fields.

So I did some testing and figured out that the data in the $_POST variable for an input with the same name is dependent on the order they are displayed in the form. So I started with this code to loop through the fields (and skip any non-data fields).

foreach ( $field_groups as $field_group ) {
	if ( in_array( $field_group['type'], array( 'tab' ) ) ) {

	echo "<input type='checkbox' value='{$field_group['name']}' name='fields[]' checked>{$field_group['label']}";

Now the next task was to allow for reordering. That was easy, I’ve used jQuery UI’s sortable before so I simply added jQuery UI to the list of dependencies for my JavaScript.

wp_enqueue_script( $this->plugin_name, plugin_dir_url( __FILE__ ) . 'js/plugin-admin.js', array( 'jquery', 'jquery-ui-sortable' ), $this->version, true );

…and wrapped the input’s with <li>’s and a <ul>:

<form method="post">
	<ul id="sortable">
	foreach ( $field_groups as $field_group ) {
		if ( in_array( $field_group['type'], array( 'tab' ) ) ) {
		echo "<li><input type='checkbox' value='{$field_group['name']}' name='fields[]' checked>{$field_group['label']}</li>";
	submit_button( 'Add fields to Content', 'primary', 'submit', false );

…and VOILA! A drag-n-drop ordered list that allows the user to convert ACF fields to post content.

(sorry it’s been so long since I posted)

Exporting WordPress pages in menu order

The original title for this post was “How to print the Internet in the correct order”, but my humor can fall a bit flat some times so I thought I better stick to a more descriptive title.

We recently had a project at work that required us to print out the contents of one of our sites.  This is an annual project that has around 20 contributors and in the past has always started out being edited and designed in Adobe InDesign and then “ported” to the web.  This year we decided to flip the process on it’s head and have all of the contributors write their sections on the site and then export the contents and do the layout in InDesign.

Luckily InDesign supports XML imports and maps tags to styles very well.  Also in our favor, WordPress natively exports in WXR format.  The problem we ran into is that by default WordPress exports in “post id” order which is usually somewhat chronological.  Due to the security practices in our shared hosting environment writing a one-off plugin (or using any existing plugin) would have to go through so many approvals that the project would be unable to meet our deadline to get to print.  That meant that the WXR export was essentially useless to us since the editor and designer would have to spend as much time formatting and editing as the “old” way and we were trying to improve the process.

Adding to our pain was the fact that our shared hosting also restricted our database access.  I knew if I could get access to the database I would be able to write a query that would provide the data (even if in SQL format) in the correct order.  So I set about building such a query in the hopes that I would be able to convince our systems administrator to run it and provide me the output.  Here is what I came up with:

In order to test it I ran it on my local development environment and that’s when a lightbulb went off in my head.  I could import the WXR import to my local development environment and have full access to the database!

So in the end, that is what ended up happening…the contributors wrote their articles, I exported the WXR, imported the WXR, ran the SQL locally, then used MySQL Workbench to export the results as an XML file that InDesign could import.

All-in-all it was a fairly pain-free process and we’re hoping next year to refine it even more.

Dashes in Javascript Objects

Super quick note on something that has been bugging me lately.  If you’re using dot notation to access Javascript properties, you can’t have a property name with dashes in it (e.g. image.attributes.media_details.sizes.plugin-name-headshot ). Instead you need to use bracket notation with quotation marks. So in replace the example above with image.attributes.media_details.sizes['plugin-name-headshot'].

WordPress REST API and ACF

I’m continuing to work on the plugin I’ve been talking about in my last few posts and have reached the point of front-end display.  The requirements for this project are to have a quick initial page load ( for which I use native PHP) and filtering in place (for which I use the WP REST API) and deep-linking (for which I use a combination of Javascript and custom WP_Query vars). All of which I hope to get to in further posts, but today I want to talk real quick about getting data in and out of the database via multiple methods (n.b. methods as in methodologies, not PHP methods).

Advanced Custom Fields is our de-facto standard for adding custom data to all of our sites.  It’s ease of use, extensibility, and customizability make it hard to beat.  However that doesn’t mean it’s perfect, in the five years we’ve been using it we’ve had to engineer our way around its shortcomings a few times.  Whenever that happens its always fun to look back and go over what the problem was and how we overcame it.  In the past I would discuss these things with other developers at internal meetings or Meetup groups (or sometimes even WordCamps) but even though I had a blog I never wrote anything, but now that I’ve decided to work on my writing skills I can share this process with the world.

That was a long intro to get to what turns out to be a rather short solution. Which all started with this rather cryptic section in the REST API Handbook.


The WordPress REST API doesn’t expose meta data by default.  ACF stores all of its data in the postmeta table so we have no way to access it outside of using PHP functions.


WordPress core has had a register_meta since version 3.3, but in 4.6 it was overhauled to include (among other things) support for the REST API.  So now all you need to do to expose your ACF data to the REST API is add the line

register_meta( 'post', '<INSERT ACF FIELD NAME HERE>', array( 'show_in_rest' => true ) );

The most confusing part of this snippet is the 'post' parameter, especially since we’re using custom post types.  In this context, post refers to the type of object that the metadata is associated with, other values can be 'comment' or 'user'.  There are some other arguments that you can pass in the last variable, they can all be found on the WordPress Codex entry.  Obviously the most important one in my case is the show_in_rest, but I also debated setting single to true but ended up leaving it with the default value (false) to make it easier to access any repeater fields we may use in the future.


Before register_meta was updated in version 4.6, Aires Gonçalves wrote a cool plugin to add ACF fields to the REST API.  It still exists in the Plugin Repository and on Github and I initially used that, but our sysadmins like to keep the number of plugins to a minimum (I know this is a whole ‘nother argument in the WordPress community, but we are still dealing with decisions made above my pay grade by Sharepoint people that worked here long before me).


The cheap-n-easy way to use “templates” in WordPress plugins

I’m continuing to work on the plugin I talked about in my last post, and have gotten to the point where we’re working on the front end display of the data. I recently sat down and really dedicated myself to figuring out the WordPress Plugin Boilerplate and really like the concept of using “partials” to reuse code for templates.

Pippin has a great article about using (full) template loaders in plugins since the builtin WordPress template_loader function is a theme function, but I didn’t need to go THAT far in this case.

My amazing coworker Martin wrote the main templating functions for the plugin that allow themes to override the plugin templates (extensibility is good!):

I spent the better part of the morning Googling around only to arrive at the conclusion that the simplest answer is the best answer:

The trickiest part of this was figuring out how and where to manipulate the WordPress (global) $post variable. After much trial and error, I discovered the easiest way was to set a global variable when calling the templates from a shortcode, and then check in the template whether or not that variable was set:

So far so good.  Next week I think I need to lay out how and why and where we’re using shortcodes.

Loading custom values into ACF field default values

A plugin I’m working on requires that the user be able to set the map center for a Google Map ACF field that is associated with a custom post type. Advanced Custom Fields has a good number of filters, but I wasn’t sure going in which filter I needed to use.  A quick Google lead me to this question on the ACF support forums which in turn led to this page on the ACF documentation.  From there it was as simple as plugging in my field names and values.

In the ACF JSON file for the options page, here is the field that allows the user to set the default map center:

Here is the JSON for the map field on the CPT:

And finally here is the code to put in the plugin constructor:

There are a few different filters you can hook onto depending on if you know the field key or if you want to set the values for all Google maps, but I chose to use this way since the field name is what we have the most control over.