4709 lines
325 KiB
PHP
4709 lines
325 KiB
PHP
<?php
|
||
require_once get_template_directory() . '/inc/template-tags.php';
|
||
|
||
// Pksh_Data — централизованная загрузка данных для page-podgotovka-k-shkole.php
|
||
require_once get_template_directory() . '/inc/class-pksh-data.php';
|
||
|
||
// ─── Carbon Fields helper (безопасный вызов с fallback) ───
|
||
if (! function_exists('crb_get_theme_option')) {
|
||
function crb_get_theme_option(string $key, $default = '')
|
||
{
|
||
return function_exists('carbon_get_theme_option')
|
||
? carbon_get_theme_option($key) ?: $default
|
||
: $default;
|
||
}
|
||
}
|
||
if (! function_exists('crb_get_post_meta')) {
|
||
function crb_get_post_meta(int $post_id, string $key, $default = '')
|
||
{
|
||
return function_exists('carbon_get_post_meta')
|
||
? carbon_get_post_meta($post_id, $key) ?: $default
|
||
: $default;
|
||
}
|
||
}
|
||
|
||
// ─── CRO-трекинг для data-track кнопок на hero (hero-front.php) ───
|
||
add_action('wp_footer', function () {
|
||
if (wp_script_is('front-page-script', 'enqueued')) {
|
||
wp_add_inline_script('front-page-script', '
|
||
document.addEventListener("DOMContentLoaded", function() {
|
||
document.querySelectorAll("[data-track]").forEach(function(el) {
|
||
el.addEventListener("click", function() {
|
||
if (typeof gtag === "function") {
|
||
gtag("event", "hero_click", {
|
||
"event_category": "engagement",
|
||
"event_label": this.dataset.track
|
||
});
|
||
}
|
||
if (typeof ym === "function") {
|
||
ym(' . ( defined('YM_COUNTER_ID') ? esc_js(YM_COUNTER_ID) : 'null' ) . ', "reachGoal", this.dataset.track);
|
||
}
|
||
});
|
||
});
|
||
});
|
||
');
|
||
}
|
||
}, 100);
|
||
|
||
/**
|
||
* Замена названия сайта из Настроек филиала.
|
||
* blogname (Внешний вид → Настроить → Свойства сайта) берётся из branch_name.
|
||
*/
|
||
add_filter('pre_option_blogname', function ($default) {
|
||
if (is_admin()) {
|
||
return $default;
|
||
}
|
||
$branch = get_option('branch_name');
|
||
if (! empty($branch)) {
|
||
return $branch;
|
||
}
|
||
return $default;
|
||
});
|
||
|
||
/* --- Удаляем мета из YOASTSEO START--- */
|
||
add_filter('wpseo_json_ld_output', '__return_false');
|
||
/* --- Удаляем мета из YOASTSEO END --- */
|
||
|
||
// ────────────────────────────────────────────────────
|
||
// SEO: страница КЛАССА (page-class.php) — переопределение
|
||
// Yoast-мета из вкладки «📊 SEO» (Настройки Страницы Класса)
|
||
// ────────────────────────────────────────────────────
|
||
add_filter('wpseo_title', function ($title) {
|
||
if (! is_page_template('page-class.php')) {
|
||
return $title;
|
||
}
|
||
$seo_title = carbon_get_post_meta(get_the_ID(), 'class_seo_title');
|
||
return $seo_title ?: $title;
|
||
}, 20);
|
||
|
||
add_filter('wpseo_metadesc', function ($desc) {
|
||
if (! is_page_template('page-class.php')) {
|
||
return $desc;
|
||
}
|
||
$seo_desc = carbon_get_post_meta(get_the_ID(), 'class_seo_description');
|
||
return $seo_desc ?: $desc;
|
||
}, 20);
|
||
|
||
add_filter('wpseo_opengraph_image', 'dekart_class_og_image', 20);
|
||
add_filter('wpseo_twitter_image', 'dekart_class_og_image', 20);
|
||
function dekart_class_og_image($img)
|
||
{
|
||
if (! is_page_template('page-class.php')) {
|
||
return $img;
|
||
}
|
||
$og_id = carbon_get_post_meta(get_the_ID(), 'class_seo_og_image');
|
||
if ($og_id) {
|
||
$src = wp_get_attachment_image_url((int) $og_id, 'full');
|
||
if ($src) {
|
||
return $src;
|
||
}
|
||
}
|
||
return $img;
|
||
}
|
||
|
||
add_filter('wpseo_robots', function ($robots) {
|
||
if (! is_page_template('page-class.php')) {
|
||
return $robots;
|
||
}
|
||
if (carbon_get_post_meta(get_the_ID(), 'class_seo_noindex')) {
|
||
$robots['index'] = 'noindex';
|
||
}
|
||
return $robots;
|
||
}, 20);
|
||
|
||
// ────────────────────────────────────────────────────
|
||
// Hero-изображение как OG/Twitter image для главной
|
||
// ────────────────────────────────────────────────────
|
||
add_filter('wpseo_opengraph_image', 'dekart_front_hero_og_image');
|
||
add_filter('wpseo_twitter_image', 'dekart_front_hero_og_image');
|
||
function dekart_front_hero_og_image($img)
|
||
{
|
||
if (! is_front_page()) {
|
||
return $img;
|
||
}
|
||
$foto_id = carbon_get_post_meta(get_the_ID(), 'banner_img_desktop');
|
||
if ($foto_id) {
|
||
$url = wp_get_attachment_image_url($foto_id, 'full');
|
||
if ($url) {
|
||
return $url;
|
||
}
|
||
}
|
||
return $img;
|
||
}
|
||
|
||
// ────────────────────────────────────────────────────
|
||
// CRO: UTM-метки → cookie (30 дней)
|
||
// ────────────────────────────────────────────────────
|
||
add_action('init', function () {
|
||
if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
|
||
return;
|
||
}
|
||
if (! isset($_COOKIE['utm_source']) && ! empty($_GET['utm_source'])) {
|
||
$utm_params = [ 'utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content' ];
|
||
foreach ($utm_params as $param) {
|
||
if (! empty($_GET[ $param ])) {
|
||
setcookie($param, sanitize_text_field($_GET[ $param ]), time() + 30 * DAY_IN_SECONDS, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);
|
||
}
|
||
}
|
||
}
|
||
});
|
||
|
||
// Отключаем Reading Time для страницы Подготовки к школе
|
||
add_filter('wpseo_frontend_presenter_classes', 'dekart_disable_reading_time_pksh');
|
||
function dekart_disable_reading_time_pksh(array $presenters): array
|
||
{
|
||
if (is_page_template('page-podgotovka-k-shkole.php')) {
|
||
return array_filter($presenters, function ($class) {
|
||
return false === strpos($class, 'ReadingTime');
|
||
});
|
||
}
|
||
return $presenters;
|
||
}
|
||
|
||
add_theme_support('title-tag');
|
||
/* --- #SEND Review Form --- */
|
||
add_action('template_redirect', 'author_archive_redirect');
|
||
add_filter('author_link', 'remove_author_pages_link');
|
||
// редиректим на главную со страниц авторов
|
||
function author_archive_redirect()
|
||
{
|
||
if (is_author()) {
|
||
wp_redirect(home_url(), 301);
|
||
exit;
|
||
}
|
||
}
|
||
// удаляем ссылку
|
||
function remove_author_pages_link($content)
|
||
{
|
||
return home_url();
|
||
}
|
||
/*
|
||
/* --- Courses --- */
|
||
add_action('init', 'create_courses_hierarchical_taxonomy', 0);
|
||
function create_courses_hierarchical_taxonomy()
|
||
{
|
||
$labels = array(
|
||
'name' => _x('Категории курсов', 'taxonomy general name'),
|
||
'singular_name' => _x('Категория курсов', 'taxonomy singular name'),
|
||
'search_items' => __('Поиск курсов по категории'),
|
||
'all_items' => __('Все категории курсов'),
|
||
'parent_item' => __('Родительская категория курсов'),
|
||
'parent_item_colon' => __('Родителькая категория курсов:'),
|
||
'edit_item' => __('Редактировать категорию'),
|
||
'update_item' => __('Обновить категорию'),
|
||
'add_new_item' => __('Добавить новую категорию'),
|
||
'new_item_name' => __('Новая категория'),
|
||
'menu_name' => __('Категории курсов'),
|
||
);
|
||
register_taxonomy('courses', array('course'), array(
|
||
'hierarchical' => true,
|
||
'labels' => $labels,
|
||
'show_ui' => true,
|
||
'show_admin_column' => true,
|
||
'query_var' => true,
|
||
'rewrite' => array( 'slug' => 'courses' ),
|
||
));
|
||
}
|
||
add_action('init', 'create_course');
|
||
function create_course()
|
||
{
|
||
register_post_type(
|
||
'course',
|
||
array(
|
||
'labels' => array(
|
||
'name' => 'Курсы',
|
||
'singular_name' => 'Курс',
|
||
'add_new' => 'Добавить курс',
|
||
'add_new_item' => 'Добавить курс',
|
||
'edit' => 'Редактировать курс',
|
||
'edit_item' => 'Редактировать курс',
|
||
'new_item' => 'Новый курс',
|
||
'view' => 'Смотреть курс',
|
||
'view_item' => 'Смотреть курс',
|
||
'search_items' => 'Поиск курсов',
|
||
'not_found' => 'Курсы не найдены',
|
||
'not_found_in_trash' => 'В корзине нет курсов',
|
||
'parent' => 'Родительский курс'
|
||
),
|
||
'public' => true,
|
||
'exclude_from_search' => false,
|
||
'menu_position' => 12,
|
||
'supports' => array( 'title' ),
|
||
'publicly_queryable' => true,
|
||
'menu_icon' => 'dashicons-welcome-learn-more',
|
||
'taxonomies' => array( 'courses' ),
|
||
'has_archive' => false
|
||
)
|
||
);
|
||
}
|
||
/* --- ##Cources## --- */
|
||
|
||
/* --- trainingCategory --- */
|
||
add_action('init', 'create_trainingCategory_hierarchical_taxonomy', 0);
|
||
function create_trainingCategory_hierarchical_taxonomy()
|
||
{
|
||
$labels = array(
|
||
'name' => _x('Категории', 'Категория обучения учителя'),
|
||
'singular_name' => _x('Категория', 'Категория'),
|
||
'search_items' => __('Поиск категории'),
|
||
'all_items' => __('Все категории'),
|
||
'parent_item' => __('Родительская категория'),
|
||
'parent_item_colon' => __('Родительская категория:'),
|
||
'edit_item' => __('Редактировать категорию'),
|
||
'update_item' => __('Обновить категорию'),
|
||
'add_new_item' => __('Добавить новую категорию'),
|
||
'new_item_name' => __('Новая категория'),
|
||
'menu_name' => __('Категории'),
|
||
);
|
||
register_taxonomy('trainingCategory', array('teacher'), array(
|
||
'hierarchical' => true,
|
||
'labels' => $labels,
|
||
'show_ui' => true,
|
||
'show_admin_column' => true,
|
||
'query_var' => true,
|
||
'rewrite' => false, // Отключаем перезапись URL
|
||
));
|
||
}
|
||
|
||
// ✅ Приоритет 5 — регистрация CPT teacher ДО инициализации Carbon Fields
|
||
add_action('init', 'create_teacher', 5);
|
||
function create_teacher()
|
||
{
|
||
register_post_type(
|
||
'teacher',
|
||
array(
|
||
'labels' => array(
|
||
'name' => 'Преподаватели',
|
||
'singular_name' => 'Преподаватель',
|
||
'add_new' => 'Добавить преподавателя',
|
||
'add_new_item' => 'Добавить преподавателя',
|
||
'edit' => 'Редактировать преподавателя',
|
||
'edit_item' => 'Редактировать преподавателя',
|
||
'new_item' => 'Новый преподаватель',
|
||
'view' => 'Смотреть преподавателя',
|
||
'view_item' => 'Смотреть преподавателя',
|
||
'search_items' => 'Поиск преподавателей',
|
||
'not_found' => 'Преподаватели не найдены',
|
||
'not_found_in_trash' => 'В корзине нет преподавателей',
|
||
'parent' => 'Родительский преподаватель'
|
||
),
|
||
'public' => true,
|
||
'exclude_from_search' => false,
|
||
'menu_position' => 12,
|
||
'show_in_rest' => true,
|
||
'supports' => array( 'title', 'thumbnail' ),
|
||
'publicly_queryable' => true,
|
||
'menu_icon' => 'dashicons-admin-users',
|
||
'taxonomies' => array( 'subject' ),
|
||
'has_archive' => false
|
||
)
|
||
);
|
||
}
|
||
/* --- ##Teacher## --- */
|
||
|
||
/* --- Reviews --- */
|
||
add_action('init', 'create_reviews');
|
||
function create_reviews()
|
||
{
|
||
register_post_type(
|
||
'reviews',
|
||
array(
|
||
'labels' => array(
|
||
'name' => 'Отзывы',
|
||
'singular_name' => 'Отзыв',
|
||
'add_new' => 'Добавить отзыв',
|
||
'add_new_item' => 'Добавить отзыв',
|
||
'edit' => 'Редактировать отзыв',
|
||
'edit_item' => 'Редактировать отзыв',
|
||
'new_item' => 'Новый отзыв',
|
||
'view' => 'Смотреть отзыв',
|
||
'view_item' => 'Смотреть отзыв',
|
||
'search_items' => 'Поиск отзывов',
|
||
'not_found' => 'Отзывы не найдены',
|
||
'not_found_in_trash' => 'В корзине нет отзывов',
|
||
'parent' => 'Родительский отзыв'
|
||
),
|
||
'public' => true,
|
||
'exclude_from_search' => true,
|
||
'menu_position' => 13,
|
||
'supports' => array( 'title' ),
|
||
'publicly_queryable' => false,
|
||
'menu_icon' => 'dashicons-format-status',
|
||
'has_archive' => false
|
||
)
|
||
);
|
||
}
|
||
|
||
use Carbon_Fields\Container;
|
||
use Carbon_Fields\Field;
|
||
|
||
add_action('carbon_fields_register_fields', 'add_carbon');
|
||
function add_carbon()
|
||
{
|
||
|
||
// ====================================================
|
||
// Настройки темы — перегруппировано 2026-07-27
|
||
// ====================================================
|
||
Container::make('theme_options', 'Настройка темы ДЕКАРТ')
|
||
->add_tab('📞 Контакты', array(
|
||
Field::make('text', 'site_name', 'Название учебного центра')
|
||
->set_help_text('Используйте только одинарные кавычки в названии.'),
|
||
Field::make('text', 'site_phone', 'Телефон'),
|
||
Field::make('text', 'site_phone_multi', 'Телефон (многоканальный)'),
|
||
Field::make('text', 'site_mail', 'Почта для связи'),
|
||
Field::make('text', 'site_index', 'Почтовый индекс'),
|
||
Field::make('text', 'site_region', 'Область'),
|
||
Field::make('text', 'site_city', 'Город'),
|
||
Field::make('text', 'site_address', 'Адрес'),
|
||
Field::make('text', 'site_map_link', 'Ссылка на карту'),
|
||
Field::make('text', 'site_location', 'Координаты адреса (для Яндекс.Карт)'),
|
||
Field::make('text', 'site_lk_url', 'Ссылка на личный кабинет (ЛК)')
|
||
->set_default_value('https://lk.dekart-school.ru/')
|
||
->set_help_text('URL личного кабинета для учеников/родителей. По умолчанию: https://lk.dekart-school.ru/'),
|
||
))
|
||
->add_tab('🖥️ Интеграции', array(
|
||
Field::make('textarea', 'site_bitrix_script', 'Скрипт Bitrix24 (формы)')
|
||
->set_help_text('JS-скрипт для форм Bitrix24 на страницах.'),
|
||
Field::make('textarea', 'site_bitrix_vacancies', 'Скрипт Bitrix24 (форма "Связаться с нами")'),
|
||
Field::make('textarea', 'site_frame_reviews', 'Код/ссылка iframe для отзывов'),
|
||
Field::make('html', 'int_banner_sep', '')
|
||
->set_html('<hr><h3>🪧 Плашка со скидкой</h3>'),
|
||
Field::make('checkbox', 'check_banner', 'Показывать плашку со скидкой на формах')
|
||
->set_option_value('yes'),
|
||
Field::make('checkbox', 'check_btn_discont', 'Скрыть кнопку "Стоимость ак. часа со скидкой"')
|
||
->set_option_value('yes'),
|
||
Field::make('text', 'text_banner', 'Текст в плашке')
|
||
->set_default_value('Всем записавшимся до 10 сентября<br class="desktop"><span>скидка 10%</span> на весь учебный год!'),
|
||
))
|
||
->add_tab('💳 Цены курсов', array(
|
||
Field::make('checkbox', 'early_bird_discount', 'Показывать "Скидка за раннюю запись"')
|
||
->set_option_value('yes'),
|
||
Field::make('html', 'price_hours_sep', '')
|
||
->set_html('<hr><h3>💰 Полная стоимость</h3>'),
|
||
Field::make('text', 'price_hour1', '1 предмет')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('text', 'price_hour2', '2 предмета')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('text', 'price_hour3', '3 предмета')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('text', 'price_hour4', '4 и более предметов')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('html', 'price_discount_sep', '')
|
||
->set_html('<hr><h3>🏷️ Со скидкой</h3>'),
|
||
Field::make('text', 'price_hour_discount1', '1 предмет со скидкой')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('text', 'price_hour_discount2', '2 предмета со скидкой')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('text', 'price_hour_discount3', '3 предмета со скидкой')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('text', 'price_hour_discount4', '4 и более предметов со скидкой')
|
||
->set_attribute('type', 'number'),
|
||
))
|
||
->add_tab('🔗 Соцсети', array(
|
||
Field::make('text', 'social_header_wt', 'WhatsApp — ссылка в шапке сайта'),
|
||
Field::make('text', 'social_wt', 'WhatsApp — ссылка на странице "Контакты"'),
|
||
Field::make('complex', 'social_media', 'Другие соцсети')
|
||
->add_fields(array(
|
||
Field::make('text', 'social_media_name', 'Название')
|
||
->set_width(100),
|
||
Field::make('image', 'social_media_img', 'Логотип')
|
||
->set_width(20),
|
||
Field::make('text', 'social_media_link', 'Ссылка')
|
||
->set_width(80),
|
||
)),
|
||
))
|
||
->add_tab('📸 Галерея', array(
|
||
Field::make('complex', 'slider_img', 'Изображения учебного центра')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('image', 'img', 'Фотография'),
|
||
)),
|
||
))
|
||
->add_tab('📊 SEO + Схема', array(
|
||
Field::make('html', 'schema_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Поля для <strong>JSON-LD микроразметки</strong> Schema.org. Если поле пусто — свойство не добавляется в @graph. Часть полей дублируется в Настройках филиала (для обратной совместимости).</p>'),
|
||
Field::make('html', 'schema_org_sep', '')
|
||
->set_html('<hr><h3>🏢 Организация</h3>'),
|
||
Field::make('text', 'schema_legal_name', 'Юридическое название (legalName)')
|
||
->set_width(50)
|
||
->set_help_text('Полное юр. название. Например: "ИП Иванов Иван Иванович"'),
|
||
Field::make('textarea', 'schema_description', 'Описание организации (description)')
|
||
->set_width(100)
|
||
->set_help_text('Описание для Schema.org Organization → School. Рекомендуется 1–2 предложения.'),
|
||
Field::make('text', 'schema_postal_code', 'Почтовый индекс (postalCode)')
|
||
->set_width(50),
|
||
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(100)
|
||
->set_help_text('Полная ссылка на Яндекс.Карты или Google Maps.'),
|
||
Field::make('html', 'schema_hours_sep', '')
|
||
->set_html('<hr><h3>🕐 Часы работы</h3>'),
|
||
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('html', 'schema_social_sep', '')
|
||
->set_html('<hr><h3>🌐 Социальные сети (sameAs)</h3>'),
|
||
Field::make('complex', 'schema_social', 'Ссылки на профили')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Ссылки на соцсети для sameAs[] Schema.org.')
|
||
->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('html', 'schema_media_sep', '')
|
||
->set_html('<hr><h3>🖼️ Медиа</h3>'),
|
||
Field::make('media_gallery', 'schema_photos', 'Фотографии филиала (image[])')
|
||
->set_help_text('Фотографии интерьера/экстерьера для image[] в микроразметке.'),
|
||
Field::make('html', 'schema_area_sep', '')
|
||
->set_html('<hr><h3>📍 Регион</h3>'),
|
||
Field::make('textarea', 'schema_area_served', 'Города присутствия (areaServed)')
|
||
->set_width(100)
|
||
->set_help_text('Список городов через запятую. Первый город должен совпадать с городом филиала. Влияет на локальный поиск.'),
|
||
Field::make('html', 'schema_content_sep', '')
|
||
->set_html('<hr><h3>📝 Контент</h3>'),
|
||
Field::make('textarea', 'teachers_block', 'Текст в блоке "Наша команда"'),
|
||
));
|
||
|
||
// (пусто — старые поля banner_img_desktop, banner_img_mobile,
|
||
// banner_h1, banner_text, page_breadcrumbs удалены 31 мая 2026)
|
||
|
||
// ====================================================
|
||
// Доп поля для категории Курсов
|
||
// ====================================================
|
||
Container::make('term_meta', 'Дополнительные поля к Курсам')
|
||
->where('term_taxonomy', '=', 'courses')
|
||
->show_on_level(1)
|
||
->where('term_level', '=', 1)
|
||
->add_fields(array(
|
||
Field::make('image', 'snippet', 'Изображение для сниппета:')
|
||
->set_width(100),
|
||
Field::make('image', 'banner_img_desktop', 'Изображение для баннера (десктопная версия)')
|
||
->help_text('Размер изображения (желательно) 1920px на 1030px')
|
||
->set_width(15),
|
||
Field::make('image', 'banner_img_mobile', 'Изображение для баннера (мобильная версия)')
|
||
->help_text('Размер изображения (желательно) 390px на 550px')
|
||
->set_width(15),
|
||
Field::make('textarea', 'banner_content', 'Текстовый контент баннера')
|
||
->set_width(70),
|
||
Field::make('text', 'title_product', 'Заголовок блока курсов:')
|
||
->set_width(100),
|
||
));
|
||
|
||
// ====================================================
|
||
// Главная Страница — tabbed-horizontal (как pksh)
|
||
// ====================================================
|
||
Container::make('post_meta', 'Настройки Главной Страницы')
|
||
->where('post_template', '=', 'front-page.php')
|
||
->add_tab('🖼️ HERO', array(
|
||
Field::make('html', 'front_hero_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:12px;margin:0 0 8px;">Фото — квадратное 600×600, в круглой рамке справа.</p>'),
|
||
Field::make('image', 'banner_img_desktop', 'Фото')
|
||
->set_width(50),
|
||
Field::make('text', 'banner_h1', 'Заголовок H1')
|
||
->set_width(50)
|
||
->set_attribute('placeholder', 'Частная школа в Щёлково'),
|
||
Field::make('html', 'front_hero_stats_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">📊 Показатели статистики</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">Добавьте/удалите карточки через +/-.</p>'),
|
||
Field::make('complex', 'hero_stats', 'Показатели')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'stat_number', 'Число')
|
||
->set_width(30)
|
||
->set_help_text('Например: 12+, 500+, до 12'),
|
||
Field::make('text', 'stat_label', 'Подпись')
|
||
->set_width(70)
|
||
->set_help_text('Например: лет опыта, выпускников'),
|
||
)),
|
||
))
|
||
->add_tab('📄 О ШКОЛЕ', array(
|
||
Field::make('text', 'about_school_title', 'Заголовок секции')
|
||
->set_default_value('О школе «Декарт»'),
|
||
Field::make('rich_text', 'block_text_1', 'Текст секции')
|
||
->set_help_text('Основной текст о школе. Используйте абзацы, списки, жирный текст.'),
|
||
))
|
||
->add_tab('👨🏫 Преподаватели', array(
|
||
Field::make('html', 'front_teachers_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция преподавателей на главной странице. Выберите преподавателей и отредактируйте текст под заголовком.</p>'),
|
||
Field::make('textarea', 'front_teachers_text', 'Текст под заголовком')
|
||
->set_default_value('Каждый педагог имеет опыт работы с дошкольниками от 5 лет. Все — действующие учителя начальных классов с высшим образованием.')
|
||
->set_help_text('Текст описания перед карточками преподавателей.'),
|
||
Field::make('complex', 'front_teachers', 'Преподаватели на странице')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте преподавателей для главной страницы. Если не добавить ни одного — покажутся все.')
|
||
->add_fields(array(
|
||
Field::make('select', 'teacher_id', 'Выберите преподавателя')
|
||
->set_options(array( 0 => '— Выберите преподавателя —' ) + dekart_get_teacher_options())
|
||
->set_width(100)
|
||
->set_help_text('ФИО и фото подтянутся из карточки преподавателя.'),
|
||
)),
|
||
))
|
||
->add_tab('🎥 Видео-тур', array(
|
||
Field::make('text', 'front_video_url', 'Ссылка на видео (YouTube/VK)')
|
||
->set_help_text('Вставьте ссылку на видео-экскурсию по школе. Если поле пустое — секция не показывается.'),
|
||
))
|
||
->add_tab('📅 День из жизни', array(
|
||
Field::make('html', 'front_daylife_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Таймлайн «День из жизни ученика». Добавьте 4–6 этапов с фото и текстом.</p>'),
|
||
Field::make('complex', 'front_daylife', 'Этапы дня')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'time', 'Время')
|
||
->set_width(20)
|
||
->set_help_text('Например: 8:30, 10:00'),
|
||
Field::make('text', 'title', 'Заголовок')
|
||
->set_width(30)
|
||
->set_help_text('Например: Зарядка, Уроки, Обед'),
|
||
Field::make('textarea', 'desc', 'Описание')
|
||
->set_width(50),
|
||
Field::make('image', 'photo', 'Фото')
|
||
->set_width(30),
|
||
)),
|
||
))
|
||
->add_tab('🌟 Истории успеха', array(
|
||
Field::make('html', 'front_stories_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Персональные кейсы учеников. Добавьте 2–3 истории с фото.</p>'),
|
||
Field::make('complex', 'front_stories', 'Истории')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'student_name', 'Имя ученика')
|
||
->set_width(25),
|
||
Field::make('text', 'age', 'Возраст / класс')
|
||
->set_width(15),
|
||
Field::make('textarea', 'problem', 'Проблема / запрос')
|
||
->set_width(60),
|
||
Field::make('textarea', 'result', 'Результат / достижение')
|
||
->set_width(60),
|
||
Field::make('image', 'photo', 'Фото (до/после)')
|
||
->set_width(30)
|
||
->set_help_text('Фото ребёнка (с согласия родителей)'),
|
||
)),
|
||
))
|
||
->add_tab('❓ FAQ', array(
|
||
Field::make('complex', 'front_faq', 'Вопросы и ответы')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте частые вопросы родителей. Если не добавить ни одного — секция не покажется.')
|
||
->add_fields(array(
|
||
Field::make('text', 'faq_question', 'Вопрос')
|
||
->set_width(30),
|
||
Field::make('textarea', 'faq_answer', 'Ответ')
|
||
->set_width(70),
|
||
)),
|
||
))
|
||
->add_tab('💰 Стоимость', array(
|
||
Field::make('html', 'front_price_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Карточки стоимости обучения. Добавьте для каждого класса/программы свою карточку с ценой и списком критериев.</p>'),
|
||
Field::make('complex', 'price_cards', 'Карточки стоимости')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте карточки для каждого класса (например: «Начальная школа», «Подготовка к школе», «Продлёнка»). Если не добавить ни одной — секция не покажется.')
|
||
->add_fields(array(
|
||
Field::make('text', 'class_name', 'Название класса / программы')
|
||
->set_width(30)
|
||
->set_help_text('Например: «Начальная школа (1–4 класс)»'),
|
||
Field::make('text', 'price', 'Стоимость')
|
||
->set_width(30)
|
||
->set_help_text('Например: «от 25 000 ₽/мес»'),
|
||
Field::make('textarea', 'features', 'Критерии (по одному на строку)')
|
||
->set_width(40)
|
||
->set_help_text('Каждая строка — отдельный критерий с галочкой. Пример для начальной школы:<br><br>Классы до 10 человек<br>Уроки до 13:00, продлёнка до 19:00<br>Продлёнка: обед, полдник, ДЗ, кружки<br>Английский язык с 1 класса<br>Лицензия Минобр МО<br>Помощь с домашними заданиями<br>Спортивные и творческие кружки<br><br>Пример для продлёнки:<br><br>Присмотр с 12:00 до 19:00<br>Горячий обед и полдник<br>Помощь с уроками<br>Прогулки на свежем воздухе<br>Творческие занятия'),
|
||
)),
|
||
))
|
||
->add_tab('📊 Сравнение', array(
|
||
Field::make('html', 'front_compare_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Таблица сравнения «Декарт vs Государственная школа». Каждая строка — отдельная запись. Порядок = порядок вывода.</p>'),
|
||
Field::make('text', 'compare_header_param', 'Заголовок колонки «Параметр»')
|
||
->set_width(33)
|
||
->set_default_value('Параметр'),
|
||
Field::make('text', 'compare_header_dekart', 'Заголовок колонки «Декарт»')
|
||
->set_width(33)
|
||
->set_default_value('🎓 «Декарт»'),
|
||
Field::make('text', 'compare_header_state', 'Заголовок колонки «Гос. школа»')
|
||
->set_width(33)
|
||
->set_default_value('📚 Государственная'),
|
||
Field::make('complex', 'compare_rows', 'Строки сравнения')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте строки сравнения. Для каждой строки: параметр, текст для Декарт, текст для государственной школы.')
|
||
->add_fields(array(
|
||
Field::make('text', 'param', 'Параметр')
|
||
->set_width(100)
|
||
->set_help_text('Название параметра, например: «Число учеников в классе»'),
|
||
Field::make('html', 'compare_dekart_sep', '')
|
||
->set_html('<hr style="margin:12px 0;border:none;border-top:1px solid #e2e8f0;"><h4 style="margin:4px 0;">🔸 Декарт</h4>'),
|
||
Field::make('textarea', 'dekart', 'Текст (Декарт)')
|
||
->set_width(100)
|
||
->set_help_text('Текст для колонки «Декарт» с галочкой. Например: «До 10 человек — малые классы»'),
|
||
Field::make('html', 'compare_state_sep', '')
|
||
->set_html('<h4 style="margin:8px 0 4px;">🔸 Государственная школа</h4>'),
|
||
Field::make('textarea', 'state', 'Текст (Гос. школа)')
|
||
->set_width(100)
|
||
->set_help_text('Текст для колонки «Государственная школа» с крестиком. Например: «30–35 человек»'),
|
||
)),
|
||
))
|
||
->add_tab('💬 Слово руководителю', array(
|
||
Field::make('html', 'front_expert_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Блок цитаты руководителя школы для повышения доверия (E-E-A-T).</p>'),
|
||
Field::make('textarea', 'expert_quote_text', 'Текст цитаты')
|
||
->set_width(100)
|
||
->set_help_text('Основная цитата руководителя. Если поле пустое — блок не показывается.'),
|
||
Field::make('text', 'expert_quote_author', 'Имя руководителя')
|
||
->set_width(50)
|
||
->set_help_text('Оставьте пустым, чтобы использовать имя из Настроек филиала.'),
|
||
Field::make('text', 'expert_quote_role', 'Должность / регалии')
|
||
->set_width(50)
|
||
->set_help_text('Оставьте пустым, чтобы использовать данные из Настроек филиала.'),
|
||
Field::make('image', 'expert_quote_photo', 'Фото руководителя')
|
||
->set_width(50)
|
||
->set_help_text('Оставьте пустым, чтобы использовать фото из Настроек филиала. Рекомендуемый размер: 200×200px.'),
|
||
Field::make('text', 'expert_quote_title', 'Заголовок секции')
|
||
->set_width(50)
|
||
->set_default_value('Почему родители выбирают «Декарт»'),
|
||
Field::make('textarea', 'expert_quote_subtitle', 'Подзаголовок секции')
|
||
->set_width(50)
|
||
->set_default_value('Руководитель школы делится ценностями и подходом к обучению'),
|
||
))
|
||
->add_tab('👁️ Видимость секций', array(
|
||
Field::make('html', 'front_visibility_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Включите/отключите показ секций на главной странице. Секции HERO, КОНТАКТЫ и Sticky CTA — всегда показаны.</p>'),
|
||
Field::make('checkbox', 'section_visible_services', '📋 Услуги')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_comparison', '📊 Сравнение')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_faq', '❓ FAQ')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_video', '🎥 Видео-тур')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_daylife', '📅 День из жизни')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_stories', '🌟 Истории успеха')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_cta', '📞 CTA-консультация')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_reviews', '⭐ Отзывы / ссылка')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_teachers', '👨🏫 Преподаватели')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_expert_quotes', '💬 Слово руководителю')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
Field::make('checkbox', 'section_visible_price', '💰 Стоимость (price cards)')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
));
|
||
|
||
// ====================================================
|
||
// Страница начальной школы — вкладки (как главная)
|
||
// ====================================================
|
||
|
||
// Общий список иконок для карточек (файлы assets/images/icons/*.svg)
|
||
$school_icon_options = array(
|
||
'users' => '👥 Ученики',
|
||
'book' => '📖 Книга',
|
||
'book-2' => '📚 Книги',
|
||
'school' => '🏫 Школа',
|
||
'shield-check' => '🛡️ Защита',
|
||
'bulb' => '💡 Идея',
|
||
'chart-bar' => '📊 График',
|
||
'star' => '⭐ Звезда',
|
||
'calendar-check' => '📅 Календарь',
|
||
'camera' => '📷 Камера',
|
||
'heart' => '❤️ Сердце',
|
||
'file-description' => '📄 Документ',
|
||
'check' => '✅ Галочка',
|
||
'cash' => '💵 Деньги',
|
||
'medal-2' => '🏅 Медаль',
|
||
'fold-up' => '📂 Папка',
|
||
'scroll-hand' => '📜 Свиток',
|
||
'icon-education' => '🎓 Образование',
|
||
'icon-experience' => '🧠 Опыт',
|
||
'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;
|
||
}
|
||
}
|
||
|
||
// Программы из каталога филиала (Настройки → Филиал → «Программы и направления»).
|
||
// Преподаватель только выбирает программу; цены/ссылки — из каталога.
|
||
$teacher_program_options = array(
|
||
'' => '— Выберите программу —',
|
||
);
|
||
$branch_programs_catalog = (array) get_option('branch_programs', array());
|
||
foreach ($branch_programs_catalog as $bp_item) {
|
||
$bp_name = trim((string) ( $bp_item['name'] ?? '' ));
|
||
if ('' !== $bp_name && ! isset($teacher_program_options[ $bp_name ])) {
|
||
$teacher_program_options[ $bp_name ] = $bp_name;
|
||
}
|
||
}
|
||
|
||
// Иконки для плашек hero — только из SVG-спрайта (use href="#icon-*")
|
||
$school_hero_float_icons = array(
|
||
'teacher' => '👨🏫 Учитель',
|
||
'users' => '👥 Ученики',
|
||
'clock' => '🕐 Часы',
|
||
'book' => '📖 Книга',
|
||
'graduation' => '🎓 Выпуск',
|
||
'target' => '🎯 Цель',
|
||
'game' => '🎮 Игра',
|
||
'gift' => '🎁 Подарок',
|
||
'coin' => '🪙 Монета',
|
||
'document' => '📄 Документ',
|
||
'calendar' => '📅 Календарь',
|
||
'check-circle' => '✅ Проверено',
|
||
'star-filled' => '⭐ Звезда',
|
||
'trending-up' => '📈 Рост',
|
||
'location-pin' => '📍 Пин',
|
||
);
|
||
|
||
Container::make('post_meta', 'Настройки Начальной Школы')
|
||
->where('post_template', '=', 'page-elementary-school.php')
|
||
->add_tab('🖼️ HERO', array(
|
||
Field::make('html', 'school_hero_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Главный экран страницы. Фото — квадратное 600×600 (круглая рамка справа). Заголовок H1 и статистика.</p>'),
|
||
Field::make('image', 'banner_img_desktop', 'Фото героя')
|
||
->set_width(40)
|
||
->set_help_text('Квадратное фото 600×600px. Показывается справа в круглой рамке.'),
|
||
Field::make('text', 'banner_h1', 'Заголовок H1')
|
||
->set_width(60)
|
||
->set_help_text('Главный заголовок страницы. Пример: «Начальная школа «Декарт» — 1–4 классы в Щёлково».'),
|
||
Field::make('textarea', 'school_hero_subtitle', 'Подзаголовок')
|
||
->set_default_value('Мини-классы до 10 учеников, английский с 1 класса и продлёнка до 19:00. Официальное прикрепление к московской школе — аттестат государственного образца.')
|
||
->set_help_text('Короткий текст под заголовком. Можно выделять важное <strong>жирным</strong>.'),
|
||
Field::make('html', 'school_hero_stats_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">📊 Показатели статистики</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">3 карточки с цифрами под заголовком.</p>'),
|
||
Field::make('complex', 'hero_stats', 'Показатели')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'stat_number', 'Число')
|
||
->set_width(30)
|
||
->set_help_text('Например: до 10, 1–4, с 1 кл.'),
|
||
Field::make('text', 'stat_label', 'Подпись')
|
||
->set_width(70)
|
||
->set_help_text('Например: человек в классе, классы начальной школы.'),
|
||
)),
|
||
Field::make('html', 'school_hero_floats_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">💬 Плашки (мобильные USP + плавающие блоки)</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">До 3 коротких преимуществ. На десктопе — плавающие карточки на фото, на мобильном — под заголовком.</p>'),
|
||
Field::make('complex', 'school_hero_floats', 'Плашки')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('select', 'icon', 'Иконка')
|
||
->set_width(30)
|
||
->set_options($school_hero_float_icons)
|
||
->set_help_text('Выберите иконку из списка.'),
|
||
Field::make('text', 'text', 'Текст')
|
||
->set_width(70)
|
||
->set_help_text('Короткая фраза. Пример: «Педагоги с опытом от 10 лет».'),
|
||
)),
|
||
Field::make('html', 'school_hero_assurance_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">🤝 Пункты доверия</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">Галочки под кнопкой записи. Снимают возражения.</p>'),
|
||
Field::make('complex', 'school_hero_assurance', 'Пункты доверия')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'text', 'Текст')
|
||
->set_help_text('Пример: «Можно просто прийти и посмотреть».'),
|
||
)),
|
||
Field::make('html', 'school_cta_label_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">🔘 Текст кнопок записи</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">Один текст для всех кнопок «Записаться» на странице.</p>'),
|
||
Field::make('text', 'school_cta_label', 'Текст кнопки записи')
|
||
->set_default_value('Записаться на экскурсию')
|
||
->set_width(100),
|
||
))
|
||
->add_tab('🏫 Классы 1–4', array(
|
||
Field::make('html', 'school_classes_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Навигационные карточки классов сразу под героем. Каждая ведёт на свою страницу.</p>'),
|
||
Field::make('text', 'school_classes_title', 'Заголовок секции')
|
||
->set_default_value('Классы начальной школы 1–4')
|
||
->set_width(50),
|
||
Field::make('text', 'school_classes_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Выберите класс — узнайте о программе, особенностях обучения и поступлении.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_classes', 'Карточки классов')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте 4 карточки (1–4 класс). Порядок = порядок вывода.')
|
||
->add_fields(array(
|
||
Field::make('text', 'num', 'Номер класса')
|
||
->set_width(15)
|
||
->set_help_text('Цифра на карточке. Пример: 1'),
|
||
Field::make('text', 'title', 'Заголовок')
|
||
->set_width(30)
|
||
->set_help_text('Пример: 1 класс'),
|
||
Field::make('textarea', 'text', 'Описание')
|
||
->set_width(55)
|
||
->set_help_text('1–2 предложения о программе класса.'),
|
||
Field::make('text', 'url', 'Ссылка на страницу класса')
|
||
->set_help_text('Начинается с /. Пример: /1-klass/'),
|
||
)),
|
||
))
|
||
->add_tab('⭐ Преимущества', array(
|
||
Field::make('html', 'school_advantages_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Карточки преимуществ школы. Цвет рамки и иконка подбираются автоматически по порядку.</p>'),
|
||
Field::make('text', 'school_advantages_title', 'Заголовок секции')
|
||
->set_default_value('Наши преимущества')
|
||
->set_width(100),
|
||
Field::make('complex', 'advantages', 'Карточки преимуществ')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Рекомендуется 6 карточек (2 ряда по 3).')
|
||
->add_fields(array(
|
||
Field::make('text', 'advantages_title', 'Заголовок')
|
||
->set_width(50),
|
||
Field::make('textarea', 'advantages_text', 'Текст')
|
||
->set_width(50),
|
||
Field::make('text', 'advantages_link', 'Ссылка «Узнать подробнее» (URL или #)')
|
||
->set_help_text('Начинается с /. Оставьте пустым, чтобы убрать ссылку.'),
|
||
)),
|
||
))
|
||
->add_tab('🚪 День открытых дверей', array(
|
||
Field::make('html', 'school_openday_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция записи на экскурсию: список пунктов + фото школы. Телефон берётся из настроек филиала.</p>'),
|
||
Field::make('text', 'school_open_day_lead', 'Вводный текст')
|
||
->set_default_value('Хотите убедиться, что наша школа идеально подойдёт вашему ребёнку?')
|
||
->set_width(100),
|
||
Field::make('text', 'school_open_day_title', 'Заголовок секции')
|
||
->set_default_value('Записаться на день открытых дверей')
|
||
->set_width(100),
|
||
Field::make('complex', 'school_open_day_points', 'Пункты (что будет на встрече)')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Список с галочками. Пример: «Экскурсия по школе».')
|
||
->add_fields(array(
|
||
Field::make('text', 'text', 'Пункт'),
|
||
)),
|
||
Field::make('image', 'school_open_day_photo', 'Фото школы')
|
||
->set_width(50)
|
||
->set_help_text('Рекомендуемый размер: 550×390px. Справа от текста.'),
|
||
Field::make('text', 'school_open_day_footnote', 'Примечание под кнопкой')
|
||
->set_default_value('Бесплатно · 30 минут · Без обязательств')
|
||
->set_width(50),
|
||
))
|
||
->add_tab('📋 Персональный план', array(
|
||
Field::make('html', 'school_plan_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция «Персональный план развития»: основной текст + 3 выгоды + плашка с цифрой.</p>'),
|
||
Field::make('text', 'school_plan_title', 'Заголовок секции')
|
||
->set_default_value('Персональный план развития для каждого ученика')
|
||
->set_width(100),
|
||
Field::make('textarea', 'block_text_1', 'Основной текст секции')
|
||
->set_help_text('1–2 абзаца о персональном плане развития.'),
|
||
Field::make('complex', 'school_plan_benefits', 'Выгоды (3 пункта с галочками)')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'text', 'Текст выгоды'),
|
||
)),
|
||
Field::make('html', 'school_plan_badge_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">🔢 Плашка на фото</h3>'),
|
||
Field::make('text', 'school_plan_badge_num', 'Число в плашке')
|
||
->set_default_value('до 10')
|
||
->set_width(30),
|
||
Field::make('text', 'school_plan_badge_label', 'Подпись плашки')
|
||
->set_default_value('учеников в классе')
|
||
->set_width(70),
|
||
))
|
||
->add_tab('📚 Программа и кружки', array(
|
||
Field::make('html', 'school_program_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Программа обучения по классам + список кружков.</p>'),
|
||
Field::make('text', 'school_program_title', 'Заголовок секции')
|
||
->set_default_value('Программа обучения 1–4 классов')
|
||
->set_width(50),
|
||
Field::make('text', 'school_program_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Программы «Перспектива» и система Занкова, углублённый английский — и кружки для всестороннего развития.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_programs', 'Программа по классам')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('4 карточки (1–4 класс).')
|
||
->add_fields(array(
|
||
Field::make('text', 'title', 'Класс')
|
||
->set_width(20)
|
||
->set_help_text('Пример: 1 класс'),
|
||
Field::make('textarea', 'items', 'Предметы')
|
||
->set_width(80)
|
||
->set_help_text('Список предметов через запятую.'),
|
||
)),
|
||
Field::make('complex', 'school_clubs', 'Кружки и доп. занятия')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Каждый кружок — отдельная запись. Пример: «Ментальная арифметика».')
|
||
->add_fields(array(
|
||
Field::make('text', 'name', 'Название кружка'),
|
||
)),
|
||
))
|
||
->add_tab('🧩 Проблемы родителей', array(
|
||
Field::make('html', 'school_problems_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция «Решаем главные проблемы»: карточки «проблема → решение».</p>'),
|
||
Field::make('text', 'school_problems_title', 'Заголовок секции')
|
||
->set_default_value('Решаем главные проблемы родителей и учеников в начальной школы')
|
||
->set_width(50),
|
||
Field::make('text', 'school_problems_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Мы продумали каждую деталь обучения, чтобы вы были спокойны за ребёнка.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_problems', 'Карточки проблем')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('5 карточек. Заголовок — тревога родителя, текст — как школа её решает.')
|
||
->add_fields(array(
|
||
Field::make('text', 'title', 'Заголовок')
|
||
->set_width(40),
|
||
Field::make('textarea', 'text', 'Текст')
|
||
->set_width(60),
|
||
)),
|
||
))
|
||
->add_tab('🌱 Адаптация', array(
|
||
Field::make('html', 'school_adaptation_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция «Мягкая адаптация первоклассника» — 4 карточки с иконками.</p>'),
|
||
Field::make('text', 'school_adaptation_title', 'Заголовок секции')
|
||
->set_default_value('Мягкая адаптация первоклассника')
|
||
->set_width(50),
|
||
Field::make('text', 'school_adaptation_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Первый класс — важный этап. Мы делаем его спокойным и радостным для ребёнка и родителей.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_adaptation', 'Карточки адаптации')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('select', 'icon', 'Иконка')
|
||
->set_width(30)
|
||
->set_options($school_icon_options),
|
||
Field::make('text', 'title', 'Заголовок')
|
||
->set_width(70),
|
||
Field::make('textarea', 'text', 'Текст')
|
||
->set_width(100),
|
||
)),
|
||
))
|
||
->add_tab('🛡️ Безопасность', array(
|
||
Field::make('html', 'school_safety_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция «Безопасность ребёнка» — 4 карточки с иконками.</p>'),
|
||
Field::make('text', 'school_safety_title', 'Заголовок секции')
|
||
->set_default_value('Безопасность ребёнка — наш приоритет')
|
||
->set_width(50),
|
||
Field::make('text', 'school_safety_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Мы создали среду, в которой дети чувствуют себя защищённо — и могут спокойно учиться.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_safety', 'Карточки безопасности')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('select', 'icon', 'Иконка')
|
||
->set_width(30)
|
||
->set_options($school_icon_options),
|
||
Field::make('text', 'title', 'Заголовок')
|
||
->set_width(70),
|
||
Field::make('textarea', 'text', 'Текст')
|
||
->set_width(100),
|
||
)),
|
||
))
|
||
->add_tab('⚖️ Сравнение с госшколой', array(
|
||
Field::make('html', 'school_compare_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Таблица «Декарт vs Государственная школа» + яркая цифра. Вводный текст — «лид» справа от заголовка.</p>'),
|
||
Field::make('text', 'school_compare_title', 'Заголовок секции')
|
||
->set_default_value('Частная школа «Декарт» или государственная?')
|
||
->set_width(100),
|
||
Field::make('textarea', 'block_text_2', 'Вводный текст (лид)')
|
||
->set_help_text('Короткий абзац справа от заголовка «Частная школа или государственная?».'),
|
||
Field::make('html', 'school_compare_hl_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">🔆 Яркая цифра (highlight)</h3>'),
|
||
Field::make('text', 'school_compare_hl_num', 'Цифра')
|
||
->set_default_value('до 30')
|
||
->set_width(20),
|
||
Field::make('text', 'school_compare_hl_text', 'Пояснение к цифре')
|
||
->set_default_value('учеников на одного учителя в государственной школе — и персональное внимание каждому ребёнку в «Декарт»')
|
||
->set_width(80),
|
||
Field::make('complex', 'school_compare_rows', 'Строки таблицы')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('5 строк. Для каждой: критерий, значение в госшколе, значение в «Декарт».')
|
||
->add_fields(array(
|
||
Field::make('text', 'criteria', 'Критерий')
|
||
->set_width(100),
|
||
Field::make('text', 'gov', 'Государственная школа')
|
||
->set_width(50),
|
||
Field::make('text', 'private', 'Школа «Декарт»')
|
||
->set_width(50),
|
||
)),
|
||
))
|
||
->add_tab('🤝 Гарантии', array(
|
||
Field::make('html', 'school_guarantees_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция «На что вы можете рассчитывать» — 4 карточки-гарантии.</p>'),
|
||
Field::make('text', 'school_guarantees_title', 'Заголовок секции')
|
||
->set_default_value('На что вы можете рассчитывать')
|
||
->set_width(50),
|
||
Field::make('text', 'school_guarantees_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Мы отвечаем за качество обучения и комфорт вашего ребёнка.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_guarantees', 'Карточки гарантий')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('select', 'icon', 'Иконка')
|
||
->set_width(30)
|
||
->set_options($school_icon_options),
|
||
Field::make('text', 'title', 'Заголовок')
|
||
->set_width(70),
|
||
Field::make('textarea', 'text', 'Текст')
|
||
->set_width(100),
|
||
)),
|
||
))
|
||
->add_tab('📈 Результаты', array(
|
||
Field::make('html', 'school_results_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция «Результаты наших учеников» — 4 цифры с подписями.</p>'),
|
||
Field::make('text', 'school_results_title', 'Заголовок секции')
|
||
->set_default_value('Результаты наших учеников')
|
||
->set_width(50),
|
||
Field::make('text', 'school_results_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Цифры, которые говорят сами за себя: ваши дети опережают сверстников и учатся с удовольствием.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_results', 'Цифры-результаты')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'num', 'Цифра')
|
||
->set_width(30)
|
||
->set_help_text('Пример: 98%, до 10, 6–12 мес'),
|
||
Field::make('text', 'label', 'Подпись')
|
||
->set_width(70),
|
||
)),
|
||
))
|
||
->add_tab('🚀 Как поступить', array(
|
||
Field::make('html', 'school_steps_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция «Как поступить» — 4 шага поступления.</p>'),
|
||
Field::make('text', 'school_steps_title', 'Заголовок секции')
|
||
->set_default_value('Как поступить в начальную школу «Декарт»')
|
||
->set_width(50),
|
||
Field::make('text', 'school_steps_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Всего 4 простых шага — и ваш ребёнок учится в мини-классе с индивидуальным подходом.')
|
||
->set_width(50),
|
||
Field::make('complex', 'school_steps', 'Шаги поступления')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'num', 'Номер')
|
||
->set_width(15)
|
||
->set_help_text('Формат 01, 02, 03, 04'),
|
||
Field::make('select', 'icon', 'Иконка')
|
||
->set_width(25)
|
||
->set_options($school_icon_options),
|
||
Field::make('text', 'title', 'Заголовок')
|
||
->set_width(60),
|
||
Field::make('textarea', 'text', 'Текст')
|
||
->set_width(100),
|
||
)),
|
||
))
|
||
->add_tab('📸 Галерея', array(
|
||
Field::make('html', 'school_gallery_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Мини-галерея 2–4 фото. Если пусто — секция не показывается.</p>'),
|
||
Field::make('complex', 'school_gallery', 'Фотографии')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('image', 'photo', 'Фотография')
|
||
->set_help_text('Рекомендуемый размер: 868×1156px (портретная).'),
|
||
)),
|
||
))
|
||
->add_tab('❓ FAQ', array(
|
||
Field::make('html', 'school_faq_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Вопросы и ответы. Разметка FAQPage JSON-LD генерируется автоматически. Если пусто — секция скрыта.</p>'),
|
||
Field::make('text', 'school_faq_title', 'Заголовок секции')
|
||
->set_default_value('Часто задаваемые вопросы')
|
||
->set_width(50),
|
||
Field::make('text', 'school_faq_subtitle', 'Подзаголовок секции')
|
||
->set_default_value('Ответы на главные вопросы родителей о начальной школе «Декарт»')
|
||
->set_width(50),
|
||
Field::make('complex', 'questions', 'Вопросы и ответы')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('textarea', 'questions_question', 'Вопрос')
|
||
->set_width(30),
|
||
Field::make('textarea', 'questions_answer', 'Ответ')
|
||
->set_width(70),
|
||
)),
|
||
))
|
||
->add_tab('✅ Готовность к школе', array(
|
||
Field::make('html', 'school_readiness_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Секция-ссылка на интерактивный тест готовности к школе.</p>'),
|
||
Field::make('text', 'school_readiness_title', 'Заголовок')
|
||
->set_default_value('Готов ли ребёнок к школе?')
|
||
->set_width(50),
|
||
Field::make('textarea', 'school_readiness_text', 'Текст')
|
||
->set_default_value('Пройдите короткий тест из 12 вопросов и получите персональные рекомендации по подготовке ребёнка к 1 классу. Это бесплатно и займёт 5 минут.')
|
||
->set_width(50),
|
||
Field::make('text', 'school_readiness_btn_label', 'Текст кнопки')
|
||
->set_default_value('Пройти тест')
|
||
->set_width(30),
|
||
Field::make('text', 'school_readiness_btn_url', 'URL кнопки')
|
||
->set_default_value('/test-gotovnost-k-shkole/')
|
||
->set_width(30),
|
||
Field::make('text', 'school_readiness_time', 'Подпись «сколько времени»')
|
||
->set_default_value('~5 минут · 12 вопросов · Бесплатно')
|
||
->set_width(40),
|
||
))
|
||
->add_tab('🏁 CTA и фото', array(
|
||
Field::make('html', 'school_cta_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Акцентная CTA-секция с фото (после сравнения). Фото широкое.</p>'),
|
||
Field::make('text', 'school_accent_eyebrow', 'Надзаголовок (eyebrow)')
|
||
->set_default_value('Приходите знакомиться')
|
||
->set_width(50),
|
||
Field::make('text', 'school_accent_title', 'Заголовок')
|
||
->set_default_value('Увидеть школу — лучше, чем прочитать о ней')
|
||
->set_width(50),
|
||
Field::make('textarea', 'school_accent_text', 'Текст')
|
||
->set_default_value('Посмотрите классы, познакомьтесь с педагогами и почувствуйте атмосферу лично. Экскурсия бесплатна, длится 30 минут и ни к чему не обязывает.'),
|
||
Field::make('image', 'school_accent_photo', 'Фото для CTA-секции')
|
||
->set_help_text('Широкий баннер. Рекомендуемый размер: 1295×454px.'),
|
||
Field::make('html', 'school_cta_why_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">📝 Секция «Почему частная школа»</h3>'),
|
||
Field::make('text', 'school_why_private_title', 'Заголовок секции «Почему частная школа»')
|
||
->set_default_value('Почему начальная частная школа «Декарт», а не государственная?')
|
||
->set_width(100),
|
||
Field::make('textarea', 'school_why_private_text', 'Текст секции «Почему частная школа»')
|
||
->set_help_text('Абзац с аргументами в пользу частной школы.'),
|
||
Field::make('image', 'school_why_private_photo', 'Фото ученика')
|
||
->set_width(50)
|
||
->set_help_text('Рекомендуемый размер: 273×285px.'),
|
||
Field::make('html', 'school_cta_final_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">🏁 Финальный CTA</h3>'),
|
||
Field::make('text', 'school_final_cta_title', 'Заголовок финального CTA')
|
||
->set_default_value('Готовы записать ребёнка в начальную школу?')
|
||
->set_width(50),
|
||
Field::make('textarea', 'school_final_cta_text', 'Текст финального CTA')
|
||
->set_default_value('Позвоните нам или оставьте заявку — ответим на все вопросы и пригласим на экскурсию.')
|
||
->set_width(50),
|
||
Field::make('html', 'school_cta_family_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">🔗 Перелинковка (семейные классы)</h3>'),
|
||
Field::make('complex', 'school_family_links', 'Ссылки-рекомендации')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('До 3 ссылок в блоке «Узнайте больше о форматах обучения».')
|
||
->add_fields(array(
|
||
Field::make('text', 'text', 'Текст ссылки')
|
||
->set_width(70),
|
||
Field::make('text', 'url', 'Ссылка (URL или #якорь)')
|
||
->set_width(30),
|
||
)),
|
||
))
|
||
->add_tab('📝 Прочее', array(
|
||
Field::make('html', 'school_misc_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Служебные поля. Обычно не требуют редактирования.</p>'),
|
||
Field::make('textarea', 'teachers_block', 'Текст в блоке «Наша команда»'),
|
||
Field::make('textarea', 'block_text_3', 'Текст для блока «Семейные классы в Щёлково» (зарезервировано)'),
|
||
));
|
||
|
||
// ====================================================
|
||
// Страница КЛАССА начальной школы (page-class.php)
|
||
// ====================================================
|
||
Container::make('post_meta', '🏫 Настройки Страницы Класса')
|
||
->where('post_template', '=', 'page-class.php')
|
||
->add_tab('🖼️ HERO', array(
|
||
Field::make('html', 'class_hero_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Главный экран страницы класса. Заголовок H1 — под поисковый запрос «частная школа [N] класс [город]». Фото — горизонтальное 1200×800px, WebP/JPEG, до 2 МБ.</p>'),
|
||
Field::make('text', 'class_hero_title', 'Заголовок H1')
|
||
->set_width(60)
|
||
->set_default_value('Частная школа 1 класс в Щёлково')
|
||
->set_help_text('Главный заголовок. Пример: «Частная школа 2 класс в Щёлково: набор 2026/27».'),
|
||
Field::make('image', 'class_hero_image', 'Фото героя')
|
||
->set_width(40)
|
||
->set_help_text('Горизонтальное фото 1200×800px. Показывается в правой части героя.'),
|
||
Field::make('textarea', 'class_hero_subtitle', 'Подзаголовок')
|
||
->set_default_value('Мини-класс до 15 учеников, учитель начальных классов и английский каждый день. Официальное прикрепление к московской школе — аттестат государственного образца.')
|
||
->set_help_text('Короткий текст под заголовком (2–3 предложения). Можно выделять важное <strong>жирным</strong>.'),
|
||
Field::make('html', 'class_hero_btn_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">🔘 Кнопка записи</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">Единая CTA на странице. Ведите на форму записи или мессенджер.</p>'),
|
||
Field::make('text', 'class_hero_btn_text', 'Текст кнопки')
|
||
->set_width(50)
|
||
->set_default_value('Записаться на пробный урок')
|
||
->set_help_text('Конверсионный интент: «Записаться на пробный урок» / «Записаться на экскурсию».'),
|
||
Field::make('text', 'class_hero_btn_url', 'Ссылка кнопки')
|
||
->set_width(50)
|
||
->set_default_value('#form')
|
||
->set_help_text('URL формы записи, страницы контактов или мессенджера. Начинается с /.'),
|
||
Field::make('html', 'class_hero_stats_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">📊 Показатели статистики</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">3 карточки с цифрами под заголовком.</p>'),
|
||
Field::make('complex', 'class_hero_stats', 'Показатели')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'stat_number', 'Число')
|
||
->set_width(30)
|
||
->set_help_text('Например: до 15, 5, 8:30.'),
|
||
Field::make('text', 'stat_label', 'Подпись')
|
||
->set_width(70)
|
||
->set_help_text('Например: человек в классе, дней в неделю, старт занятий.'),
|
||
)),
|
||
))
|
||
->add_tab('📚 Программа', array(
|
||
Field::make('html', 'class_program_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Программа обучения класса: описание + список предметов (6–8 карточек) + галерея фото класса. Рекомендуемый объём текста 200–300 символов.</p>'),
|
||
Field::make('text', 'class_program_title', 'Заголовок блока')
|
||
->set_default_value('Программа обучения'),
|
||
Field::make('rich_text', 'class_program_text', 'Описание программы')
|
||
->set_help_text('2–3 абзаца об учебном плане класса. Укажите ключевые предметы и особенности.'),
|
||
Field::make('complex', 'class_program_items', 'Предметы')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Рекомендуется 6–8 карточек. Иконка — название из набора (book, math, pen, globe, music, art, sport, science, computer, shield).')
|
||
->add_fields(array(
|
||
Field::make('text', 'item_icon', 'Иконка')
|
||
->set_width(20)
|
||
->set_help_text('book, math, pen, globe, music, art, sport, science, computer, shield.'),
|
||
Field::make('text', 'item_title', 'Название предмета')
|
||
->set_width(40),
|
||
Field::make('textarea', 'item_text', 'Краткое описание')
|
||
->set_width(40)
|
||
->set_help_text('1–2 предложения. Что изучают, результат.'),
|
||
)),
|
||
Field::make('html', 'class_gallery_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">📸 Фото класса</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">3–4 фото 800×600px, WebP/JPEG. Выводятся галереей.</p>'),
|
||
Field::make('complex', 'class_program_gallery', 'Галерея')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('image', 'gallery_image', 'Фото')
|
||
->set_help_text('Рекомендуемый размер 800×600px.'),
|
||
)),
|
||
))
|
||
->add_tab('👨🏫 Преподаватели', array(
|
||
Field::make('html', 'class_teachers_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Учителя класса. Выберите преподавателей из картотеки «Преподаватели». Если ничего не выбрано — покажутся все преподаватели школы.</p>'),
|
||
Field::make('text', 'class_teachers_title', 'Заголовок блока')
|
||
->set_default_value('Преподаватели класса'),
|
||
Field::make('text', 'class_teachers_subtitle', 'Подзаголовок')
|
||
->set_default_value('Учитель начальных классов и педагоги-предметники, которые ведут уроки в этом классе')
|
||
->set_help_text('Короткий текст под заголовком.'),
|
||
Field::make('association', 'class_teachers', 'Преподаватели')
|
||
->set_types(array(
|
||
array('type' => 'post', 'post_type' => 'teacher'),
|
||
))
|
||
->set_max(12)
|
||
->set_help_text('Выберите учителей для этого класса. Пусто = показать всех преподавателей школы.'),
|
||
))
|
||
->add_tab('🗓 Расписание и стоимость', array(
|
||
Field::make('html', 'class_schedule_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Расписание занятий класса и стоимость обучения. Если стоимость не заполнена — подтянется глобальная цена из настроек филиала.</p>'),
|
||
Field::make('text', 'class_schedule_title', 'Заголовок блока')
|
||
->set_default_value('Расписание и стоимость'),
|
||
Field::make('complex', 'class_schedule', 'Расписание')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('5–10 строк: день недели, время, предмет.')
|
||
->add_fields(array(
|
||
Field::make('select', 'schedule_day', 'День')
|
||
->set_width(25)
|
||
->add_options(array(
|
||
'Понедельник' => 'Понедельник',
|
||
'Вторник' => 'Вторник',
|
||
'Среда' => 'Среда',
|
||
'Четверг' => 'Четверг',
|
||
'Пятница' => 'Пятница',
|
||
)),
|
||
Field::make('text', 'schedule_time', 'Время')
|
||
->set_width(25)
|
||
->set_help_text('Например: 9:00–9:45.'),
|
||
Field::make('text', 'schedule_subject', 'Предмет')
|
||
->set_width(50)
|
||
->set_help_text('Например: Математика.'),
|
||
)),
|
||
Field::make('html', 'class_price_sep', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:0 0 8px;font-size:13px;color:#475569;">💰 Стоимость</h3><p style="color:#94a3b8;font-size:12px;margin:0 0 8px;">Оставьте пустым, чтобы взять глобальную цену из настроек филиала.</p>'),
|
||
Field::make('text', 'class_price_text', 'Стоимость обучения')
|
||
->set_width(60)
|
||
->set_help_text('Например: 45 000 ₽ / месяц. Пусто = глобальная цена филиала.'),
|
||
Field::make('text', 'class_price_note', 'Примечание к цене')
|
||
->set_width(40)
|
||
->set_help_text('Например: «включая питание и продлёнку».'),
|
||
))
|
||
->add_tab('💬 Отзывы', array(
|
||
Field::make('html', 'class_reviews_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Отзывы родителей о школе. Выберите из картотеки «Отзывы». Если ничего не выбрано — покажутся последние отзывы школы.</p>'),
|
||
Field::make('text', 'class_reviews_title', 'Заголовок блока')
|
||
->set_default_value('Отзывы родителей'),
|
||
Field::make('association', 'class_reviews', 'Отзывы')
|
||
->set_types(array(
|
||
array('type' => 'post', 'post_type' => 'reviews'),
|
||
))
|
||
->set_max(6)
|
||
->set_help_text('Выберите 3–6 отзывов. Пусто = последние отзывы из картотеки.'),
|
||
))
|
||
->add_tab('❓ FAQ', array(
|
||
Field::make('html', 'class_faq_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Вопросы-ответы о классе. Выводятся на странице и в микроразметке FAQPage (для поисковой выдачи). Рекомендуется 4–6 пар.</p>'),
|
||
Field::make('text', 'class_faq_title', 'Заголовок блока')
|
||
->set_default_value('Часто задаваемые вопросы'),
|
||
Field::make('complex', 'class_faq_items', 'Вопросы')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('textarea', 'faq_question', 'Вопрос')
|
||
->set_width(50),
|
||
Field::make('textarea', 'faq_answer', 'Ответ')
|
||
->set_width(50)
|
||
->set_help_text('Развёрнутый ответ 1–3 предложения.'),
|
||
)),
|
||
))
|
||
->add_tab('📊 SEO', array(
|
||
Field::make('html', 'class_seo_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">SEO-поля страницы класса. Основные title/description задаёт Yoast SEO (блок ниже редактора). Эти поля переопределяют их и используются в Schema.org разметке. Заполнять по желанию — при пустых значениях берутся Yoast/стандартные.</p>'),
|
||
Field::make('text', 'class_seo_title', 'SEO-заголовок (title)')
|
||
->set_width(60)
|
||
->set_help_text('Пример: «Частная школа 3 класс в Щёлково — набор 2026/27». 50–60 символов.'),
|
||
Field::make('textarea', 'class_seo_description', 'SEO-описание (meta description)')
|
||
->set_width(40)
|
||
->set_help_text('140–160 символов, с ключевым запросом и призывом.'),
|
||
Field::make('image', 'class_seo_og_image', 'Open Graph картинка')
|
||
->set_help_text('1200×630px, JPEG/PNG. Для соцсетей.'),
|
||
Field::make('checkbox', 'class_seo_noindex', 'Не индексировать (noindex)')
|
||
->set_help_text('Включите, если страница-черновик или дубль.'),
|
||
));
|
||
|
||
// ====================================================
|
||
// Доп поля для страницы "ВСЕ КУРСЫ"
|
||
// ====================================================
|
||
Container::make('post_meta', 'Настройки Страницы Все Курсы')
|
||
->where('post_template', '=', 'page-course.php')
|
||
->add_fields(array(
|
||
Field::make('image', 'banner_img_desktop', 'Изображение для баннера (десктопная версия)')
|
||
->help_text('Размер изображения (желательно) 1920px на 440px')
|
||
->set_width(15),
|
||
Field::make('image', 'banner_img_mobile', 'Изображение для баннера (мобильная версия)')
|
||
->help_text('Размер изображения (желательно) 450px на 225px')
|
||
->set_width(15),
|
||
));
|
||
|
||
// ====================================================
|
||
// Доп поля для страницы "ВАКАНСИИ"
|
||
// ====================================================
|
||
Container::make('post_meta', 'Настройки Страницы ВАКАНСИИ')
|
||
->where('post_template', '=', 'page-vacancies.php')
|
||
->add_fields(array(
|
||
Field::make('complex', 'vacancies', 'Вакансии учебного центра:')
|
||
->add_fields(array(
|
||
Field::make('text', 'vacancie_name', 'Название вакансии:'),
|
||
Field::make('text', 'vacancie_link', 'Ссылка на страницу вакансии:'),
|
||
))
|
||
));
|
||
|
||
// ====================================================
|
||
// Доп поля для страницы "КОНТАКТЫ"
|
||
// ====================================================
|
||
Container::make('post_meta', 'Настройки Страницы Контакты')
|
||
->where('post_template', '=', 'page-contacts.php')
|
||
->add_fields(array(
|
||
Field::make('image', 'img_school', 'Изображение школы:')
|
||
));
|
||
|
||
// ====================================================
|
||
// Доп поля для категории (ПРЕДМЕТ)
|
||
// ====================================================
|
||
Container::make('term_meta', 'Category Properties')
|
||
->where('term_taxonomy', '=', 'subject')
|
||
->show_on_level(1)
|
||
->where('term_level', '=', 1)
|
||
->add_fields(array(
|
||
Field::make('text', 'subject_h1', 'Заголовок H1:')
|
||
->set_width(100)
|
||
));
|
||
|
||
// ====================================================
|
||
// Доп поля для сущностей reviews (ОТЗЫВ)
|
||
// ====================================================
|
||
Container::make('post_meta', 'Поля для отзыва')
|
||
->where('post_type', '=', 'reviews')
|
||
->add_fields(array(
|
||
Field::make('radio', 'review_type', 'Тип отзыва')
|
||
->set_options([
|
||
'camp' => 'О лагере',
|
||
'school' => 'О школе',
|
||
'primary' => 'О начальной школе',
|
||
])
|
||
->set_default_value('school')
|
||
->set_help_text('Выберите тип отзыва'),
|
||
Field::make('image', 'review_avatar', 'Автар:')
|
||
->set_width(15),
|
||
Field::make('text', 'review_star', 'Оценка:')
|
||
->set_attribute('type', 'number'),
|
||
Field::make('textarea', 'review_text', 'Текст отзыва:')
|
||
->set_width(100),
|
||
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('Дата отзыва. Формат: ДД.ММ.ГГГГ'),
|
||
Field::make('association', 'review_teacher', 'Выберите преподавателя:')
|
||
->set_width(32)
|
||
->set_types(array(
|
||
array(
|
||
'type' => 'post',
|
||
'post_type' => 'teacher',
|
||
)
|
||
))
|
||
->set_required(true)
|
||
->set_max(1)
|
||
->help_text('выбирается только один'),
|
||
Field::make('checkbox', 'review_show_on_front', 'Показывать на главной')
|
||
->set_option_value('yes')
|
||
->set_help_text('Отметьте, чтобы отзыв отображался в секции отзывов на главной странице'),
|
||
));
|
||
|
||
// ====================================================
|
||
// Доп поля для записей teacher
|
||
// ====================================================
|
||
Container::make('post_meta', 'Поля для преподавателя')
|
||
->where('post_type', '=', 'teacher')
|
||
->add_tab('🎬 Hero', array(
|
||
Field::make('html', 'teacher_hero_tab_desc', '')
|
||
->set_html('<p style="color:#64748b;font-size:13px;margin:0 0 12px;">Фото и текст под заголовком на личной странице преподавателя. Если текст пуст — подставляется автоматически (направление + мини-группа + экзамен + школа и город).</p>'),
|
||
Field::make('image', 'teacher_avatar', 'Фото преподавателя (hero/карточка):')
|
||
->set_width(30),
|
||
Field::make('textarea', 'teacher_hero_subtitle', 'Текст под H1 (subtitle)')
|
||
->set_width(100)
|
||
->set_help_text('Пример: «Учитель начальных классов — мини-группы 2-6 чел. · ОГЭ/ЕГЭ · школа «Декарт» в Щёлково». Пусто — соберётся автоматически.'),
|
||
Field::make('text', 'teacher_rating', 'Оценка преподавателя (для hero и микроразметки)')
|
||
->set_width(25)
|
||
->set_default_value('5')
|
||
->set_help_text('Пример: <strong>5</strong> или <strong>4,5</strong>. Звёзды в hero и aggregateRating в Schema.org.'),
|
||
Field::make('text', 'teacher_group_size', 'Размер мини-группы (для hero, курсов, шагов и CTA)')
|
||
->set_width(25)
|
||
->set_default_value('2-6')
|
||
->set_help_text('Пример: <strong>2-6</strong>. Участвует в hero, курсах, шагах, финальном CTA и микроразметке — заполняйте всегда.'),
|
||
))
|
||
->add_tab('👤 Профиль и данные', array(
|
||
Field::make('text', 'teacher_direction', 'Направление преподавателя (текст в под фото):'),
|
||
Field::make('textarea', 'teacher_description', 'Дескрипшн преподавателя (коротко — для карточек)')
|
||
->set_width(100)
|
||
->set_help_text('Выводится в карточке преподавателя на главной и на странице «Наши преподаватели». Максимум вывода в карточке — 3 строки. Рекомендуемый размер: до 140 знаков. Более длинный текст в карточке обрезается многоточием.'),
|
||
Field::make('text', 'teacher_badge', 'Бейдж на карточке (например: 👶 Работает с дошкольниками)')
|
||
->set_width(30)
|
||
->set_help_text('Текст бейджа на карточке преподавателя. Если пусто — бейдж скрыт.'),
|
||
Field::make('text', 'teacher_start_year', 'Год начала работы (только год, например: 1987)')
|
||
->set_width(30)
|
||
->set_attribute('placeholder', '1987')
|
||
->set_help_text('Стаж рассчитается автоматически на странице подготовки к школе.'),
|
||
))
|
||
->add_tab('📄 О преподавателе', array(
|
||
Field::make('textarea', 'teacher_about', 'О себе:')
|
||
->set_width(100)
|
||
->help_text('Обычный текст, вёрстка не нужна — абзацы разделяйте пустой строкой (Enter + пустая строка). Рекомендуемый объём: 600–1200 знаков (2–4 коротких абзаца).'),
|
||
Field::make('textarea', 'teacher_education', 'Образование:'),
|
||
Field::make('textarea', 'teacher_add_education', 'Дополнительное образование:'),
|
||
Field::make('text', 'teacher_diploma', 'Учебное заведение (для микроразметки alumniOf)')
|
||
->set_width(50)
|
||
->help_text('Одно главное учебное заведение (напр. «Московский педагогический государственный университет (МПГУ)»). Используется в Schema.org для свойства alumniOf. Если пусто — свойство не выводится.'),
|
||
Field::make('text', 'teacher_video', 'Ссылка на видеопрезентацию')
|
||
->set_width(100)
|
||
->help_text('Укажите ссылку на видео в youtube. Пример: <iframe src="https://vk.com/video_ext.php?oid=-43228812&id=456240170hd=2" width="853" height="480" allow="autoplay; encrypted-media; fullscreen; picture-in-picture;" frameborder="0" allowfullscreen></iframe>'),
|
||
))
|
||
->add_tab('📚 Предметы и документы', array(
|
||
Field::make('complex', 'teacher_subjects', 'Предметы обучения')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('select', 'teacher_subjects_title', 'Программа (направление)')
|
||
->set_options($teacher_program_options)
|
||
->set_width(50)
|
||
->set_required(true)
|
||
->help_text('Выберите из каталога программ филиала (Настройки → Филиал → «Программы и направления»). Цена и ссылка на страницу подтянутся из каталога.'),
|
||
Field::make('textarea', 'teacher_subjects_topics', 'Темы направления (каждая с новой строки)')
|
||
->set_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(
|
||
Field::make('image', 'certificates_foto', 'Изображение')
|
||
))
|
||
->help_text('Добавьте изображение дипломов и сертификатов преподавателя'),
|
||
))
|
||
->add_tab('📊 Цифры и дефицит', array(
|
||
Field::make('html', 'teacher_metrics_help')
|
||
->set_html('<div style="background:#F8FAFC;border:1px solid #E2E8F0;border-radius:8px;padding:12px 14px;margin:0 0 14px;color:#334155;font-size:13px;line-height:1.6"><strong>Блок «Цифры»</strong> — карточки под hero (рейтинг, средний балл, цифра про систему, размер группы и любые другие факты). Кнопкой <strong>«+ Добавить»</strong> создаёте карточку, крестиком рядом с полями — удаляете. В каждой карточке два поля: <strong>цифра</strong> и <strong>подпись</strong>. Порядок карточек = порядок вывода на странице. Пустые карточки не выводятся. Если карточек нет — блок «Цифры» скрыт.</div>'),
|
||
Field::make('complex', 'teacher_metrics', 'Карточки цифр')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'metric_num', 'Цифра / факт')
|
||
->set_width(25)
|
||
->set_required(true)
|
||
->set_help_text('Короткое значение-результат. Примеры: <strong>5/5</strong>, <strong>100%</strong>, <strong>2-6</strong>, <strong>4,7</strong>, <strong>45 минут</strong>, <strong>500+</strong>.'),
|
||
Field::make('text', 'metric_text', 'Подпись под цифрой')
|
||
->set_width(75)
|
||
->set_help_text('Что означает цифра. Примеры: <strong>«Рейтинг преподавателя · 5 отзывов»</strong>, <strong>«учеников продолжают обучение на следующий учебный год»</strong>, <strong>«человек в мини-группе — внимание как на репетиторе»</strong>, <strong>«средний балл учеников»</strong>.'),
|
||
))
|
||
->set_help_text('«+ Добавить» — новая карточка (цифра + подпись). Нет карточек — блок «Цифры» на странице скрыт, используйте Hero-таб для рейтинга и размера группы.'),
|
||
Field::make('html', 'teacher_scarcity_sep', '')
|
||
->set_html('<hr><h3>⏳ Полоса дефицита</h3><p style="color:#64748B;font-size:12px;margin:4px 0 10px;">Жёлтая полоса под цифрами: счётчик дней до экзамена + места в группе + пояснение. Пустое поле — пункт скрыт.</p>'),
|
||
Field::make('text', 'teacher_seats_left', 'Осталось мест в группе')
|
||
->set_width(25)
|
||
->set_default_value('4')
|
||
->set_help_text('Пример: <strong>4</strong>. Полоса дефицита: «4 места в группе». Пусто/0 — пункт скрыт.'),
|
||
Field::make('text', 'teacher_exam_label', 'Экзамен/формат')
|
||
->set_width(25)
|
||
->set_default_value('ОГЭ/ЕГЭ')
|
||
->set_help_text('Пример: <strong>«ОГЭ/ЕГЭ»</strong>. Полоса дефицита: «дней до ОГЭ/ЕГЭ».'),
|
||
Field::make('text', 'teacher_exam_date', 'Дата экзамена для счётчика (YYYY-MM-DD)')
|
||
->set_width(25)
|
||
->set_default_value('')
|
||
->set_help_text('Пример: <strong>2027-05-24</strong>. Пусто — счётчик дней скрыт.'),
|
||
Field::make('text', 'teacher_scarcity_note', 'Текст полосы дефицита')
|
||
->set_width(100)
|
||
->set_default_value('Набор в группу идёт каждый месяц, но места ограничены.')
|
||
->set_help_text('Пример: <strong>«Набор в группу идёт каждый месяц, но места ограничены»</strong>. Пусто — скрыто.'),
|
||
))
|
||
->add_tab('🎨 Сегменты, кейсы, шаги', array(
|
||
Field::make('complex', 'teacher_segments', 'Сегменты учеников (карточки)')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'segment_title', 'Заголовок карточки')
|
||
->set_width(30),
|
||
Field::make('textarea', 'segment_text', 'Текст карточки')
|
||
->set_width(70),
|
||
))
|
||
->set_help_text('3 карточки «Для кого занятия». Пусто — покажутся 3 стандартные.'),
|
||
Field::make('complex', 'teacher_cases', 'Кейсы учеников (табы 9/11 класс)')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'case_tab', 'Таб (9 или 11)')
|
||
->set_width(20),
|
||
Field::make('textarea', 'case_text', 'История кейса')
|
||
->set_width(80),
|
||
))
|
||
->set_help_text('Кейсы с результатом. tab: 9 или 11 класс.'),
|
||
Field::make('complex', 'teacher_steps', 'Шаги «Как проходит первое занятие»')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'step_title', 'Название шага')
|
||
->set_width(30),
|
||
Field::make('textarea', 'step_text', 'Описание шага')
|
||
->set_width(70),
|
||
))
|
||
->set_help_text('Таймлайн: от заявки до обратной связи. Пусто — 5 стандартных шагов.'),
|
||
))
|
||
->add_tab('📈 Результаты учеников', array(
|
||
Field::make('html', 'teacher_results_help')
|
||
->set_html('<div style="background:#F8FAFC;border:1px solid #E2E8F0;border-radius:8px;padding:12px 14px;margin:0 0 14px;color:#334155;font-size:13px;line-height:1.6"><strong>Блок «Измеримые результаты»</strong> — отдельная секция на странице (не путать с «Кому подойдут»). 3–6 пунктов: короткий измеримый результат + пояснение. Пусто — блок соберётся из заполненных метрик преподавателя (рейтинг, стаж, средний балл, отзывы).</div>'),
|
||
Field::make('complex', 'teacher_results', 'Измеримые результаты')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('text', 'result_title', 'Короткий результат (цифра/факт)')
|
||
->set_width(30)
|
||
->set_required(true)
|
||
->help_text('Например: «+2 балла», «100%», «45 минут».'),
|
||
Field::make('textarea', 'result_text', 'Пояснение')
|
||
->set_width(70)
|
||
->help_text('Например: «средний рост успеваемости за полугодие».'),
|
||
))
|
||
->set_help_text('3–6 пунктов. Пусто — собирается из метрик преподавателя.'),
|
||
Field::make('html', 'teacher_results_fallback_sep', '')
|
||
->set_html('<hr><h3>⚙ Авто-пункты (если «Измеримые результаты» пустые)</h3><p style="color:#64748B;font-size:12px;margin:4px 0 10px;">Подставляются в секцию результатов, пока complex выше не заполнен. Заполните — complex перекроет авто-пункты.</p>'),
|
||
Field::make('text', 'teacher_avg_score', 'Средний балл учеников')
|
||
->set_width(25)
|
||
->set_default_value('')
|
||
->set_help_text('Авто-пункт. Пример: <strong>4,7</strong>. Пусто — пункт скрыт.'),
|
||
Field::make('text', 'teacher_avg_label', 'Подпись среднего балла')
|
||
->set_width(25)
|
||
->set_default_value('Средний балл учеников')
|
||
->set_help_text('Пример: <strong>«Средний балл учеников»</strong>.'),
|
||
Field::make('text', 'teacher_school_num', 'Цифра про систему/школу')
|
||
->set_width(25)
|
||
->set_default_value('100%')
|
||
->set_help_text('Авто-пункт. Пример: <strong>100%</strong>. Пусто — пункт скрыт.'),
|
||
Field::make('text', 'teacher_school_label', 'Подпись к цифре про систему')
|
||
->set_width(25)
|
||
->set_default_value('учеников продолжают обучение на следующий учебный год')
|
||
->set_help_text('Пример: <strong>«учеников продолжают обучение на следующий учебный год»</strong>.'),
|
||
))
|
||
->add_tab('❓ Вопросы и отзывы', array(
|
||
Field::make('complex', 'questions', 'Блок вопросы и ответы (страница)')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('textarea', 'questions_question', 'Текст вопроса')
|
||
->set_width(30),
|
||
Field::make('textarea', 'questions_answer', 'Текст ответа')
|
||
->set_width(70),
|
||
)),
|
||
Field::make('complex', 'teacher_faq_extra', 'Доп. вопросы (про мини-группы)')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('textarea', 'faq_q', 'Вопрос')
|
||
->set_width(30),
|
||
Field::make('textarea', 'faq_a', 'Ответ')
|
||
->set_width(70),
|
||
))
|
||
->set_help_text('Вопросы про формат: «Чем мини-группа лучше репетитора?» и т.п. Пусто — 2 стандартных.'),
|
||
Field::make('checkbox', 'teacher_show_social_reviews', 'Показывать «Отзывы о преподавателе» на странице')
|
||
->set_option_value('yes')
|
||
->set_default_value('yes'),
|
||
))
|
||
->add_tab('📜 Лицензия и доверие', array(
|
||
Field::make('textarea', 'teacher_license', 'Текст блока «Лицензия и доверие»')
|
||
->set_default_value('Частная школа «Декарт» работает по лицензии на образовательную деятельность (бессрочная). Копия лицензии и реквизиты — по запросу у администратора. Рейтинг на Яндекс Картах и 2ГИС формируется из реальных отзывов родителей.')
|
||
->set_help_text('Показывается в блоке доверия перед картой.'),
|
||
))->set_layout('tabbed-vertical');
|
||
|
||
|
||
// ====================================================
|
||
// Доп поля для страницы "Преподаватели" (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('1–2 предложения: направления школы и гео-ключи.'),
|
||
Field::make('textarea', 'teachers_intro_title', 'Заголовок блока')
|
||
->set_default_value('Преподаватели школы «Декарт» в Щёлково')
|
||
->set_help_text('Второй заголовок с ключевым запросом.'),
|
||
Field::make('textarea', 'teachers_intro_text', 'Вводный текст')
|
||
->set_help_text('2–4 предложения: сколько учителей, какие направления закрывают, первое вхождение гео-ключей.'),
|
||
))
|
||
->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('Добавьте 2–4 цифры. Пример: «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)"
|
||
// ====================================================
|
||
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_subtitle_footnote_link', 'Ссылка для звёздочки (*) в подзаголовке')
|
||
->set_width(50)
|
||
->set_help_text('URL для иконки * после текста подзаголовка. Если не указано — * неактивна.'),
|
||
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>. Текст о срочности/дефиците мест под кнопкой.'),
|
||
Field::make('textarea', 'pksh_hero_definition', 'Определение для AI (первые 60 слов)')
|
||
->set_rows(3)
|
||
->set_help_text(
|
||
'📖 <strong>Для AI-поиска (GEO).</strong> Текст, который AI использует для ответа на «Что такое подготовка к школе в [городе]?». '
|
||
. 'Рекомендуется <strong>40–60 слов</strong>, начинается с «Подготовка к школе в [городе] — это…». '
|
||
. 'Выводится на странице после H1, перед подзаголовком. Если не заполнено — блок скрыт.'
|
||
)
|
||
->set_default_value('Подготовка к школе в Щёлково — это комплексные занятия для детей 5–7 лет, которые помогают освоить чтение, письмо, счёт и развить логическое мышление. Программа построена на игровой методике: ребёнок учится без стресса, в комфортном темпе. Группы до 10 человек, индивидуальный подход к каждому.'),
|
||
))
|
||
->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('Например: выпускников в топ-школах'),
|
||
)),
|
||
Field::make('html', 'pksh_social_author_header', '')
|
||
->set_html('<hr style="margin:16px 0;border:none;border-top:1px solid #e2e8f0;"><h3 style="margin:8px 0;color:#2563EB;">👤 Автор контента (E-E-A-T для SEO)</h3><p style="color:#64748b;font-size:12px;margin:0 0 8px;">Эти поля влияют на <strong>E-E-A-T</strong> (Experience, Expertise, Authoritativeness, Trustworthiness) — фактор ранжирования Google. Указываются в микроразметке Schema.org и отображаются в блоке автора внизу страницы. Заполните, чтобы повысить доверие поисковых систем к контенту.</p>'),
|
||
Field::make('text', 'pksh_author_name', 'Имя автора контента')
|
||
->set_width(50)
|
||
->set_default_value('Частная школа «Декарт»')
|
||
->set_help_text(
|
||
'<strong>Для SEO:</strong> Имя автора для Schema.org Person / author. '
|
||
. 'Рекомендуется: фактическое название организации или ФИО руководителя/педагога. '
|
||
. 'Влияет на E-E-A-T — Google проверяет автора контента. '
|
||
. 'По умолчанию: название из поля «Название филиала» в Настройках темы.'
|
||
),
|
||
))
|
||
->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_storage_format('d.m.Y')
|
||
->set_input_format('d.m.Y', 'd.m.Y')
|
||
->set_picker_options(array( 'altInput' => false ))
|
||
->set_help_text('Для Schema.org Review.datePublished. Формат: ДД.ММ.ГГГГ'),
|
||
Field::make('association', 'review_teacher', 'Преподаватель')
|
||
->set_width(25)
|
||
->set_types(array(
|
||
array(
|
||
'type' => 'post',
|
||
'post_type' => 'teacher',
|
||
),
|
||
))
|
||
->set_max(1)
|
||
->set_help_text('Если родитель хвалит конкретного учителя — привяжите отзыв к нему. Необязательно.'),
|
||
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>. Выберите преподавателей из добавленных в разделе <strong>Преподаватели</strong> главного меню админки. ФИО и фото берутся из карточки преподавателя.</p>'),
|
||
Field::make('textarea', 'pksh_teachers_text', 'Текст под заголовком')
|
||
->set_default_value('Каждый педагог имеет опыт работы с дошкольниками от 5 лет. Все — действующие учителя начальных классов с высшим образованием.')
|
||
->set_help_text('Текст описания перед карточками преподавателей.'),
|
||
Field::make('complex', 'pksh_teachers', 'Преподаватели на странице')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте преподавателей для этой страницы. Выберите из списка существующих.')
|
||
->add_fields(array(
|
||
Field::make('select', 'teacher_id', 'Выберите преподавателя')
|
||
->set_options(array( 0 => '— Выберите преподавателя —' ) + dekart_get_teacher_options())
|
||
->set_width(100)
|
||
->set_help_text('ФИО и фото подтянутся из карточки преподавателя. Если нужного нет — добавьте в разделе Преподаватели.'),
|
||
)),
|
||
))
|
||
// ====================================================
|
||
// Вкладка: Программы подготовки к школе
|
||
// ====================================================
|
||
->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('html', 'pksh_prog_base_title', '')
|
||
->set_html('<h3 style="margin:16px 0 8px;">🔵 Базовая — «Уверенный старт»</h3>'),
|
||
Field::make('text', 'pksh_prog_base_name', 'Название программы')
|
||
->set_width(100)
|
||
->set_default_value('Уверенный старт'),
|
||
Field::make('text', 'pksh_prog_base_subname', 'Подзаголовок')
|
||
->set_width(100)
|
||
->set_default_value('2 раза в неделю — комфортный темп без перегрузки'),
|
||
Field::make('text', 'pksh_prog_base_schedule', 'Расписание')
|
||
->set_width(100)
|
||
->set_default_value('вт, чт — 18:00–19:30'),
|
||
Field::make('text', 'pksh_prog_base_price_sub', 'Стоимость абонемента за 4 недели')
|
||
->set_width(50)
|
||
->set_default_value('7 500 ₽'),
|
||
Field::make('text', 'pksh_prog_base_price_single', 'Стоимость разового занятия')
|
||
->set_width(50)
|
||
->set_default_value('1 000 ₽'),
|
||
Field::make('text', 'pksh_prog_base_price_razov', 'Стоимость разового занятия ВНЕ абонемента')
|
||
->set_width(50)
|
||
->set_default_value('1 200 ₽')
|
||
->set_help_text('Отдельная цена для «Разовое занятие вне абонемента: …». Если пусто — используется price_single.'),
|
||
Field::make('text', 'pksh_prog_base_urgency', 'Срочность (мест в группе)')
|
||
->set_width(100)
|
||
->set_default_value('Осталось 2 места в группе'),
|
||
Field::make('html', 'pksh_prog_prem_title', '')
|
||
->set_html('<h3 style="margin:20px 0 8px;">🟣 Расширенная — «Результат за 3 месяца»</h3>'),
|
||
Field::make('text', 'pksh_prog_prem_name', 'Название программы')
|
||
->set_width(100)
|
||
->set_default_value('Результат за 3 месяца'),
|
||
Field::make('text', 'pksh_prog_prem_subname', 'Подзаголовок')
|
||
->set_width(100)
|
||
->set_default_value('3 раза в неделю — быстрый прогресс'),
|
||
Field::make('text', 'pksh_prog_prem_schedule', 'Расписание')
|
||
->set_width(100)
|
||
->set_default_value('пн, ср, пт — 16:30–18:00'),
|
||
Field::make('text', 'pksh_prog_prem_price_sub', 'Стоимость абонемента за 4 недели')
|
||
->set_width(50)
|
||
->set_default_value('10 500 ₽'),
|
||
Field::make('text', 'pksh_prog_prem_price_single', 'Стоимость разового занятия')
|
||
->set_width(50)
|
||
->set_default_value('1 500 ₽'),
|
||
Field::make('text', 'pksh_prog_prem_price_razov', 'Стоимость разового занятия ВНЕ абонемента')
|
||
->set_width(50)
|
||
->set_default_value('2 000 ₽')
|
||
->set_help_text('Отдельная цена для «Разовое занятие вне абонемента: …». Если пусто — используется price_single.'),
|
||
Field::make('text', 'pksh_prog_prem_urgency', 'Срочность (мест в группе)')
|
||
->set_width(100)
|
||
->set_default_value('Осталось 3 места в группе'),
|
||
))
|
||
// ====================================================
|
||
// Вкладка: Сравнение (Как мы отличаемся)
|
||
// ====================================================
|
||
->add_tab('📊 Как мы отличаемся', array(
|
||
Field::make('html', 'pksh_compare_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.pksh-compare</strong>. Таблица сравнения Декарт vs Репетитор vs Кружок. Каждая строка — отдельная запись. Порядок = порядок вывода.</p>'),
|
||
Field::make('complex', 'pksh_compare_rows', 'Строки таблицы')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте строки сравнения. Для каждой строки: критерий, текст для трёх колонок, иконка ✓/✗ для каждой колонки.')
|
||
->add_fields(array(
|
||
Field::make('text', 'criteria', 'Критерий')
|
||
->set_width(100)
|
||
->set_help_text('Название строки, например: «Гослицензия»'),
|
||
Field::make('html', 'pksh_compare_dekart_header', '')
|
||
->set_html('<hr style="margin: 12px 0; border: none; border-top: 1px solid #e2e8f0;"><h4 style="margin: 4px 0; color: #7C3AED;">🔸 Декарт</h4>'),
|
||
Field::make('select', 'dekart_icon', 'Иконка')
|
||
->set_width(20)
|
||
->set_options(array(
|
||
'' => '— нет —',
|
||
'yes' => '✓ (да)',
|
||
'no' => '✗ (нет)',
|
||
)),
|
||
Field::make('textarea', 'dekart_text', 'Текст')
|
||
->set_width(80)
|
||
->set_help_text('Например: «Есть»'),
|
||
Field::make('html', 'pksh_compare_repetitor_header', '')
|
||
->set_html('<h4 style="margin: 8px 0 4px;">🔸 Репетитор</h4>'),
|
||
Field::make('select', 'repetitor_icon', 'Иконка')
|
||
->set_width(20)
|
||
->set_options(array(
|
||
'' => '— нет —',
|
||
'yes' => '✓ (да)',
|
||
'no' => '✗ (нет)',
|
||
)),
|
||
Field::make('textarea', 'repetitor_text', 'Текст')
|
||
->set_width(80),
|
||
Field::make('html', 'pksh_compare_kruzhok_header', '')
|
||
->set_html('<h4 style="margin: 8px 0 4px;">🔸 Обычный кружок</h4>'),
|
||
Field::make('select', 'kruzhok_icon', 'Иконка')
|
||
->set_width(20)
|
||
->set_options(array(
|
||
'' => '— нет —',
|
||
'yes' => '✓ (да)',
|
||
'no' => '✗ (нет)',
|
||
)),
|
||
Field::make('textarea', 'kruzhok_text', 'Текст')
|
||
->set_width(80),
|
||
)),
|
||
Field::make('textarea', 'pksh_compare_footnote', 'Сноска под таблицей')
|
||
->set_help_text('Текст под таблицей. Можно использовать HTML.')
|
||
->set_default_value('<strong>Важно:</strong> Данные по репетиторам и кружкам — рыночная оценка по городу и требует уточнения.'),
|
||
))
|
||
// ====================================================
|
||
// Вкладка: 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", "Письмо печатными буквами"'),
|
||
)),
|
||
))
|
||
// ====================================================
|
||
// Вкладка: GEO / AI-поиск (self-contained answer блоки для цитирования)
|
||
// ====================================================
|
||
->add_tab('🤖 GEO (AI-поиск)', array(
|
||
Field::make('html', 'pksh_geo_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Поля для <strong>Generative Engine Optimization</strong> — контент, оптимизированный для цитирования AI-поиском (Google AI Overviews, ChatGPT, Perplexity). Каждый блок должен быть <strong>самодостаточным (134–167 слов)</strong> и содержать конкретные данные.</p>'),
|
||
Field::make('html', 'pksh_geo_questions_title', '')
|
||
->set_html('<h3 style="margin:16px 0 8px;">❓ Вопросы-заголовки для AI</h3>'),
|
||
Field::make('html', 'pksh_geo_questions_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 12px; margin: 0 0 8px;">Эти заголовки (H2/H3) отвечают на типичные поисковые запросы. AI видит их как прямые ответы. Если поле пусто — секция не выводится.</p>'),
|
||
Field::make('text', 'pksh_geo_q1', 'Вопрос-заголовок #1')
|
||
->set_width(100)
|
||
->set_help_text('Например: «Сколько стоит подготовка к школе в Щёлково?»')
|
||
->set_default_value('Сколько стоит подготовка к школе в Щёлково?'),
|
||
Field::make('text', 'pksh_geo_q2', 'Вопрос-заголовок #2')
|
||
->set_width(100)
|
||
->set_help_text('Например: «Что должен знать ребёнок перед школой?»')
|
||
->set_default_value('Что должен знать ребёнок перед школой?'),
|
||
Field::make('text', 'pksh_geo_q3', 'Вопрос-заголовок #3')
|
||
->set_width(100)
|
||
->set_help_text('Например: «Как выбрать центр подготовки к школе?»')
|
||
->set_default_value('Как выбрать центр подготовки к школе?'),
|
||
Field::make('html', 'pksh_geo_answers_title', '')
|
||
->set_html('<h3 style="margin:20px 0 8px;">📝 Answer-блоки для AI-цитирования</h3>'),
|
||
Field::make('html', 'pksh_geo_answers_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 12px; margin: 0 0 8px;">Каждый блок — <strong>134–167 слов</strong>, самодостаточный, с конкретными данными. AI может процитировать его целиком. Рекомендуется: факты, цифры, сроки, цены. Если поле пусто — блок не выводится.</p>'),
|
||
Field::make('textarea', 'pksh_geo_answer_programs', 'Answer-блок: Программы и цены')
|
||
->set_rows(8)
|
||
->set_help_text(
|
||
'Выводится в секции <strong>Программы</strong> перед карточками. '
|
||
. 'Рекомендуется 134–167 слов. Опишите программы, цены, разницу между базовой и расширенной.'
|
||
)
|
||
->set_default_value(
|
||
'В детском центре «Декарт» в Щёлково действуют две программы подготовки к школе. Базовая программа «Уверенный старт» включает 2 занятия в неделю по 30–40 минут — стоимость абонемента 7 500 ₽ в месяц. Расширенная программа «Результат за 3 месяца» — 3 занятия в неделю, 10 500 ₽ в месяц. Обе программы ведут действующие педагоги начальных классов со стажем от 12 лет. Группы до 10 человек — каждому ребёнку уделяется внимание. Первое занятие — бесплатно, без договора и оплаты. В стоимость включены все учебные материалы и пособия. Занятия проходят очно по адресу: Талсинская ул., 24. Результат через 3 недели — дети начинают читать по слогам.'
|
||
),
|
||
Field::make('textarea', 'pksh_geo_answer_results', 'Answer-блок: Результаты и статистика')
|
||
->set_rows(8)
|
||
->set_help_text(
|
||
'Выводится в секции <strong>Результаты</strong>. '
|
||
. 'Рекомендуется 134–167 слов. Конкретные цифры, проценты, сроки.'
|
||
)
|
||
->set_default_value(
|
||
'95% выпускников центра «Декарт» поступают в школы и лицеи Щёлкова без стресса — они готовы к учебной нагрузке и требованиям учителей. Первые результаты заметны уже через 3 недели: нечитавшие дети складывают первый осмысленный слог. 87% родителей отмечают рост самостоятельности ребёнка после месяца занятий. Выпускники центра адаптируются в первом классе в 2,5 раза быстрее сверстников — они не боятся отвечать у доски, поднимать руку и работать в коллективе. За 12 лет работы центром подготовлено более 500 детей. Программа построена так, что каждый ребёнок осваивает чтение, письмо, счёт и логику без перегрузки — занятия длятся 30–40 минут, каждые 7 минут смена активности.'
|
||
),
|
||
Field::make('textarea', 'pksh_geo_answer_howitworks', 'Answer-блок: Как проходят занятия')
|
||
->set_rows(8)
|
||
->set_help_text(
|
||
'Выводится в секции <strong>Как проходят занятия</strong>. '
|
||
. 'Рекомендуется 134–167 слов. Опишите методику, длительность, структуру.'
|
||
)
|
||
->set_default_value(
|
||
'Каждое занятие длится 30–40 минут и построено так, чтобы ребёнок не уставал. Активность меняется каждые 7 минут — это оптимальный интервал удержания внимания для детей 5–7 лет. Урок начинается с короткой истории или загадки, которая вводит в тему и включает интерес. Затем следует игровое задание: чтение через игру, счёт через механику соревнования, логика через головоломки. После каждого блока — активная перемена с нейрогимнастикой. Завершается занятие рефлексией: ребёнок сам рассказывает, чему научился. Все педагоги имеют высшее педагогическое образование и опыт работы с дошкольниками от 5 лет. Методика исключает скучные прописи и многочасовое сидение за партой — дети воспринимают занятия как игру и с удовольствием возвращаются.'
|
||
),
|
||
))
|
||
// ====================================================
|
||
// Вкладка: Фотогалерея
|
||
// ====================================================
|
||
->add_tab('📸 Фотогалерея', array(
|
||
Field::make('html', 'pksh_gallery_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>#gallery</strong>. Фотографии занятий, 3 в ряд. Если фото не добавлены — секция не выводится.</p>'),
|
||
Field::make('complex', 'pksh_gallery', 'Фотографии')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте фотографии с занятий. Оптимальная ширина: 600–1200 px.')
|
||
->add_fields(array(
|
||
Field::make('image', 'gallery_image', 'Фото')
|
||
->set_width(60)
|
||
->set_help_text('Рекомендуемый размер: 800×600 px, соотношение 4:3 или 3:2.'),
|
||
Field::make('text', 'gallery_caption', 'Подпись (опционально)')
|
||
->set_width(40)
|
||
->set_help_text('Короткая подпись под фото. Если не указана — только фото.'),
|
||
)),
|
||
));
|
||
|
||
// ====================================================
|
||
// Контейнер: Программа Подготовки к школе (служебная страница)
|
||
// ====================================================
|
||
Container::make('post_meta', '📄 Программа «Подготовка к школе»')
|
||
->where('post_template', '=', 'page-program-pksh.php')
|
||
->add_fields(array(
|
||
Field::make('html', 'pksh_prog_header', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 8px;">Официальный документ — образовательная программа подготовки к школе. <strong>Текст программы менять нельзя</strong> — это утверждённый документ. Для обновления скопируйте новый текст целиком.</p>'),
|
||
Field::make('rich_text', 'pksh_prog_content', 'Текст программы')
|
||
->set_help_text(
|
||
'<strong>ВАЖНО:</strong> Это официально утверждённый документ. Не меняйте содержание. '
|
||
. 'Для обновления — замените текст целиком на новую версию. '
|
||
. 'Рекомендуется вставлять из Google Docs / Word без форматирования, '
|
||
. 'затем применить заголовки H2-H3 и списки вручную.'
|
||
),
|
||
Field::make('html', 'pksh_prog_legal_header', '')
|
||
->set_html('<hr><h3 style="margin:12px 0 4px;">⚖️ Юридическая информация</h3>'),
|
||
Field::make('date', 'pksh_prog_doc_date', 'Дата утверждения / обновления документа')
|
||
->set_width(30)
|
||
->set_storage_format('Y-m-d')
|
||
->set_input_format('Y-m-d', 'Y-m-d')
|
||
->set_help_text('Дата последнего утверждения или обновления программы (YYYY-MM-DD). Отображается в дисклеймере.'),
|
||
Field::make('textarea', 'pksh_prog_disclaimer', 'Текст дисклеймера')
|
||
->set_width(100)
|
||
->set_default_value(
|
||
'Электронная версия программы предназначена для ознакомления. При переносе в электронный вид '
|
||
. 'возможны технические неточности (опечатки, ошибки форматирования). '
|
||
. 'Юридически значимым считается документ, предоставленный в офисе организации. '
|
||
. 'Дата последнего обновления электронной версии:'
|
||
)
|
||
->set_rows(4)
|
||
->set_help_text('Текст, который выводится в блоке дисклеймера. Можно редактировать независимо от текста программы.'),
|
||
Field::make('html', 'pksh_prog_service_header', '')
|
||
->set_html('<hr><h3 style="margin:12px 0 4px;">🔗 Ссылка на услугу</h3>'),
|
||
Field::make('text', 'pksh_prog_service_url', 'URL услуги')
|
||
->set_width(50)
|
||
->set_default_value('/podgotovka-k-shkole/')
|
||
->set_help_text('Ссылка на страницу услуги, которая реализует данную программу.'),
|
||
Field::make('text', 'pksh_prog_service_label', 'Текст ссылки')
|
||
->set_width(50)
|
||
->set_default_value('Записаться на подготовку к школе')
|
||
->set_help_text('Текст кнопки/ссылки для перехода на услугу.'),
|
||
));
|
||
|
||
// ====================================================
|
||
// Уникальное имя контейнера Продлёнки
|
||
// ====================================================
|
||
Container::make('post_meta', 'Настройки Продлёнки')
|
||
->where('post_template', '=', 'page-after-school.php')
|
||
->add_tab('Общие', array(
|
||
Field::make('text', 'as_address', 'Наш адрес:'),
|
||
Field::make('text', 'as_price', 'Цена:'),
|
||
))
|
||
->add_tab('Педагоги', array(
|
||
Field::make('complex', 'as_mentors', 'Педагоги')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('image', 'mentor_foto', 'Фотография:')
|
||
->set_width(15),
|
||
Field::make('text', 'mentor_name', 'ФИО:')
|
||
->set_width(30),
|
||
Field::make('text', 'mentor_directions', 'Описание:')
|
||
->set_width(55),
|
||
))
|
||
))
|
||
->add_tab('Распорядок дня', array(
|
||
Field::make('textarea', 'as_routine', 'Блок "Распорядок дня":'),
|
||
))
|
||
->add_tab('Отзывы', array(
|
||
Field::make('complex', 'as_reviews', 'Отзывы клиентов:')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('image', 'review_avatar', 'Автар:')
|
||
->set_width(15),
|
||
Field::make('text', 'review_name', 'Имя:')
|
||
->set_width(30),
|
||
Field::make('text', 'review_star', 'Оценка:')
|
||
->set_width(15)
|
||
->set_attribute('type', 'number'),
|
||
Field::make('textarea', 'review_text', 'Текст отзыва:')
|
||
->set_width(100),
|
||
)),
|
||
))
|
||
->add_tab('Вопросы-Ответы', array(
|
||
Field::make('complex', 'as_questions', 'Блок вопросы и ответы')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('textarea', 'questions_question', 'Текст вопроса')
|
||
->set_width(30),
|
||
Field::make('textarea', 'questions_answer', 'Текст ответа')
|
||
->set_width(70),
|
||
)),
|
||
))
|
||
->add_tab('Фото', array(
|
||
Field::make('complex', 'as_fotos', 'Фотографии:')
|
||
->set_layout('tabbed-horizontal')
|
||
->add_fields(array(
|
||
Field::make('image', 'foto', 'Фото')
|
||
)),
|
||
))
|
||
->add_tab('Битрикс', array(
|
||
Field::make('textarea', 'as_bitrix_script', 'script (формы) БИТРИКС24:'),
|
||
));
|
||
|
||
// ====================================================
|
||
// Доп поля для страницы "ГОРОДСКОЙ ЛАГЕРЬ"
|
||
// ====================================================
|
||
Container::make('post_meta', '🏰 Настройки Городской Лагерь')
|
||
->where('post_template', '=', 'page-camp.php')
|
||
->add_tab('🖼️ Первый экран', array(
|
||
Field::make('html', 'hero_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Шаблон: <strong>page-camp.php</strong> · Секция: <strong>.hero-media-search</strong></p>'),
|
||
Field::make('separator', 'hero_media_sep', 'Изображения'),
|
||
Field::make('image', 'banner_img', 'Фото на весь экран (десктоп)')
|
||
->set_help_text('Оптимально: 1920×1080 px, WebP/JPG. Дети в движении, эмоции.')
|
||
->set_width(50),
|
||
Field::make('separator', 'hero_titles_sep', 'Заголовки и текст'),
|
||
Field::make('text', 'hero_title_h1', 'Заголовок H1')
|
||
->set_default_value('Лето, которое он запомнит навсегда')
|
||
->set_width(50)
|
||
->set_help_text('Основной заголовок страницы. Эмоциональный, зацепляющий.'),
|
||
Field::make('text', 'hero_title_span', 'Заголовок (вторая часть, цветная)')
|
||
->set_default_value('Big Summer Fun!')
|
||
->set_width(50)
|
||
->set_help_text('Выделяется цветом на фоне основного.'),
|
||
Field::make('separator', 'hero_cta_sep', 'Кнопка'),
|
||
Field::make('text', 'hero_btn_primary', 'Текст главной кнопки (CTA)')
|
||
->set_default_value('Записаться на пробный день')
|
||
->set_width(100)
|
||
->set_help_text('Главное действие, к которому призываем. Лучше: конкретная выгода, а не действие.'),
|
||
Field::make('separator', 'hero_metrics_sep', 'Метрики доверия (блок достижений)'),
|
||
Field::make('image', 'hero_metric_1_img', 'Иконка метрики 1 (изображение)')
|
||
->set_width(30)
|
||
->set_help_text('Оптимально: 1200x800px, WebP/JPG'),
|
||
Field::make('text', 'hero_metric_1_number', 'Число метрики 1')
|
||
->set_default_value('90+')
|
||
->set_width(30),
|
||
Field::make('text', 'hero_metric_1_label', 'Подпись метрики 1')
|
||
->set_default_value('Количество клубов')
|
||
->set_width(40),
|
||
Field::make('image', 'hero_metric_2_img', 'Иконка метрики 2 (изображение)')
|
||
->set_width(30)
|
||
->set_help_text('Оптимально: 1200x800px, WebP/JPG'),
|
||
Field::make('text', 'hero_metric_2_number', 'Число метрики 2')
|
||
->set_default_value('570K+')
|
||
->set_width(30),
|
||
Field::make('text', 'hero_metric_2_label', 'Подпись метрики 2')
|
||
->set_default_value('Юных инноваторов')
|
||
->set_width(40),
|
||
Field::make('image', 'hero_metric_3_img', 'Иконка метрики 3 (изображение)')
|
||
->set_width(30)
|
||
->set_help_text('Оптимально: 1200x800px, WebP/JPG'),
|
||
Field::make('text', 'hero_metric_3_number', 'Число метрики 3')
|
||
->set_default_value('49K+')
|
||
->set_width(30),
|
||
Field::make('text', 'hero_metric_3_label', 'Подпись метрики 3')
|
||
->set_default_value('Стипендий')
|
||
->set_width(40),
|
||
))
|
||
->add_tab('ℹ️ О нас', array(
|
||
Field::make('html', 'about_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.about-us</strong></p>'),
|
||
Field::make('separator', 'about_us_sep', 'Текст и фото'),
|
||
Field::make('image', 'about_us_img', 'Фото')
|
||
->set_help_text('Оптимально: 1200x800px, WebP/JPG. Реальные дети, эмоции.')
|
||
->set_width(30),
|
||
Field::make('textarea', 'about_us_text', 'Текст о нас')
|
||
->set_help_text('Краткий текст о лагере. Выводится на странице лагеря после Hero-секции.')
|
||
->set_default_value('Dekart — это сеть детских клубов, где наука, творчество и спорт объединяются в одну захватывающую программу. Мы помогаем детям раскрывать таланты, находить друзей и проводить лето с пользой. Наши вожатые — профессиональные педагоги и наставники, которые создают атмосферу доверия и вдохновения. Каждый день в лагере — это новое открытие.'),
|
||
))
|
||
->add_tab('🏭 Преимущества', array(
|
||
Field::make('html', 'suggestions_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.suggestions</strong></p>'),
|
||
Field::make('complex', 'suggestions', 'Блок «Почему выбирают нас»')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('3–6 преимуществ с заголовком и описанием.')
|
||
->add_fields(array(
|
||
Field::make('text', 'suggestions_title', 'Заголовок')
|
||
->set_width(100),
|
||
Field::make('textarea', 'suggestions_text', 'Описание')
|
||
->set_width(100),
|
||
)),
|
||
))
|
||
->add_tab('📅 Программы', array(
|
||
Field::make('html', 'programs_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.programs</strong></p>'),
|
||
Field::make('complex', 'programs', 'Список программ (смен)')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте каждую тематическую смену отдельной записью.')
|
||
->add_fields(array(
|
||
Field::make('image', 'programs_img', 'Изображение смены')
|
||
->set_help_text('Оптимально: 1200x800px, WebP/JPG')
|
||
->set_width(100),
|
||
Field::make('text', 'programs_title', 'Название смены')
|
||
->set_width(50)
|
||
->set_help_text('Например: «Космический десант»'),
|
||
Field::make('text', 'programs_date', 'Даты проведения')
|
||
->set_width(50)
|
||
->set_help_text('Например: «2–6 июня»'),
|
||
Field::make('textarea', 'programs_text', 'Краткое описание (в карточке)')
|
||
->set_width(100)
|
||
->set_help_text('2–3 предложения.'),
|
||
Field::make('text', 'programs_price', 'Стоимость (в рублях)')
|
||
->set_attribute('type', 'number')
|
||
->set_width(50),
|
||
Field::make('text', 'programs_days', 'Количество дней')
|
||
->set_width(50)
|
||
->set_help_text('Например: «5 дней» или «7 дней»'),
|
||
Field::make('rich_text', 'programs_content', 'Полное описание (в модальном окне)')
|
||
->set_width(100)
|
||
->set_help_text('Полный текст программы для всплывающего окна.'),
|
||
)),
|
||
))
|
||
->add_tab('💰 Цены', array(
|
||
Field::make('html', 'pricing_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.bring-child</strong></p>'),
|
||
Field::make('text', 'price_half_day', 'Стоимость за половину дня (в рублях)')
|
||
->set_attribute('type', 'number')
|
||
->set_width(50)
|
||
->set_help_text('Цена за 5 дней, например: 12900'),
|
||
Field::make('text', 'price_full_day', 'Стоимость за полный день (в рублях)')
|
||
->set_attribute('type', 'number')
|
||
->set_width(50)
|
||
->set_help_text('Цена за 5 дней, например: 17900'),
|
||
))
|
||
->add_tab('👨🏫 Наставники', array(
|
||
Field::make('html', 'mentors_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.mentors</strong></p>'),
|
||
Field::make('complex', 'mentors', 'Список наставников лагеря')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Каждый наставник — отдельная запись.')
|
||
->add_fields(array(
|
||
Field::make('text', 'mentor_name', 'ФИО наставника')
|
||
->set_width(50),
|
||
Field::make('image', 'mentor_foto', 'Фото наставника')
|
||
->set_help_text('Оптимально: 1200x800px, WebP/JPG')
|
||
->set_width(50),
|
||
Field::make('text', 'mentor_job', 'Должность в лагере')
|
||
->set_width(100),
|
||
Field::make('textarea', 'mentor_about', 'О себе')
|
||
->set_help_text('Кратко о наставнике (показывается на карточке).'),
|
||
))
|
||
))
|
||
->add_tab('⏰ Распорядок дня', array(
|
||
Field::make('html', 'routine_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.routine</strong></p>'),
|
||
Field::make('complex', 'routine', 'Расписание по времени')
|
||
->set_help_text('Добавьте пункты распорядка по порядку следования.')
|
||
->add_fields(array(
|
||
Field::make('text', 'routine_time', 'Время')
|
||
->set_width(15)
|
||
->set_help_text('Формат: 08:30'),
|
||
Field::make('text', 'routine_title', 'Название активности')
|
||
->set_width(40)
|
||
->set_help_text('Например: «Научный блок»'),
|
||
Field::make('textarea', 'routine_text', 'Описание')
|
||
->set_width(45),
|
||
))
|
||
))
|
||
->add_tab('📷 Фотографии', array(
|
||
Field::make('html', 'fotos_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.foto</strong></p>'),
|
||
Field::make('complex', 'fotos', 'Галерея фотографий')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Добавьте реальные фото детей из лагеря. Формат: WebP, 1:1 или 4:3.')
|
||
->add_fields(array(
|
||
Field::make('image', 'foto', 'Фотография')
|
||
->set_help_text('Оптимально: 1200x800px, WebP/JPG, до 300Кб'),
|
||
)),
|
||
))
|
||
->add_tab('❓ Вопросы и ответы (FAQ)', array(
|
||
Field::make('html', 'faq_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.camp-faq</strong></p>'),
|
||
Field::make('complex', 'questions', 'Список вопросов и ответов')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('Чем больше вопросов, тем меньше возражений у родителей. Минимум 7–8 вопросов.')
|
||
->add_fields(array(
|
||
Field::make('textarea', 'questions_question', 'Текст вопроса')
|
||
->set_width(30),
|
||
Field::make('textarea', 'questions_answer', 'Текст ответа')
|
||
->set_width(70),
|
||
)),
|
||
))
|
||
->add_tab('⭐ Отзывы', array(
|
||
Field::make('html', 'reviews_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.camp-reviews</strong>. Отзывы выводятся на странице лагеря.</p>'),
|
||
Field::make('complex', 'camp_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_storage_format('d.m.Y')
|
||
->set_input_format('d.m.Y', 'd.m.Y')
|
||
->set_picker_options(array( 'altInput' => false ))
|
||
->set_help_text('Для Schema.org Review.datePublished. Формат: ДД.ММ.ГГГГ'),
|
||
Field::make('association', 'review_teacher', 'Преподаватель')
|
||
->set_width(25)
|
||
->set_types(array(
|
||
array(
|
||
'type' => 'post',
|
||
'post_type' => 'teacher',
|
||
),
|
||
))
|
||
->set_max(1)
|
||
->set_help_text('Если родитель хвалит конкретного учителя — привяжите отзыв к нему. Необязательно.'),
|
||
Field::make('textarea', 'review_text', 'Текст отзыва')
|
||
->set_width(35),
|
||
)),
|
||
))
|
||
->add_tab('📍 Контакты и карта', array(
|
||
Field::make('html', 'contacts_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">⚠️ Данные филиала (телефон, email, адрес, соцсети) — в <strong>Настройки филиала</strong> (меню слева). Здесь только подпись метки карты.</p>'),
|
||
Field::make('text', 'contact_location_text', 'Подпись метки на карте')
|
||
->set_width(50)
|
||
->set_help_text('Что написано в баллуне на карте.'),
|
||
))
|
||
->add_tab('🗂️ Битрикс24', array(
|
||
Field::make('html', 'bitrix_tab_desc', '')
|
||
->set_html('<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.modal-camp-request-form</strong><br>Скрипт кнопок перенесён в <strong>Настройки филиала → 🎯 СКРИПТ ДЛЯ КНОПОК → для лагеря</strong>.</p>'),
|
||
));
|
||
|
||
// ════════════════════════════════════════════════════════════
|
||
// СТРАНИЦА ОТЗЫВОВ (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('text', 'reviews_hero_subtitle', 'Подзаголовок (под H1)')
|
||
->set_default_value('Родители доверяют нам самое главное — вот что они говорят о нас')
|
||
->set_width(100)
|
||
->set_help_text('Текст под заголовком H1. Отображается белым на тёмном фоне hero.'),
|
||
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. Пример: «отзывов о школе», «педагогов», «лет на рынке».'),
|
||
Field::make('separator', 'reviews_hero_badges_sep', '🏷️ Плавающие подписи (у фото)'),
|
||
Field::make('complex', 'reviews_hero_badges', 'Подписи-плашки вокруг фото')
|
||
->set_layout('tabbed-horizontal')
|
||
->set_help_text('До 4 подписей, которые отображаются вокруг фото в hero-секции. Каждая запись: иконка (emoji) + текст. Позиции фиксированы: 1 = верх-право, 2 = лево-середина, 3 = низ-право, 4 = лево-верх. Если записей меньше 4 — отсутствующие не выводятся.')
|
||
->add_fields(array(
|
||
Field::make('text', 'badge_icon', 'Иконка (emoji)')
|
||
->set_width(20)
|
||
->set_help_text('Один символ emoji для плашки. Примеры: ⭐ 🎓 ❤️ 🌟 🎮 📚 👩🏫 🏆'),
|
||
Field::make('textarea', 'badge_text', 'Текст подписи')
|
||
->set_width(80)
|
||
->set_help_text('Короткий текст плашки. Можно использовать HTML: <strong>, <br>. Примеры: «Рейтинг 4.9 на Яндексе», «500+ выпускников», «Родители рекомендуют», «Школа <strong>№1</strong> в районе».'),
|
||
)),
|
||
// 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(50)
|
||
->set_help_text('Текст стоимости в блоке .reviews-intro__info. Пример: «от 40 000 ₽ в месяц» или «от 35 000 ₽/мес». Если поле пусто — строка не выводится.'),
|
||
Field::make('text', 'reviews_intro_hours', 'Режим работы (текст)')
|
||
->set_default_value('ежедневно с 8:00 до 19:00, кроме воскресенья')
|
||
->set_width(50)
|
||
->set_help_text('Текст режима работы в блоке .reviews-intro__info. Отображается на странице отзывов под SEO-текстом. Пример: «ежедневно с 8:00 до 19:00, кроме воскресенья» или «Пн–Пт: 08:00–19:00, Сб: 09:00–14:00». Если пусто — строка не выводится.'),
|
||
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('oembed', '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 курса по его названию
|
||
function get_post_by_title($page_title)
|
||
{
|
||
$query = new WP_Query(
|
||
[
|
||
'post_type' => 'course',
|
||
'title' => $page_title,
|
||
'post_status' => 'publish',
|
||
'posts_per_page' => 1,
|
||
'update_post_term_cache' => false,
|
||
'update_post_meta_cache' => false,
|
||
'orderby' => 'post_date ID',
|
||
'order' => 'ASC',
|
||
'no_found_rows' => true,
|
||
'ignore_sticky_posts' => true,
|
||
]
|
||
);
|
||
wp_reset_postdata();
|
||
if ($query->post) {
|
||
return $query->post->ID;
|
||
} else {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
// функция случайного цвета
|
||
function rand_color()
|
||
{
|
||
return sprintf('#%06X', mt_rand(0, 0xFFFFFF));
|
||
}
|
||
|
||
add_theme_support('post-thumbnails');
|
||
|
||
// Навигационные меню: возвращает пункт «Внешний вид → Меню» в админке
|
||
add_theme_support('menus');
|
||
register_nav_menus(array(
|
||
'top' => __('Основное меню (шапка/подвал)', 'dekart'),
|
||
));
|
||
|
||
add_action('pre_get_posts', 'exclude_custom_taxonomy_posts');
|
||
function exclude_custom_taxonomy_posts($query)
|
||
{
|
||
if (!is_admin() && $query->is_main_query() && ($query->is_tax('trainingCategory') || $query->is_tax('direction'))) {
|
||
$query->set_404();
|
||
}
|
||
}
|
||
|
||
function add_og_image()
|
||
{
|
||
$term = get_queried_object();
|
||
if (! is_a($term, 'WP_Term') || empty($term->term_id)) {
|
||
return;
|
||
}
|
||
$snippet = carbon_get_term_meta($term->term_id, 'snippet');
|
||
if ($snippet) {
|
||
echo '<meta property="og:image" content="' . esc_url(wp_get_attachment_url($snippet)) . '" >' . "\n";
|
||
}
|
||
}
|
||
add_action('wp_head', 'add_og_image');
|
||
|
||
function yoastVariableToTitle($post_id)
|
||
{
|
||
$yoast_title = get_post_meta($post_id, '_yoast_wpseo_title', true);
|
||
$title = strstr($yoast_title, '%%', true);
|
||
if (empty($title)) {
|
||
$title = get_the_title($post_id);
|
||
}
|
||
$wpseo_titles = get_option('wpseo_titles');
|
||
$sep_options = WPSEO_Option_Titles::get_instance()->get_separator_options();
|
||
if (isset($wpseo_titles['separator']) && isset($sep_options[$wpseo_titles['separator']])) {
|
||
$sep = $sep_options[$wpseo_titles['separator']];
|
||
} else {
|
||
$sep = '-';
|
||
}
|
||
$site_title = get_bloginfo('name');
|
||
$meta_title = $title . ' ' . $sep . ' ' . $site_title;
|
||
return $meta_title;
|
||
}
|
||
|
||
function replaceQuotes($text)
|
||
{
|
||
$text = str_replace(['"'], "'", $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);
|
||
}
|
||
|
||
/**
|
||
* Парсит Bitrix24 скрипт из настроек филиала, извлекая data-b24-form и URL загрузчика.
|
||
* Используется для динамической загрузки формы в модальном окне.
|
||
*
|
||
* @param string $script Полный HTML скрипта Bitrix24.
|
||
* @return array{form: string, loader: string} Массив с ключами 'form' и 'loader'.
|
||
*/
|
||
function dekart_parse_b24_script(string $script): array
|
||
{
|
||
$result = array( 'form' => '', 'loader' => '' );
|
||
if (preg_match('/data-b24-form="([^"]+)"/', $script, $m)) {
|
||
$result['form'] = $m[1];
|
||
}
|
||
if (preg_match("/\\(window,document,'([^']+)'\\)/", $script, $m)) {
|
||
$result['loader'] = $m[1];
|
||
}
|
||
return $result;
|
||
}
|
||
|
||
function enqueue_template_specific_styles()
|
||
{
|
||
// Yandex Maps — загружается на всех страницах.
|
||
// JS сам проверяет наличие #ya-map[data-coords] перед активацией.
|
||
wp_enqueue_script(
|
||
'yandex-map',
|
||
get_template_directory_uri() . '/assets/js/yandex-map.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/yandex-map.js'),
|
||
true
|
||
);
|
||
|
||
if (is_page_template('page-camp.php')) {
|
||
wp_enqueue_style(
|
||
'template-specific-style',
|
||
get_template_directory_uri() . '/assets/css/camp.css',
|
||
array(),
|
||
'1.8'
|
||
);
|
||
wp_enqueue_script(
|
||
'camp-script',
|
||
get_template_directory_uri() . '/assets/js/camp.js',
|
||
null,
|
||
'1.0.0',
|
||
true
|
||
);
|
||
}
|
||
if (is_page_template('page-reviews.php')) {
|
||
// Phosphor Icons загружаются через preload+onload в wp_head (page-reviews.php:46)
|
||
// Не используем wp_enqueue_style — избегаем render-blocking
|
||
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-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_singular('teacher')) {
|
||
wp_enqueue_style(
|
||
'single-teacher-style',
|
||
get_template_directory_uri() . '/assets/css/single-teacher.css',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/css/single-teacher.css')
|
||
);
|
||
wp_enqueue_script(
|
||
'single-teacher-script',
|
||
get_template_directory_uri() . '/assets/js/single-teacher.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/single-teacher.js'),
|
||
true
|
||
);
|
||
}
|
||
if (is_page_template('page-after-school.php')) {
|
||
wp_enqueue_style(
|
||
'template-after-style',
|
||
get_template_directory_uri() . '/assets/css/after-school.css',
|
||
array(),
|
||
'1.1'
|
||
);
|
||
}
|
||
|
||
// PKS: Подготовка к школе — CSS и JS
|
||
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')
|
||
);
|
||
wp_enqueue_script(
|
||
'pksh-timer',
|
||
get_template_directory_uri() . '/assets/js/pksh-timer.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/pksh-timer.js'),
|
||
true
|
||
);
|
||
wp_enqueue_script(
|
||
'pksh-sticky-cta',
|
||
get_template_directory_uri() . '/assets/js/pksh-sticky-cta.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/pksh-sticky-cta.js'),
|
||
true
|
||
);
|
||
}
|
||
|
||
// Front page
|
||
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
|
||
);
|
||
wp_enqueue_script(
|
||
'sticky-cta',
|
||
get_template_directory_uri() . '/assets/js/sticky-cta.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/sticky-cta.js'),
|
||
true
|
||
);
|
||
}
|
||
|
||
// Страница начальной школы — hero в стиле главной + cta-секция
|
||
if (is_page_template('page-elementary-school.php')) {
|
||
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_style(
|
||
'school-style',
|
||
get_template_directory_uri() . '/assets/css/school.css',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/css/school.css')
|
||
);
|
||
wp_enqueue_script(
|
||
'school-script',
|
||
get_template_directory_uri() . '/assets/js/school.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/school.js'),
|
||
true
|
||
);
|
||
wp_enqueue_script(
|
||
'sticky-cta',
|
||
get_template_directory_uri() . '/assets/js/sticky-cta.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/sticky-cta.js'),
|
||
true
|
||
);
|
||
}
|
||
|
||
// Страница КЛАССА начальной школы — наследует стили школы + свои
|
||
if (is_page_template('page-class.php')) {
|
||
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_style(
|
||
'school-style',
|
||
get_template_directory_uri() . '/assets/css/school.css',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/css/school.css')
|
||
);
|
||
wp_enqueue_style(
|
||
'class-style',
|
||
get_template_directory_uri() . '/assets/css/class.css',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/css/class.css')
|
||
);
|
||
wp_enqueue_script(
|
||
'class-script',
|
||
get_template_directory_uri() . '/assets/js/class.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/class.js'),
|
||
true
|
||
);
|
||
wp_enqueue_script(
|
||
'sticky-cta',
|
||
get_template_directory_uri() . '/assets/js/sticky-cta.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/sticky-cta.js'),
|
||
true
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* IndexNow — автоматический пинг поисковых систем при обновлении контента.
|
||
*
|
||
* @see https://www.indexnow.org/
|
||
*/
|
||
add_action('wp_head', function () {
|
||
$key = get_option('indexnow_api_key', 'b8a7c3d9e1f204856a7b9c0d1e2f3a4b');
|
||
$loc = home_url('/.well-known/' . $key . '.txt');
|
||
echo '<link rel="alternate" type="application/json" href="' . esc_url($loc) . '" />' . "\n";
|
||
});
|
||
|
||
/**
|
||
* Пинг IndexNow при публикации/обновлении поста.
|
||
*/
|
||
add_action('publish_post', 'dekart_ping_indexnow', 10, 2);
|
||
add_action('publish_page', 'dekart_ping_indexnow', 10, 2);
|
||
function dekart_ping_indexnow($post_id, $post)
|
||
{
|
||
if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) {
|
||
return;
|
||
}
|
||
$key = get_option('indexnow_api_key', 'b8a7c3d9e1f204856a7b9c0d1e2f3a4b');
|
||
$urls = array( get_permalink($post_id) );
|
||
$body = wp_json_encode(array(
|
||
'host' => wp_parse_url(home_url(), PHP_URL_HOST),
|
||
'key' => $key,
|
||
'urlList' => $urls,
|
||
));
|
||
wp_remote_post('https://api.indexnow.org/indexnow', array(
|
||
'body' => $body,
|
||
'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
|
||
'timeout' => 5,
|
||
'blocking' => false,
|
||
));
|
||
}
|
||
|
||
/**
|
||
* CrUX — Chrome User Experience Report.
|
||
* Добавляет заголовок для мониторинга реальных пользовательских метрик.
|
||
*/
|
||
add_action('send_headers', function () {
|
||
if (! is_admin()) {
|
||
header('Link: <https://chromeuxreport.googleapis.com/>; rel=preconnect', false);
|
||
}
|
||
});
|
||
|
||
// Очистка метабоксов на странице Подготовка к школе — оставить только CF и Yoast
|
||
add_action('load-post.php', function () {
|
||
$post_id = isset($_GET['post']) ? (int) $_GET['post'] : 0;
|
||
if (! $post_id) {
|
||
return;
|
||
}
|
||
if ('page-podgotovka-k-shkole.php' !== get_page_template_slug($post_id)) {
|
||
return;
|
||
}
|
||
add_action('add_meta_boxes', function () {
|
||
foreach (
|
||
array(
|
||
'postcustom' => array( 'page', 'normal' ),
|
||
'commentstatusdiv' => array( 'page', 'normal' ),
|
||
'commentsdiv' => array( 'page', 'normal' ),
|
||
'slugdiv' => array( 'page', 'normal' ),
|
||
'authordiv' => array( 'page', 'normal' ),
|
||
'revisionsdiv' => array( 'page', 'normal' ),
|
||
'postexcerpt' => array( 'page', 'normal' ),
|
||
'pageparentdiv' => array( 'page', 'side' ),
|
||
) as $box_id => $args
|
||
) {
|
||
remove_meta_box($box_id, $args[0], $args[1]);
|
||
}
|
||
}, 100);
|
||
});
|
||
|
||
add_action('wp_enqueue_scripts', 'enqueue_template_specific_styles');
|
||
// Удаляем ненужные inline-стили WordPress Block Library — тема кастомная, блоки не используются
|
||
add_action('wp_enqueue_scripts', static function () {
|
||
wp_dequeue_style('wp-block-library');
|
||
wp_dequeue_style('classic-theme-styles');
|
||
wp_dequeue_style('global-styles');
|
||
|
||
// WP 6.8+ re-enqueue global-styles на wp_footer (priority 1) для hoist-механизма
|
||
// (wp_hoist_late_printed_styles). Удаляем re-enqueue — иначе dequeue выше бесполезен.
|
||
remove_action('wp_footer', 'wp_enqueue_global_styles', 1);
|
||
}, 100);
|
||
|
||
|
||
|
||
// Enqueue вынесенный global-styles CSS внешним файлом (кэшируемый)
|
||
add_action('wp_enqueue_scripts', 'enqueue_block_library_global_styles');
|
||
function enqueue_block_library_global_styles(): void
|
||
{
|
||
$file_path = get_template_directory() . '/assets/css/block-library-global-styles.css';
|
||
if (! file_exists($file_path)) {
|
||
return;
|
||
}
|
||
wp_enqueue_style(
|
||
'block-library-global-styles',
|
||
get_template_directory_uri() . '/assets/css/block-library-global-styles.css',
|
||
array(),
|
||
filemtime($file_path)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Helper: determine if current page needs Swiper slider assets.
|
||
*
|
||
* @return bool True if the current page uses Swiper directly or via template-parts.
|
||
*/
|
||
function needs_swiper(): bool
|
||
{
|
||
if (is_singular([ 'course', 'teacher' ])) {
|
||
return true;
|
||
}
|
||
$swiper_templates = [
|
||
'page-after-school.php',
|
||
'page-foto.php',
|
||
'page-o-nas.php',
|
||
'page-elementary-school.php',
|
||
'page-contacts.php',
|
||
'page-camp.php',
|
||
];
|
||
foreach ($swiper_templates as $tmpl) {
|
||
if (is_page_template($tmpl)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
add_shortcode('get_form_bitrix', 'form_bitrix');
|
||
function form_bitrix($atts, $content = null)
|
||
{
|
||
return carbon_get_theme_option('site_bitrix_script');
|
||
}
|
||
|
||
add_shortcode('get_reviews', 'sc_reviews');
|
||
function sc_reviews($atts)
|
||
{
|
||
$atts = shortcode_atts([
|
||
'type' => 'school',
|
||
], $atts);
|
||
set_query_var('type', $atts['type']);
|
||
ob_start();
|
||
load_template(locate_template('/template-parts/reviews.php'), false);
|
||
return ob_get_clean();
|
||
}
|
||
|
||
add_shortcode('get_teachers', 'sc_teachers');
|
||
function sc_teachers($atts, $content = null)
|
||
{
|
||
ob_start();
|
||
set_query_var('sc_teachers', '1');
|
||
load_template(locate_template('/template-parts/teachers.php'), false);
|
||
return ob_get_clean();
|
||
}
|
||
|
||
/**
|
||
* Карта «преподаватель → число опубликованных отзывов» (один запрос на страницу).
|
||
* Учитывает CF association review_teacher и легаси-ключ prepodavatel.
|
||
*
|
||
* @return array<int,int>
|
||
*/
|
||
function dekart_teacher_review_counts(): array
|
||
{
|
||
static $map = null;
|
||
if (null !== $map) {
|
||
return $map;
|
||
}
|
||
$map = array();
|
||
|
||
$review_ids = get_posts(array(
|
||
'post_type' => 'reviews',
|
||
'post_status' => 'publish',
|
||
'posts_per_page' => -1,
|
||
'fields' => 'ids',
|
||
'no_found_rows' => true,
|
||
'update_post_meta_cache' => true,
|
||
));
|
||
|
||
$link_keys = array( '_review_teacher', 'review_teacher', 'prepodavatel' );
|
||
|
||
foreach ($review_ids as $review_id) {
|
||
$teacher_id = 0;
|
||
|
||
// Основной путь: Carbon Fields Association (ключи вида _review_teacher|||0|id)
|
||
if (function_exists('carbon_get_post_meta')) {
|
||
$cached = carbon_get_post_meta((int) $review_id, 'review_teacher');
|
||
if (is_array($cached)) {
|
||
foreach ($cached as $entry) {
|
||
if (is_array($entry) && ! empty($entry['id'])) {
|
||
$teacher_id = (int) $entry['id'];
|
||
break;
|
||
}
|
||
if (is_string($entry) && preg_match('/post:teacher:(\d+)/', $entry, $m)) {
|
||
$teacher_id = (int) $m[1];
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// Legacy fallback: сырые ключи меты
|
||
if (! $teacher_id) {
|
||
foreach ($link_keys as $key) {
|
||
$raw = get_post_meta((int) $review_id, $key, true);
|
||
if (empty($raw)) {
|
||
continue;
|
||
}
|
||
$value = maybe_unserialize($raw);
|
||
$ids = array();
|
||
if (is_array($value)) {
|
||
foreach ($value as $entry) {
|
||
if (is_object($entry) && isset($entry->id)) {
|
||
$ids[] = (int) $entry->id;
|
||
} elseif (is_array($entry) && isset($entry['id'])) {
|
||
$ids[] = (int) $entry['id'];
|
||
} elseif (is_string($entry) && preg_match('/post:teacher:(\d+)/', $entry, $m)) {
|
||
$ids[] = (int) $m[1];
|
||
} elseif (is_numeric($entry)) {
|
||
$ids[] = (int) $entry;
|
||
}
|
||
}
|
||
} elseif (is_numeric($value)) {
|
||
$ids[] = (int) $value;
|
||
}
|
||
if (! empty($ids)) {
|
||
$teacher_id = $ids[0];
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ($teacher_id > 0) {
|
||
$map[ $teacher_id ] = isset($map[ $teacher_id ]) ? $map[ $teacher_id ] + 1 : 1;
|
||
}
|
||
}
|
||
|
||
return $map;
|
||
}
|
||
|
||
/**
|
||
* Число отзывов конкретного преподавателя.
|
||
*
|
||
* @param int $teacher_id ID записи CPT teacher.
|
||
* @return int
|
||
*/
|
||
function dekart_teacher_review_count(int $teacher_id): int
|
||
{
|
||
$map = dekart_teacher_review_counts();
|
||
return isset($map[ $teacher_id ]) ? (int) $map[ $teacher_id ] : 0;
|
||
}
|
||
|
||
/**
|
||
* OG-изображение 1200×630 для страницы «Преподаватели».
|
||
* Глобальный дефолт Yoast (banner-dekart-small.webp 355×250) даёт битый сниппет.
|
||
*/
|
||
add_filter('wpseo_opengraph_image', 'dekart_teachers_og_image', 10, 1);
|
||
function dekart_teachers_og_image($image)
|
||
{
|
||
if (is_page_template('page-teachers.php')) {
|
||
// Занятия для детей в Щёлково (медиатека), 1249×943 — релевантно теме страницы.
|
||
$og_url = wp_get_attachment_url(1043);
|
||
if ($og_url) {
|
||
return $og_url;
|
||
}
|
||
}
|
||
return $image;
|
||
}
|
||
|
||
function fix_page_1_in_pagination($link)
|
||
{
|
||
$reviews_page_id = 91;
|
||
$root_url = get_permalink($reviews_page_id);
|
||
if (substr($root_url, -1) !== '/') {
|
||
$root_url .= '/';
|
||
}
|
||
if (isset($_GET['filter'])) {
|
||
$root_url = add_query_arg('filter', esc_attr($_GET['filter']), $root_url);
|
||
}
|
||
$page_1_url_full = get_pagenum_link(1);
|
||
if (substr($page_1_url_full, -1) !== '/') {
|
||
$page_1_url_full .= '/';
|
||
}
|
||
$canonical_root_url = get_permalink($reviews_page_id);
|
||
if (substr($canonical_root_url, -1) !== '/') {
|
||
$canonical_root_url .= '/';
|
||
}
|
||
if (isset($_GET['filter'])) {
|
||
$canonical_root_url = add_query_arg('filter', esc_attr($_GET['filter']), $canonical_root_url);
|
||
}
|
||
$link = str_replace(
|
||
'href="' . esc_url($page_1_url_full) . '"',
|
||
'href="' . esc_url($canonical_root_url) . '"',
|
||
$link
|
||
);
|
||
$link = str_replace(
|
||
'href="' . esc_url(get_pagenum_link(1)) . '"',
|
||
'href="' . esc_url($canonical_root_url) . '"',
|
||
$link
|
||
);
|
||
return $link;
|
||
}
|
||
add_filter('paginate_links', 'fix_page_1_in_pagination');
|
||
|
||
remove_action('wp_head', 'wp_generator');
|
||
remove_action('wp_head', 'rest_output_link_wp_head');
|
||
remove_action('wp_head', 'wp_oembed_add_discovery_links');
|
||
remove_action('wp_head', 'wp_shortlink_wp_head');
|
||
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
|
||
remove_action('template_redirect', 'rest_output_link_header', 11);
|
||
|
||
function dekart_disable_emojis()
|
||
{
|
||
remove_action('wp_head', 'print_emoji_detection_script', 7);
|
||
remove_action('admin_print_scripts', 'print_emoji_detection_script');
|
||
remove_action('wp_print_styles', 'print_emoji_styles');
|
||
remove_action('admin_print_styles', 'print_emoji_styles');
|
||
remove_filter('the_content_feed', 'wp_staticize_emoji');
|
||
remove_filter('comment_text_rss', 'wp_staticize_emoji');
|
||
remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
|
||
add_filter('tiny_mce_plugins', 'dekart_disable_emojis_tinymce');
|
||
add_filter('wp_resource_hints', 'dekart_disable_emojis_remove_dns_prefetch', 10, 2);
|
||
}
|
||
add_action('init', 'dekart_disable_emojis');
|
||
|
||
function dekart_disable_emojis_tinymce($plugins)
|
||
{
|
||
if (is_array($plugins)) {
|
||
return array_diff($plugins, array('wpemoji'));
|
||
}
|
||
return array();
|
||
}
|
||
|
||
function dekart_disable_emojis_remove_dns_prefetch($urls, $relation_type)
|
||
{
|
||
if ('dns-prefetch' === $relation_type) {
|
||
$emoji_svg_url = apply_filters('emoji_svg_url', 'https://s.w.org/images/core/emoji/');
|
||
$urls = array_diff($urls, array($emoji_svg_url));
|
||
}
|
||
return $urls;
|
||
}
|
||
|
||
// ====================================================
|
||
// ✅ Оптимизация скриптов — defer только на фронтенде
|
||
// ====================================================
|
||
function dekart_add_defer_to_scripts($tag, $handle, $src)
|
||
{
|
||
// Не деферим скрипты в админке, AJAX и REST запросах
|
||
if (is_admin() || wp_doing_ajax() || ( defined('REST_REQUEST') && REST_REQUEST )) {
|
||
return $tag;
|
||
}
|
||
$no_defer = array(
|
||
'jquery-core',
|
||
'jquery',
|
||
'carbon-fields-script',
|
||
'wp-api-request',
|
||
'wp-element',
|
||
'wp-components',
|
||
);
|
||
if (in_array($handle, $no_defer)) {
|
||
return $tag;
|
||
}
|
||
if (strpos($tag, 'defer') !== false || strpos($tag, 'async') !== false) {
|
||
return $tag;
|
||
}
|
||
return str_replace('<script ', '<script defer ', $tag);
|
||
}
|
||
add_filter('script_loader_tag', 'dekart_add_defer_to_scripts', 10, 3);
|
||
|
||
// ====================================================
|
||
// ✅ Заголовки безопасности — только на фронтенде
|
||
// ====================================================
|
||
add_action('send_headers', 'dekart_security_headers');
|
||
function dekart_security_headers(): void
|
||
{
|
||
if (! is_admin()) {
|
||
if (is_ssl()) {
|
||
header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
|
||
}
|
||
header('X-Content-Type-Options: nosniff');
|
||
header('X-Frame-Options: SAMEORIGIN');
|
||
header('Referrer-Policy: strict-origin-when-cross-origin');
|
||
// Content-Security-Policy — базовый, без блокировки легаси-скриптов
|
||
header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn-ru.bitrix24.ru https://alee.bitrix24.ru https://api-maps.yandex.ru https://yastatic.net https://cdn.jsdelivr.net https://www.google.com https://www.gstatic.com https://www.googletagmanager.com https://mc.yandex.ru; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://alee.bitrix24.ru; img-src 'self' data: https: blob:; font-src 'self' data:; frame-src 'self' https://cdn-ru.bitrix24.ru https://alee.bitrix24.ru https://www.google.com; connect-src 'self' https://api-maps.yandex.ru https://yastatic.net https://cdn-ru.bitrix24.ru https://alee.bitrix24.ru https://mc.yandex.ru wss://mc.yandex.ru; object-src 'none'; base-uri 'self'; form-action 'self' https://alee.bitrix24.ru;");
|
||
}
|
||
}
|
||
|
||
function dekart_add_preload_hints()
|
||
{
|
||
// резерв для preload hints
|
||
}
|
||
add_action('wp_head', 'dekart_add_preload_hints', 1);
|
||
|
||
// ====================================================
|
||
// ✅ Hardening: XML-RPC + REST user enumeration (пред-продакшен)
|
||
// ====================================================
|
||
|
||
// XML-RPC полностью выключен (защита от pingback DDoS и брутфорса через system.multicall)
|
||
add_filter('xmlrpc_enabled', '__return_false');
|
||
|
||
// Убрать ВСЕ XML-RPC методы (включая анонимные pingback.* / system.* — вектор амплификации).
|
||
// WP 7.1: xmlrpc_enabled=false не блокирует анонимные методы, поэтому дублируем.
|
||
add_filter('xmlrpc_methods', '__return_empty_array');
|
||
|
||
// Закрыть REST-эндпоинты пользователей для анонимов (wp/v2/users раскрывает логины)
|
||
add_filter('rest_endpoints', static function (array $endpoints): array {
|
||
if (is_user_logged_in()) {
|
||
return $endpoints;
|
||
}
|
||
|
||
foreach (array_keys($endpoints) as $route) {
|
||
if (preg_match('#^/wp/v2/users(/|$)#', $route)) {
|
||
unset($endpoints[$route]);
|
||
}
|
||
}
|
||
|
||
return $endpoints;
|
||
});
|
||
|
||
/* ── Honest timer: end-of-month deadline ── */
|
||
/**
|
||
* Return end-of-current-month as ISO 8601 string.
|
||
* Stored in wp_option 'dekart_honest_deadline' so same value
|
||
* is used by PHP (template) and exposed to JS.
|
||
*/
|
||
function dekart_get_honest_deadline(): string
|
||
{
|
||
$cached = get_option('dekart_honest_deadline', '');
|
||
if ($cached && (int) $cached > time()) {
|
||
return $cached;
|
||
}
|
||
return dekart_recalc_honest_deadline();
|
||
}
|
||
|
||
function dekart_recalc_honest_deadline(): string
|
||
{
|
||
$end = new DateTime('last day of this month 23:59:59');
|
||
$ts = (int) $end->format('U'); // Unix timestamp — безопасен для JSON/JS
|
||
update_option('dekart_honest_deadline', $ts, false);
|
||
return (string) $ts;
|
||
}
|
||
|
||
add_action('dekart_daily_refresh_deadline', 'dekart_recalc_honest_deadline');
|
||
if (! wp_next_scheduled('dekart_daily_refresh_deadline')) {
|
||
wp_schedule_event(time(), 'daily', 'dekart_daily_refresh_deadline');
|
||
}
|
||
|
||
// === ACF JSON Auto-save ===
|
||
// Автоматически сохраняет группы полей в JSON при редактировании
|
||
add_filter('acf/settings/save_json', function ($path) {
|
||
return get_stylesheet_directory() . '/acf-json';
|
||
});
|
||
|
||
// Загружает группы полей из JSON
|
||
add_filter('acf/settings/load_json', function ($paths) {
|
||
$paths[] = get_stylesheet_directory() . '/acf-json';
|
||
return $paths;
|
||
});
|
||
|
||
// Автоматическое удаление JSON при удалении группы полей
|
||
add_action('trashed_post', 'dekart_acf_delete_json', 10, 1);
|
||
add_action('deleted_post', 'dekart_acf_delete_json', 10, 1);
|
||
function dekart_acf_delete_json($post_id)
|
||
{
|
||
if (get_post_type($post_id) !== 'acf-field-group') {
|
||
return;
|
||
}
|
||
|
||
$key = get_post_field('post_name', $post_id);
|
||
$json_file = get_stylesheet_directory() . '/acf-json/' . $key . '.json';
|
||
|
||
if (file_exists($json_file)) {
|
||
unlink($json_file);
|
||
}
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────
|
||
// Счетчики — перенесены во вкладку «Настройки филиала»
|
||
// (ТОП-меню удалено; опции зарегистрированы в dekart_branch_group;
|
||
// вывод на фронте — те же хуки wp_head/wp_body_open/wp_footer)
|
||
// ─────────────────────────────────────────────────────────────
|
||
add_action('admin_init', 'dekart_counters_settings');
|
||
function dekart_counters_settings()
|
||
{
|
||
register_setting('dekart_counters_group', 'dekart_counter_yandex');
|
||
register_setting('dekart_counters_group', 'dekart_counter_gtm_head');
|
||
register_setting('dekart_counters_group', 'dekart_counter_gtm_body');
|
||
register_setting('dekart_counters_group', 'dekart_counter_footer');
|
||
|
||
$yandex_default = "<!-- Yandex.Metrika counter -->\n<script>\n (function(m,e,t,r,i,k,a){\n m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};\n m[i].l=1*new Date();\n for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}\n k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)\n })(window, document,'script','https://mc.yandex.ru/metrika/tag.js', 'ym');\n\n ym(99835482, 'init', {webvisor:true, clickmap:true, referrer: document.referrer, url: location.href, accurateTrackBounce:true, trackLinks:true});\n</script>\n<!-- /Yandex.Metrika counter -->";
|
||
|
||
$gtm_head_default = "<!-- Google Tag Manager -->\n<script>\n(function(w,d,s,l,i){\n w[l]=w[l]||[];\n w[l].push({'gtm.start':new Date().getTime(),event:'gtm.js'});\n var f=d.getElementsByTagName(s)[0],\n j=d.createElement(s),\n dl=l!='dataLayer'?'&l='+l:'';\n j.async=true;\n j.src='https://www.googletagmanager.com/gtm.js?id='+i+dl;\n f.parentNode.insertBefore(j,f);\n})(window,document,'script','dataLayer','GTM-WJVZ4MKN');\n</script>\n<!-- /Google Tag Manager -->";
|
||
|
||
$gtm_body_default = "<!-- Google Tag Manager (noscript) -->\n<noscript><iframe src=\"https://www.googletagmanager.com/ns.html?id=GTM-WJVZ4MKN\"\nheight=\"0\" width=\"0\" style=\"display:none;visibility:hidden\"></iframe></noscript>\n<!-- /Google Tag Manager (noscript) -->";
|
||
|
||
$footer_default = "<!-- Yandex.Metrika counter -->\n<noscript><div><img src=\"https://mc.yandex.ru/watch/99835482\" style=\"position:absolute; left:-9999px;\" alt=\"\"></div></noscript>\n<!-- /Yandex.Metrika counter -->";
|
||
|
||
if (get_option('dekart_counter_yandex') === false) {
|
||
add_option('dekart_counter_yandex', $yandex_default);
|
||
}
|
||
if (get_option('dekart_counter_gtm_head') === false) {
|
||
add_option('dekart_counter_gtm_head', $gtm_head_default);
|
||
}
|
||
if (get_option('dekart_counter_gtm_body') === false) {
|
||
add_option('dekart_counter_gtm_body', $gtm_body_default);
|
||
}
|
||
if (get_option('dekart_counter_footer') === false) {
|
||
add_option('dekart_counter_footer', $footer_default);
|
||
}
|
||
}
|
||
|
||
function dekart_counters_page()
|
||
{
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Счетчики</h1>
|
||
<form method="post" action="options.php">
|
||
<?php settings_fields('dekart_counters_group'); ?>
|
||
<h2 class="title">Яндекс.Метрика / Tag Manager</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th scope="row">Yandex Code</th>
|
||
<td><textarea name="dekart_counter_yandex" rows="10" class="large-text code"><?php echo esc_textarea(get_option('dekart_counter_yandex', '')); ?></textarea>
|
||
<p class="description">Код счетчика. Выводится в <code><head></code>.</p></td>
|
||
</tr>
|
||
</table>
|
||
<h2 class="title">Google Tag Manager (GTM)</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th scope="row">GTM Head</th>
|
||
<td><textarea name="dekart_counter_gtm_head" rows="10" class="large-text code"><?php echo esc_textarea(get_option('dekart_counter_gtm_head', '')); ?></textarea>
|
||
<p class="description">Основной код GTM. Выводится в <code><head></code>.</p></td>
|
||
</tr>
|
||
<tr>
|
||
<th scope="row">GTM Body</th>
|
||
<td><textarea name="dekart_counter_gtm_body" rows="6" class="large-text code"><?php echo esc_textarea(get_option('dekart_counter_gtm_body', '')); ?></textarea>
|
||
<p class="description">Код <code><noscript></code>. Выводится сразу после открытия <code><body></code> через хук <code>wp_body_open</code>.</p></td>
|
||
</tr>
|
||
</table>
|
||
<h2 class="title">Произвольные скрипты</h2>
|
||
<table class="form-table">
|
||
<tr>
|
||
<th scope="row">Site-wide Footer Scripts</th>
|
||
<td><textarea name="dekart_counter_footer" rows="10" class="large-text code"><?php echo esc_textarea(get_option('dekart_counter_footer', '')); ?></textarea>
|
||
<p class="description">Для чатов, пикселей и прочих скриптов. Выводится в <code><footer></code>.</p></td>
|
||
</tr>
|
||
</table>
|
||
<?php submit_button(); ?>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
add_action('wp_head', 'dekart_output_counters', 1);
|
||
function dekart_output_counters()
|
||
{
|
||
$yandex = stripslashes(get_option('dekart_counter_yandex', ''));
|
||
$gtmhead = stripslashes(get_option('dekart_counter_gtm_head', ''));
|
||
if ($yandex) {
|
||
echo "\n" . $yandex . "\n";
|
||
}
|
||
if ($gtmhead) {
|
||
echo "\n" . $gtmhead . "\n";
|
||
}
|
||
}
|
||
|
||
add_action('wp_body_open', 'dekart_output_gtm_body', 1);
|
||
function dekart_output_gtm_body()
|
||
{
|
||
$gtmbody = stripslashes(get_option('dekart_counter_gtm_body', ''));
|
||
if ($gtmbody) {
|
||
echo "\n" . $gtmbody . "\n";
|
||
}
|
||
}
|
||
|
||
add_action('wp_footer', 'dekart_output_counters_footer', 100);
|
||
function dekart_output_counters_footer()
|
||
{
|
||
$footer = stripslashes(get_option('dekart_counter_footer', ''));
|
||
if ($footer) {
|
||
echo "\n" . $footer . "\n";
|
||
}
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────
|
||
// 🎨 Тёмная тема для Carbon Fields + Настройки филиала
|
||
// ─────────────────────────────────────────────────────────────
|
||
add_action('admin_head', function () {
|
||
$screen = get_current_screen();
|
||
if (! $screen) { return; }
|
||
$is_carbon = strpos($screen->id, 'carbon_fields') !== false;
|
||
if (! $is_carbon) { return; }
|
||
?>
|
||
<style>
|
||
:root {
|
||
--cf-bg: #1a1a2e;
|
||
--cf-bg-card: #2a2a3e;
|
||
--cf-bg-input: #363650;
|
||
--cf-border: #3e3e5a;
|
||
--cf-text: #e0e0f0;
|
||
--cf-text-muted: #9090b0;
|
||
--cf-primary: #7c5cfc;
|
||
--cf-primary-bg: rgba(124,92,252,0.12);
|
||
--cf-success: #4ade80;
|
||
--cf-warning: #fbbf24;
|
||
}
|
||
/* Общий фон страницы */
|
||
body.branch-settings_page_carbon_fields,
|
||
body.toplevel_page_carbon_fields {
|
||
background: var(--cf-bg) !important;
|
||
}
|
||
#wpbody-content .wrap {
|
||
background: transparent !important;
|
||
}
|
||
/* Carbon Fields dark */
|
||
#carbon_fields_container_Настройки_темы_ДЕКАРТ {
|
||
background: var(--cf-bg) !important;
|
||
color: var(--cf-text) !important;
|
||
}
|
||
.cf-container__tabs-list {
|
||
background: var(--cf-bg-card) !important;
|
||
border-color: var(--cf-border) !important;
|
||
}
|
||
.cf-container__tabs-item {
|
||
color: var(--cf-text-muted) !important;
|
||
}
|
||
.cf-container__tabs-item--current {
|
||
background: var(--cf-bg) !important;
|
||
color: var(--cf-text) !important;
|
||
border-color: var(--cf-primary) !important;
|
||
}
|
||
.cf-container__tabs-item:hover {
|
||
color: var(--cf-text) !important;
|
||
background: var(--cf-primary-bg) !important;
|
||
}
|
||
.cf-field {
|
||
background: var(--cf-bg-card) !important;
|
||
border-color: var(--cf-border) !important;
|
||
}
|
||
.cf-field__label {
|
||
color: var(--cf-text) !important;
|
||
}
|
||
.cf-field input[type="text"],
|
||
.cf-field input[type="email"],
|
||
.cf-field input[type="url"],
|
||
.cf-field input[type="number"],
|
||
.cf-field textarea,
|
||
.cf-field select {
|
||
background: var(--cf-bg-input) !important;
|
||
color: var(--cf-text) !important;
|
||
border-color: var(--cf-border) !important;
|
||
}
|
||
.cf-field input:focus,
|
||
.cf-field textarea:focus,
|
||
.cf-field select:focus {
|
||
border-color: var(--cf-primary) !important;
|
||
box-shadow: 0 0 0 1px var(--cf-primary) !important;
|
||
}
|
||
.cf-complex__groups {
|
||
background: var(--cf-bg) !important;
|
||
}
|
||
.cf-complex__group {
|
||
background: var(--cf-bg-card) !important;
|
||
border-color: var(--cf-border) !important;
|
||
}
|
||
.cf-complex__group__title {
|
||
background: var(--cf-bg-input) !important;
|
||
color: var(--cf-text) !important;
|
||
}
|
||
.cf-help-text {
|
||
color: var(--cf-text-muted) !important;
|
||
}
|
||
.cf-field__help {
|
||
color: var(--cf-text-muted) !important;
|
||
}
|
||
.cf-container__text {
|
||
color: var(--cf-text-muted) !important;
|
||
}
|
||
.cf-container h1, .cf-container h2, .cf-container h3 {
|
||
color: var(--cf-text) !important;
|
||
}
|
||
hr {
|
||
border-color: var(--cf-border) !important;
|
||
}
|
||
/* Compact Carbon Fields */
|
||
.cf-field {
|
||
padding: 12px 16px !important;
|
||
margin: 4px 0 !important;
|
||
}
|
||
.cf-field__label {
|
||
font-size: 12px !important;
|
||
margin-bottom: 4px !important;
|
||
}
|
||
.cf-container__tabs {
|
||
margin-bottom: 8px !important;
|
||
}
|
||
.cf-container__tabs-item {
|
||
padding: 8px 14px !important;
|
||
font-size: 12px !important;
|
||
}
|
||
.cf-complex__group {
|
||
margin: 4px 0 !important;
|
||
}
|
||
.cf-field input, .cf-field textarea, .cf-field select {
|
||
font-size: 13px !important;
|
||
padding: 6px 10px !important;
|
||
}
|
||
/* Settings API dark + compact */
|
||
.branch-section {
|
||
background: var(--cf-bg-card) !important;
|
||
border-color: var(--cf-border) !important;
|
||
padding: 12px 16px !important;
|
||
margin: 8px 0 !important;
|
||
}
|
||
.branch-section.collapsed {
|
||
background: var(--cf-bg) !important;
|
||
border-color: var(--cf-border) !important;
|
||
}
|
||
.branch-section h2 {
|
||
color: var(--cf-text) !important;
|
||
font-size: 14px !important;
|
||
padding-bottom: 8px !important;
|
||
}
|
||
.branch-section label {
|
||
color: var(--cf-text) !important;
|
||
font-size: 12px !important;
|
||
}
|
||
.branch-section input,
|
||
.branch-section textarea,
|
||
.branch-section select {
|
||
background: var(--cf-bg-input) !important;
|
||
color: var(--cf-text) !important;
|
||
border-color: var(--cf-border) !important;
|
||
font-size: 13px !important;
|
||
padding: 6px 10px !important;
|
||
}
|
||
.branch-section .desc {
|
||
color: var(--cf-text-muted) !important;
|
||
font-size: 11px !important;
|
||
}
|
||
.branch-field {
|
||
margin-bottom: 10px !important;
|
||
}
|
||
.wrap h1 {
|
||
color: var(--cf-text) !important;
|
||
}
|
||
.wrap p, .wrap label {
|
||
color: var(--cf-text) !important;
|
||
}
|
||
.branch-section.collapsed {
|
||
border-color: var(--cf-border) !important;
|
||
}
|
||
/* submit button */
|
||
.wrap .button-primary {
|
||
background: var(--cf-primary) !important;
|
||
border-color: var(--cf-primary) !important;
|
||
color: #fff !important;
|
||
}
|
||
</style>
|
||
<?php
|
||
}, 999);
|
||
|
||
// ─────────────────────────────────────────────────────────────
|
||
// Настройки филиала — WordPress Settings API (под Счетчиками)
|
||
// ─────────────────────────────────────────────────────────────
|
||
add_action('admin_menu', 'dekart_branch_add_menu');
|
||
function dekart_branch_add_menu()
|
||
{
|
||
add_menu_page(
|
||
'Настройки филиала',
|
||
'Настройки филиала',
|
||
'edit_posts',
|
||
'branch-settings',
|
||
'dekart_branch_settings_page',
|
||
'dashicons-location-alt',
|
||
3.1
|
||
);
|
||
add_submenu_page(
|
||
'branch-settings',
|
||
'Сбросить кэш',
|
||
'🗄️ Сбросить кэш',
|
||
'manage_options',
|
||
'branch-cache-flush',
|
||
'dekart_flush_cache_page'
|
||
);
|
||
}
|
||
|
||
add_action('admin_init', 'dekart_branch_register_settings');
|
||
function dekart_branch_register_settings()
|
||
{
|
||
// Кастомная валидация branch_city от опечаток и лишних пробелов
|
||
add_filter('sanitize_option_branch_city', function ($value) {
|
||
$value = trim($value);
|
||
$value = preg_replace('/\s+/', ' ', $value); // множественные пробелы → один
|
||
$value = mb_strtoupper(mb_substr($value, 0, 1)) . mb_substr($value, 1); // первая заглавная
|
||
return $value;
|
||
});
|
||
$text_fields = array(
|
||
'branch_city_prep' => 'text',
|
||
'branch_city' => 'text',
|
||
'branch_region' => 'text',
|
||
'branch_address' => 'text',
|
||
'branch_coords' => 'text',
|
||
'branch_postal_code' => 'text',
|
||
'branch_phone' => 'text',
|
||
'branch_email' => 'email',
|
||
'branch_name' => 'text',
|
||
'branch_price_range' => 'text',
|
||
'branch_price' => 'text',
|
||
'branch_price_note' => 'text',
|
||
'branch_logistics_walk' => 'text',
|
||
'branch_logistics_parking' => 'text',
|
||
'branch_logistics_schools' => 'text',
|
||
'branch_area_served' => 'text',
|
||
'branch_director_name' => 'text',
|
||
'branch_director_creds' => 'text',
|
||
);
|
||
foreach ($text_fields as $slug => $type) {
|
||
register_setting('dekart_branch_group', $slug, array( 'sanitize_callback' => $type === 'email' ? 'sanitize_email' : ( $type === 'url' ? 'esc_url_raw' : 'sanitize_text_field' ) ));
|
||
}
|
||
register_setting('dekart_branch_group', 'branch_logo', array( 'sanitize_callback' => 'absint' ));
|
||
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_camp_script', array( 'sanitize_callback' => 'dekart_sanitize_script_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_vk', 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' ));
|
||
register_setting('dekart_branch_group', 'branch_og_site_name', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_ext_review_count', array( 'sanitize_callback' => 'absint' ));
|
||
register_setting('dekart_branch_group', 'branch_avg_rating', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_rating_yandex', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_rating_2gis', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_rating_vk', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_rating_otzovik', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_remaining_seats', array( 'sanitize_callback' => 'absint' ));
|
||
register_setting('dekart_branch_group', 'branch_messenger_whatsapp', array( 'sanitize_callback' => 'esc_url_raw' ));
|
||
register_setting('dekart_branch_group', 'branch_messenger_telegram', array( 'sanitize_callback' => 'esc_url_raw' ));
|
||
register_setting('dekart_branch_group', 'branch_messenger_max', array( 'sanitize_callback' => 'esc_url_raw' ));
|
||
register_setting('dekart_branch_group', 'branch_messenger_whatsapp_on', array( 'sanitize_callback' => 'absint' ));
|
||
register_setting('dekart_branch_group', 'branch_messenger_telegram_on', array( 'sanitize_callback' => 'absint' ));
|
||
register_setting('dekart_branch_group', 'branch_messenger_max_on', array( 'sanitize_callback' => 'absint' ));
|
||
register_setting('dekart_branch_group', 'branch_messenger_extra');
|
||
register_setting('dekart_branch_group', 'branch_schema_description', array( 'sanitize_callback' => 'sanitize_textarea_field' ));
|
||
register_setting('dekart_branch_group', 'branch_license', array( 'sanitize_callback' => 'sanitize_textarea_field' ));
|
||
register_setting('dekart_branch_group', 'branch_area_served', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_programs', array( 'sanitize_callback' => 'dekart_sanitize_branch_programs' ));
|
||
register_setting('dekart_branch_group', 'branch_price_school', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_price_preschool', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_price_afterschool', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_price_exam', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_price_camp', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_price_clubs', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_work_hours', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_hours', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_google_place_id', array( 'sanitize_callback' => 'sanitize_text_field' ));
|
||
register_setting('dekart_branch_group', 'branch_google_maps_url', array( 'sanitize_callback' => 'esc_url_raw' ));
|
||
register_setting('dekart_branch_group', 'branch_google_business_url', array( 'sanitize_callback' => 'esc_url_raw' ));
|
||
register_setting('dekart_branch_group', 'branch_yandex_business_url', array( 'sanitize_callback' => 'esc_url_raw' ));
|
||
register_setting('dekart_branch_group', 'branch_logistics_walk', array( 'sanitize_callback' => 'sanitize_textarea_field' ));
|
||
register_setting('dekart_branch_group', 'branch_logistics_parking', array( 'sanitize_callback' => 'sanitize_textarea_field' ));
|
||
register_setting('dekart_branch_group', 'branch_logistics_nearby', array( 'sanitize_callback' => 'sanitize_textarea_field' ));
|
||
// Поля branch_map_url, branch_founded, branch_photos — удалены.
|
||
// Они дублировали CF таб «SEO и микроразметка» (schema_*).
|
||
// Чтение: inc/schema.php → dekart_schema_option() → CF → Settings API (backward compat).
|
||
|
||
// Счётчики (перенесены из ТОП-меню «Счетчики» во вкладку филиала).
|
||
// Регистрация в группе филиала, чтобы сохранялись одной кнопкой.
|
||
// Старая группа dekart_counters_group остаётся для обратной совместимости.
|
||
foreach (array( 'dekart_counter_yandex', 'dekart_counter_gtm_head', 'dekart_counter_gtm_body', 'dekart_counter_footer' ) as $counter_option) {
|
||
register_setting('dekart_branch_group', $counter_option);
|
||
}
|
||
}
|
||
|
||
function dekart_branch_settings_page()
|
||
{
|
||
?>
|
||
<div class="wrap">
|
||
<h1>Настройки филиала</h1>
|
||
<form method="post" action="options.php">
|
||
<?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;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 collapsed">
|
||
<h2>🌍 ГЕО</h2>
|
||
<div class="branch-section-body">
|
||
<div class="branch-field">
|
||
<label>Город (с предлогом)</label>
|
||
<input type="text" name="branch_city_prep" value="<?php echo esc_attr(get_option('branch_city_prep', 'в Щёлково')); ?>">
|
||
<p class="desc">Например: "в Щёлково", "в Королёве". Для alt-текстов и описаний.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Город (чистый)</label>
|
||
<input type="text" name="branch_city" value="<?php echo esc_attr(get_option('branch_city', 'Щёлково')); ?>">
|
||
<p class="desc">Для JSON-LD addressLocality.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Регион</label>
|
||
<input type="text" name="branch_region" value="<?php echo esc_attr(get_option('branch_region', 'Московская область')); ?>">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Адрес (улица, дом)</label>
|
||
<input type="text" name="branch_address" value="<?php echo esc_attr(get_option('branch_address', 'ул. Талсинская, 24')); ?>">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Координаты для карты</label>
|
||
<input type="text" name="branch_coords" value="<?php echo esc_attr(get_option('branch_coords', '55.9217, 37.9914')); ?>">
|
||
<p class="desc">Формат: "55.9217, 37.9914"</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Почтовый индекс</label>
|
||
<input type="text" name="branch_postal_code" value="<?php echo esc_attr(get_option('branch_postal_code', '')); ?>">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Часы работы (текст — контакты)</label>
|
||
<input type="text" name="branch_work_hours" value="<?php echo esc_attr(get_option('branch_work_hours', 'пн-пт 8:30–19:00, сб 9:00–15:00')); ?>">
|
||
<p class="desc">Показывается в блоке контактов. Например: "пн-пт 8:30–19:00, сб 9:00–15:00"</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Часы работы (текст — хедер)</label>
|
||
<input type="text" name="branch_hours" value="<?php echo esc_attr(get_option('branch_hours', 'ежедневно с 8:00 до 19:00, кроме субботы')); ?>">
|
||
<p class="desc">Показывается на главной странице в hero-секции, рядом с адресом. Например: "ежедневно с 8:00 до 19:00, кроме субботы" или "пн-пт 8:00–19:00, сб 9:00–14:00"</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Google Place ID</label>
|
||
<input type="text" name="branch_google_place_id" value="<?php echo esc_attr(get_option('branch_google_place_id', '')); ?>">
|
||
<p class="desc">Из Google Business Profile. Для Schema.org identifier + @id</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Google Maps URL</label>
|
||
<input type="url" name="branch_google_maps_url" value="<?php echo esc_attr(get_option('branch_google_maps_url', '')); ?>">
|
||
<p class="desc">Полная ссылка на профиль в Google Maps. Для Schema.org hasMap</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Пешком от ориентира</label>
|
||
<input type="text" name="branch_logistics_walk" value="<?php echo esc_attr(get_option('branch_logistics_walk', '5 минут пешком от ТЦ «Глобус»')); ?>">
|
||
<p class="desc">Например: «5 минут пешком от ТЦ «Глобус»</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Парковка</label>
|
||
<input type="text" name="branch_logistics_parking" value="<?php echo esc_attr(get_option('branch_logistics_parking', 'Есть бесплатная парковка у входа')); ?>">
|
||
<p class="desc">Например: «Есть бесплатная парковка у входа»</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Рядом с школами/садами</label>
|
||
<input type="text" name="branch_logistics_schools" value="<?php echo esc_attr(get_option('branch_logistics_schools', 'Рядом со школами №9 и №12, детским садом №15')); ?>">
|
||
<p class="desc">Например: «Рядом со школами №9 и №12, детским садом №15»</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Гео — города обслуживания</label>
|
||
<input type="text" name="branch_area_served" value="<?php echo esc_attr(get_option('branch_area_served', 'Щёлково, Фрязино и Ивантеевки')); ?>">
|
||
<p class="desc">Регион работы школы: перечислите города через запятую. Используется в текстах «Принимаем детей из ...».<br>
|
||
<strong>Пример:</strong> «Щёлково, Фрязино, Ивантеевка, Королёв»<br>
|
||
<strong>Формат:</strong> названия городов в именительном падеже, через запятую.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="branch-section collapsed">
|
||
<h2>📞 КОНТАКТЫ</h2>
|
||
<div class="branch-section-body">
|
||
<div class="branch-field">
|
||
<label>Телефон</label>
|
||
<input type="text" name="branch_phone" value="<?php echo esc_attr(get_option('branch_phone', '+7 (495) 120-00-78')); ?>">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Email</label>
|
||
<input type="email" name="branch_email" value="<?php echo esc_attr(get_option('branch_email', 'info@dekart.school')); ?>">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Автор контента — ФИО</label>
|
||
<input type="text" name="branch_director_name" value="<?php echo esc_attr(get_option('branch_director_name', 'Елена Сергеевна Дегтярёва')); ?>">
|
||
<p class="desc">Для E-E-A-T: имя автора страниц школ. Выводится в подвале.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Автор контента — должность и опыт</label>
|
||
<input type="text" name="branch_director_creds" value="<?php echo esc_attr(get_option('branch_director_creds', 'директор частной школы «Декарт», педагогический стаж 18 лет')); ?>">
|
||
<p class="desc">Должность и достижения. Например: «директор частной школы «Декарт», педагогический стаж 18 лет»</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Лицензия (для Schema.org hasCredential)</label>
|
||
<textarea name="branch_license" rows="2" style="width:100%;"><?php echo esc_textarea(get_option('branch_license', '')); ?></textarea>
|
||
<p class="desc">Текст про лицензию на образовательную деятельность. Выводится в микроразметке (hasCredential) и в блоке «Работаем официально».</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<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 class="branch-msg-row">
|
||
<span class="branch-msg-icon">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="#25D366"><path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 0 1-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 0 1-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 0 1 2.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0 0 12.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 0 0 5.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 0 0-3.48-8.413"/></svg>
|
||
</span>
|
||
<input type="url" name="branch_messenger_whatsapp" value="<?php echo esc_attr(get_option('branch_messenger_whatsapp', '')); ?>" placeholder="https://wa.me/79991234567" style="flex:1;min-width:180px;">
|
||
<label><input type="checkbox" name="branch_messenger_whatsapp_on" value="1" <?php checked(get_option('branch_messenger_whatsapp_on', 1), 1); ?>> Показывать</label>
|
||
</div>
|
||
|
||
<div class="branch-msg-row">
|
||
<span class="branch-msg-icon">
|
||
<svg width="18" height="18" viewBox="0 0 24 24" fill="#0088CC"><path d="M11.944 0A12 12 0 0 0 0 12a12 12 0 0 0 1.698 6.147L.02 24l6.469-1.796A12 12 0 0 0 12 24a12 12 0 0 0 12-12A12 12 0 0 0 12 0zm7.502 17.21a7.498 7.498 0 0 1-1.356.807 8.486 8.486 0 0 1-1.82.6 7.44 7.44 0 0 1-2.266.13c-2.09-.27-4.082-1.05-5.61-2.103a18.57 18.57 0 0 1-3.967-3.751A14.8 14.8 0 0 1 2.8 6.106a7.68 7.68 0 0 1 .93-2.905 5.26 5.26 0 0 1 1.08-1.426c.078-.08.157-.149.246-.215.113-.081.226-.161.343-.226.397-.214.838-.221 1.252-.101.21.06.415.139.607.23.285.137.568.278.84.435.09.05.173.115.252.176.326.252.52.572.656.946.08.22.132.448.155.68.053.539.05 1.078-.003 1.611a4.12 4.12 0 0 1-.246.873 5.38 5.38 0 0 1-.34.715c-.104.172-.226.333-.387.446a3.09 3.09 0 0 0-.418.377c-.137.17-.139.375-.028.549a13.482 13.482 0 0 0 1.474 2.005c.018.018.036.035.054.053a13.659 13.659 0 0 0 2.058 1.603c.214.133.398.08.55-.067a4.37 4.37 0 0 1 .902-.72c.397-.24.778-.186 1.125.12.334.294.661.596.983.903.204.195.404.394.589.607.031.036.053.078.077.112a1.81 1.81 0 0 1 .324.603c.062.184.09.375.062.565a2.63 2.63 0 0 1-.218.68 4.98 4.98 0 0 1-.346.639.977.977 0 0 1-.333.322c-.233.148-.479.266-.72.378a3.12 3.12 0 0 1-.525.208c-.214.065-.43.123-.649.163"/></svg>
|
||
</span>
|
||
<input type="url" name="branch_messenger_telegram" value="<?php echo esc_attr(get_option('branch_messenger_telegram', '')); ?>" placeholder="https://t.me/your_channel" style="flex:1;min-width:180px;">
|
||
<label><input type="checkbox" name="branch_messenger_telegram_on" value="1" <?php checked(get_option('branch_messenger_telegram_on', 1), 1); ?>> Показывать</label>
|
||
</div>
|
||
|
||
<div class="branch-msg-row">
|
||
<span class="branch-msg-icon">
|
||
<svg width="18" height="18" viewBox="0 0 32 32" fill="#7360F2"><path d="M16 2C8.268 2 2 8.268 2 16s6.268 14 14 14 14-6.268 14-14S23.732 2 16 2zm7.066 19.445a3.408 3.408 0 0 1-.65.746 4.19 4.19 0 0 1-.874.574 5.054 5.054 0 0 1-1.352.374 3.02 3.02 0 0 0-.472.058 2.986 2.986 0 0 1-.64-.03c-.138-.03-.268-.072-.398-.118-.154-.058-.304-.132-.45-.208-.282-.15-.54-.346-.778-.562a19.364 19.364 0 0 1-2.306-2.412 16.543 16.543 0 0 1-.906-1.188c-.06-.086-.12-.172-.178-.26a1.8 1.8 0 0 1-.146-.264c-.058-.122-.072-.256-.034-.38.036-.116.1-.222.166-.322a5.08 5.08 0 0 1 .332-.422c.084-.102.176-.2.252-.31.114-.164.218-.336.288-.52.05-.128.07-.264.04-.396a1.56 1.56 0 0 0-.102-.312c-.054-.124-.116-.246-.176-.368l-.384-.82c-.152-.326-.308-.652-.46-.978l-.466-1c-.124-.266-.252-.53-.38-.794-.12-.252-.246-.5-.37-.75-.106-.216-.216-.43-.326-.644-.166-.324-.34-.644-.51-.966-.068-.128-.134-.26-.202-.388-.078-.148-.144-.302-.21-.456-.108-.26-.168-.542-.182-.822-.014-.268.002-.542.058-.8.104-.47.3-.912.568-1.304.156-.226.33-.434.532-.614.07-.06.15-.112.228-.166.126-.09.264-.164.398-.232.218-.114.454-.188.694-.246a6.25 6.25 0 0 1 .88-.138c.306-.032.614-.036.92-.012.22.018.434.07.64.14.122.042.238.094.35.156l.19.112c.078.046.15.098.22.158.14.122.264.262.37.414.048.068.09.138.13.21l.062.112c.044.08.082.164.114.25.064.174.11.354.138.538.016.098.024.198.03.298.008.11.01.222.008.332v.158c0 .094-.004.188-.012.28-.008.09-.02.18-.036.268a3.46 3.46 0 0 1-.256.7 3.52 3.52 0 0 1-.242.458 1.86 1.86 0 0 1-.26.322c-.082.084-.17.16-.24.252-.11.146-.154.332-.12.514.022.11.07.214.12.316.058.116.12.23.186.342.254.43.536.844.842 1.24.214.278.442.544.686.79.114.116.234.226.356.334.068.06.14.118.212.174.14.108.3.182.47.216.176.036.36-.002.518-.094.134-.078.26-.168.382-.264.084-.066.164-.138.248-.202.058-.044.118-.086.176-.126.12-.082.246-.156.376-.22.114-.056.23-.106.35-.148a2.22 2.22 0 0 1 .578-.13c.17-.02.342-.006.504.056.164.06.312.152.44.27.128.114.23.25.312.4.046.082.082.168.112.256.034.096.06.196.078.296.022.114.032.23.032.346 0 .134-.008.274-.024.41a4.76 4.76 0 0 1-.228.864c-.104.308-.25.6-.43.874-.07.108-.146.212-.226.314z"/></svg>
|
||
</span>
|
||
<input type="url" name="branch_messenger_max" value="<?php echo esc_attr(get_option('branch_messenger_max', '')); ?>" placeholder="https://..." style="flex:1;min-width:180px;">
|
||
<label><input type="checkbox" name="branch_messenger_max_on" value="1" <?php checked(get_option('branch_messenger_max_on', 1), 1); ?>> Показывать</label>
|
||
</div>
|
||
|
||
<div id="branch-messengers-container">
|
||
<?php
|
||
$extra_msgs = get_option('branch_messenger_extra', array());
|
||
if (! empty($extra_msgs) && is_array($extra_msgs)) :
|
||
foreach ($extra_msgs as $i => $m) :
|
||
$m_name = $m['name'] ?? '';
|
||
$m_url = $m['url'] ?? '';
|
||
?>
|
||
<div class="branch-social-row">
|
||
<input type="text" name="branch_messenger_extra[<?php echo intval($i); ?>][name]" value="<?php echo esc_attr($m_name); ?>" placeholder="Название" style="max-width:160px;">
|
||
<input type="url" name="branch_messenger_extra[<?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>
|
||
<style>
|
||
.branch-msg-row {
|
||
display:flex; align-items:center; gap:8px; margin-bottom:6px; flex-wrap:wrap;
|
||
}
|
||
.branch-msg-icon {
|
||
display:inline-flex; width:32px; height:32px; align-items:center; justify-content:center; flex-shrink:0;
|
||
}
|
||
.branch-msg-icon svg { display:block; }
|
||
</style>
|
||
<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 extraContainer = document.getElementById('branch-messengers-container');
|
||
var extraAdd = document.getElementById('branch-messenger-add');
|
||
if (extraAdd) {
|
||
var idx = extraContainer.children.length;
|
||
extraAdd.addEventListener('click', function() {
|
||
var row = document.createElement('div');
|
||
row.className = 'branch-social-row';
|
||
row.innerHTML = '<input type="text" name="branch_messenger_extra[' + idx + '][name]" placeholder="Название" style="max-width:160px;">' +
|
||
'<input type="url" name="branch_messenger_extra[' + idx + '][url]" placeholder="https://..." style="max-width:300px;">' +
|
||
'<button type="button" class="button branch-messenger-remove">−</button>';
|
||
extraContainer.appendChild(row);
|
||
idx++;
|
||
row.querySelector('.branch-messenger-remove').addEventListener('click', function() { row.remove(); });
|
||
});
|
||
extraContainer.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>
|
||
<div class="branch-section-body">
|
||
<p class="desc">Единый каталог программ/направлений школы: <strong>название, цена, пояснение к цене, ссылка на страницу программы, теги каталога</strong>. Цены отсюда попадают в карточки преподавателей и в микроразметку Offer. Преподаватели <strong>выбирают</strong> программу из каталога (Настройки → преподаватель → «Предметы обучения») — свои теги направления у них задаются облаком тегов отдельно.</p>
|
||
<div id="branch-programs-repeater">
|
||
<?php
|
||
$programs = get_option('branch_programs', array());
|
||
if (! is_array($programs) || empty($programs)) {
|
||
$programs = array( array( 'name' => '', 'price' => '', 'price_note' => '', 'url' => '', 'tags' => '' ) );
|
||
}
|
||
foreach ($programs as $i => $p) {
|
||
echo '<div class="branch-program-row">'
|
||
. '<input type="text" name="branch_programs[' . $i . '][name]" value="' . esc_attr($p['name'] ?? '') . '" placeholder="Название (напр. Нейропсихолог)">'
|
||
. '<input type="text" name="branch_programs[' . $i . '][price]" value="' . esc_attr($p['price'] ?? '') . '" placeholder="Цена (напр. от 1 290 ₽)" style="max-width:170px;">'
|
||
. '<input type="text" name="branch_programs[' . $i . '][price_note]" value="' . esc_attr($p['price_note'] ?? '') . '" placeholder="Пояснение к цене" style="max-width:200px;">'
|
||
. '<input type="url" name="branch_programs[' . $i . '][url]" value="' . esc_attr($p['url'] ?? '') . '" placeholder="https://… (страница программы)" style="max-width:200px;">'
|
||
. '<input type="text" name="branch_programs[' . $i . '][tags]" value="' . esc_attr($p['tags'] ?? '') . '" placeholder="Теги каталога (слова через пробел)" style="max-width:240px;">'
|
||
. '<button type="button" class="button branch-program-remove">—</button>'
|
||
. '</div>';
|
||
}
|
||
?>
|
||
</div>
|
||
<button type="button" class="button" id="branch-programs-add">+ Добавить программу</button>
|
||
<style>
|
||
.branch-program-row {
|
||
display:flex; align-items:center; gap:8px; margin-bottom:6px; flex-wrap:wrap;
|
||
}
|
||
.branch-program-row input[type="text"],
|
||
.branch-program-row input[type="url"] {
|
||
min-width:160px;
|
||
}
|
||
</style>
|
||
<script>
|
||
(function() {
|
||
var container = document.getElementById('branch-programs-repeater');
|
||
var addBtn = document.getElementById('branch-programs-add');
|
||
if (! addBtn) { return; }
|
||
addBtn.addEventListener('click', function() {
|
||
var idx = container.children.length;
|
||
var row = document.createElement('div');
|
||
row.className = 'branch-program-row';
|
||
row.innerHTML = '<input type="text" name="branch_programs[' + idx + '][name]" placeholder="Название (напр. Нейропсихолог)">'
|
||
+ '<input type="text" name="branch_programs[' + idx + '][price]" placeholder="Цена (напр. от 1 290 ₽)" style="max-width:170px;">'
|
||
+ '<input type="text" name="branch_programs[' + idx + '][price_note]" placeholder="Пояснение к цене" style="max-width:200px;">'
|
||
+ '<input type="url" name="branch_programs[' + idx + '][url]" placeholder="https://…" style="max-width:200px;">'
|
||
+ '<input type="text" name="branch_programs[' + idx + '][tags]" placeholder="Теги каталога" style="max-width:240px;">'
|
||
+ '<button type="button" class="button branch-program-remove">—</button>';
|
||
container.appendChild(row);
|
||
});
|
||
container.addEventListener('click', function(e) {
|
||
if (e.target.classList.contains('branch-program-remove')) {
|
||
e.target.parentElement.remove();
|
||
}
|
||
});
|
||
})();
|
||
</script>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="branch-section collapsed">
|
||
<h2>🏢 ОРГАНИЗАЦИЯ</h2>
|
||
<div class="branch-section-body">
|
||
<div class="branch-field">
|
||
<label>Полное название организации</label>
|
||
<input type="text" name="branch_name" value="<?php echo esc_attr(get_option('branch_name', 'Декарт')); ?>">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>OG: Site Name (для мета-тега og:site_name)</label>
|
||
<input type="text" name="branch_og_site_name" value="<?php echo esc_attr(get_option('branch_og_site_name', 'Частная школа Декарт в Щёлково')); ?>" style="width:100%;max-width:500px">
|
||
<p class="desc">Значение тега <code>og:site_name</code> — отображается в сниппетах Яндекса и Google. Рекомендуется: «Частная школа Декарт в Щёлково». Если оставить пустым — будет использован заголовок сайта из настроек WordPress.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Ценовой диапазон</label>
|
||
<input type="text" name="branch_price_range" value="<?php echo esc_attr(get_option('branch_price_range', '$$')); ?>">
|
||
<p class="desc">Для микроразметки. Например: "$", "$$", "$$$".</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Цена занятия (для страниц преподавателей)</label>
|
||
<input type="text" name="branch_price" value="<?php echo esc_attr(get_option('branch_price', '')); ?>" style="width:100%;max-width:220px">
|
||
<p class="desc">Стоимость занятия в мини-группе. Пример: «от 1 290 ₽». Выводится в блоке стоимости на странице преподавателя и в микроразметке Offer (price).<br><strong>Пусто</strong> — на странице преподавателя покажется «Стоимость — по запросу», в микроразметке price не выводится.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Пояснение к цене</label>
|
||
<input type="text" name="branch_price_note" value="<?php echo esc_attr(get_option('branch_price_note', 'за занятие 60 минут в мини-группе')); ?>" style="width:100%;max-width:420px">
|
||
<p class="desc">Подпись под ценой. Пример: «за занятие 60 минут в мини-группе». Пусто — подпись скрыта.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Средний рейтинг школы (для метрик)</label>
|
||
<input type="text" name="branch_avg_rating" value="<?php echo esc_attr(get_option('branch_avg_rating', '4.9')); ?>" style="width:100%;max-width:120px">
|
||
<p class="desc">Отображается в блоке метрик на странице отзывов. Пример: 4.9</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Оставшиеся места (для триггера срочности)</label>
|
||
<input type="number" name="branch_remaining_seats" value="<?php echo esc_attr(get_option('branch_remaining_seats', '12')); ?>" style="width:100%;max-width:120px" min="0">
|
||
<p class="desc">Отображается в финальном CTA на странице отзывов: «осталось N мест».</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Логотип организации (ID вложения)</label>
|
||
<input type="number" name="branch_logo" value="<?php echo esc_attr(get_option('branch_logo', '')); ?>" min="0" style="max-width:120px">
|
||
<p class="desc">ID изображения из Медиафайлы. Для JSON-LD image.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Описание организации (для Schema.org)</label>
|
||
<textarea name="branch_schema_description" rows="3" style="width:100%;max-width:500px"><?php echo esc_textarea(get_option('branch_schema_description', '')); ?></textarea>
|
||
<p class="desc">Появляется в сниппете Google и Яндекса как описание организации. Рекомендуется 1–2 предложения: тип школы, какие классы, особенности. Пример: «Частная школа в Щёлково с углублённым английским. Обучение с 1 по 11 класс, подготовка к ЕГЭ и ОГЭ, продлёнка, индивидуальный подход.» Если пусто — собирается автоматически из названия и города филиала.</p>
|
||
</div>
|
||
|
||
</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 class="branch-field">
|
||
<label>Скрипт (JS/HTML) — для лагеря</label>
|
||
<textarea name="branch_camp_script" rows="6" style="width:100%;max-width:700px;font-family:monospace;font-size:13px"><?php echo esc_textarea(get_option('branch_camp_script', '')); ?></textarea>
|
||
<p class="desc">Скрипт для кнопок на странице <strong>/gorodskoj-lager/</strong>. Если не заполнен — используется общий скрипт выше.</p>
|
||
</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>Google Business Profile (ссылка на профиль)</label>
|
||
<input type="url" name="branch_google_business_url" value="<?php echo esc_attr(get_option('branch_google_business_url', '')); ?>" style="width:100%;max-width:500px">
|
||
<p class="desc">Полная ссылка на профиль в Google Business Profile. Добавляется в sameAs[] Schema.org и выводится как кнопка на странице. <br><strong>Где взять:</strong> откройте Google Карты → найдите свою организацию → нажмите «Поделиться» → скопируйте ссылку. Пример: https://maps.google.com/?cid=1234567890 или https://g.page/r/your-business-slug</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Яндекс Бизнес / Карты (профиль организации)</label>
|
||
<input type="url" name="branch_yandex_business_url" value="<?php echo esc_attr(get_option('branch_yandex_business_url', '')); ?>" style="width:100%;max-width:500px">
|
||
<p class="desc">Ссылка на профиль организации в Яндекс Бизнес / Яндекс Картах. Добавляется в sameAs[] Schema.org. <br><strong>Где взять:</strong> откройте Яндекс Карты → найдите организацию → скопируйте URL из адресной строки. Пример: https://yandex.ru/maps/org/.../</p>
|
||
</div>
|
||
<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 class="branch-field">
|
||
<label>Количество отзывов на внешних площадках</label>
|
||
<input type="number" name="branch_ext_review_count" value="<?php echo esc_attr(get_option('branch_ext_review_count', '247')); ?>" style="width:100%;max-width:200px" min="0">
|
||
<p class="desc">Отображается в бейдже под метриками: «4.9 из 5 на основе N отзывов на внешних площадках».</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Рейтинг на Яндекс.Картах</label>
|
||
<input type="text" name="branch_rating_yandex" value="<?php echo esc_attr(get_option('branch_rating_yandex', '5.0')); ?>" style="width:100%;max-width:80px" placeholder="4.8">
|
||
<p class="desc">Отображается в блоке «Нас рекомендуют» на странице /podgotovka-k-shkole/. Пример: 5.0</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Рейтинг на 2ГИС</label>
|
||
<input type="text" name="branch_rating_2gis" value="<?php echo esc_attr(get_option('branch_rating_2gis', '4.7')); ?>" style="width:100%;max-width:80px" placeholder="4.7">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Рейтинг ВКонтакте</label>
|
||
<input type="text" name="branch_rating_vk" value="<?php echo esc_attr(get_option('branch_rating_vk', '4.9')); ?>" style="width:100%;max-width:80px" placeholder="4.9">
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Рейтинг на Otzovik</label>
|
||
<input type="text" name="branch_rating_otzovik" value="<?php echo esc_attr(get_option('branch_rating_otzovik', '4.6')); ?>" style="width:100%;max-width:80px" placeholder="4.6">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="branch-section collapsed">
|
||
<h2>📊 СЧЕТЧИКИ</h2>
|
||
<div class="branch-section-body">
|
||
<div class="branch-field">
|
||
<label>Яндекс.Метрика (head)</label>
|
||
<textarea name="dekart_counter_yandex" rows="8" style="width:100%;max-width:700px;font-family:monospace;font-size:13px"><?php echo esc_textarea(get_option('dekart_counter_yandex', '')); ?></textarea>
|
||
<p class="desc">Код счётчика. Выводится в <code><head></code>.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Google Tag Manager (head)</label>
|
||
<textarea name="dekart_counter_gtm_head" rows="8" style="width:100%;max-width:700px;font-family:monospace;font-size:13px"><?php echo esc_textarea(get_option('dekart_counter_gtm_head', '')); ?></textarea>
|
||
<p class="desc">Основной код GTM. Выводится в <code><head></code>.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Google Tag Manager (body / noscript)</label>
|
||
<textarea name="dekart_counter_gtm_body" rows="5" style="width:100%;max-width:700px;font-family:monospace;font-size:13px"><?php echo esc_textarea(get_option('dekart_counter_gtm_body', '')); ?></textarea>
|
||
<p class="desc">Код <code><noscript></code>. Выводится сразу после открытия <code><body></code> через хук <code>wp_body_open</code>.</p>
|
||
</div>
|
||
<div class="branch-field">
|
||
<label>Произвольные скрипты (footer)</label>
|
||
<textarea name="dekart_counter_footer" rows="8" style="width:100%;max-width:700px;font-family:monospace;font-size:13px"><?php echo esc_textarea(get_option('dekart_counter_footer', '')); ?></textarea>
|
||
<p class="desc">Для чатов, пикселей и прочих скриптов. Выводится в <code><footer></code>.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Сворачивание/разворачивание блоков
|
||
document.querySelectorAll('.branch-section > h2').forEach(function(h2){
|
||
h2.addEventListener('click', function(){
|
||
this.parentElement.classList.toggle('collapsed');
|
||
});
|
||
});
|
||
// Соцсети и мессенджеры: их JS инициализируется внутри секции «СОЦСЕТИ И МЕССЕНДЖЕРЫ»
|
||
</script>
|
||
|
||
<?php submit_button('Сохранить настройки филиала'); ?>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
/**
|
||
* Страница: Сброс кеша (подменю Настройки филиала)
|
||
*/
|
||
function dekart_flush_cache_page()
|
||
{
|
||
?>
|
||
<div class="wrap">
|
||
<h1>🗄️ Сброс кеша</h1>
|
||
<p class="desc" style="margin:16px 0;color:#646970;font-size:13px">Полная диагностика и очистка: проверка файлов, установка drop-in, сброс кеша и транзиентов.</p>
|
||
<button type="button" id="dekart-flush-cache-btn" class="button button-hero button-secondary" style="display:inline-flex;align-items:center;gap:8px">
|
||
<span class="dashicons dashicons-update" style="font-size:20px;width:20px;height:20px"></span> Выполнить проверку и сброс
|
||
</button>
|
||
<div id="dekart-flush-cache-log" style="margin-top:20px;max-width:700px;display:none"></div>
|
||
|
||
<script>
|
||
(function() {
|
||
var btn = document.getElementById('dekart-flush-cache-btn');
|
||
var log = document.getElementById('dekart-flush-cache-log');
|
||
if (!btn) return;
|
||
|
||
function addLog(type, text) {
|
||
var icons = { ok: '✅', fail: '❌', warn: '⚠️', info: 'ℹ️', doing: '🔄' };
|
||
var colors = { ok: '#00a32a', fail: '#d63638', warn: '#dba617', info: '#2271b1', doing: '#646970' };
|
||
var line = document.createElement('div');
|
||
line.style.cssText = 'padding:6px 10px;margin:2px 0;border-radius:4px;background:#f6f7f7;font-size:13px;line-height:1.5';
|
||
line.innerHTML = (icons[type] || '') + ' <span style="color:' + (colors[type] || '#333') + '">' + text + '</span>';
|
||
log.appendChild(line);
|
||
}
|
||
|
||
btn.addEventListener('click', function() {
|
||
if (btn.disabled) return;
|
||
btn.disabled = true;
|
||
btn.innerHTML = '<span style="display:inline-block;animation:spin 1s linear infinite">↻</span> Выполнение...';
|
||
log.style.display = 'block';
|
||
log.innerHTML = '';
|
||
addLog('doing', 'Запуск диагностики...');
|
||
|
||
var data = new FormData();
|
||
data.set('action', 'dekart_flush_cache');
|
||
data.set('nonce', '<?php echo wp_create_nonce('dekart_flush_cache_nonce'); ?>');
|
||
|
||
fetch(ajaxurl, { method: 'POST', body: data })
|
||
.then(function(r) { return r.json(); })
|
||
.then(function(j) {
|
||
log.innerHTML = '';
|
||
if (j.success && j.data && j.data.log) {
|
||
j.data.log.forEach(function(item) {
|
||
addLog(item.type, item.text);
|
||
});
|
||
if (j.data.summary) {
|
||
var s = document.createElement('div');
|
||
s.style.cssText = 'margin-top:12px;padding:10px 14px;border-radius:6px;font-weight:600;font-size:14px;background:' + (j.data.summary.type === 'ok' ? '#edfaef' : '#fcf0f1') + ';color:' + (j.data.summary.type === 'ok' ? '#00a32a' : '#d63638');
|
||
s.innerHTML = (j.data.summary.type === 'ok' ? '✅' : '❌') + ' ' + j.data.summary.text;
|
||
log.appendChild(s);
|
||
}
|
||
} else {
|
||
addLog('fail', j.data && j.data.message ? j.data.message : 'Неизвестная ошибка');
|
||
}
|
||
})
|
||
.catch(function() {
|
||
log.innerHTML = '';
|
||
addLog('fail', 'Ошибка соединения с сервером');
|
||
})
|
||
.finally(function() {
|
||
btn.disabled = false;
|
||
btn.innerHTML = '<span class="dashicons dashicons-update" style="font-size:20px;width:20px;height:20px"></span> Выполнить проверку и сброс';
|
||
});
|
||
});
|
||
})();
|
||
</script>
|
||
|
||
<style>
|
||
@keyframes spin { to { transform: rotate(360deg); } }
|
||
</style>
|
||
</div>
|
||
<?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 — добавляем поля
|
||
* "выпускники", "лет опыта", "рейтинг"
|
||
* (настройки темы уже есть — используем статические)
|
||
*/
|
||
|
||
|
||
|
||
// ─────────────────────────────────────────────────────────────
|
||
// Helper: список преподавателей для select поля
|
||
// ─────────────────────────────────────────────────────────────
|
||
function dekart_get_teacher_options()
|
||
{
|
||
$options = array();
|
||
$teachers = get_posts(array(
|
||
'post_type' => 'teacher',
|
||
'posts_per_page' => -1,
|
||
'post_status' => 'publish',
|
||
'orderby' => 'title',
|
||
'order' => 'ASC',
|
||
));
|
||
foreach ($teachers as $t) {
|
||
$options[ $t->ID ] = esc_html($t->post_title);
|
||
}
|
||
return $options;
|
||
}
|
||
|
||
// ─────────────────────────────────────────────────────────────
|
||
// ACF: Отзывы (Лагерь) — группа полей
|
||
// ─────────────────────────────────────────────────────────────
|
||
|
||
// ─────────────────────────────────────────────────────────────
|
||
// 🗄️ AJAX: Сброс кеша (кнопка в Настройки филиала)
|
||
// ─────────────────────────────────────────────────────────────
|
||
add_action('wp_ajax_dekart_flush_cache', 'dekart_ajax_flush_cache');
|
||
function dekart_ajax_flush_cache()
|
||
{
|
||
check_ajax_referer('dekart_flush_cache_nonce', 'nonce');
|
||
|
||
if (! current_user_can('manage_options')) {
|
||
wp_send_json_error(array( 'message' => 'Нет прав' ));
|
||
}
|
||
|
||
$log = array();
|
||
$errors = 0;
|
||
$abspath = defined('ABSPATH') ? ABSPATH : dirname(__DIR__, 4) . '/';
|
||
|
||
// ── 1. Проверка файлов ──
|
||
$files = array(
|
||
'MU-плагин (object-cache-bootstrap)' => WP_CONTENT_DIR . '/mu-plugins/object-cache-bootstrap.php',
|
||
'Плагин Memcached (object-cache.php)' => WP_CONTENT_DIR . '/plugins/memcached/object-cache.php',
|
||
'Тема (functions.php)' => get_template_directory() . '/functions.php',
|
||
'wp-config.php' => $abspath . 'wp-config.php',
|
||
);
|
||
$log[] = array( 'type' => 'info', 'text' => '🔍 Проверка файлов системы:' );
|
||
foreach ($files as $label => $path) {
|
||
if (file_exists($path)) {
|
||
$size = size_format(filesize($path));
|
||
$log[] = array( 'type' => 'ok', 'text' => "{$label} — найден ({$size})" );
|
||
} else {
|
||
$log[] = array( 'type' => 'warn', 'text' => "{$label} — отсутствует" );
|
||
}
|
||
}
|
||
|
||
// ── 2. PHP extension Memcache ──
|
||
$log[] = array( 'type' => 'info', 'text' => '🔍 Проверка PHP-расширения:' );
|
||
if (class_exists('Memcache') || class_exists('Memcached')) {
|
||
$ext = class_exists('Memcached') ? 'memcached' : 'memcache';
|
||
$log[] = array( 'type' => 'ok', 'text' => "PHP-расширение {$ext} — установлено" );
|
||
} else {
|
||
$log[] = array( 'type' => 'warn', 'text' => 'PHP-расширение memcache/memcached — не найдено (обратитесь в хостинг)' );
|
||
}
|
||
|
||
// ── 3. Memcached drop-in ──
|
||
$source = WP_CONTENT_DIR . '/plugins/memcached/object-cache.php';
|
||
$target = WP_CONTENT_DIR . '/object-cache.php';
|
||
|
||
$log[] = array( 'type' => 'info', 'text' => '🔍 Проверка drop-in Memcached:' );
|
||
if (file_exists($target)) {
|
||
$size = size_format(filesize($target));
|
||
$log[] = array( 'type' => 'ok', 'text' => "Drop-in уже установлен: wp-content/object-cache.php ({$size})" );
|
||
} else {
|
||
if (file_exists($source)) {
|
||
$copied = copy($source, $target);
|
||
if ($copied) {
|
||
$size = size_format(filesize($target));
|
||
$log[] = array( 'type' => 'ok', 'text' => "Drop-in скопирован: plugins/memcached/object-cache.php → wp-content/object-cache.php ({$size})" );
|
||
} else {
|
||
$log[] = array( 'type' => 'fail', 'text' => 'Ошибка копирования! Проверьте права на wp-content/' );
|
||
$errors++;
|
||
}
|
||
} else {
|
||
$log[] = array( 'type' => 'warn', 'text' => 'Плагин Memcached не установлен. Установите: wp plugin install memcached' );
|
||
}
|
||
}
|
||
|
||
// ── 4. Проверка WP_CACHE_KEY_SALT ──
|
||
$log[] = array( 'type' => 'info', 'text' => '🔍 Проверка изоляции ключей кеша:' );
|
||
if (defined('WP_CACHE_KEY_SALT') && WP_CACHE_KEY_SALT !== '') {
|
||
$log[] = array( 'type' => 'ok', 'text' => 'WP_CACHE_KEY_SALT = ' . WP_CACHE_KEY_SALT . ' (изоляция активна)' );
|
||
} else {
|
||
$log[] = array( 'type' => 'fail', 'text' => 'WP_CACHE_KEY_SALT не задан! Добавьте в wp-config.php: define( "WP_CACHE_KEY_SALT", DB_NAME );' );
|
||
$errors++;
|
||
}
|
||
|
||
// ── 5. Versioned cache bump (MU-плагин) ──
|
||
$log[] = array( 'type' => 'info', 'text' => '🔍 Инвалидация versioned cache:' );
|
||
if (function_exists('my_cache_bump_version')) {
|
||
my_cache_bump_version();
|
||
$log[] = array( 'type' => 'ok', 'text' => 'Версия кеша обновлена (my_cache_bump_version)' );
|
||
} else {
|
||
$log[] = array( 'type' => 'warn', 'text' => 'my_cache_bump_version() не найдена — MU-плагин не активен' );
|
||
}
|
||
|
||
// ── 6. WP object cache flush ──
|
||
$log[] = array( 'type' => 'info', 'text' => '🔍 Очистка объектного кеша:' );
|
||
if (function_exists('wp_cache_flush')) {
|
||
wp_cache_flush();
|
||
$log[] = array( 'type' => 'ok', 'text' => 'wp_cache_flush() — выполнен (ключи ротированы)' );
|
||
} else {
|
||
$log[] = array( 'type' => 'warn', 'text' => 'wp_cache_flush() — функция не найдена (drop-in не установлен)' );
|
||
}
|
||
|
||
// ── 7. Transients ──
|
||
$log[] = array( 'type' => 'info', 'text' => '🔍 Очистка транзиентов:' );
|
||
global $wpdb;
|
||
$deleted = $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_%' OR option_name LIKE '_transient_timeout_%'");
|
||
$log[] = array( 'type' => 'ok', 'text' => "Удалено {$deleted} записей _transient_* из wp_options" );
|
||
|
||
// ── Итог ──
|
||
if ($errors === 0) {
|
||
$summary = array( 'type' => 'ok', 'text' => 'Всё выполнено успешно. Ошибок нет.' );
|
||
} else {
|
||
$summary = array( 'type' => 'fail', 'text' => "Выполнено с {$errors} ошибкой(ами). Проверьте лог выше." );
|
||
}
|
||
|
||
wp_send_json_success(array(
|
||
'log' => $log,
|
||
'summary' => $summary,
|
||
));
|
||
}
|
||
|
||
/**
|
||
* program-pksh: разрешаем индексацию — страница содержит
|
||
* официальную образовательную программу со ссылками на ФЗ №273, ФГОС ДО.
|
||
* Это сильный E-E-A-T сигнал + точка входа по запросам "программа подготовка к школе фгос".
|
||
* noindex был ошибочным — он убивал E-E-A-T и терял трафик по длинным образовательным запросам.
|
||
*/
|
||
|
||
|
||
|
||
// ════════════════════════════════════════════
|
||
// Админ: вертикальные стабильные вкладки CF для преподавателя
|
||
// (нативный layout 'tabbed-vertical' + страховка от «списка вместо вкладок»)
|
||
// ════════════════════════════════════════════
|
||
function dekart_admin_teacher_tab_assets($hook)
|
||
{
|
||
if (! in_array($hook, array( 'post.php', 'post-new.php' ), true)) {
|
||
return;
|
||
}
|
||
$screen = get_current_screen();
|
||
if (! $screen || 'teacher' !== (string) $screen->post_type) {
|
||
return;
|
||
}
|
||
|
||
wp_enqueue_style(
|
||
'dekart-admin-teacher-tabs',
|
||
get_template_directory_uri() . '/assets/css/admin-teacher-tabs.css',
|
||
array( 'carbon-fields-core' ),
|
||
filemtime(get_template_directory() . '/assets/css/admin-teacher-tabs.css')
|
||
);
|
||
|
||
wp_enqueue_script(
|
||
'dekart-admin-teacher-tabs',
|
||
get_template_directory_uri() . '/assets/js/admin-teacher-tabs.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/admin-teacher-tabs.js'),
|
||
true
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Санитайзер каталога программ филиала (branch_programs).
|
||
* Каждая запись: name, price, price_note, url, tags.
|
||
*/
|
||
function dekart_sanitize_branch_programs($value)
|
||
{
|
||
if (! is_array($value)) {
|
||
return array();
|
||
}
|
||
$out = array();
|
||
foreach ($value as $item) {
|
||
if (! is_array($item)) {
|
||
continue;
|
||
}
|
||
$name = trim(sanitize_text_field((string) ( $item['name'] ?? '' )));
|
||
if ('' === $name) {
|
||
continue; // пустая строка — пропускаем
|
||
}
|
||
$out[] = array(
|
||
'name' => $name,
|
||
'price' => trim(sanitize_text_field((string) ( $item['price'] ?? '' ))),
|
||
'price_note' => trim(sanitize_text_field((string) ( $item['price_note'] ?? '' ))),
|
||
'url' => esc_url_raw(trim((string) ( $item['url'] ?? '' ))),
|
||
'tags' => trim(sanitize_text_field((string) ( $item['tags'] ?? '' ))),
|
||
);
|
||
}
|
||
return $out;
|
||
}
|
||
add_action('admin_enqueue_scripts', 'dekart_admin_teacher_tab_assets');
|
||
|
||
// ─────────────────────────────────────────────
|
||
// Админ: Настройки филиала — вертикальные вкладки
|
||
// ─────────────────────────────────────────────
|
||
function dekart_admin_branch_tab_assets($hook)
|
||
{
|
||
if (! isset($_GET['page']) || $_GET['page'] !== 'branch-settings') { // phpcs:ignore WordPress.Security.NonceVerification
|
||
return;
|
||
}
|
||
|
||
wp_enqueue_style(
|
||
'dekart-admin-branch-tabs',
|
||
get_template_directory_uri() . '/assets/css/admin-branch-tabs.css',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/css/admin-branch-tabs.css')
|
||
);
|
||
|
||
wp_enqueue_script(
|
||
'dekart-admin-branch-tabs',
|
||
get_template_directory_uri() . '/assets/js/admin-branch-tabs.js',
|
||
array(),
|
||
filemtime(get_template_directory() . '/assets/js/admin-branch-tabs.js'),
|
||
true
|
||
);
|
||
}
|
||
add_action('admin_enqueue_scripts', 'dekart_admin_branch_tab_assets');
|