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 +112 -18 0.0.5 → 2.4.1 View file →
@@ -1,8 +1,9 @@
1 1 <?php
2 2
3 3 namespace Better_Payment\Lite\Classes;
4 4
5 +use Better_Payment\Lite\Classes\Helper as ClassesHelper;
5 6 use Better_Payment\Lite\Controller;
6 7 use Better_Payment\Lite\Models\TransactionModel;
7 8 use Better_Payment\Lite\Traits\Helper;
8 9
@@ -20,9 +21,19 @@
20 21 */
21 22 class Export extends Controller{
22 23
23 24 use Helper;
25 +
24 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 + /**
25 36 * Class constructor
26 37 *
27 38 * @since 0.0.4
28 39 */
@@ -32,9 +43,9 @@
32 43
33 44 public function export_transactions() {
34 45 $response = [];
35 46
36 - if (!wp_verify_nonce($_REQUEST['nonce'], 'better_payment_admin_nonce')) {
47 + if (!wp_verify_nonce($_REQUEST['nonce'], 'wp_rest')) {
37 48 $response['message'] = __("Access Denied!", 'better-payment');
38 49 wp_send_json_error($response);
39 50 }
40 51
@@ -43,22 +54,73 @@
43 54 wp_send_json_error($response);
44 55 }
45 56
46 57 $transaction_model = new TransactionModel();
47 - $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 + }
48 99
49 - $filename = 'better-payment-transactions-' . date('Y-m-d') . '.csv';
50 100 return $this->transactions_array_to_csv_download($all_transactions, $filename);
51 101 }
52 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 +
53 116 public function transactions_array_to_csv_download($array, $filename = "export.csv", $delimiter=";") {
54 - $bp_helper_obj = new Better_Payment_Helper();
55 117 $wp_date_format = get_option('date_format');
56 118 $wp_time_format = get_option('time_format');
57 119
58 120 $f = fopen('php://memory', 'w');
59 121
60 - fputcsv($f, $this->export_transactions_heading(), $delimiter);
122 + self::put_csv_row($f, $this->export_transactions_heading(), $delimiter);
61 123
62 124 foreach ($array as $line) {
63 125 $line = (array)$line;
64 126 unset($line['id']);
@@ -69,28 +131,42 @@
69 131 // unset($line['form_fields_info']);
70 132 unset($line['referer']);
71 133
72 134
73 - $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 ) );
74 138 $line['source'] = esc_html( ucfirst( $line['source'] ) );
75 139 $line['payment_date'] = wp_date($wp_date_format.' '.$wp_time_format, strtotime($line['payment_date']));;
76 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 +
77 144 $line['form_fields_info'] = $this->form_fields_info_formatted($line['form_fields_info']);
78 -
145 +
79 146 $line['form_fields_info_name'] = isset($line['form_fields_info']['customer_name']) ? $line['form_fields_info']['customer_name'] : '';
80 147 $line['form_fields_info_email'] = isset($line['form_fields_info']['customer_email']) ? $line['form_fields_info']['customer_email'] : '';
81 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 +
82 156 $line_formatted = array(
83 157 $line['form_fields_info_name'],
84 158 $line['form_fields_info_email'],
85 159 $line['currency'] . ' ' . $line['amount'],
160 + $line['payment_type'],
86 161 $line['transaction_id'],
87 162 $line['source'],
88 163 $line['status'],
89 164 $line['payment_date'],
165 + ! empty( $line['form_fields_info'] ) ? maybe_serialize( $line['form_fields_info'] ) : '',
90 166 );
91 167
92 - fputcsv($f, $line_formatted, $delimiter);
168 + self::put_csv_row($f, $line_formatted, $delimiter);
93 169 }
94 170
95 171 // reset the file pointer to the start of the file
96 172 fseek($f, 0);
@@ -105,15 +181,17 @@
105 181 }
106 182
107 183 public function export_transactions_heading(){
108 184 return array(
109 - 'Name',
110 - 'Email Address',
111 - 'Amount',
112 - 'Transaction ID',
113 - 'Source',
114 - 'Status',
115 - 'Date',
185 + esc_html('name'),
186 + esc_html('email'),
187 + esc_html('amount'),
188 + esc_html('payment_type'),
189 + esc_html('transaction_id'),
190 + esc_html('source'),
191 + esc_html('status'),
192 + esc_html('payment_date'),
193 + esc_html('form_fields_info'),
116 194 // 'Order ID',
117 195 // 'Customer Info',
118 196 // 'Form Fields Info',
119 197 // 'Currency',
@@ -120,8 +198,18 @@
120 198 // 'Referer'
121 199 );
122 200 }
123 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 + */
124 212 public function form_fields_info_formatted($form_fields_info){
125 213 $bp_form_fields_info = maybe_unserialize($form_fields_info);
126 214
127 215 $bp_transaction_customer_name = isset($bp_form_fields_info['primary_first_name']) ? sanitize_text_field($bp_form_fields_info['primary_first_name']) : '';
@@ -140,11 +228,17 @@
140 228 if( empty($bp_transaction_customer_email) ){
141 229 $bp_transaction_customer_email = isset($bp_form_fields_info['email']) ? sanitize_text_field($bp_form_fields_info['email']) : '';
142 230 }
143 231
144 - return [
145 - 'customer_name' => $bp_transaction_customer_name,
146 - 'customer_email' => $bp_transaction_customer_email
232 + $formatted = [
233 + 'customer_name' => $bp_transaction_customer_name,
234 + 'customer_email' => $bp_transaction_customer_email,
147 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;
148 242 }
149 243
150 244 }