Рецепты кастомизации и разработка новых функций
Это руководство предназначено для разработчиков, желающих расширить функционал, локализовать опции товаров или создать собственные визуальные блоки.
Рецепт 1: Управление и перевод опций товаров и цветовых образцов (`color`)
Строгое правило для ключа цвета (Color Swatches)
В панели Medusa опция цвета обязана называться строго
color (или Color). Фронтенд Next.js использует этот ключ для поиска HEX-кодов и создания интерактивных образцов и визуальных фильтров.Процесс локализации названий опций через Strapi:
- Для остальных опций (размер, материал, бренд) название может быть любым.
- Локализованные переводы названий опций динамически настраиваются в панели Strapi CMS.
- Фронтенд Next.js запрашивает перевод из Strapi в соответствии с локалью пользователя, сохраняя ключ фильтрации как
color.
Пример получения локализованных названий опций из Strapi на фронтенде
typescript// store/src/lib/strapi-client/get-option-translations.tsexport async function getOptionTranslation(optionKey: string, locale: string = "fa") { const res = await fetch( `${process.env.NEXT_PUBLIC_STRAPI_URL}/api/option-translations?filters[key][$eq]=${optionKey}&locale=${locale}`, { headers: { Authorization: `Bearer ${process.env.STRAPI_API_TOKEN_FOR_FRONT}` } } ) const json = await res.json() return json.data?.[0]?.translated_name || optionKey}Рецепт 2: Добавление нового Workflow и REST API эндпоинта в Medusa v2
В Medusa v2 бизнес-логика выстраивается в виде Шагов (Steps) и Рабочих процессов (Workflows):
store-admin/src/workflows/daily-deals.ts
typescriptimport { createWorkflow, createStep, StepResponse, WorkflowResponse } from "@medusajs/framework/workflows-sdk"; const fetchDealsStep = createStep("fetch-deals-step", async () => { const deals = [{ id: "deal_1", title: "Специальное предложение дня", discount: "25%" }]; return new StepResponse(deals);}); export const getDailyDealsWorkflow = createWorkflow("get-daily-deals", function () { const deals = fetchDealsStep(); return new WorkflowResponse(deals);});store-admin/src/api/store/daily-deals/route.ts
typescriptimport { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";import { getDailyDealsWorkflow } from "../../../workflows/daily-deals"; export async function GET(req: MedusaRequest, res: MedusaResponse) { const { result } = await getDailyDealsWorkflow(req.scope).run(); res.json({ deals: result });}Рецепт 3: Создание нового блока для главной страницы
Блоки главной страницы находятся в store/src/modules/home/components/. Каждый блок состоит из трех частей: типизации в homepage.ts, схемы компонента в Strapi и папки React-компонента.
Реальная структура проекта
Существующие блоки, такие как
FeaturesBlock, BlogPostsBlock, ProductShowcase и ProductSplitView, имеют собственные папки и распознаются в BlockRenderer по значению __component, возвращаемому Strapi.Пример: Добавление блока «Обратный отсчет» (Countdown)
- Определение типа TypeScript — В файле
store/src/lib/data/homepage.tsдобавьте интерфейс нового блока и включите его в основной union-тип:
store/src/lib/data/homepage.ts
typescriptexport interface CountdownBlock { __component: "ui.countdown-block" id: number title?: string target_date: string} // Добавление в union typeexport type HomepageBlock = | ProductSplitViewBlock | ProductShowcaseBlock | FeaturesBlock | BlogPostsBlock | CategoryCollectionBlock | CountdownBlock // <-- добавлено сюда- Создание папки и компонента React — Создайте папку
CountdownBlockвstore/src/modules/home/components/:
store/src/modules/home/components/CountdownBlock/index.tsx
tsximport React from "react"import type { CountdownBlock as CountdownBlockType } from "@lib/data/homepage" interface CountdownBlockProps { block: CountdownBlockType} export default function CountdownBlock({ block }: CountdownBlockProps) { return ( <section className="py-16 text-center"> <h2 className="text-xl font-bold mb-4">{block.title}</h2> <p className="text-gray-500">{block.target_date}</p> </section> )}- Регистрация в BlockRenderer — Откройте
store/src/modules/home/components/BlockRenderer/index.tsxи добавьте новую ветку switch:
store/src/modules/home/components/BlockRenderer/index.tsx
tsximport CountdownBlock from "../CountdownBlock" // Внутри switch(block.__component) в BlockRenderer:case "ui.countdown-block": BlockContent = <CountdownBlock block={block} /> break- Создание схемы компонента в Strapi — Создайте новый JSON-файл в папке
website-admin/src/components/ui/:
website-admin/src/components/ui/countdown-block.json
json{ "collectionName": "components_ui_countdown_blocks", "info": { "displayName": "Countdown Block", "icon": "clock", "description": "A countdown timer block for the homepage" }, "options": {}, "attributes": { "title": { "type": "string" }, "target_date": { "type": "datetime", "required": true } }}Финальный шаг
После перезапуска Strapi откройте панель управления Homepage > Dynamic Zone. Новый «Countdown Block» появится в списке доступных компонентов.
Рецепт 4: Подключение нового платежного провайдера (Payment Provider)
Для добавления нового платежного шлюза создайте сервис, реализующий AbstractPaymentProvider в директории store-admin/src/modules/payment/, и зарегистрируйте его в medusa-config.ts в секции providers платежного модуля.