Груповий товар WooCommerce – це спеціальний тип товару, який дозволяє поєднувати кілька простих товарів в один, згрупувати їх, якщо вони мають спільні властивості, щоби спростити доступ до них. Відкривши сторінку з груповим товаром, ти можеш обрати кілька різних товарів, що входять у нього, обрати кількість кожного із товарів, та додати їх всі разом у кошик. Зручно, чи не так?

Вигляд групового товару

Але з груповими товарами може вийти невеличка плутанина, коли поруч відображаються групові товари та прості товари, які входять у них. Тобто ти можеш відкрити окремий простий товар та додати його в кошик, а можеш відкрити груповий товар і обрати той самий простий товар із групового. В загальних ситуацій це навіть плюс, коли той самий товар відображається в кількох місцях – більша імовірність, що він потрапить потенційному покупцю на очі 😂

Різниця між простим і груповим товаром
Різниця між простим і груповим товаром тільки у відображенні ціни

Що ж робити, якщо ти не хочеш відображати той самий товар по кілька разів?  Можна трішки переробити запит до бази даних, в результаті чого товари, які входять хоча б до одного групового товару, просто не будуть відображатися.

Всі приклади кодів традиційно розміщуємо у файлі functions.php поточної теми, якщо не знаєш, куди його іще вставити 😉

Приховання товарів, що входять у групу, зі сторінок категорій та атрибутів

Наступний уривок коду приховує товари, які входять хоча б в одну групу, зі сторінок категорій та атрибутів:

// 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()
    ) {
        $tax_query = $query->tax_query;
        $first_query = reset($tax_query->queries);
        $taxonomy = $first_query['taxonomy'];
        if ($taxonomy && str_starts_with($taxonomy, 'pa_') && $first_query['field'] == 'slug') {
            $term_slug = $first_query['terms'][0];
            $term = get_term_by('slug', $term_slug, $taxonomy);
            $term_id = $term ? $term->term_id : 0;
        } elseif ($taxonomy == 'product_cat') {
            $attribute = get_queried_object();
            $term_id = $attribute->term_id;
        }
        if (isset($taxonomy) && $taxonomy && isset($term_id) && $term_id) {
            $child_product_ids = get_grouped_children_ids($term_id, $taxonomy);
            if (!empty($child_product_ids)) {
                $query->set('post__not_in', $child_product_ids);
            }
        }
    }
}

Допоміжні функції

Просто так знайти товари, які входять у групу, не вдасться – стандартних методів немає. Але ми завжди можемо дописати власну допоміжну функцію, яку я вже використав у коді вище – там вона називається get_grouped_children_ids. А виглядає вона отак:

function get_grouped_children_ids($term_id, $taxonomy) {
    $args = array(
        'post_type' => 'product',
        'posts_per_page' => -1,
        'tax_query' => array(
            array(
                'taxonomy' => $taxonomy,
                'field' => 'term_id',
                'terms' => $term_id,
            ),
        ),
    );
    $products = get_posts($args);
    $child_product_ids = array();
    foreach ($products as $product) {
        $parent_grouped_id = get_parent_grouped_id($product->ID);
        if ($parent_grouped_id) {
            $child_product_ids[] = $product->ID;
        }
    }
    return $child_product_ids;
}

Також, як можна помітити, якщо спробувати розібратися в коді – у нас незнайома функція get_parent_grouped_id. Вона отримує ID групового товару, в який входить поточний товар:

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

Бонус: правильна робота із плагіном Husky

Якщо ти використовуєш плагін HUSKY – Products Filter for WooCommerce Professional (колишній WOOF Products Filter) із увімкненою опцією "Try to ajaxify the shop", то відразу помітиш, що при перемиканні сторінок в пагінації даний код перестає працювати. Справа в тому, що в даному випадку плагін шукає товари не через загальний запит, а через свій власний, та ще й за допомогою Ajax. Тому для цього випадку треба додати ще один уривок коду, який працюватиме для пагінації тих же сторінок категорій та атрибутів:

add_filter('woof_products_query', 'woof_hide_grouped_products_from_category', 100);
function woof_hide_grouped_products_from_category($query_vars)
{
    $taxonomy = $query_vars['tax_query'][0]['taxonomy'];
    $term_slug = $query_vars['tax_query'][0]['terms'][0];
    $term = get_term_by('slug', $term_slug, $taxonomy);
    $term_id = $term ? $term->term_id : 0;
    if (isset($taxonomy) && $taxonomy && isset($term_id) && $term_id) {
        $child_product_ids = get_grouped_children_ids($term_id, $taxonomy);
        if (!empty($child_product_ids)) {
            $query_vars['post__not_in'] = $child_product_ids;
        }
    }
    return $query_vars;
}

Висновок

Приховати товари, які входять хоча б в один груповий товар, не так вже й складно, потрібно тільки знати, які конкретно хуки використати. Маю надію, що моя стаття стане у пригоді не одному WordPress-розробнику. А якщо вона тобі дійсно допомогла – виділи хвилинку часу, пошир її 😉

Дякую за увагу!