Skip to content

Commit bfb8015

Browse files
committed
feat: Enhance conditional logic handling with improved JSON decoding and logging
1 parent 0c492f2 commit bfb8015

3 files changed

Lines changed: 73 additions & 46 deletions

File tree

plugin/assets/admin/js/fields.js

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -521,21 +521,34 @@
521521
*/
522522
evaluateAllConditions() {
523523
const fieldsWithConditions = document.querySelectorAll('[data-conditional-logic]');
524-
525-
fieldsWithConditions.forEach(field => {
526-
const conditionsJson = field.dataset.conditionalLogic;
527-
if (!conditionsJson) return;
528-
529-
try {
530-
const conditions = JSON.parse(conditionsJson);
531-
532-
// Determine scope: if this field is in a repeater row, scope to that row
524+
525+
console.debug(`[OpenFields] Found ${fieldsWithConditions.length} fields with conditional logic`);
526+
527+
fieldsWithConditions.forEach(field => {
528+
const conditionsJson = field.dataset.conditionalLogic;
529+
if (!conditionsJson) return;
530+
531+
const fieldId = field.getAttribute('data-field-id');
532+
console.debug(`[OpenFields] Evaluating conditions for field ${fieldId}. Raw JSON: ${conditionsJson}`);
533+
534+
try {
535+
// Decode HTML entities if present (from PHP esc_attr)
536+
let decodedJson = conditionsJson;
537+
if (decodedJson.includes('"')) {
538+
const textarea = document.createElement('textarea');
539+
textarea.innerHTML = decodedJson;
540+
decodedJson = textarea.value;
541+
console.debug(`[OpenFields] Decoded JSON for field ${fieldId}: ${decodedJson}`);
542+
}
543+
544+
const conditions = JSON.parse(decodedJson); // Determine scope: if this field is in a repeater row, scope to that row
533545
// Otherwise, null scope means global field lookup
534546
let scopeElement = null;
535547
const repeaterRow = field.closest('.openfields-repeater-row');
536548
if (repeaterRow) {
537549
// Field is inside a repeater row - scope to this row
538550
scopeElement = repeaterRow;
551+
console.debug(`[OpenFields] Field ${fieldId} is in repeater row, scoping to row`);
539552
}
540553

541554
const shouldShow = this.evaluateCondition(conditions, scopeElement);
@@ -612,19 +625,22 @@
612625

613626
// rule.field is now a FIELD ID (immutable UUID/identifier)
614627
const fieldId = rule.field;
615-
let fieldElement = null;
628+
let fieldElement = null;
616629

617-
// If we have a scope element (e.g., repeater row), search within it first
618-
if (scopeElement) {
619-
fieldElement = scopeElement.querySelector(`[data-field-id="${fieldId}"]`);
620-
}
630+
// If we have a scope element (e.g., repeater row), search within it first
631+
if (scopeElement) {
632+
fieldElement = scopeElement.querySelector(`[data-field-id="${fieldId}"]`);
633+
634+
// Debug logging for repeater fields
635+
if (!fieldElement) {
636+
console.debug(`[OpenFields] Field ${fieldId} not found in scope (repeater row), searching globally`);
637+
}
638+
}
621639

622640
// If not found in scope, search globally (for root fields)
623641
if (!fieldElement) {
624642
fieldElement = document.querySelector(`[data-field-id="${fieldId}"]`);
625-
}
626-
627-
if (fieldElement) {
643+
} if (fieldElement) {
628644
// Found by field ID - this is the preferred method
629645
// Look for the actual input element within this wrapper
630646
// For repeater subfields, the wrapper is .openfields-repeater-subfield
@@ -669,17 +685,22 @@
669685
if (!fieldElement) {
670686
fieldElement = document.querySelector(selector);
671687
}
672-
} if (!fieldElement) {
673-
console.warn(`[OpenFields] Conditional field not found: ${fieldId}`);
674-
return true; // If field not found, don't block (assume condition passes).
675-
}
676-
677-
const currentValue = this.getFieldValue(fieldElement);
678-
return this.compareValues(currentValue, rule.operator, rule.value);
679-
});
680-
},
688+
}
689+
690+
if (!fieldElement) {
691+
console.warn(`[OpenFields] Conditional field not found: ${fieldId}`);
692+
return true; // If field not found, don't block (assume condition passes).
693+
}
681694

682-
/**
695+
const currentValue = this.getFieldValue(fieldElement);
696+
const result = this.compareValues(currentValue, rule.operator, rule.value);
697+
698+
// Debug logging for conditional logic
699+
console.debug(`[OpenFields] Condition check: field=${fieldId}, value="${currentValue}", operator=${rule.operator}, expected="${rule.value}", result=${result}`);
700+
701+
return result;
702+
});
703+
}, /**
683704
* Get the current value of a field element.
684705
*
685706
* @param {HTMLElement} element - The field element.

plugin/assets/admin/js/repeater.js

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -325,24 +325,27 @@
325325
// Add to container
326326
rowsContainer.appendChild(newRow);
327327

328-
// Initialize nested repeaters in the new row
329-
this.initAllRepeaters(newRow);
330-
331-
// Reindex and update
332-
this.reindexRows(repeater);
333-
this.updateState(repeater);
334-
335-
// Focus first input
336-
const firstInput = newRow.querySelector('input:not([type="hidden"]), textarea, select');
337-
if (firstInput) {
338-
firstInput.focus();
339-
}
340-
341-
// Scroll into view
342-
newRow.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
343-
},
344-
345-
/**
328+
// Initialize nested repeaters in the new row
329+
this.initAllRepeaters(newRow);
330+
331+
// Reindex and update
332+
this.reindexRows(repeater);
333+
this.updateState(repeater);
334+
335+
// Trigger conditional logic evaluation for the new row
336+
if (window.OpenFieldsManager && window.OpenFieldsManager.evaluateAllConditions) {
337+
window.OpenFieldsManager.evaluateAllConditions();
338+
}
339+
340+
// Focus first input
341+
const firstInput = newRow.querySelector('input:not([type="hidden"]), textarea, select');
342+
if (firstInput) {
343+
firstInput.focus();
344+
}
345+
346+
// Scroll into view
347+
newRow.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
348+
}, /**
346349
* Remove a row
347350
* @param {HTMLElement} repeater
348351
* @param {HTMLElement} row

plugin/includes/admin/field-renderers/repeater.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,10 @@ function openfields_render_repeater_subfield( $sub_field, $index, $base_name, $o
275275
// Add conditional logic attribute if present
276276
$conditional_attr = '';
277277
if ( ! empty( $sub_field->conditional_logic ) ) {
278-
$conditional_attr = ' data-conditional-logic="' . esc_attr( wp_json_encode( $sub_field->conditional_logic ) ) . '"';
278+
// Decode JSON string from database, then re-encode for safe HTML attribute
279+
$decoded_conditions = json_decode( $sub_field->conditional_logic, true );
280+
$conditions = is_array( $decoded_conditions ) ? $decoded_conditions : array();
281+
$conditional_attr = ' data-conditional-logic="' . esc_attr( wp_json_encode( $conditions ) ) . '"';
279282
$conditional_attr .= ' data-conditional-status="hidden"'; // Initially hidden, shown by JS if conditions met
280283
}
281284

0 commit comments

Comments
 (0)