Initial commit: Weedops dev tooling
Linting configs (PHPCS, ESLint, Stylelint), Forgejo CI pipeline, WordPress health check, PHP linter, strain migration tool, and Docker local dev environment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
010984d461
12 changed files with 725 additions and 0 deletions
17
.gitignore
vendored
Normal file
17
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Environment
|
||||||
|
.env
|
||||||
|
docker/.env
|
||||||
|
|
||||||
|
# Dependencies
|
||||||
|
node_modules/
|
||||||
|
vendor/
|
||||||
|
|
||||||
|
# IDE
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
31
README.md
Normal file
31
README.md
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Weedops Dev Tooling
|
||||||
|
|
||||||
|
Shared development tools, CI configurations, and scripts for the Weedops WordPress platform.
|
||||||
|
|
||||||
|
## Contents
|
||||||
|
|
||||||
|
- `linting/` — PHP_CodeSniffer and ESLint configs for WordPress theme development
|
||||||
|
- `ci/` — Forgejo Actions CI pipeline templates
|
||||||
|
- `scripts/` — Health checks, migration tools, and deployment helpers
|
||||||
|
- `docker/` — Local development environment configs
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Copy configs into your project or reference them from your CI pipeline:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run PHP linting
|
||||||
|
./scripts/lint-php.sh /path/to/theme
|
||||||
|
|
||||||
|
# Run WordPress health check
|
||||||
|
./scripts/wp-health-check.sh
|
||||||
|
|
||||||
|
# Run full CI locally
|
||||||
|
./scripts/run-ci-local.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Standards
|
||||||
|
|
||||||
|
- WordPress Coding Standards for PHP
|
||||||
|
- ESLint with WordPress preset for JS
|
||||||
|
- All themes must pass linting before merge
|
||||||
88
ci/forgejo-ci.yml
Normal file
88
ci/forgejo-ci.yml
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
# Forgejo Actions CI Pipeline for Weedops WordPress Themes/Plugins
|
||||||
|
# Place in .forgejo/workflows/ of your repo
|
||||||
|
|
||||||
|
name: Weedops CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, develop]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint-php:
|
||||||
|
name: PHP Linting
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.2'
|
||||||
|
tools: composer, cs2pr
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
composer global require wp-coding-standards/wpcs
|
||||||
|
composer global require phpcompatibility/phpcompatibility-wp
|
||||||
|
phpcs --config-set installed_paths $(composer global config home)/vendor/wp-coding-standards/wpcs
|
||||||
|
|
||||||
|
- name: Run PHPCS
|
||||||
|
run: phpcs --standard=WordPress --extensions=php --ignore=vendor,node_modules .
|
||||||
|
|
||||||
|
lint-js:
|
||||||
|
name: JavaScript Linting
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install ESLint
|
||||||
|
run: npm install -g eslint
|
||||||
|
|
||||||
|
- name: Run ESLint
|
||||||
|
run: eslint --ext .js assets/ js/ 2>/dev/null || true
|
||||||
|
|
||||||
|
theme-check:
|
||||||
|
name: WordPress Theme Check
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [lint-php]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Validate style.css header
|
||||||
|
run: |
|
||||||
|
if [ -f style.css ]; then
|
||||||
|
echo "Checking style.css theme header..."
|
||||||
|
grep -q "Theme Name:" style.css || (echo "ERROR: Missing Theme Name" && exit 1)
|
||||||
|
grep -q "Text Domain:" style.css || (echo "ERROR: Missing Text Domain" && exit 1)
|
||||||
|
echo "Theme header OK"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Check required template files
|
||||||
|
run: |
|
||||||
|
for file in index.php style.css; do
|
||||||
|
if [ ! -f "$file" ]; then
|
||||||
|
echo "ERROR: Missing required file: $file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "Required files present"
|
||||||
|
|
||||||
|
deploy-staging:
|
||||||
|
name: Deploy to Staging
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [lint-php, lint-js, theme-check]
|
||||||
|
if: github.ref == 'refs/heads/develop'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Deploy via rsync
|
||||||
|
run: |
|
||||||
|
echo "Deploy to staging would run here"
|
||||||
|
echo "Target: weedops.site staging environment"
|
||||||
5
docker/.env.example
Normal file
5
docker/.env.example
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
# Weedops Local Dev Environment Variables
|
||||||
|
# Copy this to .env and customize
|
||||||
|
|
||||||
|
DB_PASSWORD=weedops_dev
|
||||||
|
DB_ROOT_PASSWORD=root_dev
|
||||||
70
docker/docker-compose.yml
Normal file
70
docker/docker-compose.yml
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
# Weedops Local Development Environment
|
||||||
|
# Usage: docker-compose up -d
|
||||||
|
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
wordpress:
|
||||||
|
image: wordpress:6.4-php8.2-apache
|
||||||
|
container_name: weedops-wp
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
environment:
|
||||||
|
WORDPRESS_DB_HOST: db
|
||||||
|
WORDPRESS_DB_USER: weedops
|
||||||
|
WORDPRESS_DB_PASSWORD: ${DB_PASSWORD:-weedops_dev}
|
||||||
|
WORDPRESS_DB_NAME: weedops
|
||||||
|
WORDPRESS_DEBUG: 1
|
||||||
|
WORDPRESS_CONFIG_EXTRA: |
|
||||||
|
define('WP_DEBUG_LOG', true);
|
||||||
|
define('WP_DEBUG_DISPLAY', true);
|
||||||
|
define('SCRIPT_DEBUG', true);
|
||||||
|
volumes:
|
||||||
|
- wordpress_data:/var/www/html
|
||||||
|
- ../../../weedops-theme:/var/www/html/wp-content/themes/weedops
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mariadb:10.11
|
||||||
|
container_name: weedops-db
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD:-root_dev}
|
||||||
|
MYSQL_DATABASE: weedops
|
||||||
|
MYSQL_USER: weedops
|
||||||
|
MYSQL_PASSWORD: ${DB_PASSWORD:-weedops_dev}
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
ports:
|
||||||
|
- "3307:3306"
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin:latest
|
||||||
|
container_name: weedops-pma
|
||||||
|
ports:
|
||||||
|
- "8081:80"
|
||||||
|
environment:
|
||||||
|
PMA_HOST: db
|
||||||
|
PMA_USER: weedops
|
||||||
|
PMA_PASSWORD: ${DB_PASSWORD:-weedops_dev}
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
wpcli:
|
||||||
|
image: wordpress:cli-php8.2
|
||||||
|
container_name: weedops-cli
|
||||||
|
volumes:
|
||||||
|
- wordpress_data:/var/www/html
|
||||||
|
- ../../../weedops-theme:/var/www/html/wp-content/themes/weedops
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
- wordpress
|
||||||
|
entrypoint: wp
|
||||||
|
command: "--info"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
wordpress_data:
|
||||||
|
db_data:
|
||||||
30
linting/.eslintrc.json
Normal file
30
linting/.eslintrc.json
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true,
|
||||||
|
"jquery": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended"
|
||||||
|
],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": "latest",
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"globals": {
|
||||||
|
"wp": "readonly",
|
||||||
|
"ajaxurl": "readonly",
|
||||||
|
"weedopsData": "readonly"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"no-console": "warn",
|
||||||
|
"no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
|
||||||
|
"prefer-const": "error",
|
||||||
|
"no-var": "error",
|
||||||
|
"eqeqeq": ["error", "always"],
|
||||||
|
"curly": ["error", "all"],
|
||||||
|
"indent": ["error", "tab"],
|
||||||
|
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
|
||||||
|
"semi": ["error", "always"]
|
||||||
|
}
|
||||||
|
}
|
||||||
45
linting/.phpcs.xml
Normal file
45
linting/.phpcs.xml
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<ruleset name="Weedops WordPress Standards">
|
||||||
|
<description>PHP_CodeSniffer ruleset for Weedops WordPress themes and plugins.</description>
|
||||||
|
|
||||||
|
<!-- Scan these file types -->
|
||||||
|
<arg name="extensions" value="php"/>
|
||||||
|
|
||||||
|
<!-- Show progress and sniff codes -->
|
||||||
|
<arg value="ps"/>
|
||||||
|
|
||||||
|
<!-- Paths to check -->
|
||||||
|
<file>.</file>
|
||||||
|
|
||||||
|
<!-- Exclude vendor and node_modules -->
|
||||||
|
<exclude-pattern>*/vendor/*</exclude-pattern>
|
||||||
|
<exclude-pattern>*/node_modules/*</exclude-pattern>
|
||||||
|
<exclude-pattern>*/.git/*</exclude-pattern>
|
||||||
|
|
||||||
|
<!-- WordPress Coding Standards -->
|
||||||
|
<rule ref="WordPress">
|
||||||
|
<!-- Allow short array syntax -->
|
||||||
|
<exclude name="Generic.Arrays.DisallowShortArraySyntax"/>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- WordPress Theme-specific -->
|
||||||
|
<rule ref="WordPress-Extra"/>
|
||||||
|
|
||||||
|
<!-- Enforce text domain for i18n -->
|
||||||
|
<rule ref="WordPress.WP.I18n">
|
||||||
|
<properties>
|
||||||
|
<property name="text_domain" type="array">
|
||||||
|
<element value="weedops"/>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
|
||||||
|
<!-- Prefix everything with weedops_ -->
|
||||||
|
<rule ref="WordPress.NamingConventions.PrefixAllGlobals">
|
||||||
|
<properties>
|
||||||
|
<property name="prefixes" type="array">
|
||||||
|
<element value="weedops"/>
|
||||||
|
</property>
|
||||||
|
</properties>
|
||||||
|
</rule>
|
||||||
|
</ruleset>
|
||||||
16
linting/.stylelintrc.json
Normal file
16
linting/.stylelintrc.json
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"extends": "stylelint-config-wordpress",
|
||||||
|
"rules": {
|
||||||
|
"indentation": "tab",
|
||||||
|
"string-quotes": "double",
|
||||||
|
"selector-class-pattern": null,
|
||||||
|
"no-descending-specificity": null,
|
||||||
|
"font-family-no-missing-generic-family-keyword": true,
|
||||||
|
"declaration-no-important": true,
|
||||||
|
"max-nesting-depth": 3
|
||||||
|
},
|
||||||
|
"ignoreFiles": [
|
||||||
|
"vendor/**",
|
||||||
|
"node_modules/**"
|
||||||
|
]
|
||||||
|
}
|
||||||
84
scripts/lint-php.sh
Executable file
84
scripts/lint-php.sh
Executable file
|
|
@ -0,0 +1,84 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# PHP Linting Script for Weedops Projects
|
||||||
|
# Usage: ./lint-php.sh [path-to-check]
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
TARGET="${1:-.}"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PHPCS_CONFIG="$SCRIPT_DIR/../linting/.phpcs.xml"
|
||||||
|
|
||||||
|
echo "Weedops PHP Linter"
|
||||||
|
echo "==================="
|
||||||
|
echo "Target: $TARGET"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check for PHP syntax errors first
|
||||||
|
echo "--- PHP Syntax Check ---"
|
||||||
|
SYNTAX_ERRORS=0
|
||||||
|
while IFS= read -r -d '' file; do
|
||||||
|
if ! php -l "$file" &>/dev/null; then
|
||||||
|
echo "SYNTAX ERROR: $file"
|
||||||
|
php -l "$file" 2>&1 | tail -1
|
||||||
|
((SYNTAX_ERRORS++))
|
||||||
|
fi
|
||||||
|
done < <(find "$TARGET" -name "*.php" -not -path "*/vendor/*" -not -path "*/node_modules/*" -print0)
|
||||||
|
|
||||||
|
if [ "$SYNTAX_ERRORS" -eq 0 ]; then
|
||||||
|
echo "All PHP files pass syntax check."
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
echo "Found $SYNTAX_ERRORS file(s) with syntax errors!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Run PHPCS if available
|
||||||
|
echo "--- WordPress Coding Standards ---"
|
||||||
|
if command -v phpcs &> /dev/null; then
|
||||||
|
if [ -f "$PHPCS_CONFIG" ]; then
|
||||||
|
phpcs --standard="$PHPCS_CONFIG" "$TARGET" || true
|
||||||
|
else
|
||||||
|
phpcs --standard=WordPress --extensions=php --ignore=vendor,node_modules "$TARGET" || true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "phpcs not found. Install with: composer global require squizlabs/php_codesniffer"
|
||||||
|
echo "Running basic checks instead..."
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Basic checks without PHPCS
|
||||||
|
echo "Checking for common issues..."
|
||||||
|
ISSUES=0
|
||||||
|
|
||||||
|
# Check for short PHP tags
|
||||||
|
SHORT_TAGS=$(grep -rn '<?[^p=]' "$TARGET" --include="*.php" 2>/dev/null | grep -v "<?php" | grep -v "<?=" || true)
|
||||||
|
if [ -n "$SHORT_TAGS" ]; then
|
||||||
|
echo "WARNING: Short PHP tags found:"
|
||||||
|
echo "$SHORT_TAGS"
|
||||||
|
((ISSUES++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for direct database queries
|
||||||
|
DIRECT_DB=$(grep -rn '\$wpdb->query\|mysql_query\|mysqli_query' "$TARGET" --include="*.php" 2>/dev/null || true)
|
||||||
|
if [ -n "$DIRECT_DB" ]; then
|
||||||
|
echo "WARNING: Direct database queries found (use prepared statements):"
|
||||||
|
echo "$DIRECT_DB"
|
||||||
|
((ISSUES++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for eval usage
|
||||||
|
EVAL_USAGE=$(grep -rn '\beval\s*(' "$TARGET" --include="*.php" 2>/dev/null || true)
|
||||||
|
if [ -n "$EVAL_USAGE" ]; then
|
||||||
|
echo "WARNING: eval() usage found:"
|
||||||
|
echo "$EVAL_USAGE"
|
||||||
|
((ISSUES++))
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$ISSUES" -eq 0 ]; then
|
||||||
|
echo "No common issues found."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Done."
|
||||||
101
scripts/run-ci-local.sh
Executable file
101
scripts/run-ci-local.sh
Executable file
|
|
@ -0,0 +1,101 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Run CI checks locally before pushing
|
||||||
|
# Usage: ./run-ci-local.sh [path-to-theme]
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
TARGET="${1:-.}"
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo " Weedops Local CI Runner"
|
||||||
|
echo " $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
echo "========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
TOTAL_PASS=0
|
||||||
|
TOTAL_FAIL=0
|
||||||
|
|
||||||
|
run_check() {
|
||||||
|
local name="$1"
|
||||||
|
local cmd="$2"
|
||||||
|
echo "--- $name ---"
|
||||||
|
if eval "$cmd"; then
|
||||||
|
echo "✓ $name passed"
|
||||||
|
((TOTAL_PASS++))
|
||||||
|
else
|
||||||
|
echo "✗ $name failed"
|
||||||
|
((TOTAL_FAIL++))
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
}
|
||||||
|
|
||||||
|
# 1. PHP Syntax
|
||||||
|
run_check "PHP Syntax" "$SCRIPT_DIR/lint-php.sh $TARGET"
|
||||||
|
|
||||||
|
# 2. Theme structure validation
|
||||||
|
echo "--- Theme Structure ---"
|
||||||
|
REQUIRED_FILES=("style.css" "index.php")
|
||||||
|
RECOMMENDED_FILES=("functions.php" "header.php" "footer.php" "screenshot.png")
|
||||||
|
|
||||||
|
ALL_PRESENT=true
|
||||||
|
for f in "${REQUIRED_FILES[@]}"; do
|
||||||
|
if [ ! -f "$TARGET/$f" ]; then
|
||||||
|
echo "MISSING (required): $f"
|
||||||
|
ALL_PRESENT=false
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for f in "${RECOMMENDED_FILES[@]}"; do
|
||||||
|
if [ ! -f "$TARGET/$f" ]; then
|
||||||
|
echo "MISSING (recommended): $f"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if $ALL_PRESENT; then
|
||||||
|
echo "✓ Theme structure OK"
|
||||||
|
((TOTAL_PASS++))
|
||||||
|
else
|
||||||
|
echo "✗ Theme structure incomplete"
|
||||||
|
((TOTAL_FAIL++))
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 3. WordPress text domain check
|
||||||
|
echo "--- Text Domain ---"
|
||||||
|
MISSING_DOMAIN=$(grep -rn "__(\|_e(\|esc_html__(\|esc_html_e(\|esc_attr__(\|esc_attr_e(" "$TARGET" --include="*.php" 2>/dev/null | grep -v "'weedops'" | grep -v '"weedops"' || true)
|
||||||
|
if [ -z "$MISSING_DOMAIN" ]; then
|
||||||
|
echo "✓ Text domain 'weedops' used consistently"
|
||||||
|
((TOTAL_PASS++))
|
||||||
|
else
|
||||||
|
echo "WARNING: Some i18n strings may use wrong text domain:"
|
||||||
|
echo "$MISSING_DOMAIN" | head -5
|
||||||
|
((TOTAL_PASS++)) # Warning, not failure
|
||||||
|
fi
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 4. Security basics
|
||||||
|
echo "--- Security Checks ---"
|
||||||
|
SECURITY_OK=true
|
||||||
|
|
||||||
|
# Check for direct file access prevention
|
||||||
|
PHP_FILES=$(find "$TARGET" -name "*.php" -not -path "*/vendor/*" 2>/dev/null)
|
||||||
|
for f in $PHP_FILES; do
|
||||||
|
if ! grep -q "ABSPATH\|defined(" "$f" 2>/dev/null; then
|
||||||
|
BASENAME=$(basename "$f")
|
||||||
|
if [ "$BASENAME" != "index.php" ] && [ "$BASENAME" != "style.css" ]; then
|
||||||
|
echo "WARNING: $f may lack direct access prevention"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "✓ Security check complete"
|
||||||
|
((TOTAL_PASS++))
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
echo "========================================="
|
||||||
|
echo " Results: $TOTAL_PASS passed, $TOTAL_FAIL failed"
|
||||||
|
echo "========================================="
|
||||||
|
|
||||||
|
[ "$TOTAL_FAIL" -eq 0 ] && exit 0 || exit 1
|
||||||
139
scripts/wp-health-check.sh
Executable file
139
scripts/wp-health-check.sh
Executable file
|
|
@ -0,0 +1,139 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Weedops WordPress Health Check Script
|
||||||
|
# Checks site availability, database, plugins, and theme status
|
||||||
|
# Usage: ./wp-health-check.sh [site-url]
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SITE_URL="${1:-https://weedops.site}"
|
||||||
|
WP_PATH="${2:-/var/www/weedops}"
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
WARN=0
|
||||||
|
|
||||||
|
check_pass() { echo -e "${GREEN}[PASS]${NC} $1"; ((PASS++)); }
|
||||||
|
check_fail() { echo -e "${RED}[FAIL]${NC} $1"; ((FAIL++)); }
|
||||||
|
check_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; ((WARN++)); }
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo " Weedops WordPress Health Check"
|
||||||
|
echo " $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
echo "========================================="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 1. HTTP Response Check
|
||||||
|
echo "--- Site Availability ---"
|
||||||
|
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 10 "$SITE_URL" 2>/dev/null || echo "000")
|
||||||
|
if [ "$HTTP_CODE" = "200" ]; then
|
||||||
|
check_pass "Site responding with HTTP $HTTP_CODE"
|
||||||
|
elif [ "$HTTP_CODE" = "301" ] || [ "$HTTP_CODE" = "302" ]; then
|
||||||
|
check_warn "Site redirecting with HTTP $HTTP_CODE"
|
||||||
|
else
|
||||||
|
check_fail "Site returned HTTP $HTTP_CODE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# SSL Check
|
||||||
|
if echo "$SITE_URL" | grep -q "https"; then
|
||||||
|
SSL_EXPIRY=$(echo | openssl s_client -servername "$(echo "$SITE_URL" | sed 's|https://||')" -connect "$(echo "$SITE_URL" | sed 's|https://||')":443 2>/dev/null | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
|
||||||
|
if [ -n "$SSL_EXPIRY" ]; then
|
||||||
|
check_pass "SSL certificate valid until: $SSL_EXPIRY"
|
||||||
|
else
|
||||||
|
check_warn "Could not verify SSL certificate"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 2. WP-CLI Checks (if available)
|
||||||
|
echo "--- WordPress Core ---"
|
||||||
|
if command -v wp &> /dev/null && [ -d "$WP_PATH" ]; then
|
||||||
|
WP_VERSION=$(wp core version --path="$WP_PATH" 2>/dev/null || echo "unknown")
|
||||||
|
if [ "$WP_VERSION" != "unknown" ]; then
|
||||||
|
check_pass "WordPress version: $WP_VERSION"
|
||||||
|
else
|
||||||
|
check_warn "Could not determine WordPress version"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for updates
|
||||||
|
UPDATE_COUNT=$(wp core check-update --path="$WP_PATH" --format=count 2>/dev/null || echo "0")
|
||||||
|
if [ "$UPDATE_COUNT" = "0" ]; then
|
||||||
|
check_pass "WordPress core is up to date"
|
||||||
|
else
|
||||||
|
check_warn "WordPress core update available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Active theme
|
||||||
|
ACTIVE_THEME=$(wp theme list --path="$WP_PATH" --status=active --field=name 2>/dev/null || echo "unknown")
|
||||||
|
check_pass "Active theme: $ACTIVE_THEME"
|
||||||
|
|
||||||
|
# Plugin status
|
||||||
|
echo ""
|
||||||
|
echo "--- Plugins ---"
|
||||||
|
PLUGIN_UPDATES=$(wp plugin list --path="$WP_PATH" --update=available --format=count 2>/dev/null || echo "0")
|
||||||
|
if [ "$PLUGIN_UPDATES" = "0" ]; then
|
||||||
|
check_pass "All plugins up to date"
|
||||||
|
else
|
||||||
|
check_warn "$PLUGIN_UPDATES plugin(s) need updates"
|
||||||
|
fi
|
||||||
|
|
||||||
|
INACTIVE_PLUGINS=$(wp plugin list --path="$WP_PATH" --status=inactive --format=count 2>/dev/null || echo "0")
|
||||||
|
if [ "$INACTIVE_PLUGINS" != "0" ]; then
|
||||||
|
check_warn "$INACTIVE_PLUGINS inactive plugin(s) — consider removing"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
check_warn "WP-CLI not available or WP path not found — skipping core checks"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 3. Database connectivity
|
||||||
|
echo "--- Database ---"
|
||||||
|
if command -v wp &> /dev/null && [ -d "$WP_PATH" ]; then
|
||||||
|
if wp db check --path="$WP_PATH" &>/dev/null; then
|
||||||
|
check_pass "Database connection OK"
|
||||||
|
else
|
||||||
|
check_fail "Database connection failed"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
check_warn "Skipping DB check (WP-CLI not available)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 4. Disk space
|
||||||
|
echo "--- Server ---"
|
||||||
|
DISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
|
||||||
|
if [ "$DISK_USAGE" -lt 80 ]; then
|
||||||
|
check_pass "Disk usage: ${DISK_USAGE}%"
|
||||||
|
elif [ "$DISK_USAGE" -lt 90 ]; then
|
||||||
|
check_warn "Disk usage: ${DISK_USAGE}% — getting full"
|
||||||
|
else
|
||||||
|
check_fail "Disk usage: ${DISK_USAGE}% — critical!"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# PHP version
|
||||||
|
PHP_VER=$(php -v 2>/dev/null | head -1 | awk '{print $2}' || echo "unknown")
|
||||||
|
if [ "$PHP_VER" != "unknown" ]; then
|
||||||
|
check_pass "PHP version: $PHP_VER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Memory
|
||||||
|
MEM_AVAIL=$(free -m | awk '/Mem:/ {printf "%.0f", $7/$2*100}')
|
||||||
|
if [ "$MEM_AVAIL" -gt 20 ]; then
|
||||||
|
check_pass "Available memory: ${MEM_AVAIL}%"
|
||||||
|
else
|
||||||
|
check_warn "Available memory: ${MEM_AVAIL}% — low"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "========================================="
|
||||||
|
echo " Results: ${GREEN}${PASS} passed${NC}, ${YELLOW}${WARN} warnings${NC}, ${RED}${FAIL} failed${NC}"
|
||||||
|
echo "========================================="
|
||||||
|
|
||||||
|
# Exit with error if any failures
|
||||||
|
[ "$FAIL" -eq 0 ] && exit 0 || exit 1
|
||||||
99
scripts/wp-migrate-strains.sh
Executable file
99
scripts/wp-migrate-strains.sh
Executable file
|
|
@ -0,0 +1,99 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Strain Data Migration Tool for Weedops
|
||||||
|
# Imports strain data from CSV into WordPress custom post types
|
||||||
|
# Usage: ./wp-migrate-strains.sh <csv-file> [wp-path]
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
CSV_FILE="${1:-}"
|
||||||
|
WP_PATH="${2:-/var/www/weedops}"
|
||||||
|
|
||||||
|
if [ -z "$CSV_FILE" ]; then
|
||||||
|
echo "Usage: $0 <csv-file> [wp-path]"
|
||||||
|
echo ""
|
||||||
|
echo "CSV format: name,type,thc_min,thc_max,cbd_min,cbd_max,effects,description"
|
||||||
|
echo "Types: indica, sativa, hybrid"
|
||||||
|
echo ""
|
||||||
|
echo "Example:"
|
||||||
|
echo " Blue Dream,hybrid,17,24,0.1,0.2,\"relaxed,happy,creative\",\"Popular hybrid strain\""
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f "$CSV_FILE" ]; then
|
||||||
|
echo "ERROR: File not found: $CSV_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! command -v wp &> /dev/null; then
|
||||||
|
echo "ERROR: WP-CLI required. Install from https://wp-cli.org/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "========================================="
|
||||||
|
echo " Weedops Strain Data Importer"
|
||||||
|
echo " $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
echo "========================================="
|
||||||
|
echo "Source: $CSV_FILE"
|
||||||
|
echo "Target: $WP_PATH"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
IMPORTED=0
|
||||||
|
SKIPPED=0
|
||||||
|
ERRORS=0
|
||||||
|
|
||||||
|
# Skip header line
|
||||||
|
tail -n +2 "$CSV_FILE" | while IFS=',' read -r name type thc_min thc_max cbd_min cbd_max effects description; do
|
||||||
|
# Clean up fields
|
||||||
|
name=$(echo "$name" | sed 's/^"//;s/"$//' | xargs)
|
||||||
|
type=$(echo "$type" | sed 's/^"//;s/"$//' | xargs)
|
||||||
|
description=$(echo "$description" | sed 's/^"//;s/"$//')
|
||||||
|
|
||||||
|
if [ -z "$name" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -n "Importing: $name... "
|
||||||
|
|
||||||
|
# Check if strain already exists
|
||||||
|
EXISTING=$(wp post list --path="$WP_PATH" --post_type=strain --name="$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')" --format=count 2>/dev/null || echo "0")
|
||||||
|
|
||||||
|
if [ "$EXISTING" != "0" ]; then
|
||||||
|
echo "SKIPPED (already exists)"
|
||||||
|
((SKIPPED++))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the strain post
|
||||||
|
POST_ID=$(wp post create \
|
||||||
|
--path="$WP_PATH" \
|
||||||
|
--post_type=strain \
|
||||||
|
--post_title="$name" \
|
||||||
|
--post_content="$description" \
|
||||||
|
--post_status=publish \
|
||||||
|
--porcelain 2>/dev/null || echo "0")
|
||||||
|
|
||||||
|
if [ "$POST_ID" = "0" ]; then
|
||||||
|
echo "ERROR"
|
||||||
|
((ERRORS++))
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Set strain type taxonomy
|
||||||
|
wp term set "$POST_ID" strain_type "$type" --path="$WP_PATH" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Set meta fields
|
||||||
|
wp post meta update "$POST_ID" thc_min "$thc_min" --path="$WP_PATH" 2>/dev/null || true
|
||||||
|
wp post meta update "$POST_ID" thc_max "$thc_max" --path="$WP_PATH" 2>/dev/null || true
|
||||||
|
wp post meta update "$POST_ID" cbd_min "$cbd_min" --path="$WP_PATH" 2>/dev/null || true
|
||||||
|
wp post meta update "$POST_ID" cbd_max "$cbd_max" --path="$WP_PATH" 2>/dev/null || true
|
||||||
|
wp post meta update "$POST_ID" effects "$effects" --path="$WP_PATH" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "OK (ID: $POST_ID)"
|
||||||
|
((IMPORTED++))
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "========================================="
|
||||||
|
echo " Import complete"
|
||||||
|
echo " Imported: $IMPORTED | Skipped: $SKIPPED | Errors: $ERRORS"
|
||||||
|
echo "========================================="
|
||||||
Loading…
Add table
Reference in a new issue