Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders
OrderLineMetaValidator{}
Validates the line payloads of the order endpoints (line_items, shipping_lines, fee_lines), for every REST API version.
Class OrderLineMetaValidator
No Hooks.
Usage
$OrderLineMetaValidator = new OrderLineMetaValidator(); // use class methods
Methods
- public static assert_no_serialized_meta_value( array $meta_data )
- public static validate_request_arg( $value, $request, $param )
- private static get_serialized_meta_value_error_message()
- private static has_serialized_meta_value( $meta_data )
Notes
| Package: Automattic\WooCommerce\Internal\RestApi\Routes\V4\Orders |
OrderLineMetaValidator{} OrderLineMetaValidator{} code WC 11.1.2
class OrderLineMetaValidator {
/**
* Meta key that WC_Data::update_meta_data() diverts to the order item's set_taxes(), which runs
* the value through maybe_unserialize(). Only serialized values are rejected.
*
* Line, fee and shipping items all carry a `taxes` data prop, so reading an existing item promotes
* `_taxes` to an internal meta key and both `taxes` and `_taxes` divert to the tax setter.
*/
private const GUARDED_META_KEY = 'taxes';
/**
* Validates an order line request argument (`line_items`, `shipping_lines` or `fee_lines`).
*
* @since 11.1.0
*
* @param mixed $value Value of the argument.
* @param WP_REST_Request<array<string, mixed>> $request The request object.
* @param string $param Name of the argument.
* @return true|WP_Error Error when a line posts a serialized value under the guarded key.
*/
public static function validate_request_arg( $value, $request, $param ) {
$valid = rest_validate_request_arg( $value, $request, $param );
if ( is_wp_error( $valid ) ) {
return $valid;
}
if ( ! is_array( $value ) ) {
return true;
}
foreach ( $value as $line ) {
if ( is_array( $line ) && self::has_serialized_meta_value( $line['meta_data'] ?? null ) ) {
return new WP_Error(
'woocommerce_rest_invalid_order_item_meta_key',
self::get_serialized_meta_value_error_message(),
array( 'status' => 400 )
);
}
}
return true;
}
/**
* Rejects a serialized value under the guarded meta key while preparing an order line.
*
* Covers requests that skip request argument validation, such as the ones the batch endpoint builds.
*
* @since 11.1.0
*
* @param array $meta_data `meta_data` payload from the request. Cast at the call site, which can receive a non-array.
* @throws WC_REST_Exception When the payload carries a serialized value under the guarded key.
*/
public static function assert_no_serialized_meta_value( array $meta_data ): void {
if ( self::has_serialized_meta_value( $meta_data ) ) {
throw new WC_REST_Exception( 'woocommerce_rest_invalid_order_item_meta_key', esc_html( self::get_serialized_meta_value_error_message() ), 400 );
}
}
/**
* Checks whether a `meta_data` payload carries a serialized value under the guarded meta key.
*
* @param mixed $meta_data Raw `meta_data` value from the request.
* @return bool
*/
private static function has_serialized_meta_value( $meta_data ): bool {
if ( ! is_array( $meta_data ) ) {
return false;
}
foreach ( MetaDataUtil::normalize( $meta_data ) as $meta ) {
// update_meta_data() resolves the setter from ltrim( $key, '_' ), so `_taxes` diverts too.
if ( ! is_string( $meta['key'] ) || self::GUARDED_META_KEY !== ltrim( $meta['key'], '_' ) ) {
continue;
}
// Keep scanning: the payload can repeat the key, and every entry reaches the setter.
if ( is_serialized( $meta['value'] ) ) {
return true;
}
}
return false;
}
/**
* Gets the error message for a rejected payload.
*
* @return string
*/
private static function get_serialized_meta_value_error_message(): string {
return sprintf(
/* translators: %s: order item meta key. */
__( 'The "%s" order line meta key cannot hold a serialized value.', 'woocommerce' ),
self::GUARDED_META_KEY
);
}
}