Compare commits
No commits in common. "d0492112e8e325ff9b53d34f39d505d40d508ffb" and "15ac1f81aa104934f3d74149cca93c0cec295113" have entirely different histories.
d0492112e8
...
15ac1f81aa
@ -643,14 +643,6 @@ function add_carbon() {
|
|||||||
Field::make( 'textarea', 'teacher_about', 'О педагоге (на этой странице)' )
|
Field::make( 'textarea', 'teacher_about', 'О педагоге (на этой странице)' )
|
||||||
->set_width( 100 )
|
->set_width( 100 )
|
||||||
->set_help_text( 'Краткое описание для этой страницы. Если оставить пустым — используется значение из карточки преподавателя.' ),
|
->set_help_text( 'Краткое описание для этой страницы. Если оставить пустым — используется значение из карточки преподавателя.' ),
|
||||||
Field::make( 'text', 'teacher_badge', 'Бейдж (на этой странице)' )
|
|
||||||
->set_width( 50 )
|
|
||||||
->set_default_value( '👶 Работает с дошкольниками' )
|
|
||||||
->set_help_text( 'Если оставить пустым — скрывается.' ),
|
|
||||||
Field::make( 'text', 'teacher_exp', 'Опыт (на этой странице)' )
|
|
||||||
->set_width( 50 )
|
|
||||||
->set_default_value( '39 лет' )
|
|
||||||
->set_help_text( 'Только число: «39» или строка: «39 лет». На странице выведется как 📅 Стаж: X. Если пусто — рассчитывается из карточки преподавателя.' ),
|
|
||||||
)),
|
)),
|
||||||
))
|
))
|
||||||
// ====================================================
|
// ====================================================
|
||||||
@ -676,10 +668,6 @@ function add_carbon() {
|
|||||||
Field::make( 'text', 'pksh_prog_base_price_single', 'Стоимость разового занятия' )
|
Field::make( 'text', 'pksh_prog_base_price_single', 'Стоимость разового занятия' )
|
||||||
->set_width( 50 )
|
->set_width( 50 )
|
||||||
->set_default_value( '1 000 ₽' ),
|
->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', 'Срочность (мест в группе)' )
|
Field::make( 'text', 'pksh_prog_base_urgency', 'Срочность (мест в группе)' )
|
||||||
->set_width( 100 )
|
->set_width( 100 )
|
||||||
->set_default_value( 'Осталось 2 места в группе' ),
|
->set_default_value( 'Осталось 2 места в группе' ),
|
||||||
@ -700,10 +688,6 @@ function add_carbon() {
|
|||||||
Field::make( 'text', 'pksh_prog_prem_price_single', 'Стоимость разового занятия' )
|
Field::make( 'text', 'pksh_prog_prem_price_single', 'Стоимость разового занятия' )
|
||||||
->set_width( 50 )
|
->set_width( 50 )
|
||||||
->set_default_value( '1 500 ₽' ),
|
->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', 'Срочность (мест в группе)' )
|
Field::make( 'text', 'pksh_prog_prem_urgency', 'Срочность (мест в группе)' )
|
||||||
->set_width( 100 )
|
->set_width( 100 )
|
||||||
->set_default_value( 'Осталось 3 места в группе' ),
|
->set_default_value( 'Осталось 3 места в группе' ),
|
||||||
|
|||||||
@ -320,38 +320,36 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Данные базовой программы
|
* Данные базовой программы
|
||||||
* @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, price_razov: string, urgency: string}
|
* @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, urgency: string}
|
||||||
*/
|
*/
|
||||||
public function get_base_program(): array {
|
public function get_base_program(): array {
|
||||||
if ( ! array_key_exists( 'base', $this->programs ) ) {
|
if ( ! array_key_exists( 'base', $this->programs ) ) {
|
||||||
$this->programs['base'] = array(
|
$this->programs['base'] = array(
|
||||||
'name' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_name' ) ?: 'Уверенный старт',
|
'name' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_name' ) ?: 'Уверенный старт',
|
||||||
'subname' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_subname' ) ?: '2 раза в неделю — комфортный темп без перегрузки',
|
'subname' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_subname' ) ?: '2 раза в неделю — комфортный темп без перегрузки',
|
||||||
'schedule' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_schedule' ) ?: 'вт, чт — 18:00–19:30',
|
'schedule' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_schedule' ) ?: 'вт, чт — 18:00–19:30',
|
||||||
'price_sub' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_price_sub' ) ?: '7 500 ₽',
|
'price_sub' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_price_sub' ) ?: '7 500 ₽',
|
||||||
'price_single' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_price_single' ) ?: '1 000 ₽',
|
'price_single' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_price_single' ) ?: '1 000 ₽',
|
||||||
'price_razov' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_price_razov' ) ?: '',
|
'urgency' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_urgency' ) ?: 'Осталось 2 места в группе',
|
||||||
'urgency' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_urgency' ) ?: 'Осталось 2 места в группе',
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return $this->programs['base'];
|
return $this->programs['base'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Данные премиум-программы
|
* Данные премиум-программы
|
||||||
* @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, price_razov: string, urgency: string}
|
* @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, urgency: string}
|
||||||
*/
|
*/
|
||||||
public function get_premium_program(): array {
|
public function get_premium_program(): array {
|
||||||
if ( ! array_key_exists( 'prem', $this->programs ) ) {
|
if ( ! array_key_exists( 'prem', $this->programs ) ) {
|
||||||
$this->programs['prem'] = array(
|
$this->programs['prem'] = array(
|
||||||
'name' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_name' ) ?: 'Результат за 3 месяца',
|
'name' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_name' ) ?: 'Результат за 3 месяца',
|
||||||
'subname' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_subname' ) ?: '3 раза в неделю — быстрый прогресс',
|
'subname' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_subname' ) ?: '3 раза в неделю — быстрый прогресс',
|
||||||
'schedule' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_schedule' ) ?: 'пн, ср, пт — 16:30–18:00',
|
'schedule' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_schedule' ) ?: 'пн, ср, пт — 16:30–18:00',
|
||||||
'price_sub' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_price_sub' ) ?: '10 500 ₽',
|
'price_sub' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_price_sub' ) ?: '10 500 ₽',
|
||||||
'price_single' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_price_single' ) ?: '1 500 ₽',
|
'price_single' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_price_single' ) ?: '1 500 ₽',
|
||||||
'price_razov' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_price_razov' ) ?: '',
|
'urgency' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_urgency' ) ?: 'Осталось 3 места в группе',
|
||||||
'urgency' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_urgency' ) ?: 'Осталось 3 места в группе',
|
);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return $this->programs['prem'];
|
return $this->programs['prem'];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -155,7 +155,13 @@ function dekart_schema_output(): void {
|
|||||||
$graph[] = $faq;
|
$graph[] = $faq;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 11b. Event — бесплатное пробное занятие
|
// 11b. QAPage — ключевые вопросы для AI citation readiness
|
||||||
|
$qa = dekart_schema_qapage();
|
||||||
|
if ( $qa ) {
|
||||||
|
$graph[] = $qa;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 11c. Event — бесплатное пробное занятие
|
||||||
$event = dekart_schema_trial_event();
|
$event = dekart_schema_trial_event();
|
||||||
if ( $event ) {
|
if ( $event ) {
|
||||||
$graph[] = $event;
|
$graph[] = $event;
|
||||||
@ -1409,6 +1415,57 @@ function dekart_schema_trial_event(): ?array {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QAPage — ключевые вопросы для AI citation readiness.
|
||||||
|
* Google retired FAQ rich results May 2026, но QAPage важен для AI Overviews/ChatGPT/Perplexity.
|
||||||
|
*
|
||||||
|
* @see https://schema.org/QAPage
|
||||||
|
*/
|
||||||
|
function dekart_schema_qapage(): ?array {
|
||||||
|
if ( ! is_page( 2 ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$page_url = dekart_schema_page_url();
|
||||||
|
$faq_items = carbon_get_post_meta( get_the_ID(), 'pksh_faq_items' );
|
||||||
|
|
||||||
|
if ( empty( $faq_items ) || ! is_array( $faq_items ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Берём только 3-5 ключевых вопросов (самые частые)
|
||||||
|
$key_questions = array_slice( $faq_items, 0, 5 );
|
||||||
|
|
||||||
|
$main_entity = array();
|
||||||
|
foreach ( $key_questions as $item ) {
|
||||||
|
$question = isset( $item['faq_question'] ) ? trim( $item['faq_question'] ) : '';
|
||||||
|
$answer = isset( $item['faq_answer'] ) ? trim( $item['faq_answer'] ) : '';
|
||||||
|
|
||||||
|
if ( empty( $question ) || empty( $answer ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$main_entity[] = array(
|
||||||
|
'@type' => 'Question',
|
||||||
|
'name' => wp_strip_all_tags( $question ),
|
||||||
|
'acceptedAnswer' => array(
|
||||||
|
'@type' => 'Answer',
|
||||||
|
'text' => wp_strip_all_tags( $answer ),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( empty( $main_entity ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'@type' => 'QAPage',
|
||||||
|
'@id' => $page_url . '#qapage',
|
||||||
|
'mainEntity' => $main_entity,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Offer / AggregateOffer с UnitPriceSpecification.
|
* Offer / AggregateOffer с UnitPriceSpecification.
|
||||||
* Добавляет priceSpecification с unitCode: 'MON' для цен за месяц.
|
* Добавляет priceSpecification с unitCode: 'MON' для цен за месяц.
|
||||||
|
|||||||
@ -1,16 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
/**
|
||||||
* Template Name: Подготовка к школе (Bento 2026)
|
* Template Name: Подготовка к школе (Bento 2026)
|
||||||
|
*
|
||||||
|
* Полный рефакторинг: логика вынесена в Pksh_Data (inc/class-pksh-data.php),
|
||||||
|
* секции — в template-parts/pksh/*.php.
|
||||||
|
*
|
||||||
|
* @package Dekart
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Автозагрузка Pksh_Data (синглтон, кэширует все get_option / carbon_get_post_meta)
|
||||||
if ( ! class_exists( 'Pksh_Data' ) ) {
|
if ( ! class_exists( 'Pksh_Data' ) ) {
|
||||||
require_once get_template_directory() . '/inc/class-pksh-data.php';
|
require_once get_template_directory() . '/inc/class-pksh-data.php';
|
||||||
}
|
}
|
||||||
|
// Инициализируем один раз при загрузке шаблона
|
||||||
$data = Pksh_Data::instance();
|
$data = Pksh_Data::instance();
|
||||||
|
|
||||||
get_header();
|
get_header();
|
||||||
@ -32,7 +38,7 @@ get_header();
|
|||||||
get_template_part( 'template-parts/pksh/compare' );
|
get_template_part( 'template-parts/pksh/compare' );
|
||||||
get_template_part( 'template-parts/pksh/programs' );
|
get_template_part( 'template-parts/pksh/programs' );
|
||||||
|
|
||||||
|
// Shared template-part (легаси, не вынесен в pksh/)
|
||||||
get_template_part( 'template-parts/block-price' );
|
get_template_part( 'template-parts/block-price' );
|
||||||
|
|
||||||
get_template_part( 'template-parts/pksh/teachers' );
|
get_template_part( 'template-parts/pksh/teachers' );
|
||||||
|
|||||||
@ -45,7 +45,7 @@ $prem = $data->get_premium_program();
|
|||||||
<div class="prog-card__pricing">
|
<div class="prog-card__pricing">
|
||||||
<div class="prog-card__price prog-card__price--premium"><?php echo esc_html( $prem['price_sub'] ); ?> <span class="prog-card__price-period">стоимость абонемента за 4 недели</span></div>
|
<div class="prog-card__price prog-card__price--premium"><?php echo esc_html( $prem['price_sub'] ); ?> <span class="prog-card__price-period">стоимость абонемента за 4 недели</span></div>
|
||||||
<div class="prog-card__price-sub"><?php echo esc_html( $prem['price_single'] ); ?> за занятие — дешевле репетитора</div>
|
<div class="prog-card__price-sub"><?php echo esc_html( $prem['price_single'] ); ?> за занятие — дешевле репетитора</div>
|
||||||
<div class="prog-card__price-single">Разовое занятие вне абонемента: <?php echo esc_html( $prem['price_razov'] ?: $prem['price_single'] ); ?></div>
|
<div class="prog-card__price-single">Разовое занятие вне абонемента: <?php echo esc_html( $prem['price_single'] ); ?></div>
|
||||||
<div class="prog-card__urgency"><?php echo esc_html( $prem['urgency'] ); ?></div>
|
<div class="prog-card__urgency"><?php echo esc_html( $prem['urgency'] ); ?></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ $prem = $data->get_premium_program();
|
|||||||
<div class="prog-card__pricing">
|
<div class="prog-card__pricing">
|
||||||
<div class="prog-card__price"><?php echo esc_html( $base['price_sub'] ); ?> <span class="prog-card__price-period">стоимость абонемента за 4 недели</span></div>
|
<div class="prog-card__price"><?php echo esc_html( $base['price_sub'] ); ?> <span class="prog-card__price-period">стоимость абонемента за 4 недели</span></div>
|
||||||
<div class="prog-card__price-sub"><?php echo esc_html( $base['price_single'] ); ?> за занятие — дешевле репетитора</div>
|
<div class="prog-card__price-sub"><?php echo esc_html( $base['price_single'] ); ?> за занятие — дешевле репетитора</div>
|
||||||
<div class="prog-card__price-single">Разовое занятие вне абонемента: <?php echo esc_html( $base['price_razov'] ?: $base['price_single'] ); ?></div>
|
<div class="prog-card__price-single">Разовое занятие вне абонемента: <?php echo esc_html( $base['price_single'] ); ?></div>
|
||||||
<div class="prog-card__urgency"><?php echo esc_html( $base['urgency'] ); ?></div>
|
<div class="prog-card__urgency"><?php echo esc_html( $base['urgency'] ); ?></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -32,8 +32,6 @@ $teachers = $data->get_teachers();
|
|||||||
$t_id = $item['teacher_id'] ?? 0;
|
$t_id = $item['teacher_id'] ?? 0;
|
||||||
$t_subj = $item['teacher_subject'] ?? '';
|
$t_subj = $item['teacher_subject'] ?? '';
|
||||||
$t_about = $item['teacher_about'] ?? '';
|
$t_about = $item['teacher_about'] ?? '';
|
||||||
$t_badge = $item['teacher_badge'] ?? '';
|
|
||||||
$t_exp = $item['teacher_exp'] ?? '';
|
|
||||||
|
|
||||||
$t_post = $t_id ? get_post( $t_id ) : null;
|
$t_post = $t_id ? get_post( $t_id ) : null;
|
||||||
$t_name = $t_post ? $t_post->post_title : '—';
|
$t_name = $t_post ? $t_post->post_title : '—';
|
||||||
@ -53,18 +51,6 @@ $teachers = $data->get_teachers();
|
|||||||
if ( empty( $t_about ) && $t_post ) {
|
if ( empty( $t_about ) && $t_post ) {
|
||||||
$t_about = get_post_meta( $t_id, '_teacher_about', true );
|
$t_about = get_post_meta( $t_id, '_teacher_about', true );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( empty( $t_exp ) && $t_post ) {
|
|
||||||
$start_year = get_post_meta( $t_id, '_teacher_start_year', true );
|
|
||||||
if ( $start_year && is_numeric( $start_year ) ) {
|
|
||||||
$e = (int) date( 'Y' ) - (int) $start_year;
|
|
||||||
if ( $e > 0 ) {
|
|
||||||
$t_exp = $e . ' лет';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif ( ! empty( $t_exp ) && ctype_digit( trim( $t_exp ) ) ) {
|
|
||||||
$t_exp = trim( $t_exp ) . ' лет';
|
|
||||||
}
|
|
||||||
?>
|
?>
|
||||||
<div class="pksh-teachers__item">
|
<div class="pksh-teachers__item">
|
||||||
<div class="pksh-teachers__card">
|
<div class="pksh-teachers__card">
|
||||||
@ -85,15 +71,26 @@ $teachers = $data->get_teachers();
|
|||||||
<?php if ( $t_subj ) : ?>
|
<?php if ( $t_subj ) : ?>
|
||||||
<p class="pksh-teachers__subj"><?php echo esc_html( $t_subj ); ?></p>
|
<p class="pksh-teachers__subj"><?php echo esc_html( $t_subj ); ?></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php if ( $t_about ) : ?>
|
<?php if ( $t_post ) :
|
||||||
<p class="pksh-teachers__desc"><?php echo esc_html( wp_strip_all_tags( $t_about ) ); ?></p>
|
$t_desc = get_post_meta( $t_id, '_teacher_description', true );
|
||||||
|
if ( ! empty( $t_desc ) ) : ?>
|
||||||
|
<p class="pksh-teachers__desc"><?php echo esc_html( wp_strip_all_tags( $t_desc ) ); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<div class="pksh-teachers__meta">
|
<div class="pksh-teachers__meta">
|
||||||
<?php if ( $t_badge ) : ?>
|
<span class="pksh-teachers__meta-badge">👶 Работает с дошкольниками</span>
|
||||||
<span class="pksh-teachers__meta-badge"><?php echo esc_html( $t_badge ); ?></span>
|
<?php if ( $t_post ) :
|
||||||
<?php endif; ?>
|
$exp_years = '';
|
||||||
<?php if ( $t_exp ) : ?>
|
$start_year = get_post_meta( $t_id, '_teacher_start_year', true );
|
||||||
<span class="pksh-teachers__meta-exp">📅 Стаж: <?php echo esc_html( $t_exp ); ?></span>
|
if ( $start_year && is_numeric( $start_year ) ) {
|
||||||
|
$exp = (int) date( 'Y' ) - (int) $start_year;
|
||||||
|
if ( $exp > 0 ) {
|
||||||
|
$exp_years = $exp . ' лет';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( $exp_years ) : ?>
|
||||||
|
<span class="pksh-teachers__meta-exp">📅 Стаж: <?php echo esc_html( $exp_years ); ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<button class="pksh-teachers__btn open-bitrix-form">Записаться к этому педагогу</button>
|
<button class="pksh-teachers__btn open-bitrix-form">Записаться к этому педагогу</button>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user