Files
wc-tier-and-package-prices/CLAUDE.md
magdev f958c7b640 Release version 1.1.21 - Add multilingual support for Swiss locales
Added translations for Swiss German (formal and informal), Swiss French,
and Swiss Italian locales to support multilingual e-commerce in Switzerland.

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

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

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

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

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 01:44:41 +01:00

17 KiB

WooCommerce Tier and Package Prices - AI Context Document

Last Updated: 2025-12-23 Current Version: 1.1.21 Author: Marco Graetsch Project Status: Production-ready WordPress plugin

Project Overview

This is a WooCommerce plugin that adds flexible pricing capabilities to products through two distinct pricing models:

  1. Tier Pricing (Volume Discounts): Progressive discounts based on quantity ranges (e.g., 1-9 items @ $12, 10-24 @ $10, 25+ @ $8)
  2. Package Pricing (Fixed Bundles): Exact quantity packages at fixed prices (e.g., exactly 10 items for $95, exactly 25 for $200)

Key Fact: 100% AI-Generated

This project is proudly "vibe-coded" using Claude.AI - the entire codebase was created through AI assistance.

Technical Stack

  • Language: PHP 7.4+
  • Framework: WordPress Plugin API
  • E-commerce: WooCommerce 8.0+ (tested up to 10.x)
  • Template Engine: Twig 3.0 (via Composer)
  • Frontend: Vanilla JavaScript + jQuery
  • Styling: Custom CSS
  • Dependency Management: Composer
  • Internationalization: WordPress i18n (.pot/.po/.mo files)

Dependencies

{
  "twig/twig": "^3.0",
  "symfony/polyfill-ctype": "^1.x",
  "symfony/polyfill-mbstring": "^1.x"
}

Architecture

Directory Structure

wc-tier-and-package-prices/
├── wc-tier-and-package-prices.php    # Main plugin file (entry point)
├── includes/                         # PHP classes
│   ├── class-wc-tpp-admin.php        # Admin settings integration
│   ├── class-wc-tpp-settings.php     # WooCommerce settings page
│   ├── class-wc-tpp-product-meta.php # Product edit page meta boxes
│   ├── class-wc-tpp-frontend.php     # Product page display logic
│   ├── class-wc-tpp-cart.php         # Cart price calculations
│   └── class-wc-tpp-template-loader.php # Twig template loader
├── templates/                        # Twig templates
│   ├── admin/                       # Admin interface templates
│   │   ├── tier-row.twig           # Single tier input row
│   │   └── package-row.twig        # Single package input row
│   └── frontend/                    # Customer-facing templates
│       ├── pricing-table.twig       # Main pricing display wrapper
│       ├── tier-pricing-table.twig  # Tier pricing display
│       └── package-pricing-display.twig # Package buttons/cards
├── assets/
│   ├── css/
│   │   ├── admin.css               # Backend styling
│   │   └── frontend.css            # Product page & cart styling
│   └── js/
│       ├── admin.js                # Meta box interaction (add/remove rows)
│       └── frontend.js             # Dynamic price updates, package selection
├── languages/                       # Translation files
│   ├── *.pot                       # Translation template
│   ├── *.po                        # Translation sources
│   └── *.mo                        # Compiled translations
├── vendor/                          # Composer dependencies (included in releases)
├── releases/                        # Release packages (not in git)
└── *.md                            # Documentation files

Class Responsibilities

1. WC_Tier_Package_Prices (Main Plugin Class)

  • Location: wc-tier-and-package-prices.php
  • Pattern: Singleton
  • Responsibilities:
    • Plugin initialization and bootstrapping
    • Loading all component classes via includes()
    • HPOS (High-Performance Order Storage) compatibility declaration
    • Text domain loading for internationalization
    • Activation/deactivation hooks

2. WC_TPP_Admin

  • Location: includes/class-wc-tpp-admin.php
  • Pattern: Singleton
  • Responsibilities:
    • Enqueues admin CSS/JS
    • Registers WooCommerce settings page via filter
    • Manages settings page instance (cached to prevent duplicates)
    • Product meta box asset loading

3. WC_TPP_Settings

  • Location: includes/class-wc-tpp-settings.php
  • Extends: WC_Settings_Page (WooCommerce core)
  • Responsibilities:
    • Creates "Tier & Package Prices" tab in WooCommerce settings
    • Defines global plugin settings (enable/disable features, display position, etc.)
    • Setting persistence through WooCommerce options API

Global Settings:

  • wc_tpp_enable_tier_pricing (yes/no)
  • wc_tpp_enable_package_pricing (yes/no)
  • wc_tpp_display_table (yes/no) - Show pricing tables on product pages
  • wc_tpp_display_position (before_add_to_cart / after_add_to_cart / after_price)
  • wc_tpp_restrict_package_quantities (yes/no) - Global quantity restrictions

4. WC_TPP_Product_Meta

  • Location: includes/class-wc-tpp-product-meta.php
  • Responsibilities:
    • Adds tier/package pricing fields to product edit page
    • Renders Twig templates for meta box rows
    • Saves tier/package data to post meta
    • Nonce verification and capability checks for security
    • Prevents autosave from corrupting data

Product Meta Keys:

  • _wc_tpp_tiers - Array of tier objects [{min_qty, price, label}]
  • _wc_tpp_packages - Array of package objects [{qty, price, label}]
  • _wc_tpp_restrict_to_packages - Per-product quantity restriction (yes/no)

5. WC_TPP_Frontend

  • Location: includes/class-wc-tpp-frontend.php
  • Responsibilities:
    • Enqueues frontend CSS/JS on product pages
    • Displays pricing tables via Twig templates
    • Localizes currency settings to JavaScript
    • Hides quantity inputs for restricted products
    • Modifies catalog "Add to Cart" buttons to "View Options" for restricted products
    • Static methods for price lookups (get_tier_price(), get_package_price())

6. WC_TPP_Cart

  • Location: includes/class-wc-tpp-cart.php
  • Responsibilities:
    • MOST CRITICAL CLASS - Handles all cart price calculations
    • Applies tier/package pricing during cart totals calculation
    • Stores pricing metadata in cart items for display
    • Customizes cart item display (price labels, quantity indicators)
    • Validates package quantities on add-to-cart
    • Hides/disables quantity inputs for restricted products (classic cart + blocks)
    • WooCommerce Blocks support via woocommerce_store_api_product_quantity_editable filter

Price Calculation Priority (in apply_tier_package_pricing()):

  1. Check for exact package match → Use package price if found
  2. Check for tier match → Use tier price if found
  3. Fall back to regular product price

7. WC_TPP_Template_Loader

  • Location: includes/class-wc-tpp-template-loader.php
  • Pattern: Singleton
  • Responsibilities:
    • Initializes Twig environment with proper paths
    • Renders Twig templates from both admin and frontend directories
    • Handles template caching and error handling

Important Implementation Details

Price Calculation Logic

Package Pricing (exact match):

// In cart: if quantity == 10 and package exists for 10, use package price
if ($quantity == $package['qty']) {
    $unit_price = $package['price'] / $quantity;  // Total price divided by quantity
    $product->set_price($unit_price);  // WooCommerce expects unit price
}

Tier Pricing (range-based):

// In cart: if quantity >= 10, use tier price for quantities 10+
foreach ($tiers as $tier) {
    if ($quantity >= $tier['min_qty']) {
        $applicable_price = $tier['price'];  // This is already unit price
    }
}
$product->set_price($applicable_price);

Quantity Restriction Feature

Products can be configured to ONLY allow purchase in package quantities:

  • Global setting: wc_tpp_restrict_package_quantities
  • Per-product setting: _wc_tpp_restrict_to_packages
  • When enabled:
    • Quantity inputs are hidden on product page, cart, and mini-cart
    • Customers must use package selection buttons
    • Validation prevents arbitrary quantities from being added
    • Catalog buttons change to "View Options" instead of "Add to Cart"

WooCommerce Blocks Compatibility

CRITICAL BUG FIXED in v1.1.20:

  • Filter woocommerce_store_api_product_quantity_editable passes WC_Product object, NOT cart item array
  • Previous code tried to use product object as array → fatal error
  • Fixed by accepting product object and using $product->get_id()

Cart Item Metadata

The plugin stores additional data in cart items for display purposes:

WC()->cart->cart_contents[$cart_item_key]['wc_tpp_pricing_type'] = 'package' | 'tier';
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_total_price'] = 99.99;  // For packages
WC()->cart->cart_contents[$cart_item_key]['wc_tpp_unit_price'] = 9.99;   // For tiers

This metadata is used by display filters to show "(Package price)" or "(Volume discount)" labels.

Common Patterns & Conventions

Class Instantiation Pattern

All classes auto-instantiate at the end of their file:

if (!class_exists('WC_TPP_Frontend')) {
    class WC_TPP_Frontend {
        // class code
    }
}
new WC_TPP_Frontend();  // Auto-instantiate

Exception: Admin and Settings classes use singleton pattern to prevent duplicates.

Security Best Practices

  • All user inputs are sanitized (integers for quantities/prices)
  • Nonce verification on form submissions
  • Capability checks (edit_products) before saving
  • Output escaping in templates (esc_attr, esc_html, esc_js)
  • Direct file access prevention via ABSPATH check

Translation Ready

All user-facing strings use:

__('Text to translate', 'wc-tier-package-prices')
_e('Text to translate', 'wc-tier-package-prices')

Text domain: wc-tier-package-prices

Available Translations (as of v1.1.21):

  • en_US - English (United States)
  • de_DE - German (Germany, formal)
  • de_DE_informal - German (Germany, informal "du")
  • de_CH - German (Switzerland, formal "Sie")
  • de_CH_informal - German (Switzerland, informal "du")
  • fr_CH - French (Switzerland)
  • it_CH - Italian (Switzerland)

Note: Swiss locales use CHF currency formatting in examples (e.g., "CHF 50.-")

Known Issues & Historical Context

Settings Page Duplication Saga (v1.1.15-1.1.19)

Multiple versions attempted to fix settings page appearing twice:

  • Root cause: Settings file auto-instantiation + Composer autoloader
  • Solution: Removed auto-instantiation from settings file, explicit instantiation in admin class
  • Prevention: Singleton pattern + duplicate detection in array

Class Redeclaration Issues (v1.1.8-1.1.14)

Plugin was completely non-functional:

  • Cause: Incorrect initialization pattern without class_exists() guards
  • Solution: Added guards and restored direct instantiation pattern
  • Lesson: Always wrap class declarations in class_exists() checks

WooCommerce Blocks Fatal Error (v1.1.19 → v1.1.20)

Fatal error: Cannot use object of type WC_Product_Simple as array
Location: includes/class-wc-tpp-cart.php:233
  • Cause: Filter signature mismatch - expected array, received product object
  • Fix: Changed method signature to accept WC_Product $product instead of $cart_item array
  • Status: FIXED in v1.1.20

Release Process

Version Bumping

Update version in 3 places:

  1. wc-tier-and-package-prices.php - Plugin header comment (line 7)
  2. wc-tier-and-package-prices.php - WC_TPP_VERSION constant (line 26)
  3. composer.json - version field (optional, not critical)

Creating Release Package

# From project root
cd releases

# Create zip excluding dev files
zip -r wc-tier-and-package-prices-X.X.X.zip .. \
  -x '*.git*' '*.log' '.claude/*' 'CLAUDE.md' 'releases/*' 'node_modules/*' \
  '.DS_Store' 'Thumbs.db' '.vscode/*' '.idea/*' '*.sublime-*' \
  'notes.*' 'logs/*' 'templates/cache/*' 'composer.lock'

# Generate checksums
md5sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.md5
sha256sum wc-tier-and-package-prices-X.X.X.zip > wc-tier-and-package-prices-X.X.X.zip.sha256

IMPORTANT: The vendor/ directory MUST be included in releases (Twig dependency required for runtime).

What Gets Released

  • All plugin source files
  • Compiled vendor dependencies
  • Translation files (.mo compiled from .po)
  • Assets (CSS, JS)
  • Documentation (README, CHANGELOG, etc.)

What's Excluded

  • Git metadata (.git/)
  • Development files (.vscode/, .claude/, CLAUDE.md)
  • Logs and cache files
  • Previous releases
  • composer.lock (but vendor/ is included)

Testing Checklist

When making changes, test these critical paths:

Admin

  • Settings page appears once under WooCommerce > Tier & Package Prices
  • Settings save correctly
  • Product edit page shows tier/package meta boxes
  • Adding/removing tiers works
  • Adding/removing packages works
  • Data saves when clicking "Update" on product

Frontend (Product Page)

  • Pricing tables display when configured
  • Package buttons update quantity selector
  • Price updates dynamically when quantity changes
  • Restricted products hide quantity input
  • "View Options" appears on catalog for restricted products

Cart & Checkout

  • Correct prices applied for tier pricing
  • Correct prices applied for package pricing
  • Cart displays pricing type labels
  • Package quantities can't be edited if restricted
  • Prices recalculate if quantity changed (non-restricted products)
  • Checkout totals are correct

WooCommerce Blocks (Critical!)

  • Mini cart block doesn't throw fatal errors
  • Cart block works correctly
  • Checkout block processes orders
  • Quantity editable flag works for blocks

Development Tips for Future AI Assistants

Future Features and Roadmap

The is a hierarchical list for upcoming features and can be considered as a Roadmap for the upcoming development.

Version 1.1.x

  1. Add translations for de_CH, de_DE_informal, fr_CH, it_CH COMPLETED in v1.1.21

Version 1.2.x

  1. New Feature: Create different, selectable templates for tierprices and packages to use in the frontend. Make the new templates selectable globally on the settings-page, not per product.

When Debugging Cart Issues

  1. Check includes/class-wc-tpp-cart.php first
  2. The apply_tier_package_pricing() method runs on woocommerce_before_calculate_totals
  3. Always validate product objects with is_a($product, 'WC_Product')
  4. Remember: WooCommerce expects UNIT prices, not total prices (except for internal calculations)

When Working with WooCommerce Hooks

  • WooCommerce has both classic and block-based systems
  • Classic cart uses different hooks than Store API (blocks)
  • Always check filter/action documentation for parameter types
  • Don't assume cart item arrays everywhere - sometimes it's product objects!

When Adding Features

  • Follow the existing pattern: add setting → add UI → add logic → add template
  • Use Twig for all new templates (consistency)
  • Add translations for all user-facing strings
  • Test with both simple products and variable products (if applicable)
  • Consider both classic and block-based cart/checkout

When Fixing Bugs

  1. Check CHANGELOG.md for historical context
  2. Look for similar issues in past versions
  3. Always add detailed changelog entry explaining root cause
  4. Consider edge cases (guest checkout, logged-in users, AJAX add-to-cart, etc.)

File Locations Quick Reference

Task File(s)
Change version wc-tier-and-package-prices.php (2 places)
Add global setting includes/class-wc-tpp-settings.php
Modify product meta box includes/class-wc-tpp-product-meta.php + templates/admin/*.twig
Change product page display includes/class-wc-tpp-frontend.php + templates/frontend/*.twig
Fix cart pricing includes/class-wc-tpp-cart.php
Update styles assets/css/frontend.css or assets/css/admin.css
Fix JavaScript bugs assets/js/frontend.js or assets/js/admin.js
Add translations languages/*.po then compile to .mo
Document changes CHANGELOG.md

Compatibility Notes

WordPress

  • Minimum: 6.0
  • Tested up to: 6.9.x
  • Uses standard plugin API, no deprecated functions

WooCommerce

  • Minimum: 8.0
  • Tested up to: 10.x
  • HPOS compatible (declared via FeaturesUtil::declare_compatibility)
  • Blocks compatible (with proper filter handling)

PHP

  • Minimum: 7.4
  • Uses modern PHP features (type hints acceptable in new code)
  • Composer autoloader handles namespacing

Browsers

  • Modern browsers (ES6+ JavaScript)
  • Responsive CSS (mobile-friendly)
  • jQuery dependency (WooCommerce provides)

Support & Resources

Final Notes

This is a production-quality plugin with real-world usage. Any changes should:

  1. Maintain backward compatibility with existing tier/package configurations
  2. Not break WooCommerce core functionality
  3. Work with both classic and block-based themes
  4. Be thoroughly tested before release
  5. Include proper error handling and validation
  6. Update CHANGELOG.md with detailed explanations

The plugin architecture is solid and well-tested. Most bugs arise from:

  • WooCommerce API changes (especially blocks)
  • Filter/action signature changes
  • Edge cases in cart calculations
  • Settings persistence issues

Always refer to this document when starting work on this project. Good luck!