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.
| Key | Required | Description |
|---|---|---|
title | yes | Heading for the shop page. |
products_dir | yes | Folder holding product files. Normally products. |
description | no | Intro text. |
order | no | Sidebar/sort weight. |
A product page
One Markdown file per product inside products/. The body becomes the Details
tab content.
| Key | Description | |
|---|---|---|
title | Product name. | |
price | Number. 0 (or omitted) means Free. | |
currency | Currency symbol. Default $. | |
sku | Optional stock code. | |
image | Hero image + card thumbnail (alias: thumbnail), from public/. | |
store | The owning store's file basename (e.g. euneolink). Links product ↔ store. | |
author | Shown in the Author tab. | |
author_bio | Author blurb in the Author tab. | |
summary | Short lead (alias: description); also the card blurb. | |
details | Spec rows for the Details tab: `Label\ | Value` list. |
download | File delivered after a paid order (public/ path or URL). Gated. | |
payment_methods | Array of allowed method ids (see Payments). Empty = all configured methods. | |
related | Array of product basenames to feature. Empty = auto (same store). | |
order | Card sort weight. | |
product | Set 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.
type | Behaviour |
|---|---|
manual | detail is shown as instructions; the order stays pending until an admin marks it paid. |
link | detail is a URL the buyer is directed to; order stays pending. |
instant | Order 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
| Key | Required | Description |
|---|---|---|
title | yes | Heading. |
stores_dir | yes | Folder holding store files. Normally stores. |
order | no | Sort weight. |
A store page
One file per store inside stores/. Its basename is the id products
reference in their store: key.
| Key | Description | |
|---|---|---|
title | Store name. | |
owner | Store owner (name or handle). | |
location | Shown with a pin. | |
website | External link chip. | |
email | mailto: chip. | |
phone | Company phone number. | |
logo | Square logo, from public/. | |
cover | Wide banner, from public/ (falls back to gradient). | |
description | Intro / card blurb. | |
affiliations | Label list, shown as tags. | |
certifications | `Label\ | Note` list, shown as award tags. |
store_page | Set true only to force store rendering from outside stores/. | |
tax_number | Tax number or TPIN. Supported aliases include tax_number, vat_number, tax_id. | |
tax_label | Label eg VAT . | |
tax_country | The country in which tax is required. Supported aliases include: tax_country, vat_country | |
registration_number | The 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.
| Key | Description |
|---|---|
shop_dashboard | true to render the dashboard. |
goal | Revenue goal for the progress bar. |
goal_period | month or year — label for the goal/period card. |
currency | Currency 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
- A signed-in visitor picks a payment method and clicks Buy. The browser
posts to
POST /api/v2/shop/orders. - 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. - An admin later marks pending orders paid or refunded from the
dashboard (
POST /api/v2/shop/orders/status). - 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)
| Data | Location |
|---|---|
| Orders | content/shop/orders/<product>.orders.json |
| Reviews | content/shop/reviews/<product>.reviews.json |
| Payments | content/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
| Endpoint | Auth | Purpose |
|---|---|---|
POST /api/v2/shop/orders | signed-in | Place an order (purchase). |
POST /api/v2/shop/reviews | signed-in | Add/replace your review. |
POST /api/v2/shop/orders/status | admin | Mark an order paid/refunded. |
GET /shop/download | signed-in | Download 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)