Skip to content

Commit

Permalink
Merge pull request #33 from a8cteam51/issue_32
Browse files Browse the repository at this point in the history
Apply delay to autoupdates
  • Loading branch information
NickGreen authored May 22, 2024
2 parents 48fe7e8 + cf82175 commit 1ed9928
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 3 deletions.
35 changes: 33 additions & 2 deletions class-plugin-autoupdate-filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
exit; // Exit if accessed directly
}

require_once 'includes/class-plugin-autoupdate-filter-helpers.php';

class Plugin_Autoupdate_Filter {

/**
Expand Down Expand Up @@ -37,6 +39,9 @@ function() use ( $error_message ) {
add_filter( 'auto_update_plugin', array( $this, 'filter_auto_update_specific_times' ), 10, 2 );
add_filter( 'auto_update_core', array( $this, 'filter_auto_update_specific_times' ), 10, 2 );

// enforce a delay on all plugin autoupdates, based on release date
add_filter( 'auto_update_plugin', array( $this, 'filter_enforce_delay' ), 11, 2 );

// Replace automatic update wording on plugin management page in admin
add_filter( 'plugin_auto_update_setting_html', array( $this, 'filter_custom_setting_html' ), 11, 3 );

Expand Down Expand Up @@ -126,15 +131,41 @@ public function filter_maybe_disable_all_autoupdates( $update, $item ): bool {
}

/**
* Enable or disable plugin auto-updates based on time and day of the week.
* Disable plugin auto-updates based on if a delay has passed since plugin was released.
*
* @param bool $update Whether to update the plugin or not.
* @param object $item The plugin update object.
*
* @return bool True to update, false to not update.
*/
public function filter_auto_update_specific_times( $update, $item ): bool {
public function filter_enforce_delay( $update, $item ): bool {
// no delay if site is a canary site
$site_url = wp_parse_url( home_url(), PHP_URL_HOST );
if ( isset( $this->settings->canary_sites ) && in_array( $site_url, $this->settings->canary_sites, true ) ) {
return $update;
}

// otherwise add delay to plugin updates
if ( true === $update ) {
$helpers = new Plugin_Autoupdate_Filter_Helpers();
$has_delay_passed = $helpers->has_delay_passed( $item->slug, $item->new_version );

if ( false === $has_delay_passed ) {
return false;
}
}
return $update;
}

/**
* Disable auto-updates based on time and day of the week.
*
* @param bool $update Whether to update the plugin or not.
* @param object $item The plugin update object.
*
* @return bool True to update, false to not update.
*/
public function filter_auto_update_specific_times( $update, $item ): bool {
$holidays = array(
'christmas' => array(
'start' => gmdate( 'Y' ) . '-12-23 00:00:00',
Expand Down
139 changes: 139 additions & 0 deletions includes/class-plugin-autoupdate-filter-helpers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php
/**
* Plugin Autoupdate Filter Helpers class
*
* @package Plugin_Autoupdate_Filter
*/

if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}

class Plugin_Autoupdate_Filter_Helpers {

/**
* Determines whether a plugin should be updated based on release version and delay rules.
*
* @param string $plugin_slug Slug of the plugin.
* @param string $update_version The version that the plugin would be updated to.
*
* @return bool True if the plugin should be updated, false otherwise.
*/
public function has_delay_passed( string $plugin_slug, string $update_version ): bool {
// delay most plugins 2 days. delay some plugins 7 days.
$longer_delay_plugins = array(
'woocommerce',
'woocommerce-payments',
);

$delay_days = in_array( $plugin_slug, $longer_delay_plugins, true ) ? 7 : 2;
$installed_version = $this->get_installed_plugin_version( $plugin_slug );

if ( empty( $installed_version ) || $update_version === $installed_version ) {
return false;
}

$installed_version_parts = explode( '.', $installed_version );
$update_version_parts = explode( '.', $update_version );

// only apply delays to major and minor releases. let point releases (patches) go through.
if ( $installed_version_parts[0] !== $update_version_parts[0] || $installed_version_parts[1] !== $update_version_parts[1] ) {
$update_allowed_after = $this->get_delay_date( $plugin_slug, $update_version, $delay_days );

if ( time() >= $update_allowed_after ) {
$this->clear_plugin_delay( $plugin_slug );
return true;
}

return false;
}

return true;
}

/**
* Retrieve the current version of an installed plugin.
*
* @param string $plugin_slug Slug of the plugin.
*
* @return string Current version of the plugin or an empty string if not found.
*/
public function get_installed_plugin_version( string $plugin_slug ): string {
if ( ! function_exists( 'get_plugins' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

$plugins = get_plugins();
foreach ( $plugins as $plugin_path => $plugin_info ) {
if ( dirname( $plugin_path ) === $plugin_slug ) {
return $plugin_info['Version'];
}
}

return '';
}

/**
* Retrieve the date after which a plugin update is allowed or calculate it if not set.
*
* @param string $plugin_slug Slug of the plugin.
* @param string $update_version The version to update to.
* @param int $delay_days Number of days to delay the update.
*
* @return int The Unix timestamp indicating when the plugin can be updated.
*/
public function get_delay_date( string $plugin_slug, string $update_version, int $delay_days ): int {
$option_key = 'plugin_update_delays';
$delays = get_option( $option_key, array() );

if ( ! isset( $delays[ $plugin_slug ][ $update_version ] ) ) {
$release_date = $this->get_plugin_release_date( $plugin_slug );

if ( ! $release_date ) {
$release_date = time();
}

$delays[ $plugin_slug ][ $update_version ] = strtotime( "+{$delay_days} days", $release_date );
update_option( $option_key, $delays );
}

return $delays[ $plugin_slug ][ $update_version ];
}

/**
* Retrieve the release date of a plugin based on its slug.
*
* @param string $plugin_slug Slug of the plugin.
* @return int The Unix timestamp of the release date or the current time if not available.
*/
public function get_plugin_release_date( string $plugin_slug ): int {
$response = wp_safe_remote_get( "https://api.wordpress.org/plugins/info/1.2/?action=plugin_information&slug={$plugin_slug}" );

if ( is_wp_error( $response ) ) {
return time();
}

$plugin_info = json_decode( wp_remote_retrieve_body( $response ), true );
if ( isset( $plugin_info['last_updated'] ) ) {
return strtotime( $plugin_info['last_updated'] ) ?? time();
}

return time();
}

/**
* Clear out the entry for the plugin in the serialized array.
*
* @param string $plugin_slug Slug of the plugin.
* @return void
*/
public function clear_plugin_delay( string $plugin_slug ): void {
$option_key = 'plugin_update_delays';
$delays = get_option( $option_key, array() );

if ( isset( $delays[ $plugin_slug ] ) ) {
unset( $delays[ $plugin_slug ] );
update_option( $option_key, $delays );
}
}
}
2 changes: 1 addition & 1 deletion plugin-autoupdate-filter.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
Plugin Name: Plugin Autoupdate Filter
Plugin URI: https://github.com/a8cteam51/plugin-autoupdate-filter
Description: Filters whether autoupdates are on based on day/time and other settings.
Version: 1.5.3
Version: 1.6.0
Author: WordPress.com Special Projects
Author URI: https://wpspecialprojects.wordpress.com/
Update URI: https://github.com/a8cteam51/plugin-autoupdate-filter/
Expand Down

0 comments on commit 1ed9928

Please sign in to comment.