Răsfoiți Sursa

Fix: pvtfw table + Available Options button not actually suppressed — v1.5.1 -> v1.5.2

Root cause: pvtfw publishes its singletons as \$pvtfw_print_table /
\$pvtfw_available_btn by writing them at the top of each class file.
Those assignments run via require_once inside pvtfw's PVTFW_TABLE::includes()
method, so in PHP they become method-locals — not true globals. Our
\`global \$pvtfw_print_table\` therefore resolved to null and the
remove_action() no-opped. Result on studiou.cz/produkt/filo/: pvtfw's
entire variant table and its "Available Options" / "Product Forms"
button kept rendering above our card stack.

Fix: reach pvtfw's singletons via their static ::instance() accessors
(PVTFW_PRINT_TABLE::instance() / PVTFW_AVAILABE_BTN::instance() — note
pvtfw's class-name typo "AVAILABE"). Those return the exact same
singleton object pvtfw registered the hooks with, so remove_action()
targets the live callback and clears it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Dalibor Votruba 2 luni în urmă
părinte
comite
280bff93a3

+ 2 - 2
studiou-wc-free-photo-product/CLAUDE.md

@@ -2,7 +2,7 @@
 
 ## Project Overview
 
-WordPress/WooCommerce plugin called **studiou-wc-free-photo-product** (QDR - Studiou WC Free Photo Product) v1.5.1.
+WordPress/WooCommerce plugin called **studiou-wc-free-photo-product** (QDR - Studiou WC Free Photo Product) v1.5.2.
 Allows publishing special variable products where customers upload custom raw images to be printed for a price.
 
 ## Initial Requirements
@@ -39,7 +39,7 @@ Allows publishing special variable products where customers upload custom raw im
 - `Studiou_WC_FPP_DB` - Custom table CRUD, media category taxonomy. Batch-aware queries: `get_batch_files($token, $product_id)`, `count_batch_files($token, $product_id)`.
 - `Studiou_WC_FPP_Product` - WC product data tab, product meta (including `_studiou_fpp_max_uploads` — per-product cap on simultaneous uploads, 0 = unlimited).
 - `Studiou_WC_FPP_Upload` - Chunked upload AJAX, file assembly, attachment creation. Mints/reuses a 32-char `studiou_fpp_batch` cookie on first chunk-upload completion and persists it in the new file record's `batch_token` column. Enforces the per-product max-uploads cap before accepting chunk 0. Legacy `studiou_fpp_att_id`/`studiou_fpp_rec_id` cookies still written for one release as a read-fallback for the shortcode path.
-- `Studiou_WC_FPP_Single_Product` - On `wp` priority 5, detaches pvtfw's variant table (`remove_action()` on the hook/priority read from pvtfw's own `pvtfw_variant_table_place` option) and pvtfw's available-options button on FPP products. On `woocommerce_single_product_summary` priority 35 renders the upload dropzone + card stack + order-overview panel. Exposes `resolve_batch_files(Studiou_WC_FPP_DB $db, $product_id = 0)` (list, 1.5.0 path) and `resolve_uploaded_file()` (single, legacy shortcode path). Adds `studiou-fpp-product-page` body class. Server-side validation (`woocommerce_add_to_cart_validation` priority 1) accepts `$cart_item_data['studiou_fpp_file_record_id']` as the primary "photo present" signal, with the resolver as fallback.
+- `Studiou_WC_FPP_Single_Product` - On `wp` priority 5, detaches pvtfw's variant table (`remove_action()` on the hook/priority read from pvtfw's own `pvtfw_variant_table_place` option) and pvtfw's available-options button on FPP products. pvtfw's singletons are reached via `PVTFW_PRINT_TABLE::instance()` / `PVTFW_AVAILABE_BTN::instance()` (the `$pvtfw_print_table` / `$pvtfw_available_btn` globals published by pvtfw end up as method-locals because pvtfw's `require_once` lives inside a method — the static singletons return the same real instances that pvtfw used to register the hooks). On `woocommerce_single_product_summary` priority 35 renders the upload dropzone + card stack + order-overview panel. Exposes `resolve_batch_files(Studiou_WC_FPP_DB $db, $product_id = 0)` (list, 1.5.0 path) and `resolve_uploaded_file()` (single, legacy shortcode path). Adds `studiou-fpp-product-page` body class. Server-side validation (`woocommerce_add_to_cart_validation` priority 1) accepts `$cart_item_data['studiou_fpp_file_record_id']` as the primary "photo present" signal, with the resolver as fallback.
 - `Studiou_WC_FPP_Shortcode` - `[studiou_free_photo_product id="X"]` renders product with WC native variation form (unchanged — still the single-file flow).
 - `Studiou_WC_FPP_Cart` - New AJAX endpoints `studiou_wcfpp_add_file_to_cart` (per-card Add-to-Cart, pre-stamps `file_record_id` on `$cart_item_data` and calls `WC()->cart->add_to_cart()`) and `studiou_wcfpp_remove_cart_line` (cart-only remove from overview panel). `add_cart_item_data()` prefers pre-stamped `file_record_id` from the new flow, falls back to the legacy visitor-level resolver. Replaces cart/order item thumbnails (classic cart via `woocommerce_cart_item_thumbnail`, block cart via `woocommerce_product_get_image_id`/`woocommerce_product_variation_get_image_id`), order item meta, order linking. `render_overview_html($product_id)` returns the panel HTML for in-place re-render after cart changes.
 - `Studiou_WC_FPP_Admin` - Summary page with filters (status, product, order number, file-name search) and pagination, sortable columns (Order / Status / Date — default Date DESC), status management, ZIP download, CSV export, file download with auto-status-change, bulk actions with confirmation dialogs.

+ 17 - 10
studiou-wc-free-photo-product/includes/class-studiou-wc-fpp-single-product.php

@@ -34,9 +34,15 @@ class Studiou_WC_FPP_Single_Product {
 
     /**
      * Detach pvtfw's variant-table + available-options-button hooks on FPP products.
-     * pvtfw exposes its instances as globals $pvtfw_print_table and $pvtfw_available_btn;
-     * the table hook/priority is derived from the same option pvtfw itself reads
-     * (pvtfw_variant_table_place, default woocommerce_after_single_product_summary_9).
+     *
+     * pvtfw assigns its singletons to `$pvtfw_print_table` / `$pvtfw_available_btn` at the
+     * top of its class files, but the `require_once` call lives inside pvtfw's
+     * PVTFW_TABLE::includes() method — so those assignments end up as method-locals, NOT
+     * true globals. We therefore reach the singletons via their static ::instance()
+     * (the same object pvtfw registered the actions with). The variant-table hook and
+     * priority are derived from pvtfw's own pvtfw_variant_table_place option (default
+     * woocommerce_after_single_product_summary_9) so admin-configured placements
+     * remain supported.
      */
     public function maybe_suppress_pvtfw() {
         if (!function_exists('is_product') || !is_product()) {
@@ -47,24 +53,25 @@ class Studiou_WC_FPP_Single_Product {
             return;
         }
 
-        global $pvtfw_print_table, $pvtfw_available_btn;
-
-        if ($pvtfw_print_table) {
+        if (class_exists('PVTFW_PRINT_TABLE')) {
+            $print_table = PVTFW_PRINT_TABLE::instance();
             $place = get_option('pvtfw_variant_table_place', 'woocommerce_after_single_product_summary_9');
             $tail  = strrchr((string) $place, '_');
             if ($tail !== false && strlen($tail) > 1) {
                 $priority = (int) ltrim($tail, '_');
                 $hook     = substr($place, 0, -strlen($tail));
                 if ($hook) {
-                    remove_action($hook, array($pvtfw_print_table, 'print_table'), $priority);
+                    remove_action($hook, array($print_table, 'print_table'), $priority);
                 }
             }
         } elseif (defined('WP_DEBUG') && WP_DEBUG) {
-            error_log('STUDIOU FPP: $pvtfw_print_table not found; cannot detach pvtfw variant table.');
+            error_log('STUDIOU FPP: PVTFW_PRINT_TABLE class not found; cannot detach pvtfw variant table.');
         }
 
-        if ($pvtfw_available_btn) {
-            remove_action('woocommerce_single_product_summary', array($pvtfw_available_btn, 'available_options_btn'), 11);
+        // Note: pvtfw's class name has a typo ("AVAILABE" missing the L) — match it verbatim
+        if (class_exists('PVTFW_AVAILABE_BTN')) {
+            $available_btn = PVTFW_AVAILABE_BTN::instance();
+            remove_action('woocommerce_single_product_summary', array($available_btn, 'available_options_btn'), 11);
         }
     }
 

+ 1 - 1
studiou-wc-free-photo-product/languages/studiou-wc-free-photo-product-cs_CZ.po

@@ -3,7 +3,7 @@
 # This file is distributed under the GPL v2 or later.
 msgid ""
 msgstr ""
-"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.5.1\n"
+"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.5.2\n"
 "Report-Msgid-Bugs-To: https://www.quadarax.com\n"
 "POT-Creation-Date: 2026-04-02 00:00+0000\n"
 "PO-Revision-Date: 2026-04-02 00:00+0000\n"

+ 1 - 1
studiou-wc-free-photo-product/languages/studiou-wc-free-photo-product.pot

@@ -2,7 +2,7 @@
 # This file is distributed under the GPL v2 or later.
 msgid ""
 msgstr ""
-"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.5.1\n"
+"Project-Id-Version: QDR - Studiou WC Free Photo Product 1.5.2\n"
 "Report-Msgid-Bugs-To: https://www.quadarax.com\n"
 "POT-Creation-Date: 2026-04-02 00:00+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

+ 2 - 2
studiou-wc-free-photo-product/studiou-wc-free-photo-product.php

@@ -3,7 +3,7 @@
  * Plugin Name: QDR - Studiou WC Free Photo Product
  * Plugin URI: https://www.quadarax.com/plugins/studiou-wc-free-photo-product
  * Description: Allows publishing special WooCommerce products with variants and custom raw image upload for photo printing
- * Version: 1.5.1
+ * Version: 1.5.2
  * Requires at least: 6.9.4
  * Requires PHP: 8.2
  * Requires Plugins: woocommerce, product-variant-table-for-woocommerce
@@ -22,7 +22,7 @@ if (!defined('WPINC')) {
     die;
 }
 
-if (!defined('STUDIOU_WCFPP_VERSION')) define('STUDIOU_WCFPP_VERSION', '1.5.1');
+if (!defined('STUDIOU_WCFPP_VERSION')) define('STUDIOU_WCFPP_VERSION', '1.5.2');
 if (!defined('STUDIOU_WCFPP_PLUGIN_DIR')) define('STUDIOU_WCFPP_PLUGIN_DIR', plugin_dir_path(__FILE__));
 if (!defined('STUDIOU_WCFPP_PLUGIN_URL')) define('STUDIOU_WCFPP_PLUGIN_URL', plugin_dir_url(__FILE__));
 if (!defined('STUDIOU_WCFPP_PLUGIN_BASENAME')) define('STUDIOU_WCFPP_PLUGIN_BASENAME', plugin_basename(__FILE__));