Почему структура БД WordPress плохо подходит для интернет-магазина
WordPress создавался как движок блога. Позже его сделали универсальным: любая сущность (страница, запись, меню, а потом и товар) попадала в wp_posts с полем post_type. Магазин WooCommerce строился поверх готовой структуры. Это было удобно для плагинов: товары получают редактор, медиа, ревизии и комментарии по умолчанию.
Цена такого решения хорошо известна:
- В wp_posts лежат поля блога (post_content, post_excerpt, comment_status, ping_status), а у товара нужных ему полей (цена, остаток, артикул) в этой таблице нет.
- Все характеристики хранятся в wp_postmeta в виде строк (post_id, meta_key, meta_value). Значение там тип LONGTEXT, поэтому цена и диапазоны сравниваются как строки, а нормальные индексы по значениям построить нельзя.
- На больших каталогах это тормозит. WooCommerce сам это признал и добавил отдельную таблицу wc_product_meta_lookup с ценой, остатком и артикулом, чтобы фильтровать и сортировать быстрее. Заказы он тоже вынес из wp_posts в собственные таблицы (HPOS).
EAV-схема
Entity – Attribute – Value («сущность – атрибут – значение»)
Это способ хранить характеристики объекта не в отдельных колонках, а в виде строк: одна строка соответствует одному значению одной характеристики.
Обычная схема (колонки)
Таблица products
products id | name | power_kw | max_head | pump_type 1 | Джилекс 100 | 0.75 | 40 | центробежный 2 | Водолей 3 | 0.30 | 72 | вибрационный
Каждая характеристика является колонкой. Это быстро и понятно, но у разных категорий разные характеристики. Если держать всё в колонках, таблица быстро обрастает десятками пустых полей. Новая характеристика требует менять структуру таблицы (ALTER TABLE).
products product_attribute_values
id | name product_id | attribute | value
1 | Джилекс 100 1 | power_kw | 0.75
2 | Водолей 3 1 | max_head | 40
1 | pump_type | центробежный
2 | power_kw | 0.30
2 | max_head | 72
Плюсы и минусы
Плюсы:
- Гибкость: у каждого товара свой набор характеристик, без пустых колонок.
- Новые атрибуты добавляются без миграций.
- Фильтры можно строить динамически из данных.
Минусы:
- Запросы сложнее. Чтобы получить товары с мощностью до 1 кВт и напором от 30 м, нужно несколько соединений или EXISTS.
- Если хранить все значения как текст (как wp_postmeta в WooCommerce), нельзя нормально сравнивать числа и строить индексы по значениям.
- Нет ограничений базы на уровне полей, поэтому проверять данные нужно в коде.
Отправка писем WooCommerce через GMail
Если письма с сайта не приходят, можно попробовать отправлять из через почтовый сервер gmail.
Для небольшого количества писем можно бесплатно получить ключи в Google Cloud.
Работает это в связке с плагином WP Mail SMTP, который позволяет настроить отправку почты через разные сервера, в обход стандартной php функции mail() на вашем хостинге. Это увеличивает вероятность доставки почты. Подходит для тех у кого письма с сайта не доходят. Особенно касается mail.ru почты.
Поможет, если не приходят email письма уведомления о заказе в WooCommerce.
Подключаем Google Cloud API
Переходим по ссылке Google Cloud API.

Нужно нажать кнопку "+ CREATE CREDENTIALS" и выбрать вариант OAuth client ID
Выбираем Application type - Web Application
После этого вам выдадут Client ID и Client Secret. Сохраните их для настройки плагина.
Далее переходим в админку WordPress. Устанавливаем плагин и в настройках выбираем отправку через gmail:
Указываем наши ключи от Google Aloud API, нажимаем кнопку "Разрешить плагину отсылать почту используя ваш Google аккаунт":
После этого Google предложит авторизоваться и аккаунт будет подключен.
Теперь вся почта с сайта будет отсылаться через ваш почтовый Google сервер
Обратите внимание, что письма будут приходить с вашего gmail ящика
Кнопка сменится на другую и будет указан почтовый ящик, с которго будут приходить письма.
Убрать автопараграфы из Категории Woocommerce
Мы можем переопределить функцию для вывода описания Категории товаров Woocommerce.
У меня бывают ситуации, когда мне нужно в описании вставить JavaScript код или добавить шорткоды, при этом стандартные фильтры, которые добавляют параграфы и разрывы строк ломают верстку
Ниже приведена функция, которую вы можете вставить в файл functions.php.
Она уберет вставку автопараграфов, позволит добавлять чистый html и JS код в описании категорий товаров Woocommerce и при этом даст возможность использовать шорткоды.
function woocommerce_taxonomy_archive_description() {
if ( is_product_taxonomy() && 0 === absint( get_query_var( 'paged' ) ) ) {
$term = get_queried_object();
if ( $term && !empty( $term->description ) ) {
add_filter( 'term_description_add_shortcode', 'do_shortcode', 11 );
echo '<div class="term-description">' . apply_filters( 'term_description_add_shortcode', $term->description ) . '</div>';
}
}
} Объединить страницы Корзина и Оформление заказа в WooCommerce
Как известно, чем меньше этапов в оформлении заказа, тем выше конверсия. В некоторых случаях имеет смысл сделать отдельную корзину, но для большинства интернет-магазинов можно смело объединять ее с оформлением заказа.
На выходе должно получиться что-то подобное:

Во-первых, должна быть создана страница "Оформление заказа". Она обычно создается при установке плагина Woocommerce. Если ее нет, создайте.
Блоки с корзиной и формой заказа выводятся с помощью шорткодов. Мы сейчас не будет обсуждать что такое шорткоды. Если в двух словах, то это блоки кода, которые можно вставлять в редактор с помощью ярлыка в квадратных скобках. Вам нужно добавить на страницу оформления заказ следующий код:
[woocommerce_cart]
[woocommerce_checkout]
Далее нужно сообщить WooCommerce, что у нас изменился порядок страниц. Делается это на странице настроек WooCommerce:
Не забудьте поменять с коде ссылки. Вместо /cart сделать /checkout. Чтобы при переходе по ссылке корзины, сразу открывалась страница оформления заказа, можно добавить редирект в файле .htaccess корневой папке с сайтом:
Redirect 301 /cart http://site/checkout
После этого остается дело за малым, настроить оформление этой страницы.
Файлы шаблонов Woocommerce — что означают?
Чтобы шаблоны работали, убедитесь, что в functions.php указано add_theme_support( 'woocommerce' );
Шаблоны вывода категории
- archive-product.php - отвечает за вывод товаров в категории
- content-product.php - вывод списка товаров в категории (эта часть подгружается в archive-product.php)
- content-product_cat.php - вывод списка подкатегорий в категории. Включается вместо archive-product.php, когда в настройках категории выбран тип отображения "Подкатегории"
- taxonomy-product_cat.php - используется для вывода категорий, подгружает archive-product.php
- taxonomy-product_tag.php - используется для вывода меток товара, подгружает archive-product.php
Шаблоны вывода страницы товара
- single-product.php - шаблон страницы товара.
- content-single-product.php - выводит контент на странице товара. Часть шаблона single-product.php
- single-product-reviews.php - выводит отзывы на странице товара
Как убрать надпись «включая НДС» в Woocommerce
Убираем надпись "(включая ХХХ ₽ НДС)" в корзине и на странице оформления заказа с помощью фильтра.
Для этого нужно в файл function.php посемтить следующий код:
add_filter( 'woocommerce_cart_totals_order_total_html', 'delete_nds_tax_from_checkout', 10 );
function delete_nds_tax_from_checkout( $value ) {
return preg_replace("/<small[^>]+?[^>]+>(.*?)<\/small>/i", '', $value);
}
Это не идеальное решение, потому что мы просто удаляем тег с этой надписью после того как он уже сгенерирован. Но почему-то разработчики Woocommerce не предусмотрели возможность переопределить функцию, выводящую итог или хотя бы отключить через админку вывод налога.
Можно было бы переписать функцию прямо в движке Woocommerce, но это плохая практика, так как если при обновлении версии woocommerce будут изменения в файле wc-cart-functions.php, то наши изменения пропадут и их надо будет вносить снова.
Скрыть метод оплаты для не авторизованных пользователей Woocommerce
Часто бывает необходимо скрыть от пользователей метод оплаты. Как пример: у нас есть интернет-магазин, где пользователи покупают товары без авторизации и создания аккаунтов. Для тестирования эквайринга на сайте (в нашем случае это эквайринг от Сбербанка) нужно скрыть этот метод оплаты от всех, кроме админа, который авторизовался.
То есть нам надо включить метод оплаты только для зарегистрированных пользователей
Нужно добавить следующий код в файл functions.php:
function sberbank_for_logged_user($available_gateways)
{
global $woocommerce;
if ( !is_user_logged_in() ) { unset($available_gateways['rbspayment']); }
return $available_gateways;
}
add_action('woocommerce_available_payment_gateways', 'sberbank_for_logged_user');
Обратите внимание на $available_gateways['rbspayment'] - где взять название метода?
Все очень просто, можно посмотреть в админке, в ссылке на этот метод, в параметре §ion=rbspayment:
Наведите мышкой на способ оплаты, чтобы увидеть ссылку
Как сделать мета-теги для категорий Woocommerce с помощью ACF
Для чего это вообще нужно?
Как вы уже наверняка знаете, мета-теги нужны для SEO-продвижения, и если вы пишите свою тему на WordPress или дорабатываете какую-то чужую, то у вас есть два варианта добавить теги. Либо плагином, либо самому подключить поля для мета-тегов на нужные страницы.
Чаще всего я вижу на клиентских сайтах плагины Yast SEO и All in One SEO Pack. На мой взгляд, они добавляют ненужный функционал, часть которого я и так добавляю вставкой заготовленного кода в functions.php. Тем более я хочу также влиять на последний узел в хлебных крошках.
Приведу пример:
- Title: "Купить расширительный бак для отопления в Москве"
- Заголовок H1: "Расширительные баки для отопления"
- Хлебные крошки: "_Бренд_ / Расширительные баки / для отопления"
Согласитесь, смотрелось бы не очень красиво, если бы я подргужал в хлебные крошки заголовок, как это делают большинство плагинов.
Поэтому я предпочитаю самостоятельно добавить поля для мета-тегов через Advanced Custom Fields. Установка описана здесь - (Установка Advanced Custom Fields).
Для этого нужно:
- Добавить группу полей
- Добавить вывод полей в шаблоне
Добавить поля ACF для мета тегов на карточки товаров и категории
В админке на вкладке "Группы полей" добавьте следующие поля.
На скриншоте пример моих полей. Достаточно при создании указать Ярлык, Имя, Тип.
И выбрать Условия отображения:
"Категории" находятся в "Формы -> Таксономия"
В итоге поля должны появиться в админке в том числе на страницах Категорий и Товаров.

Добавляем вывод полей ACF в шаблон
В Title я использую следующую логику. Сначала для данной страницы проверяется, существует ли тайтл из поля категории. Если его нет, то происходит поиск поля со страницы/записи, если его нет, то подставляется Заголовок страницы.
В шаблон это нужно вставить в файл header.php перед тегом title:
$queried_object = get_queried_object();
$taxonomy = $queried_object->taxonomy;
$term_id = $queried_object->term_id;
Внутрь тега title:
if( get_field( 'wc_title', $taxonomy . '_' . $term_id ) ) {
the_field( 'wc_title', $taxonomy . '_' . $term_id );
} elseif ( get_field('wc_title') ) {
the_field( 'wc_title' );
} else {
wp_title( '',true );
}
Для description и keywords такая же логика, только мы не подгружаем туда заголовок. Вообще keywords можно не делать, так как он в ранжировании поисковиками не участвует, но это другая история.
if( get_field( 'wc_description', $taxonomy . '_' . $term_id ) ) {
the_field( 'wc_description', $taxonomy . '_' . $term_id );
} else {
the_field( 'wc_description' );
}
Keywords:
if( get_field( 'wc_keywords', $taxonomy . '_' . $term_id ) ) {
the_field( 'wc_keywords', $taxonomy . '_' . $term_id);
} else {
the_field( 'wc_keywords' );
}
Как вывести поле ACF в письмо Woocommerce
О том как добавить произвольные поля можно почитать в разделе Руководство по Advanced Custom Fields.
Сначала приведу пример кода, потом подробно его рассмотрим:
function the_custom_field( $item_id, $item, $order, $plain_text){
if( $color = get_field( 'color', $item->get_product_id() )) {
echo $color;
}
}
add_action('woocommerce_order_item_meta_start', 'the_custom_field', 20, 4);
За вывод списка товаров в письме отвечает шаблон email-order-items.php. Если посмотреть в код, то мы увидим несколько хуков (такие места в коде, куда мы можем вклинить выполнение своих функций).
// allow other plugins to add additional product information here.
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );
// allow other plugins to add additional product information here.
do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );
У меня между ними ничего не выводится, поэтому я могу использовать любой. У вас могут выводиться атрибуты товаров, поэтому поэкспериментируйте, чтобы определить в какой именно добавиться вывод кода.
Далее, когда мы знаем какой хук использовать (например, woocommerce_order_item_meta_start) и какие параметры но принимает ($item_id, $item, $order, $plain_text), можем написать функцию вывода атрибута из ACF (тот код, который я привел в самом начале).
Поместить её нужно, как обычно, в файл functions.php вашей темы.
add_action('woocommerce_order_item_meta_start', 'the_custom_field', 20, 4); - эта строка связывает нашу функцию the_custom_field и хук woocommerce_order_item_meta_start.
Параметр "10" отвечает за приоритет. Если несколько функций привязано к хуку, то первым выведется тот, у которого это число меньше.
Параметр "4" отвечает за то, сколько параметров передается нашей функции из хука. Данный хук передает 4 параметра - $item_id, $item, $order, $plain_text. И эти же параметры мы указываем при создании функции function the_custom_field( $item_id, $item, $order, $plain_text)
Теперь посмотрим, что происходит внутри:
if( $color = get_field( 'color', $item->get_product_id() )) {
echo $color;
}
Тут буквально написано, что мы получаем поле с именем color для товара с id равным $item->get_product_id(). И если такое поле существует, то выводим его содержимое. Можете подробнее прочитать про Описание функции get_field()
Если мы заглянем в файлы шаблонов WooCommerce, то увидим, что этот Хук содержится не только в шаблоне письма, но и в шаблонах оформления заказа, и на странице, которая выводится с подтверждением, после оформления заказа. То есть внеся изменения через хук информация в форме заказа и далее в цепочке заказа обновится автоматически. Это надо помнить и при необходимости поменять шаблоны.
Изменить текст кнопки «Добавить в корзину» на странице товара
Текст выводится функцией $product->single_add_to_cart_text(), которая определена в файле /wp-content/plugins/woocommerce/includes/abstracts/abstract-wc-product.php
/**
* Get the add to cart button text for the single page.
*
* @return string
*/
public function single_add_to_cart_text() {
return apply_filters( 'woocommerce_product_single_add_to_cart_text', __( 'Add to cart', 'woocommerce' ), $this );
}
Как видно из кода, здесь можно использовать фильтр. Добавим код ниже в файл functions.php:
function my_theme_cart_button_text() {
return 'Оформить заказ';
}
add_filter( 'woocommerce_product_single_add_to_cart_text', 'my_theme_cart_button_text' );
В фильтр мы передаем новый текст, вместо старого. В принципе, можно сразу передать текст который нужно. Но если сайт использует мультиязычность, то лучше добавить файл с переводами для Вашей темы. Как сделано в примере ниже и реализовано в самом woocommerce.
function my_theme_cart_button_text() {
return __( 'Add to cart', 'my_theme' );
}
add_filter( 'woocommerce_product_single_add_to_cart_text', 'my_theme_cart_button_text' );