3
* XML-RPC protocol support for WordPress
6
* @subpackage Publishing
10
* WordPress XMLRPC server implementation.
12
* Implements compatibility for Blogger API, MetaWeblog API, MovableType, and
13
* pingback. Additional WordPress API for managing comments, pages, posts,
16
* As of WordPress 3.5.0, XML-RPC is enabled by default. It can be disabled
17
* via the xmlrpc_enabled filter found in wp_xmlrpc_server::login().
20
* @subpackage Publishing
23
class wp_xmlrpc_server extends IXR_Server {
26
* Register all of the XMLRPC methods that XMLRPC server understands.
28
* Sets up server and method property. Passes XMLRPC
29
* methods through the 'xmlrpc_methods' filter to allow plugins to extend
30
* or replace XMLRPC methods.
34
* @return wp_xmlrpc_server
36
public function __construct() {
37
$this->methods = array(
39
'wp.getUsersBlogs' => 'this:wp_getUsersBlogs',
40
'wp.newPost' => 'this:wp_newPost',
41
'wp.editPost' => 'this:wp_editPost',
42
'wp.deletePost' => 'this:wp_deletePost',
43
'wp.getPost' => 'this:wp_getPost',
44
'wp.getPosts' => 'this:wp_getPosts',
45
'wp.newTerm' => 'this:wp_newTerm',
46
'wp.editTerm' => 'this:wp_editTerm',
47
'wp.deleteTerm' => 'this:wp_deleteTerm',
48
'wp.getTerm' => 'this:wp_getTerm',
49
'wp.getTerms' => 'this:wp_getTerms',
50
'wp.getTaxonomy' => 'this:wp_getTaxonomy',
51
'wp.getTaxonomies' => 'this:wp_getTaxonomies',
52
'wp.getUser' => 'this:wp_getUser',
53
'wp.getUsers' => 'this:wp_getUsers',
54
'wp.getProfile' => 'this:wp_getProfile',
55
'wp.editProfile' => 'this:wp_editProfile',
56
'wp.getPage' => 'this:wp_getPage',
57
'wp.getPages' => 'this:wp_getPages',
58
'wp.newPage' => 'this:wp_newPage',
59
'wp.deletePage' => 'this:wp_deletePage',
60
'wp.editPage' => 'this:wp_editPage',
61
'wp.getPageList' => 'this:wp_getPageList',
62
'wp.getAuthors' => 'this:wp_getAuthors',
63
'wp.getCategories' => 'this:mw_getCategories', // Alias
64
'wp.getTags' => 'this:wp_getTags',
65
'wp.newCategory' => 'this:wp_newCategory',
66
'wp.deleteCategory' => 'this:wp_deleteCategory',
67
'wp.suggestCategories' => 'this:wp_suggestCategories',
68
'wp.uploadFile' => 'this:mw_newMediaObject', // Alias
69
'wp.deleteFile' => 'this:wp_deletePost', // Alias
70
'wp.getCommentCount' => 'this:wp_getCommentCount',
71
'wp.getPostStatusList' => 'this:wp_getPostStatusList',
72
'wp.getPageStatusList' => 'this:wp_getPageStatusList',
73
'wp.getPageTemplates' => 'this:wp_getPageTemplates',
74
'wp.getOptions' => 'this:wp_getOptions',
75
'wp.setOptions' => 'this:wp_setOptions',
76
'wp.getComment' => 'this:wp_getComment',
77
'wp.getComments' => 'this:wp_getComments',
78
'wp.deleteComment' => 'this:wp_deleteComment',
79
'wp.editComment' => 'this:wp_editComment',
80
'wp.newComment' => 'this:wp_newComment',
81
'wp.getCommentStatusList' => 'this:wp_getCommentStatusList',
82
'wp.getMediaItem' => 'this:wp_getMediaItem',
83
'wp.getMediaLibrary' => 'this:wp_getMediaLibrary',
84
'wp.getPostFormats' => 'this:wp_getPostFormats',
85
'wp.getPostType' => 'this:wp_getPostType',
86
'wp.getPostTypes' => 'this:wp_getPostTypes',
87
'wp.getRevisions' => 'this:wp_getRevisions',
88
'wp.restoreRevision' => 'this:wp_restoreRevision',
91
'blogger.getUsersBlogs' => 'this:blogger_getUsersBlogs',
92
'blogger.getUserInfo' => 'this:blogger_getUserInfo',
93
'blogger.getPost' => 'this:blogger_getPost',
94
'blogger.getRecentPosts' => 'this:blogger_getRecentPosts',
95
'blogger.newPost' => 'this:blogger_newPost',
96
'blogger.editPost' => 'this:blogger_editPost',
97
'blogger.deletePost' => 'this:blogger_deletePost',
99
// MetaWeblog API (with MT extensions to structs)
100
'metaWeblog.newPost' => 'this:mw_newPost',
101
'metaWeblog.editPost' => 'this:mw_editPost',
102
'metaWeblog.getPost' => 'this:mw_getPost',
103
'metaWeblog.getRecentPosts' => 'this:mw_getRecentPosts',
104
'metaWeblog.getCategories' => 'this:mw_getCategories',
105
'metaWeblog.newMediaObject' => 'this:mw_newMediaObject',
107
// MetaWeblog API aliases for Blogger API
108
// see http://www.xmlrpc.com/stories/storyReader$2460
109
'metaWeblog.deletePost' => 'this:blogger_deletePost',
110
'metaWeblog.getUsersBlogs' => 'this:blogger_getUsersBlogs',
113
'mt.getCategoryList' => 'this:mt_getCategoryList',
114
'mt.getRecentPostTitles' => 'this:mt_getRecentPostTitles',
115
'mt.getPostCategories' => 'this:mt_getPostCategories',
116
'mt.setPostCategories' => 'this:mt_setPostCategories',
117
'mt.supportedMethods' => 'this:mt_supportedMethods',
118
'mt.supportedTextFilters' => 'this:mt_supportedTextFilters',
119
'mt.getTrackbackPings' => 'this:mt_getTrackbackPings',
120
'mt.publishPost' => 'this:mt_publishPost',
123
'pingback.ping' => 'this:pingback_ping',
124
'pingback.extensions.getPingbacks' => 'this:pingback_extensions_getPingbacks',
126
'demo.sayHello' => 'this:sayHello',
127
'demo.addTwoNumbers' => 'this:addTwoNumbers'
130
$this->initialise_blog_option_info();
133
* Filter the methods exposed by the XML-RPC server.
135
* This filter can be used to add new methods, and remove built-in methods.
139
* @param array $methods An array of XML-RPC methods.
141
$this->methods = apply_filters( 'xmlrpc_methods', $this->methods );
145
* Make private/protected methods readable for backwards compatibility.
150
* @param callable $name Method to call.
151
* @param array $arguments Arguments to pass when calling.
152
* @return mixed|bool Return value of the callback, false otherwise.
154
public function __call( $name, $arguments ) {
155
return call_user_func_array( array( $this, $name ), $arguments );
158
public function serve_request() {
159
$this->IXR_Server($this->methods);
163
* Test XMLRPC API by saying, "Hello!" to client.
167
* @param array $args Method Parameters.
170
public function sayHello($args) {
175
* Test XMLRPC API by adding two numbers for client.
179
* @param array $args Method Parameters.
182
public function addTwoNumbers($args) {
185
return $number1 + $number2;
193
* @param string $username User's username.
194
* @param string $password User's password.
195
* @return mixed WP_User object if authentication passed, false otherwise
197
public function login( $username, $password ) {
199
* Respect old get_option() filters left for back-compat when the 'enable_xmlrpc'
200
* option was deprecated in 3.5.0. Use the 'xmlrpc_enabled' hook instead.
202
$enabled = apply_filters( 'pre_option_enable_xmlrpc', false );
203
if ( false === $enabled ) {
204
$enabled = apply_filters( 'option_enable_xmlrpc', true );
208
* Filter whether XML-RPC is enabled.
210
* This is the proper filter for turning off XML-RPC.
214
* @param bool $enabled Whether XML-RPC is enabled. Default true.
216
$enabled = apply_filters( 'xmlrpc_enabled', $enabled );
219
$this->error = new IXR_Error( 405, sprintf( __( 'XML-RPC services are disabled on this site.' ) ) );
223
$user = wp_authenticate($username, $password);
225
if (is_wp_error($user)) {
226
$this->error = new IXR_Error( 403, __( 'Incorrect username or password.' ) );
229
* Filter the XML-RPC user login error message.
233
* @param string $error The XML-RPC error message.
234
* @param WP_User $user WP_User object.
236
$this->error = apply_filters( 'xmlrpc_login_error', $this->error, $user );
240
wp_set_current_user( $user->ID );
245
* Check user's credentials. Deprecated.
249
* @deprecated use wp_xmlrpc_server::login
250
* @see wp_xmlrpc_server::login
252
* @param string $username User's username.
253
* @param string $password User's password.
254
* @return bool Whether authentication passed.
256
public function login_pass_ok( $username, $password ) {
257
return (bool) $this->login( $username, $password );
261
* Escape string or array of strings for database.
265
* @param string|array $data Escape single string or array of strings.
266
* @return string|array Type matches $data and sanitized for the database.
268
public function escape( &$data ) {
269
if ( ! is_array( $data ) )
270
return wp_slash( $data );
272
foreach ( $data as &$v ) {
273
if ( is_array( $v ) )
275
elseif ( ! is_object( $v ) )
281
* Retrieve custom fields for post.
285
* @param int $post_id Post ID.
286
* @return array Custom fields, if exist.
288
public function get_custom_fields($post_id) {
289
$post_id = (int) $post_id;
291
$custom_fields = array();
293
foreach ( (array) has_meta($post_id) as $meta ) {
294
// Don't expose protected fields.
295
if ( ! current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) )
298
$custom_fields[] = array(
299
"id" => $meta['meta_id'],
300
"key" => $meta['meta_key'],
301
"value" => $meta['meta_value']
305
return $custom_fields;
309
* Set custom fields for post.
313
* @param int $post_id Post ID.
314
* @param array $fields Custom fields.
316
public function set_custom_fields($post_id, $fields) {
317
$post_id = (int) $post_id;
319
foreach ( (array) $fields as $meta ) {
320
if ( isset($meta['id']) ) {
321
$meta['id'] = (int) $meta['id'];
322
$pmeta = get_metadata_by_mid( 'post', $meta['id'] );
323
if ( isset($meta['key']) ) {
324
$meta['key'] = wp_unslash( $meta['key'] );
325
if ( $meta['key'] !== $pmeta->meta_key )
327
$meta['value'] = wp_unslash( $meta['value'] );
328
if ( current_user_can( 'edit_post_meta', $post_id, $meta['key'] ) )
329
update_metadata_by_mid( 'post', $meta['id'], $meta['value'] );
330
} elseif ( current_user_can( 'delete_post_meta', $post_id, $pmeta->meta_key ) ) {
331
delete_metadata_by_mid( 'post', $meta['id'] );
333
} elseif ( current_user_can( 'add_post_meta', $post_id, wp_unslash( $meta['key'] ) ) ) {
334
add_post_meta( $post_id, $meta['key'], $meta['value'] );
340
* Set up blog options property.
342
* Passes property through 'xmlrpc_blog_options' filter.
346
public function initialise_blog_option_info() {
349
$this->blog_options = array(
351
'software_name' => array(
352
'desc' => __( 'Software Name' ),
354
'value' => 'WordPress'
356
'software_version' => array(
357
'desc' => __( 'Software Version' ),
359
'value' => $wp_version
362
'desc' => __( 'WordPress Address (URL)' ),
364
'option' => 'siteurl'
367
'desc' => __( 'Site Address (URL)' ),
371
'login_url' => array(
372
'desc' => __( 'Login Address (URL)' ),
374
'value' => wp_login_url( )
376
'admin_url' => array(
377
'desc' => __( 'The URL to the admin area' ),
379
'value' => get_admin_url( )
381
'image_default_link_type' => array(
382
'desc' => __( 'Image default link type' ),
384
'option' => 'image_default_link_type'
386
'image_default_size' => array(
387
'desc' => __( 'Image default size' ),
389
'option' => 'image_default_size'
391
'image_default_align' => array(
392
'desc' => __( 'Image default align' ),
394
'option' => 'image_default_align'
397
'desc' => __( 'Template' ),
399
'option' => 'template'
401
'stylesheet' => array(
402
'desc' => __( 'Stylesheet' ),
404
'option' => 'stylesheet'
406
'post_thumbnail' => array(
407
'desc' => __('Post Thumbnail'),
409
'value' => current_theme_supports( 'post-thumbnails' )
413
'time_zone' => array(
414
'desc' => __( 'Time Zone' ),
416
'option' => 'gmt_offset'
418
'blog_title' => array(
419
'desc' => __( 'Site Title' ),
421
'option' => 'blogname'
423
'blog_tagline' => array(
424
'desc' => __( 'Site Tagline' ),
426
'option' => 'blogdescription'
428
'date_format' => array(
429
'desc' => __( 'Date Format' ),
431
'option' => 'date_format'
433
'time_format' => array(
434
'desc' => __( 'Time Format' ),
436
'option' => 'time_format'
438
'users_can_register' => array(
439
'desc' => __( 'Allow new users to sign up' ),
441
'option' => 'users_can_register'
443
'thumbnail_size_w' => array(
444
'desc' => __( 'Thumbnail Width' ),
446
'option' => 'thumbnail_size_w'
448
'thumbnail_size_h' => array(
449
'desc' => __( 'Thumbnail Height' ),
451
'option' => 'thumbnail_size_h'
453
'thumbnail_crop' => array(
454
'desc' => __( 'Crop thumbnail to exact dimensions' ),
456
'option' => 'thumbnail_crop'
458
'medium_size_w' => array(
459
'desc' => __( 'Medium size image width' ),
461
'option' => 'medium_size_w'
463
'medium_size_h' => array(
464
'desc' => __( 'Medium size image height' ),
466
'option' => 'medium_size_h'
468
'large_size_w' => array(
469
'desc' => __( 'Large size image width' ),
471
'option' => 'large_size_w'
473
'large_size_h' => array(
474
'desc' => __( 'Large size image height' ),
476
'option' => 'large_size_h'
478
'default_comment_status' => array(
479
'desc' => __( 'Allow people to post comments on new articles' ),
481
'option' => 'default_comment_status'
483
'default_ping_status' => array(
484
'desc' => __( 'Allow link notifications from other blogs (pingbacks and trackbacks)' ),
486
'option' => 'default_ping_status'
491
* Filter the XML-RPC blog options property.
495
* @param array $blog_options An array of XML-RPC blog options.
497
$this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options );
501
* Retrieve the blogs of the user.
505
* @param array $args Method parameters. Contains:
508
* @return array. Contains:
513
* - 'xmlrpc' - url of xmlrpc endpoint
515
public function wp_getUsersBlogs( $args ) {
516
// If this isn't on WPMU then just use blogger_getUsersBlogs
517
if ( !is_multisite() ) {
518
array_unshift( $args, 1 );
519
return $this->blogger_getUsersBlogs( $args );
522
$this->escape( $args );
524
$username = $args[0];
525
$password = $args[1];
527
if ( !$user = $this->login($username, $password) )
531
* Fires after the XML-RPC user has been authenticated but before the rest of
532
* the method logic begins.
534
* All built-in XML-RPC methods use the action xmlrpc_call, with a parameter
535
* equal to the method's name, e.g., wp.getUsersBlogs, wp.newPost, etc.
539
* @param method $name The method name.
541
do_action( 'xmlrpc_call', 'wp.getUsersBlogs' );
543
$blogs = (array) get_blogs_of_user( $user->ID );
546
foreach ( $blogs as $blog ) {
547
// Don't include blogs that aren't hosted at this site
548
if ( $blog->site_id != get_current_site()->id )
551
$blog_id = $blog->userblog_id;
553
switch_to_blog( $blog_id );
555
$is_admin = current_user_can( 'manage_options' );
558
'isAdmin' => $is_admin,
559
'url' => home_url( '/' ),
560
'blogid' => (string) $blog_id,
561
'blogName' => get_option( 'blogname' ),
562
'xmlrpc' => site_url( 'xmlrpc.php', 'rpc' ),
565
restore_current_blog();
572
* Checks if the method received at least the minimum number of arguments.
576
* @param string|array $args Sanitize single string or array of strings.
577
* @param int $count Minimum number of arguments.
578
* @return boolean if $args contains at least $count arguments.
580
protected function minimum_args( $args, $count ) {
581
if ( count( $args ) < $count ) {
582
$this->error = new IXR_Error( 400, __( 'Insufficient arguments passed to this XML-RPC method.' ) );
590
* Prepares taxonomy data for return in an XML-RPC object.
594
* @param object $taxonomy The unprepared taxonomy data
595
* @param array $fields The subset of taxonomy fields to return
596
* @return array The prepared taxonomy data
598
protected function _prepare_taxonomy( $taxonomy, $fields ) {
600
'name' => $taxonomy->name,
601
'label' => $taxonomy->label,
602
'hierarchical' => (bool) $taxonomy->hierarchical,
603
'public' => (bool) $taxonomy->public,
604
'show_ui' => (bool) $taxonomy->show_ui,
605
'_builtin' => (bool) $taxonomy->_builtin,
608
if ( in_array( 'labels', $fields ) )
609
$_taxonomy['labels'] = (array) $taxonomy->labels;
611
if ( in_array( 'cap', $fields ) )
612
$_taxonomy['cap'] = (array) $taxonomy->cap;
614
if ( in_array( 'menu', $fields ) )
615
$_taxonomy['show_in_menu'] = (bool) $_taxonomy->show_in_menu;
617
if ( in_array( 'object_type', $fields ) )
618
$_taxonomy['object_type'] = array_unique( (array) $taxonomy->object_type );
621
* Filter XML-RPC-prepared data for the given taxonomy.
625
* @param array $_taxonomy An array of taxonomy data.
626
* @param object $taxonomy Taxonomy object.
627
* @param array $fields The subset of taxonomy fields to return.
629
return apply_filters( 'xmlrpc_prepare_taxonomy', $_taxonomy, $taxonomy, $fields );
633
* Prepares term data for return in an XML-RPC object.
637
* @param array|object $term The unprepared term data
638
* @return array The prepared term data
640
protected function _prepare_term( $term ) {
642
if ( ! is_array( $_term) )
643
$_term = get_object_vars( $_term );
645
// For integers which may be larger than XML-RPC supports ensure we return strings.
646
$_term['term_id'] = strval( $_term['term_id'] );
647
$_term['term_group'] = strval( $_term['term_group'] );
648
$_term['term_taxonomy_id'] = strval( $_term['term_taxonomy_id'] );
649
$_term['parent'] = strval( $_term['parent'] );
651
// Count we are happy to return as an integer because people really shouldn't use terms that much.
652
$_term['count'] = intval( $_term['count'] );
655
* Filter XML-RPC-prepared data for the given term.
659
* @param array $_term An array of term data.
660
* @param array|object $term Term object or array.
662
return apply_filters( 'xmlrpc_prepare_term', $_term, $term );
666
* Convert a WordPress date string to an IXR_Date object.
670
* @param string $date
673
protected function _convert_date( $date ) {
674
if ( $date === '0000-00-00 00:00:00' ) {
675
return new IXR_Date( '00000000T00:00:00Z' );
677
return new IXR_Date( mysql2date( 'Ymd\TH:i:s', $date, false ) );
681
* Convert a WordPress GMT date string to an IXR_Date object.
685
* @param string $date_gmt
686
* @param string $date
689
protected function _convert_date_gmt( $date_gmt, $date ) {
690
if ( $date !== '0000-00-00 00:00:00' && $date_gmt === '0000-00-00 00:00:00' ) {
691
return new IXR_Date( get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $date, false ), 'Ymd\TH:i:s' ) );
693
return $this->_convert_date( $date_gmt );
697
* Prepares post data for return in an XML-RPC object.
701
* @param array $post The unprepared post data
702
* @param array $fields The subset of post type fields to return
703
* @return array The prepared post data
705
protected function _prepare_post( $post, $fields ) {
706
// holds the data for this post. built up based on $fields
707
$_post = array( 'post_id' => strval( $post['ID'] ) );
709
// prepare common post fields
710
$post_fields = array(
711
'post_title' => $post['post_title'],
712
'post_date' => $this->_convert_date( $post['post_date'] ),
713
'post_date_gmt' => $this->_convert_date_gmt( $post['post_date_gmt'], $post['post_date'] ),
714
'post_modified' => $this->_convert_date( $post['post_modified'] ),
715
'post_modified_gmt' => $this->_convert_date_gmt( $post['post_modified_gmt'], $post['post_modified'] ),
716
'post_status' => $post['post_status'],
717
'post_type' => $post['post_type'],
718
'post_name' => $post['post_name'],
719
'post_author' => $post['post_author'],
720
'post_password' => $post['post_password'],
721
'post_excerpt' => $post['post_excerpt'],
722
'post_content' => $post['post_content'],
723
'post_parent' => strval( $post['post_parent'] ),
724
'post_mime_type' => $post['post_mime_type'],
725
'link' => post_permalink( $post['ID'] ),
726
'guid' => $post['guid'],
727
'menu_order' => intval( $post['menu_order'] ),
728
'comment_status' => $post['comment_status'],
729
'ping_status' => $post['ping_status'],
730
'sticky' => ( $post['post_type'] === 'post' && is_sticky( $post['ID'] ) ),
734
$post_fields['post_thumbnail'] = array();
735
$thumbnail_id = get_post_thumbnail_id( $post['ID'] );
736
if ( $thumbnail_id ) {
737
$thumbnail_size = current_theme_supports('post-thumbnail') ? 'post-thumbnail' : 'thumbnail';
738
$post_fields['post_thumbnail'] = $this->_prepare_media_item( get_post( $thumbnail_id ), $thumbnail_size );
741
// Consider future posts as published
742
if ( $post_fields['post_status'] === 'future' )
743
$post_fields['post_status'] = 'publish';
745
// Fill in blank post format
746
$post_fields['post_format'] = get_post_format( $post['ID'] );
747
if ( empty( $post_fields['post_format'] ) )
748
$post_fields['post_format'] = 'standard';
750
// Merge requested $post_fields fields into $_post
751
if ( in_array( 'post', $fields ) ) {
752
$_post = array_merge( $_post, $post_fields );
754
$requested_fields = array_intersect_key( $post_fields, array_flip( $fields ) );
755
$_post = array_merge( $_post, $requested_fields );
758
$all_taxonomy_fields = in_array( 'taxonomies', $fields );
760
if ( $all_taxonomy_fields || in_array( 'terms', $fields ) ) {
761
$post_type_taxonomies = get_object_taxonomies( $post['post_type'], 'names' );
762
$terms = wp_get_object_terms( $post['ID'], $post_type_taxonomies );
763
$_post['terms'] = array();
764
foreach ( $terms as $term ) {
765
$_post['terms'][] = $this->_prepare_term( $term );
769
if ( in_array( 'custom_fields', $fields ) )
770
$_post['custom_fields'] = $this->get_custom_fields( $post['ID'] );
772
if ( in_array( 'enclosure', $fields ) ) {
773
$_post['enclosure'] = array();
774
$enclosures = (array) get_post_meta( $post['ID'], 'enclosure' );
775
if ( ! empty( $enclosures ) ) {
776
$encdata = explode( "\n", $enclosures[0] );
777
$_post['enclosure']['url'] = trim( htmlspecialchars( $encdata[0] ) );
778
$_post['enclosure']['length'] = (int) trim( $encdata[1] );
779
$_post['enclosure']['type'] = trim( $encdata[2] );
784
* Filter XML-RPC-prepared date for the given post.
788
* @param array $_post An array of modified post data.
789
* @param array $post An array of post data.
790
* @param array $fields An array of post fields.
792
return apply_filters( 'xmlrpc_prepare_post', $_post, $post, $fields );
796
* Prepares post data for return in an XML-RPC object.
800
* @param object $post_type Post type object
801
* @param array $fields The subset of post fields to return
802
* @return array The prepared post type data
804
protected function _prepare_post_type( $post_type, $fields ) {
806
'name' => $post_type->name,
807
'label' => $post_type->label,
808
'hierarchical' => (bool) $post_type->hierarchical,
809
'public' => (bool) $post_type->public,
810
'show_ui' => (bool) $post_type->show_ui,
811
'_builtin' => (bool) $post_type->_builtin,
812
'has_archive' => (bool) $post_type->has_archive,
813
'supports' => get_all_post_type_supports( $post_type->name ),
816
if ( in_array( 'labels', $fields ) ) {
817
$_post_type['labels'] = (array) $post_type->labels;
820
if ( in_array( 'cap', $fields ) ) {
821
$_post_type['cap'] = (array) $post_type->cap;
822
$_post_type['map_meta_cap'] = (bool) $post_type->map_meta_cap;
825
if ( in_array( 'menu', $fields ) ) {
826
$_post_type['menu_position'] = (int) $post_type->menu_position;
827
$_post_type['menu_icon'] = $post_type->menu_icon;
828
$_post_type['show_in_menu'] = (bool) $post_type->show_in_menu;
831
if ( in_array( 'taxonomies', $fields ) )
832
$_post_type['taxonomies'] = get_object_taxonomies( $post_type->name, 'names' );
835
* Filter XML-RPC-prepared date for the given post type.
839
* @param array $_post_type An array of post type data.
840
* @param object $post_type Post type object.
842
return apply_filters( 'xmlrpc_prepare_post_type', $_post_type, $post_type );
846
* Prepares media item data for return in an XML-RPC object.
850
* @param object $media_item The unprepared media item data
851
* @param string $thumbnail_size The image size to use for the thumbnail URL
852
* @return array The prepared media item data
854
protected function _prepare_media_item( $media_item, $thumbnail_size = 'thumbnail' ) {
855
$_media_item = array(
856
'attachment_id' => strval( $media_item->ID ),
857
'date_created_gmt' => $this->_convert_date_gmt( $media_item->post_date_gmt, $media_item->post_date ),
858
'parent' => $media_item->post_parent,
859
'link' => wp_get_attachment_url( $media_item->ID ),
860
'title' => $media_item->post_title,
861
'caption' => $media_item->post_excerpt,
862
'description' => $media_item->post_content,
863
'metadata' => wp_get_attachment_metadata( $media_item->ID ),
866
$thumbnail_src = image_downsize( $media_item->ID, $thumbnail_size );
867
if ( $thumbnail_src )
868
$_media_item['thumbnail'] = $thumbnail_src[0];
870
$_media_item['thumbnail'] = $_media_item['link'];
873
* Filter XML-RPC-prepared data for the given media item.
877
* @param array $_media_item An array of media item data.
878
* @param object $media_item Media item object.
879
* @param string $thumbnail_size Image size.
881
return apply_filters( 'xmlrpc_prepare_media_item', $_media_item, $media_item, $thumbnail_size );
885
* Prepares page data for return in an XML-RPC object.
889
* @param object $page The unprepared page data
890
* @return array The prepared page data
892
protected function _prepare_page( $page ) {
893
// Get all of the page content and link.
894
$full_page = get_extended( $page->post_content );
895
$link = post_permalink( $page->ID );
897
// Get info the page parent if there is one.
899
if ( ! empty( $page->post_parent ) ) {
900
$parent = get_post( $page->post_parent );
901
$parent_title = $parent->post_title;
904
// Determine comment and ping settings.
905
$allow_comments = comments_open( $page->ID ) ? 1 : 0;
906
$allow_pings = pings_open( $page->ID ) ? 1 : 0;
909
$page_date = $this->_convert_date( $page->post_date );
910
$page_date_gmt = $this->_convert_date_gmt( $page->post_date_gmt, $page->post_date );
912
// Pull the categories info together.
913
$categories = array();
914
foreach ( wp_get_post_categories( $page->ID ) as $cat_id ) {
915
$categories[] = get_cat_name( $cat_id );
918
// Get the author info.
919
$author = get_userdata( $page->post_author );
921
$page_template = get_page_template_slug( $page->ID );
922
if ( empty( $page_template ) )
923
$page_template = 'default';
926
'dateCreated' => $page_date,
927
'userid' => $page->post_author,
928
'page_id' => $page->ID,
929
'page_status' => $page->post_status,
930
'description' => $full_page['main'],
931
'title' => $page->post_title,
933
'permaLink' => $link,
934
'categories' => $categories,
935
'excerpt' => $page->post_excerpt,
936
'text_more' => $full_page['extended'],
937
'mt_allow_comments' => $allow_comments,
938
'mt_allow_pings' => $allow_pings,
939
'wp_slug' => $page->post_name,
940
'wp_password' => $page->post_password,
941
'wp_author' => $author->display_name,
942
'wp_page_parent_id' => $page->post_parent,
943
'wp_page_parent_title' => $parent_title,
944
'wp_page_order' => $page->menu_order,
945
'wp_author_id' => (string) $author->ID,
946
'wp_author_display_name' => $author->display_name,
947
'date_created_gmt' => $page_date_gmt,
948
'custom_fields' => $this->get_custom_fields( $page->ID ),
949
'wp_page_template' => $page_template
953
* Filter XML-RPC-prepared data for the given page.
957
* @param array $_page An array of page data.
958
* @param WP_Post $page Page object.
960
return apply_filters( 'xmlrpc_prepare_page', $_page, $page );
964
* Prepares comment data for return in an XML-RPC object.
968
* @param object $comment The unprepared comment data
969
* @return array The prepared comment data
971
protected function _prepare_comment( $comment ) {
973
$comment_date = $this->_convert_date( $comment->comment_date );
974
$comment_date_gmt = $this->_convert_date_gmt( $comment->comment_date_gmt, $comment->comment_date );
976
if ( '0' == $comment->comment_approved )
977
$comment_status = 'hold';
978
else if ( 'spam' == $comment->comment_approved )
979
$comment_status = 'spam';
980
else if ( '1' == $comment->comment_approved )
981
$comment_status = 'approve';
983
$comment_status = $comment->comment_approved;
986
'date_created_gmt' => $comment_date_gmt,
987
'user_id' => $comment->user_id,
988
'comment_id' => $comment->comment_ID,
989
'parent' => $comment->comment_parent,
990
'status' => $comment_status,
991
'content' => $comment->comment_content,
992
'link' => get_comment_link($comment),
993
'post_id' => $comment->comment_post_ID,
994
'post_title' => get_the_title($comment->comment_post_ID),
995
'author' => $comment->comment_author,
996
'author_url' => $comment->comment_author_url,
997
'author_email' => $comment->comment_author_email,
998
'author_ip' => $comment->comment_author_IP,
999
'type' => $comment->comment_type,
1003
* Filter XML-RPC-prepared data for the given comment.
1007
* @param array $_comment An array of prepared comment data.
1008
* @param object $comment Comment object.
1010
return apply_filters( 'xmlrpc_prepare_comment', $_comment, $comment );
1014
* Prepares user data for return in an XML-RPC object.
1018
* @param WP_User $user The unprepared user object
1019
* @param array $fields The subset of user fields to return
1020
* @return array The prepared user data
1022
protected function _prepare_user( $user, $fields ) {
1023
$_user = array( 'user_id' => strval( $user->ID ) );
1025
$user_fields = array(
1026
'username' => $user->user_login,
1027
'first_name' => $user->user_firstname,
1028
'last_name' => $user->user_lastname,
1029
'registered' => $this->_convert_date( $user->user_registered ),
1030
'bio' => $user->user_description,
1031
'email' => $user->user_email,
1032
'nickname' => $user->nickname,
1033
'nicename' => $user->user_nicename,
1034
'url' => $user->user_url,
1035
'display_name' => $user->display_name,
1036
'roles' => $user->roles,
1039
if ( in_array( 'all', $fields ) ) {
1040
$_user = array_merge( $_user, $user_fields );
1042
if ( in_array( 'basic', $fields ) ) {
1043
$basic_fields = array( 'username', 'email', 'registered', 'display_name', 'nicename' );
1044
$fields = array_merge( $fields, $basic_fields );
1046
$requested_fields = array_intersect_key( $user_fields, array_flip( $fields ) );
1047
$_user = array_merge( $_user, $requested_fields );
1051
* Filter XML-RPC-prepared data for the given user.
1055
* @param array $_user An array of user data.
1056
* @param WP_User $user User object.
1057
* @param array $fields An array of user fields.
1059
return apply_filters( 'xmlrpc_prepare_user', $_user, $user, $fields );
1063
* Create a new post for any registered post type.
1067
* @param array $args Method parameters. Contains:
1069
* - string $username
1070
* - string $password
1071
* - array $content_struct
1072
* $content_struct can contain:
1073
* - post_type (default: 'post')
1074
* - post_status (default: 'draft')
1079
* - post_date_gmt | post_date
1082
* - comment_status - can be 'open' | 'closed'
1083
* - ping_status - can be 'open' | 'closed'
1085
* - post_thumbnail - ID of a media item to use as the post thumbnail/featured image
1086
* - custom_fields - array, with each element containing 'key' and 'value'
1087
* - terms - array, with taxonomy names as keys and arrays of term IDs as values
1088
* - terms_names - array, with taxonomy names as keys and arrays of term names as values
1090
* - any other fields supported by wp_insert_post()
1091
* @return string post_id
1093
public function wp_newPost( $args ) {
1094
if ( ! $this->minimum_args( $args, 4 ) )
1095
return $this->error;
1097
$this->escape( $args );
1099
$blog_id = (int) $args[0];
1100
$username = $args[1];
1101
$password = $args[2];
1102
$content_struct = $args[3];
1104
if ( ! $user = $this->login( $username, $password ) )
1105
return $this->error;
1107
// convert the date field back to IXR form
1108
if ( isset( $content_struct['post_date'] ) && ! is_a( $content_struct['post_date'], 'IXR_Date' ) ) {
1109
$content_struct['post_date'] = $this->_convert_date( $content_struct['post_date'] );
1112
// ignore the existing GMT date if it is empty or a non-GMT date was supplied in $content_struct,
1113
// since _insert_post will ignore the non-GMT date if the GMT date is set
1114
if ( isset( $content_struct['post_date_gmt'] ) && ! is_a( $content_struct['post_date_gmt'], 'IXR_Date' ) ) {
1115
if ( $content_struct['post_date_gmt'] == '0000-00-00 00:00:00' || isset( $content_struct['post_date'] ) ) {
1116
unset( $content_struct['post_date_gmt'] );
1118
$content_struct['post_date_gmt'] = $this->_convert_date( $content_struct['post_date_gmt'] );
1122
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1123
do_action( 'xmlrpc_call', 'wp.newPost' );
1125
unset( $content_struct['ID'] );
1127
return $this->_insert_post( $user, $content_struct );
1131
* Helper method for filtering out elements from an array.
1135
* @param int $count Number to compare to one.
1137
private function _is_greater_than_one( $count ) {
1142
* Helper method for wp_newPost and wp_editPost, containing shared logic.
1145
* @uses wp_insert_post()
1147
* @param WP_User $user The post author if post_author isn't set in $content_struct.
1148
* @param array $content_struct Post data to insert.
1150
protected function _insert_post( $user, $content_struct ) {
1151
$defaults = array( 'post_status' => 'draft', 'post_type' => 'post', 'post_author' => 0,
1152
'post_password' => '', 'post_excerpt' => '', 'post_content' => '', 'post_title' => '' );
1154
$post_data = wp_parse_args( $content_struct, $defaults );
1156
$post_type = get_post_type_object( $post_data['post_type'] );
1158
return new IXR_Error( 403, __( 'Invalid post type' ) );
1160
$update = ! empty( $post_data['ID'] );
1163
if ( ! get_post( $post_data['ID'] ) )
1164
return new IXR_Error( 401, __( 'Invalid post ID.' ) );
1165
if ( ! current_user_can( 'edit_post', $post_data['ID'] ) )
1166
return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post.' ) );
1167
if ( $post_data['post_type'] != get_post_type( $post_data['ID'] ) )
1168
return new IXR_Error( 401, __( 'The post type may not be changed.' ) );
1170
if ( ! current_user_can( $post_type->cap->create_posts ) || ! current_user_can( $post_type->cap->edit_posts ) )
1171
return new IXR_Error( 401, __( 'Sorry, you are not allowed to post on this site.' ) );
1174
switch ( $post_data['post_status'] ) {
1179
if ( ! current_user_can( $post_type->cap->publish_posts ) )
1180
return new IXR_Error( 401, __( 'Sorry, you are not allowed to create private posts in this post type' ) );
1184
if ( ! current_user_can( $post_type->cap->publish_posts ) )
1185
return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts in this post type' ) );
1188
if ( ! get_post_status_object( $post_data['post_status'] ) )
1189
$post_data['post_status'] = 'draft';
1193
if ( ! empty( $post_data['post_password'] ) && ! current_user_can( $post_type->cap->publish_posts ) )
1194
return new IXR_Error( 401, __( 'Sorry, you are not allowed to create password protected posts in this post type' ) );
1196
$post_data['post_author'] = absint( $post_data['post_author'] );
1197
if ( ! empty( $post_data['post_author'] ) && $post_data['post_author'] != $user->ID ) {
1198
if ( ! current_user_can( $post_type->cap->edit_others_posts ) )
1199
return new IXR_Error( 401, __( 'You are not allowed to create posts as this user.' ) );
1201
$author = get_userdata( $post_data['post_author'] );
1204
return new IXR_Error( 404, __( 'Invalid author ID.' ) );
1206
$post_data['post_author'] = $user->ID;
1209
if ( isset( $post_data['comment_status'] ) && $post_data['comment_status'] != 'open' && $post_data['comment_status'] != 'closed' )
1210
unset( $post_data['comment_status'] );
1212
if ( isset( $post_data['ping_status'] ) && $post_data['ping_status'] != 'open' && $post_data['ping_status'] != 'closed' )
1213
unset( $post_data['ping_status'] );
1215
// Do some timestamp voodoo
1216
if ( ! empty( $post_data['post_date_gmt'] ) ) {
1217
// We know this is supposed to be GMT, so we're going to slap that Z on there by force
1218
$dateCreated = rtrim( $post_data['post_date_gmt']->getIso(), 'Z' ) . 'Z';
1219
} elseif ( ! empty( $post_data['post_date'] ) ) {
1220
$dateCreated = $post_data['post_date']->getIso();
1223
if ( ! empty( $dateCreated ) ) {
1224
$post_data['post_date'] = get_date_from_gmt( iso8601_to_datetime( $dateCreated ) );
1225
$post_data['post_date_gmt'] = iso8601_to_datetime( $dateCreated, 'GMT' );
1228
if ( ! isset( $post_data['ID'] ) )
1229
$post_data['ID'] = get_default_post_to_edit( $post_data['post_type'], true )->ID;
1230
$post_ID = $post_data['ID'];
1232
if ( $post_data['post_type'] == 'post' ) {
1233
// Private and password-protected posts cannot be stickied.
1234
if ( $post_data['post_status'] == 'private' || ! empty( $post_data['post_password'] ) ) {
1235
// Error if the client tried to stick the post, otherwise, silently unstick.
1236
if ( ! empty( $post_data['sticky'] ) )
1237
return new IXR_Error( 401, __( 'Sorry, you cannot stick a private post.' ) );
1239
unstick_post( $post_ID );
1240
} elseif ( isset( $post_data['sticky'] ) ) {
1241
if ( ! current_user_can( $post_type->cap->edit_others_posts ) )
1242
return new IXR_Error( 401, __( 'Sorry, you are not allowed to stick this post.' ) );
1243
if ( $post_data['sticky'] )
1244
stick_post( $post_ID );
1246
unstick_post( $post_ID );
1250
if ( isset( $post_data['post_thumbnail'] ) ) {
1251
// empty value deletes, non-empty value adds/updates
1252
if ( ! $post_data['post_thumbnail'] )
1253
delete_post_thumbnail( $post_ID );
1254
elseif ( ! get_post( absint( $post_data['post_thumbnail'] ) ) )
1255
return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
1256
set_post_thumbnail( $post_ID, $post_data['post_thumbnail'] );
1257
unset( $content_struct['post_thumbnail'] );
1260
if ( isset( $post_data['custom_fields'] ) )
1261
$this->set_custom_fields( $post_ID, $post_data['custom_fields'] );
1263
if ( isset( $post_data['terms'] ) || isset( $post_data['terms_names'] ) ) {
1264
$post_type_taxonomies = get_object_taxonomies( $post_data['post_type'], 'objects' );
1266
// accumulate term IDs from terms and terms_names
1269
// first validate the terms specified by ID
1270
if ( isset( $post_data['terms'] ) && is_array( $post_data['terms'] ) ) {
1271
$taxonomies = array_keys( $post_data['terms'] );
1273
// validating term ids
1274
foreach ( $taxonomies as $taxonomy ) {
1275
if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) )
1276
return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
1278
if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) )
1279
return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
1281
$term_ids = $post_data['terms'][$taxonomy];
1282
$terms[ $taxonomy ] = array();
1283
foreach ( $term_ids as $term_id ) {
1284
$term = get_term_by( 'id', $term_id, $taxonomy );
1287
return new IXR_Error( 403, __( 'Invalid term ID' ) );
1289
$terms[$taxonomy][] = (int) $term_id;
1294
// now validate terms specified by name
1295
if ( isset( $post_data['terms_names'] ) && is_array( $post_data['terms_names'] ) ) {
1296
$taxonomies = array_keys( $post_data['terms_names'] );
1298
foreach ( $taxonomies as $taxonomy ) {
1299
if ( ! array_key_exists( $taxonomy , $post_type_taxonomies ) )
1300
return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
1302
if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->assign_terms ) )
1303
return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
1305
// for hierarchical taxonomies, we can't assign a term when multiple terms in the hierarchy share the same name
1306
$ambiguous_terms = array();
1307
if ( is_taxonomy_hierarchical( $taxonomy ) ) {
1308
$tax_term_names = get_terms( $taxonomy, array( 'fields' => 'names', 'hide_empty' => false ) );
1310
// count the number of terms with the same name
1311
$tax_term_names_count = array_count_values( $tax_term_names );
1313
// filter out non-ambiguous term names
1314
$ambiguous_tax_term_counts = array_filter( $tax_term_names_count, array( $this, '_is_greater_than_one') );
1316
$ambiguous_terms = array_keys( $ambiguous_tax_term_counts );
1319
$term_names = $post_data['terms_names'][$taxonomy];
1320
foreach ( $term_names as $term_name ) {
1321
if ( in_array( $term_name, $ambiguous_terms ) )
1322
return new IXR_Error( 401, __( 'Ambiguous term name used in a hierarchical taxonomy. Please use term ID instead.' ) );
1324
$term = get_term_by( 'name', $term_name, $taxonomy );
1327
// term doesn't exist, so check that the user is allowed to create new terms
1328
if ( ! current_user_can( $post_type_taxonomies[$taxonomy]->cap->edit_terms ) )
1329
return new IXR_Error( 401, __( 'Sorry, you are not allowed to add a term to one of the given taxonomies.' ) );
1331
// create the new term
1332
$term_info = wp_insert_term( $term_name, $taxonomy );
1333
if ( is_wp_error( $term_info ) )
1334
return new IXR_Error( 500, $term_info->get_error_message() );
1336
$terms[$taxonomy][] = (int) $term_info['term_id'];
1338
$terms[$taxonomy][] = (int) $term->term_id;
1344
$post_data['tax_input'] = $terms;
1345
unset( $post_data['terms'], $post_data['terms_names'] );
1347
// do not allow direct submission of 'tax_input', clients must use 'terms' and/or 'terms_names'
1348
unset( $post_data['tax_input'], $post_data['post_category'], $post_data['tags_input'] );
1351
if ( isset( $post_data['post_format'] ) ) {
1352
$format = set_post_format( $post_ID, $post_data['post_format'] );
1354
if ( is_wp_error( $format ) )
1355
return new IXR_Error( 500, $format->get_error_message() );
1357
unset( $post_data['post_format'] );
1360
// Handle enclosures
1361
$enclosure = isset( $post_data['enclosure'] ) ? $post_data['enclosure'] : null;
1362
$this->add_enclosure_if_new( $post_ID, $enclosure );
1364
$this->attach_uploads( $post_ID, $post_data['post_content'] );
1367
* Filter post data array to be inserted via XML-RPC.
1371
* @param array $post_data Parsed array of post data.
1372
* @param array $content_struct Post data array.
1374
$post_data = apply_filters( 'xmlrpc_wp_insert_post_data', $post_data, $content_struct );
1376
$post_ID = $update ? wp_update_post( $post_data, true ) : wp_insert_post( $post_data, true );
1377
if ( is_wp_error( $post_ID ) )
1378
return new IXR_Error( 500, $post_ID->get_error_message() );
1381
return new IXR_Error( 401, __( 'Sorry, your entry could not be posted. Something wrong happened.' ) );
1383
return strval( $post_ID );
1387
* Edit a post for any registered post type.
1389
* The $content_struct parameter only needs to contain fields that
1390
* should be changed. All other fields will retain their existing values.
1394
* @param array $args Method parameters. Contains:
1396
* - string $username
1397
* - string $password
1399
* - array $content_struct
1400
* @return true on success
1402
public function wp_editPost( $args ) {
1403
if ( ! $this->minimum_args( $args, 5 ) )
1404
return $this->error;
1406
$this->escape( $args );
1408
$blog_id = (int) $args[0];
1409
$username = $args[1];
1410
$password = $args[2];
1411
$post_id = (int) $args[3];
1412
$content_struct = $args[4];
1414
if ( ! $user = $this->login( $username, $password ) )
1415
return $this->error;
1417
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1418
do_action( 'xmlrpc_call', 'wp.editPost' );
1420
$post = get_post( $post_id, ARRAY_A );
1422
if ( empty( $post['ID'] ) )
1423
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
1425
if ( isset( $content_struct['if_not_modified_since'] ) ) {
1426
// If the post has been modified since the date provided, return an error.
1427
if ( mysql2date( 'U', $post['post_modified_gmt'] ) > $content_struct['if_not_modified_since']->getTimestamp() ) {
1428
return new IXR_Error( 409, __( 'There is a revision of this post that is more recent.' ) );
1432
// convert the date field back to IXR form
1433
$post['post_date'] = $this->_convert_date( $post['post_date'] );
1435
// ignore the existing GMT date if it is empty or a non-GMT date was supplied in $content_struct,
1436
// since _insert_post will ignore the non-GMT date if the GMT date is set
1437
if ( $post['post_date_gmt'] == '0000-00-00 00:00:00' || isset( $content_struct['post_date'] ) )
1438
unset( $post['post_date_gmt'] );
1440
$post['post_date_gmt'] = $this->_convert_date( $post['post_date_gmt'] );
1442
$this->escape( $post );
1443
$merged_content_struct = array_merge( $post, $content_struct );
1445
$retval = $this->_insert_post( $user, $merged_content_struct );
1446
if ( $retval instanceof IXR_Error )
1453
* Delete a post for any registered post type.
1457
* @uses wp_delete_post()
1458
* @param array $args Method parameters. Contains:
1460
* - string $username
1461
* - string $password
1463
* @return true on success
1465
public function wp_deletePost( $args ) {
1466
if ( ! $this->minimum_args( $args, 4 ) )
1467
return $this->error;
1469
$this->escape( $args );
1471
$blog_id = (int) $args[0];
1472
$username = $args[1];
1473
$password = $args[2];
1474
$post_id = (int) $args[3];
1476
if ( ! $user = $this->login( $username, $password ) )
1477
return $this->error;
1479
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1480
do_action( 'xmlrpc_call', 'wp.deletePost' );
1482
$post = get_post( $post_id, ARRAY_A );
1483
if ( empty( $post['ID'] ) )
1484
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
1486
if ( ! current_user_can( 'delete_post', $post_id ) )
1487
return new IXR_Error( 401, __( 'Sorry, you are not allowed to delete this post.' ) );
1489
$result = wp_delete_post( $post_id );
1492
return new IXR_Error( 500, __( 'The post cannot be deleted.' ) );
1502
* The optional $fields parameter specifies what fields will be included
1503
* in the response array. This should be a list of field names. 'post_id' will
1504
* always be included in the response regardless of the value of $fields.
1506
* Instead of, or in addition to, individual field names, conceptual group
1507
* names can be used to specify multiple fields. The available conceptual
1508
* groups are 'post' (all basic fields), 'taxonomies', 'custom_fields',
1512
* @param array $args Method parameters. Contains:
1514
* - string $username
1515
* - string $password
1516
* - array $fields optional
1517
* @return array contains (based on $fields parameter):
1523
* - 'post_modified_gmt'
1532
* - 'comment_status'
1541
public function wp_getPost( $args ) {
1542
if ( ! $this->minimum_args( $args, 4 ) )
1543
return $this->error;
1545
$this->escape( $args );
1547
$blog_id = (int) $args[0];
1548
$username = $args[1];
1549
$password = $args[2];
1550
$post_id = (int) $args[3];
1552
if ( isset( $args[4] ) ) {
1556
* Filter the list of post query fields used by the given XML-RPC method.
1560
* @param array $fields Array of post fields.
1561
* @param string $method Method name.
1563
$fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPost' );
1566
if ( ! $user = $this->login( $username, $password ) )
1567
return $this->error;
1569
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1570
do_action( 'xmlrpc_call', 'wp.getPost' );
1572
$post = get_post( $post_id, ARRAY_A );
1574
if ( empty( $post['ID'] ) )
1575
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
1577
if ( ! current_user_can( 'edit_post', $post_id ) )
1578
return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
1580
return $this->_prepare_post( $post, $fields );
1588
* The optional $filter parameter modifies the query used to retrieve posts.
1589
* Accepted keys are 'post_type', 'post_status', 'number', 'offset',
1590
* 'orderby', and 'order'.
1592
* The optional $fields parameter specifies what fields will be included
1593
* in the response array.
1595
* @uses wp_get_recent_posts()
1596
* @see wp_getPost() for more on $fields
1597
* @see get_posts() for more on $filter values
1599
* @param array $args Method parameters. Contains:
1601
* - string $username
1602
* - string $password
1603
* - array $filter optional
1604
* - array $fields optional
1605
* @return array contains a collection of posts.
1607
public function wp_getPosts( $args ) {
1608
if ( ! $this->minimum_args( $args, 3 ) )
1609
return $this->error;
1611
$this->escape( $args );
1613
$blog_id = (int) $args[0];
1614
$username = $args[1];
1615
$password = $args[2];
1616
$filter = isset( $args[3] ) ? $args[3] : array();
1618
if ( isset( $args[4] ) ) {
1621
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1622
$fields = apply_filters( 'xmlrpc_default_post_fields', array( 'post', 'terms', 'custom_fields' ), 'wp.getPosts' );
1625
if ( ! $user = $this->login( $username, $password ) )
1626
return $this->error;
1628
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1629
do_action( 'xmlrpc_call', 'wp.getPosts' );
1633
if ( isset( $filter['post_type'] ) ) {
1634
$post_type = get_post_type_object( $filter['post_type'] );
1635
if ( ! ( (bool) $post_type ) )
1636
return new IXR_Error( 403, __( 'The post type specified is not valid' ) );
1638
$post_type = get_post_type_object( 'post' );
1641
if ( ! current_user_can( $post_type->cap->edit_posts ) )
1642
return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts in this post type' ));
1644
$query['post_type'] = $post_type->name;
1646
if ( isset( $filter['post_status'] ) )
1647
$query['post_status'] = $filter['post_status'];
1649
if ( isset( $filter['number'] ) )
1650
$query['numberposts'] = absint( $filter['number'] );
1652
if ( isset( $filter['offset'] ) )
1653
$query['offset'] = absint( $filter['offset'] );
1655
if ( isset( $filter['orderby'] ) ) {
1656
$query['orderby'] = $filter['orderby'];
1658
if ( isset( $filter['order'] ) )
1659
$query['order'] = $filter['order'];
1662
if ( isset( $filter['s'] ) ) {
1663
$query['s'] = $filter['s'];
1666
$posts_list = wp_get_recent_posts( $query );
1668
if ( ! $posts_list )
1671
// holds all the posts data
1674
foreach ( $posts_list as $post ) {
1675
if ( ! current_user_can( 'edit_post', $post['ID'] ) )
1678
$struct[] = $this->_prepare_post( $post, $fields );
1685
* Create a new term.
1689
* @uses wp_insert_term()
1690
* @param array $args Method parameters. Contains:
1692
* - string $username
1693
* - string $password
1694
* - array $content_struct
1695
* The $content_struct must contain:
1698
* Also, it can optionally contain:
1702
* @return string term_id
1704
public function wp_newTerm( $args ) {
1705
if ( ! $this->minimum_args( $args, 4 ) )
1706
return $this->error;
1708
$this->escape( $args );
1710
$blog_id = (int) $args[0];
1711
$username = $args[1];
1712
$password = $args[2];
1713
$content_struct = $args[3];
1715
if ( ! $user = $this->login( $username, $password ) )
1716
return $this->error;
1718
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1719
do_action( 'xmlrpc_call', 'wp.newTerm' );
1721
if ( ! taxonomy_exists( $content_struct['taxonomy'] ) )
1722
return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
1724
$taxonomy = get_taxonomy( $content_struct['taxonomy'] );
1726
if ( ! current_user_can( $taxonomy->cap->manage_terms ) )
1727
return new IXR_Error( 401, __( 'You are not allowed to create terms in this taxonomy.' ) );
1729
$taxonomy = (array) $taxonomy;
1731
// hold the data of the term
1732
$term_data = array();
1734
$term_data['name'] = trim( $content_struct['name'] );
1735
if ( empty( $term_data['name'] ) )
1736
return new IXR_Error( 403, __( 'The term name cannot be empty.' ) );
1738
if ( isset( $content_struct['parent'] ) ) {
1739
if ( ! $taxonomy['hierarchical'] )
1740
return new IXR_Error( 403, __( 'This taxonomy is not hierarchical.' ) );
1742
$parent_term_id = (int) $content_struct['parent'];
1743
$parent_term = get_term( $parent_term_id , $taxonomy['name'] );
1745
if ( is_wp_error( $parent_term ) )
1746
return new IXR_Error( 500, $parent_term->get_error_message() );
1748
if ( ! $parent_term )
1749
return new IXR_Error( 403, __( 'Parent term does not exist.' ) );
1751
$term_data['parent'] = $content_struct['parent'];
1754
if ( isset( $content_struct['description'] ) )
1755
$term_data['description'] = $content_struct['description'];
1757
if ( isset( $content_struct['slug'] ) )
1758
$term_data['slug'] = $content_struct['slug'];
1760
$term = wp_insert_term( $term_data['name'] , $taxonomy['name'] , $term_data );
1762
if ( is_wp_error( $term ) )
1763
return new IXR_Error( 500, $term->get_error_message() );
1766
return new IXR_Error( 500, __( 'Sorry, your term could not be created. Something wrong happened.' ) );
1768
return strval( $term['term_id'] );
1776
* @uses wp_update_term()
1777
* @param array $args Method parameters. Contains:
1779
* - string $username
1780
* - string $password
1782
* - array $content_struct
1783
* The $content_struct must contain:
1785
* Also, it can optionally contain:
1790
* @return bool True, on success.
1792
public function wp_editTerm( $args ) {
1793
if ( ! $this->minimum_args( $args, 5 ) )
1794
return $this->error;
1796
$this->escape( $args );
1798
$blog_id = (int) $args[0];
1799
$username = $args[1];
1800
$password = $args[2];
1801
$term_id = (int) $args[3];
1802
$content_struct = $args[4];
1804
if ( ! $user = $this->login( $username, $password ) )
1805
return $this->error;
1807
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1808
do_action( 'xmlrpc_call', 'wp.editTerm' );
1810
if ( ! taxonomy_exists( $content_struct['taxonomy'] ) )
1811
return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
1813
$taxonomy = get_taxonomy( $content_struct['taxonomy'] );
1815
if ( ! current_user_can( $taxonomy->cap->edit_terms ) )
1816
return new IXR_Error( 401, __( 'You are not allowed to edit terms in this taxonomy.' ) );
1818
$taxonomy = (array) $taxonomy;
1820
// hold the data of the term
1821
$term_data = array();
1823
$term = get_term( $term_id , $content_struct['taxonomy'] );
1825
if ( is_wp_error( $term ) )
1826
return new IXR_Error( 500, $term->get_error_message() );
1829
return new IXR_Error( 404, __( 'Invalid term ID' ) );
1831
if ( isset( $content_struct['name'] ) ) {
1832
$term_data['name'] = trim( $content_struct['name'] );
1834
if ( empty( $term_data['name'] ) )
1835
return new IXR_Error( 403, __( 'The term name cannot be empty.' ) );
1838
if ( isset( $content_struct['parent'] ) ) {
1839
if ( ! $taxonomy['hierarchical'] )
1840
return new IXR_Error( 403, __( "This taxonomy is not hierarchical so you can't set a parent." ) );
1842
$parent_term_id = (int) $content_struct['parent'];
1843
$parent_term = get_term( $parent_term_id , $taxonomy['name'] );
1845
if ( is_wp_error( $parent_term ) )
1846
return new IXR_Error( 500, $parent_term->get_error_message() );
1848
if ( ! $parent_term )
1849
return new IXR_Error( 403, __( 'Parent term does not exist.' ) );
1851
$term_data['parent'] = $content_struct['parent'];
1854
if ( isset( $content_struct['description'] ) )
1855
$term_data['description'] = $content_struct['description'];
1857
if ( isset( $content_struct['slug'] ) )
1858
$term_data['slug'] = $content_struct['slug'];
1860
$term = wp_update_term( $term_id , $taxonomy['name'] , $term_data );
1862
if ( is_wp_error( $term ) )
1863
return new IXR_Error( 500, $term->get_error_message() );
1866
return new IXR_Error( 500, __( 'Sorry, editing the term failed.' ) );
1876
* @uses wp_delete_term()
1877
* @param array $args Method parameters. Contains:
1879
* - string $username
1880
* - string $password
1881
* - string $taxnomy_name
1883
* @return boolean|IXR_Error If it suceeded true else a reason why not
1885
public function wp_deleteTerm( $args ) {
1886
if ( ! $this->minimum_args( $args, 5 ) )
1887
return $this->error;
1889
$this->escape( $args );
1891
$blog_id = (int) $args[0];
1892
$username = $args[1];
1893
$password = $args[2];
1894
$taxonomy = $args[3];
1895
$term_id = (int) $args[4];
1897
if ( ! $user = $this->login( $username, $password ) )
1898
return $this->error;
1900
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1901
do_action( 'xmlrpc_call', 'wp.deleteTerm' );
1903
if ( ! taxonomy_exists( $taxonomy ) )
1904
return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
1906
$taxonomy = get_taxonomy( $taxonomy );
1908
if ( ! current_user_can( $taxonomy->cap->delete_terms ) )
1909
return new IXR_Error( 401, __( 'You are not allowed to delete terms in this taxonomy.' ) );
1911
$term = get_term( $term_id, $taxonomy->name );
1913
if ( is_wp_error( $term ) )
1914
return new IXR_Error( 500, $term->get_error_message() );
1917
return new IXR_Error( 404, __( 'Invalid term ID' ) );
1919
$result = wp_delete_term( $term_id, $taxonomy->name );
1921
if ( is_wp_error( $result ) )
1922
return new IXR_Error( 500, $term->get_error_message() );
1925
return new IXR_Error( 500, __( 'Sorry, deleting the term failed.' ) );
1936
* @param array $args Method parameters. Contains:
1938
* - string $username
1939
* - string $password
1940
* - string $taxonomy
1942
* @return array contains:
1947
* - 'term_taxonomy_id'
1953
public function wp_getTerm( $args ) {
1954
if ( ! $this->minimum_args( $args, 5 ) )
1955
return $this->error;
1957
$this->escape( $args );
1959
$blog_id = (int) $args[0];
1960
$username = $args[1];
1961
$password = $args[2];
1962
$taxonomy = $args[3];
1963
$term_id = (int) $args[4];
1965
if ( ! $user = $this->login( $username, $password ) )
1966
return $this->error;
1968
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
1969
do_action( 'xmlrpc_call', 'wp.getTerm' );
1971
if ( ! taxonomy_exists( $taxonomy ) )
1972
return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
1974
$taxonomy = get_taxonomy( $taxonomy );
1976
if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
1977
return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
1979
$term = get_term( $term_id , $taxonomy->name, ARRAY_A );
1981
if ( is_wp_error( $term ) )
1982
return new IXR_Error( 500, $term->get_error_message() );
1985
return new IXR_Error( 404, __( 'Invalid term ID' ) );
1987
return $this->_prepare_term( $term );
1991
* Retrieve all terms for a taxonomy.
1995
* The optional $filter parameter modifies the query used to retrieve terms.
1996
* Accepted keys are 'number', 'offset', 'orderby', 'order', 'hide_empty', and 'search'.
1999
* @param array $args Method parameters. Contains:
2001
* - string $username
2002
* - string $password
2003
* - string $taxonomy
2004
* - array $filter optional
2005
* @return array terms
2007
public function wp_getTerms( $args ) {
2008
if ( ! $this->minimum_args( $args, 4 ) )
2009
return $this->error;
2011
$this->escape( $args );
2013
$blog_id = (int) $args[0];
2014
$username = $args[1];
2015
$password = $args[2];
2016
$taxonomy = $args[3];
2017
$filter = isset( $args[4] ) ? $args[4] : array();
2019
if ( ! $user = $this->login( $username, $password ) )
2020
return $this->error;
2022
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2023
do_action( 'xmlrpc_call', 'wp.getTerms' );
2025
if ( ! taxonomy_exists( $taxonomy ) )
2026
return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
2028
$taxonomy = get_taxonomy( $taxonomy );
2030
if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
2031
return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
2035
if ( isset( $filter['number'] ) )
2036
$query['number'] = absint( $filter['number'] );
2038
if ( isset( $filter['offset'] ) )
2039
$query['offset'] = absint( $filter['offset'] );
2041
if ( isset( $filter['orderby'] ) ) {
2042
$query['orderby'] = $filter['orderby'];
2044
if ( isset( $filter['order'] ) )
2045
$query['order'] = $filter['order'];
2048
if ( isset( $filter['hide_empty'] ) )
2049
$query['hide_empty'] = $filter['hide_empty'];
2051
$query['get'] = 'all';
2053
if ( isset( $filter['search'] ) )
2054
$query['search'] = $filter['search'];
2056
$terms = get_terms( $taxonomy->name, $query );
2058
if ( is_wp_error( $terms ) )
2059
return new IXR_Error( 500, $terms->get_error_message() );
2063
foreach ( $terms as $term ) {
2064
$struct[] = $this->_prepare_term( $term );
2071
* Retrieve a taxonomy.
2075
* @uses get_taxonomy()
2076
* @param array $args Method parameters. Contains:
2078
* - string $username
2079
* - string $password
2080
* - string $taxonomy
2081
* @return array (@see get_taxonomy())
2083
public function wp_getTaxonomy( $args ) {
2084
if ( ! $this->minimum_args( $args, 4 ) )
2085
return $this->error;
2087
$this->escape( $args );
2089
$blog_id = (int) $args[0];
2090
$username = $args[1];
2091
$password = $args[2];
2092
$taxonomy = $args[3];
2094
if ( isset( $args[4] ) ) {
2098
* Filter the taxonomy query fields used by the given XML-RPC method.
2102
* @param array $fields An array of taxonomy fields to retrieve.
2103
* @param string $method The method name.
2105
$fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomy' );
2108
if ( ! $user = $this->login( $username, $password ) )
2109
return $this->error;
2111
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2112
do_action( 'xmlrpc_call', 'wp.getTaxonomy' );
2114
if ( ! taxonomy_exists( $taxonomy ) )
2115
return new IXR_Error( 403, __( 'Invalid taxonomy' ) );
2117
$taxonomy = get_taxonomy( $taxonomy );
2119
if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
2120
return new IXR_Error( 401, __( 'You are not allowed to assign terms in this taxonomy.' ) );
2122
return $this->_prepare_taxonomy( $taxonomy, $fields );
2126
* Retrieve all taxonomies.
2130
* @uses get_taxonomies()
2131
* @param array $args Method parameters. Contains:
2133
* - string $username
2134
* - string $password
2135
* @return array taxonomies
2137
public function wp_getTaxonomies( $args ) {
2138
if ( ! $this->minimum_args( $args, 3 ) )
2139
return $this->error;
2141
$this->escape( $args );
2143
$blog_id = (int) $args[0];
2144
$username = $args[1];
2145
$password = $args[2];
2146
$filter = isset( $args[3] ) ? $args[3] : array( 'public' => true );
2148
if ( isset( $args[4] ) ) {
2151
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2152
$fields = apply_filters( 'xmlrpc_default_taxonomy_fields', array( 'labels', 'cap', 'object_type' ), 'wp.getTaxonomies' );
2155
if ( ! $user = $this->login( $username, $password ) )
2156
return $this->error;
2158
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2159
do_action( 'xmlrpc_call', 'wp.getTaxonomies' );
2161
$taxonomies = get_taxonomies( $filter, 'objects' );
2163
// holds all the taxonomy data
2166
foreach ( $taxonomies as $taxonomy ) {
2167
// capability check for post_types
2168
if ( ! current_user_can( $taxonomy->cap->assign_terms ) )
2171
$struct[] = $this->_prepare_taxonomy( $taxonomy, $fields );
2180
* The optional $fields parameter specifies what fields will be included
2181
* in the response array. This should be a list of field names. 'user_id' will
2182
* always be included in the response regardless of the value of $fields.
2184
* Instead of, or in addition to, individual field names, conceptual group
2185
* names can be used to specify multiple fields. The available conceptual
2186
* groups are 'basic' and 'all'.
2188
* @uses get_userdata()
2189
* @param array $args Method parameters. Contains:
2191
* - string $username
2192
* - string $password
2194
* - array $fields optional
2195
* @return array contains (based on $fields parameter):
2209
public function wp_getUser( $args ) {
2210
if ( ! $this->minimum_args( $args, 4 ) )
2211
return $this->error;
2213
$this->escape( $args );
2215
$blog_id = (int) $args[0];
2216
$username = $args[1];
2217
$password = $args[2];
2218
$user_id = (int) $args[3];
2220
if ( isset( $args[4] ) ) {
2224
* Filter the default user query fields used by the given XML-RPC method.
2228
* @param array $fields User query fields for given method. Default 'all'.
2229
* @param string $method The method name.
2231
$fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getUser' );
2234
if ( ! $user = $this->login( $username, $password ) )
2235
return $this->error;
2237
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2238
do_action( 'xmlrpc_call', 'wp.getUser' );
2240
if ( ! current_user_can( 'edit_user', $user_id ) )
2241
return new IXR_Error( 401, __( 'Sorry, you cannot edit users.' ) );
2243
$user_data = get_userdata( $user_id );
2246
return new IXR_Error( 404, __( 'Invalid user ID' ) );
2248
return $this->_prepare_user( $user_data, $fields );
2254
* The optional $filter parameter modifies the query used to retrieve users.
2255
* Accepted keys are 'number' (default: 50), 'offset' (default: 0), 'role',
2256
* 'who', 'orderby', and 'order'.
2258
* The optional $fields parameter specifies what fields will be included
2259
* in the response array.
2262
* @see wp_getUser() for more on $fields and return values
2264
* @param array $args Method parameters. Contains:
2266
* - string $username
2267
* - string $password
2268
* - array $filter optional
2269
* - array $fields optional
2270
* @return array users data
2272
public function wp_getUsers( $args ) {
2273
if ( ! $this->minimum_args( $args, 3 ) )
2274
return $this->error;
2276
$this->escape( $args );
2278
$blog_id = (int) $args[0];
2279
$username = $args[1];
2280
$password = $args[2];
2281
$filter = isset( $args[3] ) ? $args[3] : array();
2283
if ( isset( $args[4] ) ) {
2286
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2287
$fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getUsers' );
2290
if ( ! $user = $this->login( $username, $password ) )
2291
return $this->error;
2293
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2294
do_action( 'xmlrpc_call', 'wp.getUsers' );
2296
if ( ! current_user_can( 'list_users' ) )
2297
return new IXR_Error( 401, __( 'Sorry, you cannot list users.' ) );
2299
$query = array( 'fields' => 'all_with_meta' );
2301
$query['number'] = ( isset( $filter['number'] ) ) ? absint( $filter['number'] ) : 50;
2302
$query['offset'] = ( isset( $filter['offset'] ) ) ? absint( $filter['offset'] ) : 0;
2304
if ( isset( $filter['orderby'] ) ) {
2305
$query['orderby'] = $filter['orderby'];
2307
if ( isset( $filter['order'] ) )
2308
$query['order'] = $filter['order'];
2311
if ( isset( $filter['role'] ) ) {
2312
if ( get_role( $filter['role'] ) === null )
2313
return new IXR_Error( 403, __( 'The role specified is not valid' ) );
2315
$query['role'] = $filter['role'];
2318
if ( isset( $filter['who'] ) ) {
2319
$query['who'] = $filter['who'];
2322
$users = get_users( $query );
2325
foreach ( $users as $user_data ) {
2326
if ( current_user_can( 'edit_user', $user_data->ID ) )
2327
$_users[] = $this->_prepare_user( $user_data, $fields );
2333
* Retrieve information about the requesting user.
2335
* @uses get_userdata()
2336
* @param array $args Method parameters. Contains:
2338
* - string $username
2339
* - string $password
2340
* - array $fields optional
2341
* @return array (@see wp_getUser)
2343
public function wp_getProfile( $args ) {
2344
if ( ! $this->minimum_args( $args, 3 ) )
2345
return $this->error;
2347
$this->escape( $args );
2349
$blog_id = (int) $args[0];
2350
$username = $args[1];
2351
$password = $args[2];
2353
if ( isset( $args[3] ) ) {
2356
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2357
$fields = apply_filters( 'xmlrpc_default_user_fields', array( 'all' ), 'wp.getProfile' );
2360
if ( ! $user = $this->login( $username, $password ) )
2361
return $this->error;
2363
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2364
do_action( 'xmlrpc_call', 'wp.getProfile' );
2366
if ( ! current_user_can( 'edit_user', $user->ID ) )
2367
return new IXR_Error( 401, __( 'Sorry, you cannot edit your profile.' ) );
2369
$user_data = get_userdata( $user->ID );
2371
return $this->_prepare_user( $user_data, $fields );
2375
* Edit user's profile.
2377
* @uses wp_update_user()
2378
* @param array $args Method parameters. Contains:
2380
* - string $username
2381
* - string $password
2382
* - array $content_struct
2383
* It can optionally contain:
2391
* @return bool True, on success.
2393
public function wp_editProfile( $args ) {
2394
if ( ! $this->minimum_args( $args, 4 ) )
2395
return $this->error;
2397
$this->escape( $args );
2399
$blog_id = (int) $args[0];
2400
$username = $args[1];
2401
$password = $args[2];
2402
$content_struct = $args[3];
2404
if ( ! $user = $this->login( $username, $password ) )
2405
return $this->error;
2407
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2408
do_action( 'xmlrpc_call', 'wp.editProfile' );
2410
if ( ! current_user_can( 'edit_user', $user->ID ) )
2411
return new IXR_Error( 401, __( 'Sorry, you cannot edit your profile.' ) );
2413
// holds data of the user
2414
$user_data = array();
2415
$user_data['ID'] = $user->ID;
2417
// only set the user details if it was given
2418
if ( isset( $content_struct['first_name'] ) )
2419
$user_data['first_name'] = $content_struct['first_name'];
2421
if ( isset( $content_struct['last_name'] ) )
2422
$user_data['last_name'] = $content_struct['last_name'];
2424
if ( isset( $content_struct['url'] ) )
2425
$user_data['user_url'] = $content_struct['url'];
2427
if ( isset( $content_struct['display_name'] ) )
2428
$user_data['display_name'] = $content_struct['display_name'];
2430
if ( isset( $content_struct['nickname'] ) )
2431
$user_data['nickname'] = $content_struct['nickname'];
2433
if ( isset( $content_struct['nicename'] ) )
2434
$user_data['user_nicename'] = $content_struct['nicename'];
2436
if ( isset( $content_struct['bio'] ) )
2437
$user_data['description'] = $content_struct['bio'];
2439
$result = wp_update_user( $user_data );
2441
if ( is_wp_error( $result ) )
2442
return new IXR_Error( 500, $result->get_error_message() );
2445
return new IXR_Error( 500, __( 'Sorry, the user cannot be updated.' ) );
2455
* @param array $args Method parameters. Contains:
2462
public function wp_getPage($args) {
2463
$this->escape($args);
2465
$blog_id = (int) $args[0];
2466
$page_id = (int) $args[1];
2467
$username = $args[2];
2468
$password = $args[3];
2470
if ( !$user = $this->login($username, $password) ) {
2471
return $this->error;
2474
$page = get_post($page_id);
2476
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
2478
if ( !current_user_can( 'edit_page', $page_id ) )
2479
return new IXR_Error( 401, __( 'Sorry, you cannot edit this page.' ) );
2481
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2482
do_action( 'xmlrpc_call', 'wp.getPage' );
2484
// If we found the page then format the data.
2485
if ( $page->ID && ($page->post_type == 'page') ) {
2486
return $this->_prepare_page( $page );
2488
// If the page doesn't exist indicate that.
2490
return new IXR_Error( 404, __( 'Sorry, no such page.' ) );
2499
* @param array $args Method parameters. Contains:
2506
public function wp_getPages($args) {
2507
$this->escape($args);
2509
$blog_id = (int) $args[0];
2510
$username = $args[1];
2511
$password = $args[2];
2512
$num_pages = isset($args[3]) ? (int) $args[3] : 10;
2514
if ( !$user = $this->login($username, $password) )
2515
return $this->error;
2517
if ( !current_user_can( 'edit_pages' ) )
2518
return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
2520
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2521
do_action( 'xmlrpc_call', 'wp.getPages' );
2523
$pages = get_posts( array('post_type' => 'page', 'post_status' => 'any', 'numberposts' => $num_pages) );
2524
$num_pages = count($pages);
2526
// If we have pages, put together their info.
2527
if ( $num_pages >= 1 ) {
2528
$pages_struct = array();
2530
foreach ($pages as $page) {
2531
if ( current_user_can( 'edit_page', $page->ID ) )
2532
$pages_struct[] = $this->_prepare_page( $page );
2535
return($pages_struct);
2537
// If no pages were found return an error.
2548
* @param array $args Method parameters. See {@link wp_xmlrpc_server::mw_newPost()}
2551
public function wp_newPage($args) {
2552
// Items not escaped here will be escaped in newPost.
2553
$username = $this->escape($args[1]);
2554
$password = $this->escape($args[2]);
2556
$publish = $args[4];
2558
if ( !$user = $this->login($username, $password) )
2559
return $this->error;
2561
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2562
do_action( 'xmlrpc_call', 'wp.newPage' );
2564
// Mark this as content for a page.
2565
$args[3]["post_type"] = 'page';
2567
// Let mw_newPost do all of the heavy lifting.
2568
return($this->mw_newPost($args));
2576
* @param array $args Method parameters.
2577
* @return bool True, if success.
2579
public function wp_deletePage($args) {
2580
$this->escape($args);
2582
$blog_id = (int) $args[0];
2583
$username = $args[1];
2584
$password = $args[2];
2585
$page_id = (int) $args[3];
2587
if ( !$user = $this->login($username, $password) )
2588
return $this->error;
2590
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2591
do_action( 'xmlrpc_call', 'wp.deletePage' );
2593
// Get the current page based on the page_id and
2594
// make sure it is a page and not a post.
2595
$actual_page = get_post($page_id, ARRAY_A);
2596
if ( !$actual_page || ($actual_page['post_type'] != 'page') )
2597
return(new IXR_Error(404, __('Sorry, no such page.')));
2599
// Make sure the user can delete pages.
2600
if ( !current_user_can('delete_page', $page_id) )
2601
return(new IXR_Error(401, __('Sorry, you do not have the right to delete this page.')));
2603
// Attempt to delete the page.
2604
$result = wp_delete_post($page_id);
2606
return(new IXR_Error(500, __('Failed to delete the page.')));
2609
* Fires after a page has been successfully deleted via XML-RPC.
2613
* @param int $page_id ID of the deleted page.
2614
* @param array $args An array of arguments to delete the page.
2616
do_action( 'xmlrpc_call_success_wp_deletePage', $page_id, $args );
2626
* @param array $args Method parameters.
2629
public function wp_editPage($args) {
2630
// Items not escaped here will be escaped in editPost.
2631
$blog_id = (int) $args[0];
2632
$page_id = (int) $this->escape($args[1]);
2633
$username = $this->escape($args[2]);
2634
$password = $this->escape($args[3]);
2635
$content = $args[4];
2636
$publish = $args[5];
2638
if ( !$user = $this->login($username, $password) )
2639
return $this->error;
2641
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2642
do_action( 'xmlrpc_call', 'wp.editPage' );
2644
// Get the page data and make sure it is a page.
2645
$actual_page = get_post($page_id, ARRAY_A);
2646
if ( !$actual_page || ($actual_page['post_type'] != 'page') )
2647
return(new IXR_Error(404, __('Sorry, no such page.')));
2649
// Make sure the user is allowed to edit pages.
2650
if ( !current_user_can('edit_page', $page_id) )
2651
return(new IXR_Error(401, __('Sorry, you do not have the right to edit this page.')));
2653
// Mark this as content for a page.
2654
$content['post_type'] = 'page';
2656
// Arrange args in the way mw_editPost understands.
2665
// Let mw_editPost do all of the heavy lifting.
2666
return($this->mw_editPost($args));
2670
* Retrieve page list.
2674
* @param array $args Method parameters.
2677
public function wp_getPageList($args) {
2680
$this->escape($args);
2682
$blog_id = (int) $args[0];
2683
$username = $args[1];
2684
$password = $args[2];
2686
if ( !$user = $this->login($username, $password) )
2687
return $this->error;
2689
if ( !current_user_can( 'edit_pages' ) )
2690
return new IXR_Error( 401, __( 'Sorry, you cannot edit pages.' ) );
2692
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2693
do_action( 'xmlrpc_call', 'wp.getPageList' );
2695
// Get list of pages ids and titles
2696
$page_list = $wpdb->get_results("
2698
post_title page_title,
2699
post_parent page_parent_id,
2704
WHERE post_type = 'page'
2708
// The date needs to be formatted properly.
2709
$num_pages = count($page_list);
2710
for ( $i = 0; $i < $num_pages; $i++ ) {
2711
$page_list[$i]->dateCreated = $this->_convert_date( $page_list[$i]->post_date );
2712
$page_list[$i]->date_created_gmt = $this->_convert_date_gmt( $page_list[$i]->post_date_gmt, $page_list[$i]->post_date );
2714
unset($page_list[$i]->post_date_gmt);
2715
unset($page_list[$i]->post_date);
2716
unset($page_list[$i]->post_status);
2723
* Retrieve authors list.
2727
* @param array $args Method parameters.
2730
public function wp_getAuthors($args) {
2732
$this->escape($args);
2734
$blog_id = (int) $args[0];
2735
$username = $args[1];
2736
$password = $args[2];
2738
if ( !$user = $this->login($username, $password) )
2739
return $this->error;
2741
if ( !current_user_can('edit_posts') )
2742
return(new IXR_Error(401, __('Sorry, you cannot edit posts on this site.')));
2744
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2745
do_action( 'xmlrpc_call', 'wp.getAuthors' );
2748
foreach ( get_users( array( 'fields' => array('ID','user_login','display_name') ) ) as $user ) {
2750
'user_id' => $user->ID,
2751
'user_login' => $user->user_login,
2752
'display_name' => $user->display_name
2760
* Get list of all tags
2764
* @param array $args Method parameters.
2767
public function wp_getTags( $args ) {
2768
$this->escape( $args );
2770
$blog_id = (int) $args[0];
2771
$username = $args[1];
2772
$password = $args[2];
2774
if ( !$user = $this->login($username, $password) )
2775
return $this->error;
2777
if ( !current_user_can( 'edit_posts' ) )
2778
return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view tags.' ) );
2780
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2781
do_action( 'xmlrpc_call', 'wp.getKeywords' );
2785
if ( $all_tags = get_tags() ) {
2786
foreach( (array) $all_tags as $tag ) {
2787
$struct['tag_id'] = $tag->term_id;
2788
$struct['name'] = $tag->name;
2789
$struct['count'] = $tag->count;
2790
$struct['slug'] = $tag->slug;
2791
$struct['html_url'] = esc_html( get_tag_link( $tag->term_id ) );
2792
$struct['rss_url'] = esc_html( get_tag_feed_link( $tag->term_id ) );
2802
* Create new category.
2806
* @param array $args Method parameters.
2807
* @return int Category ID.
2809
public function wp_newCategory($args) {
2810
$this->escape($args);
2812
$blog_id = (int) $args[0];
2813
$username = $args[1];
2814
$password = $args[2];
2815
$category = $args[3];
2817
if ( !$user = $this->login($username, $password) )
2818
return $this->error;
2820
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2821
do_action( 'xmlrpc_call', 'wp.newCategory' );
2823
// Make sure the user is allowed to add a category.
2824
if ( !current_user_can('manage_categories') )
2825
return(new IXR_Error(401, __('Sorry, you do not have the right to add a category.')));
2827
// If no slug was provided make it empty so that
2828
// WordPress will generate one.
2829
if ( empty($category['slug']) )
2830
$category['slug'] = '';
2832
// If no parent_id was provided make it empty
2833
// so that it will be a top level page (no parent).
2834
if ( !isset($category['parent_id']) )
2835
$category['parent_id'] = '';
2837
// If no description was provided make it empty.
2838
if ( empty($category["description"]) )
2839
$category["description"] = "";
2841
$new_category = array(
2842
'cat_name' => $category['name'],
2843
'category_nicename' => $category['slug'],
2844
'category_parent' => $category['parent_id'],
2845
'category_description' => $category['description']
2848
$cat_id = wp_insert_category($new_category, true);
2849
if ( is_wp_error( $cat_id ) ) {
2850
if ( 'term_exists' == $cat_id->get_error_code() )
2851
return (int) $cat_id->get_error_data();
2853
return(new IXR_Error(500, __('Sorry, the new category failed.')));
2854
} elseif ( ! $cat_id ) {
2855
return(new IXR_Error(500, __('Sorry, the new category failed.')));
2859
* Fires after a new category has been successfully created via XML-RPC.
2863
* @param int $cat_id ID of the new category.
2864
* @param array $args An array of new category arguments.
2866
do_action( 'xmlrpc_call_success_wp_newCategory', $cat_id, $args );
2876
* @param array $args Method parameters.
2877
* @return mixed See {@link wp_delete_term()} for return info.
2879
public function wp_deleteCategory($args) {
2880
$this->escape($args);
2882
$blog_id = (int) $args[0];
2883
$username = $args[1];
2884
$password = $args[2];
2885
$category_id = (int) $args[3];
2887
if ( !$user = $this->login($username, $password) )
2888
return $this->error;
2890
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2891
do_action( 'xmlrpc_call', 'wp.deleteCategory' );
2893
if ( !current_user_can('manage_categories') )
2894
return new IXR_Error( 401, __( 'Sorry, you do not have the right to delete a category.' ) );
2896
$status = wp_delete_term( $category_id, 'category' );
2898
if ( true == $status ) {
2900
* Fires after a category has been successfully deleted via XML-RPC.
2904
* @param int $category_id ID of the deleted category.
2905
* @param array $args An array of arguments to delete the category.
2907
do_action( 'xmlrpc_call_success_wp_deleteCategory', $category_id, $args );
2914
* Retrieve category list.
2918
* @param array $args Method parameters.
2921
public function wp_suggestCategories($args) {
2922
$this->escape($args);
2924
$blog_id = (int) $args[0];
2925
$username = $args[1];
2926
$password = $args[2];
2927
$category = $args[3];
2928
$max_results = (int) $args[4];
2930
if ( !$user = $this->login($username, $password) )
2931
return $this->error;
2933
if ( !current_user_can( 'edit_posts' ) )
2934
return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts to this site in order to view categories.' ) );
2936
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2937
do_action( 'xmlrpc_call', 'wp.suggestCategories' );
2939
$category_suggestions = array();
2940
$args = array('get' => 'all', 'number' => $max_results, 'name__like' => $category);
2941
foreach ( (array) get_categories($args) as $cat ) {
2942
$category_suggestions[] = array(
2943
'category_id' => $cat->term_id,
2944
'category_name' => $cat->name
2948
return($category_suggestions);
2956
* @param array $args Method parameters.
2959
public function wp_getComment($args) {
2960
$this->escape($args);
2962
$blog_id = (int) $args[0];
2963
$username = $args[1];
2964
$password = $args[2];
2965
$comment_id = (int) $args[3];
2967
if ( !$user = $this->login($username, $password) )
2968
return $this->error;
2970
if ( !current_user_can( 'moderate_comments' ) )
2971
return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
2973
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
2974
do_action( 'xmlrpc_call', 'wp.getComment' );
2976
if ( ! $comment = get_comment($comment_id) )
2977
return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
2979
return $this->_prepare_comment( $comment );
2983
* Retrieve comments.
2985
* Besides the common blog_id, username, and password arguments, it takes a filter
2986
* array as last argument.
2988
* Accepted 'filter' keys are 'status', 'post_id', 'offset', and 'number'.
2990
* The defaults are as follows:
2991
* - 'status' - Default is ''. Filter by status (e.g., 'approve', 'hold')
2992
* - 'post_id' - Default is ''. The post where the comment is posted. Empty string shows all comments.
2993
* - 'number' - Default is 10. Total number of media items to retrieve.
2994
* - 'offset' - Default is 0. See {@link WP_Query::query()} for more.
2998
* @param array $args Method parameters.
2999
* @return array. Contains a collection of comments. See {@link wp_xmlrpc_server::wp_getComment()} for a description of each item contents
3001
public function wp_getComments($args) {
3002
$this->escape($args);
3004
$blog_id = (int) $args[0];
3005
$username = $args[1];
3006
$password = $args[2];
3007
$struct = isset( $args[3] ) ? $args[3] : array();
3009
if ( !$user = $this->login($username, $password) )
3010
return $this->error;
3012
if ( !current_user_can( 'moderate_comments' ) )
3013
return new IXR_Error( 401, __( 'Sorry, you cannot edit comments.' ) );
3015
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3016
do_action( 'xmlrpc_call', 'wp.getComments' );
3018
if ( isset($struct['status']) )
3019
$status = $struct['status'];
3024
if ( isset($struct['post_id']) )
3025
$post_id = absint($struct['post_id']);
3028
if ( isset($struct['offset']) )
3029
$offset = absint($struct['offset']);
3032
if ( isset($struct['number']) )
3033
$number = absint($struct['number']);
3035
$comments = get_comments( array('status' => $status, 'post_id' => $post_id, 'offset' => $offset, 'number' => $number ) );
3037
$comments_struct = array();
3039
foreach ( $comments as $comment ) {
3040
$comments_struct[] = $this->_prepare_comment( $comment );
3043
return $comments_struct;
3049
* By default, the comment will be moved to the trash instead of deleted.
3050
* See {@link wp_delete_comment()} for more information on
3055
* @param array $args Method parameters. Contains:
3060
* @return mixed {@link wp_delete_comment()}
3062
public function wp_deleteComment($args) {
3063
$this->escape($args);
3065
$blog_id = (int) $args[0];
3066
$username = $args[1];
3067
$password = $args[2];
3068
$comment_ID = (int) $args[3];
3070
if ( !$user = $this->login($username, $password) )
3071
return $this->error;
3073
if ( !current_user_can( 'moderate_comments' ) )
3074
return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
3076
if ( ! get_comment($comment_ID) )
3077
return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
3079
if ( !current_user_can( 'edit_comment', $comment_ID ) )
3080
return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
3082
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3083
do_action( 'xmlrpc_call', 'wp.deleteComment' );
3085
$status = wp_delete_comment( $comment_ID );
3087
if ( true == $status ) {
3089
* Fires after a comment has been successfully deleted via XML-RPC.
3093
* @param int $comment_ID ID of the deleted comment.
3094
* @param array $args An array of arguments to delete the comment.
3096
do_action( 'xmlrpc_call_success_wp_deleteComment', $comment_ID, $args );
3105
* Besides the common blog_id, username, and password arguments, it takes a
3106
* comment_id integer and a content_struct array as last argument.
3108
* The allowed keys in the content_struct array are:
3113
* - 'date_created_gmt'
3114
* - 'status'. Common statuses are 'approve', 'hold', 'spam'. See {@link get_comment_statuses()} for more details
3118
* @param array $args. Contains:
3124
* @return bool True, on success.
3126
public function wp_editComment($args) {
3127
$this->escape($args);
3129
$blog_id = (int) $args[0];
3130
$username = $args[1];
3131
$password = $args[2];
3132
$comment_ID = (int) $args[3];
3133
$content_struct = $args[4];
3135
if ( !$user = $this->login($username, $password) )
3136
return $this->error;
3138
if ( !current_user_can( 'moderate_comments' ) )
3139
return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
3141
if ( ! get_comment($comment_ID) )
3142
return new IXR_Error( 404, __( 'Invalid comment ID.' ) );
3144
if ( !current_user_can( 'edit_comment', $comment_ID ) )
3145
return new IXR_Error( 403, __( 'You are not allowed to moderate comments on this site.' ) );
3147
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3148
do_action( 'xmlrpc_call', 'wp.editComment' );
3150
if ( isset($content_struct['status']) ) {
3151
$statuses = get_comment_statuses();
3152
$statuses = array_keys($statuses);
3154
if ( ! in_array($content_struct['status'], $statuses) )
3155
return new IXR_Error( 401, __( 'Invalid comment status.' ) );
3156
$comment_approved = $content_struct['status'];
3159
// Do some timestamp voodoo
3160
if ( !empty( $content_struct['date_created_gmt'] ) ) {
3161
// We know this is supposed to be GMT, so we're going to slap that Z on there by force
3162
$dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
3163
$comment_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
3164
$comment_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
3167
if ( isset($content_struct['content']) )
3168
$comment_content = $content_struct['content'];
3170
if ( isset($content_struct['author']) )
3171
$comment_author = $content_struct['author'];
3173
if ( isset($content_struct['author_url']) )
3174
$comment_author_url = $content_struct['author_url'];
3176
if ( isset($content_struct['author_email']) )
3177
$comment_author_email = $content_struct['author_email'];
3179
// We've got all the data -- post it:
3180
$comment = compact('comment_ID', 'comment_content', 'comment_approved', 'comment_date', 'comment_date_gmt', 'comment_author', 'comment_author_email', 'comment_author_url');
3182
$result = wp_update_comment($comment);
3183
if ( is_wp_error( $result ) )
3184
return new IXR_Error(500, $result->get_error_message());
3187
return new IXR_Error(500, __('Sorry, the comment could not be edited. Something wrong happened.'));
3190
* Fires after a comment has been successfully updated via XML-RPC.
3194
* @param int $comment_ID ID of the updated comment.
3195
* @param array $args An array of arguments to update the comment.
3197
do_action( 'xmlrpc_call_success_wp_editComment', $comment_ID, $args );
3203
* Create new comment.
3207
* @param array $args Method parameters.
3208
* @return mixed {@link wp_new_comment()}
3210
public function wp_newComment($args) {
3211
$this->escape($args);
3213
$blog_id = (int) $args[0];
3214
$username = $args[1];
3215
$password = $args[2];
3217
$content_struct = $args[4];
3220
* Filter whether to allow anonymous comments over XML-RPC.
3224
* @param bool $allow Whether to allow anonymous commenting via XML-RPC.
3227
$allow_anon = apply_filters( 'xmlrpc_allow_anonymous_comments', false );
3229
$user = $this->login($username, $password);
3233
if ( $allow_anon && get_option('comment_registration') )
3234
return new IXR_Error( 403, __( 'You must be registered to comment' ) );
3235
else if ( !$allow_anon )
3236
return $this->error;
3241
if ( is_numeric($post) )
3242
$post_id = absint($post);
3244
$post_id = url_to_postid($post);
3247
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
3249
if ( ! get_post($post_id) )
3250
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
3252
$comment['comment_post_ID'] = $post_id;
3255
$comment['comment_author'] = $this->escape( $user->display_name );
3256
$comment['comment_author_email'] = $this->escape( $user->user_email );
3257
$comment['comment_author_url'] = $this->escape( $user->user_url );
3258
$comment['user_ID'] = $user->ID;
3260
$comment['comment_author'] = '';
3261
if ( isset($content_struct['author']) )
3262
$comment['comment_author'] = $content_struct['author'];
3264
$comment['comment_author_email'] = '';
3265
if ( isset($content_struct['author_email']) )
3266
$comment['comment_author_email'] = $content_struct['author_email'];
3268
$comment['comment_author_url'] = '';
3269
if ( isset($content_struct['author_url']) )
3270
$comment['comment_author_url'] = $content_struct['author_url'];
3272
$comment['user_ID'] = 0;
3274
if ( get_option('require_name_email') ) {
3275
if ( 6 > strlen($comment['comment_author_email']) || '' == $comment['comment_author'] )
3276
return new IXR_Error( 403, __( 'Comment author name and email are required' ) );
3277
elseif ( !is_email($comment['comment_author_email']) )
3278
return new IXR_Error( 403, __( 'A valid email address is required' ) );
3282
$comment['comment_parent'] = isset($content_struct['comment_parent']) ? absint($content_struct['comment_parent']) : 0;
3284
$comment['comment_content'] = isset($content_struct['content']) ? $content_struct['content'] : null;
3286
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3287
do_action( 'xmlrpc_call', 'wp.newComment' );
3289
$comment_ID = wp_new_comment( $comment );
3292
* Fires after a new comment has been successfully created via XML-RPC.
3296
* @param int $comment_ID ID of the new comment.
3297
* @param array $args An array of new comment arguments.
3299
do_action( 'xmlrpc_call_success_wp_newComment', $comment_ID, $args );
3305
* Retrieve all of the comment status.
3309
* @param array $args Method parameters.
3312
public function wp_getCommentStatusList($args) {
3313
$this->escape( $args );
3315
$blog_id = (int) $args[0];
3316
$username = $args[1];
3317
$password = $args[2];
3319
if ( !$user = $this->login($username, $password) )
3320
return $this->error;
3322
if ( !current_user_can( 'moderate_comments' ) )
3323
return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
3325
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3326
do_action( 'xmlrpc_call', 'wp.getCommentStatusList' );
3328
return get_comment_statuses();
3332
* Retrieve comment count.
3336
* @param array $args Method parameters.
3339
public function wp_getCommentCount( $args ) {
3340
$this->escape($args);
3342
$blog_id = (int) $args[0];
3343
$username = $args[1];
3344
$password = $args[2];
3345
$post_id = (int) $args[3];
3347
if ( !$user = $this->login($username, $password) )
3348
return $this->error;
3350
if ( !current_user_can( 'edit_posts' ) )
3351
return new IXR_Error( 403, __( 'You are not allowed access to details about comments.' ) );
3353
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3354
do_action( 'xmlrpc_call', 'wp.getCommentCount' );
3356
$count = wp_count_comments( $post_id );
3358
'approved' => $count->approved,
3359
'awaiting_moderation' => $count->moderated,
3360
'spam' => $count->spam,
3361
'total_comments' => $count->total_comments
3366
* Retrieve post statuses.
3370
* @param array $args Method parameters.
3373
public function wp_getPostStatusList( $args ) {
3374
$this->escape( $args );
3376
$blog_id = (int) $args[0];
3377
$username = $args[1];
3378
$password = $args[2];
3380
if ( !$user = $this->login($username, $password) )
3381
return $this->error;
3383
if ( !current_user_can( 'edit_posts' ) )
3384
return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
3386
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3387
do_action( 'xmlrpc_call', 'wp.getPostStatusList' );
3389
return get_post_statuses();
3393
* Retrieve page statuses.
3397
* @param array $args Method parameters.
3400
public function wp_getPageStatusList( $args ) {
3401
$this->escape( $args );
3403
$blog_id = (int) $args[0];
3404
$username = $args[1];
3405
$password = $args[2];
3407
if ( !$user = $this->login($username, $password) )
3408
return $this->error;
3410
if ( !current_user_can( 'edit_pages' ) )
3411
return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
3413
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3414
do_action( 'xmlrpc_call', 'wp.getPageStatusList' );
3416
return get_page_statuses();
3420
* Retrieve page templates.
3424
* @param array $args Method parameters.
3427
public function wp_getPageTemplates( $args ) {
3428
$this->escape( $args );
3430
$blog_id = (int) $args[0];
3431
$username = $args[1];
3432
$password = $args[2];
3434
if ( !$user = $this->login($username, $password) )
3435
return $this->error;
3437
if ( !current_user_can( 'edit_pages' ) )
3438
return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
3440
$templates = get_page_templates();
3441
$templates['Default'] = 'default';
3447
* Retrieve blog options.
3451
* @param array $args Method parameters.
3454
public function wp_getOptions( $args ) {
3455
$this->escape( $args );
3457
$blog_id = (int) $args[0];
3458
$username = $args[1];
3459
$password = $args[2];
3460
$options = isset( $args[3] ) ? (array) $args[3] : array();
3462
if ( !$user = $this->login($username, $password) )
3463
return $this->error;
3465
// If no specific options where asked for, return all of them
3466
if ( count( $options ) == 0 )
3467
$options = array_keys($this->blog_options);
3469
return $this->_getOptions($options);
3473
* Retrieve blog options value from list.
3477
* @param array $options Options to retrieve.
3480
public function _getOptions($options) {
3482
$can_manage = current_user_can( 'manage_options' );
3483
foreach ( $options as $option ) {
3484
if ( array_key_exists( $option, $this->blog_options ) ) {
3485
$data[$option] = $this->blog_options[$option];
3486
//Is the value static or dynamic?
3487
if ( isset( $data[$option]['option'] ) ) {
3488
$data[$option]['value'] = get_option( $data[$option]['option'] );
3489
unset($data[$option]['option']);
3492
if ( ! $can_manage )
3493
$data[$option]['readonly'] = true;
3501
* Update blog options.
3505
* @param array $args Method parameters.
3508
public function wp_setOptions( $args ) {
3509
$this->escape( $args );
3511
$blog_id = (int) $args[0];
3512
$username = $args[1];
3513
$password = $args[2];
3514
$options = (array) $args[3];
3516
if ( !$user = $this->login($username, $password) )
3517
return $this->error;
3519
if ( !current_user_can( 'manage_options' ) )
3520
return new IXR_Error( 403, __( 'You are not allowed to update options.' ) );
3522
foreach ( $options as $o_name => $o_value ) {
3523
$option_names[] = $o_name;
3524
if ( !array_key_exists( $o_name, $this->blog_options ) )
3527
if ( $this->blog_options[$o_name]['readonly'] == true )
3530
update_option( $this->blog_options[$o_name]['option'], wp_unslash( $o_value ) );
3533
//Now return the updated values
3534
return $this->_getOptions($option_names);
3538
* Retrieve a media item by ID
3542
* @param array $args Method parameters. Contains:
3547
* @return array. Associative array containing:
3548
* - 'date_created_gmt'
3557
public function wp_getMediaItem($args) {
3558
$this->escape($args);
3560
$blog_id = (int) $args[0];
3561
$username = $args[1];
3562
$password = $args[2];
3563
$attachment_id = (int) $args[3];
3565
if ( !$user = $this->login($username, $password) )
3566
return $this->error;
3568
if ( !current_user_can( 'upload_files' ) )
3569
return new IXR_Error( 403, __( 'You do not have permission to upload files.' ) );
3571
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3572
do_action( 'xmlrpc_call', 'wp.getMediaItem' );
3574
if ( ! $attachment = get_post($attachment_id) )
3575
return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
3577
return $this->_prepare_media_item( $attachment );
3581
* Retrieves a collection of media library items (or attachments)
3583
* Besides the common blog_id, username, and password arguments, it takes a filter
3584
* array as last argument.
3586
* Accepted 'filter' keys are 'parent_id', 'mime_type', 'offset', and 'number'.
3588
* The defaults are as follows:
3589
* - 'number' - Default is 5. Total number of media items to retrieve.
3590
* - 'offset' - Default is 0. See {@link WP_Query::query()} for more.
3591
* - 'parent_id' - Default is ''. The post where the media item is attached. Empty string shows all media items. 0 shows unattached media items.
3592
* - 'mime_type' - Default is ''. Filter by mime type (e.g., 'image/jpeg', 'application/pdf')
3596
* @param array $args Method parameters. Contains:
3601
* @return array. Contains a collection of media items. See {@link wp_xmlrpc_server::wp_getMediaItem()} for a description of each item contents
3603
public function wp_getMediaLibrary($args) {
3604
$this->escape($args);
3606
$blog_id = (int) $args[0];
3607
$username = $args[1];
3608
$password = $args[2];
3609
$struct = isset( $args[3] ) ? $args[3] : array() ;
3611
if ( !$user = $this->login($username, $password) )
3612
return $this->error;
3614
if ( !current_user_can( 'upload_files' ) )
3615
return new IXR_Error( 401, __( 'You do not have permission to upload files.' ) );
3617
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3618
do_action( 'xmlrpc_call', 'wp.getMediaLibrary' );
3620
$parent_id = ( isset($struct['parent_id']) ) ? absint($struct['parent_id']) : '' ;
3621
$mime_type = ( isset($struct['mime_type']) ) ? $struct['mime_type'] : '' ;
3622
$offset = ( isset($struct['offset']) ) ? absint($struct['offset']) : 0 ;
3623
$number = ( isset($struct['number']) ) ? absint($struct['number']) : -1 ;
3625
$attachments = get_posts( array('post_type' => 'attachment', 'post_parent' => $parent_id, 'offset' => $offset, 'numberposts' => $number, 'post_mime_type' => $mime_type ) );
3627
$attachments_struct = array();
3629
foreach ($attachments as $attachment )
3630
$attachments_struct[] = $this->_prepare_media_item( $attachment );
3632
return $attachments_struct;
3636
* Retrieves a list of post formats used by the site
3640
* @param array $args Method parameters. Contains:
3646
public function wp_getPostFormats( $args ) {
3647
$this->escape( $args );
3649
$blog_id = (int) $args[0];
3650
$username = $args[1];
3651
$password = $args[2];
3653
if ( !$user = $this->login( $username, $password ) )
3654
return $this->error;
3656
if ( !current_user_can( 'edit_posts' ) )
3657
return new IXR_Error( 403, __( 'You are not allowed access to details about this site.' ) );
3659
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3660
do_action( 'xmlrpc_call', 'wp.getPostFormats' );
3662
$formats = get_post_format_strings();
3664
# find out if they want a list of currently supports formats
3665
if ( isset( $args[3] ) && is_array( $args[3] ) ) {
3666
if ( $args[3]['show-supported'] ) {
3667
if ( current_theme_supports( 'post-formats' ) ) {
3668
$supported = get_theme_support( 'post-formats' );
3670
$data['all'] = $formats;
3671
$data['supported'] = $supported[0];
3682
* Retrieves a post type
3686
* @uses get_post_type_object()
3687
* @param array $args Method parameters. Contains:
3689
* - string $username
3690
* - string $password
3691
* - string $post_type_name
3693
* @return array contains:
3696
* - 'capability_type'
3704
public function wp_getPostType( $args ) {
3705
if ( ! $this->minimum_args( $args, 4 ) )
3706
return $this->error;
3708
$this->escape( $args );
3710
$blog_id = (int) $args[0];
3711
$username = $args[1];
3712
$password = $args[2];
3713
$post_type_name = $args[3];
3715
if ( isset( $args[4] ) ) {
3719
* Filter the default query fields used by the given XML-RPC method.
3723
* @param array $fields An array of post type query fields for the given method.
3724
* @param string $method The method name.
3726
$fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostType' );
3729
if ( !$user = $this->login( $username, $password ) )
3730
return $this->error;
3732
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3733
do_action( 'xmlrpc_call', 'wp.getPostType' );
3735
if( ! post_type_exists( $post_type_name ) )
3736
return new IXR_Error( 403, __( 'Invalid post type' ) );
3738
$post_type = get_post_type_object( $post_type_name );
3740
if( ! current_user_can( $post_type->cap->edit_posts ) )
3741
return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post type.' ) );
3743
return $this->_prepare_post_type( $post_type, $fields );
3747
* Retrieves a post types
3751
* @uses get_post_types()
3752
* @param array $args Method parameters. Contains:
3754
* - string $username
3755
* - string $password
3760
public function wp_getPostTypes( $args ) {
3761
if ( ! $this->minimum_args( $args, 3 ) )
3762
return $this->error;
3764
$this->escape( $args );
3766
$blog_id = (int) $args[0];
3767
$username = $args[1];
3768
$password = $args[2];
3769
$filter = isset( $args[3] ) ? $args[3] : array( 'public' => true );
3771
if ( isset( $args[4] ) ) {
3774
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3775
$fields = apply_filters( 'xmlrpc_default_posttype_fields', array( 'labels', 'cap', 'taxonomies' ), 'wp.getPostTypes' );
3778
if ( ! $user = $this->login( $username, $password ) )
3779
return $this->error;
3781
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3782
do_action( 'xmlrpc_call', 'wp.getPostTypes' );
3784
$post_types = get_post_types( $filter, 'objects' );
3788
foreach( $post_types as $post_type ) {
3789
if( ! current_user_can( $post_type->cap->edit_posts ) )
3792
$struct[$post_type->name] = $this->_prepare_post_type( $post_type, $fields );
3799
* Retrieve revisions for a specific post.
3803
* The optional $fields parameter specifies what fields will be included
3804
* in the response array.
3806
* @uses wp_get_post_revisions()
3807
* @see wp_getPost() for more on $fields
3809
* @param array $args Method parameters. Contains:
3811
* - string $username
3812
* - string $password
3815
* @return array contains a collection of posts.
3817
public function wp_getRevisions( $args ) {
3818
if ( ! $this->minimum_args( $args, 4 ) )
3819
return $this->error;
3821
$this->escape( $args );
3823
$blog_id = (int) $args[0];
3824
$username = $args[1];
3825
$password = $args[2];
3826
$post_id = (int) $args[3];
3828
if ( isset( $args[4] ) ) {
3832
* Filter the default revision query fields used by the given XML-RPC method.
3836
* @param array $field An array of revision query fields.
3837
* @param string $method The method name.
3839
$fields = apply_filters( 'xmlrpc_default_revision_fields', array( 'post_date', 'post_date_gmt' ), 'wp.getRevisions' );
3842
if ( ! $user = $this->login( $username, $password ) )
3843
return $this->error;
3845
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3846
do_action( 'xmlrpc_call', 'wp.getRevisions' );
3848
if ( ! $post = get_post( $post_id ) )
3849
return new IXR_Error( 404, __( 'Invalid post ID' ) );
3851
if ( ! current_user_can( 'edit_post', $post_id ) )
3852
return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit posts.' ) );
3854
// Check if revisions are enabled.
3855
if ( ! wp_revisions_enabled( $post ) )
3856
return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) );
3858
$revisions = wp_get_post_revisions( $post_id );
3865
foreach ( $revisions as $revision ) {
3866
if ( ! current_user_can( 'read_post', $revision->ID ) )
3870
if ( wp_is_post_autosave( $revision ) )
3873
$struct[] = $this->_prepare_post( get_object_vars( $revision ), $fields );
3880
* Restore a post revision
3884
* @uses wp_restore_post_revision()
3886
* @param array $args Method parameters. Contains:
3888
* - string $username
3889
* - string $password
3891
* @return bool false if there was an error restoring, true if success.
3893
public function wp_restoreRevision( $args ) {
3894
if ( ! $this->minimum_args( $args, 3 ) )
3895
return $this->error;
3897
$this->escape( $args );
3899
$blog_id = (int) $args[0];
3900
$username = $args[1];
3901
$password = $args[2];
3902
$revision_id = (int) $args[3];
3904
if ( ! $user = $this->login( $username, $password ) )
3905
return $this->error;
3907
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3908
do_action( 'xmlrpc_call', 'wp.restoreRevision' );
3910
if ( ! $revision = wp_get_post_revision( $revision_id ) )
3911
return new IXR_Error( 404, __( 'Invalid post ID' ) );
3913
if ( wp_is_post_autosave( $revision ) )
3914
return new IXR_Error( 404, __( 'Invalid post ID' ) );
3916
if ( ! $post = get_post( $revision->post_parent ) )
3917
return new IXR_Error( 404, __( 'Invalid post ID' ) );
3919
if ( ! current_user_can( 'edit_post', $revision->post_parent ) )
3920
return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
3922
// Check if revisions are disabled.
3923
if ( ! wp_revisions_enabled( $post ) )
3924
return new IXR_Error( 401, __( 'Sorry, revisions are disabled.' ) );
3926
$post = wp_restore_post_revision( $revision_id );
3928
return (bool) $post;
3931
/* Blogger API functions.
3932
* specs on http://plant.blogger.com/api and http://groups.yahoo.com/group/bloggerDev/
3936
* Retrieve blogs that user owns.
3938
* Will make more sense once we support multiple blogs.
3942
* @param array $args Method parameters.
3945
public function blogger_getUsersBlogs($args) {
3946
if ( is_multisite() )
3947
return $this->_multisite_getUsersBlogs($args);
3949
$this->escape($args);
3951
$username = $args[1];
3952
$password = $args[2];
3954
if ( !$user = $this->login($username, $password) )
3955
return $this->error;
3957
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
3958
do_action( 'xmlrpc_call', 'blogger.getUsersBlogs' );
3960
$is_admin = current_user_can('manage_options');
3963
'isAdmin' => $is_admin,
3964
'url' => get_option('home') . '/',
3966
'blogName' => get_option('blogname'),
3967
'xmlrpc' => site_url( 'xmlrpc.php', 'rpc' ),
3970
return array($struct);
3974
* Private function for retrieving a users blogs for multisite setups
3978
protected function _multisite_getUsersBlogs($args) {
3979
$current_blog = get_blog_details();
3981
$domain = $current_blog->domain;
3982
$path = $current_blog->path . 'xmlrpc.php';
3984
$rpc = new IXR_Client( set_url_scheme( "http://{$domain}{$path}" ) );
3985
$rpc->query('wp.getUsersBlogs', $args[1], $args[2]);
3986
$blogs = $rpc->getResponse();
3988
if ( isset($blogs['faultCode']) )
3989
return new IXR_Error($blogs['faultCode'], $blogs['faultString']);
3991
if ( $_SERVER['HTTP_HOST'] == $domain && $_SERVER['REQUEST_URI'] == $path ) {
3994
foreach ( (array) $blogs as $blog ) {
3995
if ( strpos($blog['url'], $_SERVER['HTTP_HOST']) )
3996
return array($blog);
4003
* Retrieve user's data.
4005
* Gives your client some info about you, so you don't have to.
4009
* @param array $args Method parameters.
4012
public function blogger_getUserInfo($args) {
4014
$this->escape($args);
4016
$username = $args[1];
4017
$password = $args[2];
4019
if ( !$user = $this->login($username, $password) )
4020
return $this->error;
4022
if ( !current_user_can( 'edit_posts' ) )
4023
return new IXR_Error( 401, __( 'Sorry, you do not have access to user data on this site.' ) );
4025
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4026
do_action( 'xmlrpc_call', 'blogger.getUserInfo' );
4029
'nickname' => $user->nickname,
4030
'userid' => $user->ID,
4031
'url' => $user->user_url,
4032
'lastname' => $user->last_name,
4033
'firstname' => $user->first_name
4044
* @param array $args Method parameters.
4047
public function blogger_getPost($args) {
4049
$this->escape($args);
4051
$post_ID = (int) $args[1];
4052
$username = $args[2];
4053
$password = $args[3];
4055
if ( !$user = $this->login($username, $password) )
4056
return $this->error;
4058
$post_data = get_post($post_ID, ARRAY_A);
4060
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
4062
if ( !current_user_can( 'edit_post', $post_ID ) )
4063
return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
4065
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4066
do_action( 'xmlrpc_call', 'blogger.getPost' );
4068
$categories = implode(',', wp_get_post_categories($post_ID));
4070
$content = '<title>'.wp_unslash($post_data['post_title']).'</title>';
4071
$content .= '<category>'.$categories.'</category>';
4072
$content .= wp_unslash($post_data['post_content']);
4075
'userid' => $post_data['post_author'],
4076
'dateCreated' => $this->_convert_date( $post_data['post_date'] ),
4077
'content' => $content,
4078
'postid' => (string) $post_data['ID']
4085
* Retrieve list of recent posts.
4089
* @param array $args Method parameters.
4092
public function blogger_getRecentPosts($args) {
4094
$this->escape($args);
4096
// $args[0] = appkey - ignored
4097
$blog_ID = (int) $args[1]; /* though we don't use it yet */
4098
$username = $args[2];
4099
$password = $args[3];
4100
if ( isset( $args[4] ) )
4101
$query = array( 'numberposts' => absint( $args[4] ) );
4105
if ( !$user = $this->login($username, $password) )
4106
return $this->error;
4108
if ( ! current_user_can( 'edit_posts' ) )
4109
return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) );
4111
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4112
do_action( 'xmlrpc_call', 'blogger.getRecentPosts' );
4114
$posts_list = wp_get_recent_posts( $query );
4116
if ( !$posts_list ) {
4117
$this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
4118
return $this->error;
4121
foreach ($posts_list as $entry) {
4122
if ( !current_user_can( 'edit_post', $entry['ID'] ) )
4125
$post_date = $this->_convert_date( $entry['post_date'] );
4126
$categories = implode(',', wp_get_post_categories($entry['ID']));
4128
$content = '<title>'.wp_unslash($entry['post_title']).'</title>';
4129
$content .= '<category>'.$categories.'</category>';
4130
$content .= wp_unslash($entry['post_content']);
4133
'userid' => $entry['post_author'],
4134
'dateCreated' => $post_date,
4135
'content' => $content,
4136
'postid' => (string) $entry['ID'],
4141
$recent_posts = array();
4142
for ( $j=0; $j<count($struct); $j++ ) {
4143
array_push($recent_posts, $struct[$j]);
4146
return $recent_posts;
4155
public function blogger_getTemplate($args) {
4156
return new IXR_Error( 403, __('Sorry, that file cannot be edited.' ) );
4165
public function blogger_setTemplate($args) {
4166
return new IXR_Error( 403, __('Sorry, that file cannot be edited.' ) );
4174
* @param array $args Method parameters.
4177
public function blogger_newPost($args) {
4179
$this->escape($args);
4181
$blog_ID = (int) $args[1]; /* though we don't use it yet */
4182
$username = $args[2];
4183
$password = $args[3];
4184
$content = $args[4];
4185
$publish = $args[5];
4187
if ( !$user = $this->login($username, $password) )
4188
return $this->error;
4190
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4191
do_action( 'xmlrpc_call', 'blogger.newPost' );
4193
$cap = ($publish) ? 'publish_posts' : 'edit_posts';
4194
if ( ! current_user_can( get_post_type_object( 'post' )->cap->create_posts ) || !current_user_can($cap) )
4195
return new IXR_Error(401, __('Sorry, you are not allowed to post on this site.'));
4197
$post_status = ($publish) ? 'publish' : 'draft';
4199
$post_author = $user->ID;
4201
$post_title = xmlrpc_getposttitle($content);
4202
$post_category = xmlrpc_getpostcategory($content);
4203
$post_content = xmlrpc_removepostdata($content);
4205
$post_date = current_time('mysql');
4206
$post_date_gmt = current_time('mysql', 1);
4208
$post_data = compact('blog_ID', 'post_author', 'post_date', 'post_date_gmt', 'post_content', 'post_title', 'post_category', 'post_status');
4210
$post_ID = wp_insert_post($post_data);
4211
if ( is_wp_error( $post_ID ) )
4212
return new IXR_Error(500, $post_ID->get_error_message());
4215
return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
4217
$this->attach_uploads( $post_ID, $post_content );
4220
* Fires after a new post has been successfully created via the XML-RPC Blogger API.
4224
* @param int $post_ID ID of the new post.
4225
* @param array $args An array of new post arguments.
4227
do_action( 'xmlrpc_call_success_blogger_newPost', $post_ID, $args );
4237
* @param array $args Method parameters.
4238
* @return bool true when done.
4240
public function blogger_editPost( $args ) {
4242
$this->escape($args);
4244
$post_ID = (int) $args[1];
4245
$username = $args[2];
4246
$password = $args[3];
4247
$content = $args[4];
4248
$publish = $args[5];
4250
if ( ! $user = $this->login( $username, $password ) ) {
4251
return $this->error;
4254
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4255
do_action( 'xmlrpc_call', 'blogger.editPost' );
4257
$actual_post = get_post( $post_ID, ARRAY_A );
4259
if ( ! $actual_post || $actual_post['post_type'] != 'post' ) {
4260
return new IXR_Error( 404, __( 'Sorry, no such post.' ) );
4263
$this->escape($actual_post);
4265
if ( ! current_user_can( 'edit_post', $post_ID ) ) {
4266
return new IXR_Error(401, __('Sorry, you do not have the right to edit this post.'));
4268
if ( 'publish' == $actual_post['post_status'] && ! current_user_can( 'publish_posts' ) ) {
4269
return new IXR_Error( 401, __( 'Sorry, you do not have the right to publish this post.' ) );
4272
$postdata = array();
4273
$postdata['ID'] = $actual_post['ID'];
4274
$postdata['post_content'] = xmlrpc_removepostdata( $content );
4275
$postdata['post_title'] = xmlrpc_getposttitle( $content );
4276
$postdata['post_category'] = xmlrpc_getpostcategory( $content );
4277
$postdata['post_status'] = $actual_post['post_status'];
4278
$postdata['post_excerpt'] = $actual_post['post_excerpt'];
4280
$result = wp_update_post( $postdata );
4283
return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be edited.'));
4285
$this->attach_uploads( $actual_post['ID'], $postdata['post_content'] );
4288
* Fires after a post has been successfully updated via the XML-RPC Blogger API.
4292
* @param int $post_ID ID of the updated post.
4293
* @param array $args An array of arguments for the post to edit.
4295
do_action( 'xmlrpc_call_success_blogger_editPost', $post_ID, $args );
4305
* @param array $args Method parameters.
4306
* @return bool True when post is deleted.
4308
public function blogger_deletePost($args) {
4309
$this->escape($args);
4311
$post_ID = (int) $args[1];
4312
$username = $args[2];
4313
$password = $args[3];
4314
$publish = $args[4];
4316
if ( !$user = $this->login($username, $password) )
4317
return $this->error;
4319
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4320
do_action( 'xmlrpc_call', 'blogger.deletePost' );
4322
$actual_post = get_post($post_ID,ARRAY_A);
4324
if ( !$actual_post || $actual_post['post_type'] != 'post' )
4325
return new IXR_Error(404, __('Sorry, no such post.'));
4327
if ( !current_user_can('delete_post', $post_ID) )
4328
return new IXR_Error(401, __('Sorry, you do not have the right to delete this post.'));
4330
$result = wp_delete_post($post_ID);
4333
return new IXR_Error(500, __('For some strange yet very annoying reason, this post could not be deleted.'));
4336
* Fires after a post has been successfully deleted via the XML-RPC Blogger API.
4340
* @param int $post_ID ID of the deleted post.
4341
* @param array $args An array of arguments to delete the post.
4343
do_action( 'xmlrpc_call_success_blogger_deletePost', $post_ID, $args );
4348
/* MetaWeblog API functions
4349
* specs on wherever Dave Winer wants them to be
4353
* Create a new post.
4355
* The 'content_struct' argument must contain:
4364
* Also, it can optionally contain:
4367
* - wp_page_parent_id
4370
* - post_status | page_status - can be 'draft', 'private', 'publish', or 'pending'
4371
* - mt_allow_comments - can be 'open' or 'closed'
4372
* - mt_allow_pings - can be 'open' or 'closed'
4373
* - date_created_gmt
4375
* - wp_post_thumbnail
4379
* @param array $args Method parameters. Contains:
4387
public function mw_newPost($args) {
4388
$this->escape($args);
4390
$blog_ID = (int) $args[0];
4391
$username = $args[1];
4392
$password = $args[2];
4393
$content_struct = $args[3];
4394
$publish = isset( $args[4] ) ? $args[4] : 0;
4396
if ( !$user = $this->login($username, $password) )
4397
return $this->error;
4399
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4400
do_action( 'xmlrpc_call', 'metaWeblog.newPost' );
4402
$page_template = '';
4403
if ( !empty( $content_struct['post_type'] ) ) {
4404
if ( $content_struct['post_type'] == 'page' ) {
4406
$cap = 'publish_pages';
4407
elseif ( isset( $content_struct['page_status'] ) && 'publish' == $content_struct['page_status'] )
4408
$cap = 'publish_pages';
4410
$cap = 'edit_pages';
4411
$error_message = __( 'Sorry, you are not allowed to publish pages on this site.' );
4412
$post_type = 'page';
4413
if ( !empty( $content_struct['wp_page_template'] ) )
4414
$page_template = $content_struct['wp_page_template'];
4415
} elseif ( $content_struct['post_type'] == 'post' ) {
4417
$cap = 'publish_posts';
4418
elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status'] )
4419
$cap = 'publish_posts';
4421
$cap = 'edit_posts';
4422
$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
4423
$post_type = 'post';
4425
// No other post_type values are allowed here
4426
return new IXR_Error( 401, __( 'Invalid post type' ) );
4430
$cap = 'publish_posts';
4431
elseif ( isset( $content_struct['post_status'] ) && 'publish' == $content_struct['post_status'])
4432
$cap = 'publish_posts';
4434
$cap = 'edit_posts';
4435
$error_message = __( 'Sorry, you are not allowed to publish posts on this site.' );
4436
$post_type = 'post';
4439
if ( ! current_user_can( get_post_type_object( $post_type )->cap->create_posts ) )
4440
return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts on this site.' ) );
4441
if ( !current_user_can( $cap ) )
4442
return new IXR_Error( 401, $error_message );
4444
// Check for a valid post format if one was given
4445
if ( isset( $content_struct['wp_post_format'] ) ) {
4446
$content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] );
4447
if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) {
4448
return new IXR_Error( 404, __( 'Invalid post format' ) );
4452
// Let WordPress generate the post_name (slug) unless
4453
// one has been provided.
4455
if ( isset($content_struct['wp_slug']) )
4456
$post_name = $content_struct['wp_slug'];
4458
// Only use a password if one was given.
4459
if ( isset($content_struct['wp_password']) )
4460
$post_password = $content_struct['wp_password'];
4462
// Only set a post parent if one was provided.
4463
if ( isset($content_struct['wp_page_parent_id']) )
4464
$post_parent = $content_struct['wp_page_parent_id'];
4466
// Only set the menu_order if it was provided.
4467
if ( isset($content_struct['wp_page_order']) )
4468
$menu_order = $content_struct['wp_page_order'];
4470
$post_author = $user->ID;
4472
// If an author id was provided then use it instead.
4473
if ( isset( $content_struct['wp_author_id'] ) && ( $user->ID != $content_struct['wp_author_id'] ) ) {
4474
switch ( $post_type ) {
4476
if ( !current_user_can( 'edit_others_posts' ) )
4477
return( new IXR_Error( 401, __( 'You are not allowed to create posts as this user.' ) ) );
4480
if ( !current_user_can( 'edit_others_pages' ) )
4481
return( new IXR_Error( 401, __( 'You are not allowed to create pages as this user.' ) ) );
4484
return( new IXR_Error( 401, __( 'Invalid post type' ) ) );
4487
$author = get_userdata( $content_struct['wp_author_id'] );
4489
return new IXR_Error( 404, __( 'Invalid author ID.' ) );
4490
$post_author = $content_struct['wp_author_id'];
4493
$post_title = isset( $content_struct['title'] ) ? $content_struct['title'] : null;
4494
$post_content = isset( $content_struct['description'] ) ? $content_struct['description'] : null;
4496
$post_status = $publish ? 'publish' : 'draft';
4498
if ( isset( $content_struct["{$post_type}_status"] ) ) {
4499
switch ( $content_struct["{$post_type}_status"] ) {
4504
$post_status = $content_struct["{$post_type}_status"];
4507
$post_status = $publish ? 'publish' : 'draft';
4512
$post_excerpt = isset($content_struct['mt_excerpt']) ? $content_struct['mt_excerpt'] : null;
4513
$post_more = isset($content_struct['mt_text_more']) ? $content_struct['mt_text_more'] : null;
4515
$tags_input = isset($content_struct['mt_keywords']) ? $content_struct['mt_keywords'] : null;
4517
if ( isset($content_struct['mt_allow_comments']) ) {
4518
if ( !is_numeric($content_struct['mt_allow_comments']) ) {
4519
switch ( $content_struct['mt_allow_comments'] ) {
4521
$comment_status = 'closed';
4524
$comment_status = 'open';
4527
$comment_status = get_option('default_comment_status');
4531
switch ( (int) $content_struct['mt_allow_comments'] ) {
4534
$comment_status = 'closed';
4537
$comment_status = 'open';
4540
$comment_status = get_option('default_comment_status');
4545
$comment_status = get_option('default_comment_status');
4548
if ( isset($content_struct['mt_allow_pings']) ) {
4549
if ( !is_numeric($content_struct['mt_allow_pings']) ) {
4550
switch ( $content_struct['mt_allow_pings'] ) {
4552
$ping_status = 'closed';
4555
$ping_status = 'open';
4558
$ping_status = get_option('default_ping_status');
4562
switch ( (int) $content_struct['mt_allow_pings'] ) {
4564
$ping_status = 'closed';
4567
$ping_status = 'open';
4570
$ping_status = get_option('default_ping_status');
4575
$ping_status = get_option('default_ping_status');
4579
$post_content = $post_content . '<!--more-->' . $post_more;
4582
if ( isset( $content_struct['mt_tb_ping_urls'] ) ) {
4583
$to_ping = $content_struct['mt_tb_ping_urls'];
4584
if ( is_array($to_ping) )
4585
$to_ping = implode(' ', $to_ping);
4588
// Do some timestamp voodoo
4589
if ( !empty( $content_struct['date_created_gmt'] ) )
4590
// We know this is supposed to be GMT, so we're going to slap that Z on there by force
4591
$dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
4592
elseif ( !empty( $content_struct['dateCreated']) )
4593
$dateCreated = $content_struct['dateCreated']->getIso();
4595
if ( !empty( $dateCreated ) ) {
4596
$post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
4597
$post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
4599
$post_date = current_time('mysql');
4600
$post_date_gmt = current_time('mysql', 1);
4603
$post_category = array();
4604
if ( isset( $content_struct['categories'] ) ) {
4605
$catnames = $content_struct['categories'];
4607
if ( is_array($catnames) ) {
4608
foreach ($catnames as $cat) {
4609
$post_category[] = get_cat_ID($cat);
4614
$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');
4616
$post_ID = $postdata['ID'] = get_default_post_to_edit( $post_type, true )->ID;
4618
// Only posts can be sticky
4619
if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
4620
if ( $content_struct['sticky'] == true )
4621
stick_post( $post_ID );
4622
elseif ( $content_struct['sticky'] == false )
4623
unstick_post( $post_ID );
4626
if ( isset($content_struct['custom_fields']) )
4627
$this->set_custom_fields($post_ID, $content_struct['custom_fields']);
4629
if ( isset ( $content_struct['wp_post_thumbnail'] ) ) {
4630
if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false )
4631
return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
4633
unset( $content_struct['wp_post_thumbnail'] );
4636
// Handle enclosures
4637
$thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null;
4638
$this->add_enclosure_if_new($post_ID, $thisEnclosure);
4640
$this->attach_uploads( $post_ID, $post_content );
4642
// Handle post formats if assigned, value is validated earlier
4644
if ( isset( $content_struct['wp_post_format'] ) )
4645
set_post_format( $post_ID, $content_struct['wp_post_format'] );
4647
$post_ID = wp_insert_post( $postdata, true );
4648
if ( is_wp_error( $post_ID ) )
4649
return new IXR_Error(500, $post_ID->get_error_message());
4652
return new IXR_Error(500, __('Sorry, your entry could not be posted. Something wrong happened.'));
4655
* Fires after a new post has been successfully created via the XML-RPC MovableType API.
4659
* @param int $post_ID ID of the new post.
4660
* @param array $args An array of arguments to create the new post.
4662
do_action( 'xmlrpc_call_success_mw_newPost', $post_ID, $args );
4664
return strval($post_ID);
4667
public function add_enclosure_if_new( $post_ID, $enclosure ) {
4668
if ( is_array( $enclosure ) && isset( $enclosure['url'] ) && isset( $enclosure['length'] ) && isset( $enclosure['type'] ) ) {
4669
$encstring = $enclosure['url'] . "\n" . $enclosure['length'] . "\n" . $enclosure['type'] . "\n";
4671
if ( $enclosures = get_post_meta( $post_ID, 'enclosure' ) ) {
4672
foreach ( $enclosures as $enc ) {
4673
// This method used to omit the trailing new line. #23219
4674
if ( rtrim( $enc, "\n" ) == rtrim( $encstring, "\n" ) ) {
4681
add_post_meta( $post_ID, 'enclosure', $encstring );
4686
* Attach upload to a post.
4690
* @param int $post_ID Post ID.
4691
* @param string $post_content Post Content for attachment.
4693
public function attach_uploads( $post_ID, $post_content ) {
4696
// find any unattached files
4697
$attachments = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts} WHERE post_parent = '0' AND post_type = 'attachment'" );
4698
if ( is_array( $attachments ) ) {
4699
foreach ( $attachments as $file ) {
4700
if ( ! empty( $file->guid ) && strpos( $post_content, $file->guid ) !== false )
4701
$wpdb->update($wpdb->posts, array('post_parent' => $post_ID), array('ID' => $file->ID) );
4711
* @param array $args Method parameters.
4712
* @return bool True on success.
4714
public function mw_editPost($args) {
4716
$this->escape($args);
4718
$post_ID = (int) $args[0];
4719
$username = $args[1];
4720
$password = $args[2];
4721
$content_struct = $args[3];
4722
$publish = isset( $args[4] ) ? $args[4] : 0;
4724
if ( ! $user = $this->login($username, $password) )
4725
return $this->error;
4727
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
4728
do_action( 'xmlrpc_call', 'metaWeblog.editPost' );
4730
$postdata = get_post( $post_ID, ARRAY_A );
4732
// If there is no post data for the give post id, stop
4733
// now and return an error. Other wise a new post will be
4734
// created (which was the old behavior).
4735
if ( ! $postdata || empty( $postdata[ 'ID' ] ) )
4736
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
4738
if ( ! current_user_can( 'edit_post', $post_ID ) )
4739
return new IXR_Error( 401, __( 'Sorry, you do not have the right to edit this post.' ) );
4741
// Use wp.editPost to edit post types other than post and page.
4742
if ( ! in_array( $postdata[ 'post_type' ], array( 'post', 'page' ) ) )
4743
return new IXR_Error( 401, __( 'Invalid post type' ) );
4745
// Thwart attempt to change the post type.
4746
if ( ! empty( $content_struct[ 'post_type' ] ) && ( $content_struct['post_type'] != $postdata[ 'post_type' ] ) )
4747
return new IXR_Error( 401, __( 'The post type may not be changed.' ) );
4749
// Check for a valid post format if one was given
4750
if ( isset( $content_struct['wp_post_format'] ) ) {
4751
$content_struct['wp_post_format'] = sanitize_key( $content_struct['wp_post_format'] );
4752
if ( !array_key_exists( $content_struct['wp_post_format'], get_post_format_strings() ) ) {
4753
return new IXR_Error( 404, __( 'Invalid post format' ) );
4757
$this->escape($postdata);
4759
$ID = $postdata['ID'];
4760
$post_content = $postdata['post_content'];
4761
$post_title = $postdata['post_title'];
4762
$post_excerpt = $postdata['post_excerpt'];
4763
$post_password = $postdata['post_password'];
4764
$post_parent = $postdata['post_parent'];
4765
$post_type = $postdata['post_type'];
4766
$menu_order = $postdata['menu_order'];
4768
// Let WordPress manage slug if none was provided.
4770
$post_name = $postdata['post_name'];
4771
if ( isset($content_struct['wp_slug']) )
4772
$post_name = $content_struct['wp_slug'];
4774
// Only use a password if one was given.
4775
if ( isset($content_struct['wp_password']) )
4776
$post_password = $content_struct['wp_password'];
4778
// Only set a post parent if one was given.
4779
if ( isset($content_struct['wp_page_parent_id']) )
4780
$post_parent = $content_struct['wp_page_parent_id'];
4782
// Only set the menu_order if it was given.
4783
if ( isset($content_struct['wp_page_order']) )
4784
$menu_order = $content_struct['wp_page_order'];
4786
$page_template = null;
4787
if ( ! empty( $content_struct['wp_page_template'] ) && 'page' == $post_type )
4788
$page_template = $content_struct['wp_page_template'];
4790
$post_author = $postdata['post_author'];
4792
// Only set the post_author if one is set.
4793
if ( isset($content_struct['wp_author_id']) && ($user->ID != $content_struct['wp_author_id']) ) {
4794
switch ( $post_type ) {
4796
if ( !current_user_can('edit_others_posts') )
4797
return(new IXR_Error(401, __('You are not allowed to change the post author as this user.')));
4800
if ( !current_user_can('edit_others_pages') )
4801
return(new IXR_Error(401, __('You are not allowed to change the page author as this user.')));
4804
return(new IXR_Error(401, __('Invalid post type')));
4807
$post_author = $content_struct['wp_author_id'];
4810
if ( isset($content_struct['mt_allow_comments']) ) {
4811
if ( !is_numeric($content_struct['mt_allow_comments']) ) {
4812
switch ( $content_struct['mt_allow_comments'] ) {
4814
$comment_status = 'closed';
4817
$comment_status = 'open';
4820
$comment_status = get_option('default_comment_status');
4824
switch ( (int) $content_struct['mt_allow_comments'] ) {
4827
$comment_status = 'closed';
4830
$comment_status = 'open';
4833
$comment_status = get_option('default_comment_status');
4839
if ( isset($content_struct['mt_allow_pings']) ) {
4840
if ( !is_numeric($content_struct['mt_allow_pings']) ) {
4841
switch ( $content_struct['mt_allow_pings'] ) {
4843
$ping_status = 'closed';
4846
$ping_status = 'open';
4849
$ping_status = get_option('default_ping_status');
4853
switch ( (int) $content_struct["mt_allow_pings"] ) {
4855
$ping_status = 'closed';
4858
$ping_status = 'open';
4861
$ping_status = get_option('default_ping_status');
4867
if ( isset( $content_struct['title'] ) )
4868
$post_title = $content_struct['title'];
4870
if ( isset( $content_struct['description'] ) )
4871
$post_content = $content_struct['description'];
4873
$post_category = array();
4874
if ( isset( $content_struct['categories'] ) ) {
4875
$catnames = $content_struct['categories'];
4876
if ( is_array($catnames) ) {
4877
foreach ($catnames as $cat) {
4878
$post_category[] = get_cat_ID($cat);
4883
if ( isset( $content_struct['mt_excerpt'] ) )
4884
$post_excerpt = $content_struct['mt_excerpt'];
4886
$post_more = isset( $content_struct['mt_text_more'] ) ? $content_struct['mt_text_more'] : null;
4888
$post_status = $publish ? 'publish' : 'draft';
4889
if ( isset( $content_struct["{$post_type}_status"] ) ) {
4890
switch( $content_struct["{$post_type}_status"] ) {
4895
$post_status = $content_struct["{$post_type}_status"];
4898
$post_status = $publish ? 'publish' : 'draft';
4903
$tags_input = isset( $content_struct['mt_keywords'] ) ? $content_struct['mt_keywords'] : null;
4905
if ( ('publish' == $post_status) ) {
4906
if ( ( 'page' == $post_type ) && !current_user_can('publish_pages') )
4907
return new IXR_Error(401, __('Sorry, you do not have the right to publish this page.'));
4908
else if ( !current_user_can('publish_posts') )
4909
return new IXR_Error(401, __('Sorry, you do not have the right to publish this post.'));
4913
$post_content = $post_content . "<!--more-->" . $post_more;
4916
if ( isset( $content_struct['mt_tb_ping_urls'] ) ) {
4917
$to_ping = $content_struct['mt_tb_ping_urls'];
4918
if ( is_array($to_ping) )
4919
$to_ping = implode(' ', $to_ping);
4922
// Do some timestamp voodoo
4923
if ( !empty( $content_struct['date_created_gmt'] ) )
4924
// We know this is supposed to be GMT, so we're going to slap that Z on there by force
4925
$dateCreated = rtrim( $content_struct['date_created_gmt']->getIso(), 'Z' ) . 'Z';
4926
elseif ( !empty( $content_struct['dateCreated']) )
4927
$dateCreated = $content_struct['dateCreated']->getIso();
4929
if ( !empty( $dateCreated ) ) {
4930
$post_date = get_date_from_gmt(iso8601_to_datetime($dateCreated));
4931
$post_date_gmt = iso8601_to_datetime($dateCreated, 'GMT');
4933
$post_date = $postdata['post_date'];
4934
$post_date_gmt = $postdata['post_date_gmt'];
4937
// We've got all the data -- post it:
4938
$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');
4940
$result = wp_update_post($newpost, true);
4941
if ( is_wp_error( $result ) )
4942
return new IXR_Error(500, $result->get_error_message());
4945
return new IXR_Error(500, __('Sorry, your entry could not be edited. Something wrong happened.'));
4947
// Only posts can be sticky
4948
if ( $post_type == 'post' && isset( $content_struct['sticky'] ) ) {
4949
if ( $content_struct['sticky'] == true )
4950
stick_post( $post_ID );
4951
elseif ( $content_struct['sticky'] == false )
4952
unstick_post( $post_ID );
4955
if ( isset($content_struct['custom_fields']) )
4956
$this->set_custom_fields($post_ID, $content_struct['custom_fields']);
4958
if ( isset ( $content_struct['wp_post_thumbnail'] ) ) {
4959
// empty value deletes, non-empty value adds/updates
4960
if ( empty( $content_struct['wp_post_thumbnail'] ) ) {
4961
delete_post_thumbnail( $post_ID );
4963
if ( set_post_thumbnail( $post_ID, $content_struct['wp_post_thumbnail'] ) === false )
4964
return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
4966
unset( $content_struct['wp_post_thumbnail'] );
4969
// Handle enclosures
4970
$thisEnclosure = isset($content_struct['enclosure']) ? $content_struct['enclosure'] : null;
4971
$this->add_enclosure_if_new($post_ID, $thisEnclosure);
4973
$this->attach_uploads( $ID, $post_content );
4975
// Handle post formats if assigned, validation is handled
4976
// earlier in this function
4977
if ( isset( $content_struct['wp_post_format'] ) )
4978
set_post_format( $post_ID, $content_struct['wp_post_format'] );
4981
* Fires after a post has been successfully updated via the XML-RPC MovableType API.
4985
* @param int $post_ID ID of the updated post.
4986
* @param array $args An array of arguments to update the post.
4988
do_action( 'xmlrpc_call_success_mw_editPost', $post_ID, $args );
4998
* @param array $args Method parameters.
5001
public function mw_getPost($args) {
5003
$this->escape($args);
5005
$post_ID = (int) $args[0];
5006
$username = $args[1];
5007
$password = $args[2];
5009
if ( !$user = $this->login($username, $password) )
5010
return $this->error;
5012
$postdata = get_post($post_ID, ARRAY_A);
5014
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
5016
if ( !current_user_can( 'edit_post', $post_ID ) )
5017
return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
5019
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5020
do_action( 'xmlrpc_call', 'metaWeblog.getPost' );
5022
if ($postdata['post_date'] != '') {
5023
$post_date = $this->_convert_date( $postdata['post_date'] );
5024
$post_date_gmt = $this->_convert_date_gmt( $postdata['post_date_gmt'], $postdata['post_date'] );
5025
$post_modified = $this->_convert_date( $postdata['post_modified'] );
5026
$post_modified_gmt = $this->_convert_date_gmt( $postdata['post_modified_gmt'], $postdata['post_modified'] );
5028
$categories = array();
5029
$catids = wp_get_post_categories($post_ID);
5030
foreach($catids as $catid)
5031
$categories[] = get_cat_name($catid);
5033
$tagnames = array();
5034
$tags = wp_get_post_tags( $post_ID );
5035
if ( !empty( $tags ) ) {
5036
foreach ( $tags as $tag )
5037
$tagnames[] = $tag->name;
5038
$tagnames = implode( ', ', $tagnames );
5043
$post = get_extended($postdata['post_content']);
5044
$link = post_permalink($postdata['ID']);
5046
// Get the author info.
5047
$author = get_userdata($postdata['post_author']);
5049
$allow_comments = ('open' == $postdata['comment_status']) ? 1 : 0;
5050
$allow_pings = ('open' == $postdata['ping_status']) ? 1 : 0;
5052
// Consider future posts as published
5053
if ( $postdata['post_status'] === 'future' )
5054
$postdata['post_status'] = 'publish';
5057
$post_format = get_post_format( $post_ID );
5058
if ( empty( $post_format ) )
5059
$post_format = 'standard';
5062
if ( is_sticky( $post_ID ) )
5065
$enclosure = array();
5066
foreach ( (array) get_post_custom($post_ID) as $key => $val) {
5067
if ($key == 'enclosure') {
5068
foreach ( (array) $val as $enc ) {
5069
$encdata = explode("\n", $enc);
5070
$enclosure['url'] = trim(htmlspecialchars($encdata[0]));
5071
$enclosure['length'] = (int) trim($encdata[1]);
5072
$enclosure['type'] = trim($encdata[2]);
5079
'dateCreated' => $post_date,
5080
'userid' => $postdata['post_author'],
5081
'postid' => $postdata['ID'],
5082
'description' => $post['main'],
5083
'title' => $postdata['post_title'],
5085
'permaLink' => $link,
5086
// commented out because no other tool seems to use this
5087
// 'content' => $entry['post_content'],
5088
'categories' => $categories,
5089
'mt_excerpt' => $postdata['post_excerpt'],
5090
'mt_text_more' => $post['extended'],
5091
'wp_more_text' => $post['more_text'],
5092
'mt_allow_comments' => $allow_comments,
5093
'mt_allow_pings' => $allow_pings,
5094
'mt_keywords' => $tagnames,
5095
'wp_slug' => $postdata['post_name'],
5096
'wp_password' => $postdata['post_password'],
5097
'wp_author_id' => (string) $author->ID,
5098
'wp_author_display_name' => $author->display_name,
5099
'date_created_gmt' => $post_date_gmt,
5100
'post_status' => $postdata['post_status'],
5101
'custom_fields' => $this->get_custom_fields($post_ID),
5102
'wp_post_format' => $post_format,
5103
'sticky' => $sticky,
5104
'date_modified' => $post_modified,
5105
'date_modified_gmt' => $post_modified_gmt
5108
if ( !empty($enclosure) ) $resp['enclosure'] = $enclosure;
5110
$resp['wp_post_thumbnail'] = get_post_thumbnail_id( $postdata['ID'] );
5114
return new IXR_Error(404, __('Sorry, no such post.'));
5119
* Retrieve list of recent posts.
5123
* @param array $args Method parameters.
5126
public function mw_getRecentPosts($args) {
5128
$this->escape($args);
5130
$blog_ID = (int) $args[0];
5131
$username = $args[1];
5132
$password = $args[2];
5133
if ( isset( $args[3] ) )
5134
$query = array( 'numberposts' => absint( $args[3] ) );
5138
if ( !$user = $this->login($username, $password) )
5139
return $this->error;
5141
if ( ! current_user_can( 'edit_posts' ) )
5142
return new IXR_Error( 401, __( 'Sorry, you cannot edit posts on this site.' ) );
5144
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5145
do_action( 'xmlrpc_call', 'metaWeblog.getRecentPosts' );
5147
$posts_list = wp_get_recent_posts( $query );
5153
foreach ($posts_list as $entry) {
5154
if ( !current_user_can( 'edit_post', $entry['ID'] ) )
5157
$post_date = $this->_convert_date( $entry['post_date'] );
5158
$post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] );
5159
$post_modified = $this->_convert_date( $entry['post_modified'] );
5160
$post_modified_gmt = $this->_convert_date_gmt( $entry['post_modified_gmt'], $entry['post_modified'] );
5162
$categories = array();
5163
$catids = wp_get_post_categories($entry['ID']);
5164
foreach( $catids as $catid )
5165
$categories[] = get_cat_name($catid);
5167
$tagnames = array();
5168
$tags = wp_get_post_tags( $entry['ID'] );
5169
if ( !empty( $tags ) ) {
5170
foreach ( $tags as $tag ) {
5171
$tagnames[] = $tag->name;
5173
$tagnames = implode( ', ', $tagnames );
5178
$post = get_extended($entry['post_content']);
5179
$link = post_permalink($entry['ID']);
5181
// Get the post author info.
5182
$author = get_userdata($entry['post_author']);
5184
$allow_comments = ('open' == $entry['comment_status']) ? 1 : 0;
5185
$allow_pings = ('open' == $entry['ping_status']) ? 1 : 0;
5187
// Consider future posts as published
5188
if ( $entry['post_status'] === 'future' )
5189
$entry['post_status'] = 'publish';
5192
$post_format = get_post_format( $entry['ID'] );
5193
if ( empty( $post_format ) )
5194
$post_format = 'standard';
5197
'dateCreated' => $post_date,
5198
'userid' => $entry['post_author'],
5199
'postid' => (string) $entry['ID'],
5200
'description' => $post['main'],
5201
'title' => $entry['post_title'],
5203
'permaLink' => $link,
5204
// commented out because no other tool seems to use this
5205
// 'content' => $entry['post_content'],
5206
'categories' => $categories,
5207
'mt_excerpt' => $entry['post_excerpt'],
5208
'mt_text_more' => $post['extended'],
5209
'wp_more_text' => $post['more_text'],
5210
'mt_allow_comments' => $allow_comments,
5211
'mt_allow_pings' => $allow_pings,
5212
'mt_keywords' => $tagnames,
5213
'wp_slug' => $entry['post_name'],
5214
'wp_password' => $entry['post_password'],
5215
'wp_author_id' => (string) $author->ID,
5216
'wp_author_display_name' => $author->display_name,
5217
'date_created_gmt' => $post_date_gmt,
5218
'post_status' => $entry['post_status'],
5219
'custom_fields' => $this->get_custom_fields($entry['ID']),
5220
'wp_post_format' => $post_format,
5221
'date_modified' => $post_modified,
5222
'date_modified_gmt' => $post_modified_gmt,
5223
'sticky' => ( $entry['post_type'] === 'post' && is_sticky( $entry['ID'] ) ),
5226
$entry_index = count( $struct ) - 1;
5227
$struct[ $entry_index ][ 'wp_post_thumbnail' ] = get_post_thumbnail_id( $entry['ID'] );
5230
$recent_posts = array();
5231
for ( $j=0; $j<count($struct); $j++ ) {
5232
array_push($recent_posts, $struct[$j]);
5235
return $recent_posts;
5239
* Retrieve the list of categories on a given blog.
5243
* @param array $args Method parameters.
5246
public function mw_getCategories($args) {
5248
$this->escape($args);
5250
$blog_ID = (int) $args[0];
5251
$username = $args[1];
5252
$password = $args[2];
5254
if ( !$user = $this->login($username, $password) )
5255
return $this->error;
5257
if ( !current_user_can( 'edit_posts' ) )
5258
return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
5260
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5261
do_action( 'xmlrpc_call', 'metaWeblog.getCategories' );
5263
$categories_struct = array();
5265
if ( $cats = get_categories(array('get' => 'all')) ) {
5266
foreach ( $cats as $cat ) {
5267
$struct['categoryId'] = $cat->term_id;
5268
$struct['parentId'] = $cat->parent;
5269
$struct['description'] = $cat->name;
5270
$struct['categoryDescription'] = $cat->description;
5271
$struct['categoryName'] = $cat->name;
5272
$struct['htmlUrl'] = esc_html(get_category_link($cat->term_id));
5273
$struct['rssUrl'] = esc_html(get_category_feed_link($cat->term_id, 'rss2'));
5275
$categories_struct[] = $struct;
5279
return $categories_struct;
5283
* Uploads a file, following your settings.
5285
* Adapted from a patch by Johann Richard.
5287
* @link http://mycvs.org/archives/2004/06/30/file-upload-to-wordpress-in-ecto/
5291
* @param array $args Method parameters.
5294
public function mw_newMediaObject($args) {
5297
$blog_ID = (int) $args[0];
5298
$username = $this->escape($args[1]);
5299
$password = $this->escape($args[2]);
5302
$name = sanitize_file_name( $data['name'] );
5303
$type = $data['type'];
5304
$bits = $data['bits'];
5306
if ( !$user = $this->login($username, $password) )
5307
return $this->error;
5309
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5310
do_action( 'xmlrpc_call', 'metaWeblog.newMediaObject' );
5312
if ( !current_user_can('upload_files') ) {
5313
$this->error = new IXR_Error( 401, __( 'You do not have permission to upload files.' ) );
5314
return $this->error;
5318
* Filter whether to preempt the XML-RPC media upload.
5320
* Passing a truthy value will effectively short-circuit the media upload,
5321
* returning that value as a 500 error instead.
5325
* @param bool $error Whether to pre-empt the media upload. Default false.
5327
if ( $upload_err = apply_filters( 'pre_upload_error', false ) ) {
5328
return new IXR_Error( 500, $upload_err );
5331
if ( !empty($data['overwrite']) && ($data['overwrite'] == true) ) {
5332
// Get postmeta info on the object.
5333
$old_file = $wpdb->get_row("
5336
WHERE post_title = '{$name}'
5337
AND post_type = 'attachment'
5340
// Delete previous file.
5341
wp_delete_attachment($old_file->ID);
5343
// Make sure the new name is different by pre-pending the
5344
// previous post id.
5345
$filename = preg_replace('/^wpid\d+-/', '', $name);
5346
$name = "wpid{$old_file->ID}-{$filename}";
5349
$upload = wp_upload_bits($name, null, $bits);
5350
if ( ! empty($upload['error']) ) {
5351
$errorString = sprintf(__('Could not write file %1$s (%2$s)'), $name, $upload['error']);
5352
return new IXR_Error(500, $errorString);
5354
// Construct the attachment array
5356
if ( ! empty( $data['post_id'] ) ) {
5357
$post_id = (int) $data['post_id'];
5359
if ( ! current_user_can( 'edit_post', $post_id ) )
5360
return new IXR_Error( 401, __( 'Sorry, you cannot edit this post.' ) );
5362
$attachment = array(
5363
'post_title' => $name,
5364
'post_content' => '',
5365
'post_type' => 'attachment',
5366
'post_parent' => $post_id,
5367
'post_mime_type' => $type,
5368
'guid' => $upload[ 'url' ]
5372
$id = wp_insert_attachment( $attachment, $upload[ 'file' ], $post_id );
5373
wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $upload['file'] ) );
5376
* Fires after a new attachment has been added via the XML-RPC MovableType API.
5380
* @param int $id ID of the new attachment.
5381
* @param array $args An array of arguments to add the attachment.
5383
do_action( 'xmlrpc_call_success_mw_newMediaObject', $id, $args );
5386
'id' => strval( $id ),
5388
'url' => $upload[ 'url' ],
5392
/** This filter is documented in wp-admin/includes/file.php */
5393
return apply_filters( 'wp_handle_upload', $struct, 'upload' );
5396
/* MovableType API functions
5397
* specs on http://www.movabletype.org/docs/mtmanual_programmatic.html
5401
* Retrieve the post titles of recent posts.
5405
* @param array $args Method parameters.
5408
public function mt_getRecentPostTitles($args) {
5410
$this->escape($args);
5412
$blog_ID = (int) $args[0];
5413
$username = $args[1];
5414
$password = $args[2];
5415
if ( isset( $args[3] ) )
5416
$query = array( 'numberposts' => absint( $args[3] ) );
5420
if ( !$user = $this->login($username, $password) )
5421
return $this->error;
5423
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5424
do_action( 'xmlrpc_call', 'mt.getRecentPostTitles' );
5426
$posts_list = wp_get_recent_posts( $query );
5428
if ( !$posts_list ) {
5429
$this->error = new IXR_Error(500, __('Either there are no posts, or something went wrong.'));
5430
return $this->error;
5435
foreach ($posts_list as $entry) {
5436
if ( !current_user_can( 'edit_post', $entry['ID'] ) )
5439
$post_date = $this->_convert_date( $entry['post_date'] );
5440
$post_date_gmt = $this->_convert_date_gmt( $entry['post_date_gmt'], $entry['post_date'] );
5443
'dateCreated' => $post_date,
5444
'userid' => $entry['post_author'],
5445
'postid' => (string) $entry['ID'],
5446
'title' => $entry['post_title'],
5447
'post_status' => $entry['post_status'],
5448
'date_created_gmt' => $post_date_gmt
5453
$recent_posts = array();
5454
for ( $j=0; $j<count($struct); $j++ ) {
5455
array_push($recent_posts, $struct[$j]);
5458
return $recent_posts;
5462
* Retrieve list of all categories on blog.
5466
* @param array $args Method parameters.
5469
public function mt_getCategoryList($args) {
5471
$this->escape($args);
5473
$blog_ID = (int) $args[0];
5474
$username = $args[1];
5475
$password = $args[2];
5477
if ( !$user = $this->login($username, $password) )
5478
return $this->error;
5480
if ( !current_user_can( 'edit_posts' ) )
5481
return new IXR_Error( 401, __( 'Sorry, you must be able to edit posts on this site in order to view categories.' ) );
5483
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5484
do_action( 'xmlrpc_call', 'mt.getCategoryList' );
5486
$categories_struct = array();
5488
if ( $cats = get_categories(array('hide_empty' => 0, 'hierarchical' => 0)) ) {
5489
foreach ( $cats as $cat ) {
5490
$struct['categoryId'] = $cat->term_id;
5491
$struct['categoryName'] = $cat->name;
5493
$categories_struct[] = $struct;
5497
return $categories_struct;
5501
* Retrieve post categories.
5505
* @param array $args Method parameters.
5508
public function mt_getPostCategories($args) {
5510
$this->escape($args);
5512
$post_ID = (int) $args[0];
5513
$username = $args[1];
5514
$password = $args[2];
5516
if ( !$user = $this->login($username, $password) )
5517
return $this->error;
5519
if ( ! get_post( $post_ID ) )
5520
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
5522
if ( !current_user_can( 'edit_post', $post_ID ) )
5523
return new IXR_Error( 401, __( 'Sorry, you can not edit this post.' ) );
5525
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5526
do_action( 'xmlrpc_call', 'mt.getPostCategories' );
5528
$categories = array();
5529
$catids = wp_get_post_categories(intval($post_ID));
5530
// first listed category will be the primary category
5532
foreach ( $catids as $catid ) {
5533
$categories[] = array(
5534
'categoryName' => get_cat_name($catid),
5535
'categoryId' => (string) $catid,
5536
'isPrimary' => $isPrimary
5545
* Sets categories for a post.
5549
* @param array $args Method parameters.
5550
* @return bool True on success.
5552
public function mt_setPostCategories($args) {
5554
$this->escape($args);
5556
$post_ID = (int) $args[0];
5557
$username = $args[1];
5558
$password = $args[2];
5559
$categories = $args[3];
5561
if ( !$user = $this->login($username, $password) )
5562
return $this->error;
5564
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5565
do_action( 'xmlrpc_call', 'mt.setPostCategories' );
5567
if ( ! get_post( $post_ID ) )
5568
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
5570
if ( !current_user_can('edit_post', $post_ID) )
5571
return new IXR_Error(401, __('Sorry, you cannot edit this post.'));
5574
foreach ( $categories as $cat ) {
5575
$catids[] = $cat['categoryId'];
5578
wp_set_post_categories($post_ID, $catids);
5584
* Retrieve an array of methods supported by this server.
5588
* @param array $args Method parameters.
5591
public function mt_supportedMethods($args) {
5593
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5594
do_action( 'xmlrpc_call', 'mt.supportedMethods' );
5596
$supported_methods = array();
5597
foreach ( $this->methods as $key => $value ) {
5598
$supported_methods[] = $key;
5601
return $supported_methods;
5605
* Retrieve an empty array because we don't support per-post text filters.
5609
* @param array $args Method parameters.
5611
public function mt_supportedTextFilters($args) {
5612
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5613
do_action( 'xmlrpc_call', 'mt.supportedTextFilters' );
5616
* Filter the MoveableType text filters list for XML-RPC.
5620
* @param array $filters An array of text filters.
5622
return apply_filters( 'xmlrpc_text_filters', array() );
5626
* Retrieve trackbacks sent to a given post.
5630
* @param array $args Method parameters.
5633
public function mt_getTrackbackPings($args) {
5637
$post_ID = intval($args);
5639
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5640
do_action( 'xmlrpc_call', 'mt.getTrackbackPings' );
5642
$actual_post = get_post($post_ID, ARRAY_A);
5644
if ( !$actual_post )
5645
return new IXR_Error(404, __('Sorry, no such post.'));
5647
$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) );
5652
$trackback_pings = array();
5653
foreach ( $comments as $comment ) {
5654
if ( 'trackback' == $comment->comment_type ) {
5655
$content = $comment->comment_content;
5656
$title = substr($content, 8, (strpos($content, '</strong>') - 8));
5657
$trackback_pings[] = array(
5658
'pingTitle' => $title,
5659
'pingURL' => $comment->comment_author_url,
5660
'pingIP' => $comment->comment_author_IP
5665
return $trackback_pings;
5669
* Sets a post's publish status to 'publish'.
5673
* @param array $args Method parameters.
5676
public function mt_publishPost($args) {
5678
$this->escape($args);
5680
$post_ID = (int) $args[0];
5681
$username = $args[1];
5682
$password = $args[2];
5684
if ( !$user = $this->login($username, $password) )
5685
return $this->error;
5687
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5688
do_action( 'xmlrpc_call', 'mt.publishPost' );
5690
$postdata = get_post($post_ID, ARRAY_A);
5692
return new IXR_Error( 404, __( 'Invalid post ID.' ) );
5694
if ( !current_user_can('publish_posts') || !current_user_can('edit_post', $post_ID) )
5695
return new IXR_Error(401, __('Sorry, you cannot publish this post.'));
5697
$postdata['post_status'] = 'publish';
5700
$cats = wp_get_post_categories($post_ID);
5701
$postdata['post_category'] = $cats;
5702
$this->escape($postdata);
5704
$result = wp_update_post($postdata);
5709
/* PingBack functions
5710
* specs on www.hixie.ch/specs/pingback/pingback
5714
* Retrieves a pingback and registers it.
5718
* @param array $args Method parameters.
5721
public function pingback_ping($args) {
5724
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5725
do_action( 'xmlrpc_call', 'pingback.ping' );
5727
$this->escape($args);
5729
$pagelinkedfrom = $args[0];
5730
$pagelinkedto = $args[1];
5734
$pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom);
5735
$pagelinkedto = str_replace('&', '&', $pagelinkedto);
5736
$pagelinkedto = str_replace('&', '&', $pagelinkedto);
5739
* Filter the pingback source URI.
5743
* @param string $pagelinkedfrom URI of the page linked from.
5744
* @param string $pagelinkedto URI of the page linked to.
5746
$pagelinkedfrom = apply_filters( 'pingback_ping_source_uri', $pagelinkedfrom, $pagelinkedto );
5748
if ( ! $pagelinkedfrom )
5749
return $this->pingback_error( 0, __( 'A valid URL was not provided.' ) );
5751
// Check if the page linked to is in our site
5752
$pos1 = strpos($pagelinkedto, str_replace(array('http://www.','http://','https://www.','https://'), '', get_option('home')));
5754
return $this->pingback_error( 0, __( 'Is there no link to us?' ) );
5756
// let's find which post is linked to
5757
// FIXME: does url_to_postid() cover all these cases already?
5758
// if so, then let's use it and drop the old code.
5759
$urltest = parse_url($pagelinkedto);
5760
if ( $post_ID = url_to_postid($pagelinkedto) ) {
5761
$way = 'url_to_postid()';
5762
} elseif ( isset( $urltest['path'] ) && preg_match('#p/[0-9]{1,}#', $urltest['path'], $match) ) {
5763
// the path defines the post_ID (archives/p/XXXX)
5764
$blah = explode('/', $match[0]);
5765
$post_ID = (int) $blah[1];
5766
$way = 'from the path';
5767
} elseif ( isset( $urltest['query'] ) && preg_match('#p=[0-9]{1,}#', $urltest['query'], $match) ) {
5768
// the querystring defines the post_ID (?p=XXXX)
5769
$blah = explode('=', $match[0]);
5770
$post_ID = (int) $blah[1];
5771
$way = 'from the querystring';
5772
} elseif ( isset($urltest['fragment']) ) {
5773
// an #anchor is there, it's either...
5774
if ( intval($urltest['fragment']) ) {
5775
// ...an integer #XXXX (simplest case)
5776
$post_ID = (int) $urltest['fragment'];
5777
$way = 'from the fragment (numeric)';
5778
} elseif ( preg_match('/post-[0-9]+/',$urltest['fragment']) ) {
5779
// ...a post id in the form 'post-###'
5780
$post_ID = preg_replace('/[^0-9]+/', '', $urltest['fragment']);
5781
$way = 'from the fragment (post-###)';
5782
} elseif ( is_string($urltest['fragment']) ) {
5783
// ...or a string #title, a little more complicated
5784
$title = preg_replace('/[^a-z0-9]/i', '.', $urltest['fragment']);
5785
$sql = $wpdb->prepare("SELECT ID FROM $wpdb->posts WHERE post_title RLIKE %s", $title );
5786
if (! ($post_ID = $wpdb->get_var($sql)) ) {
5787
// returning unknown error '0' is better than die()ing
5788
return $this->pingback_error( 0, '' );
5790
$way = 'from the fragment (title)';
5793
// TODO: Attempt to extract a post ID from the given URL
5794
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.' ) );
5796
$post_ID = (int) $post_ID;
5798
$post = get_post($post_ID);
5800
if ( !$post ) // Post_ID not found
5801
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.' ) );
5803
if ( $post_ID == url_to_postid($pagelinkedfrom) )
5804
return $this->pingback_error( 0, __( 'The source URL and the target URL cannot both point to the same resource.' ) );
5806
// Check if pings are on
5807
if ( !pings_open($post) )
5808
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.' ) );
5810
// Let's check that the remote site didn't already pingback this entry
5811
if ( $wpdb->get_results( $wpdb->prepare("SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_author_url = %s", $post_ID, $pagelinkedfrom) ) )
5812
return $this->pingback_error( 48, __( 'The pingback has already been registered.' ) );
5814
// very stupid, but gives time to the 'from' server to publish !
5817
$remote_ip = preg_replace( '/[^0-9a-fA-F:., ]/', '', $_SERVER['REMOTE_ADDR'] );
5819
/** This filter is documented in wp-includes/class-http.php */
5820
$user_agent = apply_filters( 'http_headers_useragent', 'WordPress/' . $GLOBALS['wp_version'] . '; ' . get_bloginfo( 'url' ) );
5822
// Let's check the remote site
5823
$http_api_args = array(
5826
'limit_response_size' => 153600, // 150 KB
5827
'user-agent' => "$user_agent; verifying pingback from $remote_ip",
5829
'X-Pingback-Forwarded-For' => $remote_ip,
5832
$request = wp_safe_remote_get( $pagelinkedfrom, $http_api_args );
5833
$linea = wp_remote_retrieve_body( $request );
5836
return $this->pingback_error( 16, __( 'The source URL does not exist.' ) );
5839
* Filter the pingback remote source.
5843
* @param string $linea Response object for the page linked from.
5844
* @param string $pagelinkedto URL of the page linked to.
5846
$linea = apply_filters( 'pre_remote_source', $linea, $pagelinkedto );
5848
// Work around bug in strip_tags():
5849
$linea = str_replace('<!DOC', '<DOC', $linea);
5850
$linea = preg_replace( '/[\r\n\t ]+/', ' ', $linea ); // normalize spaces
5851
$linea = preg_replace( "/<\/*(h1|h2|h3|h4|h5|h6|p|th|td|li|dt|dd|pre|caption|input|textarea|button|body)[^>]*>/", "\n\n", $linea );
5853
preg_match('|<title>([^<]*?)</title>|is', $linea, $matchtitle);
5854
$title = $matchtitle[1];
5855
if ( empty( $title ) )
5856
return $this->pingback_error( 32, __('We cannot find a title on that page.' ) );
5858
$linea = strip_tags( $linea, '<a>' ); // just keep the tag we need
5860
$p = explode( "\n\n", $linea );
5862
$preg_target = preg_quote($pagelinkedto, '|');
5864
foreach ( $p as $para ) {
5865
if ( strpos($para, $pagelinkedto) !== false ) { // it exists, but is it a link?
5866
preg_match("|<a[^>]+?".$preg_target."[^>]*>([^>]+?)</a>|", $para, $context);
5868
// If the URL isn't in a link context, keep looking
5869
if ( empty($context) )
5872
// We're going to use this fake tag to mark the context in a bit
5873
// the marker is needed in case the link text appears more than once in the paragraph
5874
$excerpt = preg_replace('|\</?wpcontext\>|', '', $para);
5876
// prevent really long link text
5877
if ( strlen($context[1]) > 100 )
5878
$context[1] = substr($context[1], 0, 100) . '…';
5880
$marker = '<wpcontext>'.$context[1].'</wpcontext>'; // set up our marker
5881
$excerpt= str_replace($context[0], $marker, $excerpt); // swap out the link for our marker
5882
$excerpt = strip_tags($excerpt, '<wpcontext>'); // strip all tags but our context marker
5883
$excerpt = trim($excerpt);
5884
$preg_marker = preg_quote($marker, '|');
5885
$excerpt = preg_replace("|.*?\s(.{0,100}$preg_marker.{0,100})\s.*|s", '$1', $excerpt);
5886
$excerpt = strip_tags($excerpt); // YES, again, to remove the marker wrapper
5891
if ( empty($context) ) // Link to target not found
5892
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.' ) );
5894
$pagelinkedfrom = str_replace('&', '&', $pagelinkedfrom);
5896
$context = '[…] ' . esc_html( $excerpt ) . ' […]';
5897
$pagelinkedfrom = $this->escape( $pagelinkedfrom );
5899
$comment_post_ID = (int) $post_ID;
5900
$comment_author = $title;
5901
$comment_author_email = '';
5902
$this->escape($comment_author);
5903
$comment_author_url = $pagelinkedfrom;
5904
$comment_content = $context;
5905
$this->escape($comment_content);
5906
$comment_type = 'pingback';
5908
$commentdata = compact('comment_post_ID', 'comment_author', 'comment_author_url', 'comment_author_email', 'comment_content', 'comment_type');
5910
$comment_ID = wp_new_comment($commentdata);
5913
* Fires after a post pingback has been sent.
5917
* @param int $comment_ID Comment ID.
5919
do_action( 'pingback_post', $comment_ID );
5921
return sprintf(__('Pingback from %1$s to %2$s registered. Keep the web talking! :-)'), $pagelinkedfrom, $pagelinkedto);
5925
* Retrieve array of URLs that pingbacked the given URL.
5927
* Specs on http://www.aquarionics.com/misc/archives/blogite/0198.html
5931
* @param array $args Method parameters.
5934
public function pingback_extensions_getPingbacks($args) {
5938
/** This action is documented in wp-includes/class-wp-xmlrpc-server.php */
5939
do_action( 'xmlrpc_call', 'pingback.extensions.getPingbacks' );
5941
$this->escape($args);
5945
$post_ID = url_to_postid($url);
5947
// We aren't sure that the resource is available and/or pingback enabled
5948
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.' ) );
5951
$actual_post = get_post($post_ID, ARRAY_A);
5953
if ( !$actual_post ) {
5954
// No such post = resource not found
5955
return $this->pingback_error( 32, __('The specified target URL does not exist.' ) );
5958
$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) );
5963
$pingbacks = array();
5964
foreach ( $comments as $comment ) {
5965
if ( 'pingback' == $comment->comment_type )
5966
$pingbacks[] = $comment->comment_author_url;
5972
protected function pingback_error( $code, $message ) {
5974
* Filter the XML-RPC pingback error return.
5978
* @param IXR_Error $error An IXR_Error object containing the error code and message.
5980
return apply_filters( 'xmlrpc_pingback_error', new IXR_Error( $code, $message ) );