Каталог, карточка товара, корзина, оформление заказа и блог на WooCommerce. Стили разложены по слоям: токены из Figma, база, компоненты, страницы, брейкпоинты. Цвета, типографика, радиусы и отступы взяты из Variables и текстовых стилей макета, ниже по слоям хардкода нет. Иконки — Phosphor, вставляются инлайном как SVG, символами ничего не рисуется. Стили WooCommerce отключены, вёрстка своя, !important не используется.
180 lines
9.8 KiB
PHP
180 lines
9.8 KiB
PHP
<?php
|
|
/**
|
|
* Product archive and category page.
|
|
*
|
|
* @package VyatkaShop
|
|
*/
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
get_header();
|
|
|
|
$title = woocommerce_page_title( false );
|
|
$categories = get_terms(
|
|
array(
|
|
'taxonomy' => 'product_cat',
|
|
'hide_empty' => true,
|
|
'parent' => 0,
|
|
)
|
|
);
|
|
$price_min = isset( $_GET['filter_min_price'] ) ? min( 37900, absint( wp_unslash( $_GET['filter_min_price'] ) ) ) : 0;
|
|
$price_max = isset( $_GET['filter_max_price'] ) ? max( $price_min + 100, min( 38000, absint( wp_unslash( $_GET['filter_max_price'] ) ) ) ) : 25600;
|
|
$feature_options = array(
|
|
'all' => 'Земляничный нектар',
|
|
'conifer' => 'Хвойный экстракт',
|
|
'maple' => 'Кленовый сироп',
|
|
'birch' => 'Берёзовый сок',
|
|
'sea-buckthorn' => 'Облепиховый морс',
|
|
'rowan' => 'Рябиновый настой',
|
|
'blueberry' => 'Черничный кисель',
|
|
'lingonberry' => 'Брусничный компот',
|
|
);
|
|
$collection_options = array(
|
|
'' => 'Вишнёвый нектар',
|
|
'pine' => 'Сосновый сироп',
|
|
'linden' => 'Липовый нектар',
|
|
'aspen' => 'Осиновый экстракт',
|
|
'juniper' => 'Можжевёловый морс',
|
|
'cranberry' => 'Клюквенный настой',
|
|
'blackberry' => 'Ежевичный кисель',
|
|
'raspberry' => 'Малиновый компот',
|
|
);
|
|
$selected_features = isset( $_GET['feature'] )
|
|
? array_map( 'sanitize_key', (array) wp_unslash( $_GET['feature'] ) )
|
|
: array( 'all' );
|
|
$selected_collection = isset( $_GET['collection'] ) ? sanitize_key( wp_unslash( $_GET['collection'] ) ) : '';
|
|
$selected_per_page = isset( $_GET['per_page'] ) ? absint( wp_unslash( $_GET['per_page'] ) ) : 25;
|
|
$filter_action = wc_get_page_permalink( 'shop' );
|
|
|
|
if ( is_product_category() ) {
|
|
$queried_category = get_queried_object();
|
|
if ( $queried_category instanceof WP_Term ) {
|
|
$category_link = get_term_link( $queried_category );
|
|
if ( ! is_wp_error( $category_link ) ) {
|
|
$filter_action = $category_link;
|
|
}
|
|
}
|
|
}
|
|
?>
|
|
<div class="container">
|
|
<?php vyatka_shop_breadcrumbs( $title ); ?>
|
|
<h1 class="page-heading"><?php echo esc_html( $title ); ?></h1>
|
|
|
|
<?php wc_print_notices(); ?>
|
|
<?php get_template_part( 'template-parts/subcategories' ); ?>
|
|
<div class="archive-shell">
|
|
<aside class="filters" id="product-filter-panel" aria-label="<?php esc_attr_e( 'Фильтры товаров', 'vyatka-shop' ); ?>">
|
|
<?php // Below the mobile breakpoint the panel becomes the sheet the design specifies. ?>
|
|
<div class="filters-sheet-head">
|
|
<h2 class="filters-sheet-title"><?php esc_html_e( 'Фильтры', 'vyatka-shop' ); ?></h2>
|
|
<button class="icon-button filters-close" type="button" data-filter-panel-close aria-label="<?php esc_attr_e( 'Закрыть фильтры', 'vyatka-shop' ); ?>">
|
|
<?php vyatka_shop_icon( 'x', array( 'class' => 'icon-20' ) ); ?>
|
|
</button>
|
|
</div>
|
|
<form id="product-filters" action="<?php echo esc_url( $filter_action ); ?>" method="get" data-product-filters>
|
|
<?php if ( isset( $_GET['orderby'] ) ) : ?>
|
|
<input type="hidden" name="orderby" value="<?php echo esc_attr( sanitize_key( wp_unslash( $_GET['orderby'] ) ) ); ?>">
|
|
<?php endif; ?>
|
|
<div class="filter-group" data-price-filter data-price-active="<?php echo isset( $_GET['filter_min_price'], $_GET['filter_max_price'] ) ? 'true' : 'false'; ?>">
|
|
<button class="filter-title" type="button" data-filter-toggle aria-expanded="true"><?php esc_html_e( 'Цена, ₽', 'vyatka-shop' ); ?><?php vyatka_shop_icon( 'caret-up', array( 'class' => 'filter-caret' ) ); ?></button>
|
|
<div class="filter-content">
|
|
<div class="price-fields">
|
|
<input class="filter-input" type="number" name="filter_min_price" min="0" max="38000" step="100" value="<?php echo esc_attr( (string) $price_min ); ?>" data-price-field="min">
|
|
<span class="price-fields-separator" aria-hidden="true"></span>
|
|
<input class="filter-input" type="number" name="filter_max_price" min="0" max="38000" step="100" value="<?php echo esc_attr( (string) $price_max ); ?>" data-price-field="max">
|
|
</div>
|
|
<div class="price-range">
|
|
<input type="range" min="0" max="38000" step="100" value="<?php echo esc_attr( (string) $price_min ); ?>" data-price-range="min" aria-label="<?php esc_attr_e( 'Минимальная цена', 'vyatka-shop' ); ?>">
|
|
<input type="range" min="0" max="38000" step="100" value="<?php echo esc_attr( (string) $price_max ); ?>" data-price-range="max" aria-label="<?php esc_attr_e( 'Максимальная цена', 'vyatka-shop' ); ?>">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="filter-group">
|
|
<button class="filter-title filter-title-open" type="button" data-filter-toggle aria-expanded="true"><?php esc_html_e( 'Фильтр', 'vyatka-shop' ); ?><?php vyatka_shop_icon( 'caret-up', array( 'class' => 'filter-caret' ) ); ?></button>
|
|
<div class="filter-content">
|
|
<?php foreach ( $feature_options as $feature_value => $feature_label ) : ?>
|
|
<label class="filter-option"<?php echo array_search( $feature_value, array_keys( $feature_options ), true ) >= 5 ? ' data-filter-extra hidden' : ''; ?>>
|
|
<input type="checkbox" name="feature[]" value="<?php echo esc_attr( $feature_value ); ?>" data-facet-filter <?php checked( in_array( $feature_value, $selected_features, true ) ); ?>>
|
|
<?php echo esc_html( $feature_label ); ?>
|
|
</label>
|
|
<?php endforeach; ?>
|
|
<button class="filter-more" type="button" data-filter-more aria-expanded="false"><?php esc_html_e( 'Показать все', 'vyatka-shop' ); ?></button>
|
|
</div>
|
|
</div>
|
|
<div class="filter-group">
|
|
<button class="filter-title filter-title-open" type="button" data-filter-toggle aria-expanded="true"><?php esc_html_e( 'Фильтр', 'vyatka-shop' ); ?><?php vyatka_shop_icon( 'caret-up', array( 'class' => 'filter-caret' ) ); ?></button>
|
|
<div class="filter-content">
|
|
<?php foreach ( $collection_options as $collection_value => $collection_label ) : ?>
|
|
<label class="filter-option"<?php echo array_search( $collection_value, array_keys( $collection_options ), true ) >= 5 ? ' data-filter-extra hidden' : ''; ?>>
|
|
<input type="radio" name="collection" value="<?php echo esc_attr( $collection_value ); ?>" data-facet-filter <?php checked( $selected_collection, $collection_value ); ?>>
|
|
<?php echo esc_html( $collection_label ); ?>
|
|
</label>
|
|
<?php endforeach; ?>
|
|
<button class="filter-more" type="button" data-filter-more aria-expanded="false"><?php esc_html_e( 'Показать все', 'vyatka-shop' ); ?></button>
|
|
</div>
|
|
</div>
|
|
<?php for ( $filter_index = 0; $filter_index < 3; $filter_index++ ) : ?>
|
|
<div class="filter-group filter-collapsed">
|
|
<span class="filter-title"><?php esc_html_e( 'Фильтр', 'vyatka-shop' ); ?><?php vyatka_shop_icon( 'caret-up', array( 'class' => 'filter-caret' ) ); ?></span>
|
|
</div>
|
|
<?php endfor; ?>
|
|
</form>
|
|
<div class="filters-sheet-foot">
|
|
<button class="button button-l filters-apply" type="button" data-filter-panel-close><?php esc_html_e( 'Показать товары', 'vyatka-shop' ); ?></button>
|
|
</div>
|
|
</aside>
|
|
|
|
<section class="archive-results">
|
|
<?php
|
|
/*
|
|
* Quick filters. They mirror the collection facet from the sidebar —
|
|
* picking a chip selects the matching radio and submits the same
|
|
* form, so both controls always agree.
|
|
*/
|
|
?>
|
|
<div class="quick-filters" role="group" aria-label="<?php esc_attr_e( 'Быстрые фильтры', 'vyatka-shop' ); ?>">
|
|
<?php foreach ( $collection_options as $collection_value => $collection_label ) : ?>
|
|
<button
|
|
class="quick-filter<?php echo $selected_collection === $collection_value ? ' is-active' : ''; ?>"
|
|
type="button"
|
|
data-quick-filter="<?php echo esc_attr( $collection_value ); ?>"
|
|
aria-pressed="<?php echo $selected_collection === $collection_value ? 'true' : 'false'; ?>"
|
|
><?php echo esc_html( $collection_label ); ?></button>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
|
|
<div class="archive-toolbar">
|
|
<button class="filters-open" type="button" data-filter-panel-open aria-expanded="false" aria-controls="product-filter-panel">
|
|
<?php vyatka_shop_icon( 'funnel', array( 'class' => 'icon-20' ) ); ?><?php esc_html_e( 'Фильтр', 'vyatka-shop' ); ?>
|
|
</button>
|
|
<div class="sort-control"><span><?php esc_html_e( 'Сортировка', 'vyatka-shop' ); ?></span><?php woocommerce_catalog_ordering(); ?></div>
|
|
<label class="per-page-control"><span><?php esc_html_e( 'Выводить товаров', 'vyatka-shop' ); ?></span>
|
|
<select class="archive-select" name="per_page" form="product-filters" data-auto-submit data-custom-select aria-label="<?php esc_attr_e( 'Количество товаров', 'vyatka-shop' ); ?>">
|
|
<?php foreach ( array( 12, 25, 50 ) as $per_page_option ) : ?>
|
|
<option value="<?php echo esc_attr( (string) $per_page_option ); ?>" <?php selected( $selected_per_page, $per_page_option ); ?>><?php echo esc_html( (string) $per_page_option ); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
<?php if ( woocommerce_product_loop() ) : ?>
|
|
<div class="product-grid" data-filter-results>
|
|
<?php while ( have_posts() ) : ?>
|
|
<?php
|
|
the_post();
|
|
$GLOBALS['product'] = wc_get_product( get_the_ID() );
|
|
get_template_part( 'template-parts/product-card' );
|
|
?>
|
|
<?php endwhile; ?>
|
|
</div>
|
|
<p class="filter-empty" data-filter-empty hidden><?php esc_html_e( 'По выбранным параметрам товаров нет.', 'vyatka-shop' ); ?></p>
|
|
<?php vyatka_shop_pagination( (int) $GLOBALS['wp_query']->max_num_pages ); ?>
|
|
<?php else : ?>
|
|
<?php do_action( 'woocommerce_no_products_found' ); ?>
|
|
<?php endif; ?>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
get_footer();
|