public function create_order( $data ) {
/**
* Gives plugins an opportunity to create a new order themselves.
*
* @since 3.0.0 or earlier
*
* @param int|null $order_id Can be set to an order ID to short-circuit the default order creation process.
* @param WC_Checkout $checkout Reference to the current WC_Checkout instance.
*/
$order_id = apply_filters( 'woocommerce_create_order', null, $this );
if ( $order_id ) {
return $order_id;
}
try {
$order_id = absint( WC()->session->get( 'order_awaiting_payment' ) );
$cart_hash = WC()->cart->get_cart_hash();
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
$order = $order_id ? wc_get_order( $order_id ) : null;
/**
* If there is an order pending payment, we can resume it here so
* long as it has not changed. If the order has changed, i.e.
* different items or cost, create a new order. We use a hash to
* detect changes which is based on cart items + order total.
*/
if ( $order && $order->has_cart_hash( $cart_hash ) && $order->has_status( array( 'pending', 'failed' ) ) ) {
/**
* Indicates that we are resuming checkout for an existing order (which is pending payment, and which
* has not changed since it was added to the current shopping session).
*
* @since 3.0.0 or earlier
*
* @param int $order_id The ID of the order being resumed.
*/
do_action( 'woocommerce_resume_order', $order_id );
// Remove all items - we will re-add them later.
$order->remove_order_items();
} else {
$order = new WC_Order();
}
$fields_prefix = array(
'shipping' => true,
'billing' => true,
);
$shipping_fields = array(
'shipping_method' => true,
'shipping_total' => true,
'shipping_tax' => true,
);
foreach ( $data as $key => $value ) {
if ( is_callable( array( $order, "set_{$key}" ) ) ) {
$order->{"set_{$key}"}( $value );
// Store custom fields prefixed with wither shipping_ or billing_. This is for backwards compatibility with 2.6.x.
} elseif ( isset( $fields_prefix[ current( explode( '_', $key ) ) ] ) ) {
if ( ! isset( $shipping_fields[ $key ] ) ) {
$order->update_meta_data( '_' . $key, $value );
}
}
}
if ( isset( $data['billing_email'] ) ) {
$order->hold_applied_coupons( $data['billing_email'] );
}
$order->set_created_via( 'checkout' );
$order->set_cart_hash( $cart_hash );
/**
* This action is documented in woocommerce/includes/class-wc-checkout.php
*
* @since 3.0.0 or earlier
*/
$order->set_customer_id( apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() ) );
$order->set_currency( get_woocommerce_currency() );
$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
$order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
$order->set_customer_user_agent( wc_get_user_agent() );
$order->set_customer_note( isset( $data['order_comments'] ) ? $data['order_comments'] : '' );
$order->set_payment_method( isset( $available_gateways[ $data['payment_method'] ] ) ? $available_gateways[ $data['payment_method'] ] : $data['payment_method'] );
$this->set_data_from_cart( $order );
if ( $this->cogs_is_enabled() ) {
$order->calculate_cogs_total_value();
}
/**
* Action hook to adjust order before save.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_create_order', $order, $data );
// Save the order.
$order_id = $order->save();
/**
* Action hook fired after an order is created used to add custom meta to the order.
*
* @since 3.0.0
*/
do_action( 'woocommerce_checkout_update_order_meta', $order_id, $data );
/**
* Action hook fired after an order is created.
*
* @since 4.3.0
*/
do_action( 'woocommerce_checkout_order_created', $order );
return $order_id;
} catch ( Exception $e ) {
if ( $order && $order instanceof WC_Order ) {
$order->get_data_store()->release_held_coupons( $order );
/**
* Action hook fired when an order is discarded due to Exception.
*
* @since 4.3.0
*/
do_action( 'woocommerce_checkout_order_exception', $order );
}
return new WP_Error( 'checkout-error', $e->getMessage() );
}
}