Switch to Zola 0.23.3
Zola v0.23 replaced its template engine, Tera, with a new major version (Tera v2). The Zola project itself calls it
probably the most breaking version of Zola that will happen
and Linkita's templates had to be rewritten to follow it. This page walks you through moving a Linkita site from Zola v0.22.1 to Zola v0.23.3.
Repository move
Linkita was simultaneously moved from Codeberg to GitHub. If you are still using the Codeberg repository, you need to switch to the GitHub repository first. For submodule users, here are the instructions:
git submodule init
git config -f .gitmodules submodule."themes/linkita".url https://github.com/salif/linkita.git
git config -f .gitmodules submodule."themes/linkita".branch tera1
git submodule sync
git submodule update
git add .gitmodulesWho needs this guide
This guide is for you if your site currently uses Linkita on the tera1
branch (or on linkita/v4) with Zola v0.22.1 or older.
If you don't want to upgrade Zola yet, you don't have to do anything –
the tera1 branch will keep working with old Zola versions and isn't
going away.
Step 1: Upgrade Zola to v0.23.3
Install Zola v0.23.3 or newer. Check your installed version with:
zola --version
Zola v0.23 is a big jump. Skim the Zola v0.23.0 changelog entry if your site has custom templates beyond Linkita's own – the rest of this guide only covers what changed on Linkita's side.
Step 2: Switch to the main branch
Linkita's main branch now targets Zola v0.23.3+. The tera1 branch
stays on the old template engine for Zola v0.22.1 and older.
If you installed Linkita as a git submodule:
git submodule set-branch --branch main themes/linkita
git submodule update --remote themes/linkita
If you cloned it directly instead:
cd themes/linkita
git checkout main
git pullStep 3: Update your zola.toml / config.toml
Go through each of the following. None of these are enforced by Zola – leftover old keys won't break your build, but they'll silently stop doing anything, so it's worth cleaning them up.
Menu and social links: $BASE_URL → @base
$BASE_URL in extra.menus, profile social URLs, and
extra.footer.license_url is now written @base:
# Before
[extra.menus]
menu_name = [
{ url = "$BASE_URL/blog/", name = "Archive" },
]
# After
[extra.menus]
menu_name = [
{ url = "@base/blog/", name = "Archive" },
]
The same rename applies to a profile's social entries and to
extra.footer.license_url. You can also use
Zola's internal links
(@/...) instead of @base if you prefer.
There's also a new @lang prefix for menu/social URLs that resolves a
path within a specific language, if you need that.
Note this does not apply to extra.footer.copyright – that string
still uses $BASE_URL, $YEAR, and $LICENSE_URL as before:
[extra.footer]
copyright = "© $YEAR Your Name | [CC BY-SA 4.0]($LICENSE_URL)"Profiles: Open Graph settings simplified
The [extra.profiles.<user>.open_graph] sub-table is gone. image and
image_alt moved up a level and were renamed, fediverse_creator moved
up a level too, and the Facebook-specific fields
(first_name, last_name, username, gender, fb_app_id,
fb_admins) and the per-language Open Graph translation section were
removed entirely:
# Before
[extra.profiles.your_username.open_graph]
image = "cover.png"
image_alt = "A description"
fediverse_creator = { handle = "me", domain = "mastodon.social" }
# After
[extra.profiles.your_username]
# ...avatar_url, name, bio, social, etc. as before, plus:
og_image = "cover.png"
og_image_alt = "A description"
fediverse_creator = { handle = "me", domain = "mastodon.social" }
If you relied on first_name / last_name / gender / fb_app_id /
fb_admins, or on a per-language open_graph.languages.<lang>.image_alt
override, there's no direct replacement – those Open Graph fields are no
longer emitted by the theme.
Language options: locale removed, date formatting changed
Zola's date filter no longer takes a locale argument, so the
extra.languages.<lang>.locale variable (e.g. locale = "fr_FR") has
been removed. Date formatting moved from the chrono crate to jiff,
so date_format strings are now interpreted using
jiff's strftime reference
rather than chrono's.
# Before
[extra.languages.fr]
locale = "fr_FR"
date_format = "%x"
# After
[extra.languages.fr]
date_format = "%F"
num_format = "fr"
The practical effect: if you were relying on locale to print
translated month/weekday names (via tokens like %B or %A), that no
longer happens automatically. Check your
date_format tokens against the jiff docs – you may want to switch to
a numeric-only format, or accept that month/day names will render in
whatever jiff produces by default for that token. num_format (for
number formatting, unrelated to dates) is unchanged and still per
language.
disable_javascript removed
The extra.disable_javascript config variable, which let you suppress
the theme's JS and re-implement it yourself via injects, has been
removed.
Demo/documentation links
If you link to Linkita's own documentation anywhere, note the shortcode
demo moved from /shortcodes/ to /components/ (e.g. the projects
feature is now documented at
https://salif.github.io/linkita/components/#projects).
The cover image docs were clarified
to note extra.cover.image accepts either a page asset filename or a
get_url-compatible path – this already worked before, just wasn't
spelled out.
Step 4: Update your content – shortcodes are now components
This is the change most likely to affect your existing posts.
Zola v0.23 removed shortcodes completely. There is no more
templates/shortcodes/ directory, and the old function-call style of
invoking a shortcode in Markdown content (with or without a body) is
gone – both forms now fail the build with an "unknown function" /
"unknown tag" error. Instead, your .md files are templated with Tera
directly, the same as .html templates, and you call Linkita's
built-in components using Tera v2's new call syntax.
I built and tested each of the following against the real Linkita templates on Zola v0.23.3 to confirm the exact syntax.
A component with a body is called like this – note the closing percent-brace and opening percent-brace wrap the angle-bracket tags, not double curly braces:
{% <component_name arg="value"> %}
body content
{% </component_name> %}
A component with no body (self-closing) uses double curly braces instead:
{{<component_name arg="value" />}}Admonition
# Before
{% admonition(type="note", title="A note") %}
This is a **note** body.
{% end %}
# After
{% <admonition type="note" title="A note"> %}
This is a **note** body.
{% </admonition> %}Gallery
Gallery now needs page and config passed in explicitly (Tera v2
components don't get implicit access to the page/config like old
shortcodes did – you pass them by name, and since the variable names
already match the parameter names, you can just write page config):
# Before
{{ gallery() }}
# After
{{<gallery page config alt="" />}}Mermaid
# Before
{% mermaid() %}
```mermaid
graph TD;
A-->B;
```
{% end %}
# After
{% <mermaid> -%}
```mermaid
graph TD;
A-->B;
```
{%- </mermaid> %}
Use the whitespace-trim dashes shown above (right after the opening
percent-brace and right before the closing one) – without them, the
leading blank line before the fenced block isn't
stripped and the diagram renders with the ```mermaid fence markers
still visible instead of being cleaned up by the component.
Projects
Projects also now needs page and config passed explicitly:
# Before
{{ projects(path="data.toml", format="toml") }}
# After
{{<projects path="data.toml" format="toml" page config />}}If you write about Tera/Linkita syntax in your own posts
Since .md files are now templated by Tera before Markdown is parsed,
literal Tera tags inside a fenced code block – like the examples
above – will actually get executed rather than displayed, even inside
triple-backtick fences. Wrap any such example in a raw block, the same
way this guide's own code samples are wrapped, to show it literally
instead.
Step 5: Custom language files
If you added a custom static/i18n/<lang>.json file,
synchronize your changes with the theme's default language file.
Step 6 (advanced): Custom template overrides or injects
Skip this section unless you've overridden one of Linkita's own templates, or you call its internal macros directly from your own templates or injects.
Tera v1 macros are gone in Tera v2, replaced by components, which
are called globally by name – no more {% import %}
or self:: namespacing.
Other Tera v2 syntax changes visible throughout the templates, in case your own overrides use them:
trim_start_matches(pat=...)/trim_end_matches(pat=...)are nowtrim_start(pat=...)/trim_end(pat=...).linebreaksbris nownewlines_to_br.default(value=x)needsboolean=trueadded (default(value=x, boolean=true)) to treat empty strings/falseas "use the default" – without it, only a truly undefined/null value triggers the default.- Optional chaining (
?./?[...]) is available and used throughout for safely reading config values that might not be set. - Global context (
page,config,lang, etc.) is no longer implicitly available inside a component the way it was inside a macro – components declare and receive it explicitly, which is why you'll seepage: map,config: mapparameters throughout the new templates. - The custom
templates/sitemap.xmlandtemplates/split_sitemap_index.xmltemplates were removed from the theme. If you had overridden either of these yourself, check whether you still need to.
For the full picture of what changed in Tera itself, see the Tera v1 → v2 migration guide.
Step 7: Rebuild and check
zola build
Then review, especially:
- Menu items and social icons resolve to the right URLs (the
@basechange). - Your profile's Open Graph image/description and Fediverse
verification link tag are present in the page
<head>. - Non-English date formatting still looks right – this is the one most likely to have silently changed (no more locale-translated month/day names).
- Any admonitions, galleries, Mermaid diagrams, or a projects page render correctly.
Getting help
If something doesn't match what's described here, check the
README and
CHANGELOG on
the main branch, or start a discussion.