Documentation
Learn how to install Homeplate CMS and build templates using blocks, data views, and shortcodes.
Installation
1. Clone & Install
git clone <repository-url>
cd homeplate
npm install
2. Start the Server
node server.js
3. Run the Installer
Navigate to http://localhost:3000 and follow the wizard to configure your database, choose a template, and create your admin account.
4. Access Your Site
- Admin Panel:
/admin - Public Site:
/
Requirements
- Node.js 14.0.0+
- MySQL 5.7+ or MariaDB 10.3+
- npm or yarn
Custom Port
To use a port other than 3000, create a .env file before starting:
echo "PORT=8080" > .env
Template Basics
Templates live in the templates/ directory. Each template is a folder containing HTML files. Homeplate uses a drop-in system — any valid HTML file can become a CMS template.
How It Works
Place special shortcodes in your HTML. The CMS replaces them with content from the database when the page loads. Everything renders server-side, so content appears immediately with no JavaScript required.
<!DOCTYPE html>
<html>
<head>
<title>{{text:site_name}}</title>
</head>
<body>
{{include:header.html}}
<main>
<h1>{{text:site_name}}</h1>
{{block:hero_content}}
{{data:view:featured_products}}
</main>
{{include:footer.html}}
</body>
</html>
Content Blocks
Content blocks are editable regions that editors manage through the admin panel at Content in the sidebar.
How to Use Them
Add a shortcode to your template. The admin panel detects it automatically — no registration needed.
Text Blocks
Returns plain text with all HTML stripped. Use for headings, labels, and short strings.
Syntax
<h1>{{text:site_name}}</h1>
<p>{{text:hero_subtitle}}</p>
<title>{{text:page_title}}</title>
Example
If an editor sets site_name to “My Store”, the output is:
<h1>My Store</h1>
Rich Text Blocks
Returns full HTML content with formatting. Use for body copy, feature sections, and any content that needs rich formatting.
Syntax
<div class="content">
{{block:about_content}}
</div>
<section>
{{block:feature_section}}
</section>
Example
If an editor writes rich text with bold, links, and paragraphs, all formatting is preserved in the output.
Includes
Include shared HTML files. Great for headers, footers, and navigation that repeat across pages.
Syntax
<body>
{{include:header.html}}
<main>
<!-- page content -->
</main>
{{include:footer.html}}
</body>
The included file is injected inline, so it shares the same scope and styles as the parent template.
Data Blocks & Views
Data blocks are collections of structured content — products, blog posts, team members, testimonials, etc. You define a schema, editors add items, and you display them with views.
Step 1: Create a Data Block
In the admin panel under Data, create a new block and define its fields (title, description, price, images, etc.).
Step 2: Add Items
Editors add records through the admin panel — products, posts, or whatever the collection holds.
Step 3: Create a View
A view defines how items render. You write an HTML template for a single item, and the CMS loops through all matching items.
Data Views
Use the data:view shortcode to render a view in your template.
In Your Template
<section>
<h2>Featured Products</h2>
<div class="product-grid">
{{data:view:featured_products}}
</div>
</section>
View Template (written in the admin panel)
<div class="product-item">
<a href="/product/{{data:id}}">
<div class="product-card">
{{data:attr:images}}
<h3>{{data:attr:title}}</h3>
<p class="price">${{data:attr:price}}</p>
<p>{{data:attr:description}}</p>
{{if_sellable}}
<div class="actions">
{{shopping:product:quantity}}
{{shopping:product:add_to_cart}}
</div>
{{endif}}
</div>
</a>
</div>
Placeholders Available in Views
| Placeholder | What It Outputs |
|---|---|
{{data:id}} | The record's ID |
{{data:block_name}} | The data block name |
{{data:block_id}} | The data block ID |
{{data:attr:fieldname}} | Rendered attribute (full HTML for images) |
{{data:url:fieldname}} | Just the URL (for image/gallery types) |
{{data:text:fieldname}} | Field value with HTML stripped |
Filtering Views
Static Filters (Admin Panel)
When editing a view, set a Filter Config to control which items appear:
{
"filters": [
{ "attribute": "category", "operator": "=", "value": "Electronics" },
{ "attribute": "price", "operator": "<=", "value": 100 }
]
}
Dynamic Filters (in your template)
Pass filters via query string in the shortcode:
{{data:view:products?category=Electronics}}
Operators
| Operator | Meaning |
|---|---|
= | Equals |
!= | Not equals |
> >= | Greater than / greater than or equal |
< <= | Less than / less than or equal |
LIKE | Contains text (case-insensitive) |
IN | Value is in an array |
NOT IN | Value is not in an array |
Template Files
config.json
{
"name": "template-name",
"title": "Template Name",
"description": "A description of your template",
"version": "1.0.0",
"author": "Your Name"
}
Page Files
| File | Purpose |
|---|---|
index.html | Homepage (required) |
store.html | Product listing |
product.html | Single product page |
cart.html | Shopping cart |
checkout.html | Checkout |
order-confirmation.html | Order confirmation |
blog.html | Blog listing |
blog-post.html | Blog post |
cms-page.html | Admin-created custom pages (uses {{page:content}}) |
404.html | Error page |
privacy.html | Privacy policy |
terms.html | Terms of service |
Setting Up a Store
1. Create a Product Collection
In Data, create a new data block with fields like:
title text required
price number required
description textarea
images gallery
category text
sku text
featured boolean
sale_price number
2. Enable Sellable
Check "Is Sellable" on the data block and set the cart config:
{
"price_attribute": "price",
"discounted_price_attribute": "sale_price",
"title_attribute": "title",
"description_attribute": "description",
"image_attribute": "images",
"category_attribute": "category",
"sku_attribute": "sku"
}
3. Create Views
Create views for different displays: products_list, products_detail, featured_products, etc.
4. Store Routes
| Route | Template |
|---|---|
/store | store.html |
/product/:id | product.html |
/cart | cart.html |
/checkout | checkout.html |
/order-confirmation/:orderNumber | order-confirmation.html |
Shopping Tags
Product Tags
| Tag | Output |
|---|---|
{{shopping:product:add_to_cart}} | Add to cart button |
{{shopping:product:quantity}} | Quantity selector with +/- buttons |
{{shopping:product:price}} | Formatted price (with discount if applicable) |
{{shopping:products:list}} | All products from every sellable block |
{{shopping:products:featured}} | Products with featured = true |
{{shopping:products:sale}} | Products with on_sale = true |
Cart Tags
| Tag | Output |
|---|---|
{{shopping:cart:items}} | Cart items list with images, titles, quantities, and remove buttons |
{{shopping:cart:summary}} | Cart totals: subtotal, tax, total with checkout link |
{{shopping:cart:count}} | Total quantity of all items in cart |
{{shopping:cart:view}} | Link to cart page |
{{shopping:cart:subtotal}} | Formatted subtotal (before tax) as <span class="cart-subtotal"> |
{{shopping:cart:total}} | Formatted grand total (subtotal + tax) as <span class="cart-grand-total"> |
{{shopping:cart:item_count}} | Number of distinct line items (not total quantity) as <span class="cart-item-count"> |
Checkout
| Tag | Output |
|---|---|
{{shopping:checkout:form}} | Full checkout form |
Auto-Injected Checkout Assets
These assets are automatically injected into checkout.html. No manual <script> tags needed.
| Asset | Description |
|---|---|
/css/store.css | Default store styling (overridable via CSS custom properties) |
/cart-handler.js | Cart add / remove / update functionality |
/states.js | US state dropdown data — auto-populates <select id="state"> |
Conditionals
{{if_sellable}}
<p>Price: {{shopping:product:price}}</p>
{{shopping:product:add_to_cart}}
{{endif}}
{{if_not_sellable}}
<p>Contact for pricing</p>
{{endif_not_sellable}}
Template Variables
Global
| Variable | Value |
|---|---|
{{text:site_name}} | Site name from settings |
{{text:site_description}} | Site description |
{{text:site_url}} | Site URL |
Attribute Types
When you define a schema for a data block, each field has a type. Here is how each type renders when used with {{data:attr:fieldname}}:
| Type | Rendering |
|---|---|
text | Plain text string |
textarea | Multi-line text |
number | Numeric value |
boolean | Yes / No |
image | An <img> tag |
gallery | First image as <img>; slideshow starts automatically for multiple images |
select | Selected option value |
url | URL string |
date | Formatted date |
Cart CSS Classes
Use these classes in your templates for cart functionality. The JS handler binds to them automatically via event delegation — no inline onclick handlers needed.
Buttons
| Class | Description |
|---|---|
.cart-add-btn | Add to cart button |
.cart-add-button | Add to cart button (CartService variant) |
.cart-remove-btn | Remove item from cart button |
.cart-clear-btn | Clear all items button |
.cart-checkout-btn | Proceed to checkout button |
.cart-continue-btn | Continue shopping button |
.cart-view-product-btn | View Product link (for items with variants) |
.cart-out-of-stock-btn | Out of Stock disabled button |
Display
| Class | Description |
|---|---|
.cart-container | Main cart container |
.cart-item | Individual cart item row |
.cart-item-image | Product image in cart |
.cart-item-details | Product details container |
.cart-item-title | Product title |
.cart-item-type | Product type / category |
.cart-item-price | Product price |
.cart-item-quantity | Quantity controls container |
.cart-summary | Cart summary section |
.cart-subtotal | Cart subtotal value (before tax) |
.cart-total | Cart total element (legacy — renders subtotal) |
.cart-grand-total | Cart grand total value (subtotal + tax) |
.cart-item-count | Number of distinct line items in cart |
.cart-empty | Empty cart message |
Quantity
| Class | Description |
|---|---|
.cart-quantity-input | Quantity number input |
.cart-quantity-selector | Quantity controls wrapper |
.cart-quantity-decrease | Decrease quantity button |
.cart-quantity-increase | Increase quantity button |
Header Cart
| Class | Description |
|---|---|
.cart-btn | Cart button in header |
.cart-btn-icon | Cart icon SVG |
.cart-badge | Cart item count badge |
Product Cards
| Class | Description |
|---|---|
.product-card | Product card wrapper |
.product-image | Product image |
.product-title | Product title heading |
.product-price | Product price display |
.product-description | Product description text |
.product-details | Card details wrapper |
.product-category-badge | Category label |
.product-sale-badge | Sale / discount badge |
.product-variants | Variant selector wrapper |
.variant-select | Variant dropdown or text input |
.product-actions | Add-to-cart area on detail page |
.breadcrumb | Product detail breadcrumb nav |
Checkout Form
| Class | Description |
|---|---|
.checkout-input | All checkout form inputs |
.checkout-checkbox | Create account checkbox |
.checkout-submit-btn | Pay Now submit button |
.checkout-section | Checkout form section card |
.checkout-grid | Two-column checkout layout |
.checkout-login-input | Login prompt email / password inputs |
.checkout-login-btn | Login prompt submit button |
.checkout-login-toggle-btn | Toggle login form button |
.checkout-promo-input | Promo code text input |
.checkout-promo-apply-btn | Promo code Apply button |
.checkout-promo-remove-btn | Promo code Remove button |
.checkout-state-select | State / province dropdown select |
.payment-method-btn | Payment method selector button |
.payment-container | Payment method content container |
.filter-btn | Category filter button |
.filter-buttons | Category filter button group |
Data Attributes
| Attribute | Description |
|---|---|
data-block-id | Data block ID for product |
data-record-id | Data record ID for product |
data-cart-item-id | Cart item ID |
data-cart-count | Cart item count (for badges) |
Example
<!-- Add to cart button -->
<button class="cart-add-btn" data-block-id="123" data-record-id="456">
Add to Cart
</button>
<!-- Cart item display -->
<div class="cart-item" data-cart-item-id="789">
<img class="cart-item-image" src="product.jpg" alt="Product">
<div class="cart-item-details">
<div class="cart-item-title">Product Name</div>
<div class="cart-item-price">$19.99</div>
</div>
<div class="cart-item-quantity">
<input class="cart-quantity-input" data-cart-item-id="789"
value="1" min="1" max="99">
<button class="cart-remove-btn" data-cart-item-id="789">Remove</button>
</div>
</div>
Blog Shortcodes
Blog Listing (blog.html)
| Shortcode | Output |
|---|---|
{{blog:posts}} | List of published blog posts |
{{blog:pagination}} | Previous / next pagination controls |
Blog Post (blog-post.html)
| Shortcode | Output |
|---|---|
{{blog:post_title}} | Post title |
{{blog:post_content}} | Post body (HTML) |
{{blog:post_date}} | Formatted publish date |
{{blog:post_slug}} | URL slug |
{{blog:post_image}} | Post image URL |
{{blog:post_image_meta}} | <meta property="og:image"> tag (conditional) |
{{blog:post_image_meta_twitter}} | <meta name="twitter:image"> tag (conditional) |
{{blog:post_meta_description}} | Meta description text |
{{blog:post_url}} | Full URL to the post |
{{blog:related_posts}} | Up to 3 related posts sharing tags |
Custom Pages (CMS)
Admins can create pages in the admin panel under Pages. These pages are stored in the database and rendered using cms-page.html.
Page Shortcodes
| Shortcode | Output |
|---|---|
{{page:title}} | Page title |
{{page:content}} | Page body (HTML) |
{{page:slug}} | URL slug |
{{page:meta_title}} | SEO meta title (falls back to title) |
{{page:meta_description}} | Meta description text |
{{page:image}} | Page image URL |
{{page:url}} | Full URL to the page |
{{page:image_meta}} | OG image meta tag (conditional) |
{{page:image_meta_twitter}} | Twitter image meta tag (conditional) |
System Pages vs Custom Pages
| Type | Source | Editable |
|---|---|---|
| System Pages | Template HTML files (e.g. about.html) | Edit template file directly |
| Custom Pages | Database (created in admin) | Yes — via admin panel |
Menu Shortcodes
Navigation menus are managed by admins under Pages > Menu Manager with drag-and-drop reordering.
| Shortcode | Output |
|---|---|
{{menu:items}} | Renders <nav> with all active menu items |
{{menu:items_json}} | JSON array of menu items (for JS-driven navs) |
Customer Accounts
Homeplate includes a built-in customer portal at /customer/ where customers can create accounts, view order history, pay invoices, and manage their profile.
Required Pages
| Page | Purpose |
|---|---|
checkout.html | Checkout form with optional account creation |
order-confirmation.html | Order success page |
order-history.html | Customer order history |
Order Payment Statuses
| Status | Meaning |
|---|---|
pending | Awaiting payment |
paid | Payment completed |
failed | Payment failed |
refunded | Payment refunded |