问题
I want to create a new order programmatically.
Workflow is simple: After submitting simple form, user will be created and along with that, a new order.
I managed to create a new user and user_id is returned, now I need to assign a new order all in one step.
How can I accomplish this?
回答1:
Here's how I programmatically create my orders. I largely followed WC_Checkout::create_order() from @pavel's suggestion above. This is directly from a plugin I'm writing so you'll have to adjust where the source data comes form.
// build order data
$order_data = array(
'post_name' => 'order-' . date_format($order_date, 'M-d-Y-hi-a'), //'order-jun-19-2014-0648-pm'
'post_type' => 'shop_order',
'post_title' => 'Order – ' . date_format($order_date, 'F d, Y @ h:i A'), //'June 19, 2014 @ 07:19 PM'
'post_status' => 'wc-completed',
'ping_status' => 'closed',
'post_excerpt' => $order->note,
'post_author' => $account->user_id,
'post_password' => uniqid( 'order_' ), // Protects the post just in case
'post_date' => date_format($order_date, 'Y-m-d H:i:s e'), //'order-jun-19-2014-0648-pm'
'comment_status' => 'open'
);
// create order
$order_id = wp_insert_post( $order_data, true );
if ( is_wp_error( $order_id ) ) {
$order->errors = $order_id;
} else {
$order->imported = true;
// add a bunch of meta data
add_post_meta($order_id, 'transaction_id', $order->transaction_id, true);
add_post_meta($order_id, '_payment_method_title', 'Import', true);
add_post_meta($order_id, '_order_total', $order->gross, true);
add_post_meta($order_id, '_customer_user', $account->user_id, true);
add_post_meta($order_id, '_completed_date', date_format( $order_date, 'Y-m-d H:i:s e'), true);
add_post_meta($order_id, '_order_currency', $order->currency, true);
add_post_meta($order_id, '_paid_date', date_format( $order_date, 'Y-m-d H:i:s e'), true);
// billing info
add_post_meta($order_id, '_billing_address_1', $order->address_line_1, true);
add_post_meta($order_id, '_billing_address_2', $order->address_line_2, true);
add_post_meta($order_id, '_billing_city', $order->city, true);
add_post_meta($order_id, '_billing_state', $order->state, true);
add_post_meta($order_id, '_billing_postcode', $order->zip, true);
add_post_meta($order_id, '_billing_country', $order->country, true);
add_post_meta($order_id, '_billing_email', $order->from_email, true);
add_post_meta($order_id, '_billing_first_name', $order->first_name, true);
add_post_meta($order_id, '_billing_last_name', $order->last_name, true);
add_post_meta($order_id, '_billing_phone', $order->phone, true);
// get product by item_id
$product = get_product_by_sku( $order->item_id );
if( $product ) {
// add item
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => $product->get_title(),
'order_item_type' => 'line_item'
) );
if ( $item_id ) {
// add item meta data
wc_add_order_item_meta( $item_id, '_qty', 1 );
wc_add_order_item_meta( $item_id, '_tax_class', $product->get_tax_class() );
wc_add_order_item_meta( $item_id, '_product_id', $product->ID );
wc_add_order_item_meta( $item_id, '_variation_id', '' );
wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $order->gross ) );
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $order->gross ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( 0 ) );
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( 0 ) );
}
// set order status as completed
wp_set_object_terms( $order_id, 'completed', 'shop_order_status' );
// if downloadable
if( $product->is_downloadable() ) {
// add downloadable permission for each file
$download_files = $product->get_files();
foreach ( $download_files as $download_id => $file ) {
wc_downloadable_file_permission( $download_id, $product->id, new WC_Order( $order_id ) );
}
}
} else {
$order->errors = 'Product SKU (' . $order->$item_id . ') not found.';
}
}
function get_product_by_sku( $sku ) {
global $wpdb;
$product_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key='_sku' AND meta_value='%s' LIMIT 1", $sku ) );
if ( $product_id ) return new WC_Product( $product_id );
return null;
}
Order Class
The is the interim class I use to store the orders before importing into WordPress / WooCommerce.
class ImportOrder
{
// public vars
public $date;
public $time;
public $time_zone;
public $first_name;
public $middle_name;
public $last_name;
public $type;
public $status;
public $currency;
public $gross;
public $fee;
public $net;
public $note;
public $to_email;
public $from_email;
public $transaction_id;
public $counterparty_status;
public $address_status;
public $item_title;
public $item_id;
public $address_line_1;
public $address_line_2;
public $city;
public $state;
public $zip;
public $country;
public $phone;
public $imported;
public $errors;
}
Add Order
The data here is imported from a PayPal CSV download of historical transactions. The $row variable represents one row in the CSV. You can adjust this to suit your needs.
function add_import_order( $row ) {
// create new order
$order = new ImportOrder();
// done this before?
$order->exists = order_exists( $row[PayPalCols::TRANSACTION_ID] );
// add a bunch of fields
$order->date = $row[PayPalCols::DATE];
$order->time = $row[PayPalCols::TIME];
$order->time_zone = $row[PayPalCols::TIME_ZONE];
$order->type = $row[PayPalCols::TYPE];
$order->status = $row[PayPalCols::STATUS];
$order->currency = $row[PayPalCols::CURRENCY];
$order->gross = $row[PayPalCols::GROSS];
$order->fee = $row[PayPalCols::FEE];
$order->net = $row[PayPalCols::NET];
$order->note = $row[PayPalCols::NOTE];
$order->from_email = $row[PayPalCols::FROM_EMAIL];
$order->to_email = $row[PayPalCols::TO_EMAIL];
$order->transaction_id = $row[PayPalCols::TRANSACTION_ID];
$order->counterparty_status = $row[PayPalCols::COUNTERPARTY_STATUS];
$order->address_status = $row[PayPalCols::ADDRESS_STATUS];
$order->item_title = $row[PayPalCols::ITEM_TITLE];
$order->item_id = $row[PayPalCols::ITEM_ID];
$order->address_line_1 = utf8_encode( $row[PayPalCols::ADDRESS_LINE_1] );
$order->address_line_2 = utf8_encode( $row[PayPalCols::ADDRESS_LINE_2] );
$order->city = utf8_encode( $row[PayPalCols::TOWN_CITY] );
$order->state = utf8_encode( $row[PayPalCols::STATE] );
$order->zip = utf8_encode( $row[PayPalCols::ZIP] );
$order->country = utf8_encode( $row[PayPalCols::COUNTRY] );
$order->phone = utf8_encode( $row[PayPalCols::PHONE] );
return $order;
}
回答2:
For creating New order, You will have to create Object of WC_Order
, If you working outside WooCommerce or in function.php
then, First Define Global $woocommerce
variable.
So, There will be just 2 line of Code.
global $woocommerce;
$order = new WC_Order( $order_id );
Hope, It will help You.
回答3:
As of WooCommerce 2.2 (or maybe 2.1 I'm not 100% sure) there is now a function specifically designed for this.
wc_create_order( $args = array() )
with the following default arguments.
$default_args = array(
'status' => '',
'customer_id' => null,
'customer_note' => null,
'order_id' => 0
);
You can see the whole function in the includes/wc-core-functions.php
file.
回答4:
There's a much easier way of doing it, using wc_create_order()
. Here's an example, which also adds shipping and product line items. It also creates a Woocommerce subscription, but you can ignore that part for a normal product, the same code will work.
function create_test_sub() {
$email = 'test@test.com';
$start_date = '2015-01-01 00:00:00';
$address = array(
'first_name' => 'Jeremy',
'last_name' => 'Test',
'company' => '',
'email' => $email,
'phone' => '777-777-777-777',
'address_1' => '31 Main Street',
'address_2' => '',
'city' => 'Auckland',
'state' => 'AKL',
'postcode' => '12345',
'country' => 'AU'
);
$default_password = wp_generate_password();
if (!$user = get_user_by('login', $email)) $user = wp_create_user( $email, $default_password, $email );
// I've used one product with multiple variations
$parent_product = wc_get_product(22998);
$args = array(
'attribute_billing-period' => 'Yearly',
'attribute_subscription-type' => 'Both'
);
$product_variation = $parent_product->get_matching_variation($args);
$product = wc_get_product($product_variation);
// Each variation also has its own shipping class
$shipping_class = get_term_by('slug', $product->get_shipping_class(), 'product_shipping_class');
WC()->shipping->load_shipping_methods();
$shipping_methods = WC()->shipping->get_shipping_methods();
// I have some logic for selecting which shipping method to use; your use case will likely be different, so figure out the method you need and store it in $selected_shipping_method
$selected_shipping_method = $shipping_methods['free_shipping'];
$class_cost = $selected_shipping_method->get_option('class_cost_' . $shipping_class->term_id);
$quantity = 1;
// As far as I can see, you need to create the order first, then the sub
$order = wc_create_order(array('customer_id' => $user->id));
$order->add_product( $product, $quantity, $args);
$order->set_address( $address, 'billing' );
$order->set_address( $address, 'shipping' );
$order->add_shipping((object)array (
'id' => $selected_shipping_method->id,
'label' => $selected_shipping_method->title,
'cost' => (float)$class_cost,
'taxes' => array(),
'calc_tax' => 'per_order'
));
$order->calculate_totals();
$order->update_status("completed", 'Imported order', TRUE);
// Order created, now create sub attached to it -- optional if you're not creating a subscription, obvs
// Each variation has a different subscription period
$period = WC_Subscriptions_Product::get_period( $product );
$interval = WC_Subscriptions_Product::get_interval( $product );
$sub = wcs_create_subscription(array('order_id' => $order->id, 'billing_period' => $period, 'billing_interval' => $interval, 'start_date' => $start_date));
$sub->add_product( $product, $quantity, $args);
$sub->set_address( $address, 'billing' );
$sub->set_address( $address, 'shipping' );
$sub->add_shipping((object)array (
'id' => $selected_shipping_method->id,
'label' => $selected_shipping_method->title,
'cost' => (float)$class_cost,
'taxes' => array(),
'calc_tax' => 'per_order'
));
$sub->calculate_totals();
WC_Subscriptions_Manager::activate_subscriptions_for_order($order);
print "<a href='/wp-admin/post.php?post=" . $sub->id . "&action=edit'>Sub created! Click here to edit</a>";
}
回答5:
have a look at my solution: creating Woocommerce order with line_item programmatically
Works like a charm and goes to the correct WC class that is used by the new REST API
回答6:
Unfortunately, I don't think there are no easy way to do this I'm afraid.
You need to add the order post using wp_insert_post();
and then add all the meta data using update_post_meta()
. You then need to add the using woocommerce_add_order_item()
and woocommerce_add_order_item_meta()
. Lasty you need to set the order status using wp_set_object_terms()
.
It's quite a lot of steps and pitfalls. You need to check your database carefully and add all the data and meta data you need to process and complete the order.
回答7:
in woocommerce WC_Checkout class has a "create_order" method. You can clone WC_Checkout class, give it another name, change the code of the method for your purposes and call like
include 'path_to_Cloned_WC_Checkout';
$chk = new Cloned_WC_Checkout();
$chk->create_order();
in form handler
回答8:
maybe this way..
function insert_order_to_db($seller,$order_date){
global $wpdb;
$result = $wpdb->query(
"
INSERT INTO `wp_posts`(`ID`, `post_author`, `post_date`, `post_date_gmt`, `post_content`, `post_title`, `post_excerpt`, `post_status`, `comment_status`, `ping_status`, `post_password`, `post_name`, `to_ping`, `pinged`, `post_modified`, `post_modified_gmt`, `post_content_filtered`, `post_parent`, `guid`, `menu_order`, `post_type`, `post_mime_type`, `comment_count`)
VALUES (
17188,
$seller,
'".date_format($order_date, 'Y-m-d H:i:s e')."',
'".date_format($order_date, 'Y-m-d H:i:s e')."',
'no',
'Order –". date_format($order_date, 'F d, Y @ h:i A')."',
'noxp',
'wc-completed',
'open',
'close',
'".uniqid( 'order_' )."',
'order-". date_format($order_date, 'M-d-Y-hi-a')."',
'',
'',
'2017-07-24',
'2017-07-24',
'',
0,
'',
0,
'shop_order',
'',
0)
"
);
$order_id = $wpdb->insert_id;
return $order_id;
}
function proccess_order_meta(){
$date = date_create("2017-07-24");
$order_id = insert_order_to_db(194816,$date);
if( is_wp_error( $order_id ) ){
$order->errors = $order_id;
}
else
{
$order_id = 17188;
add_post_meta($order_id, '_payment_method_title', 'پرداخت آنلاین', true);
add_post_meta($order_id, '_order_total', 30000, true);
add_post_meta($order_id, '_customer_user', 194816, true);
add_post_meta($order_id, '_completed_date', date_format( $date, 'Y-m-d H:i:s e'), true);
add_post_meta($order_id, '_paid_date', date_format( $date, 'Y-m-d H:i:s e'), true);
add_post_meta($order_id, '_billing_email', "mavaezi46@gmail.com", true);
add_post_meta($order_id, '_billing_first_name', "علی", true);
}
}
proccess_order_meta();
来源:https://stackoverflow.com/questions/17163251/wordpress-woocommerce-extension-create-new-order-programmatically