From 4734287d3918d7644982a0620eb3b80dd6a51688 Mon Sep 17 00:00:00 2001 From: Serhiy Zakharchenko Date: Fri, 22 Nov 2024 17:53:04 +0000 Subject: [PATCH 1/3] Fix CSV export issue #2215 --- .../rest/class-gv-rest-views-route.php | 62 +++++++++++++---- readme.txt | 1 + templates/fields/field-checkbox-csv.php | 68 +++++++++++++++---- 3 files changed, 104 insertions(+), 27 deletions(-) diff --git a/future/includes/rest/class-gv-rest-views-route.php b/future/includes/rest/class-gv-rest-views-route.php index 5a10a9ea1..2c97c2121 100644 --- a/future/includes/rest/class-gv-rest-views-route.php +++ b/future/includes/rest/class-gv-rest-views-route.php @@ -11,6 +11,10 @@ namespace GV\REST; use GravityView_Widget_Export_Link; +use GV\Field; +use GV\GF_Form; +use GV\Internal_Source; +use GV\View; use WP_REST_Request; /** If this file is called directly, abort. */ @@ -121,7 +125,7 @@ public function get_item( $request ) { * Prepare the item for the REST response * * @since 2.0 - * @param \GV\View $view The view. + * @param View $view The view. * @param \GV\Entry $entry WordPress representation of the item. * @param \WP_REST_Request $request Request object. * @param string $context The context (directory, single) @@ -143,7 +147,7 @@ public function prepare_entry_for_response( $view, $entry, \WP_REST_Request $req * Allow more entry fields that are output in regular REST requests. * * @param array $allowed The allowed ones, default by_visible, by_position( "context_*" ), i.e. as set in the view. - * @param \GV\View $view The view. + * @param View $view The view. * @param \GV\Entry $entry The entry. * @param \WP_REST_Request $request Request object. * @param string $context The context (directory, single) @@ -173,7 +177,8 @@ function ( $field ) use ( $allowed_field_ids ) { // remove all links from output. $field->update_configuration( [ 'show_as_link' => '0' ] ); - $source = is_numeric( $field->ID ) ? $view->form : new \GV\Internal_Source(); + $source = $this->get_source( $field, $view ); + $field_id = $field->ID; $index = null; @@ -194,7 +199,7 @@ function ( $field ) use ( $allowed_field_ids ) { * Filter the key name in the results for JSON output. * * @param string $field_id The ID. Should be unique or keys will be gobbled up. - * @param \GV\View $view The view. + * @param View $view The view. * @param \GV\Entry $entry The entry. * @param \WP_REST_Request $request Request object. * @param string $context The context (directory, single) @@ -240,6 +245,39 @@ function ( $field ) use ( $allowed_field_ids ) { return $return; } + /** + * Gets the source of the field. + * + * @since $ver$ + * + * @param Field $field The field. + * @param View $view The view. + * + * @return GF_Form|Internal_Source + */ + protected function get_source( $field, $view ) { + if ( ! is_numeric( $field->ID ) ) { + return new Internal_Source(); + } + + $form_id = $field->field->formId ?? null; + + // If the field's form differs from the main view form, get the form from the joined entries. + if ( $form_id && $view->form->ID != $form_id && ! empty( $view->joins ) ) { + foreach ( $view->joins as $join ) { + if ( isset( $join->join_on->ID ) && $join->join_on->ID == $form_id ) { + return $join->join_on; + } + } + + // Edge case where the form cannot be retrieved from the joins. + return GF_Form::by_id( $form_id ); + } + + // Return the main view form. + return $view->form; + } + /** * Get entries from a view * @@ -270,7 +308,7 @@ public function get_sub_items( $request ) { } } - $view = \GV\View::by_id( $view_id ); + $view = View::by_id( $view_id ); if ( null !== $view ) { $post = $view->get_post(); @@ -298,7 +336,7 @@ function ( $context ) use ( &$count, &$total ) { * @since 2.0 * @param bool $insert_meta Add tags? [Default: true] * @param int $count The number of entries being rendered - * @param \GV\View $view The view. + * @param View $view The view. * @param \WP_REST_Request $request Request object. * @param int $total The number of total entries for the request */ @@ -406,7 +444,7 @@ public function get_sub_item( $request ) { $entry_id = intval( $url['s_id'] ); $format = \GV\Utils::get( $url, 'format', 'json' ); - $view = \GV\View::by_id( $view_id ); + $view = View::by_id( $view_id ); $entry = \GV\GF_Entry::by_id( $entry_id ); if ( 'html' === $format ) { @@ -434,7 +472,7 @@ public function prepare_view_for_response( $view_post, \WP_REST_Request $request ); } - $view = \GV\View::from_post( $view_post ); + $view = View::from_post( $view_post ); $item = $view->as_data(); @@ -485,7 +523,7 @@ public function get_item_permissions_check( $request ) { $view_id = intval( $url['id'] ); } - if ( ! $view = \GV\View::by_id( $view_id ) ) { + if ( ! $view = View::by_id( $view_id ) ) { return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this content.', 'gk-gravityview' ) ); } @@ -513,7 +551,7 @@ public function get_item_permissions_check( $request ) { * Disable rest output. Final chance. * * @param bool Enable or not. - * @param \GV\View $view The view. + * @param View $view The view. */ if ( ! apply_filters( 'gravityview/view/output/rest', true, $view ) ) { return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this content.', 'gk-gravityview' ) ); @@ -532,7 +570,7 @@ public function get_sub_item_permissions_check( $request ) { $view_id = intval( $url['id'] ); $entry_id = intval( $url['s_id'] ); - $view = \GV\View::by_id( $view_id ); + $view = View::by_id( $view_id ); if ( ! $entry = \GV\GF_Entry::by_id( $entry_id ) ) { return new \WP_Error( 'rest_forbidden', 'You are not allowed to view this content.', 'gravityview' ); @@ -580,7 +618,7 @@ public function get_sub_items_permissions_check( $request ) { $nonce = $request->get_param( '_nonce' ); $view_id = rgar( $params, 'id', 0 ); - if ( ! $view = \GV\View::by_id( $view_id ) ) { + if ( ! $view = View::by_id( $view_id ) ) { return new \WP_Error( 'rest_forbidden', __( 'You are not allowed to access this content.', 'gk-gravityview' ) ); } diff --git a/readme.txt b/readme.txt index e8a4d7fa0..acc27e6da 100644 --- a/readme.txt +++ b/readme.txt @@ -41,6 +41,7 @@ This release adds a new form notification option for updated entries, resolves f #### 💻 Developer Updates * Added `gk/gravityview/view/entries/join-conditions` filter to modify the join conditions applied when retrieving View entries. * Added `gk/gravityview/template/options` filter to programmatically modify field settings in the View editor. +* Added `gravityview/template/field/csv/tick` filter to programmatically modify the checkbox "check" output in CSV. * Added `gravityview/row-added` JavaScript event, triggered when a new row is added to a widget or field area. = 2.31.1 on November 8, 2024 = diff --git a/templates/fields/field-checkbox-csv.php b/templates/fields/field-checkbox-csv.php index a9c6dabf1..a376b1575 100644 --- a/templates/fields/field-checkbox-csv.php +++ b/templates/fields/field-checkbox-csv.php @@ -2,28 +2,66 @@ /** * The default field output template for CSVs. * - * @global \GV\Template_Context $gravityview * @since 2.0 + * @global Template_Context $gravityview */ +use GV\Template_Context; +use GV\Utils; + if ( ! isset( $gravityview ) || empty( $gravityview->template ) ) { gravityview()->log->error( '{file} template loaded without context', array( 'file' => __FILE__ ) ); + return; } -$field_id = $gravityview->field->ID; -$display_value = $gravityview->display_value; -$value = $gravityview->value; -$entry = $gravityview->entry->as_entry(); +$field_id = $gravityview->field->ID; +$field = $gravityview->field->field; +$value = $gravityview->value; +$form = $gravityview->view->form->form; +$entry = $gravityview->entry->as_entry(); +$field_settings = $gravityview->field->as_configuration(); +$display_type = Utils::get( $field_settings, 'choice_display' ); +$is_single_input = floor( $field_id ) !== floatval( $field_id ); +$output = ''; -/** - * The value used to separate multiple values in the CSV export. - * - * @since 2.4.2 - * - * @param string The glue. Default: ";" (semicolon) - * @param \GV\Template_Context The context. - */ -$glue = apply_filters( 'gravityview/template/field/csv/glue', ';', $gravityview ); +// It's the parent field, not an input +if ( ! $is_single_input ) { + /** + * The value used to separate multiple values in the CSV export. + * + * @since 2.4.2 + * + * @param string $glue The glue. Default: ";" (semicolon). + * @param Template_Context $gravityview The context. + */ + $glue = apply_filters( 'gravityview/template/field/csv/glue', ';', $gravityview ); + $output = implode( $glue, array_filter( $value ) ); +} else { + + $field_value = $entry[ $field_id ] ?? ''; + + switch ( $display_type ) { + case 'label': + $output = gravityview_get_field_label( $form, $field_id, $value ); + break; + case 'tick': + default: + if ( $field_value ) { + /** + * Change the output for a checkbox "check" symbol. + * + * @since $ver$ + * + * @param string $output Checkbox "check" symbol. Default: "✓". + * @param array $entry Entry data. + * @param GF_Field_Checkbox $field GravityView field. + * @param Template_Context $gravityview The context. + */ + $output = apply_filters( 'gravityview/template/field/csv/tick', '✓', $entry, $field, $gravityview ); + } + break; + } +} -echo implode( $glue, array_filter( $value ) ); +echo $output; From 6603f790c0ac64d386880a8029cd35702fcd3cf2 Mon Sep 17 00:00:00 2001 From: Serhiy Zakharchenko Date: Tue, 26 Nov 2024 13:51:56 -0800 Subject: [PATCH 2/3] Fix CSV export for /view/{view_slug}/csv/ URL #2215 --- future/includes/class-gv-view.php | 35 ++++++++++++++++++- .../rest/class-gv-rest-views-route.php | 35 +------------------ 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/future/includes/class-gv-view.php b/future/includes/class-gv-view.php index b3c330030..2d2de4910 100644 --- a/future/includes/class-gv-view.php +++ b/future/includes/class-gv-view.php @@ -873,6 +873,39 @@ public static function by_id( $post_id ) { return self::from_post( $post ); } + /** + * Gets the source of the field. + * + * @since $ver$ + * + * @param Field $field The field. + * @param View $view The view. + * + * @return GF_Form|Internal_Source + */ + public static function get_source( $field, $view ) { + if ( ! is_numeric( $field->ID ) ) { + return new Internal_Source(); + } + + $form_id = $field->field->formId ?? null; + + // If the field's form differs from the main view form, get the form from the joined entries. + if ( $form_id && $view->form->ID != $form_id && ! empty( $view->joins ) ) { + foreach ( $view->joins as $join ) { + if ( isset( $join->join_on->ID ) && $join->join_on->ID == $form_id ) { + return $join->join_on; + } + } + + // Edge case where the form cannot be retrieved from the joins. + return GF_Form::by_id( $form_id ); + } + + // Return the main view form. + return $view->form; + } + /** * Determines if a view exists to begin with. * @@ -1691,7 +1724,7 @@ function ( $field ) use ( $allowed_field_ids ) { } foreach ( $allowed as $field ) { - $source = is_numeric( $field->ID ) ? $view->form : new \GV\Internal_Source(); + $source = self::get_source( $field, $view ); $return[] = $renderer->render( $field, $view, $source, $entry, gravityview()->request, '\GV\Field_CSV_Template' ); diff --git a/future/includes/rest/class-gv-rest-views-route.php b/future/includes/rest/class-gv-rest-views-route.php index 2c97c2121..bf7915e9b 100644 --- a/future/includes/rest/class-gv-rest-views-route.php +++ b/future/includes/rest/class-gv-rest-views-route.php @@ -177,7 +177,7 @@ function ( $field ) use ( $allowed_field_ids ) { // remove all links from output. $field->update_configuration( [ 'show_as_link' => '0' ] ); - $source = $this->get_source( $field, $view ); + $source = View::get_source( $field, $view ); $field_id = $field->ID; $index = null; @@ -245,39 +245,6 @@ function ( $field ) use ( $allowed_field_ids ) { return $return; } - /** - * Gets the source of the field. - * - * @since $ver$ - * - * @param Field $field The field. - * @param View $view The view. - * - * @return GF_Form|Internal_Source - */ - protected function get_source( $field, $view ) { - if ( ! is_numeric( $field->ID ) ) { - return new Internal_Source(); - } - - $form_id = $field->field->formId ?? null; - - // If the field's form differs from the main view form, get the form from the joined entries. - if ( $form_id && $view->form->ID != $form_id && ! empty( $view->joins ) ) { - foreach ( $view->joins as $join ) { - if ( isset( $join->join_on->ID ) && $join->join_on->ID == $form_id ) { - return $join->join_on; - } - } - - // Edge case where the form cannot be retrieved from the joins. - return GF_Form::by_id( $form_id ); - } - - // Return the main view form. - return $view->form; - } - /** * Get entries from a view * From e36f4a9079c421902175c05dcc88ee18274efd5c Mon Sep 17 00:00:00 2001 From: Vlad Date: Wed, 27 Nov 2024 10:27:03 -0500 Subject: [PATCH 3/3] Update changelog [ci skip] --- readme.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 01f0d9515..74f513813 100644 --- a/readme.txt +++ b/readme.txt @@ -25,6 +25,10 @@ Beautifully display your Gravity Forms entries. Learn more on [gravitykit.com](h #### 🐛 Fixed * Merge tags in redirect URLs were not processed after editing or deleting an entry in the lightbox. +* Individual Checkboxes field inputs incorrectly exported in CSV. + +#### 💻 Developer Updates +* Added `gravityview/template/field/csv/tick` filter to programmatically modify the checkbox "check" output in CSV. = 2.32 on November 21, 2024 = @@ -44,7 +48,6 @@ This release adds a new form notification option for updated entries, resolves f #### 💻 Developer Updates * Added `gk/gravityview/view/entries/join-conditions` filter to modify the join conditions applied when retrieving View entries. * Added `gk/gravityview/template/options` filter to programmatically modify field settings in the View editor. -* Added `gravityview/template/field/csv/tick` filter to programmatically modify the checkbox "check" output in CSV. * Added `gravityview/row-added` JavaScript event, triggered when a new row is added to a widget or field area. = 2.31.1 on November 8, 2024 =