#!/bin/bash

# - set WPX version -
WPXV="1.0.7"

# ================================ #
# === WPX - WP CLI Multiplied! === #
# ================================ #
#
# "You'll see your commands multiplied, if you continually decide, 
# 	to faithfully pursue, the policy of root."
#
# Love this tool? Become a WP Medic Patron: https://patreon.com/wpmedic
#
# WPX Home: http://wpmedic.tech/wpx/
# WPX GitHub: https://github.com/majick777/wpx/
#
# WP CLI Home: http://wp-cli.org/
# WP CLI Command Reference: https://developer.wordpress.org/cli/commands/
#
# For Installation, Usage Notes and Changelog see README.md


# === Setup ===
# - Output Valid Command List
# - WPX Update Check
# - Colour Functions
# - Check Action Result
# - Create Command Combo Array
# - Check for Element in Array
# === YAML Helpers ===
# - Fix YAML File
# - Parse YAML File
# - Load YAML File
# === Core Commands ===
# - Debug Info 
# - Check Version
# - Verify Core
# - Update Core
# - Install Core
# - Reinstall Core
# - Lock Core
# - Unlock Core
# - Check Core Lock
# - Check File Owners/Groups
# - Fix File Owners/Groups
# - Get Option Value
# - Update List
# === Plugin Commands ===
# - List Plugins
# - Install Plugin
# - Install and Activate Plugin
# - Reinstall Plugin
# - Activate Plugin
# - Deactivate Plugin
# - Update Plugin
# - Rollback Plugin
# - Delete Plugin
# - Uninstall Plugin
# === Theme Commands ===
# - List Themes
# - Check Themes
# - Install Theme
# - Install and Activate Theme
# - Reinstall Theme
# - Activate Theme
# - Update Theme
# - Rollback Theme
# - Delete Theme
# === Sync Commands ===
# - Sync Core
# - Sync Plugin
# - Sync and Activate Plugin
# - Sync Theme
# - Sync and Activate Theme
# - Sync Must Use Plugin
# - Delete Must Use Plugin
# - Sync Dropin
# - Delete Dropin
# === Language Commands ===
# - Install Language
# - Uninstall Language
# - Activate Language
# - Update Language
# === Command Line Arguments ===
# === Loop Site Commands ===


# ------------- #
# === SETUP === #
# ------------- #

# - debug command output -
set +x

# - declare some globals -
CWD=$(pwd)
RESULT=""
INARRAY=""
REINSTALL=""
DEBUG="false"
FOUND=""
DONE=""

# - get script path -
# DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# 1.0.4: use improved symlink compatible version
# ref: https://stackoverflow.com/a/246128/5240159
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do 
	DIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"
	SOURCE="$(readlink "$SOURCE")"
	[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
SCRIPTDIR="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )"

# ------------------------- #
# Output Valid Command List #
# ------------------------- #
function validcommands {
	red "Valid Commands"; echo ":"
	printf "["; yellow "WPX"; echo "] updatecheck, updatescript, showconfig, showsites, showsources, debuginfo, updatelist"
	printf "["; yellow "CORE"; echo "] debuginfo, checkversion, verifycore, installcore, reinstallcore, updatecore, lockcore, unlockcore, checklock, checkowners, fixowners"
	printf "["; yellow "PLUGIN"; echo "] findplugin, listplugins, verifyplugin, activateplugin, deactivateplugin, installplugin, installactivateplugin, reinstallplugin, updateplugin, updateallplugins, rollbackplugin, deleteplugin"
	printf "["; yellow "THEME"; echo "] listthemes, activatetheme, installtheme, installactivatetheme, reinstalltheme, updatetheme, rollbacktheme, deletetheme"
	printf "["; yellow "SYNC"; echo "] syncplugin, syncexistingplugin, syncactivateplugin, syncmuplugin, synctheme, syncactivatetheme, syncmuplugin, deletemuplugin, syncdropin, deletedropin"
	printf "["; yellow "LANGUAGE"; echo "] installlanguage, activatelanguage, updatelanguage, uninstalllanguage"
}

# --------------------- #
# Sudo Capability Check #
# --------------------- #
# 1.0.4: added sudoer check
# ref: https://superuser.com/a/1281228/742095
function sudo_check {

	prompt=$(sudo -nv 2>&1)
	NOPWD=$(echo "$prompt" | grep -q '^sudo:')
	if [ $? -eq 0 ]; then
		# - do nothing as sudo possible without password -
		printf ""
	elif [ "$NOPWD" ]; then
		# red "Warning."; "Password for sudo is not set. You may be prompted for it."
		printf ""
	else
		# red "Error!"; echo "You need sudo capability to run this script."
		printf ""
	fi
}

# ---------------- #
# WPX Update Check #
# ---------------- #
# 1.0.4: added update check command
function updatecheck {

	# - get current and latest versions -
	getscriptversions
	
	if [ "$LATEST" -gt "$CURRENT" ]; then
	
		# - output current and latest versions -
		printf "Current Version: "; yellow "$WPXV"; printf " | Latest Version: "; yellow "$NEWV"; echo ""
		yellow "A newer version of WPX is available."; echo ""
		
		# - display changelog section(s) since last update -
		# ref: https://stackoverflow.com/a/13242563/5240159
		echo "Changes since your last update:"
		FROM="# = ""$NEWV"
		TO="# = ""$WPXV"
		CHANGELOG=${CONTENTS##*"$FROM"}
		CHANGELOG="$FROM""$CHANGELOG"
		CHANGELOG=${CHANGELOG%%"$TO"*}
		CHANGELOG=$(tr -d "#" <<< "$CHANGELOG")
		echo "$CHANGELOG"

		# - display update instructions -		
		echo ""
		printf "Download and update using: "; cyan "wpx updatescript"; echo ""
		echo "Or update manually with:"
		echo "cd ""$SCRIPTDIR"" && wget -Owpx https://raw.githubusercontent.com/majick777/wpx/master/wpx"
	else
		printf "Your current version of WPX ("; yellow "$WPXV"; echo ") is up to date."
	fi
}

# ----------------- #
# WPX Update Script #
# ----------------- #
# 1.0.4: added update script command
function updatescript {

	# - get script info -
	getscriptversions
	
	if [ "$LATEST" -gt "$CURRENT" ]; then

		# - double check script path is correct -
		SCRIPTPATH="$SCRIPTDIR""/wpx"
		if [ -f "$SCRIPTPATH" ]; then

			# - output current and latest versions -
			yellow "**"; printf " WPX will update from version "; yellow "$WPXV"; printf " to "; yellow "$NEWV"; echo ""
			COMMAND="cd ""$SCRIPTDIR"" && wget -Owpx https://raw.githubusercontent.com/majick777/wpx/master/wpx"

			# - provide detected information to user -
			printf "WPX has detected that is running from "; cyan "$SCRIPTPATH"; echo ""
			echo "The update command that will be run is:"
			yellow "$COMMAND"; echo ""
			echo "If this is incorrect, answer no and update manually."

			# - confirmation prompt -
			read -p "Do you want to run this update? " -n 1 -r
			if [[ ! $REPLY =~ ^[Yy]$ ]]; then
				echo ""
				[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1
			fi

			# - run update command -
			echo ""; yellow "****"; echo " Updating WPX to the latest version...";
			cd "$SCRIPTDIR"
			OUTPUT=$(wget -Owpx https://raw.githubusercontent.com/majick777/wpx/master/wpx)
			cd "$CWD"
			echo "Done!"
		fi
	else
		red "Error!"; echo " No newer version than the current one was found."
		printf "Current Version: "; yellow "$WPXV"; printf " | Latest Version: "; yellow "$NEWV"; echo ""
	fi	
}

# ------------------- #
# Get Script Versions #
# ------------------- #
# 1.0.4: added get script versions helper
function getscriptversions {

	# - get latest version file to variable -
	CONTENTS=$(wget -qO- 'https://raw.githubusercontent.com/majick777/wpx/master/wpx')
	CONTENTS=$(cat /usr/local/bin/wpx)
	NEWV=$(grep -m 1 'WPXV=' <<< "$CONTENTS")
	NEWV=$(tr -d 'WPXV=' <<< "$NEWV")
	NEWV=$(tr -d '"' <<< "$NEWV")

	# - set versions for comparing -
	CURRENT=$(tr -d '.' <<< "$WPXV")
	LATEST=$(tr -d '.' <<< "$NEWV")
}

# ---------------- #
# Colour Functions #
# ---------------- #
black() { printf "$(tput setaf 0)$*$(tput setaf 9)"; }
red() { printf "$(tput setaf 1)$*$(tput setaf 9)"; }
green() { printf "$(tput setaf 2)$*$(tput setaf 9)"; }
yellow() { printf "$(tput setaf 3)$*$(tput setaf 9)"; }
blue() { printf "$(tput setaf 4)$*$(tput setaf 9)"; }
magenta() { printf "$(tput setaf 5)$*$(tput setaf 9)"; }
cyan() { printf "$(tput setaf 6)$*$(tput setaf 9)"; }
white() { printf "$(tput setaf 7)$*$(tput setaf 9)"; }

# ------------------- #
# Check Action Result #
# ------------------- #
function checkresult {

	local OUTPUT; local SUCCESS; local TYPE
	OUTPUT=$1; SUCCESS=$2; TYPE=$3
	
	# - set already done check strings -
	# TODO: maybe set more "already done" strings ?
	ALREADY=""
	if [ "$TYPE" == "install" ]; then ALREADY="already installed"; fi
	if [ "$TYPE" == "activate" ]; then ALREADY="already activated"; fi
	# 1.0.7: fix activate to deactivate
	if [ "$TYPE" == "deactivate" ]; then ALREADY="already deactivated"; fi
	if [ "$TYPE" == "delete" ]; then ALREADY="already deleted"; fi
	# 1.0.7: added already updated string
	if [ "$TYPE" == "update" ]; then ALREADY="already updated"; fi
	
	# if [[ "$OUTPUT" == *"Error"* ]]; then
	
		# if [[ "$OUTPUT" == *"PHP Parse Error"* ]]; then
		#	echo "";		
		# fi

		# if [[ "$OUTPUT" == *"PHP Warning"* ]]; then
		#	echo "";		
		# fi

		# - database error -
		if [[ "$OUTPUT" == *"Error establishing a database connection"* ]]; then

			RESULT="failed"

			# - check mysql service status -
			if [ -z "$YMLPATH" ] || [ -z "$ALIAS" ] || [ -z "$SSH" ]; then
				STATUS=$(netstat -vulntp | grep -i mysql)
				if [ -z "$STATUS" ]; then
					yellow "**"; echo " Restarting MySQL Server and retrying..."
					RESTART=$(service mysql restart)
					echo "$RESTART"			
				fi
			fi
			return
		fi
		
	# fi;
	
	if [ -n "$SUCCESS" ] && [[ "$OUTPUT" == *"$SUCCESS"* ]]; then
		RESULT="success"
	elif [ -n "$ALREADY" ] && [[ "$OUTPUT" == *"$ALREADY"* ]]; then 
		RESULT="success"
	else
		RESULT="failed"
	fi
	
}

# -------------------------- #
# Create Command Combo Array #
# -------------------------- #
function createarray {

	ARRAY=()	
	ARRAY[0]="$1""$2"
	ARRAY[1]="$1""$2""s"
	ARRAY[2]="$1""_""$2"
	ARRAY[3]="$1""_""$2""s"
	ARRAY[4]="$1""-""$2"
	ARRAY[5]="$1""-""$2""s"
	ARRAY[6]="$2""$1"
	ARRAY[7]="$2""s""$2"
	ARRAY[8]="$2""_""$1"
	ARRAY[9]="$2""s_""$1"
	ARRAY[10]="$2""-""$1"
	ARRAY[11]="$2""s-""$2"
	
	if [ -n "$3" ] && [ -n "$4" ]; then
		ARRAY[12]="$3""$4"
		ARRAY[13]="$3""$4""s"
		ARRAY[14]="$3""_""$4"
		ARRAY[15]="$3""_""$4""s"
		ARRAY[16]="$3""-""$4"
		ARRAY[17]="$3""-""$4""s"
		ARRAY[18]="$4""$3"
		ARRAY[19]="$4""s""$3"
		ARRAY[20]="$4""_""$3"
		ARRAY[21]="$4""s_""$4"
		ARRAY[22]="$4""-""$3"
		ARRAY[23]="$4""s-""$3"
	fi
}

# -------------------------- #
# Check for Element in Array # 
# -------------------------- #
function checkarray {
	local MATCH; MATCH=$1; INARRAY=""
	for ELEMENT in "${ARRAY[@]}"; do
		if [[ "$ELEMENT" == "$MATCH" ]]; then 
			INARRAY="1"; echo "1"; return
		fi
	done
}

# note output elements and matches but may break things
function checkarraydebug {
	local MATCH; MATCH=$1; INARRAY=""
	for ELEMENT in "${ARRAY[@]}"; do
		white "$ELEMENT"" - ""$MATCH"
		if [[ "$ELEMENT" == "$MATCH" ]]; then 
			white " (MATCHED)"
			INARRAY="1"; return
		fi
		echo ""
	done
}

# ------------ #
# Check Source #
# ------------ #
# 1.0.4: added for handling zip sources
function checksource {

	GIT=""; ZIP=""; URL=""
	
	INSTALLTEMP="$SITEPATH""install-temp"
	
	# TODO: - handle git repository sources -
	# if [ "${SOURCEPATH:(-4):4}" == ".git" ] || [ "${SOURCEPATH:(-4):4}" == ".GIT" ]; then
	#	GITVER=$(git --version)
	#	if [[ "$GITVER" == *"Git version"* ]]; then
	#		rm -rf "$INSTALLTEMP"
	#		mkdir "$INSTALLTEMP"
	#		cd "$INSTALLTEMP"
	#		git clone "$SOURCEPATH"
	#		SOURCEPATH="$INSTALLTEMP"
	#		GIT="true"
	#	else
	#		red "Error."; printf " Git does not seem to be installed!"; echo ""
	#		SOURCEPATH=""
	#	fi
	# fi

	# - handle .zip source files -
	if [ "${SOURCEPATH:(-4):4}" == ".zip" ] || [ "${SOURCEPATH:(-4):4}" == ".ZIP" ]; then

		# - make temporary directory -
		rm -rf "$INSTALLTEMP"
		mkdir "$INSTALLTEMP"
		cd "$INSTALLTEMP"

		if [ "${SOURCEPATH:0:4}" == "http" ] || [ "${SOURCEPATH:0:4}" == "HTTP" ]; then
			# - handle http source zip -
			yellow "***"; printf "Downloading source from URL for "; cyan "$SOURCESLUG"; echo "..."
			wget "$SOURCEPATH"
			FILENAME=$(basename "$SOURCEPATH")
			if [ -f "$INSTALLTEMP""/""$FILENAME" ]; then
				unzip "$FILENAME"
				SOURCEPATH="$INSTALLTEMP""/""$SOURCESLUG""/"
				ZIP="true"; URL="true"
			else
				red "Error!"; printf " Source Zip download failed for "; cyan "$SOURCESLUG"; printf ": "; yellow "$SOURCEPATH"; echo " Skipping."
				SOURCEPATH=""
			fi

		elif [ -f "$SOURCEPATH" ]; then
			# - handle local file source zip -
			unzip -d "$INSTALLTEMP" "$SOURCEPATH"
			ZIP="true"
			SOURCEPATH="$INSTALLTEMP""/""$SOURCESLUG""/"
		else
			red "Error!"; printf " Source Zip not found for "; cyan "$SOURCESLUG"; printf ": "; yellow "$SOURCEPATH"; echo " Skipping."
		fi

		if [ "$SOURCETYPE" == "plugin" ] || [ "$SOURCETYPE" == "theme" ]; then
			if [ ! -d "$SOURCEPATH" ]; then
				red "Error!"; printf " Source Zip did not contain a directory matching source slug "; cyan "$SOURCESLUG"; echo " Aborting."
				rm -rf "$INSTALLTEMP"
				SOURCEPATH=""
			fi
		fi

	fi
}

# -------------------- #
# === YAML HELPERS === #
# -------------------- #

# ------------- #
# Fix YAML File #
# ------------- #
function fix_yaml {
	
	LINES=$(cat "$1")
	while IFS= read -r -a LINE || [ -n "$LINE" ]; do
		TESTLINE=$(echo "$LINE" | awk '{$1=$1;print}')
		CHAR="${TESTLINE:0:1}"
		if [ ! "$CHAR" == "#" ]; then
			if [ "$CHAR" == "@" ] || [ "$CHAR" == "~" ]; then
				echo "alias_""${TESTLINE:1}"
			else
				CHARS="${TESTLINE:0:3}"
				if [ "$CHARS" == "- @" ]; then
					echo " - alias_""${TESTLINE:3}"
				else
					echo "$LINE"
				fi
			fi
		fi
	done <<< "$LINES"
}

# --------------- #
# Parse YAML File #
# --------------- #
# ref: https://stackoverflow.com/a/51789677/5240159
# source: https://github.com/mrbaseman/parse_yaml.git
function parse_yaml {

   local prefix=$2
   local separator=${3:-_}
   local s='[[:space:]]*' w='[a-zA-Z0-9_]*' fs=${fs:-$(echo @|tr @ '\034')} i=${i:-  }
     
   cat $1 | \
   awk -F$fs "{multi=0; 
       if(match(\$0,/$s\|$s\$/)){multi=1; sub(/$s\|$s\$/,\"\");}
       if(match(\$0,/$s>$s\$/)){multi=2; sub(/$s>$s\$/,\"\");}
       while(multi>0){
           str=\$0; gsub(/^$s/,\"\", str);
           indent=index(\$0,str);
           indentstr=substr(\$0, 0, indent-1) \"$i\";
           obuf=\$0;
           getline;
           while(index(\$0,indentstr)){
               obuf=obuf substr(\$0, length(indentstr)+1);
               if (multi==1){obuf=obuf \"\\\\n\";}
               if (multi==2){
                   if(match(\$0,/^$s\$/))
                       obuf=obuf \"\\\\n\";
                       else obuf=obuf \" \";
               }
               getline;
           }
           sub(/$s\$/,\"\",obuf);
           multi=0;
           if(match(\$0,/$s\|$s\$/)){multi=1; sub(/$s\|$s\$/,\"\");}
           if(match(\$0,/$s>$s\$/)){multi=2; sub(/$s>$s\$/,\"\");}
       }
   print}" | \
   sed  -e "s|^\($s\)?|\1-|" \
       -ne "s|^$s#.*||;s|$s#[^\"']*$||;s|^\([^\"'#]*\)#.*|\1|;t1;t;:1;s|^$s\$||;t2;p;:2;d" | \
   sed -ne "s|,$s\]$s\$|]|" \
        -e ":1;s|^\($s\)\($w\)$s:$s\(&$w\)\?$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1\2: \3[\4]\n\1$i- \5|;t1" \
        -e "s|^\($s\)\($w\)$s:$s\(&$w\)\?$s\[$s\(.*\)$s\]|\1\2: \3\n\1$i- \4|;" \
        -e ":2;s|^\($s\)-$s\[$s\(.*\)$s,$s\(.*\)$s\]|\1- [\2]\n\1$i- \3|;t2" \
        -e "s|^\($s\)-$s\[$s\(.*\)$s\]|\1-\n\1$i- \2|;p" | \
   sed -ne "s|,$s}$s\$|}|" \
        -e ":1;s|^\($s\)-$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1- {\2}\n\1$i\3: \4|;t1" \
        -e "s|^\($s\)-$s{$s\(.*\)$s}|\1-\n\1$i\2|;" \
        -e ":2;s|^\($s\)\($w\)$s:$s\(&$w\)\?$s{$s\(.*\)$s,$s\($w\)$s:$s\(.*\)$s}|\1\2: \3 {\4}\n\1$i\5: \6|;t2" \
        -e "s|^\($s\)\($w\)$s:$s\(&$w\)\?$s{$s\(.*\)$s}|\1\2: \3\n\1$i\4|;p" | \
   sed  -e "s|^\($s\)\($w\)$s:$s\(&$w\)\(.*\)|\1\2:\4\n\3|" \
        -e "s|^\($s\)-$s\(&$w\)\(.*\)|\1- \3\n\2|" | \
   sed -ne "s|^\($s\):|\1|" \
        -e "s|^\($s\)\(---\)\($s\)||" \
        -e "s|^\($s\)\(\.\.\.\)\($s\)||" \
        -e "s|^\($s\)-$s[\"']\(.*\)[\"']$s\$|\1$fs$fs\2|p;t" \
        -e "s|^\($s\)\($w\)$s:$s[\"']\(.*\)[\"']$s\$|\1$fs\2$fs\3|p;t" \
        -e "s|^\($s\)-$s\(.*\)$s\$|\1$fs$fs\2|" \
        -e "s|^\($s\)\($w\)$s:$s[\"']\?\(.*\)$s\$|\1$fs\2$fs\3|" \
        -e "s|^\($s\)[\"']\?\([^&][^$fs]\+\)[\"']$s\$|\1$fs$fs$fs\2|" \
        -e "s|^\($s\)[\"']\?\([^&][^$fs]\+\)$s\$|\1$fs$fs$fs\2|" \
        -e "s|$s\$||p" | \
   awk -F$fs "{
      gsub(/\t/,\"        \",\$1);
      if(NF>3){if(value!=\"\"){value = value \" \";}value = value  \$4;}
      else {
        if(match(\$1,/^\&/)){anchor[substr(\$1,2)]=full_vn;getline};
        indent = length(\$1)/length(\"$i\");
        vname[indent] = \$2;
        value= \$3;
        for (i in vname) {if (i > indent) {delete vname[i]; idx[i]=0}}
        if(length(\$2)== 0){  vname[indent]= ++idx[indent] };
        vn=\"\"; for (i=0; i<indent; i++) { vn=(vn)(vname[i])(\"$separator\")}
        vn=\"$prefix\" vn;
        full_vn=vn vname[indent];
        if(vn==\"$prefix\")vn=\"$prefix$separator\";
        if(vn==\"_\")vn=\"__\";
      }
      assignment[full_vn]=value;
      if(!match(assignment[vn], full_vn))assignment[vn]=assignment[vn] \" \" full_vn;
      if(match(value,/^\*/)){
         ref=anchor[substr(value,2)];
         for(val in assignment){
            if(index(val, ref)==1){
               tmpval=assignment[val];
               sub(ref,full_vn,val);
               if(match(val,\"$separator\$\")){
                  gsub(ref,full_vn,tmpval);
               } else if (length(tmpval) > 0) {
                  printf(\"%s=\\\"%s\\\"\n\", val, tmpval);
               }
               assignment[val]=tmpval;
            }
         }
      } else if (length(value) > 0) {
         printf(\"%s=\\\"%s\\\"\n\", full_vn, value);
      }
   }END{
      asorti(assignment,sorted);
      for(val in sorted){
         if(match(sorted[val],\"$separator\$\"))
            printf(\"%s=\\\"%s\\\"\n\", sorted[val], assignment[sorted[val]]);
      }
   }"
}

# -------------- #
# Load YAML File #
# -------------- #
function load_yaml {

	# - fix @ symbols (for parsing site aliases) -
	FIXED=$(fix_yaml "$YMLPATH")
	if [ "$DEBUG" == "true" ]; then 
		white "$YMLPATH"; echo " Contents:"; echo "$FIXED"
	 fi
		
	# - parse the fixed YAML data -
	PARSED=$(parse_yaml <<< "$FIXED")
	if [ "$DEBUG" == "true" ]; then 
		echo ""; echo "Parsed Contents: "; echo "$PARSED"
	fi
	
	# - load parsed data as variables -
	eval "$PARSED"
	
	# TODO: load inherited and reload YAML ?
	if [ -n "$___inherit" ]; then
		# if [ "$DEBUG" == "true" ]; then echo "$___inherit"; fi
		echo "Inherit YML Config File: ""$___inherit"
	fi	
}


# --------------------- #
# === CORE COMMANDS === #
# --------------------- #

# ---------- #
# Debug Info #
# ---------- #
function wpclidebug {
	COMMAND="$WP"" --debug --info"
	OUTPUT=$($COMMAND)
	echo "$OUTPUT"
}

# ------------- #
# Check Version #
# ------------- #
function checkversion {
	
	# - define success -
	SUCCESS="WordPress version"

	# - get core version -
	# local VERSIONPATH; local VERSION
	# VERSIONPATH="$SITEPATH""wp-includes/version.php"
	# VERSION=$(grep -m 1 "wp_version = " "$VERSIONPATH" | cut -d \' -f2)
	COMMAND="$WP"" core version --extra"
	OUTPUT=$($COMMAND)

	# - maybe try again -
	checkresult "$OUTPUT" "$SUCCESS"
	if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

	if [[ "$OUTPUT" == *"WordPress version"* ]]; then
	
		# - get version data from output -
		VERSION=$(grep "WordPress version:" <<< "$OUTPUT" | awk '{print $3}')
		DBVERSION=$(grep "Database revision:" <<< "$OUTPUT" | awk '{print $3}')
		MCEVERSION=$(grep "TinyMCE version:" <<< "$OUTPUT" | awk '{print $3}')
		LOCALE=$(grep "Package language:" <<< "$OUTPUT" | awk '{print $3}')

		# - output coloured version info -
		white "Site: "; green "$SITENAME"; echo ""
		white "Path: "; cyan "$SITEPATH"; echo ""
		white "WordPress version: "; yellow "$VERSION"; echo ""
		white "Database revision: "; yellow "$DBVERSION"; echo ""
		white "TinyMCE version: "; yellow "$MCEVERSION"; echo ""
		white "Package language: "; yellow "$LOCALE"; echo ""
		
	else
		# - output error message -
		red "Error."; echo " Could not detect WordPress version."

	fi
}

# ------------------ #
# Check Core Updates #
# ------------------ #
function checkcore {

	# - check for core updates -
	yellow "*"; printf " Checking for core updates on "; green "$SITENAME"; echo "..."
	COMMAND="$WP"" core check-update --format=csv"
	OUTPUT=$($COMMAND)

	# - output if core updates available -
	if [[ "$OUTPUT" == *"version,update_type,package"* ]]; then
		while IFS= read -r -a LINE; do
			if [[ "$LINE" != *"version,update_type,package"* ]]; then
				if [[ "$LINE" == *","* ]]; then
					VERSION=$(awk -F',' '{print $1}' <<< "$LINE")
					TYPE=$(awk -F',' '{print $2}' <<< "$LINE")
					white "Update to WordPress "; yellow "$VERSION"; white " ("; yellow "$TYPE"; white ") available."; echo ""
				fi
			fi
		done <<< "$OUTPUT"
	else
		echo "No updates available, WordPress core is up to date."
	fi

}

# ----------- #
# Verify Core #
# ----------- #
function verifycore {

	# TODO: define SUCCESS for verify checksums?
	# SUCCESS=""

	# - get core version -
	# local VERSIONPATH; local VERSION
	# VERSIONPATH="$SITEPATH""wp-includes/version.php"
	# VERSION=$(grep -m 1 "wp_version = " "$VERSIONPATH" | cut -d \' -f2)
	# 1.0.4: split commands to avoid 'Too mny positional arguments' error
	COMMAND="$WP"" core version --extra"
	VERSION=$($COMMAND)
	VERSION=$(grep 'WordPress version:' <<< "$VERSION")
	VERSION=$(cut -d ' ' -f3 <<< "$VERSION")

	# - get active language locale -
	# 1.0.5: added locale detection for verify checksums
	COMMAND="$WP"" language core list --status=active"
	LOCALE=$($COMMAND)
	LOCALE=$(grep 'active' <<< "$LOCALE")
	LOCALE=$(cut -f1 <<< "$LOCALE")

	# - output verify checksum message -
	yellow "***"; printf " Verifying core checksums for "; green "$SITENAME"; printf " (WP "; yellow "$VERSION"; echo ")"
	
	# - set command and execute -
	COMMAND="$WP"" core verify-checksums --version=""$VERSION"" --locale=""$LOCALE"" --skip-plugins"
	OUTPUT=$($COMMAND)
	
	# - check result and maybe try again -
	checkresult "$OUTPUT"
	if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

	echo "$OUTPUT"
}

# ----------- #
# Update Core #
# ----------- #
function updatecore {
	
	local VERSION=$1

	# TODO: define SUCCESS for core update ?
	SUCCESS=""
	
	# - maybe unlock core -
	if [ "$SITELOCKING" == "true" ]; then unlockcore; fi
	
	# - attempt core update -
	if [ -n "$VERSION" ]; then
		if [ "$VERSION" == "major" ]; then
			# - update to latest version -
			# yellow "***"; printf " Updating core on "; green "$SITENAME"; printf " ("; yellow "$VERSION"; echo ")..."
			COMMAND="$WP"" core update --skip-plugins --version=""$VERSION"
		elif [ "$VERSION" == "minor" ] || [ "$VERSION" == "patch" ]; then
				# - update to minor version
				if [ "$VERSION" == "patch" ]; then VERSION="minor"; fi
				yellow "***"; printf " Updating core on "; green "$SITENAME"; printf " ("; yellow "$VERSION"; echo " only)..."
				COMMAND="$WP"" core update --skip-plugins --version=""$VERSION"
		else
			# - force update to specific version -
			yellow "***"; printf " Updating core on "; green "$SITENAME"; printf " to Version "; yellow "$VERSION"; echo "..."
			COMMAND="$WP"" core update --skip-plugins --version=""$VERSION"" --force"
		fi
	else
		# - update to latest version -
		yellow "***"; printf " Updating core on "; green "$SITENAME"; echo "..."
		COMMAND="$WP"" core update --skip-plugins"	
	fi
	
	# - execute command -
	OUTPUT=$($COMMAND)
	
	# - maybe try again -
	# 1.0.7: added third argument for already updated
	checkresult "$OUTPUT" "$SUCCESS" update
	if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi
	
	echo "$OUTPUT"
	
	# - maybe relock core -
	if [ "$SITELOCKING" == "true" ]; then lockcore; fi
}

# ------------ #
# Install Core #
# ------------ #
function installcore {

	local VERSION; local LOCALE; local TEMPCOREPATH
	
	# - set values -
	VERSION=$1; LOCALE=$2;

	# TODO: use local tmp path for SSH?
	TEMPCOREPATH="$SITEPATH""install-temp/"

	# 1.0.4: ensure not overwriting existing install
	WPCONFIG="$SITEPATH""wp-config.php"
	if [ "$REINSTALL" != "true" ] && [ -f "$WPCONFIG" ]; then
		red "Error!"; printf " Core is already installed for "; green "$SITENAME"; echo " You can reinstall with reinstallcore.";
		return
	fi

	# - maybe unlock core -
	if [ "$SITELOCKING" == "true" ]; then unlockcore; fi

	# TODO: install core for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot install core for YML configs (yet.)"; return
	fi

	# TODO: install core for site aliases
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot install core for site aliases (yet.)"; returnE
	fi

	# TODO: SSH version of this?
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot install core for SSH sites (yet.)"; return
	fi
	
	# - clear new core temp directory -
	rm -rf "$TEMPCOREPATH"
	mkdir "$TEMPCOREPATH"
	if [ -n "$SITEGROUP" ]; then
		chown -R "$SITEUSER":"$SITEGROUP" "$TEMPCOREPATH"
	else
		chown -R "$SITEUSER" "$TEMPCOREPATH"
	fi
	
	# - download core -
	if [ -z "$LOCALE" ] && [ -z "$VERSION" ]; then
		yellow "***"; printf " Installing WordPress Core for "; green "$SITENAME"; echo "..."
		COMMAND="$WP"" core download --path=""$TEMPCOREPATH"	
	elif [ -z "$LOCALE" ]; then
		yellow "***"; printf " Installing WordPress Core (Version: "; yellow "$VERSION"; printf ") for "; green "$SITENAME"; echo "..."
		COMMAND="$WP"" core download --version=""$VERSION"" --path=""$TEMPCOREPATH"
	else 
		yellow "***"; printf " Installing WordPress Core (Version: "; yellow "$VERSION"; printf ", Locale: "; yellow "$LOCALE"; printf ") for "; green "$SITENAME"; echo "..."
		COMMAND="$WP"" core download --version=""$VERSION"" --locale=""$LOCALE"" --path=""$TEMPCOREPATH"
	fi
	
	# - execute command -
	OUTPUT=$($COMMAND)
	
	# - check result success -
	SUCCESS="Success: WordPress downloaded."
	checkresult "$OUTPUT" "$SUCCESS"
	
	# - maybe retry core download -
	# if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

	echo "$OUTPUT"

	if [ "$RESULT" == "success" ]; then

		# - output core syncing message -
		yellow "***"; printf " Syncing Downloaded Core to "; cyan "$SITEPATH"; echo "..."
	
		# - remove wp-content directory from temporary core to prevent overwriting -
		if [ "$REINSTALL" == "true" ]; then
			# TODO: SSH version of this?
			rm -rf "$TEMPCOREPATH"/wp-content
		fi
	
		# - sync from temp core dir to core dir -
		# TODO: maybe use with --backup option?
		# TODO: SSH version of this
		rsync --delay-updates --remove-source-files -av "$TEMPCOREPATH" "$SITEPATH"
		
		# - cleanup temp core directory -
		# SSH version of this?
		rm -rf "$TEMPCOREPATH"
	fi
	
	# - maybe relock core -
	if [ "$SITELOCKING" == "true" ]; then lockcore; fi
}

# -------------- #
# Reinstall Core #
# -------------- #
function reinstallcore {
	
	local VERSION; local LOCALE
	
	# - get current version -
	# local VERSION; local VERSIONPATH;
	# VERSIONPATH="$SITEPATH""wp-includes/version.php"
	# VERSION=$(grep -m 1 "wp_version = " "$VERSIONPATH" | cut -d \' -f2)
	# 1.0.4: split commands to avoid 'Too many positional arguments' error
	COMMAND="$WP"" core version --extra"
	VERSION=$($COMMAND)
	VERSION=$(grep 'WordPress version:' <<< "$VERSION")
	VERSION=$(cut -d ' ' -f3 <<< "$VERSION")
	
	# - get active language locale -
	# note: older versions of WP CLI use 'wp core language list' (so update!)
	# 1.0.4: split commands to avoid 'Too many positional arguments' error
	COMMAND="$WP"" language core list --status=active"
	LOCALE=$($COMMAND)
	LOCALE=$(grep 'active' <<< "$LOCALE")
	LOCALE=$(cut -f1 <<< "$LOCALE")

	# - output reinstalling core message -
	yellow "***"; printf " Reinstalling Core (Version: "; yellow "$VERSION"; printf ", Locale: "; yellow "$LOCALE"; printf ") for "; green "$SITENAME"; echo "..."

	# - set reinstalling flag -
	REINSTALL="true"

	# - reinstall existing version / locale -
	installcore "$VERSION" "$LOCALE"
}

# --------- #
# Lock Core #
# --------- #
function lockcore {

	local INCLUDES; local ADMIN;
	
	# - set paths -
	INCLUDES="$SITEPATH""/wp-includes"
	ADMIN="$SITEPATH""/wp-admin"

	# TODO: lock core for YML configs ?
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot lock core for YML configs (yet.)"; return
	fi
	
	# TODO: lock core for aliases ?
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot lock core for site aliases (yet.)"; return
	fi
	
	# TODO: lock core for SSH ?
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot lock core for SSH sites (yet.)"; return
	fi

	# - output locking message -
	yellow "**"; printf " Locking "; white "$SITEPATH"; echo "..."
	
	# - lock core base files -
	# note: skips license.txt and readme.html
	BASEFILES=(".htaccess" "index.php" "wp-activate.php" "wp-blog-header.php" "wp-comments-post.php" "wp-config.php" "wp-config-sample.php" "wp-cron.php" "wp-links-opml.php" "wp-load.php" "wp-login.php" "wp-mail.php" "wp-settings.php" "wp-signup.php" "wp-trackback.php" "xmlrpc.php")
	for BASEFILE in "${BASEFILES[@]}"; do
		FILEPATH="$SITEPATH""/""$BASEFILE"
		if [ -e "$FILEPATH" ]; then
		 	chattr +i "$FILEPATH"
		else
			red "Error!"; white " $BASEFILE"; echo " not found!"
	 	fi
	done
	
	# - lock wp-includes recursively - 
	if [ -d "$INCLUDES" ]; then
		chattr -R +i "$INCLUDES"
	else 
		red "Error!"; echo " /wp-includes/ directory not found!"
	fi
	
	# - lock wp-admin recursively - 
	if [ -d "$ADMIN" ]; then
		chattr -R +i "$ADMIN"
		# 1.0.3: attempt to preserve wp-admin error log writeability
		if [ -f "$ADMIN""php_errors.log" ]; then
			chattr -i "$ADMIN""php_errors.log"
		fi
	else
		red "Error!"; echo " /wp-admin/ directory not found!"
	fi
}

# ----------- #
# Unlock Core #
# ----------- #
function unlockcore {

	local INCLUDES; local ADMIN
	
	# - set paths -
	INCLUDES="$SITEPATH""/wp-includes"
	ADMIN="$SITEPATH""/wp-admin"

	# TODO: unlock core for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot unlock core for YML configs (yet.)"; return
	fi

	# TODO: unlock core for site aliases
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot unlock core for site aliases (yet.)"; return
	fi

	# TODO: unlock core for SSH ?
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot unlock core for SSH sites (yet.)"; return
	fi
	
	# - output unlock message -
	yellow "**"; printf " Unlocking "; white "$SITEPATH"; echo "..."
	
	# - unlock core base files -
	# note: skip license.txt and readme.html
	BASEFILES=(".htaccess" "index.php" "wp-activate.php" "wp-blog-header.php" "wp-comments-post.php" "wp-config.php" "wp-config-sample.php" "wp-cron.php" "wp-links-opml.php" "wp-load.php" "wp-login.php" "wp-mail.php" "wp-settings.php" "wp-signup.php" "wp-trackback.php" "xmlrpc.php")
	for BASEFILE in "${BASEFILES[@]}"; do
		FILEPATH="$SITEPATH""/""$BASEFILE"
		if [ -e "$FILEPATH" ]; then
		 	chattr -i "$FILEPATH"
		else
			red "Error!"; white " ""$BASEFILE"; echo " not found!"
		fi
	done
	
	# - unlock wp-includes recursively -
	if [ -d "$INCLUDES" ]; then
		chattr -R -i "$INCLUDES"
	else
		red "Error!"; echo " /wp-includes/ directory not found!"
	fi
	
	# - unlock wp-admin recursively -
	if [ -d "$ADMIN" ]; then
		chattr -R -i "$ADMIN"
	else
		red "Error!"; echo " /wp-admin/ directory not found!"
	fi
}

# --------------- #
# Check Core Lock #
# --------------- #
function checkcorelock {
	
	local INCLUDES; local ADMIN
	
	INCLUDES="$SITEPATH""/wp-includes"
	ADMIN="$SITEPATH""/wp-admin"
	# local LOCKFILE=$SITENAME".lok"

	# TODO: check core lock for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot check core lock for YML configs (yet.)"; return
	fi
	
	# TODO: check core lock for site aliases
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot check core lock for site aliases (yet.)"; return
	fi

	# TODO: check lock core for SSH ?
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot check core lock for SSH sites (yet.)"; return
	fi
	
	# - output lock check message -
	yellow "**"; printf " Checking Core file locks for "; green "$SITENAME"; echo "..."
	
	# - check lock for core base files -
	# TODO: compare to core base file list
	# BASEFILES=(".htaccess" "index.php" "wp-activate.php" "wp-blog-header.php" "wp-comments-post.php" "wp-config.php" "wp-config-sample.php" "wp-cron.php" "wp-links-opml.php" "wp-load.php" "wp-login.php" "wp-mail.php" "wp-settings.php" "wp-signup.php" "wp-trackback.php" "xmlrpc.php")
	BASEFILES=$(lsattr -l "$SITEPATH" | grep " Immutable")
	# | tee $LOCKFILE
	COUNT=$(echo -n "$BASEFILES" | grep -c '^')
	echo "$COUNT"" immutable base files"
	
	# - check lock for wp-includes dir files -
	if [ -d "$INCLUDES" ]; then
		INCFILES=$(lsattr -R -l "$INCLUDES" | grep " Immutable")
		# | tee -a $LOCKFILE
		COUNT=$(echo -n "$INCFILES" | grep -c '^') 
		echo "$COUNT"" immutable includes files"
	fi
	
	# - check lock for wp-admin dir files -
	if [ -d "$ADMIN" ]; then
		ADMINFILES=$(lsattr -R -l "$ADMIN" | grep " Immutable")
		# | tee -a $LOCKFILE
		COUNT=$(echo -n "$ADMINFILES" | grep -c '^')
		echo "$COUNT"" immutable admin files"
	fi
}

# ------------------------ #
# Check File Owners/Groups #
# ------------------------ #
function checkowners {

	# TODO: check owners for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot check permissions for YML configs (yet.)"; return
	fi

	# TODO: check owner permissions for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot check permissions for site aliases (yet.)"; return
	fi

	# TODO: lock core for SSH ?
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot check permissions for SSH sites (yet.)"; return
	fi

	# - check permissions -
	if [ -n "$SITEGROUP" ]; then
		# - check owner / group mismatches -
		yellow "*"; printf " Searching '"; green "$SITENAME"; echo "' for files with mismatching owner/group permissions..."
		OUTPUT=$(find "$SITEPATH" \( ! -user "$SITEUSER" -o ! -group "$SITEGROUP" \) )
	else 
		# - check for owner mismatches -
		yellow "*"; printf " Searching '"; green "$SITENAME"; echo "' for files with mismatching owner permissions..."
		OUTPUT=$(find "$SITEPATH" ! -user "$SITEUSER")
	fi
	echo "$OUTPUT"
}

# ---------------------- #
# Fix File Owners/Groups #
# ---------------------- #
function fixowners {

	# TODO: fix owner permissions for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot fix permissions for YML configs (yet.)"; return
	fi

	# TODO: fix owner permissions for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot fix permissions for site aliases (yet.)"; return
	fi

	# TODO: fix owner permisions for SSH ?
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot fix permissions for for SSH sites (yet.)"; return
	fi
	
	# - maybe unlock core -
	if [ "$SITELOCKING" == "true" ]; then unlockcore; fi
	
	# - set core base files -
	BASEFILES=(".htaccess" "index.php" "wp-activate.php" "wp-blog-header.php" "wp-comments-post.php" "wp-config.php" "wp-config-sample.php" "wp-cron.php" "wp-links-opml.php" "wp-load.php" "wp-login.php" "wp-mail.php" "wp-settings.php" "wp-signup.php" "wp-trackback.php" "xmlrpc.php")
	
	# - fix permissions -
	if [ -n "$SITEGROUP" ]; then
		# - fix owner / group permissions -
		yellow "***"; printf " Fixing owner/group permissions on '"; green "$SITENAME"; echo "'..."
		# chown -R "$SITEUSER":"$SITEGROUP" "$SITEPATH"

		for BASEFILE in "${BASEFILES[@]}"; do
			chown "$SITEUSER":"$SITEGROUP" "$SITEPATH"/"$BASEFILE"
		done
		chown -R "$SITEUSER":"$SITEGROUP" "$SITEPATH"/wp-content
		chown -R "$SITEUSER":"$SITEGROUP" "$SITEPATH"/wp-admin
		chown -R "$SITEUSER":"$SITEGROUP" "$SITEPATH"/wp-includes
	else
		# - fix owner permissions -
		yellow "***"; printf " Fixing owner permissions on '"; green "$SITENAME"; echo "'..."
		chown -R "$SITEUSER" "$SITEPATH"
		
		for BASEFILE in "${BASEFILES[@]}"; do
		 	chown "$SITEUSER" "$SITEPATH"/"$BASEFILE"
		done
		chown -R "$SITEUSER" "$SITEPATH"/wp-content
		chown -R "$SITEUSER" "$SITEPATH"/wp-admin
		chown -R "$SITEUSER" "$SITEPATH"/wp-includes
	fi

	# - maybe relock core -	
	if [ "$SITELOCKING" == "true" ]; then lockcore; fi
}

# ---------------- #
# Get Option Value #
# ---------------- #
# 1.0.4: added simple get option function
function getoption {

	local FORMAT

	# TODO: allow for other output formats?
	FORMAT="json"
	
	COMMAND="$WP"" option get ""$OPTION"" --format=""$FORMAT"
	VALUE=$($COMMAND)
	FAIL="Could not get '""$OPTION""'"
	if [[ "$VALUE" == *"$FAIL"* ]]; then 
		exit 1
	else
		echo "$VALUE"
	fi
}

# ------------ #
# Search Files #
# ------------ #
# function searchfiles {

	# - output searching for string message -
	# yellow "*"; printf " Searching files for string '"; printf "$STRING"; printf "'"; on "; green "$SITENAME"; echo ": "

	# COMMAND="fgrep -R '""$STRING""' ""$SITEPATH"
	# echo "$COMMAND"
	# fgrep -R '"$STRING"' "$SITEPATH"
	# OUTPUT=$($COMMAND)
	# echo "$OUTPUT"
# }

# --------------- #
# Search Database #
# --------------- #
# function searchdatabase {
# 	COMMAND="$WP"" --dry-run search-replace '""$STRING""' ''"
# 	OUTPUT=$($COMMAND)
#	echo "$OUTPUT"
# }

# ----------- #
# Update List #
# ----------- #
function updatelist {

	# - update list message -
	yellow "**"; printf " Listing all updates for "; green "$SITENAME"; echo ""

	# - check core updates -
	checkcore

	# - check theme updates -
	listthemes "updates"

	# - check plugin updates -
	listplugins "updates"	
}


# ----------------------- #
# === PLUGIN COMMANDS === #
# ----------------------- #

# ------------ #
# List Plugins #
# ------------ #
# 1.0.3: renamed from checkplugin, deprecated old listplugin function
function listplugins {
	
	local PLUGIN; PLUGIN=$1

	# - output checking plugins message -
	yellow "*"; printf " Listing plugin(s) on "; green "$SITENAME"; echo "..."
	
	# - get plugin list -
	# 1.0.4: split commands to avoid 'Too many positional arguments' error
	COMMAND="$WP"" plugin list --fields=name,status,version,update,update_version --skip-plugins --format=csv"
	INFO=$($COMMAND)
	INFO=$(tail -n +2 <<< "$INFO")

	# - get all listed plugins -
	I=0; ALLPLUGINS=(); LINES=()
	while IFS= read -r -a LINE; do
		ALLPLUGINS[$I]=$(awk -F',' '{print $1}' <<< "$LINE"); 
		LINES[$I]=$LINE; ((++I))
	done <<< "$INFO"

	# - empty = list all plugins -
	if [ -z "$PLUGIN" ]; then
		PLUGINS=("${ALLPLUGINS[@]}")
		ALL="true"
	else
		# - read specified plugins -
		IFS="," read -r -a PLUGINS <<< "$PLUGIN"

		# - check for limit switches -
		I=0; NEWPLUGINS=()
		ALL=""; ACTIVES=""; INACTIVES=""; MUSTUSES=""; DROPINS=""; UPDATES=""; CHANGED=""
		for APLUGIN in "${PLUGINS[@]}"; do
			REMOVE=""
			if [ "$APLUGIN" == "all" ]; then ALL="true"; fi
			if [ "$APLUGIN" == "actives" ]; then ACTIVES="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$APLUGIN" == "inactives" ]; then INACTIVES="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$APLUGIN" == "mustuses" ]; then MUSTUSES="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$APLUGIN" == "dropins" ]; then DROPINS="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$APLUGIN" == "updates" ]; then UPDATES="true"; REMOVE="true"; CHANGED="true"; fi
			# 1.0.4: fix to missing space after !
			if [ ! "$REMOVE" == "true" ]; then NEWPLUGINS[$I]=$APLUGIN; ((++I)); fi
		done

		# - reassign plugin list if changed -
		if [ "$ALL" == "true" ]; then
			PLUGINS=("${ALLPLUGINS[@]}");
		elif [ "$CHANGED" == "true" ]; then 
			PLUGINS=("${NEWPLUGINS[@]}");
		fi
	fi

	# - table headings -
	TABLE=""; OTHER=""
	TABLE+=$(white "PLUGIN"); TABLE+="|"
	TABLE+=$(white "STATUS"); TABLE+="|"
	TABLE+=$(white "VERSION"); TABLE+="|"
	TABLE+=$(white "UPDATES"); TABLE+=$'\r\n'
		
	# - loop plugins -
	I=0; MATCH=""
	for APLUGIN in "${ALLPLUGINS[@]}"; do
	
		ACTIVE=""; INACTIVE=""; MUSTUSE=""; DROPIN=""; UPDATE=""

		# - get plugin info -
		PLUGININFO=${LINES[$I]}

		if [ -n "$PLUGININFO" ]; then

			ROW=$(cyan "$APLUGIN")

			# - split by tabs while preserving columns -
			# ref: https://stackoverflow.com/a/19726834/5240159
			# if [[ ! "$PLUGININFO" == *$'\t' ]]; then PLUGININFO+=$'\t'; fi
			# COLUMNS=()
			# while IFS='' read -r -d$'\t' COLUMN; do
			#   COLUMNS+=("$COLUMN")
			# done <<< "$PLUGININFO"

			# - simplified to split by CSV format -
			IFS=',' read -r -a COLUMNS <<< "$PLUGININFO"

			# - plugin status -
			ROW+="|"
			if [ "${COLUMNS[1]}" == "active" ]; then
				ROW+=$(green "Active"); ACTIVE="true"
			elif [ "${COLUMNS[1]}" == "must-use" ]; then
				ROW+=$(magenta "Must Use"); MUSTUSE="true"
			elif [ "${COLUMNS[1]}" == "dropin" ]; then
				ROW+=$(magenta "Dropin"); DROPIN="true"
			else
				ROW+=$(blue "Inactive"); INACTIVE="true"
			fi

			# - plugin version -
			ROW+="|"; 
			if [ -n "${COLUMNS[2]}" ]; then
				ROW+=$(yellow "${COLUMNS[2]}")
			else 
				ROW+="-"
			fi

			# - plugin updates -
			if [ "${COLUMNS[3]}" == "available" ]; then
				ROW+="|"; ROW+=$(yellow "${COLUMNS[4]}"); ROW+=" available"
				UPDATE="true"
			fi
		# else 	
		#	ROW+="|"; ROW+=$(red "Not Found")
		fi

		# - add row new line -
		ROW+=$'\r\n'

		# - add row if listing all -
		ADDROW=""
		if [ "$ALL" == "true" ]; then ADDROW="true"
		else 
			# - add row if matching a plugin limit filter -
			if [ "$UPDATES" == "true" -a "$UPDATE" == "true" ] \
				|| [ "$ACTIVES" == "true" -a "$ACTIVE" == "true" ] \
				|| [ "$INACTIVES" == "true" -a "$INACTIVE" == "true" ] \
				|| [ "$MUSTUSES" == "true" -a "$MUSTUSE" == "true" ] \
				|| [ "$DROPINS" == "true" -a "$DROPIN" == "true" ]; then
				ADDROW="true"
			fi

			# - check for matching plugin slug -
			if [ -z "$ADDROW" ]; then
				for PLUGIN in "${PLUGINS[@]}"; do
					# echo $PLUGIN" - "$APLUGIN
					if [ "$PLUGIN" == "$APLUGIN" ]; then
						ADDROW="true"
					fi
				done
			fi
		fi

		# - split table rows according to active status -
		if [ "$ADDROW" == "true" ]; then
			MATCH="true"
			if [ "$ACTIVE" == "true" ]; then
				TABLE+=$ROW
			else
				OTHER+=$ROW
			fi
		fi

		((++I))
		
	done

	if [ "$MATCH" == "true" ]; then
		# - add all other rows to active rows -
		TABLE+=$OTHER

		# - output pretty table -	
		OUTPUT=$(column -t -s "|" <<< "$TABLE")
		echo "$OUTPUT"
	else 
		# - output no match found -
		red "Sorry."; echo " No matching plugins were found."
	fi
}

# ----------- #
# Find Plugin #
# ----------- #
# 1.0.8: added find plugin command
function findplugins {

	local PLUGIN; PLUGIN=$1;

	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do
		
		# - check for existing plugin -
		COMMAND="$WP"" plugin is-installed ""$PLUGIN"" --skip-plugins"
		OUTPUT=$($COMMAND)

		# this gets the exit code (where 0 = installed!)
		CHECK=$?
		if [ "$CHECK" == "0" ]; then
			yellow "***"; printf " Plugin "; cyan "$PLUGIN"; printf " "; green "was"; printf " found on "; green "$SITENAME"; echo "."
		else
			yellow "***"; printf " Plugin "; cyan "$PLUGIN"; printf " "; red "was not"; printf " found on "; green "$SITENAME"; echo "."	
		fi

	done
	
}

# ------------- # 
# Verify Plugin #
# ------------- #
# 1.0.5: added command for verifying plugin checksums
function verifyplugin {

	local PLUGIN; PLUGIN=$1
	
	# - loop specified plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do

		# - check against plugin sources -
		# 1.0.5: added checksum for plugin sync sources
		MATCHED=""
		while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

			# - ignore lines starting with # -
			if [ ! "${SOURCE:0:1}" == "#" ]; then

				# - expand source data -
				IFS=" " read -r -a DATA <<< "$SOURCE"
				SOURCETYPE=${DATA[0]}
				SOURCESLUG=${DATA[1]}
				SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

				if [ "$SOURCETYPE" == "plugin" ]; then

					# - check slug match -
					if [ "$PLUGIN" == "$SOURCESLUG" ]; then
						
						MATCHED="true"

						# - output verifying plugin message -
						yellow "***"; printf " Verifying plugin source "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."

						# - handle .zip source files -
						checksource

						# - maybe split source reference to get actual plugin slug -
						ACTUALSLUG="$SOURCESLUG"
						if [[ "$SOURCESLUG" == *":"* ]]; then
							IFS=":" read -r -a SLUGINFO <<< "$SOURCESLUG"
							SOURCESLUG=${SLUGINFO[0]}
							ACTUALSLUG=${SLUGINFO[1]}
						fi
						PLUGINPATH="$SITEPATH""wp-content/plugins/""$ACTUALSLUG""/"

						# - use rsync to verify file checksums -
						COMMAND="$SUDO""rsync -n -aic --out-format=%n ""$SOURCEPATH"" ""$PLUGINPATH"

						# - maybe cleanup git / zip dir -
						if [ "$GIT" == "true" ] || [ "$ZIP" == "true" ]; then
							rm -rf "$INSTALLTEMP"
						fi
						
						# - loop matching files -						
						FILECOUNT=0; FILELIST=$($COMMAND)
						readarray -t FILES <<< "$FILELIST"
						for FILEPATH in "${FILES[@]}"; do
							if [ -n "$FILEPATH" ] && [ ! "${FILEPATH:0:2}" == "./" ]; then
								echo "$FILEPATH"
								((++FILECOUNT))
							fi
						done
						if [ "$FILECOUNT" -gt 0 ]; then
							yellow "$FILECOUNT"; echo " plugin files were found with different checksums.";
						else
							printf "All "; cyan "$PLUGIN"; printf " file checksums match on site "; green "$SITENAME"; echo "."
						fi
					fi
				fi
			fi
		done

		# - use wp CLI as not in source list - 
		if [ ! "$MATCHED" == "true" ]; then

			# - output verifying plugin message -
			yellow "***"; printf " Verifying plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."

			# - verify checksums for plugin -
			COMMAND="$WP"" plugin verify-checksums ""$PLUGIN"" --skip-plugins"
			OUTPUT=$($COMMAND)
			echo "$OUTPUT"
		fi
		
	done
}

# -------------- #
# Install Plugin #
# -------------- #
function installplugin {

	local PLUGIN; PLUGIN=$1
	SUCCESS="Success: Installed"
	
	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do
	
		# - maybe split plugin by plugin-slug:version -
		# 1.0.4: allow for specific version installs
		VERSION=""
		if [[ "$PLUGIN" == *":"* ]]; then
			IFS=":" read -r -a PLUGININFO <<< "$PLUGIN"
			PLUGIN=${PLUGININFO[0]}
			VERSION=${PLUGININFO[1]}
			
			# - install specific plugin version -
			yellow "***"; printf " Installing plugin "; cyan "$PLUGIN"; printf " (version "; yellow "$VERSION"; printf ") on "; green "$SITENAME"; echo "..."
			COMMAND="$WP"" plugin install ""$PLUGIN"" --version=""$VERSION"" --skip-plugins"
		else
			# - install latest plugin version -
			yellow "***"; printf " Installing plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."
			COMMAND="$WP"" plugin install ""$PLUGIN"" --skip-plugins"
		fi
		OUTPUT=$($COMMAND)
		
		# - check result and maybe try again
		checkresult "$OUTPUT" "$SUCCESS" install
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

		echo "$OUTPUT"
	done
}

# --------------------------- #
# Install and Activate Plugin #
# --------------------------- #
function installactivateplugin {
	
	local PLUGIN; PLUGIN=$1

	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do
		
		# - output installing plugin message -
		yellow "****"; printf " Installing and activating plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."
		
		# - install plugin -
		installplugin "$PLUGIN"
		
		# - activate the plugin if installed -
		if [ "$RESULT" == "success" ]; then 
			activateplugin "$PLUGIN"
		fi
	done
}

# ---------------- #
# Reinstall Plugin #
# ---------------- #
function reinstallplugin {
	
	local PLUGIN=$1

	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do

		# - output reinstalling plugin message -
		yellow "****"; printf " Reinstalling plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."

		# - check if plugin is active -
		# 1.0.4: to restore previous state
		MATCHED=""; ACTIVE=""
		COMMAND="$WP"" plugin list --fields=name,version,status --format=csv"
		OUTPUT=$($COMMAND)
		OUTPUT=$(tail -n +2 <<< "$OUTPUT")
		while IFS= read -r -a LINE; do
			PLUGINSLUG=($(awk -F',' '{print $1}' <<< "$LINE"))
			if [ "$PLUGINSLUG" == "$PLUGIN" ]; then
				MATCHED="true"
				VERSION=($(awk -F',' '{print $2}' <<< "$LINE"))
				STATUS=($(awk -F',' '{print $3}' <<< "$LINE"))
				if [ "$STATUS" == "active" ]; then
					ACTIVE="true"
				fi
			fi
		done <<< "$OUTPUT"
		
		# - skip if no match -
		if [ "$MATCHED" == "true" ]; then

			# - backup plugin in case of failure -
			# 1.0.4: added to handle install fails
			BACKEDUP=""
			PLUGINPATH="$SITEPATH"wp-content/plugins/"$PLUGIN"
			BACKUPPATH="$PLUGINPATH""-backup"
			if [ -d "$PLUGINPATH" ]; then
				rm -rf "$BACKUPPATH"
				mv "$PLUGINPATH" "$BACKUPPATH"
				BACKEDUP="true"
				installplugin "$PLUGIN"
			else
				# - delete existing plugin -
				deleteplugin "$PLUGIN"

				# - install plugin -
				if [ "$RESULT" == "success" ]; then 
					installplugin "$PLUGIN":"$VERSION"
				fi
			fi

			# - check if installation failed -
			if [ "$RESULT" == "failed" ]; then 
				if [ "$BACKEDUP" = "true" ]; then
					# - restore plugin backup -
					yellow "**"; echo " Reinstallation failed, restoring previous plugin files..."
					rm -rf "$PLUGINPATH"
					mv "$BACKUPPATH" "$PLUGINPATH"
				else 
					red "WARNING!"; printf " Reinstallation failed. Plugin is no longer installed!";
					ACTIVE=""
				fi
			elif [ -d "$PLUGINPATH" ]; then
				# - success so delete backup -
				rm -rf "$PLUGINPATH"-temp
			else
				# - maybe reactivate plugin -
				if [ "$ACTIVE" == "true" ]; then
					activateplugin "$PLUGIN"			
				fi
			fi
		else
			red "Error."; printf " No installed plugin match found for "; cyan "$PLUGIN"; echo " Skipping..."
		fi
	done
}

# --------------- #
# Activate Plugin #
# --------------- #
function activateplugin {
	
	local PLUGIN; PLUGIN=$1
	SUCCESS="Success: Activated"
	
	# TODO: allow for plugin activation on Multisite via Blog ID
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	if [ "$MULTISITE" == "0" ]; then
		red "Failed."; echo " WPX cannot activate a plugin on Multisite (yet.)"; return
	fi

	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do
	
		# - output activating plugin message -
		yellow "***"; printf " Activating plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."
		
		# - set and execute command -
		COMMAND="$WP"" plugin activate ""$PLUGIN"
		OUTPUT=$($COMMAND)
		
		# - check result and maybe try again -
		checkresult "$OUTPUT" "$SUCCESS" activate
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi
		
		echo "$OUTPUT"
	done
}

# ----------------- #
# Deactivate Plugin #
# ----------------- #
function deactivateplugin {
	
	local PLUGIN; PLUGIN=$1
	SUCCESS="Success: Deactivated"

	# TODO: allow for Multisite plugin deactivation via Blog ID
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	if [ "$MULTISITE" == "0" ]; then
		red "Failed."; echo " WPX cannot deactivate a plugin on Multisite (yet.)"; return
	fi
	
	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do
		
		# - output deactivating plugin message -
		yellow "***"; printf " Deactivating plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."
		
		# - set and execute command -
		COMMAND="$WP"" plugin deactivate ""$PLUGIN"" --skip-plugins"
		OUTPUT=$($COMMAND)
		
		# - check result and maybe try again -
		checkresult "$OUTPUT" "$SUCCESS" deactivate
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi
		
		echo "$OUTPUT"
	done
}

# ------------- #
# Update Plugin #
# ------------- #
function updateplugin {
	
	local PLUGIN; PLUGIN="$1"
	SUCCESS="Success: Updated"
	
	# IDEA: get plugin list before updates and compare with after
	
	# - maybe update all plugins -
	ALL=""
	if [ "$PLUGIN" == "all" ]; then

		# - use --all switch -
		COMMAND="$WP"" plugin update --all"
		OUTPUT=$($COMMAND)
		echo "$OUTPUT"
		
		# TEMP
		return

		# TODO: get plugin list and loop instead

		# - output updating all plugins message -
		yellow "****"; printf " Updating "; cyan "ALL"; printf " plugins on "; green "$SITENAME"; echo "..."

		# - get plugin list -
		# 1.0.4: split command to avoid 'Too many positional arguments' error
		COMMAND="$WP"" plugin list --fields=name --skip-plugins"
		INFO=$($COMMAND)		
		INFO=$(tail -n +2 <<< "$INFO")

		# TODO: convert plugin slugs to CSV list

		ALL="true"
	fi
	
	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do

		# - maybe split plugin by plugin-slug:version -
		VERSION=""
		if [[ "$PLUGIN" == *":"* ]]; then
			IFS=":" read -r -a PLUGININFO <<< "$PLUGIN"
			PLUGIN=${PLUGININFO[0]}
			VERSION=${PLUGININFO[1]}
		fi

		# - set command -
		if [ -n "$VERSION" ]; then
			if [ "$VERSION" == "major" ]; then			
				# - update to major version -
				yellow "***"; printf " Updating plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; printf " ("; yellow "$VERSION"; echo ")..."
				COMMAND="$WP"" plugin update ""$PLUGIN"" --""$VERSION"" --skip-plugins"
			elif [ "$VERSION" == "minor" ] || [ "$VERSION" == "patch" ]; then
				# - update to minor/patch version -
				yellow "***"; printf " Updating plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; printf " ("; yellow "$VERSION"; echo " only)..."
				COMMAND="$WP"" plugin update ""$PLUGIN"" --""$VERSION"" --skip-plugins"
			else
				# - update to specific version -
				yellow "***"; printf " Updating plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; printf " to version "; yellow "$VERSION"; echo "..."
				COMMAND="$WP"" plugin update ""$PLUGIN"" --version=""$VERSION"" --skip-plugins"
			fi
		else 
			# - update to latest version -
			yellow "***"; printf " Updating plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."
			COMMAND="$WP"" plugin update ""$PLUGIN"" --skip-plugins"
		fi

		# - execute command -
		OUTPUT=$($COMMAND)

		# - check result and maybe try again -
		# 1.0.7: added third argument for already updated
		checkresult "$OUTPUT" "$SUCCESS" update
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

		echo "$OUTPUT"
	done
}

# --------------- #
# Rollback Plugin #
# --------------- #
function rollbackplugin {

	local PLUGIN; PLUGIN=$1
	SUCCESS="Success: Installed"
	
	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do
	
		# - check if version is specified -
		VERSION=""
		if [[ "$PLUGIN" == *":"* ]]; then
		
			# - split specified plugin into pluginslug:version -
			IFS=":" read -r -a PLUGININFO <<< "$PLUGIN"
			PLUGIN=${PLUGININFO[0]}
			VERSION=${PLUGININFO[1]}

			# - output plugin rollback message -
			yellow "***"; printf " Rolling back plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; printf " to version "; yellow "$VERSION"; echo ""

			# - set command and execute -
			COMMAND="$WP"" plugin install ""$PLUGIN"" --skip-plugins --version=""$VERSION"" --force"
			OUTPUT=$($COMMAND)

			# - check result and maybe try again -
			checkresult "$OUTPUT" "$SUCCESS"
			if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

			echo "$OUTPUT"
		else
			# - no version specified message -
			red "Error!"; printf " No rollback version was specified for plugin "; cyan "$PLUGIN"; echo " Use the format plugin-slug:version"
		fi
	done
}

# ------------- #
# Delete Plugin #
# ------------- #
function deleteplugin {
	
	local PLUGIN; PLUGIN=$1
	SUCCESS="Success: Deleted"	
	
	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do

		# - deactivate plugin first -
		deactivateplugin "$PLUGIN"

		# - output delete plugin message -
		yellow "***"; printf " Deleting plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."
		
		# - set command and execute -
		COMMAND="$WP"" plugin delete ""$PLUGIN"" --skip-plugins"		
		OUTPUT=$($COMMAND)
	
		# - check result and maybe force delete plugin -
		checkresult "$OUTPUT" "$SUCCESS" delete
		if [ "$RESULT" == "failed" ]; then
			PLUGINPATH="$SITEPATH"wp-content/plugins/"$PLUGIN"
			if [ -n "$YMLPATH" ] || [ -n "$ALIAS" ] || [ -n "$SSH" ]; then
				red "Failed"; printf ": Could not delete plugin "; cyan "$PLUGIN"; echo "."
			elif [ -d "$PLUGINPATH" ]; then
				# 1.0.6: fix to unquoted command rm -rf
				COMMAND="$SUDO""rm -rf ""$PLUGINPATH"
				OUTPUT=$($COMMAND)
				if [ -d "$PLUGINPATH" ]; then
					red "Failed"; printf ": Could not delete plugin "; cyan "$PLUGIN"; printf " on site "; green "$SITENAME"; echo "."
					RESULT="failed"
				else 
					RESULT="success"; yellow "Manually Deleted plugin"; cyan "$PLUGIN"; printf " on site "; green "$SITENAME"; echo "."
				fi
			fi
		else
			echo "$OUTPUT"
		fi
	done
}

# ---------------- #
# Uninstall Plugin #
# ---------------- #
function uninstallplugin {
	
	local PLUGIN; PLUGIN=$1
	SUCCESS="Uninstalled and deleted"
	
	# - loop plugins -
	IFS="," read -r -a PLUGINS <<< "$PLUGIN"
	for PLUGIN in "${PLUGINS[@]}"; do
	
		# - output uninstalling plugin message -
		yellow "***"; printf " Uninstalling plugin "; cyan "$PLUGIN"; printf " from "; green "$SITENAME"; echo "..."
		
		# - set and execute command -
		COMMAND="$WP"" plugin uninstall ""$PLUGIN"" --deactivate"
		OUTPUT=$($COMMAND)
		
		# - check result and maybe try again -
		checkresult "$OUTPUT" "$SUCCESS"
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi
		
		echo "$OUTPUT"
	done
}


# ---------------------- #
# === THEME COMMANDS === #
# ---------------------- #

# ----------- #
# List Themes #
# ----------- #
function listthemes {

	local THEME; THEME=$1

	# - check if multisite install -
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	
	# - maybe get current template / stylesheet options -
	if [ "$MULTISITE" == "1" ]; then
		COMMAND="$WP"" option get template --skip-plugins"
		TEMPLATE=$($COMMAND)
		COMMAND="$WP"" option get stylesheet --skip-plugins"
		STYLESHEET=$($COMMAND)
	fi

	# - output listing themes message -
	yellow "*"; printf " Listing theme(s) on "; green "$SITENAME"; echo "..."

	# - get all theme info -	
	# 1.0.4: split command to avoid 'Too many positional arguments' error
	COMMAND="$WP"" theme list --fields=name,status,version,update,update_version --skip-plugins --format=csv"
	INFO=$($COMMAND)
	INFO=$(tail -n +2 <<< "$INFO")

	# - get all listed themes -
	# 1.0.5: allow for theme filters
	I=0; ALLTHEMES=(); LINES=()
	while IFS= read -r -a LINE; do
		ALLTHEMES[$I]=$(awk -F',' '{print $1}' <<< "$LINE"); 
		LINES[$I]=$LINE; ((++I))
	done <<< "$INFO"

	# - empty = list all themes -
	if [ -z "$THEME" ]; then
		THEMES=("${ALLTHEMES[@]}")
		ALL="true"
	else
		# - read specified themes -
		IFS="," read -r -a THEMES <<< "$THEME"

		# - check for limit switches -
		I=0; NEWTHEMES=()
		ALL=""; ACTIVES=""; INACTIVES=""; PARENTS=""; CHILDS=""; UPDATES=""; CHANGED=""
		for ATHEME in "${THEMES[@]}"; do
			REMOVE=""
			if [ "$ATHEME" == "all" ]; then ALL="true"; fi
			if [ "$ATHEME" == "actives" ]; then ACTIVES="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$ATHEME" == "inactives" ]; then INACTIVES="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$ATHEME" == "parents" ]; then PARENTS="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$ATHEME" == "childs" ]; then CHILDS="true"; REMOVE="true"; CHANGED="true"; fi
			if [ "$ATHEME" == "updates" ]; then UPDATES="true"; REMOVE="true"; CHANGED="true"; fi
			if [ ! "$REMOVE" == "true" ]; then NEWTHEMES[$I]=$ATHEME; ((++I)); fi
		done

		# - reassign plugin list if changed -
		if [ "$ALL" == "true" ]; then
			THEMES=("${ALLTHEMES[@]}");
		elif [ "$CHANGED" == "true" ]; then 
			THEMES=("${NEWTHEMES[@]}");
		fi
	fi

	# - table headings -
	TABLE=""; OTHER=""
	TABLE+=$(white "THEME"); TABLE+="|"
	TABLE+=$(white "STATUS"); TABLE+="|"
	TABLE+=$(white "VERSION"); TABLE+="|"
	TABLE+=$(white "UPDATES"); TABLE+=$'\r\n'

	# - loop themes -
	I=0; MATCHED=""
	for ATHEME in "${ALLTHEMES[@]}"; do
	
		ROW=$(cyan "$ATHEME")
		ACTIVE=""; INACTIVE=""; CHILD=""; PARENT=""

		# THEMEINFO=$(grep "$THEME" <<< "$INFO")
		THEMEINFO=${LINES[$I]}
		
		if [ -n "$THEMEINFO" ]; then

			# - split CSV columns -
			IFS=',' read -r -a COLUMNS <<< "$THEMEINFO"

			# - theme status -
			# 1.0.4: check for parent/child theme
			ROW+="|"
			if [ "$MULTISITE" == "1" ] && [ "${COLUMNS[0]}" == "$STYLESHEET" ]; then
				if [ "$STYLESHEET" == "$TEMPLATE" ]; then
					ROW+=$(green "Active")
				else
					ROW+=$(green "Active Child")
					CHILD="true"
				fi
				ACTIVE="true"
			elif [ "$MULTISITE" == "1" ] && [ "${COLUMNS[0]}" == "$TEMPLATE" ]; then
				ROW+=$(green "Active Parent")
				ACTIVE="true"; PARENT="true"
			elif [ "${COLUMNS[1]}" == "active" ]; then
				ROW+=$(green "Active")
				ACTIVE="true"
			else
				ROW+=$(blue "Inactive")
				INACTIVE="true"
			fi

			# - theme version -
			ROW+="|"; 
			if [ -n "${COLUMNS[2]}" ]; then
				ROW+=$(yellow "${COLUMNS[2]}")
			else 
				ROW+="-"
			fi

			# - theme updates -
			if [ "${COLUMNS[3]}" == "available" ]; then
				ROW+="|"; ROW+=$(yellow "${COLUMNS[4]}"); ROW+=" available"
				UPDATE="true"
			fi
		# else 	
		#	ROW+="|"; ROW+=$(red "Not Found")
		fi

		# - add row new line -
		ROW+=$'\r\n'

		# - add row if listing all -
		ADDROW=""
		if [ "$ALL" == "true" ]; then ADDROW="true"
		else 
			# - add row if matching a theme limit filter -
			if [ "$UPDATES" == "true" -a "$UPDATE" == "true" ] \
				|| [ "$ACTIVES" == "true" -a "$ACTIVE" == "true" ] \
				|| [ "$INACTIVES" == "true" -a "$INACTIVE" == "true" ] \
				|| [ "$PARENTS" == "true" -a "$PARENT" == "true" ] \
				|| [ "$CHILDS" == "true" -a "$CHILD" == "true" ]; then
				ADDROW="true"
			fi

			# - check for matching theme slug -
			if [ -z "$ADDROW" ]; then
				for THEME in "${THEMES[@]}"; do
					if [ "$THEME" == "$ATHEME" ]; then
						ADDROW="true"
					fi
				done
			fi
		fi

		# - split table rows according to active status -
		if [ "$ADDROW" == "true" ]; then
			MATCH="true"
			if [ "$ACTIVE" == "true" ]; then
				TABLE+=$ROW
			else
				OTHER+=$ROW
			fi
		fi

		((++I))

	done

	if [ "$MATCH" == "true" ]; then
		# - add all other rows to active rows -
		TABLE+=$OTHER

		# - output pretty table -	
		OUTPUT=$(column -t -s "|" <<< "$TABLE")
		echo "$OUTPUT"
	else 
		# - output no match found -
		red "Sorry."; echo " No matching themes were found."
	fi

}

# ----------- #
# Check Theme #
# ----------- #
function checktheme {
	
	local TEMPLATE; local TEMPLATEVERSION
	local STYLESHEET; local STYLEVERSION

	# TODO: allow for checking of theme via Blog ID
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	if [ "$MULTISITE" == "0" ]; then
		red "Failed."; echo " WPX cannot check a theme on Multisite (yet.)"; return
	fi
	
	# - get template and stylesheet options -
	COMMAND="$WP"" option get template --skip-plugins"
	TEMPLATE=$($COMMAND)
	COMMAND="$WP"" option get stylesheet --skip-plugins"
	STYLESHEET=$($COMMAND)
	
	if [ -n "$TEMPLATE" ]; then
	
		yellow "**"; printf " Checking active theme(s) on site "; green "$SITENAME"; echo ""

		# - check if theme updates are  available -
		COMMAND="$WP"" theme list --fields=name,version,update,update_version --format=csv --skip-plugins"
		OUTPUT=$($COMMAND)
		# note: this command is split to avoid 'Too many positional arguments' error
		OUTPUT=$(tail -n +2 <<< "$OUTPUT")

		if [ "$TEMPLATE" == "$STYLESHEET" ]; then
				
			# - loop to find matching theme -
			while IFS= read -r -a LINE; do
				THEME=($(awk -F',' '{print $1}' <<< "$LINE"))		
				if [ "$THEME" == "$TEMPLATE" ]; then

					# - output theme version -
					TEMPLATEVERSION=$(awk -F',' '{print $2}' <<< "$LINE")
					printf " Theme: "; cyan "$TEMPLATE"; printf " "; yellow "$TEMPLATEVERSION"; printf " (No Child Theme)"

					# - output if theme update available -
					UPDATEAVAILABLE=$(awk -F',' '{print $3}' <<< "$LINE")
					if [ "$UPDATEAVAILABLE" == 'available' ]; then
						UPDATEVERSION=$(awk -F',' '{print $4}' <<< "$LINE")
						printf " (Update to "; yellow "$UPDATEVERSION"; printf " available.)"
					fi
					echo ""
				fi				
			done <<< "$OUTPUT"
			
		else 

			# - loop to find matching theme -
			while IFS= read -r -a LINE; do
				THEME=($(awk -F',' '{print $1}' <<< "$LINE"))		
				if [ "$THEME" == "$TEMPLATE" ]; then
				
					# - output theme version -
					TEMPLATEVERSION=$(awk -F',' '{print $2}' <<< "$LINE")
					printf "Parent Theme: "; cyan "$TEMPLATE"; printf " "; yellow "$TEMPLATEVERSION"
							
					# - output if theme update available -
					UPDATEAVAILABLE=$(awk '{print $3}' <<< "$LINE")
					if [ "$UPDATEAVAILABLE" == 'available' ]; then
						UPDATEVERSION=$(awk -F',' '{print $4}' <<< "$LINE")
						printf " (Update to "; yellow "$UPDATEVERSION"; printf " available.)"
					fi
					echo ""
				fi
			done <<< "$OUTPUT"
			
			# - output message for child theme update -
			# - loop to find matching theme -
			while IFS= read -r -a LINE; do
				THEME=($(awk -F',' '{print $1}' <<< "$LINE"))		
				if [ "$THEME" == "$STYLESHEET" ]; then
					
					# - output child theme version -
					STYLEVERSION=$(awk -F',' '{print $2}' <<< "$LINE")
					printf "Child Theme: "; cyan "$STYLESHEET"; printf " "; yellow "$STYLEVERSION"
				
					# - output if theme update available -
					UPDATEAVAILABLE=$(awk '{print $3}' <<< "$LINE")
					if [ "$UPDATEAVAILABLE" == 'available' ]; then
						UPDATEVERSION=$(awk -F',' '{print $4}' <<< "$LINE")
						printf " (Update to "; yellow "$UPDATEVERSION"; printf " available.)"
					fi
					echo ""
				fi
			done <<< "$OUTPUT"
		fi
	else
		red "Warning:"; printf " could not retrieve template option value for "; yellow "$SITENAME"; echo " "
	fi
}

# ------------- #
# Install Theme #
# ------------- #
function installtheme {
	
	local THEMES; THEMES=$1
	SUCCESS="Theme installed successfully."
	
	# - loop themes -
	IFS="," read -r -a THEMESLUGS <<< "$THEMES"
	for THEME in "${THEMESLUGS[@]}"; do

		# - maybe split theme by theme-slug:version -
		# 1.0.4: allow for specific version installs
		VERSION=""
		if [[ "$THEME" == *":"* ]]; then
			IFS=":" read -r -a THEMEINFO <<< "$THEME"
			THEME=${THEMEINFO[0]}
			VERSION=${THEMEINFO[1]}
			# - install specific theme version -
			yellow "***"; printf " Installing theme "; cyan "$THEME"; printf " (version "; yellow "$VERSION"; printf ") on "; green "$SITENAME"; echo "..."
			COMMAND="$WP"" theme install ""$THEME"" --version=""$VERSION"" --skip-plugins"
		else
			# - install latest theme version -
			yellow "***"; printf " Installing theme "; cyan "$THEME"; printf " on "; green "$SITENAME"; echo "..."
			COMMAND="$WP"" theme install ""$THEME"" --skip-plugins"
		fi
		OUTPUT=$($COMMAND)
	
		# - check result and maybe try again -
		checkresult "$OUTPUT" "$SUCCESS" install
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

		echo "$OUTPUT"
	done
}

# -------------------------- #
# Install and Activate Theme #
# -------------------------- #
function installactivatetheme {

	local THEME; THEME=$1
	
	# TODO: handle multisite theme activation for blog ID(s) ?
	
	if [[ "$THEME" == *","* ]]; then
		# - output cannot activate multiple themes message -
		red "Error!"; echo " You cannot activate multiple themes. Choose one!"; exit
	else 
		# - output installing and activating theme message -
		yellow "****"; printf " Installing and activating theme "; cyan "$THEME"; printf " on site "; green "$SITENAME"; echo "..."

		# - install specified theme -
		installtheme "$THEME"

		# - activate if install successful -
		if [ "$RESULT" == 'success' ]; then 
			activatetheme "$THEME"
		fi
	fi
}

# --------------- #
# Reinstall Theme #
# --------------- #
function reinstalltheme {
	
	local THEMES; THEMES=$1

	# TODO: reinstall theme for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot reinstall themes for YML configs (yet.)"; return
	fi
	
	# TODO: reinstall theme for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot reinstall themes for site aliases (yet.)"; return
	fi

	# TODO: reinstall theme for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot reinstall themes for SSH sites (yet.)"; return
	fi
	
	# - loop themes
	IFS="," read -r -a THEMESLUGS <<< "$THEMES"
	for THEME in "${THEMESLUGS[@]}"; do
	
		# - output reinstalling theme message -
		yellow "***"; printf " Reinstalling theme(s) "; cyan "$THEME"; printf " on site "; green "$SITENAME"; echo "..."

		# - backup existing theme -
		BACKEDUP=""
		THEMEPATH="$SITEPATH""wp-content/""$THEME"
		BACKUPPATH="$SITEPATH""wp-content/""$THEME""-backup"
		if [ -d "$THEMEPATH" ]; then
			rm -rf "$BACKUPPATH"
			mv "$THEMEPATH" "$BACKUPPATH"
			BACKEDUP="true"
		fi
		
		# - reinstall theme -
		installtheme "$THEME"
		
		# - maybe restore backup on failure -
		if [ "$RESULT" == "failed" ]; then
			if [ "$BACKEDUP" == "true" ]; then
				yellow "**"; echo " Reinstallation failed, restoring previous theme files..."
				rm -rf "$THEMEPATH"
				mv "$BACKUPPATH" "$THEMEPATH"
			else
				red "WARNING!"; printf " Reinstallation failed. Theme is no longer installed!";
			fi
			
		fi
		
	done
}

# -------------- #
# Activate Theme #
# -------------- #
function activatetheme {

	local THEME; THEME=$1
	SUCCESS="Switched to"

	# TODO: maybe handle multisite theme activation for blog ID ?
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	if [ "$MULTISITE" == "0"]; then
		red "Failed."; echo " WPX cannot activate a theme on Multisite (yet.)"; return
	fi
	
	if [[ "$THEME" == *","* ]]; then
		# - output only activate one theme message -
		red "Error!"; echo " You cannot activate multiple themes. Choose one!"; exit
	else 
		# - output activating theme message -
		yellow "***"; printf " Activating theme "; cyan "$THEME"; printf " on "; green "$SITENAME"; echo "..."

		# - set command and execute -
		COMMAND="$WP"" theme activate ""$THEME"" --skip-plugins"
		OUTPUT=$($COMMAND)
		
		# - check result and maybe try again -
		checkresult "$OUTPUT" "$SUCCESS" activate
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

		echo "$OUTPUT"
	fi
}

# ------------ #
# Update Theme #
# ------------ #
function updatetheme {
	
	local THEMES; THEMES=$1
	SUCCESS="Theme updated successfully."
	
	# - maybe update all themes -
	ALL=""
	if [ "$THEMES" == "all" ]; then
	
		# - use --all switch for update -
		COMMAND="$WP"" theme update --all --skip-plugins"
		OUTPUT=$($COMMAND)
		echo "$OUTPUT"
		
		# TEMP
		return

		# TODO: get theme list and loop instead

		# - output updating all themes message -
		yellow "****"; printf " Updating "; cyan "ALL"; printf " themes on "; green "$SITENAME"; echo "..."

		# - get theme list to loop -
		# 1.0.4: split command to avoid 'Too many positional arguments' error
		COMMAND="$WP"" theme list --fields=name --skip-plugins"
		INFO=$($COMMAND)
		INFO=$(tail -n +2 <<< "$INFO")
		
		# TODO: convert theme slugs to CSV list
		
		ALL="true"
	fi
		
	# - loop themes -
	IFS="," read -r -a THEMESLUGS <<< "$THEMES"
	for THEME in "${THEMESLUGS[@]}"; do
	
		# - maybe split specified theme into themeslug:version -
		VERSION=""
		if [[ "$THEME" == *":"* ]]; then
			IFS=":" read -r -a THEMEINFO <<< "$THEME"
			THEME=${THEMEINFO[0]}
			VERSION=${THEMEINFO[1]}
		fi

		# - set command -
		if [ -n "$VERSION" ]; then
			if [ "$VERSION" == "major" ]; then
				# - update to major version -
				yellow "***"; printf " Updating theme "; cyan "$THEME"; printf " on site "; green "$SITENAME"; printf " ("; yellow "$VERSION"; echo ")..."
				COMMAND="$WP"" theme update ""$THEME"" --version=""$VERSION"" --skip-plugins"
			elif [ "$VERSION" == "minor" ] || [ "$VERSION" == "patch" ]; then
				# - update to minor/patch version -
				yellow "***"; printf " Updating theme "; cyan "$THEME"; printf " on site "; green "$SITENAME"; printf " ("; yellow "$VERSION"; echo " only)..."
				COMMAND="$WP"" theme update ""$THEME"" --version=""$VERSION"" --skip-plugins"
			else
				# - update to specific version -
				yellow "***"; printf " Updating theme "; cyan "$THEME"; printf " on site "; green "$SITENAME"; printf " to version "; yellow "$VERSION"; echo "..."
				COMMAND="$WP"" theme update ""$THEME"" --version=""$VERSION"" --skip-plugins"
			fi
		else
			# - update to latest version -
			yellow "***"; printf " Updating theme "; cyan "$THEME"; printf " on site "; green "$SITENAME"; echo "..."
			COMMAND="$WP"" theme update ""$THEME"" --skip-plugins"
		fi
		
		# - execute command -
		OUTPUT=$($COMMAND)
		
		# - check result and maybe try again -
		# 1.0.7: added third argument for already updated
		checkresult "$OUTPUT" "$SUCCESS" update
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi
		
		echo "$OUTPUT"
	done	
}

# -------------- #
# Rollback Theme #
# -------------- #
function rollbacktheme {

	local THEMES; THEMES=$1
	SUCCESS="Theme installed successfully."
	
	# - loop themes -
	IFS="," read -r -a THEMESLUGS <<< "$THEMES"
	for THEME in "${THEMESLUGS[@]}"; do

		# - check if version is specified -
		VERSION=""
		if [[ "$THEMES" == *":"* ]]; then
		
			# - split specified theme into themeslug:version -
			IFS=":" read -r -a THEMEINFO <<< "$THEME"
			THEME=${THEMEINFO[0]}
			VERSION=${THEMEINFO[1]}

			yellow "***"; printf " Rolling back theme "; cyan "$THEME"; printf " on "; green "$SITENAME"; printf " to Version "; yellow "$VERSION"

			# - set command and execute -
			COMMAND="$WP"" theme install ""$THEME"" --skip-plugins --version=""$VERSION"" --force"
			OUTPUT=$($COMMAND)
		
			# - check result and maybe try again -
			checkresult "$OUTPUT" "$SUCCESS"
			if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

			echo "$OUTPUT"
		else
			# - no version specified message -
			red "Error!"; printf " No rollback version was specified for theme "; cyan "$THEME"; echo " Use the format theme-slug:version"
		fi
	done
}

# ------------ #
# Delete Theme #
# ------------ #
# 1.0.4: added delete theme command
function deletetheme {
	
	local THEME; THEME=$1
	SUCCESS="Success: Deleted"
	
	# TODO: check for active themes on Multisite install
	
	# - get template and stylesheet options -
	COMMAND="$WP"" option get template --skip-plugins"
	TEMPLATE=$($COMMAND)
	COMMAND="$WP"" option get stylesheet --skip-plugins"
	STYLESHEET=$($COMMAND)
	
	# - loop themes -
	IFS="," read -r -a THEMES <<< "$THEME"
	for THEME in "${THEMES[@]}"; do

		SKIP=""

		# - prevent delete of active parent/child theme -
		if [ "$TEMPLATE" == "$STYLESHEET" ] && [ "$THEME" == "$STYLESHEET" ]; then
			red "Error!"; printf " Theme "; yellow "$THEME"; echo " is the active Theme and cannot be deleted while active."
			SKIP="true"
		elif [ "$THEME" == "$STYLESHEET" ]; then
			red "Error!"; printf " Theme "; yellow "$THEME"; echo " is the active Child Theme and cannot be deleted while active."
			SKIP="true"
		elif [ "$THEME" == "$TEMPLATE" ]; then
			red "Error!"; printf " Theme "; yellow "$THEME"; echo " is the active Parent Theme and cannot be deleted while active."
			SKIP="true"
		fi

		# - delete the theme -		
		if [ -z "$SKIP" ]; then

			# - output deleting theme message -
			yellow "***"; printf " Deleting theme "; cyan "$THEME"; printf " on "; green "$SITENAME"; echo "..."

			# - set command and execute -
			COMMAND="$WP"" theme delete ""$THEME"" --skip-plugins"
			OUTPUT=$($COMMAND)

			# - check result and maybe force delete theme -
			checkresult "$OUTPUT" "$SUCCESS" delete
			if [ "$RESULT" == "failed" ]; then
				THEMEPATH="$SITEPATH"wp-content/themes/"$THEME"
				if [ -n "$YMLPATH" ] || [ -n "$ALIAS" ] || [ -n "$SSH" ]; then
					red "Failed"; printf ": Could not delete theme "; cyan "$PLUGIN"; echo "."
				elif [ -d "$THEMEPATH" ]; then
					 rm -rf "$THEMEPATH"
					if [ -d "$THEMEPATH" ]; then
						red "Failed"; printf ": Could not delete theme "; cyan "$PLUGIN"; printf " on site "; green "$SITENAME"; echo "."
						RESULT="failed"
					else 
						RESULT="success"; yellow "Manually Deleted theme"; cyan "$PLUGIN"; printf " on site "; green "$SITENAME"; echo "."
					fi
				fi
			fi
		fi
	done
}


# --------------------- #
# === SYNC COMMANDS === #
# --------------------- #

# --------- #
# Sync Core #
# --------- #
function synccore {

	local SOURCETYPE; local SOURCESLUG; local SOURCEPATH
	local CORESLUG; CORESLUG=$1; 

	# TODO: sync core for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot sync core for YML configs (yet.)"; return
	fi

	# TODO: sync core for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot sync core for site aliases (yet.)"; return
	fi

	# TODO: sync core for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot sync core for SSH sites (yet.)"; return
	fi

	# - read sources config -
	MATCHED=""
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# - ignore lines starting with # -
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "core" ]; then

				# - sync core from source -
				if [ "$CORESLUG" == "$SOURCESLUG" ]; then

					RESULT=""; MATCHED="true"
					
					# - check for git and zip sources -
					checksource
					
					if [ -d "$SOURCEPATH" ]; then

						# - maybe unlock core -	
						if [ "$SITELOCKING" == "true" ]; then unlockcore; fi

						# - output syncing core message -
						yellow "***"; printf " Syncing Core "; cyan "$SOURCESLUG"; printf " to site "; green "$SITENAME"; echo "..."
					
						# TODO: maybe use rsync --backup option?
						"$SUDO"rsync -av --delay-updates "$SOURCEPATH" "$SITEPATH"

						# - maybe relock core -
						if [ "$SITELOCKING" == "true" ]; then lockcore; fi

						RESULT="success"

						# - maybe cleanup git / zip dir -
						if [ "$GIT" == "true" ] || [ "$ZIP" == "true" ]; then
							rm -rf "$INSTALLTEMP"
						fi	

					else
						# - output invalid source directory message -
						red "Warning: "; printf "Invalid Core Source configuration, check "; white "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; printf ". Skipping..."; echo " "
					fi

				fi
			fi
		fi
	done < "$CONFIG"

	if [ -z "$MATCHED" ]; then
		# - no matching plugin slug message -
		red "Error!"; printf " No matching Core Source slug found, check "; cyan "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; echo "."
	fi
}

# ----------- #
# Sync Plugin #
# ----------- #
function syncplugin {
	
	local SOURCETYPE; local SOURCESLUG; local SOURCEPATH; local PLUGINPATH; local DOSYNC
	local PLUGIN; PLUGIN=$1;
	local ONLYEXISTING; ONLYEXISTING=$2;

	# TODO: sync plugin for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot sync plugins for YML configs (yet.)"; return
	fi

	# TODO: sync plugin for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot sync plugins for site aliases (yet.)"; return
	fi

	# TODO: sync plugin for alias
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot sync plugins for SSH sites (yet.)"; return
	fi

	# - read file without requiring it to end in a new line -
	# ref: https://stackoverflow.com/a/31398490/5240159
	MATCHED=""
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# - ignore lines starting with # -
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "plugin" ]; then

				# - reset do sync flag -
				DOSYNC=""

				# - maybe split source reference to get actual plugin slug -
				# (used for syncing development versions with the same slug)
				# 1.0.7: fix by moving out from inside dosync condition
				ACTUALSLUG="$SOURCESLUG"
				if [[ "$SOURCESLUG" == *":"* ]]; then
					IFS=":" read -r -a SLUGINFO <<< "$SOURCESLUG"
					SOURCESLUG=${SLUGINFO[0]}
					ACTUALSLUG=${SLUGINFO[1]}
				fi

				# - match plugin slugs -
				if [ "$PLUGIN" == "all" ] || [ "$PLUGIN" == "$SOURCESLUG" ]; then 
					DOSYNC="true"
				elif [[ "$PLUGIN" == *","* ]]; then
					IFS="," read -r -a PLUGINS <<< "$PLUGIN"
					for PLUGINSLUG in "${PLUGINS[@]}"; do
						if [ "$PLUGINSLUG" == "$SOURCESLUG" ]; then
							DOSYNC="true"
						fi
					done
				fi

				# - check for existing plugin -
				# 1.0.8: added check for existing plugin
				if [ "$DOSYNC" == "true" ]; then
					if [ "$ONLYEXISTING" == "true" ]; then
						yellow "***"; printf " Checking for plugin "; cyan "$PLUGIN"; printf " on "; green "$SITENAME"; echo "..."
						COMMAND="$WP"" plugin is-installed ""$PLUGIN"" --skip-plugins"
						OUTPUT=$($COMMAND)
						CHECK=$?
						if [ "$CHECK" == "0" ]; then
							yellow "***"; printf " Plugin "; cyan "$PLUGIN"; printf " found on "; green "$SITENAME"; echo ". Syncing."
						else
							yellow "***"; printf " Plugin "; cyan "$PLUGIN"; printf " "; red "was not"; printf " found on "; green "$SITENAME"; echo ". Skipping."	
							DOSYNC="false"
						fi
					fi
				fi

				# - maybe sync now -
				if [ "$DOSYNC" == "true" ]; then

					RESULT=""; MATCHED="true"

					# - check if source is GIT / zip or URL zip -
					checksource

					# - sync if source path directory set -
					if [ -d "$SOURCEPATH" ]; then

						# - source refence message -
						if [ ! "$SOURCESLUG" == "$ACTUALSLUG" ]; then 
							yellow "*"; white " Using source reference "; cyan "$SOURCESLUG"; white " for plugin slug "; cyan "$ACTUALSLUG"; echo ""
							SOURCESLUG="$ACTUALSLUG"
						fi				

						# - maybe create plugin dir -
						PLUGINPATH="$SITEPATH""wp-content/plugins/""$ACTUALSLUG""/"
						if [ ! -d "$PLUGINPATH" ]; then
							mkdir "$PLUGINPATH"
						fi

						# - output plugin sync message -
						yellow "***"; printf " Syncing Plugin "; cyan "$SOURCESLUG"; printf " to site "; green "$SITENAME"; echo " "

						# - sync plugin from source -
						# TODO: maybe use rsync --backup option?
						# rsync -av --delete --delay-updates "$SOURCEPATH" "$PLUGINPATH"
						# 1.0.8: add summary stats but skip directory list output
						rsync -avO --stats --no-perms --no-owner --no-group --delete --delay-updates "$SOURCEPATH" "$PLUGINPATH"
						
						# - set file ownership permissions -
						if [ -n "$SITEGROUP" ]; then
							chown -R "$SITEUSER":"$SITEGROUP" "$PLUGINPATH"
						else
							chown -R "$SITEUSER" "$PLUGINPATH"
						fi

						# - output synced info -							
						printf "Plugin Source: "; cyan "$SOURCEPATH"; echo "";
						printf "Synced to: "; green "$PLUGINPATH"; echo " "

						RESULT="success"
						
						# - maybe cleanup git / zip dir -
						if [ "$GIT" == "true" ] || [ "$ZIP" == "true" ]; then
							rm -rf "$INSTALLTEMP"
						fi	
					else
						# - output invalid source directory message -
						# 1.0.5: fix incorrect nesting on invalid source message
						red "Warning: "; printf "Invalid Plugin Source configuration, check "; white "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; printf ". Skipping..."; echo " "
					fi
				fi
			fi
		fi
	done < "$CONFIG"

	if [ -z "$MATCHED" ]; then
		# - no matching plugin slug message -
		red "Error!"; printf " No matching Plugin Source slug found, check "; cyan "wpx.conf"; printf " for "; yellow "$PLUGIN"; echo "."
	fi
}

# ------------------------ #
# Sync and Activate Plugin #
# ------------------------ #
function syncactivateplugin {

	local PLUGIN; PLUGIN=$1

	# TODO: sync activate plugin for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot sync and activate plugins for YML configs (yet.)"; return
	fi

	# TODO: sync activate plugin for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot sync and activate plugins for site aliases (yet.)"; return
	fi

	# TODO: sync activate plugin for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot sync and activate plugins for SSH sites (yet.)"; return
	fi

	# TODO: maybe handle multisite plugin activation for blog ID ?
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	if [ "$MULTISITE" == "0" ]; then
		red "Error! "; echo "You can only sync - not sync and activate a plugin on Multisite (yet.)"
	fi

	# - loop sources -
	# 1.0.4: added source looping for dev slug usage 
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# - ignore lines starting with # -
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "plugin" ]; then

				# - loop plugin slugs -
				IFS="," read -r -a PLUGINS <<< "$PLUGIN"
				# 1.0.7: fix to use PLUGINSLUG not PLUGIN
				for PLUGINSLUG in "${PLUGINS[@]}"; do

					# - maybe split source reference to get actual plugin slug -
					# 1.0.4: fix to check for split development/actual slug
					# 1.0.7: use a different variable to ACTUALSLUG
					REALSLUG="$SOURCESLUG"
					if [[ "$SOURCESLUG" == *":"* ]]; then
						IFS=":" read -r -a SLUGINFO <<< "$SOURCESLUG"
						SOURCESLUG=${SLUGINFO[0]}
						REALSLUG=${SLUGINFO[1]}
					fi

					# 1.0.7: fix to use PLUGINSLUG not PLUGIN
					if [ "$PLUGINSLUG" == "$SOURCESLUG" ]; then

						RESULT=""
						
						# - output syncing and activating message -
						yellow "****"; printf " Syncing and activating plugin "; cyan "$PLUGINSLUG"; printf " on "; green "$SITENAME"; echo "..."

						# - sync plugin -
						syncplugin "$PLUGINSLUG"

						# - check syncing result before activating -
						if [ "$RESULT" == "success" ]; then
							activateplugin "$REALSLUG"
						else 
							red "Failed!"; printf "Plugin "; cyan "$PLUGINSLUG"; echo " was not activated."
						fi
					fi
				done
			fi
		fi
	done < "$CONFIG"
}

# ---------- #
# Sync Theme #
# ---------- #
function synctheme {
	
	local SOURCETYPE; local SOURCESLUG; local SOURCEPATH; local THEMEPATH; local DOSYNC
	local THEME; THEME=$1;

	# TODO: sync theme for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot sync theme for YML configs (yet.)"; return
	fi

	# TODO: sync theme for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot sync theme for site aliases (yet.)"; return
	fi

	# TODO: sync theme for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot sync theme for SSH sites (yet.)"; return
	fi

	# - read source config lines -
	MATCHED=""
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# - ignore lines starting with # -
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			# - match theme source types -
			if [ "$SOURCETYPE" == "theme" ]; then

				# - reset do sync flag -
				DOSYNC=""

				# - maybe split source reference to get actual plugin/theme slug -
				# (used for syncing a development version with the same slug)
				# 1.0.7: fix by moving out from inside dosync condition
				ACTUALSLUG="$SOURCESLUG"
				if [[ "$SOURCESLUG" == *":"* ]]; then
					IFS=":" read -r -a SLUGINFO <<< "$SOURCESLUG"
					SOURCESLUG=${SLUGINFO[0]}
					ACTUALSLUG=${SLUGINFO[1]}
				fi
					
				# - match theme slugs -
				if [ "$THEME" == "all" ] || [ "$THEME" == "$SOURCESLUG" ]; then 
					DOSYNC="true"
				elif [[ "$THEME" == *","* ]]; then
					IFS="," read -r -a THEMES <<< "$THEME"
					for THEMESLUG in "${THEMES[@]}"; do
						if [ "$THEMESLUG" == "$SOURCESLUG" ]; then 
							DOSYNC="true"
						fi
					done
				fi

				# - maybe sync now -
				if [ "$DOSYNC" == "true" ]; then

					RESULT=""; MATCHED="true"

					# - check if source is GIT / zip or URL zip -
					checksource

					# - sync if source path directory set -
					if [ -d "$SOURCEPATH" ]; then

						# - source reference message  -
						if [ ! "$SOURCESLUG" == "$ACTUALSLUG" ]; then
							yellow "*"; white " Using source reference "; cyan "$SOURCESLUG"; white " for theme slug "; cyan "$ACTUALSLUG"; echo ""
						fi
						
						# - maybe create theme dir -
						THEMEPATH="$SITEPATH""wp-content/themes/""$ACTUALSLUG""/"
						if [ ! -d "$THEMEPATH" ]; then
							mkdir "$THEMEPATH"
						fi

						# - output syncing theme message -
						yellow "***"; printf " Syncing Theme "; cyan "$SOURCESLUG"; printf " to site "; green "$SITENAME"; echo " "

						# - sync theme from source -							
						# TODO: maybe use rsync --backup option?
						# rsync -av --delete --delay-updates "$SOURCEPATH" "$THEMEPATH"
						# 1.0.8: add summary stats but skip directory list output
						rsync -avO --stats --no-perms --no-owner --no-group --delete --delay-updates "$SOURCEPATH" "$THEMEPATH"

						# - set file ownership permissions -
						if [ -n "$SITEGROUP" ]; then
							chown -R "$SITEUSER":"$SITEGROUP" "$THEMEPATH"
						else
							chown -R "$SITEUSER" "$THEMEPATH"
						fi

						# - output theme sync info -							
						printf "Theme Source: "; cyan "$SOURCEPATH"; echo "";
						printf "Synced to: "; green "$THEMEPATH"; echo " "

						RESULT="success"

						# - maybe cleanup git / zip dir -
						if [ "$GIT" == "true" ] || [ "$ZIP" == "true" ]; then
							rm -rf "$INSTALLTEMP"
						fi

					else
						# - output invalid source directory message -
						red "Warning: "; printf "Invalid Theme Source configuration, check "; white "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; printf ". Skipping..."; echo " "
					fi
				fi
			fi
		fi
	done < "$CONFIG"

	if [ -z "$MATCHED" ]; then
		# - output no matching theme message -
		red "Error!"; printf " No matching theme slug found, check "; cyan "wpx.conf"; printf " for "; yellow "$THEME"; echo "."
	fi
}

# ----------------------- #
# Sync and Activate Theme #
# ----------------------- #
function syncactivatetheme {

	local THEME; THEME=$1;

	# TODO: sync activate theme for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot sync and activate theme for YML configs (yet.)"; return
	fi

	# TODO: sync activate theme for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot sync and activate theme for site aliases (yet.)"; return
	fi

	# TODO: sync activate theme for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot sync and activate theme for SSH sites (yet.)"; return
	fi

	# TODO: maybe handle multisite theme activation for blog ID ?
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	if [ "$MULTISITE" == "0"]; then
		red "Error! "; echo " WPX can only sync - not sync and activate a theme on Multisite (yet.)"
	fi

	if [[ "$THEME" == *","* ]]; then
		# - output activate one theme only message -
		red "Error!"; echo " You cannot activate multiple themes. Choose one!"; exit
	else
		# - output sync and activate theme message -
		yellow "****"; printf " Syncing and activating theme "; cyan "$THEME"; printf " on "; green "$SITENAME"; echo "..."
	fi

	# - read source config lines -
	# 1.0.4: loop sources to get actual slug for dev sources
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# - ignore lines starting with # -
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "theme" ]; then

				# - maybe split source reference to get actual plugin/theme slug -
				# (used for syncing a development version with the same slug)
				THEMESLUG="$THEME"
				if [[ "$SOURCESLUG" == *":"* ]]; then
					IFS=":" read -r -a SLUGINFO <<< "$SOURCESLUG"
					SOURCESLUG=${SLUGINFO[0]}
					THEMESLUG=${SLUGINFO[1]}
				fi

				if [ "$THEME" == "$SOURCESLUG" ]; then

					RESULT=""

					# - sync theme -
					synctheme "$THEME";

					# - activate theme -
					if [ "$RESULT" == "success" ]; then	
						activatetheme "$THEMESLUG"
					else
						red "Failed!"; printf "Theme "; cyan "$THEME"; echo "not activated."
					fi
				fi
			fi
		fi
	done < "$CONFIG"
}

# ----------------------- #
# Sync Must Use Plugin(s) #
# ----------------------- #
function syncmuplugin {
	
	local SOURCETYPE; local SOURCESLUG; local SOURCEPATH; local PLUGINPATH; local DOSYNC
	local PLUGINS; PLUGINS=$1;

	# TODO: sync muse use plugin for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot sync must-use plugins for YML configs (yet.)"; return
	fi

	# TODO: sync must use plugin for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot sync must-use plugins for site aliases (yet.)"; return
	fi

	# TODO: sync must use plugin for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot sync must-use plugins for SSH sites (yet.)"; return
	fi

	# read file without requiring it to end in a new line
	# ref: https://stackoverflow.com/a/31398490/5240159
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# ignore lines starting with #
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "muplugin" ]; then

				# - reset do sync flag -
				DOSYNC="false"

				# - check slug match -
				if [ "$PLUGINS" == "all" ]; then
					DOSYNC="true"; fi
				if [ "$PLUGINS" == "$SOURCESLUG" ]; then
					DOSYNC="true"; fi
				if [[ "$PLUGINS" == *","* ]]; then
					IFS="," read -r -a PLUGINSLUGS <<< "$PLUGINS"
					for PLUGIN in "${PLUGINSLUGS[@]}"; do
						if [ "$PLUGIN" == "$SOURCESLUG" ]; then
							DOSYNC="true"; 
						fi
					done
				fi

				if [ "$DOSYNC" == "true" ]; then

					MATCHED="true"

					# - handle .zip source files -
					checksource

					if [ -d "$SOURCEPATH" ]; then
					
						# - maybe create mu-plugin dir -
						PLUGINPATH=$SITEPATH"wp-content/mu-plugins/"
						if [ ! -d "$PLUGINPATH" ]; then
							mkdir "$PLUGINPATH"
							if [ -n "$SITEGROUP" ]; then
								chown "$SITEUSER":"$SITEGROUP" "$PLUGINPATH"
							else
								chown "$SITEUSER" "$PLUGINPATH"
							fi
						fi

						# - output syncing message -
						yellow "***"; printf " Syncing Must-Use Plugin "; cyan "$SOURCESLUG"; printf " to site "; green "$SITENAME"; echo " "

						# - sync must use plugin -
						# Note: do not ever use --delete option here!!!
						# TODO: maybe use rsync with --backup option ?
						# 1.0.5: fix to use working command syntax
						COMMAND="$SUDO""rsync -av --delay-updates ""$SOURCEPATH"" ""$PLUGINPATH"
						OUTPUT=$($COMMAND)
						echo "$OUTPUT"
						
						# - find matching files with rsync dry run -
						COMMAND="$SUDO""rsync -n -I -ai --out-format=%n ""$SOURCEPATH"" ""$PLUGINPATH"

						# - loop matching files and set permissions -
						# 1.0.5: set permissions for exact file list
						FILECOUNT=0; FILELIST=$($COMMAND)
						readarray -t FILES <<< "$FILELIST"
						for FILEPATH in "${FILES[@]}"; do
							if [ ! "${FILEPATH:0:2}" == "./" ]; then
								if [ -f "$PLUGINPATH""$FILEPATH" ] || [ -d "$PLUGINPATH""$FILEPATH" ]; then
									if [ -n "$SITEGROUP" ]; then
										chown "$SITEUSER":"$SITEGROUP" "$PLUGINPATH""$FILEPATH"
									else
										chown "$SITEUSER" "$PLUGINPATH""$FILEPATH"
									fi
								fi
								((++FILECOUNT))
							fi
						done

						# - output extra info -							
						printf "Must Use Plugin Path: "; cyan "$SOURCEPATH"; echo "";
						yellow "$FILECOUNT"; printf " files Synced to: "; green "$PLUGINPATH"; echo " "

						RESULT="success"
					else
						# - output invalid source directory message -
						# 1.0.5: fix incorrect nesting on invalid source message
						red "Warning: "; printf "Invalid source directory, check "; white "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; printf ". Skipping..."; echo " "
					fi
				fi
			fi
		fi
	done < "$CONFIG"

	if [ -z "$MATCHED" ]; then
		# - output no matching slug message -
		red "Error!"; printf " No matching must-use plugin slug found, check "; white "wpx.conf"; printf " for "; yellow "$PLUGINS"; echo "."
	fi
}

# ---------------------- #
# Delete Must-use Plugin #
# ---------------------- #
function deletemuplugin {

	local SOURCETYPE; local SOURCESLUG; local SOURCEPATH; local PLUGINPATH; local DOSYNC
	local PLUGINS; PLUGINS=$1;

	# TODO: delete must use plugin for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot remove must-use plugins for YML configs (yet.)"; return
	fi

	# TODO: delete must use plugin for alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot delete must-use plugins for site aliases (yet.)"; return
	fi

	# TODO: sync must use plugin for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot delete must-use plugins for SSH sites (yet.)"; return
	fi

	# read file without requiring it to end in a new line
	# ref: https://stackoverflow.com/a/31398490/5240159
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# ignore lines starting with #
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "muplugin" ]; then

				# - reset do sync flag -
				DOSYNC="false"

				# - check slug match -
				if [ "$PLUGINS" == "all" ]; then
					DOSYNC="true"; fi
				if [ "$PLUGINS" == "$SOURCESLUG" ]; then
					DOSYNC="true"; fi
				if [[ "$PLUGINS" == *","* ]]; then
					IFS="," read -r -a PLUGINSLUGS <<< "$PLUGINS"
					for PLUGIN in "${PLUGINSLUGS[@]}"; do
						if [ "$PLUGIN" == "$SOURCESLUG" ]; then
							DOSYNC="true"; 
						fi
					done
				fi

				if [ "$DOSYNC" == "true" ]; then

					MATCHED="true"
					PLUGINPATH=$SITEPATH"wp-content/mu-plugins/"

					# - handle .zip source files -
					checksource

					if [ -d "$SOURCEPATH" ]; then
					
						# - output deleting message -
						yellow "***"; printf " Deleting matching Must-Use Plugin files for "; cyan "$SOURCESLUG"; printf " on site "; green "$SITENAME"; echo " "

						# - find matching files with rsync dry run -
						COMMAND="$SUDO""rsync -n -I -ai --out-format=%n ""$SOURCEPATH"" ""$PLUGINPATH"

						# - loop matching files and delete -						
						FILECOUNT=0; FILELIST=$($COMMAND)
						readarray -t FILES <<< "$FILELIST"
						for FILEPATH in "${FILES[@]}"; do
							if [ ! "${FILEPATH:0:2}" == "./" ]; then
								if [ -f "$PLUGINPATH""$FILEPATH" ]; then
									rm "$PLUGINPATH""$FILEPATH"
									echo "Deleted file ""$FILEPATH"" from destination site..."
									((++FILECOUNT))
								fi
							fi
						done
						if [ "$FILECOUNT" -gt 0 ]; then
							yellow "$FILECOUNT"; echo " matching files have been deleted.";
						else
							echo "No matching files found to delete.";
						fi

						# - now remove matching directories -
						DIRCOUNT=0; DIRLIST=$($COMMAND)
						readarray -t DIRS <<< "$DIRLIST"
						for DIRPATH in "${DIRS[@]}"; do
							if [ ! "${DIRPATH:0:2}" == "./" ]; then
								if [ -d "$PLUGINPATH""$DIRPATH" ]; then
									rmdir "$PLUGINPATH""$DIRPATH"
									# echo "Removed directory ""$DIRPATH"" from destination site..."
									((++DIRCOUNT))
								fi
							fi
						done
						if [ "$DIRCOUNT" -gt 0 ]; then
							yellow "$DIRCOUNT"; echo " matching (empty) directories have been removed.";
						fi

						RESULT="success"
					else
						# - output invalid source directory message -
						red "Warning: "; printf "Invalid source directory, check "; white "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; printf ". Skipping..."; echo " "
					fi
				fi
			fi
		fi
	done < "$CONFIG"

	if [ -z "$MATCHED" ]; then
		# - output no matching slug message -
		red "Error!"; printf " No matching must-use plugin slug found, check "; white "wpx.conf"; printf " for "; yellow "$PLUGINS"; echo "."
	fi
}

# -------------- #
# Sync Dropin(s) #
# -------------- #
# (files relative to source directory)
function syncdropin {
	
	local SOURCETYPE; local SOURCESLUG; local SOURCEPATH; local DOSYNC
	local DROPIN; DROPIN=$1

	# TODO: sync dropin for site alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot sync dropins for site aliases (yet.)"; return
	fi

	# TODO: sync dropin for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot sync dropins for SSH sites (yet.)"; return
	fi

	# TODO: sync dropin for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot sync dropins for YML configs (yet.)"; return
	fi

	# - read file without requiring it to end in a new line -
	# ref: https://stackoverflow.com/a/31398490/5240159
	MATCHED=""
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# - ignore lines starting with # -
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "dropin" ]; then

				# - reset do sync flag -
				DOSYNC="false"

				# - check slug match -
				if [ "$DROPIN" == "all" ]; then
					DOSYNC="true"; fi
				if [ "$DROPIN" == "$SOURCESLUG" ]; then
					DOSYNC="true"; fi
				if [[ "$DROPIN" == *","* ]]; then
					IFS="," read -r -a FILES <<< "$FILE"
					for FILE in "${FILES[@]}"; do
						if [ "$FILE" == "$SOURCESLUG" ]; then
							DOSYNC="true"; 
						fi
					done
				fi

				if [ "$DOSYNC" == "true" ]; then

					MATCHED="true"

					# - handle .zip source files -
					checksource

					if [ -d "$SOURCEPATH" ]; then

						# - output syncing drop-in (base relative) files -
						yellow "***"; printf " Syncing Drop-in Files "; cyan "$SOURCESLUG"; printf " to site "; green "$SITENAME"; echo " "

						# - sync base relative files -
						# note: do not use --delete option here!!!
						# TODO: maybe use rsync with --backup option ?
						# rsync -av --delay-updates "$SOURCEPATH" "$SITEPATH"
						# 1.0.5: fix to use working command syntax
						COMMAND="$SUDO""rsync -av --delay-updates ""$SOURCEPATH"" ""$SITEPATH"
						OUTPUT=$($COMMAND)
						echo "$OUTPUT"
						
						# - find matching files with rsync dry run -
						COMMAND="$SUDO""rsync -n -I -ai --out-format=%n ""$SOURCEPATH"" ""$SITEPATH"

						# - loop matching files and set permissions -
						# 1.0.5: set permissions for exact file list
						FILECOUNT=0; FILELIST=$($COMMAND)
						readarray -t FILES <<< "$FILELIST"
						for FILEPATH in "${FILES[@]}"; do
							if [ ! "${FILEPATH:0:2}" == "./" ]; then
								if [ -f "$PLUGINPATH""$FILEPATH" ] || [ -d "$PLUGINPATH""$FILEPATH" ]; then
									if [ -n "$SITEGROUP" ]; then
										chown "$SITEUSER":"$SITEGROUP" "$SITEPATH""$FILEPATH"
									else
										chown "$SITEUSER" "$SITEPATH""$FILEPATH"
									fi
								fi
								((++FILECOUNT))
							fi
						done

						# - output extra info -
						printf "Source Dropin File Path: "; cyan "$SOURCEPATH"; echo "";
						yellow "$FILECOUNT"; printf " files Synced (relative) to: "; green "$SITEPATH"; echo ""

						RESULT="success"

					else
						# - output invalid source directory message -
						# 1.0.5: fix incorrect nesting on invalid source message
						red "Warning: "; printf "Invalid source directory, check "; white "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; printf ". Skipping..."; echo " "
					fi
				fi

			fi
		fi
	done < "$CONFIG"

	if [ -z "$MATCHED" ]; then
		# - output no slug match message -
		red "Error!"; printf " No matching base file slug found, check "; white "wpx.conf"; printf " for "; yellow "$DROPIN"; echo "."
	fi
}

# ---------------- #
# Delete Dropin(s) #
# ---------------- #
function deletedropin {
	
	local SOURCETYPE; local SOURCESLUG; local SOURCEPATH; local DOSYNC
	local DROPIN; DROPIN=$1

	# TODO: sync dropin for site alias
	if [ -n "$ALIAS" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot delete dropins for site aliases (yet.)"; return
	fi

	# TODO: sync dropin for SSH
	if [ -n "$SSH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " "; cyan "@""$ALIAS"; echo ""
		echo " WPX cannot delete dropins for SSH sites (yet.)"; return
	fi

	# TODO: sync dropin for YML configs
	if [ -n "$YMLPATH" ]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$SSH"; echo ")"
		echo " WPX cannot delete dropins for YML configs (yet.)"; return
	fi

	# - read file without requiring it to end in a new line -
	# ref: https://stackoverflow.com/a/31398490/5240159
	MATCHED=""
	while IFS= read -r -a SOURCE || [ -n "$SOURCE" ]; do

		# - ignore lines starting with # -
		if [ ! "${SOURCE:0:1}" == "#" ]; then

			# - expand source data -
			IFS=" " read -r -a DATA <<< "$SOURCE"
			SOURCETYPE=${DATA[0]}
			SOURCESLUG=${DATA[1]}
			SOURCEPATH=$(echo "${DATA[2]}" | tr -d '\r')

			if [ "$SOURCETYPE" == "dropin" ]; then

				# - reset do sync flag -
				DOSYNC="false"

				# - check slug match -
				if [ "$DROPIN" == "all" ]; then
					DOSYNC="true"; fi
				if [ "$DROPIN" == "$SOURCESLUG" ]; then
					DOSYNC="true"; fi
				if [[ "$DROPIN" == *","* ]]; then
					IFS="," read -r -a FILES <<< "$DROPIN"
					for FILE in "${FILES[@]}"; do
						if [ "$FILE" == "$SOURCESLUG" ]; then
							DOSYNC="true"; 
						fi
					done
				fi

				if [ "$DOSYNC" == "true" ]; then

					MATCHED="true"

					# - handle .zip source files -
					checksource

					if [ -d "$SOURCEPATH" ]; then

						# - output deleting message -
						yellow "***"; printf " Deleting matching Drop-in files for "; cyan "$SOURCESLUG"; printf " on site "; green "$SITENAME"; echo " "

						# - find matching files with rsync dry run -
						COMMAND="$SUDO""rsync -n -I -ai --out-format=%n ""$SOURCEPATH"" ""$SITEPATH"
						
						# - loop matching files and delete -						
						FILECOUNT=0; FILELIST=$($COMMAND)
						readarray -t FILES <<< "$FILELIST"
						for FILEPATH in "${FILES[@]}"; do
							if [ ! "${FILEPATH:0:2}" == "./" ]; then
								if [ -f "$PLUGINPATH""$FILEPATH" ]; then
									rm "$PLUGINPATH""$FILEPATH"
									echo "Deleted file ""$FILEPATH"" from destination site..."
									((++FILECOUNT))
								fi
							fi
						done
						if [ "$FILECOUNT" -gt 0 ]; then
							yellow "$FILECOUNT"; echo " matching files have been deleted.";
						else
							echo "No matching files were found to delete.";
						fi

						# - now remove matching directories -
						DIRCOUNT=0; DIRLIST=$($COMMAND)
						readarray -t DIRS <<< "$DIRLIST"
						for DIRPATH in "${DIRS[@]}"; do
							if [ ! "${DIRPATH:0:2}" == "./" ]; then
								if [ -d "$PLUGINPATH""$DIRPATH" ]; then
									rmdir "$PLUGINPATH""$DIRPATH"
									# echo "Removed directory ""$DIRPATH"" from destination site..."
									((++DIRCOUNT))
								fi
							fi
						done
						if [ "$DIRCOUNT" -gt 0 ]; then
							yellow "$DIRCOUNT"; echo " matching (empty) directories have been removed.";
						fi

						RESULT="success"

					else
						# - output invalid source directory message -
						red "Warning: "; printf "Invalid source directory, check "; white "wpx.conf"; printf " for "; yellow "$SOURCESLUG"; printf ". Skipping..."; echo " "
					fi
				fi

			fi
		fi
	done < "$CONFIG"

	if [ -z "$MATCHED" ]; then
		# - output no slug match message -
		red "Error!"; printf " No matching base file slug found, check "; white "wpx.conf"; printf " for "; yellow "$DROPIN"; echo "."
	fi
}

# ------------------------- #
# === LANGUAGE COMMANDS === #
# ------------------------- #

# ---------------- #
# Install Language #
# ---------------- #
function installlanguage {

	local $LOCALE; LOCALE="$1"
	SUCCESS="Success: installed 1 of 1 languages"

	# - loop locale languages -
	IFS="," read -r -a LOCALES <<< "$LOCALE"
	for LOCALE in "${LOCALES[@]}"; do
	
		# - output installing language message -
		yellow "***"; printf " Installing language locale "; cyan "$LOCALE"; printf " on "; green "$SITENAME"; echo "..."
	
		# - set command and execute  -
		COMMAND="$WP"" language core install ""$LOCALE"
		OUTPUT=$($COMMAND)

		# - check result and maybe try again -
		# 1.0.7: added third argument for already installed
		checkresult "$OUTPUT" "$SUCCESS" install
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

		echo "$OUTPUT"
	done
}

# ------------------ #
# Uninstall Language #
# ------------------ #
function uninstalllanguage {

	local $LOCALE; LOCALE="$1"
	SUCCESS="Success: Language uninstalled"	

	# - loop locale languages -
	IFS="," read -r -a LOCALES <<< "$LOCALE"
	for LOCALE in "${LOCALES[@]}"; do
	
		# - output installing language message -
		yellow "***"; printf " Uninstalling language locale "; cyan "$LOCALE"; printf " from "; green "$SITENAME"; echo "..."

		# - set command and execute -
		COMMAND="$WP"" language core uninstall ""$LOCALE"
		OUTPUT=$($COMMAND)
		
		# - check result and maybe try again -
		checkresult "$OUTPUT" "$SUCCESS"
		if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi
		
		echo "$OUTPUT"
		
	done
}

# --------------- #
# Update Language #
# --------------- #
function updatelanguage {

	SUCCESS="Success: Translations are up to date"

	# - update languages -
	COMMAND="$WP"" language core update"
	OUTPUT=$($COMMAND)

	# - check result and maybe try again -
	# 1.0.7: added third argument for already updated
	checkresult "$OUTPUT" "$SUCCESS" update
	if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

	echo "$OUTPUT"
}

# ----------------- #
# Activate Language #
# ----------------- #
function activatelanguage {

	local $LOCALE; LOCALE="$1"
	SUCCESS="Success: Language activated"

	# TODO: allow for language activation on Multisite via Blog ID
	COMMAND="$WP"" core is-installed --network"
	OUTPUT=$($COMMAND)
	MULTISITE=$?
	if [ "$MULTISITE" == "0"]; then
		red "Failed "; printf " on "; green "$SITENAME"; printf " ("; yellow "$YMLPATH"; echo ")"
		echo " WPX cannot activate a language on Multisite (yet.)"; return
	fi

	# - output activating language message -
	yellow "***"; printf " Activating language locale "; cyan "$LOCALE"; printf " on "; green "$SITENAME"; echo "..."

	# - activate language -
	COMMAND="$WP"" site switch-language ""$LOCALE"
	OUTPUT=$($COMMAND)

	# - check result and maybe try again -
	# 1.0.7: added third argument for already activated
	checkresult "$OUTPUT" "$SUCCESS" activate
	if [ "$RESULT" == "failed" ]; then OUTPUT=$($COMMAND); fi

	echo "$OUTPUT"
}

# -------------------------
# end all command functions


# ------------------------------ #
# === COMMAND LINE ARGUMENTS === #
# ------------------------------ #
SILENT="false"

# [1.1] - check action argument -
if [ -z "$1" ]; then
	# - output valid commands message
	validcommands; exit 1
fi

# [1.2] - run wp --debug --info -
# 1.0.4: allow running WP CLI debug without site arg
if [ "$1" == "debug" ] || [ "$1" == "debuginfo" ]; then
	if [ -z "$2" ]; then
		wp --debug --info
		exit 0
	fi
fi

# [1.3] - maybe set show configuration switch -
createarray "show" "config" "check" "config"; IN1=$(checkarray "$1")
createarray "show" "site" "check" "site"; IN2=$(checkarray "$1")
createarray "show" "source" "check" "source"; IN3=$(checkarray "$1")
if [ "$1" == "config" ] || [ "$IN1" == "1" ] || [ "$IN2" == "1" ] || [ "$IN3" == "1" ]; then 

	# - set done and show config values -
	DONE="true"; 
	if [ "$1" == "config" ] || [ "$IN1" == "1" ]; then SHOWCONFIG="true"; fi
	if [ "$IN2" == "1" ]; then SHOWCONFIG="sites"; fi
	if [ "$IN3" == "1" ]; then SHOWCONFIG="sources"; fi
	
	# - site table headings -
	if [ "$SHOWCONFIG" == "true" ] || [ "$SHOWCONFIG" == "sites" ]; then
		SITETABLE=""; 
		SITETABLE+=$(white "SLUG"); SITETABLE+="|"
		SITETABLE+=$(white "USER"); SITETABLE+="|"
		SITETABLE+=$(white "GROUP"); SITETABLE+="|"
		SITETABLE+=$(white "PATH"); SITETABLE+="|"
		SITETABLE+=$(white "VALID"); SITETABLE+="|"
		SITETABLE+=$(white "LOCK"); SITETABLE+=$'\r\n'
	fi
	
	# - sources table headings -
	if [ "$SHOWCONFIG" == "true" ] || [ "$SHOWCONFIG" == "sources" ]; then
		SOURCETABLE=""
		SOURCETABLE+=$(white "TYPE"); SOURCETABLE+="|"
		SOURCETABLE+=$(white "SLUG"); SOURCETABLE+="|"
		SOURCETABLE+=$(white "PATH"); SOURCETABLE+=$'\r\n'
	fi
fi

# [1.4] - check for WPX updates -
# 1.0.4: added update check command
createarray "check" "update"; INARRAY=$(checkarray "$1")
if [ "$INARRAY" == "1" ]; then
	updatecheck; exit
fi

# [1.5] - update WPX script -
# 1.0.4: added update script command
createarray "update" "script"; INARRAY=$(checkarray "$1")
if [ "$INARRAY" == "1" ]; then
	updatescript; exit
fi


# [2] - target site slugs -
if [ -z "$2" ]; then
	if [ -z "$SHOWCONFIG" ]; then
		red "Error!"; printf " Specify target site slug(s)... (or use "; yellow "all"; echo ")"; exit 1
	fi
else 
	# - extract comma separated arguments for $2 to sitename slugs -
	# ref: https://stackoverflow.com/questions/10586153/split-string-into-an-array-in-bash
	IFS="," read -r -a SITENAMES <<< "$2"

	# - loop sites to check for aliases -
	# (note: development only feature)
	I=0	
	for SITE in "${SITENAMES[@]}"; do
		# - maybe split to site and alias -
		if [[ "$SITE" == *"@"* ]]; then
			# 1.0.5: fix to split SITE not SITENAMES
			IFS="@" read -r -a SITEALIAS <<< "$SITE"
			SITENAMES[$I]=${SITEALIAS[0]}
			ALIASES[$I]=${SITEALIAS[1]}
		fi
		((++I))
	done
fi

# [3.1] - plugin slugs for plugin actions -
if [[ "$1" == *"plugin"* ]]; then
	ARRAY=("updateallplugins" "update_all_plugins" "update-all-plugins"\
		"pluginsupdateall" "plugins_update_all" "plugins-update-all")
	INARRAY=$(checkarray "$1")
	if [ ! "$INARRAY" == "1" ]; then
		if [ -z "$3" ]; then
			createarray "list" "plugin" "check" "plugin"; INARRAY=$(checkarray "$1")
			if [ "$INARRAY" == "1" ]; then
				# - auto-set to list all for list actions -
				SLUGS="all"
			else 	
				# - output specify plugin slugs message -
				red "Error!"; printf " You must specify plugin slug(s)"; echo "..."; exit 1
			fi
		else
			# - set specified slugs -
			SLUGS="$3"
		fi
	fi
fi

# [3.2] - theme slugs for theme actions -
if [[ "$1" == *"theme"* ]]; then
	if [ -z "$3" ]; then
		# createarray "list" "theme"; INARRAY=$(checkarray "$1")
		# if [ "$INARRAY" == "1" ]; then
		#	# - auto-set to list all for list actions -
		#	printf "No theme specified, setting to "; yellow "all"; echo "..."
		#	SLUGS="all"
		# else
			# 1.0.5: fix to backwards check condition
		 	createarray "check" "theme"; INARRAY=$(checkarray "$1")
		 	if [ "$INARRAY" == "1" ]; then
				# - output specify theme slugs message -
				red "Error!"; printf " You must specify theme slug(s)"; echo "..."; exit 1
			fi
		# fi	
	else
		# - set specified slugs -
		SLUGS="$3"
	fi
fi

# [3.3] - misc sync command slugs -
# - synccore : core slug -
# - syncmuplugin, deletemuplugin : muplugin slug -
# - syncdropin, deletedropin : dropin slug -
if [[ "$1" == *"sync"* ]]; then
	createarray "sync" "core"; IN1=$(checkarray "$1")
	createarray "sync" "muplugin" "sync" "mustuseplugin"; IN2=$(checkarray "$1")
	createarray "sync" "dropin" "sync" "files"; IN3=$(checkarray "$1")
	if [ "$IN1" == "1" ] || [ "$IN2" == "1" ] || [ "$IN3" == "1" ]; then SLUGS="$3"; fi
fi
# 1.0.5: added checks for deletemuplugin and deletedropin
if [[ "$1" == *"delete"* ]]; then
	createarray  "delete" "muplugin" "remove" "muplugin"; IN1=$(checkarray "$1")
	createarray  "delete" "dropin" "remove" "dropin"; IN2=$(checkarray "$1")
	if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then SLUGS="$3"; fi
fi

# [3.4] - arguments for core install / update -
# - installcore : version / locale -
# - updatecore : version -
createarray "install" "core" "update" "core"; INARRAY=$(checkarray "$1")
if [ "$INARRAY" == "1" ]; then
	if [ -n "$3" ]; then VERSION="$3"; fi
	if [ -n "$4" ]; then LOCALE="$4"; fi
fi

# [3.5] - arguments for language commands -
# note: locale not used for language updates
createarray "install" "language" "uninstall" "language"; IN1=$(checkarray "$1")
createarray "activate" "language"; IN2=$(checkarray "$1")
createarray "install" "locale" "uninstall" "locale"; IN3=$(checkarray "$1")
createarray "activate" "locale"; IN4=$(checkarray "$1")
if [ "$IN1" == "1" ] || [ "$IN2" == "1" ] || [ "$IN3" == "1" ] || [ "$IN4" == "1" ]; then
	if [ -n "$3" ]; then 
		LOCALE="$3"
		if [ "$DEBUG" == "true" ]; then echo "Locale: ""$LOCALE"; fi
	else 
		red "Error!"; printf " You must specify a language locale."; echo ""; exit 1
	fi
fi

# [3.6] - option key argument for get option command -
createarray "get" "option" "get" "value"; INARRAY=$(checkarray "$1")
if [ "$INARRAY" == "1" ]; then
	if [ -n "$3" ]; then 
		OPTION="$3"; SILENT="true"
	else 
		red "Error!"; printf " You must specify an option meta key."; echo ""; exit 1
	fi
fi

# [3.7] - string argument for search commands -
# createarray "search" "files" "search" "string"; IN1=$(checkarray "$1")
# createarray "search" "db" "search" "database"; IN2=$(checkarray "$1")
# if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
# 	if [ -n "$3" ]; then 
# 		STRING="$3";
# 	else 
# 		red "Error!"; printf " You must specify a string to search for."; echo ""; exit 1
# 	fi
# fi

# - debug output for slugs -
if [ "$DEBUG" == "true" ]; then echo "Slugs: ""$SLUGS"; fi


# -------------------------- #
# === LOOP SITE COMMANDS === #
# -------------------------- #

# - check and set wpx.conf path -
if [ -f "$SCRIPTDIR""/wpx.conf" ]; then
	CONFIG="$SCRIPTDIR""/wpx.conf"
elif [ -f "/root/.wp-cli/wpx.conf" ]; then
	CONFIG="/root/.wp-cli/wpx.conf"
fi

# - maybe output configuration path -
if [ ! "$SILENT" == "true" ]; then
	if [ -n "$CONFIG" ]; then
		# - output config found message -
		printf "Using WPX configuration file found at: "; cyan "$CONFIG"; echo ""
	else 
		# - output no config file message -
		red "Error!"; printf " No "; yellow "wpx.conf"; printf " configuration file found!"; echo " Time to create one?"; exit 1
	fi
fi

# - loop all lines in config file - 
# (without requiring it to end in a new line)
# ref: https://stackoverflow.com/a/31398490/5240159
SITECOUNT=0; SOURCECOUNT=0; J=0; FOUNDSITES=()
while IFS= read -r -a LINE || [ -n "$LINE" ]; do

	# - ignore lines starting with # -
	if [ ! "${LINE:0:1}" == "#" ]; then

		# - expand config data -
		IFS=" " read -r -a DATA <<< $LINE
		TYPE=${DATA[0]}

		# - match only site lines -
		if [ "$TYPE" == "site" ]; then
			
			# - reset skip flag -
			SKIP="false";

			# - increment site count -
			((++SITECOUNT))
		
			# - get site data config -
			SITENAME=${DATA[1]}
			SITEPATH=${DATA[2]}
			SITEUSER=$(echo "${DATA[3]}" | tr -d '\r')
			SITEGROUP=""

			# - maybe get specified alias for site -
			I=0; ALIAS=""
			for SITE in "${SITENAMES[@]}"; do
				if [ -n "${ALIASES[$I]}" ]; then
					ALIAS="${ALIASES[$I]}"
				fi
				((++I))
			done

			# - maybe split user into user:group -
			if [[ "$SITEUSER" == *":"* ]]; then
				IFS=":" read -r -a SITEINFO <<< "$SITEUSER"
				SITEUSER=${SITEINFO[0]}
				SITEGROUP=${SITEINFO[1]}
			fi

			# - maybe set site locking flag -
			if [ "${SITEPATH:0:1}" == "!" ]; then
				SITEPATH=${SITEPATH:1}
				SITELOCKING="true"
			else 
				SITELOCKING="false"
			fi

			# - maybe check specified .yml file for use as config -
			YMLPATH=""; EXT="${SITEPATH:(-4):4}"
			if [ "$EXT" == ".yml" ]; then
				EXT1="${SITEPATH:(-10):10}"; EXT2="${SITEPATH:(-16):16}"
				if [ "$EXT1" == "wp-cli.yml" ] || [ "$EXT2" == "wp-cli.local.yml" ]; then

					if [ -f "$SITEPATH" ]; then
						if [ "$EXT1" == "wp-cli.yml" ]; then
							YMLPATH="$SITEPATH"
							SITEPATH="${SITEPATH:0:(-10)}"
						fi
						if [ "$EXT2" == "wp-cli.local.yml" ]; then
							YMLPATH="$SITEPATH"
							SITEPATH="${SITEPATH:0:(-16)}"
						fi
					else 
						# - output file not found message -
						red "Warning!"; printf " Site "; green "$SITENAME"; printf " config file not found. Path:"; cyan "$SITEPATH"; echo "";
						SKIP="true"
					fi
				else
					# - output YML filename warning message -
					red "Warning!"; printf " Site "; green "$SITENAME"; printf " config YML file must be "; yellow "wp-cli.yml"; printf " or "; yellow "wp-cli.local.yml"; echo " only.";
					SKIP="true"
				fi
			else
				# - check for a config YML in current path -
				# TODO: remote check for config YML in SSH path ?
				FILEPATH1="$SITEPATH""wp-cli.yml"; 
				FILEPATH2="$SITEPATH""wp-cli.local.yml"
				if [ -f "$FILEPATH1" ]; then YMLPATH="$FILEPATH1"; fi
				if [ -f "$FILEPATH2" ]; then YMLPATH="$FILEPATH2"; fi
			fi

			# - maybe add to config output table -
			if [ "$SHOWCONFIG" == "true" ] || [ "$SHOWCONFIG" == "sites" ]; then
				if [ -d "$SITEPATH" ]; then
					VALIDPATH="true"
				else
					VALIDPATH="false"
				fi
				SITETABLE+=$(white "$SITENAME"); SITETABLE+="|"
				SITETABLE+=$(white "$SITEUSER"); SITETABLE+="|"
				SITETABLE+=$(white "$SITEGROUP"); SITETABLE+="|"
				SITETABLE+=$(white "$SITEPATH"); SITETABLE+="|"
				SITETABLE+=$(white "$VALIDPATH"); SITETABLE+="|"
				SITETABLE+=$(white "$SITELOCKING"); SITETABLE+=$'\r\n'
			fi

			# - reset WP and SUDO commands -
			WP=""; SUDO=""; PREFIX=""
			if [ -n "$YMLPATH" ]; then
				# TEMP - use provided config path as global config -
				# 1.0.5: fix to add extra space suffix to YML env prefix
				PREFIX="WP_CLI_CONFIG_PATH=""$YMLPATH"" "
			fi

			# - check if site user matches current user
			# 1.0.5: remove output colors for command success matching
			if [ "$SITEUSER" == "$USER" ]; then
				# - current user is site user, so no sudo needed -
				if [ "$SITEUSER" == "root" ]; then
					WP="$PREFIX""wp --allow-root --no-color"
				else
					WP="$PREFIX""wp --no-color"
				fi				
			else
				# TODO: maybe call sudo_check first?
				WP="$PREFIX""sudo -u ""$SITEUSER"" wp --no-color"
				SUDO="sudo -u ""$SITEUSER"" "
			fi

			# - maybe append site alias to WP command -
			SSH=""
			if [ -n "$ALIAS" ]; then 
				WP+=" @""$ALIAS"" ";
			elif [ -n "$SITEPATH" ]; then 
				# - maybe append SSH switch to WP command -
				# note: experimental devolopment test code
				# see: https://danielbachhuber.com/tip/wp-ssh-custom-path/
				# WP_CLI_SSH_PRE_CMD="PATH=$HOME/bin:$PATH"
				if [ "${SITEPATH:0:4}" == "ssh:" ]; then
					SSH="true"
					SITEPATH="${SITEPATH:4}"
					WP+=" --ssh=""$SITEPATH"
				elif [ -d "$SITEPATH" ]; then
					# - standard change to site path -
					cd "$SITEPATH"
				else
					red "Error!"; printf " Site "; green "$SITENAME"; printf " path "; yellow "$SITEPATH"; echo " not found. Skipping...";
					SKIP="true"
				fi
			fi

			# - check skip flag -
			if [ "$SKIP" == "false" ]; then

				# - reset do flag -
				DO="false"

				# - check site slug match -
				if [ "$2" == "all" ]; then
					DO="true"; FOUND="true"; FOUNDSITES[0]="all";
				fi
				if [ "$2" == "$SITENAME" ]; then
					DO="true"; FOUND="true"; FOUNDSITES[0]="$SITE";
				fi
				if [[ "$2" == *","* ]]; then
					for SITE in "${SITENAMES[@]}"; do
						if [ "$SITE" == "$SITENAME" ]; then
							DO="true"; FOUND="true";
							FOUNDSITES[$J]="$SITE"; ((++J))
						fi
					done
				fi
				
				# - check for matching command -
				if [ "$DO" == "true" ]; then
				
					# - display usage of YML file -
					if [ -n "$YMLPATH" ]; then
						printf "Using YAML Config File for Site "; green "$SITENAME"; printf ": "; cyan "$YMLPATH"; echo ""
					fi

					# - display usage of Alias -
					if [ -n "$ALIAS" ]; then
						printf "Using Alias "; cyan "@""$ALIAS"; printf " for site "; green "$SITENAME"; echo "..."
					fi

					# - display usage of SSH -
					if [ -n "$SSH" ]; then
						printf "Using SSH "; printf " for site "; green "$SITENAME"; echo "..."
					fi

					# ------------- #
					# CORE COMMANDS #
					# ------------- #

					# - run wp --debug --info -
					if [ "$1" == "debug" ] || [ "$1" == "debuginfo" ]; then
						wpclidebug; DONE="true"
					fi
	
					# - check version for core(s) -	
					createarray "check" "version" "check" "core"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then checkversion; DONE="true"; fi
						
					# - verify checksums for core(s) -
					createarray "verify" "core" "verify" "checksum"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then verifycore; DONE="true"; fi

					# - update core(s) -
					createarray "update" "core"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then updatecore "$VERSION"; DONE="true"; fi

					# - install core(s) -
					createarray "install" "core"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then installcore "$VERSION" "$LOCALE"; DONE="true"; fi

					# - reinstall core(s) -
					createarray "reinstall" "core"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then reinstallcore; DONE="true"; fi		
					
					# - lock core(s) -
					createarray "lock" "core"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then lockcore; DONE="true"; fi

					# - unlock core(s) -						
					createarray "unlock" "core"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then unlockcore; DONE="true"; fi

					# - check lock on core(s) -
					createarray "check" "lock" "check" "corelock"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then checkcorelock; DONE="true"; fi
						
					# - check owner/group file permission(s) -
					createarray "check" "owner" "check" "permission"; IN1=$(checkarray "$1")
					createarray "check" "perm"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						checkowners; DONE="true"; fi

					# - fix owner/group file permission(s) -	
					createarray "fix" "owner" "fix" "permission"; IN1=$(checkarray "$1")
					createarray "fix" "perm"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						fixowners; DONE="true"; fi

					# - get option value -
					createarray "get" "option" "get" "value"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then
						getoption; DONE="true"; fi

					# - check update list -
					createarray "update" "list" "list" "update"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then
						updatelist; DONE="true"; fi

					# - search files for string -
					# createarray "search" "files" "scan" "files"; INARRAY=$(checkarray "$1")
					# if [ "$INARRAY" == "1" ]; then
					#	searchfiles; DONE="true"; fi

					# - search database for string -
					# createarray "search" "db" "scan" "database"; INARRAY=$(checkarray "$1")
					# if [ "$INARRAY" == "1" ]; then
					#	searchdatabase; DONE="true"; fi

					# --------------- #
					# PLUGIN COMMANDS #
					# --------------- #

					# - check/list plugin(s) -
					createarray "list" "plugin" "check" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then listplugins "$SLUGS"; DONE="true"; fi

					# - find plugin(s) -
					createarray "find" "plugin" "check" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then findplugins "$SLUGS"; DONE="true"; fi

					# - verify plugin(s) -	
					# 1.0.5: added verify plugin checksums command
					createarray "verify" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then verifyplugin "$SLUGS"; DONE="true"; fi

					# - install plugin(s) -	
					createarray "install" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then installplugin "$SLUGS"; DONE="true"; fi

					# - install and activate plugin(s) -
					createarray "installactivate" "plugin"; IN1=$(checkarray "$1")
					createarray "install_activate" "plugin" "install-activate" "plugin"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						installactivateplugin "$SLUGS"; DONE="true"; fi

					# - reinstall plugin(s) -
					createarray "reinstall" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then reinstallplugin "$SLUGS"; DONE="true"; fi

					# - activate plugin(s) -
					createarray "activate" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then activateplugin "$SLUGS"; DONE="true"; fi

					# - deactivate plugin(s) -
					createarray "deactivate" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then deactivateplugin "$SLUGS"; DONE="true"; fi
										
					# - update plugin(s) -
					createarray "update" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then updateplugin "$SLUGS"; DONE="true"; fi

					# - update all plugins -
					ARRAY=("updateallplugins" "update_all_plugins" "update-all-plugins"); IN1=$(checkarray "$1")
					ARRAY=("pluginsupdateall" "plugins_update_all" "plugins-update-all"); IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						updateplugin "all"; DONE="true"; fi

					# - rollback plugin(s) -
					createarray "rollback" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then rollbackplugin "$SLUGS"; DONE="true"; fi

					# - delete plugin(s) -
					createarray "delete" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then deleteplugin "$SLUGS"; DONE="true"; fi
					
					# - uninstall plugin(s) (deactivate and delete) -
					createarray "uninstall" "plugin" "deletedeactivate" "plugin"; IN1=$(checkarray "$1")
					createarray "deactivate_delete" "plugin" "deactivate-delete" "plugin"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						uninstallplugin "$SLUGS"; DONE="true"; fi

					# -------------- #
					# THEME COMMANDS # 
					# -------------- #

					# - list theme(s) -
					createarray "list" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then listthemes "$SLUGS"; DONE="true"; fi
					
					# - check theme -
					createarray "check" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then checktheme; DONE="true"; fi
													
					# - install theme(s) -
					createarray "install" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then installtheme "$SLUGS"; DONE="true"; fi
					
					# - install and activate theme (singular only) -
					createarray "installactivate" "theme"; IN1=$(checkarray "$1")
					createarray "install_activate" "theme" "install-activate" "theme"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						installactivatetheme "$SLUGS"; DONE="true"; fi
					
					# - reinstall theme(s)
					createarray "reinstall" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then reinstalltheme "$SLUGS"; DONE="true"; fi

					# - activate theme (singular only) -
					createarray "activate" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then activatetheme "$SLUGS"; DONE="true"; fi

					# - update theme(s) -
					createarray "update" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then updatetheme "$SLUGS"; DONE="true"; fi
					
					# - rollback theme(s) -
					createarray "rollback" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then rollbacktheme "$SLUGS"; DONE="true"; fi
					
					# - delete theme(s)
					createarray "delete" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then deletetheme "$SLUGS"; DONE="true"; fi

					# - update all themes -
					ARRAY=("updateallthemes" "update_all_themes" "update-all-themes"); IN1=$(checkarray "$1")
					ARRAY=("themesupdateall" "themes_update_all" "themes-update-all"); IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						updatetheme "all"; DONE="true"; fi
	
					# ------------- #
					# SYNC COMMANDS #
					# ------------- #

					# - sync core(s) -
					createarray "sync" "core"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then synccore "$SLUGS"; DONE="true"; fi
					
					# - sync plugin(s) -
					createarray "sync" "plugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then syncplugin "$SLUGS" "false"; DONE="true"; fi
					
					# - sync existing plugin(s) -
					# 1.0.8: added sync existing plugins command
					if [ "syncexistingplugin" == "$1" ]; then syncplugin "$SLUGS" "true"; DONE="true"; fi
					if [ "syncexistingplugins" == "$1" ]; then syncplugin "$SLUGS" "true"; DONE="true"; fi
						
					# - sync and activate plugin(s) -
					createarray "syncactivate" "plugin" "sync" "activateplugin"; IN1=$(checkarray "$1")
					createarray "sync_activate" "plugin" "sync-activate" "plugin"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then 
						syncactivateplugin "$SLUGS"; DONE="true"; fi
						
					# - sync theme(s) -
					createarray "sync" "theme"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then synctheme "$SLUGS"; DONE="true"; fi
					# if [ "$INARRAY" == "1" ]; then synctheme "$SLUGS" "false"; DONE="true"; fi

					# - sync existing theme(s) -
					# if [ "syncexistingtheme" == "$1" ]; then synctheme "$SLUGS" "true"; DONE="true"; fi
					# if [ "syncexistingthemes" == "$1" ]; then synctheme "$SLUGS" "true"; DONE="true"; fi
						
					# - sync and activate theme (singular only) -
					createarray "syncactivate" "theme" "sync" "activatetheme"; IN1=$(checkarray "$1")
					createarray "sync_activate" "theme" "sync-activate" "theme"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						syncactivatetheme "$SLUGS"; DONE="true"; fi
						
					# - sync must-use plugin(s) -
					createarray "sync" "muplugin" "sync" "mu-plugins"; IN1=$(checkarray "$1")
					createarray "sync" "mu_plugins"; IN2=$(checkarray "$1")
					if [ "$IN1" == "1" ] || [ "$IN2" == "1" ]; then
						syncmuplugin "$SLUGS"; DONE="true"; fi

					# - delete must-use plugin(s) -
					createarray "delete" "muplugin" "remove" "muplugin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then deletemuplugin "$SLUGS"; DONE="true"; fi
						
					# - sync dropin file(s) -
					createarray "sync" "dropin" "sync" "files"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then syncdropin "$SLUGS"; DONE="true"; fi
					
					# - delete dropin file(s) -
					createarray "delete" "dropin" "remove" "dropin"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then deletedropin "$SLUGS"; DONE="true"; fi			

					# ----------------- #
					# LANGUAGE COMMANDS #
					# ----------------- #
					
					# - install language locale pack(s) -
					createarray "install" "language" "install" "locale"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then installlanguage "$LOCALE"; DONE="true"; fi
						
					# - uninstall language locale pack(s) -
					createarray "uninstall" "language" "uninstall" "locale"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then uninstalllanguage "$LOCALE"; DONE="true"; fi
						
					# - activate language locale pack (singular only) -
					createarray "activate" "language" "activate" "locale"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then activatelanguage "$LOCALE"; DONE="true"; fi
						
					# - update language locale pack(s) -
					createarray "update" "language" "update" "locale"; INARRAY=$(checkarray "$1")
					if [ "$INARRAY" == "1" ]; then updatelanguage; DONE="true"; fi

				fi
				
				# - maybe switch back to current working directory -
				# TODO: handle this for SSH ?
				if [ -z "$SSH" ] && [ -n "$SITEPATH" ] && [ -d "$SITEPATH" ]; then
					cd "$CWD"
				fi

			elif [ ! "$SKIP" == "true" ]; then
				
				# - output invalid site path message -
				red "Warning!"; printf " Invalid path for "; green "$SITENAME"; 
				if [ -n "$ALIAS" ]; then printf "@"; yellow "$ALIAS"; fi
				printf ": "; yellow "$SITEPATH"; printf ". Skipping"; echo "..."

			fi
		else
			# - for non-site config display -
			if [ "$SHOWCONFIG" == "true" ] || [ "$SHOWCONFIG" == "sources" ]; then
				
				# - increment source count -
				((++SOURCECOUNT))
				
				# - set type / slug / path columns -
				SOURCETABLE+=$(white "${DATA[0]}"); SOURCETABLE+="|"
				SOURCETABLE+=$(white "${DATA[1]}"); SOURCETABLE+="|"
				SOURCETABLE+=$(white "${DATA[2]}"); SOURCETABLE+=$'\r\n'
			fi
		fi
	fi
done < "$CONFIG"

# - maybe output show config tables -
if [ -n "$SHOWCONFIG" ]; then

	# - sites table -
	if [ "$SITECOUNT" -gt 0 ] && [ ! "$SHOWCONFIG" == "sources" ]; then
		cyan "SITES"; echo ""
		OUTPUT=$(column -t -s "|" <<< "$SITETABLE")
		echo "$OUTPUT"
	fi

	# - maybe line break between tables -
	if [ "$SHOWCONFIG" == "true" ] && [ "$SITECOUNT" -gt 0 ] && [ "$SOURCECOUNT" -gt 0 ]; then echo ""; fi
	
	# - sources table -
	if [ "$SOURCECOUNT" -gt 0 ] && [ ! "$SHOWCONFIG" == "sites" ]; then
		cyan "SOURCES"; echo ""
		OUTPUT=$(column -t -s "|" <<< "$SOURCETABLE")
		echo "$OUTPUT"
	fi
	exit 0
fi

# - output no site slug match message -
if [ -z "$FOUND" ]; then
	red "Error!"; printf " No site match found for "; yellow "$2"; red " in "; white "wpx.conf"; echo "!"
	# 1.0.7: just exit here as no site match found
	exit 1
fi

# - output invalid command message -
if [ -z "$DONE" ]; then	
	red "Error!"; printf " Command action "; yellow "$1"; printf " not found!"; echo ""
	validcommands; exit 1
fi

# - check for site(s) specified but not found -
for SITE in "${SITENAMES[@]}"; do
	FOUND=""
	for FOUNDSITE in "${FOUNDSITES[@]}"; do
		if [ "$SITE" == "$FOUNDSITE" ]; then FOUND="true"; fi
	done
	if [ ! "$FOUND" == "true" ]; then
		red "Warning!"; printf " No matching site config found for slug "; cyan "$SITE"; echo ""
	fi
done
