Выводим список товаров WC произвольным циклом в любом месте

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

Правильный способ

Если надо получить какую-то выборку товаров, то вместо get_posts и WP_Query лучше использовать специальные функции WC, такие как wc_get_products и WC_Product_Query. Производитель пишет, что они безопасны в использовании и не будут ломаться из-за изменений базы данных в будущих версиях WooCommerce.

Поэтому кусок кода ниже основан именно на функции wc_get_products. С его помощью мы выводим все опубликованные товары, у которых статус остатка "в наличии". При необходимости так же будет выведена стандартная пагинация WooCommerce.

Скопировано
$paged = ( get_query_var( 'paged' ) ) ? absint( get_query_var( 'paged' ) ) : 1;
$products_per_page = apply_filters( 'loop_shop_per_page', wc_get_default_products_per_row() * wc_get_default_product_rows_per_page() );
$products = wc_get_products([
	'status' => 'publish',
	'limit' => $products_per_page,
	'page' => $paged,
	'paginate' => true,
	'stock_status' => 'instock',
	'return' => 'ids'
]);
wc_set_loop_prop( 'current_page', $paged );
wc_set_loop_prop( 'is_paginated', wc_string_to_bool( true ) );
wc_set_loop_prop( 'page_template', get_page_template_slug() );
wc_set_loop_prop( 'per_page', $products_per_page );
wc_set_loop_prop( 'total', $products->total );
wc_set_loop_prop( 'total_pages', $products->max_num_pages );
if( $products ) {
	do_action('woocommerce_before_shop_loop');
	woocommerce_product_loop_start();
	foreach( $products->products as $product_id ) {
		$post_obj = get_post( $product_id );
		setup_postdata( $GLOBALS['post'] =& $post_obj );
		wc_get_template_part( 'content', 'product' );
	}
	wp_reset_postdata();
	woocommerce_product_loop_end();
	do_action('woocommerce_after_shop_loop');
} else {
	do_action('woocommerce_no_products_found');
}
Показать код

Другие способы

Вариант 1

Отбор товаров с помощью WP_Query.

Скопировано
<ul class = 'products'> <?
	$args = array (
		'post_type' => 'product',
		'posts_per_page' => 5,
		'meta_key' => '_stock_status',
		'meta_value' => 'instock'
	);
	$loop = new WP_Query( $args );
	while( $loop->have_posts() ) {
		$loop->the_post();
		wc_get_template_part( 'content', 'product' );
	}
	wp_reset_postdata(); ?>
</ul>
Показать код

Здесь мы просто выводим 5 произвольных товаров, имеющих статус остатка "В наличии".

Вариант 2

Теперь рассмотрим вариант, когда список товаров для вывода хранится в некотором дополнительном поле. Дополнительное поле может быть создано разными способами, я рассмотрю вариант, когда оно создано с помощью плагина ACF и имеет название recommended_products. Поэтому первая строчка кода ниже будет работать только в этом случае.

Скопировано
<ul class = 'products'> <?
	$products = get_field( 'recommended_products' );
	global $post;
	foreach( $products as $post ) {
		setup_postdata( $post );
		wc_get_template_part( 'content', 'product' );
	}
	wp_reset_postdata(); ?>
</ul>
Показать код

 

Важно! Если товары выводятся не на стандартной странице WooCommerce, а на какой-то произвольной странице, то для правильного их отображения надо, чтобы тег <ul> находился внутри элемента, имеющего класс woocommerce. Этот класс можно присвоить любому родительскому элементу выше, или просто обернуть тег <ul> в тег <div> с таким классом.