wp_xmlrpc_server::_insert_post( WP_User $user, array|IXR_Error $content_struct ): IXR_Error|string

Helper method for wp_newPost() and wp_editPost(), containing shared logic.

Description

See also

Parameters

$userWP_Userrequired
The post author if post_author isn’t set in $content_struct.
$content_structarray|IXR_Errorrequired
Post data to insert.

Return

IXR_Error|string

Source

protected function _insert_post( $user, $content_struct ) {
	$defaults = array(
		'post_status'    => 'draft',
		'post_type'      => 'post',
		'post_author'    => 0,
		'post_password'  => '',
		'post_excerpt'   => '',
		'post_content'   => '',
		'post_title'     => '',
		'post_date'      => '',
		'post_date_gmt'  => '',
		'post_format'    => null,
		'post_name'      => null,
		'post_thumbnail' => null,
		'post_parent'    => 0,
		'ping_status'    => '',
		'comment_status' => '',
		'custom_fields'  => null,
		'terms_names'    => null,
		'terms'          => null,
		'sticky'         => null,
		'enclosure'      => null,
		'ID'             => null,
	);

	$post_data = wp_parse_args( array_intersect_key( $content_struct, $defaults ), $defaults );

	$post_type = get_post_type_object( $post_data['post_type'] );
	if ( ! $post_type ) {
		return new IXR_Error( 403, __( 'Invalid post type.' ) );
	}

	$update = ! empty( $post_data['ID'] );

	if ( $update ) {
		if ( ! get_post( $post_data['ID'] ) ) {
			return new IXR_Error( 401, __( 'Invalid post ID.' ) );
		}
		if ( ! current_user_can( 'edit_post', $post_data['ID'] ) ) {
			return new IXR_Error( 401, __( 'Sorry, you are not allowed to edit this post.' ) );
		}
		if ( get_post_type( $post_data['ID'] ) !== $post_data['post_type'] ) {
			return new IXR_Error( 401, __( 'The post type may not be changed.' ) );
		}
	} else {
		if ( ! current_user_can( $post_type->cap->create_posts ) || ! current_user_can( $post_type->cap->edit_posts ) ) {
			return new IXR_Error( 401, __( 'Sorry, you are not allowed to post on this site.' ) );
		}
	}

	switch ( $post_data['post_status'] ) {
		case 'draft':
		case 'pending':
			break;
		case 'private':
			if ( ! current_user_can( $post_type->cap->publish_posts ) ) {
				return new IXR_Error( 401, __( 'Sorry, you are not allowed to create private posts in this post type.' ) );
			}
			break;
		case 'publish':
		case 'future':
			if ( ! current_user_can( $post_type->cap->publish_posts ) ) {
				return new IXR_Error( 401, __( 'Sorry, you are not allowed to publish posts in this post type.' ) );
			}
			break;
		default:
			if ( ! get_post_status_object( $post_data['post_status'] ) ) {
				$post_data['post_status'] = 'draft';
			}
			break;
	}

	if ( ! empty( $post_data['post_password'] ) && ! current_user_can( $post_type->cap->publish_posts ) ) {
		return new IXR_Error( 401, __( 'Sorry, you are not allowed to create password protected posts in this post type.' ) );
	}

	$post_data['post_author'] = absint( $post_data['post_author'] );
	if ( ! empty( $post_data['post_author'] ) && $post_data['post_author'] != $user->ID ) {
		if ( ! current_user_can( $post_type->cap->edit_others_posts ) ) {
			return new IXR_Error( 401, __( 'Sorry, you are not allowed to create posts as this user.' ) );
		}

		$author = get_userdata( $post_data['post_author'] );

		if ( ! $author ) {
			return new IXR_Error( 404, __( 'Invalid author ID.' ) );
		}
	} else {
		$post_data['post_author'] = $user->ID;
	}

	if ( 'open' !== $post_data['comment_status'] && 'closed' !== $post_data['comment_status'] ) {
		unset( $post_data['comment_status'] );
	}

	if ( 'open' !== $post_data['ping_status'] && 'closed' !== $post_data['ping_status'] ) {
		unset( $post_data['ping_status'] );
	}

	// Do some timestamp voodoo.
	if ( ! empty( $post_data['post_date_gmt'] ) ) {
		// We know this is supposed to be GMT, so we're going to slap that Z on there by force.
		$dateCreated = rtrim( $post_data['post_date_gmt']->getIso(), 'Z' ) . 'Z';
	} elseif ( ! empty( $post_data['post_date'] ) ) {
		$dateCreated = $post_data['post_date']->getIso();
	}

	// Default to not flagging the post date to be edited unless it's intentional.
	$post_data['edit_date'] = false;

	if ( ! empty( $dateCreated ) ) {
		$post_data['post_date']     = iso8601_to_datetime( $dateCreated );
		$post_data['post_date_gmt'] = iso8601_to_datetime( $dateCreated, 'gmt' );

		// Flag the post date to be edited.
		$post_data['edit_date'] = true;
	}

	if ( ! isset( $post_data['ID'] ) ) {
		$post_data['ID'] = get_default_post_to_edit( $post_data['post_type'], true )->ID;
	}
	$post_id = $post_data['ID'];

	if ( 'post' === $post_data['post_type'] ) {
		$error = $this->_toggle_sticky( $post_data, $update );
		if ( $error ) {
			return $error;
		}
	}

	if ( isset( $post_data['post_thumbnail'] ) ) {
		// Empty value deletes, non-empty value adds/updates.
		if ( ! $post_data['post_thumbnail'] ) {
			delete_post_thumbnail( $post_id );
		} elseif ( ! get_post( absint( $post_data['post_thumbnail'] ) ) ) {
			return new IXR_Error( 404, __( 'Invalid attachment ID.' ) );
		}
		set_post_thumbnail( $post_id, $post_data['post_thumbnail'] );
		unset( $content_struct['post_thumbnail'] );
	}

	if ( isset( $post_data['custom_fields'] ) ) {
		$this->set_custom_fields( $post_id, $post_data['custom_fields'] );
	}

	if ( isset( $post_data['terms'] ) || isset( $post_data['terms_names'] ) ) {
		$post_type_taxonomies = get_object_taxonomies( $post_data['post_type'], 'objects' );

		// Accumulate term IDs from terms and terms_names.
		$terms = array();

		// First validate the terms specified by ID.
		if ( isset( $post_data['terms'] ) && is_array( $post_data['terms'] ) ) {
			$taxonomies = array_keys( $post_data['terms'] );

			// Validating term IDs.
			foreach ( $taxonomies as $taxonomy ) {
				if ( ! array_key_exists( $taxonomy, $post_type_taxonomies ) ) {
					return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
				}

				if ( ! current_user_can( $post_type_taxonomies[ $taxonomy ]->cap->assign_terms ) ) {
					return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
				}

				$term_ids           = $post_data['terms'][ $taxonomy ];
				$terms[ $taxonomy ] = array();
				foreach ( $term_ids as $term_id ) {
					$term = get_term_by( 'id', $term_id, $taxonomy );

					if ( ! $term ) {
						return new IXR_Error( 403, __( 'Invalid term ID.' ) );
					}

					$terms[ $taxonomy ][] = (int) $term_id;
				}
			}
		}

		// Now validate terms specified by name.
		if ( isset( $post_data['terms_names'] ) && is_array( $post_data['terms_names'] ) ) {
			$taxonomies = array_keys( $post_data['terms_names'] );

			foreach ( $taxonomies as $taxonomy ) {
				if ( ! array_key_exists( $taxonomy, $post_type_taxonomies ) ) {
					return new IXR_Error( 401, __( 'Sorry, one of the given taxonomies is not supported by the post type.' ) );
				}

				if ( ! current_user_can( $post_type_taxonomies[ $taxonomy ]->cap->assign_terms ) ) {
					return new IXR_Error( 401, __( 'Sorry, you are not allowed to assign a term to one of the given taxonomies.' ) );
				}

				/*
				 * For hierarchical taxonomies, we can't assign a term when multiple terms
				 * in the hierarchy share the same name.
				 */
				$ambiguous_terms = array();
				if ( is_taxonomy_hierarchical( $taxonomy ) ) {
					$tax_term_names = get_terms(
						array(
							'taxonomy'   => $taxonomy,
							'fields'     => 'names',
							'hide_empty' => false,
						)
					);

					// Count the number of terms with the same name.
					$tax_term_names_count = array_count_values( $tax_term_names );

					// Filter out non-ambiguous term names.
					$ambiguous_tax_term_counts = array_filter( $tax_term_names_count, array( $this, '_is_greater_than_one' ) );

					$ambiguous_terms = array_keys( $ambiguous_tax_term_counts );
				}

				$term_names = $post_data['terms_names'][ $taxonomy ];
				foreach ( $term_names as $term_name ) {
					if ( in_array( $term_name, $ambiguous_terms, true ) ) {
						return new IXR_Error( 401, __( 'Ambiguous term name used in a hierarchical taxonomy. Please use term ID instead.' ) );
					}

					$term = get_term_by( 'name', $term_name, $taxonomy );

					if ( ! $term ) {
						// Term doesn't exist, so check that the user is allowed to create new terms.
						if ( ! current_user_can( $post_type_taxonomies[ $taxonomy ]->cap->edit_terms ) ) {
							return new IXR_Error( 401, __( 'Sorry, you are not allowed to add a term to one of the given taxonomies.' ) );
						}

						// Create the new term.
						$term_info = wp_insert_term( $term_name, $taxonomy );
						if ( is_wp_error( $term_info ) ) {
							return new IXR_Error( 500, $term_info->get_error_message() );
						}

						$terms[ $taxonomy ][] = (int) $term_info['term_id'];
					} else {
						$terms[ $taxonomy ][] = (int) $term->term_id;
					}
				}
			}
		}

		$post_data['tax_input'] = $terms;
		unset( $post_data['terms'], $post_data['terms_names'] );
	}

	if ( isset( $post_data['post_format'] ) ) {
		$format = set_post_format( $post_id, $post_data['post_format'] );

		if ( is_wp_error( $format ) ) {
			return new IXR_Error( 500, $format->get_error_message() );
		}

		unset( $post_data['post_format'] );
	}

	// Handle enclosures.
	$enclosure = isset( $post_data['enclosure'] ) ? $post_data['enclosure'] : null;
	$this->add_enclosure_if_new( $post_id, $enclosure );

	$this->attach_uploads( $post_id, $post_data['post_content'] );

	/**
	 * Filters post data array to be inserted via XML-RPC.
	 *
	 * @since 3.4.0
	 *
	 * @param array $post_data      Parsed array of post data.
	 * @param array $content_struct Post data array.
	 */
	$post_data = apply_filters( 'xmlrpc_wp_insert_post_data', $post_data, $content_struct );

	// Remove all null values to allow for using the insert/update post default values for those keys instead.
	$post_data = array_filter(
		$post_data,
		static function ( $value ) {
			return null !== $value;
		}
	);

	$post_id = $update ? wp_update_post( $post_data, true ) : wp_insert_post( $post_data, true );
	if ( is_wp_error( $post_id ) ) {
		return new IXR_Error( 500, $post_id->get_error_message() );
	}

	if ( ! $post_id ) {
		if ( $update ) {
			return new IXR_Error( 401, __( 'Sorry, the post could not be updated.' ) );
		} else {
			return new IXR_Error( 401, __( 'Sorry, the post could not be created.' ) );
		}
	}

	return (string) $post_id;
}

Hooks

apply_filters( ‘xmlrpc_wp_insert_post_data’, array $post_data, array $content_struct )

Filters post data array to be inserted via XML-RPC.

Changelog

VersionDescription
3.4.0Introduced.

User Contributed Notes

You must log in before being able to contribute a note or feedback.