The goal of this guide is to get you up and running quickly with mynt. If after reading this guide you still have questions that aren't answered by the other doc pages or you run into any issues, feel free to open an issue on GitHub or hop in IRC.

Installation

The recommended way to install mynt is via pip. If you already have pip installed, the below command is all you need. Otherwise, head on over to the pip site to get it installed.

1
$ pip install mynt

If you'd like support for reStructuredText install mynt using the following command:

1
$ pip install mynt[reST]

After mynt has been installed, run the mynt command with the --version flag to confirm everything completed successfully.

1
$ mynt --version

Directory structure

Let's start off by initializing a new site. This is done with the init subcommand.

1
$ mynt init ~/projects/my-mynt-site/

Throughout the rest of this guide, the directory you initialized your site in will be referred to as the project root. Given the above usage of init, the project root would be ~/projects/my-mynt-site/.

If the directory you want to initialize your site in already exists, you will have to pass the -f flag to force initialization.

1
$ mynt init -f ~/projects/my-mynt-site/

In doing so, mynt will delete that directory in the process. For example, if the directory my-mynt-site already exists in ~/projects/, the above command will delete my-mynt-site before recreating it and initializing your site there.

Now that you have your site initialized, let's go over how mynt interacts with the directories and files of your site.

The first thing to go over is that any directory or file who's name begins with an underscore or period will be ignored. The one exception to this rule being the five special directories that we'll talk about shortly.

This behavior can be overridden by using the include config setting.

Beyond that rule, mynt will try to parse any file that isn't being ignored. It does this by looking for a parser that accepts the given file. If one is found it will be used to parse the file otherwise it will be ignored.

Now, onto those five special directories. In a mynt site there are five special directories: _assets/, _containers/, _locales/, _posts/, and _templates/. These five directories are located at the project root and are reserved for use by mynt.

The assets directory

The assets directory is where all of your, well, assets live. CSS files, images, JavaScript libraries, file downloads, and so on.

One place ignored directories can be useful is in the assets directory. For example, if you are using a CSS preprocessor like SASS, you can put your SASS files in _assets/css/_sass/, have SASS output to _assets/css/, and all of your SASS files will be ignored by mynt.

The containers directory

The containers directory is used for the content containers feature which we'll go over later. For now it's enough to know that it serves a role similar to that of the posts directory.

The locales directory

The locales directory is used for localization. Localization is a bit of a complicated topic to get into here, so just know that this is where your .mo files would live if you were maintaining a site available in multiple languages.

The posts directory

You likely guessed it, the posts directory is where all of your posts will live.

Ignored directories can also be put to use in the posts directory. For example, if you have some post ideas you are working on, but aren't ready to publish them, you can put them in _posts/_drafts/ and mynt will ignore them.

The templates directory

Lastly, there's the templates directory. The name of this directory can be a bit confusing for the sole reason that any HTML or XML file that isn't being ignored is a template. They are all processed by the configured renderer (Jinja by default).

The difference between having a template in the templates directory and somewhere else in your site, is that templates in the templates directory are not actual pages. They are simply templates that get reused by other templates or are used by mynt internally (like a post's layout).

It may help clear things up if you think of the templates directory as an includes directory.

Configuration

The configuration of mynt is handled by a single file at the root of your project: config.yml. If the file doesn't exist a set of defaults will be used, but if you wish to change any settings you'll have to create it. All of the settings are rather straight forward, so I won't go over them in detail here, but if that's what you're looking for, check out the config documentation.

One powerful thing about mynt's configuration file, is that everything in it, mynt setting or not, is made available to templates. This can be taken advantage of in many ways. For example, you could add a title or author attribute for use in templates and then if you ever need to change that information, all you have to do is update it in your site's config rather than in every template.

Templates

With your site set up and a general sense of how a mynt site is structured, let's move on to templates.

In the case of this guide (and also by default) the renderer used is Jinja. If you're not already familiar with Jinja, head on over and give the Jinja documentation a quick read.

For the most part a template in mynt is no different from any other Jinja template. However, there are three things worth mentioning. The first being two mynt specific helper functions and the second as well as the third being the available globals and locals.

Helper functions

Two mynt specific helper functions are provided to make retrieving URLs within your site easier. They do this by taking into account how your site is configured. Specifically the assets_url, base_url, and domain config settings.

The first helper function is get_asset(). You should use it whenever you need a URL to anything living in the assets directory. The second helper function is get_url() and it should be used whenever you need a URL to anywhere else in your site.

Whenever you need a link internal to your site, you should use these two helper functions. The reason being, if you ever decide to move it, you'll only need to update the relevant config settings.

Globals

Template globals are variables containing site data that are available in every template. There are three template globals: site, posts, and containers. The first, site, is a dictionary of everything in your site's config file. The other two contain your site's content, posts for your posts and containers for your content containers (a feature that we'll take a look at in a bit).

For a detailed look at the structure of the template globals, check out the globals section of the templates documentation.

Locals

Template locals are very similar to the globals we just discussed with the one exception that they are only available in specific templates. There are three template locals: item, archive, and tag.

Each local contains the data for a single member of it's respective global. In turn, they are only available in templates defined by their respective layout config settings. For example, item is only available in layout templates, archive in archive_layout templates, and tag in tag_layout templates.

For a detailed look at the structure of the template locals, check out the locals section of the templates documentation.

Posts

Now with templates out of the way, let's move on to posts.

The first thing you need to know about posts is that a post's filename is very important. The first of which being, in order to specify a post's date, the filename needs to be formatted in a specific way:

1
[YYYY-MM-DD[-HH-MM]-]An-example-post.md

If you don't specify a date in the filename following the above format (hour and minute optional), the post's date will be set to when the file was last edited.

Also important is the file extension. The file extension determines which parser will be used. For example, files with the .md extension will be parsed by the Markdown parser. If you installed mynt with reStructuredText support, files with the .rst extension will be parsed by the reStructuredText parser.

Now let's take a look at how posts need to be formatted themselves.

There are only two things that differentiate a post from an ordinary document of the markup language being used. The first being the YAML frontmatter and the second being the ability to use the features of the configured renderer.

YAML frontmatter

The YAML frontmatter is a block of YAML fenced by three dashes at the start of a post containing post metadata. It looks like the following:

1
2
3
---
layout: post.html
---

Every post requires a YAML frontmater with the layout attribute set. The layout attribute tells mynt which template in the templates directory it should use to render the post.

There are only two other attributes that have a special meaning in the YAML frontmatter. The first, parser, provides a way to explicitly set which parser will be used. The second, though it's optional, is tags. The tags attribute is used by the tagging feature mynt provide which we'll talk about later.

You are free to add whatever data you want to a post's YAML frontmatter and it will be available in templates when accessing that specific post. A common example of this is using an attribute to store the formatted version of a post's title.

There are many ways to make use of the YAML frontmatter. For example, you can implement simple multiple author support by adding an author attribute to every post. Then a specific author's posts can be grabbed by filtering a for loop or using the groupby filter.

1
{% for post in posts if post.author == 'Author' %} ... {% endfor %}
1
{% for author, posts in posts|groupby('author') %} ... {% endfor %}

Renderer functionality

All of the features of the configured renderer are also available for use in posts with the exception of what data is available. The only template data available to posts is the YAML frontmatter of the post itself and the site template global.

1
2
3
4
5
6
7
8
---
layout: post.html
title: An example post.
---

# {{ title }}

![image]({{ get_asset('images/image.jpg') }})

For example, in the above post, Jinja functionality is used to create a header containing the value of the title attribute from the YAML frontmatter as well as a template helper to grab a link to an image.

Tagging

With templates and posts covered, let's move on to how mynt handles tagging.

To tag a post, simply add the tags attribute to the YAML frontmatter containing a list of the desired tags.

1
2
3
4
5
---
layout: post.html
title: An example post
tags: [Foo, Bar]
---

Tags are case-sensitive. "Foo" and "foo" are two different tags.

Once a post has been tagged, this change is reflected in a couple of ways. First, all of a post's tags will be available via a tags attribute. Second, that post will be added to each tag in the tags property of the posts global.

Automatic tag pages

If your site has a lot of tagged posts it may be desirable to have a separate page for each tag. One of mynt's key features is the ability to do just that.

To enable it, tag_layout must be set in your site's config. This setting tells mynt which template in the templates directory to use when rendering these pages. Once it is set, a page will be rendered for each tag using that template.

Archives

We've gone over posts and tagging so now let's talk about archives.

For the most part, how you want to handle post archives is up to you. To give you as much flexibility post data is available in a handful of different ways, most notably the archives property of the posts global which is a dictionary of your site's posts organized by year and month.

Automatic archive pages

Just like with tags, another key feature of mynt is the ability to automatically generate archive pages. If your site has a lot of posts or if you want to provide an alternate more compact way of browsing all of your site's posts, such a feature may be of use to you.

Enabling this feature is done very much in the same way as enabling automatic tag pages. In your site's config, set archive_layout in the same manner as tag_layout. In doing so a page will be rendered for each year a post was made using that template.

Content containers

It's come up a couple of times already so now let's go over the content containers feature.

The content containers feature allows you to define containers that are handled exactly like posts, but are separate. For example, say you have a personal site with a blog, but you want a separate section of your site for the talks you've given. Let's walk through how we'd use a content container to accomplish that.

Configuration

The first step is creating a content container. This is done by putting the following in your site's config:

1
2
3
containers:
    talks:
        url: /talks/<slug>/

What's happening here is pretty straightforward. We're defining a container named talks and setting the URL for that container to /talks/<slug>/. The url config setting for content containers behaves identically to the posts_url config setting with the one exception that the url config setting must be set for each content container.

For a list of the config settings available to content containers, check out the config documentation.

File location

So where do you put your files? Remember the _containers special directory that was mentioned earlier? A container's files live in a directory with the same name as the container in that special directory. In this case that'd be _containers/talks/.

Tags and archives

The similarities between content containers and posts doesn't end there. The tagging and archives features available to posts are also available to content containers and are enabled in the same way. For example, to automatically generate tag pages for the talks container set the tag_layout:

1
2
3
4
5
containers:
    talks:
        url: /talks/<slug>/
        tag_layout: tag.talks.html
        tags_url: /talks/tag/

Template data

All that's left to go over is the containers template global. For posts there's the posts global, but how do you access content container data in your templates? The answer is the containers template global.

1
{% for talk in containers.talks %} ... {% endfor %}

A container's tag and archive data can be accessed the same as with posts:

1
2
{% for tag in containers.talks.tags|values %} ... {% endfor %}
{% for archive in containers.talks.archives|values %} ... {% endfor %}

Now you can use your preferred markup language to post your talks and even have tag and archive pages generated for them.

Pages

Lastly, we have pages. Any file outside of the special directories is considered a page by mynt.

All pages will be in the same location after generation as in the source tree. For example, an index.html at the project root will be the site's index page after generation.

The simplest pages are plain HTML files and are processed by the configured renderer. However, it is also possible to create pages using a supported markup language. Such pages behave very similar to posts and as such require a YAML frontmatter with the layout attribute set.

For example, assuming _templates/page.html contains the following:

1
2
3
4
5
6
7
8
9
<html>
<head>
    <title>{{ item.title }}</title>
</head>

<body>
    {{ item.content }}
</body>
</html>

You could write the index page in Markdown by saving the following as index.md at root of the project:

1
2
3
4
5
6
---
layout: page.html
title: It works!
---

It really does!

However, there is one disadvantage to be aware of when creating pages in this manner. The posts and containers template globals are only available to HTML pages. Other than that, the choice between HTML and markup pages is down to preference.

Generation

Now that we have the basics covered, it's time to generate your site.

Generating a mynt site is handled by two different subcommands: gen and watch. If you just need to make a quick change, gen is best for the job. It will generate your site and then exit.

1
$ mynt gen <source> <destination>

If you're going to be making a bunch of changes to your site, constantly reusing gen will quickly become a hassle. Instead you can use the watch subcommand.

1
$ mynt watch <source> <destination>

For the most part it is identical to gen, however, with watch, every time you make a change to your site it will automatically regenerate.

When using either subcommand, if the destination already exists, you will have to pass the -f flag to force generation.

1
$ mynt {gen,watch} -f <source> <destination>

In doing so, mynt will delete any directory or file at the root of the destination that doesn't begin with an underscore or period.

Now that you've generated your site, I'm sure you want to check it out. If you have a local server setup you're good to go, but if you don't, mynt's got you covered. The last subcommand we're going to talk about is serve.

1
$ mynt serve <source>

This subcommand should not be used to publicly host your site. It should only be used for local development and testing.

To start up the server pass the directory containing your generated site to the serve subcommand. Then, to view your site open your browser to http://localhost:8080/.

For a more detailed look at the commands mynt provides, check out the command line documentation.

Once you're happy with your site, you're good to upload it to the host of your preference, whether that be GitHub Pages or your own VPS.

Fork me on Github