Woocommerce: function to update all products - php

I have an issue with my Woocommerce products. This issue is fixed if I just update the product (edit the product and click in the Update button) with no changes at all.
I have around 2000 products in my site, then I am thinking of doing this using a function in my function.php file.
It should be something like this, I just need the line which update the product.
function update_all_products(){
// getting all products
$products = get_posts( $args );
// Going through all products
foreach ( $products as $key => $value ) {
// the product ID
$product_id = $value->ID;
// update product
update_post_meta...(NEED HELP HERE)...
} //..end foreach
}
// fire the function
update_all_products();

Try the following, that will update your products by 200 each time to avoid problems
(if you have variable products also, the post_type arg will need to be product & product_variation):
add_action( 'woocommerce_loaded', 'update_products_by_x' );
function update_products_by_x(){
$limit = 200;
// getting all products
$products_ids = get_posts( array(
'post_type' => 'product', // or ['product','product_variation'],
'numberposts' => $limit,
'post_status' => 'publish',
'fields' => 'ids',
'meta_query' => array( array(
'key' => '_sync_updated',
'compare' => 'NOT EXISTS',
) )
) );
// Loop through product Ids
foreach ( $products_ids as $product_id ) {
// Get the WC_Product object
$product = wc_get_product($product_id);
// Mark product as updated
$product->update_meta_data( '_sync_updated', true );
$product->save();
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Each time you will browse a page of your site the function will be triggered. processing products by 200 is just more secure and will avoid a timeout or errors.
You can increase that number to 500 for example, setting the $limit to 500

Related

Code to display all successful purchases in WooCommerce

I want to display the total number of purchases made on my site to my site users; Previously, I wrote the code that displayed the total number of products published on my site, and now I want the code to display the total number of successful purchases from my site to the user.
The code I wrote to display the number of products on my site is as follows:
function product_count_shortcode() {
$count_posts = wp_count_posts( 'product' );
return $count_posts->publish;
}
add_shortcode( 'product_counthalsho', 'product_count_shortcode' );
You will basically have to show the number of orders that have the status completed. Just create a function that will query the order post_type and with the status completed.
You can simply use get_posts and use the php function count the check how many results you have, or use WP_Query that already has a property in the return object that tells you how many orders you have with that status.
Later Edit:
function mrc_total_completed_orders() {
$args = array(
'post_type' => 'order',
'posts_per_page' => -1,
'post_status' => 'completed',
);
$orders = get_posts( $args );
return count( $orders ); }
Or you can use the WC_Order_Query
function mrc_mrc_total_completed_Orders() {
$query = new WC_Order_Query( array(
'limit' => 99999,
'status' => array( 'completed' ),
'return' => 'ids',
) );
$orders = $query->get_orders();
return count( $orders ); }
Also some documentation here
Note that I haven't tested these solutions, but its enough to get you started :)
Usage:
echo mrc_mrc_total_completed_Orders();

Woocommerce show only categories that have products with certain meta value

I am developing b2b section in my Woocommerce shop. I have managed to filter woocommerce_product_query_meta_query to display only products that have been enabled for b2b section for b2b users.
However I cannot find a way to hide product categories that shows 0 results (because no product enabled for b2b section is in that category) in Woocommerce category widget.
I was thinking about overriding default Woocommerce widget code and for each category (and subcategory) run wp query that returns number of products in this category that are enabled for b2b. But with large number of products and categories it seems very inefficient.
Is there a way to hide categories from Woocommerce category widget that are "empty" (no product in this category is enabled for b2b)?
Thanks for any suggestions.
Edit
To clarify my question: here is the function I use to filter product query to display only products that have _eda_display_in_b2b meta set to yes:
function show_only_b2b_products( $meta_query, $query ) {
if ( is_admin() || ! is_user_logged_in() || ! is_b2b_user() ) {
return $meta_query;
}
$meta_query[] = array(
'key' => '_eda_display_in_b2b',
'value' => 'yes',
'compare' => '='
);
return $meta_query;
}
add_filter( 'woocommerce_product_query_meta_query', 'show_only_b2b_products', 10, 2 );
Exaple:
https://klon.vozikyprozivot.cz/kategorie-produktu/pridavne-pohony/
This category is not empty for regular customers and not logged in users. But for b2b customers there is no product to show. So I need to hide this category from the widget for b2b customers.
If you are referring to the product categories widget, there is a setting for hiding empty categories:
If you are referring to something different, could you please share an example page URL as well as your site’s System Status? You can find it via WooCommerce > Status. Select “Get system report” and then “Copy for support”. Once you’ve done that, paste it here in your response.
Hope this will help you.
======Edit======
I think for the above issue you can use the wc category hook and remove the category. Please check the below code
//* Used when the widget is displayed as a dropdown
add_filter( 'woocommerce_product_categories_widget_dropdown_args', 'rv_exclude_wc_widget_categories' );
//* Used when the widget is displayed as a list
add_filter( 'woocommerce_product_categories_widget_args', 'rv_exclude_wc_widget_categories' );
function rv_exclude_wc_widget_categories( $cat_args ) {
//add the logic to check the category have product or not and make the array of ID and replace the below array with that.
$cat_args['exclude'] = array('55','68'); // Insert the product category IDs you wish to exclude
return $cat_args;
}
In the above code I think you can make logic and check if the category have the products or not and make the array of id for the non-product category.
In this way you can exclude the category from the list and dropdown.
How this will help you.
With a big help from Harshit Vaid I have managed to solve it:
add_filter( 'woocommerce_product_categories_widget_dropdown_args', 'eda_exclude_wc_widget_categories' );
add_filter( 'woocommerce_product_categories_widget_args', 'eda_exclude_wc_widget_categories' );
function eda_exclude_wc_widget_categories( $cat_args ) {
$args = array(
'taxonomy' => 'product_cat',
'hide_empty' => 0
);
$all_categories = get_categories( $args );
$category_exclude_list = array();
foreach ( $all_categories as $cat ) {
if ( $cat->category_parent == 0 ) {
$category_id = $cat->term_id;
$product_args = array(
'posts_per_page' => - 1,
'post_type' => 'product',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'terms' => $category_id,
'field' => 'term_id',
'operator' => 'IN'
)
),
'meta_query' => array(
array(
'key' => '_eda_display_in_b2b',
'value' => 'yes'
)
)
);
$query = new WP_Query( $product_args );
$count = $query->post_count;
if ( $count == 0 ) {
array_push( $category_exclude_list, $category_id );
}
}
}
$cat_args['exclude'] = $category_exclude_list;
return $cat_args;
}

Creating a List of Available WooCommerce Coupon Codes and Display anywhere Using Shortcode

I am trying to generate a list of available coupons and to display them using a shortcode. I was hoping to generate the list using SQL and not "-1" since that's heavier on the db from what I understand.
The error I get is this: Notice: Array to string conversion
add_shortcode('ac', 'coupon_list' );
function coupon_list() {
// array for coupons, was hoping for a sql query instead but don't know how
$args = array(
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'asc',
'post_type' => 'shop_coupon',
'post_status' => 'publish',
);
$coupons = get_posts( $args );
$coupon_names = array();
foreach ( $coupons as $coupon ) {
$coupon_name = $coupon->post_title;
array_push( $coupon_names, $coupon_name );
}
// display all available coupons on product page
echo $coupon_names;
}
There are 2 mistakes in your code: You are trying to display an array with echo and when using a shortcode function the data to display requires to be returned (not echoed).
The following function (shortcode), will display a coma separated string of all available coupon codes using a light SQL Query:
add_shortcode('ac', 'available_coupon_codes' );
function available_coupon_codes() {
global $wpdb;
// Get an array of all existing coupon codes
$coupon_codes = $wpdb->get_col("SELECT post_name FROM $wpdb->posts WHERE post_type = 'shop_coupon' AND post_status = 'publish' ORDER BY post_name ASC");
// Display available coupon codes
return implode(', ', $coupon_codes) ; // always use return in a shortcode
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
USAGE:
1) In the WordPress text editor of a post, a custom post or a page:
[ac]
2) On a php file or template:
echo available_coupon_codes();
or
echo do_shortcode('[ac]');
With a WP_Query (like in your code):
add_shortcode('ac', 'coupon_list' );
function coupon_list() {
$coupon_posts = get_posts( array(
'posts_per_page' => -1,
'orderby' => 'name',
'order' => 'asc',
'post_type' => 'shop_coupon',
'post_status' => 'publish',
) );
$coupon_codes = []; // Initializing
foreach( $coupon_posts as $coupon_post) {
$coupon_codes[] = $coupon_post->post_name;
}
// Display available coupon codes
return implode(', ', $coupon_codes) ; // always use return in a shortcode
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Same usage than the first function

Get customer "on-hold" order status total amount in Woocommerce

I'm trying to get the price of all products on hold (i.e user has placed order but haven't made a payment) by a user in woocommerce.
I have the following code which detects all products on-hold orders by a user
function get_user_on_hold_product_price() {
global $product, $woocommerce;
// GET USER
$current_user = wp_get_current_user();
// GET USER ON-HOLD ORDERS
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $current_user->ID,
'post_type' => 'shop_order',
'post_status' => 'wc-on-hold',
) );
I'm not sure what to do from here to get only the total price of all on-hold orders by the user.
Adding/hooking this function to a shortcode, like this;
add_shortcode('get_on-hold_price', 'get_user_on_hold_product_price')
Thanks
To get the total amount of customer "on-hold" orders using a WC_Order_Query for improved usability and compatibility:
add_shortcode('user_on_hold_total', 'get_user_orders_on_hold_total');
function get_user_orders_on_hold_total() {
$total_amount = 0; // Initializing
// Get current user
if( $user = wp_get_current_user() ){
// Get 'on-hold' customer ORDERS
$on_hold_orders = wc_get_orders( array(
'limit' => -1,
'customer_id' => $user->ID,
'status' => 'on-hold',
) );
foreach( $on_hold_orders as $order) {
$total_amount += $order->get_total();
}
}
return $total_amount;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
To get a formatted total amount replace return $total_amount; by return wc_price($total_amount);
Shortcode usage: [user_on_hold_total]
Related documentation: Woocommerce wc_get_orders() and WC_Order_Query

WooCommerce adding product variations programatically with different price will not reflect on the product page

Let me put it simple.
We have products with color and size attributes in database
The products are all variable products
Variations are added for every color and "Any" size
Then we wrote a few functions to add 2 more variations to each product for the sizes 2XL and 3XL (the products are t-shirts) with a higher price!
The variations are added beautifully, however, on the front end, the price will not change when I select the size with the increased price unless I go to a product edit page and click the update button. Only then will the price to be added to the cart change upon selecting that size.
How can make the variations with the increased price reflect on the front-end without having to click the update button for each product?
Maybe you need to run variable_product_sync() on each variable product?
function so_run_once(){
$variable_products = get_posts( array(
'posts_per_page'=> -1,
'post_type' => 'product',
'fields' => 'ids',
'post_status' => 'publish',
'tax_query' => array(
array(
'taxonomy' => 'product_type',
'field' => 'slug',
'terms' => 'variable',
),
)
) );
if( $variable_products ) foreach( $variable_products as $product_id ){
$_product = wc_get_product( $product_id );
$_product->variable_product_sync();
}
}
add_action( 'admin_init', 'so_run_once' );
Found a solution! We had to delete the transient meta data of each post after inserting the variation..
$transient_name = 'wc_product_children_ids_' . $proudct_id;
delete_transient( $transient_name );

Categories