wp_update_post does not change post status from draft to publish, returns 1

The question:

I’m writing a post approval utility for the front end, because we don’t want our editor to be able to access the admin dashboard. There are questions on Stack nearly identical to what I’m trying to accomplish, but that guy’s problem has to do with the infinite loop issue. Otherwise, he claims his code works:

How to change post status from publish to draft using hook in wordpress?

I’m writing a plugin to do this (in my case I want to change ‘draft’ to ‘publish’). I don’t want to have to edit the functions.php in the child theme, because I want the plugin to be standalone, for any WordPress site. So all code is in my plugin’s main php file.

  • I can get all posts with status of ‘draft’.
  • I can use an html checkbox, javascript, and WP’s ajax functions to select the post I want to change by ID.

The “change status” code looks like this (in the plugin main php file):

/* This function should toggle a post status from 'draft' to 'publish' */
add_action( 'wp_ajax_approvepost', 'approvepost_callback' );
add_action( 'wp_ajax_nopriv_approvepost', 'approvepost_callback' );
function approvepost_callback(){
    $post = array( 
                    'ID' => $_POST['postid'], // e.g., 28
                    'post_status' => 'publish',
                    'edit_date' => true
                );
    $result = wp_update_post($post,true); // (there, you like that better?)
    echo $result; // I get a result of "1". The post ID is 28. wp_update_post failed?
    wp_die(); 
}

wp_update_post returns a 1, so I take that to mean there were no errors. But when I refresh the front-end page, the post shows up again, meaning it is still in draft mode, and when I inspect the post in the WP admin dashboard, sure enough, it’s still in draft. What am I doing wrong or missing?

UPDATE:
If I execute the function from my child theme functions.php, the code works, but not by using AJAX. I have to call the function directly, like by refreshing the page, and the function returns the post ID, and the post status will change to ‘publish’. As soon as I invoke the function using AJAX, the post status does not change, and the function returns a 1.

UPDATE
I removed the AJAX action altogether, and defaulted to an old timey standard form submit, which refreshes the form page. Under these conditions, wp_update_post works as expected. Something about wp_update_post doesn’t like to be called by AJAX. My suspicion is it has something to do with security, but whatever it is, I can’t find any reference to it in the documentation.

ADDITIONAL JAVASCRIPT
Some have asked to see the javascript, especially the ajax code:

jQuery(document).ready(function($){

    // AJAX url
    var ajax_url = approve_posts_ajax_object.ajax_url;
    var data = {
                 'action': 'approvepost',
                };

    $('button#submit-approval').on("click",function(){

        var checkboxes = $("input[name='post_id']");
        data.postid = [];
        // loop over them all
        for (var i=0; i<checkboxes.length; i++) {
            // And stick the checked ones onto an array...
            if (checkboxes[i].checked) {
                data.postid[i] = $(checkboxes[i]).val();
            }
            else{
                data.postid[i] = "";
            }
        }

        $.ajax({
            url: ajax_url,
            type: 'post',
            data: data,
            dataType: 'json',
            success: function(response){
              // Add new rows to table
              approvePost(response);
            }
        });    
    });
});

function approvePost(data){
    jQuery("#diag").html(data); //just want to output the callback response for now.
}

SOLUTION (so that others can see what works):

Javascript, with AJAX call:

jQuery(document).ready(function($){

    // AJAX url
    var ajax_url = approve_posts_ajax_object.ajax_url;
    var data = {
                 'action': 'approvepost',
                };

    $('button#approval_submit').on("click",function(){

        var checkboxes = $("input[name='post_id']");
        data.postid = [];
        // loop over them all
        for (var i=0; i<checkboxes.length; i++) {
            // And stick the checked ones onto an array...
            if (checkboxes[i].checked) {
                data.postid[i] = $(checkboxes[i]).val();
            }
        }

        $.ajax({
            url: ajax_url,
            type: 'post',
            data: data,
            dataType: 'json',
            success: function(response){
              approvePost(response);
            }
        });    
    });
});

function approvePost(data){
    jQuery("#diag").html("");
    var string = "n";
    jQuery.each(data,function(k,v){
        string += k + " = " + v + "<br>";
    });
    jQuery("#diag").append(string);
    
}

PHP (with ajax callback function, in main plugin file):

/* This is the function that toggles a post status from draft to published */
add_action( 'wp_ajax_approvepost', 'approvepost_callback' );
add_action( 'wp_ajax_nopriv_approvepost', 'approvepost_callback' );
function approvepost_callback(){

    $update = array();
    for($i=0;$i<count($_POST['postid']);$i++){
            $post = array( 
                'ID' => $_POST['postid'][$i],
                'post_status' => 'publish'
            );
            $update[$i] = wp_update_post($post);
    }
    echo json_encode($update);    
    wp_die(); 
}

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

Something about wp_update_post doesn’t like to be called by AJAX.

No, there is no such thing. 🙂

My suspicion is it has something to do with security

And I believed that also wasn’t the case, hence I asked for your JS code.

And the actual problem is that the POST parameter postid (i.e. $_POST['postid']) is actually an array of post IDs, so you can’t simply do 'ID' => $_POST['postid']. And regarding this: “wp_update_post returns a 1“, it’s because the function calls get_post() and it’s actually the one which returned 1. So that also means, the post that was updated is the one with that ID, i.e. 1 (which is the “Hello world!” post in a default WordPress install).

So you need to do a foreach then call wp_update_post() to update each of the posts. Example based on your code:

function approvepost_callback() {
    $data = array();

    foreach ( (array) $_POST['postid'] as $post_id ) {
        if ( empty( $post_id ) || ! is_numeric( $post_id ) ) {
            continue;
        }

        $post = array(
            'ID'          => $post_id,
            'post_status' => 'publish',
            'edit_date'   => true // what is edit_date?
        );

        $result = wp_update_post( $post, true );
        if ( $result && ! is_wp_error( $result ) ) {
            $data[] = $post_id;
        }
    }

    // In your JS, you set dataType to 'json', so make sure to send a valid JSON response.
    wp_send_json( $data ); // this function will call wp_die()
}

Some JavaScript Notes

  1. You don’t need the following else because it will add empty items to the array (data.postid):

    else{
        data.postid[i] = "";
    }
    
  2. I would ensure the above array is not empty before proceeding with the AJAX ($.ajax()) call:

    if ( data.postid.length < 1 ) {
        console.log( 'no selections' );
        return;
    }
    
    $.ajax( ... your code here. );
    

And last but not least… you should consider using the REST API instead to update your posts (see the Update a Post endpoint), because among other good things, the REST API has a better error handling and for example if you specified an invalid/non-existent post ID, the response would look like so which tells what exactly went wrong: {code: "rest_post_invalid_id", message: "Invalid post ID.", data: {status: 404}} — better than simply 0 or 1, right? 🙂

Method 2

This may be a weird answer since I think it has nothing to do with the ajax…. try clearing the cache memory or install 1 and purge the cache also 1s more save the permalink with post name selected


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment