Global 2026-07-18 ПКШ + программа
This commit is contained in:
parent
9ed786b881
commit
8f91d6e177
48
llms.txt
48
llms.txt
@ -1,34 +1,18 @@
|
||||
# Декарт — частная школа в Щёлково
|
||||
> Частная школа полного дня в Щёлково, Московская область. Программы начальной школы (1–4 класс), средней школы (5–9 класс), подготовка к ЕГЭ и ОГЭ (10–11 класс). Индивидуальный подход, классы до 12 человек, продлённый день, подготовка к школе.
|
||||
# Детский центр «Декарт» — Подготовка к школе в Щёлково
|
||||
> Образовательный центр в Щёлково с гослицензией. Работаем с 2014 года. Готовим детей 5–7 лет к школе: чтение, письмо, математика, логика.
|
||||
|
||||
## Основные страницы
|
||||
- [Отзывы родителей и учеников](https://schelkovo.dekart.school/otzyvy/)
|
||||
- [Начальная школа](https://schelkovo.dekart.school/nachalnaya-shkola/)
|
||||
- [Подготовка к ЕГЭ и ОГЭ](https://schelkovo.dekart.school/podgotovka-k-ege/)
|
||||
- [Группа продлённого дня](https://schelkovo.dekart.school/prodlenka/)
|
||||
- [Подготовка к школе](https://schelkovo.dekart.school/podgotovka-k-shkole/)
|
||||
- [Летний городской лагерь](https://schelkovo.dekart.school/gorodskoj-lager/)
|
||||
- [Контакты](https://schelkovo.dekart.school/kontakty/)
|
||||
- [О школе](https://schelkovo.dekart.school/o-nas/)
|
||||
## Основные разделы
|
||||
- [Подготовка к школе](https://xn--80atdlj0d.xn--p1ai/podgotovka-k-shkole/): Комплексные занятия для детей 5–7 лет. Чтение, письмо, счёт, логика. Первое занятие — бесплатно.
|
||||
- [Начальная школа](https://xn--80atdlj0d.xn--p1ai/nachalnaya-shkola/): Программы 1–4 классов. УМК «Перспектива», система Занкова, Cambridge English.
|
||||
- [О нас](https://xn--80atdlj0d.xn--p1ai/o-nas/): Лицензия, документы, педагоги.
|
||||
- [Отзывы](https://xn--80atdlj0d.xn--p1ai/otzyvy/): Отзывы родителей и выпускников.
|
||||
- [Контакты](https://xn--80atdlj0d.xn--p1ai/contacts/): Адрес, телефон, карта.
|
||||
|
||||
## О школе
|
||||
- Частная школа «Декарт» основана в 2010 году
|
||||
- Расположена по адресу: ул. Талсинская, 24, Щёлково, Московская область
|
||||
- Режим работы: пн–пт 8:00–19:00, сб 9:00–14:00
|
||||
- Классы: до 12 человек
|
||||
- Наполняемость: более 500 выпускников
|
||||
- Педагоги: 50+ квалифицированных специалистов
|
||||
|
||||
## Что предлагает школа
|
||||
- Начальное общее образование (1–4 класс) с углублённым английским
|
||||
- Основное общее образование (5–9 класс) с предпрофильной подготовкой
|
||||
- Среднее общее образование (10–11 класс) с подготовкой к ЕГЭ
|
||||
- Подготовка к школе для детей 5–6 лет
|
||||
- Группа продлённого дня с 8:00 до 19:00
|
||||
- Летний городской лагерь
|
||||
- Кружки: робототехника, шахматы, английский театр, изостудия
|
||||
|
||||
<!--
|
||||
TODO: уточнить актуальные URL страниц программ на проде
|
||||
TODO: добавить страницу «Поступление» после её создания
|
||||
-->
|
||||
## Ключевые факты
|
||||
- Адрес: Талсинская ул., 24, Щёлково, Московская область
|
||||
- Телефон: +7 (926) 931-14-34
|
||||
- Лицензия: государственная образовательная лицензия
|
||||
- Основан: 2014 год
|
||||
- Педагоги: высшее педагогическое образование, стаж от 12 лет
|
||||
- Группы: до 10 человек
|
||||
- Формат: очные занятия
|
||||
|
||||
978
wp-content/object-cache.php.dev-disabled
Normal file
978
wp-content/object-cache.php.dev-disabled
Normal file
@ -0,0 +1,978 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
Plugin Name: Memcached
|
||||
Description: Memcached backend for the WP Object Cache.
|
||||
Version: 4.0.0
|
||||
Plugin URI: https://wordpress.org/plugins/memcached/
|
||||
Author: Ryan Boren, Denis de Bernardy, Matt Martz, Andy Skelton
|
||||
|
||||
Install this file to wp-content/object-cache.php
|
||||
*/
|
||||
|
||||
// Users with setups where multiple installs share a common wp-config.php or $table_prefix
|
||||
// can use this to guarantee uniqueness for the keys generated by this object cache
|
||||
if ( ! defined( 'WP_CACHE_KEY_SALT' ) ) {
|
||||
define( 'WP_CACHE_KEY_SALT', '' );
|
||||
}
|
||||
|
||||
function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->add( $key, $data, $group, $expire );
|
||||
}
|
||||
|
||||
function wp_cache_incr( $key, $n = 1, $group = '' ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->incr( $key, $n, $group );
|
||||
}
|
||||
|
||||
function wp_cache_decr( $key, $n = 1, $group = '' ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->decr( $key, $n, $group );
|
||||
}
|
||||
|
||||
function wp_cache_close() {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->close();
|
||||
}
|
||||
|
||||
function wp_cache_delete( $key, $group = '' ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->delete( $key, $group );
|
||||
}
|
||||
|
||||
function wp_cache_flush() {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->flush();
|
||||
}
|
||||
|
||||
function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
$value = apply_filters( 'pre_wp_cache_get', false, $key, $group, $force );
|
||||
if ( false !== $value ) {
|
||||
$found = true;
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $wp_object_cache->get( $key, $group, $force, $found );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve multiple cache entries
|
||||
*
|
||||
* @param array $groups Array of arrays, of groups and keys to retrieve
|
||||
* @return mixed
|
||||
*/
|
||||
function wp_cache_get_multi( $groups ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->get_multi( $groups );
|
||||
}
|
||||
|
||||
function wp_cache_init() {
|
||||
global $wp_object_cache;
|
||||
|
||||
$wp_object_cache = new WP_Object_Cache();
|
||||
}
|
||||
|
||||
function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->replace( $key, $data, $group, $expire );
|
||||
}
|
||||
|
||||
function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
if ( defined( 'WP_INSTALLING' ) == false ) {
|
||||
return $wp_object_cache->set( $key, $data, $group, $expire );
|
||||
} else {
|
||||
return $wp_object_cache->delete( $key, $group );
|
||||
}
|
||||
}
|
||||
|
||||
function wp_cache_switch_to_blog( $blog_id ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
return $wp_object_cache->switch_to_blog( $blog_id );
|
||||
}
|
||||
|
||||
function wp_cache_add_global_groups( $groups ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
$wp_object_cache->add_global_groups( $groups );
|
||||
}
|
||||
|
||||
function wp_cache_add_non_persistent_groups( $groups ) {
|
||||
global $wp_object_cache;
|
||||
|
||||
$wp_object_cache->add_non_persistent_groups( $groups );
|
||||
}
|
||||
|
||||
class WP_Object_Cache {
|
||||
var $global_groups = array( 'WP_Object_Cache_global' );
|
||||
|
||||
var $no_mc_groups = array();
|
||||
|
||||
var $cache = array();
|
||||
var $mc = array();
|
||||
var $default_mcs = array();
|
||||
var $stats = array();
|
||||
var $group_ops = array();
|
||||
|
||||
var $flush_group = 'WP_Object_Cache';
|
||||
var $global_flush_group = 'WP_Object_Cache_global';
|
||||
var $flush_key = "flush_number_v4";
|
||||
var $old_flush_key = "flush_number";
|
||||
var $flush_number = array();
|
||||
var $global_flush_number = null;
|
||||
|
||||
var $cache_enabled = true;
|
||||
var $default_expiration = 0;
|
||||
var $max_expiration = 2592000; // 30 days
|
||||
|
||||
var $stats_callback = null;
|
||||
|
||||
var $connection_errors = array();
|
||||
|
||||
var $time_total = 0;
|
||||
var $size_total = 0;
|
||||
var $slow_op_microseconds = 0.005; // 5 ms
|
||||
|
||||
function add( $id, $data, $group = 'default', $expire = 0 ) {
|
||||
$key = $this->key( $id, $group );
|
||||
|
||||
if ( is_object( $data ) ) {
|
||||
$data = clone $data;
|
||||
}
|
||||
|
||||
if ( in_array( $group, $this->no_mc_groups ) ) {
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $data,
|
||||
'found' => false,
|
||||
];
|
||||
|
||||
return true;
|
||||
} elseif ( isset( $this->cache[ $key ][ 'value' ] ) && false !== $this->cache[ $key ][ 'value' ] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$mc =& $this->get_mc( $group );
|
||||
|
||||
$expire = intval( $expire );
|
||||
if ( 0 === $expire || $expire > $this->max_expiration ) {
|
||||
$expire = $this->default_expiration;
|
||||
}
|
||||
|
||||
$size = $this->get_data_size( $data );
|
||||
$this->timer_start();
|
||||
$result = $mc->add( $key, $data, false, $expire );
|
||||
$elapsed = $this->timer_stop();
|
||||
|
||||
$comment = '';
|
||||
if ( isset( $this->cache[ $key ] ) ) {
|
||||
$comment .= ' [lc already]';
|
||||
}
|
||||
if ( false === $result ) {
|
||||
$comment .= ' [mc already]';
|
||||
}
|
||||
|
||||
$this->group_ops_stats( 'add', $key, $group, $size, $elapsed, $comment );
|
||||
|
||||
if ( false !== $result ) {
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $data,
|
||||
'found' => true,
|
||||
];
|
||||
} else if ( false === $result && true === isset( $this->cache[$key][ 'value' ] ) && false === $this->cache[$key][ 'value' ] ) {
|
||||
/*
|
||||
* Here we unset local cache if remote add failed and local cache value is equal to `false` in order
|
||||
* to update the local cache anytime we get a new information from remote server. This way, the next
|
||||
* cache get will go to remote server and will fetch recent data.
|
||||
*/
|
||||
unset( $this->cache[$key] );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function add_global_groups( $groups ) {
|
||||
if ( ! is_array( $groups ) ) {
|
||||
$groups = (array) $groups;
|
||||
}
|
||||
|
||||
$this->global_groups = array_merge( $this->global_groups, $groups );
|
||||
$this->global_groups = array_unique( $this->global_groups );
|
||||
}
|
||||
|
||||
function add_non_persistent_groups( $groups ) {
|
||||
if ( ! is_array( $groups ) ) {
|
||||
$groups = (array) $groups;
|
||||
}
|
||||
|
||||
$this->no_mc_groups = array_merge( $this->no_mc_groups, $groups );
|
||||
$this->no_mc_groups = array_unique( $this->no_mc_groups );
|
||||
}
|
||||
|
||||
function incr( $id, $n = 1, $group = 'default' ) {
|
||||
$key = $this->key( $id, $group );
|
||||
$mc =& $this->get_mc( $group );
|
||||
|
||||
$incremented = $mc->increment( $key, $n );
|
||||
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $incremented,
|
||||
'found' => false !== $incremented,
|
||||
];
|
||||
|
||||
return $this->cache[ $key ][ 'value' ];
|
||||
}
|
||||
|
||||
function decr( $id, $n = 1, $group = 'default' ) {
|
||||
$key = $this->key( $id, $group );
|
||||
$mc =& $this->get_mc( $group );
|
||||
|
||||
$decremented = $mc->decrement( $key, $n );
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $decremented,
|
||||
'found' => false !== $decremented,
|
||||
];
|
||||
|
||||
return $this->cache[ $key ][ 'value' ];
|
||||
}
|
||||
|
||||
function close() {
|
||||
foreach ( $this->mc as $bucket => $mc ) {
|
||||
$mc->close();
|
||||
}
|
||||
}
|
||||
|
||||
function delete( $id, $group = 'default' ) {
|
||||
$key = $this->key( $id, $group );
|
||||
|
||||
if ( in_array( $group, $this->no_mc_groups ) ) {
|
||||
unset( $this->cache[ $key ] );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$mc =& $this->get_mc( $group );
|
||||
|
||||
$this->timer_start();
|
||||
$result = $mc->delete( $key );
|
||||
$elapsed = $this->timer_stop();
|
||||
|
||||
$this->group_ops_stats( 'delete', $key, $group, null, $elapsed );
|
||||
|
||||
if ( false !== $result ) {
|
||||
unset( $this->cache[ $key ] );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Gets number from all default servers, replicating if needed
|
||||
function get_max_flush_number( $group ) {
|
||||
$key = $this->key( $this->flush_key, $group );
|
||||
|
||||
$values = array();
|
||||
$size = 19; // size of microsecond timestamp serialized
|
||||
foreach ( $this->default_mcs as $i => $mc ) {
|
||||
$flags = false;
|
||||
$this->timer_start();
|
||||
$values[ $i ] = $mc->get( $key, $flags );
|
||||
$elapsed = $this->timer_stop();
|
||||
|
||||
if ( empty( $values[ $i ] ) ) {
|
||||
$this->group_ops_stats( 'get_flush_number', $key, $group, null, $elapsed, 'not_in_memcache' );
|
||||
} else {
|
||||
$this->group_ops_stats( 'get_flush_number', $key, $group, $size, $elapsed, 'memcache' );
|
||||
}
|
||||
}
|
||||
|
||||
$max = max( $values );
|
||||
|
||||
if ( ! $max > 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Replicate to servers not having the max.
|
||||
$expire = 0;
|
||||
foreach ( $this->default_mcs as $i => $mc ) {
|
||||
if ( $values[ $i ] < $max ) {
|
||||
$this->timer_start();
|
||||
$mc->set( $key, $max, false, $expire );
|
||||
$elapsed = $this->timer_stop();
|
||||
$this->group_ops_stats( 'set_flush_number', $key, $group, $size, $elapsed, 'replication_repair' );
|
||||
}
|
||||
}
|
||||
|
||||
return $max;
|
||||
}
|
||||
|
||||
function set_flush_number( $value, $group ) {
|
||||
$key = $this->key( $this->flush_key, $group );
|
||||
$expire = 0;
|
||||
$size = 19;
|
||||
foreach ( $this->default_mcs as $i => $mc ) {
|
||||
$this->timer_start();
|
||||
$mc->set( $key, $value, false, $expire );
|
||||
$elapsed = $this->timer_stop();
|
||||
$this->group_ops_stats( 'set_flush_number', $key, $group, $size, $elapsed, 'replication' );
|
||||
}
|
||||
}
|
||||
|
||||
function get_flush_number( $group ) {
|
||||
$flush_number = $this->get_max_flush_number( $group );
|
||||
// What if there is no v4 flush number?
|
||||
if ( empty( $flush_number ) ) {
|
||||
// Look for the v3 flush number key.
|
||||
$flush_number = intval( $this->get( $this->old_flush_key, $group ) );
|
||||
if ( !empty( $flush_number ) ) {
|
||||
// Found v3 flush number. Upgrade to v4 with replication.
|
||||
$this->set_flush_number( $flush_number, $group );
|
||||
// Delete v3 key so we can't later restore it and find stale keys.
|
||||
} else {
|
||||
// No flush number found anywhere. Make a new one. This flushes the cache.
|
||||
$flush_number = $this->new_flush_number();
|
||||
$this->set_flush_number( $flush_number, $group );
|
||||
}
|
||||
}
|
||||
|
||||
return $flush_number;
|
||||
}
|
||||
|
||||
function get_global_flush_number() {
|
||||
if ( ! isset( $this->global_flush_number ) ) {
|
||||
$this->global_flush_number = $this->get_flush_number( $this->global_flush_group );
|
||||
}
|
||||
return $this->global_flush_number;
|
||||
}
|
||||
|
||||
function get_blog_flush_number() {
|
||||
if ( ! isset( $this->flush_number[ $this->blog_prefix ] ) ) {
|
||||
$this->flush_number[ $this->blog_prefix ] = $this->get_flush_number( $this->flush_group );
|
||||
}
|
||||
return $this->flush_number[ $this->blog_prefix ];
|
||||
}
|
||||
|
||||
function flush() {
|
||||
// Do not use the memcached flush method. It acts on an
|
||||
// entire memcached server, affecting all sites.
|
||||
// Flush is also unusable in some setups, e.g. twemproxy.
|
||||
// Instead, rotate the key prefix for the current site.
|
||||
// Global keys are rotated when flushing on any network's
|
||||
// main site.
|
||||
$this->cache = array();
|
||||
|
||||
$flush_number = $this->new_flush_number();
|
||||
|
||||
$this->rotate_site_keys( $flush_number );
|
||||
|
||||
if ( is_main_site() ) {
|
||||
$this->rotate_global_keys( $flush_number );
|
||||
}
|
||||
}
|
||||
|
||||
function rotate_site_keys( $flush_number = null ) {
|
||||
if ( is_null( $flush_number ) ) {
|
||||
$flush_number = $this->new_flush_number();
|
||||
}
|
||||
|
||||
$this->set_flush_number( $flush_number, $this->flush_group );
|
||||
|
||||
$this->flush_number[ $this->blog_prefix ] = $flush_number;
|
||||
}
|
||||
|
||||
function rotate_global_keys( $flush_number = null ) {
|
||||
if ( is_null( $flush_number ) ) {
|
||||
$flush_number = $this->new_flush_number();
|
||||
}
|
||||
|
||||
$this->set_flush_number( $flush_number, $this->global_flush_group );
|
||||
|
||||
$this->global_flush_number = $flush_number;
|
||||
}
|
||||
|
||||
function new_flush_number() {
|
||||
return intval( microtime( true ) * 1e6 );
|
||||
}
|
||||
|
||||
function get( $id, $group = 'default', $force = false, &$found = null ) {
|
||||
$key = $this->key( $id, $group );
|
||||
$mc =& $this->get_mc( $group );
|
||||
$found = true;
|
||||
|
||||
if ( isset( $this->cache[ $key ] ) && ( ! $force || in_array( $group, $this->no_mc_groups ) ) ) {
|
||||
if ( isset( $this->cache[ $key ][ 'value' ] ) && is_object( $this->cache[ $key ][ 'value' ] ) ) {
|
||||
$value = clone $this->cache[ $key ][ 'value' ];
|
||||
} else {
|
||||
$value = $this->cache[ $key ][ 'value' ];
|
||||
}
|
||||
$found = $this->cache[ $key ][ 'found' ];
|
||||
|
||||
$this->group_ops_stats( 'get_local', $key, $group, null, null, 'local' );
|
||||
} else if ( in_array( $group, $this->no_mc_groups ) ) {
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $value = false,
|
||||
'found' => false,
|
||||
];
|
||||
|
||||
$found = false;
|
||||
|
||||
$this->group_ops_stats( 'get_local', $key, $group, null, null, 'not_in_local' );
|
||||
} else {
|
||||
$flags = false;
|
||||
$this->timer_start();
|
||||
$value = $mc->get( $key, $flags );
|
||||
$elapsed = $this->timer_stop();
|
||||
|
||||
// Value will be unchanged if the key doesn't exist.
|
||||
if ( false === $flags ) {
|
||||
$found = false;
|
||||
$value = false;
|
||||
}
|
||||
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $value,
|
||||
'found' => $found,
|
||||
];
|
||||
|
||||
if ( is_null( $value ) || $value === false ) {
|
||||
$this->group_ops_stats( 'get', $key, $group, null, $elapsed, 'not_in_memcache' );
|
||||
} else if ( 'checkthedatabaseplease' === $value ) {
|
||||
$this->group_ops_stats( 'get', $key, $group, null, $elapsed, 'checkthedatabaseplease' );
|
||||
} else {
|
||||
$size = $this->get_data_size( $value );
|
||||
$this->group_ops_stats( 'get', $key, $group, $size, $elapsed, 'memcache' );
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'checkthedatabaseplease' === $value ) {
|
||||
unset( $this->cache[ $key ] );
|
||||
|
||||
$found = false;
|
||||
$value = false;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
function get_multi( $groups ) {
|
||||
/*
|
||||
format: $get['group-name'] = array( 'key1', 'key2' );
|
||||
*/
|
||||
$return = array();
|
||||
$return_cache = array(
|
||||
'value' => false,
|
||||
'found' => false,
|
||||
);
|
||||
|
||||
foreach ( $groups as $group => $ids ) {
|
||||
$mc =& $this->get_mc( $group );
|
||||
$keys = array();
|
||||
$this->timer_start();
|
||||
|
||||
foreach ( $ids as $id ) {
|
||||
$key = $this->key( $id, $group );
|
||||
$keys[] = $key;
|
||||
|
||||
if ( isset( $this->cache[ $key ] ) ) {
|
||||
if ( is_object( $this->cache[ $key ][ 'value'] ) ) {
|
||||
$return[ $key ] = clone $this->cache[ $key ][ 'value'];
|
||||
$return_cache[ $key ] = [
|
||||
'value' => clone $this->cache[ $key ][ 'value'],
|
||||
'found' => $this->cache[ $key ][ 'found'],
|
||||
];
|
||||
} else {
|
||||
$return[ $key ] = $this->cache[ $key ][ 'value'];
|
||||
$return_cache[ $key ] = [
|
||||
'value' => $this->cache[ $key ][ 'value' ],
|
||||
'found' => $this->cache[ $key ][ 'found' ],
|
||||
];
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if ( in_array( $group, $this->no_mc_groups ) ) {
|
||||
$return[ $key ] = false;
|
||||
$return_cache[ $key ] = [
|
||||
'value' => false,
|
||||
'found' => false,
|
||||
];
|
||||
|
||||
continue;
|
||||
} else {
|
||||
$fresh_get = $mc->get( $key );
|
||||
$return[ $key ] = $fresh_get;
|
||||
$return_cache[ $key ] = [
|
||||
'value' => $fresh_get,
|
||||
'found' => false !== $fresh_get,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$elapsed = $this->timer_stop();
|
||||
$this->group_ops_stats( 'get_multi', $keys, $group, null, $elapsed );
|
||||
}
|
||||
|
||||
$this->cache = array_merge( $this->cache, $return_cache );
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
function flush_prefix( $group ) {
|
||||
if ( $group === $this->flush_group || $group === $this->global_flush_group ) {
|
||||
// Never flush the flush numbers.
|
||||
$number = '_';
|
||||
} elseif ( false !== array_search( $group, $this->global_groups ) ) {
|
||||
$number = $this->get_global_flush_number();
|
||||
} else {
|
||||
$number = $this->get_blog_flush_number();
|
||||
}
|
||||
return $number . ':';
|
||||
}
|
||||
|
||||
function key( $key, $group ) {
|
||||
if ( empty( $group ) ) {
|
||||
$group = 'default';
|
||||
}
|
||||
|
||||
$prefix = $this->key_salt;
|
||||
|
||||
$prefix .= $this->flush_prefix( $group );
|
||||
|
||||
if ( false !== array_search( $group, $this->global_groups ) ) {
|
||||
$prefix .= $this->global_prefix;
|
||||
} else {
|
||||
$prefix .= $this->blog_prefix;
|
||||
}
|
||||
|
||||
return preg_replace( '/\s+/', '', "$prefix:$group:$key" );
|
||||
}
|
||||
|
||||
function replace( $id, $data, $group = 'default', $expire = 0 ) {
|
||||
$key = $this->key( $id, $group );
|
||||
$expire = intval( $expire );
|
||||
if ( 0 === $expire || $expire > $this->max_expiration ) {
|
||||
$expire = $this->default_expiration;
|
||||
}
|
||||
$mc =& $this->get_mc( $group );
|
||||
|
||||
if ( is_object( $data ) ) {
|
||||
$data = clone $data;
|
||||
}
|
||||
|
||||
$size = $this->get_data_size( $data );
|
||||
$this->timer_start();
|
||||
$result = $mc->replace( $key, $data, false, $expire );
|
||||
$elapsed = $this->timer_stop();
|
||||
$this->group_ops_stats( 'replace', $key, $group, $size, $elapsed );
|
||||
|
||||
if ( false !== $result ) {
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $data,
|
||||
'found' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function set( $id, $data, $group = 'default', $expire = 0 ) {
|
||||
$key = $this->key( $id, $group );
|
||||
|
||||
if ( isset( $this->cache[ $key ] ) && ( 'checkthedatabaseplease' === $this->cache[ $key ][ 'value' ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_object( $data ) ) {
|
||||
$data = clone $data;
|
||||
}
|
||||
|
||||
$this->cache[ $key ] = [
|
||||
'value' => $data,
|
||||
'found' => false, // Set to false as not technically found in memcache at this point.
|
||||
];
|
||||
|
||||
if ( in_array( $group, $this->no_mc_groups ) ) {
|
||||
$this->group_ops_stats( 'set_local', $key, $group, null, null );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$expire = intval( $expire );
|
||||
if ( 0 === $expire || $expire > $this->max_expiration ) {
|
||||
$expire = $this->default_expiration;
|
||||
}
|
||||
|
||||
$mc =& $this->get_mc( $group );
|
||||
|
||||
$size = $this->get_data_size( $data );
|
||||
$this->timer_start();
|
||||
$result = $mc->set( $key, $data, false, $expire );
|
||||
$elapsed = $this->timer_stop();
|
||||
$this->group_ops_stats( 'set', $key, $group, $size, $elapsed );
|
||||
|
||||
// Update the found cache value with the result of the set in memcache.
|
||||
$this->cache[ $key ][ 'found' ] = $result;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function switch_to_blog( $blog_id ) {
|
||||
global $table_prefix;
|
||||
|
||||
$blog_id = (int) $blog_id;
|
||||
|
||||
$this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix );
|
||||
}
|
||||
|
||||
function colorize_debug_line( $line, $trailing_html = '' ) {
|
||||
$colors = array(
|
||||
'get' => 'green',
|
||||
'get_local' => 'lightgreen',
|
||||
'get_multi' => 'fuchsia',
|
||||
'set' => 'purple',
|
||||
'set_local' => 'orchid',
|
||||
'add' => 'blue',
|
||||
'delete' => 'red',
|
||||
'delete_local' => 'tomato',
|
||||
'slow-ops' => 'crimson',
|
||||
);
|
||||
|
||||
$cmd = substr( $line, 0, strpos( $line, ' ' ) );
|
||||
|
||||
// Start off with a neutral default color...
|
||||
$color_for_cmd = 'brown';
|
||||
// And if the cmd has a specific color, use that instead
|
||||
if ( isset( $colors[ $cmd ] ) ) {
|
||||
$color_for_cmd = $colors[ $cmd ];
|
||||
}
|
||||
|
||||
$cmd2 = "<span style='color:" . esc_attr( $color_for_cmd ) . "; font-weight: bold;'>" . esc_html( $cmd ) . "</span>";
|
||||
|
||||
return $cmd2 . esc_html( substr( $line, strlen( $cmd ) ) ) . "$trailing_html\n";
|
||||
}
|
||||
|
||||
function js_toggle() {
|
||||
echo "
|
||||
<script>
|
||||
function memcachedToggleVisibility( id, hidePrefix ) {
|
||||
var element = document.getElementById( id );
|
||||
if ( ! element ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide all element with `hidePrefix` if given. Used to display only one element at a time.
|
||||
if ( hidePrefix ) {
|
||||
var groupStats = document.querySelectorAll( '[id^=\"' + hidePrefix + '\"]' );
|
||||
groupStats.forEach(
|
||||
function ( element ) {
|
||||
element.style.display = 'none';
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Toggle the one we clicked.
|
||||
if ( 'none' === element.style.display ) {
|
||||
element.style.display = 'block';
|
||||
} else {
|
||||
element.style.display = 'none';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
";
|
||||
}
|
||||
|
||||
function stats() {
|
||||
$this->js_toggle();
|
||||
|
||||
echo '<h2><span>Total memcache query time:</span>' . number_format_i18n( sprintf( '%0.1f', $this->time_total * 1000 ), 1 ) . ' ms</h2>';
|
||||
echo "\n";
|
||||
echo '<h2><span>Total memcache size:</span>' . esc_html( size_format( $this->size_total, 2 ) ) . '</h2>';
|
||||
echo "\n";
|
||||
|
||||
foreach ( $this->stats as $stat => $n ) {
|
||||
if ( empty( $n ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo '<h2>';
|
||||
echo $this->colorize_debug_line( "$stat $n" );
|
||||
echo '</h2>';
|
||||
}
|
||||
|
||||
echo "<ul class='debug-menu-links' style='clear:left;font-size:14px;'>\n";
|
||||
$groups = array_keys( $this->group_ops );
|
||||
usort( $groups, 'strnatcasecmp' );
|
||||
|
||||
$active_group = $groups[0];
|
||||
// Always show `slow-ops` first
|
||||
if ( in_array( 'slow-ops', $groups ) ) {
|
||||
$slow_ops_key = array_search( 'slow-ops', $groups );
|
||||
$slow_ops = $groups[ $slow_ops_key ];
|
||||
unset( $groups[ $slow_ops_key ] );
|
||||
array_unshift( $groups, $slow_ops );
|
||||
$active_group = 'slow-ops';
|
||||
}
|
||||
|
||||
$total_ops = 0;
|
||||
$group_titles = array();
|
||||
foreach ( $groups as $group ) {
|
||||
$group_name = $group;
|
||||
if ( empty( $group_name ) ) {
|
||||
$group_name = 'default';
|
||||
}
|
||||
$group_ops = count( $this->group_ops[ $group ] );
|
||||
$group_size = size_format( array_sum( array_map( function ( $op ) { return $op[2]; }, $this->group_ops[ $group ] ) ), 2 );
|
||||
$group_time = number_format_i18n( sprintf( '%0.1f', array_sum( array_map( function ( $op ) { return $op[3]; }, $this->group_ops[ $group ] ) ) * 1000 ), 1 );
|
||||
$total_ops += $group_ops;
|
||||
$group_title = "{$group_name} [$group_ops][$group_size][{$group_time} ms]";
|
||||
$group_titles[ $group ] = $group_title;
|
||||
echo "\t<li><a href='#' onclick='memcachedToggleVisibility( \"object-cache-stats-menu-target-" . esc_js( $group_name ) . "\", \"object-cache-stats-menu-target-\" );'>" . esc_html( $group_title ) . "</a></li>\n";
|
||||
}
|
||||
echo "</ul>\n";
|
||||
|
||||
echo "<div id='object-cache-stats-menu-targets'>\n";
|
||||
foreach ( $groups as $group ) {
|
||||
$group_name = $group;
|
||||
if ( empty( $group_name ) ) {
|
||||
$group_name = 'default';
|
||||
}
|
||||
$current = $active_group == $group ? 'style="display: block"' : 'style="display: none"';
|
||||
echo "<div id='object-cache-stats-menu-target-" . esc_attr( $group_name ) . "' class='object-cache-stats-menu-target' $current>\n";
|
||||
echo '<h3>' . esc_html( $group_titles[ $group ] ) . '</h3>' . "\n";
|
||||
echo "<pre>\n";
|
||||
foreach ( $this->group_ops[ $group ] as $index => $arr ) {
|
||||
printf( '%3d ', $index );
|
||||
echo $this->get_group_ops_line( $index, $arr );
|
||||
}
|
||||
echo "</pre>\n";
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
echo "</div>";
|
||||
}
|
||||
|
||||
function get_group_ops_line( $index, $arr ) {
|
||||
// operation
|
||||
$line = "{$arr[0]} ";
|
||||
|
||||
// key
|
||||
$json_encoded_key = json_encode( $arr[1] );
|
||||
$line .= $json_encoded_key . " ";
|
||||
|
||||
// comment
|
||||
if ( ! empty( $arr[4] ) ) {
|
||||
$line .= "{$arr[4]} ";
|
||||
}
|
||||
|
||||
// size
|
||||
if ( isset( $arr[2] ) ) {
|
||||
$line .= '(' . size_format( $arr[2], 2 ) . ') ';
|
||||
}
|
||||
|
||||
// time
|
||||
if ( isset( $arr[3] ) ) {
|
||||
$line .= '(' . number_format_i18n( sprintf( '%0.1f', $arr[3] * 1000 ), 1 ) . ' ms)';
|
||||
}
|
||||
|
||||
// backtrace
|
||||
$bt_link = '';
|
||||
if ( isset( $arr[6] ) ) {
|
||||
$key_hash = md5( $index . $json_encoded_key );
|
||||
$bt_link = " <small><a href='#' onclick='memcachedToggleVisibility( \"object-cache-stats-debug-$key_hash\" );'>Toggle Backtrace</a></small>";
|
||||
$bt_link .= "<pre id='object-cache-stats-debug-$key_hash' style='display:none'>" . esc_html( $arr[6] ) . "</pre>";
|
||||
}
|
||||
|
||||
return $this->colorize_debug_line( $line, $bt_link );
|
||||
}
|
||||
|
||||
function &get_mc( $group ) {
|
||||
if ( isset( $this->mc[ $group ] ) ) {
|
||||
return $this->mc[ $group ];
|
||||
}
|
||||
|
||||
return $this->mc['default'];
|
||||
}
|
||||
|
||||
function failure_callback( $host, $port ) {
|
||||
$this->connection_errors[] = array(
|
||||
'host' => $host,
|
||||
'port' => $port,
|
||||
);
|
||||
}
|
||||
|
||||
function salt_keys( $key_salt ) {
|
||||
if ( strlen( $key_salt ) ) {
|
||||
$this->key_salt = $key_salt . ':';
|
||||
} else {
|
||||
$this->key_salt = '';
|
||||
}
|
||||
}
|
||||
|
||||
function __construct() {
|
||||
$this->stats = array(
|
||||
'get' => 0,
|
||||
'get_local' => 0,
|
||||
'get_multi' => 0,
|
||||
'set' => 0,
|
||||
'set_local' => 0,
|
||||
'add' => 0,
|
||||
'delete' => 0,
|
||||
'delete_local' => 0,
|
||||
'slow-ops' => 0,
|
||||
);
|
||||
|
||||
global $memcached_servers;
|
||||
|
||||
if ( isset( $memcached_servers ) ) {
|
||||
$buckets = $memcached_servers;
|
||||
} else {
|
||||
$buckets = array( '127.0.0.1:11211' );
|
||||
}
|
||||
|
||||
reset( $buckets );
|
||||
|
||||
if ( is_int( key( $buckets ) ) ) {
|
||||
$buckets = array( 'default' => $buckets );
|
||||
}
|
||||
|
||||
foreach ( $buckets as $bucket => $servers ) {
|
||||
$this->mc[ $bucket ] = new Memcache();
|
||||
|
||||
foreach ( $servers as $i => $server ) {
|
||||
if ( 'unix://' == substr( $server, 0, 7 ) ) {
|
||||
$node = $server;
|
||||
$port = 0;
|
||||
} else {
|
||||
list ( $node, $port ) = explode( ':', $server );
|
||||
|
||||
if ( ! $port ) {
|
||||
$port = ini_get( 'memcache.default_port' );
|
||||
}
|
||||
|
||||
$port = intval( $port );
|
||||
|
||||
if ( ! $port ) {
|
||||
$port = 11211;
|
||||
}
|
||||
}
|
||||
|
||||
$this->mc[ $bucket ]->addServer( $node, $port, true, 1, 1, 15, true, array( $this, 'failure_callback' ) );
|
||||
$this->mc[ $bucket ]->setCompressThreshold( 20000, 0.2 );
|
||||
|
||||
// Prepare individual connections to servers in default bucket for flush_number redundancy
|
||||
if ( 'default' === $bucket ) {
|
||||
$this->default_mcs[ $i ] = new Memcache();
|
||||
$this->default_mcs[ $i ]->addServer( $node, $port, true, 1, 1, 15, true, array( $this, 'failure_callback' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global $blog_id, $table_prefix;
|
||||
|
||||
$this->global_prefix = '';
|
||||
$this->blog_prefix = '';
|
||||
|
||||
if ( function_exists( 'is_multisite' ) ) {
|
||||
$this->global_prefix = ( is_multisite() || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) ) ? '' : $table_prefix;
|
||||
$this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix );
|
||||
}
|
||||
|
||||
$this->salt_keys( WP_CACHE_KEY_SALT );
|
||||
|
||||
$this->cache_hits =& $this->stats['get'];
|
||||
$this->cache_misses =& $this->stats['add'];
|
||||
}
|
||||
|
||||
function increment_stat( $field, $num = 1 ) {
|
||||
if ( ! isset( $this->stats[ $field ] ) ) {
|
||||
$this->stats[ $field ] = $num;
|
||||
} else {
|
||||
$this->stats[ $field ] += $num;
|
||||
}
|
||||
}
|
||||
|
||||
function group_ops_stats( $op, $keys, $group, $size, $time, $comment = '' ) {
|
||||
$this->increment_stat( $op );
|
||||
|
||||
// we have no use of the local ops details for now
|
||||
if ( strpos( $op, '_local' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->size_total += $size;
|
||||
|
||||
$keys = $this->strip_memcached_keys( $keys );
|
||||
|
||||
if ( $time > $this->slow_op_microseconds && 'get_multi' !== $op ) {
|
||||
$this->increment_stat( 'slow-ops' );
|
||||
$backtrace = null;
|
||||
if ( function_exists( 'wp_debug_backtrace_summary' ) ) {
|
||||
$backtrace = wp_debug_backtrace_summary();
|
||||
}
|
||||
$this->group_ops['slow-ops'][] = array( $op, $keys, $size, $time, $comment, $group, $backtrace );
|
||||
}
|
||||
|
||||
$this->group_ops[ $group ][] = array( $op, $keys, $size, $time, $comment );
|
||||
}
|
||||
|
||||
/**
|
||||
* Key format: key_salt:flush_number:table_prefix:key_name
|
||||
*
|
||||
* We want to strip the `key_salt:flush_number` part to not leak the memcached keys.
|
||||
* If `key_salt` is set we strip `'key_salt:flush_number`, otherwise just strip the `flush_number` part.
|
||||
*/
|
||||
function strip_memcached_keys( $keys ) {
|
||||
if ( ! is_array( $keys ) ) {
|
||||
$keys = [ $keys ];
|
||||
}
|
||||
|
||||
foreach ( $keys as $key => $value ) {
|
||||
$offset = 0;
|
||||
if ( ! empty( $this->key_salt ) ) {
|
||||
$offset = strpos( $value, ':' ) + 1;
|
||||
}
|
||||
|
||||
$start = strpos( $value, ':', $offset );
|
||||
$keys[ $key ] = substr( $value, $start + 1 );
|
||||
}
|
||||
|
||||
if ( 1 === count( $keys ) ) {
|
||||
return $keys[0];
|
||||
}
|
||||
|
||||
return $keys;
|
||||
}
|
||||
|
||||
function timer_start() {
|
||||
$this->time_start = microtime( true );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function timer_stop() {
|
||||
$time_total = microtime( true ) - $this->time_start;
|
||||
$this->time_total += $time_total;
|
||||
|
||||
return $time_total;
|
||||
}
|
||||
|
||||
function get_data_size( $data ) {
|
||||
if ( is_string( $data ) ) {
|
||||
return strlen( $data );
|
||||
}
|
||||
|
||||
$serialized = serialize( $data );
|
||||
|
||||
return strlen( $serialized );
|
||||
}
|
||||
}
|
||||
@ -205,7 +205,7 @@ html {
|
||||
}
|
||||
.ds-hero__subtitle {
|
||||
font-size: 18px; line-height: 1.55;
|
||||
color: rgba(255,255,255,0.72); margin-bottom: 28px;
|
||||
color: var(--color-rating); margin-bottom: 28px;
|
||||
max-width: 500px;
|
||||
}
|
||||
/* Metrics — стиль «glass card» как на /otzyvy/ */
|
||||
@ -275,7 +275,7 @@ html {
|
||||
margin-top: 10px; font-size: 13px; color: rgba(255,255,255,0.55);
|
||||
}
|
||||
.ds-hero__phone a {
|
||||
color: var(--color-accent); font-weight: 500; text-decoration: underline;
|
||||
color: var(--color-rating); font-weight: 500; text-decoration: underline;
|
||||
white-space: nowrap;
|
||||
}
|
||||
/* ---- Visual ---- */
|
||||
|
||||
@ -112,6 +112,9 @@
|
||||
.page-pksh .section-header--left .bento-p {
|
||||
max-width: 65ch;
|
||||
}
|
||||
.page-pksh .section-header--left .geo-answer-text {
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
/* ── Section vertical rhythm ── */
|
||||
.page-pksh .pksh-section,
|
||||
@ -1718,6 +1721,34 @@
|
||||
.page-pksh .trust-authority__grid { grid-template-columns: 1fr; gap: 16px; }
|
||||
}
|
||||
|
||||
.page-pksh .trust-program-link {
|
||||
margin-top: 24px;
|
||||
padding: 16px 24px;
|
||||
background: var(--color-bg);
|
||||
border-radius: var(--pksh-radius-card, 24px);
|
||||
box-shadow: var(--shadow-sm);
|
||||
text-align: center;
|
||||
transition: box-shadow var(--transition-base, 300ms ease-out);
|
||||
}
|
||||
.page-pksh .trust-program-link:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
.page-pksh .trust-program-link a {
|
||||
color: var(--color-primary);
|
||||
font-weight: 600;
|
||||
font-size: 0.9375rem;
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 3px;
|
||||
}
|
||||
.page-pksh .trust-program-link a:hover {
|
||||
color: var(--color-primary-dark);
|
||||
text-decoration: none;
|
||||
}
|
||||
.page-pksh .trust-program-link a::after {
|
||||
content: ' ↗';
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
/* ── 3o. EXTERNAL REVIEWS ── */
|
||||
.page-pksh .external-reviews {
|
||||
max-width: 1000px;
|
||||
@ -2076,12 +2107,14 @@
|
||||
|
||||
.page-pksh .sticky-cta-desktop__badge {
|
||||
display: inline-block;
|
||||
padding: 4px 14px;
|
||||
background: var(--color-primary);
|
||||
color: var(--color-text-on-dark);
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: var(--color-primary);
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 700;
|
||||
border-radius: var(--radius-pill, 100px);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.page-pksh .sticky-cta-desktop__text {
|
||||
@ -2297,3 +2330,184 @@
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
html { scroll-behavior: smooth; }
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
GEO / AI-оптимизация — answer-блоки, автор, даты
|
||||
Matching the page's blue/navy bento-card design system
|
||||
============================================================ */
|
||||
|
||||
/* Определение для AI (hero) — стиль как bento-p hero, с акцентом */
|
||||
.page-pksh .ds-hero__definition {
|
||||
font-size: clamp(1.0625rem, 1.3vw, 1.125rem);
|
||||
line-height: 1.7;
|
||||
color: rgba(255,255,255,0.72);
|
||||
margin-top: 16px;
|
||||
margin-bottom: 12px;
|
||||
max-width: 65ch;
|
||||
text-wrap: pretty;
|
||||
font-weight: 450;
|
||||
}
|
||||
|
||||
/* Answer-блоки для AI-цитирования — карточка в стиле bento-секций */
|
||||
.page-pksh .geo-answer-block {
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
padding: clamp(20px, 2.5vw, 24px) clamp(20px, 2.5vw, 24px);
|
||||
background: var(--color-bg);
|
||||
border-radius: var(--radius-sm, 12px);
|
||||
border-left: 4px solid var(--color-primary);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
/* В тёмной секции результатов — прозрачный фон, тёплый акцент */
|
||||
.page-pksh .bento-card--highlight-results .geo-answer-block {
|
||||
background: color-mix(in oklab, var(--color-bg-dark), white 6%);
|
||||
border-left-color: var(--color-rating);
|
||||
box-shadow: none;
|
||||
padding: 20px 24px;
|
||||
border-radius: var(--radius-sm, 12px);
|
||||
text-align: center;
|
||||
}
|
||||
.page-pksh .bento-card--highlight-results .geo-answer-text {
|
||||
max-width: none;
|
||||
}
|
||||
.page-pksh .bento-card--highlight-results .geo-answer-text {
|
||||
color: var(--color-slate-300);
|
||||
margin: 0;
|
||||
}
|
||||
.page-pksh .bento-card--highlight-results .geo-answer-heading {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--color-rating);
|
||||
}
|
||||
|
||||
/* Answer-блок с изображением справа (только десктоп) */
|
||||
.page-pksh .geo-answer-block--with-img {
|
||||
display: flex;
|
||||
gap: 28px;
|
||||
align-items: stretch;
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.page-pksh .geo-answer-block__text {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.page-pksh .geo-answer-block__img-wrap {
|
||||
flex-shrink: 0;
|
||||
width: auto;
|
||||
aspect-ratio: 1 / 1;
|
||||
height: 100%;
|
||||
max-height: 220px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 3px solid var(--color-primary);
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.page-pksh .geo-answer-block__img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
.page-pksh .geo-answer-block--with-img {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
.page-pksh .geo-answer-block__img-wrap {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.page-pksh .geo-answer-text {
|
||||
font-size: clamp(1rem, 1.2vw, 1.0625rem);
|
||||
line-height: 1.7;
|
||||
color: var(--color-text-muted);
|
||||
margin: 0;
|
||||
max-width: none;
|
||||
text-wrap: pretty;
|
||||
}
|
||||
|
||||
/* Question-based H3 headings — иерархия: H1 hero → H2 bento → H3 bento */
|
||||
.page-pksh .bento-h3 {
|
||||
font-size: clamp(1.125rem, 1.5vw, 1.375rem);
|
||||
font-weight: 700;
|
||||
line-height: 1.35;
|
||||
color: var(--color-text);
|
||||
margin-top: 24px;
|
||||
margin-bottom: 12px;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* Question-heading with accent mark */
|
||||
.page-pksh .geo-answer-heading {
|
||||
font-size: clamp(1.0625rem, 1.3vw, 1.25rem);
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
color: var(--color-primary);
|
||||
margin-top: 20px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* Автор и даты (E-E-A-T) — подвал страницы, компактный */
|
||||
.page-pksh .pksh-section--author {
|
||||
padding: 12px clamp(16px, 3vw, 32px) 32px;
|
||||
}
|
||||
|
||||
.page-pksh .author-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 24px;
|
||||
padding: 16px 0 8px;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-light);
|
||||
border-top: 1px solid var(--color-border);
|
||||
}
|
||||
|
||||
.page-pksh .author-info__block {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.page-pksh .author-info__label {
|
||||
font-weight: 600;
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.page-pksh .author-info__name {
|
||||
font-weight: 600;
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.page-pksh .author-info__title {
|
||||
color: var(--color-text-muted);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.page-pksh .author-info__date {
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 639px) {
|
||||
.page-pksh .ds-hero__definition {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.page-pksh .geo-answer-block {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.page-pksh .author-info {
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
288
wp-content/themes/dekart/assets/css/program-pksh.css
Normal file
288
wp-content/themes/dekart/assets/css/program-pksh.css
Normal file
@ -0,0 +1,288 @@
|
||||
/* ═══════════════════════════════════════════════════════════
|
||||
program-pksh.css — служебная страница программы
|
||||
═══════════════════════════════════════════════════════════ */
|
||||
|
||||
/* ── Container ── */
|
||||
.page-program-pksh .prog-container {
|
||||
max-width: 880px;
|
||||
margin: 0 auto;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
/* ── Section rhythm ── */
|
||||
.page-program-pksh .prog-section {
|
||||
padding: 48px 0;
|
||||
}
|
||||
.page-program-pksh .prog-section--muted {
|
||||
background: var(--color-bg-alt, #F1F5F9);
|
||||
}
|
||||
.page-program-pksh .prog-section--accent {
|
||||
background: var(--color-bg-dark, #0F172A);
|
||||
}
|
||||
.page-program-pksh .prog-section--disclaimer {
|
||||
background: rgba(245, 158, 11, 0.06);
|
||||
border-top: 3px solid var(--color-rating, #F59E0B);
|
||||
border-bottom: 3px solid var(--color-rating, #F59E0B);
|
||||
}
|
||||
|
||||
/* ── Intro ── */
|
||||
.page-program-pksh .prog-intro {
|
||||
padding: 48px 0 24px;
|
||||
}
|
||||
|
||||
.page-program-pksh .prog-label {
|
||||
display: inline-block;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--color-primary, #2563EB);
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.page-program-pksh .prog-title {
|
||||
font-size: clamp(1.5rem, 2.5vw, 2.125rem);
|
||||
font-weight: 800;
|
||||
line-height: 1.2;
|
||||
color: var(--color-text, #0F172A);
|
||||
margin: 0 0 20px;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.page-program-pksh .prog-desc {
|
||||
font-size: 1rem;
|
||||
line-height: 1.7;
|
||||
color: var(--color-text-muted, #475569);
|
||||
margin: 0;
|
||||
max-width: 75ch;
|
||||
}
|
||||
|
||||
/* ── Section title ── */
|
||||
.page-program-pksh .prog-section-title {
|
||||
font-size: clamp(1.25rem, 1.8vw, 1.5rem);
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
color: var(--color-text, #0F172A);
|
||||
margin: 0 0 20px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 2px solid var(--color-border, #E2E8F0);
|
||||
}
|
||||
.page-program-pksh .prog-section-title--light {
|
||||
color: var(--color-text-on-dark, #FFFFFF);
|
||||
border-bottom-color: rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
/* ── Body text ── */
|
||||
.page-program-pksh .prog-text {
|
||||
font-size: 1rem;
|
||||
line-height: 1.7;
|
||||
color: var(--color-text-muted, #475569);
|
||||
margin: 0 0 16px;
|
||||
max-width: 75ch;
|
||||
}
|
||||
.page-program-pksh .prog-text--light {
|
||||
color: rgba(255,255,255,0.75);
|
||||
}
|
||||
|
||||
/* ── Program content (WYSIWYG) ── */
|
||||
.page-program-pksh .prog-content {
|
||||
font-size: 0.938rem;
|
||||
line-height: 1.75;
|
||||
color: var(--color-text, #0F172A);
|
||||
max-width: 85ch;
|
||||
}
|
||||
|
||||
.page-program-pksh .prog-content h2,
|
||||
.page-program-pksh .prog-content h3,
|
||||
.page-program-pksh .prog-content h4 {
|
||||
font-weight: 700;
|
||||
color: var(--color-text, #0F172A);
|
||||
margin-top: 32px;
|
||||
margin-bottom: 12px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.page-program-pksh .prog-content h2 {
|
||||
font-size: 1.25rem;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--color-border, #E2E8F0);
|
||||
}
|
||||
.page-program-pksh .prog-content h3 {
|
||||
font-size: 1.0625rem;
|
||||
}
|
||||
.page-program-pksh .prog-content h4 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.page-program-pksh .prog-content p {
|
||||
margin: 0 0 12px;
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.page-program-pksh .prog-content ul,
|
||||
.page-program-pksh .prog-content ol {
|
||||
margin: 0 0 12px;
|
||||
padding-left: 24px;
|
||||
}
|
||||
.page-program-pksh .prog-content li {
|
||||
margin-bottom: 4px;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
.page-program-pksh .prog-content table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.page-program-pksh .prog-content th,
|
||||
.page-program-pksh .prog-content td {
|
||||
border: 1px solid var(--color-border, #E2E8F0);
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
.page-program-pksh .prog-content th {
|
||||
background: var(--color-bg-alt, #F1F5F9);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* ── Office info block ── */
|
||||
.page-program-pksh .prog-office__details {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 24px 40px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
.page-program-pksh .prog-office__item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
.page-program-pksh .prog-office__label {
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 600;
|
||||
color: var(--color-text-muted, #475569);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
.page-program-pksh .prog-office__value {
|
||||
font-size: 1.0625rem;
|
||||
color: var(--color-text, #0F172A);
|
||||
}
|
||||
|
||||
/* ── CTA block ── */
|
||||
.page-program-pksh .prog-cta {
|
||||
text-align: center;
|
||||
padding: 8px 0;
|
||||
}
|
||||
.page-program-pksh .prog-cta .prog-text {
|
||||
margin: 0 auto 24px;
|
||||
max-width: 65ch;
|
||||
}
|
||||
.page-program-pksh .prog-cta__btn {
|
||||
display: inline-block;
|
||||
padding: 16px 40px;
|
||||
font-size: 1.0625rem;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-on-dark, #FFFFFF);
|
||||
background: var(--pksh-gradient-btn, linear-gradient(135deg, #2563EB, #1D4ED8));
|
||||
border-radius: var(--radius-pill, 100px);
|
||||
text-decoration: none;
|
||||
transition: transform 200ms ease-out, box-shadow 200ms ease-out;
|
||||
}
|
||||
.page-program-pksh .prog-cta__btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 28px rgba(37, 99, 235, 0.35);
|
||||
}
|
||||
.page-program-pksh .prog-cta__btn:focus-visible {
|
||||
outline: 3px solid var(--color-primary, #2563EB);
|
||||
outline-offset: 3px;
|
||||
}
|
||||
|
||||
/* ── E-E-A-T links ── */
|
||||
.page-program-pksh .prog-eeat {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.page-program-pksh .prog-eeat a {
|
||||
color: var(--color-primary, #2563EB);
|
||||
font-weight: 600;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* ── Disclaimer ── */
|
||||
.page-program-pksh .prog-disclaimer {
|
||||
padding: 8px 0;
|
||||
}
|
||||
.page-program-pksh .prog-disclaimer__text {
|
||||
font-size: 0.9375rem;
|
||||
line-height: 1.65;
|
||||
color: var(--color-text, #0F172A);
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
.page-program-pksh .prog-disclaimer__note {
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-muted, #475569);
|
||||
margin: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* ── Responsive ── */
|
||||
@media (max-width: 639px) {
|
||||
.page-program-pksh .prog-section {
|
||||
padding: 32px 0;
|
||||
}
|
||||
.page-program-pksh .prog-intro {
|
||||
padding: 32px 0 16px;
|
||||
}
|
||||
.page-program-pksh .prog-office__details {
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
.page-program-pksh .prog-content table {
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
.page-program-pksh .prog-content th,
|
||||
.page-program-pksh .prog-content td {
|
||||
padding: 6px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── Author block (E-E-A-T) ── */
|
||||
.page-program-pksh .prog-author {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px 24px;
|
||||
padding: 16px 0;
|
||||
font-size: 0.875rem;
|
||||
color: var(--color-text-light, #64748B);
|
||||
border-top: 1px solid var(--color-border, #E2E8F0);
|
||||
border-bottom: 1px solid var(--color-border, #E2E8F0);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.page-program-pksh .prog-author__block {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
}
|
||||
.page-program-pksh .prog-author__label {
|
||||
font-weight: 600;
|
||||
color: var(--color-text-muted, #475569);
|
||||
}
|
||||
.page-program-pksh .prog-author__name {
|
||||
font-weight: 600;
|
||||
color: var(--color-text, #0F172A);
|
||||
}
|
||||
.page-program-pksh .prog-author__title {
|
||||
color: var(--color-text-muted, #475569);
|
||||
font-style: italic;
|
||||
}
|
||||
.page-program-pksh .prog-author__date {
|
||||
color: var(--color-text, #0F172A);
|
||||
}
|
||||
|
||||
@media (max-width: 639px) {
|
||||
.page-program-pksh .prog-author {
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,18 @@ 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';
|
||||
|
||||
/**
|
||||
* Замена названия сайта из Настроек филиала.
|
||||
* blogname (Внешний вид → Настроить → Свойства сайта) берётся из branch_name.
|
||||
*/
|
||||
add_filter( 'pre_option_blogname', function( $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 --- */
|
||||
@ -558,10 +570,18 @@ function add_carbon() {
|
||||
Field::make( 'text', 'banner_subtitle_footnote_link', 'Ссылка для звёздочки (*) в подзаголовке' )
|
||||
->set_width( 50 )
|
||||
->set_help_text( 'URL для иконки * после текста подзаголовка. Если не указано — * неактивна.' ),
|
||||
Field::make( 'text', 'banner_scarcity', 'Текст дефицита (срочность)' )
|
||||
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', '' )
|
||||
@ -576,9 +596,20 @@ function add_carbon() {
|
||||
Field::make( 'text', 'counter_label', 'Подпись' )
|
||||
->set_width( 70 )
|
||||
->set_help_text( 'Например: выпускников в топ-школах' ),
|
||||
)),
|
||||
))
|
||||
->add_tab('⭐ Отзывы', array(
|
||||
)),
|
||||
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', 'Отзывы' )
|
||||
@ -803,6 +834,60 @@ function add_carbon() {
|
||||
)),
|
||||
))
|
||||
// ====================================================
|
||||
// Вкладка: 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(
|
||||
@ -821,6 +906,50 @@ function add_carbon() {
|
||||
)),
|
||||
));
|
||||
|
||||
// ====================================================
|
||||
// Контейнер: Программа Подготовки к школе (служебная страница)
|
||||
// ====================================================
|
||||
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( 'Текст кнопки/ссылки для перехода на услугу.' ),
|
||||
));
|
||||
|
||||
// ====================================================
|
||||
// Уникальное имя контейнера Продлёнки
|
||||
// ====================================================
|
||||
@ -1983,6 +2112,7 @@ function dekart_branch_register_settings() {
|
||||
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' ) );
|
||||
@ -2544,6 +2674,24 @@ function dekart_ajax_flush_cache() {
|
||||
$summary = array( 'type' => 'fail', 'text' => "Выполнено с {$errors} ошибкой(ами). Проверьте лог выше." );
|
||||
}
|
||||
|
||||
/**
|
||||
* Noindex для служебной страницы программы.
|
||||
* Юридический документ не должен индексироваться,
|
||||
* чтобы не размывать SEO-вес коммерческих страниц.
|
||||
*/
|
||||
/**
|
||||
* Noindex для служебной страницы программы.
|
||||
*/
|
||||
add_filter( 'wpseo_robots', function( $robots ) {
|
||||
$post_id = get_the_ID();
|
||||
if ( $post_id && 'program-pksh' === get_post_field( 'post_name', $post_id ) ) {
|
||||
return 'noindex, follow';
|
||||
}
|
||||
return $robots;
|
||||
}, 999 );
|
||||
|
||||
|
||||
|
||||
wp_send_json_success( array(
|
||||
'log' => $log,
|
||||
'summary' => $summary,
|
||||
|
||||
@ -48,12 +48,9 @@ class Pksh_Data {
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// BRANCH / OPTION DATA (get_option → theme_option → post_meta)
|
||||
// BRANCH / OPTION DATA (get_option -> theme_option -> post_meta)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Адрес филиала
|
||||
*/
|
||||
public function get_address(): string {
|
||||
$cache_key = 'dekart_branch_address';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -70,9 +67,6 @@ class Pksh_Data {
|
||||
return $this->branch['address'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Координаты филиала (для карты)
|
||||
*/
|
||||
public function get_coords(): string {
|
||||
$cache_key = 'dekart_branch_coords';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -88,9 +82,6 @@ class Pksh_Data {
|
||||
return $this->branch['coords'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Телефон филиала
|
||||
*/
|
||||
public function get_phone(): string {
|
||||
$cache_key = 'dekart_branch_phone';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -107,9 +98,6 @@ class Pksh_Data {
|
||||
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() );
|
||||
@ -117,9 +105,6 @@ class Pksh_Data {
|
||||
return $this->branch['phone_clean'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Email филиала
|
||||
*/
|
||||
public function get_email(): string {
|
||||
$cache_key = 'dekart_branch_email';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -136,9 +121,6 @@ class Pksh_Data {
|
||||
return $this->branch['email'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Название филиала / организации
|
||||
*/
|
||||
public function get_name(): string {
|
||||
$cache_key = 'dekart_branch_name';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -154,9 +136,6 @@ class Pksh_Data {
|
||||
return $this->branch['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Город с предлогом (например "в Щёлково")
|
||||
*/
|
||||
public function get_city_prep(): string {
|
||||
$cache_key = 'dekart_branch_city_prep';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -170,20 +149,12 @@ class Pksh_Data {
|
||||
return $this->branch['city_prep'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Город без предлога (например "Щёлково")
|
||||
*/
|
||||
/**
|
||||
* Город в родительном падеже (школы Щёлкова)
|
||||
* Берёт из branch_city_genitive, fallback: city_clean с -о→-а
|
||||
*/
|
||||
public function get_city_genitive(): string {
|
||||
$genitive = get_option( 'branch_city_genitive', '' );
|
||||
if ( ! empty( $genitive ) ) {
|
||||
return $genitive;
|
||||
}
|
||||
$clean = $this->get_city_clean();
|
||||
// Для русских городов на -ово/-ево/-ино: замена -о → -а
|
||||
if ( str_ends_with( $clean, 'ово' ) || str_ends_with( $clean, 'ево' ) || str_ends_with( $clean, 'ино' ) || str_ends_with( $clean, 'ыно' ) ) {
|
||||
return mb_substr( $clean, 0, -1 ) . 'а';
|
||||
}
|
||||
@ -197,9 +168,6 @@ class Pksh_Data {
|
||||
return $this->branch['city_clean'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Количество отзывов на внешних площадках
|
||||
*/
|
||||
public function get_ext_review_count(): string {
|
||||
$cache_key = 'dekart_branch_ext_review_count';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -213,9 +181,6 @@ class Pksh_Data {
|
||||
return $this->branch['ext_review_count'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Социальные сети (из branch_social option или CF)
|
||||
*/
|
||||
public function get_social_links(): array {
|
||||
$cache_key = 'dekart_branch_social';
|
||||
$cached = wp_cache_get( $cache_key, 'dekart_branch' );
|
||||
@ -228,13 +193,10 @@ class Pksh_Data {
|
||||
[];
|
||||
$this->branch['social'] = is_array( $raw ) ? $raw : [];
|
||||
}
|
||||
wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECONDS );
|
||||
return $this->branch['social'];
|
||||
wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECONDS );
|
||||
return $this->branch['social'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Логистика — пешком от ТЦ (branch_logistics_walk)
|
||||
*/
|
||||
public function get_logistics_walk(): string {
|
||||
if ( ! array_key_exists( 'logistics_walk', $this->branch ) ) {
|
||||
$this->branch['logistics_walk'] = get_option( 'branch_logistics_walk', '5 минут пешком от ТЦ «Глобус»' );
|
||||
@ -242,9 +204,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
return $this->branch['logistics_walk'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Логистика — парковка (branch_logistics_parking)
|
||||
*/
|
||||
public function get_logistics_parking(): string {
|
||||
if ( ! array_key_exists( 'logistics_parking', $this->branch ) ) {
|
||||
$this->branch['logistics_parking'] = get_option( 'branch_logistics_parking', 'Есть бесплатная парковка у входа' );
|
||||
@ -252,9 +211,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
return $this->branch['logistics_parking'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Логистика — соседние школы/сад (branch_logistics_schools)
|
||||
*/
|
||||
public function get_logistics_nearby(): string {
|
||||
if ( ! array_key_exists( 'logistics_nearby', $this->branch ) ) {
|
||||
$this->branch['logistics_nearby'] = get_option( 'branch_logistics_schools', 'Рядом со школами №9 и №12, детским садом №15' );
|
||||
@ -262,13 +218,62 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
return $this->branch['logistics_nearby'];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// AUTHOR / DATES (E-E-A-T / GEO)
|
||||
// ============================================================
|
||||
|
||||
public function get_author_name(): string {
|
||||
if ( ! array_key_exists( 'author_name', $this->page ) ) {
|
||||
$this->page['author_name'] = carbon_get_post_meta( $this->post_id, 'pksh_author_name' )
|
||||
?: get_option( 'branch_og_site_name' )
|
||||
?: get_option( 'branch_name' )
|
||||
?: carbon_get_theme_option( 'site_name' )
|
||||
?: 'Детский центр «Декарт»';
|
||||
}
|
||||
return $this->page['author_name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Количество лет на рынке (из года основания).
|
||||
* Автоматически: текущий год − год основания.
|
||||
* Источник: CF schema_founded → Settings API branch_founded.
|
||||
* Если год основания не задан — 0.
|
||||
*/
|
||||
public function get_years_on_market(): int {
|
||||
if ( ! array_key_exists( 'years_market', $this->page ) ) {
|
||||
$founded = carbon_get_theme_option( 'schema_founded' );
|
||||
if ( empty( $founded ) ) {
|
||||
$founded = get_option( 'branch_founded' );
|
||||
}
|
||||
if ( ! empty( $founded ) && is_string( $founded ) && is_numeric( $founded ) ) {
|
||||
$this->page['years_market'] = (int) date( 'Y' ) - (int) $founded;
|
||||
} else {
|
||||
$this->page['years_market'] = 0;
|
||||
}
|
||||
}
|
||||
return $this->page['years_market'];
|
||||
}
|
||||
|
||||
public function get_page_publish_date(): string {
|
||||
if ( ! array_key_exists( 'publish_date', $this->page ) ) {
|
||||
$post = get_post( $this->post_id );
|
||||
$this->page['publish_date'] = $post ? get_the_date( 'c', $post ) : '';
|
||||
}
|
||||
return $this->page['publish_date'];
|
||||
}
|
||||
|
||||
public function get_page_modified_date(): string {
|
||||
if ( ! array_key_exists( 'modified_date', $this->page ) ) {
|
||||
$post = get_post( $this->post_id );
|
||||
$this->page['modified_date'] = $post ? get_the_modified_date( 'c', $post ) : '';
|
||||
}
|
||||
return $this->page['modified_date'];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 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' );
|
||||
@ -276,20 +281,13 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
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' ) ?:
|
||||
'Подготовка к школе в Щёлково';
|
||||
$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' ) ?:
|
||||
@ -298,9 +296,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
return $this->page['subtitle'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ссылка для * в подзаголовке hero
|
||||
*/
|
||||
public function get_subtitle_footnote_link(): string {
|
||||
if ( ! array_key_exists( 'subtitle_footnote_link', $this->page ) ) {
|
||||
$this->page['subtitle_footnote_link'] = carbon_get_post_meta( $this->post_id, 'banner_subtitle_footnote_link' ) ?: '';
|
||||
@ -308,14 +303,21 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
return $this->page['subtitle_footnote_link'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Определение для AI-цитирования (GEO, первые 60 слов).
|
||||
* Заполняется в админке: вкладка "🖼️ Герой" -> поле "Определение для AI".
|
||||
*/
|
||||
public function get_hero_definition(): string {
|
||||
if ( ! array_key_exists( 'hero_definition', $this->page ) ) {
|
||||
$this->page['hero_definition'] = carbon_get_post_meta( $this->post_id, 'pksh_hero_definition' ) ?: '';
|
||||
}
|
||||
return $this->page['hero_definition'];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 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' );
|
||||
@ -324,9 +326,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
return $this->social;
|
||||
}
|
||||
|
||||
/**
|
||||
* Иконки для social counters (порядок соответствует полю)
|
||||
*/
|
||||
public static function social_icons(): array {
|
||||
return array( 'icon-graduation', 'icon-calendar', 'icon-star-filled', 'icon-teacher' );
|
||||
}
|
||||
@ -335,52 +334,86 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
// PROGRAMS
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Данные базовой программы
|
||||
* @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, price_razov: 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 ₽',
|
||||
'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 места в группе',
|
||||
);
|
||||
$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 ₽',
|
||||
'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 места в группе',
|
||||
);
|
||||
}
|
||||
return $this->programs['base'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Данные премиум-программы
|
||||
* @return array{name: string, subname: string, schedule: string, price_sub: string, price_single: string, price_razov: 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 ₽',
|
||||
'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 места в группе',
|
||||
);
|
||||
$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 ₽',
|
||||
'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 места в группе',
|
||||
);
|
||||
}
|
||||
return $this->programs['prem'];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// GEO ANSWER BLOCKS (self-contained, 134-167 слов)
|
||||
// ============================================================
|
||||
|
||||
public function get_geo_answer_programs(): string {
|
||||
if ( ! array_key_exists( 'geo_answer_programs', $this->page ) ) {
|
||||
$this->page['geo_answer_programs'] = carbon_get_post_meta( $this->post_id, 'pksh_geo_answer_programs' ) ?: '';
|
||||
}
|
||||
return $this->page['geo_answer_programs'];
|
||||
}
|
||||
|
||||
public function get_geo_answer_results(): string {
|
||||
if ( ! array_key_exists( 'geo_answer_results', $this->page ) ) {
|
||||
$this->page['geo_answer_results'] = carbon_get_post_meta( $this->post_id, 'pksh_geo_answer_results' ) ?: '';
|
||||
}
|
||||
return $this->page['geo_answer_results'];
|
||||
}
|
||||
|
||||
public function get_geo_answer_howitworks(): string {
|
||||
if ( ! array_key_exists( 'geo_answer_howitworks', $this->page ) ) {
|
||||
$this->page['geo_answer_howitworks'] = carbon_get_post_meta( $this->post_id, 'pksh_geo_answer_howitworks' ) ?: '';
|
||||
}
|
||||
return $this->page['geo_answer_howitworks'];
|
||||
}
|
||||
|
||||
public function get_geo_question_1(): string {
|
||||
if ( ! array_key_exists( 'geo_q1', $this->page ) ) {
|
||||
$this->page['geo_q1'] = carbon_get_post_meta( $this->post_id, 'pksh_geo_q1' ) ?: '';
|
||||
}
|
||||
return $this->page['geo_q1'];
|
||||
}
|
||||
|
||||
public function get_geo_question_2(): string {
|
||||
if ( ! array_key_exists( 'geo_q2', $this->page ) ) {
|
||||
$this->page['geo_q2'] = carbon_get_post_meta( $this->post_id, 'pksh_geo_q2' ) ?: '';
|
||||
}
|
||||
return $this->page['geo_q2'];
|
||||
}
|
||||
|
||||
public function get_geo_question_3(): string {
|
||||
if ( ! array_key_exists( 'geo_q3', $this->page ) ) {
|
||||
$this->page['geo_q3'] = carbon_get_post_meta( $this->post_id, 'pksh_geo_q3' ) ?: '';
|
||||
}
|
||||
return $this->page['geo_q3'];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 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' );
|
||||
@ -389,9 +422,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
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' ) ?: '';
|
||||
@ -403,10 +433,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
// 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' );
|
||||
@ -419,10 +445,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
// 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' );
|
||||
@ -435,10 +457,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
// 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' );
|
||||
@ -451,10 +469,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
// GALLERY (complex)
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Массив фотографий (complex field pksh_gallery)
|
||||
* @return array[]
|
||||
*/
|
||||
public function get_gallery(): array {
|
||||
if ( null === $this->gallery ) {
|
||||
$raw = carbon_get_post_meta( $this->post_id, 'pksh_gallery' );
|
||||
@ -464,12 +478,9 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// HONEST TIMER (shared helper)
|
||||
// HONEST TIMER
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Timestamp честного дедлайна
|
||||
*/
|
||||
public function get_honest_deadline(): int {
|
||||
if ( ! array_key_exists( 'deadline', $this->page ) ) {
|
||||
$this->page['deadline'] = function_exists( 'dekart_get_honest_deadline' )
|
||||
@ -479,12 +490,6 @@ wp_cache_set( $cache_key, $this->branch['social'], 'dekart_branch', DAY_IN_SECON
|
||||
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 ) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -44,6 +44,7 @@ get_header();
|
||||
get_template_part( 'template-parts/pksh/external-reviews' );
|
||||
get_template_part( 'template-parts/pksh/final-cta' );
|
||||
get_template_part( 'template-parts/pksh/contacts' );
|
||||
get_template_part( 'template-parts/author-eaat' );
|
||||
get_template_part( 'template-parts/pksh/sticky-cta' );
|
||||
?>
|
||||
|
||||
|
||||
61
wp-content/themes/dekart/page-program-pksh.php
Normal file
61
wp-content/themes/dekart/page-program-pksh.php
Normal file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
/**
|
||||
* Template Name: Программа — Подготовка к школе (служебная)
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Подключаем CSS напрямую в head (надёжнее ранних хуков)
|
||||
add_action( 'wp_head', function() {
|
||||
$css_url = get_template_directory_uri() . '/assets/css/program-pksh.css';
|
||||
$css_path = get_template_directory() . '/assets/css/program-pksh.css';
|
||||
if ( file_exists( $css_path ) ) {
|
||||
echo '<link rel="stylesheet" id="dekart-program-pksh-css" href="' . esc_url( $css_url . '?ver=' . filemtime( $css_path ) ) . '" media="all">' . "\n";
|
||||
}
|
||||
// Schema.org Article для программы
|
||||
$org_name = get_option( 'branch_og_site_name' ) ?: get_option( 'branch_name', 'Детский центр «Декарт»' );
|
||||
$post_id = get_the_ID();
|
||||
?>
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
"@context": "https://schema.org",
|
||||
"@type": "Article",
|
||||
"headline": "Дополнительная общеразвивающая программа «Подготовка к школе»",
|
||||
"description": "Официальная образовательная программа подготовки к школе для детей 5–7 лет. Разработана в соответствии с ФЗ №273, Приказом Минпросвещения №629 и ФГОС ДО.",
|
||||
"author": {
|
||||
"@type": "Organization",
|
||||
"name": "<?php echo esc_js( $org_name ); ?>"
|
||||
},
|
||||
"publisher": {
|
||||
"@type": "Organization",
|
||||
"name": "<?php echo esc_js( $org_name ); ?>"
|
||||
},
|
||||
"datePublished": "<?php echo esc_js( get_the_date( 'c' ) ?: '' ); ?>",
|
||||
"dateModified": "<?php echo esc_js( get_the_modified_date( 'c' ) ?: '' ); ?>"
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
}, 0 );
|
||||
|
||||
get_header();
|
||||
?>
|
||||
|
||||
<main class="page page-program-pksh">
|
||||
|
||||
<?php
|
||||
get_template_part( 'template-parts/program-pksh/header' );
|
||||
get_template_part( 'template-parts/program-pksh/program-content' );
|
||||
get_template_part( 'template-parts/program-pksh/office-info' );
|
||||
get_template_part( 'template-parts/program-pksh/service-link' );
|
||||
get_template_part( 'template-parts/program-pksh/eeat-links' );
|
||||
get_template_part( 'template-parts/author-eaat' );
|
||||
get_template_part( 'template-parts/program-pksh/disclaimer' );
|
||||
?>
|
||||
|
||||
</main>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
67
wp-content/themes/dekart/template-parts/author-eaat.php
Normal file
67
wp-content/themes/dekart/template-parts/author-eaat.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* E-E-A-T автор и даты — универсальный шаблон.
|
||||
*
|
||||
* Автор: поле на странице → OG: Site Name → «Частная школа Декарт».
|
||||
* Годы на рынке: из branch_founded.
|
||||
* Даты: из WordPress (публикация/обновление).
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$post_id = get_the_ID();
|
||||
|
||||
// Автор: CF на странице → OG: Site Name → fallback
|
||||
$author_name = carbon_get_post_meta( $post_id, 'pksh_author_name' )
|
||||
?: get_option( 'branch_og_site_name', 'Частная школа Декарт' );
|
||||
|
||||
// Годы на рынке
|
||||
$founded = get_option( 'branch_founded', '' );
|
||||
$years = $founded ? (int) date( 'Y' ) - (int) $founded : 0;
|
||||
|
||||
$author_title = 'Образовательный центр с гослицензией';
|
||||
if ( $years > 0 ) {
|
||||
$author_title .= ', ' . $years . ' лет на рынке';
|
||||
}
|
||||
|
||||
// Даты
|
||||
$publish_date = $post_id ? get_the_date( 'c', $post_id ) : '';
|
||||
$modified_date = $post_id ? get_the_modified_date( 'c', $post_id ) : '';
|
||||
$publish_fmt = $publish_date ? date_i18n( 'j F Y', strtotime( $publish_date ) ) : '';
|
||||
$modified_fmt = $modified_date ? date_i18n( 'j F Y', strtotime( $modified_date ) ) : '';
|
||||
|
||||
if ( empty( $author_name ) && empty( $publish_fmt ) && empty( $modified_fmt ) && $years < 1 ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<section class="bento pksh-section pksh-section--author" aria-label="Информация об авторе">
|
||||
<div class="bento__full">
|
||||
<div class="author-info">
|
||||
<?php if ( ! empty( $author_name ) ) : ?>
|
||||
<div class="author-info__block">
|
||||
<span class="author-info__label">Автор:</span>
|
||||
<span class="author-info__name"><?php echo esc_html( $author_name ); ?></span>
|
||||
<?php if ( ! empty( $author_title ) ) : ?>
|
||||
<span class="author-info__title">, <?php echo esc_html( $author_title ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $publish_fmt ) ) : ?>
|
||||
<div class="author-info__block">
|
||||
<span class="author-info__label">Опубликовано:</span>
|
||||
<time class="author-info__date" datetime="<?php echo esc_attr( $publish_date ); ?>"><?php echo esc_html( $publish_fmt ); ?></time>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $modified_fmt ) && $modified_fmt !== $publish_fmt ) : ?>
|
||||
<div class="author-info__block">
|
||||
<span class="author-info__label">Обновлено:</span>
|
||||
<time class="author-info__date" datetime="<?php echo esc_attr( $modified_date ); ?>"><?php echo esc_html( $modified_fmt ); ?></time>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
63
wp-content/themes/dekart/template-parts/pksh/author-info.php
Normal file
63
wp-content/themes/dekart/template-parts/pksh/author-info.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
/**
|
||||
* Информация об авторе и датах публикации (E-E-A-T / GEO)
|
||||
* Выводится после внешних отзывов, перед финальным CTA.
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = Pksh_Data::instance();
|
||||
$author_name = $data->get_author_name();
|
||||
$publish_date = $data->get_page_publish_date();
|
||||
$modified_date = $data->get_page_modified_date();
|
||||
|
||||
$author_years = $data->get_years_on_market();
|
||||
|
||||
// Должность автора — хардкор + авто-расчёт лет на рынке
|
||||
$author_title = 'Образовательный центр с гослицензией';
|
||||
if ( $author_years > 0 ) {
|
||||
$author_title .= ', ' . $author_years . ' лет на рынке';
|
||||
}
|
||||
|
||||
// Форматируем даты для отображения
|
||||
$publish_formatted = $publish_date ? date_i18n( 'j F Y', strtotime( $publish_date ) ) : '';
|
||||
$modified_formatted = $modified_date ? date_i18n( 'j F Y', strtotime( $modified_date ) ) : '';
|
||||
|
||||
// Если нет автора и нет дат — не выводим секцию
|
||||
if ( empty( $author_name ) && empty( $publish_formatted ) && empty( $modified_formatted ) && $author_years < 1 ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<section class="bento pksh-section pksh-section--author" aria-label="Информация об авторе">
|
||||
<div class="bento__full">
|
||||
<div class="author-info">
|
||||
<?php if ( ! empty( $author_name ) ) : ?>
|
||||
<div class="author-info__block">
|
||||
<span class="author-info__label">Автор:</span>
|
||||
<span class="author-info__name"><?php echo esc_html( $author_name ); ?></span>
|
||||
<?php if ( ! empty( $author_title ) ) : ?>
|
||||
<span class="author-info__title">, <?php echo esc_html( $author_title ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $publish_formatted ) ) : ?>
|
||||
<div class="author-info__block">
|
||||
<span class="author-info__label">Опубликовано:</span>
|
||||
<time class="author-info__date" datetime="<?php echo esc_attr( $publish_date ); ?>"><?php echo esc_html( $publish_formatted ); ?></time>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( ! empty( $modified_formatted ) && $modified_formatted !== $publish_formatted ) : ?>
|
||||
<div class="author-info__block">
|
||||
<span class="author-info__label">Обновлено:</span>
|
||||
<time class="author-info__date" datetime="<?php echo esc_attr( $modified_date ); ?>"><?php echo esc_html( $modified_formatted ); ?></time>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,7 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Отзывы на внешних площадках (Яндекс, 2ГИС, ВК, Otzovik)
|
||||
* .bento .pksh-section
|
||||
* Отзывы на внешних площадках.
|
||||
* Карточки выводятся только если ссылка на площадку заполнена в настройках.
|
||||
* Если ни одна ссылка не заполнена — секция не выводится.
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
@ -12,32 +13,55 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
||||
$data = Pksh_Data::instance();
|
||||
$city_prep = $data->get_city_prep();
|
||||
|
||||
$platforms = array(
|
||||
'yandex' => array(
|
||||
'url' => get_option( 'branch_ext_yandex', '' ),
|
||||
'icon' => 'Я',
|
||||
'name' => 'Яндекс.Карты',
|
||||
'rating' => '4.8',
|
||||
),
|
||||
'2gis' => array(
|
||||
'url' => get_option( 'branch_ext_2gis', '' ),
|
||||
'icon' => '2ГИС',
|
||||
'name' => '2ГИС',
|
||||
'rating' => '4.7',
|
||||
),
|
||||
'vk' => array(
|
||||
'url' => get_option( 'branch_ext_vk', '' ),
|
||||
'icon' => 'ВК',
|
||||
'name' => 'ВКонтакте',
|
||||
'rating' => '4.9',
|
||||
),
|
||||
'otzovik' => array(
|
||||
'url' => get_option( 'branch_ext_otzovik', '' ),
|
||||
'icon' => 'O',
|
||||
'name' => 'Otzovik',
|
||||
'rating' => '4.6',
|
||||
),
|
||||
);
|
||||
|
||||
// Фильтруем: только площадки с заполненной ссылкой
|
||||
$active = array_filter( $platforms, function( $p ) {
|
||||
return ! empty( $p['url'] );
|
||||
} );
|
||||
|
||||
if ( empty( $active ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<section class="bento pksh-section" aria-label="Отзывы на внешних площадках">
|
||||
<div class="bento__full section-header--left">
|
||||
<div class="external-reviews">
|
||||
<h2 class="bento-h2">Нас рекомендуют на площадках — отзывы о подготовке к школе <?php echo esc_html( $city_prep ); ?></h2>
|
||||
<div class="external-reviews__grid">
|
||||
<a href="https://yandex.ru/maps/org/detskiy_tsentr_dekart/155905693075/" target="_blank" rel="noopener noreferrer" class="external-reviews__card">
|
||||
<span class="external-reviews__icon">Я</span>
|
||||
<span class="external-reviews__name">Яндекс.Карты</span>
|
||||
<span class="external-reviews__rating">⭐ 4.8</span>
|
||||
</a>
|
||||
<a href="https://2gis.ru/schelkovo/firm/155905693075" target="_blank" rel="noopener noreferrer" class="external-reviews__card">
|
||||
<span class="external-reviews__icon">2ГИС</span>
|
||||
<span class="external-reviews__name">2ГИС</span>
|
||||
<span class="external-reviews__rating">⭐ 4.7</span>
|
||||
</a>
|
||||
<a href="https://vk.com/dekart_school" target="_blank" rel="noopener noreferrer" class="external-reviews__card">
|
||||
<span class="external-reviews__icon">ВК</span>
|
||||
<span class="external-reviews__name">ВКонтакте</span>
|
||||
<span class="external-reviews__rating">⭐ 4.9</span>
|
||||
</a>
|
||||
<a href="https://otzovik.com/reviews/detskiy_centr_dekart/" target="_blank" rel="noopener noreferrer" class="external-reviews__card">
|
||||
<span class="external-reviews__icon">O</span>
|
||||
<span class="external-reviews__name">Otzovik</span>
|
||||
<span class="external-reviews__rating">⭐ 4.6</span>
|
||||
<?php foreach ( $active as $p ) : ?>
|
||||
<a href="<?php echo esc_url( $p['url'] ); ?>" target="_blank" rel="noopener noreferrer" class="external-reviews__card">
|
||||
<span class="external-reviews__icon"><?php echo esc_html( $p['icon'] ); ?></span>
|
||||
<span class="external-reviews__name"><?php echo esc_html( $p['name'] ); ?></span>
|
||||
<span class="external-reviews__rating">⭐ <?php echo esc_html( $p['rating'] ); ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -22,6 +22,7 @@ $opt_phone = $data->get_phone();
|
||||
$hero_phone_clean = $data->get_phone_clean();
|
||||
$banner_img_id = $data->get_banner_image_id();
|
||||
$hero_metrics = $data->get_social_counters();
|
||||
$hero_definition = $data->get_hero_definition();
|
||||
?>
|
||||
|
||||
<section class="section-bg ds-hero" data-bg="hero" id="ds-hero" aria-label="Подготовка к школе">
|
||||
@ -30,12 +31,18 @@ $hero_metrics = $data->get_social_counters();
|
||||
|
||||
<div class="ds-hero__content">
|
||||
|
||||
<?php if ( ! empty( $opt_address ) || ! empty( $branch_city_clean ) ) : ?>
|
||||
<div class="ds-hero__address">
|
||||
<svg aria-hidden="true" width="16" height="16"><use href="#icon-location-pin"/></svg>
|
||||
<span><?php echo esc_html( $opt_address ?: 'ул. Талсинская, 24' ); ?> — центр <?php echo esc_html( $branch_city_clean ?: 'Щёлково' ); ?></span>
|
||||
<span><?php echo esc_html( $opt_address ?: '' ); ?><?php if ( $opt_address && $branch_city_clean ) : ?> — центр <?php endif; ?><?php echo esc_html( $branch_city_clean ?: '' ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h1 class="ds-hero__h1"><?php echo esc_html( $h1_hero ?: 'Подготовка к школе в Щёлково' ); ?></h1>
|
||||
<h1 class="ds-hero__h1"><?php echo esc_html( $h1_hero ?: 'Подготовка к школе' ); ?></h1>
|
||||
|
||||
<?php if ( '' !== $hero_definition ) : ?>
|
||||
<p class="ds-hero__definition"><?php echo esc_html( $hero_definition ); ?></p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( '' !== $subtitle_hero ) :
|
||||
$footnote_url = $data->get_subtitle_footnote_link();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Как проходят занятия + почему родители выбирают нас
|
||||
* Как проходят занятия + почему родители выбирают нас + answer-блок AI
|
||||
* .bento .pksh-section #how-it-works
|
||||
*
|
||||
* @package Dekart
|
||||
@ -9,6 +9,13 @@
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = Pksh_Data::instance();
|
||||
$city_clean = $data->get_city_clean();
|
||||
$city_prep = $data->get_city_prep();
|
||||
$answer = $data->get_geo_answer_howitworks();
|
||||
$q3 = $data->get_geo_question_3();
|
||||
$hero_img_id = $data->get_banner_image_id();
|
||||
?>
|
||||
<section class="bento pksh-section" id="how-it-works" aria-label="Как проходят занятия">
|
||||
<div class="bento__full section-header--left">
|
||||
@ -79,10 +86,36 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
</div>
|
||||
<div>
|
||||
<strong>Дорого?</strong>
|
||||
<p>От <?php echo esc_html( Pksh_Data::instance()->get_premium_program()['price_single'] ); ?> за занятие. Первое — бесплатно.</p>
|
||||
<p>От <?php echo esc_html( $data->get_premium_program()['price_single'] ); ?> за занятие. Первое — бесплатно.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( '' !== $q3 ) : ?>
|
||||
<div class="bento__full">
|
||||
<h3 class="bento-h3 geo-answer-heading"><?php echo esc_html( $q3 ); ?></h3>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( '' !== $answer ) : ?>
|
||||
<div class="bento__full">
|
||||
<div class="geo-answer-block geo-answer-block--with-img">
|
||||
<?php if ( $hero_img_id ) : ?>
|
||||
<div class="geo-answer-block__img-wrap">
|
||||
<?php echo wp_get_attachment_image( $hero_img_id, 'medium', false, array(
|
||||
'class' => 'geo-answer-block__img',
|
||||
'loading' => 'lazy',
|
||||
'decoding' => 'async',
|
||||
'alt' => 'Подготовка к школе — занятия для детей 5–7 лет',
|
||||
) ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="geo-answer-block__text">
|
||||
<p class="bento-p geo-answer-text"><?php echo wp_kses_post( $answer ); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Программы подготовки (базовая + премиум)
|
||||
* Программы подготовки (базовая + премиум) + answer-блок AI
|
||||
* .bento .pksh-section #programs
|
||||
*
|
||||
* @package Dekart
|
||||
@ -10,10 +10,12 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = Pksh_Data::instance();
|
||||
$data = Pksh_Data::instance();
|
||||
$city_clean = $data->get_city_clean();
|
||||
$base = $data->get_base_program();
|
||||
$prem = $data->get_premium_program();
|
||||
$base = $data->get_base_program();
|
||||
$prem = $data->get_premium_program();
|
||||
$answer = $data->get_geo_answer_programs();
|
||||
$q1 = $data->get_geo_question_1();
|
||||
?>
|
||||
<section class="bento pksh-section" id="programs" aria-label="Программы подготовки">
|
||||
<div class="bento__full section-header--left">
|
||||
@ -21,6 +23,16 @@ $prem = $data->get_premium_program();
|
||||
<h2 class="bento-h2">Выберите формат подготовки</h2>
|
||||
<p class="bento-p">Все программы ведут действующие педагоги начальных классов. Группы до 10 человек — каждому ребёнку уделяем внимание.</p>
|
||||
|
||||
<?php if ( '' !== $q1 ) : ?>
|
||||
<h3 class="bento-h3 geo-answer-heading"><?php echo esc_html( $q1 ); ?></h3>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( '' !== $answer ) : ?>
|
||||
<div class="geo-answer-block">
|
||||
<p class="bento-p geo-answer-text"><?php echo wp_kses_post( $answer ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="pksh-swipe-hint" aria-hidden="true">
|
||||
<span class="pksh-swipe-hint__arrow">👇</span>
|
||||
<span class="pksh-swipe-hint__text">Листайте, чтобы сравнить программы</span>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Результаты учеников
|
||||
* Результаты учеников + answer-блок для AI-цитирования
|
||||
* .bento .pksh-section #results .bento-card--highlight-results
|
||||
*
|
||||
* @package Dekart
|
||||
@ -10,8 +10,10 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$data = Pksh_Data::instance();
|
||||
$city_gen = $data->get_city_genitive();
|
||||
$data = Pksh_Data::instance();
|
||||
$city_gen = $data->get_city_genitive();
|
||||
$answer = $data->get_geo_answer_results();
|
||||
$q2 = $data->get_geo_question_2();
|
||||
?>
|
||||
<section class="bento pksh-section" id="results" aria-label="Результаты учеников">
|
||||
<div class="bento__full bento-card bento-card--highlight-results section-header--centered">
|
||||
@ -36,5 +38,15 @@ $city_gen = $data->get_city_genitive();
|
||||
<span class="result-item__desc">быстрее адаптируются в первом классе</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if ( '' !== $q2 ) : ?>
|
||||
<h3 class="bento-h3 geo-answer-heading"><?php echo esc_html( $q2 ); ?></h3>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( '' !== $answer ) : ?>
|
||||
<div class="geo-answer-block">
|
||||
<p class="bento-p geo-answer-text"><?php echo wp_kses_post( $answer ); ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -34,6 +34,11 @@ $city_gen = $data->get_city_genitive();
|
||||
<p class="trust-authority__text">Если через 3 месяца ребёнок не начнёт читать — вернём деньги и продолжим обучение бесплатно.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="trust-program-link">
|
||||
<a href="/program-pksh/" target="_blank" rel="noopener noreferrer">
|
||||
Официальная образовательная программа «Подготовка к школе»
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* Юридический дисклеймер
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$disclaimer_text = carbon_get_post_meta( get_the_ID(), 'pksh_prog_disclaimer' );
|
||||
$doc_date = carbon_get_post_meta( get_the_ID(), 'pksh_prog_doc_date' );
|
||||
?>
|
||||
<section class="prog-section prog-section--disclaimer">
|
||||
<div class="prog-container">
|
||||
<div class="prog-disclaimer">
|
||||
<p class="prog-disclaimer__text">
|
||||
<?php echo esc_html( $disclaimer_text ?: 'Электронная версия программы предназначена для ознакомления.' ); ?>
|
||||
<?php if ( $doc_date ) : ?>
|
||||
<strong><?php echo esc_html( $doc_date ); ?></strong>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<p class="prog-disclaimer__note">
|
||||
Если вы заметили ошибку в тексте программы, пожалуйста, сообщите нам — мы оперативно внесём исправления.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
/**
|
||||
* E-E-A-T сигналы: ссылка на сведения об организации
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$org_name = get_option( 'branch_og_site_name' ) ?: get_option( 'branch_name', 'Детский центр «Декарт»' );
|
||||
?>
|
||||
<section class="prog-section prog-section--muted">
|
||||
<div class="prog-container">
|
||||
<div class="prog-eeat">
|
||||
<p class="prog-text">
|
||||
<strong><?php echo esc_html( $org_name ); ?></strong> —
|
||||
образовательная организация, осуществляющая образовательную деятельность на основании
|
||||
государственной лицензии.
|
||||
Полные сведения об организации доступны в разделе
|
||||
<a href="/svedeniya-ob-obrazovatelnoj-organizaczii/">«Сведения об образовательной организации»</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
/**
|
||||
* Intro-секция страницы программы
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
?>
|
||||
<section class="prog-intro">
|
||||
<div class="prog-container">
|
||||
<p class="prog-label">Официальный документ</p>
|
||||
<h1 class="prog-title">Дополнительная общеразвивающая программа<br>«Подготовка к школе»</h1>
|
||||
<p class="prog-desc">
|
||||
Настоящая программа разработана в соответствии с Федеральным законом от 29.12.2012 № 273-ФЗ
|
||||
«Об образовании в Российской Федерации» и определяет содержание образовательной деятельности
|
||||
по подготовке детей старшего дошкольного возраста (5–7 лет) к обучению в школе.
|
||||
Программа является официальным документом Детского центра «Декарт».
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* Блок ознакомления с программой в офисе
|
||||
* Данные из Настроек филиала (Settings API) — единый источник.
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$address = get_option( 'branch_address', '' );
|
||||
$city = get_option( 'branch_city', '' );
|
||||
$phone = get_option( 'branch_phone', '' );
|
||||
$hours = get_option( 'branch_hours', '' );
|
||||
$name = get_option( 'branch_og_site_name' ) ?: get_option( 'branch_name', 'Детский центр «Декарт»' );
|
||||
|
||||
if ( empty( $address ) && empty( $phone ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<section class="prog-section prog-section--muted">
|
||||
<div class="prog-container">
|
||||
<div class="prog-office">
|
||||
<h2 class="prog-section-title">Ознакомиться с программой в офисе</h2>
|
||||
<p class="prog-text">Действующая образовательная программа находится в офисе <?php echo esc_html( $name ); ?> и всегда доступна для ознакомления.</p>
|
||||
<div class="prog-office__details">
|
||||
<?php if ( ! empty( $address ) ) : ?>
|
||||
<div class="prog-office__item">
|
||||
<span class="prog-office__label">Адрес:</span>
|
||||
<span class="prog-office__value"><?php echo esc_html( $address . ( $city ? ', ' . $city : '' ) ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $phone ) ) : ?>
|
||||
<div class="prog-office__item">
|
||||
<span class="prog-office__label">Телефон:</span>
|
||||
<span class="prog-office__value"><a href="tel:+<?php echo preg_replace( '/[^0-9]/', '', $phone ); ?>"><?php echo esc_html( $phone ); ?></a></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $hours ) ) : ?>
|
||||
<div class="prog-office__item">
|
||||
<span class="prog-office__label">Часы приёма:</span>
|
||||
<span class="prog-office__value"><?php echo esc_html( $hours ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
/**
|
||||
* Основной текст программы — дословно из CF
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$content = carbon_get_post_meta( get_the_ID(), 'pksh_prog_content' );
|
||||
if ( empty( $content ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<section class="prog-section">
|
||||
<div class="prog-container">
|
||||
<h2 class="prog-section-title">Текст программы</h2>
|
||||
<div class="prog-content">
|
||||
<?php echo wp_kses_post( wpautop( $content ) ); ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
/**
|
||||
* Ссылка на услугу — страница /podgotovka-k-shkole/
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$url = carbon_get_post_meta( get_the_ID(), 'pksh_prog_service_url' );
|
||||
$label = carbon_get_post_meta( get_the_ID(), 'pksh_prog_service_label' );
|
||||
|
||||
if ( empty( $url ) ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<section class="prog-section prog-section--accent">
|
||||
<div class="prog-container">
|
||||
<div class="prog-cta">
|
||||
<h2 class="prog-section-title prog-section-title--light">Записаться на занятия</h2>
|
||||
<p class="prog-text prog-text--light">Данная программа реализуется в рамках курса подготовки к школе. Запишите ребёнка на бесплатное пробное занятие и познакомьтесь с педагогами.</p>
|
||||
<a href="<?php echo esc_url( $url ); ?>" class="prog-cta__btn">
|
||||
<?php echo esc_html( $label ?: 'Записаться на подготовку к школе' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
Loading…
Reference in New Issue
Block a user