Content Management



Creating new content

How to create new posts or pages has already been described in quickstart. See more details here regarding commands bestatic newpage filepath and bestatic newpost filepath.

(New in v0.0.30) When you use these commands, slugs will now be automatically generated based on the filename. Of course, you can still customize the slug in the frontmatter as before.

You can always add any number of extra key: value pairs in the front-matter section as described below.



Front matter

Basics

All markdown files that Bestatic processes need to have a yaml style frontmatter, i.e., key: value pairs (note the whitespace after key) need to be enclosed with three dashes --- in top and bottom. The title and description keys are required to be present in all markdown files. Do not enclose any of these values with quotation marks or anything else.

Slug

The slug key tells bestatic where to generate the webpage. For example, if ./pages/sub/directory/example1.md file has slug: slug1 set, this page will be generated and served at the /sub/directory/slug1 location.

Again, if ./posts/another/directory/example2.md file has slug: slug2 set, this page will be generated and served at the /posts/another/directory/slug2 location. If no slug key is present, that is fine; In that case, the filename will be used to auto-generate the slug.

Enabling LaTeX formatting

Set the key: value katex: true, to make sure Bestatic themes will load katex.html.jinja in the page, and as a result all the LaTeX markups will be rendered correctly.

Date and time

The blog posts also have additional keys, such as date and tags. Currently, dates in formats like "March 12, 2024" are accepted by default. If you want to use a different date format, you can set the date_format key in your bestatic.yaml file. See config file section for details.

Tags

The tags should be listed with commas (such as: markdown, css, html). If you want to use multi-word tags, join them by hyphen, such as tags: tag1, this-one. (New in v0.0.30) Tags field can now be empty if you choose not to use any tags. Additionally, you can now define custom taxonomies beyond tags (such as categories, authors, etc.) in your bestatic.yaml file and use them in your post frontmatter.

Custom Taxonomies

(New in v0.0.30) Beyond the default "tags" taxonomy, you can now define custom taxonomies such as categories, authors, movies, or any other classification system. This powerful feature allows you to organize your content in multiple dimensions.

In your bestatic.yaml file, add:

1
2
3
4
taxonomies:
  - tags
  - categories
  - authors

In your post frontmatter, add values for each taxonomy:

1
2
3
4
5
6
7
8
---
title: "My Blog Post"
description: "A great article"
date: "December 22, 2025"
tags: python, web-development
categories: tutorials
authors: john-doe
---


You can additionally provide additional data for each taxonomy term (e.g., author biographies, category descriptions) by creating YAML files in the _includes/yamls/[taxonomy_name]/ directory. See below Custom Taxonomies section and config file section for more details.

Custom page template

You do not have to use the same page template throughout your site. You can potentially use a different design for each page!

While Bestatic by default uses page.html.jinja2 template to generate static pages and uses post.html.jinja2 to generate blog pages, these can easily be changed. Just use: template: custompage1.html.jinja2 in your page's front matter and make sure your theme's template directory has custompage1.html.jinja2 template. Then you are good to go!



Directory Structure

When you run bestatic quickstrt and add some static content, you will get a tree something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
├── _output
│   ├── about
│   │   └── index.html
│   ├── contact
│   │   └── index.html
│   ├── index.html
│   ├── index.json
│   ├── index.rss
│   ├── post
│   │   ├── tags
│   │   │   ├── amet
│   │   │   │   └── index.html
│   │   │   ├── dolor-ipsum
│   │   │   │   └── index.html
│   │   │   ├── first
│   │   │   │   └── index.html
│   │   │   ├── good
│   │   │   │   └── index.html
│   │   │   ├── great
│   │   │   │   └── index.html
│   │   │   └── sit
│   │   │       └── index.html
│   │   ├── the-first-article
│   │   │   └── index.html
│   │   └── the-second-article
│   │       └── index.html
│   ├── posts
│   │   └── index.html
│   ├── sitemap.xml
│   ├── static
│   │   ├── Images
│   │   │   ├── Bottom logo.png
│   │   │   ├── Logo_1.png
│   │   │   ├── Young1.png
│   │   │   └── favicon.ico
│   │   ├── css
│   │   │   ├── banerstyle.css
│   │   │   └── styles.css
│   │   └── js
│   │       ├── fuse-search.js
│   │       └── vanilla-back-to-top.min.js
│   └── static-content
│       └── Images
│           └── sampleimage.png
├── bestatic.yaml
├── pages
│   ├── about.md
│   └── contact.md
├── posts
│   ├── the-first-article.md
│   └── the-second-article.md
├── static-content
│   └── Images
│       └── sampleimage.png
└── themes
    └── Amazing
        ├── static
        │   ├── Images
        │   │   ├── Bottom logo.png
        │   │   ├── Logo_1.png
        │   │   ├── Young1.png
        │   │   └── favicon.ico
        │   ├── css
        │   │   ├── banerstyle.css
        │   │   └── styles.css
        │   └── js
        │       ├── fuse-search.js
        │       └── vanilla-back-to-top.min.js
        └── templates
            ├── 404.html.jinja2
            ├── home.html.jinja2
            ├── layout.html.jinja2
            ├── list.html.jinja2
            ├── page.html.jinja2
            ├── partials
            │   ├── footer.html.jinja2
            │   ├── head.html.jinja2
            │   ├── header.html.jinja2
            │   ├── katex.html.jinja2
            │   └── nav.html.jinja2
            ├── post.html.jinja2
            └── taglist.html.jinja2



Notes on the directories
  • In the above filetree, lines # 1-44 delineate the files and folders from the _output directory which Bestatic generates (this folder can be served from any web server). Lines # 45-82 list the files and folders that Bestatic used to generate the website.

  • In pre-existing files (lines # 45-82):

    • There is a bestatic.yaml file at line #45 (previously config.yaml; see details here).

    • There is a pages folder which contains markdown files for static/non-blog pages (line #46-48); note that, instead of this simple single directory as shown here, this can be nested and that organization will be maintained when Bestatic will generate the _output directory. Importantly, while writing in the _output directory, Bestatic will use the slug values (from frontmatter, if specified) to generate the pages. For example, if ./pages/sub/directory/example1.md file has slug: slug1 set, this page will be generated and served at the /sub/directory/slug1 location. If no slug key is present, that is fine; In that case, the filename will be used to auto-generate the slug.

    • There is a posts folder which contains markdown files for blog posts (line #49-51); note that, instead of this simple single directory as shown here, this can be nested and that organization will be maintained when Bestatic will generate the _output directory. Importantly, while writing in the _output directory, Bestatic will use the slug values (from frontmatter, if specified) to generate the blog pages. For example, if ./posts/another/directory/example2.md file has slug: slug2 set, this page will be generated and served at the /posts/another/directory/slug2 location. If no slug key is present, that is fine; In that case, the filename will be used to auto-generate the slug.

    • There is a static-content folder (line # 52-54). When Bestatic builds site, this directory is directly copied to _output in a nested fashion. For example, if ./static-content/Images/sampleimage.png file is present, it will be copied to _output/static-content/Images/sampleimage.png. Any sub-directories in this directory will be copied to _output/static-content in a nested fashion. You should put all your static files (images, videos, pdfs, documents, etc.) in this directory.

    • Lines # 55-82 provide details of Amazing theme files. Details about themes are documented in a separate page.

    • Notes:

      • A) While it is not present here, but you can include a root-import directory which will be directly copied to the root of the generated site folder (in a nested fashion). This maybe helpful if you have to include some record in a particular folder for verification purposes (such as the .well-known directory) or serving the robots.txt file.

      • B) You can also include a _includes directory. If you are using custom taxonomies, you can put your taxonomy data in this directory (in _includes/yamls/[taxonomy_name]/ sub-directory). See Custom Taxonomies section for details.

      • C) Inside the _includes directory, you can also include a datafiles directory. If you are using datafiles, you can put your datafiles in this directory (in _includes/datafiles/[datafile_name].csv or _includes/datafiles/[datafile_name].yaml). See Data Handling section for details.

      • D) Inside the _includes directory or markdown-data directory, you can also include markdown files that you want to include in one or more of your pages or posts. See Markdown Data section for details.

      • E) You can also include shortcodes that you want to use for custom markdown content. See Shortcodes section for details.

  • In Bestatic generated files (_output directory; line # 2-44):

    • All the pages under pages folder before (as described above) are processed and resulted a folder here in _output directory with slug values as folder name (line # 2-5). Bestatic creates an index.html file in each of these slug folders so that URLs become pretty and pages (or posts) do not have a .html extension to its links. As mentioned before, nested directory structure in _pages_ and _posts_ would have resulted nested directory structure here as well.

    • All the pages under posts folder before (as described above) are processed and resulted in a folder inside _output/post folder, with slug values as the folder name, and an index.html file inside each of those slug folders (line # 23-26).

    • All blog posts are listed in posts page (line # 27-28; see pagination section below for more relevant details).

    • All the tags in the blogs have been processed to generate tags pages (which lists posts with a particular tag) in _output/post/tags (line # 10-26).

    • The static-content folder has been copied in a nested fashion, as expected (line # 42-44).

    • All the static content of the themes/themename/static folder, such as CSS, JS, Images, etc., has been copied to _output/static folder (line # 30-41).

    • The index.html page in root of _output folder is the designated homepage (line #6). Also see details below for homepage customization.

    • Note that, Bestatic also automatically generated index.json (search index, see below) and sitemap.xml (the XML sitemap, see below).



Homepage options

Bestatic, by default, assumes that you will be using a separate homepage template home.html.jinja2 where you are going to make the homepage in plain HTML. Default "Amazing" theme come with such a home.html.jinja2 template. However, this is not required and it is easy to change homepage type.

Custom static homepage without special template

If you want to make a static page (such as your about page, contact page, etc.) your homepage, in that particular markdown file's front matter, put slug: index.html. This is a special slug and should be used for only one page in your entire website which you want to serve as your homepage.

Irrespective of location of that markdown file inside pages folder, this will be rendered as /index.html and will be served as homepage. Make sure homepage_type: default is set in the bestatic.yaml file.

List of blog posts as homepage

If you want to put your (first of the) blog list pages as the homepage, put homepage_type: list in the bestatic.yaml file and you are all set.

To learn how to control number of blog posts per list page see Paginating the Blog section below. To more about the config file, see config file section for details.



Commenting systems

For your blog posts, Disqus and Giscus comments are supported out-of-the-box. But, you can actually use anythings else - as long as they provide a Javascript snippet that you can put under your post.html.jinja2 template (or whatever name you give to your blog post template).

If you are using Giscus or Disqus and provide the id under configuration file, Bestatic will make them available to your theme under variable name "giscus" and "disqus" respectively. If you are using theme that we provide, mentioning the id in configuration file will be sufficient for enabling comments.

To provide a Giscus id to Bestatic:
  • Make a GitHub repo, make it public, and enable discussion in that repo.

  • Install giscus app on that repo.

  • Use your repo id (such as GitHubUsername/repo) as the comment_system_id for Bestatic. See "comments" section under config file notes for details.

To provide a Disqus id to Bestatic:
  • Sign Up for Disqus and go to https://disqus.com/admin/create/.

  • Fill out the details, copy the shortname (As Disqus mentions: "Your unique disqus URL will be: shortname.disqus.com"), and click on Create site.

  • Use the disqus shortname as the comment_system_id for Bestatic. See "comments" section under config file notes for details.



Paginating the blog

Bestatic gives you the option to control the number of blog posts per list page via the number_of_pages key in the bestatic.yaml file. For example, if you have 24 blog posts and want to have 6 blog posts listed per page, put number_of_pages: 4 in the bestatic.yaml file and Bestatic will generate /posts, /posts2, /posts3, and /posts4 pages automatically. If you have blog posts and do not specify this, Bestatic will list all posts in a single page (which will be served at /posts).

Note that, if you want to a word that is different from the default "posts", you can set the post_directory_singular and post_directory_plural keys in your bestatic.yaml file. See config file section for details.

(New in v0.0.30) In addition to previous and next post slugs, each post now has access to the titles of the previous and next posts. This makes it easier to create meaningful navigation links in your blog posts.

In your templates, you can now use:

  • {{ prev_title }} - Title of the previous post

  • {{ prev_slug }} - Slug of the previous post

  • {{ next_title }} - Title of the next post

  • {{ next_slug }} - Slug of the next post



Removing the blog

Bestatic, by default, assumes that you are creating a website and a blog. If your website does not have any blog/post/news like content (such as a standard academic profile website), that is perfectly fine. Just do not create any posts directory in your site's root directory. Also, if it exists, you may want to remove number_of_pages, rss_feed, and comments keys from your bestatic.yaml file.

To more about the config file, see config file section for details.



Search functionality has been implemented in Bestatic using Fuse.js library which enables client-side fuzzy (approximate string matching) search. No action is required from user-end: Whenever the user adds new content and build the website, it automatically generates a new search index at /index.json. The search UI in the themes has been included in the themes for convenience (filename: static/js/fuse-search-modal-ui.js or static/js/fuse-search.js). If you are comfortable with vanilla JavaScript, you can always use your own search UI by overriding the default one.

Of note, with proper tweaking, any other client-side search protocols such as lunr.js, or pagefind, or even Algolia can be implemented. And of course, there is always Google Programmable Search Engine that can be implemented in any site.



Sitemap

Sitemaps are automatically generated by Bestatic using Python's ElementTree XML API. Make sure that siteURL parameter is currently supplied in bestatic.yaml file so that Bestatic can list correct URLs. See config file section for details. The generated file is conveniently served at the /sitemap.xml. You can add that URL to your Google Search Console and other search engine tools to help them crawl your site.



Custom Taxonomies

(New in v0.0.30) Beyond the default "tags" taxonomy, you can now define custom taxonomies such as categories, authors, movies, or any other classification system. This powerful feature allows you to organize your content in multiple dimensions.

Defining Taxonomies

In your bestatic.yaml file, add:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
taxonomies:
  tags:
    taxonomy_template: taglist.html.jinja2
    taxonomy_directory: tags
  categories:
    taxonomy_template: category.html.jinja2
    taxonomy_directory: categories
  authors:
    taxonomy_template: author.html.jinja2
    taxonomy_directory: authors


Using Taxonomies in Content

In your post frontmatter, add values for each taxonomy:

1
2
3
4
5
6
7
8
---
title: My Blog Post
description: A great article about python and web development
date: December 22, 2025
tags: python, web-development
categories: tutorials
authors: john-doe, sam-smith
---



Bestatic will automatically generate list pages for each taxonomy term and users can filter posts by these taxonomies. For example, if you have a taxonomy called "authors" and you have a post with the author "John Doe" and "Sam Smith", Bestatic will automatically generate a list page for "John Doe" at /post/authors/john-doe and "Sam Smith" at /post/authors/sam-smith. Users can then filter posts by "John Doe" by visiting /post/authors/john-doe and "Sam Smith" by visiting /post/authors/sam-smith. Similarly, if you have a taxonomy called "categories" and you have a post with the category "Tutorials" and "Machine Learning", Bestatic will automatically generate a list page for "Tutorials" at /post/categories/tutorials and "Machine Learning" at /post/categories/machine-learning. Users can then filter posts by "Tutorials" by visiting /post/categories/tutorials and "Machine Learning" by visiting /post/categories/machine-learning.

Adding Taxonomy Metadata with YAML Files

You can provide additional data for each taxonomy term (e.g., author biographies, category descriptions) by creating YAML files in the _includes/yamls/[taxonomy_name]/ directory. This will enable you to access this data in your templates and process them to generate rich taxonomy pages with additional descriptions. See taxonomy data handling section for details.