> For the complete documentation index, see [llms.txt](https://docs.norrnext.com/norrcompetition/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.norrnext.com/norrcompetition/customisation/events/other.md).

# Other

These events cover cross-cutting concerns including Open Graph meta tags, permission overrides, OTP verification delivery channels, photo upload moderation, remote storage integrations, and user points gates.

***

### `onOpenGraphPrepare`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\View\OpenGraphPrepareEvent`
* **Contexts:** `com_competition.competition`, `com_competition.participant`, `com_competition.category`
* **Triggered In:** Frontend Views (`site/src/View/*`)

#### Description

Fired before rendering Open Graph meta tags (`og:title`, `og:description`, `og:image`, `twitter:card`), allowing plugins to modify metadata attributes.

```php
use NorrNext\Component\Competition\Administrator\Event\View\OpenGraphPrepareEvent;

public function onOpenGraphPrepare(OpenGraphPrepareEvent $event): void
{
    $context  = $event->getContext();
    $item     = $event->getItem();     // Read-only clone of contest/entry
    $ogObject = $event->getOgObject(); // Open Graph data object
    $options  = $event->getOptions();  // Options array (e.g. twitter_card)

    $ogObject->title = $item->title . ' - Custom Contest Brand';
    $options['twitter_card'] = 'summary_large_image';

    $event->setArgument('options', $options);
}
```

***

### `onUserAuthorise`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\Permission\UserAuthoriseEvent`
* **Triggered In:** Core permission checks throughout the component

#### Description

Allows plugins to override a denied ACL permission check (`User::authorise()`). Returning `true` grants the permission (e.g., granting `core.vote` or `core.unvote` to non-standard user roles).

```php
use NorrNext\Component\Competition\Administrator\Event\Permission\UserAuthoriseEvent;

public function onUserAuthorise(UserAuthoriseEvent $event): bool
{
    $user      = $event->getUser();      // Joomla User object
    $action    = $event->getAction();    // e.g. 'core.vote'
    $assetname = $event->getAssetname(); // e.g. 'com_competition.competition.5'

    // Return true to grant access even if Joomla ACL returned false
    if ($action === 'core.vote' && $user->id > 0) {
        return true;
    }

    return false;
}
```

***

### `onTokenChannels`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\Token\TokenChannelsEvent`
* **Context:** `com_competition.token`
* **Triggered In:** `VoteTokenWorkflow::getAvailableChannels()`

#### Description

Allows plugins to register custom OTP verification delivery channels (such as SMS, WhatsApp, Telegram, or custom webhook).

```php
use NorrNext\Component\Competition\Administrator\Event\Token\TokenChannelsEvent;

public function onTokenChannels(TokenChannelsEvent $event): void
{
    $channels = $event->getChannels();
    $channels['telegram'] = 'Telegram Bot';

    $event->setArgument('channels', $channels);
}
```

***

### `onTokenSend`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\Token\TokenSendEvent`
* **Context:** `com_competition.token`
* **Triggered In:** `VoteTokenWorkflow::sendToken()`

#### Description

Dispatches the generated one-time verification code to the voter via the specified channel.

```php
use NorrNext\Component\Competition\Administrator\Event\Token\TokenSendEvent;

public function onTokenSend(TokenSendEvent $event): void
{
    $channel   = $event->getChannel();
    $recipient = $event->getRecipient();
    $code      = $event->getCode();

    if ($channel === 'telegram') {
        // Send OTP verification code via Telegram Bot API
    }
}
```

***

### `onBeforeImageUpload`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\Photo\BeforeImageUploadEvent`
* **Triggered In:** Photo upload controllers during AJAX / form upload

#### Description

Fired before an uploaded image file is committed to disk. Used by moderation plugins (e.g. AI content moderation via Sightengine) to inspect image streams and reject inappropriate content.

```php
use NorrNext\Component\Competition\Administrator\Event\Photo\BeforeImageUploadEvent;

public function onBeforeImageUpload(BeforeImageUploadEvent $event): void
{
    $image = $event->getImage(); // Uploaded file array ($_FILES structure)

    // Inspect or moderate image
    // $event->addResult(['status' => 'rejected', 'message' => 'Image does not comply with contest rules.']);
}
```

***

### `onRemoteStorageGetEndpoint`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\RemoteStorage\GetEndpointEvent`
* **Triggered In:** Remote storage adapter resolution

#### Description

Returns the public endpoint URL for media assets hosted on cloud object storage (e.g., AWS S3 / Flysystem CDN endpoints).

***

### `onRemoteStorageGetFieldOption`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\RemoteStorage\GetFieldOptionEvent`
* **Triggered In:** Remote Storage form field options (`RemoteStorageField::getOptions()`)

#### Description

Allows storage plugins to register their adapter names into the component configuration dropdowns.

***

### `onBeforePhotoSave`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\Photo\BeforePhotoSaveEvent`
* **Triggered In:** `ParticipantModel::savePhoto()` and gallery handling

#### Description

Fired before photos or photo galleries are persisted to an entry.

```php
use NorrNext\Component\Competition\Administrator\Event\Photo\BeforePhotoSaveEvent;

public function onBeforePhotoSave(BeforePhotoSaveEvent $event): void
{
    $context   = $event->getContext();
    $photos    = $event->getPhotos();
    $contestId = $event->getContestId();
    $entryId   = $event->getEntryId();
    $formData  = $event->getData();
}
```

***

### `onItemBeforeSetQuery` & `onListBeforeSetQuery`

* **Event Classes:**
  * Single item: `\NorrNext\Component\Competition\Administrator\Event\Query\ItemBeforeSetQueryEvent`
  * List query: `\NorrNext\Component\Competition\Administrator\Event\Query\ListBeforeSetQueryEvent`
* **Triggered In:** Models before compiling and executing database select queries

#### Description

Allows plugins to modify database query objects (`\Joomla\Database\QueryInterface`) directly — adding custom JOINs, WHERE clauses, or custom sorting parameters.

```php
use NorrNext\Component\Competition\Administrator\Event\Query\ListBeforeSetQueryEvent;

public function onListBeforeSetQuery(ListBeforeSetQueryEvent $event): void
{
    $context = $event->getContext(); // e.g. 'com_competition.competition'
    $query   = $event->getQuery();   // Database QueryInterface object

    // Append custom conditions
    // $query->where('a.featured = 1');
}
```

***

### `onAppformBeforeGate` & `onVoteBeforeGate`

* **Event Classes:**
  * Entry submission: `\NorrNext\Component\Competition\Administrator\Event\Points\BeforeAppformSaveGateEvent`
  * Voting: `\NorrNext\Component\Competition\Administrator\Event\Points\BeforeVoteGateEvent`
* **Triggered In:** `AppformController::save()` and `VoteModel::vote()`

#### Description

Fired when user points integration is enabled for a contest. Plugins verify if the user possesses sufficient points balance to submit an entry or cast a vote, and can deny the action with a custom message (`$event->setDenied(true, 'Insufficient points')`).

```php
use NorrNext\Component\Competition\Administrator\Event\Points\BeforeVoteGateEvent;

public function onVoteBeforeGate(BeforeVoteGateEvent $event): void
{
    $contestId = $event->getCompetitionId();
    $userId    = $event->getUserId();

    // Check user points balance and deny if insufficient
    // $event->setDenied(true, 'You need 10 points to vote in this contest.');
}
```

***

### `onAfterPointsChange`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\Points\AfterPointsChangeEvent`
* **Triggered In:** `Points::change()` service

#### Description

Fired whenever user points are awarded or deducted as a result of contest participation or voting actions.

***

### `onNotificationSend`

* **Event Class:** `\NorrNext\Component\Competition\Administrator\Event\Notification\NotificationSendEvent`
* **Triggered In:** `Notification::send()` service

#### Description

Dispatches non-email notifications (such as SMS, Push, Telegram) for contest lifecycle events.

```php
use NorrNext\Component\Competition\Administrator\Event\Notification\NotificationSendEvent;

public function onNotificationSend(NotificationSendEvent $event): void
{
    $channel   = $event->getChannel();
    $recipient = $event->getRecipient();
    $template  = $event->getTemplate();
    $data      = $event->getData();

    if ($channel === 'sms') {
        // Send SMS message and update delivery status
        $event->setArgument('delivery_status', 'sent');
    }
}
```
