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

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

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

135 lines
4.3 KiB
PHP

<?php
/**
* Inline SVG icon component.
*
* Every icon in the design is a Phosphor vector. Icons are stored as real
* `.svg` files under `assets/icons/` and inlined into the document so they
* inherit `currentColor`, can be sized from CSS and never cost an extra
* request. Nothing in the theme may draw an icon with a text glyph.
*
* @package VyatkaShop
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Read an icon file and normalise it for inline use.
*
* @param string $name Icon file name without extension.
* @return string Normalised `<svg>` markup, or an empty string when missing.
*/
function vyatka_shop_icon_source( string $name ): string {
static $cache = array();
if ( isset( $cache[ $name ] ) ) {
return $cache[ $name ];
}
$file = get_template_directory() . '/assets/icons/' . $name . '.svg';
if ( ! preg_match( '/^[a-z0-9-]+$/', $name ) || ! is_readable( $file ) ) {
$cache[ $name ] = '';
return '';
}
$svg = (string) file_get_contents( $file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
// Sizing belongs to CSS, colour to `currentColor`.
$svg = preg_replace( '/\s(?:width|height)="[^"]*"/', '', $svg );
$svg = preg_replace( '/\sfill="(?:black|#000(?:000)?)"/i', ' fill="currentColor"', $svg );
$svg = preg_replace( '/<svg\b(?![^>]*\bfill=)/', '<svg fill="currentColor"', $svg );
$cache[ $name ] = trim( (string) $svg );
return $cache[ $name ];
}
/**
* Build the markup for an inline icon.
*
* @param string $name Icon name, e.g. `cart`, `check-bold`.
* @param array<string,string> $args {
* Optional. Presentation options.
*
* @type string $class Extra class names appended to `icon icon-{name}`.
* @type string $label Accessible label. When omitted the icon is hidden
* from assistive technology.
* @type string $size Pixel size applied inline, for one-off sizes.
* }
* @return string
*/
function vyatka_shop_get_icon( string $name, array $args = array() ): string {
$svg = vyatka_shop_icon_source( $name );
if ( '' === $svg ) {
return '';
}
$classes = trim( 'icon icon-' . $name . ' ' . ( $args['class'] ?? '' ) );
$label = trim( (string) ( $args['label'] ?? '' ) );
$attributes = sprintf( ' class="%s"', esc_attr( $classes ) );
if ( '' !== $label ) {
$attributes .= sprintf( ' role="img" aria-label="%s"', esc_attr( $label ) );
} else {
$attributes .= ' aria-hidden="true" focusable="false"';
}
if ( ! empty( $args['size'] ) ) {
$attributes .= sprintf( ' style="--icon-size:%dpx"', absint( $args['size'] ) );
}
return (string) preg_replace( '/<svg\b/', '<svg' . $attributes, $svg, 1 );
}
/**
* Echo an inline icon.
*
* @param string $name Icon name.
* @param array<string,string> $args See vyatka_shop_get_icon().
*/
function vyatka_shop_icon( string $name, array $args = array() ): void {
echo vyatka_shop_get_icon( $name, $args ); // phpcs:ignore WordPress.Security.EscapingOutput.OutputNotEscaped
}
/**
* Allow inline SVG through `wp_kses_post()` so icons survive filtered output.
*
* @param array<string,array<string,bool>> $tags Allowed tags.
* @return array<string,array<string,bool>>
*/
function vyatka_shop_allow_inline_svg( array $tags ): array {
$shared = array(
'class' => true,
'style' => true,
'fill' => true,
'stroke' => true,
'aria-hidden' => true,
'aria-label' => true,
'focusable' => true,
'role' => true,
);
$tags['svg'] = $shared + array(
'xmlns' => true,
'viewbox' => true,
'width' => true,
'height' => true,
);
$tags['path'] = $shared + array(
'd' => true,
'fill-rule' => true,
'clip-rule' => true,
'stroke-width' => true,
'stroke-linecap' => true,
'stroke-linejoin' => true,
);
$tags['g'] = $shared;
$tags['circle'] = $shared + array( 'cx' => true, 'cy' => true, 'r' => true );
$tags['rect'] = $shared + array( 'x' => true, 'y' => true, 'width' => true, 'height' => true, 'rx' => true, 'ry' => true );
$tags['line'] = $shared + array( 'x1' => true, 'y1' => true, 'x2' => true, 'y2' => true );
$tags['polyline'] = $shared + array( 'points' => true );
$tags['polygon'] = $shared + array( 'points' => true );
return $tags;
}
add_filter( 'wp_kses_allowed_html', 'vyatka_shop_allow_inline_svg' );