WC_REST_Orders_V2_Controller::prepare_line_items
Create or update a line item.
Method of the class: WC_REST_Orders_V2_Controller{}
No Hooks.
Returns
WC_Order_Item_Product.
Usage
// protected - for code of main (parent) or child class $result = $this->prepare_line_items( $posted, $action, $item );
- $posted(array) (required)
- Line item data.
- $action(string)
'create'to add line item or'update'to update it.
Default:'create'- $item(object)
- Passed when updating an item. Null during creation.
Default:null
WC_REST_Orders_V2_Controller::prepare_line_items() WC REST Orders V2 Controller::prepare line items code WC 11.1.2
protected function prepare_line_items( $posted, $action = 'create', $item = null ) {
$item = is_null( $item ) ? new WC_Order_Item_Product( ! empty( $posted['id'] ) ? $posted['id'] : '' ) : $item;
$product = wc_get_product( $this->get_product_id( $posted, $action ) );
$product_item = $item instanceof WC_Order_Item_Product ? $item : null;
$current_product_id = $product_item ? (int) $product_item->get_product_id( 'edit' ) : 0;
$current_variation_id = $product_item ? (int) $product_item->get_variation_id( 'edit' ) : 0;
// set_product() clears a variation when given its parent. REST partial updates restore it only
// when the posted parent and SKU-resolved product still identify the current item.
// An explicit variation_id of 0 still demotes the item.
$same_product_update = 'update' === $action
&& array_key_exists( 'product_id', $posted )
&& $product instanceof WC_Product
&& (int) $posted['product_id'] === $current_product_id
&& in_array( $product->get_id(), array( $current_product_id, $current_variation_id ), true );
$restore_variation_id = $same_product_update
&& $current_variation_id
&& ( ! array_key_exists( 'variation_id', $posted ) || (int) $posted['variation_id'] === $current_variation_id );
$clear_variation_id = $same_product_update
&& $current_variation_id
&& array_key_exists( 'variation_id', $posted )
&& 0 === (int) $posted['variation_id'];
if ( $clear_variation_id && $product instanceof WC_Product_Variation ) {
$product = wc_get_product( $current_product_id );
}
if ( $product && $product !== $item->get_product() ) {
$item->set_product( $product );
if ( $restore_variation_id && $product_item ) {
try {
$product_item->set_variation_id( $current_variation_id );
} catch ( WC_Data_Exception $e ) {
if (
'order_item_product_invalid_variation_id' !== $e->getErrorCode()
|| 'product_variation' === get_post_type( $current_variation_id )
) {
throw $e;
}
// The stored variation ID no longer identifies a variation. Keep set_product()'s parent demotion.
// A subclass veto reusing this error code for an already-deleted variation is indistinguishable
// from the core throw and is deliberately swallowed too: rethrowing for subclasses (e.g. via a
// get_class() check) would revive the 400 on every store substituting order item classes.
wc_get_logger()->warning(
sprintf(
'Order item #%d (order #%d) referenced variation #%d, which no longer exists; the item was demoted to its parent product during a REST update.',
$product_item->get_id(),
$product_item->get_order_id(),
$current_variation_id
),
array( 'source' => 'rest-api' )
);
}
}
if ( 'create' === $action ) {
$quantity = isset( $posted['quantity'] ) ? $posted['quantity'] : 1;
$total = wc_get_price_excluding_tax( $product, array( 'qty' => $quantity ) );
$item->set_total( $total );
$item->set_subtotal( $total );
}
}
if ( $clear_variation_id && $product_item ) {
$product_item->set_variation_id( 0 );
}
OrderLineMetaValidator::assert_no_serialized_meta_value( (array) ( $posted['meta_data'] ?? array() ) );
$this->maybe_set_item_props( $item, array( 'name', 'quantity', 'total', 'subtotal', 'tax_class' ), $posted );
$this->maybe_set_item_meta_data( $item, $posted );
return $item;
}