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;
Related
There is a custom post named 'project' and has acf fields.
The tile of the each post is user name.
user name is from logged in users' email id.
Eg, post title is jeff (jeff#gmail.com).
When a user Jeff purchased a product, I need to automatically add ‘50’ in the ACF field ‘field_690d1eis5xx89’ of the Jeff post.
The code to check whether a user purchased a product or not, works well:
function has_bought( $value = 0 ) {
if ( ! is_user_logged_in() && $value === 0 ) {
return false;
}
global $wpdb;
// Based on user ID (registered users)
if ( is_numeric( $value) ) {
$meta_key = '_customer_user';
$meta_value = $value == 0 ? (int) get_current_user_id() : (int) $value;
}
// Based on billing email (Guest users)
else {
$meta_key = '_billing_email';
$meta_value = sanitize_email( $value );
}
$paid_order_statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
$count = $wpdb->get_var( $wpdb->prepare("
SELECT COUNT(p.ID) FROM {$wpdb->prefix}posts AS p
INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $paid_order_statuses ) . "' )
AND p.post_type LIKE 'shop_order'
AND pm.meta_key = '%s'
AND pm.meta_value = %s
LIMIT 1
", $meta_key, $meta_value ) );
// Return a boolean value based on orders count
return $count > 0 ? true : false;
}
This code doesn't update 50 to the acf field of the logged in user's post after the user purchased a product.
I tried both title and post_title but it still doesn't update.
I'm not sure but, maybe due to the $post->ID?
if( has_bought() ){
$current_user = wp_get_current_user();
$current_user_id = $current_user->display_name;
// query to get a post with the user
$args = array(
'post_type' => 'project',
'posts_per_page' => -1,
'title' =>$current_user_id
); // end $args
$query = new WP_Query($args);
// if posts are returned, update field
if ($query->have_posts()) {
global $post;
update_field('field_690d1eis5xx89', '50', $post->ID);
} else {
return;
}
} // end if have_posts
I’m a beginner, would you please help me?
Thank you
As per the documentation the update_field function accepts three parameter i.e. $selector $value and $post_id but it looks like in you code you are using $current_user_id which I think might not work.
Try to add $post_id in place of $current_user_id
Check: https://www.advancedcustomfields.com/resources/update_field/
I am using WordPress and WooCommerce and have an SQL query to call meta tags for a specific product type.
function get_last_order_id_from_product( $product_id ) {
global $wpdb;
return $wpdb->get_col( $wpdb->prepare( "
SELECT oi.order_id
FROM {$wpdb->prefix}woocommerce_order_items as oi
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta as oim
ON oi.order_item_id = oim.order_item_id
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta as oim2
ON oi.order_item_id = oim2.order_item_id
LEFT JOIN {$wpdb->posts} AS p
ON oi.order_id = p.ID
WHERE p.post_type = 'shop_order'
AND oi.order_item_type = 'line_item'
AND oim.meta_key = '_product_id'
AND oim.meta_value = '%d'
AND oim2.meta_key = 'Ticket Number'
ORDER BY SUBSTRING_INDEX(oim2.meta_value, ' ', 10) DESC
LIMIT 1
", $product_id ) );
}
The code above takes a product id and outputs the meta tag, my issue arose when I realized that when a user buys more than a single quantity the meta value it creates for the 'Ticket Number' key is '10 11' which mysql views as a single string. I tried breaking it apart using SUBSTRING_INDEX as shown above but it wont view any orders past the first.
I need it to view the numbers as individual numbers so if a user buys ten of the item it can recognise the last number as the highest (say 21 22 23 24) and the next user to buy this product the sql query will recognise the 24 from the string as the highest number and make the new items meta be 25.
Here is my function as well if it is of any use, it currently runs but is only working from the meta value of 1 however many of the product is bought:
add_action('woocommerce_order_status_processing', 'action_woocommerce_order_status_completed');
function action_woocommerce_order_status_completed($order_id) {
$order = new WC_Order($order_id);
$items = $order->get_items();
foreach ($items as $key => $value) {
$get_last_order = get_last_order_id_from_product( 10 );
if ($get_last_order == null){
$gen_id_1 = "0";
} else {
$get_order_id = implode($get_last_order);
$lastorder = wc_get_order($get_order_id);
$lastitem = $lastorder->get_items();
foreach ($lastitem as $key2 => $value2) {
$custom_thing = $value2->get_meta('Ticket Number');
}
$gen_ids = explode(' ', $custom_thing);
$gen_id_1 = end($gen_ids);
}
$qua = $value->get_quantity();
for ($x = 1; $x <= $qua; $x++) {
$gen_id_1++;
$gen_id_2 .= " $gen_id_1";
};
$value->add_meta_data( "Ticket Number", $gen_id_2);
$value->save();
}
}
There is a different way, much more easy and efficient to make that work.
When an order change to processing status:
First, for each order item, I increase the number of tickets sold (item quantity) as an index at the product level (saved/updated as custom product meta data).
Then for each order item, I generate from the related product index (before updating it) the tickets numbers based on the item quantity, that I save as custom order item meta data.
And to finish, for each order item, I update the related product "index" adding the quantity sold to the current "index" value.
The code (commented):
add_action( 'woocommerce_order_status_processing', 'action_woocommerce_order_status_processing', 10, 2 );
function action_woocommerce_order_status_processing( $order_id, $order ) {
// Loop through order items
foreach ($order->get_items() as $item_id => $item ) {
// Check that tickets numbers haven't been generated yet for this item
if( $item->get_meta( "_tickets_number") )
continue;
$product = $item->get_product(); // Get the WC_Produt Object
$quantity = (int) $item->get_quantity(); // Get item quantity
// Get last ticket sold index from product meta data
$now_index = (int) $product->get_meta('_tickets_sold');
$tickets_ids = array(); // Initializing
// Generate an array of the customer tickets Ids from the product registered index (last ticket ID)
for ($i = 1; $i <= $quantity; $i++) {
$tickets_ids[] = $now_index + $i;
};
// Save the tickets numbers as order item custom meta data
$item->update_meta_data( "Tickets numbers", implode(' ', $tickets_ids) ); // Displayed string of tickets numbers on customer orders and emails
$item->update_meta_data( "_tickets_number", $tickets_ids ); // (Optional) Array of the ticket numbers (Not displayed to the customer)
$item->save(); // Save item meta data
// Update the Ticket index for the product (custom meta data)
$product->update_meta_data('_tickets_sold', $now_index + $quantity );
$product->save(); // Save product data
}
$order->save(); // Save all order data
}
Code goes in functions.php file of your active child theme (active theme). Tested and works.
The _tickets_number hidden custom order item meta data is optional and allow you to get the array of tickets, instead of a string of tickets using: $item->get_meta('_tickets_number');
If you want a global ticket system (not at product level) you will use the following instead:
add_action( 'woocommerce_order_status_processing', 'action_woocommerce_order_status_processing', 10, 2 );
function action_woocommerce_order_status_processing( $order_id, $order ) {
// Loop through order items
foreach ($order->get_items() as $item_id => $item ) {
$now_index = (int) get_option( "wc_tickets_number_index"); // Get last ticket number sold (globally)
$quantity = (int) $item->get_quantity(); // Get item quantity
$tickets_ids = array(); // Initializing
// Generate an array of the customer tickets Ids from the tickets index
for ($i = 1; $i <= $quantity; $i++) {
$tickets_ids[] = $now_index + $i;
};
// Save the tickets numbers as order item custom meta data
$item->update_meta_data( "Tickets numbers", implode(' ', $tickets_ids) ); // Displayed string of tickets numbers on customer orders and emails
$item->update_meta_data( "_tickets_number", $tickets_ids ); // (Optional) Array of the ticket numbers (Not displayed to the customer)
$item->save(); // Save item meta data
// Update last ticket number sold (globally)
update_option( 'wc_tickets_number_index', $now_index + $quantity );
}
$order->save(); // Save all order data
}
Code goes in functions.php file of your active child theme (active theme). It should work.
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 am trying to get the order id in the file /woocommerce/emails/customer-new-account as I needed it for a function of mine.
I tried
global $wp;
$order_id = $wp->query_vars['order-received'];
=> this outputs NULL
ALSO
$order = new WC_Order($post->ID);
$order_id = trim(str_replace('#', '', $order->get_order_number()));
=> this outputs a total different ID than the order id that customer placed.