How to update similar variation stock after purchase in Woocommerce - wordpress

I struggle to find a way to update the stock of the similar variation of a product.
All my product have, say, a main variation, "Black" (30$) or "white" (250$) but sometimes they have another variation which is a "date start", so date_start:"12th june", date_start: "30th july", etc. I need to update the stock of the "date" variation when it's present (if there is no date, woocommerce update the main stock, no problem).
If someone choose "Black"+"12th June" I need the stock of "12 June" to be decreased also for "white"...
Before someone ask, "black" and "white" have different price per product... And "date" change also per product, that's why I need to use variation (and not addon attribute with a plugin).
Maybe someone have a better idea for organising this, but I try many other solution, always a caveat. This one seems the simpler, just have to find the good "hook" and "code"
Here is some pseudo code I made for this:
if(Product is sold):
VarSoldVariation = getSoldVariation(product->ID);
OtherVariationWithSameDate = getVariations (VarSoldVariation->pa_dates);
foreach(OtherVariationWithSameDate)updateStockVariation();
endif;

OK, it seems a little weird for not using metadata/attributes for this case, instead of variations. However, I've done more unusual stuff with variations than this one, so without judging your decision:
At first, you have to find a suitable action hook which fires after an order takes place. Some of them are:
woocommerce_order_status_$STATUS_TRANSITION[from]_to_$STATUS_TRANSITION[to]
woocommerce_order_status_$STATUS_TRANSITION[to] (e.g. woocommerce_order_status_completed)
woocommerce_order_status_changed
woocommerce_payment_complete
woocommerce_thankyou
Update 2:
I rewrite the code with some improvements:
In my initial answer, I used a WordPress get_posts function (which uses WP_Query) with a meta_query parameter, which you should definitely change to tax_query in this case, due to performance considerations. And we also know that it's better practice to use wc_get_products and WC_Product_Query where it's possible. However in this case it's not even needed to do a direct post query on db and it's possible to get the variations from get_available_variations method of WC_Product_Variable
Now it checks for quantity on order item and uses it on other date variations stock update.
Now it uses WC classes and functions wherever is possible, instead of direct updating of metadata, stock quantity, stock status, etc.
The Updated Code:
add_action('woocommerce_order_status_processing', 'sync_variations_stock');
/**
* Update same date variations on customer order place
* #param $order_id
* #return void
*/
function sync_variations_stock($order_id)
{
if (is_admin()) return; // make sure it's a user order and we aren't on admin dashboard
$order = wc_get_order( $order_id );
foreach( $order->get_items() as $item ) {
if ($item->get_type() !== 'line_item') continue; //if $item is not a product or variation
$order_variation_count = $item->get_quantity();
$order_product_id = $item->get_product_id();
$order_variation_id = $item->get_variation_id();
if ( ! $order_variation_id ) continue; // if the item isn't a variation
$order_variation = wc_get_product($order_variation_id);
$order_variation_attribs = $order_variation->get_variation_attributes();
if ( isset($order_variation_attribs['attribute_pa_date']) ) {
$current_date_attrib = $order_variation_attribs['attribute_pa_date'];
} else {
continue; // stop if the variation in the order doesn't have 'pa_date' attrib
}
$product = wc_get_product( $order_product_id );
$variations = $product->get_available_variations();
foreach ( $variations as $variation ) {
if ( $variation['variation_id'] == $order_variation_id ) {
continue; //if this variation is the one we have in our order
}
if ( ! isset( $variation['attributes']['attribute_pa_color'] ) || !isset( $variation['attributes']['attribute_pa_date'] ) ) {
continue; //if this variation does not have the color or date attrib
}
if ( $variation['attributes']['attribute_pa_date'] == $current_date_attrib ) {
/*
* wc_update_product_stock function sets the stock quantity if the variation stock management is enabled
* NOTE: This function may cause a negative stock even if the variation backorder is set to false
*/
wc_update_product_stock( $variation['variation_id'], $order_variation_count, 'decrease' );
wc_delete_product_transients($variation['variation_id']); // Clear/refresh the variation cache (optionally if needed)
}
}
}
}
Tested and It's Working!
My First Answer:
For this example, I will use the last one. However you should be careful about this hook, since it fires on every page load of the 'WC Thank You page'. It would be a good idea to use one of these hooks instead:
woocommerce_order_status_processing
woocommerce_order_status_completed
woocommerce_payment_complete
Final code would be something like this:
add_action('woocommerce_thankyou', 'sync_variations_stock');
function sync_variations_stock($order_id)
{
$order = wc_get_order( $order_id );
foreach( $order->get_items() as $item ){
$product_id = $item->get_product_id();
$product_variation_id = $item->get_variation_id();
if (!$product_variation_id) return; // if the item isn't a variation
$date_variation = get_post_meta( $product_variation_id, 'attribute_pa_date', true);
$color_variation = get_post_meta( $product_variation_id, 'attribute_pa_color', true);
if ( ! $date_variation && ! $color_variation ) return; //if the variation doesn't have date and color attributes
$args = array(
'post_parent' => $product_id,
'post_type' => 'product_variation',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => 'attribute_pa_date',
'value' => $date_variation,
'compare' => '='
),
array(
'key' => 'attribute_pa_color',
'value' => $color_variation,
'compare' => '!='
)
),
);
$other_date_variations = get_posts($args);
if( is_array($other_date_variations) && !empty($other_date_variations) ){
foreach ($other_date_variations as $date_variation) {
// do your stock updating proccess here. (updateStockVariation() as you write in your code)
$variation_id = $date_variation->ID;
$date_variation_stock = (int) get_post_meta( $variation_id, '_stock', true);
if ($date_variation_stock > 0) { //to prevent backorders
$date_variation_stock = $date_variation_stock - 1;
update_post_meta($variation_id, '_stock', $date_variation_stock);
// if the variation is now out-of-stock, set it as so
if ($date_variation_stock === 0) {
update_post_meta($variation_id, '_stock_status', 'outofstock');
wp_set_post_terms( $variation_id, 'outofstock', 'product_visibility', true );
}
}
}
}
}
}
Note: You have to replace attribute_pa_date & attribute_pa_color to match your attribute slugs.
Update 1
There are other consideration in this topic. WC Variation stock quantities may be changed in other senarios and circumstances, such as order edit on dashboard, order refunds, direct product edit, etc. Before going live, you have to think about these too.
Whoever as I said, there may be other ways to do what you are trying to. But I couldn't understand your setup and the relation between your variations and the dates. I think it's better to ask a approach related question for this, on WB.SE

I also just made a small change. In your code, if people refresh the page, the stock of the other variation are decreased... As woocommerce will always decrease the stock of the bought variation first, I go get this stock variation number and update other one with it. So I'm sure everything stays the same. :)
Here is the code updated:
function sync_variations_stock($order_id)
{
if (is_admin()) return; // make sure it's a user order and we aren't on admin dashboard
$order = wc_get_order( $order_id );
foreach( $order->get_items() as $item ) {
if ($item->get_type() !== 'line_item') continue; //if $item is not a product or variation
$order_variation_count = $item->get_quantity();
$order_product_id = $item->get_product_id();
$order_variation_id = $item->get_variation_id();
if ( ! $order_variation_id ) continue; // if the item isn't a variation
$order_variation = wc_get_product($order_variation_id);
$order_variation_attribs = $order_variation->get_variation_attributes();
if ( isset($order_variation_attribs['attribute_pa_dates']) ) {
$current_date_attrib = $order_variation_attribs['attribute_pa_dates'];
//Get the stock of the current variation for updating others.
$new_stock = $order_variation->get_stock_quantity();
} else {
continue; // stop if the variation in the order doesn't have 'pa_dates' attrib
}
$product = wc_get_product( $order_product_id );
$variations = $product->get_available_variations();
foreach ( $variations as $variation ) {
if ( $variation['variation_id'] == $order_variation_id ) {
continue; //if this variation is the one we have in our order
}
if ( ! isset( $variation['attributes']['attribute_pa_admissible-emploi-quebec'] ) || !isset( $variation['attributes']['attribute_pa_dates'] ) ) {
continue; //if this variation does not have the color or date attrib
}
if ( $variation['attributes']['attribute_pa_dates'] == $current_date_attrib ) {
/*
* wc_update_product_stock function sets the stock quantity if the variation stock management is enabled
* NOTE: This function may cause a negative stock even if the variation backorder is set to false
*/
//wc_update_product_stock( $variation['variation_id'], $order_variation_count, 'decrease' );
//Update stock of other variation with the stock number of the one just bought
wc_update_product_stock( $variation['variation_id'], $new_stock, 'set' );
wc_delete_product_transients($variation['variation_id']); // Clear/refresh the variation cache (optionally if needed)
}
}
}
}

Related

Breadcrumbs on product page don't reflect current url/slug when using multiple categories for product

My Wordpress site uses Woocommerce for products to sell. But when you assign multiple product categories to a product and visit the product page (with Product Permalinks set to Shop base with category), something unexpected is happening. The breadcrumb link to the (parent) category is always the same one and does not reflect the navigated url. (This is the same problem as described here.)
Problem in summary:
Navigate to
Breadcrumb link
Expected breadcrumb link
/shop/category-1/sample-product/
category-2
category-1
/shop/category-2/sample-product/
category-2
category-2
I found no real answer on any source that fixes this. (I think it should be fixed, but some might say it's for SEO reasons, preventing duplicate site contents.) So to help anyone searching for the answer, here it is:
What's going (wr)on(g)?
The breadcrumbs on the product page are produced by the woocommerce_breadcrumb() function. Which in turn gets it through WC_Breadcrumb->generate().
Traversing further in the code, you end up inside the add_crumbs_single() function where the woocommerce_breadcrumb_product_terms_args filter is applied to the ordering of the product terms fetch. (See wp_get_post_terms and WP_Term_Query::__construct() for more info on this.)
It's clear from the code, that they prioritize the term with the highest parent value, in other words, the term with the latest added parent in the database.
Solution 1
Since this will always be the same for this product, you might want to add a filter to your theme's function.php (or using a custom plugin) that will overwrite this behavior. I got mine working using this:
function prioritize_current_url_cat_in_breadcrumbs( $args ) {
// Only if we're on a product page..
if ( is_product() ) {
// ..and there's a product category slug in the navigated url..
$product_cat_slug = get_query_var( 'product_cat', '' );
if ( ! empty($product_cat_slug) ) {
// ..which we can find
$product_cat = get_term_by( 'slug', $product_cat_slug, 'product_cat', ARRAY_A );
if ( ! empty($product_cat) ) {
// Then only get that current product category to start the breadcrumb trail
$args['term_taxonomy_id'] = $product_cat['term_taxonomy_id'];
}
}
}
return $args;
}
add_filter( 'woocommerce_breadcrumb_product_terms_args', 'prioritize_current_url_cat_in_breadcrumbs' );
The rest of the add_crumbs_single() function will take care of traversing the category's parents etc up 'till Home.
Solution 2
Alternatively, you could use the woocommerce_breadcrumb_main_term filter to change the 'main term' used for the breadcrumb trail. The filter function receives 2 arguments: the main term (as WP_Term) and an array of WP_Terms with all product categories found. And it returns one term, so you can search through the array and pick the right one you want to start the breadcrumbs with.
function prioritize_current_url_cat( $first_term, $all_terms ) {
if ( is_product() ) {
$product_cat_slug = get_query_var( 'product_cat', '' );
if ( ! empty($product_cat_slug) ) {
// Get the WP_Term with the current slug
$filtered_terms = array_values( array_filter($all_terms, function($v) use ($product_cat_slug) {
return $v->slug === $product_cat_slug;
}) );
if ( ! empty($filtered_terms) ) {
return $filtered_terms[0];
}
}
}
// Fallback to default
return $first_term;
}
add_filter( 'woocommerce_breadcrumb_main_term', 'prioritize_current_url_cat', 10, 2 );
Hope this helps anyone searching for hours and working through lines of source code..!
Extra: Fix permalinks on archive pages as well
For tackling the same problem on the product archive pages, you can hook into the post_type_link filter and pre-emptively replace the %product_cat% part of the permalink with the correct slug like so:
/**
* Set product link slugs to match the page context,
* for products with multiple associated categories.
*
* For example:
* when viewing Category A, use '/category-a/this-product/'
* when viewing Category B, use '/category-b/this-product/'
*/
function my_plugin_product_url_use_current_cat( $post_link, $post, $leavename, $sample ) {
// Get current term slug (used in page url)
$current_product_term_slug = get_query_var( 'product_cat', '' );
if ( empty ( $current_product_term_slug ) ) {
return $post_link;
}
if ( is_product_category() ) {
// Get current term object
$current_product_term = get_term_by( 'slug', $current_product_term_slug, 'product_cat' );
if ( FALSE === $current_product_term ) {
return $post_link;
}
// Get all terms associated with product
$all_product_terms = get_the_terms( $post->ID, 'product_cat' );
// Filter terms, taking only relevant terms for current term
$matching_or_descendant_terms = array_filter( array_map( function( $term ) use ( $current_product_term ) {
// Return term if it is the current term
if ( $term->term_id === $current_product_term->term_id ) {
return [ TRUE, $term ];
}
// Return term if one of its ancestors is the current term (highest hierarchy first)
$parent_terms = array_reverse( get_ancestors( $term->term_id, 'product_cat' ) );
foreach ( $parent_terms as $parent_term_id ) {
if ( $parent_term_id === $current_product_term->term_id ) {
return [ FALSE, $term ];
}
}
// Leave out all others
return NULL;
}, $all_product_terms ) );
if ( count( $matching_or_descendant_terms ) > 0 ) {
// Sort terms (directly associated first, descendants next)
usort( $matching_or_descendant_terms, function( $a, $b ) {
if ( $a[0] === $b[0] ) {
return 0;
} else if ( TRUE === $a[0] ) {
return -1;
} else {
return 1;
}
} );
// Get entire slug (including ancestors)
$slug = get_term_parents_list( $matching_or_descendant_terms[0][1]->term_id, 'product_cat', [
'format' => 'slug',
'separator' => '/',
'link' => false,
'inclusive' => true,
] );
// Set url slug to closest child term of current term
// or current term (if directly associated)
$post_link = str_replace('%product_cat%/', $slug, $post_link);
}
} else if ( is_product() ) {
$post_link = str_replace('%product_cat%', $current_product_term_slug, $post_link);
}
return $post_link;
}
add_filter( 'post_type_link', 'my_plugin_product_url_use_current_cat', 10, 4 );
Explanation
As #Markos mentioned, we tried to figure out the most logical and intuitive way to do this.
Basically, it checks if the current product category (slug from the url) is directly associated with the displayed product. If so, use that slug for the link to the product page. (Using one of the solutions above, the breadcrumbs reflect the url path for intuitive navigation.)
If the current viewed product category is not directly associated with the product, it looks for the first matching descendant (sub) category and uses that slug for the link to the product page.
This way, the user always sees how they came on the current product page and can easily navigate back to the category.
Note: If this snippet doesn't change anything, try an earlier hook priority and/or check whether the $post_link variable contains the %product_cat% template part.
After a lengthy chat with Philip and troubleshooting scenarios when a shop has multiple layers of categories (thank you Philip) I found the following approach for the permalinks working for me.
function my_plugin_product_url_use_current_cat( $post_link, $post, $leavename, $sample ) {
if ( is_product_category() || is_product() ) {
$product_cat_slug = get_query_var( 'product_cat', '' );
// get all the category of products
$terms = get_the_terms ( $post->ID, 'product_cat' );
foreach($terms as $term){
$term_slug = $term->slug;
// check if category page belongs to the category of the product
if($term_slug == $product_cat_slug){
$post_link = str_replace('%product_cat%', $term_slug, $post_link);
return $post_link;
}
// or category page is a parent category of the product
else{
$all_parents = get_ancestors($term->term_id, 'product_cat');
foreach($all_parents as $cat_id){
$cat_term = get_term( $cat_id, 'product_cat' );
if($cat_term->slug == $product_cat_slug){
$post_link = str_replace('%product_cat%', $term_slug, $post_link);
return $post_link;
}
}
}
}
}
return $post_link;
}
add_filter( 'post_type_link', 'my_plugin_product_url_use_current_cat', 9, 4 );

Stop WooCommerce For Reducing Stock On Abandoned Admin New Order

If an admin goes to create an order but abandons it, the stock level is still reduced.
Steps to reproduce:
install WordPress
install WooCommerce
create simple product and tick "manage stock?" and set stock level to 10
view on front-end (see screenshot before.png)
as admin create new order but don't save it (new -> order -> add item -> exit page)
view on front-end (see screenshot after.png)
Notice stock level has been reduced even those order wasn't saved.
Is there anyway to avoid this?
Before.png:
After.png
I have worked on this issue and wrote a basic code for that.
Hooks used: "woocommerce_order_item_add_action_buttons" for Admin Order Add Item(s) and "woocommerce_process_shop_order_meta" for Admin Order Creation/Update.
First part: Stop reducing stocks of items that added while the order has not been created.
// define the woocommerce_order_item_add_action_buttons callback
function action_woocommerce_order_item_add_action_buttons( $order ) {
$orderID = $order->ID;
//check if this is the admin manual order creation
if(get_post_status($orderID) == "auto-draft" && get_post_type($orderID) == "shop_order")
{
foreach( $order->get_items() as $item_id => $item )
{
$product_id = $item->get_product_id();
$variation_id = $item->get_variation_id();
$product_quantity = $item->get_quantity();
if($variation_id == 0)
{
$product = wc_get_product($product_id);
wc_update_product_stock($product, $product_quantity, 'increase');
}
else
{
$variation = wc_get_product($variation_id);
wc_update_product_stock($variation, $product_quantity, 'increase' );
}
// The text for the note
$note = __("Stock incremented due to the auto draft post type. Stock for each item will be decremented when this order created.");
// Add the note
$order->add_order_note( $note );
}
}
};
// add the action
add_action( 'woocommerce_order_item_add_action_buttons', 'action_woocommerce_order_item_add_action_buttons', 10, 1 );
Second Part: Reduce stocks of items that added if order is created.
add_action( 'woocommerce_process_shop_order_meta', 'woocommerce_process_shop_order', 10, 2 );
function woocommerce_process_shop_order ( $post_id, $post ) {
$order = wc_get_order( $post_id );
//check if this is order create action, not an update action
if(get_post_status($post_id) == "draft" && get_post_type($post_id) == "shop_order")
{
foreach( $order->get_items() as $item_id => $item )
{
$product_id = $item->get_product_id();
$variation_id = $item->get_variation_id();
$product_quantity = $item->get_quantity();
if($variation_id == 0)
{
$product = wc_get_product($product_id);
wc_update_product_stock($product, $product_quantity, 'decrease');
}
else
{
$variation = wc_get_product($variation_id);
wc_update_product_stock($variation, $product_quantity, 'decrease' );
}
// The text for the note
$note = __("Stock decremented for all items in this order.");
// Add the note
$order->add_order_note( $note );
}
}
}
Tested and works fine. I hope this will help you. Have a good day.

Get Woocommerce variation attributes

I am trying to get variations of a variable product on custom product page. I have two attributes, one for sizes as select and the other for colors as swatches. The problem that I cannot display the attribute that I need to display, and when I use the following code it returns a text names of sizes or colors not the select dropdown for sizes or the colors swatches. Any help please ?!
echo implode(', ', wc_get_product_terms( $product_id, 'pa_colors' ));
This is a brief code to solve your question, I let you entire code, you can use only that you need.
The first is check if get_product function exists, and check the product type, to create a correct product object with the id (in my case $idProduct).
It work on woocommerce 3.x, I don't test it on woocommerce < 3.x.
if( function_exists('get_product') ) {
$product = get_product( $idProduct );
if ( $product->is_type( 'variable' ) ) {
$product = new WC_Product_Variable( $idProduct );
$available_variations = $product->get_available_variations(); //get all child variations
$variation_variations = $product- >get_variation_attributes(); // get all attributes by variations
// taxonomy => terms
// pa_attribute-color => array('blue', 'red', green)
// Use ex: get_taxonomy('pa_attribute-color')->labels; to get the Name and not the slug to attributes, it can be the taxonomy
// Use ex: get_term_by('name', 'pa_attribute-color', 'pa_attribute-color); to get the Name/label
$result = array( $available_variations , $attributes); // only to see the result you can use var_dump, error_log, etc.
//...
//...
}elseif ( $product->is_type( 'bundle' ) && class_exists( 'WC_Product_Bundle' ) ) {
$product = new WC_Product_Bundle( $idProduct );
}else{
$product = new WC_Product( $idProduct );
}
}
Also you try with:
$product->get_attribute( $key );
wc_attribute_label($key);
where $key can be pa_color , pa_size, etc
I hope help you.

Set Wordpress excerpt and post thumbnail based on custom field

As stated in the title, I would like to automatically save/update the value of post_excerpt and post_thumbnail based on an ACF custom field (mostly for compatibily reasons with other plugins). Now, while tring to accomplish this I encountered 2 issues, first being with the following function:
function test_FeaturedImageSetByACF() {
$current_screen = get_current_screen(); // Current admin screen needed to identify the current cpt
$current_cpt_name = $current_screen->post_type; // Current cpt name
$current_cpt_support = 'thumbnail'; // We want to check if the CPT supports this feature
$post_id = get_the_ID(); // Current post ID
$post_image_field = get_field('post_head_img'); // ACF field we want to sync
$post_image_id = $post_image_field['id']; // ACF image filed ID
$post_image_url = $post_image_field['url']; // ACF image filed URL
// If current cpt supports thumbnails/featured images
if ( post_type_supports( $current_cpt_name, $current_cpt_support ) ) {
if ( ( $post_image_url ) AND ( ( $post_image_url ) != ( get_the_post_thumbnail() ) ) ) {
delete_post_thumbnail( $post_id );
set_post_thumbnail( $post_id, $post_image_id );
}
}
}
add_action('save_post', 'test_FeaturedImageSetByACF', 13, 2 );
add_action('publish_post', 'test_FeaturedImageSetByACF', 10, 2 );
It does work, however sometimes it seems to update the value only the second time I save (which means I have to save twice). I understand I'm either using a wrong hook, a wrong priority or something like that, but I can't figure out which one it is.
Second issue I have, is I would like to accomplish something similar for post excerpts. Now the functions's will look alike the previous one quite a lot, but I don't know which value to update. Can anyone point me in the right direction?
Thanks in advance
You can use acf/save_post hook. Object ID is passed
add_action('acf/save_post', 'handle_acf', 20);
function handle_acf($object_id)
{
// Do your stuff
}
Since this became more of an ACF specific question rather than a generic one, I decided to post on ACF's support forums aswell were user John Huebner pointed me in the right direction. For anyone interested, the topic can be found at https://support.advancedcustomfields.com/forums/topic/set-wordpress-excerpt-and-post-thumbnail-based-on-custom-field/ while (in the event that post may get deleted or something) this is the code I used both for the excerpt part and the custom post thumbnail/featured image:
add_action('save_post', 'flex_CustomExcerptSetByACF', 50);
function flex_CustomExcerptSetByACF() {
global $post;
$post_id = ( $post->ID ); // Current post ID
$post_excerpt = get_field( 'post_excerpt', $post_id ); // ACF field
if ( ( $post_id ) AND ( $post_excerpt ) ) {
$post_array = array(
'ID' => $post_id,
'post_excerpt' => $post_excerpt
);
remove_action('save_post', 'flex_CustomExcerptSetByACF', 50); // Unhook this function so it doesn't loop infinitely
wp_update_post( $post_array );
add_action( 'save_post', 'flex_CustomExcerptSetByACF', 50); // Re-hook this function
}
}
add_action('save_post', 'flex_FeaturedImageSetByACF', 50);
function flex_FeaturedImageSetByACF() {
$current_screen = get_current_screen(); // Current admin screen needed to identify the current cpt
$current_cpt_name = $current_screen->post_type; // Current cpt name
$current_cpt_support = 'thumbnail'; // We want to check if the CPT supports this feature
global $post;
$post_id = ( $post->ID ); // Current post ID
$post_image_field = get_field('post_head_img', $post_id ); // ACF field
if ( ( $post_id ) AND ( $post_image_field ) ) {
$post_image_id = $post_image_field['id']; // ACF image filed ID
$post_image_url = $post_image_field['url']; // ACF image filed URL
// If current cpt supports thumbnails/featured images
if ( post_type_supports( $current_cpt_name, $current_cpt_support ) ) {
if ( ( $post_image_url ) AND ( ( $post_image_url ) != ( get_the_post_thumbnail() ) ) ) {
update_post_meta($post_id, '_thumbnail_id', $post_image_id);
}
}
}
}

Wordpress variable, user created, woocommerce product

Basically I am interested in using woocommerce to sell a product . This product is a Print Order of a external printing service that I have implemented in a brand new plugin.
What I want now is after the order, is to be able to put that "order" in the buy cart, and buy it normally as just another woocommerce product.
The product has to be created on the fly, manually by a way of some function that I can use to create a product during a certain workflow point.
Can you help me to find a solution?
Using woocommerce or not!
What i understand from your requirement/comments is that you want to be able to dynamically create a product, which is bad idea. But here is my suggestion.
Lets say you have a simple product called "Print Job" with a price of $1 and with an id of 10. And i am supposing that your external printing service would send back a response with the order and the price of printing, lets say $64.
Once you recieve the response you can simply call add_product_to_cart(10), this will automatically add the print job product to your cart.
/************* functions.php ***************/
function add_product_to_cart($product_id) {
if ( ! is_admin() ) {
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
You also need to add this function in your functions.php, this function will override the price of the product i.e "Print Job" with the actual price of $64.
/******************* Functions.php ****************/
add_action( 'woocommerce_before_calculate_totals', 'override_printing_price' );
function override_printing_price( $cart_object ) {
$custom_price = 64;
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->price = $custom_price;
}
}

Resources