Imported or half-finished WooCommerce products often end up with a price of 0 or no price at all. WooCommerce still lists them in the shop, where they look free or show an empty price and a Read more button instead of Add to cart.
This snippet hides WooCommerce products with a zero or empty price from the shop page, product categories and tags, product search and the product shortcodes. As soon as a price is filled in, the product shows up again.
The snippet
<?php
/**
* Hide WooCommerce products whose price is 0 or empty from the shop, categories, search and [products] lists.
*/
function dpc_priced_products_meta_query(): array {
return array(
'key' => '_price',
'value' => 0,
'compare' => '>',
'type' => 'DECIMAL(10,4)',
);
}
// Shop page, product categories and tags, product search.
add_action( 'woocommerce_product_query', 'dpc_hide_unpriced_products' );
function dpc_hide_unpriced_products( $query ) {
$meta_query = (array) $query->get( 'meta_query' );
$meta_query[] = dpc_priced_products_meta_query();
$query->set( 'meta_query', $meta_query );
}
// [products], [sale_products], [product_category] and the other product shortcodes.
add_filter( 'woocommerce_shortcode_products_query', 'dpc_hide_unpriced_products_shortcode' );
function dpc_hide_unpriced_products_shortcode( $args ) {
$args['meta_query'] = isset( $args['meta_query'] ) ? (array) $args['meta_query'] : array();
$args['meta_query'][] = dpc_priced_products_meta_query();
return $args;
}
How it works
- WooCommerce stores the active price of each product in the
_pricefield. The snippet adds a condition to the product query: only products whose_priceis greater than 0. - Products with no price have an empty
_priceor none at all, so the same condition hides both cases. The older version of this post needed two snippets for that. 'type' => 'DECIMAL(10,4)'makes the database compare numbers. Without it the value is compared as text.woocommerce_product_querychanges the main shop, category, tag and search queries.woocommerce_shortcode_products_querydoes the same for[products]and the other product shortcodes.- A variable product stays visible as long as at least one of its variations has a price above 0.
Add it with Scripts Organizer
In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor, edit the config and publish. Leave Action/Hook empty.
The code only adds a hook and a filter, so it is safe to load before WooCommerce. If WooCommerce is off, nothing happens.
The same code also works unchanged in a small plugin or an mu-plugin.
Customise it
- Hide only products without any price but keep free ones: change
'compare' => '>'to'>='. Products with an empty price are still hidden. - Hide them in the shop only: remove the
woocommerce_shortcode_products_queryfilter.
Gotchas
- The products are only hidden from lists. Their own page still opens from a direct link, and a product with price 0 can still be bought there. Set such products to Draft or Private if they must not be reachable.
- The Product Collection and other WooCommerce blocks build their own queries and are not filtered by this snippet.
- Related products, upsells and cross-sells are picked separately and can still show an unpriced product.
- If the shop shows nothing after you add the snippet, your prices are probably stored without the
_pricefield, for example by an import that writes the regular price only. Save one product again to check.
To change the price output for the products that remain, see Add Text After the Price in WooCommerce.
In the Scripts Organizer library Import it with one click from Scripts Organizer.