В посте про создание вариативного товара спрашивали как сделать отображение доступных опций на архивной странице каталога (категории/теге). В принципе, фишка интересная, может сэкономить время пользователю, когда у вас на сайте не особо много позиций и все они с возможностью выбора (например, сфера доставки еды/пиццы). По теме я нашел парочку решений. Изначально хотел добавить их в пост с хаками для вариаций, дабы не плодить лишние записи, но в сниппетах слишком много кода, поэтому они тут.
Если будете гуглить данный вопрос, то ищите что-то вроде «woocommerce show variations shop page» (или заменив последние 2 слова на «in archive»). Вполне возможно, что спустя некоторое время появится доступное и работающее решение в виде плагина. Хотя, если быть точным, они уже есть — несколько модулей «всплывали» в Гугле, но, к сожалению, только платные.
Содержание
Хак №1 от James Kemp
Из всех найденных хаков 100% рабочим оказался только один. Автор выпустил его в 2017 году, однако недавно информация была обновлена! Это значит, что он следит за апдейтами движка и вносит правки в сниппет. Кстати, параллельно Джеймс создал другой плагин под данную задачу, но что-то демка мне лично не совсем зашла.
Вот как в идеале должен работать выбор вариации:

Код ниже добавляете в файл functions.php темы или используйте плагин Code Snippets.
/**
* Replace add to cart button in the loop.
*/
function iconic_change_loop_add_to_cart() {
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
add_action( 'woocommerce_after_shop_loop_item', 'iconic_template_loop_add_to_cart', 10 );
}
add_action( 'init', 'iconic_change_loop_add_to_cart', 10 );
/**
* Use single add to cart button for variable products.
*/
function iconic_template_loop_add_to_cart() {
global $product;
if ( ! $product->is_type( 'variable' ) ) {
woocommerce_template_loop_add_to_cart();
return;
}
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
add_action( 'woocommerce_single_variation', 'iconic_loop_variation_add_to_cart_button', 20 );
woocommerce_template_single_add_to_cart();
}
/**
* Customise variable add to cart button for loop.
*
* Remove qty selector and simplify.
*/
function iconic_loop_variation_add_to_cart_button() {
global $product;
?>
<div class="woocommerce-variation-add-to-cart variations_button">
<button type="submit" class="single_add_to_cart_button button"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
<input type="hidden" name="add-to-cart" value="<?php echo absint( $product->get_id() ); ?>" />
<input type="hidden" name="product_id" value="<?php echo absint( $product->get_id() ); ?>" />
<input type="hidden" name="variation_id" class="variation_id" value="0" />
</div>
<?php
} |
В оригинальной статье есть пояснение каждого шага сниппета (они отделены закомментированными строками). Если вкратце, то суть следующая:
- Сначала вы меняете стандартную кнопку добавить в корзину на свою функцию. Это применится и к обычной продукции, но позже мы все исправим.
- Далее проверяем если объект не вариативный, то подгружаем стандартную функцию, в противном случае будем использовать свой код.
- На финальном этапе создаем свой вид блока покупки, где будет поле выбора доступных вариантов.
Вот что у меня в итоге вышло на одном из сайтов:

Понятно, что все оформление кнопок/надписей задается в CSS стилях вашего текущего шаблона. Автор решения предлагает использовать дополнительное оформление, которое следует добавить в настройки макета или style.css.
.products .variations {
border: 1px solid #eee;
position: relative;
margin-bottom: 50px;
}
.products .variations td {
display: block;
padding: 10px 20px 18px;
text-align: center;
border-bottom: 1px solid #eee;
}
.products .variations td:first-child {
padding-bottom: 0;
border: none;
}
.products .variations td:last-child {
padding-top: 5px;
}
.products .variations tr:last-child td {
border: none;
}
.products .variations td label {
font-weight: 600;
}
.products .variations td select {
width: 100%;
}
.products .variations .reset_variations {
margin: 10px 0 0;
position: absolute;
bottom: -35px;
left: 0;
right: 0;
} |
В моем случае это мало что изменило — по крайней мере вы увидите для каких элементов следует прописать свои стили.
Важные нюансы (недостатки?) метода:
- Джеймс говорит, что пользователи не поймут, что перед ними вариативная продукция, с чем я не согласен (в крайнем случае можно дописать свой текст в блоке товара).
- Он может повлиять на внешний вид макета. Ну, это, в принципе, логично — более того вам придется подправить оформление элемента и привести его к виду всего сайта.
- Если вы используете какие-то дополнительные Woocommerce модули и сниппеты, то следует проверить их совместимость между собой после внедрения.
- Нет выбора количества товаров.
Хак №2 от Rémi Corson
Решение, описанное тут, позволяет исправить последний недостаток предыдущего. После его внедрения страница каталога должна выглядеть приблизительно так:

Код для вставки в functions.php:
| <?php | |
| // Display variations dropdowns on shop page for variable products | |
| add_filter( ‘woocommerce_loop_add_to_cart_link’, ‘woo_display_variation_dropdown_on_shop_page’ ); | |
| function woo_display_variation_dropdown_on_shop_page() { | |
| global $product; | |
| if( $product->is_type( ‘variable’ )) { | |
| $attribute_keys = array_keys( $product->get_attributes() ); | |
| ?> | |
| <form class=»variations_form cart» method=»post» enctype=’multipart/form-data‘ data-product_id=»<?php echo absint( $product->id ); ?>» data-product_variations=»<?php echo htmlspecialchars( json_encode( $product->get_available_variations() ) ) ?>«> | |
| <?php do_action( ‘woocommerce_before_variations_form’ ); ?> | |
| <?php if ( empty( $product->get_available_variations() ) && false !== $product->get_available_variations() ) : ?> | |
| <p class=»stock out-of-stock«><?php _e( ‘This product is currently out of stock and unavailable.’, ‘woocommerce’ ); ?></p> | |
| <?php else : ?> | |
| <table class=»variations» cellspacing=»0«> | |
| <tbody> | |
| <?php foreach ( $product->get_attributes() as $attribute_name => $options ) : ?> | |
| <tr> | |
| <td class=»label«><label for=»<?php echo sanitize_title( $attribute_name ); ?>«><?php echo wc_attribute_label( $attribute_name ); ?></label></td> | |
| <td class=»value«> | |
| <?php | |
| $selected = isset( $_REQUEST[ ‘attribute_’ . sanitize_title( $attribute_name ) ] ) ? wc_clean( urldecode( $_REQUEST[ ‘attribute_’ . sanitize_title( $attribute_name ) ] ) ) : $product->get_variation_default_attribute( $attribute_name ); | |
| wc_dropdown_variation_attribute_options( array( ‘options’ => $options, ‘attribute’ => $attribute_name, ‘product’ => $product, ‘selected’ => $selected ) ); | |
| echo end( $attribute_keys ) === $attribute_name ? apply_filters( ‘woocommerce_reset_variations_link’, ‘<a class=»reset_variations» href=»#»>’ . __( ‘Clear’, ‘woocommerce’ ) . ‘</a>’ ) : »; | |
| ?> | |
| </td> | |
| </tr> | |
| <?php endforeach;?> | |
| </tbody> | |
| </table> | |
| <?php do_action( ‘woocommerce_before_add_to_cart_button’ ); ?> | |
| <div class=»single_variation_wrap«> | |
| <?php | |
| /** | |
| * woocommerce_before_single_variation Hook. | |
| */ | |
| do_action( ‘woocommerce_before_single_variation’ ); | |
| /** | |
| * woocommerce_single_variation hook. Used to output the cart button and placeholder for variation data. | |
| * @since 2.4.0 | |
| * @hooked woocommerce_single_variation — 10 Empty div for variation data. | |
| * @hooked woocommerce_single_variation_add_to_cart_button — 20 Qty and cart button. | |
| */ | |
| do_action( ‘woocommerce_single_variation’ ); | |
| /** | |
| * woocommerce_after_single_variation Hook. | |
| */ | |
| do_action( ‘woocommerce_after_single_variation’ ); | |
| ?> | |
| </div> | |
| <?php do_action( ‘woocommerce_after_add_to_cart_button’ ); ?> | |
| <?php endif; ?> | |
| <?php do_action( ‘woocommerce_after_variations_form’ ); ?> | |
| </form> | |
| <?php } else { | |
| echo sprintf( ‘<a rel=»nofollow» href=»%s» data-quantity=»%s» data-product_id=»%s» data-product_sku=»%s» class=»%s»>%s</a>’, | |
| esc_url( $product->add_to_cart_url() ), | |
| esc_attr( isset( $quantity ) ? $quantity : 1 ), | |
| esc_attr( $product->id ), | |
| esc_attr( $product->get_sku() ), | |
| esc_attr( isset( $class ) ? $class : ‘button’ ), | |
| esc_html( $product->add_to_cart_text() ) | |
| ); | |
| } | |
| } |
К сожалению, интеграция прошла не так гладко, как в прошлом случае. После внедрения пропала кнопка добавления в корзину, хотя все остальное есть — и вариации, и количество. Поэтому метод требует доработки!
Итого. Что же делать? В идеале вам нужно взять первый хак и дополнить его недостающим куском кода из второго, где реализуется задание количества товаров для покупки. После этого подправьте CSS-стили под внешний вид своего макета и все.
Если честно, я пока что не сталкивался с данной задачей лично, выполнил что-то вроде предварительного изучения вопроса… поэтому общего кода нет. Кстати, если знаете модули по теме — присылайте названия.