VIP Services developer Daniel Bachhuber shares some tips on writing better code for your WordPress site:
Your code works, but is it safe? When writing code for a high-profile environment, you’ll need to be extra cautious of how you handle data coming into WordPress and how it’s presented to the end user. This commonly comes up when building a settings page for your theme, creating and manipulating shortcodes, or saving and rendering extra data associated with a post.
There’s a distinction between how input and output are managed, however.
Validation: Checking User Input
To validate is to ensure the data you’ve requested of the user matches what they’ve submitted. There are several core methods you can use for input validation; usage obviously depends on the type of fields you’d like to validate. Let’s take a look at an example.
Say we have an input area in our form like this:
<input type="text" id="my-zipcode" name="my-zipcode" maxlength="5" />
Just like that, we’ve limited my user to five characters of input, but there’s no limitation on what they can input. They could enter “11221” or “eval(“. If we’re saving to the database, there’s no way we want to give the user unrestricted write access.
This is where validation plays a role. When processing the form, we’ll write code to check each field for its proper data type. If it’s not of the proper data type, we’ll discard it. For instance, to check “my-zipcode” field, we might do something like this:
$safe_zipcode = intval( $_POST['my-zipcode'] ); if ( ! $safe_zipcode ) $safe_zipcode = ''; update_post_meta( $post->ID, 'my_zipcode', $safe_zipcode );
The intval() function casts user input as an integer, and defaults to zero if the input was a non-numeric value. We then check to see if the value ended up as zero. If it did, we’ll save an empty value to the database. Otherwise, we’ll save the properly validated zipcode.
This style of validation most closely follows WordPress’ whitelist philosophy: only allow the user to input what you’re expecting. Luckily, there’s a number of handy helper functions you can use for most every data type.
Sanitization: Escaping Output
For security on the other end of the spectrum, we have sanitization. To sanitize is to take the data you may already have and help secure it prior to rendering it for the end user. WordPress thankfully has a few helper functions we can use for most of what we’ll commonly need to do:
esc_html() we should use anytime our HTML element encloses a section of data we’re outputting.
<h4><?php echo esc_html( $title ); ?></h4>
esc_url() should be used on all URLs, including those in the ‘src’ and ‘href’ attributes of an HTML element.
<img src="<?php echo esc_url( $great_user_picture_url ); ?>" />
<a href="#" onclick="<?php echo esc_js( $custom_js ); ?>">Click me</a>
esc_attr() can be used on everything else that’s printed into an HTML element’s attribute.
<ul class="<?php echo esc_attr( $stored_class ); ?>">
It’s important to note that most WordPress functions properly prepare the data for output, and you don’t need to escape again.
<h4><?php the_title(); ?></h4>
Also, as there are always exceptions to the rule, there are a selection of user-submitted data that needs to be validated and sanitized. Freeform text areas would fall into this category. For this, you can run user data through sanitize_text_field() or any of the wp_kses_*() functions.
To recap: follow the whitelist philosophy with data validation, and only allow the user to input data of your expected type. If it’s not the proper type, discard it. Sanitize data as much as possible on output, and a selection needs to be sanitized on input too.
Hit us with your questions or tips in the comments.