Testing Javascript for your Gutenberg Integrated Plugin

As a part of my work with Event Espresso I’ve been assisting them with moving over to a more modern Javascript build system.  This has been prompted by the upcoming new editor for WordPress codenamed Gutenberg.  I’m not going to spend a whole lot of time talking about Gutenberg since there’s already a ton of information on the internet.  What I want to do in this post is outline a way for plugin developers to test their custom components/blocks built for Gutenberg using the Jest framework.

Writing javascript tests using Jest is pretty straightforward and this isn’t a how-to-post since there’s a lot of that already available (including this readme the Gutenberg team prepared).  Instead I thought it’d be useful to write how I solved a problem with a particular set of tests I was trying to write for some code I had written (especially since I couldn’t find anything useful on the internet myself to help with it).

The Problem

For Event Espresso I’m creating a reusable react component that exposes a Event Selector populated with events currently on the user’s site.  This will end up getting used in various parts of the Gutenberg friendly api we’re building.  I wanted a way to test this component using jest but ran into a few problems:

  1. The EventSelect component is composed of the Placeholder, SelectControl, and Spinner components from @wordpress/components (or  wp.elements ).
  2. There’s a few other dependencies in file for this component including @wordpress/i18n and @wordpress/data
  3. Gutenberg itself is a plugin and most of the dependencies the code has on Gutenberg itself are thus not available in the context of the javascript being tested (because of assumption of Gutenberg functionality being exposed on the wp global at runtime).
  4. I want to at a minimum use jest’s snapshot feature (using shallow) to verify that EventSelect is rendered correctly depending on the various props provided to it. 

While I could mock all of the dependencies, mocking the WordPress components being used would mean needing to make the assumption they would never change.

The Solution

I’ll get into the specifics of how I fixed this first, and then I’ll take some time to explain why it works (or in some cases why I think it works because frankly I’m still learning Jest and its intricacies).

The very first thing that needs done is importing gutenberg as a package.  Wait what?  Gutenberg is an npm package?  It’s not published to npm, however technically, anything with a npm package.json file in it is already a package.  If it’s hosted on github, you can install it.  So the first step to exposing gutenberg javascript for our tests is to install it!  How do you do that?

npm install WordPress/gutenberg#master --save-dev

That’s it!  In case you’re wondering, npm automatically looks on github for packages if they aren’t in the npm package repository.  So the format I used corresponds to the github {organization}/{repo}#{branch} format.

Next there’s some configuration file changes needed.

The jest.config.json file ended up with this.

{
	"rootDir": "../../../",
	"collectCoverageFrom": [
		"assets/src/**/*.js",
		"!**/node_modules/**",
		"!**/vendor/**",
		"!**/test/**"
	],
	"moduleDirectories": ["node_modules"],
	"moduleNameMapper": {
		"@eventespresso\\/(eejs)": "assets/src/$1",
		"@wordpress\\/(blocks|components|date|editor|element|data|utils|edit-post|viewport|plugins|core-data)": "<rootDir>/node_modules/gutenberg/$1",
		"tinymce": "<rootDir>/tests/javascript-config/unit/mocks/tinymce",
		"@wordpress/i18n": "<rootDir>/tests/javascript-config/unit/mocks/i18n"
	},
	"setupFiles": [
		"core-js/fn/symbol/async-iterator",
		"<rootDir>/tests/javascript-config/unit/setup-globals"
	],
	"preset": "@wordpress/jest-preset-default",
	"testPathIgnorePatterns": [
		"/node_modules/",
		"/test/e2e"
	],
	"transformIgnorePatterns": [
		"node_modules/(?!(gutenberg)/)"
	]
}

Three particular  properties you should take note of are:

moduleNameMapper

The property allows you to map module names to a specific location or to a mock.  In this case I wanted to map all @wordpress/* packages to the gutenberg package I just installed.  So this line does exactly that:

"@wordpress\\/(blocks|components|date|editor|element|data|utils|edit-post|viewport|plugins|core-data)": "<rootDir>/node_modules/gutenberg/$1",

Wait a minute!  How can you be using things like@wordpress/data for your imports if that isn’t a package?

Most Gutenberg tutorials you see on the internet give instructions for using the wp global as an external in your js source files, resulting in something like this:

const { Placeholder } = wp.components;
const { withSelect } = wp.data;

This works just fine,  however, if Gutenberg ever publishes some of these things as a bona-fide package, and you want to use that package, you’d have to go through and change every file in your source to to imports. I’m lazy, I don’t want to have to go through all my files if that happens. So instead I want to do this:

import { Placeholder } from '@wordpress/components';
import { withSelect } from '@wordpress/data';

However, if I do that, Webpack won’t know what to do with those imports because @wordpress/components and @wordpress/data don’t exist in node_modules.  So we need to help webpack out.  In the webpack configuration file I have something like this:

const externals = {
	'@wordpress/data': {
		this: [ 'wp', 'data' ],
	},
	'@wordpress/components': {
		this: [ 'wp', 'components' ],
	},
};

The externals object is then assigned to the externals configuration property for webpack.  What this does is alias@wordpress/data to the wp.data global.  So on builds any imports are correctly translated to use the wp.data global.

However, when running jest tests, jest does not work with the webpack builds (obviously) and is oblivious to this aliasing.  So when it encounters the imports (and goes to translate them to commonjs modules) it can’t find the @wordpress/* packages.  We get around that by using the moduleNameMapper property.

You’ll also notice that I mapped tinymce to a specific location for a mock.   What I discovered is that jest will follow the package import chain all the way down.  I would hit import not found for tinymce because guess what?  Gutenberg itself sets up tinymce as an external in its webpack config.  Since I’ll never need tinymce for my own testing (and shouldn’t need it anyways), I can just mock it.  So this line ends up being:

"tinymce": "<rootDir>/tests/javascript-config/unit/mocks/tinymce",

The path it points to simply contains this the tinymce.js file I created with this as its contents:

module.exports = jest.fn()

Which is just a handy method jest provides for mocking.

Finally, you’ll see that I also mock @wordpress/i18n.  The interesting thing here is that because @wordpress/i18n exists as a package.  I didn’t have to mock it.  However, I don’t really need to initialize jed or anything with i18n so to avoid errors related to it not being initialized in the test environment (and the usage of an actual text_domain in any i18n function calls), its better to just mock it.  So this line…

"@wordpress/i18n": "<rootDir>/tests/javascript-config/unit/mocks/i18n"

…points to the i18n.js file which currently has this as its contents:

module.exports = {
	 __ : (string) => {
		return string;
	}
};

Right now I’m only mocking the __ function, but as I start testing various code that utilizes other wp.i18n functions I’ll add them to this as well.

The next property I want to zero in on in the jest.config.json file is the setupFiles property.  This property is used to indicate any files you want executed before jest runs tests.  In particular, take note of this file reference:

"<rootDir>/tests/javascript-config/unit/setup-globals"

This points to a setup-globals.js file at that path and its contents are this:

/**
 * Setup globals used in various tests
 */
// Setup eejsdata global. This is something set in EE core via
// wp_localize_script so its outside of the build process.
global.eejsdata = {
	data: {
		testData: true
	},
};

// Set up `wp.*` aliases.  Doing this because any tests importing wp stuff will
// likely run into this.
global.wp = {
	shortcode: {
		next() {},
		regexp: jest.fn().mockReturnValue( new RegExp() ),
	},
};

[
	'element',
	'components',
	'utils',
	'blocks',
	'date',
	'editor',
	'data',
	'core-data',
	'edit-post',
	'viewport',
	'plugins',
].forEach( entryPointName => {
	Object.defineProperty( global.wp, entryPointName, {
		get: () => require( 'gutenberg/' + entryPointName ),
	} );
} );

This is needed not because I’m going to be using the wp global anywhere in the source js I’m testing, but because I’m actually importing Gutenberg source for the tests, some of the Gutenberg files ARE referencing the wp globals and thus they need to be defined to avoid undefined errors when running tests.  With this bit of code, we’re linking up the wp.{module name} with its module location in the node_modules folder.  So for instance anytime jest encounters wp.blocks it will set the property to the module loaded from node_modules/gutenberg/blocks.  

The final property I want to zero in on for the jest.config.json file is the transformIgnorePatterns property.  For a while I was struggling with the following error every time I ran a test (prior to this property value being inserted):

huh? what do you mean unexpected token import!

Jest expects packages that are included to be pre-compiled (i.e from ES6 to commonjs).  So if you have any imports that point to uncompiled packages you’ll get the above kind of error.  Since we’re including gutenberg as a package straight from its repo, we don’t have the compiled assets, hence the need to let jest know it needs to transform any imports it comes across in gutenberg. I accidentally discovered this when I was reading through the Jest documentation and came across this line:

Since all files inside node_modules are not transformed by default, Jest will not understand the code in these modules, resulting in syntax errors.

Jest Documentation for transformIgnorePatterns

Oooooo, ya I’m getting syntax errors.  What I didn’t realize is that this property allows you to whitelist things you want to be transformed. Groovy, so as a reminder here’s what I ended up using:

"transformIgnorePatterns": [
		"node_modules/(?!(gutenberg)/)"
	]

This then made sure that anytime the node_modules/gutenberg package (or any dependencies in those packages) were imported, the code referenced would be transformed into something jest can work with.  Say good bye to syntax errors!

Winner winner, chicken dinner!

With all that work, the code I wanted tested:

/**
 * External dependencies
 */
import { stringify } from 'querystringify';
import moment from 'moment';
import { isUndefined, pickBy, isEmpty } from 'lodash';
import PropTypes from 'prop-types';

/**
 * WP dependencies
 */
import { Placeholder, SelectControl, Spinner } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { withSelect } from '@wordpress/data';

/**
 * Internal dependencies
 */
import { buildEventOptions } from './build-event-options';

const nowDateAndTime = moment();

export const EventSelect = ( {
	events,
	onEventSelect,
	selectLabel,
	selectedEventId,
	isLoading,
} ) => {
	if ( isLoading || isEmpty( events ) ) {
		return <Placeholder key="placeholder"
			icon="calendar"
			label={ __( 'EventSelect', 'event_espresso' ) }
		>
			{ isLoading ?
				<Spinner /> :
				__(
					'There are no events to select from. You need to create an event first.',
					'event_espresso'
				)
			}
		</Placeholder>;
	}

	return <SelectControl
		label={ selectLabel }
		value={ selectedEventId }
		options={ buildEventOptions( events ) }
		onChange={ ( value ) => onEventSelect( value ) }
	/>;
}

/**
 * @todo some of these proptypes are likely reusable in various place so we may
 * want to consider extracting them into a separate file/object that can be
 * included as needed.
 * @type {{events: *, onEventSelect, selectLabel: *, selectedEventId: *,
 *   isLoading: *, attributes: {limit: *, orderBy: *, order: *, showExpired: *,
 *   categorySlug: *, month: *}}}
 */
EventSelect.propTypes = {
	events: PropTypes.arrayOf( PropTypes.shape( {
		EVT_name: PropTypes.string.required,
		EVT_ID: PropTypes.number.required,
	} ) ),
	onEventSelect: PropTypes.func,
	selectLabel: PropTypes.string,
	selectedEventId: PropTypes.number,
	isLoading: PropTypes.bool,
	attributes: PropTypes.shape( {
		limit: PropTypes.number,
		orderBy: PropTypes.oneOf( [
			'EVT_name',
			'EVT_ID',
			'start_date',
			'end_date',
			'ticket_start',
			'ticket_end',
		] ),
		order: PropTypes.oneOf( [ 'asc', 'desc' ] ),
		showExpired: PropTypes.bool,
		categorySlug: PropTypes.string,
		month: PropTypes.month,
	} ),
};

EventSelect.defaultProps = {
	attributes: {
		limit: 20,
		orderBy: 'start_date',
		order: 'desc',
		showExpired: false,
	},
	selectLabel: __( 'Select Event', 'event_espresso' ),
	isLoading: true,
	events: [],
};

/**
 * Used to map an orderBy string to the actual value used in a REST query from
 * the context of an event.
 * @todo this should be moved to a mapper library for various EE Rest Related
 * things maybe?
 *
 * @param {string} orderBy
 *
 * @return { string } Returns an actual orderBy string for the REST query for
 * 					  the provided alias
 */
const mapOrderBy = ( orderBy ) => {
	const orderByMap = {
		start_date: 'Datetime.DTT_EVT_start',
		end_date: 'Datetime.DTT_EVT_end',
		ticket_start: 'Datetime.Ticket.TKT_start_date',
		ticket_end: 'Datetime.Ticket.TKT_end_date',
	};
	return isUndefined( orderByMap[ orderBy ] ) ? orderBy : orderByMap[ orderBy ];
};

const whereConditions = ( { showExpired, categorySlug, month } ) => {
	const where = [];
	const GREATER_AND_EQUAL = encodeURIComponent( '>=' );
	const LESS_AND_EQUAL = encodeURIComponent( '<=' );

	if ( ! showExpired ) {
		where.push( 'where[Datetime.DTT_EVT_end**expired][]=>&where[Datetime.DTT_EVT_end**expired][]=' +
			nowDateAndTime.local().format() );
	}
	if ( categorySlug ) {
		where.push( 'where[Term_Relationship.Term_Taxonomy.Term.slug]=' + categorySlug );
	}
	if ( month && month !== 'none' ) {
		where.push( 'where[Datetime.DTT_EVT_start][]=' + GREATER_AND_EQUAL + '&where[Datetime.DTT_EVT_start][]=' +
			moment().month( month ).startOf( 'month' ).local().format() );
		where.push( 'where[Datetime.DTT_EVT_end][]=' + LESS_AND_EQUAL + '&where[Datetime.DTT_EVT_end][]=' +
			moment().month( month ).endOf( 'month' ).local().format() );
	}
	return where.join( '&' );
};

export default withSelect( ( select, ownProps ) => {
	const { limit, order, orderBy } = ownProps.attributes;
	const where = whereConditions( ownProps.attributes );
	const { getEvents, isRequestingEvents } = select( 'eventespresso/lists' );
	const queryArgs = {
		limit,
		order,
		order_by: mapOrderBy( orderBy ),
	};
	let queryString = stringify( pickBy( queryArgs,
		value => ! isUndefined( value ),
	) );

	if ( where ) {
		queryString += '&' + where;
	}
	return {
		events: getEvents( queryString ),
		isLoading: isRequestingEvents( queryString ),
	};
} )( EventSelect );

And the actual test I tried to get working:

import { shallow } from 'enzyme';
import { EventSelect } from '../index';

describe( 'EventSelect', () => {
	it( 'should render', () => {
		const wrapper = shallow( <EventSelect /> );
		expect( wrapper ).toMatchSnapshot();
	} );
} );

results in a winner!

whoah, there’s that green I’m looking for!

I’m not done yet, but the big part is done, now I can go ahead and write tests for various states of the component.

Any thoughts?  I’m pretty new to jest so there may be some things I’m not doing “right”.  If you’re a javascript/jest guru and have some pointers to help improve on this I’m all ears 🙂

If you want to follow along with my journey in writing this component and the related tests etc, you can go to this pull request.

Something every Language/Library debate needs to keep in mind….

There’s some discussion happening right now in the WordPress world about what javascript framework to add to WP core.  These kind of debates happen frequently in the programming world (Google “PHP sucks” for some great examples).  In the course of these types of discussions, support is usually brought up for one point of view or another by pointing to what others have written about it on the internet.  Certainly it is reasonable to glean from what has been written,  but I think it’s also important to recognize there is a silent majority of programmers out there that we’ll never get input from as demonstrated by this simple diagram I did up (horrendous but communicates the point I want to make):

peoplewhoprogrampeoplewhowrite

The intersection of people who write (and you might add write well to that) and those who program (and you might add those who program well to that) is a small portion of the entire picture.  Sure, we don’t discard what is written about, but let’s not give it undue weight either.  Ultimately, there is a silent majority of people building solutions who really don’t care about these discussions or flame wars because they are using what gets the job done.

At the end of the day, use what gets the job done.  Learn it well.  Learn it deeply.  If you’re one of the few who also has the gift/time to write, write about it!

Using circleci.com for automated WordPress plugin testing.

A few months ago, one of the teams I work with went on the hunt for a good continuous integration service for running tests on the code we write.  We jumped on the unit test bandwagon at the beginning of the year and wanted to really amp up the quality of our product by having tests run on every commit.  I was tasked with this job (and anyone who knows me knows I LOVE playing with new things, so it was a task I was looking forward to doing)

Most WordPress users are familiar with travis-ci.org and the internets were full of instructions for getting things plugged in and up with travis.  Unfortunately, our project is inside a private github repo so we couldn’t use the free travis plan to run our tests on and the premium plan was a bit to pricey for our first attempt at this.  So after searching around, I stumbled on circle.  From all appearances, circle looked like it would work very similarly to travis and bonus points were that their plans are much cheaper – so great for getting started with.

All their documentation was great for getting things hooked up to your github repo, and getting started with tests, with the exception of one glaring thing.  I couldn’t find ANYTHING on the internets about how to setup a circleci.yml file for automating WordPress and WordPress plugin tests. Boo.  But actually, probably better in the long run because I ended up having to come up with something through trial and error and in the process learned a lot about the magic behind these scripts.

In this post, I’m not going to highlight how to setup unit testing for your WordPress plugin since there’s already a wealth of knowledge on the internets for that. Instead I just want to give an example circle.yml file that we use for our plugins at EventEspresso.com

So in the interest of passing on what I learned for anyone else searching the internets, I present to you our circle.yml script:

## Customize the test machine
machine:

  timezone:
    America/Denver # Set the timezone

  # Version of php to use
  php:
    version: 5.4.21

  # Add some environment variables
  environment:
    CIRCLE_ENV: test
    WP_MULTISITE: 0
    WP_CORE_DIR: /home/ubuntu/wordpress-develop
    WP_TESTS_DIR: /home/ubuntu/wordpress-develop/tests/phpunit
    plugin_loc: /home/ubuntu/$CIRCLE_PROJECT_REPONAME
    plugin_slug: $CIRCLE_PROJECT_REPONAME
    plugin_dir: /home/ubuntu/wordpress-develop/src/wp-content/plugins/$plugin_slug
    plugin_tests_dir: /home/ubuntu/wordpress-develop/src/wp-content/plugins/$plugin_slug/tests


## Customize dependencies
dependencies:
  pre:
    #enable xdebug.  LINE 1/2 to uncomment if you want to run a code coverage report.
    # - sed -i 's/^;//' ~/.phpenv/versions/$(phpenv global)/etc/conf.d/xdebug.ini
    #setup WP install
    - git clone git://develop.git.wordpress.org/ $WP_CORE_DIR;
    - cd $WP_CORE_DIR && cp wp-tests-config-sample.php wp-tests-config.php && sed -i "s/youremptytestdbnamehere/wordpress_test/" wp-tests-config.php && sed -i "s/yourusernamehere/root/" wp-tests-config.php && sed -i "s/yourpasswordhere//" wp-tests-config.php;
    # move plugin into tests/src
    - mv $plugin_loc $plugin_dir;
    # set up database
    - mysql -e 'CREATE DATABASE wordpress_test;' -uroot;
    # setup phpunit
    - wget https://phar.phpunit.de/phpunit.phar && chmod +x phpunit.phar && mv phpunit.phar /home/ubuntu/.phpenv/shims/phpunit

## tests override
test:
  override:
    # comment out the below line to run a code coverage report.
    - cd $plugin_tests_dir; phpunit
    ## LINE 2/2 to uncomment if you want to run a code coverage report.
    # - cd $plugin_tests_dir; phpunit --coverage-html $CIRCLE_ARTIFACTS

Where does the script go?

The circle.yml should be in the root directory of your WordPress plugin, and I’m assuming that the plugin itself has all its tests in a /tests/ directory off of the root.

What does all that stuff mean?

The circle.yml script itself is based off of the sample file circle provides. I just had to use trial and error to figure out setting up all the components needing setup on the virtual machines circle spins up to run the tests on. Let’s walk through the sections one by one.

machine:
The machine section basically is the group for all the machine variables controlling the vm setup.

timezone:
In this section you can set what the timezone will be setup for the spun up machine. In reality, you don’t have to put anything here, because WordPress runs in UTC. But if you are doing anything else on your machine or are collecting errors etc., setting the timezone could be useful.

php:
Here you set what php version you want the tests to run in. One thing I haven’t been able to figure out on circle yet is whether I can have our tests run consecutively on different php versions (which seems to be REALLY easy with travis). Note, PHP5.2 is NOT an option with circle (which may be an option with travis, not clear on it).Since most hosts dropping support for PHP are jumping right to PHP5.4 (and skipping PHP5.3) that’s the version we’ve decided to run our automated tests on.

environment:
In this section you set all the environment variables you want exposed in bash for your test setup. Note the following variables I’ve setup:

  • CIRCLE_ENV: test – currently unused, I just used this to set that we’re in the CIRCLE_ENV testing environment. At some point I may use this in our test scripts so I have a way of knowing we’re running tests on a circle server.
  • WP_MULTISITE: 0 – used by WordPress test library, this basically allows us to designate that we are not running our tests on WordPress multisite (of course when we DO want that to happen we change this).
  • WP_CORE_DIR – here we set the path where wp core tests suite will be installed. Note that circle vm’s are spun up with a user named ubuntu. So all files are typically found in the ubuntu user directory.
  • WP_TESTS_DIR – here we set the path for where the tests directory will be for the WordPress phpunit tests.
  • plugin_loc – here is the path set for where the plugin will be installed. Note I use a special environment variable Circle automatically exposes called $CIRCLE_PROJECT_REPONAME. Circle automatically pulls in the project from the repo its connected with and installs it in a path in the home directory. I set this as a variable so later I can instruct the script to move the project from that location to its new home in the WordPress wp-content/plugins folder.
  • plugin_slug – just to save typing and be more explicit – this is an alias for $CIRCLE_PROJECT_REPONAME
  • plugin_dir – this is the path where the plugin will be moved to after WordPress is installed.
  • plugin_tests_dir – this is the path to the tests folder where phpunit will be run for our plugin.

dependencies:
This section of the circle.yml file is where you can setup all the dependencies before the tests are run. In our file, we only use the “pre” index (but there are others you can read about in the circle docs).

pre:
This is where you list instructions for how circle should setup the machine before the tests are run. It appears that any bash commands can be included as separate line items in this list.

  • sed -i 's/^;//' ~/.phpenv/versions/$(phpenv global)/etc/conf.d/xdebug.ini – note this line is commented out by default. it basically takes care of enabling xdebug for php. If you want to do a coverage report at the end of your tests then you need to remove the commenting.
  • git clone git://develop.git.wordpress.org/ $WP_CORE_DIR; – here we’re pulling in the WordPress development repo that contains all the WordPress tests.
  • cd $WP_CORE_DIR && cp wp-tests-config-sample.php wp-tests-config.php && sed -i "s/youremptytestdbnamehere/wordpress_test/" wp-tests-config.php && sed -i "s/yourusernamehere/root/" wp-tests-config.php && sed -i "s/ – here is where we give instructions to cd into the WordPress installation we just installed, and then modify the wp-tests-config.php file to have the db instructions.
  • mv $plugin_loc $plugin_dir; – we’re moving the plugin the tests are being run against from the directory it was installed in, into the WordPress plugins folder where it needs to be.
  • mysql -e 'CREATE DATABASE wordpress_test;' -uroot; – This just sets up the db to be used by the tests suite.
  • wget https://phar.phpunit.de/phpunit.phar && chmod +x phpunit.phar && mv phpunit.phar /home/ubuntu/.phpenv/shims/phpunit – for some reason, the installation of phpunit that comes with circle machine installations is just not setup correctly because it doesn’t work. So this line takes care of installing the latest phpunit so that it does work. This little line is the culmination of hours of work (just because there’s so little usable information, I’m not a server guru, and I had a lot of trial and error).

test:
In this section of the circle.yml file you are able to give specific instructions regarding the tests. The only parameter we use in our file is the “override” one. This just ensures that the default circle test isn’t run but instead what we specify.

override:

  • cd $plugin_tests_dir; phpunit – here we cd into the tests directory for our plugin and run phpunit. That’s it! Now if you want to run a code coverage report then you make sure this line is commented out and uncomment the following line…
  • cd $plugin_tests_dir; phpunit --coverage-html $CIRCLE_ARTIFACTS – this line is commented out by default. However, if you wish to run a code coverage report then xdebug has to be enabled, and then you remove the comments from this line and comment out the previous line. What happens is when the test is complete, phpunit will create a html code coverage report and install it in the $CIRCLE_ARTIFACTS path. The groovy thing about this is that when complete, the circle artifacts path is visible on the internet so you can click the provided link (or share it with the team) to access the code coverage report. The reason why this is commented out by default is it takes significantly longer to generate a report than just running the tests, so we don’t want a report generated on every commit.

Conclusion

That’s it! I hope this is useful for anyone wanting to get WordPress unit testing setup on the excellent (cheaper) circle service. If any of you reading this are more of a server guru than I am and have suggestions for improvement I welcome that in the comments!

WP 3.7 drops with an interesting surprise…

I thought I was following the development of WordPress 3.7 fairly closely but something totally missed my notice and only caught my attention when a plugin I develop stopped working with the latest version of WordPress.

The culprit?

do_action( 'save_post', $post_ID, $post, $update );

Notice anything different?  The difference is that this hook used to only have 2 parameters, “$post_ID”, and “$post” but NOW it has a third one, “$update”.  It’s actually a nice addition as it makes it super easy to determine whether the post is being updated or not.  However, due to the way I hooked into this action (with a function that had extra parameters on it), Organize Series broke.  Easy enough fix, but quirky enough that I thought it deserved a post as I haven’t seen anybody mention this little addition!

 

Get wp-cli running with MAMP

I got really intrigued with the wp-cli tool for command line WordPress (seriously awesome, check it out)… however I haven’t switched my osx machine to use the built in php and mysql so I kept getting this error:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

Easy fix:

sudo ln -s /Applications/MAMP/tmp/mysql/mysql.sock /tmp/mysql.sock

And BOOM! I’ve got wp-cli working now.