: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
if ( current_user_can( 'edit_term_meta', $term_id ) ) {
update_metadata_by_mid( 'term', $meta['id'], $meta['value'] );
} elseif ( current_user_can( 'delete_term_meta', $term_id ) ) {
delete_metadata_by_mid( 'term', $meta['id'] );
} elseif ( current_user_can( 'add_term_meta', $term_id ) ) {
add_term_meta( $term_id, $meta['key'], $meta['value'] );
* Sets up blog options property.
* Passes property through {@see 'xmlrpc_blog_options'} filter.
public function initialise_blog_option_info() {
$this->blog_options = array(
'software_name' => array(
'desc' => __( 'Software Name' ),
'software_version' => array(
'desc' => __( 'Software Version' ),
'value' => get_bloginfo( 'version' ),
'desc' => __( 'WordPress Address (URL)' ),
'desc' => __( 'Site Address (URL)' ),
'desc' => __( 'Login Address (URL)' ),
'value' => wp_login_url(),
'desc' => __( 'The URL to the admin area' ),
'value' => get_admin_url(),
'image_default_link_type' => array(
'desc' => __( 'Image default link type' ),
'option' => 'image_default_link_type',
'image_default_size' => array(
'desc' => __( 'Image default size' ),
'option' => 'image_default_size',
'image_default_align' => array(
'desc' => __( 'Image default align' ),
'option' => 'image_default_align',
'desc' => __( 'Template' ),
'desc' => __( 'Stylesheet' ),
'option' => 'stylesheet',
'post_thumbnail' => array(
'desc' => __( 'Post Thumbnail' ),
'value' => current_theme_supports( 'post-thumbnails' ),
'desc' => __( 'Time Zone' ),
'option' => 'gmt_offset',
'desc' => __( 'Site Title' ),
'desc' => __( 'Site Tagline' ),
'option' => 'blogdescription',
'desc' => __( 'Date Format' ),
'option' => 'date_format',
'desc' => __( 'Time Format' ),
'option' => 'time_format',
'users_can_register' => array(
'desc' => __( 'Allow new users to sign up' ),
'option' => 'users_can_register',
'thumbnail_size_w' => array(
'desc' => __( 'Thumbnail Width' ),
'option' => 'thumbnail_size_w',
'thumbnail_size_h' => array(
'desc' => __( 'Thumbnail Height' ),
'option' => 'thumbnail_size_h',
'thumbnail_crop' => array(
'desc' => __( 'Crop thumbnail to exact dimensions' ),
'option' => 'thumbnail_crop',
'medium_size_w' => array(
'desc' => __( 'Medium size image width' ),
'option' => 'medium_size_w',
'medium_size_h' => array(
'desc' => __( 'Medium size image height' ),
'option' => 'medium_size_h',
'medium_large_size_w' => array(
'desc' => __( 'Medium-Large size image width' ),
'option' => 'medium_large_size_w',
'medium_large_size_h' => array(
'desc' => __( 'Medium-Large size image height' ),
'option' => 'medium_large_size_h',
'desc' => __( 'Large size image width' ),
'option' => 'large_size_w',
'desc' => __( 'Large size image height' ),
'option' => 'large_size_h',
'default_comment_status' => array(
'desc' => __( 'Allow people to submit comments on new posts.' ),
'option' => 'default_comment_status',
'default_ping_status' => array(
'desc' => __( 'Allow link notifications from other blogs (pingbacks and trackbacks) on new posts.' ),
'option' => 'default_ping_status',
* Filters the XML-RPC blog options property.
* @param array $blog_options An array of XML-RPC blog options.
$this->blog_options = apply_filters( 'xmlrpc_blog_options', $this->blog_options );
* Retrieves the blogs of the user.
* Method arguments. Note: arguments must be ordered as documented.
* @type string $0 Username.
* @type string $1 Password.
* @return array|IXR_Error Array contains:
* - 'isPrimary' - whether the blog is the user's primary blog
* - 'xmlrpc' - url of xmlrpc endpoint
public function wp_getUsersBlogs( $args ) {
if ( ! $this->minimum_args( $args, 2 ) ) {
// If this isn't on WPMU then just use blogger_getUsersBlogs().
if ( ! is_multisite() ) {
array_unshift( $args, 1 );
return $this->blogger_getUsersBlogs( $args );
$user = $this->login( $username, $password );
* Fires after the XML-RPC user has been authenticated but before the rest of
* the method logic begins.
* All built-in XML-RPC methods use the action xmlrpc_call, with a parameter
* equal to the method's name, e.g., wp.getUsersBlogs, wp.newPost, etc.
* @since 5.7.0 Added the `$args` and `$server` parameters.
* @param string $name The method name.
* @param array|string $args The escaped arguments passed to the method.
* @param wp_xmlrpc_server $server The XML-RPC server instance.
do_action( 'xmlrpc_call', 'wp.getUsersBlogs', $args, $this );
$blogs = (array) get_blogs_of_user( $user->ID );
$active_blog = get_active_blog_for_user( $user->ID );
$primary_blog_id = (int) $active_blog->blog_id;
foreach ( $blogs as $blog ) {
// Don't include blogs that aren't hosted at this site.
if ( get_current_network_id() != $blog->site_id ) {
$blog_id = $blog->userblog_id;
switch_to_blog( $blog_id );
$is_admin = current_user_can( 'manage_options' );
$is_primary = ( (int) $blog_id === $primary_blog_id );
'isPrimary' => $is_primary,
'url' => home_url( '/' ),
'blogid' => (string) $blog_id,
'blogName' => get_option( 'blogname' ),
'xmlrpc' => site_url( 'xmlrpc.php', 'rpc' ),
* Checks if the method received at least the minimum number of arguments.
* @param array $args An array of arguments to check.
* @param int $count Minimum number of arguments.
* @return bool True if `$args` contains at least `$count` arguments, false otherwise.
protected function minimum_args( $args, $count ) {
if ( ! is_array( $args ) || count( $args ) < $count ) {
$this->error = new IXR_Error( 400, __( 'Insufficient arguments passed to this XML-RPC method.' ) );
* Prepares taxonomy data for return in an XML-RPC object.
* @param WP_Taxonomy $taxonomy The unprepared taxonomy data.
* @param array $fields The subset of taxonomy fields to return.
* @return array The prepared taxonomy data.
protected function _prepare_taxonomy( $taxonomy, $fields ) {
'name' => $taxonomy->name,
'label' => $taxonomy->label,
'hierarchical' => (bool) $taxonomy->hierarchical,
'public' => (bool) $taxonomy->public,
'show_ui' => (bool) $taxonomy->show_ui,
'_builtin' => (bool) $taxonomy->_builtin,
if ( in_array( 'labels', $fields, true ) ) {
$_taxonomy['labels'] = (array) $taxonomy->labels;
if ( in_array( 'cap', $fields, true ) ) {
$_taxonomy['cap'] = (array) $taxonomy->cap;
if ( in_array( 'menu', $fields, true ) ) {
$_taxonomy['show_in_menu'] = (bool) $taxonomy->show_in_menu;
if ( in_array( 'object_type', $fields, true ) ) {
$_taxonomy['object_type'] = array_unique( (array) $taxonomy->object_type );
* Filters XML-RPC-prepared data for the given taxonomy.
* @param array $_taxonomy An array of taxonomy data.
* @param WP_Taxonomy $taxonomy Taxonomy object.
* @param array $fields The subset of taxonomy fields to return.
return apply_filters( 'xmlrpc_prepare_taxonomy', $_taxonomy, $taxonomy, $fields );
* Prepares term data for return in an XML-RPC object.
* @param array|object $term The unprepared term data.
* @return array The prepared term data.
protected function _prepare_term( $term ) {
if ( ! is_array( $_term ) ) {
$_term = get_object_vars( $_term );
// For integers which may be larger than XML-RPC supports ensure we return strings.
$_term['term_id'] = (string) $_term['term_id'];
$_term['term_group'] = (string) $_term['term_group'];
$_term['term_taxonomy_id'] = (string) $_term['term_taxonomy_id'];
$_term['parent'] = (string) $_term['parent'];
// Count we are happy to return as an integer because people really shouldn't use terms that much.
$_term['count'] = (int) $_term['count'];
$_term['custom_fields'] = $this->get_term_custom_fields( $_term['term_id'] );
* Filters XML-RPC-prepared data for the given term.
* @param array $_term An array of term data.
* @param array|object $term Term object or array.
return apply_filters( 'xmlrpc_prepare_term', $_term, $term );
* Converts a WordPress date string to an IXR_Date object.
* @param string $date Date string to convert.
* @return IXR_Date IXR_Date object.
protected function _convert_date( $date ) {
if ( '0000-00-00 00:00:00' === $date ) {
return new IXR_Date( '00000000T00:00:00Z' );
return new IXR_Date( mysql2date( 'Ymd\TH:i:s', $date, false ) );
* Converts a WordPress GMT date string to an IXR_Date object.
* @param string $date_gmt WordPress GMT date string.
* @param string $date Date string.
* @return IXR_Date IXR_Date object.
protected function _convert_date_gmt( $date_gmt, $date ) {
if ( '0000-00-00 00:00:00' !== $date && '0000-00-00 00:00:00' === $date_gmt ) {
return new IXR_Date( get_gmt_from_date( mysql2date( 'Y-m-d H:i:s', $date, false ), 'Ymd\TH:i:s' ) );
return $this->_convert_date( $date_gmt );
* Prepares post data for return in an XML-RPC object.
* @param array $post The unprepared post data.
* @param array $fields The subset of post type fields to return.
* @return array The prepared post data.
protected function _prepare_post( $post, $fields ) {
// Holds the data for this post. built up based on $fields.
$_post = array( 'post_id' => (string) $post['ID'] );
// Prepare common post fields.
'post_title' => $post['post_title'],
'post_date' => $this->_convert_date( $post['post_date'] ),
'post_date_gmt' => $this->_convert_date_gmt( $post['post_date_gmt'], $post['post_date'] ),
'post_modified' => $this->_convert_date( $post['post_modified'] ),
'post_modified_gmt' => $this->_convert_date_gmt( $post['post_modified_gmt'], $post['post_modified'] ),
'post_status' => $post['post_status'],
'post_type' => $post['post_type'],
'post_name' => $post['post_name'],
'post_author' => $post['post_author'],
'post_password' => $post['post_password'],
'post_excerpt' => $post['post_excerpt'],
'post_content' => $post['post_content'],
'post_parent' => (string) $post['post_parent'],
'post_mime_type' => $post['post_mime_type'],
'link' => get_permalink( $post['ID'] ),
'menu_order' => (int) $post['menu_order'],
'comment_status' => $post['comment_status'],
'ping_status' => $post['ping_status'],
'sticky' => ( 'post' === $post['post_type'] && is_sticky( $post['ID'] ) ),
$post_fields['post_thumbnail'] = array();
$thumbnail_id = get_post_thumbnail_id( $post['ID'] );
$thumbnail_size = current_theme_supports( 'post-thumbnail' ) ? 'post-thumbnail' : 'thumbnail';
$post_fields['post_thumbnail'] = $this->_prepare_media_item( get_post( $thumbnail_id ), $thumbnail_size );
// Consider future posts as published.
if ( 'future' === $post_fields['post_status'] ) {
$post_fields['post_status'] = 'publish';
// Fill in blank post format.
$post_fields['post_format'] = get_post_format( $post['ID'] );
if ( empty( $post_fields['post_format'] ) ) {
$post_fields['post_format'] = 'standard';
// Merge requested $post_fields fields into $_post.
if ( in_array( 'post', $fields, true ) ) {
$_post = array_merge( $_post, $post_fields );
$requested_fields = array_intersect_key( $post_fields, array_flip( $fields ) );
$_post = array_merge( $_post, $requested_fields );
$all_taxonomy_fields = in_array( 'taxonomies', $fields, true );
if ( $all_taxonomy_fields || in_array( 'terms', $fields, true ) ) {
$post_type_taxonomies = get_object_taxonomies( $post['post_type'], 'names' );
$terms = wp_get_object_terms( $post['ID'], $post_type_taxonomies );
$_post['terms'] = array();
foreach ( $terms as $term ) {
$_post['terms'][] = $this->_prepare_term( $term );
if ( in_array( 'custom_fields', $fields, true ) ) {
$_post['custom_fields'] = $this->get_custom_fields( $post['ID'] );
if ( in_array( 'enclosure', $fields, true ) ) {
$_post['enclosure'] = array();
$enclosures = (array) get_post_meta( $post['ID'], 'enclosure' );
if ( ! empty( $enclosures ) ) {
$encdata = explode( "\n", $enclosures[0] );
$_post['enclosure']['url'] = trim( htmlspecialchars( $encdata[0] ) );
$_post['enclosure']['length'] = (int) trim( $encdata[1] );
$_post['enclosure']['type'] = trim( $encdata[2] );
* Filters XML-RPC-prepared date for the given post.
* @param array $_post An array of modified post data.
* @param array $post An array of post data.
* @param array $fields An array of post fields.
return apply_filters( 'xmlrpc_prepare_post', $_post, $post, $fields );
* Prepares post data for return in an XML-RPC object.