Related
I am trying to get previous order number from the specified order number for example there are 5 orders we have.
1780
1781
1782
1784
1786
Now if i specifiy the order number
wc_custom_get_previous_order_number(1784)
I should get 1782. I have tried multiple solutions. For example :
add_filter( 'woocommerce_order_number', 'custom_woocommerce_order_number', 1, 2 );
function custom_woocommerce_order_number( $oldnumber, $order ) {
$lastorderid = $order->id-1; // here is i am trying to get previous order number.
// other code...
}
You could build your own function with a SQL query with 2 arguments:
$order_id is the starting order ID.
$limit is the number of orders Ids to get from.
The function code:
function get_orders_from( $order_id, $limit = 1 ){
global $wpdb;
// The SQL query
$results = $wpdb->get_col( "
SELECT ID
FROM {$wpdb->prefix}posts
WHERE post_type LIKE 'shop_order'
AND ID < $order_id
ORDER BY ID DESC
LIMIT $limit
" );
return $limit == 1 ? reset( $results ) : $results;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
USAGE (examples):
1) To get the previous order ID from the current $order_id you will use in your code:
$previous_order_id = get_orders_from( $order_id );
You will get directly the previous order ID…
2) To get the 3 previous orders IDs from order ID 1784:
// Get the array of orders_ids
$orders_ids = get_orders_from( 1784, 3 );
// Converting and displaying a string of IDs (coma separated)
echo implode( ', ', $orders_ids );
You will get: 1780, 1781, 1782
How can I get an array with Order IDs by Product ID?
I mean receive all orders where specific product is presented.
I know how to do this by MySQL, but is there a way to do this by WP_Query function?
Updates:
2017 - SQL query changed to "SELECT DISTINCT" instead of "SELECT" to avoid duplicated Order IDs in the array (then no need of array_unique() to filter duplicates…).
2019 - Enabled product variation type support in the SQL Query
Then you can embed this in a custom function with $product_id as argument. You will have to set inside it, the order statuses that you are targeting.
So here is the function that will do the job:
function get_orders_ids_by_product_id( $product_id ) {
global $wpdb;
// Define HERE the orders status to include in <== <== <== <== <== <== <==
$orders_statuses = "'wc-completed', 'wc-processing', 'wc-on-hold'";
# Get All defined statuses Orders IDs for a defined product ID (or variation ID)
return $wpdb->get_col( "
SELECT DISTINCT woi.order_id
FROM {$wpdb->prefix}woocommerce_order_itemmeta as woim,
{$wpdb->prefix}woocommerce_order_items as woi,
{$wpdb->prefix}posts as p
WHERE woi.order_item_id = woim.order_item_id
AND woi.order_id = p.ID
AND p.post_status IN ( $orders_statuses )
AND woim.meta_key IN ( '_product_id', '_variation_id' )
AND woim.meta_value LIKE '$product_id'
ORDER BY woi.order_item_id DESC"
);
}
This code goes in any php file.
This code is tested and works for WooCommerce version 2.5+, 2.6+ and 3+
USAGE EXAMPLES:
## This will display all orders containing this product ID in a coma separated string ##
// A defined product ID: 40
$product_id = 40;
// We get all the Orders for the given product ID in an arrray
$orders_ids_array = get_orders_ids_by_product_id( $product_id );
// We display the orders in a coma separated list
echo '<p>' . implode( ', ', $orders_ids_array ) . '</p>';
If you want your code to work in future WC updates, it is better to use functions provided by WC to get details from the DB, since WC often change the DB structure.
I'd try something like:
function get_orders_id_from_product_id($product_id, $args = array() ) {
//first get all the order ids
$query = new WC_Order_Query( $args );
$order_ids = $query->get_orders();
//iterate through order
$filtered_order_ids = array();
foreach ($order_ids as $order_id) {
$order = wc_get_order($order_id);
$order_items = $order->get_items();
//iterate through an order's items
foreach ($order_items as $item) {
//if one item has the product id, add it to the array and exit the loop
if ($item->get_product_id() == $product_id) {
array_push($filtered_order_ids, $order_id);
break;
}
}
}
return $filtered_order_ids;
}
Usage example:
$product_id = '2094';
// NOTE: With 'limit' => 10 you only search in the last 10 orders
$args = array(
'limit' => 10,
'orderby' => 'date',
'order' => 'DESC',
'return' => 'ids',
);
$filtered_order_ids = get_orders_id_from_product_id($product_id, $args);
print_r($filtered_order_ids);
I'd like to note that the above answer will return a duplicate of the order_id if the order has multiple items in it.
E.g.
If there was a product called "apples" with product_id=>1036
Customer puts "apples" 3 times in their cart and purchases it, creating order_id=>555
If I query product_id->1036, I will get array(555,555,555).
There's probably an SQL way of doing this which may be faster, (would appreciate anyone that could add to this), otherwise I used: array_unqiue() to merge the duplicates.
function retrieve_orders_ids_from_a_product_id( $product_id )
{
global $wpdb;
$table_posts = $wpdb->prefix . "posts";
$table_items = $wpdb->prefix . "woocommerce_order_items";
$table_itemmeta = $wpdb->prefix . "woocommerce_order_itemmeta";
// Define HERE the orders status to include in <== <== <== <== <== <== <==
$orders_statuses = "'wc-completed', 'wc-processing', 'wc-on-hold'";
# Requesting All defined statuses Orders IDs for a defined product ID
$orders_ids = $wpdb->get_col( "
SELECT $table_items.order_id
FROM $table_itemmeta, $table_items, $table_posts
WHERE $table_items.order_item_id = $table_itemmeta.order_item_id
AND $table_items.order_id = $table_posts.ID
AND $table_posts.post_status IN ( $orders_statuses )
AND $table_itemmeta.meta_key LIKE '_product_id'
AND $table_itemmeta.meta_value LIKE '$product_id'
ORDER BY $table_items.order_item_id DESC"
);
// return an array of Orders IDs for the given product ID
$orders_ids = array_unique($orders_ids);
return $orders_ids;
}
Modified function to get specific user product ids
function retrieve_orders_ids_from_a_product_id( $product_id,$user_id )
{
global $wpdb;
$table_posts = $wpdb->prefix . "posts";
$table_postmeta = $wpdb->prefix . "postmeta";
$table_items = $wpdb->prefix . "woocommerce_order_items";
$table_itemmeta = $wpdb->prefix . "woocommerce_order_itemmeta";
// Define HERE the orders status to include in <== <== <== <== <== <== <==
$orders_statuses = "'wc-completed', 'wc-processing', 'wc-on-hold'";
# Requesting All defined statuses Orders IDs for a defined product ID
$orders_ids = $wpdb->get_col( "
SELECT DISTINCT $table_items.order_id
FROM $table_itemmeta, $table_items, $table_posts , $table_postmeta
WHERE $table_items.order_item_id = $table_itemmeta.order_item_id
AND $table_items.order_id = $table_posts.ID
AND $table_posts.post_status IN ( $orders_statuses )
AND $table_postmeta.meta_key LIKE '_customer_user'
AND $table_postmeta.meta_value LIKE '$user_id '
AND $table_itemmeta.meta_key LIKE '_product_id'
AND $table_itemmeta.meta_value LIKE '$product_id'
ORDER BY $table_items.order_item_id DESC"
);
// return an array of Orders IDs for the given product ID
return $orders_ids;
}
Usage Example
## This will display all orders containing this product ID in a coma separated string ##
// A defined product ID: 40
$product_id = 40;
// Current User
$current_user = wp_get_current_user();
// We get all the Orders for the given product ID of current user in an arrray
$orders_ids_array = retrieve_orders_ids_from_a_product_id( $product_id, $current_user->ID );
// We display the orders in a coma separated list
echo '<p>' . implode( ', ', $orders_ids_array ) . '</p>';
I need to get post_id in wordpress from woocommerce order id or order number.
global $woocommerce, $post;
$order = new WC_Order($post->ID);
//to escape # from order id
$order_id = trim(str_replace('#', '', $order->get_order_number()));
with this code i am getting order id from post id. I have to reverse this and get post id from order id.
you do realize that an order may contain 1 or more post id right?
$order = new WC_Order( $order_id );
$items = $order->get_items();
foreach ( $items as $item ) {
//$product_name = $item['name'];
//$product_id = $item['product_id']; // post id
//$product_variation_id = $item['variation_id'];
}
Have you tried this?
$post_id = get_post($order_id)->ID;
I need to find that a particular customer has done business with that store previously.
To achieve that I need to find the number of orders by a given customer.
How can I achieve that?
I tried Googling, but did not find any solution.
Just drop in the user id and you'll get your total number of orders:
$numorders = wc_get_customer_order_count( $userid );
To go a step further for my own purposes, I use this code to get the number of a customer's non-cancelled orders since I don't want to count failed order attempts:
// Get TOTAL number of orders for customer
$numorders = wc_get_customer_order_count( $userid );
// Get CANCELLED orders for customer
$args = array(
'customer_id' => $userid,
'post_status' => 'cancelled',
'post_type' => 'shop_order',
'return' => 'ids',
);
$numorders_cancelled = 0;
$numorders_cancelled = count( wc_get_orders( $args ) ); // count the array of orders
// NON-CANCELLED equals TOTAL minus CANCELLED
$num_not_cancelled = $numorders - $numorders_cancelled;
Modifying #MarkPraschan Code, which works well for me without throwing any notice, as i got 2 notice about undefined variable $user_id and i'm not passing the code through a function. Using below code worked for me (which gets the number of order transaction minus canceled orders);
$current_user = wp_get_current_user();
$numorders = wc_get_customer_order_count( $current_user->ID );
// Get CANCELLED orders for customer
$args = array(
'customer_id' => $current_user->ID,
'post_status' => 'cancelled',
'post_type' => 'shop_order',
'return' => 'ids',
);
$numorders_cancelled = 0;
$numorders_cancelled = count( wc_get_orders( $args ) ); // count the array of orders
// NON-CANCELLED equals TOTAL minus CANCELLED
$num_not_cancelled = $numorders - $numorders_cancelled;
if you intend to display both completed and non completed orders, you will use the first two line of the above code, which is;
$current_user = wp_get_current_user();
$numorders = wc_get_customer_order_count( $current_user->ID );
Tested and working on;
WP = v4.9.9
WC = v3.5.3
I know this is an old question, but thought I'd share my code/info anyways.
The customer will be connected to the order via the postmeta key _customer_user in the wp_postmeta table.
You can lookup all orders with the status completed and processing for a specific user ID with the following query, where 279 is the user ID:
SELECT COUNT(p.ID)
FROM wp_posts AS p
INNER JOIN wp_postmeta AS m ON m.post_id = p.ID AND m.meta_key = '_customer_user' AND m.meta_value = 279
WHERE p.post_status IN ('wc-completed', 'wc-processing') AND p.post_type = 'shop_order'
When translated into PHP code that can be used on any WP installation simply by placing the code at the bottom of your theme functions.php file.
This example displays the total orders for a customer on the order page in the back-end of WordPress, directly below the customer selection/dropdown. For instance if you need to know if this is the first order a customer has placed/done you can display a message. Obviously you will want to change the order status filter to something that suits your needs. Doing a direct query like below is more efficient I believe.
// Hook into the order back-end WooCommerce > Orders > [Edit]
// The output will be placed under the dropdown to choose/connect a customer to the order
add_action('woocommerce_admin_order_data_after_order_details', 'f4d_customer_order_count');
function f4d_customer_order_count($order){
global $wpdb;
// Retrieve customer ID based on current order
$customerId = $order->get_customer_id();
// When the order was placed by a guest, just return
if($customerId===0) return;
// When the order is connected to a user/customer, query the total orders
// Database tables we will use in our query (also grab the table prefix)
$postsTable = $wpdb->prefix.'posts';
$postsMetaTable = $wpdb->prefix.'postmeta';
// Filter orders by specific status
$orderStatusFilter = array('wc-completed', 'wc-processing');
// Connect the array into a string that is compatible with our query (IN() query statement)
$orderStatusFilter = "'".implode("','", $orderStatusFilter)."'";
// Only get the single variable from the database
$totalOrders = $wpdb->get_var("
SELECT COUNT(p.ID)
FROM $postsTable AS p
INNER JOIN $postsMetaTable AS m ON m.post_id = p.ID AND m.meta_key = '_customer_user' AND m.meta_value = $customerId
WHERE p.post_status IN ($orderStatusFilter) AND p.post_type = 'shop_order'");
echo '<p class="form-field form-field-wide wc-customer-order-count">';
if($totalOrders===1){
// When this is the first order, display a message to our admin to give a first time offer
echo '<span style="color:white;background-color:red;padding:20px;">FIRST TIME OFFER</span>';
}else{
// Otherwise just display the total orders the customer has placed in the past
echo '<span>'.esc_html__( 'Total Orders', 'super-forms' ) . ': '.$totalOrders.'</span>';
}
echo '</p>';
}
If you need a list format of multiple customers/users, then you can use the $wpdb->get_results() instead of $wpdb->get_var() and loop over the results (table rows).
Found a way.
$args = [
'author' => 'id',
'post_status' => 'any',
'post_type' => 'shop_order'
];
$query = new WP_Query($args);
$orderCountByCustomer = $query->found_posts;
i had develop a phonegap application with my woocommerce store.
now i want to create order manually.
So anyone can tell me when new order is created in woocommerce store how many data inserted in which tables in database. i mean data at the time of new order generation in which table and in which fashion are they stored. Please help
A order in WooCommerce is stored as as WordPress post with post_type = 'shop_order' in the table wp_posts.
Each order item in the order is stored in wp_woocommerce_order_items, with additional information about each order item line in the table wp_woocommerce_order_itemmeta.
To add a new order:
Insert a new order into the wp_posts table
Add the requested order lines into wp_woocommerce_order_items
For each of the order lines, add the order line details into wp_woocommerce_order_itemmeta.
Example data from a MySQL dump:
INSERT INTO wp_posts VALUES (38,1,'2014-06-09 10:02:00','2014-06-09 10:02:00','','Order – June 9, 2014 # 10:02 AM','','publish','closed','closed','','order','','','2014-06-09 10:02:43','2014-06-09 10:02:43','',0,'http://example.com/?post_type=shop_order&p=38',0,'shop_order','',0);
INSERT INTO wp_woocommerce_order_items VALUES (33,'My product','line_item',38);
INSERT INTO wp_woocommerce_order_itemmeta VALUES (167,33,'_qty','1');
INSERT INTO wp_woocommerce_order_itemmeta VALUES (168,33,'_tax_class','');
INSERT INTO wp_woocommerce_order_itemmeta VALUES (169,33,'_product_id','20');
INSERT INTO wp_woocommerce_order_itemmeta VALUES (170,33,'_variation_id','');
INSERT INTO wp_woocommerce_order_itemmeta VALUES (171,33,'_line_subtotal','13');
INSERT INTO wp_woocommerce_order_itemmeta VALUES (172,33,'_line_subtotal_tax','');
INSERT INTO wp_woocommerce_order_itemmeta VALUES (173,33,'_line_total','13');
INSERT INTO wp_woocommerce_order_itemmeta VALUES (174,33,'_line_tax','');
I would recommend that you try manually creating an order in the database with the settings you want the generated order to have, that way you see the relations and the various settings that you will need to set manually.
I spent many hours on this code - so I want to share it.
It creates a new order, with one product, adds shipment to the order with the flat rate of shipment, by the postcode of the customer.
I use it to create subscription orders for my clients.
function create_order($user_id, $product_id)
{
$order = wc_create_order();
$order->set_created_via("subscription");
$product = wc_get_product($product_id);
$order->add_product($product, $quantity);
$order_id = $order->get_id();
$postcode = get_user_meta($user_id, 'shipping_postcode', true);
$package = array('destination' => array('country' => 'IL', 'postcode' => $postcode));
$zone = WC_Shipping_Zones::get_zone_matching_package($package);
$method = WC_Shipping_Zones::get_shipping_method( $zone->get_id() );
This was the hardest to find out. The get_shipping_method returns class name. The next line create instance of it.
$shipping = new $method;
Now get the price of the shipment:
$rate = new WC_Shipping_Rate();
$rate->id = 'flat_rate';
$rate->label = 'shipment';
$rate->cost = $shipping->cost;
$rate->calc_tax = 'per_order'; // Not sure about this one
// Adding it to the order
$order->add_shipping($rate);
$order->calculate_totals();
// assign the order to the current user
update_post_meta($order->get_id(), '_customer_user', $user_id);
// payment_complete
$order->payment_complete();`
Copy billing and shipment info
foreach (array('billing_first_name',
'billing_last_name',
'billing_phone',
'billing_address_1',
'billing_address_2',
'shipping_first_name',
'shipping_last_name',
'shipping_address_1',
'shipping_address_2',
'shipping_city',
'shipping_postcode') as $key) {
$values = get_user_meta($user_id, $key);
update_post_meta($order_id, "_" . $key, $values[0]);
}