How to create a custom XML-RPC handler for WordPress

By , last updated August 17, 2019

This post will show how to get started with writing a custom XML-RPC handler through a WordPress plugin.

Remember to develop code locally in your own controlled environment before publishing your code to the wild. XML-RPC is known to have caused some security concerns.

We will create a new plugin, which is able to handle a custom XML-RPC call to WordPress. This code has only been tested with WordPress 4.0

Basics

The standard WordPress plugin header.

<?php

/**
 * Plugin Name: Studiofreya Media Upload
 * Plugin URI:
 * Description:
 * Version: 1.0.0
 * Author:
 * Author URI: http://studiofreya.com
 * License: GPL
 */

?>

A note about the WordPress license. It must be GPL or GPL compatible. By definition, all plugins for WordPress are required to be GPL.

The plan ahead is the following:

  1. Tell WordPress we are subscribing on the following XML-RPC method call.
  2. Provide a method as a callback when that method is called through XML-RPC.
  3. Validate user input.
  4. Receive some data.
  5. Return some data.

Implementation

Step 1: Create handler

Tell WordPress we will handle methods calling sf.uploadMediaFile in a method called handle_sf_upload_media_file.

Due to the nature of PHP, this is completely legal code. If we don’t specify anything, WordPress will just return a standard not found return code.

The first add_filter method tells WordPress, we’re interested in executing my_xmlrpc_methods when WordPress executes that bit.

Finally when WordPress executes xmlrpc_methods, our method is also executed, in which we will only add to it, and not mangle it in any way.

<?php

add_filter('xmlrpc_methods', 'my_xmlrpc_methods');
function my_xmlrpc_methods($methods)
{
	$methods['sf.uploadMediaFile'] = 'handle_sf_upload_media_file';
	return $methods;
}

Step 2: Actual handler

This method will be called when XML-RPC requests for sf.uploadMediaFile comes.

The signature is straight forward. Just a method with one input parameter (an array).

Remember to validate the inputs. No one will do it for you!

function handle_sf_upload_media_file($args)
{
	global $wp_xmlrpc_server;

	$wpxml = $wp_xmlrpc_server;

	// Parse the arguments. The order is BlogId, Username, Password.
	$blogid		= $args[0];
	$username	= $wpxml->escape($args[1]);
	$password	= $wpxml->escape($args[2]);
	$data 		= $args[3];

	// Let's run a check to see if credentials are okay
	if ( !$user = $wpxml->login($username, $password) )
	{
		return $wpxml->error;
	}

	if ( !current_user_can('upload_files') )
	{
		$wpxml->error = new IXR_Error( 401, __( 'You do not have permission to upload files.' ) );
		return $wpxml->error;
	}

Step 3: Validate user

At this point we’ve validated that the user is valid and registered, and that the user can upload files.

Here we’re preparing the application specific bits. The actual data received must be a contract between the sender and the receiver.

	// Let's gather the title and custom fields
	// At a later stage we'll send these via XML-RPC

	$post_type = "attachment";
	$mime = $data["type"];
	$overwrite = $data["overwrite"];
	$imgarray = $data["data"];
	$datefmt = date("Y/m");
	$uploaddir = wp_upload_dir($datefmt);
	$upsubdir = $uploaddir["subdir"];		// /2010/05
	$upurl = $uploaddir["url"];
	$bitsresult = "";
	$meta = array();						// attachment metadata
	$upfilefull = "";						// full path to the uploaded file
	$upurl = "";

	// Write bits
	foreach ($imgarray as $key => $value)
	{
		$imgname = $value["name"];
		$upimgname = "$upsubdir/$imgname";
		$imgwidth = $value["width"];
		$imgheight = $value["height"];
		$bits = $value["data"];
		$sizename = $value["sizename"];
		$full = $sizename == "" ? true : false;
		$thumb = $sizename == "thumbnail" ? true : false;

		// wp_upload_bits( $name, $deprecated, $bits, $time ) 

		$result = wp_upload_bits($imgname, null, $bits, $datefmt);
		$resultfile = $result["file"];
		$resultbasename = basename($resultfile);

		$bitsresult .= print_r($result, true);

		if ($thumbnail)
		{
			$meta["hwstring_small"] = "height='$imgwidth' width='$imgheight'";
		}

		if ($full)
		{
			$meta["width"]			= $imgwidth;
			$meta["height"]			= $imgheight;
			$meta["file"] 			= $resultbasename;

			$upfilefull 			= $result["file"];
			$upurl 					= $result["url"];
			$meta["image_meta"] 	= wp_read_image_metadata($upfilefull);
		}
		else
		{
			$meta["sizes"][$sizename]["width"]	= $imgwidth;
			$meta["sizes"][$sizename]["height"]	= $imgheight;
			$meta["sizes"][$sizename]["file"] 	= $resultbasename;
		}

	}

Step 4: Prepare data

We’ve gathered data in the format in which it was sent to the server. How the data is structured is entirely up to you.

In the next step we’re inserting data into the WordPress database through the WordPress API.

Again, this is application specific and it just serves as an example.


	$attachment = array(
		"post_mime_type"	=> "$mime",
		"post_title"		=> basename($meta["file"]),
		"post_content"		=> "",
		"post_status"		=> "inherit"
	);

	$attnid = wp_insert_attachment($attachment, $upfilefull, 0);
	wp_update_attachment_metadata($attnid, $meta);

	$struct = array(
		"id" => "$attnid",
		"file" => "filecontent",
		"url" => "url",
		"type" => "typ",
		"args" => "$arg",
		"bitsresult" => $bitsresult
	);

	return $struct;
}

?>

Step 5: Return some data

Finally some data is sent back to the browser. Through WordPress, it’s just as easy as returning an array with the given data.

What happens behind the covers is XML-RPC doing magic serializing the array to the XML-RPC format.

This is just a guide covering the basics of creating a custom XML-RPC handler for WordPress.