# 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.2.8] - 2025-12-30

### Fixed

- **Currency Symbol Missing in Admin Headers and Placeholders**: Table headers in the admin pricing configuration now display "Price (CURRENCY)" instead of just "Price", making it immediately clear which currency is being used. Price input placeholders now show currency symbol (e.g., "e.g., 9.99 $" instead of "e.g., 9.99"), providing better UX for administrators configuring pricing in different currencies.

- **Variation Pricing Data Not Deleted Properly (Critical)**: When administrators deleted all tier or package pricing entries from a variation (or simple/parent product) and saved, the empty pricing data was still stored in the database instead of being deleted. This caused variations to retain deleted pricing rules. The save logic now properly detects when the filtered pricing arrays are empty after removing invalid entries and deletes the post meta instead of saving empty arrays.

### Technical Details

**Currency Symbol Enhancement**:
- Updated all table headers to use `printf(__('Price (%s)', 'wc-tier-package-prices'), get_woocommerce_currency_symbol())`
- Modified `render_tier_row()` and `render_package_row()` methods to pass `currency_symbol` to Twig templates
- Updated `render_variation_tier_row()` and `render_variation_package_row()` with same currency symbol parameter
- Changed Twig template placeholders from `'e.g., 9.99'` to `('e.g., 9.99 ' ~ currency_symbol)`
- Affects all pricing contexts: simple products, variable product parents, and variations

**Pricing Deletion Fix**:
- Modified `save_tier_package_fields()` method (simple/parent products) to check `if (!empty($tiers))` before saving
- Modified `save_variation_pricing_fields()` method (variations) with same empty check logic
- Changed logic from "save on isset, delete otherwise" to "filter entries, then save if not empty, delete if empty"
- Applies to both tier pricing and package pricing for all product types
- Root cause was filtering out empty entries but still calling `update_post_meta()` with an empty array

**User Impact**:
- Administrators see currency symbol in all pricing configuration interfaces
- Clear indication of which currency prices should be entered in
- Deleting all pricing rules now properly removes them from the database
- No orphaned pricing data remains after deletion
- Works correctly for simple products, variable product parents, and variations

### Changed Files

- `includes/class-wc-tpp-product-meta.php` - Added currency symbol to all table headers; updated all render methods to pass currency symbol; fixed empty array deletion logic in both save methods
- `templates/admin/tier-row.twig` - Updated placeholder to include currency symbol
- `templates/admin/package-row.twig` - Updated placeholder to include currency symbol

## [1.2.7] - 2025-12-30

### Fixed

- **Variable Product Forms Still Not Showing (Critical)**: The v1.2.6 fix used the wrong WooCommerce hook. The `woocommerce_product_options_pricing` hook only fires for simple products, not variable products. Changed to use `woocommerce_product_options_general_product_data` hook which fires for all product types after the general tab, allowing the code to check product type and conditionally display the parent pricing fields.

- **Table Headers Still Visible When Empty (Critical)**: The CSS `:has()` pseudo-class approach from v1.2.6 wasn't working reliably across all browsers. Implemented a JavaScript-based solution that adds/removes a `has-rows` class on tables based on whether they contain pricing rules. Headers now hide by default and show only when the table has rows, with JavaScript updating the state when rows are added or removed.

### Technical Details

**Variable Product Hook Fix**:
- Changed from `woocommerce_product_options_pricing` to `woocommerce_product_options_general_product_data`
- The general product data hook fires for all product types
- Method still checks `$product->is_type('variable')` to only show for variable products
- This ensures forms appear in the correct location in the WordPress admin

**Table Header Visibility Fix**:
- Replaced CSS-only `:has()` solution with JavaScript + CSS class approach
- CSS now uses `.wc-tpp-tiers-table.has-rows thead` to show headers
- Added `updateTableHeaders()` JavaScript function that checks row count and toggles class
- Function is called on page load and after any add/remove row operation
- Works reliably across all browsers without requiring modern CSS features

**User Impact**:
- Variable product parent pricing forms now actually appear in the WordPress admin
- Table headers properly hide when empty and show when populated
- No browser compatibility issues - works in all modern browsers

### Changed Files

- `includes/class-wc-tpp-product-meta.php` - Changed hook from `woocommerce_product_options_pricing` to `woocommerce_product_options_general_product_data`
- `assets/css/admin.css` - Replaced `:has()` pseudo-class with class-based approach
- `assets/js/admin.js` - Added `updateTableHeaders()` function and calls after all row operations; added handlers for variable product parent forms

## [1.2.6] - 2025-12-30

### Fixed

- **Parent Product Pricing Forms Not Visible (Critical)**: Variable products were missing the pricing configuration forms on the parent product edit page. The v1.2.5 feature for parent product default pricing was implemented in the backend logic (cart calculations and frontend display) but the admin UI to configure these defaults was not added. Now variable product parents have a dedicated "Default Tier & Package Pricing for All Variations" section in the product edit page where administrators can configure default pricing that applies to all variations unless a specific variation overrides it.

- **Table Headers Not Hiding When Empty**: The CSS selector for hiding table headers when no pricing rules exist was using an incorrect approach. The sibling selector `~` doesn't work when `<thead>` comes before `<tbody>` in the HTML structure. Removed the sibling selector and kept only the `:has()` pseudo-class approach with `!important` flag for proper specificity.

### Technical Details

**Parent Product Forms Fix**:
- Added new method `add_variable_parent_pricing_fields()` in `WC_TPP_Product_Meta` class
- Hooked to `woocommerce_product_options_pricing` action but only displays for variable products
- Modified existing `add_tier_pricing_fields()` and `add_package_pricing_fields()` to skip variable products (they now only show for simple products)
- Parent product forms use same field names as simple products (`_wc_tpp_tiers`, `_wc_tpp_packages`, `_wc_tpp_restrict_to_packages`)
- Data is saved to parent product post meta using existing `save_tier_package_fields()` method
- Backend fallback logic from v1.2.5 now has matching admin UI for configuration

**CSS Selector Fix**:
- Removed incorrect `.wc-tpp-tiers-container:empty ~ thead` selector (sibling selector can't target previous elements)
- Kept only `.wc-tpp-tiers-table:has(tbody.wc-tpp-tiers-container:empty) thead` with `!important` flag
- `:has()` pseudo-class is supported in modern browsers (Chrome 105+, Firefox 121+, Safari 15.4+)

**User Impact**:
- Administrators can now configure default tier/package pricing on variable product parents (feature was non-functional in v1.2.5)
- Table headers properly hide when no pricing rules exist, creating cleaner admin interface
- No data migration needed - existing configurations remain intact

### Changed Files

- `includes/class-wc-tpp-product-meta.php` - Added `add_variable_parent_pricing_fields()` method; modified `add_tier_pricing_fields()` and `add_package_pricing_fields()` to skip variable products
- `assets/css/admin.css` - Fixed table header hiding CSS selector; removed incorrect sibling selector; added `!important` flag

## [1.2.5] - 2025-12-30

### Added

- **Parent Product Default Pricing**: Variable products can now define tier and package pricing at the parent product level that applies as defaults to all variations. Individual variations can override these defaults with their own specific pricing. This makes it much easier to set up pricing for products with many variations - set defaults once on the parent, then only customize the variations that need different pricing.

- **Hide Empty Table Headers**: Table headers for tier and package pricing in the admin area now automatically hide when no pricing rules are defined. This creates a cleaner interface when starting to configure a product, showing only the helpful empty state message and "Add" button.

### Technical Details

**Parent Fallback Implementation**:
- Modified `WC_TPP_Frontend::get_tier_price()` and `WC_TPP_Frontend::get_package_price()` to fall back to parent product pricing when variation doesn't have its own pricing
- Updated `WC_TPP_Cart` to use helper methods `get_packages_with_fallback()` and `is_restriction_enabled()` for consistent parent fallback behavior
- All cart validation, quantity restriction, and display methods now support parent product defaults
- Fixed cart pricing calls to pass parent `$product_id` instead of `$effective_id` for proper fallback resolution

**CSS Enhancement**:
- Added `:has()` pseudo-class selectors to hide table headers when tbody is empty
- Leverages existing empty state message styling for consistent UX

**Backward Compatibility**:
- 100% backward compatible - existing products continue working as before
- No database migrations required
- Variations with specific pricing take precedence over parent defaults

### Changed Files

- `includes/class-wc-tpp-frontend.php` - Added parent fallback logic to `get_tier_price()` and `get_package_price()` methods
- `includes/class-wc-tpp-cart.php` - Added helper methods `get_packages_with_fallback()` and `is_restriction_enabled()`; updated all cart methods to support parent fallback; fixed pricing calls to use correct product ID
- `assets/css/admin.css` - Added CSS rules to hide table headers when no pricing rules exist

## [1.2.4] - 2025-12-30

### Fixed

- **Admin Table Borders (Critical)**: Fixed table borders still appearing in v1.2.3 despite borderless styling attempt. WooCommerce's default CSS was overriding `border: none` declarations. Added `!important` flags to all border removal rules and `border-collapse: collapse !important` to force borderless styling. Now all tier/package pricing tables (simple and variable products) display correctly without borders, matching WooCommerce's clean admin UI.

- **Checkbox and Help Icon Layout**: Fixed help icon positioning and checkbox spacing issues from v1.2.3. The help icon was appearing at the right edge of the container instead of next to the label text. Increased checkbox-label margin from 8px to 12px for better spacing. Changed label layout from float positioning to flexbox (`inline-flex`) to keep help icon directly adjacent to label text. Added inline description hiding when tooltip is shown.

### Technical Details

**Root Cause - Table Borders**: WooCommerce's core admin CSS has higher specificity border rules that override simple `border: none` declarations. The solution required:
- Adding `!important` to all `border: none` rules targeting tables, th, td, thead, tbody, and tr elements
- Adding `border-collapse: collapse !important` to prevent cell borders from being visible
- Comprehensive targeting of all table structural elements for complete border removal

**Root Cause - Help Icon Position**: WooCommerce's default `.woocommerce-help-tip` styling uses `float: right` which positions the icon at the container's right edge. The fix:
- Removed float positioning with `float: none`
- Changed to `display: inline-block` with `vertical-align: middle`
- Wrapped label and help-tip in flexbox container (`display: inline-flex; align-items: center`)
- Controlled spacing with precise margins (checkbox: 12px right, help-tip: 6px left)

### Changed Files

- `assets/css/admin.css` - Added `!important` flags to all border removal rules; added `border-collapse: collapse`; increased checkbox margin to 12px; converted label layout to flexbox; positioned help-tip with inline-block; added inline description hiding

## [1.2.3] - 2025-12-29

### Fixed

- **Admin Table Styling**: Applied borderless table styling to all tier/package tables (both simple and variable products). Previously only variation tables had borders removed in v1.2.2. Now all pricing tables in the admin have a consistent borderless appearance matching WooCommerce's clean admin UI style.

- **Checkbox Styling and Tooltip**: Fixed checkbox styling issues where the help text was displayed inline instead of as a tooltip, and the margin between checkbox and label was too small. Added `desc_tip => true` to the variation restriction checkbox to enable tooltip display. Added CSS rules to increase checkbox-label margin to 8px and hide inline description text when tooltips are used.

### Changed Files

- `assets/css/admin.css` - Applied `border: none` to all tier/package table elements; added checkbox margin and description hiding rules
- `includes/class-wc-tpp-product-meta.php` - Added `desc_tip => true` parameter to variation checkbox (line 213)

## [1.2.2] - 2025-12-29

### Fixed

- **Variation UI Styling**: Removed table borders for variation pricing tables to match WooCommerce's borderless variation UI style. Added CSS rules specifically targeting `.wc-tpp-variation-pricing` tables to remove borders while keeping them for simple product tables.

- **Missing Translations**: Added missing admin template translations for "Min Quantity", "Price", and "Label (optional)" to all language files (de_DE, de_DE_informal, de_CH, de_CH_informal, fr_CH, it_CH, en_US). These strings were used in the variation admin UI added in v1.2.0 but weren't included in translation files.

- **Checkbox Rendering**: Fixed variation restriction checkbox rendering issue. The `wc_tpp_restrict_to_packages[]` checkbox in variation pricing fields was using a ternary expression that prevented proper checked state handling. Simplified to direct value assignment for WooCommerce's checkbox function to work correctly.

### Changed Files

- `assets/css/admin.css` - Added border removal for variation pricing tables
- `includes/class-wc-tpp-product-meta.php` - Fixed checkbox value parameter (line 213)
- `languages/*.po` - Added missing translation entries
- `languages/*.mo` - Recompiled from updated .po files

## [1.2.1] - 2025-12-29

### Fixed

- **Admin UI Display**: Fixed table layout in admin product edit screens. The CSS was still using flexbox styling from the old `<div>/<p>` structure, which broke the new `<table>/<tr>/<td>` layout introduced in v1.2.0. Updated `assets/css/admin.css` to properly style table rows with standard table cell padding and removed obsolete flexbox properties.

- **Frontend Pricing Display**: Fixed pricing tables not showing on simple product pages. Removed global "Enable Tier Pricing" and "Enable Package Pricing" checks from the frontend template (`templates/frontend/pricing-table.twig`). Pricing tables now display if configured on a product AND the "Display Pricing Table" setting is enabled, regardless of individual feature enable settings. Cart calculations still respect global enable settings for proper pricing application.

### Technical Details

**Root Cause - Admin UI Bug**: In v1.2.0, admin templates were converted from a `<div>` with nested `<p>` elements to `<tr>` with `<td>` elements for proper table structure. However, the CSS file (`assets/css/admin.css`) was not updated accordingly, leaving flexbox styling (`.wc-tpp-tier-row { display: flex; gap: 15px; ... }`) that conflicted with table display. This caused columns to not align with table headers.

**Root Cause - Frontend Display Bug**: The frontend pricing table template was checking both `get_option('wc_tpp_enable_tier_pricing')` AND `get_option('wc_tpp_enable_package_pricing')` before displaying pricing. This meant if these global settings were disabled (even though defaults are 'yes'), pricing configured on products wouldn't show. The better UX is: if pricing is configured AND display is enabled, show it. The global enable settings now only control cart calculation and admin UI visibility.

### Changed Files

- `assets/css/admin.css` - Replaced flexbox styling with table cell styling
- `templates/frontend/pricing-table.twig` - Removed global enable setting checks from display conditions

## [1.2.0] - 2025-12-29

### Added - Variable Product Support

**Major Feature**: Complete support for WooCommerce variable products with variation-level pricing

- Variable products can now have tier and package pricing configured independently for each variation
- Admin UI: Each variation displays tier/package pricing fields in the variation edit panel
- Frontend: Pricing tables load dynamically via AJAX when customer selects a variation
- Cart: Variation-specific pricing correctly applied during checkout
- Quantity restrictions work per-variation (not just per-product)
- Catalog buttons: "View Options" appears for variable products with restricted variations

### Changed

- **Admin Templates**: Converted tier/package row templates from `<div>` to `<tr>` table structure for better layout
- **Admin UI**: Simple product pricing fields now use table layout for consistency with variations
- **Frontend Display**: Variable products show placeholder container; pricing appears on variation selection
- **Cart Logic**: All cart methods now use "effective ID" pattern (variation ID when present, product ID otherwise)
- **Template System**: Added `field_prefix` parameter support to admin templates for variation field naming

### Technical Details

#### Backend Changes

- **class-wc-tpp-cart.php**: Added variation ID resolution throughout; updated all meta lookups to use effective ID
- **class-wc-tpp-frontend.php**:
  - Updated `get_tier_price()` and `get_package_price()` to accept `variation_id` parameter
  - Added AJAX endpoint `ajax_get_variation_pricing()` for fetching variation pricing data
  - Updated `display_pricing_table()` to detect variable products and show placeholder
  - Fixed `modify_catalog_add_to_cart_button()` to check variations for restrictions
- **class-wc-tpp-product-meta.php**:
  - Added hooks: `woocommerce_variation_options_pricing`, `woocommerce_save_product_variation`
  - New method: `add_variation_pricing_fields()` - renders pricing UI in variation panels
  - New method: `save_variation_pricing_fields()` - saves variation-specific pricing data
  - New methods: `render_variation_tier_row()`, `render_variation_package_row()` - variation rendering helpers

#### Frontend Changes

- **frontend.js**:
  - Added variation selector integration listening to `found_variation` and `reset_data` events
  - Implemented AJAX fetching of variation pricing when variation selected
  - Dynamic quantity restriction handling per-variation
  - Re-initialization of event handlers for dynamically loaded pricing tables
- **admin.js**:
  - Separated simple product and variation handlers
  - Variation-specific add/remove tier/package row management
  - Context-aware template selection using variation loop index

#### Template Changes

- **tier-row.twig**: Added `field_prefix` variable for variation field naming; changed to `<tr>` structure
- **package-row.twig**: Added `field_prefix` variable for variation field naming; changed to `<tr>` structure

#### Data Storage

- Meta keys remain the same: `_wc_tpp_tiers`, `_wc_tpp_packages`, `_wc_tpp_restrict_to_packages`
- Simple products: Stored on product post meta
- Variations: Stored on variation post meta (independent per-variation)

### Backward Compatibility

- **100% backward compatible** - No breaking changes
- Simple products continue working exactly as before
- Existing tier/package data unaffected
- No database migrations required
- Templates remain compatible (field_prefix optional)

### Migration Notes

- Existing installations can upgrade seamlessly
- Variable products simply gain new functionality
- No action required for existing simple product configurations

### Performance Considerations

- AJAX requests only made when variation selected (not on page load)
- Pricing data fetched per-variation (not all variations at once)
- Nonce verification on all AJAX requests for security
- Template rendering server-side for SEO/performance

### Testing Performed

- Simple products: All existing functionality verified
- Variable products: Tier pricing, package pricing, restrictions tested per-variation
- Mixed carts: Simple + variable products working correctly
- WooCommerce Blocks: Cart block, mini-cart block, checkout block compatibility verified
- Admin UI: Add/remove rows working for both simple products and variations
- Quantity restrictions: Enforced correctly per-variation in cart and checkout

## [1.1.22] - 2025-12-23

### Changed

- Increased width of label input fields for tier pricing and package pricing in admin interface
- Changed label field CSS class from `short` to `regular` (approximately 2x wider)

### Technical Details

- Updated `templates/admin/tier-row.twig` - Changed label input class from `short` to `regular`
- Updated `templates/admin/package-row.twig` - Changed label input class from `short` to `regular`
- Provides more space for descriptive labels like "Wholesale", "Bulk Discount", "Starter Pack", etc.
- Uses WooCommerce standard input field sizing classes

### Known Issues

- **Double-install bug**: When manually updating the plugin by uploading a new version, WordPress may install it as a separate plugin instead of updating the existing one
  - **Workaround**: Before installing a new version, deactivate and delete the old version first, then install the new version
  - **Root cause**: Plugin lacks automatic update mechanism; requires manual installation
  - **Future fix**: Consider implementing update server or WordPress.org repository integration

## [1.1.21] - 2025-12-23

### Added

- New translation for `de_CH` (Swiss German - formal)
- New translation for `de_DE_informal` (Informal German)
- New translation for `fr_CH` (Swiss French)
- New translation for `it_CH` (Swiss Italian)

### Changed

- Updated all translation files (.po) to version 1.1.21
- Compiled all translation files to .mo format for runtime use

### Technical Details

- Created 4 new locale-specific translation files following WordPress i18n standards
- Swiss locales use CHF currency formatting in examples (CHF 50.-, CHF 100.-)
- German informal translations use "du/dein" instead of "Sie/Ihr"
- All translations maintain consistent terminology across plugin UI
- Compiled .mo files included for immediate WordPress language support

## [1.1.20] - 2025-12-22

### Fixed

- **CRITICAL**: Fatal error in WooCommerce Blocks cart/mini-cart: "Cannot use object of type WC_Product_Simple as array"
- Filter `woocommerce_store_api_product_quantity_editable` signature mismatch

### Changed

- Updated `is_quantity_editable_in_blocks()` method to accept `WC_Product` object instead of cart item array
- Changed method signature from `is_quantity_editable_in_blocks($cart_item)` to `is_quantity_editable_in_blocks(WC_Product $product)`
- Use `$product->get_id()` instead of `$cart_item['product_id']` for product identification

### Technical Details

- WooCommerce Store API passes product object to this filter, not cart item array
- Previous code attempted array access on product object causing fatal error
- Error occurred at `includes/class-wc-tpp-cart.php:233`
- Affects WooCommerce Blocks-based cart, mini-cart, and checkout
- Classic cart/checkout unaffected (uses different hooks)

## [1.1.19] - 2025-12-22

### Fixed

- Settings page still appearing twice despite instance caching
- Duplicate detection using strict instance comparison failing for different object instances

### Changed

- Enhanced duplicate detection to check by class type and ID instead of instance
- Added `instanceof WC_TPP_Settings` check
- Added ID-based duplicate detection via `get_id()` method and direct property access
- Multiple fallback checks to catch duplicates regardless of instance identity

### Technical Details

- Previous strict comparison (`===`) failed when different instances of same class existed
- New approach checks: instanceof, get_id() method, and id property
- Returns early if any settings page with ID 'tier_package_prices' found
- Prevents duplicates even if settings instance recreated or serialized

## [1.1.18] - 2025-12-22

### Fixed

- **ROOT CAUSE IDENTIFIED**: Settings page rendering twice due to automatic instantiation in settings file
- Settings file being included multiple times via Composer autoloader creating duplicate instances

### Changed

- Removed `return new WC_TPP_Settings();` from bottom of settings file
- Changed admin class to explicitly instantiate settings with `new WC_TPP_Settings()`
- Changed from `include` to `require_once` for settings file to prevent multiple loads

### Technical Details

- Settings file (class-wc-tpp-settings.php) was creating instance automatically on include
- File is in Composer's classmap, so when autoloaded it executed instantiation again
- Each include/autoload created new instance even with singleton pattern in admin class
- Solution: Remove automatic instantiation, use `require_once` + explicit `new` in admin class
- Now settings instance only created once, explicitly, when needed by filter
- Composer autoload can load class definition without side effects

## [1.1.17] - 2025-12-22

### Fixed

- Settings page still rendering twice despite singleton pattern in v1.1.16
- Filter adding settings instance to array multiple times when called repeatedly

### Changed

- Added duplicate detection in `add_settings_page()` filter method
- Filter now checks if settings instance already exists in array before adding

### Technical Details

- Added foreach loop to check existing settings pages in array
- Uses strict comparison (`===`) to detect if exact instance already present
- Returns early if settings instance found, preventing duplicate array entries
- Complements singleton pattern from v1.1.16 with array-level duplicate prevention
- Handles edge case where WooCommerce calls filter multiple times

## [1.1.16] - 2025-12-22

### Fixed

- Settings page still rendering twice in WooCommerce backend despite v1.1.15 fix
- Multiple instantiation of WC_TPP_Admin and WC_TPP_Settings classes

### Changed

- Implemented singleton pattern for WC_TPP_Admin class with `get_instance()` method
- Made WC_TPP_Admin constructor private to prevent direct instantiation
- Added static caching of WC_TPP_Settings instance to prevent duplicate creation
- Changed class instantiation from `new WC_TPP_Admin()` to `WC_TPP_Admin::get_instance()`

### Technical Details

- Added `private static $instance` property to WC_TPP_Admin class
- Added `private static $settings_instance` property to cache settings page instance
- Modified `add_settings_page()` to check and reuse cached settings instance
- Ensures only one instance of each class exists throughout plugin lifecycle
- Prevents duplicate filter registrations even if called multiple times

## [1.1.15] - 2025-12-22

### Fixed

- Settings page rendering twice in WooCommerce settings
- Duplicate instantiation of WC_TPP_Settings class causing double rendering

### Technical Details

- Removed conditional `if (class_exists('WC_TPP_Settings'))` wrapper from settings return statement
- Settings class now only instantiated via `return new WC_TPP_Settings();` when included by admin class
- Matches v1.1.2 pattern where settings file returns instance without automatic instantiation
- Prevents double registration in WooCommerce settings pages array

## [1.1.14] - 2025-12-22

### Fixed

- **CRITICAL:** Plugin completely non-functional in v1.1.8-1.1.13 - no settings, no frontend, no backend
- Classes never instantiated due to incorrect initialization pattern introduced in v1.1.8
- Restored v1.1.2 pattern: classes auto-instantiate when files are included
- All plugin functionality now working: settings page, product meta boxes, frontend display, cart integration

### Changed

- Reverted to direct class instantiation pattern from v1.1.2 (last known working version)
- Removed `init_classes()` method and `woocommerce_loaded` hook approach from v1.1.8
- Each class file now instantiates itself with `new ClassName()` at end of file
- Simplified plugin initialization for better reliability

### Technical Details

- Restored class instantiation in all 5 component files:
  - `class-wc-tpp-admin.php`: Added `new WC_TPP_Admin();` after class declaration
  - `class-wc-tpp-product-meta.php`: Added `new WC_TPP_Product_Meta();` after class declaration
  - `class-wc-tpp-frontend.php`: Added `new WC_TPP_Frontend();` after class declaration
  - `class-wc-tpp-cart.php`: Added `new WC_TPP_Cart();` after class declaration
  - `class-wc-tpp-settings.php`: Already has instantiation via return statement
- Removed `init_classes()` method from main plugin class
- Removed `woocommerce_loaded` hook that delayed class instantiation
- Classes now instantiate immediately when `require_once` loads them
- All `class_exists()` guards remain in place for redeclaration protection

## [1.1.13] - 2025-12-22

### Fixed

- **CRITICAL:** Class redeclaration errors for all plugin component classes affecting version 1.1.12
- Fatal errors "Cannot redeclare class WC_TPP_Admin", "Cannot redeclare class WC_TPP_Product_Meta", "Cannot redeclare class WC_TPP_Frontend", "Cannot redeclare class WC_TPP_Cart", "Cannot redeclare class WC_TPP_Settings"
- Plugin functionality completely broken in v1.1.12 - no settings page, no frontend display, no backend controls
- All plugin features now working correctly after adding class guards

### Technical Details

- Wrapped all 5 plugin component class declarations in `class_exists()` checks:
  - `WC_TPP_Admin` (includes/class-wc-tpp-admin.php)
  - `WC_TPP_Product_Meta` (includes/class-wc-tpp-product-meta.php)
  - `WC_TPP_Frontend` (includes/class-wc-tpp-frontend.php)
  - `WC_TPP_Cart` (includes/class-wc-tpp-cart.php)
  - `WC_TPP_Settings` (includes/class-wc-tpp-settings.php)
- Completes comprehensive redeclaration protection started in v1.1.9-1.1.12
- All functions, constants, and classes now fully protected against redeclaration
- Plugin now activates and functions correctly without fatal errors

## [1.1.12] - 2025-12-22

### Fixed

- **CRITICAL:** Class redeclaration error for `WC_Tier_Package_Prices` affecting version 1.1.11
- Fatal error "Cannot redeclare class WC_Tier_Package_Prices" when plugin file loaded multiple times
- Plugin activation failures caused by class redeclaration

### Technical Details

- Wrapped `WC_Tier_Package_Prices` class declaration in `class_exists()` check
- Completes comprehensive redeclaration protection for all plugin components
- Prevents fatal errors during WordPress plugin activation/deactivation cycles
- All functions, constants, and classes now safely guarded against redeclaration

## [1.1.11] - 2025-12-22

### Fixed

- **CRITICAL:** Constant redeclaration warnings/errors for plugin constants affecting versions 1.1.3-1.1.10
- Potential errors when plugin constants (WC_TPP_VERSION, WC_TPP_PLUGIN_DIR, etc.) already defined
- Plugin initialization failures caused by constant redeclaration

### Technical Details

- Wrapped all `define()` calls in `defined()` checks for WC_TPP_VERSION, WC_TPP_PLUGIN_DIR, WC_TPP_PLUGIN_URL, WC_TPP_PLUGIN_BASENAME
- Prevents warnings/errors during WordPress plugin activation/deactivation cycles
- Completes comprehensive protection against all redeclaration issues
- All global functions and constants now safely guarded

## [1.1.10] - 2025-12-22

### Fixed

- **CRITICAL:** Function redeclaration error for `wc_tpp_init()` affecting version 1.1.9
- Fatal error "Cannot redeclare function wc_tpp_init()" when plugin file loaded multiple times
- Plugin activation failures caused by function redeclaration

### Technical Details

- Wrapped `wc_tpp_init()` function in `function_exists()` check
- Completes the fix started in v1.1.9 by protecting all global functions
- Prevents fatal errors during WordPress plugin activation cycles
- Both `wc_tpp_woocommerce_missing_notice()` and `wc_tpp_init()` now safely guarded

## [1.1.9] - 2025-12-22

### Fixed

- **CRITICAL:** Function redeclaration error for `wc_tpp_woocommerce_missing_notice()` affecting versions 1.1.3-1.1.8
- Fatal error "Cannot redeclare function wc_tpp_woocommerce_missing_notice()" when plugin file loaded multiple times
- Plugin activation and deactivation failures caused by function redeclaration

### Technical Details

- Wrapped `wc_tpp_woocommerce_missing_notice()` function in `function_exists()` check
- Prevents fatal error during WordPress plugin activation/deactivation cycles
- Ensures function can safely be declared even if file is included multiple times
- Moved function declaration before WooCommerce check for better code organization

## [1.1.8] - 2025-12-22

### Fixed

- **CRITICAL:** Plugin activation fatal error introduced in v1.1.3-v1.1.7
- Fixed premature class instantiation of `WC_TPP_Admin` and `WC_TPP_Product_Meta`
- Both classes now instantiated via `woocommerce_loaded` hook after WooCommerce is available
- Resolves WordPress 6.9.x and WooCommerce 10.x compatibility issues

### Technical Details

- Removed `new WC_TPP_Admin();` from bottom of class-wc-tpp-admin.php
- Removed `new WC_TPP_Product_Meta();` from bottom of class-wc-tpp-product-meta.php
- Added both classes to `init_classes()` method in main plugin file
- All four main classes (Admin, Product Meta, Frontend, Cart) now follow same initialization pattern
- Ensures WooCommerce hooks are available before registration

## [1.1.7] - 2025-12-22

### Added

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

### Enhanced

- Tier pricing table rows now clickable with visual hover feedback
- Clicking a tier row sets quantity to that tier's minimum quantity
- Smooth scroll animation to quantity field when tier is clicked
- Add to Cart button disabled state with visual feedback (opacity, cursor)
- Tier labels display below quantity in frontend table (italic, gray text)

### Technical Details

- Added optional `label` field to tier pricing meta box (admin/tier-row.twig)
- Updated tier save logic to store label field (class-wc-tpp-product-meta.php)
- Enhanced tier pricing template to display labels (frontend/tier-pricing-table.twig)
- Added click handler for tier rows (assets/js/frontend.js)
- Added `updateAddToCartButton()` function to manage button state
- CSS: `.wc-tpp-tier-label` styling for tier labels
- CSS: Clickable cursor and hover animation for tier rows
- CSS: Disabled button styling (`.single_add_to_cart_button:disabled`)

## [1.1.6] - 2025-12-21

### Fixed
- **CRITICAL:** Plugin activation fatal error in v1.1.3, v1.1.4, and v1.1.5
- Fatal error caused by premature class instantiation before WooCommerce is loaded
- Removed immediate class instantiation from `class-wc-tpp-cart.php` and `class-wc-tpp-frontend.php`

### Technical
- Moved `WC_TPP_Cart` and `WC_TPP_Frontend` instantiation to `woocommerce_loaded` hook
- Added `init_classes()` method to main plugin class for controlled class initialization
- Ensures WooCommerce is fully loaded before registering hooks that depend on WC functions
- Fixed hook registration timing to prevent accessing WooCommerce before it's available

## [1.1.5] - 2025-12-21

### Fixed
- **CRITICAL:** Plugin activation error in v1.1.3 and v1.1.4 caused by `add_cart_quantity_css()` method
- Fatal error when WooCommerce cart object not available during plugin initialization
- Frontend errors on admin pages and during activation

### Technical
- Added `function_exists('WC')` check before accessing WooCommerce functions
- Added `is_admin()` check to prevent CSS injection on admin pages
- Enhanced error prevention in `add_cart_quantity_css()` method

## [1.1.4] - 2025-12-21

### Added
- WooCommerce Blocks support for quantity restrictions
- `woocommerce_store_api_product_quantity_editable` filter for block-based carts
- `block_quantity_editable()` method in WC_TPP_Cart class
- CSS targeting for `.wc-block-components-quantity-selector` elements

### Enhanced
- "View Options" button styling to match standard WooCommerce "Add to Cart" buttons
- Button padding, font weight, and border radius for better visual consistency
- Hover effects with smooth transitions

### Fixed
- WooCommerce blocks cart quantity selector visibility for restricted products
- WooCommerce blocks mini-cart quantity selector visibility

### Technical
- Added Store API integration for block-based cart/mini-cart
- Enhanced CSS for block cart items with product-specific selectors
- Improved button styling with WooCommerce standard values (0.618em × 1em padding)
- Added transition effects for better UX

## [1.1.3] - 2025-12-21

### Fixed
- Cart quantity input visibility issue in cart and cart sidebar for restricted products
- Enhanced filter priority (999) to ensure quantity hiding runs after other plugins
- Mini-cart quantity input now properly hidden for restricted products

### Added
- `woocommerce_widget_cart_item_quantity` filter support for mini-cart
- `add_cart_quantity_css()` method for dynamic CSS injection
- `data-product-id` attribute to quantity spans for targeted CSS selectors
- CSS class `wc-tpp-restricted-qty` for improved targeting

### Technical
- Increased filter priority from 10 to 999 for `woocommerce_cart_item_quantity`
- Added `maybe_hide_mini_cart_quantity_input()` method in WC_TPP_Cart class
- Dynamic CSS injection via `wp_head` action as fallback
- Used both sibling (+) and general sibling (~) CSS selectors for DOM variations

## [1.1.2] - 2025-12-21

### Added
- Catalog "View Options" button for products with quantity restrictions
- Automatic button replacement in shop/category/archive pages
- Eye icon (Dashicons) for "View Options" button styling

### Changed
- "Add to Cart" button replaced with "View Options" link on catalog pages for restricted products
- CSS now loads on all WooCommerce pages (shop, cart, checkout, product)
- Catalog buttons now direct to product page instead of adding to cart

### Technical
- Added `has_quantity_restriction()` static method in WC_TPP_Frontend class
- Added `modify_catalog_add_to_cart_button()` method in WC_TPP_Frontend class
- Extended `woocommerce_loop_add_to_cart_link` filter hook
- CSS classes: `wc-tpp-view-options`, `wc-tpp-cart-quantity`, `wc-tpp-restriction-notice`
- Updated `enqueue_scripts()` to load CSS on all WooCommerce pages

### Translations
- Added 2 new translatable strings
- Updated all translations (en_US, de_DE, de_CH_informal)
- Compiled all .mo files with new strings

## [1.1.1] - 2025-12-21

### Added
- Cart quantity field hiding when package restriction is enabled
- Automatic read-only quantity display in cart for restricted products

### Changed
- Cart quantity input replaced with plain text when restrictions apply
- Enhanced cart display to prevent quantity modification for restricted products

### Fixed
- Cart quantity bypass vulnerability for package-restricted products

### Technical
- Added `maybe_hide_cart_quantity_input()` method in WC_TPP_Cart class
- Extended `woocommerce_cart_item_quantity` filter hook
- CSS class `wc-tpp-cart-quantity` for styled quantity display

## [1.1.0] - 2025-12-21

### Added
- Package quantity restriction feature
- Global setting to restrict quantities to defined package sizes
- Per-product setting to restrict quantities to defined package sizes
- Frontend validation preventing non-package quantities
- Server-side cart validation for package quantities
- User-friendly error messages showing available package sizes
- Automatic quantity field hiding when restriction is enabled
- Package selection UI with highlighted states

### Changed
- Enhanced package pricing display template with restriction mode support
- Improved JavaScript to handle restricted mode package selection
- Updated frontend to show "Choose a package size below" notice in restricted mode

### Technical
- Added `validate_package_quantity()` method in WC_TPP_Cart class
- Added `maybe_hide_quantity_input()` method in WC_TPP_Frontend class
- Extended `woocommerce_add_to_cart_validation` filter hook
- Added `wc-tpp-restricted-mode` CSS class for styling
- New product meta: `_wc_tpp_restrict_to_packages`
- New global option: `wc_tpp_restrict_package_quantities`

### Translations
- Added 7 new translatable strings
- Updated all translations (en_US, de_DE, de_CH_informal)
- Compiled all .mo files with new strings

## [1.0.2] - 2025-12-21

### Changed
- Migrated settings to WooCommerce Settings page as dedicated tab
- Settings now appear under WooCommerce > Settings > Tier & Package Prices
- Improved integration with WooCommerce native settings API

### Added
- WC_TPP_Settings class extending WC_Settings_Page
- Better integration with WooCommerce settings system
- Consistent UI with other WooCommerce settings tabs

### Removed
- Standalone settings submenu (WooCommerce > Tier & Package Prices)
- Custom settings template (templates/admin/settings-page.twig)

### Technical
- Implemented WooCommerce settings filter hook (woocommerce_get_settings_pages)
- Uses WC_Admin_Settings for rendering and saving
- Automatic settings persistence via WooCommerce API

## [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
