Passed
Push — master ( 7aa753...344feb )
by Brian
04:22
created

GetPaid_Invoice_Notification_Emails::init_hooks()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
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 7
rs 10
cc 2
nc 2
nop 0
1
<?php
2
/**
3
 * Contains the invoice notification emails management class.
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * This class handles invoice notificaiton emails.
11
 *
12
 */
13
class GetPaid_Invoice_Notification_Emails {
14
15
	/**
16
	 * The array of invoice email actions.
17
	 *
18
	 * @param array
19
	 */
20
	public $invoice_actions;
21
22
	/**
23
	 * Class constructor
24
	 *
25
	 */
26
	public function __construct() {
27
28
		$this->invoice_actions = apply_filters(
29
			'getpaid_notification_email_invoice_triggers',
30
			array(
31
				'getpaid_new_invoice'                   => array( 'new_invoice', 'user_invoice' ),
32
				'getpaid_invoice_status_wpi-cancelled'  => 'cancelled_invoice',
33
				'getpaid_invoice_status_wpi-failed'     => 'failed_invoice',
34
				'getpaid_invoice_status_wpi-onhold'     => 'onhold_invoice',
35
				'getpaid_invoice_status_wpi-processing' => 'processing_invoice',
36
				'getpaid_invoice_status_publish'        => 'completed_invoice',
37
				'getpaid_invoice_status_wpi-renewal'    => 'completed_invoice',
38
				'getpaid_invoice_status_wpi-refunded'   => 'refunded_invoice',
39
				'getpaid_new_customer_note'             => 'user_note',
40
				'getpaid_daily_maintenance'             => 'overdue',
41
			)
42
		);
43
44
		$this->init_hooks();
45
46
	}
47
48
	/**
49
	 * Registers email hooks.
50
	 */
51
	public function init_hooks() {
52
53
		add_filter( 'getpaid_get_email_merge_tags', array( $this, 'invoice_merge_tags' ), 10, 2 );
54
		add_filter( 'getpaid_invoice_email_recipients', array( $this, 'filter_email_recipients' ), 10, 2 );
55
56
		foreach ( $this->invoice_actions as $hook => $email_type ) {
57
			$this->init_email_type_hook( $hook, $email_type );
58
		}
59
	}
60
61
	/**
62
	 * Registers an email hook for an invoice action.
63
	 * 
64
	 * @param string $hook
65
	 * @param string|array $email_type
66
	 */
67
	public function init_email_type_hook( $hook, $email_type ) {
68
69
		$email_type = wpinv_parse_list( $email_type );
70
71
		foreach ( $email_type as $type ) {
72
73
			$email = new GetPaid_Notification_Email( $type );
74
75
			// Abort if it is not active.
76
			if ( ! $email->is_active() ) {
77
				continue;
78
			}
79
80
			if ( method_exists( $this, $type ) ) {
81
				add_action( $hook, array( $this, $type ), 100, 2 );
82
				continue;
83
			}
84
85
			do_action( 'getpaid_invoice_init_email_type_hook', $type, $hook );
86
		}
87
88
	}
89
90
	/**
91
	 * Filters invoice merge tags.
92
	 *
93
	 * @param array $merge_tags
94
	 * @param mixed|WPInv_Invoice|WPInv_Subscription $object
95
	 */
96
	public function invoice_merge_tags( $merge_tags, $object ) {
97
98
		if ( is_a( $object, 'WPInv_Invoice' ) ) {
99
			return array_merge(
100
				$merge_tags,
101
				$this->get_invoice_merge_tags( $object )
102
			);
103
		}
104
105
		if ( is_a( $object, 'WPInv_Subscription' ) ) {
106
			return array_merge(
107
				$merge_tags,
108
				$this->get_invoice_merge_tags( $object->get_parent_payment() )
109
			);
110
		}
111
112
		return $merge_tags;
113
114
	}
115
116
	/**
117
	 * Generates invoice merge tags.
118
	 *
119
	 * @param WPInv_Invoice $invoice
120
	 * @return array
121
	 */
122
	public function get_invoice_merge_tags( $invoice ) {
123
124
		// Abort if it does not exist.
125
		if ( ! $invoice->get_id() ) {
126
			return array();
127
		}
128
129
		$merge_tags = array(
130
			'{name}'                => sanitize_text_field( $invoice->get_user_full_name() ),
131
			'{full_name}'           => sanitize_text_field( $invoice->get_user_full_name() ),
132
			'{first_name}'          => sanitize_text_field( $invoice->get_first_name() ),
133
			'{last_name}'           => sanitize_text_field( $invoice->get_last_name() ),
134
			'{email}'               => sanitize_email( $invoice->get_email() ),
135
			'{invoice_number}'      => sanitize_text_field( $invoice->get_number() ),
136
			'{invoice_currency}'    => sanitize_text_field( $invoice->get_currency() ),
137
			'{invoice_total}'       => sanitize_text_field( wpinv_price( $invoice->get_total(), $invoice->get_currency() ) ),
138
			'{invoice_link}'        => esc_url( $invoice->get_view_url() ),
139
			'{invoice_pay_link}'    => esc_url( $invoice->get_checkout_payment_url() ),
140
			'{invoice_receipt_link}'=> esc_url( $invoice->get_receipt_url() ),
141
			'{invoice_date}'        => getpaid_format_date_value( $invoice->get_date_created() ),
142
			'{invoice_due_date}'    => getpaid_format_date_value( $invoice->get_due_date(), __( 'on receipt', 'invoicing' ) ),
143
			'{invoice_quote}'       => sanitize_text_field( strtolower( $invoice->get_label() ) ),
144
			'{invoice_label}'       => sanitize_text_field( ucfirst( $invoice->get_label() ) ),
145
			'{invoice_description}' => wp_kses_post( $invoice->get_description() ),
146
			'{subscription_name}'   => wp_kses_post( $invoice->get_subscription_name() ),
147
			'{is_was}'              => strtotime( $invoice->get_due_date() ) < current_time( 'timestamp' ) ? __( 'was', 'invoicing' ) : __( 'is', 'invoicing' ),
148
		);
149
150
		$payment_form_data = $invoice->get_meta( 'payment_form_data', true );
151
152
		if ( is_array( $payment_form_data ) ) {
153
154
			foreach ( $payment_form_data as $label => $value ) {
155
156
				$label = preg_replace( '/[^a-z0-9]+/', '_', strtolower( $label ) );
157
				$value = is_array( $value ) ? implode( ', ', $value ) : $value;
158
159
				if ( is_scalar ( $value ) ) {
160
					$merge_tags[ "{{$label}}" ] = wp_kses_post( $value );
161
				}
162
163
			}
164
165
		}
166
167
		return apply_filters( 'getpaid_invoice_email_merge_tags', $merge_tags, $invoice );
168
	}
169
170
	/**
171
	 * Helper function to send an email.
172
	 *
173
	 * @param WPInv_Invoice $invoice
174
	 * @param GetPaid_Notification_Email $email
175
	 * @param string $type
176
	 * @param string|array $recipients
177
	 * @param array $extra_args Extra template args.
178
	 */
179
	public function send_email( $invoice, $email, $type, $recipients, $extra_args = array() ) {
180
181
		do_action( 'getpaid_before_send_invoice_notification', $type, $invoice, $email );
182
183
		$skip = $invoice->is_free() && wpinv_get_option( 'skip_email_free_invoice' );
184
		if ( apply_filters( 'getpaid_skip_invoice_email', $skip, $type, $invoice ) ) {
185
			return;
186
		}
187
188
		$mailer     = new GetPaid_Notification_Email_Sender();
189
		$merge_tags = $email->get_merge_tags();
190
191
		$result = $mailer->send(
192
			apply_filters( 'getpaid_invoice_email_recipients', wpinv_parse_list( $recipients ), $email ),
193
			$email->add_merge_tags( $email->get_subject(), $merge_tags ),
194
			$email->get_content( $merge_tags, $extra_args ),
195
			$email->get_attachments()
196
		);
197
198
		// Maybe send a copy to the admin.
199
		if ( $email->include_admin_bcc() ) {
200
			$mailer->send(
201
				wpinv_get_admin_email(),
0 ignored issues
show
Bug introduced by
It seems like wpinv_get_admin_email() can also be of type false; however, parameter $to of GetPaid_Notification_Email_Sender::send() does only seem to accept array|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

201
				/** @scrutinizer ignore-type */ wpinv_get_admin_email(),
Loading history...
202
				$email->add_merge_tags( $email->get_subject() . __( ' - ADMIN BCC COPY', 'invoicing' ), $merge_tags ),
203
				$email->get_content( $merge_tags ),
204
				$email->get_attachments()
205
			);
206
		}
207
208
		if ( $result ) {
209
			$invoice->add_system_note(
210
				sprintf(
211
					__( 'Successfully sent %s notification email to %s.', 'invoicing' ),
212
					sanitize_key( $type ),
213
					$email->is_admin_email() ? __( 'admin' ) : __( 'the customer' )
214
				)
215
			);
216
		} else {
217
			$invoice->add_system_note(
218
				sprintf(
219
					__( 'Failed sending %s notification email to %s.', 'invoicing' ),
220
					sanitize_key( $type ),
221
					$email->is_admin_email() ? __( 'admin' ) : __( 'the customer' )
222
				)
223
			);	
224
		}
225
226
		do_action( 'getpaid_after_send_invoice_notification', $type, $invoice, $email );
227
228
		return $result;
229
	}
230
231
	/**
232
	 * Also send emails to any cc users.
233
	 *
234
	 * @param array $recipients
235
	 * @param GetPaid_Notification_Email $email
236
	 */
237
	public function filter_email_recipients( $recipients, $email ) {
238
239
		if ( ! $email->is_admin_email() ) {
240
			$cc = $email->object->get_email_cc();
0 ignored issues
show
Bug introduced by
The method get_email_cc() does not exist on WPInv_Subscription. ( Ignorable by Annotation )

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

240
			/** @scrutinizer ignore-call */ 
241
   $cc = $email->object->get_email_cc();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method get_email_cc() does not exist on WPInv_Item. ( Ignorable by Annotation )

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

240
			/** @scrutinizer ignore-call */ 
241
   $cc = $email->object->get_email_cc();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
241
242
			if ( ! empty( $cc ) ) {
243
				$cc = array_map( 'sanitize_email', wpinv_parse_list( $cc ) );
244
				$recipients = array_filter( array_unique( array_merge( $recipients, $cc ) ) );
245
			}
246
247
		}
248
249
		return $recipients;
250
251
	}
252
253
	/**
254
	 * Sends a new invoice notification.
255
	 *
256
	 * @param WPInv_Invoice $invoice
257
	 */
258
	public function new_invoice( $invoice ) {
259
260
		// Only send this email for invoices created via the admin page.
261
		if ( ! $invoice->is_type( 'invoice' ) || $this->is_payment_form_invoice( $invoice->get_id() ) ) {
262
			return;
263
		}
264
265
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
266
		$recipient = wpinv_get_admin_email();
267
268
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
0 ignored issues
show
Bug introduced by
It seems like $recipient can also be of type false; however, parameter $recipients of GetPaid_Invoice_Notification_Emails::send_email() does only seem to accept array|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

268
		return $this->send_email( $invoice, $email, __FUNCTION__, /** @scrutinizer ignore-type */ $recipient );
Loading history...
269
270
	}
271
272
	/**
273
	 * Sends a cancelled invoice notification.
274
	 *
275
	 * @param WPInv_Invoice $invoice
276
	 */
277
	public function cancelled_invoice( $invoice ) {
278
279
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
280
		$recipient = wpinv_get_admin_email();
281
282
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
0 ignored issues
show
Bug introduced by
It seems like $recipient can also be of type false; however, parameter $recipients of GetPaid_Invoice_Notification_Emails::send_email() does only seem to accept array|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

282
		return $this->send_email( $invoice, $email, __FUNCTION__, /** @scrutinizer ignore-type */ $recipient );
Loading history...
283
284
	}
285
286
	/**
287
	 * Sends a failed invoice notification.
288
	 *
289
	 * @param WPInv_Invoice $invoice
290
	 */
291
	public function failed_invoice( $invoice ) {
292
293
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
294
		$recipient = wpinv_get_admin_email();
295
296
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
0 ignored issues
show
Bug introduced by
It seems like $recipient can also be of type false; however, parameter $recipients of GetPaid_Invoice_Notification_Emails::send_email() does only seem to accept array|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

296
		return $this->send_email( $invoice, $email, __FUNCTION__, /** @scrutinizer ignore-type */ $recipient );
Loading history...
297
298
	}
299
300
	/**
301
	 * Sends a notification whenever an invoice is put on hold.
302
	 *
303
	 * @param WPInv_Invoice $invoice
304
	 */
305
	public function onhold_invoice( $invoice ) {
306
307
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
308
		$recipient = $invoice->get_email();
309
310
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
311
312
	}
313
314
	/**
315
	 * Sends a notification whenever an invoice is marked as processing payment.
316
	 *
317
	 * @param WPInv_Invoice $invoice
318
	 */
319
	public function processing_invoice( $invoice ) {
320
321
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
322
		$recipient = $invoice->get_email();
323
324
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
325
326
	}
327
328
	/**
329
	 * Sends a notification whenever an invoice is paid.
330
	 *
331
	 * @param WPInv_Invoice $invoice
332
	 */
333
	public function completed_invoice( $invoice ) {
334
335
		// (Maybe) abort if it is a renewal invoice.
336
		if ( $invoice->is_renewal() && ! wpinv_get_option( 'email_completed_invoice_renewal_active', false ) ) {
337
			return;
338
		}
339
340
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
341
		$recipient = $invoice->get_email();
342
343
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
344
345
	}
346
347
	/**
348
	 * Sends a notification whenever an invoice is refunded.
349
	 *
350
	 * @param WPInv_Invoice $invoice
351
	 */
352
	public function refunded_invoice( $invoice ) {
353
354
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
355
		$recipient = $invoice->get_email();
356
357
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
358
359
	}
360
361
	/**
362
	 * Notifies a user about new invoices
363
	 *
364
	 * @param WPInv_Invoice $invoice
365
	 * @param bool $force
366
	 */
367
	public function user_invoice( $invoice, $force = false ) {
368
369
		if ( ! empty( $GLOBALS['wpinv_skip_invoice_notification'] ) ) {
370
			return;
371
		}
372
373
		// Only send this email for invoices created via the admin page.
374
		if ( ! $invoice->is_type( 'invoice' ) || ( empty( $force ) && $this->is_payment_form_invoice( $invoice->get_id() ) ) ) {
375
			return;
376
		}
377
378
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
379
		$recipient = $invoice->get_email();
380
381
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient );
382
383
	}
384
385
	/**
386
	 * Checks if an invoice is a payment form invoice.
387
	 *
388
	 * @param int $invoice
389
	 * @return bool
390
	 */
391
	public function is_payment_form_invoice( $invoice ) {
392
		$is_payment_form_invoice = empty( $_GET['getpaid-admin-action'] ) && ( 'payment_form' == get_post_meta( $invoice, 'wpinv_created_via', true ) || 'geodirectory' == get_post_meta( $invoice, 'wpinv_created_via', true ) );
393
		return apply_filters( 'getpaid_invoice_notifications_is_payment_form_invoice', $is_payment_form_invoice, $invoice );
394
	}
395
396
	/**
397
	 * Notifies admin about new invoice notes
398
	 *
399
	 * @param WPInv_Invoice $invoice
400
	 * @param string $note
401
	 */
402
	public function user_note( $invoice, $note ) {
403
404
		$email     = new GetPaid_Notification_Email( __FUNCTION__, $invoice );
405
		$recipient = $invoice->get_email();
406
407
		return $this->send_email( $invoice, $email, __FUNCTION__, $recipient, array( 'customer_note' => $note ) );
408
409
	}
410
411
	/**
412
	 * (Force) Sends overdue notices.
413
	 *
414
	 * @param WPInv_Invoice $invoice
415
	 */
416
	public function force_send_overdue_notice( $invoice ) {
417
		$email = new GetPaid_Notification_Email( 'overdue', $invoice );
418
		return $this->send_email( $invoice, $email, 'overdue', $invoice->get_email() );
419
	}
420
421
	/**
422
	 * Sends overdue notices.
423
	 *
424
	 * @TODO: Create an invoices query class.
425
	 */
426
	public function overdue() {
427
		global $wpdb;
428
429
		$email = new GetPaid_Notification_Email( __FUNCTION__ );
430
431
		// Fetch reminder days.
432
		$reminder_days = array_unique( wp_parse_id_list( $email->get_option( 'days' ) ) );
433
434
		// Abort if non is set.
435
		if ( empty( $reminder_days ) ) {
436
			return;
437
		}
438
439
		// Retrieve date query.
440
		$date_query = $this->get_date_query( $reminder_days );
441
442
		// Invoices table.
443
		$table = $wpdb->prefix . 'getpaid_invoices';
444
445
		// Fetch invoices.
446
		$invoices  = $wpdb->get_col(
447
			"SELECT posts.ID FROM $wpdb->posts as posts
448
			LEFT JOIN $table as invoices ON invoices.post_id = posts.ID
449
			WHERE posts.post_type = 'wpi_invoice' AND posts.post_status = 'wpi-pending' $date_query");
450
451
		foreach ( $invoices as $invoice ) {
452
453
			// Only send this email for invoices created via the admin page.
454
			if ( ! $this->is_payment_form_invoice( $invoice ) ) {
455
				$invoice       = new WPInv_Invoice( $invoice );
456
				$email->object = $invoice;
457
458
				if ( $invoice->needs_payment() ) {
459
					$this->send_email( $invoice, $email, __FUNCTION__, $invoice->get_email() );
460
				}
461
462
			}
463
464
		}
465
466
	}
467
468
	/**
469
	 * Calculates the date query for an invoices query
470
	 *
471
	 * @param array $reminder_days
472
	 * @return string
473
	 */
474
	public function get_date_query( $reminder_days ) {
475
476
		$date_query = array(
477
			'relation'  => 'OR'
478
		);
479
480
		foreach ( $reminder_days as $days ) {
481
			$date = date_parse( date( 'Y-m-d', strtotime( "-$days days", current_time( 'timestamp' ) ) ) );
482
483
			$date_query[] = array(
484
				'year'  => $date['year'],
485
				'month' => $date['month'],
486
				'day'   => $date['day'],
487
			);
488
489
		}
490
491
		$date_query = new WP_Date_Query( $date_query, 'invoices.due_date' );
492
493
		return $date_query->get_sql();
494
495
	}
496
497
}
498