WP test container created
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# The demo WordPress
|
||||
|
||||
A clean install with **no Avada and no plugins**, so the theme has to stand on
|
||||
its own. The `wp-migrate` rig is the opposite — the production tree, kept as the
|
||||
reference to compare against — and is never touched from here.
|
||||
|
||||
cd local
|
||||
docker compose up -d # http://localhost:8090/
|
||||
|
||||
Docroot is the project's own `../site`, so a `npm run build` lands in the running
|
||||
theme with no copy step and no restart.
|
||||
|
||||
## Logging in
|
||||
|
||||
http://localhost:8090/wp-admin/ admin / tlig
|
||||
|
||||
Throwaway credentials for a throwaway local install. Nothing here is ever
|
||||
deployed, and the database lives in a named volume, not in the repo.
|
||||
|
||||
## wp-cli
|
||||
|
||||
The `cli` service is behind a Compose profile so it never starts with the site.
|
||||
Run it one command at a time:
|
||||
|
||||
docker compose --profile cli run --rm cli wp user list
|
||||
docker compose --profile cli run --rm cli wp plugin list
|
||||
docker compose --profile cli run --rm cli wp post list --post_type=page
|
||||
|
||||
Adding a user, for instance:
|
||||
|
||||
docker compose --profile cli run --rm cli \
|
||||
wp user create editor editor@example.org --role=editor --user_pass=tlig
|
||||
|
||||
It talks to MySQL directly — it does not go through Apache — so it works even
|
||||
when the site itself is down. It shares the same `../site` mount and the same
|
||||
`wp-config.php` as the web container, so the two can never disagree about which
|
||||
database they are looking at.
|
||||
|
||||
## Resetting
|
||||
|
||||
docker compose down -v # -v also drops the database volume
|
||||
|
||||
`site/` survives, because it is the repo's own tree. Re-running `wp core install`
|
||||
gives a fresh site against the same files.
|
||||
|
||||
## Offline by design
|
||||
|
||||
`wp-config.php` sets `WP_HTTP_BLOCK_EXTERNAL`: the rig boots with no network and
|
||||
never reports this install to WordPress.org. Blocking the request does not stop
|
||||
WordPress making it, though — the update checks still ran, each got a `WP_Error`
|
||||
back, and under `WP_DEBUG` each printed a warning *before* the headers, so every
|
||||
redirect and cookie after it failed too. The message it printed ("could not
|
||||
establish a secure connection") was misleading: nothing was wrong with TLS, the
|
||||
request was refused locally.
|
||||
|
||||
`site/wp-content/mu-plugins/tlig-offline.php` stops the checks at the source
|
||||
instead of letting them fail. Keep it; without it the admin fills with warnings.
|
||||
|
||||
## The menus
|
||||
|
||||
`site/wp-content/import/` holds the fifteen desktop menu trees lifted from the
|
||||
live site — 748 items, structure and labels only, with UberMenu's 149-key
|
||||
settings blob reduced to the eight fields the audit shows are ever used. Re-run
|
||||
it after changing `menus.json`; it replaces each tree rather than doubling it:
|
||||
|
||||
docker compose --profile cli run --rm cli \
|
||||
wp eval-file wp-content/import/import-menus.php
|
||||
|
||||
It takes a couple of minutes — `wp_update_nav_menu_item` is not fast — and
|
||||
finishes with a count of menus, items and images.
|
||||
|
||||
`?lang=el` picks the language (WPML is not installed; `inc/demo-languages.php`
|
||||
stands in for it). `?open=3` holds the third panel open and `?open=all` drops
|
||||
every panel into the flow — the second is the argument in one picture: seven
|
||||
panels of seven heights, all from one 328px file.
|
||||
|
||||
## Regenerating the parchment
|
||||
|
||||
python3 tools/cut-parchment.py && npm run build
|
||||
|
||||
It reads `papyrus_submenu_450_cnd.png` from the production tree, so that path
|
||||
has to exist. The tile is the master whole — 1200x450, WebP at quality 90 —
|
||||
because every narrower cut has to manufacture junctions the artwork does not
|
||||
have, and the corners showed it badly. The script's header records what was
|
||||
tried; its output prints the four corner junctions (the master's own, so a
|
||||
regression check rather than a correction) and how many vertical repeats each
|
||||
panel height needs.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Logs and the PID file must go to writable paths: /var/log/apache2 and
|
||||
# /var/run/apache2 are root-owned in the image, and this container runs as an
|
||||
# unprivileged uid so that it matches the owner of the bind-mounted tree.
|
||||
ErrorLog /dev/stderr
|
||||
PidFile /tmp/apache2.pid
|
||||
ServerName localhost
|
||||
|
||||
<Directory /var/www/html>
|
||||
Options FollowSymLinks
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
|
||||
# Fonts are the only subresource the browser always fetches in CORS mode, and
|
||||
# WordPress emits asset URLs from WP_HOME — so opening the site at any other
|
||||
# host turns every font into a blocked cross-origin request. Fine on a local
|
||||
# rig; never in production.
|
||||
<IfModule mod_headers.c>
|
||||
<FilesMatch "\.(woff2?|ttf|otf|eot)$">
|
||||
Header always set Access-Control-Allow-Origin "*"
|
||||
</FilesMatch>
|
||||
</IfModule>
|
||||
@@ -0,0 +1,4 @@
|
||||
# Apache runs as an unprivileged uid here, so it cannot bind port 80. It listens
|
||||
# on 8080 inside the container; compose publishes that as 8090 on the host, one
|
||||
# port along from the wp-migrate rig so both can run side by side.
|
||||
Listen 8080
|
||||
@@ -0,0 +1,12 @@
|
||||
# Replaces the image's 000-default.conf, which is bound to port 80.
|
||||
<VirtualHost *:8080>
|
||||
DocumentRoot /var/www/html
|
||||
|
||||
ErrorLog /dev/stderr
|
||||
CustomLog /dev/stdout combined
|
||||
|
||||
<Directory /var/www/html>
|
||||
AllowOverride All
|
||||
Require all granted
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
@@ -0,0 +1,88 @@
|
||||
# A clean WordPress for the TLIG theme.
|
||||
#
|
||||
# Deliberately NOT the wp-migrate rig. That one bind-mounts the production tree
|
||||
# — Avada, 55 plugins, a 1.5 GB database — and exists to mirror what ships. This
|
||||
# one boots in seconds with nothing but core, so the theme has to stand on its
|
||||
# own. Keep both: the other is the reference to compare against.
|
||||
name: tlig-theme
|
||||
|
||||
services:
|
||||
db:
|
||||
image: mysql:8.4
|
||||
command: ["--mysql-native-password=ON"]
|
||||
environment:
|
||||
MYSQL_DATABASE: tlig
|
||||
MYSQL_USER: tlig
|
||||
MYSQL_PASSWORD: tlig
|
||||
MYSQL_ROOT_PASSWORD: tlig
|
||||
volumes:
|
||||
- db:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-ptlig"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 20
|
||||
|
||||
wp:
|
||||
image: wordpress:php8.3-apache
|
||||
# Skip the image's core-unpacking entrypoint: core is already on disk in
|
||||
# site/, extracted from this same image so the versions cannot drift. The
|
||||
# entrypoint would otherwise try to chmod a bind mount it does not own.
|
||||
entrypoint: ["apache2-foreground"]
|
||||
# Fedora runs SELinux enforcing, which blocks container access to bind
|
||||
# mounts — including, silently, the config files below, which is why Apache
|
||||
# kept binding port 80 despite a mounted ports.conf.
|
||||
security_opt:
|
||||
- label=disable
|
||||
# Rootless podman maps the host user to container root by default, but
|
||||
# Apache refuses to run workers as root. keep-id maps host uid 1000 to
|
||||
# container uid 1000, so the container process is literally the owner of the
|
||||
# bind-mounted tree. Under rootful docker, drop this and set RUN_UID=1000.
|
||||
userns_mode: "keep-id"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
ports:
|
||||
- "8090:8080"
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db
|
||||
WORDPRESS_DB_NAME: tlig
|
||||
WORDPRESS_DB_USER: tlig
|
||||
WORDPRESS_DB_PASSWORD: tlig
|
||||
WORDPRESS_DEBUG: "1"
|
||||
WORDPRESS_CONFIG_EXTRA: |
|
||||
define( 'WP_DEBUG_DISPLAY', true );
|
||||
define( 'SCRIPT_DEBUG', true );
|
||||
define( 'DISALLOW_FILE_EDIT', true );
|
||||
# The project's own site/ is the docroot, so a Vite build lands in the
|
||||
# running theme immediately — no copy step, no container restart. Config is
|
||||
# mounted over the top, so site/ never holds environment-specific settings.
|
||||
volumes:
|
||||
- ../site:/var/www/html
|
||||
- ./wp-config.php:/var/www/html/wp-config.php:ro
|
||||
- ./apache-ports.conf:/etc/apache2/ports.conf:ro
|
||||
- ./apache-vhost.conf:/etc/apache2/sites-enabled/000-default.conf:ro
|
||||
- ./apache-local.conf:/etc/apache2/conf-enabled/zz-local.conf:ro
|
||||
user: "${RUN_UID:-1000}:${RUN_GID:-1000}"
|
||||
|
||||
cli:
|
||||
image: wordpress:cli-php8.3
|
||||
security_opt:
|
||||
- label=disable
|
||||
userns_mode: "keep-id"
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db
|
||||
WORDPRESS_DB_NAME: tlig
|
||||
WORDPRESS_DB_USER: tlig
|
||||
WORDPRESS_DB_PASSWORD: tlig
|
||||
volumes:
|
||||
- ../site:/var/www/html
|
||||
- ./wp-config.php:/var/www/html/wp-config.php:ro
|
||||
user: "${RUN_UID:-1000}:${RUN_GID:-1000}"
|
||||
profiles: ["cli"]
|
||||
|
||||
volumes:
|
||||
db:
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/**
|
||||
* Local config for the clean TLIG rig.
|
||||
*
|
||||
* Mounted over /var/www/html/wp-config.php, so site/ stays free of config and
|
||||
* nothing environment-specific can be committed by accident.
|
||||
*/
|
||||
|
||||
define( 'DB_NAME', 'tlig' );
|
||||
define( 'DB_USER', 'tlig' );
|
||||
define( 'DB_PASSWORD', 'tlig' );
|
||||
define( 'DB_HOST', 'db' );
|
||||
define( 'DB_CHARSET', 'utf8mb4' );
|
||||
define( 'DB_COLLATE', '' );
|
||||
|
||||
// Local only — these are not secrets and are not used anywhere else.
|
||||
define( 'AUTH_KEY', 'tlig-local-auth' );
|
||||
define( 'SECURE_AUTH_KEY', 'tlig-local-secure-auth' );
|
||||
define( 'LOGGED_IN_KEY', 'tlig-local-logged-in' );
|
||||
define( 'NONCE_KEY', 'tlig-local-nonce' );
|
||||
define( 'AUTH_SALT', 'tlig-local-auth-salt' );
|
||||
define( 'SECURE_AUTH_SALT', 'tlig-local-secure-auth-salt' );
|
||||
define( 'LOGGED_IN_SALT', 'tlig-local-logged-in-salt' );
|
||||
define( 'NONCE_SALT', 'tlig-local-nonce-salt' );
|
||||
|
||||
$table_prefix = 'wp_';
|
||||
|
||||
define( 'WP_HOME', 'http://localhost:8090' );
|
||||
define( 'WP_SITEURL', 'http://localhost:8090' );
|
||||
|
||||
define( 'WP_DEBUG', true );
|
||||
define( 'WP_DEBUG_DISPLAY', true );
|
||||
define( 'SCRIPT_DEBUG', true );
|
||||
define( 'DISALLOW_FILE_EDIT', true );
|
||||
|
||||
// Outbound HTTP is allowed. It was blocked here once, to stop the rig
|
||||
// reporting itself to WordPress.org on every admin page — but blocking the
|
||||
// domain also broke Add Plugins, which has to reach the directory to list
|
||||
// anything. The automatic calls are stopped where they start instead, in
|
||||
// site/wp-content/mu-plugins/tlig-offline.php; deliberate ones go out.
|
||||
define( 'AUTOMATIC_UPDATER_DISABLED', true );
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
define( 'ABSPATH', __DIR__ . '/' );
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-settings.php';
|
||||
Reference in New Issue
Block a user