You've already forked wc-tier-and-package-prices
Release version 1.0.1
- Add Twig template engine integration - Migrate all templates to Twig format - Add German (Switzerland, Informal) translation - Improve template organization and security - Add Composer dependency management - Create comprehensive changelog
This commit is contained in:
11
.claude/settings.local.json
Normal file
11
.claude/settings.local.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(unzip:*)",
|
||||
"Bash(msgfmt:*)",
|
||||
"Bash(ls:*)",
|
||||
"Bash(mkdir:*)",
|
||||
"Bash(composer init:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
27
.gitignore
vendored
Normal file
27
.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
# WordPress
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Composer
|
||||
/vendor/
|
||||
composer.lock
|
||||
|
||||
# Twig cache
|
||||
/templates/cache/
|
||||
|
||||
# IDE
|
||||
.vscode/
|
||||
.idea/
|
||||
*.sublime-project
|
||||
*.sublime-workspace
|
||||
|
||||
# Node
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
._*
|
||||
55
CHANGELOG.md
Normal file
55
CHANGELOG.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to WooCommerce Tier and Package Prices will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.0.1] - 2025-12-21
|
||||
|
||||
### Added
|
||||
- Twig template engine integration for all templates
|
||||
- Template loader class with WordPress integration
|
||||
- German (Switzerland, Informal) translation (de_CH_informal)
|
||||
- Composer dependency management
|
||||
- Comprehensive translation support in Twig templates
|
||||
- Template caching support (disabled in debug mode)
|
||||
|
||||
### Changed
|
||||
- Migrated all PHP templates to Twig format (.twig)
|
||||
- Improved template organization and separation of concerns
|
||||
- Enhanced security with automatic HTML escaping in templates
|
||||
- Updated composer.json with complete package metadata
|
||||
|
||||
### Removed
|
||||
- Old PHP template files (replaced with Twig)
|
||||
|
||||
### Technical
|
||||
- Added Twig v3.22.2 dependency
|
||||
- Created WC_TPP_Template_Loader class for centralized template rendering
|
||||
- Integrated WordPress functions (__(), _e(), esc_*, wc_price()) into Twig
|
||||
- Added Swiss German localization with informal address form
|
||||
- Organized templates into admin/ and frontend/ directories
|
||||
|
||||
## [1.0.0] - 2025-12-21
|
||||
|
||||
### Added
|
||||
- Initial release
|
||||
- Tier pricing functionality (quantity-based discounts)
|
||||
- Package pricing functionality (fixed-price bundles)
|
||||
- Admin settings page for plugin configuration
|
||||
- Product meta boxes for configuring tier and package prices
|
||||
- Frontend pricing tables display
|
||||
- Cart integration for automatic price calculation
|
||||
- WooCommerce HPOS compatibility
|
||||
- Multilingual support with text domain
|
||||
- German (Germany) translation (de_DE)
|
||||
- English (US) translation (en_US)
|
||||
|
||||
### Features
|
||||
- Volume discounts based on quantity thresholds
|
||||
- Fixed-price packages with custom labels
|
||||
- Configurable display positions (before/after cart button, after price)
|
||||
- Real-time price updates in cart
|
||||
- Responsive pricing tables
|
||||
- Admin-friendly interface for price management
|
||||
188
INSTALLATION.md
Normal file
188
INSTALLATION.md
Normal file
@@ -0,0 +1,188 @@
|
||||
# Installation Guide
|
||||
|
||||
## Quick Installation
|
||||
|
||||
### Method 1: WordPress Admin Upload (Recommended)
|
||||
|
||||
1. Download `wc-tier-and-package-prices.zip` from the releases
|
||||
2. Log in to your WordPress admin dashboard
|
||||
3. Navigate to **Plugins > Add New**
|
||||
4. Click **Upload Plugin** button at the top
|
||||
5. Click **Choose File** and select `wc-tier-and-package-prices.zip`
|
||||
6. Click **Install Now**
|
||||
7. After installation, click **Activate Plugin**
|
||||
8. You're done! The plugin is now active.
|
||||
|
||||
### Method 2: Manual FTP Upload
|
||||
|
||||
1. Download `wc-tier-and-package-prices.zip`
|
||||
2. Extract the ZIP file to get the `wc-tier-and-package-prices` folder
|
||||
3. Connect to your server via FTP
|
||||
4. Upload the entire `wc-tier-and-package-prices` folder to `/wp-content/plugins/`
|
||||
5. Go to your WordPress admin dashboard
|
||||
6. Navigate to **Plugins**
|
||||
7. Find "WooCommerce Tier and Package Prices" and click **Activate**
|
||||
|
||||
### Method 3: WP-CLI
|
||||
|
||||
If you have WP-CLI installed:
|
||||
|
||||
```bash
|
||||
wp plugin install wc-tier-and-package-prices.zip --activate
|
||||
```
|
||||
|
||||
## Post-Installation Setup
|
||||
|
||||
### 1. Verify Installation
|
||||
|
||||
After activation, you should see:
|
||||
- A new menu item: **WooCommerce > Tier & Package Prices**
|
||||
- No error messages
|
||||
- Plugin listed in **Plugins** page
|
||||
|
||||
### 2. Configure Global Settings
|
||||
|
||||
1. Go to **WooCommerce > Tier & Package Prices**
|
||||
2. Configure the following options:
|
||||
- **Enable Tier Pricing**: ✓ (checked)
|
||||
- **Enable Package Pricing**: ✓ (checked)
|
||||
- **Display Pricing Table**: ✓ (checked)
|
||||
- **Display Position**: Choose where to show pricing tables
|
||||
- Before Add to Cart (recommended)
|
||||
- After Add to Cart
|
||||
- After Price
|
||||
3. Click **Save Changes**
|
||||
|
||||
### 3. Configure Your First Product
|
||||
|
||||
1. Go to **Products** and edit any product (or create new one)
|
||||
2. Scroll to **Product data** panel
|
||||
3. Click the **General** tab
|
||||
4. Scroll down to find the pricing sections
|
||||
|
||||
#### Add Tier Pricing (Volume Discounts)
|
||||
|
||||
1. Click **Add Tier** button
|
||||
2. Example configuration:
|
||||
- Min Quantity: `10`, Price: `9.50`
|
||||
- Min Quantity: `25`, Price: `8.50`
|
||||
- Min Quantity: `50`, Price: `7.50`
|
||||
3. Click **Update** to save
|
||||
|
||||
#### Add Package Pricing (Fixed Packages)
|
||||
|
||||
1. Click **Add Package** button
|
||||
2. Example configuration:
|
||||
- Quantity: `12`, Price: `99.00`, Label: "Dozen Pack"
|
||||
- Quantity: `24`, Price: `180.00`, Label: "Double Pack"
|
||||
3. Click **Update** to save
|
||||
|
||||
### 4. Test on Frontend
|
||||
|
||||
1. Visit your product page on the frontend
|
||||
2. You should see:
|
||||
- Pricing table showing tiers and/or packages
|
||||
- Price updates when changing quantity
|
||||
- Package selection buttons (if packages configured)
|
||||
3. Add to cart and verify correct pricing
|
||||
|
||||
## Requirements Check
|
||||
|
||||
Before installation, verify:
|
||||
|
||||
- ✓ WordPress 5.8 or higher
|
||||
- ✓ WooCommerce 5.0 or higher installed and activated
|
||||
- ✓ PHP 7.4 or higher
|
||||
- ✓ Write permissions in `/wp-content/plugins/` directory
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin Won't Activate
|
||||
|
||||
**Error: "WooCommerce is required"**
|
||||
- Solution: Install and activate WooCommerce first
|
||||
|
||||
**Error: "Parse error" or "Syntax error"**
|
||||
- Solution: Your PHP version is too old. Upgrade to PHP 7.4 or higher
|
||||
|
||||
### Pricing Tables Not Showing
|
||||
|
||||
1. Check global settings are enabled (**WooCommerce > Tier & Package Prices**)
|
||||
2. Verify you added tiers/packages to the specific product
|
||||
3. Clear browser cache and reload the page
|
||||
4. Check theme compatibility (try default WordPress theme)
|
||||
|
||||
### Prices Not Calculating Correctly
|
||||
|
||||
1. Make sure tiers are sorted by minimum quantity (plugin does this automatically)
|
||||
2. Verify package quantities exactly match what customer selects
|
||||
3. Clear WooCommerce caches (**WooCommerce > Status > Tools > Clear template cache**)
|
||||
|
||||
### Styling Issues
|
||||
|
||||
1. Clear browser cache
|
||||
2. Check if theme has conflicting CSS
|
||||
3. Try adding custom CSS in **Appearance > Customize > Additional CSS**
|
||||
|
||||
## Uninstallation
|
||||
|
||||
To completely remove the plugin:
|
||||
|
||||
1. Go to **Plugins** page
|
||||
2. Deactivate "WooCommerce Tier and Package Prices"
|
||||
3. Click **Delete**
|
||||
4. Confirm deletion
|
||||
|
||||
**Note:** Product meta data (tiers and packages) will be preserved in database even after uninstallation. If you reinstall, your configurations will still be there.
|
||||
|
||||
To completely remove all data:
|
||||
1. Before uninstalling, remove all tiers and packages from products
|
||||
2. Then proceed with uninstallation
|
||||
|
||||
## File Structure After Installation
|
||||
|
||||
Your WordPress installation should have:
|
||||
|
||||
```
|
||||
wp-content/
|
||||
└── plugins/
|
||||
└── wc-tier-and-package-prices/
|
||||
├── wc-tier-and-package-prices.php (main file)
|
||||
├── README.md
|
||||
├── INSTALLATION.md
|
||||
├── USAGE_EXAMPLES.md
|
||||
├── includes/
|
||||
│ ├── class-wc-tpp-admin.php
|
||||
│ ├── class-wc-tpp-cart.php
|
||||
│ ├── class-wc-tpp-frontend.php
|
||||
│ └── class-wc-tpp-product-meta.php
|
||||
└── assets/
|
||||
├── css/
|
||||
│ ├── admin.css
|
||||
│ └── frontend.css
|
||||
└── js/
|
||||
├── admin.js
|
||||
└── frontend.js
|
||||
```
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you encounter issues:
|
||||
|
||||
1. Check this installation guide
|
||||
2. Review the [README.md](README.md) for feature documentation
|
||||
3. Review [USAGE_EXAMPLES.md](USAGE_EXAMPLES.md) for configuration examples
|
||||
4. Check WordPress error logs
|
||||
5. Enable WP_DEBUG to see detailed errors
|
||||
|
||||
## Next Steps
|
||||
|
||||
After successful installation:
|
||||
|
||||
1. Read [USAGE_EXAMPLES.md](USAGE_EXAMPLES.md) for practical examples
|
||||
2. Configure tier pricing on your products
|
||||
3. Test the complete checkout flow
|
||||
4. Customize display settings to match your theme
|
||||
5. Consider creating package deals for popular quantities
|
||||
|
||||
Enjoy your new tier and package pricing capabilities!
|
||||
97
QUICKSTART.md
Normal file
97
QUICKSTART.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Quick Start Guide
|
||||
|
||||
Get started with WooCommerce Tier and Package Prices in 5 minutes!
|
||||
|
||||
## Step 1: Install (2 minutes)
|
||||
|
||||
1. Go to **Plugins > Add New** in WordPress
|
||||
2. Click **Upload Plugin**
|
||||
3. Choose `wc-tier-and-package-prices.zip`
|
||||
4. Click **Install Now** then **Activate**
|
||||
|
||||
✓ Done! Plugin is active.
|
||||
|
||||
## Step 2: Basic Setup (1 minute)
|
||||
|
||||
1. Go to **WooCommerce > Tier & Package Prices**
|
||||
2. Make sure all checkboxes are checked:
|
||||
- ✓ Enable Tier Pricing
|
||||
- ✓ Enable Package Pricing
|
||||
- ✓ Display Pricing Table
|
||||
3. Set Display Position to **Before Add to Cart**
|
||||
4. Click **Save Changes**
|
||||
|
||||
## Step 3: Add Pricing to a Product (2 minutes)
|
||||
|
||||
### Example: Selling T-Shirts
|
||||
|
||||
1. Edit a product (or create new one)
|
||||
2. Set regular price: **$20.00**
|
||||
|
||||
#### Add Volume Discounts
|
||||
|
||||
Click **Add Tier** and create:
|
||||
- Min Qty: `10` → Price: `$18.00` (10% off)
|
||||
- Min Qty: `25` → Price: `$16.00` (20% off)
|
||||
|
||||
#### Add Package Deals
|
||||
|
||||
Click **Add Package** and create:
|
||||
- Qty: `12` → Price: `$200` → Label: "Team Pack"
|
||||
- Qty: `24` → Price: `$360` → Label: "Bulk Order"
|
||||
|
||||
5. Click **Update** to save
|
||||
|
||||
## Step 4: Test It!
|
||||
|
||||
1. Visit your product page
|
||||
2. See the pricing table appear
|
||||
3. Change quantity to `12` → price updates automatically
|
||||
4. Click "Select Package" on Team Pack → quantity changes to 12
|
||||
5. Add to cart → verify price is correct ($200)
|
||||
|
||||
## That's It!
|
||||
|
||||
Your tier and package pricing is now working!
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
### Wholesale Store
|
||||
```
|
||||
Tier 1: 10+ items = $X each
|
||||
Tier 2: 50+ items = $Y each
|
||||
Tier 3: 100+ items = $Z each
|
||||
```
|
||||
|
||||
### Bulk Packages
|
||||
```
|
||||
Package 1: 6 items = $XX
|
||||
Package 2: 12 items = $YY
|
||||
Package 3: 24 items = $ZZ
|
||||
```
|
||||
|
||||
### Mixed Approach
|
||||
Use tiers for flexible quantities (10+, 25+, 50+)
|
||||
Use packages for common bundles (6-pack, dozen, case)
|
||||
|
||||
## Pro Tips
|
||||
|
||||
1. **Round Numbers**: Use 10, 25, 50, 100 for tiers
|
||||
2. **Meaningful Savings**: Offer at least 10% off per tier
|
||||
3. **Label Packages**: "Family Pack" sells better than "4-pack"
|
||||
4. **Test Checkout**: Always complete a test order
|
||||
5. **Mobile Check**: View on phone to verify responsiveness
|
||||
|
||||
## Need More Help?
|
||||
|
||||
- Full documentation: [README.md](README.md)
|
||||
- Detailed examples: [USAGE_EXAMPLES.md](USAGE_EXAMPLES.md)
|
||||
- Installation help: [INSTALLATION.md](INSTALLATION.md)
|
||||
|
||||
## Keyboard Shortcuts (Admin)
|
||||
|
||||
- Add new tier: Click "Add Tier" button
|
||||
- Remove tier: Click "Remove" button on that tier
|
||||
- Save: Press Ctrl+S (or Cmd+S on Mac) to save product
|
||||
|
||||
Happy selling!
|
||||
201
README.md
Normal file
201
README.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# WooCommerce Tier and Package Prices
|
||||
|
||||
A powerful WooCommerce plugin that adds tier pricing and package pricing functionality to your products with configurable quantities at fixed prices.
|
||||
|
||||
## Features
|
||||
|
||||
### Tier Pricing (Volume Discounts)
|
||||
- Set quantity-based pricing tiers
|
||||
- Automatic discounts when customers buy in larger quantities
|
||||
- Display savings percentage and amount
|
||||
- Dynamically updates price based on quantity selected
|
||||
|
||||
### Package Pricing
|
||||
- Create fixed-price packages with specific quantities
|
||||
- Example: 10 pieces for $50, 25 pieces for $100
|
||||
- Custom labels for packages (e.g., "Starter Pack", "Value Bundle")
|
||||
- One-click package selection on product pages
|
||||
|
||||
### Admin Features
|
||||
- Easy-to-use product meta boxes for adding tiers and packages
|
||||
- Global settings page under WooCommerce menu
|
||||
- Configure display position (before/after add to cart, after price)
|
||||
- Enable/disable tier or package pricing independently
|
||||
- Sortable pricing rules
|
||||
|
||||
### Frontend Features
|
||||
- Beautiful pricing tables on product pages
|
||||
- Responsive design for mobile devices
|
||||
- Visual highlighting of active tier/package
|
||||
- Real-time price updates when quantity changes
|
||||
- Cart integration with proper price calculations
|
||||
- Clear pricing indicators in cart
|
||||
|
||||
## Installation
|
||||
|
||||
1. Upload the `wc-tier-and-package-prices` folder to the `/wp-content/plugins/` directory
|
||||
2. Activate the plugin through the 'Plugins' menu in WordPress
|
||||
3. Make sure WooCommerce is installed and activated
|
||||
|
||||
## Configuration
|
||||
|
||||
### Global Settings
|
||||
|
||||
Navigate to **WooCommerce > Tier & Package Prices** to configure:
|
||||
|
||||
- **Enable Tier Pricing**: Turn on/off volume discounts
|
||||
- **Enable Package Pricing**: Turn on/off fixed-price packages
|
||||
- **Display Pricing Table**: Show/hide pricing tables on product pages
|
||||
- **Display Position**: Choose where to show pricing tables
|
||||
|
||||
### Product Settings
|
||||
|
||||
When editing a product, scroll to the **Product data** panel:
|
||||
|
||||
1. Click on the **General** tab
|
||||
2. Scroll down to find **Tier Pricing** and **Package Pricing** sections
|
||||
|
||||
#### Adding Tier Pricing
|
||||
|
||||
1. Click "Add Tier" button
|
||||
2. Set minimum quantity (e.g., 10)
|
||||
3. Set price per unit (e.g., 9.99)
|
||||
4. Add more tiers as needed
|
||||
5. Tiers are automatically sorted by quantity
|
||||
|
||||
**Example:**
|
||||
- 1-9 items: $12.00 each (regular price)
|
||||
- 10-24 items: $10.00 each (tier 1)
|
||||
- 25-49 items: $8.50 each (tier 2)
|
||||
- 50+ items: $7.00 each (tier 3)
|
||||
|
||||
#### Adding Package Pricing
|
||||
|
||||
1. Click "Add Package" button
|
||||
2. Set exact quantity (e.g., 10)
|
||||
3. Set fixed price for that quantity (e.g., 99.99)
|
||||
4. Optionally add a custom label (e.g., "Starter Pack")
|
||||
5. Add more packages as needed
|
||||
|
||||
**Example:**
|
||||
- Package 1: 10 pieces for $95 (labeled "Small Bundle")
|
||||
- Package 2: 25 pieces for $200 (labeled "Value Pack")
|
||||
- Package 3: 50 pieces for $350 (labeled "Business Pack")
|
||||
|
||||
## How It Works
|
||||
|
||||
### Price Calculation Priority
|
||||
|
||||
1. **Package Price** (highest priority): If the exact quantity matches a package, the package price applies
|
||||
2. **Tier Price**: If no package match, the highest applicable tier price is used
|
||||
3. **Regular Price**: If no tier or package applies, the regular product price is used
|
||||
|
||||
### Frontend Display
|
||||
|
||||
- Pricing tables show all available tiers and packages
|
||||
- Current tier/package is highlighted based on selected quantity
|
||||
- Prices update dynamically when quantity changes
|
||||
- Package buttons allow one-click quantity selection
|
||||
|
||||
### Cart Behavior
|
||||
|
||||
- Correct prices are applied in the cart
|
||||
- Cart shows whether tier or package pricing is applied
|
||||
- Subtotals are calculated correctly
|
||||
- Compatible with WooCommerce checkout process
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
wc-tier-and-package-prices/
|
||||
├── wc-tier-and-package-prices.php # Main plugin file
|
||||
├── includes/
|
||||
│ ├── class-wc-tpp-admin.php # Admin settings
|
||||
│ ├── class-wc-tpp-product-meta.php # Product meta boxes
|
||||
│ ├── class-wc-tpp-frontend.php # Frontend display
|
||||
│ └── class-wc-tpp-cart.php # Cart price calculations
|
||||
├── assets/
|
||||
│ ├── css/
|
||||
│ │ ├── admin.css # Admin styles
|
||||
│ │ └── frontend.css # Frontend styles
|
||||
│ └── js/
|
||||
│ ├── admin.js # Admin JavaScript
|
||||
│ └── frontend.js # Frontend JavaScript
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- WordPress 6.0 or higher (tested up to 6.9.x)
|
||||
- WooCommerce 8.0 or higher (tested up to 10.x)
|
||||
- PHP 7.4 or higher
|
||||
|
||||
### Compatibility
|
||||
|
||||
- ✅ **WooCommerce 10.x**: Fully compatible with the latest WooCommerce release
|
||||
- ✅ **WordPress 6.9.x**: Tested and verified with WordPress 6.9.x
|
||||
- ✅ **HPOS (High-Performance Order Storage)**: Full support for WooCommerce Custom Order Tables
|
||||
- ✅ **Block-based Themes**: Compatible with modern WordPress block themes
|
||||
- ✅ **Multisite**: Works on WordPress multisite installations
|
||||
|
||||
## Frequently Asked Questions
|
||||
|
||||
**Q: Can I use both tier pricing and package pricing on the same product?**
|
||||
A: Yes! Package pricing takes priority when the exact quantity matches.
|
||||
|
||||
**Q: What happens if a customer changes the quantity in the cart?**
|
||||
A: The price will automatically recalculate based on the new quantity.
|
||||
|
||||
**Q: Can I set different tiers for different products?**
|
||||
A: Yes, each product can have its own tier and package pricing configuration.
|
||||
|
||||
**Q: Does this work with variable products?**
|
||||
A: Currently, this plugin is designed for simple products. Variable product support may be added in future versions.
|
||||
|
||||
## Support
|
||||
|
||||
For bug reports and feature requests, please use the plugin's support forum or contact the developer.
|
||||
|
||||
## License
|
||||
|
||||
This plugin is licensed under the GPL v2 or later.
|
||||
|
||||
## Changelog
|
||||
|
||||
### Version 1.0.0 - 2025-12-21
|
||||
|
||||
#### Compatibility Updates
|
||||
|
||||
- ✅ Updated for WooCommerce 10.x compatibility
|
||||
- ✅ Updated for WordPress 6.9.x compatibility
|
||||
- ✅ Added HPOS (High-Performance Order Storage) support
|
||||
- ✅ Declared compatibility with WooCommerce Custom Order Tables
|
||||
|
||||
#### Security Enhancements
|
||||
|
||||
- ✅ Added nonce verification for product meta save operations
|
||||
- ✅ Added capability checks for user permissions
|
||||
- ✅ Enhanced data escaping and sanitization
|
||||
- ✅ Implemented autosave prevention
|
||||
|
||||
#### Code Improvements
|
||||
|
||||
- ✅ Enhanced cart object validation
|
||||
- ✅ Improved product object type checking
|
||||
- ✅ Better error handling for edge cases
|
||||
- ✅ Updated data storage methods for cart items
|
||||
- ✅ Modernized JavaScript localization with proper escaping
|
||||
|
||||
#### Initial Features
|
||||
|
||||
- Initial release with tier pricing functionality
|
||||
- Package pricing with fixed quantities
|
||||
- Customizable pricing tables
|
||||
- Global settings page
|
||||
- Product-level configuration
|
||||
- Cart integration with dynamic pricing
|
||||
- Responsive frontend design
|
||||
|
||||
## Credits
|
||||
|
||||
Developed by Marco Graetsch for WooCommerce store owners who need flexible pricing options.
|
||||
171
USAGE_EXAMPLES.md
Normal file
171
USAGE_EXAMPLES.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Usage Examples
|
||||
|
||||
## Example 1: T-Shirt Store with Volume Discounts
|
||||
|
||||
### Tier Pricing Setup
|
||||
|
||||
For a t-shirt that normally costs $20:
|
||||
|
||||
| Min Quantity | Price per Unit | Customer Saves |
|
||||
|--------------|----------------|----------------|
|
||||
| 1 | $20.00 | - |
|
||||
| 10 | $18.00 | $2.00 (10%) |
|
||||
| 25 | $16.00 | $4.00 (20%) |
|
||||
| 50 | $14.00 | $6.00 (30%) |
|
||||
|
||||
**How to configure:**
|
||||
1. Edit your t-shirt product
|
||||
2. Set regular price to $20.00
|
||||
3. Add tier: Min Qty = 10, Price = $18.00
|
||||
4. Add tier: Min Qty = 25, Price = $16.00
|
||||
5. Add tier: Min Qty = 50, Price = $14.00
|
||||
6. Save product
|
||||
|
||||
**Customer experience:**
|
||||
- Buys 5 shirts: $20.00 each = $100.00 total
|
||||
- Buys 15 shirts: $18.00 each = $270.00 total (saves $30)
|
||||
- Buys 30 shirts: $16.00 each = $480.00 total (saves $120)
|
||||
|
||||
## Example 2: Office Supplies with Package Deals
|
||||
|
||||
### Package Pricing Setup
|
||||
|
||||
For pens that normally cost $2.00 each:
|
||||
|
||||
| Package | Quantity | Fixed Price | Price per Unit |
|
||||
|--------------|----------|-------------|----------------|
|
||||
| Single | 1 | $2.00 | $2.00 |
|
||||
| Small Pack | 12 | $20.00 | $1.67 |
|
||||
| Value Pack | 24 | $36.00 | $1.50 |
|
||||
| Bulk Pack | 50 | $65.00 | $1.30 |
|
||||
|
||||
**How to configure:**
|
||||
1. Edit your pen product
|
||||
2. Set regular price to $2.00
|
||||
3. Add package: Qty = 12, Price = $20.00, Label = "Small Pack"
|
||||
4. Add package: Qty = 24, Price = $36.00, Label = "Value Pack"
|
||||
5. Add package: Qty = 50, Price = $65.00, Label = "Bulk Pack"
|
||||
6. Save product
|
||||
|
||||
**Customer experience:**
|
||||
- Customer sees package cards on product page
|
||||
- Clicks "Select Package" for "Value Pack"
|
||||
- Quantity automatically set to 24
|
||||
- Price shows $36.00 (not $48.00)
|
||||
|
||||
## Example 3: Combined Tier and Package Pricing
|
||||
|
||||
### Coffee Beans Store
|
||||
|
||||
For premium coffee beans at $15.00 per bag:
|
||||
|
||||
**Tier Pricing:**
|
||||
- 1-4 bags: $15.00 each
|
||||
- 5-9 bags: $14.00 each
|
||||
- 10+ bags: $13.00 each
|
||||
|
||||
**Package Deals:**
|
||||
- Monthly subscription: 4 bags for $50.00 ($12.50 each)
|
||||
- Quarterly bundle: 12 bags for $140.00 ($11.67 each)
|
||||
|
||||
**How to configure:**
|
||||
1. Set regular price: $15.00
|
||||
2. Add tier: Min Qty = 5, Price = $14.00
|
||||
3. Add tier: Min Qty = 10, Price = $13.00
|
||||
4. Add package: Qty = 4, Price = $50.00, Label = "Monthly Box"
|
||||
5. Add package: Qty = 12, Price = $140.00, Label = "Quarterly Bundle"
|
||||
|
||||
**Customer scenarios:**
|
||||
- Buys 3 bags: $15.00 each = $45.00
|
||||
- Buys 4 bags: Gets prompted for Monthly Box at $50.00
|
||||
- Buys 6 bags: $14.00 each = $84.00 (tier pricing)
|
||||
- Buys 12 bags: Gets Quarterly Bundle at $140.00 (package beats tier)
|
||||
|
||||
## Example 4: Promotional Packages
|
||||
|
||||
### Seasonal Gift Sets
|
||||
|
||||
Regular mug price: $10.00
|
||||
|
||||
**Package Deals:**
|
||||
- Pair Pack: 2 mugs for $18.00 (10% off)
|
||||
- Family Set: 4 mugs for $32.00 (20% off)
|
||||
- Office Bundle: 10 mugs for $70.00 (30% off)
|
||||
|
||||
**Configuration:**
|
||||
- Package 1: Qty = 2, Price = $18.00, Label = "Perfect Pair"
|
||||
- Package 2: Qty = 4, Price = $32.00, Label = "Family Set"
|
||||
- Package 3: Qty = 10, Price = $70.00, Label = "Office Bundle"
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
### Tier Pricing Best Practices
|
||||
|
||||
1. **Progressive Discounts**: Make higher quantities more attractive
|
||||
- Good: 10 items = 10% off, 25 items = 20% off, 50 items = 30% off
|
||||
- Bad: 10 items = 20% off, 25 items = 15% off
|
||||
|
||||
2. **Clear Break Points**: Use round numbers for quantities
|
||||
- Good: 10, 25, 50, 100
|
||||
- Avoid: 7, 23, 47, 93
|
||||
|
||||
3. **Meaningful Savings**: Ensure discounts are worth the extra purchase
|
||||
- Minimum 5-10% per tier level
|
||||
- Higher tiers should have progressively better deals
|
||||
|
||||
### Package Pricing Best Practices
|
||||
|
||||
1. **Strategic Quantities**: Match common use cases
|
||||
- 12-pack (dozen)
|
||||
- 24-pack (two dozen)
|
||||
- 6-pack (half dozen)
|
||||
|
||||
2. **Compelling Labels**: Make packages attractive
|
||||
- "Starter Pack" instead of "10-piece"
|
||||
- "Family Bundle" instead of "4-pack"
|
||||
- "Business Value Pack" instead of "50-piece"
|
||||
|
||||
3. **Sweet Spot Pricing**: Price just below psychological barriers
|
||||
- $99.99 instead of $100.00
|
||||
- $49.95 instead of $50.00
|
||||
|
||||
### Combining Both Strategies
|
||||
|
||||
1. Use **packages** for common quantities (6, 12, 24)
|
||||
2. Use **tiers** for flexible volume discounts (10+, 25+, 50+)
|
||||
3. Packages take priority when exact match exists
|
||||
4. Tiers fill the gaps between packages
|
||||
|
||||
## Display Position Recommendations
|
||||
|
||||
- **Before Add to Cart**: Best for products where pricing is the main decision factor
|
||||
- **After Add to Cart**: Good for impulse purchases and upsells
|
||||
- **After Price**: Ideal for clean product pages, keeps info near the price
|
||||
|
||||
## Testing Your Setup
|
||||
|
||||
1. Add a product to your store
|
||||
2. Configure tier/package pricing
|
||||
3. View the product page in an incognito window
|
||||
4. Test different quantities
|
||||
5. Verify prices update correctly
|
||||
6. Add to cart and check cart totals
|
||||
7. Complete a test checkout
|
||||
|
||||
## Common Scenarios
|
||||
|
||||
### Wholesale Store
|
||||
- Tier 1: 10+ items = wholesale price tier 1
|
||||
- Tier 2: 50+ items = wholesale price tier 2
|
||||
- Tier 3: 100+ items = wholesale price tier 3
|
||||
|
||||
### Subscription Box
|
||||
- Package 1: 1 month (4 items) = $40
|
||||
- Package 2: 3 months (12 items) = $108 (10% off)
|
||||
- Package 3: 6 months (24 items) = $192 (20% off)
|
||||
|
||||
### Event Supplies
|
||||
- Package 1: Small party (10 pieces) = $50
|
||||
- Package 2: Medium party (25 pieces) = $110
|
||||
- Package 3: Large party (50 pieces) = $200
|
||||
- Package 4: Event package (100 pieces) = $350
|
||||
91
assets/css/admin.css
Normal file
91
assets/css/admin.css
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Admin styles for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
.wc-tpp-tier-pricing,
|
||||
.wc-tpp-package-pricing {
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 15px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing > p:first-child,
|
||||
.wc-tpp-package-pricing > p:first-child {
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing .description,
|
||||
.wc-tpp-package-pricing .description {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row,
|
||||
.wc-tpp-package-row {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
align-items: flex-end;
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row .form-field,
|
||||
.wc-tpp-package-row .form-field {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row label,
|
||||
.wc-tpp-package-row label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-row input,
|
||||
.wc-tpp-package-row input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wc-tpp-remove-tier,
|
||||
.wc-tpp-remove-package {
|
||||
flex-shrink: 0;
|
||||
color: #b32d2e;
|
||||
border-color: #b32d2e;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.wc-tpp-remove-tier:hover,
|
||||
.wc-tpp-remove-package:hover {
|
||||
background: #b32d2e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.wc-tpp-add-tier,
|
||||
.wc-tpp-add-package {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-tiers-container,
|
||||
.wc-tpp-packages-container {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-tiers-container:empty::before,
|
||||
.wc-tpp-packages-container:empty::before {
|
||||
content: "No items added yet. Click 'Add' button to create pricing rules.";
|
||||
display: block;
|
||||
padding: 20px;
|
||||
background: #f0f0f1;
|
||||
border: 1px dashed #ccc;
|
||||
border-radius: 4px;
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
}
|
||||
173
assets/css/frontend.css
Normal file
173
assets/css/frontend.css
Normal file
@@ -0,0 +1,173 @@
|
||||
/**
|
||||
* Frontend styles for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
.wc-tpp-pricing-container {
|
||||
margin: 20px 0;
|
||||
padding: 20px;
|
||||
background: #f9f9f9;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing-table,
|
||||
.wc-tpp-package-pricing-table {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing-table:last-child,
|
||||
.wc-tpp-package-pricing-table:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.wc-tpp-tier-pricing-table h3,
|
||||
.wc-tpp-package-pricing-table h3 {
|
||||
margin: 0 0 15px 0;
|
||||
font-size: 1.2em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* Tier pricing table */
|
||||
.wc-tpp-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wc-tpp-table thead {
|
||||
background: #333;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.wc-tpp-table th {
|
||||
padding: 12px;
|
||||
text-align: left;
|
||||
font-weight: 600;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.wc-tpp-table tbody tr {
|
||||
border-bottom: 1px solid #e0e0e0;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.wc-tpp-table tbody tr:hover {
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.wc-tpp-table tbody tr.wc-tpp-active-tier {
|
||||
background: #e7f3e7;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.wc-tpp-table td {
|
||||
padding: 12px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
/* Package pricing */
|
||||
.wc-tpp-packages {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-package {
|
||||
background: #fff;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
transition: all 0.3s;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.wc-tpp-package:hover {
|
||||
border-color: #333;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.wc-tpp-package.wc-tpp-selected {
|
||||
border-color: #4CAF50;
|
||||
background: #f0f8f0;
|
||||
}
|
||||
|
||||
.wc-tpp-package-header h4 {
|
||||
margin: 0 0 15px 0;
|
||||
font-size: 1.1em;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.wc-tpp-package-details {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.wc-tpp-package-qty {
|
||||
font-size: 1.4em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.wc-tpp-package-qty strong {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.wc-tpp-package-price {
|
||||
font-size: 1.6em;
|
||||
font-weight: 700;
|
||||
color: #4CAF50;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.wc-tpp-package-unit-price {
|
||||
font-size: 0.85em;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.wc-tpp-select-package {
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
background: #333;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.95em;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.wc-tpp-select-package:hover {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.wc-tpp-package.wc-tpp-selected .wc-tpp-select-package {
|
||||
background: #4CAF50;
|
||||
}
|
||||
|
||||
.wc-tpp-package.wc-tpp-selected .wc-tpp-select-package:hover {
|
||||
background: #45a049;
|
||||
}
|
||||
|
||||
/* Cart notices */
|
||||
.wc-tpp-notice {
|
||||
color: #4CAF50;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.wc-tpp-packages {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.wc-tpp-table {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.wc-tpp-table th,
|
||||
.wc-tpp-table td {
|
||||
padding: 8px;
|
||||
}
|
||||
}
|
||||
62
assets/js/admin.js
Normal file
62
assets/js/admin.js
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Admin JavaScript for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function() {
|
||||
let tierIndex = $('.wc-tpp-tier-row').length;
|
||||
let packageIndex = $('.wc-tpp-package-row').length;
|
||||
|
||||
// Add tier
|
||||
$('.wc-tpp-add-tier').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const template = $('#wc-tpp-tier-row-template').html();
|
||||
const newRow = template.replace(/\{\{INDEX\}\}/g, tierIndex);
|
||||
$('.wc-tpp-tiers-container').append(newRow);
|
||||
tierIndex++;
|
||||
});
|
||||
|
||||
// Remove tier
|
||||
$(document).on('click', '.wc-tpp-remove-tier', function(e) {
|
||||
e.preventDefault();
|
||||
if (confirm('Are you sure you want to remove this tier?')) {
|
||||
$(this).closest('.wc-tpp-tier-row').remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Add package
|
||||
$('.wc-tpp-add-package').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const template = $('#wc-tpp-package-row-template').html();
|
||||
const newRow = template.replace(/\{\{INDEX\}\}/g, packageIndex);
|
||||
$('.wc-tpp-packages-container').append(newRow);
|
||||
packageIndex++;
|
||||
});
|
||||
|
||||
// Remove package
|
||||
$(document).on('click', '.wc-tpp-remove-package', function(e) {
|
||||
e.preventDefault();
|
||||
if (confirm('Are you sure you want to remove this package?')) {
|
||||
$(this).closest('.wc-tpp-package-row').remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Validate inputs
|
||||
$(document).on('input', 'input[name*="[min_qty]"], input[name*="[qty]"]', function() {
|
||||
const value = parseInt($(this).val());
|
||||
if (value < 1) {
|
||||
$(this).val(1);
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('input', 'input[name*="[price]"]', function() {
|
||||
const value = parseFloat($(this).val());
|
||||
if (value < 0) {
|
||||
$(this).val(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
179
assets/js/frontend.js
Normal file
179
assets/js/frontend.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Frontend JavaScript for WooCommerce Tier and Package Prices
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
$(document).ready(function() {
|
||||
const $quantityInput = $('input.qty');
|
||||
const $priceDisplay = $('.woocommerce-Price-amount.amount').first();
|
||||
|
||||
if ($quantityInput.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get tiers and packages data
|
||||
const tiers = [];
|
||||
const packages = [];
|
||||
|
||||
$('.wc-tpp-tier-pricing-table tbody tr').each(function() {
|
||||
tiers.push({
|
||||
minQty: parseInt($(this).data('min-qty')),
|
||||
price: parseFloat($(this).data('price'))
|
||||
});
|
||||
});
|
||||
|
||||
$('.wc-tpp-package').each(function() {
|
||||
packages.push({
|
||||
qty: parseInt($(this).data('qty')),
|
||||
price: parseFloat($(this).data('price'))
|
||||
});
|
||||
});
|
||||
|
||||
// Update price display based on quantity
|
||||
function updatePriceDisplay() {
|
||||
const quantity = parseInt($quantityInput.val()) || 1;
|
||||
|
||||
// Check for exact package match
|
||||
let matchedPackage = null;
|
||||
packages.forEach(function(pkg) {
|
||||
if (pkg.qty === quantity) {
|
||||
matchedPackage = pkg;
|
||||
}
|
||||
});
|
||||
|
||||
if (matchedPackage) {
|
||||
const totalPrice = matchedPackage.price;
|
||||
const unitPrice = totalPrice / quantity;
|
||||
updatePrice(unitPrice, 'Package price: ' + formatPrice(totalPrice) + ' total');
|
||||
highlightPackage(quantity);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for tier pricing
|
||||
let applicableTier = null;
|
||||
tiers.forEach(function(tier) {
|
||||
if (quantity >= tier.minQty) {
|
||||
applicableTier = tier;
|
||||
}
|
||||
});
|
||||
|
||||
if (applicableTier) {
|
||||
updatePrice(applicableTier.price, 'Volume discount applied');
|
||||
highlightTier(quantity);
|
||||
removePackageHighlight();
|
||||
} else {
|
||||
removeAllHighlights();
|
||||
}
|
||||
}
|
||||
|
||||
// Update price in the product page
|
||||
function updatePrice(price, message) {
|
||||
if ($priceDisplay.length) {
|
||||
const formattedPrice = formatPrice(price);
|
||||
$priceDisplay.html(formattedPrice);
|
||||
|
||||
// Add message if provided
|
||||
if (message) {
|
||||
if (!$('.wc-tpp-price-message').length) {
|
||||
$priceDisplay.after('<div class="wc-tpp-price-message"></div>');
|
||||
}
|
||||
$('.wc-tpp-price-message').html('<small>' + message + '</small>');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format price according to WooCommerce settings
|
||||
function formatPrice(price) {
|
||||
const decimals = wcTppData.price_decimals || 2;
|
||||
const decimalSep = wcTppData.price_decimal_separator || '.';
|
||||
const thousandSep = wcTppData.price_thousand_separator || ',';
|
||||
const symbol = wcTppData.currency_symbol || '$';
|
||||
const position = wcTppData.currency_position || 'left';
|
||||
|
||||
let priceStr = price.toFixed(decimals);
|
||||
const parts = priceStr.split('.');
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, thousandSep);
|
||||
priceStr = parts.join(decimalSep);
|
||||
|
||||
switch (position) {
|
||||
case 'left':
|
||||
return symbol + priceStr;
|
||||
case 'right':
|
||||
return priceStr + symbol;
|
||||
case 'left_space':
|
||||
return symbol + ' ' + priceStr;
|
||||
case 'right_space':
|
||||
return priceStr + ' ' + symbol;
|
||||
default:
|
||||
return symbol + priceStr;
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight active tier
|
||||
function highlightTier(quantity) {
|
||||
$('.wc-tpp-table tbody tr').removeClass('wc-tpp-active-tier');
|
||||
let activeRow = null;
|
||||
|
||||
$('.wc-tpp-table tbody tr').each(function() {
|
||||
const minQty = parseInt($(this).data('min-qty'));
|
||||
if (quantity >= minQty) {
|
||||
activeRow = $(this);
|
||||
}
|
||||
});
|
||||
|
||||
if (activeRow) {
|
||||
activeRow.addClass('wc-tpp-active-tier');
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight selected package
|
||||
function highlightPackage(quantity) {
|
||||
$('.wc-tpp-package').removeClass('wc-tpp-selected');
|
||||
$('.wc-tpp-table tbody tr').removeClass('wc-tpp-active-tier');
|
||||
|
||||
$('.wc-tpp-package').each(function() {
|
||||
const pkgQty = parseInt($(this).data('qty'));
|
||||
if (pkgQty === quantity) {
|
||||
$(this).addClass('wc-tpp-selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Remove package highlight
|
||||
function removePackageHighlight() {
|
||||
$('.wc-tpp-package').removeClass('wc-tpp-selected');
|
||||
}
|
||||
|
||||
// Remove all highlights
|
||||
function removeAllHighlights() {
|
||||
$('.wc-tpp-package').removeClass('wc-tpp-selected');
|
||||
$('.wc-tpp-table tbody tr').removeClass('wc-tpp-active-tier');
|
||||
$('.wc-tpp-price-message').remove();
|
||||
}
|
||||
|
||||
// Handle quantity input changes
|
||||
$quantityInput.on('input change', function() {
|
||||
updatePriceDisplay();
|
||||
});
|
||||
|
||||
// Handle package selection
|
||||
$('.wc-tpp-select-package').on('click', function(e) {
|
||||
e.preventDefault();
|
||||
const $package = $(this).closest('.wc-tpp-package');
|
||||
const qty = parseInt($package.data('qty'));
|
||||
|
||||
$quantityInput.val(qty).trigger('change');
|
||||
|
||||
// Scroll to add to cart button
|
||||
$('html, body').animate({
|
||||
scrollTop: $('.single_add_to_cart_button').offset().top - 100
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Initial update
|
||||
updatePriceDisplay();
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
22
composer.json
Normal file
22
composer.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "magdev/wc-tier-package-prices",
|
||||
"description": "WooCommerce plugin for tier pricing and package prices with Twig templates",
|
||||
"version": "1.0.1",
|
||||
"type": "wordpress-plugin",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marco Graetsch",
|
||||
"homepage": "https://src.bundespruefstelle.ch/magdev"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.4",
|
||||
"twig/twig": "^3.0"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"includes/"
|
||||
]
|
||||
}
|
||||
}
|
||||
48
includes/class-wc-tpp-admin.php
Normal file
48
includes/class-wc-tpp-admin.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin settings and configuration
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WC_TPP_Admin {
|
||||
|
||||
public function __construct() {
|
||||
add_action('admin_menu', array($this, 'add_admin_menu'));
|
||||
add_action('admin_init', array($this, 'register_settings'));
|
||||
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
|
||||
}
|
||||
|
||||
public function add_admin_menu() {
|
||||
add_submenu_page(
|
||||
'woocommerce',
|
||||
__('Tier & Package Prices', 'wc-tier-package-prices'),
|
||||
__('Tier & Package Prices', 'wc-tier-package-prices'),
|
||||
'manage_woocommerce',
|
||||
'wc-tier-package-prices',
|
||||
array($this, 'settings_page')
|
||||
);
|
||||
}
|
||||
|
||||
public function register_settings() {
|
||||
register_setting('wc_tpp_settings', 'wc_tpp_enable_tier_pricing');
|
||||
register_setting('wc_tpp_settings', 'wc_tpp_enable_package_pricing');
|
||||
register_setting('wc_tpp_settings', 'wc_tpp_display_table');
|
||||
register_setting('wc_tpp_settings', 'wc_tpp_display_position');
|
||||
}
|
||||
|
||||
public function enqueue_admin_scripts($hook) {
|
||||
if ('woocommerce_page_wc-tier-package-prices' === $hook || 'post.php' === $hook || 'post-new.php' === $hook) {
|
||||
wp_enqueue_style('wc-tpp-admin', WC_TPP_PLUGIN_URL . 'assets/css/admin.css', array(), WC_TPP_VERSION);
|
||||
wp_enqueue_script('wc-tpp-admin', WC_TPP_PLUGIN_URL . 'assets/js/admin.js', array('jquery'), WC_TPP_VERSION, true);
|
||||
}
|
||||
}
|
||||
|
||||
public function settings_page() {
|
||||
WC_TPP_Template_Loader::get_instance()->display('admin/settings-page.twig');
|
||||
}
|
||||
}
|
||||
|
||||
new WC_TPP_Admin();
|
||||
94
includes/class-wc-tpp-cart.php
Normal file
94
includes/class-wc-tpp-cart.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* Cart price calculation for tier and package pricing
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WC_TPP_Cart {
|
||||
|
||||
public function __construct() {
|
||||
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_subtotal', array($this, 'display_cart_item_subtotal'), 10, 3);
|
||||
}
|
||||
|
||||
public function apply_tier_package_pricing($cart) {
|
||||
if (is_admin() && !defined('DOING_AJAX')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent infinite loops
|
||||
if (did_action('woocommerce_before_calculate_totals') >= 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if cart object is valid
|
||||
if (!$cart || !is_a($cart, 'WC_Cart')) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
|
||||
$product_id = $cart_item['product_id'];
|
||||
$quantity = $cart_item['quantity'];
|
||||
$product = $cart_item['data'];
|
||||
|
||||
// Validate product object
|
||||
if (!$product || !is_a($product, 'WC_Product')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for exact package match first
|
||||
$package_price = null;
|
||||
if (get_option('wc_tpp_enable_package_pricing') === 'yes') {
|
||||
$package_price = WC_TPP_Frontend::get_package_price($product_id, $quantity);
|
||||
}
|
||||
|
||||
if ($package_price !== null) {
|
||||
// Apply package pricing (total price divided by quantity)
|
||||
$unit_price = $package_price / $quantity;
|
||||
$product->set_price($unit_price);
|
||||
// Store pricing information in cart item for display
|
||||
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_pricing_type'] = 'package';
|
||||
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_total_price'] = $package_price;
|
||||
} else {
|
||||
// Apply tier pricing if no package match
|
||||
if (get_option('wc_tpp_enable_tier_pricing') === 'yes') {
|
||||
$tier_price = WC_TPP_Frontend::get_tier_price($product_id, $quantity);
|
||||
if ($tier_price !== null) {
|
||||
$product->set_price($tier_price);
|
||||
// Store pricing information in cart item for display
|
||||
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_pricing_type'] = 'tier';
|
||||
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_unit_price'] = $tier_price;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function display_cart_item_price($price, $cart_item, $cart_item_key) {
|
||||
if (isset($cart_item['wc_tpp_pricing_type'])) {
|
||||
if ($cart_item['wc_tpp_pricing_type'] === 'package') {
|
||||
$total_price = isset($cart_item['wc_tpp_total_price']) ? $cart_item['wc_tpp_total_price'] : $cart_item['line_total'];
|
||||
$unit_price = $total_price / $cart_item['quantity'];
|
||||
return wc_price($unit_price) . ' <small class="wc-tpp-notice">(' . __('Package price', 'wc-tier-package-prices') . ')</small>';
|
||||
} elseif ($cart_item['wc_tpp_pricing_type'] === 'tier') {
|
||||
$unit_price = isset($cart_item['wc_tpp_unit_price']) ? $cart_item['wc_tpp_unit_price'] : $cart_item['data']->get_price();
|
||||
return wc_price($unit_price) . ' <small class="wc-tpp-notice">(' . __('Volume discount', 'wc-tier-package-prices') . ')</small>';
|
||||
}
|
||||
}
|
||||
return $price;
|
||||
}
|
||||
|
||||
public function display_cart_item_subtotal($subtotal, $cart_item, $cart_item_key) {
|
||||
if (isset($cart_item['wc_tpp_pricing_type']) && $cart_item['wc_tpp_pricing_type'] === 'package') {
|
||||
$total_price = isset($cart_item['wc_tpp_total_price']) ? $cart_item['wc_tpp_total_price'] : $cart_item['line_total'];
|
||||
return wc_price($total_price);
|
||||
}
|
||||
return $subtotal;
|
||||
}
|
||||
}
|
||||
|
||||
new WC_TPP_Cart();
|
||||
109
includes/class-wc-tpp-frontend.php
Normal file
109
includes/class-wc-tpp-frontend.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
/**
|
||||
* Frontend display for tier and package pricing
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WC_TPP_Frontend {
|
||||
|
||||
public function __construct() {
|
||||
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
|
||||
add_action('woocommerce_before_add_to_cart_button', array($this, 'display_pricing_table_before'), 20);
|
||||
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);
|
||||
}
|
||||
|
||||
public function enqueue_scripts() {
|
||||
if (is_product()) {
|
||||
wp_enqueue_style('wc-tpp-frontend', WC_TPP_PLUGIN_URL . 'assets/css/frontend.css', array(), WC_TPP_VERSION);
|
||||
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
|
||||
wp_localize_script('wc-tpp-frontend', 'wcTppData', array(
|
||||
'currency_symbol' => esc_js(get_woocommerce_currency_symbol()),
|
||||
'currency_position' => esc_js(get_option('woocommerce_currency_pos', 'left')),
|
||||
'price_decimals' => absint(wc_get_price_decimals()),
|
||||
'price_decimal_separator' => esc_js(wc_get_price_decimal_separator()),
|
||||
'price_thousand_separator' => esc_js(wc_get_price_thousand_separator())
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function display_pricing_table_before() {
|
||||
if (get_option('wc_tpp_display_position') === 'before_add_to_cart') {
|
||||
$this->display_pricing_table();
|
||||
}
|
||||
}
|
||||
|
||||
public function display_pricing_table_after() {
|
||||
if (get_option('wc_tpp_display_position') === 'after_add_to_cart') {
|
||||
$this->display_pricing_table();
|
||||
}
|
||||
}
|
||||
|
||||
public function display_pricing_table_after_price() {
|
||||
if (get_option('wc_tpp_display_position') === 'after_price') {
|
||||
$this->display_pricing_table();
|
||||
}
|
||||
}
|
||||
|
||||
public function display_pricing_table() {
|
||||
global $product;
|
||||
|
||||
if (!$product || !is_a($product, 'WC_Product') || get_option('wc_tpp_display_table') !== 'yes') {
|
||||
return;
|
||||
}
|
||||
|
||||
$product_id = $product->get_id();
|
||||
$tiers = get_post_meta($product_id, '_wc_tpp_tiers', true);
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
|
||||
if (empty($tiers) && empty($packages)) {
|
||||
return;
|
||||
}
|
||||
|
||||
WC_TPP_Template_Loader::get_instance()->display('frontend/pricing-table.twig', array(
|
||||
'product' => $product,
|
||||
'tiers' => $tiers,
|
||||
'packages' => $packages
|
||||
));
|
||||
}
|
||||
|
||||
public static function get_tier_price($product_id, $quantity) {
|
||||
$tiers = get_post_meta($product_id, '_wc_tpp_tiers', true);
|
||||
|
||||
if (empty($tiers) || !is_array($tiers)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$applicable_price = null;
|
||||
foreach ($tiers as $tier) {
|
||||
if ($quantity >= $tier['min_qty']) {
|
||||
$applicable_price = $tier['price'];
|
||||
}
|
||||
}
|
||||
|
||||
return $applicable_price;
|
||||
}
|
||||
|
||||
public static function get_package_price($product_id, $quantity) {
|
||||
$packages = get_post_meta($product_id, '_wc_tpp_packages', true);
|
||||
|
||||
if (empty($packages) || !is_array($packages)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($packages as $package) {
|
||||
if ($quantity == $package['qty']) {
|
||||
return $package['price'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
new WC_TPP_Frontend();
|
||||
157
includes/class-wc-tpp-product-meta.php
Normal file
157
includes/class-wc-tpp-product-meta.php
Normal file
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
/**
|
||||
* Product meta boxes for tier and package pricing
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class WC_TPP_Product_Meta {
|
||||
|
||||
public function __construct() {
|
||||
add_action('woocommerce_product_options_pricing', array($this, 'add_tier_pricing_fields'));
|
||||
add_action('woocommerce_product_options_pricing', array($this, 'add_package_pricing_fields'));
|
||||
add_action('woocommerce_process_product_meta', array($this, 'save_tier_package_fields'));
|
||||
}
|
||||
|
||||
public function add_tier_pricing_fields() {
|
||||
global $post;
|
||||
?>
|
||||
<div class="options_group wc-tpp-tier-pricing">
|
||||
<p class="form-field">
|
||||
<label><?php _e('Tier Pricing', 'wc-tier-package-prices'); ?></label>
|
||||
<span class="description"><?php _e('Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities.', 'wc-tier-package-prices'); ?></span>
|
||||
</p>
|
||||
|
||||
<div class="wc-tpp-tiers-container">
|
||||
<?php
|
||||
$tiers = get_post_meta($post->ID, '_wc_tpp_tiers', true);
|
||||
if (!is_array($tiers)) {
|
||||
$tiers = array();
|
||||
}
|
||||
|
||||
foreach ($tiers as $index => $tier) {
|
||||
$this->render_tier_row($index, $tier);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<p class="form-field">
|
||||
<button type="button" class="button wc-tpp-add-tier"><?php _e('Add Tier', 'wc-tier-package-prices'); ?></button>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function add_package_pricing_fields() {
|
||||
global $post;
|
||||
?>
|
||||
<div class="options_group wc-tpp-package-pricing">
|
||||
<p class="form-field">
|
||||
<label><?php _e('Package Pricing', 'wc-tier-package-prices'); ?></label>
|
||||
<span class="description"><?php _e('Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100.', 'wc-tier-package-prices'); ?></span>
|
||||
</p>
|
||||
|
||||
<div class="wc-tpp-packages-container">
|
||||
<?php
|
||||
$packages = get_post_meta($post->ID, '_wc_tpp_packages', true);
|
||||
if (!is_array($packages)) {
|
||||
$packages = array();
|
||||
}
|
||||
|
||||
foreach ($packages as $index => $package) {
|
||||
$this->render_package_row($index, $package);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<p class="form-field">
|
||||
<button type="button" class="button wc-tpp-add-package"><?php _e('Add Package', 'wc-tier-package-prices'); ?></button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<script type="text/html" id="wc-tpp-tier-row-template">
|
||||
<?php $this->render_tier_row('{{INDEX}}', array('min_qty' => '', 'price' => '')); ?>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="wc-tpp-package-row-template">
|
||||
<?php $this->render_package_row('{{INDEX}}', array('qty' => '', 'price' => '', 'label' => '')); ?>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
private function render_tier_row($index, $tier) {
|
||||
WC_TPP_Template_Loader::get_instance()->display('admin/tier-row.twig', array(
|
||||
'index' => $index,
|
||||
'tier' => $tier
|
||||
));
|
||||
}
|
||||
|
||||
private function render_package_row($index, $package) {
|
||||
WC_TPP_Template_Loader::get_instance()->display('admin/package-row.twig', array(
|
||||
'index' => $index,
|
||||
'package' => $package
|
||||
));
|
||||
}
|
||||
|
||||
public function save_tier_package_fields($post_id) {
|
||||
// Verify nonce for security
|
||||
if (!isset($_POST['woocommerce_meta_nonce']) || !wp_verify_nonce($_POST['woocommerce_meta_nonce'], 'woocommerce_save_data')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check user permissions
|
||||
if (!current_user_can('edit_post', $post_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Avoid auto-save
|
||||
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save tier pricing
|
||||
if (isset($_POST['_wc_tpp_tiers'])) {
|
||||
$tiers = array();
|
||||
foreach ($_POST['_wc_tpp_tiers'] as $tier) {
|
||||
if (!empty($tier['min_qty']) && !empty($tier['price'])) {
|
||||
$tiers[] = array(
|
||||
'min_qty' => absint($tier['min_qty']),
|
||||
'price' => wc_format_decimal($tier['price'])
|
||||
);
|
||||
}
|
||||
}
|
||||
// Sort by minimum quantity
|
||||
usort($tiers, function($a, $b) {
|
||||
return $a['min_qty'] - $b['min_qty'];
|
||||
});
|
||||
update_post_meta($post_id, '_wc_tpp_tiers', $tiers);
|
||||
} else {
|
||||
delete_post_meta($post_id, '_wc_tpp_tiers');
|
||||
}
|
||||
|
||||
// Save package pricing
|
||||
if (isset($_POST['_wc_tpp_packages'])) {
|
||||
$packages = array();
|
||||
foreach ($_POST['_wc_tpp_packages'] as $package) {
|
||||
if (!empty($package['qty']) && !empty($package['price'])) {
|
||||
$packages[] = array(
|
||||
'qty' => absint($package['qty']),
|
||||
'price' => wc_format_decimal($package['price']),
|
||||
'label' => sanitize_text_field($package['label'])
|
||||
);
|
||||
}
|
||||
}
|
||||
// Sort by quantity
|
||||
usort($packages, function($a, $b) {
|
||||
return $a['qty'] - $b['qty'];
|
||||
});
|
||||
update_post_meta($post_id, '_wc_tpp_packages', $packages);
|
||||
} else {
|
||||
delete_post_meta($post_id, '_wc_tpp_packages');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new WC_TPP_Product_Meta();
|
||||
103
includes/class-wc-tpp-template-loader.php
Normal file
103
includes/class-wc-tpp-template-loader.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Twig Template Loader for WC Tier Package Prices
|
||||
*
|
||||
* @package WC_Tier_Package_Prices
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
use Twig\TwigFilter;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
class WC_TPP_Template_Loader {
|
||||
|
||||
private static $instance = null;
|
||||
private $twig;
|
||||
|
||||
public static function get_instance() {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function __construct() {
|
||||
$this->init_twig();
|
||||
}
|
||||
|
||||
private function init_twig() {
|
||||
$loader = new FilesystemLoader(WC_TPP_PLUGIN_DIR . 'templates');
|
||||
|
||||
$this->twig = new Environment($loader, array(
|
||||
'cache' => WP_DEBUG ? false : WC_TPP_PLUGIN_DIR . 'templates/cache',
|
||||
'auto_reload' => true,
|
||||
'autoescape' => 'html',
|
||||
));
|
||||
|
||||
// Add WordPress translation filter
|
||||
$this->twig->addFilter(new TwigFilter('__', function ($string, $domain = 'wc-tier-package-prices') {
|
||||
return __($string, $domain);
|
||||
}));
|
||||
|
||||
$this->twig->addFilter(new TwigFilter('_e', function ($string, $domain = 'wc-tier-package-prices') {
|
||||
_e($string, $domain);
|
||||
}));
|
||||
|
||||
$this->twig->addFilter(new TwigFilter('esc_html', 'esc_html'));
|
||||
$this->twig->addFilter(new TwigFilter('esc_attr', 'esc_attr'));
|
||||
$this->twig->addFilter(new TwigFilter('esc_url', 'esc_url'));
|
||||
|
||||
// Add WordPress functions
|
||||
$this->twig->addFunction(new TwigFunction('get_option', 'get_option'));
|
||||
$this->twig->addFunction(new TwigFunction('checked', function($checked, $current = true, $echo = false) {
|
||||
return checked($checked, $current, $echo);
|
||||
}));
|
||||
$this->twig->addFunction(new TwigFunction('selected', function($selected, $current = true, $echo = false) {
|
||||
return selected($selected, $current, $echo);
|
||||
}));
|
||||
$this->twig->addFunction(new TwigFunction('settings_fields', function($option_group) {
|
||||
settings_fields($option_group);
|
||||
}));
|
||||
$this->twig->addFunction(new TwigFunction('submit_button', function($text = null) {
|
||||
submit_button($text);
|
||||
}));
|
||||
$this->twig->addFunction(new TwigFunction('get_admin_page_title', 'get_admin_page_title'));
|
||||
$this->twig->addFunction(new TwigFunction('wc_price', 'wc_price'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a Twig template
|
||||
*
|
||||
* @param string $template Template file name (e.g., 'admin/settings-page.twig')
|
||||
* @param array $context Variables to pass to the template
|
||||
* @return string Rendered template
|
||||
*/
|
||||
public function render($template, $context = array()) {
|
||||
try {
|
||||
return $this->twig->render($template, $context);
|
||||
} catch (Exception $e) {
|
||||
if (WP_DEBUG) {
|
||||
return sprintf(
|
||||
'<div class="error"><p>Twig Error: %s</p></div>',
|
||||
esc_html($e->getMessage())
|
||||
);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a Twig template
|
||||
*
|
||||
* @param string $template Template file name
|
||||
* @param array $context Variables to pass to the template
|
||||
*/
|
||||
public function display($template, $context = array()) {
|
||||
echo $this->render($template, $context);
|
||||
}
|
||||
}
|
||||
223
languages/README.md
Normal file
223
languages/README.md
Normal file
@@ -0,0 +1,223 @@
|
||||
# WooCommerce Tier and Package Prices - Translations
|
||||
|
||||
This directory contains translation files for the WooCommerce Tier and Package Prices plugin.
|
||||
|
||||
## Available Languages
|
||||
|
||||
- **English (US)** - `en_US` - Default language
|
||||
- **German (Germany)** - `de_DE` - Deutsch
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
languages/
|
||||
├── README.md # This file
|
||||
├── wc-tier-package-prices.pot # Translation template (3.1 KB)
|
||||
├── wc-tier-package-prices-en_US.po # English source file
|
||||
├── wc-tier-package-prices-en_US.mo # English compiled file (2.9 KB)
|
||||
├── wc-tier-package-prices-de_DE.po # German source file
|
||||
└── wc-tier-package-prices-de_DE.mo # German compiled file (3.0 KB)
|
||||
```
|
||||
|
||||
## File Types
|
||||
|
||||
- **`.pot`** - Portable Object Template - Master template file for creating new translations
|
||||
- **`.po`** - Portable Object - Human-readable translation source file
|
||||
- **`.mo`** - Machine Object - Compiled binary file used by WordPress
|
||||
|
||||
## Adding a New Translation
|
||||
|
||||
### Method 1: Using Poedit (Recommended)
|
||||
|
||||
1. Download and install [Poedit](https://poedit.net/)
|
||||
2. Open Poedit and click "Create new translation"
|
||||
3. Select the `wc-tier-package-prices.pot` file
|
||||
4. Choose your language
|
||||
5. Translate all strings
|
||||
6. Save the file (this creates both `.po` and `.mo` files automatically)
|
||||
7. Name the files as `wc-tier-package-prices-{locale}.po` and `wc-tier-package-prices-{locale}.mo`
|
||||
- Example for French: `wc-tier-package-prices-fr_FR.po` and `wc-tier-package-prices-fr_FR.mo`
|
||||
|
||||
### Method 2: Using Command Line
|
||||
|
||||
1. Copy the POT file to create a new PO file:
|
||||
```bash
|
||||
cp wc-tier-package-prices.pot wc-tier-package-prices-fr_FR.po
|
||||
```
|
||||
|
||||
2. Edit the PO file header:
|
||||
```
|
||||
"Language: fr_FR\n"
|
||||
"Language-Team: French\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
```
|
||||
|
||||
3. Translate all `msgstr` entries in the PO file
|
||||
|
||||
4. Compile the PO file to MO:
|
||||
```bash
|
||||
msgfmt -o wc-tier-package-prices-fr_FR.mo wc-tier-package-prices-fr_FR.po
|
||||
```
|
||||
|
||||
## WordPress Locale Codes
|
||||
|
||||
Common locale codes for WordPress:
|
||||
|
||||
- `en_US` - English (United States)
|
||||
- `en_GB` - English (United Kingdom)
|
||||
- `de_DE` - German (Germany)
|
||||
- `de_CH` - German (Switzerland)
|
||||
- `fr_FR` - French (France)
|
||||
- `fr_CH` - French (Switzerland)
|
||||
- `es_ES` - Spanish (Spain)
|
||||
- `it_IT` - Italian (Italy)
|
||||
- `nl_NL` - Dutch (Netherlands)
|
||||
- `pt_BR` - Portuguese (Brazil)
|
||||
- `ru_RU` - Russian
|
||||
- `zh_CN` - Chinese (Simplified)
|
||||
- `ja` - Japanese
|
||||
|
||||
For a complete list, see: https://translate.wordpress.org/
|
||||
|
||||
## Translation Statistics
|
||||
|
||||
### English (en_US)
|
||||
- **Total strings**: 30
|
||||
- **Translated**: 30 (100%)
|
||||
- **Status**: ✅ Complete
|
||||
|
||||
### German (de_DE)
|
||||
- **Total strings**: 30
|
||||
- **Translated**: 30 (100%)
|
||||
- **Status**: ✅ Complete
|
||||
|
||||
## Translatable Strings
|
||||
|
||||
The plugin contains translations for:
|
||||
|
||||
### Admin Interface
|
||||
- Settings page titles and descriptions
|
||||
- Product meta box labels
|
||||
- Field labels and placeholders
|
||||
- Button text
|
||||
|
||||
### Frontend
|
||||
- Pricing table headers
|
||||
- Package selection buttons
|
||||
- Cart notifications
|
||||
- Discount displays
|
||||
|
||||
## Testing Translations
|
||||
|
||||
### 1. Install Translation Files
|
||||
|
||||
Upload the `.mo` file to one of these locations:
|
||||
- Plugin directory: `wp-content/plugins/wc-tier-and-package-prices/languages/`
|
||||
- WordPress languages directory: `wp-content/languages/plugins/`
|
||||
|
||||
### 2. Change WordPress Language
|
||||
|
||||
1. Go to **Settings > General**
|
||||
2. Set **Site Language** to your desired language
|
||||
3. Save changes
|
||||
|
||||
### 3. Verify Translation
|
||||
|
||||
1. Navigate to **WooCommerce > Tier & Package Prices**
|
||||
2. Edit a product and check the meta boxes
|
||||
3. View a product on the frontend
|
||||
4. Check the cart page
|
||||
|
||||
All text should appear in the selected language.
|
||||
|
||||
## Updating Existing Translations
|
||||
|
||||
When the plugin is updated with new strings:
|
||||
|
||||
1. Update the POT template file
|
||||
2. Open your PO file in Poedit
|
||||
3. Click **Catalog > Update from POT file**
|
||||
4. Select the new `wc-tier-package-prices.pot` file
|
||||
5. Translate any new strings
|
||||
6. Save (automatically compiles to MO)
|
||||
|
||||
## Command Line Compilation
|
||||
|
||||
If you prefer command-line tools:
|
||||
|
||||
```bash
|
||||
# Compile a single language
|
||||
msgfmt -o wc-tier-package-prices-de_DE.mo wc-tier-package-prices-de_DE.po
|
||||
|
||||
# Compile all languages at once
|
||||
for po in *.po; do
|
||||
msgfmt -o "${po%.po}.mo" "$po"
|
||||
done
|
||||
|
||||
# Verify MO file
|
||||
msgunfmt wc-tier-package-prices-de_DE.mo | less
|
||||
```
|
||||
|
||||
## Translation Guidelines
|
||||
|
||||
### Style Guide
|
||||
|
||||
1. **Consistency**: Use consistent terminology throughout
|
||||
2. **Context**: Consider the context where text appears (admin vs frontend)
|
||||
3. **Length**: Keep translations similar in length to the original
|
||||
4. **Formality**: Maintain appropriate level of formality for your language
|
||||
5. **Technical Terms**: Don't translate technical terms like "WooCommerce"
|
||||
|
||||
### German Translation Notes
|
||||
|
||||
- Uses formal "Sie" form (not informal "du")
|
||||
- Currency examples adjusted (€ instead of $)
|
||||
- Decimal separator uses comma (9,99 instead of 9.99)
|
||||
- Date format: DD.MM.YYYY
|
||||
|
||||
### Best Practices
|
||||
|
||||
- ✅ Translate user-facing strings
|
||||
- ✅ Keep HTML tags intact
|
||||
- ✅ Preserve placeholders like `%s`, `%d`
|
||||
- ✅ Maintain the same number of placeholders
|
||||
- ❌ Don't translate variable names
|
||||
- ❌ Don't translate code or CSS classes
|
||||
- ❌ Don't remove or add HTML tags
|
||||
|
||||
## Contributing Translations
|
||||
|
||||
To contribute a new translation:
|
||||
|
||||
1. Create the PO and MO files following the guidelines above
|
||||
2. Test thoroughly in a WordPress installation
|
||||
3. Submit via pull request or contact the developer
|
||||
4. Include:
|
||||
- Both PO and MO files
|
||||
- Your name/credits for attribution
|
||||
- Screenshot showing the translation in use
|
||||
|
||||
## Support
|
||||
|
||||
For translation-related questions or to request a new language:
|
||||
|
||||
- **Plugin URI**: https://src.bundespruefstelle.ch/wc-tier-package-prices
|
||||
- **Author**: Marco Graetsch
|
||||
- **Author URI**: https://src.bundespruefstelle.ch/magdev
|
||||
|
||||
## Credits
|
||||
|
||||
### Translators
|
||||
|
||||
- **English (en_US)**: Marco Graetsch
|
||||
- **German (de_DE)**: Marco Graetsch
|
||||
|
||||
### Translation Tools
|
||||
|
||||
- [Poedit](https://poedit.net/) - Cross-platform PO editor
|
||||
- [Loco Translate](https://wordpress.org/plugins/loco-translate/) - WordPress plugin for translations
|
||||
- [GNU gettext](https://www.gnu.org/software/gettext/) - Command-line tools
|
||||
|
||||
## License
|
||||
|
||||
Translation files are distributed under the same GPL v2 or later license as the plugin.
|
||||
BIN
languages/wc-tier-package-prices-de_CH_informal.mo
Normal file
BIN
languages/wc-tier-package-prices-de_CH_informal.mo
Normal file
Binary file not shown.
163
languages/wc-tier-package-prices-de_CH_informal.po
Normal file
163
languages/wc-tier-package-prices-de_CH_informal.po
Normal file
@@ -0,0 +1,163 @@
|
||||
# German (Switzerland, Informal) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German (Switzerland)\n"
|
||||
"Language: de_CH_informal\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise benötigt eine installierte und aktive WooCommerce-Installation."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr "Staffel- & Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr "Staffelpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr "Staffelpreise für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr "Paketpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr "Festpreis-Pakete für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
msgid "Display Pricing Table"
|
||||
msgstr "Preistabelle anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr "Staffel- und Paketpreis-Tabelle auf Produktseiten anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
msgid "Display Position"
|
||||
msgstr "Anzeigeposition"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr "Vor \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr "Nach \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
msgid "After Price"
|
||||
msgstr "Nach dem Preis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr "Staffelpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Mengenbasierte Preisstaffeln festlegen. Kunden erhalten günstigere Preise beim Kauf grösserer Mengen."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr "Staffel hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr "Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Festpreis-Pakete mit bestimmten Mengen festlegen. Zum Beispiel: 10 Stück für CHF 50.-, 25 Stück für CHF 100.-."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr "Paket hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr "z.B. 10"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr "z.B. 9.90"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr "Entfernen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr "Menge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr "Festpreis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr "Bezeichnung (Optional)"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr "z.B. Starter-Paket"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr "Mengenrabatte"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr "Preis pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr "Du sparst"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr "Paketangebote"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr "Stück"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr "pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr "Paket auswählen"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr "Paketpreis"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr "Mengenrabatt"
|
||||
BIN
languages/wc-tier-package-prices-de_DE.mo
Normal file
BIN
languages/wc-tier-package-prices-de_DE.mo
Normal file
Binary file not shown.
163
languages/wc-tier-package-prices-de_DE.po
Normal file
163
languages/wc-tier-package-prices-de_DE.po
Normal file
@@ -0,0 +1,163 @@
|
||||
# German (Germany) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr "WooCommerce Staffel- und Paketpreise erfordert, dass WooCommerce installiert und aktiviert ist."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr "Staffel- & Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr "Staffelpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr "Staffelpreise für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr "Paketpreise aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr "Festpreis-Pakete für Produkte aktivieren"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
msgid "Display Pricing Table"
|
||||
msgstr "Preistabelle anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr "Staffel- und Paketpreis-Tabelle auf Produktseiten anzeigen"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
msgid "Display Position"
|
||||
msgstr "Anzeigeposition"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr "Vor \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr "Nach \"In den Warenkorb\""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
msgid "After Price"
|
||||
msgstr "Nach dem Preis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr "Staffelpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Mengenbasierte Preisstaffeln festlegen. Kunden erhalten Rabatte beim Kauf größerer Mengen."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr "Staffel hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr "Paketpreise"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Festpreis-Pakete mit bestimmten Mengen festlegen. Zum Beispiel: 10 Stück für 50€, 25 Stück für 100€."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr "Paket hinzufügen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr "Mindestmenge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr "z.B. 10"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr "z.B. 9,99"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr "Entfernen"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr "Menge"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr "Festpreis"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr "Bezeichnung (Optional)"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr "z.B. Starter-Paket"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr "Mengenrabatte"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr "Preis pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr "Sie sparen"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr "Paketangebote"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr "Stück"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr "pro Einheit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr "Paket auswählen"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr "Paketpreis"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr "Mengenrabatt"
|
||||
BIN
languages/wc-tier-package-prices-en_US.mo
Normal file
BIN
languages/wc-tier-package-prices-en_US.mo
Normal file
Binary file not shown.
163
languages/wc-tier-package-prices-en_US.po
Normal file
163
languages/wc-tier-package-prices-en_US.po
Normal file
@@ -0,0 +1,163 @@
|
||||
# English (US) translation for WooCommerce Tier and Package Prices
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||
"PO-Revision-Date: 2025-12-21 00:00+0000\n"
|
||||
"Last-Translator: Marco Graetsch\n"
|
||||
"Language-Team: English\n"
|
||||
"Language: en_US\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr "Tier & Package Prices"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr "Enable Tier Pricing"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr "Enable tier pricing for products"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr "Enable Package Pricing"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr "Enable fixed-price packages for products"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
msgid "Display Pricing Table"
|
||||
msgstr "Display Pricing Table"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr "Show tier and package pricing table on product pages"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
msgid "Display Position"
|
||||
msgstr "Display Position"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr "Before Add to Cart"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr "After Add to Cart"
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
msgid "After Price"
|
||||
msgstr "After Price"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr "Tier Pricing"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr "Add Tier"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr "Package Pricing"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr "Add Package"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr "Minimum Quantity"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr "e.g., 10"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr "e.g., 9.99"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr "Remove"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr "Quantity"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr "Fixed Price"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr "Label (Optional)"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr "e.g., Starter Pack"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr "Volume Discounts"
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr "Price per Unit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr "You Save"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr "Package Deals"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr "pieces"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr "per unit"
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr "Select Package"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr "Package price"
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr "Volume discount"
|
||||
166
languages/wc-tier-package-prices.pot
Normal file
166
languages/wc-tier-package-prices.pot
Normal file
@@ -0,0 +1,166 @@
|
||||
# Copyright (C) 2025 Marco Graetsch
|
||||
# This file is distributed under the GPL v2 or later.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: WooCommerce Tier and Package Prices 1.0.0\n"
|
||||
"Report-Msgid-Bugs-To: https://src.bundespruefstelle.ch/wc-tier-package-prices\n"
|
||||
"POT-Creation-Date: 2025-12-21 00:00+0000\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"PO-Revision-Date: 2025-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"X-Generator: Poedit 3.0\n"
|
||||
"X-Domain: wc-tier-package-prices\n"
|
||||
|
||||
#: wc-tier-and-package-prices.php:41
|
||||
msgid "WooCommerce Tier and Package Prices requires WooCommerce to be installed and active."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:21
|
||||
#: includes/class-wc-tpp-admin.php:22
|
||||
msgid "Tier & Package Prices"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:54
|
||||
msgid "Enable Tier Pricing"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:58
|
||||
msgid "Enable tier pricing for products"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:63
|
||||
msgid "Enable Package Pricing"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:67
|
||||
msgid "Enable fixed-price packages for products"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:72
|
||||
msgid "Display Pricing Table"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:76
|
||||
msgid "Show tier and package pricing table on product pages"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:81
|
||||
msgid "Display Position"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:85
|
||||
msgid "Before Add to Cart"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:86
|
||||
msgid "After Add to Cart"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-admin.php:87
|
||||
msgid "After Price"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:23
|
||||
msgid "Tier Pricing"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:24
|
||||
msgid "Set quantity-based pricing tiers. Customers get discounted prices when buying in larger quantities."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:41
|
||||
msgid "Add Tier"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:52
|
||||
msgid "Package Pricing"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:53
|
||||
msgid "Set fixed-price packages with specific quantities. For example: 10 pieces for $50, 25 pieces for $100."
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:70
|
||||
msgid "Add Package"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:90
|
||||
msgid "Minimum Quantity"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:91
|
||||
msgid "e.g., 10"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:94
|
||||
msgid "Price per Unit"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:95
|
||||
#: includes/class-wc-tpp-product-meta.php:114
|
||||
msgid "e.g., 9.99"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:97
|
||||
#: includes/class-wc-tpp-product-meta.php:120
|
||||
msgid "Remove"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:109
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:113
|
||||
msgid "Fixed Price"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:117
|
||||
msgid "Label (Optional)"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-product-meta.php:118
|
||||
msgid "e.g., Starter Pack"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:71
|
||||
msgid "Volume Discounts"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:75
|
||||
msgid "Quantity"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:76
|
||||
msgid "Price per Unit"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:77
|
||||
msgid "You Save"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:110
|
||||
msgid "Package Deals"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:123
|
||||
msgid "pieces"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:129
|
||||
msgid "per unit"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-frontend.php:133
|
||||
msgid "Select Package"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:63
|
||||
msgid "Package price"
|
||||
msgstr ""
|
||||
|
||||
#: includes/class-wc-tpp-cart.php:66
|
||||
msgid "Volume discount"
|
||||
msgstr ""
|
||||
36
templates/admin/package-row.twig
Normal file
36
templates/admin/package-row.twig
Normal file
@@ -0,0 +1,36 @@
|
||||
{#
|
||||
# Admin Package Row Template
|
||||
#
|
||||
# @package WC_Tier_Package_Prices
|
||||
# @var int index
|
||||
# @var array package
|
||||
#}
|
||||
<div class="wc-tpp-package-row">
|
||||
<p class="form-field">
|
||||
<label>{{ 'Quantity'|__('wc-tier-package-prices') }}</label>
|
||||
<input type="number"
|
||||
name="_wc_tpp_packages[{{ index|esc_attr }}][qty]"
|
||||
value="{{ package.qty|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 10'|__('wc-tier-package-prices') }}"
|
||||
min="1"
|
||||
step="1"
|
||||
class="short">
|
||||
</p>
|
||||
<p class="form-field">
|
||||
<label>{{ 'Fixed Price'|__('wc-tier-package-prices') }}</label>
|
||||
<input type="text"
|
||||
name="_wc_tpp_packages[{{ index|esc_attr }}][price]"
|
||||
value="{{ package.price|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 99.99'|__('wc-tier-package-prices') }}"
|
||||
class="short wc_input_price">
|
||||
</p>
|
||||
<p class="form-field">
|
||||
<label>{{ 'Label (Optional)'|__('wc-tier-package-prices') }}</label>
|
||||
<input type="text"
|
||||
name="_wc_tpp_packages[{{ index|esc_attr }}][label]"
|
||||
value="{{ package.label|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., Starter Pack'|__('wc-tier-package-prices') }}"
|
||||
class="short">
|
||||
</p>
|
||||
<button type="button" class="button wc-tpp-remove-package">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
||||
</div>
|
||||
53
templates/admin/settings-page.twig
Normal file
53
templates/admin/settings-page.twig
Normal file
@@ -0,0 +1,53 @@
|
||||
{#
|
||||
# Admin Settings Page Template
|
||||
#
|
||||
# @package WC_Tier_Package_Prices
|
||||
#}
|
||||
<div class="wrap">
|
||||
<h1>{{ get_admin_page_title()|esc_html }}</h1>
|
||||
<form action="options.php" method="post">
|
||||
{{ settings_fields('wc_tpp_settings') }}
|
||||
<table class="form-table">
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="wc_tpp_enable_tier_pricing">{{ 'Enable Tier Pricing'|__('wc-tier-package-prices') }}</label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="checkbox" id="wc_tpp_enable_tier_pricing" name="wc_tpp_enable_tier_pricing" value="yes" {{ checked(get_option('wc_tpp_enable_tier_pricing'), 'yes')|raw }}>
|
||||
<p class="description">{{ 'Enable tier pricing for products'|__('wc-tier-package-prices') }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="wc_tpp_enable_package_pricing">{{ 'Enable Package Pricing'|__('wc-tier-package-prices') }}</label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="checkbox" id="wc_tpp_enable_package_pricing" name="wc_tpp_enable_package_pricing" value="yes" {{ checked(get_option('wc_tpp_enable_package_pricing'), 'yes')|raw }}>
|
||||
<p class="description">{{ 'Enable fixed-price packages for products'|__('wc-tier-package-prices') }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="wc_tpp_display_table">{{ 'Display Pricing Table'|__('wc-tier-package-prices') }}</label>
|
||||
</th>
|
||||
<td>
|
||||
<input type="checkbox" id="wc_tpp_display_table" name="wc_tpp_display_table" value="yes" {{ checked(get_option('wc_tpp_display_table'), 'yes')|raw }}>
|
||||
<p class="description">{{ 'Show tier and package pricing table on product pages'|__('wc-tier-package-prices') }}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">
|
||||
<label for="wc_tpp_display_position">{{ 'Display Position'|__('wc-tier-package-prices') }}</label>
|
||||
</th>
|
||||
<td>
|
||||
<select id="wc_tpp_display_position" name="wc_tpp_display_position">
|
||||
<option value="before_add_to_cart" {{ selected(get_option('wc_tpp_display_position'), 'before_add_to_cart')|raw }}>{{ 'Before Add to Cart'|__('wc-tier-package-prices') }}</option>
|
||||
<option value="after_add_to_cart" {{ selected(get_option('wc_tpp_display_position'), 'after_add_to_cart')|raw }}>{{ 'After Add to Cart'|__('wc-tier-package-prices') }}</option>
|
||||
<option value="after_price" {{ selected(get_option('wc_tpp_display_position'), 'after_price')|raw }}>{{ 'After Price'|__('wc-tier-package-prices') }}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
{{ submit_button() }}
|
||||
</form>
|
||||
</div>
|
||||
28
templates/admin/tier-row.twig
Normal file
28
templates/admin/tier-row.twig
Normal file
@@ -0,0 +1,28 @@
|
||||
{#
|
||||
# Admin Tier Row Template
|
||||
#
|
||||
# @package WC_Tier_Package_Prices
|
||||
# @var int index
|
||||
# @var array tier
|
||||
#}
|
||||
<div class="wc-tpp-tier-row">
|
||||
<p class="form-field">
|
||||
<label>{{ 'Minimum Quantity'|__('wc-tier-package-prices') }}</label>
|
||||
<input type="number"
|
||||
name="_wc_tpp_tiers[{{ index|esc_attr }}][min_qty]"
|
||||
value="{{ tier.min_qty|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 10'|__('wc-tier-package-prices') }}"
|
||||
min="1"
|
||||
step="1"
|
||||
class="short">
|
||||
</p>
|
||||
<p class="form-field">
|
||||
<label>{{ 'Price per Unit'|__('wc-tier-package-prices') }}</label>
|
||||
<input type="text"
|
||||
name="_wc_tpp_tiers[{{ index|esc_attr }}][price]"
|
||||
value="{{ tier.price|default('')|esc_attr }}"
|
||||
placeholder="{{ 'e.g., 9.99'|__('wc-tier-package-prices') }}"
|
||||
class="short wc_input_price">
|
||||
</p>
|
||||
<button type="button" class="button wc-tpp-remove-tier">{{ 'Remove'|__('wc-tier-package-prices') }}</button>
|
||||
</div>
|
||||
35
templates/frontend/package-pricing-display.twig
Normal file
35
templates/frontend/package-pricing-display.twig
Normal file
@@ -0,0 +1,35 @@
|
||||
{#
|
||||
# Frontend Package Pricing Display Template
|
||||
#
|
||||
# @package WC_Tier_Package_Prices
|
||||
# @var array packages
|
||||
#}
|
||||
<div class="wc-tpp-package-pricing-table">
|
||||
<h3>{{ 'Package Deals'|__('wc-tier-package-prices') }}</h3>
|
||||
<div class="wc-tpp-packages">
|
||||
{% for index, package in packages %}
|
||||
{% set price_per_unit = package.qty > 0 ? package.price / package.qty : 0 %}
|
||||
<div class="wc-tpp-package" data-qty="{{ package.qty|esc_attr }}" data-price="{{ package.price|esc_attr }}">
|
||||
<div class="wc-tpp-package-header">
|
||||
{% if package.label is not empty %}
|
||||
<h4>{{ package.label|esc_html }}</h4>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="wc-tpp-package-details">
|
||||
<div class="wc-tpp-package-qty">
|
||||
<strong>{{ package.qty|esc_html }}</strong> {{ 'pieces'|__('wc-tier-package-prices') }}
|
||||
</div>
|
||||
<div class="wc-tpp-package-price">
|
||||
{{ wc_price(package.price)|raw }}
|
||||
</div>
|
||||
<div class="wc-tpp-package-unit-price">
|
||||
{{ wc_price(price_per_unit)|raw }} {{ 'per unit'|__('wc-tier-package-prices') }}
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="button wc-tpp-select-package" data-package-index="{{ index|esc_attr }}">
|
||||
{{ 'Select Package'|__('wc-tier-package-prices') }}
|
||||
</button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
17
templates/frontend/pricing-table.twig
Normal file
17
templates/frontend/pricing-table.twig
Normal file
@@ -0,0 +1,17 @@
|
||||
{#
|
||||
# Frontend Pricing Table Template
|
||||
#
|
||||
# @package WC_Tier_Package_Prices
|
||||
# @var object product
|
||||
# @var array tiers
|
||||
# @var array packages
|
||||
#}
|
||||
<div class="wc-tpp-pricing-container">
|
||||
{% if tiers is not empty and get_option('wc_tpp_enable_tier_pricing') == 'yes' %}
|
||||
{% include 'frontend/tier-pricing-table.twig' with {'product': product, 'tiers': tiers} %}
|
||||
{% endif %}
|
||||
|
||||
{% if packages is not empty and get_option('wc_tpp_enable_package_pricing') == 'yes' %}
|
||||
{% include 'frontend/package-pricing-display.twig' with {'packages': packages} %}
|
||||
{% endif %}
|
||||
</div>
|
||||
41
templates/frontend/tier-pricing-table.twig
Normal file
41
templates/frontend/tier-pricing-table.twig
Normal file
@@ -0,0 +1,41 @@
|
||||
{#
|
||||
# Frontend Tier Pricing Table Template
|
||||
#
|
||||
# @package WC_Tier_Package_Prices
|
||||
# @var object product
|
||||
# @var array tiers
|
||||
#}
|
||||
<div class="wc-tpp-tier-pricing-table">
|
||||
<h3>{{ 'Volume Discounts'|__('wc-tier-package-prices') }}</h3>
|
||||
<table class="wc-tpp-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'Quantity'|__('wc-tier-package-prices') }}</th>
|
||||
<th>{{ 'Price per Unit'|__('wc-tier-package-prices') }}</th>
|
||||
<th>{{ 'You Save'|__('wc-tier-package-prices') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% set regular_price = product.get_regular_price() %}
|
||||
{% for tier in tiers %}
|
||||
{% set savings = 0 %}
|
||||
{% set savings_percent = 0 %}
|
||||
{% if regular_price > 0 %}
|
||||
{% set savings = regular_price - tier.price %}
|
||||
{% set savings_percent = (savings / regular_price) * 100 %}
|
||||
{% endif %}
|
||||
<tr data-min-qty="{{ tier.min_qty|esc_attr }}" data-price="{{ tier.price|esc_attr }}">
|
||||
<td>{{ tier.min_qty|esc_html }}+</td>
|
||||
<td>{{ wc_price(tier.price)|raw }}</td>
|
||||
<td>
|
||||
{% if savings > 0 %}
|
||||
{{ wc_price(savings)|raw }} ({{ savings_percent|round(2) }}%)
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
111
wc-tier-and-package-prices.php
Normal file
111
wc-tier-and-package-prices.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Plugin Name: WooCommerce Tier and Package Prices
|
||||
* Plugin URI: https://src.bundespruefstelle.ch/wc-tier-package-prices
|
||||
* Description: Add tier pricing and package prices to WooCommerce products with configurable quantities at fixed prices
|
||||
* Version: 1.0.1
|
||||
* Author: Marco Graetsch
|
||||
* Author URI: https://src.bundespruefstelle.ch/magdev
|
||||
* Text Domain: wc-tier-package-prices
|
||||
* Domain Path: /languages
|
||||
* Requires at least: 6.0
|
||||
* Requires PHP: 7.4
|
||||
* WC requires at least: 8.0
|
||||
* WC tested up to: 10.0
|
||||
* License: GPL v2 or later
|
||||
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
// Define plugin constants
|
||||
define('WC_TPP_VERSION', '1.0.1');
|
||||
define('WC_TPP_PLUGIN_DIR', plugin_dir_path(__FILE__));
|
||||
define('WC_TPP_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||||
define('WC_TPP_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
||||
|
||||
// Load Composer autoloader
|
||||
require_once WC_TPP_PLUGIN_DIR . 'vendor/autoload.php';
|
||||
|
||||
/**
|
||||
* Check if WooCommerce is active
|
||||
*/
|
||||
if (!in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
|
||||
add_action('admin_notices', 'wc_tpp_woocommerce_missing_notice');
|
||||
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
|
||||
*/
|
||||
class WC_Tier_Package_Prices {
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function get_instance() {
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
private function __construct() {
|
||||
$this->init_hooks();
|
||||
$this->includes();
|
||||
}
|
||||
|
||||
private function init_hooks() {
|
||||
add_action('plugins_loaded', array($this, 'load_textdomain'));
|
||||
add_action('before_woocommerce_init', array($this, 'declare_hpos_compatibility'));
|
||||
register_activation_hook(__FILE__, array($this, 'activate'));
|
||||
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
|
||||
}
|
||||
|
||||
private function includes() {
|
||||
require_once WC_TPP_PLUGIN_DIR . 'includes/class-wc-tpp-template-loader.php';
|
||||
require_once WC_TPP_PLUGIN_DIR . 'includes/class-wc-tpp-admin.php';
|
||||
require_once WC_TPP_PLUGIN_DIR . 'includes/class-wc-tpp-product-meta.php';
|
||||
require_once WC_TPP_PLUGIN_DIR . 'includes/class-wc-tpp-frontend.php';
|
||||
require_once WC_TPP_PLUGIN_DIR . 'includes/class-wc-tpp-cart.php';
|
||||
}
|
||||
|
||||
public function declare_hpos_compatibility() {
|
||||
if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
|
||||
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
|
||||
}
|
||||
}
|
||||
|
||||
public function load_textdomain() {
|
||||
load_plugin_textdomain('wc-tier-package-prices', false, dirname(WC_TPP_PLUGIN_BASENAME) . '/languages');
|
||||
}
|
||||
|
||||
public function activate() {
|
||||
// Add default options
|
||||
add_option('wc_tpp_enable_tier_pricing', 'yes');
|
||||
add_option('wc_tpp_enable_package_pricing', 'yes');
|
||||
add_option('wc_tpp_display_table', 'yes');
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
public function deactivate() {
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the plugin
|
||||
function wc_tpp_init() {
|
||||
return WC_Tier_Package_Prices::get_instance();
|
||||
}
|
||||
|
||||
add_action('plugins_loaded', 'wc_tpp_init', 11);
|
||||
Reference in New Issue
Block a user