Passed
Push — master ( 8aa7be...c93677 )
by Brian
05:15
created

WPInv_Subscriptions_Widget::print_table_body()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
b 0
f 0
dl 0
loc 6
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * Subscriptions Widget Class.
4
 *
5
 * @version 1.0.0
6
 */
7
8
defined( 'ABSPATH' ) || exit;
9
10
/**
11
 * Contains the subscriptions widget.
12
 *
13
 * @package INVOICING
14
 */
15
class WPInv_Subscriptions_Widget extends WP_Super_Duper {
16
17
	/**
18
	 * Register the widget with WordPress.
19
	 *
20
	 */
21
	public function __construct() {
22
23
		$options = array(
24
			'textdomain'    => 'invoicing',
25
			'block-icon'    => 'controls-repeat',
26
			'block-category'=> 'widgets',
27
			'block-keywords'=> "['invoicing','subscriptions', 'getpaid']",
28
			'class_name'     => __CLASS__,
29
			'base_id'       => 'wpinv_subscriptions',
30
			'name'          => __( 'GetPaid > Subscriptions', 'invoicing' ),
31
			'widget_ops'    => array(
32
				'classname'   => 'getpaid-subscriptions bsui',
33
				'description' => esc_html__( "Displays the current user's subscriptions.", 'invoicing' ),
34
			),
35
			'arguments'     => array(
36
				'title'  => array(
37
					'title'       => __( 'Widget title', 'invoicing' ),
38
					'desc'        => __( 'Enter widget title.', 'invoicing' ),
39
					'type'        => 'text',
40
					'desc_tip'    => true,
41
					'default'     => '',
42
					'advanced'    => false
43
				),
44
			)
45
46
		);
47
48
49
		parent::__construct( $options );
50
	}
51
52
	/**
53
	 * Retrieves current user's subscriptions.
54
	 *
55
	 * @return GetPaid_Subscriptions_Query
56
	 */
57
	public function get_subscriptions() {
58
59
		// Prepare license args.
60
		$args  = array(
61
			'customer_in' => get_current_user_id(),
62
			'paged'       => ( get_query_var( 'paged' ) ) ? absint( get_query_var( 'paged' ) ) : 1,
63
		);
64
65
		return new GetPaid_Subscriptions_Query( $args );
66
67
	}
68
69
	/**
70
	 * The Super block output function.
71
	 *
72
	 * @param array $args
73
	 * @param array $widget_args
74
	 * @param string $content
75
	 *
76
	 * @return mixed|string|bool
77
	 */
78
	public function output( $args = array(), $widget_args = array(), $content = '' ) {
79
80
		// Ensure that the user is logged in.
81
		if ( ! is_user_logged_in() ) {
82
83
			return aui()->alert(
84
				array(
85
					'content' => wp_kses_post( __( 'You need to log-in or create an account to view this section.', 'invoicing' ) ),
86
					'type'    => 'error',
87
				)
88
			);
89
90
		}
91
92
		// Are we displaying a single subscription?
93
		if ( isset( $_GET['subscription'] ) ) {
94
			return $this->display_single_subscription( trim( $_GET['subscription'] ) );
95
		}
96
97
		// Retrieve the user's subscriptions.
98
		$subscriptions = $this->get_subscriptions();
99
100
		// Start the output buffer.
101
		ob_start();
102
103
        // Backwards compatibility.
104
		do_action( 'wpinv_before_user_subscriptions' );
105
106
		// Display errors and notices.
107
		wpinv_print_errors();
108
109
		do_action( 'getpaid_license_manager_before_subscriptions', $subscriptions );
110
111
		// Print the table header.
112
		$this->print_table_header();
113
114
		// Print table body.
115
		$this->print_table_body( $subscriptions->get_results() );
116
117
		// Print table footer.
118
		$this->print_table_footer();
119
120
		// Print the navigation.
121
		$this->print_navigation( $subscriptions->get_total() );
122
123
        // Backwards compatibility.
124
		do_action( 'wpinv_after_user_subscriptions' );
125
126
		// Return the output.
127
		return ob_get_clean();
128
129
	}
130
131
	/**
132
	 * Retrieves the subscription columns.
133
	 *
134
	 * @return array
135
	 */
136
	public function get_subscriptions_table_columns() {
137
138
		$columns = array(
139
            'subscription'   => __( 'Subscription', 'invoicing' ),
140
            'amount'         => __( 'Amount', 'invoicing' ),
141
            'renewal-date'   => __( 'Next payment', 'invoicing' ),
142
			'status'         => __( 'Status', 'invoicing' ),
143
		);
144
145
		return apply_filters( 'getpaid_frontend_subscriptions_table_columns', $columns );
146
	}
147
148
	/**
149
	 * Displays the table header.
150
	 *
151
	 */
152
	public function print_table_header() {
153
154
		?>
155
156
			<style>
157
				.getpaid-subscriptions-table-column-subscription {
158
					width: 35%;
159
					font-weight: 500;
160
				}
161
162
				.getpaid-subscriptions-table-row span.label {
163
					font-weight: 500;
164
				}
165
166
				.getpaid-subscriptions.bsui .table-bordered thead th {
167
					border-bottom-width: 1px;
168
				}
169
170
				.getpaid-subscriptions.bsui .table-striped tbody tr:nth-of-type(odd) {
171
					background-color: rgb(0 0 0 / 0.01);
172
				}
173
			</style>
174
175
			<table class="table table-bordered">
176
177
				<thead>
178
					<tr>
179
						<?php foreach ( $this->get_subscriptions_table_columns() as $key => $label ) : ?>
180
							<th scope="col" class="getpaid-subscriptions-table-<?php echo sanitize_html_class( $key ); ?>">
181
								<?php echo sanitize_text_field( $label ); ?>
182
							</th>
183
						<?php endforeach; ?>
184
					</tr>
185
				</thead>
186
187
		<?php
188
189
	}
190
191
	/**
192
	 * Displays the table body.
193
	 *
194
	 * @param WPInv_Subscription[] $subscriptions
195
	 */
196
	public function print_table_body( $subscriptions ) {
197
198
		if ( empty( $subscriptions ) ) {
199
			$this->print_table_body_no_subscriptions();
200
		} else {
201
			$this->print_table_body_subscriptions( $subscriptions );
202
		}
203
204
	}
205
206
	/**
207
	 * Displays the table body if no subscriptions were found.
208
	 *
209
	 */
210
	public function print_table_body_no_subscriptions() {
211
212
		?>
213
		<tbody>
214
215
			<tr>
216
				<td colspan="<?php echo count( $this->get_subscriptions_table_columns() ); ?>">
217
218
					<?php
219
						echo aui()->alert(
220
							array(
221
								'content' => wp_kses_post( __( 'No subscriptions found.', 'invoicing' ) ),
222
								'type'    => 'warning',
223
							)
224
						);
225
					?>
226
227
				</td>
228
			</tr>
229
230
		</tbody>
231
		<?php
232
	}
233
234
	/**
235
	 * Displays the table body if subscriptions were found.
236
	 *
237
	 * @param WPInv_Subscription[] $subscriptions
238
	 */
239
	public function print_table_body_subscriptions( $subscriptions ) {
240
241
		?>
242
		<tbody>
243
244
			<?php foreach ( $subscriptions as $subscription ) : ?>
245
				<tr class="getpaid-subscriptions-table-row subscription-<?php echo (int) $subscription->get_id(); ?>">
246
					<?php foreach ( array_keys( $this->get_subscriptions_table_columns() ) as $column ) : ?>
247
248
						<td class="getpaid-subscriptions-table-column-<?php echo sanitize_html_class( $column ); ?>">
249
							<?php
250
								switch( $column ) :
251
252
									case 'subscription':
253
										echo $this->column_subscription( $subscription );
254
                                        break;
255
                                    
256
                                    case 'status':
257
                                        echo $subscription->get_status_label_html();
258
                                        break;
259
                                        
260
                                    case 'renewal-date':
261
                                        $renewal = $this->format_date_field( $subscription->get_next_renewal_date() );
262
                                        echo $subscription->is_active() ? $renewal : "&mdash;";
263
										break;
264
265
                                        
266
                                    case 'amount':
267
                                        $frequency = sanitize_text_field( WPInv_Subscriptions::wpinv_get_pretty_subscription_frequency( $subscription->get_period(), $subscription->get_frequency(), true ) );
268
                                        $amount    = wpinv_price( wpinv_format_amount( wpinv_sanitize_amount( $subscription->get_recurring_amount() ) ), $subscription->get_parent_payment()->get_currency() );
269
										echo "<strong style='font-weight: 500;'>$amount</strong> / $frequency";
270
										break;
271
272
								endswitch;
273
274
								do_action( "getpaid_subscriptions_frontend_subscription_table_$column", $subscription );
275
276
							?>
277
						</td>
278
279
					<?php endforeach; ?>
280
				</tr>
281
			<?php endforeach; ?>
282
283
		</tbody>
284
		<?php
285
	}
286
287
	/**
288
	 * Formats a date field.
289
	 *
290
	 * @param string $date
291
	 */
292
	public function format_date_field( $date, $default = "&mdash;" ) {
293
294
		if ( empty( $date ) || '0000-00-00 00:00:00' == $date ) {
295
			return $default;
296
		} else {
297
			return date_i18n( get_option( 'date_format' ), strtotime( $date ) );
0 ignored issues
show
Bug introduced by
It seems like get_option('date_format') can also be of type false; however, parameter $format of date_i18n() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

297
			return date_i18n( /** @scrutinizer ignore-type */ get_option( 'date_format' ), strtotime( $date ) );
Loading history...
298
		}
299
300
	}
301
302
	/**
303
	 * Subscription column
304
	 *
305
	 * @param WPInv_Subscription $subscription
306
	 * @since       1.0.0
307
	 * @return      string
308
	 */
309
	public function column_subscription( $subscription ) {
310
        $subscription_id = (int) $subscription->get_id();
311
        $url             = esc_url( add_query_arg( 'subscription', $subscription_id, get_permalink( (int) wpinv_get_option( 'invoice_subscription_page' ) ) ) );
312
        return $this->add_row_actions( "<a href='$url' class='text-decoration-none'>#$subscription_id</a>", $subscription );
313
	}
314
315
    /**
316
	 * Adds row actions to a column
317
	 *
318
	 * @param string $content column content
319
	 * @param WPInv_Subscription $subscription
320
	 * @since       1.0.0
321
	 * @return      string
322
	 */
323
    public function add_row_actions( $content, $subscription ) {
324
325
        // Prepare row actions.
326
        $actions = array();
327
328
        // View subscription action.
329
        $view_url        = esc_url( add_query_arg( 'subscription', (int) $subscription->get_id(), get_permalink( (int) wpinv_get_option( 'invoice_subscription_page' ) ) ) );
330
        $actions['view'] = "<a href='$view_url' class='text-decoration-none'>" . __( 'Manage Subscription', 'invoicing' ) . '</a>';
331
332
        // View invoice action.
333
        $invoice = $subscription->get_parent_payment();
334
335
        if ( $invoice->get_id() ) {
336
            $view_url           = esc_url( $invoice->get_view_url() );
337
            $actions['invoice'] = "<a href='$view_url' class='text-decoration-none'>" . __( 'View Invoice', 'invoicing' ) . '</a>';
338
        }
339
340
        // Filter the actions.
341
        $actions = apply_filters( 'getpaid_subscriptions_table_subscription_actions', $actions, $subscription );
342
343
        if ( ! empty( $actions ) ) {
344
345
            $sanitized  = array();
346
            foreach ( $actions as $key => $action ) {
347
                $key         = sanitize_html_class( $key );
348
                $action      = wp_kses_post( $action );
349
                $sanitized[] = "<span class='$key'>$action</span>";
350
            }
351
352
            $row_actions  = "<small class='form-text getpaid-subscription-item-actions'>";
353
            $row_actions .= implode( ' | ', $sanitized );
354
            $row_actions .= '</small>';
355
356
        }
357
358
        return $content . $row_actions;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $row_actions does not seem to be defined for all execution paths leading up to this point.
Loading history...
359
    }
360
361
	/**
362
	 * Displays the table footer.
363
	 *
364
	 */
365
	public function print_table_footer() {
366
367
		?>
368
369
				<tfoot>
370
					<tr>
371
						<?php foreach ( $this->get_subscriptions_table_columns() as $key => $label ) : ?>
372
							<th class="getpaid-subscriptions-<?php echo sanitize_html_class( $key ); ?>">
373
								<?php echo sanitize_text_field( $label ); ?>
374
							</th>
375
						<?php endforeach; ?>
376
					</tr>
377
				</tfoot>
378
379
			</table>
380
		<?php
381
382
	}
383
384
	/**
385
	 * Displays the navigation.
386
	 *
387
	 * @param int $total
388
	 */
389
	public function print_navigation( $total ) {
390
391
		if ( $total < 1 ) {
392
393
			// Out-of-bounds, run the query again without LIMIT for total count.
394
			$args  = array(
395
				'customer_in' => get_current_user_id(),
396
				'fields'      => 'id',
397
			);
398
399
			$count_query = new GetPaid_Subscriptions_Query( $args );
400
			$total       = $count_query->get_total();
401
		}
402
403
		// Abort if we do not have pages.
404
		if ( 2 > $total ) {
405
			return;
406
		}
407
408
		?>
409
410
		<div class="getpaid-subscriptions-pagination">
411
			<?php
412
				$big = 999999;
413
414
				echo paginate_links(
0 ignored issues
show
Bug introduced by
Are you sure paginate_links(array('ba...int)ceil($total / 10))) of type array|string|string[] can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

414
				echo /** @scrutinizer ignore-type */ paginate_links(
Loading history...
415
					array(
416
						'base'    => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
417
						'format'  => '?paged=%#%',
418
						'total'   => (int) ceil( $total / 10 ),
419
					)
420
				);
421
			?>
422
		</div>
423
424
		<?php
425
	}
426
427
	/**
428
	 * Displays a single subscription.
429
	 *
430
	 * @param string $subscription
431
	 *
432
	 * @return string
433
	 */
434
	public function display_single_subscription( $subscription ) {
435
436
		// Fetch the subscription.
437
		$subscription = new WPInv_Subscription( (int) $subscription );
438
439
		if ( ! $subscription->get_id() ) {
440
441
			return aui()->alert(
442
				array(
443
					'content' => wp_kses_post( __( 'Subscription not found.', 'invoicing' ) ),
444
					'type'    => 'error',
445
				)
446
			);
447
448
		}
449
450
		// Ensure that the user owns this subscription key.
451
		if ( get_current_user_id() != $subscription->get_customer_id() ) {
452
453
			return aui()->alert(
454
				array(
455
					'content' => wp_kses_post( __( 'You do not have permission to view this subscription. Ensure that you are logged in to the account that owns the subscription.', 'invoicing' ) ),
456
					'type'    => 'error',
457
				)
458
			);
459
460
		}
461
462
		// Start the output buffer.
463
		ob_start();
464
465
		do_action( 'getpaid_single_subscription_before_notices', $subscription );
466
467
		// Display errors and notices.
468
		wpinv_print_errors();
469
470
		do_action( 'getpaid_before_single_subscription', $subscription );
471
472
		// Prepare subscription detail columns.
473
		$fields = apply_filters(
474
			'getpaid_single_subscription_details_fields',
475
			array(
476
                'status'           => __( 'Status', 'invoicing' ),
477
                'start_date'       => __( 'Start date', 'invoicing' ),
478
				'expiry_date'      => __( 'Next payment', 'invoicing' ),
479
				'initial_amount'   => __( 'Initial amount', 'invoicing' ),
480
				'recurring_amount' => __( 'Recurring amount', 'invoicing' ),
481
				'payments'         => __( 'Payments', 'invoicing' ),
482
                'item'             => __( 'Item', 'invoicing' ),
483
                'invoice'          => __( 'Invoice', 'invoicing' ),
484
			),
485
			$subscription
486
		);
487
488
        if ( ! $subscription->is_active() || $subscription->is_last_renewal() ) {
489
            $fields['expiry_date'] = __( 'End date', 'invoicing' );
490
        }
491
492
        if ( $subscription->get_initial_amount() == $subscription->get_recurring_amount() ) {
493
            unset( $fields['initial_amount'] );
494
        }
495
		?>
496
497
		<table class="table table-bordered">
498
			<tbody>
499
500
				<?php foreach ( $fields as $key => $label ) : ?>
501
502
					<tr class="getpaid-subscription-meta-<?php echo sanitize_html_class( $key ); ?>">
503
504
						<th class="w-25" style="font-weight: 500;">
505
							<?php echo sanitize_text_field( $label ); ?>
506
						</th>
507
508
						<td class="w-75 text-muted">
509
							<?php
510
								switch ( $key ) {
511
512
									case 'status':
513
										echo sanitize_text_field( $subscription->get_status_label() );
514
										break;
515
516
									case 'start_date':
517
										echo sanitize_text_field( $this->format_date_field( $subscription->get_date_created() ) );
518
                                        break;
519
                                        
520
                                    case 'expiry_date':
521
										echo sanitize_text_field( $this->format_date_field( $subscription->get_next_renewal_date() ) );
522
                                        break;
523
                                        
524
                                    case 'initial_amount':
525
										echo wpinv_price( wpinv_format_amount( $subscription->get_initial_amount(), $subscription->get_parent_payment()->get_currency() ) );
526
                                        break;
527
                                        
528
                                    case 'recurring_amount':
529
                                        $frequency = sanitize_text_field( WPInv_Subscriptions::wpinv_get_pretty_subscription_frequency( $subscription->get_period(), $subscription->get_frequency(), true ) );
530
                                        $amount    = wpinv_price( wpinv_format_amount( $subscription->get_recurring_amount() ), $subscription->get_parent_payment()->get_currency() );
531
										echo "<strong style='font-weight: 500;'>$amount</strong> / $frequency";
532
										break;
533
                                        
534
									case 'invoice':
535
										$invoice = $subscription->get_parent_invoice();
536
537
										if ( $invoice->get_id() ) {
538
											$view_url = esc_url( $invoice->get_view_url() );
539
											$number   = sanitize_text_field( $invoice->get_number() );
540
											echo "<a href='$view_url' class='text-decoration-none'>$number</a>";
541
										} else {
542
											echo "&mdash;";
543
										}
544
545
										break;
546
547
									case 'item':
548
										$item = get_post( $subscription->get_product_id() );
549
550
										if ( ! empty( $item ) ) {
551
											echo esc_html( get_the_title( $item ) );
552
										} else {
553
											echo sprintf( __( 'Item #%s', 'invoicing' ), $subscription->get_product_id() );
554
										}
555
556
										break;
557
558
									case 'payments':
559
560
										$max_activations = (int) $subscription->get_bill_times();
561
										echo (int) $subscription->get_times_billed() . ' / ' . ( empty( $max_activations ) ? "&infin;" : $max_activations );
562
563
										break;
564
565
									case 'activated_on':
566
567
										$activations = $license->get_activated_on();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $license seems to be never defined.
Loading history...
568
569
										if ( empty( $activations ) ) {
570
											echo __( 'This license has not been activated anywhere yet', 'invoicing' );
571
										}
572
573
										foreach ( $activations as $website => $date ) {
574
											$website = sanitize_text_field( $website );
575
											$date    = date_i18n( get_option( 'date_format' ), strtotime( $date ) );
0 ignored issues
show
Bug introduced by
It seems like get_option('date_format') can also be of type false; however, parameter $format of date_i18n() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

575
											$date    = date_i18n( /** @scrutinizer ignore-type */ get_option( 'date_format' ), strtotime( $date ) );
Loading history...
576
											$message = esc_attr__( 'Are you sure you want to delete this license from the app/website?', 'invoicing' );
577
											$url     = esc_url(
578
												wp_nonce_url(
579
													add_query_arg(
580
														array(
581
															'getpaid-action' => 'delete_license_activation',
582
															'app'            => urlencode( $website )
583
														)
584
													),
585
													'getpaid-nonce',
586
													'getpaid-nonce'
587
												)
588
											);
589
											echo "<span class='form-text text-monospace'>$website &mdash; $date <a href='$url' onclick=\"return confirm('$message')\" class='text-danger'><i class='fa fa-times'></i></a></span>";
590
										}
591
592
										break;
593
594
								}
595
								do_action( "getpaid_render_single_subscription_column_$key", $subscription );
596
							?>
597
						</td>
598
599
					</tr>
600
601
				<?php endforeach; ?>
602
603
			</tbody>
604
		</table>
605
606
	<?php
607
608
		// Return the output.
609
		return ob_get_clean();
610
611
	}
612
613
}
614