From 66fbd9738b7ca92a25029651b4965533e0e4724b Mon Sep 17 00:00:00 2001 From: Mike Jolley Date: Thu, 11 Feb 2021 16:26:52 +0000 Subject: [PATCH] Moved Nonce Logic to Cart API Classes (https://github.com/woocommerce/woocommerce-blocks/pull/3812) * Reduce repetition in SchemaController::initialize * Ensure AbstractCartRoute has a cart schema when it returns errors * Move nonce logic to cart * typo --- .../src/StoreApi/Routes/AbstractCartRoute.php | 101 ++++++++++++++- .../src/StoreApi/Routes/AbstractRoute.php | 45 ------- .../StoreApi/Routes/CartUpdateCustomer.php | 39 +----- .../src/StoreApi/Routes/Checkout.php | 22 +--- .../src/StoreApi/Routes/Products.php | 2 - .../src/StoreApi/RoutesController.php | 12 +- .../src/StoreApi/SchemaController.php | 118 +++++++++--------- .../src/StoreApi/Schemas/CartSchema.php | 14 +-- 8 files changed, 183 insertions(+), 170 deletions(-) diff --git a/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractCartRoute.php b/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractCartRoute.php index a8d2c9f461b..2725e4dca66 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractCartRoute.php +++ b/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractCartRoute.php @@ -2,6 +2,8 @@ namespace Automattic\WooCommerce\Blocks\StoreApi\Routes; use Automattic\WooCommerce\Blocks\StoreApi\Utilities\CartController; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\AbstractSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartSchema; /** * Abstract Cart Route @@ -9,6 +11,32 @@ use Automattic\WooCommerce\Blocks\StoreApi\Utilities\CartController; * @internal This API is used internally by Blocks--it is still in flux and may be subject to revisions. */ abstract class AbstractCartRoute extends AbstractRoute { + /** + * Schema class for this route's response. + * + * @var AbstractSchema|CartSchema + */ + protected $schema; + + /** + * Schema class for the cart. + * + * @var CartSchema + */ + protected $cart_schema; + + /** + * Constructor accepts two types of schema; one for the item being returned, and one for the cart as a whole. These + * may be the same depending on the route. + * + * @param CartSchema $cart_schema Schema class for the cart. + * @param AbstractSchema $item_schema Schema class for this route's items if it differs from the cart schema. + */ + public function __construct( CartSchema $cart_schema, AbstractSchema $item_schema = null ) { + $this->schema = is_null( $item_schema ) ? $cart_schema : $item_schema; + $this->cart_schema = $cart_schema; + } + /** * Get the route response based on the type of request. * @@ -18,7 +46,37 @@ abstract class AbstractCartRoute extends AbstractRoute { public function get_response( \WP_REST_Request $request ) { $this->maybe_load_cart(); $this->calculate_totals(); - return parent::get_response( $request ); + + try { + if ( $this->requires_nonce( $request ) ) { + $this->check_nonce( $request ); + } + $response = parent::get_response( $request ); + } catch ( RouteException $error ) { + $response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode(), $error->getAdditionalData() ); + } catch ( \Exception $error ) { + $response = $this->get_route_error_response( 'unknown_server_error', $error->getMessage(), 500 ); + } + + if ( is_wp_error( $response ) ) { + $response = $this->error_to_response( $response ); + } + + $response->header( 'X-WC-Store-API-Nonce', wp_create_nonce( 'wc_store_api' ) ); + $response->header( 'X-WC-Store-API-Nonce-Timestamp', time() ); + $response->header( 'X-WC-Store-API-User', get_current_user_id() ); + + return $response; + } + + /** + * Checks if a nonce is required for the route. + * + * @param \WP_REST_Request $request Request. + * @return bool + */ + protected function requires_nonce( \WP_REST_Request $request ) { + return 'GET' !== $request->get_method(); } /** @@ -46,6 +104,34 @@ abstract class AbstractCartRoute extends AbstractRoute { wc_release_stock_for_order( $draft_order ); } + /** + * For non-GET endpoints, require and validate a nonce to prevent CSRF attacks. + * + * Nonces will mismatch if the logged in session cookie is different! If using a client to test, set this cookie + * to match the logged in cookie in your browser. + * + * @throws RouteException On error. + * + * @param \WP_REST_Request $request Request object. + */ + protected function check_nonce( \WP_REST_Request $request ) { + $nonce = $request->get_header( 'X-WC-Store-API-Nonce' ); + + if ( apply_filters( 'woocommerce_store_api_disable_nonce_check', false ) ) { + return; + } + + if ( null === $nonce ) { + throw new RouteException( 'woocommerce_rest_missing_nonce', __( 'Missing the X-WC-Store-API-Nonce header. This endpoint requires a valid nonce.', 'woo-gutenberg-products-block' ), 401 ); + } + + $valid_nonce = wp_verify_nonce( $nonce, 'wc_store_api' ); + + if ( ! $valid_nonce ) { + throw new RouteException( 'woocommerce_rest_invalid_nonce', __( 'X-WC-Store-API-Nonce is invalid.', 'woo-gutenberg-products-block' ), 403 ); + } + } + /** * Get route response when something went wrong. * @@ -69,11 +155,22 @@ abstract class AbstractCartRoute extends AbstractRoute { $additional_data, [ 'status' => $http_status_code, - 'cart' => $this->schema->get_item_response( $cart ), + 'cart' => $this->cart_schema->get_item_response( $cart ), ] ) ); } return new \WP_Error( $error_code, $error_message, [ 'status' => $http_status_code ] ); } + + /** + * Makes the cart and sessions available to a route by loading them from core. + */ + protected function maybe_load_cart() { + if ( ! did_action( 'woocommerce_load_cart_from_session' ) && function_exists( 'wc_load_cart' ) ) { + include_once WC_ABSPATH . 'includes/wc-cart-functions.php'; + include_once WC_ABSPATH . 'includes/wc-notice-functions.php'; + wc_load_cart(); + } + } } diff --git a/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractRoute.php b/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractRoute.php index 1beabb282b9..63851bf6ed8 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractRoute.php +++ b/plugins/woocommerce-blocks/src/StoreApi/Routes/AbstractRoute.php @@ -52,9 +52,6 @@ abstract class AbstractRoute implements RouteInterface { public function get_response( \WP_REST_Request $request ) { $response = null; try { - if ( 'GET' !== $request->get_method() ) { - $this->check_nonce( $request ); - } switch ( $request->get_method() ) { case 'POST': $response = $this->get_route_post_response( $request ); @@ -80,9 +77,6 @@ abstract class AbstractRoute implements RouteInterface { $response = $this->error_to_response( $response ); } - $response->header( 'X-WC-Store-API-Nonce', wp_create_nonce( 'wc_store_api' ) ); - $response->header( 'X-WC-Store-API-Nonce-Timestamp', time() ); - $response->header( 'X-WC-Store-API-User', get_current_user_id() ); return $response; } @@ -116,34 +110,6 @@ abstract class AbstractRoute implements RouteInterface { return new \WP_REST_Response( $data, $status ); } - /** - * For non-GET endpoints, require and validate a nonce to prevent CSRF attacks. - * - * Nonces will mismatch if the logged in session cookie is different! If using a client to test, set this cookie - * to match the logged in cookie in your browser. - * - * @throws RouteException On error. - * - * @param \WP_REST_Request $request Request object. - */ - protected function check_nonce( \WP_REST_Request $request ) { - $nonce = $request->get_header( 'X-WC-Store-API-Nonce' ); - - if ( apply_filters( 'woocommerce_store_api_disable_nonce_check', false ) ) { - return; - } - - if ( null === $nonce ) { - throw new RouteException( 'woocommerce_rest_missing_nonce', __( 'Missing the X-WC-Store-API-Nonce header. This endpoint requires a valid nonce.', 'woo-gutenberg-products-block' ), 401 ); - } - - $valid_nonce = wp_verify_nonce( $nonce, 'wc_store_api' ); - - if ( ! $valid_nonce ) { - throw new RouteException( 'woocommerce_rest_invalid_nonce', __( 'X-WC-Store-API-Nonce is invalid.', 'woo-gutenberg-products-block' ), 403 ); - } - } - /** * Get route response for GET requests. * @@ -296,15 +262,4 @@ abstract class AbstractRoute implements RouteInterface { 'context' => $this->get_context_param(), ); } - - /** - * Makes the cart and sessions available to a route by loading them from core. - */ - protected function maybe_load_cart() { - if ( ! did_action( 'woocommerce_load_cart_from_session' ) && function_exists( 'wc_load_cart' ) ) { - include_once WC_ABSPATH . 'includes/wc-cart-functions.php'; - include_once WC_ABSPATH . 'includes/wc-notice-functions.php'; - wc_load_cart(); - } - } } diff --git a/plugins/woocommerce-blocks/src/StoreApi/Routes/CartUpdateCustomer.php b/plugins/woocommerce-blocks/src/StoreApi/Routes/CartUpdateCustomer.php index ca7b8a2f746..dab8f96202f 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/Routes/CartUpdateCustomer.php +++ b/plugins/woocommerce-blocks/src/StoreApi/Routes/CartUpdateCustomer.php @@ -14,33 +14,6 @@ use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ShippingAddressSchema; * @internal This API is used internally by Blocks--it is still in flux and may be subject to revisions. */ class CartUpdateCustomer extends AbstractCartRoute { - /** - * Billing address schema instance. - * - * @var BillingAddressSchema - */ - protected $billing_address_schema; - - /** - * Shipping address schema instance. - * - * @var ShippingAddressSchema - */ - protected $shipping_address_schema; - - /** - * Constructor. - * - * @param CartSchema $schema Schema class for this route. - * @param ShippingAddressSchema $shipping_address_schema Billing address schema class for this route. - * @param BillingAddressSchema $billing_address_schema Billing address schema class for this route. - */ - public function __construct( CartSchema $schema, ShippingAddressSchema $shipping_address_schema, BillingAddressSchema $billing_address_schema ) { - $this->schema = $schema; - $this->shipping_address_schema = $shipping_address_schema; - $this->billing_address_schema = $billing_address_schema; - } - /** * Get the namespace for this route. * @@ -75,17 +48,17 @@ class CartUpdateCustomer extends AbstractCartRoute { 'description' => __( 'Billing address.', 'woo-gutenberg-products-block' ), 'type' => 'object', 'context' => [ 'view', 'edit' ], - 'properties' => $this->billing_address_schema->get_properties(), - 'sanitize_callback' => [ $this->billing_address_schema, 'sanitize_callback' ], - 'validate_callback' => [ $this->billing_address_schema, 'validate_callback' ], + 'properties' => $this->schema->billing_address_schema->get_properties(), + 'sanitize_callback' => [ $this->schema->billing_address_schema, 'sanitize_callback' ], + 'validate_callback' => [ $this->schema->billing_address_schema, 'validate_callback' ], ], 'shipping_address' => [ 'description' => __( 'Shipping address.', 'woo-gutenberg-products-block' ), 'type' => 'object', 'context' => [ 'view', 'edit' ], - 'properties' => $this->shipping_address_schema->get_properties(), - 'sanitize_callback' => [ $this->shipping_address_schema, 'sanitize_callback' ], - 'validate_callback' => [ $this->shipping_address_schema, 'validate_callback' ], + 'properties' => $this->schema->shipping_address_schema->get_properties(), + 'sanitize_callback' => [ $this->schema->shipping_address_schema, 'sanitize_callback' ], + 'validate_callback' => [ $this->schema->shipping_address_schema, 'validate_callback' ], ], ], ], diff --git a/plugins/woocommerce-blocks/src/StoreApi/Routes/Checkout.php b/plugins/woocommerce-blocks/src/StoreApi/Routes/Checkout.php index f5539af2d9e..760b6c4791b 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/Routes/Checkout.php +++ b/plugins/woocommerce-blocks/src/StoreApi/Routes/Checkout.php @@ -21,7 +21,7 @@ use Automattic\WooCommerce\Blocks\Payments\PaymentContext; * * @internal This API is used internally by Blocks--it is still in flux and may be subject to revisions. */ -class Checkout extends AbstractRoute { +class Checkout extends AbstractCartRoute { /** * Holds the current order being processed. * @@ -39,23 +39,13 @@ class Checkout extends AbstractRoute { } /** - * Enforce nonces for all checkout endpoints. + * Checks if a nonce is required for the route. * - * @param WP_REST_Request $request Request object. - * @return WP_Error|WP_REST_Response + * @param \WP_REST_Request $request Request. + * @return bool */ - public function get_response( WP_REST_Request $request ) { - $this->maybe_load_cart(); - $response = null; - try { - $this->check_nonce( $request ); - $response = parent::get_response( $request ); - } catch ( RouteException $error ) { - $response = $this->get_route_error_response( $error->getErrorCode(), $error->getMessage(), $error->getCode() ); - } catch ( Exception $error ) { - $response = $this->get_route_error_response( 'unknown_server_error', $error->getMessage(), 500 ); - } - return $response; + protected function requires_nonce( \WP_REST_Request $request ) { + return true; } /** diff --git a/plugins/woocommerce-blocks/src/StoreApi/Routes/Products.php b/plugins/woocommerce-blocks/src/StoreApi/Routes/Products.php index 20924c2f0f5..fcc42df6e7c 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/Routes/Products.php +++ b/plugins/woocommerce-blocks/src/StoreApi/Routes/Products.php @@ -44,8 +44,6 @@ class Products extends AbstractRoute { * @return \WP_REST_Response */ protected function get_route_response( \WP_REST_Request $request ) { - // we load so that we have the same session, this is done so that Add to Cart can function. - $this->maybe_load_cart(); $response = new \WP_REST_Response(); $product_query = new ProductQuery(); diff --git a/plugins/woocommerce-blocks/src/StoreApi/RoutesController.php b/plugins/woocommerce-blocks/src/StoreApi/RoutesController.php index 96d640c87e6..147c2a2a41c 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/RoutesController.php +++ b/plugins/woocommerce-blocks/src/StoreApi/RoutesController.php @@ -70,16 +70,16 @@ class RoutesController { 'cart' => new Routes\Cart( $this->schemas->get( 'cart' ) ), 'cart-add-item' => new Routes\CartAddItem( $this->schemas->get( 'cart' ) ), 'cart-apply-coupon' => new Routes\CartApplyCoupon( $this->schemas->get( 'cart' ) ), - 'cart-coupons' => new Routes\CartCoupons( $this->schemas->get( 'cart-coupon' ) ), - 'cart-coupons-by-code' => new Routes\CartCouponsByCode( $this->schemas->get( 'cart-coupon' ) ), - 'cart-items' => new Routes\CartItems( $this->schemas->get( 'cart-item' ) ), - 'cart-items-by-key' => new Routes\CartItemsByKey( $this->schemas->get( 'cart-item' ) ), + 'cart-coupons' => new Routes\CartCoupons( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-coupon' ) ), + 'cart-coupons-by-code' => new Routes\CartCouponsByCode( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-coupon' ) ), + 'cart-items' => new Routes\CartItems( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-item' ) ), + 'cart-items-by-key' => new Routes\CartItemsByKey( $this->schemas->get( 'cart' ), $this->schemas->get( 'cart-item' ) ), 'cart-remove-coupon' => new Routes\CartRemoveCoupon( $this->schemas->get( 'cart' ) ), 'cart-remove-item' => new Routes\CartRemoveItem( $this->schemas->get( 'cart' ) ), 'cart-select-shipping-rate' => new Routes\CartSelectShippingRate( $this->schemas->get( 'cart' ) ), 'cart-update-item' => new Routes\CartUpdateItem( $this->schemas->get( 'cart' ) ), - 'cart-update-customer' => new Routes\CartUpdateCustomer( $this->schemas->get( 'cart' ), $this->schemas->get( 'shipping-address' ), $this->schemas->get( 'billing-address' ) ), - 'checkout' => new Routes\Checkout( $this->schemas->get( 'checkout' ) ), + 'cart-update-customer' => new Routes\CartUpdateCustomer( $this->schemas->get( 'cart' ) ), + 'checkout' => new Routes\Checkout( $this->schemas->get( 'cart' ), $this->schemas->get( 'checkout' ) ), 'product-attributes' => new Routes\ProductAttributes( $this->schemas->get( 'product-attribute' ) ), 'product-attributes-by-id' => new Routes\ProductAttributesById( $this->schemas->get( 'product-attribute' ) ), 'product-attribute-terms' => new Routes\ProductAttributeTerms( $this->schemas->get( 'term' ) ), diff --git a/plugins/woocommerce-blocks/src/StoreApi/SchemaController.php b/plugins/woocommerce-blocks/src/StoreApi/SchemaController.php index 0c26720f1a6..b087142bab5 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/SchemaController.php +++ b/plugins/woocommerce-blocks/src/StoreApi/SchemaController.php @@ -2,7 +2,23 @@ namespace Automattic\WooCommerce\Blocks\StoreApi; use Exception; -use Schemas\AbstractSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\AbstractSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\BillingAddressSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ShippingAddressSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartShippingRateSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartItemSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartCouponSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CartFeeSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ErrorSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\CheckoutSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ProductSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ImageAttachmentSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ProductAttributeSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ProductCategorySchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ProductCollectionDataSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\ProductReviewSchema; +use Automattic\WooCommerce\Blocks\StoreApi\Schemas\TermSchema; use Automattic\WooCommerce\Blocks\Domain\Services\ExtendRestApi; @@ -56,63 +72,47 @@ class SchemaController { * Load schema class instances. */ protected function initialize() { - $this->schemas = [ - Schemas\BillingAddressSchema::IDENTIFIER => new Schemas\BillingAddressSchema( - $this->extend - ), - Schemas\ShippingAddressSchema::IDENTIFIER => new Schemas\ShippingAddressSchema( - $this->extend - ), - Schemas\CartShippingRateSchema::IDENTIFIER => new Schemas\CartShippingRateSchema( - $this->extend - ), - Schemas\CartSchema::IDENTIFIER => new Schemas\CartSchema( - $this->extend, - new Schemas\CartItemSchema( - $this->extend, - new Schemas\ImageAttachmentSchema( $this->extend ) - ), - new Schemas\CartCouponSchema( $this->extend ), - new Schemas\CartFeeSchema( $this->extend ), - new Schemas\CartShippingRateSchema( $this->extend ), - new Schemas\ShippingAddressSchema( $this->extend ), - new Schemas\BillingAddressSchema( $this->extend ), - new Schemas\ErrorSchema( $this->extend ) - ), - Schemas\CartCouponSchema::IDENTIFIER => new Schemas\CartCouponSchema( $this->extend ), - Schemas\CartItemSchema::IDENTIFIER => new Schemas\CartItemSchema( - $this->extend, - new Schemas\ImageAttachmentSchema( $this->extend ) - ), - Schemas\CartFeeSchema::IDENTIFIER => new Schemas\CartFeeSchema( $this->extend ), - Schemas\CheckoutSchema::IDENTIFIER => new Schemas\CheckoutSchema( - $this->extend, - new Schemas\BillingAddressSchema( $this->extend ), - new Schemas\ShippingAddressSchema( - $this->extend - ) - ), - Schemas\ProductSchema::IDENTIFIER => new Schemas\ProductSchema( - $this->extend, - new Schemas\ImageAttachmentSchema( - $this->extend - ) - ), - Schemas\ProductAttributeSchema::IDENTIFIER => new Schemas\ProductAttributeSchema( $this->extend ), - Schemas\ProductCategorySchema::IDENTIFIER => new Schemas\ProductCategorySchema( - $this->extend, - new Schemas\ImageAttachmentSchema( $this->extend ) - ), - Schemas\ProductCollectionDataSchema::IDENTIFIER => new Schemas\ProductCollectionDataSchema( - $this->extend - ), - Schemas\ProductReviewSchema::IDENTIFIER => new Schemas\ProductReviewSchema( - $this->extend, - new Schemas\ImageAttachmentSchema( $this->extend ) - ), - Schemas\TermSchema::IDENTIFIER => new Schemas\TermSchema( - $this->extend - ), - ]; + $this->schemas = []; + $this->schemas[ ErrorSchema::IDENTIFIER ] = new ErrorSchema( $this->extend ); + $this->schemas[ ImageAttachmentSchema::IDENTIFIER ] = new ImageAttachmentSchema( $this->extend ); + $this->schemas[ TermSchema::IDENTIFIER ] = new TermSchema( $this->extend ); + $this->schemas[ BillingAddressSchema::IDENTIFIER ] = new BillingAddressSchema( $this->extend ); + $this->schemas[ ShippingAddressSchema::IDENTIFIER ] = new ShippingAddressSchema( $this->extend ); + $this->schemas[ CartShippingRateSchema::IDENTIFIER ] = new CartShippingRateSchema( $this->extend ); + $this->schemas[ CartCouponSchema::IDENTIFIER ] = new CartCouponSchema( $this->extend ); + $this->schemas[ CartFeeSchema::IDENTIFIER ] = new CartFeeSchema( $this->extend ); + $this->schemas[ CartItemSchema::IDENTIFIER ] = new CartItemSchema( + $this->extend, + $this->schemas[ ImageAttachmentSchema::IDENTIFIER ] + ); + $this->schemas[ CartSchema::IDENTIFIER ] = new CartSchema( + $this->extend, + $this->schemas[ CartItemSchema::IDENTIFIER ], + $this->schemas[ CartCouponSchema::IDENTIFIER ], + $this->schemas[ CartFeeSchema::IDENTIFIER ], + $this->schemas[ CartShippingRateSchema::IDENTIFIER ], + $this->schemas[ ShippingAddressSchema::IDENTIFIER ], + $this->schemas[ BillingAddressSchema::IDENTIFIER ], + $this->schemas[ ErrorSchema::IDENTIFIER ] + ); + $this->schemas[ CheckoutSchema::IDENTIFIER ] = new CheckoutSchema( + $this->extend, + $this->schemas[ BillingAddressSchema::IDENTIFIER ], + $this->schemas[ ShippingAddressSchema::IDENTIFIER ] + ); + $this->schemas[ ProductSchema::IDENTIFIER ] = new ProductSchema( + $this->extend, + $this->schemas[ ImageAttachmentSchema::IDENTIFIER ] + ); + $this->schemas[ ProductAttributeSchema::IDENTIFIER ] = new ProductAttributeSchema( $this->extend ); + $this->schemas[ ProductCategorySchema::IDENTIFIER ] = new ProductCategorySchema( + $this->extend, + $this->schemas[ ImageAttachmentSchema::IDENTIFIER ] + ); + $this->schemas[ ProductCollectionDataSchema::IDENTIFIER ] = new ProductCollectionDataSchema( $this->extend ); + $this->schemas[ ProductReviewSchema::IDENTIFIER ] = new ProductReviewSchema( + $this->extend, + $this->schemas[ ImageAttachmentSchema::IDENTIFIER ] + ); } } diff --git a/plugins/woocommerce-blocks/src/StoreApi/Schemas/CartSchema.php b/plugins/woocommerce-blocks/src/StoreApi/Schemas/CartSchema.php index 6a8e3249cd0..23ca97ffa14 100644 --- a/plugins/woocommerce-blocks/src/StoreApi/Schemas/CartSchema.php +++ b/plugins/woocommerce-blocks/src/StoreApi/Schemas/CartSchema.php @@ -31,49 +31,49 @@ class CartSchema extends AbstractSchema { * * @var CartItemSchema */ - protected $item_schema; + public $item_schema; /** * Coupon schema instance. * * @var CartCouponSchema */ - protected $coupon_schema; + public $coupon_schema; /** * Fee schema instance. * * @var CartFeeSchema */ - protected $fee_schema; + public $fee_schema; /** * Shipping rates schema instance. * * @var CartShippingRateSchema */ - protected $shipping_rate_schema; + public $shipping_rate_schema; /** * Shipping address schema instance. * * @var ShippingAddressSchema */ - protected $shipping_address_schema; + public $shipping_address_schema; /** * Billing address schema instance. * * @var BillingAddressSchema */ - protected $billing_address_schema; + public $billing_address_schema; /** * Error schema instance. * * @var ErrorSchema */ - protected $error_schema; + public $error_schema; /** * Constructor.