Daniel Dvorkin

My take on WordPress and related geekery

iStock_LaptopBeach

WordPress XML-RPC Helper Class

I found myself copying and pasting quite often the necessary code to make WordPress XML-RPC work. And what do we nerds do in those situations? Abstract!

This helper class will take the burden off of you. I’ll post the whole code here, and then explain each part.

abstract class MZAXMLRPC {
	protected $calls = Array();
	protected $namespace = "myxmlrpc";

	function __construct( $namespace ) {
		$this->namespace = $namespace;
		$reflector       = new ReflectionClass( $this );
		foreach ( $reflector->getMethods( ReflectionMethod::IS_PUBLIC ) as $method ) {
			if ( $method->isUserDefined() && $method->getDeclaringClass()->name != get_class() ) {
				$this->calls[] = $method->name;
			}
		}
		add_filter( 'xmlrpc_methods', array( $this, 'xmlrpc_methods' ) );
	}

	public function xmlrpc_methods( $methods ) {
		foreach ( $this->calls as $call ) {
			$methods[$this->namespace . "." . $call] = array( $this, "dispatch" );
		}
		return $methods;
	}

	public function dispatch( $args ) {
		global $wp_xmlrpc_server;

		$username = $args[1];
		$password = $args[2];
		$data     = $args[3];

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

		$call = $this->get_called_method();

		if ( method_exists( $this, $call ) ) {
			$status = call_user_func_array( array( $this, $call ), array( $data ) );
			return $status;
		} else {
			return "Method not allowed";
		}

	}

	private function get_called_method() {
		global $wp_xmlrpc_server;
		$call   = $wp_xmlrpc_server->message->methodName;
		$pieces = explode( ".", $call );
		return $pieces[1];
	}

}

This is an abstract class. You won’t instantiate objects out of it. What you’ll do is create a new class that inherits from MZAXMLRPC, and in it you’ll make public methods for each XML-RPC call you want to expose. I’ll post an example in a moment, but first let’s break this code into parts.

The constructor uses Reflection to find all the user-defined public methods of the child class that is inheriting from it. Then it will tell WordPress that we’re accepting XML-RPC calls for this methods. The XML-RPC methods are exposed with the name $namespace.$public_method_name.

All those new XML-RPC will arrive to the same method, dispatch. It will first validate the user/pass for the remote call, then it will check that effectively there is a method declared to take care of the XML-RPC call. If all validates ok it will dispatch the call to the appropriate method of the child class, passing along all the data that came through the XML-RPC server.

Enough gibberish already! The only thing you need to do is:

class MY_XMLRPC extends MZAXMLRPC {

	public function QuoteUpload( $data ) {

		if ( !isset( $data["author"] ) ) return "Missing 'author' parameter";

		if ( !isset( $data["quote"] ) ) return "Missing 'quote' parameter";

		$author = $data["author"];
		$quote  = $data["quote"];

		$new_post = array( 'post_status' => 'publish',
		                   'post_type'   => 'mzaquotes',
		                   'post_title'  => $quote );

		$new_post_id = wp_insert_post( $new_post );
		wp_set_post_terms( $new_post_id, $author, 'quote_author' );

		return "OK";
	}
}

new MY_XMLRPC( 'my_function' );

This little piece of code will expose a XML-RPC method called my_function.QuoteUpload. The parent class will deal with authentication and WordPress XML-RPC APIs for you.

Previous

How long users stay on Websites?

Next

Bash script to backup all your MySQL databases

2 Comments

  1. Max Cutler

    Interesting helper class, I wish we could just make this simpler for plugins in core.

    Two notes about your example:

    * On error conditions (e.g., ‘author’ or ‘quote’ missing), you should try to return an instance of IXR_Error (from wp-includes/class-IXR.php) so that XML-RPC clients can handle errors without looking for specific string values. Maybe you could add a helper method in the utility class that takes a string and returns an IXR_Error object.
    * Although the parent class will check that the user has a legitimate account, when using wp_insert_post or anything else that modifies the database, you should still really call “current_user_can( ‘edit_posts’ )” or similar.

    Also note that as of 3.4 release you’ll be able to create/update custom post types using the core wp.newPost/wp.editPost methods.

    • Hey Max, thanks for stopping by.

      Good suggestions! I’ll patch the class and update the post asap. Thanks

      And about 3.4, I’ve been following closely all the work you did. Really stocked to see so much work over the XML-RPC API. Congrats to you and the rest of the team.

Leave a Reply

Powered by WordPress & Theme by Anders Norén