Passed
Push — 124-feature/notify-admins-on-e... ( 99307f...a3e7cd )
by Maria Daniel Deepak
03:25
created

CoreSetting::load()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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

251
			'<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...
252
253
		$logs_threshold_input_field = sprintf( '<input type="number" name="%1$s" placeholder="5000" value="%2$s" min="0" max="99999999" />',
254
			esc_attr( $logs_threshold_field_name ),
255
			empty( $db_size_notification_data['logs_threshold'] ) ? '' : esc_attr( $db_size_notification_data['logs_threshold'] )
256
		);
257
		?>
258
259
        <input type="checkbox" name="<?php echo esc_attr( $db_size_notification_field_name ); ?>" value="true" <?php
260
		checked( true, $db_size_notification_data['notify'] ); ?> />
261
		<?php
262
		// The values within each field are already escaped.
263
		printf( __( 'Notify %1$s if there are more than %2$s logs.', 'email-log' ),
264
			$admin_email_input_field,
265
			$logs_threshold_input_field
266
		);
267
		?>
268
        <p>
269
            <em>
270
				<?php printf(
271
					__( '%1$s There are %2$s email logs currently logged in the database.', 'email-log' ),
272
					'<strong>Note:</strong>',
273
					'<strong>' . esc_attr( $logs_count ) . '</strong>'
274
				); ?>
275
            </em>
276
        </p>
277
		<?php
278
	}
279
280
	/**
281
	 * Removes any additional keys set other than the ones in db_size_notification array.
282
	 *
283
	 * @since 2.3.0
284
	 *
285
	 * @param array $arr `db_size_notification` option array.
286
	 *
287
	 * @return array `db_size_notification` option array with keys removed other than the allowed.
288
	 */
289
	protected function restrict_array_to_db_size_notification_setting_keys( $arr ) {
290
		$allowed_keys = array_keys( $this->section->default_value['db_size_notification'] );
291
		$arr_keys     = array_keys( $arr );
292
293
		// Return the array when only the allowed keys exist.
294
		$intersecting_keys = array_intersect( $allowed_keys, $arr_keys );
295
		if ( count( $allowed_keys ) === count( $intersecting_keys ) ) {
296
			return $arr;
297
		}
298
299
		// Otherwise remove keys that aren't expected.
300
		$diff_keys = array_diff_key( $arr, $allowed_keys );
301
		foreach ( $diff_keys as $key ) {
302
			unset( $arr[ $key ] );
303
		}
304
305
		return $arr;
306
	}
307
308
	/**
309
	 * Sanitizes the db_size_notification option.
310
	 *
311
	 * @since 2.3.0
312
	 *
313
	 * @param array $db_size_notification_data
314
	 *
315
	 * @return array $db_size_notification_data
316
	 */
317
	public function sanitize_db_size_notification( $db_size_notification_data ) {
318
		$db_size_notification_data = $this->restrict_array_to_db_size_notification_setting_keys( $db_size_notification_data );
319
320
		foreach ( $db_size_notification_data as $setting => $value ) {
321
			if ( $setting === 'notify' ) {
322
				$db_size_notification_data[ $setting ] = \filter_var( $value, FILTER_VALIDATE_BOOLEAN );
323
			} elseif ( $setting === 'admin_email' ) {
324
				$db_size_notification_data[ $setting ] = \sanitize_email( $value );
325
			} elseif ( $setting === 'logs_threshold' ) {
326
				$db_size_notification_data[ $setting ] = absint( \sanitize_text_field( $value ) );
327
			}
328
		}
329
330
		// wp_parse_args won't merge nested array keys. So add the key here if it is not set.
331
		if ( ! array_key_exists( 'notify', $db_size_notification_data ) ) {
332
			$db_size_notification_data['notify'] = false;
333
		}
334
		if ( ! array_key_exists( 'log_threshold_met', $db_size_notification_data ) ) {
335
			$db_size_notification_data['log_threshold_met'] = false;
336
		}
337
338
		return $db_size_notification_data;
339
	}
340
341
	/**
342
	 * Triggers the Cron to notify admin via email.
343
	 *
344
	 * Email is triggered only when the threshold setting is met.
345
	 *
346
	 * @since 2.3.0
347
	 */
348
	public function verify_email_log_threshold() {
349
		$cron_hook = 'el_trigger_notify_email_when_log_threshold_met';
350
		if ( ! wp_next_scheduled( $cron_hook ) ) {
351
			wp_schedule_event( time(), 'hourly', $cron_hook );
352
		}
353
	}
354
355
	/**
356
	 * Utility method to verify all the given keys exist in the given array.
357
	 *
358
	 * This method helps reduce the Cyclomatic Complexity in its parent method.
359
	 *
360
	 * @since 2.3.0
361
	 *
362
	 * @param array $arr
363
	 * @param array $keys
364
	 *
365
	 * @return bool
366
	 */
367
	protected function has_array_contains_required_keys( $arr, $keys ) {
368
		$has_keys = true;
369
370
		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...
371
			return false;
372
		}
373
374
		foreach ( $arr as $key => $value ) {
375
			$has_keys = $has_keys && in_array( $key, $keys );
376
		}
377
378
		return $has_keys;
379
	}
380
381
	/**
382
	 * Send the Threshold notification email to the admin.
383
	 *
384
	 * @since 2.3.0
385
	 */
386
	public function trigger_threshold_met_notification_email() {
387
		$email_log  = email_log();
388
		$logs_count = absint( $email_log->table_manager->get_logs_count() );
389
390
		$setting_data = $this->get_value();
391
392
		// Return early.
393
		if ( ! array_key_exists( 'db_size_notification', $setting_data ) ) {
394
			return;
395
		}
396
397
		$db_size_notification_key  = 'db_size_notification';
398
		$db_size_notification_data = $setting_data[ $db_size_notification_key ];
399
400
		// Return early.
401
		$keys = array_keys( $this->section->default_value['db_size_notification'] );
402
		if ( ! $this->has_array_contains_required_keys( $db_size_notification_data, $keys ) ) {
403
			return;
404
		}
405
406
		$is_notification_enabled = $db_size_notification_data['notify'];
407
		$admin_email             = $db_size_notification_data['admin_email'];
408
		$logs_threshold          = absint( $db_size_notification_data['logs_threshold'] );
409
		$logs_threshold_met      = $db_size_notification_data['log_threshold_met'];
410
411
		// Ideally threshold cannot be 0. Also, skip sending email if it is already sent.
412
		if ( $logs_threshold === 0 || $logs_threshold_met === true ) {
413
			return;
414
		}
415
416
		if ( $logs_count < $logs_threshold ) {
417
			return;
418
		}
419
420
		$this->register_threshold_met_admin_notice();
421
422
		if ( $is_notification_enabled && is_email( $admin_email ) ) {
423
			$subject = sprintf( __( 'Email Log Plugin: Your log threshold of %s has been met', 'email-log' ),
424
				$logs_threshold );
425
			$message = <<<EOT
426
<p>This email is generated by the Email Log plugin.</p>
427
<p>Your log threshold of $logs_threshold has been met. You may manually delete the logs to keep your database table in size.</p>
428
<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>
429
EOT;
430
			$headers = array( 'Content-Type: text/html; charset=UTF-8' );
431
432
			/**
433
			 * Filters Log threshold notification email subject.
434
			 *
435
			 * @since 2.3.0
436
			 *
437
			 * @param string $subject The email subject.
438
			 */
439
			$subject = apply_filters( 'el_log_threshold_met_notification_email_subject', $subject );
440
441
			/**
442
			 * Filters Log threshold notification email body.
443
			 *
444
			 * @since 2.3.0
445
			 *
446
			 * @param string $message        The email body.
447
			 * @param int    $logs_threshold The log threshold value set by the user.
448
			 */
449
			$message = apply_filters( 'el_log_threshold_met_notification_email_body', $message, $logs_threshold );
450
451
			wp_mail( $admin_email, $subject, $message, $headers );
452
453
			$setting_data[ $db_size_notification_key ]['log_threshold_met'] = true;
454
			\update_option( $this->section->option_name, $setting_data );
455
		}
456
	}
457
458
	/**
459
	 * Registers the Email Log threshold met admin notice.
460
	 *
461
	 * @since 2.3.0
462
	 */
463
	public function register_threshold_met_admin_notice() {
464
		add_action( 'admin_notices', array( $this, 'render_log_threshold_met_notice' ) );
465
	}
466
467
	/**
468
	 * Displays the Email Log threshold met admin notice.
469
	 *
470
	 * @since 2.3.0
471
	 */
472
	public function render_log_threshold_met_notice() {
473
		$email_log      = email_log();
474
		$logs_count     = absint( $email_log->table_manager->get_logs_count() );
475
		$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',
476
			'email-log' ),
477
			$logs_count . _n( ' email log', ' email logs', $logs_count, 'email-log' ),
478
			'<a href="' . esc_url( admin_url( 'admin.php?page=' . SettingsPage::PAGE_SLUG ) ) . '">settings</a> screen',
479
			'<a href="' . esc_url( 'https://wpemaillog.com/addons/auto-delete-logs/' ) . '">Auto Delete Logs</a>'
480
			 );
481
		?>
482
        <div class="notice notice-warning is-dismissible">
483
            <p><?php echo $notice_message; ?></p>
484
        </div>
485
		<?php
486
	}
487
488
}
489