diff --git a/src/wp-admin/includes/class-wp-plugins-list-table.php b/src/wp-admin/includes/class-wp-plugins-list-table.php index a36ec05221..e299f47734 100644 --- a/src/wp-admin/includes/class-wp-plugins-list-table.php +++ b/src/wp-admin/includes/class-wp-plugins-list-table.php @@ -40,7 +40,7 @@ class WP_Plugins_List_Table extends WP_List_Table { ); $status = 'all'; - if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused' ) ) ) { + if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search', 'paused', 'update-on', 'update-off' ) ) ) { $status = $_REQUEST['plugin_status']; } @@ -100,6 +100,8 @@ class WP_Plugins_List_Table extends WP_List_Table { 'mustuse' => array(), 'dropins' => array(), 'paused' => array(), + 'update-on' => array(), + 'update-off' => array(), ); $screen = $this->screen; @@ -179,7 +181,8 @@ class WP_Plugins_List_Table extends WP_List_Table { update_option( 'recently_activated', $recently_activated ); } - $plugin_info = get_site_transient( 'update_plugins' ); + $plugin_info = get_site_transient( 'update_plugins' ); + $wp_autoupdated_plugins = get_option( 'wp_autoupdated_plugins', array() ); foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) { // Extra info if known. array_merge() ensures $plugin_data has precedence if keys collide. @@ -233,6 +236,12 @@ class WP_Plugins_List_Table extends WP_List_Table { // Populate the inactive list with plugins that aren't activated $plugins['inactive'][ $plugin_file ] = $plugin_data; } + + if ( in_array( $plugin_data['plugin'], $wp_autoupdated_plugins, true ) ) { + $plugins['update-on'][ $plugin_file ] = $plugin_data; + } else { + $plugins['update-off'][ $plugin_file ] = $plugin_data; + } } if ( strlen( $s ) ) { @@ -493,6 +502,22 @@ class WP_Plugins_List_Table extends WP_List_Table { $count ); break; + case 'update-on': + /* translators: %s: Number of plugins. */ + $text = _n( + 'Auto Update On (%s)', + 'Auto Update On (%s)', + $count + ); + break; + case 'update-off': + /* translators: %s: Number of plugins. */ + $text = _n( + 'Auto Update Off (%s)', + 'Auto Update Off (%s)', + $count + ); + break; } if ( 'search' !== $type ) { @@ -527,7 +552,9 @@ class WP_Plugins_List_Table extends WP_List_Table { if ( ! is_multisite() || $this->screen->in_admin( 'network' ) ) { if ( current_user_can( 'update_plugins' ) ) { - $actions['update-selected'] = __( 'Update' ); + $actions['update-selected'] = __( 'Update' ); + $actions['enable-autoupdate-selected'] = __( 'Enable auto update' ); + $actions['disable-autoupdate-selected'] = __( 'Disable auto update' ); } if ( current_user_can( 'delete_plugins' ) && ( 'active' != $status ) ) { $actions['delete-selected'] = __( 'Delete' ); @@ -960,6 +987,46 @@ class WP_Plugins_List_Table extends WP_List_Table { } } + $wp_autoupdated_plugins = get_option( 'wp_autoupdated_plugins', array() ); + if ( in_array( $plugin_file, $wp_autoupdated_plugins, true ) ) { + $aria_label = esc_attr( + sprintf( + /* translators: Plugin name. */ + _x( 'Disable automatic updates for %s', 'plugin' ), + $plugin_name + ) + ); + echo '
'; + echo ' ' . __( 'Automatic update enabled' ); + if ( current_user_can( 'update_plugins', $plugin_file ) ) { + echo sprintf( + ' | %s', + wp_nonce_url( 'plugins.php?action=autoupdate&plugin=' . urlencode( $plugin_file ) . '&paged=' . $page, 'autoupdate-plugin_' . $plugin_file ), + $aria_label, + __( 'Disable' ) + ); + } + echo '
'; + } else { + if ( current_user_can( 'update_plugins', $plugin_file ) ) { + $aria_label = esc_attr( + sprintf( + /* translators: Plugin name. */ + _x( 'Enable automatic updates for %s', 'plugin' ), + $plugin_name + ) + ); + echo ''; + echo sprintf( + ' %s', + wp_nonce_url( 'plugins.php?action=autoupdate&plugin=' . urlencode( $plugin_file ) . '&paged=' . $page, 'autoupdate-plugin_' . $plugin_file ), + $aria_label, + __( 'Enable automatic updates' ) + ); + echo '
'; + } + } + echo ''; break; default: diff --git a/src/wp-admin/includes/update.php b/src/wp-admin/includes/update.php index 0caa04a963..2d39b9bbde 100644 --- a/src/wp-admin/includes/update.php +++ b/src/wp-admin/includes/update.php @@ -488,9 +488,22 @@ function wp_plugin_update_row( $file, $plugin_data ) { ); } else { if ( $compatible_php ) { + $wp_autoupdated_plugins = get_option( 'wp_autoupdated_plugins', array() ); /* JBA */ + $autoupdate = ''; + if ( in_array( $plugin_data['plugin'], $wp_autoupdated_plugins, true ) ) { + $next_update_time = wp_next_scheduled( 'wp_version_check' ); + $time_to_next_update = human_time_diff( intval( $next_update_time ) ); + $autoupdate = ' '; + $autoupdate .= sprintf( + /* translators: Time until the next update. */ + __( 'Automatic update scheduled in %s.' ), + $time_to_next_update + ); + $autoupdate .= ' '; + } printf( - /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes. */ - __( 'There is a new version of %1$s available. View version %4$s details or update now.' ), + /* translators: 1: Plugin name, 2: Details URL, 3: Additional link attributes, 4: Version number, 5: Update URL, 6: Additional link attributes, 7: Automatic update informations. */ + __( 'There is a new version of %1$s available. View version %4$s details or update now. %7$s' ), $plugin_name, esc_url( $details_url ), sprintf( @@ -504,7 +517,8 @@ function wp_plugin_update_row( $file, $plugin_data ) { 'class="update-link" aria-label="%s"', /* translators: %s: Plugin name. */ esc_attr( sprintf( __( 'Update %s now' ), $plugin_name ) ) - ) + ), + $autoupdate ); } else { printf( diff --git a/src/wp-admin/plugins.php b/src/wp-admin/plugins.php index acebd8e452..4aef5150eb 100644 --- a/src/wp-admin/plugins.php +++ b/src/wp-admin/plugins.php @@ -154,6 +154,81 @@ if ( $action ) { require_once( ABSPATH . 'wp-admin/admin-footer.php' ); exit; + case 'autoupdate': + if ( ! current_user_can( 'update_plugins' ) ) { + wp_die( __( 'Sorry, you are not allowed to update plugins.' ) ); + } + + if ( is_multisite() && ! is_network_admin() && is_network_only_plugin( $plugin ) ) { + wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) ); + exit; + } + + if ( empty( $plugin ) ) { + wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) ); + exit; + } + + check_admin_referer( 'autoupdate-plugin_' . $plugin ); + + $autoupdated_plugins = get_option( 'wp_autoupdated_plugins', array() ); + if ( in_array( $plugin, $autoupdated_plugins, true ) ) { + $autoupdated_plugins = array_diff( $autoupdated_plugins, array( $plugin ) ); + $action_type = 'disable-autoupdate=true'; + } else { + $autoupdated_plugins[] = $plugin; + $action_type = 'enable-autoupdate=true'; + } + update_option( 'wp_autoupdated_plugins', $autoupdated_plugins ); + + wp_redirect( self_admin_url( "plugins.php?$action_type&plugin_status=$status&paged=$page&s=$s" ) ); + + exit; + + case 'enable-autoupdate-selected': + if ( ! current_user_can( 'update_plugins' ) ) { + wp_die( __( 'Sorry, you are not allowed to enable plugin automatic updates.' ) ); + } + + check_admin_referer( 'bulk-plugins' ); + + $plugins = isset( $_POST['checked'] ) ? (array) wp_unslash( $_POST['checked'] ) : array(); + + if ( empty( $plugins ) ) { + wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) ); + exit; + } + + $previous_autoupdated_plugins = get_option( 'wp_autoupdated_plugins', array() ); + $new_autoupdated_plugins = array_merge( $previous_autoupdated_plugins, $plugins ); + $new_autoupdated_plugins = array_unique( $new_autoupdated_plugins ); + update_option( 'wp_autoupdated_plugins', $new_autoupdated_plugins ); + + wp_redirect( self_admin_url( "plugins.php?enable-autoupdate=true&plugin_status=$status&paged=$page&s=$s" ) ); + exit; + + case 'disable-autoupdate-selected': + if ( ! current_user_can( 'update_plugins' ) ) { + wp_die( __( 'Sorry, you are not allowed to disable plugin automatic updates.' ) ); + } + + check_admin_referer( 'bulk-plugins' ); + + $plugins = isset( $_POST['checked'] ) ? (array) wp_unslash( $_POST['checked'] ) : array(); + + if ( empty( $plugins ) ) { + wp_redirect( self_admin_url( "plugins.php?plugin_status=$status&paged=$page&s=$s" ) ); + exit; + } + + $previous_autoupdated_plugins = get_option( 'wp_autoupdated_plugins', array() ); + $new_autoupdated_plugins = array_diff( $previous_autoupdated_plugins, $plugins ); + $new_autoupdated_plugins = array_unique( $new_autoupdated_plugins ); + update_option( 'wp_autoupdated_plugins', $new_autoupdated_plugins ); + + wp_redirect( self_admin_url( "plugins.php?disable-autoupdate=true&plugin_status=$status&paged=$page&s=$s" ) ); + exit; + case 'error_scrape': if ( ! current_user_can( 'activate_plugin', $plugin ) ) { wp_die( __( 'Sorry, you are not allowed to activate this plugin.' ) ); @@ -578,6 +653,10 @@ elseif ( isset( $_GET['deleted'] ) ) :