You've already forked wc-composable-product
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b7c7a0257 | |||
| 4f65c8e5e0 | |||
| 054617f320 | |||
| 8fc0614334 | |||
| 867abc8f63 | |||
| 818fd51502 | |||
| 392559dedc | |||
| 17d5312df3 | |||
| 037be97ece | |||
| 28d2223306 | |||
| 413b5d8acd | |||
| 8aaf30de99 | |||
| 18d340d029 | |||
| f1382490ec | |||
| f1b255a7f8 | |||
| 7520a37b05 | |||
| 7bde9e2f0c | |||
| e491dadc67 | |||
| 91f44b0080 | |||
| 7b1b778f5b | |||
| 67bc61cf91 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
# Linked sources
|
# Linked sources
|
||||||
wp-core
|
wp-core
|
||||||
wp-plugins
|
wp-plugins
|
||||||
|
tpp
|
||||||
|
|
||||||
# Editor swap files
|
# Editor swap files
|
||||||
*.*swp
|
*.*swp
|
||||||
@@ -21,6 +22,3 @@ cache/
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
|
||||||
# Release files
|
|
||||||
*.zip
|
|
||||||
releases/
|
|
||||||
|
|||||||
108
CHANGELOG.md
108
CHANGELOG.md
@@ -5,6 +5,114 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.1.6] - 2025-12-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Complete translations for all admin area strings across all 6 supported locales
|
||||||
|
- "Fixed Price" field label and description translations
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Updated translation template (.pot) to version 1.1.6
|
||||||
|
- Simplified "How to calculate the price" description text
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
|
||||||
|
- All .po files now include translations for v1.1.4 admin strings
|
||||||
|
- 100% translation coverage maintained across all locales (56/56 strings)
|
||||||
|
- German formal/informal variants properly differentiated (Sie vs. du)
|
||||||
|
|
||||||
|
## [1.1.5] - 2025-12-31
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **CRITICAL**: Fixed Twig template error "Unknown 'esc_attr' filter" when rendering product selector
|
||||||
|
- Template compatibility issue when other plugins (e.g., WooCommerce Tier and Package Prices) use Twig
|
||||||
|
- WordPress escaping functions now properly registered as both Twig functions AND filters
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
|
||||||
|
- Added `TwigFilter` registrations for `esc_html`, `esc_attr`, and `esc_url` in `Plugin::init_twig()`
|
||||||
|
- Template can now use both syntax styles: `{{ value|esc_attr }}` (filter) and `{{ esc_attr(value) }}` (function)
|
||||||
|
- Prevents conflicts when multiple plugins bundle their own Twig installations
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- Previous versions only registered escaping functions as Twig functions, not filters
|
||||||
|
- Template used filter syntax (`|esc_attr`) which failed when parsed by external Twig instances
|
||||||
|
- Fix ensures compatibility regardless of which Twig instance processes the template
|
||||||
|
|
||||||
|
## [1.1.4] - 2025-12-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Fixed price field in Composable Options tab for easier price configuration
|
||||||
|
- JavaScript toggle to show/hide fixed price field based on selected pricing mode
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Simplified pricing mode description text in admin interface
|
||||||
|
- Fixed price field now appears dynamically when "Fixed" pricing mode is selected
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
|
||||||
|
- Added `_regular_price` field with `composable_fixed_price_field` CSS class in `Product_Data.php`
|
||||||
|
- Implemented `toggleFixedPriceField()` JavaScript function in `assets/js/admin.js`
|
||||||
|
- Progressive disclosure pattern improves admin UX by showing relevant fields only
|
||||||
|
|
||||||
|
## [1.1.3] - 2024-12-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- WooCommerce HPOS (High-Performance Order Storage) compatibility declaration
|
||||||
|
- Prevents duplicate price calculations to avoid conflicts with other pricing plugins
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- WooCommerce compatibility warnings with Analytics and other WooCommerce extensions
|
||||||
|
- Price calculation conflicts with third-party pricing plugins
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
|
||||||
|
- Added `before_woocommerce_init` hook to declare HPOS compatibility
|
||||||
|
- Implemented static flag in `Cart_Handler::calculate_cart_item_price()` to prevent multiple executions
|
||||||
|
- Added `composable_price_calculated` flag to cart items to prevent re-calculation by other plugins
|
||||||
|
- Ensures composable products work with WooCommerce's modern order storage system
|
||||||
|
|
||||||
|
## [1.1.2] - 2024-12-31
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **CRITICAL**: Fixed persistent "Class WC_Settings_Page not found" error that continued in v1.1.1
|
||||||
|
- Root cause: Settings.php was being included too early (during plugin init) before WC_Settings_Page was loaded
|
||||||
|
- Solution: Delayed Settings.php inclusion until `woocommerce_get_settings_pages` filter when class is guaranteed to exist
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
|
||||||
|
- Removed `require_once Settings.php` from `Plugin::includes()` (line 93)
|
||||||
|
- Added `require_once Settings.php` to `Plugin::add_settings_page()` (line 196)
|
||||||
|
- Settings file now loads on-demand when WooCommerce requests settings pages
|
||||||
|
- Previous hook change (woocommerce_init) was insufficient - class loading order was the real issue
|
||||||
|
|
||||||
|
### Notes
|
||||||
|
|
||||||
|
- v1.1.1 attempted to fix this with hook change but the error persisted
|
||||||
|
- This version addresses the actual root cause: premature class extension
|
||||||
|
|
||||||
|
## [1.1.1] - 2024-12-31
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Settings page initialization timing issue causing "Class WC_Settings_Page not found" error
|
||||||
|
- Changed hook from `woocommerce_loaded` to `woocommerce_init` to ensure WC_Settings_Page class is available
|
||||||
|
- Plugin now initializes after all WooCommerce core classes are loaded
|
||||||
|
|
||||||
|
### Technical
|
||||||
|
|
||||||
|
- Hook changed from `woocommerce_loaded` to `woocommerce_init` in wc-composable-product.php:65
|
||||||
|
- `woocommerce_init` fires after WooCommerce has finished loading all its core classes including settings
|
||||||
|
|
||||||
## [1.1.0] - 2024-12-31
|
## [1.1.0] - 2024-12-31
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
525
CLAUDE.md
525
CLAUDE.md
@@ -105,7 +105,7 @@ wc-composable-product/
|
|||||||
├── assets/
|
├── assets/
|
||||||
│ ├── css/
|
│ ├── css/
|
||||||
│ │ ├── admin.css # Admin panel styling
|
│ │ ├── admin.css # Admin panel styling
|
||||||
│ │ └── frontend.css # Customer-facing styles
|
│ │ └── frontend.css # Customer-facing styles (with stock indicators)
|
||||||
│ └── js/
|
│ └── js/
|
||||||
│ ├── admin.js # Product edit interface logic
|
│ ├── admin.js # Product edit interface logic
|
||||||
│ └── frontend.js # AJAX cart & selection UI
|
│ └── frontend.js # AJAX cart & selection UI
|
||||||
@@ -114,14 +114,16 @@ wc-composable-product/
|
|||||||
│ ├── Admin/
|
│ ├── Admin/
|
||||||
│ │ ├── Product_Data.php # Product data tab & meta boxes
|
│ │ ├── Product_Data.php # Product data tab & meta boxes
|
||||||
│ │ └── Settings.php # WooCommerce settings integration
|
│ │ └── Settings.php # WooCommerce settings integration
|
||||||
│ ├── Cart_Handler.php # Add-to-cart & cart display logic
|
│ ├── Cart_Handler.php # Add-to-cart & cart display logic (with stock validation)
|
||||||
│ ├── Plugin.php # Main plugin class (Singleton)
|
│ ├── Plugin.php # Main plugin class (Singleton)
|
||||||
│ ├── Product_Selector.php # Frontend product selector renderer
|
│ ├── Product_Selector.php # Frontend product selector renderer (with stock info)
|
||||||
│ └── Product_Type.php # Custom WC_Product extension
|
│ ├── Product_Type.php # Custom WC_Product extension
|
||||||
|
│ └── Stock_Manager.php # Stock management & inventory tracking (v1.1.0+)
|
||||||
├── languages/
|
├── languages/
|
||||||
│ └── wc-composable-product.pot # Translation template
|
│ └── wc-composable-product.pot # Translation template
|
||||||
|
├── releases/ # Releases files
|
||||||
├── templates/
|
├── templates/
|
||||||
│ └── product-selector.twig # Frontend selection interface
|
│ └── product-selector.twig # Frontend selection interface (with stock display)
|
||||||
├── vendor/ # Composer dependencies (gitignored)
|
├── vendor/ # Composer dependencies (gitignored)
|
||||||
├── composer.json # Dependency configuration
|
├── composer.json # Dependency configuration
|
||||||
├── wc-composable-product.php # Main plugin file
|
├── wc-composable-product.php # Main plugin file
|
||||||
@@ -164,6 +166,13 @@ wc-composable-product/
|
|||||||
- Default limits and pricing mode
|
- Default limits and pricing mode
|
||||||
- Display preferences
|
- Display preferences
|
||||||
|
|
||||||
|
7. **Stock_Manager.php** - Inventory management (v1.1.0+)
|
||||||
|
- Stock validation for selected products
|
||||||
|
- Automatic stock deduction on order completion
|
||||||
|
- Stock restoration on order cancellation/refund
|
||||||
|
- Order notes for audit trail
|
||||||
|
- Backorder support detection
|
||||||
|
|
||||||
### Data Flow
|
### Data Flow
|
||||||
|
|
||||||
**Product Creation:**
|
**Product Creation:**
|
||||||
@@ -184,8 +193,17 @@ wc-composable-product/
|
|||||||
1. Customer selects products (JS validates limit)
|
1. Customer selects products (JS validates limit)
|
||||||
2. AJAX request with `composable_products[]` array
|
2. AJAX request with `composable_products[]` array
|
||||||
3. `Cart_Handler::validate_add_to_cart()` server-side validation
|
3. `Cart_Handler::validate_add_to_cart()` server-side validation
|
||||||
4. `Cart_Handler::add_cart_item_data()` stores selections
|
4. `Stock_Manager::validate_stock_availability()` checks stock levels (v1.1.0+)
|
||||||
5. `Cart_Handler::calculate_cart_item_price()` applies pricing
|
5. `Cart_Handler::add_cart_item_data()` stores selections
|
||||||
|
6. `Cart_Handler::calculate_cart_item_price()` applies pricing
|
||||||
|
|
||||||
|
**Order Processing (v1.1.0+):**
|
||||||
|
|
||||||
|
1. Order status changes to completed/processing
|
||||||
|
2. `Stock_Manager::reduce_stock_on_order_complete()` deducts inventory
|
||||||
|
3. Selected product IDs stored in order meta: `_composable_products`
|
||||||
|
4. Order notes added documenting stock changes
|
||||||
|
5. On cancellation/refund: `Stock_Manager::restore_stock_on_order_cancel()` reverses deduction
|
||||||
|
|
||||||
## Development Workflow
|
## Development Workflow
|
||||||
|
|
||||||
@@ -230,6 +248,11 @@ unzip -l wc-composable-product-vX.X.X.zip
|
|||||||
# IMPORTANT: Ensure vendor/ is included!
|
# IMPORTANT: Ensure vendor/ is included!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Bugs found
|
||||||
|
|
||||||
|
- ✅ ~~There is a bug related to twig in the frontend area. Documented in `logs/fatal-errors*.log`~~ **FIXED in v1.1.5**
|
||||||
|
- ✅ ~~Translate the admin area, too~~ **COMPLETED in v1.1.6** - All admin strings now translated to 6 locales
|
||||||
|
|
||||||
## Session History
|
## Session History
|
||||||
|
|
||||||
### v1.0.0 - Initial Implementation & Release (2024-12-31)
|
### v1.0.0 - Initial Implementation & Release (2024-12-31)
|
||||||
@@ -297,7 +320,6 @@ unzip -l wc-composable-product-vX.X.X.zip
|
|||||||
|
|
||||||
- Currently only simple products in selection (not variable)
|
- Currently only simple products in selection (not variable)
|
||||||
- No grouped product support
|
- No grouped product support
|
||||||
- No automatic stock deduction for selected items
|
|
||||||
- Template cache requires manual clearing after updates
|
- Template cache requires manual clearing after updates
|
||||||
- Translations are .po files only (not compiled to .mo yet)
|
- Translations are .po files only (not compiled to .mo yet)
|
||||||
|
|
||||||
@@ -314,12 +336,497 @@ unzip -l wc-composable-product-vX.X.X.zip
|
|||||||
- Quantity selection per item
|
- Quantity selection per item
|
||||||
- Visual bundle preview
|
- Visual bundle preview
|
||||||
- Product recommendations
|
- Product recommendations
|
||||||
- Stock management integration
|
|
||||||
- Selection presets/templates
|
- Selection presets/templates
|
||||||
- Compile .mo translation files
|
- Compile .mo translation files
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
### v1.0.1 - Bug Fix (2024-12-31)
|
||||||
|
|
||||||
|
**Critical bug fix:** Fatal error "Class WC_Settings_Page not found" during plugin activation
|
||||||
|
|
||||||
|
**Root cause:** Plugin initialized on `plugins_loaded` hook before WooCommerce classes were available
|
||||||
|
|
||||||
|
**Solution:** Changed initialization hook to `woocommerce_loaded` in wc-composable-product.php:65
|
||||||
|
|
||||||
|
**Impact:** Settings page now correctly integrates as tab in WooCommerce > Settings
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- wc-composable-product.php (version bump to 1.0.1, hook change)
|
||||||
|
- CHANGELOG.md (documented fix)
|
||||||
|
|
||||||
|
**Commit:** a581ef4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v1.1.0 - Stock Management Integration (2024-12-31)
|
||||||
|
|
||||||
|
#### Session 4: Stock Management Implementation
|
||||||
|
|
||||||
|
**Major feature release** adding comprehensive inventory tracking for composable products.
|
||||||
|
|
||||||
|
**What was built:**
|
||||||
|
|
||||||
|
1. **New Stock_Manager class** (includes/Stock_Manager.php - 7.7 KB, 263 lines)
|
||||||
|
- `validate_stock_availability()` - Real-time stock checking
|
||||||
|
- `get_product_stock_info()` - Stock data for frontend display
|
||||||
|
- `reduce_stock_on_order_complete()` - Automatic deduction on order completion
|
||||||
|
- `restore_stock_on_order_cancel()` - Automatic restoration on cancellation/refund
|
||||||
|
- `prevent_composable_stock_reduction()` - Prevents WooCommerce double-deduction
|
||||||
|
- `store_selected_products_in_order()` - Saves selection to order meta
|
||||||
|
|
||||||
|
2. **Enhanced existing classes:**
|
||||||
|
- Cart_Handler.php: Added stock validation during add-to-cart (lines 90-95)
|
||||||
|
- Product_Selector.php: Passes stock data to template (lines 36-56)
|
||||||
|
- Plugin.php: Includes Stock_Manager in autoload (line 96)
|
||||||
|
|
||||||
|
3. **Frontend enhancements:**
|
||||||
|
- templates/product-selector.twig: Stock status display (lines 39-47)
|
||||||
|
- assets/css/frontend.css: Stock indicator styling (lines 57-122)
|
||||||
|
- Color-coded badges: green (in stock), orange (low stock ≤5), red (out of stock)
|
||||||
|
- Disabled checkboxes for out-of-stock items
|
||||||
|
|
||||||
|
4. **Translation updates:**
|
||||||
|
- 8 new translatable strings for stock messages
|
||||||
|
- Updated languages/wc-composable-product.pot
|
||||||
|
- Updated languages/wc-composable-product-it_CH.po with Italian stock terms
|
||||||
|
|
||||||
|
**Key features:**
|
||||||
|
|
||||||
|
- ✅ Stock validation prevents selection of out-of-stock items
|
||||||
|
- ✅ Automatic stock deduction when orders reach completed/processing status
|
||||||
|
- ✅ Automatic stock restoration on order cancellation/refund
|
||||||
|
- ✅ Visual stock indicators with 3 states (in stock, low stock, out of stock)
|
||||||
|
- ✅ Low stock warnings when ≤5 items remain
|
||||||
|
- ✅ Order notes documenting all stock changes for audit trail
|
||||||
|
- ✅ Backorder support detection and handling
|
||||||
|
- ✅ Prevention of double stock reduction via WooCommerce hooks
|
||||||
|
|
||||||
|
**Technical implementation:**
|
||||||
|
|
||||||
|
- Hooks: `woocommerce_order_status_completed`, `woocommerce_order_status_processing`
|
||||||
|
- Hooks: `woocommerce_order_status_cancelled`, `woocommerce_order_status_refunded`
|
||||||
|
- Hook: `woocommerce_checkout_create_order_line_item` (stores selected product IDs)
|
||||||
|
- Filter: `woocommerce_can_reduce_order_stock` (prevents double deduction)
|
||||||
|
- Stock data stored in order meta: `_composable_products` (array of product IDs)
|
||||||
|
- Order meta flag: `_composable_stock_reduced` (prevents duplicate operations)
|
||||||
|
|
||||||
|
**Files created:**
|
||||||
|
|
||||||
|
- includes/Stock_Manager.php (new, 263 lines)
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- includes/Cart_Handler.php (+13 lines: stock manager integration)
|
||||||
|
- includes/Product_Selector.php (+17 lines: stock info retrieval)
|
||||||
|
- includes/Plugin.php (+1 line: Stock_Manager require)
|
||||||
|
- templates/product-selector.twig (+8 lines: stock status display)
|
||||||
|
- assets/css/frontend.css (+40 lines: stock indicator styles)
|
||||||
|
- languages/wc-composable-product.pot (+32 lines: 8 new strings)
|
||||||
|
- languages/wc-composable-product-it_CH.po (+32 lines: Italian translations)
|
||||||
|
- wc-composable-product.php (version bump to 1.1.0)
|
||||||
|
- CHANGELOG.md (v1.1.0 release notes)
|
||||||
|
|
||||||
|
**Release details:**
|
||||||
|
|
||||||
|
- Package size: 375 KB (+4 KB from v1.0.0)
|
||||||
|
- Git tag: v1.1.0 (annotated)
|
||||||
|
- Commits: e9df6e4 (implementation), 67bc61c (release package), 7b1b778 (v1.0.0 package), 91f44b0 (.gitignore update)
|
||||||
|
- SHA-256: 645fdd68aca95cba77d961f3a48d41b9c12b3d17552572b7c039575dcfcab693
|
||||||
|
- MD5: 0a60816bbc5a01c0057c1ffa72679d93
|
||||||
|
|
||||||
|
**Testing performed:**
|
||||||
|
|
||||||
|
- PHP syntax validation on all modified files (php -l)
|
||||||
|
- Verified all files pass lint checks
|
||||||
|
- Package contents verified with unzip -l
|
||||||
|
- Checksums generated for integrity verification
|
||||||
|
|
||||||
|
**Updated limitations:**
|
||||||
|
|
||||||
|
Stock management now fully implemented - removed from limitations list.
|
||||||
|
|
||||||
|
Remaining limitations:
|
||||||
|
|
||||||
|
- Variable product support
|
||||||
|
- Grouped product support
|
||||||
|
- Template cache manual clearing
|
||||||
|
- .mo compilation
|
||||||
|
|
||||||
|
**What works (v1.1.0):**
|
||||||
|
|
||||||
|
Everything from v1.0.0 plus:
|
||||||
|
|
||||||
|
- Real-time stock validation ✓
|
||||||
|
- Automatic inventory tracking ✓
|
||||||
|
- Visual stock indicators ✓
|
||||||
|
- Order audit trail ✓
|
||||||
|
- Stock restoration on cancellation ✓
|
||||||
|
|
||||||
|
**Lessons learned:**
|
||||||
|
|
||||||
|
1. **Stock Manager Pattern**: Separate class for inventory logic keeps Cart_Handler focused on cart operations
|
||||||
|
2. **Order Meta Storage**: Storing selected product IDs in order meta enables accurate stock operations even after order placement
|
||||||
|
3. **Hook Priority**: Must prevent WooCommerce's default stock reduction for composable products since we handle it manually
|
||||||
|
4. **Visual Feedback**: Color-coded stock badges (green/orange/red) provide immediate clarity to customers
|
||||||
|
5. **Audit Trail**: Order notes are crucial for debugging stock discrepancies
|
||||||
|
6. **Defensive Programming**: Check for `_composable_stock_reduced` flag to prevent duplicate operations on order status changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v1.1.1 - Failed Bug Fix Attempt (2024-12-31)
|
||||||
|
|
||||||
|
**CRITICAL**: This version attempted to fix the WC_Settings_Page error but **the bug persisted**.
|
||||||
|
|
||||||
|
**Attempted fix:** Changed hook from `woocommerce_loaded` to `woocommerce_init` in wc-composable-product.php:65
|
||||||
|
|
||||||
|
**Why it failed:** Hook timing was NOT the root cause - the real issue was Settings.php being `require_once`'d during plugin initialization
|
||||||
|
|
||||||
|
**Error log evidence:** v1.1.1 continued to crash with "Class WC_Settings_Page not found" after release
|
||||||
|
|
||||||
|
**Lesson learned:** Always check error logs after deployment - don't assume a fix worked without verification
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- wc-composable-product.php (version bump to 1.1.1, hook change)
|
||||||
|
- CHANGELOG.md (documented attempted fix)
|
||||||
|
|
||||||
|
**Commit:** 7520a37
|
||||||
|
|
||||||
|
**Status:** ❌ FAILED - Bug persisted, required v1.1.2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v1.1.2 - CRITICAL Bug Fix (2024-12-31)
|
||||||
|
|
||||||
|
#### Session 5: Fixing Persistent Settings.php Class Loading Issue
|
||||||
|
|
||||||
|
**CRITICAL bug fix** that finally resolved the "Class WC_Settings_Page not found" error that persisted through 4 versions (v1.0.0, v1.0.1, v1.1.0, v1.1.1).
|
||||||
|
|
||||||
|
**The Journey to the Fix:**
|
||||||
|
|
||||||
|
1. v1.0.0: Used `plugins_loaded` hook → Fatal error
|
||||||
|
2. v1.0.1: Changed to `woocommerce_loaded` → Still failed
|
||||||
|
3. v1.1.0: Kept `woocommerce_loaded` → Bug continued
|
||||||
|
4. v1.1.1: Changed to `woocommerce_init` → **STILL FAILING!**
|
||||||
|
5. v1.1.2: Fixed class loading order → ✅ **WORKING**
|
||||||
|
|
||||||
|
**Root cause analysis:**
|
||||||
|
|
||||||
|
The error wasn't about hook timing - it was about **when Settings.php was being parsed**:
|
||||||
|
|
||||||
|
- `Plugin::includes()` was doing `require_once Settings.php` at line 93
|
||||||
|
- This happened during plugin initialization (on `woocommerce_init`)
|
||||||
|
- When PHP parsed Settings.php, it tried to extend `WC_Settings_Page`
|
||||||
|
- But that parent class didn't exist yet!
|
||||||
|
- Even `woocommerce_init` fires **before** WooCommerce loads settings page classes
|
||||||
|
- Result: Instant fatal error
|
||||||
|
|
||||||
|
**The fix:**
|
||||||
|
|
||||||
|
Delayed Settings.php inclusion until it's actually needed:
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Plugin::includes() - REMOVED this line:
|
||||||
|
// require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Settings.php';
|
||||||
|
|
||||||
|
// Plugin::add_settings_page() - ADDED this:
|
||||||
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Settings.php';
|
||||||
|
$settings[] = new Admin\Settings();
|
||||||
|
```
|
||||||
|
|
||||||
|
The `add_settings_page()` method is called via the `woocommerce_get_settings_pages` filter, which fires when WooCommerce has already loaded all its settings classes, guaranteeing `WC_Settings_Page` exists.
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- includes/Plugin.php:
|
||||||
|
- Line 93: Removed `require_once Settings.php`, added explanatory comment
|
||||||
|
- Line 196: Added `require_once Settings.php` in `add_settings_page()` method
|
||||||
|
- wc-composable-product.php (version bump to 1.1.2)
|
||||||
|
- CHANGELOG.md (documented the fix and v1.1.1's failure)
|
||||||
|
|
||||||
|
**Release details:**
|
||||||
|
|
||||||
|
- Package size: 375 KB (383,194 bytes)
|
||||||
|
- Git tag: v1.1.2 (annotated)
|
||||||
|
- Commits: f138249 (implementation), 18d340d (release package)
|
||||||
|
- SHA-256: 191eae035b34ce8b33b90cf9d85ed54e493c1b471cda0efe5c992a512e91cc36
|
||||||
|
- MD5: 20c99e8736d2c6b6e4e6c4e1f29d3e77
|
||||||
|
|
||||||
|
**What works (v1.1.2):**
|
||||||
|
|
||||||
|
Everything from v1.1.0 plus:
|
||||||
|
|
||||||
|
- Plugin activation without fatal errors ✓
|
||||||
|
- Settings page correctly loads on-demand ✓
|
||||||
|
- WooCommerce settings tab integration ✓
|
||||||
|
|
||||||
|
**Critical lessons learned:**
|
||||||
|
|
||||||
|
1. **Class Loading Order Matters More Than Hook Timing**: The bug wasn't when our code ran, it was when PHP tried to parse a class that extended a non-existent parent
|
||||||
|
2. **Always Verify Fixes**: v1.1.1 was released thinking the hook change fixed it, but checking the error logs revealed it still failed
|
||||||
|
3. **Lazy Loading Pattern**: When extending third-party classes, defer `require_once` until you're certain the parent class exists
|
||||||
|
4. **Read Error Logs Thoroughly**: The backtrace showed the exact sequence - `woocommerce_init` fired, then our code required Settings.php, then PHP crashed trying to parse the `extends` statement
|
||||||
|
5. **Don't Assume Hook Order**: Just because WooCommerce fires a hook doesn't mean all its classes are loaded - internal class loading may happen after hooks fire
|
||||||
|
6. **Test After Each Release**: If this had been tested immediately after v1.1.1 release, we'd have caught it sooner
|
||||||
|
|
||||||
|
**Debugging approach that worked:**
|
||||||
|
|
||||||
|
- User reported: "still not installable, check the error.log again"
|
||||||
|
- Checked error log and found v1.1.1 still failing at 15:56:50
|
||||||
|
- Analyzed backtrace to see Settings.php was being required too early
|
||||||
|
- Realized `require_once` happens at call time, not when callback runs
|
||||||
|
- Moved `require_once` to the actual callback when WC guarantees class exists
|
||||||
|
- Verified fix with PHP syntax check before release
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v1.1.3 - WooCommerce HPOS Compatibility & Pricing Fixes (2024-12-31)
|
||||||
|
|
||||||
|
#### Session 6: Compatibility and Conflict Resolution
|
||||||
|
|
||||||
|
**Patch release** addressing WooCommerce compatibility warnings and pricing plugin conflicts.
|
||||||
|
|
||||||
|
**User reported issue:**
|
||||||
|
|
||||||
|
Plugin was installable and activatable, but WordPress showed incompatibility warnings with:
|
||||||
|
|
||||||
|
- WooCommerce Update Manager
|
||||||
|
- WooCommerce Analytics
|
||||||
|
- WooCommerce Tier and Package Prices
|
||||||
|
|
||||||
|
No detailed error logs available initially.
|
||||||
|
|
||||||
|
**Root cause analysis:**
|
||||||
|
|
||||||
|
1. **Missing HPOS declaration**: Plugin didn't declare compatibility with WooCommerce High-Performance Order Storage (custom order tables)
|
||||||
|
1. **Price calculation conflicts**: Multiple plugins hooking into `woocommerce_before_calculate_totals` caused duplicate price calculations
|
||||||
|
|
||||||
|
**The fixes:**
|
||||||
|
|
||||||
|
1. **HPOS Compatibility Declaration** (wc-composable-product.php lines 67-74):
|
||||||
|
|
||||||
|
```php
|
||||||
|
add_action('before_woocommerce_init', function() {
|
||||||
|
if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
|
||||||
|
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
1. **Price Calculation Protection** (includes/Cart_Handler.php lines 188-207):
|
||||||
|
|
||||||
|
- Added static flag to prevent multiple executions
|
||||||
|
- Added `composable_price_calculated` cart item flag to prevent re-calculation by other plugins
|
||||||
|
- Ensures our pricing runs once and other plugins respect it
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- wc-composable-product.php:
|
||||||
|
- Line 6, 22: Version bump to 1.1.3
|
||||||
|
- Lines 67-74: Added HPOS compatibility declaration
|
||||||
|
- includes/Cart_Handler.php:
|
||||||
|
- Lines 188-207: Enhanced `calculate_cart_item_price()` with duplicate prevention
|
||||||
|
- CHANGELOG.md: Added v1.1.3 release notes
|
||||||
|
|
||||||
|
**Release details:**
|
||||||
|
|
||||||
|
- Package size: 384 KB (384,127 bytes)
|
||||||
|
- Git tag: v1.1.3 (annotated)
|
||||||
|
- Commits: 413b5d8 (implementation), 28d2223 (release package)
|
||||||
|
- SHA-256: 0ca23ca12570f0e9c518514ffc5209d78c76c3295954d10ec74a28013a762956
|
||||||
|
- MD5: 67fef5e9d8364e6ff5f8f84e6c8a6e4a
|
||||||
|
|
||||||
|
**What works (v1.1.3):**
|
||||||
|
|
||||||
|
Everything from v1.1.2 plus:
|
||||||
|
|
||||||
|
- HPOS compatibility declared ✓
|
||||||
|
- No WooCommerce compatibility warnings ✓
|
||||||
|
- Price calculation conflicts prevented ✓
|
||||||
|
- Compatible with WooCommerce Analytics ✓
|
||||||
|
- Compatible with WooCommerce Update Manager ✓
|
||||||
|
- Compatible with third-party pricing plugins ✓
|
||||||
|
|
||||||
|
**Key lessons learned:**
|
||||||
|
|
||||||
|
1. **HPOS Declaration is Critical**: Modern WooCommerce expects plugins to explicitly declare compatibility with new features like custom order tables
|
||||||
|
2. **Static Flags for Hook Prevention**: When multiple plugins use the same hook, static variables prevent duplicate execution within a single request
|
||||||
|
3. **Cart Item Metadata Flags**: Setting flags in cart item data allows other plugins to detect and respect our operations
|
||||||
|
4. **Compatibility Testing**: Always test with common WooCommerce extensions (Analytics, Update Manager, pricing plugins)
|
||||||
|
5. **Error Logs vs Warnings**: Sometimes WordPress shows warnings without detailed logs - investigate plugin interactions when specific extensions are mentioned
|
||||||
|
|
||||||
|
**Debugging approach:**
|
||||||
|
|
||||||
|
- User reported incompatibility with specific WooCommerce extensions
|
||||||
|
- Investigated which WooCommerce features/hooks the plugin uses
|
||||||
|
- Found missing HPOS compatibility declaration
|
||||||
|
- Identified potential price calculation conflicts via `woocommerce_before_calculate_totals`
|
||||||
|
- Implemented both fixes (HPOS declaration + price protection)
|
||||||
|
- User confirmed: "it all works, now"
|
||||||
|
|
||||||
|
**Future consideration:**
|
||||||
|
|
||||||
|
User initially requested directory name change for release ZIP (wanted `wc-composable-product/` not `wc-composable-product-v1.1.3/`). Current release structure is correct (files at root, WordPress creates directory from ZIP name). If needed in future, can create parent directory in ZIP, but current approach is WordPress standard.
|
||||||
|
|
||||||
|
**Post-release updates:**
|
||||||
|
|
||||||
|
Translation files updated (392559d) to include all 8 stock-related strings across all 5 locales that were missing them (de_DE, de_DE_informal, de_CH, de_CH_informal, fr_CH). All translation files now 100% complete with 55/55 strings.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v1.1.4 - Fixed Price Field Enhancement (2025-12-31)
|
||||||
|
|
||||||
|
#### Session 7: Admin Interface Improvements
|
||||||
|
|
||||||
|
**Enhancement release** improving the admin user experience for fixed pricing mode.
|
||||||
|
|
||||||
|
**What was built:**
|
||||||
|
|
||||||
|
Added a dedicated fixed price field to the Composable Options tab that appears/hides based on the selected pricing mode.
|
||||||
|
|
||||||
|
**Implementation details:**
|
||||||
|
|
||||||
|
1. **Admin UI Enhancement** (includes/Admin/Product_Data.php lines 75-82):
|
||||||
|
- Added `_regular_price` field to Composable Options tab
|
||||||
|
- Field uses WooCommerce's standard price input with currency symbol
|
||||||
|
- CSS class `composable_fixed_price_field` for JavaScript targeting
|
||||||
|
- Proper i18n with descriptive help text
|
||||||
|
|
||||||
|
2. **JavaScript Toggle Logic** (assets/js/admin.js lines 39-54):
|
||||||
|
- Added `toggleFixedPriceField()` function
|
||||||
|
- Shows field only when pricing mode is "fixed"
|
||||||
|
- Hides field for "sum" mode or when using global default
|
||||||
|
- Triggers on page load and when pricing mode changes
|
||||||
|
|
||||||
|
3. **UX Improvements:**
|
||||||
|
- Field appears/disappears dynamically without page reload
|
||||||
|
- Clear visual feedback for which pricing mode is active
|
||||||
|
- Uses WooCommerce's native price input styling
|
||||||
|
- Consistent with WooCommerce admin patterns
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- includes/Admin/Product_Data.php:
|
||||||
|
- Line 66: Simplified pricing mode description text
|
||||||
|
- Lines 75-82: Added fixed price field with wrapper class
|
||||||
|
- assets/js/admin.js:
|
||||||
|
- Lines 39-54: Added price field toggle functionality
|
||||||
|
|
||||||
|
**User experience improvements:**
|
||||||
|
|
||||||
|
- ✅ Fixed price field now visible in Composable Options tab
|
||||||
|
- ✅ Field automatically shows/hides based on pricing mode selection
|
||||||
|
- ✅ Eliminates confusion about where to set the fixed price
|
||||||
|
- ✅ Follows WooCommerce UI/UX conventions
|
||||||
|
|
||||||
|
**Key lessons learned:**
|
||||||
|
|
||||||
|
1. **Reuse Standard Fields**: Using `_regular_price` instead of custom meta leverages WooCommerce's existing price handling
|
||||||
|
2. **Progressive Disclosure**: Show/hide fields based on context reduces cognitive load
|
||||||
|
3. **JavaScript + CSS Classes**: Using semantic class names (`composable_fixed_price_field`) makes JS targeting clean
|
||||||
|
4. **Trigger on Load**: Always call toggle functions on page load to set initial state
|
||||||
|
5. **Native WooCommerce Patterns**: Using `woocommerce_wp_text_input()` with `data_type: 'price'` ensures proper formatting
|
||||||
|
|
||||||
|
**Testing considerations:**
|
||||||
|
|
||||||
|
- [ ] Verify fixed price field appears when pricing mode is "fixed"
|
||||||
|
- [ ] Verify field hides when pricing mode is "sum" or default
|
||||||
|
- [ ] Test price value persistence after save
|
||||||
|
- [ ] Ensure price validation works correctly
|
||||||
|
- [ ] Check currency symbol displays for all locales
|
||||||
|
|
||||||
|
**Status:** Ready for testing and release
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### v1.1.5 - Critical Twig Filter Bug Fix (2025-12-31)
|
||||||
|
|
||||||
|
#### Session 8: Twig Template Compatibility Fix
|
||||||
|
|
||||||
|
**Critical bug fix** resolving template rendering errors when other plugins use Twig.
|
||||||
|
|
||||||
|
**The bug:**
|
||||||
|
|
||||||
|
Plugin crashed with `Twig\Error\SyntaxError: Unknown "esc_attr" filter` when rendering the product selector template on the frontend.
|
||||||
|
|
||||||
|
**Root cause analysis:**
|
||||||
|
|
||||||
|
1. **Filter vs Function mismatch**: The template used filter syntax (`{{ product.name|esc_attr }}`), but WordPress escaping functions were only registered as Twig **functions**, not **filters**
|
||||||
|
2. **Plugin conflict**: When another plugin (e.g., WooCommerce Tier and Package Prices) bundles its own Twig installation, it may parse our templates with its Twig instance
|
||||||
|
3. **Missing registrations**: That external Twig instance didn't have our custom filters registered, causing the "Unknown filter" error
|
||||||
|
|
||||||
|
**Error log evidence:**
|
||||||
|
|
||||||
|
From [logs/fatal-errors-2025-12-31.log:5](logs/fatal-errors-2025-12-31.log#L5):
|
||||||
|
|
||||||
|
```text
|
||||||
|
Uncaught Twig\Error\SyntaxError: Unknown "esc_attr" filter in "product-selector.twig" at line 26
|
||||||
|
```
|
||||||
|
|
||||||
|
The backtrace showed the error originated from `/wp-content/plugins/wc-tier-and-package-prices/vendor/twig/twig/`, proving another plugin's Twig instance was parsing our template.
|
||||||
|
|
||||||
|
**The fix:**
|
||||||
|
|
||||||
|
Added Twig filter registrations alongside existing function registrations in [includes/Plugin.php:88-91](includes/Plugin.php#L88-L91):
|
||||||
|
|
||||||
|
```php
|
||||||
|
// Add WordPress escaping functions as Twig filters
|
||||||
|
$this->twig->addFilter(new \Twig\TwigFilter('esc_html', 'esc_html'));
|
||||||
|
$this->twig->addFilter(new \Twig\TwigFilter('esc_attr', 'esc_attr'));
|
||||||
|
$this->twig->addFilter(new \Twig\TwigFilter('esc_url', 'esc_url'));
|
||||||
|
```
|
||||||
|
|
||||||
|
This allows both syntaxes to work:
|
||||||
|
|
||||||
|
- Filter syntax: `{{ product.name|esc_attr }}` ✅
|
||||||
|
- Function syntax: `{{ esc_attr(product.name) }}` ✅
|
||||||
|
|
||||||
|
**Files modified:**
|
||||||
|
|
||||||
|
- includes/Plugin.php:
|
||||||
|
- Lines 88-91: Added TwigFilter registrations for WordPress escaping functions
|
||||||
|
- wc-composable-product.php:
|
||||||
|
- Lines 6, 22: Version bump to 1.1.5
|
||||||
|
- CHANGELOG.md: Added v1.1.5 release notes with technical details
|
||||||
|
|
||||||
|
**What works (v1.1.5):**
|
||||||
|
|
||||||
|
Everything from v1.1.4 plus:
|
||||||
|
|
||||||
|
- Product selector template renders without errors ✅
|
||||||
|
- Compatible with plugins that bundle Twig (e.g., pricing plugins) ✅
|
||||||
|
- WordPress escaping works with both filter and function syntax ✅
|
||||||
|
- No more "Unknown filter" errors ✅
|
||||||
|
|
||||||
|
**Key lessons learned:**
|
||||||
|
|
||||||
|
1. **Filter vs Function Registration**: In Twig, `{{ value|filter }}` requires `TwigFilter`, while `{{ function(value) }}` requires `TwigFunction` - they're not interchangeable
|
||||||
|
2. **Multiple Twig Instances**: WordPress plugins may bundle their own Twig installations that can parse other plugins' templates
|
||||||
|
3. **Template Syntax Matters**: Using filter syntax in templates requires filter registration, even if function registration exists
|
||||||
|
4. **Defensive Compatibility**: Register WordPress functions as BOTH filters and functions for maximum compatibility
|
||||||
|
5. **Error Log Investigation**: Backtrace reveals which Twig instance is parsing the template, crucial for diagnosing multi-plugin conflicts
|
||||||
|
6. **Template Location Doesn't Matter**: Even though our template is in our plugin directory, other Twig instances can still parse it during rendering
|
||||||
|
|
||||||
|
**Debugging approach:**
|
||||||
|
|
||||||
|
1. User mentioned Twig bug in CLAUDE.md "Bugs found" section
|
||||||
|
2. Checked `logs/fatal-errors-2025-12-31.log` and found the exact error
|
||||||
|
3. Analyzed backtrace showing external Twig instance from another plugin
|
||||||
|
4. Examined template and found filter syntax (`|esc_attr`)
|
||||||
|
5. Checked Plugin.php and discovered only function registrations existed
|
||||||
|
6. Added filter registrations alongside function registrations
|
||||||
|
7. Committed fix with detailed explanation
|
||||||
|
|
||||||
|
**Impact:**
|
||||||
|
|
||||||
|
This was a **critical bug** preventing the plugin from working on sites with certain other WooCommerce extensions installed. Users would see a blank page or error when viewing composable products.
|
||||||
|
|
||||||
|
**Status:** Fixed and committed to dev branch (8fc0614)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
**For AI Assistants:**
|
**For AI Assistants:**
|
||||||
|
|
||||||
When starting a new session on this project:
|
When starting a new session on this project:
|
||||||
|
|||||||
@@ -36,6 +36,23 @@
|
|||||||
$('#composable_criteria_' + criteriaType).show();
|
$('#composable_criteria_' + criteriaType).show();
|
||||||
}).trigger('change');
|
}).trigger('change');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggle fixed price field based on pricing mode
|
||||||
|
*/
|
||||||
|
function toggleFixedPriceField() {
|
||||||
|
const pricingMode = $('#_composable_pricing_mode').val();
|
||||||
|
const $fixedPriceField = $('.composable_fixed_price_field');
|
||||||
|
|
||||||
|
if (pricingMode === 'fixed') {
|
||||||
|
$fixedPriceField.show();
|
||||||
|
} else {
|
||||||
|
$fixedPriceField.hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#_composable_pricing_mode').on('change', toggleFixedPriceField);
|
||||||
|
toggleFixedPriceField();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize enhanced select for categories and tags
|
* Initialize enhanced select for categories and tags
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ class Product_Data {
|
|||||||
woocommerce_wp_select([
|
woocommerce_wp_select([
|
||||||
'id' => '_composable_pricing_mode',
|
'id' => '_composable_pricing_mode',
|
||||||
'label' => __('Pricing Mode', 'wc-composable-product'),
|
'label' => __('Pricing Mode', 'wc-composable-product'),
|
||||||
'description' => __('How to calculate the price. Leave empty to use global default.', 'wc-composable-product'),
|
'description' => __('How to calculate the price.', 'wc-composable-product'),
|
||||||
'desc_tip' => true,
|
'desc_tip' => true,
|
||||||
'options' => [
|
'options' => [
|
||||||
'' => __('Use global default', 'wc-composable-product'),
|
'' => __('Use global default', 'wc-composable-product'),
|
||||||
@@ -72,6 +72,16 @@ class Product_Data {
|
|||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
woocommerce_wp_text_input([
|
||||||
|
'id' => '_regular_price',
|
||||||
|
'label' => __('Fixed Price', 'wc-composable-product') . ' (' . get_woocommerce_currency_symbol() . ')',
|
||||||
|
'description' => __('Enter the fixed price for this composable product.', 'wc-composable-product'),
|
||||||
|
'desc_tip' => true,
|
||||||
|
'type' => 'text',
|
||||||
|
'data_type' => 'price',
|
||||||
|
'wrapper_class' => 'composable_fixed_price_field',
|
||||||
|
]);
|
||||||
|
|
||||||
echo '</div>';
|
echo '</div>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,14 +185,25 @@ class Cart_Handler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use static flag to prevent multiple executions
|
||||||
|
static $already_calculated = false;
|
||||||
|
if ($already_calculated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
|
foreach ($cart->get_cart() as $cart_item_key => $cart_item) {
|
||||||
if (isset($cart_item['data']) && $cart_item['data']->get_type() === 'composable') {
|
if (isset($cart_item['data']) && $cart_item['data']->get_type() === 'composable') {
|
||||||
if (isset($cart_item['composable_products'])) {
|
if (isset($cart_item['composable_products']) && !isset($cart_item['composable_price_calculated'])) {
|
||||||
$product = $cart_item['data'];
|
$product = $cart_item['data'];
|
||||||
$price = $product->calculate_composed_price($cart_item['composable_products']);
|
$price = $product->calculate_composed_price($cart_item['composable_products']);
|
||||||
$cart_item['data']->set_price($price);
|
$cart_item['data']->set_price($price);
|
||||||
|
|
||||||
|
// Mark as calculated to prevent re-calculation by other plugins
|
||||||
|
$cart->cart_contents[$cart_item_key]['composable_price_calculated'] = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$already_calculated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,13 +84,19 @@ class Plugin {
|
|||||||
$this->twig->addFunction(new \Twig\TwigFunction('esc_html', 'esc_html'));
|
$this->twig->addFunction(new \Twig\TwigFunction('esc_html', 'esc_html'));
|
||||||
$this->twig->addFunction(new \Twig\TwigFunction('esc_attr', 'esc_attr'));
|
$this->twig->addFunction(new \Twig\TwigFunction('esc_attr', 'esc_attr'));
|
||||||
$this->twig->addFunction(new \Twig\TwigFunction('esc_url', 'esc_url'));
|
$this->twig->addFunction(new \Twig\TwigFunction('esc_url', 'esc_url'));
|
||||||
|
|
||||||
|
// Add WordPress escaping functions as Twig filters
|
||||||
|
$this->twig->addFilter(new \Twig\TwigFilter('esc_html', 'esc_html'));
|
||||||
|
$this->twig->addFilter(new \Twig\TwigFilter('esc_attr', 'esc_attr'));
|
||||||
|
$this->twig->addFilter(new \Twig\TwigFilter('esc_url', 'esc_url'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include required files
|
* Include required files
|
||||||
*/
|
*/
|
||||||
private function includes() {
|
private function includes() {
|
||||||
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Settings.php';
|
// Note: Settings.php is NOT included here because it extends WC_Settings_Page
|
||||||
|
// which isn't loaded until later. It's included in add_settings_page() instead.
|
||||||
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Product_Data.php';
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Product_Data.php';
|
||||||
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Product_Type.php';
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Product_Type.php';
|
||||||
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Stock_Manager.php';
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Stock_Manager.php';
|
||||||
@@ -191,6 +197,8 @@ class Plugin {
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function add_settings_page($settings) {
|
public function add_settings_page($settings) {
|
||||||
|
// Include Settings.php here, when WC_Settings_Page is guaranteed to be loaded
|
||||||
|
require_once WC_COMPOSABLE_PRODUCT_PATH . 'includes/Admin/Settings.php';
|
||||||
$settings[] = new Admin\Settings();
|
$settings[] = new Admin\Settings();
|
||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -144,8 +144,16 @@ msgid "Pricing Mode"
|
|||||||
msgstr "Preismodus"
|
msgstr "Preismodus"
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "How to calculate the price. Leave empty to use global default."
|
msgid "How to calculate the price."
|
||||||
msgstr "Wie der Preis berechnet wird. Leer lassen, um den globalen Standard zu verwenden."
|
msgstr "Wie der Preis berechnet wird."
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Fixed Price"
|
||||||
|
msgstr "Festpreis"
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Enter the fixed price for this composable product."
|
||||||
|
msgstr "Geben Sie den Festpreis für dieses zusammenstellbare Produkt ein."
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "Use global default"
|
msgid "Use global default"
|
||||||
@@ -198,3 +206,35 @@ msgstr "Geben Sie Produkt-Artikelnummern durch Kommas getrennt ein."
|
|||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "SKU-1, SKU-2, SKU-3"
|
msgid "SKU-1, SKU-2, SKU-3"
|
||||||
msgstr "ART-1, ART-2, ART-3"
|
msgstr "ART-1, ART-2, ART-3"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "\"%s\" is out of stock and cannot be selected."
|
||||||
|
msgstr "\"%s\" ist nicht an Lager und kann nicht ausgewählt werden."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Only %2$d of \"%1$s\" are available in stock."
|
||||||
|
msgstr "Nur %2$d von \"%1$s\" sind an Lager verfügbar."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock reduced for \"%1$s\": -%2$d (remaining: %3$d)"
|
||||||
|
msgstr "Lagerbestand reduziert für \"%1$s\": -%2$d (verbleibend: %3$d)"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock restored for \"%1$s\": +%2$d (total: %3$d)"
|
||||||
|
msgstr "Lagerbestand wiederhergestellt für \"%1$s\": +%2$d (gesamt: %3$d)"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Out of stock"
|
||||||
|
msgstr "Nicht an Lager"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Only"
|
||||||
|
msgstr "Nur"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "left"
|
||||||
|
msgstr "übrig"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "In stock"
|
||||||
|
msgstr "An Lager"
|
||||||
|
|||||||
@@ -144,8 +144,16 @@ msgid "Pricing Mode"
|
|||||||
msgstr "Preismodus"
|
msgstr "Preismodus"
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "How to calculate the price. Leave empty to use global default."
|
msgid "How to calculate the price."
|
||||||
msgstr "Wie der Preis berechnet wird. Leer lassen, um den globalen Standard zu verwenden."
|
msgstr "Wie der Preis berechnet wird."
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Fixed Price"
|
||||||
|
msgstr "Festpreis"
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Enter the fixed price for this composable product."
|
||||||
|
msgstr "Gib den Festpreis für dieses zusammenstellbare Produkt ein."
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "Use global default"
|
msgid "Use global default"
|
||||||
@@ -198,3 +206,35 @@ msgstr "Gib Produkt-Artikelnummern durch Kommas getrennt ein."
|
|||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "SKU-1, SKU-2, SKU-3"
|
msgid "SKU-1, SKU-2, SKU-3"
|
||||||
msgstr "ART-1, ART-2, ART-3"
|
msgstr "ART-1, ART-2, ART-3"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "\"%s\" is out of stock and cannot be selected."
|
||||||
|
msgstr "\"%s\" ist nicht an Lager und kann nicht ausgewählt werden."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Only %2$d of \"%1$s\" are available in stock."
|
||||||
|
msgstr "Nur %2$d von \"%1$s\" sind an Lager verfügbar."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock reduced for \"%1$s\": -%2$d (remaining: %3$d)"
|
||||||
|
msgstr "Lagerbestand reduziert für \"%1$s\": -%2$d (verbleibend: %3$d)"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock restored for \"%1$s\": +%2$d (total: %3$d)"
|
||||||
|
msgstr "Lagerbestand wiederhergestellt für \"%1$s\": +%2$d (gesamt: %3$d)"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Out of stock"
|
||||||
|
msgstr "Nicht an Lager"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Only"
|
||||||
|
msgstr "Nur"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "left"
|
||||||
|
msgstr "übrig"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "In stock"
|
||||||
|
msgstr "An Lager"
|
||||||
|
|||||||
@@ -144,8 +144,16 @@ msgid "Pricing Mode"
|
|||||||
msgstr "Preismodus"
|
msgstr "Preismodus"
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "How to calculate the price. Leave empty to use global default."
|
msgid "How to calculate the price."
|
||||||
msgstr "Wie der Preis berechnet wird. Leer lassen, um den globalen Standard zu verwenden."
|
msgstr "Wie der Preis berechnet wird."
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Fixed Price"
|
||||||
|
msgstr "Festpreis"
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Enter the fixed price for this composable product."
|
||||||
|
msgstr "Geben Sie den Festpreis für dieses zusammenstellbare Produkt ein."
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "Use global default"
|
msgid "Use global default"
|
||||||
@@ -198,3 +206,35 @@ msgstr "Geben Sie Produkt-Artikelnummern durch Kommas getrennt ein."
|
|||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "SKU-1, SKU-2, SKU-3"
|
msgid "SKU-1, SKU-2, SKU-3"
|
||||||
msgstr "ART-1, ART-2, ART-3"
|
msgstr "ART-1, ART-2, ART-3"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "\"%s\" is out of stock and cannot be selected."
|
||||||
|
msgstr "\"%s\" ist nicht auf Lager und kann nicht ausgewählt werden."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Only %2$d of \"%1$s\" are available in stock."
|
||||||
|
msgstr "Nur %2$d von \"%1$s\" sind auf Lager verfügbar."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock reduced for \"%1$s\": -%2$d (remaining: %3$d)"
|
||||||
|
msgstr "Lagerbestand reduziert für \"%1$s\": -%2$d (verbleibend: %3$d)"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock restored for \"%1$s\": +%2$d (total: %3$d)"
|
||||||
|
msgstr "Lagerbestand wiederhergestellt für \"%1$s\": +%2$d (gesamt: %3$d)"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Out of stock"
|
||||||
|
msgstr "Nicht auf Lager"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Only"
|
||||||
|
msgstr "Nur"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "left"
|
||||||
|
msgstr "übrig"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "In stock"
|
||||||
|
msgstr "Auf Lager"
|
||||||
|
|||||||
@@ -144,8 +144,16 @@ msgid "Pricing Mode"
|
|||||||
msgstr "Preismodus"
|
msgstr "Preismodus"
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "How to calculate the price. Leave empty to use global default."
|
msgid "How to calculate the price."
|
||||||
msgstr "Wie der Preis berechnet wird. Leer lassen, um den globalen Standard zu verwenden."
|
msgstr "Wie der Preis berechnet wird."
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Fixed Price"
|
||||||
|
msgstr "Festpreis"
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Enter the fixed price for this composable product."
|
||||||
|
msgstr "Gib den Festpreis für dieses zusammenstellbare Produkt ein."
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "Use global default"
|
msgid "Use global default"
|
||||||
@@ -198,3 +206,35 @@ msgstr "Gib Produkt-Artikelnummern durch Kommas getrennt ein."
|
|||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "SKU-1, SKU-2, SKU-3"
|
msgid "SKU-1, SKU-2, SKU-3"
|
||||||
msgstr "ART-1, ART-2, ART-3"
|
msgstr "ART-1, ART-2, ART-3"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "\"%s\" is out of stock and cannot be selected."
|
||||||
|
msgstr "\"%s\" ist nicht auf Lager und kann nicht ausgewählt werden."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Only %2$d of \"%1$s\" are available in stock."
|
||||||
|
msgstr "Nur %2$d von \"%1$s\" sind auf Lager verfügbar."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock reduced for \"%1$s\": -%2$d (remaining: %3$d)"
|
||||||
|
msgstr "Lagerbestand reduziert für \"%1$s\": -%2$d (verbleibend: %3$d)"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock restored for \"%1$s\": +%2$d (total: %3$d)"
|
||||||
|
msgstr "Lagerbestand wiederhergestellt für \"%1$s\": +%2$d (gesamt: %3$d)"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Out of stock"
|
||||||
|
msgstr "Nicht auf Lager"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Only"
|
||||||
|
msgstr "Nur"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "left"
|
||||||
|
msgstr "übrig"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "In stock"
|
||||||
|
msgstr "Auf Lager"
|
||||||
|
|||||||
@@ -144,8 +144,16 @@ msgid "Pricing Mode"
|
|||||||
msgstr "Mode de tarification"
|
msgstr "Mode de tarification"
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "How to calculate the price. Leave empty to use global default."
|
msgid "How to calculate the price."
|
||||||
msgstr "Comment calculer le prix. Laisser vide pour utiliser la valeur par défaut globale."
|
msgstr "Comment calculer le prix."
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Fixed Price"
|
||||||
|
msgstr "Prix fixe"
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Enter the fixed price for this composable product."
|
||||||
|
msgstr "Entrez le prix fixe pour ce produit composable."
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "Use global default"
|
msgid "Use global default"
|
||||||
@@ -198,3 +206,35 @@ msgstr "Entrez les références des produits séparées par des virgules."
|
|||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "SKU-1, SKU-2, SKU-3"
|
msgid "SKU-1, SKU-2, SKU-3"
|
||||||
msgstr "REF-1, REF-2, REF-3"
|
msgstr "REF-1, REF-2, REF-3"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "\"%s\" is out of stock and cannot be selected."
|
||||||
|
msgstr "\"%s\" est en rupture de stock et ne peut pas être sélectionné."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Only %2$d of \"%1$s\" are available in stock."
|
||||||
|
msgstr "Seulement %2$d de \"%1$s\" sont disponibles en stock."
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock reduced for \"%1$s\": -%2$d (remaining: %3$d)"
|
||||||
|
msgstr "Stock réduit pour \"%1$s\": -%2$d (restant: %3$d)"
|
||||||
|
|
||||||
|
#: includes/Stock_Manager.php
|
||||||
|
msgid "Stock restored for \"%1$s\": +%2$d (total: %3$d)"
|
||||||
|
msgstr "Stock restauré pour \"%1$s\": +%2$d (total: %3$d)"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Out of stock"
|
||||||
|
msgstr "Rupture de stock"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "Only"
|
||||||
|
msgstr "Seulement"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "left"
|
||||||
|
msgstr "restant"
|
||||||
|
|
||||||
|
#: templates/product-selector.twig
|
||||||
|
msgid "In stock"
|
||||||
|
msgstr "En stock"
|
||||||
|
|||||||
@@ -144,8 +144,16 @@ msgid "Pricing Mode"
|
|||||||
msgstr "Modalità di prezzo"
|
msgstr "Modalità di prezzo"
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "How to calculate the price. Leave empty to use global default."
|
msgid "How to calculate the price."
|
||||||
msgstr "Come calcolare il prezzo. Lasciare vuoto per utilizzare il valore predefinito globale."
|
msgstr "Come calcolare il prezzo."
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Fixed Price"
|
||||||
|
msgstr "Prezzo fisso"
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Enter the fixed price for this composable product."
|
||||||
|
msgstr "Inserisci il prezzo fisso per questo prodotto componibile."
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "Use global default"
|
msgid "Use global default"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
# This file is distributed under the GPL v3 or later.
|
# This file is distributed under the GPL v3 or later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: WooCommerce Composable Products 1.0.0\n"
|
"Project-Id-Version: WooCommerce Composable Products 1.1.6\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/magdev/wc-composable-product/issues\n"
|
"Report-Msgid-Bugs-To: https://github.com/magdev/wc-composable-product/issues\n"
|
||||||
"POT-Creation-Date: 2024-12-31 00:00+0000\n"
|
"POT-Creation-Date: 2024-12-31 00:00+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
@@ -143,7 +143,15 @@ msgid "Pricing Mode"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
msgid "How to calculate the price. Leave empty to use global default."
|
msgid "How to calculate the price."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Fixed Price"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/Product_Data.php
|
||||||
|
msgid "Enter the fixed price for this composable product."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/Product_Data.php
|
#: includes/Admin/Product_Data.php
|
||||||
|
|||||||
BIN
releases/wc-composable-product-v1.0.0.zip
Normal file
BIN
releases/wc-composable-product-v1.0.0.zip
Normal file
Binary file not shown.
1
releases/wc-composable-product-v1.0.0.zip.md5
Normal file
1
releases/wc-composable-product-v1.0.0.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
aec3bae001f0013322a73fa941169688 wc-composable-product-v1.0.0.zip
|
||||||
1
releases/wc-composable-product-v1.0.0.zip.sha256
Normal file
1
releases/wc-composable-product-v1.0.0.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4a0f7ec2171aeabfdfe155419fd6124f35f3e14501ee2ca324bbab447259a8bb wc-composable-product-v1.0.0.zip
|
||||||
BIN
releases/wc-composable-product-v1.1.0.zip
Normal file
BIN
releases/wc-composable-product-v1.1.0.zip
Normal file
Binary file not shown.
1
releases/wc-composable-product-v1.1.0.zip.md5
Normal file
1
releases/wc-composable-product-v1.1.0.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0a60816bbc5a01c0057c1ffa72679d93 releases/wc-composable-product-v1.1.0.zip
|
||||||
1
releases/wc-composable-product-v1.1.0.zip.sha256
Normal file
1
releases/wc-composable-product-v1.1.0.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
645fdd68aca95cba77d961f3a48d41b9c12b3d17552572b7c039575dcfcab693 releases/wc-composable-product-v1.1.0.zip
|
||||||
BIN
releases/wc-composable-product-v1.1.1.zip
Normal file
BIN
releases/wc-composable-product-v1.1.1.zip
Normal file
Binary file not shown.
1
releases/wc-composable-product-v1.1.1.zip.md5
Normal file
1
releases/wc-composable-product-v1.1.1.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
db09928aea6fffbf9c2e754d2264f2bc wc-composable-product-v1.1.1.zip
|
||||||
1
releases/wc-composable-product-v1.1.1.zip.sha256
Normal file
1
releases/wc-composable-product-v1.1.1.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
761eef69da910ecfdb20ceeed70b5d0381c7cab895e81a040d132cb0f88d749b wc-composable-product-v1.1.1.zip
|
||||||
BIN
releases/wc-composable-product-v1.1.2.zip
Normal file
BIN
releases/wc-composable-product-v1.1.2.zip
Normal file
Binary file not shown.
1
releases/wc-composable-product-v1.1.2.zip.md5
Normal file
1
releases/wc-composable-product-v1.1.2.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
37cef191778b448dcbd2ae10141f64c6 wc-composable-product-v1.1.2.zip
|
||||||
1
releases/wc-composable-product-v1.1.2.zip.sha256
Normal file
1
releases/wc-composable-product-v1.1.2.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
191eae035b34ce8b33b90cf9d85ed54e493c1b471cda0efe5c992a512e91cc36 wc-composable-product-v1.1.2.zip
|
||||||
BIN
releases/wc-composable-product-v1.1.3.zip
Normal file
BIN
releases/wc-composable-product-v1.1.3.zip
Normal file
Binary file not shown.
1
releases/wc-composable-product-v1.1.3.zip.md5
Normal file
1
releases/wc-composable-product-v1.1.3.zip.md5
Normal file
@@ -0,0 +1 @@
|
|||||||
|
9bbed416019a796b4d4a5ef72e016e1f wc-composable-product-v1.1.3.zip
|
||||||
1
releases/wc-composable-product-v1.1.3.zip.sha256
Normal file
1
releases/wc-composable-product-v1.1.3.zip.sha256
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0ca23ca12570f0e9c518514ffc5209d78c76c3295954d10ec74a28013a762956 wc-composable-product-v1.1.3.zip
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
* Plugin Name: WooCommerce Composable Products
|
* Plugin Name: WooCommerce Composable Products
|
||||||
* Plugin URI: https://github.com/magdev/wc-composable-product
|
* Plugin URI: https://github.com/magdev/wc-composable-product
|
||||||
* Description: Create composable products where customers select a limited number of items from a configurable set
|
* Description: Create composable products where customers select a limited number of items from a configurable set
|
||||||
* Version: 1.1.0
|
* Version: 1.1.6
|
||||||
* Author: Marco Graetsch
|
* Author: Marco Graetsch
|
||||||
* Author URI: https://example.com
|
* Author URI: https://example.com
|
||||||
* License: GPL v3 or later
|
* License: GPL v3 or later
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
defined('ABSPATH') || exit;
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
// Define plugin constants
|
// Define plugin constants
|
||||||
define('WC_COMPOSABLE_PRODUCT_VERSION', '1.1.0');
|
define('WC_COMPOSABLE_PRODUCT_VERSION', '1.1.6');
|
||||||
define('WC_COMPOSABLE_PRODUCT_FILE', __FILE__);
|
define('WC_COMPOSABLE_PRODUCT_FILE', __FILE__);
|
||||||
define('WC_COMPOSABLE_PRODUCT_PATH', plugin_dir_path(__FILE__));
|
define('WC_COMPOSABLE_PRODUCT_PATH', plugin_dir_path(__FILE__));
|
||||||
define('WC_COMPOSABLE_PRODUCT_URL', plugin_dir_url(__FILE__));
|
define('WC_COMPOSABLE_PRODUCT_URL', plugin_dir_url(__FILE__));
|
||||||
@@ -61,8 +61,17 @@ function wc_composable_product_init() {
|
|||||||
// Initialize main plugin class
|
// Initialize main plugin class
|
||||||
WC_Composable_Product\Plugin::instance();
|
WC_Composable_Product\Plugin::instance();
|
||||||
}
|
}
|
||||||
// Use woocommerce_loaded to ensure WooCommerce classes are available
|
// Use woocommerce_init to ensure all WooCommerce classes including settings are loaded
|
||||||
add_action('woocommerce_loaded', 'wc_composable_product_init');
|
add_action('woocommerce_init', 'wc_composable_product_init');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declare HPOS compatibility
|
||||||
|
*/
|
||||||
|
add_action('before_woocommerce_init', function() {
|
||||||
|
if (class_exists(\Automattic\WooCommerce\Utilities\FeaturesUtil::class)) {
|
||||||
|
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activation hook
|
* Activation hook
|
||||||
|
|||||||
Reference in New Issue
Block a user