Hook to set product weight on save_post - woocommerce

Is there a way to set product weight with save_post hook?
I've following code, but I don't know how to overwrite weight:
add_action( 'save_post', 'change_weight' );
function change_weight($post_id) {
$WC_Product = wc_get_product($post_id);
}

If you use the woocommerce_process_product_meta_$product_type then you don't have to worry about nonces as you can piggy back on WooCommerce's sanity checks.
// This will work in both WC 2.6 and WC 2.7
add_action( 'woocommerce_process_product_meta_simple', 'so_42445796_process_meta' );
function so_42445796_process_meta( $post_id ) {
$weight = 100;
update_post_meta( $post_id, '_weight', $weight );
}
WC 2.7 will introduce CRUD methods that abstract how the data is saved. I suspect they will eventually move products and product meta out of default WordPress tables, but I can't know for sure. In 2.7 you can use the woocommerce_admin_process_product_object hook to modify the $product object before it is saved.
// Coming in WC2.7 you can use the CRUD methods instead
add_action( 'woocommerce_admin_process_product_object', 'so_42445796_process_product_object' );
function so_42445796_process_product_object( $product ) {
$weight = 100;
$product->set_weight( $weight );
}

To set the weight you need to update the post meta. This can be done like this:
update_post_meta( $post_id, '_weight', $weight );
$weight in the above code is a variable containing the value you want the weight to be. However the save_post hook is triggered every time any post is saved, so blog posts, pages, products, etc. You will probably want to validate that the post is a product. You can do that like this:
if ( get_post_type ( $post_id ) == 'shop_order' ) {
update_post_meta( $post_id, '_weight', $weight );
}
Also if you want to get the current weight of the product before you alter it you can do it like this:
$product = wc_get_product( $post_id );
$weight = $product->get_weight();

Related

Custom field value set to permalink only on new post, But they change it every time it's updated

I want to set the permalink slug using the custom field value for the first save only, but it is not working.
The code below changes the slug not only for the first save, but also for every update.
function custom_slug_auto_setting( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
return $_POST['custom_field_title'];
}
add_filter( 'wp_unique_post_slug', 'custom_slug_auto_setting', 10, 6 );
For the second and subsequent saves, I want to keep the slug set for the first save.
I tried using the filter hook for wp_insert_post to specify post_name only for the first save, but that didn't work well either.
Is there any good solution?
Thank you.
save_post or save_post_{$post->post_type} Fires once a post has been saved. The dynamic portion of the hook name, {$post->post_type}, refers to the post type slug.
We need to discard any updates autosave or revision actions. The WordPress autosave system fire every 60 seconds.
#See https://wordpress.org/support/article/revisions/
The $update parameter is supposed to determined whether this is an existing post being updated. It applies more specifically to a post autosave revision. The $update parameter will always be true when firing through wp_publish_post. But that isn't true for its usage in wp_insert_post (See the following wordpress stackexchange answer and comments for more details...).
#See https://wordpress.stackexchange.com/a/185991/190376
In our case, the wp_publish_post function publish a post by transitioning the post status.
#See https://developer.wordpress.org/reference/functions/wp_publish_post/
By additionally crosschecking the post status we can effectively determine whether it is indeed a non-existing post.
If you are calling a function such as wp_update_post that includes the save_post hook, your hooked function will create an infinite loop. To avoid this, unhook your function before calling the function you need, then re-hook it afterward.
#See https://developer.wordpress.org/reference/hooks/save_post/#avoiding-infinite-loops
save_post will fire on post Update (eg: Autosave) or Publish which is why we're runing into an infinite loop.
#See https://wordpress.stackexchange.com/a/19539/190376
<?php
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
if ( ! function_exists( 'wpso74121743' ) ) {
function wpso74121743( $post_id, $post, $update ) {
if ( ! wp_is_post_autosave( $post_id ) && ! wp_is_post_revision( $post_id ) && ! $update && $post->post_status == 'auto-draft' ) {
$override_post_name = sanitize_title( get_post_custom_values( 'custom_field_title', $post_id ), get_the_title( $post_id ) );
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
wp_update_post( array(
'ID' => $post_id,
'post_name' => $self,
) );
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
};
};
};

save_post_post-type WordPress Hook, only works when i create a new post but it doesnt work when i edit a post

I have a Custom Post Type "Compania", it has a meta field called "compania_id" i would like that field = current post_id
I implemented this action to do that and it works when i create a new post (compania_id automatically is equal to current post_id) but in older compania post when this code hasnt been created, when i edit these post and save, compania_id isnt filled with the post_id as when i create a new post, why??
function anadir_post_id($post_id){
update_post_meta($post_id, 'compania_id', $post_id);
}
add_action( 'save_post_compania', 'anadir_post_id', 10, 1);
The hook you use has three parameters. Therefore your code needs to look like this.
function anadir_post_id( int $post_ID, WP_Post $post, bool $update ){
update_post_meta( $post_id, 'compania_id', $post_id );
}
add_action( 'save_post_compania', 'anadir_post_id', 10, 3 ); //<--- 3 params!
If you have an older version of php it will look like this:
function anadir_post_id( $post_ID, WP_$post, $update ){
update_post_meta( $post_id, 'compania_id', $post_id );
}
add_action( 'save_post_compania', 'anadir_post_id', 10, 3 ); //<--- 3 params!
And, of course, if you have access to a post's wp_postmeta rows, you already know its ID. What you store here may be redundant.

Sort Woocommerce products by most viewed using Post View Counter

Any ideas would be much appreciated.
I am trying to reorder my woocommerce products by most viewed using the post-views-counter plugin.
Followed these examples which did not seem to work Sort products by most viewed
function my_view_filter($query){
if ($query->is_main_query() && ( $query->is_home() || $query- >is_archive()
)
) {
$query->set('post_type', 'product');
$query->set('suppress_filters', false);
$query->set('orderby', 'post_views');
$query->set('order', 'asc');
$query->set('fields', '');
}
}
add_action( 'pre_get_posts', 'my_view_filter' );
First of all, the plugin you're trying to use is outdated. Secondly, it seems to create a table to hold the views and this would require changing the actual MySQL query to retrieve posts ordered by date which is a lot of work looking what you need to do.
You could simply just save views on visit to post meta and use that to order products on the catalog like this:
/**
* Setting post count on each visit
*
*/
add_action( 'woocommerce_before_single_product', 'prefix_save_product_views' );
function prefix_save_product_views( ) {
$product_id = get_the_ID();
$increment = 1;
$current_visit_count = get_post_meta( $product_id, 'product_visit_count', true );
$total_visit_count = (int)$current_visit_count + $increment;
update_post_meta( $product_id, 'product_visit_count', $total_visit_count );
}
/**
* Change the display order based on visit count only in Catalog
*
*/
add_filter('woocommerce_get_catalog_ordering_args', 'prefix_woocommerce_catalog_orderby');
function prefix_woocommerce_catalog_orderby( $args ) {
$args['meta_key'] = 'product_visit_count';
$args['orderby'] = 'meta_value_num';
$args['order'] = 'desc';
return $args;
}
You'd run into multiple issues using pre_get_posts
// Remove product category/tag meta from its original position
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_meta', 40 );
// Add product meta in new position
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_meta', 5 );

Any way to Overwrite get_stock_quantity in my functions.php?

I am working in Wordpress Multisite and trying to ensure that all the stock info is fetched from the base site tables. I am trying to overwrite get_stock_quantity() woocomerce function in my theme's functions.php. What i found was
public function get_stock_quantity( $context = 'view' ) {
return $this->get_prop( 'stock_quantity', $context );
}
Now this is neither a filter nor an action. I overwrote one filter that is
add_filter( 'woocommerce_product_get_stock_quantity', 'wcs_custom_get_stock_quantity', 1, 2);
function wcs_custom_get_stock_quantity( $availability, $_product ) {
global $wpdb;
$productQuantity = $wpdb->get_results( 'SELECT * FROM '.$wpdb->base_prefix.'postmeta WHERE post_id = '.$_product->get_id() ." AND meta_key = '_stock'", OBJECT );
return $productQuantity[0]->meta_value;
}
But woocommerce_product_get_stock_quantity only works on the Products List page. The individual product-edit page uses get_stock_quantity.
How can I overwrite it without changing Core files?
Thanks
The correct way to alter get_stock_quantity() method depends on the product. AS you have already notice looking at the source code you see that:
return $this->get_prop( 'stock_quantity', $context );
Now get_prop() method is a part of WC_Data class and has a generic filter hook:
$value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
And if you look to get_hook_prefix() method you have this:
return 'woocommerce_' . $this->object_type . '_get_';
For product variations the object_type is: product_variation
For other products the object_type is: product
The $prop argument is stock_quantity
So know you can built the related filter hooks. Try this:
add_filter( 'woocommerce_product_get_stock_quantity' ,'custom_get_stock_quantity', 10, 2 );
add_filter( 'woocommerce_product_variation_get_stock_quantity' ,'custom_get_stock_quantity', 10, 2 );
function custom_get_stock_quantity( $value, $product ) {
$value = 15; // <== Just for testing
return $value;
}
So for product variations you use woocommerce_product_variation_get_stock_quantity filter hook.
And for the other cases woocommerce_product_get_stock_quantity filter hook
You can update the database, but remember this code is executed one time each time you list your products, and when you update your product
add_filter( 'woocommerce_product_get_stock_quantity' ,'custom_get_stock_quantity', 10, 2 );
add_filter( 'woocommerce_product_variation_get_stock_quantity' ,'custom_get_stock_quantity', 10, 2 );
function custom_get_stock_quantity( $value, $product ) {
$value = 15; // <== Just for testing
//update dabatabase:
update_post_meta( $product->get_id(), '_stock', $value );
return $value;
}
From what I understand you can use $product->set_stock($value); as well to set the value in database
add_filter( 'woocommerce_product_get_stock_quantity' ,'custom_get_stock_quantity', 10, 2 );
add_filter( 'woocommerce_product_variation_get_stock_quantity' ,'custom_get_stock_quantity', 10, 2 );
function custom_get_stock_quantity( $value, $product ) {
$value = 15; // <== Just for testing
//update dabatabase:
$product->set_stock($value);
return $value;
}

Woocommerce Product publish, update and delete hooks

I need Woocommerce Product publish, update and delete hooks if any one know then please inform me.
I find this hook :
add_action('transition_post_status', 'wpse_110037_new_posts', 10, 3);
function wpse_110037_new_posts($new_status, $old_status, $post) {
if(
$old_status != 'publish'
&& $new_status == 'publish'
&& !empty($post->ID)
&& in_array( $post->post_type,
array( 'product')
)
) {
//add some cde here
}
}
but it's only display product id, title, publish status etc....but i want product price, category, tag, brand and stock status.
So please replay me if any one know.
Thanks,
Ketan.
Woocommerce Products are basically wordpress posts. You can use wordpress hooks
add_action( 'before_delete_post', 'wpse_110037_new_posts' );
add_action( 'save_post', 'wpse_110037_new_posts' );
function wpse_110037_new_posts($post_id){
$WC_Product = wc_get_product( $post_id);
}
wc_get_product() will return WC_Product object and you can get the product details from it.
I Prefer to check if the status if not a draft. Also you can have the third parameter updateto check if it's an update or not
add_action( 'save_post', array($this, 'wpse1511_create_or_update_product' ), 10, 3);
function wpse1511_create_or_update_product($post_id, $post, $update){
if ($post->post_status != 'publish' || $post->post_type != 'product') {
return;
}
if (!$product = wc_get_product( $post )) {
return;
}
// Make something with $product
// You can also check $update
}
The save_post and save_post_product hooks run before the post_meta is updated and since most of the WooCommerce product data is stored as post_meta, using them might cause issues.
Thankfully, since v3, there are specific WooCommerce hooks that run after a product is updated (woocommerce_update_product) and when a product is created (woocommerce_new_product).
add_action( 'woocommerce_new_product', 'on_product_save', 10, 1 );
add_action( 'woocommerce_update_product', 'on_product_save', 10, 1 );
function on_product_save( $product_id ) {
$product = wc_get_product( $product_id );
// do something with this product
}
This hook will run after WC has updated the product in the DB:
add_action('save_post_product', 'ns_sync_on_product_save', 10, 3);
function ns_sync_on_product_save( $post_id, $post, $update ) {
$product = wc_get_product( $post_id );
}

Resources