5

OK, I had no idea how to title this topic.

I'm trying to override the default behavior with ajax. The problem here is not actually a problem, but a wish more.

I have this url:

<a href="http://example.com/?reaction=smk_remove_post&id=1226&_nonce=7be82cd4a0" class="smk-remove-post">Remove post</a>

In the functions.php I have this function and the call right after:

function smk_remove_post(){
    if( !empty( $_GET['reaction'] ) && 'smk_remove_post' == $_GET['reaction'] && !empty( $_GET['id'] ) ){
        if( current_user_can('edit_others_posts') && !empty($_GET['_nonce']) ){
            if( wp_verify_nonce( esc_html( $_GET['_nonce'] ), 'smk_remove_post' ) ){
                // Delete the post
                wp_delete_post( absint( $_GET['id'] ), true );
            }
        }
    }
}
smk_remove_post();

Now if I click on the link the post with ID 1226 will be removed. All is ok. The task is done successfuly and the page is reloaded.

Here is where I need the AJAX. I want to process this URL using ajax and not reload the page, and get a proper response.

I've added this jQuery script:

function smk_remove_post(){
    $('.smk-remove-post').on( 'click', function( event ){
        event.preventDefault();
        var _this = $(this);

        jQuery.ajax({
            type: "GET",
            url: _this.attr('href'),
            success: function(response){
                console.log(response);
                _this.text('All great, the post is removed.');
            }
        });
    });
}
smk_remove_post();

Everything works as expected. The post is removed via ajax and no need to reload the page. But I can't get a proper response, instead I get the full HTML source of the current page.

I know that I should use admin-ajax.php(ajaxurl), but how do I do it? I need to send the query from URL and get the response back.

Here is what I've tryied:

I have added this to the jQuery script above:

data: {
    'action': 'smk_remove_post_ajax',
},

And this to the PHP:

function smk_remove_post_ajax(){
    smk_remove_post();
    die();
}
add_action('wp_ajax_smk_remove_post_ajax', 'smk_remove_post_ajax');

It does not work. It's ignored, the previous call is executed insted, just like this would be done without ajax.

I understand that I need somehow to send the query to admin-ajax.php instead, but how?

3

I finally got it.

First mistake was to process the same function twice. I've called it once after the function and one more time in ajax action. So when using the ajax call, the function got executed twice. In the example from the OP, this is not a problem at all, because it is simplified to do only one thing, but in my real code it does much more and can result in lost of unwanted data.

Also, I just needed to stop the ajax and get a custom responce, nothing more. Here is what I've did:

1. I've changed this:

smk_remove_post();

to this:

add_action('parse_query', 'smk_remove_post');

It is better to run the function later when needed in special action.

2. Next, I've modified the ajax handler: I've deleted this line smk_remove_post(); and changed the ajax action from wp_ajax_smk_remove_post_ajax to wp_ajax_smk_remove_post:

function smk_remove_post_ajax(){
    wp_die( 'ok' );
}
add_action('wp_ajax_smk_remove_post', 'smk_remove_post_ajax');

3. I've renamed the query string reaction to action. Changed it in the url, and function:

4. Finally modified the jQuery script. So it uses the admin-ajax.php and sends the url as data:

url: ajaxurl,
data: _this.attr('href'),

Here is the final code:

Link:

<a href="http://example.com/?action=smk_remove_post&id=1226&_nonce=7be82cd4a0" class="smk-remove-post">Remove post</a>

PHP code:

function smk_remove_post(){
    if( !empty( $_GET['action'] ) && 'smk_remove_post' == $_GET['action'] && !empty( $_GET['id'] ) ){
        if( current_user_can('edit_others_posts') && !empty($_GET['_nonce']) ){
            if( wp_verify_nonce( esc_html( $_GET['_nonce'] ), 'smk_remove_post' ) ){
                // Delete the post
                wp_delete_post( absint( $_GET['id'] ), true );
            }
        }
    }
}
add_action('parse_query', 'smk_remove_post');

function smk_remove_post_ajax(){
    wp_die( 'ok' );
}
add_action('wp_ajax_smk_remove_post', 'smk_remove_post_ajax');

Javascript:

function smk_remove_post(){
    $('.smk-remove-post').on( 'click', function( event ){
        event.preventDefault();
        var _this = $(this);

        jQuery.ajax({
            type: "GET",
            url: ajaxurl,
            data: _this.attr('href').split('?')[1],
            success: function(response){
                console.log(response); // ok
                _this.text('All great, the post is removed.');
            }
        });
    });
}
smk_remove_post();

Edit: Also a small update to the code above. To process the query strings is required to delete the site path, else it may create unexpected problems. I've added this to data href:

.split('?')[1]
1

AJAX is not magical and when you request url X you will receive the same HTML for that url if you do it from the browser address bar, link or ajax. Therefor, if you want different response then the HTML you can not use the same url for the ajax request as in the link.

Wordpress has a special "end point" to handle ajax request - admin-ajax.php and all ajax request should be send only to it, something like $.ajax({url:....admin-ajax.php})

Next you need do let wordpress know what you want to do and for that there is a special parameter in the request named action. This parameter will identify the hook to be used at the server side to handle the request. This part you have done right in your code.

Now you need the additional parameters that identifies which object should be manipulated or retrieved by the AJAX operation. You can use the permalink of the post, or the post id for example, but it all depends on the complexity of the operation you are trying to do. In your specific case I would guess that a post id will be the best parameter to pass in the request.

How to send the parameters? most people do a POST request when doing AJAX but if you want a GET the you can pass them as part of the url (which I assume is exactly what jquery will do for you).

1

Make link like this

<a href="http://example.com/?reaction=smk_remove_post&id=1226&_nonce=7be82cd4a0" data-id="1226" data-nonce="7be82cd4a0" class="smk-remove-post">Remove post</a>

And jQuery

$('.smk-remove-post').on( 'click', function( event ){
    event.preventDefault();
    var _this = $(this);

    var data = {
        'action': 'smk_remove_post_ajax',
        'reaction': 'smk_remove_post',
        'id': _this.data('id'),
        '_nonce': _this.data('nonce')
    };

    // since 2.8 ajaxurl is always defined in the admin header and points to admin-ajax.php
    jQuery.ajax({
        type: "GET",
        url: ajaxurl,
        data: data,
        success: function(response){
            console.log(response);
            _this.text('All great, the post is removed.');
        }
    });
});

See Codex about AJAX in Plugins. And in Codex, it says:

Most of the time you should be using wp_die() in your Ajax callback function. This provides better integration with WordPress and makes it easier to test your code.

So use wp_die(); instead of die();

  • This is what I've used before, but here I need the code to work with or without ajax. – Andrei Surdu Mar 31 '15 at 14:06
  • If I disable the javascript it will fallback to page reload and process the action without ajax. In your example it will work only if JS is enabled. – Andrei Surdu Mar 31 '15 at 14:07
  • Ok. Just add back href value and it will work. If javascript is disabled, then event.preventDefault won't work and it will go to that link. – Rene Korss Mar 31 '15 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.