Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 481 B After Width: | Height: | Size: 481 B |
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 456 B |
Before Width: | Height: | Size: 458 B After Width: | Height: | Size: 458 B |
Before Width: | Height: | Size: 954 B After Width: | Height: | Size: 954 B |
Before Width: | Height: | Size: 455 B After Width: | Height: | Size: 455 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
@ -0,0 +1,20 @@ |
||||
<?php |
||||
use Timber\Timber; |
||||
global $post; |
||||
|
||||
$context = Timber::get_context(); |
||||
|
||||
// Получаем текущий продукт |
||||
$product_id = get_the_ID(); |
||||
$product = wc_get_product($product_id); |
||||
|
||||
// Добавляем продукт в контекст |
||||
$context['product'] = $product; |
||||
$context['post'] = Timber::get_post(); |
||||
|
||||
include_module('shop'); |
||||
include_component('shop', 'reviews'); |
||||
|
||||
?> |
||||
<?php |
||||
Timber::render('woocommerce/single-product.twig', $context); |
@ -0,0 +1,49 @@ |
||||
/* Стили для загрузки корзины на single странице */ |
||||
|
||||
.product-incart__wrap.loading { |
||||
position: relative; |
||||
pointer-events: none; |
||||
opacity: 0.7; |
||||
} |
||||
|
||||
.product-incart__wrap.loading::before { |
||||
content: ''; |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
right: 0; |
||||
bottom: 0; |
||||
background: rgba(255, 255, 255, 0.8); |
||||
z-index: 10; |
||||
} |
||||
|
||||
.product-incart__wrap.loading::after { |
||||
content: ''; |
||||
position: absolute; |
||||
top: 50%; |
||||
left: 50%; |
||||
width: 20px; |
||||
height: 20px; |
||||
margin: -10px 0 0 -10px; |
||||
border: 2px solid #f3f3f3; |
||||
border-top: 2px solid #3498db; |
||||
border-radius: 50%; |
||||
animation: spin 1s linear infinite; |
||||
z-index: 11; |
||||
} |
||||
|
||||
@keyframes spin { |
||||
0% { transform: rotate(0deg); } |
||||
100% { transform: rotate(360deg); } |
||||
} |
||||
|
||||
/* Стили для кнопок во время загрузки */ |
||||
.product-incart__wrap.loading .product-incart__btn { |
||||
opacity: 0.5; |
||||
pointer-events: none; |
||||
} |
||||
|
||||
/* Стили для счетчика во время загрузки */ |
||||
.product-incart__wrap.loading .product-incart__count { |
||||
opacity: 0.5; |
||||
} |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 459 B After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 481 B After Width: | Height: | Size: 481 B |
Before Width: | Height: | Size: 456 B After Width: | Height: | Size: 456 B |
Before Width: | Height: | Size: 458 B After Width: | Height: | Size: 458 B |
Before Width: | Height: | Size: 954 B After Width: | Height: | Size: 954 B |
Before Width: | Height: | Size: 455 B After Width: | Height: | Size: 455 B |
@ -0,0 +1,156 @@ |
||||
<?php |
||||
|
||||
$product; |
||||
$product_type; |
||||
$context_for_twig; |
||||
|
||||
// Получаем данные продукта |
||||
$product_id = get_the_ID(); |
||||
$product = wc_get_product($product_id); |
||||
|
||||
// Проверяем, что продукт существует |
||||
if (!$product) { |
||||
return; // Просто выходим, если продукт не найден |
||||
} |
||||
|
||||
$attributes = []; |
||||
$product_attributes = $product->get_attributes(); |
||||
|
||||
/* Получение категорий */ |
||||
$tags = get_the_terms($product_id, 'product_cat'); |
||||
if (!empty($tags) && !is_wp_error($tags)) { |
||||
foreach ($tags as $tag) { |
||||
$context_for_twig['product_tags'][] = $tag->name; |
||||
} |
||||
} |
||||
|
||||
/* Получение атрибутов */ |
||||
if (!empty($product_attributes)) { |
||||
foreach ($product_attributes as $taxonomy => $attribute) { |
||||
if ($attribute->is_taxonomy()) { |
||||
$terms = wc_get_product_terms($product_id, $taxonomy, ['fields' => 'all']); |
||||
// $tags = wc_get_product_terms( $product_id, 'pa_catalog_tags' ); |
||||
|
||||
if (!empty($terms)) { |
||||
$attr_values = []; |
||||
foreach ($terms as $term) { |
||||
$attr_values[] = [ |
||||
'name' => $term->name, |
||||
'slug' => $term->slug, |
||||
'term_id' => $term->term_id, |
||||
'link' => get_term_link($term->term_id, $taxonomy), |
||||
]; |
||||
} |
||||
$attributes[wc_attribute_label($taxonomy)] = $attr_values; |
||||
} |
||||
} else { |
||||
$attributes[wc_attribute_label($taxonomy)] = $attribute->get_options(); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
$context_for_twig['product_attributes'] = $attributes; |
||||
|
||||
/* Получение вариаций товара */ |
||||
if ($product->is_type('variable')) { |
||||
$available_variations = $product->get_available_variations(); |
||||
$variations_data = []; |
||||
|
||||
foreach ($available_variations as $variation) { |
||||
$variation_id = $variation['variation_id']; |
||||
$variation_obj = wc_get_product($variation_id); |
||||
|
||||
$variations_data[] = [ |
||||
'variation_id' => $variation_id, |
||||
'price' => $variation_obj->get_price(), |
||||
'regular_price' => $variation_obj->get_regular_price(), |
||||
'sale_price' => $variation_obj->get_sale_price(), |
||||
'attributes' => $variation['attributes'] |
||||
]; |
||||
} |
||||
|
||||
$context_for_twig['variations'] = $variations_data; |
||||
} |
||||
|
||||
/* ACF-поля и мета-данные продукта */ |
||||
$meta_fields = [ |
||||
'composition' => get_post_meta($product_id, '_composition', true), |
||||
'feeding_recommendations' => get_post_meta($product_id, '_feeding_recommendations', true), // Ранее выводились HTML-полем «Рекомендации по кормлению» |
||||
'feeding_recommendations_table' => get_field('feeding_recommendations_table', get_post(get_field('p_tables_field', $product_id))) , // Таблица «Рекомендации по кормлению» |
||||
'nutritional_value' => get_post_meta($product_id, '_nutritional_value', true), |
||||
'vitamins' => get_post_meta($product_id, '_vitamins', true), |
||||
'additives' => get_post_meta($product_id, '_additives', true), |
||||
'energy_value' => get_post_meta($product_id, '_energy_value', true), |
||||
'important' => get_post_meta($product_id, '_important', true), |
||||
]; |
||||
|
||||
$context_for_twig['product_meta'] = $meta_fields; |
||||
|
||||
|
||||
/* Товар оформляется по подписке? */ |
||||
$context_for_twig['is_subscription'] = $product->is_type( array( 'subscription', 'subscription_variation', 'variable-subscription' )) ? true : false; |
||||
|
||||
$context = Timber::get_context(); |
||||
$post = Timber::get_post(); |
||||
$context['post'] = $post; |
||||
$context['wc_breadcrumbs'] = array(); |
||||
|
||||
if (function_exists('woocommerce_breadcrumb')) { |
||||
$args = array( |
||||
'delimiter' => '', |
||||
'wrap_before' => '', |
||||
'wrap_after' => '', |
||||
'before' => '', |
||||
'after' => '', |
||||
'home' => _x('Home', 'breadcrumb', 'woocommerce'), |
||||
); |
||||
|
||||
$breadcrumbs = new WC_Breadcrumb(); |
||||
$breadcrumbs->generate(); |
||||
|
||||
$formatted_breadcrumbs = array(); |
||||
foreach ($breadcrumbs->get_breadcrumb() as $crumb) { |
||||
$formatted_breadcrumbs[] = array( |
||||
'text' => $crumb[0], |
||||
'url' => $crumb[1] |
||||
); |
||||
} |
||||
|
||||
$context['wc_breadcrumbs'] = $formatted_breadcrumbs; |
||||
} |
||||
|
||||
$context['product'] = $product; |
||||
|
||||
$context['related_products'] = array(); |
||||
$related_products_ids = $product->get_upsell_ids(); |
||||
if ($related_products_ids) { |
||||
foreach ($related_products_ids as $related_id) { |
||||
$related_product = wc_get_product($related_id); |
||||
if ($related_product) { |
||||
$context['related_products'][] = $related_product; |
||||
} |
||||
} |
||||
} |
||||
if (class_exists('WCS_ATT_Product_Schemes')) { |
||||
$schemes = WCS_ATT_Product_Schemes::get_subscription_schemes($product); |
||||
$context['has_subscription_options'] = !empty($schemes); |
||||
} else { |
||||
$context['has_subscription_options'] = false; |
||||
} |
||||
|
||||
Timber::render('_pages/shop/product-single.twig', $context); |
||||
|
||||
// Подключение стилей для загрузки корзины |
||||
add_action('wp_enqueue_scripts', 'single_product_cart_styles'); |
||||
|
||||
function single_product_cart_styles() { |
||||
if (is_product()) { |
||||
wp_enqueue_style( |
||||
'single-product-cart-loading', |
||||
get_template_directory_uri() . '/modules/shop/components/single-product/assets/css/cart-loading.css', |
||||
array(), |
||||
'1.0.0' |
||||
); |
||||
} |
||||
} |
@ -1,152 +0,0 @@ |
||||
<?php |
||||
|
||||
|
||||
$product; |
||||
$product_type; |
||||
$context_for_twig; |
||||
|
||||
if (function_exists('is_product') && is_product()) { |
||||
$product_id = get_the_ID(); |
||||
$product = wc_get_product($product_id); |
||||
|
||||
$attributes = []; |
||||
$product_attributes = $product->get_attributes(); |
||||
|
||||
/* Получение категорий */ |
||||
$tags = get_the_terms($product_id, 'product_cat'); |
||||
if (!empty($tags) && !is_wp_error($tags)) { |
||||
foreach ($tags as $tag) { |
||||
$context_for_twig['product_tags'][] = $tag->name; |
||||
} |
||||
} |
||||
|
||||
/* Получение атрибутов */ |
||||
if (!empty($product_attributes)) { |
||||
foreach ($product_attributes as $taxonomy => $attribute) { |
||||
if ($attribute->is_taxonomy()) { |
||||
$terms = wc_get_product_terms($product_id, $taxonomy, ['fields' => 'all']); |
||||
// $tags = wc_get_product_terms( $product_id, 'pa_catalog_tags' ); |
||||
|
||||
if (!empty($terms)) { |
||||
$attr_values = []; |
||||
foreach ($terms as $term) { |
||||
$attr_values[] = [ |
||||
'name' => $term->name, |
||||
'slug' => $term->slug, |
||||
'term_id' => $term->term_id, |
||||
'link' => get_term_link($term->term_id, $taxonomy), |
||||
]; |
||||
} |
||||
$attributes[wc_attribute_label($taxonomy)] = $attr_values; |
||||
} |
||||
} else { |
||||
$attributes[wc_attribute_label($taxonomy)] = $attribute->get_options(); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
$context_for_twig['product_attributes'] = $attributes; |
||||
|
||||
/* Получение вариаций товара */ |
||||
if ($product->is_type('variable')) { |
||||
$available_variations = $product->get_available_variations(); |
||||
$variations_data = []; |
||||
|
||||
foreach ($available_variations as $variation) { |
||||
$variation_id = $variation['variation_id']; |
||||
$variation_obj = wc_get_product($variation_id); |
||||
|
||||
$variations_data[] = [ |
||||
'variation_id' => $variation_id, |
||||
'price' => $variation_obj->get_price(), |
||||
'regular_price' => $variation_obj->get_regular_price(), |
||||
'sale_price' => $variation_obj->get_sale_price(), |
||||
'attributes' => $variation['attributes'] |
||||
]; |
||||
} |
||||
|
||||
$context_for_twig['variations'] = $variations_data; |
||||
} |
||||
|
||||
/* ACF-поля и мета-данные продукта */ |
||||
$meta_fields = [ |
||||
'composition' => get_post_meta($product_id, '_composition', true), |
||||
'feeding_recommendations' => get_post_meta($product_id, '_feeding_recommendations', true), // Ранее выводились HTML-полем «Рекомендации по кормлению» |
||||
'feeding_recommendations_table' => get_field('feeding_recommendations_table', get_post(get_field('p_tables_field', $product_id))) , // Таблица «Рекомендации по кормлению» |
||||
'nutritional_value' => get_post_meta($product_id, '_nutritional_value', true), |
||||
'vitamins' => get_post_meta($product_id, '_vitamins', true), |
||||
'additives' => get_post_meta($product_id, '_additives', true), |
||||
'energy_value' => get_post_meta($product_id, '_energy_value', true), |
||||
'important' => get_post_meta($product_id, '_important', true), |
||||
]; |
||||
|
||||
$context_for_twig['product_meta'] = $meta_fields; |
||||
|
||||
|
||||
|
||||
/* Товар оформляется по подписке? */ |
||||
$context_for_twig['is_subscription'] = $product->is_type( array( 'subscription', 'subscription_variation', 'variable-subscription' )) ? true : false; |
||||
} |
||||
|
||||
|
||||
add_filter('timber/context', function ($context) use ($context_for_twig) { |
||||
return array_merge($context, $context_for_twig); |
||||
}); |
||||
|
||||
|
||||
|
||||
$context = Timber::get_context(); |
||||
$post = Timber::get_post(); |
||||
$context['post'] = $post; |
||||
|
||||
$context['wc_breadcrumbs'] = array(); |
||||
|
||||
if (function_exists('woocommerce_breadcrumb')) { |
||||
$args = array( |
||||
'delimiter' => '', |
||||
'wrap_before' => '', |
||||
'wrap_after' => '', |
||||
'before' => '', |
||||
'after' => '', |
||||
'home' => _x('Home', 'breadcrumb', 'woocommerce'), |
||||
); |
||||
|
||||
$breadcrumbs = new WC_Breadcrumb(); |
||||
$breadcrumbs->generate(); |
||||
|
||||
$formatted_breadcrumbs = array(); |
||||
foreach ($breadcrumbs->get_breadcrumb() as $crumb) { |
||||
$formatted_breadcrumbs[] = array( |
||||
'text' => $crumb[0], |
||||
'url' => $crumb[1] |
||||
); |
||||
} |
||||
|
||||
$context['wc_breadcrumbs'] = $formatted_breadcrumbs; |
||||
} |
||||
|
||||
$product_id = get_the_ID(); |
||||
$product = wc_get_product($product_id); |
||||
|
||||
$context['product'] = $product; |
||||
|
||||
$context['related_products'] = array(); |
||||
$related_products_ids = $product->get_upsell_ids(); |
||||
if ($related_products_ids) { |
||||
foreach ($related_products_ids as $related_id) { |
||||
$related_product = wc_get_product($related_id); |
||||
if ($related_product) { |
||||
$context['related_products'][] = $related_product; |
||||
} |
||||
} |
||||
} |
||||
if (class_exists('WCS_ATT_Product_Schemes')) { |
||||
$schemes = WCS_ATT_Product_Schemes::get_subscription_schemes($product); |
||||
$context['has_subscription_options'] = !empty($schemes); |
||||
} else { |
||||
$context['has_subscription_options'] = false; |
||||
} |
||||
|
||||
|
||||
Timber::render('_pages/shop/product-single.twig', $context); |
@ -1,13 +0,0 @@ |
||||
<?php |
||||
use Timber\Timber; |
||||
global $post; |
||||
|
||||
$context = Timber::get_context(); |
||||
|
||||
include_module('shop'); |
||||
include_component('shop', 'reviews'); |
||||
include_component('shop', 'product-card'); |
||||
|
||||
?> |
||||
<?php |
||||
Timber::render('shop/single-product.twig', $context); |
@ -1,6 +0,0 @@ |
||||
<?php |
||||
|
||||
include_module('author'); |
||||
include_component('author', 'author-single'); |
||||
|
||||
?> |
@ -1,6 +0,0 @@ |
||||
<?php |
||||
|
||||
include_module('blog'); |
||||
include_component('blog', 'single'); |
||||
|
||||
?> |
@ -1,22 +0,0 @@ |
||||
<?php |
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) { |
||||
exit; |
||||
} |
||||
|
||||
if (is_product()) { |
||||
|
||||
include_module('shop'); |
||||
global $product; |
||||
// Get the product ID |
||||
$product_id = get_the_ID(); |
||||
if ($product_id == 1105){ |
||||
include_component('shop', 'single-product_new'); |
||||
} |
||||
else{ |
||||
// include_component('shop', 'single-product'); |
||||
include_component('shop', 'single-product_new'); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,26 @@ |
||||
<?php |
||||
/** |
||||
* The Template for displaying all single posts |
||||
* |
||||
* @link https://developer.wordpress.org/themes/basics/template-hierarchy/ |
||||
*/ |
||||
|
||||
namespace App; |
||||
|
||||
use Timber\Timber; |
||||
|
||||
$context = Timber::context(); |
||||
$post = $context['post']; |
||||
|
||||
if ( is_singular('post') ) { |
||||
include_module('blog'); |
||||
include_component('blog', 'single'); |
||||
} elseif ( is_singular('blog_author') ) { |
||||
include_module('author'); |
||||
include_component('author', 'author-single'); |
||||
} else { |
||||
// Для других типов записей |
||||
$templates = [ 'views/single-' . get_post_type() . '.twig', 'views/single.twig' ]; |
||||
} |
||||
|
||||
Timber::render( $templates, $context ); |
@ -0,0 +1,26 @@ |
||||
{% set in_stock = post.meta('_stock_status') == 'instock' %} |
||||
|
||||
{% set cart_quantity = post.getCartQuantity %} |
||||
{% if in_stock %} |
||||
{% if post.getCartQuantity == 0 %} |
||||
{{ function('do_action', 'woocommerce_' ~ post.product.get_type() ~ '_add_to_cart') }} |
||||
{% else %} |
||||
<div class="product-incart__wrap" data-product-id="{{ post.id }}"> |
||||
<div class="product-incart counter"> |
||||
<button class="product-incart__btn product-incart__btn--minus" data-key="{{post.getCartItemKey}}" data-action="decrease"></button> |
||||
|
||||
<div class="product-incart__count" data-key="{{post.getCartItemKey}}">{{ cart_quantity }}</div> |
||||
<button class="product-incart__btn product-incart__btn--plus" data-key="{{post.getCartItemKey}}" data-action="increase"></button> |
||||
</div> |
||||
<div class="product-incart__label"> |
||||
{{fn('pll_e', 'В корзине')}} |
||||
</div> |
||||
</div> |
||||
{% endif %} |
||||
{% else %} |
||||
<div class="detail-block-form__item detail-block-form__item--tn"> |
||||
<button type="button" data-pname="{{ product.title }}" class="to-know open-to-know" > |
||||
<p>{{ function('pll_e', 'Узнать о поступлении') }}</p> |
||||
</button> |
||||
</div> |
||||
{% endif %} |
@ -0,0 +1,52 @@ |
||||
<?php |
||||
/** |
||||
* The template for displaying WooCommerce pages |
||||
*/ |
||||
|
||||
if (!defined('ABSPATH')) { |
||||
exit; |
||||
} |
||||
|
||||
$context = Timber::context(); |
||||
|
||||
// Добавляем WooCommerce контекст |
||||
if (class_exists('WooCommerce')) { |
||||
$context['is_woocommerce'] = true; |
||||
$context['is_product'] = is_product(); |
||||
$context['is_shop'] = is_shop(); |
||||
|
||||
// Получаем текущий продукт если это страница товара |
||||
if (is_product()) { |
||||
$context['product'] = wc_get_product(get_the_ID()); |
||||
} |
||||
} |
||||
|
||||
// Определяем какой шаблон использовать |
||||
if (is_product()) { |
||||
$product_id = get_the_ID(); |
||||
$categories = get_the_terms($product_id, 'product_cat'); |
||||
$use_new_template = false; |
||||
|
||||
if ($categories && !is_wp_error($categories)) { |
||||
foreach ($categories as $category) { |
||||
if (in_array($category->slug, ['korm', 'lakomstva'])) { |
||||
$use_new_template = true; |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if ($use_new_template) { |
||||
include_component('shop', 'product-single--new'); |
||||
} else { |
||||
include_component('shop', 'product-single'); |
||||
} |
||||
} elseif (is_shop()) { |
||||
include_component('shop', 'catalog'); |
||||
} elseif (is_product_category()) { |
||||
include_component('shop', 'catalog'); |
||||
} else { |
||||
include_component('shop', 'catalog'); |
||||
} |
||||
|
||||
// Рендеринг уже происходит внутри компонентов, поэтому здесь ничего не нужно |
@ -1,5 +0,0 @@ |
||||
<?php |
||||
|
||||
include_component('shop', 'catalog') |
||||
|
||||
?> |