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.
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
});
, 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
- Synchronize an English listing to its Joomla language associations
- Register a typed Laravel event listener
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,
],
];
Source Files
app/Actions/DispatchListingEntitlementsChangedAction.php