I have a ACF select field with a field name of "sales_rep". It is populated with:
John Doe
Bart Simpson
Eric Cartman
The field is set to show on the "User Form" and only show when the "Current User Role" is an admin.
The field shows on each user page and I can manually change it to the sales rep I want and save it.
The issue is that I want to be able to programmatically update it whenever the user profile is saved. I will eventually add more code to determine the sales rep but I simplified the issue for this post.
Below is my code in functions.php:
Attempt 1: No error and no change to value
// Update sales rep
add_action( 'edit_user_profile_update', 'update_rep' );
add_action( 'personal_options_update', 'update_rep' );
function update_rep( $user_id )
{
update_user_meta( $user_id, 'sales_rep', 'Eric Cartman' );
}
Attempt 2: No error and no change to value
// Update sales rep
add_action( 'edit_user_profile_update', 'update_rep' );
add_action( 'personal_options_update', 'update_rep' );
function update_rep( $user_id )
{
$field_key = "sales_rep";
$value = array("Eric Cartman");
update_field( $field_key, $value, $user_id );
}
Seems like user_ prefix could fix the issue.
Try to get/update fields with user_ prefix.
F.e:
update_field( $field_key, $value, "user_$user_id" );
And for update_user_meta,
Calling delete_user_meta before could solve the problem.
User meta could have duplicate keys.
Try this one
delete_user_meta( $user_id, $field_key );
add_user_meta( $user_id, $field_key, $value );
I think #Andrii Kovalenko is right, user_ prefix could be your issue.
Also noticed you are saving acf field data as an array("Eric Cartman").
I am assuming your ACF select field predefined select options look like this...
John Doe
Bart Simpson
Eric Cartman
This should work for your acf option...
// is run when you edit YOUR profile, and save it
add_action('personal_options_update', 'handle_user_profile_update' );
// is run when you edit ANY OTHER profile and save it
add_action('edit_user_profile_update', 'handle_user_profile_update' );
// on user profile update function handler
function handle_user_profile_update($user_id) {
// update sales rep
update_sales_rep_field($user_id);
// add anymore on user update profile functions here...
}
// update sales rep field
function update_sales_rep_field($user_id) {
// our values
$value = 'Eric Cartman';
// update acf user field by user id
update_field('sales_rep', $value, 'user_' . $user_id);
}
Out of curiosity, are these sales reps actually users in your wordpress site?
If so you can dynamically populate the select sales_rep user field with sales rep users on your site like this...
function render_sales_rep_select_field($field) {
// reset sales_rep select field choices
$field['choices'] = [];
// get users with user role sales
$args = array(
'role' => 'sales', // your sales reps user role
'orderby' => 'user_nicename',
'order' => 'ASC'
);
// get user with args from above
$users = get_users( $args );
// for each sales rep user
foreach ( $users as $user ) {
// build our sales rep select field choices by user_id > full name
$field['choices'][$user->id] = $user->first_name . ' ' . $user->last_name
}
// return the select field
return $field;
}
// load user field with our custom select drop of sales rep users
add_filter('acf/load_field/name=sales_rep', 'render_sales_rep_select_field');
With this method you won't need to update the field when the user saves changes to their profile.
For example if you get_field like this...
// get user field sales rep array
get_field('sales_rep', 'user_' . $user_id ); // random user id
it will return an array of user_id and full name...
Array
(
[5] => Eric Cartman
)
In your acf user select field settings you will need select return both value and label.
Related
I'm looking for a way to extend the search field in WooCommerce admin orders list for a custom meta key. Currently i'm using the woocommerce_shop_order_search_fields filter hook.
Resulting in this code, which allows me to search by the user id, order total and order number.
add_filter( 'woocommerce_shop_order_search_fields', 'woocommerce_shop_order_search_order_total' );
function woocommerce_shop_order_search_order_total( $search_fields ) {
$search_fields[] = '_order_total';
$search_fields[] = '_user_id';
$search_fields[] = '_order_number';
return $search_fields;
}
However, these are all existing meta keys, what if I want to search for meta data that doesn't yet exist? Any adivce?
Expanding the search in WooCommerce admin orders list can be done very easily by using the woocommerce_shop_order_search_fields filter hook, you just need to add some post_meta fields for order (item(s)). As long as this data exists of course!
By default, the following metakeys are present:
_billing_address_index
_shipping_address_index
_billing_last_name
_billing_email
So, for example, if you want to extend the search by the billing first name, you can do this by simply adding the metakey _billing_first_name, and then you get:
function filter_woocommerce_shop_order_search_fields( $search_fields ) {
// Metakey
$search_fields[] = '_billing_first_name';
return $search_fields;
}
add_filter( 'woocommerce_shop_order_search_fields', 'filter_woocommerce_shop_order_search_fields', 10, 1 );
Now, what if this metadata is not present for the orders? You could add that specific metadata for future orders, when the order is created. But wait! what about the existing orders? for these orders this data would not exist!
Wouldn't it be useful if we could add this data to existing orders, or even newer orders. Well this is possible, namely by using wc_get_orders(), to get (and update) the existing orders before running the search.
So you get: (where we in this example add the user's nickname as meta data to orders)
function filter_woocommerce_shop_order_search_fields( $search_fields ) {
// The desired meta key
$meta_key = '_user_nickname';
// Get ALL orders where a certain meta key not exists
$orders = wc_get_orders( array(
'limit' => -1, // Query all orders
'meta_key' => $meta_key, // Post meta_key
'meta_compare' => 'NOT EXISTS', // Comparison argument
));
// NOT empty
if ( ! empty ( $orders ) ) {
// Loop through the orders
foreach ( $orders as $order ) {
// Get the desired information via the order object
// Get user
$user = $order->get_user();
// User is NOT empty
if ( ! empty ( $user ) ) {
// Get nickname from user
$meta_value = $user->nickname;
// Meta value is NOT empty
if ( ! empty ( $meta_value ) ) {
// Add the meta data
$order->update_meta_data( $meta_key, $meta_value );
$order->save();
}
}
}
}
// Metakey
$search_fields[] = $meta_key;
return $search_fields;
}
add_filter( 'woocommerce_shop_order_search_fields', 'filter_woocommerce_shop_order_search_fields', 10, 1 );
I'm looking for a way to display the last ordered product on another page.
I think it would be possible to maybe create a shortcode in the functions that takes the order details and displays them wherever I add the shortcode.
But I can't seem to figure out how to get it to work. So far I got this information to work with:
add_shortcode( 'displaylast', 'last' );
function last(){
$customer_id = get_current_user_id();
$order = wc_get_customer_last_order( $customer_id );
return $order->get_order();
}
[displaylast] is currently showing me noting. It does work when I change get_order() to get_billing_first_name().
That displays the order name. But I can't seem to get the item that was bought. Maybe there is a get_() that I'm not seeing?
You are close, however you must obtain the last product from the order object.
So you get:
function last() {
// Not available
$na = __( 'N/A', 'woocommerce' );
// For logged in users only
if ( ! is_user_logged_in() ) return $na;
// The current user ID
$user_id = get_current_user_id();
// Get the WC_Customer instance Object for the current user
$customer = new WC_Customer( $user_id );
// Get the last WC_Order Object instance from current customer
$last_order = $customer->get_last_order();
// When empty
if ( empty ( $last_order ) ) return $na;
// Get order items
$order_items = $last_order->get_items();
// Latest WC_Order_Item_Product Object instance
$last_item = end( $order_items );
// Get product ID
$product_id = $last_item->get_variation_id() > 0 ? $last_item->get_variation_id() : $last_item->get_product_id();
// Pass product ID to products shortcode
return do_shortcode("[product id='$product_id']");
}
// Register shortcode
add_shortcode( 'display_last', 'last' );
SHORTCODE USAGE
In an existing page:
[display_last]
Or in PHP:
echo do_shortcode('[display_last]');
I'm trying to add some custom meta_data to a WooCommerce Order, by running a Order action.
Here is my code:
function custom_add_order_actions( $actions ){
global $theorder;
$actions['my_custom_action'] = 'My custom action';
return $actions;
}
add_action( 'woocommerce_order_actions', 'custom_add_order_actions' );
function custom_add_single_action( $order ){
// Non of these change anything on the order
$order->set_billing_first_name( 'A new test name' );
$order->update_post_meta( 'a_test_field', 'Test field value' );
update_post_meta( $order->get_id(), 'a_test_field', 'Some other value' );
// $order->save(); // I even tried adding this as well, but it doesn't change anything.
}
add_action( 'woocommerce_order_action_my_custom_action', 'custom_add_single_action' );
How do I change the order (or specifically, post_meta fields for an order) from inside an action?
A example
Imagine that I add a post_meta field, with the field name (key): a_test_field.
It's currently an ACF-field, but it's the same for regular WordPress custom fields.
If I change the value of the field and press 'Update', then the value changes:
So far so good. Now the value of the field is 'Foobar'.
What's wierd is that even if I do this:
add_action( 'woocommerce_order_action_my_custom_action', 'custom_add_single_action' );
function custom_add_single_action( $order ){
update_post_meta( $order->get_id(), 'a_test_field', 'A new value' );
die(); // This die is vital, to make the change in the database.
}
Then I can see the value change in the database to 'A new value'.
But if I just do this:
add_action( 'woocommerce_order_action_my_custom_action', 'custom_add_single_action' );
function custom_add_single_action( $order ){
$order->update_post_meta( 'a_test_field', 'A new value' );
// No die(); here...
}
Then the value remains 'Foobar' in the database.
Sorry but the following lightly revisited code works (Selecting the action and click on the button arrow):
add_action( 'woocommerce_order_actions', 'add_custom_order_action' );
function add_custom_order_action( $actions ){
$actions['my_custom_action'] = __('My custom action', 'WooCommerce');
return $actions;
}
add_action( 'woocommerce_order_action_my_custom_action', 'triggered_custom_order_action' );
function triggered_custom_order_action( $order ){
$order->update_meta_data( '_test_1_custom_field', 'AAFFBB9977' );
$order->save();
update_post_meta( $order->get_id(), '_test_2_custom_field', 'Some other value' );
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Note: Order actions are mostly used for some other things than what you are trying to do.
Now when using a meta box with an input field (as you are showing), on submit, you should save that field value using the action hook save_post_shop_order like in those related threads:
Metabox with multi checkbox in WooCommerce admin single orders
Dynamic custom order numbers based on payment method
Metabox with multiple custom fields for WooCommerce admin order pages
I'm making a wordpress plugin that needs to grab the user's name on registration when integrated with BuddyPress. Unfortunately, the Name field never returns anything. The following code runs in the user_register hook.
add_action( 'user_register', 'ts_api_registration_save', 9999999, 1 );
function ts_api_registration_save($user_id)
{
$info = get_userdata($user_id);
$name = bp_profile_field_data( array( 'field' => 'Name', 'user_id' => $info->ID));
}
Unfortunately $name is always empty. I have checked the database, and the Name field is the only one in bp_xprofile_fields, so I know it exists.
I have also confirmed that $info->ID is not empty, and it correctly contains a user id. Any idea why this isn't working?
In the mean time I have been able to do this to get what I want:
$results = $GLOBALS['wpdb']->get_results( 'SELECT * FROM ' . $wpdb->prefix . "bp_xprofile_fields WHERE name = 'Name'" );
$fullName = $_POST["field_" . $nameFieldId];
But this is not optimal.
This function only works in the context of a user profile page: bp_profile_field_data
Instead, try using xprofile_get_field_data
Also - the 'user_register' hook probably runs too early.
Try using one of these hooks:
bp_core_signup_user
bp_signup_pre_validate
bp_signup_usermeta
Try to use xprofile_get_field_data() instead of bp_profile_field_data()
For example:
$name = xprofile_get_field_data( 'Name', $user_id, $multi_format = 'comma' );
echo $name;
http://hookr.io/functions/xprofile_get_field_data/
Another solution
Try to pass the field id rather than the field name.
$value = xprofile_get_field_data($field_id, $user_id);
You can get the field id by looking at the url in wp-admin when you edit that field, or just rolling over the edit button.
I'm looking to add a custom field into my users section of the wordpress admin, I have a registration field that has an input for company, i can see the company value in the wp_usermeta table but need to get it in the users column in the admin, any ideas on how to achieve this?
You will need to add action and filter hooks for showing custom value in users table. Place the following into your theme's functions.php. Notice: 'PLACE COLUMN NAME HERE' and 'PLACE META KEY HERE':
function add_custom_column_name($columns) {
$columns['columns_array_name'] = 'PLACE COLUMN NAME HERE:';
return $columns;
}
function show_custom_column_values($value, $column_name, $user_id) {
if ( 'columns_array_name' == $column_name )
return get_user_meta( $user_id, 'PLACE META KEY HERE', true );
return $value;
}
add_filter('manage_users_columns', 'add_custom_column_name');
add_action('manage_users_custom_column', 'show_custom_column_values', 10, 3);