Как написать SQL-запрос для получения дочерних категорий WooCommerce, у которых есть записи в их дочерних категориях?

Здравствуйте! Структура категорий товаров на сайте WP Woo выглядит следующим образом:  
Шины  
- Летние  
-- Bridgestone (бренд)  
--- Turanza T005 (модель)  
- Зимние  
-- Бренд  
--- Модель  
- Всесезонные  
-- .....  
--- .....  
Товары привязаны к самой последней категории (например, Turanza T005).  
Необходимо получить массив названий брендов с дополнительным условием: в любой дочерней категории (модель) должна находиться хотя бы одна запись (товар).  
На текущий момент я реализовал получение массива брендов как одного уровня дочерних по отношению к сезонам категорий:  
<pre><code class="php">function theme_get_cats_by_parent( $parent_ids = array() ) {
	
	if ( empty( $parent_ids ) ) return '$parent_ids is empty!';
	
	global $wpdb;

	$in_holders = implode( ',', array_fill( 0, count( $parent_ids ), '%d' ) );
	
	$term_names = $wpdb-&gt;get_col( $wpdb-&gt;prepare( "
		SELECT DISTINCT t.name
		FROM $wpdb-&gt;terms t
		INNER JOIN $wpdb-&gt;term_taxonomy tt
				   on t.term_id = tt.term_id
		WHERE tt.taxonomy = %s
		AND tt.parent IN ( $in_holders )
		ORDER BY t.name
	", [ 'product_cat', ...$parent_ids ] ) );
	
	return $term_names;
}

$brands = theme_get_cats_by_parent( array( 195, 196, 197 ) );</code></pre>  
Уважаемые специалисты, подскажите, пожалуйста, как можно модифицировать запрос, чтобы в результирующем массиве не оказалось пустых категорий?  
Примечание: использование SQL-запроса обусловлено большим количеством категорий — около 4K.
  • 27 августа 2024 г. 7:24
Ответы на вопрос 2
Чтобы модифицировать ваш SQL-запрос так, чтобы он возвращал только те категории (бренды), под которыми есть товары, вам нужно использовать объединение таблиц для проверки наличия записей (товаров) в каждой из дочерних категорий (моделей). 

Так как WooCommerce использует кастомные таксономии для категорий товаров, вам необходимо объединить таблицы `wp_terms`, `wp_term_taxonomy`, и `wp_term_relationships` (в зависимости от префикса, установленного при установке WordPress) и фильтровать их по условию наличия товаров. Вот как это можно сделать:

```php
function theme_get_cats_by_parent_with_products( $parent_ids = array() ) {
    if ( empty( $parent_ids ) ) return '$parent_ids is empty!';

    global $wpdb;

    // Подготовка условий для родительских категорий
    $in_holders = implode( ',', array_fill( 0, count( $parent_ids ), '%d' ) );

    // SQL-запрос для получения названий брендов с учетом наличия товаров
    $term_names = $wpdb->get_col( $wpdb->prepare( "
        SELECT DISTINCT t.name
        FROM $wpdb->terms t
        INNER JOIN $wpdb->term_taxonomy tt ON t.term_id = tt.term_id
        INNER JOIN $wpdb->term_relationships tr ON tt.term_id = tr.term_taxonomy_id
        INNER JOIN $wpdb->posts p ON tr.object_id = p.ID
        WHERE tt.taxonomy = %s
        AND tt.parent IN ( $in_holders )
        AND p.post_type = 'product'
        AND p.post_status = 'publish'
        ORDER BY t.name
    ", 'product_cat', ...$parent_ids ) );

    return $term_names;
}

$brands = theme_get_cats_by_parent_with_products( array( 195, 196, 197 ) );
```

### Объяснение запроса:
1. **Внутренние соединения (INNER JOIN)**:
   - Сначала мы соединяем таблицы `wp_terms` и `wp_term_taxonomy`, чтобы получить термины (категории).
   - Затем соединяем с `wp_term_relationships`, чтобы получить связь между терминами и постами (товарами).
   - Наконец, соединяем с `wp_posts`, чтобы убедиться, что мы только выбираем опубликованные товары (`post_type = 'product'` и `post_status = 'publish'`).
   
2. **Фильтрация**: Мы фильтруем по родительским категориям, переданным в аргументы функции `$parent_ids`.

3. **DISTINCT**: Используется для получения уникальных имен брендов.

### Примечание:
- Убедитесь, что префиксы таблиц, используемые в запросе, совпадают с установленными на вашем сайте. Например, если ваш префикс не `wp_`, измените его на свой.
- Этот запрос может быть ресурсовоёмким, особенно на больших базах данных, поэтому рекомендуем рассмотреть возможность кэширования результата или использование механизма кэширования в WordPress (например, `transients` или `object cache`), чтобы уменьшить нагрузку на БД.
подскажите, пожалуйста, как нужно модифицировать запрос

Этот огород не нужен - есть же get_terms() иже с ним.

А по хорошему сайт надо переделывать - структура данных сплошная каша.
Похожие вопросы