fix: SEO audit fixes for /otzyvy/ — Schema.org, PHP, JS, CSS, A11Y
Critical: - Move GeoCoordinates from PostalAddress to Organization level - Fix AggregateRating @id to point at #organization, not page URL High: - Replace Review.itemReviewed inline LocalBusiness with @id reference - Change @type from array to just 'School' - Remove foundingDate from reviews page (add comment for CF) - Make telephone property conditional (only when non-empty) - Add postalCode from branch_postal_code option - Fix branch_city fallback from 'городе' to 'Щёлково' - Replace inline onclick yaCounter with JS global handler - Remove inline critical CSS (styles in file) - Move price text to CF field reviews_intro_price_text Medium: - Add --color-bg and --accent CSS variables - Fix .page-rewiews typo → .page-reviews - Fix .contact-map display:flex→block - Add prefers-reduced-motion support - JS: var→let/const, scroll throttle via requestAnimationFrame - JS: catch(e)→console.warn - JS: data-target→data-target-value (avoid conflict) - A11Y: FAQ aria-expanded/aria-controls, phone aria-label - A11Y: modal role=dialog aria-modal=true - A11Y: breadcrumb role=navigation aria-label - Remove desktop-only class from breadcrumbs (mobile support) Low: - Add preconnect for unpkg.com (Phosphor Icons CDN) - Add decoding=async to gallery images
This commit is contained in:
parent
6f5feb7521
commit
c7bd6cef74
1906
wp-content/themes/dekart/assets/css/reviews-page.css
Normal file
1906
wp-content/themes/dekart/assets/css/reviews-page.css
Normal file
File diff suppressed because it is too large
Load Diff
222
wp-content/themes/dekart/assets/js/reviews-page.js
Normal file
222
wp-content/themes/dekart/assets/js/reviews-page.js
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
/**
|
||||||
|
* reviews-page.js — интерактив для page-reviews.php
|
||||||
|
* Анимации, фильтры, sticky CTA, FAQ, пагинация
|
||||||
|
*
|
||||||
|
* @package Dekart
|
||||||
|
*/
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 1. АНИМАЦИЯ ПОЯВЛЕНИЯ (Intersection Observer)
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
const revealElements = document.querySelectorAll('.reveal');
|
||||||
|
if (revealElements.length && 'IntersectionObserver' in window) {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
function (entries) {
|
||||||
|
entries.forEach(function (entry) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
entry.target.classList.add('reveal--visible');
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ threshold: 0.1 }
|
||||||
|
);
|
||||||
|
revealElements.forEach(function (el) {
|
||||||
|
observer.observe(el);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fallback: показываем всё сразу
|
||||||
|
revealElements.forEach(function (el) {
|
||||||
|
el.classList.add('reveal--visible');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 2. КНОПКИ "ЧИТАТЬ ЕЩЁ"
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
document.querySelectorAll('.review-card__btn-more').forEach(function (btn) {
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
const textBlock = this.parentNode.querySelector('.lw-card__text');
|
||||||
|
if (textBlock) {
|
||||||
|
textBlock.classList.toggle('review-card__text--expanded');
|
||||||
|
this.textContent = textBlock.classList.contains('review-card__text--expanded')
|
||||||
|
? 'Свернуть'
|
||||||
|
: 'Читать ещё';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 3. КНОПКА "ПОКАЗАТЬ ЕЩЁ" (десктоп)
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
const loadMoreBtn = document.getElementById('reviews-loadmore');
|
||||||
|
if (loadMoreBtn) {
|
||||||
|
let nextBatch = 2;
|
||||||
|
const btn = loadMoreBtn.querySelector('.reviews-loadmore__btn');
|
||||||
|
if (btn) {
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
const cards = document.querySelectorAll('.lw-card[data-batch="' + nextBatch + '"]');
|
||||||
|
if (cards.length) {
|
||||||
|
cards.forEach(function (card) {
|
||||||
|
card.style.display = 'flex';
|
||||||
|
});
|
||||||
|
nextBatch++;
|
||||||
|
// Если следующих батчей нет — прячем кнопку
|
||||||
|
const remaining = document.querySelectorAll('.lw-card[data-batch="' + nextBatch + '"]');
|
||||||
|
if (!remaining.length) {
|
||||||
|
loadMoreBtn.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 4. FAQ Accordion — keyboard + ARIA
|
||||||
|
// Глобальный click handler в add.js обрабатывает
|
||||||
|
// .box__accordion_label, синхронизируем aria-expanded
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
document.querySelectorAll('.box__accordion_label').forEach(function (label) {
|
||||||
|
label.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') {
|
||||||
|
e.preventDefault();
|
||||||
|
this.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// При клике (из add.js) синхронизируем aria-expanded
|
||||||
|
label.addEventListener('click', function () {
|
||||||
|
const content = document.getElementById(this.getAttribute('aria-controls'));
|
||||||
|
const isOpen = content && content.style.maxHeight && content.style.maxHeight !== '0px';
|
||||||
|
this.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 5. СЧЁТЧИК (CountUp) для цифр доверия
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
function animateCounter(el) {
|
||||||
|
const target = parseInt(el.getAttribute('data-target-value'), 10) ||
|
||||||
|
parseInt(el.getAttribute('data-target'), 10);
|
||||||
|
if (!target) return;
|
||||||
|
let current = 0;
|
||||||
|
const step = Math.ceil(target / 60); // 60 кадров ~ 1 сек
|
||||||
|
const timer = setInterval(function () {
|
||||||
|
current += step;
|
||||||
|
if (current >= target) {
|
||||||
|
current = target;
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
el.textContent = current.toLocaleString('ru-RU');
|
||||||
|
}, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll('.counter-number').forEach(function (counter) {
|
||||||
|
if ('IntersectionObserver' in window) {
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
function (entries) {
|
||||||
|
entries.forEach(function (entry) {
|
||||||
|
if (entry.isIntersecting) {
|
||||||
|
animateCounter(entry.target);
|
||||||
|
observer.unobserve(entry.target);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{ threshold: 0.5 }
|
||||||
|
);
|
||||||
|
observer.observe(counter);
|
||||||
|
} else {
|
||||||
|
animateCounter(counter);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 6. STICKY CTA (мобильные) — троттлинг скролла
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
const stickyCta = document.querySelector('.sticky-cta-mobile');
|
||||||
|
if (stickyCta) {
|
||||||
|
const heroSection = document.querySelector('.reviews-hero');
|
||||||
|
if (heroSection) {
|
||||||
|
const heroBottom = heroSection.offsetTop + heroSection.offsetHeight;
|
||||||
|
let ticking = false;
|
||||||
|
window.addEventListener('scroll', function () {
|
||||||
|
if (!ticking) {
|
||||||
|
window.requestAnimationFrame(function () {
|
||||||
|
if (window.scrollY > heroBottom) {
|
||||||
|
stickyCta.classList.add('sticky-cta-mobile--visible');
|
||||||
|
} else {
|
||||||
|
stickyCta.classList.remove('sticky-cta-mobile--visible');
|
||||||
|
}
|
||||||
|
ticking = false;
|
||||||
|
});
|
||||||
|
ticking = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 7. POPUP ФОРМЫ ОТЗЫВА (iframe)
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
const formBtn = document.querySelector('.review-form-block__btn');
|
||||||
|
if (formBtn) {
|
||||||
|
formBtn.addEventListener('click', function () {
|
||||||
|
const popup = document.querySelector('.frame__popup');
|
||||||
|
const iframe = popup ? popup.querySelector('.frame_reviews') : null;
|
||||||
|
const frameUrl = popup ? popup.getAttribute('data-frame-url') : '';
|
||||||
|
if (popup && iframe && frameUrl) {
|
||||||
|
iframe.src = frameUrl;
|
||||||
|
popup.style.display = 'flex';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeBtn = document.querySelector('.btn-close-frame__popup');
|
||||||
|
if (closeBtn) {
|
||||||
|
closeBtn.addEventListener('click', function () {
|
||||||
|
const popup = this.parentNode.parentNode;
|
||||||
|
popup.style.display = 'none';
|
||||||
|
const iframe = popup.querySelector('.frame_reviews');
|
||||||
|
if (iframe) iframe.src = '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
// 8. ЦЕЛИ ЯНДЕКС.МЕТРИКИ
|
||||||
|
// ───────────────────────────────────────────────
|
||||||
|
function reachGoal(name) {
|
||||||
|
if (typeof yaCounter99835482 !== 'undefined') {
|
||||||
|
try {
|
||||||
|
yaCounter99835482.reachGoal(name);
|
||||||
|
} catch (e) {
|
||||||
|
if (window.console) {
|
||||||
|
console.warn('Metrika reachGoal error:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Клики по всем CTA-кнопкам
|
||||||
|
document.querySelectorAll('.js-reviews-cta').forEach(function (btn) {
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
const goal = this.getAttribute('data-goal') || 'cta_otzyvy_click';
|
||||||
|
reachGoal(goal);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Клик по телефону
|
||||||
|
document.querySelectorAll('a[href^="tel:"]').forEach(function (link) {
|
||||||
|
link.addEventListener('click', function () {
|
||||||
|
reachGoal('phone_click_otzyvy');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Клик по WhatsApp/Telegram
|
||||||
|
document.querySelectorAll('a[href*="wa.me"], a[href*="t.me"]').forEach(function (link) {
|
||||||
|
link.addEventListener('click', function () {
|
||||||
|
reachGoal('messenger_click_otzyvy');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -240,35 +240,62 @@ function add_carbon() {
|
|||||||
->add_fields( array(
|
->add_fields( array(
|
||||||
Field::make( 'image', 'img', 'Фотография:' ),
|
Field::make( 'image', 'img', 'Фотография:' ),
|
||||||
)),
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('SEO и микроразметка', array(
|
||||||
|
Field::make( 'html', 'schema_branch_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Поля для <strong>JSON-LD микроразметки</strong> Schema.org филиала. Если поле пусто — свойство не добавляется в граф.</p>' ),
|
||||||
|
Field::make( 'text', 'schema_legal_name', 'Юридическое название (legalName)' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Полное юр. название организации. Например: "ИП Иванов Иван Иванович"' ),
|
||||||
|
Field::make( 'text', 'schema_postal_code', 'Почтовый индекс (postalCode)' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Индекс для address.postalCode в микроразметке.' ),
|
||||||
|
Field::make( 'text', 'schema_founded', 'Год основания (foundingDate)' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Год или полная дата: "2015" или "2015-09-01".' ),
|
||||||
|
Field::make( 'text', 'schema_map_url', 'Ссылка на карту (hasMap)' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Полная ссылка на Яндекс.Карты или Google Maps.' ),
|
||||||
|
Field::make( 'complex', 'schema_hours', 'Часы работы (openingHoursSpecification)' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Режим работы на каждый день недели.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'select', 'day_of_week', 'День недели' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_options( array(
|
||||||
|
'Monday' => 'Понедельник',
|
||||||
|
'Tuesday' => 'Вторник',
|
||||||
|
'Wednesday' => 'Среда',
|
||||||
|
'Thursday' => 'Четверг',
|
||||||
|
'Friday' => 'Пятница',
|
||||||
|
'Saturday' => 'Суббота',
|
||||||
|
'Sunday' => 'Воскресенье',
|
||||||
|
) ),
|
||||||
|
Field::make( 'time', 'opens', 'Открытие' )
|
||||||
|
->set_width( 25 ),
|
||||||
|
Field::make( 'time', 'closes', 'Закрытие' )
|
||||||
|
->set_width( 25 ),
|
||||||
|
Field::make( 'checkbox', 'day_off', 'Выходной' )
|
||||||
|
->set_width( 20 )
|
||||||
|
->set_help_text( 'Отметьте, если в этот день не работаем.' ),
|
||||||
|
) ),
|
||||||
|
Field::make( 'complex', 'schema_social', 'Социальные сети (sameAs)' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Ссылки на соцсети профилей для sameAs[].' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'platform', 'Платформа' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Например: VK, Telegram, YouTube' ),
|
||||||
|
Field::make( 'text', 'url', 'Ссылка' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Полный URL профиля.' ),
|
||||||
|
) ),
|
||||||
|
Field::make( 'media_gallery', 'schema_photos', 'Фотографии филиала (image[])' )
|
||||||
|
->set_help_text( 'Выберите фотографии интерьера/экстерьера для image[].' ),
|
||||||
));
|
));
|
||||||
|
|
||||||
// ====================================================
|
// (пусто — старые поля banner_img_desktop, banner_img_mobile,
|
||||||
// Доп поля для всех страниц
|
// banner_h1, banner_text, page_breadcrumbs удалены 31 мая 2026)
|
||||||
// ====================================================
|
|
||||||
Container::make('post_meta', 'Дополнительные поля')
|
|
||||||
->where('post_type', '=', 'page')
|
|
||||||
->where('post_id', '!=', 64)
|
|
||||||
->add_fields(array(
|
|
||||||
Field::make( 'image', 'banner_img_desktop', 'Изображение для баннера (десктопная версия)' )
|
|
||||||
->help_text( 'Размер изображения (желательно) 1295px на 454px' )
|
|
||||||
->set_width( 15 ),
|
|
||||||
Field::make( 'image', 'banner_img_mobile', 'Изображение для баннера (мобильная версия)' )
|
|
||||||
->help_text( 'Размер изображения (желательно) 450px на 225px' )
|
|
||||||
->set_width( 15 ),
|
|
||||||
Field::make( 'text', 'banner_h1', 'текст для H1' )
|
|
||||||
->set_width( 100 ),
|
|
||||||
Field::make( 'text', 'banner_text', 'Дополнительный текст под H1' )
|
|
||||||
->set_width( 100 ),
|
|
||||||
Field::make( 'complex', 'page_breadcrumbs', 'Хлебные крошки' )
|
|
||||||
->set_layout( 'tabbed-horizontal' )
|
|
||||||
->add_fields( array(
|
|
||||||
Field::make( 'text', 'breadcrumbs_name', 'Название крошки:' )
|
|
||||||
->set_width( 50 ),
|
|
||||||
Field::make( 'text', 'breadcrumbs_link', 'Ссылка крошки:' )
|
|
||||||
->set_width( 50 )
|
|
||||||
->set_default_value('#'),
|
|
||||||
)),
|
|
||||||
));
|
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// Доп поля для категории Курсов
|
// Доп поля для категории Курсов
|
||||||
@ -473,6 +500,212 @@ function add_carbon() {
|
|||||||
)),
|
)),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// ====================================================
|
||||||
|
// Доп поля для страницы "Подготовка к школе (Bento 2026)"
|
||||||
|
// ====================================================
|
||||||
|
Container::make('post_meta', 'Настройки Подготовки к школе')
|
||||||
|
->where('post_template', '=', 'page-podgotovka-k-shkole.php')
|
||||||
|
->add_tab('🖼️ Герой (баннер)', array(
|
||||||
|
Field::make( 'html', 'pksh_hero_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.hero-pksh</strong>. Первый экран страницы подготовки к школе.</p>' ),
|
||||||
|
Field::make( 'image', 'banner_image', 'Фото баннера' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Рекомендуемый размер: 689×689 px, квадратное. Если не указано — используется фото по умолчанию.' ),
|
||||||
|
Field::make( 'text', 'banner_h1', 'Заголовок H1' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_default_value( 'Ваш ребёнок готов к первому классу? Научим читать, считать и писать за 4 месяца — без слёз и стресса' )
|
||||||
|
->set_help_text( 'Главный заголовок на первом экране.' ),
|
||||||
|
Field::make( 'textarea', 'banner_subtitle', 'Подзаголовок' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_default_value( 'Первое занятие — бесплатно. Результат через 3 недели — или вернём деньги' )
|
||||||
|
->set_help_text( 'Текст под заголовком. Опционально.' ),
|
||||||
|
Field::make( 'text', 'banner_scarcity', 'Текст дефицита (срочность)' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_default_value( '🔥 Осталось <strong>2 места из 8</strong> в группе 5–6 лет. Стартуем <strong>1 июня</strong>' )
|
||||||
|
->set_help_text( 'Можно использовать HTML-теги: <strong>, <br>. Текст о срочности/дефиците мест под кнопкой.' ),
|
||||||
|
))
|
||||||
|
->add_tab('📊 Соц.доказательство', array(
|
||||||
|
Field::make( 'html', 'pksh_social_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.social-counters</strong>. Блок цифр социального доказательства (4 карточки). Иконки заданы в шаблоне, здесь только текст.</p>' ),
|
||||||
|
Field::make( 'complex', 'pksh_social_counters', 'Показатели' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Добавьте до 4 показателей. Порядок = порядок вывода. Иконки не редактируются.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'counter_number', 'Число' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Например: 500+, 12, 4.8, 20+' ),
|
||||||
|
Field::make( 'text', 'counter_label', 'Подпись' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Например: выпускников в топ-школах' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('Битрикс24', array(
|
||||||
|
Field::make( 'textarea', 'pksh_bitrix_script', 'Скрипт формы Битрикс24' )
|
||||||
|
->set_help_text( 'Вставьте полный JS-код интеграции с CRM-формой Битрикс24. Выводится в блоке Final CTA на странице подготовки к школе.' ),
|
||||||
|
))
|
||||||
|
->add_tab('⭐ Отзывы', array(
|
||||||
|
Field::make( 'html', 'pksh_reviews_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.pksh-reviews</strong>. Отзывы родителей на странице подготовки к школе.</p>' ),
|
||||||
|
Field::make( 'complex', 'pksh_reviews_list', 'Отзывы' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Добавьте отзывы родителей. Показываются на странице подготовки к школе.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'image', 'review_avatar', 'Аватар' )
|
||||||
|
->set_width( 15 )
|
||||||
|
->set_help_text( 'Опционально. Если не указано — генерируется из имени.' ),
|
||||||
|
Field::make( 'text', 'review_author', 'Имя автора' )
|
||||||
|
->set_width( 25 ),
|
||||||
|
Field::make( 'text', 'review_rating', 'Оценка (1–5)' )
|
||||||
|
->set_width( 10 )
|
||||||
|
->set_attribute( 'type', 'number' ),
|
||||||
|
Field::make( 'date', 'review_date', 'Дата отзыва' )
|
||||||
|
->set_width( 15 )
|
||||||
|
->set_help_text( 'Для Schema.org Review.datePublished.' ),
|
||||||
|
Field::make( 'textarea', 'review_text', 'Текст отзыва' )
|
||||||
|
->set_width( 35 ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('❓ FAQ', array(
|
||||||
|
Field::make( 'html', 'pksh_faq_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>#pksh-faq</strong>. Вопросы и ответы в стиле лагеря, две колонки.</p>' ),
|
||||||
|
Field::make( 'complex', 'pksh_faq_items', 'Вопросы и ответы' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Добавьте вопросы и ответы. Показываются в секции FAQ на странице подготовки к школе.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'textarea', 'faq_question', 'Вопрос' )
|
||||||
|
->set_width( 30 ),
|
||||||
|
Field::make( 'textarea', 'faq_answer', 'Ответ' )
|
||||||
|
->set_width( 70 ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('👨🏫 Преподаватели', array(
|
||||||
|
Field::make( 'html', 'pksh_teachers_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>#teachers</strong>. Карточки преподавателей в стиле лагеря.</p>' ),
|
||||||
|
Field::make( 'complex', 'pksh_teachers', 'Преподаватели' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Добавьте преподавателей. Выводятся на странице подготовки к школе в секции Преподаватели.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'teacher_name', 'ФИО' )
|
||||||
|
->set_width( 40 ),
|
||||||
|
Field::make( 'image', 'teacher_photo', 'Фото' )
|
||||||
|
->set_help_text( 'Оптимально: 240×240 px, квадратное.' )
|
||||||
|
->set_width( 30 ),
|
||||||
|
Field::make( 'text', 'teacher_subject', 'Предмет / должность' )
|
||||||
|
->set_width( 30 ),
|
||||||
|
Field::make( 'textarea', 'teacher_about', 'О педагоге' )
|
||||||
|
->set_width( 100 ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
// ====================================================
|
||||||
|
// Вкладка: Программы подготовки к школе
|
||||||
|
// ====================================================
|
||||||
|
->add_tab('📚 Программы', array(
|
||||||
|
Field::make( 'html', 'pksh_programs_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>#programs</strong>. Карточки программ подготовки к школе. Каждая карточка — отдельная запись.</p>' ),
|
||||||
|
Field::make( 'complex', 'pksh_programs', 'Программы подготовки' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Добавьте программы подготовки к школе. Каждая — отдельная карточка.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'program_icon', 'Иконка (emoji)' )
|
||||||
|
->set_width( 20 )
|
||||||
|
->set_default_value( '🎓' ),
|
||||||
|
Field::make( 'text', 'program_title', 'Название программы' )
|
||||||
|
->set_width( 80 ),
|
||||||
|
Field::make( 'text', 'program_intensity', 'Интенсивность' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Например: 2 раза в неделю' ),
|
||||||
|
Field::make( 'textarea', 'program_schedule', 'Расписание' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Каждая строка — один вариант расписания' ),
|
||||||
|
Field::make( 'text', 'program_duration', 'Длительность занятия' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_default_value( '90 мин' ),
|
||||||
|
Field::make( 'textarea', 'program_lesson_structure', 'Структура занятия (timeline)' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Каждая строка: время 🔤 Название. Например: "15 мин 🧠 Нейрогимнастика"' ),
|
||||||
|
Field::make( 'textarea', 'program_includes', 'Программа включает' )
|
||||||
|
->set_width( 100 )
|
||||||
|
->set_help_text( 'Каждая строка — пункт списка' ),
|
||||||
|
Field::make( 'text', 'program_price_subscription', 'Цена абонемента' )
|
||||||
|
->set_width( 40 )
|
||||||
|
->set_default_value( '7 500 ₽' )
|
||||||
|
->set_help_text( 'Например: 7 500 ₽' ),
|
||||||
|
Field::make( 'text', 'program_price_single', 'Цена разового занятия' )
|
||||||
|
->set_width( 40 )
|
||||||
|
->set_default_value( '1 000 ₽' )
|
||||||
|
->set_help_text( 'Например: 1 000 ₽' ),
|
||||||
|
Field::make( 'text', 'program_time_required', 'Длительность курса (timeRequired)' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Общая длительность курса. Например: "4 месяца", "P4M"' ),
|
||||||
|
Field::make( 'text', 'program_repeat_frequency', 'Частота занятий (ISO 8601)' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text(
|
||||||
|
'Для Schema.org Schedule.repeatFrequency. '
|
||||||
|
. 'Пример: P1W (раз в неделю), P4D (дважды в неделю). '
|
||||||
|
. 'program_intensity остаётся для отображения на сайте.'
|
||||||
|
)
|
||||||
|
->set_attribute( 'placeholder', 'P1W' ),
|
||||||
|
Field::make( 'text', 'program_workload', 'Нагрузка (courseWorkload)' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Например: "2 занятия в неделю по 90 минут"' ),
|
||||||
|
Field::make( 'date', 'program_start_date', 'Дата старта программы' )
|
||||||
|
->set_width( 33 ),
|
||||||
|
Field::make( 'date', 'program_end_date', 'Дата окончания' )
|
||||||
|
->set_width( 33 ),
|
||||||
|
Field::make( 'date', 'program_price_valid', 'Цена действительна до' )
|
||||||
|
->set_width( 34 )
|
||||||
|
->set_help_text( 'Дата, до которой актуальна указанная цена.' ),
|
||||||
|
Field::make( 'text', 'program_button_text', 'Текст кнопки' )
|
||||||
|
->set_width( 40 )
|
||||||
|
->set_default_value( 'Записаться' ),
|
||||||
|
Field::make( 'text', 'program_button_url', 'Ссылка кнопки' )
|
||||||
|
->set_width( 60 )
|
||||||
|
->set_default_value( '/zapis/' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
// ====================================================
|
||||||
|
// Вкладка: JSON-LD Schema (данные для микроразметки)
|
||||||
|
// ====================================================
|
||||||
|
->add_tab('🧠 JSON-LD (схема)', array(
|
||||||
|
Field::make( 'html', 'pksh_schema_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Поля для <strong>JSON-LD микроразметки</strong> Schema.org. Заполняются опционально — если поле пусто, свойство не добавляется в граф.</p>' ),
|
||||||
|
Field::make( 'textarea', 'pksh_description', 'Описание курса (для микроразметки)' )
|
||||||
|
->set_help_text(
|
||||||
|
'Подробное описание программы для Schema.org Course.description. '
|
||||||
|
. 'Если заполнено — заменяет banner_subtitle в микроразметке. '
|
||||||
|
. 'Рекомендуется минимум 150 символов. НЕ влияет на отображение страницы.'
|
||||||
|
)
|
||||||
|
->set_rows( 4 )
|
||||||
|
->set_attribute( 'placeholder', 'Комплексная программа подготовки детей 5–7 лет к первому классу...' ),
|
||||||
|
Field::make( 'text', 'pksh_level', 'Уровень образования (educationalLevel)' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Например: "дошкольное образование" или "5-7 лет"' ),
|
||||||
|
Field::make( 'text', 'pksh_age', 'Возраст детей' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Например: "5–7 лет"' ),
|
||||||
|
Field::make( 'text', 'pksh_audience', 'Целевая аудитория (audience)' )
|
||||||
|
->set_help_text( 'Например: "Дети 5–7 лет, будущие первоклассники"' ),
|
||||||
|
Field::make( 'select', 'pksh_course_mode', 'Формат обучения (courseMode)' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Формат занятий для Schema.org CourseInstance.courseMode.' )
|
||||||
|
->add_options( array(
|
||||||
|
'' => '— выберите —',
|
||||||
|
'Onsite' => 'Очно (в центре)',
|
||||||
|
'Online' => 'Онлайн',
|
||||||
|
'Blended' => 'Смешанный (очно + онлайн)',
|
||||||
|
) ),
|
||||||
|
|
||||||
|
Field::make( 'complex', 'pksh_skills', 'Чему учат на курсе' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Навыки, которые освоит ребёнок. Каждая запись — отдельный навык (дисциплина).' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'skill', 'Навык / дисциплина' )
|
||||||
|
->set_width( 100 )
|
||||||
|
->set_attribute( 'placeholder', 'Чтение, Счёт до 100, Письмо печатными буквами' )
|
||||||
|
->set_help_text( 'Например: "Чтение", "Счёт до 100", "Письмо печатными буквами"' ),
|
||||||
|
)),
|
||||||
|
));
|
||||||
|
|
||||||
// ====================================================
|
// ====================================================
|
||||||
// Уникальное имя контейнера Продлёнки
|
// Уникальное имя контейнера Продлёнки
|
||||||
// ====================================================
|
// ====================================================
|
||||||
@ -742,6 +975,245 @@ function add_carbon() {
|
|||||||
->set_help_text( 'Вставьте полный JS-код интеграции с CRM-формой Битрикс24. Выводится в модальном окне заявки.' ),
|
->set_help_text( 'Вставьте полный JS-код интеграции с CRM-формой Битрикс24. Выводится в модальном окне заявки.' ),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// ════════════════════════════════════════════════════════════
|
||||||
|
// СТРАНИЦА ОТЗЫВОВ (page-reviews.php)
|
||||||
|
// ════════════════════════════════════════════════════════════
|
||||||
|
Container::make('post_meta', '⭐ Настройки страницы Отзывы')
|
||||||
|
->where('post_template', '=', 'page-reviews.php')
|
||||||
|
->add_tab('🧑🏫 Hero (первый экран)', array(
|
||||||
|
Field::make( 'html', 'reviews_hero_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">H1 и подзаголовок — статические в шаблоне. Здесь только метрики и CTA.</p>' ),
|
||||||
|
Field::make( 'separator', 'reviews_metric_sep', 'Метрики доверия' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_1_number', 'Метрика 1 — число' )
|
||||||
|
->set_default_value( '500+' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Крупная цифра, которая сразу привлекает внимание. Выбирайте самую сильную — ту, что впечатляет больше всего: количество учеников, лет на рынке, % поступления. Добавьте + или % для эффекта. Примеры: «500+», «98%», «15».' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_1_label', 'Метрика 1 — подпись' )
|
||||||
|
->set_default_value( 'счастливых семей' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Подпись к цифре из левого поля. Объясняет, что именно посчитано. Совет: используйте родительный падеж — звучит весомее. Примеры: «счастливых семей», «выпускников», «учеников». Не пишите просто «семей» — добавьте «счастливых», это продаёт эмоцию.' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_2_number', 'Метрика 2 — число' )
|
||||||
|
->set_default_value( '12+' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Вторая по силе цифра. Не ставьте 0, 1, 2 — они не впечатляют. Примеры: «12+», «97%», «50».' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_2_label', 'Метрика 2 — подпись' )
|
||||||
|
->set_default_value( 'лет в образовании' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Подпись к цифре 2. Примеры: «лет на рынке», «лет в образовании», «преподавателей». Старайтесь, чтобы подпись читалась вместе с цифрой как законченная фраза: «12+ лет в образовании».' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_3_number', 'Метрика 3 — число' )
|
||||||
|
->set_default_value( '4.9' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Третья цифра. Если сильных цифр больше нет — поставьте рейтинг или оценку. Примеры: «4.9», «5.0», «топ-3». Дробные числа пишите через точку.' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_3_label', 'Метрика 3 — подпись' )
|
||||||
|
->set_default_value( 'рейтинг на Яндексе' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Подпись к цифре 3. Примеры: «рейтинг на Яндексе», «звёзд», «место в рейтинге области». Если указали рейтинг — обязательно добавьте «из 5» или площадку: «рейтинг на Яндексе» звучит убедительнее, чем просто «рейтинг».' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_4_number', 'Метрика 4 — число' )
|
||||||
|
->set_default_value( '14' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Четвёртая цифра. Например: количество отзывов, количество педагогов, лет опыта.' ),
|
||||||
|
Field::make( 'text', 'reviews_hero_metric_4_label', 'Метрика 4 — подпись' )
|
||||||
|
->set_default_value( 'отзывов о школе' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Подпись к цифре 4. Пример: «отзывов о школе», «педагогов», «лет на рынке».' ),
|
||||||
|
// CTA кнопка — статическая в шаблоне, открывает модалку Bitrix24
|
||||||
|
))
|
||||||
|
->add_tab('📝 Вступление (SEO-текст)', array(
|
||||||
|
Field::make( 'html', 'reviews_intro_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.reviews-intro</strong> — SEO-текст в начале страницы. Управляется из админки, чтобы можно было править текст без редактирования шаблона.</p>' ),
|
||||||
|
Field::make( 'text', 'reviews_intro_price_text', 'Стоимость обучения (текст)' )
|
||||||
|
->set_default_value( 'от 40 000 ₽ в месяц' )
|
||||||
|
->set_width( 100 )
|
||||||
|
->set_help_text( 'Текст стоимости в блоке .reviews-intro__info. Пример: «от 40 000 ₽ в месяц» или «от 35 000 ₽/мес». Если поле пусто — строка не выводится.' ),
|
||||||
|
Field::make( 'textarea', 'reviews_intro_lead', 'Лид-абзац (первый, крупный)' )
|
||||||
|
->set_default_value( 'Частная школа Декарт в Щёлково — это образовательное пространство, где каждый ребёнок получает внимание, заботу и качественные знания. Мы работаем в Щёлковском городском округе с 2010 года и за это время помогли раскрыть потенциал сотням учеников. Отзывы родителей о школе Декарт — это реальные истории семей, которые доверили нам образование своих детей. Мы публикуем их, чтобы вы могли принять взвешенное решение.' )
|
||||||
|
->set_help_text( 'Первый, самый заметный абзац. Отображается крупнее остальных, отделён линией. 150–180 символов — оптимально. Должен вовлекать и отвечать на главный вопрос посетителя.' ),
|
||||||
|
Field::make( 'textarea', 'reviews_intro_card_1', 'Блок «О школе» (карточка 1)' )
|
||||||
|
->set_default_value( 'В нашей частной школе в Щёлково учатся дети с 1 по 11 класс. Мы предлагаем программы начального общего образования, подготовки к ОГЭ и ЕГЭ, углублённое изучение английского языка. Классы небольшие — до 12 человек, поэтому каждый ученик получает индивидуальный подход. Родители, которые ищут качественное образование в Щёлково и Московской области, выбирают Декарт за профессионализм педагогов и тёплую атмосферу.' )
|
||||||
|
->set_help_text( 'Левая карточка в сетке из двух колонок. Здесь — факты о школе: классы, программы, преимущества. 100–200 символов.' ),
|
||||||
|
Field::make( 'textarea', 'reviews_intro_card_2', 'Блок «О странице» (карточка 2)' )
|
||||||
|
->set_default_value( 'Мы ценим каждое мнение и постоянно работаем над улучшением обучения. Ниже вы найдёте реальные отзывы родителей о нашей частной школе, достижения учеников и ответы на частые вопросы. Приятного чтения!' )
|
||||||
|
->set_help_text( 'Правая карточка в сетке. Объясняет, что пользователь найдёт на странице. 80–120 символов.' ),
|
||||||
|
))
|
||||||
|
->add_tab('🏠 Почему выбирают (локальный)', array(
|
||||||
|
Field::make( 'html', 'reviews_local_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.reviews-local</strong> — список причин выбрать школу с привязкой к городу. Заголовок секции статический в шаблоне, подставляет город из настроек филиала.</p>' ),
|
||||||
|
Field::make( 'complex', 'reviews_local_items', 'Причины' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( '4–6 причин, почему родители выбирают именно Декарт. Каждая — жирный заголовок + описание. Текст должен быть с гео-привязкой (упоминания города, района, местных реалий).' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'title', 'Заголовок' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Короткий, ёмкий заголовок. 2–5 слов. ✅ «Удобное расположение» ❌ «Мы находимся в удобном месте с хорошей транспортной доступностью».' ),
|
||||||
|
Field::make( 'textarea', 'text', 'Описание' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( '2–3 предложения с гео-привязкой. Упомяните город, район, местные реалии. Родитель должен почувствовать: «Это про мой город, это для меня».' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('📊 Наши результаты (цифрами)', array(
|
||||||
|
Field::make( 'html', 'reviews_results_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.results</strong></p>' ),
|
||||||
|
Field::make( 'text', 'reviews_results_title', 'Заголовок секции' )
|
||||||
|
->set_default_value( 'Декарт в цифрах' )
|
||||||
|
->set_width( 100 )
|
||||||
|
->set_help_text( 'Заголовок блока с результатами. Должен привлекать внимание и обещать пользу. Примеры: «Декарт в цифрах», «Наши достижения», «Почему нам доверяют родители». Избегайте канцеляризмов: «Статистические показатели» — плохо.' ),
|
||||||
|
Field::make( 'complex', 'reviews_results', 'Показатели' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( '4-6 цифр, которые доказывают качество школы. Каждый показатель должен отвечать на вопрос родителя: «Почему мы должны вам доверять?». Примеры: % поступивших в вузы, средний балл учеников, стаж преподавателей, количество учеников. Избегайте абстрактных цифр вроде «более 50 довольных клиентов» — звучит неубедительно.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'number', 'Число' )
|
||||||
|
->set_width( 25 )
|
||||||
|
->set_help_text( 'Сама цифра — должна выглядеть эффектно и убедительно. ✅ «100%», «85%», «500+», «50». ❌ «много», «больше 10», «каждый второй» — размытые формулировки не работают. Используйте % и + чтобы цифра казалась больше.' ),
|
||||||
|
Field::make( 'select', 'icon', 'Иконка' )
|
||||||
|
->set_width( 20 )
|
||||||
|
->set_help_text( 'Иконка рядом с цифрой. Подбирайте по смыслу: 🏆 достижения, 📖 учёба, 👥 ученики, ❤️ любовь/забота. Иконка помогает быстро понять суть.' )
|
||||||
|
->add_options( array(
|
||||||
|
'ph-graduation-cap' => '🎓 Диплом / шапочка',
|
||||||
|
'ph-chats' => '💬 Речевой пузырь',
|
||||||
|
'ph-users-three' => '👥 Люди / группа',
|
||||||
|
'ph-star' => '⭐ Звезда',
|
||||||
|
'ph-shield-check' => '🛡️ Галочка / щит',
|
||||||
|
'ph-book' => '📖 Книга',
|
||||||
|
'ph-heart' => '❤️ Сердце',
|
||||||
|
'ph-clock' => '🕐 Часы',
|
||||||
|
'ph-house' => '🏠 Дом',
|
||||||
|
'ph-trophy' => '🏆 Кубок',
|
||||||
|
)),
|
||||||
|
Field::make( 'text', 'label', 'Подпись' )
|
||||||
|
->set_width( 55 )
|
||||||
|
->set_help_text( 'Пояснение к цифре. Текст должен быть понятен САМ ПО СЕБЕ, даже без цифры. ✅ «учеников сдают ВПР на 4 и 5», ❌ «сдают ВПР» (что? кто?). Длина — 3-5 слов. Примеры: «лет на рынке», «выпускников поступают в топ-вузы», «средний балл учеников по математике».' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('❓ FAQ (вопросы-ответы)', array(
|
||||||
|
Field::make( 'html', 'reviews_faq_tab_desc', '' )
|
||||||
|
->set_html( '<div style="background:#f0f6fc;border-left:4px solid #72aee6;padding:16px 20px;margin:0 0 16px;border-radius:4px;font-size:13px;line-height:1.6;max-width:680px">
|
||||||
|
<p style="margin:0 0 8px;font-weight:700;font-size:14px">🎯 Какие вопросы добавлять на эту страницу</p>
|
||||||
|
<p style="margin:0 0 12px">Эта страница — последний шаг перед записью. Человек уже почти решился, он читает отзывы чтобы окончательно убедиться. Вопросы и ответы здесь должны <strong>снимать последние сомнения</strong>, а не рассказывать о центре в целом.</p>
|
||||||
|
<p style="margin:0 0 6px;font-weight:600;color:#2c3338">✅ Правильные вопросы — про доверие и финальные сомнения:</p>
|
||||||
|
<ul style="margin:0 0 12px;padding-left:20px">
|
||||||
|
<li>— Что если после первого занятия не понравится?</li>
|
||||||
|
<li>— Можно ли сначала прийти на пробный урок?</li>
|
||||||
|
<li>— Мой ребёнок сильно отстаёт от программы — вам это не помешает?</li>
|
||||||
|
<li>— Как быстро будет виден результат?</li>
|
||||||
|
<li>— Что если мы пропустим занятие?</li>
|
||||||
|
</ul>
|
||||||
|
<p style="margin:0 0 6px;font-weight:600;color:#b32d2e">❌ Неправильные вопросы — их размещайте на других страницах:</p>
|
||||||
|
<ul style="margin:0 0 12px;padding-left:20px">
|
||||||
|
<li>— Какие предметы вы преподаёте? → <em>на главную или страницу курсов</em></li>
|
||||||
|
<li>— Сколько стоит обучение? → <em>на страницу цен</em></li>
|
||||||
|
<li>— Где вы находитесь? → <em>на страницу контактов</em></li>
|
||||||
|
<li>— Чем вы отличаетесь от других центров? → <em>на страницу «О нас»</em></li>
|
||||||
|
</ul>
|
||||||
|
<p style="margin:0 0 4px;font-weight:600">📐 Сколько вопросов добавлять:</p>
|
||||||
|
<p style="margin:0">Оптимально <strong>4–6</strong>. Меньше — не закрывает сомнения, больше — отвлекает от записи.</p>
|
||||||
|
</div>' ),
|
||||||
|
// Заголовок секции — статический в шаблоне
|
||||||
|
Field::make( 'complex', 'reviews_faq', 'Вопросы и ответы' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Вопросы — снимают последние сомнения перед записью. 4–6 штук.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'textarea', 'question', 'Вопрос' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Вопрос должен звучать так, как его задаст реальный родитель — простыми словами, без канцелярита. ✅ «А если ребёнок не захочет ходить?» ❌ «Как преодолеть сопротивление ребёнка к посещению занятий?». Первое — вызывает доверие, второе — выглядит как копипаста с другого сайта.' ),
|
||||||
|
Field::make( 'textarea', 'answer', 'Ответ' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Ответ должен снимать страх или сомнение, а не просто сухо информировать. Используйте слова-усилители: «да», «конечно», «бесплатно», «попробуйте», «всегда можно». Структура: 1) Поймите чувства родителя («Это нормально, что вы переживаете…»). 2) Дайте решение («…поэтому у нас есть пробный урок»). 3) Позовите к действию («Приходите познакомиться — это бесплатно»).' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('⭐ Отзывы (карточки)', array(
|
||||||
|
Field::make( 'html', 'reviews_cards_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.reviews-grid</strong>. Карточки отзывов, которые видят посетители.</p>' ),
|
||||||
|
Field::make( 'complex', 'reviews_cards', 'Отзывы' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Карточки отзывов родителей — главный элемент доверия на странице. Лучше 3-4 подробных отзыва, чем 10 коротких «всё нравится». Хороший отзыв содержит: с чего начали → что изменилось → какой результат. Эмоциональные отзывы продают лучше фактов.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'review_author', 'Имя автора' )
|
||||||
|
->set_width( 22 )
|
||||||
|
->set_help_text( 'Реальное имя родителя: «Анна», «Сергей», «Екатерина М.». Имена повышают доверие. Можно добавить статус: «Анна, мама Артёма». НЕ используйте анонимные «Родитель» или «Гость» — это вызывает подозрение.' ),
|
||||||
|
Field::make( 'image', 'review_photo', 'Фото автора' )
|
||||||
|
->set_width( 13 )
|
||||||
|
->set_value_type( 'url' )
|
||||||
|
->set_help_text( 'Фото родителя (реальное лицо). Если не загружено — показывается аватар-заглушка с первой буквой имени. Фото повышает доверие к отзыву. Рекомендуемый размер: 96×96px, формат: WebP/JPG.' ),
|
||||||
|
Field::make( 'text', 'review_rating', 'Оценка (1–5)' )
|
||||||
|
->set_width( 10 )
|
||||||
|
->set_attribute( 'type', 'number' )
|
||||||
|
->set_help_text( 'Оценка от 1 до 5. Ставьте 5 — если отзыв восторженный. 4 — если есть мелкие замечания (это добавляет правдоподобности). Оценки 3 и ниже публиковать не стоит — они снижают доверие.' ),
|
||||||
|
Field::make( 'date', 'review_date', 'Дата отзыва' )
|
||||||
|
->set_storage_format( 'd.m.Y' )
|
||||||
|
->set_input_format( 'd.m.Y', 'd.m.Y' )
|
||||||
|
->set_picker_options( array(
|
||||||
|
'altInput' => false,
|
||||||
|
) )
|
||||||
|
->set_help_text( 'Дата отзыва. Свежие отзывы (2024-2025) работают лучше старых. Формат: ДД.ММ.ГГГГ (например: 10.03.2025). Можно открыть календарь — иконка справа.' )
|
||||||
|
->set_width( 20 ),
|
||||||
|
Field::make( 'association', 'review_teacher', 'Преподаватель' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_max( 1 )
|
||||||
|
->set_types( array(
|
||||||
|
array(
|
||||||
|
'type' => 'post',
|
||||||
|
'post_type' => 'teacher',
|
||||||
|
),
|
||||||
|
) )
|
||||||
|
->set_help_text( 'Если родитель хвалит конкретного учителя — привяжите отзыв к нему. Тогда на странице преподавателя тоже появится этот отзыв. Необязательно.' ),
|
||||||
|
Field::make( 'textarea', 'review_text', 'Текст отзыва' )
|
||||||
|
->set_width( 35 )
|
||||||
|
->set_help_text( 'Полный текст отзыва. 3-5 предложений — оптимально. Хорошая структура: 1) С чего начали («Пришли с проблемой…»), 2) Что изменилось («Через месяц ребёнок…»), 3) Результат («Сейчас читает лучше всех в классе»). Эмоции и конкретные детали убеждают сильнее общих фраз. Орфографию можно поправить, но сохраните живую речь.' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
// 📝 Форма отзыва — тексты статические в шаблоне page-reviews.php
|
||||||
|
// 🎯 Финальный CTA — статический в шаблоне page-reviews.php.
|
||||||
|
// Скрипт для кнопок — branch_button_script (Settings API → Настройки филиала).
|
||||||
|
->add_tab('🔗 Перелинковка', array(
|
||||||
|
Field::make( 'html', 'reviews_cross_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.cross-links</strong> — ссылки на другие разделы сайта. Улучшает навигацию и SEO.</p>' ),
|
||||||
|
Field::make( 'text', 'reviews_cross_title', 'Заголовок' )
|
||||||
|
->set_default_value( 'Наши программы' )
|
||||||
|
->set_width( 100 )
|
||||||
|
->set_help_text( 'Заголовок блока со ссылками. По умолчанию «Наши программы». Альтернативы: «Узнайте больше», «Другие направления», «Выберите программу». Важно: заголовок должен подталкивать перейти по ссылкам.' ),
|
||||||
|
Field::make( 'complex', 'reviews_cross_links', 'Ссылки на другие страницы' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( '5-7 ссылок на другие страницы сайта. Это помогает родителям найти нужную программу и улучшает SEO (перелинковка). Обязательно добавьте: подготовка к школе, начальная школа, средняя школа, ВПР, ОГЭ/ЕГЭ, продлёнка, летний лагерь.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'title', 'Название' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'Текст ссылки, который увидит посетитель. ✅ «Подготовка к школе», «Группа продлённого дня». Название должно быть понятно без контекста.' ),
|
||||||
|
Field::make( 'text', 'url', 'Ссылка' )
|
||||||
|
->set_width( 50 )
|
||||||
|
->set_help_text( 'URL страницы. Можно указать сокращённо: /podgotovka-k-shkole/ или полный адрес. Скопируйте из адресной строки браузера при просмотре нужной страницы.' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('💎 Видеоотзывы', array(
|
||||||
|
Field::make( 'html', 'reviews_video_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.video-reviews</strong>. Видеоотзывы — самый убедительный формат контента. Добавьте 2-4 коротких видео (1-3 минуты).</p>' ),
|
||||||
|
Field::make( 'text', 'reviews_video_title', 'Заголовок секции' )
|
||||||
|
->set_default_value( 'Видеоотзывы родителей' )
|
||||||
|
->set_width( 100 )
|
||||||
|
->set_help_text( 'Заголовок секции с видео. По умолчанию «Видеоотзывы родителей». Можно изменить на «Смотрите, что говорят родители», «Истории наших семей» — более эмоциональные варианты работают лучше.' ),
|
||||||
|
Field::make( 'complex', 'reviews_video', 'Видеоотзывы' )
|
||||||
|
->set_layout( 'tabbed-horizontal' )
|
||||||
|
->set_help_text( 'Добавьте видеоотзывы — это повышает доверие сильнее, чем текст. Видео должны быть на YouTube, в открытом доступе, длительностью 1-3 минуты. Хорошо, если родитель рассказывает историю: пришли с проблемой → как школа помогла → результат.' )
|
||||||
|
->add_fields( array(
|
||||||
|
Field::make( 'text', 'name', 'Имя автора' )
|
||||||
|
->set_width( 30 )
|
||||||
|
->set_help_text( 'Имя родителя из видео. Например: «Мария, мама Артёма». Если в видео несколько человек — укажите главного героя.' ),
|
||||||
|
Field::make( 'url', 'url', 'Ссылка на видео (YouTube)' )
|
||||||
|
->set_width( 70 )
|
||||||
|
->set_help_text( 'Ссылка на видео. Поддерживаются: YouTube (https://www.youtube.com/watch?v=...), VK Видео (https://vk.com/video-... или https://vkvideo.ru/...), Rutube и другие oEmbed-провайдеры. Видео должно быть в открытом доступе. Проверьте ссылку перед публикацией.' ),
|
||||||
|
)),
|
||||||
|
))
|
||||||
|
->add_tab('📸 Фото с занятий', array(
|
||||||
|
Field::make( 'html', 'reviews_photos_tab_desc', '' )
|
||||||
|
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.reviews-photos</strong> — фотогалерея с занятий. 4-8 фото повышают доверие и показывают атмосферу школы. Рекомендуемый размер: 800×600px, формат WebP.</p>' ),
|
||||||
|
Field::make( 'text', 'reviews_photos_title', 'Заголовок секции' )
|
||||||
|
->set_default_value( 'Фото с занятий' )
|
||||||
|
->set_width( 100 )
|
||||||
|
->set_help_text( 'Заголовок галереи. По умолчанию «Фото с занятий». Альтернативы: «Как проходят занятия», «Наши будни», «Атмосфера школы».' ),
|
||||||
|
Field::make( 'media_gallery', 'reviews_photos', 'Фотографии' )
|
||||||
|
->set_type( array( 'image' ) )
|
||||||
|
->set_help_text( 'Загрузите 4-8 фотографий. РЕКОМЕНДУЕМЫЙ РАЗМЕР: 800×600px (4:3), формат WebP. Все фото в галерее автоматически обрезаются до одинакового размера на странице (4:3), соотношение сторон сохраняется.' ),
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// функция получения id курса по его названию
|
// функция получения id курса по его названию
|
||||||
@ -810,6 +1282,24 @@ function replaceQuotes($text) {
|
|||||||
return $text;
|
return $text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Санитация для поля branch_button_script.
|
||||||
|
* Сохраняет <script> тэги (в отличие от wp_kses_post).
|
||||||
|
*/
|
||||||
|
function dekart_sanitize_script_field( $value ) {
|
||||||
|
$allowed = wp_kses_allowed_html( 'post' );
|
||||||
|
$allowed['script'] = array(
|
||||||
|
'src' => true,
|
||||||
|
'async' => true,
|
||||||
|
'defer' => true,
|
||||||
|
'data-b24-form' => true,
|
||||||
|
'data-skip-moving'=> true,
|
||||||
|
'type' => true,
|
||||||
|
'charset' => true,
|
||||||
|
);
|
||||||
|
return wp_kses( $value, $allowed );
|
||||||
|
}
|
||||||
|
|
||||||
function enqueue_template_specific_styles() {
|
function enqueue_template_specific_styles() {
|
||||||
if ( is_page_template('page-camp.php') ) {
|
if ( is_page_template('page-camp.php') ) {
|
||||||
wp_enqueue_style(
|
wp_enqueue_style(
|
||||||
@ -826,6 +1316,27 @@ function enqueue_template_specific_styles() {
|
|||||||
true
|
true
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if ( is_page_template('page-reviews.php') ) {
|
||||||
|
wp_enqueue_style(
|
||||||
|
'phosphor-icons',
|
||||||
|
'https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css',
|
||||||
|
array(),
|
||||||
|
'2.1.1'
|
||||||
|
);
|
||||||
|
wp_enqueue_style(
|
||||||
|
'reviews-page-style',
|
||||||
|
get_template_directory_uri() . '/assets/css/reviews-page.css',
|
||||||
|
array(),
|
||||||
|
filemtime(get_template_directory() . '/assets/css/reviews-page.css')
|
||||||
|
);
|
||||||
|
wp_enqueue_script(
|
||||||
|
'reviews-page-script',
|
||||||
|
get_template_directory_uri() . '/assets/js/reviews-page.js',
|
||||||
|
array(),
|
||||||
|
filemtime(get_template_directory() . '/assets/js/reviews-page.js'),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
if ( is_page_template('page-after-school.php') ) {
|
if ( is_page_template('page-after-school.php') ) {
|
||||||
wp_enqueue_style(
|
wp_enqueue_style(
|
||||||
'template-after-style',
|
'template-after-style',
|
||||||
@ -834,6 +1345,29 @@ function enqueue_template_specific_styles() {
|
|||||||
'1.1'
|
'1.1'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if ( is_page_template('page-podgotovka-k-shkole.php') ) {
|
||||||
|
wp_enqueue_style(
|
||||||
|
'template-pksh-style',
|
||||||
|
get_template_directory_uri() . '/assets/css/podgotovka-k-shkole.css',
|
||||||
|
array(),
|
||||||
|
'2.1.' . filemtime(get_template_directory() . '/assets/css/podgotovka-k-shkole.css')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ( is_page_template('front-page.php') || is_front_page() ) {
|
||||||
|
wp_enqueue_style(
|
||||||
|
'front-page-style',
|
||||||
|
get_template_directory_uri() . '/assets/css/front-page.css',
|
||||||
|
array(),
|
||||||
|
filemtime(get_template_directory() . '/assets/css/front-page.css')
|
||||||
|
);
|
||||||
|
wp_enqueue_script(
|
||||||
|
'front-page-script',
|
||||||
|
get_template_directory_uri() . '/assets/js/front-page.js',
|
||||||
|
array(),
|
||||||
|
filemtime(get_template_directory() . '/assets/js/front-page.js'),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
add_action('wp_enqueue_scripts', 'enqueue_template_specific_styles');
|
add_action('wp_enqueue_scripts', 'enqueue_template_specific_styles');
|
||||||
|
|
||||||
@ -1121,8 +1655,6 @@ function dekart_branch_register_settings() {
|
|||||||
'branch_postal_code' => 'text',
|
'branch_postal_code' => 'text',
|
||||||
'branch_phone' => 'text',
|
'branch_phone' => 'text',
|
||||||
'branch_email' => 'email',
|
'branch_email' => 'email',
|
||||||
'branch_whatsapp' => 'url',
|
|
||||||
'branch_telegram' => 'url',
|
|
||||||
'branch_name' => 'text',
|
'branch_name' => 'text',
|
||||||
'branch_price_range' => 'text',
|
'branch_price_range' => 'text',
|
||||||
);
|
);
|
||||||
@ -1131,6 +1663,19 @@ function dekart_branch_register_settings() {
|
|||||||
}
|
}
|
||||||
register_setting( 'dekart_branch_group', 'branch_logo', array( 'sanitize_callback' => 'absint' ) );
|
register_setting( 'dekart_branch_group', 'branch_logo', array( 'sanitize_callback' => 'absint' ) );
|
||||||
register_setting( 'dekart_branch_group', 'branch_social' );
|
register_setting( 'dekart_branch_group', 'branch_social' );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_messengers' );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_button_script', array( 'sanitize_callback' => 'dekart_sanitize_script_field' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_hours', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_myreviews_widget', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_ext_yandex', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_ext_google', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_ext_2gis', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_ext_otzovik', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_ext_other_name', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||||
|
register_setting( 'dekart_branch_group', 'branch_ext_other_url', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||||
|
// Поля branch_map_url, branch_founded, branch_photos — удалены.
|
||||||
|
// Они дублировали CF таб «SEO и микроразметка» (schema_*).
|
||||||
|
// Чтение: inc/schema.php → dekart_schema_option() → CF → Settings API (backward compat).
|
||||||
}
|
}
|
||||||
|
|
||||||
function dekart_branch_settings_page() {
|
function dekart_branch_settings_page() {
|
||||||
@ -1139,10 +1684,26 @@ function dekart_branch_settings_page() {
|
|||||||
<h1>Настройки филиала</h1>
|
<h1>Настройки филиала</h1>
|
||||||
<form method="post" action="options.php">
|
<form method="post" action="options.php">
|
||||||
<?php settings_fields( 'dekart_branch_group' ); ?>
|
<?php settings_fields( 'dekart_branch_group' ); ?>
|
||||||
<style>.branch-section{background:#fff;padding:20px;margin:20px 0;border:1px solid #c3c4c7;border-radius:4px;max-width:800px}.branch-section h2{margin-top:0;padding-bottom:10px;border-bottom:1px solid #eee}.branch-field{margin-bottom:16px}.branch-field label{display:block;font-weight:600;margin-bottom:4px}.branch-field input[type=text],.branch-field input[type=email],.branch-field input[type=url]{width:100%;max-width:400px}.branch-field .desc{color:#646970;font-size:12px;margin:4px 0 0}.branch-media-wrap{display:flex;align-items:center;gap:12px}.branch-media-wrap img{max-width:120px;max-height:80px;border:1px solid #ddd;border-radius:4px}.branch-social-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}.branch-social-row input{flex:1}</style>
|
<style>
|
||||||
|
.branch-section{background:#fff;padding:20px;margin:20px 0;border:1px solid #c3c4c7;border-radius:4px;max-width:800px}
|
||||||
|
.branch-section h2{margin-top:0;padding-bottom:10px;border-bottom:1px solid #eee;cursor:pointer;user-select:none;display:flex;align-items:center;justify-content:space-between}
|
||||||
|
.branch-section h2::after{content:'−';font-size:20px;line-height:1;color:#999;transition:transform .2s}
|
||||||
|
.branch-section.collapsed h2::after{content:'+'}
|
||||||
|
.branch-section.collapsed .branch-section-body{display:none}
|
||||||
|
.branch-section.collapsed{border-color:#e0e0e0;background:#fcfcfc}
|
||||||
|
.branch-field{margin-bottom:16px}
|
||||||
|
.branch-field label{display:block;font-weight:600;margin-bottom:4px}
|
||||||
|
.branch-field input[type=text],.branch-field input[type=email],.branch-field input[type=url]{width:100%;max-width:400px}
|
||||||
|
.branch-field .desc{color:#646970;font-size:12px;margin:4px 0 0}
|
||||||
|
.branch-media-wrap{display:flex;align-items:center;gap:12px}
|
||||||
|
.branch-media-wrap img{max-width:120px;max-height:80px;border:1px solid #ddd;border-radius:4px}
|
||||||
|
.branch-social-row{display:flex;gap:8px;align-items:center;margin-bottom:8px}
|
||||||
|
.branch-social-row input{flex:1}
|
||||||
|
</style>
|
||||||
|
|
||||||
<div class="branch-section">
|
<div class="branch-section collapsed">
|
||||||
<h2>🌍 ГЕО</h2>
|
<h2>🌍 ГЕО</h2>
|
||||||
|
<div class="branch-section-body">
|
||||||
<div class="branch-field">
|
<div class="branch-field">
|
||||||
<label>Город (с предлогом)</label>
|
<label>Город (с предлогом)</label>
|
||||||
<input type="text" name="branch_city_prep" value="<?php echo esc_attr( get_option( 'branch_city_prep', 'в Щёлково' ) ); ?>">
|
<input type="text" name="branch_city_prep" value="<?php echo esc_attr( get_option( 'branch_city_prep', 'в Щёлково' ) ); ?>">
|
||||||
@ -1171,9 +1732,11 @@ function dekart_branch_settings_page() {
|
|||||||
<input type="text" name="branch_postal_code" value="<?php echo esc_attr( get_option( 'branch_postal_code', '' ) ); ?>">
|
<input type="text" name="branch_postal_code" value="<?php echo esc_attr( get_option( 'branch_postal_code', '' ) ); ?>">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="branch-section">
|
<div class="branch-section collapsed">
|
||||||
<h2>📞 КОНТАКТЫ</h2>
|
<h2>📞 КОНТАКТЫ</h2>
|
||||||
|
<div class="branch-section-body">
|
||||||
<div class="branch-field">
|
<div class="branch-field">
|
||||||
<label>Телефон</label>
|
<label>Телефон</label>
|
||||||
<input type="text" name="branch_phone" value="<?php echo esc_attr( get_option( 'branch_phone', '+7 (495) 120-00-78' ) ); ?>">
|
<input type="text" name="branch_phone" value="<?php echo esc_attr( get_option( 'branch_phone', '+7 (495) 120-00-78' ) ); ?>">
|
||||||
@ -1182,19 +1745,101 @@ function dekart_branch_settings_page() {
|
|||||||
<label>Email</label>
|
<label>Email</label>
|
||||||
<input type="email" name="branch_email" value="<?php echo esc_attr( get_option( 'branch_email', 'info@dekart.school' ) ); ?>">
|
<input type="email" name="branch_email" value="<?php echo esc_attr( get_option( 'branch_email', 'info@dekart.school' ) ); ?>">
|
||||||
</div>
|
</div>
|
||||||
<div class="branch-field">
|
|
||||||
<label>WhatsApp</label>
|
|
||||||
<input type="url" name="branch_whatsapp" value="<?php echo esc_attr( get_option( 'branch_whatsapp', '' ) ); ?>">
|
|
||||||
<p class="desc">https://wa.me/79991234567</p>
|
|
||||||
</div>
|
|
||||||
<div class="branch-field">
|
|
||||||
<label>Telegram</label>
|
|
||||||
<input type="url" name="branch_telegram" value="<?php echo esc_attr( get_option( 'branch_telegram', '' ) ); ?>">
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="branch-section">
|
<div class="branch-section collapsed">
|
||||||
|
<h2>🌐 СОЦСЕТИ И МЕССЕНДЖЕРЫ</h2>
|
||||||
|
<div class="branch-section-body">
|
||||||
|
<p class="desc">Добавьте как соцсети (VK, YouTube, Instagram*), так и мессенджеры (WhatsApp, Telegram, Viber и др.). Все они отображаются в блоке «Наши соцсети» на странице. *Meta признана экстремистской организацией.</p>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Социальные сети</label>
|
||||||
|
<p class="desc" style="margin-bottom:8px;">Название + ссылка на профиль.</p>
|
||||||
|
<div id="branch-social-repeater">
|
||||||
|
<?php
|
||||||
|
$social = get_option( 'branch_social', array() );
|
||||||
|
if ( ! is_array( $social ) || empty( $social ) ) {
|
||||||
|
$social = array( array( 'name' => '', 'url' => '' ) );
|
||||||
|
}
|
||||||
|
foreach ( $social as $i => $item ) {
|
||||||
|
$name = esc_attr( $item['name'] ?? '' );
|
||||||
|
$url = esc_attr( $item['url'] ?? '' );
|
||||||
|
echo '<div class="branch-social-row"><input type="text" name="branch_social[' . $i . '][name]" value="' . $name . '" placeholder="Название"><input type="url" name="branch_social[' . $i . '][url]" value="' . $url . '" placeholder="https://..."><button type="button" class="button branch-social-remove">—</button></div>';
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="button" id="branch-social-add">+ Добавить соцсеть</button>
|
||||||
|
</div>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Мессенджеры</label>
|
||||||
|
<p class="desc" style="margin-bottom:8px;">Название + ссылка для связи.</p>
|
||||||
|
<div id="branch-messengers-container">
|
||||||
|
<?php
|
||||||
|
$messengers = get_option( 'branch_messengers', array() );
|
||||||
|
if ( ! empty( $messengers ) && is_array( $messengers ) ) :
|
||||||
|
foreach ( $messengers as $i => $m ) :
|
||||||
|
$m_name = $m['name'] ?? '';
|
||||||
|
$m_url = $m['url'] ?? '';
|
||||||
|
?>
|
||||||
|
<div class="branch-social-row">
|
||||||
|
<input type="text" name="branch_messengers[<?php echo intval( $i ); ?>][name]" value="<?php echo esc_attr( $m_name ); ?>" placeholder="Название (напр. WhatsApp)" style="max-width:160px;">
|
||||||
|
<input type="url" name="branch_messengers[<?php echo intval( $i ); ?>][url]" value="<?php echo esc_attr( $m_url ); ?>" placeholder="https://..." style="max-width:300px;">
|
||||||
|
<button type="button" class="button branch-messenger-remove">−</button>
|
||||||
|
</div>
|
||||||
|
<?php endforeach;
|
||||||
|
endif; ?>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="button" id="branch-messenger-add" style="margin-top:4px;">+ Добавить мессенджер</button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
// Соцсети
|
||||||
|
var socialContainer = document.getElementById('branch-social-repeater');
|
||||||
|
var socialAdd = document.getElementById('branch-social-add');
|
||||||
|
if (socialAdd) {
|
||||||
|
socialAdd.addEventListener('click', function() {
|
||||||
|
var idx = socialContainer.children.length;
|
||||||
|
var row = document.createElement('div');
|
||||||
|
row.className = 'branch-social-row';
|
||||||
|
row.innerHTML = '<input type="text" name="branch_social[' + idx + '][name]" placeholder="Название"><input type="url" name="branch_social[' + idx + '][url]" placeholder="https://..."><button type="button" class="button branch-social-remove">—</button>';
|
||||||
|
socialContainer.appendChild(row);
|
||||||
|
row.querySelector('.branch-social-remove').addEventListener('click', function() { row.remove(); });
|
||||||
|
});
|
||||||
|
socialContainer.addEventListener('click', function(e) {
|
||||||
|
if (e.target.classList.contains('branch-social-remove')) {
|
||||||
|
e.target.parentElement.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Мессенджеры
|
||||||
|
var messengerContainer = document.getElementById('branch-messengers-container');
|
||||||
|
var messengerAdd = document.getElementById('branch-messenger-add');
|
||||||
|
var idx = messengerContainer.children.length;
|
||||||
|
if (messengerAdd) {
|
||||||
|
messengerAdd.addEventListener('click', function() {
|
||||||
|
var row = document.createElement('div');
|
||||||
|
row.className = 'branch-social-row';
|
||||||
|
row.innerHTML = '<input type="text" name="branch_messengers[' + idx + '][name]" placeholder="Название (напр. WhatsApp)" style="max-width:160px;">' +
|
||||||
|
'<input type="url" name="branch_messengers[' + idx + '][url]" placeholder="https://..." style="max-width:300px;">' +
|
||||||
|
'<button type="button" class="button branch-messenger-remove">−</button>';
|
||||||
|
messengerContainer.appendChild(row);
|
||||||
|
idx++;
|
||||||
|
row.querySelector('.branch-messenger-remove').addEventListener('click', function() { row.remove(); });
|
||||||
|
});
|
||||||
|
messengerContainer.addEventListener('click', function(e) {
|
||||||
|
if (e.target.classList.contains('branch-messenger-remove')) {
|
||||||
|
e.target.parentElement.remove();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="branch-section collapsed">
|
||||||
<h2>🏢 ОРГАНИЗАЦИЯ</h2>
|
<h2>🏢 ОРГАНИЗАЦИЯ</h2>
|
||||||
|
<div class="branch-section-body">
|
||||||
<div class="branch-field">
|
<div class="branch-field">
|
||||||
<label>Полное название организации</label>
|
<label>Полное название организации</label>
|
||||||
<input type="text" name="branch_name" value="<?php echo esc_attr( get_option( 'branch_name', 'Декарт' ) ); ?>">
|
<input type="text" name="branch_name" value="<?php echo esc_attr( get_option( 'branch_name', 'Декарт' ) ); ?>">
|
||||||
@ -1210,36 +1855,85 @@ function dekart_branch_settings_page() {
|
|||||||
<p class="desc">ID изображения из Медиафайлы. Для JSON-LD image.</p>
|
<p class="desc">ID изображения из Медиафайлы. Для JSON-LD image.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="branch-section">
|
<div class="branch-section collapsed">
|
||||||
<h2>🔗 СОЦСЕТИ</h2>
|
<h2>⏰ РЕЖИМ РАБОТЫ</h2>
|
||||||
<p class="desc">Добавьте ссылки (название и URL).</p>
|
<div class="branch-section-body">
|
||||||
<div id="branch-social-repeater">
|
<div class="branch-field">
|
||||||
<?php
|
<label>Режим работы школы</label>
|
||||||
$social = get_option( 'branch_social', array() );
|
<input type="text" name="branch_hours" value="<?php echo esc_attr( get_option( 'branch_hours', 'ежедневно с 8:00 до 19:00, кроме воскресенья' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
if ( ! is_array( $social ) || empty( $social ) ) {
|
<p class="desc">Текст с режимом работы. Появляется на странице отзывов после вступительного текста.</p>
|
||||||
$social = array( array( 'name' => '', 'url' => '' ) );
|
|
||||||
}
|
|
||||||
foreach ( $social as $i => $item ) {
|
|
||||||
$name = esc_attr( $item['name'] ?? '' );
|
|
||||||
$url = esc_attr( $item['url'] ?? '' );
|
|
||||||
echo '<div class="branch-social-row"><input type="text" name="branch_social[' . $i . '][name]" value="' . $name . '" placeholder="Название"><input type="url" name="branch_social[' . $i . '][url]" value="' . $url . '" placeholder="https://..."><button type="button" class="button branch-social-remove">—</button></div>';
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
</div>
|
</div>
|
||||||
<button type="button" class="button" id="branch-social-add">+ Добавить</button>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="branch-section collapsed">
|
||||||
|
<h2>🎯 СКРИПТ ДЛЯ КНОПОК</h2>
|
||||||
|
<div class="branch-section-body">
|
||||||
|
<p class="desc">Bitrix24-скрипт, который выполняется при клике на CTA-кнопки (например, «Записаться на экскурсию»). Вставьте полный JS-код формы.</p>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Скрипт (JS/HTML)</label>
|
||||||
|
<textarea name="branch_button_script" rows="8" style="width:100%;max-width:700px;font-family:monospace;font-size:13px"><?php echo esc_textarea( get_option( 'branch_button_script', '' ) ); ?></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="branch-section collapsed">
|
||||||
|
<h2>⭐ MYREVIEWS</h2>
|
||||||
|
<div class="branch-section-body">
|
||||||
|
<p class="desc">Виджет отзывов от MyReviews. Вставьте ссылку на фид.</p>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Ссылка фида MyReviews</label>
|
||||||
|
<input type="text" name="branch_myreviews_widget" value="<?php echo esc_attr( get_option( 'branch_myreviews_widget', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
|
<p class="desc">Например: https://feed.myreviews.ru/27645</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="branch-section collapsed">
|
||||||
|
<h2>🔗 E-E-A-T: Внешние платформы</h2>
|
||||||
|
<div class="branch-section-body">
|
||||||
|
<p class="desc">Ссылки на внешние площадки с отзывами для повышения E-E-A-T. Отображаются под заголовком «Отзывы на внешних площадках».</p>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Яндекс Карты (ссылка на отзывы)</label>
|
||||||
|
<input type="url" name="branch_ext_yandex" value="<?php echo esc_attr( get_option( 'branch_ext_yandex', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
|
<p class="desc">https://yandex.ru/maps/org/.../reviews/</p>
|
||||||
|
</div>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Google Карты (ссылка на отзывы)</label>
|
||||||
|
<input type="url" name="branch_ext_google" value="<?php echo esc_attr( get_option( 'branch_ext_google', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
|
<p class="desc">https://maps.google.com/maps/place/.../ ...</p>
|
||||||
|
</div>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>2ГИС (ссылка на отзывы)</label>
|
||||||
|
<input type="url" name="branch_ext_2gis" value="<?php echo esc_attr( get_option( 'branch_ext_2gis', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
|
<p class="desc">https://2gis.ru/.../</p>
|
||||||
|
</div>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Отзовик / IRecommend</label>
|
||||||
|
<input type="url" name="branch_ext_otzovik" value="<?php echo esc_attr( get_option( 'branch_ext_otzovik', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
|
</div>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Другая платформа (название)</label>
|
||||||
|
<input type="text" name="branch_ext_other_name" value="<?php echo esc_attr( get_option( 'branch_ext_other_name', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
|
</div>
|
||||||
|
<div class="branch-field">
|
||||||
|
<label>Другая платформа (ссылка)</label>
|
||||||
|
<input type="url" name="branch_ext_other_url" value="<?php echo esc_attr( get_option( 'branch_ext_other_url', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.getElementById('branch-social-add')?.addEventListener('click', function(){
|
// Сворачивание/разворачивание блоков
|
||||||
var c = document.querySelectorAll('#branch-social-repeater .branch-social-row').length;
|
document.querySelectorAll('.branch-section > h2').forEach(function(h2){
|
||||||
var d = document.createElement('div'); d.className = 'branch-social-row';
|
h2.addEventListener('click', function(){
|
||||||
d.innerHTML = '<input type="text" name="branch_social['+c+'][name]" value="" placeholder="Название"><input type="url" name="branch_social['+c+'][url]" value="" placeholder="https://..."><button type="button" class="button branch-social-remove">—</button>';
|
this.parentElement.classList.toggle('collapsed');
|
||||||
document.getElementById('branch-social-repeater').appendChild(d);
|
|
||||||
});
|
});
|
||||||
document.addEventListener('click', function(e){
|
|
||||||
if(e.target.classList.contains('branch-social-remove')) e.target.parentElement.remove();
|
|
||||||
});
|
});
|
||||||
|
// Соцсети и мессенджеры: их JS инициализируется внутри секции «СОЦСЕТИ И МЕССЕНДЖЕРЫ»
|
||||||
</script>
|
</script>
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php submit_button('Сохранить настройки филиала'); ?>
|
<?php submit_button('Сохранить настройки филиала'); ?>
|
||||||
</form>
|
</form>
|
||||||
@ -1247,6 +1941,29 @@ function dekart_branch_settings_page() {
|
|||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ════════════════════════════════════════════════════════════
|
||||||
|
🎯 REDESIGN 2026 — Schema + H1 filter + Bento CSS/JS
|
||||||
|
════════════════════════════════════════════════════════════ */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Подключаем динамический генератор Schema.org JSON-LD
|
||||||
|
* Единый @graph в wp_head. Только Carbon Fields данные.
|
||||||
|
*/
|
||||||
|
require_once __DIR__ . '/inc/schema.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Фильтр: замена H1 для страницы "Подготовка к школе" (ID 2)
|
||||||
|
* Добавляет Risk Reversal в заголовок
|
||||||
|
*/
|
||||||
|
|
||||||
|
// podgotovka-k-shkole.css enqueued in enqueue_template_specific_styles()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Счётчики доверия в админку Carbon Fields — добавляем поля
|
||||||
|
* "выпускники", "лет опыта", "рейтинг"
|
||||||
|
* (настройки темы уже есть — используем статические)
|
||||||
|
*/
|
||||||
|
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
// ACF: Отзывы (Лагерь) — группа полей
|
// ACF: Отзывы (Лагерь) — группа полей
|
||||||
// ─────────────────────────────────────────────────────────────
|
// ─────────────────────────────────────────────────────────────
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user