You've already forked wc-tier-and-package-prices
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d721ab123a | |||
| dfe1a4364a | |||
| 9b7638a7e2 | |||
| db9ba2bacd | |||
| e46372da51 | |||
| 2b2c06794b | |||
| 959229b9d8 | |||
| f0ab2ff755 | |||
| 4dd9b3cd62 | |||
| 9dab123209 | |||
| 3f117ae519 | |||
| 58bbd5164f | |||
| cfdbfe1504 | |||
| e4e4de82cb | |||
| af532b56eb | |||
| e2a11de80a | |||
| e40830b69b | |||
| 9765c5f119 | |||
| 5cfabedb94 | |||
| 88e30d028c | |||
| d55ada7924 | |||
| 4ece4dd69e | |||
| 3e06137559 |
@@ -8,7 +8,17 @@
|
|||||||
"Bash(composer init:*)",
|
"Bash(composer init:*)",
|
||||||
"Bash(composer install:*)",
|
"Bash(composer install:*)",
|
||||||
"Bash(composer update:*)",
|
"Bash(composer update:*)",
|
||||||
"Bash(git add:*)"
|
"Bash(git add:*)",
|
||||||
|
"Bash(git tag:*)",
|
||||||
|
"Bash(rsync:*)",
|
||||||
|
"Bash(zip -r:*)",
|
||||||
|
"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:*)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -21,6 +21,10 @@ npm-debug.log
|
|||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
/logs
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
notes.*
|
||||||
|
|
||||||
# OS
|
# OS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
362
CHANGELOG.md
362
CHANGELOG.md
@@ -5,6 +5,368 @@ All notable changes to WooCommerce Tier and Package Prices will be documented in
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.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
|
||||||
|
- Cart quantity field hiding when package restriction is enabled
|
||||||
|
- Automatic read-only quantity display in cart for restricted products
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Cart quantity input replaced with plain text when restrictions apply
|
||||||
|
- Enhanced cart display to prevent quantity modification for restricted products
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Cart quantity bypass vulnerability for package-restricted products
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
- Added `maybe_hide_cart_quantity_input()` method in WC_TPP_Cart class
|
||||||
|
- Extended `woocommerce_cart_item_quantity` filter hook
|
||||||
|
- CSS class `wc-tpp-cart-quantity` for styled quantity display
|
||||||
|
|
||||||
## [1.1.0] - 2025-12-21
|
## [1.1.0] - 2025-12-21
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
429
CLAUDE.md
Normal file
429
CLAUDE.md
Normal file
@@ -0,0 +1,429 @@
|
|||||||
|
# WooCommerce Tier and Package Prices - AI Context Document
|
||||||
|
|
||||||
|
**Last Updated:** 2025-12-23
|
||||||
|
**Current Version:** 1.1.20
|
||||||
|
**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
|
||||||
|
```
|
||||||
|
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`
|
||||||
|
|
||||||
|
## 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)
|
||||||
|
```
|
||||||
|
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
|
||||||
|
|
||||||
|
## 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
|
||||||
|
```bash
|
||||||
|
# From project root
|
||||||
|
cd releases
|
||||||
|
|
||||||
|
# Create zip excluding dev files
|
||||||
|
zip -r wc-tier-and-package-prices-X.X.X.zip .. \
|
||||||
|
-x '*.git*' '*.log' '.claude/*' 'releases/*' 'node_modules/*' \
|
||||||
|
'.DS_Store' 'Thumbs.db' '.vscode/*' '.idea/*' '*.sublime-*' \
|
||||||
|
'notes.*' 'logs/*' 'templates/cache/*' 'composer.lock'
|
||||||
|
|
||||||
|
# Generate checksums
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
**IMPORTANT:** The `vendor/` directory MUST be included in releases (Twig dependency required for runtime).
|
||||||
|
|
||||||
|
### 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/`, `.idea/`)
|
||||||
|
- 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
|
||||||
|
|
||||||
|
### 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!
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
# WooCommerce Tier and Package Prices
|
# 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.
|
A powerful WooCommerce plugin that adds tier pricing and package pricing functionality to your products with configurable quantities at fixed prices.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|||||||
@@ -50,11 +50,13 @@
|
|||||||
|
|
||||||
.wc-tpp-table tbody tr {
|
.wc-tpp-table tbody tr {
|
||||||
border-bottom: 1px solid #e0e0e0;
|
border-bottom: 1px solid #e0e0e0;
|
||||||
transition: background-color 0.2s;
|
transition: all 0.2s;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wc-tpp-table tbody tr:hover {
|
.wc-tpp-table tbody tr:hover {
|
||||||
background: #f5f5f5;
|
background: #f5f5f5;
|
||||||
|
transform: translateX(2px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.wc-tpp-table tbody tr.wc-tpp-active-tier {
|
.wc-tpp-table tbody tr.wc-tpp-active-tier {
|
||||||
@@ -67,6 +69,14 @@
|
|||||||
font-size: 0.95em;
|
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 */
|
/* Package pricing */
|
||||||
.wc-tpp-packages {
|
.wc-tpp-packages {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -156,6 +166,67 @@
|
|||||||
font-style: italic;
|
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 */
|
/* Responsive design */
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.wc-tpp-packages {
|
.wc-tpp-packages {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
const $quantityInput = $('input.qty');
|
const $quantityInput = $('input.qty');
|
||||||
const $priceDisplay = $('.woocommerce-Price-amount.amount').first();
|
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');
|
const isRestrictedMode = $('.wc-tpp-package-pricing-table').hasClass('wc-tpp-restricted-mode');
|
||||||
|
|
||||||
if ($quantityInput.length === 0 && !isRestrictedMode) {
|
if ($quantityInput.length === 0 && !isRestrictedMode) {
|
||||||
@@ -154,9 +155,35 @@
|
|||||||
$('.wc-tpp-price-message').remove();
|
$('.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
|
// Handle quantity input changes
|
||||||
$quantityInput.on('input change', function() {
|
$quantityInput.on('input change', function() {
|
||||||
updatePriceDisplay();
|
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
|
// Handle package selection
|
||||||
@@ -212,6 +239,11 @@
|
|||||||
if (!isRestrictedMode) {
|
if (!isRestrictedMode) {
|
||||||
updatePriceDisplay();
|
updatePriceDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initial button state check
|
||||||
|
if ($quantityInput.length > 0 && $addToCartButton.length > 0) {
|
||||||
|
updateAddToCartButton();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "magdev/wc-tier-package-prices",
|
"name": "magdev/wc-tier-package-prices",
|
||||||
"description": "WooCommerce plugin for tier pricing and package prices with Twig templates",
|
"description": "WooCommerce plugin for tier pricing and package prices with Twig templates",
|
||||||
"version": "1.1.0",
|
"version": "1.1.19",
|
||||||
"type": "wordpress-plugin",
|
"type": "wordpress-plugin",
|
||||||
"license": "GPL-2.0-or-later",
|
"license": "GPL-2.0-or-later",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|||||||
@@ -7,9 +7,20 @@ if (!defined('ABSPATH')) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
class WC_TPP_Admin {
|
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_filter('woocommerce_get_settings_pages', array($this, 'add_settings_page'));
|
||||||
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
|
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
|
||||||
}
|
}
|
||||||
@@ -18,7 +29,32 @@ class WC_TPP_Admin {
|
|||||||
* Add settings page to WooCommerce settings
|
* Add settings page to WooCommerce settings
|
||||||
*/
|
*/
|
||||||
public function add_settings_page($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;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,4 +66,5 @@ class WC_TPP_Admin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new WC_TPP_Admin();
|
WC_TPP_Admin::get_instance();
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,13 +7,20 @@ if (!defined('ABSPATH')) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
class WC_TPP_Cart {
|
if (!class_exists('WC_TPP_Cart')) {
|
||||||
|
class WC_TPP_Cart {
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
add_action('woocommerce_before_calculate_totals', array($this, 'apply_tier_package_pricing'), 10, 1);
|
add_action('woocommerce_before_calculate_totals', array($this, 'apply_tier_package_pricing'), 10, 1);
|
||||||
add_filter('woocommerce_cart_item_price', array($this, 'display_cart_item_price'), 10, 3);
|
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_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_add_to_cart_validation', array($this, 'validate_package_quantity'), 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) {
|
public function apply_tier_package_pricing($cart) {
|
||||||
@@ -137,6 +144,115 @@ class WC_TPP_Cart {
|
|||||||
|
|
||||||
return $passed;
|
return $passed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function maybe_hide_cart_quantity_input($product_quantity, $cart_item_key, $cart_item) {
|
||||||
|
$product_id = $cart_item['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 wc-tpp-restricted-qty" data-product-id="%d">%s</span>',
|
||||||
|
$product_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'];
|
||||||
|
|
||||||
|
// 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 wc-tpp-restricted-qty" data-product-id="%d">%s ×</span>',
|
||||||
|
$product_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'];
|
||||||
|
$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);
|
||||||
|
|
||||||
|
if (($global_restrict || $product_restrict) && !empty($packages)) {
|
||||||
|
$restricted_products[] = $product_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
|
||||||
|
* @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;
|
||||||
|
}
|
||||||
|
|
||||||
|
$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);
|
||||||
|
|
||||||
|
// If restriction is enabled and packages exist, make quantity non-editable
|
||||||
|
if (($global_restrict || $product_restrict) && !empty($packages)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $editable;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new WC_TPP_Cart();
|
new WC_TPP_Cart();
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ if (!defined('ABSPATH')) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
class WC_TPP_Frontend {
|
if (!class_exists('WC_TPP_Frontend')) {
|
||||||
|
class WC_TPP_Frontend {
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
|
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
|
||||||
@@ -15,11 +16,19 @@ class WC_TPP_Frontend {
|
|||||||
add_action('woocommerce_after_add_to_cart_button', array($this, 'display_pricing_table_after'), 10);
|
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_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'));
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function enqueue_scripts() {
|
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);
|
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);
|
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
|
||||||
@@ -126,6 +135,54 @@ class WC_TPP_Frontend {
|
|||||||
|
|
||||||
return null;
|
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();
|
||||||
|
|
||||||
|
// Check if product has quantity restrictions
|
||||||
|
if (!self::has_quantity_restriction($product_id)) {
|
||||||
|
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');
|
||||||
|
|
||||||
|
$new_html = sprintf(
|
||||||
|
'<a href="%s" class="button wc-tpp-view-options product_type_simple" aria-label="%s">%s</a>',
|
||||||
|
$product_url,
|
||||||
|
esc_attr(sprintf(__('View options for %s', 'wc-tier-package-prices'), $product->get_name())),
|
||||||
|
$button_text
|
||||||
|
);
|
||||||
|
|
||||||
|
return $new_html;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new WC_TPP_Frontend();
|
new WC_TPP_Frontend();
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ if (!defined('ABSPATH')) {
|
|||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
class WC_TPP_Product_Meta {
|
if (!class_exists('WC_TPP_Product_Meta')) {
|
||||||
|
class WC_TPP_Product_Meta {
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
add_action('woocommerce_product_options_pricing', array($this, 'add_tier_pricing_fields'));
|
add_action('woocommerce_product_options_pricing', array($this, 'add_tier_pricing_fields'));
|
||||||
@@ -81,7 +82,7 @@ class WC_TPP_Product_Meta {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="text/html" id="wc-tpp-tier-row-template">
|
<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>
|
||||||
|
|
||||||
<script type="text/html" id="wc-tpp-package-row-template">
|
<script type="text/html" id="wc-tpp-package-row-template">
|
||||||
@@ -127,7 +128,8 @@ class WC_TPP_Product_Meta {
|
|||||||
if (!empty($tier['min_qty']) && !empty($tier['price'])) {
|
if (!empty($tier['min_qty']) && !empty($tier['price'])) {
|
||||||
$tiers[] = array(
|
$tiers[] = array(
|
||||||
'min_qty' => absint($tier['min_qty']),
|
'min_qty' => absint($tier['min_qty']),
|
||||||
'price' => wc_format_decimal($tier['price'])
|
'price' => wc_format_decimal($tier['price']),
|
||||||
|
'label' => sanitize_text_field($tier['label'] ?? '')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -168,3 +170,4 @@ class WC_TPP_Product_Meta {
|
|||||||
}
|
}
|
||||||
|
|
||||||
new WC_TPP_Product_Meta();
|
new WC_TPP_Product_Meta();
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ if (!class_exists('WC_Settings_Page')) {
|
|||||||
/**
|
/**
|
||||||
* WC_TPP_Settings class
|
* WC_TPP_Settings class
|
||||||
*/
|
*/
|
||||||
class WC_TPP_Settings extends WC_Settings_Page {
|
if (!class_exists('WC_TPP_Settings')) {
|
||||||
|
class WC_TPP_Settings extends WC_Settings_Page {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@@ -139,5 +140,4 @@ class WC_TPP_Settings extends WC_Settings_Page {
|
|||||||
WC_Admin_Settings::save_fields($settings);
|
WC_Admin_Settings::save_fields($settings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return new WC_TPP_Settings();
|
|
||||||
|
|||||||
Binary file not shown.
@@ -3,7 +3,7 @@
|
|||||||
# This file is distributed under the GPL v2 or later.
|
# This file is distributed under the GPL v2 or later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.0\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"
|
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||||
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
||||||
@@ -235,3 +235,11 @@ msgstr "dieses Produkt"
|
|||||||
#: includes/class-wc-tpp-cart.php:128
|
#: 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"
|
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"
|
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-frontend.php:178
|
||||||
|
msgid "View options for %s"
|
||||||
|
msgstr "Optionen für %s ansehen"
|
||||||
|
|||||||
Binary file not shown.
@@ -3,7 +3,7 @@
|
|||||||
# This file is distributed under the GPL v2 or later.
|
# This file is distributed under the GPL v2 or later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.0\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"
|
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||||
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
||||||
@@ -235,3 +235,11 @@ msgstr "dieses Produkt"
|
|||||||
#: includes/class-wc-tpp-cart.php:128
|
#: 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"
|
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"
|
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-frontend.php:178
|
||||||
|
msgid "View options for %s"
|
||||||
|
msgstr "Optionen für %s ansehen"
|
||||||
|
|||||||
Binary file not shown.
@@ -3,7 +3,7 @@
|
|||||||
# This file is distributed under the GPL v2 or later.
|
# This file is distributed under the GPL v2 or later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.0\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"
|
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||||
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
||||||
@@ -235,3 +235,11 @@ msgstr "this product"
|
|||||||
#: includes/class-wc-tpp-cart.php:128
|
#: 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"
|
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"
|
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-frontend.php:178
|
||||||
|
msgid "View options for %s"
|
||||||
|
msgstr "View options for %s"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# This file is distributed under the GPL v2 or later.
|
# This file is distributed under the GPL v2 or later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.1.0\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"
|
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
@@ -222,3 +222,11 @@ msgstr ""
|
|||||||
#: includes/class-wc-tpp-cart.php:128
|
#: 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"
|
msgid "The quantity %1$d is not available for %2$s. Please choose from the available package sizes: %3$s"
|
||||||
msgstr ""
|
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 ""
|
||||||
|
|||||||
@@ -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.
|
|
||||||
@@ -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.
|
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.0.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.0.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.0.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.0.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ef68125c54b0c10f04ba82d48a98b4aa wc-tier-and-package-prices-1.1.0.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.0.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.0.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
da6b462f3dc297b282ed0da258b78fd9f2f82f3e76289c4c8fadd1ac9e02c55b wc-tier-and-package-prices-1.1.0.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.1.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.1.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.1.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.1.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
51c4f8a7c3ccede2d2005f2fe3ebe44e wc-tier-and-package-prices-1.1.1.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.1.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.1.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
b951f8b7ddd2bad6b3415d4583709fdf88f66aea4eae70110c903757ff53e045 wc-tier-and-package-prices-1.1.1.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.10.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.10.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.10.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.10.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
81be5283219cfa722f6d382a788e7dc1 releases/wc-tier-and-package-prices-1.1.10.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.10.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.10.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2d3b01e61c8a03a8f20bc99b2019ca50fa08ecd68188feb2d2105dfe35d36f0d releases/wc-tier-and-package-prices-1.1.10.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.11.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.11.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.11.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.11.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4a0c0b07b29d4b7046f9d3ff3f091321 releases/wc-tier-and-package-prices-1.1.11.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.11.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.11.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3da9423d136a2ff254b61577ba1f84d4c0f0d1e57bae361ac29c90327feeeceb releases/wc-tier-and-package-prices-1.1.11.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.12.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.12.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.12.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.12.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
c1c0b5880636686227246be2c37dc42a releases/wc-tier-and-package-prices-1.1.12.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.12.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.12.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
05b32356d46803dbb7fa17c13a2d8da96f77126746e2895e2f5c6dd0e7b490ff releases/wc-tier-and-package-prices-1.1.12.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.13.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.13.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.13.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.13.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8572eed399554905fbf331d18f0677a0 wc-tier-and-package-prices-1.1.13.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.13.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.13.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
83e29b2e40dd43e77bd83cd03d4ccc54ef53555b55544eba4d38161101f79f20 wc-tier-and-package-prices-1.1.13.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.14.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.14.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.14.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.14.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
e0cc51d1493ed35ab254220d9f46997b wc-tier-and-package-prices-1.1.14.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.14.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.14.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8a2ce7438ee49baffdcaaf323b6426d73dd1cf704bea94a80fcce27a42c097ad wc-tier-and-package-prices-1.1.14.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.15.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.15.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.15.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.15.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
15fa0e0933c85b23f66940bf43810835 wc-tier-and-package-prices-1.1.15.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.15.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.15.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
a419579111ad20b127411e1078ca99187156d606381549e6bf147ffc3bd58de1 wc-tier-and-package-prices-1.1.15.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.16.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.16.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.16.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.16.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
d30a90715dbcd46a1dfd19f025897530 wc-tier-and-package-prices-1.1.16.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.16.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.16.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
e2ad36e049a902b8e287154867ef72c0e169766508781e223176a2a753b60915 wc-tier-and-package-prices-1.1.16.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.17.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.17.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.17.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.17.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
9adbb9aad13b8d141cfabfdf53643480 wc-tier-and-package-prices-1.1.17.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.17.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.17.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
985a195bf98d4dbc0a7afa90173efcda472f4c769adf3c833fa6a99ba9d44095 wc-tier-and-package-prices-1.1.17.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.18.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.18.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.18.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.18.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ec4bb1d78a3c27488244b44971916ffd wc-tier-and-package-prices-1.1.18.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.18.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.18.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
7d942002edd866c2b6f3192ba010fe64058b7433c5ac776a48e9c3c41f4e2fda wc-tier-and-package-prices-1.1.18.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.19.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.19.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.19.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.19.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
c61c3a059429d8dacdce71d4acce401e wc-tier-and-package-prices-1.1.19.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.19.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.19.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0e8bc4ccd233d388238e800cd0e0a129f9e8da14008e7164db7934a48ca8223a wc-tier-and-package-prices-1.1.19.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.2.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.2.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.2.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.2.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
eee69fcf391b3f3df9380306ffb31b1b wc-tier-and-package-prices-1.1.2.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.2.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.2.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
40ffd29ebc6af635f689472040acd220ae1c8df2f0d852fab4b43ce0fb5fe739 wc-tier-and-package-prices-1.1.2.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.20.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.20.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.20.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.20.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
bfdeee75bfe3795c9ab9abfe47f12a41 wc-tier-and-package-prices-1.1.20.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.20.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.20.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
953859241d15d76ec4783c72bac851ddd69e5a1f7b119ee4f9ebd30c7fabed17 wc-tier-and-package-prices-1.1.20.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.3.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.3.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.3.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.3.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dfec91be7e375b09613ba81cfebbe013 wc-tier-and-package-prices-1.1.3.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.3.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.3.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
7938542680b71a7b73269c96a4dff78f2222ac8409092011c5e40e97a5e465aa wc-tier-and-package-prices-1.1.3.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.4.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.4.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.4.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.4.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3e5bc2cae17ecb81b729c3fdc979df23 wc-tier-and-package-prices-1.1.4.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.4.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.4.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
19553b2fed1c6ca20a8168eab8c570cb0302be801322cd41d86cec40b70ff162 wc-tier-and-package-prices-1.1.4.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.5.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.5.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.5.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.5.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
e9f8a69e4be107d857d3beb671d5a9fe wc-tier-and-package-prices-1.1.5.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.5.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.5.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
a13d71f3f65c7cf41613f88d7bcfcb112acfefb800fa6b95932f44a47cf764f3 wc-tier-and-package-prices-1.1.5.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.6.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.6.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.6.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.6.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
dbea10acffdc849f9aa387d128cb6d6e wc-tier-and-package-prices-1.1.6.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.6.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.6.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
730e366764449ac963bc85848ac8a91f654e4b35500ed3132a280ab4f215c80c wc-tier-and-package-prices-1.1.6.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.7.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.7.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.7.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.7.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
c593b6fc730133ecaf772f77d5659080 wc-tier-and-package-prices-1.1.7.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.7.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.7.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
00e7c473a8b0fc23eb1cd52f4b38db030618ed142a9a9fdfd9b1aa4c5849ec70 wc-tier-and-package-prices-1.1.7.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.8.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.8.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.8.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.8.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
666e1acad9f349982463b65d0e3e7fa3 wc-tier-and-package-prices-1.1.8.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.8.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.8.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
2c100d0d100a6fd7bd8f9c9b154d878a675bc795c5fddb19314bc9991b9a60ba wc-tier-and-package-prices-1.1.8.zip
|
||||||
BIN
releases/wc-tier-and-package-prices-1.1.9.zip
Normal file
BIN
releases/wc-tier-and-package-prices-1.1.9.zip
Normal file
Binary file not shown.
1
releases/wc-tier-and-package-prices-1.1.9.zip.md5
Normal file
1
releases/wc-tier-and-package-prices-1.1.9.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
7421aceb8d1cc89b7d15b19d68cdfabe wc-tier-and-package-prices-1.1.9.zip
|
||||||
1
releases/wc-tier-and-package-prices-1.1.9.zip.sha256
Normal file
1
releases/wc-tier-and-package-prices-1.1.9.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8224bf8b9bfc3dc760d77c61700d27c31db1a67b70834d8b6a4581df66fd45bd wc-tier-and-package-prices-1.1.9.zip
|
||||||
@@ -24,5 +24,13 @@
|
|||||||
placeholder="{{ 'e.g., 9.99'|__('wc-tier-package-prices') }}"
|
placeholder="{{ 'e.g., 9.99'|__('wc-tier-package-prices') }}"
|
||||||
class="short wc_input_price">
|
class="short wc_input_price">
|
||||||
</p>
|
</p>
|
||||||
|
<p class="form-field">
|
||||||
|
<label>{{ 'Label (Optional)'|__('wc-tier-package-prices') }}</label>
|
||||||
|
<input type="text"
|
||||||
|
name="_wc_tpp_tiers[{{ index|esc_attr }}][label]"
|
||||||
|
value="{{ tier.label|default('')|esc_attr }}"
|
||||||
|
placeholder="{{ 'e.g., Wholesale'|__('wc-tier-package-prices') }}"
|
||||||
|
class="short">
|
||||||
|
</p>
|
||||||
<button type="button" class="button wc-tpp-remove-tier">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
<button type="button" class="button wc-tpp-remove-tier">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -25,7 +25,12 @@
|
|||||||
{% set savings_percent = (savings / regular_price) * 100 %}
|
{% set savings_percent = (savings / regular_price) * 100 %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<tr data-min-qty="{{ tier.min_qty|esc_attr }}" data-price="{{ tier.price|esc_attr }}">
|
<tr data-min-qty="{{ tier.min_qty|esc_attr }}" data-price="{{ tier.price|esc_attr }}">
|
||||||
<td>{{ tier.min_qty|esc_html }}+</td>
|
<td>
|
||||||
|
{{ tier.min_qty|esc_html }}+
|
||||||
|
{% if tier.label is defined and tier.label is not empty %}
|
||||||
|
<br><small class="wc-tpp-tier-label">{{ tier.label|esc_html }}</small>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
<td>{{ wc_price(tier.price)|raw }}</td>
|
<td>{{ wc_price(tier.price)|raw }}</td>
|
||||||
<td>
|
<td>
|
||||||
{% if savings > 0 %}
|
{% if savings > 0 %}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Plugin Name: WooCommerce Tier and Package Prices
|
* Plugin Name: WooCommerce Tier and Package Prices
|
||||||
* Plugin URI: https://src.bundespruefstelle.ch/wc-tier-package-prices
|
* Plugin URI: https://src.bundespruefstelle.ch/magdev/wc-tier-package-prices
|
||||||
* Description: Add tier pricing and package prices to WooCommerce products with configurable quantities at fixed prices
|
* Description: Add tier pricing and package prices to WooCommerce products with configurable quantities at fixed prices
|
||||||
* Version: 1.1.0
|
* Version: 1.1.20
|
||||||
* Author: Marco Graetsch
|
* Author: Marco Graetsch
|
||||||
* Author URI: https://src.bundespruefstelle.ch/magdev
|
* Author URI: https://src.bundespruefstelle.ch/magdev
|
||||||
* Text Domain: wc-tier-package-prices
|
* Text Domain: wc-tier-package-prices
|
||||||
@@ -22,14 +22,35 @@ if (!defined('ABSPATH')) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Define plugin constants
|
// Define plugin constants
|
||||||
define('WC_TPP_VERSION', '1.1.0');
|
if (!defined('WC_TPP_VERSION')) {
|
||||||
define('WC_TPP_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
define('WC_TPP_VERSION', '1.1.20');
|
||||||
define('WC_TPP_PLUGIN_URL', plugin_dir_url(__FILE__));
|
}
|
||||||
define('WC_TPP_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
if (!defined('WC_TPP_PLUGIN_DIR')) {
|
||||||
|
define('WC_TPP_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||||
|
}
|
||||||
|
if (!defined('WC_TPP_PLUGIN_URL')) {
|
||||||
|
define('WC_TPP_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||||
|
}
|
||||||
|
if (!defined('WC_TPP_PLUGIN_BASENAME')) {
|
||||||
|
define('WC_TPP_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
||||||
|
}
|
||||||
|
|
||||||
// Load Composer autoloader
|
// Load Composer autoloader
|
||||||
require_once WC_TPP_PLUGIN_DIR . 'vendor/autoload.php';
|
require_once WC_TPP_PLUGIN_DIR . 'vendor/autoload.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display WooCommerce missing notice
|
||||||
|
*/
|
||||||
|
if (!function_exists('wc_tpp_woocommerce_missing_notice')) {
|
||||||
|
function wc_tpp_woocommerce_missing_notice() {
|
||||||
|
?>
|
||||||
|
<div class="notice notice-error">
|
||||||
|
<p><?php _e('WooCommerce Tier and Package Prices requires WooCommerce to be installed and active.', 'wc-tier-package-prices'); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if WooCommerce is active
|
* Check if WooCommerce is active
|
||||||
*/
|
*/
|
||||||
@@ -38,18 +59,11 @@ if (!in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
function wc_tpp_woocommerce_missing_notice() {
|
|
||||||
?>
|
|
||||||
<div class="notice notice-error">
|
|
||||||
<p><?php _e('WooCommerce Tier and Package Prices requires WooCommerce to be installed and active.', 'wc-tier-package-prices'); ?></p>
|
|
||||||
</div>
|
|
||||||
<?php
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main plugin class
|
* Main plugin class
|
||||||
*/
|
*/
|
||||||
class WC_Tier_Package_Prices {
|
if (!class_exists('WC_Tier_Package_Prices')) {
|
||||||
|
class WC_Tier_Package_Prices {
|
||||||
|
|
||||||
private static $instance = null;
|
private static $instance = null;
|
||||||
|
|
||||||
@@ -101,11 +115,14 @@ class WC_Tier_Package_Prices {
|
|||||||
public function deactivate() {
|
public function deactivate() {
|
||||||
flush_rewrite_rules();
|
flush_rewrite_rules();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the plugin
|
// Initialize the plugin
|
||||||
function wc_tpp_init() {
|
if (!function_exists('wc_tpp_init')) {
|
||||||
|
function wc_tpp_init() {
|
||||||
return WC_Tier_Package_Prices::get_instance();
|
return WC_Tier_Package_Prices::get_instance();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_action('plugins_loaded', 'wc_tpp_init', 11);
|
add_action('plugins_loaded', 'wc_tpp_init', 11);
|
||||||
|
|||||||
Reference in New Issue
Block a user