param mixed $value Updated value. * @return bool|WP_Error True if the meta field was updated, WP_Error otherwise. */ protected function update_meta_value( $object_id, $meta_key, $name, $value ) { $meta_type = $this->get_meta_type(); if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $meta_key ) ) { return new WP_Error( 'rest_cannot_update', /* translators: %s: custom field key */ sprintf( __( 'Sorry, you are not allowed to edit the %s custom field.' ), $name ), array( 'key' => $name, 'status' => rest_authorization_required_code() ) ); } $meta_key = wp_slash( $meta_key ); $meta_value = wp_slash( $value ); // Do the exact same check for a duplicate value as in update_metadata() to avoid update_metadata() returning false. $old_value = get_metadata( $meta_type, $object_id, $meta_key ); if ( 1 === count( $old_value ) ) { if ( $old_value[0] === $meta_value ) { return true; } } if ( ! update_metadata( $meta_type, $object_id, $meta_key, $meta_value ) ) { return new WP_Error( 'rest_meta_database_error', __( 'Could not update meta value in database.' ), array( 'key' => $name, 'status' => WP_Http::INTERNAL_SERVER_ERROR ) ); } return true; } /** * Retrieves all the registered meta fields. * * @since 4.7.0 * * @return array Registered fields. */ protected function get_registered_fields() { $registered = array(); $meta_type = $this->get_meta_type(); $meta_subtype = $this->get_meta_subtype(); $meta_keys = get_registered_meta_keys( $meta_type ); if ( ! empty( $meta_subtype ) ) { $meta_keys = array_merge( $meta_keys, get_registered_meta_keys( $meta_type, $meta_subtype ) ); } foreach ( $meta_keys as $name => $args ) { if ( empty( $args['show_in_rest'] ) ) { continue; } $rest_args = array(); if ( is_array( $args['show_in_rest'] ) ) { $rest_args = $args['show_in_rest']; } $default_args = array( 'name' => $name, 'single' => $args['single'], 'type' => ! empty( $args['type'] ) ? $args['type'] : null, 'schema' => array(), 'prepare_callback' => array( $this, 'prepare_value' ), ); $default_schema = array( 'type' => $default_args['type'], 'description' => empty( $args['description'] ) ? '' : $args['description'], 'default' => isset( $args['default'] ) ? $args['default'] : null, ); $rest_args = array_merge( $default_args, $rest_args ); $rest_args['schema'] = array_merge( $default_schema, $rest_args['schema'] ); $type = ! empty( $rest_args['type'] ) ? $rest_args['type'] : null; $type = ! empty( $rest_args['schema']['type'] ) ? $rest_args['schema']['type'] : $type; if ( ! in_array( $type, array( 'string', 'boolean', 'integer', 'number' ) ) ) { continue; } if ( empty( $rest_args['single'] ) ) { $rest_args['schema']['items'] = array( 'type' => $rest_args['type'], ); $rest_args['schema']['type'] = 'array'; } $registered[ $name ] = $rest_args; } return $registered; } /** * Retrieves the object's meta schema, conforming to JSON Schema. * * @since 4.7.0 * * @return array Field schema data. */ public function get_field_schema() { $fields = $this->get_registered_fields(); $schema = array( 'description' => __( 'Meta fields.' ), 'type' => 'object', 'context' => array( 'view', 'edit' ), 'properties' => array(), 'arg_options' => array( 'sanitize_callback' => null, 'validate_callback' => array( $this, 'check_meta_is_array' ), ), ); foreach ( $fields as $args ) { $schema['properties'][ $args['name'] ] = $args['schema']; } return $schema; } /** * Prepares a meta value for output. * * Default preparation for meta fields. Override by passing the * `prepare_callback` in your `show_in_rest` options. * * @since 4.7.0 * * @param mixed $value Meta value from the database. * @param WP_REST_Request $request Request object. * @param array $args REST-specific options for the meta key. * @return mixed Value prepared for output. If a non-JsonSerializable object, null. */ public static function prepare_value( $value, $request, $args ) { $type = $args['schema']['type']; // For multi-value fields, check the item type instead. if ( 'array' === $type && ! empty( $args['schema']['items']['type'] ) ) { $type = $args['schema']['items']['type']; } switch ( $type ) { case 'string': $value = (string) $value; break; case 'integer': $value = (int) $value; break; case 'number': $value = (float) $value; break; case 'boolean': $value = (bool) $value; break; } // Don't allow objects to be output. if ( is_object( $value ) && ! ( $value instanceof JsonSerializable ) ) { return null; } return $value; } /** * Check the 'meta' value of a request is an associative array. * * @since 4.7.0 * * @param mixed $value The meta value submitted in the request. * @param WP_REST_Request $request Full details about the request. * @param string $param The parameter name. * @return WP_Error|string The meta array, if valid, otherwise an error. */ public function check_meta_is_array( $value, $request, $param ) { if ( ! is_array( $value ) ) { return false; } return $value; } }