From eaf9ee4151dc3bcc6ec7a6a8d2d4c4bdc337b6b6 Mon Sep 17 00:00:00 2001 From: Rey C Date: Tue, 12 Aug 2025 00:10:09 +0800 Subject: [PATCH 1/2] Fix: dding Repeaters as subfields of a Repeater should be allowed. Resolves https://github.com/WPUserManager/wpum-custom-fields/issues/80 @polevaultweb --- assets/js/src/wp-user-manager.js | 164 +++++++++++------- .../settings/field-type-repeater.vue | 8 - templates/forms/form-registration-fields.php | 13 ++ 3 files changed, 116 insertions(+), 69 deletions(-) diff --git a/assets/js/src/wp-user-manager.js b/assets/js/src/wp-user-manager.js index 49667539..e2fc328d 100644 --- a/assets/js/src/wp-user-manager.js +++ b/assets/js/src/wp-user-manager.js @@ -30,14 +30,18 @@ jQuery( function( $ ) { init: function() { var self = this; - $( '.add-repeater-row' ).each( function() { - var parent = $( this ).parents( 'fieldset' ); - var repeater = parent.find( '.fieldset-wpum_field_group' ).not('.fieldset-wpum_field_group-clone' ); - - if ( repeater.length ) { - var name = parent.get( 0 ).classList[ 0 ]; - self.increaseInstance( name ); - self.validateMaxRows( name ); + // Setup instances to first level repeaters + $('form > fieldset > .add-repeater-row').each(function () { + var fieldSet = $(this).closest( 'fieldset' ); + var fieldGroup = $(fieldSet).find( ' > .fieldset-wpum_field_group' ).not('.fieldset-wpum_field_group-clone' ); + + if ( fieldGroup.length ) { + self.setupInstances(fieldSet, null); + + var repeaterKey = self.getRepeaterKey(fieldSet); + + self.increaseInstance( repeaterKey ); + self.validateMaxRows( fieldSet ); } } ); @@ -51,17 +55,21 @@ jQuery( function( $ ) { } ); self.form.on( 'click', '.add-repeater-row', function() { - var parent = $( this ).parents( 'fieldset' ); - self.addNewInstance( parent.get( 0 ).classList[ 0 ] ); + var fieldSet = $(this).parent('fieldset'); + // Setup new instance based on the parent fieldset + self.addNewInstance( fieldSet ); self.form.wpumConditionalFields({}); } ); self.form.on( 'click', '.remove-repeater-row', function(e) { e.preventDefault(); - var parent = $( this ).parents( 'fieldset' ); - var $row = $( this ).parents( '.fieldset-wpum_field_group' ); + var fieldSet = $(this).closest('fieldset'); + var parentBase = $(fieldSet).attr('data-parent-base'); + var $row = $( this ).parent( '.fieldset-wpum_field_group' ); $row.remove(); - self.setupInstances( parent.get( 0 ).classList[ 0 ] ); + + self.setupInstances( fieldSet, parentBase ); + self.validateMaxRows( fieldSet ); } ); }, @@ -73,9 +81,12 @@ jQuery( function( $ ) { this.repeaters[ name ]++; }, - addNewInstance: function( name ) { - this.addNewRepeaterRow( name ); - this.setupInstances( name ); + addNewInstance: function( fieldSet ) { + this.addNewRepeaterRow(fieldSet); + + var parentBase = $(fieldSet).attr('data-parent-base'); + this.setupInstances(fieldSet, parentBase); + initFields(); }, @@ -83,13 +94,14 @@ jQuery( function( $ ) { this.repeaters[ name ] = 0; }, - addNewRepeaterRow: function( name ) { - var repeater = $( '.' + name ).find( '.fieldset-wpum_field_group-clone' ).last(); + addNewRepeaterRow: function (fieldSet) { + // Get repeater from the immediate child + var repeater = $(fieldSet).find(' > .fieldset-wpum_field_group-clone').last(); if ( !repeater.length ) { return; } - if ( !this.validateMaxRows( name ) ) { + if ( !this.validateMaxRows( fieldSet ) ) { return; } @@ -99,58 +111,88 @@ jQuery( function( $ ) { newRepeater.insertBefore( repeater ); }, - setupInstances: function( name ) { - var repeaterRow = $( '.' + name ).find( '.fieldset-wpum_field_group' ).not( '.fieldset-wpum_field_group-clone' ); + getRepeaterKey: function(fieldSet) { + var parentBase = $(fieldSet).attr('data-parent-base'); + var repeaterKey = $(fieldSet).get(0).classList[0]; + repeaterKey = repeaterKey.replace('fieldset-', ''); + + if (parentBase) { + repeaterKey = parentBase + '[' + repeaterKey + ']'; + } + + return repeaterKey; + }, + + setupInstances: function (fieldSet, parentBase) { + if (typeof parentBase === 'undefined' || parentBase === null) { + parentBase = null; + } + + var repeaterRow = $( fieldSet ).find( ' > .fieldset-wpum_field_group' ).not( '.fieldset-wpum_field_group-clone' ); var self = this; if ( !repeaterRow.length ) { return; } - self.resetInstance( name ); - - repeaterRow.each( function( i ) { - $( this ).find('fieldset').attr('data-index', i); - $( this ).find( ':input' ).each( function() { - var name = ''; - if ( $( this ).attr( 'data-name' ) ) { - name = $( this ).attr( 'data-name' ); - } else { - name = $( this ).prop( 'name' ); - } - - $( this ).attr( - 'name', - name.replace( - new RegExp( /\[(.*?)\]/ ), - function() { - return '[' + i + ']'; - } - ) - ); - - if ( i > 0 ) { - var clone_id = ''; - if ( $( this ).attr( 'data-clone' ) ) { - clone_id = $( this ).attr( 'data-clone' ); - } else { - clone_id = $(this).prop( 'id' ); + // Apply parentBase to the fieldset to make it available later + if (parentBase) { + $(fieldSet).attr('data-parent-base', parentBase); + } + + var repeaterKey = self.getRepeaterKey(fieldSet); + self.resetInstance(repeaterKey); + + repeaterRow.each(function (i) { + $(fieldSet).attr('data-index', i); + $(this) + .find('> fieldset > .field :input') + // Exclude sub repeater fields + .not($(this).find('> fieldset > .fieldset-wpum_field_group :input')) + .each(function() { + var fieldName = $(this).attr('data-name') || $(this).prop('name'); + fieldName = fieldName.replace(/\[(.*?)\]/, '[' + i + ']'); + + // Prepend parentBase if available and does not already have a parentBase + if (parentBase && !fieldName.includes(parentBase)) { + // Wrap the base key (before the first "[") in brackets + fieldName = fieldName.replace(/^([^[]+)/, '[$1]'); + fieldName = parentBase + fieldName; } - var id = clone_id + '_' + i; - $( this ).attr( 'id', id ); - $( this ).closest( 'fieldset' ).find( 'label' ).attr( 'for', id ); - } - } ); - self.increaseInstance( name ); - } ); + $(this).attr( + 'name', + fieldName + ); + + if (i > 0) { + var clone_id = $(this).attr('data-clone') || $(this).prop('id'); + var id = clone_id + '_' + i; + $(this).attr('id', id); + $(this).closest('fieldset').find('label').attr('for', id); + } + }); + + self.increaseInstance(repeaterKey); + + // Recurse into subrepeaters + $(this) + .find('> fieldset > .add-repeater-row') + .each(function () { + var fieldSet = $(this).closest('fieldset'); + var currentParentBase = repeaterKey + '[' + i + ']'; + + self.setupInstances(fieldSet, currentParentBase); + self.validateMaxRows(fieldSet); + }); + }); }, + validateMaxRows: function( fieldSet ) { + var repeater = $(fieldSet).find( ' > .fieldset-wpum_field_group' ).not( '.fieldset-wpum_field_group-clone' ); + var addBtn = $(fieldSet).find( ' > .add-repeater-row' ); + var maxRows = addBtn.data('max-row'); + const repeaterKey = this.getRepeaterKey(fieldSet); - validateMaxRows: function( name ) { - var parent = $( '.' + name ); - var repeater = parent.find( '.fieldset-wpum_field_group' ).not( '.fieldset-wpum_field_group-clone' ); - var addBtn = parent.find( '.add-repeater-row' ); - var maxRows = addBtn.data( 'max-row' ); if ( !maxRows || parseInt( maxRows ) < 1 ) { return true; } diff --git a/src/fields-editor/settings/field-type-repeater.vue b/src/fields-editor/settings/field-type-repeater.vue index 5b0bfcee..da18bb9a 100644 --- a/src/fields-editor/settings/field-type-repeater.vue +++ b/src/fields-editor/settings/field-type-repeater.vue @@ -158,17 +158,9 @@ export default { this.labels.fields_create = this.labels.repeater_fields_create; }, created(){ - this.repeater = wpumFieldsEditor.fields_types.advanced.fields.find((field) => field.type === 'repeater') - if(this.repeater){ - wpumFieldsEditor.fields_types.advanced.fields = wpumFieldsEditor.fields_types.advanced.fields.filter((field) => field.type !== 'repeater') - } - this.getFields() }, destroyed(){ - if(this.repeater){ - wpumFieldsEditor.fields_types.advanced.fields.push(this.repeater) - } this.labels.fields_add_new = this.clonedLabels.fields_add_new; this.labels.fields_create = this.clonedLabels.fields_create; } diff --git a/templates/forms/form-registration-fields.php b/templates/forms/form-registration-fields.php index 66a656e4..c18af41f 100644 --- a/templates/forms/form-registration-fields.php +++ b/templates/forms/form-registration-fields.php @@ -20,6 +20,19 @@ $field = $data->field; $key = $data->key; + +// Parent field should handle the child field rendering +if ( in_array( $field['type'], wpum_get_registered_parent_field_types(), true ) ) { + + $field['key'] = $key; + $template = isset( $field['template'] ) ? $field['template'] : $field['type']; + + WPUM()->templates + ->set_template_data( $field ) + ->get_template_part( 'form-fields/' . $template, 'field' ); + return; +} + if ( ! empty( $field['default_value'] ) ) { $field['value'] = $field['default_value']; From b3b91dea80e8379e7e878afcd52ebff9f708c363 Mon Sep 17 00:00:00 2001 From: Rey C Date: Tue, 12 Aug 2025 00:16:34 +0800 Subject: [PATCH 2/2] Remove unnecessary code @polevaultweb --- assets/js/src/wp-user-manager.js | 1 - 1 file changed, 1 deletion(-) diff --git a/assets/js/src/wp-user-manager.js b/assets/js/src/wp-user-manager.js index e2fc328d..f7506ba6 100644 --- a/assets/js/src/wp-user-manager.js +++ b/assets/js/src/wp-user-manager.js @@ -191,7 +191,6 @@ jQuery( function( $ ) { var repeater = $(fieldSet).find( ' > .fieldset-wpum_field_group' ).not( '.fieldset-wpum_field_group-clone' ); var addBtn = $(fieldSet).find( ' > .add-repeater-row' ); var maxRows = addBtn.data('max-row'); - const repeaterKey = this.getRepeaterKey(fieldSet); if ( !maxRows || parseInt( maxRows ) < 1 ) { return true;