wit-cms
wit-cms
is a flat-file, "blog aware", publishing platform for Express.
It's designed for those who want WordPress-like functionality without the heft
and attack-surface of a WordPress installation. It emphasizes simplicity,
security, and performance.
Overview
Page and post content is declared by creating markdown files within the
appropriate directories. wit-cms
will generate everything else automatically,
including:
- express routes (both sync and async)
- a "home" page
- "pages" and "posts" (with "read more" links and pagination)
- "tag" and "category" taxonomies
- blog search and archive
- a
sitemap.xml
- an RSS feed
- syntax-highlighting on all content via highlight.js.
On application start, wit-cms
loads all site content into an in-memory
object, making it possible to serve content without reading a disk. This makes
it faster than traditional database-backed content-management systems.
wit-cms
seeks to offer a compromise between the full-featuredness of
WordPress and the ultra-minimalism of Jekyll, and strives to be a viable
alternative to those who may be dissatisfied with either.
Quick Start
To install only the wit-cms
module, run:
npm install wit-cms
To spare yourself the tedium of having to write boilerplate templating,
however, it may be preferable to clone the wit-cms-bootstrap
repository and
modify from there. This is the recommended approach for using wit-cms
:
https://github.com/chrisallenlane/wit-cms-bootstrap
Creating Content
In order to create a "post" (a blog entry) or a "page" (content that exists
outside of the blog context), simply create a markdown file of the appropriate
name, and in the appropriate location. By default, markdown files that source
page content live in <webroot>/pages/
, and markdown files that source blog
posts live in <webroot>/posts/
.
Page and post urls will be generated based off of the filename of the
corresponding markdown file. For example, the source markdown for a "Hello
World" blog post should be saved to <webroot>/posts/hello-world.md
, and its
URL would be /blog/post/hello-world
.
Front-matter
As with Jekyll, wit
reads page and post metadata (title, date, author,
categories, tags, etc.) out of front-matter embedded within each post or page
via the json-front-matter module.
For example, all posts should contain a header like the following:
"title" : "Hello World (of node blogging)""description" : "The post description.""author" : "John Doe""categories" : "node" "blogging" "tags" : "javascript" "express" "date" : "2012-09-15"
Pages will have a similar, but sparser, header:
"title" : "About Me""description" : "The page description.""url" : /about-me"searchable" : true
The url
property provides a mechanism to specify the URL at which the page
should be published. This parameter is optional, and defaults to the name of
the corresponding markdown file. (Example: about-me.md
will publish by
default to /about-me
.)
The searchable
property provides a mechanism for excluding pages from
appearing in search results. The searchable
parameter is optional, and
defaults to true
.
Beyond the above, any additional properties specified in front-matter will be made available to the corresponding rendered views as page locals.
Routes
wit-cms
automatically generates the following routes:
Synchronous
/
/:page
/page/search
/blog/
/blog/post/:name
/blog/category/:category
/blog/tag/:tag
/blog/archive/:year/:month?/:day?
/blog/search
/search
/feed
/feed.xml
/sitemap.xml
Asynchronous
/async/pages
/async/pages/search
/async/pages/:page
/async/blog/
/async/blog/post/:name
/async/blog/category/:category
/async/blog/tag/:tag
/async/blog/archive/:year/:month?/:day?
/async/blog/search
/async/tags
/async/categories
/async/params
The asyncronous routes return JSON responses.
Objects
wit-cms
buffers all site content in a wit
object. Here is an example of its
structure:
wit pages: "about" : aPageObject "contact" : aPageObject "portfolio" : aPageObject posts: "website-redesign" : aPostObject "blogging-in-node" : aPostObject "wit-vs-wordpress" : aPostObject tags: 'the-first-tag' 'the-second-tag' 'the-third-tag' 'etc' categories: 'the-first-category' 'the-second-category' 'the-third-category' 'etc' index: page: aLunrIndex post: aLunrIndex params: // arbitrary params specified on initialization
Whereby a post object takes the following shape:
title : 'The Post Name' name : 'the-post-name' url : '/blog/post/the-post-name' author : 'John Doe' categories : 'foo' 'bar' tags : 'alpha' 'bravo' 'charlie' date: datetime : '2012-09-12T00:00:00-04:00' day : '02' month : '04' pretty : '2 April 2014' // configurable unix : '1396411200' year : '2014' excerpt: '<p>Content before the break.</p>' content: '<p>The page content.</p>'
And a page object takes the following shape:
title : 'The Page Name' name : 'the-page-name' url : '/the-page-name' author : 'John Doe' description : 'A descripton for the page.' content : '<p>The full page content.</p>'
Initializing
The wit-cms
module will export a single function that will decorate an
initialized Express app. Upon invokation, the function will also return a wit
object that contains the entirety of the wit data.
const express = ;const path = ;const Wit = ;var app = ; // express configsapp;app; // wit configsvar config = // template params params: author : 'John Doe' fqdn : 'https://example.com' name : 'Example Website' tagLine : 'An example site made using wit-cms' // 302 redirect '/' to this page pages: home: '/about-me' ; // initialize the wit instanceconst wit = ;
Note that arbitrary properties may be attached to config.params
. These
properties will be made available to page templates via the returned wit
object as wit.params
.
Searching
wit-cms
provides for searching among pages and blog posts via the
lunr
module.
Commenting
Because wit-cms
stores its content in flat files instead of a database, it
does not and can not natively support a reader commeting system. If you'd like
to enable commenting on your blog, consider using Disqus or isso
.
Security
wit-cms
neither implements administrative access controls, nor requires a
database back-end. As such, it is immune to many classes of attacks to which
other content-management systems may be vulnerable.
It is not "hack proof", however. Its attack-surface consists (at least) of:
- Inputs that write to the DOM (search boxes, URLs, etc.)
- The attack-surface of Express
- The attack-surface of nodejs
As a defense against Cross-Site Scripting attacks, wit-cms
internally relies on the xss
module to sanitize user inputs that may
be written back to the DOM. Regardless, it is still prudent to use a
templating engine (ejs
, hogan
, etc.) when authoring views.
Lastly - though this should go without saying - the node
application should
never be run as root
.
Upgrading
wit-cms@v5.0.0
is backwards-incompatible with prior versions. See [the
wiki][wiki] for upgrading instructions.
License
wit-cms
is released under the MIT license. See LICENSE.txt
for details.
[wiki]: https://github.com/chrisallenlane/wit-cms/wiki/Upgrading-to-v5.0.0