19 Commits

Author SHA1 Message Date
74c14581f1 Release version 1.3.0 - License management and settings sub-tabs
Breaking Changes:
- PHP 8.3+ now required (previously 7.4+)

Added:
- License management integration using magdev/wc-licensed-product-client
- Settings page split into General and License sub-tabs
- License validation and activation via AJAX
- PHP version check with admin notice

Changed:
- Refactored settings class to use modern WooCommerce patterns
- Updated all translations with new license-related strings

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:39:12 +01:00
0dbe18d954 Remove releases from git tracking and clean up MD5 checksums
- Remove all release packages from git tracking (kept locally)
- Delete MD5 checksum files, keeping only SHA256
- Update .gitignore to exclude releases/ directory
- Update CLAUDE.md release documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 19:17:04 +01:00
63c8137f4e Document v1.2.9 learnings in CLAUDE.md
Added three new critical sections documenting lessons learned during v1.2.9 development:

1. WordPress Translation Functions with printf
   - Correct pattern: printf(esc_html__('Text (%s)', 'domain'), value)
   - Wrong pattern: printf(__('Text (%s)', 'domain'), value) - missing text domain
   - Explains why text domain must be in translation function
   - Shows proper output escaping with esc_html

2. Twig Translation Filters and HTML Entity Encoding
   - Explains why translation filters encode special characters in concatenated strings
   - Correct pattern: {{ 'text ' ~ currency_symbol }} (no translation filter)
   - Wrong pattern: {{ ('text ' ~ currency_symbol)|__() }} causes HTML entity encoding
   - Rule: Only translate static text, not concatenated dynamic values

3. Defensive Programming for POST Data Processing
   - Compares v1.2.8 (branching) vs v1.2.9 (defensive) patterns
   - Shows why single decision point is better than multiple branches
   - Key principles: initialize early, minimize branching, guaranteed execution
   - Pattern: initialize → conditionally populate → unconditionally act

Also corrected v1.2.8 examples that had wrong patterns, noting they were fixed in v1.2.9.

These patterns prevent future bugs and ensure consistent, secure implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 05:08:09 +01:00
b2efb89d59 Update CLAUDE.md and add v1.2.9 release package
- Updated Current Version to 1.2.9
- Moved v1.2.8 bugs to 'Bugfixes (Completed in v1.2.9)' section
- Added detailed fix descriptions for both bugs:
  * Translation fix with esc_html__() and proper text domain
  * Placeholder encoding fix by removing translation filter
  * Variation save logic refactoring with defensive programming
- Updated roadmap section to v1.2.10+
- Added release package and checksums:
  * wc-tier-and-package-prices-1.2.9.zip (441KB, 383 files)
  * MD5: 073fbf114a32d99cd8ced683a1efa19c
  * SHA256: 00d2568e9acfd7fc05c88b9048a6a281d007b55dec9c4c7a4a55cb515e013e97

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 05:04:20 +01:00
0f5779dc56 Release version 1.2.9 - Translation and deletion fixes
## Bugfixes

1. **Price Header Not Translated**
   - Fixed translation function placement in printf statements
   - Changed from printf(__()) to printf(esc_html__())
   - Headers now display in administrator's configured language

2. **Placeholder HTML Entity Encoding**
   - Currency symbols were showing as HTML entities (e.g., &euro;)
   - Removed translation filter from concatenated placeholder strings
   - Placeholders are example values that should not be translated

3. **Variation Pricing Still Not Deletable (Regression)**
   - Despite v1.2.8 fix, edge cases remained due to conditional branching
   - Refactored save logic to be more defensive
   - Always initializes arrays, then unconditionally updates or deletes
   - Guarantees proper cleanup regardless of POST data structure

## Technical Details

- Updated all 6 table headers: printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), ...)
- Removed |__() filter from Twig placeholder concatenations
- Refactored save_variation_pricing_fields() with simplified logic:
  * Initialize arrays at start
  * Populate only if valid POST data exists
  * Always perform update (if !empty) or delete (if empty)
- Added is_array() check for extra safety

## Changed Files

- includes/class-wc-tpp-product-meta.php
- templates/admin/tier-row.twig
- templates/admin/package-row.twig

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 05:02:50 +01:00
d71f2c01dc fixed markdown syntax 2025-12-30 01:34:46 +01:00
82c8008fed added wp-core symlink 2025-12-30 01:33:24 +01:00
4871b7957d added skills to end sessions 2025-12-30 01:32:03 +01:00
f7508a3d9c Document v1.2.8 learnings in CLAUDE.md
Added two new critical sections documenting lessons learned during v1.2.8 development:

1. Currency Symbol Display
   - Proper pattern for displaying currency in table headers using printf()
   - How to pass currency_symbol to Twig templates
   - Correct concatenation in Twig placeholders
   - List of affected render methods

2. Post Meta Deletion vs. Empty Arrays
   - Explains WordPress distinction between deleted meta and empty arrays
   - Shows wrong pattern (saving empty arrays) vs correct pattern (deleting meta)
   - Why this matters for database cleanliness and bug prevention
   - Affected methods in save_tier_package_fields() and save_variation_pricing_fields()

These patterns prevent future bugs and ensure consistent implementation across the codebase.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 01:31:11 +01:00
23f81ce58c Add v1.2.8 release package and checksums
- Release package: wc-tier-and-package-prices-1.2.8.zip (440KB, 383 files)
- MD5: d412c85ef32b2e79e17227749265919f
- SHA256: 0c47e2a966c485b377beaffb56703a130158a15e7ffe9d95b43dea84f9229e9c

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 01:29:10 +01:00
9e96ff3321 Merge branch 'dev' 2025-12-30 01:28:09 +01:00
cf11cb5bd1 Update CLAUDE.md for v1.2.8 release
- Updated Current Version to 1.2.8
- Moved v1.2.7 bugs to 'Bugfixes (Completed in v1.2.8)' section
- Added detailed fix descriptions for both bugs
- Updated roadmap section to v1.2.9+

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 01:26:48 +01:00
f26574aa4b Release version 1.2.8 - Currency display and data deletion fixes
Fixed two important bugs reported in v1.2.7:

Bug 1: Currency Symbol Missing in Admin Headers and Placeholders
- Table headers now show "Price (CURRENCY)" instead of just "Price"
- Input placeholders include currency symbol (e.g., "9.99 $")
- Better UX for multi-currency stores

Bug 2: Variation Pricing Data Not Deleted Properly (Critical)
- Empty pricing arrays were being saved instead of deleted
- Fixed save logic to check if arrays are empty after filtering
- Properly deletes post meta when all entries are removed
- Affects simple products, variable parents, and variations

Technical changes:
- Updated all table headers with currency symbol display
- Modified all render methods to pass currency_symbol to templates
- Updated Twig templates to use currency in placeholders
- Fixed save_tier_package_fields() and save_variation_pricing_fields()
- Added !empty() checks before update_post_meta() calls

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 01:23:55 +01:00
348158050e added new permitted shell command 2025-12-30 01:06:31 +01:00
d7a61f29b4 Merge branch 'dev' 2025-12-30 01:05:21 +01:00
10a1f94a31 Update CLAUDE.md with v1.2.7 learnings and roadmap
Updated documentation to reflect:
- Current version is now 1.2.7
- v1.2.5 issues (table headers, parent pricing forms) are FIXED in v1.2.6/v1.2.7
- Translation updates completed in v1.2.7
- Added critical section on WooCommerce product type-specific hooks

Key learnings documented:
- woocommerce_product_options_pricing only fires for simple products
- woocommerce_product_options_general_product_data fires for all product types
- Proper hook selection is critical for variable product parent UI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 01:04:48 +01:00
ae946683b3 Update translation files with new strings from v1.2.6 and v1.2.7
Added translations for variable product parent pricing features:
- "Default Tier & Package Pricing for All Variations"
- "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
- "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
- "Restrict to Package Quantities (Default)"
- "Default restriction setting for all variations. Only allow quantities defined in packages above."

Updated all available language files:
- wc-tier-package-prices.pot (v1.2.7)
- de_CH, de_CH_informal, de_DE, de_DE_informal (German)
- fr_CH (French, Switzerland)
- it_CH (Italian, Switzerland)
- en_US (English, US)

Compiled all .po files to .mo for production use.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 01:01:49 +01:00
71ea40598f Merge branch 'dev' 2025-12-30 00:48:46 +01:00
e5aca708cc Release version 1.2.7 - Fix v1.2.6 regressions (both issues still not working)
Fixed both critical issues that were not resolved in v1.2.6:

1. Variable Product Forms Still Not Showing (Critical)
   - v1.2.6 used wrong hook (woocommerce_product_options_pricing)
   - That hook only fires for simple products, not variable products
   - Changed to woocommerce_product_options_general_product_data
   - This hook fires for all product types after general tab
   - Forms now appear correctly for variable product parents

2. Table Headers Still Visible When Empty (Critical)
   - CSS :has() pseudo-class wasn't working reliably
   - Implemented JavaScript + CSS class approach instead
   - Added updateTableHeaders() function that toggles has-rows class
   - Headers hide by default, show only when table has rows
   - Function called on page load and after all add/remove operations
   - Works across all browsers without modern CSS requirements

Changed files:
- includes/class-wc-tpp-product-meta.php - Fixed WooCommerce hook
- assets/css/admin.css - Class-based header visibility
- assets/js/admin.js - Added updateTableHeaders() and parent handlers

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 00:48:46 +01:00
124 changed files with 2019 additions and 398 deletions

View File

@@ -39,7 +39,10 @@
"Bash('wc-tier-and-package-prices/logs/*' )", "Bash('wc-tier-and-package-prices/logs/*' )",
"Bash('wc-tier-and-package-prices/templates/cache/*' )", "Bash('wc-tier-and-package-prices/templates/cache/*' )",
"Bash('wc-tier-and-package-prices/composer.lock' )", "Bash('wc-tier-and-package-prices/composer.lock' )",
"Bash('*/wordpress/*')" "Bash('*/wordpress/*')",
"Bash(echo:*)",
"Skill(fix-session)",
"Skill(fix-session:*)"
] ]
} }
} }

5
.gitignore vendored Normal file → Executable file
View File

@@ -32,3 +32,8 @@ notes.*
# local code # local code
wordpress wordpress
core
wp-core
# Releases (not tracked in git)
/releases/

View File

@@ -5,6 +5,190 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [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
- **Price Header Not Translated**: The "Price (%s)" header in admin tables was not being properly translated because the translation function was placed incorrectly within the printf statement. Changed from `printf(__('Price (%s)', ...), ...)` to `printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), ...)` to ensure proper translation while maintaining the currency placeholder functionality.
- **Placeholder HTML Entity Encoding Issue**: Currency symbols in price input placeholders were being displayed as HTML entities (e.g., "&euro;" instead of "€") because the concatenated string was being passed through the translation filter which was encoding special characters. Removed the unnecessary translation filter from concatenated placeholder strings since they are example values that should not be translated.
- **Variation Pricing Still Not Deletable (Regression from v1.2.8)**: Despite the fix in v1.2.8, variation pricing data was still not being properly deleted in all scenarios. The issue was with the conditional logic structure - the code had separate `if/else` branches that could fail in edge cases. Restructured the save logic to be more defensive: initialize arrays at the start, populate only if valid POST data exists, then unconditionally perform either update (if not empty) or delete (if empty). This guarantees proper cleanup regardless of POST data structure.
### Technical Details
**Translation Fix**:
- Changed all 6 instances of `printf(__('Price (%s)', 'wc-tier-package-prices'), ...)`
- To: `printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), ...)`
- The `__()` function now receives the text domain parameter correctly
- Added `esc_html` for proper output escaping
**Placeholder Encoding Fix**:
- Changed tier-row.twig placeholder from: `{{ ('e.g., 9.99 ' ~ currency_symbol)|__('wc-tier-package-prices') }}`
- To: `{{ 'e.g., 9.99 ' ~ currency_symbol }}`
- Changed package-row.twig placeholder from: `{{ ('e.g., 99.99 ' ~ currency_symbol)|__('wc-tier-package-prices') }}`
- To: `{{ 'e.g., 99.99 ' ~ currency_symbol }}`
- Removed translation filter from concatenated example values to prevent HTML entity encoding
**Variation Save Logic Refactor**:
```php
// Old pattern (v1.2.8):
if (isset($_POST['wc_tpp_tiers'][$loop])) {
$tiers = array();
// ... populate tiers ...
if (!empty($tiers)) {
update_post_meta(...);
} else {
delete_post_meta(...);
}
} else {
delete_post_meta(...);
}
// New pattern (v1.2.9):
$tiers = array();
if (isset($_POST['wc_tpp_tiers'][$loop]) && is_array($_POST['wc_tpp_tiers'][$loop])) {
// ... populate tiers ...
}
// Always perform update or delete based on final state
if (!empty($tiers)) {
update_post_meta(...);
} else {
delete_post_meta(...);
}
```
- Eliminated conditional branching that could miss edge cases
- Added explicit `is_array()` check for extra safety
- Guaranteed that one of update_post_meta() or delete_post_meta() is always called
- Applied to both `save_variation_pricing_fields()` for tier and package pricing
**User Impact**:
- Price headers now display in the administrator's configured language
- Currency symbols display correctly without HTML encoding in placeholders
- Variation pricing deletion now works reliably in all scenarios
- Database remains clean with no orphaned empty arrays
### Changed Files
- `includes/class-wc-tpp-product-meta.php` - Fixed translation function calls in 6 table headers; refactored save_variation_pricing_fields() logic for tiers and packages
- `templates/admin/tier-row.twig` - Removed translation filter from placeholder concatenation
- `templates/admin/package-row.twig` - Removed translation filter from placeholder concatenation
## [1.2.8] - 2025-12-30
### Fixed
- **Currency Symbol Missing in Admin Headers and Placeholders**: Table headers in the admin pricing configuration now display "Price (CURRENCY)" instead of just "Price", making it immediately clear which currency is being used. Price input placeholders now show currency symbol (e.g., "e.g., 9.99 $" instead of "e.g., 9.99"), providing better UX for administrators configuring pricing in different currencies.
- **Variation Pricing Data Not Deleted Properly (Critical)**: When administrators deleted all tier or package pricing entries from a variation (or simple/parent product) and saved, the empty pricing data was still stored in the database instead of being deleted. This caused variations to retain deleted pricing rules. The save logic now properly detects when the filtered pricing arrays are empty after removing invalid entries and deletes the post meta instead of saving empty arrays.
### Technical Details
**Currency Symbol Enhancement**:
- Updated all table headers to use `printf(__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol())`
- Modified `render_tier_row()` and `render_package_row()` methods to pass `currency_symbol` to Twig templates
- Updated `render_variation_tier_row()` and `render_variation_package_row()` with same currency symbol parameter
- Changed Twig template placeholders from `'e.g., 9.99'` to `('e.g., 9.99 ' ~ currency_symbol)`
- Affects all pricing contexts: simple products, variable product parents, and variations
**Pricing Deletion Fix**:
- Modified `save_tier_package_fields()` method (simple/parent products) to check `if (!empty($tiers))` before saving
- Modified `save_variation_pricing_fields()` method (variations) with same empty check logic
- Changed logic from "save on isset, delete otherwise" to "filter entries, then save if not empty, delete if empty"
- Applies to both tier pricing and package pricing for all product types
- Root cause was filtering out empty entries but still calling `update_post_meta()` with an empty array
**User Impact**:
- Administrators see currency symbol in all pricing configuration interfaces
- Clear indication of which currency prices should be entered in
- Deleting all pricing rules now properly removes them from the database
- No orphaned pricing data remains after deletion
- Works correctly for simple products, variable product parents, and variations
### Changed Files
- `includes/class-wc-tpp-product-meta.php` - Added currency symbol to all table headers; updated all render methods to pass currency symbol; fixed empty array deletion logic in both save methods
- `templates/admin/tier-row.twig` - Updated placeholder to include currency symbol
- `templates/admin/package-row.twig` - Updated placeholder to include currency symbol
## [1.2.7] - 2025-12-30
### Fixed
- **Variable Product Forms Still Not Showing (Critical)**: The v1.2.6 fix used the wrong WooCommerce hook. The `woocommerce_product_options_pricing` hook only fires for simple products, not variable products. Changed to use `woocommerce_product_options_general_product_data` hook which fires for all product types after the general tab, allowing the code to check product type and conditionally display the parent pricing fields.
- **Table Headers Still Visible When Empty (Critical)**: The CSS `:has()` pseudo-class approach from v1.2.6 wasn't working reliably across all browsers. Implemented a JavaScript-based solution that adds/removes a `has-rows` class on tables based on whether they contain pricing rules. Headers now hide by default and show only when the table has rows, with JavaScript updating the state when rows are added or removed.
### Technical Details
**Variable Product Hook Fix**:
- Changed from `woocommerce_product_options_pricing` to `woocommerce_product_options_general_product_data`
- The general product data hook fires for all product types
- Method still checks `$product->is_type('variable')` to only show for variable products
- This ensures forms appear in the correct location in the WordPress admin
**Table Header Visibility Fix**:
- Replaced CSS-only `:has()` solution with JavaScript + CSS class approach
- CSS now uses `.wc-tpp-tiers-table.has-rows thead` to show headers
- Added `updateTableHeaders()` JavaScript function that checks row count and toggles class
- Function is called on page load and after any add/remove row operation
- Works reliably across all browsers without requiring modern CSS features
**User Impact**:
- Variable product parent pricing forms now actually appear in the WordPress admin
- Table headers properly hide when empty and show when populated
- No browser compatibility issues - works in all modern browsers
### Changed Files
- `includes/class-wc-tpp-product-meta.php` - Changed hook from `woocommerce_product_options_pricing` to `woocommerce_product_options_general_product_data`
- `assets/css/admin.css` - Replaced `:has()` pseudo-class with class-based approach
- `assets/js/admin.js` - Added `updateTableHeaders()` function and calls after all row operations; added handlers for variable product parent forms
## [1.2.6] - 2025-12-30 ## [1.2.6] - 2025-12-30
### Fixed ### Fixed

296
CLAUDE.md
View File

@@ -1,7 +1,7 @@
# WooCommerce Tier and Package Prices - AI Context Document # WooCommerce Tier and Package Prices - AI Context Document
**Last Updated:** 2025-12-30 **Last Updated:** 2026-01-25
**Current Version:** 1.2.5 **Current Version:** 1.3.0
**Author:** Marco Graetsch **Author:** Marco Graetsch
**Project Status:** Production-ready WordPress plugin **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. 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.3.1
- TBD
## Technical Stack ## Technical Stack
- **Language:** PHP 7.4+ - **Language:** PHP 8.3+
- **Framework:** WordPress Plugin API - **Framework:** WordPress Plugin API
- **E-commerce:** WooCommerce 8.0+ (tested up to 10.x) - **E-commerce:** WooCommerce 8.0+ (tested up to 10.x)
- **Template Engine:** Twig 3.0 (via Composer) - **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 ```json
{ {
"twig/twig": "^3.0", "twig/twig": "^3.0",
"symfony/polyfill-ctype": "^1.x", "magdev/wc-licensed-product-client": "^0.1",
"symfony/polyfill-mbstring": "^1.x" "symfony/http-client": "^7.0",
"psr/log": "^3.0",
"psr/cache": "^3.0",
"psr/http-client": "^1.0"
} }
``` ```
@@ -355,8 +366,8 @@ Update version in 3 places:
**CRITICAL:** The zip command must be run from the **parent directory** of the plugin folder to create proper archive structure. **CRITICAL:** The zip command must be run from the **parent directory** of the plugin folder to create proper archive structure.
```bash ```bash
# From parent directory (/home/magdev/workspaces/node) # From parent directory (/home/magdev/workspaces/php)
cd /home/magdev/workspaces/node cd /home/magdev/workspaces/php
# Create zip excluding dev files - note the correct path structure # 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/ \ zip -r wc-tier-and-package-prices/releases/wc-tier-and-package-prices-X.X.X.zip wc-tier-and-package-prices/ \
@@ -379,9 +390,8 @@ zip -r wc-tier-and-package-prices/releases/wc-tier-and-package-prices-X.X.X.zip
# Return to project directory # Return to project directory
cd wc-tier-and-package-prices cd wc-tier-and-package-prices
# Generate checksums # Generate SHA256 checksum
cd releases 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 sha256sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.sha256
cd .. cd ..
``` ```
@@ -546,11 +556,13 @@ When modifying admin input fields in Twig templates, use WooCommerce's standard
**CRITICAL LESSON from v1.2.4:** WooCommerce's core admin CSS uses high-specificity selectors that require `!important` to override. **CRITICAL LESSON from v1.2.4:** WooCommerce's core admin CSS uses high-specificity selectors that require `!important` to override.
**Problem Symptoms:** **Problem Symptoms:**
- CSS rules not applying despite correct selectors - CSS rules not applying despite correct selectors
- Styles work in simple cases but fail with WooCommerce elements - Styles work in simple cases but fail with WooCommerce elements
- Browser DevTools shows rule crossed out or overridden - Browser DevTools shows rule crossed out or overridden
**Diagnostic Steps:** **Diagnostic Steps:**
1. Inspect element in browser DevTools 1. Inspect element in browser DevTools
2. Check "Computed" tab to see which styles are actually applied 2. Check "Computed" tab to see which styles are actually applied
3. Look for crossed-out rules in "Styles" tab (indicates override) 3. Look for crossed-out rules in "Styles" tab (indicates override)
@@ -559,6 +571,7 @@ When modifying admin input fields in Twig templates, use WooCommerce's standard
**Solution Patterns:** **Solution Patterns:**
**For Table Styling:** **For Table Styling:**
```css ```css
/* ❌ This will likely be overridden */ /* ❌ This will likely be overridden */
.wc-tpp-tiers-table { .wc-tpp-tiers-table {
@@ -582,6 +595,7 @@ When modifying admin input fields in Twig templates, use WooCommerce's standard
``` ```
**For Float-Based Layouts:** **For Float-Based Layouts:**
```css ```css
/* ❌ Float positioning is hard to control precisely */ /* ❌ Float positioning is hard to control precisely */
.woocommerce-help-tip { .woocommerce-help-tip {
@@ -606,6 +620,7 @@ label[for="_wc_tpp_restrict_to_packages"] {
``` ```
**General Rules:** **General Rules:**
1. **Always test in actual WordPress admin** - browser preview may not show WooCommerce's CSS 1. **Always test in actual WordPress admin** - browser preview may not show WooCommerce's CSS
2. **Target all related elements** - tables require styling on `table`, `thead`, `tbody`, `tr`, `th`, `td` 2. **Target all related elements** - tables require styling on `table`, `thead`, `tbody`, `tr`, `th`, `td`
3. **Use `!important` sparingly but don't fear it** - sometimes it's the only way to override WooCommerce core 3. **Use `!important` sparingly but don't fear it** - sometimes it's the only way to override WooCommerce core
@@ -613,6 +628,7 @@ label[for="_wc_tpp_restrict_to_packages"] {
5. **Check across browsers** - table rendering can vary between Chrome/Firefox/Safari 5. **Check across browsers** - table rendering can vary between Chrome/Firefox/Safari
**When Styles Don't Apply:** **When Styles Don't Apply:**
- First verify selector is correct (DevTools should show rule, even if crossed out) - First verify selector is correct (DevTools should show rule, even if crossed out)
- If selector is correct but crossed out, increase specificity or add `!important` - If selector is correct but crossed out, increase specificity or add `!important`
- If selector doesn't appear at all, check file is enqueued and cache is cleared - If selector doesn't appear at all, check file is enqueued and cache is cleared
@@ -670,9 +686,10 @@ Based on v1.1.22, v1.2.2, and v1.2.3 release experience, here's the complete wor
- `composer.json` - Version bump - `composer.json` - Version bump
- `CHANGELOG.md` - Release notes - `CHANGELOG.md` - Release notes
- `CLAUDE.md` - Version and roadmap updates - `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.) - 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 ### Release Package Creation - Critical Notes
**IMPORTANT:** The zip command must be run from the **parent directory** to create proper archive structure. **IMPORTANT:** The zip command must be run from the **parent directory** to create proper archive structure.
@@ -692,7 +709,7 @@ zip -r wc-tier-and-package-prices/releases/wc-tier-and-package-prices-X.X.X.zip
**Critical Exclusions:** **Critical Exclusions:**
- `*/wordpress/*` - MUST be excluded! The project has a symlink to WordPress installation that zip will follow, creating 129MB+ packages instead of ~430KB - `*/wordpress/*` and `*/core/*` - MUST be excluded! The project has a symlink to WordPress installation that zip will follow, creating 129MB+ packages instead of ~430KB
- `.git/*` - All git metadata (multiple patterns needed for reliability) - `.git/*` - All git metadata (multiple patterns needed for reliability)
- `.claude/*` and `CLAUDE.md` - Development documentation - `.claude/*` and `CLAUDE.md` - Development documentation
- `releases/*` - Prevents including previous releases in new ones - `releases/*` - Prevents including previous releases in new ones
@@ -765,13 +782,29 @@ Roadmap for the upcoming development.
2. ~~Make it possible to define tier or package prices on variable products in the parent product as a default for that product and all variants of it unless a variant has its own tier or package prices.~~**COMPLETED in v1.2.5** - Implemented parent product default pricing with automatic fallback. Variable products can define tier/package pricing once at parent level; variations inherit these defaults unless they have their own specific pricing. Added helper methods in cart class and updated all pricing/restriction checks to support parent fallback. 2. ~~Make it possible to define tier or package prices on variable products in the parent product as a default for that product and all variants of it unless a variant has its own tier or package prices.~~**COMPLETED in v1.2.5** - Implemented parent product default pricing with automatic fallback. Variable products can define tier/package pricing once at parent level; variations inherit these defaults unless they have their own specific pricing. Added helper methods in cart class and updated all pricing/restriction checks to support parent fallback.
##### Fixes for v1.2.5 ##### Bugfixes (Completed in v1.2.6 and v1.2.7)
1. The table headers in admin are still visible. 1. ~~Table headers in admin are still visible when empty.~~**FIXED in v1.2.7** - The CSS `:has()` pseudo-class approach from v1.2.5/v1.2.6 wasn't working reliably across all browsers. Implemented JavaScript-based solution that adds/removes `has-rows` class on tables. Headers now hide by default (CSS) and show only when table has rows (JavaScript toggles class). Function `updateTableHeaders()` is called on page load and after all add/remove row operations.
2. The parent product fallback on variable product is also not visible. 2. ~~Parent product pricing forms not visible in admin.~~**FIXED in v1.2.6 and v1.2.7** - The backend fallback logic from v1.2.5 was implemented but the admin UI to configure it was missing. Added `add_variable_parent_pricing_fields()` method that displays pricing forms for variable product parents. Fixed hook issue in v1.2.7: changed from `woocommerce_product_options_pricing` (only fires for simple products) to `woocommerce_product_options_general_product_data` (fires for all product types). Variable product parents now have a "Default Tier & Package Pricing for All Variations" section where defaults can be configured.
##### Planned Enhancements for v1.2.6+ ##### Translation Updates (Completed in v1.2.7)
1.**COMPLETED** - Updated all translation files (.pot, .po, .mo) with new strings from v1.2.6 and v1.2.7 for variable product parent pricing features. All 7 language variants updated with translations for "Default Tier & Package Pricing for All Variations" and related strings.
##### Bugfixes (Completed in v1.2.8)
1. ~~Add a Suffix with the current configured default currency to the table-header and form placeholder. Use the common currency notation in placeholder~~**FIXED in v1.2.8** - Updated all table headers in admin to display "Price (€)" format using `printf(__('Price (%s)'), get_woocommerce_currency_symbol())`. Modified all template render methods (tier_row, package_row, variation_tier_row, variation_package_row) to pass currency_symbol to Twig templates. Updated admin/tier-row.twig and admin/package-row.twig to concatenate currency symbol in price input placeholders (e.g., "e.g., 9.99 €"). Applied to simple products, variable parent products, and all variations.
2. ~~Already stored tier and package prices on the children of a variable product are still available after deletion. Looks like the storage mechanism has an error. This occurs only on the child product, not on the parent product.~~**FIXED in v1.2.8** - Fixed save logic in both `save_tier_package_fields()` and `save_variation_pricing_fields()` methods. Root cause: Empty arrays were being saved via `update_post_meta()` instead of being deleted. Changed logic from "save on isset, delete otherwise" to "filter entries, then save if not empty, delete if empty". Added `if (!empty($tiers))` and `if (!empty($packages))` checks before calling `update_post_meta()`. Now properly calls `delete_post_meta()` when all pricing entries are removed, preventing empty arrays from persisting in database.
##### Bugfixes (Completed in v1.2.9)
1. ~~The Price header in admin tables while configuring tier and package prices is not translated. Also the placeholder on the form elements for prices has the wrong encoding, the special characters on the placeholder are show in html-entity encoding.~~**FIXED in v1.2.9** - Fixed translation function placement in printf statements by changing from `printf(__('Price (%s)', ...), ...)` to `printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), ...)`. This ensures the text domain is passed correctly to the translation function while maintaining the currency placeholder functionality. Also removed the translation filter from concatenated placeholder strings in Twig templates (changed from `{{ ('e.g., 9.99 ' ~ currency_symbol)|__('wc-tier-package-prices') }}` to `{{ 'e.g., 9.99 ' ~ currency_symbol }}`) because example values should not be translated and the filter was causing HTML entity encoding of special characters.
2. ~~The tier and package prices for children of a variable product are still not deletable. After storing the product, the previously deleted rows are back again.~~**FIXED in v1.2.9** - Despite the fix in v1.2.8, edge cases remained due to conditional branching structure. Refactored `save_variation_pricing_fields()` with more defensive logic: initialize arrays at the start ($tiers = array()), populate only if valid POST data exists (with added is_array() check), then unconditionally perform either update_post_meta() (if !empty) or delete_post_meta() (if empty). This guarantees proper cleanup regardless of POST data structure and eliminates the if/else branching that could miss edge cases.
##### Planned Enhancements for v1.2.10+
1. Create different, selectable templates for tierprices and packages to use in the frontend. Make the new templates selectable globally on the settings-page, not per product. 1. Create different, selectable templates for tierprices and packages to use in the frontend. Make the new templates selectable globally on the settings-page, not per product.
@@ -789,6 +822,239 @@ Roadmap for the upcoming development.
- Always check filter/action documentation for parameter types - Always check filter/action documentation for parameter types
- Don't assume cart item arrays everywhere - sometimes it's product objects! - Don't assume cart item arrays everywhere - sometimes it's product objects!
#### CRITICAL: Product Type-Specific Hooks (Learned in v1.2.6/v1.2.7)
WooCommerce has different hooks for different product types in the admin product edit page:
- `woocommerce_product_options_pricing` - **ONLY fires for simple products**, NOT variable products
- `woocommerce_product_options_general_product_data` - Fires for ALL product types after the general tab
- `woocommerce_variation_options_pricing` - Fires for individual variations within variable products
**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, Corrected in v1.2.9)
When displaying currency symbols in admin interface table headers and input placeholders:
**Table Headers:**
```php
// ✅ 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>
<th><?php _e('Price (€)', 'wc-tier-package-prices'); ?></th>
```
**Twig Template Placeholders:**
```twig
{# ✅ 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') }}"
placeholder="{{ 'e.g., 9.99 €'|__('wc-tier-package-prices') }}"
```
**Implementation Pattern:**
1. In PHP render methods, pass currency symbol to Twig: `'currency_symbol' => get_woocommerce_currency_symbol()`
2. In Twig templates, concatenate using `~` operator: `'text ' ~ currency_symbol`
3. Always use WooCommerce's `get_woocommerce_currency_symbol()` - never hard-code currency symbols
**Affected Methods:** All template render methods must pass `currency_symbol`:
- `render_tier_row()`
- `render_package_row()`
- `render_variation_tier_row()`
- `render_variation_package_row()`
#### CRITICAL: Post Meta Deletion vs. Empty Arrays (Learned in v1.2.8)
When saving product meta data, WordPress distinguishes between "no data" (deleted meta) and "empty data" (empty array saved as meta):
**Problem Pattern:**
```php
// ❌ WRONG - Saves empty array when all entries removed
if (isset($_POST['_wc_tpp_tiers'])) {
$tiers = array();
foreach ($_POST['_wc_tpp_tiers'] as $tier) {
if (!empty($tier['min_qty']) && !empty($tier['price'])) {
$tiers[] = array(...);
}
}
update_post_meta($post_id, '_wc_tpp_tiers', $tiers); // Saves [] if no valid entries
} else {
delete_post_meta($post_id, '_wc_tpp_tiers');
}
```
**Correct Pattern:**
```php
// ✅ CORRECT - Deletes meta when no valid entries exist
if (isset($_POST['_wc_tpp_tiers'])) {
$tiers = array();
foreach ($_POST['_wc_tpp_tiers'] as $tier) {
if (!empty($tier['min_qty']) && !empty($tier['price'])) {
$tiers[] = array(...);
}
}
// Only save if we have valid entries, otherwise delete
if (!empty($tiers)) {
update_post_meta($post_id, '_wc_tpp_tiers', $tiers);
} else {
delete_post_meta($post_id, '_wc_tpp_tiers');
}
} else {
delete_post_meta($post_id, '_wc_tpp_tiers');
}
```
**Why This Matters:**
- Empty arrays `[]` saved via `update_post_meta()` persist in database as serialized empty arrays
- Frontend/cart code checking `if ($tiers)` will evaluate `[]` as falsy, but meta still exists in database
- Database queries like `get_post_meta()` return `[]` instead of `false`, causing subtle bugs
- Properly deleting meta keeps database clean and prevents "ghost" configurations
**Affected Methods in v1.2.8:**
- `save_tier_package_fields()` - Simple and variable parent products
- `save_variation_pricing_fields()` - Individual variations
**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 (`&euro;`, `&pound;`, 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 &euro;)
**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 ### When Adding Features
- Follow the existing pattern: add setting → add UI → add logic → add template - Follow the existing pattern: add setting → add UI → add logic → add template

View File

@@ -112,10 +112,16 @@
} }
/* Hide table headers when there are no pricing rules */ /* Hide table headers when there are no pricing rules */
/* Use :has() pseudo-class to check if tbody is empty */ /* Default: hide headers initially, JavaScript will show them when rows are added */
.wc-tpp-tiers-table:has(tbody.wc-tpp-tiers-container:empty) thead, .wc-tpp-tiers-table thead,
.wc-tpp-packages-table:has(tbody.wc-tpp-packages-container:empty) thead { .wc-tpp-packages-table thead {
display: none !important; display: none;
}
/* Show headers when table has pricing rows */
.wc-tpp-tiers-table.has-rows thead,
.wc-tpp-packages-table.has-rows thead {
display: table-header-group !important;
} }
/* Checkbox styling improvements */ /* Checkbox styling improvements */
@@ -148,3 +154,52 @@ label[for^="wc_tpp_restrict_to_packages_"] {
input[id^="wc_tpp_restrict_to_packages_"] + .description { input[id^="wc_tpp_restrict_to_packages_"] + .description {
display: none; 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;
}

View File

@@ -10,6 +10,28 @@
let tierIndex = $('.wc-tpp-tier-pricing .wc-tpp-tier-row').length; let tierIndex = $('.wc-tpp-tier-pricing .wc-tpp-tier-row').length;
let packageIndex = $('.wc-tpp-package-pricing .wc-tpp-package-row').length; let packageIndex = $('.wc-tpp-package-pricing .wc-tpp-package-row').length;
// Function to update table header visibility
function updateTableHeaders() {
// Check all tier tables
$('.wc-tpp-tiers-table').each(function() {
const $table = $(this);
const $tbody = $table.find('.wc-tpp-tiers-container');
const hasRows = $tbody.find('tr').length > 0;
$table.toggleClass('has-rows', hasRows);
});
// Check all package tables
$('.wc-tpp-packages-table').each(function() {
const $table = $(this);
const $tbody = $table.find('.wc-tpp-packages-container');
const hasRows = $tbody.find('tr').length > 0;
$table.toggleClass('has-rows', hasRows);
});
}
// Initialize table headers on page load
updateTableHeaders();
// ======================================== // ========================================
// Simple Product Handlers // Simple Product Handlers
// ======================================== // ========================================
@@ -21,6 +43,7 @@
const newRow = template.replace(/\{\{INDEX\}\}/g, tierIndex); const newRow = template.replace(/\{\{INDEX\}\}/g, tierIndex);
$('.wc-tpp-tier-pricing .wc-tpp-tiers-container').append(newRow); $('.wc-tpp-tier-pricing .wc-tpp-tiers-container').append(newRow);
tierIndex++; tierIndex++;
updateTableHeaders();
}); });
// Add package (simple products) // Add package (simple products)
@@ -30,6 +53,31 @@
const newRow = template.replace(/\{\{INDEX\}\}/g, packageIndex); const newRow = template.replace(/\{\{INDEX\}\}/g, packageIndex);
$('.wc-tpp-package-pricing .wc-tpp-packages-container').append(newRow); $('.wc-tpp-package-pricing .wc-tpp-packages-container').append(newRow);
packageIndex++; packageIndex++;
updateTableHeaders();
});
// ========================================
// Variable Product Parent Handlers
// ========================================
// Add tier (variable product parent default pricing)
$('.wc-tpp-variable-parent-pricing .wc-tpp-add-tier').on('click', function(e) {
e.preventDefault();
const template = $('#wc-tpp-tier-row-template').html();
const newRow = template.replace(/\{\{INDEX\}\}/g, tierIndex);
$('.wc-tpp-variable-parent-pricing .wc-tpp-tiers-container').append(newRow);
tierIndex++;
updateTableHeaders();
});
// Add package (variable product parent default pricing)
$('.wc-tpp-variable-parent-pricing .wc-tpp-add-package').on('click', function(e) {
e.preventDefault();
const template = $('#wc-tpp-package-row-template').html();
const newRow = template.replace(/\{\{INDEX\}\}/g, packageIndex);
$('.wc-tpp-variable-parent-pricing .wc-tpp-packages-container').append(newRow);
packageIndex++;
updateTableHeaders();
}); });
// ======================================== // ========================================
@@ -50,6 +98,7 @@
const newRow = template.replace(/\{\{INDEX\}\}/g, currentIndex); const newRow = template.replace(/\{\{INDEX\}\}/g, currentIndex);
$tbody.append(newRow); $tbody.append(newRow);
updateTableHeaders();
}); });
// Add package (variations) // Add package (variations)
@@ -66,6 +115,7 @@
const newRow = template.replace(/\{\{INDEX\}\}/g, currentIndex); const newRow = template.replace(/\{\{INDEX\}\}/g, currentIndex);
$tbody.append(newRow); $tbody.append(newRow);
updateTableHeaders();
}); });
// ======================================== // ========================================
@@ -77,6 +127,7 @@
e.preventDefault(); e.preventDefault();
if (confirm('Are you sure you want to remove this tier?')) { if (confirm('Are you sure you want to remove this tier?')) {
$(this).closest('.wc-tpp-tier-row').remove(); $(this).closest('.wc-tpp-tier-row').remove();
updateTableHeaders();
} }
}); });
@@ -85,6 +136,7 @@
e.preventDefault(); e.preventDefault();
if (confirm('Are you sure you want to remove this package?')) { if (confirm('Are you sure you want to remove this package?')) {
$(this).closest('.wc-tpp-package-row').remove(); $(this).closest('.wc-tpp-package-row').remove();
updateTableHeaders();
} }
}); });

View File

@@ -1,7 +1,7 @@
{ {
"name": "magdev/wc-tier-package-prices", "name": "magdev/wc-tier-package-prices",
"description": "WooCommerce plugin for tier pricing and package prices with Twig templates", "description": "WooCommerce plugin for tier pricing and package prices with Twig templates",
"version": "1.2.6", "version": "1.3.0",
"type": "wordpress-plugin", "type": "wordpress-plugin",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"authors": [ "authors": [
@@ -10,9 +10,16 @@
"homepage": "https://src.bundespruefstelle.ch/magdev" "homepage": "https://src.bundespruefstelle.ch/magdev"
} }
], ],
"repositories": [
{
"type": "vcs",
"url": "https://src.bundespruefstelle.ch/magdev/wc-licensed-product-client.git"
}
],
"require": { "require": {
"php": ">=7.4", "php": ">=8.3",
"twig/twig": "^3.0" "twig/twig": "^3.0",
"magdev/wc-licensed-product-client": "^0.1"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [

View File

@@ -17,7 +17,8 @@ if (!class_exists('WC_TPP_Product_Meta')) {
add_action('woocommerce_process_product_meta', array($this, 'save_tier_package_fields')); add_action('woocommerce_process_product_meta', array($this, 'save_tier_package_fields'));
// Variable product parent hooks (for default pricing) // Variable product parent hooks (for default pricing)
add_action('woocommerce_product_options_pricing', array($this, 'add_variable_parent_pricing_fields')); // Use product_options_general_product_data which shows for all product types after the general tab
add_action('woocommerce_product_options_general_product_data', array($this, 'add_variable_parent_pricing_fields'));
// Variable product variation hooks // Variable product variation hooks
add_action('woocommerce_variation_options_pricing', array($this, 'add_variation_pricing_fields'), 10, 3); add_action('woocommerce_variation_options_pricing', array($this, 'add_variation_pricing_fields'), 10, 3);
@@ -54,7 +55,7 @@ if (!class_exists('WC_TPP_Product_Meta')) {
<thead> <thead>
<tr> <tr>
<th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th> <th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th>
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th> <th><?php printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th> <th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
<th></th> <th></th>
</tr> </tr>
@@ -84,7 +85,7 @@ if (!class_exists('WC_TPP_Product_Meta')) {
<thead> <thead>
<tr> <tr>
<th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th> <th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th>
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th> <th><?php printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th> <th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
<th></th> <th></th>
</tr> </tr>
@@ -148,7 +149,7 @@ if (!class_exists('WC_TPP_Product_Meta')) {
<thead> <thead>
<tr> <tr>
<th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th> <th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th>
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th> <th><?php printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th> <th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
<th></th> <th></th>
</tr> </tr>
@@ -194,7 +195,7 @@ if (!class_exists('WC_TPP_Product_Meta')) {
<thead> <thead>
<tr> <tr>
<th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th> <th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th>
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th> <th><?php printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th> <th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
<th></th> <th></th>
</tr> </tr>
@@ -240,14 +241,16 @@ if (!class_exists('WC_TPP_Product_Meta')) {
private function render_tier_row($index, $tier) { private function render_tier_row($index, $tier) {
WC_TPP_Template_Loader::get_instance()->display('admin/tier-row.twig', array( WC_TPP_Template_Loader::get_instance()->display('admin/tier-row.twig', array(
'index' => $index, 'index' => $index,
'tier' => $tier 'tier' => $tier,
'currency_symbol' => get_woocommerce_currency_symbol()
)); ));
} }
private function render_package_row($index, $package) { private function render_package_row($index, $package) {
WC_TPP_Template_Loader::get_instance()->display('admin/package-row.twig', array( WC_TPP_Template_Loader::get_instance()->display('admin/package-row.twig', array(
'index' => $index, 'index' => $index,
'package' => $package 'package' => $package,
'currency_symbol' => get_woocommerce_currency_symbol()
)); ));
} }
@@ -284,7 +287,7 @@ if (!class_exists('WC_TPP_Product_Meta')) {
<thead> <thead>
<tr> <tr>
<th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th> <th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th>
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th> <th><?php printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th> <th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
<th></th> <th></th>
</tr> </tr>
@@ -307,7 +310,7 @@ if (!class_exists('WC_TPP_Product_Meta')) {
<thead> <thead>
<tr> <tr>
<th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th> <th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th>
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th> <th><?php printf(esc_html__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol()); ?></th>
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th> <th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
<th></th> <th></th>
</tr> </tr>
@@ -362,7 +365,8 @@ if (!class_exists('WC_TPP_Product_Meta')) {
WC_TPP_Template_Loader::get_instance()->display('admin/tier-row.twig', array( WC_TPP_Template_Loader::get_instance()->display('admin/tier-row.twig', array(
'index' => $index, 'index' => $index,
'tier' => $tier, 'tier' => $tier,
'field_prefix' => 'wc_tpp_tiers[' . $loop . ']' 'field_prefix' => 'wc_tpp_tiers[' . $loop . ']',
'currency_symbol' => get_woocommerce_currency_symbol()
)); ));
} }
@@ -377,7 +381,8 @@ if (!class_exists('WC_TPP_Product_Meta')) {
WC_TPP_Template_Loader::get_instance()->display('admin/package-row.twig', array( WC_TPP_Template_Loader::get_instance()->display('admin/package-row.twig', array(
'index' => $index, 'index' => $index,
'package' => $package, 'package' => $package,
'field_prefix' => 'wc_tpp_packages[' . $loop . ']' 'field_prefix' => 'wc_tpp_packages[' . $loop . ']',
'currency_symbol' => get_woocommerce_currency_symbol()
)); ));
} }
@@ -413,10 +418,15 @@ if (!class_exists('WC_TPP_Product_Meta')) {
usort($tiers, function($a, $b) { usort($tiers, function($a, $b) {
return $a['min_qty'] - $b['min_qty']; return $a['min_qty'] - $b['min_qty'];
}); });
// Only save if we have valid tiers, otherwise delete
if (!empty($tiers)) {
update_post_meta($post_id, '_wc_tpp_tiers', $tiers); update_post_meta($post_id, '_wc_tpp_tiers', $tiers);
} else { } else {
delete_post_meta($post_id, '_wc_tpp_tiers'); delete_post_meta($post_id, '_wc_tpp_tiers');
} }
} else {
delete_post_meta($post_id, '_wc_tpp_tiers');
}
// Save package pricing // Save package pricing
if (isset($_POST['_wc_tpp_packages'])) { if (isset($_POST['_wc_tpp_packages'])) {
@@ -434,10 +444,15 @@ if (!class_exists('WC_TPP_Product_Meta')) {
usort($packages, function($a, $b) { usort($packages, function($a, $b) {
return $a['qty'] - $b['qty']; return $a['qty'] - $b['qty'];
}); });
// Only save if we have valid packages, otherwise delete
if (!empty($packages)) {
update_post_meta($post_id, '_wc_tpp_packages', $packages); update_post_meta($post_id, '_wc_tpp_packages', $packages);
} else { } else {
delete_post_meta($post_id, '_wc_tpp_packages'); delete_post_meta($post_id, '_wc_tpp_packages');
} }
} else {
delete_post_meta($post_id, '_wc_tpp_packages');
}
// Save package quantity restriction setting // Save package quantity restriction setting
$restrict_to_packages = isset($_POST['_wc_tpp_restrict_to_packages']) ? 'yes' : 'no'; $restrict_to_packages = isset($_POST['_wc_tpp_restrict_to_packages']) ? 'yes' : 'no';
@@ -457,8 +472,8 @@ if (!class_exists('WC_TPP_Product_Meta')) {
} }
// Save tier pricing for this variation // Save tier pricing for this variation
if (isset($_POST['wc_tpp_tiers'][$loop])) {
$tiers = array(); $tiers = array();
if (isset($_POST['wc_tpp_tiers'][$loop]) && is_array($_POST['wc_tpp_tiers'][$loop])) {
foreach ($_POST['wc_tpp_tiers'][$loop] as $tier) { foreach ($_POST['wc_tpp_tiers'][$loop] as $tier) {
if (!empty($tier['min_qty']) && !empty($tier['price'])) { if (!empty($tier['min_qty']) && !empty($tier['price'])) {
$tiers[] = array( $tiers[] = array(
@@ -472,14 +487,17 @@ if (!class_exists('WC_TPP_Product_Meta')) {
usort($tiers, function($a, $b) { usort($tiers, function($a, $b) {
return $a['min_qty'] - $b['min_qty']; return $a['min_qty'] - $b['min_qty'];
}); });
}
// Always update or delete based on whether we have valid tiers
if (!empty($tiers)) {
update_post_meta($variation_id, '_wc_tpp_tiers', $tiers); update_post_meta($variation_id, '_wc_tpp_tiers', $tiers);
} else { } else {
delete_post_meta($variation_id, '_wc_tpp_tiers'); delete_post_meta($variation_id, '_wc_tpp_tiers');
} }
// Save package pricing for this variation // Save package pricing for this variation
if (isset($_POST['wc_tpp_packages'][$loop])) {
$packages = array(); $packages = array();
if (isset($_POST['wc_tpp_packages'][$loop]) && is_array($_POST['wc_tpp_packages'][$loop])) {
foreach ($_POST['wc_tpp_packages'][$loop] as $package) { foreach ($_POST['wc_tpp_packages'][$loop] as $package) {
if (!empty($package['qty']) && !empty($package['price'])) { if (!empty($package['qty']) && !empty($package['price'])) {
$packages[] = array( $packages[] = array(
@@ -493,6 +511,9 @@ if (!class_exists('WC_TPP_Product_Meta')) {
usort($packages, function($a, $b) { usort($packages, function($a, $b) {
return $a['qty'] - $b['qty']; return $a['qty'] - $b['qty'];
}); });
}
// Always update or delete based on whether we have valid packages
if (!empty($packages)) {
update_post_meta($variation_id, '_wc_tpp_packages', $packages); update_post_meta($variation_id, '_wc_tpp_packages', $packages);
} else { } else {
delete_post_meta($variation_id, '_wc_tpp_packages'); delete_post_meta($variation_id, '_wc_tpp_packages');

368
includes/class-wc-tpp-settings.php Normal file → Executable file
View File

@@ -2,7 +2,7 @@
/** /**
* WooCommerce Settings Integration * 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 * @package WC_Tier_Package_Prices
*/ */
@@ -29,32 +29,31 @@ if (!class_exists('WC_TPP_Settings')) {
$this->label = __('Tier & Package Prices', 'wc-tier-package-prices'); $this->label = __('Tier & Package Prices', 'wc-tier-package-prices');
parent::__construct(); 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'));
} }
/** /**
* Get sections * Get own sections - Modern WooCommerce pattern
* *
* @return array * @return array
*/ */
public function get_sections() { protected function get_own_sections() {
$sections = array( return array(
'' => __('General', 'wc-tier-package-prices'), '' => __('General', 'wc-tier-package-prices'),
'license' => __('License', '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 * @return array
*/ */
public function get_settings($current_section = '') { protected function get_settings_for_default_section() {
$settings = array(); return array(
if ('' === $current_section) {
$settings = array(
array( array(
'title' => __('Tier & Package Prices Settings', 'wc-tier-package-prices'), 'title' => __('Tier & Package Prices Settings', 'wc-tier-package-prices'),
'type' => 'title', 'type' => 'title',
@@ -121,23 +120,352 @@ 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' => __('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 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'] ?? ''));
if (empty($license_key) || empty($server_url)) {
wp_send_json_error(array('message' => __('License key and server URL are required.', 'wc-tier-package-prices')));
}
try {
$client = $this->get_license_client($server_url);
$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\LicenseException $e) {
delete_transient('wc_tpp_license_status');
wp_send_json_error(array(
'message' => $e->getMessage(),
'code' => $e->errorCode ?? 'unknown',
));
} catch (\Exception $e) {
delete_transient('wc_tpp_license_status');
wp_send_json_error(array(
'message' => $e->getMessage(),
'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'] ?? ''));
if (empty($license_key) || empty($server_url)) {
wp_send_json_error(array('message' => __('License key and server URL are required.', 'wc-tier-package-prices')));
}
try {
$client = $this->get_license_client($server_url);
$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\LicenseException $e) {
wp_send_json_error(array(
'message' => $e->getMessage(),
'code' => $e->errorCode ?? 'unknown',
));
} catch (\Exception $e) {
wp_send_json_error(array(
'message' => $e->getMessage(),
'code' => 'exception',
));
}
}
/**
* Get license client instance
*
* @param string $server_url License server URL.
* @return \Magdev\WcLicensedProductClient\LicenseClientInterface
*/
private function get_license_client(string $server_url): \Magdev\WcLicensedProductClient\LicenseClientInterface {
$httpClient = \Symfony\Component\HttpClient\HttpClient::create();
return new \Magdev\WcLicensedProductClient\LicenseClient(
httpClient: $httpClient,
baseUrl: $server_url,
);
}
/**
* 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 * Output the settings
*/ */
public function output() { public function output() {
$settings = $this->get_settings(); global $current_section;
WC_Admin_Settings::output_fields($settings);
// Register custom field type for license status display
add_action('woocommerce_admin_field_wc_tpp_license_status', array($this, 'output_license_status_field'));
parent::output();
// Add JavaScript for license section
if ('license' === $current_section) {
$this->output_license_scripts();
}
} }
/** /**
* Save settings * Output license status custom field
*
* @param array $value Field configuration.
*/ */
public function save() { public function output_license_status_field($value) {
$settings = $this->get_settings(); $status = $this->get_cached_license_status();
WC_Admin_Settings::save_fields($settings); ?>
<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) {
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 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(),
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) {
alert('<?php echo esc_js(__('Please enter both license server URL and license key.', '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) {
alert('<?php echo esc_js(__('Please enter both license server URL and license key.', '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
} }
} }
} }

View File

@@ -3,10 +3,10 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-23 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"PO-Revision-Date: 2025-12-23 00:00+0000\n" "PO-Revision-Date: 2025-12-30 00:00+0000\n"
"Last-Translator: Marco Graetsch\n" "Last-Translator: Marco Graetsch\n"
"Language-Team: German (Switzerland)\n" "Language-Team: German (Switzerland)\n"
"Language: de_CH\n" "Language: de_CH\n"
@@ -152,6 +152,26 @@ msgstr "Paket hinzufügen"
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "Nur oben definierte Paketmengen zulassen" msgstr "Nur oben definierte Paketmengen zulassen"
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr "Standard Staffel- & Paketpreise für alle Varianten"
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr "Legen Sie Standardpreise für alle Varianten fest. Einzelne Varianten können diese Standardwerte mit ihren eigenen spezifischen Preisen überschreiben."
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr "Konfigurieren Sie hier Standard-Staffel- und Paketpreise. Alle Varianten übernehmen diese Einstellungen, es sei denn, sie definieren ihre eigenen spezifischen Preise."
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr "Auf Paketmengen beschränken (Standard)"
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr "Standard-Beschränkungseinstellung für alle Varianten. Nur oben definierte Paketmengen zulassen."
#: includes/class-wc-tpp-product-meta.php:90 #: includes/class-wc-tpp-product-meta.php:90
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "Mindestmenge" msgstr "Mindestmenge"
@@ -257,3 +277,103 @@ msgstr "Preis"
#: includes/class-wc-tpp-product-meta.php:165 #: includes/class-wc-tpp-product-meta.php:165
msgid "Label (optional)" msgid "Label (optional)"
msgstr "Beschriftung (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 "License key and server URL are required."
msgstr "Lizenzschlüssel und Server-URL sind erforderlich."
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
msgstr "Bitte geben Sie sowohl die Lizenzserver-URL als auch den Lizenzschlüssel 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."

View File

@@ -3,10 +3,10 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"PO-Revision-Date: 2025-12-21 00:00+0000\n" "PO-Revision-Date: 2025-12-30 00:00+0000\n"
"Last-Translator: Marco Graetsch\n" "Last-Translator: Marco Graetsch\n"
"Language-Team: German (Switzerland)\n" "Language-Team: German (Switzerland)\n"
"Language: de_CH_informal\n" "Language: de_CH_informal\n"
@@ -152,6 +152,26 @@ msgstr "Paket hinzufügen"
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "Nur oben definierte Paketmengen zulassen" msgstr "Nur oben definierte Paketmengen zulassen"
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr "Standard Staffel- & Paketpreise für alle Varianten"
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr "Lege Standardpreise für alle Varianten fest. Einzelne Varianten können diese Standardwerte mit ihren eigenen spezifischen Preisen überschreiben."
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr "Konfiguriere hier Standard-Staffel- und Paketpreise. Alle Varianten übernehmen diese Einstellungen, es sei denn, sie definieren ihre eigenen spezifischen Preise."
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr "Auf Paketmengen beschränken (Standard)"
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr "Standard-Beschränkungseinstellung für alle Varianten. Nur oben definierte Paketmengen zulassen."
#: includes/class-wc-tpp-product-meta.php:90 #: includes/class-wc-tpp-product-meta.php:90
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "Mindestmenge" msgstr "Mindestmenge"
@@ -257,3 +277,103 @@ msgstr "Preis"
#: includes/class-wc-tpp-product-meta.php:165 #: includes/class-wc-tpp-product-meta.php:165
msgid "Label (optional)" msgid "Label (optional)"
msgstr "Beschriftung (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 "License key and server URL are required."
msgstr "Lizenzschlüssel und Server-URL sind erforderlich."
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
msgstr "Bitte gib sowohl die Lizenzserver-URL als auch den Lizenzschlüssel 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."

View File

@@ -3,10 +3,10 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"PO-Revision-Date: 2025-12-21 00:00+0000\n" "PO-Revision-Date: 2025-12-30 00:00+0000\n"
"Last-Translator: Marco Graetsch\n" "Last-Translator: Marco Graetsch\n"
"Language-Team: German\n" "Language-Team: German\n"
"Language: de_DE\n" "Language: de_DE\n"
@@ -152,6 +152,26 @@ msgstr "Paket hinzufügen"
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "Nur oben definierte Paketmengen zulassen" msgstr "Nur oben definierte Paketmengen zulassen"
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr "Standard Staffel- & Paketpreise für alle Varianten"
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr "Legen Sie Standardpreise für alle Varianten fest. Einzelne Varianten können diese Standardwerte mit ihren eigenen spezifischen Preisen überschreiben."
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr "Konfigurieren Sie hier Standard-Staffel- und Paketpreise. Alle Varianten übernehmen diese Einstellungen, es sei denn, sie definieren ihre eigenen spezifischen Preise."
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr "Auf Paketmengen beschränken (Standard)"
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr "Standard-Beschränkungseinstellung für alle Varianten. Nur oben definierte Paketmengen zulassen."
#: includes/class-wc-tpp-product-meta.php:90 #: includes/class-wc-tpp-product-meta.php:90
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "Mindestmenge" msgstr "Mindestmenge"
@@ -257,3 +277,103 @@ msgstr "Preis"
#: includes/class-wc-tpp-product-meta.php:165 #: includes/class-wc-tpp-product-meta.php:165
msgid "Label (optional)" msgid "Label (optional)"
msgstr "Beschriftung (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 "License key and server URL are required."
msgstr "Lizenzschlüssel und Server-URL sind erforderlich."
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
msgstr "Bitte geben Sie sowohl die Lizenzserver-URL als auch den Lizenzschlüssel 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."

View File

@@ -3,10 +3,10 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-23 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"PO-Revision-Date: 2025-12-23 00:00+0000\n" "PO-Revision-Date: 2025-12-30 00:00+0000\n"
"Last-Translator: Marco Graetsch\n" "Last-Translator: Marco Graetsch\n"
"Language-Team: German (Germany)\n" "Language-Team: German (Germany)\n"
"Language: de_DE_informal\n" "Language: de_DE_informal\n"
@@ -152,6 +152,26 @@ msgstr "Paket hinzufügen"
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "Nur oben definierte Paketmengen zulassen" msgstr "Nur oben definierte Paketmengen zulassen"
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr "Standard Staffel- & Paketpreise für alle Varianten"
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr "Lege Standardpreise für alle Varianten fest. Einzelne Varianten können diese Standardwerte mit ihren eigenen spezifischen Preisen überschreiben."
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr "Konfiguriere hier Standard-Staffel- und Paketpreise. Alle Varianten übernehmen diese Einstellungen, es sei denn, sie definieren ihre eigenen spezifischen Preise."
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr "Auf Paketmengen beschränken (Standard)"
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr "Standard-Beschränkungseinstellung für alle Varianten. Nur oben definierte Paketmengen zulassen."
#: includes/class-wc-tpp-product-meta.php:90 #: includes/class-wc-tpp-product-meta.php:90
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "Mindestmenge" msgstr "Mindestmenge"
@@ -257,3 +277,103 @@ msgstr "Preis"
#: includes/class-wc-tpp-product-meta.php:165 #: includes/class-wc-tpp-product-meta.php:165
msgid "Label (optional)" msgid "Label (optional)"
msgstr "Beschriftung (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 "License key and server URL are required."
msgstr "Lizenzschlüssel und Server-URL sind erforderlich."
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
msgstr "Bitte gib sowohl die Lizenzserver-URL als auch den Lizenzschlüssel 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."

View File

@@ -3,10 +3,10 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"PO-Revision-Date: 2025-12-21 00:00+0000\n" "PO-Revision-Date: 2025-12-30 00:00+0000\n"
"Last-Translator: Marco Graetsch\n" "Last-Translator: Marco Graetsch\n"
"Language-Team: English\n" "Language-Team: English\n"
"Language: en_US\n" "Language: en_US\n"
@@ -152,6 +152,26 @@ msgstr "Add Package"
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "Only allow quantities defined in packages above" msgstr "Only allow quantities defined in packages above"
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr "Default Tier & Package Pricing for All Variations"
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr "Restrict to Package Quantities (Default)"
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr "Default restriction setting for all variations. Only allow quantities defined in packages above."
#: includes/class-wc-tpp-product-meta.php:90 #: includes/class-wc-tpp-product-meta.php:90
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "Minimum Quantity" msgstr "Minimum Quantity"
@@ -257,3 +277,103 @@ msgstr "Price"
#: includes/class-wc-tpp-product-meta.php:165 #: includes/class-wc-tpp-product-meta.php:165
msgid "Label (optional)" msgid "Label (optional)"
msgstr "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 "License key and server URL are required."
msgstr "License key and server URL are required."
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
msgstr "Please enter both license server URL and license key."
#: 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."

View File

@@ -3,10 +3,10 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-23 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"PO-Revision-Date: 2025-12-23 00:00+0000\n" "PO-Revision-Date: 2025-12-30 00:00+0000\n"
"Last-Translator: Marco Graetsch\n" "Last-Translator: Marco Graetsch\n"
"Language-Team: French (Switzerland)\n" "Language-Team: French (Switzerland)\n"
"Language: fr_CH\n" "Language: fr_CH\n"
@@ -152,6 +152,26 @@ msgstr "Ajouter un forfait"
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "Autoriser uniquement les quantités définies dans les forfaits ci-dessus" msgstr "Autoriser uniquement les quantités définies dans les forfaits ci-dessus"
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr "Tarification par paliers et forfaits par défaut pour toutes les variations"
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr "Définir la tarification par défaut pour toutes les variations. Les variations individuelles peuvent remplacer ces valeurs par défaut par leur propre tarification spécifique."
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr "Configurez ici la tarification par paliers et forfaits par défaut. Toutes les variations hériteront de ces paramètres sauf si elles définissent leur propre tarification spécifique."
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr "Limiter aux quantités de forfaits (par défaut)"
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr "Paramètre de restriction par défaut pour toutes les variations. Autoriser uniquement les quantités définies dans les forfaits ci-dessus."
#: includes/class-wc-tpp-product-meta.php:90 #: includes/class-wc-tpp-product-meta.php:90
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "Quantité minimale" msgstr "Quantité minimale"
@@ -257,3 +277,103 @@ msgstr "Prix"
#: includes/class-wc-tpp-product-meta.php:165 #: includes/class-wc-tpp-product-meta.php:165
msgid "Label (optional)" msgid "Label (optional)"
msgstr "Étiquette (optionnel)" 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 "License key and server URL are required."
msgstr "La clé de licence et l'URL du serveur sont requises."
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
msgstr "Veuillez entrer l'URL du serveur de licence et la clé de licence."
#: 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."

View File

@@ -3,10 +3,10 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-23 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"PO-Revision-Date: 2025-12-23 00:00+0000\n" "PO-Revision-Date: 2025-12-30 00:00+0000\n"
"Last-Translator: Marco Graetsch\n" "Last-Translator: Marco Graetsch\n"
"Language-Team: Italian (Switzerland)\n" "Language-Team: Italian (Switzerland)\n"
"Language: it_CH\n" "Language: it_CH\n"
@@ -152,6 +152,26 @@ msgstr "Aggiungi pacchetto"
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "Consenti solo le quantità definite nei pacchetti sopra" msgstr "Consenti solo le quantità definite nei pacchetti sopra"
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr "Prezzi a scaglioni e pacchetti predefiniti per tutte le variazioni"
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr "Imposta i prezzi predefiniti per tutte le variazioni. Le singole variazioni possono sovrascrivere questi valori predefiniti con i propri prezzi specifici."
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr "Configura qui i prezzi a scaglioni e pacchetti predefiniti. Tutte le variazioni erediteranno queste impostazioni a meno che non definiscano i propri prezzi specifici."
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr "Limita alle quantità dei pacchetti (predefinito)"
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr "Impostazione di restrizione predefinita per tutte le variazioni. Consenti solo le quantità definite nei pacchetti sopra."
#: includes/class-wc-tpp-product-meta.php:90 #: includes/class-wc-tpp-product-meta.php:90
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "Quantità minima" msgstr "Quantità minima"
@@ -257,3 +277,103 @@ msgstr "Prezzo"
#: includes/class-wc-tpp-product-meta.php:165 #: includes/class-wc-tpp-product-meta.php:165
msgid "Label (optional)" msgid "Label (optional)"
msgstr "Etichetta (facoltativo)" 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 "License key and server URL are required."
msgstr "La chiave di licenza e l'URL del server sono obbligatori."
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
msgstr "Inserisci sia l'URL del server di licenza che la chiave di licenza."
#: 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."

View File

@@ -2,9 +2,9 @@
# This file is distributed under the GPL v2 or later. # This file is distributed under the GPL v2 or later.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n" "Project-Id-Version: WooCommerce Tier and Package Prices 1.2.7\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n" "Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n" "POT-Creation-Date: 2025-12-30 00:00+0000\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@@ -132,6 +132,26 @@ msgstr ""
msgid "Only allow quantities defined in packages above" msgid "Only allow quantities defined in packages above"
msgstr "" msgstr ""
#: includes/class-wc-tpp-product-meta.php:42
msgid "Default Tier & Package Pricing for All Variations"
msgstr ""
#: includes/class-wc-tpp-product-meta.php:43
msgid "Set default pricing for all variations. Individual variations can override these defaults with their own specific pricing."
msgstr ""
#: includes/class-wc-tpp-product-meta.php:44
msgid "Configure default tier and package pricing here. All variations will inherit these settings unless they define their own specific pricing."
msgstr ""
#: includes/class-wc-tpp-product-meta.php:87
msgid "Restrict to Package Quantities (Default)"
msgstr ""
#: includes/class-wc-tpp-product-meta.php:88
msgid "Default restriction setting for all variations. Only allow quantities defined in packages above."
msgstr ""
#: templates/admin/tier-row.twig:9 #: templates/admin/tier-row.twig:9
msgid "Minimum Quantity" msgid "Minimum Quantity"
msgstr "" msgstr ""
@@ -230,3 +250,103 @@ msgstr ""
#: includes/class-wc-tpp-frontend.php:178 #: includes/class-wc-tpp-frontend.php:178
msgid "View options for %s" msgid "View options for %s"
msgstr "" 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 "License key and server URL are required."
msgstr ""
#: includes/class-wc-tpp-settings.php
msgid "Please enter both license server URL and license key."
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 ""

View File

@@ -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.

View File

@@ -1 +0,0 @@
e6cfc9b88df9e7763be0cd56517ce8ab wc-tier-and-package-prices-1.0.1.zip

View File

@@ -1 +0,0 @@
92c1385d92527e77646e37f23c1bd1555a4290a5ec9314c0ee6ed896ded55e88 wc-tier-and-package-prices-1.0.1.zip

View File

@@ -1 +0,0 @@
830f443ce4b65e2ca9cfede3257bc4f5 wc-tier-and-package-prices-1.0.2.zip

View File

@@ -1 +0,0 @@
c1a5339da10b3625156b8fff4ec848e4a1318d6edc497bd5026cfe0a3ef39daa wc-tier-and-package-prices-1.0.2.zip

View File

@@ -1 +0,0 @@
ef68125c54b0c10f04ba82d48a98b4aa wc-tier-and-package-prices-1.1.0.zip

View File

@@ -1 +0,0 @@
da6b462f3dc297b282ed0da258b78fd9f2f82f3e76289c4c8fadd1ac9e02c55b wc-tier-and-package-prices-1.1.0.zip

View File

@@ -1 +0,0 @@
51c4f8a7c3ccede2d2005f2fe3ebe44e wc-tier-and-package-prices-1.1.1.zip

View File

@@ -1 +0,0 @@
b951f8b7ddd2bad6b3415d4583709fdf88f66aea4eae70110c903757ff53e045 wc-tier-and-package-prices-1.1.1.zip

View File

@@ -1 +0,0 @@
81be5283219cfa722f6d382a788e7dc1 releases/wc-tier-and-package-prices-1.1.10.zip

View File

@@ -1 +0,0 @@
2d3b01e61c8a03a8f20bc99b2019ca50fa08ecd68188feb2d2105dfe35d36f0d releases/wc-tier-and-package-prices-1.1.10.zip

View File

@@ -1 +0,0 @@
4a0c0b07b29d4b7046f9d3ff3f091321 releases/wc-tier-and-package-prices-1.1.11.zip

View File

@@ -1 +0,0 @@
3da9423d136a2ff254b61577ba1f84d4c0f0d1e57bae361ac29c90327feeeceb releases/wc-tier-and-package-prices-1.1.11.zip

View File

@@ -1 +0,0 @@
c1c0b5880636686227246be2c37dc42a releases/wc-tier-and-package-prices-1.1.12.zip

View File

@@ -1 +0,0 @@
05b32356d46803dbb7fa17c13a2d8da96f77126746e2895e2f5c6dd0e7b490ff releases/wc-tier-and-package-prices-1.1.12.zip

View File

@@ -1 +0,0 @@
8572eed399554905fbf331d18f0677a0 wc-tier-and-package-prices-1.1.13.zip

View File

@@ -1 +0,0 @@
83e29b2e40dd43e77bd83cd03d4ccc54ef53555b55544eba4d38161101f79f20 wc-tier-and-package-prices-1.1.13.zip

View File

@@ -1 +0,0 @@
e0cc51d1493ed35ab254220d9f46997b wc-tier-and-package-prices-1.1.14.zip

View File

@@ -1 +0,0 @@
8a2ce7438ee49baffdcaaf323b6426d73dd1cf704bea94a80fcce27a42c097ad wc-tier-and-package-prices-1.1.14.zip

View File

@@ -1 +0,0 @@
15fa0e0933c85b23f66940bf43810835 wc-tier-and-package-prices-1.1.15.zip

View File

@@ -1 +0,0 @@
a419579111ad20b127411e1078ca99187156d606381549e6bf147ffc3bd58de1 wc-tier-and-package-prices-1.1.15.zip

View File

@@ -1 +0,0 @@
d30a90715dbcd46a1dfd19f025897530 wc-tier-and-package-prices-1.1.16.zip

View File

@@ -1 +0,0 @@
e2ad36e049a902b8e287154867ef72c0e169766508781e223176a2a753b60915 wc-tier-and-package-prices-1.1.16.zip

View File

@@ -1 +0,0 @@
9adbb9aad13b8d141cfabfdf53643480 wc-tier-and-package-prices-1.1.17.zip

View File

@@ -1 +0,0 @@
985a195bf98d4dbc0a7afa90173efcda472f4c769adf3c833fa6a99ba9d44095 wc-tier-and-package-prices-1.1.17.zip

View File

@@ -1 +0,0 @@
ec4bb1d78a3c27488244b44971916ffd wc-tier-and-package-prices-1.1.18.zip

View File

@@ -1 +0,0 @@
7d942002edd866c2b6f3192ba010fe64058b7433c5ac776a48e9c3c41f4e2fda wc-tier-and-package-prices-1.1.18.zip

View File

@@ -1 +0,0 @@
c61c3a059429d8dacdce71d4acce401e wc-tier-and-package-prices-1.1.19.zip

View File

@@ -1 +0,0 @@
0e8bc4ccd233d388238e800cd0e0a129f9e8da14008e7164db7934a48ca8223a wc-tier-and-package-prices-1.1.19.zip

View File

@@ -1 +0,0 @@
eee69fcf391b3f3df9380306ffb31b1b wc-tier-and-package-prices-1.1.2.zip

View File

@@ -1 +0,0 @@
40ffd29ebc6af635f689472040acd220ae1c8df2f0d852fab4b43ce0fb5fe739 wc-tier-and-package-prices-1.1.2.zip

View File

@@ -1 +0,0 @@
bfdeee75bfe3795c9ab9abfe47f12a41 wc-tier-and-package-prices-1.1.20.zip

View File

@@ -1 +0,0 @@
953859241d15d76ec4783c72bac851ddd69e5a1f7b119ee4f9ebd30c7fabed17 wc-tier-and-package-prices-1.1.20.zip

View File

@@ -1 +0,0 @@
16813b3ed0d1001d5f60194d61d36fc2 wc-tier-and-package-prices-1.1.21.zip

View File

@@ -1 +0,0 @@
e0063852a9ac23b1fd994471a2829f9dcbe26316f00ddee2d00f77c7c6a47c8f wc-tier-and-package-prices-1.1.21.zip

View File

@@ -1 +0,0 @@
7d5a5c7980a91dff5167c90a6f3290b0 wc-tier-and-package-prices-1.1.22.zip

View File

@@ -1 +0,0 @@
f94dee838a3f288b4acb3b3d9a4e88ef987f9b1bc918403186014d8d43fee6d9 wc-tier-and-package-prices-1.1.22.zip

View File

@@ -1 +0,0 @@
dfec91be7e375b09613ba81cfebbe013 wc-tier-and-package-prices-1.1.3.zip

View File

@@ -1 +0,0 @@
7938542680b71a7b73269c96a4dff78f2222ac8409092011c5e40e97a5e465aa wc-tier-and-package-prices-1.1.3.zip

View File

@@ -1 +0,0 @@
3e5bc2cae17ecb81b729c3fdc979df23 wc-tier-and-package-prices-1.1.4.zip

View File

@@ -1 +0,0 @@
19553b2fed1c6ca20a8168eab8c570cb0302be801322cd41d86cec40b70ff162 wc-tier-and-package-prices-1.1.4.zip

View File

@@ -1 +0,0 @@
e9f8a69e4be107d857d3beb671d5a9fe wc-tier-and-package-prices-1.1.5.zip

View File

@@ -1 +0,0 @@
a13d71f3f65c7cf41613f88d7bcfcb112acfefb800fa6b95932f44a47cf764f3 wc-tier-and-package-prices-1.1.5.zip

View File

@@ -1 +0,0 @@
dbea10acffdc849f9aa387d128cb6d6e wc-tier-and-package-prices-1.1.6.zip

View File

@@ -1 +0,0 @@
730e366764449ac963bc85848ac8a91f654e4b35500ed3132a280ab4f215c80c wc-tier-and-package-prices-1.1.6.zip

View File

@@ -1 +0,0 @@
c593b6fc730133ecaf772f77d5659080 wc-tier-and-package-prices-1.1.7.zip

View File

@@ -1 +0,0 @@
00e7c473a8b0fc23eb1cd52f4b38db030618ed142a9a9fdfd9b1aa4c5849ec70 wc-tier-and-package-prices-1.1.7.zip

View File

@@ -1 +0,0 @@
666e1acad9f349982463b65d0e3e7fa3 wc-tier-and-package-prices-1.1.8.zip

View File

@@ -1 +0,0 @@
2c100d0d100a6fd7bd8f9c9b154d878a675bc795c5fddb19314bc9991b9a60ba wc-tier-and-package-prices-1.1.8.zip

View File

@@ -1 +0,0 @@
7421aceb8d1cc89b7d15b19d68cdfabe wc-tier-and-package-prices-1.1.9.zip

View File

@@ -1 +0,0 @@
8224bf8b9bfc3dc760d77c61700d27c31db1a67b70834d8b6a4581df66fd45bd wc-tier-and-package-prices-1.1.9.zip

Some files were not shown because too many files have changed in this diff Show More