Completed
Pull Request — dev/2.5.0 (#239)
by Sudar
15:21 queued 11:55
created

CoreSetting::initialize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 28
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 6
Bugs 0 Features 1
Metric Value
cc 1
eloc 21
c 6
b 0
f 1
nc 1
nop 0
dl 0
loc 28
ccs 0
cts 25
cp 0
crap 2
rs 9.584
1
<?php namespace EmailLog\Core\UI\Setting;
2
3
use  \EmailLog\Core\UI\Page\SettingsPage;
4
5
defined( 'ABSPATH' ) || exit; // Exit if accessed directly.
6
7
/**
8
 * All Email Log Core settings.
9
 *
10
 * @since 2.1.0
11
 */
12
class CoreSetting extends Setting {
13
14
	protected function initialize() {
15
		$this->section->id          = 'email-log-core';
16
		$this->section->title       = __( 'Core Email Log Settings', 'email-log' );
17
		$this->section->option_name = 'email-log-core';
18
19
		$this->section->field_labels = array(
20
			'allowed_user_roles'    => __( 'Allowed User Roles', 'email-log' ),
21
			'remove_on_uninstall'   => __( 'Remove Data on Uninstall?', 'email-log' ),
22
			'hide_dashboard_widget' => __( 'Disable Dashboard Widget', 'email-log' ),
23
			'db_size_notification'  => __( 'Database Size Notification', 'email-log' ),
24
			'pause_emails'          => __( 'Pause Emails', 'email-log' ),
25
		);
26
27
		$this->section->default_value = array(
28
			'allowed_user_roles'    => array(),
29
			'remove_on_uninstall'   => '',
30
			'hide_dashboard_widget' => false,
31
			'db_size_notification'  => array(
32
				'notify'                    => false,
33
				'admin_email'               => '',
34
				'logs_threshold'            => '',
35
				'log_threshold_met'         => false,
36
				'threshold_email_last_sent' => false,
37
			),
38
			'pause_emails'          => 'false',
39
		);
40
41
		$this->load();
42
	}
43
44
	/**
45
	 * Override `load` method so that the core settings are displayed first.
46
	 *
47
	 * @inheritdoc
48
	 */
49
	public function load() {
50
		add_filter( 'el_setting_sections', array( $this, 'register' ), 9 );
51
52
		add_action( 'add_option_' . $this->section->option_name, array( $this, 'allowed_user_roles_added' ), 10, 2 );
53
		add_action( 'update_option_' . $this->section->option_name, array( $this, 'allowed_user_roles_changed' ), 10, 2 );
54
55
		add_action( 'el_email_log_inserted', array( $this, 'verify_email_log_threshold' ) );
56
		add_action( 'el_trigger_notify_email_when_log_threshold_met', array( $this, 'trigger_threshold_met_notification_email' ) );
57
	}
58
59
	/**
60
	 * Renders the Email Log `Allowed User Roles` settings.
61
	 *
62
	 * @param array $args Arguments.
63
	 */
64
	public function render_allowed_user_roles_settings( $args ) {
65
		$option         = $this->get_value();
66
		$selected_roles = $option[ $args['id'] ];
67
68
		$field_name = $this->section->option_name . '[' . $args['id'] . '][]';
69
70
		$available_roles = get_editable_roles();
71
		unset( $available_roles['administrator'] );
72
		?>
73
74
		<p>
75
			<input type="checkbox" checked disabled><?php _e( 'Administrator', 'email-log' ); ?>
76
		</p>
77
78
		<?php foreach ( $available_roles as $role_id => $role ) : ?>
79
			<p>
80
				<input type="checkbox" name="<?php echo esc_attr( $field_name ); ?>" value="<?php echo esc_attr( $role_id ); ?>"
81
					<?php \EmailLog\Util\checked_array( $selected_roles, $role_id ); ?>>
82
83
				<?php echo $role['name']; ?>
84
			</p>
85
		<?php endforeach; ?>
86
87
		<p>
88
			<em>
89
				<?php _e( '<strong>Note:</strong> Users with the above User Roles can view Email Logs.', 'email-log' ); ?>
90
				<?php _e( 'Administrator role always has access and cannot be disabled.', 'email-log' ); ?>
91
			</em>
92
		</p>
93
94
		<?php
95
	}
96
97
	/**
98
	 * Sanitize allowed user roles setting.
99
	 *
100
	 * @param array $roles User selected user roles.
101
	 *
102
	 * @return array Sanitized user roles.
103
	 */
104
	public function sanitize_allowed_user_roles( $roles ) {
105
		if ( ! is_array( $roles ) ) {
0 ignored issues
show
introduced by
The condition is_array($roles) is always true.
Loading history...
106
			return array();
107
		}
108
109
		return array_map( 'sanitize_text_field', $roles );
110
	}
111
112
	/**
113
	 * Renders the Email Log `Remove Data on Uninstall?` settings.
114
	 *
115
	 * @param array $args
116
	 */
117
	public function render_remove_on_uninstall_settings( $args ) {
118
		$option      = $this->get_value();
119
		$remove_data = $option[ $args['id'] ];
120
121
		$field_name = $this->section->option_name . '[' . $args['id'] . ']';
122
		?>
123
124
		<input type="checkbox" name="<?php echo esc_attr( $field_name ); ?>" value="true" <?php checked( 'true', $remove_data ); ?>>
125
		<?php _e( 'Check this box if you would like to completely remove all of its data when the plugin is deleted.', 'email-log' ) ?>
126
127
		<p>
128
			<em>
129
				<?php printf(
130
					__( '<strong>Note:</strong> You can also export the Email Logs using our <a href="%s" rel="noopener noreferrer" target="_blank">Export Logs</a> add-on.', 'email-log' ),
131
					'https://wpemaillog.com/addons/export-logs/?utm_campaign=Upsell&utm_medium=wpadmin&utm_source=settings&utm_content=el'
132
				); ?>
133
			</em>
134
		</p>
135
136
		<?php
137
	}
138
139
	/**
140
	 * Sanitize Remove on uninstall value.
141
	 *
142
	 * @param string $value User entered value.
143
	 *
144
	 * @return string Sanitized value.
145
	 */
146
	public function sanitize_remove_on_uninstall( $value ) {
147
		return sanitize_text_field( $value );
148
	}
149
150
	/**
151
	 * Allowed user role list option is added.
152
	 *
153
	 * @param string $option Option name.
154
	 * @param array  $value  Option value.
155
	 */
156
	public function allowed_user_roles_added( $option, $value ) {
157
		$this->allowed_user_roles_changed( array(), $value );
158
	}
159
160
	/**
161
	 * Allowed user role list option was update.
162
	 *
163
	 * Change user role capabilities when the allowed user role list is changed.
164
	 *
165
	 * @param array $old_value Old Value.
166
	 * @param array $new_value New Value.
167
	 */
168
	public function allowed_user_roles_changed( $old_value, $new_value ) {
169
		$old_roles = $this->get_user_roles( $old_value );
170
		$new_roles = $this->get_user_roles( $new_value );
171
172
		/**
173
		 * The user roles who can manage email log list is changed.
174
		 *
175
		 * @since 2.1.0
176
		 *
177
		 * @param array $old_roles Old user roles.
178
		 * @param array $new_roles New user roles.
179
		 */
180
		do_action( 'el-log-list-manage-user-roles-changed', $old_roles, $new_roles );
181
	}
182
183
	/**
184
	 * Get User roles from option value.
185
	 *
186
	 * @access protected
187
	 *
188
	 * @param array $option Option value
189
	 *
190
	 * @return array User roles.
191
	 */
192
	protected function get_user_roles( $option ) {
193
		if ( ! array_key_exists( 'allowed_user_roles', $option ) ) {
194
			return array();
195
		}
196
197
		$user_roles = $option['allowed_user_roles'];
198
		if ( ! is_array( $user_roles ) ) {
199
			$user_roles = array( $user_roles );
200
		}
201
202
		return $user_roles;
203
	}
204
205
	/**
206
	 * Renders the Email Log `Remove Data on Uninstall?` settings.
207
	 *
208
	 * @param array $args
209
	 */
210
	public function render_hide_dashboard_widget_settings( $args ) {
211
		$option                = $this->get_value();
212
		$hide_dashboard_widget = $option[ $args['id'] ];
213
214
		$field_name = $this->section->option_name . '[' . $args['id'] . ']';
215
		?>
216
217
		<input type="checkbox" name="<?php echo esc_attr( $field_name ); ?>" value="true" <?php checked( 'true', $hide_dashboard_widget ); ?>>
218
		<?php _e( 'Check this box if you would like to disable dashboard widget.', 'email-log' ) ?>
219
220
		<p>
221
			<em>
222
				<?php printf(
223
					__( '<strong>Note:</strong> Each users can also disable dashboard widget using screen options', 'email-log' )
224
				); ?>
225
			</em>
226
		</p>
227
228
		<?php
229
	}
230
231
	/**
232
	 * Renders the Email Log `Database Size Notification` settings.
233
	 *
234
	 * @since 2.3.0
235
	 *
236
	 * @param array $args
237
	 */
238
	public function render_db_size_notification_settings( $args ) {
239
		$option                    = $this->get_value();
240
		$db_size_notification_data = $option[ $args['id'] ];
241
242
		$field_name = $this->section->option_name . '[' . $args['id'] . ']';
243
		// Since we store three different fields, give each field a unique name.
244
		$db_size_notification_field_name = $field_name . '[notify]';
245
		$admin_email_field_name          = $field_name . '[admin_email]';
246
		$logs_threshold_field_name       = $field_name . '[logs_threshold]';
247
248
		$email_log  = email_log();
249
		$logs_count = $email_log->table_manager->get_logs_count();
250
251
		$admin_email_input_field = sprintf(
252
			'<input type="email" name="%1$s" value="%2$s" size="35" />', esc_attr( $admin_email_field_name ), empty( $db_size_notification_data['admin_email'] ) ? get_option( 'admin_email', '' ) : esc_attr( $db_size_notification_data['admin_email'] ) );
0 ignored issues
show
Bug introduced by
It seems like empty($db_size_notificat...on_data['admin_email']) can also be of type false; however, parameter $args of sprintf() 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

252
			'<input type="email" name="%1$s" value="%2$s" size="35" />', esc_attr( $admin_email_field_name ), /** @scrutinizer ignore-type */ empty( $db_size_notification_data['admin_email'] ) ? get_option( 'admin_email', '' ) : esc_attr( $db_size_notification_data['admin_email'] ) );
Loading history...
253
254
		$logs_threshold_input_field = sprintf( '<input type="number" name="%1$s" placeholder="5000" value="%2$s" min="0" max="99999999" />',
255
			esc_attr( $logs_threshold_field_name ),
256
			empty( $db_size_notification_data['logs_threshold'] ) ? '' : esc_attr( $db_size_notification_data['logs_threshold'] )
257
		);
258
		?>
259
260
        <input type="checkbox" name="<?php echo esc_attr( $db_size_notification_field_name ); ?>" value="true" <?php
261
		checked( true, $db_size_notification_data['notify'] ); ?> />
262
		<?php
263
		// The values within each field are already escaped.
264
		printf( __( 'Notify %1$s if there are more than %2$s logs.', 'email-log' ),
265
			$admin_email_input_field,
266
			$logs_threshold_input_field
267
		);
268
		?>
269
        <p>
270
            <em>
271
				<?php printf(
272
					__( '%1$s There are %2$s email logs currently logged in the database.', 'email-log' ),
273
					'<strong>Note:</strong>',
274
					'<strong>' . esc_attr( $logs_count ) . '</strong>'
275
				); ?>
276
            </em>
277
        </p>
278
		<?php if ( ! empty( $db_size_notification_data['threshold_email_last_sent'] ) ) : ?>
279
            <p>
280
				<?php printf(
281
					__( 'Last notification email was sent on %1$s. Click %2$s button to reset sending the notification.', 'email-log' ),
282
					'<strong>' . get_date_from_gmt( date( 'Y-m-d H:i:s', $db_size_notification_data['threshold_email_last_sent'] ), \EmailLog\Util\get_user_defined_date_time_format() ) . '</strong>',
283
					'<b>Save</b>'
284
				); ?>
285
            </p>
286
		<?php
287
		endif;
288
		/**
289
		 * After DB size notification setting in Settings page.
290
		 *
291
		 * @since 2.4.0
292
		 */
293
		do_action( 'el_after_db_size_notification_setting' );
294
	}
295
296
	/**
297
	 * Removes any additional keys set other than the ones in db_size_notification array.
298
	 *
299
	 * @since 2.3.0
300
	 *
301
	 * @param array $arr `db_size_notification` option array.
302
	 *
303
	 * @return array `db_size_notification` option array with keys removed other than the allowed.
304
	 */
305
	protected function restrict_array_to_db_size_notification_setting_keys( $arr ) {
306
		$allowed_keys = array_keys( $this->section->default_value['db_size_notification'] );
307
		$arr_keys     = array_keys( $arr );
308
309
		// Return the array when only the allowed keys exist.
310
		$intersecting_keys = array_intersect( $allowed_keys, $arr_keys );
311
		if ( count( $allowed_keys ) === count( $intersecting_keys ) ) {
312
			return $arr;
313
		}
314
315
		// Otherwise remove keys that aren't expected.
316
		$diff_keys = array_diff_key( $arr, $allowed_keys );
317
		foreach ( $diff_keys as $key ) {
318
			unset( $arr[ $key ] );
319
		}
320
321
		return $arr;
322
	}
323
324
	/**
325
	 * Sanitizes the db_size_notification option.
326
	 *
327
	 * @since 2.3.0
328
	 *
329
	 * @param array $db_size_notification_data
330
	 *
331
	 * @return array $db_size_notification_data
332
	 */
333
	public function sanitize_db_size_notification( $db_size_notification_data ) {
334
		$db_size_notification_data = $this->restrict_array_to_db_size_notification_setting_keys( $db_size_notification_data );
335
336
		foreach ( $db_size_notification_data as $setting => $value ) {
337
			if ( 'notify' === $setting ) {
338
				$db_size_notification_data[ $setting ] = \filter_var( $value, FILTER_VALIDATE_BOOLEAN );
339
			} elseif ( 'admin_email' === $setting ) {
340
				$db_size_notification_data[ $setting ] = \sanitize_email( $value );
341
			} elseif ( 'logs_threshold' === $setting ) {
342
				$db_size_notification_data[ $setting ] = absint( \sanitize_text_field( $value ) );
343
			}
344
		}
345
346
		// wp_parse_args won't merge nested array keys. So add the key here if it is not set.
347
		if ( ! array_key_exists( 'notify', $db_size_notification_data ) ) {
348
			$db_size_notification_data['notify'] = false;
349
		}
350
		if ( ! array_key_exists( 'log_threshold_met', $db_size_notification_data ) ) {
351
			$db_size_notification_data['log_threshold_met'] = false;
352
		}
353
		if ( ! array_key_exists( 'threshold_email_last_sent', $db_size_notification_data ) ) {
354
			$db_size_notification_data['threshold_email_last_sent'] = false;
355
		}
356
357
		return $db_size_notification_data;
358
	}
359
360
	/**
361
	 * Triggers the Cron to notify admin via email.
362
	 *
363
	 * Email is triggered only when the threshold setting is met.
364
	 *
365
	 * @since 2.3.0
366
	 */
367
	public function verify_email_log_threshold() {
368
		$cron_hook = 'el_trigger_notify_email_when_log_threshold_met';
369
		if ( ! wp_next_scheduled( $cron_hook ) ) {
370
			wp_schedule_event( time(), 'hourly', $cron_hook );
371
		}
372
	}
373
374
	/**
375
	 * Utility method to verify all the given keys exist in the given array.
376
	 *
377
	 * This method helps reduce the Cyclomatic Complexity in its parent method.
378
	 *
379
	 * @since 2.3.0
380
	 *
381
	 * @param array $arr  The array whose keys must be checked.
382
	 * @param array $keys All the required keys that the array must contain.
383
	 *
384
	 * @return bool
385
	 */
386
	protected function has_array_contains_required_keys( $arr, $keys ) {
387
		$has_keys = true;
388
389
		if ( ! is_array( $arr ) || ! is_array( $keys ) ) {
0 ignored issues
show
introduced by
The condition is_array($keys) is always true.
Loading history...
introduced by
The condition is_array($arr) is always true.
Loading history...
390
			return false;
391
		}
392
393
		foreach ( $arr as $key => $value ) {
394
			$has_keys = $has_keys && in_array( $key, $keys, true );
395
		}
396
397
		return $has_keys;
398
	}
399
400
	/**
401
	 * Send the Threshold notification email to the admin.
402
	 *
403
	 * @since 2.3.0
404
	 */
405
	public function trigger_threshold_met_notification_email() {
406
		$email_log  = email_log();
407
		$logs_count = absint( $email_log->table_manager->get_logs_count() );
408
409
		$setting_data = $this->get_value();
410
411
		// Return early.
412
		if ( ! array_key_exists( 'db_size_notification', $setting_data ) ) {
413
			return;
414
		}
415
416
		$db_size_notification_key  = 'db_size_notification';
417
		$db_size_notification_data = $setting_data[ $db_size_notification_key ];
418
419
		// Return early.
420
		$keys = array_keys( $this->section->default_value['db_size_notification'] );
421
		if ( ! $this->has_array_contains_required_keys( $db_size_notification_data, $keys ) ) {
422
			return;
423
		}
424
425
		$is_notification_enabled = $db_size_notification_data['notify'];
426
		$admin_email             = $db_size_notification_data['admin_email'];
427
		$logs_threshold          = absint( $db_size_notification_data['logs_threshold'] );
428
		$logs_threshold_met      = $db_size_notification_data['log_threshold_met'];
429
430
		// Ideally threshold cannot be 0. Also, skip sending email if it is already sent.
431
		if ( 0 === $logs_threshold || true === $logs_threshold_met ) {
432
			return;
433
		}
434
435
		if ( $logs_count < $logs_threshold ) {
436
			return;
437
		}
438
439
		$this->register_threshold_met_admin_notice();
440
441
		if ( $is_notification_enabled && is_email( $admin_email ) ) {
442
			$subject = sprintf( __( 'Email Log Plugin: Your log threshold of %s has been met', 'email-log' ), $logs_threshold );
443
			$message = <<<EOT
444
<p>This email is generated by the Email Log plugin.</p>
445
<p>Your log threshold of $logs_threshold has been met. You may manually delete the logs to keep your database table in size.</p>
446
<p>Also, consider using our <a href="https://wpemaillog.com/addons/auto-delete-logs/">Auto Delete Logs</a> plugin to delete the logs automatically.</p>
447
EOT;
448
			$headers = array( 'Content-Type: text/html; charset=UTF-8' );
449
450
			/**
451
			 * Filters Log threshold notification email subject.
452
			 *
453
			 * @since 2.3.0
454
			 *
455
			 * @param string $subject The email subject.
456
			 */
457
			$subject = apply_filters( 'el_log_threshold_met_notification_email_subject', $subject );
458
459
			/**
460
			 * Filters Log threshold notification email body.
461
			 *
462
			 * @since 2.3.0
463
			 *
464
			 * @param string $message        The email body.
465
			 * @param int    $logs_threshold The log threshold value set by the user.
466
			 */
467
			$message = apply_filters( 'el_log_threshold_met_notification_email_body', $message, $logs_threshold );
468
469
			wp_mail( $admin_email, $subject, $message, $headers );
470
471
			$setting_data[ $db_size_notification_key ]['log_threshold_met']         = true;
472
			$setting_data[ $db_size_notification_key ]['threshold_email_last_sent'] = time();
473
			\update_option( $this->section->option_name, $setting_data );
474
		}
475
	}
476
477
	/**
478
	 * Registers the Email Log threshold met admin notice.
479
	 *
480
	 * @since 2.3.0
481
	 */
482
	public function register_threshold_met_admin_notice() {
483
		add_action( 'admin_notices', array( $this, 'render_log_threshold_met_notice' ) );
484
	}
485
486
	/**
487
	 * Displays the Email Log threshold met admin notice.
488
	 *
489
	 * @since 2.3.0
490
	 */
491
	public function render_log_threshold_met_notice() {
492
		$email_log      = email_log();
493
		$logs_count     = absint( $email_log->table_manager->get_logs_count() );
494
		$notice_message = sprintf( __( 'Currently there are %1$s logged, which is more than the threshold that is set in the %2$s screen. You can delete some logs or increase the threshold. You can also use our %3$s add-on to automatically delete logs', 'email-log' ),
495
			$logs_count . _n( ' email log', ' email logs', $logs_count, 'email-log' ),
496
			'<a href="' . esc_url( admin_url( 'admin.php?page=' . SettingsPage::PAGE_SLUG ) ) . '">settings</a> screen',
497
			'<a href="' . esc_url( 'https://wpemaillog.com/addons/auto-delete-logs/' ) . '">Auto Delete Logs</a>'
498
			 );
499
		?>
500
        <div class="notice notice-warning is-dismissible">
501
            <p><?php echo $notice_message; ?></p>
502
        </div>
503
		<?php
504
	}
505
506
	/**
507
	 * Sanitize Pause Emails value.
508
	 *
509
	 * @param string $value User selected value. Either 'true' or 'false'.
510
	 *
511
	 * @return string Sanitized value.
512
	 */
513
	public function sanitize_pause_emails( $value ) {
514
		return sanitize_text_field( $value );
515
	}
516
517
	public function render_pause_emails_settings( $args ) {
518
		$option      = $this->get_value();
519
		$remove_data = $option[ $args['id'] ];
520
521
		$field_name = $this->section->option_name . '[' . $args['id'] . ']';
522
		?>
523
524
		<input type="checkbox" name="<?php echo esc_attr( $field_name ); ?>" value="true" <?php checked( 'true', $remove_data ); ?>>
525
		<?php _e( 'Check this box if you would like to pause the emails that are sent.', 'email-log' ) ?>
526
527
		<p>
528
			<em>
529
				<?php echo wp_kses(
530
					__( '<strong>Note</strong>: Emails will only be logged and won\'t be sent.', 'email-log' ),
531
					array(
532
						'strong' => array(),
533
						'em'     => array(),
534
					)
535
				);
536
				?>
537
			</em>
538
		</p>
539
540
		<?php
541
	}
542
}
543