From 3e779343b2a40bc6eaeee010a53fe19a4ce3a276 Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Sat, 25 Oct 2025 16:55:22 -0500 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8feature:=20Initial=20commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + README.md | 67 +++++++++ plugins.json | 27 ++++ windows/README-Windows.md | 67 +++++++++ windows/bootstrap.bat | 4 + windows/wp-bootstrap.ps1 | 169 +++++++++++++++++++++++ wp-bootstrap.sh | 284 ++++++++++++++++++++++++++++++++++++++ wp-bootstraprc.example | 21 +++ 8 files changed, 642 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 plugins.json create mode 100644 windows/README-Windows.md create mode 100644 windows/bootstrap.bat create mode 100644 windows/wp-bootstrap.ps1 create mode 100644 wp-bootstrap.sh create mode 100644 wp-bootstraprc.example diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5491676 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.vscode/ +notes +.wp-bootstraprc diff --git a/README.md b/README.md new file mode 100644 index 0000000..ccc7cf1 --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# Easy WordPress Bootstrap + +Easily set up a new WordPress dev environment utilizing Laravel Herd and DBngin (or other MySQL/MariaDB solutions). + +One command to spin up a new WordPress project locally: + +- Creates a project folder in your Herd workspace +- Provisions MySQL DB + user via DBngin or other MySQL/MariaDB solution. +- Generates wp-config.php with salts +- Installs WP and sets default options (Home/News, other useful pages, permalinks) +- Installs/activates plugins from `plugins.json` +- Clones theme starter (with fresh history), activates it, and initializes a clean repo + +## Prerequisites + +- macOS or Windows +- Herd installed and a workspace directory (default: `~/Herd`) +- DBngin or other MySQL/MariaDB server +- CLI tools in PATH: `wp`, `git`, `curl`, `openssl`, `mysql`, and optionally `jq` + +## Quick Start + +1. Copy `wp-bootstraprc.example` to `~/.wp-bootstraprc` and edit values (one-time setup): + + ```bash + cp wp-bootstraprc.example ~/.wp-bootstraprc + ``` + +2. (Optional) Edit `plugins.json`. + +3. Run the bootstrap: + + ```bash + chmod +x wp-bootstrap.sh + ./wp-bootstrap.sh + ``` + +4. Answer prompts. When finished, the script prints a summary and writes `bootstrap-summary.txt`. + +## Configuration + +- **Herd workspace**: set `HERD_WORKSPACE` in `~/.wp-bootstraprc`. +- **Local TLD**: set `LOCAL_TLD` (`test` by default). +- **DBngin**: set `MYSQL_HOST`, `MYSQL_PORT`, `MYSQL_ROOT_USER`, `MYSQL_ROOT_PASS`. +- **Theme starter**: set `THEME_STARTER_REPO`. The script clones shallow, removes `.git`, then re-initializes the theme repo. +- **Theme remote**: set `DEFAULT_THEME_REMOTE_ORIGIN` if you want the script to push the new theme repo automatically. + +## Plugins + +Baseline plugins are defined in `plugins.json`. Each entry accepts either a WordPress.org **slug** or a direct **zip** URL. + +> Premium/private zips: use signed/internal URLs or manually download and point to a local `/tmp/file.zip` (adjust the script to `wp plugin install /tmp/file.zip`). + +## Notes + +- The script sets friendly permalinks (`/%postname%/`) and creates Home/News pages by default. +- Sample content is removed if present. +- A plugin install log is written to `wp-content/plugin-bootstrap.log`. + +## Troubleshooting + +- If `wp` is not found, ensure WP-CLI is installed and available in `PATH`. +- If MySQL connection fails, confirm DBngin is running and credentials are correct in `~/.wp-bootstraprc`. +- On Windows, prefer WSL or Git Bash for best results. + +-- +DIY-first policy: keep `plugins.json` minimal. Add big off-the-shelf stacks (e.g., ecomm) only when warranted. diff --git a/plugins.json b/plugins.json new file mode 100644 index 0000000..01feab3 --- /dev/null +++ b/plugins.json @@ -0,0 +1,27 @@ +[ + { + "zip": "https://docs.vincentdevelopment.ca/files/advanced-custom-fields-pro.zip", + "activate": true + }, + { + "zip": "https://docs.vincentdevelopment.ca/files/gravity-forms.zip", + "activate": true + }, + + { + "slug": "autodescription", + "activate": true + }, + { + "slug": "better-search-replace", + "activate": true + }, + { + "slug": "google-site-kit", + "activate": false + }, + { + "slug": "simple-history", + "activate": true + } +] diff --git a/windows/README-Windows.md b/windows/README-Windows.md new file mode 100644 index 0000000..57a0791 --- /dev/null +++ b/windows/README-Windows.md @@ -0,0 +1,67 @@ +# Easy WordPress Bootstrap (Herd + DBngin) — Windows Edition + +This kit lets Windows devs spin up a new local WordPress project using **PowerShell only**. + +## Includes + +- `wp-bootstrap.ps1` — main PowerShell script +- `bootstrap.bat` — one-click launcher +- `plugins.json` — minimal default plugin list (use file from repo root) + +## Prerequisites + +- **PHP** installed and in PATH +- **MySQL client** (`mysql.exe`) in PATH (DBngin/MySQL installed and running) +- **Git** installed (for cloning the starter theme) +- **WP-CLI**: either installed globally as `wp`, **or** put `wp-cli.phar` next to this script and call with: + - `-WpCliPath "php .\wp-cli.phar"` + +## Quick Start + +1. Right-click **PowerShell** → *Run as Administrator* (first run only): + + ```powershell + Set-ExecutionPolicy RemoteSigned -Scope CurrentUser + ``` + +2. Open a normal PowerShell in this folder and run: + + ```powershell + .\wp-bootstrap.ps1 -ProjectName "Client Site" + ``` + + or double-click `bootstrap.bat` and enter the project name when prompted. + +### Optional parameters + +- `-AdminUser` (default: `vdidev`) +- `-AdminEmail` (default: `dev@vincentdesign.ca`) +- `-ThemeStarterRepo` (default: VDI starter theme) +- `-HerdWorkspace` (default: `"$HOME\Herd"`) +- `-LocalTld` (default: `test`) +- `-MysqlHost` / `-MysqlPort` / `-MysqlRootUser` / `-MysqlRootPass` +- `-WpCliPath` (set to `"php .\wp-cli.phar"` if not installed globally) + +## What it does + +- Creates project folder under your Herd workspace +- Downloads WordPress core +- Creates database + user with random password +- Generates `wp-config.php`, shuffles salts +- Installs WordPress and sets the site/home URLs +- Creates **Home** and **News** pages, sets **front page**/**posts page** +- Sets permalinks to `/%postname%/` and flushes +- Clones the starter theme, strips history, re-initializes a clean repo, and activates it +- Installs and (optionally) activates plugins from `plugins.json` +- Prints and saves a summary (`bootstrap-summary.txt`) + +## Troubleshooting + +- **WP-CLI not found**: pass `-WpCliPath "php .\wp-cli.phar"` (place `wp-cli.phar` beside this script). +- **MySQL not found**: ensure `mysql.exe` is in PATH. With DBngin, add the MySQL bin folder to PATH. +- **Access denied creating DB**: verify `-MysqlRootUser`/`-MysqlRootPass`, or create a dev-only MySQL user with `CREATE` privileges. +- **Herd not serving**: Add/link the folder in Herd and browse to `http://.test` (or your chosen TLD). + +## Philosophy + +DIY-first: keep `plugins.json` minimal. Only add big off‑the‑shelf stacks (e.g., ecomm) when warranted. diff --git a/windows/bootstrap.bat b/windows/bootstrap.bat new file mode 100644 index 0000000..e19984e --- /dev/null +++ b/windows/bootstrap.bat @@ -0,0 +1,4 @@ +@echo off +REM One-click launcher for the Windows PowerShell bootstrap. +REM Usage: bootstrap "Client Site Name" +PowerShell -ExecutionPolicy Bypass -File "%~dp0wp-bootstrap.ps1" -ProjectName "%*" diff --git a/windows/wp-bootstrap.ps1 b/windows/wp-bootstrap.ps1 new file mode 100644 index 0000000..3993bb1 --- /dev/null +++ b/windows/wp-bootstrap.ps1 @@ -0,0 +1,169 @@ + +Param( + [Parameter(Mandatory=$true)][string]$ProjectName, + [string]$AdminUser = "vdidev", + [string]$AdminEmail = "dev@vincentdesign.ca", + [string]$ThemeStarterRepo = "https://github.com/vincent-design-inc/starter-theme-3.git", + [string]$HerdWorkspace = "$HOME\Herd", + [string]$LocalTld = "test", + [string]$MysqlHost = "127.0.0.1", + [string]$MysqlPort = "3306", + [string]$MysqlRootUser = "root", + [string]$MysqlRootPass = "", + # If WP-CLI isn't globally installed, set this to 'php .\wp-cli.phar' + [string]$WpCliPath = "wp" +) + +function Slugify([string]$s) { ($s.ToLower() -replace '[^a-z0-9]+','-').Trim('-') } + +function RandPass() { + $bytes = New-Object 'System.Byte[]' 18 + (New-Object System.Security.Cryptography.RNGCryptoServiceProvider).GetBytes($bytes) + [Convert]::ToBase64String($bytes) -replace '[^a-zA-Z0-9]','' | ForEach-Object { $_.Substring(0,24) } +} + +function Invoke-WP { + param([string[]]$Args) + # Support 'wp' OR 'php .\wp-cli.phar' + if ($WpCliPath -match '\s') { + $parts = $WpCliPath -split '\s+' + & $parts[0] $parts[1..($parts.Count-1)] $Args 2>&1 | ForEach-Object { "$_" } + } else { + & $WpCliPath $Args 2>&1 | ForEach-Object { "$_" } + } + if ($LASTEXITCODE -ne 0) { throw "WP-CLI command failed: $($Args -join ' ')" } +} + +function WP([string]$line) { + # Convenience to pass a single-line string; splits on spaces + $args = @() + $token = "" + $inQuote = $false + foreach ($c in $line.ToCharArray()) { + if ($c -eq '"') { $inQuote = -not $inQuote; continue } + if (-not $inQuote -and [char]::IsWhiteSpace($c)) { + if ($token.Length -gt 0) { $args += $token; $token = "" } + } else { $token += $c } + } + if ($token.Length -gt 0) { $args += $token } + Invoke-WP $args +} + +# === Start === +$Slug = Slugify $ProjectName +$ProjectDir = Join-Path $HerdWorkspace $Slug +$LocalUrl = "http://$Slug.$LocalTld" + +$DbName = "vdi_$Slug" +$DbUser = $DbName +$DbPass = RandPass +$AdminPass = RandPass + +Write-Host "Creating project at $ProjectDir..." +New-Item -ItemType Directory -Force -Path $ProjectDir | Out-Null +Set-Location $ProjectDir + +# --- WordPress Core --- +Write-Host "Downloading WordPress..." +Invoke-WP @("core","download","--force") + +# --- Database setup --- +Write-Host "Creating MySQL DB and user..." +$mysqlArgs = @("-h", $MysqlHost, "-P", $MysqlPort, "-u", $MysqlRootUser) +if ($MysqlRootPass -ne "") { $mysqlArgs += "-p$MysqlRootPass" } +$sql = @" +CREATE DATABASE IF NOT EXISTS `$DbName` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; +CREATE USER IF NOT EXISTS '$DbUser'@'%' IDENTIFIED BY '$DbPass'; +GRANT ALL PRIVILEGES ON `$DbName`.* TO '$DbUser'@'%'; +FLUSH PRIVILEGES; +"@ +try { + $sql | & mysql.exe @mysqlArgs +} catch { + throw "MySQL client not found or connection failed. Ensure mysql.exe is in PATH and DBngin/MySQL is running." +} + +# --- Config + Install --- +Invoke-WP @("config","create","--dbname=$DbName","--dbuser=$DbUser","--dbpass=$DbPass","--dbhost=$MysqlHost`:$MysqlPort","--force") +Invoke-WP @("config","shuffle-salts") +Invoke-WP @("core","install","--url=$LocalUrl","--title=$ProjectName","--admin_user=$AdminUser","--admin_password=$AdminPass","--admin_email=$AdminEmail") +Invoke-WP @("option","update","siteurl",$LocalUrl) +Invoke-WP @("option","update","home",$LocalUrl) + +# --- Pages & Reading --- +Write-Host "Creating Home/News pages and setting permalinks..." +$homeId = (Invoke-WP @("post","create","--post_type=page","--post_status=publish","--post_title=Home","--porcelain") | Select-Object -Last 1).Trim() +$newsId = (Invoke-WP @("post","create","--post_type=page","--post_status=publish","--post_title=News","--porcelain") | Select-Object -Last 1).Trim() +Invoke-WP @("option","update","show_on_front","page") +Invoke-WP @("option","update","page_on_front",$homeId) +Invoke-WP @("option","update","page_for_posts",$newsId) +Invoke-WP @("rewrite","structure","/%postname%/") +Invoke-WP @("rewrite","flush","--hard") + +# --- Theme --- +Write-Host "Cloning starter theme..." +$tmp = ".starter-tmp" +if (Test-Path $tmp) { Remove-Item -Recurse -Force $tmp } +git clone --depth=1 $ThemeStarterRepo $tmp | Out-Null + +$ThemeDir = "wp-content\themes\$Slug-theme" +if (Test-Path $ThemeDir) { Remove-Item -Recurse -Force $ThemeDir } +New-Item -ItemType Directory -Force -Path (Split-Path $ThemeDir) | Out-Null +Move-Item $tmp $ThemeDir +if (Test-Path "$ThemeDir\.git") { Remove-Item -Recurse -Force "$ThemeDir\.git" } + +Invoke-WP @("theme","activate","$Slug-theme") + +Push-Location $ThemeDir +git init -b main | Out-Null +git add -A +git commit -m "feat: bootstrap ${ProjectName} theme from starter" | Out-Null +Pop-Location + +# --- Plugins --- +if (Test-Path "plugins.json") { + try { + $plugins = Get-Content "plugins.json" | ConvertFrom-Json + foreach ($plugin in $plugins) { + if ($plugin.zip) { + $args = @("plugin","install",$plugin.zip,"--force") + if ($plugin.activate -eq $true) { $args += "--activate" } + Invoke-WP $args + } elseif ($plugin.slug) { + $args = @("plugin","install",$plugin.slug,"--force") + if ($plugin.version) { $args += "--version=$($plugin.version)" } + if ($plugin.activate -eq $true) { $args += "--activate" } + Invoke-WP $args + } + } + } catch { + Write-Host "Error reading plugins.json: $_" + } +} + +# --- Summary --- +$Summary = @" +VDI WP Bootstrap — Summary +=========================== + +Project: $ProjectName +Slug: $Slug +Folder: $ProjectDir +Local URL: $LocalUrl + +DB Host: $MysqlHost +DB Port: $MysqlPort +DB Name: $DbName +DB User: $DbUser +DB Pass: $DbPass + +WP Admin User: $AdminUser +WP Admin Pass: $AdminPass +WP Admin Email: $AdminEmail + +Theme Dir: $ThemeDir +"@ +$SummaryFile = Join-Path $ProjectDir "bootstrap-summary.txt" +$Summary | Out-File -FilePath $SummaryFile -Encoding utf8 +Write-Host $Summary +Write-Host "Saved summary to $SummaryFile" diff --git a/wp-bootstrap.sh b/wp-bootstrap.sh new file mode 100644 index 0000000..7c8b651 --- /dev/null +++ b/wp-bootstrap.sh @@ -0,0 +1,284 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Load machine/user defaults +if [[ -f "$HOME/.vdi-wp-bootstraprc" ]]; then + # shellcheck disable=SC1090 + source "$HOME/.vdi-wp-bootstraprc" +fi + +# Sensible fallbacks if config missing +HERD_WORKSPACE="${HERD_WORKSPACE:-$HOME/Herd}" +MYSQL_HOST="${MYSQL_HOST:-127.0.0.1}" +MYSQL_PORT="${MYSQL_PORT:-3306}" +MYSQL_ROOT_USER="${MYSQL_ROOT_USER:-root}" +MYSQL_ROOT_PASS="${MYSQL_ROOT_PASS:-}" +DEFAULT_ADMIN_EMAIL="${DEFAULT_ADMIN_EMAIL:-dev@vincentdesign.ca}" +DEFAULT_ADMIN_USER="${DEFAULT_ADMIN_USER:-vdidev}" +THEME_STARTER_REPO="${THEME_STARTER_REPO:-https://github.com/WordPress/twentytwentyfour.git}" +DEFAULT_THEME_REMOTE_ORIGIN="${DEFAULT_THEME_REMOTE_ORIGIN:-}" +LOCAL_TLD="${LOCAL_TLD:-test}" + +require() { + command -v "$1" >/dev/null 2>&1 || { echo "Missing dependency: $1"; exit 1; } +} + +for bin in wp git curl openssl mysql; do + require "$bin" +done + +slugify() { + # lower, spaces->-, strip non [a-z0-9-] + echo "$1" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g;s/^-+|-+$//g' +} + +randpass() { + # 24 char base64, strip non-url-safe chars + openssl rand -base64 24 | tr -d '\n' | tr -d '=/+' | cut -c1-24 +} + +prompt() { + local q def ans + q="$1"; def="${2:-}" + if [[ -n "$def" ]]; then + read -r -p "$q [$def]: " ans || true + echo "${ans:-$def}" + else + read -r -p "$q: " ans || true + echo "$ans" + fi +} + +setup_pages_and_reading() { + echo "Setting up default pages and reading options…" + + HOME_ID=$(wp post list --post_type=page --name='home' --field=ID --format=ids) + if [[ -z "$HOME_ID" ]]; then + HOME_ID=$(wp post create --post_type=page --post_status=publish --post_title="Home" --porcelain) + fi + + NEWS_ID=$(wp post list --post_type=page --name='news' --field=ID --format=ids) + if [[ -z "$NEWS_ID" ]]; then + NEWS_ID=$(wp post create --post_type=page --post_status=publish --post_title="News" --porcelain) + fi + + for TITLE in "Page Not Found (Error 404)" "Contact Us"; do + SLUG="$(echo "$TITLE" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g;s/^-+|-+$//g')" + ID=$(wp post list --post_type=page --name="$SLUG" --field=ID --format=ids) + [[ -z "$ID" ]] && wp post create --post_type=page --post_status=publish --post_title="$TITLE" --porcelain >/dev/null + done + + wp option update show_on_front 'page' + wp option update page_on_front "$HOME_ID" + wp option update page_for_posts "$NEWS_ID" + + wp post delete 1 --force >/dev/null 2>&1 || true + wp post delete 2 --force >/dev/null 2>&1 || true + + wp rewrite structure '/%postname%/' + wp rewrite flush --hard + echo "Default pages and reading options configured." +} + +install_and_activate_plugins() { + local LOG="wp-content/plugin-bootstrap.log" + echo "=== $(date -u '+%F %T') :: Plugin bootstrap start ===" | tee -a "$LOG" + + if [[ -f "plugins.json" ]]; then + if command -v jq >/dev/null 2>&1; then + jq -c '.[]' plugins.json | while read -r item; do + ZIP=$(echo "$item" | jq -r '.zip // empty') + SLUG=$(echo "$item" | jq -r '.slug // empty') + VER=$(echo "$item" | jq -r '.version // empty') + ACT=$(echo "$item" | jq -r '.activate // false') + + if [[ -n "$ZIP" ]]; then + echo "Installing from zip: $ZIP" | tee -a "$LOG" + if wp plugin install "$ZIP" --force $( [[ "$ACT" == "true" ]] && echo --activate ); then + echo "OK zip: $ZIP (activate=$ACT)" | tee -a "$LOG" + else + echo "FAIL zip: $ZIP" | tee -a "$LOG" + fi + elif [[ -n "$SLUG" ]]; then + ARGS=(plugin install "$SLUG" --force) + [[ -n "$VER" ]] && ARGS+=("--version=$VER") + [[ "$ACT" == "true" ]] && ARGS+=("--activate") + echo "Installing slug: $SLUG ${VER:+(v$VER)}" | tee -a "$LOG" + if wp "${ARGS[@]}"; then + echo "OK slug: $SLUG (activate=$ACT)" | tee -a "$LOG" + else + echo "FAIL slug: $SLUG" | tee -a "$LOG" + fi + else + echo "SKIP item with no slug/zip: $item" | tee -a "$LOG" + fi + done + else + echo "plugins.json found but jq is not installed; skipping plugin install." | tee -a "$LOG" + fi + else + echo "No plugins.json present; skipping plugin install." | tee -a "$LOG" + fi + + echo "=== $(date -u '+%F %T') :: Plugin bootstrap end ===" | tee -a "$LOG" +} + +echo "— VDI WP Bootstrap (Herd + DBngin) —" +PROJECT_NAME="$(prompt 'Project name (Human-readable)')" +[[ -z "$PROJECT_NAME" ]] && { echo "Project name is required."; exit 1; } + +PROJECT_SLUG="$(slugify "$PROJECT_NAME")" +FOLDER_NAME="$PROJECT_SLUG" +PROJECT_DIR="$HERD_WORKSPACE/$FOLDER_NAME" +LOCAL_URL="http://$PROJECT_SLUG.$LOCAL_TLD" + +echo "Derived:" +echo " slug: $PROJECT_SLUG" +echo " path: $PROJECT_DIR" +echo " local URL: $LOCAL_URL" +echo + +ADMIN_USER="$(prompt 'Admin username' "$DEFAULT_ADMIN_USER")" +ADMIN_EMAIL="$(prompt 'Admin email' "$DEFAULT_ADMIN_EMAIL")" +ADMIN_PASS="$(randpass)" + +DB_NAME="vdi_${PROJECT_SLUG}" +DB_USER="$DB_NAME" +DB_PASS="$(randpass)" + +THEME_REPO_URL="$(prompt 'Theme starter repo URL' "$THEME_STARTER_REPO")" +THEME_DIR="wp-content/themes/${PROJECT_SLUG}-theme" +THEME_REMOTE_ORIGIN="$(prompt 'New theme repo remote (origin) URL (leave blank to skip push)' "$DEFAULT_THEME_REMOTE_ORIGIN")" + +echo +echo "Creating project directory…" +mkdir -p "$PROJECT_DIR" +cd "$PROJECT_DIR" + +echo "Downloading WordPress core…" +wp core download --force + +echo "Creating database and user in MySQL ($MYSQL_HOST:$MYSQL_PORT)…" +MYSQL_AUTH=(-h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_ROOT_USER") +if [[ -n "$MYSQL_ROOT_PASS" ]]; then + MYSQL_AUTH+=(-p"$MYSQL_ROOT_PASS") +fi + +mysql "${MYSQL_AUTH[@]}" </dev/null 2>&1; then + echo "Salt keys shuffled." +else + echo "Fetching salts from api.wordpress.org…" + SALTS="$(curl -fsSL https://api.wordpress.org/secret-key/1.1/salt/)" + wp config set AUTH_KEY "dummy" --type=constant --raw >/dev/null 2>&1 || true + php -r 'file_put_contents("wp-config.php", preg_replace("/\\?>\\s*$/","",file_get_contents("wp-config.php"))."\n".'"'"$SALTS"'"'."\n");' +fi + +echo "Installing WordPress…" +wp core install \ + --url="$LOCAL_URL" \ + --title="$PROJECT_NAME" \ + --admin_user="$ADMIN_USER" \ + --admin_password="$ADMIN_PASS" \ + --admin_email="$ADMIN_EMAIL" + +wp option update siteurl "$LOCAL_URL" +wp option update home "$LOCAL_URL" + +setup_pages_and_reading + +echo "Cloning theme starter (history will be stripped)…" +TMP_DIR=".starter-tmp" +rm -rf "$TMP_DIR" +git clone --depth=1 "$THEME_REPO_URL" "$TMP_DIR" + +mkdir -p "$(dirname "$THEME_DIR")" +rm -rf "$THEME_DIR" +mv "$TMP_DIR" "$THEME_DIR" +rm -rf "$THEME_DIR/.git" + +if [[ -f "$THEME_DIR/style.css" ]]; then + sed -i.bak "s/Theme Name:.*/Theme Name: ${PROJECT_NAME}/" "$THEME_DIR/style.css" || true + sed -i.bak "s/Text Domain:.*/Text Domain: ${PROJECT_SLUG}-theme/" "$THEME_DIR/style.css" || true + rm -f "$THEME_DIR/style.css.bak" +fi + +echo "Activating theme…" +wp theme activate "${PROJECT_SLUG}-theme" || { + echo "Activation failed (maybe theme slug mismatch). Listing themes:" + wp theme list +} + +install_and_activate_plugins + +echo "Initializing theme repo…" +pushd "$THEME_DIR" >/dev/null +git init -b main +git add -A +git commit -m "feat: bootstrap ${PROJECT_NAME} theme from starter" +if [[ -n "$THEME_REMOTE_ORIGIN" ]]; then + git remote add origin "$THEME_REMOTE_ORIGIN" + git push -u origin main +fi +popd >/dev/null + +create_wpengine_staging() { + if [[ -z "${WPE_API_TOKEN:-}" ]]; then + echo "WPE_API_TOKEN not set; skipping staging creation." + return + fi + echo "Stub: Add WPE API call here to create staging for ${PROJECT_SLUG}." +} +create_wpengine_staging + +SUMMARY_FILE="$PROJECT_DIR/bootstrap-summary.txt" +cat > "$SUMMARY_FILE" <} + +Log files: +- Plugin install log: wp-content/plugin-bootstrap.log + +Next steps: +- If Herd doesn’t auto-serve the folder, link it via Herd UI/CLI and open $LOCAL_URL +- Remove legacy activation.php from the starter theme if present (now handled by bootstrap) +- Wire CI/CD as needed (never push DB to production) +TXT + +echo +echo "✅ Bootstrap complete." +echo "Summary saved to: $SUMMARY_FILE" +echo +cat "$SUMMARY_FILE" diff --git a/wp-bootstraprc.example b/wp-bootstraprc.example new file mode 100644 index 0000000..836224b --- /dev/null +++ b/wp-bootstraprc.example @@ -0,0 +1,21 @@ +# Herd workspace (adjust if yours differs) +HERD_WORKSPACE="$HOME/Herd" # e.g., "$HOME/Sites" or "$HOME/Projects" + +# DBngin/MySQL connection +MYSQL_HOST="127.0.0.1" +MYSQL_PORT="3306" +MYSQL_ROOT_USER="root" +MYSQL_ROOT_PASS="" + +# Defaults for project bootstrap +DEFAULT_ADMIN_EMAIL="dev@vincentdesign.ca" +DEFAULT_ADMIN_USER="vdidev" + +# Theme starter (public or private – ensure your git auth is set up for private repos) +THEME_STARTER_REPO="https://github.com/vincent-design-inc/starter-theme-3.git" + +# Optional: default remote you often use for new theme repos (leave blank to skip pushing) +DEFAULT_THEME_REMOTE_ORIGIN="" + +# Default local domain suffix used by Herd/Valet +LOCAL_TLD="test"