Встала задача вывести информацию о наличии/предзаказе товара в магазине на WooCommerce в нескольких местах: в карточке товара, в корзине и в заказах, что отображаются в админке магазина. Сразу скажу, что я не адепт так называемых "правильных путей" программирования. А потому решаю каждый случай тем способом, который более эффективен для именно этого случая.
Сначала я стал работать с карточкой товара. Пошёл, как мне казалось, самым простым и очевидным путём. Если вордпресс состоит из мелких блоков-хуков, почему бы не добавить в шаблон content-single-product.php дополнительную вёрстку в нужной позиции? Попробовал. Скопировал /wp-content/plugins/woocommerce/templates/content-single-product.php в /wp-content/themes/<тема>/woocommerce/content-single-product.php и в хук woocommerce_single_product_summary добавил строчку
/**
* Hook: woocommerce_single_product_summary.
*
* ...
* ...
* ...
* ...
* @hooked woocommerce_template_single_stock - 25
* ...
* ...
* ...
* ...
*/
А в директорию /wp-content/themes/<тема>/woocommerce/single-product добавил файл stock.php с такой вёрсткой:
<?php
/**
* Single Product Stock
*
* @package WooCommerce\Templates
* @version 3.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
global $product;
if ($product->stock_status = 'onbackorder') {
echo '<div class="stock">Предзаказ</div>';
} else {
echo '<div class="stock">В наличии</div>';
}
По идее должно работать. Но эта вёрстка отчего-то подключалась только в карточках товаров, у которых стоял статус Предзаказ. У товаров В наличии файл не подключался. Можно было поковыряться и всё-таки найти причину неподключения, но я пошёл другим путём. Так как эту надпись надо было выводить над кнопкой добавления в корзину, я посмотрел в файле /wp-content/plugins/woocommerce/templates/single-product/add-to-cart/simple.php название хука, который выводится перед нужной кнопкой. И в functions.php повесил на этот хук woocommerce_before_add_to_cart_form вывод этой же самой вёрстки с немного изменёнными условиями:
add_filter( 'woocommerce_before_add_to_cart_form' , 'jinsite_product_availability' );
function jinsite_product_availability() {
global $product;
$availability = $product->get_availability();
if ( $availability['availability'] == 'Доступно для предзаказа') {
echo '<div class="stock">Предзаказ</div>';
} else {
echo '<div class="stock">В наличии</div>';
}
}
Далее меняем корзину. Поскольку информация о товарах в корзине подгружается через массив базы данных, я тоже сразу решил обойтись простой вёрсткой корзины. Для этого я скопировал шаблон корзины cart.php из /wp-content/plugins/woocommerce/templates/cart/ в директорию темы /wp-content/themes/<тема>/woocommerce/cart/ и начал править.
Сначала для того, чтобы вывести заголовок "Наличие", добавил в вёрстку заголовков строчку
<th class="product-stock">Наличие</th>
Знаю-знаю, что русские надписи в шаблонах принято выводить через конструкции вида esc_html_e('any_text', 'theme_domain'). Но это относится к мультиязычному содержимому и необходимо только для оформления кода в официальном репозитории Wordpress. В коде для одного сайта, при условия сохранения файлов в юникоде, вполне допустимо включать русские надписи прямо в код. Не вижу в этом ничего дурного.
Чуть ниже, в теле таблицы, где перечисляется вывод данных о заказах, добавил код
<td class="product-stock" data-title="Stock">
<?php
if ($_product->stock_status == 'instock') {
echo '<div class="stock_in_cart">В наличии</div>';
} else {
echo '<div class="stock_in_cart">Предзаказ</div>';
}
?>
</td>
Тут главное не промахнуться и добавить новую ячейку, точнее, новый столбец таблицы в ту же позицию, что и заголовок. Как можно заметить, условие вывода изменено. Это зависит от того, что массив $product->get_availability() доступен только в карточке заказа. В корзине приходится использовать другой параметр для выборки значения наличия товара.
Ну и самое интересное - админка. Шаблонов нет, поэтому пришлось работать одними хуками. Благо, прописанные в functions.php активной темы экшены распространяются и на админку тоже. Сначала выбрал место вывода. В списке заказов не получится, так как в одном заказе могут быть собраны товары с разными статусами. Значит, нужно выводить информацию в списке товаров внутри заказа. В результате недолгих поисков был найден хук woocommerce_after_order_itemmeta. Пишем:
add_action( 'woocommerce_after_order_itemmeta', 'jinsite_product_availability_order', 20, 3 );
function jinsite_product_availability_order( $item_id, $item, $product ) {
if( is_admin() && $product->stock_status == 'instock') {
echo '<p class="jinsite-console-order-availability">В наличии</p>';
} else {
echo '<p class="jinsite-console-order-availability">Предзаказ</p>';
}
}
Условие вывода то же самое, что и для корзины, плюс указание на вывод в админке. Всё отлично, но появилось одно "но". Дело в том, что этот хук почему-то выводится в двух местах на странице заказа в админке. Собственно в списке товаров и ещё в блоке с выбранным методом доставки. Возможно, это промах команды WooCommerce, один и тот же хук в двух местах. Понятно, что программно исправить это нельзя. Остаётся одно - скрывать стилями. Причём нужно помнить, что файлы стилей для фронта сайта в админке не работают. Добавляем новый файл стилей в директорию нашей темы. Я назвал его style-admin.css. Прописал в нём правило
#order_shipping_line_items p.jinsite-console-order-availability {
display: none;
}
А в functions.php подключил этот файл в админке:
add_action('admin_head', 'jinsite_style_admin');
function jinsite_style_admin() {
wp_enqueue_style( 'admin-style', get_stylesheet_directory_uri() . '/style-admin.css' );
}
После этого информация о наличии/предзаказе скрылась из блока с выбранным методом доставки.