diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ec617c6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,19 @@ +.git +.gitea +.github +.vscode +.claude +.idea +node_modules +vendor +releases +wp-core +wc-core +CLAUDE.md +PLAN.md +SETUP.md +*.log +*.bak +*.po~ +.DS_Store +Thumbs.db diff --git a/.gitignore b/.gitignore index 524b708..b9d8a2c 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ npm-debug.log # Build artifacts (releases directory) releases/ + +# Docker runtime +.env diff --git a/CHANGELOG.md b/CHANGELOG.md index eaa8834..c0b6cbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ All notable changes to this project will be documented in this file. - Theme wrapping signal via `woocommerce_is_theme_wrapped` filter - CI/CD release workflow (Gitea Actions) - Translation support (`.pot` template ready) +- Docker development environment (multistage Dockerfile, Compose, auto-setup entrypoint) ### Skipped diff --git a/README.md b/README.md index 94bd104..62bc30a 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,13 @@ wc-bootstrap/ │ ├── notices/ │ ├── order/ │ └── single-product/ +├── docker/ +│ ├── Dockerfile # Multistage build (WC download, npm, composer, WP) +│ ├── entrypoint.sh # Auto-setup wrapper entrypoint +│ ├── setup.sh # First-run WP install + plugin/theme activation +│ └── .env-dist # Environment variable template +├── compose.yaml # WordPress + MariaDB services +├── compose.override.yaml # Dev overrides (bind mounts, debug flags) ├── composer.json ├── functions.php └── style.css @@ -95,6 +102,29 @@ WooCommerce wc_get_template("cart/cart.php") → Result: Bootstrap 5 Twig output only ``` +### Docker Environment + +```bash +# Copy and adjust environment variables (optional) +cp docker/.env-dist .env + +# Build and start +docker compose build +docker compose up -d + +# WordPress installs automatically on first boot (admin/admin) +# → http://localhost:8080 +# → http://localhost:8080/wp-admin/ + +# Manual setup (if WP_AUTO_SETUP=0) +docker compose exec wordpress setup.sh + +# Tear down +docker compose down -v +``` + +The image preinstalls WooCommerce and wp-bootstrap. The override bind-mounts both themes for live development. + ### Building Translations ```bash diff --git a/compose.override.yaml b/compose.override.yaml new file mode 100644 index 0000000..a42f06f --- /dev/null +++ b/compose.override.yaml @@ -0,0 +1,15 @@ +services: + db: + container_name: woocommerce-db + + wordpress: + container_name: woocommerce + volumes: + - ../wp-bootstrap:/var/www/html/wp-content/themes/wp-bootstrap + - .:/var/www/html/wp-content/themes/wc-bootstrap + environment: + WORDPRESS_DEBUG: "1" + WORDPRESS_CONFIG_EXTRA: | + define('WP_DEBUG_LOG', true); + define('WP_DEBUG_DISPLAY', true); + define('SCRIPT_DEBUG', true); diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..74e8c8f --- /dev/null +++ b/compose.yaml @@ -0,0 +1,45 @@ +services: + db: + image: mariadb:11 + volumes: + - db_data:/var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpass} + MYSQL_DATABASE: ${MYSQL_DATABASE:-wordpress} + MYSQL_USER: ${MYSQL_USER:-wordpress} + MYSQL_PASSWORD: ${MYSQL_PASSWORD:-wordpress} + healthcheck: + test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] + interval: 10s + timeout: 5s + retries: 5 + + wordpress: + build: + context: . + dockerfile: docker/Dockerfile + additional_contexts: + wp-bootstrap: ../wp-bootstrap + target: wp_runtime + ports: + - "${WP_PORT:-8080}:80" + environment: + WORDPRESS_DB_HOST: db + WORDPRESS_DB_NAME: ${MYSQL_DATABASE:-wordpress} + WORDPRESS_DB_USER: ${MYSQL_USER:-wordpress} + WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD:-wordpress} + WP_AUTO_SETUP: ${WP_AUTO_SETUP:-1} + WP_URL: ${WP_URL:-http://localhost:${WP_PORT:-8080}} + WP_TITLE: ${WP_TITLE:-WC Bootstrap Dev} + WP_ADMIN_USER: ${WP_ADMIN_USER:-admin} + WP_ADMIN_PASSWORD: ${WP_ADMIN_PASSWORD:-admin} + WP_ADMIN_EMAIL: ${WP_ADMIN_EMAIL:-admin@example.com} + depends_on: + db: + condition: service_healthy + volumes: + - wp_data:/var/www/html + +volumes: + db_data: + wp_data: diff --git a/docker/.env-dist b/docker/.env-dist new file mode 100644 index 0000000..eb70ec3 --- /dev/null +++ b/docker/.env-dist @@ -0,0 +1,19 @@ +# Database +MYSQL_ROOT_PASSWORD=rootpass +MYSQL_DATABASE=wordpress +MYSQL_USER=wordpress +MYSQL_PASSWORD=wordpress + +# WordPress +WP_PORT=8080 + +# Auto-setup (runs on first boot, set to 0 to disable) +WP_AUTO_SETUP=1 +WP_URL=http://localhost:8080 +WP_TITLE=WC Bootstrap Dev +WP_ADMIN_USER=admin +WP_ADMIN_PASSWORD=admin +WP_ADMIN_EMAIL=admin@example.com + +# Build args (used during `docker compose build`) +# WOOCOMMERCE_VERSION=latest diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..414cba0 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,70 @@ +############################################################################### +# Stage 1 — Download WooCommerce from WordPress.org +############################################################################### +FROM alpine:3.21 AS woocommerce + +RUN apk add --no-cache curl unzip jq + +ARG WOOCOMMERCE_VERSION=latest +RUN set -ex; \ + if [ "$WOOCOMMERCE_VERSION" = "latest" ]; then \ + URL=$(curl -sSf "https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&slug=woocommerce" \ + | jq -r '.download_link'); \ + else \ + URL="https://downloads.wordpress.org/plugin/woocommerce.${WOOCOMMERCE_VERSION}.zip"; \ + fi; \ + curl -sSfL -o /tmp/woocommerce.zip "$URL"; \ + unzip -q /tmp/woocommerce.zip -d /tmp/plugins; \ + rm /tmp/woocommerce.zip + + +############################################################################### +# Stage 2 — Build wp-bootstrap theme assets +############################################################################### +FROM node:20-alpine AS wp-bootstrap-assets + +COPY --from=wp-bootstrap . /build +WORKDIR /build +RUN npm ci && npm run build \ + && rm -rf node_modules src .git .gitea .github .vscode .claude .idea \ + CLAUDE.md PLAN.md package.json package-lock.json .editorconfig \ + releases .gitignore + + +############################################################################### +# Stage 3 — Install Composer dependencies for both themes +############################################################################### +FROM composer:2 AS composer + +COPY --from=wp-bootstrap-assets /build /themes/wp-bootstrap +WORKDIR /themes/wp-bootstrap +RUN composer install --no-dev --optimize-autoloader --no-interaction + +COPY . /themes/wc-bootstrap +WORKDIR /themes/wc-bootstrap +RUN composer install --no-dev --optimize-autoloader --no-interaction + + +############################################################################### +# Stage 4 — Final WordPress image +############################################################################### +FROM wordpress:6.9.1-php8.4-apache AS wp_runtime + +RUN curl -sSfL -o /usr/local/bin/wp \ + https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar \ + && chmod +x /usr/local/bin/wp + +COPY --from=woocommerce /tmp/plugins/woocommerce \ + /var/www/html/wp-content/plugins/woocommerce + +COPY --from=composer /themes/wp-bootstrap \ + /var/www/html/wp-content/themes/wp-bootstrap + +COPY --from=composer /themes/wc-bootstrap \ + /var/www/html/wp-content/themes/wc-bootstrap + +COPY --link --chmod=0755 docker/setup.sh /usr/local/bin/setup.sh +COPY --link --chmod=0755 docker/entrypoint.sh /usr/local/bin/wc-entrypoint.sh + +ENTRYPOINT ["wc-entrypoint.sh"] +CMD ["apache2-foreground"] diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100644 index 0000000..8923d47 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Wrapper entrypoint: runs first-time WordPress setup in the background, +# then hands off to the official WordPress entrypoint. +# +# Set WP_AUTO_SETUP=0 to disable automatic setup. +# + +if [ "${WP_AUTO_SETUP:-1}" = "1" ]; then + ( + cd /var/www/html + until [ -f wp-config.php ]; do sleep 2; done + sleep 3 + + if ! wp core is-installed --allow-root 2>/dev/null; then + setup.sh + fi + ) & +fi + +exec docker-entrypoint.sh "$@" diff --git a/docker/setup.sh b/docker/setup.sh new file mode 100644 index 0000000..b40b9a9 --- /dev/null +++ b/docker/setup.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# +# First-run setup: installs WordPress, activates WooCommerce and wc-bootstrap. +# +# Usage: +# docker compose exec wordpress setup.sh +# +set -euo pipefail + +WP_URL="${WP_URL:-http://localhost:8080}" +WP_TITLE="${WP_TITLE:-WC Bootstrap Dev}" +WP_ADMIN_USER="${WP_ADMIN_USER:-admin}" +WP_ADMIN_PASSWORD="${WP_ADMIN_PASSWORD:-admin}" +WP_ADMIN_EMAIL="${WP_ADMIN_EMAIL:-admin@example.com}" + +cd /var/www/html + +# Wait for WordPress files (entrypoint copies them on first boot) +until [ -f wp-config.php ]; do + echo "Waiting for WordPress to initialize..." + sleep 2 +done + +if ! wp core is-installed --allow-root 2>/dev/null; then + echo "Installing WordPress..." + wp core install \ + --url="$WP_URL" \ + --title="$WP_TITLE" \ + --admin_user="$WP_ADMIN_USER" \ + --admin_password="$WP_ADMIN_PASSWORD" \ + --admin_email="$WP_ADMIN_EMAIL" \ + --skip-email \ + --allow-root +fi + +echo "Activating WooCommerce..." +wp plugin activate woocommerce --allow-root 2>/dev/null || true + +echo "Activating wc-bootstrap theme..." +wp theme activate wc-bootstrap --allow-root 2>/dev/null || true + +echo "" +echo "Setup complete!" +echo " URL: $WP_URL" +echo " Admin: $WP_URL/wp-admin/" +echo " User: $WP_ADMIN_USER" +echo " Password: $WP_ADMIN_PASSWORD"