Документация

Формы витрины

Защита формы, проверка «я не робот», вывод ошибок рядом с полем и адреса всех действий покупателя.

На этой странице

На витрине два вида форм. Одни отправляются обычным POST и возвращают страницу — вход, регистрация, профиль. Другие отправляются из браузера и получают данные — корзина, оформление, отзывы. Правила у них разные.

Защита формы

Любая форма обязана нести ключ защиты, иначе магазин её не примет.

<form method="post" action="/account/login">
    {csrf_field}
    …
</form>

Для запросов из браузера ключ приходит в настройках витрины — CartiX.csrf:

headers: { 'X-CSRF-TOKEN': CartiX.csrf }

Ставить его в разметку не нужно: мета-тег csrf-token магазин печатает сам.

Проверка «я не робот»

{captcha form="reviews"}

Тег сам спрашивает, включена ли проверка для этой формы, и рисует нужный виджет. Проверка выключена — тег не выводит ничего, ветку {if} вокруг него писать не надо.

Готовые имена форм: login, register, forgot, reviews, questions. Дополнения могут завести свои.

Владелец выбирает способ проверки один на весь магазин: выключено, встроенная защита (скрытое поле-ловушка) или Google reCAPTCHA. Тема про это не знает и знать не должна — вид виджета приходит готовым.

⚠️ reCAPTCHA подключает скрипт с сайта Google. Это единственное место, где витрина обращается наружу без участия владельца. Если вы делаете тему, для которой это неприемлемо, скажите об этом в описании — выбор способа проверки остаётся за владельцем магазина.

Ошибки и введённые значения

Форма, отправленная обычным POST и не прошедшая проверку, возвращает покупателя назад. Вместе с ним приходят три переменные:

{if $status}<p class="ok">{$status}</p>{/if}

<label>
    Почта
    <input type="email" name="email" value="{$old.email|default:''}"
           class="{if $errors.email}is-invalid{/if}">
    {if $errors.email}<span class="err">{$errors.email}</span>{/if}
</label>
Переменная Что внутри
$errors ошибки по именам полей; ошибок нет — пустой список
$old введённые значения, чтобы покупателю не набирать всё заново
$status сообщение об успехе

Подставлять $old обязательно. Форма, которая после ошибки очищает всё, что человек набрал, — самая частая причина брошенной регистрации.

Формы, которые обслуживает магазин

Их разметка описана атрибутами, а не адресами: корзина, оформление заказа, избранное, сравнение, отзывы и вопросы. Что и как размечать — на странице Атрибуты data-*.

Коротко: адреса действий печатает магазин — объектом window.CartiX, теме их знать не нужно.

fetch(CartiX.urls.reviewSubmit, { … });

Вход и регистрация

{* account/login.html *}
<form method="post" action="{url path='/account/login'}">
    {csrf_field}

    <input type="text" name="identifier" value="{$old.identifier|default:''}"
           placeholder="Почта или телефон">
    {if $errors.identifier}<span class="err">{$errors.identifier}</span>{/if}

    <input type="password" name="password" placeholder="Пароль">
    {if $errors.password}<span class="err">{$errors.password}</span>{/if}

    {captcha form="login"}
    <button type="submit">Войти</button>
</form>

{if $auth.social}
    {include file="partials/social-login.html"}
{/if}

$auth говорит, какие способы входа владелец включил: по паролю, по коду из письма или SMS, через соцсети. Показывать нужно только включённые — кнопка входа через Google в магазине, где он не настроен, ведёт в никуда.

У регистрации сверх этого приходит $reg_types — виды покупателя (частное лицо, компания) и поля, которые владелец сделал обязательными.

Профиль

account/profile.html получает $profile: вид покупателя, контакты, привязанные соцсети. Набор полей задаёт владелец, поэтому рисуйте их списком по данным, а не перечисляйте руками: на чужом магазине список другой.

Поля, которых может не быть

Состав полей оформления, регистрации и профиля владелец настраивает сам. Тема, написанная под один магазин, на другом покажет пустоту или потеряет обязательное поле.

Правильный подход — обходить то, что пришло:

{foreach $checkout.recipient_fields as $field}
    <label>
        {$field.label}{if $field.required} *{/if}
        <input type="{$field.type}" name="{$field.name}"
               placeholder="{$field.placeholder}"
               {if $field.required}required{/if}>
    </label>
{/foreach}

Отзывы и вопросы

Разметку удобно вынести в partials/reviews.html и partials/questions.html — они нужны и на странице товара, и в других местах.

<form data-review-form>
    {csrf_field}
    <input type="hidden" name="product_id" value="{$product.id}">
    <div class="rating-input">…</div>
    <textarea name="text" placeholder="Расскажите о товаре"></textarea>
    {captcha form="reviews"}
    <button type="submit">Отправить</button>
</form>

Отправку обрабатывает тема — по адресу CartiX.urls.reviewSubmit. Ответы на отзывы и оценки «полезно / бесполезно» устроены так же: CartiX.urls.reviewReply, CartiX.urls.reviewVote.

⚠️ Отзывы могут быть выключены владельцем — тогда в $reviews приходит только признак «выключено». Обращаться к $reviews.items без проверки нельзя:

{if $reviews.enabled}
    {include file="partials/reviews.html"}
{/if}

Плейсхолдер в каждом поле

Пустое поле без подсказки внутри — это вопрос без ответа: покупатель не знает, что туда писать и в каком виде. Плейсхолдер нужен везде: в тексте, в числе, в многострочном поле, в выпадающем списке без выбранного значения.

Тексты плейсхолдеров, как и все остальные надписи темы, берут из её файлов переводов — см. Тексты темы и языки.

Обновлено 25 августа 2026