diff --git a/includes/class-updater.php b/includes/class-updater.php index e6cd9ca..7b908f4 100644 --- a/includes/class-updater.php +++ b/includes/class-updater.php @@ -146,10 +146,42 @@ class WC_EDM_Updater { return $update; } + // Shared by both branches on purpose. When these were two separate + // literals the no-release branch was simply missing them, and the + // symptom is the grey default plug on Dashboard -> Updates for as long + // as the feed stays down. + // + // Served from the shop's own copy of the plugin rather than from the + // release host: one fewer thing that has to be up and reachable for + // wp-admin to render correctly, it cannot go mixed content on an HTTPS + // shop, and the icon is in the zip anyway. + $icons = array( + 'svg' => WC_EDM_PLUGIN_URL . 'assets/icon.svg', + 'default' => WC_EDM_PLUGIN_URL . 'assets/icon.svg', + ); + $release = $this->latest_release(); + // 🔴 Answer with the INSTALLED version rather than returning $update + // untouched. A plugin that answers neither way is in neither the + // `response` nor the `no_update` list, and WP_Plugins_List_Table builds + // the per-plugin "Enable auto-updates" link from that transient — so + // the row reads "Auto-updates are not available for this plugin", + // which reads as a setting rather than as a failed HTTP request. The + // shop then quietly stops being offered fixes, and nothing says so. + // + // The version is true and comparable, so WordPress files it under + // no_update and the row behaves normally until the feed answers again. if ( ! $release ) { - return $update; + return array( + 'slug' => dirname( plugin_basename( WC_EDM_PLUGIN_FILE ) ), + 'version' => isset( $plugin_data['Version'] ) ? $plugin_data['Version'] : WC_EDM_VERSION, + 'package' => '', + 'url' => self::update_uri(), + 'requires' => isset( $plugin_data['RequiresWP'] ) ? $plugin_data['RequiresWP'] : '', + 'requires_php' => isset( $plugin_data['RequiresPHP'] ) ? $plugin_data['RequiresPHP'] : '', + 'icons' => $icons, + ); } return array( @@ -163,15 +195,7 @@ class WC_EDM_Updater { // Without this, Dashboard → Updates shows the generic grey plug // next to the plugin. WordPress takes the first of svg, 2x, 1x, // default that is set. - // - // Served from the shop's own copy of the plugin rather than from - // the release host: it is one fewer thing that has to be up and - // reachable for wp-admin to render correctly, it cannot go mixed - // content on an HTTPS shop, and the icon is in the zip anyway. - 'icons' => array( - 'svg' => WC_EDM_PLUGIN_URL . 'assets/icon.svg', - 'default' => WC_EDM_PLUGIN_URL . 'assets/icon.svg', - ), + 'icons' => $icons, ); } diff --git a/tests/smoke.php b/tests/smoke.php index 05d18bb..77edebd 100644 --- a/tests/smoke.php +++ b/tests/smoke.php @@ -359,6 +359,26 @@ set_transient( $offered = wc_edm()->updater->offer_update( false, get_plugin_data( WC_EDM_PLUGIN_FILE, false, false ), plugin_basename( WC_EDM_PLUGIN_FILE ) ); wc_edm_is( 'the current version is answered too, not passed over', WC_EDM_VERSION, is_array( $offered ) ? $offered['version'] : null ); +// And the case neither assertion above covers: the feed could not be reached. +// Returning $update untouched there drops the plugin out of BOTH the response +// and no_update lists, and WP_Plugins_List_Table builds the per-plugin "Enable +// auto-updates" link from that transient — so the row reads "Auto-updates are +// not available for this plugin", which looks like a setting rather than a +// failed HTTP request. The shop then silently stops being offered fixes. +set_transient( WC_EDM_Updater::TRANSIENT, 'none', 60 ); +$offered = wc_edm()->updater->offer_update( false, get_plugin_data( WC_EDM_PLUGIN_FILE, false, false ), plugin_basename( WC_EDM_PLUGIN_FILE ) ); +wc_edm_is( + 'an unreachable feed still answers with the installed version', + WC_EDM_VERSION, + is_array( $offered ) ? $offered['version'] : null +); +wc_edm_ok( + 'and that answer still carries the icon', + is_array( $offered ) && ! empty( $offered['icons'] ), + 'without icons in this branch Dashboard -> Updates shows the grey default plug until the feed answers again' +); +delete_transient( WC_EDM_Updater::TRANSIENT ); + // 🔴 The filter name is built from the HOSTNAME, not the repository. Every // plugin updating from gitea.nolimit.dk shares the hook // update_plugins_gitea.nolimit.dk, and WordPress runs every callback on it for