Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions gp-entry-blocks/gpeb-filter-by-nested-field.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
/**
* Gravity Perks // Entry Blocks // Filter values by Nested Entry.
* https://gravitywiz.com/documentation/gravity-forms-entry-blocks/
*
* Instruction Video: https://www.loom.com/share/f795e8b5ef58489794dca96e83fcd230
*
*/
class GPEB_Filter_By_Nested_Entry {

private $parent_form_id;
private $nested_form_id;
private $parent_hidden_field_id;
private $nested_target_field_id;

public function __construct( $config = array() ) {
$this->parent_form_id = rgar( $config, 'parent_form_id' );
$this->nested_form_id = rgar( $config, 'nested_form_id' );
$this->parent_hidden_field_id = rgar( $config, 'parent_hidden_field_id' );
$this->nested_target_field_id = rgar( $config, 'nested_target_field_id' );

add_action( 'init', array( $this, 'init' ) );
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add input validation for required configuration parameters.

The constructor accepts configuration parameters but doesn't validate that required parameters are provided, which could lead to runtime errors when the class methods are called.

Consider adding validation in the constructor:

 public function __construct( $config = array() ) {
+	// Validate required configuration parameters
+	$required_params = array( 'parent_form_id', 'nested_form_id', 'parent_hidden_field_id', 'nested_target_field_id' );
+	foreach ( $required_params as $param ) {
+		if ( empty( $config[ $param ] ) ) {
+			throw new InvalidArgumentException( "Required parameter '$param' is missing or empty." );
+		}
+	}
+
 	$this->parent_form_id         = rgar( $config, 'parent_form_id' );
 	$this->nested_form_id         = rgar( $config, 'nested_form_id' );
 	$this->parent_hidden_field_id = rgar( $config, 'parent_hidden_field_id' );
 	$this->nested_target_field_id = rgar( $config, 'nested_target_field_id' );

 	add_action( 'init', array( $this, 'init' ) );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function __construct( $config = array() ) {
$this->parent_form_id = rgar( $config, 'parent_form_id' );
$this->nested_form_id = rgar( $config, 'nested_form_id' );
$this->parent_hidden_field_id = rgar( $config, 'parent_hidden_field_id' );
$this->nested_target_field_id = rgar( $config, 'nested_target_field_id' );
add_action( 'init', array( $this, 'init' ) );
}
public function __construct( $config = array() ) {
// Validate required configuration parameters
$required_params = array( 'parent_form_id', 'nested_form_id', 'parent_hidden_field_id', 'nested_target_field_id' );
foreach ( $required_params as $param ) {
if ( empty( $config[ $param ] ) ) {
throw new InvalidArgumentException( "Required parameter '$param' is missing or empty." );
}
}
$this->parent_form_id = rgar( $config, 'parent_form_id' );
$this->nested_form_id = rgar( $config, 'nested_form_id' );
$this->parent_hidden_field_id = rgar( $config, 'parent_hidden_field_id' );
$this->nested_target_field_id = rgar( $config, 'nested_target_field_id' );
add_action( 'init', array( $this, 'init' ) );
}
🤖 Prompt for AI Agents
In gp-entry-blocks/gpeb-filter-by-nested-field.php around lines 16 to 23, the
constructor assigns configuration parameters without validating their presence,
which may cause runtime errors later. Add input validation in the constructor to
check that all required parameters like parent_form_id, nested_form_id,
parent_hidden_field_id, and nested_target_field_id are provided and not empty.
If any required parameter is missing, throw an exception or trigger an error to
prevent improper instantiation.


public function init() {
add_filter( 'gpeb_filter_form', array( $this, 'modify_filter_form' ) );
add_filter( 'gpeb_queryer_entries', array( $this, 'filter_entries_by_nested_value' ), 10, 2 );
}

private function is_applicable_form( $form_id = null ) {
if ( $form_id === null ) {
$form_id = rgget( 'filters_form_id' );
}
return $form_id == $this->parent_form_id;
}

public function modify_filter_form( $form ) {
if ( ! $this->is_applicable_form( $form['id'] ) ) {
return $form;
}

foreach ( $form['fields'] as &$field ) {
if ( $field->id == $this->parent_hidden_field_id ) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@saifsultanc do you think this could work without the need for a hidden field by simply adding a copy of the nested form field here to the parent $form['fields'] array?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My reservations for that were:

  1. Field conflict - managing conflicting field ID if a parent form's field had the same ID as our targeted nested form field.
  2. Field settings - The nested field copied may have display or conditional logic incompatible with the parent form.

Keeping a separate "placeholder" like hidden field seemed a little safer and cleaner to me. What you say?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@saifsultanc Good points! Let's go hidden field 🤝

$nested_form_field = GFAPI::get_field( $this->nested_form_id, $this->nested_target_field_id );
$field = $nested_form_field;
$field->id = $this->parent_hidden_field_id;
}
}

return $form;
}

public function filter_entries_by_nested_value( $entries, $gf_queryer ) {
if ( ! $this->is_applicable_form() ) {
return $entries;
}

$filters = rgget( 'filters' );
if ( ! isset( $filters[ $this->parent_hidden_field_id ] ) ) {
return $entries;
}

$nested_entries = GFAPI::get_entries( $this->nested_form_id, array(
'field_filters' => array(
array(
'key' => $this->nested_target_field_id,
'value' => $filters[ $this->parent_hidden_field_id ],
),
),
) );

$entries = array();
$parent_entry_ids = array();

foreach ( $nested_entries as $nested_entry ) {
$parent_entry_id = rgar( $nested_entry, 'gpnf_entry_parent' );
$entry = GFAPI::get_entry( $parent_entry_id );
if ( ! in_array( $parent_entry_id, $parent_entry_ids ) && $entry && ! is_wp_error( $entry ) ) {
$parent_entry_ids[] = $parent_entry_id;
$entries[] = $entry;
}
}

return $entries;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Optimize performance and add error handling for entry queries.

The current implementation has several performance and reliability issues:

  1. Multiple individual GFAPI::get_entry() calls in a loop
  2. No error handling for GFAPI calls
  3. Complete replacement of entries array rather than filtering existing entries

Consider this optimized approach:

-$entries = array();
-$parent_entry_ids = array();
-
-foreach ( $nested_entries as $nested_entry ) {
-	$parent_entry_id = rgar( $nested_entry, 'gpnf_entry_parent' );
-	$entry = GFAPI::get_entry( $parent_entry_id );
-	if ( ! in_array( $parent_entry_id, $parent_entry_ids ) && $entry && ! is_wp_error( $entry ) ) {
-		$parent_entry_ids[] = $parent_entry_id;
-		$entries[] = $entry;
-	}
-}
+// Collect unique parent entry IDs
+$parent_entry_ids = array();
+foreach ( $nested_entries as $nested_entry ) {
+	$parent_entry_id = rgar( $nested_entry, 'gpnf_entry_parent' );
+	if ( $parent_entry_id && ! in_array( $parent_entry_id, $parent_entry_ids ) ) {
+		$parent_entry_ids[] = $parent_entry_id;
+	}
+}
+
+// Filter existing entries to only include those with matching parent IDs
+if ( ! empty( $parent_entry_ids ) ) {
+	$entries = array_filter( $entries, function( $entry ) use ( $parent_entry_ids ) {
+		return in_array( $entry['id'], $parent_entry_ids );
+	});
+} else {
+	$entries = array(); // No matching nested entries found
+}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In gp-entry-blocks/gpeb-filter-by-nested-field.php around lines 63 to 85, the
code inefficiently calls GFAPI::get_entry() inside a loop without error handling
and replaces the entries array instead of filtering it. To fix this, refactor to
batch query parent entries in one call if possible, add checks for errors after
each GFAPI call, and modify the logic to filter the existing entries array
rather than replacing it entirely. This will improve performance and
reliability.

}

new GPEB_Filter_By_Nested_Entry( array(
'parent_form_id' => 4,
'nested_form_id' => 3,
'parent_hidden_field_id' => 10,
'nested_target_field_id' => 4,
) );
Loading