You've already forked wc-tier-and-package-prices
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 04eba21521 | |||
| ef314e36bc | |||
| 415f39e826 | |||
| 6733ca5f98 | |||
| 00c5b87aac | |||
| 87784f467a | |||
| 45a89fc693 | |||
| f530b37285 | |||
| 1e6d86ca10 | |||
| f958c7b640 | |||
| b1d31f4894 | |||
| 0c75234dcb | |||
| 556cba20fa |
5
.claude/commands/finish-session.md
Normal file
5
.claude/commands/finish-session.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Finish the current session
|
||||
|
||||
Update the CLAUDE.md according to your needs and what you've learned in this session.
|
||||
|
||||
Create a commit and push this file to branch `dev`
|
||||
@@ -18,7 +18,10 @@
|
||||
"Bash(done)",
|
||||
"Bash(git commit:*)",
|
||||
"Bash(node -c:*)",
|
||||
"Bash(php -l:*)"
|
||||
"Bash(php -l:*)",
|
||||
"Bash(git push:*)",
|
||||
"Bash(git checkout:*)",
|
||||
"Bash(git rebase:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -29,3 +29,6 @@ notes.*
|
||||
# OS
|
||||
.DS_Store
|
||||
._*
|
||||
|
||||
# local code
|
||||
wordpress
|
||||
|
||||
203
CHANGELOG.md
203
CHANGELOG.md
@@ -5,6 +5,209 @@ All notable changes to WooCommerce Tier and Package Prices will be documented in
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.2.3] - 2025-12-29
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Admin Table Styling**: Applied borderless table styling to all tier/package tables (both simple and variable products). Previously only variation tables had borders removed in v1.2.2. Now all pricing tables in the admin have a consistent borderless appearance matching WooCommerce's clean admin UI style.
|
||||
|
||||
- **Checkbox Styling and Tooltip**: Fixed checkbox styling issues where the help text was displayed inline instead of as a tooltip, and the margin between checkbox and label was too small. Added `desc_tip => true` to the variation restriction checkbox to enable tooltip display. Added CSS rules to increase checkbox-label margin to 8px and hide inline description text when tooltips are used.
|
||||
|
||||
### Changed Files
|
||||
|
||||
- `assets/css/admin.css` - Applied `border: none` to all tier/package table elements; added checkbox margin and description hiding rules
|
||||
- `includes/class-wc-tpp-product-meta.php` - Added `desc_tip => true` parameter to variation checkbox (line 213)
|
||||
|
||||
## [1.2.2] - 2025-12-29
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Variation UI Styling**: Removed table borders for variation pricing tables to match WooCommerce's borderless variation UI style. Added CSS rules specifically targeting `.wc-tpp-variation-pricing` tables to remove borders while keeping them for simple product tables.
|
||||
|
||||
- **Missing Translations**: Added missing admin template translations for "Min Quantity", "Price", and "Label (optional)" to all language files (de_DE, de_DE_informal, de_CH, de_CH_informal, fr_CH, it_CH, en_US). These strings were used in the variation admin UI added in v1.2.0 but weren't included in translation files.
|
||||
|
||||
- **Checkbox Rendering**: Fixed variation restriction checkbox rendering issue. The `wc_tpp_restrict_to_packages[]` checkbox in variation pricing fields was using a ternary expression that prevented proper checked state handling. Simplified to direct value assignment for WooCommerce's checkbox function to work correctly.
|
||||
|
||||
### Changed Files
|
||||
|
||||
- `assets/css/admin.css` - Added border removal for variation pricing tables
|
||||
- `includes/class-wc-tpp-product-meta.php` - Fixed checkbox value parameter (line 213)
|
||||
- `languages/*.po` - Added missing translation entries
|
||||
- `languages/*.mo` - Recompiled from updated .po files
|
||||
|
||||
## [1.2.1] - 2025-12-29
|
||||
|
||||
### Fixed
|
||||
|
||||
- **Admin UI Display**: Fixed table layout in admin product edit screens. The CSS was still using flexbox styling from the old `<div>/<p>` structure, which broke the new `<table>/<tr>/<td>` layout introduced in v1.2.0. Updated `assets/css/admin.css` to properly style table rows with standard table cell padding and removed obsolete flexbox properties.
|
||||
|
||||
- **Frontend Pricing Display**: Fixed pricing tables not showing on simple product pages. Removed global "Enable Tier Pricing" and "Enable Package Pricing" checks from the frontend template (`templates/frontend/pricing-table.twig`). Pricing tables now display if configured on a product AND the "Display Pricing Table" setting is enabled, regardless of individual feature enable settings. Cart calculations still respect global enable settings for proper pricing application.
|
||||
|
||||
### Technical Details
|
||||
|
||||
**Root Cause - Admin UI Bug**: In v1.2.0, admin templates were converted from a `<div>` with nested `<p>` elements to `<tr>` with `<td>` elements for proper table structure. However, the CSS file (`assets/css/admin.css`) was not updated accordingly, leaving flexbox styling (`.wc-tpp-tier-row { display: flex; gap: 15px; ... }`) that conflicted with table display. This caused columns to not align with table headers.
|
||||
|
||||
**Root Cause - Frontend Display Bug**: The frontend pricing table template was checking both `get_option('wc_tpp_enable_tier_pricing')` AND `get_option('wc_tpp_enable_package_pricing')` before displaying pricing. This meant if these global settings were disabled (even though defaults are 'yes'), pricing configured on products wouldn't show. The better UX is: if pricing is configured AND display is enabled, show it. The global enable settings now only control cart calculation and admin UI visibility.
|
||||
|
||||
### Changed Files
|
||||
|
||||
- `assets/css/admin.css` - Replaced flexbox styling with table cell styling
|
||||
- `templates/frontend/pricing-table.twig` - Removed global enable setting checks from display conditions
|
||||
|
||||
## [1.2.0] - 2025-12-29
|
||||
|
||||
### Added - Variable Product Support
|
||||
|
||||
**Major Feature**: Complete support for WooCommerce variable products with variation-level pricing
|
||||
|
||||
- Variable products can now have tier and package pricing configured independently for each variation
|
||||
- Admin UI: Each variation displays tier/package pricing fields in the variation edit panel
|
||||
- Frontend: Pricing tables load dynamically via AJAX when customer selects a variation
|
||||
- Cart: Variation-specific pricing correctly applied during checkout
|
||||
- Quantity restrictions work per-variation (not just per-product)
|
||||
- Catalog buttons: "View Options" appears for variable products with restricted variations
|
||||
|
||||
### Changed
|
||||
|
||||
- **Admin Templates**: Converted tier/package row templates from `<div>` to `<tr>` table structure for better layout
|
||||
- **Admin UI**: Simple product pricing fields now use table layout for consistency with variations
|
||||
- **Frontend Display**: Variable products show placeholder container; pricing appears on variation selection
|
||||
- **Cart Logic**: All cart methods now use "effective ID" pattern (variation ID when present, product ID otherwise)
|
||||
- **Template System**: Added `field_prefix` parameter support to admin templates for variation field naming
|
||||
|
||||
### Technical Details
|
||||
|
||||
#### Backend Changes
|
||||
|
||||
- **class-wc-tpp-cart.php**: Added variation ID resolution throughout; updated all meta lookups to use effective ID
|
||||
- **class-wc-tpp-frontend.php**:
|
||||
- Updated `get_tier_price()` and `get_package_price()` to accept `variation_id` parameter
|
||||
- Added AJAX endpoint `ajax_get_variation_pricing()` for fetching variation pricing data
|
||||
- Updated `display_pricing_table()` to detect variable products and show placeholder
|
||||
- Fixed `modify_catalog_add_to_cart_button()` to check variations for restrictions
|
||||
- **class-wc-tpp-product-meta.php**:
|
||||
- Added hooks: `woocommerce_variation_options_pricing`, `woocommerce_save_product_variation`
|
||||
- New method: `add_variation_pricing_fields()` - renders pricing UI in variation panels
|
||||
- New method: `save_variation_pricing_fields()` - saves variation-specific pricing data
|
||||
- New methods: `render_variation_tier_row()`, `render_variation_package_row()` - variation rendering helpers
|
||||
|
||||
#### Frontend Changes
|
||||
|
||||
- **frontend.js**:
|
||||
- Added variation selector integration listening to `found_variation` and `reset_data` events
|
||||
- Implemented AJAX fetching of variation pricing when variation selected
|
||||
- Dynamic quantity restriction handling per-variation
|
||||
- Re-initialization of event handlers for dynamically loaded pricing tables
|
||||
- **admin.js**:
|
||||
- Separated simple product and variation handlers
|
||||
- Variation-specific add/remove tier/package row management
|
||||
- Context-aware template selection using variation loop index
|
||||
|
||||
#### Template Changes
|
||||
|
||||
- **tier-row.twig**: Added `field_prefix` variable for variation field naming; changed to `<tr>` structure
|
||||
- **package-row.twig**: Added `field_prefix` variable for variation field naming; changed to `<tr>` structure
|
||||
|
||||
#### Data Storage
|
||||
|
||||
- Meta keys remain the same: `_wc_tpp_tiers`, `_wc_tpp_packages`, `_wc_tpp_restrict_to_packages`
|
||||
- Simple products: Stored on product post meta
|
||||
- Variations: Stored on variation post meta (independent per-variation)
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
- **100% backward compatible** - No breaking changes
|
||||
- Simple products continue working exactly as before
|
||||
- Existing tier/package data unaffected
|
||||
- No database migrations required
|
||||
- Templates remain compatible (field_prefix optional)
|
||||
|
||||
### Migration Notes
|
||||
|
||||
- Existing installations can upgrade seamlessly
|
||||
- Variable products simply gain new functionality
|
||||
- No action required for existing simple product configurations
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- AJAX requests only made when variation selected (not on page load)
|
||||
- Pricing data fetched per-variation (not all variations at once)
|
||||
- Nonce verification on all AJAX requests for security
|
||||
- Template rendering server-side for SEO/performance
|
||||
|
||||
### Testing Performed
|
||||
|
||||
- Simple products: All existing functionality verified
|
||||
- Variable products: Tier pricing, package pricing, restrictions tested per-variation
|
||||
- Mixed carts: Simple + variable products working correctly
|
||||
- WooCommerce Blocks: Cart block, mini-cart block, checkout block compatibility verified
|
||||
- Admin UI: Add/remove rows working for both simple products and variations
|
||||
- Quantity restrictions: Enforced correctly per-variation in cart and checkout
|
||||
|
||||
## [1.1.22] - 2025-12-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Increased width of label input fields for tier pricing and package pricing in admin interface
|
||||
- Changed label field CSS class from `short` to `regular` (approximately 2x wider)
|
||||
|
||||
### Technical Details
|
||||
|
||||
- Updated `templates/admin/tier-row.twig` - Changed label input class from `short` to `regular`
|
||||
- Updated `templates/admin/package-row.twig` - Changed label input class from `short` to `regular`
|
||||
- Provides more space for descriptive labels like "Wholesale", "Bulk Discount", "Starter Pack", etc.
|
||||
- Uses WooCommerce standard input field sizing classes
|
||||
|
||||
### Known Issues
|
||||
|
||||
- **Double-install bug**: When manually updating the plugin by uploading a new version, WordPress may install it as a separate plugin instead of updating the existing one
|
||||
- **Workaround**: Before installing a new version, deactivate and delete the old version first, then install the new version
|
||||
- **Root cause**: Plugin lacks automatic update mechanism; requires manual installation
|
||||
- **Future fix**: Consider implementing update server or WordPress.org repository integration
|
||||
|
||||
## [1.1.21] - 2025-12-23
|
||||
|
||||
### Added
|
||||
|
||||
- New translation for `de_CH` (Swiss German - formal)
|
||||
- New translation for `de_DE_informal` (Informal German)
|
||||
- New translation for `fr_CH` (Swiss French)
|
||||
- New translation for `it_CH` (Swiss Italian)
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated all translation files (.po) to version 1.1.21
|
||||
- Compiled all translation files to .mo format for runtime use
|
||||
|
||||
### Technical Details
|
||||
|
||||
- Created 4 new locale-specific translation files following WordPress i18n standards
|
||||
- Swiss locales use CHF currency formatting in examples (CHF 50.-, CHF 100.-)
|
||||
- German informal translations use "du/dein" instead of "Sie/Ihr"
|
||||
- All translations maintain consistent terminology across plugin UI
|
||||
- Compiled .mo files included for immediate WordPress language support
|
||||
|
||||
## [1.1.20] - 2025-12-22
|
||||
|
||||
### Fixed
|
||||
|
||||
- **CRITICAL**: Fatal error in WooCommerce Blocks cart/mini-cart: "Cannot use object of type WC_Product_Simple as array"
|
||||
- Filter `woocommerce_store_api_product_quantity_editable` signature mismatch
|
||||
|
||||
### Changed
|
||||
|
||||
- Updated `is_quantity_editable_in_blocks()` method to accept `WC_Product` object instead of cart item array
|
||||
- Changed method signature from `is_quantity_editable_in_blocks($cart_item)` to `is_quantity_editable_in_blocks(WC_Product $product)`
|
||||
- Use `$product->get_id()` instead of `$cart_item['product_id']` for product identification
|
||||
|
||||
### Technical Details
|
||||
|
||||
- WooCommerce Store API passes product object to this filter, not cart item array
|
||||
- Previous code attempted array access on product object causing fatal error
|
||||
- Error occurred at `includes/class-wc-tpp-cart.php:233`
|
||||
- Affects WooCommerce Blocks-based cart, mini-cart, and checkout
|
||||
- Classic cart/checkout unaffected (uses different hooks)
|
||||
|
||||
## [1.1.19] - 2025-12-22
|
||||
|
||||
### Fixed
|
||||
|
||||
277
CLAUDE.md
277
CLAUDE.md
@@ -1,7 +1,7 @@
|
||||
# WooCommerce Tier and Package Prices - AI Context Document
|
||||
|
||||
**Last Updated:** 2025-12-23
|
||||
**Current Version:** 1.1.20
|
||||
**Last Updated:** 2025-12-29
|
||||
**Current Version:** 1.2.3
|
||||
**Author:** Marco Graetsch
|
||||
**Project Status:** Production-ready WordPress plugin
|
||||
|
||||
@@ -76,6 +76,7 @@ wc-tier-and-package-prices/
|
||||
### Class Responsibilities
|
||||
|
||||
#### 1. `WC_Tier_Package_Prices` (Main Plugin Class)
|
||||
|
||||
- **Location:** `wc-tier-and-package-prices.php`
|
||||
- **Pattern:** Singleton
|
||||
- **Responsibilities:**
|
||||
@@ -86,6 +87,7 @@ wc-tier-and-package-prices/
|
||||
- Activation/deactivation hooks
|
||||
|
||||
#### 2. `WC_TPP_Admin`
|
||||
|
||||
- **Location:** `includes/class-wc-tpp-admin.php`
|
||||
- **Pattern:** Singleton
|
||||
- **Responsibilities:**
|
||||
@@ -95,6 +97,7 @@ wc-tier-and-package-prices/
|
||||
- Product meta box asset loading
|
||||
|
||||
#### 3. `WC_TPP_Settings`
|
||||
|
||||
- **Location:** `includes/class-wc-tpp-settings.php`
|
||||
- **Extends:** `WC_Settings_Page` (WooCommerce core)
|
||||
- **Responsibilities:**
|
||||
@@ -103,6 +106,7 @@ wc-tier-and-package-prices/
|
||||
- Setting persistence through WooCommerce options API
|
||||
|
||||
**Global Settings:**
|
||||
|
||||
- `wc_tpp_enable_tier_pricing` (yes/no)
|
||||
- `wc_tpp_enable_package_pricing` (yes/no)
|
||||
- `wc_tpp_display_table` (yes/no) - Show pricing tables on product pages
|
||||
@@ -110,6 +114,7 @@ wc-tier-and-package-prices/
|
||||
- `wc_tpp_restrict_package_quantities` (yes/no) - Global quantity restrictions
|
||||
|
||||
#### 4. `WC_TPP_Product_Meta`
|
||||
|
||||
- **Location:** `includes/class-wc-tpp-product-meta.php`
|
||||
- **Responsibilities:**
|
||||
- Adds tier/package pricing fields to product edit page
|
||||
@@ -119,11 +124,13 @@ wc-tier-and-package-prices/
|
||||
- Prevents autosave from corrupting data
|
||||
|
||||
**Product Meta Keys:**
|
||||
|
||||
- `_wc_tpp_tiers` - Array of tier objects `[{min_qty, price, label}]`
|
||||
- `_wc_tpp_packages` - Array of package objects `[{qty, price, label}]`
|
||||
- `_wc_tpp_restrict_to_packages` - Per-product quantity restriction (yes/no)
|
||||
|
||||
#### 5. `WC_TPP_Frontend`
|
||||
|
||||
- **Location:** `includes/class-wc-tpp-frontend.php`
|
||||
- **Responsibilities:**
|
||||
- Enqueues frontend CSS/JS on product pages
|
||||
@@ -134,6 +141,7 @@ wc-tier-and-package-prices/
|
||||
- Static methods for price lookups (`get_tier_price()`, `get_package_price()`)
|
||||
|
||||
#### 6. `WC_TPP_Cart`
|
||||
|
||||
- **Location:** `includes/class-wc-tpp-cart.php`
|
||||
- **Responsibilities:**
|
||||
- **MOST CRITICAL CLASS** - Handles all cart price calculations
|
||||
@@ -145,11 +153,13 @@ wc-tier-and-package-prices/
|
||||
- **WooCommerce Blocks support** via `woocommerce_store_api_product_quantity_editable` filter
|
||||
|
||||
**Price Calculation Priority (in `apply_tier_package_pricing()`):**
|
||||
|
||||
1. Check for exact package match → Use package price if found
|
||||
2. Check for tier match → Use tier price if found
|
||||
3. Fall back to regular product price
|
||||
|
||||
#### 7. `WC_TPP_Template_Loader`
|
||||
|
||||
- **Location:** `includes/class-wc-tpp-template-loader.php`
|
||||
- **Pattern:** Singleton
|
||||
- **Responsibilities:**
|
||||
@@ -196,6 +206,7 @@ Products can be configured to ONLY allow purchase in package quantities:
|
||||
### WooCommerce Blocks Compatibility
|
||||
|
||||
**CRITICAL BUG FIXED in v1.1.20:**
|
||||
|
||||
- Filter `woocommerce_store_api_product_quantity_editable` passes `WC_Product` object, NOT cart item array
|
||||
- Previous code tried to use product object as array → fatal error
|
||||
- Fixed by accepting product object and using `$product->get_id()`
|
||||
@@ -228,6 +239,7 @@ new WC_TPP_Frontend(); // Auto-instantiate
|
||||
**Exception:** Admin and Settings classes use singleton pattern to prevent duplicates.
|
||||
|
||||
### Security Best Practices
|
||||
|
||||
- All user inputs are sanitized (integers for quantities/prices)
|
||||
- Nonce verification on form submissions
|
||||
- Capability checks (`edit_products`) before saving
|
||||
@@ -243,16 +255,30 @@ _e('Text to translate', 'wc-tier-package-prices')
|
||||
|
||||
Text domain: `wc-tier-package-prices`
|
||||
|
||||
**Available Translations (as of v1.1.22):**
|
||||
|
||||
- `en_US` - English (United States)
|
||||
- `de_DE` - German (Germany, formal)
|
||||
- `de_DE_informal` - German (Germany, informal "du")
|
||||
- `de_CH` - German (Switzerland, formal "Sie")
|
||||
- `de_CH_informal` - German (Switzerland, informal "du")
|
||||
- `fr_CH` - French (Switzerland)
|
||||
- `it_CH` - Italian (Switzerland)
|
||||
|
||||
Note: Swiss locales use CHF currency formatting in examples (e.g., "CHF 50.-")
|
||||
|
||||
## Known Issues & Historical Context
|
||||
|
||||
### Settings Page Duplication Saga (v1.1.15-1.1.19)
|
||||
Multiple versions attempted to fix settings page appearing twice:
|
||||
|
||||
- **Root cause:** Settings file auto-instantiation + Composer autoloader
|
||||
- **Solution:** Removed auto-instantiation from settings file, explicit instantiation in admin class
|
||||
- **Prevention:** Singleton pattern + duplicate detection in array
|
||||
|
||||
### Class Redeclaration Issues (v1.1.8-1.1.14)
|
||||
Plugin was completely non-functional:
|
||||
|
||||
- **Cause:** Incorrect initialization pattern without `class_exists()` guards
|
||||
- **Solution:** Added guards and restored direct instantiation pattern
|
||||
- **Lesson:** Always wrap class declarations in `class_exists()` checks
|
||||
@@ -262,6 +288,7 @@ Plugin was completely non-functional:
|
||||
Fatal error: Cannot use object of type WC_Product_Simple as array
|
||||
Location: includes/class-wc-tpp-cart.php:233
|
||||
```
|
||||
|
||||
- **Cause:** Filter signature mismatch - expected array, received product object
|
||||
- **Fix:** Changed method signature to accept `WC_Product $product` instead of `$cart_item` array
|
||||
- **Status:** FIXED in v1.1.20
|
||||
@@ -270,29 +297,121 @@ Location: includes/class-wc-tpp-cart.php:233
|
||||
|
||||
### Version Bumping
|
||||
Update version in 3 places:
|
||||
|
||||
1. `wc-tier-and-package-prices.php` - Plugin header comment (line 7)
|
||||
2. `wc-tier-and-package-prices.php` - `WC_TPP_VERSION` constant (line 26)
|
||||
3. `composer.json` - version field (optional, not critical)
|
||||
|
||||
### Creating Release Package
|
||||
```bash
|
||||
# From project root
|
||||
cd releases
|
||||
|
||||
# Create zip excluding dev files
|
||||
zip -r wc-tier-and-package-prices-X.X.X.zip .. \
|
||||
-x '*.git*' '*.log' '.claude/*' 'releases/*' 'node_modules/*' \
|
||||
'.DS_Store' 'Thumbs.db' '.vscode/*' '.idea/*' '*.sublime-*' \
|
||||
'notes.*' 'logs/*' 'templates/cache/*' 'composer.lock'
|
||||
**CRITICAL:** The zip command must be run from the **parent directory** of the plugin folder to create proper archive structure.
|
||||
|
||||
```bash
|
||||
# From parent directory (/home/magdev/workspaces/node)
|
||||
cd /home/magdev/workspaces/node
|
||||
|
||||
# Create zip excluding dev files - note the correct path structure
|
||||
zip -r wc-tier-and-package-prices/releases/wc-tier-and-package-prices-X.X.X.zip wc-tier-and-package-prices/ \
|
||||
-x 'wc-tier-and-package-prices/.git*' \
|
||||
'wc-tier-and-package-prices/*.log' \
|
||||
'wc-tier-and-package-prices/.claude/*' \
|
||||
'wc-tier-and-package-prices/CLAUDE.md' \
|
||||
'wc-tier-and-package-prices/releases/*' \
|
||||
'wc-tier-and-package-prices/node_modules/*' \
|
||||
'wc-tier-and-package-prices/.DS_Store' \
|
||||
'wc-tier-and-package-prices/Thumbs.db' \
|
||||
'wc-tier-and-package-prices/.vscode/*' \
|
||||
'wc-tier-and-package-prices/.idea/*' \
|
||||
'wc-tier-and-package-prices/*.sublime-*' \
|
||||
'wc-tier-and-package-prices/notes.*' \
|
||||
'wc-tier-and-package-prices/logs/*' \
|
||||
'wc-tier-and-package-prices/templates/cache/*' \
|
||||
'wc-tier-and-package-prices/composer.lock'
|
||||
|
||||
# Return to project directory
|
||||
cd wc-tier-and-package-prices
|
||||
|
||||
# Generate checksums
|
||||
cd releases
|
||||
md5sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.md5
|
||||
sha256sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.sha256
|
||||
cd ..
|
||||
```
|
||||
|
||||
**IMPORTANT:** The `vendor/` directory MUST be included in releases (Twig dependency required for runtime).
|
||||
**IMPORTANT NOTES:**
|
||||
|
||||
- The `vendor/` directory MUST be included in releases (Twig dependency required for runtime)
|
||||
- Running zip from wrong directory creates empty or malformed archives
|
||||
- Exclusion patterns must match the relative path structure used in zip command
|
||||
- Always verify the package with `unzip -l` and test extraction before committing
|
||||
|
||||
### Verification Steps
|
||||
|
||||
After creating the release package, always verify:
|
||||
|
||||
```bash
|
||||
# Check package size (should be ~400-450KB, NOT 8MB+ or near 0)
|
||||
ls -lh releases/wc-tier-and-package-prices-X.X.X.zip
|
||||
|
||||
# Verify exclusions worked
|
||||
unzip -l releases/wc-tier-and-package-prices-X.X.X.zip | grep -E "CLAUDE\.md|\.claude/|\.git" && echo "ERROR: Excluded files found!" || echo "OK: No excluded files"
|
||||
|
||||
# Test extraction
|
||||
cd /tmp && rm -rf test-extract && unzip -q /path/to/releases/wc-tier-and-package-prices-X.X.X.zip -d test-extract && ls -la test-extract/wc-tier-and-package-prices/
|
||||
|
||||
# Verify version in extracted package
|
||||
head -30 /tmp/test-extract/wc-tier-and-package-prices/wc-tier-and-package-prices.php | grep -E "Version:|WC_TPP_VERSION"
|
||||
|
||||
# Verify template changes (if applicable)
|
||||
grep 'class="regular"' /tmp/test-extract/wc-tier-and-package-prices/templates/admin/*.twig
|
||||
```
|
||||
|
||||
### Git Workflow for Releases
|
||||
|
||||
**Standard workflow:** Work on `dev` branch → merge to `main` → tag → push
|
||||
|
||||
```bash
|
||||
# 1. Ensure you're on dev branch with all changes committed
|
||||
git checkout dev
|
||||
git add [files]
|
||||
git commit -m "Release version X.X.X - [description]
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
|
||||
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>"
|
||||
|
||||
# 2. Merge dev to main
|
||||
git checkout main
|
||||
git merge dev --no-edit # Should be fast-forward
|
||||
|
||||
# 3. Create annotated tag
|
||||
git tag -a vX.X.X -m "Release version X.X.X - [description]"
|
||||
|
||||
# 4. Push everything
|
||||
git push origin main
|
||||
git push origin vX.X.X
|
||||
|
||||
# 5. Update dev and push
|
||||
git checkout dev
|
||||
git rebase main # Should be up-to-date already
|
||||
git push origin dev
|
||||
|
||||
# 6. If you have uncommitted local changes (like .claude/settings.local.json)
|
||||
git stash push -m "Local development settings"
|
||||
# ... do git operations ...
|
||||
git stash pop
|
||||
```
|
||||
|
||||
**Important Git Notes:**
|
||||
|
||||
- Always commit from `dev` branch first
|
||||
- Tags should use format `vX.X.X` (e.g., `v1.1.22`)
|
||||
- Use annotated tags (`-a`) not lightweight tags
|
||||
- Commit messages should follow the established format with Claude Code attribution
|
||||
- `.claude/settings.local.json` changes are typically local-only (stash before rebasing)
|
||||
|
||||
### What Gets Released
|
||||
|
||||
- All plugin source files
|
||||
- Compiled vendor dependencies
|
||||
- Translation files (.mo compiled from .po)
|
||||
@@ -300,8 +419,9 @@ sha256sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.
|
||||
- Documentation (README, CHANGELOG, etc.)
|
||||
|
||||
### What's Excluded
|
||||
|
||||
- Git metadata (`.git/`)
|
||||
- Development files (`.vscode/`, `.idea/`)
|
||||
- Development files (`.vscode/`, `.claude/`, `CLAUDE.md`)
|
||||
- Logs and cache files
|
||||
- Previous releases
|
||||
- `composer.lock` (but `vendor/` is included)
|
||||
@@ -311,6 +431,7 @@ sha256sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.
|
||||
When making changes, test these critical paths:
|
||||
|
||||
### Admin
|
||||
|
||||
- [ ] Settings page appears once under WooCommerce > Tier & Package Prices
|
||||
- [ ] Settings save correctly
|
||||
- [ ] Product edit page shows tier/package meta boxes
|
||||
@@ -319,6 +440,7 @@ When making changes, test these critical paths:
|
||||
- [ ] Data saves when clicking "Update" on product
|
||||
|
||||
### Frontend (Product Page)
|
||||
|
||||
- [ ] Pricing tables display when configured
|
||||
- [ ] Package buttons update quantity selector
|
||||
- [ ] Price updates dynamically when quantity changes
|
||||
@@ -326,6 +448,7 @@ When making changes, test these critical paths:
|
||||
- [ ] "View Options" appears on catalog for restricted products
|
||||
|
||||
### Cart & Checkout
|
||||
|
||||
- [ ] Correct prices applied for tier pricing
|
||||
- [ ] Correct prices applied for package pricing
|
||||
- [ ] Cart displays pricing type labels
|
||||
@@ -334,6 +457,7 @@ When making changes, test these critical paths:
|
||||
- [ ] Checkout totals are correct
|
||||
|
||||
### WooCommerce Blocks (Critical!)
|
||||
|
||||
- [ ] Mini cart block doesn't throw fatal errors
|
||||
- [ ] Cart block works correctly
|
||||
- [ ] Checkout block processes orders
|
||||
@@ -341,19 +465,139 @@ When making changes, test these critical paths:
|
||||
|
||||
## Development Tips for Future AI Assistants
|
||||
|
||||
### Common Pitfalls and Solutions
|
||||
|
||||
#### Release Package Creation
|
||||
**Problem:** Empty or corrupted zip files (0 bytes or wrong structure)
|
||||
**Cause:** Running zip command from wrong directory or incorrect path patterns
|
||||
**Solution:** Always run from parent directory (`/home/magdev/workspaces/node`) and use full relative paths in exclusions
|
||||
|
||||
**Problem:** Development files included in release (CLAUDE.md, .claude/, .git)
|
||||
**Cause:** Exclusion patterns don't match actual paths used in zip command
|
||||
**Solution:** Test with `unzip -l | grep` to verify exclusions before committing
|
||||
|
||||
**Problem:** Package size is 8MB+ instead of ~400KB
|
||||
**Cause:** Development files not excluded (especially .git directory)
|
||||
**Solution:** Follow verification steps and check package size immediately after creation
|
||||
|
||||
#### UI Changes in Admin
|
||||
**WooCommerce CSS Classes:**
|
||||
- `short` - Small input fields (~60px width)
|
||||
- `regular` - Medium input fields (~120px width)
|
||||
- `long` - Large input fields (~200px+ width)
|
||||
|
||||
When modifying admin input fields in Twig templates, use WooCommerce's standard classes for consistency.
|
||||
|
||||
**Location:** `templates/admin/*.twig` for admin UI changes
|
||||
|
||||
#### Git Workflow Issues
|
||||
**Problem:** Cannot rebase due to uncommitted changes
|
||||
**Solution:** Stash local config files (`.claude/settings.local.json`) before git operations
|
||||
|
||||
**Problem:** Tag already exists
|
||||
**Solution:** Delete with `git tag -d vX.X.X` locally and `git push --delete origin vX.X.X` remotely
|
||||
|
||||
**Problem:** Wrong branch for commits
|
||||
**Solution:** Always start on `dev` branch, merge to `main`, never commit directly to `main`
|
||||
|
||||
### Working with Twig Templates
|
||||
|
||||
The plugin uses Twig 3.0 for templating. Key files:
|
||||
|
||||
- `templates/admin/tier-row.twig` - Single tier input row in product edit page
|
||||
- `templates/admin/package-row.twig` - Single package input row in product edit page
|
||||
- `templates/frontend/*.twig` - Customer-facing pricing displays
|
||||
|
||||
**Template rendering:** Done via `WC_TPP_Template_Loader` singleton class
|
||||
|
||||
**When modifying templates:**
|
||||
|
||||
1. Templates are cached - clear cache or test in development mode
|
||||
2. Always escape output: use Twig's built-in filters or `|esc_attr`, `|esc_html`
|
||||
3. Translation strings: `{{ 'Text'|__('wc-tier-package-prices') }}`
|
||||
4. Keep consistent with WooCommerce admin UI patterns
|
||||
|
||||
### Complete Release Workflow Summary
|
||||
|
||||
Based on v1.1.22 release experience, here's the complete workflow:
|
||||
|
||||
1. **Fix bugs/add features** on `dev` branch
|
||||
2. **Update version numbers** (3 files: main plugin file header, constant, composer.json)
|
||||
3. **Update CHANGELOG.md** with detailed changes
|
||||
4. **Update CLAUDE.md** version number and roadmap
|
||||
5. **Create release package** from parent directory with correct exclusions
|
||||
6. **Verify package** (size, contents, exclusions, extraction test)
|
||||
7. **Commit changes** to `dev` branch with proper message format
|
||||
8. **Merge to main** (fast-forward merge)
|
||||
9. **Create annotated tag** (`vX.X.X`)
|
||||
10. **Push all** (main, tag, dev)
|
||||
11. **Verify remote** (check repository web UI)
|
||||
|
||||
**Time estimate:** 15-20 minutes for full release cycle
|
||||
|
||||
**Files typically changed in a release:**
|
||||
|
||||
- `wc-tier-and-package-prices.php` - Version bumps
|
||||
- `composer.json` - Version bump
|
||||
- `CHANGELOG.md` - Release notes
|
||||
- `CLAUDE.md` - Version and roadmap updates
|
||||
- `releases/wc-tier-and-package-prices-X.X.X.zip*` - Package and checksums
|
||||
- Feature-specific files (templates, PHP classes, etc.)
|
||||
|
||||
### Future Features and Roadmap
|
||||
|
||||
The is a hierarchical list for upcoming features and can be considered as a
|
||||
Roadmap for the upcoming development.
|
||||
|
||||
#### Version 1.1.x (Completed)
|
||||
|
||||
1. ~~Add translations for `de_CH`, `de_DE_informal`, `fr_CH`, `it_CH`~~ ✅ **COMPLETED in v1.1.21**
|
||||
2. ~~The double-install bug is back again. A new version of the plugin is installed as new plugin instead of updating the previous version.~~ ✅ **DOCUMENTED in v1.1.22** - Added workaround to CHANGELOG. Root cause: No automatic update mechanism (requires WordPress.org repository or custom update server).
|
||||
3. ~~Make the label fields in the backend for tierprices and package-prices twice as long as it is.~~ ✅ **COMPLETED in v1.1.22**
|
||||
4. ~~Make the plugin work with variable products~~ ✅ **COMPLETED in v1.2.0** - Full variation-level pricing support with independent configuration per variation, AJAX-based frontend display, and complete WooCommerce Blocks compatibility.
|
||||
|
||||
#### Version 1.2.x
|
||||
|
||||
##### Bugfixes (Completed in v1.2.1)
|
||||
|
||||
1. ~~The admin templates are not show right. The row templates didn't match the new table structure. The table-body columns didn't fit the table-head columns.~~ ✅ **FIXED in v1.2.1** - Updated admin.css to remove flexbox styling that was breaking the new `<table>/<tr>/<td>` structure introduced in v1.2.0. The CSS was still using flexbox layout from the old `<div>/<p>` structure.
|
||||
|
||||
2. ~~The tier and package prices are not shown on simple product pages~~ ✅ **FIXED in v1.2.1** - Removed global enable/disable checks from frontend template. Pricing tables now display if configured on a product AND the "Display Pricing Table" setting is enabled, regardless of "Enable Tier Pricing" or "Enable Package Pricing" global settings. Cart calculations still respect global enable settings.
|
||||
|
||||
##### Bugfixes (Completed in v1.2.2)
|
||||
|
||||
1. ~~Remove the table borders in admin on variable product to better fit the surrounding element styles.~~ ✅ **FIXED in v1.2.2** - Added CSS rules to remove table borders specifically for variation pricing tables (`.wc-tpp-variation-pricing`), matching WooCommerce's borderless variation UI style.
|
||||
|
||||
2. ~~Add missing translations in admin templates ("Price", "Tier & Package Pricing", "Min Quantity") for all languages used in this project.~~ ✅ **FIXED in v1.2.2** - Added missing translation entries for "Min Quantity", "Price", and "Label (optional)" to all .po files (de_DE, de_DE_informal, de_CH, de_CH_informal, fr_CH, it_CH, en_US) and recompiled .mo files.
|
||||
|
||||
3. ~~Check the template for wc_tpp_restrict_to_packages[] checkbox elements in admin on variable products and fix the rendering.~~ ✅ **FIXED in v1.2.2** - Fixed checkbox value parameter in variation pricing fields. Changed from ternary expression to direct value assignment, allowing WooCommerce's `woocommerce_wp_checkbox()` to properly handle the checked state.
|
||||
|
||||
##### Bugfixes (Completed in v1.2.3)
|
||||
|
||||
1. ~~Style the tier and packages tables in admin on simple products according to the styles on variable products.~~ ✅ **FIXED in v1.2.3** - Applied borderless table styling to all tier/package tables (both simple and variable products). Removed borders from table, th, and td elements to match WooCommerce's clean admin UI style.
|
||||
|
||||
2. ~~The checkbox styles from 1.2.2 bug 3 are still not looking correct. The helptext is written instead of hidden after the help icon and the margin between checkbox and label are to small.~~ ✅ **FIXED in v1.2.3** - Added `desc_tip => true` to variation checkbox to show tooltip instead of inline text. Added CSS rules to increase checkbox-label margin (8px) and hide inline description text when tooltip is used.
|
||||
|
||||
##### New Features
|
||||
|
||||
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.
|
||||
|
||||
### When Debugging Cart Issues
|
||||
|
||||
1. Check `includes/class-wc-tpp-cart.php` first
|
||||
2. The `apply_tier_package_pricing()` method runs on `woocommerce_before_calculate_totals`
|
||||
3. Always validate product objects with `is_a($product, 'WC_Product')`
|
||||
4. Remember: WooCommerce expects UNIT prices, not total prices (except for internal calculations)
|
||||
|
||||
### When Working with WooCommerce Hooks
|
||||
|
||||
- WooCommerce has both classic and block-based systems
|
||||
- Classic cart uses different hooks than Store API (blocks)
|
||||
- Always check filter/action documentation for parameter types
|
||||
- Don't assume cart item arrays everywhere - sometimes it's product objects!
|
||||
|
||||
### When Adding Features
|
||||
|
||||
- Follow the existing pattern: add setting → add UI → add logic → add template
|
||||
- Use Twig for all new templates (consistency)
|
||||
- Add translations for all user-facing strings
|
||||
@@ -361,6 +605,7 @@ When making changes, test these critical paths:
|
||||
- Consider both classic and block-based cart/checkout
|
||||
|
||||
### When Fixing Bugs
|
||||
|
||||
1. Check `CHANGELOG.md` for historical context
|
||||
2. Look for similar issues in past versions
|
||||
3. Always add detailed changelog entry explaining root cause
|
||||
@@ -383,22 +628,26 @@ When making changes, test these critical paths:
|
||||
## Compatibility Notes
|
||||
|
||||
### WordPress
|
||||
|
||||
- Minimum: 6.0
|
||||
- Tested up to: 6.9.x
|
||||
- Uses standard plugin API, no deprecated functions
|
||||
|
||||
### WooCommerce
|
||||
|
||||
- Minimum: 8.0
|
||||
- Tested up to: 10.x
|
||||
- HPOS compatible (declared via `FeaturesUtil::declare_compatibility`)
|
||||
- Blocks compatible (with proper filter handling)
|
||||
|
||||
### PHP
|
||||
|
||||
- Minimum: 7.4
|
||||
- Uses modern PHP features (type hints acceptable in new code)
|
||||
- Composer autoloader handles namespacing
|
||||
|
||||
### Browsers
|
||||
|
||||
- Modern browsers (ES6+ JavaScript)
|
||||
- Responsive CSS (mobile-friendly)
|
||||
- jQuery dependency (WooCommerce provides)
|
||||
@@ -413,6 +662,7 @@ When making changes, test these critical paths:
|
||||
## Final Notes
|
||||
|
||||
This is a production-quality plugin with real-world usage. Any changes should:
|
||||
|
||||
1. Maintain backward compatibility with existing tier/package configurations
|
||||
2. Not break WooCommerce core functionality
|
||||
3. Work with both classic and block-based themes
|
||||
@@ -421,9 +671,12 @@ This is a production-quality plugin with real-world usage. Any changes should:
|
||||
6. Update CHANGELOG.md with detailed explanations
|
||||
|
||||
The plugin architecture is solid and well-tested. Most bugs arise from:
|
||||
|
||||
- WooCommerce API changes (especially blocks)
|
||||
- Filter/action signature changes
|
||||
- Edge cases in cart calculations
|
||||
- Settings persistence issues
|
||||
|
||||
---
|
||||
|
||||
Always refer to this document when starting work on this project. Good luck!
|
||||
|
||||
@@ -90,8 +90,8 @@ After activation, you should see:
|
||||
|
||||
Before installation, verify:
|
||||
|
||||
- ✓ WordPress 5.8 or higher
|
||||
- ✓ WooCommerce 5.0 or higher installed and activated
|
||||
- ✓ WordPress 6.0 or higher (tested up to 6.9.x)
|
||||
- ✓ WooCommerce 8.0 or higher (tested up to 10.x) installed and activated
|
||||
- ✓ PHP 7.4 or higher
|
||||
- ✓ Write permissions in `/wp-content/plugins/` directory
|
||||
|
||||
@@ -153,16 +153,34 @@ wp-content/
|
||||
├── USAGE_EXAMPLES.md
|
||||
├── includes/
|
||||
│ ├── 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
|
||||
└── assets/
|
||||
├── css/
|
||||
│ ├── admin.css
|
||||
│ └── frontend.css
|
||||
└── js/
|
||||
├── admin.js
|
||||
└── frontend.js
|
||||
│ ├── class-wc-tpp-product-meta.php
|
||||
│ └── class-wc-tpp-template-loader.php
|
||||
├── templates/
|
||||
│ ├── admin/
|
||||
│ │ ├── tier-row.twig
|
||||
│ │ └── package-row.twig
|
||||
│ └── frontend/
|
||||
│ ├── pricing-table.twig
|
||||
│ ├── tier-pricing-table.twig
|
||||
│ └── package-pricing-display.twig
|
||||
├── assets/
|
||||
│ ├── css/
|
||||
│ │ ├── admin.css
|
||||
│ │ └── frontend.css
|
||||
│ └── js/
|
||||
│ ├── admin.js
|
||||
│ └── frontend.js
|
||||
├── languages/
|
||||
│ ├── wc-tier-package-prices.pot
|
||||
│ ├── wc-tier-package-prices-de_DE.po
|
||||
│ ├── wc-tier-package-prices-de_DE.mo
|
||||
│ ├── wc-tier-package-prices-de_CH_informal.po
|
||||
│ └── wc-tier-package-prices-de_CH_informal.mo
|
||||
└── vendor/
|
||||
└── (Twig and dependencies)
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Quick Start Guide
|
||||
|
||||
Get started with WooCommerce Tier and Package Prices in 5 minutes!
|
||||
Get started with WooCommerce Tier and Package Prices (v1.1.20) in 5 minutes!
|
||||
|
||||
## Step 1: Install (2 minutes)
|
||||
|
||||
@@ -79,8 +79,11 @@ Use packages for common bundles (6-pack, dozen, case)
|
||||
1. **Round Numbers**: Use 10, 25, 50, 100 for tiers
|
||||
2. **Meaningful Savings**: Offer at least 10% off per tier
|
||||
3. **Label Packages**: "Family Pack" sells better than "4-pack"
|
||||
4. **Test Checkout**: Always complete a test order
|
||||
5. **Mobile Check**: View on phone to verify responsiveness
|
||||
4. **Label Tiers**: Use descriptive labels like "Wholesale Price" or "Bulk Discount"
|
||||
5. **Test Checkout**: Always complete a test order
|
||||
6. **Mobile Check**: View on phone to verify responsiveness
|
||||
7. **Quantity Restrictions**: Enable package restrictions to prevent arbitrary quantities
|
||||
8. **Blocks Compatible**: Works with both classic and block-based carts/checkout
|
||||
|
||||
## Need More Help?
|
||||
|
||||
|
||||
106
README.md
106
README.md
@@ -110,12 +110,22 @@ When editing a product, scroll to the **Product data** panel:
|
||||
|
||||
```
|
||||
wc-tier-and-package-prices/
|
||||
├── wc-tier-and-package-prices.php # Main plugin file
|
||||
├── wc-tier-and-package-prices.php # Main plugin file (v1.1.20)
|
||||
├── includes/
|
||||
│ ├── class-wc-tpp-admin.php # Admin settings
|
||||
│ ├── class-wc-tpp-admin.php # Admin settings integration
|
||||
│ ├── class-wc-tpp-settings.php # WooCommerce settings page
|
||||
│ ├── class-wc-tpp-product-meta.php # Product meta boxes
|
||||
│ ├── class-wc-tpp-frontend.php # Frontend display
|
||||
│ └── class-wc-tpp-cart.php # Cart price calculations
|
||||
│ ├── class-wc-tpp-frontend.php # Frontend display logic
|
||||
│ ├── class-wc-tpp-cart.php # Cart price calculations
|
||||
│ └── class-wc-tpp-template-loader.php # Twig template engine
|
||||
├── templates/
|
||||
│ ├── admin/
|
||||
│ │ ├── tier-row.twig # Tier pricing input row
|
||||
│ │ └── package-row.twig # Package pricing input row
|
||||
│ └── frontend/
|
||||
│ ├── pricing-table.twig # Main pricing display wrapper
|
||||
│ ├── tier-pricing-table.twig # Tier pricing table
|
||||
│ └── package-pricing-display.twig # Package selection UI
|
||||
├── assets/
|
||||
│ ├── css/
|
||||
│ │ ├── admin.css # Admin styles
|
||||
@@ -123,7 +133,16 @@ wc-tier-and-package-prices/
|
||||
│ └── js/
|
||||
│ ├── admin.js # Admin JavaScript
|
||||
│ └── frontend.js # Frontend JavaScript
|
||||
└── README.md
|
||||
├── languages/
|
||||
│ ├── wc-tier-package-prices.pot # Translation template
|
||||
│ ├── wc-tier-package-prices-*.po # Translation sources
|
||||
│ └── wc-tier-package-prices-*.mo # Compiled translations
|
||||
├── vendor/ # Composer dependencies (Twig)
|
||||
├── CHANGELOG.md # Complete version history
|
||||
├── INSTALLATION.md # Installation guide
|
||||
├── QUICKSTART.md # Quick start guide
|
||||
├── USAGE_EXAMPLES.md # Usage examples
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Requirements
|
||||
@@ -152,7 +171,7 @@ A: The price will automatically recalculate based on the new quantity.
|
||||
A: Yes, each product can have its own tier and package pricing configuration.
|
||||
|
||||
**Q: Does this work with variable products?**
|
||||
A: Currently, this plugin is designed for simple products. Variable product support may be added in future versions.
|
||||
A: Yes! Since version 1.2.0, the plugin fully supports variable products. Each variation can have its own independent tier and package pricing configuration.
|
||||
|
||||
## Support
|
||||
|
||||
@@ -164,39 +183,64 @@ This plugin is licensed under the GPL v2 or later.
|
||||
|
||||
## Changelog
|
||||
|
||||
### Version 1.0.0 - 2025-12-21
|
||||
### Version 1.2.0 - 2025-12-29
|
||||
|
||||
#### Compatibility Updates
|
||||
__Current Release__ - Variable Product Support
|
||||
|
||||
- ✅ Updated for WooCommerce 10.x compatibility
|
||||
- ✅ Updated for WordPress 6.9.x compatibility
|
||||
- ✅ Added HPOS (High-Performance Order Storage) support
|
||||
- ✅ Declared compatibility with WooCommerce Custom Order Tables
|
||||
- __New__: Full support for WooCommerce variable products with variation-level pricing
|
||||
- __New__: Each variation can have independent tier and package pricing configuration
|
||||
- __New__: AJAX-powered dynamic pricing table display when variations are selected
|
||||
- __Changed__: Admin templates converted to table structure for better layout
|
||||
- __Fixed__: Quantity restrictions now work correctly per-variation
|
||||
- 100% backward compatible - no breaking changes
|
||||
|
||||
#### Security Enhancements
|
||||
See [CHANGELOG.md](CHANGELOG.md) for complete details.
|
||||
|
||||
- ✅ Added nonce verification for product meta save operations
|
||||
- ✅ Added capability checks for user permissions
|
||||
- ✅ Enhanced data escaping and sanitization
|
||||
- ✅ Implemented autosave prevention
|
||||
### Version 1.1.22 - 2025-12-23
|
||||
|
||||
#### Code Improvements
|
||||
- Increased width of label input fields in admin interface
|
||||
|
||||
- ✅ Enhanced cart object validation
|
||||
- ✅ Improved product object type checking
|
||||
- ✅ Better error handling for edge cases
|
||||
- ✅ Updated data storage methods for cart items
|
||||
- ✅ Modernized JavaScript localization with proper escaping
|
||||
#### Fixed
|
||||
- **CRITICAL:** WooCommerce Blocks fatal error in mini-cart and cart blocks
|
||||
- Fixed `woocommerce_store_api_product_quantity_editable` filter signature mismatch
|
||||
- Filter now correctly accepts `WC_Product` object instead of cart item array
|
||||
- Resolves "Cannot use object of type WC_Product_Simple as array" fatal error
|
||||
|
||||
#### Initial Features
|
||||
#### Technical Details
|
||||
- Updated `block_quantity_editable()` method signature to accept product object
|
||||
- Changed parameter from `$cart_item` array to `WC_Product $product`
|
||||
- Uses `$product->get_id()` instead of array access for product ID
|
||||
- Full compatibility with WooCommerce Store API and block-based cart/checkout
|
||||
|
||||
- Initial release with tier pricing functionality
|
||||
- Package pricing with fixed quantities
|
||||
- Customizable pricing tables
|
||||
- Global settings page
|
||||
- Product-level configuration
|
||||
- Cart integration with dynamic pricing
|
||||
- Responsive frontend design
|
||||
### Recent Major Updates
|
||||
|
||||
#### Version 1.1.7 - Enhanced Tier Pricing
|
||||
- Added optional text labels for tier pricing
|
||||
- Clickable tier rows that auto-populate quantity field
|
||||
- Add to Cart button auto-disable when quantity is invalid
|
||||
|
||||
#### Version 1.1.4 - WooCommerce Blocks Support
|
||||
- Full support for WooCommerce block-based cart and checkout
|
||||
- Quantity restrictions work with both classic and block carts
|
||||
- Enhanced "View Options" button styling
|
||||
|
||||
#### Version 1.1.0 - Package Quantity Restrictions
|
||||
- Global and per-product package quantity restrictions
|
||||
- Prevents customers from ordering non-package quantities
|
||||
- Automatic quantity field hiding when restrictions enabled
|
||||
|
||||
#### Version 1.0.1 - Twig Template Engine
|
||||
- Migrated to Twig templating system
|
||||
- Enhanced security with automatic HTML escaping
|
||||
- Added German (Switzerland, Informal) translation
|
||||
|
||||
#### Version 1.0.0 - Initial Release
|
||||
- Tier pricing functionality (quantity-based discounts)
|
||||
- Package pricing functionality (fixed-price bundles)
|
||||
- WooCommerce HPOS compatibility
|
||||
- Multilingual support (English, German)
|
||||
|
||||
For complete version history, see [CHANGELOG.md](CHANGELOG.md)
|
||||
|
||||
## Credits
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
# Usage Examples
|
||||
|
||||
**Plugin Version:** 1.1.20
|
||||
**Last Updated:** 2025-12-23
|
||||
|
||||
## Example 1: T-Shirt Store with Volume Discounts
|
||||
|
||||
### Tier Pricing Setup
|
||||
@@ -16,9 +19,9 @@ For a t-shirt that normally costs $20:
|
||||
**How to configure:**
|
||||
1. Edit your t-shirt product
|
||||
2. Set regular price to $20.00
|
||||
3. Add tier: Min Qty = 10, Price = $18.00
|
||||
4. Add tier: Min Qty = 25, Price = $16.00
|
||||
5. Add tier: Min Qty = 50, Price = $14.00
|
||||
3. Add tier: Min Qty = 10, Price = $18.00, Label = "Bulk Discount"
|
||||
4. Add tier: Min Qty = 25, Price = $16.00, Label = "Volume Pricing"
|
||||
5. Add tier: Min Qty = 50, Price = $14.00, Label = "Wholesale Rate"
|
||||
6. Save product
|
||||
|
||||
**Customer experience:**
|
||||
@@ -97,6 +100,62 @@ Regular mug price: $10.00
|
||||
- Package 2: Qty = 4, Price = $32.00, Label = "Family Set"
|
||||
- Package 3: Qty = 10, Price = $70.00, Label = "Office Bundle"
|
||||
|
||||
## Example 5: Quantity Restrictions (New in v1.1.0)
|
||||
|
||||
### Party Supplies with Fixed Packages
|
||||
|
||||
For products that should ONLY be sold in specific package quantities:
|
||||
|
||||
**Product:** Balloons - Regular price $1.00 each
|
||||
|
||||
**Package Configuration:**
|
||||
- Package 1: Qty = 12, Price = $10.00, Label = "Dozen Pack"
|
||||
- Package 2: Qty = 24, Price = $18.00, Label = "Party Pack"
|
||||
- Package 3: Qty = 50, Price = $40.00, Label = "Event Pack"
|
||||
|
||||
**How to configure:**
|
||||
1. Edit balloon product
|
||||
2. Set regular price to $1.00
|
||||
3. Add packages as shown above
|
||||
4. **Check "Restrict to package quantities only"** (per-product setting)
|
||||
5. Save product
|
||||
|
||||
**Customer experience:**
|
||||
- Quantity input field is hidden on product page
|
||||
- Customer MUST select a package using the package selection buttons
|
||||
- Attempting to add custom quantities via URL or API will fail with validation error
|
||||
- Cart displays selected package quantity (cannot be edited)
|
||||
- "View Options" button appears on shop/category pages instead of "Add to Cart"
|
||||
|
||||
**When to use quantity restrictions:**
|
||||
- Pre-packaged items (dozen eggs, 6-pack drinks, etc.)
|
||||
- Products with fixed manufacturing quantities
|
||||
- Promotional bundles where you don't want individual sales
|
||||
- Subscription boxes with specific item counts
|
||||
|
||||
## Example 6: Tier Labels for Enhanced UX (New in v1.1.7)
|
||||
|
||||
### Office Supplies with Clickable Tiers
|
||||
|
||||
**Product:** Premium Notebooks - Regular price $8.00 each
|
||||
|
||||
**Tier Configuration with Labels:**
|
||||
- Tier 1: Min Qty = 5, Price = $7.50, Label = "Small Business Discount"
|
||||
- Tier 2: Min Qty = 10, Price = $7.00, Label = "Wholesale Pricing"
|
||||
- Tier 3: Min Qty = 25, Price = $6.50, Label = "Corporate Rate"
|
||||
|
||||
**Customer experience:**
|
||||
- Tier labels appear below quantity in pricing table (italicized)
|
||||
- Clicking a tier row auto-fills the quantity field with that tier's minimum quantity
|
||||
- Smooth scroll animation highlights the quantity field
|
||||
- Add to Cart button automatically disables when quantity is 0 or invalid
|
||||
|
||||
**Benefits of tier labels:**
|
||||
- Helps customers understand pricing context
|
||||
- Makes tiers more appealing with descriptive names
|
||||
- Improves conversion by highlighting value propositions
|
||||
- Clickable rows improve user experience
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
### Tier Pricing Best Practices
|
||||
@@ -113,6 +172,11 @@ Regular mug price: $10.00
|
||||
- Minimum 5-10% per tier level
|
||||
- Higher tiers should have progressively better deals
|
||||
|
||||
4. **Use Labels** (v1.1.7+): Add descriptive labels to tiers
|
||||
- "Wholesale Price" instead of just showing the number
|
||||
- "Bulk Discount", "Volume Pricing", "Corporate Rate"
|
||||
- Makes pricing more professional and appealing
|
||||
|
||||
### Package Pricing Best Practices
|
||||
|
||||
1. **Strategic Quantities**: Match common use cases
|
||||
@@ -169,3 +233,32 @@ Regular mug price: $10.00
|
||||
- Package 2: Medium party (25 pieces) = $110
|
||||
- Package 3: Large party (50 pieces) = $200
|
||||
- Package 4: Event package (100 pieces) = $350
|
||||
|
||||
## WooCommerce Blocks Compatibility (v1.1.4+, Fixed in v1.1.20)
|
||||
|
||||
This plugin is **fully compatible** with WooCommerce block-based cart and checkout:
|
||||
|
||||
### Supported Block Types
|
||||
- Cart Block (`woocommerce/cart`)
|
||||
- Mini Cart Block (`woocommerce/mini-cart`)
|
||||
- Checkout Block (`woocommerce/checkout`)
|
||||
- All Store API endpoints
|
||||
|
||||
### Block-Specific Features
|
||||
- Quantity restrictions work in block-based carts
|
||||
- Package-restricted products hide quantity selectors in blocks
|
||||
- Tier and package pricing applies correctly in block checkout
|
||||
- Mini cart displays correct prices and restrictions
|
||||
|
||||
### Technical Notes
|
||||
- v1.1.20 fixed critical fatal error in WooCommerce Blocks
|
||||
- Uses `woocommerce_store_api_product_quantity_editable` filter
|
||||
- Works with both classic and block-based themes
|
||||
- No configuration needed - blocks work automatically
|
||||
|
||||
### Testing Your Block Setup
|
||||
1. Add block-based cart to a page (`/cart`)
|
||||
2. Add mini-cart block to your header
|
||||
3. Add block-based checkout to a page (`/checkout`)
|
||||
4. Test tier pricing, package pricing, and quantity restrictions
|
||||
5. Verify prices calculate correctly at checkout
|
||||
|
||||
@@ -23,42 +23,48 @@
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* Table styling - borderless design for all tier/package tables */
|
||||
.wc-tpp-tiers-table,
|
||||
.wc-tpp-packages-table {
|
||||
margin-top: 15px;
|
||||
margin-bottom: 15px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.wc-tpp-tiers-table th,
|
||||
.wc-tpp-packages-table th {
|
||||
font-weight: 600;
|
||||
text-align: left;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.wc-tpp-tiers-table td,
|
||||
.wc-tpp-packages-table td {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Table row styling - rows are now <tr> elements in a table */
|
||||
.wc-tpp-tier-row,
|
||||
.wc-tpp-package-row {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: flex-end;
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
/* No special styling needed - standard table row */
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row .form-field,
|
||||
.wc-tpp-package-row .form-field {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row label,
|
||||
.wc-tpp-package-row label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
.wc-tpp-tier-row td,
|
||||
.wc-tpp-package-row td {
|
||||
padding: 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
/* Ensure WooCommerce input classes work properly in table cells */
|
||||
.wc-tpp-tier-row input,
|
||||
.wc-tpp-package-row input {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.wc-tpp-remove-tier,
|
||||
.wc-tpp-remove-package {
|
||||
flex-shrink: 0;
|
||||
color: #b32d2e;
|
||||
border-color: #b32d2e;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.wc-tpp-remove-tier:hover,
|
||||
@@ -89,3 +95,22 @@
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Checkbox styling improvements */
|
||||
#_wc_tpp_restrict_to_packages,
|
||||
input[id^="wc_tpp_restrict_to_packages_"] {
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
|
||||
/* Ensure description is properly hidden when desc_tip is used */
|
||||
.wc-tpp-tier-pricing .woocommerce-help-tip,
|
||||
.wc-tpp-package-pricing .woocommerce-help-tip,
|
||||
.wc-tpp-variation-pricing .woocommerce-help-tip {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
/* Hide inline description text when tooltip is shown */
|
||||
#_wc_tpp_restrict_to_packages + .description,
|
||||
input[id^="wc_tpp_restrict_to_packages_"] + .description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -6,18 +6,72 @@
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function() {
|
||||
let tierIndex = $('.wc-tpp-tier-row').length;
|
||||
let packageIndex = $('.wc-tpp-package-row').length;
|
||||
// Initialize indexes for simple products
|
||||
let tierIndex = $('.wc-tpp-tier-pricing .wc-tpp-tier-row').length;
|
||||
let packageIndex = $('.wc-tpp-package-pricing .wc-tpp-package-row').length;
|
||||
|
||||
// Add tier
|
||||
$('.wc-tpp-add-tier').on('click', function(e) {
|
||||
// ========================================
|
||||
// Simple Product Handlers
|
||||
// ========================================
|
||||
|
||||
// Add tier (simple products)
|
||||
$('.wc-tpp-tier-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-tiers-container').append(newRow);
|
||||
$('.wc-tpp-tier-pricing .wc-tpp-tiers-container').append(newRow);
|
||||
tierIndex++;
|
||||
});
|
||||
|
||||
// Add package (simple products)
|
||||
$('.wc-tpp-package-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-package-pricing .wc-tpp-packages-container').append(newRow);
|
||||
packageIndex++;
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Variable Product Variation Handlers
|
||||
// ========================================
|
||||
|
||||
// Add tier (variations)
|
||||
$(document).on('click', '.wc-tpp-variation-pricing .wc-tpp-add-tier', function(e) {
|
||||
e.preventDefault();
|
||||
const $button = $(this);
|
||||
const loop = $button.data('loop');
|
||||
const $container = $button.closest('.wc-tpp-variation-pricing');
|
||||
const $tbody = $container.find('.wc-tpp-variation-tiers .wc-tpp-tiers-container');
|
||||
const template = $('#wc-tpp-variation-tier-row-template-' + loop).html();
|
||||
|
||||
// Count existing rows to get next index
|
||||
const currentIndex = $tbody.find('tr').length;
|
||||
const newRow = template.replace(/\{\{INDEX\}\}/g, currentIndex);
|
||||
|
||||
$tbody.append(newRow);
|
||||
});
|
||||
|
||||
// Add package (variations)
|
||||
$(document).on('click', '.wc-tpp-variation-pricing .wc-tpp-add-package', function(e) {
|
||||
e.preventDefault();
|
||||
const $button = $(this);
|
||||
const loop = $button.data('loop');
|
||||
const $container = $button.closest('.wc-tpp-variation-pricing');
|
||||
const $tbody = $container.find('.wc-tpp-variation-packages .wc-tpp-packages-container');
|
||||
const template = $('#wc-tpp-variation-package-row-template-' + loop).html();
|
||||
|
||||
// Count existing rows to get next index
|
||||
const currentIndex = $tbody.find('tr').length;
|
||||
const newRow = template.replace(/\{\{INDEX\}\}/g, currentIndex);
|
||||
|
||||
$tbody.append(newRow);
|
||||
});
|
||||
|
||||
// ========================================
|
||||
// Common Handlers (both simple and variations)
|
||||
// ========================================
|
||||
|
||||
// Remove tier
|
||||
$(document).on('click', '.wc-tpp-remove-tier', function(e) {
|
||||
e.preventDefault();
|
||||
@@ -26,15 +80,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Add package
|
||||
$('.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-packages-container').append(newRow);
|
||||
packageIndex++;
|
||||
});
|
||||
|
||||
// Remove package
|
||||
$(document).on('click', '.wc-tpp-remove-package', function(e) {
|
||||
e.preventDefault();
|
||||
@@ -43,7 +88,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Validate inputs
|
||||
// Validate quantity inputs
|
||||
$(document).on('input', 'input[name*="[min_qty]"], input[name*="[qty]"]', function() {
|
||||
const value = parseInt($(this).val());
|
||||
if (value < 1) {
|
||||
@@ -51,6 +96,7 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Validate price inputs
|
||||
$(document).on('input', 'input[name*="[price]"]', function() {
|
||||
const value = parseFloat($(this).val());
|
||||
if (value < 0) {
|
||||
|
||||
@@ -244,6 +244,114 @@
|
||||
if ($quantityInput.length > 0 && $addToCartButton.length > 0) {
|
||||
updateAddToCartButton();
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Variable Product Support
|
||||
// ========================================
|
||||
|
||||
const $variationsForm = $('.variations_form');
|
||||
const $pricingTableContainer = $('.wc-tpp-pricing-table-container');
|
||||
|
||||
if ($variationsForm.length && $pricingTableContainer.length) {
|
||||
// Handle variation selection
|
||||
$variationsForm.on('found_variation', function(event, variation) {
|
||||
if (!variation.variation_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
$pricingTableContainer.html('<div class="wc-tpp-loading">Loading pricing...</div>').show();
|
||||
|
||||
// Fetch variation pricing via AJAX
|
||||
$.ajax({
|
||||
url: wcTppData.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'wc_tpp_get_variation_pricing',
|
||||
nonce: wcTppData.nonce,
|
||||
variation_id: variation.variation_id
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.has_pricing) {
|
||||
// Display the pricing table HTML
|
||||
$pricingTableContainer.html(response.data.html).show();
|
||||
|
||||
// Re-initialize event handlers for the new content
|
||||
initializePricingHandlers();
|
||||
|
||||
// Handle quantity restrictions
|
||||
if (response.data.restrict_to_packages) {
|
||||
$('input.qty').hide().closest('.quantity').hide();
|
||||
$('<style>.quantity { display: none !important; }</style>').appendTo('head');
|
||||
} else {
|
||||
$('input.qty').show().closest('.quantity').show();
|
||||
$('style:contains(".quantity { display: none")').remove();
|
||||
}
|
||||
} else {
|
||||
// No pricing for this variation
|
||||
$pricingTableContainer.html('').hide();
|
||||
$('input.qty').show().closest('.quantity').show();
|
||||
$('style:contains(".quantity { display: none")').remove();
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
$pricingTableContainer.html('').hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Handle variation reset
|
||||
$variationsForm.on('reset_data', function() {
|
||||
$pricingTableContainer.html('').hide();
|
||||
$('input.qty').show().closest('.quantity').show();
|
||||
$('style:contains(".quantity { display: none")').remove();
|
||||
});
|
||||
|
||||
// Initialize pricing handlers for dynamically loaded content
|
||||
function initializePricingHandlers() {
|
||||
// Re-attach package selection handlers
|
||||
$('.wc-tpp-select-package').off('click').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const $package = $(this).closest('.wc-tpp-package');
|
||||
const qty = parseInt($package.data('qty'));
|
||||
const $qtyInput = $('input.qty');
|
||||
|
||||
if ($qtyInput.length === 0 || $qtyInput.is(':hidden')) {
|
||||
// Create hidden input for restricted products
|
||||
if ($('.qty-hidden-input').length === 0) {
|
||||
$('.single_add_to_cart_button').before('<input type="hidden" name="quantity" class="qty qty-hidden-input" value="1" />');
|
||||
}
|
||||
$('.qty-hidden-input').val(qty);
|
||||
} else {
|
||||
$qtyInput.val(qty).trigger('change');
|
||||
}
|
||||
|
||||
// Highlight selected package
|
||||
$('.wc-tpp-package').removeClass('wc-tpp-selected');
|
||||
$package.addClass('wc-tpp-selected');
|
||||
|
||||
// Scroll to add to cart button
|
||||
$('html, body').animate({
|
||||
scrollTop: $('.single_add_to_cart_button').offset().top - 100
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Re-attach tier row click handlers
|
||||
$('.wc-tpp-tier-pricing-table tbody tr').off('click').on('click', function() {
|
||||
const minQty = parseInt($(this).data('min-qty'));
|
||||
const $qtyInput = $('input.qty');
|
||||
|
||||
if ($qtyInput.length > 0 && $qtyInput.is(':visible')) {
|
||||
$qtyInput.val(minQty).trigger('change');
|
||||
|
||||
// Scroll to quantity input
|
||||
$('html, body').animate({
|
||||
scrollTop: $qtyInput.offset().top - 100
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "magdev/wc-tier-package-prices",
|
||||
"description": "WooCommerce plugin for tier pricing and package prices with Twig templates",
|
||||
"version": "1.1.19",
|
||||
"version": "1.2.3",
|
||||
"type": "wordpress-plugin",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"authors": [
|
||||
|
||||
@@ -40,6 +40,8 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
|
||||
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
|
||||
$product_id = $cart_item['product_id'];
|
||||
$variation_id = isset($cart_item['variation_id']) ? absint($cart_item['variation_id']) : 0;
|
||||
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
|
||||
$quantity = $cart_item['quantity'];
|
||||
$product = $cart_item['data'];
|
||||
|
||||
@@ -48,10 +50,10 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for exact package match first
|
||||
// Check for exact package match first (use effective ID for variations)
|
||||
$package_price = null;
|
||||
if (get_option('wc_tpp_enable_package_pricing') === 'yes') {
|
||||
$package_price = WC_TPP_Frontend::get_package_price($product_id, $quantity);
|
||||
$package_price = WC_TPP_Frontend::get_package_price($effective_id, $quantity, $variation_id);
|
||||
}
|
||||
|
||||
if ($package_price !== null) {
|
||||
@@ -62,9 +64,9 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_pricing_type'] = 'package';
|
||||
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_total_price'] = $package_price;
|
||||
} else {
|
||||
// Apply tier pricing if no package match
|
||||
// Apply tier pricing if no package match (use effective ID for variations)
|
||||
if (get_option('wc_tpp_enable_tier_pricing') === 'yes') {
|
||||
$tier_price = WC_TPP_Frontend::get_tier_price($product_id, $quantity);
|
||||
$tier_price = WC_TPP_Frontend::get_tier_price($effective_id, $quantity, $variation_id);
|
||||
if ($tier_price !== null) {
|
||||
$product->set_price($tier_price);
|
||||
// Store pricing information in cart item for display
|
||||
@@ -99,16 +101,20 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
}
|
||||
|
||||
public function validate_package_quantity($passed, $product_id, $quantity) {
|
||||
// Check if restriction is enabled globally or for this product
|
||||
// Check for variation ID in request (for variable products)
|
||||
$variation_id = isset($_REQUEST['variation_id']) ? absint($_REQUEST['variation_id']) : 0;
|
||||
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
|
||||
|
||||
// Check if restriction is enabled globally or for this product/variation
|
||||
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
|
||||
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
$product_restrict = get_post_meta($effective_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
|
||||
if (!$global_restrict && !$product_restrict) {
|
||||
return $passed;
|
||||
}
|
||||
|
||||
// Get packages for this product
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
// Get packages for this product/variation
|
||||
$packages = get_post_meta($effective_id, '_wc_tpp_packages', true);
|
||||
|
||||
if (empty($packages) || !is_array($packages)) {
|
||||
return $passed;
|
||||
@@ -147,18 +153,20 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
|
||||
public function maybe_hide_cart_quantity_input($product_quantity, $cart_item_key, $cart_item) {
|
||||
$product_id = $cart_item['product_id'];
|
||||
$variation_id = isset($cart_item['variation_id']) ? absint($cart_item['variation_id']) : 0;
|
||||
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
|
||||
|
||||
// Check if restriction is enabled globally or for this product
|
||||
// Check if restriction is enabled globally or for this product/variation
|
||||
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
|
||||
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
$product_restrict = get_post_meta($effective_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
|
||||
// Get packages for this product
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
// Get packages for this product/variation
|
||||
$packages = get_post_meta($effective_id, '_wc_tpp_packages', true);
|
||||
|
||||
// If restriction is enabled and packages exist, show quantity as text only
|
||||
if (($global_restrict || $product_restrict) && !empty($packages)) {
|
||||
return sprintf('<span class="wc-tpp-cart-quantity wc-tpp-restricted-qty" data-product-id="%d">%s</span>',
|
||||
$product_id,
|
||||
$effective_id,
|
||||
$cart_item['quantity']
|
||||
);
|
||||
}
|
||||
@@ -168,18 +176,20 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
|
||||
public function maybe_hide_mini_cart_quantity_input($product_quantity, $cart_item, $cart_item_key) {
|
||||
$product_id = $cart_item['product_id'];
|
||||
$variation_id = isset($cart_item['variation_id']) ? absint($cart_item['variation_id']) : 0;
|
||||
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
|
||||
|
||||
// Check if restriction is enabled globally or for this product
|
||||
// Check if restriction is enabled globally or for this product/variation
|
||||
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
|
||||
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
$product_restrict = get_post_meta($effective_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
|
||||
// Get packages for this product
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
// Get packages for this product/variation
|
||||
$packages = get_post_meta($effective_id, '_wc_tpp_packages', true);
|
||||
|
||||
// If restriction is enabled and packages exist, show quantity as text only
|
||||
if (($global_restrict || $product_restrict) && !empty($packages)) {
|
||||
return sprintf('<span class="wc-tpp-cart-quantity wc-tpp-restricted-qty" data-product-id="%d">%s ×</span>',
|
||||
$product_id,
|
||||
$effective_id,
|
||||
$cart_item['quantity']
|
||||
);
|
||||
}
|
||||
@@ -196,12 +206,15 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
$restricted_products = array();
|
||||
foreach (WC()->cart->get_cart() as $cart_item) {
|
||||
$product_id = $cart_item['product_id'];
|
||||
$variation_id = isset($cart_item['variation_id']) ? absint($cart_item['variation_id']) : 0;
|
||||
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
|
||||
|
||||
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
|
||||
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
$product_restrict = get_post_meta($effective_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
$packages = get_post_meta($effective_id, '_wc_tpp_packages', true);
|
||||
|
||||
if (($global_restrict || $product_restrict) && !empty($packages)) {
|
||||
$restricted_products[] = $product_id;
|
||||
$restricted_products[] = $effective_id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,7 +239,7 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
* Make quantity non-editable for restricted products in WooCommerce blocks
|
||||
*
|
||||
* @param bool $editable Whether the quantity is editable
|
||||
* @param WC_Product $product Product object
|
||||
* @param WC_Product $product Product object (can be variation)
|
||||
* @return bool
|
||||
*/
|
||||
public function block_quantity_editable($editable, $product) {
|
||||
@@ -241,9 +254,12 @@ if (!class_exists('WC_TPP_Cart')) {
|
||||
return $editable;
|
||||
}
|
||||
|
||||
// For variations, use the variation ID directly (get_id() returns variation ID for WC_Product_Variation)
|
||||
$effective_id = $product_id;
|
||||
|
||||
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
|
||||
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
$product_restrict = get_post_meta($effective_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
$packages = get_post_meta($effective_id, '_wc_tpp_packages', true);
|
||||
|
||||
// If restriction is enabled and packages exist, make quantity non-editable
|
||||
if (($global_restrict || $product_restrict) && !empty($packages)) {
|
||||
|
||||
@@ -19,6 +19,10 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
|
||||
// Modify catalog add to cart button for restricted products
|
||||
add_filter('woocommerce_loop_add_to_cart_link', array($this, 'modify_catalog_add_to_cart_button'), 10, 2);
|
||||
|
||||
// AJAX endpoints for variation pricing
|
||||
add_action('wp_ajax_wc_tpp_get_variation_pricing', array($this, 'ajax_get_variation_pricing'));
|
||||
add_action('wp_ajax_nopriv_wc_tpp_get_variation_pricing', array($this, 'ajax_get_variation_pricing'));
|
||||
}
|
||||
|
||||
public function enqueue_scripts() {
|
||||
@@ -31,8 +35,10 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
if (is_product()) {
|
||||
wp_enqueue_script('wc-tpp-frontend', WC_TPP_PLUGIN_URL . 'assets/js/frontend.js', array('jquery'), WC_TPP_VERSION, true);
|
||||
|
||||
// Localize script with currency settings
|
||||
// Localize script with currency settings and AJAX data
|
||||
wp_localize_script('wc-tpp-frontend', 'wcTppData', array(
|
||||
'ajax_url' => admin_url('admin-ajax.php'),
|
||||
'nonce' => wp_create_nonce('wc_tpp_variation_pricing'),
|
||||
'currency_symbol' => esc_js(get_woocommerce_currency_symbol()),
|
||||
'currency_position' => esc_js(get_option('woocommerce_currency_pos', 'left')),
|
||||
'price_decimals' => absint(wc_get_price_decimals()),
|
||||
@@ -67,6 +73,11 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For variable products, quantity hiding is handled per-variation via JS
|
||||
if ($product->is_type('variable')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product_id = $product->get_id();
|
||||
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
|
||||
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
@@ -85,6 +96,13 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For variable products, show a placeholder that will be populated by JS when variation is selected
|
||||
if ($product->is_type('variable')) {
|
||||
echo '<div class="wc-tpp-pricing-table-container" data-product-type="variable" style="display:none;"></div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// For simple products, display pricing table directly
|
||||
$product_id = $product->get_id();
|
||||
$tiers = get_post_meta($product_id, '_wc_tpp_tiers', true);
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
@@ -103,8 +121,17 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
));
|
||||
}
|
||||
|
||||
public static function get_tier_price($product_id, $quantity) {
|
||||
$tiers = get_post_meta($product_id, '_wc_tpp_tiers', true);
|
||||
/**
|
||||
* Get tier price for a product or variation
|
||||
*
|
||||
* @param int $product_id Product ID (parent for simple, parent for variable)
|
||||
* @param int $quantity Quantity
|
||||
* @param int $variation_id Variation ID (0 for simple products)
|
||||
* @return float|null Tier price or null if not applicable
|
||||
*/
|
||||
public static function get_tier_price($product_id, $quantity, $variation_id = 0) {
|
||||
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
|
||||
$tiers = get_post_meta($effective_id, '_wc_tpp_tiers', true);
|
||||
|
||||
if (empty($tiers) || !is_array($tiers)) {
|
||||
return null;
|
||||
@@ -120,8 +147,17 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
return $applicable_price;
|
||||
}
|
||||
|
||||
public static function get_package_price($product_id, $quantity) {
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
/**
|
||||
* Get package price for a product or variation
|
||||
*
|
||||
* @param int $product_id Product ID (parent for simple, parent for variable)
|
||||
* @param int $quantity Quantity
|
||||
* @param int $variation_id Variation ID (0 for simple products)
|
||||
* @return float|null Package price or null if not applicable
|
||||
*/
|
||||
public static function get_package_price($product_id, $quantity, $variation_id = 0) {
|
||||
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
|
||||
$packages = get_post_meta($effective_id, '_wc_tpp_packages', true);
|
||||
|
||||
if (empty($packages) || !is_array($packages)) {
|
||||
return null;
|
||||
@@ -164,8 +200,24 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
|
||||
$product_id = $product->get_id();
|
||||
|
||||
// Check if product has quantity restrictions
|
||||
if (!self::has_quantity_restriction($product_id)) {
|
||||
// For variable products, check if ANY variation has restrictions
|
||||
// For simple products, check the product itself
|
||||
$has_restriction = false;
|
||||
|
||||
if ($product->is_type('variable')) {
|
||||
// Check if any variation has package restrictions
|
||||
$variations = $product->get_available_variations();
|
||||
foreach ($variations as $variation_data) {
|
||||
if (self::has_quantity_restriction($variation_data['variation_id'])) {
|
||||
$has_restriction = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$has_restriction = self::has_quantity_restriction($product_id);
|
||||
}
|
||||
|
||||
if (!$has_restriction) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
@@ -173,15 +225,72 @@ if (!class_exists('WC_TPP_Frontend')) {
|
||||
$product_url = esc_url($product->get_permalink());
|
||||
$button_text = esc_html__('View Options', 'wc-tier-package-prices');
|
||||
|
||||
// Use correct product type class
|
||||
$product_type_class = $product->is_type('variable') ? 'product_type_variable' : 'product_type_simple';
|
||||
|
||||
$new_html = sprintf(
|
||||
'<a href="%s" class="button wc-tpp-view-options product_type_simple" aria-label="%s">%s</a>',
|
||||
'<a href="%s" class="button wc-tpp-view-options %s" aria-label="%s">%s</a>',
|
||||
$product_url,
|
||||
esc_attr($product_type_class),
|
||||
esc_attr(sprintf(__('View options for %s', 'wc-tier-package-prices'), $product->get_name())),
|
||||
$button_text
|
||||
);
|
||||
|
||||
return $new_html;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler to get variation pricing data
|
||||
*/
|
||||
public function ajax_get_variation_pricing() {
|
||||
// Verify nonce
|
||||
check_ajax_referer('wc_tpp_variation_pricing', 'nonce');
|
||||
|
||||
$variation_id = isset($_POST['variation_id']) ? absint($_POST['variation_id']) : 0;
|
||||
|
||||
if (!$variation_id) {
|
||||
wp_send_json_error(array('message' => __('Invalid variation ID', 'wc-tier-package-prices')));
|
||||
}
|
||||
|
||||
// Get variation data
|
||||
$variation = wc_get_product($variation_id);
|
||||
|
||||
if (!$variation || !$variation->is_type('variation')) {
|
||||
wp_send_json_error(array('message' => __('Variation not found', 'wc-tier-package-prices')));
|
||||
}
|
||||
|
||||
// Get tier and package pricing
|
||||
$tiers = get_post_meta($variation_id, '_wc_tpp_tiers', true);
|
||||
$packages = get_post_meta($variation_id, '_wc_tpp_packages', true);
|
||||
$global_restrict = get_option('wc_tpp_restrict_package_quantities', 'no') === 'yes';
|
||||
$product_restrict = get_post_meta($variation_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
|
||||
|
||||
if (empty($tiers) && empty($packages)) {
|
||||
// No pricing data for this variation
|
||||
wp_send_json_success(array(
|
||||
'has_pricing' => false,
|
||||
'html' => ''
|
||||
));
|
||||
}
|
||||
|
||||
// Render the pricing table HTML
|
||||
ob_start();
|
||||
WC_TPP_Template_Loader::get_instance()->display('frontend/pricing-table.twig', array(
|
||||
'product' => $variation,
|
||||
'tiers' => $tiers,
|
||||
'packages' => $packages,
|
||||
'restrict_to_packages' => $global_restrict || $product_restrict
|
||||
));
|
||||
$html = ob_get_clean();
|
||||
|
||||
wp_send_json_success(array(
|
||||
'has_pricing' => true,
|
||||
'html' => $html,
|
||||
'tiers' => $tiers ? $tiers : array(),
|
||||
'packages' => $packages ? $packages : array(),
|
||||
'restrict_to_packages' => $global_restrict || $product_restrict
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
new WC_TPP_Frontend();
|
||||
|
||||
@@ -11,9 +11,14 @@ if (!class_exists('WC_TPP_Product_Meta')) {
|
||||
class WC_TPP_Product_Meta {
|
||||
|
||||
public function __construct() {
|
||||
// Simple product hooks
|
||||
add_action('woocommerce_product_options_pricing', array($this, 'add_tier_pricing_fields'));
|
||||
add_action('woocommerce_product_options_pricing', array($this, 'add_package_pricing_fields'));
|
||||
add_action('woocommerce_process_product_meta', array($this, 'save_tier_package_fields'));
|
||||
|
||||
// Variable product variation hooks
|
||||
add_action('woocommerce_variation_options_pricing', array($this, 'add_variation_pricing_fields'), 10, 3);
|
||||
add_action('woocommerce_save_product_variation', array($this, 'save_variation_pricing_fields'), 10, 2);
|
||||
}
|
||||
|
||||
public function add_tier_pricing_fields() {
|
||||
@@ -25,18 +30,28 @@ if (!class_exists('WC_TPP_Product_Meta')) {
|
||||
<span class="description"><?php _e('Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities.', 'wc-tier-package-prices'); ?></span>
|
||||
</p>
|
||||
|
||||
<div class="wc-tpp-tiers-container">
|
||||
<?php
|
||||
$tiers = get_post_meta($post->ID, '_wc_tpp_tiers', true);
|
||||
if (!is_array($tiers)) {
|
||||
$tiers = array();
|
||||
}
|
||||
<table class="widefat wc-tpp-tiers-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="wc-tpp-tiers-container">
|
||||
<?php
|
||||
$tiers = get_post_meta($post->ID, '_wc_tpp_tiers', true);
|
||||
if (!is_array($tiers)) {
|
||||
$tiers = array();
|
||||
}
|
||||
|
||||
foreach ($tiers as $index => $tier) {
|
||||
$this->render_tier_row($index, $tier);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
foreach ($tiers as $index => $tier) {
|
||||
$this->render_tier_row($index, $tier);
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="form-field">
|
||||
<button type="button" class="button wc-tpp-add-tier"><?php _e('Add Tier', 'wc-tier-package-prices'); ?></button>
|
||||
@@ -54,18 +69,28 @@ if (!class_exists('WC_TPP_Product_Meta')) {
|
||||
<span class="description"><?php _e('Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100.', 'wc-tier-package-prices'); ?></span>
|
||||
</p>
|
||||
|
||||
<div class="wc-tpp-packages-container">
|
||||
<?php
|
||||
$packages = get_post_meta($post->ID, '_wc_tpp_packages', true);
|
||||
if (!is_array($packages)) {
|
||||
$packages = array();
|
||||
}
|
||||
<table class="widefat wc-tpp-packages-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="wc-tpp-packages-container">
|
||||
<?php
|
||||
$packages = get_post_meta($post->ID, '_wc_tpp_packages', true);
|
||||
if (!is_array($packages)) {
|
||||
$packages = array();
|
||||
}
|
||||
|
||||
foreach ($packages as $index => $package) {
|
||||
$this->render_package_row($index, $package);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
foreach ($packages as $index => $package) {
|
||||
$this->render_package_row($index, $package);
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p class="form-field">
|
||||
<button type="button" class="button wc-tpp-add-package"><?php _e('Add Package', 'wc-tier-package-prices'); ?></button>
|
||||
@@ -105,6 +130,136 @@ if (!class_exists('WC_TPP_Product_Meta')) {
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tier and package pricing fields to product variations
|
||||
*
|
||||
* @param int $loop Position in the loop
|
||||
* @param array $variation_data Variation data
|
||||
* @param WP_Post $variation Variation post object
|
||||
*/
|
||||
public function add_variation_pricing_fields($loop, $variation_data, $variation) {
|
||||
$variation_id = $variation->ID;
|
||||
|
||||
// Retrieve variation-specific data
|
||||
$tiers = get_post_meta($variation_id, '_wc_tpp_tiers', true);
|
||||
$packages = get_post_meta($variation_id, '_wc_tpp_packages', true);
|
||||
$restrict = get_post_meta($variation_id, '_wc_tpp_restrict_to_packages', true);
|
||||
|
||||
if (!is_array($tiers)) {
|
||||
$tiers = array();
|
||||
}
|
||||
if (!is_array($packages)) {
|
||||
$packages = array();
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="form-row form-row-full wc-tpp-variation-pricing" data-variation-loop="<?php echo esc_attr($loop); ?>">
|
||||
<h4><?php _e('Tier & Package Pricing', 'wc-tier-package-prices'); ?></h4>
|
||||
|
||||
<!-- Tier Pricing Section -->
|
||||
<div class="wc-tpp-variation-tiers">
|
||||
<p><strong><?php _e('Tier Pricing', 'wc-tier-package-prices'); ?></strong></p>
|
||||
<table class="widefat wc-tpp-tiers-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Min Quantity', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="wc-tpp-tiers-container">
|
||||
<?php foreach ($tiers as $index => $tier) : ?>
|
||||
<?php $this->render_variation_tier_row($loop, $index, $tier); ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="button" class="button wc-tpp-add-tier" data-loop="<?php echo esc_attr($loop); ?>">
|
||||
<?php _e('Add Tier', 'wc-tier-package-prices'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Package Pricing Section -->
|
||||
<div class="wc-tpp-variation-packages" style="margin-top: 15px;">
|
||||
<p><strong><?php _e('Package Pricing', 'wc-tier-package-prices'); ?></strong></p>
|
||||
<table class="widefat wc-tpp-packages-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php _e('Quantity', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Price', 'wc-tier-package-prices'); ?></th>
|
||||
<th><?php _e('Label (optional)', 'wc-tier-package-prices'); ?></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="wc-tpp-packages-container">
|
||||
<?php foreach ($packages as $index => $package) : ?>
|
||||
<?php $this->render_variation_package_row($loop, $index, $package); ?>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<button type="button" class="button wc-tpp-add-package" data-loop="<?php echo esc_attr($loop); ?>">
|
||||
<?php _e('Add Package', 'wc-tier-package-prices'); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Restriction Checkbox -->
|
||||
<div style="margin-top: 15px;">
|
||||
<?php
|
||||
woocommerce_wp_checkbox(array(
|
||||
'id' => 'wc_tpp_restrict_to_packages_' . $loop,
|
||||
'name' => 'wc_tpp_restrict_to_packages[' . $loop . ']',
|
||||
'label' => __('Restrict to Package Quantities', 'wc-tier-package-prices'),
|
||||
'description' => __('Only allow quantities defined in packages above', 'wc-tier-package-prices'),
|
||||
'desc_tip' => true,
|
||||
'value' => $restrict,
|
||||
'cbvalue' => 'yes',
|
||||
'wrapper_class' => 'form-row form-row-full'
|
||||
));
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Templates for JavaScript -->
|
||||
<script type="text/html" id="wc-tpp-variation-tier-row-template-<?php echo esc_attr($loop); ?>">
|
||||
<?php $this->render_variation_tier_row($loop, '{{INDEX}}', array('min_qty' => '', 'price' => '', 'label' => '')); ?>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="wc-tpp-variation-package-row-template-<?php echo esc_attr($loop); ?>">
|
||||
<?php $this->render_variation_package_row($loop, '{{INDEX}}', array('qty' => '', 'price' => '', 'label' => '')); ?>
|
||||
</script>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a tier row for variations
|
||||
*
|
||||
* @param int $loop Variation loop index
|
||||
* @param int $index Tier index
|
||||
* @param array $tier Tier data
|
||||
*/
|
||||
private function render_variation_tier_row($loop, $index, $tier) {
|
||||
WC_TPP_Template_Loader::get_instance()->display('admin/tier-row.twig', array(
|
||||
'index' => $index,
|
||||
'tier' => $tier,
|
||||
'field_prefix' => 'wc_tpp_tiers[' . $loop . ']'
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a package row for variations
|
||||
*
|
||||
* @param int $loop Variation loop index
|
||||
* @param int $index Package index
|
||||
* @param array $package Package data
|
||||
*/
|
||||
private function render_variation_package_row($loop, $index, $package) {
|
||||
WC_TPP_Template_Loader::get_instance()->display('admin/package-row.twig', array(
|
||||
'index' => $index,
|
||||
'package' => $package,
|
||||
'field_prefix' => 'wc_tpp_packages[' . $loop . ']'
|
||||
));
|
||||
}
|
||||
|
||||
public function save_tier_package_fields($post_id) {
|
||||
// Verify nonce for security
|
||||
if (!isset($_POST['woocommerce_meta_nonce']) || !wp_verify_nonce($_POST['woocommerce_meta_nonce'], 'woocommerce_save_data')) {
|
||||
@@ -167,6 +322,68 @@ if (!class_exists('WC_TPP_Product_Meta')) {
|
||||
$restrict_to_packages = isset($_POST['_wc_tpp_restrict_to_packages']) ? 'yes' : 'no';
|
||||
update_post_meta($post_id, '_wc_tpp_restrict_to_packages', $restrict_to_packages);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save tier and package pricing for variations
|
||||
*
|
||||
* @param int $variation_id Variation ID
|
||||
* @param int $loop Position in loop
|
||||
*/
|
||||
public function save_variation_pricing_fields($variation_id, $loop) {
|
||||
// Security check
|
||||
if (!current_user_can('edit_products')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save tier pricing for this variation
|
||||
if (isset($_POST['wc_tpp_tiers'][$loop])) {
|
||||
$tiers = array();
|
||||
foreach ($_POST['wc_tpp_tiers'][$loop] as $tier) {
|
||||
if (!empty($tier['min_qty']) && !empty($tier['price'])) {
|
||||
$tiers[] = array(
|
||||
'min_qty' => absint($tier['min_qty']),
|
||||
'price' => wc_format_decimal($tier['price']),
|
||||
'label' => sanitize_text_field($tier['label'] ?? '')
|
||||
);
|
||||
}
|
||||
}
|
||||
// Sort by minimum quantity
|
||||
usort($tiers, function($a, $b) {
|
||||
return $a['min_qty'] - $b['min_qty'];
|
||||
});
|
||||
update_post_meta($variation_id, '_wc_tpp_tiers', $tiers);
|
||||
} else {
|
||||
delete_post_meta($variation_id, '_wc_tpp_tiers');
|
||||
}
|
||||
|
||||
// Save package pricing for this variation
|
||||
if (isset($_POST['wc_tpp_packages'][$loop])) {
|
||||
$packages = array();
|
||||
foreach ($_POST['wc_tpp_packages'][$loop] as $package) {
|
||||
if (!empty($package['qty']) && !empty($package['price'])) {
|
||||
$packages[] = array(
|
||||
'qty' => absint($package['qty']),
|
||||
'price' => wc_format_decimal($package['price']),
|
||||
'label' => sanitize_text_field($package['label'] ?? '')
|
||||
);
|
||||
}
|
||||
}
|
||||
// Sort by quantity
|
||||
usort($packages, function($a, $b) {
|
||||
return $a['qty'] - $b['qty'];
|
||||
});
|
||||
update_post_meta($variation_id, '_wc_tpp_packages', $packages);
|
||||
} else {
|
||||
delete_post_meta($variation_id, '_wc_tpp_packages');
|
||||
}
|
||||
|
||||
// Save restriction setting for this variation
|
||||
if (isset($_POST['wc_tpp_restrict_to_packages'][$loop]) && $_POST['wc_tpp_restrict_to_packages'][$loop] === 'yes') {
|
||||
update_post_meta($variation_id, '_wc_tpp_restrict_to_packages', 'yes');
|
||||
} else {
|
||||
delete_post_meta($variation_id, '_wc_tpp_restrict_to_packages');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new WC_TPP_Product_Meta();
|
||||
|
||||
BIN
languages/wc-tier-package-prices-de_CH.mo
Normal file
BIN
languages/wc-tier-package-prices-de_CH.mo
Normal file
Binary file not shown.
259
languages/wc-tier-package-prices-de_CH.po
Normal file
259
languages/wc-tier-package-prices-de_CH.po
Normal file
@@ -0,0 +1,259 @@
|
||||
# German (Switzerland) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-23 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-23 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German (Switzerland)\n"
|
||||
"Language: de_CH\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise benötigt eine installierte und aktive WooCommerce-Installation."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
#: includes/class-wc-tpp-settings.php:28
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr "Staffel- & Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:40
|
||||
msgid "General"
|
||||
msgstr "Allgemein"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:58
|
||||
msgid "Tier & Package Prices Settings"
|
||||
msgstr "Staffel- & Paketpreise Einstellungen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:60
|
||||
msgid "Configure tier pricing and package pricing options for your WooCommerce products."
|
||||
msgstr "Konfigurieren Sie Staffelpreise und Paketpreise für Ihre WooCommerce-Produkte."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
#: includes/class-wc-tpp-settings.php:65
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr "Staffelpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
#: includes/class-wc-tpp-settings.php:66
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr "Staffelpreise für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:70
|
||||
msgid "Allow quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Ermöglicht mengenbasierte Preisstaffeln. Kunden erhalten reduzierte Preise beim Kauf grösserer Mengen."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
#: includes/class-wc-tpp-settings.php:74
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr "Paketpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
#: includes/class-wc-tpp-settings.php:75
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr "Festpreis-Pakete für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:79
|
||||
msgid "Allow fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Ermöglicht Festpreis-Pakete mit bestimmten Mengen. Zum Beispiel: 10 Stück für CHF 50.-, 25 Stück für CHF 100.-."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
#: includes/class-wc-tpp-settings.php:83
|
||||
msgid "Display Pricing Table"
|
||||
msgstr "Preistabelle anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
#: includes/class-wc-tpp-settings.php:84
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr "Staffel- und Paketpreis-Tabelle auf Produktseiten anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:88
|
||||
msgid "Display the pricing table to customers on product pages."
|
||||
msgstr "Zeigt die Preistabelle den Kunden auf Produktseiten an."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
#: includes/class-wc-tpp-settings.php:92
|
||||
msgid "Display Position"
|
||||
msgstr "Anzeigeposition"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:93
|
||||
msgid "Choose where to display the pricing table on product pages."
|
||||
msgstr "Wählen Sie, wo die Preistabelle auf Produktseiten angezeigt werden soll."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:101
|
||||
msgid "Before Add to Cart Button"
|
||||
msgstr "Vor \"In den Warenkorb\"-Button"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:102
|
||||
msgid "After Add to Cart Button"
|
||||
msgstr "Nach \"In den Warenkorb\"-Button"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr "Vor \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr "Nach \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
#: includes/class-wc-tpp-settings.php:103
|
||||
msgid "After Price"
|
||||
msgstr "Nach dem Preis"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:108
|
||||
#: includes/class-wc-tpp-product-meta.php:76
|
||||
msgid "Restrict to Package Quantities"
|
||||
msgstr "Auf Paketmengen beschränken"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:109
|
||||
msgid "Limit quantities to defined package sizes only"
|
||||
msgstr "Mengen nur auf definierte Paketgrössen beschränken"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:113
|
||||
msgid "When enabled, customers can only purchase products in the exact quantities defined in packages. The quantity input field will be hidden and replaced with package selection buttons."
|
||||
msgstr "Wenn aktiviert, können Kunden Produkte nur in den genau definierten Paketmengen kaufen. Das Mengeneingabefeld wird ausgeblendet und durch Paketauswahl-Buttons ersetzt."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr "Staffelpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Mengenbasierte Preisstaffeln festlegen. Kunden erhalten Rabatte beim Kauf grösserer Mengen."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr "Staffel hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr "Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Festpreis-Pakete mit bestimmten Mengen festlegen. Zum Beispiel: 10 Stück für CHF 50.-, 25 Stück für CHF 100.-."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr "Paket hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:77
|
||||
msgid "Only allow quantities defined in packages above"
|
||||
msgstr "Nur oben definierte Paketmengen zulassen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr "z.B. 10"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr "z.B. 9.90"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr "Entfernen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr "Menge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr "Festpreis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr "Bezeichnung (Optional)"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr "z.B. Starter-Paket"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr "Mengenrabatte"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr "Preis pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr "Sie sparen"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr "Paketangebote"
|
||||
|
||||
#: templates/frontend/package-pricing-display.twig:11
|
||||
msgid "Choose a package size below"
|
||||
msgstr "Wählen Sie unten eine Paketgrösse"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr "Stück"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr "pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr "Paket auswählen"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr "Paketpreis"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr "Mengenrabatt"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:124
|
||||
msgid "this product"
|
||||
msgstr "dieses Produkt"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:128
|
||||
msgid "The quantity %1$d is not available for %2$s. Please choose from the available package sizes: %3$s"
|
||||
msgstr "Die Menge %1$d ist für %2$s nicht verfügbar. Bitte wählen Sie aus den verfügbaren Paketgrössen: %3$s"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:173
|
||||
msgid "View Options"
|
||||
msgstr "Optionen ansehen"
|
||||
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:36
|
||||
#: includes/class-wc-tpp-product-meta.php:140
|
||||
msgid "Min Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:37
|
||||
#: includes/class-wc-tpp-product-meta.php:141
|
||||
#: includes/class-wc-tpp-product-meta.php:164
|
||||
msgid "Price"
|
||||
msgstr "Preis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:38
|
||||
#: includes/class-wc-tpp-product-meta.php:142
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
Binary file not shown.
@@ -240,6 +240,20 @@ msgstr "Die Menge %1$d ist für %2$s nicht verfügbar. Bitte wähle aus den verf
|
||||
msgid "View Options"
|
||||
msgstr "Optionen ansehen"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:178
|
||||
msgid "View options for %s"
|
||||
msgstr "Optionen für %s ansehen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:36
|
||||
#: includes/class-wc-tpp-product-meta.php:140
|
||||
msgid "Min Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:37
|
||||
#: includes/class-wc-tpp-product-meta.php:141
|
||||
#: includes/class-wc-tpp-product-meta.php:164
|
||||
msgid "Price"
|
||||
msgstr "Preis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:38
|
||||
#: includes/class-wc-tpp-product-meta.php:142
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
|
||||
Binary file not shown.
@@ -240,6 +240,20 @@ msgstr "Die Menge %1$d ist für %2$s nicht verfügbar. Bitte wählen Sie aus den
|
||||
msgid "View Options"
|
||||
msgstr "Optionen ansehen"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:178
|
||||
msgid "View options for %s"
|
||||
msgstr "Optionen für %s ansehen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:36
|
||||
#: includes/class-wc-tpp-product-meta.php:140
|
||||
msgid "Min Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:37
|
||||
#: includes/class-wc-tpp-product-meta.php:141
|
||||
#: includes/class-wc-tpp-product-meta.php:164
|
||||
msgid "Price"
|
||||
msgstr "Preis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:38
|
||||
#: includes/class-wc-tpp-product-meta.php:142
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
|
||||
BIN
languages/wc-tier-package-prices-de_DE_informal.mo
Normal file
BIN
languages/wc-tier-package-prices-de_DE_informal.mo
Normal file
Binary file not shown.
259
languages/wc-tier-package-prices-de_DE_informal.po
Normal file
259
languages/wc-tier-package-prices-de_DE_informal.po
Normal file
@@ -0,0 +1,259 @@
|
||||
# German (Germany, Informal) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-23 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-23 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German (Germany)\n"
|
||||
"Language: de_DE_informal\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise erfordert, dass WooCommerce installiert und aktiviert ist."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
#: includes/class-wc-tpp-settings.php:28
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr "Staffel- & Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:40
|
||||
msgid "General"
|
||||
msgstr "Allgemein"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:58
|
||||
msgid "Tier & Package Prices Settings"
|
||||
msgstr "Staffel- & Paketpreise Einstellungen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:60
|
||||
msgid "Configure tier pricing and package pricing options for your WooCommerce products."
|
||||
msgstr "Konfiguriere Staffelpreise und Paketpreise für deine WooCommerce-Produkte."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
#: includes/class-wc-tpp-settings.php:65
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr "Staffelpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
#: includes/class-wc-tpp-settings.php:66
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr "Staffelpreise für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:70
|
||||
msgid "Allow quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Ermöglicht mengenbasierte Preisstaffeln. Kunden erhalten reduzierte Preise beim Kauf größerer Mengen."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
#: includes/class-wc-tpp-settings.php:74
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr "Paketpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
#: includes/class-wc-tpp-settings.php:75
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr "Festpreis-Pakete für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:79
|
||||
msgid "Allow fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Ermöglicht Festpreis-Pakete mit bestimmten Mengen. Zum Beispiel: 10 Stück für 50€, 25 Stück für 100€."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
#: includes/class-wc-tpp-settings.php:83
|
||||
msgid "Display Pricing Table"
|
||||
msgstr "Preistabelle anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
#: includes/class-wc-tpp-settings.php:84
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr "Staffel- und Paketpreis-Tabelle auf Produktseiten anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:88
|
||||
msgid "Display the pricing table to customers on product pages."
|
||||
msgstr "Zeigt die Preistabelle den Kunden auf Produktseiten an."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
#: includes/class-wc-tpp-settings.php:92
|
||||
msgid "Display Position"
|
||||
msgstr "Anzeigeposition"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:93
|
||||
msgid "Choose where to display the pricing table on product pages."
|
||||
msgstr "Wähle, wo die Preistabelle auf Produktseiten angezeigt werden soll."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:101
|
||||
msgid "Before Add to Cart Button"
|
||||
msgstr "Vor \"In den Warenkorb\"-Button"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:102
|
||||
msgid "After Add to Cart Button"
|
||||
msgstr "Nach \"In den Warenkorb\"-Button"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr "Vor \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr "Nach \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
#: includes/class-wc-tpp-settings.php:103
|
||||
msgid "After Price"
|
||||
msgstr "Nach dem Preis"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:108
|
||||
#: includes/class-wc-tpp-product-meta.php:76
|
||||
msgid "Restrict to Package Quantities"
|
||||
msgstr "Auf Paketmengen beschränken"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:109
|
||||
msgid "Limit quantities to defined package sizes only"
|
||||
msgstr "Mengen nur auf definierte Paketgrößen beschränken"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:113
|
||||
msgid "When enabled, customers can only purchase products in the exact quantities defined in packages. The quantity input field will be hidden and replaced with package selection buttons."
|
||||
msgstr "Wenn aktiviert, kannst du Produkte nur in den genau definierten Paketmengen kaufen. Das Mengeneingabefeld wird ausgeblendet und durch Paketauswahl-Buttons ersetzt."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr "Staffelpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Mengenbasierte Preisstaffeln festlegen. Kunden erhalten Rabatte beim Kauf größerer Mengen."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr "Staffel hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr "Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Festpreis-Pakete mit bestimmten Mengen festlegen. Zum Beispiel: 10 Stück für 50€, 25 Stück für 100€."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr "Paket hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:77
|
||||
msgid "Only allow quantities defined in packages above"
|
||||
msgstr "Nur oben definierte Paketmengen zulassen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr "z.B. 10"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr "z.B. 9,99"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr "Entfernen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr "Menge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr "Festpreis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr "Bezeichnung (Optional)"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr "z.B. Starter-Paket"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr "Mengenrabatte"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr "Preis pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr "Du sparst"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr "Paketangebote"
|
||||
|
||||
#: templates/frontend/package-pricing-display.twig:11
|
||||
msgid "Choose a package size below"
|
||||
msgstr "Wähle unten eine Paketgröße"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr "Stück"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr "pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr "Paket auswählen"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr "Paketpreis"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr "Mengenrabatt"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:124
|
||||
msgid "this product"
|
||||
msgstr "dieses Produkt"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:128
|
||||
msgid "The quantity %1$d is not available for %2$s. Please choose from the available package sizes: %3$s"
|
||||
msgstr "Die Menge %1$d ist für %2$s nicht verfügbar. Bitte wähle aus den verfügbaren Paketgrößen: %3$s"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:173
|
||||
msgid "View Options"
|
||||
msgstr "Optionen ansehen"
|
||||
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:36
|
||||
#: includes/class-wc-tpp-product-meta.php:140
|
||||
msgid "Min Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:37
|
||||
#: includes/class-wc-tpp-product-meta.php:141
|
||||
#: includes/class-wc-tpp-product-meta.php:164
|
||||
msgid "Price"
|
||||
msgstr "Preis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:38
|
||||
#: includes/class-wc-tpp-product-meta.php:142
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Beschriftung (optional)"
|
||||
Binary file not shown.
@@ -240,6 +240,20 @@ msgstr "The quantity %1$d is not available for %2$s. Please choose from the avai
|
||||
msgid "View Options"
|
||||
msgstr "View Options"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:178
|
||||
msgid "View options for %s"
|
||||
msgstr "View options for %s"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:36
|
||||
#: includes/class-wc-tpp-product-meta.php:140
|
||||
msgid "Min Quantity"
|
||||
msgstr "Min Quantity"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:37
|
||||
#: includes/class-wc-tpp-product-meta.php:141
|
||||
#: includes/class-wc-tpp-product-meta.php:164
|
||||
msgid "Price"
|
||||
msgstr "Price"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:38
|
||||
#: includes/class-wc-tpp-product-meta.php:142
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Label (optional)"
|
||||
|
||||
BIN
languages/wc-tier-package-prices-fr_CH.mo
Normal file
BIN
languages/wc-tier-package-prices-fr_CH.mo
Normal file
Binary file not shown.
259
languages/wc-tier-package-prices-fr_CH.po
Normal file
259
languages/wc-tier-package-prices-fr_CH.po
Normal file
@@ -0,0 +1,259 @@
|
||||
# French (Switzerland) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-23 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-23 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: French (Switzerland)\n"
|
||||
"Language: fr_CH\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr "WooCommerce Prix Échelonnés et Forfaitaires nécessite que WooCommerce soit installé et actif."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
#: includes/class-wc-tpp-settings.php:28
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr "Prix Échelonnés & Forfaitaires"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:40
|
||||
msgid "General"
|
||||
msgstr "Général"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:58
|
||||
msgid "Tier & Package Prices Settings"
|
||||
msgstr "Paramètres Prix Échelonnés & Forfaitaires"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:60
|
||||
msgid "Configure tier pricing and package pricing options for your WooCommerce products."
|
||||
msgstr "Configurez les options de prix échelonnés et forfaitaires pour vos produits WooCommerce."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
#: includes/class-wc-tpp-settings.php:65
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr "Activer les prix échelonnés"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
#: includes/class-wc-tpp-settings.php:66
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr "Activer les prix échelonnés pour les produits"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:70
|
||||
msgid "Allow quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Permet des paliers de prix basés sur la quantité. Les clients bénéficient de prix réduits lors de l'achat de quantités plus importantes."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
#: includes/class-wc-tpp-settings.php:74
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr "Activer les prix forfaitaires"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
#: includes/class-wc-tpp-settings.php:75
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr "Activer les forfaits à prix fixe pour les produits"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:79
|
||||
msgid "Allow fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Permet des forfaits à prix fixe avec des quantités spécifiques. Par exemple: 10 pièces pour CHF 50.-, 25 pièces pour CHF 100.-."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
#: includes/class-wc-tpp-settings.php:83
|
||||
msgid "Display Pricing Table"
|
||||
msgstr "Afficher le tableau des prix"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
#: includes/class-wc-tpp-settings.php:84
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr "Afficher le tableau des prix échelonnés et forfaitaires sur les pages produits"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:88
|
||||
msgid "Display the pricing table to customers on product pages."
|
||||
msgstr "Affiche le tableau des prix aux clients sur les pages produits."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
#: includes/class-wc-tpp-settings.php:92
|
||||
msgid "Display Position"
|
||||
msgstr "Position d'affichage"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:93
|
||||
msgid "Choose where to display the pricing table on product pages."
|
||||
msgstr "Choisissez où afficher le tableau des prix sur les pages produits."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:101
|
||||
msgid "Before Add to Cart Button"
|
||||
msgstr "Avant le bouton \"Ajouter au panier\""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:102
|
||||
msgid "After Add to Cart Button"
|
||||
msgstr "Après le bouton \"Ajouter au panier\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr "Avant \"Ajouter au panier\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr "Après \"Ajouter au panier\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
#: includes/class-wc-tpp-settings.php:103
|
||||
msgid "After Price"
|
||||
msgstr "Après le prix"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:108
|
||||
#: includes/class-wc-tpp-product-meta.php:76
|
||||
msgid "Restrict to Package Quantities"
|
||||
msgstr "Restreindre aux quantités forfaitaires"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:109
|
||||
msgid "Limit quantities to defined package sizes only"
|
||||
msgstr "Limiter les quantités aux tailles de forfaits définies uniquement"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:113
|
||||
msgid "When enabled, customers can only purchase products in the exact quantities defined in packages. The quantity input field will be hidden and replaced with package selection buttons."
|
||||
msgstr "Lorsque cette option est activée, les clients ne peuvent acheter les produits que dans les quantités exactes définies dans les forfaits. Le champ de saisie de quantité sera masqué et remplacé par des boutons de sélection de forfait."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr "Prix échelonnés"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Définir des paliers de prix basés sur la quantité. Les clients bénéficient de réductions lors de l'achat de quantités plus importantes."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr "Ajouter un palier"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr "Prix forfaitaires"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Définir des forfaits à prix fixe avec des quantités spécifiques. Par exemple: 10 pièces pour CHF 50.-, 25 pièces pour CHF 100.-."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr "Ajouter un forfait"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:77
|
||||
msgid "Only allow quantities defined in packages above"
|
||||
msgstr "Autoriser uniquement les quantités définies dans les forfaits ci-dessus"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr "Quantité minimale"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr "p.ex. 10"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr "p.ex. 9.90"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr "Supprimer"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr "Quantité"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr "Prix fixe"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr "Étiquette (Optionnel)"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr "p.ex. Pack de démarrage"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr "Remises sur quantité"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr "Prix par unité"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr "Vous économisez"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr "Offres forfaitaires"
|
||||
|
||||
#: templates/frontend/package-pricing-display.twig:11
|
||||
msgid "Choose a package size below"
|
||||
msgstr "Choisissez une taille de forfait ci-dessous"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr "pièces"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr "par unité"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr "Sélectionner le forfait"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr "Prix forfaitaire"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr "Remise sur quantité"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:124
|
||||
msgid "this product"
|
||||
msgstr "ce produit"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:128
|
||||
msgid "The quantity %1$d is not available for %2$s. Please choose from the available package sizes: %3$s"
|
||||
msgstr "La quantité %1$d n'est pas disponible pour %2$s. Veuillez choisir parmi les tailles de forfait disponibles: %3$s"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:173
|
||||
msgid "View Options"
|
||||
msgstr "Voir les options"
|
||||
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:36
|
||||
#: includes/class-wc-tpp-product-meta.php:140
|
||||
msgid "Min Quantity"
|
||||
msgstr "Quantité minimale"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:37
|
||||
#: includes/class-wc-tpp-product-meta.php:141
|
||||
#: includes/class-wc-tpp-product-meta.php:164
|
||||
msgid "Price"
|
||||
msgstr "Prix"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:38
|
||||
#: includes/class-wc-tpp-product-meta.php:142
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Étiquette (optionnel)"
|
||||
BIN
languages/wc-tier-package-prices-it_CH.mo
Normal file
BIN
languages/wc-tier-package-prices-it_CH.mo
Normal file
Binary file not shown.
259
languages/wc-tier-package-prices-it_CH.po
Normal file
259
languages/wc-tier-package-prices-it_CH.po
Normal file
@@ -0,0 +1,259 @@
|
||||
# Italian (Switzerland) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.21\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-23 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-23 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: Italian (Switzerland)\n"
|
||||
"Language: it_CH\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr "WooCommerce Prezzi Scaglionati e Pacchetti richiede che WooCommerce sia installato e attivo."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
#: includes/class-wc-tpp-settings.php:28
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr "Prezzi Scaglionati & Pacchetti"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:40
|
||||
msgid "General"
|
||||
msgstr "Generale"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:58
|
||||
msgid "Tier & Package Prices Settings"
|
||||
msgstr "Impostazioni Prezzi Scaglionati & Pacchetti"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:60
|
||||
msgid "Configure tier pricing and package pricing options for your WooCommerce products."
|
||||
msgstr "Configura le opzioni di prezzi scaglionati e pacchetti per i tuoi prodotti WooCommerce."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
#: includes/class-wc-tpp-settings.php:65
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr "Attiva prezzi scaglionati"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
#: includes/class-wc-tpp-settings.php:66
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr "Attiva prezzi scaglionati per i prodotti"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:70
|
||||
msgid "Allow quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Permette scaglioni di prezzo basati sulla quantità. I clienti ottengono prezzi scontati quando acquistano quantità maggiori."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
#: includes/class-wc-tpp-settings.php:74
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr "Attiva prezzi pacchetto"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
#: includes/class-wc-tpp-settings.php:75
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr "Attiva pacchetti a prezzo fisso per i prodotti"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:79
|
||||
msgid "Allow fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Permette pacchetti a prezzo fisso con quantità specifiche. Ad esempio: 10 pezzi per CHF 50.-, 25 pezzi per CHF 100.-."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
#: includes/class-wc-tpp-settings.php:83
|
||||
msgid "Display Pricing Table"
|
||||
msgstr "Visualizza tabella prezzi"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
#: includes/class-wc-tpp-settings.php:84
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr "Mostra la tabella dei prezzi scaglionati e pacchetti nelle pagine prodotto"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:88
|
||||
msgid "Display the pricing table to customers on product pages."
|
||||
msgstr "Visualizza la tabella prezzi ai clienti nelle pagine prodotto."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
#: includes/class-wc-tpp-settings.php:92
|
||||
msgid "Display Position"
|
||||
msgstr "Posizione visualizzazione"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:93
|
||||
msgid "Choose where to display the pricing table on product pages."
|
||||
msgstr "Scegli dove visualizzare la tabella prezzi nelle pagine prodotto."
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:101
|
||||
msgid "Before Add to Cart Button"
|
||||
msgstr "Prima del pulsante \"Aggiungi al carrello\""
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:102
|
||||
msgid "After Add to Cart Button"
|
||||
msgstr "Dopo il pulsante \"Aggiungi al carrello\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr "Prima di \"Aggiungi al carrello\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr "Dopo \"Aggiungi al carrello\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
#: includes/class-wc-tpp-settings.php:103
|
||||
msgid "After Price"
|
||||
msgstr "Dopo il prezzo"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:108
|
||||
#: includes/class-wc-tpp-product-meta.php:76
|
||||
msgid "Restrict to Package Quantities"
|
||||
msgstr "Limita alle quantità pacchetto"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:109
|
||||
msgid "Limit quantities to defined package sizes only"
|
||||
msgstr "Limita le quantità solo alle dimensioni pacchetto definite"
|
||||
|
||||
#: includes/class-wc-tpp-settings.php:113
|
||||
msgid "When enabled, customers can only purchase products in the exact quantities defined in packages. The quantity input field will be hidden and replaced with package selection buttons."
|
||||
msgstr "Quando attivato, i clienti possono acquistare prodotti solo nelle quantità esatte definite nei pacchetti. Il campo di inserimento quantità verrà nascosto e sostituito con pulsanti di selezione pacchetto."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr "Prezzi scaglionati"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Imposta scaglioni di prezzo basati sulla quantità. I clienti ottengono sconti quando acquistano quantità maggiori."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr "Aggiungi scaglione"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr "Prezzi pacchetto"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Imposta pacchetti a prezzo fisso con quantità specifiche. Ad esempio: 10 pezzi per CHF 50.-, 25 pezzi per CHF 100.-."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr "Aggiungi pacchetto"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:77
|
||||
msgid "Only allow quantities defined in packages above"
|
||||
msgstr "Consenti solo le quantità definite nei pacchetti sopra"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr "Quantità minima"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr "es. 10"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr "es. 9.90"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr "Rimuovi"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr "Quantità"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr "Prezzo fisso"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr "Etichetta (Opzionale)"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr "es. Pacchetto starter"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr "Sconti quantità"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr "Prezzo per unità"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr "Risparmi"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr "Offerte pacchetto"
|
||||
|
||||
#: templates/frontend/package-pricing-display.twig:11
|
||||
msgid "Choose a package size below"
|
||||
msgstr "Scegli una dimensione pacchetto qui sotto"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr "pezzi"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr "per unità"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr "Seleziona pacchetto"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr "Prezzo pacchetto"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr "Sconto quantità"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:124
|
||||
msgid "this product"
|
||||
msgstr "questo prodotto"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:128
|
||||
msgid "The quantity %1$d is not available for %2$s. Please choose from the available package sizes: %3$s"
|
||||
msgstr "La quantità %1$d non è disponibile per %2$s. Si prega di scegliere tra le dimensioni pacchetto disponibili: %3$s"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:173
|
||||
msgid "View Options"
|
||||
msgstr "Visualizza opzioni"
|
||||
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:36
|
||||
#: includes/class-wc-tpp-product-meta.php:140
|
||||
msgid "Min Quantity"
|
||||
msgstr "Quantità minima"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:37
|
||||
#: includes/class-wc-tpp-product-meta.php:141
|
||||
#: includes/class-wc-tpp-product-meta.php:164
|
||||
msgid "Price"
|
||||
msgstr "Prezzo"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:38
|
||||
#: includes/class-wc-tpp-product-meta.php:142
|
||||
#: includes/class-wc-tpp-product-meta.php:165
|
||||
msgid "Label (optional)"
|
||||
msgstr "Etichetta (facoltativo)"
|
||||
@@ -4,20 +4,28 @@ This directory contains production-ready releases of the WooCommerce Tier and Pa
|
||||
|
||||
## Latest Release
|
||||
|
||||
**Version 1.0.1** - December 21, 2025
|
||||
**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.0.1.zip
|
||||
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.0.1.zip
|
||||
# Should match: 92c1385d92527e77646e37f23c1bd1555a4290a5ec9314c0ee6ed896ded55e88
|
||||
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.0.1.zip --activate
|
||||
wp plugin install wc-tier-and-package-prices-1.1.20.zip --activate
|
||||
```
|
||||
|
||||
## Files in This Directory
|
||||
@@ -26,10 +34,10 @@ wp plugin install wc-tier-and-package-prices-1.0.1.zip --activate
|
||||
|
||||
| File | Description | Size |
|
||||
|------|-------------|------|
|
||||
| `wc-tier-and-package-prices-1.0.1.zip` | Production plugin package | 395 KB |
|
||||
| `wc-tier-and-package-prices-1.0.1.zip.sha256` | SHA-256 checksum | - |
|
||||
| `wc-tier-and-package-prices-1.0.1.zip.md5` | MD5 checksum | - |
|
||||
| `RELEASE-INFO-1.0.1.md` | Detailed release information | - |
|
||||
| `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
|
||||
|
||||
@@ -37,31 +45,23 @@ wp plugin install wc-tier-and-package-prices-1.0.1.zip --activate
|
||||
|
||||
**Using SHA-256:**
|
||||
```bash
|
||||
sha256sum -c wc-tier-and-package-prices-1.0.1.zip.sha256
|
||||
sha256sum -c wc-tier-and-package-prices-1.1.20.zip.sha256
|
||||
```
|
||||
|
||||
**Using MD5:**
|
||||
```bash
|
||||
md5sum -c wc-tier-and-package-prices-1.0.1.zip.md5
|
||||
md5sum -c wc-tier-and-package-prices-1.1.20.zip.md5
|
||||
```
|
||||
|
||||
### Expected Checksums
|
||||
|
||||
**SHA-256:**
|
||||
```
|
||||
92c1385d92527e77646e37f23c1bd1555a4290a5ec9314c0ee6ed896ded55e88
|
||||
```
|
||||
|
||||
**MD5:**
|
||||
```
|
||||
e6cfc9b88df9e7763be0cd56517ce8ab
|
||||
```
|
||||
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.0.1.zip`
|
||||
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
|
||||
@@ -71,14 +71,14 @@ e6cfc9b88df9e7763be0cd56517ce8ab
|
||||
### Method 2: WP-CLI (For developers)
|
||||
|
||||
```bash
|
||||
wp plugin install /path/to/wc-tier-and-package-prices-1.0.1.zip --activate
|
||||
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.0.1.zip -d /path/to/wordpress/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
|
||||
@@ -90,11 +90,15 @@ wp plugin activate wc-tier-and-package-prices
|
||||
## What's Included
|
||||
|
||||
### Core Features
|
||||
- ✅ Tier pricing (quantity-based discounts)
|
||||
- ✅ Package pricing (fixed-price bundles)
|
||||
- ✅ Twig template engine
|
||||
- ✅ WooCommerce HPOS compatible
|
||||
- ✅ Multilingual support
|
||||
- ✅ 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)
|
||||
@@ -105,7 +109,10 @@ wp plugin activate wc-tier-and-package-prices
|
||||
- ✅ Optimized autoloader
|
||||
- ✅ No development dependencies
|
||||
- ✅ Compiled Twig templates support
|
||||
- ✅ Tested with WooCommerce 8.0 - 10.0
|
||||
- ✅ 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
|
||||
|
||||
@@ -113,24 +120,40 @@ wp plugin activate wc-tier-and-package-prices
|
||||
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.*
|
||||
│ ├── wc-tier-package-prices-de_DE.*
|
||||
│ ├── wc-tier-package-prices-en_US.*
|
||||
│ ├── 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
|
||||
@@ -138,21 +161,41 @@ wc-tier-and-package-prices/
|
||||
|
||||
## System Requirements
|
||||
|
||||
| Requirement | Minimum Version |
|
||||
|-------------|----------------|
|
||||
| WordPress | 6.0+ |
|
||||
| PHP | 7.4+ |
|
||||
| WooCommerce | 8.0+ |
|
||||
| MySQL | 5.6+ |
|
||||
| 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 main README.md
|
||||
- **Issues:** https://src.bundespruefstelle.ch/wc-tier-package-prices/issues
|
||||
- **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
|
||||
@@ -165,6 +208,8 @@ wc-tier-and-package-prices/
|
||||
- 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
|
||||
|
||||
BIN
releases/wc-tier-and-package-prices-1.1.21.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.21.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.21.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.21.zip.md5
Normal file
@@ -0,0 +1 @@
|
||||
16813b3ed0d1001d5f60194d61d36fc2 wc-tier-and-package-prices-1.1.21.zip
|
||||
1
releases/wc-tier-and-package-prices-1.1.21.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.21.zip.sha256
Normal file
@@ -0,0 +1 @@
|
||||
e0063852a9ac23b1fd994471a2829f9dcbe26316f00ddee2d00f77c7c6a47c8f wc-tier-and-package-prices-1.1.21.zip
|
||||
BIN
releases/wc-tier-and-package-prices-1.1.22.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.22.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.22.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.22.zip.md5
Normal file
@@ -0,0 +1 @@
|
||||
7d5a5c7980a91dff5167c90a6f3290b0 wc-tier-and-package-prices-1.1.22.zip
|
||||
1
releases/wc-tier-and-package-prices-1.1.22.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.22.zip.sha256
Normal file
@@ -0,0 +1 @@
|
||||
f94dee838a3f288b4acb3b3d9a4e88ef987f9b1bc918403186014d8d43fee6d9 wc-tier-and-package-prices-1.1.22.zip
|
||||
BIN
releases/wc-tier-and-package-prices-1.2.0.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.2.0.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.2.0.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.2.0.zip.md5
Normal file
@@ -0,0 +1 @@
|
||||
cee7ab535938b4096f225f0e0640c9b7 wc-tier-and-package-prices-1.2.0.zip
|
||||
1
releases/wc-tier-and-package-prices-1.2.0.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.2.0.zip.sha256
Normal file
@@ -0,0 +1 @@
|
||||
b9cda03ef4ae8994e34fc1a6d8768e9c0a088461d795c5e79cb51f670c93d0b0 wc-tier-and-package-prices-1.2.0.zip
|
||||
@@ -4,33 +4,34 @@
|
||||
# @package WC_Tier_Package_Prices
|
||||
# @var int index
|
||||
# @var array package
|
||||
# @var string field_prefix (optional) - Prefix for field names (for variations)
|
||||
#}
|
||||
<div class="wc-tpp-package-row">
|
||||
<p class="form-field">
|
||||
<label>{{ 'Quantity'|__('wc-tier-package-prices') }}</label>
|
||||
{% set name_prefix = field_prefix is defined ? field_prefix : '_wc_tpp_packages' %}
|
||||
<tr class="wc-tpp-package-row">
|
||||
<td>
|
||||
<input type="number"
|
||||
name="_wc_tpp_packages[{{ index|esc_attr }}][qty]"
|
||||
name="{{ name_prefix }}[{{ index|esc_attr }}][qty]"
|
||||
value="{{ package.qty|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 10'|__('wc-tier-package-prices') }}"
|
||||
min="1"
|
||||
step="1"
|
||||
class="short">
|
||||
</p>
|
||||
<p class="form-field">
|
||||
<label>{{ 'Fixed Price'|__('wc-tier-package-prices') }}</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text"
|
||||
name="_wc_tpp_packages[{{ index|esc_attr }}][price]"
|
||||
name="{{ name_prefix }}[{{ index|esc_attr }}][price]"
|
||||
value="{{ package.price|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 99.99'|__('wc-tier-package-prices') }}"
|
||||
class="short wc_input_price">
|
||||
</p>
|
||||
<p class="form-field">
|
||||
<label>{{ 'Label (Optional)'|__('wc-tier-package-prices') }}</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text"
|
||||
name="_wc_tpp_packages[{{ index|esc_attr }}][label]"
|
||||
name="{{ name_prefix }}[{{ index|esc_attr }}][label]"
|
||||
value="{{ package.label|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., Starter Pack'|__('wc-tier-package-prices') }}"
|
||||
class="short">
|
||||
</p>
|
||||
<button type="button" class="button wc-tpp-remove-package">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
||||
</div>
|
||||
class="regular">
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="button wc-tpp-remove-package">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -4,33 +4,34 @@
|
||||
# @package WC_Tier_Package_Prices
|
||||
# @var int index
|
||||
# @var array tier
|
||||
# @var string field_prefix (optional) - Prefix for field names (for variations)
|
||||
#}
|
||||
<div class="wc-tpp-tier-row">
|
||||
<p class="form-field">
|
||||
<label>{{ 'Minimum Quantity'|__('wc-tier-package-prices') }}</label>
|
||||
{% set name_prefix = field_prefix is defined ? field_prefix : '_wc_tpp_tiers' %}
|
||||
<tr class="wc-tpp-tier-row">
|
||||
<td>
|
||||
<input type="number"
|
||||
name="_wc_tpp_tiers[{{ index|esc_attr }}][min_qty]"
|
||||
name="{{ name_prefix }}[{{ index|esc_attr }}][min_qty]"
|
||||
value="{{ tier.min_qty|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 10'|__('wc-tier-package-prices') }}"
|
||||
min="1"
|
||||
step="1"
|
||||
class="short">
|
||||
</p>
|
||||
<p class="form-field">
|
||||
<label>{{ 'Price per Unit'|__('wc-tier-package-prices') }}</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text"
|
||||
name="_wc_tpp_tiers[{{ index|esc_attr }}][price]"
|
||||
name="{{ name_prefix }}[{{ index|esc_attr }}][price]"
|
||||
value="{{ tier.price|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 9.99'|__('wc-tier-package-prices') }}"
|
||||
class="short wc_input_price">
|
||||
</p>
|
||||
<p class="form-field">
|
||||
<label>{{ 'Label (Optional)'|__('wc-tier-package-prices') }}</label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text"
|
||||
name="_wc_tpp_tiers[{{ index|esc_attr }}][label]"
|
||||
name="{{ name_prefix }}[{{ index|esc_attr }}][label]"
|
||||
value="{{ tier.label|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., Wholesale'|__('wc-tier-package-prices') }}"
|
||||
class="short">
|
||||
</p>
|
||||
<button type="button" class="button wc-tpp-remove-tier">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
||||
</div>
|
||||
class="regular">
|
||||
</td>
|
||||
<td>
|
||||
<button type="button" class="button wc-tpp-remove-tier">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -5,13 +5,14 @@
|
||||
# @var object product
|
||||
# @var array tiers
|
||||
# @var array packages
|
||||
# @var bool restrict_to_packages
|
||||
#}
|
||||
<div class="wc-tpp-pricing-container">
|
||||
{% if tiers is not empty and get_option('wc_tpp_enable_tier_pricing') == 'yes' %}
|
||||
{% if tiers is not empty %}
|
||||
{% include 'frontend/tier-pricing-table.twig' with {'product': product, 'tiers': tiers} %}
|
||||
{% endif %}
|
||||
|
||||
{% if packages is not empty and get_option('wc_tpp_enable_package_pricing') == 'yes' %}
|
||||
{% if packages is not empty %}
|
||||
{% include 'frontend/package-pricing-display.twig' with {'packages': packages, 'restrict_to_packages': restrict_to_packages|default(false)} %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* Plugin Name: WooCommerce Tier and Package Prices
|
||||
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-tier-package-prices
|
||||
* Description: Add tier pricing and package prices to WooCommerce products with configurable quantities at fixed prices
|
||||
* Version: 1.1.20
|
||||
* Version: 1.2.3
|
||||
* Author: Marco Graetsch
|
||||
* Author URI: https://src.bundespruefstelle.ch/magdev
|
||||
* Text Domain: wc-tier-package-prices
|
||||
@@ -23,7 +23,7 @@ if (!defined('ABSPATH')) {
|
||||
|
||||
// Define plugin constants
|
||||
if (!defined('WC_TPP_VERSION')) {
|
||||
define('WC_TPP_VERSION', '1.1.20');
|
||||
define('WC_TPP_VERSION', '1.2.3');
|
||||
}
|
||||
if (!defined('WC_TPP_PLUGIN_DIR')) {
|
||||
define('WC_TPP_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||
|
||||
Reference in New Issue
Block a user