XF 2.3 Custom webhook events

QuackieMackie

Active member
I'm looking to set up my own events that could trigger a webhook, is this possible and if so is anyone able to point me in the right direction for setting this up?
 
Solution
Okay so I did a bit of digging and figured it out! :D
So like always i'm going to explain the process here and then write it up for docs when I have a chance.

First off, we've gotta set some bits up.

In the admin control panel under Development -> Content Type I added these values:
1758326046623.webp
What these do are:
  • entity: adds entity definition for content type
  • webhook_handler_class: Register addon_log content type for webhooks
  • phrase_plural: adds a phrase to be used in the webhooks options

I started off by creating a handler:
PHP:
<?php

namespace Sylphian\Library\Webhook\Event;

use XF\Webhook\Event\AbstractHandler;

class AddonLogHandler extends AbstractHandler
{
    /**
     * Define the available events for...
Okay so I did a bit of digging and figured it out! :D
So like always i'm going to explain the process here and then write it up for docs when I have a chance.

First off, we've gotta set some bits up.

In the admin control panel under Development -> Content Type I added these values:
1758326046623.webp
What these do are:
  • entity: adds entity definition for content type
  • webhook_handler_class: Register addon_log content type for webhooks
  • phrase_plural: adds a phrase to be used in the webhooks options

I started off by creating a handler:
PHP:
<?php

namespace Sylphian\Library\Webhook\Event;

use XF\Webhook\Event\AbstractHandler;

class AddonLogHandler extends AbstractHandler
{
    /**
     * Define the available events for addon logs
     *
     * @return array
     */
    public function getEvents(): array
    {
        return [
            'debug',
            'info',
            'notice',
            'warning',
            'error',
            'critical',
            'alert',
            'emergency',
        ];
    }

    /**
     * Provide a hint for each event
     *
     * @param string $event
     * @return string
     */
    public function getEventHint(string $event): string
    {
        return match ($event)
        {
            'debug' => 'When a debug level log is created',
            'info' => 'When an info level log is created',
            'notice' => 'When a notice level log is created',
            'warning' => 'When a warning level log is created',
            'error' => 'When an error level log is created',
            'critical' => 'When a critical level log is created',
            'alert' => 'When an alert level log is created',
            'emergency' => 'When an emergency level log is created',
            default => '',
        };
    }

    /**
     * Get relations to include with the entity when sending webhooks
     *
     * @return array
     */
    public function getEntityWith(): array
    {
        return ['AddOn'];
    }
}
This tells the content type what types of events might occur.
It also tells the webhook what other entites it needs to include. In this case I pass along the XF\Entity\AddOn entity so I can see some details of the addon the log is occuring in.

Next I modify my entity getStructure to include:
PHP:
$structure->behaviors['XF:Webhook'] = ['enabled' => true];
$structure->contentType = 'syl_library_addon_log';

This tells the entity when x events occur, check for webhook events, under the content type syl_library_addon_log

I then add this method:
PHP:
    /**
     * Define how entity data is structured for API and webhook results
     *
     * @param EntityResult $result
     * @param int $verbosity
     * @param array $options
     */
    protected function setupApiResultData(
        EntityResult $result,
        $verbosity = self::VERBOSITY_NORMAL,
        array $options = []
    ): void
    {
        $result->includeColumn(['log_id', 'type', 'content', 'details']);

        $addonInfo = null;
        if ($this->AddOn)
        {
            $addonInfo = [
                'addon_id' => $this->AddOn->addon_id,
                'title' => $this->AddOn->title,
                'version_string' => $this->AddOn->version_string,
            ];
        }

        $result->includeExtra([
            'date_formatted' => $this->app()->language()->dateTime($this->date),
            'addon_info' => $addonInfo,
            'view_url' => $this->log_id
                ? $this->app()->router()->buildLink('admin/logs/addon_logs/details', ['log_id' => $this->log_id])
                : null,
        ]);
    }

This structures the data from the AddonLog entity and the AddOn entity into this format:
JSON:
{
  "content_type": "syl_library_addon_log",
  "event": "emergency",
  "content_id": 831,
  "data": {
    "addon_info": {
      "addon_id": "Sylphian/Map",
      "title": "Sylphian - Map",
      "version_string": "1.0.8"
    },
    "content": "Map page accessed",
    "date_formatted": "Sep 20, 2025 at 12:07 AM",
    "details": null,
    "log_id": 831,
    "type": "emergency",
    "view_url": "/index.php?admin/logs/addon_logs/details"
  }
}

To see the full source check out:
 
Last edited:
Solution
Back
Top Bottom