Feature

Tags & hooks

Register your own HTML tags, Markdown shortcodes and render hooks from one includes file.

prepros.includes: [_lib/functions.php] runs one file before any page renders. This site uses it for all three extension points.

A custom tag


                        register_tag('swatches', function ($tag, $attrs, $body) {
                            $chips = '';
                            foreach (img_palette($attrs['asset'], (int) $attrs['count']) as $hex) {
                                $chips .= "<li style=\"--chip:$hex\"><span></span><code>$hex</code></li>";
                            }
                            return "<ul class=\"swatches\">$chips</ul>";
                        });
                    

Used as <swatches asset="cover.jpg" count="5">, it renders:

  • #575563
  • #77889c
  • #777584
  • #272934
  • #331714

A tag from a plugin

Tags don't have to be hand-rolled — @kirigami/plugin-extlink registers <extlink src="…"> the exact same way, via prepros:php. It scrapes the target page for its title, description, preview image and site name, and caches all of it to disk (_data/extlink/, assets/images/extlink/) so a later build never re-crawls a URL it has already resolved:

php-kirigami/kirigami: Core package Core package. Contribute to php-kirigami/kirigami development by creating an account on GitHub. GitHub

A tag resolved in the browser, not at build time

@kirigami/plugin-embed registers <youtube id="…"> / <vimeo id="…"> the same way again — but this one does nothing at build time. It ships a script (via esbuild:after) that swaps the tag for a placeholder on load, fetches the video's oEmbed data (thumbnail, title, real aspect-ratio) — cached in localStorage, so a repeat visit costs nothing — and wires a play button that loads the real player only once clicked:

Same tag mechanism, two different strategies: <extlink> resolves once, at build time, and commits the result; <youtube>/<vimeo> resolve every time, in the visitor's own browser. Neither is "more correct" — it depends on whether the data can change after the build and whether a network call at build time is acceptable.

A Markdown shortcode


                                md_register_plugin('badge', fn($args, $body) => sprintf(
                                    '<span class="badge badge--%s">%s</span>',
                                    $args[0], str_htmlesc(implode(' ', array_slice($args, 1)))
                                ));
                            

A bare call renders inline — Live — anywhere Markdown is parsed.

A render hook


                                $token = '{{' . 'build-date}}';
                                register_hook('post_render', fn($html) =>
                                    str_replace($token, date('F j, Y'), $html));
                            

This hook rewrites a placeholder token on the assembled HTML — look at the "last updated …" line at the bottom of every page.