The SimpleMap Shortcode

For a recent client, I used the plugin SimpleMap, which uses a custom post type for managing locations (think store locations) and Google Maps location search for the front-end using a shortcode. Practically every setting in the plugin can overridden in the shortcode, which is really cool for us developers. However, while their Help tab shows you some of the options available with the shortcode, there are tons more and their documentation is practically non-existent, so I’m putting this out there, at least for my own reference.

The gist below explain how to use the shortcode and the more common attributes to use with it.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
* 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]
* 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]
view raw gistfile1.txt hosted with ❤ by GitHub

This is the short list. I will add more as I have time.

Sane Inline SVG

Like everyone else these days, I’ve totally jumped onboard the SVG train. They’re scalable and easy to use. If you put them inline, they are style-able and reduce server requests, which helps your SEO.

Sadly, they also bork up your code. There’s nothing more disappointing than combing through neatly organized code thats completely marred by a giant block of inline SVG sticking out in the middle of it.

Recently, I discovered a simple way to have my cake and eat it too (mmm, cake!). Check this out:

function get_svg( $svg ) {
 $output = '';
 switch ( $svg ) {

  case 'logo' : $output .= '<svg xmlns="" version="1.1" x="0" y="0" viewBox="0 0 301.2 97.8" enable-background="new 0 0 301.2 97.8" xml:space="preserve"><path fill="#E31B23" d="... SVG stuff here..."/></svg>'; break;
 } // switch
 return $output;
} // get_svg()

Simple, right? The function has one parameter that determines which SVG is returned. While this one function may look out of control (although in my editor, each SVG is on one looooooong line, so it still remains neat and tidy), the SVGs and their craziness are contained to one place in your code.

This still gives you all the advantages of inline SVGs, without borking up your nicely indented, organized code. In my next post, I’ll show how combining this with some other simple functions can give you inline SVGs in menu items!

As a footnote, the $output being initiated and returned outside the switch means there’s a fallback. If the requested icon isn’t in the switch, nothing is returned. You could do that with a “default” statement within the switch, but I’ve also found being able to append the $output variable is more dummy-proof that other methods.

Child themes for WooThemes

I’ve been using child themes for several years now, but I’d never used one with theme by WooThemes. Most of my clients needed simple customizing, so I used WooTheme’s backend options to make the changes.

A recent client needed a bit more than I could do through their backend though. I started off making the customization directly in the theme, which is never a good idea. Catching my mistake, I decided to throw my changes in a child theme and work from there. However, reloading with the child theme activated, everything was borked. Looking at the source, I noticed how the stylesheets were loading because my child theme stylesheet should be last in the cascade, therefore overriding all other styles. There were two files from the parent theme loading after mine. I tried several solutions, hoping a newer one using wp_enqueue_style to load the parent stylesheet instead of @import would work, but that didn’t affect the other two stylesheets.

Thankfully (before pulling my hair out), I found this page in the WooThemes support docs. What they don’t spell out on the page (not helpful WooThemes!) is that you don’t actually make CSS changes in the child theme style.css. You make a second CSS file called custom.css and make your changes there. The custom.css file is loaded next-to-last, only followed by styles put into their custom CSS field on the backend forms, and therefore overrides all the other stylesheets.

The Trail of the Saved Option

WARNING: In this article, I ask you to alter core WordPress files while troubleshooting. Please remember to undo any changes you make so WordPress continues working correctly. I do NOT advise making these changes on a public-facing website.

Recently, I’ve been troubleshooting why my options for a new plugin aren’t saving correctly. So far, I’ve discovered, or should I say “re-discovered” some interesting items that other devs might find useful. For starters, when saving your plugin options, ideally, you should combine them into an array before saving them. This saves the database from having tons of random options entries just for your plugin. There are exceptions, like if you need options separated from each other, but that’s another post.

When saving data into an array, you’ll need to make the name of the field something like: name_of_the_registered_setting[name_of_the_form_field]. Notice those brackets? That helps the options save process place this field’s data into the correct place within the array.

While troubleshooting options, I began to trace where the data goes and how it gets processed by WordPress, then your own plugin, so I’m going to lay it out here.

First, when you create your settings page, your form tag has these attributes:

method="post" action="options.php"

This means, the form will use the Post method to send the data to the options.php file.

The action check in wp-admin >  options.php.

The action check and the added wp_die() in wp-admin > options.php.

Within the options.php file (version 3.9.1 as of this writing), line 133 checks if the action was “update”. There’s lots of code before this mostly dealing with making sure WordPress will be saving to the correct set of options, which changes if you’re saving options for Multi-site vs a single site installation.

If one checks the $_POST PHP superglobal on line 134, you’ll see the raw posted information you typed into the fields. To do this, one would use this bit of code within the root > wp-admin > options.php file:

wp_die( serialize( $_POST ) );

wp_die() stops WordPress right where it is and the first argument allows you to enter an optional message. In this case, we’re serializing the $_POST array so we can read it and using that as our message. From my test data, here’s what I see:

a:6:{s:11:"option_page";s:19:"slushman_wpmi_first";s:6:"action";s:6:"update";s:8:"_wpnonce";s:10:"4d37626dc4";s:16:"_wp_http_referer";s:77:"/showcase/wp-admin/options-general.php?page=wp-maximage&settings-updated=true";s:19:"slushman_wpmi_first";a:2:{s:15:"wpmi_test_field";s:9:"save this";s:17:"wpmi_test_field_2";s:0:"";}s:6:"submit";s:12:"Save Changes";}

In my test settings page, I have a field called  ‘slushman_wpmi_first’ and I entered ‘save this’ and clicked the Save Changes button.

After checking if the action is “update”, options.php then checks the admin referrer, which in our test case is ‘/showcase/wp-admin/options-general.php?page=wp-maximage&settings-updated=true‘. You can comment out and copy the wp_die() statement then paste it  just after this admin referrer check, but it should be the same stuff.

After this, it checks the whitelisted options. Most of the code above the update check in line 133 is about compiling that list of whitelisted options. If you used the register_setting() function for your plugin options, your options should be automatically added to the whitelisted options. It then checks your capabilities for multisite installations or whitelists your settings. If you’re not having capabilities issues, copy/pasting the wp_die() statement after line 153 really shouldn’t show anything different.

The next batch of code has to do with checking the time and date settings from the WordPress general page, so skip that block of code.

Line 168 checks if the variable $options is valid and has data. If all the whitelisting code passed, this variable should have been assigned in line 151. You can move the wp_die() statement to line 169 and change $_POST to $options to see your whitelisted options. Here’s what my test settings page shows:

The option value processing block in wp-admin > options.php.

The option value processing block in wp-admin > options.php.

This is the first bit where the data starts to be processed and possibly changed. After checking the $options variable, it breaks each option apart and processed them separately (in PHP, that’s a foreach loop). If you copy/paste the wp_die() within the foreach loop and change $options to $option, you should see the first one:


First, it checks each option to see if its unregistered, which was assigned to the $unregistered variable back in lines 135 or 138. Since you’ve used the register_setting() function, this should be false because your setting is registered, otherwise you’d see a WordPress error once the processing reaches this point.

The option is trimmed to remove extra white space and the $value variable set to NULL in lines 172 and 173.

Line 175 checks the $_POST superglobal for the option. If its not in $_POST there’s no reason to attempt to update it, so it would skip any further processing and go back to the settings page.

Otherwise in line 175, it assigns the $value variable the value of the option from $_POST. You can check this value for yourself by using this on line 176:

wp_die( serialize( $_POST['name_of_your_option'] ) );

In my test page, I get:

a:2:{s:15:"wpmi_test_field";s:9:"save this";s:17:"wpmi_test_field_2";s:0:"";}

It sees that both fields were submitted for the option ‘slushman_wpmi_first’. In the next line, it check  the data type of the $value and if its not an array, it trims it to remove white space, the sends it off to wp_unslash() to remove any slashes.

After this, the $option and the $value are sent to update_option(). One might think the processing ends there, but no. update_option() is located in the wp-includes/option.php file around line 231. Pasting this at the top of the update_option() function:

wp_die( serialize( $value ) );

Yields this result for my test page:

a:2:{s:15:"wpmi_test_field";s:0:"save this";s:17:"wpmi_test_field_2";s:0:"";}

First, it trims $option again. If $option is empty, it returns FALSE. Then, it sends $option off to wp_protect_special_option(), which is around line 136 in this same file. It prevents you from updating two options used by WordPress (since WordPress 2.2): alloptions and notoptions. These are used by WordPress in conjunction with transients to autoload options. I’d welcome any additional comments about their roles.

Next, if the $value is an object, it creates a clone of the object and works that with the clone rather than the original.

It then sends $option and $value off to sanitize_option(), which is in the wp-includes/formatting.php file. Looking at the code for sanitize_option(), most of it consists of a switch statement that looks at the $option parameter and acts accordingly. It already includes processing instructions for all the standard WordPress options, but after the switch statement, it includes a filter, ‘sanitize_option_{$option}‘. The sanitize_option_ filter is created and defined in register_setting() (yet another reason to use the Settings API). When you define your sanitization callback function, it adds that function to the sanitize_option_ filter.

At this point, your option’s $value is filtered by whatever you put into your sanitization callback function. After it finishes processing in your sanitization callback, its then returned back to the update_option function. If you add this to the top of your sanitization function:

wp_die( serialize( $input ) );

You can now see exactly what’s being passed into your sanitization callback function. In my case:

a:2:{s:15:"wpmi_test_field";s:9:"save this";s:17:"wpmi_test_field_2";s:0:"";}

After the new value is sanitized in your callback function, the current “old” value is recovered from the database using get_option().

The new value is now passed through two more optional filters, ‘pre_update_option_’ . $option‘, and ‘pre_update_option‘.

Now the new and old values are compared. If they aren’t different, there’s no reason to update the value, so it exits. If the old value doesn’t exist, The new value is sent off to add_option() to be created, the result is returned to this function as $value.

The $value is now sent off to maybe_serialize(), which is in the wp-includes/functions.php file, to possibly serialize it, or in other words, prep it to be stored in the database safely.

Updating the database in option.php

Updating the database in option.php

After this, an action is added for ‘update_option‘. One might get this mixed up with the function update_option(). The action happens right before the option is actually updated, while the function does all the checks and processing to make the updated data safe.

Finally, the updated value is written to the database using the $wpdb object and its update() method. The update() method does not alter the data.

After saving the data to the database, it refreshes the options caches and added to the auto-loading process.

There are two final actions, which allow for processing the value after its been saved to the database: ‘update_option_{$option}‘, which happens after a specific value has been updated, and ‘updated_option’, which happens after the value an option has been updated.

Lastly, if all has gone to plan, update_option() return TRUE.

Back in options.php, if errors occurred at some point in this process, they are handled and displayed appropriately.

Then, finally, the user is sent back to the plugin’s settings page.


Obviously, there are lots of places for things to go badly when saving your plugin settings. Hopefully, this breakdown can help narrow down where things happen and you can use the wp_die() function to discover where issues are happening. In all cases, I’d highly recommend using the Settings API as much as possible!

BP Profile Widgets 0.5 is out!

This is a major update for this plugin. 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 this plugin, 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!

Building Your First Widget

So, I spoke at WordCamp Nashville today and I had an absolute blast! The other sessions were very informative, I especially enjoyed learning about some tools for debugging plugins and themes. My session was the last one in the developer track. You can download my boilerplate widget code using the nice, giant green button on my home page. Here are my slides, I hope you learn something new:

Download the Boilerplate Widget code

Six Steps to Protecting Your WordPress Site Against Attacks

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 blogs. 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 said user.

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

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”, they will just waste their time attacking your site.

Don’t stop there though!

2) Beef-up your passwords. While standard practice is to use an 8-digit password 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? 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 length of the password is over 15 digits, making it’s basically impossible to figure out using a brute-force attack.

3) Limit login attempts. 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:

  • Better WP Security
  • WordFence
  • Limit Login Attempts

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

4) Use some kind of caching plugin. 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. This can prevent certain types of attacks and sudden increases in popularity.

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.

6) Delete unused plugins and themes. 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.

Returning a submit button

If you need a submit button returned instead of echoed, for example, returning a form from a function, use the get_submit_button() function, which accepts the same arguments as the submit_button() function.

Adding a Custom Class to a Submit Button

While you can hand-code the HTML for a submit button in a form, WordPress has a nice function, submit_button(), that can drop in the correct code for you. The function accepts five arguments: $text, $type, $name, $wrap, and $other_attributes.

$text changes the text on the button.

$type determines the style of the button. The common options are primary, secondary, and delete, with primary being the default.

$name sets the name attribute for the button, its “submit” by default.

$wrap determines if the button is wrapped in paragraphs tags or not, the default is true.

$other_attributes sets other attributes for the button.

For a recent project, I wanted to restyle some buttons to make them look like links, like on the posts page, rather than buttons. While you don’t NEED an special class to pull this off, it certainly makes it easier and neater in the CSS. I thought this would be achievable in the $other_attributes, but through trial-and-error I discovered you add your custom class in $type instead of using one of the defaults, like this:

submit_button( 'Whatever Text', 'my_custom_class' );

Basically, whatever you put there will be added to the class attribute of the button and you’re good to restyle the button however you want using your custom class.

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!