Skip to content

PHP Code Interpolation

10/19/26: Mod. by D

PHP Test Code

The following code snippet is a simple test to verify whether PHP code interpolation is working correctly, in which case the current date and time will be displayed below the code snippet.

<?php
// Set the default timezone
date_default_timezone_set( 'America/Los_Angeles' );
echo 'Page last updated: ' . date( 'F d, Y, h:i:s a.', filemtime( __FILE__ ) );
echo '<br>Path: ' . __FILE__;
echo '<br>' . date( 'l, F j, Y, ' ) . date( 'h:i:s a' );
?>
Page last updated: October 24, 2026, 11:44:55 am.
Path: /opt/zensical/zensical-project/site/php-test.html
Sunday, November 15, 2026, 10:07:39 am

Is the current date and time shown immediately above? Reload to change it.

PHP Configuration

Loaded Configuration File: /etc/php-zts/php.ini

Setting up PHP interpolation

Our Zensical subdomains are served by FrankenPHP, which adds fast PHP code interpolation to its underlying Caddy web server. Zensical runs its own web server on a separate localhost port but it is not suitable for production service. As a backend server it can be safely reverse-proxied to the internet via FrankenPHP:

Caddyfile
### Begin zen-proxy.langley.stream configuration ###
zen-proxy.langley.stream {
        # Reverse proxy the Zensical server running on localhost port 8006:
        reverse_proxy localhost:8006
}
### End zen-proxy.langley.stream configuration ###

Unfortunately FrankenPHP offers no easy way to execute any PHP code flowing from a reverse-proxied backend server, it needs to directly access the static HTML files built by Zensical, located in the project’s site directory.

But what if we can’t serve files directly from the location of our Zensical installation, for instance if it’s running in root’s home directory? We can copy Zensical’s static site directory into the standard web root at /var/www or /opt/<project-name> (Debian-based Linux):

bash
cp -ru /root/docker/zensical/site/. /var/www/zensical/site-copy

Note

If the destination folder already exists and you want to copy the contents of the source directory directly into it without nesting folders, append /. to the source path.

When FrankenPHP is configured to serve static Zensical files directly, without reverse proxy, it can interpolate embedded PHP code, provided that it has been configured to treat files with the .html extension as though they were .php files:

Caddyfile
### Begin zen-php.langley.stream configuration ###
zen-php.langley.stream {
    root /opt/zensical/zensical-project/site
    @phpFiles {
        path *.html *.php
    }
    php @phpFiles
    encode
    php_server
}
### End zen-php.langley.stream configuration ###

Adjust directory structure

Normally Zensical builds navigation using directory-based links, without specifying index.html files. The use_directory_urls setting in zensical.tomlcontrols the directory structure of your documentation site, and thereby the URL format used for linking to pages. Turn it off to generate file-based URLs, facilitate offline usage, and enable interpolation of PHP code embedded in .html files.

zensical.toml
[project]
use_directory_urls = false

Note that this is automatically set to false when building for offline usage, so your documentation can be browsed from a local filesystem without a web server. The default value is true.

Add the page modification date in the footer’s copyright notice:

zensical.toml - NOTE: Use triple quotes to allow embedded backslash line breaks.
[project]
copyright = """Copyright &copy; 2026 Dennis C. Langley <br> \
<?php \
date_default_timezone_set( 'America/Los_Angeles' ); \
echo 'Mod. ' . date( 'm/d/Y, h:i:s a.', filemtime( __FILE__ ) ); \
?>"""

Auto-load PHP scripts

First create a new directory in our project’s docs directory named phpscripts. It will hold all our project’s php scripts.

A single common php code file named common.php, will be included at the head of every page. Per-page php code files named <page-name>.php will be included on each matching page. For example, if a page markdown file is named front.md, the php file docs/phpscripts/front.php will autoload into the header of the corresponding html page, front.html, after the front.md page is built by Zensical and then served by FrankenPHP.

Here’s where the magic happens. By extending Zensical’s “base.html” template, we can insert a php code snippet into the extrahead block of each page which will include the matching php files if they exist:

overrides/main.html
{% extends "base.html" %}

{% block extrahead %}
    <!-- This is my custom extrahead block. -->
    <?php
    $file = $_SERVER['DOCUMENT_ROOT'] . '/phpscripts/common.php';
    if ( file_exists( $file ) ) include $file;

    $file = pathinfo( __FILE__, PATHINFO_FILENAME ) . '.php';
    if ( file_exists( $file ) ) include $file;
    ?>
{% endblock %}