diff --git a/AGENTS.md b/AGENTS.md index 7319f00..55effa8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -4,7 +4,7 @@ - **trellis/** - Trellis-specific: `backup/`, `monitoring/`, `updater/` - **wp-cli/** - WordPress CLI tools: `content-creation/`, `diagnostics/`, `migration/` - **scripts/** - Utilities: `backup/`, `monitoring/`, `git/create-pr.sh`, `sync/rsync-theme.sh` -- **docs/** - Design docs at the top level; guides in subdirectories: `nginx/` (server configs), `bedrock/` (Composer workflows), `wordpress-utilities/` (copy-paste components) +- **docs/** - Design docs at the top level; guides in subdirectories: `nginx/` (Trellis include templates), `bedrock/` (the standard `wp-cli.yml`) - **Root docs**: `README.md`, `CLAUDE.md`, `CREATE-PR.md`, `AGENTS.md`, `CHANGELOG.md`, `LICENSE.md` - Keep new tools self-contained: add to appropriate category with a concise `README.md` and example configs. diff --git a/CHANGELOG.md b/CHANGELOG.md index 1566753..2ac7db0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Removed +- **The Bedrock guides, the WP-CLI snippets and the speed-optimization pointer**, now four posts on wpvilla.in: [testing an unreleased plugin with a Composer path repository](https://wpvilla.in/bedrock-composer-path-repository-test-plugin-before-release-symlink-false/), [the standard `wp-cli.yml` and `pattern-validate`](https://wpvilla.in/bedrock-wp-cli-yml-and-pattern-validate-block-pattern-files/), [a frozen Site Editor template override](https://wpvilla.in/wordpress-block-template-frozen-site-editor-database-override-wp-cli/) and [creating a temporary admin when locked out](https://wpvilla.in/wordpress-locked-out-emergency-admin-user-wp-cli-ssh/); TTFB measuring was already [a post](https://wpvilla.in/measure-wordpress-ttfb-curl-wget-user-agents/). `docs/wordpress-utilities/` is gone entirely, as are the two READMEs under `docs/bedrock/`; `wp-cli.yml` stays with a header linking its post. The old admin-user guide gave 16-character passwords "~95 bits"; `openssl rand -base64 16` is 128 bits of randomness, and the post says so. - **The Nginx guides**, now two new posts and one existing post on wpvilla.in: [serving WebP and AVIF through Accept-header negotiation](https://wpvilla.in/serve-webp-avif-nginx-trellis-accept-header-bedrock-uploads/), [browser caching headers as a global include](https://wpvilla.in/nginx-browser-caching-headers-trellis-all-includes-expires/) and [the redirect provision tag and query string](https://wpvilla.in/trellis-nginx-redirect-not-deployed-query-string-dropped/). The four READMEs under `docs/nginx/` are gone; the `.conf.j2` templates stay, and each now opens with a link to its post. The WebP/AVIF template is now `docs/nginx/image-optimization/nginx-includes/all/00-webp-avif.conf.j2`, rewritten after testing it against Nginx: the old file failed `nginx -t` as a site include (`map` is not allowed in a server block), served `photo.webp` instead of the documented `photo.jpg.webp`, and lost to the caching include's image block. It is now a global include that loads first, uses `set`/`if` instead of `map`, and sets its own expiry; rename existing `photo.webp` files to `photo.jpg.webp`. Site includes live in a folder named after the site key; the guides' `nginx_includes` setting does not exist. The browser caching guide had documented 30-day and 7-day durations while the template sets one year; the post describes the template. The generic redirect best-practice and rollback sections are not carried over. - **The troubleshooting guides**, now covered on wpvilla.in: [PHP-FPM memory exhaustion](https://wpvilla.in/debugging-php-fpm-memory-exhaustion-wordpress-woocommerce-trellis/), [mail that never arrives or bounces](https://wpvilla.in/trellis-mail-not-sending-smtp-config-reset-and-bounces/), [the MariaDB failure at "Set root user password"](https://wpvilla.in/trellis-provision-set-root-user-password-fails-mariadb-provider-plugins/) and a new post on [the OOM killer, cron and the unlimited PHP CLI memory limit](https://wpvilla.in/linux-oom-killer-wordpress-cron-php-cli-memory-limit-trellis/). `docs/troubleshooting/` is gone, and the README, `AGENTS.md` and `CLAUDE.md` no longer point at it. The generic MariaDB diagnostics and the PHP-FPM sizing tables are not carried over; they stay in git history. - **The security guides**, now four posts on wpvilla.in: [the two scanners and checksum verification](https://wpvilla.in/wordpress-malware-scanners-targeted-general-checksum-verification/), [reading scan results](https://wpvilla.in/reading-malware-scan-results-false-positives-wordpress-hardening/), [a permanent Nginx deny list](https://wpvilla.in/nginx-deny-list-trellis-cidr-whitelist-self-lockout/) and [a Trellis security routine](https://wpvilla.in/trellis-wordpress-security-routine-abuseipdb-fail2ban/), plus the existing [fail2ban post](https://wpvilla.in/fail2ban-wordpress-wp-login-trellis-nginx-deny-list/). The `README`, `SECURITY-GUIDE` and `SCANNER-SUMMARY` guides in `wp-cli/security/` and the `README`, `FAIL2BAN` and `MANUAL-IP-BLOCKING` guides in `trellis/security/` are gone; the scanners and the AbuseIPDB scripts stay. The scanner wrapper's closing hint now names the post. diff --git a/CLAUDE.md b/CLAUDE.md index 3a33577..1a50ba4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,8 +38,7 @@ This is a collection of tools, scripts, and documentation for WordPress operatio - `docs/dev/` - Design and planning docs for wp-ops itself. New ones go here, not at the `docs/` top level - `docs/cli/` - How the `wp-ops` binary works: usage reference (categories, platforms, completion, guide search) and the trellis-cli plugin - `docs/nginx/` - Web server configs: `browser-caching/`, `image-optimization/`, `redirects/` (the `.conf.j2` templates; each header links its wpvilla.in post) - - `docs/bedrock/` - Bedrock/Composer workflows: local package development, and the standard `wp-cli.yml` for Bedrock path setup - - `docs/wordpress-utilities/` - Copy-paste-into-a-project components and reference material: `snippets/`, `speed-optimization/` + - `docs/bedrock/` - The standard `wp-cli.yml` for Bedrock path setup (its header links the wpvilla.in post) ## Key Technologies diff --git a/README.md b/README.md index 49ad82a..628df50 100644 --- a/README.md +++ b/README.md @@ -135,8 +135,8 @@ sites are run with: | **Security** | Malware scanners with checksum verification, fail2ban, manual IP blocking, AbuseIPDB lookup | [routine](https://wpvilla.in/trellis-wordpress-security-routine-abuseipdb-fail2ban/) · [scanners](https://wpvilla.in/wordpress-malware-scanners-targeted-general-checksum-verification/) | | **Content & SEO** | Page creation, block pattern validation, redirect/schema/orphan-page audits | [SEO](wp-cli/seo/README.md) | | **Nginx** | WebP/AVIF serving, browser caching and redirect templates for Trellis `nginx-includes/` [images](https://wpvilla.in/serve-webp-avif-nginx-trellis-accept-header-bedrock-uploads/) · [caching](https://wpvilla.in/nginx-browser-caching-headers-trellis-all-includes-expires/) · [redirects](https://wpvilla.in/trellis-nginx-redirect-not-deployed-query-string-dropped/) | -| **Bedrock** | Testing unreleased packages via Composer `path` repos, standard `wp-cli.yml` | [packages](docs/bedrock/local-package-development/README.md) · [wp-cli.yml](docs/bedrock/wp-cli-config/README.md) | -| **Scripts & guides** | Theme sync, PR helpers, WP-CLI snippets for Bedrock | [scripts](scripts/README.md) · [snippets](docs/wordpress-utilities/snippets/README.md) | +| **Bedrock** | Testing unreleased packages via Composer `path` repos, standard `wp-cli.yml` | [packages](https://wpvilla.in/bedrock-composer-path-repository-test-plugin-before-release-symlink-false/) · [wp-cli.yml](https://wpvilla.in/bedrock-wp-cli-yml-and-pattern-validate-block-pattern-files/) | +| **Scripts** | Theme sync, PR helpers, emergency admin creation | [scripts](scripts/README.md) · [admin recovery](https://wpvilla.in/wordpress-locked-out-emergency-admin-user-wp-cli-ssh/) | ## Requirements diff --git a/docs/bedrock/README.md b/docs/bedrock/README.md deleted file mode 100644 index 3b74566..0000000 --- a/docs/bedrock/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Bedrock - -Tools and workflows for [Bedrock](https://roots.io/bedrock/)-based WordPress sites. - -## Contents - -### [`local-package-development/`](local-package-development/) - -Test an in-development plugin or theme inside a Bedrock site before tagging a release, by pointing the site's Composer dependency at a local git working copy via a `path` repository. Covers setup, the `symlink: false` requirement, re-syncing after edits, and cleanup. - -### [`wp-cli-config/`](wp-cli-config/) - -Standard `wp-cli.yml` for Bedrock (sets `path: web/wp` so `--path` is never needed) plus a custom `wp imagewize pattern-validate` command that round-trips block pattern files through WordPress's own parser to enforce canonical formatting. diff --git a/docs/bedrock/local-package-development/README.md b/docs/bedrock/local-package-development/README.md deleted file mode 100644 index 39bd3f3..0000000 --- a/docs/bedrock/local-package-development/README.md +++ /dev/null @@ -1,184 +0,0 @@ -# Local Package Development (Composer path repository) - -Test an in-development plugin or theme inside a [Bedrock](https://roots.io/bedrock/) -site **before tagging a release**, by pointing the site's Composer dependency at -your local git working copy / branch instead of Packagist (or a private repo such -as wp-packages.org). - -This is purely a local-dev change to the site's `composer.json` — **do not commit -it to the site repository**. Revert it once the package release is tagged. - -## TL;DR - -```bash -# In the Bedrock site's composer.json: -# 1. add a "path" repository pointing at your local package checkout -# 2. change the package constraint to the branch: "dev-" -# Then: -cd /path/to/bedrock-site -composer update vendor/package-name -``` - -## Setup - -### 1. Add a `path` repository - -In the site's `composer.json`, add a `path` repository to the **top** of the -`repositories` array (entries are evaluated in order; listing it first lets it win -over Packagist / private repos for this package): - -```json -"repositories": [ - { - "type": "path", - "url": "../../my-plugin", - "options": { - "symlink": false - } - }, - { - "name": "wp-packages", - "type": "composer", - "url": "https://repo.wp-packages.org" - } -], -``` - -- `url` is the path to your local package checkout, relative to the site's - `composer.json` (absolute paths also work, but relative is more portable). -- **`symlink: false` is important** — see [Why `symlink: false`](#why-symlink-false-not-true) below. - -### 2. Point the constraint at your branch - -Change the package's version constraint to Composer's `dev-` form: - -```json -"require": { - "vendor/my-plugin": "dev-feature-xyz" -} -``` - -A `path` repository derives the package version from the **currently checked-out -branch** of that local repo, so the constraint must match that branch. Branch -`feature-xyz` → constraint `dev-feature-xyz`. (Slashes are kept: branch -`feat/xyz` → `dev-feat/xyz`.) - -Bedrock ships with `"minimum-stability": "dev"` and `"prefer-stable": true`, so a -`dev-` constraint resolves fine. If some *other* package depends on yours with a -semver range (e.g. `^2.0`), add an inline alias so both resolve: - -```json -"vendor/my-plugin": "dev-feature-xyz as 2.0.99" -``` - -### 3. Install - -```bash -cd /path/to/bedrock-site -composer update vendor/my-plugin -``` - -You should see `Mirroring from ../../my-plugin`. The package lands as a **real -copied directory** in `web/app/plugins/` (or `web/app/themes/`), which WordPress -activates normally. - -## Why `symlink: false` (not `true`) - -Composer's `path` repository defaults to **symlinking** the package into place. For -a Bedrock plugin/theme that breaks activation: - -> The plugin `my-plugin/my-plugin.php` has been deactivated due to an error: -> Plugin file does not exist. - -WordPress calls `realpath()` on the plugin file, which resolves the symlink to its -target **outside** `web/app/plugins/` (e.g. `/Users/you/code/my-plugin`). -`plugin_basename()` then computes a slug that no longer matches the stored -activation record (`my-plugin/my-plugin.php`), so WordPress decides the file is -missing and deactivates it. Themes hit the analogous problem. - -`symlink: false` makes Composer **mirror (copy)** the package instead, giving -WordPress a real directory inside the install. Trade-off: see re-syncing below. - -## Re-syncing after local edits - -Because the package is **copied**, edits in your local checkout do **not** appear -in the site automatically. Composer also won't re-mirror when the commit hash is -unchanged, so force it: - -```bash -cd /path/to/bedrock-site -rm -rf web/app/plugins/my-plugin && composer update vendor/my-plugin -``` - -Commit (or at least stage) changes in the package repo first — the mirror reflects -the working tree at mirror time. - -## Alternative: `vcs` repository (pushed branch) - -If you've pushed the branch to GitHub and prefer not to reference a local path -(e.g. so a teammate can reproduce), use a `vcs` repository instead. This installs a -normal git checkout — no symlink, so no activation bug: - -```json -"repositories": [ - { - "type": "vcs", - "url": "https://github.com/vendor/my-plugin" - } -] -``` - -```json -"vendor/my-plugin": "dev-feature-xyz" -``` - -Trade-off: edits require `git push` + `composer update` to reach the site (no live -local working copy). - -## Revert / cleanup - -When the package release is tagged, undo the local-dev wiring: - -1. Remove the `path` (or `vcs`) repository entry from the site's `composer.json`. -2. Restore the normal constraint (e.g. `^2.0`). -3. `composer update vendor/my-plugin`. - -## Gotchas - -- **Don't commit the change to the site repo** — the `path` `url` is specific to - your machine. Keep it on a local-only branch or `git stash` / revert it. -- **`symlink: true` breaks plugin/theme activation** — always use `false` for - Bedrock. (See above.) -- **Stale mirror** — Composer skips re-mirroring an unchanged commit hash; - `rm -rf` the installed dir to force a fresh copy. -- **Compiled assets** — if the package ships a build artifact (e.g. a webpack - bundle in `dist/`), make sure it's built/committed in the package before - mirroring; the site loads the committed artifact, not your `src/`. -- **`minimum-stability`** — `dev-` constraints need `dev` (or a per-package - `@dev` flag) allowed. Bedrock defaults to `"minimum-stability": "dev"`. - -## Worked example - -Testing the `issues-30-05-26` branch of `example/warder-cookie-consent` in a -Bedrock site located at `code/example.com/demo`, with the plugin checked out at -`code/warder-cookie-consent`: - -```json -"repositories": [ - { - "type": "path", - "url": "../../warder-cookie-consent", - "options": { "symlink": false } - } -], -"require": { - "example/warder-cookie-consent": "dev-issues-30-05-26" -} -``` - -```bash -cd code/example.com/demo -composer update example/warder-cookie-consent -# - Installing example/warder-cookie-consent (dev-issues-30-05-26 7290d6d): -# Mirroring from ../../warder-cookie-consent -``` diff --git a/docs/bedrock/wp-cli-config/README.md b/docs/bedrock/wp-cli-config/README.md deleted file mode 100644 index fa4c327..0000000 --- a/docs/bedrock/wp-cli-config/README.md +++ /dev/null @@ -1,137 +0,0 @@ -# Bedrock WP-CLI Configuration - -Standard `wp-cli.yml` for a [Bedrock](https://roots.io/bedrock/) site plus a custom -`wp imagewize pattern-validate` command for keeping block pattern files in canonical form. - -Place both files in your **Bedrock site root** (the directory that contains `composer.json`). - ---- - -## `wp-cli.yml` - -```yaml -path: web/wp -server: - docroot: web -require: - - wp-cli-pattern-validate.php -``` - -| Key | Purpose | -|-----|---------| -| `path` | Tells WP-CLI where WordPress core lives in a Bedrock layout — saves you `--path=web/wp` on every command | -| `server.docroot` | Used by `wp server` (built-in dev server) to serve from Bedrock's public root | -| `require` | Auto-loads `wp-cli-pattern-validate.php` on every `wp` call so the `imagewize pattern-validate` command is always available without an explicit `--require` flag | - ---- - -## `wp-cli-pattern-validate.php` - -A WP-CLI command that round-trips block pattern files through WordPress's own -`parse_blocks()` / `serialize_blocks()` to produce the exact markup WordPress -would write after a Gutenberg save. Ideal for enforcing consistent formatting -across a block theme's `patterns/` directory in CI or as a pre-commit check. - -### How it works - -1. Reads each `.php` pattern file and extracts the block HTML (supports both the - `return 'string';` format and the PHP docblock + raw HTML format). -2. Passes the block HTML through `parse_blocks()` then `serialize_blocks()`. -3. Reverses the unicode escapes WordPress adds to `<`, `>`, `&`, and `--` so that - PHP open/close tags, CSS custom properties (`--wp--…`), and literal `&` survive - round-tripping unchanged. -4. Compares original vs canonical — reports PASS / FAIL, optionally diffs or fixes. - -### Usage - -```bash -# Validate all patterns — dry run, shows PASS/FAIL per file -wp imagewize pattern-validate web/app/themes/your-theme/patterns/ - -# Show a unified diff for each file that needs changes (no writes) -wp imagewize pattern-validate web/app/themes/your-theme/patterns/ --diff - -# Auto-fix all structural issues in-place -wp imagewize pattern-validate web/app/themes/your-theme/patterns/ --fix - -# Fix and save per-file diff logs + a summary to docs/pattern-logs// -wp imagewize pattern-validate web/app/themes/your-theme/patterns/ --fix --log - -# Override the log output directory -wp imagewize pattern-validate web/app/themes/your-theme/patterns/ --fix --log --log-dir=/tmp/pattern-logs - -# Validate a single file -wp imagewize pattern-validate web/app/themes/your-theme/patterns/hero.php --fix - -# Validate a subdirectory only -wp imagewize pattern-validate web/app/themes/your-theme/patterns/woocommerce/ --fix -``` - -If `wp-cli-pattern-validate.php` is **not** auto-loaded via `wp-cli.yml`, pass it explicitly: - -```bash -wp --require=wp-cli-pattern-validate.php imagewize pattern-validate web/app/themes/your-theme/patterns/ -``` - -**Via wp-ops:** runnable straight from the wp-ops checkout (no copying required) — set `WP_SITE_DIR` to your Bedrock site root: `WP_SITE_DIR=/path/to/site wp-ops bedrock wp-cli-pattern-validate web/app/themes/your-theme/patterns/ --fix`. See [`wp-ops`](../../../README.md). - -### Options - -| Flag | Description | -|------|-------------| -| `--fix` | Rewrite each non-canonical file in-place | -| `--diff` | Print a unified diff to stdout (dry-run, no writes) | -| `--log` | Write per-file `.diff` logs and a `summary.md` to `docs/pattern-logs//` | -| `--log-dir=` | Override the default log directory | -| `--compliance` | Run project-specific compliance checks after structural validation | -| `--compliance-only` | Skip Gutenberg round-trip; run only compliance checks | - -### Exit codes - -| Code | Meaning | -|------|---------| -| `0` | All files pass (or all issues fixed) | -| `1` | One or more files need changes (dry-run) or a write error occurred | - -### WooCommerce patterns - -Files under a `woocommerce/patterns/` path are automatically skipped — they follow -WooCommerce's own standards rather than your theme's. - -### Compliance hook - -The `--compliance` and `--compliance-only` flags call `run_compliance_checks()`, which -is a stub in the distributed file. Adapt it to point at your project's own static-analysis -script (e.g. a checker that enforces theme-specific block rules): - -```php -// Inside run_compliance_checks(): -$checker = dirname( __FILE__ ) . '/scripts/pattern-check/class-compliancechecker.php'; -``` - -Projects that don't need this can leave the stub as-is — the flags will emit a warning -and exit cleanly. - -### Log output structure - -With `--log`, each run creates: - -``` -docs/pattern-logs/ -└── 2026-05-30/ - ├── hero.php.diff - ├── card.php.diff - └── summary.md -``` - -`summary.md` contains a per-file status table (PASS / FIXED / NEEDS_FIX) and counts. - ---- - -## Requirements - -- WP-CLI 2.x -- PHP 7.4+ -- `diff` binary available in `$PATH` (standard on macOS and Linux) -- WordPress must be bootstrapped for `parse_blocks()` / `serialize_blocks()` to be - available — run `wp` from the Bedrock site root as usual diff --git a/docs/bedrock/wp-cli-config/wp-cli.yml b/docs/bedrock/wp-cli-config/wp-cli.yml index 41370b6..41e0a30 100644 --- a/docs/bedrock/wp-cli-config/wp-cli.yml +++ b/docs/bedrock/wp-cli-config/wp-cli.yml @@ -1,3 +1,6 @@ +# Standard wp-cli.yml for a Bedrock site root (next to composer.json). +# Guide: https://wpvilla.in/bedrock-wp-cli-yml-and-pattern-validate-block-pattern-files/ +# The require line loads wp-cli/content-creation/wp-cli-pattern-validate.php; copy that file next to this one, or drop the line. path: web/wp server: docroot: web diff --git a/docs/wordpress-utilities/README.md b/docs/wordpress-utilities/README.md deleted file mode 100644 index 5f009af..0000000 --- a/docs/wordpress-utilities/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# WordPress Utilities - -A collection of reusable WordPress components, scripts, and tools for common functionality and diagnostics. These utilities are designed to be copied into WordPress themes or used as reference implementations. - -## Overview - -This directory contains self-contained utilities that can be integrated into any WordPress project. Each utility is documented with installation instructions, dependencies, and usage examples. - -## Available Utilities - -### Analytics - -Implementation notes and curl-based detection for Site Kit, Google Analytics, Tag Manager and Matomo now live on the blog: [Which Analytics Is This WordPress Site Running?](https://wpvilla.in/detect-wordpress-analytics-curl-site-kit-gtm-matomo/). - -### [Snippets](snippets/) - -WP-CLI guides for Trellis and Bedrock sites. - -**Available:** -- `admin-user-creation-wpcli.md` — WP-CLI commands for safe admin user creation -- `wp-template-db-override-wpcli.md` — Fix block theme templates frozen by a Site Editor database override - -The non-Trellis snippets (WooCommerce attributes, post-expiry noindex, WebP featured images, the age gate) are on the blog; the [snippets README](snippets/README.md) links them. - -### [Speed Optimization](speed-optimization/) - -Performance testing tools and TTFB (Time To First Byte) analysis utilities. - -**Features:** -- curl-based TTFB measurement -- wget timing diagnostics -- Google web.dev performance guidelines (≤ 0.8s target) -- Response header analysis -- Server cache validation (LiteSpeed, etc.) - -**Performance Targets:** -- Good: TTFB ≤ 0.8 seconds -- Needs Improvement: 0.8 - 1.8 seconds -- Poor: > 1.8 seconds - -**Key Files:** -- `README.md` - The bundled TTFB scripts, with a link to the full measuring guide - -## Installation - -Each utility is self-contained and can be integrated independently: - -1. Navigate to the specific utility directory -2. Review the README.md for requirements and dependencies -3. Copy the necessary files to your WordPress theme or plugin -4. Follow the installation and configuration instructions - -### General Prerequisites - -Most utilities may require one or more of: -- WordPress 5.0+ -- WP-CLI (for command-line utilities) -- PHP 7.4+ or 8.0+ - -## Usage Patterns - -### Development Workflow - -1. **Test locally first**: Always test utilities in a development environment -2. **Review dependencies**: Check README files for required plugins and libraries -3. **Customize as needed**: Utilities are templates - adapt to your specific requirements -4. **Version control**: Track customizations separately from source utilities - -### Integration Examples - -**Speed Testing in deployment scripts:** -```bash -#!/bin/bash -# Post-deployment performance check -DOMAIN="example.com" -TTFB=$(curl -w "%{time_starttransfer}" -o /dev/null -s https://$DOMAIN) - -if (( $(echo "$TTFB > 0.8" | bc -l) )); then - echo "WARNING: TTFB is ${TTFB}s (target: ≤0.8s)" -fi -``` - -**Analytics Detection in site audits:** -```bash -# Quick check for analytics implementation -curl -sL https://example.com | grep -E 'googlesitekit|matomo|gtag' -``` -See [the detection post](https://wpvilla.in/detect-wordpress-analytics-curl-site-kit-gtm-matomo/) for the full set of checks. - -## Best Practices - -### Security - -- **Never commit sensitive data**: API keys, tracking IDs should be in environment variables -- **Validate user input**: Especially for utilities that accept user data -- **Keep dependencies updated**: Regularly update plugins and other dependencies -- **Use HTTPS**: All external script references should use secure protocols - -### Performance - -- **Minimize JavaScript**: Only load scripts on pages where needed -- **Use conditional loading**: Check for required conditions before enqueuing assets -- **Cache static assets**: Leverage browser caching for CSS/JS files - -### Maintenance - -- **Document customizations**: Track changes made to base utilities -- **Test after WordPress updates**: Verify compatibility with major WordPress releases -- **Monitor deprecations**: Watch for deprecated functions in utilities -- **Regular audits**: Periodically review utility usage and necessity - -## Architecture - -### File Organization - -Each utility follows this structure: -``` -utility-name/ -├── README.md # Complete documentation -└── examples/ # Usage examples (optional) -``` - -## Contributing - -When adding new utilities: - -1. Create a dedicated directory with descriptive name -2. Include comprehensive README.md with: - - Feature overview - - Installation instructions - - Dependencies and requirements - - Usage examples - - Troubleshooting guide -3. Follow existing code patterns -4. Test with current WordPress version -5. Update this main README.md - -## Related Tools - -These utilities complement other tools in the wp-ops repository: - -- **[wp-cli/](../../wp-cli/)** - WordPress command-line operations -- **[nginx/](../nginx/)** - Web server configurations for performance -- **[scripts/](../../scripts/)** - Automation and deployment scripts -- **[trellis/](../../trellis/)** - Server provisioning and deployment - -## License - -These utilities are provided as-is for use in WordPress projects. Refer to individual utility directories for specific licensing information. - -## Support - -For issues or questions: -- Review the specific utility's README.md -- Check WordPress Codex and plugin documentation - ---- - -*Part of the [wp-ops](../) repository - Tools and documentation for WordPress operations* diff --git a/docs/wordpress-utilities/snippets/README.md b/docs/wordpress-utilities/snippets/README.md deleted file mode 100644 index ea004aa..0000000 --- a/docs/wordpress-utilities/snippets/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# WordPress Snippets - -WP-CLI guides for Trellis and Bedrock sites. - -Guides that were not specific to Trellis or Bedrock now live on the blog: - -- [WooCommerce product attributes and variations with WP-CLI](https://wpvilla.in/woocommerce-product-attributes-variations-wp-cli-trellis-multisite/) -- [Noindex posts after an expiry date with Yoast's `wpseo_robots` filter](https://wpvilla.in/wordpress-post-expiry-noindex-yoast-wpseo-robots-timezone/) -- [WebP featured images without breaking `og:image`](https://wpvilla.in/wordpress-webp-featured-images-og-image-original-jpg/) -- [A cookie-based age gate for WordPress](https://wpvilla.in/wordpress-age-verification-modal-cookie-acf-jquery/) - -## Available Snippets - -### [admin-user-creation-wpcli.md](admin-user-creation-wpcli.md) - -**Recommended approach** for creating WordPress administrator users safely from the command line. - -**Features:** -- No code to add/remove from WordPress files -- Credentials aren't stored in files -- Full control via command line -- Secure random password generation examples -- Batch user creation from CSV files -- Emergency lockout recovery workflow - -**Quick Start:** -```bash -wp user create temp_admin temp@example.com --role=administrator --user_pass="$(openssl rand -base64 16)" -``` - -### [wp-template-db-override-wpcli.md](wp-template-db-override-wpcli.md) - -Fix block theme templates that appear frozen — changes to PHP pattern files or `.html` template files are silently ignored because the Site Editor saved a DB override (`wp_template` post type) that takes precedence over the file on disk. - -**Features:** -- Detect DB overrides by listing `wp_template` posts -- Option A: delete the DB copy to restore file-system control -- Option B: surgically update specific block markup in the DB copy using `wp eval` + `str_replace` -- Trellis VM variants for all commands -- Prevention guidance (`WP_DEVELOPMENT_MODE=theme`) - -**Quick Start:** -```bash -# Find the frozen template post -wp post list --post_type=wp_template --fields=ID,post_name,post_status --path=web/wp --url=https://example.com/ - -# Delete it (restores file-system template) -wp post delete --force --path=web/wp --url=https://example.com/ -``` diff --git a/docs/wordpress-utilities/snippets/admin-user-creation-wpcli.md b/docs/wordpress-utilities/snippets/admin-user-creation-wpcli.md deleted file mode 100644 index 18f489b..0000000 --- a/docs/wordpress-utilities/snippets/admin-user-creation-wpcli.md +++ /dev/null @@ -1,231 +0,0 @@ -# Admin User Creation via WP-CLI - -Create WordPress administrator users safely from the command line using WP-CLI. - -**Recommended approach** over PHP snippets — no code to remove, credentials aren't stored in files, and you have full control via the command line. - -## Quick Command - -```bash -wp user create temp_admin temp@example.com --role=administrator --user_pass="$(openssl rand -base64 16)" -``` - -This: -- Creates user `temp_admin` with email `temp@example.com` -- Assigns the `administrator` role -- Generates a secure random 16-character password -- Outputs the password to the terminal (visible during execution) - -## Basic Usage - -### Create a user with a specific password - -```bash -wp user create username user@example.com --role=administrator --user_pass="YourStrongPassword123!" -``` - -### Create a user with a generated password (more secure) - -```bash -# macOS/Linux - using openssl for random password -wp user create temp_admin temp@example.com --role=administrator --user_pass="$(openssl rand -base64 16)" - -# Alternative: using pwgen (if installed) -wp user create temp_admin temp@example.com --role=administrator --user_pass="$(pwgen -s 16 1)" - -# Fallback: using date-based password (less secure but works everywhere) -wp user create temp_admin temp@example.com --role=administrator --user_pass="TempPass-$(date +%s)" -``` - -### Create without specifying password (WP-CLI will generate one) - -```bash -wp user create temp_admin temp@example.com --role=administrator -# WP-CLI auto-generates a password and displays it -``` - -## Practical Examples - -### Emergency admin access after lockout - -When you've been locked out of WordPress (lost admin password, plugin conflict, etc.): - -```bash -# Connect to server via SSH -ssh admin_user@yoursite.com - -# Navigate to WordPress directory -cd /srv/www/yoursite.com/current - -# Create temporary admin user -wp user create recovery_admin recovery@yoursite.com --role=administrator --user_pass="$(openssl rand -base64 16)" - -# Note: WP-CLI will output the password - copy it immediately -# Then log in at: https://yoursite.com/wp-admin - -# After regaining access, delete the temporary user: -wp user delete recovery_admin --yes -``` - -### Create admin with display name - -```bash -wp user create john.doe john@example.com --role=administrator --display_name="John Doe" --first_name=John --last_name=Doe -``` - -### Create multiple admin users from a list - -```bash -# Using a simple text file with format: username,email -while IFS=, read -r username email; do - wp user create "$username" "$email" --role=administrator --user_pass="$(openssl rand -base64 16)" -done < users.csv -``` - -### Create admin and immediately change their password - -```bash -# Create user -wp user create temp_admin temp@example.com --role=administrator --user_pass="initial_password" - -# Change password (user must use password reset link, or admin can change it via WP Admin) -wp user update temp_admin --user_pass="new_secure_password" -``` - -## Security Best Practices - -### Always use strong passwords - -```bash -# Good: Random base64 string (16 chars = ~95 bits of entropy) -wp user create temp_admin temp@example.com --role=administrator --user_pass="$(openssl rand -base64 16)" - -# Better: Random base64 string (24 chars = ~143 bits of entropy) -wp user create temp_admin temp@example.com --role=administrator --user_pass="$(openssl rand -base64 24)" - -# Best: Use a password manager to generate and store the password -``` - -### Use temporary email addresses - -```bash -# Use a mailinator-style disposable address for temporary access -temp_email="temp-$(date +%s)@example.com" -wp user create temp_admin "$temp_email" --role=administrator --user_pass="$(openssl rand -base64 16)" -``` - -### Delete temporary users after use - -```bash -# List all admin users -wp user list --role=administrator --format=csv - -# Delete a temporary user by login -wp user delete temp_admin --yes - -# Delete a temporary user by ID -wp user delete 123 --yes - -# Delete and reassign their content to another user -wp user delete temp_admin --yes --reassign=1 -``` - -## Common Issues & Solutions - -### "Error: Could not create user because email already exists" - -```bash -# Check if email exists -wp user list --field=user_email | grep temp@example.com - -# Check if username exists -wp user get temp_admin --field=user_login - -# Use a different email or username -wp user create temp_admin2 temp2@example.com --role=administrator -``` - -### "Error: This username is already registered" - -```bash -# List all users -wp user list --field=user_login - -# Choose a different username -wp user create different_username temp@example.com --role=administrator -``` - -### User created but can't log in - -```bash -# Verify the user exists and has correct role -wp user get temp_admin --fields=user_login,role,user_email - -# Reset the password -wp user update temp_admin --user_pass="new_password" - -# Check if user is marked as spam (some plugins do this) -wp user meta get temp_admin wp_user_level -``` - -## Automation & Scripting - -### Create admin user in a deployment script - -```bash -#!/bin/bash -# create-temp-admin.sh - -SITE_DIR="/srv/www/yoursite.com/current" -USERNAME="deploy_temp_admin" -EMAIL="deploy@yoursite.com" - -cd "$SITE_DIR" - -# Only create if doesn't exist -if ! wp user get "$USERNAME" &>/dev/null; then - PASSWORD=$(openssl rand -base64 16) - wp user create "$USERNAME" "$EMAIL" --role=administrator --user_pass="$PASSWORD" - echo "Temporary admin created. Password: $PASSWORD" - echo "REMEMBER: Delete this user after use with: wp user delete $USERNAME --yes" -fi -``` - -### Create admin with environment variables - -```bash -# Set variables -export WP_USER="temp_$(date +%Y%m%d)" -export WP_EMAIL="${WP_USER}@yoursite.com" -export WP_PASS=$(openssl rand -base64 16) - -# Create user -wp user create "$WP_USER" "$WP_EMAIL" --role=administrator --user_pass="$WP_PASS" - -# Display credentials (be careful with terminal history) -echo "User: $WP_USER" -echo "Email: $WP_EMAIL" -echo "Password: $WP_PASS" -``` - -## Cleanup - -### Remove temporary users - -```bash -# Delete by username -wp user delete temp_admin --yes - -# Delete by email (find user first) -USER_ID=$(wp user list --field=ID,user_email | grep temp@example.com | awk -F, '{print $1}') -wp user delete "$USER_ID" --yes - -# Delete all temporary users with matching prefix -wp user list --field=ID,user_login | grep temp_ | while IFS=, read -r id login; do - wp user delete "$id" --yes -done -``` - -## See Also - -- [WP-CLI User Management Docs](https://developer.wordpress.org/cli/commands/user/) diff --git a/docs/wordpress-utilities/snippets/wp-template-db-override-wpcli.md b/docs/wordpress-utilities/snippets/wp-template-db-override-wpcli.md deleted file mode 100644 index 3d57a93..0000000 --- a/docs/wordpress-utilities/snippets/wp-template-db-override-wpcli.md +++ /dev/null @@ -1,87 +0,0 @@ -# WordPress DB Template Override — WP-CLI - -When a block theme template (e.g. `single-product.html`) is edited in the Site Editor, WordPress saves the modified version as a `wp_template` post in the database. This DB copy takes precedence over the file on disk, so changes to theme PHP pattern files (or template `.html` files) are silently ignored. - -## Detecting the problem - -Symptoms: -- You edited a PHP block pattern file but the frontend still shows old block markup. -- `data-image-sizing`, `data-block-name`, or other rendered attributes still reflect old values after a cache flush. -- `wp cache flush` does not help. - -Confirm a DB override exists: - -```bash -# List all DB-stored templates for a site (or multisite subsite) -wp post list --post_type=wp_template \ - --fields=ID,post_name,post_status \ - --path=web/wp \ - --url=https://example.com/store/ - -# Inspect the stored content for a specific template -wp post get --field=post_content --path=web/wp --url=https://example.com/store/ | head -100 -``` - -If the output contains static block markup (rather than a `` reference), the pattern was frozen/inlined when the template was saved. - -## Option A — Delete the DB override (restores file-system template) - -Use this when you want the theme file to fully control the template: - -```bash -wp post delete --force --path=web/wp --url=https://example.com/store/ -``` - -After deletion, WordPress falls back to the theme's `.html` template file, and dynamic `` references are re-evaluated from PHP on each request. - -## Option B — Surgically update the DB template content - -Use this when only part of the template needs updating (the DB copy has other customisations worth keeping): - -```bash -wp eval ' -$post_id = ; -$content = get_post($post_id)->post_content; - -$old = "\n\n"; - -$new = "\n\n\n\n"; - -if (strpos($content, $old) !== false) { - $new_content = str_replace($old, $new, $content); - wp_update_post(["ID" => $post_id, "post_content" => $new_content]); - echo "Updated successfully\n"; -} else { - echo "Old string not found — check the content manually\n"; - echo substr($content, strpos($content, "product-image"), 300) . "\n"; -} -' --path=web/wp --url=https://example.com/store/ -``` - -Flush the cache afterwards: - -```bash -wp cache flush --path=web/wp --url=https://example.com/store/ -``` - -## Trellis VM variant - -Prefix all `wp` commands with the Trellis shell wrapper: - -```bash -trellis vm shell --workdir /srv/www/demo.example.com/current -- \ - wp post list --post_type=wp_template --fields=ID,post_name,post_status \ - --path=web/wp --url=http://demo.example.test/store/ - -trellis vm shell --workdir /srv/www/demo.example.com/current -- \ - wp post delete --force --path=web/wp --url=http://demo.example.test/store/ - -trellis vm shell --workdir /srv/www/demo.example.com/current -- \ - wp cache flush --path=web/wp --url=http://demo.example.test/store/ -``` - -## Preventing re-freeze - -Once you delete or repair the DB override, avoid editing the template in the Site Editor unless you intend to create a new DB override. Prefer editing the theme `.html` template file or the referenced PHP pattern files directly. - -For development, enable `WP_DEVELOPMENT_MODE=theme` in `config/environments/development.php` (Bedrock) so WordPress skips pattern caching and picks up PHP file changes immediately. diff --git a/docs/wordpress-utilities/speed-optimization/README.md b/docs/wordpress-utilities/speed-optimization/README.md deleted file mode 100644 index 564de68..0000000 --- a/docs/wordpress-utilities/speed-optimization/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# WordPress Speed Optimization Tools - -Measuring TTFB with `curl` and `wget`, the 0.8 s / 1.8 s thresholds, and why to test as a crawler too: [Measuring WordPress TTFB From the Command Line](https://wpvilla.in/measure-wordpress-ttfb-curl-wget-user-agents/). - -## Running the Bundled Scripts - -Two runnable scripts back the manual `curl`/`wget` checks above with repeatable, -averaged measurements. They live in -[`scripts/monitoring/`](../../../scripts/monitoring/), not this folder — everything -under `wordpress-utilities/` is reference material, which doesn't fit an -actual runnable tool. - -- [`../../scripts/monitoring/ttfb-test.sh`](../../../scripts/monitoring/ttfb-test.sh) — - runs `curl` against a URL 5 times from your machine, averages - TTFB/DNS/connect/SSL timings, rates the result against the benchmarks above, - and writes a detailed report with optimization recommendations to `audits/`. - ```bash - wp-ops ttfb-test https://example.com - ``` -- [`../../scripts/monitoring/remote-ttfb-ua.sh`](../../../scripts/monitoring/remote-ttfb-ua.sh) — - runs `curl` on the server itself over SSH (so your own network distance - doesn't skew the result), once per URL for each of: default, Googlebot, - AhrefsBot, and Screaming Frog user agents — useful when a WAF or cache - treats bots differently from regular visitors. - ```bash - wp-ops remote-ttfb-ua web@example.com https://example.com/ https://example.com/blog/ - ``` \ No newline at end of file