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:attr:title}} | The title field |
{{data:attr:fieldname}} | Any field from your schema |
{{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 |
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 |
{{shopping:cart:summary}} | Subtotal, tax, total |
{{shopping:cart:count}} | Number of items in cart |
{{shopping:cart:view}} | Link to cart page |
Checkout
| Tag | Output |
|---|---|
{{shopping:checkout:form}} | Full checkout form |
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.
Buttons
.cart-add-btn .cart-remove-btn
.cart-clear-btn .cart-checkout-btn
.cart-continue-btn
Display
.cart-container .cart-item
.cart-item-image .cart-item-title
.cart-item-price .cart-item-details
.cart-summary .cart-total
.cart-empty
Quantity
.cart-quantity-input
.cart-quantity-selector
.cart-quantity-decrease
.cart-quantity-increase
Data Attributes
data-block-id <!-- collection ID -->
data-record-id <!-- item ID -->
data-cart-item-id <!-- cart item ID -->