| [ Root ] [ Index ] |
PHP Cross Reference of WordPress 2.9.1Provided by Yoast |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * XML-RPC protocol support for WordPress 4 * 5 * @license GPL v2 <./license.txt> 6 * @package WordPress 7 */ 8 9 /** 10 * Whether this is a XMLRPC Request 11 * 12 * @var bool 13 */ 14 define('XMLRPC_REQUEST', true); 15 16 // Some browser-embedded clients send cookies. We don't want them. 17 $_COOKIE = array(); 18 19 // A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default, 20 // but we can do it ourself. 21 if ( !isset( $HTTP_RAW_POST_DATA ) ) { 22 $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' ); 23 } 24 25 // fix for mozBlog and other cases where '<?xml' isn't on the very first line 26 if ( isset($HTTP_RAW_POST_DATA) ) 27 $HTTP_RAW_POST_DATA = trim($HTTP_RAW_POST_DATA); 28 29 /** Include the bootstrap for setting up WordPress environment */ 30 include ('./wp-load.php'); 31 32 if ( isset( $_GET['rsd'] ) ) { // http://archipelago.phrasewise.com/rsd 33 header('Content-Type: text/xml; charset=' . get_option('blog_charset'), true); 34 ?> 35 <?php echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>'; ?> 36 <rsd version="1.0" xmlns="http://archipelago.phrasewise.com/rsd"> 37 <service> 38 <engineName>WordPress</engineName> 39 <engineLink>http://wordpress.org/</engineLink> 40 <homePageLink><?php bloginfo_rss('url') ?></homePageLink> 41 <apis> 42 <api name="WordPress" blogID="1" preferred="true" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" /> 43 <api name="Movable Type" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" /> 44 <api name="MetaWeblog" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" /> 45 <api name="Blogger" blogID="1" preferred="false" apiLink="<?php echo site_url('xmlrpc.php', 'rpc') ?>" /> 46 <api name="Atom" blogID="" preferred="false" apiLink="<?php echo apply_filters('atom_service_url', site_url('wp-app.php/service', 'rpc') ) ?>" /> 47 </apis> 48 </service> 49 </rsd> 50 <?php 51 exit; 52 } 53 54 include_once (ABSPATH . 'wp-admin/includes/admin.php'); 55 include_once(ABSPATH . WPINC . '/class-IXR.php'); 56 57 // Turn off all warnings and errors. 58 // error_reporting(0); 59 60 /** 61 * Posts submitted via the xmlrpc interface get that title 62 * @name post_default_title 63 * @var string 64 */ 65 $post_default_title = ""; 66 67 /** 68 * Whether to enable XMLRPC Logging. 69 * 70 * @name xmlrpc_logging 71 * @var int|bool 72 */ 73 $xmlrpc_logging = 0; 74 75 /** 76 * logIO() - Writes logging info to a file. 77 * 78 * @uses $xmlrpc_logging 79 * @package WordPress 80 * @subpackage Logging 81 * 82 * @param string $io Whether input or output 83 * @param string $msg Information describing logging reason. 84 * @return bool Always return true 85 */ 86 function logIO($io,$msg) { 87 global $xmlrpc_logging; 88 if ($xmlrpc_logging) { 89 $fp = fopen("../xmlrpc.log","a+"); 90 $date = gmdate("Y-m-d H:i:s "); 91 $iot = ($io == "I") ? " Input: " : " Output: "; 92 fwrite($fp, "\n\n".$date.$iot.$msg); 93 fclose($fp); 94 } 95 return true; 96 } 97 98 if ( isset($HTTP_RAW_POST_DATA) ) 99 logIO("I", $HTTP_RAW_POST_DATA); 100 101 /** 102 * WordPress XMLRPC server implementation. 103 * 104 * Implements compatability for Blogger API, MetaWeblog API, MovableType, and 105 * pingback. Additional WordPress API for managing comments, pages, posts, 106 * options, etc. 107 * 108 * Since WordPress 2.6.0, WordPress XMLRPC server can be disabled in the 109 * administration panels. 110 * 111 * @package WordPress 112 * @subpackage Publishing 113 * @since 1.5.0 114 */ 115 class wp_xmlrpc_server extends IXR_Server { 116 117 /** 118 * Register all of the XMLRPC methods that XMLRPC server understands. 119 * 120 * PHP4 constructor and sets up server and method property. Passes XMLRPC 121 * methods through the 'xmlrpc_methods' filter to allow plugins to extend 122 * or replace XMLRPC methods. 123 * 124 * @since 1.5.0 125 * 126 * @return wp_xmlrpc_server 127 */ 128 function wp_xmlrpc_server() { 129 $this->methods = array( 130 // WordPress API 131 'wp.getUsersBlogs' => 'this:wp_getUsersBlogs', 132 'wp.getPage' => 'this:wp_getPage', 133 'wp.getPages' => 'this:wp_getPages', 134 'wp.newPage' => 'this:wp_newPage', 135 'wp.deletePage' => 'this:wp_deletePage', 136 'wp.editPage' => 'this:wp_editPage', 137 'wp.getPageList' => 'this:wp_getPageList', 138 'wp.getAuthors' => 'this:wp_getAuthors', 139 'wp.getCategories' => 'this:mw_getCategories', // Alias 140 'wp.getTags' => 'this:wp_getTags', 141 'wp.newCategory' => 'this:wp_newCategory', 142 'wp.deleteCategory' => 'this:wp_deleteCategory', 143 'wp.suggestCategories' => 'this:wp_suggestCategories', 144 'wp.uploadFile' => 'this:mw_newMediaObject', // Alias 145 'wp.getCommentCount' => 'this:wp_getCommentCount', 146 'wp.getPostStatusList' => 'this:wp_getPostStatusList', 147 'wp.getPageStatusList' => 'this:wp_getPageStatusList', 148 'wp.getPageTemplates' => 'this:wp_getPageTemplates', 149 'wp.getOptions' => 'this:wp_getOptions', 150 'wp.setOptions' => 'this:wp_setOptions', 151 'wp.getComment' => 'this:wp_getComment', 152 'wp.getComments' => 'this:wp_getComments', 153 'wp.deleteComment' => 'this:wp_deleteComment', 154 'wp.editComment' => 'this:wp_editComment', 155 'wp.newComment' => 'this:wp_newComment', 156 'wp.getCommentStatusList' => 'this:wp_getCommentStatusList', 157 158 // Blogger API 159 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs', 160 'blogger.getUserInfo' => 'this:blogger_getUserInfo', 161 'blogger.getPost' => 'this:blogger_getPost', 162 'blogger.getRecentPosts' => 'this:blogger_getRecentPosts', 163 'blogger.getTemplate' => 'this:blogger_getTemplate', 164 'blogger.setTemplate' => 'this:blogger_setTemplate', 165 'blogger.newPost' => 'this:blogger_newPost', 166 'blogger.editPost' => 'this:blogger_editPost', 167 'blogger.deletePost' => 'this:blogger_deletePost', 168 169 // MetaWeblog API (with MT extensions to structs) 170 'metaWeblog.newPost' => 'this:mw_newPost', 171 'metaWeblog.editPost' => 'this:mw_editPost', 172 'metaWeblog.getPost' => 'this:mw_getPost', 173 'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts', 174 'metaWeblog.getCategories' => 'this:mw_getCategories', 175 'metaWeblog.newMediaObject' => 'this:mw_newMediaObject', 176 177 // MetaWeblog API aliases for Blogger API 178 // see http://www.xmlrpc.com/stories/storyReader$2460 179 'metaWeblog.deletePost' => 'this:blogger_deletePost', 180 'metaWeblog.getTemplate' => 'this:blogger_getTemplate', 181 'metaWeblog.setTemplate' => 'this:blogger_setTemplate', 182 'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs', 183 184 // MovableType API 185 'mt.getCategoryList' => 'this:mt_getCategoryList', 186 'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles', 187 'mt.getPostCategories' => 'this:mt_getPostCategories', 188 'mt.setPostCategories' => 'this:mt_setPostCategories', 189 'mt.supportedMethods' => 'this:mt_supportedMethods', 190 'mt.supportedTextFilters' => 'this:mt_supportedTextFilters', 191 'mt.getTrackbackPings' => 'this:mt_getTrackbackPings', 192 'mt.publishPost' => 'this:mt_publishPost', 193 194 // PingBack 195 'pingback.ping' => 'this:pingback_ping', 196 'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks', 197 198 'demo.sayHello' => 'this:sayHello', 199 'demo.addTwoNumbers' => 'this:addTwoNumbers' 200 ); 201 202 $this->initialise_blog_option_info( ); 203 $this->methods = apply_filters('xmlrpc_methods', $this->methods); 204 } 205 206 function serve_request() { 207 $this->IXR_Server($this->methods); 208 } 209 210 /** 211 * Test XMLRPC API by saying, "Hello!" to client. 212 * 213 * @since 1.5.0 214 * 215 * @param array $args Method Parameters. 216 * @return string 217 */ 218 function sayHello($args) { 219 return 'Hello!'; 220 } 221 222 /** 223 * Test XMLRPC API by adding two numbers for client. 224 * 225 * @since 1.5.0 226 * 227 * @param array $args Method Parameters. 228 * @return int 229 */ 230 function addTwoNumbers($args) { 231 $number1 = $args[0]; 232 $number2 = $args[1]; 233 return $number1 + $number2; 234 } 235 236 /** 237 * Check user's credentials. 238 * 239 * @since 1.5.0 240 * 241 * @param string $user_login User's username. 242 * @param string $user_pass User's password. 243 * @return bool Whether authentication passed. 244 * @deprecated use wp_xmlrpc_server::login 245 * @see wp_xmlrpc_server::login 246 */ 247 function login_pass_ok($user_login, $user_pass) { 248 if ( !get_option( 'enable_xmlrpc' ) ) { 249 $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this blog. An admin user can enable them at %s'), admin_url('options-writing.php') ) ); 250 return false; 251 } 252 253 if (!user_pass_ok($user_login, $user_pass)) { 254 $this->error = new IXR_Error(403, __('Bad login/pass combination.')); 255 return false; 256 } 257 return true; 258 } 259 260 /** 261 * Log user in. 262 * 263 * @since 2.8 264 * 265 * @param string $username User's username. 266 * @param string $password User's password. 267 * @return mixed WP_User object if authentication passed, false otherwise 268 */ 269 function login($username, $password) { 270 if ( !get_option( 'enable_xmlrpc' ) ) { 271 $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this blog. An admin user can enable them at %s'), admin_url('options-writing.php') ) ); 272 return false; 273 } 274 275 $user = wp_authenticate($username, $password); 276 277 if (is_wp_error($user)) { 278 $this->error = new IXR_Error(403, __('Bad login/pass combination.')); 279 return false; 280 } 281 282 set_current_user( $user->ID ); 283 return $user; 284 } 285 286 /** 287 * Sanitize string or array of strings for database. 288 * 289 * @since 1.5.2 290 * 291 * @param string|array $array Sanitize single string or array of strings. 292 * @return string|array Type matches $array and sanitized for the database. 293 */ 294 function escape(&$array) { 295 global $wpdb; 296 297 if(!is_array($array)) { 298 return($wpdb->escape($array)); 299 } 300 else { 301 foreach ( (array) $array as $k => $v ) { 302 if (is_array($v)) { 303 $this->escape($array[$k]); 304 } else if (is_object($v)) { 305 //skip 306 } else { 307 $array[$k] = $wpdb->escape($v); 308 } 309 } 310 } 311 } 312 313 /** 314 * Retrieve custom fields for post. 315 * 316 * @since 2.5.0 317 * 318 * @param int $post_id Post ID. 319 * @return array Custom fields, if exist. 320 */ 321 function get_custom_fields($post_id) { 322 $post_id = (int) $post_id; 323 324 $custom_fields = array(); 325 326 foreach ( (array) has_meta($post_id) as $meta ) { 327 // Don't expose protected fields. 328 if ( strpos($meta['meta_key'], '_wp_') === 0 ) { 329 continue; 330 } 331 332 $custom_fields[] = array( 333 "id" => $meta['meta_id'], 334 "key" => $meta['meta_key'], 335 "value" => $meta['meta_value'] 336 ); 337 } 338 339 return $custom_fields; 340 } 341 342 /** 343 * Set custom fields for post. 344 * 345 * @since 2.5.0 346 * 347 * @param int $post_id Post ID. 348 * @param array $fields Custom fields. 349 */ 350 function set_custom_fields($post_id, $fields) { 351 $post_id = (int) $post_id; 352 353 foreach ( (array) $fields as $meta ) { 354 if ( isset($meta['id']) ) { 355 $meta['id'] = (int) $meta['id']; 356 357 if ( isset($meta['key']) ) { 358 update_meta($meta['id'], $meta['key'], $meta['value']); 359 } 360 else { 361 delete_meta($meta['id']); 362 } 363 } 364 else { 365 $_POST['metakeyinput'] = $meta['key']; 366 $_POST['metavalue'] = $meta['value']; 367 add_meta($post_id); 368 } 369 } 370 } 371 372 /** 373 * Setup blog options property. 374 * 375 * Passes property through 'xmlrpc_blog_options' filter. 376 * 377 * @since 2.6.0 378 */ 379 function initialise_blog_option_info( ) { 380 global $wp_version; 381 382 $this->blog_options = array( 383 // Read only options 384 'software_name' => array( 385 'desc' => __( 'Software Name' ), 386 'readonly' => true, 387 'value' => 'WordPress' 388 ), 389 'software_version' => array( 390 'desc' => __( 'Software Version' ), 391 'readonly' => true, 392 'value' => $wp_version 393 ), 394 'blog_url' => array( 395 'desc' => __( 'Blog URL' ), 396 'readonly' => true, 397 'option' => 'siteurl' 398 ), 399 400 // Updatable options 401 'time_zone' => array( 402 'desc' => __( 'Time Zone' ), 403 'readonly' => false, 404 'option' => 'gmt_offset' 405 ), 406 'blog_title' => array( 407 'desc' => __( 'Blog Title' ), 408 'readonly' => false, 409 'option' => 'blogname' 410 ), 411 'blog_tagline' => array( 412 'desc' => __( 'Blog Tagline' ), 413 'readonly' => false, 414 'option' => 'blogdescription' 415 ), 416 'date_format' => array( 417 'desc' => __( 'Date Format' ), 418 'readonly' => false, 419 'option' => 'date_format' 420 ), 421 'time_format' => array( 422 'desc' => __( 'Time Format' ), 423 'readonly' => false, 424 'option' => 'time_format' 425 ), 426 'users_can_register' => array( 427 'desc' => __( 'Allow new users to sign up' ), 428 'readonly' => false, 429 'option' => 'users_can_register' 430 ) 431 ); 432 433 $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options ); 434 } 435 436 /** 437 * Retrieve the blogs of the user. 438 * 439 * @since 2.6.0 440 * 441 * @param array $args Method parameters. 442 * @return array 443 */ 444 function wp_getUsersBlogs( $args ) { 445 // If this isn't on WPMU then just use blogger_getUsersBlogs 446 if( !function_exists( 'is_site_admin' ) ) { 447 array_unshift( $args, 1 ); 448 return $this->blogger_getUsersBlogs( $args ); 449 } 450 451 $this->escape( $args ); 452 453 $username = $args[0]; 454 $password = $args[1]; 455 456 if ( !$user = $this->login($username, $password) ) { 457 return $this->error; 458 } 459 460 do_action( 'xmlrpc_call', 'wp.getUsersBlogs' ); 461 462 $blogs = (array) get_blogs_of_user( $user->ID ); 463 $struct = array( ); 464 465 foreach( $blogs as $blog ) { 466 // Don't include blogs that aren't hosted at this site 467 if( $blog->site_id != $current_site->id ) 468 continue; 469 470 $blog_id = $blog->userblog_id; 471 switch_to_blog($blog_id); 472 $is_admin = current_user_can('level_8'); 473 474 $struct[] = array( 475 'isAdmin' => $is_admin, 476 'url' => get_option( 'home' ) . '/', 477 'blogid' => $blog_id, 478 'blogName' => get_option( 'blogname' ), 479 'xmlrpc' => site_url( 'xmlrpc.php' ) 480 ); 481 482 restore_current_blog( ); 483 } 484 485 return $struct; 486 } 487 488 /** 489 * Retrieve page. 490 * 491 * @since 2.2.0 492 * 493 * @param array $args Method parameters. 494 * @return array 495 */ 496 function wp_getPage($args) { 497 $this->escape($args); 498 499 $blog_id = (int) $args[0]; 500 $page_id = (int) $args[1]; 501 $username = $args[2]; 502 $password = $args[3]; 503 504 if ( !$user = $this->login($username, $password) ) { 505 return $this->error; 506 } 507 508 if( !current_user_can( 'edit_page', $page_id ) ) 509 return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) ); 510 511 do_action('xmlrpc_call', 'wp.getPage'); 512 513 // Lookup page info. 514 $page = get_page($page_id); 515 516 // If we found the page then format the data. 517 if($page->ID && ($page->post_type == "page")) { 518 // Get all of the page content and link. 519 $full_page = get_extended($page->post_content); 520 $link = post_permalink($page->ID); 521 522 // Get info the page parent if there is one. 523 $parent_title = ""; 524 if(!empty($page->post_parent)) { 525 $parent = get_page($page->post_parent); 526 $parent_title = $parent->post_title; 527 } 528 529 // Determine comment and ping settings. 530 $allow_comments = comments_open($page->ID) ? 1 : 0; 531 $allow_pings = pings_open($page->ID) ? 1 : 0; 532 533 // Format page date. 534 $page_date = mysql2date("Ymd\TH:i:s", $page->post_date, false); 535 $page_date_gmt = mysql2date("Ymd\TH:i:s", $page->post_date_gmt, false); 536 537 // For drafts use the GMT version of the date 538 if ( $page->post_status == 'draft' ) { 539 $page_date_gmt = get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $page->post_date ), 'Ymd\TH:i:s' ); 540 } 541 542 // Pull the categories info together. 543 $categories = array(); 544 foreach(wp_get_post_categories($page->ID) as $cat_id) { 545 $categories[] = get_cat_name($cat_id); 546 } 547 548 // Get the author info. 549 $author = get_userdata($page->post_author); 550 551 $page_template = get_post_meta( $page->ID, '_wp_page_template', true ); 552 if( empty( $page_template ) ) 553 $page_template = 'default'; 554 555 $page_struct = array( 556 "dateCreated" => new IXR_Date($page_date), 557 "userid" => $page->post_author, 558 "page_id" => $page->ID, 559 "page_status" => $page->post_status, 560 "description" => $full_page["main"], 561 "title" => $page->post_title, 562 "link" => $link, 563 "permaLink" => $link, 564 "categories" => $categories, 565 "excerpt" => $page->post_excerpt, 566 "text_more" => $full_page["extended"], 567 "mt_allow_comments" => $allow_comments, 568 "mt_allow_pings" => $allow_pings, 569 "wp_slug" => $page->post_name, 570 "wp_password" => $page->post_password, 571 "wp_author" => $author->display_name, 572 "wp_page_parent_id" => $page->post_parent, 573 "wp_page_parent_title" => $parent_title, 574 "wp_page_order" => $page->menu_order, 575 "wp_author_id" => $author->ID, 576 "wp_author_display_name" => $author->display_name, 577 "date_created_gmt" => new IXR_Date($page_date_gmt), 578 "custom_fields" => $this->get_custom_fields($page_id), 579 "wp_page_template" => $page_template 580 ); 581 582 return($page_struct); 583 } 584 // If the page doesn't exist indicate that. 585 else { 586 return(new IXR_Error(404, __("Sorry, no such page."))); 587 } 588 } 589 590 /** 591 * Retrieve Pages. 592 * 593 * @since 2.2.0 594 * 595 * @param array $args Method parameters. 596 * @return array 597 */ 598 function wp_getPages($args) { 599 $this->escape($args); 600 601 $blog_id = (int) $args[0]; 602 $username = $args[1]; 603 $password = $args[2]; 604 $num_pages = isset($args[3]) ? (int) $args[3] : 10; 605 606 if ( !$user = $this->login($username, $password) ) { 607 return $this->error; 608 } 609 610 if( !current_user_can( 'edit_pages' ) ) 611 return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); 612 613 do_action('xmlrpc_call', 'wp.getPages'); 614 615 $pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) ); 616 $num_pages = count($pages); 617 618 // If we have pages, put together their info. 619 if($num_pages >= 1) { 620 $pages_struct = array(); 621 622 for($i = 0; $i < $num_pages; $i++) { 623 $page = wp_xmlrpc_server::wp_getPage(array( 624 $blog_id, $pages[$i]->ID, $username, $password 625 )); 626 $pages_struct[] = $page; 627 } 628 629 return($pages_struct); 630 } 631 // If no pages were found return an error. 632 else { 633 return(array()); 634 } 635 } 636 637 /** 638 * Create new page. 639 * 640 * @since 2.2.0 641 * 642 * @param array $args Method parameters. 643 * @return unknown 644 */ 645 function wp_newPage($args) { 646 // Items not escaped here will be escaped in newPost. 647 $username = $this->escape($args[1]); 648 $password = $this->escape($args[2]); 649 $page = $args[3]; 650 $publish = $args[4]; 651 652 if ( !$user = $this->login($username, $password) ) { 653 return $this->error; 654 } 655 656 do_action('xmlrpc_call', 'wp.newPage'); 657 658 // Make sure the user is allowed to add new pages. 659 if(!current_user_can("publish_pages")) { 660 return(new IXR_Error(401, __("Sorry, you cannot add new pages."))); 661 } 662 663 // Mark this as content for a page. 664 $args[3]["post_type"] = "page"; 665 666 // Let mw_newPost do all of the heavy lifting. 667 return($this->mw_newPost($args)); 668 } 669 670 /** 671 * Delete page. 672 * 673 * @since 2.2.0 674 * 675 * @param array $args Method parameters. 676 * @return bool True, if success. 677 */ 678 function wp_deletePage($args) { 679 $this->escape($args); 680 681 $blog_id = (int) $args[0]; 682 $username = $args[1]; 683 $password = $args[2]; 684 $page_id = (int) $args[3]; 685 686 if ( !$user = $this->login($username, $password) ) { 687 return $this->error; 688 } 689 690 do_action('xmlrpc_call', 'wp.deletePage'); 691 692 // Get the current page based on the page_id and 693 // make sure it is a page and not a post. 694 $actual_page = wp_get_single_post($page_id, ARRAY_A); 695 if( 696 !$actual_page 697 || ($actual_page["post_type"] != "page") 698 ) { 699 return(new IXR_Error(404, __("Sorry, no such page."))); 700 } 701 702 // Make sure the user can delete pages. 703 if(!current_user_can("delete_page", $page_id)) { 704 return(new IXR_Error(401, __("Sorry, you do not have the right to delete this page."))); 705 } 706 707 // Attempt to delete the page. 708 $result = wp_delete_post($page_id); 709 if(!$result) { 710 return(new IXR_Error(500, __("Failed to delete the page."))); 711 } 712 713 return(true); 714 } 715 716 /** 717 * Edit page. 718 * 719 * @since 2.2.0 720 * 721 * @param array $args Method parameters. 722 * @return unknown 723 */ 724 function wp_editPage($args) { 725 // Items not escaped here will be escaped in editPost. 726 $blog_id = (int) $args[0]; 727 $page_id = (int) $this->escape($args[1]); 728 $username = $this->escape($args[2]); 729 $password = $this->escape($args[3]); 730 $content = $args[4]; 731 $publish = $args[5]; 732 733 if ( !$user = $this->login($username, $password) ) { 734 return $this->error; 735 } 736 737 do_action('xmlrpc_call', 'wp.editPage'); 738 739 // Get the page data and make sure it is a page. 740 $actual_page = wp_get_single_post($page_id, ARRAY_A); 741 if( 742 !$actual_page 743 || ($actual_page["post_type"] != "page") 744 ) { 745 return(new IXR_Error(404, __("Sorry, no such page."))); 746 } 747 748 // Make sure the user is allowed to edit pages. 749 if(!current_user_can("edit_page", $page_id)) { 750 return(new IXR_Error(401, __("Sorry, you do not have the right to edit this page."))); 751 } 752 753 // Mark this as content for a page. 754 $content["post_type"] = "page"; 755 756 // Arrange args in the way mw_editPost understands. 757 $args = array( 758 $page_id, 759 $username, 760 $password, 761 $content, 762 $publish 763 ); 764 765 // Let mw_editPost do all of the heavy lifting. 766 return($this->mw_editPost($args)); 767 } 768 769 /** 770 * Retrieve page list. 771 * 772 * @since 2.2.0 773 * 774 * @param array $args Method parameters. 775 * @return unknown 776 */ 777 function wp_getPageList($args) { 778 global $wpdb; 779 780 $this->escape($args); 781 782 $blog_id = (int) $args[0]; 783 $username = $args[1]; 784 $password = $args[2]; 785 786 if ( !$user = $this->login($username, $password) ) { 787 return $this->error; 788 } 789 790 if( !current_user_can( 'edit_pages' ) ) 791 return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); 792 793 do_action('xmlrpc_call', 'wp.getPageList'); 794 795 // Get list of pages ids and titles 796 $page_list = $wpdb->get_results(" 797 SELECT ID page_id, 798 post_title page_title, 799 post_parent page_parent_id, 800 post_date_gmt, 801 post_date, 802 post_status 803 FROM {$wpdb->posts} 804 WHERE post_type = 'page' 805 ORDER BY ID 806 "); 807 808 // The date needs to be formated properly. 809 $num_pages = count($page_list); 810 for($i = 0; $i < $num_pages; $i++) { 811 $post_date = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date, false); 812 $post_date_gmt = mysql2date("Ymd\TH:i:s", $page_list[$i]->post_date_gmt, false); 813 814 $page_list[$i]->dateCreated = new IXR_Date($post_date); 815 $page_list[$i]->date_created_gmt = new IXR_Date($post_date_gmt); 816 817 // For drafts use the GMT version of the date 818 if ( $page_list[$i]->post_status == 'draft' ) { 819 $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' ); 820 $page_list[$i]->date_created_gmt = new IXR_Date( $page_list[$i]->date_created_gmt ); 821 } 822 823 unset($page_list[$i]->post_date_gmt); 824 unset($page_list[$i]->post_date); 825 unset($page_list[$i]->post_status); 826 } 827 828 return($page_list); 829 } 830 831 /** 832 * Retrieve authors list. 833 * 834 * @since 2.2.0 835 * 836 * @param array $args Method parameters. 837 * @return array 838 */ 839 function wp_getAuthors($args) { 840 841 $this->escape($args); 842 843 $blog_id = (int) $args[0]; 844 $username = $args[1]; 845 $password = $args[2]; 846 847 if ( !$user = $this->login($username, $password) ) { 848 return $this->error; 849 } 850 851 if(!current_user_can("edit_posts")) { 852 return(new IXR_Error(401, __("Sorry, you cannot edit posts on this blog."))); 853 } 854 855 do_action('xmlrpc_call', 'wp.getAuthors'); 856 857 $authors = array(); 858 foreach( (array) get_users_of_blog() as $row ) { 859 $authors[] = array( 860 "user_id" => $row->user_id, 861 "user_login" => $row->user_login, 862 "display_name" => $row->display_name 863 ); 864 } 865 866 return($authors); 867 } 868 869 /** 870 * Get list of all tags 871 * 872 * @since 2.7 873 * 874 * @param array $args Method parameters. 875 * @return array 876 */ 877 function wp_getTags( $args ) { 878 $this->escape( $args ); 879 880 $blog_id = (int) $args[0]; 881 $username = $args[1]; 882 $password = $args[2]; 883 884 if ( !$user = $this->login($username, $password) ) { 885 return $this->error; 886 } 887 888 if( !current_user_can( 'edit_posts' ) ) { 889 return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this blog in order to view tags.' ) ); 890 } 891 892 do_action( 'xmlrpc_call', 'wp.getKeywords' ); 893 894 $tags = array( ); 895 896 if( $all_tags = get_tags( ) ) { 897 foreach( (array) $all_tags as $tag ) { 898 $struct['tag_id'] = $tag->term_id; 899 $struct['name'] = $tag->name; 900 $struct['count'] = $tag->count; 901 $struct['slug'] = $tag->slug; 902 $struct['html_url'] = esc_html( get_tag_link( $tag->term_id ) ); 903 $struct['rss_url'] = esc_html( get_tag_feed_link( $tag->term_id ) ); 904 905 $tags[] = $struct; 906 } 907 } 908 909 return $tags; 910 } 911 912 /** 913 * Create new category. 914 * 915 * @since 2.2.0 916 * 917 * @param array $args Method parameters. 918 * @return int Category ID. 919 */ 920 function wp_newCategory($args) { 921 $this->escape($args); 922 923 $blog_id = (int) $args[0]; 924 $username = $args[1]; 925 $password = $args[2]; 926 $category = $args[3]; 927 928 if ( !$user = $this->login($username, $password) ) { 929 return $this->error; 930 } 931 932 do_action('xmlrpc_call', 'wp.newCategory'); 933 934 // Make sure the user is allowed to add a category. 935 if(!current_user_can("manage_categories")) { 936 return(new IXR_Error(401, __("Sorry, you do not have the right to add a category."))); 937 } 938 939 // If no slug was provided make it empty so that 940 // WordPress will generate one. 941 if(empty($category["slug"])) { 942 $category["slug"] = ""; 943 } 944 945 // If no parent_id was provided make it empty 946 // so that it will be a top level page (no parent). 947 if ( !isset($category["parent_id"]) ) 948 $category["parent_id"] = ""; 949 950 // If no description was provided make it empty. 951 if(empty($category["description"])) { 952 $category["description"] = ""; 953 } 954 955 $new_category = array( 956 "cat_name" => $category["name"], 957 "category_nicename" => $category["slug"], 958 "category_parent" => $category["parent_id"], 959 "category_description" => $category["description"] 960 ); 961 962 $cat_id = wp_insert_category($new_category); 963 if(!$cat_id) { 964 return(new IXR_Error(500, __("Sorry, the new category failed."))); 965 } 966 967 return($cat_id); 968 } 969 970 /** 971 * Remove category. 972 * 973 * @since 2.5.0 974 * 975 * @param array $args Method parameters. 976 * @return mixed See {@link wp_delete_category()} for return info. 977 */ 978 function wp_deleteCategory($args) { 979 $this->escape($args); 980 981 $blog_id = (int) $args[0]; 982 $username = $args[1]; 983 $password = $args[2]; 984 $category_id = (int) $args[3]; 985 986 if ( !$user = $this->login($username, $password) ) { 987 return $this->error; 988 } 989 990 do_action('xmlrpc_call', 'wp.deleteCategory'); 991 992 if( !current_user_can("manage_categories") ) { 993 return new IXR_Error( 401, __( "Sorry, you do not have the right to delete a category." ) ); 994 } 995 996 return wp_delete_category( $category_id ); 997 } 998 999 /** 1000 * Retrieve category list. 1001 * 1002 * @since 2.2.0 1003 * 1004 * @param array $args Method parameters. 1005 * @return array 1006 */ 1007 function wp_suggestCategories($args) { 1008 $this->escape($args); 1009 1010 $blog_id = (int) $args[0]; 1011 $username = $args[1]; 1012 $password = $args[2]; 1013 $category = $args[3]; 1014 $max_results = (int) $args[4]; 1015 1016 if ( !$user = $this->login($username, $password) ) { 1017 return $this->error; 1018 } 1019 1020 if( !current_user_can( 'edit_posts' ) ) 1021 return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this blog in order to view categories.' ) ); 1022 1023 do_action('xmlrpc_call', 'wp.suggestCategories'); 1024 1025 $category_suggestions = array(); 1026 $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category); 1027 foreach ( (array) get_categories($args) as $cat ) { 1028 $category_suggestions[] = array( 1029 "category_id" => $cat->cat_ID, 1030 "category_name" => $cat->cat_name 1031 ); 1032 } 1033 1034 return($category_suggestions); 1035 } 1036 1037 /** 1038 * Retrieve comment. 1039 * 1040 * @since 2.7.0 1041 * 1042 * @param array $args Method parameters. 1043 * @return array 1044 */ 1045 function wp_getComment($args) { 1046 $this->escape($args); 1047 1048 $blog_id = (int) $args[0]; 1049 $username = $args[1]; 1050 $password = $args[2]; 1051 $comment_id = (int) $args[3]; 1052 1053 if ( !$user = $this->login($username, $password) ) { 1054 return $this->error; 1055 } 1056 1057 if ( !current_user_can( 'moderate_comments' ) ) 1058 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this blog.' ) ); 1059 1060 do_action('xmlrpc_call', 'wp.getComment'); 1061 1062 if ( ! $comment = get_comment($comment_id) ) 1063 return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 1064 1065 // Format page date. 1066 $comment_date = mysql2date("Ymd\TH:i:s", $comment->comment_date, false); 1067 $comment_date_gmt = mysql2date("Ymd\TH:i:s", $comment->comment_date_gmt, false); 1068 1069 if ( '0' == $comment->comment_approved ) 1070 $comment_status = 'hold'; 1071 else if ( 'spam' == $comment->comment_approved ) 1072 $comment_status = 'spam'; 1073 else if ( '1' == $comment->comment_approved ) 1074 $comment_status = 'approve'; 1075 else 1076 $comment_status = $comment->comment_approved; 1077 1078 $link = get_comment_link($comment); 1079 1080 $comment_struct = array( 1081 "date_created_gmt" => new IXR_Date($comment_date_gmt), 1082 "user_id" => $comment->user_id, 1083 "comment_id" => $comment->comment_ID, 1084 "parent" => $comment->comment_parent, 1085 "status" => $comment_status, 1086 "content" => $comment->comment_content, 1087 "link" => $link, 1088 "post_id" => $comment->comment_post_ID, 1089 "post_title" => get_the_title($comment->comment_post_ID), 1090 "author" => $comment->comment_author, 1091 "author_url" => $comment->comment_author_url, 1092 "author_email" => $comment->comment_author_email, 1093 "author_ip" => $comment->comment_author_IP, 1094 "type" => $comment->comment_type, 1095 ); 1096 1097 return $comment_struct; 1098 } 1099 1100 /** 1101 * Retrieve comments. 1102 * 1103 * @since 2.7.0 1104 * 1105 * @param array $args Method parameters. 1106 * @return array 1107 */ 1108 function wp_getComments($args) { 1109 $this->escape($args); 1110 1111 $blog_id = (int) $args[0]; 1112 $username = $args[1]; 1113 $password = $args[2]; 1114 $struct = $args[3]; 1115 1116 if ( !$user = $this->login($username, $password) ) { 1117 return $this->error; 1118 } 1119 1120 if ( !current_user_can( 'moderate_comments' ) ) 1121 return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) ); 1122 1123 do_action('xmlrpc_call', 'wp.getComments'); 1124 1125 if ( isset($struct['status']) ) 1126 $status = $struct['status']; 1127 else 1128 $status = ''; 1129 1130 $post_id = ''; 1131 if ( isset($struct['post_id']) ) 1132 $post_id = absint($struct['post_id']); 1133 1134 $offset = 0; 1135 if ( isset($struct['offset']) ) 1136 $offset = absint($struct['offset']); 1137 1138 $number = 10; 1139 if ( isset($struct['number']) ) 1140 $number = absint($struct['number']); 1141 1142 $comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) ); 1143 $num_comments = count($comments); 1144 1145 if ( ! $num_comments ) 1146 return array(); 1147 1148 $comments_struct = array(); 1149 1150 for ( $i = 0; $i < $num_comments; $i++ ) { 1151 $comment = wp_xmlrpc_server::wp_getComment(array( 1152 $blog_id, $username, $password, $comments[$i]->comment_ID, 1153 )); 1154 $comments_struct[] = $comment; 1155 } 1156 1157 return $comments_struct; 1158 } 1159 1160 /** 1161 * Remove comment. 1162 * 1163 * @since 2.7.0 1164 * 1165 * @param array $args Method parameters. 1166 * @return mixed {@link wp_delete_comment()} 1167 */ 1168 function wp_deleteComment($args) { 1169 $this->escape($args); 1170 1171 $blog_id = (int) $args[0]; 1172 $username = $args[1]; 1173 $password = $args[2]; 1174 $comment_ID = (int) $args[3]; 1175 1176 if ( !$user = $this->login($username, $password) ) { 1177 return $this->error; 1178 } 1179 1180 if ( !current_user_can( 'moderate_comments' ) ) 1181 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this blog.' ) ); 1182 1183 do_action('xmlrpc_call', 'wp.deleteComment'); 1184 1185 if ( ! get_comment($comment_ID) ) 1186 return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 1187 1188 return wp_delete_comment($comment_ID); 1189 } 1190 1191 /** 1192 * Edit comment. 1193 * 1194 * @since 2.7.0 1195 * 1196 * @param array $args Method parameters. 1197 * @return bool True, on success. 1198 */ 1199 function wp_editComment($args) { 1200 $this->escape($args); 1201 1202 $blog_id = (int) $args[0]; 1203 $username = $args[1]; 1204 $password = $args[2]; 1205 $comment_ID = (int) $args[3]; 1206 $content_struct = $args[4]; 1207 1208 if ( !$user = $this->login($username, $password) ) { 1209 return $this->error; 1210 } 1211 1212 if ( !current_user_can( 'moderate_comments' ) ) 1213 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this blog.' ) ); 1214 1215 do_action('xmlrpc_call', 'wp.editComment'); 1216 1217 if ( ! get_comment($comment_ID) ) 1218 return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 1219 1220 if ( isset($content_struct['status']) ) { 1221 $statuses = get_comment_statuses(); 1222 $statuses = array_keys($statuses); 1223 1224 if ( ! in_array($content_struct['status'], $statuses) ) 1225 return new IXR_Error( 401, __( 'Invalid comment status.' ) ); 1226 $comment_approved = $content_struct['status']; 1227 } 1228 1229 // Do some timestamp voodoo 1230 if ( !empty( $content_struct['date_created_gmt'] ) ) { 1231 $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 1232 $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 1233 $comment_date_gmt = iso8601_to_datetime($dateCreated, GMT); 1234 } 1235 1236 if ( isset($content_struct['content']) ) 1237 $comment_content = $content_struct['content']; 1238 1239 if ( isset($content_struct['author']) ) 1240 $comment_author = $content_struct['author']; 1241 1242 if ( isset($content_struct['author_url']) ) 1243 $comment_author_url = $content_struct['author_url']; 1244 1245 if ( isset($content_struct['author_email']) ) 1246 $comment_author_email = $content_struct['author_email']; 1247 1248 // We've got all the data -- post it: 1249 $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url'); 1250 1251 $result = wp_update_comment($comment); 1252 if ( is_wp_error( $result ) ) 1253 return new IXR_Error(500, $result->get_error_message()); 1254 1255 if ( !$result ) 1256 return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.')); 1257 1258 return true; 1259 } 1260 1261 /** 1262 * Create new comment. 1263 * 1264 * @since 2.7.0 1265 * 1266 * @param array $args Method parameters. 1267 * @return mixed {@link wp_new_comment()} 1268 */ 1269 function wp_newComment($args) { 1270 global $wpdb; 1271 1272 $this->escape($args); 1273 1274 $blog_id = (int) $args[0]; 1275 $username = $args[1]; 1276 $password = $args[2]; 1277 $post = $args[3]; 1278 $content_struct = $args[4]; 1279 1280 $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false); 1281 1282 $user = $this->login($username, $password); 1283 1284 if ( !$user ) { 1285 $logged_in = false; 1286 if ( $allow_anon && get_option('comment_registration') ) 1287 return new IXR_Error( 403, __( 'You must be registered to comment' ) ); 1288 else if ( !$allow_anon ) 1289 return $this->error; 1290 } else { 1291 $logged_in = true; 1292 } 1293 1294 if ( is_numeric($post) ) 1295 $post_id = absint($post); 1296 else 1297 $post_id = url_to_postid($post); 1298 1299 if ( ! $post_id ) 1300 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 1301 1302 if ( ! get_post($post_id) ) 1303 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 1304 1305 $comment['comment_post_ID'] = $post_id; 1306 1307 if ( $logged_in ) { 1308 $comment['comment_author'] = $wpdb->escape( $user->display_name ); 1309 $comment['comment_author_email'] = $wpdb->escape( $user->user_email ); 1310 $comment['comment_author_url'] = $wpdb->escape( $user->user_url ); 1311 $comment['user_ID'] = $user->ID; 1312 } else { 1313 $comment['comment_author'] = ''; 1314 if ( isset($content_struct['author']) ) 1315 $comment['comment_author'] = $content_struct['author']; 1316 1317 $comment['comment_author_email'] = ''; 1318 if ( isset($content_struct['author_email']) ) 1319 $comment['comment_author_email'] = $content_struct['author_email']; 1320 1321 $comment['comment_author_url'] = ''; 1322 if ( isset($content_struct['author_url']) ) 1323 $comment['comment_author_url'] = $content_struct['author_url']; 1324 1325 $comment['user_ID'] = 0; 1326 1327 if ( get_option('require_name_email') ) { 1328 if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] ) 1329 return new IXR_Error( 403, __( 'Comment author name and email are required' ) ); 1330 elseif ( !is_email($comment['comment_author_email']) ) 1331 return new IXR_Error( 403, __( 'A valid email address is required' ) ); 1332 } 1333 } 1334 1335 $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0; 1336 1337 $comment['comment_content'] = $content_struct['content']; 1338 1339 do_action('xmlrpc_call', 'wp.newComment'); 1340 1341 return wp_new_comment($comment); 1342 } 1343 1344 /** 1345 * Retrieve all of the comment status. 1346 * 1347 * @since 2.7.0 1348 * 1349 * @param array $args Method parameters. 1350 * @return array 1351 */ 1352 function wp_getCommentStatusList($args) { 1353 $this->escape( $args ); 1354 1355 $blog_id = (int) $args[0]; 1356 $username = $args[1]; 1357 $password = $args[2]; 1358 1359 if ( !$user = $this->login($username, $password) ) { 1360 return $this->error; 1361 } 1362 1363 if ( !current_user_can( 'moderate_comments' ) ) 1364 return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); 1365 1366 do_action('xmlrpc_call', 'wp.getCommentStatusList'); 1367 1368 return get_comment_statuses( ); 1369 } 1370 1371 /** 1372 * Retrieve comment count. 1373 * 1374 * @since 2.5.0 1375 * 1376 * @param array $args Method parameters. 1377 * @return array 1378 */ 1379 function wp_getCommentCount( $args ) { 1380 $this->escape($args); 1381 1382 $blog_id = (int) $args[0]; 1383 $username = $args[1]; 1384 $password = $args[2]; 1385 $post_id = (int) $args[3]; 1386 1387 if ( !$user = $this->login($username, $password) ) { 1388 return $this->error; 1389 } 1390 1391 if( !current_user_can( 'edit_posts' ) ) { 1392 return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) ); 1393 } 1394 1395 do_action('xmlrpc_call', 'wp.getCommentCount'); 1396 1397 $count = wp_count_comments( $post_id ); 1398 return array( 1399 "approved" => $count->approved, 1400 "awaiting_moderation" => $count->moderated, 1401 "spam" => $count->spam, 1402 "total_comments" => $count->total_comments 1403 ); 1404 } 1405 1406 /** 1407 * Retrieve post statuses. 1408 * 1409 * @since 2.5.0 1410 * 1411 * @param array $args Method parameters. 1412 * @return array 1413 */ 1414 function wp_getPostStatusList( $args ) { 1415 $this->escape( $args ); 1416 1417 $blog_id = (int) $args[0]; 1418 $username = $args[1]; 1419 $password = $args[2]; 1420 1421 if ( !$user = $this->login($username, $password) ) { 1422 return $this->error; 1423 } 1424 1425 if( !current_user_can( 'edit_posts' ) ) { 1426 return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); 1427 } 1428 1429 do_action('xmlrpc_call', 'wp.getPostStatusList'); 1430 1431 return get_post_statuses( ); 1432 } 1433 1434 /** 1435 * Retrieve page statuses. 1436 * 1437 * @since 2.5.0 1438 * 1439 * @param array $args Method parameters. 1440 * @return array 1441 */ 1442 function wp_getPageStatusList( $args ) { 1443 $this->escape( $args ); 1444 1445 $blog_id = (int) $args[0]; 1446 $username = $args[1]; 1447 $password = $args[2]; 1448 1449 if ( !$user = $this->login($username, $password) ) { 1450 return $this->error; 1451 } 1452 1453 if( !current_user_can( 'edit_posts' ) ) { 1454 return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); 1455 } 1456 1457 do_action('xmlrpc_call', 'wp.getPageStatusList'); 1458 1459 return get_page_statuses( ); 1460 } 1461 1462 /** 1463 * Retrieve page templates. 1464 * 1465 * @since 2.6.0 1466 * 1467 * @param array $args Method parameters. 1468 * @return array 1469 */ 1470 function wp_getPageTemplates( $args ) { 1471 $this->escape( $args ); 1472 1473 $blog_id = (int) $args[0]; 1474 $username = $args[1]; 1475 $password = $args[2]; 1476 1477 if ( !$user = $this->login($username, $password) ) { 1478 return $this->error; 1479 } 1480 1481 if( !current_user_can( 'edit_pages' ) ) { 1482 return new IXR_Error( 403, __( 'You are not allowed access to details about this blog.' ) ); 1483 } 1484 1485 $templates = get_page_templates( ); 1486 $templates['Default'] = 'default'; 1487 1488 return $templates; 1489 } 1490 1491 /** 1492 * Retrieve blog options. 1493 * 1494 * @since 2.6.0 1495 * 1496 * @param array $args Method parameters. 1497 * @return array 1498 */ 1499 function wp_getOptions( $args ) { 1500 $this->escape( $args ); 1501 1502 $blog_id = (int) $args[0]; 1503 $username = $args[1]; 1504 $password = $args[2]; 1505 $options = (array) $args[3]; 1506 1507 if ( !$user = $this->login($username, $password) ) { 1508 return $this->error; 1509 } 1510 1511 // If no specific options where asked for, return all of them 1512 if (count( $options ) == 0 ) { 1513 $options = array_keys($this->blog_options); 1514 } 1515 1516 return $this->_getOptions($options); 1517 } 1518 1519 /** 1520 * Retrieve blog options value from list. 1521 * 1522 * @since 2.6.0 1523 * 1524 * @param array $options Options to retrieve. 1525 * @return array 1526 */ 1527 function _getOptions($options) 1528 { 1529 $data = array( ); 1530 foreach( $options as $option ) { 1531 if( array_key_exists( $option, $this->blog_options ) ) 1532 { 1533 $data[$option] = $this->blog_options[$option]; 1534 //Is the value static or dynamic? 1535 if( isset( $data[$option]['option'] ) ) { 1536 $data[$option]['value'] = get_option( $data[$option]['option'] ); 1537 unset($data[$option]['option']); 1538 } 1539 } 1540 } 1541 1542 return $data; 1543 } 1544 1545 /** 1546 * Update blog options. 1547 * 1548 * @since 2.6.0 1549 * 1550 * @param array $args Method parameters. 1551 * @return unknown 1552 */ 1553 function wp_setOptions( $args ) { 1554 $this->escape( $args ); 1555 1556 $blog_id = (int) $args[0]; 1557 $username = $args[1]; 1558 $password = $args[2]; 1559 $options = (array) $args[3]; 1560 1561 if ( !$user = $this->login($username, $password) ) { 1562 return $this->error; 1563 } 1564 1565 if( !current_user_can( 'manage_options' ) ) 1566 return new IXR_Error( 403, __( 'You are not allowed to update options.' ) ); 1567 1568 foreach( $options as $o_name => $o_value ) { 1569 $option_names[] = $o_name; 1570 if( !array_key_exists( $o_name, $this->blog_options ) ) 1571 continue; 1572 1573 if( $this->blog_options[$o_name]['readonly'] == true ) 1574 continue; 1575 1576 update_option( $this->blog_options[$o_name]['option'], $o_value ); 1577 } 1578 1579 //Now return the updated values 1580 return $this->_getOptions($option_names); 1581 } 1582 1583 /* Blogger API functions. 1584 * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/ 1585 */ 1586 1587 /** 1588 * Retrieve blogs that user owns. 1589 * 1590 * Will make more sense once we support multiple blogs. 1591 * 1592 * @since 1.5.0 1593 * 1594 * @param array $args Method parameters. 1595 * @return array 1596 */ 1597 function blogger_getUsersBlogs($args) { 1598 1599 $this->escape($args); 1600 1601 $username = $args[1]; 1602 $password = $args[2]; 1603 1604 if ( !$user = $this->login($username, $password) ) { 1605 return $this->error; 1606 } 1607 1608 do_action('xmlrpc_call', 'blogger.getUsersBlogs'); 1609 1610 $is_admin = current_user_can('manage_options'); 1611 1612 $struct = array( 1613 'isAdmin' => $is_admin, 1614 'url' => get_option('home') . '/', 1615 'blogid' => '1', 1616 'blogName' => get_option('blogname'), 1617 'xmlrpc' => site_url( 'xmlrpc.php' ) 1618 ); 1619 1620 return array($struct); 1621 } 1622 1623 /** 1624 * Retrieve user's data. 1625 * 1626 * Gives your client some info about you, so you don't have to. 1627 * 1628 * @since 1.5.0 1629 * 1630 * @param array $args Method parameters. 1631 * @return array 1632 */ 1633 function blogger_getUserInfo($args) { 1634 1635 $this->escape($args); 1636 1637 $username = $args[1]; 1638 $password = $args[2]; 1639 1640 if ( !$user = $this->login($username, $password) ) { 1641 return $this->error; 1642 } 1643 1644 if( !current_user_can( 'edit_posts' ) ) 1645 return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this blog.' ) ); 1646 1647 do_action('xmlrpc_call', 'blogger.getUserInfo'); 1648 1649 $struct = array( 1650 'nickname' => $user->nickname, 1651 'userid' => $user->ID, 1652 'url' => $user->user_url, 1653 'lastname' => $user->last_name, 1654 'firstname' => $user->first_name 1655 ); 1656 1657 return $struct; 1658 } 1659 1660 /** 1661 * Retrieve post. 1662 * 1663 * @since 1.5.0 1664 * 1665 * @param array $args Method parameters. 1666 * @return array 1667 */ 1668 function blogger_getPost($args) { 1669 1670 $this->escape($args); 1671 1672 $post_ID = (int) $args[1]; 1673 $username = $args[2]; 1674 $password = $args[3]; 1675 1676 if ( !$user = $this->login($username, $password) ) { 1677 return $this->error; 1678 } 1679 1680 if( !current_user_can( 'edit_post', $post_ID ) ) 1681 return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); 1682 1683 do_action('xmlrpc_call', 'blogger.getPost'); 1684 1685 $post_data = wp_get_single_post($post_ID, ARRAY_A); 1686 1687 $categories = implode(',', wp_get_post_categories($post_ID)); 1688 1689 $content = '<title>'.stripslashes($post_data['post_title']).'</title>'; 1690 $content .= '<category>'.$categories.'</category>'; 1691 $content .= stripslashes($post_data['post_content']); 1692 1693 $struct = array( 1694 'userid' => $post_data['post_author'], 1695 'dateCreated' => new IXR_Date(mysql2date('Ymd\TH:i:s', $post_data['post_date'], false)), 1696 'content' => $content, 1697 'postid' => $post_data['ID'] 1698 ); 1699 1700 return $struct; 1701 } 1702 1703 /** 1704 * Retrieve list of recent posts. 1705 * 1706 * @since 1.5.0 1707 * 1708 * @param array $args Method parameters. 1709 * @return array 1710 */ 1711 function blogger_getRecentPosts($args) { 1712 1713 $this->escape($args); 1714 1715 $blog_ID = (int) $args[1]; /* though we don't use it yet */ 1716 $username = $args[2]; 1717 $password = $args[3]; 1718 $num_posts = $args[4]; 1719 1720 if ( !$user = $this->login($username, $password) ) { 1721 return $this->error; 1722 } 1723 1724 do_action('xmlrpc_call', 'blogger.getRecentPosts'); 1725 1726 $posts_list = wp_get_recent_posts($num_posts); 1727 1728 if (!$posts_list) { 1729 $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.')); 1730 return $this->error; 1731 } 1732 1733 foreach ($posts_list as $entry) { 1734 if( !current_user_can( 'edit_post', $entry['ID'] ) ) 1735 continue; 1736 1737 $post_date = mysql2date('Ymd\TH:i:s', $entry['post_date'], false); 1738 $categories = implode(',', wp_get_post_categories($entry['ID'])); 1739 1740 $content = '<title>'.stripslashes($entry['post_title']).'</title>'; 1741 $content .= '<category>'.$categories.'</category>'; 1742 $content .= stripslashes($entry['post_content']); 1743 1744 $struct[] = array( 1745 'userid' => $entry['post_author'], 1746 'dateCreated' => new IXR_Date($post_date), 1747 'content' => $content, 1748 'postid' => $entry['ID'], 1749 ); 1750 1751 } 1752 1753 $recent_posts = array(); 1754 for ($j=0; $j<count($struct); $j++) { 1755 array_push($recent_posts, $struct[$j]); 1756 } 1757 1758 return $recent_posts; 1759 } 1760 1761 /** 1762 * Retrieve blog_filename content. 1763 * 1764 * @since 1.5.0 1765 * 1766 * @param array $args Method parameters. 1767 * @return string 1768 */ 1769 function blogger_getTemplate($args) { 1770 1771 $this->escape($args); 1772 1773 $blog_ID = (int) $args[1]; 1774 $username = $args[2]; 1775 $password = $args[3]; 1776 $template = $args[4]; /* could be 'main' or 'archiveIndex', but we don't use it */ 1777 1778 if ( !$user = $this->login($username, $password) ) { 1779 return $this->error; 1780 } 1781 1782 do_action('xmlrpc_call', 'blogger.getTemplate'); 1783 1784 if ( !current_user_can('edit_themes') ) { 1785 return new IXR_Error(401, __('Sorry, this user can not edit the template.')); 1786 } 1787 1788 /* warning: here we make the assumption that the blog's URL is on the same server */ 1789 $filename = get_option('home') . '/'; 1790 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 1791 1792 $f = fopen($filename, 'r'); 1793 $content = fread($f, filesize($filename)); 1794 fclose($f); 1795 1796 /* so it is actually editable with a windows/mac client */ 1797 // 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); 1798 1799 return $content; 1800 } 1801 1802 /** 1803 * Updates the content of blog_filename. 1804 * 1805 * @since 1.5.0 1806 * 1807 * @param array $args Method parameters. 1808 * @return bool True when done. 1809 */ 1810 function blogger_setTemplate($args) { 1811 1812 $this->escape($args); 1813 1814 $blog_ID = (int) $args[1]; 1815 $username = $args[2]; 1816 $password = $args[3]; 1817 $content = $args[4]; 1818 $template = $args[5]; /* could be 'main' or 'archiveIndex', but we don't use it */ 1819 1820 if ( !$user = $this->login($username, $password) ) { 1821 return $this->error; 1822 } 1823 1824 do_action('xmlrpc_call', 'blogger.setTemplate'); 1825 1826 if ( !current_user_can('edit_themes') ) { 1827 return new IXR_Error(401, __('Sorry, this user cannot edit the template.')); 1828 } 1829 1830 /* warning: here we make the assumption that the blog's URL is on the same server */ 1831 $filename = get_option('home') . '/'; 1832 $filename = preg_replace('#https?://.+?/#', $_SERVER['DOCUMENT_ROOT'].'/', $filename); 1833 1834 if ($f = fopen($filename, 'w+')) { 1835 fwrite($f, $content); 1836 fclose($f); 1837 } else { 1838 return new IXR_Error(500, __('Either the file is not writable, or something wrong happened. The file has not been updated.')); 1839 } 1840 1841 return true; 1842 } 1843 1844 /** 1845 * Create new post. 1846 * 1847 * @since 1.5.0 1848 * 1849 * @param array $args Method parameters. 1850 * @return int 1851 */ 1852 function blogger_newPost($args) { 1853 1854 $this->escape($args); 1855 1856 $blog_ID = (int) $args[1]; /* though we don't use it yet */ 1857 $username = $args[2]; 1858 $password = $args[3]; 1859 $content = $args[4]; 1860 $publish = $args[5]; 1861 1862 if ( !$user = $this->login($username, $password) ) { 1863 return $this->error; 1864 } 1865 1866 do_action('xmlrpc_call', 'blogger.newPost'); 1867 1868 $cap = ($publish) ? 'publish_posts' : 'edit_posts'; 1869 if ( !current_user_can($cap) ) 1870 return new IXR_Error(401, __('Sorry, you are not allowed to post on this blog.')); 1871 1872 $post_status = ($publish) ? 'publish' : 'draft'; 1873 1874 $post_author = $user->ID; 1875 1876 $post_title = xmlrpc_getposttitle($content); 1877 $post_category = xmlrpc_getpostcategory($content); 1878 $post_content = xmlrpc_removepostdata($content); 1879 1880 $post_date = current_time('mysql'); 1881 $post_date_gmt = current_time('mysql', 1); 1882 1883 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status'); 1884 1885 $post_ID = wp_insert_post($post_data); 1886 if ( is_wp_error( $post_ID ) ) 1887 return new IXR_Error(500, $post_ID->get_error_message()); 1888 1889 if (!$post_ID) 1890 return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); 1891 1892 $this->attach_uploads( $post_ID, $post_content ); 1893 1894 logIO('O', "Posted ! ID: $post_ID"); 1895 1896 return $post_ID; 1897 } 1898 1899 /** 1900 * Edit a post. 1901 * 1902 * @since 1.5.0 1903 * 1904 * @param array $args Method parameters. 1905 * @return bool true when done. 1906 */ 1907 function blogger_editPost($args) { 1908 1909 $this->escape($args); 1910 1911 $post_ID = (int) $args[1]; 1912 $username = $args[2]; 1913 $password = $args[3]; 1914 $content = $args[4]; 1915 $publish = $args[5]; 1916 1917 if ( !$user = $this->login($username, $password) ) { 1918 return $this->error; 1919 } 1920 1921 do_action('xmlrpc_call', 'blogger.editPost'); 1922 1923 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 1924 1925 if (!$actual_post || $actual_post['post_type'] != 'post') { 1926 return new IXR_Error(404, __('Sorry, no such post.')); 1927 } 1928 1929 $this->escape($actual_post); 1930 1931 if ( !current_user_can('edit_post', $post_ID) ) 1932 return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.')); 1933 1934 extract($actual_post, EXTR_SKIP); 1935 1936 if ( ('publish' == $post_status) && !current_user_can('publish_posts') ) 1937 return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); 1938 1939 $post_title = xmlrpc_getposttitle($content); 1940 $post_category = xmlrpc_getpostcategory($content); 1941 $post_content = xmlrpc_removepostdata($content); 1942 1943 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt'); 1944 1945 $result = wp_update_post($postdata); 1946 1947 if (!$result) { 1948 return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.')); 1949 } 1950 $this->attach_uploads( $ID, $post_content ); 1951 1952 return true; 1953 } 1954 1955 /** 1956 * Remove a post. 1957 * 1958 * @since 1.5.0 1959 * 1960 * @param array $args Method parameters. 1961 * @return bool True when post is deleted. 1962 */ 1963 function blogger_deletePost($args) { 1964 $this->escape($args); 1965 1966 $post_ID = (int) $args[1]; 1967 $username = $args[2]; 1968 $password = $args[3]; 1969 $publish = $args[4]; 1970 1971 if ( !$user = $this->login($username, $password) ) { 1972 return $this->error; 1973 } 1974 1975 do_action('xmlrpc_call', 'blogger.deletePost'); 1976 1977 $actual_post = wp_get_single_post($post_ID,ARRAY_A); 1978 1979 if (!$actual_post || $actual_post['post_type'] != 'post') { 1980 return new IXR_Error(404, __('Sorry, no such post.')); 1981 } 1982 1983 if ( !current_user_can('edit_post', $post_ID) ) 1984 return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.')); 1985 1986 $result = wp_delete_post($post_ID); 1987 1988 if (!$result) { 1989 return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.')); 1990 } 1991 1992 return true; 1993 } 1994 1995 /* MetaWeblog API functions 1996 * specs on wherever Dave Winer wants them to be 1997 */ 1998 1999 /** 2000 * Create a new post. 2001 * 2002 * @since 1.5.0 2003 * 2004 * @param array $args Method parameters. 2005 * @return int 2006 */ 2007 function mw_newPost($args) { 2008 $this->escape($args); 2009 2010 $blog_ID = (int) $args[0]; // we will support this in the near future 2011 $username = $args[1]; 2012 $password = $args[2]; 2013 $content_struct = $args[3]; 2014 $publish = $args[4]; 2015 2016 if ( !$user = $this->login($username, $password) ) { 2017 return $this->error; 2018 } 2019 2020 do_action('xmlrpc_call', 'metaWeblog.newPost'); 2021 2022 $cap = ( $publish ) ? 'publish_posts' : 'edit_posts'; 2023 $error_message = __( 'Sorry, you are not allowed to publish posts on this blog.' ); 2024 $post_type = 'post'; 2025 $page_template = ''; 2026 if( !empty( $content_struct['post_type'] ) ) { 2027 if( $content_struct['post_type'] == 'page' ) { 2028 $cap = ( $publish ) ? 'publish_pages' : 'edit_pages'; 2029 $error_message = __( 'Sorry, you are not allowed to publish pages on this blog.' ); 2030 $post_type = 'page'; 2031 if( !empty( $content_struct['wp_page_template'] ) ) 2032 $page_template = $content_struct['wp_page_template']; 2033 } 2034 elseif( $content_struct['post_type'] == 'post' ) { 2035 // This is the default, no changes needed 2036 } 2037 else { 2038 // No other post_type values are allowed here 2039 return new IXR_Error( 401, __( 'Invalid post type.' ) ); 2040 } 2041 } 2042 2043 if( !current_user_can( $cap ) ) { 2044 return new IXR_Error( 401, $error_message ); 2045 } 2046 2047 // Let WordPress generate the post_name (slug) unless 2048 // one has been provided. 2049 $post_name = ""; 2050 if(isset($content_struct["wp_slug"])) { 2051 $post_name = $content_struct["wp_slug"]; 2052 } 2053 2054 // Only use a password if one was given. 2055 if(isset($content_struct["wp_password"])) { 2056 $post_password = $content_struct["wp_password"]; 2057 } 2058 2059 // Only set a post parent if one was provided. 2060 if(isset($content_struct["wp_page_parent_id"])) { 2061 $post_parent = $content_struct["wp_page_parent_id"]; 2062 } 2063 2064 // Only set the menu_order if it was provided. 2065 if(isset($content_struct["wp_page_order"])) { 2066 $menu_order = $content_struct["wp_page_order"]; 2067 } 2068 2069 $post_author = $user->ID; 2070 2071 // If an author id was provided then use it instead. 2072 if( 2073 isset($content_struct["wp_author_id"]) 2074 && ($user->ID != $content_struct["wp_author_id"]) 2075 ) { 2076 switch($post_type) { 2077 case "post": 2078 if(!current_user_can("edit_others_posts")) { 2079 return(new IXR_Error(401, __("You are not allowed to post as this user"))); 2080 } 2081 break; 2082 case "page": 2083 if(!current_user_can("edit_others_pages")) { 2084 return(new IXR_Error(401, __("You are not allowed to create pages as this user"))); 2085 } 2086 break; 2087 default: 2088 return(new IXR_Error(401, __("Invalid post type."))); 2089 break; 2090 } 2091 $post_author = $content_struct["wp_author_id"]; 2092 } 2093 2094 $post_title = $content_struct['title']; 2095 $post_content = $content_struct['description']; 2096 2097 $post_status = $publish ? 'publish' : 'draft'; 2098 2099 if( isset( $content_struct["{$post_type}_status"] ) ) { 2100 switch( $content_struct["{$post_type}_status"] ) { 2101 case 'draft': 2102 case 'private': 2103 case 'publish': 2104 $post_status = $content_struct["{$post_type}_status"]; 2105 break; 2106 case 'pending': 2107 // Pending is only valid for posts, not pages. 2108 if( $post_type === 'post' ) { 2109 $post_status = $content_struct["{$post_type}_status"]; 2110 } 2111 break; 2112 default: 2113 $post_status = $publish ? 'publish' : 'draft'; 2114 break; 2115 } 2116 } 2117 2118 $post_excerpt = $content_struct['mt_excerpt']; 2119 $post_more = $content_struct['mt_text_more']; 2120 2121 $tags_input = $content_struct['mt_keywords']; 2122 2123 if(isset($content_struct["mt_allow_comments"])) { 2124 if(!is_numeric($content_struct["mt_allow_comments"])) { 2125 switch($content_struct["mt_allow_comments"]) { 2126 case "closed": 2127 $comment_status = "closed"; 2128 break; 2129 case "open": 2130 $comment_status = "open"; 2131 break; 2132 default: 2133 $comment_status = get_option("default_comment_status"); 2134 break; 2135 } 2136 } 2137 else { 2138 switch((int) $content_struct["mt_allow_comments"]) { 2139 case 0: 2140 case 2: 2141 $comment_status = "closed"; 2142 break; 2143 case 1: 2144 $comment_status = "open"; 2145 break; 2146 default: 2147 $comment_status = get_option("default_comment_status"); 2148 break; 2149 } 2150 } 2151 } 2152 else { 2153 $comment_status = get_option("default_comment_status"); 2154 } 2155 2156 if(isset($content_struct["mt_allow_pings"])) { 2157 if(!is_numeric($content_struct["mt_allow_pings"])) { 2158 switch($content_struct['mt_allow_pings']) { 2159 case "closed": 2160 $ping_status = "closed"; 2161 break; 2162 case "open": 2163 $ping_status = "open"; 2164 break; 2165 default: 2166 $ping_status = get_option("default_ping_status"); 2167 break; 2168 } 2169 } 2170 else { 2171 switch((int) $content_struct["mt_allow_pings"]) { 2172 case 0: 2173 $ping_status = "closed"; 2174 break; 2175 case 1: 2176 $ping_status = "open"; 2177 break; 2178 default: 2179 $ping_status = get_option("default_ping_status"); 2180 break; 2181 } 2182 } 2183 } 2184 else { 2185 $ping_status = get_option("default_ping_status"); 2186 } 2187 2188 if ($post_more) { 2189 $post_content = $post_content . "<!--more-->" . $post_more; 2190 } 2191 2192 $to_ping = $content_struct['mt_tb_ping_urls']; 2193 if ( is_array($to_ping) ) 2194 $to_ping = implode(' ', $to_ping); 2195 2196 // Do some timestamp voodoo 2197 if ( !empty( $content_struct['date_created_gmt'] ) ) 2198 $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 2199 elseif ( !empty( $content_struct['dateCreated']) ) 2200 $dateCreated = $content_struct['dateCreated']->getIso(); 2201 2202 if ( !empty( $dateCreated ) ) { 2203 $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 2204 $post_date_gmt = iso8601_to_datetime($dateCreated, GMT); 2205 } else { 2206 $post_date = current_time('mysql'); 2207 $post_date_gmt = current_time('mysql', 1); 2208 } 2209 2210 $catnames = $content_struct['categories']; 2211 logIO('O', 'Post cats: ' . var_export($catnames,true)); 2212 $post_category = array(); 2213 2214 if (is_array($catnames)) { 2215 foreach ($catnames as $cat) { 2216 $post_category[] = get_cat_ID($cat); 2217 } 2218 } 2219 2220 // We've got all the data -- post it: 2221 $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'); 2222 2223 $post_ID = wp_insert_post($postdata, true); 2224 if ( is_wp_error( $post_ID ) ) 2225 return new IXR_Error(500, $post_ID->get_error_message()); 2226 2227 if (!$post_ID) { 2228 return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); 2229 } 2230 2231 // Only posts can be sticky 2232 if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) 2233 if ( $content_struct['sticky'] == true ) 2234 stick_post( $post_ID ); 2235 elseif ( $content_struct['sticky'] == false ) 2236 unstick_post( $post_ID ); 2237 2238 if ( isset($content_struct['custom_fields']) ) { 2239 $this->set_custom_fields($post_ID, $content_struct['custom_fields']); 2240 } 2241 2242 // Handle enclosures 2243 $this->add_enclosure_if_new($post_ID, $content_struct['enclosure']); 2244 2245 $this->attach_uploads( $post_ID, $post_content ); 2246 2247 logIO('O', "Posted ! ID: $post_ID"); 2248 2249 return strval($post_ID); 2250 } 2251 2252 function add_enclosure_if_new($post_ID, $enclosure) { 2253 if( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) { 2254 2255 $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type']; 2256 $found = false; 2257 foreach ( (array) get_post_custom($post_ID) as $key => $val) { 2258 if ($key == 'enclosure') { 2259 foreach ( (array) $val as $enc ) { 2260 if ($enc == $encstring) { 2261 $found = true; 2262 break 2; 2263 } 2264 } 2265 } 2266 } 2267 if (!$found) { 2268 add_post_meta( $post_ID, 'enclosure', $encstring ); 2269 } 2270 } 2271 } 2272 2273 /** 2274 * Attach upload to a post. 2275 * 2276 * @since 2.1.0 2277 * 2278 * @param int $post_ID Post ID. 2279 * @param string $post_content Post Content for attachment. 2280 */ 2281 function attach_uploads( $post_ID, $post_content ) { 2282 global $wpdb; 2283 2284 // find any unattached files 2285 $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" ); 2286 if( is_array( $attachments ) ) { 2287 foreach( $attachments as $file ) { 2288 if( strpos( $post_content, $file->guid ) !== false ) { 2289 $wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) ); 2290 } 2291 } 2292 } 2293 } 2294 2295 /** 2296 * Edit a post. 2297 * 2298 * @since 1.5.0 2299 * 2300 * @param array $args Method parameters. 2301 * @return bool True on success. 2302 */ 2303 function mw_editPost($args) { 2304 2305 $this->escape($args); 2306 2307 $post_ID = (int) $args[0]; 2308 $username = $args[1]; 2309 $password = $args[2]; 2310 $content_struct = $args[3]; 2311 $publish = $args[4]; 2312 2313 if ( !$user = $this->login($username, $password) ) { 2314 return $this->error; 2315 } 2316 2317 do_action('xmlrpc_call', 'metaWeblog.editPost'); 2318 2319 $cap = ( $publish ) ? 'publish_posts' : 'edit_posts'; 2320 $error_message = __( 'Sorry, you are not allowed to publish posts on this blog.' ); 2321 $post_type = 'post'; 2322 $page_template = ''; 2323 if( !empty( $content_struct['post_type'] ) ) { 2324 if( $content_struct['post_type'] == 'page' ) { 2325 $cap = ( $publish ) ? 'publish_pages' : 'edit_pages'; 2326 $error_message = __( 'Sorry, you are not allowed to publish pages on this blog.' ); 2327 $post_type = 'page'; 2328 if( !empty( $content_struct['wp_page_template'] ) ) 2329 $page_template = $content_struct['wp_page_template']; 2330 } 2331 elseif( $content_struct['post_type'] == 'post' ) { 2332 // This is the default, no changes needed 2333 } 2334 else { 2335 // No other post_type values are allowed here 2336 return new IXR_Error( 401, __( 'Invalid post type.' ) ); 2337 } 2338 } 2339 2340 if( !current_user_can( $cap ) ) { 2341 return new IXR_Error( 401, $error_message ); 2342 } 2343 2344 $postdata = wp_get_single_post($post_ID, ARRAY_A); 2345 2346 // If there is no post data for the give post id, stop 2347 // now and return an error. Other wise a new post will be 2348 // created (which was the old behavior). 2349 if(empty($postdata["ID"])) { 2350 return(new IXR_Error(404, __("Invalid post ID."))); 2351 } 2352 2353 $this->escape($postdata); 2354 extract($postdata, EXTR_SKIP); 2355 2356 // Let WordPress manage slug if none was provided. 2357 $post_name = ""; 2358 if(isset($content_struct["wp_slug"])) { 2359 $post_name = $content_struct["wp_slug"]; 2360 } 2361 2362 // Only use a password if one was given. 2363 if(isset($content_struct["wp_password"])) { 2364 $post_password = $content_struct["wp_password"]; 2365 } 2366 2367 // Only set a post parent if one was given. 2368 if(isset($content_struct["wp_page_parent_id"])) { 2369 $post_parent = $content_struct["wp_page_parent_id"]; 2370 } 2371 2372