diff --git a/admin/assets/js/admin-editor.js b/admin/assets/js/admin-editor.js index f1006d9..dc505bf 100644 --- a/admin/assets/js/admin-editor.js +++ b/admin/assets/js/admin-editor.js @@ -596,11 +596,6 @@ jQuery(function($){ } } - $(document).on('change', '#customer_data select', function() { - var value = $(this).val(); - $(this).attr('data-current-value', value); - }); - $(document).on('click', '.delete-preview-field', function(e){ e.preventDefault(); $(this).parents('.preview-field').remove(); @@ -760,40 +755,40 @@ jQuery(function($){ $(this).closest('.child-field-title').toggleClass('option-detail-opened'); }); - var all_checkbox = $('[type="checkbox"]'); - if(all_checkbox.length > 0){ - $.each(all_checkbox, function(a,b){ - if($(b).val() == 'yes'){ - $(b).val('no').trigger('click'); - } - }); - } + // var all_checkbox = $('[type="checkbox"]'); + // if(all_checkbox.length > 0){ + // $.each(all_checkbox, function(a,b){ + // if($(b).val() == 'yes'){ + // $(b).val('no').trigger('click'); + // } + // }); + // } - function modify_payment_box_behavior() { + // function modify_payment_box_behavior() { - var allbox = $('#payments multi_checkbox'); - var checkbox_input = $('.payments-payment input[type=checkbox]'); - var checked_value = []; - if(checkbox_input.length > 0){ - $.each(checkbox_input, function(x, y){ - if($(y).is(':checked')){ - checked_value.push($(y).val()); - $('[data-field=wpcfto_addon_option_payment_'+$(y).val()+']').show(); - }else{ - $('[data-field=wpcfto_addon_option_payment_'+$(y).val()+']').hide(); - } - }); - } + // var allbox = $('#payments multi_checkbox'); + // var checkbox_input = $('.payments-payment input[type=checkbox]'); + // var checked_value = []; + // if(checkbox_input.length > 0){ + // $.each(checkbox_input, function(x, y){ + // if($(y).is(':checked')){ + // checked_value.push($(y).val()); + // $('[data-field=wpcfto_addon_option_payment_'+$(y).val()+']').show(); + // }else{ + // $('[data-field=wpcfto_addon_option_payment_'+$(y).val()+']').hide(); + // } + // }); + // } - } + // } - setTimeout(() => { - modify_payment_box_behavior(); - }, 500); + // setTimeout(() => { + // modify_payment_box_behavior(); + // }, 500); - $(document).on('click', '.payments-payment input[type=checkbox]', function(){ - modify_payment_box_behavior(); - }); + // $(document).on('click', '.payments-payment input[type=checkbox]', function(){ + // modify_payment_box_behavior(); + // }); $(document).on('mouseover', 'span.grab', function(){ $(this).css('pointer', 'grab'); @@ -807,9 +802,14 @@ jQuery(function($){ $(this).closest('.child-fields-wrapper').find('.the_title').text($(this).val()); }); + $(document).on('change', '#customer_data select', function() { + var value = $(this).val(); + $(this).attr('data-current-value', value); + }); + }); -jQuery(function($){ +// jQuery(function($){ // setTimeout(() => { // var autocomplete_fields = $('.wpcfto-box .autocomplete'); @@ -831,116 +831,116 @@ jQuery(function($){ // }, 500); // }); - $( document ).on( 'click', '.add-thumbnail', function( event ) { + // $( document ).on( 'click', '.add-thumbnail', function( event ) { - var gallery_items_frame; - const $el = $( this ); - var target_field = $el.attr('data-field'); - var target_id = $el.siblings('.'+target_field+'-id'); - var target_url = $el.siblings('.'+target_field+'-url'); - var selected = target_id.val(); - var able_multiple = $el.attr('data-able-multiple'); + // var gallery_items_frame; + // const $el = $( this ); + // var target_field = $el.attr('data-field'); + // var target_id = $el.siblings('.'+target_field+'-id'); + // var target_url = $el.siblings('.'+target_field+'-url'); + // var selected = target_id.val(); + // var able_multiple = $el.attr('data-able-multiple'); - event.preventDefault(); + // event.preventDefault(); - if ( gallery_items_frame ) { + // if ( gallery_items_frame ) { - // Select the attachment when the frame opens - gallery_items_frame.on( 'open', function() { - var selection = gallery_items_frame.state().get( 'selection' ); - selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] ); - }); + // // Select the attachment when the frame opens + // gallery_items_frame.on( 'open', function() { + // var selection = gallery_items_frame.state().get( 'selection' ); + // selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] ); + // }); - // Open the modal. - gallery_items_frame.open(); + // // Open the modal. + // gallery_items_frame.open(); - return; - } + // return; + // } - // Create the media frame. - gallery_items_frame = wp.media.frames.gallery_items = wp.media({ - // Set the title of the modal. - title: 'Choose or upload media', - button: { - text: 'Select' - }, - states: [ - new wp.media.controller.Library({ - title: 'Choose or upload media', - filterable: 'all', - multiple: able_multiple - }) - ] - }); + // // Create the media frame. + // gallery_items_frame = wp.media.frames.gallery_items = wp.media({ + // // Set the title of the modal. + // title: 'Choose or upload media', + // button: { + // text: 'Select' + // }, + // states: [ + // new wp.media.controller.Library({ + // title: 'Choose or upload media', + // filterable: 'all', + // multiple: able_multiple + // }) + // ] + // }); - // Select the attachment when the frame opens - gallery_items_frame.on( 'open', function() { - var selection = gallery_items_frame.state().get( 'selection' ); - selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] ); - }); + // // Select the attachment when the frame opens + // gallery_items_frame.on( 'open', function() { + // var selection = gallery_items_frame.state().get( 'selection' ); + // selection.reset( selected ? [ wp.media.attachment( selected ) ] : [] ); + // }); - gallery_items_frame.on( 'select', function() { - attachment = gallery_items_frame.state().get('selection').first().toJSON(); - target_id.val( attachment.id ); - target_url.val( attachment.url ); - if(target_id.val() !== ''){ - // $el.removeClass('text-white').addClass('text-info d-none'); - if($el.hasClass('btn')){ - $el.siblings('i').hide(); - }else{ - $el.hide(); - } - $el.siblings('img').removeClass('d-none').attr('src', attachment.url).show(); - }else{ - // $el.removeClass('text-info d-none').addClass('text-white'); - if($el.hasClass('btn')){ - $el.siblings('i').show(); - }else{ - $el.show(); - } - $el.siblings('img').addClass('d-none').hide(); - } - }); + // gallery_items_frame.on( 'select', function() { + // attachment = gallery_items_frame.state().get('selection').first().toJSON(); + // target_id.val( attachment.id ); + // target_url.val( attachment.url ); + // if(target_id.val() !== ''){ + // // $el.removeClass('text-white').addClass('text-info d-none'); + // if($el.hasClass('btn')){ + // $el.siblings('i').hide(); + // }else{ + // $el.hide(); + // } + // $el.siblings('img').removeClass('d-none').attr('src', attachment.url).show(); + // }else{ + // // $el.removeClass('text-info d-none').addClass('text-white'); + // if($el.hasClass('btn')){ + // $el.siblings('i').show(); + // }else{ + // $el.show(); + // } + // $el.siblings('img').addClass('d-none').hide(); + // } + // }); - // Open the modal. - gallery_items_frame.open(); + // // Open the modal. + // gallery_items_frame.open(); - }); + // }); - $( document ).on( 'click', '.trumbowyg-button-group:has(.trumbowyg-insertImage-button)', function( event ) { + // $( document ).on( 'click', '.trumbowyg-button-group:has(.trumbowyg-insertImage-button)', function( event ) { - var gallery_items_frame; + // var gallery_items_frame; - event.preventDefault(); + // event.preventDefault(); - // Create the media frame. - gallery_items_frame = wp.media.frames.gallery_items = wp.media({ - // Set the title of the modal. - title: 'Choose or upload media', - button: { - text: 'Select' - }, - states: [ - new wp.media.controller.Library({ - title: 'Choose or upload media', - filterable: 'all', - multiple: false - }) - ] - }); + // // Create the media frame. + // gallery_items_frame = wp.media.frames.gallery_items = wp.media({ + // // Set the title of the modal. + // title: 'Choose or upload media', + // button: { + // text: 'Select' + // }, + // states: [ + // new wp.media.controller.Library({ + // title: 'Choose or upload media', + // filterable: 'all', + // multiple: false + // }) + // ] + // }); - gallery_items_frame.on( 'select', function() { - attachment = gallery_items_frame.state().get('selection').first().toJSON(); - var target_input_url = $('.trumbowyg-modal.trumbowyg-fixed-top .trumbowyg-input-html input'); - var target_confirm = $('.trumbowyg-modal.trumbowyg-fixed-top .trumbowyg-modal-submit'); - target_input_url.val( attachment.url ); - target_confirm.trigger('click'); + // gallery_items_frame.on( 'select', function() { + // attachment = gallery_items_frame.state().get('selection').first().toJSON(); + // var target_input_url = $('.trumbowyg-modal.trumbowyg-fixed-top .trumbowyg-input-html input'); + // var target_confirm = $('.trumbowyg-modal.trumbowyg-fixed-top .trumbowyg-modal-submit'); + // target_input_url.val( attachment.url ); + // target_confirm.trigger('click'); - }); + // }); - // Open the modal. - gallery_items_frame.open(); + // // Open the modal. + // gallery_items_frame.open(); - }); + // }); -}); \ No newline at end of file +// }); \ No newline at end of file diff --git a/admin/assets/js/admin-pages.js b/admin/assets/js/admin-pages.js index 7c7177b..1ed22da 100644 --- a/admin/assets/js/admin-pages.js +++ b/admin/assets/js/admin-pages.js @@ -1,13 +1,13 @@ function numberFormat(nStr) { - nStr = parseFloat(nStr).toFixed(2); - var x = nStr.split('.'); - var x1 = x[0]; - var x2 = x.length > 1 ? '.' + x[1] : ''; - var rgx = /(\d+)(\d{3})/; - while (rgx.test(x1)) { - x1 = x1.replace(rgx, '$1' + ',' + '$2'); - } - return x1 + x2; + nStr = parseFloat(nStr).toFixed(2); + var x = nStr.split('.'); + var x1 = x[0]; + var x2 = x.length > 1 ? '.' + x[1] : ''; + var rgx = /(\d+)(\d{3})/; + while (rgx.test(x1)) { + x1 = x1.replace(rgx, '$1' + ',' + '$2'); + } + return x1 + x2; } function processPostsReport(data) { @@ -38,32 +38,32 @@ jQuery(function($){ }); (function() { - var supportsPassive = false; - try { - var opts = Object.defineProperty({}, 'passive', { - get: function() { - supportsPassive = true; - } - }); - window.addEventListener("testPassive", null, opts); - window.removeEventListener("testPassive", null, opts); - } catch (e) {} - - if (!supportsPassive) return; - - var origAddEventListener = EventTarget.prototype.addEventListener; - EventTarget.prototype.addEventListener = function(type, listener, options) { - // Only patch touchstart and touchmove if options is not explicitly passive - if ( - (type === 'touchstart' || type === 'touchmove') && - (options === undefined || options === false || (typeof options === 'object' && !options.passive)) - ) { - options = options || {}; - if (typeof options === 'object') { - options.passive = true; - } + var supportsPassive = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function() { + supportsPassive = true; } - return origAddEventListener.call(this, type, listener, options); - }; - })(); + }); + window.addEventListener("testPassive", null, opts); + window.removeEventListener("testPassive", null, opts); + } catch (e) {} + + if (!supportsPassive) return; + + var origAddEventListener = EventTarget.prototype.addEventListener; + EventTarget.prototype.addEventListener = function(type, listener, options) { + // Only patch touchstart and touchmove if options is not explicitly passive + if ( + (type === 'touchstart' || type === 'touchmove') && + (options === undefined || options === false || (typeof options === 'object' && !options.passive)) + ) { + options = options || {}; + if (typeof options === 'object') { + options.passive = true; + } + } + return origAddEventListener.call(this, type, listener, options); + }; +})(); \ No newline at end of file diff --git a/includes/Form.php b/includes/Form.php index 06aff05..d5ae24f 100644 --- a/includes/Form.php +++ b/includes/Form.php @@ -1216,7 +1216,11 @@ class Form { 'placeholder' => esc_html__( '-- Choose related field', 'formipay' ) ] ], - 'nonce' => wp_create_nonce('formipay-form-editor') + 'nonce' => wp_create_nonce('formipay-form-editor'), + 'multicurrency' => formipay_is_multi_currency_active(), + 'all_currencies' => formipay_currency_as_options(), + 'global_selected_currencies' => formipay_global_currency_options(), + 'default_currency' => formipay_default_currency() ] ); wp_enqueue_media(); diff --git a/includes/Integration/ExchangeRateAPI.php b/includes/Integration/ExchangeRateAPI.php new file mode 100644 index 0000000..9bcd4b7 --- /dev/null +++ b/includes/Integration/ExchangeRateAPI.php @@ -0,0 +1,10 @@ + __( 'General', 'formipay' ), 'group' => 'started' ), + 'allowed_currencies' => array( + 'type' => 'multi_checkbox', + 'searchable' => true, + 'required' => true, + 'label' => __( 'Allowed Currencies', 'formipay' ), + 'options' => formipay_global_currency_options(), + 'submenu' => __( 'General', 'formipay' ), + 'description' => __( 'Activate multicurrency and set more than one currency to enable this option. Default, only default currency is allowed.', 'formipay' ) + ), + 'default_currencies' => array( + 'type' => 'select', + 'searchable' => true, + 'required' => true, + 'label' => __( 'Default Currency', 'formipay' ), + 'options' => formipay_global_currency_options(), + 'submenu' => __( 'General', 'formipay' ), + 'description' => __( 'First apply currency before buyer select.', 'formipay' ) + ), 'payment_section_title' => array( 'type' => 'text', 'label' => __( 'Payment Section Title', 'formipay' ), @@ -102,10 +120,10 @@ abstract class Payment { ); $channels['payment_tablet_columns'] = array( - 'type' => 'number', - 'label' => __( 'Tablet View', 'formipay' ), - 'submenu' => __( 'General', 'formipay' ), - 'value' => 3 + 'type' => 'number', + 'label' => __( 'Tablet View', 'formipay' ), + 'submenu' => __( 'General', 'formipay' ), + 'value' => 3 ); $channels['payment_mobile_columns'] = array( diff --git a/includes/Settings.php b/includes/Settings.php index 85951e6..6eb7506 100644 --- a/includes/Settings.php +++ b/includes/Settings.php @@ -57,6 +57,30 @@ class Settings { 'type' => 'checkbox', 'label' => __( 'Enable Multi Currency', 'formipay' ) ], + 'enable_auto_exchangerate' => [ + 'type' => 'checkbox', + 'label' => __( 'Enable Auto Exchange Rate', 'formipay' ), + 'dependency' => [ + 'key' => 'enable_multicurrency', + 'value' => 'not_empty' + ] + ], + 'enable_auto_exchangerate_apikey' => [ + 'type' => 'text', + 'label' => __( 'Auto Exchange Rate API Key', 'formipay' ), + 'required' => true, + 'dependency' => [ + [ + 'key' => 'enable_multicurrency', + 'value' => 'not_empty' + ], + [ + 'key' => 'enable_auto_exchangerate', + 'value' => 'not_empty' + ] + ], + 'dependencies' => '&&' + ], 'multicurrencies' => [ 'type' => 'repeater', 'label' => __( 'Currencies', 'formipay' ), @@ -94,13 +118,12 @@ class Settings { 'options' => $payment_checkboxes, 'submenu' => __( 'General', 'formipay' ), ), - 'payment_gateways_select' => array( - 'type' => 'multiselect', - 'label' => __( 'Payment Gateways', 'formipay' ), - 'options' => $payment_checkboxes, + 'exchange_rate' => array( + 'type' => 'number', + 'label' => __( 'Manual Exchange Rate', 'formipay' ), + 'description' => __( 'This value is the exchange rate of default currency against this currency. If this currency selected, total order will be multiplied to this value. This override the value from ExchangeRatePI if enabled', 'formipay' ), 'submenu' => __( 'General', 'formipay' ), - 'placeholder' => 'Select related Payments' - ), + ) ], 'required' => true, 'dependency' => [ diff --git a/readme.txt b/readme.txt index 86a3ed3..7207113 100644 --- a/readme.txt +++ b/readme.txt @@ -76,4 +76,41 @@ Developed by Dwindi Ramadhana. == Privacy == -Formipay collects and processes user data in accordance with GDPR. Please review and customize the included privacy policy template for your site. \ No newline at end of file +Formipay collects and processes user data in accordance with GDPR. Please review and customize the included privacy policy template for your site. + +== Mermaid Multi-Currency Implementation == + +flowchart TD + GS[Global Settings] + GS -->|Toggle: Multi‑Currency ON/OFF| MODE{Mode} + + %% SINGLE-CURRENCY MODE + MODE -->|OFF| SC[Single‑Currency Mode] + SC -->|GS Default Currency only| FS1[Form Settings] + SC -->|GS Default Currency only| PS1[Product Settings] + FS1 --> CO1[Checkout] + PS1 --> CO1 + CO1 --> ORD1[Order Stored :: currency = GS default] + ORD1 --> RPT1[Reports for single currency] + + %% MULTI-CURRENCY MODE + MODE -->|ON| MC[Multi‑Currency Mode] + GS -->|Enabled Currencies + Rates| FS[Form Settings] + GS -->|Enabled Currencies + Rates| PS[Product Settings xN] + + FS -->|FS.allowed ⊆ GS.enabled\nFS.default ∈ FS.allowed| CK[Checkout] + PS -->|Per Product:\nBase currency default GS\nManual overrides optional\nDerive from base via GS toggle| CK + + CK -->|Compute CheckoutAllowed =\nFS.allowed ∩ as ProductSupported p| ALLOWED{CheckoutAllowed empty?} + ALLOWED -->|Yes| BLOCK[Block checkout + Admin diagnostic:\nEnable derive / add manual prices /\nadjust FS.allowed / remove product] + ALLOWED -->|No| CUR[Buyer selects currency ∈ CheckoutAllowed] + + CUR --> PAY[Filter payment gateways by selected currency] + PAY --> TOT[Compute totals:\nManual price → else derive via GS] + TOT --> ORD[Persist Order:\norder_currency, total_in_order_currency,\nfx_rate_used, report_total_in_GS_base] + ORD --> RPT[Reports:\nSum in GS base with per‑currency breakdown option] + + %% CATALOG (when MC=ON) + MC --> CAT[Catalog] + CAT -->|Query: currency=USD,IDR,AUTO| RESOLVE[Resolve display currency AUTO→pref/GS default] + RESOLVE --> FILT[Filter products strictly:\nshow only products supporting the display currency\n derive ok if product toggle is ON] \ No newline at end of file diff --git a/vendor/wpcfto/metaboxes/assets/js/metaboxes.js b/vendor/wpcfto/metaboxes/assets/js/metaboxes.js index 57d565e..f24d1a5 100644 --- a/vendor/wpcfto/metaboxes/assets/js/metaboxes.js +++ b/vendor/wpcfto/metaboxes/assets/js/metaboxes.js @@ -126,9 +126,18 @@ if ($boxChild.hasClass('repeater')) { // Repeater parent label (the field label for the repeater itself) const parentLabel = ($boxChild.find('.wpcfto-field-aside__label span:first-child').first().text() || '').trim(); - - // checker for the parent itself - if($boxChild.find('.wpcfto-repeater-single').length == 0){ + + // Determine if this repeater is required. + // We prefer presence of the hidden proxy input (rendered only when required). + // Fallback: a data attribute marker if used by templates. + const isRequiredRepeater = ( + $boxChild.find('.wpcfto-required-proxy').length > 0 || + $boxChild.is('[data-required="true"]') + ); + + // Parent-level empty check: only flag when the repeater itself is required + const hasRows = $boxChild.find('.wpcfto-repeater-single').length > 0; + if (isRequiredRepeater && !hasRows) { invalid.push({ id: fieldId, tab: tabTitle, @@ -137,6 +146,7 @@ }); } + // Child-level checks: scan only inputs that explicitly declare [required] $boxChild.find('.wpcfto-repeater-single').each(function (idx) { const $item = $(this); @@ -156,6 +166,7 @@ } if (!repeaterLabel) repeaterLabel = `Item #${idx+1}`; + // Only required child fields should be considered invalid when empty $item.find('input, textarea, select').filter('[required]').each(function () { const $f = $(this); if (isRequiredEmpty($f)) { diff --git a/vendor/wpcfto/metaboxes/assets/js/validationMixin.js b/vendor/wpcfto/metaboxes/assets/js/validationMixin.js index bd5985d..1b53485 100644 --- a/vendor/wpcfto/metaboxes/assets/js/validationMixin.js +++ b/vendor/wpcfto/metaboxes/assets/js/validationMixin.js @@ -1,4 +1,3 @@ - window.validationMixin = { methods: { // --- Helpers @@ -24,6 +23,12 @@ window.validationMixin = { if (Array.isArray(a) || Array.isArray(b)) return JSON.stringify(a) === JSON.stringify(b); return String(a) == String(b); }, + _coalesceValue() { + // Prefer prop field_value if present; otherwise fall back to instance `value` + if (typeof this.field_value !== 'undefined') return this.field_value; + if (typeof this.value !== 'undefined') return this.value; + return undefined; + }, // --- Visibility according to dependencies isVisible() { @@ -56,7 +61,7 @@ window.validationMixin = { const visible = this.isVisible(); const required = 'required' in this.fields && this.fields.required === true; const type = this.fields.type || ''; - const value = this.field_value; + const value = this._coalesceValue(); let filled; if (!required) { @@ -66,8 +71,18 @@ window.validationMixin = { filled = true; } else if (type === 'checkbox') { filled = value === 1 || value === true || value === '1' || value === 'true'; - } else if (type === 'repeater' && required) { - filled = this.fields.value && this.fields.value.length > 0; + } else if (type === 'repeater') { + if (!required) { + filled = true; // optional repeater: always valid + } else { + // Prefer the component's live repeater array; fallback to value/field_value + const list = Array.isArray(this.repeater) + ? this.repeater + : (Array.isArray(value) + ? value + : (this.fields && Array.isArray(this.fields.value) ? this.fields.value : [])); + filled = list.length > 0; + } } else if (Array.isArray(value)) { filled = value.length > 0; } else if (typeof value === 'number') { @@ -95,6 +110,11 @@ window.validationMixin = { if (typeof this.validateField === 'function') { this.validateField(); } + }, + value() { + if (typeof this.validateField === 'function') { + this.validateField(); + } } }, diff --git a/vendor/wpcfto/metaboxes/fields/autocomplete.php b/vendor/wpcfto/metaboxes/fields/autocomplete.php index 7366cde..0f3eb45 100644 --- a/vendor/wpcfto/metaboxes/fields/autocomplete.php +++ b/vendor/wpcfto/metaboxes/fields/autocomplete.php @@ -21,5 +21,5 @@ $field = "data['{$section_name}']['fields']['{$field_name}']"; :field_id="''" :field_value="" :field_data='' - @wpcfto-get-value=" = $event"> + @wpcfto-get-value="$set(, 'value', $event)"> diff --git a/vendor/wpcfto/metaboxes/fields/repeater.php b/vendor/wpcfto/metaboxes/fields/repeater.php index c895ef1..b970a94 100644 --- a/vendor/wpcfto/metaboxes/fields/repeater.php +++ b/vendor/wpcfto/metaboxes/fields/repeater.php @@ -23,5 +23,5 @@ wp_enqueue_script('my-super-component', STM_WPCFTO_URL . '/metaboxes/general_com v-bind:field_id="''" v-bind:field_value="" v-bind:field_data='' - @wpcfto-get-value="$set(, 'value', $event)" + @wpcfto-get-value="$set(, 'value', $event)" > \ No newline at end of file diff --git a/vendor/wpcfto/metaboxes/general_components/js/autocomplete.js b/vendor/wpcfto/metaboxes/general_components/js/autocomplete.js index e0a6dce..bc9e4fb 100644 --- a/vendor/wpcfto/metaboxes/general_components/js/autocomplete.js +++ b/vendor/wpcfto/metaboxes/general_components/js/autocomplete.js @@ -59,9 +59,10 @@ @@ -70,6 +71,11 @@ `, computed: { + serializedValue() { + const v = this.value; + if (Array.isArray(v)) return v.join(','); + return v || ''; + }, computedPlaceholder() { // Default placeholder template or fallback const template = formipay_admin?.config?.autocomplete?.placeholder || 'Search {field_label}...'; @@ -92,6 +98,9 @@ } else { this.limit = 5; // default limit } + if (!this.field_value) { + this.value = []; + } }, mounted() { this.$nextTick(() => { diff --git a/vendor/wpcfto/metaboxes/general_components/js/repeater.js b/vendor/wpcfto/metaboxes/general_components/js/repeater.js index 07a6468..e8c44f8 100644 --- a/vendor/wpcfto/metaboxes/general_components/js/repeater.js +++ b/vendor/wpcfto/metaboxes/general_components/js/repeater.js @@ -34,15 +34,22 @@ Vue.component('wpcfto_repeater', {