Global-2026-07-12
This commit is contained in:
parent
d5dceedef6
commit
1fa6f06ccf
@ -1239,6 +1239,25 @@ background: rgba(124, 58, 237, 0.2);
|
|||||||
padding-right: 32px;
|
padding-right: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Hero footnote (*) ── */
|
||||||
|
.page-pksh .ds-hero__footnote,
|
||||||
|
.page-pksh .ds-hero__footnote-link {
|
||||||
|
font-size: 1.1em;
|
||||||
|
color: var(--accent, #7C3AED);
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: default;
|
||||||
|
vertical-align: super;
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
.page-pksh .ds-hero__footnote-link {
|
||||||
|
cursor: pointer;
|
||||||
|
transition: color 0.2s;
|
||||||
|
}
|
||||||
|
.page-pksh .ds-hero__footnote-link:hover {
|
||||||
|
color: var(--accent-hover, #6D28D9);
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
25. BANNER GUARANTEE MICRO
|
25. BANNER GUARANTEE MICRO
|
||||||
============================================================ */
|
============================================================ */
|
||||||
@ -2122,6 +2141,39 @@ background: rgba(124, 58, 237, 0.2);
|
|||||||
color: var(--slate-400, #94A3B8);
|
color: var(--slate-400, #94A3B8);
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Logistics chips (как добраться) ── */
|
||||||
|
.page-pksh .pksh-contact__logistics {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 8px;
|
||||||
|
margin: 16px 0 8px;
|
||||||
|
padding: 16px;
|
||||||
|
background: #F8F4F0;
|
||||||
|
border-radius: 16px;
|
||||||
|
border: 1px solid #EDE9E3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-pksh .pksh-contact__logistics-item {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
color: #475569;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-pksh .pksh-contact__logistics-icon {
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 1.125rem;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.page-pksh .pksh-contact__logistics-text {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.page-pksh .pksh-contact__map {
|
.page-pksh .pksh-contact__map {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
@ -2932,3 +2984,62 @@ background: rgba(124, 58, 237, 0.2);
|
|||||||
font-size: 0.75rem;
|
font-size: 0.75rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
32. PHOTO GALLERY
|
||||||
|
3-column grid, cards with rounded corners + shadow.
|
||||||
|
Если caption пустой — img заполняет всю карточку.
|
||||||
|
============================================================ */
|
||||||
|
.pksh-gallery__grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 20px;
|
||||||
|
margin: 28px 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pksh-gallery__item {
|
||||||
|
margin: 0;
|
||||||
|
border-radius: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0 2px 16px rgba(0, 0, 0, 0.07);
|
||||||
|
transition: transform 0.25s ease, box-shadow 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pksh-gallery__item:hover {
|
||||||
|
transform: translateY(-4px);
|
||||||
|
box-shadow: 0 10px 32px rgba(0, 0, 0, 0.12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pksh-gallery__img {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
aspect-ratio: 4 / 3;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pksh-gallery__caption {
|
||||||
|
display: block;
|
||||||
|
padding: 12px 16px 14px;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #334155;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Tablet: 2 columns ── */
|
||||||
|
@media (max-width: 860px) {
|
||||||
|
.pksh-gallery__grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── Mobile: 1 column ── */
|
||||||
|
@media (max-width: 540px) {
|
||||||
|
.pksh-gallery__grid {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
gap: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
21
wp-content/themes/dekart/assets/js/pksh-sticky-cta.js
Normal file
21
wp-content/themes/dekart/assets/js/pksh-sticky-cta.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* Sticky CTA — shows desktop bar when hero scrolls out of view
|
||||||
|
*
|
||||||
|
* IntersectionObserver on .ds-hero; toggles .visible on .sticky-cta-desktop.
|
||||||
|
*
|
||||||
|
* @package Dekart
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var sticky = document.querySelector('.sticky-cta-desktop');
|
||||||
|
var hero = document.querySelector('.ds-hero');
|
||||||
|
if (!sticky || !hero) return;
|
||||||
|
|
||||||
|
var observer = new IntersectionObserver(function (entries) {
|
||||||
|
entries.forEach(function (entry) {
|
||||||
|
sticky.classList.toggle('visible', !entry.isIntersecting);
|
||||||
|
});
|
||||||
|
}, { threshold: 0 });
|
||||||
|
|
||||||
|
observer.observe(hero);
|
||||||
|
})();
|
||||||
50
wp-content/themes/dekart/assets/js/pksh-timer.js
Normal file
50
wp-content/themes/dekart/assets/js/pksh-timer.js
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Honest countdown timer — Подготовка к школе
|
||||||
|
*
|
||||||
|
* Reads deadline timestamp (seconds) from .honest-timer[data-deadline].
|
||||||
|
* Finds [data-timer] children within that timer container only.
|
||||||
|
* Updates (d, h, m, s) via requestAnimationFrame. Stops at 00:00:00:00.
|
||||||
|
*
|
||||||
|
* Поддерживает несколько таймеров на одной странице (cta-test + final-cta).
|
||||||
|
* Каждый экземпляр получает собственную замыкание.
|
||||||
|
*
|
||||||
|
* @package Dekart
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var timers = document.querySelectorAll('.honest-timer');
|
||||||
|
if (!timers.length) return;
|
||||||
|
|
||||||
|
function pad(n) {
|
||||||
|
return n < 10 ? '0' + n : '' + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
[].forEach.call(timers, function (timerEl) {
|
||||||
|
var deadline = parseInt(timerEl.getAttribute('data-deadline'), 10);
|
||||||
|
if (!deadline || deadline <= 0) return;
|
||||||
|
|
||||||
|
var deadlineMs = deadline * 1000;
|
||||||
|
var els = timerEl.querySelectorAll('[data-timer]');
|
||||||
|
if (!els.length) return;
|
||||||
|
|
||||||
|
var map = {};
|
||||||
|
[].forEach.call(els, function (el) {
|
||||||
|
map[el.getAttribute('data-timer')] = el;
|
||||||
|
});
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
var diff = deadlineMs - Date.now();
|
||||||
|
if (diff <= 0) {
|
||||||
|
for (var key in map) map[key].textContent = '00';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
map.d.textContent = pad(Math.floor(diff / 86400000));
|
||||||
|
map.h.textContent = pad(Math.floor((diff % 86400000) / 3600000));
|
||||||
|
map.m.textContent = pad(Math.floor((diff % 3600000) / 60000));
|
||||||
|
map.s.textContent = pad(Math.floor((diff % 60000) / 1000));
|
||||||
|
requestAnimationFrame(tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
tick();
|
||||||
|
});
|
||||||
|
})();
|
||||||
79
wp-content/themes/dekart/assets/js/yandex-map.js
Normal file
79
wp-content/themes/dekart/assets/js/yandex-map.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Yandex Maps lazy loader — shared across all pages
|
||||||
|
*
|
||||||
|
* Activates only when #ya-map[data-coords] is present.
|
||||||
|
* Loads Yandex Maps API on first scroll > 100px (passive) or after 3s fallback.
|
||||||
|
* Creates map with a placemark at the given coordinates.
|
||||||
|
*
|
||||||
|
* Required data attributes on #ya-map:
|
||||||
|
* data-coords — comma-separated lat,lng (e.g. "55.7558,37.6173")
|
||||||
|
* data-label — placemark text (e.g. "Детский центр «Декарт»")
|
||||||
|
*
|
||||||
|
* @package Dekart
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
var mapEl = document.getElementById('ya-map');
|
||||||
|
if (!mapEl) return;
|
||||||
|
|
||||||
|
var coordsAttr = mapEl.getAttribute('data-coords');
|
||||||
|
var label = mapEl.getAttribute('data-label') || '';
|
||||||
|
if (!coordsAttr) return;
|
||||||
|
|
||||||
|
var parts = coordsAttr.split(',');
|
||||||
|
if (parts.length < 2) return;
|
||||||
|
var mapCoords = [parseFloat(parts[0]), parseFloat(parts[1])];
|
||||||
|
if (isNaN(mapCoords[0]) || isNaN(mapCoords[1])) return;
|
||||||
|
|
||||||
|
var mapLoaded = false;
|
||||||
|
var apiLoading = false;
|
||||||
|
|
||||||
|
function initMap() {
|
||||||
|
if (typeof ymaps === 'undefined') return;
|
||||||
|
ymaps.ready(function () {
|
||||||
|
var map = new ymaps.Map('ya-map', {
|
||||||
|
center: mapCoords,
|
||||||
|
zoom: 16
|
||||||
|
}, {
|
||||||
|
searchControlProvider: 'yandex#search'
|
||||||
|
});
|
||||||
|
var placemark = new ymaps.Placemark(
|
||||||
|
mapCoords,
|
||||||
|
{ iconContent: label },
|
||||||
|
{ preset: 'islands#redStretchyIcon' }
|
||||||
|
);
|
||||||
|
map.geoObjects.add(placemark);
|
||||||
|
mapLoaded = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadYandexMaps() {
|
||||||
|
if (mapLoaded || apiLoading) return;
|
||||||
|
apiLoading = true;
|
||||||
|
var script = document.createElement('script');
|
||||||
|
script.src = 'https://api-maps.yandex.ru/2.1/?lang=ru_RU';
|
||||||
|
script.onerror = function () {
|
||||||
|
apiLoading = false;
|
||||||
|
};
|
||||||
|
script.onload = initMap;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll trigger — first >100px
|
||||||
|
function onScroll() {
|
||||||
|
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||||
|
if (scrollTop > 100) {
|
||||||
|
loadYandexMaps();
|
||||||
|
window.removeEventListener('scroll', onScroll);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback — 3 seconds after page load
|
||||||
|
window.addEventListener('load', function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
if (!mapLoaded && !apiLoading) loadYandexMaps();
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('scroll', onScroll, { passive: true });
|
||||||
|
})();
|
||||||
@ -555,6 +555,9 @@ function add_carbon() {
|
|||||||
->set_width( 50 )
|
->set_width( 50 )
|
||||||
->set_default_value( 'Первое занятие — бесплатно. Результат через 3 недели — или вернём деньги' )
|
->set_default_value( 'Первое занятие — бесплатно. Результат через 3 недели — или вернём деньги' )
|
||||||
->set_help_text( 'Текст под заголовком. Опционально.' ),
|
->set_help_text( 'Текст под заголовком. Опционально.' ),
|
||||||
|
Field::make( 'text', 'banner_subtitle_footnote_link', 'Ссылка для звёздочки (*) в подзаголовке' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'URL для иконки * после текста подзаголовка. Если не указано — * неактивна.' ),
|
||||||
Field::make( 'text', 'banner_scarcity', 'Текст дефицита (срочность)' )
|
Field::make( 'text', 'banner_scarcity', 'Текст дефицита (срочность)' )
|
||||||
->set_width( 50 )
|
->set_width( 50 )
|
||||||
->set_default_value( '🔥 Осталось <strong>2 места из 8</strong> в группе 5–6 лет. Стартуем <strong>1 июня</strong>' )
|
->set_default_value( '🔥 Осталось <strong>2 места из 8</strong> в группе 5–6 лет. Стартуем <strong>1 июня</strong>' )
|
||||||
@ -782,6 +785,24 @@ function add_carbon() {
|
|||||||
->set_attribute( 'placeholder', 'Чтение, Счёт до 100, Письмо печатными буквами' )
|
->set_attribute( 'placeholder', 'Чтение, Счёт до 100, Письмо печатными буквами' )
|
||||||
->set_help_text( 'Например: "Чтение", "Счёт до 100", "Письмо печатными буквами"' ),
|
->set_help_text( 'Например: "Чтение", "Счёт до 100", "Письмо печатными буквами"' ),
|
||||||
)),
|
)),
|
||||||
|
))
|
||||||
|
// ====================================================
|
||||||
|
// Вкладка: Фотогалерея
|
||||||
|
// ====================================================
|
||||||
|
->add_tab('📸 Фотогалерея', array(
|
||||||
|
Field::make( 'html', 'pksh_gallery_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>#gallery</strong>. Фотографии занятий, 3 в ряд. Если фото не добавлены — секция не выводится.</p>' ),
|
||||||
|
Field::make( 'complex', 'pksh_gallery', 'Фотографии' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Добавьте фотографии с занятий. Оптимальная ширина: 600–1200 px.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'image', 'gallery_image', 'Фото' )
|
||||||
|
->set_width( 60 )
|
||||||
|
->set_help_text( 'Рекомендуемый размер: 800×600 px, соотношение 4:3 или 3:2.' ),
|
||||||
|
Field::make( 'text', 'gallery_caption', 'Подпись (опционально)' )
|
||||||
|
->set_width( 40 )
|
||||||
|
->set_help_text( 'Короткая подпись под фото. Если не указана — только фото.' ),
|
||||||
|
)),
|
||||||
));
|
));
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
@ -1439,6 +1460,16 @@ function dekart_parse_b24_script( string $script ): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function enqueue_template_specific_styles() {
|
function enqueue_template_specific_styles() {
|
||||||
|
// Yandex Maps — загружается на всех страницах.
|
||||||
|
// JS сам проверяет наличие #ya-map[data-coords] перед активацией.
|
||||||
|
wp_enqueue_script(
|
||||||
|
'yandex-map',
|
||||||
|
get_template_directory_uri() . '/assets/js/yandex-map.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/assets/js/yandex-map.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
if ( is_page_template('page-camp.php') ) {
|
if ( is_page_template('page-camp.php') ) {
|
||||||
wp_enqueue_style(
|
wp_enqueue_style(
|
||||||
'template-specific-style',
|
'template-specific-style',
|
||||||
@ -1486,6 +1517,20 @@ function enqueue_template_specific_styles() {
|
|||||||
array(),
|
array(),
|
||||||
'2.1.' . filemtime(get_template_directory() . '/assets/css/podgotovka-k-shkole.css')
|
'2.1.' . filemtime(get_template_directory() . '/assets/css/podgotovka-k-shkole.css')
|
||||||
);
|
);
|
||||||
|
wp_enqueue_script(
|
||||||
|
'pksh-timer',
|
||||||
|
get_template_directory_uri() . '/assets/js/pksh-timer.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/assets/js/pksh-timer.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
wp_enqueue_script(
|
||||||
|
'pksh-sticky-cta',
|
||||||
|
get_template_directory_uri() . '/assets/js/pksh-sticky-cta.js',
|
||||||
|
array(),
|
||||||
|
filemtime( get_template_directory() . '/assets/js/pksh-sticky-cta.js' ),
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if ( is_page_template('front-page.php') || is_front_page() ) {
|
if ( is_page_template('front-page.php') || is_front_page() ) {
|
||||||
wp_enqueue_style(
|
wp_enqueue_style(
|
||||||
@ -1505,6 +1550,11 @@ function enqueue_template_specific_styles() {
|
|||||||
}
|
}
|
||||||
add_action('wp_enqueue_scripts', 'enqueue_template_specific_styles');
|
add_action('wp_enqueue_scripts', 'enqueue_template_specific_styles');
|
||||||
|
|
||||||
|
// Удаляем wp-block-library (Gutenberg inline стили) — тема кастомная, блоки не используются
|
||||||
|
add_action('wp_enqueue_scripts', static function () {
|
||||||
|
wp_dequeue_style('wp-block-library');
|
||||||
|
}, 100);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper: determine if current page needs Swiper slider assets.
|
* Helper: determine if current page needs Swiper slider assets.
|
||||||
*
|
*
|
||||||
|
|||||||
@ -31,6 +31,7 @@ class Pksh_Data {
|
|||||||
private ?array $teachers = null;
|
private ?array $teachers = null;
|
||||||
private ?array $reviews = null;
|
private ?array $reviews = null;
|
||||||
private ?array $faq = null;
|
private ?array $faq = null;
|
||||||
|
private ?array $gallery = null;
|
||||||
|
|
||||||
private function __construct() {
|
private function __construct() {
|
||||||
$this->post_id = get_the_ID();
|
$this->post_id = get_the_ID();
|
||||||
@ -202,6 +203,16 @@ class Pksh_Data {
|
|||||||
return $this->page['subtitle'];
|
return $this->page['subtitle'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ссылка для * в подзаголовке hero
|
||||||
|
*/
|
||||||
|
public function get_subtitle_footnote_link(): string {
|
||||||
|
if ( ! array_key_exists( 'subtitle_footnote_link', $this->page ) ) {
|
||||||
|
$this->page['subtitle_footnote_link'] = carbon_get_post_meta( $this->post_id, 'banner_subtitle_footnote_link' ) ?: '';
|
||||||
|
}
|
||||||
|
return $this->page['subtitle_footnote_link'];
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// SOCIAL COUNTERS (complex)
|
// SOCIAL COUNTERS (complex)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@ -339,6 +350,22 @@ class Pksh_Data {
|
|||||||
return $this->faq;
|
return $this->faq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// GALLERY (complex)
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Массив фотографий (complex field pksh_gallery)
|
||||||
|
* @return array[]
|
||||||
|
*/
|
||||||
|
public function get_gallery(): array {
|
||||||
|
if ( null === $this->gallery ) {
|
||||||
|
$raw = carbon_get_post_meta( $this->post_id, 'pksh_gallery' );
|
||||||
|
$this->gallery = is_array( $raw ) ? $raw : [];
|
||||||
|
}
|
||||||
|
return $this->gallery;
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================
|
// ============================================================
|
||||||
// HONEST TIMER (shared helper)
|
// HONEST TIMER (shared helper)
|
||||||
// ============================================================
|
// ============================================================
|
||||||
@ -367,7 +394,7 @@ class Pksh_Data {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<div class="honest-timer">
|
<div class="honest-timer" data-deadline="<?php echo (int) $ts; ?>">
|
||||||
<span class="honest-timer__label"><?php echo esc_html( $label ); ?></span>
|
<span class="honest-timer__label"><?php echo esc_html( $label ); ?></span>
|
||||||
<div class="honest-timer__digits">
|
<div class="honest-timer__digits">
|
||||||
<span class="honest-timer__unit">
|
<span class="honest-timer__unit">
|
||||||
@ -391,10 +418,6 @@ class Pksh_Data {
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script>window.__HONEST_DEADLINE=<?php echo (int) $ts; ?>;</script>
|
|
||||||
<script>
|
|
||||||
!function(){var e=window.__HONEST_DEADLINE;if(!e)return;e*=1e3;var t=document.querySelectorAll('[data-timer]');if(!t.length)return;var n={};t.forEach(function(r){n[r.getAttribute('data-timer')]=r});var o=function(r){return r<10?'0'+r:''+r};!function r(){var t=e-Date.now();if(t<=0){for(var u in n)n[u].textContent='00';return}n.d.textContent=o(Math.floor(t/864e5)),n.h.textContent=o(Math.floor(t%864e5/36e5)),n.m.textContent=o(Math.floor(t%36e5/6e4)),n.s.textContent=o(Math.floor(t%6e4/1e3)),requestAnimationFrame(r)}()}();
|
|
||||||
</script>
|
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,12 +25,32 @@ add_filter( 'wpseo_json_ld_output', '__return_false' );
|
|||||||
*/
|
*/
|
||||||
add_filter( 'wpseo_opengraph_type', 'dekart_schema_og_type', 10, 1 );
|
add_filter( 'wpseo_opengraph_type', 'dekart_schema_og_type', 10, 1 );
|
||||||
function dekart_schema_og_type( string $type ): string {
|
function dekart_schema_og_type( string $type ): string {
|
||||||
if ( is_page( 2 ) ) {
|
if ( is_page( 2 ) || is_page_template( 'page-camp.php' ) ) {
|
||||||
return 'website';
|
return 'website';
|
||||||
}
|
}
|
||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Убираем article:* OG-теги для страницы Подготовки к школе (ID=2),
|
||||||
|
* чтобы не было конфликта og:type=website с article:modified_time.
|
||||||
|
* Аналог page-camp.php:15-27.
|
||||||
|
*/
|
||||||
|
add_filter( 'wpseo_frontend_presenter_classes', function( array $presenters ): array {
|
||||||
|
if ( ! is_page( 2 ) ) {
|
||||||
|
return $presenters;
|
||||||
|
}
|
||||||
|
$presenters = array_filter( $presenters, function( string $p ): bool {
|
||||||
|
return strpos( $p, 'Article_Modified_Time' ) === false
|
||||||
|
&& strpos( $p, 'Article_Published_Time' ) === false
|
||||||
|
&& strpos( $p, 'Article_Author' ) === false
|
||||||
|
&& strpos( $p, 'Article_Publisher' ) === false
|
||||||
|
&& strpos( $p, 'Label1' ) === false
|
||||||
|
&& strpos( $p, 'Data1' ) === false;
|
||||||
|
} );
|
||||||
|
return $presenters;
|
||||||
|
} );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Главная функция: сборка @graph и вывод в wp_head.
|
* Главная функция: сборка @graph и вывод в wp_head.
|
||||||
* Срабатывает только на странице ID=2 (Подготовка к школе).
|
* Срабатывает только на странице ID=2 (Подготовка к школе).
|
||||||
@ -766,6 +786,43 @@ function dekart_schema_course(): ?array {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// review — 1-2 отзыва прямо в Course (Google требует для звёзд в rich snippet)
|
||||||
|
$reviews_raw = carbon_get_post_meta( 2, 'pksh_reviews_list' );
|
||||||
|
if ( ! empty( $reviews_raw ) && is_array( $reviews_raw ) ) {
|
||||||
|
$review_items = array();
|
||||||
|
foreach ( $reviews_raw as $rv ) {
|
||||||
|
$author = isset( $rv['review_author'] ) ? trim( $rv['review_author'] ) : '';
|
||||||
|
$body = isset( $rv['review_text'] ) ? trim( $rv['review_text'] ) : '';
|
||||||
|
$rating = isset( $rv['review_rating'] ) ? intval( $rv['review_rating'] ) : 0;
|
||||||
|
if ( empty( $author ) || empty( $body ) || $rating < 1 || $rating > 5 ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$item = array(
|
||||||
|
'@type' => 'Review',
|
||||||
|
'author' => array( '@type' => 'Person', 'name' => wp_strip_all_tags( $author ) ),
|
||||||
|
'reviewBody' => wp_strip_all_tags( $body ),
|
||||||
|
'reviewRating' => array(
|
||||||
|
'@type' => 'Rating',
|
||||||
|
'ratingValue' => (string) $rating,
|
||||||
|
'bestRating' => '5',
|
||||||
|
'worstRating' => '1',
|
||||||
|
),
|
||||||
|
'itemReviewed' => array( '@id' => $page_url . '#course' ),
|
||||||
|
);
|
||||||
|
$date = isset( $rv['review_date'] ) ? trim( $rv['review_date'] ) : '';
|
||||||
|
if ( $date ) {
|
||||||
|
$item['datePublished'] = sanitize_text_field( $date );
|
||||||
|
}
|
||||||
|
$review_items[] = $item;
|
||||||
|
if ( count( $review_items ) >= 2 ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( ! empty( $review_items ) ) {
|
||||||
|
$course['review'] = $review_items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// educationalLevel — уровень образования (условно)
|
// educationalLevel — уровень образования (условно)
|
||||||
if ( ! empty( $level ) && is_string( $level ) ) {
|
if ( ! empty( $level ) && is_string( $level ) ) {
|
||||||
$course['educationalLevel'] = wp_strip_all_tags( trim( $level ) );
|
$course['educationalLevel'] = wp_strip_all_tags( trim( $level ) );
|
||||||
@ -790,10 +847,7 @@ function dekart_schema_course(): ?array {
|
|||||||
foreach ( $skills as $skill ) {
|
foreach ( $skills as $skill ) {
|
||||||
$name = isset( $skill['skill'] ) ? trim( $skill['skill'] ) : '';
|
$name = isset( $skill['skill'] ) ? trim( $skill['skill'] ) : '';
|
||||||
if ( $name ) {
|
if ( $name ) {
|
||||||
$teaches[] = array(
|
$teaches[] = wp_strip_all_tags( $name );
|
||||||
'@type' => 'Thing',
|
|
||||||
'name' => wp_strip_all_tags( $name ),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( ! empty( $teaches ) ) {
|
if ( ! empty( $teaches ) ) {
|
||||||
|
|||||||
@ -40,6 +40,7 @@ get_header();
|
|||||||
get_template_part( 'template-parts/block-price' );
|
get_template_part( 'template-parts/block-price' );
|
||||||
|
|
||||||
get_template_part( 'template-parts/pksh/teachers' );
|
get_template_part( 'template-parts/pksh/teachers' );
|
||||||
|
get_template_part( 'template-parts/pksh/gallery' );
|
||||||
get_template_part( 'template-parts/pksh/guarantee-standalone' );
|
get_template_part( 'template-parts/pksh/guarantee-standalone' );
|
||||||
get_template_part( 'template-parts/pksh/faq' );
|
get_template_part( 'template-parts/pksh/faq' );
|
||||||
get_template_part( 'template-parts/pksh/reviews' );
|
get_template_part( 'template-parts/pksh/reviews' );
|
||||||
|
|||||||
@ -6,69 +6,9 @@
|
|||||||
<?php echo esc_html( carbon_get_theme_option( 'site_address' ) ); ?>
|
<?php echo esc_html( carbon_get_theme_option( 'site_address' ) ); ?>
|
||||||
<span><?php echo esc_html( carbon_get_theme_option( 'site_name' ) ); ?></span>
|
<span><?php echo esc_html( carbon_get_theme_option( 'site_name' ) ); ?></span>
|
||||||
</div>
|
</div>
|
||||||
<div id="ya-map" style="width: 100%; height: 420px;"></div>
|
<div id="ya-map" style="width: 100%; height: 420px;"
|
||||||
|
data-coords="<?php echo esc_attr( carbon_get_theme_option( 'site_location' ) ); ?>"
|
||||||
|
data-label="<?php echo esc_attr( carbon_get_theme_option( 'site_name' ) ); ?>"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
// Координаты и флаги — берём из PHP один раз
|
|
||||||
var mapCoords = [<?php echo esc_js( carbon_get_theme_option( 'site_location' ) ); ?>];
|
|
||||||
var mapLabel = '<?php echo esc_js( carbon_get_theme_option( 'site_name' ) ); ?>';
|
|
||||||
var mapLoaded = false;
|
|
||||||
var apiLoading = false;
|
|
||||||
|
|
||||||
function initMap() {
|
|
||||||
ymaps.ready(function() {
|
|
||||||
var map = new ymaps.Map('ya-map', {
|
|
||||||
center: mapCoords,
|
|
||||||
zoom: 16
|
|
||||||
}, {
|
|
||||||
searchControlProvider: 'yandex#search'
|
|
||||||
});
|
|
||||||
var placemark = new ymaps.Placemark(
|
|
||||||
mapCoords,
|
|
||||||
{ iconContent: mapLabel },
|
|
||||||
{ preset: 'islands#redStretchyIcon' }
|
|
||||||
);
|
|
||||||
map.geoObjects.add(placemark);
|
|
||||||
mapLoaded = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadYandexMaps() {
|
|
||||||
if (mapLoaded || apiLoading) return;
|
|
||||||
apiLoading = true;
|
|
||||||
|
|
||||||
// Динамически создаём тег <script> — API грузится только сейчас,
|
|
||||||
// а не при загрузке страницы. Экономит ~200kb в критическом пути.
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.src = 'https://api-maps.yandex.ru/2.1/?lang=ru_RU';
|
|
||||||
script.onerror = function() { console.warn("Yandex Maps API failed to load"); apiLoading = false; };
|
|
||||||
script.onload = initMap;
|
|
||||||
document.head.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Запускаем загрузку при первом скролле > 100px
|
|
||||||
function onScroll() {
|
|
||||||
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
|
||||||
if (scrollTop > 100) {
|
|
||||||
loadYandexMaps();
|
|
||||||
window.removeEventListener('scroll', onScroll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Запасной вариант: если карта видна без скролла (большой экран)
|
|
||||||
// — грузим через 3 секунды после загрузки страницы
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
setTimeout(function() {
|
|
||||||
if (!mapLoaded && !apiLoading) {
|
|
||||||
loadYandexMaps();
|
|
||||||
}
|
|
||||||
}, 3000);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.addEventListener('scroll', onScroll, { passive: true });
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
@ -42,6 +42,21 @@ $opt_name = $data->get_name();
|
|||||||
<div class="pksh-contact__value"><?php echo esc_html( $opt_address ); ?></div>
|
<div class="pksh-contact__value"><?php echo esc_html( $opt_address ); ?></div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="pksh-contact__logistics">
|
||||||
|
<span class="pksh-contact__logistics-item">
|
||||||
|
<span class="pksh-contact__logistics-icon">📍</span>
|
||||||
|
<span class="pksh-contact__logistics-text">5 минут пешком от ТЦ «Глобус»</span>
|
||||||
|
</span>
|
||||||
|
<span class="pksh-contact__logistics-item">
|
||||||
|
<span class="pksh-contact__logistics-icon">🅿️</span>
|
||||||
|
<span class="pksh-contact__logistics-text">Есть бесплатная парковка у входа</span>
|
||||||
|
</span>
|
||||||
|
<span class="pksh-contact__logistics-item">
|
||||||
|
<span class="pksh-contact__logistics-icon">🚸</span>
|
||||||
|
<span class="pksh-contact__logistics-text">Рядом со школами №9 и №12, детским садом №15</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<?php if ( ! empty( $opt_social ) && is_array( $opt_social ) ) : ?>
|
<?php if ( ! empty( $opt_social ) && is_array( $opt_social ) ) : ?>
|
||||||
<div class="pksh-contact__subtitle">Наши соцсети:</div>
|
<div class="pksh-contact__subtitle">Наши соцсети:</div>
|
||||||
<div class="pksh-contact__social">
|
<div class="pksh-contact__social">
|
||||||
@ -58,58 +73,11 @@ $opt_name = $data->get_name();
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="pksh-contact__map">
|
<div class="pksh-contact__map">
|
||||||
<div id="ya-map" style="width: 100%; height: 100%; min-height: 400px;"></div>
|
<div id="ya-map" style="width: 100%; height: 100%; min-height: 400px;"
|
||||||
|
data-coords="<?php echo esc_attr( $opt_coords ?: '55.7558,37.6173' ); ?>"
|
||||||
|
data-label="<?php echo esc_attr( $opt_name ?: 'Детский центр «Декарт»' ); ?>"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
var mapCoords = [<?php echo esc_js( $opt_coords ?: '55.7558,37.6173' ); ?>];
|
|
||||||
var mapLabel = '<?php echo esc_js( $opt_name ); ?>';
|
|
||||||
var mapLoaded = false;
|
|
||||||
var apiLoading = false;
|
|
||||||
|
|
||||||
function initMap() {
|
|
||||||
ymaps.ready(function() {
|
|
||||||
var map = new ymaps.Map('ya-map', {
|
|
||||||
center: mapCoords,
|
|
||||||
zoom: 16
|
|
||||||
}, {
|
|
||||||
searchControlProvider: 'yandex#search'
|
|
||||||
});
|
|
||||||
var placemark = new ymaps.Placemark(
|
|
||||||
mapCoords,
|
|
||||||
{ iconContent: mapLabel },
|
|
||||||
{ preset: 'islands#redStretchyIcon' }
|
|
||||||
);
|
|
||||||
map.geoObjects.add(placemark);
|
|
||||||
mapLoaded = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadYandexMaps() {
|
|
||||||
if (mapLoaded || apiLoading) return;
|
|
||||||
apiLoading = true;
|
|
||||||
var script = document.createElement('script');
|
|
||||||
script.src = 'https://api-maps.yandex.ru/2.1/?lang=ru_RU';
|
|
||||||
script.onerror = function() { <?php if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) : ?>console.warn("Yandex Maps API failed to load");<?php endif; ?> apiLoading = false; };
|
|
||||||
script.onload = initMap;
|
|
||||||
document.head.appendChild(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onScroll() {
|
|
||||||
if ((window.pageYOffset || document.documentElement.scrollTop) > 100) {
|
|
||||||
loadYandexMaps();
|
|
||||||
window.removeEventListener('scroll', onScroll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
setTimeout(function() {
|
|
||||||
if (!mapLoaded && !apiLoading) loadYandexMaps();
|
|
||||||
}, 3000);
|
|
||||||
});
|
|
||||||
window.addEventListener('scroll', onScroll, { passive: true });
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|||||||
56
wp-content/themes/dekart/template-parts/pksh/gallery.php
Normal file
56
wp-content/themes/dekart/template-parts/pksh/gallery.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Фотогалерея (сетка 3 колонки)
|
||||||
|
* .bento .pksh-section #gallery
|
||||||
|
*
|
||||||
|
* @package Dekart
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = Pksh_Data::instance();
|
||||||
|
$gallery = $data->get_gallery();
|
||||||
|
|
||||||
|
if ( empty( $gallery ) || ! is_array( $gallery ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<section class="bento pksh-section" id="gallery" aria-label="Фотогалерея">
|
||||||
|
<div class="bento__full section-header--centered">
|
||||||
|
<span class="bento-label">Фотогалерея</span>
|
||||||
|
<h2 class="bento-h2">Как проходят занятия</h2>
|
||||||
|
<p class="bento-p">Фотографии с наших уроков — посмотрите, как увлекательно и продуктивно проходят занятия в центре «Декарт».</p>
|
||||||
|
</div>
|
||||||
|
<div class="bento__full">
|
||||||
|
<div class="pksh-gallery__grid">
|
||||||
|
<?php foreach ( $gallery as $item ) :
|
||||||
|
$img_id = $item['gallery_image'] ?? 0;
|
||||||
|
$caption = $item['gallery_caption'] ?? '';
|
||||||
|
|
||||||
|
if ( empty( $img_id ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$img_full = wp_get_attachment_image_url( $img_id, 'full' );
|
||||||
|
$img_thumb = wp_get_attachment_image_url( $img_id, 'medium_large' );
|
||||||
|
$img_alt = $caption ? wp_strip_all_tags( $caption ) : esc_attr__( 'Фото занятия', 'dekart' );
|
||||||
|
|
||||||
|
if ( empty( $img_full ) || empty( $img_thumb ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<figure class="pksh-gallery__item">
|
||||||
|
<img class="pksh-gallery__img" src="<?php echo esc_url( $img_thumb ); ?>"
|
||||||
|
alt="<?php echo esc_attr( $img_alt ); ?>"
|
||||||
|
loading="lazy" decoding="async">
|
||||||
|
<?php if ( $caption ) : ?>
|
||||||
|
<figcaption class="pksh-gallery__caption"><?php echo esc_html( $caption ); ?></figcaption>
|
||||||
|
<?php endif; ?>
|
||||||
|
</figure>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<?php
|
||||||
@ -9,6 +9,9 @@
|
|||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data = Pksh_Data::instance();
|
||||||
|
$footnote_url = $data->get_subtitle_footnote_link();
|
||||||
?>
|
?>
|
||||||
<section class="bento pksh-section" aria-label="Гарантия">
|
<section class="bento pksh-section" aria-label="Гарантия">
|
||||||
<div class="bento__full">
|
<div class="bento__full">
|
||||||
@ -18,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
</div>
|
</div>
|
||||||
<div class="guarantee-hero__content">
|
<div class="guarantee-hero__content">
|
||||||
<h2 class="bento-h2">Ваш ребёнок начнёт читать через 3 недели</h2>
|
<h2 class="bento-h2">Ваш ребёнок начнёт читать через 3 недели</h2>
|
||||||
<p class="guarantee-hero__text">Или <strong>мы вернём деньги</strong> и продолжим обучение бесплатно, пока не дойдём до результата. Мы — частная школа <strong>с гослицензией</strong>, а не кружок. Отвечаем за результат.</p>
|
<p class="guarantee-hero__text">Или <strong>мы вернём деньги</strong> и продолжим обучение бесплатно, пока не дойдём до результата.<?php if ( $footnote_url ) : ?><sup><a href="<?php echo esc_url( $footnote_url ); ?>" class="ds-hero__footnote-link" target="_blank" rel="noopener noreferrer">*</a></sup><?php else : ?><sup class="ds-hero__footnote">*</sup><?php endif; ?> Мы — частная школа <strong>с гослицензией</strong>, а не кружок. Отвечаем за результат.</p>
|
||||||
</div>
|
</div>
|
||||||
<nav class="pksh-anchor-nav" aria-label="Навигация по странице">
|
<nav class="pksh-anchor-nav" aria-label="Навигация по странице">
|
||||||
<a href="#how-it-works" class="pksh-anchor-link">Как проходят занятия</a>
|
<a href="#how-it-works" class="pksh-anchor-link">Как проходят занятия</a>
|
||||||
|
|||||||
@ -39,8 +39,10 @@ $hero_metrics = $data->get_social_counters();
|
|||||||
|
|
||||||
<h1 class="ds-hero__h1"><?php echo esc_html( $h1_hero ?: 'Подготовка к школе в Щёлково' ); ?></h1>
|
<h1 class="ds-hero__h1"><?php echo esc_html( $h1_hero ?: 'Подготовка к школе в Щёлково' ); ?></h1>
|
||||||
|
|
||||||
<?php if ( '' !== $subtitle_hero ) : ?>
|
<?php if ( '' !== $subtitle_hero ) :
|
||||||
<p class="ds-hero__subtitle"><?php echo esc_html( $subtitle_hero ); ?></p>
|
$footnote_url = $data->get_subtitle_footnote_link();
|
||||||
|
?>
|
||||||
|
<p class="ds-hero__subtitle"><?php echo esc_html( $subtitle_hero ); ?><?php if ( $footnote_url ) : ?><sup><a href="<?php echo esc_url( $footnote_url ); ?>" class="ds-hero__footnote-link" target="_blank" rel="noopener noreferrer">*</a></sup><?php else : ?><sup class="ds-hero__footnote">*</sup><?php endif; ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ( ! empty( $hero_metrics ) && is_array( $hero_metrics ) ) : ?>
|
<?php if ( ! empty( $hero_metrics ) && is_array( $hero_metrics ) ) : ?>
|
||||||
|
|||||||
@ -26,19 +26,3 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||||||
<button class="sticky-cta-desktop__btn btn-write">Записаться</button>
|
<button class="sticky-cta-desktop__btn btn-write">Записаться</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
|
||||||
(function() {
|
|
||||||
var sticky = document.querySelector('.sticky-cta-desktop');
|
|
||||||
var hero = document.querySelector('.ds-hero');
|
|
||||||
if (!sticky || !hero) return;
|
|
||||||
|
|
||||||
var observer = new IntersectionObserver(function(entries) {
|
|
||||||
entries.forEach(function(entry) {
|
|
||||||
sticky.classList.toggle('visible', !entry.isIntersecting);
|
|
||||||
});
|
|
||||||
}, { threshold: 0 });
|
|
||||||
|
|
||||||
observer.observe(hero);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user