|
| 1 | +<?php |
| 2 | +/** |
| 3 | + * Experimental! See important notes below. |
| 4 | + * |
| 5 | + * Gravity Perks // GP Entry Blocks // Show "Download Entries as CSV" link for Entries Table blocks |
| 6 | + * https://gravitywiz.com/documentation/gravity-forms-entry-blocks/ |
| 7 | + * |
| 8 | + * Installation: |
| 9 | + * 1. Install per https://gravitywiz.com/documentation/how-do-i-install-a-snippet/ |
| 10 | + * |
| 11 | + * Important notes: |
| 12 | + * * This will show the link on all Entries Table blocks for now. |
| 13 | + * * The CSV export does not take into consideration the filters in an Entries Table's parent Entries block. |
| 14 | + * * Exporting will only export for 20 seconds. Anything after that will not be included in the export. We will need to implement AJAX |
| 15 | + * much like Gravity Forms does in the admin to enable exporting for longer than that. |
| 16 | + * * This is a server-side request to handle exporting. If this block is visible to the public, it could potentially create |
| 17 | + * performance issues if frequently clicked. |
| 18 | + */ |
| 19 | +add_action( 'gpeb_before_render_block', function( $block ) { |
| 20 | + // Do not show this in the Block Editor (or when saving in the BE) |
| 21 | + if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { |
| 22 | + return; |
| 23 | + } |
| 24 | + |
| 25 | + if ( $block->name !== 'gp-entry-blocks/entries-table' ) { |
| 26 | + return; |
| 27 | + } |
| 28 | + |
| 29 | + global $post; |
| 30 | + |
| 31 | + $export_url = add_query_arg( array( |
| 32 | + 'export_block_entries' => $block->context['gp-entry-blocks/uuid'], |
| 33 | + 'export_block_entries_nonce' => wp_create_nonce( $block->context['gp-entry-blocks/uuid'] ), |
| 34 | + 'block_type' => $block->context['gp-entry-blocks/uuid'], |
| 35 | + ), \GP_Entry_Blocks\get_current_url() ); |
| 36 | + |
| 37 | + echo '<a href="' . $export_url . '" target="_blank" class="gpeb-export-csv-link">Download Entries as CSV</a>'; |
| 38 | +} ); |
| 39 | + |
| 40 | +add_action( 'template_redirect', function() { |
| 41 | + $block_uuid = rgget( 'export_block_entries' ); |
| 42 | + |
| 43 | + if ( ! $block_uuid ) { |
| 44 | + return; |
| 45 | + } |
| 46 | + |
| 47 | + if ( ! wp_verify_nonce( rgget( 'export_block_entries_nonce' ), $block_uuid ) ) { |
| 48 | + return; |
| 49 | + } |
| 50 | + |
| 51 | + $parsed_entries_block = \GP_Entry_Blocks\get_parsed_block_by_uuid( $block_uuid, 'gp-entry-blocks/entries' ); |
| 52 | + $parsed_entries_table_block = \GP_Entry_Blocks\get_parsed_block_by_uuid( $block_uuid, 'gp-entry-blocks/entries-table' ); |
| 53 | + |
| 54 | + if ( ! $parsed_entries_block || ! $parsed_entries_table_block ) { |
| 55 | + return; |
| 56 | + } |
| 57 | + |
| 58 | + $block = new WP_Block( $parsed_entries_block, $parsed_entries_block['availableContext'] ); |
| 59 | + |
| 60 | + // Use $block->attributes with the keys prefixed with "gp-entry-blocks/" as the context. |
| 61 | + $context = array_combine( |
| 62 | + array_map( function( $key ) { |
| 63 | + return 'gp-entry-blocks/' . $key; |
| 64 | + }, array_keys( $block->attributes ) ), |
| 65 | + $block->attributes |
| 66 | + ); |
| 67 | + |
| 68 | + // @todo Wire up to `gform_search_criteria_export_entries` |
| 69 | + $queryer = \GP_Entry_Blocks\GF_Queryer::attach( $context ); |
| 70 | + |
| 71 | + require_once( GFCommon::get_base_path() . '/export.php' ); |
| 72 | + |
| 73 | + $form = GFAPI::get_form( $block->attributes['formId'] ); |
| 74 | + |
| 75 | + // Make unique to GPEB. |
| 76 | + $export_id = wp_hash( uniqid( 'export', true ) ); |
| 77 | + $export_id = sanitize_key( $export_id ); |
| 78 | + |
| 79 | + // Use the summary columns from the Entries Table block in the export. |
| 80 | + $summary_columns = $parsed_entries_table_block['attrs']['formFields']; |
| 81 | + |
| 82 | + $_POST['export_field'] = array(); |
| 83 | + |
| 84 | + foreach ( $summary_columns as $summary_column ) { |
| 85 | + switch ( $summary_column['type'] ) { |
| 86 | + case 'id': |
| 87 | + $_POST['export_field'][] = $summary_column['type']; |
| 88 | + break; |
| 89 | + |
| 90 | + case 'field': |
| 91 | + $_POST['export_field'][] = $summary_column['meta']['fieldId']; |
| 92 | + break; |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + /** |
| 97 | + * @var array{ |
| 98 | + * status: 'complete'|'in_progress', |
| 99 | + * offset: int, |
| 100 | + * exportId: string, |
| 101 | + * progress: string, |
| 102 | + * } $export_result |
| 103 | + */ |
| 104 | + // Note, the way this works is it'll only export for 20 seconds (or whatever is set in `gform_export_max_execution_time`). |
| 105 | + // Anything after that will not be included in the export. |
| 106 | + $export_result = GFExport::start_export( $form, 0, $export_id ); |
| 107 | + |
| 108 | + $filename = sanitize_title_with_dashes( $form['title'] ) . '-' . gmdate( 'Y-m-d', GFCommon::get_local_timestamp( time() ) ) . '.csv'; |
| 109 | + $export_folder = RGFormsModel::get_upload_root() . 'export/'; |
| 110 | + $file = $export_folder . sanitize_file_name( 'export-' . $export_id . '.csv' ); |
| 111 | + |
| 112 | + $charset = get_option( 'blog_charset' ); |
| 113 | + header( 'Content-Description: File Transfer' ); |
| 114 | + header( "Content-Disposition: attachment; filename=$filename" ); |
| 115 | + header( 'Content-Type: text/csv; charset=' . $charset, true ); |
| 116 | + $buffer_length = ob_get_length(); //length or false if no buffer |
| 117 | + if ( $buffer_length > 1 ) { |
| 118 | + ob_clean(); |
| 119 | + } |
| 120 | + |
| 121 | + $result = readfile( $file ); |
| 122 | + |
| 123 | + if ( $result === false ) { |
| 124 | + GFCommon::log_error( __METHOD__ . '(): An issue occurred whilst reading the file.' ); |
| 125 | + } else { |
| 126 | + @unlink( $file ); |
| 127 | + GFCommon::log_debug( __METHOD__ . '(): Number of bytes read from the file: ' . print_r( $result, 1 ) ); |
| 128 | + } |
| 129 | + |
| 130 | + die(); |
| 131 | +} ); |
0 commit comments