[ Index ] |
WordPress Cross Reference |
[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 compatibility for Blogger API, MetaWeblog API, MovableType, and 12 * pingback. Additional WordPress API for managing comments, pages, posts, 13 * options, etc. 14 * 15 * As of WordPress 3.5.0, XML-RPC is enabled by default. It can be disabled 16 * via the xmlrpc_enabled filter found in wp_xmlrpc_server::login(). 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.newPost' => 'this:wp_newPost', 40 'wp.editPost' => 'this:wp_editPost', 41 'wp.deletePost' => 'this:wp_deletePost', 42 'wp.getPost' => 'this:wp_getPost', 43 'wp.getPosts' => 'this:wp_getPosts', 44 'wp.newTerm' => 'this:wp_newTerm', 45 'wp.editTerm' => 'this:wp_editTerm', 46 'wp.deleteTerm' => 'this:wp_deleteTerm', 47 'wp.getTerm' => 'this:wp_getTerm', 48 'wp.getTerms' => 'this:wp_getTerms', 49 'wp.getTaxonomy' => 'this:wp_getTaxonomy', 50 'wp.getTaxonomies' => 'this:wp_getTaxonomies', 51 'wp.getUser' => 'this:wp_getUser', 52 'wp.getUsers' => 'this:wp_getUsers', 53 'wp.getProfile' => 'this:wp_getProfile', 54 'wp.editProfile' => 'this:wp_editProfile', 55 'wp.getPage' => 'this:wp_getPage', 56 'wp.getPages' => 'this:wp_getPages', 57 'wp.newPage' => 'this:wp_newPage', 58 'wp.deletePage' => 'this:wp_deletePage', 59 'wp.editPage' => 'this:wp_editPage', 60 'wp.getPageList' => 'this:wp_getPageList', 61 'wp.getAuthors' => 'this:wp_getAuthors', 62 'wp.getCategories' => 'this:mw_getCategories', // Alias 63 'wp.getTags' => 'this:wp_getTags', 64 'wp.newCategory' => 'this:wp_newCategory', 65 'wp.deleteCategory' => 'this:wp_deleteCategory', 66 'wp.suggestCategories' => 'this:wp_suggestCategories', 67 'wp.uploadFile' => 'this:mw_newMediaObject', // Alias 68 'wp.getCommentCount' => 'this:wp_getCommentCount', 69 'wp.getPostStatusList' => 'this:wp_getPostStatusList', 70 'wp.getPageStatusList' => 'this:wp_getPageStatusList', 71 'wp.getPageTemplates' => 'this:wp_getPageTemplates', 72 'wp.getOptions' => 'this:wp_getOptions', 73 'wp.setOptions' => 'this:wp_setOptions', 74 'wp.getComment' => 'this:wp_getComment', 75 'wp.getComments' => 'this:wp_getComments', 76 'wp.deleteComment' => 'this:wp_deleteComment', 77 'wp.editComment' => 'this:wp_editComment', 78 'wp.newComment' => 'this:wp_newComment', 79 'wp.getCommentStatusList' => 'this:wp_getCommentStatusList', 80 'wp.getMediaItem' => 'this:wp_getMediaItem', 81 'wp.getMediaLibrary' => 'this:wp_getMediaLibrary', 82 'wp.getPostFormats' => 'this:wp_getPostFormats', 83 'wp.getPostType' => 'this:wp_getPostType', 84 'wp.getPostTypes' => 'this:wp_getPostTypes', 85 'wp.getRevisions' => 'this:wp_getRevisions', 86 'wp.restoreRevision' => 'this:wp_restoreRevision', 87 88 // Blogger API 89 'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs', 90 'blogger.getUserInfo' => 'this:blogger_getUserInfo', 91 'blogger.getPost' => 'this:blogger_getPost', 92 'blogger.getRecentPosts' => 'this:blogger_getRecentPosts', 93 'blogger.newPost' => 'this:blogger_newPost', 94 'blogger.editPost' => 'this:blogger_editPost', 95 'blogger.deletePost' => 'this:blogger_deletePost', 96 97 // MetaWeblog API (with MT extensions to structs) 98 'metaWeblog.newPost' => 'this:mw_newPost', 99 'metaWeblog.editPost' => 'this:mw_editPost', 100 'metaWeblog.getPost' => 'this:mw_getPost', 101 'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts', 102 'metaWeblog.getCategories' => 'this:mw_getCategories', 103 'metaWeblog.newMediaObject' => 'this:mw_newMediaObject', 104 105 // MetaWeblog API aliases for Blogger API 106 // see http://www.xmlrpc.com/stories/storyReader$2460 107 'metaWeblog.deletePost' => 'this:blogger_deletePost', 108 'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs', 109 110 // MovableType API 111 'mt.getCategoryList' => 'this:mt_getCategoryList', 112 'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles', 113 'mt.getPostCategories' => 'this:mt_getPostCategories', 114 'mt.setPostCategories' => 'this:mt_setPostCategories', 115 'mt.supportedMethods' => 'this:mt_supportedMethods', 116 'mt.supportedTextFilters' => 'this:mt_supportedTextFilters', 117 'mt.getTrackbackPings' => 'this:mt_getTrackbackPings', 118 'mt.publishPost' => 'this:mt_publishPost', 119 120 // PingBack 121 'pingback.ping' => 'this:pingback_ping', 122 'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks', 123 124 'demo.sayHello' => 'this:sayHello', 125 'demo.addTwoNumbers' => 'this:addTwoNumbers' 126 ); 127 128 $this->initialise_blog_option_info(); 129 $this->methods = apply_filters('xmlrpc_methods', $this->methods); 130 } 131 132 function serve_request() { 133 $this->IXR_Server($this->methods); 134 } 135 136 /** 137 * Test XMLRPC API by saying, "Hello!" to client. 138 * 139 * @since 1.5.0 140 * 141 * @param array $args Method Parameters. 142 * @return string 143 */ 144 function sayHello($args) { 145 return 'Hello!'; 146 } 147 148 /** 149 * Test XMLRPC API by adding two numbers for client. 150 * 151 * @since 1.5.0 152 * 153 * @param array $args Method Parameters. 154 * @return int 155 */ 156 function addTwoNumbers($args) { 157 $number1 = $args[0]; 158 $number2 = $args[1]; 159 return $number1 + $number2; 160 } 161 162 /** 163 * Log user in. 164 * 165 * @since 2.8.0 166 * 167 * @param string $username User's username. 168 * @param string $password User's password. 169 * @return mixed WP_User object if authentication passed, false otherwise 170 */ 171 function login( $username, $password ) { 172 // Respect any old filters against get_option() for 'enable_xmlrpc'. 173 $enabled = apply_filters( 'pre_option_enable_xmlrpc', false ); // Deprecated 174 if ( false === $enabled ) 175 $enabled = apply_filters( 'option_enable_xmlrpc', true ); // Deprecated 176 177 // Proper filter for turning off XML-RPC. It is on by default. 178 $enabled = apply_filters( 'xmlrpc_enabled', $enabled ); 179 180 if ( ! $enabled ) { 181 $this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.' ) ) ); 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, __( 'Incorrect username or password.' ) ); 189 $this->error = apply_filters( 'xmlrpc_login_error', $this->error, $user ); 190 return false; 191 } 192 193 wp_set_current_user( $user->ID ); 194 return $user; 195 } 196 197 /** 198 * Check user's credentials. Deprecated. 199 * 200 * @since 1.5.0 201 * @deprecated 2.8.0 202 * @deprecated use wp_xmlrpc_server::login 203 * @see wp_xmlrpc_server::login 204 * 205 * @param string $username User's username. 206 * @param string $password User's password. 207 * @return bool Whether authentication passed. 208 */ 209 function login_pass_ok( $username, $password ) { 210 return (bool) $this->login( $username, $password ); 211 } 212 213 /** 214 * Escape string or array of strings for database. 215 * 216 * @since 1.5.2 217 * 218 * @param string|array $data Escape single string or array of strings. 219 * @return string|array Type matches $data and sanitized for the database. 220 */ 221 function escape( &$data ) { 222 if ( ! is_array( $data ) ) 223 return wp_slash( $data ); 224 225 foreach ( $data as &$v ) { 226 if ( is_array( $v ) ) 227 $this->escape( $v ); 228 elseif ( ! is_object( $v ) ) 229 $v = wp_slash( $v ); 230 } 231 } 232 233 /** 234 * Retrieve custom fields for post. 235 * 236 * @since 2.5.0 237 * 238 * @param int $post_id Post ID. 239 * @return array Custom fields, if exist. 240 */ 241 function get_custom_fields($post_id) { 242 $post_id = (int) $post_id; 243 244 $custom_fields = array(); 245 246 foreach ( (array) has_meta($post_id) as $meta ) { 247 // Don't expose protected fields. 248 if ( ! current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) ) 249 continue; 250 251 $custom_fields[] = array( 252 "id" => $meta['meta_id'], 253 "key" => $meta['meta_key'], 254 "value" => $meta['meta_value'] 255 ); 256 } 257 258 return $custom_fields; 259 } 260 261 /** 262 * Set custom fields for post. 263 * 264 * @since 2.5.0 265 * 266 * @param int $post_id Post ID. 267 * @param array $fields Custom fields. 268 */ 269 function set_custom_fields($post_id, $fields) { 270 $post_id = (int) $post_id; 271 272 foreach ( (array) $fields as $meta ) { 273 if ( isset($meta['id']) ) { 274 $meta['id'] = (int) $meta['id']; 275 $pmeta = get_metadata_by_mid( 'post', $meta['id'] ); 276 if ( isset($meta['key']) ) { 277 $meta['key'] = wp_unslash( $meta['key'] ); 278 if ( $meta['key'] !== $pmeta->meta_key ) 279 continue; 280 $meta['value'] = wp_unslash( $meta['value'] ); 281 if ( current_user_can( 'edit_post_meta', $post_id, $meta['key'] ) ) 282 update_metadata_by_mid( 'post', $meta['id'], $meta['value'] ); 283 } elseif ( current_user_can( 'delete_post_meta', $post_id, $pmeta->meta_key ) ) { 284 delete_metadata_by_mid( 'post', $meta['id'] ); 285 } 286 } elseif ( current_user_can( 'add_post_meta', $post_id, wp_unslash( $meta['key'] ) ) ) { 287 add_post_meta( $post_id, $meta['key'], $meta['value'] ); 288 } 289 } 290 } 291 292 /** 293 * Set up blog options property. 294 * 295 * Passes property through 'xmlrpc_blog_options' filter. 296 * 297 * @since 2.6.0 298 */ 299 function initialise_blog_option_info() { 300 global $wp_version; 301 302 $this->blog_options = array( 303 // Read only options 304 'software_name' => array( 305 'desc' => __( 'Software Name' ), 306 'readonly' => true, 307 'value' => 'WordPress' 308 ), 309 'software_version' => array( 310 'desc' => __( 'Software Version' ), 311 'readonly' => true, 312 'value' => $wp_version 313 ), 314 'blog_url' => array( 315 'desc' => __( 'WordPress Address (URL)' ), 316 'readonly' => true, 317 'option' => 'siteurl' 318 ), 319 'home_url' => array( 320 'desc' => __( 'Site Address (URL)' ), 321 'readonly' => true, 322 'option' => 'home' 323 ), 324 'login_url' => array( 325 'desc' => __( 'Login Address (URL)' ), 326 'readonly' => true, 327 'value' => wp_login_url( ) 328 ), 329 'admin_url' => array( 330 'desc' => __( 'The URL to the admin area' ), 331 'readonly' => true, 332 'value' => get_admin_url( ) 333 ), 334 'image_default_link_type' => array( 335 'desc' => __( 'Image default link type' ), 336 'readonly' => true, 337 'option' => 'image_default_link_type' 338 ), 339 'image_default_size' => array( 340 'desc' => __( 'Image default size' ), 341 'readonly' => true, 342 'option' => 'image_default_size' 343 ), 344 'image_default_align' => array( 345 'desc' => __( 'Image default align' ), 346 'readonly' => true, 347 'option' => 'image_default_align' 348 ), 349 'template' => array( 350 'desc' => __( 'Template' ), 351 'readonly' => true, 352 'option' => 'template' 353 ), 354 'stylesheet' => array( 355 'desc' => __( 'Stylesheet' ), 356 'readonly' => true, 357 'option' => 'stylesheet' 358 ), 359 'post_thumbnail' => array( 360 'desc' => __('Post Thumbnail'), 361 'readonly' => true, 362 'value' => current_theme_supports( 'post-thumbnails' ) 363 ), 364 365 // Updatable options 366 'time_zone' => array( 367 'desc' => __( 'Time Zone' ), 368 'readonly' => false, 369 'option' => 'gmt_offset' 370 ), 371 'blog_title' => array( 372 'desc' => __( 'Site Title' ), 373 'readonly' => false, 374 'option' => 'blogname' 375 ), 376 'blog_tagline' => array( 377 'desc' => __( 'Site Tagline' ), 378 'readonly' => false, 379 'option' => 'blogdescription' 380 ), 381 'date_format' => array( 382 'desc' => __( 'Date Format' ), 383 'readonly' => false, 384 'option' => 'date_format' 385 ), 386 'time_format' => array( 387 'desc' => __( 'Time Format' ), 388 'readonly' => false, 389 'option' => 'time_format' 390 ), 391 'users_can_register' => array( 392 'desc' => __( 'Allow new users to sign up' ), 393 'readonly' => false, 394 'option' => 'users_can_register' 395 ), 396 'thumbnail_size_w' => array( 397 'desc' => __( 'Thumbnail Width' ), 398 'readonly' => false, 399 'option' => 'thumbnail_size_w' 400 ), 401 'thumbnail_size_h' => array( 402 'desc' => __( 'Thumbnail Height' ), 403 'readonly' => false, 404 'option' => 'thumbnail_size_h' 405 ), 406 'thumbnail_crop' => array( 407 'desc' => __( 'Crop thumbnail to exact dimensions' ), 408 'readonly' => false, 409 'option' => 'thumbnail_crop' 410 ), 411 'medium_size_w' => array( 412 'desc' => __( 'Medium size image width' ), 413 'readonly' => false, 414 'option' => 'medium_size_w' 415 ), 416 'medium_size_h' => array( 417 'desc' => __( 'Medium size image height' ), 418 'readonly' => false, 419 'option' => 'medium_size_h' 420 ), 421 'large_size_w' => array( 422 'desc' => __( 'Large size image width' ), 423 'readonly' => false, 424 'option' => 'large_size_w' 425 ), 426 'large_size_h' => array( 427 'desc' => __( 'Large size image height' ), 428 'readonly' => false, 429 'option' => 'large_size_h' 430 ), 431 'default_comment_status' => array( 432 'desc' => __( 'Allow people to post comments on new articles' ), 433 'readonly' => false, 434 'option' => 'default_comment_status' 435 ), 436 'default_ping_status' => array( 437 'desc' => __( 'Allow link notifications from other blogs (pingbacks and trackbacks)' ), 438 'readonly' => false, 439 'option' => 'default_ping_status' 440 ) 441 ); 442 443 $this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options ); 444 } 445 446 /** 447 * Retrieve the blogs of the user. 448 * 449 * @since 2.6.0 450 * 451 * @param array $args Method parameters. Contains: 452 * - username 453 * - password 454 * @return array. Contains: 455 * - 'isAdmin' 456 * - 'url' 457 * - 'blogid' 458 * - 'blogName' 459 * - 'xmlrpc' - url of xmlrpc endpoint 460 */ 461 function wp_getUsersBlogs( $args ) { 462 // If this isn't on WPMU then just use blogger_getUsersBlogs 463 if ( !is_multisite() ) { 464 array_unshift( $args, 1 ); 465 return $this->blogger_getUsersBlogs( $args ); 466 } 467 468 $this->escape( $args ); 469 470 $username = $args[0]; 471 $password = $args[1]; 472 473 if ( !$user = $this->login($username, $password) ) 474 return $this->error; 475 476 do_action( 'xmlrpc_call', 'wp.getUsersBlogs' ); 477 478 $blogs = (array) get_blogs_of_user( $user->ID ); 479 $struct = array(); 480 481 foreach ( $blogs as $blog ) { 482 // Don't include blogs that aren't hosted at this site 483 if ( $blog->site_id != get_current_site()->id ) 484 continue; 485 486 $blog_id = $blog->userblog_id; 487 488 switch_to_blog( $blog_id ); 489 490 $is_admin = current_user_can( 'manage_options' ); 491 492 $struct[] = array( 493 'isAdmin' => $is_admin, 494 'url' => home_url( '/' ), 495 'blogid' => (string) $blog_id, 496 'blogName' => get_option( 'blogname' ), 497 'xmlrpc' => site_url( 'xmlrpc.php', 'rpc' ), 498 ); 499 500 restore_current_blog(); 501 } 502 503 return $struct; 504 } 505 506 /** 507 * Checks if the method received at least the minimum number of arguments. 508 * 509 * @since 3.4.0 510 * 511 * @param string|array $args Sanitize single string or array of strings. 512 * @param int $count Minimum number of arguments. 513 * @return boolean if $args contains at least $count arguments. 514 */ 515 protected function minimum_args( $args, $count ) { 516 if ( count( $args ) < $count ) { 517 $this->error = new IXR_Error( 400, __( 'Insufficient arguments passed to this XML-RPC method.' ) ); 518 return false; 519 } 520 521 return true; 522 } 523 524 /** 525 * Prepares taxonomy data for return in an XML-RPC object. 526 * 527 * @access protected 528 * 529 * @param object $taxonomy The unprepared taxonomy data 530 * @param array $fields The subset of taxonomy fields to return 531 * @return array The prepared taxonomy data 532 */ 533 protected function _prepare_taxonomy( $taxonomy, $fields ) { 534 $_taxonomy = array( 535 'name' => $taxonomy->name, 536 'label' => $taxonomy->label, 537 'hierarchical' => (bool) $taxonomy->hierarchical, 538 'public' => (bool) $taxonomy->public, 539 'show_ui' => (bool) $taxonomy->show_ui, 540 '_builtin' => (bool) $taxonomy->_builtin, 541 ); 542 543 if ( in_array( 'labels', $fields ) ) 544 $_taxonomy['labels'] = (array) $taxonomy->labels; 545 546 if ( in_array( 'cap', $fields ) ) 547 $_taxonomy['cap'] = (array) $taxonomy->cap; 548 549 if ( in_array( 'menu', $fields ) ) 550 $_taxonomy['show_in_menu'] = (bool) $_taxonomy->show_in_menu; 551 552 if ( in_array( 'object_type', $fields ) ) 553 $_taxonomy['object_type'] = array_unique( (array) $taxonomy->object_type ); 554 555 return apply_filters( 'xmlrpc_prepare_taxonomy', $_taxonomy, $taxonomy, $fields ); 556 } 557 558 /** 559 * Prepares term data for return in an XML-RPC object. 560 * 561 * @access protected 562 * 563 * @param array|object $term The unprepared term data 564 * @return array The prepared term data 565 */ 566 protected function _prepare_term( $term ) { 567 $_term = $term; 568 if ( ! is_array( $_term) ) 569 $_term = get_object_vars( $_term ); 570 571 // For integers which may be larger than XML-RPC supports ensure we return strings. 572 $_term['term_id'] = strval( $_term['term_id'] ); 573 $_term['term_group'] = strval( $_term['term_group'] ); 574 $_term['term_taxonomy_id'] = strval( $_term['term_taxonomy_id'] ); 575 $_term['parent'] = strval( $_term['parent'] ); 576 577 // Count we are happy to return as an integer because people really shouldn't use terms that much. 578 $_term['count'] = intval( $_term['count'] ); 579 580 return apply_filters( 'xmlrpc_prepare_term', $_term, $term ); 581 } 582 583 /** 584 * Convert a WordPress date string to an IXR_Date object. 585 * 586 * @access protected 587 * 588 * @param string $date 589 * @return IXR_Date 590 */ 591 protected function _convert_date( $date ) { 592 if ( $date === '0000-00-00 00:00:00' ) { 593 return new IXR_Date( '00000000T00:00:00Z' ); 594 } 595 return new IXR_Date( mysql2date( 'Ymd\TH:i:s', $date, false ) ); 596 } 597 598 /** 599 * Convert a WordPress GMT date string to an IXR_Date object. 600 * 601 * @access protected 602 * 603 * @param string $date_gmt 604 * @param string $date 605 * @return IXR_Date 606 */ 607 protected function _convert_date_gmt( $date_gmt, $date ) { 608 if ( $date !== '0000-00-00 00:00:00' && $date_gmt === '0000-00-00 00:00:00' ) { 609 return new IXR_Date( get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $date, false ), 'Ymd\TH:i:s' ) ); 610 } 611 return $this->_convert_date( $date_gmt ); 612 } 613 614 /** 615 * Prepares post data for return in an XML-RPC object. 616 * 617 * @access protected 618 * 619 * @param array $post The unprepared post data 620 * @param array $fields The subset of post type fields to return 621 * @return array The prepared post data 622 */ 623 protected function _prepare_post( $post, $fields ) { 624 // holds the data for this post. built up based on $fields 625 $_post = array( 'post_id' => strval( $post['ID'] ) ); 626 627 // prepare common post fields 628 $post_fields = array( 629 'post_title' => $post['post_title'], 630 'post_date' => $this->_convert_date( $post['post_date'] ), 631 'post_date_gmt' => $this->_convert_date_gmt( $post['post_date_gmt'], $post['post_date'] ), 632 'post_modified' => $this->_convert_date( $post['post_modified'] ), 633 'post_modified_gmt' => $this->_convert_date_gmt( $post['post_modified_gmt'], $post['post_modified'] ), 634 'post_status' => $post['post_status'], 635 'post_type' => $post['post_type'], 636 'post_name' => $post['post_name'], 637 'post_author' => $post['post_author'], 638 'post_password' => $post['post_password'], 639 'post_excerpt' => $post['post_excerpt'], 640 'post_content' => $post['post_content'], 641 'post_parent' => strval( $post['post_parent'] ), 642 'post_mime_type' => $post['post_mime_type'], 643 'link' => post_permalink( $post['ID'] ), 644 'guid' => $post['guid'], 645 'menu_order' => intval( $post['menu_order'] ), 646 'comment_status' => $post['comment_status'], 647 'ping_status' => $post['ping_status'], 648 'sticky' => ( $post['post_type'] === 'post' && is_sticky( $post['ID'] ) ), 649 ); 650 651 // Thumbnail 652 $post_fields['post_thumbnail'] = array(); 653 $thumbnail_id = get_post_thumbnail_id( $post['ID'] ); 654 if ( $thumbnail_id ) { 655 $thumbnail_size = current_theme_supports('post-thumbnail') ? 'post-thumbnail' : 'thumbnail'; 656 $post_fields['post_thumbnail'] = $this->_prepare_media_item( get_post( $thumbnail_id ), $thumbnail_size ); 657 } 658 659 // Consider future posts as published 660 if ( $post_fields['post_status'] === 'future' ) 661 $post_fields['post_status'] = 'publish'; 662 663 // Fill in blank post format 664 $post_fields['post_format'] = get_post_format( $post['ID'] ); 665 if ( empty( $post_fields['post_format'] ) ) 666 $post_fields['post_format'] = 'standard'; 667 668 // Merge requested $post_fields fields into $_post 669 if ( in_array( 'post', $fields ) ) { 670 $_post = array_merge( $_post, $post_fields ); 671 } else { 672 $requested_fields = array_intersect_key( $post_fields, array_flip( $fields ) ); 673 $_post = array_merge( $_post, $requested_fields ); 674 } 675 676 $all_taxonomy_fields = in_array( 'taxonomies', $fields ); 677 678 if ( $all_taxonomy_fields || in_array( 'terms', $fields ) ) { 679 $post_type_taxonomies = get_object_taxonomies( $post['post_type'], 'names' ); 680 $terms = wp_get_object_terms( $post['ID'], $post_type_taxonomies ); 681 $_post['terms'] = array(); 682 foreach ( $terms as $term ) { 683 $_post['terms'][] = $this->_prepare_term( $term ); 684 } 685 } 686 687 if ( in_array( 'custom_fields', $fields ) ) 688 $_post['custom_fields'] = $this->get_custom_fields( $post['ID'] ); 689 690 if ( in_array( 'enclosure', $fields ) ) { 691 $_post['enclosure'] = array(); 692 $enclosures = (array) get_post_meta( $post['ID'], 'enclosure' ); 693 if ( ! empty( $enclosures ) ) { 694 $encdata = explode( "\n", $enclosures[0] ); 695 $_post['enclosure']['url'] = trim( htmlspecialchars( $encdata[0] ) ); 696 $_post['enclosure']['length'] = (int) trim( $encdata[1] ); 697 $_post['enclosure']['type'] = trim( $encdata[2] ); 698 } 699 } 700 701 return apply_filters( 'xmlrpc_prepare_post', $_post, $post, $fields ); 702 } 703 704 /** 705 * Prepares post data for return in an XML-RPC object. 706 * 707 * @access protected 708 * 709 * @param object $post_type Post type object 710 * @param array $fields The subset of post fields to return 711 * @return array The prepared post type data 712 */ 713 protected function _prepare_post_type( $post_type, $fields ) { 714 $_post_type = array( 715 'name' => $post_type->name, 716 'label' => $post_type->label, 717 'hierarchical' => (bool) $post_type->hierarchical, 718 'public' => (bool) $post_type->public, 719 'show_ui' => (bool) $post_type->show_ui, 720 '_builtin' => (bool) $post_type->_builtin, 721 'has_archive' => (bool) $post_type->has_archive, 722 'supports' => get_all_post_type_supports( $post_type->name ), 723 ); 724 725 if ( in_array( 'labels', $fields ) ) { 726 $_post_type['labels'] = (array) $post_type->labels; 727 } 728 729 if ( in_array( 'cap', $fields ) ) { 730 $_post_type['cap'] = (array) $post_type->cap; 731 $_post_type['map_meta_cap'] = (bool) $post_type->map_meta_cap; 732 } 733 734 if ( in_array( 'menu', $fields ) ) { 735 $_post_type['menu_position'] = (int) $post_type->menu_position; 736 $_post_type['menu_icon'] = $post_type->menu_icon; 737 $_post_type['show_in_menu'] = (bool) $post_type->show_in_menu; 738 } 739 740 if ( in_array( 'taxonomies', $fields ) ) 741 $_post_type['taxonomies'] = get_object_taxonomies( $post_type->name, 'names' ); 742 743 return apply_filters( 'xmlrpc_prepare_post_type', $_post_type, $post_type ); 744 } 745 746 /** 747 * Prepares media item data for return in an XML-RPC object. 748 * 749 * @access protected 750 * 751 * @param object $media_item The unprepared media item data 752 * @param string $thumbnail_size The image size to use for the thumbnail URL 753 * @return array The prepared media item data 754 */ 755 protected function _prepare_media_item( $media_item, $thumbnail_size = 'thumbnail' ) { 756 $_media_item = array( 757 'attachment_id' => strval( $media_item->ID ), 758 'date_created_gmt' => $this->_convert_date_gmt( $media_item->post_date_gmt, $media_item->post_date ), 759 'parent' => $media_item->post_parent, 760 'link' => wp_get_attachment_url( $media_item->ID ), 761 'title' => $media_item->post_title, 762 'caption' => $media_item->post_excerpt, 763 'description' => $media_item->post_content, 764 'metadata' => wp_get_attachment_metadata( $media_item->ID ), 765 ); 766 767 $thumbnail_src = image_downsize( $media_item->ID, $thumbnail_size ); 768 if ( $thumbnail_src ) 769 $_media_item['thumbnail'] = $thumbnail_src[0]; 770 else 771 $_media_item['thumbnail'] = $_media_item['link']; 772 773 return apply_filters( 'xmlrpc_prepare_media_item', $_media_item, $media_item, $thumbnail_size ); 774 } 775 776 /** 777 * Prepares page data for return in an XML-RPC object. 778 * 779 * @access protected 780 * 781 * @param object $page The unprepared page data 782 * @return array The prepared page data 783 */ 784 protected function _prepare_page( $page ) { 785 // Get all of the page content and link. 786 $full_page = get_extended( $page->post_content ); 787 $link = post_permalink( $page->ID ); 788 789 // Get info the page parent if there is one. 790 $parent_title = ""; 791 if ( ! empty( $page->post_parent ) ) { 792 $parent = get_post( $page->post_parent ); 793 $parent_title = $parent->post_title; 794 } 795 796 // Determine comment and ping settings. 797 $allow_comments = comments_open( $page->ID ) ? 1 : 0; 798 $allow_pings = pings_open( $page->ID ) ? 1 : 0; 799 800 // Format page date. 801 $page_date = $this->_convert_date( $page->post_date ); 802 $page_date_gmt = $this->_convert_date_gmt( $page->post_date_gmt, $page->post_date ); 803 804 // Pull the categories info together. 805 $categories = array(); 806 foreach ( wp_get_post_categories( $page->ID ) as $cat_id ) { 807 $categories[] = get_cat_name( $cat_id ); 808 } 809 810 // Get the author info. 811 $author = get_userdata( $page->post_author ); 812 813 $page_template = get_page_template_slug( $page->ID ); 814 if ( empty( $page_template ) ) 815 $page_template = 'default'; 816 817 $_page = array( 818 'dateCreated' => $page_date, 819 'userid' => $page->post_author, 820 'page_id' => $page->ID, 821 'page_status' => $page->post_status, 822 'description' => $full_page['main'], 823 'title' => $page->post_title, 824 'link' => $link, 825 'permaLink' => $link, 826 'categories' => $categories, 827 'excerpt' => $page->post_excerpt, 828 'text_more' => $full_page['extended'], 829 'mt_allow_comments' => $allow_comments, 830 'mt_allow_pings' => $allow_pings, 831 'wp_slug' => $page->post_name, 832 'wp_password' => $page->post_password, 833 'wp_author' => $author->display_name, 834 'wp_page_parent_id' => $page->post_parent, 835 'wp_page_parent_title' => $parent_title, 836 'wp_page_order' => $page->menu_order, 837 'wp_author_id' => (string) $author->ID, 838 'wp_author_display_name' => $author->display_name, 839 'date_created_gmt' => $page_date_gmt, 840 'custom_fields' => $this->get_custom_fields( $page->ID ), 841 'wp_page_template' => $page_template 842 ); 843 844 return apply_filters( 'xmlrpc_prepare_page', $_page, $page ); 845 } 846 847 /** 848 * Prepares comment data for return in an XML-RPC object. 849 * 850 * @access protected 851 * 852 * @param object $comment The unprepared comment data 853 * @return array The prepared comment data 854 */ 855 protected function _prepare_comment( $comment ) { 856 // Format page date. 857 $comment_date = $this->_convert_date( $comment->comment_date ); 858 $comment_date_gmt = $this->_convert_date_gmt( $comment->comment_date_gmt, $comment->comment_date ); 859 860 if ( '0' == $comment->comment_approved ) 861 $comment_status = 'hold'; 862 else if ( 'spam' == $comment->comment_approved ) 863 $comment_status = 'spam'; 864 else if ( '1' == $comment->comment_approved ) 865 $comment_status = 'approve'; 866 else 867 $comment_status = $comment->comment_approved; 868 869 $_comment = array( 870 'date_created_gmt' => $comment_date_gmt, 871 'user_id' => $comment->user_id, 872 'comment_id' => $comment->comment_ID, 873 'parent' => $comment->comment_parent, 874 'status' => $comment_status, 875 'content' => $comment->comment_content, 876 'link' => get_comment_link($comment), 877 'post_id' => $comment->comment_post_ID, 878 'post_title' => get_the_title($comment->comment_post_ID), 879 'author' => $comment->comment_author, 880 'author_url' => $comment->comment_author_url, 881 'author_email' => $comment->comment_author_email, 882 'author_ip' => $comment->comment_author_IP, 883 'type' => $comment->comment_type, 884 ); 885 886 return apply_filters( 'xmlrpc_prepare_comment', $_comment, $comment ); 887 } 888 889 /** 890 * Prepares user data for return in an XML-RPC object. 891 * 892 * @access protected 893 * 894 * @param WP_User $user The unprepared user object 895 * @param array $fields The subset of user fields to return 896 * @return array The prepared user data 897 */ 898 protected function _prepare_user( $user, $fields ) { 899 $_user = array( 'user_id' => strval( $user->ID ) ); 900 901 $user_fields = array( 902 'username' => $user->user_login, 903 'first_name' => $user->user_firstname, 904 'last_name' => $user->user_lastname, 905 'registered' => $this->_convert_date( $user->user_registered ), 906 'bio' => $user->user_description, 907 'email' => $user->user_email, 908 'nickname' => $user->nickname, 909 'nicename' => $user->user_nicename, 910 'url' => $user->user_url, 911 'display_name' => $user->display_name, 912 'roles' => $user->roles, 913 ); 914 915 if ( in_array( 'all', $fields ) ) { 916 $_user = array_merge( $_user, $user_fields ); 917 } else { 918 if ( in_array( 'basic', $fields ) ) { 919 $basic_fields = array( 'username', 'email', 'registered', 'display_name', 'nicename' ); 920 $fields = array_merge( $fields, $basic_fields ); 921 } 922 $requested_fields = array_intersect_key( $user_fields, array_flip( $fields ) ); 923 $_user = array_merge( $_user, $requested_fields ); 924 } 925 926 return apply_filters( 'xmlrpc_prepare_user', $_user, $user, $fields ); 927 } 928 929 /** 930 * Create a new post for any registered post type. 931 * 932 * @since 3.4.0 933 * 934 * @param array $args Method parameters. Contains: 935 * - int $blog_id 936 * - string $username 937 * - string $password 938 * - array $content_struct 939 * $content_struct can contain: 940 * - post_type (default: 'post') 941 * - post_status (default: 'draft') 942 * - post_title 943 * - post_author 944 * - post_excerpt 945 * - post_content 946 * - post_date_gmt | post_date 947 * - post_format 948 * - post_password 949 * - comment_status - can be 'open' | 'closed' 950 * - ping_status - can be 'open' | 'closed' 951 * - sticky 952 * - post_thumbnail - ID of a media item to use as the post thumbnail/featured image 953 * - custom_fields - array, with each element containing 'key' and 'value' 954 * - terms - array, with taxonomy names as keys and arrays of term IDs as values 955 * - terms_names - array, with taxonomy names as keys and arrays of term names as values 956 * - enclosure 957 * - any other fields supported by wp_insert_post() 958 * @return string post_id 959 */ 960 function wp_newPost( $args ) { 961 if ( ! $this->minimum_args( $args, 4 ) ) 962 return $this->error; 963 964 $this->escape( $args ); 965 966 $blog_id = (int) $args[0]; 967 $username = $args[1]; 968 $password = $args[2]; 969 $content_struct = $args[3]; 970 971 if ( ! $user = $this->login( $username, $password ) ) 972 return $this->error; 973 974 do_action( 'xmlrpc_call', 'wp.newPost' ); 975 976 unset( $content_struct['ID'] ); 977 978 return $this->_insert_post( $user, $content_struct ); 979 } 980 981 /** 982 * Helper method for filtering out elements from an array. 983 * 984 * @since 3.4.0 985 * 986 * @param int $count Number to compare to one. 987 */ 988 private function _is_greater_than_one( $count ) { 989 return $count > 1; 990 } 991 992 /** 993 * Helper method for wp_newPost and wp_editPost, containing shared logic. 994 * 995 * @since 3.4.0 996 * @uses wp_insert_post() 997 * 998 * @param WP_User $user The post author if post_author isn't set in $content_struct. 999 * @param array $content_struct Post data to insert. 1000 */ 1001 protected function _insert_post( $user, $content_struct ) { 1002 $defaults = array( 'post_status' => 'draft', 'post_type' => 'post', 'post_author' => 0, 1003 'post_password' => '', 'post_excerpt' => '', 'post_content' => '', 'post_title' => '' ); 1004 1005 $post_data = wp_parse_args( $content_struct, $defaults ); 1006 1007 $post_type = get_post_type_object( $post_data['post_type'] ); 1008 if ( ! $post_type ) 1009 return new IXR_Error( 403, __( 'Invalid post type' ) ); 1010 1011 $update = ! empty( $post_data['ID'] ); 1012 1013 if ( $update ) { 1014 if ( ! get_post( $post_data['ID'] ) ) 1015 return new IXR_Error( 401, __( 'Invalid post ID.' ) ); 1016 if ( ! current_user_can( 'edit_post', $post_data['ID'] ) ) 1017 return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post.' ) ); 1018 if ( $post_data['post_type'] != get_post_type( $post_data['ID'] ) ) 1019 return new IXR_Error( 401, __( 'The post type may not be changed.' ) ); 1020 } else { 1021 if ( ! current_user_can( $post_type->cap->create_posts ) || ! current_user_can( $post_type->cap->edit_posts ) ) 1022 return new IXR_Error( 401, __( 'Sorry, you are not allowed to post on this site.' ) ); 1023 } 1024 1025 switch ( $post_data['post_status'] ) { 1026 case 'draft': 1027 case 'pending': 1028 break; 1029 case 'private': 1030 if ( ! current_user_can( $post_type->cap->publish_posts ) ) 1031 return new IXR_Error( 401, __( 'Sorry, you are not allowed to create private posts in this post type' ) ); 1032 break; 1033 case 'publish': 1034 case 'future': 1035 if ( ! current_user_can( $post_type->cap->publish_posts ) ) 1036 return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts in this post type' ) ); 1037 break; 1038 default: 1039 if ( ! get_post_status_object( $post_data['post_status'] ) ) 1040 $post_data['post_status'] = 'draft'; 1041 break; 1042 } 1043 1044 if ( ! empty( $post_data['post_password'] ) && ! current_user_can( $post_type->cap->publish_posts ) ) 1045 return new IXR_Error( 401, __( 'Sorry, you are not allowed to create password protected posts in this post type' ) ); 1046 1047 $post_data['post_author'] = absint( $post_data['post_author'] ); 1048 if ( ! empty( $post_data['post_author'] ) && $post_data['post_author'] != $user->ID ) { 1049 if ( ! current_user_can( $post_type->cap->edit_others_posts ) ) 1050 return new IXR_Error( 401, __( 'You are not allowed to create posts as this user.' ) ); 1051 1052 $author = get_userdata( $post_data['post_author'] ); 1053 1054 if ( ! $author ) 1055 return new IXR_Error( 404, __( 'Invalid author ID.' ) ); 1056 } else { 1057 $post_data['post_author'] = $user->ID; 1058 } 1059 1060 if ( isset( $post_data['comment_status'] ) && $post_data['comment_status'] != 'open' && $post_data['comment_status'] != 'closed' ) 1061 unset( $post_data['comment_status'] ); 1062 1063 if ( isset( $post_data['ping_status'] ) && $post_data['ping_status'] != 'open' && $post_data['ping_status'] != 'closed' ) 1064 unset( $post_data['ping_status'] ); 1065 1066 // Do some timestamp voodoo 1067 if ( ! empty( $post_data['post_date_gmt'] ) ) { 1068 // We know this is supposed to be GMT, so we're going to slap that Z on there by force 1069 $dateCreated = rtrim( $post_data['post_date_gmt']->getIso(), 'Z' ) . 'Z'; 1070 } elseif ( ! empty( $post_data['post_date'] ) ) { 1071 $dateCreated = $post_data['post_date']->getIso(); 1072 } 1073 1074 if ( ! empty( $dateCreated ) ) { 1075 $post_data['post_date'] = get_date_from_gmt( iso8601_to_datetime( $dateCreated ) ); 1076 $post_data['post_date_gmt'] = iso8601_to_datetime( $dateCreated, 'GMT' ); 1077 } 1078 1079 if ( ! isset( $post_data['ID'] ) ) 1080 $post_data['ID'] = get_default_post_to_edit( $post_data['post_type'], true )->ID; 1081 $post_ID = $post_data['ID']; 1082 1083 if ( $post_data['post_type'] == 'post' ) { 1084 // Private and password-protected posts cannot be stickied. 1085 if ( $post_data['post_status'] == 'private' || ! empty( $post_data['post_password'] ) ) { 1086 // Error if the client tried to stick the post, otherwise, silently unstick. 1087 if ( ! empty( $post_data['sticky'] ) ) 1088 return new IXR_Error( 401, __( 'Sorry, you cannot stick a private post.' ) ); 1089 if ( $update ) 1090 unstick_post( $post_ID ); 1091 } elseif ( isset( $post_data['sticky'] ) ) { 1092 if ( ! current_user_can( $post_type->cap->edit_others_posts ) ) 1093 return new IXR_Error( 401, __( 'Sorry, you are not allowed to stick this post.' ) ); 1094 if ( $post_data['sticky'] ) 1095 stick_post( $post_ID ); 1096 else 1097 unstick_post( $post_ID ); 1098 } 1099 } 1100 1101 if ( isset( $post_data['post_thumbnail'] ) ) { 1102 // empty value deletes, non-empty value adds/updates 1103 if ( ! $post_data['post_thumbnail'] ) 1104 delete_post_thumbnail( $post_ID ); 1105 elseif ( ! get_post( absint( $post_data['post_thumbnail'] ) ) ) 1106 return new IXR_Error( 404, __( 'Invalid attachment ID.' ) ); 1107 set_post_thumbnail( $post_ID, $post_data['post_thumbnail'] ); 1108 unset( $content_struct['post_thumbnail'] ); 1109 } 1110 1111 if ( isset( $post_data['custom_fields'] ) ) 1112 $this->set_custom_fields( $post_ID, $post_data['custom_fields'] ); 1113 1114 if ( isset( $post_data['terms'] ) || isset( $post_data['terms_names'] ) ) { 1115 $post_type_taxonomies = get_object_taxonomies( $post_data['post_type'], 'objects' ); 1116 1117 // accumulate term IDs from terms and terms_names 1118 $terms = array(); 1119 1120 // first validate the terms specified by ID 1121 if ( isset( $post_data['terms'] ) && is_array( $post_data['terms'] ) ) { 1122 $taxonomies = array_keys( $post_data['terms'] ); 1123 1124 // validating term ids 1125 foreach ( $taxonomies as $taxonomy ) { 1126 if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) ) 1127 return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) ); 1128 1129 if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) ) 1130 return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) ); 1131 1132 $term_ids = $post_data['terms'][$taxonomy]; 1133 foreach ( $term_ids as $term_id ) { 1134 $term = get_term_by( 'id', $term_id, $taxonomy ); 1135 1136 if ( ! $term ) 1137 return new IXR_Error( 403, __( 'Invalid term ID' ) ); 1138 1139 $terms[$taxonomy][] = (int) $term_id; 1140 } 1141 } 1142 } 1143 1144 // now validate terms specified by name 1145 if ( isset( $post_data['terms_names'] ) && is_array( $post_data['terms_names'] ) ) { 1146 $taxonomies = array_keys( $post_data['terms_names'] ); 1147 1148 foreach ( $taxonomies as $taxonomy ) { 1149 if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) ) 1150 return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) ); 1151 1152 if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) ) 1153 return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) ); 1154 1155 // for hierarchical taxonomies, we can't assign a term when multiple terms in the hierarchy share the same name 1156 $ambiguous_terms = array(); 1157 if ( is_taxonomy_hierarchical( $taxonomy ) ) { 1158 $tax_term_names = get_terms( $taxonomy, array( 'fields' => 'names', 'hide_empty' => false ) ); 1159 1160 // count the number of terms with the same name 1161 $tax_term_names_count = array_count_values( $tax_term_names ); 1162 1163 // filter out non-ambiguous term names 1164 $ambiguous_tax_term_counts = array_filter( $tax_term_names_count, array( $this, '_is_greater_than_one') ); 1165 1166 $ambiguous_terms = array_keys( $ambiguous_tax_term_counts ); 1167 } 1168 1169 $term_names = $post_data['terms_names'][$taxonomy]; 1170 foreach ( $term_names as $term_name ) { 1171 if ( in_array( $term_name, $ambiguous_terms ) ) 1172 return new IXR_Error( 401, __( 'Ambiguous term name used in a hierarchical taxonomy. Please use term ID instead.' ) ); 1173 1174 $term = get_term_by( 'name', $term_name, $taxonomy ); 1175 1176 if ( ! $term ) { 1177 // term doesn't exist, so check that the user is allowed to create new terms 1178 if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->edit_terms ) ) 1179 return new IXR_Error( 401, __( 'Sorry, you are not allowed to add a term to one of the given taxonomies.' ) ); 1180 1181 // create the new term 1182 $term_info = wp_insert_term( $term_name, $taxonomy ); 1183 if ( is_wp_error( $term_info ) ) 1184 return new IXR_Error( 500, $term_info->get_error_message() ); 1185 1186 $terms[$taxonomy][] = (int) $term_info['term_id']; 1187 } else { 1188 $terms[$taxonomy][] = (int) $term->term_id; 1189 } 1190 } 1191 } 1192 } 1193 1194 $post_data['tax_input'] = $terms; 1195 unset( $post_data['terms'], $post_data['terms_names'] ); 1196 } else { 1197 // do not allow direct submission of 'tax_input', clients must use 'terms' and/or 'terms_names' 1198 unset( $post_data['tax_input'], $post_data['post_category'], $post_data['tags_input'] ); 1199 } 1200 1201 if ( isset( $post_data['post_format'] ) ) { 1202 $format = set_post_format( $post_ID, $post_data['post_format'] ); 1203 1204 if ( is_wp_error( $format ) ) 1205 return new IXR_Error( 500, $format->get_error_message() ); 1206 1207 unset( $post_data['post_format'] ); 1208 } 1209 1210 // Handle enclosures 1211 $enclosure = isset( $post_data['enclosure'] ) ? $post_data['enclosure'] : null; 1212 $this->add_enclosure_if_new( $post_ID, $enclosure ); 1213 1214 $this->attach_uploads( $post_ID, $post_data['post_content'] ); 1215 1216 $post_data = apply_filters( 'xmlrpc_wp_insert_post_data', $post_data, $content_struct ); 1217 1218 $post_ID = $update ? wp_update_post( $post_data, true ) : wp_insert_post( $post_data, true ); 1219 if ( is_wp_error( $post_ID ) ) 1220 return new IXR_Error( 500, $post_ID->get_error_message() ); 1221 1222 if ( ! $post_ID ) 1223 return new IXR_Error( 401, __( 'Sorry, your entry could not be posted. Something wrong happened.' ) ); 1224 1225 return strval( $post_ID ); 1226 } 1227 1228 /** 1229 * Edit a post for any registered post type. 1230 * 1231 * The $content_struct parameter only needs to contain fields that 1232 * should be changed. All other fields will retain their existing values. 1233 * 1234 * @since 3.4.0 1235 * 1236 * @param array $args Method parameters. Contains: 1237 * - int $blog_id 1238 * - string $username 1239 * - string $password 1240 * - int $post_id 1241 * - array $content_struct 1242 * @return true on success 1243 */ 1244 function wp_editPost( $args ) { 1245 if ( ! $this->minimum_args( $args, 5 ) ) 1246 return $this->error; 1247 1248 $this->escape( $args ); 1249 1250 $blog_id = (int) $args[0]; 1251 $username = $args[1]; 1252 $password = $args[2]; 1253 $post_id = (int) $args[3]; 1254 $content_struct = $args[4]; 1255 1256 if ( ! $user = $this->login( $username, $password ) ) 1257 return $this->error; 1258 1259 do_action( 'xmlrpc_call', 'wp.editPost' ); 1260 1261 $post = get_post( $post_id, ARRAY_A ); 1262 1263 if ( empty( $post['ID'] ) ) 1264 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 1265 1266 if ( isset( $content_struct['if_not_modified_since'] ) ) { 1267 // If the post has been modified since the date provided, return an error. 1268 if ( mysql2date( 'U', $post['post_modified_gmt'] ) > $content_struct['if_not_modified_since']->getTimestamp() ) { 1269 return new IXR_Error( 409, __( 'There is a revision of this post that is more recent.' ) ); 1270 } 1271 } 1272 1273 // convert the date field back to IXR form 1274 $post['post_date'] = $this->_convert_date( $post['post_date'] ); 1275 1276 // ignore the existing GMT date if it is empty or a non-GMT date was supplied in $content_struct, 1277 // since _insert_post will ignore the non-GMT date if the GMT date is set 1278 if ( $post['post_date_gmt'] == '0000-00-00 00:00:00' || isset( $content_struct['post_date'] ) ) 1279 unset( $post['post_date_gmt'] ); 1280 else 1281 $post['post_date_gmt'] = $this->_convert_date( $post['post_date_gmt'] ); 1282 1283 $this->escape( $post ); 1284 $merged_content_struct = array_merge( $post, $content_struct ); 1285 1286 $retval = $this->_insert_post( $user, $merged_content_struct ); 1287 if ( $retval instanceof IXR_Error ) 1288 return $retval; 1289 1290 return true; 1291 } 1292 1293 /** 1294 * Delete a post for any registered post type. 1295 * 1296 * @since 3.4.0 1297 * 1298 * @uses wp_delete_post() 1299 * @param array $args Method parameters. Contains: 1300 * - int $blog_id 1301 * - string $username 1302 * - string $password 1303 * - int $post_id 1304 * @return true on success 1305 */ 1306 function wp_deletePost( $args ) { 1307 if ( ! $this->minimum_args( $args, 4 ) ) 1308 return $this->error; 1309 1310 $this->escape( $args ); 1311 1312 $blog_id = (int) $args[0]; 1313 $username = $args[1]; 1314 $password = $args[2]; 1315 $post_id = (int) $args[3]; 1316 1317 if ( ! $user = $this->login( $username, $password ) ) 1318 return $this->error; 1319 1320 do_action( 'xmlrpc_call', 'wp.deletePost' ); 1321 1322 $post = get_post( $post_id, ARRAY_A ); 1323 if ( empty( $post['ID'] ) ) 1324 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 1325 1326 if ( ! current_user_can( 'delete_post', $post_id ) ) 1327 return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete this post.' ) ); 1328 1329 $result = wp_delete_post( $post_id ); 1330 1331 if ( ! $result ) 1332 return new IXR_Error( 500, __( 'The post cannot be deleted.' ) ); 1333 1334 return true; 1335 } 1336 1337 /** 1338 * Retrieve a post. 1339 * 1340 * @since 3.4.0 1341 * 1342 * The optional $fields parameter specifies what fields will be included 1343 * in the response array. This should be a list of field names. 'post_id' will 1344 * always be included in the response regardless of the value of $fields. 1345 * 1346 * Instead of, or in addition to, individual field names, conceptual group 1347 * names can be used to specify multiple fields. The available conceptual 1348 * groups are 'post' (all basic fields), 'taxonomies', 'custom_fields', 1349 * and 'enclosure'. 1350 * 1351 * @uses get_post() 1352 * @param array $args Method parameters. Contains: 1353 * - int $post_id 1354 * - string $username 1355 * - string $password 1356 * - array $fields optional 1357 * @return array contains (based on $fields parameter): 1358 * - 'post_id' 1359 * - 'post_title' 1360 * - 'post_date' 1361 * - 'post_date_gmt' 1362 * - 'post_modified' 1363 * - 'post_modified_gmt' 1364 * - 'post_status' 1365 * - 'post_type' 1366 * - 'post_name' 1367 * - 'post_author' 1368 * - 'post_password' 1369 * - 'post_excerpt' 1370 * - 'post_content' 1371 * - 'link' 1372 * - 'comment_status' 1373 * - 'ping_status' 1374 * - 'sticky' 1375 * - 'custom_fields' 1376 * - 'terms' 1377 * - 'categories' 1378 * - 'tags' 1379 * - 'enclosure' 1380 */ 1381 function wp_getPost( $args ) { 1382 if ( ! $this->minimum_args( $args, 4 ) ) 1383 return $this->error; 1384 1385 $this->escape( $args ); 1386 1387 $blog_id = (int) $args[0]; 1388 $username = $args[1]; 1389 $password = $args[2]; 1390 $post_id = (int) $args[3]; 1391 1392 if ( isset( $args[4] ) ) 1393 $fields = $args[4]; 1394 else 1395 $fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPost' ); 1396 1397 if ( ! $user = $this->login( $username, $password ) ) 1398 return $this->error; 1399 1400 do_action( 'xmlrpc_call', 'wp.getPost' ); 1401 1402 $post = get_post( $post_id, ARRAY_A ); 1403 1404 if ( empty( $post['ID'] ) ) 1405 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 1406 1407 if ( ! current_user_can( 'edit_post', $post_id ) ) 1408 return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); 1409 1410 return $this->_prepare_post( $post, $fields ); 1411 } 1412 1413 /** 1414 * Retrieve posts. 1415 * 1416 * @since 3.4.0 1417 * 1418 * The optional $filter parameter modifies the query used to retrieve posts. 1419 * Accepted keys are 'post_type', 'post_status', 'number', 'offset', 1420 * 'orderby', and 'order'. 1421 * 1422 * The optional $fields parameter specifies what fields will be included 1423 * in the response array. 1424 * 1425 * @uses wp_get_recent_posts() 1426 * @see wp_getPost() for more on $fields 1427 * @see get_posts() for more on $filter values 1428 * 1429 * @param array $args Method parameters. Contains: 1430 * - int $blog_id 1431 * - string $username 1432 * - string $password 1433 * - array $filter optional 1434 * - array $fields optional 1435 * @return array contains a collection of posts. 1436 */ 1437 function wp_getPosts( $args ) { 1438 if ( ! $this->minimum_args( $args, 3 ) ) 1439 return $this->error; 1440 1441 $this->escape( $args ); 1442 1443 $blog_id = (int) $args[0]; 1444 $username = $args[1]; 1445 $password = $args[2]; 1446 $filter = isset( $args[3] ) ? $args[3] : array(); 1447 1448 if ( isset( $args[4] ) ) 1449 $fields = $args[4]; 1450 else 1451 $fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPosts' ); 1452 1453 if ( ! $user = $this->login( $username, $password ) ) 1454 return $this->error; 1455 1456 do_action( 'xmlrpc_call', 'wp.getPosts' ); 1457 1458 $query = array(); 1459 1460 if ( isset( $filter['post_type'] ) ) { 1461 $post_type = get_post_type_object( $filter['post_type'] ); 1462 if ( ! ( (bool) $post_type ) ) 1463 return new IXR_Error( 403, __( 'The post type specified is not valid' ) ); 1464 } else { 1465 $post_type = get_post_type_object( 'post' ); 1466 } 1467 1468 if ( ! current_user_can( $post_type->cap->edit_posts ) ) 1469 return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts in this post type' )); 1470 1471 $query['post_type'] = $post_type->name; 1472 1473 if ( isset( $filter['post_status'] ) ) 1474 $query['post_status'] = $filter['post_status']; 1475 1476 if ( isset( $filter['number'] ) ) 1477 $query['numberposts'] = absint( $filter['number'] ); 1478 1479 if ( isset( $filter['offset'] ) ) 1480 $query['offset'] = absint( $filter['offset'] ); 1481 1482 if ( isset( $filter['orderby'] ) ) { 1483 $query['orderby'] = $filter['orderby']; 1484 1485 if ( isset( $filter['order'] ) ) 1486 $query['order'] = $filter['order']; 1487 } 1488 1489 if ( isset( $filter['s'] ) ) { 1490 $query['s'] = $filter['s']; 1491 } 1492 1493 $posts_list = wp_get_recent_posts( $query ); 1494 1495 if ( ! $posts_list ) 1496 return array(); 1497 1498 // holds all the posts data 1499 $struct = array(); 1500 1501 foreach ( $posts_list as $post ) { 1502 if ( ! current_user_can( 'edit_post', $post['ID'] ) ) 1503 continue; 1504 1505 $struct[] = $this->_prepare_post( $post, $fields ); 1506 } 1507 1508 return $struct; 1509 } 1510 1511 /** 1512 * Create a new term. 1513 * 1514 * @since 3.4.0 1515 * 1516 * @uses wp_insert_term() 1517 * @param array $args Method parameters. Contains: 1518 * - int $blog_id 1519 * - string $username 1520 * - string $password 1521 * - array $content_struct 1522 * The $content_struct must contain: 1523 * - 'name' 1524 * - 'taxonomy' 1525 * Also, it can optionally contain: 1526 * - 'parent' 1527 * - 'description' 1528 * - 'slug' 1529 * @return string term_id 1530 */ 1531 function wp_newTerm( $args ) { 1532 if ( ! $this->minimum_args( $args, 4 ) ) 1533 return $this->error; 1534 1535 $this->escape( $args ); 1536 1537 $blog_id = (int) $args[0]; 1538 $username = $args[1]; 1539 $password = $args[2]; 1540 $content_struct = $args[3]; 1541 1542 if ( ! $user = $this->login( $username, $password ) ) 1543 return $this->error; 1544 1545 do_action( 'xmlrpc_call', 'wp.newTerm' ); 1546 1547 if ( ! taxonomy_exists( $content_struct['taxonomy'] ) ) 1548 return new IXR_Error( 403, __( 'Invalid taxonomy' ) ); 1549 1550 $taxonomy = get_taxonomy( $content_struct['taxonomy'] ); 1551 1552 if ( ! current_user_can( $taxonomy->cap->manage_terms ) ) 1553 return new IXR_Error( 401, __( 'You are not allowed to create terms in this taxonomy.' ) ); 1554 1555 $taxonomy = (array) $taxonomy; 1556 1557 // hold the data of the term 1558 $term_data = array(); 1559 1560 $term_data['name'] = trim( $content_struct['name'] ); 1561 if ( empty( $term_data['name'] ) ) 1562 return new IXR_Error( 403, __( 'The term name cannot be empty.' ) ); 1563 1564 if ( isset( $content_struct['parent'] ) ) { 1565 if ( ! $taxonomy['hierarchical'] ) 1566 return new IXR_Error( 403, __( 'This taxonomy is not hierarchical.' ) ); 1567 1568 $parent_term_id = (int) $content_struct['parent']; 1569 $parent_term = get_term( $parent_term_id , $taxonomy['name'] ); 1570 1571 if ( is_wp_error( $parent_term ) ) 1572 return new IXR_Error( 500, $parent_term->get_error_message() ); 1573 1574 if ( ! $parent_term ) 1575 return new IXR_Error( 403, __( 'Parent term does not exist.' ) ); 1576 1577 $term_data['parent'] = $content_struct['parent']; 1578 } 1579 1580 if ( isset( $content_struct['description'] ) ) 1581 $term_data['description'] = $content_struct['description']; 1582 1583 if ( isset( $content_struct['slug'] ) ) 1584 $term_data['slug'] = $content_struct['slug']; 1585 1586 $term = wp_insert_term( $term_data['name'] , $taxonomy['name'] , $term_data ); 1587 1588 if ( is_wp_error( $term ) ) 1589 return new IXR_Error( 500, $term->get_error_message() ); 1590 1591 if ( ! $term ) 1592 return new IXR_Error( 500, __( 'Sorry, your term could not be created. Something wrong happened.' ) ); 1593 1594 return strval( $term['term_id'] ); 1595 } 1596 1597 /** 1598 * Edit a term. 1599 * 1600 * @since 3.4.0 1601 * 1602 * @uses wp_update_term() 1603 * @param array $args Method parameters. Contains: 1604 * - int $blog_id 1605 * - string $username 1606 * - string $password 1607 * - string $term_id 1608 * - array $content_struct 1609 * The $content_struct must contain: 1610 * - 'taxonomy' 1611 * Also, it can optionally contain: 1612 * - 'name' 1613 * - 'parent' 1614 * - 'description' 1615 * - 'slug' 1616 * @return bool True, on success. 1617 */ 1618 function wp_editTerm( $args ) { 1619 if ( ! $this->minimum_args( $args, 5 ) ) 1620 return $this->error; 1621 1622 $this->escape( $args ); 1623 1624 $blog_id = (int) $args[0]; 1625 $username = $args[1]; 1626 $password = $args[2]; 1627 $term_id = (int) $args[3]; 1628 $content_struct = $args[4]; 1629 1630 if ( ! $user = $this->login( $username, $password ) ) 1631 return $this->error; 1632 1633 do_action( 'xmlrpc_call', 'wp.editTerm' ); 1634 1635 if ( ! taxonomy_exists( $content_struct['taxonomy'] ) ) 1636 return new IXR_Error( 403, __( 'Invalid taxonomy' ) ); 1637 1638 $taxonomy = get_taxonomy( $content_struct['taxonomy'] ); 1639 1640 if ( ! current_user_can( $taxonomy->cap->edit_terms ) ) 1641 return new IXR_Error( 401, __( 'You are not allowed to edit terms in this taxonomy.' ) ); 1642 1643 $taxonomy = (array) $taxonomy; 1644 1645 // hold the data of the term 1646 $term_data = array(); 1647 1648 $term = get_term( $term_id , $content_struct['taxonomy'] ); 1649 1650 if ( is_wp_error( $term ) ) 1651 return new IXR_Error( 500, $term->get_error_message() ); 1652 1653 if ( ! $term ) 1654 return new IXR_Error( 404, __( 'Invalid term ID' ) ); 1655 1656 if ( isset( $content_struct['name'] ) ) { 1657 $term_data['name'] = trim( $content_struct['name'] ); 1658 1659 if ( empty( $term_data['name'] ) ) 1660 return new IXR_Error( 403, __( 'The term name cannot be empty.' ) ); 1661 } 1662 1663 if ( isset( $content_struct['parent'] ) ) { 1664 if ( ! $taxonomy['hierarchical'] ) 1665 return new IXR_Error( 403, __( "This taxonomy is not hierarchical so you can't set a parent." ) ); 1666 1667 $parent_term_id = (int) $content_struct['parent']; 1668 $parent_term = get_term( $parent_term_id , $taxonomy['name'] ); 1669 1670 if ( is_wp_error( $parent_term ) ) 1671 return new IXR_Error( 500, $parent_term->get_error_message() ); 1672 1673 if ( ! $parent_term ) 1674 return new IXR_Error( 403, __( 'Parent term does not exist.' ) ); 1675 1676 $term_data['parent'] = $content_struct['parent']; 1677 } 1678 1679 if ( isset( $content_struct['description'] ) ) 1680 $term_data['description'] = $content_struct['description']; 1681 1682 if ( isset( $content_struct['slug'] ) ) 1683 $term_data['slug'] = $content_struct['slug']; 1684 1685 $term = wp_update_term( $term_id , $taxonomy['name'] , $term_data ); 1686 1687 if ( is_wp_error( $term ) ) 1688 return new IXR_Error( 500, $term->get_error_message() ); 1689 1690 if ( ! $term ) 1691 return new IXR_Error( 500, __( 'Sorry, editing the term failed.' ) ); 1692 1693 return true; 1694 } 1695 1696 /** 1697 * Delete a term. 1698 * 1699 * @since 3.4.0 1700 * 1701 * @uses wp_delete_term() 1702 * @param array $args Method parameters. Contains: 1703 * - int $blog_id 1704 * - string $username 1705 * - string $password 1706 * - string $taxnomy_name 1707 * - string $term_id 1708 * @return boolean|IXR_Error If it suceeded true else a reason why not 1709 */ 1710 function wp_deleteTerm( $args ) { 1711 if ( ! $this->minimum_args( $args, 5 ) ) 1712 return $this->error; 1713 1714 $this->escape( $args ); 1715 1716 $blog_id = (int) $args[0]; 1717 $username = $args[1]; 1718 $password = $args[2]; 1719 $taxonomy = $args[3]; 1720 $term_id = (int) $args[4]; 1721 1722 if ( ! $user = $this->login( $username, $password ) ) 1723 return $this->error; 1724 1725 do_action( 'xmlrpc_call', 'wp.deleteTerm' ); 1726 1727 if ( ! taxonomy_exists( $taxonomy ) ) 1728 return new IXR_Error( 403, __( 'Invalid taxonomy' ) ); 1729 1730 $taxonomy = get_taxonomy( $taxonomy ); 1731 1732 if ( ! current_user_can( $taxonomy->cap->delete_terms ) ) 1733 return new IXR_Error( 401, __( 'You are not allowed to delete terms in this taxonomy.' ) ); 1734 1735 $term = get_term( $term_id, $taxonomy->name ); 1736 1737 if ( is_wp_error( $term ) ) 1738 return new IXR_Error( 500, $term->get_error_message() ); 1739 1740 if ( ! $term ) 1741 return new IXR_Error( 404, __( 'Invalid term ID' ) ); 1742 1743 $result = wp_delete_term( $term_id, $taxonomy->name ); 1744 1745 if ( is_wp_error( $result ) ) 1746 return new IXR_Error( 500, $term->get_error_message() ); 1747 1748 if ( ! $result ) 1749 return new IXR_Error( 500, __( 'Sorry, deleting the term failed.' ) ); 1750 1751 return $result; 1752 } 1753 1754 /** 1755 * Retrieve a term. 1756 * 1757 * @since 3.4.0 1758 * 1759 * @uses get_term() 1760 * @param array $args Method parameters. Contains: 1761 * - int $blog_id 1762 * - string $username 1763 * - string $password 1764 * - string $taxonomy 1765 * - string $term_id 1766 * @return array contains: 1767 * - 'term_id' 1768 * - 'name' 1769 * - 'slug' 1770 * - 'term_group' 1771 * - 'term_taxonomy_id' 1772 * - 'taxonomy' 1773 * - 'description' 1774 * - 'parent' 1775 * - 'count' 1776 */ 1777 function wp_getTerm( $args ) { 1778 if ( ! $this->minimum_args( $args, 5 ) ) 1779 return $this->error; 1780 1781 $this->escape( $args ); 1782 1783 $blog_id = (int) $args[0]; 1784 $username = $args[1]; 1785 $password = $args[2]; 1786 $taxonomy = $args[3]; 1787 $term_id = (int) $args[4]; 1788 1789 if ( ! $user = $this->login( $username, $password ) ) 1790 return $this->error; 1791 1792 do_action( 'xmlrpc_call', 'wp.getTerm' ); 1793 1794 if ( ! taxonomy_exists( $taxonomy ) ) 1795 return new IXR_Error( 403, __( 'Invalid taxonomy' ) ); 1796 1797 $taxonomy = get_taxonomy( $taxonomy ); 1798 1799 if ( ! current_user_can( $taxonomy->cap->assign_terms ) ) 1800 return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) ); 1801 1802 $term = get_term( $term_id , $taxonomy->name, ARRAY_A ); 1803 1804 if ( is_wp_error( $term ) ) 1805 return new IXR_Error( 500, $term->get_error_message() ); 1806 1807 if ( ! $term ) 1808 return new IXR_Error( 404, __( 'Invalid term ID' ) ); 1809 1810 return $this->_prepare_term( $term ); 1811 } 1812 1813 /** 1814 * Retrieve all terms for a taxonomy. 1815 * 1816 * @since 3.4.0 1817 * 1818 * The optional $filter parameter modifies the query used to retrieve terms. 1819 * Accepted keys are 'number', 'offset', 'orderby', 'order', 'hide_empty', and 'search'. 1820 * 1821 * @uses get_terms() 1822 * @param array $args Method parameters. Contains: 1823 * - int $blog_id 1824 * - string $username 1825 * - string $password 1826 * - string $taxonomy 1827 * - array $filter optional 1828 * @return array terms 1829 */ 1830 function wp_getTerms( $args ) { 1831 if ( ! $this->minimum_args( $args, 4 ) ) 1832 return $this->error; 1833 1834 $this->escape( $args ); 1835 1836 $blog_id = (int) $args[0]; 1837 $username = $args[1]; 1838 $password = $args[2]; 1839 $taxonomy = $args[3]; 1840 $filter = isset( $args[4] ) ? $args[4] : array(); 1841 1842 if ( ! $user = $this->login( $username, $password ) ) 1843 return $this->error; 1844 1845 do_action( 'xmlrpc_call', 'wp.getTerms' ); 1846 1847 if ( ! taxonomy_exists( $taxonomy ) ) 1848 return new IXR_Error( 403, __( 'Invalid taxonomy' ) ); 1849 1850 $taxonomy = get_taxonomy( $taxonomy ); 1851 1852 if ( ! current_user_can( $taxonomy->cap->assign_terms ) ) 1853 return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) ); 1854 1855 $query = array(); 1856 1857 if ( isset( $filter['number'] ) ) 1858 $query['number'] = absint( $filter['number'] ); 1859 1860 if ( isset( $filter['offset'] ) ) 1861 $query['offset'] = absint( $filter['offset'] ); 1862 1863 if ( isset( $filter['orderby'] ) ) { 1864 $query['orderby'] = $filter['orderby']; 1865 1866 if ( isset( $filter['order'] ) ) 1867 $query['order'] = $filter['order']; 1868 } 1869 1870 if ( isset( $filter['hide_empty'] ) ) 1871 $query['hide_empty'] = $filter['hide_empty']; 1872 else 1873 $query['get'] = 'all'; 1874 1875 if ( isset( $filter['search'] ) ) 1876 $query['search'] = $filter['search']; 1877 1878 $terms = get_terms( $taxonomy->name, $query ); 1879 1880 if ( is_wp_error( $terms ) ) 1881 return new IXR_Error( 500, $terms->get_error_message() ); 1882 1883 $struct = array(); 1884 1885 foreach ( $terms as $term ) { 1886 $struct[] = $this->_prepare_term( $term ); 1887 } 1888 1889 return $struct; 1890 } 1891 1892 /** 1893 * Retrieve a taxonomy. 1894 * 1895 * @since 3.4.0 1896 * 1897 * @uses get_taxonomy() 1898 * @param array $args Method parameters. Contains: 1899 * - int $blog_id 1900 * - string $username 1901 * - string $password 1902 * - string $taxonomy 1903 * @return array (@see get_taxonomy()) 1904 */ 1905 function wp_getTaxonomy( $args ) { 1906 if ( ! $this->minimum_args( $args, 4 ) ) 1907 return $this->error; 1908 1909 $this->escape( $args ); 1910 1911 $blog_id = (int) $args[0]; 1912 $username = $args[1]; 1913 $password = $args[2]; 1914 $taxonomy = $args[3]; 1915 1916 if ( isset( $args[4] ) ) 1917 $fields = $args[4]; 1918 else 1919 $fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomy' ); 1920 1921 if ( ! $user = $this->login( $username, $password ) ) 1922 return $this->error; 1923 1924 do_action( 'xmlrpc_call', 'wp.getTaxonomy' ); 1925 1926 if ( ! taxonomy_exists( $taxonomy ) ) 1927 return new IXR_Error( 403, __( 'Invalid taxonomy' ) ); 1928 1929 $taxonomy = get_taxonomy( $taxonomy ); 1930 1931 if ( ! current_user_can( $taxonomy->cap->assign_terms ) ) 1932 return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) ); 1933 1934 return $this->_prepare_taxonomy( $taxonomy, $fields ); 1935 } 1936 1937 /** 1938 * Retrieve all taxonomies. 1939 * 1940 * @since 3.4.0 1941 * 1942 * @uses get_taxonomies() 1943 * @param array $args Method parameters. Contains: 1944 * - int $blog_id 1945 * - string $username 1946 * - string $password 1947 * @return array taxonomies 1948 */ 1949 function wp_getTaxonomies( $args ) { 1950 if ( ! $this->minimum_args( $args, 3 ) ) 1951 return $this->error; 1952 1953 $this->escape( $args ); 1954 1955 $blog_id = (int) $args[0]; 1956 $username = $args[1]; 1957 $password = $args[2]; 1958 $filter = isset( $args[3] ) ? $args[3] : array( 'public' => true ); 1959 1960 if ( isset( $args[4] ) ) 1961 $fields = $args[4]; 1962 else 1963 $fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomies' ); 1964 1965 if ( ! $user = $this->login( $username, $password ) ) 1966 return $this->error; 1967 1968 do_action( 'xmlrpc_call', 'wp.getTaxonomies' ); 1969 1970 $taxonomies = get_taxonomies( $filter, 'objects' ); 1971 1972 // holds all the taxonomy data 1973 $struct = array(); 1974 1975 foreach ( $taxonomies as $taxonomy ) { 1976 // capability check for post_types 1977 if ( ! current_user_can( $taxonomy->cap->assign_terms ) ) 1978 continue; 1979 1980 $struct[] = $this->_prepare_taxonomy( $taxonomy, $fields ); 1981 } 1982 1983 return $struct; 1984 } 1985 1986 /** 1987 * Retrieve a user. 1988 * 1989 * The optional $fields parameter specifies what fields will be included 1990 * in the response array. This should be a list of field names. 'user_id' will 1991 * always be included in the response regardless of the value of $fields. 1992 * 1993 * Instead of, or in addition to, individual field names, conceptual group 1994 * names can be used to specify multiple fields. The available conceptual 1995 * groups are 'basic' and 'all'. 1996 * 1997 * @uses get_userdata() 1998 * @param array $args Method parameters. Contains: 1999 * - int $blog_id 2000 * - string $username 2001 * - string $password 2002 * - int $user_id 2003 * - array $fields optional 2004 * @return array contains (based on $fields parameter): 2005 * - 'user_id' 2006 * - 'username' 2007 * - 'first_name' 2008 * - 'last_name' 2009 * - 'registered' 2010 * - 'bio' 2011 * - 'email' 2012 * - 'nickname' 2013 * - 'nicename' 2014 * - 'url' 2015 * - 'display_name' 2016 * - 'roles' 2017 */ 2018 function wp_getUser( $args ) { 2019 if ( ! $this->minimum_args( $args, 4 ) ) 2020 return $this->error; 2021 2022 $this->escape( $args ); 2023 2024 $blog_id = (int) $args[0]; 2025 $username = $args[1]; 2026 $password = $args[2]; 2027 $user_id = (int) $args[3]; 2028 2029 if ( isset( $args[4] ) ) 2030 $fields = $args[4]; 2031 else 2032 $fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getUser' ); 2033 2034 if ( ! $user = $this->login( $username, $password ) ) 2035 return $this->error; 2036 2037 do_action( 'xmlrpc_call', 'wp.getUser' ); 2038 2039 if ( ! current_user_can( 'edit_user', $user_id ) ) 2040 return new IXR_Error( 401, __( 'Sorry, you cannot edit users.' ) ); 2041 2042 $user_data = get_userdata( $user_id ); 2043 2044 if ( ! $user_data ) 2045 return new IXR_Error( 404, __( 'Invalid user ID' ) ); 2046 2047 return $this->_prepare_user( $user_data, $fields ); 2048 } 2049 2050 /** 2051 * Retrieve users. 2052 * 2053 * The optional $filter parameter modifies the query used to retrieve users. 2054 * Accepted keys are 'number' (default: 50), 'offset' (default: 0), 'role', 2055 * 'who', 'orderby', and 'order'. 2056 * 2057 * The optional $fields parameter specifies what fields will be included 2058 * in the response array. 2059 * 2060 * @uses get_users() 2061 * @see wp_getUser() for more on $fields and return values 2062 * 2063 * @param array $args Method parameters. Contains: 2064 * - int $blog_id 2065 * - string $username 2066 * - string $password 2067 * - array $filter optional 2068 * - array $fields optional 2069 * @return array users data 2070 */ 2071 function wp_getUsers( $args ) { 2072 if ( ! $this->minimum_args( $args, 3 ) ) 2073 return $this->error; 2074 2075 $this->escape( $args ); 2076 2077 $blog_id = (int) $args[0]; 2078 $username = $args[1]; 2079 $password = $args[2]; 2080 $filter = isset( $args[3] ) ? $args[3] : array(); 2081 2082 if ( isset( $args[4] ) ) 2083 $fields = $args[4]; 2084 else 2085 $fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getUsers' ); 2086 2087 if ( ! $user = $this->login( $username, $password ) ) 2088 return $this->error; 2089 2090 do_action( 'xmlrpc_call', 'wp.getUsers' ); 2091 2092 if ( ! current_user_can( 'list_users' ) ) 2093 return new IXR_Error( 401, __( 'Sorry, you cannot list users.' ) ); 2094 2095 $query = array( 'fields' => 'all_with_meta' ); 2096 2097 $query['number'] = ( isset( $filter['number'] ) ) ? absint( $filter['number'] ) : 50; 2098 $query['offset'] = ( isset( $filter['offset'] ) ) ? absint( $filter['offset'] ) : 0; 2099 2100 if ( isset( $filter['orderby'] ) ) { 2101 $query['orderby'] = $filter['orderby']; 2102 2103 if ( isset( $filter['order'] ) ) 2104 $query['order'] = $filter['order']; 2105 } 2106 2107 if ( isset( $filter['role'] ) ) { 2108 if ( get_role( $filter['role'] ) === null ) 2109 return new IXR_Error( 403, __( 'The role specified is not valid' ) ); 2110 2111 $query['role'] = $filter['role']; 2112 } 2113 2114 if ( isset( $filter['who'] ) ) { 2115 $query['who'] = $filter['who']; 2116 } 2117 2118 $users = get_users( $query ); 2119 2120 $_users = array(); 2121 foreach ( $users as $user_data ) { 2122 if ( current_user_can( 'edit_user', $user_data->ID ) ) 2123 $_users[] = $this->_prepare_user( $user_data, $fields ); 2124 } 2125 return $_users; 2126 } 2127 2128 /** 2129 * Retrieve information about the requesting user. 2130 * 2131 * @uses get_userdata() 2132 * @param array $args Method parameters. Contains: 2133 * - int $blog_id 2134 * - string $username 2135 * - string $password 2136 * - array $fields optional 2137 * @return array (@see wp_getUser) 2138 */ 2139 function wp_getProfile( $args ) { 2140 if ( ! $this->minimum_args( $args, 3 ) ) 2141 return $this->error; 2142 2143 $this->escape( $args ); 2144 2145 $blog_id = (int) $args[0]; 2146 $username = $args[1]; 2147 $password = $args[2]; 2148 2149 if ( isset( $args[3] ) ) 2150 $fields = $args[3]; 2151 else 2152 $fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getProfile' ); 2153 2154 if ( ! $user = $this->login( $username, $password ) ) 2155 return $this->error; 2156 2157 do_action( 'xmlrpc_call', 'wp.getProfile' ); 2158 2159 if ( ! current_user_can( 'edit_user', $user->ID ) ) 2160 return new IXR_Error( 401, __( 'Sorry, you cannot edit your profile.' ) ); 2161 2162 $user_data = get_userdata( $user->ID ); 2163 2164 return $this->_prepare_user( $user_data, $fields ); 2165 } 2166 2167 /** 2168 * Edit user's profile. 2169 * 2170 * @uses wp_update_user() 2171 * @param array $args Method parameters. Contains: 2172 * - int $blog_id 2173 * - string $username 2174 * - string $password 2175 * - array $content_struct 2176 * It can optionally contain: 2177 * - 'first_name' 2178 * - 'last_name' 2179 * - 'website' 2180 * - 'display_name' 2181 * - 'nickname' 2182 * - 'nicename' 2183 * - 'bio' 2184 * @return bool True, on success. 2185 */ 2186 function wp_editProfile( $args ) { 2187 if ( ! $this->minimum_args( $args, 4 ) ) 2188 return $this->error; 2189 2190 $this->escape( $args ); 2191 2192 $blog_id = (int) $args[0]; 2193 $username = $args[1]; 2194 $password = $args[2]; 2195 $content_struct = $args[3]; 2196 2197 if ( ! $user = $this->login( $username, $password ) ) 2198 return $this->error; 2199 2200 do_action( 'xmlrpc_call', 'wp.editProfile' ); 2201 2202 if ( ! current_user_can( 'edit_user', $user->ID ) ) 2203 return new IXR_Error( 401, __( 'Sorry, you cannot edit your profile.' ) ); 2204 2205 // holds data of the user 2206 $user_data = array(); 2207 $user_data['ID'] = $user->ID; 2208 2209 // only set the user details if it was given 2210 if ( isset( $content_struct['first_name'] ) ) 2211 $user_data['first_name'] = $content_struct['first_name']; 2212 2213 if ( isset( $content_struct['last_name'] ) ) 2214 $user_data['last_name'] = $content_struct['last_name']; 2215 2216 if ( isset( $content_struct['url'] ) ) 2217 $user_data['user_url'] = $content_struct['url']; 2218 2219 if ( isset( $content_struct['display_name'] ) ) 2220 $user_data['display_name'] = $content_struct['display_name']; 2221 2222 if ( isset( $content_struct['nickname'] ) ) 2223 $user_data['nickname'] = $content_struct['nickname']; 2224 2225 if ( isset( $content_struct['nicename'] ) ) 2226 $user_data['user_nicename'] = $content_struct['nicename']; 2227 2228 if ( isset( $content_struct['bio'] ) ) 2229 $user_data['description'] = $content_struct['bio']; 2230 2231 $result = wp_update_user( $user_data ); 2232 2233 if ( is_wp_error( $result ) ) 2234 return new IXR_Error( 500, $result->get_error_message() ); 2235 2236 if ( ! $result ) 2237 return new IXR_Error( 500, __( 'Sorry, the user cannot be updated.' ) ); 2238 2239 return true; 2240 } 2241 2242 /** 2243 * Retrieve page. 2244 * 2245 * @since 2.2.0 2246 * 2247 * @param array $args Method parameters. Contains: 2248 * - blog_id 2249 * - page_id 2250 * - username 2251 * - password 2252 * @return array 2253 */ 2254 function wp_getPage($args) { 2255 $this->escape($args); 2256 2257 $blog_id = (int) $args[0]; 2258 $page_id = (int) $args[1]; 2259 $username = $args[2]; 2260 $password = $args[3]; 2261 2262 if ( !$user = $this->login($username, $password) ) { 2263 return $this->error; 2264 } 2265 2266 $page = get_post($page_id); 2267 if ( ! $page ) 2268 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 2269 2270 if ( !current_user_can( 'edit_page', $page_id ) ) 2271 return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) ); 2272 2273 do_action('xmlrpc_call', 'wp.getPage'); 2274 2275 // If we found the page then format the data. 2276 if ( $page->ID && ($page->post_type == 'page') ) { 2277 return $this->_prepare_page( $page ); 2278 } 2279 // If the page doesn't exist indicate that. 2280 else { 2281 return(new IXR_Error(404, __('Sorry, no such page.'))); 2282 } 2283 } 2284 2285 /** 2286 * Retrieve Pages. 2287 * 2288 * @since 2.2.0 2289 * 2290 * @param array $args Method parameters. Contains: 2291 * - blog_id 2292 * - username 2293 * - password 2294 * - num_pages 2295 * @return array 2296 */ 2297 function wp_getPages($args) { 2298 $this->escape($args); 2299 2300 $blog_id = (int) $args[0]; 2301 $username = $args[1]; 2302 $password = $args[2]; 2303 $num_pages = isset($args[3]) ? (int) $args[3] : 10; 2304 2305 if ( !$user = $this->login($username, $password) ) 2306 return $this->error; 2307 2308 if ( !current_user_can( 'edit_pages' ) ) 2309 return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); 2310 2311 do_action('xmlrpc_call', 'wp.getPages'); 2312 2313 $pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) ); 2314 $num_pages = count($pages); 2315 2316 // If we have pages, put together their info. 2317 if ( $num_pages >= 1 ) { 2318 $pages_struct = array(); 2319 2320 foreach ($pages as $page) { 2321 if ( current_user_can( 'edit_page', $page->ID ) ) 2322 $pages_struct[] = $this->_prepare_page( $page ); 2323 } 2324 2325 return($pages_struct); 2326 } 2327 // If no pages were found return an error. 2328 else { 2329 return(array()); 2330 } 2331 } 2332 2333 /** 2334 * Create new page. 2335 * 2336 * @since 2.2.0 2337 * 2338 * @param array $args Method parameters. See {@link wp_xmlrpc_server::mw_newPost()} 2339 * @return unknown 2340 */ 2341 function wp_newPage($args) { 2342 // Items not escaped here will be escaped in newPost. 2343 $username = $this->escape($args[1]); 2344 $password = $this->escape($args[2]); 2345 $page = $args[3]; 2346 $publish = $args[4]; 2347 2348 if ( !$user = $this->login($username, $password) ) 2349 return $this->error; 2350 2351 do_action('xmlrpc_call', 'wp.newPage'); 2352 2353 // Mark this as content for a page. 2354 $args[3]["post_type"] = 'page'; 2355 2356 // Let mw_newPost do all of the heavy lifting. 2357 return($this->mw_newPost($args)); 2358 } 2359 2360 /** 2361 * Delete page. 2362 * 2363 * @since 2.2.0 2364 * 2365 * @param array $args Method parameters. 2366 * @return bool True, if success. 2367 */ 2368 function wp_deletePage($args) { 2369 $this->escape($args); 2370 2371 $blog_id = (int) $args[0]; 2372 $username = $args[1]; 2373 $password = $args[2]; 2374 $page_id = (int) $args[3]; 2375 2376 if ( !$user = $this->login($username, $password) ) 2377 return $this->error; 2378 2379 do_action('xmlrpc_call', 'wp.deletePage'); 2380 2381 // Get the current page based on the page_id and 2382 // make sure it is a page and not a post. 2383 $actual_page = get_post($page_id, ARRAY_A); 2384 if ( !$actual_page || ($actual_page['post_type'] != 'page') ) 2385 return(new IXR_Error(404, __('Sorry, no such page.'))); 2386 2387 // Make sure the user can delete pages. 2388 if ( !current_user_can('delete_page', $page_id) ) 2389 return(new IXR_Error(401, __('Sorry, you do not have the right to delete this page.'))); 2390 2391 // Attempt to delete the page. 2392 $result = wp_delete_post($page_id); 2393 if ( !$result ) 2394 return(new IXR_Error(500, __('Failed to delete the page.'))); 2395 2396 do_action( 'xmlrpc_call_success_wp_deletePage', $page_id, $args ); 2397 2398 return(true); 2399 } 2400 2401 /** 2402 * Edit page. 2403 * 2404 * @since 2.2.0 2405 * 2406 * @param array $args Method parameters. 2407 * @return unknown 2408 */ 2409 function wp_editPage($args) { 2410 // Items not escaped here will be escaped in editPost. 2411 $blog_id = (int) $args[0]; 2412 $page_id = (int) $this->escape($args[1]); 2413 $username = $this->escape($args[2]); 2414 $password = $this->escape($args[3]); 2415 $content = $args[4]; 2416 $publish = $args[5]; 2417 2418 if ( !$user = $this->login($username, $password) ) 2419 return $this->error; 2420 2421 do_action('xmlrpc_call', 'wp.editPage'); 2422 2423 // Get the page data and make sure it is a page. 2424 $actual_page = get_post($page_id, ARRAY_A); 2425 if ( !$actual_page || ($actual_page['post_type'] != 'page') ) 2426 return(new IXR_Error(404, __('Sorry, no such page.'))); 2427 2428 // Make sure the user is allowed to edit pages. 2429 if ( !current_user_can('edit_page', $page_id) ) 2430 return(new IXR_Error(401, __('Sorry, you do not have the right to edit this page.'))); 2431 2432 // Mark this as content for a page. 2433 $content['post_type'] = 'page'; 2434 2435 // Arrange args in the way mw_editPost understands. 2436 $args = array( 2437 $page_id, 2438 $username, 2439 $password, 2440 $content, 2441 $publish 2442 ); 2443 2444 // Let mw_editPost do all of the heavy lifting. 2445 return($this->mw_editPost($args)); 2446 } 2447 2448 /** 2449 * Retrieve page list. 2450 * 2451 * @since 2.2.0 2452 * 2453 * @param array $args Method parameters. 2454 * @return unknown 2455 */ 2456 function wp_getPageList($args) { 2457 global $wpdb; 2458 2459 $this->escape($args); 2460 2461 $blog_id = (int) $args[0]; 2462 $username = $args[1]; 2463 $password = $args[2]; 2464 2465 if ( !$user = $this->login($username, $password) ) 2466 return $this->error; 2467 2468 if ( !current_user_can( 'edit_pages' ) ) 2469 return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) ); 2470 2471 do_action('xmlrpc_call', 'wp.getPageList'); 2472 2473 // Get list of pages ids and titles 2474 $page_list = $wpdb->get_results(" 2475 SELECT ID page_id, 2476 post_title page_title, 2477 post_parent page_parent_id, 2478 post_date_gmt, 2479 post_date, 2480 post_status 2481 FROM {$wpdb->posts} 2482 WHERE post_type = 'page' 2483 ORDER BY ID 2484 "); 2485 2486 // The date needs to be formatted properly. 2487 $num_pages = count($page_list); 2488 for ( $i = 0; $i < $num_pages; $i++ ) { 2489 $page_list[$i]->dateCreated = $this->_convert_date( $page_list[$i]->post_date ); 2490 $page_list[$i]->date_created_gmt = $this->_convert_date_gmt( $page_list[$i]->post_date_gmt, $page_list[$i]->post_date ); 2491 2492 unset($page_list[$i]->post_date_gmt); 2493 unset($page_list[$i]->post_date); 2494 unset($page_list[$i]->post_status); 2495 } 2496 2497 return($page_list); 2498 } 2499 2500 /** 2501 * Retrieve authors list. 2502 * 2503 * @since 2.2.0 2504 * 2505 * @param array $args Method parameters. 2506 * @return array 2507 */ 2508 function wp_getAuthors($args) { 2509 2510 $this->escape($args); 2511 2512 $blog_id = (int) $args[0]; 2513 $username = $args[1]; 2514 $password = $args[2]; 2515 2516 if ( !$user = $this->login($username, $password) ) 2517 return $this->error; 2518 2519 if ( !current_user_can('edit_posts') ) 2520 return(new IXR_Error(401, __('Sorry, you cannot edit posts on this site.'))); 2521 2522 do_action('xmlrpc_call', 'wp.getAuthors'); 2523 2524 $authors = array(); 2525 foreach ( get_users( array( 'fields' => array('ID','user_login','display_name') ) ) as $user ) { 2526 $authors[] = array( 2527 'user_id' => $user->ID, 2528 'user_login' => $user->user_login, 2529 'display_name' => $user->display_name 2530 ); 2531 } 2532 2533 return $authors; 2534 } 2535 2536 /** 2537 * Get list of all tags 2538 * 2539 * @since 2.7.0 2540 * 2541 * @param array $args Method parameters. 2542 * @return array 2543 */ 2544 function wp_getTags( $args ) { 2545 $this->escape( $args ); 2546 2547 $blog_id = (int) $args[0]; 2548 $username = $args[1]; 2549 $password = $args[2]; 2550 2551 if ( !$user = $this->login($username, $password) ) 2552 return $this->error; 2553 2554 if ( !current_user_can( 'edit_posts' ) ) 2555 return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view tags.' ) ); 2556 2557 do_action( 'xmlrpc_call', 'wp.getKeywords' ); 2558 2559 $tags = array(); 2560 2561 if ( $all_tags = get_tags() ) { 2562 foreach( (array) $all_tags as $tag ) { 2563 $struct['tag_id'] = $tag->term_id; 2564 $struct['name'] = $tag->name; 2565 $struct['count'] = $tag->count; 2566 $struct['slug'] = $tag->slug; 2567 $struct['html_url'] = esc_html( get_tag_link( $tag->term_id ) ); 2568 $struct['rss_url'] = esc_html( get_tag_feed_link( $tag->term_id ) ); 2569 2570 $tags[] = $struct; 2571 } 2572 } 2573 2574 return $tags; 2575 } 2576 2577 /** 2578 * Create new category. 2579 * 2580 * @since 2.2.0 2581 * 2582 * @param array $args Method parameters. 2583 * @return int Category ID. 2584 */ 2585 function wp_newCategory($args) { 2586 $this->escape($args); 2587 2588 $blog_id = (int) $args[0]; 2589 $username = $args[1]; 2590 $password = $args[2]; 2591 $category = $args[3]; 2592 2593 if ( !$user = $this->login($username, $password) ) 2594 return $this->error; 2595 2596 do_action('xmlrpc_call', 'wp.newCategory'); 2597 2598 // Make sure the user is allowed to add a category. 2599 if ( !current_user_can('manage_categories') ) 2600 return(new IXR_Error(401, __('Sorry, you do not have the right to add a category.'))); 2601 2602 // If no slug was provided make it empty so that 2603 // WordPress will generate one. 2604 if ( empty($category['slug']) ) 2605 $category['slug'] = ''; 2606 2607 // If no parent_id was provided make it empty 2608 // so that it will be a top level page (no parent). 2609 if ( !isset($category['parent_id']) ) 2610 $category['parent_id'] = ''; 2611 2612 // If no description was provided make it empty. 2613 if ( empty($category["description"]) ) 2614 $category["description"] = ""; 2615 2616 $new_category = array( 2617 'cat_name' => $category['name'], 2618 'category_nicename' => $category['slug'], 2619 'category_parent' => $category['parent_id'], 2620 'category_description' => $category['description'] 2621 ); 2622 2623 $cat_id = wp_insert_category($new_category, true); 2624 if ( is_wp_error( $cat_id ) ) { 2625 if ( 'term_exists' == $cat_id->get_error_code() ) 2626 return (int) $cat_id->get_error_data(); 2627 else 2628 return(new IXR_Error(500, __('Sorry, the new category failed.'))); 2629 } elseif ( ! $cat_id ) { 2630 return(new IXR_Error(500, __('Sorry, the new category failed.'))); 2631 } 2632 2633 do_action( 'xmlrpc_call_success_wp_newCategory', $cat_id, $args ); 2634 2635 return $cat_id; 2636 } 2637 2638 /** 2639 * Remove category. 2640 * 2641 * @since 2.5.0 2642 * 2643 * @param array $args Method parameters. 2644 * @return mixed See {@link wp_delete_term()} for return info. 2645 */ 2646 function wp_deleteCategory($args) { 2647 $this->escape($args); 2648 2649 $blog_id = (int) $args[0]; 2650 $username = $args[1]; 2651 $password = $args[2]; 2652 $category_id = (int) $args[3]; 2653 2654 if ( !$user = $this->login($username, $password) ) 2655 return $this->error; 2656 2657 do_action('xmlrpc_call', 'wp.deleteCategory'); 2658 2659 if ( !current_user_can('manage_categories') ) 2660 return new IXR_Error( 401, __( 'Sorry, you do not have the right to delete a category.' ) ); 2661 2662 $status = wp_delete_term( $category_id, 'category' ); 2663 2664 if( true == $status ) 2665 do_action( 'xmlrpc_call_success_wp_deleteCategory', $category_id, $args ); 2666 2667 return $status; 2668 } 2669 2670 /** 2671 * Retrieve category list. 2672 * 2673 * @since 2.2.0 2674 * 2675 * @param array $args Method parameters. 2676 * @return array 2677 */ 2678 function wp_suggestCategories($args) { 2679 $this->escape($args); 2680 2681 $blog_id = (int) $args[0]; 2682 $username = $args[1]; 2683 $password = $args[2]; 2684 $category = $args[3]; 2685 $max_results = (int) $args[4]; 2686 2687 if ( !$user = $this->login($username, $password) ) 2688 return $this->error; 2689 2690 if ( !current_user_can( 'edit_posts' ) ) 2691 return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this site in order to view categories.' ) ); 2692 2693 do_action('xmlrpc_call', 'wp.suggestCategories'); 2694 2695 $category_suggestions = array(); 2696 $args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category); 2697 foreach ( (array) get_categories($args) as $cat ) { 2698 $category_suggestions[] = array( 2699 'category_id' => $cat->term_id, 2700 'category_name' => $cat->name 2701 ); 2702 } 2703 2704 return($category_suggestions); 2705 } 2706 2707 /** 2708 * Retrieve comment. 2709 * 2710 * @since 2.7.0 2711 * 2712 * @param array $args Method parameters. 2713 * @return array 2714 */ 2715 function wp_getComment($args) { 2716 $this->escape($args); 2717 2718 $blog_id = (int) $args[0]; 2719 $username = $args[1]; 2720 $password = $args[2]; 2721 $comment_id = (int) $args[3]; 2722 2723 if ( !$user = $this->login($username, $password) ) 2724 return $this->error; 2725 2726 if ( !current_user_can( 'moderate_comments' ) ) 2727 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 2728 2729 do_action('xmlrpc_call', 'wp.getComment'); 2730 2731 if ( ! $comment = get_comment($comment_id) ) 2732 return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 2733 2734 return $this->_prepare_comment( $comment ); 2735 } 2736 2737 /** 2738 * Retrieve comments. 2739 * 2740 * Besides the common blog_id, username, and password arguments, it takes a filter 2741 * array as last argument. 2742 * 2743 * Accepted 'filter' keys are 'status', 'post_id', 'offset', and 'number'. 2744 * 2745 * The defaults are as follows: 2746 * - 'status' - Default is ''. Filter by status (e.g., 'approve', 'hold') 2747 * - 'post_id' - Default is ''. The post where the comment is posted. Empty string shows all comments. 2748 * - 'number' - Default is 10. Total number of media items to retrieve. 2749 * - 'offset' - Default is 0. See {@link WP_Query::query()} for more. 2750 * 2751 * @since 2.7.0 2752 * 2753 * @param array $args Method parameters. 2754 * @return array. Contains a collection of comments. See {@link wp_xmlrpc_server::wp_getComment()} for a description of each item contents 2755 */ 2756 function wp_getComments($args) { 2757 $this->escape($args); 2758 2759 $blog_id = (int) $args[0]; 2760 $username = $args[1]; 2761 $password = $args[2]; 2762 $struct = isset( $args[3] ) ? $args[3] : array(); 2763 2764 if ( !$user = $this->login($username, $password) ) 2765 return $this->error; 2766 2767 if ( !current_user_can( 'moderate_comments' ) ) 2768 return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) ); 2769 2770 do_action('xmlrpc_call', 'wp.getComments'); 2771 2772 if ( isset($struct['status']) ) 2773 $status = $struct['status']; 2774 else 2775 $status = ''; 2776 2777 $post_id = ''; 2778 if ( isset($struct['post_id']) ) 2779 $post_id = absint($struct['post_id']); 2780 2781 $offset = 0; 2782 if ( isset($struct['offset']) ) 2783 $offset = absint($struct['offset']); 2784 2785 $number = 10; 2786 if ( isset($struct['number']) ) 2787 $number = absint($struct['number']); 2788 2789 $comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) ); 2790 2791 $comments_struct = array(); 2792 2793 foreach ( $comments as $comment ) { 2794 $comments_struct[] = $this->_prepare_comment( $comment ); 2795 } 2796 2797 return $comments_struct; 2798 } 2799 2800 /** 2801 * Delete a comment. 2802 * 2803 * By default, the comment will be moved to the trash instead of deleted. 2804 * See {@link wp_delete_comment()} for more information on 2805 * this behavior. 2806 * 2807 * @since 2.7.0 2808 * 2809 * @param array $args Method parameters. Contains: 2810 * - blog_id 2811 * - username 2812 * - password 2813 * - comment_id 2814 * @return mixed {@link wp_delete_comment()} 2815 */ 2816 function wp_deleteComment($args) { 2817 $this->escape($args); 2818 2819 $blog_id = (int) $args[0]; 2820 $username = $args[1]; 2821 $password = $args[2]; 2822 $comment_ID = (int) $args[3]; 2823 2824 if ( !$user = $this->login($username, $password) ) 2825 return $this->error; 2826 2827 if ( !current_user_can( 'moderate_comments' ) ) 2828 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 2829 2830 if ( ! get_comment($comment_ID) ) 2831 return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 2832 2833 if ( !current_user_can( 'edit_comment', $comment_ID ) ) 2834 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 2835 2836 do_action('xmlrpc_call', 'wp.deleteComment'); 2837 2838 $status = wp_delete_comment( $comment_ID ); 2839 2840 if( true == $status ) 2841 do_action( 'xmlrpc_call_success_wp_deleteComment', $comment_ID, $args ); 2842 2843 return $status; 2844 } 2845 2846 /** 2847 * Edit comment. 2848 * 2849 * Besides the common blog_id, username, and password arguments, it takes a 2850 * comment_id integer and a content_struct array as last argument. 2851 * 2852 * The allowed keys in the content_struct array are: 2853 * - 'author' 2854 * - 'author_url' 2855 * - 'author_email' 2856 * - 'content' 2857 * - 'date_created_gmt' 2858 * - 'status'. Common statuses are 'approve', 'hold', 'spam'. See {@link get_comment_statuses()} for more details 2859 * 2860 * @since 2.7.0 2861 * 2862 * @param array $args. Contains: 2863 * - blog_id 2864 * - username 2865 * - password 2866 * - comment_id 2867 * - content_struct 2868 * @return bool True, on success. 2869 */ 2870 function wp_editComment($args) { 2871 $this->escape($args); 2872 2873 $blog_id = (int) $args[0]; 2874 $username = $args[1]; 2875 $password = $args[2]; 2876 $comment_ID = (int) $args[3]; 2877 $content_struct = $args[4]; 2878 2879 if ( !$user = $this->login($username, $password) ) 2880 return $this->error; 2881 2882 if ( !current_user_can( 'moderate_comments' ) ) 2883 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 2884 2885 if ( ! get_comment($comment_ID) ) 2886 return new IXR_Error( 404, __( 'Invalid comment ID.' ) ); 2887 2888 if ( !current_user_can( 'edit_comment', $comment_ID ) ) 2889 return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) ); 2890 2891 do_action('xmlrpc_call', 'wp.editComment'); 2892 2893 if ( isset($content_struct['status']) ) { 2894 $statuses = get_comment_statuses(); 2895 $statuses = array_keys($statuses); 2896 2897 if ( ! in_array($content_struct['status'], $statuses) ) 2898 return new IXR_Error( 401, __( 'Invalid comment status.' ) ); 2899 $comment_approved = $content_struct['status']; 2900 } 2901 2902 // Do some timestamp voodoo 2903 if ( !empty( $content_struct['date_created_gmt'] ) ) { 2904 // We know this is supposed to be GMT, so we're going to slap that Z on there by force 2905 $dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z'; 2906 $comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 2907 $comment_date_gmt = iso8601_to_datetime($dateCreated, 'GMT'); 2908 } 2909 2910 if ( isset($content_struct['content']) ) 2911 $comment_content = $content_struct['content']; 2912 2913 if ( isset($content_struct['author']) ) 2914 $comment_author = $content_struct['author']; 2915 2916 if ( isset($content_struct['author_url']) ) 2917 $comment_author_url = $content_struct['author_url']; 2918 2919 if ( isset($content_struct['author_email']) ) 2920 $comment_author_email = $content_struct['author_email']; 2921 2922 // We've got all the data -- post it: 2923 $comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url'); 2924 2925 $result = wp_update_comment($comment); 2926 if ( is_wp_error( $result ) ) 2927 return new IXR_Error(500, $result->get_error_message()); 2928 2929 if ( !$result ) 2930 return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.')); 2931 2932 do_action( 'xmlrpc_call_success_wp_editComment', $comment_ID, $args ); 2933 2934 return true; 2935 } 2936 2937 /** 2938 * Create new comment. 2939 * 2940 * @since 2.7.0 2941 * 2942 * @param array $args Method parameters. 2943 * @return mixed {@link wp_new_comment()} 2944 */ 2945 function wp_newComment($args) { 2946 global $wpdb; 2947 2948 $this->escape($args); 2949 2950 $blog_id = (int) $args[0]; 2951 $username = $args[1]; 2952 $password = $args[2]; 2953 $post = $args[3]; 2954 $content_struct = $args[4]; 2955 2956 $allow_anon = apply_filters('xmlrpc_allow_anonymous_comments', false); 2957 2958 $user = $this->login($username, $password); 2959 2960 if ( !$user ) { 2961 $logged_in = false; 2962 if ( $allow_anon && get_option('comment_registration') ) 2963 return new IXR_Error( 403, __( 'You must be registered to comment' ) ); 2964 else if ( !$allow_anon ) 2965 return $this->error; 2966 } else { 2967 $logged_in = true; 2968 } 2969 2970 if ( is_numeric($post) ) 2971 $post_id = absint($post); 2972 else 2973 $post_id = url_to_postid($post); 2974 2975 if ( ! $post_id ) 2976 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 2977 2978 if ( ! get_post($post_id) ) 2979 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 2980 2981 $comment['comment_post_ID'] = $post_id; 2982 2983 if ( $logged_in ) { 2984 $comment['comment_author'] = $this->escape( $user->display_name ); 2985 $comment['comment_author_email'] = $this->escape( $user->user_email ); 2986 $comment['comment_author_url'] = $this->escape( $user->user_url ); 2987 $comment['user_ID'] = $user->ID; 2988 } else { 2989 $comment['comment_author'] = ''; 2990 if ( isset($content_struct['author']) ) 2991 $comment['comment_author'] = $content_struct['author']; 2992 2993 $comment['comment_author_email'] = ''; 2994 if ( isset($content_struct['author_email']) ) 2995 $comment['comment_author_email'] = $content_struct['author_email']; 2996 2997 $comment['comment_author_url'] = ''; 2998 if ( isset($content_struct['author_url']) ) 2999 $comment['comment_author_url'] = $content_struct['author_url']; 3000 3001 $comment['user_ID'] = 0; 3002 3003 if ( get_option('require_name_email') ) { 3004 if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] ) 3005 return new IXR_Error( 403, __( 'Comment author name and email are required' ) ); 3006 elseif ( !is_email($comment['comment_author_email']) ) 3007 return new IXR_Error( 403, __( 'A valid email address is required' ) ); 3008 } 3009 } 3010 3011 $comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0; 3012 3013 $comment['comment_content'] = isset($content_struct['content']) ? $content_struct['content'] : null; 3014 3015 do_action('xmlrpc_call', 'wp.newComment'); 3016 3017 $comment_ID = wp_new_comment( $comment ); 3018 3019 do_action( 'xmlrpc_call_success_wp_newComment', $comment_ID, $args ); 3020 3021 return $comment_ID; 3022 } 3023 3024 /** 3025 * Retrieve all of the comment status. 3026 * 3027 * @since 2.7.0 3028 * 3029 * @param array $args Method parameters. 3030 * @return array 3031 */ 3032 function wp_getCommentStatusList($args) { 3033 $this->escape( $args ); 3034 3035 $blog_id = (int) $args[0]; 3036 $username = $args[1]; 3037 $password = $args[2]; 3038 3039 if ( !$user = $this->login($username, $password) ) 3040 return $this->error; 3041 3042 if ( !current_user_can( 'moderate_comments' ) ) 3043 return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 3044 3045 do_action('xmlrpc_call', 'wp.getCommentStatusList'); 3046 3047 return get_comment_statuses(); 3048 } 3049 3050 /** 3051 * Retrieve comment count. 3052 * 3053 * @since 2.5.0 3054 * 3055 * @param array $args Method parameters. 3056 * @return array 3057 */ 3058 function wp_getCommentCount( $args ) { 3059 $this->escape($args); 3060 3061 $blog_id = (int) $args[0]; 3062 $username = $args[1]; 3063 $password = $args[2]; 3064 $post_id = (int) $args[3]; 3065 3066 if ( !$user = $this->login($username, $password) ) 3067 return $this->error; 3068 3069 if ( !current_user_can( 'edit_posts' ) ) 3070 return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) ); 3071 3072 do_action('xmlrpc_call', 'wp.getCommentCount'); 3073 3074 $count = wp_count_comments( $post_id ); 3075 return array( 3076 'approved' => $count->approved, 3077 'awaiting_moderation' => $count->moderated, 3078 'spam' => $count->spam, 3079 'total_comments' => $count->total_comments 3080 ); 3081 } 3082 3083 /** 3084 * Retrieve post statuses. 3085 * 3086 * @since 2.5.0 3087 * 3088 * @param array $args Method parameters. 3089 * @return array 3090 */ 3091 function wp_getPostStatusList( $args ) { 3092 $this->escape( $args ); 3093 3094 $blog_id = (int) $args[0]; 3095 $username = $args[1]; 3096 $password = $args[2]; 3097 3098 if ( !$user = $this->login($username, $password) ) 3099 return $this->error; 3100 3101 if ( !current_user_can( 'edit_posts' ) ) 3102 return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 3103 3104 do_action('xmlrpc_call', 'wp.getPostStatusList'); 3105 3106 return get_post_statuses(); 3107 } 3108 3109 /** 3110 * Retrieve page statuses. 3111 * 3112 * @since 2.5.0 3113 * 3114 * @param array $args Method parameters. 3115 * @return array 3116 */ 3117 function wp_getPageStatusList( $args ) { 3118 $this->escape( $args ); 3119 3120 $blog_id = (int) $args[0]; 3121 $username = $args[1]; 3122 $password = $args[2]; 3123 3124 if ( !$user = $this->login($username, $password) ) 3125 return $this->error; 3126 3127 if ( !current_user_can( 'edit_pages' ) ) 3128 return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 3129 3130 do_action('xmlrpc_call', 'wp.getPageStatusList'); 3131 3132 return get_page_statuses(); 3133 } 3134 3135 /** 3136 * Retrieve page templates. 3137 * 3138 * @since 2.6.0 3139 * 3140 * @param array $args Method parameters. 3141 * @return array 3142 */ 3143 function wp_getPageTemplates( $args ) { 3144 $this->escape( $args ); 3145 3146 $blog_id = (int) $args[0]; 3147 $username = $args[1]; 3148 $password = $args[2]; 3149 3150 if ( !$user = $this->login($username, $password) ) 3151 return $this->error; 3152 3153 if ( !current_user_can( 'edit_pages' ) ) 3154 return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 3155 3156 $templates = get_page_templates(); 3157 $templates['Default'] = 'default'; 3158 3159 return $templates; 3160 } 3161 3162 /** 3163 * Retrieve blog options. 3164 * 3165 * @since 2.6.0 3166 * 3167 * @param array $args Method parameters. 3168 * @return array 3169 */ 3170 function wp_getOptions( $args ) { 3171 $this->escape( $args ); 3172 3173 $blog_id = (int) $args[0]; 3174 $username = $args[1]; 3175 $password = $args[2]; 3176 $options = isset( $args[3] ) ? (array) $args[3] : array(); 3177 3178 if ( !$user = $this->login($username, $password) ) 3179 return $this->error; 3180 3181 // If no specific options where asked for, return all of them 3182 if ( count( $options ) == 0 ) 3183 $options = array_keys($this->blog_options); 3184 3185 return $this->_getOptions($options); 3186 } 3187 3188 /** 3189 * Retrieve blog options value from list. 3190 * 3191 * @since 2.6.0 3192 * 3193 * @param array $options Options to retrieve. 3194 * @return array 3195 */ 3196 function _getOptions($options) { 3197 $data = array(); 3198 $can_manage = current_user_can( 'manage_options' ); 3199 foreach ( $options as $option ) { 3200 if ( array_key_exists( $option, $this->blog_options ) ) { 3201 $data[$option] = $this->blog_options[$option]; 3202 //Is the value static or dynamic? 3203 if ( isset( $data[$option]['option'] ) ) { 3204 $data[$option]['value'] = get_option( $data[$option]['option'] ); 3205 unset($data[$option]['option']); 3206 } 3207 3208 if ( ! $can_manage ) 3209 $data[$option]['readonly'] = true; 3210 } 3211 } 3212 3213 return $data; 3214 } 3215 3216 /** 3217 * Update blog options. 3218 * 3219 * @since 2.6.0 3220 * 3221 * @param array $args Method parameters. 3222 * @return unknown 3223 */ 3224 function wp_setOptions( $args ) { 3225 $this->escape( $args ); 3226 3227 $blog_id = (int) $args[0]; 3228 $username = $args[1]; 3229 $password = $args[2]; 3230 $options = (array) $args[3]; 3231 3232 if ( !$user = $this->login($username, $password) ) 3233 return $this->error; 3234 3235 if ( !current_user_can( 'manage_options' ) ) 3236 return new IXR_Error( 403, __( 'You are not allowed to update options.' ) ); 3237 3238 foreach ( $options as $o_name => $o_value ) { 3239 $option_names[] = $o_name; 3240 if ( !array_key_exists( $o_name, $this->blog_options ) ) 3241 continue; 3242 3243 if ( $this->blog_options[$o_name]['readonly'] == true ) 3244 continue; 3245 3246 update_option( $this->blog_options[$o_name]['option'], $o_value ); 3247 } 3248 3249 //Now return the updated values 3250 return $this->_getOptions($option_names); 3251 } 3252 3253 /** 3254 * Retrieve a media item by ID 3255 * 3256 * @since 3.1.0 3257 * 3258 * @param array $args Method parameters. Contains: 3259 * - blog_id 3260 * - username 3261 * - password 3262 * - attachment_id 3263 * @return array. Associative array containing: 3264 * - 'date_created_gmt' 3265 * - 'parent' 3266 * - 'link' 3267 * - 'thumbnail' 3268 * - 'title' 3269 * - 'caption' 3270 * - 'description' 3271 * - 'metadata' 3272 */ 3273 function wp_getMediaItem($args) { 3274 $this->escape($args); 3275 3276 $blog_id = (int) $args[0]; 3277 $username = $args[1]; 3278 $password = $args[2]; 3279 $attachment_id = (int) $args[3]; 3280 3281 if ( !$user = $this->login($username, $password) ) 3282 return $this->error; 3283 3284 if ( !current_user_can( 'upload_files' ) ) 3285 return new IXR_Error( 403, __( 'You do not have permission to upload files.' ) ); 3286 3287 do_action('xmlrpc_call', 'wp.getMediaItem'); 3288 3289 if ( ! $attachment = get_post($attachment_id) ) 3290 return new IXR_Error( 404, __( 'Invalid attachment ID.' ) ); 3291 3292 return $this->_prepare_media_item( $attachment ); 3293 } 3294 3295 /** 3296 * Retrieves a collection of media library items (or attachments) 3297 * 3298 * Besides the common blog_id, username, and password arguments, it takes a filter 3299 * array as last argument. 3300 * 3301 * Accepted 'filter' keys are 'parent_id', 'mime_type', 'offset', and 'number'. 3302 * 3303 * The defaults are as follows: 3304 * - 'number' - Default is 5. Total number of media items to retrieve. 3305 * - 'offset' - Default is 0. See {@link WP_Query::query()} for more. 3306 * - 'parent_id' - Default is ''. The post where the media item is attached. Empty string shows all media items. 0 shows unattached media items. 3307 * - 'mime_type' - Default is ''. Filter by mime type (e.g., 'image/jpeg', 'application/pdf') 3308 * 3309 * @since 3.1.0 3310 * 3311 * @param array $args Method parameters. Contains: 3312 * - blog_id 3313 * - username 3314 * - password 3315 * - filter 3316 * @return array. Contains a collection of media items. See {@link wp_xmlrpc_server::wp_getMediaItem()} for a description of each item contents 3317 */ 3318 function wp_getMediaLibrary($args) { 3319 $this->escape($args); 3320 3321 $blog_id = (int) $args[0]; 3322 $username = $args[1]; 3323 $password = $args[2]; 3324 $struct = isset( $args[3] ) ? $args[3] : array() ; 3325 3326 if ( !$user = $this->login($username, $password) ) 3327 return $this->error; 3328 3329 if ( !current_user_can( 'upload_files' ) ) 3330 return new IXR_Error( 401, __( 'You do not have permission to upload files.' ) ); 3331 3332 do_action('xmlrpc_call', 'wp.getMediaLibrary'); 3333 3334 $parent_id = ( isset($struct['parent_id']) ) ? absint($struct['parent_id']) : '' ; 3335 $mime_type = ( isset($struct['mime_type']) ) ? $struct['mime_type'] : '' ; 3336 $offset = ( isset($struct['offset']) ) ? absint($struct['offset']) : 0 ; 3337 $number = ( isset($struct['number']) ) ? absint($struct['number']) : -1 ; 3338 3339 $attachments = get_posts( array('post_type' => 'attachment', 'post_parent' => $parent_id, 'offset' => $offset, 'numberposts' => $number, 'post_mime_type' => $mime_type ) ); 3340 3341 $attachments_struct = array(); 3342 3343 foreach ($attachments as $attachment ) 3344 $attachments_struct[] = $this->_prepare_media_item( $attachment ); 3345 3346 return $attachments_struct; 3347 } 3348 3349 /** 3350 * Retrieves a list of post formats used by the site 3351 * 3352 * @since 3.1 3353 * 3354 * @param array $args Method parameters. Contains: 3355 * - blog_id 3356 * - username 3357 * - password 3358 * @return array 3359 */ 3360 function wp_getPostFormats( $args ) { 3361 $this->escape( $args ); 3362 3363 $blog_id = (int) $args[0]; 3364 $username = $args[1]; 3365 $password = $args[2]; 3366 3367 if ( !$user = $this->login( $username, $password ) ) 3368 return $this->error; 3369 3370 if ( !current_user_can( 'edit_posts' ) ) 3371 return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) ); 3372 3373 do_action( 'xmlrpc_call', 'wp.getPostFormats' ); 3374 3375 $formats = get_post_format_strings(); 3376 3377 # find out if they want a list of currently supports formats 3378 if ( isset( $args[3] ) && is_array( $args[3] ) ) { 3379 if ( $args[3]['show-supported'] ) { 3380 if ( current_theme_supports( 'post-formats' ) ) { 3381 $supported = get_theme_support( 'post-formats' ); 3382 3383 $data['all'] = $formats; 3384 $data['supported'] = $supported[0]; 3385 3386 $formats = $data; 3387 } 3388 } 3389 } 3390 3391 return $formats; 3392 } 3393 3394 /** 3395 * Retrieves a post type 3396 * 3397 * @since 3.4.0 3398 * 3399 * @uses get_post_type_object() 3400 * @param array $args Method parameters. Contains: 3401 * - int $blog_id 3402 * - string $username 3403 * - string $password 3404 * - string $post_type_name 3405 * - array $fields 3406 * @return array contains: 3407 * - 'labels' 3408 * - 'description' 3409 * - 'capability_type' 3410 * - 'cap' 3411 * - 'map_meta_cap' 3412 * - 'hierarchical' 3413 * - 'menu_position' 3414 * - 'taxonomies' 3415 * - 'supports' 3416 */ 3417 function wp_getPostType( $args ) { 3418 if ( ! $this->minimum_args( $args, 4 ) ) 3419 return $this->error; 3420 3421 $this->escape( $args ); 3422 3423 $blog_id = (int) $args[0]; 3424 $username = $args[1]; 3425 $password = $args[2]; 3426 $post_type_name = $args[3]; 3427 3428 if ( isset( $args[4] ) ) 3429 $fields = $args[4]; 3430 else 3431 $fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostType' ); 3432 3433 if ( !$user = $this->login( $username, $password ) ) 3434 return $this->error; 3435 3436 do_action( 'xmlrpc_call', 'wp.getPostType' ); 3437 3438 if( ! post_type_exists( $post_type_name ) ) 3439 return new IXR_Error( 403, __( 'Invalid post type' ) ); 3440 3441 $post_type = get_post_type_object( $post_type_name ); 3442 3443 if( ! current_user_can( $post_type->cap->edit_posts ) ) 3444 return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post type.' ) ); 3445 3446 return $this->_prepare_post_type( $post_type, $fields ); 3447 } 3448 3449 /** 3450 * Retrieves a post types 3451 * 3452 * @since 3.4.0 3453 * 3454 * @uses get_post_types() 3455 * @param array $args Method parameters. Contains: 3456 * - int $blog_id 3457 * - string $username 3458 * - string $password 3459 * - array $filter 3460 * - array $fields 3461 * @return array 3462 */ 3463 function wp_getPostTypes( $args ) { 3464 if ( ! $this->minimum_args( $args, 3 ) ) 3465 return $this->error; 3466 3467 $this->escape( $args ); 3468 3469 $blog_id = (int) $args[0]; 3470 $username = $args[1]; 3471 $password = $args[2]; 3472 $filter = isset( $args[3] ) ? $args[3] : array( 'public' => true ); 3473 3474 if ( isset( $args[4] ) ) 3475 $fields = $args[4]; 3476 else 3477 $fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostTypes' ); 3478 3479 if ( ! $user = $this->login( $username, $password ) ) 3480 return $this->error; 3481 3482 do_action( 'xmlrpc_call', 'wp.getPostTypes' ); 3483 3484 $post_types = get_post_types( $filter, 'objects' ); 3485 3486 $struct = array(); 3487 3488 foreach( $post_types as $post_type ) { 3489 if( ! current_user_can( $post_type->cap->edit_posts ) ) 3490 continue; 3491 3492 $struct[$post_type->name] = $this->_prepare_post_type( $post_type, $fields ); 3493 } 3494 3495 return $struct; 3496 } 3497 3498 /** 3499 * Retrieve revisions for a specific post. 3500 * 3501 * @since 3.5.0 3502 * 3503 * The optional $fields parameter specifies what fields will be included 3504 * in the response array. 3505 * 3506 * @uses wp_get_post_revisions() 3507 * @see wp_getPost() for more on $fields 3508 * 3509 * @param array $args Method parameters. Contains: 3510 * - int $blog_id 3511 * - string $username 3512 * - string $password 3513 * - int $post_id 3514 * - array $fields 3515 * @return array contains a collection of posts. 3516 */ 3517 function wp_getRevisions( $args ) { 3518 if ( ! $this->minimum_args( $args, 4 ) ) 3519 return $this->error; 3520 3521 $this->escape( $args ); 3522 3523 $blog_id = (int) $args[0]; 3524 $username = $args[1]; 3525 $password = $args[2]; 3526 $post_id = (int) $args[3]; 3527 3528 if ( isset( $args[4] ) ) 3529 $fields = $args[4]; 3530 else 3531 $fields = apply_filters( 'xmlrpc_default_revision_fields', array( 'post_date', 'post_date_gmt' ), 'wp.getRevisions' ); 3532 3533 if ( ! $user = $this->login( $username, $password ) ) 3534 return $this->error; 3535 3536 do_action( 'xmlrpc_call', 'wp.getRevisions' ); 3537 3538 if ( ! $post = get_post( $post_id ) ) 3539 return new IXR_Error( 404, __( 'Invalid post ID' ) ); 3540 3541 if ( ! current_user_can( 'edit_post', $post_id ) ) 3542 return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts.' ) ); 3543 3544 // Check if revisions are enabled. 3545 if ( ! wp_revisions_enabled( $post ) ) 3546 return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) ); 3547 3548 $revisions = wp_get_post_revisions( $post_id ); 3549 3550 if ( ! $revisions ) 3551 return array(); 3552 3553 $struct = array(); 3554 3555 foreach ( $revisions as $revision ) { 3556 if ( ! current_user_can( 'read_post', $revision->ID ) ) 3557 continue; 3558 3559 // Skip autosaves 3560 if ( wp_is_post_autosave( $revision ) ) 3561 continue; 3562 3563 $struct[] = $this->_prepare_post( get_object_vars( $revision ), $fields ); 3564 } 3565 3566 return $struct; 3567 } 3568 3569 /** 3570 * Restore a post revision 3571 * 3572 * @since 3.5.0 3573 * 3574 * @uses wp_restore_post_revision() 3575 * 3576 * @param array $args Method parameters. Contains: 3577 * - int $blog_id 3578 * - string $username 3579 * - string $password 3580 * - int $post_id 3581 * @return bool false if there was an error restoring, true if success. 3582 */ 3583 function wp_restoreRevision( $args ) { 3584 if ( ! $this->minimum_args( $args, 3 ) ) 3585 return $this->error; 3586 3587 $this->escape( $args ); 3588 3589 $blog_id = (int) $args[0]; 3590 $username = $args[1]; 3591 $password = $args[2]; 3592 $revision_id = (int) $args[3]; 3593 3594 if ( ! $user = $this->login( $username, $password ) ) 3595 return $this->error; 3596 3597 do_action( 'xmlrpc_call', 'wp.restoreRevision' ); 3598 3599 if ( ! $revision = wp_get_post_revision( $revision_id ) ) 3600 return new IXR_Error( 404, __( 'Invalid post ID' ) ); 3601 3602 if ( wp_is_post_autosave( $revision ) ) 3603 return new IXR_Error( 404, __( 'Invalid post ID' ) ); 3604 3605 if ( ! $post = get_post( $revision->post_parent ) ) 3606 return new IXR_Error( 404, __( 'Invalid post ID' ) ); 3607 3608 if ( ! current_user_can( 'edit_post', $revision->post_parent ) ) 3609 return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); 3610 3611 // Check if revisions are disabled. 3612 if ( ! wp_revisions_enabled( $post ) ) 3613 return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) ); 3614 3615 $post = wp_restore_post_revision( $revision_id ); 3616 3617 return (bool) $post; 3618 } 3619 3620 /* Blogger API functions. 3621 * specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/ 3622 */ 3623 3624 /** 3625 * Retrieve blogs that user owns. 3626 * 3627 * Will make more sense once we support multiple blogs. 3628 * 3629 * @since 1.5.0 3630 * 3631 * @param array $args Method parameters. 3632 * @return array 3633 */ 3634 function blogger_getUsersBlogs($args) { 3635 if ( is_multisite() ) 3636 return $this->_multisite_getUsersBlogs($args); 3637 3638 $this->escape($args); 3639 3640 $username = $args[1]; 3641 $password = $args[2]; 3642 3643 if ( !$user = $this->login($username, $password) ) 3644 return $this->error; 3645 3646 do_action('xmlrpc_call', 'blogger.getUsersBlogs'); 3647 3648 $is_admin = current_user_can('manage_options'); 3649 3650 $struct = array( 3651 'isAdmin' => $is_admin, 3652 'url' => get_option('home') . '/', 3653 'blogid' => '1', 3654 'blogName' => get_option('blogname'), 3655 'xmlrpc' => site_url( 'xmlrpc.php', 'rpc' ), 3656 ); 3657 3658 return array($struct); 3659 } 3660 3661 /** 3662 * Private function for retrieving a users blogs for multisite setups 3663 * 3664 * @access protected 3665 */ 3666 function _multisite_getUsersBlogs($args) { 3667 $current_blog = get_blog_details(); 3668 3669 $domain = $current_blog->domain; 3670 $path = $current_blog->path . 'xmlrpc.php'; 3671 3672 $rpc = new IXR_Client( set_url_scheme( "http://{$domain}{$path}" ) ); 3673 $rpc->query('wp.getUsersBlogs', $args[1], $args[2]); 3674 $blogs = $rpc->getResponse(); 3675 3676 if ( isset($blogs['faultCode']) ) 3677 return new IXR_Error($blogs['faultCode'], $blogs['faultString']); 3678 3679 if ( $_SERVER['HTTP_HOST'] == $domain && $_SERVER['REQUEST_URI'] == $path ) { 3680 return $blogs; 3681 } else { 3682 foreach ( (array) $blogs as $blog ) { 3683 if ( strpos($blog['url'], $_SERVER['HTTP_HOST']) ) 3684 return array($blog); 3685 } 3686 return array(); 3687 } 3688 } 3689 3690 /** 3691 * Retrieve user's data. 3692 * 3693 * Gives your client some info about you, so you don't have to. 3694 * 3695 * @since 1.5.0 3696 * 3697 * @param array $args Method parameters. 3698 * @return array 3699 */ 3700 function blogger_getUserInfo($args) { 3701 3702 $this->escape($args); 3703 3704 $username = $args[1]; 3705 $password = $args[2]; 3706 3707 if ( !$user = $this->login($username, $password) ) 3708 return $this->error; 3709 3710 if ( !current_user_can( 'edit_posts' ) ) 3711 return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this site.' ) ); 3712 3713 do_action('xmlrpc_call', 'blogger.getUserInfo'); 3714 3715 $struct = array( 3716 'nickname' => $user->nickname, 3717 'userid' => $user->ID, 3718 'url' => $user->user_url, 3719 'lastname' => $user->last_name, 3720 'firstname' => $user->first_name 3721 ); 3722 3723 return $struct; 3724 } 3725 3726 /** 3727 * Retrieve post. 3728 * 3729 * @since 1.5.0 3730 * 3731 * @param array $args Method parameters. 3732 * @return array 3733 */ 3734 function blogger_getPost($args) { 3735 3736 $this->escape($args); 3737 3738 $post_ID = (int) $args[1]; 3739 $username = $args[2]; 3740 $password = $args[3]; 3741 3742 if ( !$user = $this->login($username, $password) ) 3743 return $this->error; 3744 3745 $post_data = get_post($post_ID, ARRAY_A); 3746 if ( ! $post_data ) 3747 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 3748 3749 if ( !current_user_can( 'edit_post', $post_ID ) ) 3750 return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); 3751 3752 do_action('xmlrpc_call', 'blogger.getPost'); 3753 3754 $categories = implode(',', wp_get_post_categories($post_ID)); 3755 3756 $content = '<title>'.wp_unslash($post_data['post_title']).'</title>'; 3757 $content .= '<category>'.$categories.'</category>'; 3758 $content .= wp_unslash($post_data['post_content']); 3759 3760 $struct = array( 3761 'userid' => $post_data['post_author'], 3762 'dateCreated' => $this->_convert_date( $post_data['post_date'] ), 3763 'content' => $content, 3764 'postid' => (string) $post_data['ID'] 3765 ); 3766 3767 return $struct; 3768 } 3769 3770 /** 3771 * Retrieve list of recent posts. 3772 * 3773 * @since 1.5.0 3774 * 3775 * @param array $args Method parameters. 3776 * @return array 3777 */ 3778 function blogger_getRecentPosts($args) { 3779 3780 $this->escape($args); 3781 3782 // $args[0] = appkey - ignored 3783 $blog_ID = (int) $args[1]; /* though we don't use it yet */ 3784 $username = $args[2]; 3785 $password = $args[3]; 3786 if ( isset( $args[4] ) ) 3787 $query = array( 'numberposts' => absint( $args[4] ) ); 3788 else 3789 $query = array(); 3790 3791 if ( !$user = $this->login($username, $password) ) 3792 return $this->error; 3793 3794 if ( ! current_user_can( 'edit_posts' ) ) 3795 return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) ); 3796 3797 do_action('xmlrpc_call', 'blogger.getRecentPosts'); 3798 3799 $posts_list = wp_get_recent_posts( $query ); 3800 3801 if ( !$posts_list ) { 3802 $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.')); 3803 return $this->error; 3804 } 3805 3806 foreach ($posts_list as $entry) { 3807 if ( !current_user_can( 'edit_post', $entry['ID'] ) ) 3808 continue; 3809 3810 $post_date = $this->_convert_date( $entry['post_date'] ); 3811 $categories = implode(',', wp_get_post_categories($entry['ID'])); 3812 3813 $content = '<title>'.wp_unslash($entry['post_title']).'</title>'; 3814 $content .= '<category>'.$categories.'</category>'; 3815 $content .= wp_unslash($entry['post_content']); 3816 3817 $struct[] = array( 3818 'userid' => $entry['post_author'], 3819 'dateCreated' => $post_date, 3820 'content' => $content, 3821 'postid' => (string) $entry['ID'], 3822 ); 3823 3824 } 3825 3826 $recent_posts = array(); 3827 for ( $j=0; $j<count($struct); $j++ ) { 3828 array_push($recent_posts, $struct[$j]); 3829 } 3830 3831 return $recent_posts; 3832 } 3833 3834 /** 3835 * Deprecated. 3836 * 3837 * @since 1.5.0 3838 * @deprecated 3.5.0 3839 */ 3840 function blogger_getTemplate($args) { 3841 return new IXR_Error( 403, __('Sorry, that file cannot be edited.' ) ); 3842 } 3843 3844 /** 3845 * Deprecated. 3846 * 3847 * @since 1.5.0 3848 * @deprecated 3.5.0 3849 */ 3850 function blogger_setTemplate($args) { 3851 return new IXR_Error( 403, __('Sorry, that file cannot be edited.' ) ); 3852 } 3853 3854 /** 3855 * Create new post. 3856 * 3857 * @since 1.5.0 3858 * 3859 * @param array $args Method parameters. 3860 * @return int 3861 */ 3862 function blogger_newPost($args) { 3863 3864 $this->escape($args); 3865 3866 $blog_ID = (int) $args[1]; /* though we don't use it yet */ 3867 $username = $args[2]; 3868 $password = $args[3]; 3869 $content = $args[4]; 3870 $publish = $args[5]; 3871 3872 if ( !$user = $this->login($username, $password) ) 3873 return $this->error; 3874 3875 do_action('xmlrpc_call', 'blogger.newPost'); 3876 3877 $cap = ($publish) ? 'publish_posts' : 'edit_posts'; 3878 if ( ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) || !current_user_can($cap) ) 3879 return new IXR_Error(401, __('Sorry, you are not allowed to post on this site.')); 3880 3881 $post_status = ($publish) ? 'publish' : 'draft'; 3882 3883 $post_author = $user->ID; 3884 3885 $post_title = xmlrpc_getposttitle($content); 3886 $post_category = xmlrpc_getpostcategory($content); 3887 $post_content = xmlrpc_removepostdata($content); 3888 3889 $post_date = current_time('mysql'); 3890 $post_date_gmt = current_time('mysql', 1); 3891 3892 $post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status'); 3893 3894 $post_ID = wp_insert_post($post_data); 3895 if ( is_wp_error( $post_ID ) ) 3896 return new IXR_Error(500, $post_ID->get_error_message()); 3897 3898 if ( !$post_ID ) 3899 return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); 3900 3901 $this->attach_uploads( $post_ID, $post_content ); 3902 3903 do_action( 'xmlrpc_call_success_blogger_newPost', $post_ID, $args ); 3904 3905 return $post_ID; 3906 } 3907 3908 /** 3909 * Edit a post. 3910 * 3911 * @since 1.5.0 3912 * 3913 * @param array $args Method parameters. 3914 * @return bool true when done. 3915 */ 3916 function blogger_editPost($args) { 3917 3918 $this->escape($args); 3919 3920 $post_ID = (int) $args[1]; 3921 $username = $args[2]; 3922 $password = $args[3]; 3923 $content = $args[4]; 3924 $publish = $args[5]; 3925 3926 if ( !$user = $this->login($username, $password) ) 3927 return $this->error; 3928 3929 do_action('xmlrpc_call', 'blogger.editPost'); 3930 3931 $actual_post = get_post($post_ID,ARRAY_A); 3932 3933 if ( !$actual_post || $actual_post['post_type'] != 'post' ) 3934 return new IXR_Error(404, __('Sorry, no such post.')); 3935 3936 $this->escape($actual_post); 3937 3938 if ( !current_user_can('edit_post', $post_ID) ) 3939 return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.')); 3940 3941 extract($actual_post, EXTR_SKIP); 3942 3943 if ( ('publish' == $post_status) && !current_user_can('publish_posts') ) 3944 return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); 3945 3946 $post_title = xmlrpc_getposttitle($content); 3947 $post_category = xmlrpc_getpostcategory($content); 3948 $post_content = xmlrpc_removepostdata($content); 3949 3950 $postdata = compact('ID', 'post_content', 'post_title', 'post_category', 'post_status', 'post_excerpt'); 3951 3952 $result = wp_update_post($postdata); 3953 3954 if ( !$result ) 3955 return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.')); 3956 3957 $this->attach_uploads( $ID, $post_content ); 3958 3959 do_action( 'xmlrpc_call_success_blogger_editPost', $post_ID, $args ); 3960 3961 return true; 3962 } 3963 3964 /** 3965 * Remove a post. 3966 * 3967 * @since 1.5.0 3968 * 3969 * @param array $args Method parameters. 3970 * @return bool True when post is deleted. 3971 */ 3972 function blogger_deletePost($args) { 3973 $this->escape($args); 3974 3975 $post_ID = (int) $args[1]; 3976 $username = $args[2]; 3977 $password = $args[3]; 3978 $publish = $args[4]; 3979 3980 if ( !$user = $this->login($username, $password) ) 3981 return $this->error; 3982 3983 do_action('xmlrpc_call', 'blogger.deletePost'); 3984 3985 $actual_post = get_post($post_ID,ARRAY_A); 3986 3987 if ( !$actual_post || $actual_post['post_type'] != 'post' ) 3988 return new IXR_Error(404, __('Sorry, no such post.')); 3989 3990 if ( !current_user_can('delete_post', $post_ID) ) 3991 return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.')); 3992 3993 $result = wp_delete_post($post_ID); 3994 3995 if ( !$result ) 3996 return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.')); 3997 3998 do_action( 'xmlrpc_call_success_blogger_deletePost', $post_ID, $args ); 3999 4000 return true; 4001 } 4002 4003 /* MetaWeblog API functions 4004 * specs on wherever Dave Winer wants them to be 4005 */ 4006 4007 /** 4008 * Create a new post. 4009 * 4010 * The 'content_struct' argument must contain: 4011 * - title 4012 * - description 4013 * - mt_excerpt 4014 * - mt_text_more 4015 * - mt_keywords 4016 * - mt_tb_ping_urls 4017 * - categories 4018 * 4019 * Also, it can optionally contain: 4020 * - wp_slug 4021 * - wp_password 4022 * - wp_page_parent_id 4023 * - wp_page_order 4024 * - wp_author_id 4025 * - post_status | page_status - can be 'draft', 'private', 'publish', or 'pending' 4026 * - mt_allow_comments - can be 'open' or 'closed' 4027 * - mt_allow_pings - can be 'open' or 'closed' 4028 * - date_created_gmt 4029 * - dateCreated 4030 * - wp_post_thumbnail 4031 * 4032 * @since 1.5.0 4033 * 4034 * @param array $args Method parameters. Contains: 4035 * - blog_id 4036 * - username 4037 * - password 4038 * - content_struct 4039 * - publish 4040 * @return int 4041 */ 4042 function mw_newPost($args) { 4043 $this->escape($args); 4044 4045 $blog_ID = (int) $args[0]; 4046 $username = $args[1]; 4047 $password = $args[2]; 4048 $content_struct = $args[3]; 4049 $publish = isset( $args[4] ) ? $args[4] : 0; 4050 4051 if ( !$user = $this->login($username, $password) ) 4052 return $this->error; 4053 4054 do_action('xmlrpc_call', 'metaWeblog.newPost'); 4055 4056 $page_template = ''; 4057 if ( !empty( $content_struct['post_type'] ) ) { 4058 if ( $content_struct['post_type'] == 'page' ) { 4059 if ( $publish ) 4060 $cap = 'publish_pages'; 4061 elseif ( isset( $content_struct['page_status'] ) && 'publish' == $content_struct['page_status'] ) 4062 $cap = 'publish_pages'; 4063 else 4064 $cap = 'edit_pages'; 4065 $error_message = __( 'Sorry, you are not allowed to publish pages on this site.' ); 4066 $post_type = 'page'; 4067 if ( !empty( $content_struct['wp_page_template'] ) ) 4068 $page_template = $content_struct['wp_page_template']; 4069 } elseif ( $content_struct['post_type'] == 'post' ) { 4070 if ( $publish ) 4071 $cap = 'publish_posts'; 4072 elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status'] ) 4073 $cap = 'publish_posts'; 4074 else 4075 $cap = 'edit_posts'; 4076 $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' ); 4077 $post_type = 'post'; 4078 } else { 4079 // No other post_type values are allowed here 4080 return new IXR_Error( 401, __( 'Invalid post type' ) ); 4081 } 4082 } else { 4083 if ( $publish ) 4084 $cap = 'publish_posts'; 4085 elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status']) 4086 $cap = 'publish_posts'; 4087 else 4088 $cap = 'edit_posts'; 4089 $error_message = __( 'Sorry, you are not allowed to publish posts on this site.' ); 4090 $post_type = 'post'; 4091 } 4092 4093 if ( ! current_user_can( get_post_type_object( $post_type )->cap->create_posts ) ) 4094 return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts on this site.' ) ); 4095 if ( !current_user_can( $cap ) ) 4096 return new IXR_Error( 401, $error_message ); 4097 4098 // Check for a valid post format if one was given 4099 if ( isset( $content_struct['wp_post_format'] ) ) { 4100 $content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] ); 4101 if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) { 4102 return new IXR_Error( 404, __( 'Invalid post format' ) ); 4103 } 4104 } 4105 4106 // Let WordPress generate the post_name (slug) unless 4107 // one has been provided. 4108 $post_name = ""; 4109 if ( isset($content_struct['wp_slug']) ) 4110 $post_name = $content_struct['wp_slug']; 4111 4112 // Only use a password if one was given. 4113 if ( isset($content_struct['wp_password']) ) 4114 $post_password = $content_struct['wp_password']; 4115 4116 // Only set a post parent if one was provided. 4117 if ( isset($content_struct['wp_page_parent_id']) ) 4118 $post_parent = $content_struct['wp_page_parent_id']; 4119 4120 // Only set the menu_order if it was provided. 4121 if ( isset($content_struct['wp_page_order']) ) 4122 $menu_order = $content_struct['wp_page_order']; 4123 4124 $post_author = $user->ID; 4125 4126 // If an author id was provided then use it instead. 4127 if ( isset( $content_struct['wp_author_id'] ) && ( $user->ID != $content_struct['wp_author_id'] ) ) { 4128 switch ( $post_type ) { 4129 case "post": 4130 if ( !current_user_can( 'edit_others_posts' ) ) 4131 return( new IXR_Error( 401, __( 'You are not allowed to create posts as this user.' ) ) ); 4132 break; 4133 case "page": 4134 if ( !current_user_can( 'edit_others_pages' ) ) 4135 return( new IXR_Error( 401, __( 'You are not allowed to create pages as this user.' ) ) ); 4136 break; 4137 default: 4138 return( new IXR_Error( 401, __( 'Invalid post type' ) ) ); 4139 break; 4140 } 4141 $author = get_userdata( $content_struct['wp_author_id'] ); 4142 if ( ! $author ) 4143 return new IXR_Error( 404, __( 'Invalid author ID.' ) ); 4144 $post_author = $content_struct['wp_author_id']; 4145 } 4146 4147 $post_title = isset( $content_struct['title'] ) ? $content_struct['title'] : null; 4148 $post_content = isset( $content_struct['description'] ) ? $content_struct['description'] : null; 4149 4150 $post_status = $publish ? 'publish' : 'draft'; 4151 4152 if ( isset( $content_struct["{$post_type}_status"] ) ) { 4153 switch ( $content_struct["{$post_type}_status"] ) { 4154 case 'draft': 4155 case 'pending': 4156 case 'private': 4157 case 'publish': 4158 $post_status = $content_struct["{$post_type}_status"]; 4159 break; 4160 default: 4161 $post_status = $publish ? 'publish' : 'draft'; 4162 break; 4163 } 4164 } 4165 4166 $post_excerpt = isset($content_struct['mt_excerpt']) ? $content_struct['mt_excerpt'] : null; 4167 $post_more = isset($content_struct['mt_text_more']) ? $content_struct['mt_text_more'] : null; 4168 4169 $tags_input = isset($content_struct['mt_keywords']) ? $content_struct['mt_keywords'] : null; 4170 4171 if ( isset($content_struct['mt_allow_comments']) ) { 4172 if ( !is_numeric($content_struct['mt_allow_comments']) ) { 4173 switch ( $content_struct['mt_allow_comments'] ) { 4174 case 'closed': 4175 $comment_status = 'closed'; 4176 break; 4177 case 'open': 4178 $comment_status = 'open'; 4179 break; 4180 default: 4181 $comment_status = get_option('default_comment_status'); 4182 break; 4183 } 4184 } else { 4185 switch ( (int) $content_struct['mt_allow_comments'] ) { 4186 case 0: 4187 case 2: 4188 $comment_status = 'closed'; 4189 break; 4190 case 1: 4191 $comment_status = 'open'; 4192 break; 4193 default: 4194 $comment_status = get_option('default_comment_status'); 4195 break; 4196 } 4197 } 4198 } else { 4199 $comment_status = get_option('default_comment_status'); 4200 } 4201 4202 if ( isset($content_struct['mt_allow_pings']) ) { 4203 if ( !is_numeric($content_struct['mt_allow_pings']) ) { 4204 switch ( $content_struct['mt_allow_pings'] ) { 4205 case 'closed': 4206 $ping_status = 'closed'; 4207 break; 4208 case 'open': 4209 $ping_status = 'open'; 4210 break; 4211 default: 4212 $ping_status = get_option('default_ping_status'); 4213 break; 4214 } 4215 } else { 4216 switch ( (int) $content_struct['mt_allow_pings'] ) { 4217 case 0: 4218 $ping_status = 'closed'; 4219 break; 4220 case 1: 4221 $ping_status = 'open'; 4222 break; 4223 default: 4224 $ping_status = get_option('default_ping_status'); 4225 break; 4226 } 4227 } 4228 } else { 4229 $ping_status = get_option('default_ping_status'); 4230 } 4231 4232 if ( $post_more ) 4233 $post_content = $post_content . '<!--more-->' . $post_more; 4234 4235 $to_ping = null; 4236 if ( isset( $content_struct['mt_tb_ping_urls'] ) ) { 4237 $to_ping = $content_struct['mt_tb_ping_urls']; 4238 if ( is_array($to_ping) ) 4239 $to_ping = implode(' ', $to_ping); 4240 } 4241 4242 // Do some timestamp voodoo 4243 if ( !empty( $content_struct['date_created_gmt'] ) ) 4244 // We know this is supposed to be GMT, so we're going to slap that Z on there by force 4245 $dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z'; 4246 elseif ( !empty( $content_struct['dateCreated']) ) 4247 $dateCreated = $content_struct['dateCreated']->getIso(); 4248 4249 if ( !empty( $dateCreated ) ) { 4250 $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 4251 $post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT'); 4252 } else { 4253 $post_date = current_time('mysql'); 4254 $post_date_gmt = current_time('mysql', 1); 4255 } 4256 4257 $post_category = array(); 4258 if ( isset( $content_struct['categories'] ) ) { 4259 $catnames = $content_struct['categories']; 4260 4261 if ( is_array($catnames) ) { 4262 foreach ($catnames as $cat) { 4263 $post_category[] = get_cat_ID($cat); 4264 } 4265 } 4266 } 4267 4268 $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'); 4269 4270 $post_ID = $postdata['ID'] = get_default_post_to_edit( $post_type, true )->ID; 4271 4272 // Only posts can be sticky 4273 if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) { 4274 if ( $content_struct['sticky'] == true ) 4275 stick_post( $post_ID ); 4276 elseif ( $content_struct['sticky'] == false ) 4277 unstick_post( $post_ID ); 4278 } 4279 4280 if ( isset($content_struct['custom_fields']) ) 4281 $this->set_custom_fields($post_ID, $content_struct['custom_fields']); 4282 4283 if ( isset ( $content_struct['wp_post_thumbnail'] ) ) { 4284 if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false ) 4285 return new IXR_Error( 404, __( 'Invalid attachment ID.' ) ); 4286 4287 unset( $content_struct['wp_post_thumbnail'] ); 4288 } 4289 4290 // Handle enclosures 4291 $thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null; 4292 $this->add_enclosure_if_new($post_ID, $thisEnclosure); 4293 4294 $this->attach_uploads( $post_ID, $post_content ); 4295 4296 // Handle post formats if assigned, value is validated earlier 4297 // in this function 4298 if ( isset( $content_struct['wp_post_format'] ) ) 4299 set_post_format( $post_ID, $content_struct['wp_post_format'] ); 4300 4301 $post_ID = wp_insert_post( $postdata, true ); 4302 if ( is_wp_error( $post_ID ) ) 4303 return new IXR_Error(500, $post_ID->get_error_message()); 4304 4305 if ( !$post_ID ) 4306 return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.')); 4307 4308 do_action( 'xmlrpc_call_success_mw_newPost', $post_ID, $args ); 4309 4310 return strval($post_ID); 4311 } 4312 4313 function add_enclosure_if_new( $post_ID, $enclosure ) { 4314 if ( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) { 4315 $encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'] . "\n"; 4316 $found = false; 4317 if ( $enclosures = get_post_meta( $post_ID, 'enclosure' ) ) { 4318 foreach ( $enclosures as $enc ) { 4319 // This method used to omit the trailing new line. #23219 4320 if ( rtrim( $enc, "\n" ) == rtrim( $encstring, "\n" ) ) { 4321 $found = true; 4322 break; 4323 } 4324 } 4325 } 4326 if ( ! $found ) 4327 add_post_meta( $post_ID, 'enclosure', $encstring ); 4328 } 4329 } 4330 4331 /** 4332 * Attach upload to a post. 4333 * 4334 * @since 2.1.0 4335 * 4336 * @param int $post_ID Post ID. 4337 * @param string $post_content Post Content for attachment. 4338 */ 4339 function attach_uploads( $post_ID, $post_content ) { 4340 global $wpdb; 4341 4342 // find any unattached files 4343 $attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" ); 4344 if ( is_array( $attachments ) ) { 4345 foreach ( $attachments as $file ) { 4346 if ( ! empty( $file->guid ) && strpos( $post_content, $file->guid ) !== false ) 4347 $wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) ); 4348 } 4349 } 4350 } 4351 4352 /** 4353 * Edit a post. 4354 * 4355 * @since 1.5.0 4356 * 4357 * @param array $args Method parameters. 4358 * @return bool True on success. 4359 */ 4360 function mw_editPost($args) { 4361 4362 $this->escape($args); 4363 4364 $post_ID = (int) $args[0]; 4365 $username = $args[1]; 4366 $password = $args[2]; 4367 $content_struct = $args[3]; 4368 $publish = isset( $args[4] ) ? $args[4] : 0; 4369 4370 if ( ! $user = $this->login($username, $password) ) 4371 return $this->error; 4372 4373 do_action('xmlrpc_call', 'metaWeblog.editPost'); 4374 4375 $postdata = get_post( $post_ID, ARRAY_A ); 4376 4377 // If there is no post data for the give post id, stop 4378 // now and return an error. Other wise a new post will be 4379 // created (which was the old behavior). 4380 if ( ! $postdata || empty( $postdata[ 'ID' ] ) ) 4381 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 4382 4383 if ( ! current_user_can( 'edit_post', $post_ID ) ) 4384 return new IXR_Error( 401, __( 'Sorry, you do not have the right to edit this post.' ) ); 4385 4386 // Use wp.editPost to edit post types other than post and page. 4387 if ( ! in_array( $postdata[ 'post_type' ], array( 'post', 'page' ) ) ) 4388 return new IXR_Error( 401, __( 'Invalid post type' ) ); 4389 4390 // Thwart attempt to change the post type. 4391 if ( ! empty( $content_struct[ 'post_type' ] ) && ( $content_struct['post_type'] != $postdata[ 'post_type' ] ) ) 4392 return new IXR_Error( 401, __( 'The post type may not be changed.' ) ); 4393 4394 // Check for a valid post format if one was given 4395 if ( isset( $content_struct['wp_post_format'] ) ) { 4396 $content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] ); 4397 if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) { 4398 return new IXR_Error( 404, __( 'Invalid post format' ) ); 4399 } 4400 } 4401 4402 $this->escape($postdata); 4403 extract($postdata, EXTR_SKIP); 4404 4405 // Let WordPress manage slug if none was provided. 4406 $post_name = ""; 4407 $post_name = $postdata['post_name']; 4408 if ( isset($content_struct['wp_slug']) ) 4409 $post_name = $content_struct['wp_slug']; 4410 4411 // Only use a password if one was given. 4412 if ( isset($content_struct['wp_password']) ) 4413 $post_password = $content_struct['wp_password']; 4414 4415 // Only set a post parent if one was given. 4416 if ( isset($content_struct['wp_page_parent_id']) ) 4417 $post_parent = $content_struct['wp_page_parent_id']; 4418 4419 // Only set the menu_order if it was given. 4420 if ( isset($content_struct['wp_page_order']) ) 4421 $menu_order = $content_struct['wp_page_order']; 4422 4423 if ( ! empty( $content_struct['wp_page_template'] ) && 'page' == $post_type ) 4424 $page_template = $content_struct['wp_page_template']; 4425 4426 $post_author = $postdata['post_author']; 4427 4428 // Only set the post_author if one is set. 4429 if ( isset($content_struct['wp_author_id']) && ($user->ID != $content_struct['wp_author_id']) ) { 4430 switch ( $post_type ) { 4431 case 'post': 4432 if ( !current_user_can('edit_others_posts') ) 4433 return(new IXR_Error(401, __('You are not allowed to change the post author as this user.'))); 4434 break; 4435 case 'page': 4436 if ( !current_user_can('edit_others_pages') ) 4437 return(new IXR_Error(401, __('You are not allowed to change the page author as this user.'))); 4438 break; 4439 default: 4440 return(new IXR_Error(401, __('Invalid post type'))); 4441 break; 4442 } 4443 $post_author = $content_struct['wp_author_id']; 4444 } 4445 4446 if ( isset($content_struct['mt_allow_comments']) ) { 4447 if ( !is_numeric($content_struct['mt_allow_comments']) ) { 4448 switch ( $content_struct['mt_allow_comments'] ) { 4449 case 'closed': 4450 $comment_status = 'closed'; 4451 break; 4452 case 'open': 4453 $comment_status = 'open'; 4454 break; 4455 default: 4456 $comment_status = get_option('default_comment_status'); 4457 break; 4458 } 4459 } else { 4460 switch ( (int) $content_struct['mt_allow_comments'] ) { 4461 case 0: 4462 case 2: 4463 $comment_status = 'closed'; 4464 break; 4465 case 1: 4466 $comment_status = 'open'; 4467 break; 4468 default: 4469 $comment_status = get_option('default_comment_status'); 4470 break; 4471 } 4472 } 4473 } 4474 4475 if ( isset($content_struct['mt_allow_pings']) ) { 4476 if ( !is_numeric($content_struct['mt_allow_pings']) ) { 4477 switch ( $content_struct['mt_allow_pings'] ) { 4478 case 'closed': 4479 $ping_status = 'closed'; 4480 break; 4481 case 'open': 4482 $ping_status = 'open'; 4483 break; 4484 default: 4485 $ping_status = get_option('default_ping_status'); 4486 break; 4487 } 4488 } else { 4489 switch ( (int) $content_struct["mt_allow_pings"] ) { 4490 case 0: 4491 $ping_status = 'closed'; 4492 break; 4493 case 1: 4494 $ping_status = 'open'; 4495 break; 4496 default: 4497 $ping_status = get_option('default_ping_status'); 4498 break; 4499 } 4500 } 4501 } 4502 4503 if ( isset( $content_struct['title'] ) ) 4504 $post_title = $content_struct['title']; 4505 4506 if ( isset( $content_struct['description'] ) ) 4507 $post_content = $content_struct['description']; 4508 4509 $post_category = array(); 4510 if ( isset( $content_struct['categories'] ) ) { 4511 $catnames = $content_struct['categories']; 4512 if ( is_array($catnames) ) { 4513 foreach ($catnames as $cat) { 4514 $post_category[] = get_cat_ID($cat); 4515 } 4516 } 4517 } 4518 4519 if ( isset( $content_struct['mt_excerpt'] ) ) 4520 $post_excerpt = $content_struct['mt_excerpt']; 4521 4522 $post_more = isset( $content_struct['mt_text_more'] ) ? $content_struct['mt_text_more'] : null; 4523 4524 $post_status = $publish ? 'publish' : 'draft'; 4525 if ( isset( $content_struct["{$post_type}_status"] ) ) { 4526 switch( $content_struct["{$post_type}_status"] ) { 4527 case 'draft': 4528 case 'pending': 4529 case 'private': 4530 case 'publish': 4531 $post_status = $content_struct["{$post_type}_status"]; 4532 break; 4533 default: 4534 $post_status = $publish ? 'publish' : 'draft'; 4535 break; 4536 } 4537 } 4538 4539 $tags_input = isset( $content_struct['mt_keywords'] ) ? $content_struct['mt_keywords'] : null; 4540 4541 if ( ('publish' == $post_status) ) { 4542 if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') ) 4543 return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.')); 4544 else if ( !current_user_can('publish_posts') ) 4545 return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.')); 4546 } 4547 4548 if ( $post_more ) 4549 $post_content = $post_content . "<!--more-->" . $post_more; 4550 4551 $to_ping = null; 4552 if ( isset( $content_struct['mt_tb_ping_urls'] ) ) { 4553 $to_ping = $content_struct['mt_tb_ping_urls']; 4554 if ( is_array($to_ping) ) 4555 $to_ping = implode(' ', $to_ping); 4556 } 4557 4558 // Do some timestamp voodoo 4559 if ( !empty( $content_struct['date_created_gmt'] ) ) 4560 // We know this is supposed to be GMT, so we're going to slap that Z on there by force 4561 $dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z'; 4562 elseif ( !empty( $content_struct['dateCreated']) ) 4563 $dateCreated = $content_struct['dateCreated']->getIso(); 4564 4565 if ( !empty( $dateCreated ) ) { 4566 $post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated)); 4567 $post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT'); 4568 } else { 4569 $post_date = $postdata['post_date']; 4570 $post_date_gmt = $postdata['post_date_gmt']; 4571 } 4572 4573 // We've got all the data -- post it: 4574 $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'); 4575 4576 $result = wp_update_post($newpost, true); 4577 if ( is_wp_error( $result ) ) 4578 return new IXR_Error(500, $result->get_error_message()); 4579 4580 if ( !$result ) 4581 return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.')); 4582 4583 // Only posts can be sticky 4584 if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) { 4585 if ( $content_struct['sticky'] == true ) 4586 stick_post( $post_ID ); 4587 elseif ( $content_struct['sticky'] == false ) 4588 unstick_post( $post_ID ); 4589 } 4590 4591 if ( isset($content_struct['custom_fields']) ) 4592 $this->set_custom_fields($post_ID, $content_struct['custom_fields']); 4593 4594 if ( isset ( $content_struct['wp_post_thumbnail'] ) ) { 4595 // empty value deletes, non-empty value adds/updates 4596 if ( empty( $content_struct['wp_post_thumbnail'] ) ) { 4597 delete_post_thumbnail( $post_ID ); 4598 } else { 4599 if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false ) 4600 return new IXR_Error( 404, __( 'Invalid attachment ID.' ) ); 4601 } 4602 unset( $content_struct['wp_post_thumbnail'] ); 4603 } 4604 4605 // Handle enclosures 4606 $thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null; 4607 $this->add_enclosure_if_new($post_ID, $thisEnclosure); 4608 4609 $this->attach_uploads( $ID, $post_content ); 4610 4611 // Handle post formats if assigned, validation is handled 4612 // earlier in this function 4613 if ( isset( $content_struct['wp_post_format'] ) ) 4614 set_post_format( $post_ID, $content_struct['wp_post_format'] ); 4615 4616 do_action( 'xmlrpc_call_success_mw_editPost', $post_ID, $args ); 4617 4618 return true; 4619 } 4620 4621 /** 4622 * Retrieve post. 4623 * 4624 * @since 1.5.0 4625 * 4626 * @param array $args Method parameters. 4627 * @return array 4628 */ 4629 function mw_getPost($args) { 4630 4631 $this->escape($args); 4632 4633 $post_ID = (int) $args[0]; 4634 $username = $args[1]; 4635 $password = $args[2]; 4636 4637 if ( !$user = $this->login($username, $password) ) 4638 return $this->error; 4639 4640 $postdata = get_post($post_ID, ARRAY_A); 4641 if ( ! $postdata ) 4642 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 4643 4644 if ( !current_user_can( 'edit_post', $post_ID ) ) 4645 return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); 4646 4647 do_action('xmlrpc_call', 'metaWeblog.getPost'); 4648 4649 if ($postdata['post_date'] != '') { 4650 $post_date = $this->_convert_date( $postdata['post_date'] ); 4651 $post_date_gmt = $this->_convert_date_gmt( $postdata['post_date_gmt'], $postdata['post_date'] ); 4652 $post_modified = $this->_convert_date( $postdata['post_modified'] ); 4653 $post_modified_gmt = $this->_convert_date_gmt( $postdata['post_modified_gmt'], $postdata['post_modified'] ); 4654 4655 $categories = array(); 4656 $catids = wp_get_post_categories($post_ID); 4657 foreach($catids as $catid) 4658 $categories[] = get_cat_name($catid); 4659 4660 $tagnames = array(); 4661 $tags = wp_get_post_tags( $post_ID ); 4662 if ( !empty( $tags ) ) { 4663 foreach ( $tags as $tag ) 4664 $tagnames[] = $tag->name; 4665 $tagnames = implode( ', ', $tagnames ); 4666 } else { 4667 $tagnames = ''; 4668 } 4669 4670 $post = get_extended($postdata['post_content']); 4671 $link = post_permalink($postdata['ID']); 4672 4673 // Get the author info. 4674 $author = get_userdata($postdata['post_author']); 4675 4676 $allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0; 4677 $allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0; 4678 4679 // Consider future posts as published 4680 if ( $postdata['post_status'] === 'future' ) 4681 $postdata['post_status'] = 'publish'; 4682 4683 // Get post format 4684 $post_format = get_post_format( $post_ID ); 4685 if ( empty( $post_format ) ) 4686 $post_format = 'standard'; 4687 4688 $sticky = false; 4689 if ( is_sticky( $post_ID ) ) 4690 $sticky = true; 4691 4692 $enclosure = array(); 4693 foreach ( (array) get_post_custom($post_ID) as $key => $val) { 4694 if ($key == 'enclosure') { 4695 foreach ( (array) $val as $enc ) { 4696 $encdata = explode("\n", $enc); 4697 $enclosure['url'] = trim(htmlspecialchars($encdata[0])); 4698 $enclosure['length'] = (int) trim($encdata[1]); 4699 $enclosure['type'] = trim($encdata[2]); 4700 break 2; 4701 } 4702 } 4703 } 4704 4705 $resp = array( 4706 'dateCreated' => $post_date, 4707 'userid' => $postdata['post_author'], 4708 'postid' => $postdata['ID'], 4709 'description' => $post['main'], 4710 'title' => $postdata['post_title'], 4711 'link' => $link, 4712 'permaLink' => $link, 4713 // commented out because no other tool seems to use this 4714 // 'content' => $entry['post_content'], 4715 'categories' => $categories, 4716 'mt_excerpt' => $postdata['post_excerpt'], 4717 'mt_text_more' => $post['extended'], 4718 'wp_more_text' => $post['more_text'], 4719 'mt_allow_comments' => $allow_comments, 4720 'mt_allow_pings' => $allow_pings, 4721 'mt_keywords' => $tagnames, 4722 'wp_slug' => $postdata['post_name'], 4723 'wp_password' => $postdata['post_password'], 4724 'wp_author_id' => (string) $author->ID, 4725 'wp_author_display_name' => $author->display_name, 4726 'date_created_gmt' => $post_date_gmt, 4727 'post_status' => $postdata['post_status'], 4728 'custom_fields' => $this->get_custom_fields($post_ID), 4729 'wp_post_format' => $post_format, 4730 'sticky' => $sticky, 4731 'date_modified' => $post_modified, 4732 'date_modified_gmt' => $post_modified_gmt 4733 ); 4734 4735 if ( !empty($enclosure) ) $resp['enclosure'] = $enclosure; 4736 4737 $resp['wp_post_thumbnail'] = get_post_thumbnail_id( $postdata['ID'] ); 4738 4739 return $resp; 4740 } else { 4741 return new IXR_Error(404, __('Sorry, no such post.')); 4742 } 4743 } 4744 4745 /** 4746 * Retrieve list of recent posts. 4747 * 4748 * @since 1.5.0 4749 * 4750 * @param array $args Method parameters. 4751 * @return array 4752 */ 4753 function mw_getRecentPosts($args) { 4754 4755 $this->escape($args); 4756 4757 $blog_ID = (int) $args[0]; 4758 $username = $args[1]; 4759 $password = $args[2]; 4760 if ( isset( $args[3] ) ) 4761 $query = array( 'numberposts' => absint( $args[3] ) ); 4762 else 4763 $query = array(); 4764 4765 if ( !$user = $this->login($username, $password) ) 4766 return $this->error; 4767 4768 if ( ! current_user_can( 'edit_posts' ) ) 4769 return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) ); 4770 4771 do_action('xmlrpc_call', 'metaWeblog.getRecentPosts'); 4772 4773 $posts_list = wp_get_recent_posts( $query ); 4774 4775 if ( !$posts_list ) 4776 return array(); 4777 4778 $struct = array(); 4779 foreach ($posts_list as $entry) { 4780 if ( !current_user_can( 'edit_post', $entry['ID'] ) ) 4781 continue; 4782 4783 $post_date = $this->_convert_date( $entry['post_date'] ); 4784 $post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] ); 4785 $post_modified = $this->_convert_date( $entry['post_modified'] ); 4786 $post_modified_gmt = $this->_convert_date_gmt( $entry['post_modified_gmt'], $entry['post_modified'] ); 4787 4788 $categories = array(); 4789 $catids = wp_get_post_categories($entry['ID']); 4790 foreach( $catids as $catid ) 4791 $categories[] = get_cat_name($catid); 4792 4793 $tagnames = array(); 4794 $tags = wp_get_post_tags( $entry['ID'] ); 4795 if ( !empty( $tags ) ) { 4796 foreach ( $tags as $tag ) { 4797 $tagnames[] = $tag->name; 4798 } 4799 $tagnames = implode( ', ', $tagnames ); 4800 } else { 4801 $tagnames = ''; 4802 } 4803 4804 $post = get_extended($entry['post_content']); 4805 $link = post_permalink($entry['ID']); 4806 4807 // Get the post author info. 4808 $author = get_userdata($entry['post_author']); 4809 4810 $allow_comments = ('open' == $entry['comment_status']) ? 1 : 0; 4811 $allow_pings = ('open' == $entry['ping_status']) ? 1 : 0; 4812 4813 // Consider future posts as published 4814 if ( $entry['post_status'] === 'future' ) 4815 $entry['post_status'] = 'publish'; 4816 4817 // Get post format 4818 $post_format = get_post_format( $entry['ID'] ); 4819 if ( empty( $post_format ) ) 4820 $post_format = 'standard'; 4821 4822 $struct[] = array( 4823 'dateCreated' => $post_date, 4824 'userid' => $entry['post_author'], 4825 'postid' => (string) $entry['ID'], 4826 'description' => $post['main'], 4827 'title' => $entry['post_title'], 4828 'link' => $link, 4829 'permaLink' => $link, 4830 // commented out because no other tool seems to use this 4831 // 'content' => $entry['post_content'], 4832 'categories' => $categories, 4833 'mt_excerpt' => $entry['post_excerpt'], 4834 'mt_text_more' => $post['extended'], 4835 'wp_more_text' => $post['more_text'], 4836 'mt_allow_comments' => $allow_comments, 4837 'mt_allow_pings' => $allow_pings, 4838 'mt_keywords' => $tagnames, 4839 'wp_slug' => $entry['post_name'], 4840 'wp_password' => $entry['post_password'], 4841 'wp_author_id' => (string) $author->ID, 4842 'wp_author_display_name' => $author->display_name, 4843 'date_created_gmt' => $post_date_gmt, 4844 'post_status' => $entry['post_status'], 4845 'custom_fields' => $this->get_custom_fields($entry['ID']), 4846 'wp_post_format' => $post_format, 4847 'date_modified' => $post_modified, 4848 'date_modified_gmt' => $post_modified_gmt 4849 ); 4850 4851 $entry_index = count( $struct ) - 1; 4852 $struct[ $entry_index ][ 'wp_post_thumbnail' ] = get_post_thumbnail_id( $entry['ID'] ); 4853 } 4854 4855 $recent_posts = array(); 4856 for ( $j=0; $j<count($struct); $j++ ) { 4857 array_push($recent_posts, $struct[$j]); 4858 } 4859 4860 return $recent_posts; 4861 } 4862 4863 /** 4864 * Retrieve the list of categories on a given blog. 4865 * 4866 * @since 1.5.0 4867 * 4868 * @param array $args Method parameters. 4869 * @return array 4870 */ 4871 function mw_getCategories($args) { 4872 4873 $this->escape($args); 4874 4875 $blog_ID = (int) $args[0]; 4876 $username = $args[1]; 4877 $password = $args[2]; 4878 4879 if ( !$user = $this->login($username, $password) ) 4880 return $this->error; 4881 4882 if ( !current_user_can( 'edit_posts' ) ) 4883 return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) ); 4884 4885 do_action('xmlrpc_call', 'metaWeblog.getCategories'); 4886 4887 $categories_struct = array(); 4888 4889 if ( $cats = get_categories(array('get' => 'all')) ) { 4890 foreach ( $cats as $cat ) { 4891 $struct['categoryId'] = $cat->term_id; 4892 $struct['parentId'] = $cat->parent; 4893 $struct['description'] = $cat->name; 4894 $struct['categoryDescription'] = $cat->description; 4895 $struct['categoryName'] = $cat->name; 4896 $struct['htmlUrl'] = esc_html(get_category_link($cat->term_id)); 4897 $struct['rssUrl'] = esc_html(get_category_feed_link($cat->term_id, 'rss2')); 4898 4899 $categories_struct[] = $struct; 4900 } 4901 } 4902 4903 return $categories_struct; 4904 } 4905 4906 /** 4907 * Uploads a file, following your settings. 4908 * 4909 * Adapted from a patch by Johann Richard. 4910 * 4911 * @link http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/ 4912 * 4913 * @since 1.5.0 4914 * 4915 * @param array $args Method parameters. 4916 * @return array 4917 */ 4918 function mw_newMediaObject($args) { 4919 global $wpdb; 4920 4921 $blog_ID = (int) $args[0]; 4922 $username = $this->escape($args[1]); 4923 $password = $this->escape($args[2]); 4924 $data = $args[3]; 4925 4926 $name = sanitize_file_name( $data['name'] ); 4927 $type = $data['type']; 4928 $bits = $data['bits']; 4929 4930 if ( !$user = $this->login($username, $password) ) 4931 return $this->error; 4932 4933 do_action('xmlrpc_call', 'metaWeblog.newMediaObject'); 4934 4935 if ( !current_user_can('upload_files') ) { 4936 $this->error = new IXR_Error( 401, __( 'You do not have permission to upload files.' ) ); 4937 return $this->error; 4938 } 4939 4940 if ( $upload_err = apply_filters( 'pre_upload_error', false ) ) 4941 return new IXR_Error(500, $upload_err); 4942 4943 if ( !empty($data['overwrite']) && ($data['overwrite'] == true) ) { 4944 // Get postmeta info on the object. 4945 $old_file = $wpdb->get_row(" 4946 SELECT ID 4947 FROM {$wpdb->posts} 4948 WHERE post_title = '{$name}' 4949 AND post_type = 'attachment' 4950 "); 4951 4952 // Delete previous file. 4953 wp_delete_attachment($old_file->ID); 4954 4955 // Make sure the new name is different by pre-pending the 4956 // previous post id. 4957 $filename = preg_replace('/^wpid\d+-/', '', $name); 4958 $name = "wpid{$old_file->ID}-{$filename}"; 4959 } 4960 4961 $upload = wp_upload_bits($name, null, $bits); 4962 if ( ! empty($upload['error']) ) { 4963 $errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']); 4964 return new IXR_Error(500, $errorString); 4965 } 4966 // Construct the attachment array 4967 $post_id = 0; 4968 if ( ! empty( $data['post_id'] ) ) { 4969 $post_id = (int) $data['post_id']; 4970 4971 if ( ! current_user_can( 'edit_post', $post_id ) ) 4972 return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) ); 4973 } 4974 $attachment = array( 4975 'post_title' => $name, 4976 'post_content' => '', 4977 'post_type' => 'attachment', 4978 'post_parent' => $post_id, 4979 'post_mime_type' => $type, 4980 'guid' => $upload[ 'url' ] 4981 ); 4982 4983 // Save the data 4984 $id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id ); 4985 wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) ); 4986 4987 do_action( 'xmlrpc_call_success_mw_newMediaObject', $id, $args ); 4988 4989 $struct = array( 4990 'id' => strval( $id ), 4991 'file' => $name, 4992 'url' => $upload[ 'url' ], 4993 'type' => $type 4994 ); 4995 return apply_filters( 'wp_handle_upload', $struct, 'upload' ); 4996 } 4997 4998 /* MovableType API functions 4999 * specs on http://www.movabletype.org/docs/mtmanual_programmatic.html 5000 */ 5001 5002 /** 5003 * Retrieve the post titles of recent posts. 5004 * 5005 * @since 1.5.0 5006 * 5007 * @param array $args Method parameters. 5008 * @return array 5009 */ 5010 function mt_getRecentPostTitles($args) { 5011 5012 $this->escape($args); 5013 5014 $blog_ID = (int) $args[0]; 5015 $username = $args[1]; 5016 $password = $args[2]; 5017 if ( isset( $args[3] ) ) 5018 $query = array( 'numberposts' => absint( $args[3] ) ); 5019 else 5020 $query = array(); 5021 5022 if ( !$user = $this->login($username, $password) ) 5023 return $this->error; 5024 5025 do_action('xmlrpc_call', 'mt.getRecentPostTitles'); 5026 5027 $posts_list = wp_get_recent_posts( $query ); 5028 5029 if ( !$posts_list ) { 5030 $this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.')); 5031 return $this->error; 5032 } 5033 5034 $struct = array(); 5035 5036 foreach ($posts_list as $entry) { 5037 if ( !current_user_can( 'edit_post', $entry['ID'] ) ) 5038 continue; 5039 5040 $post_date = $this->_convert_date( $entry['post_date'] ); 5041 $post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] ); 5042 5043 $struct[] = array( 5044 'dateCreated' => $post_date, 5045 'userid' => $entry['post_author'], 5046 'postid' => (string) $entry['ID'], 5047 'title' => $entry['post_title'], 5048 'post_status' => $entry['post_status'], 5049 'date_created_gmt' => $post_date_gmt 5050 ); 5051 5052 } 5053 5054 $recent_posts = array(); 5055 for ( $j=0; $j<count($struct); $j++ ) { 5056 array_push($recent_posts, $struct[$j]); 5057 } 5058 5059 return $recent_posts; 5060 } 5061 5062 /** 5063 * Retrieve list of all categories on blog. 5064 * 5065 * @since 1.5.0 5066 * 5067 * @param array $args Method parameters. 5068 * @return array 5069 */ 5070 function mt_getCategoryList($args) { 5071 5072 $this->escape($args); 5073 5074 $blog_ID = (int) $args[0]; 5075 $username = $args[1]; 5076 $password = $args[2]; 5077 5078 if ( !$user = $this->login($username, $password) ) 5079 return $this->error; 5080 5081 if ( !current_user_can( 'edit_posts' ) ) 5082 return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) ); 5083 5084 do_action('xmlrpc_call', 'mt.getCategoryList'); 5085 5086 $categories_struct = array(); 5087 5088 if ( $cats = get_categories(array('hide_empty' => 0, 'hierarchical' => 0)) ) { 5089 foreach ( $cats as $cat ) { 5090 $struct['categoryId'] = $cat->term_id; 5091 $struct['categoryName'] = $cat->name; 5092 5093 $categories_struct[] = $struct; 5094 } 5095 } 5096 5097 return $categories_struct; 5098 } 5099 5100 /** 5101 * Retrieve post categories. 5102 * 5103 * @since 1.5.0 5104 * 5105 * @param array $args Method parameters. 5106 * @return array 5107 */ 5108 function mt_getPostCategories($args) { 5109 5110 $this->escape($args); 5111 5112 $post_ID = (int) $args[0]; 5113 $username = $args[1]; 5114 $password = $args[2]; 5115 5116 if ( !$user = $this->login($username, $password) ) 5117 return $this->error; 5118 5119 if ( ! get_post( $post_ID ) ) 5120 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 5121 5122 if ( !current_user_can( 'edit_post', $post_ID ) ) 5123 return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) ); 5124 5125 do_action('xmlrpc_call', 'mt.getPostCategories'); 5126 5127 $categories = array(); 5128 $catids = wp_get_post_categories(intval($post_ID)); 5129 // first listed category will be the primary category 5130 $isPrimary = true; 5131 foreach ( $catids as $catid ) { 5132 $categories[] = array( 5133 'categoryName' => get_cat_name($catid), 5134 'categoryId' => (string) $catid, 5135 'isPrimary' => $isPrimary 5136 ); 5137 $isPrimary = false; 5138 } 5139 5140 return $categories; 5141 } 5142 5143 /** 5144 * Sets categories for a post. 5145 * 5146 * @since 1.5.0 5147 * 5148 * @param array $args Method parameters. 5149 * @return bool True on success. 5150 */ 5151 function mt_setPostCategories($args) { 5152 5153 $this->escape($args); 5154 5155 $post_ID = (int) $args[0]; 5156 $username = $args[1]; 5157 $password = $args[2]; 5158 $categories = $args[3]; 5159 5160 if ( !$user = $this->login($username, $password) ) 5161 return $this->error; 5162 5163 do_action('xmlrpc_call', 'mt.setPostCategories'); 5164 5165 if ( ! get_post( $post_ID ) ) 5166 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 5167 5168 if ( !current_user_can('edit_post', $post_ID) ) 5169 return new IXR_Error(401, __('Sorry, you cannot edit this post.')); 5170 5171 $catids = array(); 5172 foreach ( $categories as $cat ) { 5173 $catids[] = $cat['categoryId']; 5174 } 5175 5176 wp_set_post_categories($post_ID, $catids); 5177 5178 return true; 5179 } 5180 5181 /** 5182 * Retrieve an array of methods supported by this server. 5183 * 5184 * @since 1.5.0 5185 * 5186 * @param array $args Method parameters. 5187 * @return array 5188 */ 5189 function mt_supportedMethods($args) { 5190 5191 do_action('xmlrpc_call', 'mt.supportedMethods'); 5192 5193 $supported_methods = array(); 5194 foreach ( $this->methods as $key => $value ) { 5195 $supported_methods[] = $key; 5196 } 5197 5198 return $supported_methods; 5199 } 5200 5201 /** 5202 * Retrieve an empty array because we don't support per-post text filters. 5203 * 5204 * @since 1.5.0 5205 * 5206 * @param array $args Method parameters. 5207 */ 5208 function mt_supportedTextFilters($args) { 5209 do_action('xmlrpc_call', 'mt.supportedTextFilters'); 5210 return apply_filters('xmlrpc_text_filters', array()); 5211 } 5212 5213 /** 5214 * Retrieve trackbacks sent to a given post. 5215 * 5216 * @since 1.5.0 5217 * 5218 * @param array $args Method parameters. 5219 * @return mixed 5220 */ 5221 function mt_getTrackbackPings($args) { 5222 5223 global $wpdb; 5224 5225 $post_ID = intval($args); 5226 5227 do_action('xmlrpc_call', 'mt.getTrackbackPings'); 5228 5229 $actual_post = get_post($post_ID, ARRAY_A); 5230 5231 if ( !$actual_post ) 5232 return new IXR_Error(404, __('Sorry, no such post.')); 5233 5234 $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) ); 5235 5236 if ( !$comments ) 5237 return array(); 5238 5239 $trackback_pings = array(); 5240 foreach ( $comments as $comment ) { 5241 if ( 'trackback' == $comment->comment_type ) { 5242 $content = $comment->comment_content; 5243 $title = substr($content, 8, (strpos($content, '</strong>') - 8)); 5244 $trackback_pings[] = array( 5245 'pingTitle' => $title, 5246 'pingURL' => $comment->comment_author_url, 5247 'pingIP' => $comment->comment_author_IP 5248 ); 5249 } 5250 } 5251 5252 return $trackback_pings; 5253 } 5254 5255 /** 5256 * Sets a post's publish status to 'publish'. 5257 * 5258 * @since 1.5.0 5259 * 5260 * @param array $args Method parameters. 5261 * @return int 5262 */ 5263 function mt_publishPost($args) { 5264 5265 $this->escape($args); 5266 5267 $post_ID = (int) $args[0]; 5268 $username = $args[1]; 5269 $password = $args[2]; 5270 5271 if ( !$user = $this->login($username, $password) ) 5272 return $this->error; 5273 5274 do_action('xmlrpc_call', 'mt.publishPost'); 5275 5276 $postdata = get_post($post_ID, ARRAY_A); 5277 if ( ! $postdata ) 5278 return new IXR_Error( 404, __( 'Invalid post ID.' ) ); 5279 5280 if ( !current_user_can('publish_posts') || !current_user_can('edit_post', $post_ID) ) 5281 return new IXR_Error(401, __('Sorry, you cannot publish this post.')); 5282 5283 $postdata['post_status'] = 'publish'; 5284 5285 // retain old cats 5286 $cats = wp_get_post_categories($post_ID); 5287 $postdata['post_category'] = $cats; 5288 $this->escape($postdata); 5289 5290 $result = wp_update_post($postdata); 5291 5292 return $result; 5293 } 5294 5295 /* PingBack functions 5296 * specs on www.hixie.ch/specs/pingback/pingback 5297 */ 5298 5299 /** 5300 * Retrieves a pingback and registers it. 5301 * 5302 * @since 1.5.0 5303 * 5304 * @param array $args Method parameters. 5305 * @return array 5306 */ 5307 function pingback_ping($args) { 5308 global $wpdb; 5309 5310 do_action('xmlrpc_call', 'pingback.ping'); 5311 5312 $this->escape($args); 5313 5314 $pagelinkedfrom = $args[0]; 5315 $pagelinkedto = $args[1]; 5316 5317 $title = ''; 5318 5319 $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom); 5320 $pagelinkedto = str_replace('&', '&', $pagelinkedto); 5321 $pagelinkedto = str_replace('&', '&', $pagelinkedto); 5322 5323 $pagelinkedfrom = apply_filters( 'pingback_ping_source_uri', $pagelinkedfrom, $pagelinkedto ); 5324 if ( ! $pagelinkedfrom ) 5325 return $this->pingback_error( 0, __( 'A valid URL was not provided.' ) ); 5326 5327 // Check if the page linked to is in our site 5328 $pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home'))); 5329 if ( !$pos1 ) 5330 return $this->pingback_error( 0, __( 'Is there no link to us?' ) ); 5331 5332 // let's find which post is linked to 5333 // FIXME: does url_to_postid() cover all these cases already? 5334 // if so, then let's use it and drop the old code. 5335 $urltest = parse_url($pagelinkedto); 5336 if ( $post_ID = url_to_postid($pagelinkedto) ) { 5337 $way = 'url_to_postid()'; 5338 } elseif ( preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) { 5339 // the path defines the post_ID (archives/p/XXXX) 5340 $blah = explode('/', $match[0]); 5341 $post_ID = (int) $blah[1]; 5342 $way = 'from the path'; 5343 } elseif ( isset( $urltest['query'] ) && preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) { 5344 // the querystring defines the post_ID (?p=XXXX) 5345 $blah = explode('=', $match[0]); 5346 $post_ID = (int) $blah[1]; 5347 $way = 'from the querystring'; 5348 } elseif ( isset($urltest['fragment']) ) { 5349 // an #anchor is there, it's either... 5350 if ( intval($urltest['fragment']) ) { 5351 // ...an integer #XXXX (simplest case) 5352 $post_ID = (int) $urltest['fragment']; 5353 $way = 'from the fragment (numeric)'; 5354 } elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) { 5355 // ...a post id in the form 'post-###' 5356 $post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']); 5357 $way = 'from the fragment (post-###)'; 5358 } elseif ( is_string($urltest['fragment']) ) { 5359 // ...or a string #title, a little more complicated 5360 $title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']); 5361 $sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", like_escape( $title ) ); 5362 if (! ($post_ID = $wpdb->get_var($sql)) ) { 5363 // returning unknown error '0' is better than die()ing 5364 return $this->pingback_error( 0, '' ); 5365 } 5366 $way = 'from the fragment (title)'; 5367 } 5368 } else { 5369 // TODO: Attempt to extract a post ID from the given URL 5370 return $this->pingback_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.' ) ); 5371 } 5372 $post_ID = (int) $post_ID; 5373 5374 $post = get_post($post_ID); 5375 5376 if ( !$post ) // Post_ID not found 5377 return $this->pingback_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.' ) ); 5378 5379 if ( $post_ID == url_to_postid($pagelinkedfrom) ) 5380 return $this->pingback_error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) ); 5381 5382 // Check if pings are on 5383 if ( !pings_open($post) ) 5384 return $this->pingback_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.' ) ); 5385 5386 // Let's check that the remote site didn't already pingback this entry 5387 if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) ) 5388 return $this->pingback_error( 48, __( 'The pingback has already been registered.' ) ); 5389 5390 // very stupid, but gives time to the 'from' server to publish ! 5391 sleep(1); 5392 5393 // Let's check the remote site 5394 $http_api_args = array( 5395 'timeout' => 10, 5396 'redirection' => 0, 5397 'limit_response_size' => 153600, // 150 KB 5398 ); 5399 $linea = wp_remote_retrieve_body( wp_safe_remote_get( $pagelinkedfrom, $http_api_args ) ); 5400 5401 if ( !$linea ) 5402 return $this->pingback_error( 16, __( 'The source URL does not exist.' ) ); 5403 5404 $linea = apply_filters('pre_remote_source', $linea, $pagelinkedto); 5405 5406 // Work around bug in strip_tags(): 5407 $linea = str_replace('<!DOC', '<DOC', $linea); 5408 $linea = preg_replace( '/[\r\n\t ]+/', ' ', $linea ); // normalize spaces 5409 $linea = preg_replace( "/<\/*(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea ); 5410 5411 preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle); 5412 $title = $matchtitle[1]; 5413 if ( empty( $title ) ) 5414 return $this->pingback_error( 32, __('We cannot find a title on that page.' ) ); 5415 5416 $linea = strip_tags( $linea, '<a>' ); // just keep the tag we need 5417 5418 $p = explode( "\n\n", $linea ); 5419 5420 $preg_target = preg_quote($pagelinkedto, '|'); 5421 5422 foreach ( $p as $para ) { 5423 if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link? 5424 preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context); 5425 5426 // If the URL isn't in a link context, keep looking 5427 if ( empty($context) ) 5428 continue; 5429 5430 // We're going to use this fake tag to mark the context in a bit 5431 // the marker is needed in case the link text appears more than once in the paragraph 5432 $excerpt = preg_replace('|\</?wpcontext\>|', '', $para); 5433 5434 // prevent really long link text 5435 if ( strlen($context[1]) > 100 ) 5436 $context[1] = substr($context[1], 0, 100) . '…'; 5437 5438 $marker = '<wpcontext>'.$context[1].'</wpcontext>'; // set up our marker 5439 $excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker 5440 $excerpt = strip_tags($excerpt, '<wpcontext>'); // strip all tags but our context marker 5441 $excerpt = trim($excerpt); 5442 $preg_marker = preg_quote($marker, '|'); 5443 $excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt); 5444 $excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper 5445 break; 5446 } 5447 } 5448 5449 if ( empty($context) ) // Link to target not found 5450 return $this->pingback_error( 17, __( 'The source URL does not contain a link to the target URL, and so cannot be used as a source.' ) ); 5451 5452 $pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom); 5453 5454 $context = '[…] ' . esc_html( $excerpt ) . ' […]'; 5455 $pagelinkedfrom = $this->escape( $pagelinkedfrom ); 5456 5457 $comment_post_ID = (int) $post_ID; 5458 $comment_author = $title; 5459 $comment_author_email = ''; 5460 $this->escape($comment_author); 5461 $comment_author_url = $pagelinkedfrom; 5462 $comment_content = $context; 5463 $this->escape($comment_content); 5464 $comment_type = 'pingback'; 5465 5466 $commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_author_email', 'comment_content', 'comment_type'); 5467 5468 $comment_ID = wp_new_comment($commentdata); 5469 do_action('pingback_post', $comment_ID); 5470 5471 return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto); 5472 } 5473 5474 /** 5475 * Retrieve array of URLs that pingbacked the given URL. 5476 * 5477 * Specs on http://www.aquarionics.com/misc/archives/blogite/0198.html 5478 * 5479 * @since 1.5.0 5480 * 5481 * @param array $args Method parameters. 5482 * @return array 5483 */ 5484 function pingback_extensions_getPingbacks($args) { 5485 5486 global $wpdb; 5487 5488 do_action('xmlrpc_call', 'pingback.extensions.getPingbacks'); 5489 5490 $this->escape($args); 5491 5492 $url = $args; 5493 5494 $post_ID = url_to_postid($url); 5495 if ( !$post_ID ) { 5496 // We aren't sure that the resource is available and/or pingback enabled 5497 return $this->pingback_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.' ) ); 5498 } 5499 5500 $actual_post = get_post($post_ID, ARRAY_A); 5501 5502 if ( !$actual_post ) { 5503 // No such post = resource not found 5504 return $this->pingback_error( 32, __('The specified target URL does not exist.' ) ); 5505 } 5506 5507 $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) ); 5508 5509 if ( !$comments ) 5510 return array(); 5511 5512 $pingbacks = array(); 5513 foreach ( $comments as $comment ) { 5514 if ( 'pingback' == $comment->comment_type ) 5515 $pingbacks[] = $comment->comment_author_url; 5516 } 5517 5518 return $pingbacks; 5519 } 5520 5521 protected function pingback_error( $code, $message ) { 5522 return apply_filters( 'xmlrpc_pingback_error', new IXR_Error( $code, $message ) ); 5523 } 5524 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Tue Mar 25 01:41:18 2014 | WordPress honlapkészítés: online1.hu |