Skip to content
Article Shop, Stores & Payments
☀️ Light Clean and bright
📜 Sepia Warm and vintage
🌤️ Light Gray Subtle and neutral
🔵 Light Blue Calm and serene
🌙 Dark Easy on the eyes
🌑 Dark Gray Deep and modern
🔷 Dark Blue Professional and sleek
🌿 Forest Calm and natural

Shop, Stores & Payments

The shop is entirely file-based — no database. Products and stores are Markdown pages driven by front matter; orders and reviews are JSON files on disk. This page documents every metadata key and where data is written.

Image and download paths resolve against the asset base (public/), e.g. image: img/shop/x.jpg<plugin>/public/img/shop/x.jpg. A download may also be an absolute https:// URL.


Products

Products index

One file (e.g. products.md) renders the grid/list of product cards.

KeyRequiredDescription
titleyesHeading for the shop page.
products_diryesFolder holding product files. Normally products.
descriptionnoIntro text.
ordernoSidebar/sort weight.

A product page

One Markdown file per product inside products/. The body becomes the Details tab content.

KeyDescription
titleProduct name.
priceNumber. 0 (or omitted) means Free.
currencyCurrency symbol. Default $.
skuOptional stock code.
imageHero image + card thumbnail (alias: thumbnail), from public/.
storeThe owning store's file basename (e.g. euneolink). Links product ↔ store.
authorShown in the Author tab.
author_bioAuthor blurb in the Author tab.
summaryShort lead (alias: description); also the card blurb.
detailsSpec rows for the Details tab: `Label\Value` list.
downloadFile delivered after a paid order (public/ path or URL). Gated.
payment_methodsArray of allowed method ids (see Payments). Empty = all configured methods.
relatedArray of product basenames to feature. Empty = auto (same store).
orderCard sort weight.
productSet true only to force product rendering from outside products/.
---
title: Widget Pro
price: 49.00
currency: $
store: euneolink
author: Jane Okoro
image: img/shop/widget-pro.jpg
summary: The professional-grade widget.
download: files/widget-pro.zip
payment_methods: [bank, paypal, cash]
details: [Format|Digital download, License|Single site, Updates|1 year]
related: [widget-lite, widget-team]
---

## About Widget Pro
Full description here…

The single product page shows: the image, tabs (Details / Author / Reviews), a related products row, and a right-hand cart panel (price, allowed payment methods, Buy button). After a paid order the panel shows a Download button instead, gated by the buyer's order.


Payments

Payment methods are configured once in products/_payments.md (underscore = never listed as a page). Each entry is id | label | type | detail.

typeBehaviour
manualdetail is shown as instructions; the order stays pending until an admin marks it paid.
linkdetail is a URL the buyer is directed to; order stays pending.
instantOrder is marked paid immediately (use for free / on-account items).
---
methods:
  - bank|Bank Transfer|manual|Transfer to Acct 0123, ref your email.
  - paypal|PayPal|link|https://paypal.me/you
  - cash|Cash on Delivery|manual|Pay on pickup.
  - free|Free / On account|instant|
currency: $
---

A product opts into methods by id via payment_methods: [bank, paypal]. Omit the key to allow every configured method.


Stores

Multiple stores are supported, each with an owner.

Stores index

KeyRequiredDescription
titleyesHeading.
stores_diryesFolder holding store files. Normally stores.
ordernoSort weight.

A store page

One file per store inside stores/. Its basename is the id products reference in their store: key.

KeyDescription
titleStore name.
ownerStore owner (name or handle).
locationShown with a pin.
websiteExternal link chip.
emailmailto: chip.
phoneCompany phone number.
logoSquare logo, from public/.
coverWide banner, from public/ (falls back to gradient).
descriptionIntro / card blurb.
affiliationsLabel list, shown as tags.
certifications`Label\Note` list, shown as award tags.
store_pageSet true only to force store rendering from outside stores/.
tax_numberTax number or TPIN. Supported aliases include tax_number, vat_number, tax_id.
tax_labelLabel eg VAT .
tax_countryThe country in which tax is required. Supported aliases include: tax_country, vat_country
registration_numberThe business Registration number. Supported Aliases include: registration_number, company_registration, reg_number

The store page renders the header (owner, location, contacts, affiliations, certifications) followed by every product whose store: matches this store.

---
title: Euneolink Solutions
owner: Jane Okoro
location: Lusaka, ZM
website: https://euneolink.example
email: shop@euneolink.example
logo: img/stores/euneolink-logo.png
cover: img/stores/euneolink-cover.jpg
description: Tools for the SepoDesk ecosystem.
affiliations: [SepoDesk Core Team, Open Web Alliance]
certifications: [ISO 9001|Quality management, PCI-DSS|Payment security]
---

Sales dashboard

Any page with shop_dashboard: true renders the sales overview. Admins only — everyone else sees a notice.

KeyDescription
shop_dashboardtrue to render the dashboard.
goalRevenue goal for the progress bar.
goal_periodmonth or year — label for the goal/period card.
currencyCurrency symbol.

It shows cards for total revenue, this period's revenue, pending, refunded, and paid-order count; a goal progress bar; a recent-orders table with Mark paid / Refund actions; and a top-customers table (who purchased, how many orders, how much spent).


Purchase flow & data

  1. A signed-in visitor picks a payment method and clicks Buy. The browser posts to POST /api/v2/shop/orders.
  2. The server validates the method against the product and the config, reads the price, and records an order — paid for instant/free methods, otherwise pending with the method's instructions returned to the buyer.
  3. An admin later marks pending orders paid or refunded from the dashboard (POST /api/v2/shop/orders/status).
  4. Once an order is paid, the product page shows a Download button that streams the file through GET /shop/download — only for a buyer with a paid order.

Where data lives (no database)

DataLocation
Orderscontent/shop/orders/<product>.orders.json
Reviewscontent/shop/reviews/<product>.reviews.json
Paymentscontent/pages/products/_payments.md

<product> is the product file's basename without .md. Order records include the buyer's uid, display name, opt-in email, amount, currency, method, and status — that's the "who bought what" stat, kept per product.

API summary

EndpointAuthPurpose
POST /api/v2/shop/orderssigned-inPlace an order (purchase).
POST /api/v2/shop/reviewssigned-inAdd/replace your review.
POST /api/v2/shop/orders/statusadminMark an order paid/refunded.
GET /shop/downloadsigned-inDownload a product you've paid for.

Policy page

The policy page is an ordinary Markdown page — no special front matter. Add a policy.md with your shipping, returns/reimbursement, and privacy sections and link it from _nav.md.


Reachability

products and stores are in the sidebar exclusion list, and their index pages are hidden by products_dir / stores_dir. Surface them from _nav.md:

- [Shop](/docs/products)
- [Stores](/docs/stores)
- [Policy](/docs/policy)