Skip to content

Instantly share code, notes, and snippets.

@rmpel
Last active February 27, 2026 07:35
Show Gist options
  • Select an option

  • Save rmpel/f5c220b5e49baf0df4f5bbf5b7e76fdf to your computer and use it in GitHub Desktop.

Select an option

Save rmpel/f5c220b5e49baf0df4f5bbf5b7e76fdf to your computer and use it in GitHub Desktop.
zsh automatic LocalWP context switcher when navigating folders of projects on MacOS
# this is a zsh script to automatically switch to the localwp shell when you enter a
# directory that contains a LocalWP website installation
# it is designed to trigger on any directory deeper or exactly the app/ folder of a localwp site.
# this code is FAR FROM perfect, but it works! Feel free to suggest/improve/etc
#
# this file is to be sourced in your .zshrc .
#
# Suggested install method:
# cd ~ ; mkdir -p .zsh ; git clone https://gist.github.com/f5c220b5e49baf0df4f5bbf5b7e76fdf.git .zsh/zsh-auto-localwp
# echo "source ~/.zsh/zsh-auto-localwp/zsh-auto-localwp.sh" >> ~/.zshrc
#
# Some software is required apart from tools you should already have on your mac;
# Prereq; LocalWP (required, of course ;) )
# https://localwp.com/
# Prereq; jq (required)
# Linux: sudo apt install jq
# MacOS: brew install jq
# If you do not already have brew, please go to https://brew.sh/ for installation instructions.
# Prereq; local-cli (optional)
# npm install -g @getflywheel/local-cli
# WARNING! local-cli is no longer maintained, if unavailable, you can install from my github. This is convoluted, and I am
# probably doing it wrong, but this worked;
# npm install -g https://github.com/rmpel/local-cli.git
# npm list -g --depth=0 | grep local-cli
# echo 'Find the clone path, see output above, for example ├── @getflywheel/local-cli@0.0.5 -> ./../../../../../.npm/_cacache/tmp/git-cloneJZTRb5'
# echo 'If the ~/.npm/_cacache/tmp/git-cloneJZTRb5/bin folder is missing or empty, do this;
# rm -rf ~/.npm/_cacache/tmp/git-cloneJZTRb5 && git clone https://github.com/rmpel/local-cli.git ~/.npm/_cacache/tmp/git-cloneJZTRb5
#
# Prereq; realpath, sed, grep
#
# Method of operation:
# 1. When you enter a directory that matches a pattern ....../a-name/app/..... it will assume the sitename is a-name, and the site path is ....../a-name
# 2. It will look up the site id in the localwp sites.json file. If this path is listed, it will use the site id to set the environment.
# 3. If local-cli is available, it will check if the site is running, and start it if it is not.
# 4. When the environment is set, this will not be done again until you leave the site directory.
# 5. When you leave the site directory, the environment will be unset. You can jump between sites without any issues and each terminal will have their own environment.
#
# Notes;
# Script is far from DRY. Optimisation is needed.
# Script is far from perfect. It works, but it can and should be improved.
# Only developed and tested for MacOS using the Apple Terminal emulator.
# And for linux, MX Linux, xfce4 Terminal.
# And it goes without saying; only for zsh.
#
# This script is provided as-is, without any warranty or guarantee. Use at your own risk.
# Feel free to use, modify, share, etc. If you have improvements, please share them back.
#
# License; GPL v3, see https://www.gnu.org/licenses/gpl-3.0.html share-alike, attribution required.
###
# Global configuration;
# Define in your environment before loading this add-on.
# export AUTO_START_LOCALWP_APP=yes
AUTO_START_LOCALWP_APP=${AUTO_START_LOCALWP_APP:-no}
ZSH_AUTO_LOCALWP_PATH=$0:P
LOCAL_RUNTIME_DIRECTORY=~/.config/zsh-localwp/runtime
LOCAL_APP_LOCATION=~/.config/zsh-localwp/binary
LOCAL_APP_RESOURCES=~/.config/zsh-localwp/resources
LOCAL_CLI=$(which local-cli | head -n 1)
NOHUP=$(which setsid nohup | head -n 1)
LOCAL_SYSTEM_ARCHITECTURE=
###
# Get architecture
# returns linux, arm64 for macos on arm, x86_64 for macos on intel. Windows WSL support not yet here. Please contribute.
# @return string
function localwp_get_arch {
[ "" != "$LOCAL_SYSTEM_ARCHITECTURE" ] && echo "$LOCAL_SYSTEM_ARCHITECTURE" && return 0
[ "" != "$(which arch)" ] && LOCAL_SYSTEM_ARCHITECTURE=darwin && [ "arm64" = "$(arch)" ] && LOCAL_SYSTEM_ARCHITECTURE=darwin-arm64
[ -d /opt/Local/resources ] && LOCAL_SYSTEM_ARCHITECTURE=linux
echo "$LOCAL_SYSTEM_ARCHITECTURE"
}
LOCAL_SYSTEM_ARCHITECTURE=$(localwp_get_arch)
# function _localwp_screenresize {
# printf '\e[1;%dr' $((LINES-1)) # set scrolling region (rows 1..LINES-1)
# }
# trap _localwp_screenresize SIGWINCH
# _localwp_screenresize
###
# Wrapper function for local-cli calls that handles Node version switching
# This ensures local-cli is available even when the user has switched Node versions
# @param $@ All arguments to pass to local-cli
# @return Exit code from local-cli
function _localwp_safe_cli_call {
local EXIT_CODE
local ORIGINAL_NODE=""
local NODE_SWITCHED=0
# Check if local-cli is available
[ ! -e "$LOCAL_CLI" ] && return 1
# Detect and handle nvm (Node Version Manager)
if [ -n "$NVM_DIR" ] && [ -s "$NVM_DIR/nvm.sh" ]; then
# Source nvm if not already loaded
if ! command -v nvm >/dev/null 2>&1; then
source "$NVM_DIR/nvm.sh" >/dev/null 2>&1
fi
if command -v nvm >/dev/null 2>&1; then
ORIGINAL_NODE=$(nvm current 2>/dev/null)
# Only switch if we're not already on system or default
if [ "$ORIGINAL_NODE" != "system" ] && [ "$ORIGINAL_NODE" != "default" ]; then
nvm use default >/dev/null 2>&1 || nvm use system >/dev/null 2>&1
NODE_SWITCHED=1
fi
fi
# Detect and handle fnm (Fast Node Manager)
elif command -v fnm >/dev/null 2>&1; then
ORIGINAL_NODE=$(node -v 2>/dev/null)
# Try to switch to default
if fnm use default >/dev/null 2>&1 || fnm use system >/dev/null 2>&1; then
NODE_SWITCHED=1
fi
fi
# Execute the local-cli command
"$LOCAL_CLI" "$@"
EXIT_CODE=$?
# Restore original Node version if we switched
if [ $NODE_SWITCHED -eq 1 ] && [ -n "$ORIGINAL_NODE" ]; then
if [ -n "$NVM_DIR" ] && command -v nvm >/dev/null 2>&1; then
nvm use "$ORIGINAL_NODE" >/dev/null 2>&1
elif command -v fnm >/dev/null 2>&1; then
fnm use "$ORIGINAL_NODE" >/dev/null 2>&1
fi
fi
return $EXIT_CODE
}
### Start site in background and use polling to check if running.
# We do this because very often local-cli start-site will hang, even if the site is successfully started. This is a workaround for that issue.
# polling ends when either the background tasks is ended or when the local-cli is responsive for the site.
# $1 is the site id.
function _localwp_polling_start_site {
local SITE_ID="$1"
# Start the site in the background
_localwp_safe_cli_call start-site "$SITE_ID" >/dev/null 2>&1 &
local START_PID=$!
echo -n "Starting site (PID: $START_PID)..." >&2
# Poll until either the background process ends or the site is running
local MAX_WAIT=60 # Maximum wait time in seconds
local ELAPSED=0
while [ $ELAPSED -lt $MAX_WAIT ]; do
# Check if the background process is still running
if ! kill -0 "$START_PID" 2>/dev/null; then
echo " process ended." >&2
break
fi
# Check if the site is now running
local SITE_STATE=$(localwp_get_nth_word 6 $(_localwp_safe_cli_call list-sites 2>/dev/null | grep -- "$SITE_ID"))
if [ "$SITE_STATE" = "running" ]; then
echo " site is running!" >&2
# Kill the hanging start-site process since the site is already running
kill "$START_PID" 2>/dev/null
wait "$START_PID" 2>/dev/null
return 0
fi
# Wait briefly before checking again
sleep 1
ELAPSED=$((ELAPSED + 1))
echo -n "." >&2
done
# If we reached the timeout, warn the user
if [ $ELAPSED -ge $MAX_WAIT ]; then
echo " timeout reached!" >&2
# Kill the process if it's still running
if kill -0 "$START_PID" 2>/dev/null; then
kill "$START_PID" 2>/dev/null
wait "$START_PID" 2>/dev/null
fi
return 1
fi
# Wait for the background process to fully exit
wait "$START_PID" 2>/dev/null
return 0
}
### Create or update symlinks to the LocalWP runtime directory, Application Resources, and LocalWP binary.
# We do this to create a uniform environment for all platforms.
#
function _localwp_symlink_maintenance {
[ ! -d ~/.config/zsh-localwp ] && mkdir -p ~/.config/zsh-localwp
[ -L "$LOCAL_RUNTIME_DIRECTORY" ] && rm "$LOCAL_RUNTIME_DIRECTORY"
[ -L "$LOCAL_APP_LOCATION" ] && rm "$LOCAL_APP_LOCATION"
[ -L "$LOCAL_APP_RESOURCES" ] && rm "$LOCAL_APP_RESOURCES"
local APP_LOCATION
case $LOCAL_SYSTEM_ARCHITECTURE in
darwin-arm64|darwin)
# create symlinks; MacOS edition.
APP_LOCATION="$(ls -1d {,~}/Applications/Local.app 2>/dev/null | grep Applications -m 1)"
[ -e ~/Library/Application" "Support/Local ] && ln -s ~/Library/Application" "Support/Local "$LOCAL_RUNTIME_DIRECTORY"
[ -e "$APP_LOCATION" ] && ln -s "$APP_LOCATION" "$LOCAL_APP_LOCATION"
[ -e "$APP_LOCATION/Contents/Resources" ] && ln -s "$APP_LOCATION/Contents/Resources" "$LOCAL_APP_RESOURCES"
;;
linux)
# create symlinks; Linux edition.
[ -e ~/.config/Local ] && ln -s /opt/Local "$LOCAL_RUNTIME_DIRECTORY"
[ -e /opt/Local/local ] && ln -s /opt/Local/local "$LOCAL_APP_LOCATION"
[ -e /opt/Local/resources ] && ln -s /opt/Local/resources "$LOCAL_APP_RESOURCES"
;;
esac
# PolyFill; the local-cli has hardcoded paths to the MacOS runtime directory.
local LOCAL_RUNTIME=~/.config/Local
local LOCAL_RUNTIME_MACOS=~/Library/Application" "Support/Local
[ -d $LOCAL_RUNTIME ] && [ ! -d "$LOCAL_RUNTIME_MACOS" ] && echo Non-MacOS path detected. Local-CLI expects it. Creating symlinks. Please hold... >&2 && mkdir -p ~/Library/Application\ Support && ln -s ~/.config/Local ~/Library/Application\ Support/ && echo Done. >&2
}
_localwp_symlink_maintenance
[ ! -d "$LOCAL_RUNTIME_DIRECTORY" ] && echo LocalWP Runtime Dir not found. Inspect code, fix, try again. && return;
###
# Get the basename of a path, without using the basename command.
# @param $1 Path to the file or directory
# @param $2 Suffix to remove from the basename (optional)
_localwp_basename() {
# Usage: basename "path" ["suffix"]
# Strip all trailing forward-slashes '/' from
# the end of the string.
#
# "${1##*[!/]}": Remove all non-forward-slashes
# from the start of the string, leaving us with only
# the trailing slashes.
# "${1%%"${}"}: Remove the result of the above
# substitution (a string of forward slashes) from the
# end of the original string.
dir=${1%${1##*[!/]}}
# Remove everything before the final forward-slash '/'.
dir=${dir##*/}
# If a suffix was passed to the function, remove it from
# the end of the resulting string.
dir=${dir%"$2"}
# Print the resulting string and if it is empty,
# print '/'.
printf '%s\n' "${dir:-/}"
}
###
# Check if LocalWP process is running
# @return 0 if running, 1 if not
function localwp_is_process_running {
case $(localwp_get_arch) in
linux)
# On Linux, check for the local process
pgrep -x "local" >/dev/null 2>&1 && return 0
# Also try with full path matching
pgrep -f "/opt/Local/local" >/dev/null 2>&1 && return 0
;;
darwin-arm64|darwin)
# On macOS, check for Local.app process
# Check both "Local" and "Local Helper" processes
pgrep -f "Local.app/Contents/MacOS/Local" >/dev/null 2>&1 && return 0
# Fallback: check if Local.app is in running applications
osascript -e 'tell application "System Events" to (name of processes) contains "Local"' 2>/dev/null | grep -q "true" && return 0
;;
esac
return 1
}
###
# Start LocalWP.
# @param $1 Path to the detected LocalWP app. If missing, we just Hail Mary on Local.app
function localwp_launch_localwp {
# prevent broken shell from infinitely trying to start Local.
[ ! -e "$LOCAL_CLI" ] && echo LOCAL_CLI error && return 0;
# Check if local-cli is already responsive
_localwp_safe_cli_call list-sites >/dev/null 2>&1 && return 0
# Check if the process is already running but not yet responsive
if localwp_is_process_running; then
echo -n "Local.app is starting up, waiting for it to be ready..." >&2
local TIMEOUT=30
local RETRY=$TIMEOUT
# loop until we have a connection to the local-cli
while [ $RETRY -gt 0 ]; do
_localwp_safe_cli_call list-sites >/dev/null 2>&1 && break
sleep 1
RETRY=$((RETRY-1))
echo -n "." >&2
done
echo "" >&2
_localwp_safe_cli_call list-sites >/dev/null 2>&1 && \
echo "Local.app became ready in $((TIMEOUT-RETRY)) seconds." >&2 || \
echo "Local.app did not become ready in $TIMEOUT seconds." >&2
return 0
fi
# Process is not running, launch it
echo -n "Starting Local.app ... Please wait ..." >&2
# if linux, get local_app, start in background
if [ "linux" = "$(localwp_get_arch)" ]; then
$NOHUP "$LOCAL_APP_LOCATION" >/dev/null 2>&1 &
else
open -a "$LOCAL_APP_LOCATION"
fi
# start a retry counter at 15; we wait at most 15 seconds for the app to start.
local TIMEOUT=15
local RETRY=$TIMEOUT
# loop until we have a connection to the local-cli
while [ $RETRY -gt 0 ]; do
_localwp_safe_cli_call list-sites >/dev/null 2>&1 && break
sleep 1
RETRY=$((RETRY-1))
# echo a dot, no new line
echo -n "." >&2
done
echo "" >&2
_localwp_safe_cli_call list-sites >/dev/null 2>&1 && \
echo "Local.app started in $((TIMEOUT-RETRY)) seconds." >&2 || \
echo "Local.app did not start in $TIMEOUT seconds." >&2
}
###
# Find the MySQL binary path for a specific version, it will auto-detect the architecture and try the best match.
# @param $1 MySQL version
#
function localwp_find_mysql_binary_path {
LOCAL_SYSTEM_ARCHITECTURE=$(localwp_get_arch)
setopt nullglob
for i in \
${LOCAL_RUNTIME_DIRECTORY}/lightning-services/mysql-${1}*/bin/${LOCAL_SYSTEM_ARCHITECTURE}/bin \
${LOCAL_APP_RESOURCES}/extraResources/lightning-services/mysql-${1}*/bin/${LOCAL_SYSTEM_ARCHITECTURE}/bin \
${LOCAL_RUNTIME_DIRECTORY}/lightning-services/mysql-${1}*/bin/darwin/bin \
${LOCAL_APP_RESOURCES}/extraResources/lightning-services/mysql-${1}*/bin/darwin/bin \
; do
if [ -d "$i" ]; then
export _LOCALWP_INTERNAL_CALL=1
pushd $i >/dev/null 2>&1
MYSQL_PATH=$(pwd -P)
popd >/dev/null 2>&1
unset _LOCALWP_INTERNAL_CALL
break;
else
MYSQL_PATH=""
fi
done
unsetopt nullglob
echo "$MYSQL_PATH"
}
###
# Find the PHP binary path for a specific version, it will auto-detect the architecture and try the best match.
# @param $1 PHP version
#
function localwp_find_php_binary_path {
LOCAL_SYSTEM_ARCHITECTURE=$(localwp_get_arch)
setopt nullglob
for i in \
${LOCAL_RUNTIME_DIRECTORY}/lightning-services/php-${1}*/bin/${LOCAL_SYSTEM_ARCHITECTURE}/bin \
${LOCAL_APP_RESOURCES}/extraResources/lightning-services/php-${1}*/bin/${LOCAL_SYSTEM_ARCHITECTURE}/bin \
${LOCAL_RUNTIME_DIRECTORY}/lightning-services/php-${1}*/bin/darwin/bin \
${LOCAL_APP_RESOURCES}/extraResources/lightning-services/php-${1}*/bin/darwin/bin \
; do
if [ -d "$i" ]; then
export _LOCALWP_INTERNAL_CALL=1
pushd "$i" >/dev/null 2>&1
PHP_PATH=$(pwd -P)
popd >/dev/null 2>&1
unset _LOCALWP_INTERNAL_CALL
break;
else
PHP_PATH=""
fi
done
unsetopt nullglob
echo "$PHP_PATH"
}
###
# Find the Imagick module path for a specific PHP version, it will auto-detect the architecture and try the best match.
# @param $1 PHP version
#
function localwp_find_php_imagick_path {
LOCAL_SYSTEM_ARCHITECTURE=$(localwp_get_arch)
setopt nullglob
for i in \
"${LOCAL_RUNTIME_DIRECTORY}/lightning-services/php-${1}+0/bin/${LOCAL_SYSTEM_ARCHITECTURE}/ImageMagick/modules-Q16/coders" \
"${LOCAL_APP_RESOURCES}/extraResources/lightning-services/php-${1}*/bin/${LOCAL_SYSTEM_ARCHITECTURE}/ImageMagick/modules-Q16/coders \
"${LOCAL_RUNTIME_DIRECTORY}/lightning-services/php-${1}+0/bin/darwin/ImageMagick/modules-Q16/coders" \
"${LOCAL_APP_RESOURCES}/extraResources/lightning-services/php-${1}*/bin/darwin/ImageMagick/modules-Q16/coders \
; do
if [ -d "$i" ]; then
export _LOCALWP_INTERNAL_CALL=1
pushd $i >/dev/null 2>&1
MGK_PATH=$(pwd -P)
popd >/dev/null 2>&1
unset _LOCALWP_INTERNAL_CALL
break;
else
MGK_PATH=""
fi
done
unsetopt nullglob
echo "$MGK_PATH"
}
###
# Get the nth word from a string
# @param $1 Nth word
# @param $2..$N Strings
#
function localwp_get_nth_word {
local NTH="$1"
shift;
local WORDS=($*)
local WORD="${WORDS[$NTH]}"
echo "$WORD"
}
###
# Set the environment for a LocalWP site
# @param $1 Site name
# @param $2 Site ID
# @param $3 MySQL version
# @param $4 PHP version
#
function localwp_set_env {
if [ "yes" = $AUTO_START_LOCALWP_APP ]; then
localwp_launch_localwp
fi
echo -e "\033[33mSwitching to Local Shell for ${1}\033[0m" >&2
if [ -e "$LOCAL_CLI" ]; then
SITE_STATE=$(localwp_get_nth_word 6 $(_localwp_safe_cli_call list-sites | grep -- "$2"))
[ "halted" = "$SITE_STATE" ] && ( echo -e "\033[33m${1} not running, starting ...\033[0m" >&2 && _localwp_polling_start_site "$2" ) || echo -n '' >&2
fi
export WP_ENV=local-by-flywheel
export MYSQL_HOME="${LOCAL_RUNTIME_DIRECTORY}/run/${2}/conf/mysql"
export PHPRC="${LOCAL_RUNTIME_DIRECTORY}/run/${2}/conf/php"
export WP_CLI_CONFIG_PATH="$LOCAL_APP_RESOURCES/extraResources/bin/wp-cli/config.yaml"
export WP_CLI_DISABLE_AUTO_CHECK_UPDATE=1
PATH="$(localwp_find_mysql_binary_path ${3}):$PATH"
PATH="$(localwp_find_php_binary_path ${4}):$PATH"
PATH="${LOCAL_APP_RESOURCES}/extraResources/bin/wp-cli/posix:$PATH"
PATH="${LOCAL_APP_RESOURCES}/extraResources/bin/composer/posix:$PATH"
export PATH
MGK=$(localwp_find_php_imagick_path ${4})
[ "" != "${MGK}" ] && export MAGICK_CODER_MODULE_PATH="${MGK}"
export LOCALWP_SITE="$1"
export LOCALWP_SITE_ID="$2"
[ "" = "$LD_LIBRARY_PATH" ] && LD_LIBRARY_PATH="$(localwp_find_php_binary_path ${4})"/../shared-libs
export LD_LIBRARY_PATH
local WEB_PATH="$(ls -d1 "${SITE_PATH}"/app/public "${SITE_PATH}"/app/public_html "${SITE_PATH}"/app/web 2>/dev/null | grep app | head -n1)"
local COMPOSER_PATH="$(ls -d1 "${WEB_PATH}"/composer.json "${WEB_PATH}"/../composer.json "${WEB_PATH}"/../../composer.json 2>/dev/null | grep composer.json | head -n1)"
if [ -f "$COMPOSER_PATH" ]; then
local SITE_PHP_VERSION=$(jq -r .config.platform.php "$COMPOSER_PATH")
if [ ! -z $SITE_PHP_VERSION ] && [ "null" != "$SITE_PHP_VERSION" ]; then
( echo "$SITE_PHP_VERSION" | php -r '$mm=function($in) { $in = explode(".", $in); return (float)"{$in[0]}.{$in[1]}"; }; $a = file_get_contents("php://stdin"); $a = $mm($a); $p = $mm(PHP_VERSION); exit (version_compare($a,$p));' ) || \
( echo -e "\033[36mPHP Version in composer.json differs from LocalWP configured version. \033[0m" >&2 ; echo -e "\033[36mcomposer.json: $SITE_PHP_VERSION, LocalWP: $(php -r 'echo PHP_VERSION;'). \033[0m" >&2 )
fi
fi
}
###
# Unset the environment for a LocalWP site
#
function localwp_unset_env {
unset LD_LIBRARY_PATH
unset WP_ENV
unset MYSQL_HOME
unset PHPRC
unset WP_CLI_CONFIG_PATH
unset WP_CLI_DISABLE_AUTO_CHECK_UPDATE
unset MAGICK_CODER_MODULE_PATH
# remove paths from PATH
# remove paths matching ${LOCAL_APP_LOCATION}/Contents/Resources/extraResources/bin/
# remove paths matching ${LOCAL_RUNTIME_DIRECTORY}/lightning-services
PATH=$(echo $PATH | tr ':' '\n' | grep -v "${LOCAL_APP_RESOURCES}/extraResources/" | grep -v "${LOCAL_RUNTIME_DIRECTORY}/lightning-services" | tr '\n' ':')
# trim trailing/leading colons and remove multiple colons in a row
PATH=$(echo $PATH | sed 's/:*$//;s/^:*//;s/:+/:/g')
export PATH
export LOCALWP_SITE=
export LOCALWP_SITE_ID=
}
###
# MAIN Automatically switch to the LocalWP shell when entering a LocalWP site directory
#
function localwp_auto_switch {
if [ "" != "$_LOCALWP_INTERNAL_CALL" ]; then
return;
fi
[ "" = "$(which jq)" ] && return;
SITES_JSON_PATH="$LOCAL_RUNTIME_DIRECTORY"/sites.json
THEPWD="$(pwd)"
if [[ "$THEPWD" =~ /.+/([^/]+)/app($|/.*) ]]; then
## variable cutting, on first match with %%, on last match with % .
SITE_PATH=${THEPWD%%/app/*}
SITE_ID=$(jq -r ".[] | select(.path == \"$SITE_PATH\") | .id" "$SITES_JSON_PATH")
# does not seem to be a localwp site, but maybe the path is different
if [ "" = "$SITE_ID" ]; then
SITE_REAL_PATH=$(realpath "$SITE_PATH")
SITE_ID=$(jq -r ".[] | select(.path == \"$SITE_REAL_PATH\") | .id" "$SITES_JSON_PATH")
SITE_PATH="$SITE_REAL_PATH"
fi
# still no site id, we are done.
[ "" = "$SITE_ID" ] && return;
# PHP Config already pointing to this site, we assume all is o.k.
# This is because this variable is set by the localwp_set_env function
if [[ "$PHPRC" =~ "/$SITE_ID/" ]]; then
return
fi
# get the site name
SITE_NAME=$(_localwp_basename "$SITE_PATH")
MYSQL_VERSION=$(jq -r ".[] | select(.path == \"$SITE_PATH\") | .services.mysql.version" "$SITES_JSON_PATH")
PHP_VERSION=$(jq -r ".[] | select(.path == \"$SITE_PATH\") | .services.php.version" "$SITES_JSON_PATH")
echo -n -e "\033]0;Local Shell for ${SITE_NAME}\007"
# clear the environment
localwp_unset_env
# set the environment
localwp_set_env $SITE_NAME $SITE_ID $MYSQL_VERSION $PHP_VERSION
elif [[ "$PHPRC" =~ "/$SITE_ID/" ]]; then
# clear the environment
localwp_unset_env
# notify the user
echo -e "\033[33mSwitching off Local Shell\033[0m" >&2
# clear the title
echo -n -e "\033]0;\007"
fi
}
function localwp_siteid_from_name {
SITES_JSON_PATH="$LOCAL_RUNTIME_DIRECTORY"/sites.json
SITE_ID=$(jq -r ".[] | select(.name == \"$1\") | .id" "$SITES_JSON_PATH")
if [ "" = "$SITE_ID" ]; then
echo "Site not found: $1"
return 1
fi
echo "$SITE_ID"
}
function localwp_site_info_query {
# $1 is the query, $2 is the site id
SITES_JSON_PATH="$LOCAL_RUNTIME_DIRECTORY"/sites.json
jq -r .\"${2:-$SITE_ID}\"${1} "$SITES_JSON_PATH"
}
function localwp_evaluatepath {
local THE_PATH="$1"
local OLD_PATH="$1"
if [ -L "$THE_PATH" ] ; then
THE_PATH=$(readlink -f "$THE_PATH")
fi
if [ -e "$THE_PATH" ]; then
THE_PATH=$(realpath "$THE_PATH")
fi
if [ "$THE_PATH" != "$OLD_PATH" ]; then
localwp_evaluatepath "$THE_PATH"
else
# no change, return the path
echo "$THE_PATH"
fi
}
function localwp_print_info {
local S="${1:-$SITE_ID}"
local SITE_PATH="$(localwp_site_info_query .path "${S}")"
echo "SiteID: " ${S}
local ITEM
ITEM="${SITE_PATH}"/app
echo "Site root from current path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM=$(ls -d1 "${SITE_PATH}"/app/public "${SITE_PATH}"/app/public_html "${SITE_PATH}"/app/web 2>/dev/null | grep app | head -n1)
echo "Web root for this site (by disk): " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM="${SITE_PATH}"/app/.idea
echo ".IDEA folder location (by disk): " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM="${LOCAL_RUNTIME_DIRECTORY}"/run/"${S}"/conf/apache/site.conf
local APACHECONF="$ITEM"
echo "Apache config path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM="${SITE_PATH}"/conf/apache/site.conf.hbs
echo "Apache config template path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM=$(grep DocumentRoot "$APACHECONF" -m 1)
# data is in the form: DocumentRoot "/Users/username/Local Sites/sitename/app/public"
# Remove everything (" included) up til the first " found
ITEM=${ITEM#*\"}
# Remove everything (" included) after the first " found
ITEM=${ITEM%\"*}
echo "Web root for this ste (Apache): " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM="${LOCAL_RUNTIME_DIRECTORY}"/run/"${S}"/conf/php/php.ini
local PHPCONF="$ITEM"
echo "PHP config path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM="${SITE_PATH}"/conf/php/php.ini.hbs
echo "PHP config template path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM=$(grep openssl.cafile "$PHPCONF" -m 1)
# data is in the form: openssl.cafile="/Users/username/Local Sites/sitename/app/public/wp-includes/certificates/ca-bundle.crt"
# Remove everything ( = included) up til the first " found
ITEM=${ITEM#*\"}
# Remove everything (" included) after the first " found
ITEM=${ITEM%\"*}
echo "WordPress SSL CA Cert path (PHP): " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
local NAME="$(localwp_site_info_query .name "${S}")"
ITEM="${LOCAL_RUNTIME_DIRECTORY}/run/router/nginx/conf/route.${NAME}.test.conf"
echo "Router Config: " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM="${LOCAL_RUNTIME_DIRECTORY}/run/router/nginx/certs/${NAME}.test.crt"
echo "SSL Certificate: " $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
ITEM="$LOCAL_APP_LOCATION"
echo "LocalWP Application path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $ITEM
echo " =>" $(localwp_evaluatepath "$ITEM")
ITEM="$LOCAL_RUNTIME_DIRECTORY"
echo "LocalWP Runtime path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $ITEM
echo " =>" $(localwp_evaluatepath "$ITEM")
ITEM="$LOCAL_APP_RESOURCES"
echo "LocalWP Resources path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $ITEM
echo " =>" $(localwp_evaluatepath "$ITEM")
ITEM="$LOCAL_RUNTIME_DIRECTORY"/sites.json
echo "LocalWP Sites JSON path: " $( [ -e "$ITEM" ] && echo √ || echo x ) $ITEM
echo " =>" $(localwp_evaluatepath "$ITEM")
echo "TCP/IP ports:"
echo " Apache: " $(localwp_site_info_query ".services.apache.ports.HTTP[0]" "${S}")
echo " MySQL: " $(localwp_site_info_query ".services.mysql.ports.MYSQL[0]" "${S}")
ITEM="$LOCAL_RUNTIME_DIRECTORY/run/${S}/mysql/mysqld.sock"
echo " socket:" $( [ -e "$ITEM" ] && echo √ || echo x ) $(localwp_evaluatepath "$ITEM")
echo " PHP CGI: " $(localwp_site_info_query ".services.php.ports.cgi[0]" "${S}")
echo " MailPit UI: " $(localwp_site_info_query ".services.mailpit.ports.WEB[0]" "${S}")
echo " MailPit SMTP: " $(localwp_site_info_query ".services.mailpit.ports.SMTP[0]" "${S}")
echo "URLs:"
echo " Website: " http://$(localwp_site_info_query ".domain" "${S}")/
echo " Mailpit: " http://$(localwp_site_info_query ".domain" "${S}"):$(localwp_site_info_query ".services.mailpit.ports.WEB[0]" "${S}")/
}
function localwp {
if [ "" = "$1" ]; then
echo "Usage: localwp <command>"
echo "Commands:"
echo " start <site> Start a LocalWP site by name"
echo " stop <site> Stop a LocalWP site by name"
echo " restart <site> Restart a LocalWP site by name"
echo " status <site> Get the status of a LocalWP site by name"
echo " info Show relevant information on the current site"
echo " list List all LocalWP sites"
echo " refresh Refresh the current environment (e.g. when PHP version changed)"
[ -n "$(which dblab)" ] && echo " dblab Open dblab for this site"
[ -n "$(which lazysql)" ] && echo " lazysql Open lazysql for this site"
echo " selfupdate Update this script from GIT"
echo " selfreload Reload script in current session"
echo " selfedit Edit this script with editor defined in \$EDITOR"
return 1
fi
if [ "yes" = $AUTO_START_LOCALWP_APP ]; then
localwp_launch_localwp
fi
local CURSITE="$LOCALWP_SITE_ID"
[ "$2" != "" ] && CURSITE=$(localwp_siteid_from_name "$2")
case "$1" in
start)
_localwp_polling_start_site "$CURSITE"
;;
stop)
_localwp_safe_cli_call stop-site "$CURSITE"
;;
restart)
_localwp_safe_cli_call stop-site "$CURSITE"
_localwp_polling_start_site "$CURSITE"
;;
status)
_localwp_safe_cli_call list-sites | grep -- "$CURSITE"
;;
info)
localwp_print_info "$CURSITE"
;;
list)
_localwp_safe_cli_call list-sites
;;
selfreload)
echo "Reloading localwp script..."
source "$ZSH_AUTO_LOCALWP_PATH"
;;
refresh)
echo "Refreshing environment..."
[ ! -z $LOCALWP_SITE_ID ] && localwp_unset_env
localwp_auto_switch
;;
dblab|db)
if [ -z "$(which dblab)" ]; then
echo "dblab is not installed or not in PATH"
return 1
fi
local SOCKET="$LOCAL_RUNTIME_DIRECTORY/run/${CURSITE}/mysql/mysqld.sock"
if [ ! -e "$SOCKET" ]; then
echo "MySQL socket not found at: $SOCKET"
echo "Is the site running?"
return 1
fi
dblab --socket "$SOCKET" --db local --user root --pass root --driver mysql
;;
lazysql)
if [ -z "$(which lazysql)" ]; then
echo "lazysql is not installed or not in PATH"
return 1
fi
local SOCKET="$LOCAL_RUNTIME_DIRECTORY/run/${CURSITE}/mysql/mysqld.sock"
if [ ! -e "$SOCKET" ]; then
echo "MySQL socket not found at: $SOCKET"
echo "Is the site running?"
return 1
fi
lazysql "mysql://root:root@/$SOCKET/local"
;;
selfupdate)
echo "Updating localwp script..."
cd "$(dirname "$ZSH_AUTO_LOCALWP_PATH")" || { echo "Failed to change directory to $(dirname "$ZSH_AUTO_LOCALWP_PATH")"; return 1; }
# fetch the latest version from the gist
[ -d .git ] && git pull || { echo "Not a git repository, cannot update."; return 1; }
cd - >/dev/null || { echo "Failed to return to previous directory."; return 1; }
echo "Update complete."
;;
selfedit)
if [ -z "$EDITOR" ]; then
echo "No editor defined in \$EDITOR, please set it to your preferred editor."
return 1
fi
echo "$EDITOR" "$ZSH_AUTO_LOCALWP_PATH" >&2
"$EDITOR" "$ZSH_AUTO_LOCALWP_PATH"
;;
*)
echo "Unknown command: $1"
return 1
;;
esac
}
# autoload the hook
autoload -U add-zsh-hook
add-zsh-hook chpwd localwp_auto_switch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment