Global 2026-07-18 ПКШ + программа

This commit is contained in:
Dekart Deploy Bot 2026-07-18 16:05:15 +00:00
parent 9ed786b881
commit 8f91d6e177
24 changed files with 2596 additions and 812 deletions

View File

@ -1,34 +1,18 @@
# Декарт — частная школа в Щёлково
> Частная школа полного дня в Щёлково, Московская область. Программы начальной школы (14 класс), средней школы (59 класс), подготовка к ЕГЭ и ОГЭ (1011 класс). Индивидуальный подход, классы до 12 человек, продлённый день, подготовка к школе.
# Детский центр «Декарт» — Подготовка к школе в Щёлково
> Образовательный центр в Щёлково с гослицензией. Работаем с 2014 года. Готовим детей 57 лет к школе: чтение, письмо, математика, логика.
## Основные страницы
- [Отзывы родителей и учеников](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/): Комплексные занятия для детей 57 лет. Чтение, письмо, счёт, логика. Первое занятие — бесплатно.
- [Начальная школа](https://xn--80atdlj0d.xn--p1ai/nachalnaya-shkola/): Программы 14 классов. УМК «Перспектива», система Занкова, Cambridge English.
- [О нас](https://xn--80atdlj0d.xn--p1ai/o-nas/): Лицензия, документы, педагоги.
- [Отзывы](https://xn--80atdlj0d.xn--p1ai/otzyvy/): Отзывы родителей и выпускников.
- [Контакты](https://xn--80atdlj0d.xn--p1ai/contacts/): Адрес, телефон, карта.
## О школе
- Частная школа «Декарт» основана в 2010 году
- Расположена по адресу: ул. Талсинская, 24, Щёлково, Московская область
- Режим работы: пн–пт 8:0019:00, сб 9:0014:00
- Классы: до 12 человек
- Наполняемость: более 500 выпускников
- Педагоги: 50+ квалифицированных специалистов
## Что предлагает школа
- Начальное общее образование (14 класс) с углублённым английским
- Основное общее образование (59 класс) с предпрофильной подготовкой
- Среднее общее образование (1011 класс) с подготовкой к ЕГЭ
- Подготовка к школе для детей 56 лет
- Группа продлённого дня с 8:00 до 19:00
- Летний городской лагерь
- Кружки: робототехника, шахматы, английский театр, изостудия
<!--
TODO: уточнить актуальные URL страниц программ на проде
TODO: добавить страницу «Поступление» после её создания
-->
## Ключевые факты
- Адрес: Талсинская ул., 24, Щёлково, Московская область
- Телефон: +7 (926) 931-14-34
- Лицензия: государственная образовательная лицензия
- Основан: 2014 год
- Педагоги: высшее педагогическое образование, стаж от 12 лет
- Группы: до 10 человек
- Формат: очные занятия

View 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 );
}
}

View File

@ -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 ---- */

View File

@ -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;
}
}

View 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;
}
}

View File

@ -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> в группе 56 лет. Стартуем <strong>1 июня</strong>' )
->set_help_text( 'Можно использовать HTML-теги: &lt;strong&gt;, &lt;br&gt;. Текст о срочности/дефиците мест под кнопкой.' ),
Field::make( 'textarea', 'pksh_hero_definition', 'Определение для AI (первые 60 слов)' )
->set_rows( 3 )
->set_help_text(
'📖 <strong>Для AI-поиска (GEO).</strong> Текст, который AI использует для ответа на «Что такое подготовка к школе в [городе]?». '
. 'Рекомендуется <strong>4060 слов</strong>, начинается с «Подготовка к школе в [городе] — это…». '
. 'Выводится на странице после H1, перед подзаголовком. Если не заполнено — блок скрыт.'
)
->set_default_value( 'Подготовка к школе в Щёлково — это комплексные занятия для детей 57 лет, которые помогают освоить чтение, письмо, счёт и развить логическое мышление. Программа построена на игровой методике: ребёнок учится без стресса, в комфортном темпе. Группы до 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>самодостаточным (134167 слов)</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>134167 слов</strong>, самодостаточный, с конкретными данными. AI может процитировать его целиком. Рекомендуется: факты, цифры, сроки, цены. Если поле пусто — блок не выводится.</p>' ),
Field::make( 'textarea', 'pksh_geo_answer_programs', 'Answer-блок: Программы и цены' )
->set_rows( 8 )
->set_help_text(
'Выводится в секции <strong>Программы</strong> перед карточками. '
. 'Рекомендуется 134167 слов. Опишите программы, цены, разницу между базовой и расширенной.'
)
->set_default_value(
'В детском центре «Декарт» в Щёлково действуют две программы подготовки к школе. Базовая программа «Уверенный старт» включает 2 занятия в неделю по 3040 минут — стоимость абонемента 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>. '
. 'Рекомендуется 134167 слов. Конкретные цифры, проценты, сроки.'
)
->set_default_value(
'95% выпускников центра «Декарт» поступают в школы и лицеи Щёлкова без стресса — они готовы к учебной нагрузке и требованиям учителей. Первые результаты заметны уже через 3 недели: нечитавшие дети складывают первый осмысленный слог. 87% родителей отмечают рост самостоятельности ребёнка после месяца занятий. Выпускники центра адаптируются в первом классе в 2,5 раза быстрее сверстников — они не боятся отвечать у доски, поднимать руку и работать в коллективе. За 12 лет работы центром подготовлено более 500 детей. Программа построена так, что каждый ребёнок осваивает чтение, письмо, счёт и логику без перегрузки — занятия длятся 3040 минут, каждые 7 минут смена активности.'
),
Field::make( 'textarea', 'pksh_geo_answer_howitworks', 'Answer-блок: Как проходят занятия' )
->set_rows( 8 )
->set_help_text(
'Выводится в секции <strong>Как проходят занятия</strong>. '
. 'Рекомендуется 134167 слов. Опишите методику, длительность, структуру.'
)
->set_default_value(
'Каждое занятие длится 3040 минут и построено так, чтобы ребёнок не уставал. Активность меняется каждые 7 минут — это оптимальный интервал удержания внимания для детей 57 лет. Урок начинается с короткой истории или загадки, которая вводит в тему и включает интерес. Затем следует игровое задание: чтение через игру, счёт через механику соревнования, логика через головоломки. После каждого блока — активная перемена с нейрогимнастикой. Завершается занятие рефлексией: ребёнок сам рассказывает, чему научился. Все педагоги имеют высшее педагогическое образование и опыт работы с дошкольниками от 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,

View File

@ -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:0019: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:0019: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:3018: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:3018: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

View File

@ -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' );
?>

View 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": "Официальная образовательная программа подготовки к школе для детей 57 лет. Разработана в соответствии с ФЗ №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(); ?>

View 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>

View 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>

View File

@ -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>

View File

@ -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();

View File

@ -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' => 'Подготовка к школе — занятия для детей 57 лет',
) ); ?>
</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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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-ФЗ
«Об образовании в Российской Федерации» и определяет содержание образовательной деятельности
по подготовке детей старшего дошкольного возраста (57 лет) к обучению в школе.
Программа является официальным документом Детского центра «Декарт».
</p>
</div>
</section>

View File

@ -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>

View File

@ -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>

View File

@ -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>