I just tried to add a "Delivery Date" to WooCommerce checkout process based on this and this threads.
This is the related code to print delivery date on order meta and view it on Thank you page and also admin order page:
//Shipping (Delivery) Date
// Add custom checkout datepicker field
add_action( 'woocommerce_before_order_notes', 'checkout_display_datepicker_custom_field' );
function checkout_display_datepicker_custom_field( $checkout ) {
$field_id = 'my_datepicker';
echo '<div id="datepicker-wrapper">';
$today = strtotime('today');
$tomorrow = strtotime('tomorrow');
$dayAfterTomorrow = strtotime('+2 days');
woocommerce_form_field( $field_id, array(
'type' => 'select',
'class' => array('my-field-class form-row-wide'),
'label' => __('Choose a date'),
'placeholder' => __('Select delivery date'),
'required' => true, // Or false
'options' => array(
'' => 'Select',
date( 'yyyy-mm-dd', $today ) => date( get_option('date_format'), $today ),
date( 'yyyy-mm-dd', $tomorrow ) => date( get_option('date_format'), $tomorrow ),
date( 'yyyy-mm-dd', $dayAfterTomorrow ) => date( get_option('date_format'), $dayAfterTomorrow ),
)));
echo '<br></div>';
}
// Save field
add_action( 'woocommerce_checkout_create_order', 'save_datepicker_custom_field_value', 10, 2 );
function save_datepicker_custom_field_value( $order, $data ){
$field_id = 'my_datepicker';
$meta_key = '_'.$field_id;
if ( isset($_POST[$field_id]) && ! empty($_POST[$field_id]) ) {
$date = esc_attr($_POST[$field_id]);
$order->update_meta_data( $meta_key, $date ); // Save date as order meta data
$note = sprintf(__("Chosen date for Thank you page: %s.", "woocommerce"), $date );
$note = isset($data['order_comments']) && ! empty($data['order_comments']) ? $data['order_comments'] . '. ' . $note : $note;
// Save date on customer order note
$order->set_customer_note( $note );
}
}
It prints choosed date but in a wrong format like: 20202020-1212-2424
How can I modify this bug?
You're using the wrong format on your date() functions.
Have a look at date/time format docs.
In your case, yyyy-mm-dd:
y A two digit representation of a year
m Numeric representation of a month, with leading zeros
d Day of the month, 2 digits with leading zeros
Hence, 20202020-1212-2424.
You probably meant 2020-12-24, which should be Y-m-d:
Y A full numeric representation of a year, 4 digits
I am working on my WordPress / Woocommerce website.
How can I add a constant value, which would always be the first value in the drop down list which consists of times (hour:minute). This constant value at the top should say "As soon as possible".
Here is the code which generates the form itself:
public function time_select( $checkout ) {
echo '<div id="local-pickup-time-select"><h2>' . __( 'Delivery Time', $this->plugin_slug ) . '</h2>';
woocommerce_form_field( 'local_pickup_time_select', array(
'type' => 'select',
'class' => array( 'local-pickup-time-select-field form-row-wide' ),
'label' => __( 'Delivery Time', $this->plugin_slug ),
'required' => true,
'options' => self::create_hour_options()
), $checkout->get_value( 'local_pickup_time_select' ));
self::create_hour_options();
echo '</div>';
}
public function pickup_time_select_translatable( $value ) {
$value = preg_replace('/(\d)_(\d)/','$1:$2', $value);
$value = explode('_', $value);
$return = __( $value[0], $this->plugin_slug ). ' ' .$value[1];
return $return;
}
public function create_hour_options() {
// Make sure we have a time zone set
$offset = get_option( 'gmt_offset' );
$timezone_setting = get_option( 'timezone_string' );
if ( $timezone_setting ) {
date_default_timezone_set( get_option( 'timezone_string', 'America/New_York' ) );
}
else {
$timezone = timezone_name_from_abbr( null, $offset * 3600, true );
if( $timezone === false ) $timezone = timezone_name_from_abbr( null, $offset * 3600, false );
date_default_timezone_set( $timezone );
}
// Get days closed textarea from settings, explode into an array
$closing_days_raw = trim( get_option( 'local_pickup_hours_closings' ) );
$closing_days = explode( "\n", $closing_days_raw );
$closing_days = array_filter( $closing_days, 'trim' );
// Get delay, interval, and number of days ahead settings
$delay_minutes = get_option( 'local_pickup_delay_minutes', 60 );
$interval = get_option( 'local_pickup_hours_interval', 30 );
$num_days_allowed = get_option( 'local_pickup_days_ahead', 1 );
// Setup time variables for calculations
$today_name = strtolower( date( 'l' ) );
$today_date = date( 'm/d/Y' );
// Create an empty array for our dates
$pickup_options = array();
//Translateble days
__( 'Monday', $this->plugin_slug );
__( 'Tuesday', $this->plugin_slug );
__( 'Wednesday', $this->plugin_slug );
__( 'Thursday', $this->plugin_slug );
__( 'Friday', $this->plugin_slug );
__( 'Saturday', $this->plugin_slug );
__( 'Sunday', $this->plugin_slug );
// Add empty option
$pickup_options[''] = __( 'Select time', $this->plugin_slug );
// Loop through all days ahead and add the pickup time options to the array
for ( $i = 0; $i < $num_days_allowed; $i++ ) {
// Get the date of current iteration
$current_day_name = date( 'l', strtotime( "+$i days" ) );
$current_day_name_lower = strtolower( $current_day_name );
// Get the day's opening and closing times
$open_time = get_option( 'local_pickup_hours_' . $current_day_name_lower . '_start', '10:00' );
$close_time = get_option( 'local_pickup_hours_' . $current_day_name_lower . '_end', '19:00' );
// Today
$tStart = strtotime( $open_time );
$tEnd = strtotime( $close_time );
$tNow = $tStart;
$current_time = time();
// Date format based on user settings
$date_format = get_option('time_format');
$date_format_key = preg_replace("/[^\w]+/", "_", $date_format);
// If Closed today or today's pickup times are over, don't allow a pickup option
if ( ( in_array( $today_date, $closing_days ) || ( $current_time >= $tEnd ) ) && $num_days_allowed == 1 ) {
// Set drop down text to let user know store is closed
$pickup_options['closed_today'] = __( 'Closed today, please check back tomorrow!', $this->plugin_slug );
// Hide Order Review so user doesn't order anything today
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_order_review', 10 );
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 );
}
else {
// Create array of time options to return to woocommerce_form_field
// Today
if ( $i == 0) {
// Check if it's not too late for pickup
if ( $current_time < $tEnd ) {
// Fix tNow if is pickup possible today
if ( $i == 0 ) {
$todayStart = $tStart;
$delayStart = strtotime("+$delay_minutes minutes", $current_time);
while ( $todayStart <= $delayStart ) {
$todayStart = strtotime("+$interval minutes", $todayStart);
}
$tNow = $todayStart;
}
while ( $tNow <= $tEnd ) {
$day_name = __( 'Today', $this->plugin_slug );
$option_key = $current_day_name . date( $date_format_key, $tNow );
$option_value = $day_name . ' ' . date( $date_format, $tNow );
$pickup_options[$option_key] = $option_value;
$tNow = strtotime( "+$interval minutes", $tNow );
}
}
// Other days
} else {
if ( !empty($open_time) && !empty($close_time )) {
while ( $tNow <= $tEnd ) {
$day_name = __( $current_day_name, $this->plugin_slug );
$option_key = $current_day_name . date( $date_format_key, $tNow );
$option_value = $day_name . ' ' . date( $date_format, $tNow );
$pickup_options[$option_key] = $option_value;
$tNow = strtotime( "+$interval minutes", $tNow );
}
}
}
}
} // end for loop
if ( count($pickup_options) == 1) {
// Set drop down text to let user know store is closed
$pickup_options['closed_today'] = __( 'Closed today, please check back tomorrow!', $this->plugin_slug );
// Hide Order Review so user doesn't order anything today
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_order_review', 10 );
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 );
}
return $pickup_options;
}
The final result would look something like this Drop-down list:
As soon as possible
Tuesday 7:30 pm
Tuesday 8:00 pm
Tuesday 8:30 pm
There is many ways to do it depending if the key value you want for "As soon as possible" choice has to be dynamic. This is done in your first function with array_merge() this way:
public function time_select( $checkout ) {
echo '<div id="local-pickup-time-select"><h2>' . __( 'Delivery Time', $this->plugin_slug ) . '</h2>';
// The default empty value and your translatable sentence to be included
$array_to_insert = array(
'' => __( 'Select your delivery time', $this->plugin_slug ),
'as_soon' => __( 'As soon as possible', $this->plugin_slug )
);
// Getting your calculated hours options array
$options = self::create_hour_options();
// Merging both arrays in one
$options = array_merge( $array_to_insert, $options );
woocommerce_form_field( 'local_pickup_time_select', array(
'type' => 'select',
'class' => array( 'local-pickup-time-select-field form-row-wide' ),
'label' => __( 'Delivery Time', $this->plugin_slug ),
'required' => true,
'options' => $options,
), $checkout->get_value( 'local_pickup_time_select' ));
echo '</div>';
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works. you will get that:
I have noticed in your code that your //Translateble days (monday to sunday) are not set in individual variables or in an array…
Why can't I retrieve the data from a Woocommerce checkout field to update subscription data as the order processes?
I want to update the next renewal date based on the customers' frequency request on checkout. Here is my code:
1) Set up the checkout field:
add_action( 'woocommerce_after_order_notes', 'hgf_custom_checkout_field' );
function hgf_custom_checkout_field( $checkout ) {
global $woocommerce;
woocommerce_form_field( 'frequency', array(
'type' => 'select',
'required' => true,
'class' => array('form-row-wide'),
'label' => __('Change this any time, just email.'),
'options' => array(
'blank' => __( 'Select frequency preference', 'woocommerce' ),
1 => __( 'Every Week', 'woocommerce' ),
2 => __( 'Every Other Week' , 'woocommerce' ),
3 => __( 'Once Per Month' , 'woocommerce' )
)
), $checkout->get_value( 'frequency' ));
echo '</div>';
}
2) Update the order meta. This creates two custom fields on the customer order, as well as updates the billing interval on the subscription:
add_action( 'woocommerce_checkout_update_order_meta', 'hgf_checkout_field_update_order_meta' );
function hgf_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['frequency'] ) ) {
update_post_meta( $order_id, 'frequency', $_POST['frequency'] );
update_post_meta( $order_id, 'billing_interval', $_POST['frequency'] );
}
}
3) Update the renewal date
For the last part, I can update the renewal date with a dummy date of my choosing (for instance: $renewal date = "2018-12-15", but when I try to get it to read the 'billing_interval' field, it reverts to the else default.
add_action( 'woocommerce_checkout_create_subscription', 'hgf_next_renewal' );
function hgf_next_renewal( $subscription, $timezone='site' ) {
$billing_interval = get_post_meta( get_the_ID(), 'billing_interval', true);
if( $billing_interval == 2 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-10-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+2 weeks" ) ) */ ;
} if( $billing_interval == 4 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-12-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+4 weeks" ) ) */ ;
} else {
$renewal_date = date( 'Y-m-d H:i:s' ) ) /* date( 'Y-m-d H:i:s', strtotime( $renewal_date) ) */ ;
}
$subscription->update_dates( array(
'next_payment' => $renewal_date,
) );
return $subscription;
}
This is all the different ways I have tried:
1) $billing_interval = $subscription->get_billing_interval();
2) $billing_interval = get_post_meta( $subscription->get_ID(), 'billing_interval', true);
3) $billing_interval = get_post_meta( $order_id, 'billing_interval', true);
4) $subscriptions = wcs_get_users_subscriptions( $user_id );
foreach ( $subscriptions as $sub ) {
$billing_interval = get_post_meta( $sub->get_order_number(), '_billing_interval', true);
}
5) $billing_interval = $checkout->get_value( 'frequency' );
Does anyone know why I can't retrieve a value from my checkout field while in the 'woocommerce_checkout_create_subscription' action?
As you are saving your 'billing_interval' custom field in the Order meta data, you can't get this custom field through the subscription object or ID… You need to get first the Parent Order ID.
To get the parent Order ID from the subscription object you need to use the WC_Order method get_parent_id()
add_action( 'woocommerce_checkout_create_subscription', 'hgf_next_renewal' );
function hgf_next_renewal( $subscription, $timezone='site' ) {
// MISSING!: The parent order ID to set below
$order_parent_id = $subscription->get_parent_id();
$billing_interval = get_post_meta( $order_parent_id, 'billing_interval', true);
if( $billing_interval == 2 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-10-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+2 weeks" ) ) */ ;
} elseif( $billing_interval == 4 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-12-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+4 weeks" ) ) */ ;
} else {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-09-01" ) ) /* date( 'Y-m-d H:i:s' ) */ ;
}
$subscription->update_dates( array(
'next_payment' => $renewal_date,
) );
return $subscription;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
I haven't tested your code for real, but it doesn't throw any error and should work for you this time.
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?
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;
}
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.
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.
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>";
}
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
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.
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
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();
that line for downloadables is fire.
my files weren't showing up under user downloads without it.
// 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 ) );
}
}