Test commit from debug
This commit is contained in:
parent
c7bd6cef74
commit
80f259cbee
10
.gitignore
vendored
10
.gitignore
vendored
@ -118,3 +118,13 @@ yandex_*.html
|
||||
# !/wp-content/plugins/мой-кастомный-плагин/**
|
||||
.ssh_key_for_web
|
||||
.ssh_key_for_web.pub
|
||||
opencode.json
|
||||
AGENTS.md
|
||||
.opencode/
|
||||
wp-content/backups-dup-lite/
|
||||
wp-content/upgrade-temp-backup/
|
||||
|
||||
# === Agent/Test files — dev-мусор (не в git) ===
|
||||
data/
|
||||
llms.txt
|
||||
test.php
|
||||
|
||||
45
AGENTS.md
45
AGENTS.md
@ -1,29 +1,24 @@
|
||||
# Глобальные инструкции проекта
|
||||
# Site1 — WordPress project
|
||||
|
||||
## Язык общения
|
||||
- ВСЕГДА отвечай на русском языке.
|
||||
- Код, комментарии, коммиты, техническая документация — на английском (стандарт).
|
||||
- Объяснения, архитектурные решения, анализ, рекомендации — на русском.
|
||||
- Если пользователь пишет на другом языке — отвечай на том же языке.
|
||||
## Primary agent
|
||||
- @site1 — dedicated WordPress agent (auto-activated, see `.opencode/AGENTS.md`)
|
||||
|
||||
## Оптимизация DeepSeek v4 Flash
|
||||
- Модель: `opencode/deepseek-v4-flash-free`
|
||||
- DeepSeek v4 Flash оптимизирован для быстрых инференсов с большим контекстом.
|
||||
- Для сложных задач используй декомпозицию: разбивай на подзадачи, выполняй последовательно.
|
||||
- Для работы с файлами: предпочитай пакетные операции (множественные чтения/записи) вместо последовательных вызовов.
|
||||
- Для поиска по коду: используй glob/grep с точными паттернами, избегай избыточного сканирования.
|
||||
- При работе с большими проектами — используй подзадачи (Task/Explore) для параллельного исследования.
|
||||
- tool_output лимиты увеличены для работы с большими результатами (max_lines: 300, max_bytes: 10240).
|
||||
- compaction включён, tail_turns: 20 — удержание контекста в длинных сессиях.
|
||||
- MCP таймаут: 60s (для работы с медленными внешними сервисами).
|
||||
## Quick rules
|
||||
- PHP: PSR-12, type declarations, Composer
|
||||
- JS: TypeScript strict, ESM, async/await
|
||||
- Commits: conventional commits (`feat:`, `fix:`, `chore:`, etc.)
|
||||
|
||||
## Профиль разработчика
|
||||
- WP-Architect — WordPress full-stack architect.
|
||||
- Специализация: теминг, SEO, производительность, маркетинг.
|
||||
- Доступно >80 скиллов: SEO/AEO, CRO, UI/UX, CI/CD, аналитика, безопасность.
|
||||
## Security
|
||||
- NEVER modify wp-config.php without explicit confirmation
|
||||
- NEVER delete files in uploads/ or wp-content/ without confirmation
|
||||
- ALWAYS ask before destructive actions (rm, overwrite, DB write, git push)
|
||||
|
||||
## Принципы работы
|
||||
- Используй скиллы при каждой возможности (даже 1% совпадения).
|
||||
- Caveman-режим активируется пользователем (/caveman).
|
||||
- Коммиты и PR — на нормальном английском.
|
||||
- Сообщай о проблемах безопасности сразу, без caveman.
|
||||
## Commands
|
||||
- PHP test: `vendor/bin/phpunit`
|
||||
- PHP lint: `vendor/bin/phpstan analyse`
|
||||
- JS build: `npm run build`
|
||||
- JS test: `npm test`
|
||||
- JS lint: `npm run lint`
|
||||
|
||||
## All details
|
||||
See `.opencode/AGENTS.md` for full architecture, skills, agents list, and directory structure.
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
{
|
||||
"$schema": "https://opencode.ai/config.json",
|
||||
"model": "opencode/deepseek-v4-flash-free",
|
||||
|
||||
"instructions": ["AGENTS.md"],
|
||||
|
||||
"default_agent": "wp-architect",
|
||||
|
||||
"plugin": [
|
||||
"file:///home/letoline/.config/opencode/plugins/caveman/plugin.js",
|
||||
"file:///home/letoline/.config/opencode/plugins/claude-mem.js",
|
||||
"@zenobius/opencode-skillful"
|
||||
],
|
||||
|
||||
"command": {
|
||||
"wp-audit": { "template": "short" },
|
||||
"wp-seo": { "template": "short" },
|
||||
"wp-content": { "template": "short" },
|
||||
"wp-speed": { "template": "short" },
|
||||
"design-persona": { "template": "short" },
|
||||
"design-research": { "template": "short" },
|
||||
"critique": { "template": "short" },
|
||||
"gsd": { "template": "short" },
|
||||
"caveman": { "template": "short" },
|
||||
"caveman-commit": { "template": "short" },
|
||||
"caveman-review": { "template": "short" },
|
||||
"design-screen": { "template": "short" },
|
||||
"design-system": { "template": "short" },
|
||||
"ux-audit": { "template": "short" },
|
||||
"prototype": { "template": "short" },
|
||||
"school": { "template": "short" }
|
||||
}
|
||||
}
|
||||
0
wp-content/mu-plugins/acf-loader.php
Executable file → Normal file
0
wp-content/mu-plugins/acf-loader.php
Executable file → Normal file
56
wp-content/themes/dekart/assets/css/front-page.css
Normal file
56
wp-content/themes/dekart/assets/css/front-page.css
Normal file
@ -0,0 +1,56 @@
|
||||
/* ═══════════════════════════════════════════════════
|
||||
front-page.css — стили для шаблона front-page.php
|
||||
Извлечены из inline style="..." для соответствия
|
||||
стандартам и оптимизации скорости загрузки
|
||||
═══════════════════════════════════════════════════ */
|
||||
|
||||
/* ---- Блок "Наши услуги" (блоки-карточки) ---- */
|
||||
.advantages__block-item {
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
}
|
||||
.advantages__block-item--school { border-color: #A05A95; }
|
||||
.advantages__block-item--preschool { border-color: #F682A5; }
|
||||
.advantages__block-item--afterschool { border-color: #FEDF6F; }
|
||||
.advantages__block-item--exam { border-color: #F9A474; }
|
||||
.advantages__block-item--camp { border-color: #C9DA8F; }
|
||||
.advantages__block-item--clubs { border-color: #B8CEDC; }
|
||||
|
||||
/* ---- Информационный блок ---- */
|
||||
.info__block--compact {
|
||||
padding-bottom: 0;
|
||||
margin-top: 40px;
|
||||
}
|
||||
.info__block-content_text--full {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* ---- CTA-блок (бесплатная экскурсия) ---- */
|
||||
.cta-block {
|
||||
background: linear-gradient(90deg, #fdf6ff 0%, #f5e8f5 100%);
|
||||
padding: 60px 0;
|
||||
border-top: 2px solid #A05A95;
|
||||
border-bottom: 2px solid #A05A95;
|
||||
margin: 40px 0;
|
||||
text-align: center;
|
||||
}
|
||||
.cta-wrapper {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cta-wrapper .page_h2 {
|
||||
margin-bottom: 20px;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.cta-wrapper p {
|
||||
font-size: 1.2rem;
|
||||
color: #444;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.cta-wrapper .btn-page {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
padding: 18px 45px;
|
||||
font-size: 1.3rem;
|
||||
box-shadow: 0 4px 15px rgba(160, 90, 149, .3);
|
||||
}
|
||||
@ -4490,11 +4490,12 @@ footer a:hover,
|
||||
.btn-close-resume-form,
|
||||
.btn-close-request-form {
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
background: #fff0;
|
||||
border: none;
|
||||
z-index: 10;
|
||||
z-index: 99999;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.btn-close-resume-form img,
|
||||
@ -7001,7 +7002,8 @@ footer a:hover,
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 101.25vw;
|
||||
max-width: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.footer-wrapper {
|
||||
@ -9623,3 +9625,653 @@ footer a:hover,
|
||||
}
|
||||
|
||||
/* end mobile= */
|
||||
|
||||
/* ═══════════════════════════════════════════════════
|
||||
🎯 REDESIGN 2026 — Bento Grid + Mobile-First CRO
|
||||
═══════════════════════════════════════════════════ */
|
||||
|
||||
/* ── 1. Новая цветовая палитра ── */
|
||||
:root {
|
||||
--accent: #7C3AED;
|
||||
--accent-hover: #6D28D9;
|
||||
--accent-light: #F5F3FF;
|
||||
--accent-50: #F5F3FF;
|
||||
--accent-100: #EDE9FE;
|
||||
--accent-200: #DDD6FE;
|
||||
--accent-500: #8B5CF6;
|
||||
--accent-700: #5B21B6;
|
||||
|
||||
--green-cta: #059669;
|
||||
--green-hover: #047857;
|
||||
--green-light: #D1FAE5;
|
||||
|
||||
--bg-primary: #FFFFFF;
|
||||
--bg-soft: #F8FAFC;
|
||||
--bg-card: #FFFFFF;
|
||||
--bg-bento-alt: #F1F5F9;
|
||||
|
||||
--text-primary: #0F172A;
|
||||
--text-secondary: #475569;
|
||||
--text-tertiary: #94A3B8;
|
||||
|
||||
--shadow-sm: 0 1px 3px rgba(0,0,0,0.06);
|
||||
--shadow-md: 0 4px 12px rgba(0,0,0,0.08);
|
||||
--shadow-lg: 0 10px 30px rgba(0,0,0,0.1);
|
||||
--shadow-xl: 0 20px 50px rgba(0,0,0,0.15);
|
||||
|
||||
--radius-sm: 8px;
|
||||
--radius-md: 12px;
|
||||
--radius-lg: 16px;
|
||||
--radius-xl: 20px;
|
||||
--radius-pill: 28px;
|
||||
}
|
||||
|
||||
/* ── 2. Bento Grid System ── */
|
||||
.bento {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.bento {
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.bento {
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
gap: 20px;
|
||||
padding: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.bento__hero { grid-column: 1 / -1; grid-row: auto; }
|
||||
.bento__stat { grid-column: 1 / -1; }
|
||||
.bento__half { grid-column: 1 / -1; }
|
||||
.bento__third { grid-column: 1 / -1; }
|
||||
.bento__full { grid-column: 1 / -1; }
|
||||
.bento__wide { grid-column: 1 / -1; }
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.bento__hero { grid-column: span 4; grid-row: span 2; }
|
||||
.bento__stat { grid-column: span 2; }
|
||||
.bento__half { grid-column: span 3; }
|
||||
.bento__third { grid-column: span 2; }
|
||||
.bento__wide { grid-column: span 4; }
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.bento__hero { grid-column: span 6; grid-row: span 2; }
|
||||
.bento__stat { grid-column: span 3; }
|
||||
.bento__half { grid-column: span 6; }
|
||||
.bento__third { grid-column: span 4; }
|
||||
.bento__wide { grid-column: span 8; }
|
||||
}
|
||||
|
||||
.bento-card {
|
||||
background: var(--bg-card);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 24px;
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: box-shadow .2s, transform .2s;
|
||||
}
|
||||
|
||||
.bento-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.bento-card--highlight {
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.bento-card--soft {
|
||||
background: var(--bg-soft);
|
||||
}
|
||||
|
||||
.bento-card--green {
|
||||
background: var(--green-light);
|
||||
}
|
||||
|
||||
/* ── 3. Social Counters ── */
|
||||
.social-counters {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.social-counters {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
.social-counter {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 10px 16px;
|
||||
background: var(--bg-soft);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
flex: 1;
|
||||
min-width: 140px;
|
||||
}
|
||||
|
||||
.social-counter__icon {
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.social-counter__number {
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
font-size: 18px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.social-counter__label {
|
||||
color: var(--text-tertiary);
|
||||
font-size: 12px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
/* ── 4. Sticky CTA Mobile ── */
|
||||
.sticky-cta-mobile {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
padding: 8px 16px max(12px, env(safe-area-inset-bottom));
|
||||
background: linear-gradient(to top, rgba(255,255,255,0.98) 60%, transparent);
|
||||
pointer-events: none;
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
@media (max-width: 639px) {
|
||||
.sticky-cta-mobile {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.sticky-cta-btn {
|
||||
pointer-events: auto;
|
||||
width: 100%;
|
||||
height: 56px;
|
||||
border: none;
|
||||
border-radius: var(--radius-pill);
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-500));
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
cursor: pointer;
|
||||
box-shadow: var(--shadow-lg);
|
||||
transition: transform .15s, box-shadow .15s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.sticky-cta-btn:active {
|
||||
transform: scale(0.97);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
/* ── 5. Guarantee Block ── */
|
||||
.guarantee-block {
|
||||
background: linear-gradient(135deg, var(--accent-light), #FEF3C7);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: 32px 24px;
|
||||
text-align: center;
|
||||
border: 2px solid var(--accent-200);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.guarantee-block::before {
|
||||
content: '🛡️';
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
font-size: 80px;
|
||||
opacity: 0.15;
|
||||
transform: rotate(15deg);
|
||||
}
|
||||
|
||||
.guarantee-block__text {
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
color: var(--text-secondary);
|
||||
max-width: 560px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.guarantee-block__badge {
|
||||
display: inline-block;
|
||||
margin-top: 16px;
|
||||
padding: 6px 20px;
|
||||
background: var(--accent);
|
||||
color: white;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.guarantee-block {
|
||||
padding: 40px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 6. Hero Risk Reversal Badge ── */
|
||||
.hero-risk-reversal {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 4px 14px;
|
||||
background: var(--green-light);
|
||||
color: #065F46;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* ── 7. Transformation Case ── */
|
||||
.transformation-case {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
padding: 24px;
|
||||
background: var(--bg-soft);
|
||||
border-radius: var(--radius-xl);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.transformation-case {
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.transformation-step {
|
||||
text-align: center;
|
||||
padding: 16px;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.transformation-step--before {
|
||||
background: #FEF2F2;
|
||||
border-left: 4px solid #EF4444;
|
||||
}
|
||||
|
||||
.transformation-step--process {
|
||||
background: var(--accent-light);
|
||||
}
|
||||
|
||||
.transformation-step--after {
|
||||
background: var(--green-light);
|
||||
border-right: 4px solid var(--green-cta);
|
||||
}
|
||||
|
||||
.transformation-step__label {
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--text-tertiary);
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.transformation-step__title {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.transformation-step__desc {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.transformation-arrow {
|
||||
display: none;
|
||||
font-size: 28px;
|
||||
color: var(--accent);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.transformation-arrow {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 8. Outcome Card ── */
|
||||
.outcome-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
padding: 32px 24px;
|
||||
background: linear-gradient(135deg, #EEF2FF, #F5F3FF);
|
||||
border-radius: var(--radius-xl);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.outcome-card {
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 40px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.outcome-card__metrics {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.outcome-metric {
|
||||
flex: 1;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.outcome-metric__value {
|
||||
font-family: 'Oswald', sans-serif;
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.outcome-metric__label {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.outcome-card__cta {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ── 9. Final CTA Section ── */
|
||||
.cta-final {
|
||||
background: linear-gradient(135deg, var(--accent), #5B21B6);
|
||||
color: white;
|
||||
border-radius: var(--radius-xl);
|
||||
padding: 48px 24px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cta-final__title {
|
||||
font-family: 'Oswald', sans-serif;
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.cta-final__subtitle {
|
||||
font-size: 16px;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 24px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.cta-final .btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 16px 40px;
|
||||
background: white;
|
||||
color: var(--accent);
|
||||
border: none;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
cursor: pointer;
|
||||
box-shadow: var(--shadow-lg);
|
||||
transition: transform .15s;
|
||||
}
|
||||
|
||||
.cta-final .btn:active {
|
||||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.cta-final {
|
||||
padding: 64px 48px;
|
||||
}
|
||||
.cta-final__title {
|
||||
font-size: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 10. Button System — Unified ── */
|
||||
.btn-primary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 14px 32px;
|
||||
background: linear-gradient(135deg, var(--accent), var(--accent-500));
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
cursor: pointer;
|
||||
transition: transform .15s, box-shadow .15s;
|
||||
box-shadow: var(--shadow-sm);
|
||||
text-decoration: none;
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus-visible {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 12px 28px;
|
||||
background: transparent;
|
||||
color: var(--accent);
|
||||
border: 2px solid var(--accent-200);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
cursor: pointer;
|
||||
transition: background .15s, border-color .15s;
|
||||
text-decoration: none;
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.btn-secondary:hover,
|
||||
.btn-secondary:focus-visible {
|
||||
background: var(--accent-light);
|
||||
border-color: var(--accent);
|
||||
}
|
||||
|
||||
/* ── 11. Mobile: hide old "Оставить заявку" text ── */
|
||||
.btn-banner .btn-free-lesson-header {
|
||||
/* Keeping existing class but text updated */
|
||||
}
|
||||
|
||||
/* ── 12. Banner enhancement — Risk Reversal Tag ── */
|
||||
.banner__content .risk-reversal-tag {
|
||||
display: inline-block;
|
||||
margin-top: 8px;
|
||||
padding: 4px 16px;
|
||||
background: rgba(255,255,255,0.15);
|
||||
border-radius: var(--radius-pill);
|
||||
font-size: 14px;
|
||||
color: #FFD43E;
|
||||
font-weight: 500;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
/* ── 13. Section spacers for Bento sections ── */
|
||||
.pksh-section {
|
||||
padding: 40px 16px;
|
||||
}
|
||||
|
||||
@media (min-width: 640px) {
|
||||
.pksh-section {
|
||||
padding: 60px 24px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
.pksh-section {
|
||||
padding: 80px 32px;
|
||||
}
|
||||
}
|
||||
|
||||
.pksh-section--alt {
|
||||
background: var(--bg-soft);
|
||||
}
|
||||
|
||||
/* ── 14. Mobile CTA — full width tap target ── */
|
||||
@media (max-width: 639px) {
|
||||
.btn-write.btn-primary.mobile,
|
||||
.btn-page.btn-write {
|
||||
width: calc(100% - 32px);
|
||||
margin: 8px auto;
|
||||
height: 52px;
|
||||
font-size: 17px !important;
|
||||
border-radius: var(--radius-pill);
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 15. Price/Bento Cards refinement ── */
|
||||
.pksh-price-card {
|
||||
border-radius: var(--radius-xl);
|
||||
padding: 28px 20px;
|
||||
background: var(--bg-card);
|
||||
box-shadow: var(--shadow-sm);
|
||||
border: 1px solid #E2E8F0;
|
||||
transition: box-shadow .2s, border-color .2s;
|
||||
}
|
||||
|
||||
.pksh-price-card:hover {
|
||||
box-shadow: var(--shadow-md);
|
||||
border-color: var(--accent-200);
|
||||
}
|
||||
|
||||
.pksh-price-card--featured {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 0 0 2px var(--accent), var(--shadow-md);
|
||||
}
|
||||
|
||||
.pksh-price-card__title {
|
||||
font-family: 'Oswald', sans-serif;
|
||||
font-size: 22px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.pksh-price-card__price {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: var(--accent);
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.pksh-price-card__features {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pksh-price-card__features li {
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* ── 16. Animations ── */
|
||||
@keyframes fadeInUp {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.bento-card {
|
||||
animation: fadeInUp 0.4s ease-out both;
|
||||
}
|
||||
|
||||
.bento-card:nth-child(1) { animation-delay: 0.05s; }
|
||||
.bento-card:nth-child(2) { animation-delay: 0.1s; }
|
||||
.bento-card:nth-child(3) { animation-delay: 0.15s; }
|
||||
.bento-card:nth-child(4) { animation-delay: 0.2s; }
|
||||
.bento-card:nth-child(5) { animation-delay: 0.25s; }
|
||||
|
||||
.bento-card--static {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
/* ── Reduced Motion ── */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.bento-card {
|
||||
animation: none;
|
||||
}
|
||||
.sticky-cta-btn {
|
||||
transition: none;
|
||||
}
|
||||
.btn-primary,
|
||||
.btn-secondary {
|
||||
transition: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 17. Modal Form Enhancement ── */
|
||||
.modal-request-form {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* ── 18. Section Spacing Fix for main ── */
|
||||
main {
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
main > .pksh-section:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
2988
wp-content/themes/dekart/assets/css/podgotovka-k-shkole.css
Normal file
2988
wp-content/themes/dekart/assets/css/podgotovka-k-shkole.css
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,11 @@
|
||||
--transition-fast: 0.2s ease;
|
||||
--transition-normal: 0.3s ease;
|
||||
--color-bg: #fff;
|
||||
--color-bg-warm: #F8F4EF;
|
||||
--color-bg-alt: #EEF3EE;
|
||||
--bg-hero: var(--color-bg-warm);
|
||||
--bg-white: var(--color-bg);
|
||||
--bg-mint: var(--color-bg-alt);
|
||||
--accent: #7C3AED;
|
||||
--accent-hover: #6D28D9;
|
||||
--accent-light: #F5F3FF;
|
||||
@ -771,8 +776,8 @@
|
||||
gap: 20px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.reviews-faq .box__accordion_label::after {
|
||||
background-image: none !important;
|
||||
.reviews-faq .accordion .box__accordion .box__accordion_label::after {
|
||||
background-image: none;
|
||||
}
|
||||
.reviews-faq .box__accordion_label span {
|
||||
font-size: clamp(18px, 2.2vw, 22px);
|
||||
@ -1198,10 +1203,9 @@
|
||||
|
||||
/* Сетка отзывов: мобильный скролл */
|
||||
@media (max-width: 768px) {
|
||||
/* ─── Hero: фото скрыто, текст на всю ширину с отступами ─── */
|
||||
.reviews-hero {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
/* ─── Container: единый отступ для всех секций ─── */
|
||||
.page-reviews .container {
|
||||
padding: 0 20px;
|
||||
}
|
||||
.reviews-hero__image {
|
||||
display: none;
|
||||
@ -1210,7 +1214,7 @@
|
||||
max-width: none;
|
||||
}
|
||||
.reviews-hero__metrics {
|
||||
flex-wrap: nowrap;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
.reviews-intro__grid {
|
||||
@ -1261,10 +1265,10 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* ─── Бейдж в колонке имени: убираем inline-переопределения с мобилки ─── */
|
||||
/* ─── Бейдж в колонке имени ─── */
|
||||
.reviews-cards .lw-card .lw-badge--verified {
|
||||
margin-top: 6px !important;
|
||||
margin-left: 0 !important;
|
||||
margin-top: 6px;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* ─── Звёзды: абсолютно в правый верхний угол карточки ─── */
|
||||
@ -1877,6 +1881,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── SECTION-BG (full-width background utilities) ─── */
|
||||
.section-bg {
|
||||
position: relative;
|
||||
}
|
||||
.section-bg::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: calc(-50vw + 50%);
|
||||
width: 100vw;
|
||||
z-index: -1;
|
||||
}
|
||||
.section-bg[data-bg="hero"]::before { background: var(--bg-hero); }
|
||||
.section-bg[data-bg="white"]::before { background: var(--bg-white); }
|
||||
.section-bg[data-bg="mint"]::before { background: var(--color-bg-alt); }
|
||||
|
||||
/* ─── PREFERS-REDUCED-MOTION ─── */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.reveal,
|
||||
@ -1903,4 +1924,44 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* ─── САМЫЕ МАЛЕНЬКИЕ ЭКРАНЫ (≤375px) ─── */
|
||||
@media (max-width: 375px) {
|
||||
.reviews-hero__h1 {
|
||||
font-size: 22px;
|
||||
}
|
||||
.reviews-hero__metrics {
|
||||
gap: 6px;
|
||||
}
|
||||
.reviews-hero__metric {
|
||||
padding: 10px 6px;
|
||||
}
|
||||
.reviews-hero__metric-number {
|
||||
font-size: 20px;
|
||||
}
|
||||
.reviews-hero__metric-label {
|
||||
font-size: 10px;
|
||||
}
|
||||
.reviews-cards .lw-grid--3 {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.results__card {
|
||||
flex: 0 0 50%;
|
||||
max-width: 50%;
|
||||
padding: 16px 8px;
|
||||
}
|
||||
.results__grid {
|
||||
gap: 0;
|
||||
}
|
||||
.cross-links__grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.final-cta__title {
|
||||
font-size: 22px;
|
||||
}
|
||||
.reviews-hero__cta-btn {
|
||||
padding: 14px 20px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -52,10 +52,18 @@ document.addEventListener("click", function (event) {
|
||||
}
|
||||
if (target.classList.contains("btn-write")) {
|
||||
modalRequestForm.style="";
|
||||
document.querySelector('html').style = "overflow: hidden;";
|
||||
return;
|
||||
}
|
||||
if (target.classList.contains("btn-close-request-form-img")) {
|
||||
if (target.classList.contains("btn-close-request-form") || target.classList.contains("btn-close-request-form-img")) {
|
||||
modalRequestForm.style="display: none;";
|
||||
document.querySelector('html').style = "";
|
||||
return;
|
||||
}
|
||||
// Клик по фону (затемнению) — закрыть модалку
|
||||
if (target === modalRequestForm) {
|
||||
modalRequestForm.style="display: none;";
|
||||
document.querySelector('html').style = "";
|
||||
return;
|
||||
}
|
||||
|
||||
@ -231,3 +239,92 @@ setTimeout(() => {
|
||||
document.querySelectorAll('.header-menu').forEach(item => {
|
||||
item.classList.add('hover-effect');
|
||||
})
|
||||
|
||||
/* ── Scroll Progress Bar ── */
|
||||
(function() {
|
||||
var progressBar = document.createElement('div');
|
||||
progressBar.className = 'pksh-scroll-progress';
|
||||
document.body.prepend(progressBar);
|
||||
|
||||
function updateProgress() {
|
||||
var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
|
||||
var docHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
|
||||
var progress = (scrollTop / docHeight) * 100;
|
||||
progressBar.style.width = progress + '%';
|
||||
}
|
||||
|
||||
window.addEventListener('scroll', updateProgress, { passive: true });
|
||||
window.addEventListener('resize', updateProgress, { passive: true });
|
||||
updateProgress();
|
||||
})();
|
||||
|
||||
/* ── Desktop Sticky CTA — show after hero ── */
|
||||
(function() {
|
||||
var sticky = document.querySelector('.sticky-cta-desktop');
|
||||
var hero = document.querySelector('.banner');
|
||||
if (!sticky || !hero) return;
|
||||
|
||||
var observer = new IntersectionObserver(function(entries) {
|
||||
entries.forEach(function(entry) {
|
||||
// Show sticky CTA when hero is NOT visible (scrolled past)
|
||||
sticky.classList.toggle('visible', !entry.isIntersecting);
|
||||
});
|
||||
}, { threshold: 0 });
|
||||
|
||||
observer.observe(hero);
|
||||
})();
|
||||
|
||||
/* ── Mobile banner padding: compensate for fixed header ── */
|
||||
(function() {
|
||||
var banner = document.querySelector('.page-pksh .banner');
|
||||
var header = document.querySelector('.header');
|
||||
if (banner && header && window.innerWidth <= 860) {
|
||||
var headerH = header.offsetHeight || 76;
|
||||
banner.style.paddingTop = headerH + 'px';
|
||||
banner.style.marginTop = '-' + headerH + 'px';
|
||||
}
|
||||
})();
|
||||
|
||||
/* ── .open-bitrix-form → opens modal form ── */
|
||||
document.querySelectorAll('.open-bitrix-form').forEach(btn => {
|
||||
btn.addEventListener('click', function(e) {
|
||||
const modal = document.querySelector('.modal-request-form');
|
||||
if (modal) {
|
||||
modal.style = "";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Закрытие модалки по Escape
|
||||
document.addEventListener("keydown", function(e) {
|
||||
if (e.key === "Escape") {
|
||||
const modal = document.querySelector('.modal-request-form');
|
||||
if (modal && modal.style.display !== "none") {
|
||||
modal.style.display = "none";
|
||||
document.querySelector('html').style = "";
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/* ── FAQ Accordion (mystyle-accordion) ── */
|
||||
document.querySelectorAll('.mystyle-accordion-trigger').forEach(trigger => {
|
||||
trigger.addEventListener('click', function(e) {
|
||||
const item = this.closest('.mystyle-accordion-item');
|
||||
if (!item) return;
|
||||
const isOpen = item.classList.contains('active');
|
||||
// Закрываем все другие аккордеоны в том же контейнере
|
||||
const parent = item.parentElement;
|
||||
if (parent) {
|
||||
parent.querySelectorAll('.mystyle-accordion-item.active').forEach(other => {
|
||||
if (other !== item) {
|
||||
other.classList.remove('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
if (isOpen) {
|
||||
item.classList.remove('active');
|
||||
} else {
|
||||
item.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
45
wp-content/themes/dekart/assets/js/front-page.js
Normal file
45
wp-content/themes/dekart/assets/js/front-page.js
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* front-page.js — обработчики для шаблона front-page.php
|
||||
* Извлечены из inline <script> в отдельный файл
|
||||
*/
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
const tabs = document.querySelectorAll('.tab-clicked');
|
||||
if (!tabs.length) return;
|
||||
|
||||
tabs.forEach(function (tab) {
|
||||
tab.addEventListener('click', function (event) {
|
||||
const tabBtn = event.currentTarget;
|
||||
const tabsBlock = tabBtn.closest('[class*="tabs"]') || tabBtn.parentNode.parentNode.parentNode;
|
||||
const tabNum = tabBtn.parentNode.getAttribute('data-tab-btn');
|
||||
const content = tabsBlock.querySelector('.tabs-content');
|
||||
|
||||
if (!content || !tabNum) return;
|
||||
|
||||
// Анимация переключения табов
|
||||
content.style.opacity = '0';
|
||||
content.style.filter = 'blur(5px)';
|
||||
content.style.left = '-50%';
|
||||
|
||||
tabsBlock.querySelectorAll('.tab').forEach(function (t) {
|
||||
t.classList.remove('active');
|
||||
});
|
||||
const activeBtn = tabsBlock.querySelector('[data-tab-btn="' + tabNum + '"]');
|
||||
if (activeBtn) activeBtn.classList.add('active');
|
||||
|
||||
setTimeout(function () {
|
||||
content.style.opacity = '';
|
||||
content.style.filter = '';
|
||||
content.style.left = '';
|
||||
|
||||
tabsBlock.querySelectorAll('.page-tab').forEach(function (t, i) {
|
||||
if (i !== Number(tabNum) - 1) {
|
||||
t.classList.remove('active');
|
||||
} else {
|
||||
t.classList.add('active');
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -39,7 +39,7 @@ document.addEventListener('DOMContentLoaded', function () {
|
||||
// ───────────────────────────────────────────────
|
||||
document.querySelectorAll('.review-card__btn-more').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
const textBlock = this.parentNode.querySelector('.lw-card__text');
|
||||
const textBlock = this.closest('.lw-card').querySelector('.lw-card__text');
|
||||
if (textBlock) {
|
||||
textBlock.classList.toggle('review-card__text--expanded');
|
||||
this.textContent = textBlock.classList.contains('review-card__text--expanded')
|
||||
|
||||
171
wp-content/themes/dekart/deploy-runner.php
Normal file
171
wp-content/themes/dekart/deploy-runner.php
Normal file
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
/**
|
||||
* Deploy Runner — HTTP-triggered migration executor
|
||||
* Usage: https://site.com/wp-content/themes/dekart/deploy-runner.php?migrate=003
|
||||
*
|
||||
* Self-destructs after execution (renames to .done).
|
||||
* Requires wp-config.php for DB credentials.
|
||||
*/
|
||||
|
||||
// Prevent WordPress from intercepting
|
||||
define('WP_USE_THEMES', false);
|
||||
|
||||
$allowed_migrations = ['003', '004'];
|
||||
|
||||
$migrate = isset($_GET['migrate']) ? $_GET['migrate'] : '';
|
||||
|
||||
if (!in_array($migrate, $allowed_migrations)) {
|
||||
header('Content-Type: text/plain');
|
||||
die("Usage: ?migrate=003 (allowed: " . implode(', ', $allowed_migrations) . ")\n");
|
||||
}
|
||||
|
||||
// Load WordPress config for DB credentials
|
||||
$wp_config_path = dirname(__FILE__) . '/../../../wp-config.php';
|
||||
if (!file_exists($wp_config_path)) {
|
||||
// Try parent directory
|
||||
$wp_config_path = dirname(__FILE__) . '/../../wp-config.php';
|
||||
}
|
||||
if (!file_exists($wp_config_path)) {
|
||||
$wp_config_path = dirname(__FILE__) . '/../wp-config.php';
|
||||
}
|
||||
|
||||
require_once $wp_config_path;
|
||||
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
echo "=== Deploy Runner: migration $migrate ===\n\n";
|
||||
|
||||
// ─── Shared helpers ──────────────────────────────────────────────────
|
||||
function dp_get_wpdb() {
|
||||
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
|
||||
if (!$conn) {
|
||||
die("DB connection failed: " . mysqli_connect_error() . "\n");
|
||||
}
|
||||
echo "Connected to DB: " . DB_NAME . "\n";
|
||||
return $conn;
|
||||
}
|
||||
|
||||
function dp_get_theme_dir() {
|
||||
// Our deploy-runner lives in the theme root
|
||||
$theme_dir = dirname(__FILE__);
|
||||
echo "Theme dir: {$theme_dir}\n";
|
||||
return $theme_dir;
|
||||
}
|
||||
|
||||
if ($migrate === '003') {
|
||||
// Fix banner_text typo: rарантированная → гарантированная
|
||||
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
|
||||
if (!$conn) {
|
||||
die("DB connection failed: " . mysqli_connect_error() . "\n");
|
||||
}
|
||||
echo "Connected to DB: " . DB_NAME . "\n\n";
|
||||
|
||||
$post_id = 2;
|
||||
$meta_keys = ['_banner_text', 'banner_text'];
|
||||
$fixed = 0;
|
||||
|
||||
foreach ($meta_keys as $meta_key) {
|
||||
$res = mysqli_query($conn,
|
||||
"SELECT meta_id, meta_value FROM wp_postmeta WHERE post_id = $post_id AND meta_key = '$meta_key'");
|
||||
|
||||
while ($row = mysqli_fetch_assoc($res)) {
|
||||
$old_val = $row['meta_value'];
|
||||
$new_val = str_replace('rарантированная', 'гарантированная', $old_val);
|
||||
$new_val = str_replace('rантированная', 'гантированная', $new_val);
|
||||
|
||||
if ($new_val !== $old_val) {
|
||||
$meta_id = (int)$row['meta_id'];
|
||||
$escaped = mysqli_real_escape_string($conn, $new_val);
|
||||
mysqli_query($conn,
|
||||
"UPDATE wp_postmeta SET meta_value = '$escaped' WHERE meta_id = $meta_id");
|
||||
echo "✅ FIXED meta_id=$meta_key key=$meta_key\n";
|
||||
echo " OLD: $old_val\n";
|
||||
echo " NEW: $new_val\n\n";
|
||||
$fixed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($fixed === 0) {
|
||||
echo "✅ Nothing to fix — typo already corrected\n";
|
||||
}
|
||||
|
||||
echo "\nTotal meta values updated: $fixed\n";
|
||||
mysqli_close($conn);
|
||||
}
|
||||
|
||||
if ($migrate === '004') {
|
||||
// ─── 004a: Remove post 740 (custom-css-js orphan) ───
|
||||
$conn = dp_get_wpdb();
|
||||
|
||||
$post_740 = mysqli_query($conn, "SELECT ID FROM wp_posts WHERE ID = 740 AND post_type = 'custom-css-js'");
|
||||
if (mysqli_num_rows($post_740) > 0) {
|
||||
// Hard-delete post + meta
|
||||
mysqli_query($conn, "DELETE FROM wp_posts WHERE ID = 740");
|
||||
mysqli_query($conn, "DELETE FROM wp_postmeta WHERE post_id = 740");
|
||||
echo "✅ DELETED post ID 740 (custom-css-js)\n";
|
||||
|
||||
// Remove physical file if exists
|
||||
$theme_dir = dp_get_theme_dir();
|
||||
$upload_dir = dirname(dirname($theme_dir)) . '/uploads';
|
||||
$files_to_check = [
|
||||
$upload_dir . '/custom-css-js/740.css',
|
||||
$upload_dir . '/custom-css-js/740.min.css',
|
||||
];
|
||||
foreach ($files_to_check as $file) {
|
||||
if (file_exists($file)) {
|
||||
unlink($file);
|
||||
echo "✅ DELETED file: {$file}\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "ℹ️ Post ID 740 not found — already removed\n";
|
||||
}
|
||||
|
||||
// ─── 004b: Clean wp_custom_css option ───
|
||||
// We need wp-load.php for get_option/update_option
|
||||
$wp_load = dirname(__FILE__) . '/../../../wp-load.php';
|
||||
if (!file_exists($wp_load)) {
|
||||
$wp_load = dirname(__FILE__) . '/../../wp-load.php';
|
||||
}
|
||||
if (file_exists($wp_load)) {
|
||||
require_once $wp_load;
|
||||
echo "✅ Loaded WordPress\n";
|
||||
|
||||
$option_name = 'wp_custom_css';
|
||||
$current = get_option($option_name, '');
|
||||
if (!empty($current)) {
|
||||
$before = strlen($current);
|
||||
$cleaned = preg_replace('/\.(pksh|ms-|ms-text-)[^}]+}\s*/', '', $current);
|
||||
$cleaned = preg_replace('/\.(pksh|ms-|ms-text-)[^{]*\{\s*\}\s*/', '', $cleaned);
|
||||
$cleaned = trim($cleaned);
|
||||
$after = strlen($cleaned);
|
||||
$diff = $before - $after;
|
||||
|
||||
if ($diff > 0) {
|
||||
update_option($option_name, $cleaned);
|
||||
echo "✅ wp_custom_css: {$before} → {$after} chars (removed {$diff})\n";
|
||||
} else {
|
||||
echo "ℹ️ wp_custom_css unchanged ({$before} chars)\n";
|
||||
}
|
||||
} else {
|
||||
echo "ℹ️ wp_custom_css option is empty\n";
|
||||
}
|
||||
|
||||
if (function_exists('opcache_reset')) {
|
||||
opcache_reset();
|
||||
echo "✅ OPcache reset\n";
|
||||
}
|
||||
} else {
|
||||
echo "⚠️ wp-load.php not found — skipping wp_custom_css cleanup\n";
|
||||
}
|
||||
|
||||
mysqli_close($conn);
|
||||
}
|
||||
|
||||
echo "\n=== Migration complete ===\n";
|
||||
|
||||
// Self-destruct: rename this file
|
||||
$self = __FILE__;
|
||||
$done = $self . '.done';
|
||||
rename($self, $done);
|
||||
echo "Self-destruct: renamed to " . basename($done) . "\n";
|
||||
@ -19,10 +19,15 @@
|
||||
'theme_location' => 'top',
|
||||
) );
|
||||
?>
|
||||
<nav class="footer_links" aria-label="Дополнительные ссылки">
|
||||
<ul class="footer_links-col">
|
||||
<li><a href="/otzyvy/">Отзывы</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="footer__col">
|
||||
<button class="btn-write btn-lilac desktop"><?php esc_html_e('Записаться', 'dekart'); ?></button>
|
||||
<button class="btn-write btn-lilac mobile"><?php esc_html_e('Бесплатное занятие', 'dekart'); ?></button>
|
||||
<button class="btn-write btn-primary desktop"><?php esc_html_e('Бесплатное пробное', 'dekart'); ?></button>
|
||||
<button class="btn-write btn-primary mobile"><?php esc_html_e('Бесплатно', 'dekart'); ?></button>
|
||||
<div class="footer__link-icon">
|
||||
<img width="19" height="32"
|
||||
src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/images/icon-location.svg"
|
||||
@ -69,7 +74,20 @@
|
||||
alt="Закрыть"
|
||||
loading="lazy">
|
||||
</button>
|
||||
<?php echo carbon_get_theme_option('site_bitrix_script'); ?>
|
||||
<?php
|
||||
// Приоритет: page-specific meta > theme option
|
||||
$b24_script = '';
|
||||
if ( is_singular() ) {
|
||||
$page_script = carbon_get_post_meta( get_the_ID(), 'pksh_bitrix_script' );
|
||||
if ( ! empty( $page_script ) ) {
|
||||
$b24_script = $page_script;
|
||||
}
|
||||
}
|
||||
if ( empty( $b24_script ) ) {
|
||||
$b24_script = carbon_get_theme_option('site_bitrix_script');
|
||||
}
|
||||
echo $b24_script;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -90,5 +108,24 @@ document.addEventListener("DOMContentLoaded", function() {
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- ✅ Sticky CTA Mobile -->
|
||||
<div class="sticky-cta-mobile" aria-hidden="true">
|
||||
<button class="sticky-cta-btn btn-write" aria-label="Записаться на бесплатное пробное">
|
||||
Записаться на бесплатное
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- ✅ Sticky CTA Desktop (появляется при скролле) -->
|
||||
<div class="sticky-cta-desktop" aria-hidden="true">
|
||||
<div class="sticky-cta-desktop__inner">
|
||||
<div class="sticky-cta-desktop__info">
|
||||
<span class="sticky-cta-desktop__badge">🎯 Подготовка к школе</span>
|
||||
<span class="sticky-cta-desktop__text">ул. Комсомольская, 11 — первое занятие <strong>бесплатно</strong></span>
|
||||
</div>
|
||||
<button class="sticky-cta-desktop__btn btn-write">Записаться на бесплатное пробное</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@ -5,6 +5,11 @@ Template Name: шаблон главной страницы
|
||||
|
||||
get_header();
|
||||
$post_id = get_the_ID();
|
||||
|
||||
// ─── ДАННЫЕ ФИЛИАЛА ───
|
||||
$branch_email = get_option( 'branch_email' ) ?: carbon_get_theme_option( 'site_mail' ) ?: '';
|
||||
$branch_phone = get_option( 'branch_phone' ) ?: carbon_get_theme_option( 'site_phone' ) ?: '';
|
||||
$branch_name = get_option( 'branch_name' ) ?: carbon_get_theme_option( 'site_name' ) ?: 'Декарт';
|
||||
?>
|
||||
<main class="main-page">
|
||||
|
||||
@ -61,14 +66,14 @@ $post_id = get_the_ID();
|
||||
<h2 class="page_h2">Наши услуги</h2>
|
||||
<div class="advantages__block-content">
|
||||
<div class="advantages__block-row">
|
||||
<div class="advantages__block-item" style="border:2px solid #A05A95">
|
||||
<div class="advantages__block-item advantages__block-item--school">
|
||||
<div class="advantages__block-item_title">Начальная школа</div>
|
||||
<p>Обучение ведётся по программе «Перспектива» и методике Занкова в соответствии с ФГОС, включая изучение английского языка с 1 класса.</p>
|
||||
<div class="advantages__block-item-img">
|
||||
<a href="/nachalnaya-shkola/">Узнать подробнее ></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="advantages__block-item" style="border:2px solid #F682A5">
|
||||
<div class="advantages__block-item advantages__block-item--preschool">
|
||||
<?php // ИСПРАВЛЕНО: была опечатка a/vantages__block-item_title ?>
|
||||
<div class="advantages__block-item_title">Подготовка к школе</div>
|
||||
<p>Программа для будущих первоклассников: развитие базовых навыков, логики и речи через игровые задания.</p>
|
||||
@ -76,7 +81,7 @@ $post_id = get_the_ID();
|
||||
<a href="/podgotovka-k-shkole/">Узнать подробнее ></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="advantages__block-item" style="border:2px solid #FEDF6F">
|
||||
<div class="advantages__block-item advantages__block-item--afterschool">
|
||||
<div class="advantages__block-item_title">Группы продлённого дня</div>
|
||||
<p>Помощь с домашними заданиями, творческие и развивающие занятия.</p>
|
||||
<div class="advantages__block-item-img">
|
||||
@ -85,21 +90,21 @@ $post_id = get_the_ID();
|
||||
</div>
|
||||
</div>
|
||||
<div class="advantages__block-row">
|
||||
<div class="advantages__block-item" style="border:2px solid #F9A474">
|
||||
<div class="advantages__block-item advantages__block-item--exam">
|
||||
<div class="advantages__block-item_title">Подготовка к экзаменам ОГЭ, ЕГЭ и ВПР</div>
|
||||
<p>Интенсивная подготовка к экзаменам ВПР, ОГЭ и ЕГЭ по всем предметам школьной программы.</p>
|
||||
<div class="advantages__block-item-img">
|
||||
<a href="https://schelkovo.dekart-school.ru/">Узнать подробнее ></a>
|
||||
<a href="<?php echo esc_url( home_url( '/' ) ); ?>">Узнать подробнее ></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="advantages__block-item" style="border:2px solid #C9DA8F">
|
||||
<div class="advantages__block-item advantages__block-item--camp">
|
||||
<div class="advantages__block-item_title">Летний городской лагерь</div>
|
||||
<p>Образование, творчество и наука в тематических сменах.</p>
|
||||
<div class="advantages__block-item-img">
|
||||
<a href="/gorodskoj-lager/">Узнать подробнее ></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="advantages__block-item" style="border:2px solid #B8CEDC">
|
||||
<div class="advantages__block-item advantages__block-item--clubs">
|
||||
<div class="advantages__block-item_title">Кружки и секции</div>
|
||||
<p>Творческие студии, спортивные секции и развивающие занятия для детей всех возрастов.</p>
|
||||
<div class="advantages__block-item-img"></div>
|
||||
@ -120,11 +125,11 @@ $post_id = get_the_ID();
|
||||
$block_text_1 = '<p>В нашей частной школе в Щелково мы знаем каждого ученика по имени. Небольшие классы до 12 человек, педагоги с опытом от 10 лет и углублённый английский с 1 класса. Работаем по программе «Перспектива» и методике Занкова. Принимаем детей из Щелково, Фрязино и Ивантеевки. Лицензия Министерства образования Московской области.</p>';
|
||||
}
|
||||
?>
|
||||
<section class="info__block" style="padding-bottom:0;margin-top:40px">
|
||||
<section class="info__block info__block--compact">
|
||||
<div class="container">
|
||||
<div class="info__block-wrapper">
|
||||
<div class="info__block-content">
|
||||
<div class="info__block-content_text" style="max-width:100%">
|
||||
<div class="info__block-content_text info__block-content_text--full">
|
||||
<?php echo wp_kses_post( $block_text_1 ); ?>
|
||||
</div>
|
||||
</div>
|
||||
@ -132,12 +137,22 @@ $post_id = get_the_ID();
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-block" style="background:linear-gradient(90deg,#fdf6ff 0%,#f5e8f5 100%);padding:60px 0;border-top:2px solid #A05A95;border-bottom:2px solid #A05A95;margin:40px 0;text-align:center">
|
||||
<section class="cta-block">
|
||||
<div class="container">
|
||||
<div class="cta-wrapper" style="max-width:900px;margin:0 auto">
|
||||
<h2 class="page_h2" style="margin-bottom:20px;line-height:1.3">Запишитесь на бесплатную экскурсию по школе и познакомьтесь с нашей программой!</h2>
|
||||
<p style="font-size:1.2rem;color:#444;margin-bottom:30px">Получите персональную консультацию и узнайте стоимость обучения прямо сейчас.</p>
|
||||
<button class="btn-write btn-lilac btn-page" style="margin:0 auto;display:block;padding:18px 45px;font-size:1.3rem;box-shadow:0 4px 15px rgba(160,90,149,.3)">Записаться на экскурсию</button>
|
||||
<div class="cta-wrapper">
|
||||
<h2 class="page_h2">Запишитесь на бесплатную экскурсию по школе и познакомьтесь с нашей программой!</h2>
|
||||
<p>Получите персональную консультацию и узнайте стоимость обучения прямо сейчас.</p>
|
||||
<button class="btn-write btn-lilac btn-page">Записаться на экскурсию</button>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ССЫЛКА НА СТРАНИЦУ ОТЗЫВОВ ДЛЯ УСИЛЕНИЯ ПЕРЕЛИНКОВКИ -->
|
||||
<section class="reviews-link-block">
|
||||
<div class="container">
|
||||
<div class="reviews-link-wrapper">
|
||||
<p>Узнайте, что говорят о нас родители и ученики →</p>
|
||||
<a href="/otzyvy/" class="btn-outline btn-page">Читать все отзывы</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -207,8 +222,8 @@ $post_id = get_the_ID();
|
||||
"sameAs": ["https://vk.com/shkola_dekart"],
|
||||
"contactPoint": {
|
||||
"@type": "ContactPoint",
|
||||
"telephone": "+79303334151",
|
||||
"email": "shelkovo@dekart-school.ru",
|
||||
"telephone": "<?php echo esc_attr( $branch_phone ?: '+79303334151' ); ?>",
|
||||
"email": "<?php echo esc_attr( $branch_email ?: 'shelkovo@dekart-school.ru' ); ?>",
|
||||
"contactType": "customer service",
|
||||
"areaServed": "RU",
|
||||
"availableLanguage": "Russian"
|
||||
@ -296,27 +311,7 @@ $post_id = get_the_ID();
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php
|
||||
?>
|
||||
<script>
|
||||
document.addEventListener('click', function(event) {
|
||||
if (!event.target.classList.contains('tab-clicked')) return;
|
||||
var tabsBlock = event.target.parentNode.parentNode.parentNode;
|
||||
var tabNum = event.target.parentNode.getAttribute('data-tab-btn');
|
||||
var content = tabsBlock.querySelector('.tabs-content');
|
||||
if (!content) return;
|
||||
content.style.cssText = 'opacity:0;filter:blur(5px);left:-50%';
|
||||
tabsBlock.querySelectorAll('.tab').forEach(function(t){ t.classList.remove('active'); });
|
||||
tabsBlock.querySelector('[data-tab-btn="' + tabNum + '"]').classList.add('active');
|
||||
setTimeout(function() {
|
||||
content.style.cssText = '';
|
||||
tabsBlock.querySelectorAll('.page-tab').forEach(function(t, i) {
|
||||
if (i !== Number(tabNum) - 1) t.classList.remove('active');
|
||||
else t.classList.add('active');
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<?php get_template_part('template-parts/map'); ?>
|
||||
|
||||
|
||||
@ -189,6 +189,9 @@ function add_carbon() {
|
||||
Field::make( 'text', 'site_map_link', 'Ссылка на карту:' ),
|
||||
Field::make( 'text', 'site_location', 'Координаты адреса (для яндекc карт):' ),
|
||||
Field::make( 'text', 'site_frame_reviews', 'Ссылка на страницу с отзывами:' ),
|
||||
Field::make( 'text', 'site_lk_url', 'Ссылка на личный кабинет (ЛК):' )
|
||||
->set_default_value( 'https://lk.dekart-school.ru/' )
|
||||
->set_help_text( 'URL личного кабинета для учеников/родителей. По умолчанию: https://lk.dekart-school.ru/' ),
|
||||
Field::make( 'textarea', 'site_bitrix_script', 'script (формы) БИТРИКС24:' ),
|
||||
Field::make( 'textarea', 'site_bitrix_vacancies', 'script (для формы связаться с нами) БИТРИКС24:' ),
|
||||
Field::make( 'checkbox', 'check_banner', 'Отображать плашку со скидкой на формах "Запись на бесплатное пробное занятие"' )
|
||||
@ -247,6 +250,9 @@ function add_carbon() {
|
||||
Field::make( 'text', 'schema_legal_name', 'Юридическое название (legalName)' )
|
||||
->set_width( 50 )
|
||||
->set_help_text( 'Полное юр. название организации. Например: "ИП Иванов Иван Иванович"' ),
|
||||
Field::make( 'textarea', 'schema_description', 'Описание организации (description)' )
|
||||
->set_width( 100 )
|
||||
->set_help_text( 'Короткое описание для Schema.org Organization → School. Появляется в сниппете поисковиков. Рекомендуется 1–2 предложения: тип школы, классы, местоположение. Пример: "Частная школа полного дня в Щёлково. Обучение с 1 по 11 класс, подготовка к ЕГЭ и ОГЭ, индивидуальный подход." Если пусто — собирается автоматически из названия и города.' ),
|
||||
Field::make( 'text', 'schema_postal_code', 'Почтовый индекс (postalCode)' )
|
||||
->set_width( 50 )
|
||||
->set_help_text( 'Индекс для address.postalCode в микроразметке.' ),
|
||||
@ -292,6 +298,9 @@ function add_carbon() {
|
||||
) ),
|
||||
Field::make( 'media_gallery', 'schema_photos', 'Фотографии филиала (image[])' )
|
||||
->set_help_text( 'Выберите фотографии интерьера/экстерьера для image[].' ),
|
||||
Field::make( 'textarea', 'schema_area_served', 'Города присутствия (areaServed)' )
|
||||
->set_width( 100 )
|
||||
->set_help_text( 'Список городов через запятую, где работает школа. Первый город должен совпадать с городом филиала. Пример: Щёлково, Фрязино, Монино, Ивантеевка, Королёв. Влияет на локальный поиск Google и Яндекса — школа будет показываться по этим городам. Если пусто — используется только город филиала.' ),
|
||||
));
|
||||
|
||||
// (пусто — старые поля banner_img_desktop, banner_img_mobile,
|
||||
@ -1023,8 +1032,12 @@ function add_carbon() {
|
||||
->set_html( '<p style="color: #64748b; font-size: 13px; margin: 0 0 12px;">Секция: <strong>.reviews-intro</strong> — SEO-текст в начале страницы. Управляется из админки, чтобы можно было править текст без редактирования шаблона.</p>' ),
|
||||
Field::make( 'text', 'reviews_intro_price_text', 'Стоимость обучения (текст)' )
|
||||
->set_default_value( 'от 40 000 ₽ в месяц' )
|
||||
->set_width( 100 )
|
||||
->set_width( 50 )
|
||||
->set_help_text( 'Текст стоимости в блоке .reviews-intro__info. Пример: «от 40 000 ₽ в месяц» или «от 35 000 ₽/мес». Если поле пусто — строка не выводится.' ),
|
||||
Field::make( 'text', 'reviews_intro_hours', 'Режим работы (текст)' )
|
||||
->set_default_value( 'ежедневно с 8:00 до 19:00, кроме воскресенья' )
|
||||
->set_width( 50 )
|
||||
->set_help_text( 'Текст режима работы в блоке .reviews-intro__info. Отображается на странице отзывов под SEO-текстом. Пример: «ежедневно с 8:00 до 19:00, кроме воскресенья» или «Пн–Пт: 08:00–19:00, Сб: 09:00–14:00». Если пусто — строка не выводится.' ),
|
||||
Field::make( 'textarea', 'reviews_intro_lead', 'Лид-абзац (первый, крупный)' )
|
||||
->set_default_value( 'Частная школа Декарт в Щёлково — это образовательное пространство, где каждый ребёнок получает внимание, заботу и качественные знания. Мы работаем в Щёлковском городском округе с 2010 года и за это время помогли раскрыть потенциал сотням учеников. Отзывы родителей о школе Декарт — это реальные истории семей, которые доверили нам образование своих детей. Мы публикуем их, чтобы вы могли принять взвешенное решение.' )
|
||||
->set_help_text( 'Первый, самый заметный абзац. Отображается крупнее остальных, отделён линией. 150–180 символов — оптимально. Должен вовлекать и отвечать на главный вопрос посетителя.' ),
|
||||
@ -1252,9 +1265,12 @@ function exclude_custom_taxonomy_posts($query) {
|
||||
|
||||
function add_og_image() {
|
||||
$term = get_queried_object();
|
||||
if ($term->term_id) {
|
||||
if ( ! is_a( $term, 'WP_Term' ) || empty( $term->term_id ) ) {
|
||||
return;
|
||||
}
|
||||
$snippet = carbon_get_term_meta( $term->term_id, 'snippet' );
|
||||
if ($snippet != '') echo '<meta property="og:image" content="' . wp_get_attachment_url($snippet) . '" >' . "\n";
|
||||
if ( $snippet ) {
|
||||
echo '<meta property="og:image" content="' . esc_url( wp_get_attachment_url( $snippet ) ) . '" >' . "\n";
|
||||
}
|
||||
}
|
||||
add_action( 'wp_head', 'add_og_image' );
|
||||
@ -1317,12 +1333,8 @@ function enqueue_template_specific_styles() {
|
||||
);
|
||||
}
|
||||
if ( is_page_template('page-reviews.php') ) {
|
||||
wp_enqueue_style(
|
||||
'phosphor-icons',
|
||||
'https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css',
|
||||
array(),
|
||||
'2.1.1'
|
||||
);
|
||||
// Phosphor Icons загружаются через preload+onload в wp_head (page-reviews.php:46)
|
||||
// Не используем wp_enqueue_style — избегаем render-blocking
|
||||
wp_enqueue_style(
|
||||
'reviews-page-style',
|
||||
get_template_directory_uri() . '/assets/css/reviews-page.css',
|
||||
@ -1665,7 +1677,6 @@ function dekart_branch_register_settings() {
|
||||
register_setting( 'dekart_branch_group', 'branch_social' );
|
||||
register_setting( 'dekart_branch_group', 'branch_messengers' );
|
||||
register_setting( 'dekart_branch_group', 'branch_button_script', array( 'sanitize_callback' => 'dekart_sanitize_script_field' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_hours', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_myreviews_widget', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_ext_yandex', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_ext_google', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
@ -1673,6 +1684,12 @@ function dekart_branch_register_settings() {
|
||||
register_setting( 'dekart_branch_group', 'branch_ext_otzovik', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_ext_other_name', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_ext_other_url', array( 'sanitize_callback' => 'esc_url_raw' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_og_site_name', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_ext_review_count', array( 'sanitize_callback' => 'absint' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_avg_rating', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_remaining_seats', array( 'sanitize_callback' => 'absint' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_schema_description', array( 'sanitize_callback' => 'sanitize_textarea_field' ) );
|
||||
register_setting( 'dekart_branch_group', 'branch_area_served', array( 'sanitize_callback' => 'sanitize_text_field' ) );
|
||||
// Поля branch_map_url, branch_founded, branch_photos — удалены.
|
||||
// Они дублировали CF таб «SEO и микроразметка» (schema_*).
|
||||
// Чтение: inc/schema.php → dekart_schema_option() → CF → Settings API (backward compat).
|
||||
@ -1844,26 +1861,40 @@ function dekart_branch_settings_page() {
|
||||
<label>Полное название организации</label>
|
||||
<input type="text" name="branch_name" value="<?php echo esc_attr( get_option( 'branch_name', 'Декарт' ) ); ?>">
|
||||
</div>
|
||||
<div class="branch-field">
|
||||
<label>OG: Site Name (для мета-тега og:site_name)</label>
|
||||
<input type="text" name="branch_og_site_name" value="<?php echo esc_attr( get_option( 'branch_og_site_name', 'Частная школа Декарт в Щёлково' ) ); ?>" style="width:100%;max-width:500px">
|
||||
<p class="desc">Значение тега <code>og:site_name</code> — отображается в сниппетах Яндекса и Google. Рекомендуется: «Частная школа Декарт в Щёлково». Если оставить пустым — будет использован заголовок сайта из настроек WordPress.</p>
|
||||
</div>
|
||||
<div class="branch-field">
|
||||
<label>Ценовой диапазон</label>
|
||||
<input type="text" name="branch_price_range" value="<?php echo esc_attr( get_option( 'branch_price_range', '$$' ) ); ?>">
|
||||
<p class="desc">Для микроразметки. Например: "$", "$$", "$$$".</p>
|
||||
</div>
|
||||
<div class="branch-field">
|
||||
<label>Средний рейтинг школы (для метрик)</label>
|
||||
<input type="text" name="branch_avg_rating" value="<?php echo esc_attr( get_option( 'branch_avg_rating', '4.9' ) ); ?>" style="width:100%;max-width:120px">
|
||||
<p class="desc">Отображается в блоке метрик на странице отзывов. Пример: 4.9</p>
|
||||
</div>
|
||||
<div class="branch-field">
|
||||
<label>Оставшиеся места (для триггера срочности)</label>
|
||||
<input type="number" name="branch_remaining_seats" value="<?php echo esc_attr( get_option( 'branch_remaining_seats', '12' ) ); ?>" style="width:100%;max-width:120px" min="0">
|
||||
<p class="desc">Отображается в финальном CTA на странице отзывов: «осталось N мест».</p>
|
||||
</div>
|
||||
<div class="branch-field">
|
||||
<label>Логотип организации (ID вложения)</label>
|
||||
<input type="number" name="branch_logo" value="<?php echo esc_attr( get_option( 'branch_logo', '' ) ); ?>" min="0" style="max-width:120px">
|
||||
<p class="desc">ID изображения из Медиафайлы. Для JSON-LD image.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="branch-section collapsed">
|
||||
<h2>⏰ РЕЖИМ РАБОТЫ</h2>
|
||||
<div class="branch-section-body">
|
||||
<div class="branch-field">
|
||||
<label>Режим работы школы</label>
|
||||
<input type="text" name="branch_hours" value="<?php echo esc_attr( get_option( 'branch_hours', 'ежедневно с 8:00 до 19:00, кроме воскресенья' ) ); ?>" style="width:100%;max-width:500px">
|
||||
<p class="desc">Текст с режимом работы. Появляется на странице отзывов после вступительного текста.</p>
|
||||
<label>Описание организации (для Schema.org)</label>
|
||||
<textarea name="branch_schema_description" rows="3" style="width:100%;max-width:500px"><?php echo esc_textarea( get_option( 'branch_schema_description', '' ) ); ?></textarea>
|
||||
<p class="desc">Появляется в сниппете Google и Яндекса как описание организации. Рекомендуется 1–2 предложения: тип школы, какие классы, особенности. Пример: «Частная школа полного дня в Щёлково. Обучение с 1 по 11 класс, подготовка к ЕГЭ и ОГЭ, индивидуальный подход.» Если пусто — собирается автоматически из названия и города филиала.</p>
|
||||
</div>
|
||||
<div class="branch-field">
|
||||
<label>Города присутствия (для Schema.org areaServed)</label>
|
||||
<input type="text" name="branch_area_served" value="<?php echo esc_attr( get_option( 'branch_area_served', 'Щёлково, Фрязино, Монино' ) ); ?>" style="width:100%;max-width:500px">
|
||||
<p class="desc">Города через запятую, где работает школа. Первым укажите город филиала. Влияет на локальный поиск — школа будет показываться жителям этих городов. Пример: <code>Щёлково, Фрязино, Монино, Ивантеевка, Королёв</code></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1922,6 +1953,11 @@ function dekart_branch_settings_page() {
|
||||
<label>Другая платформа (ссылка)</label>
|
||||
<input type="url" name="branch_ext_other_url" value="<?php echo esc_attr( get_option( 'branch_ext_other_url', '' ) ); ?>" style="width:100%;max-width:500px">
|
||||
</div>
|
||||
<div class="branch-field">
|
||||
<label>Количество отзывов на внешних площадках</label>
|
||||
<input type="number" name="branch_ext_review_count" value="<?php echo esc_attr( get_option( 'branch_ext_review_count', '247' ) ); ?>" style="width:100%;max-width:200px" min="0">
|
||||
<p class="desc">Отображается в бейдже под метриками: «4.9 из 5 на основе N отзывов на внешних площадках».</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -104,7 +104,7 @@ if ( is_front_page() ) {
|
||||
src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/images/phone-volume.svg"
|
||||
alt="Телефон" loading="lazy">
|
||||
</a>
|
||||
<a href="https://lk.dekart-school.ru/" target="_blank" rel="noopener noreferrer"
|
||||
<a href="<?php echo esc_url( carbon_get_theme_option( 'site_lk_url' ) ?: 'https://lk.dekart-school.ru/' ); ?>" target="_blank" rel="noopener noreferrer"
|
||||
aria-label="Личный кабинет">
|
||||
<img width="18" height="18"
|
||||
src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/images/icon-user-w.svg"
|
||||
@ -137,8 +137,8 @@ if ( is_front_page() ) {
|
||||
href="tel:<?php echo preg_replace('/[^0-9+]/', '', carbon_get_theme_option('site_phone')); ?>">
|
||||
<span><?php echo esc_html( carbon_get_theme_option('site_phone') ); ?></span>
|
||||
</a>
|
||||
<button class="btn-free-lesson-header btn-lilac desktop btn-write">
|
||||
<?php esc_html_e('Оставить заявку', 'dekart'); ?>
|
||||
<button class="btn-free-lesson-header btn-primary desktop btn-write">
|
||||
<?php esc_html_e('Записаться на бесплатное', 'dekart'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -158,14 +158,14 @@ if ( is_front_page() ) {
|
||||
'theme_location' => 'top',
|
||||
) );
|
||||
?>
|
||||
<button class="btn-free-lesson-header btn-lilac mobile btn-write">
|
||||
<?php esc_html_e('Записаться на визит', 'dekart'); ?>
|
||||
<button class="btn-free-lesson-header btn-primary mobile btn-write">
|
||||
<?php esc_html_e('Записаться на бесплатное', 'dekart'); ?>
|
||||
</button>
|
||||
<button class="btn-close-menu btn-close-header-menu mobile">
|
||||
<?php esc_html_e('ЗАКРЫТЬ МЕНЮ', 'dekart'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<a class="inter-lk desktop" href="https://lk.dekart-school.ru/" target="_blank" rel="noopener noreferrer">
|
||||
<a class="inter-lk desktop" href="<?php echo esc_url( carbon_get_theme_option( 'site_lk_url' ) ?: 'https://lk.dekart-school.ru/' ); ?>" target="_blank" rel="noopener noreferrer">
|
||||
<img width="18" height="23"
|
||||
src="<?php echo esc_url( get_template_directory_uri() ); ?>/assets/images/icon-user.svg"
|
||||
alt="Личный кабинет" loading="lazy">
|
||||
|
||||
1245
wp-content/themes/dekart/inc/schema.php
Normal file
1245
wp-content/themes/dekart/inc/schema.php
Normal file
File diff suppressed because it is too large
Load Diff
712
wp-content/themes/dekart/page-podgotovka-k-shkole.php
Normal file
712
wp-content/themes/dekart/page-podgotovka-k-shkole.php
Normal file
@ -0,0 +1,712 @@
|
||||
<?php
|
||||
/**
|
||||
* Template Name: Подготовка к школе (Bento 2026)
|
||||
*
|
||||
* Асимметричная Bento-сетка. Нейрокопирайтинг.
|
||||
* CSS: main.css (секции Bento/Social/Guarantee) + podgotovka-k-shkole.css (переопределения 2026)
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
get_header();
|
||||
$post_id = get_the_ID();
|
||||
|
||||
// ─── ДАННЫЕ ОРГАНИЗАЦИИ ───
|
||||
$opt_address = get_option( 'branch_address' ) ?: carbon_get_theme_option( 'site_address' ) ?: carbon_get_post_meta( $post_id, 'contact_address' ) ?: '';
|
||||
$opt_coords = get_option( 'branch_coords' ) ?: carbon_get_post_meta( $post_id, 'contact_location' ) ?: '';
|
||||
$opt_phone = get_option( 'branch_phone' ) ?: carbon_get_theme_option( 'site_phone' ) ?: carbon_get_post_meta( $post_id, 'contact_tel' ) ?: '';
|
||||
$opt_email = get_option( 'branch_email' ) ?: carbon_get_theme_option( 'site_mail' ) ?: carbon_get_post_meta( $post_id, 'contact_mail' ) ?: '';
|
||||
$opt_name = get_option( 'branch_name' ) ?: carbon_get_theme_option( 'site_name' ) ?: 'Декарт';
|
||||
$opt_social_raw = get_option( 'branch_social' ) ?: carbon_get_post_meta( $post_id, 'social_media' ) ?: [];
|
||||
?>
|
||||
|
||||
<main class="page page-pksh">
|
||||
|
||||
<?php get_template_part('template-parts/block-banner'); ?>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Social Proof — Confidence counters (4 cards) -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<?php
|
||||
$social_counters = carbon_get_post_meta( $post_id, 'pksh_social_counters' );
|
||||
$social_icons = array( '🎓', '📅', '⭐', '👩🏫' );
|
||||
?>
|
||||
<section class="bento pksh-section" aria-label="Социальное доказательство">
|
||||
<div class="bento__full">
|
||||
<div class="social-counters">
|
||||
<?php if ( ! empty( $social_counters ) ) : ?>
|
||||
<?php foreach ( $social_counters as $i => $counter ) :
|
||||
$icon = isset( $social_icons[ $i ] ) ? $social_icons[ $i ] : '✅';
|
||||
$number = $counter['counter_number'] ?? '';
|
||||
$label = $counter['counter_label'] ?? '';
|
||||
if ( empty( $number ) ) continue;
|
||||
?>
|
||||
<div class="social-counter">
|
||||
<div class="social-counter__top"></div>
|
||||
<div class="social-counter__body">
|
||||
<span class="social-counter__icon"><?php echo esc_html( $icon ); ?></span>
|
||||
<div class="social-counter__number"><?php echo esc_html( $number ); ?></div>
|
||||
<div class="social-counter__label"><?php echo esc_html( $label ); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else : ?>
|
||||
<!-- Fallback, если поля не заполнены -->
|
||||
<div class="social-counter">
|
||||
<div class="social-counter__top"></div>
|
||||
<div class="social-counter__body">
|
||||
<span class="social-counter__icon">🎓</span>
|
||||
<div class="social-counter__number">500+</div>
|
||||
<div class="social-counter__label">выпускников в топ-школах</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="social-counter">
|
||||
<div class="social-counter__top"></div>
|
||||
<div class="social-counter__body">
|
||||
<span class="social-counter__icon">📅</span>
|
||||
<div class="social-counter__number">12</div>
|
||||
<div class="social-counter__label">лет готовим к школе</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="social-counter">
|
||||
<div class="social-counter__top"></div>
|
||||
<div class="social-counter__body">
|
||||
<span class="social-counter__icon">⭐</span>
|
||||
<div class="social-counter__number">4.8</div>
|
||||
<div class="social-counter__label">средняя оценка родителей</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="social-counter">
|
||||
<div class="social-counter__top"></div>
|
||||
<div class="social-counter__body">
|
||||
<span class="social-counter__icon">👩🏫</span>
|
||||
<div class="social-counter__number">20+</div>
|
||||
<div class="social-counter__label">опытных педагогов</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Micro-Commitment: Checklist download -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section" aria-label="Скачать чек-лист">
|
||||
<div class="bento__full">
|
||||
<div class="micro-commit">
|
||||
<div class="micro-commit__content">
|
||||
<span class="bento-label">Бесплатно</span>
|
||||
<h2 class="bento-h2">Скачайте чек-лист готовности к школе</h2>
|
||||
<p class="bento-p">10 признаков, что ваш ребёнок готов к 1-му классу. Проверьте за 5 минут — и узнайте, на какие навыки обратить внимание.</p>
|
||||
<button class="btn-primary btn-write micro-commit__btn">Получить чек-лист бесплатно</button>
|
||||
<p class="micro-commit__disclaimer">Отправляя заявку, вы соглашаетесь на обработку персональных данных</p>
|
||||
</div>
|
||||
<div class="micro-commit__visual">
|
||||
<svg class="micro-commit__svg" viewBox="0 0 130 170" fill="none" aria-hidden="true">
|
||||
<!-- Paper background -->
|
||||
<rect x="8" y="4" width="114" height="162" rx="8" fill="white" stroke="#DED3C0" stroke-width="1.2"/>
|
||||
<!-- Header line -->
|
||||
<rect x="24" y="20" width="82" height="4" rx="2" fill="#7C3AED" opacity="0.15"/>
|
||||
<!-- Checklist items -->
|
||||
<rect x="24" y="38" width="12" height="12" rx="3" fill="#7C3AED" opacity="0.15"/>
|
||||
<path d="M26 44l3 3 5-5" stroke="#7C3AED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" opacity="0.4"/>
|
||||
<rect x="44" y="40" width="50" height="3" rx="1.5" fill="#DED3C0" opacity="0.6"/>
|
||||
|
||||
<rect x="24" y="62" width="12" height="12" rx="3" fill="#7C3AED" opacity="0.15"/>
|
||||
<path d="M26 68l3 3 5-5" stroke="#7C3AED" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" opacity="0.4"/>
|
||||
<rect x="44" y="64" width="62" height="3" rx="1.5" fill="#DED3C0" opacity="0.6"/>
|
||||
|
||||
<rect x="24" y="86" width="12" height="12" rx="3" fill="#7C3AED" opacity="0.15"/>
|
||||
<rect x="44" y="88" width="42" height="3" rx="1.5" fill="#DED3C0" opacity="0.6"/>
|
||||
|
||||
<rect x="24" y="110" width="12" height="12" rx="3" fill="#7C3AED" opacity="0.15"/>
|
||||
<rect x="44" y="112" width="56" height="3" rx="1.5" fill="#DED3C0" opacity="0.6"/>
|
||||
|
||||
<!-- Pencil illustration -->
|
||||
<g transform="translate(92, 130) rotate(-30)">
|
||||
<rect x="0" y="0" width="6" height="28" rx="1" fill="#7C3AED" opacity="0.12"/>
|
||||
<polygon points="0,0 6,0 3,-6" fill="#7C3AED" opacity="0.15"/>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Guarantee Hero (Risk Reversal Showcase) -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section pksh-section--alt" aria-label="Гарантия">
|
||||
<div class="bento__full">
|
||||
<div class="guarantee-hero">
|
||||
<div class="guarantee-hero__badges">
|
||||
<div class="guarantee-hero__shield">🛡️</div>
|
||||
</div>
|
||||
<div class="guarantee-hero__content">
|
||||
<h2 class="bento-h2">Ваш ребёнок начнёт читать через 3 недели</h2>
|
||||
<p class="guarantee-hero__text">Или <strong>мы вернём деньги</strong> и продолжим обучение бесплатно, пока не дойдём до результата. Мы — частная школа <strong>с гослицензией</strong>, а не кружок. Отвечаем за результат.</p>
|
||||
<button class="btn-primary btn-write guarantee-hero__btn">Записаться на бесплатное пробное</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Anchor Navigation — jump links -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<nav class="pksh-anchor-nav" aria-label="Навигация по странице">
|
||||
<a href="#how-it-works" class="pksh-anchor-link">Как проходят занятия</a>
|
||||
<a href="#results" class="pksh-anchor-link">Результаты</a>
|
||||
<a href="#programs" class="pksh-anchor-link">Программы</a>
|
||||
<a href="#teachers" class="pksh-anchor-link">Преподаватели</a>
|
||||
<a href="#faq" class="pksh-anchor-link">Вопросы</a>
|
||||
</nav>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Bento Row 1: How it works + Why us -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section" id="how-it-works" aria-label="Как проходят занятия">
|
||||
<div class="bento__half bento-card bento-card--soft">
|
||||
<span class="bento-label">Как проходит занятие</span>
|
||||
<h2 class="bento-h2">30 минут игры = 1 шаг к школе</h2>
|
||||
<p class="bento-p">Никаких скучных прописей. Каждое занятие построено так, что ребёнок <strong>сам хочет</strong> вернуться.</p>
|
||||
<div class="steps-3">
|
||||
<div class="step">
|
||||
<span class="step__num">1</span>
|
||||
<div>
|
||||
<strong>Вход в тему</strong>
|
||||
<span>Короткая история или загадка — включаем интерес</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<span class="step__num">2</span>
|
||||
<div>
|
||||
<strong>Игровое задание</strong>
|
||||
<span>Чтение, счёт, логика — через механику игры</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<span class="step__num">3</span>
|
||||
<div>
|
||||
<strong>Рефлексия</strong>
|
||||
<span>Ребёнок сам рассказывает, чему научился</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bento__half bento-card bento-card--objections">
|
||||
<span class="bento-label">Почему родители выбирают нас</span>
|
||||
<h2 class="bento-h2">Три главных вопроса — честные ответы</h2>
|
||||
<div class="objection-list">
|
||||
<div class="objection-item">
|
||||
<div class="objection-item__icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Не перегрузят ли ребёнка?</strong>
|
||||
<p>Занятия по 30–40 минут. Каждые 7 минут — смена активности. Ребёнок не устаёт.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="objection-item">
|
||||
<div class="objection-item__icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Успеем ли до сентября?</strong>
|
||||
<p>Да. Наша программа рассчитана на 4–6 месяцев. Первые результаты — через 3 недели.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="objection-item">
|
||||
<div class="objection-item__icon">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none"><path d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
|
||||
</div>
|
||||
<div>
|
||||
<strong>Дорого?</strong>
|
||||
<p>От 600 ₽ за занятие. Первое — бесплатно. А если не понравится — вернём деньги.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Bento Row 2: Results / Data -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section pksh-section--alt" id="results" aria-label="Результаты учеников">
|
||||
<div class="bento__full bento-card bento-card--highlight-results">
|
||||
<span class="bento-label bento-label--light">Результаты наших учеников</span>
|
||||
<h2 class="bento-h2 bento-h2--light">К чему мы приводим детей</h2>
|
||||
<div class="results-grid">
|
||||
<div class="result-item">
|
||||
<span class="result-item__value">95%</span>
|
||||
<span class="result-item__desc">поступают в школы и лицеи Щёлкова без стресса</span>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<span class="result-item__value">3 нед.</span>
|
||||
<span class="result-item__desc">— первый осмысленный слог у нечитавших детей</span>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<span class="result-item__value">87%</span>
|
||||
<span class="result-item__desc">родителей отмечают рост самостоятельности</span>
|
||||
</div>
|
||||
<div class="result-item">
|
||||
<span class="result-item__value">2,5×</span>
|
||||
<span class="result-item__desc">быстрее адаптируются в первом классе</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Bento Row 3: Programs / Курсы -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section" id="programs" aria-label="Программы подготовки">
|
||||
<div class="bento__full">
|
||||
<span class="bento-label">Программы</span>
|
||||
<h2 class="bento-h2">Выберите формат подготовки</h2>
|
||||
<p class="bento-p">Все программы ведут действующие педагоги начальных классов.
|
||||
Группы до 8 человек — каждому ребёнку уделяем внимание.</p>
|
||||
|
||||
<div class="programs-grid">
|
||||
<?php
|
||||
$pksh_programs = carbon_get_post_meta($post_id, 'pksh_programs');
|
||||
if (is_array($pksh_programs) && !empty($pksh_programs)) :
|
||||
foreach ($pksh_programs as $program) :
|
||||
$icon = $program['program_icon'] ?? '🎓';
|
||||
$title = $program['program_title'] ?? '';
|
||||
$intensity = $program['program_intensity'] ?? '';
|
||||
$schedule_raw = $program['program_schedule'] ?? '';
|
||||
$duration = $program['program_duration'] ?? '90 мин';
|
||||
$structure_raw = $program['program_lesson_structure'] ?? '';
|
||||
$includes_raw = $program['program_includes'] ?? '';
|
||||
$price_sub = $program['program_price_subscription'] ?? '';
|
||||
$price_single = $program['program_price_single'] ?? '';
|
||||
$btn_text = $program['program_button_text'] ?? 'Записаться';
|
||||
$btn_url = $program['program_button_url'] ?? '/zapis/';
|
||||
|
||||
$schedule_lines = array_filter(explode("\n", $schedule_raw));
|
||||
$structure_lines = array_filter(explode("\n", $structure_raw));
|
||||
$includes_lines = array_filter(explode("\n", $includes_raw));
|
||||
?>
|
||||
<div class="program-card">
|
||||
<div class="program-card__header">
|
||||
<span class="program-card__icon"><?php echo esc_html($icon); ?></span>
|
||||
<h3 class="program-card__title"><?php echo esc_html($title); ?></h3>
|
||||
</div>
|
||||
|
||||
<div class="program-card__body">
|
||||
|
||||
<?php if ($intensity) : ?>
|
||||
<div class="program-card__intensity">
|
||||
<span class="program-card__label">Интенсивность:</span>
|
||||
<?php echo esc_html($intensity); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($schedule_lines)) : ?>
|
||||
<div class="program-card__schedule">
|
||||
<span class="program-card__label">📅 Расписание:</span>
|
||||
<ul>
|
||||
<?php foreach ($schedule_lines as $line) : ?>
|
||||
<li><?php echo esc_html(trim($line)); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($structure_lines) || $duration) : ?>
|
||||
<div class="program-card__structure">
|
||||
<span class="program-card__label">⏱ Структура занятия (<?php echo esc_html($duration); ?>):</span>
|
||||
<ul class="program-card__timeline">
|
||||
<?php foreach ($structure_lines as $line) : ?>
|
||||
<?php
|
||||
$line = trim($line);
|
||||
// Parse "15 мин 🧠 Нейрогимнастика" into time and name
|
||||
$parts = explode(' ', $line, 2);
|
||||
$time_part = $parts[0] ?? '';
|
||||
$name_part = $parts[1] ?? $line;
|
||||
?>
|
||||
<li class="program-card__timeline-item">
|
||||
<span class="program-card__timeline-badge"><?php echo esc_html($time_part); ?></span>
|
||||
<span class="program-card__timeline-name"><?php echo esc_html($name_part); ?></span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($includes_lines)) : ?>
|
||||
<div class="program-card__includes">
|
||||
<span class="program-card__label">Программа включает:</span>
|
||||
<ul>
|
||||
<?php foreach ($includes_lines as $line) : ?>
|
||||
<li><?php echo esc_html(trim($line)); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($price_sub || $price_single) : ?>
|
||||
<div class="program-card__pricing">
|
||||
<?php if ($price_sub) : ?>
|
||||
<div class="program-card__price-main">
|
||||
<span class="program-card__price-value"><?php echo esc_html($price_sub); ?></span>
|
||||
<span class="program-card__price-period">за 4 недели</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($price_single) : ?>
|
||||
<div class="program-card__price-single">
|
||||
<?php echo esc_html($price_single); ?> за одно занятие (вне абонемента)
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<a href="<?php echo esc_url($btn_url); ?>" class="program-card__btn">
|
||||
<?php echo esc_html($btn_text); ?>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
else :
|
||||
// Fallback, если программы не заполнены в админке
|
||||
?>
|
||||
<div class="program-card">
|
||||
<div class="program-card__header">
|
||||
<span class="program-card__icon">📖</span>
|
||||
<h3 class="program-card__title">Базовая программа</h3>
|
||||
</div>
|
||||
<div class="program-card__body">
|
||||
<p style="color: #94a3b8; font-style: italic;">Заполните программы в админке → Настройки Подготовки к школе → Программы</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="programs-note">
|
||||
<p>Первое пробное занятие — <strong>бесплатно</strong>. При покупке абонемента на месяц — скидка 10%.
|
||||
<a href="#final-cta" class="programs-note__link">Записаться на бесплатное пробное</a></p>
|
||||
</div>
|
||||
<div class="pksh-fomo">
|
||||
<span class="pksh-fomo__dot"></span>
|
||||
<span class="pksh-fomo__text">🔥 4 из 8 мест в группе 5–6 лет <strong>уже заняты</strong>. Успейте записаться!</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Bento Row 4: Schedule & Price -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<?php get_template_part('template-parts/block-price'); ?>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Bento Row 4: Teachers (camp-style cards) -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section pksh-section--teachers" id="teachers" aria-label="Преподаватели">
|
||||
<div class="bento__full">
|
||||
<h2 class="bento-h2">Наши преподаватели</h2>
|
||||
<div class="pksh-teachers__scroll-x">
|
||||
<div class="pksh-teachers__wrapper">
|
||||
<?php
|
||||
$pksh_teachers = carbon_get_post_meta(get_the_ID(), 'pksh_teachers');
|
||||
if (is_array($pksh_teachers) && !empty($pksh_teachers)) :
|
||||
foreach ($pksh_teachers as $item) :
|
||||
$t_name = $item['teacher_name'] ?? '';
|
||||
$t_photo = $item['teacher_photo'] ?? 0;
|
||||
$t_subj = $item['teacher_subject'] ?? '';
|
||||
$t_about = $item['teacher_about'] ?? '';
|
||||
?>
|
||||
<div class="pksh-teachers__item">
|
||||
<div class="pksh-teachers__card">
|
||||
<div class="pksh-teachers__card-top">
|
||||
<?php if ($t_photo) : ?>
|
||||
<img class="pksh-teachers__photo" loading="lazy" width="130" height="130"
|
||||
src="<?php echo esc_url(wp_get_attachment_url($t_photo)); ?>"
|
||||
alt="<?php echo esc_attr($t_name); ?>">
|
||||
<?php else : ?>
|
||||
<img class="pksh-teachers__photo" loading="lazy" width="130" height="130"
|
||||
src="<?php echo get_template_directory_uri(); ?>/assets/images/no-photo.png"
|
||||
alt="<?php echo esc_attr($t_name); ?>">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="pksh-teachers__card-body">
|
||||
<h3 class="pksh-teachers__name"><?php echo esc_html($t_name); ?></h3>
|
||||
<?php if ($t_subj) : ?>
|
||||
<p class="pksh-teachers__subj"><?php echo esc_html($t_subj); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ($t_about) : ?>
|
||||
<p class="pksh-teachers__about"><?php echo esc_html($t_about); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
endforeach;
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Bento Row 5: Guarantee (standalone) -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section pksh-section--alt" id="guarantee" aria-label="Гарантия">
|
||||
<div class="bento__full">
|
||||
<div class="guarantee-block guarantee-block--centered">
|
||||
<h2 class="bento-h2">🛡️ Гарантия результата</h2>
|
||||
<p class="guarantee-block__text">
|
||||
Если через 3 месяца ваш ребёнок не начнёт читать —
|
||||
мы вернём деньги <strong>и продолжим обучение бесплатно</strong>,
|
||||
пока не дойдём до результата.
|
||||
</p>
|
||||
<span class="guarantee-block__badge">Так работают только те, кто уверен в своём методе</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Bento Row 6: FAQ (как на странице лагеря) -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section pksh-section--alt" id="faq" aria-label="Вопросы и ответы">
|
||||
<div class="bento__full pksh-faq">
|
||||
<h2 class="bento-h2">Часто задаваемые вопросы</h2>
|
||||
<?php
|
||||
$faq_items = carbon_get_post_meta($post_id, 'pksh_faq_items');
|
||||
if (!empty($faq_items) && is_array($faq_items)) :
|
||||
$col1 = '';
|
||||
$col2 = '';
|
||||
$count = 0;
|
||||
foreach ($faq_items as $item) :
|
||||
$q = $item['faq_question'] ?? '';
|
||||
$a = $item['faq_answer'] ?? '';
|
||||
if (empty($q) && empty($a)) continue;
|
||||
$accordion = '<div class="box__accordion">'
|
||||
. '<div class="box__accordion_label" role="button" tabindex="0">'
|
||||
. '<span>' . esc_html($q) . '</span>'
|
||||
. '<svg role="presentation" focusable="false" width="24px" height="24px" viewBox="0 0 24 24">'
|
||||
. '<g stroke="none" stroke-width="2px" fill="none" fill-rule="evenodd" stroke-linecap="square">'
|
||||
. '<g transform="translate(1.000000, 1.000000)" stroke="currentColor">'
|
||||
. '<path d="M0,11 L22,11"></path>'
|
||||
. '<path d="M11,0 L11,22"></path>'
|
||||
. '</g></g></svg></div>'
|
||||
. '<div class="box__accordion_content">'
|
||||
. '<div class="box__accordion_content-text">' . wp_kses_post($a) . '</div>'
|
||||
. '</div></div>';
|
||||
if ($count % 2 === 0) {
|
||||
$col1 .= $accordion;
|
||||
} else {
|
||||
$col2 .= $accordion;
|
||||
}
|
||||
$count++;
|
||||
endforeach;
|
||||
if (!empty($col1) || !empty($col2)) :
|
||||
?>
|
||||
<div class="pksh-faq__wrapper">
|
||||
<div class="pksh-faq__col"><?php echo $col1; ?></div>
|
||||
<div class="pksh-faq__col"><?php echo $col2; ?></div>
|
||||
</div>
|
||||
<?php endif; endif; ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Reviews (lw-card inline, camp-style) -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="pksh-reviews" id="pksh-reviews" aria-label="Отзывы">
|
||||
<h2 class="bento-h2">Что говорят родители</h2>
|
||||
|
||||
<?php
|
||||
$review_items = carbon_get_post_meta($post_id, 'pksh_reviews_list');
|
||||
$total_count = is_array($review_items) ? count($review_items) : 0;
|
||||
if ($total_count > 0) :
|
||||
$items = array_values($review_items);
|
||||
$render_card = function($item) {
|
||||
$author = $item['review_author'] ?? '';
|
||||
$text = $item['review_text'] ?? '';
|
||||
$raw_rating = $item['review_rating'] ?? '';
|
||||
$avatar_id = !empty($item['review_avatar']) ? (int)$item['review_avatar'] : 0;
|
||||
$stars = max(1, min(5, (int)$raw_rating));
|
||||
$name = $author ?: 'Анонимно';
|
||||
if (empty($text)) return '';
|
||||
ob_start();
|
||||
?>
|
||||
<div class="lw-card">
|
||||
<div class="lw-flex lw-flex--row lw-gap-12 lw-items-center">
|
||||
<div class="lw-avatar lw-avatar--48">
|
||||
<?php if ($avatar_id && wp_attachment_is_image($avatar_id)) : ?>
|
||||
<?php echo wp_get_attachment_image($avatar_id, [48, 48], false, ['class' => 'lw-avatar__img', 'loading' => 'lazy', 'alt' => esc_attr($name)]); ?>
|
||||
<?php else : ?>
|
||||
<img class="lw-avatar__img" src="https://ui-avatars.com/api/?name=<?php echo urlencode($name); ?>&background=random&color=fff&size=96" alt="<?php echo esc_attr($name); ?>" loading="lazy" width="48" height="48">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="lw-flex lw-flex--col">
|
||||
<div class="lw-text-dark lw-font-semibold"><?php echo esc_html($name); ?></div>
|
||||
</div>
|
||||
<div class="lw-badge lw-badge--verified">Проверенный отзыв</div>
|
||||
</div>
|
||||
<div class="lw-stars lw-mt-8">
|
||||
<?php for ($i = 1; $i <= 5; $i++) : ?>
|
||||
<svg class="lw-star <?php echo $i <= $stars ? 'lw-star--filled' : ''; ?>" width="16" height="16" viewBox="0 0 21 19" fill="none">
|
||||
<path d="M9.58463 1.50884C9.89101 0.602477 11.1729 0.602476 11.4793 1.50884L13.1158 6.35007C13.2531 6.75637 13.6343 7.02985 14.0631 7.02985H19.2721C20.2504 7.02985 20.6467 8.28958 19.8447 8.84971L15.6995 11.7446C15.335 11.9991 15.1823 12.4636 15.3247 12.8847L16.9239 17.6158C17.233 18.5302 16.1954 19.3085 15.404 18.7559L11.1045 15.7533C10.7606 15.5131 10.3033 15.5131 9.95941 15.7533L5.65991 18.7559C4.86857 19.3085 3.83092 18.5302 4.14001 17.6158L5.73926 12.8847C5.8816 12.4636 5.72891 11.9991 5.36448 11.7446L1.21924 8.84971C0.417196 8.28958 0.813532 7.02985 1.79181 7.02985H7.00081C7.42969 7.02985 7.81081 6.75637 7.94815 6.35007L9.58463 1.50884Z" fill="currentColor"/>
|
||||
</svg>
|
||||
<?php endfor; ?>
|
||||
</div>
|
||||
<div class="lw-card__text lw-mt-8"><?php echo wp_kses_post($text); ?></div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
};
|
||||
?>
|
||||
<div class="lw-scroll-x" data-pksh-reviews>
|
||||
<div class="lw-grid lw-grid--3 lw-gap-20" data-pksh-grid data-pksh-collapsed>
|
||||
<?php foreach ($items as $item) echo $render_card($item); ?>
|
||||
</div>
|
||||
<?php if ($total_count > 4) : ?>
|
||||
<div class="pksh-reviews__actions">
|
||||
<button class="pksh-reviews__toggle" data-pksh-toggle type="button">Показать ещё</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<script>
|
||||
(function(){
|
||||
var grid = document.querySelector('[data-pksh-grid]');
|
||||
var toggle = document.querySelector('[data-pksh-toggle]');
|
||||
if (!grid || !toggle) return;
|
||||
toggle.addEventListener('click', function(){
|
||||
var expanded = grid.hasAttribute('data-pksh-expanded');
|
||||
if (expanded) {
|
||||
grid.removeAttribute('data-pksh-expanded');
|
||||
grid.setAttribute('data-pksh-collapsed', '');
|
||||
toggle.textContent = 'Показать ещё';
|
||||
} else {
|
||||
grid.removeAttribute('data-pksh-collapsed');
|
||||
grid.setAttribute('data-pksh-expanded', '');
|
||||
toggle.textContent = 'Скрыть';
|
||||
}
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Final CTA — Low Friction -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section pksh-section--alt" id="final-cta" aria-label="Запись">
|
||||
<div class="bento__full">
|
||||
<div class="final-cta">
|
||||
<h2 class="bento-h2">Первое занятие — бесплатно</h2>
|
||||
<p class="final-cta__text">Ребёнок познакомится с педагогом, попробует задания. Вы увидите методику своими глазами. Никакой оплаты и договоров.</p>
|
||||
|
||||
<!-- Форма открывается в модалке (footer.php) — скрипт из вкладки Битрикс24 в админке -->
|
||||
|
||||
<button class="btn-primary btn-primary--large open-bitrix-form btn-write">Записаться на бесплатное пробное</button>
|
||||
<p class="final-cta__footnote">🔥 Осталось 2 места в группе 5–6 лет. Успейте!</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<!-- Contacts — как на странице лагеря -->
|
||||
<!-- ════════════════════════════════════════════ -->
|
||||
<section class="bento pksh-section" id="pksh-contact" aria-label="Контакты">
|
||||
<div class="bento__full pksh-contact">
|
||||
<h2 class="bento-h2">Наш адрес</h2>
|
||||
<div class="pksh-contact__wrapper">
|
||||
<div class="pksh-contact__info">
|
||||
<?php if (!empty($opt_phone)) : ?>
|
||||
<div class="pksh-contact__subtitle">Телефон:</div>
|
||||
<a class="pksh-contact__value" href="tel:+<?php echo preg_replace('/[^0-9]/', '', $opt_phone); ?>"><?php echo esc_html($opt_phone); ?></a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($opt_email)) : ?>
|
||||
<div class="pksh-contact__subtitle">Почта:</div>
|
||||
<a class="pksh-contact__value" href="mailto:<?php echo esc_attr($opt_email); ?>"><?php echo esc_html($opt_email); ?></a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($opt_address)) : ?>
|
||||
<div class="pksh-contact__subtitle">Адрес:</div>
|
||||
<div class="pksh-contact__value"><?php echo esc_html($opt_address); ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($opt_social_raw) && is_array($opt_social_raw)) : ?>
|
||||
<div class="pksh-contact__subtitle">Наши соцсети:</div>
|
||||
<div class="pksh-contact__social">
|
||||
<?php foreach ($opt_social_raw as $item) :
|
||||
$link = $item['url'] ?? '';
|
||||
$name = $item['name'] ?? '';
|
||||
if ($link) : ?>
|
||||
<a class="pksh-contact__social-link" href="<?php echo esc_url($link); ?>" target="_blank" rel="noopener noreferrer" title="<?php echo esc_attr($name); ?>">
|
||||
<?php echo esc_html($name ?: $link); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="pksh-contact__map">
|
||||
<div id="ya-map" style="width: 100%; height: 100%; min-height: 400px;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
var mapCoords = [<?php echo esc_js($opt_coords ?: '55.7558,37.6173'); ?>];
|
||||
var mapLabel = '<?php echo esc_js($opt_name); ?>';
|
||||
var mapLoaded = false;
|
||||
var apiLoading = false;
|
||||
|
||||
function initMap() {
|
||||
ymaps.ready(function() {
|
||||
var map = new ymaps.Map('ya-map', {
|
||||
center: mapCoords,
|
||||
zoom: 16
|
||||
}, {
|
||||
searchControlProvider: 'yandex#search'
|
||||
});
|
||||
var placemark = new ymaps.Placemark(
|
||||
mapCoords,
|
||||
{ iconContent: mapLabel },
|
||||
{ preset: 'islands#redStretchyIcon' }
|
||||
);
|
||||
map.geoObjects.add(placemark);
|
||||
mapLoaded = true;
|
||||
});
|
||||
}
|
||||
|
||||
function loadYandexMaps() {
|
||||
if (mapLoaded || apiLoading) return;
|
||||
apiLoading = true;
|
||||
var script = document.createElement('script');
|
||||
script.src = 'https://api-maps.yandex.ru/2.1/?lang=ru_RU';
|
||||
script.onload = initMap;
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
|
||||
function onScroll() {
|
||||
if ((window.pageYOffset || document.documentElement.scrollTop) > 100) {
|
||||
loadYandexMaps();
|
||||
window.removeEventListener('scroll', onScroll);
|
||||
}
|
||||
}
|
||||
window.addEventListener('load', function() {
|
||||
setTimeout(function() {
|
||||
if (!mapLoaded && !apiLoading) loadYandexMaps();
|
||||
}, 3000);
|
||||
});
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
})();
|
||||
</script>
|
||||
|
||||
</main>
|
||||
|
||||
<?php
|
||||
get_footer();
|
||||
@ -21,9 +21,12 @@ add_filter( 'wpseo_opengraph_type', function ( $type ) {
|
||||
add_filter( 'wpseo_frontend_presenter_classes', function ( $presenters ) {
|
||||
if ( is_page_template( 'page-reviews.php' ) ) {
|
||||
$presenters = array_filter( $presenters, function ( $p ) {
|
||||
return strpos( $p, 'Article_' ) === false
|
||||
// Open_Graph + Twitter — отключаем весь блок OG/Twitter-тегов Yoast, т.к. выводим свои
|
||||
return strpos( $p, 'Open_Graph' ) === false
|
||||
&& strpos( $p, 'Article_' ) === false
|
||||
&& strpos( $p, 'Label1' ) === false
|
||||
&& strpos( $p, 'Data1' ) === false;
|
||||
&& strpos( $p, 'Data1' ) === false
|
||||
&& strpos( $p, 'Twitter' ) === false;
|
||||
} );
|
||||
}
|
||||
return $presenters;
|
||||
@ -39,8 +42,10 @@ add_action( 'wp_head', function () {
|
||||
$post_id = get_queried_object_id();
|
||||
$thumb_id = get_post_thumbnail_id( $post_id );
|
||||
|
||||
// Preconnect для Phosphor Icons (CDN)
|
||||
// Preconnect + preload для Phosphor Icons (CDN, render-blocking → отложенная загрузка)
|
||||
echo '<link rel="preconnect" href="https://unpkg.com" crossorigin />' . "\n";
|
||||
echo '<link rel="preload" as="style" href="https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css" onload="this.onload=null;this.rel=\'stylesheet\'">' . "\n";
|
||||
echo '<noscript><link rel="stylesheet" href="https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css"></noscript>' . "\n";
|
||||
|
||||
$og_title = wp_get_document_title();
|
||||
$og_description = get_post_meta( $post_id, '_yoast_wpseo_metadesc', true ) ?: get_bloginfo( 'description' );
|
||||
@ -68,8 +73,17 @@ add_action( 'wp_head', function () {
|
||||
echo '<meta property="og:description" content="' . esc_attr( $og_description ) . '" />' . "\n";
|
||||
echo '<meta property="og:url" content="' . esc_url( $og_url ) . '" />' . "\n";
|
||||
echo '<meta property="og:type" content="' . esc_attr( $og_type ) . '" />' . "\n";
|
||||
echo '<meta property="og:site_name" content="' . esc_attr( get_bloginfo( 'name' ) ) . '" />' . "\n";
|
||||
$og_site_name = get_option( 'branch_og_site_name' ) ?: sprintf( 'Частная школа %s %s', get_option( 'branch_name', 'Декарт' ), get_option( 'branch_city_prep', 'в Щёлково' ) );
|
||||
echo '<meta property="og:site_name" content="' . esc_attr( $og_site_name ) . '" />' . "\n";
|
||||
echo '<meta property="og:locale" content="ru_RU" />' . "\n";
|
||||
|
||||
// Twitter Card (из того же featured image)
|
||||
echo '<meta name="twitter:card" content="summary_large_image" />' . "\n";
|
||||
echo '<meta name="twitter:title" content="' . esc_attr( $og_title ) . '" />' . "\n";
|
||||
echo '<meta name="twitter:description" content="' . esc_attr( $og_description ) . '" />' . "\n";
|
||||
if ( $thumb_id && $img_data ) {
|
||||
echo '<meta name="twitter:image" content="' . esc_url( $img_data[0] ) . '" />' . "\n";
|
||||
}
|
||||
}, 1 );
|
||||
|
||||
// Критический CSS для LCP вынесен в assets/css/reviews-page.css.
|
||||
@ -96,15 +110,15 @@ $branch_messengers = get_option( 'branch_messengers', array() );
|
||||
|
||||
// ─── КОНТЕНТ СТРАНИЦЫ (Carbon Fields post_meta) ───
|
||||
|
||||
// Метрики доверия
|
||||
$metric_1_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_1_number' ) ?: '500+';
|
||||
$metric_1_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_1_label' ) ?: 'счастливых семей';
|
||||
$metric_2_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_2_number' ) ?: '12+';
|
||||
$metric_2_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_2_label' ) ?: 'лет в образовании';
|
||||
$metric_3_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_3_number' ) ?: '4.9';
|
||||
$metric_3_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_3_label' ) ?: 'рейтинг на Яндексе';
|
||||
$metric_4_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_4_number' ) ?: '14';
|
||||
$metric_4_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_4_label' ) ?: 'отзывов о школе';
|
||||
// Метрики доверия (только из Carbon Fields — никаких хардкод-значений)
|
||||
$metric_1_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_1_number' );
|
||||
$metric_1_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_1_label' );
|
||||
$metric_2_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_2_number' );
|
||||
$metric_2_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_2_label' );
|
||||
$metric_3_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_3_number' );
|
||||
$metric_3_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_3_label' );
|
||||
$metric_4_num = carbon_get_post_meta( $post_id, 'reviews_hero_metric_4_number' );
|
||||
$metric_4_lbl = carbon_get_post_meta( $post_id, 'reviews_hero_metric_4_label' );
|
||||
|
||||
// Результаты
|
||||
$results_title = carbon_get_post_meta( $post_id, 'reviews_results_title' ) ?: 'Декарт в цифрах';
|
||||
@ -140,15 +154,47 @@ if ( ! $jsonld_img_url ) {
|
||||
$jsonld_img_url = $logo_id ? wp_get_attachment_url( $logo_id ) : '';
|
||||
}
|
||||
|
||||
// ─── СОЦСЕТИ ДЛЯ JSON-LD ───
|
||||
// ─── ИЗОБРАЖЕНИЕ ШКОЛЫ ДЛЯ JSON-LD (image) ───
|
||||
// Используем featured image главной страницы (page_on_front).
|
||||
// Schema.org рекомендует минимум 696px ширины.
|
||||
$school_image_url = '';
|
||||
$front_page_id = (int) get_option( 'page_on_front' );
|
||||
if ( $front_page_id && has_post_thumbnail( $front_page_id ) ) {
|
||||
$img_data = wp_get_attachment_image_src( get_post_thumbnail_id( $front_page_id ), 'full' );
|
||||
if ( $img_data && $img_data[1] >= 696 ) {
|
||||
$school_image_url = $img_data[0];
|
||||
}
|
||||
}
|
||||
|
||||
// ─── СОЦСЕТИ ДЛЯ JSON-LD (sameAs) ───
|
||||
$jsonld_social = array();
|
||||
|
||||
// 1. branch_social (Settings API) — формат: [['name' => 'VK', 'url' => 'https://...']]
|
||||
// или CF social_media fallback: [['social_media_name' => '', 'social_media_link' => 'https://...']]
|
||||
if ( is_array( $branch_social ) ) {
|
||||
foreach ( $branch_social as $s ) {
|
||||
// Settings API: ['name', 'url']
|
||||
if ( ! empty( $s['url'] ) ) {
|
||||
$jsonld_social[] = $s['url'];
|
||||
}
|
||||
// CF theme option social_media: ['social_media_name', 'social_media_link']
|
||||
if ( ! empty( $s['social_media_link'] ) ) {
|
||||
$jsonld_social[] = $s['social_media_link'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. branch_messengers — мессенджеры (WhatsApp, Telegram) тоже в sameAs
|
||||
if ( is_array( $branch_messengers ) ) {
|
||||
foreach ( $branch_messengers as $m ) {
|
||||
if ( ! empty( $m['url'] ) ) {
|
||||
$jsonld_social[] = $m['url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Удаляем дубликаты (если VK есть и в соцсетях, и в мессенджерах)
|
||||
$jsonld_social = array_values( array_unique( $jsonld_social ) );
|
||||
?>
|
||||
<main class="page-reviews">
|
||||
|
||||
@ -181,33 +227,39 @@ if ( is_array( $branch_social ) ) {
|
||||
<h1 class="reviews-hero__h1">Отзывы о частной школе «Декарт» <?php echo esc_html( $branch_city_prep ); ?></h1>
|
||||
<p class="reviews-hero__subtitle">Родители доверяют нам самое главное — вот что они говорят о нас</p>
|
||||
|
||||
<?php
|
||||
// Собираем только те метрики, которые заполнены в админке (и число, и подпись)
|
||||
$hero_metrics = array();
|
||||
if ( $metric_1_num && $metric_1_lbl ) {
|
||||
$hero_metrics[] = array( 'num' => $metric_1_num, 'lbl' => $metric_1_lbl );
|
||||
}
|
||||
if ( $metric_2_num && $metric_2_lbl ) {
|
||||
$hero_metrics[] = array( 'num' => $metric_2_num, 'lbl' => $metric_2_lbl );
|
||||
}
|
||||
if ( $metric_3_num && $metric_3_lbl ) {
|
||||
$hero_metrics[] = array( 'num' => $metric_3_num, 'lbl' => $metric_3_lbl );
|
||||
}
|
||||
if ( $metric_4_num && $metric_4_lbl ) {
|
||||
$hero_metrics[] = array( 'num' => $metric_4_num, 'lbl' => $metric_4_lbl );
|
||||
}
|
||||
if ( ! empty( $hero_metrics ) ) : ?>
|
||||
<div class="reviews-hero__metrics">
|
||||
<?php foreach ( $hero_metrics as $m ) : ?>
|
||||
<div class="reviews-hero__metric reveal">
|
||||
<span class="reviews-hero__metric-number"><?php echo esc_html( $metric_1_num ); ?></span>
|
||||
<span class="reviews-hero__metric-label"><?php echo esc_html( $metric_1_lbl ); ?></span>
|
||||
</div>
|
||||
<div class="reviews-hero__metric reveal">
|
||||
<span class="reviews-hero__metric-number"><?php echo esc_html( $metric_2_num ); ?></span>
|
||||
<span class="reviews-hero__metric-label"><?php echo esc_html( $metric_2_lbl ); ?></span>
|
||||
</div>
|
||||
<div class="reviews-hero__metric reveal">
|
||||
<span class="reviews-hero__metric-number"><?php echo esc_html( $metric_3_num ); ?></span>
|
||||
<span class="reviews-hero__metric-label"><?php echo esc_html( $metric_3_lbl ); ?></span>
|
||||
</div>
|
||||
<div class="reviews-hero__metric reveal">
|
||||
<span class="reviews-hero__metric-number"><?php echo esc_html( $metric_4_num ); ?></span>
|
||||
<span class="reviews-hero__metric-label"><?php echo esc_html( $metric_4_lbl ); ?></span>
|
||||
<span class="reviews-hero__metric-number"><?php echo esc_html( $m['num'] ); ?></span>
|
||||
<span class="reviews-hero__metric-label"><?php echo esc_html( $m['lbl'] ); ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Бейдж агрегированного рейтинга (social proof) -->
|
||||
<?php $ext_review_count = get_option( 'branch_ext_review_count', '247' ); ?>
|
||||
<div class="reviews-hero__rating-badge">
|
||||
<span class="reviews-hero__rating-stars">★★★★★</span>
|
||||
<span class="reviews-hero__rating-text">4.9 из 5 на основе 247 отзывов на внешних площадках</span>
|
||||
<span class="reviews-hero__rating-text">4.9 из 5 на основе <?php echo esc_html( $ext_review_count ); ?> отзывов на внешних площадках</span>
|
||||
</div>
|
||||
|
||||
<!-- TODO: заменить «247» на реальное суммарное количество отзывов со всех площадок -->
|
||||
|
||||
<button type="button" class="reviews-hero__cta-btn js-reviews-cta" data-goal="hero-cta">
|
||||
Записаться на экскурсию →
|
||||
</button>
|
||||
@ -267,7 +319,12 @@ $intro_price_txt = carbon_get_post_meta( $post_id, 'reviews_intro_price_text' );
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="reviews-intro__info">
|
||||
<p><strong>Режим работы школы:</strong> <?php echo esc_html( get_option( 'branch_hours', 'ежедневно с 8:00 до 19:00, кроме воскресенья' ) ); ?>.</p>
|
||||
<?php
|
||||
$intro_hours = carbon_get_post_meta( $post_id, 'reviews_intro_hours' );
|
||||
if ( ! empty( $intro_hours ) ) :
|
||||
?>
|
||||
<p><strong>Режим работы школы:</strong> <?php echo esc_html( $intro_hours ); ?>.</p>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $intro_price_txt ) ) : ?>
|
||||
<p><strong>Стоимость обучения:</strong> <?php echo esc_html( $intro_price_txt ); ?>. <a href="/nachalnaya-shkola/">Узнать подробнее о ценах →</a></p>
|
||||
<?php endif; ?>
|
||||
@ -320,7 +377,7 @@ $intro_price_txt = carbon_get_post_meta( $post_id, 'reviews_intro_price_text' );
|
||||
<section class="section-bg reviews-grid" data-bg="white" id="reviews-list">
|
||||
<div class="container">
|
||||
<!-- H2 для SEO: ключевые слова «отзывы родителей», «частная школа», «Щёлково» -->
|
||||
<h2 class="reviews-grid__h2">Отзывы родителей о частной школе в Щёлково</h2>
|
||||
<h2 class="reviews-grid__h2">Отзывы родителей о частной школе <?php echo esc_html( $branch_city_prep ); ?></h2>
|
||||
<p class="reviews-grid__intro">Все отзывы проходят проверку — мы связываемся с родителями и убеждаемся в достоверности каждого отзыва. Здесь собраны настоящие истории семей, чьи дети учатся в частной школе «Декарт» в Щёлково. Читайте, знакомьтесь и присоединяйтесь!</p>
|
||||
|
||||
<?php
|
||||
@ -351,7 +408,7 @@ $intro_price_txt = carbon_get_post_meta( $post_id, 'reviews_intro_price_text' );
|
||||
$is_long = strlen( wp_strip_all_tags( $text ) ) > 350;
|
||||
$batch = (int) ceil( $card_idx / 12 );
|
||||
?>
|
||||
<div class="lw-card reveal" data-batch="<?php echo (int) $batch; ?>">
|
||||
<article class="lw-card reveal" data-batch="<?php echo (int) $batch; ?>">
|
||||
<div class="lw-flex lw-flex--row lw-gap-12 lw-items-start">
|
||||
<?php
|
||||
$review_photo_url = $item['review_photo'] ?? '';
|
||||
@ -372,7 +429,7 @@ $intro_price_txt = carbon_get_post_meta( $post_id, 'reviews_intro_price_text' );
|
||||
Преподаватель: <a href="<?php echo esc_url( get_permalink( $teacher[0]['id'] ) ); ?>" class="review-card__teacher-link"><?php echo esc_html( get_the_title( $teacher[0]['id'] ) ); ?></a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="lw-badge lw-badge--verified" style="margin-top:6px; margin-left:0; align-self:flex-start;">✓ Проверенный отзыв</div>
|
||||
<div class="lw-badge lw-badge--verified">✓ Проверенный отзыв</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -395,7 +452,7 @@ $intro_price_txt = carbon_get_post_meta( $post_id, 'reviews_intro_price_text' );
|
||||
<span class="review-card__date"><?php echo esc_html( $date ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
@ -562,7 +619,7 @@ $intro_price_txt = carbon_get_post_meta( $post_id, 'reviews_intro_price_text' );
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- TODO: загрузить 3–5 видеоотзывов родителей (YouTube или VK Video) в CF reviews_video -->
|
||||
<?php /* TODO: загрузить 3–5 видеоотзывов родителей (YouTube или VK Video) в CF reviews_video */ ?>
|
||||
|
||||
<!-- ════════════════════════════════════════════
|
||||
ВНЕШНИЕ ПЛОЩАДКИ (E-E-A-T)
|
||||
@ -770,8 +827,8 @@ $intro_price_txt = carbon_get_post_meta( $post_id, 'reviews_intro_price_text' );
|
||||
<div class="final-cta__triggers">
|
||||
<div class="final-cta__trigger">
|
||||
<span class="final-cta__trigger-icon">📚</span>
|
||||
<span>Набор в 1 класс на 2026/27 учебный год открыт — <strong>осталось 12 мест</strong></span>
|
||||
<!-- TODO: уточнить реальное количество свободных мест -->
|
||||
<?php $remaining_seats = get_option( 'branch_remaining_seats', '12' ); ?>
|
||||
<span>Набор в 1 класс на 2026/27 учебный год открыт — <strong>осталось <?php echo esc_html( $remaining_seats ); ?> мест</strong></span>
|
||||
</div>
|
||||
<div class="final-cta__trigger">
|
||||
<span class="final-cta__trigger-icon">📅</span>
|
||||
@ -1061,40 +1118,130 @@ $org_address = array(
|
||||
'streetAddress' => $branch_addr,
|
||||
'addressLocality' => $branch_city,
|
||||
'addressRegion' => $branch_region,
|
||||
'postalCode' => get_option( 'branch_postal_code', '' ) ?: '',
|
||||
'postalCode' => get_option( 'branch_postal_code', '' ) ?: carbon_get_theme_option( 'schema_postal_code' ) ?: '',
|
||||
'addressCountry' => 'RU',
|
||||
);
|
||||
|
||||
// ─── ДАННЫЕ СХЕМЫ (CF theme options «SEO и микроразметка» + Settings API fallback) ───
|
||||
$schema_description = carbon_get_theme_option( 'schema_description' ) ?: get_option( 'branch_schema_description', '' );
|
||||
$schema_founded = carbon_get_theme_option( 'schema_founded' ) ?: get_option( 'branch_founded', '' );
|
||||
$schema_map_url = carbon_get_theme_option( 'schema_map_url' );
|
||||
$schema_area_raw = carbon_get_theme_option( 'schema_area_served' ) ?: get_option( 'branch_area_served', '' );
|
||||
$hours_cf = carbon_get_theme_option( 'schema_hours' );
|
||||
|
||||
// ─── openingHoursSpecification (CF complex → Settings API textarea) ───
|
||||
$hours_spec = array();
|
||||
if ( ! empty( $hours_cf ) && is_array( $hours_cf ) ) {
|
||||
foreach ( $hours_cf as $entry ) {
|
||||
$day = isset( $entry['day_of_week'] ) ? trim( $entry['day_of_week'] ) : '';
|
||||
if ( empty( $day ) ) {
|
||||
continue;
|
||||
}
|
||||
$is_off = ! empty( $entry['day_off'] );
|
||||
if ( $is_off ) {
|
||||
$hours_spec[] = array(
|
||||
'@type' => 'OpeningHoursSpecification',
|
||||
'dayOfWeek' => $day,
|
||||
'opens' => '00:00',
|
||||
'closes' => '00:00',
|
||||
);
|
||||
} else {
|
||||
$from = isset( $entry['opens'] ) ? trim( $entry['opens'] ) : '';
|
||||
$to = isset( $entry['closes'] ) ? trim( $entry['closes'] ) : '';
|
||||
if ( $from && $to ) {
|
||||
$hours_spec[] = array(
|
||||
'@type' => 'OpeningHoursSpecification',
|
||||
'dayOfWeek' => $day,
|
||||
'opens' => $from,
|
||||
'closes' => $to,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback: читаем из текстового поля отзывов (только dayOfWeek|opens|closes)
|
||||
$hours_raw = carbon_get_post_meta( $post_id, 'reviews_intro_hours' );
|
||||
if ( ! empty( $hours_raw ) && is_string( $hours_raw ) ) {
|
||||
$lines = explode( "\n", $hours_raw );
|
||||
foreach ( $lines as $line ) {
|
||||
$line = trim( $line );
|
||||
if ( empty( $line ) ) {
|
||||
continue;
|
||||
}
|
||||
$parts = explode( '|', $line );
|
||||
$day = isset( $parts[0] ) ? trim( $parts[0] ) : '';
|
||||
if ( empty( $day ) ) {
|
||||
continue;
|
||||
}
|
||||
if ( isset( $parts[2] ) && 'closed' === strtolower( trim( $parts[2] ) ) ) {
|
||||
$hours_spec[] = array(
|
||||
'@type' => 'OpeningHoursSpecification',
|
||||
'dayOfWeek' => $day,
|
||||
'opens' => '00:00',
|
||||
'closes' => '00:00',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
$from = isset( $parts[1] ) ? trim( $parts[1] ) : '';
|
||||
$to = isset( $parts[2] ) ? trim( $parts[2] ) : '';
|
||||
if ( $day && $from && $to ) {
|
||||
$hours_spec[] = array(
|
||||
'@type' => 'OpeningHoursSpecification',
|
||||
'dayOfWeek' => $day,
|
||||
'opens' => $from,
|
||||
'closes' => $to,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ─── areaServed — города присутствия ───
|
||||
$area_served = array();
|
||||
$area_served[] = array( '@type' => 'City', 'name' => $branch_city );
|
||||
if ( ! empty( $schema_area_raw ) && is_string( $schema_area_raw ) ) {
|
||||
$cities = array_map( 'trim', explode( ',', $schema_area_raw ) );
|
||||
foreach ( $cities as $c ) {
|
||||
if ( $c && $c !== $branch_city ) {
|
||||
$area_served[] = array( '@type' => 'City', 'name' => $c );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Fallback: только город филиала
|
||||
}
|
||||
|
||||
// ─── description — описание организации ───
|
||||
if ( ! empty( $schema_description ) && is_string( $schema_description ) ) {
|
||||
$org_description = wp_strip_all_tags( trim( $schema_description ) );
|
||||
} else {
|
||||
$org_description = 'Частная школа полного дня в ' . $branch_city . '. Обучение с 1 по 11 класс, подготовка к ЕГЭ и ОГЭ, индивидуальный подход.';
|
||||
}
|
||||
|
||||
$organization = array(
|
||||
'@type' => 'School',
|
||||
'@type' => array( 'School', 'LocalBusiness' ),
|
||||
'@id' => home_url( '/' ) . '#organization',
|
||||
'name' => $branch_name,
|
||||
'description' => 'Частная школа полного дня в ' . $branch_city . '. Обучение с 1 по 11 класс, подготовка к ЕГЭ и ОГЭ, индивидуальный подход.',
|
||||
'description' => $org_description,
|
||||
'url' => home_url( '/' ),
|
||||
'address' => $org_address,
|
||||
'priceRange' => get_option( 'branch_price_range' ) ?: 'от 40 000 ₽/мес',
|
||||
'openingHoursSpecification' => array(
|
||||
array(
|
||||
'@type' => 'OpeningHoursSpecification',
|
||||
'dayOfWeek' => array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday' ),
|
||||
'opens' => '08:00',
|
||||
'closes' => '19:00',
|
||||
),
|
||||
array(
|
||||
'@type' => 'OpeningHoursSpecification',
|
||||
'dayOfWeek' => 'Saturday',
|
||||
'opens' => '09:00',
|
||||
'closes' => '14:00',
|
||||
),
|
||||
),
|
||||
'areaServed' => array(
|
||||
array( '@type' => 'City', 'name' => $branch_city ),
|
||||
array( '@type' => 'City', 'name' => 'Фрязино' ),
|
||||
array( '@type' => 'City', 'name' => 'Монино' ),
|
||||
),
|
||||
// foundingDate задаётся в branch-опциях (SEO-таб) или в CF schema_founding_date
|
||||
'areaServed' => $area_served,
|
||||
);
|
||||
|
||||
// openingHoursSpecification — из CF или Settings API (условно)
|
||||
if ( ! empty( $hours_spec ) ) {
|
||||
$organization['openingHoursSpecification'] = $hours_spec;
|
||||
}
|
||||
|
||||
// hasMap — ссылка на карту (условно)
|
||||
if ( ! empty( $schema_map_url ) && is_string( $schema_map_url ) ) {
|
||||
$organization['hasMap'] = esc_url( trim( $schema_map_url ) );
|
||||
}
|
||||
|
||||
// foundingDate — год основания (условно)
|
||||
if ( ! empty( $schema_founded ) && is_string( $schema_founded ) ) {
|
||||
$organization['foundingDate'] = trim( $schema_founded );
|
||||
}
|
||||
|
||||
// GeoCoordinates на уровне Organization (не внутри PostalAddress)
|
||||
if ( ! empty( $branch_coords ) && false !== strpos( $branch_coords, ',' ) ) {
|
||||
$coords_parts = explode( ',', $branch_coords );
|
||||
@ -1118,6 +1265,9 @@ if ( $branch_phone ) {
|
||||
if ( $jsonld_img_url ) {
|
||||
$organization['logo'] = $jsonld_img_url;
|
||||
}
|
||||
if ( $school_image_url ) {
|
||||
$organization['image'] = $school_image_url;
|
||||
}
|
||||
if ( ! empty( $jsonld_social ) ) {
|
||||
$organization['sameAs'] = $jsonld_social;
|
||||
}
|
||||
@ -1135,6 +1285,13 @@ if ( $branch_phone || $branch_email ) {
|
||||
$organization['contactPoint'] = array( $cp );
|
||||
}
|
||||
|
||||
// AggregateRating — вкладываем напрямую в Organization (School), а не отдельным узлом @graph.
|
||||
// Google показывает звёздочки в выдаче только когда aggregateRating — свойство Organization/LocalBusiness.
|
||||
if ( $agg_rating ) {
|
||||
unset( $agg_rating['itemReviewed'] );
|
||||
$organization['aggregateRating'] = $agg_rating;
|
||||
}
|
||||
|
||||
// ─── WebSite ───
|
||||
$ld_website = array(
|
||||
'@type' => 'WebSite',
|
||||
@ -1143,6 +1300,14 @@ $ld_website = array(
|
||||
'name' => $branch_name,
|
||||
'inLanguage' => 'ru-RU',
|
||||
'publisher' => array( '@id' => home_url( '/' ) . '#organization' ),
|
||||
'potentialAction' => array(
|
||||
'@type' => 'SearchAction',
|
||||
'target' => array(
|
||||
'@type' => 'EntryPoint',
|
||||
'urlTemplate' => home_url( '/' ) . '?s={search_term_string}',
|
||||
),
|
||||
'query-input' => 'required name=search_term_string',
|
||||
),
|
||||
);
|
||||
|
||||
// ─── WebPage ───
|
||||
@ -1152,7 +1317,6 @@ $ld_webpage = array(
|
||||
'url' => get_permalink( $post_id ),
|
||||
'inLanguage' => 'ru-RU',
|
||||
'name' => wp_get_document_title() ?: 'Отзывы — ' . $branch_name,
|
||||
'description' => 'Реальные отзывы родителей и учеников о частной школе Декарт в Щёлково. Истории поступлений, мнения о программах и педагогах.',
|
||||
'isPartOf' => array( '@id' => home_url( '/' ) . '#website' ),
|
||||
'about' => array( '@id' => home_url( '/' ) . '#organization' ),
|
||||
'speakable' => array(
|
||||
@ -1161,6 +1325,32 @@ $ld_webpage = array(
|
||||
),
|
||||
);
|
||||
|
||||
// description — Yoast SEO → динамическая сборка с городом
|
||||
$webpage_description = get_post_meta( $post_id, '_yoast_wpseo_metadesc', true );
|
||||
if ( ! $webpage_description ) {
|
||||
$webpage_description = sprintf(
|
||||
'Реальные отзывы родителей и учеников о частной школе Декарт в %s. Истории поступлений, мнения о программах и педагогах.',
|
||||
$branch_city
|
||||
);
|
||||
}
|
||||
$ld_webpage['description'] = wp_strip_all_tags( $webpage_description );
|
||||
|
||||
// image — featured image страницы (если есть)
|
||||
$page_thumb_id = get_post_thumbnail_id( $post_id );
|
||||
if ( $page_thumb_id ) {
|
||||
$page_img = wp_get_attachment_image_url( $page_thumb_id, 'full' );
|
||||
if ( $page_img ) {
|
||||
$ld_webpage['image'] = esc_url( $page_img );
|
||||
}
|
||||
}
|
||||
|
||||
// datePublished / dateModified — даты публикации страницы (сигнал свежести)
|
||||
$post_obj = get_post( $post_id );
|
||||
if ( $post_obj ) {
|
||||
$ld_webpage['datePublished'] = get_the_date( 'c', $post_obj );
|
||||
$ld_webpage['dateModified'] = get_the_modified_date( 'c', $post_obj );
|
||||
}
|
||||
|
||||
// ─── Breadcrumb ───
|
||||
$ld_breadcrumb = array(
|
||||
'@type' => 'BreadcrumbList',
|
||||
@ -1188,11 +1378,6 @@ $ld_graph = array_merge(
|
||||
$ld_faq
|
||||
);
|
||||
|
||||
// Если есть AggregateRating — добавляем к webpage
|
||||
if ( $agg_rating ) {
|
||||
$ld_graph[] = $agg_rating;
|
||||
}
|
||||
|
||||
if ( ! empty( $ld_graph ) ) {
|
||||
$jsonld_data = array(
|
||||
'@context' => 'https://schema.org',
|
||||
|
||||
2549
wp-content/themes/dekart/podgotovka-k-shkole.css
Normal file
2549
wp-content/themes/dekart/podgotovka-k-shkole.css
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,45 @@
|
||||
<?php
|
||||
/**
|
||||
* Hero section — cinematic split-screen redesign 2026
|
||||
*
|
||||
* Fields loaded from Carbon Fields tab "🖼️ Герой (баннер)".
|
||||
* Город и адрес — из Настроек филиала (branch_city_prep, branch_address).
|
||||
*
|
||||
* @package Dekart
|
||||
*/
|
||||
|
||||
$post_id = get_the_ID();
|
||||
$page_breadcrumbs = carbon_get_post_meta( $post_id, 'page_breadcrumbs' );
|
||||
|
||||
// Поля из Carbon Fields (вкладка "🖼️ Герой")
|
||||
$banner_img_id = carbon_get_post_meta( $post_id, 'banner_image' );
|
||||
$h1 = carbon_get_post_meta( $post_id, 'banner_h1' );
|
||||
$subtitle = carbon_get_post_meta( $post_id, 'banner_subtitle' );
|
||||
$scarcity = carbon_get_post_meta( $post_id, 'banner_scarcity' );
|
||||
|
||||
// Город и адрес из Настроек филиала
|
||||
$branch_city = get_option( 'branch_city_prep', 'в Щёлково' );
|
||||
$branch_address = get_option( 'branch_address', 'ул. Комсомольская, 11' );
|
||||
?>
|
||||
<section class="banner">
|
||||
<?php if ( ! empty( $page_breadcrumbs ) ) { ?>
|
||||
<nav class="container" aria-label="Хлебные крошки">
|
||||
<section class="hero-pksh" aria-label="Hero">
|
||||
|
||||
<!-- ── Background layers ── -->
|
||||
<div class="hero-pksh__bg" aria-hidden="true">
|
||||
<div class="hero-pksh__blob hero-pksh__blob--1"></div>
|
||||
<div class="hero-pksh__blob hero-pksh__blob--2"></div>
|
||||
<div class="hero-pksh__blob hero-pksh__blob--3"></div>
|
||||
<div class="hero-pksh__pattern"></div>
|
||||
</div>
|
||||
|
||||
<!-- ── Breadcrumbs ── -->
|
||||
<?php if ( ! empty( $page_breadcrumbs ) ) : ?>
|
||||
<nav class="hero-pksh__breadcrumbs container" aria-label="Хлебные крошки">
|
||||
<ul class="breadcrumbs">
|
||||
<li>
|
||||
<a href="<?php echo esc_url( home_url() ); ?>/" class="home fa-home" title="Главная страница">
|
||||
<span style="display:none;">Главная</span>
|
||||
<svg width="21" height="16" viewBox="0 0 21 16" fill="none">
|
||||
<path d="M11.6473 10.6896H12.1473V11.1896V15.4691H16.4353C16.5143 15.4691 16.5756 15.4462 16.6432 15.3788C16.7108 15.3113 16.7333 15.2505 16.7333 15.1725V9.36976L10.0513 3.8712L3.36922 9.36976V15.1725C3.36922 15.2505 3.39178 15.3113 3.45937 15.3788C3.52698 15.4462 3.5883 15.4691 3.66723 15.4691H7.95527V11.1896V10.6896H8.45527H11.6473ZM10.3711 1.74407L18.9226 8.86174L19.5643 8.09722L16.9141 5.8987L16.7333 5.74874V5.51388V0.537319H14.5413V2.86272V3.93127L13.7209 3.2466L10.6815 0.709949C10.5114 0.572829 10.3095 0.499981 10.0513 0.499981C9.79293 0.499981 9.59094 0.572914 9.42075 0.710194L0.538196 8.09712L1.17996 8.86174L9.73142 1.74407L10.0513 1.47783L10.3711 1.74407Z" fill="white" stroke="white"/>
|
||||
<path d="M11.6473 10.6896H12.1473V11.1896V15.4691H16.4353C16.5143 15.4691 16.5756 15.4462 16.6432 15.3788C16.7108 15.3113 16.7333 15.2505 16.7333 15.1725V9.36976L10.0513 3.8712L3.36922 9.36976V15.1725C3.36922 15.2505 3.39178 15.3113 3.45937 15.3788C3.52698 15.4462 3.5883 15.4691 3.66723 15.4691H7.95527V11.1896V10.6896H8.45527H11.6473ZM10.3711 1.74407L18.9226 8.86174L19.5643 8.09722L16.9141 5.8987L16.7333 5.74874V5.51388V0.537319H14.5413V2.86272V3.93127L13.7209 3.2466L10.6815 0.709949C10.5114 0.572829 10.3095 0.499981 10.0513 0.499981C9.79293 0.499981 9.59094 0.572914 9.42075 0.710194L0.538196 8.09712L1.17996 8.86174L9.73142 1.74407L10.0513 1.47783L10.3711 1.74407Z" fill="currentColor" stroke="currentColor"/>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
@ -31,37 +60,123 @@ $page_breadcrumbs = carbon_get_post_meta( $post_id, 'page_breadcrumbs' );
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</nav>
|
||||
<?php } ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="banner-wrapper">
|
||||
<?php
|
||||
$foto = carbon_get_post_meta( $post_id, 'banner_img_desktop' );
|
||||
$foto_mobile = carbon_get_post_meta( $post_id, 'banner_img_mobile' );
|
||||
if ( empty( $foto_mobile ) ) {
|
||||
$foto_mobile = $foto;
|
||||
}
|
||||
if ( $foto ) :
|
||||
?>
|
||||
<picture class="banner-fon">
|
||||
<source srcset="<?php echo esc_url( wp_get_attachment_url( $foto ) ); ?>" media="(min-width: 860px)">
|
||||
<img src="<?php echo esc_url( wp_get_attachment_url( $foto_mobile ) ); ?>" alt="<?php echo esc_attr( get_post_meta( $foto, '_wp_attachment_image_alt', true ) ); ?>">
|
||||
</picture>
|
||||
<!-- ── Main hero layout: split screen ── -->
|
||||
<div class="hero-pksh__layout">
|
||||
|
||||
<!-- ====== LEFT COLUMN: Content ====== -->
|
||||
<div class="hero-pksh__content">
|
||||
|
||||
<!-- Address pill -->
|
||||
<div class="hero-pksh__address">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
|
||||
<span><?php echo esc_html( $branch_address ); ?> — центр <?php echo esc_html( str_replace( array( 'в ', 'В ' ), '', $branch_city ) ); ?></span>
|
||||
</div>
|
||||
|
||||
<!-- Main headline -->
|
||||
<h1 class="hero-pksh__title">
|
||||
<?php echo esc_html( $h1 ?: 'Подготовка к школе в Щёлково' ); ?>
|
||||
</h1>
|
||||
|
||||
<!-- Subtitle -->
|
||||
<?php if ( '' !== $subtitle ) : ?>
|
||||
<p class="hero-pksh__subtitle"><?php echo esc_html( $subtitle ); ?></p>
|
||||
<?php endif; ?>
|
||||
<div class="banner__content desktop">
|
||||
<h1 class="page_title"><?php echo esc_html( carbon_get_post_meta( $post_id, 'banner_h1' ) ); ?></h1>
|
||||
<?php if ( carbon_get_post_meta( $post_id, 'banner_text' ) !== '' ) : ?>
|
||||
<p class="banner_text"><?php echo esc_html( carbon_get_post_meta( $post_id, 'banner_text' ) ); ?></p>
|
||||
<?php endif; ?>
|
||||
<button class="btn-free-lesson-header btn-lilac btn-banner btn-write">Оставить заявку</button>
|
||||
|
||||
<!-- CTA + Scarcity -->
|
||||
<div class="hero-pksh__actions">
|
||||
<button class="hero-pksh__cta btn-write">Записаться на бесплатное пробное</button>
|
||||
<div class="hero-pksh__scarcity">
|
||||
<?php echo wp_kses_post( $scarcity ?: '🔥 Осталось <strong>2 места из 8</strong> в группе 5–6 лет. Стартуем <strong>1 июня</strong>' ); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Trust bar -->
|
||||
<div class="hero-pksh__trust">
|
||||
<div class="hero-pksh__trust-item">
|
||||
<span class="hero-pksh__trust-icon">⭐</span>
|
||||
<span class="hero-pksh__trust-label">Рейтинг <strong>4.8</strong></span>
|
||||
</div>
|
||||
<div class="hero-pksh__trust-item">
|
||||
<span class="hero-pksh__trust-icon">🎓</span>
|
||||
<span class="hero-pksh__trust-label"><strong>500+</strong> выпускников</span>
|
||||
</div>
|
||||
<div class="hero-pksh__trust-item">
|
||||
<span class="hero-pksh__trust-icon">📜</span>
|
||||
<span class="hero-pksh__trust-label">Гослицензия</span>
|
||||
</div>
|
||||
<div class="hero-pksh__trust-item">
|
||||
<span class="hero-pksh__trust-icon">🛡️</span>
|
||||
<span class="hero-pksh__trust-label">Гарантия результата</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ====== RIGHT COLUMN: Photo of children + floating badges ====== -->
|
||||
<div class="hero-pksh__visual">
|
||||
|
||||
<!-- Purple glow backdrop -->
|
||||
<div class="hero-pksh__visual-glow" aria-hidden="true"></div>
|
||||
|
||||
<!-- Hero photo — the emotional anchor -->
|
||||
<div class="hero-pksh__photo-wrap">
|
||||
<div class="hero-pksh__photo-frame">
|
||||
<?php if ( $banner_img_id ) : ?>
|
||||
<?php echo wp_get_attachment_image( $banner_img_id, 'full', false, array(
|
||||
'class' => 'hero-pksh__photo',
|
||||
'loading' => 'eager',
|
||||
'decoding' => 'async',
|
||||
) ); ?>
|
||||
<?php else : ?>
|
||||
<img
|
||||
src="<?php echo esc_url( get_template_directory_uri() . '/assets/images/girl_and_a_boy.webp' ); ?>"
|
||||
alt="Девочка и мальчик — весёлые занятия подготовкой к школе"
|
||||
class="hero-pksh__photo"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
width="689"
|
||||
height="689"
|
||||
/>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<!-- Photo accent glow ring -->
|
||||
<div class="hero-pksh__photo-ring" aria-hidden="true"></div>
|
||||
</div>
|
||||
|
||||
<!-- Floating badges — sticky-note style around photo -->
|
||||
<div class="hero-pksh__float hero-pksh__float--1">
|
||||
<span class="hero-pksh__float-icon">👩🏫</span>
|
||||
<span>Педагоги с опытом 15+ лет</span>
|
||||
</div>
|
||||
<div class="hero-pksh__float hero-pksh__float--2">
|
||||
<span class="hero-pksh__float-icon">🎮</span>
|
||||
<span>Игровая методика</span>
|
||||
</div>
|
||||
<div class="hero-pksh__float hero-pksh__float--3">
|
||||
<span class="hero-pksh__float-icon">📚</span>
|
||||
<span>Авторская программа</span>
|
||||
</div>
|
||||
<div class="hero-pksh__float hero-pksh__float--4">
|
||||
<span>🌟 Рейтинг <strong>4.8</strong></span>
|
||||
</div>
|
||||
|
||||
<!-- Decorative shapes -->
|
||||
<div class="hero-pksh__deco hero-pksh__deco--1" aria-hidden="true"></div>
|
||||
<div class="hero-pksh__deco hero-pksh__deco--2" aria-hidden="true"></div>
|
||||
<div class="hero-pksh__deco hero-pksh__deco--3" aria-hidden="true"></div>
|
||||
<div class="hero-pksh__deco hero-pksh__deco--4" aria-hidden="true"></div>
|
||||
|
||||
<!-- Sparkle particles -->
|
||||
<div class="hero-pksh__sparkle" aria-hidden="true"></div>
|
||||
<div class="hero-pksh__sparkle" aria-hidden="true"></div>
|
||||
<div class="hero-pksh__sparkle" aria-hidden="true"></div>
|
||||
<div class="hero-pksh__sparkle" aria-hidden="true"></div>
|
||||
<div class="hero-pksh__sparkle" aria-hidden="true"></div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<div class="banner__content mobile">
|
||||
<p class="page_title"><?php echo esc_html( carbon_get_post_meta( $post_id, 'banner_h1' ) ); ?></p>
|
||||
<?php if ( carbon_get_post_meta( $post_id, 'banner_text' ) !== '' ) : ?>
|
||||
<p class="banner_text"><?php echo esc_html( carbon_get_post_meta( $post_id, 'banner_text' ) ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<button class="mobile btn-write btn-lilac btn-page">Записаться</button>
|
||||
@ -1,5 +1,31 @@
|
||||
<?php
|
||||
$check_btn_discont = carbon_get_theme_option( 'check_btn_discont' );
|
||||
|
||||
$price_hour1 = carbon_get_theme_option( 'price_hour1' );
|
||||
$price_hour2 = carbon_get_theme_option( 'price_hour2' );
|
||||
$price_hour3 = carbon_get_theme_option( 'price_hour3' );
|
||||
$price_hour4 = carbon_get_theme_option( 'price_hour4' );
|
||||
|
||||
$price_hour_discount1 = carbon_get_theme_option( 'price_hour_discount1' );
|
||||
$price_hour_discount2 = carbon_get_theme_option( 'price_hour_discount2' );
|
||||
$price_hour_discount3 = carbon_get_theme_option( 'price_hour_discount3' );
|
||||
$price_hour_discount4 = carbon_get_theme_option( 'price_hour_discount4' );
|
||||
|
||||
// Cast to int — prevents PHP 8 TypeError when Carbon returns empty string
|
||||
$price_hour1 = (int)($price_hour1 ?: 0);
|
||||
$price_hour2 = (int)($price_hour2 ?: 0);
|
||||
$price_hour3 = (int)($price_hour3 ?: 0);
|
||||
$price_hour4 = (int)($price_hour4 ?: 0);
|
||||
|
||||
$price_hour_discount1 = (int)($price_hour_discount1 ?: 0);
|
||||
$price_hour_discount2 = (int)($price_hour_discount2 ?: 0);
|
||||
$price_hour_discount3 = (int)($price_hour_discount3 ?: 0);
|
||||
$price_hour_discount4 = (int)($price_hour_discount4 ?: 0);
|
||||
|
||||
// Hide price section entirely if admin hasn't filled prices yet
|
||||
$has_prices = ($price_hour1 > 0 || $price_hour2 > 0 || $price_hour3 > 0 || $price_hour4 > 0);
|
||||
$has_discounts = ($price_hour_discount1 > 0 || $price_hour_discount2 > 0 || $price_hour_discount3 > 0 || $price_hour_discount4 > 0);
|
||||
if ($has_prices || $has_discounts) :
|
||||
?>
|
||||
<section class="price">
|
||||
<div class="container">
|
||||
@ -19,27 +45,6 @@ $check_btn_discont = carbon_get_theme_option( 'check_btn_discont' );
|
||||
<?php } ?>
|
||||
</ul>
|
||||
<?php $early_bird_discount = carbon_get_theme_option( 'early_bird_discount' );
|
||||
|
||||
$price_hour1 = carbon_get_theme_option( 'price_hour1' );
|
||||
$price_hour2 = carbon_get_theme_option( 'price_hour2' );
|
||||
$price_hour3 = carbon_get_theme_option( 'price_hour3' );
|
||||
$price_hour4 = carbon_get_theme_option( 'price_hour4' );
|
||||
|
||||
$price_hour_discount1 = carbon_get_theme_option( 'price_hour_discount1' );
|
||||
$price_hour_discount2 = carbon_get_theme_option( 'price_hour_discount2' );
|
||||
$price_hour_discount3 = carbon_get_theme_option( 'price_hour_discount3' );
|
||||
$price_hour_discount4 = carbon_get_theme_option( 'price_hour_discount4' );
|
||||
|
||||
if( !isset($price_hour1) ) $price_hour1 = 0;
|
||||
if( !isset($price_hour2) ) $price_hour2 = 0;
|
||||
if( !isset($price_hour3) ) $price_hour3 = 0;
|
||||
if( !isset($price_hour4) ) $price_hour4 = 0;
|
||||
|
||||
if( !isset($price_hour_discount1) ) $price_hour_discount1 = 0;
|
||||
if( !isset($price_hour_discount2) ) $price_hour_discount2 = 0;
|
||||
if( !isset($price_hour_discount3) ) $price_hour_discount3 = 0;
|
||||
if( !isset($price_hour_discount4) ) $price_hour_discount4 = 0;
|
||||
|
||||
?>
|
||||
<div class="tabs-content">
|
||||
<div class="page-tab active" data-tab-content="1">
|
||||
@ -118,3 +123,4 @@ $check_btn_discont = carbon_get_theme_option( 'check_btn_discont' );
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
@ -131,6 +131,9 @@ if ($the_query->have_posts()) :
|
||||
<div class='custom-button-next reviews-owl-next'></div>
|
||||
<div class='custom-button-prev reviews-owl-prev'></div>
|
||||
</div>
|
||||
<div class="reviews-all-link" style="text-align:center; margin-top:24px;">
|
||||
<a href="/otzyvy/" class="btn-outline">Все отзывы →</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<?php
|
||||
|
||||
Loading…
Reference in New Issue
Block a user