admin管理员组

文章数量:1291037

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(); 
}

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(); 
}
Share Improve this question edited Jun 4, 2021 at 15:37 TARKUS asked Jun 2, 2021 at 21:31 TARKUSTARKUS 13710 bronze badges 8
  • 2 The docs clearly say that wp_update_post returns the post ID on success, so unless your ID is 1, then something is awry there. Try checking for a wp_error. – vancoder Commented Jun 2, 2021 at 22:17
  • 1 Assigning values to $_POST is unusual and likely to cause fatal errors on newer versions of PHP. It also means everything passed into the AJAX endpoint also gets returned which could lead to security issues. Was there a reason not to use the Posts endpoint of the REST API for your AJAX? This code would allow any post to be published bypassing capability security checks – Tom J Nowell Commented Jun 2, 2021 at 22:25
  • @vancoder The post ID is 28, so I guess it did not succeed. – TARKUS Commented Jun 2, 2021 at 22:35
  • 1 @TARKUS, "My suspicion is it has something to do with security" - maybe, and maybe not. And FYI, your code worked fine for me, both when logged-in and not. So I suggest you to replace that echo $result with var_dump( $result ) and try again making your AJAX call, then see what the dump outputted. And I also agreed with @HowdyMcGee, so can we see your AJAX/JS script? Did you try checking the console for any errors? – Sally CJ Commented Jun 4, 2021 at 1:35
  • 1 @SallyCJ , No matter whether I use var_dump, echo, or print_r, using the ajax callback, it only returns "1". The AJAX sends the entire POST object to the callback function. That was why I echo json_encode($_POST), to see what was operated on in the callback function. Also, I tried this plugin on my localhost and a remote site with https. Same results. I will add my js to my question for all who are interested. I ditched ajax for now, and the plain-jane html form submit works, until I can solve the ajax problem. B.T.W., I also tried the wp_error, which returned nothing. – TARKUS Commented Jun 4, 2021 at 12:05
 |  Show 3 more comments

2 Answers 2

Reset to default 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? :)

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

本文标签: pluginswpupdatepost does not change post status from draft to publishreturns 1