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: 15%

4 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!

  4. Pierinux on June 6th, 2011

    Fantastic, it worked straight away. Thank you, you saved me lots of work.

Vale Presente