My Goal: I am using WooCommerce with WCVendor plugin. All vendors have a taxonomy of location. Similarly all products publish by them have taxonomy called 'Product Location'. When vendors add new product, they have to select their location(s) everytime. Now, I would like to run a program that will update their product's location(s) according to their location.
I have managed to get a snippet by searching online -
add_action( 'added_post_meta', 'mp_sync_on_product_save', 10, 4 );
add_action( 'updated_post_meta', 'mp_sync_on_product_save', 10, 4 );
function mp_sync_on_product_save( $meta_id, $post_id, $meta_key, $meta_value ) {
if ( $meta_key == '_edit_lock' ) { // we've been editing the post
if ( get_post_type( $post_id ) == 'product' ) { // we've been editing a product
$product = wc_get_product( $post_id );
// Find the locations of author and save it as product's location
}
}
}
Can anyone please help?
Thank you.
Related
I'm customizing Woocommerce plugin, trying to remove decimals from product variation prices in product detail page.
Ex- if someone select option i want to display the regular and sales prices without decimals and the other locations of site like shop, cart, checkout no need to change.
I found this filter but it change prices of whole site.
add_filter( 'woocommerce_price_trim_zeros', '__return_true' );
https://snipboard.io/GXgtUi.jpg
anyone have idea or solution about archive this, Thanks a lot
You can try below code snippet into your theme function.php file
add_filter( 'formatted_woocommerce_price', 'ums_remove_zero_decimals', 10, 5 );
function ums_remove_zero_decimals( $formatted_price, $price, $decimal_places, $decimal_separator, $thousand_separator ) {
$product_id = get_the_ID();
$product = wc_get_product( $product_id );
if( is_single()) {
if($product->is_type( 'variable' )) {
return (int) round( $price );
}
else {
return ( $formatted_price);
}
}
}
Let me know if this works for you or not.
I am adding a custom field to woocommerce product variations to attach additional product categories to product variations. Everything works, during the save process the terms are updated in wp_term_relationships table however, a bit later in the save operation the terms are overwritten again with the parent product ones.
I am using the following code:
add_action( 'woocommerce_save_product_variation', 'save_custom_field_variations', 99, 2 );
function save_custom_field_variations( $variation_id, $i ) {
$custom_categories = $_POST['variation_product_cat'][$variation_id];
if ( isset( $custom_categories ) && !empty( $custom_categories )) {
wp_set_post_terms( $variation_id, $custom_categories, 'product_cat' );
}
}
I have also tried a different hook with the same result:
add_action( 'woocommerce_update_product', 'save_custom_field_variations_2', 99, 1 );
function save_custom_field_variations_2( $post_id ) {
foreach($_POST['variation_product_cat'] as $variation_id => $custom_categories)
if ( isset( $custom_categories ) && !empty( $custom_categories )) {
$response = wp_set_post_terms( $variation_id, $custom_categories, 'product_cat' );
}
}
Any tips on what process is overwriting my changes are very welcome!
Turns out it was one of the plugins that was overwriting the changes (found out by disabling all and then enabling them one by one)
I made a new post type named "sub_products" containing the meta tag "unit_price".
After assigning a new field for every Woocommerce product containing a list of all the "sub_products" posts, the goal was to update every product price based on the selected "sub_products" meta "unit_price".
function kulcskron_edit_post( $p1, $p2 )
{
if ( !is_admin() )
return;
if ( get_post_type() != 'product' )
return;
$sub_product_ids = $p2->get_meta( 'sub_products' );
if ( empty($sub_product_ids) )
return;
$product_regular_price = 0;
foreach ( $sub_product_ids as $id )
$product_regular_price += get_post_meta( $id, 'unit_price', true );
if ( $p1 == $product_regular_price )
return;
$p2->set_regular_price( $product_regular_price );
$p2->save();
}
add_action( 'woocommerce_product_get_price', 'kulcskron_edit_post', 10, 2 );
I tried every possible hook to make this work:
add_action( 'the_post', 'kulcskron_edit_post', 9, 1 );
add_action( 'edit_post', 'kulcskron_edit_post', 10, 2 );
add_action( 'pre_get_posts', 'kulcskron_edit_post' );
add_action( 'save_post', 'kulcskron_edit_post' );
This code updates the price but in a strange way:
Admin single product edit view: The price is not updated right away, just after I revisit the edit screen.
Admin product listing view: Every price is 0.
Front-end product page view: The displayed price is 0.
How do I update the product price based on the assigned "sub_products" "unit_price" post meta when a single product is saved in admin view?
You may use the hook "woocommefrce_get_price_html" it should work
I managed to solve the price update problem.
I used the save_post action:
save_post is an action triggered whenever a post or page is created or updated, which could be from an import, post/page edit form, xmlrpc, or post by email.
The final code:
function kulcskron_update_product( $product_obj )
{
if ( !is_admin() )
return;
if ( get_post_type() != 'product' )
return;
$product = wc_get_product( $product_obj );
if ( !$product->meta_exists( 'sub_products' ) )
return;
$sub_product_ids = $product->get_meta( 'sub_products' );
if ( empty($sub_product_ids) )
return;
_update_product_price( $product_obj, $sub_product_ids );
}
add_action( 'save_post', 'kulcskron_update_product' );
And for the sake of completeness here is the rest of code:
function _update_product_price( $product_obj, $sub_product_ids )
{
$product = wc_get_product( $product_obj );
$product_regular_price = 0;
foreach ( $sub_product_ids as $id )
$product_regular_price += get_post_meta( $id, 'kulcskron_unit_price', true );
$product->set_regular_price( $product_regular_price );
$product->set_price( $product_regular_price );
$product->save();
}
This way basically everything can be edited and updated. Example:
function _update_product_stock( $product_obj, $sub_product_ids )
{
$product = wc_get_product( $product_obj );
$sub_product_stocks = array();
foreach ( $sub_product_ids as $id )
$sub_product_stocks[] = get_post_meta( $id, 'kulcskron_free_stock_quantity', true );
$product->set_manage_stock( true );
$product->set_stock_quantity( min($sub_product_stocks) );
$product->save();
}
I would love to post a link to all the methods to edit a product but I have no rep for that.
But sadly this is not all...
In order to fully update the price, we need to filter the price HTML to return the newly updated price.
function kulcskron_price_html( $priceHtml, $product )
{
$symbol = get_woocommerce_currency_symbol();
$price = $product->get_regular_price();
$html = '<span class="woocommerce-Price-amount amount">'. $price .' <span class="woocommerce-Price-currencySymbol">'. $symbol .'</span></span>';
return $html;
};
add_filter( 'woocommerce_get_price_html', 'kulcskron_price_html', 10, 2 );
A little backstory. We need to sync all the products from an external database through an XML file. But there is a catch, the XML file only contains product parts and they are not displayed, searched, filtered and certainly can't be ordered individually. None of the Woocommerce build in functionality meet these requirements.
In order to solve this, I registered a new post type and imported all the product parts into this newly created post type. After that, I registered a new field for every WC Product with the Advanced Custom Fields plugin.
It looks like this:
Newly registered custom post type with the custom fields
The code above makes easy to update the WC Products (e.g. Prices) based on the selected Sub products.
I have issue with updating of product price from external database. I need to check price of product in every access to this position. For that I use the_post hook. For example I got '1718' price value for single product.
function chd_the_post_action( $post ) {
if ( $post && $post->post_type == 'product' ) {
$product = wc_get_product( $post->ID );
if ( $product ) {
$price = '1718';
$product->set_price( "$price" );
$product->set_regular_price( "$price" );
$product->set_sale_price( "$price" );
$product->save();
}
}
}
This code update product price in database, but it's not change view of price on page in the same moment, but only after page reload because post and product variables was setup by setup_postdata().
Therefore I use woocommerce hook for display updated price:
function chd_get_price_filter( $price, $item ) {
return '1718';
}
add_filter( 'woocommerce_product_get_price', 'chd_get_price_filter', 100, 2 );
add_filter( 'woocommerce_product_get_regular_price', 'chd_get_price_filter', 100, 2 );
add_filter( 'woocommerce_product_get_sale_price', 'chd_get_price_filter', 100, 2 );
Is there any hook in which I can do this action in better way?
Update product price using update_post_meta function like this
update_post_meta( $product->id, '_sale_price', '1718' );
update_post_meta( $product->id, '_regular_price', '1718 );
add_action( 'the_post', 'chd_the_post_action', 9, 1);
As part of a WooCommerce site I want to have a sale page that lists sale items (with pagination and filtering). I think the best way to do this is to have a 'Sale' category that is added automatically to any posts that are part of the sale (as category pages allow for filtering and pagination automatically.
I have this code so far to programatically add the sale category to products when you save them:
function update_test( $product) {
wp_set_object_terms($product, 'sale', 'product_cat', true );
}
add_action( 'save_post', 'update_test', 1, 2);`
However, I only want this to happen if a product is on sale (i.e has sale price set) so that saving posts that are not on sale does not add the sale category. I have tried several different things, but have had no luck. I tried this, but it didnt work:
function update_test( $product ) {
if($product->is_on_sale()){
wp_set_object_terms($product, 'sale', 'product_cat', true );
}
}
add_action( 'save_post', 'update_test', 1, 2);`
but this just made my site freeze on save.
Any ideas?
Andy
Updated 2 (October 2018)
save_post is a WordPress hook that works with $post_id argument and target all kind of posts. You need to target product custom WooCommerce post_type first in a condition (and publish post_status).
Also as it's not a post object you can't use is_on_sale() method with it. But you can use get_post_meta() function to check if the sale price is set in the product.
Here is the fully functional and tested code (for simple products only):
add_action( 'save_post_product', 'update_product_set_sale_cat' );
function update_product_set_sale_cat( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
if ( ! current_user_can( 'edit_product', $post_id ) ) {
return $post_id;
}
if( get_post_status( $post_id ) == 'publish' && isset($_POST['_sale_price']) ) {
$sale_price = $_POST['_sale_price'];
if( $sale_price >= 0 && ! has_term( 'Sale', 'product_cat', $post_id ) ){
wp_set_object_terms($post_id, 'sale', 'product_cat', true );
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related: Auto remove Sale product category from not on sale products in Woocommerce
I think a more convenient way of doing this, that also works on variable products, would be adding the following in child theme's function.php (or via a plugin, etc):
add_action( 'woocommerce_update_product', 'update_product_set_sale_cat', 10, 2 );
function update_product_set_sale_cat( $product_id, $product ) {
if ( $product->is_on_sale() ) {
wp_add_object_terms($product_id, "sale", 'product_cat');
} else { // this will also remove the sale category when the product in no longer on sale
wp_remove_object_terms($product_id, "sale", 'product_cat');
}
}
It uses the woocommerce_update_product hook which runs whenever a product is updated/created in the database.