YahnisElsts / plugin-update-checker

A custom update checker for WordPress plugins. Useful if you don't want to host your project in the official WP repository, but would still like it to support automatic updates. Despite the name, it also works with themes.
MIT License
2.21k stars 403 forks source link

[Feature] Check for updates if WP-CLI checks for updates #558

Closed hirasso closed 6 months ago

hirasso commented 7 months ago

Hi there!

The Problem

The WP-CLI command wp plugin ... has a few commands where they automatically check for plugin updates, for example:

I just noticed that Plugin Update Checker doesn't check for updates if these commands are being executed.

Proposed Solution

Both these commands call wp_update_plugins directly if being executed.

Would it be possible to automatically check for updates in Plugin Update Checker as well, if one of those commands is being executed? I just checked and it seems like in wp_update_plugins there is no action being triggered. So it might be hard to achieve updates based on only that function.

Alternatives considered

Implement a custom wp cli command in userland, something like this:

$bb_checker = PucFactory::buildUpdateChecker(
  "https://bitbucket.org/user/$plugin_slug", // Metadata URL.
  $file_path, // Full path to the main plugin file.
  $plugin_slug, // Plugin slug. Usually it's the same as the name of the directory.
  24*7 // <-- update interval in hours
);

if (defined('WP_CLI') && WP_CLI) {
  \WP_CLI::add_command('bb-updater check', function() use ($bb_updater) {
    $bb_updater->checkForUpdates();
  });
}

That works, but it would be amazing to get this out of the box.

YahnisElsts commented 7 months ago

wp_update_plugins modifies the update_plugins transient, which triggers filters that could be used to hook into the function (e.g. pre_set_site_transient_{$transient}. However, that transient is also used in other places (in Cron, and potentially on every admin page load), so, for better performance, I would want a way to check if the filter is being called inside WP-CLI, preferably even a way to identify the current WP-CLI command.

I believe the first part can be covered by checking if the WP_CLI constant is defined, but I'm not sure about identifying the running command. Do you happen to know how to do that?

hirasso commented 7 months ago

@YahnisElsts thanks for getting back to me! I asked in the cli slack channel and got the following answer for how to get information about the current WP-CLI command:

For the current command, try:

$args = WP_CLI::get_runner()->arguments;

print_r( $args );

For wp cron event run wp_version_check, the output should be:

Array
(
   [0] => cron
   [1] => event
   [2] => run
   [3] => wp_version_check
)

Based on that, I played around a bit:

/**
 * Check for WP-CLI commands running wp_update_plugins
 */
function isWpCliUpdateCheck(): bool
{
  if (!defined('WP_CLI') || !WP_CLI) return false;

  // get the args of the current command
  $args = \WP_CLI::get_runner()->arguments;

  // convert the args array back to the command string
  $command = implode(' ', $args);

  // check for wp-cli commands that are known to trigger a check for plugin updates
  return match ($command) {
    'plugin list' => true,
    'plugin status' => true,
    'cron event run wp_version_check' => true,
    // 'foo bar' => true, ???
    default => false
  };
}

if (isWpCliUpdateCheck()) {
  // ... run the update checker
}

While this technically works, it will be a pain to maintain. These commands could change at any time, not even mentioning theme updates...

So I think we should continue to look for a reliably way to detect wp_update_plugins.

hirasso commented 7 months ago

Actually, re-reading your comment:

wp_update_plugins modifies the update_plugins transient, which triggers filters that could be used to hook into the function (e.g. pre_set_site_transient_{$transient})

Maybe we could get away with combining the two?

  1. hook into the appropriate filter
  2. check if currently running a WP_CLI command starting with "plugin"
  3. run the update checker
YahnisElsts commented 7 months ago

It looks like WP-CLI provides a before_invoke:<command> hook that can be used to detect when certain (sub-)commands run more directly. I've written a basic implementation that hooks into the relevant plugin and theme commands. For consistency with wp_update_plugins(), this implementation doesn't check for updates every time but just triggers the normal scheduled update check logic.

This could use more testing - give it a try.

hirasso commented 6 months ago

Works like a charm! I tested it with two plugins – one managed by WordPress (relevanssi), one managed by plugin update checker (rh-admin-utils). Here is the relevant command output: Before updating puc, rh-admin-utils didn't detect that there was a new version available, after updating puc it detected the new version:

Before

❯ wp plugin list
+---------------------------------------+--------+-----------+------------+
| name                                  | status | update    | version    |
+---------------------------------------+--------+-----------+------------+
| relevanssi                            | active | available | 4.22.0     |
| rh-admin-utils                        | active | none      | 1.9.4      |
+---------------------------------------+--------+-----------+------------+

After

❯ wp plugin list
+---------------------------------------+--------+-----------+------------+
| name                                  | status | update    | version    |
+---------------------------------------+--------+-----------+------------+
| relevanssi                            | active | available | 4.22.0     |
| rh-admin-utils                        | active | available | 1.9.4      |
+---------------------------------------+--------+-----------+------------+

Also, sorry for keeping you waiting for so long... your help means a lot!

YahnisElsts commented 6 months ago

Sounds good. I've made a new release (5.4) that includes this feature, so I'll close the issue now.