Make WordPress Core

Changeset 15648


Ignore:
Timestamp:
09/23/2010 09:38:28 PM (16 years ago)
Author:
westi
Message:

Complete the move to a seperate class file for #14820 props filosofo.
Add support for replacing the class used. Fixes #14814 props filosofo.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/class.wp-xmlrpc-server.php

    r15647 r15648  
    55 * @package WordPress
    66 */
    7 
    8 /**
    9  * Whether this is a XMLRPC Request
    10  *
    11  * @var bool
    12  */
    13 define('XMLRPC_REQUEST', true);
    14 
    15 // Some browser-embedded clients send cookies. We don't want them.
    16 $_COOKIE = array();
    17 
    18 // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
    19 // but we can do it ourself.
    20 if ( !isset( $HTTP_RAW_POST_DATA ) ) {
    21         $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
    22 }
    23 
    24 // fix for mozBlog and other cases where '<?xml' isn't on the very first line
    25 if ( isset($HTTP_RAW_POST_DATA) )
    26         $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA);
    27 
    28 /** Include the bootstrap for setting up WordPress environment */
    29 include('./wp-load.php');
    30 
    31 if ( isset( $_GET['rsd'] ) ) { // http://archipelago.phrasewise.com/rsd
    32 header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true);
    33 ?>
    34 <?php echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?>
    35 <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd">
    36   <service>
    37     <engineName>WordPress</engineName>
    38     <engineLink>http://wordpress.org/</engineLink>
    39     <homePageLink><?php bloginfo_rss('url') ?></homePageLink>
    40     <apis>
    41       <api name="WordPress" blogID="1" preferred="true" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
    42       <api name="Movable Type" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
    43       <api name="MetaWeblog" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
    44       <api name="Blogger" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" />
    45       <api name="Atom" blogID="" preferred="false" apiLink="<?php echo apply_filters('atom_service_url', site_url('wp-app.php/service', 'rpc') ) ?>" />
    46     </apis>
    47   </service>
    48 </rsd>
    49 <?php
    50 exit;
    51 }
    52 
    53 include_once(ABSPATH . 'wp-admin/includes/admin.php');
    54 include_once(ABSPATH . WPINC . '/class-IXR.php');
    55 
    56 // Turn off all warnings and errors.
    57 // error_reporting(0);
    58 
    59 /**
    60  * Posts submitted via the xmlrpc interface get that title
    61  * @name post_default_title
    62  * @var string
    63  */
    64 $post_default_title = "";
    65 
    66 /**
    67  * Whether to enable XMLRPC Logging.
    68  *
    69  * @name xmlrpc_logging
    70  * @var int|bool
    71  */
    72 $xmlrpc_logging = 0;
    73 
    74 /**
    75  * logIO() - Writes logging info to a file.
    76  *
    77  * @uses $xmlrpc_logging
    78  * @package WordPress
    79  * @subpackage Logging
    80  *
    81  * @param string $io Whether input or output
    82  * @param string $msg Information describing logging reason.
    83  * @return bool Always return true
    84  */
    85 function logIO($io,$msg) {
    86         global $xmlrpc_logging;
    87         if ($xmlrpc_logging) {
    88                 $fp = fopen("../xmlrpc.log","a+");
    89                 $date = gmdate("Y-m-d H:i:s ");
    90                 $iot = ($io == "I") ? " Input: " : " Output: ";
    91                 fwrite($fp, "\n\n".$date.$iot.$msg);
    92                 fclose($fp);
    93         }
    94         return true;
    95 }
    96 
    97 if ( isset($HTTP_RAW_POST_DATA) )
    98         logIO("I", $HTTP_RAW_POST_DATA);
    997
    1008/**
    … …  
    33363244        }
    33373245}
    3338 
    3339 $wp_xmlrpc_server = new wp_xmlrpc_server();
    3340 $wp_xmlrpc_server->serve_request();
    33413246?>
  • trunk/xmlrpc.php

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