You've already forked wc-tier-and-package-prices
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e17bdefe06 | |||
| fa26247d1b | |||
| a4b84f7e41 | |||
| 2e9c948a07 | |||
| dd4333bd11 | |||
| b909221ae2 | |||
| d80c9d90f9 | |||
| 2bf0cd82fe | |||
| 9451cc1965 | |||
| 02b0308058 | |||
| 38e9506d4e | |||
| 74cc56005e | |||
| 136eed2bdd | |||
| 178f86f3e6 | |||
| 7286459ff2 | |||
| cbe758267e | |||
| 74c14581f1 | |||
| 0dbe18d954 | |||
| 63c8137f4e |
217
.gitea/workflows/release.yml
Normal file
217
.gitea/workflows/release.yml
Normal file
@@ -0,0 +1,217 @@
|
||||
name: Create Release Package
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
build-release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.3'
|
||||
extensions: mbstring, xml, zip, intl, gettext
|
||||
tools: composer:v2
|
||||
|
||||
- name: Get version from tag
|
||||
id: version
|
||||
run: |
|
||||
VERSION=${GITHUB_REF_NAME#v}
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "Building version: $VERSION"
|
||||
|
||||
- name: Validate composer.json
|
||||
run: composer validate --strict
|
||||
|
||||
- name: Install Composer dependencies (production)
|
||||
run: |
|
||||
composer config platform.php 8.3.0
|
||||
composer install --no-dev --optimize-autoloader --no-interaction
|
||||
|
||||
- name: Install gettext
|
||||
run: apt-get update && apt-get install -y gettext
|
||||
|
||||
- name: Compile translations
|
||||
run: |
|
||||
for po in languages/*.po; do
|
||||
if [ -f "$po" ]; then
|
||||
mo="${po%.po}.mo"
|
||||
echo "Compiling $po to $mo"
|
||||
msgfmt -o "$mo" "$po"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Verify plugin version matches tag
|
||||
run: |
|
||||
PLUGIN_VERSION=$(grep -oP "Version:\s*\K[0-9]+\.[0-9]+\.[0-9]+" wc-tier-and-package-prices.php | head -1)
|
||||
TAG_VERSION=${{ steps.version.outputs.version }}
|
||||
if [ "$PLUGIN_VERSION" != "$TAG_VERSION" ]; then
|
||||
echo "Error: Plugin version ($PLUGIN_VERSION) does not match tag version ($TAG_VERSION)"
|
||||
exit 1
|
||||
fi
|
||||
echo "Version verified: $PLUGIN_VERSION"
|
||||
|
||||
- name: Create release directory
|
||||
run: mkdir -p releases
|
||||
|
||||
- name: Build release package
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.version }}
|
||||
PLUGIN_NAME="wc-tier-and-package-prices"
|
||||
RELEASE_FILE="releases/${PLUGIN_NAME}-${VERSION}.zip"
|
||||
|
||||
cd ..
|
||||
zip -r "${PLUGIN_NAME}/${RELEASE_FILE}" "${PLUGIN_NAME}" \
|
||||
-x "${PLUGIN_NAME}/.git/*" \
|
||||
-x "${PLUGIN_NAME}/.gitea/*" \
|
||||
-x "${PLUGIN_NAME}/.github/*" \
|
||||
-x "${PLUGIN_NAME}/.vscode/*" \
|
||||
-x "${PLUGIN_NAME}/.idea/*" \
|
||||
-x "${PLUGIN_NAME}/.claude/*" \
|
||||
-x "${PLUGIN_NAME}/CLAUDE.md" \
|
||||
-x "${PLUGIN_NAME}/wordpress" \
|
||||
-x "${PLUGIN_NAME}/wordpress/*" \
|
||||
-x "${PLUGIN_NAME}/core" \
|
||||
-x "${PLUGIN_NAME}/core/*" \
|
||||
-x "${PLUGIN_NAME}/wp-core" \
|
||||
-x "${PLUGIN_NAME}/wp-core/*" \
|
||||
-x "${PLUGIN_NAME}/releases/*" \
|
||||
-x "${PLUGIN_NAME}/composer.lock" \
|
||||
-x "${PLUGIN_NAME}/*.log" \
|
||||
-x "${PLUGIN_NAME}/logs/*" \
|
||||
-x "${PLUGIN_NAME}/.gitignore" \
|
||||
-x "${PLUGIN_NAME}/.gitmodules" \
|
||||
-x "${PLUGIN_NAME}/.editorconfig" \
|
||||
-x "${PLUGIN_NAME}/phpcs.xml*" \
|
||||
-x "${PLUGIN_NAME}/phpunit.xml*" \
|
||||
-x "${PLUGIN_NAME}/tests/*" \
|
||||
-x "${PLUGIN_NAME}/templates/cache/*" \
|
||||
-x "${PLUGIN_NAME}/notes.*" \
|
||||
-x "${PLUGIN_NAME}/*.po~" \
|
||||
-x "${PLUGIN_NAME}/*.bak" \
|
||||
-x "${PLUGIN_NAME}/lib/*/.git/*" \
|
||||
-x "${PLUGIN_NAME}/lib/*/CLAUDE.md" \
|
||||
-x "${PLUGIN_NAME}/vendor/magdev/*/.git/*" \
|
||||
-x "${PLUGIN_NAME}/vendor/magdev/*/CLAUDE.md" \
|
||||
-x "*.DS_Store" \
|
||||
-x "*Thumbs.db"
|
||||
|
||||
cd "${PLUGIN_NAME}"
|
||||
echo "Created: ${RELEASE_FILE}"
|
||||
ls -lh "${RELEASE_FILE}"
|
||||
|
||||
- name: Generate checksums
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.version }}
|
||||
PLUGIN_NAME="wc-tier-and-package-prices"
|
||||
RELEASE_FILE="releases/${PLUGIN_NAME}-${VERSION}.zip"
|
||||
|
||||
cd releases
|
||||
sha256sum "${PLUGIN_NAME}-${VERSION}.zip" > "${PLUGIN_NAME}-${VERSION}.zip.sha256"
|
||||
echo "SHA256:"
|
||||
cat "${PLUGIN_NAME}-${VERSION}.zip.sha256"
|
||||
|
||||
- name: Verify package structure
|
||||
run: |
|
||||
set +o pipefail
|
||||
VERSION=${{ steps.version.outputs.version }}
|
||||
PLUGIN_NAME="wc-tier-and-package-prices"
|
||||
|
||||
echo "Package contents (first 50 entries):"
|
||||
unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | head -50 || true
|
||||
|
||||
# Verify main plugin file exists
|
||||
if unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -q "${PLUGIN_NAME}/${PLUGIN_NAME}.php"; then
|
||||
echo "✓ Main plugin file at correct location"
|
||||
else
|
||||
echo "✗ Error: Main plugin file not found at ${PLUGIN_NAME}/${PLUGIN_NAME}.php"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify vendor directory included
|
||||
if unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -q "${PLUGIN_NAME}/vendor/"; then
|
||||
echo "✓ Vendor directory included"
|
||||
else
|
||||
echo "✗ Error: Vendor directory not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify excluded files are not present
|
||||
if unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -qE "CLAUDE\.md|\.claude/|\.git/|wordpress/"; then
|
||||
echo "✗ Error: Excluded files found in package"
|
||||
unzip -l "releases/${PLUGIN_NAME}-${VERSION}.zip" | grep -E "CLAUDE\.md|\.claude/|\.git/|wordpress/"
|
||||
exit 1
|
||||
else
|
||||
echo "✓ No excluded files in package"
|
||||
fi
|
||||
|
||||
- name: Extract changelog for release notes
|
||||
id: changelog
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.version }}
|
||||
|
||||
# Extract release notes from CHANGELOG.md
|
||||
NOTES=$(sed -n "/^## \[${VERSION}\]/,/^## \[/p" CHANGELOG.md | sed '$ d' | tail -n +2)
|
||||
if [ -z "$NOTES" ]; then
|
||||
NOTES="Release version ${VERSION}"
|
||||
fi
|
||||
|
||||
echo "$NOTES" > release_notes.txt
|
||||
echo "Release notes extracted"
|
||||
|
||||
- name: Create Gitea Release
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.SRC_GITEA_TOKEN }}
|
||||
run: |
|
||||
VERSION=${{ steps.version.outputs.version }}
|
||||
TAG_NAME=${{ github.ref_name }}
|
||||
PLUGIN_NAME="wc-tier-and-package-prices"
|
||||
|
||||
# Check if this is a prerelease (contains hyphen like v1.0.0-beta)
|
||||
PRERELEASE="false"
|
||||
if [[ "$TAG_NAME" == *-* ]]; then
|
||||
PRERELEASE="true"
|
||||
fi
|
||||
|
||||
BODY=$(cat release_notes.txt)
|
||||
|
||||
# Create release via Gitea API
|
||||
RELEASE_RESPONSE=$(curl -s -X POST \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"tag_name\": \"${TAG_NAME}\", \"name\": \"Release ${VERSION}\", \"body\": $(echo "$BODY" | jq -Rs .), \"draft\": false, \"prerelease\": ${PRERELEASE}}" \
|
||||
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases")
|
||||
|
||||
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id')
|
||||
|
||||
if [ "$RELEASE_ID" == "null" ] || [ -z "$RELEASE_ID" ]; then
|
||||
echo "Failed to create release:"
|
||||
echo "$RELEASE_RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Created release ID: $RELEASE_ID"
|
||||
|
||||
# Upload release assets
|
||||
for file in "releases/${PLUGIN_NAME}-${VERSION}.zip" "releases/${PLUGIN_NAME}-${VERSION}.zip.sha256"; do
|
||||
if [ -f "$file" ]; then
|
||||
FILENAME=$(basename "$file")
|
||||
echo "Uploading $FILENAME..."
|
||||
curl -s -X POST \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary "@$file" \
|
||||
"${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}/releases/${RELEASE_ID}/assets?name=${FILENAME}"
|
||||
echo "Uploaded $FILENAME"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Release created successfully: ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/releases/tag/${TAG_NAME}"
|
||||
10
.gitignore
vendored
Normal file → Executable file
10
.gitignore
vendored
Normal file → Executable file
@@ -33,3 +33,13 @@ notes.*
|
||||
# local code
|
||||
wordpress
|
||||
core
|
||||
wp-core
|
||||
|
||||
# Releases (not tracked in git)
|
||||
/releases/
|
||||
|
||||
# Claude Code local settings
|
||||
.claude/settings.json
|
||||
|
||||
# Marketing texts (not for public distribution)
|
||||
MARKETING.md
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "lib/wc-licensed-product-client"]
|
||||
path = lib/wc-licensed-product-client
|
||||
url = ../wc-licensed-product-client.git
|
||||
150
CHANGELOG.md
150
CHANGELOG.md
@@ -5,6 +5,156 @@ All notable changes to WooCommerce Tier and Package Prices will be documented in
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.4.1] - 2026-02-03
|
||||
|
||||
### Added
|
||||
|
||||
- **Localhost License Bypass**: License validation is automatically bypassed for localhost environments
|
||||
- Supports localhost, 127.0.0.1, ::1 (IPv6), `*.localhost`, `*.local`, `*.test`, `*.example`, `*.invalid`
|
||||
- Private IP ranges (Docker, VMs) are also recognized as localhost
|
||||
- Displays "(Localhost environment - license validation bypassed)" in License Status
|
||||
|
||||
- **Self-Licensing Bypass**: License validation is bypassed when the site URL matches the license server URL
|
||||
- Useful for testing the plugin on the license server itself
|
||||
- Displays "(Self-licensing server - license validation bypassed)" in License Status
|
||||
|
||||
- **Auto-Update System**: Plugin can now receive updates directly from the license server
|
||||
- New "Auto-Updates" settings tab under WooCommerce > Tier & Package Prices
|
||||
- **Enable Update Notifications**: Toggle to check for available updates (default: enabled)
|
||||
- **Automatically Install Updates**: Optional auto-install when WordPress performs background updates
|
||||
- **Check Frequency**: Configurable hours between update checks (1-168 hours, default: 12)
|
||||
- **Update Status**: Shows current version and available update with "Check for Updates" button
|
||||
- Updates appear in WordPress Dashboard > Updates with full plugin info
|
||||
|
||||
- **New Classes**:
|
||||
- `WC_TPP_License_Checker`: Singleton class handling license validation with localhost/self-licensing bypass
|
||||
- `WC_TPP_Update_Checker`: Singleton class integrating with WordPress plugin update system
|
||||
|
||||
### Technical Details
|
||||
|
||||
**License Checker Features**:
|
||||
|
||||
- `is_localhost()`: Detects localhost environments using multiple patterns
|
||||
- `is_self_licensing()`: Compares license server URL with site URL
|
||||
- `is_license_valid()`: Main entry point with bypass logic
|
||||
- `get_bypass_reason()`: Returns 'localhost', 'self_licensing', or null
|
||||
- Cached validation (1 hour success, 5 minutes error)
|
||||
|
||||
**Update Checker Features**:
|
||||
|
||||
- Hooks into `pre_set_site_transient_update_plugins` for update detection
|
||||
- Hooks into `plugins_api` for update modal information
|
||||
- Hooks into `http_request_args` for license authentication
|
||||
- Hooks into `auto_update_plugin` for background updates
|
||||
- Can be disabled via `WC_TPP_DISABLE_AUTO_UPDATE` constant
|
||||
|
||||
**New Settings Options**:
|
||||
|
||||
- `wc_tpp_update_notification_enabled` (yes/no, default: yes)
|
||||
- `wc_tpp_auto_install_enabled` (yes/no, default: no)
|
||||
- `wc_tpp_update_check_frequency` (number, default: 12)
|
||||
|
||||
**Update Server Endpoint**:
|
||||
|
||||
- POST to `/wp-json/wc-licensed-product/v1/update-check`
|
||||
- Request body: `{license_key, domain, plugin_slug, current_version}`
|
||||
- Response: `{success, update_available, version, download_url, ...}`
|
||||
|
||||
---
|
||||
|
||||
## [1.4.0] - 2026-01-29
|
||||
|
||||
### Added
|
||||
|
||||
- **Gitea CI/CD Release Pipeline**: Automated release workflow triggered on version tags
|
||||
- Validates plugin version matches tag version
|
||||
- Installs production Composer dependencies
|
||||
- Compiles translation files (.po to .mo)
|
||||
- Creates release package with proper exclusions
|
||||
- Generates SHA256 checksum
|
||||
- Publishes release to Gitea with changelog notes
|
||||
|
||||
---
|
||||
|
||||
## [1.3.1] - 2026-01-27
|
||||
|
||||
### Changed
|
||||
|
||||
- **Switched to SecureLicenseClient**: Upgraded from basic `LicenseClient` to `SecureLicenseClient` with HMAC-SHA256 response signature verification for enhanced security against tampering and replay attacks
|
||||
|
||||
- **Added Server Secret Configuration**: New "Server Secret" field in License settings for secure communication with the license server
|
||||
|
||||
### Added
|
||||
|
||||
- **Rate Limit Handling**: Added proper handling of `RateLimitExceededException` with user-friendly messages showing retry wait time
|
||||
- **Signature Verification Error Handling**: Added dedicated handling for `SignatureException` when response signatures fail verification
|
||||
- **URL Validation Error Handling**: Added handling for `InvalidArgumentException` from SSRF protection in the license client
|
||||
|
||||
### Security
|
||||
|
||||
- Response signatures are now verified using HMAC-SHA256 with license-specific derived keys (RFC 5869 HKDF)
|
||||
- The license client now validates server URLs to prevent SSRF attacks (blocks private IP ranges)
|
||||
- HTTP connections require HTTPS unless explicitly allowed for localhost testing
|
||||
|
||||
### Technical Details
|
||||
|
||||
**License Client Upgrade**:
|
||||
|
||||
- Changed from `LicenseClient` to `SecureLicenseClient`
|
||||
- Added `serverSecret` parameter for signature verification
|
||||
- Library updated from `v0.1.0` to `dev-main` with new security features
|
||||
|
||||
**New Exception Handling**:
|
||||
|
||||
- `RateLimitExceededException` - shows retry time to user
|
||||
- `SignatureException` - indicates server secret mismatch
|
||||
- `InvalidArgumentException` - invalid/blocked URL detected
|
||||
|
||||
**New Settings Field**:
|
||||
|
||||
- `wc_tpp_license_server_secret` (password type) for the shared secret
|
||||
|
||||
---
|
||||
|
||||
## [1.3.0] - 2026-01-25
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- **PHP 8.3 Required**: Minimum PHP version increased from 7.4 to 8.3 to support modern dependencies and the license client library. Users on older PHP versions will see an admin notice and the plugin will not load.
|
||||
|
||||
### Added
|
||||
|
||||
- **License Management**: Integrated `magdev/wc-licensed-product-client` library for license validation and activation
|
||||
- New "License" settings tab for entering license server URL and license key
|
||||
- License validation and activation via AJAX with visual feedback
|
||||
- License status display showing active/inactive state, expiration date, and last check time
|
||||
- Cached license status with daily auto-refresh
|
||||
|
||||
- **Settings Page Sub-tabs**: Split the settings page into "General" and "License" tabs using modern WooCommerce patterns
|
||||
- Refactored to use `get_own_sections()` and `get_settings_for_{section}_section()` methods
|
||||
- Improved navigation and organization of settings
|
||||
|
||||
- **PHP Version Check**: Added runtime PHP version validation with admin notice for incompatible servers
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated composer.json to require PHP 8.3+ and added `magdev/wc-licensed-product-client` dependency
|
||||
- Settings class now uses modern WooCommerce settings API patterns
|
||||
|
||||
### Technical Details
|
||||
|
||||
**New Dependencies**:
|
||||
- `magdev/wc-licensed-product-client: ^0.1` (from private repository)
|
||||
- `symfony/http-client: ^7.0` (transitive)
|
||||
- `psr/log: ^3.0`, `psr/cache: ^3.0`, `psr/http-client: ^1.0` (transitive)
|
||||
|
||||
**License Client Integration**:
|
||||
- Uses `LicenseClient` class for API communication
|
||||
- AJAX endpoints: `wc_tpp_validate_license`, `wc_tpp_activate_license`
|
||||
- License status cached in WordPress transient (`wc_tpp_license_status`)
|
||||
|
||||
---
|
||||
|
||||
## [1.2.9] - 2025-12-30
|
||||
|
||||
### Fixed
|
||||
|
||||
563
CLAUDE.md
563
CLAUDE.md
@@ -1,7 +1,7 @@
|
||||
# WooCommerce Tier and Package Prices - AI Context Document
|
||||
|
||||
**Last Updated:** 2025-12-30
|
||||
**Current Version:** 1.2.9
|
||||
**Last Updated:** 2026-02-03
|
||||
**Current Version:** 1.4.1
|
||||
**Author:** Marco Graetsch
|
||||
**Project Status:** Production-ready WordPress plugin
|
||||
|
||||
@@ -16,9 +16,17 @@ This is a WooCommerce plugin that adds flexible pricing capabilities to products
|
||||
|
||||
This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase was created through AI assistance.
|
||||
|
||||
## Temporary Roadmap
|
||||
|
||||
**Note for AI Assistants:** Clean this section after the specific features are done or new releases are made. Effective changes are tracked in `CHANGELOG.md`. Do not add completed versions here - document them in the Session History section at the end of this file. Always keep the `Known Bugs` section and create a section with the next bugfix and minor version after a release.
|
||||
|
||||
### Version 1.4.2
|
||||
|
||||
- No planned features yet
|
||||
|
||||
## Technical Stack
|
||||
|
||||
- **Language:** PHP 7.4+
|
||||
- **Language:** PHP 8.3+
|
||||
- **Framework:** WordPress Plugin API
|
||||
- **E-commerce:** WooCommerce 8.0+ (tested up to 10.x)
|
||||
- **Template Engine:** Twig 3.0 (via Composer)
|
||||
@@ -32,8 +40,11 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w
|
||||
```json
|
||||
{
|
||||
"twig/twig": "^3.0",
|
||||
"symfony/polyfill-ctype": "^1.x",
|
||||
"symfony/polyfill-mbstring": "^1.x"
|
||||
"magdev/wc-licensed-product-client": "dev-main",
|
||||
"symfony/http-client": "^7.0",
|
||||
"psr/log": "^3.0",
|
||||
"psr/cache": "^3.0",
|
||||
"psr/http-client": "^1.0"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -44,6 +55,8 @@ This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase w
|
||||
```txt
|
||||
wc-tier-and-package-prices/
|
||||
├── wc-tier-and-package-prices.php # Main plugin file (entry point)
|
||||
├── .gitea/workflows/
|
||||
│ └── release.yml # CI/CD release pipeline
|
||||
├── includes/ # PHP classes
|
||||
│ ├── class-wc-tpp-admin.php # Admin settings integration
|
||||
│ ├── class-wc-tpp-settings.php # WooCommerce settings page
|
||||
@@ -70,7 +83,9 @@ wc-tier-and-package-prices/
|
||||
│ ├── *.pot # Translation template
|
||||
│ ├── *.po # Translation sources
|
||||
│ └── *.mo # Compiled translations
|
||||
├── vendor/ # Composer dependencies (included in releases)
|
||||
├── lib/ # Bundled libraries (git submodules)
|
||||
│ └── wc-licensed-product-client/ # License client library (v0.2.x)
|
||||
├── vendor/ # Composer dependencies (generated)
|
||||
├── releases/ # Release packages (not in git)
|
||||
└── *.md # Documentation files
|
||||
|
||||
@@ -342,137 +357,133 @@ Symptom: Help icon appearing far from label text at container edge
|
||||
|
||||
## Release Process
|
||||
|
||||
### Version Bumping
|
||||
### Automated CI/CD Pipeline (Recommended)
|
||||
|
||||
Update version in 3 places:
|
||||
Since v1.4.0, releases are automated via Gitea CI/CD. The pipeline is triggered when a version tag is pushed.
|
||||
|
||||
1. `wc-tier-and-package-prices.php` - Plugin header comment (line 7)
|
||||
2. `wc-tier-and-package-prices.php` - `WC_TPP_VERSION` constant (line 26)
|
||||
3. `composer.json` - version field (optional, not critical)
|
||||
|
||||
### Creating Release Package
|
||||
|
||||
**CRITICAL:** The zip command must be run from the **parent directory** of the plugin folder to create proper archive structure.
|
||||
**Workflow:**
|
||||
|
||||
```bash
|
||||
# From parent directory (/home/magdev/workspaces/php)
|
||||
cd /home/magdev/workspaces/php
|
||||
# 1. Update version in 3 places
|
||||
# - wc-tier-and-package-prices.php (header comment, line 7)
|
||||
# - wc-tier-and-package-prices.php (WC_TPP_VERSION constant)
|
||||
# - composer.json (version field)
|
||||
|
||||
# Create zip excluding dev files - note the correct path structure
|
||||
zip -r wc-tier-and-package-prices/releases/wc-tier-and-package-prices-X.X.X.zip wc-tier-and-package-prices/ \
|
||||
-x 'wc-tier-and-package-prices/.git*' \
|
||||
'wc-tier-and-package-prices/*.log' \
|
||||
'wc-tier-and-package-prices/.claude/*' \
|
||||
'wc-tier-and-package-prices/CLAUDE.md' \
|
||||
'wc-tier-and-package-prices/releases/*' \
|
||||
'wc-tier-and-package-prices/node_modules/*' \
|
||||
'wc-tier-and-package-prices/.DS_Store' \
|
||||
'wc-tier-and-package-prices/Thumbs.db' \
|
||||
'wc-tier-and-package-prices/.vscode/*' \
|
||||
'wc-tier-and-package-prices/.idea/*' \
|
||||
'wc-tier-and-package-prices/*.sublime-*' \
|
||||
'wc-tier-and-package-prices/notes.*' \
|
||||
'wc-tier-and-package-prices/logs/*' \
|
||||
'wc-tier-and-package-prices/templates/cache/*' \
|
||||
'wc-tier-and-package-prices/composer.lock'
|
||||
# 2. Update CHANGELOG.md with release notes
|
||||
|
||||
# Return to project directory
|
||||
cd wc-tier-and-package-prices
|
||||
# 3. Commit and push to dev
|
||||
git add -A && git commit -m "Version X.X.X - [description]
|
||||
|
||||
# Generate checksums
|
||||
cd releases
|
||||
md5sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.md5
|
||||
sha256sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.sha256
|
||||
cd ..
|
||||
```
|
||||
|
||||
**IMPORTANT NOTES:**
|
||||
|
||||
- The `vendor/` directory MUST be included in releases (Twig dependency required for runtime)
|
||||
- Running zip from wrong directory creates empty or malformed archives
|
||||
- Exclusion patterns must match the relative path structure used in zip command
|
||||
- Always verify the package with `unzip -l` and test extraction before committing
|
||||
|
||||
### Verification Steps
|
||||
|
||||
After creating the release package, always verify:
|
||||
|
||||
```bash
|
||||
# Check package size (should be ~400-450KB, NOT 8MB+ or near 0)
|
||||
ls -lh releases/wc-tier-and-package-prices-X.X.X.zip
|
||||
|
||||
# Verify exclusions worked
|
||||
unzip -l releases/wc-tier-and-package-prices-X.X.X.zip | grep -E "CLAUDE\.md|\.claude/|\.git" && echo "ERROR: Excluded files found!" || echo "OK: No excluded files"
|
||||
|
||||
# Test extraction
|
||||
cd /tmp && rm -rf test-extract && unzip -q /path/to/releases/wc-tier-and-package-prices-X.X.X.zip -d test-extract && ls -la test-extract/wc-tier-and-package-prices/
|
||||
|
||||
# Verify version in extracted package
|
||||
head -30 /tmp/test-extract/wc-tier-and-package-prices/wc-tier-and-package-prices.php | grep -E "Version:|WC_TPP_VERSION"
|
||||
|
||||
# Verify template changes (if applicable)
|
||||
grep 'class="regular"' /tmp/test-extract/wc-tier-and-package-prices/templates/admin/*.twig
|
||||
```
|
||||
|
||||
### Git Workflow for Releases
|
||||
|
||||
**Standard workflow:** Work on `dev` branch → merge to `main` → tag → push
|
||||
|
||||
```bash
|
||||
# 1. Ensure you're on dev branch with all changes committed
|
||||
git checkout dev
|
||||
git add [files]
|
||||
git commit -m "Release version X.X.X - [description]
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
|
||||
# 2. Merge dev to main
|
||||
git checkout main
|
||||
git merge dev --no-edit # Should be fast-forward
|
||||
|
||||
# 3. Create annotated tag
|
||||
git tag -a vX.X.X -m "Release version X.X.X - [description]"
|
||||
|
||||
# 4. Push everything
|
||||
git push origin main
|
||||
git push origin vX.X.X
|
||||
|
||||
# 5. Update dev and push
|
||||
git checkout dev
|
||||
git rebase main # Should be up-to-date already
|
||||
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>"
|
||||
git push origin dev
|
||||
|
||||
# 6. If you have uncommitted local changes (like .claude/settings.local.json)
|
||||
git stash push -m "Local development settings"
|
||||
# ... do git operations ...
|
||||
git stash pop
|
||||
# 4. Merge to main and push
|
||||
git checkout main && git merge dev --no-edit && git push origin main
|
||||
|
||||
# 5. Create and push tag (triggers CI/CD)
|
||||
git tag -a vX.X.X -m "Release version X.X.X - [description]"
|
||||
git push origin vX.X.X
|
||||
|
||||
# 6. Switch back to dev
|
||||
git checkout dev
|
||||
```
|
||||
|
||||
**Important Git Notes:**
|
||||
**What the CI/CD Pipeline Does:**
|
||||
|
||||
- Always commit from `dev` branch first
|
||||
- Tags should use format `vX.X.X` (e.g., `v1.1.22`)
|
||||
- Use annotated tags (`-a`) not lightweight tags
|
||||
- Commit messages should follow the established format with Claude Code attribution
|
||||
- `.claude/settings.local.json` changes are typically local-only (stash before rebasing)
|
||||
1. Checks out code with git submodules (`submodules: recursive`)
|
||||
2. Sets up PHP 8.3 with required extensions
|
||||
3. Validates `composer.json`
|
||||
4. Installs production Composer dependencies (`--no-dev`)
|
||||
5. Compiles translation files (.po → .mo)
|
||||
6. Validates plugin version matches tag version
|
||||
7. Creates release package with proper exclusions
|
||||
8. Generates SHA256 checksum
|
||||
9. Verifies package structure
|
||||
10. Extracts changelog notes for release description
|
||||
11. Creates Gitea release with assets
|
||||
|
||||
**Pipeline Location:** `.gitea/workflows/release.yml`
|
||||
|
||||
**Required Secret:** `SRC_GITEA_TOKEN` - Gitea API token for creating releases
|
||||
|
||||
### Git Submodule: wc-licensed-product-client
|
||||
|
||||
The `magdev/wc-licensed-product-client` library is bundled as a git submodule in `lib/` to avoid private repository authentication during CI/CD and to prevent conflicts with Composer's `vendor/` directory.
|
||||
|
||||
**Location:** `lib/wc-licensed-product-client/`
|
||||
|
||||
**Submodule URL:** Relative path `../wc-licensed-product-client.git` (works with Gitea CI/CD)
|
||||
|
||||
**Updating the submodule:**
|
||||
|
||||
```bash
|
||||
# Update to a specific tag
|
||||
cd lib/wc-licensed-product-client
|
||||
git fetch --tags
|
||||
git checkout v0.2.3 # or desired version
|
||||
cd ../..
|
||||
git add lib/wc-licensed-product-client
|
||||
git commit -m "Update wc-licensed-product-client to v0.2.3"
|
||||
```
|
||||
|
||||
**Composer Configuration:**
|
||||
|
||||
```json
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "lib/wc-licensed-product-client"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"magdev/wc-licensed-product-client": "^0.2"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Composer creates a symlink in `vendor/magdev/wc-licensed-product-client` pointing to `lib/wc-licensed-product-client`.
|
||||
|
||||
### Manual Release (Legacy)
|
||||
|
||||
For manual releases without CI/CD, run from the **parent directory**:
|
||||
|
||||
```bash
|
||||
cd /home/magdev/workspaces/php/wordpress/wp-content/plugins
|
||||
|
||||
zip -r wc-tier-and-package-prices/releases/wc-tier-and-package-prices-X.X.X.zip wc-tier-and-package-prices/ \
|
||||
-x 'wc-tier-and-package-prices/.git/*' \
|
||||
-x 'wc-tier-and-package-prices/.gitea/*' \
|
||||
-x 'wc-tier-and-package-prices/.claude/*' \
|
||||
-x 'wc-tier-and-package-prices/CLAUDE.md' \
|
||||
-x 'wc-tier-and-package-prices/releases/*' \
|
||||
-x 'wc-tier-and-package-prices/composer.lock' \
|
||||
-x 'wc-tier-and-package-prices/*.log' \
|
||||
-x 'wc-tier-and-package-prices/.gitignore' \
|
||||
-x 'wc-tier-and-package-prices/.gitmodules' \
|
||||
-x 'wc-tier-and-package-prices/vendor/*/.git/*' \
|
||||
-x '*.DS_Store'
|
||||
|
||||
cd wc-tier-and-package-prices/releases
|
||||
sha256sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.sha256
|
||||
```
|
||||
|
||||
### What Gets Released
|
||||
|
||||
- All plugin source files
|
||||
- Compiled vendor dependencies
|
||||
- Compiled vendor dependencies (including submodule)
|
||||
- Translation files (.mo compiled from .po)
|
||||
- Assets (CSS, JS)
|
||||
- Documentation (README, CHANGELOG, etc.)
|
||||
|
||||
### What's Excluded
|
||||
|
||||
- Git metadata (`.git/`)
|
||||
- Git metadata (`.git/`, `.gitmodules`)
|
||||
- CI/CD workflows (`.gitea/`)
|
||||
- Development files (`.vscode/`, `.claude/`, `CLAUDE.md`)
|
||||
- Logs and cache files
|
||||
- Previous releases
|
||||
- `composer.lock` (but `vendor/` is included)
|
||||
- `composer.lock`
|
||||
|
||||
## Testing Checklist
|
||||
|
||||
@@ -676,9 +687,10 @@ Based on v1.1.22, v1.2.2, and v1.2.3 release experience, here's the complete wor
|
||||
- `composer.json` - Version bump
|
||||
- `CHANGELOG.md` - Release notes
|
||||
- `CLAUDE.md` - Version and roadmap updates
|
||||
- `releases/wc-tier-and-package-prices-X.X.X.zip*` - Package and checksums
|
||||
- Feature-specific files (templates, PHP classes, etc.)
|
||||
|
||||
**Note:** Release packages (`releases/`) are not tracked in git - they are generated locally for distribution.
|
||||
|
||||
### Release Package Creation - Critical Notes
|
||||
|
||||
**IMPORTANT:** The zip command must be run from the **parent directory** to create proper archive structure.
|
||||
@@ -821,15 +833,15 @@ WooCommerce has different hooks for different product types in the admin product
|
||||
|
||||
**Lesson:** When adding admin UI for variable product parents, use `woocommerce_product_options_general_product_data` and check `$product->is_type('variable')` to conditionally display. Using `woocommerce_product_options_pricing` will cause forms to never appear for variable products (as discovered in v1.2.6 → v1.2.7 fix).
|
||||
|
||||
#### CRITICAL: Currency Symbol Display (Learned in v1.2.8)
|
||||
#### CRITICAL: Currency Symbol Display (Learned in v1.2.8, Corrected in v1.2.9)
|
||||
|
||||
When displaying currency symbols in admin interface table headers and input placeholders:
|
||||
|
||||
**Table Headers:**
|
||||
|
||||
```php
|
||||
// ✅ Correct - Use printf with translation and WooCommerce currency function
|
||||
<th><?php printf(__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
|
||||
// ✅ Correct - Use printf with esc_html__ for translation (CORRECTED in v1.2.9)
|
||||
<th><?php printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
|
||||
|
||||
// ❌ Wrong - Hard-coded or missing currency
|
||||
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th>
|
||||
@@ -839,8 +851,8 @@ When displaying currency symbols in admin interface table headers and input plac
|
||||
**Twig Template Placeholders:**
|
||||
|
||||
```twig
|
||||
{# ✅ Correct - Pass currency_symbol from PHP and concatenate in template #}
|
||||
placeholder="{{ ('e.g., 9.99 ' ~ currency_symbol)|__('wc-tier-package-prices') }}"
|
||||
{# ✅ Correct - Pass currency_symbol from PHP and concatenate (CORRECTED in v1.2.9 - no translation filter) #}
|
||||
placeholder="{{ 'e.g., 9.99 ' ~ currency_symbol }}"
|
||||
|
||||
{# ❌ Wrong - Hard-coded or missing currency #}
|
||||
placeholder="{{ 'e.g., 9.99'|__('wc-tier-package-prices') }}"
|
||||
@@ -917,6 +929,133 @@ if (isset($_POST['_wc_tpp_tiers'])) {
|
||||
|
||||
**Rule:** Always check `if (!empty($array))` before calling `update_post_meta()` for array data. If empty, call `delete_post_meta()` instead.
|
||||
|
||||
#### CRITICAL: WordPress Translation Functions with printf (Learned in v1.2.9)
|
||||
|
||||
When using `printf()` with WordPress translation functions, the text domain must be passed to the translation function, NOT to printf:
|
||||
|
||||
**Wrong Pattern:**
|
||||
|
||||
```php
|
||||
// ❌ WRONG - Text domain not passed to translation function
|
||||
printf(__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol());
|
||||
```
|
||||
|
||||
**Problem:** The `__()` function receives the text domain as a second parameter, but in this pattern it's missing. This causes the string "Price (%s)" to not be found in translation files, so it won't be translated.
|
||||
|
||||
**Correct Pattern:**
|
||||
|
||||
```php
|
||||
// ✅ CORRECT - Text domain in translation function, with esc_html for output escaping
|
||||
printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol());
|
||||
```
|
||||
|
||||
**Why This Works:**
|
||||
|
||||
- `esc_html__('Price (%s)', 'wc-tier-package-prices')` translates the string and returns it
|
||||
- `printf()` then substitutes the `%s` placeholder with the currency symbol
|
||||
- The translated string is used in the final output
|
||||
- `esc_html` ensures proper output escaping
|
||||
|
||||
**Applied in v1.2.9:** All 6 table headers in `includes/class-wc-tpp-product-meta.php`
|
||||
|
||||
#### CRITICAL: Twig Translation Filters and HTML Entity Encoding (Learned in v1.2.9)
|
||||
|
||||
When concatenating dynamic values in Twig templates, applying the translation filter can cause HTML entity encoding issues:
|
||||
|
||||
**Wrong Pattern:**
|
||||
|
||||
```twig
|
||||
{# ❌ WRONG - Translation filter encodes special characters in concatenated string #}
|
||||
placeholder="{{ ('e.g., 9.99 ' ~ currency_symbol)|__('wc-tier-package-prices') }}"
|
||||
```
|
||||
|
||||
**Problem:** When `currency_symbol` contains special characters (€, £, ¥, etc.), the concatenated string is passed through the translation function which treats it as a translatable string and encodes special characters as HTML entities (`€`, `£`, etc.).
|
||||
|
||||
**Correct Pattern:**
|
||||
|
||||
```twig
|
||||
{# ✅ CORRECT - No translation filter, just concatenation #}
|
||||
placeholder="{{ 'e.g., 9.99 ' ~ currency_symbol }}"
|
||||
```
|
||||
|
||||
**Why This Works:**
|
||||
|
||||
- Placeholder examples don't need translation - they're illustrative values
|
||||
- Direct concatenation preserves special characters
|
||||
- Currency symbol displays correctly (€ instead of €)
|
||||
|
||||
**Rule:** Only apply translation filters to static text that needs translation, not to concatenated strings with dynamic values that contain special characters.
|
||||
|
||||
**Applied in v1.2.9:**
|
||||
|
||||
- `templates/admin/tier-row.twig` - Price input placeholder
|
||||
- `templates/admin/package-row.twig` - Price input placeholder
|
||||
|
||||
#### CRITICAL: Defensive Programming for POST Data Processing (Learned in v1.2.9)
|
||||
|
||||
The v1.2.8 fix for variation pricing deletion had the right logic but used a branching structure that could miss edge cases. The v1.2.9 refactor demonstrates a more defensive pattern:
|
||||
|
||||
**Less Defensive Pattern (v1.2.8):**
|
||||
|
||||
```php
|
||||
// ❌ BRITTLE - Multiple branches, easy to miss edge cases
|
||||
if (isset($_POST['wc_tpp_tiers'][$loop])) {
|
||||
$tiers = array();
|
||||
foreach ($_POST['wc_tpp_tiers'][$loop] as $tier) {
|
||||
// ... populate tiers ...
|
||||
}
|
||||
if (!empty($tiers)) {
|
||||
update_post_meta($variation_id, '_wc_tpp_tiers', $tiers);
|
||||
} else {
|
||||
delete_post_meta($variation_id, '_wc_tpp_tiers');
|
||||
}
|
||||
} else {
|
||||
delete_post_meta($variation_id, '_wc_tpp_tiers');
|
||||
}
|
||||
```
|
||||
|
||||
**Problem:** Two separate code paths to `delete_post_meta()`. If logic changes, easy to update one path but forget the other.
|
||||
|
||||
**More Defensive Pattern (v1.2.9):**
|
||||
|
||||
```php
|
||||
// ✅ DEFENSIVE - Single decision point, guaranteed cleanup
|
||||
$tiers = array();
|
||||
if (isset($_POST['wc_tpp_tiers'][$loop]) && is_array($_POST['wc_tpp_tiers'][$loop])) {
|
||||
foreach ($_POST['wc_tpp_tiers'][$loop] as $tier) {
|
||||
// ... populate tiers ...
|
||||
}
|
||||
}
|
||||
// Always execute one of these based on final state
|
||||
if (!empty($tiers)) {
|
||||
update_post_meta($variation_id, '_wc_tpp_tiers', $tiers);
|
||||
} else {
|
||||
delete_post_meta($variation_id, '_wc_tpp_tiers');
|
||||
}
|
||||
```
|
||||
|
||||
**Why This Is Better:**
|
||||
|
||||
- Initialize array at the start (guaranteed initial state)
|
||||
- Single conditional for populating (with extra `is_array()` safety check)
|
||||
- Single decision point for save/delete (one place to maintain)
|
||||
- Impossible to have a code path that doesn't call either update or delete
|
||||
- Much easier to reason about and modify
|
||||
|
||||
**Key Principles:**
|
||||
|
||||
1. **Initialize variables early** - Establish known initial state
|
||||
2. **Minimize branching** - Fewer code paths = fewer bugs
|
||||
3. **Single decision point** - One place determines final action
|
||||
4. **Add safety checks** - Validate assumptions (`is_array()`)
|
||||
5. **Guaranteed execution** - Always perform one of update/delete, never neither
|
||||
|
||||
**Applied in v1.2.9:**
|
||||
|
||||
- `save_variation_pricing_fields()` - Both tier and package pricing logic refactored
|
||||
|
||||
**Rule:** When processing user input to decide between update and delete, prefer the pattern: initialize → conditionally populate → unconditionally act based on final state.
|
||||
|
||||
### When Adding Features
|
||||
|
||||
- Follow the existing pattern: add setting → add UI → add logic → add template
|
||||
@@ -963,8 +1102,8 @@ if (isset($_POST['_wc_tpp_tiers'])) {
|
||||
|
||||
### PHP
|
||||
|
||||
- Minimum: 7.4
|
||||
- Uses modern PHP features (type hints acceptable in new code)
|
||||
- Minimum: 8.3 (breaking change in v1.3.0)
|
||||
- Uses modern PHP features (type hints, named arguments, etc.)
|
||||
- Composer autoloader handles namespacing
|
||||
|
||||
### Browsers
|
||||
@@ -1000,4 +1139,188 @@ The plugin architecture is solid and well-tested. Most bugs arise from:
|
||||
|
||||
---
|
||||
|
||||
## Session History
|
||||
|
||||
### v1.3.0 Release Session (2026-01-25)
|
||||
|
||||
**Accomplished:**
|
||||
|
||||
1. Fixed known bugs from CLAUDE.md:
|
||||
- Removed all releases from git tracking (`git rm --cached -r releases/`)
|
||||
- Deleted all MD5 checksum files, keeping only SHA256
|
||||
- Updated `.gitignore` to exclude `/releases/`
|
||||
|
||||
2. Implemented v1.3.0 features:
|
||||
- Bumped PHP requirement from 7.4 to 8.3 (breaking change)
|
||||
- Added PHP version check with admin notice for incompatible servers
|
||||
- Added `magdev/wc-licensed-product-client` library integration
|
||||
- Refactored settings page to use WooCommerce modern sub-tabs pattern (`get_own_sections()`)
|
||||
- Created "General" and "License" sub-tabs
|
||||
- Implemented license management with AJAX validation/activation
|
||||
- Added license status caching via WordPress transients
|
||||
- Added CSS styling for license status display
|
||||
|
||||
3. Updated all translation files:
|
||||
- Added 28 new translation strings for license management
|
||||
- Updated .pot template and all 7 .po files
|
||||
- Compiled all .mo files
|
||||
|
||||
4. Created release package:
|
||||
- Package size: 737KB (increased due to new dependencies)
|
||||
- 642 files included (more due to license client library)
|
||||
- SHA256 checksum generated
|
||||
|
||||
**Key Learnings:**
|
||||
|
||||
- WooCommerce settings sub-tabs use `get_own_sections()` and `get_settings_for_{section}_section()` pattern
|
||||
- License client library `magdev/wc-licensed-product-client` is from private Gitea repo - requires `repositories` config in composer.json
|
||||
- Package version was `^0.1` not `^1.0` - always check available versions before setting constraint
|
||||
- Release package size increased from ~430KB to ~737KB due to new Composer dependencies
|
||||
|
||||
### v1.3.1 Release Session (2026-01-27)
|
||||
|
||||
**Accomplished:**
|
||||
|
||||
1. Reviewed server-implementation.md from license client library
|
||||
2. Upgraded from `LicenseClient` to `SecureLicenseClient`:
|
||||
- Added "Server Secret" configuration field in License settings tab
|
||||
- Updated `get_license_client()` to use `SecureLicenseClient` with HMAC-SHA256 signature verification
|
||||
- Updated JavaScript to pass `server_secret` in AJAX requests
|
||||
|
||||
3. Added comprehensive exception handling:
|
||||
- `RateLimitExceededException` - Shows retry time to user
|
||||
- `SignatureException` - Reports signature verification failures
|
||||
- `InvalidArgumentException` - SSRF protection for private IP blocking
|
||||
|
||||
4. Updated Composer dependencies:
|
||||
- Changed `magdev/wc-licensed-product-client` from `^0.1` to `dev-main`
|
||||
- Library includes new security features (SSRF protection, response signatures)
|
||||
|
||||
5. Updated translations:
|
||||
- Added 7 new translation strings for v1.3.1
|
||||
- All 7 language files updated and compiled
|
||||
|
||||
6. Created release package:
|
||||
- Package size: 775KB (after proper exclusions)
|
||||
- 650 files included
|
||||
- SHA256 checksum generated
|
||||
|
||||
7. Updated README.md:
|
||||
- Documented license management feature
|
||||
- Updated PHP requirement to 8.3
|
||||
- Added v1.3.0 and v1.3.1 changelog entries
|
||||
|
||||
8. Re-released v1.3.1:
|
||||
- Fixed release package exclusions (vendor .git dirs were included)
|
||||
- Added `.claude/settings.json` to .gitignore
|
||||
|
||||
**Key Learnings:**
|
||||
|
||||
- `SecureLicenseClient` requires `serverSecret` parameter for HMAC verification
|
||||
- The library's exception classes are in `Magdev\WcLicensedProductClient\Exception\` and `Magdev\WcLicensedProductClient\Security\` namespaces
|
||||
- `RateLimitExceededException` has a `retryAfter` property (int seconds)
|
||||
- Always check library documentation in `docs/server-implementation.md` for implementation requirements
|
||||
|
||||
**Release Package Learnings (CRITICAL):**
|
||||
|
||||
- Vendor directories installed via Composer (dev-main) contain their own `.git/` folders
|
||||
- Release exclusion patterns must include `'wc-tier-and-package-prices/vendor/*/.git/*'` and `'wc-tier-and-package-prices/vendor/*/CLAUDE.md'`
|
||||
- Run zip from `/home/magdev/workspaces/php/wordpress/wp-content/plugins/` (NOT `/home/magdev/workspaces/php/`)
|
||||
- Always verify exclusions with: `unzip -l package.zip | grep -E "\.git/|CLAUDE\.md"`
|
||||
|
||||
### v1.4.0 Release Session (2026-01-29)
|
||||
|
||||
**Accomplished:**
|
||||
|
||||
1. Created Gitea CI/CD release pipeline:
|
||||
- `.gitea/workflows/release.yml` - Automated release workflow
|
||||
- Triggers on version tags (`v*`)
|
||||
- Validates plugin version matches tag
|
||||
- Installs production Composer dependencies
|
||||
- Compiles translations (.po → .mo)
|
||||
- Creates release package with proper exclusions
|
||||
- Generates SHA256 checksum
|
||||
- Publishes release to Gitea with changelog notes
|
||||
|
||||
2. Added git submodule for license client:
|
||||
- Initially placed in `vendor/magdev/` - **FAILED** (Composer conflicts)
|
||||
- Fixed: Moved to `lib/wc-licensed-product-client/` like wp-fedistream
|
||||
- Uses relative URL `../wc-licensed-product-client.git`
|
||||
- Pinned to v0.2.2 tag
|
||||
- Avoids private repository authentication during CI/CD
|
||||
|
||||
3. Updated documentation:
|
||||
- README.md - Added CI/CD section, updated file structure
|
||||
- CLAUDE.md - Updated release process, added submodule docs
|
||||
|
||||
**Key Learnings:**
|
||||
|
||||
- **CRITICAL:** Git submodules should be in `lib/` NOT `vendor/` to avoid Composer conflicts
|
||||
- Composer manages `vendor/` directory - don't put submodules there
|
||||
- Use relative submodule URL (`../repo.git`) for Gitea CI/CD compatibility
|
||||
- Use version constraint `^0.2` instead of `@dev` for stability
|
||||
- Git submodules require `submodules: recursive` in checkout action
|
||||
- Composer creates symlink from `vendor/` to `lib/` automatically
|
||||
|
||||
**CI/CD Pipeline Notes:**
|
||||
|
||||
- Pipeline file: `.gitea/workflows/release.yml`
|
||||
- Required secret: `SRC_GITEA_TOKEN` for Gitea API access
|
||||
- Uses `shivammathur/setup-php@v2` for PHP setup
|
||||
- Uses `actions/checkout@v4` with `submodules: recursive`
|
||||
- Modeled after working wp-fedistream implementation
|
||||
|
||||
### v1.4.1 Release Session (2026-02-03)
|
||||
|
||||
**Accomplished:**
|
||||
|
||||
1. Implemented localhost license bypass:
|
||||
- Created `WC_TPP_License_Checker` class (singleton pattern)
|
||||
- `is_localhost()` detects localhost environments: localhost, 127.0.0.1, ::1, `*.localhost`, `*.local`, `*.test`, `*.example`, `*.invalid`, and private IP ranges
|
||||
- `is_self_licensing()` compares license server URL with site URL
|
||||
- `is_license_valid()` returns true for localhost/self-licensing without server check
|
||||
- Updated license status display to show bypass reason
|
||||
|
||||
2. Implemented auto-update system:
|
||||
- Created `WC_TPP_Update_Checker` class (singleton pattern)
|
||||
- Hooks into WordPress plugin update system (`pre_set_site_transient_update_plugins`, `plugins_api`, `http_request_args`, `auto_update_plugin`)
|
||||
- Fetches update info from license server API endpoint
|
||||
- Supports auto-install when WordPress performs background updates
|
||||
- Configurable check frequency (1-168 hours)
|
||||
|
||||
3. Added Auto-Updates settings tab:
|
||||
- Enable Update Notifications (checkbox, default: yes)
|
||||
- Automatically Install Updates (checkbox, default: no, requires valid license)
|
||||
- Check Frequency in Hours (number, default: 12)
|
||||
- Update Status display with "Check for Updates" button
|
||||
- AJAX handler for manual update checks
|
||||
|
||||
4. Updated all translation files:
|
||||
- Added 23 new translation strings for v1.4.1
|
||||
- All 7 language variants updated (de_DE, de_DE_informal, de_CH, de_CH_informal, fr_CH, it_CH, en_US)
|
||||
- Compiled all .mo files
|
||||
|
||||
**Key Implementation Details:**
|
||||
|
||||
- License checker uses 1-hour cache for successful validation, 5-minute cache for errors
|
||||
- Update checker respects `WC_TPP_DISABLE_AUTO_UPDATE` constant to disable updates
|
||||
- Update server endpoint: `POST /wp-json/wc-licensed-product/v1/update-check`
|
||||
- Both new classes are instantiated in main plugin's `includes()` method
|
||||
- Auto-install requires valid license (disabled when no license active)
|
||||
|
||||
**New Files:**
|
||||
|
||||
- `includes/class-wc-tpp-license-checker.php`
|
||||
- `includes/class-wc-tpp-update-checker.php`
|
||||
|
||||
**Modified Files:**
|
||||
|
||||
- `wc-tier-and-package-prices.php` - Version bump, include new classes
|
||||
- `includes/class-wc-tpp-settings.php` - Added Auto-Updates tab, updated license status display
|
||||
- All translation files (.pot, .po, .mo)
|
||||
- `CHANGELOG.md` - v1.4.1 release notes
|
||||
- `CLAUDE.md` - Updated version and session history
|
||||
|
||||
---
|
||||
|
||||
Always refer to this document when starting work on this project. Good luck!
|
||||
|
||||
77
README.md
77
README.md
@@ -20,10 +20,11 @@ A powerful WooCommerce plugin that adds tier pricing and package pricing functio
|
||||
|
||||
### Admin Features
|
||||
- Easy-to-use product meta boxes for adding tiers and packages
|
||||
- Global settings page under WooCommerce menu
|
||||
- Global settings page under WooCommerce menu with sub-tabs
|
||||
- Configure display position (before/after add to cart, after price)
|
||||
- Enable/disable tier or package pricing independently
|
||||
- Sortable pricing rules
|
||||
- License management with secure HMAC signature verification
|
||||
|
||||
### Frontend Features
|
||||
- Beautiful pricing tables on product pages
|
||||
@@ -39,6 +40,20 @@ A powerful WooCommerce plugin that adds tier pricing and package pricing functio
|
||||
2. Activate the plugin through the 'Plugins' menu in WordPress
|
||||
3. Make sure WooCommerce is installed and activated
|
||||
|
||||
### Automated Releases
|
||||
|
||||
This project uses a Gitea CI/CD pipeline for automated releases. When a version tag (e.g., `v1.4.0`) is pushed:
|
||||
|
||||
1. Code is checked out with git submodules (dependencies bundled)
|
||||
2. The pipeline validates the plugin version matches the tag
|
||||
3. Composer dependencies are installed (production only)
|
||||
4. Translation files are compiled (.po → .mo)
|
||||
5. A release package is created with proper exclusions
|
||||
6. SHA256 checksum is generated
|
||||
7. Release is published to Gitea with changelog notes extracted from CHANGELOG.md
|
||||
|
||||
The `magdev/wc-licensed-product-client` library is bundled as a git submodule to avoid private repository authentication during CI/CD.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Global Settings
|
||||
@@ -110,7 +125,9 @@ When editing a product, scroll to the **Product data** panel:
|
||||
|
||||
```
|
||||
wc-tier-and-package-prices/
|
||||
├── wc-tier-and-package-prices.php # Main plugin file (v1.1.20)
|
||||
├── wc-tier-and-package-prices.php # Main plugin file (v1.4.0)
|
||||
├── .gitea/workflows/
|
||||
│ └── release.yml # CI/CD release pipeline
|
||||
├── includes/
|
||||
│ ├── class-wc-tpp-admin.php # Admin settings integration
|
||||
│ ├── class-wc-tpp-settings.php # WooCommerce settings page
|
||||
@@ -137,7 +154,9 @@ wc-tier-and-package-prices/
|
||||
│ ├── wc-tier-package-prices.pot # Translation template
|
||||
│ ├── wc-tier-package-prices-*.po # Translation sources
|
||||
│ └── wc-tier-package-prices-*.mo # Compiled translations
|
||||
├── vendor/ # Composer dependencies (Twig)
|
||||
├── lib/ # Bundled libraries (git submodules)
|
||||
│ └── wc-licensed-product-client/ # License client library
|
||||
├── vendor/ # Composer dependencies (generated)
|
||||
├── CHANGELOG.md # Complete version history
|
||||
├── INSTALLATION.md # Installation guide
|
||||
├── QUICKSTART.md # Quick start guide
|
||||
@@ -149,7 +168,7 @@ wc-tier-and-package-prices/
|
||||
|
||||
- WordPress 6.0 or higher (tested up to 6.9.x)
|
||||
- WooCommerce 8.0 or higher (tested up to 10.x)
|
||||
- PHP 7.4 or higher
|
||||
- PHP 8.3 or higher (required since v1.3.0)
|
||||
|
||||
### Compatibility
|
||||
|
||||
@@ -183,9 +202,39 @@ This plugin is licensed under the GPL v2 or later.
|
||||
|
||||
## Changelog
|
||||
|
||||
### Version 1.4.0 - 2026-01-29
|
||||
|
||||
__Current Release__ - CI/CD Release Pipeline
|
||||
|
||||
- __New__: Gitea CI/CD release pipeline for automated builds and releases
|
||||
- __New__: Git submodule for `magdev/wc-licensed-product-client` library
|
||||
- __Changed__: Composer now uses path repository for bundled license client
|
||||
- __DevOps__: Automated version validation, translation compilation, and release publishing
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for complete details.
|
||||
|
||||
### Version 1.3.1 - 2026-01-27
|
||||
|
||||
Secure License Client
|
||||
|
||||
- __Changed__: Switched to `SecureLicenseClient` with HMAC-SHA256 response signature verification
|
||||
- __New__: Server Secret configuration field for secure communication with license server
|
||||
- __Security__: Response signatures verified using HMAC-SHA256 with license-specific derived keys
|
||||
|
||||
### Version 1.3.0 - 2026-01-25
|
||||
|
||||
__Breaking Changes__ - PHP 8.3+ Required
|
||||
|
||||
- __Breaking__: Minimum PHP version increased from 7.4 to 8.3
|
||||
- __New__: License management via `magdev/wc-licensed-product-client` library
|
||||
- __New__: Settings page split into "General" and "License" sub-tabs
|
||||
- __New__: AJAX-based license validation and activation with visual feedback
|
||||
- __New__: License status caching with daily auto-refresh
|
||||
- __New__: PHP version check with admin notice for incompatible servers
|
||||
|
||||
### Version 1.2.0 - 2025-12-29
|
||||
|
||||
__Current Release__ - Variable Product Support
|
||||
Variable Product Support
|
||||
|
||||
- __New__: Full support for WooCommerce variable products with variation-level pricing
|
||||
- __New__: Each variation can have independent tier and package pricing configuration
|
||||
@@ -194,24 +243,6 @@ __Current Release__ - Variable Product Support
|
||||
- __Fixed__: Quantity restrictions now work correctly per-variation
|
||||
- 100% backward compatible - no breaking changes
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md) for complete details.
|
||||
|
||||
### Version 1.1.22 - 2025-12-23
|
||||
|
||||
- Increased width of label input fields in admin interface
|
||||
|
||||
#### Fixed
|
||||
- **CRITICAL:** WooCommerce Blocks fatal error in mini-cart and cart blocks
|
||||
- Fixed `woocommerce_store_api_product_quantity_editable` filter signature mismatch
|
||||
- Filter now correctly accepts `WC_Product` object instead of cart item array
|
||||
- Resolves "Cannot use object of type WC_Product_Simple as array" fatal error
|
||||
|
||||
#### Technical Details
|
||||
- Updated `block_quantity_editable()` method signature to accept product object
|
||||
- Changed parameter from `$cart_item` array to `WC_Product $product`
|
||||
- Uses `$product->get_id()` instead of array access for product ID
|
||||
- Full compatibility with WooCommerce Store API and block-based cart/checkout
|
||||
|
||||
### Recent Major Updates
|
||||
|
||||
#### Version 1.1.7 - Enhanced Tier Pricing
|
||||
|
||||
@@ -154,3 +154,52 @@ label[for^="wc_tpp_restrict_to_packages_"] {
|
||||
input[id^="wc_tpp_restrict_to_packages_"] + .description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* License Status Styling */
|
||||
.wc-tpp-license-active {
|
||||
color: #46b450;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wc-tpp-license-inactive {
|
||||
color: #dc3232;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wc-tpp-license-expired {
|
||||
color: #ffb900;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#wc-tpp-license-spinner {
|
||||
float: none;
|
||||
margin-top: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
#wc-tpp-validate-license,
|
||||
#wc-tpp-activate-license {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
#wc-tpp-license-status-container {
|
||||
margin-bottom: 10px;
|
||||
padding: 10px 15px;
|
||||
background: #f9f9f9;
|
||||
border-left: 4px solid #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
#wc-tpp-license-status-container.valid {
|
||||
border-left-color: #46b450;
|
||||
background: #f0fff0;
|
||||
}
|
||||
|
||||
#wc-tpp-license-status-container.invalid {
|
||||
border-left-color: #dc3232;
|
||||
background: #fff0f0;
|
||||
}
|
||||
|
||||
#wc-tpp-license-status-container small {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
{
|
||||
"name": "magdev/wc-tier-package-prices",
|
||||
"description": "WooCommerce plugin for tier pricing and package prices with Twig templates",
|
||||
"version": "1.2.9",
|
||||
"type": "wordpress-plugin",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"authors": [
|
||||
@@ -10,13 +9,28 @@
|
||||
"homepage": "https://src.bundespruefstelle.ch/magdev"
|
||||
}
|
||||
],
|
||||
"repositories": [
|
||||
{
|
||||
"type": "path",
|
||||
"url": "lib/wc-licensed-product-client"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"twig/twig": "^3.0"
|
||||
"php": ">=8.3",
|
||||
"twig/twig": "^3.0",
|
||||
"magdev/wc-licensed-product-client": "^0.2"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"includes/"
|
||||
]
|
||||
},
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"platform": {
|
||||
"php": "8.3.0"
|
||||
}
|
||||
},
|
||||
"minimum-stability": "stable",
|
||||
"prefer-stable": true
|
||||
}
|
||||
|
||||
333
includes/class-wc-tpp-license-checker.php
Normal file
333
includes/class-wc-tpp-license-checker.php
Normal file
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
/**
|
||||
* License Checker
|
||||
*
|
||||
* Handles license validation with localhost and self-licensing bypass
|
||||
*
|
||||
* @package WC_Tier_Package_Prices
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_TPP_License_Checker class
|
||||
*/
|
||||
if (!class_exists('WC_TPP_License_Checker')) {
|
||||
class WC_TPP_License_Checker {
|
||||
|
||||
/**
|
||||
* Singleton instance
|
||||
*
|
||||
* @var WC_TPP_License_Checker|null
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Cache key for license status
|
||||
*/
|
||||
private const CACHE_KEY = 'wc_tpp_license_status';
|
||||
|
||||
/**
|
||||
* Cache TTL for successful validation (1 hour)
|
||||
*/
|
||||
private const CACHE_TTL_SUCCESS = 3600;
|
||||
|
||||
/**
|
||||
* Cache TTL for failed validation (5 minutes)
|
||||
*/
|
||||
private const CACHE_TTL_ERROR = 300;
|
||||
|
||||
/**
|
||||
* Localhost patterns
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private const LOCALHOST_HOSTS = ['localhost', '127.0.0.1', '::1'];
|
||||
|
||||
/**
|
||||
* Localhost TLDs
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private const LOCALHOST_TLDS = ['.localhost', '.local', '.test', '.example', '.invalid'];
|
||||
|
||||
/**
|
||||
* Get singleton instance
|
||||
*
|
||||
* @return WC_TPP_License_Checker
|
||||
*/
|
||||
public static function get_instance(): WC_TPP_License_Checker {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private function __construct() {
|
||||
// Clear cache when license settings change
|
||||
add_action('update_option_wc_tpp_license_key', array($this, 'clear_cache'));
|
||||
add_action('update_option_wc_tpp_license_server_url', array($this, 'clear_cache'));
|
||||
add_action('update_option_wc_tpp_license_server_secret', array($this, 'clear_cache'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current environment is localhost
|
||||
*
|
||||
* Matches patterns:
|
||||
* - localhost
|
||||
* - 127.0.0.1
|
||||
* - ::1 (IPv6 localhost)
|
||||
* - *.localhost (subdomains)
|
||||
* - *.local (subdomains)
|
||||
* - *.test (RFC 2606)
|
||||
* - *.example (RFC 2606)
|
||||
* - *.invalid (RFC 2606)
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_localhost(): bool {
|
||||
$domain = $this->get_current_domain();
|
||||
|
||||
// Remove port number if present
|
||||
$domain = preg_replace('/:[\d]+$/', '', $domain);
|
||||
$domain = strtolower($domain);
|
||||
|
||||
// Check exact matches
|
||||
if (in_array($domain, self::LOCALHOST_HOSTS, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check TLD patterns
|
||||
foreach (self::LOCALHOST_TLDS as $tld) {
|
||||
if (str_ends_with($domain, $tld)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for private IP ranges (Docker, VMs, etc.)
|
||||
if ($this->is_private_ip($domain)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if domain is a private IP address
|
||||
*
|
||||
* @param string $domain The domain to check.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_private_ip(string $domain): bool {
|
||||
// Check if it's a valid IP first
|
||||
if (!filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check for private/reserved ranges
|
||||
return !filter_var(
|
||||
$domain,
|
||||
FILTER_VALIDATE_IP,
|
||||
FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current site is self-licensing
|
||||
*
|
||||
* Returns true if the license server URL and site URL are on the same domain.
|
||||
* This allows the license server itself to use the plugin without a license.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_self_licensing(): bool {
|
||||
$server_url = get_option('wc_tpp_license_server_url', '');
|
||||
|
||||
if (empty($server_url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$server_domain = $this->normalize_domain($server_url);
|
||||
$site_domain = $this->normalize_domain(get_site_url());
|
||||
|
||||
return $server_domain === $site_domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a URL to its domain
|
||||
*
|
||||
* @param string $url The URL to normalize.
|
||||
* @return string
|
||||
*/
|
||||
private function normalize_domain(string $url): string {
|
||||
$parsed = wp_parse_url($url);
|
||||
$host = $parsed['host'] ?? '';
|
||||
|
||||
// Convert to lowercase
|
||||
$host = strtolower($host);
|
||||
|
||||
// Remove www. prefix
|
||||
$host = preg_replace('/^www\./', '', $host);
|
||||
|
||||
return $host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current domain from site URL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_current_domain(): string {
|
||||
$site_url = get_site_url();
|
||||
$parsed = wp_parse_url($site_url);
|
||||
$host = $parsed['host'] ?? 'localhost';
|
||||
|
||||
// Include port if non-standard
|
||||
if (isset($parsed['port'])) {
|
||||
$host .= ':' . $parsed['port'];
|
||||
}
|
||||
|
||||
return strtolower($host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the license is valid
|
||||
*
|
||||
* This is the main entry point for license validation.
|
||||
* It implements the bypass logic for localhost and self-licensing.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_license_valid(): bool {
|
||||
// Always valid on localhost
|
||||
if ($this->is_localhost()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Always valid for self-licensing
|
||||
if ($this->is_self_licensing()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check cached status
|
||||
$cached = $this->get_cached_status();
|
||||
if (false !== $cached) {
|
||||
return !empty($cached['valid']);
|
||||
}
|
||||
|
||||
// Validate against server
|
||||
return $this->validate_license();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the license bypass reason if applicable
|
||||
*
|
||||
* @return string|null 'localhost', 'self_licensing', or null
|
||||
*/
|
||||
public function get_bypass_reason(): ?string {
|
||||
if ($this->is_localhost()) {
|
||||
return 'localhost';
|
||||
}
|
||||
|
||||
if ($this->is_self_licensing()) {
|
||||
return 'self_licensing';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached license status
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
public function get_cached_status() {
|
||||
return get_transient(self::CACHE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate license against the server
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validate_license(): bool {
|
||||
$license_key = get_option('wc_tpp_license_key', '');
|
||||
$server_url = get_option('wc_tpp_license_server_url', '');
|
||||
$server_secret = get_option('wc_tpp_license_server_secret', '');
|
||||
|
||||
// Can't validate without credentials
|
||||
if (empty($license_key) || empty($server_url) || empty($server_secret)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->get_license_client($server_url, $server_secret);
|
||||
$domain = $this->get_current_domain();
|
||||
|
||||
// Remove port for validation
|
||||
$domain = preg_replace('/:[\d]+$/', '', $domain);
|
||||
|
||||
$result = $client->validate($license_key, $domain);
|
||||
|
||||
// Cache successful validation
|
||||
set_transient(self::CACHE_KEY, array(
|
||||
'valid' => true,
|
||||
'product_id' => $result->productId,
|
||||
'expires_at' => $result->expiresAt?->format('Y-m-d H:i:s'),
|
||||
'is_lifetime' => $result->isLifetime(),
|
||||
'checked_at' => current_time('mysql'),
|
||||
), self::CACHE_TTL_SUCCESS);
|
||||
|
||||
return true;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Cache validation failure
|
||||
set_transient(self::CACHE_KEY, array(
|
||||
'valid' => false,
|
||||
'error' => $e->getMessage(),
|
||||
'checked_at' => current_time('mysql'),
|
||||
), self::CACHE_TTL_ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get license client instance
|
||||
*
|
||||
* @param string $server_url License server URL.
|
||||
* @param string $server_secret Shared secret for signature verification.
|
||||
* @return \Magdev\WcLicensedProductClient\LicenseClientInterface
|
||||
*/
|
||||
private function get_license_client(string $server_url, string $server_secret): \Magdev\WcLicensedProductClient\LicenseClientInterface {
|
||||
$httpClient = \Symfony\Component\HttpClient\HttpClient::create();
|
||||
return new \Magdev\WcLicensedProductClient\SecureLicenseClient(
|
||||
httpClient: $httpClient,
|
||||
baseUrl: $server_url,
|
||||
serverSecret: $server_secret,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the license cache
|
||||
*/
|
||||
public function clear_cache(): void {
|
||||
delete_transient(self::CACHE_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force revalidation of the license
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function revalidate(): bool {
|
||||
$this->clear_cache();
|
||||
return $this->is_license_valid();
|
||||
}
|
||||
}
|
||||
}
|
||||
647
includes/class-wc-tpp-settings.php
Normal file → Executable file
647
includes/class-wc-tpp-settings.php
Normal file → Executable file
@@ -2,7 +2,7 @@
|
||||
/**
|
||||
* WooCommerce Settings Integration
|
||||
*
|
||||
* Adds Tier & Package Prices settings to WooCommerce Settings > Advanced tab
|
||||
* Adds Tier & Package Prices settings to WooCommerce Settings with sub-tabs
|
||||
*
|
||||
* @package WC_Tier_Package_Prices
|
||||
*/
|
||||
@@ -29,32 +29,35 @@ if (!class_exists('WC_TPP_Settings')) {
|
||||
$this->label = __('Tier & Package Prices', 'wc-tier-package-prices');
|
||||
|
||||
parent::__construct();
|
||||
|
||||
// Add AJAX handlers for license validation
|
||||
add_action('wp_ajax_wc_tpp_validate_license', array($this, 'ajax_validate_license'));
|
||||
add_action('wp_ajax_wc_tpp_activate_license', array($this, 'ajax_activate_license'));
|
||||
|
||||
// Add AJAX handler for update checks
|
||||
add_action('wp_ajax_wc_tpp_check_updates', array($this, 'ajax_check_updates'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get sections
|
||||
* Get own sections - Modern WooCommerce pattern
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_sections() {
|
||||
$sections = array(
|
||||
protected function get_own_sections() {
|
||||
return array(
|
||||
'' => __('General', 'wc-tier-package-prices'),
|
||||
'license' => __('License', 'wc-tier-package-prices'),
|
||||
'updates' => __('Auto-Updates', 'wc-tier-package-prices'),
|
||||
);
|
||||
|
||||
return apply_filters('woocommerce_get_sections_' . $this->id, $sections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get settings array
|
||||
* Get settings for the default (General) section
|
||||
*
|
||||
* @param string $current_section Current section name.
|
||||
* @return array
|
||||
*/
|
||||
public function get_settings($current_section = '') {
|
||||
$settings = array();
|
||||
|
||||
if ('' === $current_section) {
|
||||
$settings = array(
|
||||
protected function get_settings_for_default_section() {
|
||||
return array(
|
||||
array(
|
||||
'title' => __('Tier & Package Prices Settings', 'wc-tier-package-prices'),
|
||||
'type' => 'title',
|
||||
@@ -121,23 +124,625 @@ if (!class_exists('WC_TPP_Settings')) {
|
||||
);
|
||||
}
|
||||
|
||||
return apply_filters('woocommerce_get_settings_' . $this->id, $settings, $current_section);
|
||||
/**
|
||||
* Get settings for the License section
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_settings_for_license_section() {
|
||||
return array(
|
||||
array(
|
||||
'title' => __('License Management', 'wc-tier-package-prices'),
|
||||
'type' => 'title',
|
||||
'desc' => __('Enter your license key to receive updates and support.', 'wc-tier-package-prices'),
|
||||
'id' => 'wc_tpp_license_settings',
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('License Server URL', 'wc-tier-package-prices'),
|
||||
'desc' => __('The URL of the license server.', 'wc-tier-package-prices'),
|
||||
'id' => 'wc_tpp_license_server_url',
|
||||
'type' => 'url',
|
||||
'default' => '',
|
||||
'css' => 'min-width:400px;',
|
||||
'desc_tip' => true,
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('License Key', 'wc-tier-package-prices'),
|
||||
'desc' => __('Your license key for this plugin.', 'wc-tier-package-prices'),
|
||||
'id' => 'wc_tpp_license_key',
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
'css' => 'min-width:400px;',
|
||||
'desc_tip' => true,
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('Server Secret', 'wc-tier-package-prices'),
|
||||
'desc' => __('The shared secret for secure communication with the license server.', 'wc-tier-package-prices'),
|
||||
'id' => 'wc_tpp_license_server_secret',
|
||||
'type' => 'password',
|
||||
'default' => '',
|
||||
'css' => 'min-width:400px;',
|
||||
'desc_tip' => true,
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('License Status', 'wc-tier-package-prices'),
|
||||
'type' => 'wc_tpp_license_status',
|
||||
'id' => 'wc_tpp_license_status_display',
|
||||
),
|
||||
|
||||
array(
|
||||
'type' => 'sectionend',
|
||||
'id' => 'wc_tpp_license_settings',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get settings for the Auto-Updates section
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_settings_for_updates_section() {
|
||||
// Check if auto-install is available (requires valid license or bypass)
|
||||
$license_checker = WC_TPP_License_Checker::get_instance();
|
||||
$auto_install_disabled = !$license_checker->is_license_valid();
|
||||
$auto_install_desc = __('Automatically install updates when available.', 'wc-tier-package-prices');
|
||||
|
||||
if ($auto_install_disabled) {
|
||||
$auto_install_desc .= ' ' . __('(Requires a valid license)', 'wc-tier-package-prices');
|
||||
}
|
||||
|
||||
return array(
|
||||
array(
|
||||
'title' => __('Auto-Update Settings', 'wc-tier-package-prices'),
|
||||
'type' => 'title',
|
||||
'desc' => __('Configure automatic plugin updates from the license server.', 'wc-tier-package-prices'),
|
||||
'id' => 'wc_tpp_update_settings',
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('Enable Update Notifications', 'wc-tier-package-prices'),
|
||||
'desc' => __('Check for available plugin updates.', 'wc-tier-package-prices'),
|
||||
'id' => 'wc_tpp_update_notification_enabled',
|
||||
'default' => 'yes',
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => __('When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin.', 'wc-tier-package-prices'),
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('Automatically Install Updates', 'wc-tier-package-prices'),
|
||||
'desc' => $auto_install_desc,
|
||||
'id' => 'wc_tpp_auto_install_enabled',
|
||||
'default' => 'no',
|
||||
'type' => 'checkbox',
|
||||
'desc_tip' => __('When enabled, updates will be automatically installed when WordPress performs background updates.', 'wc-tier-package-prices'),
|
||||
'custom_attributes' => $auto_install_disabled ? array('disabled' => 'disabled') : array(),
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('Check Frequency (Hours)', 'wc-tier-package-prices'),
|
||||
'desc' => __('How often to check for updates.', 'wc-tier-package-prices'),
|
||||
'id' => 'wc_tpp_update_check_frequency',
|
||||
'default' => '12',
|
||||
'type' => 'number',
|
||||
'css' => 'width: 80px;',
|
||||
'desc_tip' => __('Number of hours between update checks. Default is 12 hours.', 'wc-tier-package-prices'),
|
||||
'custom_attributes' => array(
|
||||
'min' => '1',
|
||||
'max' => '168',
|
||||
),
|
||||
),
|
||||
|
||||
array(
|
||||
'title' => __('Update Status', 'wc-tier-package-prices'),
|
||||
'type' => 'wc_tpp_update_status',
|
||||
'id' => 'wc_tpp_update_status_display',
|
||||
),
|
||||
|
||||
array(
|
||||
'type' => 'sectionend',
|
||||
'id' => 'wc_tpp_update_settings',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cached license status
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
private function get_cached_license_status() {
|
||||
return get_transient('wc_tpp_license_status');
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for license validation
|
||||
*/
|
||||
public function ajax_validate_license() {
|
||||
check_ajax_referer('wc_tpp_license_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_woocommerce')) {
|
||||
wp_send_json_error(array('message' => __('Permission denied.', 'wc-tier-package-prices')));
|
||||
}
|
||||
|
||||
$license_key = sanitize_text_field(wp_unslash($_POST['license_key'] ?? ''));
|
||||
$server_url = esc_url_raw(wp_unslash($_POST['server_url'] ?? ''));
|
||||
$server_secret = sanitize_text_field(wp_unslash($_POST['server_secret'] ?? ''));
|
||||
|
||||
if (empty($license_key) || empty($server_url) || empty($server_secret)) {
|
||||
wp_send_json_error(array('message' => __('License key, server URL, and server secret are required.', 'wc-tier-package-prices')));
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->get_license_client($server_url, $server_secret);
|
||||
$domain = $this->get_current_domain();
|
||||
$result = $client->validate($license_key, $domain);
|
||||
|
||||
// Cache the status
|
||||
set_transient('wc_tpp_license_status', array(
|
||||
'valid' => true,
|
||||
'product_id' => $result->productId,
|
||||
'expires_at' => $result->expiresAt?->format('Y-m-d H:i:s'),
|
||||
'is_lifetime' => $result->isLifetime(),
|
||||
'checked_at' => current_time('mysql'),
|
||||
), DAY_IN_SECONDS);
|
||||
|
||||
wp_send_json_success(array(
|
||||
'message' => __('License is valid!', 'wc-tier-package-prices'),
|
||||
'status' => $this->get_cached_license_status(),
|
||||
));
|
||||
|
||||
} catch (\Magdev\WcLicensedProductClient\Exception\RateLimitExceededException $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => sprintf(
|
||||
/* translators: %d: Number of seconds to wait */
|
||||
__('Rate limit exceeded. Please try again in %d seconds.', 'wc-tier-package-prices'),
|
||||
$e->retryAfter ?? 60
|
||||
),
|
||||
'code' => 'rate_limit_exceeded',
|
||||
'retry_after' => $e->retryAfter,
|
||||
));
|
||||
} catch (\Magdev\WcLicensedProductClient\Security\SignatureException $e) {
|
||||
delete_transient('wc_tpp_license_status');
|
||||
wp_send_json_error(array(
|
||||
'message' => __('Response signature verification failed. Please check your server secret.', 'wc-tier-package-prices'),
|
||||
'code' => 'signature_error',
|
||||
));
|
||||
} catch (\Magdev\WcLicensedProductClient\Exception\LicenseException $e) {
|
||||
delete_transient('wc_tpp_license_status');
|
||||
wp_send_json_error(array(
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->errorCode ?? 'unknown',
|
||||
));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 'invalid_url',
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
delete_transient('wc_tpp_license_status');
|
||||
wp_send_json_error(array(
|
||||
'message' => __('An unexpected error occurred. Please try again.', 'wc-tier-package-prices'),
|
||||
'code' => 'exception',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for license activation
|
||||
*/
|
||||
public function ajax_activate_license() {
|
||||
check_ajax_referer('wc_tpp_license_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_woocommerce')) {
|
||||
wp_send_json_error(array('message' => __('Permission denied.', 'wc-tier-package-prices')));
|
||||
}
|
||||
|
||||
$license_key = sanitize_text_field(wp_unslash($_POST['license_key'] ?? ''));
|
||||
$server_url = esc_url_raw(wp_unslash($_POST['server_url'] ?? ''));
|
||||
$server_secret = sanitize_text_field(wp_unslash($_POST['server_secret'] ?? ''));
|
||||
|
||||
if (empty($license_key) || empty($server_url) || empty($server_secret)) {
|
||||
wp_send_json_error(array('message' => __('License key, server URL, and server secret are required.', 'wc-tier-package-prices')));
|
||||
}
|
||||
|
||||
try {
|
||||
$client = $this->get_license_client($server_url, $server_secret);
|
||||
$domain = $this->get_current_domain();
|
||||
$result = $client->activate($license_key, $domain);
|
||||
|
||||
if ($result->success) {
|
||||
// Validate to get full status after activation
|
||||
$validate_result = $client->validate($license_key, $domain);
|
||||
|
||||
set_transient('wc_tpp_license_status', array(
|
||||
'valid' => true,
|
||||
'product_id' => $validate_result->productId,
|
||||
'expires_at' => $validate_result->expiresAt?->format('Y-m-d H:i:s'),
|
||||
'is_lifetime' => $validate_result->isLifetime(),
|
||||
'checked_at' => current_time('mysql'),
|
||||
), DAY_IN_SECONDS);
|
||||
|
||||
wp_send_json_success(array(
|
||||
'message' => __('License activated successfully!', 'wc-tier-package-prices'),
|
||||
'status' => $this->get_cached_license_status(),
|
||||
));
|
||||
}
|
||||
|
||||
wp_send_json_error(array('message' => $result->message));
|
||||
|
||||
} catch (\Magdev\WcLicensedProductClient\Exception\RateLimitExceededException $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => sprintf(
|
||||
/* translators: %d: Number of seconds to wait */
|
||||
__('Rate limit exceeded. Please try again in %d seconds.', 'wc-tier-package-prices'),
|
||||
$e->retryAfter ?? 60
|
||||
),
|
||||
'code' => 'rate_limit_exceeded',
|
||||
'retry_after' => $e->retryAfter,
|
||||
));
|
||||
} catch (\Magdev\WcLicensedProductClient\Security\SignatureException $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => __('Response signature verification failed. Please check your server secret.', 'wc-tier-package-prices'),
|
||||
'code' => 'signature_error',
|
||||
));
|
||||
} catch (\Magdev\WcLicensedProductClient\Exception\LicenseException $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->errorCode ?? 'unknown',
|
||||
));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => $e->getMessage(),
|
||||
'code' => 'invalid_url',
|
||||
));
|
||||
} catch (\Exception $e) {
|
||||
wp_send_json_error(array(
|
||||
'message' => __('An unexpected error occurred. Please try again.', 'wc-tier-package-prices'),
|
||||
'code' => 'exception',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get license client instance
|
||||
*
|
||||
* Uses SecureLicenseClient for HMAC signature verification.
|
||||
*
|
||||
* @param string $server_url License server URL.
|
||||
* @param string $server_secret Shared secret for signature verification.
|
||||
* @return \Magdev\WcLicensedProductClient\LicenseClientInterface
|
||||
*/
|
||||
private function get_license_client(string $server_url, string $server_secret): \Magdev\WcLicensedProductClient\LicenseClientInterface {
|
||||
$httpClient = \Symfony\Component\HttpClient\HttpClient::create();
|
||||
return new \Magdev\WcLicensedProductClient\SecureLicenseClient(
|
||||
httpClient: $httpClient,
|
||||
baseUrl: $server_url,
|
||||
serverSecret: $server_secret,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current domain for license validation
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_current_domain(): string {
|
||||
return wp_parse_url(home_url(), PHP_URL_HOST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the settings
|
||||
*/
|
||||
public function output() {
|
||||
$settings = $this->get_settings();
|
||||
WC_Admin_Settings::output_fields($settings);
|
||||
global $current_section;
|
||||
|
||||
// Register custom field types
|
||||
add_action('woocommerce_admin_field_wc_tpp_license_status', array($this, 'output_license_status_field'));
|
||||
add_action('woocommerce_admin_field_wc_tpp_update_status', array($this, 'output_update_status_field'));
|
||||
|
||||
parent::output();
|
||||
|
||||
// Add JavaScript for license section
|
||||
if ('license' === $current_section) {
|
||||
$this->output_license_scripts();
|
||||
}
|
||||
|
||||
// Add JavaScript for updates section
|
||||
if ('updates' === $current_section) {
|
||||
$this->output_updates_scripts();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save settings
|
||||
* Output license status custom field
|
||||
*
|
||||
* @param array $value Field configuration.
|
||||
*/
|
||||
public function save() {
|
||||
$settings = $this->get_settings();
|
||||
WC_Admin_Settings::save_fields($settings);
|
||||
public function output_license_status_field($value) {
|
||||
$status = $this->get_cached_license_status();
|
||||
?>
|
||||
<tr valign="top">
|
||||
<th scope="row" class="titledesc">
|
||||
<label><?php esc_html_e('License Status', 'wc-tier-package-prices'); ?></label>
|
||||
</th>
|
||||
<td class="forminp">
|
||||
<div id="wc-tpp-license-status-container" class="<?php echo !empty($status['valid']) ? 'valid' : 'invalid'; ?>">
|
||||
<?php $this->render_license_status_html($status); ?>
|
||||
</div>
|
||||
<p class="description" style="margin-top: 10px;">
|
||||
<button type="button" class="button" id="wc-tpp-validate-license">
|
||||
<?php esc_html_e('Validate License', 'wc-tier-package-prices'); ?>
|
||||
</button>
|
||||
<button type="button" class="button" id="wc-tpp-activate-license">
|
||||
<?php esc_html_e('Activate License', 'wc-tier-package-prices'); ?>
|
||||
</button>
|
||||
<span class="spinner" id="wc-tpp-license-spinner"></span>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render license status HTML
|
||||
*
|
||||
* @param array|false $status License status data.
|
||||
*/
|
||||
private function render_license_status_html($status) {
|
||||
// Check for license bypass
|
||||
$license_checker = WC_TPP_License_Checker::get_instance();
|
||||
$bypass_reason = $license_checker->get_bypass_reason();
|
||||
|
||||
if ($bypass_reason) {
|
||||
echo '<span class="wc-tpp-license-active">' . esc_html__('License Active', 'wc-tier-package-prices') . '</span>';
|
||||
if ('localhost' === $bypass_reason) {
|
||||
echo '<br><small>' . esc_html__('(Localhost environment - license validation bypassed)', 'wc-tier-package-prices') . '</small>';
|
||||
} elseif ('self_licensing' === $bypass_reason) {
|
||||
echo '<br><small>' . esc_html__('(Self-licensing server - license validation bypassed)', 'wc-tier-package-prices') . '</small>';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($status)) {
|
||||
echo '<span class="wc-tpp-license-inactive">' . esc_html__('No license activated', 'wc-tier-package-prices') . '</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!empty($status['valid'])) {
|
||||
echo '<span class="wc-tpp-license-active">' . esc_html__('License Active', 'wc-tier-package-prices') . '</span>';
|
||||
if (!empty($status['expires_at']) && empty($status['is_lifetime'])) {
|
||||
echo '<br><small>' . sprintf(
|
||||
/* translators: %s: Expiration date */
|
||||
esc_html__('Expires: %s', 'wc-tier-package-prices'),
|
||||
esc_html($status['expires_at'])
|
||||
) . '</small>';
|
||||
} elseif (!empty($status['is_lifetime'])) {
|
||||
echo '<br><small>' . esc_html__('Lifetime License', 'wc-tier-package-prices') . '</small>';
|
||||
}
|
||||
if (!empty($status['checked_at'])) {
|
||||
echo '<br><small>' . sprintf(
|
||||
/* translators: %s: Last check timestamp */
|
||||
esc_html__('Last checked: %s', 'wc-tier-package-prices'),
|
||||
esc_html($status['checked_at'])
|
||||
) . '</small>';
|
||||
}
|
||||
} else {
|
||||
echo '<span class="wc-tpp-license-inactive">' . esc_html__('License Invalid', 'wc-tier-package-prices') . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output update status custom field
|
||||
*
|
||||
* @param array $value Field configuration.
|
||||
*/
|
||||
public function output_update_status_field($value) {
|
||||
$update_checker = WC_TPP_Update_Checker::get_instance();
|
||||
$available_version = $update_checker->get_available_version();
|
||||
?>
|
||||
<tr valign="top">
|
||||
<th scope="row" class="titledesc">
|
||||
<label><?php esc_html_e('Update Status', 'wc-tier-package-prices'); ?></label>
|
||||
</th>
|
||||
<td class="forminp">
|
||||
<div id="wc-tpp-update-status-container">
|
||||
<?php $this->render_update_status_html($available_version); ?>
|
||||
</div>
|
||||
<p class="description" style="margin-top: 10px;">
|
||||
<button type="button" class="button" id="wc-tpp-check-updates">
|
||||
<?php esc_html_e('Check for Updates', 'wc-tier-package-prices'); ?>
|
||||
</button>
|
||||
<span class="spinner" id="wc-tpp-update-spinner"></span>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render update status HTML
|
||||
*
|
||||
* @param string|null $available_version Available update version.
|
||||
*/
|
||||
private function render_update_status_html(?string $available_version) {
|
||||
echo '<p><strong>' . esc_html__('Current Version:', 'wc-tier-package-prices') . '</strong> ' . esc_html(WC_TPP_VERSION) . '</p>';
|
||||
|
||||
if ($available_version) {
|
||||
echo '<p class="wc-tpp-update-available"><strong>' . esc_html__('Update Available:', 'wc-tier-package-prices') . '</strong> ' . esc_html($available_version) . '</p>';
|
||||
echo '<p><a href="' . esc_url(admin_url('update-core.php')) . '" class="button button-primary">' . esc_html__('Update Now', 'wc-tier-package-prices') . '</a></p>';
|
||||
} else {
|
||||
echo '<p class="wc-tpp-up-to-date">' . esc_html__('You are running the latest version.', 'wc-tier-package-prices') . '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output JavaScript for license management
|
||||
*/
|
||||
private function output_license_scripts() {
|
||||
$nonce = wp_create_nonce('wc_tpp_license_nonce');
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
jQuery(function($) {
|
||||
var $validateBtn = $('#wc-tpp-validate-license');
|
||||
var $activateBtn = $('#wc-tpp-activate-license');
|
||||
var $spinner = $('#wc-tpp-license-spinner');
|
||||
|
||||
function getLicenseData() {
|
||||
return {
|
||||
license_key: $('#wc_tpp_license_key').val(),
|
||||
server_url: $('#wc_tpp_license_server_url').val(),
|
||||
server_secret: $('#wc_tpp_license_server_secret').val(),
|
||||
nonce: '<?php echo esc_js($nonce); ?>'
|
||||
};
|
||||
}
|
||||
|
||||
function showSpinner() {
|
||||
$spinner.addClass('is-active');
|
||||
$validateBtn.prop('disabled', true);
|
||||
$activateBtn.prop('disabled', true);
|
||||
}
|
||||
|
||||
function hideSpinner() {
|
||||
$spinner.removeClass('is-active');
|
||||
$validateBtn.prop('disabled', false);
|
||||
$activateBtn.prop('disabled', false);
|
||||
}
|
||||
|
||||
$validateBtn.on('click', function() {
|
||||
var data = getLicenseData();
|
||||
if (!data.license_key || !data.server_url || !data.server_secret) {
|
||||
alert('<?php echo esc_js(__('Please enter license server URL, license key, and server secret.', 'wc-tier-package-prices')); ?>');
|
||||
return;
|
||||
}
|
||||
|
||||
showSpinner();
|
||||
$.post(ajaxurl, $.extend({action: 'wc_tpp_validate_license'}, data))
|
||||
.done(function(response) {
|
||||
if (response.success) {
|
||||
alert(response.data.message);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.data.message || '<?php echo esc_js(__('Validation failed.', 'wc-tier-package-prices')); ?>');
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
alert('<?php echo esc_js(__('Request failed. Please try again.', 'wc-tier-package-prices')); ?>');
|
||||
})
|
||||
.always(hideSpinner);
|
||||
});
|
||||
|
||||
$activateBtn.on('click', function() {
|
||||
var data = getLicenseData();
|
||||
if (!data.license_key || !data.server_url || !data.server_secret) {
|
||||
alert('<?php echo esc_js(__('Please enter license server URL, license key, and server secret.', 'wc-tier-package-prices')); ?>');
|
||||
return;
|
||||
}
|
||||
|
||||
showSpinner();
|
||||
$.post(ajaxurl, $.extend({action: 'wc_tpp_activate_license'}, data))
|
||||
.done(function(response) {
|
||||
if (response.success) {
|
||||
alert(response.data.message);
|
||||
location.reload();
|
||||
} else {
|
||||
alert(response.data.message || '<?php echo esc_js(__('Activation failed.', 'wc-tier-package-prices')); ?>');
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
alert('<?php echo esc_js(__('Request failed. Please try again.', 'wc-tier-package-prices')); ?>');
|
||||
})
|
||||
.always(hideSpinner);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for checking updates
|
||||
*/
|
||||
public function ajax_check_updates() {
|
||||
check_ajax_referer('wc_tpp_update_nonce', 'nonce');
|
||||
|
||||
if (!current_user_can('manage_woocommerce')) {
|
||||
wp_send_json_error(array('message' => __('Permission denied.', 'wc-tier-package-prices')));
|
||||
}
|
||||
|
||||
$update_checker = WC_TPP_Update_Checker::get_instance();
|
||||
$update_info = $update_checker->force_check();
|
||||
|
||||
if ($update_info && !empty($update_info['update_available'])) {
|
||||
wp_send_json_success(array(
|
||||
'message' => sprintf(
|
||||
/* translators: %s: Version number */
|
||||
__('Update available: version %s', 'wc-tier-package-prices'),
|
||||
$update_info['version']
|
||||
),
|
||||
'update_available' => true,
|
||||
'version' => $update_info['version'],
|
||||
'current_version' => WC_TPP_VERSION,
|
||||
));
|
||||
} else {
|
||||
wp_send_json_success(array(
|
||||
'message' => __('You are running the latest version.', 'wc-tier-package-prices'),
|
||||
'update_available' => false,
|
||||
'current_version' => WC_TPP_VERSION,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output JavaScript for update management
|
||||
*/
|
||||
private function output_updates_scripts() {
|
||||
$nonce = wp_create_nonce('wc_tpp_update_nonce');
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
jQuery(function($) {
|
||||
var $checkBtn = $('#wc-tpp-check-updates');
|
||||
var $spinner = $('#wc-tpp-update-spinner');
|
||||
var $container = $('#wc-tpp-update-status-container');
|
||||
|
||||
$checkBtn.on('click', function() {
|
||||
$spinner.addClass('is-active');
|
||||
$checkBtn.prop('disabled', true);
|
||||
|
||||
$.post(ajaxurl, {
|
||||
action: 'wc_tpp_check_updates',
|
||||
nonce: '<?php echo esc_js($nonce); ?>'
|
||||
})
|
||||
.done(function(response) {
|
||||
if (response.success) {
|
||||
var html = '<p><strong><?php echo esc_js(__('Current Version:', 'wc-tier-package-prices')); ?></strong> ' + response.data.current_version + '</p>';
|
||||
|
||||
if (response.data.update_available) {
|
||||
html += '<p class="wc-tpp-update-available"><strong><?php echo esc_js(__('Update Available:', 'wc-tier-package-prices')); ?></strong> ' + response.data.version + '</p>';
|
||||
html += '<p><a href="<?php echo esc_url(admin_url('update-core.php')); ?>" class="button button-primary"><?php echo esc_js(__('Update Now', 'wc-tier-package-prices')); ?></a></p>';
|
||||
} else {
|
||||
html += '<p class="wc-tpp-up-to-date"><?php echo esc_js(__('You are running the latest version.', 'wc-tier-package-prices')); ?></p>';
|
||||
}
|
||||
|
||||
$container.html(html);
|
||||
} else {
|
||||
alert(response.data.message || '<?php echo esc_js(__('Failed to check for updates.', 'wc-tier-package-prices')); ?>');
|
||||
}
|
||||
})
|
||||
.fail(function() {
|
||||
alert('<?php echo esc_js(__('Request failed. Please try again.', 'wc-tier-package-prices')); ?>');
|
||||
})
|
||||
.always(function() {
|
||||
$spinner.removeClass('is-active');
|
||||
$checkBtn.prop('disabled', false);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
468
includes/class-wc-tpp-update-checker.php
Normal file
468
includes/class-wc-tpp-update-checker.php
Normal file
@@ -0,0 +1,468 @@
|
||||
<?php
|
||||
/**
|
||||
* Update Checker
|
||||
*
|
||||
* Handles WordPress plugin updates from the license server
|
||||
*
|
||||
* @package WC_Tier_Package_Prices
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_TPP_Update_Checker class
|
||||
*/
|
||||
if (!class_exists('WC_TPP_Update_Checker')) {
|
||||
class WC_TPP_Update_Checker {
|
||||
|
||||
/**
|
||||
* Singleton instance
|
||||
*
|
||||
* @var WC_TPP_Update_Checker|null
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Plugin slug
|
||||
*/
|
||||
private const PLUGIN_SLUG = 'wc-tier-and-package-prices';
|
||||
|
||||
/**
|
||||
* Update check cache key
|
||||
*/
|
||||
private const CACHE_KEY = 'wc_tpp_update_info';
|
||||
|
||||
/**
|
||||
* Default check frequency in hours
|
||||
*/
|
||||
private const DEFAULT_CHECK_FREQUENCY = 12;
|
||||
|
||||
/**
|
||||
* Get singleton instance
|
||||
*
|
||||
* @return WC_TPP_Update_Checker
|
||||
*/
|
||||
public static function get_instance(): WC_TPP_Update_Checker {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private function __construct() {
|
||||
// Only register if updates are not disabled
|
||||
if ($this->is_disabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->register_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if auto-updates are disabled via constant
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_disabled(): bool {
|
||||
return defined('WC_TPP_DISABLE_AUTO_UPDATE') && WC_TPP_DISABLE_AUTO_UPDATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register WordPress hooks
|
||||
*/
|
||||
private function register_hooks(): void {
|
||||
// Check for updates
|
||||
add_filter('pre_set_site_transient_update_plugins', array($this, 'check_for_updates'));
|
||||
|
||||
// Provide plugin information for update modal
|
||||
add_filter('plugins_api', array($this, 'get_plugin_info'), 10, 3);
|
||||
|
||||
// Add authentication headers to download requests
|
||||
add_filter('http_request_args', array($this, 'add_auth_headers'), 10, 2);
|
||||
|
||||
// Handle auto-install setting
|
||||
add_filter('auto_update_plugin', array($this, 'handle_auto_install'), 10, 2);
|
||||
|
||||
// Clear cache when settings change
|
||||
add_action('update_option_wc_tpp_license_key', array($this, 'clear_cache'));
|
||||
add_action('update_option_wc_tpp_license_server_url', array($this, 'clear_cache'));
|
||||
add_action('update_option_wc_tpp_update_notification_enabled', array($this, 'clear_cache'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if update notifications are enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_update_notification_enabled(): bool {
|
||||
return get_option('wc_tpp_update_notification_enabled', 'yes') === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if auto-install is enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_auto_install_enabled(): bool {
|
||||
return get_option('wc_tpp_auto_install_enabled', 'no') === 'yes';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get update check frequency in hours
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_check_frequency(): int {
|
||||
$frequency = (int) get_option('wc_tpp_update_check_frequency', self::DEFAULT_CHECK_FREQUENCY);
|
||||
return max(1, min(168, $frequency)); // Clamp between 1 and 168 hours
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for plugin updates
|
||||
*
|
||||
* @param object $transient WordPress update transient.
|
||||
* @return object
|
||||
*/
|
||||
public function check_for_updates($transient) {
|
||||
if (empty($transient->checked)) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
// Skip if notifications disabled
|
||||
if (!self::is_update_notification_enabled()) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
// Get update info (cached)
|
||||
$update_info = $this->get_update_info();
|
||||
|
||||
if (empty($update_info) || !$update_info['update_available']) {
|
||||
return $transient;
|
||||
}
|
||||
|
||||
// Build update object
|
||||
$update_obj = $this->build_update_object($update_info);
|
||||
|
||||
if ($update_obj) {
|
||||
$transient->response[WC_TPP_PLUGIN_BASENAME] = $update_obj;
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin information for update modal
|
||||
*
|
||||
* @param false|object|array $result The result object or array.
|
||||
* @param string $action The type of information being requested.
|
||||
* @param object $args Plugin API arguments.
|
||||
* @return false|object
|
||||
*/
|
||||
public function get_plugin_info($result, $action, $args) {
|
||||
if ('plugin_information' !== $action) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (!isset($args->slug) || self::PLUGIN_SLUG !== $args->slug) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Get update info
|
||||
$update_info = $this->get_update_info(true); // Force fetch for full info
|
||||
|
||||
if (empty($update_info)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Build plugin info object
|
||||
return $this->build_plugin_info_object($update_info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add authentication headers to download requests
|
||||
*
|
||||
* @param array $args HTTP request arguments.
|
||||
* @param string $url The request URL.
|
||||
* @return array
|
||||
*/
|
||||
public function add_auth_headers(array $args, string $url): array {
|
||||
$server_url = get_option('wc_tpp_license_server_url', '');
|
||||
|
||||
// Only add headers for requests to our license server
|
||||
if (empty($server_url) || strpos($url, $server_url) !== 0) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
$license_key = get_option('wc_tpp_license_key', '');
|
||||
|
||||
if (!empty($license_key)) {
|
||||
$args['headers']['X-License-Key'] = $license_key;
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle auto-install setting
|
||||
*
|
||||
* @param bool|null $update Whether to auto-update.
|
||||
* @param object $item The plugin update object.
|
||||
* @return bool|null
|
||||
*/
|
||||
public function handle_auto_install($update, $item) {
|
||||
// Check if this is our plugin
|
||||
if (!isset($item->plugin) || WC_TPP_PLUGIN_BASENAME !== $item->plugin) {
|
||||
return $update;
|
||||
}
|
||||
|
||||
// Return our setting, or default behavior
|
||||
if (self::is_auto_install_enabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $update;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get update info from cache or server
|
||||
*
|
||||
* @param bool $force_fetch Force fetching from server.
|
||||
* @return array|null
|
||||
*/
|
||||
private function get_update_info(bool $force_fetch = false): ?array {
|
||||
// Check cache first
|
||||
if (!$force_fetch) {
|
||||
$cached = get_transient(self::CACHE_KEY);
|
||||
if (false !== $cached) {
|
||||
return $cached;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch from server
|
||||
$update_info = $this->fetch_update_info();
|
||||
|
||||
if ($update_info) {
|
||||
// Cache the result
|
||||
$cache_ttl = self::get_check_frequency() * HOUR_IN_SECONDS;
|
||||
set_transient(self::CACHE_KEY, $update_info, $cache_ttl);
|
||||
}
|
||||
|
||||
return $update_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch update info from license server
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function fetch_update_info(): ?array {
|
||||
$server_url = get_option('wc_tpp_license_server_url', '');
|
||||
$license_key = get_option('wc_tpp_license_key', '');
|
||||
$server_secret = get_option('wc_tpp_license_server_secret', '');
|
||||
|
||||
if (empty($server_url)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Build the update check endpoint
|
||||
$endpoint = trailingslashit($server_url) . 'wp-json/wc-licensed-product/v1/update-check';
|
||||
|
||||
// Get license checker for domain
|
||||
$license_checker = WC_TPP_License_Checker::get_instance();
|
||||
$domain = $license_checker->get_current_domain();
|
||||
|
||||
// Remove port for API call
|
||||
$domain = preg_replace('/:[\d]+$/', '', $domain);
|
||||
|
||||
// Prepare request body
|
||||
$body = array(
|
||||
'license_key' => $license_key,
|
||||
'domain' => $domain,
|
||||
'plugin_slug' => self::PLUGIN_SLUG,
|
||||
'current_version' => WC_TPP_VERSION,
|
||||
);
|
||||
|
||||
// Make the request
|
||||
$response = wp_remote_post($endpoint, array(
|
||||
'timeout' => 15,
|
||||
'headers' => array(
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode($body),
|
||||
));
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code($response);
|
||||
|
||||
// Handle rate limiting
|
||||
if (429 === $response_code) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Handle other errors
|
||||
if ($response_code < 200 || $response_code >= 300) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body($response);
|
||||
$data = json_decode($body, true);
|
||||
|
||||
if (empty($data) || !isset($data['success'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build WordPress update object
|
||||
*
|
||||
* @param array $update_info Update information from server.
|
||||
* @return object|null
|
||||
*/
|
||||
private function build_update_object(array $update_info): ?object {
|
||||
if (empty($update_info['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if update is actually available
|
||||
if (version_compare(WC_TPP_VERSION, $update_info['version'], '>=')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$obj = new \stdClass();
|
||||
$obj->id = $update_info['id'] ?? self::PLUGIN_SLUG;
|
||||
$obj->slug = $update_info['slug'] ?? self::PLUGIN_SLUG;
|
||||
$obj->plugin = $update_info['plugin'] ?? WC_TPP_PLUGIN_BASENAME;
|
||||
$obj->new_version = $update_info['version'];
|
||||
$obj->url = $update_info['url'] ?? '';
|
||||
$obj->package = $update_info['download_url'] ?? $update_info['package'] ?? '';
|
||||
$obj->tested = $update_info['tested'] ?? '';
|
||||
$obj->requires = $update_info['requires'] ?? '6.0';
|
||||
$obj->requires_php = $update_info['requires_php'] ?? '8.3';
|
||||
|
||||
// Icons
|
||||
if (!empty($update_info['icons'])) {
|
||||
$obj->icons = $update_info['icons'];
|
||||
}
|
||||
|
||||
// Banners
|
||||
if (!empty($update_info['banners'])) {
|
||||
$obj->banners = $update_info['banners'];
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build plugin info object for update modal
|
||||
*
|
||||
* @param array $update_info Update information from server.
|
||||
* @return object
|
||||
*/
|
||||
private function build_plugin_info_object(array $update_info): object {
|
||||
$obj = new \stdClass();
|
||||
|
||||
$obj->name = $update_info['name'] ?? 'WooCommerce Tier and Package Prices';
|
||||
$obj->slug = $update_info['slug'] ?? self::PLUGIN_SLUG;
|
||||
$obj->version = $update_info['version'] ?? WC_TPP_VERSION;
|
||||
$obj->author = $update_info['author'] ?? '<a href="https://src.bundespruefstelle.ch/magdev">Marco Graetsch</a>';
|
||||
$obj->author_profile = $update_info['author_profile'] ?? 'https://src.bundespruefstelle.ch/magdev';
|
||||
$obj->homepage = $update_info['homepage'] ?? $update_info['url'] ?? '';
|
||||
$obj->requires = $update_info['requires'] ?? '6.0';
|
||||
$obj->tested = $update_info['tested'] ?? '';
|
||||
$obj->requires_php = $update_info['requires_php'] ?? '8.3';
|
||||
$obj->last_updated = $update_info['last_updated'] ?? '';
|
||||
$obj->download_link = $update_info['download_url'] ?? $update_info['package'] ?? '';
|
||||
|
||||
// Sections (description, changelog, etc.)
|
||||
$obj->sections = array();
|
||||
|
||||
if (!empty($update_info['sections']['description'])) {
|
||||
$obj->sections['description'] = $update_info['sections']['description'];
|
||||
} else {
|
||||
$obj->sections['description'] = __('Add tier pricing and package prices to WooCommerce products with configurable quantities at fixed prices.', 'wc-tier-package-prices');
|
||||
}
|
||||
|
||||
if (!empty($update_info['sections']['changelog'])) {
|
||||
$obj->sections['changelog'] = $update_info['sections']['changelog'];
|
||||
} elseif (!empty($update_info['changelog'])) {
|
||||
$obj->sections['changelog'] = $update_info['changelog'];
|
||||
}
|
||||
|
||||
if (!empty($update_info['sections']['installation'])) {
|
||||
$obj->sections['installation'] = $update_info['sections']['installation'];
|
||||
}
|
||||
|
||||
// Icons
|
||||
if (!empty($update_info['icons'])) {
|
||||
$obj->icons = $update_info['icons'];
|
||||
}
|
||||
|
||||
// Banners
|
||||
if (!empty($update_info['banners'])) {
|
||||
$obj->banners = $update_info['banners'];
|
||||
}
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear update cache
|
||||
*/
|
||||
public function clear_cache(): void {
|
||||
delete_transient(self::CACHE_KEY);
|
||||
|
||||
// Also clear WordPress plugin update transient to force recheck
|
||||
delete_site_transient('update_plugins');
|
||||
}
|
||||
|
||||
/**
|
||||
* Force check for updates
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function force_check(): ?array {
|
||||
$this->clear_cache();
|
||||
return $this->get_update_info(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the available update version if any
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_available_version(): ?string {
|
||||
$update_info = $this->get_update_info();
|
||||
|
||||
if (empty($update_info) || empty($update_info['version'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check if it's actually newer
|
||||
if (version_compare(WC_TPP_VERSION, $update_info['version'], '>=')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $update_info['version'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an update is available
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_update_available(): bool {
|
||||
return null !== $this->get_available_version();
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
# German (Switzerland) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-03 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German (Switzerland)\n"
|
||||
"Language: de_CH\n"
|
||||
@@ -277,3 +277,219 @@ msgstr "Preis"
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise erfordert PHP 8.3 oder höher. Ihr Server verwendet PHP %s."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr "Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr "Lizenzverwaltung"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr "Geben Sie Ihren Lizenzschlüssel ein, um Updates und Support zu erhalten."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr "Lizenzserver-URL"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr "Die URL des Lizenzservers."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr "Lizenzschlüssel"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr "Ihr Lizenzschlüssel für dieses Plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr "Lizenzstatus"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr "Lizenz überprüfen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr "Lizenz aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr "Keine Lizenz aktiviert"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr "Lizenz aktiv"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr "Lizenz ungültig"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr "Lebenslange Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr "Läuft ab: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr "Zuletzt geprüft: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr "Lizenz ist gültig!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr "Lizenz erfolgreich aktiviert!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Zugriff verweigert."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr "Server-Geheimnis"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr "Das gemeinsame Geheimnis für die sichere Kommunikation mit dem Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr "Lizenzschlüssel, Server-URL und Server-Geheimnis sind erforderlich."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr "Anfragelimit überschritten. Bitte versuchen Sie es in %d Sekunden erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr "Überprüfung der Antwortsignatur fehlgeschlagen. Bitte überprüfen Sie Ihr Server-Geheimnis."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr "Bitte geben Sie die Lizenzserver-URL, den Lizenzschlüssel und das Server-Geheimnis ein."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr "Überprüfung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr "Aktivierung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr "Anfrage fehlgeschlagen. Bitte versuchen Sie es erneut."
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr "Auto-Updates"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr "Auto-Update Einstellungen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr "Konfigurieren Sie automatische Plugin-Updates vom Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr "Update-Benachrichtigungen aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr "Nach verfügbaren Plugin-Updates suchen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr "Wenn aktiviert, prüft das Plugin auf Updates vom Lizenzserver und zeigt Benachrichtigungen im WordPress-Admin an."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr "Updates automatisch installieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr "Updates automatisch installieren, wenn verfügbar."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr "(Erfordert eine gültige Lizenz)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr "Wenn aktiviert, werden Updates automatisch installiert, wenn WordPress Hintergrund-Updates durchführt."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr "Prüfhäufigkeit (Stunden)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr "Wie oft nach Updates gesucht werden soll."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr "Anzahl der Stunden zwischen Update-Prüfungen. Standard ist 12 Stunden."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr "Update-Status"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr "Nach Updates suchen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr "Aktuelle Version:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr "Update verfügbar:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr "Sie verwenden die neueste Version."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr "Jetzt aktualisieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr "Update verfügbar: Version %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr "Fehler beim Suchen nach Updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr "(Localhost-Umgebung - Lizenzvalidierung übersprungen)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr "(Selbstlizenzierender Server - Lizenzvalidierung übersprungen)"
|
||||
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
# German (Switzerland, Informal) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-03 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German (Switzerland)\n"
|
||||
"Language: de_CH_informal\n"
|
||||
@@ -277,3 +277,219 @@ msgstr "Preis"
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise erfordert PHP 8.3 oder höher. Dein Server verwendet PHP %s."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr "Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr "Lizenzverwaltung"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr "Gib deinen Lizenzschlüssel ein, um Updates und Support zu erhalten."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr "Lizenzserver-URL"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr "Die URL des Lizenzservers."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr "Lizenzschlüssel"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr "Dein Lizenzschlüssel für dieses Plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr "Lizenzstatus"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr "Lizenz überprüfen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr "Lizenz aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr "Keine Lizenz aktiviert"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr "Lizenz aktiv"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr "Lizenz ungültig"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr "Lebenslange Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr "Läuft ab: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr "Zuletzt geprüft: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr "Lizenz ist gültig!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr "Lizenz erfolgreich aktiviert!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Zugriff verweigert."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr "Server-Geheimnis"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr "Das gemeinsame Geheimnis für die sichere Kommunikation mit dem Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr "Lizenzschlüssel, Server-URL und Server-Geheimnis sind erforderlich."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr "Anfragelimit überschritten. Bitte versuche es in %d Sekunden erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr "Überprüfung der Antwortsignatur fehlgeschlagen. Bitte überprüfe dein Server-Geheimnis."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuche es erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr "Bitte gib die Lizenzserver-URL, den Lizenzschlüssel und das Server-Geheimnis ein."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr "Überprüfung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr "Aktivierung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr "Anfrage fehlgeschlagen. Bitte versuche es erneut."
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr "Auto-Updates"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr "Auto-Update Einstellungen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr "Konfiguriere automatische Plugin-Updates vom Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr "Update-Benachrichtigungen aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr "Nach verfügbaren Plugin-Updates suchen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr "Wenn aktiviert, prüft das Plugin auf Updates vom Lizenzserver und zeigt Benachrichtigungen im WordPress-Admin an."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr "Updates automatisch installieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr "Updates automatisch installieren, wenn verfügbar."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr "(Erfordert eine gültige Lizenz)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr "Wenn aktiviert, werden Updates automatisch installiert, wenn WordPress Hintergrund-Updates durchführt."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr "Prüfhäufigkeit (Stunden)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr "Wie oft nach Updates gesucht werden soll."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr "Anzahl der Stunden zwischen Update-Prüfungen. Standard ist 12 Stunden."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr "Update-Status"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr "Nach Updates suchen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr "Aktuelle Version:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr "Update verfügbar:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr "Du verwendest die neueste Version."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr "Jetzt aktualisieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr "Update verfügbar: Version %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr "Fehler beim Suchen nach Updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr "(Localhost-Umgebung - Lizenzvalidierung übersprungen)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr "(Selbstlizenzierender Server - Lizenzvalidierung übersprungen)"
|
||||
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
# German (Germany) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-03 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
@@ -277,3 +277,219 @@ msgstr "Preis"
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise erfordert PHP 8.3 oder höher. Ihr Server verwendet PHP %s."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr "Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr "Lizenzverwaltung"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr "Geben Sie Ihren Lizenzschlüssel ein, um Updates und Support zu erhalten."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr "Lizenzserver-URL"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr "Die URL des Lizenzservers."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr "Lizenzschlüssel"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr "Ihr Lizenzschlüssel für dieses Plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr "Lizenzstatus"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr "Lizenz überprüfen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr "Lizenz aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr "Keine Lizenz aktiviert"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr "Lizenz aktiv"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr "Lizenz ungültig"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr "Lebenslange Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr "Läuft ab: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr "Zuletzt geprüft: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr "Lizenz ist gültig!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr "Lizenz erfolgreich aktiviert!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Zugriff verweigert."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr "Server-Geheimnis"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr "Das gemeinsame Geheimnis für die sichere Kommunikation mit dem Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr "Lizenzschlüssel, Server-URL und Server-Geheimnis sind erforderlich."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr "Anfragelimit überschritten. Bitte versuchen Sie es in %d Sekunden erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr "Überprüfung der Antwortsignatur fehlgeschlagen. Bitte überprüfen Sie Ihr Server-Geheimnis."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr "Bitte geben Sie die Lizenzserver-URL, den Lizenzschlüssel und das Server-Geheimnis ein."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr "Überprüfung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr "Aktivierung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr "Anfrage fehlgeschlagen. Bitte versuchen Sie es erneut."
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr "Auto-Updates"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr "Auto-Update Einstellungen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr "Konfigurieren Sie automatische Plugin-Updates vom Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr "Update-Benachrichtigungen aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr "Nach verfügbaren Plugin-Updates suchen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr "Wenn aktiviert, prüft das Plugin auf Updates vom Lizenzserver und zeigt Benachrichtigungen im WordPress-Admin an."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr "Updates automatisch installieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr "Updates automatisch installieren, wenn verfügbar."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr "(Erfordert eine gültige Lizenz)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr "Wenn aktiviert, werden Updates automatisch installiert, wenn WordPress Hintergrund-Updates durchführt."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr "Prüfhäufigkeit (Stunden)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr "Wie oft nach Updates gesucht werden soll."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr "Anzahl der Stunden zwischen Update-Prüfungen. Standard ist 12 Stunden."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr "Update-Status"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr "Nach Updates suchen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr "Aktuelle Version:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr "Update verfügbar:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr "Sie verwenden die neueste Version."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr "Jetzt aktualisieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr "Update verfügbar: Version %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr "Fehler beim Suchen nach Updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr "(Localhost-Umgebung - Lizenzvalidierung übersprungen)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr "(Selbstlizenzierender Server - Lizenzvalidierung übersprungen)"
|
||||
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
# German (Germany, Informal) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-03 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German (Germany)\n"
|
||||
"Language: de_DE_informal\n"
|
||||
@@ -277,3 +277,219 @@ msgstr "Preis"
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise erfordert PHP 8.3 oder höher. Dein Server verwendet PHP %s."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr "Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr "Lizenzverwaltung"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr "Gib deinen Lizenzschlüssel ein, um Updates und Support zu erhalten."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr "Lizenzserver-URL"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr "Die URL des Lizenzservers."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr "Lizenzschlüssel"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr "Dein Lizenzschlüssel für dieses Plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr "Lizenzstatus"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr "Lizenz überprüfen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr "Lizenz aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr "Keine Lizenz aktiviert"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr "Lizenz aktiv"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr "Lizenz ungültig"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr "Lebenslange Lizenz"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr "Läuft ab: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr "Zuletzt geprüft: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr "Lizenz ist gültig!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr "Lizenz erfolgreich aktiviert!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Zugriff verweigert."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr "Server-Geheimnis"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr "Das gemeinsame Geheimnis für die sichere Kommunikation mit dem Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr "Lizenzschlüssel, Server-URL und Server-Geheimnis sind erforderlich."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr "Anfragelimit überschritten. Bitte versuche es in %d Sekunden erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr "Überprüfung der Antwortsignatur fehlgeschlagen. Bitte überprüfe dein Server-Geheimnis."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuche es erneut."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr "Bitte gib die Lizenzserver-URL, den Lizenzschlüssel und das Server-Geheimnis ein."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr "Überprüfung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr "Aktivierung fehlgeschlagen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr "Anfrage fehlgeschlagen. Bitte versuche es erneut."
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr "Auto-Updates"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr "Auto-Update Einstellungen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr "Konfiguriere automatische Plugin-Updates vom Lizenzserver."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr "Update-Benachrichtigungen aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr "Nach verfügbaren Plugin-Updates suchen."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr "Wenn aktiviert, prüft das Plugin auf Updates vom Lizenzserver und zeigt Benachrichtigungen im WordPress-Admin an."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr "Updates automatisch installieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr "Updates automatisch installieren, wenn verfügbar."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr "(Erfordert eine gültige Lizenz)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr "Wenn aktiviert, werden Updates automatisch installiert, wenn WordPress Hintergrund-Updates durchführt."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr "Prüfhäufigkeit (Stunden)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr "Wie oft nach Updates gesucht werden soll."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr "Anzahl der Stunden zwischen Update-Prüfungen. Standard ist 12 Stunden."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr "Update-Status"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr "Nach Updates suchen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr "Aktuelle Version:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr "Update verfügbar:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr "Du verwendest die neueste Version."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr "Jetzt aktualisieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr "Update verfügbar: Version %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr "Fehler beim Suchen nach Updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr "(Localhost-Umgebung - Lizenzvalidierung übersprungen)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr "(Selbstlizenzierender Server - Lizenzvalidierung übersprungen)"
|
||||
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
# English (US) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-03 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: English\n"
|
||||
"Language: en_US\n"
|
||||
@@ -277,3 +277,219 @@ msgstr "Price"
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Label (optional)"
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr "License"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr "License Management"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr "Enter your license key to receive updates and support."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr "License Server URL"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr "The URL of the license server."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr "License Key"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr "Your license key for this plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr "License Status"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr "Validate License"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr "Activate License"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr "No license activated"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr "License Active"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr "License Invalid"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr "Lifetime License"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr "Expires: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr "Last checked: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr "License is valid!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr "License activated successfully!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Permission denied."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr "Server Secret"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr "The shared secret for secure communication with the license server."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr "License key, server URL, and server secret are required."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr "Rate limit exceeded. Please try again in %d seconds."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr "Response signature verification failed. Please check your server secret."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "An unexpected error occurred. Please try again."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr "Please enter license server URL, license key, and server secret."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr "Validation failed."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr "Activation failed."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr "Request failed. Please try again."
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr "Auto-Updates"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr "Auto-Update Settings"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr "Configure automatic plugin updates from the license server."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr "Enable Update Notifications"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr "Check for available plugin updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr "Automatically Install Updates"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr "Automatically install updates when available."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr "(Requires a valid license)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr "Check Frequency (Hours)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr "How often to check for updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr "Number of hours between update checks. Default is 12 hours."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr "Update Status"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr "Check for Updates"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr "Current Version:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr "Update Available:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr "You are running the latest version."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr "Update Now"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr "Update available: version %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr "Failed to check for updates."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr "(Localhost environment - license validation bypassed)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr "(Self-licensing server - license validation bypassed)"
|
||||
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
# French (Switzerland) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-03 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: French (Switzerland)\n"
|
||||
"Language: fr_CH\n"
|
||||
@@ -277,3 +277,219 @@ msgstr "Prix"
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Étiquette (optionnel)"
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr "WooCommerce Prix par paliers et forfaits nécessite PHP 8.3 ou supérieur. Votre serveur utilise PHP %s."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr "Licence"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr "Gestion des licences"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr "Entrez votre clé de licence pour recevoir des mises à jour et du support."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr "URL du serveur de licence"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr "L'URL du serveur de licence."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr "Clé de licence"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr "Votre clé de licence pour cette extension."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr "Statut de la licence"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr "Valider la licence"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr "Activer la licence"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr "Aucune licence activée"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr "Licence active"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr "Licence invalide"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr "Licence à vie"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr "Expire le: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr "Dernière vérification: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr "La licence est valide!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr "Licence activée avec succès!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Accès refusé."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr "Secret serveur"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr "Le secret partagé pour la communication sécurisée avec le serveur de licence."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr "La clé de licence, l'URL du serveur et le secret serveur sont requis."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr "Limite de requêtes dépassée. Veuillez réessayer dans %d secondes."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr "La vérification de la signature a échoué. Veuillez vérifier votre secret serveur."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Une erreur inattendue s'est produite. Veuillez réessayer."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr "Veuillez entrer l'URL du serveur de licence, la clé de licence et le secret serveur."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr "La validation a échoué."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr "L'activation a échoué."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr "La requête a échoué. Veuillez réessayer."
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr "Mises à jour automatiques"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr "Paramètres de mise à jour automatique"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr "Configurez les mises à jour automatiques du plugin depuis le serveur de licence."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr "Activer les notifications de mise à jour"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr "Rechercher les mises à jour disponibles du plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr "Lorsque cette option est activée, le plugin vérifiera les mises à jour depuis le serveur de licence et affichera des notifications dans l'administration WordPress."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr "Installer automatiquement les mises à jour"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr "Installer automatiquement les mises à jour lorsqu'elles sont disponibles."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr "(Nécessite une licence valide)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr "Lorsque cette option est activée, les mises à jour seront automatiquement installées lors des mises à jour en arrière-plan de WordPress."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr "Fréquence de vérification (heures)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr "Fréquence de recherche des mises à jour."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr "Nombre d'heures entre les vérifications de mise à jour. Par défaut: 12 heures."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr "Statut de mise à jour"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr "Rechercher des mises à jour"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr "Version actuelle:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr "Mise à jour disponible:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr "Vous utilisez la dernière version."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr "Mettre à jour maintenant"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr "Mise à jour disponible: version %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr "Échec de la recherche de mises à jour."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr "(Environnement localhost - validation de licence ignorée)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr "(Serveur auto-licencié - validation de licence ignorée)"
|
||||
|
||||
Binary file not shown.
@@ -1,12 +1,12 @@
|
||||
# Italian (Switzerland) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"PO-Revision-Date: 2026-02-03 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: Italian (Switzerland)\n"
|
||||
"Language: it_CH\n"
|
||||
@@ -277,3 +277,219 @@ msgstr "Prezzo"
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Etichetta (facoltativo)"
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr "WooCommerce Prezzi a scaglioni e pacchetti richiede PHP 8.3 o superiore. Il tuo server utilizza PHP %s."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr "Licenza"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr "Gestione licenza"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr "Inserisci la tua chiave di licenza per ricevere aggiornamenti e supporto."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr "URL server licenza"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr "L'URL del server di licenza."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr "Chiave di licenza"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr "La tua chiave di licenza per questo plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr "Stato licenza"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr "Verifica licenza"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr "Attiva licenza"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr "Nessuna licenza attivata"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr "Licenza attiva"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr "Licenza non valida"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr "Licenza a vita"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr "Scade il: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr "Ultima verifica: %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr "La licenza è valida!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr "Licenza attivata con successo!"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr "Accesso negato."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr "Segreto del server"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr "Il segreto condiviso per la comunicazione sicura con il server di licenza."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr "La chiave di licenza, l'URL del server e il segreto del server sono obbligatori."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr "Limite di richieste superato. Per favore riprova tra %d secondi."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr "Verifica della firma della risposta fallita. Per favore controlla il tuo segreto del server."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr "Si è verificato un errore imprevisto. Per favore riprova."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr "Inserisci l'URL del server di licenza, la chiave di licenza e il segreto del server."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr "Verifica fallita."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr "Attivazione fallita."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr "Richiesta fallita. Per favore riprova."
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr "Aggiornamenti automatici"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr "Impostazioni aggiornamento automatico"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr "Configura gli aggiornamenti automatici del plugin dal server di licenza."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr "Abilita notifiche di aggiornamento"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr "Verifica la disponibilità di aggiornamenti del plugin."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr "Se abilitato, il plugin verificherà la presenza di aggiornamenti dal server di licenza e mostrerà le notifiche nell'amministrazione WordPress."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr "Installa automaticamente gli aggiornamenti"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr "Installa automaticamente gli aggiornamenti quando disponibili."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr "(Richiede una licenza valida)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr "Se abilitato, gli aggiornamenti verranno installati automaticamente quando WordPress esegue gli aggiornamenti in background."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr "Frequenza di controllo (ore)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr "Con quale frequenza controllare gli aggiornamenti."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr "Numero di ore tra i controlli degli aggiornamenti. Predefinito: 12 ore."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr "Stato aggiornamento"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr "Verifica aggiornamenti"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr "Versione attuale:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr "Aggiornamento disponibile:"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr "Stai utilizzando l'ultima versione."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr "Aggiorna ora"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr "Aggiornamento disponibile: versione %s"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr "Impossibile verificare la presenza di aggiornamenti."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr "(Ambiente localhost - verifica della licenza saltata)"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr "(Server auto-licenziato - verifica della licenza saltata)"
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# Copyright (C) 2026 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.4.1\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-30 00:00+0000\n"
|
||||
"POT-Creation-Date: 2026-02-03 00:00+0000\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
@@ -250,3 +250,219 @@ msgstr ""
|
||||
#: includes/class-wc-tpp-frontend.php:178
|
||||
msgid "View options for %s"
|
||||
msgstr ""
|
||||
|
||||
#: wc-tier-and-package-prices.php
|
||||
msgid "WooCommerce Tier and Package Prices requires PHP 8.3 or higher. Your server is running PHP %s."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Management"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enter your license key to receive updates and support."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Server URL"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The URL of the license server."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Key"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Your license key for this plugin."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Status"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validate License"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activate License"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "No license activated"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Active"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License Invalid"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Lifetime License"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Expires: %s"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Last checked: %s"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License is valid!"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License activated successfully!"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Permission denied."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Server Secret"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "The shared secret for secure communication with the license server."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "License key, server URL, and server secret are required."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %d: Number of seconds to wait
|
||||
msgid "Rate limit exceeded. Please try again in %d seconds."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Response signature verification failed. Please check your server secret."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "An unexpected error occurred. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Please enter license server URL, license key, and server secret."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Validation failed."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Activation failed."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Request failed. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#. v1.4.1 - Auto-Updates and License Bypass
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Updates"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Auto-Update Settings"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Configure automatic plugin updates from the license server."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Enable Update Notifications"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for available plugin updates."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, the plugin will check for updates from the license server and show notifications in the WordPress admin."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically Install Updates"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Automatically install updates when available."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Requires a valid license)"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "When enabled, updates will be automatically installed when WordPress performs background updates."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check Frequency (Hours)"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "How often to check for updates."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Number of hours between update checks. Default is 12 hours."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Status"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Check for Updates"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Current Version:"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Available:"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "You are running the latest version."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Update Now"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
#. translators: %s: Version number
|
||||
msgid "Update available: version %s"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "Failed to check for updates."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Localhost environment - license validation bypassed)"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php
|
||||
msgid "(Self-licensing server - license validation bypassed)"
|
||||
msgstr ""
|
||||
|
||||
1
lib/wc-licensed-product-client
Submodule
1
lib/wc-licensed-product-client
Submodule
Submodule lib/wc-licensed-product-client added at 56abe8a97c
@@ -1,219 +0,0 @@
|
||||
# WooCommerce Tier and Package Prices - Releases
|
||||
|
||||
This directory contains production-ready releases of the WooCommerce Tier and Package Prices plugin.
|
||||
|
||||
## Latest Release
|
||||
|
||||
**Version 1.1.20** - December 23, 2025
|
||||
|
||||
### What's New in 1.1.20
|
||||
- 🔧 **CRITICAL FIX:** Resolved WooCommerce Blocks fatal error in mini-cart and cart blocks
|
||||
- ✅ Full WooCommerce Blocks compatibility (cart, mini-cart, checkout)
|
||||
- ✅ Fixed `woocommerce_store_api_product_quantity_editable` filter signature
|
||||
- ✅ Tier labels for enhanced UX (v1.1.7)
|
||||
- ✅ Package quantity restrictions (v1.1.0)
|
||||
- ✅ Clickable tier rows with auto-fill
|
||||
- ✅ Enhanced "View Options" buttons
|
||||
|
||||
### Quick Install
|
||||
|
||||
```bash
|
||||
# Download the package
|
||||
wget https://your-domain.com/releases/wc-tier-and-package-prices-1.1.20.zip
|
||||
|
||||
# Verify checksum (optional but recommended)
|
||||
sha256sum wc-tier-and-package-prices-1.1.20.zip
|
||||
|
||||
# Install via WordPress admin or WP-CLI
|
||||
wp plugin install wc-tier-and-package-prices-1.1.20.zip --activate
|
||||
```
|
||||
|
||||
## Files in This Directory
|
||||
|
||||
### Release Packages
|
||||
|
||||
| File | Description | Size |
|
||||
|------|-------------|------|
|
||||
| `wc-tier-and-package-prices-1.1.20.zip` | Production plugin package | ~400 KB |
|
||||
| `wc-tier-and-package-prices-1.1.20.zip.sha256` | SHA-256 checksum | - |
|
||||
| `wc-tier-and-package-prices-1.1.20.zip.md5` | MD5 checksum | - |
|
||||
| `RELEASE-INFO-1.1.20.md` | Detailed release information | - |
|
||||
|
||||
## Verification
|
||||
|
||||
### Verify Package Integrity
|
||||
|
||||
**Using SHA-256:**
|
||||
```bash
|
||||
sha256sum -c wc-tier-and-package-prices-1.1.20.zip.sha256
|
||||
```
|
||||
|
||||
**Using MD5:**
|
||||
```bash
|
||||
md5sum -c wc-tier-and-package-prices-1.1.20.zip.md5
|
||||
```
|
||||
|
||||
### Expected Checksums
|
||||
|
||||
Checksums will be generated when the release package is created.
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Method 1: WordPress Admin (Recommended for most users)
|
||||
|
||||
1. Download `wc-tier-and-package-prices-1.1.20.zip`
|
||||
2. Go to **WordPress Admin > Plugins > Add New**
|
||||
3. Click **Upload Plugin**
|
||||
4. Choose the downloaded ZIP file
|
||||
5. Click **Install Now**
|
||||
6. Click **Activate Plugin**
|
||||
|
||||
### Method 2: WP-CLI (For developers)
|
||||
|
||||
```bash
|
||||
wp plugin install /path/to/wc-tier-and-package-prices-1.1.20.zip --activate
|
||||
```
|
||||
|
||||
### Method 3: Manual Installation (Advanced)
|
||||
|
||||
```bash
|
||||
# Extract to wp-content/plugins/
|
||||
unzip wc-tier-and-package-prices-1.1.20.zip -d /path/to/wordpress/wp-content/plugins/
|
||||
|
||||
# Set correct permissions
|
||||
chmod -R 755 /path/to/wordpress/wp-content/plugins/wc-tier-and-package-prices
|
||||
|
||||
# Activate via WordPress admin or WP-CLI
|
||||
wp plugin activate wc-tier-and-package-prices
|
||||
```
|
||||
|
||||
## What's Included
|
||||
|
||||
### Core Features
|
||||
- ✅ Tier pricing with optional labels (quantity-based discounts)
|
||||
- ✅ Package pricing with quantity restrictions (fixed-price bundles)
|
||||
- ✅ Clickable tier rows with auto-quantity fill
|
||||
- ✅ WooCommerce Blocks full support (cart, mini-cart, checkout)
|
||||
- ✅ Twig template engine for secure templating
|
||||
- ✅ WooCommerce HPOS (High-Performance Order Storage) compatible
|
||||
- ✅ Quantity restriction enforcement
|
||||
- ✅ "View Options" catalog buttons for restricted products
|
||||
- ✅ Multilingual support (3 languages)
|
||||
|
||||
### Translations
|
||||
- 🇺🇸 English (US)
|
||||
- 🇩🇪 German (Germany)
|
||||
- 🇨🇭 German (Switzerland, Informal)
|
||||
|
||||
### Production Ready
|
||||
- ✅ Optimized autoloader
|
||||
- ✅ No development dependencies
|
||||
- ✅ Compiled Twig templates support
|
||||
- ✅ Tested with WooCommerce 8.0 - 10.x
|
||||
- ✅ Tested with WordPress 6.0 - 6.9.x
|
||||
- ✅ PHP 7.4+ compatible
|
||||
- ✅ Block-based themes compatible
|
||||
|
||||
## Package Contents
|
||||
|
||||
```
|
||||
wc-tier-and-package-prices/
|
||||
├── assets/ # CSS and JavaScript
|
||||
│ ├── css/
|
||||
│ │ ├── admin.css
|
||||
│ │ └── frontend.css
|
||||
│ └── js/
|
||||
│ ├── admin.js
|
||||
│ └── frontend.js
|
||||
├── includes/ # PHP classes
|
||||
│ ├── class-wc-tpp-admin.php
|
||||
│ ├── class-wc-tpp-settings.php
|
||||
│ ├── class-wc-tpp-cart.php
|
||||
│ ├── class-wc-tpp-frontend.php
|
||||
│ ├── class-wc-tpp-product-meta.php
|
||||
│ └── class-wc-tpp-template-loader.php
|
||||
├── languages/ # Translation files
|
||||
│ ├── wc-tier-package-prices-de_CH_informal.po
|
||||
│ ├── wc-tier-package-prices-de_CH_informal.mo
|
||||
│ ├── wc-tier-package-prices-de_DE.po
|
||||
│ ├── wc-tier-package-prices-de_DE.mo
|
||||
│ ├── wc-tier-package-prices-en_US.po
|
||||
│ ├── wc-tier-package-prices-en_US.mo
|
||||
│ └── wc-tier-package-prices.pot
|
||||
├── templates/ # Twig templates
|
||||
│ ├── admin/
|
||||
│ │ ├── tier-row.twig
|
||||
│ │ └── package-row.twig
|
||||
│ └── frontend/
|
||||
│ ├── pricing-table.twig
|
||||
│ ├── tier-pricing-table.twig
|
||||
│ └── package-pricing-display.twig
|
||||
├── vendor/ # Composer dependencies
|
||||
│ └── twig/twig/
|
||||
├── CHANGELOG.md
|
||||
├── INSTALLATION.md
|
||||
├── QUICKSTART.md
|
||||
├── USAGE_EXAMPLES.md
|
||||
├── README.md
|
||||
├── composer.json
|
||||
└── wc-tier-and-package-prices.php
|
||||
```
|
||||
|
||||
## System Requirements
|
||||
|
||||
| Requirement | Minimum Version | Tested Up To |
|
||||
|-------------|----------------|--------------|
|
||||
| WordPress | 6.0+ | 6.9.x |
|
||||
| PHP | 7.4+ | 8.x |
|
||||
| WooCommerce | 8.0+ | 10.x |
|
||||
| MySQL | 5.6+ | 8.x |
|
||||
|
||||
## Support
|
||||
|
||||
- **Documentation:** See README.md, INSTALLATION.md, QUICKSTART.md, USAGE_EXAMPLES.md
|
||||
- **Repository:** https://src.bundespruefstelle.ch/magdev/wc-tier-package-prices
|
||||
- **Author:** Marco Graetsch
|
||||
|
||||
## Version History
|
||||
|
||||
### 1.1.20 (2025-12-23) - Current Release
|
||||
- **CRITICAL FIX:** WooCommerce Blocks fatal error resolved
|
||||
- Fixed filter signature for `woocommerce_store_api_product_quantity_editable`
|
||||
- Full compatibility with WooCommerce Store API and block-based cart/checkout
|
||||
- Enhanced stability for block-based themes
|
||||
|
||||
### 1.1.7 (2025-12-22)
|
||||
- Added optional tier labels for enhanced UX
|
||||
- Clickable tier rows with auto-quantity fill
|
||||
- Add to Cart button auto-disable for invalid quantities
|
||||
|
||||
### 1.1.4 (2025-12-22)
|
||||
- WooCommerce Blocks support (cart, mini-cart, checkout)
|
||||
- Enhanced "View Options" button styling
|
||||
|
||||
### 1.1.0 (2025-12-21)
|
||||
- Package quantity restrictions (global and per-product)
|
||||
- Quantity field hiding for restricted products
|
||||
- Server-side validation for package quantities
|
||||
|
||||
### 1.0.1 (2025-12-21)
|
||||
- Added Twig template engine
|
||||
- Added Swiss German translation
|
||||
- Improved template organization
|
||||
- Enhanced security with auto-escaping
|
||||
|
||||
### 1.0.0 (2025-12-21)
|
||||
- Initial release
|
||||
- Tier pricing functionality
|
||||
- Package pricing functionality
|
||||
- German and English translations
|
||||
|
||||
For complete version history, see [CHANGELOG.md](../CHANGELOG.md)
|
||||
|
||||
## License
|
||||
|
||||
GPL v2 or later - https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
---
|
||||
|
||||
**Note:** All packages are production-ready with optimized autoloaders and no development dependencies included.
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
e6cfc9b88df9e7763be0cd56517ce8ab wc-tier-and-package-prices-1.0.1.zip
|
||||
@@ -1 +0,0 @@
|
||||
92c1385d92527e77646e37f23c1bd1555a4290a5ec9314c0ee6ed896ded55e88 wc-tier-and-package-prices-1.0.1.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
830f443ce4b65e2ca9cfede3257bc4f5 wc-tier-and-package-prices-1.0.2.zip
|
||||
@@ -1 +0,0 @@
|
||||
c1a5339da10b3625156b8fff4ec848e4a1318d6edc497bd5026cfe0a3ef39daa wc-tier-and-package-prices-1.0.2.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
ef68125c54b0c10f04ba82d48a98b4aa wc-tier-and-package-prices-1.1.0.zip
|
||||
@@ -1 +0,0 @@
|
||||
da6b462f3dc297b282ed0da258b78fd9f2f82f3e76289c4c8fadd1ac9e02c55b wc-tier-and-package-prices-1.1.0.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
51c4f8a7c3ccede2d2005f2fe3ebe44e wc-tier-and-package-prices-1.1.1.zip
|
||||
@@ -1 +0,0 @@
|
||||
b951f8b7ddd2bad6b3415d4583709fdf88f66aea4eae70110c903757ff53e045 wc-tier-and-package-prices-1.1.1.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
81be5283219cfa722f6d382a788e7dc1 releases/wc-tier-and-package-prices-1.1.10.zip
|
||||
@@ -1 +0,0 @@
|
||||
2d3b01e61c8a03a8f20bc99b2019ca50fa08ecd68188feb2d2105dfe35d36f0d releases/wc-tier-and-package-prices-1.1.10.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
4a0c0b07b29d4b7046f9d3ff3f091321 releases/wc-tier-and-package-prices-1.1.11.zip
|
||||
@@ -1 +0,0 @@
|
||||
3da9423d136a2ff254b61577ba1f84d4c0f0d1e57bae361ac29c90327feeeceb releases/wc-tier-and-package-prices-1.1.11.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
c1c0b5880636686227246be2c37dc42a releases/wc-tier-and-package-prices-1.1.12.zip
|
||||
@@ -1 +0,0 @@
|
||||
05b32356d46803dbb7fa17c13a2d8da96f77126746e2895e2f5c6dd0e7b490ff releases/wc-tier-and-package-prices-1.1.12.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
8572eed399554905fbf331d18f0677a0 wc-tier-and-package-prices-1.1.13.zip
|
||||
@@ -1 +0,0 @@
|
||||
83e29b2e40dd43e77bd83cd03d4ccc54ef53555b55544eba4d38161101f79f20 wc-tier-and-package-prices-1.1.13.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
e0cc51d1493ed35ab254220d9f46997b wc-tier-and-package-prices-1.1.14.zip
|
||||
@@ -1 +0,0 @@
|
||||
8a2ce7438ee49baffdcaaf323b6426d73dd1cf704bea94a80fcce27a42c097ad wc-tier-and-package-prices-1.1.14.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
15fa0e0933c85b23f66940bf43810835 wc-tier-and-package-prices-1.1.15.zip
|
||||
@@ -1 +0,0 @@
|
||||
a419579111ad20b127411e1078ca99187156d606381549e6bf147ffc3bd58de1 wc-tier-and-package-prices-1.1.15.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
d30a90715dbcd46a1dfd19f025897530 wc-tier-and-package-prices-1.1.16.zip
|
||||
@@ -1 +0,0 @@
|
||||
e2ad36e049a902b8e287154867ef72c0e169766508781e223176a2a753b60915 wc-tier-and-package-prices-1.1.16.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
9adbb9aad13b8d141cfabfdf53643480 wc-tier-and-package-prices-1.1.17.zip
|
||||
@@ -1 +0,0 @@
|
||||
985a195bf98d4dbc0a7afa90173efcda472f4c769adf3c833fa6a99ba9d44095 wc-tier-and-package-prices-1.1.17.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
ec4bb1d78a3c27488244b44971916ffd wc-tier-and-package-prices-1.1.18.zip
|
||||
@@ -1 +0,0 @@
|
||||
7d942002edd866c2b6f3192ba010fe64058b7433c5ac776a48e9c3c41f4e2fda wc-tier-and-package-prices-1.1.18.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
c61c3a059429d8dacdce71d4acce401e wc-tier-and-package-prices-1.1.19.zip
|
||||
@@ -1 +0,0 @@
|
||||
0e8bc4ccd233d388238e800cd0e0a129f9e8da14008e7164db7934a48ca8223a wc-tier-and-package-prices-1.1.19.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
eee69fcf391b3f3df9380306ffb31b1b wc-tier-and-package-prices-1.1.2.zip
|
||||
@@ -1 +0,0 @@
|
||||
40ffd29ebc6af635f689472040acd220ae1c8df2f0d852fab4b43ce0fb5fe739 wc-tier-and-package-prices-1.1.2.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
bfdeee75bfe3795c9ab9abfe47f12a41 wc-tier-and-package-prices-1.1.20.zip
|
||||
@@ -1 +0,0 @@
|
||||
953859241d15d76ec4783c72bac851ddd69e5a1f7b119ee4f9ebd30c7fabed17 wc-tier-and-package-prices-1.1.20.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
16813b3ed0d1001d5f60194d61d36fc2 wc-tier-and-package-prices-1.1.21.zip
|
||||
@@ -1 +0,0 @@
|
||||
e0063852a9ac23b1fd994471a2829f9dcbe26316f00ddee2d00f77c7c6a47c8f wc-tier-and-package-prices-1.1.21.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
7d5a5c7980a91dff5167c90a6f3290b0 wc-tier-and-package-prices-1.1.22.zip
|
||||
@@ -1 +0,0 @@
|
||||
f94dee838a3f288b4acb3b3d9a4e88ef987f9b1bc918403186014d8d43fee6d9 wc-tier-and-package-prices-1.1.22.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
dfec91be7e375b09613ba81cfebbe013 wc-tier-and-package-prices-1.1.3.zip
|
||||
@@ -1 +0,0 @@
|
||||
7938542680b71a7b73269c96a4dff78f2222ac8409092011c5e40e97a5e465aa wc-tier-and-package-prices-1.1.3.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
3e5bc2cae17ecb81b729c3fdc979df23 wc-tier-and-package-prices-1.1.4.zip
|
||||
@@ -1 +0,0 @@
|
||||
19553b2fed1c6ca20a8168eab8c570cb0302be801322cd41d86cec40b70ff162 wc-tier-and-package-prices-1.1.4.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
e9f8a69e4be107d857d3beb671d5a9fe wc-tier-and-package-prices-1.1.5.zip
|
||||
@@ -1 +0,0 @@
|
||||
a13d71f3f65c7cf41613f88d7bcfcb112acfefb800fa6b95932f44a47cf764f3 wc-tier-and-package-prices-1.1.5.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
dbea10acffdc849f9aa387d128cb6d6e wc-tier-and-package-prices-1.1.6.zip
|
||||
@@ -1 +0,0 @@
|
||||
730e366764449ac963bc85848ac8a91f654e4b35500ed3132a280ab4f215c80c wc-tier-and-package-prices-1.1.6.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
c593b6fc730133ecaf772f77d5659080 wc-tier-and-package-prices-1.1.7.zip
|
||||
@@ -1 +0,0 @@
|
||||
00e7c473a8b0fc23eb1cd52f4b38db030618ed142a9a9fdfd9b1aa4c5849ec70 wc-tier-and-package-prices-1.1.7.zip
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
666e1acad9f349982463b65d0e3e7fa3 wc-tier-and-package-prices-1.1.8.zip
|
||||
@@ -1 +0,0 @@
|
||||
2c100d0d100a6fd7bd8f9c9b154d878a675bc795c5fddb19314bc9991b9a60ba wc-tier-and-package-prices-1.1.8.zip
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user