Any way to Overwrite get_stock_quantity in my functions.php? - wordpress

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

Related

Display product excerpt in WooCommerce order details table and sort order items based on that

Currently I'm using Woocommerce Short_Description in Details Order answer code to show the product excerpt on WooCommerce checkout page:
add_filter( 'woocommerce_order_item_name', 'add_single_excerpt_to_order_item', 10, 3 );
function add_single_excerpt_to_order_item( $item_name, $item, $is_visible ){
$product_id = $item->get_product_id(); // Get the product Id
$excerpt = get_the_excerpt( $product_id ); // Get the short description
return $excerpt . $item_name ;
}
Then I try to sort the order items alphabetically, based on the product excerpt. Via How to sort WooCommerce order items alphabetically i was able to write following code:
/*
* Filters the $order->get_items() method results to order all line items by
* product name
*/
add_filter( 'woocommerce_order_get_items', function( $items, $order ) {
uasort( $items,
function( $a, $b ) {
return strnatcmp( $a['excerpt'], $b['excerpt'] );
}
);
return $items;
}, 10, 2 );
With this code I don't get any error messages, but I don't get the desired result either. Any advice how to sort excerpt by alphabetical order?
To display the short product description you can use:
function filter_woocommerce_order_item_name( $item_name, $item, $is_visible ) {
// Get the product ID
$product_id = $item->get_product_id();
// Get the short description
$excerpt = get_the_excerpt( $product_id );
// NOT empty
if ( ! empty ($excerpt ) ) {
return $excerpt . ' - ' . $item_name;
}
return $item_name;
}
add_filter( 'woocommerce_order_item_name', 'filter_woocommerce_order_item_name', 10, 3 );
Note: because the woocommerce_order_item_name hook is executed on multiple pages (as well as WooCommerce email notifications) you could use conditional tags
Regarding sorting, $a['excerpt'] does not exist, you can replace it with get_the_excerpt( $a['product_id'] )
So you get:
function filter_woocommerce_order_get_items( $items, $order, $types ) {
// Sort an array with a user-defined comparison function and maintain index association
uasort( $items, function( $a, $b ) {
// String comparisons using a "natural order" algorithm
return strnatcmp( get_the_excerpt( $a['product_id'] ), get_the_excerpt( $b['product_id'] ) );
} );
return $items;
}
add_filter( 'woocommerce_order_get_items', 'filter_woocommerce_order_get_items', 10, 3 );

post_status in Woocommerce default CSV exporter/importer

This is what I have tried to export/import the post_status with the default Woocommerce CSV importer/exporter.
I have managed to get the post_status field to show up mapped in the importer/exporter.
It also exports the column to csv. However there is no data.
How could I get the post_status to export and import correctly?
// ADD CUSTOM IMPORT COLUMN TO CSV IMPORTER
add_filter( 'woocommerce_csv_product_import_mapping_options', 'add_column_to_importer' );
function add_column_to_importer ( $options ) {
$options['post_status'] = 'post_status';
return $options;
}
add_filter( 'woocommerce_csv_product_import_mapping_default_columns', 'add_column_to_mapping_screen' );
function add_column_to_mapping_screen ( $columns ) {
$columns['post_status'] = 'post_status';
return $columns;
}
add_filter( 'woocommerce_product_import_pre_insert_product_object', 'process_import', 10, 2 );
function process_import( $object, $data ) {
if (!empty($data['post_status'])) {
$object->post_status($data['post_status']);
}
return $object;
}
// ADD CUSTOM EXPORT COLUMN TO CSV EXPORTER
add_filter( 'woocommerce_product_export_column_names', 'add_export_column' );
add_filter( 'woocommerce_product_export_product_default_columns', 'add_export_column' );
function add_export_column( $columns ) {
$columns['post_status'] = 'post_status';
return $columns;
}
add_filter( 'woocommerce_product_export_product_column_custom_column', 'add_export_data', 10, 2 );
function add_export_data( $value, $product ) {
$post_status = get_post_status();
return $post_status;
}
You have an issue inside your hooks. Check the last hook, for example. You need to replace ...._custom_column with your actual column which is in your case post_status:
add_filter( 'woocommerce_product_export_product_column_post_status', 'add_export_data', 10, 2 );
function add_export_data( $value, $product ) {
return $product->get_status();
}
add_filter( 'woocommerce_product_import_pre_insert_product_object', 'process_import', 10, 2 );
function process_import( $product, $data ) {
if ( ! empty( $data['post_status'] ) ) {
$product->set_status( $data['post_status'] );
}
return $product;
}
This hook is used to add some data to your column and because the hook is incorrect, no data is visible.

How can I modify get_price_html to create custom price display for on sale items

this is my first question on Stack Overflow...
I am modifying a WooCommerce website for a client. What they want is for all items which have a sale prices to display a red dot next to the sale price.
I have located the public function 'get_price_html' in abstract-wc-product.php:
/**
* Returns the price in html format.
*
* #param string $deprecated Deprecated param.
*
* #return string
*/
public function get_price_html( $deprecated = '' ) {
if ( '' === $this->get_price() ) {
$price = apply_filters( 'woocommerce_empty_price_html', '', $this );
} elseif ( $this->is_on_sale() ) {
$price = wc_format_sale_price( wc_get_price_to_display( $this, array( 'price' => $this->get_regular_price() ) ), wc_get_price_to_display( $this ) ) . $this->get_price_suffix();
} else {
$price = wc_price( wc_get_price_to_display( $this ) ) . $this->get_price_suffix();
}
return apply_filters( 'woocommerce_get_price_html', $price, $this );
}
I have figured out that if I modify the 'elseif ( $this->is_on_sale()' section, I can do what I want, and this works, but only when I modify and upload the core version of abstract-wc-product.php, which I don't want to do.
I have child theme going, and in my child theme directory, I have copied abstract-wc-product.php into the following folder structure:
woocommerce/includes/abstracts
This isn't working, so I have also tried to copy the function above into my functions.php file, to see if this overrides the core version.
Neither of these is working - can anybody help with how to do this, please?
Thank you!
Stuart
If you can't use CSS, here's how you do it:
/* Here's the woocommerce filter. Then we use a static function (anonymous function) to pass the two arguments that the original filter passes.*/
add_filter( 'woocommerce_get_price_html', static function( $price, $product ) {
// Now we check to see if the product is onsale.
if ( $product->is_on_sale() ) :
// Change this to whatever worked for you when you modified core files.
$price = wc_format_sale_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ), wc_get_price_to_display( $product ) ) . $product->get_price_suffix();
endif;
// Return the $price. This is here in the event the product that is passed isn't on sale.
return $price;
}, 10, 2 );
This goes into your child theme functions.php.
Your key is in return apply_filters( 'woocommerce_get_price_html', $price, $this );
Check the doc here about how to use filters in WordPress: https://developer.wordpress.org/reference/functions/apply_filters/
In your case, I believe you can achieve your goal with this function below - not tested!!
function custom_sale_price( $price, $product ){
if( $product->is_on_sale() ){
return '<span class="red-dot"></span>' . $price;
}
return $price;
}
add_filter('woocommerce_get_price_html', 'custom_sale_price', 10, 2 );

WordPress WooCommerce Membership plan add column to list

I found this 2 filters for WooCommerce to extend the membership plan list:
add_filter( 'manage_edit-wc_user_membership_columns', array( $this, 'customize_columns' ) );
add_filter( 'manage_edit-wc_user_membership_sortable_columns', array( $this, 'customize_sortable_columns' ) );
I want to add a new column with the memberships plan id to show.
any suggestion on how to use that in the functions.php
You found the correct filter manage_edit-wc_user_membership_columns – it allows to add a column in membership plans, example:
add_filter( 'manage_edit-wc_user_membership_columns', 'my_add' );
function my_add( $columns ) {
$columns['id_of_the_plan'] = 'Memberships plan id';
return $columns;
}
Once you insert this code in your current theme functions.php file or in a custom plugin, the column will appear. Now it is time to add the data to it. manage_posts_custom_column will help with it.
add_action( 'manage_posts_custom_column', 'my_id' );
function my_id( $column ) {
if( $column == 'id_of_the_plan' ) {
$m = wc_memberships_get_user_membership( get_the_ID() );
echo $m->plan_id;
}
}
The original code is taken from this example.

Need Woocommerce to only allow 1 product in the cart. If a product is already in the cart and another 1 is added then it should remove the previous 1

I think this code should work but not exactly sure where to place it. Everywhere I have tried has failed so far...
add_action('init', 'woocommerce_clear_cart');
function woocommerce_clear_cart() {
global $woocommerce, $post, $wpdb;
$url = explode('/', 'http://'.$_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"]);
$slug=$url[4];
$postid = $wpdb->get_var("SELECT ID FROM $wpdb->posts WHERE post_status='publish' AND post_name = '$slug'");
if ($postid){
if ($postid == PRODUCTID1 || $postid == PRODUCTID2){
$woocommerce->cart->empty_cart();
}
}
}
Unfortunately there is no 'action' hook before WooCommerce adds an item to the cart. But they have a 'filter' hook before adding to cart.
That is how I use it:
add_filter( 'woocommerce_add_cart_item_data', 'woo_custom_add_to_cart' );
function woo_custom_add_to_cart( $cart_item_data ) {
global $woocommerce;
$woocommerce->cart->empty_cart();
// Do nothing with the data and return
return $cart_item_data;
}
Based on the accepted answer and the latest Woo version 2.5.1 I updated the function to be slightly cleaner using the code woo uses in class-wc-checkout.php to clear the cart
add_filter( 'woocommerce_add_cart_item_data', '_empty_cart' );
function _empty_cart( $cart_item_data ) {
WC()->cart->empty_cart();
return $cart_item_data;
}
There is a filter/hook that runs before an item is added to the cart as each product goes through validation before it is added.
So when validating a product, we can check if the item if there are already items in the cart and clears those (if the current item is able to be added) and adds an error message.
/**
* When an item is added to the cart, remove other products
*/
function so_27030769_maybe_empty_cart( $valid, $product_id, $quantity ) {
if( ! empty ( WC()->cart->get_cart() ) && $valid ){
WC()->cart->empty_cart();
wc_add_notice( 'Whoa hold up. You can only have 1 item in your cart', 'error' );
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'so_27030769_maybe_empty_cart', 10, 3 );
This worked like a charm for me, removes the previous product and adds the new one with the new product configuration. Cheers
Update: For WooCommerce 3.0.X
function check_if_cart_has_product( $valid, $product_id, $quantity ) {
if(!empty(WC()->cart->get_cart()) && $valid){
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if( $product_id == $_product->get_id() ) {
unset(WC()->cart->cart_contents[$cart_item_key]);
}
}
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'check_if_cart_has_product', 10, 3 );
For WooCommerce version less than 3.0.X
function check_if_cart_has_product( $valid, $product_id, $quantity ) {
if(!empty(WC()->cart->get_cart()) && $valid){
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if( $product_id == $_product->id ) {
unset(WC()->cart->cart_contents[$cart_item_key]);
}
}
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'check_if_cart_has_product', 10, 3 );
You have two options:
WooCommerce Min/Max Quantities extension
The following code added to your functions.php theme file
add_filter ( 'woocommerce_before_cart' , 'allow_single_quantity_in_cart' );
function allow_single_quantity_in_cart() {
global $woocommerce;
$cart_contents = $woocommerce->cart->get_cart();
$keys = array_keys ( $cart_contents );
foreach ( $keys as $key ) {
$woocommerce->cart->set_quantity ( $key, 1, true );
}
}
Don't add functions directly to your commerce files...you'll lose all your code when you update.
User functions should always be hooked through the functions.php of your theme.
Add this to your child-themes functions.php (tested in 2022, requires PHP 7 or higher):
add_filter('woocommerce_add_cart_item_data', function($cart_data) {
wc_empty_cart();
return $cart_data;
}, 99);
The "woocommerce_add_cart_item_data" filter fires every time a new item is added to the cart. We use this chance to call "wc_empty_cart" which empties the cart and optionally the persistent cart too. The new items is therefore alone in the cart.
Try this,
For removing the all products from the cart and adding the last added one,
//For removing all the items from the cart
global $woocommerce;
$woocommerce->cart->empty_cart();
$woocommerce->cart->add_to_cart($product_id,$qty);
class file is wp-content/plugins/woocommerce/classes/class-wc-cart.php.
You can add the above code on the add to cart function in functions.php.
Hope its works..
Eu coloco na function.php do tema, o que faço ou no woocomerce
function check_if_cart_has_product( $valid, $product_id, $quantity ) {
if(!empty(WC()->cart->get_cart()) && $valid){
foreach (WC()->cart->get_cart() as $cart_item_key => $values) {
$_product = $values['data'];
if( $product_id == $_product->id ) {
wc_add_notice( 'The product is already in cart', 'error' );
return false;
}
}
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'check_if_cart_has_product', 10, 3 );
On WordPress 5.6.1. no need to add a custom filter or write code there is an option to limit one product add to the cart.

Resources