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:

a:1:{i:0;s:19:"slushman_wpmi_first";}
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:

s:19:"slushman_wpmi_first";

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!

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

Here’s the WP 6-step, which will help secure 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. From my first-hand experience, changing this is an extremely important to making your site secure. Attackers always start by using the “admin” username and just having it as a valid account will leave you open.

Don’t stop there though!

2) Beef-up your passwords. 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 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:

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 and secure your site 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. 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.

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.

Announcing the ArtistDataPress plugin for WordPress

ArtistDataPress shows your shows calendar on your WordPress blog and automatically matches your theme!

If you’ve been using ArtistData and didn’t care for their iFrame calendar widget, I’ve got the solution for you: ArtistDataPress!  I wanted a way to display my band’s calendar on their site and on mine, but the AD iframe widget could only be styled once, which left my site with a calendar that didn’t match the rest of my theme.  ArtistDataPress takes the raw XML shows feed and makes it into an easy to style calendar for any page or post.  There’s even a sidebar widget!  You can choose what parts of the show information you want people to see through both the page and widget options.  You can download it from the WordPress Plugin Directory. You can read up on the plugin, it’s features, and get the FAQ on the plugin’s page.

Announcing the BuddyBar Widget for BuddyPress

Slushman publishes his first plugin, the BuddyBar Widget for BuddyPress. The widget places all the links on BuddyPress’s BuddyBar in a sidebar widget.

My first WordPress plugin was recently published in the WordPress directory: BuddyBar Widget. While working on the Towermix Network for Belmont University‘s Curb College, they asked about getting rid of the Admin Bar across the top of the page, which is part of the default installation of BuddyPress. Since the BuddyBar (as some call it) contains all the links necessary for managing one’s account, this posed a problem. After some hacking and research, I found out how those links were structured and put them all into a nice little sidebar widget. I’ve called it the BuddyBar Widget and you can download it from the WordPress Plugin Directory.  You can read up on the plugin, it’s features, and get the FAQ on the plugin’s page.

How to Hide the BuddyPress Admin Bar (aka BuddyBar)

Many sites tell you how to hide the BuddyPress Admin Bar (aka BuddyBar), but only this code eliminates it completely from your site.

I’ve seen a bunch of sites that supposedly show you how to do this, but none are complete.  I have a client who wants to use BuddyPress, but doesn’t want the Admin Bar (I call it the BuddyBar) across the top of every page.  So I’m building a plugin called BuddyBar Widget that includes a sidebar widget with all the BuddyBar links in it.  Another part of the plugin hides the BuddyBar completely, even when you’re on Dashboard.

To hide the BuddyBar from users that aren’t logged in, go to the BuddyPress General Settings page and select “Yes” for the Hide admin bar for logged out users? option.

That’s great, but it doesn’t hide it if you ARE logged in.  For that, we’ll need some code.

EDIT ( February 1, 2012):

Ignore the old post from below. After trying to get that to work properly, I’ve switched to something far more effective. Paste the code snippet below into your wp-config.php file. I put it right above the “Authentication Unique Keys and Salts.” comment block. This works for sure. It’s not what I had hoped to do, but it works.

https://gist.github.com/slushman/115c3fb781a921a9f593

I created a function (I’m calling it remove_buddyadminbar), then used define to tell WordPress to turn off the BuddyBar.  This, by itself, will turn off the BuddyBar.  It may complete overkill, but I also use remove_action hooks as well.  BuddyPress uses the add_action hook in the WordPress footer to activate the BuddyBar.  Remove_action simply negates that call from BuddyPress.  You’ll notice, I also include the call for the admin_footer, which should hide the bar on your admin pages, including Dashboard.

While that’s all well and good, now you’ll notice a nice gap at the top of your admin pages.  When you kill the BuddyBar for the Dashboard, it doesn’t undo the CSS formatting that creates room for it at the top of your admin pages.  This bit of CSS takes care of that:

CODE BLOCK REMOVED

Using those two bits of code will completely eliminate the BuddyBar from appearing on your site.  I’ll post again about this when the plugin is ready to ship.

WordPress 3.0 “Thelonius” is out!

Update your blogs, WordPress 3.0 is out!

Log into your Dashboards and update your installation, 3.0 is out and available! I’ll be writing up some articles about the new features soon. I’ll also be updating Your Band Blog to reflect 3.0 and the changes it offers us musicians. Until then, get your blog updated!

BuddyPress

BuddyPress was recently updated to include support for single WordPress installs. Is this useful or just another social network?

Last May, I read about BuddyPress, a new plugin from Automattic, which also produces WordPress, that would bring social networking to WordPress blogs.  I immediately began dreaming up ways to create a community of my music’s fans.  Then I read up on it.  It required WordPress MU, which allows you to create blog networks (like for a school, company, etc).  Since I wasn’t running MU, and didn’t know any bands that were, I forgot about it.

BuddyPress 1.2 was released Friday, February 26th and can be used with a single WordPress install, so we can all have social networks related to our band blogs!  However, I’m a little hesitant: do our fans need yet another social network?  While I’m sure there are bands that could easily support their own (think: Phish, Dave Matthews Band, or KISS to name a few), most of us don’t have enough fans to justify it.  We’re better off with sticking to Myspace, Facebook, and Twitter because our fans are already on those sites.

Before you think I’m just being pessimistic, I’m in favor of using this plugin.  I just wonder how effective it will be for most artists.  If you have a community created around your band already, this will work well to help you unite them.  For the rest of us, it could assist you in building that community around your music.  Either way, this is a good step for this plugin and I hope to start working it into some artist blogs to see if it’s helpful or just another useless social network.  Once I have some first-hand knowledge, I’ll write some more (but I’ll bet you see this plugin in the next version of my book).