PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.4.1
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.4.1
2.4.1 2.4.0 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 All 68 releases
← All changes | includes/Classes/Export.php +104 -11 1.0.4 → 2.4.1 View file →
@@ -21,9 +21,19 @@
21 21 */
22 22 class Export extends Controller{
23 23
24 24 use Helper;
25 +
25 26 /**
27 + * CSV escape character, passed to fputcsv() explicitly on every call.
28 + *
29 + * PHP 8.4 deprecates relying on fputcsv()'s default $escape, because that
30 + * default will change in a later release. Passing the current default (a
31 + * backslash) keeps the output byte-identical on PHP 7.4 through 8.5.
32 + */
33 + const CSV_ESCAPE = "\\";
34 +
35 + /**
26 36 * Class constructor
27 37 *
28 38 * @since 0.0.4
29 39 */
@@ -33,9 +43,9 @@
33 43
34 44 public function export_transactions() {
35 45 $response = [];
36 46
37 - if (!wp_verify_nonce($_REQUEST['nonce'], 'better_payment_admin_nonce')) {
47 + if (!wp_verify_nonce($_REQUEST['nonce'], 'wp_rest')) {
38 48 $response['message'] = __("Access Denied!", 'better-payment');
39 49 wp_send_json_error($response);
40 50 }
41 51
@@ -44,22 +54,73 @@
44 54 wp_send_json_error($response);
45 55 }
46 56
47 57 $transaction_model = new TransactionModel();
48 - $all_transactions = $transaction_model->get_transactions();
58 +
59 + // Check if this is a filtered export
60 + $is_filtered = isset($_REQUEST['filtered']) && $_REQUEST['filtered'] === '1';
61 +
62 + if ($is_filtered) {
63 + // Build filter arguments
64 + $filter_args = [];
65 +
66 + if (!empty($_REQUEST['search_text'])) {
67 + $filter_args['search_text'] = sanitize_text_field($_REQUEST['search_text']);
68 + }
69 +
70 + if (!empty($_REQUEST['payment_date_from'])) {
71 + $filter_args['payment_date_from'] = sanitize_text_field($_REQUEST['payment_date_from']);
72 + }
73 +
74 + if (!empty($_REQUEST['payment_date_to'])) {
75 + $filter_args['payment_date_to'] = sanitize_text_field($_REQUEST['payment_date_to']);
76 + }
77 +
78 + if (!empty($_REQUEST['source'])) {
79 + $filter_args['source'] = sanitize_text_field($_REQUEST['source']);
80 + }
81 +
82 + if (!empty($_REQUEST['currency'])) {
83 + $filter_args['currency'] = sanitize_text_field($_REQUEST['currency']);
84 + }
85 +
86 + if (!empty($_REQUEST['status'])) {
87 + $filter_args['status'] = sanitize_text_field($_REQUEST['status']);
88 + }
89 +
90 + $filter_args['per_page'] = '999999999';
91 + // The admin list's v2 tab buckets, so an export of a tab holds exactly the rows that tab
92 + // lists. The v1 path matched `completed` against the raw status `completed` only.
93 + $all_transactions = $transaction_model->get_transactions($filter_args, 'v2');
94 + $filename = 'better-payment-transactions-filtered-' . date('Y-m-d') . '.csv';
95 + } else {
96 + $all_transactions = $transaction_model->get_transactions();
97 + $filename = 'better-payment-transactions-' . date('Y-m-d') . '.csv';
98 + }
49 99
50 - $filename = 'better-payment-transactions-' . date('Y-m-d') . '.csv';
51 100 return $this->transactions_array_to_csv_download($all_transactions, $filename);
52 101 }
53 102
103 + /**
104 + * Write one CSV row. All CSV writes go through here so none can rely on the
105 + * deprecated default $escape.
106 + *
107 + * @param resource $handle Open, writable stream.
108 + * @param array $fields Row values.
109 + * @param string $delimiter Field delimiter.
110 + * @return int|false Bytes written, or false on failure.
111 + */
112 + public static function put_csv_row($handle, array $fields, $delimiter = ";") {
113 + return fputcsv($handle, $fields, $delimiter, "\"", self::CSV_ESCAPE);
114 + }
115 +
54 116 public function transactions_array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
55 - $bp_helper_obj = new ClassesHelper();
56 117 $wp_date_format = get_option('date_format');
57 118 $wp_time_format = get_option('time_format');
58 119
59 120 $f = fopen('php://memory', 'w');
60 121
61 - fputcsv($f, $this->export_transactions_heading(), $delimiter);
122 + self::put_csv_row($f, $this->export_transactions_heading(), $delimiter);
62 123
63 124 foreach ($array as $line) {
64 125 $line = (array)$line;
65 126 unset($line['id']);
@@ -70,28 +131,42 @@
70 131 // unset($line['form_fields_info']);
71 132 unset($line['referer']);
72 133
73 134
74 - $line['status'] = esc_html(ucfirst($bp_helper_obj->get_type_by_transaction_status($line['status'], 'v2')));
135 + // From the stored row (form_fields_info still serialized): an unconfirmed pre-2.4.0 free
136 + // checkout exports as Incomplete (Helper::transaction_status_type()).
137 + $line['status'] = esc_html( ClassesHelper::transaction_status_label( $line ) );
75 138 $line['source'] = esc_html( ucfirst( $line['source'] ) );
76 139 $line['payment_date'] = wp_date($wp_date_format.' '.$wp_time_format, strtotime($line['payment_date']));;
77 140
141 + // 'One Time' unless Pro labels the row (better_payment/transaction/payment_type).
142 + $line['payment_type'] = ClassesHelper::payment_type_label( maybe_unserialize( $line['form_fields_info'] ) );
143 +
78 144 $line['form_fields_info'] = $this->form_fields_info_formatted($line['form_fields_info']);
79 -
145 +
80 146 $line['form_fields_info_name'] = isset($line['form_fields_info']['customer_name']) ? $line['form_fields_info']['customer_name'] : '';
81 147 $line['form_fields_info_email'] = isset($line['form_fields_info']['customer_email']) ? $line['form_fields_info']['customer_email'] : '';
82 148
149 + unset($line['form_fields_info']['customer_name']);
150 + unset($line['form_fields_info']['customer_email']);
151 +
152 + $line['form_fields_info'] = array_filter($line['form_fields_info'], function($value) {
153 + return !empty($value);
154 + });
155 +
83 156 $line_formatted = array(
84 157 $line['form_fields_info_name'],
85 158 $line['form_fields_info_email'],
86 159 $line['currency'] . ' ' . $line['amount'],
160 + $line['payment_type'],
87 161 $line['transaction_id'],
88 162 $line['source'],
89 163 $line['status'],
90 164 $line['payment_date'],
165 + ! empty( $line['form_fields_info'] ) ? maybe_serialize( $line['form_fields_info'] ) : '',
91 166 );
92 167
93 - fputcsv($f, $line_formatted, $delimiter);
168 + self::put_csv_row($f, $line_formatted, $delimiter);
94 169 }
95 170
96 171 // reset the file pointer to the start of the file
97 172 fseek($f, 0);
@@ -109,12 +184,14 @@
109 184 return array(
110 185 esc_html('name'),
111 186 esc_html('email'),
112 187 esc_html('amount'),
188 + esc_html('payment_type'),
113 189 esc_html('transaction_id'),
114 190 esc_html('source'),
115 191 esc_html('status'),
116 192 esc_html('payment_date'),
193 + esc_html('form_fields_info'),
117 194 // 'Order ID',
118 195 // 'Customer Info',
119 196 // 'Form Fields Info',
120 197 // 'Currency',
@@ -121,8 +198,18 @@
121 198 // 'Referer'
122 199 );
123 200 }
124 201
202 + /**
203 + * The fields a transaction contributes to the CSV: customer name and email, plus
204 + * whatever `better_payment/export/form_fields_info` adds.
205 + *
206 + * Pro adds the subscription keys its recurring and split checkouts store; a free
207 + * install exports name and email.
208 + *
209 + * @param mixed $form_fields_info Serialized or unserialized form_fields_info.
210 + * @return array
211 + */
125 212 public function form_fields_info_formatted($form_fields_info){
126 213 $bp_form_fields_info = maybe_unserialize($form_fields_info);
127 214
128 215 $bp_transaction_customer_name = isset($bp_form_fields_info['primary_first_name']) ? sanitize_text_field($bp_form_fields_info['primary_first_name']) : '';
@@ -141,11 +228,17 @@
141 228 if( empty($bp_transaction_customer_email) ){
142 229 $bp_transaction_customer_email = isset($bp_form_fields_info['email']) ? sanitize_text_field($bp_form_fields_info['email']) : '';
143 230 }
144 231
145 - return [
146 - 'customer_name' => $bp_transaction_customer_name,
147 - 'customer_email' => $bp_transaction_customer_email
232 + $formatted = [
233 + 'customer_name' => $bp_transaction_customer_name,
234 + 'customer_email' => $bp_transaction_customer_email,
148 235 ];
236 +
237 + $raw_fields = is_array( $bp_form_fields_info ) ? $bp_form_fields_info : [];
238 +
239 + $filtered = apply_filters( 'better_payment/export/form_fields_info', $formatted, $raw_fields );
240 +
241 + return is_array( $filtered ) ? $filtered : $formatted;
149 242 }
150 243
151 244 }