# BW Dev

Bowden Works' all-in-one WordPress dev toolkit. One plugin replaces a fleet of standalone plugins — favicon override, sticky elements, admin list columns, post-link blocks, YouTube embeds, custom widget areas, scheduled post actions, login branding, maintenance mode, server info, settings import/export, AI-context knowledge export, and a couple of dozen more — with a unified settings page and a white-label layer for client-facing block names.

## Requirements

- WordPress 6.0 or later
- PHP 7.4 or later

## Installation

1. Download the latest release zip from https://plugins.bowden.works/bw-dev/.
2. In WP Admin, go to Plugins → Add New → Upload Plugin.
3. Upload the zip and activate.

Once installed, BW Dev checks for updates automatically from `plugins.bowden.works`.

## Settings

Everything lives at **Settings → BW Dev** — a vertical-sidebar tabbed page that lands on an **About** tab by default. Modules are organised into seven sidebar groups:

- **Core** — About, Modules (enable/disable each), Branding (white-label layer), Flywheel Auto-Updates, Login Page Branding, Server Info, Import / Export.
- **Editor & Admin** — SVG Upload, Image Optimizer, Admin Note, Disable Comments, Sticky Elements, Admin Columns, Admin Menu by Role, Dashboard, Scheduled Post Actions, Title Override, Established Year.
- **Front-end** — Favicon, Maintenance Mode, Menu Visibility, Sidebars, Inline Search, Animate Row, Scroll Down.
- **Security** — Hide Login URL, Login Redirects, Security Hardening, Login Activity Log.
- **Indexing** — Robots.txt Manager, LLMs.txt Generator, Site Knowledge.
- **Blocks** — YouTube Block, Post Link Block, Subtitle Block, Separator Block.
- **Vendors** — Plugins (recommended third-party stack), Theme (audit).

Each module is independently toggleable on the **Modules** tab. Disabled modules register zero hooks and add zero overhead. Group-aware defaults: Blocks default OFF; everything else defaults ON.

## Modules at a glance

### Core utilities

- **Branding (white-label)** — plugin display name, block category label, block title prefix. `bw_dev_brand` filter lets mu-plugins force a brand without persisting.
- **Flywheel Auto-Updates** — fixes broken WP auto-updates on Flywheel-hosted sites (their managed cron fires `wp_update_plugins` but not `wp_maybe_auto_update`).
- **Login Page Branding** — custom logo, link URL + title, page background + form-panel colours, primary-button colours, "Back to site" / "Lost password" hide toggles. Injects CSS on `login_enqueue_scripts`.
- **Server Info** — read-only environment snapshot (server / PHP / WP / database / filesystem / object cache / themes / plugins) with "Copy to clipboard" for support tickets.
- **Import / Export** — back up the full `bw_dev_settings` option as JSON and restore on another site. Imported sections are run through each module's `sanitize()` for safety.

### Editor / admin

- **SVG Upload** — adds `image/svg+xml` to allowed uploads with role-based gating + DOMDocument-based sanitization (strips `<script>`, `<foreignObject>`, `<iframe>`, `<embed>`, `<object>`, `<animate>`, `<set>`, `<a>`, all `on*` attributes, `javascript:` / `data:` `href` values, `expression()` styles, XML processing-instructions, external DTDs).
- **Admin Note** — internal-only note on posts/pages, edited from a sidebar Document panel and shown as a yellow banner above the first block. Never rendered on the front-end.
- **Disable Comments** — strips every form of comment functionality site-wide. Removes post-type support, forces `comments_open` / `pings_open` / submission handlers closed, hides admin chrome, suppresses notification + moderation emails, dequeues `comment-reply.js`.
- **Sticky Elements** — make any element on the page stick on scroll. Per-element top offset, margin-bottom, z-index, push-up target, mobile-disable + breakpoint.
- **Admin Columns** — per-post-type custom columns on `edit.php`: featured image (with click-to-change AJAX media picker), taxonomy columns, sortable meta-key columns (scanned from `wp_postmeta`).
- **Admin Menu by Role** — per-role checklist for hiding top-level wp-admin sidebar items. Useful for handing a clean dashboard to client editors. Recovery constant `BW_DEV_ADMIN_MENU_ROLE_DISABLE` in wp-config.php for lockouts.
- **Dashboard** — checkboxes to remove default WP widgets (WP News, Quick Draft, At a Glance, Activity, Site Health, the "Welcome to WordPress" panel) + an optional pinned welcome widget with rich-text body + per-role visibility. **Auto-detects plugin-added widgets** (Yoast, Gravity Forms, etc.) for the same checklist treatment.
- **Scheduled Post Actions** — per-post one-shot trigger at a future datetime. Three actions: change post status, add taxonomy term(s), remove taxonomy term(s). Works with any public CPT + any taxonomy. Hourly recurring cron with an in-tab index of all upcoming/overdue actions.
- **Title Override** — per-post override of `<title>` separately from the post title.
- **Established Year** — `[bw_year_number]` / `[bw_year_word]` shortcodes for "Established YYYY" footers. Ports the standalone `established-year` plugin.

### Front-end

- **Favicon** — injects a custom favicon at priority 9999 on the front-end, admin, and login head — overriding theme defaults (notably Kadence). Also suppresses WP core's `wp_site_icon` when set, so the two don't compete.
- **Maintenance Mode** — three modes (Coming Soon HTTP 200 / Under Construction HTTP 200 / Maintenance HTTP 503 + `Retry-After`) with configurable heading, message, logo, three colours. Bypass for admins + configured roles + a shareable `?bw_preview=TOKEN` link.
- **Menu Visibility** — per-menu-item role/login visibility controls. Adds a "Visibility (BW Dev)" select on every menu item in Appearance → Menus.
- **Sidebars** — register custom widget areas (slug + name + description), unregister theme/plugin sidebars you don't want, render any sidebar anywhere via the `[bw_dev_sidebar slug="..."]` shortcode.

### Security

- **Hide Login URL** — moves wp-login.php to a custom slug; 404s the canonical `/wp-login.php` and `/wp-admin/` for guests. Recovery via `BW_DEV_HIDE_LOGIN_DISABLE`.
- **Login Redirects** — per-role landing-page redirect after a successful login. Hooks the `login_redirect` filter.
- **Security Hardening** — five independent toggles: block user enumeration (`/?author=N` + `/wp-json/wp/v2/users`), disable XML-RPC, disable file editing (defines `DISALLOW_FILE_EDIT`), strip WP version fingerprints, disable Application Passwords. All default ON.
- **Login Activity Log** — records every successful + failed login attempt to a dedicated `{prefix}bw_dev_login_log` table with Cloudflare-aware IP detection, daily prune cron, configurable retention + row cap, settings-tab table of the most recent 50 entries.

### Indexing

- **Robots.txt Manager** — edit `robots.txt` from the admin without touching the filesystem.
- **LLMs.txt Generator** — produces `llms.txt` + `llms-full.txt` at the site root for AI crawlers.
- **Site Knowledge** — exports `knowledge.json`, a structured snapshot of the entire site (identity, navigation tree, post-type contents with SEO meta auto-detected from Yoast / Rank Math / SEOPress / AIOSEO, taxonomy trees, optional developer block with server/PHP/WP/DB/themes/plugins). Designed to drop into Claude Code or any other AI tool as full site context.

### Blocks

- **YouTube Block** — dynamic Gutenberg block `bw-dev/youtube` pulling the URL from an ACF field, with featured-image fallback. Per-block ACF-field override.
- **Post Link Block** — two server-rendered blocks (parent list + child item) with Simple and Thumbnail layouts.
- **Subtitle Block** — eyebrow / kicker text with configurable color + URL.
- **Separator Block** — Unicode glyph + custom-SVG separators with configurable color.

### Vendors

- **Plugins** — status / install / activate UI for the recommended third-party stack (Kadence Blocks, Kadence Blocks Pro, ACF PRO, WebP Express, Yoast SEO, Redirection, Gravity Forms, Better Search Replace, Customizer Export/Import, Post Types Order).
- **Theme** — audit installed themes against the BW-ideal Kadence parent + child setup.

## White-label

The Branding tab controls three client-facing strings:

- **Plugin display name** — what shows in the WP plugins list and as the Settings submenu label.
- **Block category label** — the Gutenberg category that groups all bw-dev blocks in the inserter.
- **Block title prefix** — prepended to every bw-dev block title (e.g. `BW YouTube Embed` → `Acme YouTube Embed`).

The block category slug (`bw-dev-blocks`) is stable — only the label changes — so saved post content survives any rebrand. Block-level rewrites happen client-side at the `blocks.registerBlockType` filter; nothing is persisted to saved markup.

The `bw_dev_brand` PHP filter lets mu-plugins force a brand without persisting it to options.

## Migration from the legacy plugins

BW Dev replaces multiple legacy plugins. On activation it reads their options (`bw_favicon_url`, `bw_sticky_settings`, `bw_youtube_embed_settings`, `bw_admin_column_settings`, `bw_admin_note_settings`, `bw_established_date`) and copies them into the unified `bw_dev_settings` schema. The migration is idempotent and conservative — it only fills in module keys that aren't already populated.

The legacy plugins are **not auto-deactivated**. After verifying each module, deactivate the corresponding source plugin manually.

For sites with custom CSS or saved post content referencing the legacy class names / block names, see `docs/KNOWN-ISSUES.md` for the rewrites you'll need to perform.

## Updates + distribution

- **Source of truth**: this `bw-dev/` directory in the `bw-plugins` development repo.
- **Distribution host**: `plugins.bowden.works` (a separate WordPress install running `bw-update-server`).
- **Update mechanism**: WordPress checks `https://plugins.bowden.works/wp-json/bw/v1/update-check?slug=bw-dev` via the bundled `plugin-update-checker` library.
- No WP.org involvement.

## License

GPL-2.0-or-later. See `LICENSE`.
