get_*(). * Повторные вызовы instance() возвращают тот же объект — без дублирования запросов. * * @package Dekart */ if ( ! defined( 'ABSPATH' ) ) { exit; } class Pksh_Data { private static ?Pksh_Data $instance = null; private int $post_id; /** @var array Кэш branch-данных (get_option с fallback) */ private array $branch = []; /** @var array Кэш page-specific meta */ private array $page = []; /** @var array|null Кэш complex полей */ private ?array $social = null; private array $programs = []; private ?array $compare = null; private ?array $teachers = null; private ?array $reviews = null; private ?array $faq = null; private function __construct() { $this->post_id = get_the_ID(); } /** * Получить экземпляр (синглтон) */ public static function instance(): self { if ( null === self::$instance ) { self::$instance = new self(); } return self::$instance; } // ============================================================ // BRANCH / OPTION DATA (get_option → theme_option → post_meta) // ============================================================ /** * Адрес филиала */ public function get_address(): string { if ( ! array_key_exists( 'address', $this->branch ) ) { $this->branch['address'] = get_option( 'branch_address' ) ?: carbon_get_theme_option( 'site_address' ) ?: carbon_get_post_meta( $this->post_id, 'contact_address' ) ?: ''; } return $this->branch['address']; } /** * Координаты филиала (для карты) */ public function get_coords(): string { if ( ! array_key_exists( 'coords', $this->branch ) ) { $this->branch['coords'] = get_option( 'branch_coords' ) ?: carbon_get_post_meta( $this->post_id, 'contact_location' ) ?: ''; } return $this->branch['coords']; } /** * Телефон филиала */ public function get_phone(): string { if ( ! array_key_exists( 'phone', $this->branch ) ) { $this->branch['phone'] = get_option( 'branch_phone' ) ?: carbon_get_theme_option( 'site_phone' ) ?: carbon_get_post_meta( $this->post_id, 'contact_tel' ) ?: ''; } return $this->branch['phone']; } /** * Телефон, очищенный от не-цифровых символов */ public function get_phone_clean(): string { if ( ! array_key_exists( 'phone_clean', $this->branch ) ) { $this->branch['phone_clean'] = preg_replace( '/[^0-9+]/', '', $this->get_phone() ); } return $this->branch['phone_clean']; } /** * Email филиала */ public function get_email(): string { if ( ! array_key_exists( 'email', $this->branch ) ) { $this->branch['email'] = get_option( 'branch_email' ) ?: carbon_get_theme_option( 'site_mail' ) ?: carbon_get_post_meta( $this->post_id, 'contact_mail' ) ?: ''; } return $this->branch['email']; } /** * Название филиала / организации */ public function get_name(): string { if ( ! array_key_exists( 'name', $this->branch ) ) { $this->branch['name'] = get_option( 'branch_name' ) ?: carbon_get_theme_option( 'site_name' ) ?: 'Декарт'; } return $this->branch['name']; } /** * Город с предлогом (например "в Щёлково") */ public function get_city_prep(): string { if ( ! array_key_exists( 'city_prep', $this->branch ) ) { $this->branch['city_prep'] = get_option( 'branch_city_prep', 'в Щёлково' ); } return $this->branch['city_prep']; } /** * Город без предлога (например "Щёлково") */ public function get_city_clean(): string { if ( ! array_key_exists( 'city_clean', $this->branch ) ) { $this->branch['city_clean'] = str_replace( array( 'в ', 'В ' ), '', $this->get_city_prep() ); } return $this->branch['city_clean']; } /** * Количество отзывов на внешних площадках */ public function get_ext_review_count(): string { if ( ! array_key_exists( 'ext_review_count', $this->branch ) ) { $this->branch['ext_review_count'] = get_option( 'branch_ext_review_count', '247' ); } return $this->branch['ext_review_count']; } /** * Социальные сети (из branch_social option или CF) */ public function get_social_links(): array { if ( ! array_key_exists( 'social', $this->branch ) ) { $raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $this->post_id, 'social_media' ) ?: []; $this->branch['social'] = is_array( $raw ) ? $raw : []; } return $this->branch['social']; } // ============================================================ // HERO / BANNER // ============================================================ /** * ID изображения баннера (hero) */ public function get_banner_image_id(): int { if ( ! array_key_exists( 'banner_image_id', $this->page ) ) { $this->page['banner_image_id'] = (int) carbon_get_post_meta( $this->post_id, 'banner_image' ); } return $this->page['banner_image_id']; } /** * H1 заголовок hero-секции */ public function get_h1(): string { if ( ! array_key_exists( 'h1', $this->page ) ) { $this->page['h1'] = carbon_get_post_meta( $this->post_id, 'banner_h1' ) ?: 'Подготовка к школе в Щёлково'; } return $this->page['h1']; } /** * Подзаголовок hero */ public function get_subtitle(): string { if ( ! array_key_exists( 'subtitle', $this->page ) ) { $this->page['subtitle'] = carbon_get_post_meta( $this->post_id, 'banner_subtitle' ) ?: 'Первое занятие — бесплатно. Ребёнок научится читать, считать и писать в игровой форме. Группы до 10 человек.'; } return $this->page['subtitle']; } // ============================================================ // SOCIAL COUNTERS (complex) // ============================================================ /** * Массив social counters (complex field pksh_social_counters) * @return array[] */ public function get_social_counters(): array { if ( null === $this->social ) { $raw = carbon_get_post_meta( $this->post_id, 'pksh_social_counters' ); $this->social = is_array( $raw ) ? $raw : []; } return $this->social; } /** * Иконки для social counters (порядок соответствует полю) */ public static function social_icons(): array { return array( '🎓', '📅', '⭐', '👩‍🏫' ); } // ============================================================ // PROGRAMS // ============================================================ /** * Данные базовой программы * @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, urgency: string} */ public function get_base_program(): array { if ( ! array_key_exists( 'base', $this->programs ) ) { $this->programs['base'] = array( '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 раза в неделю — комфортный темп без перегрузки', '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_single' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_price_single' ) ?: '1 000 ₽', 'urgency' => carbon_get_post_meta( $this->post_id, 'pksh_prog_base_urgency' ) ?: 'Осталось 2 места в группе', ); } return $this->programs['base']; } /** * Данные премиум-программы * @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, urgency: string} */ public function get_premium_program(): array { if ( ! array_key_exists( 'prem', $this->programs ) ) { $this->programs['prem'] = array( '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 раза в неделю — быстрый прогресс', '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_single' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_price_single' ) ?: '1 500 ₽', 'urgency' => carbon_get_post_meta( $this->post_id, 'pksh_prog_prem_urgency' ) ?: 'Осталось 3 места в группе', ); } return $this->programs['prem']; } // ============================================================ // COMPARE TABLE (complex) // ============================================================ /** * Строки таблицы сравнения * @return array[] */ public function get_compare_rows(): array { if ( null === $this->compare ) { $raw = carbon_get_post_meta( $this->post_id, 'pksh_compare_rows' ); $this->compare = is_array( $raw ) ? $raw : []; } return $this->compare; } /** * Сноска под таблицей сравнения */ public function get_compare_footnote(): string { if ( ! array_key_exists( 'footnote', $this->page ) ) { $this->page['footnote'] = carbon_get_post_meta( $this->post_id, 'pksh_compare_footnote' ) ?: ''; } return $this->page['footnote']; } // ============================================================ // TEACHERS (complex) // ============================================================ /** * Массив преподавателей (complex field pksh_teachers) * @return array[] */ public function get_teachers(): array { if ( null === $this->teachers ) { $raw = carbon_get_post_meta( $this->post_id, 'pksh_teachers' ); $this->teachers = is_array( $raw ) ? $raw : []; } return $this->teachers; } // ============================================================ // REVIEWS (complex) // ============================================================ /** * Массив отзывов (complex field pksh_reviews_list) * @return array[] */ public function get_reviews(): array { if ( null === $this->reviews ) { $raw = carbon_get_post_meta( $this->post_id, 'pksh_reviews_list' ); $this->reviews = is_array( $raw ) ? $raw : []; } return $this->reviews; } // ============================================================ // FAQ (complex) // ============================================================ /** * Массив FAQ (complex field pksh_faq_items) * @return array[] */ public function get_faq_items(): array { if ( null === $this->faq ) { $raw = carbon_get_post_meta( $this->post_id, 'pksh_faq_items' ); $this->faq = is_array( $raw ) ? $raw : []; } return $this->faq; } // ============================================================ // HONEST TIMER (shared helper) // ============================================================ /** * Timestamp честного дедлайна */ public function get_honest_deadline(): int { if ( ! array_key_exists( 'deadline', $this->page ) ) { $this->page['deadline'] = function_exists( 'dekart_get_honest_deadline' ) ? (int) dekart_get_honest_deadline() : 0; } return $this->page['deadline']; } /** * Вывести HTML честного таймера + inline JS. * Используется в #cta-test и #final-cta. * * @param string $label Текст над таймером. */ public static function render_honest_timer( string $label = 'Цены действуют до конца месяца:' ): void { $ts = self::instance()->get_honest_deadline(); if ( $ts <= 0 ) { return; } ?>
00 дн : 00 ч : 00 мин : 00 сек