Nonce and AJAX
In the WordPress plugin API, Nonce is a way to verify that data passed to/from a plugin is from a trusted source. Mark Jaquith can explain this better than I can:
"A nonce is a number used once, and it is used for intention verification purposes in WordPress. Think of it as a password that changes each time it is used. [...] The idea is simple: we verify that user’s request is intentional by verifying that the request originates from within the WordPress admin."
WordPress ships with a handful of convenient functions that help you create and verify Nonces. They are chiefly designed for synchronous use, or where data is passed from one web page to another using an HTTP request. You create a nonce in your initial form using wpnoncefield() and then verify that nonce is correct in the method that handles the form with checkadminreferer(). It's fairly straight forward and well documented.
However, what if you want to secure your AJAX (asynchronous) transaction with Nonce? With a simple glance at the code, an evil-doer could still send some irresponsible data to your plugin. You can approach the problem with the same theoretical mindset as a normal nonce: pass a code, check it, carry on. The main difference here is how we pass the nonce code.
Let's imagine we have a very simple bulletin plugin that allows a registered user to type a note and post it without a page refresh. First, set up the basic plugin stuff.
$QuickNotes = new QuickNotes();
class QuickNotes {
function QuickNotes() {
add_action('admin_menu', array(&$this, 'add_note_page'));
add_action("admin_print_scripts", array(&$this, 'js_libs'));
add_action('wp_ajax_quicknotes_add', array(&$this, 'add'));
}
function add_note_page() {
add_theme_page('Quick Notes', 'Quick Notes', 'administrator', 'quick_notes', array(&$this, 'notes'));
}
function js_libs() {
wp_enqueue_script('jquery');
}
function notes() {
if ( function_exists('wp_nonce_field'))
wp_nonce_field('quicknotes_nonce', 'quicknotes_nonce');
?>
<div class="wrap">
<h2>Quick Notes</h2>
<ul id="note_board"></ul>
<p>
<textarea id="note"></textarea>
<a class="button" id="add_note">Add Note</a>
</p>
</div>
<?php
}
function add() {
}
}
As a quick overview, here's what has happened so far:
- We added an option page under Appearance that returns the 'form' held in the
notes()method. - Queued the jQuery library (good for AJAXing)
- Mapped an AJAX request using
wpajax(action =>quicknotes_add(), callback =>add())- This allows us to use a method within our plugin to handle the AJAX request, as opposed to a separate web page.
- Created a Nonce to use called
quicknotes_nonce.
Now let's set up the actual AJAX request with jQuery so the user can add the note without a page refresh. Using the $.post method, we'll send the values for both the note and the nonce when the 'Add' button is clicked. Finally, the note is pasted back to note board.
<?php function notes() { ?>
jQuery(document).ready(function($) {
$('#add_note').live('click',
function () {
note = $("#note").val();
nonce = $("input#quicknotes_nonce").val();
$.post(
"/wp-admin/admin-ajax.php",
{
action:"quicknotes_add",
note : note,
nonce : nonce
},
function (str) {
$('ul#note_board').html(str);
}
);
}
);
});
<?php } // notes() ?>
So, the nonce is now being passed as a $_POST parameter just like standard operating procedure. Next, assert the validity of the nonce in the add() method. If the nonce is correct, move on to inserting the note into the database, or just echo it back to the list.
function add() {
if (!wp_verify_nonce($_POST['nonce'], 'quicknotes_nonce'))
exit();
echo '<li>' . $_POST['note'] . '</li>';
exit();
}
That's it! Download the entire example.