2026-09-08 Наши преподавтели

This commit is contained in:
Dekart Deploy Bot 2026-09-08 18:38:27 +00:00
parent 91aa9c33ce
commit 545644682d
15 changed files with 1149 additions and 8 deletions

View File

@ -0,0 +1,382 @@
/* ======================================================
* Страница "Преподаватели" (page-teachers.php) Bento 2026
* Блоки: hero, intro, filter, cards, trust, faq, cta
* ====================================================== */
/* ── Hero (по образцу главной ds-hero, компактнее) ── */
.teachers-hero .ds-hero__inner {
gap: var(--space-5, 40px);
padding: 0;
}
.teachers-hero .ds-hero__visual {
width: 340px;
}
.teachers-hero .ds-hero__photo-frame {
width: 280px;
height: 280px;
}
.teachers-hero .ds-hero__photo-ring {
width: 320px;
height: 320px;
}
.teachers-hero .ds-hero__subtitle {
max-width: 58ch;
}
.teachers-hero .ds-hero__year {
color: #60A5FA;
font-weight: 800;
white-space: nowrap;
text-shadow: 0 0 6px rgba(96, 165, 250, 0.3);
}
.teachers-hero .ds-hero__address {
margin-bottom: var(--space-3, 16px);
}
.teachers-hero .ds-hero__h1 {
margin-bottom: var(--space-3, 16px);
}
.teachers-hero .ds-hero__assurance {
display: flex;
flex-wrap: wrap;
gap: var(--space-2, 8px);
margin-top: 12px;
margin-bottom: 8px;
}
.teachers-hero .ds-hero__assurance-item {
font-size: 14px;
color: rgba(255, 255, 255, 0.80);
display: inline-flex;
align-items: center;
gap: 4px;
}
.teachers-hero .ds-hero__assurance-item::before {
content: '✓';
color: #4ADE80;
font-weight: 700;
font-size: 11px;
}
/* ── Введение (SEO) ── */
.teachers-intro {
padding: var(--space-6, 48px) 0;
background: var(--color-bg, #FFFFFF);
}
.teachers-intro .section-header--left {
text-align: left;
}
.teachers-intro .bento-h2,
.teachers-intro .bento-p {
max-width: none;
margin-left: 0;
margin-right: auto;
}
.teachers-intro .bento-p {
max-width: 70ch;
}
/* ── Фильтр ── */
.teachers-filter-wrap {
padding: 0 0 var(--space-5, 40px);
background: var(--color-bg, #FFFFFF);
}
.teachers-filter {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--space-3, 16px);
}
.teachers-filter__title {
font-size: 0.9375rem;
font-weight: 600;
color: var(--color-text-muted, #475569);
white-space: nowrap;
}
.teachers-filter__buttons {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.teachers-filter__btn {
padding: 8px 20px;
border: 1px solid var(--color-border, #E2E8F0);
border-radius: var(--radius-pill, 100px);
background: var(--color-bg, #FFFFFF);
color: var(--color-text, #1E293B);
font-size: 0.9375rem;
font-weight: 600;
line-height: 1.2;
cursor: pointer;
transition: background .2s, color .2s, border-color .2s;
}
.teachers-filter__btn:hover {
border-color: var(--color-primary, #2563EB);
color: var(--color-primary, #2563EB);
}
.teachers-filter__btn.is-active {
background: var(--color-primary, #2563EB);
border-color: var(--color-primary, #2563EB);
color: #FFFFFF;
}
/* ── Карточки ── */
.teachers-cards {
padding: 0 0 var(--space-6, 48px);
background: var(--color-bg, #FFFFFF);
}
.teachers-cards__grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: clamp(16px, 2vw, 24px);
}
.teachers-card {
display: flex;
flex-direction: column;
background: var(--color-bg-card, #FFFFFF);
border: 1px solid var(--color-border, #E2E8F0);
border-radius: var(--radius-lg, 24px);
overflow: hidden;
transition: box-shadow .25s, transform .25s, border-color .25s;
}
.teachers-card:hover {
box-shadow: var(--shadow-md, 0 8px 24px rgba(15, 23, 42, .08));
transform: translateY(-3px);
border-color: rgba(37, 99, 235, .35);
}
.teachers-card.is-hidden {
display: none;
}
.teachers-card__media {
position: relative;
aspect-ratio: 1 / 1;
overflow: hidden;
background: var(--color-primary-light, #EFF6FF);
}
.teachers-card__photo {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.teachers-card__badge {
position: absolute;
left: 12px;
bottom: 12px;
max-width: calc(100% - 24px);
padding: 6px 14px;
border-radius: var(--radius-pill, 100px);
background: rgba(255, 255, 255, .92);
color: var(--color-primary, #2563EB);
font-size: 0.8125rem;
font-weight: 700;
line-height: 1.3;
box-shadow: 0 2px 8px rgba(15, 23, 42, .1);
}
.teachers-card__body {
display: flex;
flex-direction: column;
gap: var(--space-2, 8px);
padding: var(--space-4, 24px);
flex: 1;
}
.teachers-card__name {
font-family: var(--font-display, inherit);
font-size: clamp(1.125rem, 1.6vw, 1.375rem);
font-weight: 700;
line-height: 1.25;
margin: 0;
}
.teachers-card__direction {
font-size: 0.9375rem;
font-weight: 600;
color: var(--color-primary, #2563EB);
}
.teachers-card__tenure {
font-size: 0.875rem;
color: var(--color-text, #1E293B);
}
.teachers-card__rating {
display: flex;
align-items: center;
gap: 8px;
margin-top: auto;
padding-top: var(--space-2, 8px);
}
.teachers-card__stars {
display: inline-flex;
gap: 2px;
color: var(--color-border, #CBD5E1);
}
.teachers-card__star.is-filled {
color: #F59E0B;
}
.teachers-card__rating-num {
font-size: 0.875rem;
font-weight: 700;
color: var(--color-text-muted, #475569);
}
.teachers-card__actions {
display: flex;
flex-direction: column;
gap: 10px;
margin-top: var(--space-2, 8px);
}
.teachers-card__btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 100%;
padding: 12px 20px;
border: none;
border-radius: var(--radius-pill, 100px);
background: var(--color-primary, #2563EB);
color: #FFFFFF;
font-size: 0.9375rem;
font-weight: 700;
line-height: 1.2;
text-decoration: none;
cursor: pointer;
transition: background .2s;
}
.teachers-card__btn:hover {
background: var(--color-primary-dark, #1D4ED8);
color: #FFFFFF;
}
.teachers-card__link {
display: inline-block;
text-align: center;
font-size: 0.875rem;
font-weight: 600;
color: var(--color-primary, #2563EB);
text-decoration: none;
transition: color .2s;
}
.teachers-card__link:hover {
color: var(--color-primary-dark, #1D4ED8);
text-decoration: underline;
}
/* ── Блок доверия ── */
.teachers-trust {
padding: var(--space-5, 40px) 0;
background: var(--color-surface-soft, #F8FAFC);
}
.teachers-trust__grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: clamp(16px, 2vw, 24px);
}
.teachers-trust__item {
text-align: center;
padding: var(--space-4, 24px);
border-radius: var(--radius-lg, 24px);
background: var(--color-bg, #FFFFFF);
box-shadow: var(--shadow-sm, 0 2px 12px rgba(15, 23, 42, .05));
}
.teachers-trust__number {
font-family: var(--font-display, inherit);
font-size: clamp(1.875rem, 3.5vw, 2.75rem);
font-weight: 700;
line-height: 1.1;
color: var(--color-primary, #2563EB);
margin-bottom: 6px;
}
.teachers-trust__label {
font-size: 0.9375rem;
line-height: 1.5;
color: var(--color-text-muted, #475569);
}
/* ── FAQ ── */
.teachers-faq {
padding: var(--space-6, 48px) 0;
background: var(--color-bg, #FFFFFF);
}
/* ── CTA ── */
.teachers-cta {
padding: var(--space-6, 48px) 0;
background: var(--color-primary-light, #EFF6FF);
}
.teachers-cta__inner {
display: flex;
flex-direction: column;
align-items: center;
gap: var(--space-4, 24px);
text-align: center;
}
.teachers-cta__btn {
display: inline-flex;
align-items: center;
gap: 10px;
padding: 14px 28px;
border: none;
border-radius: var(--radius-pill, 100px);
background: var(--color-primary, #2563EB);
color: #FFFFFF;
font-size: 1rem;
font-weight: 700;
cursor: pointer;
transition: background .2s;
}
.teachers-cta__btn:hover {
background: var(--color-primary-dark, #1D4ED8);
}
.teachers-cta__btn svg {
flex: none;
}
/* ── Адаптив ── */
@media (max-width: 1024px) {
.teachers-cards__grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 768px) {
.teachers-hero .ds-hero__photo-frame {
width: 220px;
height: 220px;
}
.teachers-hero .ds-hero__photo-ring {
width: 250px;
height: 250px;
}
.teachers-hero .ds-hero__visual {
width: 100%;
margin: 0;
}
.teachers-intro,
.teachers-cards,
.teachers-faq {
padding: var(--space-4, 24px) 0;
}
.teachers-trust,
.teachers-cta {
padding: var(--space-4, 24px) 0;
}
.teachers-cards__grid {
grid-template-columns: 1fr;
}
.teachers-trust__grid {
grid-template-columns: 1fr;
}
.teachers-filter {
flex-direction: column;
align-items: flex-start;
}
.teachers-filter__buttons {
width: 100%;
}
.teachers-filter__btn {
flex: 1 1 auto;
text-align: center;
}
}
@media (prefers-reduced-motion: reduce) {
.teachers-card {
transition: none;
}
.teachers-card:hover {
transform: none;
}
}

View File

@ -0,0 +1,55 @@
/**
* Страница "Преподаватели" фильтр карточек + reveal-анимации.
* Фильтры читаются из кнопок .teachers-filter__btn[data-filter],
* карточки фильтруются по .teachers-card[data-category].
*/
(function () {
'use strict';
// ── Reveal-анимации (как на главной/школе) ──
var sections = document.querySelectorAll('.page-teachers .reveal');
if (sections.length && 'IntersectionObserver' in window) {
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
if (entry.isIntersecting) {
entry.target.classList.add('is-visible');
observer.unobserve(entry.target);
}
});
}, { threshold: 0.12 });
sections.forEach(function (el) {
observer.observe(el);
});
}
// ── Фильтр карточек ──
var filterWrap = document.querySelector('.teachers-filter');
var grid = document.getElementById('teachers-grid');
if (!filterWrap || !grid) {
return;
}
var buttons = filterWrap.querySelectorAll('.teachers-filter__btn');
var cards = grid.querySelectorAll('.teachers-card');
function applyFilter(slug) {
buttons.forEach(function (btn) {
var isActive = btn.getAttribute('data-filter') === slug;
btn.classList.toggle('is-active', isActive);
btn.setAttribute('aria-pressed', isActive ? 'true' : 'false');
});
cards.forEach(function (card) {
var cat = card.getAttribute('data-category') || 'all';
var visible = (slug === 'all' || cat === slug || cat === 'all');
card.classList.toggle('is-hidden', !visible);
});
}
buttons.forEach(function (btn) {
btn.addEventListener('click', function () {
applyFilter(btn.getAttribute('data-filter') || 'all');
});
});
})();

View File

@ -373,7 +373,7 @@ $faq_has = ! empty($front_faq) && is_array($front_faq);
<div class="exit-banner__inner">
<div class="exit-banner__content">
<span class="exit-banner__title">Остались вопросы?</span>
<span class="exit-banner__text">Позвоните расскажем о школе и запишем на экскурсию</span>
<span class="exit-banner__text">Позвоните расскажем о школе и запишем ребёнка на обучение</span>
</div>
<?php if ($exit_phone) : $exit_clean = preg_replace('/[\s\-\\(\)]/', '', $exit_phone); ?>
<a class="exit-banner__btn" href="tel:<?php echo esc_attr($exit_clean); ?>">

View File

@ -752,6 +752,20 @@ function add_carbon()
'icon-certificate' => '📜 Сертификат',
);
// Категории фильтра для карточки преподавателя (из таксономии trainingCategory)
$teacher_category_options = array(
'' => '— Без категории —',
);
$teacher_cats = get_terms(array(
'taxonomy' => 'trainingCategory',
'hide_empty' => false,
));
if (! is_wp_error($teacher_cats) && ! empty($teacher_cats)) {
foreach ($teacher_cats as $teacher_cat) {
$teacher_category_options[ $teacher_cat->slug ] = $teacher_cat->name;
}
}
// Иконки для плашек hero — только из SVG-спрайта (use href="#icon-*")
$school_hero_float_icons = array(
'teacher' => '👨‍🏫 Учитель',
@ -1484,6 +1498,10 @@ function add_carbon()
))
->help_text('В списке указаны все возможные категрии в обучении, выберите необходимые'),
)),
Field::make('select', 'teacher_category', 'Категория для фильтра на странице преподавателей')
->set_width(50)
->set_options($teacher_category_options)
->set_help_text('Значение должно совпадать со slug фильтра на странице преподавателей. Пусто — карточка видна только во «Все».'),
Field::make('complex', 'certificates', 'Дипломы и сертификаты')
->set_layout('tabbed-horizontal')
->add_fields(array(
@ -1503,6 +1521,84 @@ function add_carbon()
)),
));
// ====================================================
// Доп поля для страницы "Преподаватели" (Bento 2026)
// ====================================================
Container::make('post_meta', '📚 Настройки страницы Преподаватели')
->where('post_template', '=', 'page-teachers.php')
->add_tab('🖼️ Введение (SEO)', array(
Field::make('html', 'teachers_intro_tab_desc', '')
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Блок под баннером. H1 берётся из баннера (banner_h1), здесь — вводный текст с гео-ключами.</p>'),
Field::make('textarea', 'banner_text', 'Подзаголовок в баннере (под H1)')
->set_width(100)
->set_help_text('12 предложения: направления школы и гео-ключи.'),
Field::make('textarea', 'teachers_intro_title', 'Заголовок блока')
->set_default_value('Преподаватели школы «Декарт» в Щёлково')
->set_help_text('Второй заголовок с ключевым запросом.'),
Field::make('textarea', 'teachers_intro_text', 'Вводный текст')
->set_help_text('24 предложения: сколько учителей, какие направления закрывают, первое вхождение гео-ключей.'),
))
->add_tab('🔍 Фильтры', array(
Field::make('html', 'teachers_filters_tab_desc', '')
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Фильтр карточек преподавателей. <strong>Динамический:</strong> какие фильтры добавлены — такие и выводятся, в этом порядке. Карточки получают категорию из поля «Категория» на странице преподавателя.</p>'),
Field::make('text', 'teachers_filters_title', 'Заголовок секции фильтров')
->set_default_value('Выберите направление')
->set_width(100),
Field::make('complex', 'teachers_filters', 'Фильтры')
->set_layout('tabbed-horizontal')
->set_help_text('Добавьте нужные фильтры в нужном порядке. Пример: Начальная школа, Подготовка к школе, Продлёнка, Летний лагерь.')
->add_fields(array(
Field::make('text', 'filter_label', 'Название фильтра')
->set_width(60)
->set_required(true)
->set_help_text('Показывается на кнопке. Пример: «Начальная школа».'),
Field::make('text', 'filter_slug', 'Slug (техническое имя)')
->set_width(40)
->set_help_text('Латинскими буквами, без пробелов. Пример: nachalnaya-shkola. Должен совпадать со значением поля «Категория» у карточки преподавателя.'),
)),
))
->add_tab('📊 Блок доверия', array(
Field::make('html', 'teachers_trust_tab_desc', '')
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Цифры под карточками: стаж, категория, текучка, соотношение учитель/ученик. Показывается, если добавлены данные.</p>'),
Field::make('complex', 'teachers_trust', 'Цифры')
->set_layout('tabbed-horizontal')
->set_help_text('Добавьте 24 цифры. Пример: «10+» / «лет средний стаж», «70%» / «учителей с высшей категорией».')
->add_fields(array(
Field::make('text', 'trust_number', 'Число')
->set_width(30)
->set_help_text('Пример: 10+, 70%, 1:15'),
Field::make('text', 'trust_label', 'Подпись')
->set_width(70)
->set_help_text('Пример: лет средний стаж'),
)),
))
->add_tab('🎓 FAQ', array(
Field::make('html', 'teachers_faq_tab_desc', '')
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Частые вопросы про учителей. Из полей строится FAQPage JSON-LD. Показывается, если есть вопросы.</p>'),
Field::make('complex', 'teachers_faq', 'Вопросы и ответы')
->set_layout('tabbed-horizontal')
->add_fields(array(
Field::make('textarea', 'faq_question', 'Вопрос')
->set_width(35)
->set_required(true),
Field::make('textarea', 'faq_answer', 'Ответ')
->set_width(65)
->set_required(true),
)),
))
->add_tab('🤝 CTA', array(
Field::make('html', 'teachers_cta_tab_desc', '')
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Блок перед формой записи. Форма записи и карта — общие, не трогаются.</p>'),
Field::make('text', 'teachers_cta_title', 'Заголовок')
->set_default_value('Познакомьтесь с педагогами лично')
->set_width(100),
Field::make('textarea', 'teachers_cta_text', 'Текст')
->set_default_value('Запишитесь на экскурсию или пробный день — увидите, как проходят занятия, и зададите вопросы учителям напрямую.'),
Field::make('text', 'teachers_cta_btn', 'Текст кнопки')
->set_default_value('Записаться на экскурсию')
->set_help_text('Кнопка открывает форму записи (та же, что ниже).'),
));
// ====================================================
// Доп поля для страницы "Подготовка к школе (Bento 2026)"
// ====================================================
@ -2607,6 +2703,21 @@ function enqueue_template_specific_styles()
true
);
}
if (is_page_template('page-teachers.php')) {
wp_enqueue_style(
'teachers-page-style',
get_template_directory_uri() . '/assets/css/page-teachers.css',
array(),
filemtime(get_template_directory() . '/assets/css/page-teachers.css')
);
wp_enqueue_script(
'teachers-page-script',
get_template_directory_uri() . '/assets/js/page-teachers.js',
array(),
filemtime(get_template_directory() . '/assets/js/page-teachers.js'),
true
);
}
if (is_page_template('page-after-school.php')) {
wp_enqueue_style(
'template-after-style',

View File

@ -9,7 +9,9 @@ $post_id = get_the_ID();
?>
<main class="page-teachers">
<?php get_template_part('template-parts/block-banner'); ?>
<?php get_template_part('template-parts/svg-sprite'); ?>
<?php get_template_part('template-parts/teachers/hero'); ?>
<section class="contetn-main_block">
<div class="container">
@ -19,11 +21,21 @@ $post_id = get_the_ID();
</div>
</section>
<?php get_template_part('template-parts/teachers'); ?>
<?php get_template_part('template-parts/teachers/intro'); ?>
<?php get_template_part('template-parts/promo-form'); ?>
<?php get_template_part('template-parts/teachers/filter'); ?>
<?php get_template_part('template-parts/map'); ?>
<?php get_template_part('template-parts/teachers/cards'); ?>
<?php get_template_part('template-parts/teachers/schema'); ?>
<?php get_template_part('template-parts/teachers/trust'); ?>
<?php get_template_part('template-parts/teachers/faq'); ?>
<?php get_template_part('template-parts/teachers/cta'); ?>
<?php get_template_part('template-parts/contacts'); ?>
</main>

View File

@ -166,7 +166,7 @@ if (empty($opt_social) || ! is_array($opt_social)) {
<?php endif; ?>
</div>
<div class="contacts__map">
<div id="ya-map" style="width: 100%; height: 100%; min-height: 400px;"
<div id="ya-map" style="width: 100%; height: 100%;"
data-coords="<?php echo esc_attr($opt_coords ?: ( get_option('branch_lat', '55.928461') . ',' . get_option('branch_lng', '38.000991') )); ?>"
data-label="<?php echo esc_attr($opt_name ?: 'Частная школа «Декарт»'); ?>"></div>
</div>

View File

@ -26,7 +26,7 @@ $cta_phone_clean = $cta_phone ? preg_replace('/[\s\-\\(\)]/', '', $cta_phone)
<p class="bento-p">Познакомитесь с педагогами, увидите классы и получите персональную консультацию по обучению. Это бесплатно и ничего не обязывает.</p>
</div>
<button class="cta-consultation__btn btn-write open-bitrix-form" data-track="cta-consultation">
Записаться на бесплатную экскурсию
Записаться в школу
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</button>
<noscript>
@ -35,7 +35,7 @@ $cta_phone_clean = $cta_phone ? preg_replace('/[\s\-\\(\)]/', '', $cta_phone)
<a class="cta-consultation__fallback-phone" href="tel:<?php echo esc_attr($cta_phone_clean ?: '+74951200078'); ?>"><?php echo esc_html($cta_phone ?: '+7 (495) 120-00-78'); ?></a>
</div>
</noscript>
<p class="cta-consultation__footnote">Бесплатная экскурсия · 30 минут · Без обязательств</p>
<p class="cta-consultation__footnote">Запишитесь на обучение · Перезвоним за 15 минут · Без обязательств</p>
</div>
</div>
</section>

View File

@ -0,0 +1,107 @@
<?php
/**
* Преподаватели карточки (основной блок)
* CPT teacher + CF: направление, бейдж, аватар, год начала, образование,
* доп. образование, личная фраза, оценка, категория для фильтра.
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
$teachers_args = array(
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'ASC',
'post_type' => 'teacher',
'post_status' => 'publish',
'no_found_rows' => true,
'update_post_meta_cache' => true,
'update_post_term_cache' => true,
);
$teachers_list = get_posts($teachers_args);
if (empty($teachers_list)) {
return;
}
$current_year = (int) current_time('Y');
?>
<section class="teachers-cards section-bg reveal" data-bg="teachers-cards" aria-label="Преподаватели школы">
<div class="container">
<div class="teachers-cards__grid" id="teachers-grid">
<?php foreach ($teachers_list as $teacher) :
setup_postdata($teacher);
$tid = (int) $teacher->ID;
$full_name = get_the_title($tid);
$cat = carbon_get_post_meta($tid, 'teacher_category');
$direction = carbon_get_post_meta($tid, 'teacher_direction');
$badge = carbon_get_post_meta($tid, 'teacher_badge');
$start_year = carbon_get_post_meta($tid, 'teacher_start_year');
$rating = carbon_get_post_meta($tid, 'teacher_rating');
$avatar_id = carbon_get_post_meta($tid, 'teacher_avatar');
$avatar_url = $avatar_id ? wp_get_attachment_url($avatar_id) : '';
$alt_text = $avatar_id ? get_post_meta($avatar_id, '_wp_attachment_image_alt', true) : $full_name;
$tenure = '';
if ($start_year && absint($start_year) > 1900) {
$tenure = max(0, (int) $current_year - (int) $start_year);
}
$cat_filter = ! empty($cat) ? $cat : 'all';
?>
<article class="teachers-card reveal" data-category="<?php echo esc_attr($cat_filter); ?>">
<div class="teachers-card__media">
<?php if ($avatar_url) : ?>
<img class="teachers-card__photo" loading="lazy" decoding="async"
src="<?php echo esc_url($avatar_url); ?>"
alt="<?php echo esc_attr($alt_text); ?>"
width="480" height="480">
<?php endif; ?>
<?php if ($badge) : ?>
<span class="teachers-card__badge"><?php echo esc_html($badge); ?></span>
<?php endif; ?>
</div>
<div class="teachers-card__body">
<h3 class="teachers-card__name"><?php echo esc_html($full_name); ?></h3>
<?php if ($direction) : ?>
<div class="teachers-card__direction"><?php echo esc_html($direction); ?></div>
<?php endif; ?>
<?php if ($tenure) : ?>
<div class="teachers-card__tenure">Стаж: <strong><?php echo esc_html($tenure); ?></strong> лет</div>
<?php endif; ?>
<?php $rating_num = (float) $rating; ?>
<?php if ($rating_num > 0) : ?>
<div class="teachers-card__rating" aria-label="Оценка: <?php echo esc_attr($rating_num); ?> из 5">
<span class="teachers-card__stars" aria-hidden="true">
<?php for ($s = 1; $s <= 5; $s++) : ?>
<svg class="teachers-card__star<?php echo $s <= round($rating_num) ? ' is-filled' : ''; ?>" width="16" height="16" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true"><path d="M10 1l2.39 4.84 5.34.78-3.87 3.77.92 5.34L10 13.27l-4.78 2.51.92-5.34L2.27 6.6l5.34-.78L10 1z"/></svg>
<?php endfor; ?>
</span>
<span class="teachers-card__rating-num"><?php echo esc_html(rtrim(rtrim(number_format($rating_num, 1), '0'), '.')); ?></span>
</div>
<?php endif; ?>
<div class="teachers-card__actions">
<a class="teachers-card__btn btn-write open-bitrix-form" href="#" onclick="return false;">
Записаться к <?php echo esc_html(mb_strtolower($full_name)); ?>
</a>
<a class="teachers-card__link" href="<?php echo esc_url(get_permalink($tid)); ?>">
Подробнее о преподавателе
</a>
</div>
</div>
</article>
<?php endforeach;
wp_reset_postdata(); ?>
</div>
</div>
</section>

View File

@ -0,0 +1,43 @@
<?php
/**
* Преподаватели CTA перед формой записи
* CF teachers_cta_title/text/btn. Кнопка открывает ту же форму, что ниже (promo-form).
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
$post_id = (int) get_the_ID();
$cta_title = carbon_get_post_meta($post_id, 'teachers_cta_title');
$cta_text = carbon_get_post_meta($post_id, 'teachers_cta_text');
$cta_btn = carbon_get_post_meta($post_id, 'teachers_cta_btn');
if (empty($cta_title)) {
$cta_title = 'Познакомьтесь с педагогами лично';
}
if (empty($cta_text)) {
$cta_text = 'Запишитесь на экскурсию или пробный день — увидите, как проходят занятия, и зададите вопросы учителям напрямую.';
}
if (empty($cta_btn)) {
$cta_btn = 'Записаться на экскурсию';
}
?>
<section class="teachers-cta section-bg reveal" data-bg="teachers-cta" aria-label="Запись на экскурсию">
<div class="container">
<div class="teachers-cta__inner">
<div class="section-header--centered">
<h2 class="bento-h2"><?php echo esc_html($cta_title); ?></h2>
<p class="bento-p"><?php echo esc_html($cta_text); ?></p>
</div>
<button class="teachers-cta__btn btn-write open-bitrix-form" data-track="teachers-cta">
<?php echo esc_html($cta_btn); ?>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14m-7-7 7 7-7 7"/></svg>
</button>
</div>
</div>
</section>

View File

@ -0,0 +1,75 @@
<?php
/**
* Преподаватели FAQ (блок + FAQPage JSON-LD)
* Вопросы из CF teachers_faq (complex). Скрывается если нет данных.
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
$post_id = (int) get_the_ID();
$faq = carbon_get_post_meta($post_id, 'teachers_faq');
if (empty($faq) || ! is_array($faq)) {
return;
}
$faq_items = array();
foreach ($faq as $item) {
$q = $item['faq_question'] ?? '';
$a = $item['faq_answer'] ?? '';
if (! $q || ! $a) {
continue;
}
$faq_items[] = array( 'q' => $q, 'a' => $a );
}
if (empty($faq_items)) {
return;
}
?>
<section class="teachers-faq section-bg reveal" data-bg="teachers-faq" aria-label="Вопросы о преподавателях">
<div class="container">
<div class="section-header--centered">
<span class="bento-label">FAQ</span>
<h2 class="bento-h2">Вопросы о преподавателях</h2>
<p class="bento-p">Как мы знакомим детей с учителями и почему команда годами остаётся стабильной</p>
</div>
<div class="faq-front__list" itemscope itemtype="https://schema.org/FAQPage">
<?php foreach ($faq_items as $i => $fi) : ?>
<details class="faq-front__item" itemscope itemprop="mainEntity" itemtype="https://schema.org/Question" id="teachers-faq-<?php echo esc_attr($i); ?>">
<summary class="faq-front__question" itemprop="name">
<span><?php echo esc_html($fi['q']); ?></span>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
</summary>
<div class="faq-front__answer" itemscope itemprop="acceptedAnswer" itemtype="https://schema.org/Answer">
<div itemprop="text"><?php echo wp_kses_post($fi['a']); ?></div>
</div>
</details>
<?php endforeach; ?>
</div>
</div>
</section>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
<?php foreach ($faq_items as $i => $fi) : ?>
{
"@type": "Question",
"name": <?php echo wp_json_encode($fi['q'], JSON_UNESCAPED_UNICODE); ?>,
"acceptedAnswer": {
"@type": "Answer",
"text": <?php echo wp_json_encode($fi['a'], JSON_UNESCAPED_UNICODE); ?>
}
}<?php echo $i < count($faq_items) - 1 ? ',' : ''; ?>
<?php endforeach; ?>
]
}
</script>

View File

@ -0,0 +1,58 @@
<?php
/**
* Преподаватели фильтр по направлениям
* Фильтры задаются в админке страницы преподавателя (CF teachers_filters).
* JS (page-teachers.js) фильтрует карточки по data-category.
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
$post_id = (int) get_the_ID();
$filters = carbon_get_post_meta($post_id, 'teachers_filters');
$flt_title = carbon_get_post_meta($post_id, 'teachers_filters_title');
if (empty($flt_title)) {
$flt_title = 'Выберите направление';
}
if (empty($filters) || ! is_array($filters)) {
$filters = array();
}
// «Все» — всегда первый фильтр
$filters_list = array(array( 'filter_label' => 'Все преподаватели', 'filter_slug' => 'all' ));
foreach ($filters as $f) {
$label = $f['filter_label'] ?? '';
$slug = $f['filter_slug'] ?? '';
if (! $label || ! $slug) {
continue;
}
$filters_list[] = array( 'filter_label' => $label, 'filter_slug' => $slug );
}
if (count($filters_list) < 2) {
return;
}
?>
<div class="teachers-filter-wrap section-bg reveal" data-bg="teachers-filter">
<div class="container">
<div class="teachers-filter" role="group" aria-label="<?php echo esc_attr($flt_title); ?>">
<span class="teachers-filter__title"><?php echo esc_html($flt_title); ?>:</span>
<div class="teachers-filter__buttons">
<?php foreach ($filters_list as $i => $f) :
$is_active = (0 === $i); ?>
<button type="button"
class="teachers-filter__btn<?php echo $is_active ? ' is-active' : ''; ?>"
data-filter="<?php echo esc_attr($f['filter_slug']); ?>"
aria-pressed="<?php echo $is_active ? 'true' : 'false'; ?>">
<?php echo esc_html($f['filter_label']); ?>
</button>
<?php endforeach; ?>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,111 @@
<?php
/**
* Преподаватели Hero (по образцу главной ds-hero, но краткий)
* Фото: первый преподаватель по дате добавления (без CF).
* Гео-данные: get_option('branch_*') с fallback на site_*.
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
// ─── Гео из филиала ───
$branch_addr = get_option('branch_address') ?: crb_get_theme_option('site_address');
$branch_city = get_option('branch_city') ?: crb_get_theme_option('site_city', 'Щёлково');
$branch_city_prep = get_option('branch_city_prep', 'в Щёлково') ?: 'в Щёлково';
$branch_hours = get_option('branch_work_hours') ?: get_option('branch_hours');
$branch_phone = get_option('branch_phone') ?: crb_get_theme_option('site_phone');
$branch_name = get_option('branch_name') ?: crb_get_theme_option('site_name', 'Декарт');
$phone_clean = $branch_phone ? preg_replace('/[\s\-\\(\)]/', '', $branch_phone) : '';
// ─── Учебный год (автообновление) ───
$current_year = (int) current_time('Y');
$next_year = $current_year + 1;
$school_year = $current_year . '/' . $next_year;
// ─── Фото: первый преподаватель по добавлению ───
$first_teacher = get_posts(array(
'post_type' => 'teacher',
'post_status' => 'publish',
'posts_per_page' => 1,
'orderby' => 'date',
'order' => 'ASC',
'no_found_rows' => true,
));
$hero_photo = '';
$hero_alt = 'Преподаватели школы «' . esc_html($branch_name) . '» ' . esc_html($branch_city);
if (! empty($first_teacher)) {
$first_tid = (int) $first_teacher[0]->ID;
$av_id = carbon_get_post_meta($first_tid, 'teacher_avatar');
if ($av_id) {
$hero_photo = wp_get_attachment_url($av_id);
$alt_meta = get_post_meta($av_id, '_wp_attachment_image_alt', true);
if ($alt_meta) {
$hero_alt = $alt_meta;
}
}
}
// ─── Статистика (кратко) ───
$hero_stats = array(
array( 'num' => '12', 'label' => 'педагогов' ),
array( 'num' => '10+', 'label' => 'лет средний стаж' ),
);
?>
<section class="section-bg ds-hero teachers-hero" data-bg="hero" aria-labelledby="teachers-hero-title">
<div class="ds-container">
<div class="ds-hero__inner">
<div class="ds-hero__content">
<?php if ($branch_addr || $branch_city) : ?>
<div class="ds-hero__address">
<svg aria-hidden="true" width="16" height="16"><use href="#icon-location-pin"/></svg>
<span><?php echo esc_html(trim($branch_addr . ( $branch_addr && $branch_city ? ' — ' : '' ) . $branch_city)); ?></span>
<?php if ($branch_hours) : ?>
<span class="ds-hero__hours-badge"><svg aria-hidden="true" width="16" height="16"><use href="#icon-clock"/></svg> <?php echo esc_html($branch_hours); ?></span>
<?php endif; ?>
</div>
<?php endif; ?>
<h1 id="teachers-hero-title" class="ds-hero__h1">Наши преподаватели</h1>
<p class="ds-hero__subtitle">Команда педагогов школы «<?php echo esc_html($branch_name); ?>» <?php echo esc_html($branch_city_prep); ?>: начальная школа, средняя школа, подготовка к школе, продлёнка и летний лагерь. Средний стаж — от 10 лет. Открыт набор на <span class="ds-hero__year"><?php echo esc_html($school_year); ?></span> учебный год.</p>
<button class="ds-hero__cta-btn btn-write open-bitrix-form">
Записаться на экскурсию
</button>
<noscript>
<div class="ds-hero__cta-fallback">
Позвоните: <a href="tel:<?php echo esc_attr($phone_clean ?: '+74951206699'); ?>"><?php echo esc_html($branch_phone ?: '+7 (495) 120-66-99'); ?></a>
</div>
</noscript>
<div class="ds-hero__assurance">
<span class="ds-hero__assurance-item">Познакомитесь с учителями лично</span>
<span class="ds-hero__assurance-item">Зададите вопросы напрямую</span>
</div>
</div>
<div class="ds-hero__visual">
<?php if ($hero_photo) : ?>
<div class="ds-hero__photo-wrap">
<div class="ds-hero__photo-frame">
<img class="ds-hero__photo"
src="<?php echo esc_url($hero_photo); ?>"
alt="<?php echo esc_attr($hero_alt); ?>"
loading="eager" decoding="async"
width="600" height="600">
</div>
<div class="ds-hero__photo-ring" aria-hidden="true"></div>
</div>
<?php endif; ?>
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,33 @@
<?php
/**
* Преподаватели вводный блок (SEO + позиционирование)
* H1 берётся из баннера (banner_h1), здесь H2 с гео-ключом + текст.
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
$post_id = (int) get_the_ID();
$intro_title = carbon_get_post_meta($post_id, 'teachers_intro_title');
if (empty($intro_title)) {
$intro_title = 'Преподаватели школы «Декарт» в Щёлково';
}
$intro_text = carbon_get_post_meta($post_id, 'teachers_intro_text');
if (empty($intro_text)) {
return;
}
?>
<section class="teachers-intro section-bg reveal" data-bg="teachers-intro" aria-labelledby="teachers-intro-title">
<div class="container">
<div class="section-header--left">
<h2 id="teachers-intro-title" class="bento-h2"><?php echo esc_html($intro_title); ?></h2>
<p class="bento-p"><?php echo esc_html($intro_text); ?></p>
</div>
</div>
</section>

View File

@ -0,0 +1,108 @@
<?php
/**
* Преподаватели Schema.org: EducationalOrganization + Person[]
* Person: имя, url, jobTitle (направление), image, worksFor, description,
* alumniOf/education, knowsAbout, опционально review (rating).
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
$org_name = get_option('branch_name') ?: carbon_get_theme_option('site_name') ?: 'Частная школа «Декарт»';
$org_url = home_url('/');
$org_logo = carbon_get_theme_option('logo') ? wp_get_attachment_url(carbon_get_theme_option('logo')) : '';
$org_addr = get_option('branch_address') ?: carbon_get_theme_option('site_address') ?: '';
$org_phone = get_option('branch_phone') ?: carbon_get_theme_option('site_phone') ?: '';
// ─── Ответственные лица для schema (CF на странице можно добавить позже) ───
$founder_name = get_option('branch_head_name', '');
$head_q = get_option('branch_head_position', 'Учредитель школы «Декарт»');
$teachers_schema = array();
// Руководитель (если задан) — как Person/Founder внутри организации
if ($founder_name) {
$teachers_schema[] = array(
'@type' => 'Person',
'name' => $founder_name,
'jobTitle' => $head_q ?: 'Учредитель школы «Декарт»',
'worksFor' => array( '@type' => 'EducationalOrganization', 'name' => $org_name ),
);
}
// Педагоги из CPT teacher
$schema_args = array(
'posts_per_page' => -1,
'post_type' => 'teacher',
'post_status' => 'publish',
'orderby' => 'date',
'order' => 'ASC',
'no_found_rows' => true,
'update_post_meta_cache' => true,
);
$schema_teachers = get_posts($schema_args);
foreach ($schema_teachers as $st) {
$tid = (int) $st->ID;
$subj = carbon_get_post_meta($tid, 'teacher_direction');
$ed = carbon_get_post_meta($tid, 'teacher_education');
$img = carbon_get_post_meta($tid, 'teacher_avatar');
// Чистый текст, обрезанный для schema description
$schema_desc = '';
if ($ed) {
$schema_desc = wp_strip_all_tags($ed);
$schema_desc = preg_replace('/\s+/u', ' ', $schema_desc);
$schema_desc = trim($schema_desc);
if (mb_strlen($schema_desc) > 200) {
$schema_desc = mb_substr($schema_desc, 0, 197) . '…';
}
}
$person = array(
'@type' => 'Person',
'name' => get_the_title($tid),
'url' => get_permalink($tid),
'jobTitle' => $subj ?: 'Преподаватель',
'worksFor' => array( '@type' => 'EducationalOrganization', 'name' => $org_name ),
'description' => $schema_desc,
);
if ($img && wp_get_attachment_url($img)) {
$person['image'] = wp_get_attachment_url($img);
}
$teachers_schema[] = $person;
}
if (empty($teachers_schema)) {
return;
}
$org_schema = array(
'@type' => 'EducationalOrganization',
'name' => $org_name,
'url' => $org_url,
);
if ($org_logo) {
$org_schema['logo'] = $org_logo;
}
if ($org_addr) {
$org_schema['address'] = $org_addr;
}
if ($org_phone) {
$org_schema['telephone'] = $org_phone;
}
$org_schema['employee'] = $teachers_schema;
?>
<script type="application/ld+json">
<?php echo wp_json_encode(
array(
'@context' => 'https://schema.org',
'@graph' => array( $org_schema ),
),
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT
); ?>
</script>

View File

@ -0,0 +1,46 @@
<?php
/**
* Преподаватели блок доверия / цифры
* CF teachers_trust (complex: number + label). Показывается если есть данные.
*
* @package Dekart
*/
if (! defined('ABSPATH')) {
exit;
}
$post_id = (int) get_the_ID();
$trust = carbon_get_post_meta($post_id, 'teachers_trust');
if (empty($trust) || ! is_array($trust)) {
return;
}
$trust_items = array();
foreach ($trust as $t) {
$num = $t['trust_number'] ?? '';
$label = $t['trust_label'] ?? '';
if (! $num || ! $label) {
continue;
}
$trust_items[] = array( 'num' => $num, 'label' => $label );
}
if (empty($trust_items)) {
return;
}
?>
<section class="teachers-trust section-bg reveal" data-bg="teachers-trust" aria-label="Цифры о преподавателях">
<div class="container">
<div class="teachers-trust__grid">
<?php foreach ($trust_items as $ti) : ?>
<div class="teachers-trust__item">
<div class="teachers-trust__number"><?php echo esc_html($ti['num']); ?></div>
<div class="teachers-trust__label"><?php echo esc_html($ti['label']); ?></div>
</div>
<?php endforeach; ?>
</div>
</div>
</section>