Changeset 3489826
- Timestamp:
- 03/24/2026 10:00:22 AM (11 days ago)
- Location:
- bookpod-author-tools/trunk
- Files:
-
- 4 edited
-
bookpod-author-tools.php (modified) (1 diff)
-
bpat-checkout-logic.js (modified) (5 diffs)
-
bpat-order.php (modified) (7 diffs)
-
bpat-woocommerce-shipping.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
bookpod-author-tools/trunk/bookpod-author-tools.php
r3485558 r3489826 3 3 * Plugin Name: BookPod Author Tools 4 4 * Description: A plugin for managing books and orders through Bookpod. 5 * Version: 2.1. 65 * Version: 2.1.7 6 6 * Author: Rachel Stern 7 7 * Text Domain: bookpod-author-tools -
bookpod-author-tools/trunk/bpat-checkout-logic.js
r3485558 r3489826 409 409 // ========================== 410 410 function getSelectedBookpodMethod() { 411 // 1. Classic checkout — custom BookPod method select 412 var $methodSelect = $('select[name="bpat_bookpod_shipping_method"]'); 413 if ($methodSelect.length) return $methodSelect.val() || ""; 414 415 // 2. Classic checkout — WooCommerce shipping rate radio buttons 411 // 1. Classic checkout — WooCommerce shipping rate radio buttons 416 412 var $classicRate = $('input[name^="shipping_method"]:checked'); 417 413 if ($classicRate.length) { … … 423 419 } 424 420 425 // 3. Blocks checkout — WooCommerce shipping rate radio buttons421 // 2. Blocks checkout — WooCommerce shipping rate radio buttons 426 422 var $checkedRate = $('.wc-block-components-shipping-rates-control input[type="radio"]:checked'); 427 423 if ($checkedRate.length) { … … 459 455 lastBookpodMethod = method; 460 456 461 // Your original behavior 457 // Hide WC standard address fields when home delivery is selected — 458 // custom fields (bpat_street_name etc.) replace them. 459 // Also remove validate-required so WooCommerce doesn't block checkout 460 // because the hidden field is empty. 462 461 if (method === "home") { 463 $wcAddress1.hide(); 464 $wcAddress2.hide(); 462 $wcAddress1.hide().removeClass("validate-required"); 463 $wcAddress2.hide().removeClass("validate-required"); 464 $wcAddress1.find("input").prop("required", false); 465 465 } else { 466 $wcAddress1.show() ;466 $wcAddress1.show().addClass("validate-required"); 467 467 $wcAddress2.show(); 468 $wcAddress1.find("input").prop("required", true); 468 469 } 469 470 … … 485 486 else fetchPoints(); 486 487 } 488 487 489 } 488 490 … … 515 517 }); 516 518 517 // ✅ Classic checkout: update visibility immediately when the custom BookPod method select changes 518 // Also sync to the WooCommerce shipping rate radio so WooCommerce recalculates the order total. 519 $(document.body).on("change", 'select[name="bpat_bookpod_shipping_method"]', function () { 520 syncBlockBookpodMethod(); 521 updateVisibility(); 522 523 var selectedMethod = $(this).val(); 524 if (!selectedMethod) return; 525 526 var suffix = selectedMethod === "pickup_point" ? "pickup_point" : "home"; 527 var $rates = $('input[name^="shipping_method"]'); 528 var triggered = false; 529 530 $rates.each(function () { 531 var rateVal = String($(this).val() || ""); 532 if (rateVal.indexOf("bpat_bookpod") !== -1 && rateVal.indexOf(suffix) !== -1) { 533 if (!$(this).prop("checked")) { 534 $(this).prop("checked", true); 535 // Fire the native change event — WooCommerce's checkout.js already listens for 536 // 'change' on input[name^="shipping_method"] and calls update_order_review() from there. 537 $(this).trigger("change"); 538 } 539 triggered = true; 540 return false; // break 541 } 542 }); 543 544 // If no BookPod WC rate radio exists (shipping zone not configured), trigger update_checkout 545 // directly so woocommerce_checkout_update_order_review saves the method and 546 // woocommerce_cart_calculate_fees adds the correct shipping cost as a fee. 547 if (!triggered) { 548 $(document.body).trigger("update_checkout"); 549 } 550 }); 551 552 // ✅ Classic checkout: when WooCommerce shipping rate radio changes, sync to custom select 519 // ✅ Classic checkout: when WooCommerce BookPod shipping rate radio changes, update visibility. 553 520 $(document.body).on("change", 'input[name^="shipping_method"]', function () { 554 521 var val = String($(this).val() || ""); 555 var $sel = $('select[name="bpat_bookpod_shipping_method"]');556 if (!$sel.length) return;557 522 if (val.indexOf("bpat_bookpod") !== -1) { 558 var method = val.indexOf("pickup_point") !== -1 ? "pickup_point" : "home"; 559 if ($sel.val() !== method) { 560 $sel.val(method).trigger("change"); 561 } 523 syncBlockBookpodMethod(); 524 updateVisibility(); 562 525 } 563 526 }); -
bookpod-author-tools/trunk/bpat-order.php
r3485558 r3489826 179 179 ); 180 180 } else { 181 $items_for_bookpod[] = array( 181 $is_digital = bpat_product_is_digital( $product_id, $variation_id ); 182 $item_data = array( 182 183 'type' => 'book', 183 184 'bookid' => (string) $bookpod_id, 184 185 'quantity' => $qty, 185 186 ); 187 if ( $is_digital ) { 188 $item_data['format'] = 'epub'; 189 } 190 $items_for_bookpod[] = $item_data; 186 191 } 187 192 } … … 1021 1026 } 1022 1027 1028 /** 1029 * Returns true only when the store has manually added the BookPod WC shipping 1030 * method to at least one shipping zone (including the "Rest of World" zone). 1031 * Result is cached per request via a static variable. 1032 */ 1033 function bpat_has_bookpod_shipping_in_zones() { 1034 static $result = null; 1035 if ( null !== $result ) { 1036 return $result; 1037 } 1038 1039 $zones = WC_Shipping_Zones::get_zones(); 1040 $zones[] = array( 'zone_id' => 0 ); // Rest of World zone 1041 1042 foreach ( $zones as $zone_data ) { 1043 $zone = new WC_Shipping_Zone( $zone_data['zone_id'] ); 1044 foreach ( $zone->get_shipping_methods( true ) as $method ) { 1045 if ( 'bpat_bookpod' === $method->id ) { 1046 $result = true; 1047 return $result; 1048 } 1049 } 1050 } 1051 1052 $result = false; 1053 return $result; 1054 } 1055 1023 1056 function bpat_inject_bookpod_checkout_fields( $fields ) { 1024 if ( ! bpat_cart_has_only_physical_bookpod_items() ) {1057 if ( ! bpat_cart_has_only_physical_bookpod_items() || ! bpat_has_bookpod_shipping_in_zones() ) { 1025 1058 return $fields; 1026 1059 } … … 1029 1062 $fields['billing']['billing_phone']['label'] = __( 'Phone', 'bookpod-author-tools' ); 1030 1063 1031 $fields['billing']['bpat_bookpod_shipping_method'] = array( 1032 'type' => 'select', 1033 'label' => __( 'BookPod Shipping Method', 'bookpod-author-tools' ), 1034 'required' => true, 1035 'options' => array( 1036 '' => __( 'Select Shipping Method', 'bookpod-author-tools' ), 1037 'home' => __( 'Home Delivery', 'bookpod-author-tools' ) . ' — ₪29', 1038 'pickup_point' => __( 'Pickup Point (Locker/Shop)', 'bookpod-author-tools' ) . ' — ₪18', 1039 ), 1040 'class' => array( 'form-row-wide' ), 1041 'priority' => 25, 1042 ); 1064 // Shipping method (home / pickup_point) is now chosen via the standard 1065 // WooCommerce shipping rate radios — no custom select needed here. 1043 1066 1044 1067 $fields['billing']['bpat_street_name'] = array( … … 1117 1140 1118 1141 function bpat_inject_bookpod_block_checkout_fields( $fields ) { 1142 if ( ! bpat_has_bookpod_shipping_in_zones() ) { 1143 return $fields; 1144 } 1145 1119 1146 $fields['billing']['bpat_street_name'] = array( 1120 1147 'label' => __( 'Street Name', 'bookpod-author-tools' ), … … 1360 1387 1361 1388 // If a BookPod WC shipping rate is already selected, it handles the cost — don't double-count. 1389 // bpat_filter_package_rates_for_bookpod() syncs chosen_shipping_methods to a BookPod rate 1390 // during the same calculate_totals() call, so this check is reliable. 1362 1391 $chosen = WC()->session ? (array) WC()->session->get( 'chosen_shipping_methods', array() ) : array(); 1363 1392 foreach ( $chosen as $chosen_method ) { … … 1383 1412 return; 1384 1413 } 1414 1415 // Derive the chosen BookPod method from the standard WC shipping_method POST field. 1385 1416 // phpcs:ignore WordPress.Security.NonceVerification.Missing 1386 $shipping_method = isset( $_POST['bpat_bookpod_shipping_method'] ) ? sanitize_text_field( wp_unslash( $_POST['bpat_bookpod_shipping_method'] ) ) : ''; 1387 1388 if ( empty($shipping_method) ) { 1389 wc_add_notice( __( 'Please select a shipping method for BookPod book.', 'bookpod-author-tools' ), 'error' ); 1417 $raw_methods = isset( $_POST['shipping_method'] ) ? (array) $_POST['shipping_method'] : array(); 1418 $shipping_method = ''; 1419 foreach ( $raw_methods as $m ) { 1420 $m = sanitize_text_field( wp_unslash( $m ) ); 1421 if ( false !== strpos( $m, 'bpat_bookpod' ) ) { 1422 $shipping_method = ( false !== strpos( $m, 'pickup_point' ) ) ? 'pickup_point' : 'home'; 1423 break; 1424 } 1425 } 1426 1427 // If no BookPod rate was chosen WooCommerce itself will block submission. 1428 if ( empty( $shipping_method ) ) { 1429 return; 1390 1430 } 1391 1431 … … 1518 1558 } 1519 1559 1560 // Derive the BookPod shipping method from the chosen WC rate (home / pickup_point). 1561 // phpcs:ignore WordPress.Security.NonceVerification.Missing 1562 $raw_methods = isset( $_POST['shipping_method'] ) ? (array) $_POST['shipping_method'] : array(); 1563 $bookpod_method = ''; 1564 foreach ( $raw_methods as $m ) { 1565 $m = sanitize_text_field( wp_unslash( $m ) ); 1566 if ( false !== strpos( $m, 'bpat_bookpod' ) ) { 1567 $bookpod_method = ( false !== strpos( $m, 'pickup_point' ) ) ? 'pickup_point' : 'home'; 1568 break; 1569 } 1570 } 1571 if ( ! empty( $bookpod_method ) ) { 1572 update_post_meta( $order_id, '_bpat_bookpod_shipping_method', $bookpod_method ); 1573 } 1574 1520 1575 $fields = [ 1521 'bpat_bookpod_shipping_method',1522 1576 'bpat_street_name', 1523 1577 'bpat_building_number', -
bookpod-author-tools/trunk/bpat-woocommerce-shipping.php
r3475827 r3489826 98 98 return $methods; 99 99 } 100 101 /** 102 * When the cart contains only physical BookPod items AND the store has 103 * manually configured the BookPod WC shipping method in a zone, keep only 104 * the BookPod rates so the customer is not asked to pick twice. 105 * 106 * If BookPod is NOT configured as a WC shipping method we do not interfere — 107 * the store's own rates are returned unchanged and BookPod fulfillment happens 108 * silently via the API (bpat_add_bookpod_shipping_fee handles the cost). 109 */ 110 add_filter( 'woocommerce_package_rates', 'bpat_filter_package_rates_for_bookpod', 10, 2 ); 111 112 function bpat_filter_package_rates_for_bookpod( $rates, $package ) { 113 if ( ! function_exists( 'bpat_cart_has_only_physical_bookpod_items' ) || ! bpat_cart_has_only_physical_bookpod_items() ) { 114 return $rates; 115 } 116 117 $bookpod_rates = array_filter( 118 $rates, 119 function ( $rate_id ) { 120 return false !== strpos( $rate_id, 'bpat_bookpod' ); 121 }, 122 ARRAY_FILTER_USE_KEY 123 ); 124 125 // BookPod WC method is NOT configured in any zone — leave rates untouched. 126 if ( empty( $bookpod_rates ) ) { 127 return $rates; 128 } 129 130 // BookPod WC rates exist — keep only them so the customer picks once. 131 // Also sync chosen_shipping_methods in the session right now so that 132 // bpat_add_bookpod_shipping_fee() (which runs immediately after in the same 133 // calculate_totals() call) sees a BookPod rate as the chosen method and 134 // skips adding a fee on top of the WC rate cost. 135 if ( WC()->session ) { 136 $chosen = (array) WC()->session->get( 'chosen_shipping_methods', array() ); 137 $first_key = null; 138 foreach ( $bookpod_rates as $k => $_ ) { 139 $first_key = $k; 140 break; 141 } 142 $changed = false; 143 foreach ( $chosen as $i => $method ) { 144 if ( false === strpos( (string) $method, 'bpat_bookpod' ) ) { 145 $chosen[ $i ] = $first_key; 146 $changed = true; 147 } 148 } 149 if ( $changed ) { 150 WC()->session->set( 'chosen_shipping_methods', $chosen ); 151 } 152 } 153 154 return $bookpod_rates; 155 }
Note: See TracChangeset
for help on using the changeset viewer.