From f7508a3d9c7258c85fa38ae25ddd72eaa370850a Mon Sep 17 00:00:00 2001 From: magdev Date: Tue, 30 Dec 2025 01:31:11 +0100 Subject: [PATCH] Document v1.2.8 learnings in CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added two new critical sections documenting lessons learned during v1.2.8 development: 1. Currency Symbol Display - Proper pattern for displaying currency in table headers using printf() - How to pass currency_symbol to Twig templates - Correct concatenation in Twig placeholders - List of affected render methods 2. Post Meta Deletion vs. Empty Arrays - Explains WordPress distinction between deleted meta and empty arrays - Shows wrong pattern (saving empty arrays) vs correct pattern (deleting meta) - Why this matters for database cleanliness and bug prevention - Affected methods in save_tier_package_fields() and save_variation_pricing_fields() These patterns prevent future bugs and ensure consistent implementation across the codebase. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- CLAUDE.md | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/CLAUDE.md b/CLAUDE.md index 2d68d14..097a5a4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -809,6 +809,102 @@ WooCommerce has different hooks for different product types in the admin product **Lesson:** When adding admin UI for variable product parents, use `woocommerce_product_options_general_product_data` and check `$product->is_type('variable')` to conditionally display. Using `woocommerce_product_options_pricing` will cause forms to never appear for variable products (as discovered in v1.2.6 → v1.2.7 fix). +#### CRITICAL: Currency Symbol Display (Learned in v1.2.8) + +When displaying currency symbols in admin interface table headers and input placeholders: + +**Table Headers:** + +```php +// ✅ Correct - Use printf with translation and WooCommerce currency function + + +// ❌ Wrong - Hard-coded or missing currency + + +``` + +**Twig Template Placeholders:** + +```twig +{# ✅ Correct - Pass currency_symbol from PHP and concatenate in template #} +placeholder="{{ ('e.g., 9.99 ' ~ currency_symbol)|__('wc-tier-package-prices') }}" + +{# ❌ Wrong - Hard-coded or missing currency #} +placeholder="{{ 'e.g., 9.99'|__('wc-tier-package-prices') }}" +placeholder="{{ 'e.g., 9.99 €'|__('wc-tier-package-prices') }}" +``` + +**Implementation Pattern:** + +1. In PHP render methods, pass currency symbol to Twig: `'currency_symbol' => get_woocommerce_currency_symbol()` +2. In Twig templates, concatenate using `~` operator: `'text ' ~ currency_symbol` +3. Always use WooCommerce's `get_woocommerce_currency_symbol()` - never hard-code currency symbols + +**Affected Methods:** All template render methods must pass `currency_symbol`: + +- `render_tier_row()` +- `render_package_row()` +- `render_variation_tier_row()` +- `render_variation_package_row()` + +#### CRITICAL: Post Meta Deletion vs. Empty Arrays (Learned in v1.2.8) + +When saving product meta data, WordPress distinguishes between "no data" (deleted meta) and "empty data" (empty array saved as meta): + +**Problem Pattern:** + +```php +// ❌ WRONG - Saves empty array when all entries removed +if (isset($_POST['_wc_tpp_tiers'])) { + $tiers = array(); + foreach ($_POST['_wc_tpp_tiers'] as $tier) { + if (!empty($tier['min_qty']) && !empty($tier['price'])) { + $tiers[] = array(...); + } + } + update_post_meta($post_id, '_wc_tpp_tiers', $tiers); // Saves [] if no valid entries +} else { + delete_post_meta($post_id, '_wc_tpp_tiers'); +} +``` + +**Correct Pattern:** + +```php +// ✅ CORRECT - Deletes meta when no valid entries exist +if (isset($_POST['_wc_tpp_tiers'])) { + $tiers = array(); + foreach ($_POST['_wc_tpp_tiers'] as $tier) { + if (!empty($tier['min_qty']) && !empty($tier['price'])) { + $tiers[] = array(...); + } + } + // Only save if we have valid entries, otherwise delete + if (!empty($tiers)) { + update_post_meta($post_id, '_wc_tpp_tiers', $tiers); + } else { + delete_post_meta($post_id, '_wc_tpp_tiers'); + } +} else { + delete_post_meta($post_id, '_wc_tpp_tiers'); +} +``` + +**Why This Matters:** + +- Empty arrays `[]` saved via `update_post_meta()` persist in database as serialized empty arrays +- Frontend/cart code checking `if ($tiers)` will evaluate `[]` as falsy, but meta still exists in database +- Database queries like `get_post_meta()` return `[]` instead of `false`, causing subtle bugs +- Properly deleting meta keeps database clean and prevents "ghost" configurations + +**Affected Methods in v1.2.8:** + +- `save_tier_package_fields()` - Simple and variable parent products +- `save_variation_pricing_fields()` - Individual variations + +**Rule:** Always check `if (!empty($array))` before calling `update_post_meta()` for array data. If empty, call `delete_post_meta()` instead. + ### When Adding Features - Follow the existing pattern: add setting → add UI → add logic → add template