Patching Wordpress xmlrpc to filter post using categories

I´m building an application to integrate data between some blog apps (Wordpress and Blogger for example) and then faced a problem when I was trying to filter some posts using a specific category.

My app is AppEngine based and I´m algo using xmlrpclib and wordpress-library to make web calls. After playing a while with wordpress-library, I got some things missing and started to patch to make it work for me.

Basically I´ve added some stuff like post status, custom fields and filter posts by categories. I dont know why Wordpress don´t give a simple wrapper function inside xmlrpc.php to make things generic, allowing other users to extend functionalities. Anyway, I did it and will suggest to add support for it, because makes easier to give some maitenance.

To make the patch, you must understand the get_post function, exposed on wp-includes/post.php. Looking inside, the function body is:

function get_posts($args = null) {
    $defaults = array(
                             'numberposts' => 5, 'offset' => 0,
                             'category' => 0, 'orderby' => 'post_date',
                             'order' => 'DESC', 'include' => '',
                             'exclude' => '', 'meta_key' => '',
                             'meta_value' =>'', 'post_type' => 'post',
                             'suppress_filters' => true
                             );

…. continue

Based on that function, it becomes easier to make your on function on xmlrpc.php:

First:  Include your function entrypoint on $this->methods array. My implementation is ‘wp.getPostsByCategory’   => ‘this:wp_getPostsByCategory’. I decided to use this name, because it´s a specific function for wordpress, not a MetaWebLog structure.

Second: Change mw_wp_get_recent_posts to receive other args and change the call wp_get_recent_posts($num_posts) to use get_posts . You´ll also need to change the ways that arrays are accessed, because get_posts function returns an Object, instead of array. Example: $entry['ID'] becomes $entry->ID.

After that, just make your call to wp.getPostsByCategory, passing username, password and categoryId. Like magic :D

Just to finish, a simple python example using xmlrpclib to call a server method:

import xmlrpclib

server = xmlrpclib.ServerProxy("http://www.mywebsite.com/xmlrpc.php")
posts = server.wp.getPostsByCategory(categoryId, 'user', 'password')

for post in posts:
   print post['post_title']

.
Piece of cake ! If you have any doubt, leave a comment here.

Bookmarksbookmark bookmark bookmark bookmark bookmark bookmark

Popularity: 13%

3 Comments so far

  1. dee volume on May 8th, 2009

    Hi Robson,
    I’m trying to employ some of what you’ve written in order to do the same thing, but for a flash project
    in terms of the xmlrpc.php -
    I’m not sure if I’ve totally understood the steps…

    1 in xmlrpc.php I followed your step and added ‘wp.getPostsByCategory’ => ‘this:wp_getPostsByCategory’,
    to the $this-methods array

    but,
    2 is where im not sure if im following you.
    i copy/pasted the mw_getRecentPosts function, renamed my new function wp_getPostsByCategory, and amended the first few lines to use

    function wp_getPostsByCategory($args) {

    $this->escape($args);
    $blog_ID = (int) $args[0];
    $user_login = $args[1];
    $user_pass = $args[2];
    $num_posts = (int) $args[3];
    $cat = (int) $args[4];

    if (!$this->login_pass_ok($user_login, $user_pass)) {
    return $this->error;
    }

    do_action(‘xmlrpc_call’, ‘wp.getPostsByCategory’);

    $posts_list = get_posts( “post_type=post&post_status=all&numberposts={$num_posts}&category={$cat}” );

    after which, everything is the same as the original mw_getRecentPosts function

    while my call to:
    metaWeblog.getRecentPosts
    worked succssfully calling my:
    wp.getPostsByCategory
    doesnt work :(

    have i misunderstood what you wrote?

    thanks!

  2. admin on May 8th, 2009

    Apparently, you´ve done everything correctly. By the way, I´m copying my function here and then you can copy, paste and test.

    Anyway, if you have a public url, I can make a call and test to see if it´s ok.

    Cheers


    function wp_getPostsByCategory($args){

    $this->escape($args);
    $catid = (int) $args[0];
    $username = $args[1];
    $password = $args[2];

    if ( !$this->login_pass_ok( $username, $password ) )
    return $this->error;

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

    //$posts_list = get_posts('category='.$catid);
    $posts_list = get_posts('category='.$catid);

    if (!$posts_list) {
    return array( );
    }

    set_current_user( 0, $user_login );

    $i=0;
    foreach ($posts_list as $entry) {

    setup_postdata($entry);

    //if( !current_user_can( 'edit_post', $entry->ID ) )
    // continue;

    $post_date = mysql2date('Ymd\TH:i:s', $entry->post_date);
    $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry->post_date_gmt);

    $tagnames = array();
    $tags = wp_get_post_tags( $entry->ID );
    if ( !empty( $tags ) ) {
    foreach ( $tags as $tag ) {
    $tagnames[] = $tag->name;
    }
    $tagnames = implode( ', ', $tagnames );
    } else {
    $tagnames = '';
    }

    $post = get_extended($entry->post_content);
    $link = post_permalink($entry->ID);

    $allow_comments = ('open' == $entry->comment_status) ? 1 : 0;
    $allow_pings = ('open' == $entry->ping_status) ? 1 : 0;

    // Consider future posts as published
    if( $entry->post_status === 'future' ) {
    $entry->post_status = 'publish';
    }

    $struct[] = array(
    'dateCreated' => new IXR_Date($post_date),
    'userid' => $entry->post_author,
    'postid' => $entry->ID,
    // usando content
    'description' => $post['main'],
    'title' => $entry->post_title,
    'link' => $link,
    'permaLink' => $link,
    // commented out because no other tool seems to use this
    //'content' => $entry->post_content,
    'categories' => '',
    'mt_excerpt' => $entry->post_excerpt,
    'mt_text_more' => $post->extended,
    'mt_allow_comments' => $allow_comments,
    'mt_allow_pings' => $allow_pings,
    'mt_keywords' => $tagnames,
    'wp_slug' => $entry->post_name,
    'wp_password' => $entry->post_password,
    'wp_author_id' => '',
    'wp_author_display_name' => $author->display_name,
    'date_created_gmt' => new IXR_Date($post_date_gmt),
    'post_status' => $entry->post_status,
    'custom_fields' => $this->get_custom_fields($entry->ID)
    );

    }

    $recent_posts = array();
    for ($j=0; $j<count($struct); $j++) {
    array_push($recent_posts, $struct[$j]);
    }

    //print_r($struct);

    return $recent_posts;

    }

  3. dee volume on May 8th, 2009

    you know what, i hadn’t changed everything from array elements to object properties of $entry as you had specified, so my fault! it works perfectly!
    very grateful for this!