Настройка Craft Commerce для интернет-магазина
Craft Commerce — коммерческий плагин для CMS Craft CMS, построенный на Yii2 PHP-фреймворке. В отличие от монолитных платформ, Craft Commerce не навязывает тему или структуру каталога: всё строится через гибкую систему полей, секций и Twig-шаблонов. Это делает его выбором для нестандартных каталогов, сложных пользовательских атрибутов и headless-архитектур.
Архитектура Craft Commerce
Craft Commerce работает поверх Craft CMS и использует её:
- Elements — базовый тип данных (Products — это Elements с расширенными полями)
- Field Layout — конструктор полей без жёсткой схемы
- Twig — шаблонизатор с полным доступом к PHP API
- GraphQL — опциональный API для headless-режима (Craft Pro)
- Queue — Redis/Database очередь для фоновых задач
Ключевые сущности Commerce:
Product Types → Products → Variants
↓
Sales / Discounts
↓
Line Items → Order → Transaction
Установка и настройка
# Создание проекта через Craft Starter
composer create-project craftcms/craft mystore
cd mystore
# Установка Commerce
composer require craftcms/commerce
# Применение миграций
php craft setup
php craft migrate/all
php craft commerce/install
Настройка .env:
CRAFT_ENVIRONMENT=production
SECURITY_KEY=your-256-bit-key
DB_DRIVER=mysql
DB_SERVER=127.0.0.1
DB_PORT=3306
DB_DATABASE=craftstore
DB_USER=craftuser
DB_PASSWORD=securepassword
DB_TABLE_PREFIX=craft_
# Commerce-специфичные настройки
STRIPE_PUBLISHABLE_KEY=pk_live_xxx
STRIPE_SECRET_KEY=sk_live_xxx
Типы товаров (Product Types)
В Commerce нет единой схемы товара — каждый Product Type определяет свою структуру полей:
// config/commerce/productTypes.php — не используется напрямую,
// конфигурация через Control Panel или через Project Config
// craft/config/project/commerce-productTypes.yaml
productTypes:
clothing:
name: Одежда
handle: clothing
hasVariants: true
hasVariantTitleField: false
titleFormat: '{product.title} — {size.label} / {color.label}'
hasDimensions: true
taxCategory: standard
shippingCategory: standard
variantFieldLayouts:
- fields:
- sku
- price
- stock
Создание Product Type программно (для seed-скриптов):
use craft\commerce\elements\Product;
use craft\commerce\models\ProductType;
$productType = new ProductType();
$productType->name = 'Одежда';
$productType->handle = 'clothing';
$productType->hasVariants = true;
$productType->hasDimensions = true;
Craft::$app->getPlugins()->getPlugin('commerce')
->getProductTypes()
->saveProductType($productType);
Варианты и матрица атрибутов
Craft Commerce поддерживает варианты через Product Variants, каждый из которых является отдельным Element с полным набором полей:
{# templates/shop/product.twig #}
{% set product = craft.products.id(productId).one() %}
<h1>{{ product.title }}</h1>
{# Матрица вариантов для одежды #}
{% set variantMatrix = {} %}
{% for variant in product.variants %}
{% set size = variant.size.label %}
{% set color = variant.color.label %}
{% set variantMatrix = variantMatrix | merge({
(size): (variantMatrix[size] ?? {}) | merge({
(color): {
id: variant.id,
price: variant.price | commerceCurrency('USD'),
stock: variant.hasUnlimitedStock ? '∞' : variant.stock,
sku: variant.sku,
}
})
}) %}
{% endfor %}
<div x-data="variantSelector({{ variantMatrix | json_encode }})">
{# Alpine.js компонент выбора варианта #}
</div>
Корзина и оформление заказа
Craft Commerce использует сессию для корзины. Базовые операции:
{# Добавление в корзину #}
<form method="post">
{{ csrfInput() }}
{{ actionInput('commerce/cart/update-cart') }}
{{ hiddenInput('purchasableId', variant.id) }}
{{ hiddenInput('qty', 1) }}
{{ redirectInput('/shop/cart') }}
<button type="submit">В корзину</button>
</form>
{# Получение корзины #}
{% set cart = craft.commerce.carts.cart %}
{% for item in cart.lineItems %}
<div>{{ item.purchasable.title }} × {{ item.qty }} = {{ item.subtotal | commerceCurrency }}</div>
{% endfor %}
<strong>Итого: {{ cart.totalPrice | commerceCurrency }}</strong>
Контроллер заказа (PHP):
// Кастомный контроллер для обработки заказа
namespace modules\store\controllers;
use craft\commerce\Plugin as Commerce;
use craft\web\Controller;
class CheckoutController extends Controller
{
public function actionComplete(): \yii\web\Response
{
$this->requirePostRequest();
$order = Commerce::getInstance()->getCarts()->getCart();
// Добавление кастомных данных к заказу
$order->setFieldValue('deliveryNote', $this->request->getBodyParam('deliveryNote'));
if (!Craft::$app->getElements()->saveElement($order)) {
return $this->asFailure('Не удалось сохранить заказ');
}
return $this->redirect('/shop/order-confirmation?number=' . $order->number);
}
}
Платёжные шлюзы
Craft Commerce поддерживает несколько gateway-плагинов:
# Stripe
composer require craftcms/commerce-stripe
# PayPal
composer require craftcms/commerce-paypal
# Braintree
composer require craftcms/commerce-braintree
Конфигурация gateway через config/commerce-gateways.php:
return [
'stripe' => [
'type' => \craft\commerce\stripe\gateways\PaymentIntents::class,
'name' => 'Stripe',
'publishableKey' => getenv('STRIPE_PUBLISHABLE_KEY'),
'apiKey' => getenv('STRIPE_SECRET_KEY'),
'webhookSigningSecret' => getenv('STRIPE_WEBHOOK_SECRET'),
'testMode' => getenv('CRAFT_ENVIRONMENT') !== 'production',
],
];
GraphQL API для headless
Craft Pro + Commerce даёт полноценный GraphQL API:
# Запрос продуктов с вариантами
query ShopProducts($type: [String], $limit: Int, $offset: Int) {
products(type: $type, limit: $limit, offset: $offset) {
id
title
slug
variants {
id
sku
price
stock
... on clothing_Variant {
size { label value }
color { label value }
}
}
images: featuredImage {
url(width: 800, height: 800, format: "webp")
alt
}
}
}
Промо-акции и скидки
Craft Commerce разделяет Sales (скидки на цены) и Discounts (купоны и автоматические скидки):
use craft\commerce\models\Sale;
$sale = new Sale();
$sale->name = 'Летняя распродажа';
$sale->description = 'Скидка 20% на всю летнюю коллекцию';
$sale->apply = Sale::APPLY_BY_PERCENT;
$sale->applyAmount = -0.20; // -20%
$sale->allProducts = false;
$sale->categoryIds = [5, 8]; // ID категорий
$sale->dateFrom = new \DateTime('2024-06-01');
$sale->dateTo = new \DateTime('2024-08-31');
$sale->enabled = true;
Commerce::getInstance()->getSales()->saveSale($sale);
Мультивалютность
Craft Commerce Pro поддерживает мультивалютность нативно:
// config/commerce.php
return [
'paymentCurrencies' => [
'USD' => ['rate' => 1],
'EUR' => ['rate' => 0.92],
'RUB' => ['rate' => 90.5],
'UAH' => ['rate' => 37.2],
],
];
{# Переключатель валюты #}
{% set currentCurrency = craft.commerce.paymentCurrencies.primaryPaymentCurrency %}
<form method="post">
{{ csrfInput() }}
{{ actionInput('commerce/payment-currencies/set') }}
<select name="currency" onchange="this.form.submit()">
{% for currency in craft.commerce.paymentCurrencies.allPaymentCurrencies %}
<option value="{{ currency.iso }}" {{ currency.iso == currentCurrency.iso ? 'selected' }}>
{{ currency.iso }} — {{ currency.symbol }}
</option>
{% endfor %}
</select>
</form>
Производительность и кэширование
Craft CMS использует собственный Data Cache + Element Query Cache. Для продуктовых страниц:
{# Кэширование запроса на 1 час #}
{% cache globally using key 'product-' ~ product.id for 1 hour %}
{# Дорогостоящий запрос с вариантами, изображениями, связанными товарами #}
{% include '_partials/product-full' with { product: product } %}
{% endcache %}
Конфигурация Redis для Element Cache:
// config/app.php
return [
'components' => [
'cache' => [
'class' => yii\redis\Cache::class,
'redis' => [
'hostname' => '127.0.0.1',
'port' => 6379,
'database' => 1,
],
'defaultDuration' => 3600,
],
],
];
Сроки настройки
- Базовая установка + 1 Product Type + оформление заказа: 1–2 недели
- Полноценный магазин с 3–5 типами товаров, скидками, мультивалютностью: 4–6 недель
- Headless-магазин (Craft GraphQL + Next.js frontend): 6–10 недель
- Миграция с другой платформы в Craft Commerce: 4–8 недель (зависит от объёма каталога и сложности бизнес-логики)







