How to Delete A WordPress Post Using AJAX

This page may contain links from our sponsors. Here’s how we make money.

AJAX is an extremely powerful tool for bridging the gap between your server-side code and your client-side code. It enables you to not only make better interfaces and more useful tools but to lower your bandwidth usage and optimize your code while you’re at it.

While AJAX can be implemented freely anywhere, WordPress has built-in support for it, and there is a standard way to use it in your themes and plugins. Let’s take a look at the steps necessary to get going with AJAX.

Delete WordPress Post
Image via Vecteezy

The AJAX Flow

As you may well know, to create something useful using AJAX you’ll need a few things:

  • An action which triggers the call
  • An AJAX call
  • Server side code which is executed
  • Javascript code which processes the result

Not all these steps are required all the time, but in general, this is how it goes. Let’s continue by thinking up a scenario where AJAX would be useful.

If you have a website with a lot of posts, you may want to be able to delete posts from the front-end. This would normally be done by clicking a link that would take you to a script that deletes the post and then redirects you back. Instead, let’s have the item just fade out, no reload necessary.

  • In this scenario the trigger is the link which we click to delete the post.
  • The AJAX call will need to contain a nonce for security and an identifier to know which post to delete
  • On the server we’ll use the data passed by the AJAX call to delete the post
  • On the front-end we’ll fade the post out

Along the way we’ll look at some WordPress security issues, graceful degradation, and more!

The Trigger

All we need to do is create a link, and give it a class name based on which we’ll grab on to it with Javascript. Let’s do something simple like this:

	<div <?php post_class() ?>>
		<h1><a href="<?php the_permalink() ?>"><?php the_title() ?></h1>
		<div class="post-content">
			<?php the_content() ?>

		<?php if( current_user_can( 'delete_post' ) ) : ?>
			<a href="#" data-id="<?php the_ID() ?>" data-nonce="<?php echo wp_create_nonce('my_delete_post_nonce') ?>" class="delete-post">delete</a>
		<?php endif ?>

Four things to point out going on here. While it is not the only security measure we’ll take, it is a good idea to use current_user_can() to check for permissions and only output the link if needed. In addition, we’ve added the id as a data attribute to the link.

In many cases it would make sense to add this to the initial post div. That way if we have multiple control links we could always check the ID of the common ancestor, we wouldn’t need to add it as an attribute to all links.

We’ve added a nonce as the data-nonce parameter. Later on, our script which check the existence of this once and that it is correct. This makes sure that the user who wants to delete the post not only has the rights, but the intention to do so.

Also, later on we’ll add an actual url instead of just a hash sign to make sure it works without javascript as well.

The Call

The javascript needed to perform the AJAX call is really very simple. We need to detect the click, then send our data to the server for processing.

Before we do that, we need to talk about how to add Javascript files to WordPress, there really is only one way. You should always use functions hooked into enqueue actions to do so. This allows for dependency management, and as you’ll later see, global variable assignment.

function my_frontend_script() {
	wp_enqueue_script( 'my_script', get_template_directory_uri() . '/js/my_script.js', array( 'jquery' ), '1.0.0', true );

add_action( 'wp_enqueue_scripts', 'my_frontend_script' );

By adding the above code to the theme’s functions.php file and using the wp_enqueue_script() function we can tell WordPress to add a script to our theme’s header. Note that you’ll need to use the admin_enqueue_scripts hook for the WordPress backend.

In WordPress, all AJAX calls need to be routed to the admin-ajax.php file in wp-admin. Since we’re writing javascript by default there is no way of doing this (short of hard-coding it), since everyone’s WordPress is in a different place. Luckily there is a method to pass variables to our Javascript functions once enqueued by using the localize_script() function. make sure to add the following into the my_frontend_script() function, after you’ve enqueued your script.

wp_localize_script( 'my_script', 'MyAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );

This function will pass the MyAjax object to our script so we can use the variables contained in it. With that we can finally start writing our Javascript!

jQuery( document ).ready( function($) {
	$(document).on( 'click', '.delete-post', function() {
		var id = $(this).data('id');
		var nonce = $(this).data('nonce');
		var post = $(this).parents('.post:first');
			type: 'post',
			url: MyAjax.ajaxurl,
			data: {
				action: 'my_delete_post',
				nonce: nonce,
				id: id
			success: function( result ) {
				if( result == 'success' ) {
					post.fadeOut( function(){
		return false;

Let’s pull this apart! We detect whenever a user clicks on the delete post link and make sure the function returns false at the end so the link isn’t followed. We strip 3 pieces of data from the HTML, the ID of the post, the security nonce and the post element.

We the perform our AJAX call by using the Ajax URL defined and passed to the script. Keep in mind that an ‘action’ parameter must be passed. In addition we pass the nonce and the id to our server-side script.

We finish off by making sure that the post element is faded out when the deletion has completed and was successful. Remember that the success of an AJAX call has nothing to do with the success of the deletion process. If the user does not have permission to delete the item, the call itself will still be successful, the item just won’t be deleted.

On The Server

Heading into our functions.php file once again, let’s write the script which will make the deletion happen.

add_action( 'wp_ajax_my_delete_post', 'my_delete_post' );
function my_delete_post(){

	$permission = check_ajax_referer( 'my_delete_post_nonce', 'nonce', false );
	if( $permission == false ) {
		echo 'error';
	else {
		wp_delete_post( $_REQUEST['id'] );
		echo 'success';



First things first, we need to figure out the hook name. Hooks are dynamically created based on your action. Just prefix your action with wp_ajax_ and you have the name of your hook. If you want to execute something for non logged in users, you’ll need to prefix with wp_ajax_nopriv_. You can name your actual function any way you like, but I generally leave it as the name of the action.

Once the function is created we need to make sure that there is no naughty business, using the nonce. The check_ajax_referer() function uses the action name, the name of the parameter it was passed in and the third argument decides if the script should die automatically on failure.

After that we just perform the deletion if we have permission to and return ‘success’. This will be detected by our Javascript and our post will be hidden and removes from the DOM.

If the user does not have permission ‘error’ will be returned and nothing will happen.

Graceful Degradation

The most awesome thing about this workflow is that we need to do next to nothing to make it work without Javascript. AJAX calls pass POST or GET parameters anyway so all we need to do is pass parameters via a link. Let’s modify the code for our post like so:

	<div <?php post_class() ?>>
		<h1><a href="<?php the_permalink() ?>"><?php the_title() ?></h1>
		<div class="post-content">
			<?php the_content() ?>

		<?php if( current_user_can( 'delete_post' ) ) : ?>
			<?php $nonce = wp_create_nonce('my_delete_post_nonce') ?>
			<a href="<?php echo admin_url( 'admin-ajax.php?action=my_delete_post&id=' . get_the_ID() . '&nonce=' . $nonce ) ?>" data-id="<?php the_ID() ?>" data-nonce="<?php echo $nonce ?>" class="delete-post">delete</a>
		<?php endif ?>

In fact, nothing else needs to be done. The same nonce is used, the same action is used and the same ID is used. The only difference is that $_GET variables are used instead of $_POST. Since check_ajax_referer() uses the $_REQUEST internally and we used it in the function there should be absolutely no problem.


As you can see, there is a strict-ish workflow involved in AJAX calls. This workflow helps keep our code in check and provides for extremely easily transitions between javascript and non-javascript environments.

Using this method to add AJAX to your themes will make your code WordPress standard, more safe and secure and much easier to work with.

Get the Free Resources Bundle