wp/wp-includes/rest-api/fields/class-wp-rest-meta-fields.php
changeset 21 48c4eec2b7e6
parent 18 be944660c56a
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    10 /**
    10 /**
    11  * Core class to manage meta values for an object via the REST API.
    11  * Core class to manage meta values for an object via the REST API.
    12  *
    12  *
    13  * @since 4.7.0
    13  * @since 4.7.0
    14  */
    14  */
       
    15 #[AllowDynamicProperties]
    15 abstract class WP_REST_Meta_Fields {
    16 abstract class WP_REST_Meta_Fields {
    16 
    17 
    17 	/**
    18 	/**
    18 	 * Retrieves the object meta type.
    19 	 * Retrieves the object meta type.
    19 	 *
    20 	 *
   138 	 * @param int   $object_id Object ID to fetch meta for.
   139 	 * @param int   $object_id Object ID to fetch meta for.
   139 	 * @return null|WP_Error Null on success, WP_Error object on failure.
   140 	 * @return null|WP_Error Null on success, WP_Error object on failure.
   140 	 */
   141 	 */
   141 	public function update_value( $meta, $object_id ) {
   142 	public function update_value( $meta, $object_id ) {
   142 		$fields = $this->get_registered_fields();
   143 		$fields = $this->get_registered_fields();
       
   144 		$error  = new WP_Error();
   143 
   145 
   144 		foreach ( $fields as $meta_key => $args ) {
   146 		foreach ( $fields as $meta_key => $args ) {
   145 			$name = $args['name'];
   147 			$name = $args['name'];
   146 			if ( ! array_key_exists( $name, $meta ) ) {
   148 			if ( ! array_key_exists( $name, $meta ) ) {
   147 				continue;
   149 				continue;
   160 
   162 
   161 				if ( $args['single'] ) {
   163 				if ( $args['single'] ) {
   162 					$current = get_metadata( $this->get_meta_type(), $object_id, $meta_key, true );
   164 					$current = get_metadata( $this->get_meta_type(), $object_id, $meta_key, true );
   163 
   165 
   164 					if ( is_wp_error( rest_validate_value_from_schema( $current, $args['schema'] ) ) ) {
   166 					if ( is_wp_error( rest_validate_value_from_schema( $current, $args['schema'] ) ) ) {
   165 						return new WP_Error(
   167 						$error->add(
   166 							'rest_invalid_stored_value',
   168 							'rest_invalid_stored_value',
   167 							/* translators: %s: Custom field key. */
   169 							/* translators: %s: Custom field key. */
   168 							sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ),
   170 							sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ),
   169 							array( 'status' => 500 )
   171 							array( 'status' => 500 )
   170 						);
   172 						);
       
   173 						continue;
   171 					}
   174 					}
   172 				}
   175 				}
   173 
   176 
   174 				$result = $this->delete_meta_value( $object_id, $meta_key, $name );
   177 				$result = $this->delete_meta_value( $object_id, $meta_key, $name );
   175 				if ( is_wp_error( $result ) ) {
   178 				if ( is_wp_error( $result ) ) {
   176 					return $result;
   179 					$error->merge_from( $result );
   177 				}
   180 				}
   178 				continue;
   181 				continue;
   179 			}
   182 			}
   180 
   183 
   181 			if ( ! $args['single'] && is_array( $value ) && count( array_filter( $value, 'is_null' ) ) ) {
   184 			if ( ! $args['single'] && is_array( $value ) && count( array_filter( $value, 'is_null' ) ) ) {
   182 				return new WP_Error(
   185 				$error->add(
   183 					'rest_invalid_stored_value',
   186 					'rest_invalid_stored_value',
   184 					/* translators: %s: Custom field key. */
   187 					/* translators: %s: Custom field key. */
   185 					sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ),
   188 					sprintf( __( 'The %s property has an invalid stored value, and cannot be updated to null.' ), $name ),
   186 					array( 'status' => 500 )
   189 					array( 'status' => 500 )
   187 				);
   190 				);
       
   191 				continue;
   188 			}
   192 			}
   189 
   193 
   190 			$is_valid = rest_validate_value_from_schema( $value, $args['schema'], 'meta.' . $name );
   194 			$is_valid = rest_validate_value_from_schema( $value, $args['schema'], 'meta.' . $name );
   191 			if ( is_wp_error( $is_valid ) ) {
   195 			if ( is_wp_error( $is_valid ) ) {
   192 				$is_valid->add_data( array( 'status' => 400 ) );
   196 				$is_valid->add_data( array( 'status' => 400 ) );
   193 				return $is_valid;
   197 				$error->merge_from( $is_valid );
       
   198 				continue;
   194 			}
   199 			}
   195 
   200 
   196 			$value = rest_sanitize_value_from_schema( $value, $args['schema'] );
   201 			$value = rest_sanitize_value_from_schema( $value, $args['schema'] );
   197 
   202 
   198 			if ( $args['single'] ) {
   203 			if ( $args['single'] ) {
   200 			} else {
   205 			} else {
   201 				$result = $this->update_multi_meta_value( $object_id, $meta_key, $name, $value );
   206 				$result = $this->update_multi_meta_value( $object_id, $meta_key, $name, $value );
   202 			}
   207 			}
   203 
   208 
   204 			if ( is_wp_error( $result ) ) {
   209 			if ( is_wp_error( $result ) ) {
   205 				return $result;
   210 				$error->merge_from( $result );
   206 			}
   211 				continue;
       
   212 			}
       
   213 		}
       
   214 
       
   215 		if ( $error->has_errors() ) {
       
   216 			return $error;
   207 		}
   217 		}
   208 
   218 
   209 		return null;
   219 		return null;
   210 	}
   220 	}
   211 
   221 
   365 	 * @return true|WP_Error True if the meta field was updated, WP_Error otherwise.
   375 	 * @return true|WP_Error True if the meta field was updated, WP_Error otherwise.
   366 	 */
   376 	 */
   367 	protected function update_meta_value( $object_id, $meta_key, $name, $value ) {
   377 	protected function update_meta_value( $object_id, $meta_key, $name, $value ) {
   368 		$meta_type = $this->get_meta_type();
   378 		$meta_type = $this->get_meta_type();
   369 
   379 
       
   380 		// Do the exact same check for a duplicate value as in update_metadata() to avoid update_metadata() returning false.
       
   381 		$old_value = get_metadata( $meta_type, $object_id, $meta_key );
       
   382 		$subtype   = get_object_subtype( $meta_type, $object_id );
       
   383 
       
   384 		if ( is_array( $old_value ) && 1 === count( $old_value )
       
   385 			&& $this->is_meta_value_same_as_stored_value( $meta_key, $subtype, $old_value[0], $value )
       
   386 		) {
       
   387 			return true;
       
   388 		}
       
   389 
   370 		if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $meta_key ) ) {
   390 		if ( ! current_user_can( "edit_{$meta_type}_meta", $object_id, $meta_key ) ) {
   371 			return new WP_Error(
   391 			return new WP_Error(
   372 				'rest_cannot_update',
   392 				'rest_cannot_update',
   373 				/* translators: %s: Custom field key. */
   393 				/* translators: %s: Custom field key. */
   374 				sprintf( __( 'Sorry, you are not allowed to edit the %s custom field.' ), $name ),
   394 				sprintf( __( 'Sorry, you are not allowed to edit the %s custom field.' ), $name ),
   375 				array(
   395 				array(
   376 					'key'    => $name,
   396 					'key'    => $name,
   377 					'status' => rest_authorization_required_code(),
   397 					'status' => rest_authorization_required_code(),
   378 				)
   398 				)
   379 			);
   399 			);
   380 		}
       
   381 
       
   382 		// Do the exact same check for a duplicate value as in update_metadata() to avoid update_metadata() returning false.
       
   383 		$old_value = get_metadata( $meta_type, $object_id, $meta_key );
       
   384 		$subtype   = get_object_subtype( $meta_type, $object_id );
       
   385 
       
   386 		if ( is_array( $old_value ) && 1 === count( $old_value )
       
   387 			&& $this->is_meta_value_same_as_stored_value( $meta_key, $subtype, $old_value[0], $value )
       
   388 		) {
       
   389 			return true;
       
   390 		}
   400 		}
   391 
   401 
   392 		if ( ! update_metadata( $meta_type, $object_id, wp_slash( $meta_key ), wp_slash( $value ) ) ) {
   402 		if ( ! update_metadata( $meta_type, $object_id, wp_slash( $meta_key ), wp_slash( $value ) ) ) {
   393 			return new WP_Error(
   403 			return new WP_Error(
   394 				'rest_meta_database_error',
   404 				'rest_meta_database_error',