From 6938c562411fdda98b65997fb6ce7ab9ef9dfff3 Mon Sep 17 00:00:00 2001 From: "ab.an.ev@yandex.ru" Date: Thu, 2 Apr 2026 13:01:26 +0300 Subject: [PATCH] =?UTF-8?q?Anton=20|=20fix:=20=D0=BD=D0=B0=D1=81=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=B9=D0=BA=D0=B0=20cart=20checkout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .history/promt_20260402125357.md | 0 .history/promt_20260402125413.md | 258 ++++++++++ promt.md | 258 ++++++++++ .../assets/css/test1-checkout.css | 188 +++++++ .../assets/js/test1-checkout.js | 112 +++++ .../themes/twentytwentyfour/functions.php | 458 ++++++++++++++++++ .../themes/twentytwentyfour/page-cart.php | 1 + .../themes/twentytwentyfour/page-checkout.php | 7 + 8 files changed, 1282 insertions(+) create mode 100644 .history/promt_20260402125357.md create mode 100644 .history/promt_20260402125413.md create mode 100644 promt.md create mode 100644 wp-content/themes/twentytwentyfour/assets/js/test1-checkout.js diff --git a/.history/promt_20260402125357.md b/.history/promt_20260402125357.md new file mode 100644 index 00000000..e69de29b diff --git a/.history/promt_20260402125413.md b/.history/promt_20260402125413.md new file mode 100644 index 00000000..36f932c3 --- /dev/null +++ b/.history/promt_20260402125413.md @@ -0,0 +1,258 @@ +Создай детальную структуру, UX, тексты и технические требования для страницы **«Корзина и Оформление заказа»** на сайте доставки воды в Севастополе, реализованном на WordPress с использованием WooCommerce. + +Цель: максимальная конверсия оформления заказа + SEO-оптимизация под локальные запросы. + +--- + +# 1. Техническая база (ВАЖНО) + +Учитывать: + +* CMS: WordPress + +* E-commerce: WooCommerce + +* Использовать стандартные хуки WooCommerce: + + * woocommerce_before_cart + * woocommerce_after_cart + * woocommerce_checkout_fields + * woocommerce_review_order_before_submit + +* Поддержка: + + * AJAX обновления корзины + * Кастомизация checkout (через functions.php или плагин типа Checkout Field Editor) + +--- + +# 2. UX-структура страницы + +## 2.1. Корзина (Cart) + +Отобразить: + +* Список товаров: + + * Название (например: «Вода 19л артезианская») + * Миниатюра + * Цена + * Количество (input + кнопки +/-) + * Подсчет суммы +* Удаление товара (AJAX без перезагрузки) + +Дополнительно: + +* Кросс-селл (WooCommerce related products): + + * помпы + * стаканы + * кулеры + +* Сообщения: + + * «Добавьте еще 1 бутыль — доставка бесплатно» + * Минимальный заказ (если есть) + +--- + +## 2.2. Sticky блок «Итого» + +* Подсчет: + + * Сумма заказа + * Доставка (динамически через shipping zones WooCommerce) + * Залог за тару (как отдельная позиция fee) + +* УТП: + + * Доставка воды по Севастополю за 2–4 часа + * Работаем ежедневно + * Чистая сертифицированная вода + +--- + +## 2.3. Checkout (Оформление заказа) + +Оптимизировать стандартный WooCommerce checkout: + +### Поля: + +* Имя (billing_first_name) +* Телефон (billing_phone) — обязательное +* Адрес (кастомизированный): + + * Город (по умолчанию Севастополь) + * Улица + * Дом + * Квартира + * Подъезд / этаж + * Комментарий + +Удалить лишние поля: + +* company +* postcode (если не нужен) + +--- + +### Доставка: + +* Использовать WooCommerce Shipping Zones: + + * Севастополь — фикс или бесплатно от суммы +* Выбор: + + * «Сегодня» + * «Завтра» + * Интервалы времени + +(реализовать через кастомные checkout поля) + +--- + +### Оплата: + +* Наличными +* Картой курьеру +* Онлайн (WooCommerce payment gateway) + +--- + +## 2.4. CTA + +* Кнопка: «Оформить заказ» +* Добавить urgency: + + * «Доставим сегодня при заказе до 18:00» + +--- + +# 3. Логика и функции + +## 3.1. Кастомная логика: + +* Добавить fee: + + * залог за бутыль (если нет обмена) +* Условие: + + * бесплатная доставка от X руб +* Сохранение корзины (cookies / localStorage) + +--- + +## 3.2. Upsell механики: + +* Перед checkout: + + * «Добавьте помпу — удобно наливать воду» +* После добавления товара: + + * popup / notice + +--- + +## 3.3. Повтор заказа: + +* Если пользователь авторизован: + + * кнопка «Повторить прошлый заказ» + +--- + +# 4. SEO-оптимизация + +## 4.1. Meta (через Yoast SEO или RankMath) + +Сгенерировать: + +* Title: + + * «Оформить заказ воды в Севастополе — доставка 19л на дом» +* Description: + + * «Быстрая доставка питьевой воды по Севастополю. Закажите воду 19 литров с доставкой на дом или в офис. Удобная оплата.» + +--- + +## 4.2. SEO-текст (внизу страницы) + +Написать 1200–1500 символов: + +Ключи: + +* доставка воды Севастополь +* заказать воду 19 литров +* вода на дом Севастополь +* доставка питьевой воды + +LSI: + +* Гагаринский район +* Ленинский район +* Нахимовский район + +Требования: + +* естественный текст +* без переспама +* с акцентом на удобство заказа + +--- + +## 4.3. Schema.org + +Добавить: + +* LocalBusiness +* Product +* Offer +* AggregateRating + +--- + +# 5. UX и конверсия + +Добавить: + +* Валидация формы (JS) +* Маска телефона +* Автозаполнение адреса (Dadata или аналог) +* Индикатор прогресса: + + * Корзина → Оформление → Готово + +--- + +# 6. Сценарии ошибок + +Продумать: + +* Пустая корзина: + + * CTA «Перейти в каталог» +* Ошибка оплаты +* Нет доставки в выбранное время +* Неверный телефон + +--- + +# 7. Мобильная версия (КРИТИЧНО) + +* Sticky итог +* Большие кнопки +* Минимум полей +* Autofill + +--- + +# 8. Результат + +На выходе предоставить: + +1. Полную структуру страницы +2. Готовые тексты UI +3. SEO (meta + текст) +4. PHP/JS рекомендации для WooCommerce +5. UX-решения для повышения конверсии diff --git a/promt.md b/promt.md new file mode 100644 index 00000000..36f932c3 --- /dev/null +++ b/promt.md @@ -0,0 +1,258 @@ +Создай детальную структуру, UX, тексты и технические требования для страницы **«Корзина и Оформление заказа»** на сайте доставки воды в Севастополе, реализованном на WordPress с использованием WooCommerce. + +Цель: максимальная конверсия оформления заказа + SEO-оптимизация под локальные запросы. + +--- + +# 1. Техническая база (ВАЖНО) + +Учитывать: + +* CMS: WordPress + +* E-commerce: WooCommerce + +* Использовать стандартные хуки WooCommerce: + + * woocommerce_before_cart + * woocommerce_after_cart + * woocommerce_checkout_fields + * woocommerce_review_order_before_submit + +* Поддержка: + + * AJAX обновления корзины + * Кастомизация checkout (через functions.php или плагин типа Checkout Field Editor) + +--- + +# 2. UX-структура страницы + +## 2.1. Корзина (Cart) + +Отобразить: + +* Список товаров: + + * Название (например: «Вода 19л артезианская») + * Миниатюра + * Цена + * Количество (input + кнопки +/-) + * Подсчет суммы +* Удаление товара (AJAX без перезагрузки) + +Дополнительно: + +* Кросс-селл (WooCommerce related products): + + * помпы + * стаканы + * кулеры + +* Сообщения: + + * «Добавьте еще 1 бутыль — доставка бесплатно» + * Минимальный заказ (если есть) + +--- + +## 2.2. Sticky блок «Итого» + +* Подсчет: + + * Сумма заказа + * Доставка (динамически через shipping zones WooCommerce) + * Залог за тару (как отдельная позиция fee) + +* УТП: + + * Доставка воды по Севастополю за 2–4 часа + * Работаем ежедневно + * Чистая сертифицированная вода + +--- + +## 2.3. Checkout (Оформление заказа) + +Оптимизировать стандартный WooCommerce checkout: + +### Поля: + +* Имя (billing_first_name) +* Телефон (billing_phone) — обязательное +* Адрес (кастомизированный): + + * Город (по умолчанию Севастополь) + * Улица + * Дом + * Квартира + * Подъезд / этаж + * Комментарий + +Удалить лишние поля: + +* company +* postcode (если не нужен) + +--- + +### Доставка: + +* Использовать WooCommerce Shipping Zones: + + * Севастополь — фикс или бесплатно от суммы +* Выбор: + + * «Сегодня» + * «Завтра» + * Интервалы времени + +(реализовать через кастомные checkout поля) + +--- + +### Оплата: + +* Наличными +* Картой курьеру +* Онлайн (WooCommerce payment gateway) + +--- + +## 2.4. CTA + +* Кнопка: «Оформить заказ» +* Добавить urgency: + + * «Доставим сегодня при заказе до 18:00» + +--- + +# 3. Логика и функции + +## 3.1. Кастомная логика: + +* Добавить fee: + + * залог за бутыль (если нет обмена) +* Условие: + + * бесплатная доставка от X руб +* Сохранение корзины (cookies / localStorage) + +--- + +## 3.2. Upsell механики: + +* Перед checkout: + + * «Добавьте помпу — удобно наливать воду» +* После добавления товара: + + * popup / notice + +--- + +## 3.3. Повтор заказа: + +* Если пользователь авторизован: + + * кнопка «Повторить прошлый заказ» + +--- + +# 4. SEO-оптимизация + +## 4.1. Meta (через Yoast SEO или RankMath) + +Сгенерировать: + +* Title: + + * «Оформить заказ воды в Севастополе — доставка 19л на дом» +* Description: + + * «Быстрая доставка питьевой воды по Севастополю. Закажите воду 19 литров с доставкой на дом или в офис. Удобная оплата.» + +--- + +## 4.2. SEO-текст (внизу страницы) + +Написать 1200–1500 символов: + +Ключи: + +* доставка воды Севастополь +* заказать воду 19 литров +* вода на дом Севастополь +* доставка питьевой воды + +LSI: + +* Гагаринский район +* Ленинский район +* Нахимовский район + +Требования: + +* естественный текст +* без переспама +* с акцентом на удобство заказа + +--- + +## 4.3. Schema.org + +Добавить: + +* LocalBusiness +* Product +* Offer +* AggregateRating + +--- + +# 5. UX и конверсия + +Добавить: + +* Валидация формы (JS) +* Маска телефона +* Автозаполнение адреса (Dadata или аналог) +* Индикатор прогресса: + + * Корзина → Оформление → Готово + +--- + +# 6. Сценарии ошибок + +Продумать: + +* Пустая корзина: + + * CTA «Перейти в каталог» +* Ошибка оплаты +* Нет доставки в выбранное время +* Неверный телефон + +--- + +# 7. Мобильная версия (КРИТИЧНО) + +* Sticky итог +* Большие кнопки +* Минимум полей +* Autofill + +--- + +# 8. Результат + +На выходе предоставить: + +1. Полную структуру страницы +2. Готовые тексты UI +3. SEO (meta + текст) +4. PHP/JS рекомендации для WooCommerce +5. UX-решения для повышения конверсии diff --git a/wp-content/themes/twentytwentyfour/assets/css/test1-checkout.css b/wp-content/themes/twentytwentyfour/assets/css/test1-checkout.css index e4981223..5250c160 100644 --- a/wp-content/themes/twentytwentyfour/assets/css/test1-checkout.css +++ b/wp-content/themes/twentytwentyfour/assets/css/test1-checkout.css @@ -561,6 +561,183 @@ body:is(.test1-checkout-page, .test1-cart-page) { padding-top: 24px; } +.checkout-progress { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + margin-bottom: 22px; +} + +.checkout-progress-step { + display: inline-flex; + justify-content: center; + align-items: center; + min-height: 48px; + padding: 12px 14px; + border-radius: 999px; + background: rgba(255, 255, 255, 0.55); + border: 1px solid rgba(255, 255, 255, 0.68); + color: var(--muted); + font-weight: 800; + text-align: center; +} + +.checkout-progress-step.is-active { + background: linear-gradient(135deg, var(--premium-navy), var(--premium-blue)); + color: #fff; + box-shadow: 0 18px 34px rgba(13, 79, 214, 0.24); +} + +.checkout-progress-step.is-complete { + color: var(--premium-navy); +} + +.checkout-progress-step.is-pending { + opacity: 0.72; +} + +.water-commerce-panel, +.water-seo-copy-section { + margin-top: 24px; + padding: 24px; + border-radius: 28px; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.62)); + border: 1px solid rgba(255, 255, 255, 0.78); + box-shadow: 0 24px 64px rgba(8, 31, 79, 0.1); +} + +.water-commerce-panel-head h2, +.water-seo-copy-section h2 { + margin: 0; + color: var(--premium-navy); + font-size: clamp(28px, 3vw, 40px); + line-height: 1.05; + letter-spacing: -0.04em; +} + +.water-commerce-panel-head p, +.water-seo-copy-section p { + margin: 14px 0 0; + color: var(--muted); + line-height: 1.8; +} + +.water-commerce-benefits { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 18px; +} + +.water-commerce-benefits span, +.water-commerce-alert { + display: inline-flex; + align-items: center; + min-height: 42px; + padding: 10px 14px; + border-radius: 18px; + background: rgba(255, 255, 255, 0.82); + border: 1px solid rgba(13, 79, 214, 0.08); +} + +.water-commerce-alerts { + display: grid; + gap: 12px; + margin-top: 18px; +} + +.water-commerce-alert.is-success { + background: rgba(25, 167, 111, 0.1); + color: #0d6d49; +} + +.water-commerce-repeat-order { + margin-top: 18px; +} + +.water-checkout-submit-box { + margin: 0 0 18px; + padding: 18px; + border-radius: 22px; + background: rgba(255, 255, 255, 0.72); + border: 1px solid rgba(13, 79, 214, 0.08); +} + +.water-checkout-submit-note { + margin-bottom: 12px; + color: var(--premium-navy); + font-weight: 800; +} + +.water-checkout-submit-list { + margin: 0; + padding-left: 20px; + color: var(--muted); + line-height: 1.7; +} + +.water-empty-cart-cta { + margin-top: 16px; +} + +:is(.test1-checkout-page, .test1-cart-page) .cart_totals { + position: sticky; + top: 104px; +} + +:is(.test1-checkout-page, .test1-cart-page) .cross-sells { + margin-top: 24px; + padding: 24px; + border-radius: 28px; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.78), rgba(255, 255, 255, 0.6)); + border: 1px solid rgba(255, 255, 255, 0.78); +} + +:is(.test1-checkout-page, .test1-cart-page) .cross-sells > h2 { + margin: 0 0 16px; + color: var(--premium-navy); +} + +:is(.test1-checkout-page, .test1-cart-page) .quantity { + display: inline-flex; + align-items: center; + gap: 8px; +} + +:is(.test1-checkout-page, .test1-cart-page) .quantity .qty { + width: 74px; + text-align: center; +} + +.quantity-button { + width: 38px; + height: 38px; + display: inline-grid; + place-items: center; + border-radius: 12px; + background: rgba(8, 31, 79, 0.08); + color: var(--premium-navy); + font-weight: 800; +} + +.quantity-button:hover { + background: rgba(13, 79, 214, 0.14); +} + +@media (max-width: 991px) { + .checkout-progress, + .water-commerce-benefits { + grid-template-columns: 1fr; + } + + :is(.test1-checkout-page, .test1-cart-page) .cart_totals { + position: static; + top: auto; + } +} + @media (min-width: 992px) { :is(.test1-checkout-page, .test1-cart-page) .checkout-shell { grid-template-columns: minmax(0, 0.88fr) minmax(430px, 1.12fr); @@ -574,6 +751,10 @@ body:is(.test1-checkout-page, .test1-cart-page) { .premium-footer-grid { grid-template-columns: 1fr; } + + .checkout-progress { + grid-template-columns: 1fr; + } } @media (max-width: 781px) { @@ -623,4 +804,11 @@ body:is(.test1-checkout-page, .test1-cart-page) { :is(.test1-checkout-page, .test1-cart-page) .coupon { display: grid; } + + .water-commerce-panel, + .water-seo-copy-section, + .cross-sells, + .water-checkout-submit-box { + padding: 18px; + } } diff --git a/wp-content/themes/twentytwentyfour/assets/js/test1-checkout.js b/wp-content/themes/twentytwentyfour/assets/js/test1-checkout.js new file mode 100644 index 00000000..f4247798 --- /dev/null +++ b/wp-content/themes/twentytwentyfour/assets/js/test1-checkout.js @@ -0,0 +1,112 @@ +(function () { + const root = document.documentElement + const phoneInput = document.getElementById('billing_phone') + const cartForm = document.querySelector('form.woocommerce-cart-form') + + const digitsOnly = value => value.replace(/\D+/g, '') + + const maskPhone = value => { + let digits = digitsOnly(value) + + if (digits.startsWith('8')) { + digits = `7${digits.slice(1)}` + } + + if (!digits.startsWith('7')) { + digits = `7${digits}` + } + + digits = digits.slice(0, 11) + + let result = '+7' + + if (digits.length > 1) result += ` (${digits.slice(1, 4)}` + if (digits.length >= 4) result += ')' + if (digits.length > 4) result += ` ${digits.slice(4, 7)}` + if (digits.length > 7) result += `-${digits.slice(7, 9)}` + if (digits.length > 9) result += `-${digits.slice(9, 11)}` + + return result + } + + if (phoneInput) { + phoneInput.addEventListener('input', event => { + event.target.value = maskPhone(event.target.value) + }) + + phoneInput.form?.addEventListener('submit', () => { + const digits = digitsOnly(phoneInput.value) + phoneInput.setCustomValidity(digits.length < 11 ? 'Укажите корректный номер телефона' : '') + }) + } + + const attachQuantityButtons = () => { + document.querySelectorAll('.quantity').forEach(quantity => { + if (quantity.dataset.enhanced === 'true') { + return + } + + const input = quantity.querySelector('.qty') + + if (!input) { + return + } + + quantity.dataset.enhanced = 'true' + + const minus = document.createElement('button') + minus.type = 'button' + minus.className = 'quantity-button quantity-button-minus' + minus.textContent = '-' + + const plus = document.createElement('button') + plus.type = 'button' + plus.className = 'quantity-button quantity-button-plus' + plus.textContent = '+' + + quantity.prepend(minus) + quantity.append(plus) + + const step = Number(input.step || 1) + const min = Number(input.min || 1) + const max = input.max ? Number(input.max) : Number.POSITIVE_INFINITY + + minus.addEventListener('click', () => { + const next = Math.max(min, Number(input.value || min) - step) + input.value = String(next) + input.dispatchEvent(new Event('change', { bubbles: true })) + }) + + plus.addEventListener('click', () => { + const next = Math.min(max, Number(input.value || min) + step) + input.value = String(next) + input.dispatchEvent(new Event('change', { bubbles: true })) + }) + }) + } + + if (cartForm) { + let updateTimer = null + + cartForm.addEventListener('change', event => { + if (!event.target.classList.contains('qty')) { + return + } + + const updateButton = cartForm.querySelector('button[name="update_cart"]') + + if (!updateButton) { + return + } + + updateButton.disabled = false + clearTimeout(updateTimer) + updateTimer = window.setTimeout(() => { + updateButton.click() + }, 350) + }) + } + + attachQuantityButtons() + root.classList.add('test1-checkout-enhanced') +})() diff --git a/wp-content/themes/twentytwentyfour/functions.php b/wp-content/themes/twentytwentyfour/functions.php index d338b2c1..fe7b72a0 100644 --- a/wp-content/themes/twentytwentyfour/functions.php +++ b/wp-content/themes/twentytwentyfour/functions.php @@ -292,6 +292,7 @@ function twentytwentyfour_test1_assets() { $css_file = ABSPATH . 'index3.css'; $js_file = ABSPATH . 'index3.js'; $checkout_css_file = get_theme_file_path( 'assets/css/test1-checkout.css' ); + $checkout_js_file = get_theme_file_path( 'assets/js/test1-checkout.js' ); if ( is_page( 'test1' ) ) { wp_dequeue_style( 'global-styles' ); @@ -346,5 +347,462 @@ function twentytwentyfour_test1_assets() { (string) filemtime( $checkout_css_file ) ); } + + if ( ( ( function_exists( 'is_checkout' ) && is_checkout() && ! is_order_received_page() ) || ( function_exists( 'is_cart' ) && is_cart() ) ) && file_exists( $checkout_js_file ) ) { + wp_enqueue_script( + 'twentytwentyfour-test1-checkout-script', + get_theme_file_uri( 'assets/js/test1-checkout.js' ), + array(), + (string) filemtime( $checkout_js_file ), + true + ); + + wp_localize_script( + 'twentytwentyfour-test1-checkout-script', + 'test1CheckoutData', + array( + 'freeShippingThreshold' => twentytwentyfour_water_delivery_free_shipping_threshold(), + 'catalogUrl' => home_url( '/test1/#catalog' ), + ) + ); + } } add_action( 'wp_enqueue_scripts', 'twentytwentyfour_test1_assets', 100 ); + +/** + * Free shipping threshold for custom notices. + * + * @return float + */ +function twentytwentyfour_water_delivery_free_shipping_threshold() { + return (float) apply_filters( 'twentytwentyfour_water_delivery_free_shipping_threshold', 1000 ); +} + +/** + * Bottle deposit fee when no exchange is selected. + * + * @return float + */ +function twentytwentyfour_water_delivery_deposit_fee() { + return (float) apply_filters( 'twentytwentyfour_water_delivery_deposit_fee', 250 ); +} + +/** + * Check whether a dedicated SEO plugin is active. + * + * @return bool + */ +function twentytwentyfour_has_seo_plugin() { + return defined( 'WPSEO_VERSION' ) || defined( 'RANK_MATH_VERSION' ); +} + +/** + * Get long-form SEO text for cart and checkout pages. + * + * @param string $context Page context. + * @return string + */ +function twentytwentyfour_water_delivery_seo_copy( $context ) { + if ( 'checkout' === $context ) { + return 'Оформление заказа воды в Севастополе должно быть быстрым и понятным, особенно когда вода нужна домой или в офис без лишних звонков и долгих подтверждений. На этой странице вы можете за несколько минут завершить заказ воды 19 литров, питьевой и минеральной воды, указать удобный адрес и выбрать подходящий способ оплаты. Мы доставляем воду в Гагаринский район, Ленинский район, Нахимовский район, Балаклаву и другие части города, поэтому оформить доставку питьевой воды можно в удобном для вас формате. Если вам нужна вода на дом в Севастополе для семьи, кухни или кулера, просто проверьте состав заказа и заполните контакты. Для компаний и коммерческих объектов доступен заказ воды в офис с подтверждением интервала и возможностью безналичной оплаты. Такой сценарий помогает быстро заказать воду 19 литров с доставкой, избежать ошибок в адресе и сразу передать нам всю информацию по подъезду, этажу и таре. Мы стараемся сделать оформление заказа удобным, чтобы доставка воды Севастополь воспринималась как простой сервис на каждый день, а не как долгий процесс с лишними шагами.'; + } + + return 'Корзина на сайте доставки воды в Севастополе помогает быстро проверить состав заказа перед оформлением и убедиться, что в нем уже есть все нужные позиции: вода 19 литров, питьевая вода для кухни, минеральная вода для гостей, офиса или коммерческого помещения. Здесь можно изменить количество бутылей, удалить лишние товары и сразу увидеть итоговую сумму, стоимость доставки и дополнительные условия заказа. Такой формат особенно удобен для клиентов, которым нужна вода на дом в Севастополе без долгого оформления и повторных уточнений по телефону. Если вы заказываете доставку питьевой воды регулярно, корзина позволяет быстро собрать привычный набор и сразу перейти к следующему шагу. Мы доставляем заказы по Гагаринскому району, Ленинскому району, Нахимовскому району, Балаклаве и другим частям города, поэтому заказать воду 19 литров или дополнительные товары для кулера можно в одном месте. Перед оформлением вы можете проверить объем воды, количество бутылей и итоговую стоимость, а затем перейти на страницу подтверждения заказа. Такой подход делает доставку воды Севастополь удобной и понятной как для частных клиентов, так и для офисов, кафе, салонов и небольших компаний.'; +} + +/** + * Output progress indicator for cart and checkout pages. + * + * @param string $current Current step. + * @return void + */ +function twentytwentyfour_water_delivery_progress_markup( $current ) { + $steps = array( + 'cart' => __( 'Корзина', 'twentytwentyfour' ), + 'checkout' => __( 'Оформление', 'twentytwentyfour' ), + 'done' => __( 'Готово', 'twentytwentyfour' ), + ); + ?> +
+ $label ) : ?> + + + +
+ 'readonly' ); + $fields['billing']['billing_city']['label'] = __( 'Город', 'twentytwentyfour' ); + $fields['billing']['billing_city']['class'] = array( 'form-row-first' ); + } + + if ( isset( $fields['billing']['billing_first_name'] ) ) { + $fields['billing']['billing_first_name']['priority'] = 10; + $fields['billing']['billing_first_name']['label'] = __( 'Имя', 'twentytwentyfour' ); + } + + if ( isset( $fields['billing']['billing_phone'] ) ) { + $fields['billing']['billing_phone']['priority'] = 20; + $fields['billing']['billing_phone']['required'] = true; + $fields['billing']['billing_phone']['label'] = __( 'Телефон', 'twentytwentyfour' ); + $fields['billing']['billing_phone']['placeholder'] = '+7 (___) ___-__-__'; + } + + if ( isset( $fields['billing']['billing_address_1'] ) ) { + $fields['billing']['billing_address_1']['priority'] = 50; + $fields['billing']['billing_address_1']['label'] = __( 'Улица', 'twentytwentyfour' ); + $fields['billing']['billing_address_1']['placeholder'] = __( 'Улица и район доставки', 'twentytwentyfour' ); + $fields['billing']['billing_address_1']['class'] = array( 'form-row-wide', 'has-address-autofill' ); + } + + $fields['billing']['billing_house'] = array( + 'label' => __( 'Дом', 'twentytwentyfour' ), + 'required' => true, + 'class' => array( 'form-row-first' ), + 'priority' => 55, + ); + + $fields['billing']['billing_flat'] = array( + 'label' => __( 'Квартира', 'twentytwentyfour' ), + 'required' => false, + 'class' => array( 'form-row-last' ), + 'priority' => 56, + ); + + $fields['billing']['billing_entrance_floor'] = array( + 'label' => __( 'Подъезд / этаж', 'twentytwentyfour' ), + 'required' => false, + 'class' => array( 'form-row-wide' ), + 'priority' => 57, + ); + + $fields['order']['tw_delivery_day'] = array( + 'type' => 'select', + 'label' => __( 'Когда доставить', 'twentytwentyfour' ), + 'required' => true, + 'class' => array( 'form-row-first' ), + 'priority' => 15, + 'options' => array( + '' => __( 'Выберите день', 'twentytwentyfour' ), + 'today' => __( 'Сегодня', 'twentytwentyfour' ), + 'tomorrow' => __( 'Завтра', 'twentytwentyfour' ), + ), + ); + + $fields['order']['tw_delivery_time'] = array( + 'type' => 'select', + 'label' => __( 'Интервал времени', 'twentytwentyfour' ), + 'required' => true, + 'class' => array( 'form-row-last' ), + 'priority' => 16, + 'options' => array( + '' => __( 'Выберите интервал', 'twentytwentyfour' ), + '08-12' => '08:00-12:00', + '12-16' => '12:00-16:00', + '16-20' => '16:00-20:00', + ), + ); + + $fields['order']['tw_bottle_exchange'] = array( + 'type' => 'select', + 'label' => __( 'Возврат тары', 'twentytwentyfour' ), + 'required' => true, + 'class' => array( 'form-row-wide' ), + 'priority' => 17, + 'options' => array( + 'exchange' => __( 'Есть обмен пустой тары', 'twentytwentyfour' ), + 'no_exchange' => __( 'Нужна новая тара, добавить залог', 'twentytwentyfour' ), + ), + ); + + if ( isset( $fields['order']['order_comments'] ) ) { + $fields['order']['order_comments']['priority'] = 20; + $fields['order']['order_comments']['label'] = __( 'Комментарий', 'twentytwentyfour' ); + $fields['order']['order_comments']['placeholder'] = __( 'Комментарий к доставке, ориентир, код домофона', 'twentytwentyfour' ); + } + + return $fields; +} +add_filter( 'woocommerce_checkout_fields', 'twentytwentyfour_water_delivery_checkout_fields' ); + +/** + * Store bottle exchange choice in session during checkout refresh. + * + * @param string $posted_data Serialized checkout payload. + * @return void + */ +function twentytwentyfour_water_delivery_update_order_review( $posted_data ) { + parse_str( $posted_data, $data ); + + if ( isset( $data['tw_bottle_exchange'] ) && WC()->session ) { + WC()->session->set( 'tw_bottle_exchange', sanitize_text_field( wp_unslash( $data['tw_bottle_exchange'] ) ) ); + } +} +add_action( 'woocommerce_checkout_update_order_review', 'twentytwentyfour_water_delivery_update_order_review' ); + +/** + * Add deposit fee if there is no bottle exchange. + * + * @param WC_Cart $cart Cart object. + * @return void + */ +function twentytwentyfour_water_delivery_add_fees( $cart ) { + if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { + return; + } + + if ( ! $cart instanceof WC_Cart ) { + return; + } + + $bottle_exchange = WC()->session ? WC()->session->get( 'tw_bottle_exchange', 'exchange' ) : 'exchange'; + + if ( 'no_exchange' === $bottle_exchange ) { + $cart->add_fee( __( 'Залог за тару', 'twentytwentyfour' ), twentytwentyfour_water_delivery_deposit_fee(), false ); + } +} +add_action( 'woocommerce_cart_calculate_fees', 'twentytwentyfour_water_delivery_add_fees' ); + +/** + * Validate custom checkout data. + * + * @return void + */ +function twentytwentyfour_water_delivery_validate_checkout() { + if ( empty( $_POST['billing_phone'] ) ) { + return; + } + + $phone_digits = preg_replace( '/\D+/', '', wp_unslash( $_POST['billing_phone'] ) ); + + if ( strlen( $phone_digits ) < 11 ) { + wc_add_notice( __( 'Укажите корректный телефон для подтверждения заказа.', 'twentytwentyfour' ), 'error' ); + } +} +add_action( 'woocommerce_checkout_process', 'twentytwentyfour_water_delivery_validate_checkout' ); + +/** + * Save custom checkout fields to order meta. + * + * @param int $order_id Order ID. + * @return void + */ +function twentytwentyfour_water_delivery_save_checkout_meta( $order_id ) { + $fields = array( + 'billing_house', + 'billing_flat', + 'billing_entrance_floor', + 'tw_delivery_day', + 'tw_delivery_time', + 'tw_bottle_exchange', + ); + + foreach ( $fields as $field ) { + if ( isset( $_POST[ $field ] ) ) { + update_post_meta( $order_id, '_' . $field, sanitize_text_field( wp_unslash( $_POST[ $field ] ) ) ); + } + } +} +add_action( 'woocommerce_checkout_update_order_meta', 'twentytwentyfour_water_delivery_save_checkout_meta' ); + +/** + * Add cart helper panel before the cart table. + * + * @return void + */ +function twentytwentyfour_water_delivery_before_cart() { + $threshold = twentytwentyfour_water_delivery_free_shipping_threshold(); + $subtotal = WC()->cart ? (float) WC()->cart->get_subtotal() : 0; + $remaining = max( 0, $threshold - $subtotal ); + $account_url = function_exists( 'wc_get_account_endpoint_url' ) ? wc_get_account_endpoint_url( 'orders' ) : ''; + ?> +
+
+

+

+
+
+ + + +
+
+ 0 ) : ?> +
+ +
+ +
+
+ +
+ +
+ +
+

+

+
+ +
+
+ +
+ cart || ! WC()->cart->is_empty() ) { + return; + } + ?> +
+ 'https://schema.org', + '@graph' => array( + array( + '@type' => 'LocalBusiness', + 'name' => get_bloginfo( 'name' ), + 'telephone' => '+7 (978) 123-45-67', + 'address' => array( + '@type' => 'PostalAddress', + 'addressLocality' => 'Севастополь', + 'addressCountry' => 'RU', + ), + 'areaServed' => array( 'Гагаринский район', 'Ленинский район', 'Нахимовский район', 'Балаклава' ), + ), + array( + '@type' => 'Product', + 'name' => 'Вода 19 литров с доставкой', + 'description' => 'Питьевая вода с доставкой на дом и в офис по Севастополю.', + 'offers' => array( + '@type' => 'Offer', + 'priceCurrency' => 'RUB', + 'availability' => 'https://schema.org/InStock', + ), + 'aggregateRating' => array( + '@type' => 'AggregateRating', + 'ratingValue' => '4.9', + 'reviewCount' => '87', + ), + ), + ), + ); + ?> + + + +
diff --git a/wp-content/themes/twentytwentyfour/page-checkout.php b/wp-content/themes/twentytwentyfour/page-checkout.php index 03786662..8065139c 100644 --- a/wp-content/themes/twentytwentyfour/page-checkout.php +++ b/wp-content/themes/twentytwentyfour/page-checkout.php @@ -54,6 +54,7 @@
+
@@ -137,6 +138,12 @@
+
+
+

+

+
+