XMLRPC and Underscored custom fields

I was creating my application to automate all of my blogs from my desktop.
Target, I’ll post blog. That’s all.
I used XMLRPC service, as you know “xmlrpc.php”.

I built many of parts, near to done… But stucked at custom fields which are starting with (_) an underscore.
I would like to save as “_thumbnail_id” => (int)number. Nothing happened.

But when I tried “thumbnail_id” or something like that without starting with underscore. It’s ok. Working well but start with underscore…

I need it for determine featured image of post. Without that tag; I couldn’t. And I don’t know alternatives.

I find this: https://wordpress.org/support/topic/how-can-i-change-protected-params-xmlrpc
But not solving my problem. I don’t want to change wordpress files. If I have to, I can write a small script without RPC.

Any help will be FANTASTIC!

2 Answers
2

Playing with XML-RPC and underscored custom fields:

Let’s say we want to set the featured image to a given post with $remote_post_id.

We want it to be the attachment with ID equal to 300, so we want _thumbnail_id to be 300.

Here are three methods how one could achieve that:

Method #1 – Using post_thumbnail

It’s possible to update/add the featured image with the post_thumbnail parameter:

$result = $client->query( 
    'wp.editPost', 
    array(
        $blog_id,
        $username,
        $password,
        $remote_post_id,
        $post_data = array(
            'post_thumbnail' => '300',
        ),
    ) 
);

as can be seen [here in the wp_xmlrpc_server][1] class.

Method #2 – Using custom_fields with meta_id

If we want to update a custom field of a post, we must know it’s database meta_id value.

But how do we know the meta_id?

The custom fields are actually included by default, when we fetch a post with:

$result = $client->query( 
    'wp.getPost', 
    array(
        $blog_id,
        $username,
        $password,
        $remote_post_id,
    ) 
);

If the post has a featured post thumbnail, then the above result will contain this part:

<member>
    <name>custom_fields</name>
    <value>
        <array>
            <data>
                <value>
                    <struct>
                        <member>
                            <name>id</name>
                            <value>
                                <string>560</string>
                            </value>
                        </member>
                        <member>
                            <name>key</name>
                            <value>
                                <string>_thumbnail_id</string>
                            </value>
                        </member>
                        <member>
                            <name>value</name>
                            <value>
                                <string>200</string>
                            </value>
                        </member>
                    </struct>
                </value>
            </data>
        </array>
    </value>
 </member>

where the meta_id is for example 560 and the old meta_value is 200.

Now we can update the meta value of _thumbnail_id with our new value:

$result = $client->query( 
    'wp.editPost', 
    array(
        $blog_id,
        $username,
        $password,
        $remote_post_id,
        $post_data = array(
            'custom_fields' => array( 
                array( 
                    'id'    => '560', 
                    'key'   => '_thumbnail_id', 
                    'value' => 300 
                )
            ),
        ),
    ) 
);

Notice that if we skip the meta_id part, we would only run add_post_meta(), instead of the [update_metadata_by_mid()][2] that was
introduced in this trac. We must also have the edit_post_meta capability.

But this is not the whole story, because meta keys that begin with underscore (_) are protected.

We can fix that by using the [register_meta()][3] function on the remote site.

For example:

/**
 * Unprotect the _thumbnail_id meta key to allow updates via XML-RPC 
 * We need to set this up on the remote site.
 */

add_action( 'init', function() {
        register_meta( 'post', '_thumbnail_id', 'absint', '__return_true' );
});

to unprotect the _thumbnail_id meta key. I first tried the intval as a sanitization callback but that didn’t work.

We could use a similar setup for other protected meta keys.

Method #3 Using a custom XML-RPC method.

As @MarkKaplun mentioned in his answer, we could extend the XML-RPC setup to our needs. We could for example use the xmlrpc_methods filter to add our own method.

The Codex provides more information on that matter.

References:

Here are some links that helped me while testing this:

  • https://github.com/WordPress/WordPress/blob/master/wp-includes/class-wp-xmlrpc-server.php

  • XML RPC @Codex

  • Trac ticket #17850 @wp.org

  • update_metadata_by_mid()

  • Automattics “syndication” repo @GitHub: class-syndication-wp-xmlrpc-client.php

  • Content Type Standards @GitHub (props @kaiser) – and more specifically this issue, which explains the use case for register_meta() a bit more in detail, in the same repo.

Leave a Comment