HEX
Server: nginx/1.29.3
System: Linux 11979.bigscoots-wpo.com 6.8.0-88-generic #89-Ubuntu SMP PREEMPT_DYNAMIC Sat Oct 11 01:02:46 UTC 2025 x86_64
User: nginx (1068)
PHP: 7.4.33
Disabled: exec,system,passthru,shell_exec,proc_open,proc_close,popen,show_source,cmd# Do not modify this line # 1684243876
Upload Files
File: //bigscoots/wpo/extras/bigscoots.menu
#!/bin/bash

source /bigscoots/includes/common.sh

display_scoots_commands() {
    # Define color variables
    bold=$(tput bold)
    green=$(tput setaf 2)
    cyan=$(tput setaf 6)
    reset=$(tput sgr0)

    echo "${bold}BigScoots Commands:${reset}"
    echo "  ${green}Backups:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots backups${reset}    - Manages backups"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots backups enter${reset}"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots backups list${reset}"

    echo "  ${green}WP Admin Access:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots wpadmin${reset}    - Provides WP admin access"

    echo "  ${green}Migrate Domains:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots migrate${reset}    - Migrates domains between servers"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots migrate ALL DESTINATIONIP${reset}"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots migrate domain.com DESTINATIONIP${reset}"

    echo "  ${green}Search/Replace Domain:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots domain${reset}     - Search and replace the domain of the current WP install with the domain you specify (no https://)(specify www or non-www)"
    echo "      - ${bold}Example:${reset} ${cyan}scoots domain newdomain.com${reset}"
    echo "      - ${bold}Note:${reset} ${cyan}Only specify the new domain, it takes the current domain from the database.${reset}"

    echo "  ${green}Setup SSH Access:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots ssh${reset}        - Sets up SSH access"

    echo "  ${green}Remove Buffer from Nginx Access Logs:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots nginx rbc${reset}  - Removes the buffer from nginx access logs so tailing shows in real-time"

    echo "  ${green}Change PHP Version:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php set${reset}    - Changes the PHP version"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php set domain.com phpversion${reset}"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php set domain.com 81${reset}"

    echo "  ${green}PHP OPcache management:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php opcache deploy${reset} - Deploys a temporary opcache GUI tool for 24 hours"

    echo "  ${green}See PHP Version Information:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php info${reset}   - Displays which domain is using which PHP version"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php info${reset} - Shows all domains"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php info domain.com${reset} - Shows specific domain"

    echo "  ${green}Restart PHP Service:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php restart${reset} - Restarts PHP services for specified or all versions"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php restart all${reset} - Restarts all PHP versions"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php restart 81${reset} - Restarts PHP 8.1"

    echo "  ${green}Reload PHP Service:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php reload${reset} - Reloads PHP services for specified or all versions"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php reload all${reset} - Reloads all PHP versions"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php reload 81${reset} - Reloads PHP 8.1"

    echo "  ${green}Convert PHP Configs:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php convert${reset} - Converts PHP configurations to match current settings"

    echo "  ${green}Update PHP Service:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php update${reset} - Updates PHP service"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php update${reset}"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php update --reboot${reset}"

    echo "  ${green}PHP-FPM Max Children:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots php child set${reset} - Sets pm.max_children for different plans"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots php child set [starter|professional|business|enterprise|man N]${reset}"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php child set starter${reset} - Sets max children to 6"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php child set pro${reset} - Sets max children to 12"
    echo "      - ${bold}Example:${reset} ${cyan}scoots php child set man 50${reset} - Sets max children to 50"

    echo "    - ${bold}Command:${reset} ${cyan}scoots php child get${reset} - Gets the current PHP-FPM configurations"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots php child get${reset} - Retrieves current pm, max children, and max requests for all PHP-FPM pools"

    echo "  ${green}Print rsync command for current folder:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots rsync cmd${reset}  - Prints an rsync command for the current folder"

    echo "  ${green}Issue or Reissue an SSL Certificate for a Domain:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots ssl${reset}        - Manages SSL for a domain"
    echo "      - ${bold}Example:${reset} ${cyan}scoots ssl issue domain.com${reset}          - Issues a new certificate"
    echo "      - ${bold}Example:${reset} ${cyan}scoots ssl reissue domain.com${reset}        - Reissues an existing certificate"
    echo "      - ${bold}Example:${reset} ${cyan}scoots ssl issue domain.com --nowww${reset} - Issue certificate without www"
    echo "      - ${bold}Example:${reset} ${cyan}scoots ssl reissue domain.com --nowww${reset} - Reissue certificate without www"
    echo "      - ${bold}Example:${reset} ${cyan}scoots ssl status domain.com${reset}         - Checks current certificate status"

    echo "  ${green}Database Operations:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots db convert${reset}          - Converts ALL databases from MyISAM to InnoDB."
    echo "    - ${bold}Command:${reset} ${cyan}scoots db check${reset}            - Checks if the InnoDB buffer is full and should be increased."
    echo "    - ${bold}Command:${reset} ${cyan}scoots db cleanup${reset}          - Identifies any unused databases. Do not blindly remove databases."
    echo "    - ${bold}Command:${reset} ${cyan}scoots db list${reset}             - Lists all WordPress databases on the server and their associated domains."
    echo "    - ${bold}Command:${reset} ${cyan}scoots db create${reset}           - Creates the database & grants the user based on wp-config.php"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots db create${reset}                   # uses wp-config.php in current directory"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots db create /path/to/wp-install${reset} # uses wp-config.php at specified path"
    echo "    - ${bold}Command:${reset} ${cyan}scoots db convert-charset${reset}  - Converts all utf8mb3 tables/columns to utf8mb4_unicode_ci"

    echo "  ${green}Manage Server Cronjobs per Domain for WP Cron:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots cron on domain.com${reset}   - Adds a server cronjob for the domain and disables WP cron"
    echo "    - ${bold}Command:${reset} ${cyan}scoots cron off domain.com${reset}  - Removes the server cronjob for the domain and enables WP cron"

    echo "  ${green}Object Cache (Redis) Management:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots oc default${reset}            - Set default Redis object cache settings"
    echo "    - ${bold}Command:${reset} ${cyan}scoots oc on domain.com${reset}      - Enable Redis object cache for the domain and installs the Redis cache plugin"
    echo "    - ${bold}Command:${reset} ${cyan}scoots oc mem MEMORY_IN_MB${reset}   - Allocate specific memory (in MB) for Redis object cache"
    echo "      - ${bold}Example:${reset} ${cyan}scoots oc mem 2048${reset} - Sets redis memory limit to 2GB"

    echo "  ${green}IP Blocking Management:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots ip block <IP>${reset}       - Blocks an IP address"
    echo "    - ${bold}Command:${reset} ${cyan}scoots ip unblock <IP>${reset}     - Unblocks an IP address"
    echo "    - ${bold}Command:${reset} ${cyan}scoots ip list${reset}             - Lists all blocked IPs"
    echo "      - ${bold}Example:${reset} ${cyan}scoots ip block 192.168.1.100${reset} - Blocks the specified IP."
    echo "      - ${bold}Example:${reset} ${cyan}scoots ip unblock 192.168.1.100${reset} - Unblocks the specified IP."
    echo "      - ${bold}Example:${reset} ${cyan}scoots ip list${reset} - Displays a list of currently blocked IPs."

    echo "  ${green}WordPress Management:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots plugin reinstall-all${reset} - Reinstalls all plugins in a WordPress install"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots plugin reinstall-all${reset}           - Reinstalls plugins in the current WP install"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots plugin reinstall-all --all-domains${reset} - Runs on all installs concurrently (10 at a time)"

    echo "  ${green}Clone WordPress Site:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots clone <source domain> <destination domain> [--uploads=skip|overwrite|sync] [--staging]${reset} - Clones one site to another."
    echo "      - ${bold}--uploads${reset} options:"
    echo "        - ${cyan}skip${reset}      → Do not copy /uploads/20* content"
    echo "        - ${cyan}overwrite${reset} → Clone everything including /uploads/20*, overwriting the destination"
    echo "        - ${cyan}sync${reset}      → Sync new /uploads/20* content without deleting destination files"
    echo "      - ${bold}--staging${reset} optional flag will run the clone using the staging logic"

    echo "  ${green}Performance Tools:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots perf generate${reset} - WORDPRESS PERFMATTERS CONFIG GENERATOR"
    echo "    - ${bold}Command:${reset} ${cyan}scoots perf setup${reset}    - Install/activate Perfmatters and activate license"

    echo "  ${green}Quick(Les) Server Status:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots qstat${reset}   - Shows quick server stats and resource usage"
    echo "      - ${bold}Example:${reset} ${cyan}scoots qstat${reset}"

    echo "  ${green}Ahmad's Stats:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots astat${reset}       - Ahmad's statistics for a domain"
    echo "      - ${bold}Example:${reset} ${cyan}scoots astat${reset} - Runs on current WP install"
    echo "      - ${bold}Example:${reset} ${cyan}scoots astat domain.com${reset}"

    echo "  ${green}Print Useful Stats for Each Domain:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots kstat${reset}       - Prints out some useful stats for each domain"
    echo "      - ${bold}Example:${reset} ${cyan}scoots kstat${reset}"
    echo "      - ${bold}Example:${reset} ${cyan}scoots kstat domain.com${reset}"

    echo "  ${green}WordPress Security (Wordfence):${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots wf${reset}          - Installs and launches the Wordfence security auditing tool"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots wf${reset}                   - Opens the Wordfence interactive scan menu"
    echo "      - ${bold}Example:${reset} After launching, choose options like full audit, vulnerability scan, or malware scan"

    echo "  ${green}BigScoots Cache (Cloudflare)${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots bs_cache encrypt${reset} - Encrypts and prints CLI flags"
    echo "    - ${bold}Command:${reset} ${cyan}scoots bs_cache audit${reset}  - Server-wide audit of Cache plugin status"
    echo "      - ${bold}Options:${reset} Cloudflare Email, Cloudflare API Key, Cloudflare Zone ID, Cloudflare Token, All (Email+API Key+Zone ID)"

    echo "  ${green}Fix Permissions & Ownership:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots fixperm${reset}         - Fixes permissions (644/755) and ownership (nginx) for a domain"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots fixperm all${reset}      - Fixes all domains on the server"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots fixperm domain.com${reset} - Fixes a specific domain"
    echo "      - ${bold}Usage:${reset} ${cyan}scoots fixperm${reset}            - Automatically detects the domain from your current directory"

    echo "  ${green}Server Cleanup:${reset}"
    echo "    - ${bold}Command:${reset} ${cyan}scoots cleanup${reset}         - Runs the BigScoots cleanup script for the current domain"
    echo "      - ${bold}Note:${reset} Automatically moves you to the domain's /public folder before running."
}

function list_databases() {
    echo -e "\n🔹 Listing WordPress Databases on This Server:\n"

    # Temporary file to store results
    tmpfile=$(mktemp)

    # Disable job control messages
    set +m

    # Run processes in parallel
    {
        for domain in $(ls -1 /home/nginx/domains/); do
            (
                db_name=$(wpcli config get DB_NAME --path=/home/nginx/domains/$domain/public 2>/dev/null)
                if [[ ! -z "$db_name" ]]; then
                    echo "$domain → $db_name"
                fi
            ) &
        done
        wait
    } > "$tmpfile" 2>/dev/null  # Redirect stdout and stderr to file

    # Re-enable job control messages
    set -m

    # Sort and display the results
    sort "$tmpfile"
    rm -f "$tmpfile"
    
}

# --- BigScoots Cache: encryption helpers ---

encrypt_it() {
  local salt="$1"
  echo -n "$salt" | openssl enc -aes-256-cbc -base64 -A -K "546573746b6579" -iv "c25e89f34f9878266bede60ed2feddde" 2>/dev/null
}

bs_cache_encrypt() {
    # Map of human labels -> CLI flag names
    declare -A MAP=(
        ["Cloudflare Email"]="cf-email-salt"
        ["Cloudflare API Key"]="cf-api-key-salt"
        ["Cloudflare Zone ID"]="cf-zone-id-salt"
        ["Cloudflare Token"]="cf-api-token-salt"
    )

    local choices=("Cloudflare Email" "Cloudflare API Key" "Cloudflare Zone ID" "Cloudflare Token" "All (Cloudflare Email, Cloudflare API Key, Cloudflare Zone ID)")
    echo
    echo "Which value would you like to encrypt?"
    PS3="Select an option [1-${#choices[@]}]: "

    select choice in "${choices[@]}"; do
        case "$REPLY" in
            1|2|3|4)
                # Single item flow
                local label="$choice"
                local flag="${MAP[$label]}"

                echo -n "Enter $label: "
                # Make API key / token silent input, others normal
                local value
                if [[ "$label" == "Cloudflare API Key" || "$label" == "Cloudflare Token" ]]; then
                    read -r -s value; echo
                else
                    read -r value
                fi

                local enc
                enc="$(encrypt_it "$value")"
                echo
                echo "$label is --$flag=\"$enc\""
                echo
                break
                ;;
            5)
                # All (Email, API Key, Zone ID) — per spec, exclude Token
                local labels=("Cloudflare Email" "Cloudflare API Key" "Cloudflare Zone ID")
                declare -A ENC

                for lbl in "${labels[@]}"; do
                    local prompt="Enter $lbl: "
                    local val
                    if [[ "$lbl" == "Cloudflare API Key" ]]; then
                        echo -n "$prompt"; read -r -s val; echo
                    else
                        echo -n "$prompt"; read -r val
                    fi
                    ENC["$lbl"]="$(encrypt_it "$val")"
                done

                local outstr="--${MAP["Cloudflare Email"]}=\"${ENC["Cloudflare Email"]}\" --${MAP["Cloudflare API Key"]}=\"${ENC["Cloudflare API Key"]}\" --${MAP["Cloudflare Zone ID"]}=\"${ENC["Cloudflare Zone ID"]}\""
                echo
                echo "CLI options:"
                echo "$outstr"
                echo
                ;;
            *)
                echo "Invalid selection."
                ;;
        esac
        break
    done
}

perf_setup() {
    # ensure we're in a valid WP install
    if ! wpcli core is-installed --quiet; then
        echo "This directory does not appear to be a WordPress install (wpcli core is-installed failed)."
        return 1
    fi

    # install / activate perfmatters
    if wpcli plugin is-installed perfmatters; then
        if wpcli plugin is-active perfmatters; then
            echo "Perfmatters plugin is already active."
        else
            echo "Perfmatters plugin is installed but not active. Activating now..."
            wpcli plugin activate perfmatters
        fi
    else
        echo "Perfmatters plugin is not installed. Installing and activating now..."
        # wpcli can install from a URL; --activate simplifies the flow
        if ! wpcli plugin install "$(curl -fsSL https://sharemy.zip/get/perfmatters)" --activate; then
            echo "Failed to install/activate Perfmatters."
            return 1
        fi
    fi

    # fetch license (kept out of the script body; pulled securely at runtime)
    LICENSE="$(curl -fsSL https://www.bigscoots.com/downloads/perfmatters | tr -d '\r\n')"
    if [ -z "$LICENSE" ]; then
        echo "Failed to retrieve Perfmatters license key."
        return 1
    fi

    echo "Activating Perfmatters license..."
    if ! wp perfmatters activate-license "$LICENSE" --skip-themes --skip-plugins=$(skip_all_plugins_except perfmatters); then
        echo "Perfmatters license activation failed."
        return 1
    fi

    echo "Perfmatters setup complete."
}

function scoots() {
    if [ "$1" == backups ]
    then
        if [ "$2" == enter ]
        then
            bash /bigscoots/wpo_backups_ovz_restore.sh enter
        elif [ "$2" == list ]
        then
            bash /bigscoots/wpo_backups_ovz_restore.sh hh
        else
            echo "BigScoots Backup Commands:
                  scoots backups enter
                  scoots backups list"
        fi
    elif [ "$1" == "bs_cache" ]; then
        if [ "$2" == "encrypt" ]; then
            bs_cache_encrypt
        elif [ "$2" == "audit" ]; then
            bash /bigscoots/wpo/cloudflare/bs-cache-audit.sh
        else
            echo "BigScoots Cache Commands:
                  scoots bs_cache encrypt   # Encrypt Cloudflare creds for bs_cache CLI
                  scoots bs_cache status    # Audit cache status across server"
        fi
    elif [ "$1" == wpadmin ]
    then
        bash /bigscoots/wpo/extras/wpadmin_user.sh
    elif [ "$1" == nginx ]
    then
        if [ "$2" == rbc ]
        then
            bash /bigscoots/wpo/manage/set.sh nginx rbc
        else
            display_scoots_commands
        fi
    elif [ "$1" == "cleanup" ]; then
        CURRENT_DIR=$(pwd)
        # Regex to capture the domain from the path
        if [[ "$CURRENT_DIR" =~ ^(/home/nginx/domains/[^/]+) ]]; then
            TARGET_PUBLIC="${BASH_REMATCH[1]}/public"
            
            if [ -d "$TARGET_PUBLIC" ]; then
                echo "Moving to $TARGET_PUBLIC and running cleanup..."
                cd "$TARGET_PUBLIC" || return
                bash /bigscoots/wp_cleanup.sh
            else
                echo "Error: Could not find public folder at $TARGET_PUBLIC"
            fi
        else
            echo "Error: You must be inside a domain directory (/home/nginx/domains/domain.com/) to run cleanup."
        fi
    elif [ "$1" == "fixperm" ]; then
        if [ "$2" == "all" ]; then
            # Runs for all domains via wildcard
            echo "Fixing permissions and ownership for ALL domains in the background..."
            correct_permissions_ownership
        elif [ -n "$2" ]; then
            # Runs for specific domain provided as argument
            echo "Fixing permissions and ownership for $2..."
            correct_permissions_ownership "$2"
        else
            # Detect domain from current path
            # If path is /home/nginx/domains/example.com/public/wp-content
            # It extracts 'example.com'
            CURRENT_DIR=$(pwd)
            if [[ "$CURRENT_DIR" =~ /home/nginx/domains/([^/]+) ]]; then
                DETECTED_DOMAIN="${BASH_REMATCH[1]}"
                echo "Detected domain: $DETECTED_DOMAIN. Fixing permissions..."
                correct_permissions_ownership "$DETECTED_DOMAIN"
            else
                echo "Error: You are not inside a domain directory (/home/nginx/domains/domain.com/)."
                echo "Please specify a domain: scoots fixperm domain.com"
            fi
        fi
    elif [ "$1" == php ]
    then
        if [ "$2" == opcache ] && [ "$3" == deploy ]
        then
            deploy_opcache_gui
        elif  [ "$2" == child ]
        then
            if [ "$3" == set ]
            then
                set_max_children "$4" "$5"
            elif [ "$3" == get ]
            then
                get_php_fpm_configs
            else
                echo "Invalid option. Use 'scoots php child set [starter|professional|business|enterprise|man N]' or 'scoots php child get'"
            fi
        elif [ "$2" == update ]
        then
            if [ "$3" == "--reboot" ]
            then
                bash /bigscoots/wpo/phpfpm/multiphp.sh update --reboot
            else
                bash /bigscoots/wpo/phpfpm/multiphp.sh update
            fi
        elif [ "$2" == set ] && [ -n "$3" ] && [ -n "$4" ]
        then
            bash /bigscoots/wpo/phpfpm/multiphp.sh set --domain "$3" --phpver "$4"
        elif [ "$2" == info ]
        then
            if [ -n "$3" ] && [ "$3" != all ]
            then
                bash /bigscoots/wpo/manage/info.sh --domain "$3" phpver | jq
            else
                bash /bigscoots/wpo/manage/info.sh --domain all phpver | jq
            fi
        elif [ "$2" == convert ]
        then
            bash /bigscoots/wpo/phpfpm/multiphp.sh update_configs >/dev/null 2>&1 
            domains=$(scoots php info | jq -r '.domains | to_entries[] | [.key, .value.php.version] | @tsv')
            if [[ -n $domains ]]
            then
                while IFS=$'\t' read -r domain phpver
                do
                    phpver="${phpver//./}"
                    bash /bigscoots/wpo/phpfpm/multiphp.sh set --domain "$domain" --phpver "$phpver" --bulk
                done <<< "$domains"
            fi
            ngxreload_t "command ran: scoots php convert" || /usr/local/sbin/nginx -t
        elif [ "$2" == restart ]
        then
            # Define an array of PHP versions to support
            php_versions=("56" "70" "74" "80" "81" "82" "83" "84" "85")
            if [ "$3" == all ]
            then
                /bin/fpmrestart >/dev/null 2>&1 && echo "Native PHP has been restarted."
                # Loop through the PHP versions and only attempt to restart if the PHP binary exists
                for ver in "${php_versions[@]}"
                do
                    if [ -f "/opt/remi/php${ver}/root/usr/bin/php" ]
                    then
                        systemctl restart php"${ver}"-php-fpm.service >/dev/null 2>&1 && echo "PHP ${ver} restarted."
                    fi
                done
            elif [[ " ${php_versions[@]} " =~ " $3 " ]]
            then
                [ -f "/opt/remi/php${3}/root/usr/bin/php" ] && systemctl restart php"${3}"-php-fpm.service >/dev/null 2>&1 && echo "PHP $3 restarted."
            else
                echo "Invalid option. Use 'all' or specify a valid PHP version (${php_versions[*]})."
                echo "If you are unsure what version a domain is using run: scoots php info \$domain"
            fi
        elif [ "$2" == reload ]
        then
            # Define an array of PHP versions to support
            php_versions=("56" "70" "74" "80" "81" "82" "83" "84" "85")
            if [ "$3" == all ]
            then
                /bin/fpmreload >/dev/null 2>&1 && echo "Native PHP has been reloaded."
                # Loop through the PHP versions and only attempt to restart if the PHP binary exists
                for ver in "${php_versions[@]}"
                do
                    if [ -f "/opt/remi/php${ver}/root/usr/bin/php" ]
                    then
                        systemctl reload php"${ver}"-php-fpm.service >/dev/null 2>&1 && echo "PHP ${ver} reloaded."
                    fi
                done
            elif [[ " ${php_versions[@]} " =~ " $3 " ]]
            then
                [ -f "/opt/remi/php${3}/root/usr/bin/php" ] && systemctl reload php"${3}"-php-fpm.service >/dev/null 2>&1 && echo "PHP $3 reloaded."
            else
                echo "Invalid option. Use 'all' or specify a valid PHP version (${php_versions[*]})."
                echo "If you are unsure what version a domain is using run: scoots php info \$domain"
            fi
        else
            display_scoots_commands
        fi
    elif [ "$1" == qstat ]
    then
        bash /bigscoots/wpo/extras/les_audit.sh
    elif [ "$1" == "perf" ]
    then
        case "$2" in
            generate)
                curl -fsSL "https://raw.githubusercontent.com/ahmad-den/useful_scripts/refs/heads/main/wp-perfmatters-config-generator.sh" | bash
                ;;
            setup)
                perf_setup
                ;;
            *)
                echo "BigScoots Performance Commands:
                      scoots perf generate   # WORDPRESS PERFMATTERS CONFIG GENERATOR
                      scoots perf setup      # Install+activate Perfmatters & license"
                ;;
        esac
    elif [ "$1" == db ]; then
      if [ "$2" == convert ]; then
        bash /bigscoots/wpo/manage/dbopt.sh convert

      elif [ "$2" == check ]; then
        bash /bigscoots/wpo/manage/dbopt.sh check

      elif [ "$2" == cleanup ]; then
        # 1) detect --apply / -y
        apply=false
        for arg in "${@:3}"; do
          case "$arg" in
            --apply|-y) apply=true ;;
          esac
        done

        # 2) always run the check and capture unused DB names
        mapfile -t unused_dbs < <(
          bash /bigscoots/wpo/manage/disk_chk.sh check \
            | awk '/To Remove/ {
                for(i=1;i<=NF;i++) if($i=="drop") print $(i+1)
              }'
        )

        # 3) if none found, bail out
        if [ ${#unused_dbs[@]} -eq 0 ]; then
          echo "No unused databases found."
          return 0
        fi

        # 4) dry-run vs. apply
        if ! $apply; then
          echo
          echo "Found ${#unused_dbs[@]} unused databases:"
          printf '  - %s\n' "${unused_dbs[@]}"
          echo
          echo "Run 'scoots db cleanup --apply' (or -y) to actually drop these."
          return 0
        fi

        # 5) actually drop
        echo "Dropping ${#unused_dbs[@]} databases…"
        for db in "${unused_dbs[@]}"; do
          echo "  • mysqladmin drop \"$db\" --force"
          mysqladmin drop "$db" --force
        done
        echo "Done."
      elif [ "$2" == list ]; then
        list_databases
      elif [ "$2" == create ]; then
        # allow optional path argument, default to CWD
        if [ -n "$3" ]; then
          bash /bigscoots/wpo/manage/dbopt.sh create "$3"
        else
          bash /bigscoots/wpo/manage/dbopt.sh create
        fi
      elif [ "$2" == convert-charset ]; then
        bash /bigscoots/wpo/manage/dbopt.sh convert-charset
      else
        echo "BigScoots Database Commands:
          scoots db create [path]         # Create DB & grant user from wp-config.php (default CWD)
          scoots db convert               # Converts all databases to InnoDB
          scoots db check                 # Checks if the InnoDB buffer is full
          scoots db cleanup               # Finds unused databases
          scoots db cleanup [--apply]     # Finds unused databases (use --apply to drop)
          scoots db list                  # Lists all domains & their database names
          scoots db convert-charset       # Converts utf8mb3 tables to utf8mb4_unicode_ci safely"
      fi
    elif [ "$1" == domain ]
    then
        if [ -n "$2" ]
        then
            DOMAIN="$2"
            bash /bigscoots/wpo/manage/set.sh domain "${DOMAIN}"
        else
            echo "BigScoots Domain Commands:
                  scoots domain domain.com"
        fi
    elif [ "$1" == wf ]
    then
        URL=$(curl -s https://sharemy.zip/get/wordfence) && curl -s "$URL" > /var/tmp/wordfence.sh && chmod +x /var/tmp/wordfence.sh && /var/tmp/wordfence.sh "${@:2}" && rm -i -rf /var/tmp/wordfence.sh && cd /home/nginx/domains
    elif [ "$1" == migrate ]
    then
        if [ -n "$2" ] && [ -n "$3" ]
        then
            # scoots migrate ALL destIP [extra flags...]
            DOMAIN="$2"
            DSTIP="$3"
            EXTRA_ARGS=("${@:4}")   # forward anything after the dest IP

            if [ "$2" == "ALL" ]; then
                # robust listing (one per line; avoid weird names)
                mapfile -t DOMAINS < <(ls -1 /home/nginx/domains/ | sed '/^\s*$/d' | sort)

                echo "Starting migration on the following domains:"
                printf -- '  - %s\n' "${DOMAINS[@]}"
                echo
                echo 'If you see any issues, Ctrl+C now. Otherwise migration will start in 10 seconds...'
                sleep 10

                for D in "${DOMAINS[@]}"; do
                    bash /bigscoots/wpo/manage/migrate.sh "$D" "$DSTIP" "${EXTRA_ARGS[@]}"
                done
            else
                bash /bigscoots/wpo/manage/migrate.sh "$DOMAIN" "$DSTIP" "${EXTRA_ARGS[@]}"
            fi
        else
            echo "BigScoots Migrate Commands:
                  scoots migrate ALL DESTINATIONIP
                  scoots migrate domain.com DESTINATIONIP"
        fi                
    elif [ "$1" == ssh ]
    then
        bash /bigscoots/wpo/extras/sshuser.sh manual
    elif [ "$1" == rsync ]
    then
        if [ "$2" == cmd ]
        then
            ssh_port=$(grep -e "^\s*Port.*" /etc/ssh/sshd_config | grep -o "[0-9].*")
            ssh_conn=$(whoami)@$serverip
            domain=$(pwd | awk -F'/' '{print $(NF-1)}')
            wpcli db export wpo_to_shared.sql
            echo;echo "Run all of the following commands on the shared server, as the cPanel user, in the home directory, ex. /home/cpuser/";echo
            echo "If this is the primary domain on the cPanel account, then symlink it to home directory like: ln -s public_html $domain";echo
            echo "rsync -ahv --exclude wp-config.php --delete -e \"ssh -p $ssh_port\" $ssh_conn:$(pwd)/ $domain/"
            echo;echo wp config set table_prefix  \$\(wp config get table_prefix --path=$(pwd) --ssh=$ssh_conn:$ssh_port --allow-root --skip-plugins --skip-themes 2\>/dev/null\) --path=$domain 2\>/dev/null
            echo;echo "wp db reset --yes --path=$domain"
            echo;echo "wp db import $domain/wpo_to_shared.sql --path=$domain"
        else
            echo "BigScoots rsync Commands:
                  scoots rsync cmd # Prints an rsync command for the current folder."
        fi
    elif [ "$1" == ssl ]; then
        DOMAIN="$3"
        NOWWW=false
        for arg in "$@"; do
            if [ "$arg" == "--nowww" ]; then
                NOWWW=true
            fi
        done

        if [ "$2" == issue ] && [ -n "$DOMAIN" ]; then
            if $NOWWW; then
                bash /bigscoots/wpo/manage/ssl.sh issue "${DOMAIN}" --nowww
            else
                bash /bigscoots/wpo/manage/ssl.sh issue "${DOMAIN}"
            fi
        elif [ "$2" == reissue ] && [ -n "$DOMAIN" ]; then
            if $NOWWW; then
                bash /bigscoots/wpo/manage/ssl.sh reissue "${DOMAIN}" --nowww
            else
                bash /bigscoots/wpo/manage/ssl.sh reissue "${DOMAIN}"
            fi
        elif [ "$2" == status ] && [ -n "$DOMAIN" ]; then
            bash /bigscoots/wpo/manage/ssl.sh status "${DOMAIN}"
        else
            echo "BigScoots SSL Commands:"
            echo "  scoots ssl issue domain.com           # Issue a new SSL certificate"
            echo "  scoots ssl reissue domain.com         # Reissue an existing SSL certificate"
            echo "  scoots ssl issue domain.com --nowww   # Skip www during issue"
            echo "  scoots ssl reissue domain.com --nowww # Skip www during reissue"
            echo "  scoots ssl status domain.com          # Check certificate status"
        fi
    elif [ "$1" == kstat ]
    then
        if [ -n "$2" ]
        then
            DOMAIN="$2"
            bash /bigscoots/wpo/extras/khan_stats.sh "${DOMAIN}"
        else
            bash /bigscoots/wpo/extras/khan_stats.sh
        fi
    elif [ "$1" == plugin ] && [ "$2" == reinstall-all ]
    then
        reinstall_all_plugins "$3"
    elif [ "$1" == astat ]
    then
        if [ -n "$2" ]
        then
            DOMAIN="$2"
            bash /bigscoots/wpo/extras/ahmad_stats.sh "${DOMAIN}"
        else
            bash /bigscoots/wpo/extras/ahmad_stats.sh
        fi
    elif [ "$1" == "cron" ]
    then
        if [ "$2" == "on" ] && [ -n "$3" ]
        then
            bash /bigscoots/wpo/manage/wpcron.sh on "$3"
        elif [ "$2" == "off" ] && [ -n "$3" ]
        then
            bash /bigscoots/wpo/manage/wpcron.sh off "$3"
        else                                                
            display_scoots_commands
        fi
    elif [ "$1" == "oc" ]
    then
        if [ "$2" == "default" ]
        then
            bash /bigscoots/wpo/manage/set.sh redis default
        elif [ "$2" == "on" ] && [ -n "$3" ]
        then
            bash /bigscoots/wpo/manage/set.sh redis on "$3"
        elif [ "$2" == "mem" ] && [ -n "$3" ]
        then
            bash /bigscoots/wpo/manage/set.sh redis mem "$3"
        else
            display_scoots_commands
        fi
    elif [ "$1" == "ip" ]; then
        if [ "$2" == "block" ] && [ -n "$3" ]; then
            bash /bigscoots/wpo/nginx/blockip.sh block "$3"
        elif [ "$2" == "unblock" ] && [ -n "$3" ]; then
            bash /bigscoots/wpo/nginx/blockip.sh unblock "$3"
        elif [ "$2" == "list" ]; then
            bash /bigscoots/wpo/nginx/blockip.sh list | jq
        else
            echo "BigScoots IP Blocking Commands:"
            echo "  scoots ip block <IP>      - Blocks an IP address"
            echo "  scoots ip unblock <IP>    - Unblocks an IP address"
            echo "  scoots ip list            - Lists all blocked IPs"
            echo "    - Example: scoots ip block 192.168.1.100 - Blocks the specified IP."
            echo "    - Example: scoots ip unblock 192.168.1.100 - Unblocks the specified IP."
            echo "    - Example: scoots ip list - Displays a list of currently blocked IPs."
        fi
    elif [ "$1" == "clone" ]; then
        SOURCE="$2"
        DEST="$3"
        UPLOAD_OPTION=""
        STAGING=false

        # Validate source and dest
        if [ -z "$SOURCE" ] || [ -z "$DEST" ]; then
            echo "Usage: scoots clone <source domain> <destination domain> --uploads=skip|overwrite|sync [--staging]"
            return 1
        fi

        # Parse remaining args
        shift 3
        for arg in "$@"; do
            if [[ "$arg" == --uploads=* ]]; then
                val="${arg#*=}"
                case "$val" in
                    skip)
                        UPLOAD_OPTION="SKIPUPLOADS"
                        ;;
                    overwrite)
                        UPLOAD_OPTION="OVERWRITEALL"
                        ;;
                    sync)
                        UPLOAD_OPTION="SYNCUPLOADS"
                        ;;
                    *)
                        echo "Invalid --uploads option: $val"
                        echo "Valid options: skip, overwrite, sync"
                        return 1
                        ;;
                esac
            elif [ "$arg" == "--staging" ]; then
                STAGING=true
            fi
        done

        if [ -z "$UPLOAD_OPTION" ]; then
            echo "Missing required --uploads option. Use --uploads=skip|overwrite|sync"
            return 1
        fi

        if $STAGING; then
            bash /bigscoots/wpo/manage/staging.sh "$SOURCE" "$DEST" skip "$UPLOAD_OPTION" && echo "Staging completed: https://$DEST"
        else
            bash /bigscoots/wpo/manage/clone.sh "$SOURCE" "$DEST" "$UPLOAD_OPTION" && echo "Clone completed: https://$DEST"
        fi
    else
        display_scoots_commands
    fi
}

# Helper function to set pm.max_children and pm.max_requests
function set_max_children() {
    config_files=($(find /etc/opt/remi/ -type f -name "www.conf" 2>/dev/null))
    local max_req=500
    local reloaded_versions=""

    case $1 in
        starter)      max_children=8 ;;
        professional) max_children=16 ;;
        business)     max_children=32 ;;
        enterprise)   max_children=48 ;;
        man)          max_children="$2" ;;
        *)
            echo "Invalid option. Use 'starter', 'professional', 'business', 'enterprise', or 'man N'"
            exit 1
            ;;
    esac

    for config_file in "${config_files[@]}"; do
        if [ -f "$config_file" ]; then
            # 1. Extract current values
            current_max=$(grep -E "^pm.max_children" "$config_file" | awk -F'=' '{print $2}' | tr -d '[:space:]')
            current_req=$(grep -E "^pm.max_requests" "$config_file" | awk -F'=' '{print $2}' | tr -d '[:space:]')

            # 2. Update if values differ
            if [[ "$current_max" != "$max_children" ]] || [[ "$current_req" != "$max_req" ]]; then
                sed -i "s/^pm.max_children[[:space:]]*=[[:space:]]*[0-9]*/pm.max_children = $max_children/" "$config_file"
                sed -i "s/^pm.max_requests[[:space:]]*=[[:space:]]*[0-9]*/pm.max_requests = $max_req/" "$config_file"
                
                # 3. Identify PHP version from path (e.g., /etc/opt/remi/php83/... -> 83)
                # This assumes the path structure follows the Remi standard
                php_ver=$(echo "$config_file" | grep -oP 'php\K[0-9]+')
                
                if [[ -n "$php_ver" ]]; then
                    # 4. Reload only this version and track it so we don't reload same version twice
                    if [[ ! "$reloaded_versions" =~ "$php_ver" ]]; then
                        scoots php reload "$php_ver" >/dev/null 2>&1
                        reloaded_versions+="$php_ver "
                    fi
                fi
            fi
        fi
    done

    # Final response logic
    if [ -n "$reloaded_versions" ]; then
        msg="pm.max_children updated and reloaded PHP: $reloaded_versions"
    else
        msg="No changes required for any PHP versions"
    fi

    echo '{"errors": [], "messages": ["'"$msg"'"], "success": true, "result": {"updated_versions": "'"${reloaded_versions% }"'"}}' | jq
}

# Helper function to get current PHP-FPM configurations
function get_php_fpm_configs() {
    config_files=($(find /etc/opt/remi/ -type f -name "www.conf" 2>/dev/null))

    result="{"
    for config_file in "${config_files[@]}"; do
        if [ -f "$config_file" ]; then
            php_version=$(echo "$config_file" | grep -oP 'php\d{2}')
            pm=$(grep "^pm = " "$config_file" | cut -d ' ' -f 3)
            max_children=$(grep "^pm.max_children = " "$config_file" | cut -d ' ' -f 3)
            max_requests=$(grep "^pm.max_requests = " "$config_file" | cut -d ' ' -f 3)
            result="$result\"$php_version\": {\"pm\": \"$pm\", \"pm.max_children\": \"$max_children\", \"pm.max_requests\": \"$max_requests\"},"
        fi
    done
    result="${result%,}}"
    echo "$result" | jq
}