Формы витрины
Защита формы, проверка «я не робот», вывод ошибок рядом с полем и адреса всех действий покупателя.
На этой странице
На витрине два вида форм. Одни отправляются обычным 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}
Плейсхолдер в каждом поле
Пустое поле без подсказки внутри — это вопрос без ответа: покупатель не знает, что туда писать и в каком виде. Плейсхолдер нужен везде: в тексте, в числе, в многострочном поле, в выпадающем списке без выбранного значения.
Тексты плейсхолдеров, как и все остальные надписи темы, берут из её файлов переводов — см. Тексты темы и языки.