Quote from Andrii on August 16, 2023, 16:06
Cancel post__not_in โ he thinks for a very long time. I came up with another option, maybe someone will find it useful.
So, instead of searching for products that are part of a group product for each term separately, we store a special post_meta field for those products. We write the following synchronization when saving any product:
// Synchronize 'grouped_child' post_metas in products on product save
add_action('save_post', 'synchronize_grouped_child_post_meta', 10, 3);
function synchronize_grouped_child_post_meta($post_id, $post, $update)
{
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
);
$products = get_posts($args);
$grouped_products_ids = [];
$simple_products_ids = [];
foreach ($products as $product) {
$parent_grouped_id = get_parent_grouped_id($product->ID);
if ($parent_grouped_id) {
$grouped_products_ids[] = $product->ID;
} else {
$simple_products_ids[] = $product->ID;
}
}
foreach ($grouped_products_ids as $product_id) {
if (!get_post_meta($product_id, 'grouped_child', true)) {
update_post_meta($product_id, 'grouped_child', 'yes');
}
}
foreach ($simple_products_ids as $product_id) {
if (get_post_meta($product_id, 'grouped_child', true)) {
delete_post_meta($product_id, 'grouped_child');
}
}
}The get_parent_grouped_id function looks like this:
function get_parent_grouped_id($children_id)
{
global $wpdb;
$results = $wpdb->get_col("SELECT post_id FROM {$wpdb->prefix}postmeta
WHERE meta_key = '_children' AND meta_value LIKE '%$children_id%'");
// Will only return one product Id or false if there is zero or many
return sizeof($results) == 1 ? reset($results) : false;
}Now, instead of a complex condition to search for post__not_in, we add a simple meta-query to all three required hooks:
// Hide simple products from category page if they are in grouped product
add_filter('woocommerce_product_query', 'hide_grouped_products_from_category', 99999);
function hide_grouped_products_from_category($query)
{
if (
!is_admin() && $query->is_main_query() && $query->is_archive()
) {
$meta_query = [
[
'key' => 'grouped_child',
'compare' => 'not exists',
],
];
$query->set('meta_query', $meta_query);
}
}
add_filter('woof_products_query', 'woof_hide_grouped_products_from_category', 100);
add_filter('woof_dynamic_count_attr', 'woof_hide_grouped_products_from_category', 10);
function woof_hide_grouped_products_from_category($query_vars)
{
$query_vars['meta_query'] = [
[
'key' => 'grouped_child',
'compare' => 'not exists',
],
];
return $query_vars;
}It works! Thanks for the tips that led to the correct decision!
Cancel post__not_in โ he thinks for a very long time. I came up with another option, maybe someone will find it useful.
So, instead of searching for products that are part of a group product for each term separately, we store a special post_meta field for those products. We write the following synchronization when saving any product:
// Synchronize 'grouped_child' post_metas in products on product save
add_action('save_post', 'synchronize_grouped_child_post_meta', 10, 3);
function synchronize_grouped_child_post_meta($post_id, $post, $update)
{
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
);
$products = get_posts($args);
$grouped_products_ids = [];
$simple_products_ids = [];
foreach ($products as $product) {
$parent_grouped_id = get_parent_grouped_id($product->ID);
if ($parent_grouped_id) {
$grouped_products_ids[] = $product->ID;
} else {
$simple_products_ids[] = $product->ID;
}
}
foreach ($grouped_products_ids as $product_id) {
if (!get_post_meta($product_id, 'grouped_child', true)) {
update_post_meta($product_id, 'grouped_child', 'yes');
}
}
foreach ($simple_products_ids as $product_id) {
if (get_post_meta($product_id, 'grouped_child', true)) {
delete_post_meta($product_id, 'grouped_child');
}
}
}The get_parent_grouped_id function looks like this:
function get_parent_grouped_id($children_id)
{
global $wpdb;
$results = $wpdb->get_col("SELECT post_id FROM {$wpdb->prefix}postmeta
WHERE meta_key = '_children' AND meta_value LIKE '%$children_id%'");
// Will only return one product Id or false if there is zero or many
return sizeof($results) == 1 ? reset($results) : false;
}Now, instead of a complex condition to search for post__not_in, we add a simple meta-query to all three required hooks:
// Hide simple products from category page if they are in grouped product
add_filter('woocommerce_product_query', 'hide_grouped_products_from_category', 99999);
function hide_grouped_products_from_category($query)
{
if (
!is_admin() && $query->is_main_query() && $query->is_archive()
) {
$meta_query = [
[
'key' => 'grouped_child',
'compare' => 'not exists',
],
];
$query->set('meta_query', $meta_query);
}
}
add_filter('woof_products_query', 'woof_hide_grouped_products_from_category', 100);
add_filter('woof_dynamic_count_attr', 'woof_hide_grouped_products_from_category', 10);
function woof_hide_grouped_products_from_category($query_vars)
{
$query_vars['meta_query'] = [
[
'key' => 'grouped_child',
'compare' => 'not exists',
],
];
return $query_vars;
}It works! Thanks for the tips that led to the correct decision!