Add, update or remove product custom field in WooCommerce - php

I use the following lines to save a Value to the database. I have one question regarding this code, when I delete input it still keeps it. The only way to delete that is to put (space) as input.
$field_key_pills_1 = 'custom_text_field_category_pills';
if ( isset( $_POST[$field_key_pills_1] ) && ! empty( $_POST[$field_key_pills_1] ) ) {
$attribute_pills_1 = wc_get_product( $post_id );
$attribute_pills_1->update_meta_data( $field_key_pills_1, sanitize_text_field( $_POST[$field_key_pills_1] ) );
$attribute_pills_1->save();
} else {
$attribute_pills_1 = wc_get_product( $post_id );
$attribute_pills_1 = delete_post_meta( $post_id, 'custom_text_field_category_pills' );
}
Please give me any tip that you think, can solve this problem.

Try instead the following revisited code using WC_Data delete_meta_data() method to remove product meta data (meta key + value):
$key_pills_1 = 'custom_text_field_category_pills';
$product_pills1 = wc_get_product( $post_id );
// Check that the product and the product input field exists
if ( is_a($product_pills1, 'WC_Product') && isset($_POST[$key_pills_1]) {
if ( ! empty($_POST[$key_pills_1]) ) {
$product_pills1->update_meta_data( $key_pills_1, sanitize_text_field($_POST[$key_pills_1]) ); // Set or update
} else {
$product_pills1->delete_meta_data( $key_pills_1 ); // remove
}
$product_pills1->save(); // Sync and save to database
}
It should work.

Related

Save Post and Add Post Meta Executing Twice

I'm trying to add or update two post meta on saving a post. Add if it's a new post and update if existing, but this function creates four in the database instead of two meta.
add_action( 'save_post', 'add_rewards');
global $WCFM, $WCFMmp;
function add_rewards ($product_id){
if($product_id){
$post_type = get_post_type($product_id);
if($post_type == 'product'){
$product = wc_get_product( $product_id );
$reg_price = $product->get_regular_price();
$sal_price = $product->get_sale_price();
$pric = $product->get_price();
add_post_meta($product_id,'main_reward', $reg_price);
add_post_meta($product_id,'sub_reward', $sal_price);
}
}
}
As it explains in the save_post manual, you should use save_post_{$post->post_type} which minimizes the save_post calls on other post types. It's also a good idea to check for autosave.
Also, if you use update_post_meta instead of add_post_meta you'll end up with only one instance of each. As it explains in the manual for that function, it says:
If the meta field for the post does not exist, it will be added and its ID returned.
Can be used in place of add_post_meta().
add_action( 'save_post_product', 'so71077799_add_rewards', 99, 1 );
function so71077799_add_rewards( $product_id ) {
// Check to see if we are autosaving, if so, exit.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( isset( $_POST['_regular_price'] ) ) {
update_post_meta( $product_id, 'main_reward', number_format( floatval( $_POST['_regular_price'] ), '2' ) );
}
if ( isset( $_POST['_sale_price'] ) ) {
update_post_meta( $product_id, 'sub_reward', number_format( floatval( $_POST['_sale_price'] ), '2' ) );
}
}

Woocommerce redirect after checkout based on product custom field

So i have custom text field meta in the product so that if has a url i would like to redirect users to a custom TY page after checkout. Here is my code and not redirecting!!
add_action('template_redirect', 'my_redirect_after_purchase');
function my_redirect_after_purchase() {
global $post, $wp;
$my_redirect = get_post_meta( get_the_ID(), '_my_redirect', true ); // This has the redirect URL entered in the field tested and working
if ( '' !== $my_redirect ) { // am checking here if the field is not empty
if (!empty($wp->query_vars['order-received'])) {
wp_redirect(esc_url($my_redirect));
exit;
}
}
}
I have tried few other ways but no luck too. Am guessing the query for order-recieved runs after and thus the meta returns empty?
How should i go about this? Thanks
First, you have to get order items using wc_get_order then you can get meta based on product id. Try the below code.
add_action('template_redirect', 'my_redirect_after_purchase');
function my_redirect_after_purchase() {
/* return if we are not on order-received page */
if( !is_wc_endpoint_url( 'order-received' ) || empty( $_GET['key'] ) ) {
return;
}
$order_id = wc_get_order_id_by_order_key( $_GET['key'] );
$order = wc_get_order( $order_id );
foreach( $order->get_items() as $item ) {
$my_redirect = get_post_meta( $item['product_id'] , '_my_redirect', true );
if( $my_redirect != '' ){
wp_redirect( $my_redirect );
exit;
}
}
}

Add single custom field and its static value to all Woocommerce product variations

I am trying to add a custom field and a static value to all of my variable products in Woocommerce. I have gone through other questions but they relate to creating whole new variations. I just need to add/update custom field to existing variaitons. Here is the thing I need to add in each variation postmeta: add_post_meta($variation_id, '_wc_facebook_product_image_source', 'parent_product'); I dont know how to execute for each loop for all variations.
I need to do this is because we have thousands of products being imported through a data feed (Dropshipping site). And this custom field is used to send data to Facebook for Catalogue. We need to hook an action that whenever a new variable product is added, all of it's variation has custom field in postmeta added with value as 'parent_product'. I have already added this filter to change the data for simple products. And is working perfect for all simple products. But the problem is that variable products having variations dont get this custom field.
Here is my code for simple products:
add_filter ('facebook_for_woocommerce_integration_prepare_product', 'fix_image_url', 100, 2);
function fix_image_url( $product_data, $product_id ){
if( empty( $product_data ) || empty( $product_id ) )
{
return $product_data;
}
$product_image = get_post_meta( $product_id, "_bdroppy_url", true );
if( isset( $product_image['img_url'] ) && !empty($product_image['img_url'] ) ) {
$image_override = get_post_meta($product_id, 'fb_product_image', true);
$image_option_override = get_post_meta($product_id, '_wc_facebook_product_image_source', true);
if ( empty($image_override ) )
{
add_post_meta($product_id, 'fb_product_image', $product_image['img_url'] );
}
if ( !empty($image_override ) )
{
update_post_meta($product_id, 'fb_product_image', $product_image['img_url'] );
}
if ( empty($image_option_override) )
{
add_post_meta($product_id, '_wc_facebook_product_image_source', 'custom');
}
if ( !empty($image_option_override) && $image_option_override = 'product' )
{
update_post_meta($product_id, '_wc_facebook_product_image_source', 'custom');
}
}
return $product_data;}
Would be too grateful for your help!
I think i found the answer to add for each loop of variations:
if ( $product->is_type( 'variable' ) ) {
foreach ( $product->get_visible_children() as $variation_id ) {
//gets the product variation based on its id but not used here
$get_product_variation = wc_get_product( $variation_id );
$image_option_override_var = get_post_meta($variation_id, '_wc_facebook_product_image_source', true);
if ( empty($image_option_override_var) )
{
add_post_meta($variation_id, '_wc_facebook_product_image_source', 'parent_product');
}
if ( !empty($image_option_override_var) && $image_option_override = 'product' )
{
update_post_meta($variation_id, '_wc_facebook_product_image_source', 'parent_product');
}
}}

Can't get custom fields of a woocommerce product

i am trying to get the custom fields with this function and multiply by the product price. I am getting the product price but when printing the custom fields, i am only getting zeros.. i dont understand why, i had tryed get_metadata() and get_post_custom() too.. but nothing works
function filter_woocommerce_cart_product_subtotal( $product_subtotal, $product, $quantity, $instance ) {
$fields = get_post_meta(get_the_id(), false);
$add_on = $product->get_price()*$fields[0] + $product->get_price()*$fields[1] + $product-
>get_price()*0.75*$fields[2];
return $product_subtotal + $add_on;
};
add_filter( 'woocommerce_cart_product_subtotal', 'filter_woocommerce_cart_product_subtotal', 10, 4 );
I have tryed to get single fields too but always getting zeros.
I can get the custom fields in function below and save it in a global variable but when i try to access the global variable in the function above, i get zero again.
function tour_product_add_on_cart_item_data( $cart_item, $product_id, $cart ){
/*
if( isset( $_POST['time_add_on'] ) ) {
$cart_item['time_add_on'] = sanitize_text_field( $_POST['time_add_on'] );
}
*/
if( isset( $_POST['date_add_on'] ) ) {
$cart_item['date_add_on'] = sanitize_text_field( $_POST['date_add_on'] );
}
if( isset( $_POST['place_add_on'] ) ) {
$cart_item['place_add_on'] = sanitize_text_field( $_POST['place_add_on'] );
}
if( isset( $_POST['adult_add_on'] ) ) {
$cart_item['adult_add_on'] = sanitize_text_field( $_POST['adult_add_on'] );
}
if( isset( $_POST['child_add_on'] ) ) {
$cart_item['child_add_on'] = sanitize_text_field( $_POST['child_add_on'] );
}
if( isset( $_POST['infant_add_on'] ) ) {
$cart_item['infant_add_on'] = sanitize_text_field( $_POST['infant_add_on'] );
}
$product = wc_get_product($product_id);
$GLOBALS["fee"] = $_POST['adult_add_on']*$product->get_price() +
$_POST['child_add_on']*$product->get_price() + $_POST['infant_add_on']*0.75*$product->get_price();
return $cart_item;
}
get_post_meta() second parameter is the meta key value. So you should use for example
$date_add_on = get_post_meta(get_the_id(), 'date_add_on')
So, i have resolved this issue. When you add a custom field to a woocommerce product or a wordpress post, you have to update it's meta data. Here is a good tutorial of every step you have to follow to add a custom field.
HOW TO ADD WOOCOMMERCE CUSTOM FIELDS TO A PRODUCT

Hook woocommerce price in backend order edition

I need to change item product prices in Woocommerce Backend Order. I tried tu use the following hook, but I have a problem trying to obtain the order id. Any suggestion? Thanks in advance!
function my_custom_prices ($price, $product)
{
if ( !is_admin() || ( is_admin() && is_post_type_archive() ) ) return $price;
global $post, $woocommerce;
$order = new WC_Order( $post_id );
$user_id = $order->user_id;
$user = get_user_by('id', $user_id);
if ( in_array( 'my_role', (array) $user->roles ) ) {
return $price * 2;
}
else {
return $price;
}
}
add_filter('woocommerce_get_price', 'my_custom_prices ', 10, 2);
Complete problem:
The complete problem is as follows. I am using a plugin that adds a field to the product called wholesale price. If the customer has the wholesale customer role, the order uses those prices. The plugin works fine, but it does not take the price in the backend. I talked to the author and it's something they do not plan to change yet. My client needs to modify the orders. But when it enters the backend, it takes the common price, not the wholesaler. I need to do something in the backend that allows me to detect if the order is from a client with a wholesale customer role. If yes, take the correct price when adding products. There is more information on the discussion with the author here. https://wordpress.org/support/topic/wholesale-prices-in-backend-editing-orders/ Thank you very much for the help you can give me.
Options:
woocommerce_get_price: does not work because I cannot obtain the customer id
woocommerce_ajax_add_order_item_meta: nice option, but I could not find a sample
Button: nice option, but I do not know how can I change the price. I tryed the follow:
add_action( 'woocommerce_order_item_add_action_buttons', 'action_aplicar_mayoristas', 10, 1);
function action_aplicar_mayoristas( $order )
{
echo '<button type="button" onclick="document.post.submit();" class="button button-primary generate-items">Aplicar precios mayoristas</button>';
echo '<input type="hidden" value="1" name="aplicar_mayoristas" />';
};
add_action('save_post', 'aplicar_mayoristas', 10, 3);
function aplicar_mayoristas($post_id, $post, $update){
$slug = 'shop_order';
if(is_admin()){
if ( $slug != $post->post_type ) {
return;
}
if(isset($_POST['aplicar_mayoristas']) && $_POST['aplicar_mayoristas']){
$order = wc_get_order( $post_id);
//$order_id = $order->get_user_id();
// Iterating through each "line" items in the order
foreach ($order->get_items() as $item_id => $item_data) {
//$item_data->set_subtotal("798");
$item_data->set_price("798");
//->set_price($custom_price);
}
}
}
}
Updated
The hook that you are using is not for orders, but only for products, and is made to change the displayed prices only. So you will not get the order ID with it.
You could change the price display in many hooks, but if you want to change order item prices for real (not only the displayed formatted prices), you should trigger this prices changes when order is updated for example.
In this case you can use a custom function hooked in save_post action hook:
add_action( 'save_post', 'change_order_item_prices', 11, 1 );
function change_order_item_prices( $post_id ) {
// If this is an autosave (has not been submitted).
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id;
// Check the user's permissions.
if ( 'shop_order' == $_POST[ 'post_type' ] ){
if ( ! current_user_can( 'edit_shop_order', $post_id ) )
return $post_id;
} else {
if ( ! current_user_can( 'edit_post', $post_id ) )
return $post_id;
}
## ------------------- Changing prices Start code ------------------- ##
## ===> HERE define the targeted user role
$user_role = 'my_role';
## ===> HERE define the rate multiplier (for price calculations)
$multiplier = 2;
// If this Order items prices have already been updated, we exit
$items_prices_updated = get_post_meta( $post_id, 'line_item_updated', true );
if( ! empty( $items_prices_updated ) ) return $post_id; // Exit
$order = new WC_Order( $post_id ); // Get the order object
$user_id = $order->get_user_id(); // Get the user ID
$user_data = get_userdata( $user_id ); // Get the user data
// Check the user role
if ( ! in_array( $user_role, $user_data->roles ) ) return;
// Loop through order items
foreach( $order->get_items() as $item_id => $item ){
$item_data = $item->get_data(); // The item data
$taxes = array();
foreach( $item_data['taxes'] as $key_tax => $values ){
if( ! empty( $values ) ){
foreach( $values as $key => $tax_price ){
$taxes[$key_tax][$key] = floatval($tax_price) * $multiplier;
}
}
}
$new_line_subtotal = floatval( $item_data['subtotal'] ) * $multiplier;
$new_line_subt_tax = floatval( $item_data['subtotal_tax'] ) * $multiplier;
$new_line_total = floatval( $item_data['total'] ) * $multiplier;
$new_line_total_tax = floatval( $item_data['total_tax'] ) * $multiplier;
// Update Order item prices
$item->set_subtotal($new_line_subtotal);
$item->set_subtotal_tax($new_line_subt_tax);
$item->set_total($new_line_total);
$item->set_total_tax($new_line_total_tax);
$item->set_taxes($taxes);
// Save the updated data
$item->save();
}
// Udpate order totals and cache
$order->calculate_totals();
// We mark the order as updated (to avoid repetition)
update_post_meta( $post_id, 'line_item_updated', true );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and and finally works.
I have added a security to avoid the order items to be updated twice.
The method $order->calculate_totals(); slow down the process a little bit… It's normal as it will calculate totals, update data and refresh caches.
Your code needs to be debugged.
$post_id - there is not such variable or parameter inside your function. So, use $post->ID instead.
do
var_dump( (array) $user->roles);
before the
if (in_array( 'my_role', (array) $user->roles ) )
line. And make sure that my_role exists in that array.
Temporary comment this line for debugging purpose:
// if (is_admin() && is_post_type_archive())
Then you will see the reason and able to be fix it.

Categories