AI
1 year ago
Agentic
7 months ago
AbstractAddressSchema.php
1 year ago
AbstractSchema.php
1 month ago
BatchSchema.php
2 years ago
BillingAddressSchema.php
2 years ago
CartCouponSchema.php
1 year ago
CartExtensionsSchema.php
1 year ago
CartFeeSchema.php
2 years ago
CartItemSchema.php
1 month ago
CartSchema.php
2 months ago
CartShippingRateSchema.php
1 month ago
CheckoutOrderSchema.php
2 years ago
CheckoutSchema.php
1 month ago
ErrorSchema.php
2 years ago
ImageAttachmentSchema.php
3 months ago
ItemSchema.php
11 months ago
OrderCouponSchema.php
2 years ago
OrderFeeSchema.php
2 years ago
OrderItemSchema.php
1 month ago
OrderSchema.php
2 months ago
PatternsSchema.php
1 year ago
ProductAttributeSchema.php
2 years ago
ProductAttributeTermSchema.php
1 month ago
ProductBrandSchema.php
1 year ago
ProductCategorySchema.php
2 years ago
ProductCollectionDataSchema.php
11 months ago
ProductReviewSchema.php
2 years ago
ProductSchema.php
1 month ago
ShippingAddressSchema.php
2 years ago
ShopperListItemSchema.php
1 month ago
ShopperListSchema.php
1 month ago
TermSchema.php
2 years ago
OrderItemSchema.php
218 lines
| 1 | <?php |
| 2 | namespace Automattic\WooCommerce\StoreApi\Schemas\V1; |
| 3 | |
| 4 | use Automattic\WooCommerce\StoreApi\Utilities\ProductItemTrait; |
| 5 | |
| 6 | /** |
| 7 | * OrderItemSchema class. |
| 8 | */ |
| 9 | class OrderItemSchema extends ItemSchema { |
| 10 | use ProductItemTrait; |
| 11 | |
| 12 | /** |
| 13 | * The schema item name. |
| 14 | * |
| 15 | * @var string |
| 16 | */ |
| 17 | protected $title = 'order_item'; |
| 18 | |
| 19 | /** |
| 20 | * Cache for parent product attributes. |
| 21 | * |
| 22 | * @var array|null |
| 23 | */ |
| 24 | private $cached_parent_attributes = null; |
| 25 | |
| 26 | /** |
| 27 | * The schema item identifier. |
| 28 | * |
| 29 | * @var string |
| 30 | */ |
| 31 | const IDENTIFIER = 'order-item'; |
| 32 | |
| 33 | /** |
| 34 | * Get order items data. |
| 35 | * |
| 36 | * @param \WC_Order_Item_Product $order_item Order item instance. |
| 37 | * @return array |
| 38 | */ |
| 39 | public function get_item_response( $order_item ) { |
| 40 | $this->cached_parent_attributes = null; |
| 41 | |
| 42 | $order = $order_item->get_order(); |
| 43 | $product = $order_item->get_product(); |
| 44 | |
| 45 | $product_properties = [ |
| 46 | 'short_description' => '', |
| 47 | 'description' => '', |
| 48 | 'sku' => '', |
| 49 | 'permalink' => '', |
| 50 | 'catalog_visibility' => 'hidden', |
| 51 | 'prices' => [ |
| 52 | 'price' => '', |
| 53 | 'regular_price' => '', |
| 54 | 'sale_price' => '', |
| 55 | 'price_range' => null, |
| 56 | 'currency_code' => '', |
| 57 | 'currency_symbol' => '', |
| 58 | 'currency_minor_unit' => 2, |
| 59 | 'currency_decimal_separator' => '.', |
| 60 | 'currency_thousand_separator' => ',', |
| 61 | 'currency_prefix' => '', |
| 62 | 'currency_suffix' => '', |
| 63 | 'raw_prices' => [ |
| 64 | 'precision' => 6, |
| 65 | 'price' => '', |
| 66 | 'regular_price' => '', |
| 67 | 'sale_price' => '', |
| 68 | ], |
| 69 | ], |
| 70 | 'sold_individually' => false, |
| 71 | 'images' => [], |
| 72 | 'variation' => [], |
| 73 | ]; |
| 74 | |
| 75 | if ( is_a( $product, 'WC_Product' ) ) { |
| 76 | $product_properties['short_description'] = $product->get_short_description(); |
| 77 | $product_properties['description'] = $product->get_description(); |
| 78 | $product_properties['sku'] = $product->get_sku(); |
| 79 | $product_properties['permalink'] = $product->get_permalink(); |
| 80 | $product_properties['catalog_visibility'] = $product->get_catalog_visibility(); |
| 81 | $product_properties['prices'] = $this->prepare_product_price_response( $product, get_option( 'woocommerce_tax_display_cart' ) ); |
| 82 | $product_properties['sold_individually'] = $product->is_sold_individually(); |
| 83 | $product_properties['images'] = $this->get_images( $product ); |
| 84 | |
| 85 | // Only include variation data for product variations, not simple products. |
| 86 | // This is consistent with the cart endpoint behavior. |
| 87 | if ( $product instanceof \WC_Product_Variation ) { |
| 88 | $product_properties['variation'] = $this->get_variation_data_from_order_item( $order_item, $product ); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | return [ |
| 93 | 'key' => $order->get_order_key(), |
| 94 | 'id' => $order_item->get_id(), |
| 95 | 'quantity' => $order_item->get_quantity(), |
| 96 | 'quantity_limits' => array( |
| 97 | 'minimum' => $order_item->get_quantity(), |
| 98 | 'maximum' => $order_item->get_quantity(), |
| 99 | 'multiple_of' => 1, |
| 100 | 'editable' => false, |
| 101 | ), |
| 102 | 'name' => $order_item->get_name(), |
| 103 | 'short_description' => $this->prepare_html_response( wc_format_content( wp_kses_post( $product_properties['short_description'] ) ) ), |
| 104 | 'description' => $this->prepare_html_response( wc_format_content( wp_kses_post( $product_properties['description'] ) ) ), |
| 105 | 'sku' => $this->prepare_html_response( $product_properties['sku'] ), |
| 106 | 'low_stock_remaining' => null, |
| 107 | 'backorders_allowed' => false, |
| 108 | 'show_backorder_badge' => false, |
| 109 | 'sold_individually' => $product_properties['sold_individually'] ?? false, |
| 110 | 'permalink' => $product_properties['permalink'], |
| 111 | 'images' => $product_properties['images'], |
| 112 | 'variation' => $product_properties['variation'], |
| 113 | 'item_data' => $order_item->get_all_formatted_meta_data(), |
| 114 | 'prices' => (object) $product_properties['prices'], |
| 115 | 'totals' => (object) $this->prepare_currency_response( $this->get_totals( $order_item ) ), |
| 116 | 'catalog_visibility' => $product_properties['catalog_visibility'], |
| 117 | ]; |
| 118 | } |
| 119 | |
| 120 | /** |
| 121 | * Get totals data. |
| 122 | * |
| 123 | * @param \WC_Order_Item_Product $order_item Order item instance. |
| 124 | * @return array |
| 125 | */ |
| 126 | public function get_totals( $order_item ) { |
| 127 | $price_decimals = wc_get_price_decimals(); |
| 128 | |
| 129 | return [ |
| 130 | 'line_subtotal' => $this->prepare_money_response( $order_item->get_subtotal(), $price_decimals ), |
| 131 | 'line_subtotal_tax' => $this->prepare_money_response( $order_item->get_subtotal_tax(), $price_decimals ), |
| 132 | 'line_total' => $this->prepare_money_response( $order_item->get_total(), $price_decimals ), |
| 133 | 'line_total_tax' => $this->prepare_money_response( $order_item->get_total_tax(), $price_decimals ), |
| 134 | ]; |
| 135 | } |
| 136 | |
| 137 | /** |
| 138 | * Get variation data from order item metadata. |
| 139 | * |
| 140 | * Gets the customer's actual attribute choices from the order metadata. |
| 141 | * This fixes variations set to "Any" returning empty values. |
| 142 | * |
| 143 | * @param \WC_Order_Item_Product $order_item Order item instance. |
| 144 | * @param \WC_Product $product Product instance. |
| 145 | * @return array Formatted variation data. |
| 146 | */ |
| 147 | protected function get_variation_data_from_order_item( $order_item, $product ) { |
| 148 | $variation_data = array(); |
| 149 | $meta_data = $order_item->get_meta_data(); |
| 150 | |
| 151 | $parent_attributes = $this->get_parent_product_attributes( $product ); |
| 152 | |
| 153 | foreach ( $meta_data as $meta ) { |
| 154 | $meta_key = $meta->key; |
| 155 | $meta_value = $meta->value; |
| 156 | |
| 157 | if ( empty( $meta_key ) || ! is_scalar( $meta_value ) || '' === $meta_value || strpos( $meta_key, '_' ) === 0 ) { |
| 158 | continue; |
| 159 | } |
| 160 | |
| 161 | $is_variation_attribute = false; |
| 162 | $normalized_key = $meta_key; |
| 163 | |
| 164 | if ( strpos( $meta_key, 'attribute_' ) === 0 ) { |
| 165 | $normalized_key = substr( $meta_key, strlen( 'attribute_' ) ); |
| 166 | } |
| 167 | |
| 168 | if ( strpos( $normalized_key, 'pa_' ) === 0 ) { |
| 169 | $is_variation_attribute = true; |
| 170 | } else { |
| 171 | foreach ( $parent_attributes as $attribute ) { |
| 172 | if ( strtolower( $attribute->get_name() ) === strtolower( $normalized_key ) ) { |
| 173 | $is_variation_attribute = true; |
| 174 | break; |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | if ( $is_variation_attribute ) { |
| 180 | $variation_data[ wc_variation_attribute_name( $normalized_key ) ] = $meta_value; |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | return $this->format_variation_data( $variation_data, $product ); |
| 185 | } |
| 186 | |
| 187 | /** |
| 188 | * Get parent product attributes. |
| 189 | * |
| 190 | * Cached to avoid multiple DB lookups when processing multiple meta items. |
| 191 | * |
| 192 | * @param \WC_Product $product Product instance. |
| 193 | * @return array Array of WC_Product_Attribute objects. |
| 194 | * |
| 195 | * @since 10.5.0 |
| 196 | */ |
| 197 | protected function get_parent_product_attributes( $product ) { |
| 198 | if ( null !== $this->cached_parent_attributes ) { |
| 199 | return $this->cached_parent_attributes; |
| 200 | } |
| 201 | |
| 202 | $this->cached_parent_attributes = array(); |
| 203 | |
| 204 | if ( ! $product->get_parent_id() ) { |
| 205 | return $this->cached_parent_attributes; |
| 206 | } |
| 207 | |
| 208 | $parent_product = wc_get_product( $product->get_parent_id() ); |
| 209 | if ( ! $parent_product instanceof \WC_Product ) { |
| 210 | return $this->cached_parent_attributes; |
| 211 | } |
| 212 | |
| 213 | $this->cached_parent_attributes = $parent_product->get_attributes(); |
| 214 | |
| 215 | return $this->cached_parent_attributes; |
| 216 | } |
| 217 | } |
| 218 |