1079 lines
58 KiB
PHP
1079 lines
58 KiB
PHP
<?php
|
||
/**
|
||
* Личная страница преподавателя (Bento 2026).
|
||
*
|
||
* Данные — из CF карточки преподавателя. Общие части: reviews-link,
|
||
* teachers-cards, contacts, author-eaat. Sticky-CTA на мобильном.
|
||
*
|
||
* @package Dekart
|
||
*/
|
||
|
||
if (! defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
// og:image:alt из featured image (паттерн page-camp.php)
|
||
add_action('wp_head', function () {
|
||
if (! is_singular('teacher')) {
|
||
return;
|
||
}
|
||
$thumb_id = get_post_thumbnail_id(get_queried_object_id());
|
||
if ($thumb_id) {
|
||
$alt = get_post_meta($thumb_id, '_wp_attachment_image_alt', true);
|
||
if ($alt) {
|
||
echo '<meta property="og:image:alt" content="' . esc_attr($alt) . '" />' . "\n";
|
||
}
|
||
}
|
||
}, 1);
|
||
|
||
get_header();
|
||
|
||
$tid = (int) get_the_ID();
|
||
$full_name = get_the_title($tid);
|
||
|
||
// ─── Гео / контакты филиала ───
|
||
$branch_phone = get_option('branch_phone') ?: carbon_get_theme_option('site_phone');
|
||
$branch_city = get_option('branch_city') ?: carbon_get_theme_option('site_city', 'Щёлково');
|
||
$branch_city_prep = get_option('branch_city_prep', 'в Щёлково') ?: 'в Щёлково';
|
||
$branch_name = get_option('branch_name') ?: carbon_get_theme_option('site_name', 'Декарт');
|
||
// Тел.: цифры и «+». WhatsApp: 8-XXXXXXXXXX → 7-XXXXXXXXXX, без номера — без ссылки.
|
||
$phone_clean = $branch_phone ? preg_replace('/[^0-9+]/', '', $branch_phone) : '';
|
||
$wa_on = (bool) get_option('branch_messenger_whatsapp_on', 1);
|
||
$wa_number = '';
|
||
if ($wa_on) {
|
||
$wa_number = trim((string) get_option('branch_messenger_whatsapp'));
|
||
if (false !== strpos($wa_number, 'wa.me/')) {
|
||
$wa_number = substr($wa_number, strpos($wa_number, 'wa.me/') + 6);
|
||
}
|
||
$wa_number = preg_replace('/[^0-9]/', '', $wa_number);
|
||
if ('' !== $wa_number && '8' === $wa_number[0] && 11 === strlen($wa_number)) {
|
||
$wa_number = '7' . substr($wa_number, 1);
|
||
}
|
||
}
|
||
// Фолбэк: телефон филиала.
|
||
if ('' === $wa_number && $phone_clean) {
|
||
$wa_number = preg_replace('/[^0-9]/', '', $phone_clean);
|
||
if ('8' === $wa_number[0] && 11 === strlen($wa_number)) {
|
||
$wa_number = '7' . substr($wa_number, 1);
|
||
}
|
||
}
|
||
$wa_url = ('' !== $wa_number) ? 'https://wa.me/' . $wa_number : '';
|
||
|
||
// ─── Профиль преподавателя (CF) ───
|
||
$direction = carbon_get_post_meta($tid, 'teacher_direction');
|
||
$subj = $direction;
|
||
$badge = carbon_get_post_meta($tid, 'teacher_badge');
|
||
$rating = carbon_get_post_meta($tid, 'teacher_rating');
|
||
$rating_num = is_numeric($rating) ? (float) $rating : 0.0;
|
||
$start_year = carbon_get_post_meta($tid, 'teacher_start_year');
|
||
$tenure = '';
|
||
if ($start_year && absint($start_year) > 1900) {
|
||
$tenure = max(0, (int) current_time('Y') - (int) $start_year);
|
||
}
|
||
$avatar_id = carbon_get_post_meta($tid, 'teacher_avatar');
|
||
$avatar_url = $avatar_id ? wp_get_attachment_url($avatar_id) : ''; // Schema Person.image
|
||
$avatar_alt = $avatar_id ? get_post_meta($avatar_id, '_wp_attachment_image_alt', true) : '';
|
||
if (empty($avatar_alt)) {
|
||
$avatar_alt = 'Преподаватель ' . $full_name . ' — школа «' . $branch_name . '» ' . $branch_city;
|
||
}
|
||
// image() = проверка наличия + готовый HTML, без отдельного url-запроса.
|
||
$avatar_img = $avatar_id ? wp_get_attachment_image(
|
||
(int) $avatar_id,
|
||
array( 600, 600 ),
|
||
false,
|
||
array(
|
||
'class' => 'ds-hero__photo',
|
||
'alt' => $avatar_alt,
|
||
'loading' => 'eager',
|
||
'decoding' => 'async',
|
||
'fetchpriority' => 'high', // LCP-изображение
|
||
)
|
||
) : '';
|
||
|
||
$avg_score = carbon_get_post_meta($tid, 'teacher_avg_score');
|
||
$seats_left = carbon_get_post_meta($tid, 'teacher_seats_left');
|
||
$group_size = carbon_get_post_meta($tid, 'teacher_group_size') ?: '2-6';
|
||
$avg_label = carbon_get_post_meta($tid, 'teacher_avg_label');
|
||
if (empty($avg_label)) {
|
||
$avg_label = 'Средний балл учеников';
|
||
}
|
||
$exam_label = carbon_get_post_meta($tid, 'teacher_exam_label') ?: 'нового набора';
|
||
$cta_primary = carbon_get_post_meta($tid, 'teacher_cta_primary') ?: 'Записаться на диагностику';
|
||
$sched_label = carbon_get_post_meta($tid, 'teacher_schedule_label') ?: 'Посмотреть расписание групп';
|
||
$sched_url = carbon_get_post_meta($tid, 'teacher_schedule_url');
|
||
$risk_note = carbon_get_post_meta($tid, 'teacher_risk_note');
|
||
if (empty($risk_note)) {
|
||
$risk_note = 'Перезвоним за 15 минут · Без обязательств';
|
||
}
|
||
$school_num = carbon_get_post_meta($tid, 'teacher_school_num');
|
||
$school_label = carbon_get_post_meta($tid, 'teacher_school_label');
|
||
if (empty($school_label)) {
|
||
$school_label = 'учеников продолжают обучение на следующий учебный год';
|
||
}
|
||
$exam_date = carbon_get_post_meta($tid, 'teacher_exam_date');
|
||
$scarcity_note = carbon_get_post_meta($tid, 'teacher_scarcity_note');
|
||
if (empty($scarcity_note)) {
|
||
$scarcity_note = 'Набор в группу идёт каждый месяц, но места ограничены.';
|
||
}
|
||
|
||
$about_text = carbon_get_post_meta($tid, 'teacher_about');
|
||
$education = carbon_get_post_meta($tid, 'teacher_education');
|
||
$add_education = carbon_get_post_meta($tid, 'teacher_add_education');
|
||
$video_html = carbon_get_post_meta($tid, 'teacher_video');
|
||
// Ссылка VK/YouTube → iframe. Пусто → блок скрыт.
|
||
if ($video_html && 0 !== strpos(ltrim($video_html), '<')) {
|
||
$video_url = trim($video_html);
|
||
if (preg_match('~vk\.com/video(-?\d+)_(\d+)~', $video_url, $vm)) {
|
||
$video_html = '<iframe src="https://vk.com/video_ext.php?oid=' . esc_attr($vm[1]) . '&id=' . esc_attr($vm[2]) . '&hd=2" width="853" height="480" allow="autoplay; encrypted-media; fullscreen; picture-in-picture;" frameborder="0" allowfullscreen></iframe>';
|
||
} elseif (preg_match('~(?:youtube\.com/(?:watch\?v=|embed/)|youtu\.be/)([\w-]{6,})~', $video_url, $ym)) {
|
||
$video_html = '<iframe src="https://www.youtube.com/embed/' . esc_attr($ym[1]) . '" width="853" height="480" allow="autoplay; encrypted-media; fullscreen; picture-in-picture;" frameborder="0" allowfullscreen></iframe>';
|
||
}
|
||
}
|
||
$license = carbon_get_post_meta($tid, 'teacher_license');
|
||
if (empty($license)) {
|
||
$license = 'Частная школа «' . $branch_name . '» работает по лицензии на образовательную деятельность (бессрочная). Копия лицензии и реквизиты — по запросу у администратора.';
|
||
}
|
||
|
||
// Счётчик реальных отзывов.
|
||
$review_count = function_exists('dekart_teacher_review_count') ? dekart_teacher_review_count($tid) : 0;
|
||
|
||
// Подзаголовок hero — из админки (вкладка Hero); пусто — авто-сборка.
|
||
$hero_subtitle = trim((string) carbon_get_post_meta($tid, 'teacher_hero_subtitle'));
|
||
if ('' === $hero_subtitle) {
|
||
$hero_subtitle = ( $subj ? $subj : 'Обучение' ) . ' — мини-группы ' . $group_size . ' чел. · ' . $exam_label . ' · школа «' . $branch_name . '» ' . $branch_city_prep;
|
||
}
|
||
|
||
// ─── Шаги «Как проходит первое занятие» ───
|
||
$steps = (array) carbon_get_post_meta($tid, 'teacher_steps');
|
||
if (empty($steps) || ! is_array($steps)) {
|
||
$steps = array(
|
||
array( 'step_title' => 'Заявка', 'step_text' => 'Оставляете заявку — администратор перезванивает за 15 минут и отвечает на вопросы.' ),
|
||
array( 'step_title' => 'Бесплатная диагностика (30 мин)', 'step_text' => 'Определяем уровень знаний и разбираем «слабые места».' ),
|
||
array( 'step_title' => 'Подбор группы по уровню', 'step_text' => 'Подбираем мини-группу 2–6 человек под уровень ребёнка.' ),
|
||
array( 'step_title' => 'Первое занятие', 'step_text' => 'Знакомство с преподавателем и форматом. Ребёнок пробует — вы решаете.' ),
|
||
array( 'step_title' => 'Обратная связь родителю', 'step_text' => 'После каждого занятия — короткий отчёт: что прошли, что получается.' ),
|
||
);
|
||
}
|
||
|
||
// ─── Сегменты «Для кого» ───
|
||
$segments = (array) carbon_get_post_meta($tid, 'teacher_segments');
|
||
if (empty($segments) || ! is_array($segments)) {
|
||
$segments = array(
|
||
array( 'segment_title' => 'Начинаете заниматься', 'segment_text' => 'Системные занятия: объясняем материал, закрепляем на практике, проверяем понимание. Без стресса и зубрёжки.' ),
|
||
array( 'segment_title' => 'Отстали по программе', 'segment_text' => 'Закрываем пробелы и возвращаем уверенность. Маленькая группа — каждому хватает внимания.' ),
|
||
array( 'segment_title' => 'Хотите больше школьной программы', 'segment_text' => 'Углубляем знания, учим думать, а не запоминать. Мини-группа держит темп и азарт.' ),
|
||
);
|
||
}
|
||
$segment_4_title = 'Уже занимались с репетитором, но нет результата?';
|
||
$segment_4_text = 'Частая ситуация: деньги потрачены, а результата нет. В мини-группе другой механизм — соревнование, методика и куратор. Приходите на бесплатную диагностику и сравните сами.';
|
||
|
||
// ─── Кейсы (табы) ───
|
||
$cases = (array) carbon_get_post_meta($tid, 'teacher_cases');
|
||
|
||
// ─── FAQ: формат + общие вопросы ───
|
||
$faq_extra = (array) carbon_get_post_meta($tid, 'teacher_faq_extra');
|
||
$faq_items = array();
|
||
if (empty($faq_extra)) {
|
||
$faq_items[] = array(
|
||
'q' => 'Чем мини-группа лучше репетитора?',
|
||
'a' => 'В мини-группе 2–6 человек преподаватель видит каждого, но у детей появляется азарт, здоровая конкуренция и живое обсуждение. Стоимость ниже репетитора, а дисциплина выше — пропускать занятия не хочется.',
|
||
);
|
||
$faq_items[] = array(
|
||
'q' => 'Что если ребёнок стесняется заниматься с другими?',
|
||
'a' => 'Начинаем с диагностики и подбираем группу по уровню и темпераменту. Первые занятия преподаватель мягко вовлекает ребёнка — обычно через 2–3 занятия стеснение уходит.',
|
||
);
|
||
} else {
|
||
foreach ($faq_extra as $fx) {
|
||
if (! empty($fx['faq_q']) && ! empty($fx['faq_a'])) {
|
||
$faq_items[] = array( 'q' => $fx['faq_q'], 'a' => $fx['faq_a'] );
|
||
}
|
||
}
|
||
}
|
||
$legacy_questions = (array) carbon_get_post_meta($tid, 'questions');
|
||
foreach ($legacy_questions as $lq) {
|
||
if (! empty($lq['questions_question']) && ! empty($lq['questions_answer'])) {
|
||
$faq_items[] = array( 'q' => $lq['questions_question'], 'a' => $lq['questions_answer'] );
|
||
}
|
||
}
|
||
|
||
// ─── Дни до экзамена (полоса дефицита) ───
|
||
// «Сегодня» = 0, «завтра» = 1; прошедшая дата → блок скрыт.
|
||
$days_left = '';
|
||
if ($exam_date && preg_match('/^\d{4}-\d{2}-\d{2}$/', $exam_date)) {
|
||
$tz = wp_timezone();
|
||
$exam_ts = (int) ( new DateTime($exam_date, $tz) )->format('U');
|
||
$today_ts = (int) ( new DateTime('now', $tz) )->setTime(0, 0)->format('U');
|
||
$diff = (int) round( ( $exam_ts - $today_ts ) / DAY_IN_SECONDS );
|
||
if ($diff >= 0) {
|
||
$days_left = (string) $diff;
|
||
}
|
||
}
|
||
|
||
// ─── Микроразметка (единый @graph) ───
|
||
// Пустые свойства не выводим (Google ругается на пустые обязательные поля).
|
||
$teachers_page = get_page_by_path('our-teachers');
|
||
|
||
$page_url = get_permalink($tid);
|
||
$org_id = home_url('/') . '#org';
|
||
$person_id = $page_url . '#person';
|
||
|
||
$org_logo = '';
|
||
$branch_logo_id = absint(get_option('branch_logo'));
|
||
if ($branch_logo_id) {
|
||
$org_logo = wp_get_attachment_url($branch_logo_id);
|
||
}
|
||
if (! $org_logo && carbon_get_theme_option('site_logo')) {
|
||
$org_logo = wp_get_attachment_url(carbon_get_theme_option('site_logo'));
|
||
}
|
||
|
||
$branch_email = get_option('branch_email') ?: carbon_get_theme_option('site_email');
|
||
|
||
// ── EducationalOrganization ──
|
||
$org = array(
|
||
'@type' => 'EducationalOrganization',
|
||
'@id' => $org_id,
|
||
'name' => $branch_name,
|
||
'url' => home_url('/'),
|
||
);
|
||
if ($org_logo) {
|
||
$org['logo'] = $org_logo;
|
||
}
|
||
if ($branch_phone) {
|
||
$org['telephone'] = $branch_phone;
|
||
}
|
||
if ($branch_email) {
|
||
$org['email'] = $branch_email;
|
||
}
|
||
|
||
// Адрес филиала: branch_* → фолбэк site_*.
|
||
$org_addr = array();
|
||
$org_street = get_option('branch_address') ?: carbon_get_theme_option('site_address');
|
||
$org_city = get_option('branch_city') ?: carbon_get_theme_option('site_city');
|
||
$org_region = get_option('branch_region') ?: '';
|
||
$org_zip = get_option('branch_postal_code') ?: get_option('branch_zip') ?: '';
|
||
if (! empty($org_street)) { $org_addr['streetAddress'] = $org_street; }
|
||
if (! empty($org_city)) { $org_addr['addressLocality'] = $org_city; }
|
||
if (! empty($org_region)) { $org_addr['addressRegion'] = $org_region; }
|
||
if (! empty($org_zip)) { $org_addr['postalCode'] = $org_zip; }
|
||
if (! empty($org_addr)) {
|
||
$org_addr = array_merge(array('@type' => 'PostalAddress', 'addressCountry' => 'RU'), $org_addr);
|
||
$org['address'] = $org_addr;
|
||
}
|
||
|
||
// Лицензия — из настроек филиала.
|
||
$org_license = get_option('branch_license') ?: carbon_get_theme_option('site_license');
|
||
if (! empty($org_license)) {
|
||
$org['hasCredential'] = array(
|
||
'@type' => 'EducationalOccupationalCredential',
|
||
'name' => $org_license,
|
||
);
|
||
}
|
||
|
||
// ── Person (преподаватель) ──
|
||
// Каталог программ филиала: название → url/price (цена — только для Course.offers в микроразметке).
|
||
$branch_programs_by_name = array();
|
||
foreach ((array) get_option('branch_programs', array()) as $bp) {
|
||
$pn = trim((string) ( $bp['name'] ?? '' ));
|
||
if ('' !== $pn) {
|
||
$branch_programs_by_name[ $pn ] = array(
|
||
'price' => trim((string) ( $bp['price'] ?? '' )),
|
||
'url' => trim((string) ( $bp['url'] ?? '' )),
|
||
);
|
||
}
|
||
}
|
||
|
||
// Предметы: title → курс; topics → чипы. URL/цена — из каталога филиала (fallback — CF преподавателя).
|
||
$teacher_subjects = (array) carbon_get_post_meta($tid, 'teacher_subjects');
|
||
$subject_items = array(); // [title => ['name', 'url', 'price', 'topics[]']] без дубликатов
|
||
foreach ($teacher_subjects as $ts) {
|
||
$sn = trim((string) ( $ts['teacher_subjects_title'] ?? '' ));
|
||
if ('' === $sn) {
|
||
continue;
|
||
}
|
||
if (isset($subject_items[$sn])) {
|
||
continue; // дубликат заголовка — пропускаем
|
||
}
|
||
$topics = array();
|
||
$topics_raw = trim((string) ( $ts['teacher_subjects_topics'] ?? '' ));
|
||
if ('' !== $topics_raw) {
|
||
foreach (preg_split('/\r\n|\r|\n/', $topics_raw) as $tp) {
|
||
$tp = trim($tp);
|
||
if ('' !== $tp) {
|
||
$topics[] = $tp;
|
||
}
|
||
}
|
||
}
|
||
$prog = $branch_programs_by_name[ $sn ] ?? null;
|
||
$subject_items[$sn] = array(
|
||
'name' => $sn,
|
||
'url' => ( $prog && '' !== $prog['url'] ) ? $prog['url'] : trim((string) ( $ts['teacher_subjects_url'] ?? '' )),
|
||
'price' => ( $prog && '' !== $prog['price'] ) ? $prog['price'] : '',
|
||
'topics' => $topics,
|
||
);
|
||
}
|
||
$subject_names = array_keys($subject_items);
|
||
|
||
// ─── Общие данные из настроек филиала (не дублируются в CF преподавателя) ───
|
||
$branch_price = get_option('branch_price');
|
||
$branch_geo_areas = get_option('branch_area_served');
|
||
$geo_walk = get_option('branch_logistics_walk');
|
||
$geo_parking = get_option('branch_logistics_parking');
|
||
$geo_schools = get_option('branch_logistics_schools');
|
||
|
||
// ─── Результаты учеников: CF или авто-сборка ───
|
||
$cf_results = carbon_get_post_meta($tid, 'teacher_results');
|
||
$results = array();
|
||
if (is_array($cf_results) && ! empty($cf_results)) {
|
||
$results = array_values($cf_results);
|
||
} else {
|
||
if (! empty($school_num)) { $results[] = array( 'result_title' => (string) $school_num, 'result_text' => $school_label ); }
|
||
if ($avg_score) { $results[] = array( 'result_title' => $avg_score, 'result_text' => $avg_label ); }
|
||
if ($tenure) { $results[] = array( 'result_title' => $tenure . ' лет', 'result_text' => 'педагогический стаж преподавателя' ); }
|
||
if ($review_count > 0) { $results[] = array( 'result_title' => (string) $review_count, 'result_text' => 'реальных отзывов родителей о преподавателе' ); }
|
||
}
|
||
|
||
$person = array(
|
||
'@type' => 'Person',
|
||
'@id' => $person_id,
|
||
'name' => $full_name,
|
||
'url' => $page_url,
|
||
'worksFor' => array('@id' => $org_id),
|
||
);
|
||
if ($direction) {
|
||
$person['jobTitle'] = $direction;
|
||
}
|
||
if ($avatar_url) {
|
||
$person['image'] = $avatar_url;
|
||
}
|
||
if ($about_text) {
|
||
$person['description'] = wp_strip_all_tags($about_text);
|
||
}
|
||
if (! empty($subject_names)) {
|
||
$person['knowsAbout'] = $subject_names;
|
||
}
|
||
$diploma = trim((string) carbon_get_post_meta($tid, 'teacher_diploma'));
|
||
if ('' !== $diploma) {
|
||
$person['alumniOf'] = array('@type' => 'CollegeOrUniversity', 'name' => $diploma);
|
||
}
|
||
|
||
// ── Рейтинг преподавателя ──
|
||
// Среднее реальных отзывов (SQL-агрегат); CF teacher_rating — фолбэк, когда отзывов нет.
|
||
$sp_avg_num = function_exists('dekart_teacher_review_avg')
|
||
? (float) dekart_teacher_review_avg($tid)
|
||
: 0.0;
|
||
$sp_avg = $sp_avg_num > 0 ? number_format($sp_avg_num, 1, '.', '') : '';
|
||
$rating_num = $sp_avg_num > 0 ? $sp_avg_num : ( is_numeric($rating) ? (float) $rating : 0.0 );
|
||
|
||
// AggregateRating не размечаем: невалиден для Person в schema.org, Google не даёт
|
||
// по нему rich results. Средний балл — только UI; в Schema — отдельные Review с reviewRating.
|
||
|
||
// Review не размечаем: Google не поддерживает Person среди itemReviewed для review
|
||
// rich results. Отзывы остаются в видимом HTML (reviews-link) — там их место.
|
||
|
||
// ── Course — по каждому предмету (предмет + мини-группа) ──
|
||
// Person и Org объявляются один раз (@id); в курсах — ссылки.
|
||
$build_course = function ( $name, $cid, $availability = null, $description = '', $price = '' ) use ( $page_url, $org_id, $person_id, $group_size, $full_name, $branch_price ) {
|
||
$course = array(
|
||
'@type' => 'Course',
|
||
'@id' => $page_url . '#course-' . $cid,
|
||
'name' => $name,
|
||
'description' => ( '' !== $description )
|
||
? $description
|
||
: 'Курс «' . $name . '» в мини-группе ' . $group_size . ' человек. Преподаватель — ' . $full_name . '.',
|
||
'provider' => array('@id' => $org_id),
|
||
'hasCourseInstance' => array(
|
||
'@type' => 'CourseInstance',
|
||
'courseMode' => 'Onsite',
|
||
'instructor' => array('@id' => $person_id),
|
||
),
|
||
'offers' => array(
|
||
'@type' => 'Offer',
|
||
'category' => 'Мини-группа 2–' . $group_size . ' человек',
|
||
),
|
||
);
|
||
// Цена — только микроразметка: из каталога программы → фолбэк branch_price;
|
||
// Schema требует число — извлекаем из строки вида «от 1 290 ₽».
|
||
$offer_price = ( '' !== (string) $price ) ? $price : $branch_price;
|
||
$offer_price_norm = preg_replace('/\s+/u', '', (string) $offer_price);
|
||
if (preg_match('/\d+(?:[.,]\d+)?/', $offer_price_norm, $pm)) {
|
||
$course['offers']['price'] = str_replace(',', '.', $pm[0]);
|
||
$course['offers']['priceCurrency'] = 'RUB';
|
||
}
|
||
if (null !== $availability) {
|
||
$course['offers']['availability'] = $availability;
|
||
}
|
||
return $course;
|
||
};
|
||
|
||
$courses = array();
|
||
if (! empty($subject_names)) {
|
||
foreach ($subject_names as $i => $cn) {
|
||
// Availability: >0 → Limited, =0 → SoldOut, пусто → не указываем.
|
||
$availability = null;
|
||
if ('' !== (string) $seats_left) {
|
||
$availability = ( (int) $seats_left > 0 )
|
||
? 'https://schema.org/LimitedAvailability'
|
||
: 'https://schema.org/SoldOut';
|
||
}
|
||
$courses[] = $build_course($cn, $i + 1, $availability, '', $subject_items[$cn]['price']);
|
||
}
|
||
} else {
|
||
$courses[] = $build_course( ( $subj ? $subj : 'Обучение' ) . ' — мини-группы ' . $group_size . ' чел.', 1 );
|
||
}
|
||
|
||
// ── FAQPage ──
|
||
$schema_faq = array();
|
||
foreach ($faq_items as $fq) {
|
||
$schema_faq[] = array(
|
||
'@type' => 'Question',
|
||
'name' => $fq['q'],
|
||
'acceptedAnswer' => array('@type' => 'Answer', 'text' => $fq['a']),
|
||
);
|
||
}
|
||
|
||
// ── BreadcrumbList ──
|
||
$crumb_parents = array(array('name' => 'Главная', 'url' => home_url('/')));
|
||
if ($teachers_page) {
|
||
$crumb_parents[] = array('name' => 'Преподаватели', 'url' => get_permalink($teachers_page));
|
||
}
|
||
$crumb_parents[] = array('name' => $full_name);
|
||
$breadcrumbs = array();
|
||
foreach ($crumb_parents as $i => $p) {
|
||
$item = array('@type' => 'ListItem', 'position' => $i + 1, 'name' => $p['name']);
|
||
if (! empty($p['url'])) {
|
||
$item['item'] = $p['url'];
|
||
}
|
||
$breadcrumbs[] = $item;
|
||
}
|
||
|
||
// ── @graph ──
|
||
$org['employee'] = array(array('@id' => $person_id));
|
||
$schema_graph = array($org, $person);
|
||
foreach ($courses as $c) {
|
||
$schema_graph[] = $c;
|
||
}
|
||
if (! empty($schema_faq)) {
|
||
$schema_graph[] = array('@type' => 'FAQPage', 'mainEntity' => $schema_faq);
|
||
}
|
||
$schema_graph[] = array('@type' => 'BreadcrumbList', 'itemListElement' => $breadcrumbs);
|
||
?>
|
||
<main class="teacher-single">
|
||
<?php get_template_part('template-parts/svg-sprite'); ?>
|
||
|
||
<?php
|
||
// ─────────────────────────── HERO ───────────────────────────
|
||
?>
|
||
<section class="section-bg ds-hero teacher-single__hero" data-bg="hero" aria-labelledby="teacher-single-title">
|
||
<div class="ds-container">
|
||
<div class="ds-hero__inner">
|
||
|
||
<div class="ds-hero__content">
|
||
|
||
<nav class="ds-breadcrumbs teacher-single__breadcrumbs" aria-label="Хлебные крошки" itemscope itemtype="https://schema.org/BreadcrumbList">
|
||
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
|
||
<a itemprop="item" href="<?php echo esc_url(home_url('/')); ?>"><span itemprop="name">Главная</span></a>
|
||
<meta itemprop="position" content="1">
|
||
</span>
|
||
<span aria-hidden="true">/</span>
|
||
<?php if ($teachers_page) : ?>
|
||
<span itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
|
||
<a itemprop="item" href="<?php echo esc_url(get_permalink($teachers_page)); ?>"><span itemprop="name">Преподаватели</span></a>
|
||
<meta itemprop="position" content="2">
|
||
</span>
|
||
<span aria-hidden="true">/</span>
|
||
<?php endif; ?>
|
||
<span class="ds-breadcrumbs__current" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
|
||
<span itemprop="name"><?php echo esc_html($full_name); ?></span>
|
||
<meta itemprop="position" content="3">
|
||
</span>
|
||
</nav>
|
||
|
||
<?php if ($badge) : ?>
|
||
<span class="teacher-single__badge"><?php echo esc_html($badge); ?></span>
|
||
<?php endif; ?>
|
||
|
||
<h1 id="teacher-single-title" class="ds-hero__h1 teacher-single__h1"><?php echo esc_html($full_name); ?></h1>
|
||
|
||
<?php if ($hero_subtitle) : ?>
|
||
<p class="ds-hero__subtitle teacher-single__subtitle">
|
||
<?php echo esc_html($hero_subtitle); ?>
|
||
</p>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($rating_num > 0 || $tenure) : ?>
|
||
<div class="teacher-single__hero-facts">
|
||
<?php if ($rating_num > 0) : ?>
|
||
<span class="teacher-single__hero-fact">
|
||
<span class="teacher-single__stars" aria-hidden="true">
|
||
<?php for ($s = 1; $s <= 5; $s++) : ?>
|
||
<svg class="<?php echo $s <= round($rating_num) ? 'is-filled' : ''; ?>" width="16" height="16" viewBox="0 0 20 20" fill="currentColor"><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>
|
||
<?php echo esc_html(rtrim(rtrim(number_format($rating_num, 1), '0'), '.')); ?>
|
||
<?php if ($review_count > 0) : ?><span class="teacher-single__hero-rating-count">(<?php echo esc_html($review_count); ?>)</span><?php endif; ?>
|
||
</span>
|
||
<?php endif; ?>
|
||
<?php if ($tenure) : ?>
|
||
<span class="teacher-single__hero-fact">Стаж — <?php echo esc_html($tenure); ?> лет</span>
|
||
<?php endif; ?>
|
||
<span class="teacher-single__hero-fact">Мини-группа <?php echo esc_html($group_size); ?> чел.</span>
|
||
</div>
|
||
<?php endif; ?>
|
||
|
||
<div class="teacher-single__hero-cta">
|
||
<button type="button" class="teacher-single__btn teacher-single__btn--primary btn-write open-bitrix-form">
|
||
<?php echo esc_html($cta_primary); ?>
|
||
</button>
|
||
<?php if ($sched_url) : ?>
|
||
<a class="teacher-single__btn teacher-single__btn--ghost" href="<?php echo esc_url($sched_url); ?>">
|
||
<?php echo esc_html($sched_label); ?>
|
||
</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
<p class="teacher-single__risk-note"><?php echo esc_html($risk_note); ?></p>
|
||
<noscript>
|
||
<p 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></p>
|
||
</noscript>
|
||
</div>
|
||
|
||
<div class="ds-hero__visual teacher-single__visual">
|
||
<?php if ($avatar_img) : ?>
|
||
<div class="ds-hero__photo-wrap">
|
||
<div class="ds-hero__photo-frame teacher-single__photo-frame">
|
||
<?php echo $avatar_img; ?>
|
||
</div>
|
||
<div class="ds-hero__photo-ring" aria-hidden="true"></div>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<?php
|
||
// ─────────────────── ЦИФРЫ ───────────────────
|
||
// Карточки — только из CF complex teacher_metrics; пусто — секция скрыта.
|
||
$metrics = array();
|
||
$metric_cards = (array) carbon_get_post_meta($tid, 'teacher_metrics');
|
||
if (! empty($metric_cards) && is_array($metric_cards)) {
|
||
foreach ($metric_cards as $mc) {
|
||
$mn = trim((string) ( $mc['metric_num'] ?? '' ));
|
||
if ('' === $mn) {
|
||
continue;
|
||
}
|
||
$metrics[] = array(
|
||
'num' => $mn,
|
||
'label' => trim((string) ( $mc['metric_text'] ?? '' )),
|
||
);
|
||
}
|
||
}
|
||
if (! empty($metrics)) :
|
||
?>
|
||
<section class="teacher-single__metrics section-bg reveal" data-bg="teacher-metrics" aria-label="Цифры">
|
||
<div class="container">
|
||
<div class="teacher-single__metrics-grid<?php echo count($metrics) < 3 ? ' is-few' : ''; ?>">
|
||
<?php foreach ($metrics as $m) : ?>
|
||
<div class="teacher-single__metric">
|
||
<div class="teacher-single__metric-num"><?php echo esc_html($m['num']); ?></div>
|
||
<div class="teacher-single__metric-label"><?php echo esc_html($m['label']); ?></div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── ПОЛОСА ДЕФИЦИТА ───────────────────
|
||
if ($days_left !== '' || ( $seats_left && (int) $seats_left > 0 )) :
|
||
?>
|
||
<section class="teacher-single__scarcity section-bg reveal" data-bg="teacher-scarcity" aria-label="Осталось мест">
|
||
<div class="container">
|
||
<div class="teacher-single__scarcity-inner">
|
||
<?php if ($days_left !== '') : ?>
|
||
<div class="teacher-single__scarcity-item">
|
||
<span class="teacher-single__scarcity-num" data-countdown="<?php echo esc_attr($days_left); ?>"><?php echo esc_html($days_left); ?></span>
|
||
<span class="teacher-single__scarcity-label">дней до <?php echo esc_html($exam_label); ?></span>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if ($seats_left && (int) $seats_left > 0) : ?>
|
||
<div class="teacher-single__scarcity-item">
|
||
<span class="teacher-single__scarcity-num is-hot"><?php echo esc_html($seats_left); ?></span>
|
||
<span class="teacher-single__scarcity-label">места в группе</span>
|
||
</div>
|
||
<?php endif; ?>
|
||
<p class="teacher-single__scarcity-note"><?php echo esc_html($scarcity_note); ?></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php if (! empty($subject_items)) : ?>
|
||
<?php
|
||
// ─────────────────── ПРОГРАММЫ (H2-секция на курс) ───────────────────
|
||
// Якорь #course-N совпадает с @id в микроразметке. Цена на странице не выводится.
|
||
?>
|
||
<section class="teacher-single__courses section-bg reveal" data-bg="teacher-courses" aria-labelledby="teacher-courses-title">
|
||
<div class="container">
|
||
<div class="section-header--left">
|
||
<h2 id="teacher-courses-title" class="bento-h2">Программы и направления</h2>
|
||
<p class="bento-p"><?php echo esc_html($full_name); ?> ведёт занятия по направлениям в мини-группах <?php echo esc_html($group_size); ?> человек — выберите программу.</p>
|
||
</div>
|
||
<div class="teacher-single__courses-grid">
|
||
<?php $course_i = 1; ?>
|
||
<?php foreach ($subject_items as $si) :
|
||
$course_anchor = 'course-' . $course_i;
|
||
?>
|
||
<article class="teacher-single__course" id="<?php echo esc_attr($course_anchor); ?>">
|
||
<div class="teacher-single__course-head">
|
||
<h2 class="teacher-single__course-title">
|
||
<?php echo esc_html($si['name']); ?> <?php echo esc_html($branch_city_prep); ?>
|
||
</h2>
|
||
<?php if (! empty($si['url'])) : ?>
|
||
<a class="teacher-single__course-link" href="<?php echo esc_url($si['url']); ?>">Подробнее о программе →</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php if (! empty($si['topics'])) : ?>
|
||
<ul class="teacher-single__course-topics">
|
||
<?php foreach ($si['topics'] as $tp) : ?>
|
||
<li class="teacher-single__course-topic"><?php echo esc_html($tp); ?></li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
<div class="teacher-single__course-foot">
|
||
<button type="button" class="teacher-single__btn teacher-single__btn--primary btn-write open-bitrix-form">
|
||
<?php echo esc_html($cta_primary); ?>
|
||
</button>
|
||
</div>
|
||
</article>
|
||
<?php $course_i++; ?>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── СОЦИАЛЬНОЕ ДОКАЗАТЕЛЬСТВО ───────────────────
|
||
// Рейтинг преподавателя — $sp_avg (рассчитан выше), школы — из опций филиала.
|
||
$branch_avg = (string) get_option('branch_avg_rating', '');
|
||
$branch_cnt = (string) get_option('branch_ext_review_count', '');
|
||
if ('' !== $sp_avg || $branch_avg || $branch_cnt) :
|
||
?>
|
||
<section class="teacher-single__social-proof section-bg reveal" data-bg="teacher-social-proof" aria-label="Отзывы родителей">
|
||
<div class="container">
|
||
<div class="teacher-single__social-proof-inner">
|
||
<?php if ('' !== $sp_avg) : ?>
|
||
<div class="teacher-single__sp-item">
|
||
<span class="teacher-single__sp-stars" aria-hidden="true">
|
||
<?php for ($sp_i = 1; $sp_i <= 5; $sp_i++) : ?>
|
||
<svg class="<?php echo $sp_i <= (int) round((float) $sp_avg) ? 'is-filled' : ''; ?>" width="18" height="18" viewBox="0 0 20 20" fill="currentColor"><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>
|
||
<strong class="teacher-single__sp-num"><?php echo esc_html($sp_avg); ?></strong>
|
||
<span class="teacher-single__sp-text">оценка преподавателя по отзывам родителей</span>
|
||
<?php if ($review_count > 0) : ?>
|
||
<a class="teacher-single__sp-link" href="#reviews"><?php echo esc_html($review_count); ?> отзывов о преподавателе →</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
<?php if ($branch_avg || $branch_cnt) : ?>
|
||
<div class="teacher-single__sp-item">
|
||
<strong class="teacher-single__sp-num"><?php echo esc_html($branch_avg); ?></strong>
|
||
<span class="teacher-single__sp-text">рейтинг школы в Яндекс Картах</span>
|
||
<?php if ($branch_cnt) : ?>
|
||
<span class="teacher-single__sp-link"><?php echo esc_html($branch_cnt); ?> отзывов на внешних площадках</span>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── СЕГМЕНТЫ «ДЛЯ КОГО» ───────────────────
|
||
?>
|
||
<section class="teacher-single__segments section-bg reveal" data-bg="teacher-segments" aria-labelledby="teacher-segments-title">
|
||
<div class="container">
|
||
<div class="section-header--left">
|
||
<h2 id="teacher-segments-title" class="bento-h2">Кому подойдут занятия</h2>
|
||
<p class="bento-p">Формат мини-группы закрывает три разные задачи — выберите свою.</p>
|
||
</div>
|
||
<div class="teacher-single__segments-grid">
|
||
<?php $seg_num = 0; ?>
|
||
<?php foreach ($segments as $i => $seg) :
|
||
if ($i >= 3) {
|
||
break;
|
||
}
|
||
$s_title = $seg['segment_title'] ?? '';
|
||
$s_text = $seg['segment_text'] ?? '';
|
||
if (! $s_title) {
|
||
continue;
|
||
}
|
||
$seg_num++;
|
||
?>
|
||
<article class="teacher-single__segment-card">
|
||
<span class="teacher-single__segment-icon" aria-hidden="true"><?php echo esc_html(str_pad((string) $seg_num, 2, '0', STR_PAD_LEFT)); ?></span>
|
||
<h3 class="teacher-single__segment-title"><?php echo esc_html($s_title); ?></h3>
|
||
<p class="teacher-single__segment-text"><?php echo esc_html($s_text); ?></p>
|
||
</article>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
|
||
<details class="teacher-single__spoiler">
|
||
<summary class="teacher-single__spoiler-summary"><?php echo esc_html($segment_4_title); ?></summary>
|
||
<div class="teacher-single__spoiler-body">
|
||
<p><?php echo esc_html($segment_4_text); ?></p>
|
||
<button type="button" class="teacher-single__btn teacher-single__btn--primary btn-write open-bitrix-form">
|
||
<?php echo esc_html($cta_primary); ?>
|
||
</button>
|
||
</div>
|
||
</details>
|
||
</div>
|
||
</section>
|
||
|
||
<?php
|
||
// ─────────────────── ИЗМЕРИМЫЕ РЕЗУЛЬТАТЫ (отдельно от «Кому подойдут») ───────────────────
|
||
if (! empty($results)) :
|
||
?>
|
||
<section class="teacher-single__results section-bg reveal" data-bg="teacher-results" aria-labelledby="teacher-results-title">
|
||
<div class="container">
|
||
<div class="section-header--left">
|
||
<h2 id="teacher-results-title" class="bento-h2">Измеримые результаты учеников</h2>
|
||
<p class="bento-p">Не обещания, а факты — что меняется в знаниях и успеваемости после занятий.</p>
|
||
</div>
|
||
<div class="teacher-single__results-grid">
|
||
<?php foreach ($results as $rs) :
|
||
$rt = trim((string) ( $rs['result_title'] ?? '' ));
|
||
if ('' === $rt) {
|
||
continue;
|
||
}
|
||
?>
|
||
<div class="teacher-single__result">
|
||
<div class="teacher-single__result-num"><?php echo esc_html($rt); ?></div>
|
||
<div class="teacher-single__result-text"><?php echo esc_html($rs['result_text'] ?? ''); ?></div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── ЛИЧНАЯ ИСТОРИЯ + КАК ПРОХОДИТ ЗАНЯТИЕ ───────────────────
|
||
if ($about_text) :
|
||
?>
|
||
<section class="teacher-single__story section-bg reveal" data-bg="teacher-story" aria-labelledby="teacher-story-title">
|
||
<div class="container">
|
||
<div class="teacher-single__story-grid">
|
||
<div class="teacher-single__story-about">
|
||
<h2 id="teacher-story-title" class="bento-h2">О себе</h2>
|
||
<div class="teacher-single__story-text"><?php echo wp_kses_post(wpautop($about_text)); ?></div>
|
||
</div>
|
||
<div class="teacher-single__story-steps">
|
||
<h2 class="bento-h2">Как проходит первое занятие</h2>
|
||
<ol class="teacher-single__timeline">
|
||
<?php $step_num = 0; ?>
|
||
<?php foreach ($steps as $i => $step) :
|
||
$st_title = $step['step_title'] ?? '';
|
||
$st_text = $step['step_text'] ?? '';
|
||
if (! $st_title) {
|
||
continue;
|
||
}
|
||
$step_num++;
|
||
?>
|
||
<li class="teacher-single__timeline-item">
|
||
<span class="teacher-single__timeline-num" aria-hidden="true"><?php echo esc_html($step_num); ?></span>
|
||
<div class="teacher-single__timeline-content">
|
||
<h3><?php echo esc_html($st_title); ?></h3>
|
||
<?php if ($st_text) : ?><p><?php echo esc_html($st_text); ?></p><?php endif; ?>
|
||
</div>
|
||
</li>
|
||
<?php endforeach; ?>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php if ($video_html) : ?>
|
||
<section class="teacher-single__video section-bg reveal" data-bg="teacher-video" aria-labelledby="teacher-video-title">
|
||
<div class="container">
|
||
<h2 id="teacher-video-title" class="bento-h2">Видео-приветствие</h2>
|
||
<p class="bento-p">Посмотрите, как преподаватель общается — представьте его в роли наставника вашего ребёнка.</p>
|
||
<div class="teacher-single__video-frame">
|
||
<?php echo wp_kses_post($video_html); ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── КЕЙСЫ (ТАБЫ 9/11) ───────────────────
|
||
$case_tabs = array();
|
||
if (! empty($cases) && is_array($cases)) {
|
||
$case_tabs = array_values(array_unique(array_filter(array_map(function ($c) {
|
||
return trim((string) ( $c['case_tab'] ?? '' ));
|
||
}, $cases))));
|
||
}
|
||
if (! empty($case_tabs)) :
|
||
?>
|
||
<section class="teacher-single__cases section-bg reveal" data-bg="teacher-cases" aria-labelledby="teacher-cases-title">
|
||
<div class="container">
|
||
<h2 id="teacher-cases-title" class="bento-h2">Результаты учеников</h2>
|
||
<div class="teacher-single__cases-tabs" role="tablist" aria-label="Класс">
|
||
<?php foreach ($case_tabs as $ci => $tab) :
|
||
$tab_id = sanitize_title($tab) . '-' . $ci;
|
||
if ('' === trim($tab_id, '-')) {
|
||
$tab_id = 'tab-' . $ci;
|
||
}
|
||
?>
|
||
<button type="button" role="tab" id="case-tab-<?php echo esc_attr($tab_id); ?>" aria-controls="case-panel-<?php echo esc_attr($tab_id); ?>" aria-selected="<?php echo 0 === $ci ? 'true' : 'false'; ?>" class="teacher-single__case-tab<?php echo 0 === $ci ? ' is-active' : ''; ?>" data-case-tab="<?php echo esc_attr($tab); ?>">
|
||
<?php echo esc_html($tab); ?> класс
|
||
</button>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php foreach ($case_tabs as $ci => $tab) :
|
||
$tab_id = sanitize_title($tab) . '-' . $ci;
|
||
if ('' === trim($tab_id, '-')) {
|
||
$tab_id = 'tab-' . $ci;
|
||
}
|
||
?>
|
||
<div role="tabpanel" id="case-panel-<?php echo esc_attr($tab_id); ?>" aria-labelledby="case-tab-<?php echo esc_attr($tab_id); ?>" class="teacher-single__case-panel<?php echo 0 === $ci ? ' is-active' : ''; ?>" data-case-panel="<?php echo esc_attr($tab); ?>">
|
||
<div class="teacher-single__cases-grid">
|
||
<?php foreach ($cases as $case) :
|
||
if (trim((string) ( $case['case_tab'] ?? '' )) !== $tab || empty($case['case_text'])) {
|
||
continue;
|
||
}
|
||
?>
|
||
<div class="teacher-single__case-card">
|
||
<span class="teacher-single__case-mark" aria-hidden="true">“</span>
|
||
<p><?php echo esc_html($case['case_text']); ?></p>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── ОБРАЗОВАНИЕ / СЕРТИФИКАТЫ ───────────────────
|
||
// Направления здесь не дублируем — они уже показаны выше в секции «Программы и направления».
|
||
$certificates = (array) carbon_get_post_meta($tid, 'certificates');
|
||
if ($education || $add_education || ! empty($certificates)) :
|
||
?>
|
||
<section class="teacher-single__edu section-bg reveal" data-bg="teacher-edu" aria-labelledby="teacher-edu-title">
|
||
<div class="container">
|
||
<h2 id="teacher-edu-title" class="bento-h2">Образование и опыт</h2>
|
||
<div class="teacher-single__edu-grid">
|
||
<?php if ($education || $add_education) : ?>
|
||
<div class="teacher-single__edu-col">
|
||
<?php if ($education) : ?>
|
||
<h3 class="teacher-single__edu-h">Образование</h3>
|
||
<div class="teacher-single__edu-text"><?php echo wp_kses_post($education); ?></div>
|
||
<?php endif; ?>
|
||
<?php if ($add_education) : ?>
|
||
<h3 class="teacher-single__edu-h">Повышение квалификации</h3>
|
||
<div class="teacher-single__edu-text"><?php echo wp_kses_post($add_education); ?></div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<?php if ($certificates) : ?>
|
||
<div class="teacher-single__cert-grid">
|
||
<?php foreach ($certificates as $cert) :
|
||
$c_id = $cert['certificates_foto'] ?? '';
|
||
$c_alt = $c_id ? get_post_meta((int) $c_id, '_wp_attachment_image_alt', true) : '';
|
||
// image() = проверка наличия + вывод, без отдельного url-запроса.
|
||
$c_img = $c_id ? wp_get_attachment_image(
|
||
(int) $c_id,
|
||
'medium',
|
||
false,
|
||
array(
|
||
'alt' => $c_alt ?: ('Диплом или сертификат — ' . $full_name),
|
||
'loading' => 'lazy',
|
||
'decoding' => 'async',
|
||
)
|
||
) : '';
|
||
if (! $c_img) {
|
||
continue;
|
||
}
|
||
?>
|
||
<figure class="teacher-single__cert">
|
||
<?php echo $c_img; ?>
|
||
</figure>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── FAQ (формат + общие) ───────────────────
|
||
if (! empty($faq_items)) :
|
||
?>
|
||
<section class="teacher-single__faq section-bg reveal" data-bg="teacher-faq" aria-labelledby="teacher-faq-title">
|
||
<div class="container">
|
||
<h2 id="teacher-faq-title" class="bento-h2">Вопросы и ответы</h2>
|
||
<div class="teacher-single__faq-list">
|
||
<?php foreach ($faq_items as $fi) : ?>
|
||
<details class="teacher-single__faq-item">
|
||
<summary><?php echo esc_html($fi['q']); ?></summary>
|
||
<p><?php echo esc_html($fi['a']); ?></p>
|
||
</details>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─── ОТЗЫВЫ О ПРЕПОДАВАТЕЛЕ (part reviews-link, как на главной) ───
|
||
$show_social_reviews = carbon_get_post_meta($tid, 'teacher_show_social_reviews');
|
||
if ('no' !== (string) $show_social_reviews) {
|
||
get_template_part('template-parts/reviews-link', null, array( 'teacher' => $tid ));
|
||
}
|
||
?>
|
||
|
||
<?php
|
||
// ─────────────────── ДОВЕРИЕ / ЛИЦЕНЗИЯ ───────────────────
|
||
?>
|
||
<section class="teacher-single__trust section-bg reveal" data-bg="teacher-trust" aria-labelledby="teacher-trust-title">
|
||
<div class="container">
|
||
<div class="teacher-single__trust-inner">
|
||
<span class="teacher-single__trust-shield" aria-hidden="true"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><use href="#icon-check"/></svg></span>
|
||
<div>
|
||
<h2 id="teacher-trust-title" class="bento-h2">Работаем официально</h2>
|
||
<p class="teacher-single__trust-text"><?php echo esc_html($license); ?></p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<?php
|
||
// ─── ДРУГИЕ ПРЕПОДАВАТЕЛИ (общий блок сайта) ───
|
||
get_template_part('template-parts/teachers-cards');
|
||
?>
|
||
|
||
<?php
|
||
// ─────────────────── ГЕО-ПОКРЫТИЕ (из настроек филиала) ───────────────────
|
||
$geo_items = array();
|
||
if ('' !== (string) $branch_geo_areas) {
|
||
foreach (array_map('trim', explode(',', $branch_geo_areas)) as $ga) {
|
||
if ('' !== $ga) {
|
||
$geo_items[] = $ga;
|
||
}
|
||
}
|
||
}
|
||
if (! empty($geo_items) || $geo_walk || $geo_parking || $geo_schools) :
|
||
?>
|
||
<section class="teacher-single__geo section-bg reveal" data-bg="teacher-geo" aria-labelledby="teacher-geo-title">
|
||
<div class="container">
|
||
<div class="teacher-single__geo-inner">
|
||
<div class="teacher-single__geo-main">
|
||
<h2 id="teacher-geo-title" class="bento-h2">Принимаем детей из городов рядом</h2>
|
||
<p class="bento-p">Занятия проходят очно в школе «<?php echo esc_html($branch_name); ?>» — <?php echo esc_html($branch_city_prep); ?>. Добираться удобно из соседних городов.</p>
|
||
</div>
|
||
<?php if (! empty($geo_items)) : ?>
|
||
<ul class="teacher-single__geo-cities">
|
||
<?php foreach ($geo_items as $gc) : ?>
|
||
<li><?php echo esc_html($gc); ?></li>
|
||
<?php endforeach; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
<?php if ($geo_walk || $geo_parking || $geo_schools) : ?>
|
||
<ul class="teacher-single__geo-logistics">
|
||
<?php if ($geo_walk) : ?>
|
||
<li><span class="teacher-single__geo-pin" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0Z"/><circle cx="12" cy="10" r="3"/></svg></span><?php echo esc_html($geo_walk); ?></li>
|
||
<?php endif; ?>
|
||
<?php if ($geo_parking) : ?>
|
||
<li><span class="teacher-single__geo-pin" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0Z"/><circle cx="12" cy="10" r="3"/></svg></span><?php echo esc_html($geo_parking); ?></li>
|
||
<?php endif; ?>
|
||
<?php if ($geo_schools) : ?>
|
||
<li><span class="teacher-single__geo-pin" aria-hidden="true"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0Z"/><circle cx="12" cy="10" r="3"/></svg></span><?php echo esc_html($geo_schools); ?></li>
|
||
<?php endif; ?>
|
||
</ul>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
<?php endif; ?>
|
||
|
||
<?php
|
||
// ─────────────────── ФИНАЛЬНЫЙ CTA ───────────────────
|
||
?>
|
||
<section class="teacher-single__final section-bg reveal" data-bg="teacher-final" aria-labelledby="teacher-final-title">
|
||
<div class="container">
|
||
<div class="teacher-single__final-inner">
|
||
<h2 id="teacher-final-title" class="bento-h2">Запишитесь на бесплатную диагностику</h2>
|
||
<p class="teacher-single__final-text">Познакомимся, проверим уровень ребёнка и подберём мини-группу <?php echo esc_html($group_size); ?> человек. Перезвоним за 15 минут.</p>
|
||
<div class="teacher-single__hero-cta">
|
||
<button type="button" class="teacher-single__btn teacher-single__btn--primary btn-write open-bitrix-form">
|
||
<?php echo esc_html($cta_primary); ?>
|
||
</button>
|
||
<?php if ($branch_phone) : ?>
|
||
<a class="teacher-single__btn teacher-single__btn--ghost" href="tel:<?php echo esc_attr($phone_clean); ?>">
|
||
<?php echo esc_html($branch_phone); ?>
|
||
</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
<p class="teacher-single__risk-note"><?php echo esc_html($risk_note); ?></p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<?php
|
||
// ─── КОНТАКТЫ / АДРЕС ───
|
||
get_template_part('template-parts/contacts');
|
||
|
||
// ─── ЭКСПЕРТНОСТЬ (E-E-A-T): автор — преподаватель, под картой ───
|
||
$teacher_creds = trim(implode(', ', array_filter(array(
|
||
$direction ?: '',
|
||
($tenure ? 'педагогический стаж ' . $tenure . ' лет' : ''),
|
||
))));
|
||
get_template_part('template-parts/author-eaat', null, array(
|
||
'author_name' => $full_name,
|
||
'author_creds' => $teacher_creds,
|
||
));
|
||
?>
|
||
|
||
<?php
|
||
// ─────────────────── STICKY CTA (мобильный) ───────────────────
|
||
?>
|
||
<div class="teacher-single__sticky" hidden>
|
||
<div class="teacher-single__sticky-inner">
|
||
<button type="button" class="teacher-single__btn teacher-single__btn--primary btn-write open-bitrix-form">
|
||
<?php echo esc_html($cta_primary); ?>
|
||
</button>
|
||
<?php if ($wa_url) : ?>
|
||
<a class="teacher-single__sticky-icon" href="<?php echo esc_url($wa_url); ?>" target="_blank" rel="noopener nofollow" aria-label="Написать в WhatsApp">
|
||
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2a10 10 0 0 0-8.6 15L2 22l5.2-1.4A10 10 0 1 0 12 2Zm0 18.2a8.2 8.2 0 0 1-4.2-1.2l-.3-.2-3.1.8.8-3-.2-.3a8.2 8.2 0 1 1 7 3.9Zm4.5-6.1c-.2-.1-1.5-.7-1.7-.8-.2-.1-.4-.1-.6.1-.2.3-.6.8-.8 1-.1.2-.3.2-.5.1a6.7 6.7 0 0 1-3.4-3c-.3-.4 0-.5.2-.7l.4-.5c.1-.2.1-.3 0-.5l-.8-1.9c-.2-.5-.4-.4-.6-.4h-.5c-.2 0-.5.1-.7.3-.2.3-.9.9-.9 2.2s.9 2.5 1.1 2.7c.1.2 1.8 2.8 4.4 3.9 2.6 1.1 2.6.7 3.1.7.5 0 1.5-.6 1.7-1.2.2-.6.2-1.1.1-1.2 0-.1-.2-.2-.4-.3Z"/></svg>
|
||
</a>
|
||
<?php endif; ?>
|
||
<?php if ($phone_clean) : ?>
|
||
<a class="teacher-single__sticky-icon" href="tel:<?php echo esc_attr($phone_clean); ?>" aria-label="Позвонить">
|
||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 16.9v3a2 2 0 0 1-2.2 2 19.8 19.8 0 0 1-8.6-3.1 19.5 19.5 0 0 1-6-6A19.8 19.8 0 0 1 2.1 4.2 2 2 0 0 1 4.1 2h3a2 2 0 0 1 2 1.7c.1 1 .4 2 .7 2.9a2 2 0 0 1-.5 2.1L8 10a16 16 0 0 0 6 6l1.3-1.3a2 2 0 0 1 2.1-.5c.9.3 1.9.6 2.9.7a2 2 0 0 1 1.7 2Z"/></svg>
|
||
</a>
|
||
<?php endif; ?>
|
||
</div>
|
||
</div>
|
||
</main>
|
||
|
||
<script type="application/ld+json">
|
||
<?php echo wp_json_encode(
|
||
array(
|
||
'@context' => 'https://schema.org',
|
||
'@graph' => $schema_graph,
|
||
),
|
||
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||
); ?>
|
||
</script>
|
||
|
||
<?php get_footer(); ?>
|