Customization Recipes and New Feature Development
This guide is tailored for developers who have acquired the project source code and want to add new custom features, make product options multilingual, or build custom visual components.
Recipe 1: Managing and Translating Product Options and Color Swatches (`color`)
Immutable Rule for Color Key (Color Swatches)
color (or Color). The Next.js frontend uses this key to identify Hex color codes and create interactive color circles and visual filters.Process of making option titles multilingual with Strapi:
- For other options (like size, material, brand), naming in any language is free.
- Corresponding localized translations for option titles are defined dynamically in the Strapi CMS panel.
- The Next.js frontend fetches the title translation from Strapi based on the user's current Locale while the color filter key remains
color.
// 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}Recipe 2: Adding a New Workflow and REST API Endpoint in Medusa v2
In Medusa v2, business logic is separated into Steps and Workflows:
import { createWorkflow, createStep, StepResponse, WorkflowResponse } from "@medusajs/framework/workflows-sdk"; const fetchDealsStep = createStep("fetch-deals-step", async () => { const deals = [{ id: "deal_1", title: "Daily Special Deal", discount: "25%" }]; return new StepResponse(deals);}); export const getDailyDealsWorkflow = createWorkflow("get-daily-deals", function () { const deals = fetchDealsStep(); return new WorkflowResponse(deals);});import { 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 });}Recipe 3: Creating a New Block for the Homepage
Homepage blocks are located in the store/src/modules/home/components/ path. Each block consists of three parts: a type definition in homepage.ts, a Component schema in Strapi, and a React component folder.
Actual Project Structure
FeaturesBlock, BlogPostsBlock, ProductShowcase, and ProductSplitView each have a standalone folder and are identified in the BlockRenderer via the __component returned by Strapi.Example: Adding a "Countdown" Block
- Define TypeScript Type — In the
store/src/lib/data/homepage.tsfile, add the new block interface and append it to the main union type:
export interface CountdownBlock { __component: "ui.countdown-block" id: number title?: string target_date: string} // Add to union typeexport type HomepageBlock = | ProductSplitViewBlock | ProductShowcaseBlock | FeaturesBlock | BlogPostsBlock | CategoryCollectionBlock | CountdownBlock // <-- added here- Create Folder and React Component — Create a folder named
CountdownBlockin thestore/src/modules/home/components/path:
import 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> )}- Register in BlockRenderer — Open the
store/src/modules/home/components/BlockRenderer/index.tsxfile and add a new case to the switch:
import CountdownBlock from "../CountdownBlock" // Inside BlockRenderer switch(block.__component):case "ui.countdown-block": BlockContent = <CountdownBlock block={block} /> break- Create Component Schema in Strapi — Create a new JSON file in the
website-admin/src/components/ui/folder:
{ "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 } }}Final Step
Recipe 4: Connecting a New Payment Provider
To add a new payment gateway, define a service implementing AbstractPaymentProvider in the store-admin/src/modules/payment/ folder and register it in medusa-config.ts under the providers section of the payment module.