How to validate XML-RPC post creation and cancel when needed?

I have an IFTTT recipe that creates posts for me on some occasion, but for some weird reason it creates three, sometimes four posts of the same content.

I would like to add an add_action hook/callback to validate what will be a new post and, if it already exists, cancel the post, or move it to trash or something like it.

I found the the xmlrpc_prepare_post but I don’t think I can cancel it from there. Unless I can update some attribute and set it to trash?

Update.

I tried the following and it only ever gets into the xmlrpc_call, but never ever inside xmlrpc_wp_insert_post_meta. I even added a hard-coded add_filter call (not just in case of if newPost) and my logs never show such logging message.

Here’s the code:

function hueman_xmlrpc_call( $method )
{
    error_log("XMLRPC | hueman_xmlrpc_call Method = $method \n" , 3, '/home/.../debug.log');
    if( 'wp.newPost' === $method || 'metaWeblog.newPost' === $method )
    {
        error_log("XMLRPC | hueman_xmlrpc_call  method = " . $method . " \n" , 3, '/home/.../debug.log');
        add_filter( 'xmlrpc_wp_insert_post_data', 'hueman_xmlrpc_wp_insert_post_data' );
    }
}
add_action('xmlrpc_call', 'hueman_xmlrpc_call', 1 );


add_filter( 'xmlrpc_wp_insert_post_data', 'hueman_xmlrpc_wp_insert_post_data' );

function hueman_xmlrpc_wp_insert_post_data( $post_data )
{
    error_log("XMLRPC | hueman_xmlrpc_wp_insert_post_data  \n" , 3, '/home/.../debug.log');
    // Check if the post title exists:
    $tmp = get_page_by_title( 
        $post_data['post_title'], 
        OBJECT, 
        $post_data['post_type'] 
    );

    if( is_object ( $tmp ) )
    {
        // Go from 'insert' to 'update' mode within wp_insert_post():
        //$post_data['ID'] = $tmp->ID; 

        $post_data['post_status'] = 'trash';
        error_log("XMLRPC | hueman_xmlrpc_wp_insert_post_data I TRASHED IT! \n" , 3, '/home/.../debug.log');
    }

    return $post_data;  
}

In the logs, I have this kind of log statements:

XMLRPC | hueman_xmlrpc_call Method = mt.supportedMethods 
XMLRPC | hueman_xmlrpc_call Method = metaWeblog.getRecentPosts 
XMLRPC | hueman_xmlrpc_call Method = mt.supportedMethods 
XMLRPC | hueman_xmlrpc_call Method = metaWeblog.getRecentPosts 
XMLRPC | hueman_xmlrpc_call Method = mt.supportedMethods 
XMLRPC | hueman_xmlrpc_call Method = metaWeblog.getRecentPosts 
XMLRPC | hueman_xmlrpc_call Method = metaWeblog.getCategories 
XMLRPC | hueman_xmlrpc_call Method = metaWeblog.newPost 
XMLRPC | hueman_xmlrpc_call  method = metaWeblog.newPost 

Then, I see other filters I added when an article is created. I know I will probably end-up fixing the articles there but I’m sure this XMLRPC filters/actions should work.

From the logs, I see it go inside the if newPost and adding the filter ‘xmlrpc_wp_insert_post_data’ but it never executes the hueman_xmlrpc_wp_insert_post_data function… 🙁

3 s
3

It looks like the xmlrpc_prepare_post filter is only applied to the output of the wp_getPost and wp_getRevision methods of the wp_xmlrpc_server class.

It would be great if this code line:

do_action( 'xmlrpc_call', 'wp.newPost' );

would be replaced with extra input arguments, for example:

do_action( 'xmlrpc_call', 'wp.newPost', ..., $content_struct );

but that’s not going to happen according to this ticket.

So we need to find another way around this.

Possible workarounds:

Here are some untested ideas using the xmlrpc_call and the xmlrpc_wp_insert_post_data filters.

Modify input data before it’s inserted with wp_insert_posts():

/**
 * Prevent duplicate posts when doing wp.newPost via XML-RPC
 *
 * @see http://wordpress.stackexchange.com/a/157261/26350
 */

add_action( 'xmlrpc_call', 'wpse_xmlrpc_call' );

function wpse_xmlrpc_call( $method )
{
    if( 'wp.newPost' === $method )
        add_filter( 'xmlrpc_wp_insert_post_data', 'wpse_xmlrpc_wp_insert_post_data' );
}

function wpse_xmlrpc_wp_insert_post_data( $post_data )
{
    // Check if the post title exists:
    $tmp = get_page_by_title( 
        $post_data['post_title'], 
        OBJECT, 
        $post_data['post_type'] 
    );

    // Go from 'insert' to 'update' mode within wp_insert_post():
    if( is_object ( $tmp ) )
        $post_data['ID'] = $tmp->ID; 

    return $post_data;  
}

Here we try to find an existing post with the same title, during wp.newPost calls. If we find one, we add it’s ID to the $post_data array, so it will be updated instead.

Notice that we could also have modified the post_status instead with:

    $post_data['post_status'] = 'trash'; 

so all extra inserts are directed to the trash.

You could also try to create your own insert method via the xmlrpc_methods filter.

I hope you can modify this to your needs, assuming this will work 😉

Update: I’ve now tested this idea and it works, I can both trash the duplicated posts or update it directly.

Thanks to @DavidPeterson for noticing my silly PHP syntax errors from when I edited the code within the WPSE editor 😉

Leave a Comment