PHPUnit tests and WP-CLI

I recently discovered an easy way to add unit tests to my plugins. I’ve been using WP-CLI for years now to set up new local installs of WordPress and found out it has a command specifically for setting up PHPUnit for plugins. This post is partially for my future self so I can remember how to do all this. FYI, I’m on a Mac, so all the commands will be OS X-specific.

Install and Configure PHPUnit

Start by installing PHPUnit using Homebrew:

brew install phpunit

That installs the latest version of PHPUnit and makes it ready to use with the global keyword “phpunit”.

Next, use WP-CLI to setup the test suites and such needed for PHPUnit. I recommend running this command from the plugin’s directory.

wp scaffold plugin-tests my-plugin

Replace the “my-plugin” part with your plugin name.

If you aren’t already in your plugin directory, change to that now. Then you’ll run the installation bash script.

bin/ wordpress_test root '' localhost latest

Notes about this command:

  • ‘wordpress_test’ is the MySQL database created by this script and used for testing
  • ‘root’ is your local MySQL user
  • ” is where your local MySQL user password goes
  • ‘localhost’ is where you MySQL server is located
  • ‘latest’ changes the version of WordPress to use for testing.

Once you’ve run this script, you’re ready to start writing tests and running them using the ‘phpunit’ command. Here’s the rub though: the script installs WordPress and the testing suite in the /tmp directory. Why is that a  problem? On my computer, at least, the /tmp directory removes anything installed there upon reboot. Which means I need to re-run the tests bash script every time I reboot the computer.

Since we developers prefer not repeating ourselves, here’s how to configure things for a more permanent solution.


What I’m advising here is to move the stuff installed in /tmp to somewhere else, then fix all the references so they still work. So, run all of the above, then navigate to your /tmp folder. Move the /wordpress and /wordpress-tests-lib folders to another location outside the /tmp folder. I moved mine into a directory called unittests in my Dropbox folder.

Go to your Home folder and either open or create the .bash_profile file. You’ll probably need to tell Finder to show Hidden files first. In your .bash_profile file, add the following line, using your new directory location:

export WP_TESTS_DIR="/Your/New/Folder/Location/unittests/wordpress-tests-lib"

This line tells the PHPUnit bootstrap.php file where to find the test WordPress install and test suite files.

Now, go to the wordpress-tests-lib directory and open the wp-tests-config.php file. Edit the ABSPATH constant to the ‘/wordpress’ directory you copied over from /tmp earlier. Something like:

define( 'ABSPATH', '/Your/New/Folder/Location/unittests/wordpress//' );

Save the file and reboot your computer. Now, the tests setup by WP-CLI know where the testing WordPress is located, it doesn’t disappear when you install updates or reboot, and you can create and run PHPUnit tests for your plugins!

ArtistDataPress Expiration

In case you haven’t heard, ArtistData is shutting down. Since AritstDataPress merely re-displays the feed from ArtistData, the plugin will also be shutting down. The final date is October 14.

I recommend checking out either BandsInTown or GigPress. BandsInTown covers the online service bit; GigPress keeps everything on your site. I’ve seen good results from both, so you can’t lose.

SimpleMap Shortcode Reference

I’ve been using a plugin called SimpleMap for clients recently. SimpleMap creates a custom post type for managing locations (think store locations) and displays a Google Map with those locations. It also uses Google Map’s radius search to help people find locations near them. Everything on the front-end is managed using a shortcode. Practically every setting in SimpleMap can be overridden in the shortcode, which is really cool for us developers. Plus, they have tons of filters throughout, so any text or label can be customized for your usage. While the “Help” tab in the plugin settings shows you some of the options available with the shortcode, there are tons more and the documentation is practically non-existent. I’m putting this out there, at least for my own reference and I’ll keep adding to it as I learn more and/or have time to expand it.

The code below explains how to use the shortcode and the more common attributes to use with it.

 * Basic shortcode
 * Hide the search result list
 * @param	bool	true: hide the list
 *			false: show the list, this is the default
[simplemap hide_list=true]
 * Hide the map
 * @param	bool	true: hide the map
 *			false: show the map, this is the default
[simplemap hide_map=true]
 * Hide the search form
 * @param	bool	true: hide the search form
 *			false: show the search form, this is the default
[simplemap hide_search=true]
 * Limits the search results list to locations from the specified category or categories.
 * @param	int	A comma-separated list of category IDs. 
 *			Do not put spaces between the IDs, just a comma
[simplemap sm_category=8] 	// one category
[simplemap sm_category=8,9,10] 	// mutiple categories
 * Displays a checkbox for each category as part of the search form. 
 * Allows the site visitor to filter the search results by category.
 * @param	bool	true: show the category filters
 *			false: hide the category filters, this is the default
[simplemap show_sm_category_filter=true]

 * Specify which fields are included in the search form
 * The search form is built in a table.
 * Put "||" between each field. 
 * Here are the options for requesting a field:
 * "labelbr_": puts the label with a break return tag afterwards
 * "labelsp_": puts the label with a space afterwards
 * "labeltd_": puts the label and field in separate table cells.
 * "" (blank): puts no label, just the field itself.
 * The fields that you can include are:
 *  street
 *  city
 *  state
 *  zip
 *  country
 *  distance: the select menu for the search radius
 *  empty: puts an empty table cell (useful for formatting the search form properly)
 *  submit: the submit button. If you don't include this, a hidden button will be added for you.searc
 *  taxonomy: include the filters for a specific taxonomy. There are four defaults:
 *    "sm-category"
 *    "sm-tags"
 *    "sm-day"
 *    "sm-time"
[simplemap search_fields=labelbr_street||labelbr_city||labelbr_state||labelbr_zip||labelbr_country||labelbr_distance]

 * Changes the name of the search form.
 * Default is "Find Locations Near:"
[simplemap search_title="Search this"]

 * Changes the number of default table cells.
 * Default value is 3.
 * NOTE: This one doesn't seem to work for me.
[simplemap search_form_cols=4]

 * Changes the field format for the taxonomies.
 * Accepts "checkboxes" or "select". Default is "checkboxes".
[simplemap taxonomy_field_type="select"]

 * Sets the default latitude. Default is "44.968684".
 * Ideally, use with default_lng.
[simplemap default_lat="39.840315"]

 * Sets the default longitude. Default is "-93.215561".
 * Ideally, use with default_lat.
[simplemap default_lng="-88.954800"]

 * Sets the map width. Default is 100%.
[simplemap map_width="60%"]

 * Sets the map height. Default is 350px.
[simplemap map_height="300px"]

 * Sets the measurement units. 
 * Accepts "km" for kilometers or "mi" for miles. Default is "mi".
[simplemap units="mi"]

 * Sets the radius for the search. Default is 10.
 * Use an integer and no unit.
[simplemap radius=12]

 * Limits the quantity of how results are returned. 
 * Use an integer. Default is 20.
[simplemap limit=12]

 * Quantity of results to autoload.
 * Use an integer. Default is "all".
[simplemap autoload=12]

 * Like most shortcodes, to add multiple attributes, put a space between them
[simplemap hide_list=true hide_map=true hide_search=true sm_category=8,9,10]

Gist of the code above

ArtistDataPress updated to v0.72!

Its been a long year. I’ve been trying to get back to ArtistDataPress and finally had a break in the schedule. So I resolved the larger issues people have brought up on the WordPress support forums. First off, if anyone feels I abandoned the plugin, please forgive me. Paid gigs come before free plugins. However, my schedule has freed up quite a bit now, so I should be able to make regular updates.

Version 0.72 brings the following changes:

  • BUG FIX: Resolved the “undefined function get_example_data()” error
  • BUG FIX: Removed the transient caching – causing too many errors and complaints
  • Removed “Custom” template option; added custom template explanation instead.
  • Changed Twitter account info
  • Added plugin icon to assets

ArtistDataPress is also compatible with the current version of WordPress, so there’s also that. Happy updating!

BP Profile Widgets 0.5 is out!

This is a major update for BP Profile Widgets. One thing everyone asked for is multiple instances. Since this plugin creates a BuddyPress profile field (or two) for each widget, it was a bit challenging to figure this one out. But, I did and you now have up to 5 instances of each widget available!

The other big request was to fix the crazy bug I introduced in version 0.4. Wait, software with bugs? What? Yep. I tried out a new way of getting data from the URLs people put on their profiles, but apparently the new method only works on certain server configurations. Still not sure why, but I’ve opted to simply remove it. I could already use the older way just fine, so I’ll stop trying to fix what ain’t broke!

I’ve also had several requests to internationalize BP Profile Widgets, so I read up on what needed to be done and did it. If you want to interpret this plugin into your language, check out the answer on this page and send me your translation files. I’ll update the plugin with new translations as they come in.

Lastly, I did add a few video services to the video player plugin: Wistia,, and Vine!

BP Profile Widgets

I’m excited to announce I’ve finally updated my BuddyPress plugins! I combined them all into one plugin called BP Profile Widgets. This version has many awesome upgrades like being able to select which widgets are available to use through the plugin options. When you select a widget, the plugin automatically creates the appropriate Profile Field Group and Profile Fields – no more naming issues!

On top that, I also updated the widgets with better versions of the players, oEmbed support when possible, and more vendors included. I hope you enjoy the new plugin!

BP Profile Widgets

Six Steps to Secure Your WordPress Site

There’s a great breakdancing move called 6-step. If you’ve seen breakdancing, you’ve probably seen this before, but, like me, didn’t know what to call it. Basically, the dancer supports himself on his arms while moving his feet around in a circle. It’s great for getting momentum and launching other moves.

Why do I bring this up? You may have heard about the ongoing attacks against WordPress sites. It appears someone is using up to 90,000 different IP addresses to launch brute-force attacks against sites built with WordPress and are gaining access to some sites. Stupidly, they are trying to gain access with the username “admin” and trying to figure out the password for that user.

Here’s the WP 6-step, which will help secure your WordPress site against attacks:

Get Rid of admin

1) If you have a username “admin” on your site, create another administrator user with a different name, log in as that user, and delete “admin”. If you don’t have a user named “admin”, attackers will just waste their time attacking your site. From my first-hand experience, changing this is extremely important to make your site secure. Attackers always start by using the “admin” username. Just having it as a valid account will leave you vulnerable.

Beef-Up Passwords

2) While standard practice for a secure password is to use eight digits with a mix of lowercase and uppercase letters, numbers, and symbols – there’s a better way. Create a password from a story. Something memorable to you. Something people can’t easily find out without knowing you personally.

As an example: My band and I played a show in Johnson City, TN at a coffee shop and while we played one song, this guy gets up and starts dancing. He was probably in his late 50’s and he’s doing this wiggly, hippie dancing literally feet from us. We were trying not to die laughing while finishing the song. After the show, we discovered the coffee shop owner also owned the laundromat next door and had to go fix a washer. Did I mention it took an hour longer than normal to get there because a bunch of big rigs crashed on the same stretch of highway?

Some passwords one could glean from this story: DanceWasherBigRigCoffee, CoffeeWasherJohnsonLaundry, HighwayCoffeeDanceHippie, etc. See how easy that is to come up with a secure password? You could then throw in the year and an exclamation point, just to have all the traditional password requirements too. Attackers wouldn’t know the story and the password length is over 15 digits, making it’s basically impossible to figure out using a brute-force attack.

Limit Login Attempts

3) Part of this current attack is trying different passwords over and over again until they get it correct. While its silly WordPress allows this, you don’t have to. There are several great security plugins that allow you to limit login attempts before locking that IP address out of your WordPress site:

I’m sure there are more, but those are three I have experience with. Each has their benefits and shortcomings, but anything you can do to thwart an attacker and secure your site is a good thing.

Use Caching

4) WordPress, by itself, is pretty good, but it still needs to talk to the database to load each page. Caching plugins make copies of everything so your site loads faster. While it doesn’t seem like this can help make your site secure, this can prevent certain types of attacks as well as sudden increases in popularity.

Update, Update, Update

5) This is standard WordPress advice: keep WordPress, plugins, and themes up-to-date. I usually advise people to check once a week. You should be adding content each week anyway, so knock out both at the same time.

Delete Unused Plugins and Themes

6) While this won’t help much with the current attack, these unused items could cause problems in the future. And if you’re not using them, why keep them around?

See? Six simple steps and you’re more secure and don’t need to worry about people attacking your site. Yeah ok, I’m not a comedian and the dance thing was random. But seriously, take steps to secure your site before you have to call someone like to me to fix it.

ArtistDataPress version 0.6 released!

I’ve added some really cool stuff in this release and I’m proud to announce its officially out!

First off, I’ve added feed caching. Let me ‘splain. Before, ADP would go ask ArtistData’s servers for your info every time you reloaded the page. You may have noticed how slow that was. Fortunately, WordPress has a way that I could save the feed data when I fetch it from ArtistData and it makes everything much, much faster! The one trade-off is you’ll need to wait about an hour for new events to show up on your site. Please let me know if that timing needs adjusting. But I figure an hour is short enough.

Second, all the layouts, including widgets, are now responsive, which means they look good on mobile and tablets, as well as your laptop. This trend in web development is the future, so this change is part of future-proofing your site.

The rest of the changes are fairly minor. I altered the CSS styling for some layouts to name things more consistently and make them easier to read. I also lightened up the code a bunch by getting rid of stuff I didn’t need.

Hope you all enjoy the update, let me know of any bugs and/or suggestions.

Introducing ArtistDataPress 0.5!

Its been a while since ADP was updated and I know lots of people haven’t cared for the previous update that, in some cases, took away their ability to view their plugin settings. That should be resolved with this 0.5 update.

Previously, ADP was using a PHP library called cURL to fetch the XML feed (the raw shows data) from ArtistData. Fortunately, there’s a nice built-in WordPress function called wp_remote_get that uses HTTP’s GET method to fetch an external URL. This means, your server settings really shouldn’t matter because every server supports HTTP. Hopefully, that’s the last we hear of issues getting the XML feed. 🙂

I also perused the support forums on and found several requests for features. I’ve added some great new features that have been highly requested:

You can now have multiple instances of ADP by using the [artistdatapress] shortcode to specify how many show you want to display and from which url. Use it like this:

[artistdatapress maxshows=20 feedurl=]

The values in the shortcode will override the plugin settings.

I also added the iCal layout for the widget and you choose that on the widget’s settings.

Overall, I streamlined the code and improved the logic and a bunch of other stuff under the hood that should make it easier to update later. Hope you enjoy!

BP Profile Video Widget for BuddyPress updated to 0.3

I released the 0.3 update for BP Profile Video Widget earlier today.  This update includes one big change: the elimination of the Service profile field.  The plugin will auto-detect the service being used based on the video’s URL.  I also included support for the new Youtube short URLs and embedding of Facebook videos.  I’d happily include other video services, but I’ll need some feedback as to which ones, so if you have uggestions, let me know in the comments!  Otherwise, happy updating!