Fixes, Tricks

Solution: xml-rpc wp.deletePost does not Trash Post for Custom Post Types

Problem:
XMLRPC wp.deletePost by default sends regular posts to trash. But for custom posts, it permanently deletes the posts.
So, how to send your custom posts to trash using xml-rpc?

Reason:
According to the wordpress codex:
http://codex.wordpress.org/XML-RPC_WordPress_API/Posts#wp.deletePost

It uses the internal wordpress function: wp_delete_post:
https://codex.wordpress.org/Function_Reference/wp_delete_post

It’s usage is:

and by default $force_delete flag is supposed to be false.

And when used for regular posts (without setting the force_delete flag), it always sends the post to trash as expected. But when the same code is used for custom posts, it permanently deletes the posts.

The problem is in the actual “wp_delete_post” function which is located in the file:
wp-includes/post.php

This function has a line:
if ( !$force_delete && ( $post->post_type == 'post' || $post->post_type == 'page' ) && get_post_status( $postid ) != 'trash' && EMPTY_TRASH_DAYS )

meaning the trash post functionality will only work for posts and pages and not custom posts.

Solution 1:

To fix this you can directly change the post.php file and add your post types there.
But this is not recommended because you might lose your changes when you update wordpress.

Solution 2 (more elegant):

Better solution is to modify your theme’s functions.php file.
Also note that it is best to use Child Themes and modify functions.php there. Because if your theme gets updated, you might lose your changes.

Just add this code to your functions.php file:

/* XML-RPC - Trash post */
function add_new_xmlrpc_methods( $methods ) {
$methods['ap.trashPost'] = 'ap_trashPost';
return $methods;
}

add_filter( 'xmlrpc_methods', 'add_new_xmlrpc_methods');

function ap_trashPost( $args ) {

global $wp_xmlrpc_server;

if ( count($args) < 4 ) return new IXR_Error( 500, __( 'Invalid arguments.' ) ); $wp_xmlrpc_server->escape( $args );

$username = $args[1];
$password = $args[2];
$post_id = (int) $args[3];

if ( ! $user = $wp_xmlrpc_server->login( $username, $password ) )
return $wp_xmlrpc_server->error;

/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
//do_action( 'xmlrpc_call', 'wp.deletePost' );

$post = get_post( $post_id, ARRAY_A );
if ( empty( $post['ID'] ) ) {
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
}

if ( ! current_user_can( 'delete_post', $post_id ) ) {
return new IXR_Error( 401, __( 'Sorry, you are not allowed to send this post to trash.' ) );
}

$result = wp_trash_post( $post_id );

if ( ! $result ) {
return new IXR_Error( 500, __( 'The post cannot be sent to trash.' ) );
}

return true;
}

This is almost like the code for wp_deletePost. The only differences are:
– We don’t use the minimum_args function because it is protected and won’t work here:
if ( ! $this->minimum_args( $args, 4 ) )
So, instead we directly use the count() function to get no. of args

– Commented out:
do_action( 'xmlrpc_call', 'wp.deletePost' );
Because this just lets us add a hook. You can uncomment this if you need to add a hook and make sure to rename the function to ours: ap.trashPost
We use namespace ‘ap’ instead of default ‘wp’, in case some other plugin has a conflict with our code.
You can use any namespace instead of ‘ap’.

– Using wp_trash_post:
$result = wp_trash_post( $post_id );
We use wp_trash_post instead of wp_delete_post.

That’s it!

Hope this helps anyone else facing this similar issue.
If you have other ideas or any suggestions to improve the code please let me know in the comments below.

Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *