I’ve been quite silent for the past few weeks because I’ve been mostly working on the PieCrust 2 documentation website – a lot of time spent writing stuff, trying out different layouts, figuring out how to organize the information, and coding the infrastructure tools that will generate separate documentations for each release.
Now at least I’ve got half of something to show, in case some of you want to provide feeback or – gasp – help! Head over to the PieCrust 2 documentation preview to see it in all its work-in-progress glory!
At this point, it’s only about a third done, so there’s probably another few weeks of work. But it’s interesting how writing documentation forces you to polish a product. This is not new – it’s really a variation of README-driven development – but that’s why it’s taking a long time: a good chunk of the documentation writing time is looking at what I just wrote, thinking that it’s completely stupid, writing what it should be like, and then fixing the code so it does exactly that.
Now that you know about PieCrust 2 and you’ve upgraded your website, it’s time to look at the really new features. Today we’ll talk about the 2 ones that I think are most important: the new content model, and the new pagination model.
(this post is going to be a bit long so here’s something to keep you hungry)
Sources, routes, and taxonomies
In PieCrust 1, like in most other static website generators, the way content was defined was quite rigid: you could have pages, and you could have blog posts. PieCrust did a few extra things, like letting you have multiple blogs, each with its collection of posts, but that was it.
The only way to have a specific set of pages, different from other pages, was to use page metadata and filtering (say, filter pages where type is recipe to get all recipes), but that didn’t translate to a good file-system organization, required remembering to tag things correctly, and required to use the inverse filter to get the other pages. You also couldn’t have a different URL format for all recipe pages, as compared to normal pages.
Enter PieCrust 2, where all the content is, under the hood, defined with sources, routes, and taxonomies. Those are generated for you to something equivalent to PieCrust 1 content if you don’t define them, but you can override that for totally custom content.
Sources
Sources are where pages come from. Two source types you already know (if you used PieCrust 1 before) are:
the “simple” page source, where pages are found recursively under a given directory, and their relative path translates to their relative URL.
one of the “blog” page sources, where pages are found in a closely structured directory, and both the date and “slug” of the post are defined by the filename. So in the case of, say, the flat post source, all posts are files named YYYY-MM-DD_foo-bar.md directly under the posts/ directory.
Because a site can have as many sources as you want, it already means you could create a “recipes” source, and put all the recipes in a different directory than the other pages, so that’s already nice.
But in the future there will also be more advanced sources. See, the “simple” page source just gives one piece of information about a page: its relative URL. But the blog post sources give more information, like the date of the article (“simple” pages need to specify it as part of their config header).
You could therefore imagine, say, a page source where each folder applies a tag to pages inside it. So if you created a page like recipes/pies/fruits/apple-pie.md, it would automatically have tags pies and fruits applied to it, as if you wrote tags: [pies, fruits] in its configuration header. Another useful source would be one that applies a hierarchical order to its pages, based on a filename prefix – this would be well suited to things like documentations.
Routes
Now that PieCrust knows where to find your content, routes define how it’s exposed – or parsed, if you were to run PieCrust as a lightweight CMS, or when running chef serve.
A route defines the shape of the URL of a page. If you’ve used PieCrust 1, you can think of it as a generalization of the post_url/tag_url/category_url settings.
At the moment, it can only use the same information as the one provided by the source (e.g. the year, month, day, and slug of a post for a blog post source), but in the future you’ll get to use all the other page metadata too (so that you can generate URLs that include categories or tags if you want).
Taxonomies
Another generalization from PieCrust 1 are the taxonomies. Before, only categories and tags would have automatically generated listing pages. Now you can have whatever you want. You just need to specify if a taxonomy can have several terms applied to a page (like tags) or not, the name of the term listing page (like _tag.html and _category.html), and a few other optional things.
Putting it all together
Let’s say we want to have a section in our website where visitors can browse our favorites recipes. We want to put all recipe pages in a recipes/ directory (next to pages/ and posts/), be able to tag them by ingredients, with listings of recipes by ingredient being created automatically, and be able to tweak the URLs for all of this.
We’ll specify appropriate sources, routes, and taxonomies in the site configuration. Let’s start with just getting the recipes going:
This will make PieCrust look for pages in the recipes/ directory, using the default page source (since we didn’t specify anything), i.e. the same as the one used for pages/. URLs that look like /recipe/foo/bar will match our new route, and a file named foo/bar.md will be loaded from the recipes/ directory in that case.
Now’s the time to add the “ingredients” taxonomy. This gets more complicated because we have several things to specify:
Add a new taxonomy named ingredients. It’s a multiple taxonomy, meaning that pages can have more than one ingredient assigned to them (this tells PieCrust it potentially has to generate listing pages for combinations of ingredients).
Add a new route for listing recipes by a given ingredient. Here, the %ingredients% token, along with the taxonomy: ingredients setting, let PieCrust know how to properly find and match content for this route.
When a listing page needs to be generated, PieCrust will look for a recipes/_ingredients.md page, passing whatever value was matched by %ingredients% to an ingredients template variable. This is analogous to how tag and category listing pages work in PieCrust 1.
Some other interesting facts:
You can list all recipes by starting with {% for recipe in recipes %}.... Sources have a page iterator exposed by default to a template variable of the same name as themselves.
You can create a new recipe page easily with chef prepare recipes foo-bar.
There are many advanced settings to change the behaviour of PieCrust, but they’re outside the scope of this already quite long blog post.
Pagination
Another big change in PieCrust 2 is how pagination is handled. In PieCrust 1, you could only paginate blog posts, but in PieCrust 2 you can paginate any list of items – pages or otherwise.
The new paginate filter lets you do that, by returning a Paginator instance, exactly like the existing pagination object. But where the pagination object returns something that lists the posts in the default blog source, the paginate filter will return something that lists whatever it was passed.
This is especially useful for galleries, as shown with my Meeting Notes doodles. This was done more or less like so:
{% set thumbs = assets|paginate(9) %}
{% for thumb in thumbs.items %}
<img src="{{thumb}}" alt="Note" />
{% endfor %}
[Older entries]({{ thumbs.prev_page }})
[Newer entries]({{ thumbs.next_page }})
Of course in reality there’s more fluff (CSS classes, etc.) and tests around using prev_page and next_page, but you get the idea. Just like in PieCrust 1, assets returns the list of page assets URLs (in this case, a whole bunch of pictures), and the paginate filter makes sure only 9 of them will be shown on a given page. It also tells PieCrust to generate sub-pages.
Obviously, you can’t use 2 pagination sources on the same page – PieCrust wouldn’t know how to generate sub-pages that go in 2 different directions, so you’ll get an error if you try that.
Call for feedback
Please get in touch with me, or post comments here, if you have some constructive feedback about this new content model. PieCrust 2 is still in alpha, so there’s time to change the design without messing up every other PieCrust user.
The recently announced PieCrust 2 is all fine and dandy if you were to create a new website – the command line interface and user experience are essentially the same out of the box – but you will find that it can’t handle an existing PieCrust 1 website. This is because a few things have changed… luckily, the chef import command and this blog post will get you going in no time!
If you want to install the bleeding edge (read “unstable”) version directly from BitBucket or GitHub, instead of the latest posted release from the Python package manager, you can do one of:
There are many other options if you want to install PieCrust for advanced scenarios. See the pip documentation.
Check that everything’s OK by running chef --version. At the time of writing, you should get something like 2.0.0-alpha2.
Note: If you still get a 1.x version, you probably have the PieCrust 1 directory showing up first in your PATH environment variable, so go change that (or delete PieCrust 1 altogether!).
Upgrading a PieCrust 1 website
The chef import command was previously used for importing content from other CMSes like WordPress. Now it can also import content from a PieCrust 1 website, and even upgrade it in place. Get in your website and try:
chef import piecrust1 --upgrade
You’ll notice that a lot of things got moved. The previous layout for a website looked like this:
Basically, the _content directory is gone… everything got moved up one level, while all the asset files (CSS, images, fonts, etc.) got moved into an asset folder1.
The benefits of this change are:
It looks better! There’s no more mix of different “things” at the root level (magic folders, assets, source-control files, miscellaneous things…). Instead, “things” are arranged in different folders that are almost self-explanatory (mostly because you can choose them!).
All the assets that should be processed and copied as part of the bake are in assets. Anything that’s only for development purposes (source control files, miscellaneous stuff) can be in the root directory, or in a different folder than assets, and they won’t be picked up by the bake. This prevents a lot of “oh shit” moments where you forgot to add something to the baker/skip_patterns config and a whole bunch of files are baked but you didn’t mean to.
It’s going to be easier to manage interoperability with other tools such as Grunt, by having such external tools operate on other top-level directories.
A few other things also changed, mainly because of the move from Twig to Jinja as the default templating engine. Although they’re very similar, they do have some differences in terms of built-in functions and filters.
An example is that Twig’s slice filter maps to an array notation in Jinja (so {{items.slice(3, 6)}} becomes {{items[3:6]}}), and Jinja’s slice does something completely different (although very useful)!
Another example is date formatting, which is different between PHP and Python.
The importer will try to fix those things automatically for you (or at least warn you about it and provide guidance), but it’s probably going to miss a few ones since I only know about those I ran into while upgrading my own websites. Please report any such problems, thanks.
Unsupported features
PieCrust 2 is not quite feature complete compared to PieCrust 1 – I can’t reasonably wait until 100% of the feature set is implemented before getting it out there for feedback.
Here are things I know are missing:
Running as a CMS: there’s not much code needed for that, but there’s no WSGI application class yet.
A plugin API: not much code needed yet either, but yeah, you can’t at the moment drop anything in the plugins folder, it won’t get loaded.
Slugification of taxonomies: tags and categories containing non-ASCII characters will keep them for now. PieCrust 1 had options for transliterating them into their non-accentuated/ASCII counter-parts.
Support for RSS/Atom feed scaffolding (chef prepare feed).
Mustache as an alternative template engine.
There are also probably things I don’t know are missing, so make sure you ping me if something you care about is not on this list.
In the next blog post, we’ll finally take a look at the new features in PieCrust 2, including the completely new underlying system for specifying pages, taxonomies, and URLs.
Don’t worry, it’s configurable. You can put your asset files in a different folder, or even in multiple folders. ↩︎
I’ve been busy on it for longer than I expected – neglecting the freshly announced Wikked along with several pull requests on PieCrust – but I believe it’s at last ready for a public alpha release: PieCrust 2 is here!
WARNING: before you go clone the new repository, be aware that, at the time of writing this, it has been tested on a glorious total of 2 machines (both my own), and 2 websites (both my own as well). So don’t use it in production, but please do give it a try and post bug reports, thanks!
This post is a short overview of the reason for going a full major version number up, and of the new things you can expect to find. There will be other posts in the following days about breaking changes and upgrade paths, and a more in-depth look at the new features.
Bye bye, PHP
To say that this is a major rewrite of PieCrust would be an understatement: I moved the project over to Python, which means it’s a 100% rewrite. This may upset some users who only know PHP (or at least don’t know and/or like Python)… but this is for the best, I assure you.
First, one of the design principles of PieCrust was always to look language-agnostic. Unlike many other static website generators out there, there’s no “leak” between the underlying implementation of PieCrust and the user experience, i.e. you’re not exposed to PHP-isms at any time while using it1. This makes it easy to change the platform on which it runs without you being affected much.
Second, the reason I picked PHP for the first implementation of PieCrust, more than 3 and a half years ago, is that it felt to me it was the lowest barrier of entry for potential users. Other static website generators embrace their hacker roots, but I wanted something simple enough that any WordPress user would be able to pick it up and try it. Nowadays, people are a lot more used to installing various things to tinker with – Git, Node, Ruby, whatever. The barrier of entry doesn’t seem to be so much at the platform level.
Those two reasons meant I could look at other platforms and figure out which one has what it takes for what I have in mind for the future of PieCrust.
Packaging and distribution
One thing that quickly became annoying in PieCrust 1 was package management (both PieCrust itself and its dependencies) and distribution (how people get PieCrust on their machines). Composer has been an incredible improvement over the venerable PEAR, but both are still a few extra steps away and more complicated than they should be.
Comparatively, gem, npm, and pip are a lot simpler and, better yet, come by default with Ruby, Node, and Python 3 respectively. Getting rid of my custom installer was an appealing thought. The PieCrust 2 install instructions would basically amount to:
Install Python 3
Run pip install piecrust
That’s much better, especially when you think that the upgrade path and hosting are all taken care of for me.
Performance
But it was performance that was the major reason I switched development platforms.
The problem was not that PHP itself was not fast enough – it’s actually doing OK in the overall category of interpreted languages. The problem is that, because it’s got so much usage as a web programming language, it’s lacking a lot of features as a scripting language. One of those features is an API for multi-threading2.
To be honest, I should have thought about it back when I started PieCrust, that I would eventually need parallel processing… but it’s never to late to change direction, which is what I’m doing with PieCrust 2.
To give you an idea of how much this impacts performance, here’s a little graph. It shows the time it takes to bake my blog (the one you’re reading now!) using Octopress (the most popular static website generator around), PieCrust 1, and the newly written PieCrust 2. Obviously, shorter is better.
Octopress takes around 21 seconds3, PieCrust 1 takes around 11 seconds4, and PieCrust 2 takes around 6.5 seconds! And that’s even before I’ve made any optimization pass specific to this new codebase!5.
So yes, there is quite a substantial gain after the move to Python and parallel baking already. And that’s even before I can get into other improvements… for example, chef serve will be able to start a background thread to monitor changes to static assets on the file-system instead of checking for them when HTTP requests come in. This should make the preview server much snappier when you’re refreshing a page that has several images or CSS sheets.
Next post we’ll look at how you can upgrade your existing PieCrust 1 website to version 2, since I took the opportunity of a major version bump to clean up a few things I didn’t like anymore.
Except for date formats. Sadly, date formats are very much tied to the underlying framework – unless you implement your own wrapper syntax – and this is one annoying breaking change when upgrading to 2.0. I’m open to ideas to fix that of course! ↩︎
There are a couple extensions available to fill the gap, but they’re just terrible. ↩︎
And that’s only for the posts on this blog, along with the tag pages, with simplified markup… my crude interop script strips out code highlighting blocks and other expressions (e.g.{{foo}} expressions). I’m expecting the real thing would take an additional second or two. ↩︎
See how little it matters whether PHP sucks more or less than Ruby? Design and implementation are a lot more important for the big gains. ↩︎
Most optimizations from PieCrust 1 were ported over to the Python codebase already. ↩︎
It’s been long overdue, since PieCrust 1.0 was released more than 4 months ago, but at last it’s here: PieCrust 1.1!
Every time I figure I will go with a “release small, release often” kind of philosophy, I still end up with more of a “wait, I’ll just get this last feature ready first” kind of vicious circle… sigh.
Anyway, grab the new release, or keep reading if you want to know about the most important changes. As always, big thanks go to the people who reported bugs and/or helped fix them, or generally participated in the evolution of PieCrust.
Removing deprecated stuff
The first, most important change is that anything that was marked as deprecated, and that usually triggered a warning message if you used it, has been removed. So if you’re still using it, it will just break or, worse, silently do something else.
Make sure you don’t have any of those warnings before you update.
Self updating
If you’re running PieCrust from an installed binary (a .phar file), you will be able to update it easily with the chef selfupdate command… well, not this time (you’ll have to re-run the installer), but next time!
By default, the installer gets you the stable version of PieCrust so if you run the selfupdate command, it will always get you the latest stable. But you could also switch to the master branch (where things are in development) by running chef selfupdate master. Running selfupdate (with no argument) from now on would get you the latest master version until you switch back with chef selfupdate stable.
I hope this will encourage people to update more often, and to not be afraid to try things out on the master branch.
Also, it’s probably not working 100% so make sure you report any issues with the self-updater 🙂
Post iterator improvements
The post iterator, the thing you get when you want to loop over pagination.posts or site.pages, has a few new tricks:
Each page object that it returns now has access to the assets of that page. This is pretty handy if you want to display thumbnails or something.
The iterator itself now has a few “magic” functions to make simple filtering easier and faster to do. You can use is_foo(value) or has_foo(value) directly on the iterator to filter pages that have the foo setting set to value, or to an array that contains value respecively. This saves you from having to use filter() and define a filter in the header.
Temporary caching
You likely have something in your website layout that has to be computed for each page, but ends up being the same all the time during a single bake operation. To speed this up, there’s a new pccache operator that you can use.
Check out the documentation, with an example where it’s used to only compute a tag cloud in a sidebar once per bake. That example is incidentally from my own blog, and it cut the baking times in half… so yeah, I highly recommend it.
New baking infrastructure
PieCrust is now using a brand new system to keep track of what it’s baking now, compared to what was baked last time. This means that it’s now possible to delete files that we know we created last time, but are not valid anymore:
A page or asset that was deleted.
A page that doesn’t generate as many sub-pages as before.
A whole bunch of files that moved because the post_url, or some other URL-generation setting, changed.
Miscellaneous
A few other noteworthy changes:
The .md and .textile file extensions are now added to the auto_formats by default, which means any file (page or blog post) with that extension will be treated as Markdown or Textile respecitively.
The concept of “variants”, i.e. different versions of your website’s configuration, are now generalized to the whole of chef. See the documentation about it.
There’s no sample website anymore. If you’re feeling nostalgic, however, you can get back that ugly piece of blue as a theme.
That’s it! Grab the new version by re-running the installer, or getting the new source code from Github or BitBucket (where you can also report any issues).
PieCrust reached the big milestone of version 1.0 without much fanfare – and this post won’t be any different from the other release announcements. After a few release candidates I figured I would never be quite satisfied, so why not just keep going with the releases and not pay too much attention to the first digit.
You’ll see releases 1.1.0 and up coming soon, with the usual bunch of fixes, changes, and new features. The only difference is that the version number will now reflect better what’s going on, since I’ll be loosely following the semantic versioning specification. In a nuthsell, the digit being incremented reflects whether a release is a bug fix, a non-breaking change, or a major and/or breaking change.
The one big new thing that comes with version 1.0 is an installer script, along with a .phar binary, to make it easier for people to use PieCrust if they don’t want or need the source code. Head over to the PieCrust documentation for more information.
For the rest of the changes, keep reading.
Auto-formats
One popular request has always been to make it possible for users to write pages and posts using other extensions than .html – most specifically .md or .markdown. This is now possible with the auto-format feature, which maps extensions for formats. As of 1.0, no auto-format is declared by default, so you have to specify the ones you want in your config.yml:
The example above maps extensions .md and .markdown to the Markdown format (same as if you specified format: markdown in the page’s config header), and extension .textile to the Textile format.
As of version 1.1, .md and .textile will be defined by default.
Template data changes
Some page template variables have been changed:
asset is now assets.
link is now siblings, and returns the page’s sibling pages (i.e. in the same folder).
There’s a new family variable that returns a recursive version of siblings (i.e. sibling pages and all the children pages in sub-directories).
The old names are still available, but will trigger warnings when you bake.
Feed preparation
The chef prepare command can now create more than pages and posts for you: you can run chef prepare feed and it will create a boilerplate RSS feed page for you.
You can specify --atom to create a boilerplate Atom feed instead.
Plugin update
If your website has some plugins, you can update them easily with the new chef plugins update command. Right now it will just stupidly re-download the plugins from their source, so it may re-install the same version, but that’s enough for now 🙂 It’s especially handy if you have some custom plugin that’s used by several websites.
Sass, Compass and YUICompressor
Speaking of plugins, the previously plugin-implemented Sass, Compass and YUICompressor processors are now part of the core PieCrust code.
They have also been improved in the process. Most importantly, Compass support is a lot better.
Miscellaneous changes
The monthly blog archives (blog.months) was incorrectly ordered chronologically, instead of reverse-chronogically. This is now fixed.
Anywhere that returns a list of pages or posts should now have consistent behaviour and features, e.g. filtering template functions.
You can get access to Twig’s debug functions by setting the twig/debug site configuration variable to true.
If you want PieCrust to use the Javascript lessc compiler to process LessCSS stylesheets, set the less/use_lessc site configuration variable to true.
Pretty colors for chef commands on Mac/Linux! (this is important)
For the complete list of changes, see the CHANGELOG.
The question has come up a couple times already via email or Twitter, so here’s a quick recipe to write a nice looking archive page for your PieCrust blog.
There are 2 main types of blog archives: monthly archives and yearly archives. We’ll look at them one at a time after the break.
Yearly archives
This is the simplest one. Because PieCrust exposes your posts sorted by year in the blog.years template variable, you just need to loop on that with a for loop. Each object returned in the loop contains the following attributes:
posts: the list of posts for that year.
name: the name of the year (although you can also use the object itself, which is what we’ll do).
You end up with something like this:
---
layout: blog
title: Blog Archives
format: none
---
{% for y in blog.years %}
<h2>{{ y }}</h2>
<ulclass="archive-list">
{% for p in y.posts %}
<li>
<p>
<ahref="{{ p.url }}">{{ p.title }}</a>
<timedatetime="{{ post.date|atomdate }}">{{ p.timestamp|date('M d') }}</span>
</p>
</li>
{% endfor %}
</ul>
{% endfor %}
Note how we render the date of each post with a custom format using the date filter (here using only the day and month). For more information about the date filter, check out the Twig documentation. Also, to provide a little bit of metadata, we use a time tag along with the atomdate filter, which is a handy shortcut for using the date filter specifically with an XML date format. Of course, you don’t have to keep that same markup – you can reuse the Twig logic but completely change the rest.
Monthly archives
This one is a bit more complicated. Although PieCrust also exposes your posts sorted by month in blog.months, you still need to spot changes in years so you can print a nice title or separator. To do this, we keep a variable curYear up to date with the current post’s year. If the post has a different year than the post before it, we print the new year in an h2 tag.
Each object in the blog.months has the following attributes:
posts: the list of posts in that month.
timestamp: the timestamp of the month, so you can render it to text with the |date filter.
So to get the year of each month, we use month.timestamp|date("Y"). To print the name of each month we use month.timestamp|date("F").
In the end, it goes something like this:
---
layout: blog
title: Blog Archives
format: none
---
{% set curYear = 0 %}
{% for month in blog.months %}
{% set tempYear = month.timestamp|date("Y") %}
{% if tempYear != curYear %}
{% set curYear = tempYear %}
<h2>{{curYear}}</h2>
{% endif %}
<h3>{{ month.timestamp|date("F") }}</h3>
<ul>
{% for post in month.posts %}
<li>
<ahref="{{ post.url }}">{{ post.title }}</a>
<timedatetime="{{ post.date|atomdate }}">{{ post.date }}</time>
</li>
{% endfor %}
</ul>
{% endfor %}
Again, feel free to keep the logic and change the markup to your liking – that’s the whole point of PieCrust!
The past month has been pretty busy, between my next secret project, my day job, and of course fixing PieCrust bugs. But somehow among this chaos seems to be emerging a release candidate for PieCrust 1.0. And it’s only fitting that I announce this on Pi Day!
As always, for a complete list of changes, I’ll redirect you to the changelog. But for the highlights, please read on.
Big thanks go to the few people who contributed patches to the PieCrust code, and to the many who reported bugs and had the patience to help me fix them.
Breaking changes
First, the breaking changes. There are a bit more than I’d like, but most of them should not be a problem to 99% of users:
Chef’s command line interface has changed: global options now need to be passed first, before the command name. So for example, if you want debug output when baking, you need to type chef --debug bake.
The pagination.posts iterator can’t be modified anymore (i.e. calls to skip or limit or filter will fail). You can use the blog.posts iterator instead to do anything custom.
The xmldate Twig filter has been renamed to atomdate.
There was a bug with the monthly blog archives (accessed with blog.months), where they would be incorrectly ordered chronologically. They are now ordered reverse-chronologically, like every other list of posts.
The baker/trailing_slash is now site/trailing_slash, since PieCrust will also generate links with a trailing slash in the preview server, and not just during the bake, when that setting is enabled. The old setting is still available, though.
The asset template variable is renamed assets. The old name is still available.
Specifying a link to a multi-tag listing page is now done with the array syntax: {{pctagurl(['tag1', 'tag2'])}}. The previous syntax quickly broke down as soon as somebody decided to have tags with slashes in their name 🙂
All those changes should give you an error message that’s easy to understand, or have backwards compatibility in place with a warning telling you about the change. Look out for those.
Sass, Compass and YUI Compressor
Previously available as plugins, the Sass, Compass and YUI Compressor file processors are now part of the core. There were enough people mentioning those tools, especially Compass, that it made sense to include them by default.
The Sass processor is very similar to the one previously available in the plugin. In the site configuration, you can specify include paths with sass/load_paths, output style with sass/style, or any custom option to pass to the Sass tool with sass/options.
Compass support, however, has changed quite a bit, and should be now a lot better:
You enable it by setting compass/use_compass to true. This will prevent the default Sass processor to run on your .scss files.
If .sass or .scss files are found in the website, the compass tool will be run at the end of the bake. It will by default use any config.rb found at the root of the site. You can otherwise specify where your Compass config is with compass/config_path, or ask PieCrust to auto-generate it for you with compass/auto_config to true.
It may be a good idea to add your config file to the baker/skip_patterns list, so that it’s not copied to the output directory.
To enable the YUI Compressor to run on anything that outputs CSS, specify the path to the .jar file with yui/compressor/jar.
Linking feature now official
For a while, there was a link template variable that let you access other pages in the content tree. It was however never really official since I was still iterating on the design.
It’s now official, and available through the siblings template variable. It will return the pages and directories next to the current page.
To return the whole family tree starting from the current page, you can use family. It’s like a subset of site.pages.
Auto-format extensions
Another popular request is the ability to use different file extensions for pages and posts, like .md for Markdown content or .textile for Textile content.
This is now possible with site/auto_formats. This is a list that maps an extension to a format name:
site:
auto_formats:
md: markdown
mdown: markdown
Here I’m mapping *.md and *.mdown to the Markdown format. Files found with those extensions will be treated as if they were .html files, but will also have their format set to markdown.
Feed preparation
If you write a blog, you most probably want to have an RSS feed. You can have one prepared for you with: chef prepare feed myfeed.xml. It will create a new page that has most of what you want by default. You can then go and tweak it if you want, of course.
Miscellaneous
A few other important changes:
All libraries (including Twig, Markdown or Textile) have been upgraded to their latest versions.
It is now possible to specify posts_filters on a tag or cateogory page (_tag.html or _category.html).
When I first decided to work on PieCrust, I settled with PHP as the language – even though it mostly sucks – in an attempt to make it broadly available. Anybody who runs a blog on WordPress should be able to switch and enjoy the perks of plain text data without needing to install and learn a whole new environment.
That doesn’t mean PieCrust can’t also be used in the nerdiest ways possible. A while ago we looked at how cool it is to update your website with Git or Mercurial, and today we’ll look at how you can host it on Heroku, which incidentally also supports Git-based deployment.
If you already know how Heroku works, then the only thing you need is to make your app use the custom PieCrust buildpack. Skip to the end for a few details about it.
For the rest, here’s a detailed guide for setting up your PieCrust blog on Heroku, after the break.
1. Sign up and setup
This is pretty obvious but it’s still a step you’ll have to go through: sign up for a Heroku account and install their tools. Follow the first step to login via the command line, but don’t create any app just now.
2. Create your PieCrust website
For the sake of this tutorial, let’s start with a fresh new site. You will of course be able to use an existing one, the steps would be very similar.
Let’s create one called mypiecrustblog:
> chef init mypiecrustblog
PieCrust website created in: mypiecrustblog/
Run 'chef serve' on this directory to preview it.
Run 'chef bake' on this directory to generate the static files.
Let’s also add a post, just to be fancy:
> chef prepare post hello-heroku
Creating new post: _content/posts/2012-12-03_hello-heroku.html
Last, turn the site into a Git repository, make Git ignore the _cache directory, and commit all your files:
By the way, you can quickly check what the site looks like locally with chef serve. We should be able to see the exact same thing online in a few minutes when it’s running on Heroku.
3. Create your Heroku app
Now we’ll turn our site into a Heroku app. The only difference with the documentation on the Heroku website for this is that we’ll add an extra command line parameter to tell it that it’s a PieCrust application:
> heroku create mypiecrustblog --buildpack https://github.com/ludovicchabant/heroku-buildpack-piecrust.git
Creating mypiecrustblog... done, stack is cedar
BUILDPACK_URL=https://github.com/ludovicchabant/heroku-buildpack-piecrust.git
http://mypiecrustblog.herokuapp.com/ | git@heroku.com:mypiecrustblog.git
Git remote heroku added
What’s happening here is that, in theory, Heroku doesn’t know about any programming language or development environment – instead, it relies on “buildpacks” to tell it what to do to set up and run each application. It has a bunch of default buildpacks for the most common technologies, but it wouldn’t know what to do with a PieCrust website so we need to provide our own buildpack, with that --buildpack parameter.
If you already created you app previously, you can also make it a PieCrust application by editing your app’s configuration like this:
At this point, you should be able to browse your website on Heroku (http://mypiecrustblog.herokuapp.com in our case here).
You now just need to keep adding content, and git push to make it available online.
Appendix: The PieCrust buildpack
The PieCrust buildpack we’re using in this tutorial will, by default, bake your website and put all the generated static files in the www folder for the world to enjoy.
If, however, you set the heroku/build_typesite configuration setting to dynamic, it will copy the PieCrust binary (a .phar archive) to your app’s folder and create a small bootstrap PHP script that will run PieCrust on each request. This would make deployments very fast, as you won’t have to wait for the website to re-bake, but it’s highly recommended that you use a good cache or reverse proxy for anything else than test websites.
Note that the version of PieCrust that’s used by the buildpack is, by default, the latest one from the development branch (default in Mercurial, master in Git). You can change that with the PIECRUST_VERSION environment variable. For example, to use the stable branch instead, you can do:
> heroku config:add PIECRUST_VERSION=stable
For more information about the buildpack, you can simply go check the source code over on Github.
I just pushed a lot of changes to the dev branch of PieCrust, including the new support for themes. The point of themes is to make it easy to change your website’s appearance by further separating content and look.
Here’s an early look at how themes work, so that anybody can play with it and provide feedback. Not everything is in place yet, so now’s the best time to affect the design.
The theme folder
When a website is using a theme, that theme will be placed in the _content/theme folder.
The theme itself is really just another PieCrust website: it has its own _content folder with pages and templates and everything you expect. The only differences are:
The configuration file is named _content/theme_config.yml instead of _content/config.yml. This is so chef is not confused as to what’s the root of the current website when you go into the theme folder.
A theme should have a theme_info.yml file at the root of the theme. It’s a YAML file with, at minimum, a name and description.
The theme behaves as follows:
Pages defined in the theme (in _content/pages, like any other PieCrust website) are added to the base website, unless a page with the same URL has been defined there. It makes it possible for themes to define pages like an “About” page or some blog archives. They effectively complement the website on which the theme is applied.
The theme’s templates directories (site/templates_dirs setting) are added before the default _content/templates directory, but after any other custom directory defined by the website. It makes it possible for themes to override the default templates, and for users to override a template defined in a theme.
The themes command
A new themes command is available in chef. It looks a lot like the plugins command in the sense that is offers the same 3 sub-commands: info, find and install. Right now, however, there are no themes in the default repository, so chef themes find won’t return anything, which means there’s no theme to install.
You could setup a local repository by setting site/themes_sources to /path/to/my/themes, where that path contains one or more themes in sub-directories. You can then install one of your local themes by running chef themes install <name>, which basically just copies the theme inside _content/theme.
For faster development, however, I would recommend just sym-linking your theme’s root directory to _content/theme.
Quickstart
To summarize, here’s how you can write a theme for PieCrust at the moment:
Create a PieCrust site as usual.
Rename _content/config.yml to _content/theme_config.yml.
Add a theme_info.yml file at the root. This is a YAML file, just like config.yml.
Give it a name.
Give it a description.
Write pages, templates, CSS stylesheets and so on.
It’s a good idea to implement standard pages like _index.html, _tag.html and _category.html.
It’s also good to implement standard templates like default.html and post.html.
When you’re happy, symlink – or copy – the theme’s directory to a website’s _content/theme directory. Play around by adding new pages and posts to that site.
As always, report issues on the BitBucket or Github issue trackers.