BLOGC-TEMPLATE(7)
π blogc-template(7) β bestie, it's the blogc Manual, and we're talking templates π
okay so welcome to blogc-template, aka the whole entire guide to blogc's template format. this is the blogc Manual, section 7, and we're gonna get you fluent. grab a snack. π
β¨ NAME β¨
blogc-template β blogc's template format. that's it, that's the name, and honestly? iconic. π
πΈ DESCRIPTION πΈ
So. Template files are the base that blogc(1) uses to build your output files. Think of them as the little blueprint your whole website gets poured into. ποΈ
Inside these files you can put variables, blocks, conditionals and iterators, and every single one of them directly affects what ends up in your output files.
The syntax of template files is defined to be simple, without affecting the content output. It's somewhat inspired by Jinja2 syntax β iykyk. π
Templates must be valid UTF-8. no exceptions, no vibes-based encoding. π
This manual describes the basic syntax and functionalities of template files. let's gooo.
π§± TEMPLATE BLOCKS π§±
Template blocks are how you delimit content. Whatever's inside a block gets included in the output file β or doesn't β depending on whether the parameters passed to blogc(1) match what that block needs. it's giving β¨conditional realnessβ¨.
Blocks can be defined more than once, but they can't be nested. nope. not happening. π
The available blocks are: entry, listing, listing_empty, listing_entry and listing_once. five little icons, each with a job. π«Ά
π entry block
The content of an entry block gets included in the output file when blogc(1) is called without the -l option, and with only one source file. It's used to render a single entry of your blog/website. All the variables defined in the source file are available inside this block (see blogc-source(7)), and they override global variables (see blogc(1)).
This is how an entry block is defined:
{% block entry %}
This content will only be included when rendering a single entry.
{% endblock %}
π listing block
The content of a listing block gets included in the output file when blogc(1) is called with the -l option, and with zero or more source files. It's used to create a listing of entries, and its content will be included once for each given source file β in the order that the source files were provided to blogc(1). All the variables defined in the source files are available inside this block (see blogc-source(7)), and they override global variables (see blogc(1)). The variables get provided by each file, as blogc(1) iterates over them. π
This is how a listing block is defined:
{% block listing %}
This content will be only included when rendering an entry listing, and
will be included once for each entry.
{% endblock %}
π¦ listing_empty block
This block is similar to the listing block, but its content is included only when there are no entries to be listed β either because no source files were provided, or because there are no entries remaining after filtering (see blogc-pagination(7)). it's the "nothing to see here, bestie" block. π
This is how a listing_empty block is defined:
{% block listing_empty %}
No entries available.
{% endblock %}
π listing_entry block
This block is identical to the entry block, but its content gets included in the output file only when blogc(1) is called with the -l and -e SOURCE options. The variables available in the block are provided by the source file given with the -e SOURCE option.
This is how a listing_entry block is defined:
{% block listing_entry %}
This content will only be included when rendering a listing, but with
content provided by a single entry.
{% endblock %}
When multiple listing_entry blocks are defined, blogc(1) should be called with multiple -e SOURCE options. If a listing_entry block doesn't have a corresponding -e SOURCE option, or if its value is an empty string, the content of the listing_entry block is not included. sad but true. π
listing_entry blocks inside an iterator are evaluated as multiple blocks and also require multiple -e SOURCE options. blogc(1) won't use the same source for every iteration. no recycling here. β»οΈπ«
π listing_once block
The content of a listing_once block gets included in the output file when blogc(1) is called with the -l option, and with zero or more source files. It's like a listing block, but it's only called once, and it does not have access to the local variables defined in the source files. It's useful for adding something before an entry listing. π
The content of a listing_once block is included even if no source file is provided.
This is how a listing_once block is defined:
{% block listing_once %}
This content will be only included when rendering an entry listing, but
will be included only once.
{% endblock %}
And here's a 'real world' usage example of a listing_once block, supposing that the TITLE variable is defined:
{% block listing_once %}
<ul>
{% endblock %}
{% block listing %}
<li>{{ TITLE }}</li>
{% endblock %}
{% block listing_once %}
</ul>
{% endblock %}
see how it opens the list, then the listing fills it in, then it closes it? chef's kiss. π
π§ TEMPLATE VARIABLES π§
Template variables are how you get content into templates β from the blogc(1) command-line and from source files. π
This is how a variable is defined in a template:
{{ VARIABLE_NAME }}
The value of a variable depends on its scope. Global variables provided to blogc(1) are available everywhere in the templates. Local variables provided in the source files are available only inside entry and listing blocks, and they will override global variables.
If a variable isn't defined, it gets replaced by an empty string. blogc(1) won't raise any error in this case. no drama, no crash. π«Ά
Variables are always strings β even if the value of the variable is a number, blogc(1) handles it as a string. periodt.
β Variable formatters β
blogc(1) can apply a formatter to a variable, depending on how it's called in the template. If you append _FORMATTED to the end of the variable name, a formatter gets applied β if one's available for that variable name:
- Date formatter: if the variable name starts with
DATE_, it gets formatted with astrftime(3)format, provided by theDATE_FORMATvariable. TheDATE_FORMATTED"meta-variable" will return the formatted version of theDATEvariable. IfDATE_FORMATisn't provided, the original value will be returned.
An existing variable is not overridden by a formatter. That means if a FOO_FORMATTED variable exists, it won't be handled as a formatter "meta-variable", and the FOO_FORMATTED variable's value gets returned normally. it's real, it's not a formatter, leave it alone. π
πΈ Truncated variables πΈ
blogc(1) can truncate the value of a variable to a maximum length, if it's called with the maximum length appended to the end of the variable, like: FOO_5 will return the 5 first characters of the FOO variable, if it's bigger than 5 characters. βοΈ
This is applicable to the "meta-variables", like DATE_FORMATTED. It can be truncated like: DATE_FORMATTED_5, which will return the 5 first characters of the DATE_FORMATTED "meta-variable".
An existing variable is not overridden by the truncate syntax. That means if a FOO_5 variable exists, it won't be handled as a truncate "meta-variable", and the FOO_5 variable's value gets returned normally.
π₯ PREDEFINED TEMPLATE VARIABLES π₯
blogc(1) provides some template variables you can use to display build metadata on your website. π
If some of the variables aren't available in the system running the build, they won't be defined. It is recommended to rely on template conditionals β mainly ifdef and ifndef β when using these variables. be safe bestie!! π«Ά
π§± Static variables
These variables are always available, and are set during the blogc(1) binary compilation.
BLOGC_VERSIONβ The version ofblogc(1)used to build. e.g.:blogc 0.14.1.
π Resource usage variables
It is not possible to measure the resource usage of blogc(1) until the end of the execution, because the rendering of these variables itself is using resources, and the evaluation of the used resources was already done. To get better values, it is recommended to use these variables only in the website footer. put them at the bottom, okay? π«Ά
BLOGC_RUSAGE_CPU_TIMEβ The CPU time used to build, up to the point where this variable was used for the first time in the template (value is cached). e.g.:12.345ms.BLOGC_RUSAGE_MEMORYβ The memory used to build, up to the point where this variable was used for the first time in the template (value is cached). e.g.:1.234MB.
π¦ System information variables
BLOGC_SYSINFO_HOSTNAMEβ The hostname of the machine where the build happened (short hostname only, not FQDN).BLOGC_SYSINFO_USERNAMEβ The username of the user that executed the build.BLOGC_SYSINFO_DATETIMEβ The GMT datetime of the build. e.g.2019-02-10 22:00:00.BLOGC_SYSINFO_INSIDE_DOCKERβ If built inside a docker container, this variable will be defined, with value1.
π TEMPLATE CONDITIONALS π
Template conditionals are how you include content in the output β or don't β based on the value and existence of variables in the current scope. vibe check, but for variables.
The implementation of conditionals is simple, and each one just evaluates the value of a single variable.
The available conditionals are: ifdef, ifndef and if. else statements are supported. π
π ifdef conditional
The content of an ifdef conditional gets included in the output file when the given variable is defined in the current scope.
This is how an ifdef conditional is defined in a template:
{% ifdef TITLE %}
This is title: {{ TITLE }}
{% else %}
Untitled entry
{% endif %}
In this case, if the TITLE variable is defined, the content after the statement is included. Otherwise, the content after the else statement is included. easy peasy. β¨
π ifndef conditional
The content of an ifndef conditional gets included in the output file when the given variable is not defined in the current scope.
This is how an ifndef conditional is defined in a template:
{% ifndef TITLE %}
Untitled entry
{% endif %}
In this case, if the TITLE variable isn't defined, the content is included. else statements are supported here, even if it doesn't make much sense to be used this way. π
β if conditional
The content of an if conditional gets included in the output file when the comparison between the given variable and the given static string or variable evaluates to true in the current scope. The left operand of the comparison must be a variable.
The available operators are: ==, !=, <, >, <= and >=. The comparisons are strcmp(3)-like.
This is how an if conditional is defined in a template:
{% if TITLE == "My Title" %}
Special description of "My Title"
{% else %}
Title is {{ TITLE }}
{% endif %}
Or:
{% if TITLE == DEFAULT_TITLE %}
Title is the default title
{% endif %}
okay bestie that's part 1, and there is more coming β do not go anywhere. π
π TEMPLATE ITERATORS
okay bestie, so iterators are the ones that go loop loop loop β¨ They take a variable, treat it as a list, and go over every single thing in it.
The available conditionals are: foreach.
π foreach iterator
Here's the tea: the content of a foreach iterator gets dropped into the output file whenever the target variable is defined β and then it gets repeated for each item in the list that got parsed out of that variable's value.
The variable value has to be formatted as a space-separated list of items. No quotes, no cap β literally not supported, because this thing is meant to work with identifiers (think slugs, not arbitrary strings). So don't try it.
This is how a variable value would be formatted:
item1 item2 item3
Wanna know more about defining variables? Go peek at blogc(1) and blogc-source(7). π«Ά
This is how a foreach iterator is defined in a template:
{% foreach TAGS %}
<a href="/tag/{{ FOREACH_ITEM }}/">{{ FOREACH_ITEM }}</a>
{% endforeach %}
Where TAGS is the variable holding the space-separated list of items, and FOREACH_ITEM is the variable defined by blogc(1) that stores the item for whatever iteration we're on. π
So if the value of the TAGS variable is "item1 item2 item3", this template gets rendered 3 times β one for each item. iconic.
It is possible to map the items to arbitrary strings by defining other variables following a predefined naming schema, like:
TAGS__ITEM1
Where TAGS is the variable defined in the foreach iterator, and ITEM1 is the current iteration item β which is the value of FOREACH_ITEM for the current iteration, converted to upper case and with special characters converted to _.
This is how a foreach iterator using arbitrary string mapping is defined in a template:
{% foreach TAGS %}
<a href="/tag/{{ FOREACH_ITEM }}/">{{ FOREACH_VALUE }}</a>
{% endforeach %}
FOREACH_VALUE is the variable defined by blogc(1) that stores the arbitrary string mapped to the current iteration item. And yes bestie, you can check this variable using ifdef conditionals (and similar) like you'd normally do:
{% foreach TAGS %}
{% ifdef FOREACH_VALUE %}
<a href="/tag/{{ FOREACH_ITEM }}/">{{ FOREACH_VALUE }}</a>
{% endif %}
{% endforeach %}
The FOREACH_ITEM and FOREACH_VALUE variables can be truncated, like:
{% foreach TAGS %}
<a href="/tag/{{ FOREACH_ITEM_5 }}/">{{ FOREACH_VALUE_5 }}</a>
{% endforeach %}
π«§ WHITESPACE CONTROL
okay so this one is giving aesthetic control, because you get to decide how whitespace behaves before and after statements delimited with the {% and %} sequences, respectively.
And when we say whitespace we mean the whole squad: space, form-feed (\f), newline (\n), carriage return (\r), horizontal tab (\t), and vertical tab (\v). π
- Adding a minus sign (
-) after a{%sequence ({%-) will remove whitespaces before the sequence and after the last non-whitespace character before the sequence. - Adding a minus sign (
-) before a%}sequence (-%}) will remove whitespaces after the sequence and before the first non-whitespace character after the sequence.
π BUGS
The template content is handled by handwritten parsers, and even though they're well tested, they may still be subject to parsing bugs. Not me being fragile π β please report any issues to: https://github.com/blogc/blogc
π AUTHOR
Rafael G. Martins <rafael@rafaelmartins.eng.br>
π SEE ALSO
blogc(1), blogc-source(7), strcmp(3), strftime(3)
That's a wrap on part 2, bestie! π This lil masterpiece came from Rafael G. Martins, dated January 2025, and it lives as BLOGC-TEMPLATE(7) in the manual pages. slay, read responsibly, and go build something cute. πβ¨
π¦ where this page comes from
- fedora 43: blogc 0.20.1^20240602.b1ae9c9-1.fc42 Β· BSD-3-Clause AND MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms