Passed
Pull Request — master (#864)
by Kiran
07:42 queued 01:58
created
includes/class-getpaid-customers-query.php 1 patch
Indentation   +497 added lines, -497 removed lines patch added patch discarded remove patch
@@ -16,502 +16,502 @@
 block discarded – undo
16 16
  */
17 17
 class GetPaid_Customers_Query {
18 18
 
19
-	/**
20
-	 * Query vars, after parsing
21
-	 *
22
-	 * @since 1.0.19
23
-	 * @var array
24
-	 */
25
-	public $query_vars = array();
26
-
27
-	/**
28
-	 * List of found customers.
29
-	 *
30
-	 * @since 1.0.19
31
-	 * @var array
32
-	 */
33
-	private $results;
34
-
35
-	/**
36
-	 * Total number of found customers for the current query
37
-	 *
38
-	 * @since 1.0.19
39
-	 * @var int
40
-	 */
41
-	private $total_customers = 0;
42
-
43
-	/**
44
-	 * The SQL query used to fetch matching customers.
45
-	 *
46
-	 * @since 1.0.19
47
-	 * @var string
48
-	 */
49
-	public $request;
50
-
51
-	// SQL clauses
52
-
53
-	/**
54
-	 * Contains the 'FIELDS' sql clause
55
-	 *
56
-	 * @since 1.0.19
57
-	 * @var string
58
-	 */
59
-	public $query_fields;
60
-
61
-	/**
62
-	 * Contains the 'FROM' sql clause
63
-	 *
64
-	 * @since 1.0.19
65
-	 * @var string
66
-	 */
67
-	public $query_from;
68
-
69
-	/**
70
-	 * Contains the 'WHERE' sql clause
71
-	 *
72
-	 * @since 1.0.19
73
-	 * @var string
74
-	 */
75
-	public $query_where;
76
-
77
-	/**
78
-	 * Contains the 'ORDER BY' sql clause
79
-	 *
80
-	 * @since 1.0.19
81
-	 * @var string
82
-	 */
83
-	public $query_orderby;
84
-
85
-	/**
86
-	 * Contains the 'LIMIT' sql clause
87
-	 *
88
-	 * @since 1.0.19
89
-	 * @var string
90
-	 */
91
-	public $query_limit;
92
-
93
-	/**
94
-	 * Class constructor.
95
-	 *
96
-	 * @since 1.0.19
97
-	 *
98
-	 * @param null|string|array $query Optional. The query variables.
99
-	 */
100
-	public function __construct( $query = null ) {
101
-		if ( ! is_null( $query ) ) {
102
-			$this->prepare_query( $query );
103
-			$this->query();
104
-		}
105
-	}
106
-
107
-	/**
108
-	 * Fills in missing query variables with default values.
109
-	 *
110
-	 * @since 1.0.19
111
-	 *
112
-	 * @param  string|array $args Query vars, as passed to `GetPaid_Subscriptions_Query`.
113
-	 * @return array Complete query variables with undefined ones filled in with defaults.
114
-	 */
115
-	public static function fill_query_vars( $args ) {
116
-		$defaults = array(
117
-			'include'     => array(),
118
-			'exclude'     => array(),
119
-			'orderby'     => 'id',
120
-			'order'       => 'DESC',
121
-			'offset'      => '',
122
-			'number'      => 10,
123
-			'paged'       => 1,
124
-			'count_total' => true,
125
-			'fields'      => 'all',
126
-			's'           => '',
127
-		);
128
-
129
-		foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
130
-			$defaults[ $field ] = 'any';
131
-
132
-			if ( '%f' === $type || '%d' === $type ) {
133
-				$defaults[ $field . '_min' ] = '';
134
-				$defaults[ $field . '_max' ] = '';
135
-			}
136
-		}
137
-
138
-		return wp_parse_args( $args, $defaults );
139
-	}
140
-
141
-	/**
142
-	 * Prepare the query variables.
143
-	 *
144
-	 * @since 1.0.19
145
-	 *
146
-	 * @see self::fill_query_vars() For allowede args and their defaults.
147
-	 */
148
-	public function prepare_query( $query = array() ) {
149
-		global $wpdb;
150
-
151
-		if ( empty( $this->query_vars ) || ! empty( $query ) ) {
152
-			$this->query_limit = null;
153
-			$this->query_vars  = $this->fill_query_vars( $query );
154
-		}
155
-
156
-		if ( ! empty( $this->query_vars['fields'] ) && 'all' !== $this->query_vars['fields'] ) {
157
-			$this->query_vars['fields'] = wpinv_parse_list( $this->query_vars['fields'] );
158
-		}
159
-
160
-		do_action( 'getpaid_pre_get_customers', array( &$this ) );
161
-
162
-		// Ensure that query vars are filled after 'getpaid_pre_get_customers'.
163
-		$qv                = & $this->query_vars;
164
-		$qv                = $this->fill_query_vars( $qv );
165
-		$table             = $wpdb->prefix . 'getpaid_customers';
166
-		$this->query_from  = "FROM $table";
167
-
168
-		// Prepare query fields.
169
-		$this->prepare_query_fields( $qv, $table );
170
-
171
-		// Prepare query where.
172
-		$this->prepare_query_where( $qv, $table );
173
-
174
-		// Prepare query order.
175
-		$this->prepare_query_order( $qv, $table );
176
-
177
-		// limit
178
-		if ( isset( $qv['number'] ) && $qv['number'] > 0 ) {
179
-			if ( $qv['offset'] ) {
180
-				$this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $qv['offset'], $qv['number'] );
181
-			} else {
182
-				$this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $qv['number'] * ( $qv['paged'] - 1 ), $qv['number'] );
183
-			}
184
-		}
185
-
186
-		do_action_ref_array( 'getpaid_after_customers_query', array( &$this ) );
187
-	}
188
-
189
-	/**
190
-	 * Prepares the query fields.
191
-	 *
192
-	 * @since 1.0.19
193
-	 *
194
-	 * @param array $qv Query vars.
195
-	 * @param string $table Table name.
196
-	 */
197
-	protected function prepare_query_fields( &$qv, $table ) {
198
-
199
-		if ( is_array( $qv['fields'] ) ) {
200
-			$qv['fields']   = array_unique( $qv['fields'] );
201
-			$allowed_fields = array_keys( GetPaid_Customer_Data_Store::get_database_fields() );
202
-
203
-			$query_fields = array();
204
-			foreach ( $qv['fields'] as $field ) {
205
-				if ( ! in_array( $field, $allowed_fields ) ) {
206
-					continue;
207
-				}
208
-
209
-				$field          = sanitize_key( $field );
210
-				$query_fields[] = "$table.`$field`";
211
-			}
212
-			$this->query_fields = implode( ',', $query_fields );
213
-		} else {
214
-			$this->query_fields = "$table.*";
215
-		}
216
-
217
-		if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
218
-			$this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
219
-		}
220
-
221
-	}
222
-
223
-	/**
224
-	 * Prepares the query where.
225
-	 *
226
-	 * @since 1.0.19
227
-	 *
228
-	 * @param array $qv Query vars.
229
-	 * @param string $table Table name.
230
-	 */
231
-	protected function prepare_query_where( &$qv, $table ) {
232
-		global $wpdb;
233
-		$this->query_where = 'WHERE 1=1';
234
-
235
-		// Fields.
236
-		foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
237
-			if ( 'any' !== $qv[ $field ] ) {
238
-
239
-				// In.
240
-				if ( is_array( $qv[ $field ] ) ) {
241
-					$in                 = join( ',', array_fill( 0, count( $qv[ $field ] ), $type ) );
242
-					$this->query_where .= $wpdb->prepare( " AND $table.`status` IN ( $in )", $qv[ $field ] );
243
-				} elseif ( ! empty( $qv[ $field ] ) ) {
244
-					$this->query_where .= $wpdb->prepare( " AND $table.`$field` = $type", $qv[ $field ] );
245
-				}
246
-			}
247
-
248
-			// Min/Max.
249
-			if ( '%f' === $type || '%d' === $type ) {
250
-
251
-				// Min.
252
-				if ( is_numeric( $qv[ $field . '_min' ] ) ) {
253
-					$this->query_where .= $wpdb->prepare( " AND $table.`$field` >= $type", $qv[ $field . '_min' ] );
254
-				}
255
-
256
-				// Max.
257
-				if ( is_numeric( $qv[ $field . '_max' ] ) ) {
258
-					$this->query_where .= $wpdb->prepare( " AND $table.`$field` <= $type", $qv[ $field . '_max' ] );
259
-				}
260
-			}
261
-		}
262
-
263
-		if ( ! empty( $qv['include'] ) ) {
264
-			$include            = implode( ',', wp_parse_id_list( $qv['include'] ) );
265
-			$this->query_where .= " AND $table.`id` IN ($include)";
266
-		} elseif ( ! empty( $qv['exclude'] ) ) {
267
-			$exclude            = implode( ',', wp_parse_id_list( $qv['exclude'] ) );
268
-			$this->query_where .= " AND $table.`id` NOT IN ($exclude)";
269
-		}
270
-
271
-		// Date queries are allowed for the customer creation date.
272
-		if ( ! empty( $qv['date_created_query'] ) && is_array( $qv['date_created_query'] ) ) {
273
-			$date_created_query = new WP_Date_Query( $qv['date_created_query'], "$table.date_created" );
274
-			$this->query_where .= $date_created_query->get_sql();
275
-		}
276
-
277
-		// Search.
278
-		if ( ! empty( $qv['s'] ) ) {
279
-			$this->query_where .= $this->get_search_sql( $qv['s'] );
280
-		}
281
-	}
282
-
283
-	/**
284
-	 * Used internally to generate an SQL string for searching across multiple columns
285
-	 *
286
-	 * @since 1.2.7
287
-	 *
288
-	 * @global wpdb $wpdb WordPress database abstraction object.
289
-	 *
290
-	 * @param string $string The string to search for.
291
-	 * @return string
292
-	 */
293
-	protected function get_search_sql( $string ) {
294
-		global $wpdb;
295
-
296
-		$searches = array();
297
-		$string   = trim( $string, '%' );
298
-		$like     = '%' . $wpdb->esc_like( $string ) . '%';
299
-
300
-		foreach ( array_keys( GetPaid_Customer_Data_Store::get_database_fields() ) as $col ) {
301
-			if ( 'id' === $col || 'user_id' === $col ) {
302
-				$searches[] = $wpdb->prepare( "$col = %s", $string );  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
303
-			} else {
304
-				$searches[] = $wpdb->prepare( "$col LIKE %s", $like );  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
305
-			}
306
-		}
307
-
308
-		return ' AND (' . implode( ' OR ', $searches ) . ')';
309
-	}
310
-
311
-	/**
312
-	 * Prepares the query order.
313
-	 *
314
-	 * @since 1.0.19
315
-	 *
316
-	 * @param array $qv Query vars.
317
-	 * @param string $table Table name.
318
-	 */
319
-	protected function prepare_query_order( &$qv, $table ) {
320
-
321
-		// sorting.
322
-		$qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : '';
323
-		$order       = $this->parse_order( $qv['order'] );
324
-
325
-		// Default order is by 'id' (latest customers).
326
-		if ( empty( $qv['orderby'] ) ) {
327
-			$qv['orderby'] = array( 'id' );
328
-		}
329
-
330
-		// 'orderby' values may be an array, comma- or space-separated list.
331
-		$ordersby      = array_filter( wpinv_parse_list( $qv['orderby'] ) );
332
-
333
-		$orderby_array = array();
334
-		foreach ( $ordersby as $_key => $_value ) {
335
-
336
-			if ( is_int( $_key ) ) {
337
-				// Integer key means this is a flat array of 'orderby' fields.
338
-				$_orderby = $_value;
339
-				$_order   = $order;
340
-			} else {
341
-				// Non-integer key means that the key is the field and the value is ASC/DESC.
342
-				$_orderby = $_key;
343
-				$_order   = $_value;
344
-			}
345
-
346
-			$parsed = $this->parse_orderby( $_orderby, $table );
347
-
348
-			if ( $parsed ) {
349
-				$orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
350
-			}
351
-		}
352
-
353
-		// If no valid clauses were found, order by id.
354
-		if ( empty( $orderby_array ) ) {
355
-			$orderby_array[] = "id $order";
356
-		}
357
-
358
-		$this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array );
359
-
360
-	}
361
-
362
-	/**
363
-	 * Execute the query, with the current variables.
364
-	 *
365
-	 * @since 1.0.19
366
-	 *
367
-	 * @global wpdb $wpdb WordPress database abstraction object.
368
-	 */
369
-	public function query() {
370
-		global $wpdb;
371
-
372
-		$qv =& $this->query_vars;
373
-
374
-		// Return a non-null value to bypass the default GetPaid customers query and remember to set the
375
-		// total_customers property.
376
-		$this->results = apply_filters_ref_array( 'getpaid_customers_pre_query', array( null, &$this ) );
377
-
378
-		if ( null === $this->results ) {
379
-			$this->request = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit";
380
-
381
-			if ( ( is_array( $qv['fields'] ) && 1 !== count( $qv['fields'] ) ) || 'all' === $qv['fields'] ) {
382
-				$this->results = $wpdb->get_results( $this->request );
383
-			} else {
384
-				$this->results = $wpdb->get_col( $this->request );
385
-			}
386
-
387
-			if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
388
-				$found_customers_query = apply_filters( 'getpaid_found_customers_query', 'SELECT FOUND_ROWS()', $this );
389
-				$this->total_customers = (int) $wpdb->get_var( $found_customers_query );
390
-			}
391
-		}
392
-
393
-		if ( 'all' === $qv['fields'] ) {
394
-			foreach ( $this->results as $key => $customer ) {
395
-				$this->set_cache( $customer->id, $customer, 'getpaid_customers' );
396
-				$this->set_cache( $customer->user_id, $customer->id, 'getpaid_customer_ids_by_user_id' );
397
-				$this->set_cache( $customer->email, $customer->id, 'getpaid_customer_ids_by_email' );
398
-				$this->results[ $key ] = new GetPaid_Customer( $customer );
399
-			}
400
-		}
401
-
402
-	}
403
-
404
-	/**
405
-	 * Set cache
406
-	 *
407
-	 * @param string  $id
408
-	 * @param mixed   $data
409
-	 * @param string  $group
410
-	 * @param integer $expire
411
-	 * @return boolean
412
-	 */
413
-	public function set_cache( $key, $data, $group = '', $expire = 0 ) {
414
-
415
-		if ( empty( $key ) ) {
416
-			return false;
417
-		}
418
-
419
-		wp_cache_set( $key, $data, $group, $expire );
420
-	}
421
-
422
-	/**
423
-	 * Retrieve query variable.
424
-	 *
425
-	 * @since 1.0.19
426
-	 *
427
-	 * @param string $query_var Query variable key.
428
-	 * @return mixed
429
-	 */
430
-	public function get( $query_var ) {
431
-		if ( isset( $this->query_vars[ $query_var ] ) ) {
432
-			return $this->query_vars[ $query_var ];
433
-		}
434
-
435
-		return null;
436
-	}
437
-
438
-	/**
439
-	 * Set query variable.
440
-	 *
441
-	 * @since 1.0.19
442
-	 *
443
-	 * @param string $query_var Query variable key.
444
-	 * @param mixed $value Query variable value.
445
-	 */
446
-	public function set( $query_var, $value ) {
447
-		$this->query_vars[ $query_var ] = $value;
448
-	}
449
-
450
-	/**
451
-	 * Return the list of customers.
452
-	 *
453
-	 * @since 1.0.19
454
-	 *
455
-	 * @return GetPaid_Customer[]|array Found customers.
456
-	 */
457
-	public function get_results() {
458
-		return $this->results;
459
-	}
460
-
461
-	/**
462
-	 * Return the total number of customers for the current query.
463
-	 *
464
-	 * @since 1.0.19
465
-	 *
466
-	 * @return int Number of total customers.
467
-	 */
468
-	public function get_total() {
469
-		return $this->total_customers;
470
-	}
471
-
472
-	/**
473
-	 * Parse and sanitize 'orderby' keys passed to the customers query.
474
-	 *
475
-	 * @since 1.0.19
476
-	 *
477
-	 * @param string $orderby Alias for the field to order by.
478
-	 *  @param string $table The current table.
479
-	 * @return string Value to use in the ORDER clause, if `$orderby` is valid.
480
-	 */
481
-	protected function parse_orderby( $orderby, $table ) {
482
-
483
-		$_orderby = '';
484
-		if ( in_array( $orderby, array_keys( GetPaid_Customer_Data_Store::get_database_fields() ), true ) ) {
485
-			$_orderby = "$table.`$orderby`";
486
-		} elseif ( 'id' === strtolower( $orderby ) ) {
487
-			$_orderby = "$table.id";
488
-		} elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) {
489
-			$include     = wp_parse_id_list( $this->query_vars['include'] );
490
-			$include_sql = implode( ',', $include );
491
-			$_orderby    = "FIELD( $table.id, $include_sql )";
492
-		}
493
-
494
-		return $_orderby;
495
-	}
496
-
497
-	/**
498
-	 * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
499
-	 *
500
-	 * @since 1.0.19
501
-	 *
502
-	 * @param string $order The 'order' query variable.
503
-	 * @return string The sanitized 'order' query variable.
504
-	 */
505
-	protected function parse_order( $order ) {
506
-		if ( ! is_string( $order ) || empty( $order ) ) {
507
-			return 'DESC';
508
-		}
509
-
510
-		if ( 'ASC' === strtoupper( $order ) ) {
511
-			return 'ASC';
512
-		} else {
513
-			return 'DESC';
514
-		}
515
-	}
19
+    /**
20
+     * Query vars, after parsing
21
+     *
22
+     * @since 1.0.19
23
+     * @var array
24
+     */
25
+    public $query_vars = array();
26
+
27
+    /**
28
+     * List of found customers.
29
+     *
30
+     * @since 1.0.19
31
+     * @var array
32
+     */
33
+    private $results;
34
+
35
+    /**
36
+     * Total number of found customers for the current query
37
+     *
38
+     * @since 1.0.19
39
+     * @var int
40
+     */
41
+    private $total_customers = 0;
42
+
43
+    /**
44
+     * The SQL query used to fetch matching customers.
45
+     *
46
+     * @since 1.0.19
47
+     * @var string
48
+     */
49
+    public $request;
50
+
51
+    // SQL clauses
52
+
53
+    /**
54
+     * Contains the 'FIELDS' sql clause
55
+     *
56
+     * @since 1.0.19
57
+     * @var string
58
+     */
59
+    public $query_fields;
60
+
61
+    /**
62
+     * Contains the 'FROM' sql clause
63
+     *
64
+     * @since 1.0.19
65
+     * @var string
66
+     */
67
+    public $query_from;
68
+
69
+    /**
70
+     * Contains the 'WHERE' sql clause
71
+     *
72
+     * @since 1.0.19
73
+     * @var string
74
+     */
75
+    public $query_where;
76
+
77
+    /**
78
+     * Contains the 'ORDER BY' sql clause
79
+     *
80
+     * @since 1.0.19
81
+     * @var string
82
+     */
83
+    public $query_orderby;
84
+
85
+    /**
86
+     * Contains the 'LIMIT' sql clause
87
+     *
88
+     * @since 1.0.19
89
+     * @var string
90
+     */
91
+    public $query_limit;
92
+
93
+    /**
94
+     * Class constructor.
95
+     *
96
+     * @since 1.0.19
97
+     *
98
+     * @param null|string|array $query Optional. The query variables.
99
+     */
100
+    public function __construct( $query = null ) {
101
+        if ( ! is_null( $query ) ) {
102
+            $this->prepare_query( $query );
103
+            $this->query();
104
+        }
105
+    }
106
+
107
+    /**
108
+     * Fills in missing query variables with default values.
109
+     *
110
+     * @since 1.0.19
111
+     *
112
+     * @param  string|array $args Query vars, as passed to `GetPaid_Subscriptions_Query`.
113
+     * @return array Complete query variables with undefined ones filled in with defaults.
114
+     */
115
+    public static function fill_query_vars( $args ) {
116
+        $defaults = array(
117
+            'include'     => array(),
118
+            'exclude'     => array(),
119
+            'orderby'     => 'id',
120
+            'order'       => 'DESC',
121
+            'offset'      => '',
122
+            'number'      => 10,
123
+            'paged'       => 1,
124
+            'count_total' => true,
125
+            'fields'      => 'all',
126
+            's'           => '',
127
+        );
128
+
129
+        foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
130
+            $defaults[ $field ] = 'any';
131
+
132
+            if ( '%f' === $type || '%d' === $type ) {
133
+                $defaults[ $field . '_min' ] = '';
134
+                $defaults[ $field . '_max' ] = '';
135
+            }
136
+        }
137
+
138
+        return wp_parse_args( $args, $defaults );
139
+    }
140
+
141
+    /**
142
+     * Prepare the query variables.
143
+     *
144
+     * @since 1.0.19
145
+     *
146
+     * @see self::fill_query_vars() For allowede args and their defaults.
147
+     */
148
+    public function prepare_query( $query = array() ) {
149
+        global $wpdb;
150
+
151
+        if ( empty( $this->query_vars ) || ! empty( $query ) ) {
152
+            $this->query_limit = null;
153
+            $this->query_vars  = $this->fill_query_vars( $query );
154
+        }
155
+
156
+        if ( ! empty( $this->query_vars['fields'] ) && 'all' !== $this->query_vars['fields'] ) {
157
+            $this->query_vars['fields'] = wpinv_parse_list( $this->query_vars['fields'] );
158
+        }
159
+
160
+        do_action( 'getpaid_pre_get_customers', array( &$this ) );
161
+
162
+        // Ensure that query vars are filled after 'getpaid_pre_get_customers'.
163
+        $qv                = & $this->query_vars;
164
+        $qv                = $this->fill_query_vars( $qv );
165
+        $table             = $wpdb->prefix . 'getpaid_customers';
166
+        $this->query_from  = "FROM $table";
167
+
168
+        // Prepare query fields.
169
+        $this->prepare_query_fields( $qv, $table );
170
+
171
+        // Prepare query where.
172
+        $this->prepare_query_where( $qv, $table );
173
+
174
+        // Prepare query order.
175
+        $this->prepare_query_order( $qv, $table );
176
+
177
+        // limit
178
+        if ( isset( $qv['number'] ) && $qv['number'] > 0 ) {
179
+            if ( $qv['offset'] ) {
180
+                $this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $qv['offset'], $qv['number'] );
181
+            } else {
182
+                $this->query_limit = $wpdb->prepare( 'LIMIT %d, %d', $qv['number'] * ( $qv['paged'] - 1 ), $qv['number'] );
183
+            }
184
+        }
185
+
186
+        do_action_ref_array( 'getpaid_after_customers_query', array( &$this ) );
187
+    }
188
+
189
+    /**
190
+     * Prepares the query fields.
191
+     *
192
+     * @since 1.0.19
193
+     *
194
+     * @param array $qv Query vars.
195
+     * @param string $table Table name.
196
+     */
197
+    protected function prepare_query_fields( &$qv, $table ) {
198
+
199
+        if ( is_array( $qv['fields'] ) ) {
200
+            $qv['fields']   = array_unique( $qv['fields'] );
201
+            $allowed_fields = array_keys( GetPaid_Customer_Data_Store::get_database_fields() );
202
+
203
+            $query_fields = array();
204
+            foreach ( $qv['fields'] as $field ) {
205
+                if ( ! in_array( $field, $allowed_fields ) ) {
206
+                    continue;
207
+                }
208
+
209
+                $field          = sanitize_key( $field );
210
+                $query_fields[] = "$table.`$field`";
211
+            }
212
+            $this->query_fields = implode( ',', $query_fields );
213
+        } else {
214
+            $this->query_fields = "$table.*";
215
+        }
216
+
217
+        if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
218
+            $this->query_fields = 'SQL_CALC_FOUND_ROWS ' . $this->query_fields;
219
+        }
220
+
221
+    }
222
+
223
+    /**
224
+     * Prepares the query where.
225
+     *
226
+     * @since 1.0.19
227
+     *
228
+     * @param array $qv Query vars.
229
+     * @param string $table Table name.
230
+     */
231
+    protected function prepare_query_where( &$qv, $table ) {
232
+        global $wpdb;
233
+        $this->query_where = 'WHERE 1=1';
234
+
235
+        // Fields.
236
+        foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
237
+            if ( 'any' !== $qv[ $field ] ) {
238
+
239
+                // In.
240
+                if ( is_array( $qv[ $field ] ) ) {
241
+                    $in                 = join( ',', array_fill( 0, count( $qv[ $field ] ), $type ) );
242
+                    $this->query_where .= $wpdb->prepare( " AND $table.`status` IN ( $in )", $qv[ $field ] );
243
+                } elseif ( ! empty( $qv[ $field ] ) ) {
244
+                    $this->query_where .= $wpdb->prepare( " AND $table.`$field` = $type", $qv[ $field ] );
245
+                }
246
+            }
247
+
248
+            // Min/Max.
249
+            if ( '%f' === $type || '%d' === $type ) {
250
+
251
+                // Min.
252
+                if ( is_numeric( $qv[ $field . '_min' ] ) ) {
253
+                    $this->query_where .= $wpdb->prepare( " AND $table.`$field` >= $type", $qv[ $field . '_min' ] );
254
+                }
255
+
256
+                // Max.
257
+                if ( is_numeric( $qv[ $field . '_max' ] ) ) {
258
+                    $this->query_where .= $wpdb->prepare( " AND $table.`$field` <= $type", $qv[ $field . '_max' ] );
259
+                }
260
+            }
261
+        }
262
+
263
+        if ( ! empty( $qv['include'] ) ) {
264
+            $include            = implode( ',', wp_parse_id_list( $qv['include'] ) );
265
+            $this->query_where .= " AND $table.`id` IN ($include)";
266
+        } elseif ( ! empty( $qv['exclude'] ) ) {
267
+            $exclude            = implode( ',', wp_parse_id_list( $qv['exclude'] ) );
268
+            $this->query_where .= " AND $table.`id` NOT IN ($exclude)";
269
+        }
270
+
271
+        // Date queries are allowed for the customer creation date.
272
+        if ( ! empty( $qv['date_created_query'] ) && is_array( $qv['date_created_query'] ) ) {
273
+            $date_created_query = new WP_Date_Query( $qv['date_created_query'], "$table.date_created" );
274
+            $this->query_where .= $date_created_query->get_sql();
275
+        }
276
+
277
+        // Search.
278
+        if ( ! empty( $qv['s'] ) ) {
279
+            $this->query_where .= $this->get_search_sql( $qv['s'] );
280
+        }
281
+    }
282
+
283
+    /**
284
+     * Used internally to generate an SQL string for searching across multiple columns
285
+     *
286
+     * @since 1.2.7
287
+     *
288
+     * @global wpdb $wpdb WordPress database abstraction object.
289
+     *
290
+     * @param string $string The string to search for.
291
+     * @return string
292
+     */
293
+    protected function get_search_sql( $string ) {
294
+        global $wpdb;
295
+
296
+        $searches = array();
297
+        $string   = trim( $string, '%' );
298
+        $like     = '%' . $wpdb->esc_like( $string ) . '%';
299
+
300
+        foreach ( array_keys( GetPaid_Customer_Data_Store::get_database_fields() ) as $col ) {
301
+            if ( 'id' === $col || 'user_id' === $col ) {
302
+                $searches[] = $wpdb->prepare( "$col = %s", $string );  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
303
+            } else {
304
+                $searches[] = $wpdb->prepare( "$col LIKE %s", $like );  // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
305
+            }
306
+        }
307
+
308
+        return ' AND (' . implode( ' OR ', $searches ) . ')';
309
+    }
310
+
311
+    /**
312
+     * Prepares the query order.
313
+     *
314
+     * @since 1.0.19
315
+     *
316
+     * @param array $qv Query vars.
317
+     * @param string $table Table name.
318
+     */
319
+    protected function prepare_query_order( &$qv, $table ) {
320
+
321
+        // sorting.
322
+        $qv['order'] = isset( $qv['order'] ) ? strtoupper( $qv['order'] ) : '';
323
+        $order       = $this->parse_order( $qv['order'] );
324
+
325
+        // Default order is by 'id' (latest customers).
326
+        if ( empty( $qv['orderby'] ) ) {
327
+            $qv['orderby'] = array( 'id' );
328
+        }
329
+
330
+        // 'orderby' values may be an array, comma- or space-separated list.
331
+        $ordersby      = array_filter( wpinv_parse_list( $qv['orderby'] ) );
332
+
333
+        $orderby_array = array();
334
+        foreach ( $ordersby as $_key => $_value ) {
335
+
336
+            if ( is_int( $_key ) ) {
337
+                // Integer key means this is a flat array of 'orderby' fields.
338
+                $_orderby = $_value;
339
+                $_order   = $order;
340
+            } else {
341
+                // Non-integer key means that the key is the field and the value is ASC/DESC.
342
+                $_orderby = $_key;
343
+                $_order   = $_value;
344
+            }
345
+
346
+            $parsed = $this->parse_orderby( $_orderby, $table );
347
+
348
+            if ( $parsed ) {
349
+                $orderby_array[] = $parsed . ' ' . $this->parse_order( $_order );
350
+            }
351
+        }
352
+
353
+        // If no valid clauses were found, order by id.
354
+        if ( empty( $orderby_array ) ) {
355
+            $orderby_array[] = "id $order";
356
+        }
357
+
358
+        $this->query_orderby = 'ORDER BY ' . implode( ', ', $orderby_array );
359
+
360
+    }
361
+
362
+    /**
363
+     * Execute the query, with the current variables.
364
+     *
365
+     * @since 1.0.19
366
+     *
367
+     * @global wpdb $wpdb WordPress database abstraction object.
368
+     */
369
+    public function query() {
370
+        global $wpdb;
371
+
372
+        $qv =& $this->query_vars;
373
+
374
+        // Return a non-null value to bypass the default GetPaid customers query and remember to set the
375
+        // total_customers property.
376
+        $this->results = apply_filters_ref_array( 'getpaid_customers_pre_query', array( null, &$this ) );
377
+
378
+        if ( null === $this->results ) {
379
+            $this->request = "SELECT $this->query_fields $this->query_from $this->query_where $this->query_orderby $this->query_limit";
380
+
381
+            if ( ( is_array( $qv['fields'] ) && 1 !== count( $qv['fields'] ) ) || 'all' === $qv['fields'] ) {
382
+                $this->results = $wpdb->get_results( $this->request );
383
+            } else {
384
+                $this->results = $wpdb->get_col( $this->request );
385
+            }
386
+
387
+            if ( isset( $qv['count_total'] ) && $qv['count_total'] ) {
388
+                $found_customers_query = apply_filters( 'getpaid_found_customers_query', 'SELECT FOUND_ROWS()', $this );
389
+                $this->total_customers = (int) $wpdb->get_var( $found_customers_query );
390
+            }
391
+        }
392
+
393
+        if ( 'all' === $qv['fields'] ) {
394
+            foreach ( $this->results as $key => $customer ) {
395
+                $this->set_cache( $customer->id, $customer, 'getpaid_customers' );
396
+                $this->set_cache( $customer->user_id, $customer->id, 'getpaid_customer_ids_by_user_id' );
397
+                $this->set_cache( $customer->email, $customer->id, 'getpaid_customer_ids_by_email' );
398
+                $this->results[ $key ] = new GetPaid_Customer( $customer );
399
+            }
400
+        }
401
+
402
+    }
403
+
404
+    /**
405
+     * Set cache
406
+     *
407
+     * @param string  $id
408
+     * @param mixed   $data
409
+     * @param string  $group
410
+     * @param integer $expire
411
+     * @return boolean
412
+     */
413
+    public function set_cache( $key, $data, $group = '', $expire = 0 ) {
414
+
415
+        if ( empty( $key ) ) {
416
+            return false;
417
+        }
418
+
419
+        wp_cache_set( $key, $data, $group, $expire );
420
+    }
421
+
422
+    /**
423
+     * Retrieve query variable.
424
+     *
425
+     * @since 1.0.19
426
+     *
427
+     * @param string $query_var Query variable key.
428
+     * @return mixed
429
+     */
430
+    public function get( $query_var ) {
431
+        if ( isset( $this->query_vars[ $query_var ] ) ) {
432
+            return $this->query_vars[ $query_var ];
433
+        }
434
+
435
+        return null;
436
+    }
437
+
438
+    /**
439
+     * Set query variable.
440
+     *
441
+     * @since 1.0.19
442
+     *
443
+     * @param string $query_var Query variable key.
444
+     * @param mixed $value Query variable value.
445
+     */
446
+    public function set( $query_var, $value ) {
447
+        $this->query_vars[ $query_var ] = $value;
448
+    }
449
+
450
+    /**
451
+     * Return the list of customers.
452
+     *
453
+     * @since 1.0.19
454
+     *
455
+     * @return GetPaid_Customer[]|array Found customers.
456
+     */
457
+    public function get_results() {
458
+        return $this->results;
459
+    }
460
+
461
+    /**
462
+     * Return the total number of customers for the current query.
463
+     *
464
+     * @since 1.0.19
465
+     *
466
+     * @return int Number of total customers.
467
+     */
468
+    public function get_total() {
469
+        return $this->total_customers;
470
+    }
471
+
472
+    /**
473
+     * Parse and sanitize 'orderby' keys passed to the customers query.
474
+     *
475
+     * @since 1.0.19
476
+     *
477
+     * @param string $orderby Alias for the field to order by.
478
+     *  @param string $table The current table.
479
+     * @return string Value to use in the ORDER clause, if `$orderby` is valid.
480
+     */
481
+    protected function parse_orderby( $orderby, $table ) {
482
+
483
+        $_orderby = '';
484
+        if ( in_array( $orderby, array_keys( GetPaid_Customer_Data_Store::get_database_fields() ), true ) ) {
485
+            $_orderby = "$table.`$orderby`";
486
+        } elseif ( 'id' === strtolower( $orderby ) ) {
487
+            $_orderby = "$table.id";
488
+        } elseif ( 'include' === $orderby && ! empty( $this->query_vars['include'] ) ) {
489
+            $include     = wp_parse_id_list( $this->query_vars['include'] );
490
+            $include_sql = implode( ',', $include );
491
+            $_orderby    = "FIELD( $table.id, $include_sql )";
492
+        }
493
+
494
+        return $_orderby;
495
+    }
496
+
497
+    /**
498
+     * Parse an 'order' query variable and cast it to ASC or DESC as necessary.
499
+     *
500
+     * @since 1.0.19
501
+     *
502
+     * @param string $order The 'order' query variable.
503
+     * @return string The sanitized 'order' query variable.
504
+     */
505
+    protected function parse_order( $order ) {
506
+        if ( ! is_string( $order ) || empty( $order ) ) {
507
+            return 'DESC';
508
+        }
509
+
510
+        if ( 'ASC' === strtoupper( $order ) ) {
511
+            return 'ASC';
512
+        } else {
513
+            return 'DESC';
514
+        }
515
+    }
516 516
 
517 517
 }
Please login to merge, or discard this patch.
includes/admin/class-wpinv-customers-table.php 1 patch
Indentation   +296 added lines, -296 removed lines patch added patch discarded remove patch
@@ -11,7 +11,7 @@  discard block
 block discarded – undo
11 11
 
12 12
 // Load WP_List_Table if not loaded
13 13
 if ( ! class_exists( 'WP_List_Table' ) ) {
14
-	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
14
+    require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
15 15
 }
16 16
 
17 17
 /**
@@ -23,303 +23,303 @@  discard block
 block discarded – undo
23 23
  */
24 24
 class WPInv_Customers_Table extends WP_List_Table {
25 25
 
26
-	/**
27
-	 * @var int Number of items per page
28
-	 * @since 1.0.19
29
-	 */
30
-	public $per_page = 25;
31
-
32
-	/**
33
-	 * @var int Number of items
34
-	 * @since 1.0.19
35
-	 */
36
-	public $total_count = 0;
37
-
38
-	public $query;
39
-
40
-	/**
41
-	 * Get things started
42
-	 *
43
-	 * @since 1.0.19
44
-	 * @see WP_List_Table::__construct()
45
-	 */
46
-	public function __construct() {
47
-
48
-		// Set parent defaults
49
-		parent::__construct(
26
+    /**
27
+     * @var int Number of items per page
28
+     * @since 1.0.19
29
+     */
30
+    public $per_page = 25;
31
+
32
+    /**
33
+     * @var int Number of items
34
+     * @since 1.0.19
35
+     */
36
+    public $total_count = 0;
37
+
38
+    public $query;
39
+
40
+    /**
41
+     * Get things started
42
+     *
43
+     * @since 1.0.19
44
+     * @see WP_List_Table::__construct()
45
+     */
46
+    public function __construct() {
47
+
48
+        // Set parent defaults
49
+        parent::__construct(
50 50
             array(
51
-				'singular' => 'id',
52
-				'plural'   => 'ids',
53
-				'ajax'     => false,
51
+                'singular' => 'id',
52
+                'plural'   => 'ids',
53
+                'ajax'     => false,
54 54
             )
55 55
         );
56 56
 
57
-	}
58
-
59
-	/**
60
-	 * Gets the name of the primary column.
61
-	 *
62
-	 * @since 1.0.19
63
-	 * @access protected
64
-	 *
65
-	 * @return string Name of the primary column.
66
-	 */
67
-	protected function get_primary_column_name() {
68
-		return 'customer';
69
-	}
70
-
71
-	/**
72
-	 * This function renders most of the columns in the list table.
73
-	 *
74
-	 * @since 1.0.19
75
-	 *
76
-	 * @param GetPaid_Customer $customer
77
-	 * @param string $column_name The name of the column
78
-	 *
79
-	 * @return string Column Name
80
-	 */
81
-	public function column_default( $customer, $column_name ) {
82
-		$value = esc_html( $customer->get( $column_name ) );
83
-		return apply_filters( 'wpinv_customers_table_column' . $column_name, $value, $customer );
84
-	}
85
-
86
-	/**
87
-	 * Displays the country column.
88
-	 *
89
-	 * @since 1.0.19
90
-	 *
91
-	 * @param GetPaid_Customer $customer
92
-	 *
93
-	 * @return string Column Name
94
-	 */
95
-	public function column_country( $customer ) {
96
-		$country = wpinv_sanitize_country( $customer->get( 'country' ) );
97
-		if ( $country ) {
98
-			$country = wpinv_country_name( $country );
99
-		}
100
-		return esc_html( $country );
101
-	}
102
-
103
-	/**
104
-	 * Displays the state column.
105
-	 *
106
-	 * @since 1.0.19
107
-	 *
108
-	 * @param GetPaid_Customer $customer
109
-	 *
110
-	 * @return string Column Name
111
-	 */
112
-	public function column_state( $customer ) {
113
-		$country = wpinv_sanitize_country( $customer->get( 'country' ) );
114
-		$state   = $customer->get( 'state' );
115
-		if ( $state ) {
116
-			$state = wpinv_state_name( $state, $country );
117
-		}
118
-
119
-		return esc_html( $state );
120
-	}
121
-
122
-	/**
123
-	 * Displays the signup column.
124
-	 *
125
-	 * @since 1.0.19
126
-	 *
127
-	 * @param GetPaid_Customer $customer
128
-	 *
129
-	 * @return string Column Name
130
-	 */
131
-	public function column_date_created( $customer ) {
132
-		return getpaid_format_date_value( $customer->get( 'date_created' ) );
133
-	}
134
-
135
-	/**
136
-	 * Displays the total spent column.
137
-	 *
138
-	 * @since 1.0.19
139
-	 *
140
-	 * @param GetPaid_Customer $customer
141
-	 *
142
-	 * @return string Column Name
143
-	 */
144
-	public function column_purchase_value( $customer ) {
145
-		return wpinv_price( (float) $customer->get( 'purchase_value' ) );
146
-	}
147
-
148
-	/**
149
-	 * Displays the total spent column.
150
-	 *
151
-	 * @since 1.0.19
152
-	 *
153
-	 * @param GetPaid_Customer $customer
154
-	 *
155
-	 * @return string Column Name
156
-	 */
157
-	public function column_purchase_count( $customer ) {
158
-		$value = $customer->get( 'purchase_count' );
159
-		$url   = $customer->get( 'user_id' ) ? add_query_arg( array( 'post_type' => 'wpi_invoice', 'author' => $customer->get( 'user_id' ), ), admin_url( 'edit.php' ) ) : '';
160
-
161
-		return ( empty( $value ) || empty( $url ) ) ? (int) $value : '<a href="' . esc_url( $url ) . '">' . absint( $value ) . '</a>';
162
-
163
-	}
164
-
165
-	/**
166
-	 * Displays the customers name
167
-	 *
168
-	 * @param  GetPaid_Customer $customer customer.
169
-	 * @return string
170
-	 */
171
-	public function column_customer( $customer ) {
172
-
173
-		$first_name = $customer->get( 'first_name' );
174
-		$last_name  = $customer->get( 'last_name' );
175
-		$email      = $customer->get( 'email' );
176
-		$avatar     = get_avatar( $customer->get( 'user_id' ) ? $customer->get( 'user_id' ) : $email, 32 );
177
-
178
-		// Customer view URL.
179
-		$view_url    = $customer->get( 'user_id' ) ? esc_url( add_query_arg( 'user_id', $customer->get( 'user_id' ), admin_url( 'user-edit.php' ) ) ) : false;
180
-		$row_actions = $view_url ? $this->row_actions(
181
-			array(
182
-				'view' => '<a href="' . $view_url . '#getpaid-fieldset-billing">' . __( 'Edit Details', 'invoicing' ) . '</a>',
183
-			)
184
-		) : '';
185
-
186
-		// Customer's name.
187
-		$name   = esc_html( trim( "$first_name $last_name" ) );
188
-
189
-		if ( ! empty( $name ) ) {
190
-			$name = "<div style='overflow: hidden;height: 18px;'>$name</div>";
191
-		}
192
-
193
-		$email = "<div class='row-title'><a href='mailto:$email'>$email</a></div>";
194
-
195
-		return "<div style='display: flex;'><div>$avatar</div><div style='margin-left: 10px;'>$name<strong>$email</strong>$row_actions</div></div>";
196
-
197
-	}
198
-
199
-	/**
200
-	 * Retrieve the current page number
201
-	 *
202
-	 * @since 1.0.19
203
-	 * @return int Current page number
204
-	 */
205
-	public function get_paged() {
206
-		return isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1;
207
-	}
208
-
209
-	/**
210
-	 * Returns bulk actions.
211
-	 *
212
-	 * @since 1.0.19
213
-	 * @return void
214
-	 */
215
-	public function bulk_actions( $which = '' ) {
216
-		return array();
217
-	}
218
-
219
-	/**
220
-	 *  Prepares the display query
221
-	 */
222
-	public function prepare_query() {
223
-
224
-		// Prepare query args.
225
-		$query = array(
226
-			'number' => $this->per_page,
227
-			'paged'  => $this->get_paged(),
228
-		);
229
-
230
-		foreach ( array( 'orderby', 'order', 's' ) as $field ) {
231
-			if ( isset( $_GET[ $field ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
232
-				$query[ $field ] = wpinv_clean( rawurlencode_deep( $_GET[ $field ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
233
-			}
234
-		}
235
-
236
-		foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
237
-
238
-			if ( isset( $_GET[ $field ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
239
-				$query[ $field ] = wpinv_clean( rawurlencode_deep( $_GET[ $field ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
240
-			}
241
-
242
-			// Min max.
243
-			if ( '%f' === $type || '%d' === $type ) {
244
-
245
-				if ( isset( $_GET[ $field . '_min' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
246
-					$query[ $field . '_min' ] = floatval( $_GET[ $field . '_min' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
247
-				}
248
-
249
-				if ( isset( $_GET[ $field . '_max' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
250
-					$query[ $field . '_max' ] = floatval( $_GET[ $field . '_max' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
251
-				}
252
-			}
253
-		}
254
-
255
-		// Prepare class properties.
256
-		$this->query       = getpaid_get_customers( $query, 'query' );
257
-		$this->total_count = $this->query->get_total();
258
-		$this->items       = $this->query->get_results();
259
-	}
260
-
261
-	/**
262
-	 * Setup the final data for the table
263
-	 *
264
-	 */
265
-	public function prepare_items() {
266
-
267
-		$columns  = $this->get_columns();
268
-		$hidden   = array();
269
-		$sortable = $this->get_sortable_columns();
270
-		$this->prepare_query();
271
-
272
-		$this->_column_headers = array( $columns, $hidden, $sortable );
273
-
274
-		$this->set_pagination_args(
275
-			array(
276
-				'total_items' => $this->total_count,
277
-				'per_page'    => $this->per_page,
278
-				'total_pages' => ceil( $this->total_count / $this->per_page ),
279
-			)
280
-		);
281
-	}
282
-
283
-	/**
284
-	 * Sortable table columns.
285
-	 *
286
-	 * @return array
287
-	 */
288
-	public function get_sortable_columns() {
289
-		$sortable = array(
290
-			'customer' => array( 'first_name', true ),
291
-		);
292
-
293
-		foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
294
-			$sortable[ $field ] = array( $field, true );
295
-		}
296
-
297
-		return apply_filters( 'manage_getpaid_customers_sortable_table_columns', $sortable );
298
-	}
299
-
300
-	/**
301
-	 * Table columns
302
-	 *
303
-	 * @return array
304
-	 */
305
-	public function get_columns() {
306
-		$columns = array(
307
-			'customer' => __( 'Customer', 'invoicing' ),
308
-		);
309
-
310
-		// Add address fields.
311
-		foreach ( getpaid_user_address_fields() as $key => $value ) {
312
-
313
-			// Skip id, user_id and email.
314
-			if ( ! in_array( $key, array( 'id', 'user_id', 'email', 'purchase_value', 'purchase_count', 'date_created', 'date_modified', 'uuid', 'first_name', 'last_name' ), true ) ) {
315
-				$columns[ $key ] = $value;
316
-			}
317
-		}
318
-
319
-		$columns['purchase_value'] = __( 'Total Spend', 'invoicing' );
320
-		$columns['purchase_count'] = __( 'Invoices', 'invoicing' );
321
-		$columns['date_created']   = __( 'Date created', 'invoicing' );
322
-
323
-		return apply_filters( 'manage_getpaid_customers_table_columns', $columns );
324
-	}
57
+    }
58
+
59
+    /**
60
+     * Gets the name of the primary column.
61
+     *
62
+     * @since 1.0.19
63
+     * @access protected
64
+     *
65
+     * @return string Name of the primary column.
66
+     */
67
+    protected function get_primary_column_name() {
68
+        return 'customer';
69
+    }
70
+
71
+    /**
72
+     * This function renders most of the columns in the list table.
73
+     *
74
+     * @since 1.0.19
75
+     *
76
+     * @param GetPaid_Customer $customer
77
+     * @param string $column_name The name of the column
78
+     *
79
+     * @return string Column Name
80
+     */
81
+    public function column_default( $customer, $column_name ) {
82
+        $value = esc_html( $customer->get( $column_name ) );
83
+        return apply_filters( 'wpinv_customers_table_column' . $column_name, $value, $customer );
84
+    }
85
+
86
+    /**
87
+     * Displays the country column.
88
+     *
89
+     * @since 1.0.19
90
+     *
91
+     * @param GetPaid_Customer $customer
92
+     *
93
+     * @return string Column Name
94
+     */
95
+    public function column_country( $customer ) {
96
+        $country = wpinv_sanitize_country( $customer->get( 'country' ) );
97
+        if ( $country ) {
98
+            $country = wpinv_country_name( $country );
99
+        }
100
+        return esc_html( $country );
101
+    }
102
+
103
+    /**
104
+     * Displays the state column.
105
+     *
106
+     * @since 1.0.19
107
+     *
108
+     * @param GetPaid_Customer $customer
109
+     *
110
+     * @return string Column Name
111
+     */
112
+    public function column_state( $customer ) {
113
+        $country = wpinv_sanitize_country( $customer->get( 'country' ) );
114
+        $state   = $customer->get( 'state' );
115
+        if ( $state ) {
116
+            $state = wpinv_state_name( $state, $country );
117
+        }
118
+
119
+        return esc_html( $state );
120
+    }
121
+
122
+    /**
123
+     * Displays the signup column.
124
+     *
125
+     * @since 1.0.19
126
+     *
127
+     * @param GetPaid_Customer $customer
128
+     *
129
+     * @return string Column Name
130
+     */
131
+    public function column_date_created( $customer ) {
132
+        return getpaid_format_date_value( $customer->get( 'date_created' ) );
133
+    }
134
+
135
+    /**
136
+     * Displays the total spent column.
137
+     *
138
+     * @since 1.0.19
139
+     *
140
+     * @param GetPaid_Customer $customer
141
+     *
142
+     * @return string Column Name
143
+     */
144
+    public function column_purchase_value( $customer ) {
145
+        return wpinv_price( (float) $customer->get( 'purchase_value' ) );
146
+    }
147
+
148
+    /**
149
+     * Displays the total spent column.
150
+     *
151
+     * @since 1.0.19
152
+     *
153
+     * @param GetPaid_Customer $customer
154
+     *
155
+     * @return string Column Name
156
+     */
157
+    public function column_purchase_count( $customer ) {
158
+        $value = $customer->get( 'purchase_count' );
159
+        $url   = $customer->get( 'user_id' ) ? add_query_arg( array( 'post_type' => 'wpi_invoice', 'author' => $customer->get( 'user_id' ), ), admin_url( 'edit.php' ) ) : '';
160
+
161
+        return ( empty( $value ) || empty( $url ) ) ? (int) $value : '<a href="' . esc_url( $url ) . '">' . absint( $value ) . '</a>';
162
+
163
+    }
164
+
165
+    /**
166
+     * Displays the customers name
167
+     *
168
+     * @param  GetPaid_Customer $customer customer.
169
+     * @return string
170
+     */
171
+    public function column_customer( $customer ) {
172
+
173
+        $first_name = $customer->get( 'first_name' );
174
+        $last_name  = $customer->get( 'last_name' );
175
+        $email      = $customer->get( 'email' );
176
+        $avatar     = get_avatar( $customer->get( 'user_id' ) ? $customer->get( 'user_id' ) : $email, 32 );
177
+
178
+        // Customer view URL.
179
+        $view_url    = $customer->get( 'user_id' ) ? esc_url( add_query_arg( 'user_id', $customer->get( 'user_id' ), admin_url( 'user-edit.php' ) ) ) : false;
180
+        $row_actions = $view_url ? $this->row_actions(
181
+            array(
182
+                'view' => '<a href="' . $view_url . '#getpaid-fieldset-billing">' . __( 'Edit Details', 'invoicing' ) . '</a>',
183
+            )
184
+        ) : '';
185
+
186
+        // Customer's name.
187
+        $name   = esc_html( trim( "$first_name $last_name" ) );
188
+
189
+        if ( ! empty( $name ) ) {
190
+            $name = "<div style='overflow: hidden;height: 18px;'>$name</div>";
191
+        }
192
+
193
+        $email = "<div class='row-title'><a href='mailto:$email'>$email</a></div>";
194
+
195
+        return "<div style='display: flex;'><div>$avatar</div><div style='margin-left: 10px;'>$name<strong>$email</strong>$row_actions</div></div>";
196
+
197
+    }
198
+
199
+    /**
200
+     * Retrieve the current page number
201
+     *
202
+     * @since 1.0.19
203
+     * @return int Current page number
204
+     */
205
+    public function get_paged() {
206
+        return isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1;
207
+    }
208
+
209
+    /**
210
+     * Returns bulk actions.
211
+     *
212
+     * @since 1.0.19
213
+     * @return void
214
+     */
215
+    public function bulk_actions( $which = '' ) {
216
+        return array();
217
+    }
218
+
219
+    /**
220
+     *  Prepares the display query
221
+     */
222
+    public function prepare_query() {
223
+
224
+        // Prepare query args.
225
+        $query = array(
226
+            'number' => $this->per_page,
227
+            'paged'  => $this->get_paged(),
228
+        );
229
+
230
+        foreach ( array( 'orderby', 'order', 's' ) as $field ) {
231
+            if ( isset( $_GET[ $field ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
232
+                $query[ $field ] = wpinv_clean( rawurlencode_deep( $_GET[ $field ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
233
+            }
234
+        }
235
+
236
+        foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
237
+
238
+            if ( isset( $_GET[ $field ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
239
+                $query[ $field ] = wpinv_clean( rawurlencode_deep( $_GET[ $field ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
240
+            }
241
+
242
+            // Min max.
243
+            if ( '%f' === $type || '%d' === $type ) {
244
+
245
+                if ( isset( $_GET[ $field . '_min' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
246
+                    $query[ $field . '_min' ] = floatval( $_GET[ $field . '_min' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
247
+                }
248
+
249
+                if ( isset( $_GET[ $field . '_max' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
250
+                    $query[ $field . '_max' ] = floatval( $_GET[ $field . '_max' ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
251
+                }
252
+            }
253
+        }
254
+
255
+        // Prepare class properties.
256
+        $this->query       = getpaid_get_customers( $query, 'query' );
257
+        $this->total_count = $this->query->get_total();
258
+        $this->items       = $this->query->get_results();
259
+    }
260
+
261
+    /**
262
+     * Setup the final data for the table
263
+     *
264
+     */
265
+    public function prepare_items() {
266
+
267
+        $columns  = $this->get_columns();
268
+        $hidden   = array();
269
+        $sortable = $this->get_sortable_columns();
270
+        $this->prepare_query();
271
+
272
+        $this->_column_headers = array( $columns, $hidden, $sortable );
273
+
274
+        $this->set_pagination_args(
275
+            array(
276
+                'total_items' => $this->total_count,
277
+                'per_page'    => $this->per_page,
278
+                'total_pages' => ceil( $this->total_count / $this->per_page ),
279
+            )
280
+        );
281
+    }
282
+
283
+    /**
284
+     * Sortable table columns.
285
+     *
286
+     * @return array
287
+     */
288
+    public function get_sortable_columns() {
289
+        $sortable = array(
290
+            'customer' => array( 'first_name', true ),
291
+        );
292
+
293
+        foreach ( GetPaid_Customer_Data_Store::get_database_fields() as $field => $type ) {
294
+            $sortable[ $field ] = array( $field, true );
295
+        }
296
+
297
+        return apply_filters( 'manage_getpaid_customers_sortable_table_columns', $sortable );
298
+    }
299
+
300
+    /**
301
+     * Table columns
302
+     *
303
+     * @return array
304
+     */
305
+    public function get_columns() {
306
+        $columns = array(
307
+            'customer' => __( 'Customer', 'invoicing' ),
308
+        );
309
+
310
+        // Add address fields.
311
+        foreach ( getpaid_user_address_fields() as $key => $value ) {
312
+
313
+            // Skip id, user_id and email.
314
+            if ( ! in_array( $key, array( 'id', 'user_id', 'email', 'purchase_value', 'purchase_count', 'date_created', 'date_modified', 'uuid', 'first_name', 'last_name' ), true ) ) {
315
+                $columns[ $key ] = $value;
316
+            }
317
+        }
318
+
319
+        $columns['purchase_value'] = __( 'Total Spend', 'invoicing' );
320
+        $columns['purchase_count'] = __( 'Invoices', 'invoicing' );
321
+        $columns['date_created']   = __( 'Date created', 'invoicing' );
322
+
323
+        return apply_filters( 'manage_getpaid_customers_table_columns', $columns );
324
+    }
325 325
 }
Please login to merge, or discard this patch.
vendor/ayecode/ayecode-connect-helper/ayecode-connect-helper.php 1 patch
Indentation   +302 added lines, -302 removed lines patch added patch discarded remove patch
@@ -1,264 +1,264 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 if ( ! defined( 'ABSPATH' ) ) {
3
-	exit;
3
+    exit;
4 4
 }
5 5
 
6 6
 if ( ! class_exists( "AyeCode_Connect_Helper" ) ) {
7
-	/**
8
-	 * Allow the quick setup and connection of our AyeCode Connect plugin.
9
-	 *
10
-	 * Class AyeCode_Connect_Helper
11
-	 */
12
-	class AyeCode_Connect_Helper {
13
-
14
-		// Hold the version number
15
-		var $version = "1.0.4";
16
-
17
-		// Hold the default strings.
18
-		var $strings = array();
19
-
20
-		// Hold the default pages.
21
-		var $pages = array();
22
-
23
-		/**
24
-		 * The constructor.
25
-		 *
26
-		 * AyeCode_Connect_Helper constructor.
27
-		 *
28
-		 * @param array $strings
29
-		 * @param array $pages
30
-		 */
31
-		public function __construct( $strings = array(), $pages = array() ) {
32
-			// Only fire if not localhost and the current user has the right permissions.
33
-			if ( ! $this->is_localhost() && current_user_can( 'manage_options' ) ) {
34
-				// set default strings
35
-				$default_strings = array(
36
-					'connect_title'     => __( "Thanks for choosing an AyeCode Product!", 'ayecode-connect' ),
37
-					'connect_external'  => __( "Please confirm you wish to connect your site?", 'ayecode-connect' ),
38
-					'connect'           => wp_sprintf( __( "<strong>Have a license?</strong> Forget about entering license keys or downloading zip files, connect your site for instant access. %slearn more%s", 'ayecode-connect' ), "<a href='https://ayecode.io/introducing-ayecode-connect/' target='_blank'>", "</a>" ),
39
-					'connect_button'    => __( "Connect Site", 'ayecode-connect' ),
40
-					'connecting_button' => __( "Connecting...", 'ayecode-connect' ),
41
-					'error_localhost'   => __( "This service will only work with a live domain, not a localhost.", 'ayecode-connect' ),
42
-					'error'             => __( "Something went wrong, please refresh and try again.", 'ayecode-connect' ),
43
-				);
44
-				$this->strings   = array_merge( $default_strings, $strings );
45
-
46
-				// set default pages
47
-				$default_pages = array();
48
-				$this->pages   = array_merge( $default_pages, $pages );
49
-
50
-				// maybe show connect site notice
51
-				add_action( 'admin_notices', array( $this, 'ayecode_connect_install_notice' ) );
52
-
53
-				// add ajax action if not already added
54
-				if ( ! has_action( 'wp_ajax_ayecode_connect_helper' ) ) {
55
-					add_action( 'wp_ajax_ayecode_connect_helper', array( $this, 'ayecode_connect_install' ) );
56
-				}
57
-			}
58
-
59
-			// add ajax action if not already added
60
-			if ( ! has_action( 'wp_ajax_nopriv_ayecode_connect_helper_installed' ) ) {
61
-				add_action( 'wp_ajax_nopriv_ayecode_connect_helper_installed', array( $this, 'ayecode_connect_helper_installed' ) );
62
-			}
63
-		}
64
-
65
-		/**
66
-		 * Give a way to check we can connect via a external redirect.
67
-		 */
68
-		public function ayecode_connect_helper_installed(){
69
-			$active = array(
70
-				'gd'    =>  defined('GEODIRECTORY_VERSION') && version_compare(GEODIRECTORY_VERSION,'2.0.0.79','>') ? 1 : 0,
71
-				'uwp'    =>  defined('USERSWP_VERSION') && version_compare(USERSWP_VERSION,'1.2.1.5','>') ? 1 : 0,
72
-				'wpi'    =>  defined('WPINV_VERSION') && version_compare(WPINV_VERSION,'1.0.14','>') ? 1 : 0,
73
-			);
74
-			wp_send_json_success( $active );
75
-			wp_die();
76
-		}
77
-
78
-		/**
79
-		 * Get slug from path
80
-		 *
81
-		 * @param  string $key
82
-		 *
83
-		 * @return string
84
-		 */
85
-		private function format_plugin_slug( $key ) {
86
-			$slug = explode( '/', $key );
87
-			$slug = explode( '.', end( $slug ) );
88
-
89
-			return $slug[0];
90
-		}
91
-
92
-		/**
93
-		 * Install and activate the AyeCode Connect Plugin
94
-		 */
95
-		public function ayecode_connect_install() {
96
-			// bail if localhost
97
-			if ( $this->is_localhost() ) {
98
-				wp_send_json_error( $this->strings['error_localhost'] );
99
-			}
100
-
101
-			// Explicitly clear the event.
102
-			wp_clear_scheduled_hook( 'geodir_plugin_background_installer', func_get_args() );
103
-
104
-			$success     = true;
105
-			$plugin_slug = "ayecode-connect";
106
-			if ( ! empty( $plugin_slug ) ) {
107
-				require_once( ABSPATH . 'wp-admin/includes/file.php' );
108
-				require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
109
-				require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
110
-				require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
111
-
112
-				WP_Filesystem();
113
-
114
-				$skin              = new Automatic_Upgrader_Skin;
115
-				$upgrader          = new WP_Upgrader( $skin );
116
-				$installed_plugins = array_map( array( $this, 'format_plugin_slug' ), array_keys( get_plugins() ) );
117
-				$plugin_slug       = $plugin_slug;
118
-				$plugin            = $plugin_slug . '/' . $plugin_slug . '.php';
119
-				$installed         = false;
120
-				$activate          = false;
121
-
122
-				// See if the plugin is installed already
123
-				if ( in_array( $plugin_slug, $installed_plugins ) ) {
124
-					$installed = true;
125
-					$activate  = ! is_plugin_active( $plugin );
126
-				}
127
-
128
-				// Install this thing!
129
-				if ( ! $installed ) {
130
-
131
-					// Suppress feedback
132
-					ob_start();
133
-
134
-					try {
135
-						$plugin_information = plugins_api( 'plugin_information', array(
136
-							'slug'   => $plugin_slug,
137
-							'fields' => array(
138
-								'short_description' => false,
139
-								'sections'          => false,
140
-								'requires'          => false,
141
-								'rating'            => false,
142
-								'ratings'           => false,
143
-								'downloaded'        => false,
144
-								'last_updated'      => false,
145
-								'added'             => false,
146
-								'tags'              => false,
147
-								'homepage'          => false,
148
-								'donate_link'       => false,
149
-								'author_profile'    => false,
150
-								'author'            => false,
151
-							),
152
-						) );
153
-
154
-						if ( is_wp_error( $plugin_information ) ) {
155
-							throw new Exception( $plugin_information->get_error_message() );
156
-						}
157
-
158
-						$package  = $plugin_information->download_link;
159
-						$download = $upgrader->download_package( $package );
160
-
161
-						if ( is_wp_error( $download ) ) {
162
-							throw new Exception( $download->get_error_message() );
163
-						}
164
-
165
-						$working_dir = $upgrader->unpack_package( $download, true );
166
-
167
-						if ( is_wp_error( $working_dir ) ) {
168
-							throw new Exception( $working_dir->get_error_message() );
169
-						}
170
-
171
-						$result = $upgrader->install_package( array(
172
-							'source'                      => $working_dir,
173
-							'destination'                 => WP_PLUGIN_DIR,
174
-							'clear_destination'           => false,
175
-							'abort_if_destination_exists' => false,
176
-							'clear_working'               => true,
177
-							'hook_extra'                  => array(
178
-								'type'   => 'plugin',
179
-								'action' => 'install',
180
-							),
181
-						) );
182
-
183
-						if ( is_wp_error( $result ) ) {
184
-							throw new Exception( $result->get_error_message() );
185
-						}
186
-
187
-						$activate = true;
188
-
189
-					} catch ( Exception $e ) {
190
-						$success = false;
191
-					}
192
-
193
-					// Discard feedback
194
-					ob_end_clean();
195
-				}
196
-
197
-				wp_clean_plugins_cache();
198
-
199
-				// Activate this thing
200
-				if ( $activate ) {
201
-					try {
202
-						$result = activate_plugin( $plugin );
203
-
204
-						if ( is_wp_error( $result ) ) {
205
-							$success = false;
206
-						} else {
207
-							$success = true;
208
-						}
209
-					} catch ( Exception $e ) {
210
-						$success = false;
211
-					}
212
-				}
213
-			}
214
-
215
-			if ( $success && function_exists( 'ayecode_connect_args' ) ) {
216
-				ayecode_connect();// init
217
-				$args        = ayecode_connect_args();
218
-				$client      = new AyeCode_Connect( $args );
219
-				$redirect_to = ! empty( $_POST['redirect_to'] ) ? esc_url_raw( $_POST['redirect_to'] ) : '';
220
-				$redirect    = $client->build_connect_url( $redirect_to );
221
-				wp_send_json_success( array( 'connect_url' => $redirect ) );
222
-			} else {
223
-				wp_send_json_error( $this->strings['error_localhost'] );
224
-			}
225
-			wp_die();
226
-		}
227
-
228
-		/**
229
-		 * Check if maybe localhost.
230
-		 *
231
-		 * @return bool
232
-		 */
233
-		public function is_localhost() {
234
-			$localhost = false;
235
-
236
-			$host              = isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '';
237
-			$localhost_domains = array(
238
-				'localhost',
239
-				'localhost.localdomain',
240
-				'127.0.0.1',
241
-				'::1'
242
-			);
243
-
244
-			if ( in_array( $host, $localhost_domains ) ) {
245
-				$localhost = true;
246
-			}
247
-
248
-			return $localhost;
249
-		}
250
-
251
-		/**
252
-		 * Show notice to connect site.
253
-		 */
254
-		public function ayecode_connect_install_notice() {
255
-			if ( $this->maybe_show() ) {
256
-				$connect_title_string     = $this->strings['connect_title'];
257
-				$connect_external_string  = $this->strings['connect_external'];
258
-				$connect_string           = $this->strings['connect'];
259
-				$connect_button_string    = $this->strings['connect_button'];
260
-				$connecting_button_string = $this->strings['connecting_button'];
261
-				?>
7
+    /**
8
+     * Allow the quick setup and connection of our AyeCode Connect plugin.
9
+     *
10
+     * Class AyeCode_Connect_Helper
11
+     */
12
+    class AyeCode_Connect_Helper {
13
+
14
+        // Hold the version number
15
+        var $version = "1.0.4";
16
+
17
+        // Hold the default strings.
18
+        var $strings = array();
19
+
20
+        // Hold the default pages.
21
+        var $pages = array();
22
+
23
+        /**
24
+         * The constructor.
25
+         *
26
+         * AyeCode_Connect_Helper constructor.
27
+         *
28
+         * @param array $strings
29
+         * @param array $pages
30
+         */
31
+        public function __construct( $strings = array(), $pages = array() ) {
32
+            // Only fire if not localhost and the current user has the right permissions.
33
+            if ( ! $this->is_localhost() && current_user_can( 'manage_options' ) ) {
34
+                // set default strings
35
+                $default_strings = array(
36
+                    'connect_title'     => __( "Thanks for choosing an AyeCode Product!", 'ayecode-connect' ),
37
+                    'connect_external'  => __( "Please confirm you wish to connect your site?", 'ayecode-connect' ),
38
+                    'connect'           => wp_sprintf( __( "<strong>Have a license?</strong> Forget about entering license keys or downloading zip files, connect your site for instant access. %slearn more%s", 'ayecode-connect' ), "<a href='https://ayecode.io/introducing-ayecode-connect/' target='_blank'>", "</a>" ),
39
+                    'connect_button'    => __( "Connect Site", 'ayecode-connect' ),
40
+                    'connecting_button' => __( "Connecting...", 'ayecode-connect' ),
41
+                    'error_localhost'   => __( "This service will only work with a live domain, not a localhost.", 'ayecode-connect' ),
42
+                    'error'             => __( "Something went wrong, please refresh and try again.", 'ayecode-connect' ),
43
+                );
44
+                $this->strings   = array_merge( $default_strings, $strings );
45
+
46
+                // set default pages
47
+                $default_pages = array();
48
+                $this->pages   = array_merge( $default_pages, $pages );
49
+
50
+                // maybe show connect site notice
51
+                add_action( 'admin_notices', array( $this, 'ayecode_connect_install_notice' ) );
52
+
53
+                // add ajax action if not already added
54
+                if ( ! has_action( 'wp_ajax_ayecode_connect_helper' ) ) {
55
+                    add_action( 'wp_ajax_ayecode_connect_helper', array( $this, 'ayecode_connect_install' ) );
56
+                }
57
+            }
58
+
59
+            // add ajax action if not already added
60
+            if ( ! has_action( 'wp_ajax_nopriv_ayecode_connect_helper_installed' ) ) {
61
+                add_action( 'wp_ajax_nopriv_ayecode_connect_helper_installed', array( $this, 'ayecode_connect_helper_installed' ) );
62
+            }
63
+        }
64
+
65
+        /**
66
+         * Give a way to check we can connect via a external redirect.
67
+         */
68
+        public function ayecode_connect_helper_installed(){
69
+            $active = array(
70
+                'gd'    =>  defined('GEODIRECTORY_VERSION') && version_compare(GEODIRECTORY_VERSION,'2.0.0.79','>') ? 1 : 0,
71
+                'uwp'    =>  defined('USERSWP_VERSION') && version_compare(USERSWP_VERSION,'1.2.1.5','>') ? 1 : 0,
72
+                'wpi'    =>  defined('WPINV_VERSION') && version_compare(WPINV_VERSION,'1.0.14','>') ? 1 : 0,
73
+            );
74
+            wp_send_json_success( $active );
75
+            wp_die();
76
+        }
77
+
78
+        /**
79
+         * Get slug from path
80
+         *
81
+         * @param  string $key
82
+         *
83
+         * @return string
84
+         */
85
+        private function format_plugin_slug( $key ) {
86
+            $slug = explode( '/', $key );
87
+            $slug = explode( '.', end( $slug ) );
88
+
89
+            return $slug[0];
90
+        }
91
+
92
+        /**
93
+         * Install and activate the AyeCode Connect Plugin
94
+         */
95
+        public function ayecode_connect_install() {
96
+            // bail if localhost
97
+            if ( $this->is_localhost() ) {
98
+                wp_send_json_error( $this->strings['error_localhost'] );
99
+            }
100
+
101
+            // Explicitly clear the event.
102
+            wp_clear_scheduled_hook( 'geodir_plugin_background_installer', func_get_args() );
103
+
104
+            $success     = true;
105
+            $plugin_slug = "ayecode-connect";
106
+            if ( ! empty( $plugin_slug ) ) {
107
+                require_once( ABSPATH . 'wp-admin/includes/file.php' );
108
+                require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
109
+                require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
110
+                require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
111
+
112
+                WP_Filesystem();
113
+
114
+                $skin              = new Automatic_Upgrader_Skin;
115
+                $upgrader          = new WP_Upgrader( $skin );
116
+                $installed_plugins = array_map( array( $this, 'format_plugin_slug' ), array_keys( get_plugins() ) );
117
+                $plugin_slug       = $plugin_slug;
118
+                $plugin            = $plugin_slug . '/' . $plugin_slug . '.php';
119
+                $installed         = false;
120
+                $activate          = false;
121
+
122
+                // See if the plugin is installed already
123
+                if ( in_array( $plugin_slug, $installed_plugins ) ) {
124
+                    $installed = true;
125
+                    $activate  = ! is_plugin_active( $plugin );
126
+                }
127
+
128
+                // Install this thing!
129
+                if ( ! $installed ) {
130
+
131
+                    // Suppress feedback
132
+                    ob_start();
133
+
134
+                    try {
135
+                        $plugin_information = plugins_api( 'plugin_information', array(
136
+                            'slug'   => $plugin_slug,
137
+                            'fields' => array(
138
+                                'short_description' => false,
139
+                                'sections'          => false,
140
+                                'requires'          => false,
141
+                                'rating'            => false,
142
+                                'ratings'           => false,
143
+                                'downloaded'        => false,
144
+                                'last_updated'      => false,
145
+                                'added'             => false,
146
+                                'tags'              => false,
147
+                                'homepage'          => false,
148
+                                'donate_link'       => false,
149
+                                'author_profile'    => false,
150
+                                'author'            => false,
151
+                            ),
152
+                        ) );
153
+
154
+                        if ( is_wp_error( $plugin_information ) ) {
155
+                            throw new Exception( $plugin_information->get_error_message() );
156
+                        }
157
+
158
+                        $package  = $plugin_information->download_link;
159
+                        $download = $upgrader->download_package( $package );
160
+
161
+                        if ( is_wp_error( $download ) ) {
162
+                            throw new Exception( $download->get_error_message() );
163
+                        }
164
+
165
+                        $working_dir = $upgrader->unpack_package( $download, true );
166
+
167
+                        if ( is_wp_error( $working_dir ) ) {
168
+                            throw new Exception( $working_dir->get_error_message() );
169
+                        }
170
+
171
+                        $result = $upgrader->install_package( array(
172
+                            'source'                      => $working_dir,
173
+                            'destination'                 => WP_PLUGIN_DIR,
174
+                            'clear_destination'           => false,
175
+                            'abort_if_destination_exists' => false,
176
+                            'clear_working'               => true,
177
+                            'hook_extra'                  => array(
178
+                                'type'   => 'plugin',
179
+                                'action' => 'install',
180
+                            ),
181
+                        ) );
182
+
183
+                        if ( is_wp_error( $result ) ) {
184
+                            throw new Exception( $result->get_error_message() );
185
+                        }
186
+
187
+                        $activate = true;
188
+
189
+                    } catch ( Exception $e ) {
190
+                        $success = false;
191
+                    }
192
+
193
+                    // Discard feedback
194
+                    ob_end_clean();
195
+                }
196
+
197
+                wp_clean_plugins_cache();
198
+
199
+                // Activate this thing
200
+                if ( $activate ) {
201
+                    try {
202
+                        $result = activate_plugin( $plugin );
203
+
204
+                        if ( is_wp_error( $result ) ) {
205
+                            $success = false;
206
+                        } else {
207
+                            $success = true;
208
+                        }
209
+                    } catch ( Exception $e ) {
210
+                        $success = false;
211
+                    }
212
+                }
213
+            }
214
+
215
+            if ( $success && function_exists( 'ayecode_connect_args' ) ) {
216
+                ayecode_connect();// init
217
+                $args        = ayecode_connect_args();
218
+                $client      = new AyeCode_Connect( $args );
219
+                $redirect_to = ! empty( $_POST['redirect_to'] ) ? esc_url_raw( $_POST['redirect_to'] ) : '';
220
+                $redirect    = $client->build_connect_url( $redirect_to );
221
+                wp_send_json_success( array( 'connect_url' => $redirect ) );
222
+            } else {
223
+                wp_send_json_error( $this->strings['error_localhost'] );
224
+            }
225
+            wp_die();
226
+        }
227
+
228
+        /**
229
+         * Check if maybe localhost.
230
+         *
231
+         * @return bool
232
+         */
233
+        public function is_localhost() {
234
+            $localhost = false;
235
+
236
+            $host              = isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : '';
237
+            $localhost_domains = array(
238
+                'localhost',
239
+                'localhost.localdomain',
240
+                '127.0.0.1',
241
+                '::1'
242
+            );
243
+
244
+            if ( in_array( $host, $localhost_domains ) ) {
245
+                $localhost = true;
246
+            }
247
+
248
+            return $localhost;
249
+        }
250
+
251
+        /**
252
+         * Show notice to connect site.
253
+         */
254
+        public function ayecode_connect_install_notice() {
255
+            if ( $this->maybe_show() ) {
256
+                $connect_title_string     = $this->strings['connect_title'];
257
+                $connect_external_string  = $this->strings['connect_external'];
258
+                $connect_string           = $this->strings['connect'];
259
+                $connect_button_string    = $this->strings['connect_button'];
260
+                $connecting_button_string = $this->strings['connecting_button'];
261
+                ?>
262 262
 				<div class="notice notice-info acch-notice">
263 263
 					<span class="acch-float-left">
264 264
 						<svg width="61px" height="61px" viewBox="0 0 61 61" version="1.1"
@@ -305,9 +305,9 @@  discard block
 block discarded – undo
305 305
 				</div>
306 306
 
307 307
 				<?php
308
-				// only include the popup HTML if needed.
309
-				if ( ! empty( $_REQUEST['external-connect-request'] ) ) {
310
-					?>
308
+                // only include the popup HTML if needed.
309
+                if ( ! empty( $_REQUEST['external-connect-request'] ) ) {
310
+                    ?>
311 311
 					<div id="ayecode-connect-helper-external-confirm" style="display:none;">
312 312
 						<div class="noticex notice-info acch-notice" style="border: none;">
313 313
 					<span class="acch-float-left">
@@ -353,23 +353,23 @@  discard block
 block discarded – undo
353 353
 						</div>
354 354
 					</div>
355 355
 					<?php
356
-				}
357
-
358
-				// add required scripts
359
-				$this->script();
360
-			}
361
-		}
362
-
363
-		/**
364
-		 * Get the JS Script.
365
-		 */
366
-		public function script() {
367
-
368
-			// add thickbox if external request is requested
369
-			if ( ! empty( $_REQUEST['external-connect-request'] ) ) {
370
-				add_thickbox();
371
-			}
372
-			?>
356
+                }
357
+
358
+                // add required scripts
359
+                $this->script();
360
+            }
361
+        }
362
+
363
+        /**
364
+         * Get the JS Script.
365
+         */
366
+        public function script() {
367
+
368
+            // add thickbox if external request is requested
369
+            if ( ! empty( $_REQUEST['external-connect-request'] ) ) {
370
+                add_thickbox();
371
+            }
372
+            ?>
373 373
 			<style>
374 374
 				.acch-title {
375 375
 					margin: 0;
@@ -435,38 +435,38 @@  discard block
 block discarded – undo
435 435
 					});
436 436
 				} 
437 437
 				<?php
438
-				// add thickbox if external request is requested
439
-				if(! empty( $_REQUEST['external-connect-request'] )) {
440
-				?>
438
+                // add thickbox if external request is requested
439
+                if(! empty( $_REQUEST['external-connect-request'] )) {
440
+                ?>
441 441
 				jQuery(function () {
442 442
 					setTimeout(function () {
443 443
 						tb_show("AyeCode Connect", "?TB_inline?width=300&height=80&inlineId=ayecode-connect-helper-external-confirm");
444 444
 					}, 200);
445 445
 				});
446 446
 				<?php
447
-				}
448
-				?>
447
+                }
448
+                ?>
449 449
 			</script>
450 450
 			<?php
451
-		}
452
-
453
-		/**
454
-		 * Decide what pages to show on.
455
-		 *
456
-		 * @return bool
457
-		 */
458
-		public function maybe_show() {
459
-			$show = false;
460
-
461
-			// check if on a page set to show
462
-			if ( isset( $_REQUEST['page'] ) && in_array( $_REQUEST['page'], $this->pages ) ) {
463
-				// check if not active and connected
464
-				if ( ! defined( 'AYECODE_CONNECT_VERSION' ) || ! get_option( 'ayecode_connect_blog_token' ) ) {
465
-					$show = true;
466
-				}
467
-			}
468
-
469
-			return $show;
470
-		}
471
-	}
451
+        }
452
+
453
+        /**
454
+         * Decide what pages to show on.
455
+         *
456
+         * @return bool
457
+         */
458
+        public function maybe_show() {
459
+            $show = false;
460
+
461
+            // check if on a page set to show
462
+            if ( isset( $_REQUEST['page'] ) && in_array( $_REQUEST['page'], $this->pages ) ) {
463
+                // check if not active and connected
464
+                if ( ! defined( 'AYECODE_CONNECT_VERSION' ) || ! get_option( 'ayecode_connect_blog_token' ) ) {
465
+                    $show = true;
466
+                }
467
+            }
468
+
469
+            return $show;
470
+        }
471
+    }
472 472
 }
Please login to merge, or discard this patch.
vendor/ayecode/wp-deactivation-survey/wp-deactivation-survey.php 1 patch
Indentation   +75 added lines, -75 removed lines patch added patch discarded remove patch
@@ -1,99 +1,99 @@
 block discarded – undo
1 1
 <?php
2 2
 
3 3
 if ( ! defined( 'ABSPATH' ) ) {
4
-	exit;
4
+    exit;
5 5
 }
6 6
 
7 7
 if ( ! class_exists( 'AyeCode_Deactivation_Survey' ) ) {
8 8
 
9
-	class AyeCode_Deactivation_Survey {
9
+    class AyeCode_Deactivation_Survey {
10 10
 
11
-		/**
12
-		 * AyeCode_Deactivation_Survey instance.
13
-		 *
14
-		 * @access private
15
-		 * @since  1.0.0
16
-		 * @var    AyeCode_Deactivation_Survey There can be only one!
17
-		 */
18
-		private static $instance = null;
11
+        /**
12
+         * AyeCode_Deactivation_Survey instance.
13
+         *
14
+         * @access private
15
+         * @since  1.0.0
16
+         * @var    AyeCode_Deactivation_Survey There can be only one!
17
+         */
18
+        private static $instance = null;
19 19
 
20
-		public static $plugins;
20
+        public static $plugins;
21 21
 
22
-		public $version = "1.0.7";
22
+        public $version = "1.0.7";
23 23
 
24
-		public static function instance( $plugin = array() ) {
25
-			if ( ! isset( self::$instance ) && ! ( self::$instance instanceof AyeCode_Deactivation_Survey ) ) {
26
-				self::$instance = new AyeCode_Deactivation_Survey;
27
-				self::$plugins = array();
24
+        public static function instance( $plugin = array() ) {
25
+            if ( ! isset( self::$instance ) && ! ( self::$instance instanceof AyeCode_Deactivation_Survey ) ) {
26
+                self::$instance = new AyeCode_Deactivation_Survey;
27
+                self::$plugins = array();
28 28
 
29
-				add_action( 'admin_enqueue_scripts', array( self::$instance, 'scripts' ) );
29
+                add_action( 'admin_enqueue_scripts', array( self::$instance, 'scripts' ) );
30 30
 
31
-				do_action( 'ayecode_deactivation_survey_loaded' );
32
-			}
31
+                do_action( 'ayecode_deactivation_survey_loaded' );
32
+            }
33 33
 
34
-			if(!empty($plugin)){
35
-				self::$plugins[] = (object)$plugin;
36
-			}
34
+            if(!empty($plugin)){
35
+                self::$plugins[] = (object)$plugin;
36
+            }
37 37
 
38
-			return self::$instance;
39
-		}
38
+            return self::$instance;
39
+        }
40 40
 
41
-		public function scripts() {
42
-			global $pagenow;
41
+        public function scripts() {
42
+            global $pagenow;
43 43
 
44
-			// Bail if we are not on the plugins page
45
-			if ( $pagenow != "plugins.php" ) {
46
-				return;
47
-			}
44
+            // Bail if we are not on the plugins page
45
+            if ( $pagenow != "plugins.php" ) {
46
+                return;
47
+            }
48 48
 
49
-			// Enqueue scripts
50
-			add_thickbox();
51
-			wp_enqueue_script('ayecode-deactivation-survey', plugin_dir_url(__FILE__) . 'ayecode-ds.js');
49
+            // Enqueue scripts
50
+            add_thickbox();
51
+            wp_enqueue_script('ayecode-deactivation-survey', plugin_dir_url(__FILE__) . 'ayecode-ds.js');
52 52
 
53
-			/*
53
+            /*
54 54
 			 * Localized strings. Strings can be localised by plugins using this class.
55 55
 			 * We deliberately don't add textdomains here so that double textdomain warning is not given in theme review.
56 56
 			 */
57
-			wp_localize_script('ayecode-deactivation-survey', 'ayecodeds_deactivate_feedback_form_strings', array(
58
-				'quick_feedback'			=> __( 'Quick Feedback', 'ayecode-connect' ),
59
-				'foreword'					=> __( 'If you would be kind enough, please tell us why you\'re deactivating?', 'ayecode-connect' ),
60
-				'better_plugins_name'		=> __( 'Please tell us which plugin?', 'ayecode-connect' ),
61
-				'please_tell_us'			=> __( 'Please tell us the reason so we can improve the plugin', 'ayecode-connect' ),
62
-				'do_not_attach_email'		=> __( 'Do not send my e-mail address with this feedback', 'ayecode-connect' ),
63
-				'brief_description'			=> __( 'Please give us any feedback that could help us improve', 'ayecode-connect' ),
64
-				'cancel'					=> __( 'Cancel', 'ayecode-connect' ),
65
-				'skip_and_deactivate'		=> __( 'Skip &amp; Deactivate', 'ayecode-connect' ),
66
-				'submit_and_deactivate'		=> __( 'Submit &amp; Deactivate', 'ayecode-connect' ),
67
-				'please_wait'				=> __( 'Please wait', 'ayecode-connect' ),
68
-				'get_support'				=> __( 'Get Support', 'ayecode-connect' ),
69
-				'documentation'				=> __( 'Documentation', 'ayecode-connect' ),
70
-				'thank_you'					=> __( 'Thank you!', 'ayecode-connect' ),
71
-			));
72
-
73
-			// Plugins
74
-			$plugins = apply_filters('ayecode_deactivation_survey_plugins', self::$plugins);
75
-
76
-			// Reasons
77
-			$defaultReasons = array(
78
-				'suddenly-stopped-working'	=> __( 'The plugin suddenly stopped working', 'ayecode-connect' ),
79
-				'plugin-broke-site'			=> __( 'The plugin broke my site', 'ayecode-connect' ),
80
-				'plugin-setup-difficult'	=> __( 'Too difficult to setup', 'ayecode-connect' ),
81
-				'plugin-design-difficult'	=> __( 'Too difficult to get the design i want', 'ayecode-connect' ),
82
-				'no-longer-needed'			=> __( 'I don\'t need this plugin any more', 'ayecode-connect' ),
83
-				'found-better-plugin'		=> __( 'I found a better plugin', 'ayecode-connect' ),
84
-				'temporary-deactivation'	=> __( 'It\'s a temporary deactivation, I\'m troubleshooting', 'ayecode-connect' ),
85
-				'other'						=> __( 'Other', 'ayecode-connect' ),
86
-			);
87
-
88
-			foreach( $plugins as $plugin ) {
89
-				$plugin->reasons = apply_filters( 'ayecode_deactivation_survey_reasons', $defaultReasons, $plugin );
90
-				$plugin->url = home_url();
91
-				$plugin->activated = 0;
92
-			}
93
-
94
-			// Send plugin data
95
-			wp_localize_script('ayecode-deactivation-survey', 'ayecodeds_deactivate_feedback_form_plugins', $plugins);
96
-		}
97
-	}
57
+            wp_localize_script('ayecode-deactivation-survey', 'ayecodeds_deactivate_feedback_form_strings', array(
58
+                'quick_feedback'			=> __( 'Quick Feedback', 'ayecode-connect' ),
59
+                'foreword'					=> __( 'If you would be kind enough, please tell us why you\'re deactivating?', 'ayecode-connect' ),
60
+                'better_plugins_name'		=> __( 'Please tell us which plugin?', 'ayecode-connect' ),
61
+                'please_tell_us'			=> __( 'Please tell us the reason so we can improve the plugin', 'ayecode-connect' ),
62
+                'do_not_attach_email'		=> __( 'Do not send my e-mail address with this feedback', 'ayecode-connect' ),
63
+                'brief_description'			=> __( 'Please give us any feedback that could help us improve', 'ayecode-connect' ),
64
+                'cancel'					=> __( 'Cancel', 'ayecode-connect' ),
65
+                'skip_and_deactivate'		=> __( 'Skip &amp; Deactivate', 'ayecode-connect' ),
66
+                'submit_and_deactivate'		=> __( 'Submit &amp; Deactivate', 'ayecode-connect' ),
67
+                'please_wait'				=> __( 'Please wait', 'ayecode-connect' ),
68
+                'get_support'				=> __( 'Get Support', 'ayecode-connect' ),
69
+                'documentation'				=> __( 'Documentation', 'ayecode-connect' ),
70
+                'thank_you'					=> __( 'Thank you!', 'ayecode-connect' ),
71
+            ));
72
+
73
+            // Plugins
74
+            $plugins = apply_filters('ayecode_deactivation_survey_plugins', self::$plugins);
75
+
76
+            // Reasons
77
+            $defaultReasons = array(
78
+                'suddenly-stopped-working'	=> __( 'The plugin suddenly stopped working', 'ayecode-connect' ),
79
+                'plugin-broke-site'			=> __( 'The plugin broke my site', 'ayecode-connect' ),
80
+                'plugin-setup-difficult'	=> __( 'Too difficult to setup', 'ayecode-connect' ),
81
+                'plugin-design-difficult'	=> __( 'Too difficult to get the design i want', 'ayecode-connect' ),
82
+                'no-longer-needed'			=> __( 'I don\'t need this plugin any more', 'ayecode-connect' ),
83
+                'found-better-plugin'		=> __( 'I found a better plugin', 'ayecode-connect' ),
84
+                'temporary-deactivation'	=> __( 'It\'s a temporary deactivation, I\'m troubleshooting', 'ayecode-connect' ),
85
+                'other'						=> __( 'Other', 'ayecode-connect' ),
86
+            );
87
+
88
+            foreach( $plugins as $plugin ) {
89
+                $plugin->reasons = apply_filters( 'ayecode_deactivation_survey_reasons', $defaultReasons, $plugin );
90
+                $plugin->url = home_url();
91
+                $plugin->activated = 0;
92
+            }
93
+
94
+            // Send plugin data
95
+            wp_localize_script('ayecode-deactivation-survey', 'ayecodeds_deactivate_feedback_form_plugins', $plugins);
96
+        }
97
+    }
98 98
 
99 99
 }
100 100
\ No newline at end of file
Please login to merge, or discard this patch.
vendor/ayecode/wp-super-duper/map.php 1 patch
Indentation   +226 added lines, -226 removed lines patch added patch discarded remove patch
@@ -3,241 +3,241 @@
 block discarded – undo
3 3
 class SD_Map extends WP_Super_Duper {
4 4
 
5 5
 
6
-	public $arguments;
7
-
8
-	/**
9
-	 * Sets up the widgets name etc
10
-	 */
11
-	public function __construct() {
12
-
13
-		$options = array(
14
-			'textdomain'     => 'super-duper',
15
-			// textdomain of the plugin/theme (used to prefix the Gutenberg block)
16
-			'block-icon'     => 'admin-site',
17
-			// Dash icon name for the block: https://developer.wordpress.org/resource/dashicons/#arrow-right
18
-			'block-category' => 'widgets',
19
-			// the category for the block, 'common', 'formatting', 'layout', 'widgets', 'embed'.
20
-			'block-keywords' => "['map','super','google']",
21
-			// used in the block search, MAX 3
22
-			'block-output'   => array( // the block visual output elements as an array
23
-				array(
24
-					'element' => 'p',
25
-					'content' => __('A Google API key is required to use this block, we recommend installing our plugin which makes it easy and sets it globally, or you can set a key in the block settings sidebar: ', 'ayecode-connect' ),
26
-					//'element_require' => '"1"=='.get_option( 'rgmk_google_map_api_key', '"0"') ? '"0"' : '"1"',
27
-					'element_require' => get_option( 'rgmk_google_map_api_key', false) ? '1==0' : '1==1 && [%api_key%]==""',
28
-				),
29
-				array(
30
-					'element' => 'a',
31
-					'content' => __('API KEY for Google Maps', 'ayecode-connect' ),
32
-					'element_require' => get_option( 'rgmk_google_map_api_key', false) ? '1==0' : '1==1 && [%api_key%]==""',
33
-					'href' => 'https://wordpress.org/plugins/api-key-for-google-maps/',
34
-				),
35
-				array(
36
-					'element' => 'img',
37
-					'class'   => '[%className%]',
38
-					//'content' => 'Hello: [%after_text%]' // block properties can be added by wrapping them in [%name%]
39
-					'element_require' => '[%type%]=="image"',
40
-					'src'     => get_option( 'rgmk_google_map_api_key', false) ? "https://maps.googleapis.com/maps/api/staticmap?center=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&size=[%static_width%]x[%static_height%]&key=".get_option( 'rgmk_google_map_api_key') : "https://maps.googleapis.com/maps/api/staticmap?center=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&size=[%static_width%]x[%static_height%]&key=[%api_key%]"
41
-				),
42
-				array(
43
-					'element' => 'div',
44
-					'class'   => 'sd-map-iframe-cover',
45
-					'style'   => '{overflow:"hidden", position:"relative"}',
46
-					array(
47
-						'element' => 'iframe',
48
-						'title'   => __( 'Placeholderx', 'ayecode-connect' ),
49
-						'class'   => '[%className%]',
50
-						'width'   => '[%width%]',
51
-						'height'  => '[%height%]',
52
-						'frameborder' => '0',
53
-						'allowfullscreen' => 'true',
54
-						'style' => '{border:0}',
55
-						'element_require' => '[%type%]!="image"',
56
-						'src'     => get_option( 'rgmk_google_map_api_key', false) ? "https://www.google.com/maps/embed/v1/[%type%]?q=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&key=".get_option( 'rgmk_google_map_api_key') : "https://www.google.com/maps/embed/v1/[%type%]?q=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&key=[%api_key%]"
57
-					),
58
-				),
59
-				array(
60
-					'element' => 'style',
61
-					'content' => '.sd-map-iframe-cover:hover:before {background: #4a4a4a88; content: "'.__( 'Click here, Settings are in the block settings sidebar', 'ayecode-connect' ).'";} .sd-map-iframe-cover:before{cursor: pointer; content: ""; width: 100%; height: 100%; position: absolute; top: 0; bottom: 0;padding-top: 33%; text-align: center;  color: #fff; font-size: 20px; font-weight: bold;}',
62
-					'element_require' => '[%type%]!="image"',
63
-				),
64
-			),
65
-			'class_name'     => __CLASS__,
66
-			// The calling class name
67
-			'base_id'        => 'sd_map',
68
-			// this is used as the widget id and the shortcode id.
69
-			'name'           => __( 'Map', 'ayecode-connect' ),
70
-			// the name of the widget/block
71
-			'widget_ops'     => array(
72
-				'classname'   => 'sd-map-class',
73
-				// widget class
74
-				'description' => esc_html__( 'This is an example that will take a text parameter and output it after `Hello:`.', 'ayecode-connect' ),
75
-				// widget description
76
-			),
77
-			'arguments'      => array( // these are the arguments that will be used in the widget, shortcode and block settings.
78
-				'type'  => array(
79
-					'title' => __('Map Type:', 'ayecode-connect'),
80
-					'desc' => __('Select the map type to use.', 'ayecode-connect'),
81
-					'type' => 'select',
82
-					'options'   =>  array(
83
-						"image" => __('Static Image', 'ayecode-connect'),
84
-						"place" => __('Place', 'ayecode-connect'),
6
+    public $arguments;
7
+
8
+    /**
9
+     * Sets up the widgets name etc
10
+     */
11
+    public function __construct() {
12
+
13
+        $options = array(
14
+            'textdomain'     => 'super-duper',
15
+            // textdomain of the plugin/theme (used to prefix the Gutenberg block)
16
+            'block-icon'     => 'admin-site',
17
+            // Dash icon name for the block: https://developer.wordpress.org/resource/dashicons/#arrow-right
18
+            'block-category' => 'widgets',
19
+            // the category for the block, 'common', 'formatting', 'layout', 'widgets', 'embed'.
20
+            'block-keywords' => "['map','super','google']",
21
+            // used in the block search, MAX 3
22
+            'block-output'   => array( // the block visual output elements as an array
23
+                array(
24
+                    'element' => 'p',
25
+                    'content' => __('A Google API key is required to use this block, we recommend installing our plugin which makes it easy and sets it globally, or you can set a key in the block settings sidebar: ', 'ayecode-connect' ),
26
+                    //'element_require' => '"1"=='.get_option( 'rgmk_google_map_api_key', '"0"') ? '"0"' : '"1"',
27
+                    'element_require' => get_option( 'rgmk_google_map_api_key', false) ? '1==0' : '1==1 && [%api_key%]==""',
28
+                ),
29
+                array(
30
+                    'element' => 'a',
31
+                    'content' => __('API KEY for Google Maps', 'ayecode-connect' ),
32
+                    'element_require' => get_option( 'rgmk_google_map_api_key', false) ? '1==0' : '1==1 && [%api_key%]==""',
33
+                    'href' => 'https://wordpress.org/plugins/api-key-for-google-maps/',
34
+                ),
35
+                array(
36
+                    'element' => 'img',
37
+                    'class'   => '[%className%]',
38
+                    //'content' => 'Hello: [%after_text%]' // block properties can be added by wrapping them in [%name%]
39
+                    'element_require' => '[%type%]=="image"',
40
+                    'src'     => get_option( 'rgmk_google_map_api_key', false) ? "https://maps.googleapis.com/maps/api/staticmap?center=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&size=[%static_width%]x[%static_height%]&key=".get_option( 'rgmk_google_map_api_key') : "https://maps.googleapis.com/maps/api/staticmap?center=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&size=[%static_width%]x[%static_height%]&key=[%api_key%]"
41
+                ),
42
+                array(
43
+                    'element' => 'div',
44
+                    'class'   => 'sd-map-iframe-cover',
45
+                    'style'   => '{overflow:"hidden", position:"relative"}',
46
+                    array(
47
+                        'element' => 'iframe',
48
+                        'title'   => __( 'Placeholderx', 'ayecode-connect' ),
49
+                        'class'   => '[%className%]',
50
+                        'width'   => '[%width%]',
51
+                        'height'  => '[%height%]',
52
+                        'frameborder' => '0',
53
+                        'allowfullscreen' => 'true',
54
+                        'style' => '{border:0}',
55
+                        'element_require' => '[%type%]!="image"',
56
+                        'src'     => get_option( 'rgmk_google_map_api_key', false) ? "https://www.google.com/maps/embed/v1/[%type%]?q=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&key=".get_option( 'rgmk_google_map_api_key') : "https://www.google.com/maps/embed/v1/[%type%]?q=[%location%]&maptype=[%maptype%]&zoom=[%zoom%]&key=[%api_key%]"
57
+                    ),
58
+                ),
59
+                array(
60
+                    'element' => 'style',
61
+                    'content' => '.sd-map-iframe-cover:hover:before {background: #4a4a4a88; content: "'.__( 'Click here, Settings are in the block settings sidebar', 'ayecode-connect' ).'";} .sd-map-iframe-cover:before{cursor: pointer; content: ""; width: 100%; height: 100%; position: absolute; top: 0; bottom: 0;padding-top: 33%; text-align: center;  color: #fff; font-size: 20px; font-weight: bold;}',
62
+                    'element_require' => '[%type%]!="image"',
63
+                ),
64
+            ),
65
+            'class_name'     => __CLASS__,
66
+            // The calling class name
67
+            'base_id'        => 'sd_map',
68
+            // this is used as the widget id and the shortcode id.
69
+            'name'           => __( 'Map', 'ayecode-connect' ),
70
+            // the name of the widget/block
71
+            'widget_ops'     => array(
72
+                'classname'   => 'sd-map-class',
73
+                // widget class
74
+                'description' => esc_html__( 'This is an example that will take a text parameter and output it after `Hello:`.', 'ayecode-connect' ),
75
+                // widget description
76
+            ),
77
+            'arguments'      => array( // these are the arguments that will be used in the widget, shortcode and block settings.
78
+                'type'  => array(
79
+                    'title' => __('Map Type:', 'ayecode-connect'),
80
+                    'desc' => __('Select the map type to use.', 'ayecode-connect'),
81
+                    'type' => 'select',
82
+                    'options'   =>  array(
83
+                        "image" => __('Static Image', 'ayecode-connect'),
84
+                        "place" => __('Place', 'ayecode-connect'),
85 85
 //						"directions" => __('Directions', 'ayecode-connect'),
86 86
 //						"search" => __('Search', 'ayecode-connect'),
87 87
 //						"view" => __('View', 'ayecode-connect'),
88 88
 //						"streetview" => __('Streetview', 'ayecode-connect'),
89
-					),
90
-					'default'  => 'image',
91
-					'desc_tip' => true,
92
-					'advanced' => false
93
-				),
94
-				'location'            => array(
95
-					'type'        => 'text',
96
-					'title'       => __( 'Location:', 'ayecode-connect' ),
97
-					'desc'        => __( 'Enter the location to show on the map, place, city, zip code or GPS.', 'ayecode-connect' ),
98
-					'placeholder' => 'Place, city, zip code or GPS',
99
-					'desc_tip'    => true,
100
-					'default'     => 'Ireland',
101
-					'advanced'    => false
102
-				),
103
-				'static_width'            => array(
104
-					'type'        => 'number',
105
-					'title'       => __( 'Width:', 'ayecode-connect' ),
106
-					'desc'        => __( 'This is the width of the map, for static maps you can only use px values.', 'ayecode-connect' ),
107
-					'placeholder' => '600',
108
-					'desc_tip'    => true,
109
-					'default'     => '600',
110
-					'custom_attributes' => array(
111
-						'max'         => '2000',
112
-						'min'         => '100',
113
-					),
114
-					'element_require' => '[%type%]=="image"',
115
-					'advanced'    => false
116
-				),
117
-				'static_height'           => array(
118
-					'type'        => 'number',
119
-					'title'       => __( 'Height:', 'ayecode-connect' ),
120
-					'desc'        => __( 'This is the height of the map, for static maps you can only use px values.', 'ayecode-connect' ),
121
-					'placeholder' => '400',
122
-					'desc_tip'    => true,
123
-					'default'     => '400',
124
-					'custom_attributes' => array(
125
-						'max'         => '2000',
126
-						'min'         => '100',
127
-						'required'         => 'required',
128
-					),
129
-					'element_require' => '[%type%]=="image"',
130
-					'advanced'    => false
131
-				),
132
-				'width'            => array(
133
-					'type'        => 'text',
134
-					'title'       => __( 'Width:', 'ayecode-connect' ),
135
-					'desc'        => __( 'This is the width of the map, you can use % or px here.', 'ayecode-connect' ),
136
-					'placeholder' => '100%',
137
-					'desc_tip'    => true,
138
-					'default'     => '100%',
139
-					'element_require' => '[%type%]!="image"',
140
-					'advanced'    => false
141
-				),
142
-				'height'           => array(
143
-					'type'        => 'text',
144
-					'title'       => __( 'Height:', 'ayecode-connect' ),
145
-					'desc'        => __( 'This is the height of the map, you can use %, px or vh here.', 'ayecode-connect' ),
146
-					'placeholder' => '425px',
147
-					'desc_tip'    => true,
148
-					'default'     => '425px',
149
-					'element_require' => '[%type%]!="image"',
150
-					'advanced'    => false
151
-				),
152
-				'maptype'          => array(
153
-					'type'     => 'select',
154
-					'title'    => __( 'Mapview:', 'ayecode-connect' ),
155
-					'desc'     => __( 'This is the type of map view that will be used by default.', 'ayecode-connect' ),
156
-					'options'  => array(
157
-						"roadmap"   => __( 'Road Map', 'ayecode-connect' ),
158
-						"satellite" => __( 'Satellite Map', 'ayecode-connect' ),
89
+                    ),
90
+                    'default'  => 'image',
91
+                    'desc_tip' => true,
92
+                    'advanced' => false
93
+                ),
94
+                'location'            => array(
95
+                    'type'        => 'text',
96
+                    'title'       => __( 'Location:', 'ayecode-connect' ),
97
+                    'desc'        => __( 'Enter the location to show on the map, place, city, zip code or GPS.', 'ayecode-connect' ),
98
+                    'placeholder' => 'Place, city, zip code or GPS',
99
+                    'desc_tip'    => true,
100
+                    'default'     => 'Ireland',
101
+                    'advanced'    => false
102
+                ),
103
+                'static_width'            => array(
104
+                    'type'        => 'number',
105
+                    'title'       => __( 'Width:', 'ayecode-connect' ),
106
+                    'desc'        => __( 'This is the width of the map, for static maps you can only use px values.', 'ayecode-connect' ),
107
+                    'placeholder' => '600',
108
+                    'desc_tip'    => true,
109
+                    'default'     => '600',
110
+                    'custom_attributes' => array(
111
+                        'max'         => '2000',
112
+                        'min'         => '100',
113
+                    ),
114
+                    'element_require' => '[%type%]=="image"',
115
+                    'advanced'    => false
116
+                ),
117
+                'static_height'           => array(
118
+                    'type'        => 'number',
119
+                    'title'       => __( 'Height:', 'ayecode-connect' ),
120
+                    'desc'        => __( 'This is the height of the map, for static maps you can only use px values.', 'ayecode-connect' ),
121
+                    'placeholder' => '400',
122
+                    'desc_tip'    => true,
123
+                    'default'     => '400',
124
+                    'custom_attributes' => array(
125
+                        'max'         => '2000',
126
+                        'min'         => '100',
127
+                        'required'         => 'required',
128
+                    ),
129
+                    'element_require' => '[%type%]=="image"',
130
+                    'advanced'    => false
131
+                ),
132
+                'width'            => array(
133
+                    'type'        => 'text',
134
+                    'title'       => __( 'Width:', 'ayecode-connect' ),
135
+                    'desc'        => __( 'This is the width of the map, you can use % or px here.', 'ayecode-connect' ),
136
+                    'placeholder' => '100%',
137
+                    'desc_tip'    => true,
138
+                    'default'     => '100%',
139
+                    'element_require' => '[%type%]!="image"',
140
+                    'advanced'    => false
141
+                ),
142
+                'height'           => array(
143
+                    'type'        => 'text',
144
+                    'title'       => __( 'Height:', 'ayecode-connect' ),
145
+                    'desc'        => __( 'This is the height of the map, you can use %, px or vh here.', 'ayecode-connect' ),
146
+                    'placeholder' => '425px',
147
+                    'desc_tip'    => true,
148
+                    'default'     => '425px',
149
+                    'element_require' => '[%type%]!="image"',
150
+                    'advanced'    => false
151
+                ),
152
+                'maptype'          => array(
153
+                    'type'     => 'select',
154
+                    'title'    => __( 'Mapview:', 'ayecode-connect' ),
155
+                    'desc'     => __( 'This is the type of map view that will be used by default.', 'ayecode-connect' ),
156
+                    'options'  => array(
157
+                        "roadmap"   => __( 'Road Map', 'ayecode-connect' ),
158
+                        "satellite" => __( 'Satellite Map', 'ayecode-connect' ),
159 159
 //						"hybrid"    => __( 'Hybrid Map', 'ayecode-connect' ),
160 160
 //						"terrain"   => __( 'Terrain Map', 'ayecode-connect' ),
161
-					),
162
-					'desc_tip' => true,
163
-					'default'  => 'roadmap',
164
-					'advanced' => true
165
-				),
166
-				'zoom'             => array(
167
-					'type'        => 'select',
168
-					'title'       => __( 'Zoom level:', 'ayecode-connect' ),
169
-					'desc'        => __( 'This is the zoom level of the map, `auto` is recommended.', 'ayecode-connect' ),
170
-					'options'     => range( 1, 19 ),
171
-					'placeholder' => '',
172
-					'desc_tip'    => true,
173
-					'default'     => '7',
174
-					'advanced'    => true
175
-				),
176
-				'api_key'           => array(
177
-					'type'        => 'text',
178
-					'title'       => __( 'Api Key:', 'ayecode-connect' ),
179
-					'desc'        => __( 'This is the height of the map, you can use %, px or vh here.', 'ayecode-connect' ),
180
-					'placeholder' => '',
181
-					'desc_tip'    => true,
182
-					'default'     => '',
183
-					'element_require' => get_option( 'rgmk_google_map_api_key', false) ? '1==0' : '1==1',
184
-					'advanced'    => false
185
-				),
186
-			)
187
-		);
188
-
189
-		parent::__construct( $options );
190
-	}
191
-
192
-
193
-	/**
194
-	 * This is the output function for the widget, shortcode and block (front end).
195
-	 *
196
-	 * @param array $args The arguments values.
197
-	 * @param array $widget_args The widget arguments when used.
198
-	 * @param string $content The shortcode content argument
199
-	 *
200
-	 * @return string
201
-	 */
202
-	public function output( $args = array(), $widget_args = array(), $content = '' ) {
203
-
204
-		// options
205
-		$defaults = array(
206
-			'type'      => 'image', // image, place
207
-			'location' => 'Ireland',
208
-			'static_width' => '600',
209
-			'static_height' => '400',
210
-			'width'=> '100%',
211
-			'height'=> '425px',
212
-			'maptype'     => 'roadmap',
213
-			'zoom'     => '7',
214
-			'api_key'     => 'AIzaSyBK3ZcmK0ljxl5agNyJNQh_G24Thq1btuE',
215
-		);
216
-
217
-		/**
218
-		 * Parse incoming $args into an array and merge it with $defaults
219
-		 */
220
-		$args = wp_parse_args($args, $defaults );
221
-
222
-		$output = '';
223
-
224
-
225
-		// check if we have a global API key
226
-		$args['api_key'] = get_option( 'rgmk_google_map_api_key', false ) ? get_option( 'rgmk_google_map_api_key' ) : $args['api_key'];
227
-
228
-		if($args['type']=='image'){
229
-			$output .= "<img src='https://maps.googleapis.com/maps/api/staticmap?center=".esc_attr($args['location'])."&maptype=".esc_attr($args['maptype'])."&zoom=".esc_attr($args['zoom'])."&size=".esc_attr($args['static_width'])."x".esc_attr($args['static_height'])."&key=".esc_attr($args['api_key'])."' />";
230
-		}else{
231
-			$output .= "<iframe width='".esc_attr($args['width'])."' height='".esc_attr($args['height'])."' frameborder='0' allowfullscreen style='border:0;' src='https://www.google.com/maps/embed/v1/".esc_attr($args['type'])."?q=".esc_attr($args['location'])."&maptype=".esc_attr($args['maptype'])."&zoom=".esc_attr($args['zoom'])."&key=".esc_attr($args['api_key'])."' ></iframe> ";
232
-		}
233
-
234
-		return $output;
235
-
236
-	}
161
+                    ),
162
+                    'desc_tip' => true,
163
+                    'default'  => 'roadmap',
164
+                    'advanced' => true
165
+                ),
166
+                'zoom'             => array(
167
+                    'type'        => 'select',
168
+                    'title'       => __( 'Zoom level:', 'ayecode-connect' ),
169
+                    'desc'        => __( 'This is the zoom level of the map, `auto` is recommended.', 'ayecode-connect' ),
170
+                    'options'     => range( 1, 19 ),
171
+                    'placeholder' => '',
172
+                    'desc_tip'    => true,
173
+                    'default'     => '7',
174
+                    'advanced'    => true
175
+                ),
176
+                'api_key'           => array(
177
+                    'type'        => 'text',
178
+                    'title'       => __( 'Api Key:', 'ayecode-connect' ),
179
+                    'desc'        => __( 'This is the height of the map, you can use %, px or vh here.', 'ayecode-connect' ),
180
+                    'placeholder' => '',
181
+                    'desc_tip'    => true,
182
+                    'default'     => '',
183
+                    'element_require' => get_option( 'rgmk_google_map_api_key', false) ? '1==0' : '1==1',
184
+                    'advanced'    => false
185
+                ),
186
+            )
187
+        );
188
+
189
+        parent::__construct( $options );
190
+    }
191
+
192
+
193
+    /**
194
+     * This is the output function for the widget, shortcode and block (front end).
195
+     *
196
+     * @param array $args The arguments values.
197
+     * @param array $widget_args The widget arguments when used.
198
+     * @param string $content The shortcode content argument
199
+     *
200
+     * @return string
201
+     */
202
+    public function output( $args = array(), $widget_args = array(), $content = '' ) {
203
+
204
+        // options
205
+        $defaults = array(
206
+            'type'      => 'image', // image, place
207
+            'location' => 'Ireland',
208
+            'static_width' => '600',
209
+            'static_height' => '400',
210
+            'width'=> '100%',
211
+            'height'=> '425px',
212
+            'maptype'     => 'roadmap',
213
+            'zoom'     => '7',
214
+            'api_key'     => 'AIzaSyBK3ZcmK0ljxl5agNyJNQh_G24Thq1btuE',
215
+        );
216
+
217
+        /**
218
+         * Parse incoming $args into an array and merge it with $defaults
219
+         */
220
+        $args = wp_parse_args($args, $defaults );
221
+
222
+        $output = '';
223
+
224
+
225
+        // check if we have a global API key
226
+        $args['api_key'] = get_option( 'rgmk_google_map_api_key', false ) ? get_option( 'rgmk_google_map_api_key' ) : $args['api_key'];
227
+
228
+        if($args['type']=='image'){
229
+            $output .= "<img src='https://maps.googleapis.com/maps/api/staticmap?center=".esc_attr($args['location'])."&maptype=".esc_attr($args['maptype'])."&zoom=".esc_attr($args['zoom'])."&size=".esc_attr($args['static_width'])."x".esc_attr($args['static_height'])."&key=".esc_attr($args['api_key'])."' />";
230
+        }else{
231
+            $output .= "<iframe width='".esc_attr($args['width'])."' height='".esc_attr($args['height'])."' frameborder='0' allowfullscreen style='border:0;' src='https://www.google.com/maps/embed/v1/".esc_attr($args['type'])."?q=".esc_attr($args['location'])."&maptype=".esc_attr($args['maptype'])."&zoom=".esc_attr($args['zoom'])."&key=".esc_attr($args['api_key'])."' ></iframe> ";
232
+        }
233
+
234
+        return $output;
235
+
236
+    }
237 237
 
238 238
 }
239 239
 
240 240
 // register it.
241 241
 add_action( 'widgets_init', function () {
242
-	register_widget( 'SD_Map' );
242
+    register_widget( 'SD_Map' );
243 243
 } );
Please login to merge, or discard this patch.
includes/payments/class-getpaid-checkout.php 1 patch
Indentation   +310 added lines, -310 removed lines patch added patch discarded remove patch
@@ -12,185 +12,185 @@  discard block
 block discarded – undo
12 12
  */
13 13
 class GetPaid_Checkout {
14 14
 
15
-	/**
16
-	 * @var GetPaid_Payment_Form_Submission
17
-	 */
18
-	protected $payment_form_submission;
19
-
20
-	/**
21
-	 * Class constructor.
22
-	 *
23
-	 * @param GetPaid_Payment_Form_Submission $submission
24
-	 */
25
-	public function __construct( $submission ) {
26
-		$this->payment_form_submission = $submission;
27
-	}
28
-
29
-	/**
30
-	 * Processes the checkout.
31
-	 *
32
-	 */
33
-	public function process_checkout() {
34
-
35
-		// Validate the submission.
36
-		$this->validate_submission();
37
-
38
-		// Prepare the invoice.
39
-		$items    = $this->get_submission_items();
40
-		$invoice  = $this->get_submission_invoice();
41
-		$invoice  = $this->process_submission_invoice( $invoice, $items );
42
-		$prepared = $this->prepare_submission_data_for_saving();
43
-
44
-		$this->prepare_billing_info( $invoice );
45
-
46
-		$shipping   = $this->prepare_shipping_info( $invoice );
47
-
48
-		// Save the invoice.
49
-		$invoice->set_is_viewed( true );
50
-		$invoice->recalculate_total();
15
+    /**
16
+     * @var GetPaid_Payment_Form_Submission
17
+     */
18
+    protected $payment_form_submission;
19
+
20
+    /**
21
+     * Class constructor.
22
+     *
23
+     * @param GetPaid_Payment_Form_Submission $submission
24
+     */
25
+    public function __construct( $submission ) {
26
+        $this->payment_form_submission = $submission;
27
+    }
28
+
29
+    /**
30
+     * Processes the checkout.
31
+     *
32
+     */
33
+    public function process_checkout() {
34
+
35
+        // Validate the submission.
36
+        $this->validate_submission();
37
+
38
+        // Prepare the invoice.
39
+        $items    = $this->get_submission_items();
40
+        $invoice  = $this->get_submission_invoice();
41
+        $invoice  = $this->process_submission_invoice( $invoice, $items );
42
+        $prepared = $this->prepare_submission_data_for_saving();
43
+
44
+        $this->prepare_billing_info( $invoice );
45
+
46
+        $shipping   = $this->prepare_shipping_info( $invoice );
47
+
48
+        // Save the invoice.
49
+        $invoice->set_is_viewed( true );
50
+        $invoice->recalculate_total();
51 51
         $invoice->save();
52 52
 
53
-		do_action( 'getpaid_checkout_invoice_updated', $invoice );
53
+        do_action( 'getpaid_checkout_invoice_updated', $invoice );
54 54
 
55
-		// Send to the gateway.
56
-		$this->post_process_submission( $invoice, $prepared, $shipping );
57
-	}
55
+        // Send to the gateway.
56
+        $this->post_process_submission( $invoice, $prepared, $shipping );
57
+    }
58 58
 
59
-	/**
60
-	 * Validates the submission.
61
-	 *
62
-	 */
63
-	protected function validate_submission() {
59
+    /**
60
+     * Validates the submission.
61
+     *
62
+     */
63
+    protected function validate_submission() {
64 64
 
65
-		$submission = $this->payment_form_submission;
66
-		$data       = $submission->get_data();
65
+        $submission = $this->payment_form_submission;
66
+        $data       = $submission->get_data();
67 67
 
68
-		// Do we have an error?
68
+        // Do we have an error?
69 69
         if ( ! empty( $submission->last_error ) ) {
70
-			wp_send_json_error( $submission->last_error );
70
+            wp_send_json_error( $submission->last_error );
71 71
         }
72 72
 
73
-		// We need a billing email.
73
+        // We need a billing email.
74 74
         if ( ! $submission->has_billing_email() ) {
75 75
             wp_send_json_error( __( 'Provide a valid billing email.', 'invoicing' ) );
76
-		}
76
+        }
77 77
 
78
-		// Non-recurring gateways should not be allowed to process recurring invoices.
79
-		if ( $submission->should_collect_payment_details() && $submission->has_recurring && ! wpinv_gateway_support_subscription( $data['wpi-gateway'] ) ) {
80
-			wp_send_json_error( __( 'The selected payment gateway does not support subscription payments.', 'invoicing' ) );
81
-		}
78
+        // Non-recurring gateways should not be allowed to process recurring invoices.
79
+        if ( $submission->should_collect_payment_details() && $submission->has_recurring && ! wpinv_gateway_support_subscription( $data['wpi-gateway'] ) ) {
80
+            wp_send_json_error( __( 'The selected payment gateway does not support subscription payments.', 'invoicing' ) );
81
+        }
82 82
 
83
-		// Ensure the gateway is active.
84
-		if ( $submission->should_collect_payment_details() && ! wpinv_is_gateway_active( $data['wpi-gateway'] ) ) {
85
-			wp_send_json_error( __( 'The selected payment gateway is not active', 'invoicing' ) );
86
-		}
83
+        // Ensure the gateway is active.
84
+        if ( $submission->should_collect_payment_details() && ! wpinv_is_gateway_active( $data['wpi-gateway'] ) ) {
85
+            wp_send_json_error( __( 'The selected payment gateway is not active', 'invoicing' ) );
86
+        }
87 87
 
88
-		// Clear any existing errors.
89
-		wpinv_clear_errors();
88
+        // Clear any existing errors.
89
+        wpinv_clear_errors();
90 90
 
91
-		// Allow themes and plugins to hook to errors
92
-		do_action( 'getpaid_checkout_error_checks', $submission );
91
+        // Allow themes and plugins to hook to errors
92
+        do_action( 'getpaid_checkout_error_checks', $submission );
93 93
 
94
-		// Do we have any errors?
94
+        // Do we have any errors?
95 95
         if ( wpinv_get_errors() ) {
96 96
             wp_send_json_error( getpaid_get_errors_html() );
97
-		}
97
+        }
98 98
 
99
-	}
99
+    }
100 100
 
101
-	/**
102
-	 * Retrieves submission items.
103
-	 *
104
-	 * @return GetPaid_Form_Item[]
105
-	 */
106
-	protected function get_submission_items() {
101
+    /**
102
+     * Retrieves submission items.
103
+     *
104
+     * @return GetPaid_Form_Item[]
105
+     */
106
+    protected function get_submission_items() {
107 107
 
108
-		$items = $this->payment_form_submission->get_items();
108
+        $items = $this->payment_form_submission->get_items();
109 109
 
110 110
         // Ensure that we have items.
111 111
         if ( empty( $items ) && ! $this->payment_form_submission->has_fees() ) {
112 112
             wp_send_json_error( __( 'Please provide at least one item or amount.', 'invoicing' ) );
113
-		}
114
-
115
-		return $items;
116
-	}
117
-
118
-	/**
119
-	 * Retrieves submission invoice.
120
-	 *
121
-	 * @return WPInv_Invoice
122
-	 */
123
-	protected function get_submission_invoice() {
124
-		$submission = $this->payment_form_submission;
125
-
126
-		if ( ! $submission->has_invoice() ) {
127
-			$invoice = new WPInv_Invoice();
128
-			$invoice->set_created_via( 'payment_form' );
129
-			return $invoice;
130 113
         }
131 114
 
132
-		$invoice = $submission->get_invoice();
115
+        return $items;
116
+    }
117
+
118
+    /**
119
+     * Retrieves submission invoice.
120
+     *
121
+     * @return WPInv_Invoice
122
+     */
123
+    protected function get_submission_invoice() {
124
+        $submission = $this->payment_form_submission;
133 125
 
134
-		// Make sure that it is neither paid or refunded.
135
-		if ( $invoice->is_paid() || $invoice->is_refunded() ) {
136
-			wp_send_json_error( __( 'This invoice has already been paid for.', 'invoicing' ) );
137
-		}
126
+        if ( ! $submission->has_invoice() ) {
127
+            $invoice = new WPInv_Invoice();
128
+            $invoice->set_created_via( 'payment_form' );
129
+            return $invoice;
130
+        }
138 131
 
139
-		return $invoice;
140
-	}
132
+        $invoice = $submission->get_invoice();
141 133
 
142
-	/**
143
-	 * Processes the submission invoice.
144
-	 *
145
-	 * @param WPInv_Invoice $invoice
146
-	 * @param GetPaid_Form_Item[] $items
147
-	 * @return WPInv_Invoice
148
-	 */
149
-	protected function process_submission_invoice( $invoice, $items ) {
134
+        // Make sure that it is neither paid or refunded.
135
+        if ( $invoice->is_paid() || $invoice->is_refunded() ) {
136
+            wp_send_json_error( __( 'This invoice has already been paid for.', 'invoicing' ) );
137
+        }
150 138
 
151
-		$submission = $this->payment_form_submission;
139
+        return $invoice;
140
+    }
152 141
 
153
-		// Set-up the invoice details.
154
-		$invoice->set_email( sanitize_email( $submission->get_billing_email() ) );
155
-		$invoice->set_user_id( $this->get_submission_customer() );
156
-		$invoice->set_submission_id( $submission->id );
157
-		$invoice->set_payment_form( absint( $submission->get_payment_form()->get_id() ) );
142
+    /**
143
+     * Processes the submission invoice.
144
+     *
145
+     * @param WPInv_Invoice $invoice
146
+     * @param GetPaid_Form_Item[] $items
147
+     * @return WPInv_Invoice
148
+     */
149
+    protected function process_submission_invoice( $invoice, $items ) {
150
+
151
+        $submission = $this->payment_form_submission;
152
+
153
+        // Set-up the invoice details.
154
+        $invoice->set_email( sanitize_email( $submission->get_billing_email() ) );
155
+        $invoice->set_user_id( $this->get_submission_customer() );
156
+        $invoice->set_submission_id( $submission->id );
157
+        $invoice->set_payment_form( absint( $submission->get_payment_form()->get_id() ) );
158 158
         $invoice->set_items( $items );
159 159
         $invoice->set_fees( $submission->get_fees() );
160 160
         $invoice->set_taxes( $submission->get_taxes() );
161
-		$invoice->set_discounts( $submission->get_discounts() );
162
-		$invoice->set_gateway( $submission->get_field( 'wpi-gateway' ) );
163
-		$invoice->set_currency( $submission->get_currency() );
161
+        $invoice->set_discounts( $submission->get_discounts() );
162
+        $invoice->set_gateway( $submission->get_field( 'wpi-gateway' ) );
163
+        $invoice->set_currency( $submission->get_currency() );
164 164
 
165
-		if ( $submission->has_shipping() ) {
166
-			$invoice->set_shipping( $submission->get_shipping() );
167
-		}
165
+        if ( $submission->has_shipping() ) {
166
+            $invoice->set_shipping( $submission->get_shipping() );
167
+        }
168 168
 
169
-		$address_confirmed = $submission->get_field( 'confirm-address' );
170
-		$invoice->set_address_confirmed( ! empty( $address_confirmed ) );
169
+        $address_confirmed = $submission->get_field( 'confirm-address' );
170
+        $invoice->set_address_confirmed( ! empty( $address_confirmed ) );
171 171
 
172
-		if ( $submission->has_discount_code() ) {
172
+        if ( $submission->has_discount_code() ) {
173 173
             $invoice->set_discount_code( $submission->get_discount_code() );
174
-		}
175
-
176
-		getpaid_maybe_add_default_address( $invoice );
177
-		return $invoice;
178
-	}
179
-
180
-	/**
181
-	 * Retrieves the submission's customer.
182
-	 *
183
-	 * @return int The customer id.
184
-	 */
185
-	protected function get_submission_customer() {
186
-		$submission = $this->payment_form_submission;
187
-
188
-		// If this is an existing invoice...
189
-		if ( $submission->has_invoice() ) {
190
-			return $submission->get_invoice()->get_user_id();
191
-		}
192
-
193
-		// (Maybe) create the user.
174
+        }
175
+
176
+        getpaid_maybe_add_default_address( $invoice );
177
+        return $invoice;
178
+    }
179
+
180
+    /**
181
+     * Retrieves the submission's customer.
182
+     *
183
+     * @return int The customer id.
184
+     */
185
+    protected function get_submission_customer() {
186
+        $submission = $this->payment_form_submission;
187
+
188
+        // If this is an existing invoice...
189
+        if ( $submission->has_invoice() ) {
190
+            return $submission->get_invoice()->get_user_id();
191
+        }
192
+
193
+        // (Maybe) create the user.
194 194
         $user = get_current_user_id();
195 195
 
196 196
         if ( empty( $user ) ) {
@@ -198,16 +198,16 @@  discard block
 block discarded – undo
198 198
         }
199 199
 
200 200
         if ( empty( $user ) ) {
201
-			$name = array( $submission->get_field( 'wpinv_first_name', 'billing' ), $submission->get_field( 'wpinv_last_name', 'billing' ) );
202
-			$name = implode( '', array_filter( $name ) );
201
+            $name = array( $submission->get_field( 'wpinv_first_name', 'billing' ), $submission->get_field( 'wpinv_last_name', 'billing' ) );
202
+            $name = implode( '', array_filter( $name ) );
203 203
             $user = wpinv_create_user( $submission->get_billing_email(), $name );
204 204
 
205
-			// (Maybe) send new user notification.
206
-			$should_send_notification = wpinv_get_option( 'disable_new_user_emails' );
207
-			if ( ! empty( $user ) && is_numeric( $user ) && apply_filters( 'getpaid_send_new_user_notification', empty( $should_send_notification ), $user ) ) {
208
-				wp_send_new_user_notifications( $user, 'user' );
209
-			}
210
-		}
205
+            // (Maybe) send new user notification.
206
+            $should_send_notification = wpinv_get_option( 'disable_new_user_emails' );
207
+            if ( ! empty( $user ) && is_numeric( $user ) && apply_filters( 'getpaid_send_new_user_notification', empty( $should_send_notification ), $user ) ) {
208
+                wp_send_new_user_notifications( $user, 'user' );
209
+            }
210
+        }
211 211
 
212 212
         if ( is_wp_error( $user ) ) {
213 213
             wp_send_json_error( $user->get_error_message() );
@@ -215,49 +215,49 @@  discard block
 block discarded – undo
215 215
 
216 216
         if ( is_numeric( $user ) ) {
217 217
             return $user;
218
-		}
218
+        }
219 219
 
220
-		return $user->ID;
220
+        return $user->ID;
221 221
 
222
-	}
222
+    }
223 223
 
224
-	/**
224
+    /**
225 225
      * Prepares submission data for saving to the database.
226 226
      *
227
-	 * @return array
227
+     * @return array
228 228
      */
229 229
     public function prepare_submission_data_for_saving() {
230 230
 
231
-		$submission = $this->payment_form_submission;
231
+        $submission = $this->payment_form_submission;
232 232
 
233
-		// Prepared submission details.
233
+        // Prepared submission details.
234 234
         $prepared = array(
235
-			'all'  => array(),
236
-			'meta' => array(),
237
-		);
235
+            'all'  => array(),
236
+            'meta' => array(),
237
+        );
238 238
 
239 239
         // Raw submission details.
240
-		$data     = $submission->get_data();
240
+        $data     = $submission->get_data();
241 241
 
242
-		// Loop through the submitted details.
242
+        // Loop through the submitted details.
243 243
         foreach ( $submission->get_payment_form()->get_elements() as $field ) {
244 244
 
245
-			// Skip premade fields.
245
+            // Skip premade fields.
246 246
             if ( ! empty( $field['premade'] ) ) {
247 247
                 continue;
248 248
             }
249 249
 
250
-			// Ensure address is provided.
251
-			if ( 'address' === $field['type'] ) {
250
+            // Ensure address is provided.
251
+            if ( 'address' === $field['type'] ) {
252 252
                 $address_type = isset( $field['address_type'] ) && 'shipping' === $field['address_type'] ? 'shipping' : 'billing';
253 253
 
254
-				foreach ( $field['fields'] as $address_field ) {
254
+                foreach ( $field['fields'] as $address_field ) {
255 255
 
256
-					if ( ! empty( $address_field['visible'] ) && ! empty( $address_field['required'] ) && '' === trim( $_POST[ $address_type ][ $address_field['name'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
257
-						wp_send_json_error( __( 'Please fill all required fields.', 'invoicing' ) );
258
-					}
259
-			}
260
-		}
256
+                    if ( ! empty( $address_field['visible'] ) && ! empty( $address_field['required'] ) && '' === trim( $_POST[ $address_type ][ $address_field['name'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
257
+                        wp_send_json_error( __( 'Please fill all required fields.', 'invoicing' ) );
258
+                    }
259
+            }
260
+        }
261 261
 
262 262
             // If it is required and not set, abort.
263 263
             if ( ! $submission->is_required_field_set( $field ) ) {
@@ -267,31 +267,31 @@  discard block
 block discarded – undo
267 267
             // Handle misc fields.
268 268
             if ( isset( $data[ $field['id'] ] ) ) {
269 269
 
270
-				// Uploads.
271
-				if ( 'file_upload' === $field['type'] ) {
272
-					$max_file_num = empty( $field['max_file_num'] ) ? 1 : absint( $field['max_file_num'] );
270
+                // Uploads.
271
+                if ( 'file_upload' === $field['type'] ) {
272
+                    $max_file_num = empty( $field['max_file_num'] ) ? 1 : absint( $field['max_file_num'] );
273 273
 
274
-					if ( count( $data[ $field['id'] ] ) > $max_file_num ) {
275
-						wp_send_json_error( __( 'Maximum number of allowed files exceeded.', 'invoicing' ) );
276
-					}
274
+                    if ( count( $data[ $field['id'] ] ) > $max_file_num ) {
275
+                        wp_send_json_error( __( 'Maximum number of allowed files exceeded.', 'invoicing' ) );
276
+                    }
277 277
 
278
-					$value = array();
278
+                    $value = array();
279 279
 
280
-					foreach ( $data[ $field['id'] ] as $url => $name ) {
281
-						$value[] = sprintf(
282
-							'<a href="%s" target="_blank">%s</a>',
283
-							esc_url_raw( $url ),
284
-							esc_html( $name )
285
-						);
286
-					}
280
+                    foreach ( $data[ $field['id'] ] as $url => $name ) {
281
+                        $value[] = sprintf(
282
+                            '<a href="%s" target="_blank">%s</a>',
283
+                            esc_url_raw( $url ),
284
+                            esc_html( $name )
285
+                        );
286
+                    }
287 287
 
288
-					$value = implode( ' | ', $value );
288
+                    $value = implode( ' | ', $value );
289 289
 
290
-				} elseif ( 'checkbox' === $field['type'] ) {
291
-					$value = ! empty( $data[ $field['id'] ] ) ? __( 'Yes', 'invoicing' ) : __( 'No', 'invoicing' );
292
-				} else {
293
-					$value = wp_kses_post( $data[ $field['id'] ] );
294
-				}
290
+                } elseif ( 'checkbox' === $field['type'] ) {
291
+                    $value = ! empty( $data[ $field['id'] ] ) ? __( 'Yes', 'invoicing' ) : __( 'No', 'invoicing' );
292
+                } else {
293
+                    $value = wp_kses_post( $data[ $field['id'] ] );
294
+                }
295 295
 
296 296
                 $label = $field['id'];
297 297
 
@@ -299,192 +299,192 @@  discard block
 block discarded – undo
299 299
                     $label = $field['label'];
300 300
                 }
301 301
 
302
-				if ( ! empty( $field['add_meta'] ) ) {
303
-					$prepared['meta'][ wpinv_clean( $label ) ] = wp_kses_post_deep( $value );
304
-				}
305
-				$prepared['all'][ wpinv_clean( $label ) ] = wp_kses_post_deep( $value );
302
+                if ( ! empty( $field['add_meta'] ) ) {
303
+                    $prepared['meta'][ wpinv_clean( $label ) ] = wp_kses_post_deep( $value );
304
+                }
305
+                $prepared['all'][ wpinv_clean( $label ) ] = wp_kses_post_deep( $value );
306 306
 
307 307
             }
308
-		}
308
+        }
309 309
 
310
-		return $prepared;
310
+        return $prepared;
311 311
 
312
-	}
312
+    }
313 313
 
314
-	/**
314
+    /**
315 315
      * Retrieves address details.
316 316
      *
317
-	 * @return array
318
-	 * @param WPInv_Invoice $invoice
319
-	 * @param string $type
317
+     * @return array
318
+     * @param WPInv_Invoice $invoice
319
+     * @param string $type
320 320
      */
321 321
     public function prepare_address_details( $invoice, $type = 'billing' ) {
322 322
 
323
-		$data     = $this->payment_form_submission->get_data();
324
-		$type     = sanitize_key( $type );
325
-		$address  = array();
326
-		$prepared = array();
323
+        $data     = $this->payment_form_submission->get_data();
324
+        $type     = sanitize_key( $type );
325
+        $address  = array();
326
+        $prepared = array();
327 327
 
328
-		if ( ! empty( $data[ $type ] ) ) {
329
-			$address = $data[ $type ];
330
-		}
328
+        if ( ! empty( $data[ $type ] ) ) {
329
+            $address = $data[ $type ];
330
+        }
331 331
 
332
-		// Clean address details.
333
-		foreach ( $address as $key => $value ) {
334
-			$key             = sanitize_key( $key );
335
-			$key             = str_replace( 'wpinv_', '', $key );
336
-			$value           = wpinv_clean( $value );
337
-			$prepared[ $key ] = apply_filters( "getpaid_checkout_{$type}_address_$key", $value, $this->payment_form_submission, $invoice );
338
-		}
332
+        // Clean address details.
333
+        foreach ( $address as $key => $value ) {
334
+            $key             = sanitize_key( $key );
335
+            $key             = str_replace( 'wpinv_', '', $key );
336
+            $value           = wpinv_clean( $value );
337
+            $prepared[ $key ] = apply_filters( "getpaid_checkout_{$type}_address_$key", $value, $this->payment_form_submission, $invoice );
338
+        }
339 339
 
340
-		// Filter address details.
341
-		$prepared = apply_filters( "getpaid_checkout_{$type}_address", $prepared, $this->payment_form_submission, $invoice );
340
+        // Filter address details.
341
+        $prepared = apply_filters( "getpaid_checkout_{$type}_address", $prepared, $this->payment_form_submission, $invoice );
342 342
 
343
-		// Remove non-whitelisted values.
344
-		return array_filter( $prepared, 'getpaid_is_address_field_whitelisted', ARRAY_FILTER_USE_KEY );
343
+        // Remove non-whitelisted values.
344
+        return array_filter( $prepared, 'getpaid_is_address_field_whitelisted', ARRAY_FILTER_USE_KEY );
345 345
 
346
-	}
346
+    }
347 347
 
348
-	/**
348
+    /**
349 349
      * Prepares the billing details.
350 350
      *
351
-	 * @return array
352
-	 * @param WPInv_Invoice $invoice
351
+     * @return array
352
+     * @param WPInv_Invoice $invoice
353 353
      */
354 354
     protected function prepare_billing_info( &$invoice ) {
355 355
 
356
-		$billing_address = $this->prepare_address_details( $invoice, 'billing' );
356
+        $billing_address = $this->prepare_address_details( $invoice, 'billing' );
357 357
 
358
-		// Update the invoice with the billing details.
359
-		$invoice->set_props( $billing_address );
358
+        // Update the invoice with the billing details.
359
+        $invoice->set_props( $billing_address );
360 360
 
361
-	}
361
+    }
362 362
 
363
-	/**
363
+    /**
364 364
      * Prepares the shipping details.
365 365
      *
366
-	 * @return array
367
-	 * @param WPInv_Invoice $invoice
366
+     * @return array
367
+     * @param WPInv_Invoice $invoice
368 368
      */
369 369
     protected function prepare_shipping_info( $invoice ) {
370 370
 
371
-		$data = $this->payment_form_submission->get_data();
371
+        $data = $this->payment_form_submission->get_data();
372 372
 
373
-		if ( empty( $data['same-shipping-address'] ) ) {
374
-			return $this->prepare_address_details( $invoice, 'shipping' );
375
-		}
373
+        if ( empty( $data['same-shipping-address'] ) ) {
374
+            return $this->prepare_address_details( $invoice, 'shipping' );
375
+        }
376 376
 
377
-		return $this->prepare_address_details( $invoice, 'billing' );
377
+        return $this->prepare_address_details( $invoice, 'billing' );
378 378
 
379
-	}
379
+    }
380 380
 
381
-	/**
382
-	 * Confirms the submission is valid and send users to the gateway.
383
-	 *
384
-	 * @param WPInv_Invoice $invoice
385
-	 * @param array $prepared_payment_form_data
386
-	 * @param array $shipping
387
-	 */
388
-	protected function post_process_submission( $invoice, $prepared_payment_form_data, $shipping ) {
381
+    /**
382
+     * Confirms the submission is valid and send users to the gateway.
383
+     *
384
+     * @param WPInv_Invoice $invoice
385
+     * @param array $prepared_payment_form_data
386
+     * @param array $shipping
387
+     */
388
+    protected function post_process_submission( $invoice, $prepared_payment_form_data, $shipping ) {
389 389
 
390
-		// Ensure the invoice exists.
390
+        // Ensure the invoice exists.
391 391
         if ( ! $invoice->exists() ) {
392 392
             wp_send_json_error( __( 'An error occured while saving your invoice. Please try again.', 'invoicing' ) );
393 393
         }
394 394
 
395
-		// Save payment form data.
396
-		$prepared_payment_form_data = apply_filters( 'getpaid_prepared_payment_form_data', $prepared_payment_form_data, $invoice );
395
+        // Save payment form data.
396
+        $prepared_payment_form_data = apply_filters( 'getpaid_prepared_payment_form_data', $prepared_payment_form_data, $invoice );
397 397
         delete_post_meta( $invoice->get_id(), 'payment_form_data' );
398
-		delete_post_meta( $invoice->get_id(), 'additional_meta_data' );
399
-		if ( ! empty( $prepared_payment_form_data ) ) {
398
+        delete_post_meta( $invoice->get_id(), 'additional_meta_data' );
399
+        if ( ! empty( $prepared_payment_form_data ) ) {
400 400
 
401
-			if ( ! empty( $prepared_payment_form_data['all'] ) ) {
402
-				update_post_meta( $invoice->get_id(), 'payment_form_data', $prepared_payment_form_data['all'] );
403
-			}
401
+            if ( ! empty( $prepared_payment_form_data['all'] ) ) {
402
+                update_post_meta( $invoice->get_id(), 'payment_form_data', $prepared_payment_form_data['all'] );
403
+            }
404 404
 
405
-			if ( ! empty( $prepared_payment_form_data['meta'] ) ) {
406
-				update_post_meta( $invoice->get_id(), 'additional_meta_data', $prepared_payment_form_data['meta'] );
407
-			}
408
-		}
405
+            if ( ! empty( $prepared_payment_form_data['meta'] ) ) {
406
+                update_post_meta( $invoice->get_id(), 'additional_meta_data', $prepared_payment_form_data['meta'] );
407
+            }
408
+        }
409 409
 
410
-		// Save payment form data.
411
-		$shipping = apply_filters( 'getpaid_checkout_shipping_details', $shipping, $this->payment_form_submission );
410
+        // Save payment form data.
411
+        $shipping = apply_filters( 'getpaid_checkout_shipping_details', $shipping, $this->payment_form_submission );
412 412
         if ( ! empty( $shipping ) ) {
413 413
             update_post_meta( $invoice->get_id(), 'shipping_address', $shipping );
414
-		}
414
+        }
415 415
 
416
-		// Backwards compatibility.
416
+        // Backwards compatibility.
417 417
         add_filter( 'wp_redirect', array( $this, 'send_redirect_response' ) );
418 418
 
419
-		try {
420
-			$this->process_payment( $invoice );
421
-		} catch ( Exception $e ) {
422
-			wpinv_set_error( 'payment_error', $e->getMessage() );
423
-		}
419
+        try {
420
+            $this->process_payment( $invoice );
421
+        } catch ( Exception $e ) {
422
+            wpinv_set_error( 'payment_error', $e->getMessage() );
423
+        }
424 424
 
425 425
         // If we are here, there was an error.
426
-		wpinv_send_back_to_checkout( $invoice );
426
+        wpinv_send_back_to_checkout( $invoice );
427 427
 
428
-	}
428
+    }
429 429
 
430
-	/**
431
-	 * Processes the actual payment.
432
-	 *
433
-	 * @param WPInv_Invoice $invoice
434
-	 */
435
-	protected function process_payment( $invoice ) {
430
+    /**
431
+     * Processes the actual payment.
432
+     *
433
+     * @param WPInv_Invoice $invoice
434
+     */
435
+    protected function process_payment( $invoice ) {
436 436
 
437
-		// Clear any checkout errors.
438
-		wpinv_clear_errors();
437
+        // Clear any checkout errors.
438
+        wpinv_clear_errors();
439 439
 
440
-		// No need to send free invoices to the gateway.
441
-		if ( $invoice->is_free() ) {
442
-			$this->process_free_payment( $invoice );
443
-		}
440
+        // No need to send free invoices to the gateway.
441
+        if ( $invoice->is_free() ) {
442
+            $this->process_free_payment( $invoice );
443
+        }
444 444
 
445
-		$submission = $this->payment_form_submission;
445
+        $submission = $this->payment_form_submission;
446 446
 
447
-		// Fires before sending to the gateway.
448
-		do_action( 'getpaid_checkout_before_gateway', $invoice, $submission );
447
+        // Fires before sending to the gateway.
448
+        do_action( 'getpaid_checkout_before_gateway', $invoice, $submission );
449 449
 
450
-		// Allow the sumission data to be modified before it is sent to the gateway.
451
-		$submission_data    = $submission->get_data();
452
-		$submission_gateway = apply_filters( 'getpaid_gateway_submission_gateway', $invoice->get_gateway(), $submission, $invoice );
453
-		$submission_data    = apply_filters( 'getpaid_gateway_submission_data', $submission_data, $submission, $invoice );
450
+        // Allow the sumission data to be modified before it is sent to the gateway.
451
+        $submission_data    = $submission->get_data();
452
+        $submission_gateway = apply_filters( 'getpaid_gateway_submission_gateway', $invoice->get_gateway(), $submission, $invoice );
453
+        $submission_data    = apply_filters( 'getpaid_gateway_submission_data', $submission_data, $submission, $invoice );
454 454
 
455
-		// Validate the currency.
456
-		if ( ! apply_filters( "getpaid_gateway_{$submission_gateway}_is_valid_for_currency", true, $invoice->get_currency() ) ) {
457
-			wpinv_set_error( 'invalid_currency' );
458
-		}
455
+        // Validate the currency.
456
+        if ( ! apply_filters( "getpaid_gateway_{$submission_gateway}_is_valid_for_currency", true, $invoice->get_currency() ) ) {
457
+            wpinv_set_error( 'invalid_currency' );
458
+        }
459 459
 
460
-		// Check to see if we have any errors.
461
-		if ( wpinv_get_errors() ) {
462
-			wpinv_send_back_to_checkout( $invoice );
463
-		}
460
+        // Check to see if we have any errors.
461
+        if ( wpinv_get_errors() ) {
462
+            wpinv_send_back_to_checkout( $invoice );
463
+        }
464 464
 
465
-		// Send info to the gateway for payment processing
466
-		do_action( "getpaid_gateway_$submission_gateway", $invoice, $submission_data, $submission );
465
+        // Send info to the gateway for payment processing
466
+        do_action( "getpaid_gateway_$submission_gateway", $invoice, $submission_data, $submission );
467 467
 
468
-		// Backwards compatibility.
469
-		wpinv_send_to_gateway( $submission_gateway, $invoice );
468
+        // Backwards compatibility.
469
+        wpinv_send_to_gateway( $submission_gateway, $invoice );
470 470
 
471
-	}
471
+    }
472 472
 
473
-	/**
474
-	 * Marks the invoice as paid in case the checkout is free.
475
-	 *
476
-	 * @param WPInv_Invoice $invoice
477
-	 */
478
-	protected function process_free_payment( $invoice ) {
473
+    /**
474
+     * Marks the invoice as paid in case the checkout is free.
475
+     *
476
+     * @param WPInv_Invoice $invoice
477
+     */
478
+    protected function process_free_payment( $invoice ) {
479 479
 
480
-		$invoice->set_gateway( 'none' );
481
-		$invoice->add_note( __( "This is a free invoice and won't be sent to the payment gateway", 'invoicing' ), false, false, true );
482
-		$invoice->mark_paid();
483
-		wpinv_send_to_success_page( array( 'invoice_key' => $invoice->get_key() ) );
480
+        $invoice->set_gateway( 'none' );
481
+        $invoice->add_note( __( "This is a free invoice and won't be sent to the payment gateway", 'invoicing' ), false, false, true );
482
+        $invoice->mark_paid();
483
+        wpinv_send_to_success_page( array( 'invoice_key' => $invoice->get_key() ) );
484 484
 
485
-	}
485
+    }
486 486
 
487
-	/**
487
+    /**
488 488
      * Sends a redrect response to payment details.
489 489
      *
490 490
      */
Please login to merge, or discard this patch.
includes/api/class-getpaid-rest-date-based-controller.php 1 patch
Indentation   +491 added lines, -491 removed lines patch added patch discarded remove patch
@@ -16,496 +16,496 @@
 block discarded – undo
16 16
  */
17 17
 class GetPaid_REST_Date_Based_Controller extends GetPaid_REST_Controller {
18 18
 
19
-	/**
20
-	 * Group response items by day or month.
21
-	 *
22
-	 * @var string
23
-	 */
24
-	public $groupby = 'day';
25
-
26
-	/**
27
-	 * Returns an array with arguments to request the previous report.
28
-	 *
29
-	 * @var array
30
-	 */
31
-	public $previous_range = array();
32
-
33
-	/**
34
-	 * The period interval.
35
-	 *
36
-	 * @var int
37
-	 */
38
-	public $interval;
39
-
40
-	/**
41
-	 * Retrieves the before and after dates.
42
-	 *
43
-	 * @param WP_REST_Request $request Request object.
44
-	 * @return array The appropriate date range.
45
-	 */
46
-	public function get_date_range( $request ) {
47
-
48
-		// Check if the period is x_days.
49
-		if ( preg_match( '/^(\d+)_days$/', $request['period'], $matches ) ) {
50
-			$date_range = $this->get_x_days_date_range( absint( $matches[1] ) );
51
-		} elseif ( is_callable( array( $this, 'get_' . $request['period'] . '_date_range' ) ) ) {
52
-			$date_range = call_user_func( array( $this, 'get_' . $request['period'] . '_date_range' ), $request );
53
-		} else {
54
-			$request['period'] = '7_days';
55
-			$date_range        = $this->get_x_days_date_range();
56
-		}
57
-
58
-		// 3 months max for day view.
59
-		$before = strtotime( $date_range['before'] );
60
-		$after  = strtotime( $date_range['after'] );
61
-		if ( floor( ( $before - $after ) / MONTH_IN_SECONDS ) > 2 ) {
62
-			$this->groupby = 'month';
63
-		}
64
-
65
-		$this->prepare_interval( $date_range );
66
-
67
-		return $date_range;
68
-
69
-	}
70
-
71
-	/**
72
-	 * Groups by month or days.
73
-	 *
74
-	 * @param array $range Date range.
75
-	 * @return array The appropriate date range.
76
-	 */
77
-	public function prepare_interval( $range ) {
78
-
79
-		$before = strtotime( $range['before'] );
80
-		$after  = strtotime( $range['after'] );
81
-		if ( 'day' === $this->groupby ) {
82
-			$difference     = max( DAY_IN_SECONDS, ( DAY_IN_SECONDS + $before - $after ) ); // Prevent division by 0;
83
-			$this->interval = absint( ceil( max( 1, $difference / DAY_IN_SECONDS ) ) );
84
-			return;
85
-		}
86
-
87
-		$this->interval = 0;
88
-		$min_date       = strtotime( gmdate( 'Y-m-01', $after ) );
89
-
90
-		while ( $min_date <= $before ) {
91
-			$this->interval ++;
92
-			$min_date = strtotime( '+1 MONTH', $min_date );
93
-		}
94
-
95
-		$this->interval = max( 1, $this->interval );
96
-
97
-	}
98
-
99
-	/**
100
-	 * Retrieves a custom date range.
101
-	 *
102
-	 * @param WP_REST_Request $request Request object.
103
-	 * @return array The appropriate date range.
104
-	 */
105
-	public function get_custom_date_range( $request ) {
106
-
107
-		$after  = max( strtotime( '-20 years' ), strtotime( sanitize_text_field( $request['after'] ) ) );
108
-		$before = gmdate( 'Y-m-d' );
19
+    /**
20
+     * Group response items by day or month.
21
+     *
22
+     * @var string
23
+     */
24
+    public $groupby = 'day';
25
+
26
+    /**
27
+     * Returns an array with arguments to request the previous report.
28
+     *
29
+     * @var array
30
+     */
31
+    public $previous_range = array();
32
+
33
+    /**
34
+     * The period interval.
35
+     *
36
+     * @var int
37
+     */
38
+    public $interval;
39
+
40
+    /**
41
+     * Retrieves the before and after dates.
42
+     *
43
+     * @param WP_REST_Request $request Request object.
44
+     * @return array The appropriate date range.
45
+     */
46
+    public function get_date_range( $request ) {
47
+
48
+        // Check if the period is x_days.
49
+        if ( preg_match( '/^(\d+)_days$/', $request['period'], $matches ) ) {
50
+            $date_range = $this->get_x_days_date_range( absint( $matches[1] ) );
51
+        } elseif ( is_callable( array( $this, 'get_' . $request['period'] . '_date_range' ) ) ) {
52
+            $date_range = call_user_func( array( $this, 'get_' . $request['period'] . '_date_range' ), $request );
53
+        } else {
54
+            $request['period'] = '7_days';
55
+            $date_range        = $this->get_x_days_date_range();
56
+        }
57
+
58
+        // 3 months max for day view.
59
+        $before = strtotime( $date_range['before'] );
60
+        $after  = strtotime( $date_range['after'] );
61
+        if ( floor( ( $before - $after ) / MONTH_IN_SECONDS ) > 2 ) {
62
+            $this->groupby = 'month';
63
+        }
64
+
65
+        $this->prepare_interval( $date_range );
66
+
67
+        return $date_range;
68
+
69
+    }
70
+
71
+    /**
72
+     * Groups by month or days.
73
+     *
74
+     * @param array $range Date range.
75
+     * @return array The appropriate date range.
76
+     */
77
+    public function prepare_interval( $range ) {
78
+
79
+        $before = strtotime( $range['before'] );
80
+        $after  = strtotime( $range['after'] );
81
+        if ( 'day' === $this->groupby ) {
82
+            $difference     = max( DAY_IN_SECONDS, ( DAY_IN_SECONDS + $before - $after ) ); // Prevent division by 0;
83
+            $this->interval = absint( ceil( max( 1, $difference / DAY_IN_SECONDS ) ) );
84
+            return;
85
+        }
86
+
87
+        $this->interval = 0;
88
+        $min_date       = strtotime( gmdate( 'Y-m-01', $after ) );
89
+
90
+        while ( $min_date <= $before ) {
91
+            $this->interval ++;
92
+            $min_date = strtotime( '+1 MONTH', $min_date );
93
+        }
94
+
95
+        $this->interval = max( 1, $this->interval );
96
+
97
+    }
98
+
99
+    /**
100
+     * Retrieves a custom date range.
101
+     *
102
+     * @param WP_REST_Request $request Request object.
103
+     * @return array The appropriate date range.
104
+     */
105
+    public function get_custom_date_range( $request ) {
106
+
107
+        $after  = max( strtotime( '-20 years' ), strtotime( sanitize_text_field( $request['after'] ) ) );
108
+        $before = gmdate( 'Y-m-d' );
109 109
 		
110
-		if ( ! empty( $request['before'] ) ) {
111
-			$before  = min( strtotime( $before ), strtotime( sanitize_text_field( $request['before'] ) ) );
112
-		}
113
-
114
-		// Set the previous date range.
115
-		$difference           = $before - $after;
116
-		$this->previous_range = array(
117
-			'period' => 'custom',
118
-			'before' => gmdate( 'Y-m-d', $before - $difference - DAY_IN_SECONDS ),
119
-			'after'  => gmdate( 'Y-m-d', $after - $difference - DAY_IN_SECONDS ),
120
-		);
121
-
122
-		// Generate the report.
123
-		return array(
124
-			'before' => gmdate( 'Y-m-d', $before ),
125
-			'after'  => gmdate( 'Y-m-d', $after ),
126
-		);
127
-
128
-	}
129
-
130
-	/**
131
-	 * Retrieves todays date range.
132
-	 *
133
-	 * @return array The appropriate date range.
134
-	 */
135
-	public function get_today_date_range() {
136
-
137
-		// Set the previous date range.
138
-		$this->previous_range = array(
139
-			'period' => 'yesterday',
140
-		);
141
-
142
-		// Generate the report.
143
-		return array(
144
-			'before' => gmdate( 'Y-m-d' ),
145
-			'after'  => gmdate( 'Y-m-d' ),
146
-		);
147
-
148
-	}
149
-
150
-	/**
151
-	 * Retrieves yesterdays date range.
152
-	 *
153
-	 * @return array The appropriate date range.
154
-	 */
155
-	public function get_yesterday_date_range() {
156
-
157
-		// Set the previous date range.
158
-		$this->previous_range = array(
159
-			'period' => 'custom',
160
-			'before' => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
161
-			'after'  => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
162
-		);
163
-
164
-		// Generate the report.
165
-		return array(
166
-			'before' => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
167
-			'after'  => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
168
-		);
169
-
170
-	}
171
-
172
-	/**
173
-	 * Retrieves this week's date range.
174
-	 *
175
-	 * @return array The appropriate date range.
176
-	 */
177
-	public function get_week_date_range() {
178
-
179
-		// Set the previous date range.
180
-		$this->previous_range = array(
181
-			'period' => 'last_week',
182
-		);
183
-
184
-		// Generate the report.
185
-		$week_starts = absint( get_option( 'start_of_week' ) );
186
-		return array(
187
-			'before' => gmdate( 'Y-m-d' ),
188
-			'after'  => gmdate( 'Y-m-d', strtotime( 'next Sunday -' . ( 7 - $week_starts ) . ' days' ) ),
189
-		);
190
-	}
191
-
192
-	/**
193
-	 * Retrieves last week's date range.
194
-	 *
195
-	 * @return array The appropriate date range.
196
-	 */
197
-	public function get_last_week_date_range() {
198
-
199
-		$week_starts = absint( get_option( 'start_of_week' ) );
200
-		$week_starts = strtotime( 'last Sunday -' . ( 7 - $week_starts ) . ' days' );
201
-		$date_range  = array(
202
-			'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
203
-			'after'  => gmdate( 'Y-m-d', $week_starts ),
204
-		);
205
-
206
-		// Set the previous date range.
207
-		$week_starts          = $week_starts - 7 * DAY_IN_SECONDS;
208
-		$this->previous_range = array(
209
-			'period' => 'custom',
210
-			'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
211
-			'after'  => gmdate( 'Y-m-d', $week_starts ),
212
-		);
213
-
214
-		// Generate the report.
215
-		return $date_range;
216
-	}
217
-
218
-	/**
219
-	 * Retrieves last x days date range.
220
-	 *
221
-	 * @return array The appropriate date range.
222
-	 */
223
-	public function get_x_days_date_range( $days = 7 ) {
224
-
225
-		$days--;
226
-
227
-		$date_range  = array(
228
-			'before' => gmdate( 'Y-m-d' ),
229
-			'after'  => gmdate( 'Y-m-d', strtotime( "-$days days" ) ),
230
-		);
231
-
232
-		$days++;
233
-
234
-		// Set the previous date range.
235
-		$this->previous_range = array(
236
-			'period' => 'custom',
237
-			'before' => gmdate( 'Y-m-d', strtotime( $date_range['before'] ) - $days * DAY_IN_SECONDS ),
238
-			'after'  => gmdate( 'Y-m-d', strtotime( $date_range['after'] ) - $days * DAY_IN_SECONDS ),
239
-		);
240
-
241
-		// Generate the report.
242
-		return $date_range;
243
-	}
244
-
245
-	/**
246
-	 * Retrieves this month date range.
247
-	 *
248
-	 * @return array The appropriate date range.
249
-	 */
250
-	public function get_month_date_range() {
251
-
252
-		// Set the previous date range.
253
-		$this->previous_range = array(
254
-			'period' => 'last_month',
255
-		);
256
-
257
-		// Generate the report.
258
-		return array(
259
-			'after'  => gmdate( 'Y-m-01' ),
260
-			'before' => gmdate( 'Y-m-t' ),
261
-		);
262
-
263
-	}
264
-
265
-	/**
266
-	 * Retrieves last month's date range.
267
-	 *
268
-	 * @return array The appropriate date range.
269
-	 */
270
-	public function get_last_month_date_range() {
271
-
272
-		// Set the previous date range.
273
-		$this->previous_range = array(
274
-			'period' => 'custom',
275
-			'after'  => gmdate( 'Y-m-01', strtotime( '-2 months' ) ),
276
-			'before' => gmdate( 'Y-m-t', strtotime( '-2 months' ) ),
277
-		);
278
-
279
-		// Generate the report.
280
-		return array(
281
-			'after'  => gmdate( 'Y-m-01', strtotime( 'last month' ) ),
282
-			'before' => gmdate( 'Y-m-t', strtotime( 'last month' ) ),
283
-		);
284
-
285
-	}
286
-
287
-	/**
288
-	 * Retrieves this quarter date range.
289
-	 *
290
-	 * @return array The available quarters.
291
-	 */
292
-	public function get_quarters() {
293
-
294
-		$year      = (int) gmdate( 'Y' );
295
-		$last_year = (int) $year - 1;
296
-		return array(
297
-
298
-			// Third quarter of previous year: July 1st to September 30th
299
-			array(
300
-				'before' => "{$last_year}-09-30",
301
-				'after'  => "{$last_year}-07-01",
302
-			),
303
-
304
-			// Last quarter of previous year: October 1st to December 31st
305
-			array(
306
-				'before' => "{$last_year}-12-31",
307
-        		'after'  => "{$last_year}-10-01",
308
-			),
309
-
310
-			// First quarter: January 1st to March 31st
311
-			array(
312
-				'before' => "{$year}-03-31",
313
-				'after'  => "{$year}-01-01",
314
-			),
315
-
316
-			// Second quarter: April 1st to June 30th
317
-			array(
318
-				'before' => "{$year}-06-30",
319
-				'after'  => "{$year}-04-01",
320
-			),
321
-
322
-			// Third quarter: July 1st to September 30th
323
-			array(
324
-				'before' => "{$year}-09-30",
325
-				'after'  => "{$year}-07-01",
326
-			),
327
-
328
-			// Fourth quarter: October 1st to December 31st
329
-			array(
330
-				'before' => "{$year}-12-31",
331
-				'after'  => "{$year}-10-01",
332
-			),
333
-		);
334
-	}
335
-
336
-	/**
337
-	 * Retrieves the current quater.
338
-	 *
339
-	 * @return int The current quarter.
340
-	 */
341
-	public function get_quarter() {
342
-
343
-		$month    = (int) gmdate( 'n' );
344
-		$quarters = array( 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 );
345
-		return $quarters[ $month - 1 ];
346
-
347
-	}
348
-
349
-	/**
350
-	 * Retrieves this quarter date range.
351
-	 *
352
-	 * @return array The appropriate date range.
353
-	 */
354
-	public function get_quarter_date_range() {
355
-
356
-		// Set the previous date range.
357
-		$this->previous_range = array(
358
-			'period' => 'last_quarter',
359
-		);
360
-
361
-		// Generate the report.
362
-		$quarter  = $this->get_quarter();
363
-		$quarters = $this->get_quarters();
364
-		return $quarters[ $quarter + 1 ];
365
-
366
-	}
367
-
368
-	/**
369
-	 * Retrieves last quarter's date range.
370
-	 *
371
-	 * @return array The appropriate date range.
372
-	 */
373
-	public function get_last_quarter_date_range() {
374
-
375
-		$quarters = $this->get_quarters();
376
-		$quarter  = $this->get_quarter();
377
-
378
-		// Set the previous date range.
379
-		$this->previous_range = array_merge(
380
-			$quarters[ $quarter - 1 ],
381
-			array( 'period' => 'custom' )
382
-		);
383
-
384
-		// Generate the report.
385
-		return $quarters[ $quarter ];
386
-
387
-	}
388
-
389
-	/**
390
-	 * Retrieves this year date range.
391
-	 *
392
-	 * @return array The appropriate date range.
393
-	 */
394
-	public function get_year_date_range() {
395
-
396
-		// Set the previous date range.
397
-		$this->previous_range = array(
398
-			'period' => 'last_year',
399
-		);
400
-
401
-		// Generate the report.
402
-		return array(
403
-			'after'  => gmdate( 'Y-01-01' ),
404
-			'before' => gmdate( 'Y-12-31' ),
405
-		);
406
-
407
-	}
408
-
409
-	/**
410
-	 * Retrieves last year date range.
411
-	 *
412
-	 * @return array The appropriate date range.
413
-	 */
414
-	public function get_last_year_date_range() {
415
-
416
-		// Set the previous date range.
417
-		$this->previous_range = array(
418
-			'period' => 'custom',
419
-			'after'  => gmdate( 'Y-01-01', strtotime( '-2 years' ) ),
420
-			'before' => gmdate( 'Y-12-31', strtotime( '-2 years' ) ),
421
-		);
422
-
423
-		// Generate the report.
424
-		return array(
425
-			'after'  => gmdate( 'Y-01-01', strtotime( 'last year' ) ),
426
-			'before' => gmdate( 'Y-12-31', strtotime( 'last year' ) ),
427
-		);
428
-
429
-	}
430
-
431
-	/**
432
-	 * Prepare a the request date for SQL usage.
433
-	 *
434
-	 * @param WP_REST_Request $request Request object.
435
-	 * @param string $date_field The date field.
436
-	 * @return string The appropriate SQL.
437
-	 */
438
-	public function get_date_range_sql( $request, $date_field ) {
439
-		global $wpdb;
440
-
441
-		$sql = '1=1';
442
-		$range = $this->get_date_range( $request );
443
-
444
-		if ( ! empty( $range['after'] ) ) {
445
-			$sql .= ' AND ' . $wpdb->prepare(
446
-				"$date_field >= %s",
447
-				$range['after']
448
-			);
449
-		}
450
-
451
-		if ( ! empty( $range['before'] ) ) {
452
-			$sql .= ' AND ' . $wpdb->prepare(
453
-				"$date_field <= %s",
454
-				$range['before']
455
-			);
456
-		}
457
-
458
-		return $sql;
459
-
460
-	}
461
-
462
-	/**
463
-	 * Prepares a group by query.
464
-	 *
465
-	 * @param string $date_field The date field.
466
-	 * @return string The appropriate SQL.
467
-	 */
468
-	public function get_group_by_sql( $date_field ) {
469
-
470
-		if ( 'day' === $this->groupby ) {
471
-			return "YEAR($date_field), MONTH($date_field), DAY($date_field)";
472
-		}
473
-
474
-		return "YEAR($date_field), MONTH($date_field)";
475
-	}
476
-
477
-	/**
478
-	 * Get the query params for collections.
479
-	 *
480
-	 * @return array
481
-	 */
482
-	public function get_collection_params() {
483
-		return array(
484
-			'context' => $this->get_context_param( array( 'default' => 'view' ) ),
485
-			'period'  => array(
486
-				'description'       => __( 'Limit to results of a specific period.', 'invoicing' ),
487
-				'type'              => 'string',
488
-				'enum'              => array( 'custom', 'today', 'yesterday', 'week', 'last_week', '7_days', '30_days', '60_days', '90_days', '180_days', 'month', 'last_month', 'quarter', 'last_quarter', 'year', 'last_year', 'quarter', 'last_quarter' ),
489
-				'validate_callback' => 'rest_validate_request_arg',
490
-				'sanitize_callback' => 'sanitize_text_field',
491
-				'default'           => '7_days',
492
-			),
493
-			'after'   => array(
494
-				/* translators: %s: date format */
495
-				'description'       => sprintf( __( 'Limit to results after a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
496
-				'type'              => 'string',
497
-				'validate_callback' => 'rest_validate_request_arg',
498
-				'sanitize_callback' => 'sanitize_text_field',
499
-				'default'           => gmdate( 'Y-m-d', strtotime( '-7 days' ) ),
500
-			),
501
-			'before'  => array(
502
-				/* translators: %s: date format */
503
-				'description'       => sprintf( __( 'Limit to results before a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
504
-				'type'              => 'string',
505
-				'validate_callback' => 'rest_validate_request_arg',
506
-				'sanitize_callback' => 'sanitize_text_field',
507
-				'default'           => gmdate( 'Y-m-d' ),
508
-			),
509
-		);
510
-	}
110
+        if ( ! empty( $request['before'] ) ) {
111
+            $before  = min( strtotime( $before ), strtotime( sanitize_text_field( $request['before'] ) ) );
112
+        }
113
+
114
+        // Set the previous date range.
115
+        $difference           = $before - $after;
116
+        $this->previous_range = array(
117
+            'period' => 'custom',
118
+            'before' => gmdate( 'Y-m-d', $before - $difference - DAY_IN_SECONDS ),
119
+            'after'  => gmdate( 'Y-m-d', $after - $difference - DAY_IN_SECONDS ),
120
+        );
121
+
122
+        // Generate the report.
123
+        return array(
124
+            'before' => gmdate( 'Y-m-d', $before ),
125
+            'after'  => gmdate( 'Y-m-d', $after ),
126
+        );
127
+
128
+    }
129
+
130
+    /**
131
+     * Retrieves todays date range.
132
+     *
133
+     * @return array The appropriate date range.
134
+     */
135
+    public function get_today_date_range() {
136
+
137
+        // Set the previous date range.
138
+        $this->previous_range = array(
139
+            'period' => 'yesterday',
140
+        );
141
+
142
+        // Generate the report.
143
+        return array(
144
+            'before' => gmdate( 'Y-m-d' ),
145
+            'after'  => gmdate( 'Y-m-d' ),
146
+        );
147
+
148
+    }
149
+
150
+    /**
151
+     * Retrieves yesterdays date range.
152
+     *
153
+     * @return array The appropriate date range.
154
+     */
155
+    public function get_yesterday_date_range() {
156
+
157
+        // Set the previous date range.
158
+        $this->previous_range = array(
159
+            'period' => 'custom',
160
+            'before' => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
161
+            'after'  => gmdate( 'Y-m-d', strtotime( '-2 days' ) ),
162
+        );
163
+
164
+        // Generate the report.
165
+        return array(
166
+            'before' => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
167
+            'after'  => gmdate( 'Y-m-d', strtotime( '-1 day' ) ),
168
+        );
169
+
170
+    }
171
+
172
+    /**
173
+     * Retrieves this week's date range.
174
+     *
175
+     * @return array The appropriate date range.
176
+     */
177
+    public function get_week_date_range() {
178
+
179
+        // Set the previous date range.
180
+        $this->previous_range = array(
181
+            'period' => 'last_week',
182
+        );
183
+
184
+        // Generate the report.
185
+        $week_starts = absint( get_option( 'start_of_week' ) );
186
+        return array(
187
+            'before' => gmdate( 'Y-m-d' ),
188
+            'after'  => gmdate( 'Y-m-d', strtotime( 'next Sunday -' . ( 7 - $week_starts ) . ' days' ) ),
189
+        );
190
+    }
191
+
192
+    /**
193
+     * Retrieves last week's date range.
194
+     *
195
+     * @return array The appropriate date range.
196
+     */
197
+    public function get_last_week_date_range() {
198
+
199
+        $week_starts = absint( get_option( 'start_of_week' ) );
200
+        $week_starts = strtotime( 'last Sunday -' . ( 7 - $week_starts ) . ' days' );
201
+        $date_range  = array(
202
+            'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
203
+            'after'  => gmdate( 'Y-m-d', $week_starts ),
204
+        );
205
+
206
+        // Set the previous date range.
207
+        $week_starts          = $week_starts - 7 * DAY_IN_SECONDS;
208
+        $this->previous_range = array(
209
+            'period' => 'custom',
210
+            'before' => gmdate( 'Y-m-d', $week_starts + 6 * DAY_IN_SECONDS ),
211
+            'after'  => gmdate( 'Y-m-d', $week_starts ),
212
+        );
213
+
214
+        // Generate the report.
215
+        return $date_range;
216
+    }
217
+
218
+    /**
219
+     * Retrieves last x days date range.
220
+     *
221
+     * @return array The appropriate date range.
222
+     */
223
+    public function get_x_days_date_range( $days = 7 ) {
224
+
225
+        $days--;
226
+
227
+        $date_range  = array(
228
+            'before' => gmdate( 'Y-m-d' ),
229
+            'after'  => gmdate( 'Y-m-d', strtotime( "-$days days" ) ),
230
+        );
231
+
232
+        $days++;
233
+
234
+        // Set the previous date range.
235
+        $this->previous_range = array(
236
+            'period' => 'custom',
237
+            'before' => gmdate( 'Y-m-d', strtotime( $date_range['before'] ) - $days * DAY_IN_SECONDS ),
238
+            'after'  => gmdate( 'Y-m-d', strtotime( $date_range['after'] ) - $days * DAY_IN_SECONDS ),
239
+        );
240
+
241
+        // Generate the report.
242
+        return $date_range;
243
+    }
244
+
245
+    /**
246
+     * Retrieves this month date range.
247
+     *
248
+     * @return array The appropriate date range.
249
+     */
250
+    public function get_month_date_range() {
251
+
252
+        // Set the previous date range.
253
+        $this->previous_range = array(
254
+            'period' => 'last_month',
255
+        );
256
+
257
+        // Generate the report.
258
+        return array(
259
+            'after'  => gmdate( 'Y-m-01' ),
260
+            'before' => gmdate( 'Y-m-t' ),
261
+        );
262
+
263
+    }
264
+
265
+    /**
266
+     * Retrieves last month's date range.
267
+     *
268
+     * @return array The appropriate date range.
269
+     */
270
+    public function get_last_month_date_range() {
271
+
272
+        // Set the previous date range.
273
+        $this->previous_range = array(
274
+            'period' => 'custom',
275
+            'after'  => gmdate( 'Y-m-01', strtotime( '-2 months' ) ),
276
+            'before' => gmdate( 'Y-m-t', strtotime( '-2 months' ) ),
277
+        );
278
+
279
+        // Generate the report.
280
+        return array(
281
+            'after'  => gmdate( 'Y-m-01', strtotime( 'last month' ) ),
282
+            'before' => gmdate( 'Y-m-t', strtotime( 'last month' ) ),
283
+        );
284
+
285
+    }
286
+
287
+    /**
288
+     * Retrieves this quarter date range.
289
+     *
290
+     * @return array The available quarters.
291
+     */
292
+    public function get_quarters() {
293
+
294
+        $year      = (int) gmdate( 'Y' );
295
+        $last_year = (int) $year - 1;
296
+        return array(
297
+
298
+            // Third quarter of previous year: July 1st to September 30th
299
+            array(
300
+                'before' => "{$last_year}-09-30",
301
+                'after'  => "{$last_year}-07-01",
302
+            ),
303
+
304
+            // Last quarter of previous year: October 1st to December 31st
305
+            array(
306
+                'before' => "{$last_year}-12-31",
307
+                'after'  => "{$last_year}-10-01",
308
+            ),
309
+
310
+            // First quarter: January 1st to March 31st
311
+            array(
312
+                'before' => "{$year}-03-31",
313
+                'after'  => "{$year}-01-01",
314
+            ),
315
+
316
+            // Second quarter: April 1st to June 30th
317
+            array(
318
+                'before' => "{$year}-06-30",
319
+                'after'  => "{$year}-04-01",
320
+            ),
321
+
322
+            // Third quarter: July 1st to September 30th
323
+            array(
324
+                'before' => "{$year}-09-30",
325
+                'after'  => "{$year}-07-01",
326
+            ),
327
+
328
+            // Fourth quarter: October 1st to December 31st
329
+            array(
330
+                'before' => "{$year}-12-31",
331
+                'after'  => "{$year}-10-01",
332
+            ),
333
+        );
334
+    }
335
+
336
+    /**
337
+     * Retrieves the current quater.
338
+     *
339
+     * @return int The current quarter.
340
+     */
341
+    public function get_quarter() {
342
+
343
+        $month    = (int) gmdate( 'n' );
344
+        $quarters = array( 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4 );
345
+        return $quarters[ $month - 1 ];
346
+
347
+    }
348
+
349
+    /**
350
+     * Retrieves this quarter date range.
351
+     *
352
+     * @return array The appropriate date range.
353
+     */
354
+    public function get_quarter_date_range() {
355
+
356
+        // Set the previous date range.
357
+        $this->previous_range = array(
358
+            'period' => 'last_quarter',
359
+        );
360
+
361
+        // Generate the report.
362
+        $quarter  = $this->get_quarter();
363
+        $quarters = $this->get_quarters();
364
+        return $quarters[ $quarter + 1 ];
365
+
366
+    }
367
+
368
+    /**
369
+     * Retrieves last quarter's date range.
370
+     *
371
+     * @return array The appropriate date range.
372
+     */
373
+    public function get_last_quarter_date_range() {
374
+
375
+        $quarters = $this->get_quarters();
376
+        $quarter  = $this->get_quarter();
377
+
378
+        // Set the previous date range.
379
+        $this->previous_range = array_merge(
380
+            $quarters[ $quarter - 1 ],
381
+            array( 'period' => 'custom' )
382
+        );
383
+
384
+        // Generate the report.
385
+        return $quarters[ $quarter ];
386
+
387
+    }
388
+
389
+    /**
390
+     * Retrieves this year date range.
391
+     *
392
+     * @return array The appropriate date range.
393
+     */
394
+    public function get_year_date_range() {
395
+
396
+        // Set the previous date range.
397
+        $this->previous_range = array(
398
+            'period' => 'last_year',
399
+        );
400
+
401
+        // Generate the report.
402
+        return array(
403
+            'after'  => gmdate( 'Y-01-01' ),
404
+            'before' => gmdate( 'Y-12-31' ),
405
+        );
406
+
407
+    }
408
+
409
+    /**
410
+     * Retrieves last year date range.
411
+     *
412
+     * @return array The appropriate date range.
413
+     */
414
+    public function get_last_year_date_range() {
415
+
416
+        // Set the previous date range.
417
+        $this->previous_range = array(
418
+            'period' => 'custom',
419
+            'after'  => gmdate( 'Y-01-01', strtotime( '-2 years' ) ),
420
+            'before' => gmdate( 'Y-12-31', strtotime( '-2 years' ) ),
421
+        );
422
+
423
+        // Generate the report.
424
+        return array(
425
+            'after'  => gmdate( 'Y-01-01', strtotime( 'last year' ) ),
426
+            'before' => gmdate( 'Y-12-31', strtotime( 'last year' ) ),
427
+        );
428
+
429
+    }
430
+
431
+    /**
432
+     * Prepare a the request date for SQL usage.
433
+     *
434
+     * @param WP_REST_Request $request Request object.
435
+     * @param string $date_field The date field.
436
+     * @return string The appropriate SQL.
437
+     */
438
+    public function get_date_range_sql( $request, $date_field ) {
439
+        global $wpdb;
440
+
441
+        $sql = '1=1';
442
+        $range = $this->get_date_range( $request );
443
+
444
+        if ( ! empty( $range['after'] ) ) {
445
+            $sql .= ' AND ' . $wpdb->prepare(
446
+                "$date_field >= %s",
447
+                $range['after']
448
+            );
449
+        }
450
+
451
+        if ( ! empty( $range['before'] ) ) {
452
+            $sql .= ' AND ' . $wpdb->prepare(
453
+                "$date_field <= %s",
454
+                $range['before']
455
+            );
456
+        }
457
+
458
+        return $sql;
459
+
460
+    }
461
+
462
+    /**
463
+     * Prepares a group by query.
464
+     *
465
+     * @param string $date_field The date field.
466
+     * @return string The appropriate SQL.
467
+     */
468
+    public function get_group_by_sql( $date_field ) {
469
+
470
+        if ( 'day' === $this->groupby ) {
471
+            return "YEAR($date_field), MONTH($date_field), DAY($date_field)";
472
+        }
473
+
474
+        return "YEAR($date_field), MONTH($date_field)";
475
+    }
476
+
477
+    /**
478
+     * Get the query params for collections.
479
+     *
480
+     * @return array
481
+     */
482
+    public function get_collection_params() {
483
+        return array(
484
+            'context' => $this->get_context_param( array( 'default' => 'view' ) ),
485
+            'period'  => array(
486
+                'description'       => __( 'Limit to results of a specific period.', 'invoicing' ),
487
+                'type'              => 'string',
488
+                'enum'              => array( 'custom', 'today', 'yesterday', 'week', 'last_week', '7_days', '30_days', '60_days', '90_days', '180_days', 'month', 'last_month', 'quarter', 'last_quarter', 'year', 'last_year', 'quarter', 'last_quarter' ),
489
+                'validate_callback' => 'rest_validate_request_arg',
490
+                'sanitize_callback' => 'sanitize_text_field',
491
+                'default'           => '7_days',
492
+            ),
493
+            'after'   => array(
494
+                /* translators: %s: date format */
495
+                'description'       => sprintf( __( 'Limit to results after a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
496
+                'type'              => 'string',
497
+                'validate_callback' => 'rest_validate_request_arg',
498
+                'sanitize_callback' => 'sanitize_text_field',
499
+                'default'           => gmdate( 'Y-m-d', strtotime( '-7 days' ) ),
500
+            ),
501
+            'before'  => array(
502
+                /* translators: %s: date format */
503
+                'description'       => sprintf( __( 'Limit to results before a specific date, the date needs to be in the %s format.', 'invoicing' ), 'YYYY-MM-DD' ),
504
+                'type'              => 'string',
505
+                'validate_callback' => 'rest_validate_request_arg',
506
+                'sanitize_callback' => 'sanitize_text_field',
507
+                'default'           => gmdate( 'Y-m-d' ),
508
+            ),
509
+        );
510
+    }
511 511
 }
Please login to merge, or discard this patch.
includes/api/class-getpaid-rest-report-sales-controller.php 1 patch
Indentation   +679 added lines, -679 removed lines patch added patch discarded remove patch
@@ -18,688 +18,688 @@
 block discarded – undo
18 18
  */
19 19
 class GetPaid_REST_Report_Sales_Controller extends GetPaid_REST_Date_Based_Controller {
20 20
 
21
-	/**
22
-	 * Route base.
23
-	 *
24
-	 * @var string
25
-	 */
26
-	protected $rest_base = 'reports/sales';
27
-
28
-	/**
29
-	 * The report data.
30
-	 *
31
-	 * @var stdClass
32
-	 */
33
-	public $report_data;
34
-
35
-	/**
36
-	 * The report range.
37
-	 *
38
-	 * @var array
39
-	 */
40
-	public $report_range;
41
-
42
-	/**
43
-	 * Registers the routes for the objects of the controller.
44
-	 *
45
-	 * @since 2.0.0
46
-	 *
47
-	 * @see register_rest_route()
48
-	 */
49
-	public function register_namespace_routes( $namespace ) {
50
-
51
-		// Get sales report.
52
-		register_rest_route(
53
-			$namespace,
54
-			$this->rest_base,
55
-			array(
56
-				array(
57
-					'methods'             => WP_REST_Server::READABLE,
58
-					'callback'            => array( $this, 'get_items' ),
59
-					'permission_callback' => array( $this, 'get_items_permissions_check' ),
60
-					'args'                => $this->get_collection_params(),
61
-				),
62
-				'schema' => array( $this, 'get_public_item_schema' ),
63
-			)
64
-		);
65
-
66
-	}
67
-
68
-	/**
69
-	 * Makes sure the current user has access to READ the report APIs.
70
-	 *
71
-	 * @since  2.0.0
72
-	 * @param WP_REST_Request $request Full data about the request.
73
-	 * @return WP_Error|boolean
74
-	 */
75
-	public function get_items_permissions_check( $request ) {
76
-
77
-		if ( ! wpinv_current_user_can_manage_invoicing() ) {
78
-			return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
79
-		}
80
-
81
-		return true;
82
-	}
83
-
84
-	/**
85
-	 * Get sales reports.
86
-	 *
87
-	 * @param WP_REST_Request $request
88
-	 * @return array|WP_Error
89
-	 */
90
-	public function get_items( $request ) {
91
-		$data   = array();
92
-		$item   = $this->prepare_item_for_response( null, $request );
93
-		$data[] = $this->prepare_response_for_collection( $item );
94
-
95
-		return rest_ensure_response( $data );
96
-	}
97
-
98
-	/**
99
-	 * Prepare a report sales object for serialization.
100
-	 *
101
-	 * @param null $_
102
-	 * @param WP_REST_Request $request Request object.
103
-	 * @return WP_REST_Response $response Response data.
104
-	 */
105
-	public function prepare_item_for_response( $_, $request ) {
106
-
107
-		// Set report range.
108
-		$this->report_range = $this->get_date_range( $request );
109
-
110
-		$report_data     = $this->get_report_data();
111
-		$period_totals   = array();
112
-
113
-		// Setup period totals by ensuring each period in the interval has data.
114
-		$start_date      = strtotime( $this->report_range['after'] );
115
-
116
-		if ( 'month' === $this->groupby ) {
117
-			$start_date      = strtotime( gmdate( 'Y-m-01', $start_date ) );
118
-		}
119
-
120
-		for ( $i = 0; $i < $this->interval; $i++ ) {
121
-
122
-			switch ( $this->groupby ) {
123
-				case 'day':
124
-					$time = gmdate( 'Y-m-d', strtotime( "+{$i} DAY", $start_date ) );
125
-					break;
126
-				default:
127
-					$time = gmdate( 'Y-m', strtotime( "+{$i} MONTH", $start_date ) );
128
-					break;
129
-			}
130
-
131
-			// Set the defaults for each period.
132
-			$period_totals[ $time ] = array(
133
-				'invoices'          => 0,
134
-				'items'             => 0,
135
-				'refunded_items'    => 0,
136
-				'refunded_tax'      => wpinv_round_amount( 0.00 ),
137
-				'subtotal'          => wpinv_round_amount( 0.00 ),
138
-				'refunded_subtotal' => wpinv_round_amount( 0.00 ),
139
-				'refunded_fees'     => wpinv_round_amount( 0.00 ),
140
-				'discount'          => wpinv_round_amount( 0.00 ),
141
-			);
142
-
143
-			foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
144
-				if ( ! isset( $period_totals[ $time ][ $key ] ) ) {
145
-					$period_totals[ $time ][ $key ] = wpinv_round_amount( 0.00 );
146
-				}
147
-			}
148
-		}
149
-
150
-		// add total sales, total invoice count, total tax for each period
151
-		$date_format = ( 'day' === $this->groupby ) ? 'Y-m-d' : 'Y-m';
152
-		foreach ( $report_data->invoices as $invoice ) {
153
-			$time = gmdate( $date_format, strtotime( $invoice->post_date ) );
154
-
155
-			if ( ! isset( $period_totals[ $time ] ) ) {
156
-				continue;
157
-			}
158
-
159
-			$period_totals[ $time ]['sales']    = wpinv_round_amount( $invoice->total_sales );
160
-			$period_totals[ $time ]['tax']      = wpinv_round_amount( $invoice->total_tax );
161
-			$period_totals[ $time ]['subtotal'] = wpinv_round_amount( $invoice->subtotal );
162
-			$period_totals[ $time ]['fees']     = wpinv_round_amount( $invoice->total_fees );
163
-
164
-		}
165
-
166
-		foreach ( $report_data->refunds as $invoice ) {
167
-			$time = gmdate( $date_format, strtotime( $invoice->post_date ) );
168
-
169
-			if ( ! isset( $period_totals[ $time ] ) ) {
170
-				continue;
171
-			}
172
-
173
-			$period_totals[ $time ]['refunds']           = wpinv_round_amount( $invoice->total_sales );
174
-			$period_totals[ $time ]['refunded_tax']      = wpinv_round_amount( $invoice->total_tax );
175
-			$period_totals[ $time ]['refunded_subtotal'] = wpinv_round_amount( $invoice->subtotal );
176
-			$period_totals[ $time ]['refunded_fees']     = wpinv_round_amount( $invoice->total_fees );
177
-
178
-		}
179
-
180
-		foreach ( $report_data->invoice_counts as $invoice ) {
181
-			$time = gmdate( $date_format, strtotime( $invoice->post_date ) );
182
-
183
-			if ( isset( $period_totals[ $time ] ) ) {
184
-				$period_totals[ $time ]['invoices']   = (int) $invoice->count;
185
-			}
186
-		}
187
-
188
-		// Add total invoice items for each period.
189
-		foreach ( $report_data->invoice_items as $invoice_item ) {
190
-			$time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $invoice_item->post_date ) ) : gmdate( 'Y-m', strtotime( $invoice_item->post_date ) );
191
-
192
-			if ( isset( $period_totals[ $time ] ) ) {
193
-				$period_totals[ $time ]['items'] = (int) $invoice_item->invoice_item_count;
194
-			}
195
-		}
196
-
197
-		// Add total discount for each period.
198
-		foreach ( $report_data->coupons as $discount ) {
199
-			$time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $discount->post_date ) ) : gmdate( 'Y-m', strtotime( $discount->post_date ) );
200
-
201
-			if ( isset( $period_totals[ $time ] ) ) {
202
-				$period_totals[ $time ]['discount'] = wpinv_round_amount( $discount->discount_amount );
203
-			}
204
-		}
205
-
206
-		// Extra fields.
207
-		foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
208
-
209
-			// Abort unprepared.
210
-			if ( ! isset( $report_data->$key ) ) {
211
-				continue;
212
-			} 
213
-
214
-			// Abort defaults.
215
-			if ( in_array( $key, array( 'sales', 'refunds', 'tax', 'fees', 'discount', 'invoices', 'items' ) ) ) {
216
-				continue;
217
-			}
218
-
219
-			// Set values.
220
-			foreach ( $report_data->$key as $item ) {
221
-				$time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $item->date ) ) : gmdate( 'Y-m', strtotime( $item->date ) );
222
-
223
-				if ( isset( $period_totals[ $time ] ) ) {
224
-					$period_totals[ $time ][ $key ] = wpinv_round_amount( $item->val );
225
-				}
226
-			}
227
-
228
-			unset( $report_data->$key );
229
-		}
230
-
231
-		$report_data->totals            = $period_totals;
232
-		$report_data->grouped_by        = $this->groupby;
233
-		$report_data->interval          = max( $this->interval, 1 );
234
-		$report_data->currency          = wpinv_get_currency();
235
-		$report_data->currency_symbol   = wpinv_currency_symbol();
236
-		$report_data->currency_position = wpinv_currency_position();
237
-		$report_data->decimal_places    = wpinv_decimals();
238
-		$report_data->thousands_sep     = wpinv_thousands_separator();
239
-		$report_data->decimals_sep      = wpinv_decimal_separator();
240
-		$report_data->start_date        = gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) );
241
-		$report_data->end_date          = gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) );
242
-		$report_data->start_date_locale = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) ) );
243
-		$report_data->end_date_locale   = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) ) );
244
-		$report_data->decimals_sep      = wpinv_decimal_separator();
245
-
246
-		$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
247
-		$data    = $report_data;
248
-		unset( $data->invoice_counts, $data->invoices, $data->coupons, $data->refunds, $data->invoice_items );
249
-		$data    = $this->add_additional_fields_to_object( (array) $data, $request );
250
-		$data    = $this->filter_response_by_context( $data, $context );
251
-
252
-		// Wrap the data in a response object.
253
-		$response = rest_ensure_response( $data );
254
-		$response->add_links(
21
+    /**
22
+     * Route base.
23
+     *
24
+     * @var string
25
+     */
26
+    protected $rest_base = 'reports/sales';
27
+
28
+    /**
29
+     * The report data.
30
+     *
31
+     * @var stdClass
32
+     */
33
+    public $report_data;
34
+
35
+    /**
36
+     * The report range.
37
+     *
38
+     * @var array
39
+     */
40
+    public $report_range;
41
+
42
+    /**
43
+     * Registers the routes for the objects of the controller.
44
+     *
45
+     * @since 2.0.0
46
+     *
47
+     * @see register_rest_route()
48
+     */
49
+    public function register_namespace_routes( $namespace ) {
50
+
51
+        // Get sales report.
52
+        register_rest_route(
53
+            $namespace,
54
+            $this->rest_base,
255 55
             array(
256
-				'about' => array(
257
-					'href' => rest_url( sprintf( '%s/reports', $this->namespace ) ),
258
-				),
56
+                array(
57
+                    'methods'             => WP_REST_Server::READABLE,
58
+                    'callback'            => array( $this, 'get_items' ),
59
+                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
60
+                    'args'                => $this->get_collection_params(),
61
+                ),
62
+                'schema' => array( $this, 'get_public_item_schema' ),
259 63
             )
260 64
         );
261 65
 
262
-		return apply_filters( 'getpaid_rest_prepare_report_sales', $response, $report_data, $request );
263
-	}
264
-
265
-	/**
266
-	 * Get report data.
267
-	 *
268
-	 * @return stdClass
269
-	 */
270
-	public function get_report_data() {
271
-		if ( empty( $this->report_data ) ) {
272
-			$this->query_report_data();
273
-		}
274
-		return $this->report_data;
275
-	}
276
-
277
-	/**
278
-	 * Get all data needed for this report and store in the class.
279
-	 */
280
-	protected function query_report_data() {
281
-
282
-		// Prepare reports.
283
-		$this->report_data = (object) array(
284
-			'invoice_counts' => $this->query_invoice_counts(), //count, post_date
285
-			'coupons'        => $this->query_coupon_counts(), // discount_amount, post_date
286
-			'invoice_items'  => $this->query_item_counts(), // invoice_item_count, post_date
287
-			'refunded_items' => $this->count_refunded_items(), // invoice_item_count, post_date
288
-			'invoices'       => $this->query_invoice_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
289
-			'refunds'        => $this->query_refunded_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
290
-			'previous_range' => $this->previous_range,
291
-		);
292
-
293
-		// Calculated totals.
294
-		$this->report_data->total_tax          = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_tax' ) ) );
295
-		$this->report_data->total_sales        = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_sales' ) ) );
296
-		$this->report_data->total_discount     = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_discount' ) ) );
297
-		$this->report_data->total_fees         = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_fees' ) ) );
298
-		$this->report_data->subtotal           = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'subtotal' ) ) );
299
-		$this->report_data->net_sales          = wpinv_round_amount( $this->report_data->total_sales - max( 0, $this->report_data->total_tax ) );
300
-		$this->report_data->total_refunded_tax = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_tax' ) ) );
301
-		$this->report_data->total_refunds      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_sales' ) ) );
302
-		$this->report_data->refunded_discount  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_discount' ) ) );
303
-		$this->report_data->refunded_fees      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_fees' ) ) );
304
-		$this->report_data->refunded_subtotal  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'subtotal' ) ) );
305
-		$this->report_data->net_refunds        = wpinv_round_amount( $this->report_data->total_refunds + max( 0, $this->report_data->total_refunded_tax ) );
306
-
307
-		// Calculate average based on net.
308
-		$this->report_data->average_sales       = wpinv_round_amount( $this->report_data->net_sales / max( $this->interval, 1 ), 2 );
309
-		$this->report_data->average_total_sales = wpinv_round_amount( $this->report_data->total_sales / max( $this->interval, 1 ), 2 );
310
-
311
-		// Total invoices in this period, even if refunded.
312
-		$this->report_data->total_invoices = absint( array_sum( wp_list_pluck( $this->report_data->invoice_counts, 'count' ) ) );
313
-
314
-		// Items invoiced in this period, even if refunded.
315
-		$this->report_data->total_items = absint( array_sum( wp_list_pluck( $this->report_data->invoice_items, 'invoice_item_count' ) ) );
316
-
317
-		// 3rd party filtering of report data
318
-		$this->report_data = apply_filters( 'getpaid_rest_api_filter_report_data', $this->report_data, $this );
319
-	}
320
-
321
-	/**
322
-	 * Prepares invoice counts.
323
-	 *
324
-	 * @return array.
325
-	 */
326
-	protected function query_invoice_counts() {
327
-
328
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
329
-			array(
330
-				'data'           => array(
331
-					'ID'        => array(
332
-						'type'     => 'post_data',
333
-						'function' => 'COUNT',
334
-						'name'     => 'count',
335
-						'distinct' => true,
336
-					),
337
-					'post_date' => array(
338
-						'type'     => 'post_data',
339
-						'function' => 'MIN',
340
-						'name'     => 'post_date',
341
-					),
342
-				),
343
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
344
-				'order_by'       => 'post_date ASC',
345
-				'query_type'     => 'get_results',
346
-				'filter_range'   => $this->report_range,
347
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
348
-			)
349
-		);
350
-
351
-	}
352
-
353
-	/**
354
-	 * Prepares coupon counts.
355
-	 *
356
-	 * @return array.
357
-	 */
358
-	protected function query_coupon_counts() {
359
-
360
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
361
-			array(
362
-				'data'           => array(
363
-					'discount'  => array(
364
-						'type'     => 'invoice_data',
365
-						'function' => 'SUM',
366
-						'name'     => 'discount_amount',
367
-					),
368
-					'post_date' => array(
369
-						'type'     => 'post_data',
370
-						'function' => 'MIN',
371
-						'name'     => 'post_date',
372
-					),
373
-				),
374
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
375
-				'order_by'       => 'post_date ASC',
376
-				'query_type'     => 'get_results',
377
-				'filter_range'   => $this->report_range,
378
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
379
-			)
380
-		);
381
-
382
-	}
383
-
384
-	/**
385
-	 * Prepares item counts.
386
-	 *
387
-	 * @return array.
388
-	 */
389
-	protected function query_item_counts() {
390
-
391
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
392
-			array(
393
-				'data'           => array(
394
-					'quantity'  => array(
395
-						'type'     => 'invoice_item',
396
-						'function' => 'SUM',
397
-						'name'     => 'invoice_item_count',
398
-					),
399
-					'post_date' => array(
400
-						'type'     => 'post_data',
401
-						'function' => 'MIN',
402
-						'name'     => 'post_date',
403
-					),
404
-				),
405
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
406
-				'order_by'       => 'post_date ASC',
407
-				'query_type'     => 'get_results',
408
-				'filter_range'   => $this->report_range,
409
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
410
-			)
411
-		);
412
-
413
-	}
414
-
415
-	/**
416
-	 * Prepares refunded item counts.
417
-	 *
418
-	 * @return array.
419
-	 */
420
-	protected function count_refunded_items() {
421
-
422
-		return (int) GetPaid_Reports_Helper::get_invoice_report_data(
423
-			array(
424
-				'data'           => array(
425
-					'quantity' => array(
426
-						'type'     => 'invoice_item',
427
-						'function' => 'SUM',
428
-						'name'     => 'invoice_item_count',
429
-					),
430
-				),
431
-				'query_type'     => 'get_var',
432
-				'filter_range'   => $this->report_range,
433
-				'invoice_status' => array( 'wpi-refunded' ),
434
-			)
435
-		);
436
-
437
-	}
438
-
439
-	/**
440
-	 * Prepares daily invoice totals.
441
-	 *
442
-	 * @return array.
443
-	 */
444
-	protected function query_invoice_totals() {
445
-
446
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
447
-			array(
448
-				'data'           => array(
449
-					'total'      => array(
450
-						'type'     => 'invoice_data',
451
-						'function' => 'SUM',
452
-						'name'     => 'total_sales',
453
-					),
454
-					'tax'        => array(
455
-						'type'     => 'invoice_data',
456
-						'function' => 'SUM',
457
-						'name'     => 'total_tax',
458
-					),
459
-					'discount'   => array(
460
-						'type'     => 'invoice_data',
461
-						'function' => 'SUM',
462
-						'name'     => 'total_discount',
463
-					),
464
-					'fees_total' => array(
465
-						'type'     => 'invoice_data',
466
-						'function' => 'SUM',
467
-						'name'     => 'total_fees',
468
-					),
469
-					'subtotal'   => array(
470
-						'type'     => 'invoice_data',
471
-						'function' => 'SUM',
472
-						'name'     => 'subtotal',
473
-					),
474
-					'post_date'  => array(
475
-						'type'     => 'post_data',
476
-						'function' => '',
477
-						'name'     => 'post_date',
478
-					),
479
-				),
480
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
481
-				'order_by'       => 'post_date ASC',
482
-				'query_type'     => 'get_results',
483
-				'filter_range'   => $this->report_range,
484
-				'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-renewal' ),
485
-			)
486
-		);
487
-
488
-	}
489
-
490
-	/**
491
-	 * Prepares daily invoice totals.
492
-	 *
493
-	 * @return array.
494
-	 */
495
-	protected function query_refunded_totals() {
496
-
497
-		return (array) GetPaid_Reports_Helper::get_invoice_report_data(
498
-			array(
499
-				'data'           => array(
500
-					'total'      => array(
501
-						'type'     => 'invoice_data',
502
-						'function' => 'SUM',
503
-						'name'     => 'total_sales',
504
-					),
505
-					'tax'        => array(
506
-						'type'     => 'invoice_data',
507
-						'function' => 'SUM',
508
-						'name'     => 'total_tax',
509
-					),
510
-					'discount'   => array(
511
-						'type'     => 'invoice_data',
512
-						'function' => 'SUM',
513
-						'name'     => 'total_discount',
514
-					),
515
-					'fees_total' => array(
516
-						'type'     => 'invoice_data',
517
-						'function' => 'SUM',
518
-						'name'     => 'total_fees',
519
-					),
520
-					'subtotal'   => array(
521
-						'type'     => 'invoice_data',
522
-						'function' => 'SUM',
523
-						'name'     => 'subtotal',
524
-					),
525
-					'post_date'  => array(
526
-						'type'     => 'post_data',
527
-						'function' => '',
528
-						'name'     => 'post_date',
529
-					),
530
-				),
531
-				'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
532
-				'order_by'       => 'post_date ASC',
533
-				'query_type'     => 'get_results',
534
-				'filter_range'   => $this->report_range,
535
-				'invoice_status' => array( 'wpi-refunded' ),
536
-			)
537
-		);
538
-
539
-	}
540
-
541
-	/**
542
-	 * Get the Report's schema, conforming to JSON Schema.
543
-	 *
544
-	 * @return array
545
-	 */
546
-	public function get_item_schema() {
547
-
548
-		$schema = array(
549
-			'$schema'    => 'http://json-schema.org/draft-04/schema#',
550
-			'title'      => 'sales_report',
551
-			'type'       => 'object',
552
-			'properties' => array(
553
-				'total_sales'         => array(
554
-					'description' => __( 'Gross sales in the period.', 'invoicing' ),
555
-					'type'        => 'string',
556
-					'context'     => array( 'view' ),
557
-					'readonly'    => true,
558
-				),
559
-				'net_sales'           => array(
560
-					'description' => __( 'Net sales in the period.', 'invoicing' ),
561
-					'type'        => 'string',
562
-					'context'     => array( 'view' ),
563
-					'readonly'    => true,
564
-				),
565
-				'average_sales'       => array(
566
-					'description' => __( 'Average net daily sales.', 'invoicing' ),
567
-					'type'        => 'string',
568
-					'context'     => array( 'view' ),
569
-					'readonly'    => true,
570
-				),
571
-				'average_total_sales' => array(
572
-					'description' => __( 'Average gross daily sales.', 'invoicing' ),
573
-					'type'        => 'string',
574
-					'context'     => array( 'view' ),
575
-					'readonly'    => true,
576
-				),
577
-				'total_invoices'      => array(
578
-					'description' => __( 'Number of paid invoices.', 'invoicing' ),
579
-					'type'        => 'integer',
580
-					'context'     => array( 'view' ),
581
-					'readonly'    => true,
582
-				),
583
-				'total_items'         => array(
584
-					'description' => __( 'Number of items purchased.', 'invoicing' ),
585
-					'type'        => 'integer',
586
-					'context'     => array( 'view' ),
587
-					'readonly'    => true,
588
-				),
589
-				'refunded_items'      => array(
590
-					'description' => __( 'Number of items refunded.', 'invoicing' ),
591
-					'type'        => 'integer',
592
-					'context'     => array( 'view' ),
593
-					'readonly'    => true,
594
-				),
595
-				'total_tax'           => array(
596
-					'description' => __( 'Total charged for taxes.', 'invoicing' ),
597
-					'type'        => 'string',
598
-					'context'     => array( 'view' ),
599
-					'readonly'    => true,
600
-				),
601
-				'total_refunded_tax'  => array(
602
-					'description' => __( 'Total refunded for taxes.', 'invoicing' ),
603
-					'type'        => 'string',
604
-					'context'     => array( 'view' ),
605
-					'readonly'    => true,
606
-				),
607
-				'total_fees'          => array(
608
-					'description' => __( 'Total fees charged.', 'invoicing' ),
609
-					'type'        => 'string',
610
-					'context'     => array( 'view' ),
611
-					'readonly'    => true,
612
-				),
613
-				'total_refunds'       => array(
614
-					'description' => __( 'Total of refunded invoices.', 'invoicing' ),
615
-					'type'        => 'integer',
616
-					'context'     => array( 'view' ),
617
-					'readonly'    => true,
618
-				),
619
-				'net_refunds'         => array(
620
-					'description' => __( 'Net of refunded invoices.', 'invoicing' ),
621
-					'type'        => 'integer',
622
-					'context'     => array( 'view' ),
623
-					'readonly'    => true,
624
-				),
625
-				'total_discount'      => array(
626
-					'description' => __( 'Total of discounts used.', 'invoicing' ),
627
-					'type'        => 'integer',
628
-					'context'     => array( 'view' ),
629
-					'readonly'    => true,
630
-				),
631
-				'totals'              => array(
632
-					'description' => __( 'Totals.', 'invoicing' ),
633
-					'type'        => 'array',
634
-					'items'       => array(
635
-						'type' => 'array',
636
-					),
637
-					'context'     => array( 'view' ),
638
-					'readonly'    => true,
639
-				),
640
-				'interval'            => array(
641
-					'description' => __( 'Number of months/days in the report period.', 'invoicing' ),
642
-					'type'        => 'integer',
643
-					'context'     => array( 'view' ),
644
-					'readonly'    => true,
645
-				),
646
-				'previous_range'      => array(
647
-					'description' => __( 'The previous report period.', 'invoicing' ),
648
-					'type'        => 'array',
649
-					'items'       => array(
650
-						'type' => 'string',
651
-					),
652
-					'context'     => array( 'view' ),
653
-					'readonly'    => true,
654
-				),
655
-				'grouped_by'          => array(
656
-					'description' => __( 'The period used to group the totals.', 'invoicing' ),
657
-					'type'        => 'string',
658
-					'context'     => array( 'view' ),
659
-					'enum'        => array( 'day', 'month' ),
660
-					'readonly'    => true,
661
-				),
662
-				'currency'            => array(
663
-					'description' => __( 'The default store currency.', 'invoicing' ),
664
-					'type'        => 'string',
665
-					'context'     => array( 'view' ),
666
-					'readonly'    => true,
667
-				),
668
-				'currency_symbol'     => array(
669
-					'description' => __( 'The default store currency symbol.', 'invoicing' ),
670
-					'type'        => 'string',
671
-					'context'     => array( 'view' ),
672
-					'readonly'    => true,
673
-				),
674
-				'currency_position'   => array(
675
-					'description' => __( 'The default store currency position.', 'invoicing' ),
676
-					'type'        => 'string',
677
-					'context'     => array( 'view' ),
678
-					'readonly'    => true,
679
-				),
680
-				'decimal_places'      => array(
681
-					'description' => __( 'The default store decimal places.', 'invoicing' ),
682
-					'type'        => 'string',
683
-					'context'     => array( 'view' ),
684
-					'readonly'    => true,
685
-				),
686
-				'thousands_sep'       => array(
687
-					'description' => __( 'The default store thousands separator.', 'invoicing' ),
688
-					'type'        => 'string',
689
-					'context'     => array( 'view' ),
690
-					'readonly'    => true,
691
-				),
692
-				'decimals_sep'        => array(
693
-					'description' => __( 'The default store decimals separator.', 'invoicing' ),
694
-					'type'        => 'string',
695
-					'context'     => array( 'view' ),
696
-					'readonly'    => true,
697
-				),
698
-			),
699
-		);
700
-
701
-		return $this->add_additional_fields_schema( $schema );
702
-
703
-	}
66
+    }
67
+
68
+    /**
69
+     * Makes sure the current user has access to READ the report APIs.
70
+     *
71
+     * @since  2.0.0
72
+     * @param WP_REST_Request $request Full data about the request.
73
+     * @return WP_Error|boolean
74
+     */
75
+    public function get_items_permissions_check( $request ) {
76
+
77
+        if ( ! wpinv_current_user_can_manage_invoicing() ) {
78
+            return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
79
+        }
80
+
81
+        return true;
82
+    }
83
+
84
+    /**
85
+     * Get sales reports.
86
+     *
87
+     * @param WP_REST_Request $request
88
+     * @return array|WP_Error
89
+     */
90
+    public function get_items( $request ) {
91
+        $data   = array();
92
+        $item   = $this->prepare_item_for_response( null, $request );
93
+        $data[] = $this->prepare_response_for_collection( $item );
94
+
95
+        return rest_ensure_response( $data );
96
+    }
97
+
98
+    /**
99
+     * Prepare a report sales object for serialization.
100
+     *
101
+     * @param null $_
102
+     * @param WP_REST_Request $request Request object.
103
+     * @return WP_REST_Response $response Response data.
104
+     */
105
+    public function prepare_item_for_response( $_, $request ) {
106
+
107
+        // Set report range.
108
+        $this->report_range = $this->get_date_range( $request );
109
+
110
+        $report_data     = $this->get_report_data();
111
+        $period_totals   = array();
112
+
113
+        // Setup period totals by ensuring each period in the interval has data.
114
+        $start_date      = strtotime( $this->report_range['after'] );
115
+
116
+        if ( 'month' === $this->groupby ) {
117
+            $start_date      = strtotime( gmdate( 'Y-m-01', $start_date ) );
118
+        }
119
+
120
+        for ( $i = 0; $i < $this->interval; $i++ ) {
121
+
122
+            switch ( $this->groupby ) {
123
+                case 'day':
124
+                    $time = gmdate( 'Y-m-d', strtotime( "+{$i} DAY", $start_date ) );
125
+                    break;
126
+                default:
127
+                    $time = gmdate( 'Y-m', strtotime( "+{$i} MONTH", $start_date ) );
128
+                    break;
129
+            }
130
+
131
+            // Set the defaults for each period.
132
+            $period_totals[ $time ] = array(
133
+                'invoices'          => 0,
134
+                'items'             => 0,
135
+                'refunded_items'    => 0,
136
+                'refunded_tax'      => wpinv_round_amount( 0.00 ),
137
+                'subtotal'          => wpinv_round_amount( 0.00 ),
138
+                'refunded_subtotal' => wpinv_round_amount( 0.00 ),
139
+                'refunded_fees'     => wpinv_round_amount( 0.00 ),
140
+                'discount'          => wpinv_round_amount( 0.00 ),
141
+            );
142
+
143
+            foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
144
+                if ( ! isset( $period_totals[ $time ][ $key ] ) ) {
145
+                    $period_totals[ $time ][ $key ] = wpinv_round_amount( 0.00 );
146
+                }
147
+            }
148
+        }
149
+
150
+        // add total sales, total invoice count, total tax for each period
151
+        $date_format = ( 'day' === $this->groupby ) ? 'Y-m-d' : 'Y-m';
152
+        foreach ( $report_data->invoices as $invoice ) {
153
+            $time = gmdate( $date_format, strtotime( $invoice->post_date ) );
154
+
155
+            if ( ! isset( $period_totals[ $time ] ) ) {
156
+                continue;
157
+            }
158
+
159
+            $period_totals[ $time ]['sales']    = wpinv_round_amount( $invoice->total_sales );
160
+            $period_totals[ $time ]['tax']      = wpinv_round_amount( $invoice->total_tax );
161
+            $period_totals[ $time ]['subtotal'] = wpinv_round_amount( $invoice->subtotal );
162
+            $period_totals[ $time ]['fees']     = wpinv_round_amount( $invoice->total_fees );
163
+
164
+        }
165
+
166
+        foreach ( $report_data->refunds as $invoice ) {
167
+            $time = gmdate( $date_format, strtotime( $invoice->post_date ) );
168
+
169
+            if ( ! isset( $period_totals[ $time ] ) ) {
170
+                continue;
171
+            }
172
+
173
+            $period_totals[ $time ]['refunds']           = wpinv_round_amount( $invoice->total_sales );
174
+            $period_totals[ $time ]['refunded_tax']      = wpinv_round_amount( $invoice->total_tax );
175
+            $period_totals[ $time ]['refunded_subtotal'] = wpinv_round_amount( $invoice->subtotal );
176
+            $period_totals[ $time ]['refunded_fees']     = wpinv_round_amount( $invoice->total_fees );
177
+
178
+        }
179
+
180
+        foreach ( $report_data->invoice_counts as $invoice ) {
181
+            $time = gmdate( $date_format, strtotime( $invoice->post_date ) );
182
+
183
+            if ( isset( $period_totals[ $time ] ) ) {
184
+                $period_totals[ $time ]['invoices']   = (int) $invoice->count;
185
+            }
186
+        }
187
+
188
+        // Add total invoice items for each period.
189
+        foreach ( $report_data->invoice_items as $invoice_item ) {
190
+            $time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $invoice_item->post_date ) ) : gmdate( 'Y-m', strtotime( $invoice_item->post_date ) );
191
+
192
+            if ( isset( $period_totals[ $time ] ) ) {
193
+                $period_totals[ $time ]['items'] = (int) $invoice_item->invoice_item_count;
194
+            }
195
+        }
196
+
197
+        // Add total discount for each period.
198
+        foreach ( $report_data->coupons as $discount ) {
199
+            $time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $discount->post_date ) ) : gmdate( 'Y-m', strtotime( $discount->post_date ) );
200
+
201
+            if ( isset( $period_totals[ $time ] ) ) {
202
+                $period_totals[ $time ]['discount'] = wpinv_round_amount( $discount->discount_amount );
203
+            }
204
+        }
205
+
206
+        // Extra fields.
207
+        foreach ( array_keys( wpinv_get_report_graphs() ) as $key ) {
208
+
209
+            // Abort unprepared.
210
+            if ( ! isset( $report_data->$key ) ) {
211
+                continue;
212
+            } 
213
+
214
+            // Abort defaults.
215
+            if ( in_array( $key, array( 'sales', 'refunds', 'tax', 'fees', 'discount', 'invoices', 'items' ) ) ) {
216
+                continue;
217
+            }
218
+
219
+            // Set values.
220
+            foreach ( $report_data->$key as $item ) {
221
+                $time = ( 'day' === $this->groupby ) ? gmdate( 'Y-m-d', strtotime( $item->date ) ) : gmdate( 'Y-m', strtotime( $item->date ) );
222
+
223
+                if ( isset( $period_totals[ $time ] ) ) {
224
+                    $period_totals[ $time ][ $key ] = wpinv_round_amount( $item->val );
225
+                }
226
+            }
227
+
228
+            unset( $report_data->$key );
229
+        }
230
+
231
+        $report_data->totals            = $period_totals;
232
+        $report_data->grouped_by        = $this->groupby;
233
+        $report_data->interval          = max( $this->interval, 1 );
234
+        $report_data->currency          = wpinv_get_currency();
235
+        $report_data->currency_symbol   = wpinv_currency_symbol();
236
+        $report_data->currency_position = wpinv_currency_position();
237
+        $report_data->decimal_places    = wpinv_decimals();
238
+        $report_data->thousands_sep     = wpinv_thousands_separator();
239
+        $report_data->decimals_sep      = wpinv_decimal_separator();
240
+        $report_data->start_date        = gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) );
241
+        $report_data->end_date          = gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) );
242
+        $report_data->start_date_locale = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['after'] ) ) );
243
+        $report_data->end_date_locale   = getpaid_format_date( gmdate( 'Y-m-d', strtotime( $this->report_range['before'] ) ) );
244
+        $report_data->decimals_sep      = wpinv_decimal_separator();
245
+
246
+        $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
247
+        $data    = $report_data;
248
+        unset( $data->invoice_counts, $data->invoices, $data->coupons, $data->refunds, $data->invoice_items );
249
+        $data    = $this->add_additional_fields_to_object( (array) $data, $request );
250
+        $data    = $this->filter_response_by_context( $data, $context );
251
+
252
+        // Wrap the data in a response object.
253
+        $response = rest_ensure_response( $data );
254
+        $response->add_links(
255
+            array(
256
+                'about' => array(
257
+                    'href' => rest_url( sprintf( '%s/reports', $this->namespace ) ),
258
+                ),
259
+            )
260
+        );
261
+
262
+        return apply_filters( 'getpaid_rest_prepare_report_sales', $response, $report_data, $request );
263
+    }
264
+
265
+    /**
266
+     * Get report data.
267
+     *
268
+     * @return stdClass
269
+     */
270
+    public function get_report_data() {
271
+        if ( empty( $this->report_data ) ) {
272
+            $this->query_report_data();
273
+        }
274
+        return $this->report_data;
275
+    }
276
+
277
+    /**
278
+     * Get all data needed for this report and store in the class.
279
+     */
280
+    protected function query_report_data() {
281
+
282
+        // Prepare reports.
283
+        $this->report_data = (object) array(
284
+            'invoice_counts' => $this->query_invoice_counts(), //count, post_date
285
+            'coupons'        => $this->query_coupon_counts(), // discount_amount, post_date
286
+            'invoice_items'  => $this->query_item_counts(), // invoice_item_count, post_date
287
+            'refunded_items' => $this->count_refunded_items(), // invoice_item_count, post_date
288
+            'invoices'       => $this->query_invoice_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
289
+            'refunds'        => $this->query_refunded_totals(), // total_sales, total_tax, total_discount, total_fees, subtotal, post_date
290
+            'previous_range' => $this->previous_range,
291
+        );
292
+
293
+        // Calculated totals.
294
+        $this->report_data->total_tax          = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_tax' ) ) );
295
+        $this->report_data->total_sales        = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_sales' ) ) );
296
+        $this->report_data->total_discount     = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_discount' ) ) );
297
+        $this->report_data->total_fees         = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'total_fees' ) ) );
298
+        $this->report_data->subtotal           = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->invoices, 'subtotal' ) ) );
299
+        $this->report_data->net_sales          = wpinv_round_amount( $this->report_data->total_sales - max( 0, $this->report_data->total_tax ) );
300
+        $this->report_data->total_refunded_tax = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_tax' ) ) );
301
+        $this->report_data->total_refunds      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_sales' ) ) );
302
+        $this->report_data->refunded_discount  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_discount' ) ) );
303
+        $this->report_data->refunded_fees      = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'total_fees' ) ) );
304
+        $this->report_data->refunded_subtotal  = wpinv_round_amount( array_sum( wp_list_pluck( $this->report_data->refunds, 'subtotal' ) ) );
305
+        $this->report_data->net_refunds        = wpinv_round_amount( $this->report_data->total_refunds + max( 0, $this->report_data->total_refunded_tax ) );
306
+
307
+        // Calculate average based on net.
308
+        $this->report_data->average_sales       = wpinv_round_amount( $this->report_data->net_sales / max( $this->interval, 1 ), 2 );
309
+        $this->report_data->average_total_sales = wpinv_round_amount( $this->report_data->total_sales / max( $this->interval, 1 ), 2 );
310
+
311
+        // Total invoices in this period, even if refunded.
312
+        $this->report_data->total_invoices = absint( array_sum( wp_list_pluck( $this->report_data->invoice_counts, 'count' ) ) );
313
+
314
+        // Items invoiced in this period, even if refunded.
315
+        $this->report_data->total_items = absint( array_sum( wp_list_pluck( $this->report_data->invoice_items, 'invoice_item_count' ) ) );
316
+
317
+        // 3rd party filtering of report data
318
+        $this->report_data = apply_filters( 'getpaid_rest_api_filter_report_data', $this->report_data, $this );
319
+    }
320
+
321
+    /**
322
+     * Prepares invoice counts.
323
+     *
324
+     * @return array.
325
+     */
326
+    protected function query_invoice_counts() {
327
+
328
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
329
+            array(
330
+                'data'           => array(
331
+                    'ID'        => array(
332
+                        'type'     => 'post_data',
333
+                        'function' => 'COUNT',
334
+                        'name'     => 'count',
335
+                        'distinct' => true,
336
+                    ),
337
+                    'post_date' => array(
338
+                        'type'     => 'post_data',
339
+                        'function' => 'MIN',
340
+                        'name'     => 'post_date',
341
+                    ),
342
+                ),
343
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
344
+                'order_by'       => 'post_date ASC',
345
+                'query_type'     => 'get_results',
346
+                'filter_range'   => $this->report_range,
347
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
348
+            )
349
+        );
350
+
351
+    }
352
+
353
+    /**
354
+     * Prepares coupon counts.
355
+     *
356
+     * @return array.
357
+     */
358
+    protected function query_coupon_counts() {
359
+
360
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
361
+            array(
362
+                'data'           => array(
363
+                    'discount'  => array(
364
+                        'type'     => 'invoice_data',
365
+                        'function' => 'SUM',
366
+                        'name'     => 'discount_amount',
367
+                    ),
368
+                    'post_date' => array(
369
+                        'type'     => 'post_data',
370
+                        'function' => 'MIN',
371
+                        'name'     => 'post_date',
372
+                    ),
373
+                ),
374
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
375
+                'order_by'       => 'post_date ASC',
376
+                'query_type'     => 'get_results',
377
+                'filter_range'   => $this->report_range,
378
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
379
+            )
380
+        );
381
+
382
+    }
383
+
384
+    /**
385
+     * Prepares item counts.
386
+     *
387
+     * @return array.
388
+     */
389
+    protected function query_item_counts() {
390
+
391
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
392
+            array(
393
+                'data'           => array(
394
+                    'quantity'  => array(
395
+                        'type'     => 'invoice_item',
396
+                        'function' => 'SUM',
397
+                        'name'     => 'invoice_item_count',
398
+                    ),
399
+                    'post_date' => array(
400
+                        'type'     => 'post_data',
401
+                        'function' => 'MIN',
402
+                        'name'     => 'post_date',
403
+                    ),
404
+                ),
405
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
406
+                'order_by'       => 'post_date ASC',
407
+                'query_type'     => 'get_results',
408
+                'filter_range'   => $this->report_range,
409
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-refunded', 'wpi-renewal' ),
410
+            )
411
+        );
412
+
413
+    }
414
+
415
+    /**
416
+     * Prepares refunded item counts.
417
+     *
418
+     * @return array.
419
+     */
420
+    protected function count_refunded_items() {
421
+
422
+        return (int) GetPaid_Reports_Helper::get_invoice_report_data(
423
+            array(
424
+                'data'           => array(
425
+                    'quantity' => array(
426
+                        'type'     => 'invoice_item',
427
+                        'function' => 'SUM',
428
+                        'name'     => 'invoice_item_count',
429
+                    ),
430
+                ),
431
+                'query_type'     => 'get_var',
432
+                'filter_range'   => $this->report_range,
433
+                'invoice_status' => array( 'wpi-refunded' ),
434
+            )
435
+        );
436
+
437
+    }
438
+
439
+    /**
440
+     * Prepares daily invoice totals.
441
+     *
442
+     * @return array.
443
+     */
444
+    protected function query_invoice_totals() {
445
+
446
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
447
+            array(
448
+                'data'           => array(
449
+                    'total'      => array(
450
+                        'type'     => 'invoice_data',
451
+                        'function' => 'SUM',
452
+                        'name'     => 'total_sales',
453
+                    ),
454
+                    'tax'        => array(
455
+                        'type'     => 'invoice_data',
456
+                        'function' => 'SUM',
457
+                        'name'     => 'total_tax',
458
+                    ),
459
+                    'discount'   => array(
460
+                        'type'     => 'invoice_data',
461
+                        'function' => 'SUM',
462
+                        'name'     => 'total_discount',
463
+                    ),
464
+                    'fees_total' => array(
465
+                        'type'     => 'invoice_data',
466
+                        'function' => 'SUM',
467
+                        'name'     => 'total_fees',
468
+                    ),
469
+                    'subtotal'   => array(
470
+                        'type'     => 'invoice_data',
471
+                        'function' => 'SUM',
472
+                        'name'     => 'subtotal',
473
+                    ),
474
+                    'post_date'  => array(
475
+                        'type'     => 'post_data',
476
+                        'function' => '',
477
+                        'name'     => 'post_date',
478
+                    ),
479
+                ),
480
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
481
+                'order_by'       => 'post_date ASC',
482
+                'query_type'     => 'get_results',
483
+                'filter_range'   => $this->report_range,
484
+                'invoice_status' => array( 'publish', 'wpi-processing', 'wpi-onhold', 'wpi-renewal' ),
485
+            )
486
+        );
487
+
488
+    }
489
+
490
+    /**
491
+     * Prepares daily invoice totals.
492
+     *
493
+     * @return array.
494
+     */
495
+    protected function query_refunded_totals() {
496
+
497
+        return (array) GetPaid_Reports_Helper::get_invoice_report_data(
498
+            array(
499
+                'data'           => array(
500
+                    'total'      => array(
501
+                        'type'     => 'invoice_data',
502
+                        'function' => 'SUM',
503
+                        'name'     => 'total_sales',
504
+                    ),
505
+                    'tax'        => array(
506
+                        'type'     => 'invoice_data',
507
+                        'function' => 'SUM',
508
+                        'name'     => 'total_tax',
509
+                    ),
510
+                    'discount'   => array(
511
+                        'type'     => 'invoice_data',
512
+                        'function' => 'SUM',
513
+                        'name'     => 'total_discount',
514
+                    ),
515
+                    'fees_total' => array(
516
+                        'type'     => 'invoice_data',
517
+                        'function' => 'SUM',
518
+                        'name'     => 'total_fees',
519
+                    ),
520
+                    'subtotal'   => array(
521
+                        'type'     => 'invoice_data',
522
+                        'function' => 'SUM',
523
+                        'name'     => 'subtotal',
524
+                    ),
525
+                    'post_date'  => array(
526
+                        'type'     => 'post_data',
527
+                        'function' => '',
528
+                        'name'     => 'post_date',
529
+                    ),
530
+                ),
531
+                'group_by'       => $this->get_group_by_sql( 'posts.post_date' ),
532
+                'order_by'       => 'post_date ASC',
533
+                'query_type'     => 'get_results',
534
+                'filter_range'   => $this->report_range,
535
+                'invoice_status' => array( 'wpi-refunded' ),
536
+            )
537
+        );
538
+
539
+    }
540
+
541
+    /**
542
+     * Get the Report's schema, conforming to JSON Schema.
543
+     *
544
+     * @return array
545
+     */
546
+    public function get_item_schema() {
547
+
548
+        $schema = array(
549
+            '$schema'    => 'http://json-schema.org/draft-04/schema#',
550
+            'title'      => 'sales_report',
551
+            'type'       => 'object',
552
+            'properties' => array(
553
+                'total_sales'         => array(
554
+                    'description' => __( 'Gross sales in the period.', 'invoicing' ),
555
+                    'type'        => 'string',
556
+                    'context'     => array( 'view' ),
557
+                    'readonly'    => true,
558
+                ),
559
+                'net_sales'           => array(
560
+                    'description' => __( 'Net sales in the period.', 'invoicing' ),
561
+                    'type'        => 'string',
562
+                    'context'     => array( 'view' ),
563
+                    'readonly'    => true,
564
+                ),
565
+                'average_sales'       => array(
566
+                    'description' => __( 'Average net daily sales.', 'invoicing' ),
567
+                    'type'        => 'string',
568
+                    'context'     => array( 'view' ),
569
+                    'readonly'    => true,
570
+                ),
571
+                'average_total_sales' => array(
572
+                    'description' => __( 'Average gross daily sales.', 'invoicing' ),
573
+                    'type'        => 'string',
574
+                    'context'     => array( 'view' ),
575
+                    'readonly'    => true,
576
+                ),
577
+                'total_invoices'      => array(
578
+                    'description' => __( 'Number of paid invoices.', 'invoicing' ),
579
+                    'type'        => 'integer',
580
+                    'context'     => array( 'view' ),
581
+                    'readonly'    => true,
582
+                ),
583
+                'total_items'         => array(
584
+                    'description' => __( 'Number of items purchased.', 'invoicing' ),
585
+                    'type'        => 'integer',
586
+                    'context'     => array( 'view' ),
587
+                    'readonly'    => true,
588
+                ),
589
+                'refunded_items'      => array(
590
+                    'description' => __( 'Number of items refunded.', 'invoicing' ),
591
+                    'type'        => 'integer',
592
+                    'context'     => array( 'view' ),
593
+                    'readonly'    => true,
594
+                ),
595
+                'total_tax'           => array(
596
+                    'description' => __( 'Total charged for taxes.', 'invoicing' ),
597
+                    'type'        => 'string',
598
+                    'context'     => array( 'view' ),
599
+                    'readonly'    => true,
600
+                ),
601
+                'total_refunded_tax'  => array(
602
+                    'description' => __( 'Total refunded for taxes.', 'invoicing' ),
603
+                    'type'        => 'string',
604
+                    'context'     => array( 'view' ),
605
+                    'readonly'    => true,
606
+                ),
607
+                'total_fees'          => array(
608
+                    'description' => __( 'Total fees charged.', 'invoicing' ),
609
+                    'type'        => 'string',
610
+                    'context'     => array( 'view' ),
611
+                    'readonly'    => true,
612
+                ),
613
+                'total_refunds'       => array(
614
+                    'description' => __( 'Total of refunded invoices.', 'invoicing' ),
615
+                    'type'        => 'integer',
616
+                    'context'     => array( 'view' ),
617
+                    'readonly'    => true,
618
+                ),
619
+                'net_refunds'         => array(
620
+                    'description' => __( 'Net of refunded invoices.', 'invoicing' ),
621
+                    'type'        => 'integer',
622
+                    'context'     => array( 'view' ),
623
+                    'readonly'    => true,
624
+                ),
625
+                'total_discount'      => array(
626
+                    'description' => __( 'Total of discounts used.', 'invoicing' ),
627
+                    'type'        => 'integer',
628
+                    'context'     => array( 'view' ),
629
+                    'readonly'    => true,
630
+                ),
631
+                'totals'              => array(
632
+                    'description' => __( 'Totals.', 'invoicing' ),
633
+                    'type'        => 'array',
634
+                    'items'       => array(
635
+                        'type' => 'array',
636
+                    ),
637
+                    'context'     => array( 'view' ),
638
+                    'readonly'    => true,
639
+                ),
640
+                'interval'            => array(
641
+                    'description' => __( 'Number of months/days in the report period.', 'invoicing' ),
642
+                    'type'        => 'integer',
643
+                    'context'     => array( 'view' ),
644
+                    'readonly'    => true,
645
+                ),
646
+                'previous_range'      => array(
647
+                    'description' => __( 'The previous report period.', 'invoicing' ),
648
+                    'type'        => 'array',
649
+                    'items'       => array(
650
+                        'type' => 'string',
651
+                    ),
652
+                    'context'     => array( 'view' ),
653
+                    'readonly'    => true,
654
+                ),
655
+                'grouped_by'          => array(
656
+                    'description' => __( 'The period used to group the totals.', 'invoicing' ),
657
+                    'type'        => 'string',
658
+                    'context'     => array( 'view' ),
659
+                    'enum'        => array( 'day', 'month' ),
660
+                    'readonly'    => true,
661
+                ),
662
+                'currency'            => array(
663
+                    'description' => __( 'The default store currency.', 'invoicing' ),
664
+                    'type'        => 'string',
665
+                    'context'     => array( 'view' ),
666
+                    'readonly'    => true,
667
+                ),
668
+                'currency_symbol'     => array(
669
+                    'description' => __( 'The default store currency symbol.', 'invoicing' ),
670
+                    'type'        => 'string',
671
+                    'context'     => array( 'view' ),
672
+                    'readonly'    => true,
673
+                ),
674
+                'currency_position'   => array(
675
+                    'description' => __( 'The default store currency position.', 'invoicing' ),
676
+                    'type'        => 'string',
677
+                    'context'     => array( 'view' ),
678
+                    'readonly'    => true,
679
+                ),
680
+                'decimal_places'      => array(
681
+                    'description' => __( 'The default store decimal places.', 'invoicing' ),
682
+                    'type'        => 'string',
683
+                    'context'     => array( 'view' ),
684
+                    'readonly'    => true,
685
+                ),
686
+                'thousands_sep'       => array(
687
+                    'description' => __( 'The default store thousands separator.', 'invoicing' ),
688
+                    'type'        => 'string',
689
+                    'context'     => array( 'view' ),
690
+                    'readonly'    => true,
691
+                ),
692
+                'decimals_sep'        => array(
693
+                    'description' => __( 'The default store decimals separator.', 'invoicing' ),
694
+                    'type'        => 'string',
695
+                    'context'     => array( 'view' ),
696
+                    'readonly'    => true,
697
+                ),
698
+            ),
699
+        );
700
+
701
+        return $this->add_additional_fields_schema( $schema );
702
+
703
+    }
704 704
 
705 705
 }
Please login to merge, or discard this patch.
includes/api/class-getpaid-rest-settings-controller.php 1 patch
Indentation   +743 added lines, -743 removed lines patch added patch discarded remove patch
@@ -18,756 +18,756 @@
 block discarded – undo
18 18
  */
19 19
 class GetPaid_REST_Settings_Controller extends GetPaid_REST_Controller {
20 20
 
21
-	/**
22
-	 * An array of available settings.
23
-	 *
24
-	 * @var string
25
-	 */
26
-	protected $settings;
27
-
28
-	/**
29
-	 * Route base.
30
-	 *
31
-	 * @var string
32
-	 */
33
-	protected $rest_base = 'settings';
34
-
35
-	/**
36
-	 * Registers the routes for the objects of the controller.
37
-	 *
38
-	 * @since 2.0.0
39
-	 *
40
-	 * @see register_rest_route()
41
-	 */
42
-	public function register_namespace_routes( $namespace ) {
43
-
44
-		// List all registered tabs.
45
-		register_rest_route(
46
-			$namespace,
47
-			$this->rest_base,
48
-			array(
49
-				array(
50
-					'methods'             => WP_REST_Server::READABLE,
51
-					'callback'            => array( $this, 'get_tabs' ),
52
-					'permission_callback' => array( $this, 'get_items_permissions_check' ),
53
-				),
54
-				'schema' => '__return_empty_array',
55
-			)
56
-		);
57
-
58
-		// View/Update a single setting.
59
-		register_rest_route(
60
-			$namespace,
61
-			$this->rest_base . '/setting/(?P<id>[\w-]+)',
62
-			array(
63
-				'args'   => array(
64
-					'id' => array(
65
-						'description' => __( 'Unique identifier for the setting.', 'invoicing' ),
66
-						'type'        => 'string',
67
-						'required'    => true,
68
-					),
69
-				),
70
-				array(
71
-					'methods'             => WP_REST_Server::READABLE,
72
-					'callback'            => array( $this, 'get_item' ),
73
-					'permission_callback' => array( $this, 'get_items_permissions_check' ),
74
-				),
75
-				array(
76
-					'methods'             => WP_REST_Server::EDITABLE,
77
-					'callback'            => array( $this, 'update_item' ),
78
-					'permission_callback' => array( $this, 'update_items_permissions_check' ),
79
-					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
80
-				),
81
-				'schema' => array( $this, 'get_public_item_schema' ),
82
-			)
83
-		);
84
-
85
-		// List registered sections for a given tab.
86
-		register_rest_route(
87
-			$namespace,
88
-			$this->rest_base . '/(?P<tab>[\w-]+)',
89
-			array(
90
-				'args'   => array(
91
-					'tab' => array(
92
-						'description' => __( 'Unique identifier for the tab whose sections should be retrieved.', 'invoicing' ),
93
-						'type'        => 'string',
94
-						'required'    => true,
95
-						'enum'        => array_keys( wpinv_get_settings_tabs() ),
96
-					),
97
-				),
98
-				array(
99
-					'methods'             => WP_REST_Server::READABLE,
100
-					'callback'            => array( $this, 'get_sections' ),
101
-					'permission_callback' => array( $this, 'get_items_permissions_check' ),
102
-				),
103
-				'schema' => '__return_empty_array',
104
-			)
105
-		);
106
-
107
-		// List all registered settings for a given tab.
108
-		register_rest_route(
109
-			$namespace,
110
-			$this->rest_base . '/(?P<tab>[\w-]+)/(?P<section>[\w-]+)',
111
-			array(
112
-				'args'   => array(
113
-					'tab'     => array(
114
-						'description' => __( 'Unique identifier for the tab whose settings should be retrieved.', 'invoicing' ),
115
-						'type'        => 'string',
116
-						'required'    => true,
117
-						'enum'        => array_keys( wpinv_get_settings_tabs() ),
118
-					),
119
-					'section' => array(
120
-						'description' => __( 'The section in the tab whose settings should be retrieved.', 'invoicing' ),
121
-						'type'        => 'string',
122
-						'required'    => true,
123
-					),
124
-				),
125
-				array(
126
-					'methods'             => WP_REST_Server::READABLE,
127
-					'callback'            => array( $this, 'get_items' ),
128
-					'permission_callback' => array( $this, 'get_items_permissions_check' ),
129
-				),
130
-				'schema' => array( $this, 'get_public_item_schema' ),
131
-			)
132
-		); 
133
-
134
-		register_rest_route(
135
-			$namespace,
136
-			'/' . $this->rest_base . '/batch',
137
-			array(
138
-				'args'   => array(
139
-					'id' => array(
140
-						'description' => __( 'Setting ID.', 'invoicing' ),
141
-						'type'        => 'string',
142
-					),
143
-				),
144
-				array(
145
-					'methods'             => WP_REST_Server::EDITABLE,
146
-					'callback'            => array( $this, 'batch_items' ),
147
-					'permission_callback' => array( $this, 'batch_items_permissions_check' ),
148
-					'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
149
-				),
150
-				'schema' => array( $this, 'get_public_batch_schema' ),
151
-			)
152
-		);
153
-
154
-	}
155
-
156
-	/**
157
-	 * Return all settings.
158
-	 *
159
-	 * @since  2.0.0
160
-	 * @param  WP_REST_Request $request Request data.
161
-	 * @return WP_Error|WP_REST_Response
162
-	 */
163
-	public function get_items( $request ) {
164
-
165
-		$settings = $this->get_settings();
166
-
167
-		if ( ! isset( $settings[ $request['tab'] ] ) ) {
168
-			return new WP_Error( 'rest_invalid_tab', __( 'Invalid tab.', 'invoicing' ), array( 'status' => 400 ) );
169
-		}
170
-
171
-		if ( ! isset( $settings[ $request['tab'] ][ $request['section'] ] ) ) {
172
-			return new WP_Error( 'rest_invalid_section', __( 'Invalid section.', 'invoicing' ), array( 'status' => 400 ) );
173
-		}
174
-
175
-		$settings = $settings[ $request['tab'] ][ $request['section'] ];
176
-		$prepared = array();
177
-
178
-		foreach ( $settings as $setting ) {
179
-
180
-			$setting      = $this->sanitize_setting( $setting );
181
-			$setting_data = $this->prepare_item_for_response( $setting, $request );
182
-			$setting_data = $this->prepare_response_for_collection( $setting_data );
183
-
184
-			if ( $this->is_setting_type_valid( $setting['type'] ) ) {
185
-				$prepared[]   = $setting_data;
186
-			}
21
+    /**
22
+     * An array of available settings.
23
+     *
24
+     * @var string
25
+     */
26
+    protected $settings;
27
+
28
+    /**
29
+     * Route base.
30
+     *
31
+     * @var string
32
+     */
33
+    protected $rest_base = 'settings';
34
+
35
+    /**
36
+     * Registers the routes for the objects of the controller.
37
+     *
38
+     * @since 2.0.0
39
+     *
40
+     * @see register_rest_route()
41
+     */
42
+    public function register_namespace_routes( $namespace ) {
43
+
44
+        // List all registered tabs.
45
+        register_rest_route(
46
+            $namespace,
47
+            $this->rest_base,
48
+            array(
49
+                array(
50
+                    'methods'             => WP_REST_Server::READABLE,
51
+                    'callback'            => array( $this, 'get_tabs' ),
52
+                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
53
+                ),
54
+                'schema' => '__return_empty_array',
55
+            )
56
+        );
57
+
58
+        // View/Update a single setting.
59
+        register_rest_route(
60
+            $namespace,
61
+            $this->rest_base . '/setting/(?P<id>[\w-]+)',
62
+            array(
63
+                'args'   => array(
64
+                    'id' => array(
65
+                        'description' => __( 'Unique identifier for the setting.', 'invoicing' ),
66
+                        'type'        => 'string',
67
+                        'required'    => true,
68
+                    ),
69
+                ),
70
+                array(
71
+                    'methods'             => WP_REST_Server::READABLE,
72
+                    'callback'            => array( $this, 'get_item' ),
73
+                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
74
+                ),
75
+                array(
76
+                    'methods'             => WP_REST_Server::EDITABLE,
77
+                    'callback'            => array( $this, 'update_item' ),
78
+                    'permission_callback' => array( $this, 'update_items_permissions_check' ),
79
+                    'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
80
+                ),
81
+                'schema' => array( $this, 'get_public_item_schema' ),
82
+            )
83
+        );
84
+
85
+        // List registered sections for a given tab.
86
+        register_rest_route(
87
+            $namespace,
88
+            $this->rest_base . '/(?P<tab>[\w-]+)',
89
+            array(
90
+                'args'   => array(
91
+                    'tab' => array(
92
+                        'description' => __( 'Unique identifier for the tab whose sections should be retrieved.', 'invoicing' ),
93
+                        'type'        => 'string',
94
+                        'required'    => true,
95
+                        'enum'        => array_keys( wpinv_get_settings_tabs() ),
96
+                    ),
97
+                ),
98
+                array(
99
+                    'methods'             => WP_REST_Server::READABLE,
100
+                    'callback'            => array( $this, 'get_sections' ),
101
+                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
102
+                ),
103
+                'schema' => '__return_empty_array',
104
+            )
105
+        );
106
+
107
+        // List all registered settings for a given tab.
108
+        register_rest_route(
109
+            $namespace,
110
+            $this->rest_base . '/(?P<tab>[\w-]+)/(?P<section>[\w-]+)',
111
+            array(
112
+                'args'   => array(
113
+                    'tab'     => array(
114
+                        'description' => __( 'Unique identifier for the tab whose settings should be retrieved.', 'invoicing' ),
115
+                        'type'        => 'string',
116
+                        'required'    => true,
117
+                        'enum'        => array_keys( wpinv_get_settings_tabs() ),
118
+                    ),
119
+                    'section' => array(
120
+                        'description' => __( 'The section in the tab whose settings should be retrieved.', 'invoicing' ),
121
+                        'type'        => 'string',
122
+                        'required'    => true,
123
+                    ),
124
+                ),
125
+                array(
126
+                    'methods'             => WP_REST_Server::READABLE,
127
+                    'callback'            => array( $this, 'get_items' ),
128
+                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
129
+                ),
130
+                'schema' => array( $this, 'get_public_item_schema' ),
131
+            )
132
+        ); 
133
+
134
+        register_rest_route(
135
+            $namespace,
136
+            '/' . $this->rest_base . '/batch',
137
+            array(
138
+                'args'   => array(
139
+                    'id' => array(
140
+                        'description' => __( 'Setting ID.', 'invoicing' ),
141
+                        'type'        => 'string',
142
+                    ),
143
+                ),
144
+                array(
145
+                    'methods'             => WP_REST_Server::EDITABLE,
146
+                    'callback'            => array( $this, 'batch_items' ),
147
+                    'permission_callback' => array( $this, 'batch_items_permissions_check' ),
148
+                    'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
149
+                ),
150
+                'schema' => array( $this, 'get_public_batch_schema' ),
151
+            )
152
+        );
153
+
154
+    }
155
+
156
+    /**
157
+     * Return all settings.
158
+     *
159
+     * @since  2.0.0
160
+     * @param  WP_REST_Request $request Request data.
161
+     * @return WP_Error|WP_REST_Response
162
+     */
163
+    public function get_items( $request ) {
164
+
165
+        $settings = $this->get_settings();
166
+
167
+        if ( ! isset( $settings[ $request['tab'] ] ) ) {
168
+            return new WP_Error( 'rest_invalid_tab', __( 'Invalid tab.', 'invoicing' ), array( 'status' => 400 ) );
169
+        }
170
+
171
+        if ( ! isset( $settings[ $request['tab'] ][ $request['section'] ] ) ) {
172
+            return new WP_Error( 'rest_invalid_section', __( 'Invalid section.', 'invoicing' ), array( 'status' => 400 ) );
173
+        }
174
+
175
+        $settings = $settings[ $request['tab'] ][ $request['section'] ];
176
+        $prepared = array();
177
+
178
+        foreach ( $settings as $setting ) {
179
+
180
+            $setting      = $this->sanitize_setting( $setting );
181
+            $setting_data = $this->prepare_item_for_response( $setting, $request );
182
+            $setting_data = $this->prepare_response_for_collection( $setting_data );
183
+
184
+            if ( $this->is_setting_type_valid( $setting['type'] ) ) {
185
+                $prepared[]   = $setting_data;
186
+            }
187 187
 }
188 188
 
189
-		return rest_ensure_response( $prepared );
190
-	}
191
-
192
-	/**
193
-	 * Return a single setting.
194
-	 *
195
-	 * @since  2.0.0
196
-	 * @param  WP_REST_Request $request Request data.
197
-	 * @return WP_Error|WP_REST_Response
198
-	 */
199
-	public function get_item( $request ) {
200
-		$setting  = $this->get_setting( $request['id'] );
201
-
202
-		if ( is_wp_error( $setting ) ) {
203
-			return $setting;
204
-		}
205
-
206
-		$setting  = $this->sanitize_setting( $setting );
207
-		$response = $this->prepare_item_for_response( $setting, $request );
208
-		return rest_ensure_response( $response );
209
-	}
210
-
211
-	/**
212
-	 * Update a single setting.
213
-	 *
214
-	 * @since  2.0.0
215
-	 * @param  WP_REST_Request $request Request data.
216
-	 * @return WP_Error|WP_REST_Response
217
-	 */
218
-	public function update_item( $request ) {
219
-		$setting = $this->get_setting( $request['id'] );
220
-
221
-		if ( is_wp_error( $setting ) ) {
222
-			return $setting;
223
-		}
224
-
225
-		if ( is_callable( array( $this, 'validate_setting_' . $setting['type'] . '_field' ) ) ) {
226
-			$value = $this->{'validate_setting_' . $setting['type'] . '_field'}( $request['value'], $setting );
227
-		} else {
228
-			$value = $this->validate_setting_text_field( $request['value'], $setting );
229
-		}
230
-
231
-		if ( is_wp_error( $value ) ) {
232
-			return $value;
233
-		}
234
-
235
-		wpinv_update_option( $request['id'], $value );
236
-		$setting['value'] = $value;
237
-		$setting          = $this->sanitize_setting( $setting );
238
-		$response         = $this->prepare_item_for_response( $setting, $request );
239
-
240
-		return rest_ensure_response( $response );
241
-	}
242
-
243
-	/**
244
-	 * Makes sure the current user has access to READ the settings APIs.
245
-	 *
246
-	 * @since  2.0.0
247
-	 * @param WP_REST_Request $request Full data about the request.
248
-	 * @return WP_Error|boolean
249
-	 */
250
-	public function get_items_permissions_check( $request ) {
251
-		if ( ! wpinv_current_user_can_manage_invoicing() ) {
252
-			return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
253
-		}
254
-
255
-		return true;
256
-	}
257
-
258
-	/**
259
-	 * Makes sure the current user has access to WRITE the settings APIs.
260
-	 *
261
-	 * @since  2.0.0
262
-	 * @param WP_REST_Request $request Full data about the request.
263
-	 * @return WP_Error|boolean
264
-	 */
265
-	public function update_items_permissions_check( $request ) {
266
-		if ( ! wpinv_current_user_can_manage_invoicing() ) {
267
-			return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
268
-		}
269
-
270
-		return true;
271
-	}
272
-
273
-	/**
274
-	 * Check if a given request has access batch create, update and delete items.
275
-	 *
276
-	 * @param  WP_REST_Request $request Full details about the request.
277
-	 *
278
-	 * @return boolean|WP_Error
279
-	 */
280
-	public function batch_items_permissions_check( $request ) {
281
-		return wpinv_current_user_can_manage_invoicing() ? true : new WP_Error( 'rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
282
-	}
283
-
284
-	/**
285
-	 * Prepare links for the request.
286
-	 *
287
-	 * @param string $setting_id Setting ID.
288
-	 * @return array Links for the given setting.
289
-	 */
290
-	protected function prepare_links( $setting_id ) {
291
-
292
-		$links = array(
293
-			'self'       => array(
294
-				'href' => rest_url( sprintf( '/%s/%s/setting/%s', $this->namespace, $this->rest_base, $setting_id ) ),
295
-			),
296
-			'collection' => array(
297
-				'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
298
-			),
299
-		);
300
-
301
-		return $links;
302
-	}
303
-
304
-	/**
305
-	 * Prepare a settings object for serialization.
306
-	 *
307
-	 * @since  2.0.0
308
-	 * @param array           $item Setting object.
309
-	 * @param WP_REST_Request $request Request object.
310
-	 * @return WP_REST_Response $response Response data.
311
-	 */
312
-	public function prepare_item_for_response( $item, $request ) {
313
-		$context = empty( $request['context'] ) ? 'view' : $request['context'];
314
-		$data    = $this->add_additional_fields_to_object( $item, $request );
315
-		$data    = $this->filter_response_by_context( $data, $context );
316
-
317
-		$response = rest_ensure_response( $data );
318
-
319
-		$response->add_links( $this->prepare_links( $item['id'] ) );
320
-
321
-		return $response;
322
-	}
323
-
324
-	/**
325
-	 * Filters out bad values from the settings array/filter so we
326
-	 * only return known values via the API.
327
-	 *
328
-	 * @since 2.0.0
329
-	 * @param  array $setting Setting.
330
-	 * @return array
331
-	 */
332
-	public function filter_setting( $setting ) {
333
-		return array_intersect_key(
334
-			$setting,
335
-			array_flip( array_filter( array_keys( $setting ), array( $this, 'allowed_setting_keys' ) ) )
336
-		);
337
-	}
338
-
339
-	/**
340
-	 * Callback for allowed keys for each setting response.
341
-	 *
342
-	 * @param  string $key Key to check.
343
-	 * @return boolean
344
-	 */
345
-	public function allowed_setting_keys( $key ) {
346
-		return in_array( $key, array_keys( $this->setting_defaults() ), true );
347
-	}
348
-
349
-	/**
350
-	 * Returns default options for a setting. null means the field is required.
351
-	 *
352
-	 * @since  2.0.0
353
-	 * @return array
354
-	 */
355
-	protected function setting_defaults() {
356
-		return array(
357
-			'id'          => null,
358
-			'name'        => null,
359
-			'desc'        => '',
360
-			'options'     => array(),
361
-			'std'         => false,
362
-			'value'       => false,
363
-			'placeholder' => '',
364
-			'readonly'    => false,
365
-			'faux'        => false,
366
-			'section'     => 'main',
367
-			'tab'         => 'general',
368
-			'type'        => 'text',
369
-		);
370
-	}
371
-
372
-	/**
373
-	 * Sanitizes a setting's field.
374
-	 *
375
-	 * @param  array $setting The setting to sanitize.
376
-	 * @return array
377
-	 */
378
-	public function sanitize_setting( $setting ) {
379
-
380
-		$setting          = wp_parse_args( $setting, $this->setting_defaults() );
381
-		$setting['value'] = wpinv_get_option( $setting['id'], $setting['std'] );
382
-		return $this->filter_setting( $setting );
383
-
384
-	}
385
-
386
-	/**
387
-	 * Get setting data.
388
-	 *
389
-	 * @since  2.0.0
390
-	 * @param string $setting_id Setting ID.
391
-	 * @return array|WP_Error
392
-	 */
393
-	public function get_setting( $setting_id ) {
394
-
395
-		if ( empty( $setting_id ) ) {
396
-			return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'invoicing' ), array( 'status' => 404 ) );
397
-		}
398
-
399
-		$settings  = $this->get_settings();
400
-
401
-		foreach ( $settings as $tabs ) {
402
-
403
-			foreach ( $tabs as $sections ) {
404
-
405
-				if ( isset( $sections[ $setting_id ] ) ) {
406
-					if ( ! $this->is_setting_type_valid( $sections[ $setting_id ]['type'] ) ) {
407
-						return new WP_Error( 'rest_setting_setting_type_invalid', __( 'Invalid setting type.', 'invoicing' ), array( 'status' => 404 ) );
408
-					}
409
-
410
-					return $sections[ $setting_id ];
411
-				}
189
+        return rest_ensure_response( $prepared );
190
+    }
191
+
192
+    /**
193
+     * Return a single setting.
194
+     *
195
+     * @since  2.0.0
196
+     * @param  WP_REST_Request $request Request data.
197
+     * @return WP_Error|WP_REST_Response
198
+     */
199
+    public function get_item( $request ) {
200
+        $setting  = $this->get_setting( $request['id'] );
201
+
202
+        if ( is_wp_error( $setting ) ) {
203
+            return $setting;
204
+        }
205
+
206
+        $setting  = $this->sanitize_setting( $setting );
207
+        $response = $this->prepare_item_for_response( $setting, $request );
208
+        return rest_ensure_response( $response );
209
+    }
210
+
211
+    /**
212
+     * Update a single setting.
213
+     *
214
+     * @since  2.0.0
215
+     * @param  WP_REST_Request $request Request data.
216
+     * @return WP_Error|WP_REST_Response
217
+     */
218
+    public function update_item( $request ) {
219
+        $setting = $this->get_setting( $request['id'] );
220
+
221
+        if ( is_wp_error( $setting ) ) {
222
+            return $setting;
223
+        }
224
+
225
+        if ( is_callable( array( $this, 'validate_setting_' . $setting['type'] . '_field' ) ) ) {
226
+            $value = $this->{'validate_setting_' . $setting['type'] . '_field'}( $request['value'], $setting );
227
+        } else {
228
+            $value = $this->validate_setting_text_field( $request['value'], $setting );
229
+        }
230
+
231
+        if ( is_wp_error( $value ) ) {
232
+            return $value;
233
+        }
234
+
235
+        wpinv_update_option( $request['id'], $value );
236
+        $setting['value'] = $value;
237
+        $setting          = $this->sanitize_setting( $setting );
238
+        $response         = $this->prepare_item_for_response( $setting, $request );
239
+
240
+        return rest_ensure_response( $response );
241
+    }
242
+
243
+    /**
244
+     * Makes sure the current user has access to READ the settings APIs.
245
+     *
246
+     * @since  2.0.0
247
+     * @param WP_REST_Request $request Full data about the request.
248
+     * @return WP_Error|boolean
249
+     */
250
+    public function get_items_permissions_check( $request ) {
251
+        if ( ! wpinv_current_user_can_manage_invoicing() ) {
252
+            return new WP_Error( 'rest_cannot_view', __( 'Sorry, you cannot list resources.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
253
+        }
254
+
255
+        return true;
256
+    }
257
+
258
+    /**
259
+     * Makes sure the current user has access to WRITE the settings APIs.
260
+     *
261
+     * @since  2.0.0
262
+     * @param WP_REST_Request $request Full data about the request.
263
+     * @return WP_Error|boolean
264
+     */
265
+    public function update_items_permissions_check( $request ) {
266
+        if ( ! wpinv_current_user_can_manage_invoicing() ) {
267
+            return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you cannot edit this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
268
+        }
269
+
270
+        return true;
271
+    }
272
+
273
+    /**
274
+     * Check if a given request has access batch create, update and delete items.
275
+     *
276
+     * @param  WP_REST_Request $request Full details about the request.
277
+     *
278
+     * @return boolean|WP_Error
279
+     */
280
+    public function batch_items_permissions_check( $request ) {
281
+        return wpinv_current_user_can_manage_invoicing() ? true : new WP_Error( 'rest_cannot_batch', __( 'Sorry, you are not allowed to batch manipulate this resource.', 'invoicing' ), array( 'status' => rest_authorization_required_code() ) );
282
+    }
283
+
284
+    /**
285
+     * Prepare links for the request.
286
+     *
287
+     * @param string $setting_id Setting ID.
288
+     * @return array Links for the given setting.
289
+     */
290
+    protected function prepare_links( $setting_id ) {
291
+
292
+        $links = array(
293
+            'self'       => array(
294
+                'href' => rest_url( sprintf( '/%s/%s/setting/%s', $this->namespace, $this->rest_base, $setting_id ) ),
295
+            ),
296
+            'collection' => array(
297
+                'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
298
+            ),
299
+        );
300
+
301
+        return $links;
302
+    }
303
+
304
+    /**
305
+     * Prepare a settings object for serialization.
306
+     *
307
+     * @since  2.0.0
308
+     * @param array           $item Setting object.
309
+     * @param WP_REST_Request $request Request object.
310
+     * @return WP_REST_Response $response Response data.
311
+     */
312
+    public function prepare_item_for_response( $item, $request ) {
313
+        $context = empty( $request['context'] ) ? 'view' : $request['context'];
314
+        $data    = $this->add_additional_fields_to_object( $item, $request );
315
+        $data    = $this->filter_response_by_context( $data, $context );
316
+
317
+        $response = rest_ensure_response( $data );
318
+
319
+        $response->add_links( $this->prepare_links( $item['id'] ) );
320
+
321
+        return $response;
322
+    }
323
+
324
+    /**
325
+     * Filters out bad values from the settings array/filter so we
326
+     * only return known values via the API.
327
+     *
328
+     * @since 2.0.0
329
+     * @param  array $setting Setting.
330
+     * @return array
331
+     */
332
+    public function filter_setting( $setting ) {
333
+        return array_intersect_key(
334
+            $setting,
335
+            array_flip( array_filter( array_keys( $setting ), array( $this, 'allowed_setting_keys' ) ) )
336
+        );
337
+    }
338
+
339
+    /**
340
+     * Callback for allowed keys for each setting response.
341
+     *
342
+     * @param  string $key Key to check.
343
+     * @return boolean
344
+     */
345
+    public function allowed_setting_keys( $key ) {
346
+        return in_array( $key, array_keys( $this->setting_defaults() ), true );
347
+    }
348
+
349
+    /**
350
+     * Returns default options for a setting. null means the field is required.
351
+     *
352
+     * @since  2.0.0
353
+     * @return array
354
+     */
355
+    protected function setting_defaults() {
356
+        return array(
357
+            'id'          => null,
358
+            'name'        => null,
359
+            'desc'        => '',
360
+            'options'     => array(),
361
+            'std'         => false,
362
+            'value'       => false,
363
+            'placeholder' => '',
364
+            'readonly'    => false,
365
+            'faux'        => false,
366
+            'section'     => 'main',
367
+            'tab'         => 'general',
368
+            'type'        => 'text',
369
+        );
370
+    }
371
+
372
+    /**
373
+     * Sanitizes a setting's field.
374
+     *
375
+     * @param  array $setting The setting to sanitize.
376
+     * @return array
377
+     */
378
+    public function sanitize_setting( $setting ) {
379
+
380
+        $setting          = wp_parse_args( $setting, $this->setting_defaults() );
381
+        $setting['value'] = wpinv_get_option( $setting['id'], $setting['std'] );
382
+        return $this->filter_setting( $setting );
383
+
384
+    }
385
+
386
+    /**
387
+     * Get setting data.
388
+     *
389
+     * @since  2.0.0
390
+     * @param string $setting_id Setting ID.
391
+     * @return array|WP_Error
392
+     */
393
+    public function get_setting( $setting_id ) {
394
+
395
+        if ( empty( $setting_id ) ) {
396
+            return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'invoicing' ), array( 'status' => 404 ) );
397
+        }
398
+
399
+        $settings  = $this->get_settings();
400
+
401
+        foreach ( $settings as $tabs ) {
402
+
403
+            foreach ( $tabs as $sections ) {
404
+
405
+                if ( isset( $sections[ $setting_id ] ) ) {
406
+                    if ( ! $this->is_setting_type_valid( $sections[ $setting_id ]['type'] ) ) {
407
+                        return new WP_Error( 'rest_setting_setting_type_invalid', __( 'Invalid setting type.', 'invoicing' ), array( 'status' => 404 ) );
408
+                    }
409
+
410
+                    return $sections[ $setting_id ];
411
+                }
412 412
 }
413 413
 }
414 414
 
415
-		return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'invoicing' ), array( 'status' => 404 ) );
416
-	}
417
-
418
-	/**
419
-	 * Get all tabs.
420
-	 *
421
-	 * @param  WP_REST_Request $request Request data.
422
-	 * @return array
423
-	 */
424
-	public function get_tabs( $request ) {
425
-		$tabs     = wpinv_get_settings_tabs();
426
-		$prepared = array();
427
-
428
-		foreach ( $tabs as $id => $tab ) {
429
-
430
-			$_request        = $request;
431
-			$_request['tab'] = sanitize_title( $id );
432
-			$data            = array(
433
-				'id'       => sanitize_title( $id ),
434
-				'label'    => sanitize_text_field( $tab ),
435
-				'sections' => $this->get_sections( $_request ),
436
-			);
437
-
438
-			$data     = $this->add_additional_fields_to_object( $data, $request );
439
-			$response = rest_ensure_response( $data );
440
-
441
-			if ( ! is_wp_error( $response ) ) {
442
-				$links = array(
443
-					'sections'   => array(
444
-						'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $id ) ),
445
-					),
446
-					'collection' => array(
447
-						'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
448
-					),
449
-				);
450
-				$response->add_links( $links );
451
-				$response = $this->prepare_response_for_collection( $response );
452
-			}
453
-
454
-			$prepared[] = $response;
455
-
456
-		}
457
-
458
-		return rest_ensure_response( $prepared );
459
-	}
460
-
461
-	/**
462
-	 * Get all sections.
463
-	 *
464
-	 * @param  WP_REST_Request $request Request data.
465
-	 * @return array
466
-	 */
467
-	public function get_sections( $request ) {
468
-
469
-		$tab      = sanitize_title( $request['tab'] );
470
-		$sections = wpinv_get_settings_tab_sections( $tab );
471
-		$prepared = array();
472
-
473
-		foreach ( $sections as $id => $section ) {
474
-
475
-			$data            = array(
476
-				'id'    => sanitize_title( $id ),
477
-				'label' => sanitize_text_field( $section ),
478
-			);
479
-
480
-			$data     = $this->add_additional_fields_to_object( $data, $request );
481
-			$response = rest_ensure_response( $data );
482
-
483
-			if ( ! is_wp_error( $response ) ) {
484
-				$links = array(
485
-					'settings'   => array(
486
-						'href' => rest_url( sprintf( '/%s/%s/%s/%s', $this->namespace, $this->rest_base, $tab, $id ) ),
487
-					),
488
-					'collection' => array(
489
-						'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $tab ) ),
490
-					),
491
-					'tabs'       => array(
492
-						'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
493
-					),
494
-				);
495
-				$response->add_links( $links );
496
-				$response = $this->prepare_response_for_collection( $response );
497
-			}
498
-
499
-			$prepared[] = $response;
500
-
501
-		}
502
-
503
-		return rest_ensure_response( $prepared );
504
-	}
505
-
506
-	/**
507
-	 * Get all settings.
508
-	 *
509
-	 * @return array
510
-	 */
511
-	public function get_settings() {
512
-
513
-		if ( empty( $this->settings ) ) {
514
-			$this->settings = wpinv_get_registered_settings();
515
-		}
516
-
517
-		return $this->settings;
518
-
519
-	}
520
-
521
-	/**
522
-	 * Boolean for if a setting type is a valid supported setting type.
523
-	 *
524
-	 * @since  2.0.0
525
-	 * @param  string $type Type.
526
-	 * @return bool
527
-	 */
528
-	public function is_setting_type_valid( $type ) {
529
-
530
-		return in_array(
531
-			$type,
415
+        return new WP_Error( 'rest_setting_setting_invalid', __( 'Invalid setting.', 'invoicing' ), array( 'status' => 404 ) );
416
+    }
417
+
418
+    /**
419
+     * Get all tabs.
420
+     *
421
+     * @param  WP_REST_Request $request Request data.
422
+     * @return array
423
+     */
424
+    public function get_tabs( $request ) {
425
+        $tabs     = wpinv_get_settings_tabs();
426
+        $prepared = array();
427
+
428
+        foreach ( $tabs as $id => $tab ) {
429
+
430
+            $_request        = $request;
431
+            $_request['tab'] = sanitize_title( $id );
432
+            $data            = array(
433
+                'id'       => sanitize_title( $id ),
434
+                'label'    => sanitize_text_field( $tab ),
435
+                'sections' => $this->get_sections( $_request ),
436
+            );
437
+
438
+            $data     = $this->add_additional_fields_to_object( $data, $request );
439
+            $response = rest_ensure_response( $data );
440
+
441
+            if ( ! is_wp_error( $response ) ) {
442
+                $links = array(
443
+                    'sections'   => array(
444
+                        'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $id ) ),
445
+                    ),
446
+                    'collection' => array(
447
+                        'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
448
+                    ),
449
+                );
450
+                $response->add_links( $links );
451
+                $response = $this->prepare_response_for_collection( $response );
452
+            }
453
+
454
+            $prepared[] = $response;
455
+
456
+        }
457
+
458
+        return rest_ensure_response( $prepared );
459
+    }
460
+
461
+    /**
462
+     * Get all sections.
463
+     *
464
+     * @param  WP_REST_Request $request Request data.
465
+     * @return array
466
+     */
467
+    public function get_sections( $request ) {
468
+
469
+        $tab      = sanitize_title( $request['tab'] );
470
+        $sections = wpinv_get_settings_tab_sections( $tab );
471
+        $prepared = array();
472
+
473
+        foreach ( $sections as $id => $section ) {
474
+
475
+            $data            = array(
476
+                'id'    => sanitize_title( $id ),
477
+                'label' => sanitize_text_field( $section ),
478
+            );
479
+
480
+            $data     = $this->add_additional_fields_to_object( $data, $request );
481
+            $response = rest_ensure_response( $data );
482
+
483
+            if ( ! is_wp_error( $response ) ) {
484
+                $links = array(
485
+                    'settings'   => array(
486
+                        'href' => rest_url( sprintf( '/%s/%s/%s/%s', $this->namespace, $this->rest_base, $tab, $id ) ),
487
+                    ),
488
+                    'collection' => array(
489
+                        'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $tab ) ),
490
+                    ),
491
+                    'tabs'       => array(
492
+                        'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
493
+                    ),
494
+                );
495
+                $response->add_links( $links );
496
+                $response = $this->prepare_response_for_collection( $response );
497
+            }
498
+
499
+            $prepared[] = $response;
500
+
501
+        }
502
+
503
+        return rest_ensure_response( $prepared );
504
+    }
505
+
506
+    /**
507
+     * Get all settings.
508
+     *
509
+     * @return array
510
+     */
511
+    public function get_settings() {
512
+
513
+        if ( empty( $this->settings ) ) {
514
+            $this->settings = wpinv_get_registered_settings();
515
+        }
516
+
517
+        return $this->settings;
518
+
519
+    }
520
+
521
+    /**
522
+     * Boolean for if a setting type is a valid supported setting type.
523
+     *
524
+     * @since  2.0.0
525
+     * @param  string $type Type.
526
+     * @return bool
527
+     */
528
+    public function is_setting_type_valid( $type ) {
529
+
530
+        return in_array(
531
+            $type,
532 532
             array(
533
-				'text',         // Validates with validate_setting_text_field.
534
-				'email',        // Validates with validate_setting_text_field.
535
-				'number',       // Validates with validate_setting_text_field.
536
-				'color',        // Validates with validate_setting_text_field.
537
-				'password',     // Validates with validate_setting_text_field.
538
-				'textarea',     // Validates with validate_setting_textarea_field.
539
-				'select',       // Validates with validate_setting_select_field.
540
-				'multiselect',  // Validates with validate_setting_multiselect_field.
541
-				'radio',        // Validates with validate_setting_radio_field (-> validate_setting_select_field).
542
-				'checkbox',     // Validates with validate_setting_checkbox_field.
543
-				'header',       // Validates with validate_setting_text_field.
544
-			)
545
-		);
546
-
547
-	}
548
-
549
-	/**
550
-	 * Get the settings schema, conforming to JSON Schema.
551
-	 *
552
-	 * @return array
553
-	 */
554
-	public function get_item_schema() {
555
-
556
-		// Maybe retrieve the schema from cache.
557
-		if ( ! empty( $this->schema ) ) {
558
-			return $this->add_additional_fields_schema( $this->schema );
559
-		}
560
-
561
-		$schema = array(
562
-			'$schema'    => 'http://json-schema.org/draft-04/schema#',
563
-			'title'      => 'setting',
564
-			'type'       => 'object',
565
-			'properties' => array(
566
-				'id'          => array(
567
-					'description' => __( 'A unique identifier for the setting.', 'invoicing' ),
568
-					'type'        => 'string',
569
-					'arg_options' => array(
570
-						'sanitize_callback' => 'sanitize_title',
571
-					),
572
-					'context'     => array( 'view', 'edit' ),
573
-					'readonly'    => true,
574
-				),
575
-				'tab'         => array(
576
-					'description' => __( 'An identifier for the tab this setting belongs to.', 'invoicing' ),
577
-					'type'        => 'string',
578
-					'arg_options' => array(
579
-						'sanitize_callback' => 'sanitize_title',
580
-					),
581
-					'context'     => array( 'view', 'edit' ),
582
-					'readonly'    => true,
583
-				),
584
-				'section'     => array(
585
-					'description' => __( 'An identifier for the section this setting belongs to.', 'invoicing' ),
586
-					'type'        => 'string',
587
-					'arg_options' => array(
588
-						'sanitize_callback' => 'sanitize_title',
589
-					),
590
-					'context'     => array( 'view', 'edit' ),
591
-					'readonly'    => true,
592
-				),
593
-				'name'        => array(
594
-					'description' => __( 'A human readable label for the setting used in interfaces.', 'invoicing' ),
595
-					'type'        => 'string',
596
-					'arg_options' => array(
597
-						'sanitize_callback' => 'sanitize_text_field',
598
-					),
599
-					'context'     => array( 'view', 'edit' ),
600
-					'readonly'    => true,
601
-				),
602
-				'desc'        => array(
603
-					'description' => __( 'A human readable description for the setting used in interfaces.', 'invoicing' ),
604
-					'type'        => 'string',
605
-					'context'     => array( 'view', 'edit' ),
606
-					'readonly'    => true,
607
-				),
608
-				'value'       => array(
609
-					'description' => __( 'The current value of this setting.', 'invoicing' ),
610
-					'type'        => 'mixed',
611
-					'context'     => array( 'view', 'edit' ),
612
-				),
613
-				'default'     => array(
614
-					'description' => __( 'Default value for the setting.', 'invoicing' ),
615
-					'type'        => 'mixed',
616
-					'context'     => array( 'view', 'edit' ),
617
-					'readonly'    => true,
618
-				),
619
-				'placeholder' => array(
620
-					'description' => __( 'Placeholder text to be displayed in text inputs.', 'invoicing' ),
621
-					'type'        => 'string',
622
-					'arg_options' => array(
623
-						'sanitize_callback' => 'sanitize_text_field',
624
-					),
625
-					'context'     => array( 'view', 'edit' ),
626
-					'readonly'    => true,
627
-				),
628
-				'type'        => array(
629
-					'description' => __( 'Type of setting.', 'invoicing' ),
630
-					'type'        => 'string',
631
-					'arg_options' => array(
632
-						'sanitize_callback' => 'sanitize_text_field',
633
-					),
634
-					'context'     => array( 'view', 'edit' ),
635
-					'enum'        => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox', 'raw_html' ),
636
-					'readonly'    => true,
637
-				),
638
-				'options'     => array(
639
-					'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'invoicing' ),
640
-					'type'        => 'object',
641
-					'context'     => array( 'view', 'edit' ),
642
-					'readonly'    => true,
643
-				),
644
-				'readonly'    => array(
645
-					'description' => __( 'Whether or not this setting is readonly', 'invoicing' ),
646
-					'type'        => 'string',
647
-					'context'     => array( 'view' ),
648
-					'readonly'    => true,
649
-				),
650
-				'faux'        => array(
651
-					'description' => __( 'Whether or not this setting is readonly/faux', 'invoicing' ),
652
-					'type'        => 'string',
653
-					'context'     => array( 'view' ),
654
-					'readonly'    => true,
655
-				),
656
-			),
657
-		);
658
-
659
-		// Filters the settings schema for the REST API.
533
+                'text',         // Validates with validate_setting_text_field.
534
+                'email',        // Validates with validate_setting_text_field.
535
+                'number',       // Validates with validate_setting_text_field.
536
+                'color',        // Validates with validate_setting_text_field.
537
+                'password',     // Validates with validate_setting_text_field.
538
+                'textarea',     // Validates with validate_setting_textarea_field.
539
+                'select',       // Validates with validate_setting_select_field.
540
+                'multiselect',  // Validates with validate_setting_multiselect_field.
541
+                'radio',        // Validates with validate_setting_radio_field (-> validate_setting_select_field).
542
+                'checkbox',     // Validates with validate_setting_checkbox_field.
543
+                'header',       // Validates with validate_setting_text_field.
544
+            )
545
+        );
546
+
547
+    }
548
+
549
+    /**
550
+     * Get the settings schema, conforming to JSON Schema.
551
+     *
552
+     * @return array
553
+     */
554
+    public function get_item_schema() {
555
+
556
+        // Maybe retrieve the schema from cache.
557
+        if ( ! empty( $this->schema ) ) {
558
+            return $this->add_additional_fields_schema( $this->schema );
559
+        }
560
+
561
+        $schema = array(
562
+            '$schema'    => 'http://json-schema.org/draft-04/schema#',
563
+            'title'      => 'setting',
564
+            'type'       => 'object',
565
+            'properties' => array(
566
+                'id'          => array(
567
+                    'description' => __( 'A unique identifier for the setting.', 'invoicing' ),
568
+                    'type'        => 'string',
569
+                    'arg_options' => array(
570
+                        'sanitize_callback' => 'sanitize_title',
571
+                    ),
572
+                    'context'     => array( 'view', 'edit' ),
573
+                    'readonly'    => true,
574
+                ),
575
+                'tab'         => array(
576
+                    'description' => __( 'An identifier for the tab this setting belongs to.', 'invoicing' ),
577
+                    'type'        => 'string',
578
+                    'arg_options' => array(
579
+                        'sanitize_callback' => 'sanitize_title',
580
+                    ),
581
+                    'context'     => array( 'view', 'edit' ),
582
+                    'readonly'    => true,
583
+                ),
584
+                'section'     => array(
585
+                    'description' => __( 'An identifier for the section this setting belongs to.', 'invoicing' ),
586
+                    'type'        => 'string',
587
+                    'arg_options' => array(
588
+                        'sanitize_callback' => 'sanitize_title',
589
+                    ),
590
+                    'context'     => array( 'view', 'edit' ),
591
+                    'readonly'    => true,
592
+                ),
593
+                'name'        => array(
594
+                    'description' => __( 'A human readable label for the setting used in interfaces.', 'invoicing' ),
595
+                    'type'        => 'string',
596
+                    'arg_options' => array(
597
+                        'sanitize_callback' => 'sanitize_text_field',
598
+                    ),
599
+                    'context'     => array( 'view', 'edit' ),
600
+                    'readonly'    => true,
601
+                ),
602
+                'desc'        => array(
603
+                    'description' => __( 'A human readable description for the setting used in interfaces.', 'invoicing' ),
604
+                    'type'        => 'string',
605
+                    'context'     => array( 'view', 'edit' ),
606
+                    'readonly'    => true,
607
+                ),
608
+                'value'       => array(
609
+                    'description' => __( 'The current value of this setting.', 'invoicing' ),
610
+                    'type'        => 'mixed',
611
+                    'context'     => array( 'view', 'edit' ),
612
+                ),
613
+                'default'     => array(
614
+                    'description' => __( 'Default value for the setting.', 'invoicing' ),
615
+                    'type'        => 'mixed',
616
+                    'context'     => array( 'view', 'edit' ),
617
+                    'readonly'    => true,
618
+                ),
619
+                'placeholder' => array(
620
+                    'description' => __( 'Placeholder text to be displayed in text inputs.', 'invoicing' ),
621
+                    'type'        => 'string',
622
+                    'arg_options' => array(
623
+                        'sanitize_callback' => 'sanitize_text_field',
624
+                    ),
625
+                    'context'     => array( 'view', 'edit' ),
626
+                    'readonly'    => true,
627
+                ),
628
+                'type'        => array(
629
+                    'description' => __( 'Type of setting.', 'invoicing' ),
630
+                    'type'        => 'string',
631
+                    'arg_options' => array(
632
+                        'sanitize_callback' => 'sanitize_text_field',
633
+                    ),
634
+                    'context'     => array( 'view', 'edit' ),
635
+                    'enum'        => array( 'text', 'email', 'number', 'color', 'password', 'textarea', 'select', 'multiselect', 'radio', 'image_width', 'checkbox', 'raw_html' ),
636
+                    'readonly'    => true,
637
+                ),
638
+                'options'     => array(
639
+                    'description' => __( 'Array of options (key value pairs) for inputs such as select, multiselect, and radio buttons.', 'invoicing' ),
640
+                    'type'        => 'object',
641
+                    'context'     => array( 'view', 'edit' ),
642
+                    'readonly'    => true,
643
+                ),
644
+                'readonly'    => array(
645
+                    'description' => __( 'Whether or not this setting is readonly', 'invoicing' ),
646
+                    'type'        => 'string',
647
+                    'context'     => array( 'view' ),
648
+                    'readonly'    => true,
649
+                ),
650
+                'faux'        => array(
651
+                    'description' => __( 'Whether or not this setting is readonly/faux', 'invoicing' ),
652
+                    'type'        => 'string',
653
+                    'context'     => array( 'view' ),
654
+                    'readonly'    => true,
655
+                ),
656
+            ),
657
+        );
658
+
659
+        // Filters the settings schema for the REST API.
660 660
         $schema = apply_filters( 'getpaid_rest_settings_schema', $schema );
661 661
 
662
-		// Cache the settings schema.
663
-		$this->schema = $schema;
664
-
665
-		return $this->add_additional_fields_schema( $this->schema );
666
-
667
-	}
668
-
669
-	/**
670
-	 * Validate a text value for a text based setting.
671
-	 *
672
-	 * @since 2.0.0
673
-	 * @param string $value Value.
674
-	 * @param array  $setting Setting.
675
-	 * @return string
676
-	 */
677
-	public function validate_setting_text_field( $value ) {
678
-		$value = is_null( $value ) ? '' : $value;
679
-		return wp_kses_post( trim( stripslashes( $value ) ) );
680
-	}
681
-
682
-	/**
683
-	 * Validate select based settings.
684
-	 *
685
-	 * @since 2.0.0
686
-	 * @param string $value Value.
687
-	 * @param array  $setting Setting.
688
-	 * @return string|WP_Error
689
-	 */
690
-	public function validate_setting_select_field( $value, $setting ) {
691
-		if ( array_key_exists( $value, $setting['options'] ) ) {
692
-			return $value;
693
-		} else {
694
-			return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'invoicing' ), array( 'status' => 400 ) );
695
-		}
696
-	}
697
-
698
-	/**
699
-	 * Validate multiselect based settings.
700
-	 *
701
-	 * @since 2.0.0
702
-	 * @param array $values Values.
703
-	 * @param array $setting Setting.
704
-	 * @return array|WP_Error
705
-	 */
706
-	public function validate_setting_multiselect_field( $values, $setting ) {
707
-		if ( empty( $values ) ) {
708
-			return array();
709
-		}
710
-
711
-		if ( ! is_array( $values ) ) {
712
-			return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'invoicing' ), array( 'status' => 400 ) );
713
-		}
714
-
715
-		$final_values = array();
716
-		foreach ( $values as $value ) {
717
-			if ( array_key_exists( $value, $setting['options'] ) ) {
718
-				$final_values[] = $value;
719
-			}
720
-		}
721
-
722
-		return $final_values;
723
-	}
724
-
725
-	/**
726
-	 * Validate radio based settings.
727
-	 *
728
-	 * @since 2.0.0
729
-	 * @param string $value Value.
730
-	 * @param array  $setting Setting.
731
-	 * @return string|WP_Error
732
-	 */
733
-	public function validate_setting_radio_field( $value, $setting ) {
734
-		return $this->validate_setting_select_field( $value, $setting );
735
-	}
736
-
737
-	/**
738
-	 * Validate checkbox based settings.
739
-	 *
740
-	 * @since 2.0.0
741
-	 * @param string $value Value.
742
-	 * @return int
743
-	 */
744
-	public function validate_setting_checkbox_field( $value ) {
745
-		return (int) ! empty( $value );
746
-	}
747
-
748
-	/**
749
-	 * Validate textarea based settings.
750
-	 *
751
-	 * @since 2.0.0
752
-	 * @param string $value Value.
753
-	 * @return string
754
-	 */
755
-	public function validate_setting_textarea_field( $value ) {
756
-		$value = is_null( $value ) ? '' : $value;
757
-		return wp_kses(
758
-			trim( stripslashes( $value ) ),
759
-			array_merge(
760
-				array(
761
-					'iframe' => array(
762
-						'src'   => true,
763
-						'style' => true,
764
-						'id'    => true,
765
-						'class' => true,
766
-					),
767
-				),
768
-				wp_kses_allowed_html( 'post' )
769
-			)
770
-		);
771
-	}
662
+        // Cache the settings schema.
663
+        $this->schema = $schema;
664
+
665
+        return $this->add_additional_fields_schema( $this->schema );
666
+
667
+    }
668
+
669
+    /**
670
+     * Validate a text value for a text based setting.
671
+     *
672
+     * @since 2.0.0
673
+     * @param string $value Value.
674
+     * @param array  $setting Setting.
675
+     * @return string
676
+     */
677
+    public function validate_setting_text_field( $value ) {
678
+        $value = is_null( $value ) ? '' : $value;
679
+        return wp_kses_post( trim( stripslashes( $value ) ) );
680
+    }
681
+
682
+    /**
683
+     * Validate select based settings.
684
+     *
685
+     * @since 2.0.0
686
+     * @param string $value Value.
687
+     * @param array  $setting Setting.
688
+     * @return string|WP_Error
689
+     */
690
+    public function validate_setting_select_field( $value, $setting ) {
691
+        if ( array_key_exists( $value, $setting['options'] ) ) {
692
+            return $value;
693
+        } else {
694
+            return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'invoicing' ), array( 'status' => 400 ) );
695
+        }
696
+    }
697
+
698
+    /**
699
+     * Validate multiselect based settings.
700
+     *
701
+     * @since 2.0.0
702
+     * @param array $values Values.
703
+     * @param array $setting Setting.
704
+     * @return array|WP_Error
705
+     */
706
+    public function validate_setting_multiselect_field( $values, $setting ) {
707
+        if ( empty( $values ) ) {
708
+            return array();
709
+        }
710
+
711
+        if ( ! is_array( $values ) ) {
712
+            return new WP_Error( 'rest_setting_value_invalid', __( 'An invalid setting value was passed.', 'invoicing' ), array( 'status' => 400 ) );
713
+        }
714
+
715
+        $final_values = array();
716
+        foreach ( $values as $value ) {
717
+            if ( array_key_exists( $value, $setting['options'] ) ) {
718
+                $final_values[] = $value;
719
+            }
720
+        }
721
+
722
+        return $final_values;
723
+    }
724
+
725
+    /**
726
+     * Validate radio based settings.
727
+     *
728
+     * @since 2.0.0
729
+     * @param string $value Value.
730
+     * @param array  $setting Setting.
731
+     * @return string|WP_Error
732
+     */
733
+    public function validate_setting_radio_field( $value, $setting ) {
734
+        return $this->validate_setting_select_field( $value, $setting );
735
+    }
736
+
737
+    /**
738
+     * Validate checkbox based settings.
739
+     *
740
+     * @since 2.0.0
741
+     * @param string $value Value.
742
+     * @return int
743
+     */
744
+    public function validate_setting_checkbox_field( $value ) {
745
+        return (int) ! empty( $value );
746
+    }
747
+
748
+    /**
749
+     * Validate textarea based settings.
750
+     *
751
+     * @since 2.0.0
752
+     * @param string $value Value.
753
+     * @return string
754
+     */
755
+    public function validate_setting_textarea_field( $value ) {
756
+        $value = is_null( $value ) ? '' : $value;
757
+        return wp_kses(
758
+            trim( stripslashes( $value ) ),
759
+            array_merge(
760
+                array(
761
+                    'iframe' => array(
762
+                        'src'   => true,
763
+                        'style' => true,
764
+                        'id'    => true,
765
+                        'class' => true,
766
+                    ),
767
+                ),
768
+                wp_kses_allowed_html( 'post' )
769
+            )
770
+        );
771
+    }
772 772
 
773 773
 }
Please login to merge, or discard this patch.