Search by

foerdeliebe-sh / kirby-website-carbon

Kirby plugin that renders a Website Carbon rating badge, rated lazily server-side from measured page weight

Maintainers

Package info

github.com/HENNIROCKS/kirby-website-carbon

Type:kirby-plugin

pkg:composer/foerdeliebe-sh/kirby-website-carbon

Transparency log

Statistics

Installs: 20

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.0.2 2026-08-05 14:19 UTC

This package is auto-updated.

Last update: 2026-08-05 14:19:59 UTC


README

Kirby 5 PHP 8.2+ License: MIT

A Kirby CMS plugin that renders a self-contained Website Carbon rating badge for the current page.

The badge: a leaf icon, the rating letter, and the words "Website Carbon"

How it works

The rating depends on how many bytes a page actually transfers — something only a real browser can tell you. But api.websitecarbon.com blocks requests from cloud CI IP ranges (Cloudflare JS challenge, reproducible from GitHub Actions), while accepting them from regular hosting. So the two halves run in different places:

  1. Page weight measurementscripts/measure.mjs runs in CI via Playwright, on a schedule. It walks your sitemap.xml, measures the real transferred bytes per page and checks green hosting. No call to the rating API. The result is written to content/website-carbon.json.
  2. Rating lookupclasses/WebsiteCarbon.php runs live, server-side, on the actual page request. Results are cached (30 days by default), keyed by byte count, so a page is only re-rated when its measured weight changes.

If no measurement exists for a page, the snippet renders nothing at all. That is also what you see before the first CI run.

Requirements

  • Kirby 5
  • PHP 8.2+
  • Node 20+ in CI (for the measurement script)

Installation

Composer

composer require foerdeliebe-sh/kirby-website-carbon

Download

Download the repository and drop it into site/plugins/kirby-website-carbon.

Usage

The snippet

<?php snippet('website-carbon') ?>

Renders nothing if the current page has no measurement yet, so it is safe to place unconditionally — in a footer, for example. It can be used more than once per page; the stylesheet is only emitted on the first use.

The page method

For a custom badge, use the page method directly:

<?php if ($carbon = $page->websiteCarbon()): ?>
  <p>
    This page is rated <?= esc($carbon['rating']) ?> and cleaner than
    <?= esc($carbon['cleanerThan'] * 100) ?>% of pages tested,
    at <?= esc($carbon['gco2e']) ?> g CO₂ per view.
  </p>
<?php endif ?>

It returns null when there is no measurement or the API is unreachable, and otherwise an array:

Key Example Description
rating "A+" Rating from A+ to F
cleanerThan 0.94 Share of tested pages this one beats (01)
gco2e 0.06 Grams of CO₂ equivalent per page view

CI setup

Copy examples/website-carbon.yml into the consuming site as .github/workflows/website-carbon.yml and set SITE_URL plus the FTP secrets. The measurement itself is a single command:

node site/plugins/kirby-website-carbon/scripts/measure.mjs https://example.com content/website-carbon.json

Playwright is not vendored with the plugin; install it in the job with npm install --no-save playwright && npx playwright install --with-deps chromium.

The resulting JSON then has to reach the live site's content/ folder. The example workflow uploads that one file over FTPS with curl. Do not use a folder-syncing deploy action for this: those compare the local folder against a remote state file and delete whatever is missing locally, which can wipe content edited in the Panel.

If your site's content lives in Git and is deployed from there anyway, the simpler alternative is to commit the file back to the repository and let your regular deploy pick it up.

Options

Set in site/config/config.php:

return [
    'foerdeliebe-sh.kirby-website-carbon.cache.ttl' => 60 * 24 * 7,
];
Option Default Description
data.file content/website-carbon.json Path to the measurement file. Relative paths resolve from the site's index root.
cache.ttl 43200 (30 days) Minutes a fetched rating stays cached
cache.failureTtl 60 (1 hour) Minutes a failed lookup stays cached, so an unreachable API can't block every render
styles true Whether the snippet loads the plugin's own stylesheet
link.title null title attribute of the badge link; null uses the translation (see below)

A note on the link title

Kirby hardcodes the translation locale to en on single-language sites (AppTranslations.php), so the shipped German translation only applies to multi-language installations. On a single-language site in another language, set the title explicitly:

'foerdeliebe-sh.kirby-website-carbon.link.title' => 'Mehr über Website Carbon erfahren',

Or pass it per call: snippet('website-carbon', ['title' => '…']).

Styling

The snippet loads its own stylesheet (once per request) via a <link> tag pointing at the plugin's assets/website-carbon.css, so the badge looks right regardless of your CSS build pipeline. Classes: .website-carbon, .website-carbon__icon, .website-carbon__badge.

The badge inherits color and font-size from its surroundings. Everything else can be overridden with CSS custom properties from your own stylesheet:

Property Default
--website-carbon-gap 0.4em
--website-carbon-badge-background rgba(127, 127, 127, 0.15)
--website-carbon-badge-radius 0.2em
--website-carbon-badge-color inherit

To style the badge entirely yourself, set the styles option to false.

Troubleshooting

The badge doesn't show up. The snippet renders nothing when there is no measurement for the current page. Check that content/website-carbon.json exists on the server and contains a key for this page's URL. URLs are compared ignoring scheme, www., host case and trailing slash — anything beyond that (a different domain, a language prefix that isn't in the sitemap) will not match.

The rating is stale. Ratings are cached for 30 days, but keyed by measured byte count — a page that changed weight is re-rated on the next request. To force a refresh, delete site/cache/foerdeliebe-sh.kirby-website-carbon.

License

MIT © Hendrik Berends