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