PluginProbe
Update Control / trunk
Update Control vtrunk
trunk 1.0 1.1 1.1.1 1.1.2 1.1.3 1.2 1.2.1 1.3 1.3.1 1.3.2 1.4 1.5 1.5.1
update-control / update-control.php

update-control.php in Update Control trunk, at update-control.php

728 lines 26.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Update Control
4 * Plugin URI: https://github.com/georgestephanis/plugins/tree/main/update-control
5 * Description: Adds a manual toggle to the WordPress Admin Interface for managing auto-updates.
6 * Author: George Stephanis, Chip Bennett
7 * Version: 1.5.1
8 * Author URI: https://georgestephanis.wordpress.com/
9 * Text Domain: update-control
10 * License: GPL-2.0-or-later
11 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
12 *
13 * @package StephanisUpdateControl
14 */
15
16 namespace Stephanis\UpdateControl;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit; // Exit if accessed directly.
20 }
21
22 /**
23 * Update Control Class
24 */
25 class Update_Control {
26
27 /**
28 * Enqueue admin script and stylesheets for General settings page.
29 *
30 * @param string $hook The current admin page hook.
31 */
32 public static function enqueue_admin_scripts( $hook ) {
33 if ( is_multisite() && ! is_main_site() ) {
34 return;
35 }
36
37 if ( 'options-general.php' !== $hook ) {
38 return;
39 }
40
41 wp_enqueue_script(
42 'update-control-admin',
43 plugins_url( 'update-control.js', __FILE__ ),
44 array( 'jquery' ),
45 '1.5.1',
46 true
47 );
48
49 wp_enqueue_style(
50 'update-control-admin',
51 plugins_url( 'update-control.css', __FILE__ ),
52 array(),
53 '1.5.1'
54 );
55 }
56
57 /**
58 * Register automatic updates core/plugins/themes filters based on saved options.
59 */
60 public static function setup_upgrade_filters() {
61 if ( is_multisite() && ! is_main_site() ) {
62 return;
63 }
64
65 $options = self::get_options();
66
67 // Do these at priority 1, so other folks can easily override it.
68
69 if ( 'no' === $options['active'] ) {
70
71 add_filter( 'automatic_updater_disabled', '__return_true', 1 );
72
73 } else {
74
75 if ( 'dev' === $options['core'] ) {
76 add_filter( 'allow_dev_auto_core_updates', '__return_true', 1 );
77 add_filter( 'allow_major_auto_core_updates', '__return_true', 1 );
78 add_filter( 'allow_minor_auto_core_updates', '__return_true', 1 );
79 } elseif ( 'major' === $options['core'] ) {
80 add_filter( 'allow_dev_auto_core_updates', '__return_false', 1 );
81 add_filter( 'allow_major_auto_core_updates', '__return_true', 1 );
82 add_filter( 'allow_minor_auto_core_updates', '__return_true', 1 );
83 } else {
84 add_filter( 'allow_dev_auto_core_updates', '__return_false', 1 );
85 add_filter( 'allow_major_auto_core_updates', '__return_false', 1 );
86 add_filter( 'allow_minor_auto_core_updates', '__return_true', 1 );
87 }
88
89 if ( 'yes' === $options['plugin'] ) {
90 add_filter( 'auto_update_plugin', '__return_true', 1 );
91 add_filter( 'plugins_auto_update_enabled', '__return_false', 1 );
92 } elseif ( 'no' === $options['plugin'] ) {
93 add_filter( 'auto_update_plugin', '__return_false', 1 );
94 add_filter( 'plugins_auto_update_enabled', '__return_false', 1 );
95 }
96
97 if ( 'yes' === $options['theme'] ) {
98 add_filter( 'auto_update_theme', '__return_true', 1 );
99 add_filter( 'themes_auto_update_enabled', '__return_false', 1 );
100 } elseif ( 'no' === $options['theme'] ) {
101 add_filter( 'auto_update_theme', '__return_false', 1 );
102 add_filter( 'themes_auto_update_enabled', '__return_false', 1 );
103 }
104
105 if ( ! $options['translation'] ) {
106 add_filter( 'auto_update_translation', '__return_false', 1 );
107 }
108
109 if ( $options['vcscheck'] ) {
110 add_filter( 'automatic_updates_is_vcs_checkout', '__return_false', 1 );
111 }
112
113 if ( 'no' === $options['emailactive'] || ! ( $options['successemail'] || $options['failureemail'] || $options['criticalemail'] ) ) {
114 add_filter( 'auto_core_update_send_email', '__return_false', 1 );
115 add_filter( 'auto_plugin_update_send_email', '__return_false', 1 );
116 add_filter( 'auto_theme_update_send_email', '__return_false', 1 );
117 } else {
118 add_filter( 'auto_core_update_send_email', array( __CLASS__, 'filter_email' ), 1, 2 );
119 add_filter( 'auto_plugin_update_send_email', array( __CLASS__, 'filter_plugin_theme_email' ), 1, 2 );
120 add_filter( 'auto_theme_update_send_email', array( __CLASS__, 'filter_plugin_theme_email' ), 1, 2 );
121 }
122
123 if ( $options['debugemail'] ) {
124 add_filter( 'automatic_updates_send_debug_email', '__return_false', 1 );
125 }
126
127 if ( ! empty( $options['notification_email'] ) ) {
128 add_filter( 'auto_core_update_email', array( __CLASS__, 'filter_email_recipient' ), 10, 1 );
129 add_filter( 'auto_plugin_theme_update_email', array( __CLASS__, 'filter_email_recipient' ), 10, 1 );
130 }
131 }
132 }
133
134 /**
135 * Filters whether to send update emails based on the update status type.
136 *
137 * @param bool $should_send Whether to send the email.
138 * @param string $type The email type (e.g. success, fail, critical).
139 * @return bool True if emails should be sent, false otherwise.
140 */
141 public static function filter_email( $should_send, $type ) {
142 $options = self::get_options();
143
144 if ( 'success' === $type && ! $options['successemail'] ) {
145 return false;
146 }
147
148 if ( 'fail' === $type && ! $options['failureemail'] ) {
149 return false;
150 }
151
152 if ( 'critical' === $type && ! $options['criticalemail'] ) {
153 return false;
154 }
155 return $should_send;
156 }
157
158 /**
159 * Filters whether to send plugin/theme update emails based on the update results.
160 *
161 * @param bool $should_send Whether to send the email.
162 * @param array $update_results Array of update results.
163 * @return bool True if emails should be sent, false otherwise.
164 */
165 public static function filter_plugin_theme_email( $should_send, $update_results ) {
166 $options = self::get_options();
167
168 // If email notification is globally disabled, do not send.
169 if ( 'no' === $options['emailactive'] ) {
170 return false;
171 }
172
173 $has_success = false;
174 $has_failure = false;
175
176 if ( is_array( $update_results ) ) {
177 foreach ( $update_results as $result_obj ) {
178 if ( isset( $result_obj->result ) ) {
179 if ( true === $result_obj->result ) {
180 $has_success = true;
181 } else {
182 $has_failure = true;
183 }
184 }
185 }
186 }
187
188 // If we only have successes, check if success emails are disabled.
189 if ( $has_success && ! $has_failure && ! $options['successemail'] ) {
190 return false;
191 }
192
193 // If we only have failures, check if failure and critical emails are disabled.
194 if ( $has_failure && ! $has_success && ! $options['failureemail'] && ! $options['criticalemail'] ) {
195 return false;
196 }
197
198 // If we have both successes and failures.
199 if ( $has_success && $has_failure ) {
200 // If both success emails and failure/critical emails are disabled, then don't send.
201 if ( ! $options['successemail'] && ! $options['failureemail'] && ! $options['criticalemail'] ) {
202 return false;
203 }
204 }
205
206 return $should_send;
207 }
208
209 /**
210 * Retrieve saved plugin options combined with defaults.
211 *
212 * @return array The option array.
213 */
214 public static function get_options() {
215 $defaults = array(
216 'active' => 'yes',
217 'core' => 'minor',
218 'plugin' => 'core',
219 'theme' => 'core',
220 'translation' => true,
221 'toggleadvanced' => 'hide',
222 'vcscheck' => false,
223 'emailactive' => 'yes',
224 'successemail' => true,
225 'failureemail' => true,
226 'criticalemail' => true,
227 'debugemail' => false,
228 'notification_email' => '',
229 );
230 $args = get_option( 'update_control_options', array() );
231
232 // Migrate old boolean values to the new string format.
233 if ( isset( $args['plugin'] ) ) {
234 if ( true === $args['plugin'] || '1' === $args['plugin'] || 'yes' === $args['plugin'] ) {
235 $args['plugin'] = 'yes';
236 } elseif ( false === $args['plugin'] || '0' === $args['plugin'] || '' === $args['plugin'] ) {
237 $args['plugin'] = 'core';
238 }
239 }
240 if ( isset( $args['theme'] ) ) {
241 if ( true === $args['theme'] || '1' === $args['theme'] || 'yes' === $args['theme'] ) {
242 $args['theme'] = 'yes';
243 } elseif ( false === $args['theme'] || '0' === $args['theme'] || '' === $args['theme'] ) {
244 $args['theme'] = 'core';
245 }
246 }
247
248 return wp_parse_args( $args, $defaults );
249 }
250
251 /**
252 * Retrieve a single option value by key.
253 *
254 * @param string $key Option key.
255 * @return mixed Option value or null.
256 */
257 public static function get_option( $key ) {
258 $options = self::get_options();
259 if ( isset( $options[ $key ] ) ) {
260 return $options[ $key ];
261 }
262 return null;
263 }
264
265 /**
266 * Register plugin settings option group and add settings fields.
267 */
268 public static function register_settings() {
269 if ( is_multisite() && ! is_main_site() ) {
270 return;
271 }
272
273 if ( ! current_user_can( 'manage_options' ) ) {
274 return;
275 }
276
277 add_settings_section(
278 'update-control',
279 esc_html__( 'Automatic Updates', 'update-control' ),
280 array( __CLASS__, 'update_control_settings_section' ),
281 'general'
282 );
283
284 if ( defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED ) {
285 return;
286 }
287
288 add_settings_field(
289 'update_control_active',
290 sprintf( '<label for="update_control_active">%1$s</label>', esc_html__( 'Automatic Updates Enabled?', 'update-control' ) ),
291 array( __CLASS__, 'update_control_active_cb' ),
292 'general',
293 'update-control'
294 );
295
296 add_settings_field(
297 'update_control_core',
298 esc_html__( 'Automatic Core Update Level?', 'update-control' ),
299 array( __CLASS__, 'update_control_core_cb' ),
300 'general',
301 'update-control'
302 );
303
304 add_settings_field(
305 'update_control_plugin',
306 esc_html__( 'Automatic Plugin Updates', 'update-control' ),
307 array( __CLASS__, 'update_control_plugin_cb' ),
308 'general',
309 'update-control'
310 );
311
312 add_settings_field(
313 'update_control_theme',
314 esc_html__( 'Automatic Theme Updates', 'update-control' ),
315 array( __CLASS__, 'update_control_theme_cb' ),
316 'general',
317 'update-control'
318 );
319
320 add_settings_field(
321 'update_control_translation',
322 sprintf( '<label for="update_control_translation">%1$s</label>', esc_html__( 'Permit Automatic Translation Updates?', 'update-control' ) ),
323 array( __CLASS__, 'update_control_translation_cb' ),
324 'general',
325 'update-control'
326 );
327
328 add_settings_field(
329 'update_control_toggleadvanced',
330 esc_html__( 'Advanced Settings', 'update-control' ),
331 array( __CLASS__, 'update_control_toggleadvanced_cb' ),
332 'general',
333 'update-control'
334 );
335
336 add_settings_field(
337 'update_control_vcscheck',
338 sprintf( '<label for="update_control_vcscheck">%1$s</label>', esc_html__( 'Enable updates for VCS installations?', 'update-control' ) ),
339 array( __CLASS__, 'update_control_vcscheck_cb' ),
340 'general',
341 'update-control'
342 );
343
344 add_settings_field(
345 'update_control_email_active',
346 sprintf( '<label for="update_control_email_active">%1$s</label>', esc_html__( 'Update Emails Enabled?', 'update-control' ) ),
347 array( __CLASS__, 'update_control_email_active_cb' ),
348 'general',
349 'update-control'
350 );
351
352 add_settings_field(
353 'update_control_email_recipient',
354 sprintf( '<label for="update_control_email_recipient">%1$s</label>', esc_html__( 'Notification Email Address', 'update-control' ) ),
355 array( __CLASS__, 'update_control_email_recipient_cb' ),
356 'general',
357 'update-control'
358 );
359
360 add_settings_field(
361 'update_control_email_success',
362 sprintf( '<label for="update_control_email_success">%1$s</label>', esc_html__( 'Send Emails for Successful Updates?', 'update-control' ) ),
363 array( __CLASS__, 'update_control_email_success_cb' ),
364 'general',
365 'update-control'
366 );
367
368 add_settings_field(
369 'update_control_email_failure',
370 sprintf( '<label for="update_control_email_failure">%1$s</label>', esc_html__( 'Send Emails for Failed Updates?', 'update-control' ) ),
371 array( __CLASS__, 'update_control_email_failure_cb' ),
372 'general',
373 'update-control'
374 );
375
376 add_settings_field(
377 'update_control_email_critical',
378 sprintf( '<label for="update_control_email_critical">%1$s</label>', esc_html__( 'Send Emails for Critically Failed Updates?', 'update-control' ) ),
379 array( __CLASS__, 'update_control_email_critical_cb' ),
380 'general',
381 'update-control'
382 );
383
384 $wp_version = $GLOBALS['wp_version'];
385 if ( false !== strpos( $wp_version, '-' ) ) {
386 add_settings_field(
387 'update_control_email_debug',
388 sprintf( '<label for="update_control_email_debug">%1$s</label>', esc_html__( 'Disable Debug Emails for Development Versions?', 'update-control' ) ),
389 array( __CLASS__, 'update_control_email_debug_cb' ),
390 'general',
391 'update-control'
392 );
393 }
394
395 register_setting( 'general', 'update_control_options', array( __CLASS__, 'sanitize_options' ) );
396 }
397
398 /**
399 * Output descriptions and instructions for the settings section.
400 */
401 public static function update_control_settings_section() {
402 if ( defined( 'AUTOMATIC_UPDATER_DISABLED' ) && AUTOMATIC_UPDATER_DISABLED ) : ?>
403 <p id="update-control-settings-section">
404 <?php
405 echo wp_kses(
406 sprintf(
407 /* translators: %s: PHP constant name */
408 __( 'You have the %s constant set. Automatic updates are disabled.', 'update-control' ),
409 '<code>AUTOMATIC_UPDATER_DISABLED</code>'
410 ),
411 array( 'code' => array() )
412 );
413 ?>
414 </p>
415 <?php else : ?>
416 <p id="update-control-settings-section">
417 <?php esc_html_e( 'This section lets you specify what areas of your WordPress install will be permitted to auto-update.', 'update-control' ); ?>
418 </p>
419 <?php
420 endif;
421 }
422
423 /**
424 * Output markup for 'Automatic Updates Enabled?' field.
425 */
426 public static function update_control_active_cb() {
427 ?>
428 <select id="update_control_active" name="update_control_options[active]">
429 <option <?php selected( 'yes' === self::get_option( 'active' ) ); ?> value="yes"><?php esc_html_e( 'Yes', 'update-control' ); ?></option>
430 <option <?php selected( 'no' === self::get_option( 'active' ) ); ?> value="no"><?php esc_html_e( 'No', 'update-control' ); ?></option>
431 </select>
432 <?php
433 }
434
435 /**
436 * Output markup for 'Automatic Core Update Level?' field.
437 */
438 public static function update_control_core_cb() {
439 $val = self::get_option( 'core' );
440 ?>
441 <fieldset>
442 <legend class="screen-reader-text"><span><?php esc_html_e( 'Automatic Core Update Level?', 'update-control' ); ?></span></legend>
443 <label><input type="radio" class="update_control_dependency" id="update_control_core_minor" name="update_control_options[core]" value="minor" <?php checked( 'minor' === $val ); ?> /> <?php esc_html_e( 'Minor Updates', 'update-control' ); ?></label><br />
444 <label><input type="radio" class="update_control_dependency" id="update_control_core_major" name="update_control_options[core]" value="major" <?php checked( 'major' === $val ); ?> /> <?php esc_html_e( 'Major Updates', 'update-control' ); ?></label><br />
445 <label><input type="radio" class="update_control_dependency" id="update_control_core_dev" name="update_control_options[core]" value="dev" <?php checked( 'dev' === $val ); ?> /> <?php esc_html_e( 'Development Updates', 'update-control' ); ?></label>
446 </fieldset>
447 <?php
448 }
449
450 /**
451 * Output markup for 'Automatic Plugin Updates' field.
452 */
453 public static function update_control_plugin_cb() {
454 $val = self::get_option( 'plugin' );
455 ?>
456 <fieldset>
457 <legend class="screen-reader-text"><span><?php esc_html_e( 'Automatic Plugin Updates', 'update-control' ); ?></span></legend>
458 <label><input type="radio" class="update_control_dependency" id="update_control_plugin_yes" name="update_control_options[plugin]" value="yes" <?php checked( 'yes' === $val ); ?> /> <?php esc_html_e( 'Auto-update all plugins', 'update-control' ); ?></label><br />
459 <label><input type="radio" class="update_control_dependency" id="update_control_plugin_no" name="update_control_options[plugin]" value="no" <?php checked( 'no' === $val ); ?> /> <?php esc_html_e( 'Disable all plugin auto-updates', 'update-control' ); ?></label><br />
460 <label><input type="radio" class="update_control_dependency" id="update_control_plugin_core" name="update_control_options[plugin]" value="core" <?php checked( 'core' === $val ); ?> /> <?php esc_html_e( 'Choose individually (WordPress default)', 'update-control' ); ?></label>
461 </fieldset>
462 <?php
463 }
464
465 /**
466 * Output markup for 'Automatic Theme Updates' field.
467 */
468 public static function update_control_theme_cb() {
469 $val = self::get_option( 'theme' );
470 ?>
471 <fieldset>
472 <legend class="screen-reader-text"><span><?php esc_html_e( 'Automatic Theme Updates', 'update-control' ); ?></span></legend>
473 <label><input type="radio" class="update_control_dependency" id="update_control_theme_yes" name="update_control_options[theme]" value="yes" <?php checked( 'yes' === $val ); ?> /> <?php esc_html_e( 'Auto-update all themes', 'update-control' ); ?></label><br />
474 <label><input type="radio" class="update_control_dependency" id="update_control_theme_no" name="update_control_options[theme]" value="no" <?php checked( 'no' === $val ); ?> /> <?php esc_html_e( 'Disable all theme auto-updates', 'update-control' ); ?></label><br />
475 <label><input type="radio" class="update_control_dependency" id="update_control_theme_core" name="update_control_options[theme]" value="core" <?php checked( 'core' === $val ); ?> /> <?php esc_html_e( 'Choose individually (WordPress default)', 'update-control' ); ?></label>
476 </fieldset>
477 <?php
478 }
479
480 /**
481 * Output markup for 'Permit Automatic Translation Updates?' field.
482 */
483 public static function update_control_translation_cb() {
484 ?>
485 <input type="checkbox" class="update_control_dependency" id="update_control_translation" name="update_control_options[translation]" <?php checked( self::get_option( 'translation' ) ); ?> />
486 <?php
487 }
488
489 /**
490 * Output markup for 'Advanced Settings' field.
491 */
492 public static function update_control_toggleadvanced_cb() {
493 $options = self::get_options();
494 $is_open = 'show' === $options['toggleadvanced'];
495 ?>
496 <details id="update_control_toggleadvanced_details" class="update_control_dependency"<?php echo $is_open ? ' open' : ''; ?>>
497 <summary style="cursor: pointer; font-weight: 600; user-select: none;">
498 <span class="open-text"><?php esc_html_e( 'Hide settings', 'update-control' ); ?></span>
499 <span class="closed-text"><?php esc_html_e( 'Show settings', 'update-control' ); ?></span>
500 </summary>
501 </details>
502 <input type="hidden" id="update_control_toggleadvanced" name="update_control_options[toggleadvanced]" value="<?php echo esc_attr( $options['toggleadvanced'] ); ?>" />
503 <?php
504 }
505
506 /**
507 * Output markup for 'Enable updates for VCS installations?' field.
508 */
509 public static function update_control_vcscheck_cb() {
510 $is_vcs = self::is_vcs_checkout();
511 ?>
512 <input type="checkbox" class="update_control_advanced" id="update_control_vcscheck" name="update_control_options[vcscheck]" <?php checked( self::get_option( 'vcscheck' ) ); ?> />
513 <p class="description">
514 <?php
515 if ( null === $is_vcs ) {
516 esc_html_e( 'Unable to determine whether this site is under version control.', 'update-control' );
517 } elseif ( $is_vcs ) {
518 esc_html_e( 'This site appears to be a version control checkout, so WordPress would normally block automatic updates. Enable this to allow them anyway.', 'update-control' );
519 } else {
520 esc_html_e( 'This site does not appear to be a version control checkout, so this setting has no effect here.', 'update-control' );
521 }
522 ?>
523 </p>
524 <?php
525 $vcs_checkouts = self::get_vcs_checkouts();
526 if ( ! empty( $vcs_checkouts['plugins'] ) || ! empty( $vcs_checkouts['themes'] ) ) {
527 ?>
528 <p class="description">
529 <?php esc_html_e( 'The following are also version control checkouts and would be blocked individually:', 'update-control' ); ?>
530 <?php
531 if ( ! empty( $vcs_checkouts['plugins'] ) ) {
532 printf(
533 '<br />%1$s %2$s',
534 esc_html__( 'Plugins:', 'update-control' ),
535 esc_html( implode( ', ', $vcs_checkouts['plugins'] ) )
536 );
537 }
538 if ( ! empty( $vcs_checkouts['themes'] ) ) {
539 printf(
540 '<br />%1$s %2$s',
541 esc_html__( 'Themes:', 'update-control' ),
542 esc_html( implode( ', ', $vcs_checkouts['themes'] ) )
543 );
544 }
545 ?>
546 </p>
547 <?php
548 }
549 }
550
551 /**
552 * Scan installed plugins and themes for version control checkouts.
553 *
554 * WordPress blocks automatic updates for any plugin or theme whose directory
555 * contains version control metadata, independent of whether the core install
556 * is itself a checkout.
557 *
558 * @return array {
559 * @type string[] $plugins Names of plugin directories under version control.
560 * @type string[] $themes Names of themes under version control.
561 * }
562 */
563 private static function get_vcs_checkouts() {
564 $vcs_dirs = array( '.svn', '.git', '.hg', '.bzr' );
565 $found = array(
566 'plugins' => array(),
567 'themes' => array(),
568 );
569
570 if ( defined( 'WP_PLUGIN_DIR' ) && is_dir( WP_PLUGIN_DIR ) ) {
571 foreach ( (array) glob( WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR ) as $plugin_dir ) {
572 foreach ( $vcs_dirs as $vcs ) {
573 if ( is_dir( $plugin_dir . '/' . $vcs ) ) {
574 $found['plugins'][] = basename( $plugin_dir );
575 break;
576 }
577 }
578 }
579 }
580
581 foreach ( wp_get_themes() as $theme ) {
582 $stylesheet_dir = $theme->get_stylesheet_directory();
583 foreach ( $vcs_dirs as $vcs ) {
584 if ( is_dir( $stylesheet_dir . '/' . $vcs ) ) {
585 $found['themes'][] = $theme->get( 'Name' );
586 break;
587 }
588 }
589 }
590
591 return $found;
592 }
593
594 /**
595 * Determine whether the current site is a version control checkout.
596 *
597 * Mirrors the detection WordPress core uses to decide whether to block
598 * automatic updates on VCS installs.
599 *
600 * @return bool|null True/false if detectable, null if it cannot be determined.
601 */
602 private static function is_vcs_checkout() {
603 if ( ! class_exists( 'WP_Automatic_Updater' ) ) {
604 require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php';
605 }
606
607 if ( ! class_exists( 'WP_Automatic_Updater' ) ) {
608 return null;
609 }
610
611 $updater = new \WP_Automatic_Updater();
612
613 return (bool) $updater->is_vcs_checkout( ABSPATH );
614 }
615
616 /**
617 * Output markup for 'Update Emails Enabled?' field.
618 */
619 public static function update_control_email_active_cb() {
620 ?>
621 <select class="update_control_advanced" id="update_control_email_active" name="update_control_options[emailactive]">
622 <option <?php selected( 'yes' === self::get_option( 'emailactive' ) ); ?> value="yes"><?php esc_html_e( 'Yes', 'update-control' ); ?></option>
623 <option <?php selected( 'no' === self::get_option( 'emailactive' ) ); ?> value="no"><?php esc_html_e( 'No', 'update-control' ); ?></option>
624 </select>
625 <?php
626 }
627
628 /**
629 * Output markup for 'Send Emails for Successful Updates?' field.
630 */
631 public static function update_control_email_success_cb() {
632 ?>
633 <input type="checkbox" class="update_control_email_dependency update_control_advanced" id="update_control_email_success" name="update_control_options[successemail]" <?php checked( self::get_option( 'successemail' ) ); ?> />
634 <?php
635 }
636
637 /**
638 * Output markup for 'Send Emails for Failed Updates?' field.
639 */
640 public static function update_control_email_failure_cb() {
641 ?>
642 <input type="checkbox" class="update_control_email_dependency update_control_advanced" id="update_control_email_failure" name="update_control_options[failureemail]" <?php checked( self::get_option( 'failureemail' ) ); ?> />
643 <?php
644 }
645
646 /**
647 * Output markup for 'Send Emails for Critically Failed Updates?' field.
648 */
649 public static function update_control_email_critical_cb() {
650 ?>
651 <input type="checkbox" class="update_control_email_dependency update_control_advanced" id="update_control_email_critical" name="update_control_options[criticalemail]" <?php checked( self::get_option( 'criticalemail' ) ); ?> />
652 <?php
653 }
654
655 /**
656 * Output markup for 'Disable Debug Emails for Development Versions?' field.
657 */
658 public static function update_control_email_debug_cb() {
659 ?>
660 <input type="checkbox" class="update_control_advanced" id="update_control_email_debug" name="update_control_options[debugemail]" <?php checked( self::get_option( 'debugemail' ) ); ?> />
661 <?php
662 }
663
664 /**
665 * Output markup for 'Notification Email Address' field.
666 */
667 public static function update_control_email_recipient_cb() {
668 ?>
669 <?php
670 $default_recipient = get_option( 'admin_email' );
671 if ( $default_recipient ) {
672 $recipient_placeholder = sprintf(
673 /* translators: %s: the site's admin email address. */
674 __( 'Leave empty to use %s', 'update-control' ),
675 $default_recipient
676 );
677 } else {
678 $recipient_placeholder = __( 'Leave empty for default admin email', 'update-control' );
679 }
680 ?>
681 <input type="email" class="update_control_email_dependency update_control_advanced regular-text" id="update_control_email_recipient" name="update_control_options[notification_email]" value="<?php echo esc_attr( self::get_option( 'notification_email' ) ); ?>" placeholder="<?php echo esc_attr( $recipient_placeholder ); ?>" />
682 <?php
683 }
684
685 /**
686 * Overrides the recipient email address for auto-update notifications.
687 *
688 * @param array $email Email arguments.
689 * @return array Modified email arguments.
690 */
691 public static function filter_email_recipient( $email ) {
692 $options = self::get_options();
693 if ( ! empty( $options['notification_email'] ) && is_email( $options['notification_email'] ) ) {
694 $email['to'] = $options['notification_email'];
695 }
696 return $email;
697 }
698
699 /**
700 * Sanitize plugin options on save.
701 *
702 * @param array $options Raw options sent by option page.
703 * @return array Sanitized options.
704 */
705 public static function sanitize_options( $options ) {
706 $options = wp_parse_args( (array) $options, self::get_options() );
707
708 $options['active'] = ( in_array( $options['active'], array( 'yes', 'no' ), true ) ? $options['active'] : 'yes' );
709 $options['core'] = ( in_array( $options['core'], array( 'minor', 'major', 'dev' ), true ) ? $options['core'] : 'minor' );
710 $options['plugin'] = ( in_array( $options['plugin'], array( 'yes', 'no', 'core' ), true ) ? $options['plugin'] : 'core' );
711 $options['theme'] = ( in_array( $options['theme'], array( 'yes', 'no', 'core' ), true ) ? $options['theme'] : 'core' );
712 $options['translation'] = ! empty( $options['translation'] );
713 $options['toggleadvanced'] = ( isset( $options['toggleadvanced'] ) && in_array( $options['toggleadvanced'], array( 'show', 'hide' ), true ) ? $options['toggleadvanced'] : 'hide' );
714 $options['vcscheck'] = ! empty( $options['vcscheck'] );
715 $options['emailactive'] = ( in_array( $options['emailactive'], array( 'yes', 'no' ), true ) ? $options['emailactive'] : 'yes' );
716 $options['successemail'] = ! empty( $options['successemail'] );
717 $options['failureemail'] = ! empty( $options['failureemail'] );
718 $options['criticalemail'] = ! empty( $options['criticalemail'] );
719 $options['debugemail'] = ! empty( $options['debugemail'] );
720 $options['notification_email'] = ! empty( $options['notification_email'] ) ? sanitize_email( $options['notification_email'] ) : '';
721
722 return $options;
723 }
724 }
725 add_action( 'admin_init', array( __NAMESPACE__ . '\Update_Control', 'register_settings' ) );
726 add_action( 'init', array( __NAMESPACE__ . '\Update_Control', 'setup_upgrade_filters' ) );
727 add_action( 'admin_enqueue_scripts', array( __NAMESPACE__ . '\Update_Control', 'enqueue_admin_scripts' ) );
728