It's been a couple of days now, and I can't seem to find a hook for adding/updating user meta
add_user_meta( 'user_id', 'custom_key', 'custom_value');
when creating an order in woocommerce admin (woocommerce->orders->add order), backend.
Using
add_action('woocommerce_process_shop_order_meta', 'admin_process_shop_order', 10, 1);
This works fine for doing things while the order is processed. However, I need to get the customer ID, which from what I can tell doesn't exist until the order is actually created (makes sense).
So my question is, what hook (or other solution) can I use to get the customer ID once the order is created and searchable with
get_post_meta($order_id, '_customer_user', true);
Thank you #Gugan for your suggestions! It looks like that with your help I was finally able to get this mess sorted :)
Since I only wanted this to fire one time, i.e. when the order is created (and not again when updated), I hade to combine two actions.
First 'woocommerce_process_shop_order_meta'. Here I can check if the post meta exists (if it does, the order has already been created and should be left alone)
function check_order($post_id){
$new_order = get_post_meta($post_id, '_customer_user', true);
if(!$new_order){
add_action('woocommerce_order_status_[MY_CUSTOM_ORDER_STATUS]-processing', 'total_count');
}
}add_action('woocommerce_process_shop_order_meta', 'check_order', 10, 1);
If this is a new order move on to 'woocommerce_order_status_[MY_CUSTOM_ORDER_STATUS]-processing' (with my function 'total_count')
function total_count($post_id){
$order = wc_get_order($post_id);
$customer_id = $order->get_user_id();
$user_role = get_user_meta($customer_id, 'wp_capabilities', true);
$custom = serialize(array('[MY_CUSTOM_USER_ROLE]' => true));
$today = date('Y-m-d');
if($user_role = $custom){
$current_total = get_user_meta($customer_id, 'total', true);
$increment_total = $current_total+1;
update_user_meta( $customer_id, 'total', $increment_total);
update_user_meta( $customer_id, 'last', $today);
}
}
Now I only get an increment on my custom user metas "total" and "last" if this is a new order and if the customer is of my custom user role. Another plus to this is that it will only work for one order status (i.e. in my case [MY_CUSTOM_ORDER_STATUS]-processing).
Just jotting down my solution here for anyone else looking to handle similar custom order creation work.
Related
What I tried to do:
I have several custom meta field in a custom post type. I want to retrieve the value of all the meta field with the name 'prix-du-produit' for the 'bons-plans' post type, compare them and store the lowest one inside another meta field named 'prix-promo' and do the same thing for the link attached. All of this should happen when the post is saved, published or updated.
It's basically a tool to select the best price of a product to later display it on front end with the corresponding link to the product. For now this isn't working at all and I'm all out of answer.
What I manage to understand or not
As I understood, using usort() is the best way to proceed since it will sort each array inside the first one, which is perfect for what I tried to achieve as it will allow me to select the link within corresponding to the lowest 'prix-du-produit' value. I also understood that using the publish_post hook should do the trick.
The (crappy) code:
function compare_prices($price1, $price2){
if($price1['prix-du-produit'] == $price2['prix-du-produit']){
return rand(0,1) ? 1 : -1//if it is the same then it is random
}
return $price1[0]['prix-du-produit'] > $price2[0]['prix-du-produit'];
// if not it sorts the array
}
function best_product( $id, $post ) {
if ( get_post_type($post->ID) = 'bons-plans' ) {
$products = get_post_meta( $post->ID, 'liens-produits' );
usort($products, 'compare_prices');
$lowest_price = $products[0]['prix-du-produit'];
$best_link = $products[0]['lien-du-produit'];
update_post_meta( $post->ID , 'lien-affilie' , $best_link);
update_post_meta( $post->ID , 'prix-promo' , $lowest_price);
}
}
add_action( 'publish_post', 'best_product', 10, 2 );
Keep in mind that I am still very new to PHP, so for those who are able to give me hint on what I did wrong will have to give me a precise answer.
I'm trying to make an SQL query to run upon cancellation of a booking, via a custom plugin, updating custom user meta data.
Here's my code:
function wporg_callback() {
global $wpdb;
$wpdb->query("UPDATE usermeta SET meta_value = 15 WHERE umeta_id = 131");
}
add_action('woocommerce_bookings_cancelled_booking', 'wporg_callback');
But It's not working.
Is there something wrong with the query? Is the right action not being used?
Edit - I Also tried the following without success:
add_action('woocommerce_bookings_cancelled_booking', 'wporg_callback');
function wporg_callback( $booking_id ) {
// Add/Update custom user meta data
update_user_meta( 2, 'download_credits', 17 );
}
Updated:
The correct hook to be used is woocommerce_booking_cancelled (a composite hook) that will allow you to retrieve the user ID and to Add/update custom user meta data like below:
add_action('woocommerce_booking_cancelled', 'booking_cancelled_transition_to_callback', 10, 2 );
function booking_cancelled_transition_to_callback( $booking_id, $booking ) {
// Get the user ID from the Booking ID
$user_id = get_post_field ('post_author', $booking_id);
$download_credits = get_post_meta( $booking_id, '_booking_cost', true );
// Add/Update custom user meta data
update_user_meta( $user_id, 'download_credits', $download_credits );
}
Code goes in functions.php file of your active child theme (or theme). Tested and works.
How to get the booking data (from the booking ID displayed in the order):
Go to your database under wp_postmeta table to get the desired meta_key from the post_id (that is the booking ID)
Use that meta key in get_post_meta() WordPress function like:
$meta_value = get_post_meta($booking_id, 'the_meta_key', true);
Notes:
An SQL query is not needed to add/update custom user meta data, as you can use instead the dedicated Wordpress function update_user_meta().
I couldn't make it work using woocommerce_bookings_cancelled_booking hook.
WooCommerce Bookings action and filters hooks developer documentation
Currently, LearnDash has a function (to be added to functions.php) that allows you to auto enroll a specific user in a course. I was wondering if a simple function could be added to my theme's function file and change this from user_id to a user ROLE? That way every user in that role is enrolled.
Here is the starting point: (found in the dev section on Learndash)
//* To enroll user to course:
ld_update_course_access($user_id, $course_id, $remove = false);
I have tried this:
//* Add users to course by role
ld_update_course_access($role_name = Subscriber, $course_id = 949, $remove = false);
On the "edit course" page editor I now see "1,0,12,Subscriber" inside the "course access list" but it doesn't actually work. Obviously, that access list is working with users only.
My thought process is creating a function that will:
1) Get user IDs from user role "My-Custom-Role"
2) Return IDs and update course access.
Is something like this possible?
Yep, totally possible. The get_users() function allows you to get a list of users by role. See: https://codex.wordpress.org/Function_Reference/get_users
For example:
$users = get_users( [ 'role__in' => [ 'subscriber', 'author' ] ] );
foreach ( $users as $user ) {
ld_update_course_access( $user->ID, 949, false );
}
I worked with the development team and came up with a different although incomplete solution, so I've marked Linnea's as correct, because it works as asked in the question. This solution goes through their access hook sfwd_lms_has_access, however the "course list" never gets updated so a user is not officially "enrolled" until they start the course. By this I mean, you wont see them enrolled in the course on their profile, but if they start a lesson, it all of a sudden shows up! Thought it might help to post here in case it may help anyone as a starting point.
add_filter( 'sfwd_lms_has_access', function( $return, $post_id, $user_id ) {
if ( empty( $user_id ) ) {
$user_id = get_current_user_id();
}
if(empty($user_id))
return $return;
$course_id = learndash_get_course_id( $post_id );
$allowed_course_ids = array( 949, 1135 );
if( !in_array($course_id, $allowed_course_ids))
return $return;
if(user_can($user_id, "3a_textbook"))
return true;
if(user_can($user_id, "subscriber"))
return true;
return $return;
}, 10, 3 );
I have a Woocommerce site, and I use Gravity Forms to further expand each order.
I am coding a management tool that consumes both APIs to make some statistics and other administration tools.
I can get a list of the Gravity Forms entries, and also a list of the orders. The problem I have is that I don't know how can I get the entry that is related to a particular order.
Is there a way to do this?
have you tried with the woocomerce history plugin or fetching the raw metadata out the item¿?
wc_get_order_item_meta($order_item_id, "_gravity_forms_history");
wc_get_order_item_meta($order_item_id, "_gravity_form_data");
keep in mind that this will require a new endpoint to be created is not put of the box.
The last time I worked with the WooCommerce Gravity Forms Product Addons (a year or so ago) it did not store the order ID in the entry (would have to happen after the entry is created and after the order is created), or the entry ID in the order. The latter probably makes more sense but both would require custom code.
Again, it's been some time since I worked with the add-on. I'd ping WC support and see if they any tips on implementing support for this.
This is where I found the link between WooCommerce and the gravity forms product addon:
In the database, find the order in the table your_table_prefix_posts, and grab its ID. I was filtering for the post_type "shop_order."
In the table your_table_prefix_woocommerce_order_items, find the ID just found and filter for "line_item" in the "order_item_type" column, and grab the "order_item_id."
Use that "order_item_id" to find the order's meta in the table your_table_prefix_woocommerce_order_itemmeta.
All of the order's gravity forms data is in there. It looks like there is no actual tie between what woo does and gravity, except that the form is filled out and it data is grabbed and stuck into your_table_prefix_woocommerce_order_itemmeta. I cannot find anything that ties a particular order to a particular gf entry, but you can get the data from Woo, and at least use that to search GF entries.
I was able to do this using Gravity Forms, Gravity Forms Product Addons, and Woocommerce using a three step process:
STEP 1: Get GF Entry ID/s as the entry is made and store it in a session. This happens before checkout is complete and sometimes before the user is logged in.
add_action( 'gform_after_submission', 'blb_get_lead_entry_id', 10, 2 );
function blb_get_lead_entry_id( $entry, $form ) {
$meta_value = $entry['id'];
//session array with all the entries because GF creates 2 entries each time for validation purposes apparently
if (!isset($_SESSION['entryclump'])) {
$_SESSION['entryclump'] = array();
}
$_SESSION['entryclump'][] = $meta_value;
//also an array with just the current entry which will end up be the later of the two entries added by GF
$_SESSION[ 'gf-entry-id' ] = $meta_value;
}
STEP 2: Include the entry you just gathered ($_SESSION[ 'gf-entry-id' ]) with the Cart Item Meta and then save it.
In this case, i am saving a field called "_gf_entry_ID" which will get added to the woocommerce_order_itemmeta table with the correct order_item_id and the later of the two GF entries as the meta_value.
//add cart item data
add_filter( 'woocommerce_add_cart_item_data', 'blb_add_gfentry_to_cart_data', 10, 3 );
function blb_add_gfentry_to_cart_data( $cartItemData, $productId, $variationId ) {
$entryid=$_SESSION[ 'gf-entry-id' ];
$cartItemData['GFentryID'] = $entryid;
return $cartItemData;
unset($_SESSION[ 'gf-entry-id' ]);
}
//add cart item data: session stuff
add_filter( 'woocommerce_get_cart_item_from_session', 'blb_cart_item_session', 10, 3 );
function blb_cart_item_session( $cartItemData, $cartItemSessionData, $cartItemKey ) {
if ( isset( $cartItemSessionData['GFentryID'] ) ) {
$cartItemData['GFentryID'] = $cartItemSessionData['GFentryID'];
}
return $cartItemData;
}
//save the data
add_action( 'woocommerce_add_order_item_meta', 'blb_save_gfentry', 10, 3 );
function blb_save_gfentry( $itemId, $values, $key ) {
if ( isset( $values['GFentryID'] ) ) {
wc_add_order_item_meta( $itemId, '_gf_entry_ID', $values['GFentryID'] );
}
}
STEP 3 (optional): Update the GF Form to reflect the correct created_by user ID. Now that checkout is complete and the user is logged in, we can do that.
function blb_woocommerce_thankyou( $order_id ) {
//Current User
$currentUserID = wp_get_current_user()->ID;
//GF Entry Array for Order
$order = new WC_Order( $order_id );
$items = $order->get_items();
$order_item_ids = array();
$gf_entry_ids = array();
foreach ( $items as $key=>$item ) {
$gf_entry_ids[] = $item['item_meta']['_gf_entry_ID'][0];
}
//First real quick clear all the entries in the entry clump (in case the user was already logged in)
//This is important because GF creates two forms for product add ons with Woocommerce and we only want one to show up in the list and edit plugin
$entryclump = $_SESSION[ 'entryclump' ];
foreach ( $entryclump as $entry ) {
global $wpdb;
$wpdb->update('wp_rg_lead', array('created_by' => null), array('id' => $entry));
}
//Update wp_rg_lead
if (($currentUserID!=0) && (isset($_SESSION[ 'entryclump' ])) ) {
foreach ( $gf_entry_ids as $gf_entry_id ) {
global $wpdb;
$wpdb->update('wp_rg_lead', array('created_by' => $currentUserID), array('id' => $gf_entry_id));
} //foreach
} //if
unset($_SESSION[ 'entryclump' ]);
};
add_action( 'woocommerce_thankyou', 'blb_woocommerce_thankyou', 10, 1 );
I'm trying to find a woocommerce method that will allow me to set the billing and or shipping first name.
The customer class will allow me to set some fields but not first_name. Anyone know if a method exists or do I need to just update the wp_usermeta table directly using billing_first_name.
Here is an example of what doesn't work:
global $woocommerce;
$user_first_name = get_user_meta( $user_id, 'first_name', true );
if( !empty( $woocommerce->customer->get_billing_first_name() ) ) {
$woocommerce->customer->set_billing_first_name($user_first_name); // a set_billing_first_name method doesn't exist
}
Customer in woocommerce is nothing but a Wordpress user. If you look at WC_Checkout->process_checkout() is creates a new user and then sets billing_first_name as first_name.
So to update the billing_first_name update the first_name using update_user_meta.
Hope this helps!