Debugging WordPress REST API queries

TL;DR: Add this code to your plugin/theme and it will log all SQL queries (warning it can be a lot, and will impact performance) to a queries.log file in the current directory.

	function() {
		global $wpdb;
		error_log( print_r( $wpdb->queries, true ), 3, dirname( __FILE__ ) . '/queries.log' );

And don’t forget to enable SAVEQUERIES in wp-config.php

define( 'SAVEQUERIES', true );

I’ve been working A LOT with the WordPress REST API for a plugin I’m writing for work. Right now I’m working on tweaking the custom search functionality that is built into the plugin via REST API calls and to do so I’m doing a fair amount of copying WordPress generated SQL into Sequel Pro to do testing and debugging.

I was using XDebug breakpoints but got tired of having to start, stop, continue, and step through code to find the query I was working on, so I decided to see if I could just log all of the SQL queries somewhere so I could go through them at my leisure.

There is a fair amount of information on the web about using SAVEQUERIES to log your queries to the Debug Bar among other places, but I wasn’t able to find a way to capture queries that were run using the REST API.

If you want you can just use error_log and have the queries saved to the standard debug.log in the wp-content/ folder, but I didn’t want to clutter that up. I also ran into the problem where print_r kept outputting just 1, I’d forgotten to set the second parameter to true so PHP will just return the value instead of echoing it (which made for some very odd page displays)

Grep and Node.js

One of my most frequently used command line utilities is Grep, specifically grep -lir which searches for text inside files (great for finding where else I referenced that variable I just renamed).

As I started using Node.js more and more (and consequently my node_modules folder grew bigger and bigger) I found myself getting more annoyed by all of the “false positives” that grep found. Luckily grep version 2.5.2 introduced the --exclude_dir which does exactly what you think it would. So then I started using
grep -lir --exclude_dir=node_modules for all of my grepping needs.

Alas, because I’m a #LazyWeb programmer this became tedious and annoying to me too. I figured there had to be an environmental variable I could set in zsh so I set to Googling. I found that there is indeed a GREP_OPTIONS variable that you can set but it is not recommended. So I did as the man page suggested and created a small script named grep in my ~/bin directory (making sure that the first line in my .zshrc was export PATH=$HOME/bin:/usr/local/bin:$PATH).

Here’s the contents of my tiny grep:

! /bin/sh
export PATH=/usr/bin
exec grep --exclude-dir=node_modules "$@"

…and now all I have to do is:
grep -lir "where_did_i_put_that_variable" *

N.B. I didn’t add the -lir to my script because while I use grep for searching in files 90% of the time, the other 10% I do use it to search for file names and I’d rather type -lir than /usr/bin/grep

Regex is MAGIC 🧙‍♂️

This is going to be a quick one, I should have included it in my post on “Printing the Internet” but I forgot.

I do more manual data manipulation then I care to, but one of the biggest helpers in these endeavors is Regular Expressions. (the biggest help, BY FAR, is VSCode’s multiple cursors).

My absolute favorite to use is something like:


You can swap out the “style” for whatever tag you’re trying to alter or delete. That one takes the tags and everything inside of them (useful for inline style or .docx XML data), but if you need to keep the text in between, simply change it to:


followed by using:


My new Git-moji setup

I’ve been a HUGE fan of Ahmad Awais for awhile now. Among the things he’s created that I use daily are the git commit messages from his Emjoi Log repo.

With the announcement that Catalina is going to default to zsh instead of bash I decided to explore the new shell and came across Ali Spittel’s excellent writeup about her terminal setup and decided to use that as a jumping off point.

I’d highly recommend giving it a read. Where I started to diverge was when she got to her custom functions, but that was simply to add my custom Git Emoji messages. I put my version in a gist if you’re interested in checking them out.

bonus tip: I printed out a small notecard with the commands so I can quickly reference them before they become second nature (it didn’t take more than a week for me, YMMV)

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:

a.post_title title,
a.post_content content
m.menu_order as self_order,
p.menu_order as parent_order,
g.menu_order as gp_order,
WHEN m.post_parent = 0 THEN m.menu_order * 100
ELSE case
when g.menu_order is null then m.menu_order * 10 + p.menu_order * 100
else m.menu_order + p.menu_order * 10 + g.menu_order* 100
END AS parentId
wp_posts m
LEFT JOIN wp_posts p
ON m.post_parent = p.ID
left join wp_posts g
on p.post_parent = g.ID
where m.post_type = 'page' and m.post_status = 'publish'
ORDER BY parentId) a

view raw
hosted with ❤ by GitHub

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!):

add_filter( 'template_include', array( self::$instance, 'ppi_load_single_template' ), 99 );
function ppi_load_single_template( $template ) {
if ( is_singular( 'things' ) ) {
// look in child or parent themes for template files first
if ( $theme_template = locate_template( 'single-items.php' ) ) {
$template = $theme_template;
} else {
$template = self::$directories['templates'] . 'single-items.php';
return $template;

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

require_once( WASHU_PPI_PLUGIN_DIR . 'templates/partials/ppi-loop.php' );
require( WASHU_PPI_PLUGIN_DIR . 'templates/partials/' . get_post_type() . '.php' );

view raw
hosted with ❤ by GitHub

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:

global $ppi_query;
$ppi_query = new WP_Query( $args );
global $ppi_query;
global $post;
if ( $ppi_query ==null ) { $ppi_query = $wp_query; }

view raw
hosted with ❤ by GitHub

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