44 Commits

Author SHA1 Message Date
e4ecc2c0be Release version 1.2.5 - Parent product default pricing and UI enhancements
Added:
- Parent product default pricing for variable products - set tier/package pricing once on parent, variations inherit unless overridden
- Hide empty table headers in admin until pricing rules are defined

Technical:
- Added parent fallback logic to get_tier_price() and get_package_price() methods
- Created helper methods get_packages_with_fallback() and is_restriction_enabled() in cart class
- Updated all cart methods to support parent product defaults
- Added CSS :has() selectors to hide table headers when tbody is empty
- Fixed cart pricing calls to pass correct product ID for fallback resolution

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 00:23:56 +01:00
e2e40538df removed /finish-session in favor of the global /end-session 2025-12-30 00:16:09 +01:00
67e11d3030 permitted more commands 2025-12-30 00:15:42 +01:00
2de6a92784 Update CLAUDE.md with v1.2.4 learnings and CSS troubleshooting guide
Added comprehensive CSS specificity documentation from v1.2.4 bugfixes:
- CSS Specificity Issues section documenting table border and help-tip positioning problems
- Detailed troubleshooting guide for WooCommerce CSS overrides
- Solution patterns for table styling and float-based layouts
- General rules and diagnostic steps for CSS issues

Updated:
- Last Updated date to 2025-12-30
- Roadmap section to mark v1.2.4 bugs as completed
- Moved future enhancements to v1.2.5+ section

Key learnings documented:
- WooCommerce core CSS requires !important flags for overrides
- Float-based layouts should be replaced with flexbox for precise control
- Table borders require comprehensive targeting of all structural elements
- border-collapse: collapse is essential for borderless tables

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 00:14:16 +01:00
47f2ed771b Add release package for version 1.2.4
Release package includes:
- Fixed admin table borders with !important flags
- Fixed checkbox and help icon layout with flexbox
- Package size: 432KB (383 files)
- Checksums: MD5 and SHA256 generated

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 00:04:19 +01:00
880983a879 Merge branch 'dev' 2025-12-30 00:02:38 +01:00
937e80fce3 Release version 1.2.4 - Fix admin table borders and checkbox layout
Fixed:
- Admin table borders still visible despite v1.2.3 fix - added !important flags
- Help icon positioning at right edge instead of next to label - changed to flexbox layout
- Increased checkbox margin from 8px to 12px for better spacing

Technical:
- Added border-collapse: collapse !important to force borderless tables
- Changed label layout from float to inline-flex for proper help-tip positioning
- Added comprehensive border removal with !important on all table elements

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-30 00:02:34 +01:00
9c5e3c85ae Add release packages for v1.2.1, v1.2.2, and v1.2.3
Release packages with checksums:
- v1.2.1: Admin UI fixes and frontend display improvements
- v1.2.2: Variation UI styling, translations, checkbox rendering
- v1.2.3: Borderless tables and checkbox tooltip improvements

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 21:09:45 +01:00
3d47ee63d8 Update CLAUDE.md with v1.2.2 and v1.2.3 release learnings
Added detailed documentation for release package creation process:
- Critical exclusion patterns (especially wordpress symlink)
- Expected package size and verification steps
- Complete zip command with all necessary exclusions

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 21:09:31 +01:00
04eba21521 Release version 1.2.3 - Admin UI styling improvements
Fixed two admin UI bugs:
- Applied borderless table styling to all tier/package tables for consistency
- Fixed checkbox tooltip display and improved checkbox-label spacing

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 21:06:25 +01:00
ef314e36bc Release version 1.2.2 - Admin UI bugfixes for variations
Fixed three bugs in variation pricing interface:
- Removed table borders for variation pricing to match WooCommerce UI style
- Added missing translations (Min Quantity, Price, Label) to all language files
- Fixed restrict_to_packages checkbox rendering in variation fields

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 20:53:23 +01:00
415f39e826 Update .gitignore for local development files
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 20:28:45 +01:00
6733ca5f98 Release version 1.2.1 - Critical bugfixes for v1.2.0
Fixed two critical bugs introduced in v1.2.0:

1. Admin UI table structure mismatch - CSS still had flexbox styling from
   old template structure, breaking new table layout. Updated admin.css to
   properly style table rows with standard table cell padding.

2. Frontend pricing display not showing - Template was checking global
   enable settings before display. Removed those checks so pricing shows
   if configured on product AND display setting is enabled.

Files changed:
- wc-tier-and-package-prices.php - Version bump to 1.2.1
- composer.json - Version bump to 1.2.1
- CLAUDE.md - Updated version and documented fixes
- CHANGELOG.md - Added detailed v1.2.1 entry with root cause analysis
- assets/css/admin.css - Fixed table styling (removed flexbox)
- templates/frontend/pricing-table.twig - Removed global enable checks

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 20:28:28 +01:00
00c5b87aac Add wordpress symlink to gitignore
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 20:02:58 +01:00
87784f467a Release version 1.2.0 - Add complete variable product support
This major feature release adds full support for WooCommerce variable products with variation-level pricing configuration.

## Key Features
- Each product variation can have independent tier and package pricing
- AJAX-based dynamic pricing table loading on variation selection
- Admin UI integrated into WooCommerce variation panels
- Full backward compatibility with existing simple product functionality
- WooCommerce Blocks compatibility maintained

## Implementation Highlights
- Effective ID pattern throughout codebase for variation handling
- Variation-specific meta boxes with field prefix support
- Template system updated to support both simple and variation products
- JavaScript enhancements for variation selector integration
- Cart logic updated to handle variation pricing correctly

## Files Changed
- Core: wc-tier-and-package-prices.php (version 1.2.0), composer.json
- Cart: includes/class-wc-tpp-cart.php (effective ID logic)
- Frontend: includes/class-wc-tpp-frontend.php (AJAX endpoint, variation detection)
- Admin: includes/class-wc-tpp-product-meta.php (variation hooks and methods)
- Templates: templates/admin/*.twig (field prefix support, table structure)
- JavaScript: assets/js/*.js (variation support)
- Documentation: CHANGELOG.md, README.md, CLAUDE.md

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-29 20:02:03 +01:00
45a89fc693 Add Claude Code workflow improvements and git permissions
- Added finish-session command to guide end-of-session workflow
- Updated settings.local.json with git checkout and rebase permissions
- The finish-session command instructs AI to update CLAUDE.md with learnings
- Added git workflow commands to auto-approval list for smoother operations

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 17:16:11 +01:00
f530b37285 Update CLAUDE.md with v1.1.22 release learnings and best practices
- Added detailed release package creation instructions
- Documented correct zip command execution from parent directory
- Added comprehensive verification steps for release packages
- Included complete Git workflow for releases (dev → main → tag → push)
- Added common pitfalls and solutions section
- Documented WooCommerce CSS classes for admin UI
- Added Twig template modification guidelines
- Included complete release workflow summary with time estimates

These updates will help future AI assistants avoid common mistakes
when creating releases, especially around package creation and Git workflows.

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 17:09:46 +01:00
1e6d86ca10 Release version 1.1.22 - UI improvements and bug documentation
- Increased width of label input fields in admin (short → regular)
- Documented double-install bug workaround in CHANGELOG
- Updated version to 1.1.22 across all files
- Created release package with proper exclusions

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 14:33:42 +01:00
f958c7b640 Release version 1.1.21 - Add multilingual support for Swiss locales
Added translations for Swiss German (formal and informal), Swiss French,
and Swiss Italian locales to support multilingual e-commerce in Switzerland.

New Features:
- Added de_CH (Swiss German - formal "Sie") translation
- Added de_DE_informal (Informal German - "du") translation
- Added fr_CH (Swiss French) translation
- Added it_CH (Swiss Italian) translation

Technical Changes:
- Created 4 new .po translation source files
- Compiled all .po files to .mo format for runtime use
- Updated version to 1.1.21 in plugin header and constant
- Updated composer.json version to 1.1.21
- Swiss locales use CHF currency formatting (e.g., "CHF 50.-")
- German informal translations use "du/dein" instead of "Sie/Ihr"

Documentation:
- Updated CHANGELOG.md with v1.1.21 release notes
- Updated CLAUDE.md with current version and translation status
- Marked roadmap item as completed in CLAUDE.md

Release Package:
- Created wc-tier-and-package-prices-1.1.21.zip (404 KB)
- Generated MD5 checksum: 16813b3ed0d1001d5f60194d61d36fc2
- Generated SHA256 checksum: e0063852a9ac23b1fd994471a2829f9dcbe26316f00ddee2d00f77c7c6a47c8f

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 01:44:41 +01:00
b1d31f4894 Update releases README.md to v1.1.20
- Updated latest release to version 1.1.20 (December 23, 2025)
- Added "What's New in 1.1.20" section highlighting critical fixes
- Updated all version references from 1.0.1 to 1.1.20
- Expanded core features list with new capabilities:
  - Tier labels with clickable rows
  - Package quantity restrictions
  - WooCommerce Blocks full support
  - HPOS compatibility
  - View Options catalog buttons
- Updated package contents with complete file structure
- Added all documentation files to contents list
- Enhanced version history with 5 major releases
- Updated system requirements table with "Tested Up To" column
- Confirmed compatibility: WP 6.9.x, WC 10.x, PHP 8.x

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 00:40:12 +01:00
0c75234dcb Update documentation to v1.1.20 with current features
- Updated all version references to 1.1.20
- Updated WordPress requirement to 6.0+ (tested up to 6.9.x)
- Updated WooCommerce requirement to 8.0+ (tested up to 10.x)
- Added comprehensive file structure showing Twig templates
- Added WooCommerce Blocks compatibility documentation
- Added tier labels feature documentation (v1.1.7)
- Added quantity restrictions feature documentation (v1.1.0)
- Added new usage examples for tier labels and quantity restrictions
- Updated INSTALLATION.md with complete directory structure
- Updated README.md with current version changelog
- Updated QUICKSTART.md with 8 pro tips including new features
- Updated USAGE_EXAMPLES.md with 6 complete examples
- Documented WooCommerce Blocks support and v1.1.20 critical fix

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 00:32:19 +01:00
556cba20fa added .claude/ and CLAUDE.md to exclude from release 2025-12-23 00:23:21 +01:00
d721ab123a Release version 1.1.20 - Fix WooCommerce Blocks fatal error
## Fixed
- Fatal error in WooCommerce Blocks: "Cannot use object of type WC_Product_Simple as array"
- Error occurred in class-wc-tpp-cart.php:233 in block_quantity_editable() method

## Technical Details
- Filter woocommerce_store_api_product_quantity_editable passes WC_Product object as second parameter, not cart item array
- Updated method signature from block_quantity_editable($editable, $cart_item) to block_quantity_editable($editable, $product)
- Changed parameter access from $cart_item['id'] to $product->get_id()
- Added proper product object validation with is_a($product, 'WC_Product')

## Added
- CLAUDE.md - Comprehensive AI context document for future development
- Complete project architecture documentation
- Historical bug context and solutions
- Development guidelines and testing checklists

## Release
- Version bumped to 1.1.20
- Release package created with MD5 and SHA256 checksums

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 00:17:01 +01:00
dfe1a4364a added new packages, now it works! 2025-12-22 23:41:31 +01:00
9b7638a7e2 Release version 1.1.19 - Enhanced duplicate detection
Fixed persistent duplicate settings page by improving duplicate detection
to check by class type and ID instead of strict instance comparison.

Issue:
- Strict instance comparison (===) failed to detect duplicates
- Different object instances of same class not caught by previous check
- Settings page still appearing twice despite singleton and instance caching

Solution:
- Changed duplicate detection from instance comparison to type/ID checks
- Added instanceof WC_TPP_Settings check
- Added get_id() method check for ID 'tier_package_prices'
- Added direct id property check as fallback
- Multiple layers of detection to catch duplicates regardless of how created

Fixes:
- Settings page rendering twice in WooCommerce backend
- Duplicate detection failing for different instances of same class

Changes:
- Enhanced add_settings_page() with multi-layer duplicate detection
- Checks: instanceof, get_id(), and id property
- Returns early if any existing page matches criteria

Technical Details:
- Strict comparison only works if exact same object instance
- Different instances (even of same class/ID) fail === check
- instanceof checks class type regardless of which instance
- ID checks ensure no duplicate pages with same identifier
- Fallback checks handle different WooCommerce versions/implementations

Updated Files:
- includes/class-wc-tpp-admin.php (enhanced duplicate detection)
- wc-tier-and-package-prices.php (version 1.1.19)
- composer.json (version 1.1.19)
- CHANGELOG.md (v1.1.19 section)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 23:33:12 +01:00
db9ba2bacd Release version 1.1.18 - Fix root cause of duplicate settings
Identified and fixed the actual root cause of duplicate settings page:
automatic instantiation in settings file being executed multiple times.

Root Cause Analysis:
- Settings file ended with: return new WC_TPP_Settings();
- File is in Composer's classmap for autoloading
- When autoloader loads class, it executes the entire file including instantiation
- Each include/autoload created a NEW instance despite admin singleton pattern
- Admin singleton prevented multiple admin instances but not multiple settings instances

The Fix:
- Removed automatic instantiation (return new) from settings file
- Settings file now only contains class definition
- Admin class explicitly creates instance: new WC_TPP_Settings()
- Changed from include to require_once to prevent multiple file loads
- Settings instance now created exactly once, when filter needs it

Fixes:
- Settings page rendering twice in WooCommerce backend
- Multiple WC_TPP_Settings instances being created
- Composer autoload triggering unintended instantiation

Changes:
- Removed line 145 from class-wc-tpp-settings.php (return new WC_TPP_Settings())
- Modified add_settings_page() to use require_once + explicit new
- Settings file now side-effect free, safe for autoloading

Technical Details:
- Composer classmap autoloader includes files when class is referenced
- Previous code had side effect (instantiation) on every include
- New code separates class definition from instantiation
- Instance creation now controlled explicitly by admin class
- require_once ensures file loaded once even if accessed multiple times

Updated Files:
- includes/class-wc-tpp-settings.php (removed return new line)
- includes/class-wc-tpp-admin.php (explicit instantiation)
- wc-tier-and-package-prices.php (version 1.1.18)
- composer.json (version 1.1.18)
- CHANGELOG.md (v1.1.18 section)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 23:29:35 +01:00
e46372da51 Release version 1.1.17 - Array duplicate prevention
Fixed persistent duplicate settings page by adding array-level duplicate
detection in addition to singleton pattern from v1.1.16.

Root Cause:
- WooCommerce calls woocommerce_get_settings_pages filter multiple times
- Even with singleton pattern, each filter call added settings instance to array
- Singleton prevented multiple class instances but not multiple array entries

Fixes:
- Settings page rendering twice despite singleton pattern in v1.1.16
- Filter adding same settings instance to array on repeated calls

Changes:
- Added duplicate detection loop in add_settings_page() before array append
- Uses strict comparison (===) to check if instance already in array
- Returns early if settings page already present, preventing duplicate

Technical Details:
- foreach loop iterates through existing $settings array
- Compares each element against cached self::$settings_instance
- Only appends to array if instance not found
- Complements singleton pattern with array-level protection
- Handles WooCommerce calling filter multiple times during page load

Updated Files:
- includes/class-wc-tpp-admin.php (added duplicate check in filter)
- wc-tier-and-package-prices.php (version 1.1.17)
- composer.json (version 1.1.17)
- CHANGELOG.md (v1.1.17 section)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 23:05:11 +01:00
2b2c06794b Release version 1.1.16 - Singleton pattern for settings page
Fixed persistent duplicate settings page rendering by implementing proper
singleton pattern for admin class and caching settings instance.

Fixes:
- Settings page still appearing twice despite v1.1.15 fix
- Multiple instantiation of WC_TPP_Admin class
- Duplicate creation of WC_TPP_Settings instances

Changes:
- Implemented singleton pattern for WC_TPP_Admin class
- Added private static $instance property with get_instance() method
- Made WC_TPP_Admin constructor private
- Added static $settings_instance property to cache settings page
- Modified add_settings_page() to check and reuse cached settings instance
- Changed instantiation from new WC_TPP_Admin() to WC_TPP_Admin::get_instance()

Technical Details:
- Ensures only one WC_TPP_Admin instance exists throughout plugin lifecycle
- Prevents duplicate filter registrations even if woocommerce_get_settings_pages called multiple times
- Settings page object created once and reused on subsequent filter calls
- Follows WordPress/WooCommerce best practices for singleton implementation

Updated Files:
- includes/class-wc-tpp-admin.php (singleton pattern implementation)
- wc-tier-and-package-prices.php (version 1.1.16)
- composer.json (version 1.1.16)
- CHANGELOG.md (v1.1.16 section)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 20:01:27 +01:00
959229b9d8 Release version 1.1.15 - Fix duplicate settings page
Fixed settings page appearing twice in WooCommerce settings due to double instantiation of WC_TPP_Settings class.

**Issue:**
- Settings page rendered twice on same page
- WC_TPP_Settings class instantiated twice: once automatically in settings file, once via admin class include

**Fix:**
- Removed conditional wrapper `if (class_exists('WC_TPP_Settings'))` from settings return statement
- Settings class now only instantiated when admin class includes the file via `return new WC_TPP_Settings();`
- Restored v1.1.2 pattern for settings file

**Files Modified:**
- includes/class-wc-tpp-settings.php (simplified return statement)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 19:39:20 +01:00
f0ab2ff755 Release version 1.1.14 - Restore plugin functionality
**CRITICAL FIX:** Restored plugin to working state after v1.1.8-1.1.13 were completely non-functional.

**Root Cause:**
- v1.1.8 moved class instantiation from individual files to init_classes() method
- v1.1.13 wrapped classes in class_exists() guards
- Combination prevented any classes from being instantiated
- Result: No settings, no frontend, no backend functionality

**Solution:**
- Reverted to v1.1.2 pattern (last working version)
- Each class file now instantiates itself with `new ClassName();`
- Removed init_classes() method and woocommerce_loaded hook
- All class_exists() guards remain for redeclaration protection

**What Now Works:**
 WooCommerce Settings → Tier & Package Prices tab
 Product edit pages show tier/package pricing meta boxes
 Frontend displays pricing tables on product pages
 Cart applies tier/package pricing correctly
 All plugin functionality fully operational

**Files Modified:**
- includes/class-wc-tpp-admin.php
- includes/class-wc-tpp-product-meta.php
- includes/class-wc-tpp-frontend.php
- includes/class-wc-tpp-cart.php
- wc-tier-and-package-prices.php (removed init_classes)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 19:32:47 +01:00
4dd9b3cd62 Release version 1.1.13 - Critical class redeclaration fixes
Fixed critical class redeclaration errors affecting all plugin functionality
in version 1.1.12. All plugin component classes now properly guarded.

**CRITICAL FIXES:**
- Plugin completely non-functional in v1.1.12 (no settings, no frontend, no backend)
- Fatal errors for WC_TPP_Admin, WC_TPP_Product_Meta, WC_TPP_Frontend, WC_TPP_Cart, WC_TPP_Settings classes
- All classes now wrapped in class_exists() checks

**Files Modified:**
- includes/class-wc-tpp-admin.php
- includes/class-wc-tpp-product-meta.php
- includes/class-wc-tpp-frontend.php
- includes/class-wc-tpp-cart.php
- includes/class-wc-tpp-settings.php

**Technical Details:**
- Completes comprehensive redeclaration protection started in v1.1.9-1.1.12
- All 2 functions, 4 constants, and 6 classes now protected
- Plugin activates successfully and all features functional
- Settings page, product meta boxes, frontend display, cart integration all working

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 19:02:18 +01:00
9dab123209 Release version 1.1.12 - Final redeclaration fix
Fixed critical class redeclaration error for WC_Tier_Package_Prices
affecting version 1.1.11. This completes all redeclaration protection
by protecting the main plugin class.

Fixes:
- Class redeclaration error for WC_Tier_Package_Prices
- Fatal error "Cannot redeclare class WC_Tier_Package_Prices" when plugin file loaded multiple times
- Plugin activation failures caused by class redeclaration

Technical Changes:
- Wrapped WC_Tier_Package_Prices class declaration in class_exists() check
- Completes comprehensive redeclaration protection for all plugin components
- All functions, constants, and classes now safely guarded against redeclaration
- Plugin now fully protected from all redeclaration scenarios

Protected Components:
- Functions: wc_tpp_woocommerce_missing_notice(), wc_tpp_init()
- Constants: WC_TPP_VERSION, WC_TPP_PLUGIN_DIR, WC_TPP_PLUGIN_URL, WC_TPP_PLUGIN_BASENAME
- Classes: WC_Tier_Package_Prices

Updated Files:
- wc-tier-and-package-prices.php (version 1.1.12, class protection)
- composer.json (version 1.1.12)
- CHANGELOG.md (v1.1.12 section)
- All translation files compiled (.mo files)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 18:52:34 +01:00
3f117ae519 Release version 1.1.11 - Complete redeclaration protection
Fixed critical constant redeclaration warnings/errors for all plugin
constants affecting versions 1.1.3-1.1.10. This completes comprehensive
protection against all redeclaration issues by protecting constants.

Fixes:
- Constant redeclaration warnings/errors for WC_TPP_VERSION, WC_TPP_PLUGIN_DIR, WC_TPP_PLUGIN_URL, WC_TPP_PLUGIN_BASENAME
- Potential errors when plugin constants already defined
- Plugin initialization failures caused by constant redeclaration

Technical Changes:
- Wrapped all define() calls in defined() checks
- Protected WC_TPP_VERSION, WC_TPP_PLUGIN_DIR, WC_TPP_PLUGIN_URL, WC_TPP_PLUGIN_BASENAME
- Prevents warnings/errors during WordPress plugin activation/deactivation cycles
- Comprehensive protection: all global functions and constants now safely guarded
- No more redeclaration issues possible

Updated Files:
- wc-tier-and-package-prices.php (version 1.1.11, all constants protected)
- composer.json (version 1.1.11)
- CHANGELOG.md (v1.1.11 section)
- All translation files compiled (.mo files)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 18:48:01 +01:00
58bbd5164f Release version 1.1.10 - Complete function redeclaration fix
Fixed critical function redeclaration error for wc_tpp_init() affecting
version 1.1.9. This completes the fix started in v1.1.9 by protecting
all global functions from redeclaration during plugin lifecycle events.

Fixes:
- Function redeclaration error for wc_tpp_init()
- Fatal error "Cannot redeclare function wc_tpp_init()" when plugin file loaded multiple times
- Plugin activation failures

Technical Changes:
- Wrapped wc_tpp_init() function in function_exists() check
- Both wc_tpp_woocommerce_missing_notice() and wc_tpp_init() now safely guarded
- Prevents fatal errors during WordPress plugin activation/deactivation cycles
- Comprehensive protection for all global function declarations

Updated Files:
- wc-tier-and-package-prices.php (version 1.1.10, wc_tpp_init safety check)
- composer.json (version 1.1.10)
- CHANGELOG.md (v1.1.10 section)
- All translation files compiled (.mo files)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 18:45:05 +01:00
cfdbfe1504 Release version 1.1.9 - Critical function redeclaration fix
Fixed critical function redeclaration error affecting versions 1.1.3-1.1.8
that caused fatal errors during plugin activation and deactivation.

Fixes:
- Function redeclaration error for wc_tpp_woocommerce_missing_notice()
- Fatal error "Cannot redeclare function" when plugin file loaded multiple times
- Plugin activation/deactivation failures

Technical Changes:
- Wrapped wc_tpp_woocommerce_missing_notice() in function_exists() check
- Moved function declaration before WooCommerce check for better organization
- Prevents fatal errors during WordPress plugin lifecycle events

Updated Files:
- wc-tier-and-package-prices.php (version 1.1.9, function safety check)
- composer.json (version 1.1.9)
- CHANGELOG.md (v1.1.9 section)
- All translation files compiled (.mo files)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 18:40:48 +01:00
e4e4de82cb Release version 1.1.8 - Critical activation fix
Fixed critical plugin activation error that was preventing the plugin from
being activated on WordPress 6.9.x and WooCommerce 10.x.

The issue was introduced in v1.1.3 when admin classes were still being
instantiated immediately at file include time, before WooCommerce was loaded.
While v1.1.6 fixed this for Frontend and Cart classes, the Admin and
Product Meta classes were missed.

Critical Fix:
- Removed immediate instantiation from WC_TPP_Admin class
- Removed immediate instantiation from WC_TPP_Product_Meta class
- Both classes now instantiated via woocommerce_loaded hook
- Ensures all WooCommerce hooks are available before registration

Technical Changes:
- Removed "new WC_TPP_Admin();" from class-wc-tpp-admin.php
- Removed "new WC_TPP_Product_Meta();" from class-wc-tpp-product-meta.php
- Added both classes to init_classes() method in main plugin file
- All four main classes now follow consistent initialization pattern

Impact:
- Plugin now activates correctly on all WordPress/WooCommerce versions
- Resolves fatal errors during plugin activation
- Last working version was v1.1.2, now fixed in v1.1.8

Updated Files:
- includes/class-wc-tpp-admin.php (removed auto-instantiation)
- includes/class-wc-tpp-product-meta.php (removed auto-instantiation)
- wc-tier-and-package-prices.php (version 1.1.8, init_classes updated)
- composer.json (version 1.1.8)
- CHANGELOG.md (v1.1.8 section added)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 00:24:12 +01:00
af532b56eb Release version 1.1.7 - Enhanced user experience features
Added three new customer-facing features to improve product page interaction
and tier pricing functionality.

Features:
- Optional text labels for tier pricing (similar to package labels)
- Clickable tier pricing table rows to auto-populate quantity field
- Add to Cart button auto-disables when quantity is 0 or less

Enhanced User Experience:
- Tier pricing rows now clickable with cursor pointer and hover animation
- Clicking tier row sets quantity and smoothly scrolls to quantity field
- Add to Cart button shows disabled state with reduced opacity
- Tier labels display below quantity in italic gray text

Technical Changes:
- Added optional 'label' field to tier pricing admin meta box
- Updated tier save logic to include label field (sanitized)
- Enhanced tier pricing frontend template to display labels
- Added click handler for tier pricing rows in frontend.js
- Added updateAddToCartButton() function to manage button state
- CSS: .wc-tpp-tier-label styling for tier labels
- CSS: Clickable cursor and hover transform for tier rows
- CSS: Disabled button styling (.single_add_to_cart_button:disabled)

Updated Files:
- templates/admin/tier-row.twig (added label field)
- includes/class-wc-tpp-product-meta.php (save label, template update)
- templates/frontend/tier-pricing-table.twig (display labels)
- assets/js/frontend.js (tier row clicks, button disable logic)
- assets/css/frontend.css (tier label style, clickable rows, disabled button)
- wc-tier-and-package-prices.php (version 1.1.7)
- composer.json (version 1.1.7)
- CHANGELOG.md (v1.1.7 section)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 00:15:48 +01:00
e2a11de80a Release version 1.1.6 - Minor improvements
Updated Plugin URI to correct repository path and added notes files to gitignore.

Changes:
- Updated Plugin URI from /wc-tier-package-prices to /magdev/wc-tier-package-prices
- Added notes.* to .gitignore to exclude local notes files

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-22 00:02:19 +01:00
e40830b69b Release version 1.1.6 - Critical fix for plugin activation
Fixed critical bug that prevented plugin activation in v1.1.3, v1.1.4, and v1.1.5.

Root Cause:
- WC_TPP_Cart and WC_TPP_Frontend classes were instantiated immediately when
  their files were loaded (via `new ClassName();` at bottom of files)
- This happened BEFORE WooCommerce was fully loaded
- Hook registration attempted to access WooCommerce functions before they existed
- Result: Fatal error during plugin activation

Solution:
- Removed immediate instantiation from class-wc-tpp-cart.php (line 251)
- Removed immediate instantiation from class-wc-tpp-frontend.php (line 186)
- Added init_classes() method to main plugin class
- Classes now instantiated via woocommerce_loaded hook
- Ensures WooCommerce is fully initialized before any hooks are registered

Changes:
- includes/class-wc-tpp-cart.php - Removed `new WC_TPP_Cart();`
- includes/class-wc-tpp-frontend.php - Removed `new WC_TPP_Frontend();`
- wc-tier-and-package-prices.php - Added init_classes() and woocommerce_loaded hook
- CHANGELOG.md - Added v1.1.6 section
- composer.json - Version 1.1.6
- All translation files updated to 1.1.6
- All .mo files recompiled

This fix ensures proper WordPress plugin lifecycle:
1. Plugin file loaded
2. Classes defined (but not instantiated)
3. WooCommerce loads
4. woocommerce_loaded hook fires
5. Classes instantiated with full WooCommerce availability

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:57:27 +01:00
9765c5f119 Release version 1.1.5 - Critical bug fix for plugin activation
CRITICAL FIX: Resolved fatal error that prevented plugin activation in
versions 1.1.3 and 1.1.4. The add_cart_quantity_css() method was attempting
to access WooCommerce cart object during wp_head action, causing failures
when WooCommerce wasn't fully initialized or on admin pages.

Fixes:
- Plugin activation error in v1.1.3 and v1.1.4
- Fatal error when WooCommerce cart object not available
- Frontend errors on admin pages
- Issues during plugin initialization

Technical Changes:
- Added function_exists('WC') check before accessing WooCommerce
- Added is_admin() check to prevent CSS injection on admin pages
- Enhanced add_cart_quantity_css() with proper guards
- Line 191: if (!function_exists('WC') || !WC()->cart || is_admin())

Root Cause:
The add_cart_quantity_css() method (added in v1.1.3) hooks into wp_head
but didn't properly check if WooCommerce cart was available, causing
errors during plugin activation and on admin pages.

Updated Files:
- includes/class-wc-tpp-cart.php (enhanced error checking)
- wc-tier-and-package-prices.php (version 1.1.5)
- composer.json (version 1.1.5)
- CHANGELOG.md (v1.1.5 section)
- All translation files (.pot, .po, .mo) updated to version 1.1.5

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:49:24 +01:00
5cfabedb94 released v1.1.4 2025-12-21 19:36:35 +01:00
88e30d028c Release version 1.1.4 - WooCommerce Blocks support and improved styling
Added comprehensive WooCommerce Blocks support for quantity restrictions
and improved "View Options" button styling to match standard WooCommerce
Add to Cart buttons.

Features:
- WooCommerce Blocks cart/mini-cart quantity restriction support
- Store API integration for block-based carts
- Improved "View Options" button styling with WooCommerce standards
- Enhanced hover effects and transitions

Technical Changes:
- Added woocommerce_store_api_product_quantity_editable filter
- Added block_quantity_editable() method in WC_TPP_Cart class
- Enhanced CSS for .wc-block-components-quantity-selector targeting
- Updated button styling: padding (0.618em × 1em), font-weight (700)
- Added transition effects for smooth hover states

Fixed:
- WooCommerce blocks cart quantity selector now properly hidden
- WooCommerce blocks mini-cart quantity selector visibility
- "View Options" button now matches Add to Cart button appearance

Updated Files:
- includes/class-wc-tpp-cart.php (WooCommerce Blocks support)
- assets/css/frontend.css (enhanced button styling)
- wc-tier-and-package-prices.php (version 1.1.4)
- composer.json (version 1.1.4)
- CHANGELOG.md (v1.1.4 section)
- All translation files (.pot, .po, .mo) updated to version 1.1.4

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:33:34 +01:00
d55ada7924 Release version 1.1.3 - Cart quantity visibility fix
Fixed persistent cart quantity input visibility issues for products with
package quantity restrictions. Enhanced implementation ensures quantity
inputs are properly hidden in both main cart and mini-cart/sidebar.

Fixes:
- Cart quantity inputs now properly hidden with increased filter priority
- Mini-cart quantity inputs correctly replaced with read-only text
- Added fallback CSS injection to handle theme/plugin conflicts
- Enhanced DOM targeting with data attributes and multiple CSS selectors

Technical Changes:
- Increased filter priority to 999 for woocommerce_cart_item_quantity
- Added woocommerce_widget_cart_item_quantity filter for mini-cart support
- Added add_cart_quantity_css() method for dynamic CSS injection
- Added maybe_hide_mini_cart_quantity_input() method
- Enhanced quantity spans with data-product-id attribute
- Added wc-tpp-restricted-qty CSS class
- Implemented sibling (+) and general sibling (~) CSS selectors

Updated Files:
- includes/class-wc-tpp-cart.php (enhanced with mini-cart support)
- wc-tier-and-package-prices.php (version 1.1.3)
- composer.json (version 1.1.3)
- CHANGELOG.md (v1.1.3 section)
- All translation files (.pot, .po, .mo) updated to version 1.1.3

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:19:18 +01:00
4ece4dd69e Release version 1.1.2 - Catalog button modification
Enhanced package quantity restriction enforcement by replacing "Add to Cart"
buttons with "View Options" links on catalog pages for products with
quantity restrictions. This prevents customers from attempting to add
restricted products directly from shop/category pages.

Changes:
- Added catalog button modification for restricted products
- Implemented "View Options" button with eye icon styling
- Created has_quantity_restriction() helper method
- Extended CSS loading to all WooCommerce pages
- Added modify_catalog_add_to_cart_button() filter method
- Updated translations with 2 new strings (en_US, de_DE, de_CH_informal)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-21 19:04:41 +01:00
124 changed files with 4073 additions and 953 deletions

0
.claude/commands/.gitignore vendored Normal file
View File

View File

@@ -9,11 +9,37 @@
"Bash(composer install:*)",
"Bash(composer update:*)",
"Bash(git add:*)",
"Bash(git commit -m \"$\\(cat <<''EOF''\nRelease version 1.1.0 - Package quantity restriction feature\n\nAdded comprehensive package quantity restriction functionality that allows\nlimiting product purchases to predefined package sizes only.\n\nFeatures:\n- Global setting to enable package quantity restrictions\n- Per-product override for quantity restrictions\n- Automatic hiding of quantity input field when restricted\n- Frontend validation with package selection UI\n- Server-side cart validation\n- User-friendly error messages\n- Complete translations for all supported languages\n\n🤖 Generated with [Claude Code]\\(https://claude.com/claude-code\\)\n\nCo-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
"Bash(git tag:*)",
"Bash(rsync:*)",
"Bash(zip -r:*)",
"Bash(cat:*)"
"Bash(cat:*)",
"Bash(for po in *.po)",
"Bash(do msgfmt -o \"$po%.po.mo\" \"$po\")",
"Bash(done)",
"Bash(git commit:*)",
"Bash(node -c:*)",
"Bash(php -l:*)",
"Bash(git push:*)",
"Bash(git checkout:*)",
"Bash(git rebase:*)",
"Bash(git merge:*)",
"Bash(git stash:*)",
"Bash(for po in languages/*.po)",
"Bash('wc-tier-and-package-prices/*.log' )",
"Bash('wc-tier-and-package-prices/.claude/*' )",
"Bash('wc-tier-and-package-prices/CLAUDE.md' )",
"Bash('wc-tier-and-package-prices/releases/*' )",
"Bash('wc-tier-and-package-prices/node_modules/*' )",
"Bash('wc-tier-and-package-prices/.DS_Store' )",
"Bash('wc-tier-and-package-prices/Thumbs.db' )",
"Bash('wc-tier-and-package-prices/.vscode/*' )",
"Bash('wc-tier-and-package-prices/.idea/*' )",
"Bash('wc-tier-and-package-prices/*.sublime-*' )",
"Bash('wc-tier-and-package-prices/notes.*' )",
"Bash('wc-tier-and-package-prices/logs/*' )",
"Bash('wc-tier-and-package-prices/templates/cache/*' )",
"Bash('wc-tier-and-package-prices/composer.lock' )",
"Bash('*/wordpress/*')"
]
}
}

7
.gitignore vendored
View File

@@ -21,7 +21,14 @@ npm-debug.log
# Logs
*.log
/logs
# Notes
notes.*
# OS
.DS_Store
._*
# local code
wordpress

View File

@@ -5,6 +5,609 @@ 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.5] - 2025-12-30
### Added
- **Parent Product Default Pricing**: Variable products can now define tier and package pricing at the parent product level that applies as defaults to all variations. Individual variations can override these defaults with their own specific pricing. This makes it much easier to set up pricing for products with many variations - set defaults once on the parent, then only customize the variations that need different pricing.
- **Hide Empty Table Headers**: Table headers for tier and package pricing in the admin area now automatically hide when no pricing rules are defined. This creates a cleaner interface when starting to configure a product, showing only the helpful empty state message and "Add" button.
### Technical Details
**Parent Fallback Implementation**:
- Modified `WC_TPP_Frontend::get_tier_price()` and `WC_TPP_Frontend::get_package_price()` to fall back to parent product pricing when variation doesn't have its own pricing
- Updated `WC_TPP_Cart` to use helper methods `get_packages_with_fallback()` and `is_restriction_enabled()` for consistent parent fallback behavior
- All cart validation, quantity restriction, and display methods now support parent product defaults
- Fixed cart pricing calls to pass parent `$product_id` instead of `$effective_id` for proper fallback resolution
**CSS Enhancement**:
- Added `:has()` pseudo-class selectors to hide table headers when tbody is empty
- Leverages existing empty state message styling for consistent UX
**Backward Compatibility**:
- 100% backward compatible - existing products continue working as before
- No database migrations required
- Variations with specific pricing take precedence over parent defaults
### Changed Files
- `includes/class-wc-tpp-frontend.php` - Added parent fallback logic to `get_tier_price()` and `get_package_price()` methods
- `includes/class-wc-tpp-cart.php` - Added helper methods `get_packages_with_fallback()` and `is_restriction_enabled()`; updated all cart methods to support parent fallback; fixed pricing calls to use correct product ID
- `assets/css/admin.css` - Added CSS rules to hide table headers when no pricing rules exist
## [1.2.4] - 2025-12-30
### Fixed
- **Admin Table Borders (Critical)**: Fixed table borders still appearing in v1.2.3 despite borderless styling attempt. WooCommerce's default CSS was overriding `border: none` declarations. Added `!important` flags to all border removal rules and `border-collapse: collapse !important` to force borderless styling. Now all tier/package pricing tables (simple and variable products) display correctly without borders, matching WooCommerce's clean admin UI.
- **Checkbox and Help Icon Layout**: Fixed help icon positioning and checkbox spacing issues from v1.2.3. The help icon was appearing at the right edge of the container instead of next to the label text. Increased checkbox-label margin from 8px to 12px for better spacing. Changed label layout from float positioning to flexbox (`inline-flex`) to keep help icon directly adjacent to label text. Added inline description hiding when tooltip is shown.
### Technical Details
**Root Cause - Table Borders**: WooCommerce's core admin CSS has higher specificity border rules that override simple `border: none` declarations. The solution required:
- Adding `!important` to all `border: none` rules targeting tables, th, td, thead, tbody, and tr elements
- Adding `border-collapse: collapse !important` to prevent cell borders from being visible
- Comprehensive targeting of all table structural elements for complete border removal
**Root Cause - Help Icon Position**: WooCommerce's default `.woocommerce-help-tip` styling uses `float: right` which positions the icon at the container's right edge. The fix:
- Removed float positioning with `float: none`
- Changed to `display: inline-block` with `vertical-align: middle`
- Wrapped label and help-tip in flexbox container (`display: inline-flex; align-items: center`)
- Controlled spacing with precise margins (checkbox: 12px right, help-tip: 6px left)
### Changed Files
- `assets/css/admin.css` - Added `!important` flags to all border removal rules; added `border-collapse: collapse`; increased checkbox margin to 12px; converted label layout to flexbox; positioned help-tip with inline-block; added inline description hiding
## [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
- Settings page still appearing twice despite instance caching
- Duplicate detection using strict instance comparison failing for different object instances
### Changed
- Enhanced duplicate detection to check by class type and ID instead of instance
- Added `instanceof WC_TPP_Settings` check
- Added ID-based duplicate detection via `get_id()` method and direct property access
- Multiple fallback checks to catch duplicates regardless of instance identity
### Technical Details
- Previous strict comparison (`===`) failed when different instances of same class existed
- New approach checks: instanceof, get_id() method, and id property
- Returns early if any settings page with ID 'tier_package_prices' found
- Prevents duplicates even if settings instance recreated or serialized
## [1.1.18] - 2025-12-22
### Fixed
- **ROOT CAUSE IDENTIFIED**: Settings page rendering twice due to automatic instantiation in settings file
- Settings file being included multiple times via Composer autoloader creating duplicate instances
### Changed
- Removed `return new WC_TPP_Settings();` from bottom of settings file
- Changed admin class to explicitly instantiate settings with `new WC_TPP_Settings()`
- Changed from `include` to `require_once` for settings file to prevent multiple loads
### Technical Details
- Settings file (class-wc-tpp-settings.php) was creating instance automatically on include
- File is in Composer's classmap, so when autoloaded it executed instantiation again
- Each include/autoload created new instance even with singleton pattern in admin class
- Solution: Remove automatic instantiation, use `require_once` + explicit `new` in admin class
- Now settings instance only created once, explicitly, when needed by filter
- Composer autoload can load class definition without side effects
## [1.1.17] - 2025-12-22
### Fixed
- Settings page still rendering twice despite singleton pattern in v1.1.16
- Filter adding settings instance to array multiple times when called repeatedly
### Changed
- Added duplicate detection in `add_settings_page()` filter method
- Filter now checks if settings instance already exists in array before adding
### Technical Details
- Added foreach loop to check existing settings pages in array
- Uses strict comparison (`===`) to detect if exact instance already present
- Returns early if settings instance found, preventing duplicate array entries
- Complements singleton pattern from v1.1.16 with array-level duplicate prevention
- Handles edge case where WooCommerce calls filter multiple times
## [1.1.16] - 2025-12-22
### Fixed
- Settings page still rendering twice in WooCommerce backend despite v1.1.15 fix
- Multiple instantiation of WC_TPP_Admin and WC_TPP_Settings classes
### Changed
- Implemented singleton pattern for WC_TPP_Admin class with `get_instance()` method
- Made WC_TPP_Admin constructor private to prevent direct instantiation
- Added static caching of WC_TPP_Settings instance to prevent duplicate creation
- Changed class instantiation from `new WC_TPP_Admin()` to `WC_TPP_Admin::get_instance()`
### Technical Details
- Added `private static $instance` property to WC_TPP_Admin class
- Added `private static $settings_instance` property to cache settings page instance
- Modified `add_settings_page()` to check and reuse cached settings instance
- Ensures only one instance of each class exists throughout plugin lifecycle
- Prevents duplicate filter registrations even if called multiple times
## [1.1.15] - 2025-12-22
### Fixed
- Settings page rendering twice in WooCommerce settings
- Duplicate instantiation of WC_TPP_Settings class causing double rendering
### Technical Details
- Removed conditional `if (class_exists('WC_TPP_Settings'))` wrapper from settings return statement
- Settings class now only instantiated via `return new WC_TPP_Settings();` when included by admin class
- Matches v1.1.2 pattern where settings file returns instance without automatic instantiation
- Prevents double registration in WooCommerce settings pages array
## [1.1.14] - 2025-12-22
### Fixed
- **CRITICAL:** Plugin completely non-functional in v1.1.8-1.1.13 - no settings, no frontend, no backend
- Classes never instantiated due to incorrect initialization pattern introduced in v1.1.8
- Restored v1.1.2 pattern: classes auto-instantiate when files are included
- All plugin functionality now working: settings page, product meta boxes, frontend display, cart integration
### Changed
- Reverted to direct class instantiation pattern from v1.1.2 (last known working version)
- Removed `init_classes()` method and `woocommerce_loaded` hook approach from v1.1.8
- Each class file now instantiates itself with `new ClassName()` at end of file
- Simplified plugin initialization for better reliability
### Technical Details
- Restored class instantiation in all 5 component files:
- `class-wc-tpp-admin.php`: Added `new WC_TPP_Admin();` after class declaration
- `class-wc-tpp-product-meta.php`: Added `new WC_TPP_Product_Meta();` after class declaration
- `class-wc-tpp-frontend.php`: Added `new WC_TPP_Frontend();` after class declaration
- `class-wc-tpp-cart.php`: Added `new WC_TPP_Cart();` after class declaration
- `class-wc-tpp-settings.php`: Already has instantiation via return statement
- Removed `init_classes()` method from main plugin class
- Removed `woocommerce_loaded` hook that delayed class instantiation
- Classes now instantiate immediately when `require_once` loads them
- All `class_exists()` guards remain in place for redeclaration protection
## [1.1.13] - 2025-12-22
### Fixed
- **CRITICAL:** Class redeclaration errors for all plugin component classes affecting version 1.1.12
- Fatal errors "Cannot redeclare class WC_TPP_Admin", "Cannot redeclare class WC_TPP_Product_Meta", "Cannot redeclare class WC_TPP_Frontend", "Cannot redeclare class WC_TPP_Cart", "Cannot redeclare class WC_TPP_Settings"
- Plugin functionality completely broken in v1.1.12 - no settings page, no frontend display, no backend controls
- All plugin features now working correctly after adding class guards
### Technical Details
- Wrapped all 5 plugin component class declarations in `class_exists()` checks:
- `WC_TPP_Admin` (includes/class-wc-tpp-admin.php)
- `WC_TPP_Product_Meta` (includes/class-wc-tpp-product-meta.php)
- `WC_TPP_Frontend` (includes/class-wc-tpp-frontend.php)
- `WC_TPP_Cart` (includes/class-wc-tpp-cart.php)
- `WC_TPP_Settings` (includes/class-wc-tpp-settings.php)
- Completes comprehensive redeclaration protection started in v1.1.9-1.1.12
- All functions, constants, and classes now fully protected against redeclaration
- Plugin now activates and functions correctly without fatal errors
## [1.1.12] - 2025-12-22
### Fixed
- **CRITICAL:** Class redeclaration error for `WC_Tier_Package_Prices` affecting version 1.1.11
- Fatal error "Cannot redeclare class WC_Tier_Package_Prices" when plugin file loaded multiple times
- Plugin activation failures caused by class redeclaration
### Technical Details
- Wrapped `WC_Tier_Package_Prices` class declaration in `class_exists()` check
- Completes comprehensive redeclaration protection for all plugin components
- Prevents fatal errors during WordPress plugin activation/deactivation cycles
- All functions, constants, and classes now safely guarded against redeclaration
## [1.1.11] - 2025-12-22
### Fixed
- **CRITICAL:** Constant redeclaration warnings/errors for plugin constants affecting versions 1.1.3-1.1.10
- Potential errors when plugin constants (WC_TPP_VERSION, WC_TPP_PLUGIN_DIR, etc.) already defined
- Plugin initialization failures caused by constant redeclaration
### Technical Details
- Wrapped all `define()` calls in `defined()` checks for WC_TPP_VERSION, WC_TPP_PLUGIN_DIR, WC_TPP_PLUGIN_URL, WC_TPP_PLUGIN_BASENAME
- Prevents warnings/errors during WordPress plugin activation/deactivation cycles
- Completes comprehensive protection against all redeclaration issues
- All global functions and constants now safely guarded
## [1.1.10] - 2025-12-22
### Fixed
- **CRITICAL:** Function redeclaration error for `wc_tpp_init()` affecting version 1.1.9
- Fatal error "Cannot redeclare function wc_tpp_init()" when plugin file loaded multiple times
- Plugin activation failures caused by function redeclaration
### Technical Details
- Wrapped `wc_tpp_init()` function in `function_exists()` check
- Completes the fix started in v1.1.9 by protecting all global functions
- Prevents fatal errors during WordPress plugin activation cycles
- Both `wc_tpp_woocommerce_missing_notice()` and `wc_tpp_init()` now safely guarded
## [1.1.9] - 2025-12-22
### Fixed
- **CRITICAL:** Function redeclaration error for `wc_tpp_woocommerce_missing_notice()` affecting versions 1.1.3-1.1.8
- Fatal error "Cannot redeclare function wc_tpp_woocommerce_missing_notice()" when plugin file loaded multiple times
- Plugin activation and deactivation failures caused by function redeclaration
### Technical Details
- Wrapped `wc_tpp_woocommerce_missing_notice()` function in `function_exists()` check
- Prevents fatal error during WordPress plugin activation/deactivation cycles
- Ensures function can safely be declared even if file is included multiple times
- Moved function declaration before WooCommerce check for better code organization
## [1.1.8] - 2025-12-22
### Fixed
- **CRITICAL:** Plugin activation fatal error introduced in v1.1.3-v1.1.7
- Fixed premature class instantiation of `WC_TPP_Admin` and `WC_TPP_Product_Meta`
- Both classes now instantiated via `woocommerce_loaded` hook after WooCommerce is available
- Resolves WordPress 6.9.x and WooCommerce 10.x compatibility issues
### Technical Details
- Removed `new WC_TPP_Admin();` from bottom of class-wc-tpp-admin.php
- Removed `new WC_TPP_Product_Meta();` from bottom of class-wc-tpp-product-meta.php
- Added both classes to `init_classes()` method in main plugin file
- All four main classes (Admin, Product Meta, Frontend, Cart) now follow same initialization pattern
- Ensures WooCommerce hooks are available before registration
## [1.1.7] - 2025-12-22
### Added
- Optional text labels for tier pricing (similar to package labels)
- Clickable tier pricing rows that auto-populate quantity field
- Add to Cart button auto-disable when quantity is 0 or less
### Enhanced
- Tier pricing table rows now clickable with visual hover feedback
- Clicking a tier row sets quantity to that tier's minimum quantity
- Smooth scroll animation to quantity field when tier is clicked
- Add to Cart button disabled state with visual feedback (opacity, cursor)
- Tier labels display below quantity in frontend table (italic, gray text)
### Technical Details
- Added optional `label` field to tier pricing meta box (admin/tier-row.twig)
- Updated tier save logic to store label field (class-wc-tpp-product-meta.php)
- Enhanced tier pricing template to display labels (frontend/tier-pricing-table.twig)
- Added click handler for tier rows (assets/js/frontend.js)
- Added `updateAddToCartButton()` function to manage button state
- CSS: `.wc-tpp-tier-label` styling for tier labels
- CSS: Clickable cursor and hover animation for tier rows
- CSS: Disabled button styling (`.single_add_to_cart_button:disabled`)
## [1.1.6] - 2025-12-21
### Fixed
- **CRITICAL:** Plugin activation fatal error in v1.1.3, v1.1.4, and v1.1.5
- Fatal error caused by premature class instantiation before WooCommerce is loaded
- Removed immediate class instantiation from `class-wc-tpp-cart.php` and `class-wc-tpp-frontend.php`
### Technical
- Moved `WC_TPP_Cart` and `WC_TPP_Frontend` instantiation to `woocommerce_loaded` hook
- Added `init_classes()` method to main plugin class for controlled class initialization
- Ensures WooCommerce is fully loaded before registering hooks that depend on WC functions
- Fixed hook registration timing to prevent accessing WooCommerce before it's available
## [1.1.5] - 2025-12-21
### Fixed
- **CRITICAL:** Plugin activation error in v1.1.3 and v1.1.4 caused by `add_cart_quantity_css()` method
- Fatal error when WooCommerce cart object not available during plugin initialization
- Frontend errors on admin pages and during activation
### Technical
- Added `function_exists('WC')` check before accessing WooCommerce functions
- Added `is_admin()` check to prevent CSS injection on admin pages
- Enhanced error prevention in `add_cart_quantity_css()` method
## [1.1.4] - 2025-12-21
### Added
- WooCommerce Blocks support for quantity restrictions
- `woocommerce_store_api_product_quantity_editable` filter for block-based carts
- `block_quantity_editable()` method in WC_TPP_Cart class
- CSS targeting for `.wc-block-components-quantity-selector` elements
### Enhanced
- "View Options" button styling to match standard WooCommerce "Add to Cart" buttons
- Button padding, font weight, and border radius for better visual consistency
- Hover effects with smooth transitions
### Fixed
- WooCommerce blocks cart quantity selector visibility for restricted products
- WooCommerce blocks mini-cart quantity selector visibility
### Technical
- Added Store API integration for block-based cart/mini-cart
- Enhanced CSS for block cart items with product-specific selectors
- Improved button styling with WooCommerce standard values (0.618em × 1em padding)
- Added transition effects for better UX
## [1.1.3] - 2025-12-21
### Fixed
- Cart quantity input visibility issue in cart and cart sidebar for restricted products
- Enhanced filter priority (999) to ensure quantity hiding runs after other plugins
- Mini-cart quantity input now properly hidden for restricted products
### Added
- `woocommerce_widget_cart_item_quantity` filter support for mini-cart
- `add_cart_quantity_css()` method for dynamic CSS injection
- `data-product-id` attribute to quantity spans for targeted CSS selectors
- CSS class `wc-tpp-restricted-qty` for improved targeting
### Technical
- Increased filter priority from 10 to 999 for `woocommerce_cart_item_quantity`
- Added `maybe_hide_mini_cart_quantity_input()` method in WC_TPP_Cart class
- Dynamic CSS injection via `wp_head` action as fallback
- Used both sibling (+) and general sibling (~) CSS selectors for DOM variations
## [1.1.2] - 2025-12-21
### Added
- Catalog "View Options" button for products with quantity restrictions
- Automatic button replacement in shop/category/archive pages
- Eye icon (Dashicons) for "View Options" button styling
### Changed
- "Add to Cart" button replaced with "View Options" link on catalog pages for restricted products
- CSS now loads on all WooCommerce pages (shop, cart, checkout, product)
- Catalog buttons now direct to product page instead of adding to cart
### Technical
- Added `has_quantity_restriction()` static method in WC_TPP_Frontend class
- Added `modify_catalog_add_to_cart_button()` method in WC_TPP_Frontend class
- Extended `woocommerce_loop_add_to_cart_link` filter hook
- CSS classes: `wc-tpp-view-options`, `wc-tpp-cart-quantity`, `wc-tpp-restriction-notice`
- Updated `enqueue_scripts()` to load CSS on all WooCommerce pages
### Translations
- Added 2 new translatable strings
- Updated all translations (en_US, de_DE, de_CH_informal)
- Compiled all .mo files with new strings
## [1.1.1] - 2025-12-21
### Added

865
CLAUDE.md Normal file
View File

@@ -0,0 +1,865 @@
# WooCommerce Tier and Package Prices - AI Context Document
**Last Updated:** 2025-12-30
**Current Version:** 1.2.5
**Author:** Marco Graetsch
**Project Status:** Production-ready WordPress plugin
## Project Overview
This is a WooCommerce plugin that adds flexible pricing capabilities to products through two distinct pricing models:
1. **Tier Pricing (Volume Discounts)**: Progressive discounts based on quantity ranges (e.g., 1-9 items @ $12, 10-24 @ $10, 25+ @ $8)
2. **Package Pricing (Fixed Bundles)**: Exact quantity packages at fixed prices (e.g., exactly 10 items for $95, exactly 25 for $200)
### Key Fact: 100% AI-Generated
This project is proudly **"vibe-coded"** using Claude.AI - the entire codebase was created through AI assistance.
## Technical Stack
- **Language:** PHP 7.4+
- **Framework:** WordPress Plugin API
- **E-commerce:** WooCommerce 8.0+ (tested up to 10.x)
- **Template Engine:** Twig 3.0 (via Composer)
- **Frontend:** Vanilla JavaScript + jQuery
- **Styling:** Custom CSS
- **Dependency Management:** Composer
- **Internationalization:** WordPress i18n (.pot/.po/.mo files)
### Dependencies
```json
{
"twig/twig": "^3.0",
"symfony/polyfill-ctype": "^1.x",
"symfony/polyfill-mbstring": "^1.x"
}
```
## Architecture
### Directory Structure
```txt
wc-tier-and-package-prices/
├── wc-tier-and-package-prices.php # Main plugin file (entry point)
├── includes/ # PHP classes
│ ├── class-wc-tpp-admin.php # Admin settings integration
│ ├── class-wc-tpp-settings.php # WooCommerce settings page
│ ├── class-wc-tpp-product-meta.php # Product edit page meta boxes
│ ├── class-wc-tpp-frontend.php # Product page display logic
│ ├── class-wc-tpp-cart.php # Cart price calculations
│ └── class-wc-tpp-template-loader.php # Twig template loader
├── templates/ # Twig templates
│ ├── admin/ # Admin interface templates
│ │ ├── tier-row.twig # Single tier input row
│ │ └── package-row.twig # Single package input row
│ └── frontend/ # Customer-facing templates
│ ├── pricing-table.twig # Main pricing display wrapper
│ ├── tier-pricing-table.twig # Tier pricing display
│ └── package-pricing-display.twig # Package buttons/cards
├── assets/
│ ├── css/
│ │ ├── admin.css # Backend styling
│ │ └── frontend.css # Product page & cart styling
│ └── js/
│ ├── admin.js # Meta box interaction (add/remove rows)
│ └── frontend.js # Dynamic price updates, package selection
├── languages/ # Translation files
│ ├── *.pot # Translation template
│ ├── *.po # Translation sources
│ └── *.mo # Compiled translations
├── vendor/ # Composer dependencies (included in releases)
├── releases/ # Release packages (not in git)
└── *.md # Documentation files
```
### Class Responsibilities
#### 1. `WC_Tier_Package_Prices` (Main Plugin Class)
- **Location:** `wc-tier-and-package-prices.php`
- **Pattern:** Singleton
- **Responsibilities:**
- Plugin initialization and bootstrapping
- Loading all component classes via `includes()`
- HPOS (High-Performance Order Storage) compatibility declaration
- Text domain loading for internationalization
- Activation/deactivation hooks
#### 2. `WC_TPP_Admin`
- **Location:** `includes/class-wc-tpp-admin.php`
- **Pattern:** Singleton
- **Responsibilities:**
- Enqueues admin CSS/JS
- Registers WooCommerce settings page via filter
- Manages settings page instance (cached to prevent duplicates)
- Product meta box asset loading
#### 3. `WC_TPP_Settings`
- **Location:** `includes/class-wc-tpp-settings.php`
- **Extends:** `WC_Settings_Page` (WooCommerce core)
- **Responsibilities:**
- Creates "Tier & Package Prices" tab in WooCommerce settings
- Defines global plugin settings (enable/disable features, display position, etc.)
- 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
- `wc_tpp_display_position` (before_add_to_cart / after_add_to_cart / after_price)
- `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
- Renders Twig templates for meta box rows
- Saves tier/package data to post meta
- Nonce verification and capability checks for security
- 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
- Displays pricing tables via Twig templates
- Localizes currency settings to JavaScript
- Hides quantity inputs for restricted products
- Modifies catalog "Add to Cart" buttons to "View Options" for restricted products
- 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
- Applies tier/package pricing during cart totals calculation
- Stores pricing metadata in cart items for display
- Customizes cart item display (price labels, quantity indicators)
- Validates package quantities on add-to-cart
- Hides/disables quantity inputs for restricted products (classic cart + blocks)
- **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:**
- Initializes Twig environment with proper paths
- Renders Twig templates from both admin and frontend directories
- Handles template caching and error handling
## Important Implementation Details
### Price Calculation Logic
**Package Pricing** (exact match):
```php
// In cart: if quantity == 10 and package exists for 10, use package price
if ($quantity == $package['qty']) {
$unit_price = $package['price'] / $quantity; // Total price divided by quantity
$product->set_price($unit_price); // WooCommerce expects unit price
}
```
**Tier Pricing** (range-based):
```php
// In cart: if quantity >= 10, use tier price for quantities 10+
foreach ($tiers as $tier) {
if ($quantity >= $tier['min_qty']) {
$applicable_price = $tier['price']; // This is already unit price
}
}
$product->set_price($applicable_price);
```
### Quantity Restriction Feature
Products can be configured to ONLY allow purchase in package quantities:
- **Global setting:** `wc_tpp_restrict_package_quantities`
- **Per-product setting:** `_wc_tpp_restrict_to_packages`
- **When enabled:**
- Quantity inputs are hidden on product page, cart, and mini-cart
- Customers must use package selection buttons
- Validation prevents arbitrary quantities from being added
- Catalog buttons change to "View Options" instead of "Add to Cart"
### 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()`
### Cart Item Metadata
The plugin stores additional data in cart items for display purposes:
```php
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_pricing_type'] = 'package' | 'tier';
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_total_price'] = 99.99; // For packages
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_unit_price'] = 9.99; // For tiers
```
This metadata is used by display filters to show "(Package price)" or "(Volume discount)" labels.
## Common Patterns & Conventions
### Class Instantiation Pattern
All classes auto-instantiate at the end of their file:
```php
if (!class_exists('WC_TPP_Frontend')) {
class WC_TPP_Frontend {
// class code
}
}
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
- Output escaping in templates (`esc_attr`, `esc_html`, `esc_js`)
- Direct file access prevention via `ABSPATH` check
### Translation Ready
All user-facing strings use:
```php
__('Text to translate', 'wc-tier-package-prices')
_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
### WooCommerce Blocks Fatal Error (v1.1.19 → v1.1.20)
```txt
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
### CSS Specificity Issues (v1.2.3 → v1.2.4)
**Problem:** Admin table borders still visible despite `border: none` declarations in v1.2.3
```txt
Issue: WooCommerce's core admin CSS has higher specificity border rules
Location: assets/css/admin.css
Symptom: Tables still showing borders in product edit screens
```
- **Root Cause:** WooCommerce's default admin CSS uses highly specific selectors that override simple `border: none` declarations
- **Failed Approach (v1.2.3):** Adding `border: none` to table elements without `!important`
- **Successful Fix (v1.2.4):**
- Added `!important` flags to ALL border removal rules
- Added `border-collapse: collapse !important` to force borderless styling
- Targeted all table structural elements: `table`, `th`, `td`, `thead`, `tbody`, `tr`
- **Lesson:** When overriding WooCommerce core CSS, `!important` is often necessary due to high specificity in core styles
**Problem:** Help icon positioned at right edge instead of next to label text
```txt
Issue: WooCommerce help-tip uses float: right positioning
Location: assets/css/admin.css (checkbox/label layout)
Symptom: Help icon appearing far from label text at container edge
```
- **Root Cause:** WooCommerce's default `.woocommerce-help-tip` styling uses `float: right`
- **Failed Approach (v1.2.3):** Simple margin adjustments without changing positioning model
- **Successful Fix (v1.2.4):**
- Removed float positioning: `float: none`
- Changed to `display: inline-block` with `vertical-align: middle`
- Wrapped label and help-tip in flexbox container: `display: inline-flex; align-items: center`
- Controlled precise spacing with margins (checkbox: 12px, help-tip: 6px)
- **Lesson:** Overriding float-based layouts often requires changing to flexbox for proper control
## Release Process
### 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
**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 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)
- Assets (CSS, JS)
- Documentation (README, CHANGELOG, etc.)
### What's Excluded
- Git metadata (`.git/`)
- Development files (`.vscode/`, `.claude/`, `CLAUDE.md`)
- Logs and cache files
- Previous releases
- `composer.lock` (but `vendor/` is included)
## Testing Checklist
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
- [ ] Adding/removing tiers works
- [ ] Adding/removing packages works
- [ ] 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
- [ ] Restricted products hide quantity input
- [ ] "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
- [ ] Package quantities can't be edited if restricted
- [ ] Prices recalculate if quantity changed (non-restricted products)
- [ ] Checkout totals are correct
### WooCommerce Blocks (Critical!)
- [ ] Mini cart block doesn't throw fatal errors
- [ ] Cart block works correctly
- [ ] Checkout block processes orders
- [ ] Quantity editable flag works for blocks
## 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
#### CSS Specificity and WooCommerce Overrides
**CRITICAL LESSON from v1.2.4:** WooCommerce's core admin CSS uses high-specificity selectors that require `!important` to override.
**Problem Symptoms:**
- CSS rules not applying despite correct selectors
- Styles work in simple cases but fail with WooCommerce elements
- Browser DevTools shows rule crossed out or overridden
**Diagnostic Steps:**
1. Inspect element in browser DevTools
2. Check "Computed" tab to see which styles are actually applied
3. Look for crossed-out rules in "Styles" tab (indicates override)
4. Check selector specificity - WooCommerce often uses complex selectors
**Solution Patterns:**
**For Table Styling:**
```css
/* ❌ This will likely be overridden */
.wc-tpp-tiers-table {
border: none;
}
/* ✅ Use !important for core WooCommerce overrides */
.wc-tpp-tiers-table,
.wc-tpp-tiers-table th,
.wc-tpp-tiers-table td,
.wc-tpp-tiers-table thead,
.wc-tpp-tiers-table tbody,
.wc-tpp-tiers-table tr {
border: none !important;
}
/* ✅ Also use border-collapse to prevent cell borders */
.wc-tpp-tiers-table {
border-collapse: collapse !important;
}
```
**For Float-Based Layouts:**
```css
/* ❌ Float positioning is hard to control precisely */
.woocommerce-help-tip {
float: right;
margin-left: 10px;
}
/* ✅ Use flexbox for precise control */
label[for="_wc_tpp_restrict_to_packages"] {
display: inline-flex;
align-items: center;
gap: 0;
}
.woocommerce-help-tip {
float: none;
display: inline-block;
vertical-align: middle;
margin-left: 6px;
margin-right: 0;
}
```
**General Rules:**
1. **Always test in actual WordPress admin** - browser preview may not show WooCommerce's CSS
2. **Target all related elements** - tables require styling on `table`, `thead`, `tbody`, `tr`, `th`, `td`
3. **Use `!important` sparingly but don't fear it** - sometimes it's the only way to override WooCommerce core
4. **Prefer flexbox over floats** - gives better control over alignment and spacing
5. **Check across browsers** - table rendering can vary between Chrome/Firefox/Safari
**When Styles Don't Apply:**
- First verify selector is correct (DevTools should show rule, even if crossed out)
- If selector is correct but crossed out, increase specificity or add `!important`
- If selector doesn't appear at all, check file is enqueued and cache is cleared
- Use browser's "Inspect" right-click to see exact element structure
#### 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, v1.2.2, and v1.2.3 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.)
### Release Package Creation - Critical Notes
**IMPORTANT:** The zip command must be run from the **parent directory** to create proper archive structure.
**Correct command (from `/home/magdev/workspaces/php`):**
```bash
cd /home/magdev/workspaces/php
zip -r wc-tier-and-package-prices/releases/wc-tier-and-package-prices-X.X.X.zip wc-tier-and-package-prices/ \
-x '*/\.git/*' '*/.git/*' 'wc-tier-and-package-prices/.git/*' \
'*.gitignore' '*.log' '*/.claude/*' '*/CLAUDE.md' \
'*/releases/*' '*/wordpress/*' '*/node_modules/*' \
'*/.DS_Store' '*/Thumbs.db' '*/.vscode/*' '*/.idea/*' \
'*.sublime-*' '*/notes.*' '*/logs/*' '*/templates/cache/*' \
'*/composer.lock'
```
**Critical Exclusions:**
- `*/wordpress/*` - MUST be excluded! The project has a symlink to WordPress installation that zip will follow, creating 129MB+ packages instead of ~430KB
- `.git/*` - All git metadata (multiple patterns needed for reliability)
- `.claude/*` and `CLAUDE.md` - Development documentation
- `releases/*` - Prevents including previous releases in new ones
- `composer.lock` - Not needed in production (vendor/ is included)
**Expected Package Size:** ~430-431KB (383 files)
**Package Size Alert:** If >1MB, exclusions failed (likely wordpress symlink included)
**Verification Steps:**
```bash
# 1. Check size (should be ~430KB)
ls -lh releases/wc-tier-and-package-prices-X.X.X.zip
# 2. Verify file count (should be 383 files)
unzip -l releases/wc-tier-and-package-prices-X.X.X.zip | tail -1
# 3. Check for excluded files
unzip -l releases/wc-tier-and-package-prices-X.X.X.zip | grep -E "CLAUDE\.md|\.claude/|\.git/|wordpress/"
# Should return nothing (exit code 1)
# 4. Verify version in package
unzip -p releases/wc-tier-and-package-prices-X.X.X.zip wc-tier-and-package-prices/wc-tier-and-package-prices.php | head -30 | grep -E "Version:|WC_TPP_VERSION"
```
### 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.
##### Bugfixes (Completed in v1.2.4)
1. ~~Bug 1 in v1.2.3 is not fixed. Now both table display have border again. they shouldn't have border.~~**FIXED in v1.2.4** - Added `!important` flags and `border-collapse: collapse` to table CSS to override WooCommerce's default table styling. Added comprehensive border removal for all table elements (table, thead, tbody, tr, th, td) to ensure truly borderless tables across all browsers.
2. ~~Bug 2 in v1.2.3: Increase the margin between checkbox and label and put the help icon right next to the label, not at the right border~~**FIXED in v1.2.4** - Increased checkbox right margin from 8px to 12px. Repositioned help tip icon to display inline right next to the label text using flexbox layout with `display: inline-flex`, removing float positioning that caused it to appear at the right edge.
##### Planned Enhancements for v1.2.5+
1. Hide the table-headers in admin area until a tier or respectivly a package price is defined.
2. Make it possible to define tier or package prices on variable products in the parent product as a default for that product and all variants of it unless a variant has its own tier or package prices.
### 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
- Test with both simple products and variable products (if applicable)
- 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
4. Consider edge cases (guest checkout, logged-in users, AJAX add-to-cart, etc.)
## File Locations Quick Reference
| Task | File(s) |
| ------ | --------- |
| Change version | `wc-tier-and-package-prices.php` (2 places) |
| Add global setting | `includes/class-wc-tpp-settings.php` |
| Modify product meta box | `includes/class-wc-tpp-product-meta.php` + `templates/admin/*.twig` |
| Change product page display | `includes/class-wc-tpp-frontend.php` + `templates/frontend/*.twig` |
| Fix cart pricing | `includes/class-wc-tpp-cart.php` |
| Update styles | `assets/css/frontend.css` or `assets/css/admin.css` |
| Fix JavaScript bugs | `assets/js/frontend.js` or `assets/js/admin.js` |
| Add translations | `languages/*.po` then compile to `.mo` |
| Document changes | `CHANGELOG.md` |
## 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)
## Support & Resources
- **Repository:** <https://src.bundespruefstelle.ch/magdev/wc-tier-package-prices>
- **Documentation:** See `README.md`, `QUICKSTART.md`, `USAGE_EXAMPLES.md`, `INSTALLATION.md`
- **Changelog:** `CHANGELOG.md` (detailed version history)
- **Issue Tracking:** Check fatal-errors-*.log files for production errors
## 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
4. Be thoroughly tested before release
5. Include proper error handling and validation
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!

View File

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

View File

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

108
README.md
View File

@@ -1,5 +1,7 @@
# WooCommerce Tier and Package Prices
__THIS PROJECT IS 100% VIBE-CODED USING CLAUDE.AI__
A powerful WooCommerce plugin that adds tier pricing and package pricing functionality to your products with configurable quantities at fixed prices.
## Features
@@ -108,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
@@ -121,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
@@ -150,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
@@ -162,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

View File

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

View File

@@ -23,42 +23,63 @@
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 !important;
border-collapse: collapse !important;
}
.wc-tpp-tiers-table th,
.wc-tpp-packages-table th,
.wc-tpp-tiers-table td,
.wc-tpp-packages-table td {
border: none !important;
}
.wc-tpp-tiers-table th {
font-weight: 600;
text-align: left;
}
.wc-tpp-packages-table th {
font-weight: 600;
text-align: left;
}
.wc-tpp-tiers-table thead,
.wc-tpp-packages-table thead,
.wc-tpp-tiers-table tbody,
.wc-tpp-packages-table tbody,
.wc-tpp-tiers-table tr,
.wc-tpp-packages-table tr {
border: none !important;
}
/* 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 +110,46 @@
color: #666;
font-style: italic;
}
/* Hide table headers when there are no pricing rules */
.wc-tpp-tiers-container:empty ~ thead,
.wc-tpp-packages-container:empty ~ thead {
display: none;
}
/* Alternative approach: hide thead when tbody is empty (more reliable) */
.wc-tpp-tiers-table:has(tbody.wc-tpp-tiers-container:empty) thead,
.wc-tpp-packages-table:has(tbody.wc-tpp-packages-container:empty) thead {
display: none;
}
/* Checkbox styling improvements */
#_wc_tpp_restrict_to_packages,
input[id^="wc_tpp_restrict_to_packages_"] {
margin-right: 12px !important;
}
/* Position help tip icon right next to the label text */
.wc-tpp-tier-pricing .woocommerce-help-tip,
.wc-tpp-package-pricing .woocommerce-help-tip,
.wc-tpp-variation-pricing .woocommerce-help-tip {
margin-left: 6px;
margin-right: 0;
float: none;
display: inline-block;
vertical-align: middle;
}
/* Fix WooCommerce checkbox label layout for our checkboxes */
label[for="_wc_tpp_restrict_to_packages"],
label[for^="wc_tpp_restrict_to_packages_"] {
display: inline-flex;
align-items: center;
gap: 0;
}
/* Hide inline description text when tooltip is shown */
#_wc_tpp_restrict_to_packages + .description,
input[id^="wc_tpp_restrict_to_packages_"] + .description {
display: none;
}

View File

@@ -50,11 +50,13 @@
.wc-tpp-table tbody tr {
border-bottom: 1px solid #e0e0e0;
transition: background-color 0.2s;
transition: all 0.2s;
cursor: pointer;
}
.wc-tpp-table tbody tr:hover {
background: #f5f5f5;
transform: translateX(2px);
}
.wc-tpp-table tbody tr.wc-tpp-active-tier {
@@ -67,6 +69,14 @@
font-size: 0.95em;
}
.wc-tpp-tier-label {
display: inline-block;
margin-top: 4px;
color: #666;
font-style: italic;
font-size: 0.9em;
}
/* Package pricing */
.wc-tpp-packages {
display: grid;
@@ -156,6 +166,67 @@
font-style: italic;
}
/* Catalog "View Options" button */
a.wc-tpp-view-options {
display: inline-block;
text-align: center;
text-decoration: none;
position: relative;
/* Match WooCommerce button styling */
font-size: 1em;
font-weight: 700;
padding: 0.618em 1em;
line-height: 1.5;
border-radius: 3px;
cursor: pointer;
transition: all 0.2s ease;
}
a.wc-tpp-view-options::before {
content: "\f06e";
font-family: "dashicons";
margin-right: 5px;
display: inline-block;
font-size: 1em;
vertical-align: middle;
line-height: 1;
}
/* Hover state for View Options button */
a.wc-tpp-view-options:hover {
opacity: 0.85;
text-decoration: none;
}
/* Cart quantity display for restricted products */
.wc-tpp-cart-quantity {
display: inline-block;
padding: 5px 10px;
background: #f5f5f5;
border: 1px solid #ddd;
border-radius: 3px;
font-weight: 600;
}
/* Restriction notice */
.wc-tpp-restriction-notice {
padding: 10px 15px;
background: #fff3cd;
border: 1px solid #ffc107;
border-radius: 4px;
margin-bottom: 15px;
color: #856404;
font-size: 0.95em;
}
/* Disabled add to cart button */
.single_add_to_cart_button.disabled,
.single_add_to_cart_button:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
/* Responsive design */
@media (max-width: 768px) {
.wc-tpp-packages {

View File

@@ -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) {

View File

@@ -8,6 +8,7 @@
$(document).ready(function() {
const $quantityInput = $('input.qty');
const $priceDisplay = $('.woocommerce-Price-amount.amount').first();
const $addToCartButton = $('.single_add_to_cart_button');
const isRestrictedMode = $('.wc-tpp-package-pricing-table').hasClass('wc-tpp-restricted-mode');
if ($quantityInput.length === 0 && !isRestrictedMode) {
@@ -154,9 +155,35 @@
$('.wc-tpp-price-message').remove();
}
// Toggle add to cart button state based on quantity
function updateAddToCartButton() {
const quantity = parseInt($quantityInput.val()) || 0;
if (quantity <= 0) {
$addToCartButton.prop('disabled', true).addClass('disabled');
} else {
$addToCartButton.prop('disabled', false).removeClass('disabled');
}
}
// Handle quantity input changes
$quantityInput.on('input change', function() {
updatePriceDisplay();
updateAddToCartButton();
});
// Handle tier pricing row clicks
$('.wc-tpp-tier-pricing-table tbody tr').on('click', function() {
const minQty = parseInt($(this).data('min-qty'));
if ($quantityInput.length > 0 && !isRestrictedMode) {
$quantityInput.val(minQty).trigger('change');
// Scroll to quantity input for better UX
$('html, body').animate({
scrollTop: $quantityInput.offset().top - 100
}, 300);
}
});
// Handle package selection
@@ -212,6 +239,119 @@
if (!isRestrictedMode) {
updatePriceDisplay();
}
// Initial button state check
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);

View File

@@ -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.1",
"version": "1.2.5",
"type": "wordpress-plugin",
"license": "GPL-2.0-or-later",
"authors": [

View File

@@ -7,9 +7,20 @@ if (!defined('ABSPATH')) {
exit;
}
if (!class_exists('WC_TPP_Admin')) {
class WC_TPP_Admin {
public function __construct() {
private static $instance = null;
private static $settings_instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
add_filter('woocommerce_get_settings_pages', array($this, 'add_settings_page'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
@@ -18,7 +29,32 @@ class WC_TPP_Admin {
* Add settings page to WooCommerce settings
*/
public function add_settings_page($settings) {
$settings[] = include WC_TPP_PLUGIN_DIR . 'includes/class-wc-tpp-settings.php';
if (null === self::$settings_instance) {
require_once WC_TPP_PLUGIN_DIR . 'includes/class-wc-tpp-settings.php';
self::$settings_instance = new WC_TPP_Settings();
}
// Check if our settings page is already in the array to prevent duplicates
// Check by class type and ID instead of instance comparison
foreach ($settings as $settings_page) {
if ($settings_page instanceof WC_TPP_Settings) {
return $settings;
}
// Also check by ID property if it's a WC_Settings_Page
if (is_object($settings_page) &&
method_exists($settings_page, 'get_id') &&
$settings_page->get_id() === 'tier_package_prices') {
return $settings;
}
// Check id property directly
if (is_object($settings_page) &&
isset($settings_page->id) &&
$settings_page->id === 'tier_package_prices') {
return $settings;
}
}
$settings[] = self::$settings_instance;
return $settings;
}
@@ -30,4 +66,5 @@ class WC_TPP_Admin {
}
}
new WC_TPP_Admin();
WC_TPP_Admin::get_instance();
}

View File

@@ -7,6 +7,7 @@ if (!defined('ABSPATH')) {
exit;
}
if (!class_exists('WC_TPP_Cart')) {
class WC_TPP_Cart {
public function __construct() {
@@ -14,7 +15,12 @@ class WC_TPP_Cart {
add_filter('woocommerce_cart_item_price', array($this, 'display_cart_item_price'), 10, 3);
add_filter('woocommerce_cart_item_subtotal', array($this, 'display_cart_item_subtotal'), 10, 3);
add_filter('woocommerce_add_to_cart_validation', array($this, 'validate_package_quantity'), 10, 3);
add_filter('woocommerce_cart_item_quantity', array($this, 'maybe_hide_cart_quantity_input'), 10, 3);
add_filter('woocommerce_cart_item_quantity', array($this, 'maybe_hide_cart_quantity_input'), 999, 3);
add_filter('woocommerce_widget_cart_item_quantity', array($this, 'maybe_hide_mini_cart_quantity_input'), 999, 3);
add_action('wp_head', array($this, 'add_cart_quantity_css'));
// WooCommerce Blocks support
add_filter('woocommerce_store_api_product_quantity_editable', array($this, 'block_quantity_editable'), 10, 2);
}
public function apply_tier_package_pricing($cart) {
@@ -34,6 +40,8 @@ class 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'];
@@ -42,10 +50,10 @@ class WC_TPP_Cart {
continue;
}
// Check for exact package match first
// Check for exact package match first (pass product_id for parent fallback support)
$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($product_id, $quantity, $variation_id);
}
if ($package_price !== null) {
@@ -56,9 +64,9 @@ class 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 (pass product_id for parent fallback support)
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($product_id, $quantity, $variation_id);
if ($tier_price !== null) {
$product->set_price($tier_price);
// Store pricing information in cart item for display
@@ -93,18 +101,18 @@ class WC_TPP_Cart {
}
public function validate_package_quantity($passed, $product_id, $quantity) {
// Check if restriction is enabled globally or for this product
$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';
// Check for variation ID in request (for variable products)
$variation_id = isset($_REQUEST['variation_id']) ? absint($_REQUEST['variation_id']) : 0;
if (!$global_restrict && !$product_restrict) {
// Check if restriction is enabled (with parent fallback for variations)
if (!$this->is_restriction_enabled($product_id, $variation_id)) {
return $passed;
}
// Get packages for this product
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
// Get packages for this product/variation (with parent fallback)
$packages = $this->get_packages_with_fallback($product_id, $variation_id);
if (empty($packages) || !is_array($packages)) {
if (!$packages) {
return $passed;
}
@@ -141,21 +149,146 @@ class 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
$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';
// Get packages for this product
$packages = get_post_meta($product_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">%s</span>', $cart_item['quantity']);
// Check if restriction is enabled (with parent fallback) and packages exist
if ($this->is_restriction_enabled($product_id, $variation_id) && $this->get_packages_with_fallback($product_id, $variation_id)) {
return sprintf('<span class="wc-tpp-cart-quantity wc-tpp-restricted-qty" data-product-id="%d">%s</span>',
$effective_id,
$cart_item['quantity']
);
}
return $product_quantity;
}
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 (with parent fallback) and packages exist
if ($this->is_restriction_enabled($product_id, $variation_id) && $this->get_packages_with_fallback($product_id, $variation_id)) {
return sprintf('<span class="wc-tpp-cart-quantity wc-tpp-restricted-qty" data-product-id="%d">%s &times;</span>',
$effective_id,
$cart_item['quantity']
);
}
return $product_quantity;
}
public function add_cart_quantity_css() {
// Get all cart items and check which products have restrictions
if (!function_exists('WC') || !WC()->cart || is_admin()) {
return;
}
$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;
// Check if restriction is enabled (with parent fallback) and packages exist
if ($this->is_restriction_enabled($product_id, $variation_id) && $this->get_packages_with_fallback($product_id, $variation_id)) {
$restricted_products[] = $effective_id;
}
}
if (!empty($restricted_products)) {
echo '<style type="text/css">';
foreach ($restricted_products as $product_id) {
// Hide quantity inputs for restricted products in cart (classic cart)
echo '.cart_item .wc-tpp-restricted-qty[data-product-id="' . esc_attr($product_id) . '"] + .quantity,';
echo '.cart_item .wc-tpp-restricted-qty[data-product-id="' . esc_attr($product_id) . '"] ~ .quantity,';
echo '.woocommerce-mini-cart-item .wc-tpp-restricted-qty[data-product-id="' . esc_attr($product_id) . '"] + .quantity,';
echo '.woocommerce-mini-cart-item .wc-tpp-restricted-qty[data-product-id="' . esc_attr($product_id) . '"] ~ .quantity { display: none !important; }';
// Hide WooCommerce blocks quantity selector for restricted products
echo '.wc-block-cart-item[data-product-id="' . esc_attr($product_id) . '"] .wc-block-components-quantity-selector,';
echo '.wc-block-mini-cart__items .wc-block-cart-item[data-product-id="' . esc_attr($product_id) . '"] .wc-block-components-quantity-selector { display: none !important; }';
}
echo '</style>';
}
}
/**
* Make quantity non-editable for restricted products in WooCommerce blocks
*
* @param bool $editable Whether the quantity is editable
* @param WC_Product $product Product object (can be variation)
* @return bool
*/
public function block_quantity_editable($editable, $product) {
// Validate product object
if (!$product || !is_a($product, 'WC_Product')) {
return $editable;
}
$product_id = $product->get_id();
if (!$product_id) {
return $editable;
}
// For variations, get parent product ID and variation ID
$variation_id = 0;
$parent_id = $product_id;
if ($product->is_type('variation')) {
$variation_id = $product_id;
$parent_id = $product->get_parent_id();
}
// Check if restriction is enabled (with parent fallback) and packages exist
if ($this->is_restriction_enabled($parent_id, $variation_id) && $this->get_packages_with_fallback($parent_id, $variation_id)) {
return false;
}
return $editable;
}
/**
* Get packages with parent fallback for variations
*
* @param int $product_id Parent product ID
* @param int $variation_id Variation ID (0 for simple products)
* @return array|false Packages array or false if none found
*/
private function get_packages_with_fallback($product_id, $variation_id = 0) {
$effective_id = $variation_id > 0 ? $variation_id : $product_id;
$packages = get_post_meta($effective_id, '_wc_tpp_packages', true);
// Fall back to parent pricing if variation doesn't have its own pricing
if ((empty($packages) || !is_array($packages)) && $variation_id > 0) {
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
}
return (!empty($packages) && is_array($packages)) ? $packages : false;
}
/**
* Check if restriction is enabled for a product/variation with parent fallback
*
* @param int $product_id Parent product ID
* @param int $variation_id Variation ID (0 for simple products)
* @return bool Whether restriction is enabled
*/
private function is_restriction_enabled($product_id, $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($effective_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
// Fall back to parent restriction setting if variation doesn't have its own
if (!$product_restrict && $variation_id > 0) {
$product_restrict = get_post_meta($product_id, '_wc_tpp_restrict_to_packages', true) === 'yes';
}
return $global_restrict || $product_restrict;
}
}
new WC_TPP_Cart();
}

View File

@@ -7,6 +7,7 @@ if (!defined('ABSPATH')) {
exit;
}
if (!class_exists('WC_TPP_Frontend')) {
class WC_TPP_Frontend {
public function __construct() {
@@ -15,15 +16,29 @@ class WC_TPP_Frontend {
add_action('woocommerce_after_add_to_cart_button', array($this, 'display_pricing_table_after'), 10);
add_action('woocommerce_single_product_summary', array($this, 'display_pricing_table_after_price'), 15);
add_action('woocommerce_before_add_to_cart_quantity', array($this, 'maybe_hide_quantity_input'));
// 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() {
if (is_product()) {
// Enqueue CSS on all WooCommerce pages (for catalog buttons and cart)
if (is_woocommerce() || is_cart() || is_checkout() || is_product()) {
wp_enqueue_style('wc-tpp-frontend', WC_TPP_PLUGIN_URL . 'assets/css/frontend.css', array(), WC_TPP_VERSION);
}
// Enqueue JS only on product pages
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()),
@@ -58,6 +73,11 @@ class 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';
@@ -76,6 +96,13 @@ class 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);
@@ -94,8 +121,22 @@ class WC_TPP_Frontend {
));
}
public static function get_tier_price($product_id, $quantity) {
/**
* 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);
// Fall back to parent pricing if variation doesn't have its own pricing
if ((empty($tiers) || !is_array($tiers)) && $variation_id > 0) {
$tiers = get_post_meta($product_id, '_wc_tpp_tiers', true);
}
if (empty($tiers) || !is_array($tiers)) {
return null;
@@ -111,8 +152,22 @@ class WC_TPP_Frontend {
return $applicable_price;
}
public static function get_package_price($product_id, $quantity) {
/**
* 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);
// Fall back to parent pricing if variation doesn't have its own pricing
if ((empty($packages) || !is_array($packages)) && $variation_id > 0) {
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
}
if (empty($packages) || !is_array($packages)) {
return null;
@@ -126,6 +181,127 @@ class WC_TPP_Frontend {
return null;
}
/**
* Check if a product has quantity restrictions enabled
*
* @param int $product_id Product ID
* @return bool
*/
public static function has_quantity_restriction($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);
return ($global_restrict || $product_restrict) && !empty($packages);
}
/**
* Modify catalog add to cart button for products with quantity restrictions
*
* @param string $html Add to cart button HTML
* @param WC_Product $product Product object
* @return string Modified HTML
*/
public function modify_catalog_add_to_cart_button($html, $product) {
if (!$product || !is_a($product, 'WC_Product')) {
return $html;
}
$product_id = $product->get_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;
}
// Replace add to cart button with "View Options" link
$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 %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();
}

View File

@@ -7,12 +7,18 @@ if (!defined('ABSPATH')) {
exit;
}
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() {
@@ -24,7 +30,16 @@ class 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">
<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)) {
@@ -35,7 +50,8 @@ class WC_TPP_Product_Meta {
$this->render_tier_row($index, $tier);
}
?>
</div>
</tbody>
</table>
<p class="form-field">
<button type="button" class="button wc-tpp-add-tier"><?php _e('Add Tier', 'wc-tier-package-prices'); ?></button>
@@ -53,7 +69,16 @@ class 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">
<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)) {
@@ -64,7 +89,8 @@ class WC_TPP_Product_Meta {
$this->render_package_row($index, $package);
}
?>
</div>
</tbody>
</table>
<p class="form-field">
<button type="button" class="button wc-tpp-add-package"><?php _e('Add Package', 'wc-tier-package-prices'); ?></button>
@@ -81,7 +107,7 @@ class WC_TPP_Product_Meta {
</div>
<script type="text/html" id="wc-tpp-tier-row-template">
<?php $this->render_tier_row('{{INDEX}}', array('min_qty' => '', 'price' => '')); ?>
<?php $this->render_tier_row('{{INDEX}}', array('min_qty' => '', 'price' => '', 'label' => '')); ?>
</script>
<script type="text/html" id="wc-tpp-package-row-template">
@@ -104,6 +130,136 @@ class 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')) {
@@ -127,7 +283,8 @@ class WC_TPP_Product_Meta {
if (!empty($tier['min_qty']) && !empty($tier['price'])) {
$tiers[] = array(
'min_qty' => absint($tier['min_qty']),
'price' => wc_format_decimal($tier['price'])
'price' => wc_format_decimal($tier['price']),
'label' => sanitize_text_field($tier['label'] ?? '')
);
}
}
@@ -165,6 +322,69 @@ class 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();
}

View File

@@ -18,6 +18,7 @@ if (!class_exists('WC_Settings_Page')) {
/**
* WC_TPP_Settings class
*/
if (!class_exists('WC_TPP_Settings')) {
class WC_TPP_Settings extends WC_Settings_Page {
/**
@@ -139,5 +140,4 @@ class WC_TPP_Settings extends WC_Settings_Page {
WC_Admin_Settings::save_fields($settings);
}
}
return new WC_TPP_Settings();
}

Binary file not shown.

View 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)"

View File

@@ -3,7 +3,7 @@
# This file is distributed under the GPL v2 or later.
msgid ""
msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.1\n"
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
@@ -235,3 +235,25 @@ 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ö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)"

View File

@@ -3,7 +3,7 @@
# This file is distributed under the GPL v2 or later.
msgid ""
msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.1\n"
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
@@ -235,3 +235,25 @@ 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öß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.

View 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)"

View File

@@ -3,7 +3,7 @@
# This file is distributed under the GPL v2 or later.
msgid ""
msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.1\n"
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
@@ -235,3 +235,25 @@ msgstr "this product"
#: 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 "The quantity %1$d is not available for %2$s. Please choose from the available package sizes: %3$s"
#: includes/class-wc-tpp-frontend.php:173
msgid "View Options"
msgstr "View Options"
#: 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)"

Binary file not shown.

View 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)"

Binary file not shown.

View 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)"

View File

@@ -2,7 +2,7 @@
# This file is distributed under the GPL v2 or later.
msgid ""
msgstr ""
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.1\n"
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.6\n"
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
"MIME-Version: 1.0\n"
@@ -222,3 +222,11 @@ msgstr ""
#: 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 ""
#: includes/class-wc-tpp-frontend.php:173
msgid "View Options"
msgstr ""
#: includes/class-wc-tpp-frontend.php:178
msgid "View options for %s"
msgstr ""

View File

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

View File

@@ -1,127 +0,0 @@
# WooCommerce Tier and Package Prices - Release 1.0.1
**Release Date:** December 21, 2025
**Version:** 1.0.1
**Package Size:** 395 KB
**Git Tag:** v1.0.1
## Download
**File:** `wc-tier-and-package-prices-1.0.1.zip`
### Checksums
**SHA256:**
```
92c1385d92527e77646e37f23c1bd1555a4290a5ec9314c0ee6ed896ded55e88
```
**MD5:**
```
e6cfc9b88df9e7763be0cd56517ce8ab
```
## Installation
1. Download the ZIP file: `wc-tier-and-package-prices-1.0.1.zip`
2. Log in to your WordPress admin panel
3. Navigate to **Plugins > Add New > Upload Plugin**
4. Choose the downloaded ZIP file
5. Click **Install Now**
6. After installation, click **Activate Plugin**
### Requirements
- **WordPress:** 6.0 or higher
- **PHP:** 7.4 or higher
- **WooCommerce:** 8.0 or higher
## What's New in 1.0.1
### New Features
-**Twig Template Engine** - Modern template system with automatic escaping
-**Swiss German Translation** - Added de_CH_informal translation
-**Template Caching** - Improved performance with compiled templates
-**Composer Integration** - Professional dependency management
### Improvements
- 🔄 Migrated all templates from PHP to Twig format
- 🔒 Enhanced security with automatic HTML escaping
- 📁 Better template organization (admin/ and frontend/ directories)
- 🎨 Cleaner separation of logic and presentation
### Technical Changes
- Added Twig v3.22.2 dependency
- Created WC_TPP_Template_Loader class for centralized rendering
- Integrated WordPress functions (__(), wc_price(), etc.) into Twig
- Optimized autoloader for production
- Removed legacy PHP templates
## Package Contents
The installation package includes:
### Core Files
- `wc-tier-and-package-prices.php` - Main plugin file
- `composer.json` - Dependency configuration
- `CHANGELOG.md` - Full version history
- `README.md` - Plugin documentation
### Directories
- `includes/` - PHP class files
- `class-wc-tpp-admin.php`
- `class-wc-tpp-cart.php`
- `class-wc-tpp-frontend.php`
- `class-wc-tpp-product-meta.php`
- `class-wc-tpp-template-loader.php`
- `templates/` - Twig template files
- `admin/` - Admin interface templates
- `frontend/` - Customer-facing templates
- `languages/` - Translation files
- de_CH_informal (Swiss German, Informal)
- de_DE (German, Germany)
- en_US (English, US)
- `assets/` - CSS and JavaScript files
- `vendor/` - Composer dependencies (Twig)
## Translations Included
1. **English (US)** - en_US ✅
2. **German (Germany)** - de_DE ✅
3. **German (Switzerland, Informal)** - de_CH_informal ✅ NEW!
## Features
### Tier Pricing
- Quantity-based discount tiers
- Automatic price calculation
- Volume discount display
### Package Pricing
- Fixed-price bundles
- Custom package labels
- Multiple package options per product
### Admin Features
- Easy-to-use product meta boxes
- Configurable display positions
- Settings page for global options
### Frontend Features
- Beautiful pricing tables
- Real-time cart updates
- Responsive design
## Support
- **Documentation:** See README.md and USAGE_EXAMPLES.md
- **Issues:** https://src.bundespruefstelle.ch/wc-tier-package-prices/issues
- **Author:** Marco Graetsch
## License
GPL v2 or later - https://www.gnu.org/licenses/gpl-2.0.html
---
**Note:** This is a production-ready package with optimized autoloader and no development dependencies.

View File

@@ -1,198 +0,0 @@
# WooCommerce Tier and Package Prices - Release 1.0.2
**Release Date:** December 21, 2025
**Version:** 1.0.2
**Package Size:** 396 KB
**Git Tag:** v1.0.2
## Download
**File:** `wc-tier-and-package-prices-1.0.2.zip`
### Checksums
**SHA256:**
```
c1a5339da10b3625156b8fff4ec848e4a1318d6edc497bd5026cfe0a3ef39daa
```
**MD5:**
```
830f443ce4b65e2ca9cfede3257bc4f5
```
## What's New in 1.0.2
### Major Changes
-**Settings Migrated to WooCommerce Settings Page**
- Settings now appear as a dedicated tab: **WooCommerce > Settings > Tier & Package Prices**
- Removed standalone submenu for better integration
- Consistent UI with native WooCommerce settings
### Improvements
- 🔄 Uses WooCommerce's native settings API (WC_Settings_Page)
- 🎨 Better integration with WooCommerce admin interface
- 💾 Automatic settings persistence via WooCommerce
- 🌍 Updated all translations with new settings strings
### New Features
- ✨ WC_TPP_Settings class for proper WooCommerce integration
- 📝 9 new translatable strings in all languages
- 🔧 Enhanced tooltips and descriptions for better UX
### Technical Changes
- Implemented `woocommerce_get_settings_pages` filter hook
- Uses `WC_Admin_Settings` for rendering and saving
- Removed custom Twig settings template
- Updated all translation files to version 1.0.2
### Removed
- ❌ Standalone settings submenu (WooCommerce > Tier & Package Prices)
- ❌ Custom settings template (templates/admin/settings-page.twig)
## Installation
1. Download the ZIP file: `wc-tier-and-package-prices-1.0.2.zip`
2. Log in to your WordPress admin panel
3. Navigate to **Plugins > Add New > Upload Plugin**
4. Choose the downloaded ZIP file
5. Click **Install Now**
6. After installation, click **Activate Plugin**
7. Go to **WooCommerce > Settings > Tier & Package Prices** to configure
### Upgrade from 1.0.1
This is a **minor update** with improved settings integration. No data migration needed.
**Steps:**
1. Deactivate the current version
2. Upload and activate version 1.0.2
3. Your existing settings will be automatically preserved
4. Settings location changed: Now under **WooCommerce > Settings** tab
### Requirements
- **WordPress:** 6.0 or higher
- **PHP:** 7.4 or higher
- **WooCommerce:** 8.0 or higher
## Translation Updates
All translation files updated with new strings:
### New Translations (9 new strings)
1. "General" - Settings section
2. "Tier & Package Prices Settings" - Section title
3. "Configure tier pricing and package pricing options..." - Description
4. "Allow quantity-based pricing tiers..." - Tooltip
5. "Allow fixed-price packages..." - Tooltip
6. "Display the pricing table to customers..." - Tooltip
7. "Choose where to display the pricing table..." - Description
8. "Before Add to Cart Button" - Option
9. "After Add to Cart Button" - Option
### Languages Included
- 🇺🇸 **English (US)** - en_US - Fully updated
- 🇩🇪 **German (Germany)** - de_DE - Fully updated (formal "Sie")
- 🇨🇭 **German (Switzerland, Informal)** - de_CH_informal - Fully updated (informal "du")
## Package Contents
The installation package includes:
### Core Files
- `wc-tier-and-package-prices.php` (v1.0.2)
- `composer.json` - Updated to 1.0.2
- `CHANGELOG.md` - Full version history
### New/Modified Files
- `includes/class-wc-tpp-settings.php` ✨ NEW
- `includes/class-wc-tpp-admin.php` - Updated
- All translation files (.po/.mo) - Updated
### Complete Directory Structure
```
wc-tier-and-package-prices/
├── assets/ # CSS and JavaScript
│ ├── css/
│ └── js/
├── includes/ # PHP classes
│ ├── class-wc-tpp-admin.php
│ ├── class-wc-tpp-cart.php
│ ├── class-wc-tpp-frontend.php
│ ├── class-wc-tpp-product-meta.php
│ ├── class-wc-tpp-settings.php ✨ NEW
│ └── class-wc-tpp-template-loader.php
├── languages/ # Translation files (all updated)
│ ├── wc-tier-package-prices-de_CH_informal.po/mo
│ ├── wc-tier-package-prices-de_DE.po/mo
│ ├── wc-tier-package-prices-en_US.po/mo
│ └── wc-tier-package-prices.pot
├── templates/ # Twig templates
│ ├── admin/
│ │ ├── package-row.twig
│ │ └── tier-row.twig
│ └── frontend/
│ ├── package-pricing-display.twig
│ ├── pricing-table.twig
│ └── tier-pricing-table.twig
├── vendor/ # Composer dependencies
│ └── twig/twig/ (v3.22.2)
├── CHANGELOG.md
├── README.md
└── composer.json
```
## Features (Complete List)
### Tier Pricing
- ✅ Quantity-based discount tiers
- ✅ Automatic price calculation
- ✅ Volume discount display
### Package Pricing
- ✅ Fixed-price bundles
- ✅ Custom package labels
- ✅ Multiple package options per product
### Admin Features
-**WooCommerce Settings integration** (NEW in 1.0.2)
- ✅ Easy-to-use product meta boxes
- ✅ Configurable display positions
- ✅ Native WooCommerce UI
### Frontend Features
- ✅ Beautiful pricing tables (Twig templates)
- ✅ Real-time cart updates
- ✅ Responsive design
- ✅ 3 languages supported
## Migration Notes
### Settings Location Changed
**Old Location:** WooCommerce > Tier & Package Prices
**New Location:** WooCommerce > Settings > Tier & Package Prices
All your existing settings are automatically preserved and will appear in the new location.
### Benefits of New Location
1. ✅ Better discoverability - users expect settings under Settings
2. ✅ Consistent with WooCommerce patterns
3. ✅ Native WooCommerce UI/UX
4. ✅ Better mobile support
5. ✅ Follows WordPress/WooCommerce best practices
## Support
- **Documentation:** See README.md and USAGE_EXAMPLES.md
- **Changelog:** See CHANGELOG.md for detailed changes
- **Issues:** https://src.bundespruefstelle.ch/wc-tier-package-prices/issues
- **Author:** Marco Graetsch
## License
GPL v2 or later - https://www.gnu.org/licenses/gpl-2.0.html
---
**Production Ready:** This package includes optimized autoloader and no development dependencies.

View File

@@ -1,345 +0,0 @@
# WooCommerce Tier and Package Prices - Release 1.1.0
**Release Date:** December 21, 2025
**Version:** 1.1.0
**Package Size:** 387 KB
**Git Tag:** v1.1.0
## Download
**File:** `wc-tier-and-package-prices-1.1.0.zip`
### Checksums
**SHA256:**
```
da6b462f3dc297b282ed0da258b78fd9f2f82f3e76289c4c8fadd1ac9e02c55b
```
**MD5:**
```
ef68125c54b0c10f04ba82d48a98b4aa
```
## What's New in 1.1.0
### Major Features
-**Package Quantity Restriction** - NEW
- Limit product purchases to predefined package sizes only
- Perfect for bulk-only sales, sample packs, or fixed bundle quantities
- Global and per-product configuration options
### New Settings
- 🌍 **Global Restriction Setting**
- Enable quantity restrictions site-wide
- Located in: WooCommerce > Settings > Tier & Package Prices
- Description: "Limit quantities to defined package sizes only"
- 📦 **Per-Product Restriction Setting**
- Override global setting on individual products
- Located in: Product Edit > Package Pricing section
- Checkbox: "Restrict to Package Quantities"
### Frontend Enhancements
- 🎨 **Enhanced Package Selection UI**
- Automatic quantity field hiding when restriction is enabled
- Clear notice: "Choose a package size below"
- Visual package selection with highlighted states
- Responsive package selection buttons
-**Client-Side Validation**
- JavaScript prevents form submission without package selection
- Alert message guides users to select a package
- Real-time visual feedback on selection
### Backend Validation
- 🛡️ **Server-Side Cart Validation**
- Validates quantity matches defined packages
- Prevents manual quantity manipulation
- User-friendly error messages
- Example: "The quantity 15 is not available for Product Name. Please choose from the available package sizes: 10, 20, 50"
### Technical Improvements
- New method: `WC_TPP_Cart::validate_package_quantity()`
- New method: `WC_TPP_Frontend::maybe_hide_quantity_input()`
- Enhanced `woocommerce_add_to_cart_validation` filter integration
- Added `wc-tpp-restricted-mode` CSS class
- Added `wc-tpp-package-selectable` CSS class for styling
- New product meta key: `_wc_tpp_restrict_to_packages`
- New global option: `wc_tpp_restrict_package_quantities`
### Translations
- Added 7 new translatable strings
- Updated all language files (en_US, de_DE, de_CH_informal)
- All .mo files recompiled with new strings
## Installation
1. Download the ZIP file: `wc-tier-and-package-prices-1.1.0.zip`
2. Log in to your WordPress admin panel
3. Navigate to **Plugins > Add New > Upload Plugin**
4. Choose the downloaded ZIP file
5. Click **Install Now**
6. After installation, click **Activate Plugin**
7. Go to **WooCommerce > Settings > Tier & Package Prices** to configure
### Upgrade from 1.0.x
This is a **minor version** update with new features. No data migration needed.
**Steps:**
1. Deactivate the current version
2. Upload and activate version 1.1.0
3. All existing settings and data will be automatically preserved
4. Review new restriction settings if desired
### Upgrade from 1.0.2
No breaking changes. Safe to upgrade directly. New restriction feature is disabled by default.
### Requirements
- **WordPress:** 6.0 or higher
- **PHP:** 7.4 or higher
- **WooCommerce:** 8.0 or higher
## New Strings Translation Reference
All new strings in this release:
### Settings Page
1. "Restrict to Package Quantities" - Checkbox label
2. "Limit quantities to defined package sizes only" - Checkbox description
3. "When enabled, customers can only purchase..." - Tooltip text
### Product Meta Box
4. "Restrict to Package Quantities" - Checkbox label (same as above)
5. "Only allow quantities defined in packages above" - Tooltip text
### Frontend Display
6. "Choose a package size below" - User notice in restricted mode
### Cart Validation
7. "this product" - Fallback product name
8. "The quantity %1$d is not available for %2$s..." - Error message template
## Use Cases
### Bulk-Only Sales
Enable restriction globally to sell products only in bulk quantities.
**Example:**
- Package 1: 100 units at $500
- Package 2: 250 units at $1,100
- Package 3: 500 units at $2,000
Customers can only purchase these exact quantities.
### Sample Packs
Create fixed sample packs with no custom quantities.
**Example:**
- Starter Pack: 10 items
- Trial Pack: 25 items
- Full Pack: 50 items
### Promotional Bundles
Offer promotional pricing only for specific bundle sizes.
**Example:**
- Holiday Bundle: 12 units (seasonal pricing)
- Party Pack: 24 units (bulk discount)
- Wholesale Bundle: 100 units (wholesale pricing)
## Configuration Examples
### Example 1: Site-Wide Restriction
**Scenario:** All products should only be sold in packages
**Configuration:**
1. Go to WooCommerce > Settings > Tier & Package Prices
2. Check "Restrict to Package Quantities"
3. Save changes
4. Configure package sizes for each product
**Result:** All products with packages defined will enforce quantity restrictions
### Example 2: Per-Product Restriction
**Scenario:** Only specific products need quantity restrictions
**Configuration:**
1. Leave global setting unchecked
2. Edit the specific product
3. Scroll to Package Pricing section
4. Check "Restrict to Package Quantities"
5. Update product
**Result:** Only that product enforces restrictions
### Example 3: Mixed Approach
**Scenario:** Most products are restricted, but some allow custom quantities
**Configuration:**
1. Enable global restriction
2. For products that should allow custom quantities, simply don't define any packages
3. Products without packages defined won't show restrictions
## Feature Compatibility
### Works With
- ✅ WooCommerce 8.0 - 10.0
- ✅ WordPress 6.0+
- ✅ HPOS (High-Performance Order Storage)
- ✅ All WooCommerce themes
- ✅ Tier pricing (can use both features together)
- ✅ Package pricing (required for restriction)
- ✅ All pricing table display positions
### Requirements for Restriction Feature
- Product must have at least one package defined
- Either global or per-product restriction must be enabled
- Package pricing must be enabled in settings
## Package Contents
The installation package includes all files from version 1.0.2 plus:
### Modified Files
- `wc-tier-and-package-prices.php` - Version updated to 1.1.0
- `composer.json` - Version updated to 1.1.0
- `CHANGELOG.md` - Added v1.1.0 section
- `includes/class-wc-tpp-settings.php` - Added restriction setting
- `includes/class-wc-tpp-product-meta.php` - Added per-product checkbox
- `includes/class-wc-tpp-frontend.php` - Added quantity hiding logic
- `includes/class-wc-tpp-cart.php` - Added validation method
- `assets/js/frontend.js` - Added restricted mode handling
- `templates/frontend/package-pricing-display.twig` - Added restriction notice
- `templates/frontend/pricing-table.twig` - Pass restriction flag
- All translation files (.po/.mo) - Updated with new strings
### Complete Directory Structure
```
wc-tier-and-package-prices/
├── assets/
│ ├── css/
│ │ ├── admin.css
│ │ └── frontend.css
│ └── js/
│ ├── admin.js
│ └── frontend.js (UPDATED)
├── includes/
│ ├── class-wc-tpp-admin.php
│ ├── class-wc-tpp-cart.php (UPDATED)
│ ├── class-wc-tpp-frontend.php (UPDATED)
│ ├── class-wc-tpp-product-meta.php (UPDATED)
│ ├── class-wc-tpp-settings.php (UPDATED)
│ └── class-wc-tpp-template-loader.php
├── languages/ (ALL UPDATED)
│ ├── wc-tier-package-prices-de_CH_informal.po/mo
│ ├── wc-tier-package-prices-de_DE.po/mo
│ ├── wc-tier-package-prices-en_US.po/mo
│ └── wc-tier-package-prices.pot
├── templates/
│ ├── admin/
│ │ ├── package-row.twig
│ │ └── tier-row.twig
│ └── frontend/
│ ├── package-pricing-display.twig (UPDATED)
│ ├── pricing-table.twig (UPDATED)
│ └── tier-pricing-table.twig
├── vendor/ (Twig v3.22.2)
├── CHANGELOG.md (UPDATED)
├── composer.json (UPDATED)
└── wc-tier-and-package-prices.php (UPDATED)
```
## Features (Complete List)
### Tier Pricing
- ✅ Quantity-based discount tiers
- ✅ Automatic price calculation
- ✅ Volume discount display
### Package Pricing
- ✅ Fixed-price bundles
- ✅ Custom package labels
- ✅ Multiple package options per product
-**NEW:** Quantity restriction to packages only
### Admin Features
- ✅ WooCommerce Settings integration
- ✅ Easy-to-use product meta boxes
- ✅ Configurable display positions
- ✅ Native WooCommerce UI
-**NEW:** Global restriction setting
-**NEW:** Per-product restriction override
### Frontend Features
- ✅ Beautiful pricing tables (Twig templates)
- ✅ Real-time cart updates
- ✅ Responsive design
- ✅ 3 languages supported
-**NEW:** Package-only selection mode
-**NEW:** Automatic quantity field hiding
-**NEW:** Visual package selection
### Validation & Security
-**NEW:** Client-side JavaScript validation
-**NEW:** Server-side cart validation
-**NEW:** User-friendly error messages
- ✅ WooCommerce HPOS compatible
## Breaking Changes
**None.** This release is fully backward compatible.
The new restriction feature is disabled by default and must be explicitly enabled.
## Migration Notes
### From 1.0.2
- No migration needed
- New settings appear automatically in admin
- Feature is disabled by default
### Settings Location
All settings remain in: **WooCommerce > Settings > Tier & Package Prices**
### Data Preservation
- All existing tier pricing data preserved
- All existing package pricing data preserved
- All product meta data preserved
- No database changes required
## Known Limitations
### Current Version
1. Restriction only works when packages are defined
2. Cannot restrict to tier quantities (only packages)
3. Restriction applies to entire product (no variation-level control)
### Future Enhancements
These features may be added in future versions:
- Variation-level restriction control
- Restrict to tier quantities option
- Minimum/maximum package selection limits
## Support
- **Documentation:** See README.md and CHANGELOG.md
- **Previous Release:** See RELEASE-INFO-1.0.2.md
- **Issues:** https://src.bundespruefstelle.ch/wc-tier-package-prices/issues
- **Author:** Marco Graetsch
## License
GPL v2 or later - https://www.gnu.org/licenses/gpl-2.0.html
---
**Production Ready:** This package includes optimized autoloader and no development dependencies.
**What's Next:** Version 1.1.0 completes the package restriction feature set. Future versions may add variation-level controls and tier quantity restrictions.

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

View File

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

Binary file not shown.

View File

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

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