, _ , _ , _
/|/ \| _ |\ (| | |_//|/ \ /|/ \|\ _, o
|__/|/\ |/ |/ | | | |__/ |__/|/ | | / | | /|/|
| | |/|_/|_/ \/ \/ | | |_/ \/|_/\/|/|/ | |_/
(|
WordPress plugin skeleton for Phel, a functional programming language inspired by Clojure and Janet.
Plugin sets up a simple admin widget querying the database and rendering HTML using Phel HTML library in way familiar from Clojure hiccup.
Requires PHP 8.4+ and Composer.
- Clone this repository into plugins directory of an existing WordPress installation e.g.
wp-content/plugins/phel-wp-plugin. - Install Composer dependencies
cd phel-wp-plugin && composer install. - Activate plugin on plugin management page or with WP-CLI
wp plugin activate phel-wp-plugin.
The widget should be visible on admin dashboard. Try editing src/main.phel and see changes after page refresh.
This repository includes a devenv development environment using Caddy, PHP-FPM, and MariaDB.
Start the environment from the repository root:
devenv up -dOpen WordPress at http://localhost:8080/. Provisioning automatically downloads WordPress, installs the plugin dependencies, activates phel-wp-plugin, creates the demo post, and ensures the default administrator exists.
Development credentials:
Username: admin
Password: password
The database is available on 127.0.0.1:3307 with database/user/password wordpress.
Useful commands:
# Enter the development shell
devenv shell
# Run provisioning again (safe to repeat)
devenv tasks run wordpress:setup
# Check or update WordPress options
devenv shell -- wp option get home --path=wordpress
devenv shell -- wp plugin status phel-wp-plugin --path=wordpress
# Stop and restart services
devenv processes down
devenv up -dPHP-FPM logs are stored at:
.devenv/state/php-fpm/php-fpm.log
Follow service logs with:
devenv processes logs caddy
devenv processes logs phpfpm-web
devenv processes logs mysqlWordPress debug logging is enabled by default with errors hidden from the browser. The development configuration uses:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);WordPress writes PHP errors to wordpress/wp-content/debug.log.
For quick testing, a docker-compose.yml is included with custom Dockerfile that adds some extra tools to the official WordPress image (e.g. Composer, WP-CLI, XDebug). The custom-entrypoint.sh sets up the plugin on first run and creates an admin user.
Ensure that the port 8089 is not being exposed to unsafe network from host as the default admin credentials are weak.
Replace podman with docker in the commands if preferred. Tested on Debian 13 using APT packages podman, podman-compose, aardvark-dns.
git clone git@github.com:jasalt/phel-wp-plugin.git
cd phel-wp-plugin
podman compose up -d && podman compose logs -f
Following a success message, use the default credentials (admin / password) to access WordPress admin page http://localhost:8089/wp-admin.
For historical reasons the default WordPress container running Apache may occasionally shut down with caught SIGWINCH, shutting down gracefully when it's attached to terminal. This can be avoided by running it in the background by using podman compose up -d.
Phel REPL starts with vendor/bin/phel command. Quick way to connect to into running development container:
podman compose exec -u www-data -w /var/www/html/wp-content/plugins/phel-wp-plugin wp vendor/bin/phelInterfacing with the REPL works mostly as expected, examples:
(php/require_once "../../../wp-load.php") ; instantiate WordPress
(get php/$GLOBALS "wpdb") ; refer to wpdb for database operations
(require phel.html :refer [html]) ; load Phel core libraries
(require phel-wp-plugin.my-other-ns :as my-other-ns) # load a Phel source file from src/
(use Laminas.XmlRpc.Client) ; load installed Composer PHP librariesNote that to include your own namespaces declared in the plugin directory with require, the shell working directory should be set to plugin root directory before starting the REPL.
Composer is not required if vendor directory is included with the plugin distribution. Note that Composer autoloader does not play very well with WP plugins out-of-box and something like PHP-Scoper or Strauss is probably required for plugin distribution (see also #9).
See also wp.phel for some wrapper functions over WP API's and woocommerce-memberships-migrator as a example project (a WP-CLI utility).
- XDebug's (included with VVV) infinite loop detection gives false positive on default setting and requires
ini_set('xdebug.max_nesting_level', 300); - Plugin Phel error log file path is set into the plugin directory with
->withErrorLogFile($projectRootDir . 'error.log'); change this for production.
WordPress runs wp-load.php in beginning of each HTTP request instantiating WordPress Core which loads user plugins including the phel-wp-plugin.php which bootstraps Phel by running Phel::run.
From a standalone Phel REPL session or a script it can be loaded with (php/require_once "wp-load.php"), but this would lead to bootstrapping Phel the second time without some conditional checking in phel-wp-plugin.php e.g.
// Avoid bootstrapping Phel the second time from REPL session
if (isset($PHP_SELF) && $PHP_SELF !== "./vendor/bin/phel"){
Phel::run($projectRootDir, 'phel-wp-plugin.main');
} else {
// This debug print should be removed
print("Running REPL, skip running plugin Phel::run \n");
}
