Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions .docker/wordpress/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ trim_value() {
echo "$1" | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//'
}

is_truthy() {
case "$(echo "${1:-}" | tr '[:upper:]' '[:lower:]')" in
1|true|yes|on)
return 0
;;
*)
return 1
;;
esac
}

plugins_config_exists() {
[ -n "$(trim_value "${WORDPRESS_SETUP_CONFIG_YAML:-}")" ]
}
Expand Down Expand Up @@ -127,6 +138,46 @@ sync_site_urls() {
replace_url_occurrences "${prod_host}" "${local_host}"
}

reset_local_user_passwords() {
local reset_all_users="${WORDPRESS_LOCAL_RESET_ALL_USERS_PASSWORDS:-0}"
local target_user
local shared_password="${WORDPRESS_LOCAL_USERS_PASSWORD:-}"
local user_id

target_user="$(trim_value "${WORDPRESS_LOCAL_RESET_PASSWORD_FOR_USER:-}")"

if [ -z "$shared_password" ]; then
echo "WORDPRESS_LOCAL_USERS_PASSWORD not set; skipping local user password reset."
return
fi

if is_truthy "$reset_all_users"; then
echo "Resetting password for all local WordPress users..."
while IFS= read -r user_id; do
user_id="$(trim_value "$user_id")"
if [ -z "$user_id" ]; then
continue
fi
runuser -u www-data -- wp user update "$user_id" --user_pass="$shared_password" >/dev/null
done < <(runuser -u www-data -- wp user list --field=ID)
echo " ✓ Password reset completed for all users"
return
fi

if [ -n "$target_user" ]; then
echo "Resetting password for local WordPress user '$target_user'..."
if runuser -u www-data -- wp user get "$target_user" --field=ID >/dev/null 2>&1; then
runuser -u www-data -- wp user update "$target_user" --user_pass="$shared_password" >/dev/null
echo " ✓ Password reset completed for user '$target_user'"
else
echo " ⚠ User '$target_user' not found; skipping password reset"
fi
return
fi

echo "No local password reset target configured; set WORDPRESS_LOCAL_RESET_ALL_USERS_PASSWORDS=1 or WORDPRESS_LOCAL_RESET_PASSWORD_FOR_USER."
}

install_plugin() {
local plugin_slug="$1"

Expand Down Expand Up @@ -312,6 +363,7 @@ echo "Installing plugins and themes..."

if wordpress_is_installed; then
sync_site_urls
reset_local_user_passwords

if plugins_config_exists; then
install_org_plugins_from_config
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ services:
# Local URL that replaces PROD_SITE_URL during startup synchronization.
# Keep as localhost for local development, or change if you use another host.
LOCAL_SITE_URL: ${LOCAL_SITE_URL:-http://localhost}
# Local-only password override for imported users (do not use in production).
# Set one shared password and choose one strategy:
# - reset all local users, or
# - reset only one specific user login/email/ID.
WORDPRESS_LOCAL_USERS_PASSWORD: ${WORDPRESS_LOCAL_USERS_PASSWORD:-localdev123}
WORDPRESS_LOCAL_RESET_ALL_USERS_PASSWORDS: ${WORDPRESS_LOCAL_RESET_ALL_USERS_PASSWORDS:-1}
WORDPRESS_LOCAL_RESET_PASSWORD_FOR_USER: ${WORDPRESS_LOCAL_RESET_PASSWORD_FOR_USER:-}
# Inline YAML config for automatic plugin/theme installation.
# Use wordpress_org_plugins, wordpress_archive_plugins, wordpress_custom_plugins, and wordpress_custom_themes.
WORDPRESS_SETUP_CONFIG_YAML: |
Expand Down Expand Up @@ -89,9 +96,14 @@ After that, start the stack with the standard Compose command:

```bash
docker compose up -d --build
docker compose exec --user www-data wordpress wp user reset-password <username> --show-password --skip-email
```

On each startup (when WordPress is already installed), the entrypoint can automatically reset local user passwords:
- `WORDPRESS_LOCAL_RESET_ALL_USERS_PASSWORDS=1`: reset all users to `WORDPRESS_LOCAL_USERS_PASSWORD`.
- `WORDPRESS_LOCAL_RESET_PASSWORD_FOR_USER=<login|email|id>`: reset only one user.

Use only one strategy at a time. For local environments importing production data, resetting all users is usually the simplest approach.

### Database dump

If you need to bootstrap the environment with existing data, place your SQL dump in the folder below:
Expand Down
3 changes: 3 additions & 0 deletions common-services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ services:
- WORDPRESS_DB_PASSWORD=${WORDPRESS_DB_PASSWORD:-root}
- WORDPRESS_TABLE_PREFIX=${WORDPRESS_TABLE_PREFIX:-wp_}
- WORDPRESS_SETUP_CONFIG_YAML=${WORDPRESS_SETUP_CONFIG_YAML:-}
- WORDPRESS_LOCAL_USERS_PASSWORD=${WORDPRESS_LOCAL_USERS_PASSWORD:-}
- WORDPRESS_LOCAL_RESET_ALL_USERS_PASSWORDS=${WORDPRESS_LOCAL_RESET_ALL_USERS_PASSWORDS:-0}
- WORDPRESS_LOCAL_RESET_PASSWORD_FOR_USER=${WORDPRESS_LOCAL_RESET_PASSWORD_FOR_USER:-}
- XDEBUG_CONFIG=${XDEBUG_CONFIG:-client_host=host.docker.internal start_with_request=yes}
- XDEBUG_MODE=${XDEBUG_MODE:-off}
- HOST_UID=${HOST_UID:-1000}
Expand Down