Update all variations prices of a variable product in Woocommerce - php

I need to get all variation id and update price in loop.
Simple query and loop looks like:
$params = array(
‘posts_per_page’ => -1,
‘post_type’ => ‘product_variation’,
‘post_parent’ => $product->get_id() // tried $post-ID
);
$variations = get_posts( $params );
foreach ( $variations as $variation ) {
$variation_ID = $variation->ID; // tried $post-ID, $product->get_id()
$regular_price=34;
update_post_meta( $variation_ID, ‘_regular_price’, (float)$regular_price );
update_post_meta( $variation_ID, ‘_price’, (float)$regular_price );
}
This doesn't seem to work:
(‘post_parent’ => $product->get_id())
Neither does this:
($variation_ID = $variation->ID;).

First in your code ‘ or ’ should be replaced by '.
Also if used $post-ID should be replaced by $post->ID
Depending on where and how you are using this code, you should try to include global $post; first to be able to use the WP_Post object $post.
Then you could try to use this customized version of your code instead:
global $post;
$regular_price = 13;
// Only for product post type
if( $post->post_type == 'product' )
$product = wc_get_product( $post->ID ); // An instance of the WC_Product object
// Only for variable products
if( $product->is_type('variable') ){
foreach( $product->get_available_variations() as $variation_values ){
$variation_id = $variation_values['variation_id']; // variation id
// Updating active price and regular price
update_post_meta( $variation_id, '_regular_price', $regular_price );
update_post_meta( $variation_id, '_price', $regular_price );
wc_delete_product_transients( $variation_id ); // Clear/refresh the variation cache
}
// Clear/refresh the variable product cache
wc_delete_product_transients( $post->ID );
}
This code is tested on WooCommerce version 3+ and works

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' ) );
}
}

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');
}
}}

Trying to change purchase-button text if has term category + is variable WooCommerce

Everything works good if I remove the && $product->is_type( 'variable' )
However, when I add that line, the first if, doesn't seem to work. What am I doing wrong?
Expecting: If product is in category "farsk-ved" and is a variable product, the text should be "Välj längd". So all the single products, should go to the "else" section ("Köp").
What is happening: All products, except the "elseif" part, is getting "köp".
add_filter( 'woocommerce_product_add_to_cart_text', 'custom_loop_add_to_cart_button', 20, 2 );
function custom_loop_add_to_cart_button( $button_text ) {
// BELOW set the product categoty slug and the product ID
$product = new WC_Product( get_the_ID() );
if ( has_term( 'farsk-ved', 'product_cat') && $product->is_type( 'variable' )) {
$button_text = __("Välj längd", "woocommerce");
}
elseif ( has_term( 'torr-ved', 'product_cat') ) {
$button_text = __("Välj mängd", "woocommerce");
}
else {
$button_text = __("Köp", "woocommerce");
}
return $button_text;
}
The real way: the WC_Product Object is directly included for woocommerce_product_add_to_cart_text filter hook as 2nd argument (and missing from your function code):
add_filter( 'woocommerce_product_add_to_cart_text', 'custom_loop_add_to_cart_button', 20, 2 );
function custom_loop_add_to_cart_button( $button_text, $product ) { // <== the missing argument
// BELOW set the product category Id, slug or name
if ( has_term( 'farsk-ved', 'product_cat') && $product->is_type( 'variable' ) ) {
$button_text = __("Välj längd", "woocommerce");
}
elseif ( has_term( 'torr-ved', 'product_cat') ) {
$button_text = __("Välj mängd", "woocommerce");
}
else {
$button_text = __("Köp", "woocommerce");
}
return $button_text;
}
Tested and works.
If you use $product = new WC_Product( get_the_ID() ); and $product->is_type( 'variable' ) it will return bool(false)
If you use $product = new WC_Product( get_the_ID() ); and $product->get_type() it will return simple for all products including variable type.
So you just need to use like this,
$product = new WC_Product_Variable($product_id);
if ( has_term( 'farsk-ved', 'product_cat') && $product->get_type()=='variable') {
I think this will help.
So the solution was to replace $product = new WC_Product( get_the_ID() );
with global $product;

Woocommerce coupon code for personalized customer

I have generated coupon code dynamically for each customer when they purchasing a product from the website and i have set certain conditions.
When I have dynamically created a coupon code, it stored in woocommerce > coupons section.
function couponCodeGeneration($order_id, $i){
// Get the order ID
$coupon_code = $order_id."".$i; // Coupon Code
$amount = '100%'; // Amount
$discount_type = 'percent'; // Type: fixed_cart, percent, fixed_product, percent_product
wp_coupon_exist( $coupon_code );
if( wp_coupon_exist( $coupon_code ) ) {
//coupon code exists.
} else {
//coupon code not exists, so inserting coupon code
$coupon = array(
'post_title' => $coupon_code,
'post_content' => '',
'post_status' => 'publish',
'post_author' => 1,
'post_type' => 'shop_coupon'
//'post_category' => array(1)
);
$new_coupon_id = wp_insert_post( $coupon );
//SET THE PRODUCT CATEGORIES
wp_set_object_terms($post_id, 'Holiday Season offers', 'product_cat');
// Add meta
update_post_meta( $new_coupon_id, 'discount_type', $discount_type );
update_post_meta( $new_coupon_id, 'coupon_amount', $amount );
update_post_meta( $new_coupon_id, 'individual_use', 'yes' );
update_post_meta( $new_coupon_id, 'product_ids', '' );
update_post_meta( $new_coupon_id, 'exclude_product_ids', '' );
update_post_meta( $new_coupon_id, 'usage_limit', '1' );
update_post_meta( $new_coupon_id, 'expiry_date', '2019-07-31' );
update_post_meta( $new_coupon_id, 'apply_before_tax', 'yes' );
update_post_meta( $new_coupon_id, 'free_shipping', 'no' );
update_post_meta( $new_coupon_id, 'limit_usage_to_x_items', '1' );
update_post_meta( $new_coupon_id, 'usage_limit_per_user', '1' );
update_post_meta( $post_id, 'times', '1' );
echo '<div class="couponCode"><strong>Your Coupon Code for your next purchase - '.$coupon_code.'</strong><hr></div>';
}
}
I need help in the following situation.
The generated coupon code should not be used by another customer. The coupon only personal to that customer. Coupon code cannot be transferred.
When customer placing an order, the generated coupon code not stored in admin orders page. How do I know which coupon code is generated by which customer.
Can someone give me a suggestions.
Since Woocommerce 3 your code is really outdated, with a lot of mistakes. wp_coupon_exist() function doesn't exist.
To restrict the coupon to a specific customer, you can use Email restrictions WC_Coupon method that will also allow you to know which customer has generated the coupon code.
You could also set a some custom meta data if needed saving the user ID or the user complete name.
So there is two functions in my code:
The first one that checks if the coupon code doesn't exist
The second one that generate the coupon code as you planned.
The code:
// Utility function that check if coupon exist
function does_coupon_exist( $coupon_code ) {
global $wpdb;
$value = $wpdb->get_var( "
SELECT ID
FROM {$wpdb->prefix}posts
WHERE post_type = 'shop_coupon'
AND post_name = '".strtolower($coupon_code)."'
AND post_status = 'publish';
");
return $value > 0 ? true : false;
}
function coupon_code_generation( $order_id, $i ){
$coupon_code = $order_id."".$i; // Coupon Code
// Check that coupon code not exists
if( ! does_coupon_exist( $coupon_code ) ) {
// Get a new instance of the WC_Coupon object
$coupon = new WC_Coupon();
// Get the instance of the WC_Order object
$order = wc_get_order( $order_id );
## --- Coupon settings --- ##
$discount_type = 'percent'; // Type
$coupon_amount = '100'; // Amount
$customer_email = array( $order->get_billing_email() ); // Customer billing email
$product_categories_names = array('Holiday Season offers');
$date_expires = '2019-07-31';
// Convert to term IDs
$term_ids = array();
foreach( $product_categories_names as $term_name ) {
if ( term_exists( $term_name, 'product_cat' ) )
$term_ids[] = get_term_by( 'name', $term_name, 'product_cat' )->term_id;
}
## --- Coupon settings --- ##
// Set the necessary coupon data
$coupon->set_code( $coupon_code );
$coupon->set_discount_type( 'percent' );
$coupon->set_amount( 100 );
if( is_array($term_ids) && sizeof($term_ids) > 0 )
$coupon->set_product_categories( $term_ids );
$coupon->set_email_restrictions( $customer_email );
$coupon->set_individual_use( true );
$coupon->set_usage_limit( 1 );
$coupon->set_usage_limit_per_user( 1 );
$coupon->set_limit_usage_to_x_items( 1 );
$coupon->set_date_expires( date( "Y-m-d H:i:s", strtotime($date_expires) ) );
// Save the data
$post_id = $coupon->save();
}
echo isset($post_id) && $post_id > 0 ? sprintf(
'<div class="couponCode"><strong>%s <code>%s</code></strong>.<hr></div>',
__("Your Coupon Code for your next purchase is", "woocommerce"), $coupon_code
) : __("Sorry, a coupon code already exist.", "woocommerce");
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
You will get an output something like (when the coupon is generated):
Your Coupon Code for your next purchase is 1198A
Or if coupon exist:
Sorry, a coupon code already exist.
I have fixed my issue.
Add the following code in functions.php
add_filter( 'woocommerce_coupon_is_valid', 'wc_riotxoa_coupon_is_valid', 20, 2 );
if ( ! function_exists( 'wc_riotxoa_coupon_is_valid' ) ) {
function wc_riotxoa_coupon_is_valid( $result, $coupon ) {
$user = wp_get_current_user();
$restricted_emails = $coupon->get_email_restrictions();
return ( in_array( $user->user_email, $restricted_emails ) ? $result : false );
}
}
Ref: https://gist.github.com/riotxoa/f4f1a895052c195394ba4841085a0e83

Sort a Woocommerce product variations custom output by their price

Bellow I have a custom shortcode function based on this answer code that displays a block of product data for both Simple products and each variation of a Variable product. The output of the variation blocks seems to be ordered by the ID of the variation itself.
For example, this is a screenshot of the frontend output:
Which you can see matches the order of the variation IDs (from smallest to largest) screenshot:
What I would like is to sort the variations by their prices instead (NOT by their IDs) from lowest to highest. Any help is appreciated.
This is the current customized code that I have:
add_shortcode("price_variation_table", "fs_custom_available_variations_table");
function fs_custom_available_variations_table( $atts ) {
global $post;
// Attributes
$atts = shortcode_atts(
array(
'id' => $post->ID
),
$atts, 'price_variation_table'
);
if( is_admin() ) return; // Only on front end
$product = wc_get_product($atts['id']); // Get the WC_Product Object
$output = '<div class="fs-product-data-wrapper">';
// Variable products
if( $product->is_type('variable'))
{
// Get available variations in the variable product
$available_variations = $product->get_available_variations();
if( count($available_variations) > 0 ){
foreach( $available_variations as $variation )
$output .= fs_format_product_data_output( $variation['variation_id'] );
}
}
// Simple products
elseif( $product->is_type('simple'))
{
$output .= fs_format_product_data_output( $product->get_id() );
}
else return; // Exit
return $output .= '</div>'; // return always for a shortcode
}
// Utility funtion: getting and formtting product data
function fs_format_product_data_output( $the_id ){
$empty = __( '<em>(empty)</em>', 'woocommerce' );
// Get an instance of the WC_Product_Variation object
$product = wc_get_product( $the_id );
// Only wc_get_price_to_display() respect if product is to be displayed with or without including taxes
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) );
$sale_price = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) );
$sale_price = ! empty( $sale_price ) ? wc_price($sale_price) : $empty;
// can use this class is there is no sale price set
if ( ! $product->is_on_sale() ) {
$no_sale_price = ' no-sale-price';
}
$size = $product->get_attribute( 'pa_size' );
$size = ! empty( $size ) ? get_term_by( 'slug', $size, 'pa_size' )->name : $empty;
$stock_qty = $product->get_stock_quantity();
$stock_qty = ! empty( $stock_qty ) ? $stock_qty : '0';
if ( $stock_qty <= 0 ) {
$stock_status = 'stock-sold-out';
}
else {
$stock_status = 'stock-available';
}
$output = '
<ul class="'. $stock_status .'">
<li class="fs-data-price">'.$price.' ea.</li>
<li class="fs-data-size">Size: '.$size.'</li>
<li class="fs-data-sale'. $no_sale_price .'">'.$sale_price.' ea. Preferred customer price</li>
<li class="fs-data-stock">Quantity in Stock: '.$stock_qty.'</li>
<li class="fs-data-notice">Quantities change quickly!</li>
</ul>';
return $output;
}
Try the following lightly changed code, where each displayed variations will be sorted by regular price (low to high):
add_shortcode("price_variation_table", "custom_available_variations_table");
function custom_available_variations_table( $atts ) {
global $post;
// Attributes
$atts = shortcode_atts(
array(
'id' => $post->ID
),
$atts, 'price_variation_table'
);
if( is_admin() ) return; // Only on front end
$product = wc_get_product($atts['id']); // Get the WC_Product Object
$output = '<div class="fs-product-data-wrapper">';
// Variable products
if( $product->is_type('variable'))
{
// Get available variations in the variable product
$available_variations = $product->get_available_variations();
if( count($available_variations) > 0 ){
$variations_ids = array();
// First loop - set variations Ids in an array with regular prices
foreach( $available_variations as $variation ){
$product = wc_get_product( $variation['variation_id'] );
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) );
$variations_ids[$variation['variation_id']] = $price;
}
// Sorting variation Ids using prices from lower to highest
natsort($variations_ids);
// 2nd Loop - Display formatted variation data
foreach( array_keys($variations_ids) as $variations_id ){
$output .= format_product_data_output( $variations_id );
}
}
}
// Simple products
elseif( $product->is_type('simple'))
{
$output .= format_product_data_output( $product->get_id() );
}
else return; // Exit
return $output .= '</div>'; // return always for a shortcode
}
// Utility funtion: getting and formatting product data
function format_product_data_output( $the_id ){
$empty = __( '<em>(empty)</em>', 'woocommerce' );
// Get an instance of the WC_Product_Variation object
$product = wc_get_product( $the_id );
// Only wc_get_price_to_display() respect if product is to be displayed with or without including taxes
$price = wc_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ) );
$sale_price = wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) );
$sale_price = ! empty( $sale_price ) ? wc_price($sale_price) : $empty;
$size = $product->get_attribute( 'pa_size' );
$size = ! empty( $size ) ? get_term_by( 'slug', $size, 'pa_size' )->name : $empty;
$no_sale_price = ! $product->is_on_sale() ? ' no-sale-price' : '';
$size = $product->get_attribute( 'pa_size' );
$size = ! empty( $size ) ? get_term_by( 'slug', $size, 'pa_size' )->name : $empty;
$stock_qty = $product->get_stock_quantity();
$stock_qty = ! empty( $stock_qty ) ? $stock_qty : '0';
$stock_status = $stock_qty <= 0 ? 'stock-sold-out' : 'stock-available';
$output = '
<ul class="'. $stock_status .'">
<li class="fs-data-price">'.$price.' ea.</li>
<li class="fs-data-size">Size: '.$size.'</li>
<li class="fs-data-sale'. $no_sale_price .'">'.$sale_price.' ea. Preferred customer price</li>
<li class="fs-data-stock">Quantity in Stock: '.$stock_qty.'</li>
<li class="fs-data-notice">Quantities change quickly!</li>
</ul>';
return $output;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Categories