JReviews logo Docs
Menu
Version

paidlistings:listing_entitlements_changed

Fires after the effective paid entitlements for a listing change. The event contains the final settled snapshot and a machine-readable reason. Use it to update an external system or invoke the generic source-to-target synchronization API.

Action
PaidListings

Start here

Copy the boilerplate below, then add the logic you need. Actions receive the values listed below and do not return a value. New to hooks? Read the hooks primer first.

Synchronous best-effort notification after the JReviews 6 Early Access entitlement pipeline settles. Consumers that require certainty should reconcile from the current snapshot.

Parameters

Name Type Description
$event \JReviews\Addons\PaidListings\App\Events\ListingEntitlementsChanged The immutable entitlement change event. Action callbacks must return void.

Boilerplate

Paste this into your hook file, then add your logic or echo output.

fwd_add_action('paidlistings:listing_entitlements_changed', function($event)
{
    // Execute action or echo output
});
Why the final numbers matter: , 20, N sets the priority and how many arguments your callback accepts. If you use both $filterResult and $listing, keep , 20, 2 so both are passed to your callback.

Examples

Record the final PaidListings entitlement state

Add this to templates/jreviews_overrides/hooks.php on Joomla or jreviews_overrides/hooks.php on WordPress. It receives the immutable final snapshot after a paid entitlement changes and writes an allowlisted audit record. The callback deliberately returns void. Delivery is synchronous and best-effort, so an integration that requires certainty should periodically resolve the current snapshot too.

<?php
defined('MVC_FRAMEWORK') or die;

use JReviews\Addons\PaidListings\App\Events\ListingEntitlementsChanged;
use JReviews\App\Services\JReviewsLog;

\FWDHook::addAction(
    'paidlistings:listing_entitlements_changed',
    function (ListingEntitlementsChanged $event): void {
        JReviewsLog::log('info', 'PaidListings entitlements settled', [
            'event_id' => $event->eventId,
            'listing_id' => $event->listingId,
            'reason' => $event->reason,
            'entitlement_fingerprint' => $event->entitlements->entitlementFingerprint,
            'base_plan_ids' => array_map(
                fn ($assignment) => $assignment->planId,
                $event->entitlements->baseAssignments,
            ),
            'upgrade_plan_ids' => array_map(
                fn ($assignment) => $assignment->planId,
                $event->entitlements->upgradeAssignments,
            ),
        ], 'integrations', 'paidlistings');
    },
    20,
    1,
);

Synchronize an English listing to its Joomla language associations

Joomla-only example for sites that treat the English article as authoritative. Product code does not know about language associations: this override discovers the associated Joomla articles, chooses the direction, prevents reverse loops, and calls the generic PaidListings API. Assign the same PaidListings plans to each translated category, or fill in the plan map when translated categories use different plan IDs.

<?php
defined('MVC_FRAMEWORK') or die;

use FWD\Illuminate\Support\Facades\DB;
use Joomla\CMS\Language\Associations;
use JReviews\Addons\PaidListings\App\Actions\SyncListingEntitlementsAction;
use JReviews\Addons\PaidListings\App\Enums\EntitlementChangeReason;
use JReviews\Addons\PaidListings\App\Enums\EntitlementSyncPolicy;
use JReviews\Addons\PaidListings\App\Events\ListingEntitlementsChanged;

\FWDHook::addAction(
    'paidlistings:listing_entitlements_changed',
    function (ListingEntitlementsChanged $event): void {
        if (! jr_joomla() || $event->reason === EntitlementChangeReason::Synchronized) {
            return;
        }

        // This site chooses English as the only authoritative direction.
        $language = DB::table('content')
            ->where('id', $event->listingId)
            ->value('language');

        if ($language !== 'en-GB') {
            return;
        }

        $associations = Associations::getAssociations(
            'com_content',
            '#__content',
            'com_content.item',
            $event->listingId,
            'id',
            'alias',
            'catid',
        );

        // Leave empty when both language categories use the same plan IDs.
        $planMap = [
            // 12 => 34, // English plan 12 maps to Greek plan 34.
        ];

        foreach ($associations as $association) {
            $targetListingId = (int) ($association->id ?? 0);

            if ($targetListingId <= 0 || $targetListingId === $event->listingId) {
                continue;
            }

            SyncListingEntitlementsAction::run(
                sourceListingId: $event->listingId,
                targetListingId: $targetListingId,
                policy: EntitlementSyncPolicy::ReplaceTargetEntitlements,
                planMap: $planMap,
            );
        }
    },
    20,
    1,
);

Register a typed Laravel event listener

Use this complete config/events.php file when a class-based listener is preferable to FWDHook. On Joomla the path is templates/jreviews_overrides/config/events.php; on WordPress it is jreviews_overrides/config/events.php. The listener is declared in the same file, so no service provider or manual include is required.

<?php

namespace JReviewsOverrides\Integrations;

defined('MVC_FRAMEWORK') or die;

use JReviews\Addons\PaidListings\App\Events\ListingEntitlementsChanged;
use JReviews\App\Services\JReviewsLog;

final class RecordPaidListingEntitlements
{
    public function handle(ListingEntitlementsChanged $event): void
    {
        JReviewsLog::log('info', 'PaidListings entitlements settled', [
            'event_id' => $event->eventId,
            'listing_id' => $event->listingId,
            'reason' => $event->reason,
            'entitlement_fingerprint' => $event->entitlements->entitlementFingerprint,
        ], 'integrations', 'paidlistings');
    }
}

return [
    ListingEntitlementsChanged::class => [
        RecordPaidListingEntitlements::class,
    ],
];
Development & Support
Hooks are for custom development and are not included with support. Use the examples as a starting point and test changes on a staging site first.

Source Files

  • app/Actions/DispatchListingEntitlementsChangedAction.php