Static Site Generation With Sculpin

March 2, 2014

There are many static site generators out there. This post covers setting up a simple static website using the Sculpin static site generator, written in PHP. I found this to be a well-maintained project with easy to follow documentation.

Most dynamic websites are built using a multi-tier architecture. For a relatively simple website it is possible to cut out the data and business-logic layers and serve only static html content. This makes a site more manageable, faster, and easier to deploy. The site is composed on a web author's computer and compiled into static html pages that can be uploaded and easily served by a webserver like Apache or Nginx.

Individual posts and pages in Sculpin are composed in either Markdown, Twig, or HTML. Learning the Markdown syntax is straightforward and provides a really clean and simple way of writing web documents. Twig is a powerful and easy to use PHP templating engine with loads of great documentation.

Getting Started

The easiest way to get started with Sculpin is to get the Sculpin executable and download and run the Sculpin skeleton blog. This is also described in the Sculpin getting started guide.

Download Sculpin

curl -O https://download.sculpin.io/sculpin.phar
chmod +x sculpin.phar

Move it to somewhere useful

mv sculpin.phar ~/bin/sculpin

If you can't type sculpin from any directory, you must add this directory to your $PATH. You can do so by adding this line to your .bash_profile or .bashrc in your home directory.

export PATH=$PATH:$HOME/bin

Next, grab the sculpin skeleton blog, run it, and start poking around.

git clone https://github.com/sculpin/sculpin-blog-skeleton.git
cd sculpin-blog-skeleton

Install the project's dependencies

sculpin install

Generate the site's static files, watch for changes to any file, and run a local webserver to view the site

sculpin generate --watch --server

You should now be able to see your site at http://localhost:8000. If you make any changes to the site, Sculpin will pick these up and re-generate the static files.

Another great way to get started is by looking at the source of other sites built with Sculpin. The source for this website is available here and there are many other examples listed in the Powered by Sculpin section of the Sculpin homepage.

Configuration

Sculpin's configuration is driven by a series of YML files located in the app/config directory.

sculpin_kernel.yml: Provides system configuration, such as content types like blog posts and their url structure. The sculpin_kernel.yml provided with the skeleton blog configures posts and their permalinks, and should be fine to get started with.

sculpin_site.yml: Provides site-wide meta data configuration. Things like a site title, Google Analytics tracking ID, or text that may be repeated in more than one layout can be set here.

sculpin_site_${env}.yml: Provides environment-specific meta data configuration. This file is read instead of the default site config when the --env switch is given to the sculpin command.

sculpin generate --watch --server --env=production

The above command will look for a file called sculpin_site_production.yml. The default site config can be included as a collection of default values that the sculpin_site_production.yml can override.

imports:
  - sculpin_site.yml
url: http://my-production-domain.com

This property can then be accessed from any template

<a href="{{ site.url }}">Home</a>

A list of properties can also be declared...

some_global_images:
    - 
        filename: img1.jpg
        alt: "An image"
    - 
        filename: img2.jpg
        alt: "Another image"
    - 
        filename: img3.jpg
        alt: "Yet another image"

...and then used in a template

{% for image in site.some_global_images %}
  <img src="{{ site.url }}/images/{{ image.filename }}" alt="{{ image.alt }}"></img>
{% endfor %}

Page Templates

By default, Sculpin looks for templates in the source/_views directory. Creating a template is as simple as creating a .twig file here. A hook may be added to a template for injecting page content somewhere within that template.

For example, a template named base.twig might define a global header and footer.

<html>
  <head>
    ...some global includes...
  </head>
  <body>
    ...some header code...

    {% block content %}Page content gets inserted here{% endblock %}

    ...some footer code...
  </body>
</html>

A template can then be specified on any page. Sculpin will compile any page within the source directory. For example, an index.html could use the base.twig template created above.

---
layout: base

---
Content for index.html defined here will be inserted into the {% block content %} block in base.twig

Posts

Sculpin provides by default a mechanism for writing blog style posts. Posts are composed in the source/_posts directory as files with the name YYYY-MM-DD-post-name.md. Post permalinks are set up in sculpin_kernel.yml:

sculpin_content_types:
    posts:
        permalink: blog/:year/:month/:day/:filename/

Metadata for a post is added in YAML front matter. For example a post named 2014-03-02-some-post.md may look like

---
title: The title of this post
some_page_property: 
    property1: Property 1
    property2: Property 2
tags: 
    - one
    - two
    - three
---
The post content with property 1: {{ page.some_page_property.property1 }}

Tags:
{% for tag in page.tags %}
{{ tag }}!!<br/>
{% endfor %}

Defining custom content types is also possible, and explained in the Sculpin documentation

Paginating posts is also straightforward. In your source/_views/post.twig template or source/_views/blog.twig blog index template, add

{% if page.pagination.next_page %}
    <a href="{{ site.url }}{{ page.pagination.next_page.url }}">Older Posts</a>
{% endif %}
{% if page.pagination.previous_page %}
  <a href="{{ site.url }}{{ page.pagination.previous_page.url }}">Newer Posts</a>
{% endif %}

You'll also need to instruct the blog.twig template to use the pagination generator for posts

---
layout: base
title: Blog
generator: pagination
use:
    - posts
---
Blog index content goes here...

Comments

Since Sculpin generates static websites, this means that comments need to be included as a service. This site uses Disqus, a free service that allows people to post comments with their Facebook, Twitter, Google+, or Disqus identities. It also allows anonymous posting and comment moderation.

To include the Disqus plugin on any page, just include the disqus widget snippet in your post template. This is also available on the Disqus site after signing up for an account.

<script type="text/javascript">
    var disqus_shortname = 'your_disqus_shortname'; 

    (function() {
        var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
        dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    })();
</script>
<noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
<a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>

Deployment

To push your site live, first generate the site with production configuration. Remember, this loads site configuration from app/config/sculpin_site_production.yml

sculpin generate --env=production

This will create an output_production directory with the entirety of your static site's content. You can ftp, scp, or rsync this to your public http server.

 

comments powered by Disqus

About This Site

This site was designed by We Are How.

This site is powered by Sculpin static site generator and the source is available here.

Yotta = 10^24, or 1 000 000 000 000 000 000 000 000, the largest metric prefix.


Contact

Get in touch to find out how we can help you refine your vision and implement a dynamite product that will help your business grow. Our agile product development process is thoughtfully designed to give clients ongoing feedback and visibility from project inception to completion.