2

Is it possible with the Webhooks plugin to trigger a POST request anytime Craft has updates available? I thought the Updates Class would be the place to start but that does not appear to be correct.

Any insight into this is appreciated.

2
  • 1
    Do you need this information inside Craft, or is Craft just acting as a proxy for the information? Packagist provides RSS feeds for packages (i.e. https://packagist.org/feeds/package.craftcms/cms.rss), so this might be significantly easier with a service like IFTTT. 😉 Mar 22 at 18:10
  • @AugustMiller Thanks much for the very useful info, def wasn't aware this.
    – vanburen
    Mar 24 at 7:49

1 Answer 1

4
+50

As far as I can tell by looking at the source code and searching the Events reference, Craft doesn't dispatch any relevant events that could be used to make the Webhooks plugin trigger a POST request if/when there are updates available.

You could submit a feature request for P&T to add such an event.

In lieu of a core event, it's probably possible to hack this in yourself by creating a custom module. The module will have to check if there are updates available, and trigger a custom event if there are. You could then listen for that custom event the Webhooks plugin, same as you would a core event.

Since you can't really hook into the core updates logic and only fire it at the exact time Craft detects available updates, you'll probably need to add this logic so that it runs on every request, while avoiding that your custom event (and in turn, the webhook) fires on every request as well, in the case that there are updates available. A decent workaround to that problem is using the data cache to essentially cache the output from Craft::$app->getUpdates()->getTotalAvailableUpdates(), and only trigger the event whenever that cache doesn't exist or is expired.

Building off of the custom module example in the docs, here's how a hack like that could look:

use craft\helpers\ConfigHelper;
use craft\services\Plugins;
use yii\base\Event;

public function init()
{
    // To avoid the custom event being triggered too soon, wrap everything in a Plugins::EVENT_AFTER_LOAD_PLUGINS event listener 
    Event::on(
        Plugins::class,
        Plugins::EVENT_AFTER_LOAD_PLUGINS,
        [$this, 'doUpdateCheck']
    );
}

// Note the use of Craft::$app->getCache()->getOrSet to avoid this logic being executed on every request
public function doUpdateCheck()
{
    
    Craft::$app->getCache()->getOrSet('available_updates', function () {

        if (!Craft::$app->getUpdates()->getIsUpdateInfoCached()) {
            // Craft hasn't cached any update info yet; return false to not cache the output (which will make the check run again on the next request)
            return false;
        }
    
        // Get the total number of available updates
        $numUpdates = Craft::$app->getUpdates()->getTotalAvailableUpdates();  
    
        if ($numUpdates) {
            // There are updates available; trigger a custom "updatesAreAvailable" event
            $this->trigger('updatesAreAvailable');
        }

        // Return the number of available updates so it can be cached
        return $numUpdates;

    }, ConfigHelper::durationInSeconds('P1D')); // Only do this once a day!
}

For the Webhooks part, with the above you should be able to use the custom event event to trigger the POST request by adding your module's class (i.e. something like modules\foobar\Module) for the "Sender class setting, and updatesAreAvailable for the "Event name".

The example caches the output from the doUpdateCheck() method for a day, but you can of course use a different cache duration ('PT1H' to cache it for an hour, for example). This will prevent the event from triggering on every single event, but obviously since this just uses the data cache, the callable will run whenever the entire data cache is cleared (some people like to do this in their deploy scripts). In other words, the event could fire more often than the cache duration set, and the logic on the other end of the webhook should probably account for that.

1
  • 1
    Thanks for this answer and I very much appreciate the time you took for this.
    – vanburen
    Mar 24 at 7:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.