Make WordPress Core


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/xmlrpc.php

    r16804 r16221  
    33 * XML-RPC protocol support for WordPress
    44 *
    5  * @license GPL v2 <./license.txt>
    65 * @package WordPress
    76 */
     
    5453include_once(ABSPATH . 'wp-admin/includes/admin.php');
    5554include_once(ABSPATH . WPINC . '/class-IXR.php');
     55include_once(ABSPATH . WPINC . '/class-wp-xmlrpc-server.php');
    5656
    5757// Turn off all warnings and errors.
     
    9999    logIO("I", $HTTP_RAW_POST_DATA);
    100100
    101 /**
    102  * WordPress XMLRPC server implementation.
    103  *
    104  * Implements compatability for Blogger API, MetaWeblog API, MovableType, and
    105  * pingback. Additional WordPress API for managing comments, pages, posts,
    106  * options, etc.
    107  *
    108  * Since WordPress 2.6.0, WordPress XMLRPC server can be disabled in the
    109  * administration panels.
    110  *
    111  * @package WordPress
    112  * @subpackage Publishing
    113  * @since 1.5.0
    114  */
    115 class wp_xmlrpc_server extends IXR_Server {
     101// Allow for a plugin to insert a different class to handle requests.
     102$wp_xmlrpc_server_class = apply_filters('wp_xmlrpc_server_class', 'wp_xmlrpc_server');
     103$wp_xmlrpc_server = new $wp_xmlrpc_server_class;
    116104
    117     /**
    118      * Register all of the XMLRPC methods that XMLRPC server understands.
    119      *
    120      * PHP4 constructor and sets up server and method property. Passes XMLRPC
    121      * methods through the 'xmlrpc_methods' filter to allow plugins to extend
    122      * or replace XMLRPC methods.
    123      *
    124      * @since 1.5.0
    125      *
    126      * @return wp_xmlrpc_server
    127      */
    128     function wp_xmlrpc_server() {
    129         $this->methods = array(
    130             // WordPress API
    131             'wp.getUsersBlogs'      => 'this:wp_getUsersBlogs',
    132             'wp.getPage'            => 'this:wp_getPage',
    133             'wp.getPages'           => 'this:wp_getPages',
    134             'wp.newPage'            => 'this:wp_newPage',
    135             'wp.deletePage'         => 'this:wp_deletePage',
    136             'wp.editPage'           => 'this:wp_editPage',
    137             'wp.getPageList'        => 'this:wp_getPageList',
    138             'wp.getAuthors'         => 'this:wp_getAuthors',
    139             'wp.getCategories'      => 'this:mw_getCategories',     // Alias
    140             'wp.getTags'            => 'this:wp_getTags',
    141             'wp.newCategory'        => 'this:wp_newCategory',
    142             'wp.deleteCategory'     => 'this:wp_deleteCategory',
    143             'wp.suggestCategories'  => 'this:wp_suggestCategories',
    144             'wp.uploadFile'         => 'this:mw_newMediaObject',    // Alias
    145             'wp.getCommentCount'    => 'this:wp_getCommentCount',
    146             'wp.getPostStatusList'  => 'this:wp_getPostStatusList',
    147             'wp.getPageStatusList'  => 'this:wp_getPageStatusList',
    148             'wp.getPageTemplates'   => 'this:wp_getPageTemplates',
    149             'wp.getOptions'         => 'this:wp_getOptions',
    150             'wp.setOptions'         => 'this:wp_setOptions',
    151             'wp.getComment'         => 'this:wp_getComment',
    152             'wp.getComments'        => 'this:wp_getComments',
    153             'wp.deleteComment'      => 'this:wp_deleteComment',
    154             'wp.editComment'        => 'this:wp_editComment',
    155             'wp.newComment'         => 'this:wp_newComment',
    156             'wp.getCommentStatusList' => 'this:wp_getCommentStatusList',
    157 
    158             // Blogger API
    159             'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
    160             'blogger.getUserInfo' => 'this:blogger_getUserInfo',
    161             'blogger.getPost' => 'this:blogger_getPost',
    162             'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
    163             'blogger.getTemplate' => 'this:blogger_getTemplate',
    164             'blogger.setTemplate' => 'this:blogger_setTemplate',
    165             'blogger.newPost' => 'this:blogger_newPost',
    166             'blogger.editPost' => 'this:blogger_editPost',
    167             'blogger.deletePost' => 'this:blogger_deletePost',
    168 
    169             // MetaWeblog API (with MT extensions to structs)
    170             'metaWeblog.newPost' => 'this:mw_newPost',
    171             'metaWeblog.editPost' => 'this:mw_editPost',
    172             'metaWeblog.getPost' => 'this:mw_getPost',
    173             'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
    174             'metaWeblog.getCategories' => 'this:mw_getCategories',
    175             'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
    176 
    177             // MetaWeblog API aliases for Blogger API
    178             // see http://www.xmlrpc.com/stories/storyReader$2460
    179             'metaWeblog.deletePost' => 'this:blogger_deletePost',
    180             'metaWeblog.getTemplate' => 'this:blogger_getTemplate',
    181             'metaWeblog.setTemplate' => 'this:blogger_setTemplate',
    182             'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
    183 
    184             // MovableType API
    185             'mt.getCategoryList' => 'this:mt_getCategoryList',
    186             'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
    187             'mt.getPostCategories' => 'this:mt_getPostCategories',
    188             'mt.setPostCategories' => 'this:mt_setPostCategories',
    189             'mt.supportedMethods' => 'this:mt_supportedMethods',
    190             'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
    191             'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
    192             'mt.publishPost' => 'this:mt_publishPost',
    193 
    194             // PingBack
    195             'pingback.ping' => 'this:pingback_ping',
    196             'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
    197 
    198             'demo.sayHello' => 'this:sayHello',
    199             'demo.addTwoNumbers' => 'this:addTwoNumbers'
    200         );
    201 
    202         $this->initialise_blog_option_info( );
    203         $this->methods = apply_filters('xmlrpc_methods', $this->methods);
    204     }
    205 
    206     function serve_request() {
    207         $this->IXR_Server($this->methods);
    208     }
    209 
    210     /**
    211      * Test XMLRPC API by saying, "Hello!" to client.
    212      *
    213      * @since 1.5.0
    214      *
    215      * @param array $args Method Parameters.
    216      * @return string
    217      */
    218     function sayHello($args) {
    219         return 'Hello!';
    220     }
    221 
    222     /**
    223      * Test XMLRPC API by adding two numbers for client.
    224      *
    225      * @since 1.5.0
    226      *
    227      * @param array $args Method Parameters.
    228      * @return int
    229      */
    230     function addTwoNumbers($args) {
    231         $number1 = $args[0];
    232         $number2 = $args[1];
    233         return $number1 + $number2;
    234     }
    235 
    236     /**
    237      * Check user's credentials.
    238      *
    239      * @since 1.5.0
    240      *
    241      * @param string $user_login User's username.
    242      * @param string $user_pass User's password.
    243      * @return bool Whether authentication passed.
    244      * @deprecated use wp_xmlrpc_server::login
    245      * @see wp_xmlrpc_server::login
    246      */
    247     function login_pass_ok($user_login, $user_pass) {
    248         if ( !get_option( 'enable_xmlrpc' ) ) {
    249             $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
    250             return false;
    251         }
    252 
    253         if (!user_pass_ok($user_login, $user_pass)) {
    254             $this->error = new IXR_Error(403, __('Bad login/pass combination.'));
    255             return false;
    256         }
    257         return true;
    258     }
    259 
    260     /**
    261      * Log user in.
    262      *
    263      * @since 2.8
    264      *
    265      * @param string $username User's username.
    266      * @param string $password User's password.
    267      * @return mixed WP_User object if authentication passed, false otherwise
    268      */
    269     function login($username, $password) {
    270         if ( !get_option( 'enable_xmlrpc' ) ) {
    271             $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.  An admin user can enable them at %s'),  admin_url('options-writing.php') ) );
    272             return false;
    273         }
    274 
    275         $user = wp_authenticate($username, $password);
    276 
    277         if (is_wp_error($user)) {
    278             $this->error = new IXR_Error(403, __('Bad login/pass combination.'));
    279             return false;
    280         }
    281 
    282         wp_set_current_user( $user->ID );
    283         return $user;
    284     }
    285 
    286     /**
    287      * Sanitize string or array of strings for database.
    288      *
    289      * @since 1.5.2
    290      *
    291      * @param string|array $array Sanitize single string or array of strings.
    292      * @return string|array Type matches $array and sanitized for the database.
    293      */
    294     function escape(&$array) {
    295         global $wpdb;
    296 
    297         if (!is_array($array)) {
    298             return($wpdb->escape($array));
    299         } else {
    300             foreach ( (array) $array as $k => $v ) {
    301                 if ( is_array($v) ) {
    302                     $this->escape($array[$k]);
    303                 } else if ( is_object($v) ) {
    304                     //skip
    305                 } else {
    306                     $array[$k] = $wpdb->escape($v);
    307                 }
    308             }
    309         }
    310     }
    311 
    312     /**
    313      * Retrieve custom fields for post.
    314      *
    315      * @since 2.5.0
    316      *
    317      * @param int $post_id Post ID.
    318      * @return array Custom fields, if exist.
    319      */
    320     function get_custom_fields($post_id) {
    321         $post_id = (int) $post_id;
    322 
    323         $custom_fields = array();
    324 
    325         foreach ( (array) has_meta($post_id) as $meta ) {
    326             // Don't expose protected fields.
    327             if ( strpos($meta['meta_key'], '_wp_') === 0 ) {
    328                 continue;
    329             }
    330 
    331             $custom_fields[] = array(
    332                 "id"    => $meta['meta_id'],
    333                 "key"   => $meta['meta_key'],
    334                 "value" => $meta['meta_value']
    335             );
    336         }
    337 
    338         return $custom_fields;
    339     }
    340 
    341     /**
    342      * Set custom fields for post.
    343      *
    344      * @since 2.5.0
    345      *
    346      * @param int $post_id Post ID.
    347      * @param array $fields Custom fields.
    348      */
    349     function set_custom_fields($post_id, $fields) {
    350         $post_id = (int) $post_id;
    351 
    352         foreach ( (array) $fields as $meta ) {
    353             if ( isset($meta['id']) ) {
    354                 $meta['id'] = (int) $meta['id'];
    355 
    356                 if ( isset($meta['key']) ) {
    357                     update_meta($meta['id'], $meta['key'], $meta['value']);
    358                 }
    359                 else {
    360                     delete_meta($meta['id']);
    361                 }
    362             }
    363             else {
    364                 $_POST['metakeyinput'] = $meta['key'];
    365                 $_POST['metavalue'] = $meta['value'];
    366                 add_meta($post_id);
    367             }
    368         }
    369     }
    370 
    371     /**
    372      * Set up blog options property.
    373      *
    374      * Passes property through 'xmlrpc_blog_options' filter.
    375      *
    376      * @since 2.6.0
    377      */
    378     function initialise_blog_option_info( ) {
    379         global $wp_version;
    380 
    381         $this->blog_options = array(
    382             // Read only options
    383             'software_name'     => array(
    384                 'desc'          => __( 'Software Name' ),
    385                 'readonly'      => true,
    386                 'value'         => 'WordPress'
    387             ),
    388             'software_version'  => array(
    389                 'desc'          => __( 'Software Version' ),
    390                 'readonly'      => true,
    391                 'value'         => $wp_version
    392             ),
    393             'blog_url'          => array(
    394                 'desc'          => __( 'Site URL' ),
    395                 'readonly'      => true,
    396                 'option'        => 'siteurl'
    397             ),
    398 
    399             // Updatable options
    400             'time_zone'         => array(
    401                 'desc'          => __( 'Time Zone' ),
    402                 'readonly'      => false,
    403                 'option'        => 'gmt_offset'
    404             ),
    405             'blog_title'        => array(
    406                 'desc'          => __( 'Site Title' ),
    407                 'readonly'      => false,
    408                 'option'            => 'blogname'
    409             ),
    410             'blog_tagline'      => array(
    411                 'desc'          => __( 'Site Tagline' ),
    412                 'readonly'      => false,
    413                 'option'        => 'blogdescription'
    414             ),
    415             'date_format'       => array(
    416                 'desc'          => __( 'Date Format' ),
    417                 'readonly'      => false,
    418                 'option'        => 'date_format'
    419             ),
    420             'time_format'       => array(
    421                 'desc'          => __( 'Time Format' ),
    422                 'readonly'      => false,
    423                 'option'        => 'time_format'
    424             ),
    425             'users_can_register'    => array(
    426                 'desc'          => __( 'Allow new users to sign up' ),
    427                 'readonly'      => false,
    428                 'option'        => 'users_can_register'
    429             )
    430         );
    431 
    432         $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options );
    433     }
    434 
    435     /**
    436      * Retrieve the blogs of the user.
    437      *
    438      * @since 2.6.0
    439      *
    440      * @param array $args Method parameters.
    441      * @return array
    442      */
    443     function wp_getUsersBlogs( $args ) {
    444         global $current_site;
    445         // If this isn't on WPMU then just use blogger_getUsersBlogs
    446         if ( !is_multisite() ) {
    447             array_unshift( $args, 1 );
    448             return $this->blogger_getUsersBlogs( $args );
    449         }
    450 
    451         $this->escape( $args );
    452 
    453         $username = $args[0];
    454         $password = $args[1];
    455 
    456         if ( !$user = $this->login($username, $password) )
    457             return $this->error;
    458 
    459 
    460         do_action( 'xmlrpc_call', 'wp.getUsersBlogs' );
    461 
    462         $blogs = (array) get_blogs_of_user( $user->ID );
    463         $struct = array( );
    464 
    465         foreach ( $blogs as $blog ) {
    466             // Don't include blogs that aren't hosted at this site
    467             if ( $blog->site_id != $current_site->id )
    468                 continue;
    469 
    470             $blog_id = $blog->userblog_id;
    471             switch_to_blog($blog_id);
    472             $is_admin = current_user_can('manage_options');
    473 
    474             $struct[] = array(
    475                 'isAdmin'       => $is_admin,
    476                 'url'           => get_option( 'home' ) . '/',
    477                 'blogid'        => $blog_id,
    478                 'blogName'      => get_option( 'blogname' ),
    479                 'xmlrpc'        => site_url( 'xmlrpc.php' )
    480             );
    481 
    482             restore_current_blog( );
    483         }
    484 
    485         return $struct;
    486     }
    487 
    488     /**
    489      * Retrieve page.
    490      *
    491      * @since 2.2.0
    492      *
    493      * @param array $args Method parameters.
    494      * @return array
    495      */
    496     function wp_getPage($args) {
    497         $this->escape($args);
    498 
    499         $blog_id    = (int) $args[0];
    500         $page_id    = (int) $args[1];
    501         $username   = $args[2];
    502         $password   = $args[3];
    503 
    504         if ( !$user = $this->login($username, $password) ) {
    505             return $this->error;
    506         }
    507 
    508         if ( !current_user_can( 'edit_page', $page_id ) )
    509             return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) );
    510 
    511         do_action('xmlrpc_call', 'wp.getPage');
    512 
    513         // Lookup page info.
    514         $page = get_page($page_id);
    515 
    516         // If we found the page then format the data.
    517         if ( $page->ID && ($page->post_type == "page") ) {
    518             // Get all of the page content and link.
    519             $full_page = get_extended($page->post_content);
    520             $link = post_permalink($page->ID);
    521 
    522             // Get info the page parent if there is one.
    523             $parent_title = "";
    524             if ( !empty($page->post_parent) ) {
    525                 $parent = get_page($page->post_parent);
    526                 $parent_title = $parent->post_title;
    527             }
    528 
    529             // Determine comment and ping settings.
    530             $allow_comments = comments_open($page->ID) ? 1 : 0;
    531             $allow_pings = pings_open($page->ID) ? 1 : 0;
    532 
    533             // Format page date.
    534             $page_date = mysql2date("Ymd\TH:i:s", $page->post_date, false);
    535             $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt, false);
    536 
    537             // For drafts use the GMT version of the date
    538             if ( $page->post_status == 'draft' )
    539                 $page_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page->post_date ), 'Ymd\TH:i:s' );
    540 
    541             // Pull the categories info together.
    542             $categories = array();
    543             foreach ( wp_get_post_categories($page->ID) as $cat_id ) {
    544                 $categories[] = get_cat_name($cat_id);
    545             }
    546 
    547             // Get the author info.
    548             $author = get_userdata($page->post_author);
    549 
    550             $page_template = get_post_meta( $page->ID, '_wp_page_template', true );
    551             if ( empty( $page_template ) )
    552                 $page_template = 'default';
    553 
    554             $page_struct = array(
    555                 "dateCreated"           => new IXR_Date($page_date),
    556                 "userid"                => $page->post_author,
    557                 "page_id"               => $page->ID,
    558                 "page_status"           => $page->post_status,
    559                 "description"           => $full_page["main"],
    560                 "title"                 => $page->post_title,
    561                 "link"                  => $link,
    562                 "permaLink"             => $link,
    563                 "categories"            => $categories,
    564                 "excerpt"               => $page->post_excerpt,
    565                 "text_more"             => $full_page["extended"],
    566                 "mt_allow_comments"     => $allow_comments,
    567                 "mt_allow_pings"        => $allow_pings,
    568                 "wp_slug"               => $page->post_name,
    569                 "wp_password"           => $page->post_password,
    570                 "wp_author"             => $author->display_name,
    571                 "wp_page_parent_id"     => $page->post_parent,
    572                 "wp_page_parent_title"  => $parent_title,
    573                 "wp_page_order"         => $page->menu_order,
    574                 "wp_author_id"          => $author->ID,
    575                 "wp_author_display_name"    => $author->display_name,
    576                 "date_created_gmt"      => new IXR_Date($page_date_gmt),
    577                 "custom_fields"         => $this->get_custom_fields($page_id),
    578                 "wp_page_template"      => $page_template
    579             );
    580 
    581             return($page_struct);
    582         }
    583         // If the page doesn't exist indicate that.
    584         else {
    585             return(new IXR_Error(404, __("Sorry, no such page.")));
    586         }
    587     }
    588 
    589     /**
    590      * Retrieve Pages.
    591      *
    592      * @since 2.2.0
    593      *
    594      * @param array $args Method parameters.
    595      * @return array
    596      */
    597     function wp_getPages($args) {
    598         $this->escape($args);
    599 
    600         $blog_id    = (int) $args[0];
    601         $username   = $args[1];
    602         $password   = $args[2];
    603         $num_pages  = isset($args[3]) ? (int) $args[3] : 10;
    604 
    605         if ( !$user = $this->login($username, $password) )
    606             return $this->error;
    607 
    608         if ( !current_user_can( 'edit_pages' ) )
    609             return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
    610 
    611         do_action('xmlrpc_call', 'wp.getPages');
    612 
    613         $pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) );
    614         $num_pages = count($pages);
    615 
    616         // If we have pages, put together their info.
    617         if ( $num_pages >= 1 ) {
    618             $pages_struct = array();
    619 
    620             for ( $i = 0; $i < $num_pages; $i++ ) {
    621                 $page = wp_xmlrpc_server::wp_getPage(array(
    622                     $blog_id, $pages[$i]->ID, $username, $password
    623                 ));
    624                 $pages_struct[] = $page;
    625             }
    626 
    627             return($pages_struct);
    628         }
    629         // If no pages were found return an error.
    630         else {
    631             return(array());
    632         }
    633     }
    634 
    635     /**
    636      * Create new page.
    637      *
    638      * @since 2.2.0
    639      *
    640      * @param array $args Method parameters.
    641      * @return unknown
    642      */
    643     function wp_newPage($args) {
    644         // Items not escaped here will be escaped in newPost.
    645         $username   = $this->escape($args[1]);
    646         $password   = $this->escape($args[2]);
    647         $page       = $args[3];
    648         $publish    = $args[4];
    649 
    650         if ( !$user = $this->login($username, $password) )
    651             return $this->error;
    652 
    653         do_action('xmlrpc_call', 'wp.newPage');
    654 
    655         // Make sure the user is allowed to add new pages.
    656         if ( !current_user_can("publish_pages") )
    657             return(new IXR_Error(401, __("Sorry, you cannot add new pages.")));
    658 
    659         // Mark this as content for a page.
    660         $args[3]["post_type"] = "page";
    661 
    662         // Let mw_newPost do all of the heavy lifting.
    663         return($this->mw_newPost($args));
    664     }
    665 
    666     /**
    667      * Delete page.
    668      *
    669      * @since 2.2.0
    670      *
    671      * @param array $args Method parameters.
    672      * @return bool True, if success.
    673      */
    674     function wp_deletePage($args) {
    675         $this->escape($args);
    676 
    677         $blog_id    = (int) $args[0];
    678         $username   = $args[1];
    679         $password   = $args[2];
    680         $page_id    = (int) $args[3];
    681 
    682         if ( !$user = $this->login($username, $password) )
    683             return $this->error;
    684 
    685         do_action('xmlrpc_call', 'wp.deletePage');
    686 
    687         // Get the current page based on the page_id and
    688         // make sure it is a page and not a post.
    689         $actual_page = wp_get_single_post($page_id, ARRAY_A);
    690         if ( !$actual_page || ($actual_page["post_type"] != "page") )
    691             return(new IXR_Error(404, __("Sorry, no such page.")));
    692 
    693         // Make sure the user can delete pages.
    694         if ( !current_user_can("delete_page", $page_id) )
    695             return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page.")));
    696 
    697         // Attempt to delete the page.
    698         $result = wp_delete_post($page_id);
    699         if ( !$result )
    700             return(new IXR_Error(500, __("Failed to delete the page.")));
    701 
    702         return(true);
    703     }
    704 
    705     /**
    706      * Edit page.
    707      *
    708      * @since 2.2.0
    709      *
    710      * @param array $args Method parameters.
    711      * @return unknown
    712      */
    713     function wp_editPage($args) {
    714         // Items not escaped here will be escaped in editPost.
    715         $blog_id    = (int) $args[0];
    716         $page_id    = (int) $this->escape($args[1]);
    717         $username   = $this->escape($args[2]);
    718         $password   = $this->escape($args[3]);
    719         $content    = $args[4];
    720         $publish    = $args[5];
    721 
    722         if ( !$user = $this->login($username, $password) )
    723             return $this->error;
    724 
    725         do_action('xmlrpc_call', 'wp.editPage');
    726 
    727         // Get the page data and make sure it is a page.
    728         $actual_page = wp_get_single_post($page_id, ARRAY_A);
    729         if ( !$actual_page || ($actual_page["post_type"] != "page") )
    730             return(new IXR_Error(404, __("Sorry, no such page.")));
    731 
    732         // Make sure the user is allowed to edit pages.
    733         if ( !current_user_can("edit_page", $page_id) )
    734             return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page.")));
    735 
    736         // Mark this as content for a page.
    737         $content["post_type"] = "page";
    738 
    739         // Arrange args in the way mw_editPost understands.
    740         $args = array(
    741             $page_id,
    742             $username,
    743             $password,
    744             $content,
    745             $publish
    746         );
    747 
    748         // Let mw_editPost do all of the heavy lifting.
    749         return($this->mw_editPost($args));
    750     }
    751 
    752     /**
    753      * Retrieve page list.
    754      *
    755      * @since 2.2.0
    756      *
    757      * @param array $args Method parameters.
    758      * @return unknown
    759      */
    760     function wp_getPageList($args) {
    761         global $wpdb;
    762 
    763         $this->escape($args);
    764 
    765         $blog_id                = (int) $args[0];
    766         $username               = $args[1];
    767         $password               = $args[2];
    768 
    769         if ( !$user = $this->login($username, $password) )
    770             return $this->error;
    771 
    772         if ( !current_user_can( 'edit_pages' ) )
    773             return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
    774 
    775         do_action('xmlrpc_call', 'wp.getPageList');
    776 
    777         // Get list of pages ids and titles
    778         $page_list = $wpdb->get_results("
    779             SELECT ID page_id,
    780                 post_title page_title,
    781                 post_parent page_parent_id,
    782                 post_date_gmt,
    783                 post_date,
    784                 post_status
    785             FROM {$wpdb->posts}
    786             WHERE post_type = 'page'
    787             ORDER BY ID
    788         ");
    789 
    790         // The date needs to be formated properly.
    791         $num_pages = count($page_list);
    792         for ( $i = 0; $i < $num_pages; $i++ ) {
    793             $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date, false);
    794             $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt, false);
    795 
    796             $page_list[$i]->dateCreated = new IXR_Date($post_date);
    797             $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt);
    798 
    799             // For drafts use the GMT version of the date
    800             if ( $page_list[$i]->post_status == 'draft' ) {
    801                 $page_list[$i]->date_created_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page_list[$i]->post_date ), 'Ymd\TH:i:s' );
    802                 $page_list[$i]->date_created_gmt = new IXR_Date( $page_list[$i]->date_created_gmt );
    803             }
    804 
    805             unset($page_list[$i]->post_date_gmt);
    806             unset($page_list[$i]->post_date);
    807             unset($page_list[$i]->post_status);
    808         }
    809 
    810         return($page_list);
    811     }
    812 
    813     /**
    814      * Retrieve authors list.
    815      *
    816      * @since 2.2.0
    817      *
    818      * @param array $args Method parameters.
    819      * @return array
    820      */
    821     function wp_getAuthors($args) {
    822 
    823         $this->escape($args);
    824 
    825         $blog_id    = (int) $args[0];
    826         $username   = $args[1];
    827         $password   = $args[2];
    828 
    829         if ( !$user = $this->login($username, $password) )
    830             return $this->error;
    831 
    832         if ( !current_user_can("edit_posts") )
    833             return(new IXR_Error(401, __("Sorry, you cannot edit posts on this site.")));
    834 
    835         do_action('xmlrpc_call', 'wp.getAuthors');
    836 
    837         $authors = array();
    838         foreach ( (array) get_users_of_blog() as $row ) {
    839             $authors[] = array(
    840                 "user_id"       => $row->user_id,
    841                 "user_login"    => $row->user_login,
    842                 "display_name"  => $row->display_name
    843             );
    844         }
    845 
    846         return($authors);
    847     }
    848 
    849     /**
    850      * Get list of all tags
    851      *
    852      * @since 2.7
    853      *
    854      * @param array $args Method parameters.
    855      * @return array
    856      */
    857     function wp_getTags( $args ) {
    858         $this->escape( $args );
    859 
    860         $blog_id        = (int) $args[0];
    861         $username       = $args[1];
    862         $password       = $args[2];
    863 
    864         if ( !$user = $this->login($username, $password) )
    865             return $this->error;
    866 
    867         if ( !current_user_can( 'edit_posts' ) )
    868             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view tags.' ) );
    869 
    870         do_action( 'xmlrpc_call', 'wp.getKeywords' );
    871 
    872         $tags = array( );
    873 
    874         if ( $all_tags = get_tags() ) {
    875             foreach( (array) $all_tags as $tag ) {
    876                 $struct['tag_id']           = $tag->term_id;
    877                 $struct['name']             = $tag->name;
    878                 $struct['count']            = $tag->count;
    879                 $struct['slug']             = $tag->slug;
    880                 $struct['html_url']         = esc_html( get_tag_link( $tag->term_id ) );
    881                 $struct['rss_url']          = esc_html( get_tag_feed_link( $tag->term_id ) );
    882 
    883                 $tags[] = $struct;
    884             }
    885         }
    886 
    887         return $tags;
    888     }
    889 
    890     /**
    891      * Create new category.
    892      *
    893      * @since 2.2.0
    894      *
    895      * @param array $args Method parameters.
    896      * @return int Category ID.
    897      */
    898     function wp_newCategory($args) {
    899         $this->escape($args);
    900 
    901         $blog_id                = (int) $args[0];
    902         $username               = $args[1];
    903         $password               = $args[2];
    904         $category               = $args[3];
    905 
    906         if ( !$user = $this->login($username, $password) )
    907             return $this->error;
    908 
    909         do_action('xmlrpc_call', 'wp.newCategory');
    910 
    911         // Make sure the user is allowed to add a category.
    912         if ( !current_user_can("manage_categories") )
    913             return(new IXR_Error(401, __("Sorry, you do not have the right to add a category.")));
    914 
    915         // If no slug was provided make it empty so that
    916         // WordPress will generate one.
    917         if ( empty($category["slug"]) )
    918             $category["slug"] = "";
    919 
    920         // If no parent_id was provided make it empty
    921         // so that it will be a top level page (no parent).
    922         if ( !isset($category["parent_id"]) )
    923             $category["parent_id"] = "";
    924 
    925         // If no description was provided make it empty.
    926         if ( empty($category["description"]) )
    927             $category["description"] = "";
    928 
    929         $new_category = array(
    930             "cat_name"              => $category["name"],
    931             "category_nicename"     => $category["slug"],
    932             "category_parent"       => $category["parent_id"],
    933             "category_description"  => $category["description"]
    934         );
    935 
    936         $cat_id = wp_insert_category($new_category, true);
    937         if ( is_wp_error( $cat_id ) ) {
    938             if ( 'term_exists' == $cat_id->get_error_code() )
    939                 return (int) $cat_id->get_error_data();
    940             else
    941                 return(new IXR_Error(500, __("Sorry, the new category failed.")));
    942         } elseif ( ! $cat_id ) {
    943             return(new IXR_Error(500, __("Sorry, the new category failed.")));
    944         }
    945 
    946         return($cat_id);
    947     }
    948 
    949     /**
    950      * Remove category.
    951      *
    952      * @since 2.5.0
    953      *
    954      * @param array $args Method parameters.
    955      * @return mixed See {@link wp_delete_category()} for return info.
    956      */
    957     function wp_deleteCategory($args) {
    958         $this->escape($args);
    959 
    960         $blog_id        = (int) $args[0];
    961         $username       = $args[1];
    962         $password       = $args[2];
    963         $category_id    = (int) $args[3];
    964 
    965         if ( !$user = $this->login($username, $password) )
    966             return $this->error;
    967 
    968         do_action('xmlrpc_call', 'wp.deleteCategory');
    969 
    970         if ( !current_user_can("manage_categories") )
    971             return new IXR_Error( 401, __( "Sorry, you do not have the right to delete a category." ) );
    972 
    973         return wp_delete_category( $category_id );
    974     }
    975 
    976     /**
    977      * Retrieve category list.
    978      *
    979      * @since 2.2.0
    980      *
    981      * @param array $args Method parameters.
    982      * @return array
    983      */
    984     function wp_suggestCategories($args) {
    985         $this->escape($args);
    986 
    987         $blog_id                = (int) $args[0];
    988         $username               = $args[1];
    989         $password               = $args[2];
    990         $category               = $args[3];
    991         $max_results            = (int) $args[4];
    992 
    993         if ( !$user = $this->login($username, $password) )
    994             return $this->error;
    995 
    996         if ( !current_user_can( 'edit_posts' ) )
    997             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this site in order to view categories.' ) );
    998 
    999         do_action('xmlrpc_call', 'wp.suggestCategories');
    1000 
    1001         $category_suggestions = array();
    1002         $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
    1003         foreach ( (array) get_categories($args) as $cat ) {
    1004             $category_suggestions[] = array(
    1005                 "category_id"   => $cat->cat_ID,
    1006                 "category_name" => $cat->cat_name
    1007             );
    1008         }
    1009 
    1010         return($category_suggestions);
    1011     }
    1012 
    1013     /**
    1014      * Retrieve comment.
    1015      *
    1016      * @since 2.7.0
    1017      *
    1018      * @param array $args Method parameters.
    1019      * @return array
    1020      */
    1021     function wp_getComment($args) {
    1022         $this->escape($args);
    1023 
    1024         $blog_id    = (int) $args[0];
    1025         $username   = $args[1];
    1026         $password   = $args[2];
    1027         $comment_id = (int) $args[3];
    1028 
    1029         if ( !$user = $this->login($username, $password) )
    1030             return $this->error;
    1031 
    1032         if ( !current_user_can( 'moderate_comments' ) )
    1033             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1034 
    1035         do_action('xmlrpc_call', 'wp.getComment');
    1036 
    1037         if ( ! $comment = get_comment($comment_id) )
    1038             return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
    1039 
    1040         // Format page date.
    1041         $comment_date = mysql2date("Ymd\TH:i:s", $comment->comment_date, false);
    1042         $comment_date_gmt = mysql2date("Ymd\TH:i:s", $comment->comment_date_gmt, false);
    1043 
    1044         if ( '0' == $comment->comment_approved )
    1045             $comment_status = 'hold';
    1046         else if ( 'spam' == $comment->comment_approved )
    1047             $comment_status = 'spam';
    1048         else if ( '1' == $comment->comment_approved )
    1049             $comment_status = 'approve';
    1050         else
    1051             $comment_status = $comment->comment_approved;
    1052 
    1053         $link = get_comment_link($comment);
    1054 
    1055         $comment_struct = array(
    1056             "date_created_gmt"      => new IXR_Date($comment_date_gmt),
    1057             "user_id"               => $comment->user_id,
    1058             "comment_id"            => $comment->comment_ID,
    1059             "parent"                => $comment->comment_parent,
    1060             "status"                => $comment_status,
    1061             "content"               => $comment->comment_content,
    1062             "link"                  => $link,
    1063             "post_id"               => $comment->comment_post_ID,
    1064             "post_title"            => get_the_title($comment->comment_post_ID),
    1065             "author"                => $comment->comment_author,
    1066             "author_url"            => $comment->comment_author_url,
    1067             "author_email"          => $comment->comment_author_email,
    1068             "author_ip"             => $comment->comment_author_IP,
    1069             "type"                  => $comment->comment_type,
    1070         );
    1071 
    1072         return $comment_struct;
    1073     }
    1074 
    1075     /**
    1076      * Retrieve comments.
    1077      *
    1078      * @since 2.7.0
    1079      *
    1080      * @param array $args Method parameters.
    1081      * @return array
    1082      */
    1083     function wp_getComments($args) {
    1084         $raw_args = $args;
    1085         $this->escape($args);
    1086 
    1087         $blog_id    = (int) $args[0];
    1088         $username   = $args[1];
    1089         $password   = $args[2];
    1090         $struct     = $args[3];
    1091 
    1092         if ( !$user = $this->login($username, $password) )
    1093             return $this->error;
    1094 
    1095         if ( !current_user_can( 'moderate_comments' ) )
    1096             return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) );
    1097 
    1098         do_action('xmlrpc_call', 'wp.getComments');
    1099 
    1100         if ( isset($struct['status']) )
    1101             $status = $struct['status'];
    1102         else
    1103             $status = '';
    1104 
    1105         $post_id = '';
    1106         if ( isset($struct['post_id']) )
    1107             $post_id = absint($struct['post_id']);
    1108 
    1109         $offset = 0;
    1110         if ( isset($struct['offset']) )
    1111             $offset = absint($struct['offset']);
    1112 
    1113         $number = 10;
    1114         if ( isset($struct['number']) )
    1115             $number = absint($struct['number']);
    1116 
    1117         $comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) );
    1118         $num_comments = count($comments);
    1119 
    1120         if ( ! $num_comments )
    1121             return array();
    1122 
    1123         $comments_struct = array();
    1124 
    1125         for ( $i = 0; $i < $num_comments; $i++ ) {
    1126             $comment = wp_xmlrpc_server::wp_getComment(array(
    1127                 $raw_args[0], $raw_args[1], $raw_args[2], $comments[$i]->comment_ID,
    1128             ));
    1129             $comments_struct[] = $comment;
    1130         }
    1131 
    1132         return $comments_struct;
    1133     }
    1134 
    1135     /**
    1136      * Remove comment.
    1137      *
    1138      * @since 2.7.0
    1139      *
    1140      * @param array $args Method parameters.
    1141      * @return mixed {@link wp_delete_comment()}
    1142      */
    1143     function wp_deleteComment($args) {
    1144         $this->escape($args);
    1145 
    1146         $blog_id    = (int) $args[0];
    1147         $username   = $args[1];
    1148         $password   = $args[2];
    1149         $comment_ID = (int) $args[3];
    1150 
    1151         if ( !$user = $this->login($username, $password) )
    1152             return $this->error;
    1153 
    1154         if ( !current_user_can( 'moderate_comments' ) )
    1155             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1156 
    1157         do_action('xmlrpc_call', 'wp.deleteComment');
    1158 
    1159         if ( !$comment = get_comment( $comment_ID ) )
    1160             return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
    1161 
    1162         if ( !current_user_can( 'edit_post', $comment->comment_post_ID ) )
    1163             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1164 
    1165         return wp_delete_comment($comment_ID);
    1166     }
    1167 
    1168     /**
    1169      * Edit comment.
    1170      *
    1171      * @since 2.7.0
    1172      *
    1173      * @param array $args Method parameters.
    1174      * @return bool True, on success.
    1175      */
    1176     function wp_editComment($args) {
    1177         $this->escape($args);
    1178 
    1179         $blog_id    = (int) $args[0];
    1180         $username   = $args[1];
    1181         $password   = $args[2];
    1182         $comment_ID = (int) $args[3];
    1183         $content_struct = $args[4];
    1184 
    1185         if ( !$user = $this->login($username, $password) )
    1186             return $this->error;
    1187 
    1188         if ( !current_user_can( 'moderate_comments' ) )
    1189             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1190 
    1191         if ( !$comment = get_comment( $comment_ID ) )
    1192             return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
    1193 
    1194         if ( !current_user_can( 'edit_post', $comment->comment_post_ID ) )
    1195             return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
    1196 
    1197         do_action('xmlrpc_call', 'wp.editComment');
    1198 
    1199         if ( isset($content_struct['status']) ) {
    1200             $statuses = get_comment_statuses();
    1201             $statuses = array_keys($statuses);
    1202 
    1203             if ( ! in_array($content_struct['status'], $statuses) )
    1204                 return new IXR_Error( 401, __( 'Invalid comment status.' ) );
    1205             $comment_approved = $content_struct['status'];
    1206         }
    1207 
    1208         // Do some timestamp voodoo
    1209         if ( !empty( $content_struct['date_created_gmt'] ) ) {
    1210             $dateCreated = str_replace( 'Z', '', $content_struct['date_created_gmt']->getIso() ) . 'Z'; // We know this is supposed to be GMT, so we're going to slap that Z on there by force
    1211             $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
    1212             $comment_date_gmt = iso8601_to_datetime($dateCreated, GMT);
    1213         }
    1214 
    1215         if ( isset($content_struct['content']) )
    1216             $comment_content = $content_struct['content'];
    1217 
    1218         if ( isset($content_struct['author']) )
    1219             $comment_author = $content_struct['author'];
    1220 
    1221         if ( isset($content_struct['author_url']) )
    1222             $comment_author_url = $content_struct['author_url'];
    1223 
    1224         if ( isset($content_struct['author_email']) )
    1225             $comment_author_email = $content_struct['author_email'];
    1226 
    1227         // We've got all the data -- post it:
    1228         $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url');
    1229 
    1230         $result = wp_update_comment($comment);
    1231         if ( is_wp_error( $result ) )
    1232             return new IXR_Error(500, $result->get_error_message());
    1233 
    1234         if ( !$result )
    1235             return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.'));
    1236 
    1237         return true;
    1238     }
    1239 
    1240     /**
    1241      * Create new comment.
    1242      *
    1243      * @since 2.7.0
    1244      *
    1245      * @param array $args Method parameters.
    1246      * @return mixed {@link wp_new_comment()}
    1247      */
    1248     function wp_newComment($args) {
    1249         global $wpdb;
    1250 
    1251         $this->escape($args);
    1252 
    1253         $blog_id    = (int) $args[0];
    1254         $username   = $args[1];
    1255         $password   = $args[2];
    1256         $post       = $args[3];
    1257         $content_struct = $args[4];
    1258 
    1259         $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false);
    1260 
    1261         $user = $this->login($username, $password);
    1262 
    1263         if ( !$user ) {
    1264             $logged_in = false;
    1265             if ( $allow_anon && get_option('comment_registration') )
    1266                 return new IXR_Error( 403, __( 'You must be registered to comment' ) );
    1267             else if ( !$allow_anon )
    1268                 return $this->error;
    1269         } else {
    1270             $logged_in = true;
    1271         }
    1272 
    1273         if ( is_numeric($post) )
    1274             $post_id = absint($post);
    1275         else
    1276             $post_id = url_to_postid($post);
    1277 
    1278         if ( ! $post_id )
    1279             return new IXR_Error( 404, __( 'Invalid post ID.' ) );
    1280 
    1281         if ( ! get_post($post_id) )
    1282             return new IXR_Error( 404, __( 'Invalid post ID.' ) );
    1283 
    1284         $comment['comment_post_ID'] = $post_id;
    1285 
    1286         if ( $logged_in ) {
    1287             $comment['comment_author'] = $wpdb->escape( $user->display_name );
    1288             $comment['comment_author_email'] = $wpdb->escape( $user->user_email );
    1289             $comment['comment_author_url'] = $wpdb->escape( $user->user_url );
    1290             $comment['user_ID'] = $user->ID;
    1291         } else {
    1292             $comment['comment_author'] = '';
    1293             if ( isset($content_struct['author']) )
    1294                 $comment['comment_author'] = $content_struct['author'];
    1295 
    1296             $comment['comment_author_email'] = '';
    1297             if ( isset($content_struct['author_email']) )
    1298                 $comment['comment_author_email'] = $content_struct['author_email'];
    1299 
    1300             $comment['comment_author_url'] = '';
    1301             if ( isset($content_struct['author_url']) )
    1302                 $comment['comment_author_url'] = $content_struct['author_url'];
    1303 
    1304             $comment['user_ID'] = 0;
    1305 
    1306             if ( get_option('require_name_email') ) {
    1307                 if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] )
    1308                     return new IXR_Error( 403, __( 'Comment author name and email are required' ) );
    1309                 elseif ( !is_email($comment['comment_author_email']) )
    1310                     return new IXR_Error( 403, __( 'A valid email address is required' ) );
    1311             }
    1312         }
    1313 
    1314         $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0;
    1315 
    1316         $comment['comment_content'] = $content_struct['content'];
    1317 
    1318         do_action('xmlrpc_call', 'wp.newComment');
    1319 
    1320         return wp_new_comment($comment);
    1321     }
    1322 
    1323     /**
    1324      * Retrieve all of the comment status.
    1325      *
    1326      * @since 2.7.0
    1327      *
    1328      * @param array $args Method parameters.
    1329      * @return array
    1330      */
    1331     function wp_getCommentStatusList($args) {
    1332         $this->escape( $args );
    1333 
    1334         $blog_id    = (int) $args[0];
    1335         $username   = $args[1];
    1336         $password   = $args[2];
    1337 
    1338         if ( !$user = $this->login($username, $password) )
    1339             return $this->error;
    1340 
    1341         if ( !current_user_can( 'moderate_comments' ) )
    1342             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1343 
    1344         do_action('xmlrpc_call', 'wp.getCommentStatusList');
    1345 
    1346         return get_comment_statuses( );
    1347     }
    1348 
    1349     /**
    1350      * Retrieve comment count.
    1351      *
    1352      * @since 2.5.0
    1353      *
    1354      * @param array $args Method parameters.
    1355      * @return array
    1356      */
    1357     function wp_getCommentCount( $args ) {
    1358         $this->escape($args);
    1359 
    1360         $blog_id    = (int) $args[0];
    1361         $username   = $args[1];
    1362         $password   = $args[2];
    1363         $post_id    = (int) $args[3];
    1364 
    1365         if ( !$user = $this->login($username, $password) )
    1366             return $this->error;
    1367 
    1368         if ( !current_user_can( 'edit_posts' ) )
    1369             return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) );
    1370 
    1371         do_action('xmlrpc_call', 'wp.getCommentCount');
    1372 
    1373         $count = wp_count_comments( $post_id );
    1374         return array(
    1375             "approved" => $count->approved,
    1376             "awaiting_moderation" => $count->moderated,
    1377             "spam" => $count->spam,
    1378             "total_comments" => $count->total_comments
    1379         );
    1380     }
    1381 
    1382     /**
    1383      * Retrieve post statuses.
    1384      *
    1385      * @since 2.5.0
    1386      *
    1387      * @param array $args Method parameters.
    1388      * @return array
    1389      */
    1390     function wp_getPostStatusList( $args ) {
    1391         $this->escape( $args );
    1392 
    1393         $blog_id    = (int) $args[0];
    1394         $username   = $args[1];
    1395         $password   = $args[2];
    1396 
    1397         if ( !$user = $this->login($username, $password) )
    1398             return $this->error;
    1399 
    1400         if ( !current_user_can( 'edit_posts' ) )
    1401             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1402 
    1403         do_action('xmlrpc_call', 'wp.getPostStatusList');
    1404 
    1405         return get_post_statuses( );
    1406     }
    1407 
    1408     /**
    1409      * Retrieve page statuses.
    1410      *
    1411      * @since 2.5.0
    1412      *
    1413      * @param array $args Method parameters.
    1414      * @return array
    1415      */
    1416     function wp_getPageStatusList( $args ) {
    1417         $this->escape( $args );
    1418 
    1419         $blog_id    = (int) $args[0];
    1420         $username   = $args[1];
    1421         $password   = $args[2];
    1422 
    1423         if ( !$user = $this->login($username, $password) )
    1424             return $this->error;
    1425 
    1426         if ( !current_user_can( 'edit_pages' ) )
    1427             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1428 
    1429         do_action('xmlrpc_call', 'wp.getPageStatusList');
    1430 
    1431         return get_page_statuses( );
    1432     }
    1433 
    1434     /**
    1435      * Retrieve page templates.
    1436      *
    1437      * @since 2.6.0
    1438      *
    1439      * @param array $args Method parameters.
    1440      * @return array
    1441      */
    1442     function wp_getPageTemplates( $args ) {
    1443         $this->escape( $args );
    1444 
    1445         $blog_id    = (int) $args[0];
    1446         $username   = $args[1];
    1447         $password   = $args[2];
    1448 
    1449         if ( !$user = $this->login($username, $password) )
    1450             return $this->error;
    1451 
    1452         if ( !current_user_can( 'edit_pages' ) )
    1453             return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
    1454 
    1455         $templates = get_page_templates( );
    1456         $templates['Default'] = 'default';
    1457 
    1458         return $templates;
    1459     }
    1460 
    1461     /**
    1462      * Retrieve blog options.
    1463      *
    1464      * @since 2.6.0
    1465      *
    1466      * @param array $args Method parameters.
    1467      * @return array
    1468      */
    1469     function wp_getOptions( $args ) {
    1470         $this->escape( $args );
    1471 
    1472         $blog_id    = (int) $args[0];
    1473         $username   = $args[1];
    1474         $password   = $args[2];
    1475         $options    = (array) $args[3];
    1476 
    1477         if ( !$user = $this->login($username, $password) )
    1478             return $this->error;
    1479 
    1480         // If no specific options where asked for, return all of them
    1481         if ( count( $options ) == 0 )
    1482             $options = array_keys($this->blog_options);
    1483 
    1484         return $this->_getOptions($options);
    1485     }
    1486 
    1487     /**
    1488      * Retrieve blog options value from list.
    1489      *
    1490      * @since 2.6.0
    1491      *
    1492      * @param array $options Options to retrieve.
    1493      * @return array
    1494      */
    1495     function _getOptions($options) {
    1496         $data = array( );
    1497         foreach ( $options as $option ) {
    1498             if ( array_key_exists( $option, $this->blog_options ) ) {
    1499                 $data[$option] = $this->blog_options[$option];
    1500                 //Is the value static or dynamic?
    1501                 if ( isset( $data[$option]['option'] ) ) {
    1502                     $data[$option]['value'] = get_option( $data[$option]['option'] );
    1503                     unset($data[$option]['option']);
    1504                 }
    1505             }
    1506         }
    1507 
    1508         return $data;
    1509     }
    1510 
    1511     /**
    1512      * Update blog options.
    1513      *
    1514      * @since 2.6.0
    1515      *
    1516      * @param array $args Method parameters.
    1517      * @return unknown
    1518      */
    1519     function wp_setOptions( $args ) {
    1520         $this->escape( $args );
    1521 
    1522         $blog_id    = (int) $args[0];
    1523         $username   = $args[1];
    1524         $password   = $args[2];
    1525         $options    = (array) $args[3];
    1526 
    1527         if ( !$user = $this->login($username, $password) )
    1528             return $this->error;
    1529 
    1530         if ( !current_user_can( 'manage_options' ) )
    1531             return new IXR_Error( 403, __( 'You are not allowed to update options.' ) );
    1532 
    1533         foreach ( $options as $o_name => $o_value ) {
    1534             $option_names[] = $o_name;
    1535             if ( !array_key_exists( $o_name, $this->blog_options ) )
    1536                 continue;
    1537 
    1538             if ( $this->blog_options[$o_name]['readonly'] == true )
    1539                 continue;
    1540 
    1541             update_option( $this->blog_options[$o_name]['option'], $o_value );
    1542         }
    1543 
    1544         //Now return the updated values
    1545         return $this->_getOptions($option_names);
    1546     }
    1547 
    1548     /* Blogger API functions.
    1549      * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
    1550      */
    1551 
    1552     /**
    1553      * Retrieve blogs that user owns.
    1554      *
    1555      * Will make more sense once we support multiple blogs.
    1556      *
    1557      * @since 1.5.0
    1558      *
    1559      * @param array $args Method parameters.
    1560      * @return array
    1561      */
    1562     function blogger_getUsersBlogs($args) {
    1563         if ( is_multisite() )
    1564             return $this->_multisite_getUsersBlogs($args);
    1565 
    1566         $this->escape($args);
    1567 
    1568         $username = $args[1];
    1569         $password  = $args[2];
    1570 
    1571         if ( !$user = $this->login($username, $password) )
    1572             return $this->error;
    1573 
    1574         do_action('xmlrpc_call', 'blogger.getUsersBlogs');
    1575 
    1576         $is_admin = current_user_can('manage_options');
    1577 
    1578         $struct = array(
    1579             'isAdmin'  => $is_admin,
    1580             'url'      => get_option('home') . '/',
    1581             'blogid'   => '1',
    1582             'blogName' => get_option('blogname'),
    1583             'xmlrpc'   => site_url( 'xmlrpc.php' )
    1584         );
    1585 
    1586         return array($struct);
    1587     }
    1588 
    1589     /**
    1590      * Private function for retrieving a users blogs for multisite setups
    1591      *
    1592      * @access protected
    1593      */
    1594     function _multisite_getUsersBlogs($args) {
    1595         global $current_blog;
    1596         $domain = $current_blog->domain;
    1597         $path = $current_blog->path . 'xmlrpc.php';
    1598         $protocol = is_ssl() ? 'https' : 'http';
    1599 
    1600         $rpc = new IXR_Client("$protocol://{$domain}{$path}");
    1601         $rpc->query('wp.getUsersBlogs', $args[1], $args[2]);
    1602         $blogs = $rpc->getResponse();
    1603 
    1604         if ( isset($blogs['faultCode']) )
    1605             return new IXR_Error($blogs['faultCode'], $blogs['faultString']);
    1606 
    1607         if ( $_SERVER['HTTP_HOST'] == $domain && $_SERVER['REQUEST_URI'] == $path ) {
    1608             return $blogs;
    1609         } else {
    1610             foreach ( (array) $blogs as $blog ) {
    1611                 if ( strpos($blog['url'], $_SERVER['HTTP_HOST']) )
    1612                     return array($blog);
    1613             }
    1614             return array();
    1615         }
    1616     }
    1617 
    1618     /**
    1619      * Retrieve user's data.
    1620      *
    1621      * Gives your client some info about you, so you don't have to.
    1622      *
    1623      * @since 1.5.0
    1624      *
    1625      * @param array $args Method parameters.
    1626      * @return array
    1627      */
    1628     function blogger_getUserInfo($args) {
    1629 
    1630         $this->escape($args);
    1631 
    1632         $username = $args[1];
    1633         $password  = $args[2];
    1634 
    1635         if ( !$user = $this->login($username, $password) )
    1636             return $this->error;
    1637 
    1638         if ( !current_user_can( 'edit_posts' ) )
    1639             return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this site.' ) );
    1640 
    1641         do_action('xmlrpc_call', 'blogger.getUserInfo');
    1642 
    1643         $struct = array(
    1644             'nickname'  => $user->nickname,
    1645             'userid'    => $user->ID,
    1646             'url'       => $user->user_url,
    1647             'lastname'  => $user->last_name,
    1648             'firstname' => $user->first_name
    1649         );
    1650 
    1651         return $struct;
    1652     }
    1653 
    1654     /**
    1655      * Retrieve post.
    1656      *
    1657      * @since 1.5.0
    1658      *
    1659      * @param array $args Method parameters.
    1660      * @return array
    1661      */
    1662     function blogger_getPost($args) {
    1663 
    1664         $this->escape($args);
    1665 
    1666         $post_ID    = (int) $args[1];
    1667         $username = $args[2];
    1668         $password  = $args[3];
    1669 
    1670         if ( !$user = $this->login($username, $password) )
    1671             return $this->error;
    1672 
    1673         if ( !current_user_can( 'edit_post', $post_ID ) )
    1674             return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
    1675 
    1676         do_action('xmlrpc_call', 'blogger.getPost');
    1677 
    1678         $post_data = wp_get_single_post($post_ID, ARRAY_A);
    1679 
    1680         $categories = implode(',', wp_get_post_categories($post_ID));
    1681 
    1682         $content  = '<title>'.stripslashes($post_data['post_title']).'</title>';
    1683         $content .= '<category>'.$categories.'</category>';
    1684         $content .= stripslashes($post_data['post_content']);
    1685 
    1686         $struct = array(
    1687             'userid'    => $post_data['post_author'],
    1688             'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'], false)),
    1689             'content'     => $content,
    1690             'postid'  => $post_data['ID']
    1691         );
    1692 
    1693         return $struct;
    1694     }
    1695 
    1696     /**
    1697      * Retrieve list of recent posts.
    1698      *
    1699      * @since 1.5.0
    1700      *
    1701      * @param array $args Method parameters.
    1702      * @return array
    1703      */
    1704     function blogger_getRecentPosts($args) {
    1705 
    1706         $this->escape($args);
    1707 
    1708         $blog_ID    = (int) $args[1]; /* though we don't use it yet */
    1709         $username = $args[2];
    1710         $password  = $args[3];
    1711         $num_posts  = $args[4];
    1712 
    1713         if ( !$user = $this->login($username, $password) )
    1714             return $this->error;
    1715 
    1716         do_action('xmlrpc_call', 'blogger.getRecentPosts');
    1717 
    1718         $posts_list = wp_get_recent_posts($num_posts);
    1719 
    1720         if ( !$posts_list ) {
    1721             $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
    1722             return $this->error;
    1723         }
    1724 
    1725         foreach ($posts_list as $entry) {
    1726             if ( !current_user_can( 'edit_post', $entry['ID'] ) )
    1727                 continue;
    1728 
    1729             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false);
    1730             $categories = implode(',', wp_get_post_categories($entry['ID']));
    1731 
    1732             $content  = '<title>'.stripslashes($entry['post_title']).'</title>';
    1733             $content .= '<category>'.$categories.'</category>';
    1734             $content .= stripslashes($entry['post_content']);
    1735 
    1736             $struct[] = array(
    1737                 'userid' => $entry['post_author'],
    1738                 'dateCreated' => new IXR_Date($post_date),
    1739                 'content' => $content,
    1740                 'postid' => $entry['ID'],
    1741             );
    1742 
    1743         }
    1744 
    1745         $recent_posts = array();
    1746         for ( $j=0; $j<count($struct); $j++ ) {
    1747             array_push($recent_posts, $struct[$j]);
    1748         }
    1749 
    1750         return $recent_posts;
    1751     }
    1752 
    1753     /**
    1754      * Retrieve blog_filename content.
    1755      *
    1756      * @since 1.5.0
    1757      *
    1758      * @param array $args Method parameters.
    1759      * @return string
    1760      */
    1761     function blogger_getTemplate($args) {
    1762 
    1763         $this->escape($args);
    1764 
    1765         $blog_ID    = (int) $args[1];
    1766         $username = $args[2];
    1767         $password  = $args[3];
    1768         $template   = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */
    1769 
    1770         if ( !$user = $this->login($username, $password) )
    1771             return $this->error;
    1772 
    1773         do_action('xmlrpc_call', 'blogger.getTemplate');
    1774 
    1775         if ( !current_user_can('edit_themes') )
    1776             return new IXR_Error(401, __('Sorry, this user can not edit the template.'));
    1777 
    1778         /* warning: here we make the assumption that the blog's URL is on the same server */
    1779         $filename = get_option('home') . '/';
    1780         $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
    1781 
    1782         $f = fopen($filename, 'r');
    1783         $content = fread($f, filesize($filename));
    1784         fclose($f);
    1785 
    1786         /* so it is actually editable with a windows/mac client */
    1787         // FIXME: (or delete me) do we really want to cater to bad clients at the expense of good ones by BEEPing up their line breaks? commented.     $content = str_replace("\n", "\r\n", $content);
    1788 
    1789         return $content;
    1790     }
    1791 
    1792     /**
    1793      * Updates the content of blog_filename.
    1794      *
    1795      * @since 1.5.0
    1796      *
    1797      * @param array $args Method parameters.
    1798      * @return bool True when done.
    1799      */
    1800     function blogger_setTemplate($args) {
    1801 
    1802         $this->escape($args);
    1803 
    1804         $blog_ID    = (int) $args[1];
    1805         $username = $args[2];
    1806         $password  = $args[3];
    1807         $content    = $args[4];
    1808         $template   = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */
    1809 
    1810         if ( !$user = $this->login($username, $password) )
    1811             return $this->error;
    1812 
    1813         do_action('xmlrpc_call', 'blogger.setTemplate');
    1814 
    1815         if ( !current_user_can('edit_themes') )
    1816             return new IXR_Error(401, __('Sorry, this user cannot edit the template.'));
    1817 
    1818         /* warning: here we make the assumption that the blog's URL is on the same server */
    1819         $filename = get_option('home') . '/';
    1820         $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename);
    1821 
    1822         if ($f = fopen($filename, 'w+')) {
    1823             fwrite($f, $content);
    1824             fclose($f);
    1825         } else {
    1826             return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.'));
    1827         }
    1828 
    1829         return true;
    1830     }
    1831 
    1832     /**
    1833      * Create new post.
    1834      *
    1835      * @since 1.5.0
    1836      *
    1837      * @param array $args Method parameters.
    1838      * @return int
    1839      */
    1840     function blogger_newPost($args) {
    1841 
    1842         $this->escape($args);
    1843 
    1844         $blog_ID    = (int) $args[1]; /* though we don't use it yet */
    1845         $username = $args[2];
    1846         $password  = $args[3];
    1847         $content    = $args[4];
    1848         $publish    = $args[5];
    1849 
    1850         if ( !$user = $this->login($username, $password) )
    1851             return $this->error;
    1852 
    1853         do_action('xmlrpc_call', 'blogger.newPost');
    1854 
    1855         $cap = ($publish) ? 'publish_posts' : 'edit_posts';
    1856         if ( !current_user_can($cap) )
    1857             return new IXR_Error(401, __('Sorry, you are not allowed to post on this site.'));
    1858 
    1859         $post_status = ($publish) ? 'publish' : 'draft';
    1860 
    1861         $post_author = $user->ID;
    1862 
    1863         $post_title = xmlrpc_getposttitle($content);
    1864         $post_category = xmlrpc_getpostcategory($content);
    1865         $post_content = xmlrpc_removepostdata($content);
    1866 
    1867         $post_date = current_time('mysql');
    1868         $post_date_gmt = current_time('mysql', 1);
    1869 
    1870         $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
    1871 
    1872         $post_ID = wp_insert_post($post_data);
    1873         if ( is_wp_error( $post_ID ) )
    1874             return new IXR_Error(500, $post_ID->get_error_message());
    1875 
    1876         if ( !$post_ID )
    1877             return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
    1878 
    1879         $this->attach_uploads( $post_ID, $post_content );
    1880 
    1881         logIO('O', "Posted ! ID: $post_ID");
    1882 
    1883         return $post_ID;
    1884     }
    1885 
    1886     /**
    1887      * Edit a post.
    1888      *
    1889      * @since 1.5.0
    1890      *
    1891      * @param array $args Method parameters.
    1892      * @return bool true when done.
    1893      */
    1894     function blogger_editPost($args) {
    1895 
    1896         $this->escape($args);
    1897 
    1898         $post_ID     = (int) $args[1];
    1899         $username  = $args[2];
    1900         $password   = $args[3];
    1901         $content     = $args[4];
    1902         $publish     = $args[5];
    1903 
    1904         if ( !$user = $this->login($username, $password) )
    1905             return $this->error;
    1906 
    1907         do_action('xmlrpc_call', 'blogger.editPost');
    1908 
    1909         $actual_post = wp_get_single_post($post_ID,ARRAY_A);
    1910 
    1911         if ( !$actual_post || $actual_post['post_type'] != 'post' )
    1912             return new IXR_Error(404, __('Sorry, no such post.'));
    1913 
    1914         $this->escape($actual_post);
    1915 
    1916         if ( !current_user_can('edit_post', $post_ID) )
    1917             return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.'));
    1918 
    1919         extract($actual_post, EXTR_SKIP);
    1920 
    1921         if ( ('publish' == $post_status) && !current_user_can('publish_posts') )
    1922             return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
    1923 
    1924         $post_title = xmlrpc_getposttitle($content);
    1925         $post_category = xmlrpc_getpostcategory($content);
    1926         $post_content = xmlrpc_removepostdata($content);
    1927 
    1928         $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt');
    1929 
    1930         $result = wp_update_post($postdata);
    1931 
    1932         if ( !$result )
    1933             return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.'));
    1934 
    1935         $this->attach_uploads( $ID, $post_content );
    1936 
    1937         return true;
    1938     }
    1939 
    1940     /**
    1941      * Remove a post.
    1942      *
    1943      * @since 1.5.0
    1944      *
    1945      * @param array $args Method parameters.
    1946      * @return bool True when post is deleted.
    1947      */
    1948     function blogger_deletePost($args) {
    1949         $this->escape($args);
    1950 
    1951         $post_ID     = (int) $args[1];
    1952         $username  = $args[2];
    1953         $password   = $args[3];
    1954         $publish     = $args[4];
    1955 
    1956         if ( !$user = $this->login($username, $password) )
    1957             return $this->error;
    1958 
    1959         do_action('xmlrpc_call', 'blogger.deletePost');
    1960 
    1961         $actual_post = wp_get_single_post($post_ID,ARRAY_A);
    1962 
    1963         if ( !$actual_post || $actual_post['post_type'] != 'post' )
    1964             return new IXR_Error(404, __('Sorry, no such post.'));
    1965 
    1966         if ( !current_user_can('delete_post', $post_ID) )
    1967             return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.'));
    1968 
    1969         $result = wp_delete_post($post_ID);
    1970 
    1971         if ( !$result )
    1972             return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.'));
    1973 
    1974         return true;
    1975     }
    1976 
    1977     /* MetaWeblog API functions
    1978      * specs on wherever Dave Winer wants them to be
    1979      */
    1980 
    1981     /**
    1982      * Create a new post.
    1983      *
    1984      * @since 1.5.0
    1985      *
    1986      * @param array $args Method parameters.
    1987      * @return int
    1988      */
    1989     function mw_newPost($args) {
    1990         $this->escape($args);
    1991 
    1992         $blog_ID     = (int) $args[0]; // we will support this in the near future
    1993         $username  = $args[1];
    1994         $password   = $args[2];
    1995         $content_struct = $args[3];
    1996         $publish     = isset( $args[4] ) ? $args[4] : 0;
    1997 
    1998         if ( !$user = $this->login($username, $password) )
    1999             return $this->error;
    2000 
    2001         do_action('xmlrpc_call', 'metaWeblog.newPost');
    2002 
    2003         $page_template = '';
    2004         if ( !empty( $content_struct['post_type'] ) ) {
    2005             if ( $content_struct['post_type'] == 'page' ) {
    2006                 if ( $publish || 'publish' == $content_struct['page_status'])
    2007                     $cap  = 'publish_pages';
    2008                 else
    2009                     $cap = 'edit_pages';
    2010                 $error_message = __( 'Sorry, you are not allowed to publish pages on this site.' );
    2011                 $post_type = 'page';
    2012                 if ( !empty( $content_struct['wp_page_template'] ) )
    2013                     $page_template = $content_struct['wp_page_template'];
    2014             } elseif ( $content_struct['post_type'] == 'post' ) {
    2015                 if ( $publish || 'publish' == $content_struct['post_status'])
    2016                     $cap  = 'publish_posts';
    2017                 else
    2018                     $cap = 'edit_posts';
    2019                 $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
    2020                 $post_type = 'post';
    2021             } else {
    2022                 // No other post_type values are allowed here
    2023                 return new IXR_Error( 401, __( 'Invalid post type.' ) );
    2024             }
    2025         } else {
    2026             if ( $publish || 'publish' == $content_struct['post_status'])
    2027                 $cap  = 'publish_posts';
    2028             else
    2029                 $cap = 'edit_posts';
    2030             $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
    2031             $post_type = 'post';
    2032         }
    2033 
    2034         if ( !current_user_can( $cap ) )
    2035             return new IXR_Error( 401, $error_message );
    2036 
    2037         // Let WordPress generate the post_name (slug) unless
    2038         // one has been provided.
    2039         $post_name = "";
    2040         if ( isset($content_struct["wp_slug"]) )
    2041             $post_name = $content_struct["wp_slug"];
    2042 
    2043         // Only use a password if one was given.
    2044         if ( isset($content_struct["wp_password"]) )
    2045             $post_password = $content_struct["wp_password"];
    2046 
    2047         // Only set a post parent if one was provided.
    2048         if ( isset($content_struct["wp_page_parent_id"]) )
    2049             $post_parent = $content_struct["wp_page_parent_id"];
    2050 
    2051         // Only set the menu_order if it was provided.
    2052         if ( isset($content_struct["wp_page_order"]) )
    2053             $menu_order = $content_struct["wp_page_order"];
    2054 
    2055         $post_author = $user->ID;
    2056 
    2057         // If an author id was provided then use it instead.
    2058         if ( isset($content_struct["wp_author_id"]) && ($user->ID != $content_struct["wp_author_id"]) ) {
    2059             switch ( $post_type ) {
    2060                 case "post":
    2061                     if ( !current_user_can("edit_others_posts") )
    2062                         return(new IXR_Error(401, __("You are not allowed to post as this user")));
    2063                     break;
    2064                 case "page":
    2065                     if ( !current_user_can("edit_others_pages") )
    2066                         return(new IXR_Error(401, __("You are not allowed to create pages as this user")));
    2067                     break;
    2068                 default:
    2069                     return(new IXR_Error(401, __("Invalid post type.")));
    2070                     break;
    2071             }
    2072             $post_author = $content_struct["wp_author_id"];
    2073         }
    2074 
    2075         $post_title = $content_struct['title'];
    2076         $post_content = $content_struct['description'];
    2077 
    2078         $post_status = $publish ? 'publish' : 'draft';
    2079 
    2080         if ( isset( $content_struct["{$post_type}_status"] ) ) {
    2081             switch ( $content_struct["{$post_type}_status"] ) {
    2082                 case 'draft':
    2083                 case 'private':
    2084                 case 'publish':
    2085                     $post_status = $content_struct["{$post_type}_status"];
    2086                     break;
    2087                 case 'pending':
    2088                     // Pending is only valid for posts, not pages.
    2089                     if ( $post_type === 'post' )
    2090                         $post_status = $content_struct["{$post_type}_status"];
    2091                     break;
    2092                 default:
    2093                     $post_status = $publish ? 'publish' : 'draft';
    2094                     break;
    2095             }
    2096         }
    2097 
    2098         $post_excerpt = $content_struct['mt_excerpt'];
    2099         $post_more = $content_struct['mt_text_more'];
    2100 
    2101         $tags_input = $content_struct['mt_keywords'];
    2102 
    2103         if ( isset($content_struct["mt_allow_comments"]) ) {
    2104             if ( !is_numeric($content_struct["mt_allow_comments"]) ) {
    2105                 switch ( $content_struct["mt_allow_comments"] ) {
    2106                     case "closed":
    2107                         $comment_status = "closed";
    2108                         break;
    2109                     case "open":
    2110                         $comment_status = "open";
    2111                         break;
    2112                     default:
    2113                         $comment_status = get_option("default_comment_status");
    2114                         break;
    2115                 }
    2116             } else {
    2117                 switch ( (int) $content_struct["mt_allow_comments"] ) {
    2118                     case 0:
    2119                     case 2:
    2120                         $comment_status = "closed";
    2121                         break;
    2122                     case 1:
    2123                         $comment_status = "open";
    2124                         break;
    2125                     default:
    2126                         $comment_status = get_option("default_comment_status");
    2127                         break;
    2128                 }
    2129             }
    2130         } else {
    2131             $comment_status = get_option("default_comment_status");
    2132         }
    2133 
    2134         if ( isset($content_struct["mt_allow_pings"]) ) {
    2135             if ( !is_numeric($content_struct["mt_allow_pings"]) ) {
    2136                 switch ( $content_struct['mt_allow_pings'] ) {
    2137                     case "closed":
    2138                         $ping_status = "closed";
    2139                         break;
    2140                     case "open":
    2141                         $ping_status = "open";
    2142                         break;
    2143                     default:
    2144                         $ping_status = get_option("default_ping_status");
    2145                         break;
    2146                 }
    2147             } else {
    2148                 switch ( (int) $content_struct["mt_allow_pings"] ) {
    2149                     case 0:
    2150                         $ping_status = "closed";
    2151                         break;
    2152                     case 1:
    2153                         $ping_status = "open";
    2154                         break;
    2155                     default:
    2156                         $ping_status = get_option("default_ping_status");
    2157                         break;
    2158                 }
    2159             }
    2160         } else {
    2161             $ping_status = get_option("default_ping_status");
    2162         }
    2163 
    2164         if ( $post_more )
    2165             $post_content = $post_content . "<!--more-->" . $post_more;
    2166 
    2167         $to_ping = $content_struct['mt_tb_ping_urls'];
    2168         if ( is_array($to_ping) )
    2169             $to_ping = implode(' ', $to_ping);
    2170 
    2171         // Do some timestamp voodoo
    2172         if ( !empty( $content_struct['date_created_gmt'] ) )
    2173             $dateCreated = str_replace( 'Z', '', $content_struct['date_created_gmt']->getIso() ) . 'Z'; // We know this is supposed to be GMT, so we're going to slap that Z on there by force
    2174         elseif ( !empty( $content_struct['dateCreated']) )
    2175             $dateCreated = $content_struct['dateCreated']->getIso();
    2176 
    2177         if ( !empty( $dateCreated ) ) {
    2178             $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
    2179             $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
    2180         } else {
    2181             $post_date = current_time('mysql');
    2182             $post_date_gmt = current_time('mysql', 1);
    2183         }
    2184 
    2185         $catnames = $content_struct['categories'];
    2186         logIO('O', 'Post cats: ' . var_export($catnames,true));
    2187         $post_category = array();
    2188 
    2189         if ( is_array($catnames) ) {
    2190             foreach ($catnames as $cat) {
    2191                 $post_category[] = get_cat_ID($cat);
    2192             }
    2193         }
    2194 
    2195         // We've got all the data -- post it:
    2196         $postdata = compact('post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'to_ping', 'post_type', 'post_name', 'post_password', 'post_parent', 'menu_order', 'tags_input', 'page_template');
    2197 
    2198         $post_ID = wp_insert_post($postdata, true);
    2199         if ( is_wp_error( $post_ID ) )
    2200             return new IXR_Error(500, $post_ID->get_error_message());
    2201 
    2202         if ( !$post_ID )
    2203             return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
    2204 
    2205         // Only posts can be sticky
    2206         if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
    2207             if ( $content_struct['sticky'] == true )
    2208                 stick_post( $post_ID );
    2209             elseif ( $content_struct['sticky'] == false )
    2210                 unstick_post( $post_ID );
    2211         }
    2212 
    2213         if ( isset($content_struct['custom_fields']) )
    2214             $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
    2215 
    2216         // Handle enclosures
    2217         $this->add_enclosure_if_new($post_ID, $content_struct['enclosure']);
    2218 
    2219         $this->attach_uploads( $post_ID, $post_content );
    2220 
    2221         logIO('O', "Posted ! ID: $post_ID");
    2222 
    2223         return strval($post_ID);
    2224     }
    2225 
    2226     function add_enclosure_if_new($post_ID, $enclosure) {
    2227         if ( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) {
    2228 
    2229             $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'];
    2230             $found = false;
    2231             foreach ( (array) get_post_custom($post_ID) as $key => $val) {
    2232                 if ($key == 'enclosure') {
    2233                     foreach ( (array) $val as $enc ) {
    2234                         if ($enc == $encstring) {
    2235                             $found = true;
    2236                             break 2;
    2237                         }
    2238                     }
    2239                 }
    2240             }
    2241             if (!$found)
    2242                 add_post_meta( $post_ID, 'enclosure', $encstring );
    2243         }
    2244     }
    2245 
    2246     /**
    2247      * Attach upload to a post.
    2248      *
    2249      * @since 2.1.0
    2250      *
    2251      * @param int $post_ID Post ID.
    2252      * @param string $post_content Post Content for attachment.
    2253      */
    2254     function attach_uploads( $post_ID, $post_content ) {
    2255         global $wpdb;
    2256 
    2257         // find any unattached files
    2258         $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" );
    2259         if ( is_array( $attachments ) ) {
    2260             foreach ( $attachments as $file ) {
    2261                 if ( strpos( $post_content, $file->guid ) !== false )
    2262                     $wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) );
    2263             }
    2264         }
    2265     }
    2266 
    2267     /**
    2268      * Edit a post.
    2269      *
    2270      * @since 1.5.0
    2271      *
    2272      * @param array $args Method parameters.
    2273      * @return bool True on success.
    2274      */
    2275     function mw_editPost($args) {
    2276 
    2277         $this->escape($args);
    2278 
    2279         $post_ID     = (int) $args[0];
    2280         $username  = $args[1];
    2281         $password   = $args[2];
    2282         $content_struct = $args[3];
    2283         $publish     = $args[4];
    2284 
    2285         if ( !$user = $this->login($username, $password) )
    2286             return $this->error;
    2287 
    2288         do_action('xmlrpc_call', 'metaWeblog.editPost');
    2289 
    2290         $cap = ( $publish ) ? 'publish_posts' : 'edit_posts';
    2291         $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
    2292         $post_type = 'post';
    2293         $page_template = '';
    2294         if ( !empty( $content_struct['post_type'] ) ) {
    2295             if ( $content_struct['post_type'] == 'page' ) {
    2296                 if ( $publish || 'publish' == $content_struct['page_status'] )
    2297                     $cap  = 'publish_pages';
    2298                 else
    2299                     $cap = 'edit_pages';
    2300                 $error_message = __( 'Sorry, you are not allowed to publish pages on this site.' );
    2301                 $post_type = 'page';
    2302                 if ( !empty( $content_struct['wp_page_template'] ) )
    2303                     $page_template = $content_struct['wp_page_template'];
    2304             } elseif ( $content_struct['post_type'] == 'post' ) {
    2305                 if ( $publish || 'publish' == $content_struct['post_status'] )
    2306                     $cap  = 'publish_posts';
    2307                 else
    2308                     $cap = 'edit_posts';
    2309                 $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
    2310                 $post_type = 'post';
    2311             } else {
    2312                 // No other post_type values are allowed here
    2313                 return new IXR_Error( 401, __( 'Invalid post type.' ) );
    2314             }
    2315         } else {
    2316             if ( $publish || 'publish' == $content_struct['post_status'] )
    2317                 $cap  = 'publish_posts';
    2318             else
    2319                 $cap = 'edit_posts';
    2320             $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
    2321             $post_type = 'post';
    2322         }
    2323 
    2324         if ( !current_user_can( $cap ) )
    2325             return new IXR_Error( 401, $error_message );
    2326 
    2327         $postdata = wp_get_single_post($post_ID, ARRAY_A);
    2328 
    2329         // If there is no post data for the give post id, stop
    2330         // now and return an error.  Other wise a new post will be
    2331         // created (which was the old behavior).
    2332         if ( empty($postdata["ID"]) )
    2333             return(new IXR_Error(404, __("Invalid post ID.")));
    2334 
    2335         $this->escape($postdata);
    2336         extract($postdata, EXTR_SKIP);
    2337 
    2338         // Let WordPress manage slug if none was provided.
    2339         $post_name = "";
    2340         if ( isset($content_struct["wp_slug"]) )
    2341             $post_name = $content_struct["wp_slug"];
    2342 
    2343         // Only use a password if one was given.
    2344         if ( isset($content_struct["wp_password"]) )
    2345             $post_password = $content_struct["wp_password"];
    2346 
    2347         // Only set a post parent if one was given.
    2348         if ( isset($content_struct["wp_page_parent_id"]) )
    2349             $post_parent = $content_struct["wp_page_parent_id"];
    2350 
    2351         // Only set the menu_order if it was given.
    2352         if ( isset($content_struct["wp_page_order"]) )
    2353             $menu_order = $content_struct["wp_page_order"];
    2354 
    2355         $post_author = $postdata["post_author"];
    2356 
    2357         // Only set the post_author if one is set.
    2358         if ( isset($content_struct["wp_author_id"]) && ($user->ID != $content_struct["wp_author_id"]) ) {
    2359             switch ( $post_type ) {
    2360                 case "post":
    2361                     if ( !current_user_can("edit_others_posts") )
    2362                         return(new IXR_Error(401, __("You are not allowed to change the post author as this user.")));
    2363                     break;
    2364                 case "page":
    2365                     if ( !current_user_can("edit_others_pages") )
    2366                         return(new IXR_Error(401, __("You are not allowed to change the page author as this user.")));
    2367                     break;
    2368                 default:
    2369                     return(new IXR_Error(401, __("Invalid post type.")));
    2370                     break;
    2371             }
    2372             $post_author = $content_struct["wp_author_id"];
    2373         }
    2374 
    2375         if ( isset($content_struct["mt_allow_comments"]) ) {
    2376             if ( !is_numeric($content_struct["mt_allow_comments"]) ) {
    2377                 switch ( $content_struct["mt_allow_comments"] ) {
    2378                     case "closed":
    2379                         $comment_status = "closed";
    2380                         break;
    2381                     case "open":
    2382                         $comment_status = "open";
    2383                         break;
    2384                     default:
    2385                         $comment_status = get_option("default_comment_status");
    2386                         break;
    2387                 }
    2388             } else {
    2389                 switch ( (int) $content_struct["mt_allow_comments"] ) {
    2390                     case 0:
    2391                     case 2:
    2392                         $comment_status = "closed";
    2393                         break;
    2394                     case 1:
    2395                         $comment_status = "open";
    2396                         break;
    2397                     default:
    2398                         $comment_status = get_option("default_comment_status");
    2399                         break;
    2400                 }
    2401             }
    2402         }
    2403 
    2404         if ( isset($content_struct["mt_allow_pings"]) ) {
    2405             if ( !is_numeric($content_struct["mt_allow_pings"]) ) {
    2406                 switch ( $content_struct["mt_allow_pings"] ) {
    2407                     case "closed":
    2408                         $ping_status = "closed";
    2409                         break;
    2410                     case "open":
    2411                         $ping_status = "open";
    2412                         break;
    2413                     default:
    2414                         $ping_status = get_option("default_ping_status");
    2415                         break;
    2416                 }
    2417             } else {
    2418                 switch ( (int) $content_struct["mt_allow_pings"] ) {
    2419                     case 0:
    2420                         $ping_status = "closed";
    2421                         break;
    2422                     case 1:
    2423                         $ping_status = "open";
    2424                         break;
    2425                     default:
    2426                         $ping_status = get_option("default_ping_status");
    2427                         break;
    2428                 }
    2429             }
    2430         }
    2431 
    2432         $post_title = $content_struct['title'];
    2433         $post_content = $content_struct['description'];
    2434         $catnames = $content_struct['categories'];
    2435 
    2436         $post_category = array();
    2437 
    2438         if ( is_array($catnames) ) {
    2439             foreach ($catnames as $cat) {
    2440                 $post_category[] = get_cat_ID($cat);
    2441             }
    2442         }
    2443 
    2444         $post_excerpt = $content_struct['mt_excerpt'];
    2445         $post_more = $content_struct['mt_text_more'];
    2446 
    2447         $post_status = $publish ? 'publish' : 'draft';
    2448         if ( isset( $content_struct["{$post_type}_status"] ) ) {
    2449             switch( $content_struct["{$post_type}_status"] ) {
    2450                 case 'draft':
    2451                 case 'private':
    2452                 case 'publish':
    2453                     $post_status = $content_struct["{$post_type}_status"];
    2454                     break;
    2455                 case 'pending':
    2456                     // Pending is only valid for posts, not pages.
    2457                     if ( $post_type === 'post' )
    2458                         $post_status = $content_struct["{$post_type}_status"];
    2459                     break;
    2460                 default:
    2461                     $post_status = $publish ? 'publish' : 'draft';
    2462                     break;
    2463             }
    2464         }
    2465 
    2466         $tags_input = $content_struct['mt_keywords'];
    2467 
    2468         if ( ('publish' == $post_status) ) {
    2469             if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') )
    2470                 return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.'));
    2471             else if ( !current_user_can('publish_posts') )
    2472                 return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
    2473         }
    2474 
    2475         if ( $post_more )
    2476             $post_content = $post_content . "<!--more-->" . $post_more;
    2477 
    2478         $to_ping = $content_struct['mt_tb_ping_urls'];
    2479         if ( is_array($to_ping) )
    2480             $to_ping = implode(' ', $to_ping);
    2481 
    2482         // Do some timestamp voodoo
    2483         if ( !empty( $content_struct['date_created_gmt'] ) )
    2484             $dateCreated = str_replace( 'Z', '', $content_struct['date_created_gmt']->getIso() ) . 'Z'; // We know this is supposed to be GMT, so we're going to slap that Z on there by force
    2485         elseif ( !empty( $content_struct['dateCreated']) )
    2486             $dateCreated = $content_struct['dateCreated']->getIso();
    2487 
    2488         if ( !empty( $dateCreated ) ) {
    2489             $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
    2490             $post_date_gmt = iso8601_to_datetime($dateCreated, GMT);
    2491         } else {
    2492             $post_date     = $postdata['post_date'];
    2493             $post_date_gmt = $postdata['post_date_gmt'];
    2494         }
    2495 
    2496         // We've got all the data -- post it:
    2497         $newpost = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt', 'comment_status', 'ping_status', 'post_date', 'post_date_gmt', 'to_ping', 'post_name', 'post_password', 'post_parent', 'menu_order', 'post_author', 'tags_input', 'page_template');
    2498 
    2499         $result = wp_update_post($newpost, true);
    2500         if ( is_wp_error( $result ) )
    2501             return new IXR_Error(500, $result->get_error_message());
    2502 
    2503         if ( !$result )
    2504             return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.'));
    2505 
    2506         // Only posts can be sticky
    2507         if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
    2508             if ( $content_struct['sticky'] == true )
    2509                 stick_post( $post_ID );
    2510             elseif ( $content_struct['sticky'] == false )
    2511                 unstick_post( $post_ID );
    2512         }
    2513 
    2514         if ( isset($content_struct['custom_fields']) )
    2515             $this->set_custom_fields($post_ID, $content_struct['custom_fields']);
    2516 
    2517         // Handle enclosures
    2518         $this->add_enclosure_if_new($post_ID, $content_struct['enclosure']);
    2519 
    2520         $this->attach_uploads( $ID, $post_content );
    2521 
    2522         logIO('O',"(MW) Edited ! ID: $post_ID");
    2523 
    2524         return true;
    2525     }
    2526 
    2527     /**
    2528      * Retrieve post.
    2529      *
    2530      * @since 1.5.0
    2531      *
    2532      * @param array $args Method parameters.
    2533      * @return array
    2534      */
    2535     function mw_getPost($args) {
    2536 
    2537         $this->escape($args);
    2538 
    2539         $post_ID     = (int) $args[0];
    2540         $username  = $args[1];
    2541         $password   = $args[2];
    2542 
    2543         if ( !$user = $this->login($username, $password) )
    2544             return $this->error;
    2545 
    2546         if ( !current_user_can( 'edit_post', $post_ID ) )
    2547             return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
    2548 
    2549         do_action('xmlrpc_call', 'metaWeblog.getPost');
    2550 
    2551         $postdata = wp_get_single_post($post_ID, ARRAY_A);
    2552 
    2553         if ($postdata['post_date'] != '') {
    2554             $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date'], false);
    2555             $post_date_gmt = mysql2date('Ymd\TH:i:s', $postdata['post_date_gmt'], false);
    2556 
    2557             // For drafts use the GMT version of the post date
    2558             if ( $postdata['post_status'] == 'draft' )
    2559                 $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $postdata['post_date'] ), 'Ymd\TH:i:s' );
    2560 
    2561             $categories = array();
    2562             $catids = wp_get_post_categories($post_ID);
    2563             foreach($catids as $catid)
    2564                 $categories[] = get_cat_name($catid);
    2565 
    2566             $tagnames = array();
    2567             $tags = wp_get_post_tags( $post_ID );
    2568             if ( !empty( $tags ) ) {
    2569                 foreach ( $tags as $tag )
    2570                     $tagnames[] = $tag->name;
    2571                 $tagnames = implode( ', ', $tagnames );
    2572             } else {
    2573                 $tagnames = '';
    2574             }
    2575 
    2576             $post = get_extended($postdata['post_content']);
    2577             $link = post_permalink($postdata['ID']);
    2578 
    2579             // Get the author info.
    2580             $author = get_userdata($postdata['post_author']);
    2581 
    2582             $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
    2583             $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
    2584 
    2585             // Consider future posts as published
    2586             if ( $postdata['post_status'] === 'future' )
    2587                 $postdata['post_status'] = 'publish';
    2588 
    2589             $sticky = false;
    2590             if ( is_sticky( $post_ID ) )
    2591                 $sticky = true;
    2592 
    2593             $enclosure = array();
    2594             foreach ( (array) get_post_custom($post_ID) as $key => $val) {
    2595                 if ($key == 'enclosure') {
    2596                     foreach ( (array) $val as $enc ) {
    2597                         $encdata = split("\n", $enc);
    2598                         $enclosure['url'] = trim(htmlspecialchars($encdata[0]));
    2599                         $enclosure['length'] = (int) trim($encdata[1]);
    2600                         $enclosure['type'] = trim($encdata[2]);
    2601                         break 2;
    2602                     }
    2603                 }
    2604             }
    2605 
    2606             $resp = array(
    2607                 'dateCreated' => new IXR_Date($post_date),
    2608                 'userid' => $postdata['post_author'],
    2609                 'postid' => $postdata['ID'],
    2610                 'description' => $post['main'],
    2611                 'title' => $postdata['post_title'],
    2612                 'link' => $link,
    2613                 'permaLink' => $link,
    2614                 // commented out because no other tool seems to use this
    2615                 //        'content' => $entry['post_content'],
    2616                 'categories' => $categories,
    2617                 'mt_excerpt' => $postdata['post_excerpt'],
    2618                 'mt_text_more' => $post['extended'],
    2619                 'mt_allow_comments' => $allow_comments,
    2620                 'mt_allow_pings' => $allow_pings,
    2621                 'mt_keywords' => $tagnames,
    2622                 'wp_slug' => $postdata['post_name'],
    2623                 'wp_password' => $postdata['post_password'],
    2624                 'wp_author_id' => $author->ID,
    2625                 'wp_author_display_name'    => $author->display_name,
    2626                 'date_created_gmt' => new IXR_Date($post_date_gmt),
    2627                 'post_status' => $postdata['post_status'],
    2628                 'custom_fields' => $this->get_custom_fields($post_ID),
    2629                 'sticky' => $sticky
    2630             );
    2631 
    2632             if ( !empty($enclosure) ) $resp['enclosure'] = $enclosure;
    2633 
    2634             return $resp;
    2635         } else {
    2636             return new IXR_Error(404, __('Sorry, no such post.'));
    2637         }
    2638     }
    2639 
    2640     /**
    2641      * Retrieve list of recent posts.
    2642      *
    2643      * @since 1.5.0
    2644      *
    2645      * @param array $args Method parameters.
    2646      * @return array
    2647      */
    2648     function mw_getRecentPosts($args) {
    2649 
    2650         $this->escape($args);
    2651 
    2652         $blog_ID     = (int) $args[0];
    2653         $username  = $args[1];
    2654         $password   = $args[2];
    2655         $num_posts   = (int) $args[3];
    2656 
    2657         if ( !$user = $this->login($username, $password) )
    2658             return $this->error;
    2659 
    2660         do_action('xmlrpc_call', 'metaWeblog.getRecentPosts');
    2661 
    2662         $posts_list = wp_get_recent_posts($num_posts);
    2663 
    2664         if ( !$posts_list )
    2665             return array( );
    2666 
    2667         foreach ($posts_list as $entry) {
    2668             if ( !current_user_can( 'edit_post', $entry['ID'] ) )
    2669                 continue;
    2670 
    2671             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false);
    2672             $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt'], false);
    2673 
    2674             // For drafts use the GMT version of the date
    2675             if ( $entry['post_status'] == 'draft' )
    2676                 $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $entry['post_date'] ), 'Ymd\TH:i:s' );
    2677 
    2678             $categories = array();
    2679             $catids = wp_get_post_categories($entry['ID']);
    2680             foreach( $catids as $catid )
    2681                 $categories[] = get_cat_name($catid);
    2682 
    2683             $tagnames = array();
    2684             $tags = wp_get_post_tags( $entry['ID'] );
    2685             if ( !empty( $tags ) ) {
    2686                 foreach ( $tags as $tag ) {
    2687                     $tagnames[] = $tag->name;
    2688                 }
    2689                 $tagnames = implode( ', ', $tagnames );
    2690             } else {
    2691                 $tagnames = '';
    2692             }
    2693 
    2694             $post = get_extended($entry['post_content']);
    2695             $link = post_permalink($entry['ID']);
    2696 
    2697             // Get the post author info.
    2698             $author = get_userdata($entry['post_author']);
    2699 
    2700             $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
    2701             $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
    2702 
    2703             // Consider future posts as published
    2704             if ( $entry['post_status'] === 'future' )
    2705                 $entry['post_status'] = 'publish';
    2706 
    2707             $struct[] = array(
    2708                 'dateCreated' => new IXR_Date($post_date),
    2709                 'userid' => $entry['post_author'],
    2710                 'postid' => $entry['ID'],
    2711                 'description' => $post['main'],
    2712                 'title' => $entry['post_title'],
    2713                 'link' => $link,
    2714                 'permaLink' => $link,
    2715                 // commented out because no other tool seems to use this
    2716                 // 'content' => $entry['post_content'],
    2717                 'categories' => $categories,
    2718                 'mt_excerpt' => $entry['post_excerpt'],
    2719                 'mt_text_more' => $post['extended'],
    2720                 'mt_allow_comments' => $allow_comments,
    2721                 'mt_allow_pings' => $allow_pings,
    2722                 'mt_keywords' => $tagnames,
    2723                 'wp_slug' => $entry['post_name'],
    2724                 'wp_password' => $entry['post_password'],
    2725                 'wp_author_id' => $author->ID,
    2726                 'wp_author_display_name' => $author->display_name,
    2727                 'date_created_gmt' => new IXR_Date($post_date_gmt),
    2728                 'post_status' => $entry['post_status'],
    2729                 'custom_fields' => $this->get_custom_fields($entry['ID'])
    2730             );
    2731 
    2732         }
    2733 
    2734         $recent_posts = array();
    2735         for ( $j=0; $j<count($struct); $j++ ) {
    2736             array_push($recent_posts, $struct[$j]);
    2737         }
    2738 
    2739         return $recent_posts;
    2740     }
    2741 
    2742     /**
    2743      * Retrieve the list of categories on a given blog.
    2744      *
    2745      * @since 1.5.0
    2746      *
    2747      * @param array $args Method parameters.
    2748      * @return array
    2749      */
    2750     function mw_getCategories($args) {
    2751 
    2752         $this->escape($args);
    2753 
    2754         $blog_ID     = (int) $args[0];
    2755         $username  = $args[1];
    2756         $password   = $args[2];
    2757 
    2758         if ( !$user = $this->login($username, $password) )
    2759             return $this->error;
    2760 
    2761         if ( !current_user_can( 'edit_posts' ) )
    2762             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
    2763 
    2764         do_action('xmlrpc_call', 'metaWeblog.getCategories');
    2765 
    2766         $categories_struct = array();
    2767 
    2768         if ( $cats = get_categories(array('get' => 'all')) ) {
    2769             foreach ( $cats as $cat ) {
    2770                 $struct['categoryId'] = $cat->term_id;
    2771                 $struct['parentId'] = $cat->parent;
    2772                 $struct['description'] = $cat->name;
    2773                 $struct['categoryDescription'] = $cat->description;
    2774                 $struct['categoryName'] = $cat->name;
    2775                 $struct['htmlUrl'] = esc_html(get_category_link($cat->term_id));
    2776                 $struct['rssUrl'] = esc_html(get_category_feed_link($cat->term_id, 'rss2'));
    2777 
    2778                 $categories_struct[] = $struct;
    2779             }
    2780         }
    2781 
    2782         return $categories_struct;
    2783     }
    2784 
    2785     /**
    2786      * Uploads a file, following your settings.
    2787      *
    2788      * Adapted from a patch by Johann Richard.
    2789      *
    2790      * @link http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
    2791      *
    2792      * @since 1.5.0
    2793      *
    2794      * @param array $args Method parameters.
    2795      * @return array
    2796      */
    2797     function mw_newMediaObject($args) {
    2798         global $wpdb;
    2799 
    2800         $blog_ID     = (int) $args[0];
    2801         $username  = $wpdb->escape($args[1]);
    2802         $password   = $wpdb->escape($args[2]);
    2803         $data        = $args[3];
    2804 
    2805         $name = sanitize_file_name( $data['name'] );
    2806         $type = $data['type'];
    2807         $bits = $data['bits'];
    2808 
    2809         logIO('O', '(MW) Received '.strlen($bits).' bytes');
    2810 
    2811         if ( !$user = $this->login($username, $password) )
    2812             return $this->error;
    2813 
    2814         do_action('xmlrpc_call', 'metaWeblog.newMediaObject');
    2815 
    2816         if ( !current_user_can('upload_files') ) {
    2817             logIO('O', '(MW) User does not have upload_files capability');
    2818             $this->error = new IXR_Error(401, __('You are not allowed to upload files to this site.'));
    2819             return $this->error;
    2820         }
    2821 
    2822         if ( $upload_err = apply_filters( "pre_upload_error", false ) )
    2823             return new IXR_Error(500, $upload_err);
    2824 
    2825         if ( !empty($data["overwrite"]) && ($data["overwrite"] == true) ) {
    2826             // Get postmeta info on the object.
    2827             $old_file = $wpdb->get_row("
    2828                 SELECT ID
    2829                 FROM {$wpdb->posts}
    2830                 WHERE post_title = '{$name}'
    2831                     AND post_type = 'attachment'
    2832             ");
    2833 
    2834             // Delete previous file.
    2835             wp_delete_attachment($old_file->ID);
    2836 
    2837             // Make sure the new name is different by pre-pending the
    2838             // previous post id.
    2839             $filename = preg_replace("/^wpid\d+-/", "", $name);
    2840             $name = "wpid{$old_file->ID}-{$filename}";
    2841         }
    2842 
    2843         $upload = wp_upload_bits($name, $type, $bits);
    2844         if ( ! empty($upload['error']) ) {
    2845             $errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']);
    2846             logIO('O', '(MW) ' . $errorString);
    2847             return new IXR_Error(500, $errorString);
    2848         }
    2849         // Construct the attachment array
    2850         // attach to post_id 0
    2851         $post_id = 0;
    2852         $attachment = array(
    2853             'post_title' => $name,
    2854             'post_content' => '',
    2855             'post_type' => 'attachment',
    2856             'post_parent' => $post_id,
    2857             'post_mime_type' => $type,
    2858             'guid' => $upload[ 'url' ]
    2859         );
    2860 
    2861         // Save the data
    2862         $id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id );
    2863         wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
    2864 
    2865         return apply_filters( 'wp_handle_upload', array( 'file' => $name, 'url' => $upload[ 'url' ], 'type' => $type ), 'upload' );
    2866     }
    2867 
    2868     /* MovableType API functions
    2869      * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
    2870      */
    2871 
    2872     /**
    2873      * Retrieve the post titles of recent posts.
    2874      *
    2875      * @since 1.5.0
    2876      *
    2877      * @param array $args Method parameters.
    2878      * @return array
    2879      */
    2880     function mt_getRecentPostTitles($args) {
    2881 
    2882         $this->escape($args);
    2883 
    2884         $blog_ID     = (int) $args[0];
    2885         $username  = $args[1];
    2886         $password   = $args[2];
    2887         $num_posts   = (int) $args[3];
    2888 
    2889         if ( !$user = $this->login($username, $password) )
    2890             return $this->error;
    2891 
    2892         do_action('xmlrpc_call', 'mt.getRecentPostTitles');
    2893 
    2894         $posts_list = wp_get_recent_posts($num_posts);
    2895 
    2896         if ( !$posts_list ) {
    2897             $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
    2898             return $this->error;
    2899         }
    2900 
    2901         foreach ($posts_list as $entry) {
    2902             if ( !current_user_can( 'edit_post', $entry['ID'] ) )
    2903                 continue;
    2904 
    2905             $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false);
    2906             $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt'], false);
    2907 
    2908             // For drafts use the GMT version of the date
    2909             if ( $entry['post_status'] == 'draft' )
    2910                 $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $entry['post_date'] ), 'Ymd\TH:i:s' );
    2911 
    2912             $struct[] = array(
    2913                 'dateCreated' => new IXR_Date($post_date),
    2914                 'userid' => $entry['post_author'],
    2915                 'postid' => $entry['ID'],
    2916                 'title' => $entry['post_title'],
    2917                 'date_created_gmt' => new IXR_Date($post_date_gmt)
    2918             );
    2919 
    2920         }
    2921 
    2922         $recent_posts = array();
    2923         for ( $j=0; $j<count($struct); $j++ ) {
    2924             array_push($recent_posts, $struct[$j]);
    2925         }
    2926 
    2927         return $recent_posts;
    2928     }
    2929 
    2930     /**
    2931      * Retrieve list of all categories on blog.
    2932      *
    2933      * @since 1.5.0
    2934      *
    2935      * @param array $args Method parameters.
    2936      * @return array
    2937      */
    2938     function mt_getCategoryList($args) {
    2939 
    2940         $this->escape($args);
    2941 
    2942         $blog_ID     = (int) $args[0];
    2943         $username  = $args[1];
    2944         $password   = $args[2];
    2945 
    2946         if ( !$user = $this->login($username, $password) )
    2947             return $this->error;
    2948 
    2949         if ( !current_user_can( 'edit_posts' ) )
    2950             return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
    2951 
    2952         do_action('xmlrpc_call', 'mt.getCategoryList');
    2953 
    2954         $categories_struct = array();
    2955 
    2956         if ( $cats = get_categories(array('hide_empty' => 0, 'hierarchical' => 0)) ) {
    2957             foreach ( $cats as $cat ) {
    2958                 $struct['categoryId'] = $cat->term_id;
    2959                 $struct['categoryName'] = $cat->name;
    2960 
    2961                 $categories_struct[] = $struct;
    2962             }
    2963         }
    2964 
    2965         return $categories_struct;
    2966     }
    2967 
    2968     /**
    2969      * Retrieve post categories.
    2970      *
    2971      * @since 1.5.0
    2972      *
    2973      * @param array $args Method parameters.
    2974      * @return array
    2975      */
    2976     function mt_getPostCategories($args) {
    2977 
    2978         $this->escape($args);
    2979 
    2980         $post_ID     = (int) $args[0];
    2981         $username  = $args[1];
    2982         $password   = $args[2];
    2983 
    2984         if ( !$user = $this->login($username, $password) )
    2985             return $this->error;
    2986 
    2987         if ( !current_user_can( 'edit_post', $post_ID ) )
    2988             return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
    2989 
    2990         do_action('xmlrpc_call', 'mt.getPostCategories');
    2991 
    2992         $categories = array();
    2993         $catids = wp_get_post_categories(intval($post_ID));
    2994         // first listed category will be the primary category
    2995         $isPrimary = true;
    2996         foreach ( $catids as $catid ) {
    2997             $categories[] = array(
    2998                 'categoryName' => get_cat_name($catid),
    2999                 'categoryId' => (string) $catid,
    3000                 'isPrimary' => $isPrimary
    3001             );
    3002             $isPrimary = false;
    3003         }
    3004 
    3005         return $categories;
    3006     }
    3007 
    3008     /**
    3009      * Sets categories for a post.
    3010      *
    3011      * @since 1.5.0
    3012      *
    3013      * @param array $args Method parameters.
    3014      * @return bool True on success.
    3015      */
    3016     function mt_setPostCategories($args) {
    3017 
    3018         $this->escape($args);
    3019 
    3020         $post_ID     = (int) $args[0];
    3021         $username  = $args[1];
    3022         $password   = $args[2];
    3023         $categories  = $args[3];
    3024 
    3025         if ( !$user = $this->login($username, $password) )
    3026             return $this->error;
    3027 
    3028         do_action('xmlrpc_call', 'mt.setPostCategories');
    3029 
    3030         if ( !current_user_can('edit_post', $post_ID) )
    3031             return new IXR_Error(401, __('Sorry, you cannot edit this post.'));
    3032 
    3033         foreach ( $categories as $cat ) {
    3034             $catids[] = $cat['categoryId'];
    3035         }
    3036 
    3037         wp_set_post_categories($post_ID, $catids);
    3038 
    3039         return true;
    3040     }
    3041 
    3042     /**
    3043      * Retrieve an array of methods supported by this server.
    3044      *
    3045      * @since 1.5.0
    3046      *
    3047      * @param array $args Method parameters.
    3048      * @return array
    3049      */
    3050     function mt_supportedMethods($args) {
    3051 
    3052         do_action('xmlrpc_call', 'mt.supportedMethods');
    3053 
    3054         $supported_methods = array();
    3055         foreach ( $this->methods as $key => $value ) {
    3056             $supported_methods[] = $key;
    3057         }
    3058 
    3059         return $supported_methods;
    3060     }
    3061 
    3062     /**
    3063      * Retrieve an empty array because we don't support per-post text filters.
    3064      *
    3065      * @since 1.5.0
    3066      *
    3067      * @param array $args Method parameters.
    3068      */
    3069     function mt_supportedTextFilters($args) {
    3070         do_action('xmlrpc_call', 'mt.supportedTextFilters');
    3071         return apply_filters('xmlrpc_text_filters', array());
    3072     }
    3073 
    3074     /**
    3075      * Retrieve trackbacks sent to a given post.
    3076      *
    3077      * @since 1.5.0
    3078      *
    3079      * @param array $args Method parameters.
    3080      * @return mixed
    3081      */
    3082     function mt_getTrackbackPings($args) {
    3083 
    3084         global $wpdb;
    3085 
    3086         $post_ID = intval($args);
    3087 
    3088         do_action('xmlrpc_call', 'mt.getTrackbackPings');
    3089 
    3090         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
    3091 
    3092         if ( !$actual_post )
    3093             return new IXR_Error(404, __('Sorry, no such post.'));
    3094 
    3095         $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) );
    3096 
    3097         if ( !$comments )
    3098             return array();
    3099 
    3100         $trackback_pings = array();
    3101         foreach ( $comments as $comment ) {
    3102             if ( 'trackback' == $comment->comment_type ) {
    3103                 $content = $comment->comment_content;
    3104                 $title = substr($content, 8, (strpos($content, '</strong>') - 8));
    3105                 $trackback_pings[] = array(
    3106                     'pingTitle' => $title,
    3107                     'pingURL'   => $comment->comment_author_url,
    3108                     'pingIP'    => $comment->comment_author_IP
    3109                 );
    3110             }
    3111         }
    3112 
    3113         return $trackback_pings;
    3114     }
    3115 
    3116     /**
    3117      * Sets a post's publish status to 'publish'.
    3118      *
    3119      * @since 1.5.0
    3120      *
    3121      * @param array $args Method parameters.
    3122      * @return int
    3123      */
    3124     function mt_publishPost($args) {
    3125 
    3126         $this->escape($args);
    3127 
    3128         $post_ID     = (int) $args[0];
    3129         $username  = $args[1];
    3130         $password   = $args[2];
    3131 
    3132         if ( !$user = $this->login($username, $password) )
    3133             return $this->error;
    3134 
    3135         do_action('xmlrpc_call', 'mt.publishPost');
    3136 
    3137         if ( !current_user_can('publish_posts') || !current_user_can('edit_post', $post_ID) )
    3138             return new IXR_Error(401, __('Sorry, you cannot edit this post.'));
    3139 
    3140         $postdata = wp_get_single_post($post_ID,ARRAY_A);
    3141 
    3142         $postdata['post_status'] = 'publish';
    3143 
    3144         // retain old cats
    3145         $cats = wp_get_post_categories($post_ID);
    3146         $postdata['post_category'] = $cats;
    3147         $this->escape($postdata);
    3148 
    3149         $result = wp_update_post($postdata);
    3150 
    3151         return $result;
    3152     }
    3153 
    3154     /* PingBack functions
    3155      * specs on www.hixie.ch/specs/pingback/pingback
    3156      */
    3157 
    3158     /**
    3159      * Retrieves a pingback and registers it.
    3160      *
    3161      * @since 1.5.0
    3162      *
    3163      * @param array $args Method parameters.
    3164      * @return array
    3165      */
    3166     function pingback_ping($args) {
    3167         global $wpdb;
    3168 
    3169         do_action('xmlrpc_call', 'pingback.ping');
    3170 
    3171         $this->escape($args);
    3172 
    3173         $pagelinkedfrom = $args[0];
    3174         $pagelinkedto   = $args[1];
    3175 
    3176         $title = '';
    3177 
    3178         $pagelinkedfrom = str_replace('&amp;', '&', $pagelinkedfrom);
    3179         $pagelinkedto = str_replace('&amp;', '&', $pagelinkedto);
    3180         $pagelinkedto = str_replace('&', '&amp;', $pagelinkedto);
    3181 
    3182         // Check if the page linked to is in our site
    3183         $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
    3184         if ( !$pos1 )
    3185             return new IXR_Error(0, __('Is there no link to us?'));
    3186 
    3187         // let's find which post is linked to
    3188         // FIXME: does url_to_postid() cover all these cases already?
    3189         //        if so, then let's use it and drop the old code.
    3190         $urltest = parse_url($pagelinkedto);
    3191         if ( $post_ID = url_to_postid($pagelinkedto) ) {
    3192             $way = 'url_to_postid()';
    3193         } elseif ( preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) {
    3194             // the path defines the post_ID (archives/p/XXXX)
    3195             $blah = explode('/', $match[0]);
    3196             $post_ID = (int) $blah[1];
    3197             $way = 'from the path';
    3198         } elseif ( preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) {
    3199             // the querystring defines the post_ID (?p=XXXX)
    3200             $blah = explode('=', $match[0]);
    3201             $post_ID = (int) $blah[1];
    3202             $way = 'from the querystring';
    3203         } elseif ( isset($urltest['fragment']) ) {
    3204             // an #anchor is there, it's either...
    3205             if ( intval($urltest['fragment']) ) {
    3206                 // ...an integer #XXXX (simpliest case)
    3207                 $post_ID = (int) $urltest['fragment'];
    3208                 $way = 'from the fragment (numeric)';
    3209             } elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) {
    3210                 // ...a post id in the form 'post-###'
    3211                 $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
    3212                 $way = 'from the fragment (post-###)';
    3213             } elseif ( is_string($urltest['fragment']) ) {
    3214                 // ...or a string #title, a little more complicated
    3215                 $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
    3216                 $sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", $title);
    3217                 if (! ($post_ID = $wpdb->get_var($sql)) ) {
    3218                     // returning unknown error '0' is better than die()ing
    3219                     return new IXR_Error(0, '');
    3220                 }
    3221                 $way = 'from the fragment (title)';
    3222             }
    3223         } else {
    3224             // TODO: Attempt to extract a post ID from the given URL
    3225             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3226         }
    3227         $post_ID = (int) $post_ID;
    3228 
    3229 
    3230         logIO("O","(PB) URL='$pagelinkedto' ID='$post_ID' Found='$way'");
    3231 
    3232         $post = get_post($post_ID);
    3233 
    3234         if ( !$post ) // Post_ID not found
    3235             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3236 
    3237         if ( $post_ID == url_to_postid($pagelinkedfrom) )
    3238             return new IXR_Error(0, __('The source URL and the target URL cannot both point to the same resource.'));
    3239 
    3240         // Check if pings are on
    3241         if ( !pings_open($post) )
    3242             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3243 
    3244         // Let's check that the remote site didn't already pingback this entry
    3245         if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) )
    3246             return new IXR_Error( 48, __( 'The pingback has already been registered.' ) );
    3247 
    3248         // very stupid, but gives time to the 'from' server to publish !
    3249         sleep(1);
    3250 
    3251         // Let's check the remote site
    3252         $linea = wp_remote_fopen( $pagelinkedfrom );
    3253         if ( !$linea )
    3254             return new IXR_Error(16, __('The source URL does not exist.'));
    3255 
    3256         $linea = apply_filters('pre_remote_source', $linea, $pagelinkedto);
    3257 
    3258         // Work around bug in strip_tags():
    3259         $linea = str_replace('<!DOC', '<DOC', $linea);
    3260         $linea = preg_replace( '/[\s\r\n\t]+/', ' ', $linea ); // normalize spaces
    3261         $linea = preg_replace( "/ <(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea );
    3262 
    3263         preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
    3264         $title = $matchtitle[1];
    3265         if ( empty( $title ) )
    3266             return new IXR_Error(32, __('We cannot find a title on that page.'));
    3267 
    3268         $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
    3269 
    3270         $p = explode( "\n\n", $linea );
    3271 
    3272         $preg_target = preg_quote($pagelinkedto, '|');
    3273 
    3274         foreach ( $p as $para ) {
    3275             if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
    3276                 preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
    3277 
    3278                 // If the URL isn't in a link context, keep looking
    3279                 if ( empty($context) )
    3280                     continue;
    3281 
    3282                 // We're going to use this fake tag to mark the context in a bit
    3283                 // the marker is needed in case the link text appears more than once in the paragraph
    3284                 $excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
    3285 
    3286                 // prevent really long link text
    3287                 if ( strlen($context[1]) > 100 )
    3288                     $context[1] = substr($context[1], 0, 100) . '...';
    3289 
    3290                 $marker = '<wpcontext>'.$context[1].'</wpcontext>';    // set up our marker
    3291                 $excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
    3292                 $excerpt = strip_tags($excerpt, '<wpcontext>');        // strip all tags but our context marker
    3293                 $excerpt = trim($excerpt);
    3294                 $preg_marker = preg_quote($marker, '|');
    3295                 $excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
    3296                 $excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
    3297                 break;
    3298             }
    3299         }
    3300 
    3301         if ( empty($context) ) // Link to target not found
    3302             return new IXR_Error(17, __('The source URL does not contain a link to the target URL, and so cannot be used as a source.'));
    3303 
    3304         $pagelinkedfrom = str_replace('&', '&amp;', $pagelinkedfrom);
    3305 
    3306         $context = '[...] ' . esc_html( $excerpt ) . ' [...]';
    3307         $pagelinkedfrom = $wpdb->escape( $pagelinkedfrom );
    3308 
    3309         $comment_post_ID = (int) $post_ID;
    3310         $comment_author = $title;
    3311         $this->escape($comment_author);
    3312         $comment_author_url = $pagelinkedfrom;
    3313         $comment_content = $context;
    3314         $this->escape($comment_content);
    3315         $comment_type = 'pingback';
    3316 
    3317         $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_content', 'comment_type');
    3318 
    3319         $comment_ID = wp_new_comment($commentdata);
    3320         do_action('pingback_post', $comment_ID);
    3321 
    3322         return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto);
    3323     }
    3324 
    3325     /**
    3326      * Retrieve array of URLs that pingbacked the given URL.
    3327      *
    3328      * Specs on http://www.aquarionics.com/misc/archives/blogite/0198.html
    3329      *
    3330      * @since 1.5.0
    3331      *
    3332      * @param array $args Method parameters.
    3333      * @return array
    3334      */
    3335     function pingback_extensions_getPingbacks($args) {
    3336 
    3337         global $wpdb;
    3338 
    3339         do_action('xmlrpc_call', 'pingback.extensions.getPingbacks');
    3340 
    3341         $this->escape($args);
    3342 
    3343         $url = $args;
    3344 
    3345         $post_ID = url_to_postid($url);
    3346         if ( !$post_ID ) {
    3347             // We aren't sure that the resource is available and/or pingback enabled
    3348             return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn&#8217;t exist, or it is not a pingback-enabled resource.'));
    3349         }
    3350 
    3351         $actual_post = wp_get_single_post($post_ID, ARRAY_A);
    3352 
    3353         if ( !$actual_post ) {
    3354             // No such post = resource not found
    3355             return new IXR_Error(32, __('The specified target URL does not exist.'));
    3356         }
    3357 
    3358         $comments = $wpdb->get_results( $wpdb->prepare("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = %d", $post_ID) );
    3359 
    3360         if ( !$comments )
    3361             return array();
    3362 
    3363         $pingbacks = array();
    3364         foreach ( $comments as $comment ) {
    3365             if ( 'pingback' == $comment->comment_type )
    3366                 $pingbacks[] = $comment->comment_author_url;
    3367         }
    3368 
    3369         return $pingbacks;
    3370     }
    3371 }
    3372 
    3373 $wp_xmlrpc_server = new wp_xmlrpc_server();
     105// Fire off the request
    3374106$wp_xmlrpc_server->serve_request();
    3375107?>
Note: See TracChangeset for help on using the changeset viewer.