Files
f1den 29d10ce4cf Тема магазина по макету Figma
Каталог, карточка товара, корзина, оформление заказа и блог на WooCommerce.

Стили разложены по слоям: токены из Figma, база, компоненты, страницы,
брейкпоинты. Цвета, типографика, радиусы и отступы взяты из Variables и
текстовых стилей макета, ниже по слоям хардкода нет.

Иконки — Phosphor, вставляются инлайном как SVG, символами ничего не рисуется.
Стили WooCommerce отключены, вёрстка своя, !important не используется.
2026-07-30 22:38:49 +03:00

164 lines
4.8 KiB
PHP

<?php
/**
* Front-end assets.
*
* The stylesheet is layered: tokens -> base -> components -> style.css
* (layout and pages). Each layer may only use what the layers before it
* defined, which is what keeps the cascade free of override chains.
*
* @package VyatkaShop
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Version a theme asset with a short token derived from the file itself.
*
* Four characters is enough to tell one build of a file from the next, and it
* keeps the query string out of the way. Deriving it from the file rather than
* randomising it per request is what lets the browser actually cache: the
* token only moves when the file does.
*
* @param string $relative_path Path relative to the theme root.
* @return string
*/
function vyatka_shop_asset_version( string $relative_path ): string {
$file = get_template_directory() . '/' . ltrim( $relative_path, '/' );
if ( ! is_readable( $file ) ) {
return substr( hash( 'crc32b', $relative_path . VYATKA_SHOP_VERSION ), 0, 4 );
}
return substr( hash( 'crc32b', $relative_path . filemtime( $file ) . filesize( $file ) ), 0, 4 );
}
/**
* Icons the front-end script has to render on its own (toasts, dismiss
* buttons). Sharing them from PHP keeps `assets/icons/*.svg` the single
* source of truth.
*
* @return array<string,string>
*/
function vyatka_shop_script_icons(): array {
$icons = array();
foreach ( array( 'check-circle-fill', 'x-circle-fill', 'warning-fill', 'info-fill', 'x', 'caret-down' ) as $name ) {
$icons[ $name ] = vyatka_shop_get_icon( $name );
}
return $icons;
}
/**
* Load public assets.
*/
function vyatka_shop_assets(): void {
/*
* Order is the cascade. Each layer may only build on the ones before it:
* tokens define the vocabulary, base sets element defaults, components own
* the controls, the page layers place them, and responsive comes last
* because it overrides all of the above.
*/
$layers = array(
'vyatka-tokens' => 'assets/css/tokens.css',
'vyatka-base' => 'assets/css/base.css',
'vyatka-components' => 'assets/css/components.css',
'vyatka-layout' => 'assets/css/layout.css',
'vyatka-home' => 'assets/css/home.css',
'vyatka-catalog' => 'assets/css/catalog.css',
'vyatka-product' => 'assets/css/product.css',
'vyatka-blog' => 'assets/css/blog.css',
'vyatka-cart' => 'assets/css/cart.css',
'vyatka-responsive' => 'assets/css/responsive.css',
'vyatka-misc' => 'assets/css/misc.css',
);
$previous = array();
foreach ( $layers as $handle => $path ) {
wp_enqueue_style(
$handle,
get_template_directory_uri() . '/' . $path,
$previous,
vyatka_shop_asset_version( $path )
);
$previous = array( $handle );
}
// style.css only carries the theme header WordPress reads, but it still has
// to be enqueued so child themes can depend on it.
wp_enqueue_style(
'vyatka-shop',
get_stylesheet_uri(),
array( 'vyatka-misc' ),
vyatka_shop_asset_version( 'style.css' )
);
wp_enqueue_script(
'vyatka-shop',
get_template_directory_uri() . '/assets/js/theme.js',
array(),
vyatka_shop_asset_version( 'assets/js/theme.js' ),
true
);
wp_localize_script(
'vyatka-shop',
'vyatkaShopCart',
array(
'ajaxUrl' => '/wp-admin/admin-ajax.php',
'nonce' => wp_create_nonce( 'vyatka-cart' ),
)
);
wp_localize_script( 'vyatka-shop', 'vyatkaShopIcons', vyatka_shop_script_icons() );
}
add_action( 'wp_enqueue_scripts', 'vyatka_shop_assets' );
/**
* Drop WooCommerce's default presentation.
*
* The theme templates every WooCommerce surface it uses, so the plugin's
* stylesheets only add rules that have to be fought with `!important`.
* Removing them is what lets the component layer win on its own specificity.
*
* @param array<string,array<string,string>> $styles Registered WooCommerce styles.
* @return array<string,array<string,string>>
*/
function vyatka_shop_remove_woocommerce_styles( array $styles ): array {
unset(
$styles['woocommerce-general'],
$styles['woocommerce-layout'],
$styles['woocommerce-smallscreen']
);
return $styles;
}
add_filter( 'woocommerce_enqueue_styles', 'vyatka_shop_remove_woocommerce_styles' );
/**
* Remove the block-editor front-end styles WooCommerce and core add for
* surfaces this theme renders itself.
*
* Hooked on `wp_print_styles` rather than `wp_enqueue_scripts`: WooCommerce
* Blocks registers its stylesheet from `enqueue_block_assets`, which runs
* after the theme's own enqueue pass.
*/
function vyatka_shop_dequeue_block_styles(): void {
if ( is_admin() ) {
return;
}
$handles = array(
'wc-blocks-style',
'wc-blocks-style-all-products',
'wc-blocks-packages-style',
'wp-block-library-theme',
'classic-theme-styles',
'global-styles',
);
foreach ( $handles as $handle ) {
wp_dequeue_style( $handle );
wp_deregister_style( $handle );
}
}
add_action( 'wp_print_styles', 'vyatka_shop_dequeue_block_styles', 100 );