X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/a66f9e26487c560245ef9cd17d7e87c0cbb650af..refs/tags/wordpress-2.9:/xmlrpc.php diff --git a/xmlrpc.php b/xmlrpc.php index 56d58432..8e683b75 100644 --- a/xmlrpc.php +++ b/xmlrpc.php @@ -1,5 +1,16 @@ + * @package WordPress + */ + +/** + * Whether this is a XMLRPC Request + * + * @var bool + */ define('XMLRPC_REQUEST', true); // Some browser-embedded clients send cookies. We don't want them. @@ -11,15 +22,15 @@ if ( !isset( $HTTP_RAW_POST_DATA ) ) { $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' ); } -# fix for mozBlog and other cases where ' '; ?> @@ -28,10 +39,11 @@ header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true); http://wordpress.org/ - - - - + + + + + @@ -45,10 +57,32 @@ include_once(ABSPATH . WPINC . '/class-IXR.php'); // Turn off all warnings and errors. // error_reporting(0); -$post_default_title = ""; // posts submitted via the xmlrpc interface get that title - +/** + * Posts submitted via the xmlrpc interface get that title + * @name post_default_title + * @var string + */ +$post_default_title = ""; + +/** + * Whether to enable XMLRPC Logging. + * + * @name xmlrpc_logging + * @var int|bool + */ $xmlrpc_logging = 0; +/** + * logIO() - Writes logging info to a file. + * + * @uses $xmlrpc_logging + * @package WordPress + * @subpackage Logging + * + * @param string $io Whether input or output + * @param string $msg Information describing logging reason. + * @return bool Always return true + */ function logIO($io,$msg) { global $xmlrpc_logging; if ($xmlrpc_logging) { @@ -59,22 +93,42 @@ function logIO($io,$msg) { fclose($fp); } return true; - } - -function starify($string) { - $i = strlen($string); - return str_repeat('*', $i); } if ( isset($HTTP_RAW_POST_DATA) ) - logIO("I", $HTTP_RAW_POST_DATA); - - + logIO("I", $HTTP_RAW_POST_DATA); + +/** + * WordPress XMLRPC server implementation. + * + * Implements compatability for Blogger API, MetaWeblog API, MovableType, and + * pingback. Additional WordPress API for managing comments, pages, posts, + * options, etc. + * + * Since WordPress 2.6.0, WordPress XMLRPC server can be disabled in the + * administration panels. + * + * @package WordPress + * @subpackage Publishing + * @since 1.5.0 + */ class wp_xmlrpc_server extends IXR_Server { + /** + * Register all of the XMLRPC methods that XMLRPC server understands. + * + * PHP4 constructor and sets up server and method property. Passes XMLRPC + * methods through the 'xmlrpc_methods' filter to allow plugins to extend + * or replace XMLRPC methods. + * + * @since 1.5.0 + * + * @return wp_xmlrpc_server + */ function wp_xmlrpc_server() { $this->methods = array( // WordPress API + 'wp.getUsersBlogs' => 'this:wp_getUsersBlogs', 'wp.getPage' => 'this:wp_getPage', 'wp.getPages' => 'this:wp_getPages', 'wp.newPage' => 'this:wp_newPage', @@ -83,9 +137,23 @@ class wp_xmlrpc_server extends IXR_Server { 'wp.getPageList' => 'this:wp_getPageList', 'wp.getAuthors' => 'this:wp_getAuthors', 'wp.getCategories' => 'this:mw_getCategories', // Alias + 'wp.getTags' => 'this:wp_getTags', 'wp.newCategory' => 'this:wp_newCategory', + 'wp.deleteCategory' => 'this:wp_deleteCategory', 'wp.suggestCategories' => 'this:wp_suggestCategories', 'wp.uploadFile' => 'this:mw_newMediaObject', // Alias + 'wp.getCommentCount' => 'this:wp_getCommentCount', + 'wp.getPostStatusList' => 'this:wp_getPostStatusList', + 'wp.getPageStatusList' => 'this:wp_getPageStatusList', + 'wp.getPageTemplates' => 'this:wp_getPageTemplates', + 'wp.getOptions' => 'this:wp_getOptions', + 'wp.setOptions' => 'this:wp_setOptions', + 'wp.getComment' => 'this:wp_getComment', + 'wp.getComments' => 'this:wp_getComments', + 'wp.deleteComment' => 'this:wp_deleteComment', + 'wp.editComment' => 'this:wp_editComment', + 'wp.newComment' => 'this:wp_newComment', + 'wp.getCommentStatusList' => 'this:wp_getCommentStatusList', // Blogger API 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs', @@ -130,21 +198,58 @@ class wp_xmlrpc_server extends IXR_Server { 'demo.sayHello' => 'this:sayHello', 'demo.addTwoNumbers' => 'this:addTwoNumbers' ); + + $this->initialise_blog_option_info( ); $this->methods = apply_filters('xmlrpc_methods', $this->methods); + } + + function serve_request() { $this->IXR_Server($this->methods); } + /** + * Test XMLRPC API by saying, "Hello!" to client. + * + * @since 1.5.0 + * + * @param array $args Method Parameters. + * @return string + */ function sayHello($args) { return 'Hello!'; } + /** + * Test XMLRPC API by adding two numbers for client. + * + * @since 1.5.0 + * + * @param array $args Method Parameters. + * @return int + */ function addTwoNumbers($args) { $number1 = $args[0]; $number2 = $args[1]; return $number1 + $number2; } + /** + * Check user's credentials. + * + * @since 1.5.0 + * + * @param string $user_login User's username. + * @param string $user_pass User's password. + * @return bool Whether authentication passed. + * @deprecated use wp_xmlrpc_server::login + * @see wp_xmlrpc_server::login + */ function login_pass_ok($user_login, $user_pass) { + if ( !get_option( 'enable_xmlrpc' ) ) { + $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this blog. An admin user can enable them at %s'), admin_url('options-writing.php') ) ); + return false; + } + if (!user_pass_ok($user_login, $user_pass)) { $this->error = new IXR_Error(403, __('Bad login/pass combination.')); return false; @@ -152,6 +257,40 @@ class wp_xmlrpc_server extends IXR_Server { return true; } + /** + * Log user in. + * + * @since 2.8 + * + * @param string $username User's username. + * @param string $password User's password. + * @return mixed WP_User object if authentication passed, false otherwise + */ + function login($username, $password) { + if ( !get_option( 'enable_xmlrpc' ) ) { + $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this blog. An admin user can enable them at %s'), admin_url('options-writing.php') ) ); + return false; + } + + $user = wp_authenticate($username, $password); + + if (is_wp_error($user)) { + $this->error = new IXR_Error(403, __('Bad login/pass combination.')); + return false; + } + + set_current_user( $user->ID ); + return $user; + } + + /** + * Sanitize string or array of strings for database. + * + * @since 1.5.2 + * + * @param string|array $array Sanitize single string or array of strings. + * @return string|array Type matches $array and sanitized for the database. + */ function escape(&$array) { global $wpdb; @@ -172,8 +311,187 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_getPage + * Retrieve custom fields for post. + * + * @since 2.5.0 + * + * @param int $post_id Post ID. + * @return array Custom fields, if exist. + */ + function get_custom_fields($post_id) { + $post_id = (int) $post_id; + + $custom_fields = array(); + + foreach ( (array) has_meta($post_id) as $meta ) { + // Don't expose protected fields. + if ( strpos($meta['meta_key'], '_wp_') === 0 ) { + continue; + } + + $custom_fields[] = array( + "id" => $meta['meta_id'], + "key" => $meta['meta_key'], + "value" => $meta['meta_value'] + ); + } + + return $custom_fields; + } + + /** + * Set custom fields for post. + * + * @since 2.5.0 + * + * @param int $post_id Post ID. + * @param array $fields Custom fields. + */ + function set_custom_fields($post_id, $fields) { + $post_id = (int) $post_id; + + foreach ( (array) $fields as $meta ) { + if ( isset($meta['id']) ) { + $meta['id'] = (int) $meta['id']; + + if ( isset($meta['key']) ) { + update_meta($meta['id'], $meta['key'], $meta['value']); + } + else { + delete_meta($meta['id']); + } + } + else { + $_POST['metakeyinput'] = $meta['key']; + $_POST['metavalue'] = $meta['value']; + add_meta($post_id); + } + } + } + + /** + * Setup blog options property. + * + * Passes property through 'xmlrpc_blog_options' filter. + * + * @since 2.6.0 + */ + function initialise_blog_option_info( ) { + global $wp_version; + + $this->blog_options = array( + // Read only options + 'software_name' => array( + 'desc' => __( 'Software Name' ), + 'readonly' => true, + 'value' => 'WordPress' + ), + 'software_version' => array( + 'desc' => __( 'Software Version' ), + 'readonly' => true, + 'value' => $wp_version + ), + 'blog_url' => array( + 'desc' => __( 'Blog URL' ), + 'readonly' => true, + 'option' => 'siteurl' + ), + + // Updatable options + 'time_zone' => array( + 'desc' => __( 'Time Zone' ), + 'readonly' => false, + 'option' => 'gmt_offset' + ), + 'blog_title' => array( + 'desc' => __( 'Blog Title' ), + 'readonly' => false, + 'option' => 'blogname' + ), + 'blog_tagline' => array( + 'desc' => __( 'Blog Tagline' ), + 'readonly' => false, + 'option' => 'blogdescription' + ), + 'date_format' => array( + 'desc' => __( 'Date Format' ), + 'readonly' => false, + 'option' => 'date_format' + ), + 'time_format' => array( + 'desc' => __( 'Time Format' ), + 'readonly' => false, + 'option' => 'time_format' + ), + 'users_can_register' => array( + 'desc' => __( 'Allow new users to sign up' ), + 'readonly' => false, + 'option' => 'users_can_register' + ) + ); + + $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options ); + } + + /** + * Retrieve the blogs of the user. + * + * @since 2.6.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getUsersBlogs( $args ) { + // If this isn't on WPMU then just use blogger_getUsersBlogs + if( !function_exists( 'is_site_admin' ) ) { + array_unshift( $args, 1 ); + return $this->blogger_getUsersBlogs( $args ); + } + + $this->escape( $args ); + + $username = $args[0]; + $password = $args[1]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + do_action( 'xmlrpc_call', 'wp.getUsersBlogs' ); + + $blogs = (array) get_blogs_of_user( $user->ID ); + $struct = array( ); + + foreach( $blogs as $blog ) { + // Don't include blogs that aren't hosted at this site + if( $blog->site_id != $current_site->id ) + continue; + + $blog_id = $blog->userblog_id; + switch_to_blog($blog_id); + $is_admin = current_user_can('level_8'); + + $struct[] = array( + 'isAdmin' => $is_admin, + 'url' => get_option( 'home' ) . '/', + 'blogid' => $blog_id, + 'blogName' => get_option( 'blogname' ), + 'xmlrpc' => site_url( 'xmlrpc.php' ) + ); + + restore_current_blog( ); + } + + return $struct; + } + + /** + * Retrieve page. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return array */ function wp_getPage($args) { $this->escape($args); @@ -183,13 +501,12 @@ class wp_xmlrpc_server extends IXR_Server { $username = $args[2]; $password = $args[3]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } - set_current_user( 0, $username ); if( !current_user_can( 'edit_page', $page_id ) ) - return new IXR_Error( 401, __( 'Sorry, you can not edit this page.' ) ); + return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) ); do_action('xmlrpc_call', 'wp.getPage'); @@ -210,12 +527,17 @@ class wp_xmlrpc_server extends IXR_Server { } // Determine comment and ping settings. - $allow_comments = ("open" == $page->comment_status) ? 1 : 0; - $allow_pings = ("open" == $page->ping_status) ? 1 : 0; + $allow_comments = comments_open($page->ID) ? 1 : 0; + $allow_pings = pings_open($page->ID) ? 1 : 0; // Format page date. - $page_date = mysql2date("Ymd\TH:i:s", $page->post_date); - $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt); + $page_date = mysql2date("Ymd\TH:i:s", $page->post_date, false); + $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt, false); + + // For drafts use the GMT version of the date + if ( $page->post_status == 'draft' ) { + $page_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page->post_date ), 'Ymd\TH:i:s' ); + } // Pull the categories info together. $categories = array(); @@ -226,6 +548,10 @@ class wp_xmlrpc_server extends IXR_Server { // Get the author info. $author = get_userdata($page->post_author); + $page_template = get_post_meta( $page->ID, '_wp_page_template', true ); + if( empty( $page_template ) ) + $page_template = 'default'; + $page_struct = array( "dateCreated" => new IXR_Date($page_date), "userid" => $page->post_author, @@ -248,7 +574,9 @@ class wp_xmlrpc_server extends IXR_Server { "wp_page_order" => $page->menu_order, "wp_author_id" => $author->ID, "wp_author_display_name" => $author->display_name, - "date_created_gmt" => new IXR_Date($page_date_gmt) + "date_created_gmt" => new IXR_Date($page_date_gmt), + "custom_fields" => $this->get_custom_fields($page_id), + "wp_page_template" => $page_template ); return($page_struct); @@ -260,8 +588,12 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_getPages + * Retrieve Pages. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return array */ function wp_getPages($args) { $this->escape($args); @@ -269,19 +601,18 @@ class wp_xmlrpc_server extends IXR_Server { $blog_id = (int) $args[0]; $username = $args[1]; $password = $args[2]; + $num_pages = isset($args[3]) ? (int) $args[3] : 10; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } - set_current_user( 0, $username ); if( !current_user_can( 'edit_pages' ) ) - return new IXR_Error( 401, __( 'Sorry, you can not edit pages.' ) ); + return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); do_action('xmlrpc_call', 'wp.getPages'); - // Lookup info on pages. - $pages = get_pages(); + $pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) ); $num_pages = count($pages); // If we have pages, put together their info. @@ -304,8 +635,12 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_newPage + * Create new page. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return unknown */ function wp_newPage($args) { // Items not escaped here will be escaped in newPost. @@ -314,15 +649,15 @@ class wp_xmlrpc_server extends IXR_Server { $page = $args[3]; $publish = $args[4]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } - // Set the user context and check if they are allowed - // to add new pages. - $user = set_current_user(0, $username); + do_action('xmlrpc_call', 'wp.newPage'); + + // Make sure the user is allowed to add new pages. if(!current_user_can("publish_pages")) { - return(new IXR_Error(401, __("Sorry, you can not add new pages."))); + return(new IXR_Error(401, __("Sorry, you cannot add new pages."))); } // Mark this as content for a page. @@ -333,8 +668,12 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_deletePage + * Delete page. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return bool True, if success. */ function wp_deletePage($args) { $this->escape($args); @@ -344,10 +683,12 @@ class wp_xmlrpc_server extends IXR_Server { $password = $args[2]; $page_id = (int) $args[3]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } + do_action('xmlrpc_call', 'wp.deletePage'); + // Get the current page based on the page_id and // make sure it is a page and not a post. $actual_page = wp_get_single_post($page_id, ARRAY_A); @@ -358,8 +699,7 @@ class wp_xmlrpc_server extends IXR_Server { return(new IXR_Error(404, __("Sorry, no such page."))); } - // Set the user context and make sure they can delete pages. - set_current_user(0, $username); + // Make sure the user can delete pages. if(!current_user_can("delete_page", $page_id)) { return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page."))); } @@ -374,8 +714,12 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_editPage + * Edit page. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return unknown */ function wp_editPage($args) { // Items not escaped here will be escaped in editPost. @@ -386,10 +730,12 @@ class wp_xmlrpc_server extends IXR_Server { $content = $args[4]; $publish = $args[5]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } + do_action('xmlrpc_call', 'wp.editPage'); + // Get the page data and make sure it is a page. $actual_page = wp_get_single_post($page_id, ARRAY_A); if( @@ -399,8 +745,7 @@ class wp_xmlrpc_server extends IXR_Server { return(new IXR_Error(404, __("Sorry, no such page."))); } - // Set the user context and make sure they are allowed to edit pages. - set_current_user(0, $username); + // Make sure the user is allowed to edit pages. if(!current_user_can("edit_page", $page_id)) { return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page."))); } @@ -422,8 +767,12 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_getPageList + * Retrieve page list. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return unknown */ function wp_getPageList($args) { global $wpdb; @@ -434,13 +783,12 @@ class wp_xmlrpc_server extends IXR_Server { $username = $args[1]; $password = $args[2]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } - set_current_user( 0, $username ); if( !current_user_can( 'edit_pages' ) ) - return new IXR_Error( 401, __( 'Sorry, you can not edit pages.' ) ); + return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); do_action('xmlrpc_call', 'wp.getPageList'); @@ -450,7 +798,8 @@ class wp_xmlrpc_server extends IXR_Server { post_title page_title, post_parent page_parent_id, post_date_gmt, - post_date + post_date, + post_status FROM {$wpdb->posts} WHERE post_type = 'page' ORDER BY ID @@ -459,22 +808,33 @@ class wp_xmlrpc_server extends IXR_Server { // The date needs to be formated properly. $num_pages = count($page_list); for($i = 0; $i < $num_pages; $i++) { - $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date); - $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt); + $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date, false); + $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt, false); $page_list[$i]->dateCreated = new IXR_Date($post_date); $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt); + // For drafts use the GMT version of the date + if ( $page_list[$i]->post_status == 'draft' ) { + $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' ); + $page_list[$i]->date_created_gmt = new IXR_Date( $page_list[$i]->date_created_gmt ); + } + unset($page_list[$i]->post_date_gmt); unset($page_list[$i]->post_date); + unset($page_list[$i]->post_status); } return($page_list); } /** - * WordPress XML-RPC API - * wp_getAuthors + * Retrieve authors list. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return array */ function wp_getAuthors($args) { @@ -484,14 +844,13 @@ class wp_xmlrpc_server extends IXR_Server { $username = $args[1]; $password = $args[2]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } - set_current_user(0, $username); if(!current_user_can("edit_posts")) { - return(new IXR_Error(401, __("Sorry, you can not edit posts on this blog."))); - } + return(new IXR_Error(401, __("Sorry, you cannot edit posts on this blog."))); + } do_action('xmlrpc_call', 'wp.getAuthors'); @@ -508,8 +867,55 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_newCategory + * Get list of all tags + * + * @since 2.7 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getTags( $args ) { + $this->escape( $args ); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if( !current_user_can( 'edit_posts' ) ) { + return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this blog in order to view tags.' ) ); + } + + do_action( 'xmlrpc_call', 'wp.getKeywords' ); + + $tags = array( ); + + if( $all_tags = get_tags( ) ) { + foreach( (array) $all_tags as $tag ) { + $struct['tag_id'] = $tag->term_id; + $struct['name'] = $tag->name; + $struct['count'] = $tag->count; + $struct['slug'] = $tag->slug; + $struct['html_url'] = esc_html( get_tag_link( $tag->term_id ) ); + $struct['rss_url'] = esc_html( get_tag_feed_link( $tag->term_id ) ); + + $tags[] = $struct; + } + } + + return $tags; + } + + /** + * Create new category. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return int Category ID. */ function wp_newCategory($args) { $this->escape($args); @@ -519,13 +925,13 @@ class wp_xmlrpc_server extends IXR_Server { $password = $args[2]; $category = $args[3]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; } - // Set the user context and make sure they are - // allowed to add a category. - set_current_user(0, $username); + do_action('xmlrpc_call', 'wp.newCategory'); + + // Make sure the user is allowed to add a category. if(!current_user_can("manage_categories")) { return(new IXR_Error(401, __("Sorry, you do not have the right to add a category."))); } @@ -562,12 +968,43 @@ class wp_xmlrpc_server extends IXR_Server { } /** - * WordPress XML-RPC API - * wp_suggestCategories + * Remove category. + * + * @since 2.5.0 + * + * @param array $args Method parameters. + * @return mixed See {@link wp_delete_category()} for return info. */ - function wp_suggestCategories($args) { - global $wpdb; + function wp_deleteCategory($args) { + $this->escape($args); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $category_id = (int) $args[3]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + do_action('xmlrpc_call', 'wp.deleteCategory'); + + if( !current_user_can("manage_categories") ) { + return new IXR_Error( 401, __( "Sorry, you do not have the right to delete a category." ) ); + } + + return wp_delete_category( $category_id ); + } + + /** + * Retrieve category list. + * + * @since 2.2.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_suggestCategories($args) { $this->escape($args); $blog_id = (int) $args[0]; @@ -576,102 +1013,672 @@ class wp_xmlrpc_server extends IXR_Server { $category = $args[3]; $max_results = (int) $args[4]; - if(!$this->login_pass_ok($username, $password)) { - return($this->error); + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if( !current_user_can( 'edit_posts' ) ) + return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this blog in order to view categories.' ) ); + + do_action('xmlrpc_call', 'wp.suggestCategories'); + + $category_suggestions = array(); + $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category); + foreach ( (array) get_categories($args) as $cat ) { + $category_suggestions[] = array( + "category_id" => $cat->cat_ID, + "category_name" => $cat->cat_name + ); + } + + return($category_suggestions); + } + + /** + * Retrieve comment. + * + * @since 2.7.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getComment($args) { + $this->escape($args); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $comment_id = (int) $args[3]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if ( !current_user_can( 'moderate_comments' ) ) + return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this blog.' ) ); + + do_action('xmlrpc_call', 'wp.getComment'); + + if ( ! $comment = get_comment($comment_id) ) + return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); + + // Format page date. + $comment_date = mysql2date("Ymd\TH:i:s", $comment->comment_date, false); + $comment_date_gmt = mysql2date("Ymd\TH:i:s", $comment->comment_date_gmt, false); + + if ( '0' == $comment->comment_approved ) + $comment_status = 'hold'; + else if ( 'spam' == $comment->comment_approved ) + $comment_status = 'spam'; + else if ( '1' == $comment->comment_approved ) + $comment_status = 'approve'; + else + $comment_status = $comment->comment_approved; + + $link = get_comment_link($comment); + + $comment_struct = array( + "date_created_gmt" => new IXR_Date($comment_date_gmt), + "user_id" => $comment->user_id, + "comment_id" => $comment->comment_ID, + "parent" => $comment->comment_parent, + "status" => $comment_status, + "content" => $comment->comment_content, + "link" => $link, + "post_id" => $comment->comment_post_ID, + "post_title" => get_the_title($comment->comment_post_ID), + "author" => $comment->comment_author, + "author_url" => $comment->comment_author_url, + "author_email" => $comment->comment_author_email, + "author_ip" => $comment->comment_author_IP, + "type" => $comment->comment_type, + ); + + return $comment_struct; + } + + /** + * Retrieve comments. + * + * @since 2.7.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getComments($args) { + $this->escape($args); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $struct = $args[3]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if ( !current_user_can( 'moderate_comments' ) ) + return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) ); + + do_action('xmlrpc_call', 'wp.getComments'); + + if ( isset($struct['status']) ) + $status = $struct['status']; + else + $status = ''; + + $post_id = ''; + if ( isset($struct['post_id']) ) + $post_id = absint($struct['post_id']); + + $offset = 0; + if ( isset($struct['offset']) ) + $offset = absint($struct['offset']); + + $number = 10; + if ( isset($struct['number']) ) + $number = absint($struct['number']); + + $comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) ); + $num_comments = count($comments); + + if ( ! $num_comments ) + return array(); + + $comments_struct = array(); + + for ( $i = 0; $i < $num_comments; $i++ ) { + $comment = wp_xmlrpc_server::wp_getComment(array( + $blog_id, $username, $password, $comments[$i]->comment_ID, + )); + $comments_struct[] = $comment; + } + + return $comments_struct; + } + + /** + * Remove comment. + * + * @since 2.7.0 + * + * @param array $args Method parameters. + * @return mixed {@link wp_delete_comment()} + */ + function wp_deleteComment($args) { + $this->escape($args); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $comment_ID = (int) $args[3]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if ( !current_user_can( 'moderate_comments' ) ) + return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this blog.' ) ); + + do_action('xmlrpc_call', 'wp.deleteComment'); + + if ( ! get_comment($comment_ID) ) + return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); + + return wp_delete_comment($comment_ID); + } + + /** + * Edit comment. + * + * @since 2.7.0 + * + * @param array $args Method parameters. + * @return bool True, on success. + */ + function wp_editComment($args) { + $this->escape($args); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $comment_ID = (int) $args[3]; + $content_struct = $args[4]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if ( !current_user_can( 'moderate_comments' ) ) + return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this blog.' ) ); + + do_action('xmlrpc_call', 'wp.editComment'); + + if ( ! get_comment($comment_ID) ) + return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); + + if ( isset($content_struct['status']) ) { + $statuses = get_comment_statuses(); + $statuses = array_keys($statuses); + + if ( ! in_array($content_struct['status'], $statuses) ) + return new IXR_Error( 401, __( 'Invalid comment status.' ) ); + $comment_approved = $content_struct['status']; + } + + // Do some timestamp voodoo + if ( !empty( $content_struct['date_created_gmt'] ) ) { + $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 + $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); + $comment_date_gmt = iso8601_to_datetime($dateCreated, GMT); + } + + if ( isset($content_struct['content']) ) + $comment_content = $content_struct['content']; + + if ( isset($content_struct['author']) ) + $comment_author = $content_struct['author']; + + if ( isset($content_struct['author_url']) ) + $comment_author_url = $content_struct['author_url']; + + if ( isset($content_struct['author_email']) ) + $comment_author_email = $content_struct['author_email']; + + // We've got all the data -- post it: + $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url'); + + $result = wp_update_comment($comment); + if ( is_wp_error( $result ) ) + return new IXR_Error(500, $result->get_error_message()); + + if ( !$result ) + return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.')); + + return true; + } + + /** + * Create new comment. + * + * @since 2.7.0 + * + * @param array $args Method parameters. + * @return mixed {@link wp_new_comment()} + */ + function wp_newComment($args) { + global $wpdb; + + $this->escape($args); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $post = $args[3]; + $content_struct = $args[4]; + + $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false); + + $user = $this->login($username, $password); + + if ( !$user ) { + $logged_in = false; + if ( $allow_anon && get_option('comment_registration') ) + return new IXR_Error( 403, __( 'You must be registered to comment' ) ); + else if ( !$allow_anon ) + return $this->error; + } else { + $logged_in = true; + } + + if ( is_numeric($post) ) + $post_id = absint($post); + else + $post_id = url_to_postid($post); + + if ( ! $post_id ) + return new IXR_Error( 404, __( 'Invalid post ID.' ) ); + + if ( ! get_post($post_id) ) + return new IXR_Error( 404, __( 'Invalid post ID.' ) ); + + $comment['comment_post_ID'] = $post_id; + + if ( $logged_in ) { + $comment['comment_author'] = $wpdb->escape( $user->display_name ); + $comment['comment_author_email'] = $wpdb->escape( $user->user_email ); + $comment['comment_author_url'] = $wpdb->escape( $user->user_url ); + $comment['user_ID'] = $user->ID; + } else { + $comment['comment_author'] = ''; + if ( isset($content_struct['author']) ) + $comment['comment_author'] = $content_struct['author']; + + $comment['comment_author_email'] = ''; + if ( isset($content_struct['author_email']) ) + $comment['comment_author_email'] = $content_struct['author_email']; + + $comment['comment_author_url'] = ''; + if ( isset($content_struct['author_url']) ) + $comment['comment_author_url'] = $content_struct['author_url']; + + $comment['user_ID'] = 0; + + if ( get_option('require_name_email') ) { + if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] ) + return new IXR_Error( 403, __( 'Comment author name and email are required' ) ); + elseif ( !is_email($comment['comment_author_email']) ) + return new IXR_Error( 403, __( 'A valid email address is required' ) ); + } + } + + $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0; + + $comment['comment_content'] = $content_struct['content']; + + do_action('xmlrpc_call', 'wp.newComment'); + + return wp_new_comment($comment); + } + + /** + * Retrieve all of the comment status. + * + * @since 2.7.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getCommentStatusList($args) { + $this->escape( $args ); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if ( !current_user_can( 'moderate_comments' ) ) + return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); + + do_action('xmlrpc_call', 'wp.getCommentStatusList'); + + return get_comment_statuses( ); + } + + /** + * Retrieve comment count. + * + * @since 2.5.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getCommentCount( $args ) { + $this->escape($args); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $post_id = (int) $args[3]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if( !current_user_can( 'edit_posts' ) ) { + return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) ); + } + + do_action('xmlrpc_call', 'wp.getCommentCount'); + + $count = wp_count_comments( $post_id ); + return array( + "approved" => $count->approved, + "awaiting_moderation" => $count->moderated, + "spam" => $count->spam, + "total_comments" => $count->total_comments + ); + } + + /** + * Retrieve post statuses. + * + * @since 2.5.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getPostStatusList( $args ) { + $this->escape( $args ); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if( !current_user_can( 'edit_posts' ) ) { + return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); + } + + do_action('xmlrpc_call', 'wp.getPostStatusList'); + + return get_post_statuses( ); + } + + /** + * Retrieve page statuses. + * + * @since 2.5.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getPageStatusList( $args ) { + $this->escape( $args ); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if( !current_user_can( 'edit_posts' ) ) { + return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); + } + + do_action('xmlrpc_call', 'wp.getPageStatusList'); + + return get_page_statuses( ); + } + + /** + * Retrieve page templates. + * + * @since 2.6.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getPageTemplates( $args ) { + $this->escape( $args ); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + if( !current_user_can( 'edit_pages' ) ) { + return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); + } + + $templates = get_page_templates( ); + $templates['Default'] = 'default'; + + return $templates; + } + + /** + * Retrieve blog options. + * + * @since 2.6.0 + * + * @param array $args Method parameters. + * @return array + */ + function wp_getOptions( $args ) { + $this->escape( $args ); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $options = (array) $args[3]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + // If no specific options where asked for, return all of them + if (count( $options ) == 0 ) { + $options = array_keys($this->blog_options); + } + + return $this->_getOptions($options); + } + + /** + * Retrieve blog options value from list. + * + * @since 2.6.0 + * + * @param array $options Options to retrieve. + * @return array + */ + function _getOptions($options) + { + $data = array( ); + foreach( $options as $option ) { + if( array_key_exists( $option, $this->blog_options ) ) + { + $data[$option] = $this->blog_options[$option]; + //Is the value static or dynamic? + if( isset( $data[$option]['option'] ) ) { + $data[$option]['value'] = get_option( $data[$option]['option'] ); + unset($data[$option]['option']); + } + } + } + + return $data; + } + + /** + * Update blog options. + * + * @since 2.6.0 + * + * @param array $args Method parameters. + * @return unknown + */ + function wp_setOptions( $args ) { + $this->escape( $args ); + + $blog_id = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $options = (array) $args[3]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; } - set_current_user(0, $username); - if( !current_user_can( 'edit_posts' ) ) - return new IXR_Error( 401, __( 'Sorry, you must be able to publish to this blog in order to view categories.' ) ); + if( !current_user_can( 'manage_options' ) ) + return new IXR_Error( 403, __( 'You are not allowed to update options.' ) ); - do_action('xmlrpc_call', 'wp.suggestCategories'); + foreach( $options as $o_name => $o_value ) { + $option_names[] = $o_name; + if( !array_key_exists( $o_name, $this->blog_options ) ) + continue; - $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category); - $category_suggestions = get_categories($args); + if( $this->blog_options[$o_name]['readonly'] == true ) + continue; - return($category_suggestions); - } + update_option( $this->blog_options[$o_name]['option'], $o_value ); + } + //Now return the updated values + return $this->_getOptions($option_names); + } - /* Blogger API functions + /* Blogger API functions. * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/ */ - - /* blogger.getUsersBlogs will make more sense once we support multiple blogs */ + /** + * Retrieve blogs that user owns. + * + * Will make more sense once we support multiple blogs. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function blogger_getUsersBlogs($args) { $this->escape($args); - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user(0, $user_login); - $is_admin = current_user_can('level_8'); + do_action('xmlrpc_call', 'blogger.getUsersBlogs'); + + $is_admin = current_user_can('manage_options'); $struct = array( 'isAdmin' => $is_admin, 'url' => get_option('home') . '/', 'blogid' => '1', - 'blogName' => get_option('blogname') + 'blogName' => get_option('blogname'), + 'xmlrpc' => site_url( 'xmlrpc.php' ) ); return array($struct); } - - /* blogger.getUsersInfo gives your client some info about you, so you don't have to */ + /** + * Retrieve user's data. + * + * Gives your client some info about you, so you don't have to. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function blogger_getUserInfo($args) { $this->escape($args); - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user( 0, $user_login ); - if( !current_user_can( 'edit_posts' ) ) + if( !current_user_can( 'edit_posts' ) ) return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this blog.' ) ); do_action('xmlrpc_call', 'blogger.getUserInfo'); - $user_data = get_userdatabylogin($user_login); - $struct = array( - 'nickname' => $user_data->nickname, - 'userid' => $user_data->ID, - 'url' => $user_data->user_url, - 'lastname' => $user_data->last_name, - 'firstname' => $user_data->first_name + 'nickname' => $user->nickname, + 'userid' => $user->ID, + 'url' => $user->user_url, + 'lastname' => $user->last_name, + 'firstname' => $user->first_name ); return $struct; } - - /* blogger.getPost ...gets a post */ + /** + * Retrieve post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function blogger_getPost($args) { $this->escape($args); $post_ID = (int) $args[1]; - $user_login = $args[2]; - $user_pass = $args[3]; + $username = $args[2]; + $password = $args[3]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user( 0, $user_login ); - if( !current_user_can( 'edit_post', $post_ID ) ) - return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) ); + if( !current_user_can( 'edit_post', $post_ID ) ) + return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); do_action('xmlrpc_call', 'blogger.getPost'); @@ -685,7 +1692,7 @@ class wp_xmlrpc_server extends IXR_Server { $struct = array( 'userid' => $post_data['post_author'], - 'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'])), + 'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'], false)), 'content' => $content, 'postid' => $post_data['ID'] ); @@ -693,26 +1700,30 @@ class wp_xmlrpc_server extends IXR_Server { return $struct; } - - /* blogger.getRecentPosts ...gets recent posts */ + /** + * Retrieve list of recent posts. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function blogger_getRecentPosts($args) { - global $wpdb; - $this->escape($args); $blog_ID = (int) $args[1]; /* though we don't use it yet */ - $user_login = $args[2]; - $user_pass = $args[3]; + $username = $args[2]; + $password = $args[3]; $num_posts = $args[4]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - $posts_list = wp_get_recent_posts($num_posts); + do_action('xmlrpc_call', 'blogger.getRecentPosts'); - set_current_user( 0, $user_login ); + $posts_list = wp_get_recent_posts($num_posts); if (!$posts_list) { $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.')); @@ -723,7 +1734,7 @@ class wp_xmlrpc_server extends IXR_Server { if( !current_user_can( 'edit_post', $entry['ID'] ) ) continue; - $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']); + $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false); $categories = implode(',', wp_get_post_categories($entry['ID'])); $content = ''.stripslashes($entry['post_title']).''; @@ -747,246 +1758,280 @@ class wp_xmlrpc_server extends IXR_Server { return $recent_posts; } - - /* blogger.getTemplate returns your blog_filename */ + /** + * Retrieve blog_filename content. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return string + */ function blogger_getTemplate($args) { $this->escape($args); - $blog_ID = (int) $args[1]; - $user_login = $args[2]; - $user_pass = $args[3]; - $template = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */ + $blog_ID = (int) $args[1]; + $username = $args[2]; + $password = $args[3]; + $template = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */ - if (!$this->login_pass_ok($user_login, $user_pass)) { - return $this->error; - } + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } - set_current_user(0, $user_login); - if ( !current_user_can('edit_themes') ) { - return new IXR_Error(401, __('Sorry, this user can not edit the template.')); - } + do_action('xmlrpc_call', 'blogger.getTemplate'); - /* warning: here we make the assumption that the blog's URL is on the same server */ - $filename = get_option('home') . '/'; - $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); + if ( !current_user_can('edit_themes') ) { + return new IXR_Error(401, __('Sorry, this user can not edit the template.')); + } - $f = fopen($filename, 'r'); - $content = fread($f, filesize($filename)); - fclose($f); + /* warning: here we make the assumption that the blog's URL is on the same server */ + $filename = get_option('home') . '/'; + $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); - /* so it is actually editable with a windows/mac client */ - // 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); + $f = fopen($filename, 'r'); + $content = fread($f, filesize($filename)); + fclose($f); - return $content; - } + /* so it is actually editable with a windows/mac client */ + // 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); + return $content; + } - /* blogger.setTemplate updates the content of blog_filename */ + /** + * Updates the content of blog_filename. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return bool True when done. + */ function blogger_setTemplate($args) { $this->escape($args); - $blog_ID = (int) $args[1]; - $user_login = $args[2]; - $user_pass = $args[3]; - $content = $args[4]; - $template = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */ - - if (!$this->login_pass_ok($user_login, $user_pass)) { - return $this->error; - } - - set_current_user(0, $user_login); - if ( !current_user_can('edit_themes') ) { - return new IXR_Error(401, __('Sorry, this user can not edit the template.')); - } - - /* warning: here we make the assumption that the blog's URL is on the same server */ - $filename = get_option('home') . '/'; - $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); - - if ($f = fopen($filename, 'w+')) { - fwrite($f, $content); - fclose($f); - } else { - return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.')); - } - - return true; - } + $blog_ID = (int) $args[1]; + $username = $args[2]; + $password = $args[3]; + $content = $args[4]; + $template = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */ + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } - /* blogger.newPost ...creates a new post */ - function blogger_newPost($args) { + do_action('xmlrpc_call', 'blogger.setTemplate'); + + if ( !current_user_can('edit_themes') ) { + return new IXR_Error(401, __('Sorry, this user cannot edit the template.')); + } + + /* warning: here we make the assumption that the blog's URL is on the same server */ + $filename = get_option('home') . '/'; + $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); + + if ($f = fopen($filename, 'w+')) { + fwrite($f, $content); + fclose($f); + } else { + return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.')); + } + + return true; + } - global $wpdb; + /** + * Create new post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return int + */ + function blogger_newPost($args) { $this->escape($args); - $blog_ID = (int) $args[1]; /* though we don't use it yet */ - $user_login = $args[2]; - $user_pass = $args[3]; - $content = $args[4]; - $publish = $args[5]; + $blog_ID = (int) $args[1]; /* though we don't use it yet */ + $username = $args[2]; + $password = $args[3]; + $content = $args[4]; + $publish = $args[5]; - if (!$this->login_pass_ok($user_login, $user_pass)) { - return $this->error; - } + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } - $cap = ($publish) ? 'publish_posts' : 'edit_posts'; - $user = set_current_user(0, $user_login); - if ( !current_user_can($cap) ) - return new IXR_Error(401, __('Sorry, you are not allowed to post on this blog.')); + do_action('xmlrpc_call', 'blogger.newPost'); - $post_status = ($publish) ? 'publish' : 'draft'; + $cap = ($publish) ? 'publish_posts' : 'edit_posts'; + if ( !current_user_can($cap) ) + return new IXR_Error(401, __('Sorry, you are not allowed to post on this blog.')); - $post_author = $user->ID; + $post_status = ($publish) ? 'publish' : 'draft'; - $post_title = xmlrpc_getposttitle($content); - $post_category = xmlrpc_getpostcategory($content); - $post_content = xmlrpc_removepostdata($content); + $post_author = $user->ID; - $post_date = current_time('mysql'); - $post_date_gmt = current_time('mysql', 1); + $post_title = xmlrpc_getposttitle($content); + $post_category = xmlrpc_getpostcategory($content); + $post_content = xmlrpc_removepostdata($content); - $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status'); + $post_date = current_time('mysql'); + $post_date_gmt = current_time('mysql', 1); - $post_ID = wp_insert_post($post_data); - if ( is_wp_error( $post_ID ) ) - return new IXR_Error(500, $post_ID->get_error_message()); + $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status'); - if (!$post_ID) { - return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); - } - $this->attach_uploads( $post_ID, $post_content ); + $post_ID = wp_insert_post($post_data); + if ( is_wp_error( $post_ID ) ) + return new IXR_Error(500, $post_ID->get_error_message()); - logIO('O', "Posted ! ID: $post_ID"); + if (!$post_ID) + return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); - return $post_ID; - } + $this->attach_uploads( $post_ID, $post_content ); + logIO('O', "Posted ! ID: $post_ID"); - /* blogger.editPost ...edits a post */ - function blogger_editPost($args) { + return $post_ID; + } - global $wpdb; + /** + * Edit a post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return bool true when done. + */ + function blogger_editPost($args) { $this->escape($args); - $post_ID = (int) $args[1]; - $user_login = $args[2]; - $user_pass = $args[3]; - $content = $args[4]; - $publish = $args[5]; + $post_ID = (int) $args[1]; + $username = $args[2]; + $password = $args[3]; + $content = $args[4]; + $publish = $args[5]; - if (!$this->login_pass_ok($user_login, $user_pass)) { - return $this->error; - } + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } - $actual_post = wp_get_single_post($post_ID,ARRAY_A); + do_action('xmlrpc_call', 'blogger.editPost'); - if (!$actual_post) { - return new IXR_Error(404, __('Sorry, no such post.')); - } + $actual_post = wp_get_single_post($post_ID,ARRAY_A); + + if (!$actual_post || $actual_post['post_type'] != 'post') { + return new IXR_Error(404, __('Sorry, no such post.')); + } $this->escape($actual_post); - set_current_user(0, $user_login); - if ( !current_user_can('edit_post', $post_ID) ) - return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.')); + if ( !current_user_can('edit_post', $post_ID) ) + return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.')); - extract($actual_post, EXTR_SKIP); + extract($actual_post, EXTR_SKIP); - if ( ('publish' == $post_status) && !current_user_can('publish_posts') ) - return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); + if ( ('publish' == $post_status) && !current_user_can('publish_posts') ) + return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); - $post_title = xmlrpc_getposttitle($content); - $post_category = xmlrpc_getpostcategory($content); - $post_content = xmlrpc_removepostdata($content); + $post_title = xmlrpc_getposttitle($content); + $post_category = xmlrpc_getpostcategory($content); + $post_content = xmlrpc_removepostdata($content); - $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt'); + $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt'); - $result = wp_update_post($postdata); + $result = wp_update_post($postdata); - if (!$result) { - return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.')); - } - $this->attach_uploads( $ID, $post_content ); + if (!$result) { + return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.')); + } + $this->attach_uploads( $ID, $post_content ); - return true; + return true; } - - /* blogger.deletePost ...deletes a post */ + /** + * Remove a post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return bool True when post is deleted. + */ function blogger_deletePost($args) { - - global $wpdb; - $this->escape($args); - $post_ID = (int) $args[1]; - $user_login = $args[2]; - $user_pass = $args[3]; - $publish = $args[4]; + $post_ID = (int) $args[1]; + $username = $args[2]; + $password = $args[3]; + $publish = $args[4]; - if (!$this->login_pass_ok($user_login, $user_pass)) { - return $this->error; - } - - $actual_post = wp_get_single_post($post_ID,ARRAY_A); + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } - if (!$actual_post) { - return new IXR_Error(404, __('Sorry, no such post.')); - } + do_action('xmlrpc_call', 'blogger.deletePost'); - set_current_user(0, $user_login); - if ( !current_user_can('edit_post', $post_ID) ) - return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.')); + $actual_post = wp_get_single_post($post_ID,ARRAY_A); - $result = wp_delete_post($post_ID); + if (!$actual_post || $actual_post['post_type'] != 'post') { + return new IXR_Error(404, __('Sorry, no such post.')); + } - if (!$result) { - return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.')); - } + if ( !current_user_can('edit_post', $post_ID) ) + return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.')); - return true; - } + $result = wp_delete_post($post_ID); + if (!$result) { + return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.')); + } + return true; + } /* MetaWeblog API functions * specs on wherever Dave Winer wants them to be */ - /* metaweblog.newPost creates a post */ + /** + * Create a new post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return int + */ function mw_newPost($args) { - - global $wpdb, $post_default_category; - $this->escape($args); - $blog_ID = (int) $args[0]; // we will support this in the near future - $user_login = $args[1]; - $user_pass = $args[2]; - $content_struct = $args[3]; - $publish = $args[4]; + $blog_ID = (int) $args[0]; // we will support this in the near future + $username = $args[1]; + $password = $args[2]; + $content_struct = $args[3]; + $publish = $args[4]; - if (!$this->login_pass_ok($user_login, $user_pass)) { - return $this->error; - } - $user = set_current_user(0, $user_login); + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } + + do_action('xmlrpc_call', 'metaWeblog.newPost'); $cap = ( $publish ) ? 'publish_posts' : 'edit_posts'; $error_message = __( 'Sorry, you are not allowed to publish posts on this blog.' ); $post_type = 'post'; + $page_template = ''; if( !empty( $content_struct['post_type'] ) ) { if( $content_struct['post_type'] == 'page' ) { $cap = ( $publish ) ? 'publish_pages' : 'edit_pages'; $error_message = __( 'Sorry, you are not allowed to publish pages on this blog.' ); $post_type = 'page'; + if( !empty( $content_struct['wp_page_template'] ) ) + $page_template = $content_struct['wp_page_template']; } - elseif( $content_type['post_type'] == 'post' ) { + elseif( $content_struct['post_type'] == 'post' ) { // This is the default, no changes needed } else { @@ -1021,7 +2066,7 @@ class wp_xmlrpc_server extends IXR_Server { $menu_order = $content_struct["wp_page_order"]; } - $post_author = $user->ID; + $post_author = $user->ID; // If an author id was provided then use it instead. if( @@ -1046,12 +2091,32 @@ class wp_xmlrpc_server extends IXR_Server { $post_author = $content_struct["wp_author_id"]; } - $post_title = $content_struct['title']; - $post_content = apply_filters( 'content_save_pre', $content_struct['description'] ); - $post_status = $publish ? 'publish' : 'draft'; + $post_title = $content_struct['title']; + $post_content = $content_struct['description']; + + $post_status = $publish ? 'publish' : 'draft'; + + if( isset( $content_struct["{$post_type}_status"] ) ) { + switch( $content_struct["{$post_type}_status"] ) { + case 'draft': + case 'private': + case 'publish': + $post_status = $content_struct["{$post_type}_status"]; + break; + case 'pending': + // Pending is only valid for posts, not pages. + if( $post_type === 'post' ) { + $post_status = $content_struct["{$post_type}_status"]; + } + break; + default: + $post_status = $publish ? 'publish' : 'draft'; + break; + } + } - $post_excerpt = $content_struct['mt_excerpt']; - $post_more = $content_struct['mt_text_more']; + $post_excerpt = $content_struct['mt_excerpt']; + $post_more = $content_struct['mt_text_more']; $tags_input = $content_struct['mt_keywords']; @@ -1072,6 +2137,7 @@ class wp_xmlrpc_server extends IXR_Server { else { switch((int) $content_struct["mt_allow_comments"]) { case 0: + case 2: $comment_status = "closed"; break; case 1: @@ -1119,18 +2185,21 @@ class wp_xmlrpc_server extends IXR_Server { $ping_status = get_option("default_ping_status"); } - if ($post_more) { - $post_content = $post_content . "\n\n" . $post_more; - } + if ($post_more) { + $post_content = $post_content . "" . $post_more; + } - $to_ping = $content_struct['mt_tb_ping_urls']; - if ( is_array($to_ping) ) - $to_ping = implode(' ', $to_ping); + $to_ping = $content_struct['mt_tb_ping_urls']; + if ( is_array($to_ping) ) + $to_ping = implode(' ', $to_ping); // Do some timestamp voodoo - $dateCreatedd = $content_struct['dateCreated']; - if (!empty($dateCreatedd)) { - $dateCreated = $dateCreatedd->getIso(); + if ( !empty( $content_struct['date_created_gmt'] ) ) + $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 + elseif ( !empty( $content_struct['dateCreated']) ) + $dateCreated = $content_struct['dateCreated']->getIso(); + + if ( !empty( $dateCreated ) ) { $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); $post_date_gmt = iso8601_to_datetime($dateCreated, GMT); } else { @@ -1138,76 +2207,128 @@ class wp_xmlrpc_server extends IXR_Server { $post_date_gmt = current_time('mysql', 1); } - $catnames = $content_struct['categories']; - logIO('O', 'Post cats: ' . printr($catnames,true)); - $post_category = array(); + $catnames = $content_struct['categories']; + logIO('O', 'Post cats: ' . var_export($catnames,true)); + $post_category = array(); + + if (is_array($catnames)) { + foreach ($catnames as $cat) { + $post_category[] = get_cat_ID($cat); + } + } + + // We've got all the data -- post it: + $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'); + + $post_ID = wp_insert_post($postdata, true); + if ( is_wp_error( $post_ID ) ) + return new IXR_Error(500, $post_ID->get_error_message()); + + if (!$post_ID) { + return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); + } - if (is_array($catnames)) { - foreach ($catnames as $cat) { - $post_category[] = get_cat_ID($cat); - } - } + // Only posts can be sticky + if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) + if ( $content_struct['sticky'] == true ) + stick_post( $post_ID ); + elseif ( $content_struct['sticky'] == false ) + unstick_post( $post_ID ); - // We've got all the data -- post it: - $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'); + if ( isset($content_struct['custom_fields']) ) { + $this->set_custom_fields($post_ID, $content_struct['custom_fields']); + } - $post_ID = wp_insert_post($postdata); - if ( is_wp_error( $post_ID ) ) - return new IXR_Error(500, $post_ID->get_error_message()); + // Handle enclosures + $this->add_enclosure_if_new($post_ID, $content_struct['enclosure']); - if (!$post_ID) { - return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); - } + $this->attach_uploads( $post_ID, $post_content ); - $this->attach_uploads( $post_ID, $post_content ); + logIO('O', "Posted ! ID: $post_ID"); - logIO('O', "Posted ! ID: $post_ID"); + return strval($post_ID); + } - return strval($post_ID); + function add_enclosure_if_new($post_ID, $enclosure) { + if( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) { + + $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type']; + $found = false; + foreach ( (array) get_post_custom($post_ID) as $key => $val) { + if ($key == 'enclosure') { + foreach ( (array) $val as $enc ) { + if ($enc == $encstring) { + $found = true; + break 2; + } + } + } + } + if (!$found) { + add_post_meta( $post_ID, 'enclosure', $encstring ); + } + } } + /** + * Attach upload to a post. + * + * @since 2.1.0 + * + * @param int $post_ID Post ID. + * @param string $post_content Post Content for attachment. + */ function attach_uploads( $post_ID, $post_content ) { global $wpdb; // find any unattached files - $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '-1' AND post_type = 'attachment'" ); + $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" ); if( is_array( $attachments ) ) { foreach( $attachments as $file ) { if( strpos( $post_content, $file->guid ) !== false ) { - $wpdb->query( "UPDATE {$wpdb->posts} SET post_parent = '$post_ID' WHERE ID = '{$file->ID}'" ); + $wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) ); } } } } - /* metaweblog.editPost ...edits a post */ + /** + * Edit a post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return bool True on success. + */ function mw_editPost($args) { - global $wpdb, $post_default_category; - $this->escape($args); - $post_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; - $content_struct = $args[3]; - $publish = $args[4]; + $post_ID = (int) $args[0]; + $username = $args[1]; + $password = $args[2]; + $content_struct = $args[3]; + $publish = $args[4]; + + if ( !$user = $this->login($username, $password) ) { + return $this->error; + } - if (!$this->login_pass_ok($user_login, $user_pass)) { - return $this->error; - } - $user = set_current_user(0, $user_login); + do_action('xmlrpc_call', 'metaWeblog.editPost'); $cap = ( $publish ) ? 'publish_posts' : 'edit_posts'; $error_message = __( 'Sorry, you are not allowed to publish posts on this blog.' ); $post_type = 'post'; + $page_template = ''; if( !empty( $content_struct['post_type'] ) ) { if( $content_struct['post_type'] == 'page' ) { $cap = ( $publish ) ? 'publish_pages' : 'edit_pages'; $error_message = __( 'Sorry, you are not allowed to publish pages on this blog.' ); $post_type = 'page'; + if( !empty( $content_struct['wp_page_template'] ) ) + $page_template = $content_struct['wp_page_template']; } - elseif( $content_type['post_type'] == 'post' ) { + elseif( $content_struct['post_type'] == 'post' ) { // This is the default, no changes needed } else { @@ -1220,13 +2341,13 @@ class wp_xmlrpc_server extends IXR_Server { return new IXR_Error( 401, $error_message ); } - $postdata = wp_get_single_post($post_ID, ARRAY_A); + $postdata = wp_get_single_post($post_ID, ARRAY_A); // If there is no post data for the give post id, stop // now and return an error. Other wise a new post will be // created (which was the old behavior). if(empty($postdata["ID"])) { - return(new IXR_Error(404, __("Invalid post id."))); + return(new IXR_Error(404, __("Invalid post ID."))); } $this->escape($postdata); @@ -1295,6 +2416,7 @@ class wp_xmlrpc_server extends IXR_Server { else { switch((int) $content_struct["mt_allow_comments"]) { case 0: + case 2: $comment_status = "closed"; break; case 1: @@ -1336,104 +2458,150 @@ class wp_xmlrpc_server extends IXR_Server { } } - $post_title = $content_struct['title']; - $post_content = apply_filters( 'content_save_pre', $content_struct['description'] ); - $catnames = $content_struct['categories']; + $post_title = $content_struct['title']; + $post_content = $content_struct['description']; + $catnames = $content_struct['categories']; + + $post_category = array(); + + if (is_array($catnames)) { + foreach ($catnames as $cat) { + $post_category[] = get_cat_ID($cat); + } + } + + $post_excerpt = $content_struct['mt_excerpt']; + $post_more = $content_struct['mt_text_more']; - $post_category = array(); + $post_status = $publish ? 'publish' : 'draft'; + if( isset( $content_struct["{$post_type}_status"] ) ) { + switch( $content_struct["{$post_type}_status"] ) { + case 'draft': + case 'private': + case 'publish': + $post_status = $content_struct["{$post_type}_status"]; + break; + case 'pending': + // Pending is only valid for posts, not pages. + if( $post_type === 'post' ) { + $post_status = $content_struct["{$post_type}_status"]; + } + break; + default: + $post_status = $publish ? 'publish' : 'draft'; + break; + } + } - if (is_array($catnames)) { - foreach ($catnames as $cat) { - $post_category[] = get_cat_ID($cat); - } - } + $tags_input = $content_struct['mt_keywords']; - $post_excerpt = $content_struct['mt_excerpt']; - $post_more = $content_struct['mt_text_more']; - $post_status = $publish ? 'publish' : 'draft'; + if ( ('publish' == $post_status) ) { + if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') ) + return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.')); + else if ( !current_user_can('publish_posts') ) + return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); + } - $tags_input = $content_struct['mt_keywords']; + if ($post_more) { + $post_content = $post_content . "" . $post_more; + } - if ( ('publish' == $post_status) ) { - if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') ) - return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.')); - else if ( !current_user_can('publish_posts') ) - return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); - } + $to_ping = $content_struct['mt_tb_ping_urls']; + if ( is_array($to_ping) ) + $to_ping = implode(' ', $to_ping); - if ($post_more) { - $post_content = $post_content . "\n\n" . $post_more; - } + // Do some timestamp voodoo + if ( !empty( $content_struct['date_created_gmt'] ) ) + $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 + elseif ( !empty( $content_struct['dateCreated']) ) + $dateCreated = $content_struct['dateCreated']->getIso(); - $to_ping = $content_struct['mt_tb_ping_urls']; - if ( is_array($to_ping) ) - $to_ping = implode(' ', $to_ping); + if ( !empty( $dateCreated ) ) { + $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); + $post_date_gmt = iso8601_to_datetime($dateCreated, GMT); + } else { + $post_date = $postdata['post_date']; + $post_date_gmt = $postdata['post_date_gmt']; + } - // Do some timestamp voodoo - $dateCreatedd = $content_struct['dateCreated']; - if (!empty($dateCreatedd)) { - $dateCreated = $dateCreatedd->getIso(); - $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); - $post_date_gmt = iso8601_to_datetime($dateCreated . "Z", GMT); - } else { - $post_date = $postdata['post_date']; - $post_date_gmt = $postdata['post_date_gmt']; - } + // We've got all the data -- post it: + $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'); - // We've got all the data -- post it: - $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'); + $result = wp_update_post($newpost, true); + if ( is_wp_error( $result ) ) + return new IXR_Error(500, $result->get_error_message()); - $result = wp_update_post($newpost); - if (!$result) { - return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.')); - } - $this->attach_uploads( $ID, $post_content ); + if (!$result) { + return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.')); + } - logIO('O',"(MW) Edited ! ID: $post_ID"); + // Only posts can be sticky + if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) + if ( $content_struct['sticky'] == true ) + stick_post( $post_ID ); + elseif ( $content_struct['sticky'] == false ) + unstick_post( $post_ID ); - return true; - } + if ( isset($content_struct['custom_fields']) ) { + $this->set_custom_fields($post_ID, $content_struct['custom_fields']); + } + // Handle enclosures + $this->add_enclosure_if_new($post_ID, $content_struct['enclosure']); - /* metaweblog.getPost ...returns a post */ - function mw_getPost($args) { + $this->attach_uploads( $ID, $post_content ); - global $wpdb; + logIO('O',"(MW) Edited ! ID: $post_ID"); + + return true; + } + + /** + * Retrieve post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ + function mw_getPost($args) { $this->escape($args); $post_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user( 0, $user_login ); if( !current_user_can( 'edit_post', $post_ID ) ) - return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) ); + return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); do_action('xmlrpc_call', 'metaWeblog.getPost'); $postdata = wp_get_single_post($post_ID, ARRAY_A); if ($postdata['post_date'] != '') { - $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date']); - $post_date_gmt = mysql2date('Ymd\TH:i:s', $postdata['post_date_gmt']); + $post_date = mysql2date('Ymd\TH:i:s', $postdata['post_date'], false); + $post_date_gmt = mysql2date('Ymd\TH:i:s', $postdata['post_date_gmt'], false); + + // For drafts use the GMT version of the post date + if ( $postdata['post_status'] == 'draft' ) { + $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $postdata['post_date'] ), 'Ymd\TH:i:s' ); + } $categories = array(); $catids = wp_get_post_categories($post_ID); - foreach($catids as $catid) { + foreach($catids as $catid) $categories[] = get_cat_name($catid); - } $tagnames = array(); $tags = wp_get_post_tags( $post_ID ); if ( !empty( $tags ) ) { - foreach ( $tags as $tag ) { + foreach ( $tags as $tag ) $tagnames[] = $tag->name; - } $tagnames = implode( ', ', $tagnames ); } else { $tagnames = ''; @@ -1448,8 +2616,30 @@ class wp_xmlrpc_server extends IXR_Server { $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0; $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0; + // Consider future posts as published + if( $postdata['post_status'] === 'future' ) { + $postdata['post_status'] = 'publish'; + } + + $sticky = false; + if ( is_sticky( $post_ID ) ) + $sticky = true; + + $enclosure = array(); + foreach ( (array) get_post_custom($post_ID) as $key => $val) { + if ($key == 'enclosure') { + foreach ( (array) $val as $enc ) { + $encdata = split("\n", $enc); + $enclosure['url'] = trim(htmlspecialchars($encdata[0])); + $enclosure['length'] = trim($encdata[1]); + $enclosure['type'] = trim($encdata[2]); + break 2; + } + } + } + $resp = array( - 'dateCreated' => new IXR_Date($post_date), + 'dateCreated' => new IXR_Date($post_date), 'userid' => $postdata['post_author'], 'postid' => $postdata['ID'], 'description' => $post['main'], @@ -1468,45 +2658,60 @@ class wp_xmlrpc_server extends IXR_Server { 'wp_password' => $postdata['post_password'], 'wp_author_id' => $author->ID, 'wp_author_display_name' => $author->display_name, - 'date_created_gmt' => new IXR_Date($post_date_gmt) + 'date_created_gmt' => new IXR_Date($post_date_gmt), + 'post_status' => $postdata['post_status'], + 'custom_fields' => $this->get_custom_fields($post_ID), + 'sticky' => $sticky ); + if (!empty($enclosure)) $resp['enclosure'] = $enclosure; + return $resp; } else { return new IXR_Error(404, __('Sorry, no such post.')); } } - - /* metaweblog.getRecentPosts ...returns recent posts */ + /** + * Retrieve list of recent posts. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function mw_getRecentPosts($args) { $this->escape($args); $blog_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; $num_posts = (int) $args[3]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } + do_action('xmlrpc_call', 'metaWeblog.getRecentPosts'); + $posts_list = wp_get_recent_posts($num_posts); if (!$posts_list) { - $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.')); - return $this->error; + return array( ); } - set_current_user( 0, $user_login ); - foreach ($posts_list as $entry) { if( !current_user_can( 'edit_post', $entry['ID'] ) ) continue; - $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']); - $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt']); + $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false); + $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt'], false); + + // For drafts use the GMT version of the date + if ( $entry['post_status'] == 'draft' ) { + $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $entry['post_date'] ), 'Ymd\TH:i:s' ); + } $categories = array(); $catids = wp_get_post_categories($entry['ID']); @@ -1534,6 +2739,11 @@ class wp_xmlrpc_server extends IXR_Server { $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0; $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0; + // Consider future posts as published + if( $entry['post_status'] === 'future' ) { + $entry['post_status'] = 'publish'; + } + $struct[] = array( 'dateCreated' => new IXR_Date($post_date), 'userid' => $entry['post_author'], @@ -1542,8 +2752,8 @@ class wp_xmlrpc_server extends IXR_Server { 'title' => $entry['post_title'], 'link' => $link, 'permaLink' => $link, -// commented out because no other tool seems to use this -// 'content' => $entry['post_content'], + // commented out because no other tool seems to use this + // 'content' => $entry['post_content'], 'categories' => $categories, 'mt_excerpt' => $entry['post_excerpt'], 'mt_text_more' => $post['extended'], @@ -1554,7 +2764,9 @@ class wp_xmlrpc_server extends IXR_Server { 'wp_password' => $entry['post_password'], 'wp_author_id' => $author->ID, 'wp_author_display_name' => $author->display_name, - 'date_created_gmt' => new IXR_Date($post_date_gmt) + 'date_created_gmt' => new IXR_Date($post_date_gmt), + 'post_status' => $entry['post_status'], + 'custom_fields' => $this->get_custom_fields($entry['ID']) ); } @@ -1567,23 +2779,26 @@ class wp_xmlrpc_server extends IXR_Server { return $recent_posts; } - - /* metaweblog.getCategories ...returns the list of categories on a given blog */ + /** + * Retrieve the list of categories on a given blog. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function mw_getCategories($args) { - global $wpdb; - $this->escape($args); $blog_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user( 0, $user_login ); if( !current_user_can( 'edit_posts' ) ) return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this blog in order to view categories.' ) ); @@ -1596,9 +2811,10 @@ class wp_xmlrpc_server extends IXR_Server { $struct['categoryId'] = $cat->term_id; $struct['parentId'] = $cat->parent; $struct['description'] = $cat->name; + $struct['categoryDescription'] = $cat->description; $struct['categoryName'] = $cat->name; - $struct['htmlUrl'] = wp_specialchars(get_category_link($cat->term_id)); - $struct['rssUrl'] = wp_specialchars(get_category_rss_link(false, $cat->term_id, $cat->name)); + $struct['htmlUrl'] = esc_html(get_category_link($cat->term_id)); + $struct['rssUrl'] = esc_html(get_category_feed_link($cat->term_id, 'rss2')); $categories_struct[] = $struct; } @@ -1607,17 +2823,24 @@ class wp_xmlrpc_server extends IXR_Server { return $categories_struct; } - - /* metaweblog.newMediaObject uploads a file, following your settings */ + /** + * Uploads a file, following your settings. + * + * Adapted from a patch by Johann Richard. + * + * @link http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/ + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function mw_newMediaObject($args) { - // adapted from a patch by Johann Richard - // http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/ - global $wpdb; $blog_ID = (int) $args[0]; - $user_login = $wpdb->escape($args[1]); - $user_pass = $wpdb->escape($args[2]); + $username = $wpdb->escape($args[1]); + $password = $wpdb->escape($args[2]); $data = $args[3]; $name = sanitize_file_name( $data['name'] ); @@ -1626,10 +2849,12 @@ class wp_xmlrpc_server extends IXR_Server { logIO('O', '(MW) Received '.strlen($bits).' bytes'); - if ( !$this->login_pass_ok($user_login, $user_pass) ) + if ( !$user = $this->login($username, $password) ) { return $this->error; + } + + do_action('xmlrpc_call', 'metaWeblog.newMediaObject'); - set_current_user(0, $user_login); if ( !current_user_can('upload_files') ) { logIO('O', '(MW) User does not have upload_files capability'); $this->error = new IXR_Error(401, __('You are not allowed to upload files to this site.')); @@ -1657,15 +2882,15 @@ class wp_xmlrpc_server extends IXR_Server { $name = "wpid{$old_file->ID}-{$filename}"; } - $upload = wp_upload_bits($name, $type, $bits, $overwrite); + $upload = wp_upload_bits($name, $type, $bits); if ( ! empty($upload['error']) ) { $errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']); logIO('O', '(MW) ' . $errorString); return new IXR_Error(500, $errorString); } // Construct the attachment array - // attach to post_id -1 - $post_id = -1; + // attach to post_id 0 + $post_id = 0; $attachment = array( 'post_title' => $name, 'post_content' => '', @@ -1682,25 +2907,33 @@ class wp_xmlrpc_server extends IXR_Server { return apply_filters( 'wp_handle_upload', array( 'file' => $name, 'url' => $upload[ 'url' ], 'type' => $type ) ); } - /* MovableType API functions * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html */ - /* mt.getRecentPostTitles ...returns recent posts' titles */ + /** + * Retrieve the post titles of recent posts. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function mt_getRecentPostTitles($args) { $this->escape($args); $blog_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; $num_posts = (int) $args[3]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } + do_action('xmlrpc_call', 'mt.getRecentPostTitles'); + $posts_list = wp_get_recent_posts($num_posts); if (!$posts_list) { @@ -1708,14 +2941,17 @@ class wp_xmlrpc_server extends IXR_Server { return $this->error; } - set_current_user( 0, $user_login ); - foreach ($posts_list as $entry) { - if( !current_user_can( 'edit_post', $entry['ID'] ) ) + if( !current_user_can( 'edit_post', $entry['ID'] ) ) continue; - $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date']); - $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt']); + $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false); + $post_date_gmt = mysql2date('Ymd\TH:i:s', $entry['post_date_gmt'], false); + + // For drafts use the GMT version of the date + if ( $entry['post_status'] == 'draft' ) { + $post_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $entry['post_date'] ), 'Ymd\TH:i:s' ); + } $struct[] = array( 'dateCreated' => new IXR_Date($post_date), @@ -1735,23 +2971,26 @@ class wp_xmlrpc_server extends IXR_Server { return $recent_posts; } - - /* mt.getCategoryList ...returns the list of categories on a given blog */ + /** + * Retrieve list of all categories on blog. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function mt_getCategoryList($args) { - global $wpdb; - $this->escape($args); $blog_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user( 0, $user_login ); if( !current_user_can( 'edit_posts' ) ) return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this blog in order to view categories.' ) ); @@ -1771,21 +3010,26 @@ class wp_xmlrpc_server extends IXR_Server { return $categories_struct; } - - /* mt.getPostCategories ...returns a post's categories */ + /** + * Retrieve post categories. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function mt_getPostCategories($args) { $this->escape($args); $post_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user( 0, $user_login ); if( !current_user_can( 'edit_post', $post_ID ) ) return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) ); @@ -1807,24 +3051,31 @@ class wp_xmlrpc_server extends IXR_Server { return $categories; } - - /* mt.setPostCategories ...sets a post's categories */ + /** + * Sets categories for a post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return bool True on success. + */ function mt_setPostCategories($args) { $this->escape($args); $post_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; $categories = $args[3]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user(0, $user_login); + do_action('xmlrpc_call', 'mt.setPostCategories'); + if ( !current_user_can('edit_post', $post_ID) ) - return new IXR_Error(401, __('Sorry, you can not edit this post.')); + return new IXR_Error(401, __('Sorry, you cannot edit this post.')); foreach($categories as $cat) { $catids[] = $cat['categoryId']; @@ -1835,10 +3086,18 @@ class wp_xmlrpc_server extends IXR_Server { return true; } - - /* mt.supportedMethods ...returns an array of methods supported by this server */ + /** + * Retrieve an array of methods supported by this server. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function mt_supportedMethods($args) { + do_action('xmlrpc_call', 'mt.supportedMethods'); + $supported_methods = array(); foreach($this->methods as $key=>$value) { $supported_methods[] = $key; @@ -1847,28 +3106,41 @@ class wp_xmlrpc_server extends IXR_Server { return $supported_methods; } - - /* mt.supportedTextFilters ...returns an empty array because we don't - support per-post text filters yet */ + /** + * Retrieve an empty array because we don't support per-post text filters. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + */ function mt_supportedTextFilters($args) { + do_action('xmlrpc_call', 'mt.supportedTextFilters'); return apply_filters('xmlrpc_text_filters', array()); } - - /* mt.getTrackbackPings ...returns trackbacks sent to a given post */ + /** + * Retrieve trackbacks sent to a given post. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return mixed + */ function mt_getTrackbackPings($args) { global $wpdb; $post_ID = intval($args); + do_action('xmlrpc_call', 'mt.getTrackbackPings'); + $actual_post = wp_get_single_post($post_ID, ARRAY_A); if (!$actual_post) { return new IXR_Error(404, __('Sorry, no such post.')); } - $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID"); + $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) ); if (!$comments) { return array(); @@ -1890,23 +3162,30 @@ class wp_xmlrpc_server extends IXR_Server { return $trackback_pings; } - - /* mt.publishPost ...sets a post's publish status to 'publish' */ + /** + * Sets a post's publish status to 'publish'. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return int + */ function mt_publishPost($args) { $this->escape($args); $post_ID = (int) $args[0]; - $user_login = $args[1]; - $user_pass = $args[2]; + $username = $args[1]; + $password = $args[2]; - if (!$this->login_pass_ok($user_login, $user_pass)) { + if ( !$user = $this->login($username, $password) ) { return $this->error; } - set_current_user(0, $user_login); + do_action('xmlrpc_call', 'mt.publishPost'); + if ( !current_user_can('edit_post', $post_ID) ) - return new IXR_Error(401, __('Sorry, you can not edit this post.')); + return new IXR_Error(401, __('Sorry, you cannot edit this post.')); $postdata = wp_get_single_post($post_ID,ARRAY_A); @@ -1922,15 +3201,22 @@ class wp_xmlrpc_server extends IXR_Server { return $result; } - - /* PingBack functions * specs on www.hixie.ch/specs/pingback/pingback */ - /* pingback.ping gets a pingback and registers it */ + /** + * Retrieves a pingback and registers it. + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function pingback_ping($args) { - global $wpdb, $wp_version; + global $wpdb; + + do_action('xmlrpc_call', 'pingback.ping'); $this->escape($args); @@ -1943,12 +3229,10 @@ class wp_xmlrpc_server extends IXR_Server { $pagelinkedto = str_replace('&', '&', $pagelinkedto); $pagelinkedto = str_replace('&', '&', $pagelinkedto); - $error_code = -1; - // Check if the page linked to is in our site $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home'))); if( !$pos1 ) - return new IXR_Error(0, __('Is there no link to us?')); + return new IXR_Error(0, __('Is there no link to us?')); // let's find which post is linked to // FIXME: does url_to_postid() cover all these cases already? @@ -1979,7 +3263,7 @@ class wp_xmlrpc_server extends IXR_Server { } elseif (is_string($urltest['fragment'])) { // ...or a string #title, a little more complicated $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']); - $sql = "SELECT ID FROM $wpdb->posts WHERE post_title RLIKE '$title'"; + $sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", $title); if (! ($post_ID = $wpdb->get_var($sql)) ) { // returning unknown error '0' is better than die()ing return new IXR_Error(0, ''); @@ -1988,7 +3272,7 @@ class wp_xmlrpc_server extends IXR_Server { } } else { // TODO: Attempt to extract a post ID from the given URL - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.')); + return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); } $post_ID = (int) $post_ID; @@ -1998,17 +3282,17 @@ class wp_xmlrpc_server extends IXR_Server { $post = get_post($post_ID); if ( !$post ) // Post_ID not found - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.')); + return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); if ( $post_ID == url_to_postid($pagelinkedfrom) ) return new IXR_Error(0, __('The source URL and the target URL cannot both point to the same resource.')); // Check if pings are on - if ( 'closed' == $post->ping_status ) - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.')); + if ( !pings_open($post) ) + return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); // Let's check that the remote site didn't already pingback this entry - $result = $wpdb->get_results("SELECT * FROM $wpdb->comments WHERE comment_post_ID = '$post_ID' AND comment_author_url = '$pagelinkedfrom'"); + $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ); if ( $wpdb->num_rows ) // We already have a Pingback from this URL return new IXR_Error(48, __('The pingback has already been registered.')); @@ -2021,6 +3305,8 @@ class wp_xmlrpc_server extends IXR_Server { if ( !$linea ) return new IXR_Error(16, __('The source URL does not exist.')); + $linea = apply_filters('pre_remote_source', $linea, $pagelinkedto); + // Work around bug in strip_tags(): $linea = str_replace(''); // strip all tags but our context marker $excerpt = trim($excerpt); - $preg_marker = preg_quote($marker); + $preg_marker = preg_quote($marker, '|'); $excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt); $excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper break; @@ -2069,10 +3355,8 @@ class wp_xmlrpc_server extends IXR_Server { $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom); - $context = '[...] ' . wp_specialchars( $excerpt ) . ' [...]'; - $original_pagelinkedfrom = $pagelinkedfrom; + $context = '[...] ' . esc_html( $excerpt ) . ' [...]'; $pagelinkedfrom = $wpdb->escape( $pagelinkedfrom ); - $original_title = $title; $comment_post_ID = (int) $post_ID; $comment_author = $title; @@ -2090,14 +3374,22 @@ class wp_xmlrpc_server extends IXR_Server { return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto); } - - /* pingback.extensions.getPingbacks returns an array of URLs - that pingbacked the given URL - specs on http://www.aquarionics.com/misc/archives/blogite/0198.html */ + /** + * Retrieve array of URLs that pingbacked the given URL. + * + * Specs on http://www.aquarionics.com/misc/archives/blogite/0198.html + * + * @since 1.5.0 + * + * @param array $args Method parameters. + * @return array + */ function pingback_extensions_getPingbacks($args) { global $wpdb; + do_action('xmlrpc_call', 'pingback.extensions.getPingbacks'); + $this->escape($args); $url = $args; @@ -2105,7 +3397,7 @@ class wp_xmlrpc_server extends IXR_Server { $post_ID = url_to_postid($url); if (!$post_ID) { // We aren't sure that the resource is available and/or pingback enabled - return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn\'t exist, or it is not a pingback-enabled resource.')); + return new IXR_Error(33, __('The specified target URL cannot be used as a target. It either doesn’t exist, or it is not a pingback-enabled resource.')); } $actual_post = wp_get_single_post($post_ID, ARRAY_A); @@ -2115,7 +3407,7 @@ class wp_xmlrpc_server extends IXR_Server { return new IXR_Error(32, __('The specified target URL does not exist.')); } - $comments = $wpdb->get_results("SELECT comment_author_url, comment_content, comment_author_IP, comment_type FROM $wpdb->comments WHERE comment_post_ID = $post_ID"); + $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) ); if (!$comments) { return array(); @@ -2131,7 +3423,6 @@ class wp_xmlrpc_server extends IXR_Server { } } - $wp_xmlrpc_server = new wp_xmlrpc_server(); - +$wp_xmlrpc_server->serve_request(); ?>