Changeset 3390679
- Timestamp:
- 11/05/2025 07:28:48 PM (4 months ago)
- Location:
- boxo-return
- Files:
-
- 18 edited
- 1 copied
-
tags/0.0.63 (copied) (copied from boxo-return/trunk)
-
tags/0.0.63/admin/order.css (modified) (1 diff)
-
tags/0.0.63/admin/product-picker.css (modified) (1 diff)
-
tags/0.0.63/admin/product-picker.js (modified) (1 diff)
-
tags/0.0.63/admin/settings.css (modified) (1 diff)
-
tags/0.0.63/boxo-return.php (modified) (2 diffs)
-
tags/0.0.63/checkout/boxo-checkout.css (modified) (1 diff)
-
tags/0.0.63/checkout/boxo-checkout.js (modified) (1 diff)
-
tags/0.0.63/checkout/checkout.php (modified) (2 diffs)
-
tags/0.0.63/readme.txt (modified) (2 diffs)
-
trunk/admin/order.css (modified) (1 diff)
-
trunk/admin/product-picker.css (modified) (1 diff)
-
trunk/admin/product-picker.js (modified) (1 diff)
-
trunk/admin/settings.css (modified) (1 diff)
-
trunk/boxo-return.php (modified) (2 diffs)
-
trunk/checkout/boxo-checkout.css (modified) (1 diff)
-
trunk/checkout/boxo-checkout.js (modified) (1 diff)
-
trunk/checkout/checkout.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
boxo-return/tags/0.0.63/admin/order.css
r3208611 r3390679 1 1 .boxo_packaging-info { 2 display: flex;3 align-items: center;4 gap: 5px;5 color: #01cc9b;6 font-weight: 500;2 display: flex; 3 align-items: center; 4 gap: 5px; 5 color: #01cc9b; 6 font-weight: 500; 7 7 } 8 8 9 9 .boxo_packaging-icon { 10 display: inline-block;11 width: 22px !important;12 height: 22px !important;10 display: inline-block; 11 width: 22px !important; 12 height: 22px !important; 13 13 } 14 14 15 15 .boxo_packaging-icon svg { 16 display: block !important;17 width: 100% !important;18 height: 100% !important;16 display: block !important; 17 width: 100% !important; 18 height: 100% !important; 19 19 } -
boxo-return/tags/0.0.63/admin/product-picker.css
r3274490 r3390679 1 1 .bxpp, 2 2 .bxpp * { 3 /* Reset */4 margin: 0;5 box-sizing: border-box;3 /* Reset */ 4 margin: 0; 5 box-sizing: border-box; 6 6 } 7 7 8 8 .bxpp { 9 display: flex;10 flex-direction: column;11 gap: 10px;9 display: flex; 10 flex-direction: column; 11 gap: 10px; 12 12 } 13 13 14 14 .bxpp_search { 15 position: relative;15 position: relative; 16 16 } 17 17 18 18 .bxpp_search-input-container { 19 display: flex;20 width: fit-content;21 align-items: center;22 gap: 10px;19 display: flex; 20 width: fit-content; 21 align-items: center; 22 gap: 10px; 23 23 } 24 24 25 25 .bxpp_search-results { 26 z-index: 999;27 display: none;28 position: absolute;29 top: calc(100% + 5px);30 width: 100%;31 max-width: 600px;32 max-height: 330px;33 overflow: scroll;34 border: 1px solid #8c8f94;35 background-color: white;26 z-index: 999; 27 display: none; 28 position: absolute; 29 top: calc(100% + 5px); 30 width: 100%; 31 max-width: 600px; 32 max-height: 330px; 33 overflow: scroll; 34 border: 1px solid #8c8f94; 35 background-color: white; 36 36 } 37 37 38 38 .bxpp_search:focus-within .bxpp_search-results { 39 display: block;39 display: block; 40 40 } 41 41 42 42 .bxpp_search-result { 43 display: flex;44 gap: 10px;45 align-items: center;46 padding: 10px;43 display: flex; 44 gap: 10px; 45 align-items: center; 46 padding: 10px; 47 47 } 48 48 49 49 .bxpp_search-result-image { 50 width: 30px;51 height: 30px;52 object-fit: contain;50 width: 30px; 51 height: 30px; 52 object-fit: contain; 53 53 } 54 54 55 55 .bxpp_search-result.clickable { 56 cursor: pointer;56 cursor: pointer; 57 57 } 58 58 59 59 .bxpp_search-result.clickable:hover { 60 background-color: #dcdcde;60 background-color: #dcdcde; 61 61 } 62 62 63 63 .bxpp_selected-products-viewport { 64 max-height: 300px;65 overflow: scroll;64 max-height: 300px; 65 overflow: scroll; 66 66 } 67 67 68 68 .bxpp_selected-product-image-column { 69 width: 40px;69 width: 40px; 70 70 } 71 71 72 72 .bxpp_selected-product-image { 73 width: 30px;74 height: 30px;75 object-fit: contain;73 width: 30px; 74 height: 30px; 75 object-fit: contain; 76 76 } -
boxo-return/tags/0.0.63/admin/product-picker.js
r3273560 r3390679 1 1 document.addEventListener('alpine:init', () => { 2 /**3 * @param {string} ajaxUrl4 * @param {string} nonce5 */6 const productPicker = (ajaxUrl, nonce) => ({7 init() {8 this.selectedProducts = JSON.parse(9 // @ts-ignore: no Alpine type for 'this'.10 this.$root.querySelector('.bxpp_initial-products-json').innerText11 )12 this.searchProducts()13 // @ts-ignore: no Alpine type for 'this'.14 this.$watch('keyword', (val) => this.searchProducts(val))15 },2 /** 3 * @param {string} ajaxUrl 4 * @param {string} nonce 5 */ 6 const productPicker = (ajaxUrl, nonce) => ({ 7 init() { 8 this.selectedProducts = JSON.parse( 9 // @ts-ignore: no Alpine type for 'this'. 10 this.$root.querySelector('.bxpp_initial-products-json').innerText 11 ) 12 this.searchProducts() 13 // @ts-ignore: no Alpine type for 'this'. 14 this.$watch('keyword', (val) => this.searchProducts(val)) 15 }, 16 16 17 // State:18 /** @type {{id: string; title: string, image: string | null}[]} */19 selectedProducts: [],20 keyword: '',21 loading: false,22 searchResults: [],17 // State: 18 /** @type {{id: string; title: string, image: string | null}[]} */ 19 selectedProducts: [], 20 keyword: '', 21 loading: false, 22 searchResults: [], 23 23 24 // Derived state:25 value() {26 return this.selectedProducts.map((p) => p.id).join(',')27 },28 hasSelectedProducts() {29 return this.selectedProducts.length > 030 },31 hasSearchResults() {32 return this.searchResults.length > 033 },24 // Derived state: 25 value() { 26 return this.selectedProducts.map((p) => p.id).join(',') 27 }, 28 hasSelectedProducts() { 29 return this.selectedProducts.length > 0 30 }, 31 hasSearchResults() { 32 return this.searchResults.length > 0 33 }, 34 34 35 // Methods:36 async searchProducts() {37 this.loading = true35 // Methods: 36 async searchProducts() { 37 this.loading = true 38 38 39 try {40 const params = new URLSearchParams({41 action: 'boxo_product_search',42 _ajax_nonce: nonce,43 keyword: this.keyword,44 skip: this.selectedProducts.map((p) => p.id).join(',')45 })39 try { 40 const params = new URLSearchParams({ 41 action: 'boxo_product_search', 42 _ajax_nonce: nonce, 43 keyword: this.keyword, 44 skip: this.selectedProducts.map((p) => p.id).join(','), 45 }) 46 46 47 const res = await fetch(ajaxUrl + '?' + params.toString()) 48 if (!res.ok) { 49 console.error('[BOXO Return] Search products: ' + res.status + ' ' + res.statusText) 50 this.searchResults = [] 51 return 52 } 53 this.searchResults = await res.json() 54 } catch (err) { 55 console.error(err) 56 } finally { 57 this.loading = false 58 } 59 }, 47 const res = await fetch(ajaxUrl + '?' + params.toString()) 48 if (!res.ok) { 49 console.error( 50 '[BOXO Return] Search products: ' + res.status + ' ' + res.statusText 51 ) 52 this.searchResults = [] 53 return 54 } 55 this.searchResults = await res.json() 56 } catch (err) { 57 console.error(err) 58 } finally { 59 this.loading = false 60 } 61 }, 60 62 61 /**62 *63 * @param {KeyboardEvent} e64 */65 handleEnterPress(e) {66 // Prevent parent form submit.67 e.preventDefault()68 },63 /** 64 * 65 * @param {KeyboardEvent} e 66 */ 67 handleEnterPress(e) { 68 // Prevent parent form submit. 69 e.preventDefault() 70 }, 69 71 70 /**71 * @param {string} id72 * @param {string} title73 * @param {string} image74 */75 handleSearchResultClick(id, title, image) {76 this.selectedProducts.unshift({id, title, image})77 if (this.keyword) {78 // Clear keyword, which triggers a new blank search automatically.79 this.keyword = ''80 return81 }82 // If keyword was already blank, trigger a new blank search manually.83 this.searchProducts()84 },72 /** 73 * @param {string} id 74 * @param {string} title 75 * @param {string} image 76 */ 77 handleSearchResultClick(id, title, image) { 78 this.selectedProducts.unshift({id, title, image}) 79 if (this.keyword) { 80 // Clear keyword, which triggers a new blank search automatically. 81 this.keyword = '' 82 return 83 } 84 // If keyword was already blank, trigger a new blank search manually. 85 this.searchProducts() 86 }, 85 87 86 /**87 * @param {string} id88 */89 handleRemoveProductClick(id) {90 this.selectedProducts.splice(91 this.selectedProducts.findIndex((p) => p.id === id),92 193 )94 this.searchProducts()95 }96 })88 /** 89 * @param {string} id 90 */ 91 handleRemoveProductClick(id) { 92 this.selectedProducts.splice( 93 this.selectedProducts.findIndex((p) => p.id === id), 94 1 95 ) 96 this.searchProducts() 97 }, 98 }) 97 99 98 // @ts-ignore: no Alpine types.99 window.Alpine.data('productPicker', productPicker)100 // @ts-ignore: no Alpine types. 101 window.Alpine.data('productPicker', productPicker) 100 102 }) -
boxo-return/tags/0.0.63/admin/settings.css
r3208611 r3390679 1 1 [x-cloak] { 2 display: none !important;2 display: none !important; 3 3 } 4 4 5 5 .boxo_settings-field { 6 display: flex;7 flex-direction: column;8 gap: 20px;6 display: flex; 7 flex-direction: column; 8 gap: 20px; 9 9 } -
boxo-return/tags/0.0.63/boxo-return.php
r3375141 r3390679 2 2 /* 3 3 * Plugin Name: BOXO Return 4 * Version: 0.0.6 24 * Version: 0.0.63 5 5 * Requires at least: 6.5 6 6 * Requires PHP: 7.1 … … 22 22 } 23 23 24 const BOXO_RETURN_PLUGIN_VERSION = "0.0.6 2";24 const BOXO_RETURN_PLUGIN_VERSION = "0.0.63"; 25 25 26 26 include plugin_dir_path(__FILE__) . 'includes/constants.php'; -
boxo-return/tags/0.0.63/checkout/boxo-checkout.css
r3312507 r3390679 1 1 #boxo_container br { 2 /* Hide automatically inserted br tags. */3 display: none !important;2 /* Hide automatically inserted br tags. */ 3 display: none !important; 4 4 } 5 5 6 6 .boxo_option-icon { 7 display: inline-block;8 width: 22px !important;9 height: 22px !important;10 vertical-align: text-bottom;7 display: inline-block; 8 width: 22px !important; 9 height: 22px !important; 10 vertical-align: text-bottom; 11 11 } 12 12 13 13 .boxo_option-icon svg { 14 display: block !important;15 width: 100% !important;16 height: 100% !important;14 display: block !important; 15 width: 100% !important; 16 height: 100% !important; 17 17 } 18 18 19 19 .boxo_list-item-reusable { 20 /* Anchors tooltip. */21 position: relative;20 /* Anchors tooltip. */ 21 position: relative; 22 22 } 23 23 24 24 .boxo_info-container { 25 /* Reset */26 display: inline !important;25 /* Reset */ 26 display: inline !important; 27 27 } 28 28 29 29 .boxo_info-container, 30 30 .boxo_info-container * { 31 /* Reset */32 color: inherit !important;33 border: none !important;34 box-shadow: none !important;31 /* Reset */ 32 color: inherit !important; 33 border: none !important; 34 box-shadow: none !important; 35 35 } 36 36 37 37 .boxo_info-container:hover .boxo_info-tooltip { 38 visibility: visible;39 opacity: 1;38 visibility: visible; 39 opacity: 1; 40 40 } 41 41 42 42 .boxo_info-icon { 43 display: inline-block;44 width: 12px !important;45 height: 12px !important;46 vertical-align: middle;43 display: inline-block; 44 width: 12px !important; 45 height: 12px !important; 46 vertical-align: middle; 47 47 } 48 48 49 49 .boxo_info-icon svg { 50 display: block !important;51 width: 100% !important;52 height: 100% !important;50 display: block !important; 51 width: 100% !important; 52 height: 100% !important; 53 53 } 54 54 55 55 .boxo_info-tooltip { 56 /* Reset */57 white-space: normal;58 text-align: left;59 text-indent: initial;60 font-weight: normal;61 font-style: normal;62 text-transform: none;56 /* Reset */ 57 white-space: normal; 58 text-align: left; 59 text-indent: initial; 60 font-weight: normal; 61 font-style: normal; 62 text-transform: none; 63 63 64 z-index: 999; 65 position: absolute; 66 top: calc(100% + 8px); 67 right: 0; 68 width: max-content; 69 max-width: 360px; 70 border: 1px solid black !important; 71 background-color: white; 72 padding: 16px; 73 word-break: keep-all; 74 visibility: hidden; 75 opacity: 0; 76 transition: visibility 0.2s, opacity 0.2s; 64 z-index: 999; 65 position: absolute; 66 top: calc(100% + 8px); 67 right: 0; 68 width: max-content; 69 max-width: 360px; 70 border: 1px solid black !important; 71 background-color: white; 72 padding: 16px; 73 word-break: keep-all; 74 visibility: hidden; 75 opacity: 0; 76 transition: 77 visibility 0.2s, 78 opacity 0.2s; 77 79 } 78 80 79 81 .boxo_header { 80 /* Prevent table header from being hidden by another plugin. */81 display: table-cell;82 /* Prevent table header from being hidden by another plugin. */ 83 display: table-cell; 82 84 } -
boxo-return/tags/0.0.63/checkout/boxo-checkout.js
r3371141 r3390679 1 1 if (document.readyState !== 'loading') { 2 init()2 init() 3 3 } else { 4 document.addEventListener('DOMContentLoaded', init)4 document.addEventListener('DOMContentLoaded', init) 5 5 } 6 6 7 7 async function init() { 8 // Must use jQuery for event handlers because propagation of certain events appears to be blocked.9 jQuery(function ($) {10 // AJAX update checkout (incl. total price) on change in relevant data or packaging selection.11 $(document.body).on(12 'change',13 '#billing_country, #billing_postcode, #shipping_country, #shipping_postcode, #ship-to-different-address-checkbox, [name=boxo_packaging]',14 async () => {15 document.body.dispatchEvent(new Event('update_checkout'))16 }17 )18 })8 // Must use jQuery for event handlers because propagation of certain events appears to be blocked. 9 jQuery(function ($) { 10 // AJAX update checkout (incl. total price) on change in relevant data or packaging selection. 11 $(document.body).on( 12 'change', 13 '#billing_country, #billing_postcode, #shipping_country, #shipping_postcode, #ship-to-different-address-checkbox, [name=boxo_packaging]', 14 async () => { 15 document.body.dispatchEvent(new Event('update_checkout')) 16 } 17 ) 18 }) 19 19 20 console.info('[BOXO Return] Ready') 20 // Add selected packaging to AJAX request for custom checkouts where the input 21 // is not inside the checkout form. When the input is inside the checkout form, 22 // the data is already added in post_data, but it's redundantly added here as well. 23 jQuery(function ($) { 24 $.ajaxPrefilter(function (options) { 25 // If anything goes wrong, do not block the AJAX request. 26 try { 27 if (!options.url?.includes('wc-ajax=update_order_review')) { 28 return 29 } 30 /** @type HTMLInputElement | null */ 31 const input = document.querySelector('input[name="boxo_packaging"]:checked') 32 const packaging = input?.value 33 if (!packaging) { 34 throw new Error('[BOXO Return] No packaging input value.') 35 } 36 options.data += '&boxo_packaging=' + packaging 37 } catch (err) { 38 console.error('[BOXO Return]', err) 39 } 40 }) 41 }) 42 43 console.info('[BOXO Return] Ready') 21 44 } -
boxo-return/tags/0.0.63/checkout/checkout.php
r3371141 r3390679 8 8 add_action('woocommerce_init', 'Boxo_Checkout::init'); 9 9 10 // On trigger, eg. change in packaging selection, an AJAX request is made to 11 // ?wc-ajax=update-order-review. This request contains the selected packaging. 12 // This value is normally added to the AJAX because the form with class="checkout" 13 // is serialized as post_data. However, when the plugin inputs are outside of the 14 // checkout form, this does not work. To solve this, the selected packaging is 15 // also added to the AJAX request by script. 10 16 if (!class_exists('Boxo_Checkout')) { 11 17 class Boxo_Checkout { … … 288 294 */ 289 295 private static function get_selected_packaging() { 296 // In AJAX requests in standard woocommerce checkouts, the selected packaging 297 // will be inside the post_data field. 290 298 if (isset($_POST['post_data']) && is_string($_POST['post_data'])) { 291 // AJAX requests.299 $post_data = []; 292 300 parse_str($_POST['post_data'], $post_data); 293 } else { 294 // Non-AJAX requests (eg. checkout submit). 295 $post_data = $_POST; 296 } 297 return isset($post_data['boxo_packaging']) && is_string($post_data['boxo_packaging']) 298 ? $post_data['boxo_packaging'] 299 : null; 301 if (isset($post_data['boxo_packaging']) && is_string($post_data['boxo_packaging'])) { 302 return $post_data['boxo_packaging']; 303 } 304 } 305 306 // In custom woocommerce checkouts the value is added to $_POST by our script. 307 // Also, in non-AJAX requests (eg. checkout submit) the value will be in $_POST. 308 if (isset($_POST['boxo_packaging']) && is_string($_POST['boxo_packaging'])) { 309 return $_POST['boxo_packaging']; 310 } 311 return null; 300 312 } 301 313 } -
boxo-return/tags/0.0.63/readme.txt
r3375141 r3390679 4 4 Requires at least: 6.5 5 5 Tested up to: 6.8.3 6 Stable tag: 0.0.6 26 Stable tag: 0.0.63 7 7 Requires PHP: 7.1 8 8 License: GPLv2 or later … … 26 26 27 27 == Changelog == 28 29 = 0.0.63 = 30 Support custom checkouts where the checkout form has been modified. 28 31 29 32 = 0.0.62 = -
boxo-return/trunk/admin/order.css
r3208611 r3390679 1 1 .boxo_packaging-info { 2 display: flex;3 align-items: center;4 gap: 5px;5 color: #01cc9b;6 font-weight: 500;2 display: flex; 3 align-items: center; 4 gap: 5px; 5 color: #01cc9b; 6 font-weight: 500; 7 7 } 8 8 9 9 .boxo_packaging-icon { 10 display: inline-block;11 width: 22px !important;12 height: 22px !important;10 display: inline-block; 11 width: 22px !important; 12 height: 22px !important; 13 13 } 14 14 15 15 .boxo_packaging-icon svg { 16 display: block !important;17 width: 100% !important;18 height: 100% !important;16 display: block !important; 17 width: 100% !important; 18 height: 100% !important; 19 19 } -
boxo-return/trunk/admin/product-picker.css
r3274490 r3390679 1 1 .bxpp, 2 2 .bxpp * { 3 /* Reset */4 margin: 0;5 box-sizing: border-box;3 /* Reset */ 4 margin: 0; 5 box-sizing: border-box; 6 6 } 7 7 8 8 .bxpp { 9 display: flex;10 flex-direction: column;11 gap: 10px;9 display: flex; 10 flex-direction: column; 11 gap: 10px; 12 12 } 13 13 14 14 .bxpp_search { 15 position: relative;15 position: relative; 16 16 } 17 17 18 18 .bxpp_search-input-container { 19 display: flex;20 width: fit-content;21 align-items: center;22 gap: 10px;19 display: flex; 20 width: fit-content; 21 align-items: center; 22 gap: 10px; 23 23 } 24 24 25 25 .bxpp_search-results { 26 z-index: 999;27 display: none;28 position: absolute;29 top: calc(100% + 5px);30 width: 100%;31 max-width: 600px;32 max-height: 330px;33 overflow: scroll;34 border: 1px solid #8c8f94;35 background-color: white;26 z-index: 999; 27 display: none; 28 position: absolute; 29 top: calc(100% + 5px); 30 width: 100%; 31 max-width: 600px; 32 max-height: 330px; 33 overflow: scroll; 34 border: 1px solid #8c8f94; 35 background-color: white; 36 36 } 37 37 38 38 .bxpp_search:focus-within .bxpp_search-results { 39 display: block;39 display: block; 40 40 } 41 41 42 42 .bxpp_search-result { 43 display: flex;44 gap: 10px;45 align-items: center;46 padding: 10px;43 display: flex; 44 gap: 10px; 45 align-items: center; 46 padding: 10px; 47 47 } 48 48 49 49 .bxpp_search-result-image { 50 width: 30px;51 height: 30px;52 object-fit: contain;50 width: 30px; 51 height: 30px; 52 object-fit: contain; 53 53 } 54 54 55 55 .bxpp_search-result.clickable { 56 cursor: pointer;56 cursor: pointer; 57 57 } 58 58 59 59 .bxpp_search-result.clickable:hover { 60 background-color: #dcdcde;60 background-color: #dcdcde; 61 61 } 62 62 63 63 .bxpp_selected-products-viewport { 64 max-height: 300px;65 overflow: scroll;64 max-height: 300px; 65 overflow: scroll; 66 66 } 67 67 68 68 .bxpp_selected-product-image-column { 69 width: 40px;69 width: 40px; 70 70 } 71 71 72 72 .bxpp_selected-product-image { 73 width: 30px;74 height: 30px;75 object-fit: contain;73 width: 30px; 74 height: 30px; 75 object-fit: contain; 76 76 } -
boxo-return/trunk/admin/product-picker.js
r3273560 r3390679 1 1 document.addEventListener('alpine:init', () => { 2 /**3 * @param {string} ajaxUrl4 * @param {string} nonce5 */6 const productPicker = (ajaxUrl, nonce) => ({7 init() {8 this.selectedProducts = JSON.parse(9 // @ts-ignore: no Alpine type for 'this'.10 this.$root.querySelector('.bxpp_initial-products-json').innerText11 )12 this.searchProducts()13 // @ts-ignore: no Alpine type for 'this'.14 this.$watch('keyword', (val) => this.searchProducts(val))15 },2 /** 3 * @param {string} ajaxUrl 4 * @param {string} nonce 5 */ 6 const productPicker = (ajaxUrl, nonce) => ({ 7 init() { 8 this.selectedProducts = JSON.parse( 9 // @ts-ignore: no Alpine type for 'this'. 10 this.$root.querySelector('.bxpp_initial-products-json').innerText 11 ) 12 this.searchProducts() 13 // @ts-ignore: no Alpine type for 'this'. 14 this.$watch('keyword', (val) => this.searchProducts(val)) 15 }, 16 16 17 // State:18 /** @type {{id: string; title: string, image: string | null}[]} */19 selectedProducts: [],20 keyword: '',21 loading: false,22 searchResults: [],17 // State: 18 /** @type {{id: string; title: string, image: string | null}[]} */ 19 selectedProducts: [], 20 keyword: '', 21 loading: false, 22 searchResults: [], 23 23 24 // Derived state:25 value() {26 return this.selectedProducts.map((p) => p.id).join(',')27 },28 hasSelectedProducts() {29 return this.selectedProducts.length > 030 },31 hasSearchResults() {32 return this.searchResults.length > 033 },24 // Derived state: 25 value() { 26 return this.selectedProducts.map((p) => p.id).join(',') 27 }, 28 hasSelectedProducts() { 29 return this.selectedProducts.length > 0 30 }, 31 hasSearchResults() { 32 return this.searchResults.length > 0 33 }, 34 34 35 // Methods:36 async searchProducts() {37 this.loading = true35 // Methods: 36 async searchProducts() { 37 this.loading = true 38 38 39 try {40 const params = new URLSearchParams({41 action: 'boxo_product_search',42 _ajax_nonce: nonce,43 keyword: this.keyword,44 skip: this.selectedProducts.map((p) => p.id).join(',')45 })39 try { 40 const params = new URLSearchParams({ 41 action: 'boxo_product_search', 42 _ajax_nonce: nonce, 43 keyword: this.keyword, 44 skip: this.selectedProducts.map((p) => p.id).join(','), 45 }) 46 46 47 const res = await fetch(ajaxUrl + '?' + params.toString()) 48 if (!res.ok) { 49 console.error('[BOXO Return] Search products: ' + res.status + ' ' + res.statusText) 50 this.searchResults = [] 51 return 52 } 53 this.searchResults = await res.json() 54 } catch (err) { 55 console.error(err) 56 } finally { 57 this.loading = false 58 } 59 }, 47 const res = await fetch(ajaxUrl + '?' + params.toString()) 48 if (!res.ok) { 49 console.error( 50 '[BOXO Return] Search products: ' + res.status + ' ' + res.statusText 51 ) 52 this.searchResults = [] 53 return 54 } 55 this.searchResults = await res.json() 56 } catch (err) { 57 console.error(err) 58 } finally { 59 this.loading = false 60 } 61 }, 60 62 61 /**62 *63 * @param {KeyboardEvent} e64 */65 handleEnterPress(e) {66 // Prevent parent form submit.67 e.preventDefault()68 },63 /** 64 * 65 * @param {KeyboardEvent} e 66 */ 67 handleEnterPress(e) { 68 // Prevent parent form submit. 69 e.preventDefault() 70 }, 69 71 70 /**71 * @param {string} id72 * @param {string} title73 * @param {string} image74 */75 handleSearchResultClick(id, title, image) {76 this.selectedProducts.unshift({id, title, image})77 if (this.keyword) {78 // Clear keyword, which triggers a new blank search automatically.79 this.keyword = ''80 return81 }82 // If keyword was already blank, trigger a new blank search manually.83 this.searchProducts()84 },72 /** 73 * @param {string} id 74 * @param {string} title 75 * @param {string} image 76 */ 77 handleSearchResultClick(id, title, image) { 78 this.selectedProducts.unshift({id, title, image}) 79 if (this.keyword) { 80 // Clear keyword, which triggers a new blank search automatically. 81 this.keyword = '' 82 return 83 } 84 // If keyword was already blank, trigger a new blank search manually. 85 this.searchProducts() 86 }, 85 87 86 /**87 * @param {string} id88 */89 handleRemoveProductClick(id) {90 this.selectedProducts.splice(91 this.selectedProducts.findIndex((p) => p.id === id),92 193 )94 this.searchProducts()95 }96 })88 /** 89 * @param {string} id 90 */ 91 handleRemoveProductClick(id) { 92 this.selectedProducts.splice( 93 this.selectedProducts.findIndex((p) => p.id === id), 94 1 95 ) 96 this.searchProducts() 97 }, 98 }) 97 99 98 // @ts-ignore: no Alpine types.99 window.Alpine.data('productPicker', productPicker)100 // @ts-ignore: no Alpine types. 101 window.Alpine.data('productPicker', productPicker) 100 102 }) -
boxo-return/trunk/admin/settings.css
r3208611 r3390679 1 1 [x-cloak] { 2 display: none !important;2 display: none !important; 3 3 } 4 4 5 5 .boxo_settings-field { 6 display: flex;7 flex-direction: column;8 gap: 20px;6 display: flex; 7 flex-direction: column; 8 gap: 20px; 9 9 } -
boxo-return/trunk/boxo-return.php
r3375141 r3390679 2 2 /* 3 3 * Plugin Name: BOXO Return 4 * Version: 0.0.6 24 * Version: 0.0.63 5 5 * Requires at least: 6.5 6 6 * Requires PHP: 7.1 … … 22 22 } 23 23 24 const BOXO_RETURN_PLUGIN_VERSION = "0.0.6 2";24 const BOXO_RETURN_PLUGIN_VERSION = "0.0.63"; 25 25 26 26 include plugin_dir_path(__FILE__) . 'includes/constants.php'; -
boxo-return/trunk/checkout/boxo-checkout.css
r3312507 r3390679 1 1 #boxo_container br { 2 /* Hide automatically inserted br tags. */3 display: none !important;2 /* Hide automatically inserted br tags. */ 3 display: none !important; 4 4 } 5 5 6 6 .boxo_option-icon { 7 display: inline-block;8 width: 22px !important;9 height: 22px !important;10 vertical-align: text-bottom;7 display: inline-block; 8 width: 22px !important; 9 height: 22px !important; 10 vertical-align: text-bottom; 11 11 } 12 12 13 13 .boxo_option-icon svg { 14 display: block !important;15 width: 100% !important;16 height: 100% !important;14 display: block !important; 15 width: 100% !important; 16 height: 100% !important; 17 17 } 18 18 19 19 .boxo_list-item-reusable { 20 /* Anchors tooltip. */21 position: relative;20 /* Anchors tooltip. */ 21 position: relative; 22 22 } 23 23 24 24 .boxo_info-container { 25 /* Reset */26 display: inline !important;25 /* Reset */ 26 display: inline !important; 27 27 } 28 28 29 29 .boxo_info-container, 30 30 .boxo_info-container * { 31 /* Reset */32 color: inherit !important;33 border: none !important;34 box-shadow: none !important;31 /* Reset */ 32 color: inherit !important; 33 border: none !important; 34 box-shadow: none !important; 35 35 } 36 36 37 37 .boxo_info-container:hover .boxo_info-tooltip { 38 visibility: visible;39 opacity: 1;38 visibility: visible; 39 opacity: 1; 40 40 } 41 41 42 42 .boxo_info-icon { 43 display: inline-block;44 width: 12px !important;45 height: 12px !important;46 vertical-align: middle;43 display: inline-block; 44 width: 12px !important; 45 height: 12px !important; 46 vertical-align: middle; 47 47 } 48 48 49 49 .boxo_info-icon svg { 50 display: block !important;51 width: 100% !important;52 height: 100% !important;50 display: block !important; 51 width: 100% !important; 52 height: 100% !important; 53 53 } 54 54 55 55 .boxo_info-tooltip { 56 /* Reset */57 white-space: normal;58 text-align: left;59 text-indent: initial;60 font-weight: normal;61 font-style: normal;62 text-transform: none;56 /* Reset */ 57 white-space: normal; 58 text-align: left; 59 text-indent: initial; 60 font-weight: normal; 61 font-style: normal; 62 text-transform: none; 63 63 64 z-index: 999; 65 position: absolute; 66 top: calc(100% + 8px); 67 right: 0; 68 width: max-content; 69 max-width: 360px; 70 border: 1px solid black !important; 71 background-color: white; 72 padding: 16px; 73 word-break: keep-all; 74 visibility: hidden; 75 opacity: 0; 76 transition: visibility 0.2s, opacity 0.2s; 64 z-index: 999; 65 position: absolute; 66 top: calc(100% + 8px); 67 right: 0; 68 width: max-content; 69 max-width: 360px; 70 border: 1px solid black !important; 71 background-color: white; 72 padding: 16px; 73 word-break: keep-all; 74 visibility: hidden; 75 opacity: 0; 76 transition: 77 visibility 0.2s, 78 opacity 0.2s; 77 79 } 78 80 79 81 .boxo_header { 80 /* Prevent table header from being hidden by another plugin. */81 display: table-cell;82 /* Prevent table header from being hidden by another plugin. */ 83 display: table-cell; 82 84 } -
boxo-return/trunk/checkout/boxo-checkout.js
r3371141 r3390679 1 1 if (document.readyState !== 'loading') { 2 init()2 init() 3 3 } else { 4 document.addEventListener('DOMContentLoaded', init)4 document.addEventListener('DOMContentLoaded', init) 5 5 } 6 6 7 7 async function init() { 8 // Must use jQuery for event handlers because propagation of certain events appears to be blocked.9 jQuery(function ($) {10 // AJAX update checkout (incl. total price) on change in relevant data or packaging selection.11 $(document.body).on(12 'change',13 '#billing_country, #billing_postcode, #shipping_country, #shipping_postcode, #ship-to-different-address-checkbox, [name=boxo_packaging]',14 async () => {15 document.body.dispatchEvent(new Event('update_checkout'))16 }17 )18 })8 // Must use jQuery for event handlers because propagation of certain events appears to be blocked. 9 jQuery(function ($) { 10 // AJAX update checkout (incl. total price) on change in relevant data or packaging selection. 11 $(document.body).on( 12 'change', 13 '#billing_country, #billing_postcode, #shipping_country, #shipping_postcode, #ship-to-different-address-checkbox, [name=boxo_packaging]', 14 async () => { 15 document.body.dispatchEvent(new Event('update_checkout')) 16 } 17 ) 18 }) 19 19 20 console.info('[BOXO Return] Ready') 20 // Add selected packaging to AJAX request for custom checkouts where the input 21 // is not inside the checkout form. When the input is inside the checkout form, 22 // the data is already added in post_data, but it's redundantly added here as well. 23 jQuery(function ($) { 24 $.ajaxPrefilter(function (options) { 25 // If anything goes wrong, do not block the AJAX request. 26 try { 27 if (!options.url?.includes('wc-ajax=update_order_review')) { 28 return 29 } 30 /** @type HTMLInputElement | null */ 31 const input = document.querySelector('input[name="boxo_packaging"]:checked') 32 const packaging = input?.value 33 if (!packaging) { 34 throw new Error('[BOXO Return] No packaging input value.') 35 } 36 options.data += '&boxo_packaging=' + packaging 37 } catch (err) { 38 console.error('[BOXO Return]', err) 39 } 40 }) 41 }) 42 43 console.info('[BOXO Return] Ready') 21 44 } -
boxo-return/trunk/checkout/checkout.php
r3371141 r3390679 8 8 add_action('woocommerce_init', 'Boxo_Checkout::init'); 9 9 10 // On trigger, eg. change in packaging selection, an AJAX request is made to 11 // ?wc-ajax=update-order-review. This request contains the selected packaging. 12 // This value is normally added to the AJAX because the form with class="checkout" 13 // is serialized as post_data. However, when the plugin inputs are outside of the 14 // checkout form, this does not work. To solve this, the selected packaging is 15 // also added to the AJAX request by script. 10 16 if (!class_exists('Boxo_Checkout')) { 11 17 class Boxo_Checkout { … … 288 294 */ 289 295 private static function get_selected_packaging() { 296 // In AJAX requests in standard woocommerce checkouts, the selected packaging 297 // will be inside the post_data field. 290 298 if (isset($_POST['post_data']) && is_string($_POST['post_data'])) { 291 // AJAX requests.299 $post_data = []; 292 300 parse_str($_POST['post_data'], $post_data); 293 } else { 294 // Non-AJAX requests (eg. checkout submit). 295 $post_data = $_POST; 296 } 297 return isset($post_data['boxo_packaging']) && is_string($post_data['boxo_packaging']) 298 ? $post_data['boxo_packaging'] 299 : null; 301 if (isset($post_data['boxo_packaging']) && is_string($post_data['boxo_packaging'])) { 302 return $post_data['boxo_packaging']; 303 } 304 } 305 306 // In custom woocommerce checkouts the value is added to $_POST by our script. 307 // Also, in non-AJAX requests (eg. checkout submit) the value will be in $_POST. 308 if (isset($_POST['boxo_packaging']) && is_string($_POST['boxo_packaging'])) { 309 return $_POST['boxo_packaging']; 310 } 311 return null; 300 312 } 301 313 } -
boxo-return/trunk/readme.txt
r3375141 r3390679 4 4 Requires at least: 6.5 5 5 Tested up to: 6.8.3 6 Stable tag: 0.0.6 26 Stable tag: 0.0.63 7 7 Requires PHP: 7.1 8 8 License: GPLv2 or later … … 26 26 27 27 == Changelog == 28 29 = 0.0.63 = 30 Support custom checkouts where the checkout form has been modified. 28 31 29 32 = 0.0.62 =
Note: See TracChangeset
for help on using the changeset viewer.