WordPress Data Validation, Sanitizing and Escaping

Most security problems in plugins and themes come from the same mistake: trusting the data from the user. In WordPress we follow one simple rule: validate or sanitize the input, escape the output. Also check who is allowed to do the action.

StepWhenExamples
ValidateCheck if the data is correct. Reject it if notis_email(), is_numeric()
SanitizeClean the data when it comes in (before saving)sanitize_text_field(), absint()
EscapeMake the data safe when it goes out (printing)esc_html(), esc_attr(), esc_url()

Sanitizing the input

echo sanitize_text_field( '  <b>Riya</b>  Sharma <script>alert(1)</script> ' ) . "\n";
echo sanitize_email( 'riya@@example.com' ) . "\n";
echo sanitize_title( 'My First Post!' ) . "\n";
echo absint( '-25abc' ) . "\n";
echo sanitize_file_name( 'my photo (1).JPG' ) . "\n";
echo wp_kses_post( '<p>Hello <a href="https://example.com" onclick="steal()">link</a><script>bad()</script></p>' );
Output

Riya Sharma
riya@example.com
my-first-post
25
my-photo-1.JPG
<p>Hello <a href="https://example.com">link</a>bad()</p>

wp_kses_post() keeps the safe HTML tags (like those allowed in a post) and removes the dangerous ones.

Validating

var_dump( is_email( 'riya@example.com' ) );
var_dump( is_email( 'not-an-email' ) );
var_dump( in_array( 'blue', array( 'red', 'green', 'blue' ), true ) );
Output

string(16) "riya@example.com"
bool(false)
bool(true)

Escaping the output

$name = 'Riya "<b>Sharma</b>"';
echo esc_html( $name ) . "\n";
echo '<input value="' . esc_attr( $name ) . '">' . "\n";
echo esc_url( 'javascript:alert(1)' ) . "|\n";
echo esc_url( 'https://example.com/a b?x=1&y=2' ) . "\n";   // spaces and & are encoded
echo wp_kses( '<a href="/x" class="y">Safe</a>', array( 'a' => array( 'href' => true ) ) );
Output

Riya &quot;&lt;b&gt;Sharma&lt;/b&gt;&quot;
<input value="Riya &quot;&lt;b&gt;Sharma&lt;/b&gt;&quot;">
|
https://example.com/a%20b?x=1&y=2
<a href="/x">Safe</a>

FunctionUse for
esc_html()Text inside HTML tags
esc_attr()Values of HTML attributes
esc_url()Links and image addresses
esc_js()Text inside inline JavaScript
wp_kses_post()HTML content you want to allow in part

Nonces: protect from forged requests

A nonce (“number used once”) is a short token that proves a form or link was made by your own site, for a given user and action. It protects against CSRF attacks.

wp_set_current_user( 1 );
$nonce = wp_create_nonce( 'delete_book_5' );
echo 'Nonce length: ' . strlen( $nonce ) . "\n";
echo 'Right action: ' . var_export( (bool) wp_verify_nonce( $nonce, 'delete_book_5' ), true ) . "\n";
echo 'Wrong action: ' . var_export( (bool) wp_verify_nonce( $nonce, 'delete_book_6' ), true );
Output

Nonce length: 10
Right action: true
Wrong action: false

In a form use wp_nonce_field( 'action_name', 'field_name' ), and in the handler check it with check_admin_referer() or wp_verify_nonce(). For links, use wp_nonce_url().

Capability checks

A nonce only proves the request is from your site. It does not prove that the user is allowed. Always check the capability too:

wp_set_current_user( 2 );   // user 2 does not exist here, so no capabilities
var_dump( current_user_can( 'manage_options' ) );
wp_set_current_user( 1 );   // the administrator
var_dump( current_user_can( 'manage_options' ) );
Output

bool(false)
bool(true)

A safe form handler

function tc_handle_form() {
	// 1. Who is allowed?
	if ( ! current_user_can( 'edit_posts' ) ) {
		wp_die( 'Not allowed', 403 );
	}
	// 2. Is the request real?
	check_admin_referer( 'tc_save_form', 'tc_nonce' );

	// 3. Sanitize the input
	$title = isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : '';
	$age   = isset( $_POST['age'] ) ? absint( $_POST['age'] ) : 0;

	// 4. Validate
	if ( $title === '' || $age < 18 ) {
		wp_die( 'Invalid data', 400 );
	}
	// ... save the data ...
}
Note: Remember it as: sanitize early, escape late. Even when you trust a value, escape it when you print it. Database queries have their own rule, $wpdb->prepare(), in the next chapter WordPress $wpdb.

Congratulations! Chapter Finished. Learn more about the similar topics:
Exercises & Assignments
No Content Found.
Interview Questions & Answers
No Content Found.