I'm deleting all of my out of stock products automatically with an sql statement (I saw the example at another question here on StackOverFlow).
This deletes the product from the database but leaves the image in the media library.
Is there a way to delete the image aswell?
Code:
function remove_out_of_stock_status(){
global $wpdb;
$results = $wpdb->get_results( "
DELETE p FROM {$wpdb->prefix}posts p
join {$wpdb->prefix}postmeta pm
on p.ID = pm.post_id
WHERE p.post_type = 'product'
and pm.meta_key = '_stock_status'
and pm.meta_value = 'outofstock'
" );
}
add_action( 'init', 'remove_out_of_stock_status', 10, 1 );
You can use before_delete_post hook to delete product image, If product get permanently deleted.
add_action('before_delete_post', 'delete_thumbnail_before_delete_post');
function delete_thumbnail_before_delete_post($post_id) {
$post = get_post($post_id);
if ($post->post_type === 'product') {
$thumb_id = get_post_thumbnail_id($post_id);
if ($thumb_id) {
wp_delete_attachment($thumb_id, true);
}
}
}
Above code work fine for me!
Related
How can I get an object list of products with SKU that starts with the same value?
Example:
I've following products:
Article 1 - Sku: ART_1
Article 2 - Sku: ART_2
Article 3 - Sku: ART_3
I want to get all products that starts with "ART_".
Thanks in advance.
The following custom function, will query all product Id(s) and sku(s) (standard objects) using a light SQL query from a sku excerpt (as ART_):
wc_get_products_ids_and_skus( $sku_excerpt ) {
global $wpdb;
// Get all product Ids and skus (standard objects) from a sku excerpt
return $wpdb->get_results( $wpdb->prepare( "
SELECT p.ID as id, pm.meta_value as sku
FROM {$wpdb->prefix}posts p
INNER JOIN {$wpdb->prefix}postmeta pm
ON p.ID = pm.post_id
WHERE p.post_type = 'product'
AND p.post_status = 'publish'
AND pm.meta_key = '_sku'
AND pm.meta_value LIKE '%s'
", '%'.$sku_excerpt.'%' ) );
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
USAGE (example):
$sku_excerpt = 'ART_';
$results = wc_get_products_ids_and_skus( $sku_excerpt );
// Loop through results
foreach ( $results as $result ) {
$product_id = $result->id;
$product_sku = $result->sku;
// Get the WC_Product Object (if needed)
$product = wc_get_product( $product_id );
// Testing output
echo 'Product Id '.$product_id.' and sku '.$product_sku.'<br>';
}
On WooCommerce products, I have a custom meta field called "amazon_price" and I wanna hide the products from showing on front-end if no price is set for this "amazon_price" custom field.
I used this code to do the filtering which works fine for simple products but it doesn't show variable products even if they have "amazon_price" field set , My guess the reason behind that issue is that this code maybe looking for "amazon_price" field value on the main post ID for the product so I think this could might be looking for the main post id for the variable product instead of looking for that field into the variable id, but even if my guess was true I still dont know how to fix that.
add_action( 'woocommerce_product_query', 'apm_products_meta_query' );
function apm_products_meta_query( $q ){
$meta_query = $q->get( 'meta_query' );
$meta_query[] = array(
'key' => 'amazon_price',
'value' => 0,
'compare' => '>'
);
$q->set( 'meta_query', $meta_query );
}
I don't think that is possible to make a WC meta query for product variations of variable products. But a with a custom light SQL query you can make everything at the same time:
// The custom SQL query
function custom_query_incl_ids() {
global $wpdb;
$meta_key = 'amazon_price';
return $wpdb->get_col( "
SELECT DISTINCT p.ID FROM {$wpdb->prefix}posts p
LEFT JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE p.post_type = 'product' AND p.post_status = 'publish'
AND ( ( pm.meta_key = '$meta_key' AND pm.meta_value > 0 )
OR p.ID IN (
SELECT DISTINCT v.post_parent FROM {$wpdb->prefix}posts v
LEFT JOIN {$wpdb->prefix}postmeta as vm ON v.ID = vm.post_id
WHERE v.post_type = 'product_variation'
AND v.post_status = 'publish' AND v.post_parent > 0
AND vm.meta_key = '$meta_key' AND vm.meta_value > 0
) )
");
}
// The WC query
add_action( 'woocommerce_product_query', 'product_query_action_callback' );
function product_query_action_callback( $q ){
$q->set( 'post__in', (array) custom_query_incl_ids() );
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
With woocommerce 2.3 there was post_parent for single products what was the part of grouped product. So it was possible to link them by:
function parent_permalink_button() {
global $post;
if( $post->post_parent != 0 ){
$permalink = get_permalink($post->post_parent);
echo '<a class="button" href="'.$permalink.'">Link to Parent</a>';
}
}
with woocommerce 3.0.0 update situation changed. Actually it is opposite now. Grouped product has its _children.
How can I create the link from single product to its grouped? It can be a part of more grouped product so there can be multiple links (but it is not the case of my shop)
Thanks Michal
It's possible to build that function for WooCommerce 3+ this way:
(with an optional $post_id argument)
/**
* Get a button linked to the parent grouped product.
*
* #param string (optional): The children product ID (of a grouped product)
* #output button html
*/
function parent_permalink_button( $post_id = 0 ){
global $post, $wpdb;
if( $post_id == 0 )
$post_id = $post->ID;
$parent_grouped_id = 0;
// The SQL query
$results = $wpdb->get_results( "
SELECT pm.meta_value as child_ids, pm.post_id
FROM {$wpdb->prefix}postmeta as pm
INNER JOIN {$wpdb->prefix}posts as p ON pm.post_id = p.ID
INNER JOIN {$wpdb->prefix}term_relationships as tr ON pm.post_id = tr.object_id
INNER JOIN {$wpdb->prefix}terms as t ON tr.term_taxonomy_id = t.term_id
WHERE p.post_type LIKE 'product'
AND p.post_status LIKE 'publish'
AND t.slug LIKE 'grouped'
AND pm.meta_key LIKE '_children'
ORDER BY p.ID
" );
// Retreiving the parent grouped product ID
foreach( $results as $result ){
foreach( maybe_unserialize( $result->child_ids ) as $child_id )
if( $child_id == $post_id ){
$parent_grouped_id = $result->post_id;
break;
}
if( $parent_grouped_id != 0 ) break;
}
if( $parent_grouped_id != 0 ){
echo '<a class="button" href="'.get_permalink( $parent_grouped_id ).'">Link to Parent</a>';
}
// Optional empty button link when no grouped parent is found
else {
echo '<a class="button" style="color:grey">No Parent found</a>';
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works in WooCommerce 3+
USAGE: (2 cases)
1) Without using the optional argument $post_id for example directly in the product templates:
parent_permalink_button();
2) Using the function everywhere, defining the it's argument $post_id:
$product_id = 37; // the product ID is defined here or dynamically…
parent_permalink_button( $product_id );
I have a site where products are considered trade/deal. Therefore, when someone take a trade (buy a product), it become out of stock.
What would be the PHP snippet to display the remaining numbers of product currently available (basically In Stock) ?
ex: Hurry Up! Only 10 trades (woocommerce -> products) available!
Thanks in advance!
I tried the code provided :
function fp2() {
global $wpdb;
$stock = get_post_meta( $post->ID, '_stock', true );
echo '<span style="color:#fff;text-align:center;font-size:12px">Remaining Trade:' . $stock;
}
add_shortcode('fp7', 'fp2');
Updated (2021)
Here is a custom function with a SQL query that will return the products "instock" count:
function get_instock_products_count(){
global $wpdb;
// The SQL query
$result = $wpdb->get_var( "
SELECT COUNT(p.ID)
FROM {$wpdb->prefix}posts as p
INNER JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE p.post_type LIKE '%product%'
AND p.post_status = 'publish'
AND pm.meta_key = '_stock_status'
AND pm.meta_value = 'instock'
" );
return reset($result);
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and working
Usage example (in any php file):
$count = get_instock_products_count();
$message = sprintf( __( 'Hurry Up! Only %s remaining trades' ), $count );
echo '<div class="woocommerce-message">'.$message.'</div>';
will display something like:
On my Woocommerce website, I have a plugin which sometimes change product price to regular price = null (for different reasons).
When that happens, we'd like to disable the product so it doesn't show in our online store. How can we do this in functions.php?
This code will disable products from catalog and search, when regular price is NULL and will re-enable the disabled products when regular price is not NULL anymore:
add_action( 'init', 'action_on_product_reg_price' );
function action_on_product_reg_price(){
global $wpdb;
// First query: Get the product Ids that have a NULL regular price
$product_ids = $wpdb->get_col( "
SELECT DISTINCT pm.post_id as product_id
FROM {$wpdb->prefix}postmeta as pm
LEFT JOIN {$wpdb->prefix}postmeta AS pm2 ON pm2.post_id = pm.post_id
WHERE (pm.meta_key = '_regular_price'
AND (pm.meta_value IS NULL
OR pm.meta_value LIKE 'null'))
OR (pm2.meta_key LIKE '_force_visibility'
AND pm2.meta_value IS NOT NULL)
" );
// Disable the products from catalog and search
if(count($product_ids) > 0){
foreach($product_ids as $product_id){
$product = wc_get_product($product_id);
if($product->get_catalog_visibility() != 'hidden' ) {
$product->set_catalog_visibility('hidden'); // visible
$product->save();
update_post_meta( $product_id, '_force_visibility', 1 );
}
}
}
// 2nd query: Get the product Ids that have changed from NULL regular price
$product_ids = $wpdb->get_col( "
SELECT DISTINCT pm.post_id as product_id
FROM {$wpdb->prefix}postmeta as pm
INNER JOIN {$wpdb->prefix}postmeta AS pm2 ON pm2.post_id = pm.post_id
WHERE pm.meta_key = '_regular_price'
AND (pm.meta_value IS NOT NULL
OR pm.meta_value NOT LIKE 'null')
AND pm2.meta_key LIKE '_force_visibility'
AND pm2.meta_value = '1'
" );
// Re-enable catolog and search visibility
if(count($product_ids) > 0){
foreach($product_ids as $product_id){
$product = wc_get_product($product_id);
if($product->get_catalog_visibility() != 'visible' ) {
$product->set_catalog_visibility('visible'); // visible
$product->save();
update_post_meta( $product_id, '_force_visibility', NULL );
}
}
}
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works on WooCommerce 3+