From ec4201e08b19a11f5f9703596dc3740457ec6b5d Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 27 May 2022 20:34:30 -0400 Subject: [PATCH 1/5] Added better support for handling pages with no fields after randomization. --- gravity-forms/gw-random-fields.php | 131 +++++++++++++++-------------- 1 file changed, 67 insertions(+), 64 deletions(-) diff --git a/gravity-forms/gw-random-fields.php b/gravity-forms/gw-random-fields.php index 4e4f7cd59..0890d105d 100644 --- a/gravity-forms/gw-random-fields.php +++ b/gravity-forms/gw-random-fields.php @@ -5,7 +5,7 @@ * * Randomly display a specified number of fields on your form. * - * @version 1.3 + * @version 1.3.x * @author David Smith * @license GPL-2.0+ * @link https://gravitywiz.com/random-fields-with-gravity-forms/ @@ -14,7 +14,7 @@ * Plugin URI: https://gravitywiz.com/random-fields-with-gravity-forms/ * Description: Randomly display a specified number of fields on your form. * Author: Gravity Wiz - * Version: 1.3 + * Version: 1.3.x * Author URI: http://gravitywiz.com */ class GFRandomFields { @@ -23,21 +23,21 @@ class GFRandomFields { public $display_count; public $selected_field_ids = array(); public $preserve_order; + public $restructure_pages; - public function __construct( $form_id, $display_count = 5, $random_field_ids = false, $preserve_order = false ) { + public function __construct( $form_id, $display_count = 5, $random_field_ids = false, $preserve_order = false, $restructure_pages = true ) { $this->_form_id = (int) $form_id; $this->all_random_field_ids = array_map( 'intval', array_filter( (array) $random_field_ids ) ); $this->display_count = (int) $display_count; $this->preserve_order = (bool) $preserve_order; + $this->restructure_pages = (bool) $restructure_pages; add_filter( "gform_pre_render_$form_id", array( $this, 'pre_render' ) ); + add_filter( "gform_pre_process_$form_id", array( $this, 'pre_render' ) ); + add_filter( "gform_form_tag_$form_id", array( $this, 'store_selected_field_ids' ), 10, 2 ); - add_filter( "gform_validation_$form_id", array( $this, 'validate' ) ); - add_filter( "gform_pre_submission_filter_$form_id", array( $this, 'pre_render' ) ); - add_filter( "gform_target_page_{$form_id}", array( $this, 'modify_target_page' ), 10, 3 ); - //add_filter( "gform_admin_pre_render_$form_id", array( $this, 'admin_pre_render' ) ); add_action( 'gform_entry_created', array( $this, 'save_selected_field_ids_meta' ), 10, 2 ); } @@ -46,15 +46,6 @@ public function pre_render( $form ) { return $this->filter_form_fields( $form, $this->get_selected_field_ids( false, $form ) ); } - public function admin_pre_render( $form ) { - - if ( (int) $form['id'] !== $this->_form_id ) { - return $form; - } - - return $form; - } - public function store_selected_field_ids( $form_tag, $form ) { $hash = $this->get_selected_field_ids_hash( $form ); $value = implode( ',', $this->get_selected_field_ids( false, $form ) ); @@ -78,12 +69,21 @@ public function validate( $validation_result ) { public function filter_form_fields( $form, $selected_fields ) { + // Prevent the form from being randomized multiple times. Once per runtime is enough. 😅 + if ( rgar( $form, 'gwrfRandomized' ) ) { + return $form; + } + $filtered_fields = array(); - $selected_fields = array_map( 'intval', $selected_fields ); $random_indexes = array(); + $selected_fields = array_map( 'intval', $selected_fields ); foreach ( $form['fields'] as $field ) { + if ( $field->type === 'page' ) { + continue; + } + if ( in_array( (int) $field['id'], $this->get_random_field_ids( $form['fields'] ), true ) ) { if ( in_array( (int) $field['id'], $selected_fields, true ) ) { $filtered_fields[] = $field; @@ -94,6 +94,10 @@ public function filter_form_fields( $form, $selected_fields ) { } } + if ( $this->restructure_pages ) { + $filtered_fields = $this->handle_pagination( $filtered_fields, $form ); + } + if ( ! $this->preserve_order ) { $reordered_fields = array(); @@ -114,11 +118,55 @@ public function filter_form_fields( $form, $selected_fields ) { } - $form['fields'] = $filtered_fields; + $form['gwrfRandomized'] = true; + $form['fields'] = $filtered_fields; return $form; } + public function handle_pagination( $filtered_fields, $form ) { + + $pages = array(); + foreach ( $form['fields'] as $field ) { + if ( $field->type === 'page' ) { + $pages[] = $field; + } + } + + // Get all the page numbers that exist now that the fields have been filtered. + $page_numbers = array_values( array_unique( wp_list_pluck( $filtered_fields, 'pageNumber' ) ) ); + + // Updates 0-based index to a 1-based index so the array key represents the new page number exactly (e.g. Page 1 vs Page 0). + array_unshift( $page_numbers, false ); + unset( $page_numbers[0] ); + + // Loop through the page numbers and assign fields to their new page number based on their old page number. + foreach ( $page_numbers as $new_page_number => $old_page_number ) { + + // $pages is still a 0-based indexed array; subtract 2 from the old page number to find the right page. + $page = rgar( $pages, $old_page_number - 2 ); + if ( ! $page ) { + continue; + } + + foreach ( $filtered_fields as $index => &$field ) { + if ( $field->pageNumber == $old_page_number && $field->type !== 'page' ) { + + $field->pageNumber = $new_page_number; + + // Update the page to its new page number and inject it into the filtered fields ahead. + $page->pageNumber = $new_page_number; + array_splice( $filtered_fields, $index, 0, array( $page ) ); + + } + } + } + + unset( $field ); + + return $filtered_fields; + } + public function get_random_field_ids( $fields ) { if ( ! empty( $this->all_random_field_ids ) ) { @@ -179,49 +227,4 @@ public function save_selected_field_ids_meta( $entry, $form ) { } } - /** - * When the form is submitted modify the target page to avoid navigating to a page that has no visible fields. - * - * Known limitation: If the first page of a form has no visible fields, this will not avoid that as this only works - * on submission. - * - * @param $page_number - * @param $form - * @param $current_page - * @param $field_values - * - * @return int|mixed - */ - public function modify_target_page( $page_number, $form, $current_page ) { - - $page_number = intval( $page_number ); - $form = $this->pre_render( $form ); - - $page_has_visible_fields = false; - foreach ( $form['fields'] as $field ) { - if ( (int) $field->pageNumber === (int) $page_number && GFFormDisplay::is_field_validation_supported( $field ) ) { - $page_has_visible_fields = true; - } - } - - if ( ! $page_has_visible_fields ) { - // Are we moving to the next or previous page? - $is_next = $page_number === 0 || $page_number > $current_page; - $max_page = GFFormDisplay::get_max_page_number( $form ); - if ( $page_number !== 0 && $page_number < $max_page ) { - $page_number += $is_next ? 1 : -1; - // When moving to a previous page, always stop at the first page. Otherwise, we'll submit the form. - if ( ! $is_next && $page_number === 0 ) { - return 1; - } - $page_number = $this->modify_target_page( $page_number, $form, $current_page ); - } elseif ( $page_number >= $max_page ) { - // Target page number 0 to submit the form. - $page_number = 0; - } - } - - return $page_number; - } - -} +} \ No newline at end of file From 1eb91632b497c9e911014ea96c99a49cab3003ee Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 27 May 2022 20:42:21 -0400 Subject: [PATCH 2/5] ~ PHPCS: File must end with a newline character --- gravity-forms/gw-random-fields.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gravity-forms/gw-random-fields.php b/gravity-forms/gw-random-fields.php index 0890d105d..49127fae4 100644 --- a/gravity-forms/gw-random-fields.php +++ b/gravity-forms/gw-random-fields.php @@ -227,4 +227,4 @@ public function save_selected_field_ids_meta( $entry, $form ) { } } -} \ No newline at end of file +} From e0d21e2411e24340817c41349f6d844d63e029ae Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 27 May 2022 21:19:42 -0400 Subject: [PATCH 3/5] Updated to remove Section fields if they are the only fields left after randomization. --- gravity-forms/gw-random-fields.php | 39 +++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/gravity-forms/gw-random-fields.php b/gravity-forms/gw-random-fields.php index 49127fae4..5fa616d02 100644 --- a/gravity-forms/gw-random-fields.php +++ b/gravity-forms/gw-random-fields.php @@ -80,7 +80,7 @@ public function filter_form_fields( $form, $selected_fields ) { foreach ( $form['fields'] as $field ) { - if ( $field->type === 'page' ) { + if ( $this->restructure_pages && $field->type === 'page' ) { continue; } @@ -133,6 +133,15 @@ public function handle_pagination( $filtered_fields, $form ) { } } + // Remove Section fields if they are the only fields left on a page after randomization. + foreach ( $filtered_fields as $index => $field ) { + if ( $field->type === 'section' && $this->is_only_field_on_page( $filtered_fields, $field ) ) { + unset( $filtered_fields[ $index ] ); + } + } + + $filtered_fields = array_filter( $filtered_fields ); + // Get all the page numbers that exist now that the fields have been filtered. $page_numbers = array_values( array_unique( wp_list_pluck( $filtered_fields, 'pageNumber' ) ) ); @@ -154,9 +163,13 @@ public function handle_pagination( $filtered_fields, $form ) { $field->pageNumber = $new_page_number; - // Update the page to its new page number and inject it into the filtered fields ahead. - $page->pageNumber = $new_page_number; - array_splice( $filtered_fields, $index, 0, array( $page ) ); + // Only inject the page once. + if ( isset( $page ) ) { + // Update the page to its new page number and inject it into the filtered fields ahead. + $page->pageNumber = $new_page_number; + array_splice( $filtered_fields, $index, 0, array( $page ) ); + unset( $page ); + } } } @@ -167,6 +180,15 @@ public function handle_pagination( $filtered_fields, $form ) { return $filtered_fields; } + public function get_page_by_page_number( $form, $page_number ) { + foreach ( $form['fields'] as $field ) { + if ( $field->type === 'page' && $field->pageNumber == $page_number ) { + return $field; + } + } + return false; + } + public function get_random_field_ids( $fields ) { if ( ! empty( $this->all_random_field_ids ) ) { @@ -227,4 +249,13 @@ public function save_selected_field_ids_meta( $entry, $form ) { } } + public function is_only_field_on_page( $fields, $source_field ) { + foreach ( $fields as $_field ) { + if ( $_field->id != $source_field->id && $_field->pageNumber == $source_field->pageNumber && $_field->type !== 'section' ) { + return false; + } + } + return true; + } + } From 0b4b1e6483628099b305f1c16123a700930b14b5 Mon Sep 17 00:00:00 2001 From: David Smith Date: Fri, 27 May 2022 21:23:10 -0400 Subject: [PATCH 4/5] ~ PHPCS: Blank line found after control structure --- gravity-forms/gw-random-fields.php | 1 - 1 file changed, 1 deletion(-) diff --git a/gravity-forms/gw-random-fields.php b/gravity-forms/gw-random-fields.php index 5fa616d02..3bd10cdd4 100644 --- a/gravity-forms/gw-random-fields.php +++ b/gravity-forms/gw-random-fields.php @@ -170,7 +170,6 @@ public function handle_pagination( $filtered_fields, $form ) { array_splice( $filtered_fields, $index, 0, array( $page ) ); unset( $page ); } - } } } From 14dd9f34388e23ba9d123bf0d818b50b82ac47a1 Mon Sep 17 00:00:00 2001 From: David Smith Date: Sat, 7 Oct 2023 15:11:27 -0400 Subject: [PATCH 5/5] Fixed issue where randomizing the field order could result in empty pages. --- gravity-forms/gw-random-fields.php | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/gravity-forms/gw-random-fields.php b/gravity-forms/gw-random-fields.php index 3bd10cdd4..9e814f557 100644 --- a/gravity-forms/gw-random-fields.php +++ b/gravity-forms/gw-random-fields.php @@ -18,13 +18,11 @@ * Author URI: http://gravitywiz.com */ class GFRandomFields { - public $all_random_field_ids; public $display_count; public $selected_field_ids = array(); public $preserve_order; public $restructure_pages; - public function __construct( $form_id, $display_count = 5, $random_field_ids = false, $preserve_order = false, $restructure_pages = true ) { $this->_form_id = (int) $form_id; @@ -94,11 +92,13 @@ public function filter_form_fields( $form, $selected_fields ) { } } - if ( $this->restructure_pages ) { + if ( $this->restructure_pages && GFCommon::has_pages( $form ) ) { $filtered_fields = $this->handle_pagination( $filtered_fields, $form ); } - if ( ! $this->preserve_order ) { + // @todo Fix issue where randomized order is not preserved on subsequent form renders (e.g. pages, validation errors). + // For now, let's preserve field order for paginated forms. + if ( ! $this->preserve_order && ( ! $this->restructure_pages || ! GFCommon::has_pages( $form ) ) ) { $reordered_fields = array(); $random_index_key = $random_indexes; @@ -126,13 +126,6 @@ public function filter_form_fields( $form, $selected_fields ) { public function handle_pagination( $filtered_fields, $form ) { - $pages = array(); - foreach ( $form['fields'] as $field ) { - if ( $field->type === 'page' ) { - $pages[] = $field; - } - } - // Remove Section fields if they are the only fields left on a page after randomization. foreach ( $filtered_fields as $index => $field ) { if ( $field->type === 'section' && $this->is_only_field_on_page( $filtered_fields, $field ) ) { @@ -153,7 +146,7 @@ public function handle_pagination( $filtered_fields, $form ) { foreach ( $page_numbers as $new_page_number => $old_page_number ) { // $pages is still a 0-based indexed array; subtract 2 from the old page number to find the right page. - $page = rgar( $pages, $old_page_number - 2 ); + $page = $this->get_page_by_page_number( $form, $old_page_number ); if ( ! $page ) { continue; }