Modify front-end delete button to publish pending posts

I’ve found this helpful snippet to make a delete post link on the front-end:

<?php if (current_user_can('edit_post', $post->ID)) 
    echo "<a href='" . wp_nonce_url("/wp-admin/post.php?action=delete&amp;post=$id", 'delete-post_' . $post->ID) . "'>Delete</a>" ?>

What I am wondering if there is a way to modify this code and create a complementary Publish link, which would publish a pending post, from the front end. I’ve tried the following with no luck…

Read More
<?php if (current_user_can('edit_post', $post->ID)) 
    echo "<a href='" . wp_nonce_url("/wp-admin/post.php?action=publish&amp;post=$id", 'publish-post_' . $post->ID) . "'>Publish</a>" ?>

If anyone knows if or how a front-end Publish post link would be possible, and if it could be derived from the delete post link, that would be awesomely helpful.

Thank you!

Related posts

Leave a Reply

1 comment

  1. There isn’t, by default, a ‘publish’ link because of the way WordPress handles publishing posts. ‘publish‘ is not consider an action in the same way ‘delete‘ is, instead you save the post, with all its data, including its post status.

    To get round this you can create your own action handler. In order to avoid potential clashes with WP or other plug-ins, you should probably prefix your custom action, or at the very least your nonce.

    The following code should work for this link (note prefixed action and nonce):

    $url = add_query_arg(array('action'=>'mypublish', 'post'=>$post->ID),home_url());
    echo  "<a href='" . wp_nonce_url($url, 'my-publish-post_' . $post->ID) . "'>Publish</a>"; 
    

    The following function performs some checks, publishes the post and then re-directs you to the published post.

    //Run the publish function only if the action variable is correct.
    if(isset($_REQUEST['action']) && $_REQUEST['action']=='mypublish')
        add_action('init','my_publish_draft');
    
        function my_publish_draft(){
             //Get the post's ID.
             $post_id = (isset($_REQUEST['post']) ?  (int) $_REQUEST['post'] : 0);
    
            //No post? Oh well..
            if(empty($post_id))
                return;
    
            $nonce = $_REQUEST['_wpnonce'];
    
            //Check nonce
            if (! wp_verify_nonce($nonce,'my-publish-post_'.$post_id)) 
                wp_die('Are you sure?'); 
    
            //Check user permissions
            if (!current_user_can('publish_posts'))
                wp_die("You can't do that"); 
    
            //Any other checks you may wish to perform..
    
            //Publish post
            wp_publish_post( $post_id );
    
            //Redirect to published post
            $redirect = get_permalink($post_id);
            wp_redirect($redirect);
            exit;
        }
    

    Edit

    As mentioned in the comments, slugs are not set when using this method. WordPress does not automatically give draft posts a slug, but only when you click ‘Publish’. The above does not update the slug, just the status. To get round this you can manually set the slug when you create the draft.

    Alternatively, you can replace the wp_publish_post call with the following (slightly heavier and a bit uglier) code:

        $post = get_post($post_id,ARRAY_A);
        $post['post_status'] ='publish';
        wp_update_post($post);