From cec5daa0b0b3d6c32c9d3065fa59ab26fb601da0 Mon Sep 17 00:00:00 2001 From: jknapp Date: Wed, 10 Sep 2025 06:02:50 -0700 Subject: [PATCH] removing unneeded files from repo and plugin --- .gitea/workflows/release.yml | 40 +++++++- .gitea/workflows/update-version.yml | 18 +++- .gitignore | 17 +++- clean-sensitive-data.sh | 63 +++++++++++++ docs/developer-integration-guide.md | 114 ++++++++++++++++++++--- includes/wpdd-plugin-updater.php | 138 +++++++++++++++++++++------- 6 files changed, 343 insertions(+), 47 deletions(-) create mode 100755 clean-sensitive-data.sh diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index 1130910..5118fd3 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -66,8 +66,44 @@ jobs: # Copy files to the temp directory (excluding git and other unnecessary files) cp -r * /tmp/wp-digital-download/ 2>/dev/null || true - # Exclude .git, .gitea, and .playwright-mcp directories - rm -rf /tmp/wp-digital-download/.git /tmp/wp-digital-download/.gitea /tmp/wp-digital-download/.playwright-mcp 2>/dev/null || true + # Exclude development and sensitive files from plugin distribution + # Remove version control and CI/CD files + rm -rf /tmp/wp-digital-download/.git 2>/dev/null || true + rm -rf /tmp/wp-digital-download/.gitea 2>/dev/null || true + rm -rf /tmp/wp-digital-download/.github 2>/dev/null || true + rm -f /tmp/wp-digital-download/.gitignore 2>/dev/null || true + + # Remove testing and development files + rm -rf /tmp/wp-digital-download/.playwright-mcp 2>/dev/null || true + rm -rf /tmp/wp-digital-download/tests 2>/dev/null || true + rm -rf /tmp/wp-digital-download/test 2>/dev/null || true + rm -rf /tmp/wp-digital-download/node_modules 2>/dev/null || true + + # Remove documentation and config files that might contain sensitive data + rm -f /tmp/wp-digital-download/CLAUDE.md 2>/dev/null || true + rm -f /tmp/wp-digital-download/README.md 2>/dev/null || true + + # Remove ALL JSON files (package.json, composer.json, and any test configs) + find /tmp/wp-digital-download -type f -name "*.json" -delete 2>/dev/null || true + + # Remove any lock files + rm -f /tmp/wp-digital-download/package-lock.json 2>/dev/null || true + rm -f /tmp/wp-digital-download/composer.lock 2>/dev/null || true + + # Remove any .env files that might contain credentials + find /tmp/wp-digital-download -type f -name ".env*" -delete 2>/dev/null || true + + # Remove any backup or temporary files + find /tmp/wp-digital-download -type f -name "*~" -delete 2>/dev/null || true + find /tmp/wp-digital-download -type f -name "*.bak" -delete 2>/dev/null || true + find /tmp/wp-digital-download -type f -name "*.tmp" -delete 2>/dev/null || true + + # Remove any log files + find /tmp/wp-digital-download -type f -name "*.log" -delete 2>/dev/null || true + + # List what's being included (for verification) + echo "Files being included in the release:" + ls -la /tmp/wp-digital-download/ # Create the ZIP file with the proper structure cd /tmp diff --git a/.gitea/workflows/update-version.yml b/.gitea/workflows/update-version.yml index 2e22d2e..37d05d3 100644 --- a/.gitea/workflows/update-version.yml +++ b/.gitea/workflows/update-version.yml @@ -42,7 +42,23 @@ jobs: - name: Create plugin zip run: | mkdir -p /tmp/wp-digital-download - rsync -av --exclude=".git" --exclude=".gitea" --exclude=".playwright-mcp" --exclude="build" . /tmp/wp-digital-download/ + rsync -av \ + --exclude=".git" \ + --exclude=".gitea" \ + --exclude=".gitignore" \ + --exclude=".playwright-mcp" \ + --exclude="build" \ + --exclude="node_modules" \ + --exclude="tests" \ + --exclude="test" \ + --exclude="CLAUDE.md" \ + --exclude="*.json" \ + --exclude="*.log" \ + --exclude=".env*" \ + --exclude="*.bak" \ + --exclude="*.tmp" \ + --exclude="*~" \ + . /tmp/wp-digital-download/ cd /tmp zip -r $GITEA_WORK_DIR/wp-digital-download.zip wp-digital-download diff --git a/.gitignore b/.gitignore index 1fe5e52..ef1af17 100644 --- a/.gitignore +++ b/.gitignore @@ -11,12 +11,27 @@ wp-content/wp-cache-config.php wp-content/cache/ wp-content/backups/ -# Plugin specific +# Development files (excluded from plugin distribution) node_modules/ +tests/ +test/ +CLAUDE.md *.log .DS_Store Thumbs.db +# Package and config files (may contain test data) +package.json +package-lock.json +composer.json +composer.lock +*.json + +# Environment files +.env +.env.* +*.env + # IDE files .vscode/ .idea/ diff --git a/clean-sensitive-data.sh b/clean-sensitive-data.sh new file mode 100755 index 0000000..4e4a65b --- /dev/null +++ b/clean-sensitive-data.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Script to remove sensitive files from git history +# WARNING: This will rewrite git history! + +echo "WARNING: This script will rewrite git history to remove sensitive files." +echo "Make sure you have a backup of your repository before proceeding." +echo "" +read -p "Do you want to continue? (y/N): " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Aborted." + exit 1 +fi + +echo "Removing sensitive files from git history..." + +# Files to remove from history +FILES_TO_REMOVE=( + "CLAUDE.md" + "package.json" + "package-lock.json" + "composer.json" + "composer.lock" + ".playwright-mcp/*" + "tests/*" + "*.json" + ".env" + ".env.*" +) + +# Remove each file from git history +for file in "${FILES_TO_REMOVE[@]}"; do + echo "Removing $file from history..." + git filter-branch --force --index-filter \ + "git rm -rf --cached --ignore-unmatch $file" \ + --prune-empty --tag-name-filter cat -- --all 2>/dev/null || true +done + +echo "" +echo "Cleaning up..." + +# Clean up refs +git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d + +# Expire reflog +git reflog expire --expire=now --all + +# Garbage collect +git gc --prune=now --aggressive + +echo "" +echo "Done! Sensitive files have been removed from git history." +echo "" +echo "IMPORTANT NEXT STEPS:" +echo "1. Review the changes with: git log --oneline" +echo "2. Force push to remote: git push --force --all" +echo "3. Tell all collaborators to re-clone the repository" +echo "4. Update any CI/CD secrets that may have been exposed" +echo "" +echo "The following files are now in .gitignore and won't be committed again:" +cat .gitignore | grep -E "CLAUDE|json|.env|playwright|test" | head -10 \ No newline at end of file diff --git a/docs/developer-integration-guide.md b/docs/developer-integration-guide.md index 2f1e439..99a4c31 100644 --- a/docs/developer-integration-guide.md +++ b/docs/developer-integration-guide.md @@ -8,7 +8,33 @@ This guide shows developers how to integrate their WordPress plugins with the WP Download `wpdd-plugin-updater.php` from your product page and include it in your plugin. -### 2. Basic Integration +### 2. Minimal Integration + +For the simplest integration with automatic license management: + +```php + true) + ); +} +``` + +This creates a license settings page under Settings → My Plugin License. + +### 3. Full Integration ```php updater = new WPDD_Plugin_Updater( - MY_PLUGIN_FILE, + MY_PLUGIN_FILE, // Define this constant to your main plugin file $license_key, 'https://your-store.com', - array('add_settings_page' => false) // We'll handle settings ourselves + array('add_settings_page' => false) // We'll handle settings ourselves ); } @@ -102,7 +135,7 @@ class My_Plugin_Settings { public function render_license_section() { $license_key = get_option('my_plugin_license_key', ''); - $is_valid = $this->updater->validate_license(); + $is_valid = $this->updater ? $this->updater->validate_license() : false; ?>

License Settings

@@ -150,6 +183,11 @@ class My_Premium_Feature { private $updater; public function __construct() { + // Include updater if not already loaded + if (!class_exists('WPDD_Plugin_Updater')) { + require_once plugin_dir_path(__FILE__) . 'includes/wpdd-plugin-updater.php'; + } + $license_key = get_option('my_plugin_license_key', ''); $this->updater = new WPDD_Plugin_Updater( @@ -167,7 +205,8 @@ class My_Premium_Feature { } private function is_license_valid() { - return $this->updater->validate_license(); + // Check if updater exists and validate license + return $this->updater ? $this->updater->validate_license() : false; } private function enable_premium_features() { @@ -195,14 +234,20 @@ class My_Premium_Feature { ### WPDD_Plugin_Updater Class +#### Requirements + +- **WordPress**: 5.0 or higher +- **PHP**: 7.0 or higher +- **Plugin Version Header**: Your main plugin file must include a Version header + #### Constructor Parameters ```php new WPDD_Plugin_Updater($plugin_file, $license_key, $update_server, $args); ``` -- **$plugin_file** (string) - Full path to your main plugin file -- **$license_key** (string) - The user's license key +- **$plugin_file** (string) - Full path to your main plugin file (typically `__FILE__`) +- **$license_key** (string) - The user's license key (can be empty string) - **$update_server** (string) - URL to your store (e.g., 'https://your-store.com') - **$args** (array) - Optional arguments: - `add_settings_page` (bool) - Auto-create license settings page (default: false) @@ -352,10 +397,18 @@ Then visit: `wp-admin/plugins.php?force_update_check=1` Always handle API failures gracefully: ```php +// Check if updater was initialized properly +if (!$this->updater) { + // Handle initialization failure + error_log('WPDD Updater failed to initialize'); + return; +} + $result = $updater->validate_license(); if ($result === false) { // Network error or server down - allow functionality to continue // but maybe show a notice + error_log('License validation failed - network or server issue'); } ``` @@ -388,13 +441,50 @@ if ($this->is_license_valid()) { } ``` +## What's New in Version 1.1.0 + +The updated `wpdd-plugin-updater.php` includes several improvements: + +### Enhanced Error Handling +- Better HTTP request error handling with status code checking +- JSON validation to prevent parsing errors +- Improved timeout handling (30 seconds default) +- More detailed error logging for debugging + +### Improved Compatibility +- Better API response structure handling +- Flexible URL checking for package downloads +- Support for different server configurations +- Fallback values for missing data fields + +### Security Enhancements +- SSL verification enabled by default +- Proper input validation in constructor +- Safe handling of network failures + +### Performance Improvements +- 12-hour caching for update checks +- Optimized HTTP requests with proper headers +- Reduced unnecessary API calls + ## Troubleshooting ### Common Issues -1. **Updates not showing:** Check that the plugin slug matches the product slug in your store -2. **License validation fails:** Ensure the update server URL is correct and accessible -3. **Download fails:** Verify the license is activated and not expired +1. **Updates not showing:** + - Check that the plugin slug matches the product slug in your store + - Verify the plugin file has a proper Version header + - Clear update transients using the force update check method + +2. **License validation fails:** + - Ensure the update server URL is correct and accessible + - Check that the license key is properly formatted + - Verify SSL certificates are valid on your server + +3. **Download fails:** + - Verify the license is activated and not expired + - Check activation limits haven't been exceeded + - Ensure the package file exists on the server ### Debug Mode diff --git a/includes/wpdd-plugin-updater.php b/includes/wpdd-plugin-updater.php index 44c88f0..1fbb3ce 100644 --- a/includes/wpdd-plugin-updater.php +++ b/includes/wpdd-plugin-updater.php @@ -5,7 +5,21 @@ * Include this file in your WordPress plugin to enable automatic updates * and license validation through the WP Digital Download licensing system. * - * @version 1.0.0 + * Usage example: + * + * // Initialize the updater + * if (!class_exists('WPDD_Plugin_Updater')) { + * require_once 'path/to/wpdd-plugin-updater.php'; + * } + * + * $updater = new WPDD_Plugin_Updater( + * __FILE__, // Main plugin file path + * get_option('my_plugin_license_key', ''), // License key from options + * 'https://your-site.com', // Update server URL + * array('add_settings_page' => true) // Optional: Add license settings page + * ); + * + * @version 1.1.0 * @author WP Digital Download */ @@ -33,9 +47,20 @@ class WPDD_Plugin_Updater { * @param array $args Additional arguments */ public function __construct($plugin_file, $license_key, $update_server, $args = array()) { + // Validate required parameters + if (empty($plugin_file) || !file_exists($plugin_file)) { + error_log('WPDD Updater: Invalid plugin file path provided'); + return; + } + + if (empty($update_server) || !filter_var($update_server, FILTER_VALIDATE_URL)) { + error_log('WPDD Updater: Invalid update server URL provided'); + return; + } + $this->plugin_file = $plugin_file; $this->plugin_slug = basename($plugin_file, '.php'); - $this->license_key = $license_key; + $this->license_key = trim($license_key); $this->update_server = trailingslashit($update_server); // Get plugin version from header @@ -43,7 +68,7 @@ class WPDD_Plugin_Updater { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $plugin_data = get_plugin_data($plugin_file); - $this->version = $plugin_data['Version']; + $this->version = $plugin_data['Version'] ?? '1.0.0'; $this->transient_key = 'wpdd_update_' . $this->plugin_slug; @@ -90,15 +115,16 @@ class WPDD_Plugin_Updater { $update_info = $this->request_update_info(); if ($update_info && isset($update_info['update_available']) && $update_info['update_available']) { + // API returns proper structure - use it directly $plugin_data = array( - 'slug' => $this->plugin_slug, - 'plugin' => $this->plugin_file, - 'new_version' => $update_info['version'], - 'url' => $update_info['url'], - 'package' => $update_info['package'], - 'tested' => $update_info['tested'], - 'requires' => $update_info['requires'], - 'requires_php' => $update_info['requires_php'], + 'slug' => $update_info['slug'] ?? $this->plugin_slug, + 'plugin' => $update_info['plugin'] ?? $this->plugin_file, + 'new_version' => $update_info['version'] ?? $update_info['new_version'], + 'url' => $update_info['url'] ?? '', + 'package' => $update_info['package'] ?? $update_info['download_url'], + 'tested' => $update_info['tested'] ?? get_bloginfo('version'), + 'requires' => $update_info['requires'] ?? '5.0', + 'requires_php' => $update_info['requires_php'] ?? '7.0', 'compatibility' => new stdClass() ); @@ -133,19 +159,25 @@ class WPDD_Plugin_Updater { return $false; } + // Extract product name from plugin file if available + if (!function_exists('get_plugin_data')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + $plugin_data = get_plugin_data($this->plugin_file); + return (object) array( 'slug' => $this->plugin_slug, - 'name' => $update_info['name'] ?? $this->plugin_slug, - 'version' => $update_info['version'] ?? $this->version, - 'author' => $update_info['author'] ?? '', - 'homepage' => $update_info['url'] ?? '', + 'name' => $plugin_data['Name'] ?? $this->plugin_slug, + 'version' => $update_info['version'] ?? $update_info['new_version'] ?? $this->version, + 'author' => $plugin_data['Author'] ?? $update_info['author'] ?? '', + 'homepage' => $plugin_data['PluginURI'] ?? $update_info['url'] ?? '', 'requires' => $update_info['requires'] ?? '5.0', 'tested' => $update_info['tested'] ?? get_bloginfo('version'), 'requires_php' => $update_info['requires_php'] ?? '7.0', - 'download_link' => $update_info['package'] ?? '', + 'download_link' => $update_info['package'] ?? $update_info['download_url'] ?? '', 'sections' => array( - 'changelog' => $update_info['changelog'] ?? '', - 'description' => $update_info['description'] ?? '' + 'changelog' => $update_info['changelog'] ?? $update_info['release_notes'] ?? '', + 'description' => $plugin_data['Description'] ?? $update_info['description'] ?? '' ), 'banners' => array(), 'icons' => array() @@ -157,7 +189,17 @@ class WPDD_Plugin_Updater { */ public function maybe_download_package($reply, $package, $upgrader) { // Check if this is our plugin's package - if (strpos($package, $this->update_server) === false || strpos($package, $this->plugin_slug) === false) { + // More flexible URL checking - handle different URL structures + $server_host = parse_url($this->update_server, PHP_URL_HOST); + $package_host = parse_url($package, PHP_URL_HOST); + + if ($server_host !== $package_host && strpos($package, $this->plugin_slug) === false) { + return $reply; + } + + // Also check if this is a WPDD download URL pattern + if (strpos($package, 'wp-json/wpdd/v1/download-update') === false && + strpos($package, $this->update_server) === false) { return $reply; } @@ -182,10 +224,15 @@ class WPDD_Plugin_Updater { ), $url); $response = wp_remote_get($url, array( - 'timeout' => 15, + 'timeout' => 30, + 'redirection' => 3, + 'httpversion' => '1.1', + 'user-agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url(), 'headers' => array( - 'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url() - ) + 'Accept' => 'application/json', + 'Content-Type' => 'application/json' + ), + 'sslverify' => true )); if (is_wp_error($response)) { @@ -193,9 +240,25 @@ class WPDD_Plugin_Updater { return false; } + $http_code = wp_remote_retrieve_response_code($response); + if ($http_code !== 200) { + error_log('WPDD Updater: HTTP error ' . $http_code . ' when checking for updates'); + return false; + } + $body = wp_remote_retrieve_body($response); + if (empty($body)) { + error_log('WPDD Updater: Empty response body when checking for updates'); + return false; + } + $data = json_decode($body, true); + if (json_last_error() !== JSON_ERROR_NONE) { + error_log('WPDD Updater: Invalid JSON response: ' . json_last_error_msg()); + return false; + } + if (!$data || !isset($data['success'])) { error_log('WPDD Updater: Invalid response from update server'); return false; @@ -208,6 +271,7 @@ class WPDD_Plugin_Updater { return false; } + // Return the data array directly - API already provides proper structure return $data; } @@ -222,15 +286,19 @@ class WPDD_Plugin_Updater { $url = $this->update_server . 'wp-json/wpdd/v1/validate-license'; $response = wp_remote_post($url, array( - 'timeout' => 15, + 'timeout' => 30, + 'redirection' => 3, + 'httpversion' => '1.1', 'body' => array( 'license_key' => $this->license_key, 'product_slug' => $this->plugin_slug, 'site_url' => home_url() ), 'headers' => array( - 'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url() - ) + 'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url(), + 'Accept' => 'application/json' + ), + 'sslverify' => true )); if (is_wp_error($response)) { @@ -261,7 +329,9 @@ class WPDD_Plugin_Updater { $url = $this->update_server . 'wp-json/wpdd/v1/activate-license'; $response = wp_remote_post($url, array( - 'timeout' => 15, + 'timeout' => 30, + 'redirection' => 3, + 'httpversion' => '1.1', 'body' => array( 'license_key' => $this->license_key, 'site_url' => home_url(), @@ -270,8 +340,10 @@ class WPDD_Plugin_Updater { 'php_version' => PHP_VERSION ), 'headers' => array( - 'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url() - ) + 'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url(), + 'Accept' => 'application/json' + ), + 'sslverify' => true )); if (is_wp_error($response)) { @@ -308,14 +380,18 @@ class WPDD_Plugin_Updater { $url = $this->update_server . 'wp-json/wpdd/v1/deactivate-license'; $response = wp_remote_post($url, array( - 'timeout' => 15, + 'timeout' => 30, + 'redirection' => 3, + 'httpversion' => '1.1', 'body' => array( 'license_key' => $this->license_key, 'site_url' => home_url() ), 'headers' => array( - 'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url() - ) + 'User-Agent' => 'WPDD-Updater/' . $this->version . '; ' . home_url(), + 'Accept' => 'application/json' + ), + 'sslverify' => true )); if (is_wp_error($response)) {