How to Build a CARL Theme

A CARL theme is a zip archive renamed with a .carltheme extension. It contains three-page template files, a set of site include files, and a theme.json manifest. Build those components, run the package script, and you have a distributable theme file anyone can install on their CARL site in one step.

How to Build a CARL Theme

The Package Structure

A valid .carltheme package must follow this directory structure inside the zip:

mytheme/
  theme.json
  tpl/
    blog.tpl
    full-width.tpl
    category.tpl
  includes/
    css_include.txt
    nav_include.txt
    footer_include.txt
    footer_scripts.txt
    site_header.txt
    header_scripts.txt
    hub_render.txt
    recent_posts.txt
    sidebar_include.txt
    special_cta_include.txt
  assets/              (optional — images, fonts)

The top-level folder name doesn't matter. CARL locates theme.json automatically wherever it appears inside the zip. The tpl/ folder deploys to admin/tpl/ on the server. The includes/ folder deploys to site_includes/. The optional assets/ folder deploys to a web-accessible path at /assets/themes/{slug}/.

The theme.json Manifest

Every theme package requires a theme.json file that tells the installer what to do with the package contents:

{
  "name":          "My Theme",
  "slug":          "my-theme",
  "version":       "1.0",
  "description":   "A short description shown on the install confirmation screen.",
  "author":        "Your Name",
  "requires_carl": "1.0",
  "templates": {
    "blog":        "tpl/blog.tpl",
    "full-width":  "tpl/full-width.tpl",
    "category":    "tpl/category.tpl"
  },
  "includes": [
    "css_include.txt",
    "nav_include.txt",
    "footer_include.txt",
    "footer_scripts.txt",
    "site_header.txt",
    "header_scripts.txt",
    "hub_render.txt",
    "recent_posts.txt",
    "sidebar_include.txt",
    "special_cta_include.txt"
  ]
}

The slug field must be lowercase letters, numbers, and hyphens only. It's used to construct the template slugs stored in the database (for example, my-theme-blog) and the assets path on the server. The three template role names — blog, full-width, and category — are fixed. CARL uses them to remap existing pages to the new theme's layouts during install.

Building the Template Files

Each template file is a complete HTML document with CARL tokens in place of dynamic content. The four tokens are {{TITLE}} for the page title, {{META}} for the meta tag block, {{HEAD_EXTRA}} for any additional head content, and {{BODY}} for the full page content. Never hardcode an H1 heading directly in a template file. CARL generates the H1 as part of {{BODY}} and writes it into the file at generation time.

Every template must include lang="en" on the html element for accessibility compliance. Your viewport meta tag and any preload directives belong in header_scripts.txt rather than hardcoded in the template, so they can be updated without rebuilding the template files. The feedback widget, if you want it on category pages, is included via admin/modules/feedback/display.php.

The Include Files

All ten include files are required in the package. css_include.txt contains your entire stylesheet as an inline style block — putting CSS here rather than as an external file eliminates asset path problems when deploying the theme and removes any render-blocking external CSS request. nav_include.txt contains your site navigation HTML. footer_include.txt contains your footer. hub_render.txt contains the PHP that queries and outputs the article card grid on category pages. recent_posts.txt contains the PHP that powers the sidebar related posts widget. The remaining files handle scripts, the site header, the sidebar wrapper, and the mid-article CTA slot.

CSS and PageSpeed

Two CSS rules are essential for a zero Cumulative Layout Shift score. Content images need aspect-ratio and object-fit: cover declared so the browser reserves their space before they download. The site header banner image needs the same treatment. Without these, images cause layout jumps as they load and PageSpeed will penalize the score. Do not add transition: margin-top to the body rule — it causes measurable CLS on desktop.

For the H1 selector, use a descendant selector (.article-main h1) rather than a direct child selector. The H1 sits inside a content column div inside the article element, so a direct child selector won't reach it.

Packaging the Theme

Once all files are ready, create a folder named after your theme slug, place theme.json at the root, and add your tpl/ and includes/ subfolders with the correct files in each. Zip the folder, then rename the resulting zip file with the .carltheme extension. On Windows, a PowerShell script that copies and renames files into the correct structure and zips them in one command makes rebuilding fast and consistent whenever you update any source file.

Testing Before Distribution

Test every theme on a local or staging CARL install before distributing it. Verify the blog, full-width, and category templates all render correctly. Check the hamburger menu opens and closes on mobile. Run PageSpeed Insights on all three templates and confirm CLS is 0. Verify theme.json parses correctly, all ten include files are present, all three template files are in tpl/, and the install completes without errors on a clean test site with pages remapping correctly after install.

What do you think?

0 Responses

Free Membership

It's free. Log in instantly.

We won't send you spam. Unsubscribe at any time.

Related Posts