Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix CSV export issue #2215 #2216

Merged
merged 4 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
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
35 changes: 34 additions & 1 deletion future/includes/class-gv-view.php
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,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.
*
Expand Down Expand Up @@ -1696,7 +1729,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' );

Expand Down
29 changes: 17 additions & 12 deletions future/includes/rest/class-gv-rest-views-route.php
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mrcasual This was the cause of the bug - it always used the main form as the source, even when the field belonged to the joined form.

$source = View::get_source( $field, $view );

$field_id = $field->ID;
$index = null;

Expand All @@ -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)
Expand Down Expand Up @@ -270,7 +275,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();
Expand Down Expand Up @@ -298,7 +303,7 @@ function ( $context ) use ( &$count, &$total ) {
* @since 2.0
* @param bool $insert_meta Add <meta> 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
*/
Expand Down Expand Up @@ -406,7 +411,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 ) {
Expand Down Expand Up @@ -434,7 +439,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();

Expand Down Expand Up @@ -485,7 +490,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' ) );
}

Expand Down Expand Up @@ -513,7 +518,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' ) );
Expand All @@ -532,7 +537,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' );
Expand Down Expand Up @@ -580,7 +585,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' ) );
}

Expand Down
4 changes: 4 additions & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 =

Expand Down
68 changes: 53 additions & 15 deletions templates/fields/field-checkbox-csv.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mrcasual This is the same logic as in the field-checkbox-html.php file.

/**
* 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 );
Copy link
Collaborator

Choose a reason for hiding this comment

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

@zahardev, is there a reason why you didn't use the existing gravityview_field_tick filter?

Copy link
Contributor Author

@zahardev zahardev Nov 25, 2024

Choose a reason for hiding this comment

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

@mrcasual The gravityview_field_tick filter is used on web pages, and its default value is <span class="dashicons dashicons-yes"></span>. We can't use this value in CSV exports as it won't convert to a tick symbol. That's why I added a new filter specifically for CSV handling. Please let me know if we can somehow improve it or use gravityview_field_tick instead.

Copy link
Contributor

@rafaehlers rafaehlers Nov 25, 2024

Choose a reason for hiding this comment

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

Thanks for the clarification @zahardev! @mrcasual that explains why DataTables wasn't able to export the ticks (DT strips HTML), and I had to use an emoji in place: https://github.com/GravityKit/DataTables/issues/60#issuecomment-856311493

}
break;
}
}

echo implode( $glue, array_filter( $value ) );
echo $output;