WooCommerce

Как упорядочить товары по наличию в WooCommerce: сначала в наличии, потом остальные

M
Markabus
·
Фотореалистичный кадр складского стеллажа небольшого интернет-магазина по диагонали вглубь: на переднем плане открытый ноутбук со страницей каталога, где верхние ряды карточек товаров обычные, а нижний ряд приглушён серым, за ним полки — ближние плотно заставлены картонными коробками, дальние полупустые с одинокими коробками и пустыми ячейками — иллюстрация к статье о сортировке товаров по наличию в WooCommerce.

Когда в каталоге много позиций, которых сейчас нет на складе, они неизбежно перемешиваются с доступными: сортировка по названию или цене ничего не знает о наличии. Покупатель листает первый экран, видит серые плашки «Нет в наличии» и уходит с ощущением, что магазин не работает. Решений два: либо скрыть отсутствующие товары совсем, либо оставить их в каталоге, но опустить в конец списка. Второй вариант обычно выгоднее — страницы товаров продолжают собирать трафик из поиска, а покупатель может оформить предзаказ или подписаться на уведомление о поступлении.

Без кода: просто скрыть отсутствующие

Если товар, которого нет, не вернётся в продажу, его проще убрать из каталога штатной настройкой: WooCommerce → Настройки → Товары → Запасы → «Скрывать товары не в наличии из каталога». Страницы самих товаров при этом остаются доступны по прямой ссылке, но из списков и поиска по магазину исчезают. Для сезонного ассортимента или позиций, которые регулярно закупаются заново, такой вариант не подходит — их лучше показывать, но в конце. Дальше речь именно об этом.

Как это работает

Статус наличия WooCommerce хранит в мета-поле _stock_status с тремя значениями: instock (в наличии), onbackorder (под заказ) и outofstock (нет в наличии). Начиная с версии 3.6 эти же данные дублируются в служебную таблицу wc_product_meta_lookup — она создана специально для быстрой сортировки и фильтрации и, в отличие от postmeta, имеет индекс по колонке stock_status.

Основной запрос каталога — это обычный WP_Query, а значит, его SQL можно доработать фильтром posts_clauses: подключить таблицу lookup через JOIN и поставить сортировку по наличию перед той, что уже есть в запросе. Тогда выбранная покупателем сортировка (по цене, по названию, по популярности) не пропадает, а применяется внутри каждой группы: сначала товары в наличии по цене, затем под заказ по цене, затем отсутствующие по цене.

Код для functions.php дочерней темы

add_filter( 'posts_clauses', 'shop_order_by_stock_status', 2000, 2 );
function shop_order_by_stock_status( $clauses, $query ) {
    global $wpdb;

    // Только фронтенд и только основной запрос страницы
    if ( is_admin() || ! $query->is_main_query() ) {
        return $clauses;
    }

    // Только списки каталога: магазин, категория, метка
    if ( ! ( is_shop() || is_product_category() || is_product_tag() ) ) {
        return $clauses;
    }

    $lookup = $wpdb->prefix . 'wc_product_meta_lookup';

    $clauses['join'] .= " INNER JOIN {$lookup} AS stock_lookup ON {$wpdb->posts}.ID = stock_lookup.product_id ";

    // Явный порядок групп: в наличии → под заказ → нет в наличии
    $stock_order = " FIELD( stock_lookup.stock_status, 'instock', 'onbackorder', 'outofstock' ) ";

    $clauses['orderby'] = $stock_order . ( $clauses['orderby'] ? ', ' . $clauses['orderby'] : '' );

    return $clauses;
}

Что здесь важно. Проверка is_main_query() ограничивает фильтр основным запросом страницы: похожие товары, виджеты и шорткоды делают собственные запросы, и трогать их не нужно. Приоритет 2000 ставит нашу функцию после собственных обработчиков WooCommerce, которые через тот же posts_clauses собирают сортировку по цене и популярности — иначе они переписали бы наш ORDER BY. Функция FIELD() задаёт порядок групп явно; полагаться на алфавитный порядок значений было бы хрупко. И, наконец, условие с пустым orderby: в обычном каталоге он всегда заполнен, но лишняя запятая в SQL стоила бы белого экрана.

Почему таблица lookup, а не postmeta

Присоединить можно и postmeta по ключу _stock_status — результат будет тот же. Но postmeta в магазине с тысячами товаров — самая тяжёлая таблица, а колонка meta_value не индексирована. Таблица wc_product_meta_lookup хранит по одной строке на товар, индексирована по нужным колонкам и обновляется самим WooCommerce при каждом сохранении товара и изменении остатков. Если после переноса магазина или ручных правок в базе кажется, что данные в ней устарели, её можно перестроить: WooCommerce → Статус → Инструменты, пункт про обновление таблиц поиска (lookup tables).

Вариативные товары

У товара с вариациями статус родительской записи вычисляется автоматически: он «в наличии», пока в наличии хотя бы одна вариация. Поэтому футболка, у которой закончился самый ходовой размер, но остались другие, по-прежнему попадёт в первую группу — и это правильно, ведь купить её можно. В конец уйдут только те вариативные товары, у которых распроданы все вариации.

Шорткоды и блочные темы

Шорткод [products] и блок «Коллекция товаров» (Product Collection) выполняют собственные запросы, поэтому проверка is_main_query() их отсекает. Для подборок на главной или в статьях это, как правило, и нужно: там порядок задаётся вручную. Если же у вас блочная тема и сам каталог выводится блоком «Коллекция товаров», у его запроса в актуальных версиях WooCommerce есть служебный признак isProductCollectionBlock. Расширьте условие так, чтобы фильтр срабатывал и для него:

if ( is_admin() || ! ( $query->is_main_query() || $query->get( 'isProductCollectionBlock' ) ) ) {
    return $clauses;
}

Остальной код не меняется. После правки проверьте, что порядок изменился именно на странице каталога, а подборки в других местах сайта остались как были.

Что проверить после установки

  • Выпадающий список сортировки в каталоге по-прежнему работает — но внутри групп по наличию.
  • Количество товаров и число страниц пагинации не изменилось. Если товаров стало меньше, у части позиций нет строки в таблице lookup — перестройте её инструментом из раздела «Статус».
  • Кеш страниц (плагин кеширования или CDN) сброшен, иначе старый порядок будет виден ещё какое-то время.

Коротко

Чтобы товары в наличии шли первыми, достаточно одного фильтра posts_clauses: присоединяем wc_product_meta_lookup, ставим FIELD() по статусу впереди существующей сортировки и ограничиваем всё основным запросом каталога. Покупатель по-прежнему сортирует по цене или названию, но отсутствующие товары больше не мешают на первом экране.

Частые вопросы

Q.Можно ли обойтись без кода?

Да, если отсутствующие товары не нужно показывать вовсе: WooCommerce → Настройки → Товары → Запасы → «Скрывать товары не в наличии из каталога». Если их нужно оставить в каталоге, но опустить в конец, без фильтра не обойтись.

Q.Почему не задать сортировку через pre_get_posts и meta_key?

Сортировка по meta_value заменяет собой ту, что выбрал покупатель: пропадает порядок по цене или названию. Фильтр posts_clauses добавляет сортировку по наличию перед существующей, и она продолжает работать внутри групп.

Q.Сработает ли это вместе с сортировкой по цене или популярности?

Да. WooCommerce собирает эти сортировки тем же фильтром posts_clauses, поэтому наш обработчик подключён с приоритетом 2000 — после них. Товары делятся на группы по наличию, а внутри групп сортируются по цене или популярности.

Q.После установки часть товаров пропала из каталога — почему?

INNER JOIN с таблицей wc_product_meta_lookup отбрасывает товары, у которых нет строки в ней. Такое бывает после переноса базы или прямых правок в ней. Перестройте таблицы поиска в WooCommerce → Статус → Инструменты.

Источники

Предыдущая
Как отключить наложенный платёж для конкретных товаров в WooCommerce
Следующая
Как убрать последний элемент из хлебных крошек WooCommerce

Читайте также

Фотореалистичный кадр стола приёмки товара: кожаный рюкзак стоит на почтовых весах, вдоль него растянута жёлтая рулетка, рядом штангенциркуль и крафтовая бирка со штрихкодом, слева монитор с админской карточкой товара — длинная форма с вкладками и полями — иллюстрация к статье о получении всех данных товара WooCommerce по его ID.WooCommerce
12 сентября 2026 г.

Как получить все данные товара WooCommerce по его ID: объект WC_Product и его методы

Название, цена, остаток, вес, картинки, атрибуты, произвольные поля — всё это отдаёт объект товара, который возвращает wc_get_product(). Шпаргалка по методам WC_Product по группам, разница между типами товаров, работа с вариациями, датами и ценами, а также способ получить все данные разом.

Читать →
Фотореалистичный кадр рабочего стола: на переднем плане проволочная магазинная корзинка с серым керамическим чайником на упаковочной бумаге, за ней открытый ноутбук с карточкой того же чайника, где под ценой контурная кнопка с иконкой корзины и стрелкой вместо обычной кнопки покупки — иллюстрация к статье о замене кнопки «В корзину» на «Перейти в корзину» для товаров, уже добавленных в корзину WooCommerce.WooCommerce
12 сентября 2026 г.

Кнопка «Перейти в корзину» вместо «В корзину», если товар уже добавлен: WooCommerce без правки шаблонов

Покупатель уже положил товар в корзину, а карточка по-прежнему предлагает «В корзину» — так появляются случайные дубли. Показываем, как заменить кнопку на «Перейти в корзину» для товаров, которые уже в корзине: хуками, без правки шаблонов, в карточке товара и в каталоге, с учётом Ajax-добавления и кеширования страниц.

Читать →
Фотореалистичный кадр сверху на прилавок небольшой лавки: планшет в подставке со страницей корзины, где у средней строки выделено поле количества, а блок итогов полупрозрачный с кольцом загрузки и под таблицей пустое место без кнопок, рядом плетёная корзинка с мылом, свечами и банкой джема, слева крафтовые пакеты и бечёвка — иллюстрация к статье о скрытии кнопки «Обновить корзину» и автообновлении корзины WooCommerce.WooCommerce
12 сентября 2026 г.

Как скрыть кнопку «Обновить корзину» в WooCommerce и обновлять корзину автоматически

Кнопка «Обновить корзину» — лишний шаг для покупателя: изменил количество, забыл нажать, и итог не пересчитался. Показываем, как заставить классическую корзину WooCommerce обновляться сама при изменении количества, спрятать кнопку одним CSS-правилом и почему в блочной корзине делать ничего не нужно.

Читать →