As I mentioned before, the WordPress built-in XMLRPC functionality can do so much. Basic stuff that works for most. But, the power-users out there need more. And there's the rFC/rSQL helper plugin to do that. But there's also a drawback with rFC. It can run one function call at a time. For example it can only do this:
<?php
// Equivalent of a remote call_user_func() call
$wpapi->remoteCall('stick_post', $post_ID = 1); // Makes a post sticky
// Equivalent of a remote call_user_func_array() call
$wpapi->remoteCallArgs('stick_post', array($post_ID = 1)); // Makes a post sticky
?>
These functions are good but that's not enough. There are many scenarios where you need multiple functions executed at a time. It can be done with multiple calls but performance of such functionality is kind of a joke and many times, it's vital for a result of a function to be handled instantly.
That's why the following two functionalities emerged:
1 | The remoteCall() Method
<?php
// Create a new post and setup some extras
if($post_id = $wpapi->remoteCall('wp_insert_post', array(
// Post type can be anything
'post_type' => 'post',
// We schedule this one for tomorrow, same time
'post_date_gmt' => gmdate('Y-m-d H:i:s', strtotime('+1 day')),
// Publish it (or better say schedule it as it's for tomorrow)
'post_status' => 'publish',
// Setup the post information here
'post_title' => 'Title',
'post_content' => implode(PHP_EOL, array(
'Text',
'<!--more-->',
'More Text',
)),
'post_name' => 'Slug',
'post_excerpt' => 'Excerpt',
// Current user claims the post
'post_author' => 0,
), false)){
// Get the new post's permalink
$permalink = $wpapi->remoteCall('get_permalink', $post_id);
// Add custom fields using the eval wrap
// $argv[#] expands automatically to func_get_arg(#)
$metas = $wpapi->remoteEvalArgs(array(
'list($post_id, $metas) = array($argv[0], $argv[1]);',
'$results = array();',
'foreach($metas as $meta_name => $meta_value){',
'$results[$meta_name] = add_post_meta(',
'$post_id, $meta_name, $meta_value, true',
');',
'if(!$results[$meta_name]){',
'$results[$meta_name] = update_post_meta(',
'$post_id, $meta_name, $meta_value',
');',
'}',
'}',
'return $results;' // <-- Function body ends | Arguments start -->
), $post_id, $metas = array(
'custom_field1' => 'custom_field_value1',
'custom_field2' => 'custom_field_value2',
));
// Create new categories
// $argv expands automatically to func_get_args()
$category_ids = $wpapi->remoteEvalArgs(array(
'$categories = array_map("trim", array_filter($categories, "is_string"));',
'$categories = array_filter($categories, "strlen");',
'return array_combine($categories, array_map("wp_create_category", $categories));'
), 'Category1', 'Category2');
// Assign them to the post
$wpapi->remoteCall('wp_set_post_terms', $post_id, $category_ids, 'category', true);
$tags = array('Tag1', 'Tag2');
$wpapi->remoteCall('wp_set_post_terms', $post_id, $tags, 'post_tag', true);
// Make the post sticky
$wpapi->remoteCall('stick_post', $post_id); // unstick_post
}
?>
As you can see, the previous snippets sends several remoteCall() requests to the server. The more requests, the slower the result. And we have 7 of them just here (two are remoteEvalArgs() and that saves use at least two more requests).
removeCall() is good and there's situations where it's fit for use but those who want to remote manage WordPress like a boss need to learn the remoteEval() and removeEvalArgs() functions.
PS: remoteCall() and remoteCallArgs() are the remote equivalents of call_user_func() and call_user_func_array().
2 | The remoteEval() / removeEvalArgs() Methods
<?php
// Create a new post with eval_args and wp_insert_post
// Do more magic on it when it's created (categories, tags, metas, sticky)
// In the function body, $argv expands automatically to func_get_args()
$post_id = $wpapi->remoteEvalArgs(
// Actual function to be executed remotely STARTS here -->
<<<'PHP'
list($post_args, $categories, $tags, $metas) = $args;
// Create the post or bail on fail
if(!($post_id = wp_insert_post($post_args, false))){
return false;
}
$permalink = get_permalink($post_id);
// Add custom fields to the post
foreach($metas as $meta_name => $meta_value){
if(!add_post_meta($post_id, $meta_name, $meta_value, true)){
update_post_meta($post_id, $meta_name, $meta_value);
}
}
// Filter categories (strings, trimmed and not empty)
$categories = array_map("trim", array_filter($categories, "is_string"));
$categories = array_filter($categories, "strlen");
// Create the categories to later assign to the post
$category_ids = array_map("wp_create_category", $categories);
wp_set_post_terms($post_id, $category_ids, 'category', false); // Replace old
// Assign tags to posts (non hyerarchical terms don't need numeric IDs)
$tags = array_map("trim", array_filter($tags, "is_string"));
$tags = array_filter($tags, "strlen");
wp_set_post_terms($post_id, $tags, "post_tag", false); // Replace old
// Make the post sticky
stick_post($post_id); // unstick_post to reverse the effects
return array("ID" => $post_id, "URL" => $permalink);
PHP
// <-- Actual function to be executed remotely ENDS here
,
// Arguments for function to be executed remotely START here -->
$post_args = array(
// Post type can be anything
'post_type' => 'post',
// We schedule this one for tomorrow, same time
'post_date_gmt' => gmdate('Y-m-d H:i:s', strtotime('+1 day')),
// Publish it (or better say schedule it as it's for tomorrow)
'post_status' => 'publish',
// Setup the post information here
'post_title' => 'Title',
'post_content' => implode(PHP_EOL, array(
'Text',
'<!--more-->',
'More Text',
// Core deep-choice SPIN support
'(SPIN({{Spin|Blend}|Shuffle} Me))'
)),
'post_name' => 'Slug',
'post_excerpt' => 'Excerpt',
// Current user claims the post
'post_author' => 0,
),
$categories = array( // Categories
'Category 1',
'Category 2',
),
$tags = array( // Tags
'Tag 1',
'Tag 2',
),
$metas = array( // Custom Fields
'custom_field1' => 'custom_field_value1',
'custom_field2' => 'custom_field_value2',
)
// <-- Arguments for function to be executed remotely END here
);
?>
Now, this snippet does the same thing IN JUST ONE CALL! One request to the server and the entire thing is done. Response is so many times faster than the regular XMLRPC equivalent, event the many remoteCalls required to achieve the same results.
How does this snippet work?
remoteEval($php_code) takes raw PHP code and attempts to create_function() locally from it. If it succeeds the function is sent by XMLRPC, it's executed on the server and the result is shipped back. You control every single step. You control the code and you control the return value. MORE POWER TO YOU!
removeEvalArgs($php_code) does the same thing as remoteEval($php_code) but also sends any arguments found in the function call after $php_code. Those arguments are fed to the anonymous function and can be accessed with func_get_args(), func_get_arg(), func_num_args(). I'M SURE YOU'RE STARTING TO UNDERSTAND THE DIFFERENCE.
EvalArgs allows dynamic arguments that can be strings, arrays while Eval needs them inserted in the code. To achieve the same results with Eval() that you can achieve with EvalArgs() would sometimes be a monumental effort of variable exporting and inserting in a string.


