V5 to V6 Hooks Migration
Complete migration guide for JReviews 5 hooks to their JReviews 6 equivalents.
Overview
JReviews 6 introduces a modernized hook system with a new naming convention and helper functions. This guide maps v5 hooks to their v6 equivalents with complete code examples for LLM-assisted migration.
Quick Reference
File Location Change
| Version | File Path |
|---|---|
| V5 | jreviews_overrides/filters/filter_functions.php |
| V6 | jreviews_overrides/hooks.php |
Syntax Changes
V5 Filter Registration:
Clickfwd\Hook\Filter::add('filter_name', function($data, $params) {
return $data;
}, $priority = 10);
V6 Filter Registration:
fwd_add_filter('filter_name', function($data, $params) {
return $data;
}, $priority = 20);
V5 Action Registration:
Clickfwd\Hook\Action::add('action_name', function($params) {
// Execute action
}, $priority = 10);
V6 Action Registration:
fwd_add_action('action_name', function($params) {
// Execute action
}, $priority = 20);
Naming Pattern Changes
| V5 Pattern | V6 Pattern | Example |
|---|---|---|
can_{action}_{entity} |
jreviews:permission:{entity}.{action} |
can_create_listing → jreviews:permission:listing.create |
trusted_on_{action} |
jreviews:permission:{entity}.autopublish |
trusted_on_create_listing → jreviews:permission:listing.autopublish |
{entity}_form_bottom |
jreviews:{entity}_form.bottom |
listing_form_bottom → jreviews:listing_form.bottom |
{entity}_submit_validation |
jreviews:{entity}_form.validation |
listing_submit_validation → jreviews:listing_form.validation |
before_theme_render_viewvars |
jreviews:view_data |
View data filtering |
field_output{:name} |
jreviews:custom_field.output:{:name} |
Custom field output |
| Review hooks | Comment hooks | v6 uses "comment" for user reviews |
Data Access Patterns
Listing Data: V5 vs V6
| Data | V5 (Array) | V6 (Eloquent Model) |
|---|---|---|
| Listing ID | $listing['Listing']['listing_id'] |
$listing->id |
| Title | $listing['Listing']['title'] |
$listing->title |
| URL Alias | $listing['Listing']['slug'] |
$listing->alias |
| Summary | $listing['Listing']['summary'] |
$listing->summary |
| Description | $listing['Listing']['description'] |
$listing->description |
| URL | $listing['Listing']['url'] |
$listing->url |
| Views | $listing['Listing']['hits'] |
$listing->views |
| Created | $listing['Listing']['created'] |
$listing->created |
| Modified | $listing['Listing']['modified'] |
$listing->updated |
| Category ID | $listing['Category']['cat_id'] |
$listing->cat_id |
| Category Title | $listing['Category']['title'] |
$listing->category_title |
| Directory ID | $listing['Directory']['dir_id'] |
$listing->directory->id or $listing->category->dir_id |
| Directory Title | $listing['Directory']['title'] |
$listing->directory->title |
| Listing Type ID | $listing['ListingType']['listing_type_id'] |
$listing->listing_type_id |
| Listing Type Title | $listing['ListingType']['title'] |
$listing->listing_type->title |
| Owner ID | $listing['User']['user_id'] |
$listing->owner_id |
| Owner Name | $listing['User']['name'] |
$listing->owner_name |
| Owner Email | $listing['User']['email'] |
$listing->owner_email |
| User Rating Avg | $listing['Review']['user_rating'] |
$listing->aggregates->user_rating |
| User Rating Count | $listing['Review']['user_rating_count'] |
$listing->aggregates->user_rating_count |
| Editor Rating Avg | $listing['Review']['editor_rating'] |
$listing->aggregates->editor_rating |
| Main Photo URL | $listing['MainMedia']['media_info']['image']['url'] |
$listing->mainPhoto->url |
| Cover Photo URL | $listing['CoverMedia']['media_info']['image']['url'] |
$listing->coverPhoto->url |
| Featured | $listing['Listing']['featured'] |
$listing->featured |
| Status | $listing['Listing']['state'] |
$listing->status |
| PaidListings Data | $listing['Paid'] |
$listing->paid (array with same structure) |
V6 Listing Helper Methods
// Status checks
$listing->isPublished()
$listing->isUnpublished()
$listing->isPending()
$listing->isDraft()
$listing->isTrashed()
$listing->isScheduled()
$listing->isExpired()
// Feature checks
$listing->allowsRatings()
$listing->allowsComments()
$listing->hasMainPhoto()
$listing->hasCoverPhoto()
$listing->hasLogoPhoto()
$listing->hasGalleryPhotos()
// Custom field access
$listing->getFieldValue('jr_fieldname') // Raw value
$listing->getFieldText('jr_fieldname') // Text/label for options
$listing->getField('jr_fieldname') // Field configuration
// Media access
$listing->getPhotos()
$listing->getVideos()
$listing->getAudio()
$listing->getAttachments()
Comment/Review Data: V5 vs V6
| Data | V5 (Array) | V6 (Eloquent Model) |
|---|---|---|
| Review/Comment ID | $review['Review']['review_id'] |
$comment->id |
| Title | $review['Review']['title'] |
$comment->title |
| Comment Text | $review['Review']['comments'] |
$comment->comment |
| Rating | $review['Review']['rating'] |
$comment->rating |
| Status | $review['Review']['published'] |
$comment->status |
| Created | $review['Review']['created'] |
$comment->created |
| Modified | $review['Review']['modified'] |
$comment->modified |
| Owner ID | $review['User']['user_id'] |
$comment->owner_id |
| Owner Name | $review['User']['name'] |
$comment->owner_name |
| Listing ID | $review['Review']['listing_id'] |
$comment->listing_id |
V6 Comment Helper Methods
// Status checks
$comment->isPublished()
$comment->isUnpublished()
$comment->isPendingModeration()
$comment->isTrashed()
// Type checks
$comment->isEditorComment()
$comment->isUserComment()
// Owner reply checks
$comment->hasPublishedOwnerReply()
$comment->hasOwnerReplyPendingModeration()
// Custom field access
$comment->getFieldValue('jr_fieldname')
$comment->getFieldText('jr_fieldname')
// Media access
$comment->getPhotos()
$comment->getVideos()
Service Access Changes
Authentication:
// V5
$auth = S2Object::make('auth');
$userId = $auth->id;
$isGuest = $auth->guest;
// V6
$auth = fwd_auth();
$userId = $auth->id;
$isGuest = $auth->guest;
// Or shortcuts:
$userId = fwd_user_id();
Permissions Messages:
// V5
$listingPermissions = (S2Object::make('perm'))->__('listing');
$listingPermissions->setMessage('Custom error message');
return false;
// V6 - Use validation hooks for messages, or return false from permission hooks
fwd_add_action('jreviews:listing_form.validation', function($params) {
$params['validator']->errors()->add('general', 'Custom error message');
}, 20);
Complete Migration Examples
Example 1: One Listing Per User Limit
V5:
function one_listing_limit_registered_user($permission, $params)
{
$listingPermissions = (S2Object::make('perm'))->__('listing');
$auth = S2Object::make('auth');
if ($auth->id > 0) {
$Model = new S2Model();
$query = sprintf(
'SELECT count(*) FROM %s WHERE %s = %d AND state = 1',
EverywhereComContentModel::_LISTING_TABLE,
EverywhereComContentModel::_LISTING_USER_ID,
$auth->id
);
$count = $Model->query($query, 'loadResult');
if ($count > 0) {
$listingPermissions->setMessage('You have reached the limit of one listing per user');
return false;
}
}
return $permission;
}
Clickfwd\Hook\Filter::add('can_create_listing', 'one_listing_limit_registered_user', 10);
V6:
fwd_add_filter('jreviews:permission:listing.create', function($permission, $params) {
$auth = fwd_auth();
if ($auth->id > 0) {
$count = \JReviews\Models\Listing::query()
->where('owner_id', $auth->id)
->where('status', 1)
->count();
if ($count > 0) {
// Message will be shown via the form validation system
return false;
}
}
return $permission;
}, 20);
// Add custom message via validation hook
fwd_add_action('jreviews:listing_form.validation', function($params) {
$auth = fwd_auth();
if ($auth->id > 0) {
$count = \JReviews\Models\Listing::query()
->where('owner_id', $auth->id)
->where('status', 1)
->count();
if ($count > 0) {
$params['validator']->errors()->add('general', 'You have reached the limit of one listing per user');
}
}
}, 20);
Example 2: Modify View Data
V5:
Clickfwd\Hook\Filter::add('before_theme_render_viewvars', function($viewVars, $params) {
// Add custom data to listing detail page
if ($params['controller'] == 'listings' && $params['action'] == 'detail') {
if (isset($viewVars['listing'])) {
$listing = $viewVars['listing'];
$listingId = $listing['Listing']['listing_id'];
$categoryId = $listing['Category']['cat_id'];
// Add custom data
$viewVars['customData'] = [
'special_offer' => $categoryId == 5 ? 'Free shipping!' : null,
];
}
}
return $viewVars;
}, 10);
V6:
fwd_add_filter('jreviews:view_data', function($data, $params) {
$viewName = $params['normalizedName'] ?? '';
// Add custom data to listing detail page
if (str_contains($viewName, 'listing') && str_contains($viewName, 'detail')) {
if (isset($data['listing'])) {
$listing = $data['listing'];
$listingId = $listing->id;
$categoryId = $listing->cat_id;
// Add custom data
$data['customData'] = [
'special_offer' => $categoryId == 5 ? 'Free shipping!' : null,
];
}
}
return $data;
}, 20);
Example 3: Form Validation with Custom Fields
V5:
Clickfwd\Hook\Filter::add('listing_submit_validation', function($validation, $params) {
$formData = $params['data'];
$listingTypeId = $formData['Listing']['listing_type_id'] ?? null;
// Require phone for listing type 3
if ($listingTypeId == 3) {
$phone = $formData['Field']['jr_phone'] ?? '';
if (empty($phone)) {
$validation[] = 'Phone number is required for this listing type';
}
}
return $validation;
}, 10);
V6:
fwd_add_action('jreviews:listing_form.validation', function($params) {
$formData = $params['data'];
$listingTypeId = $formData['listing_type_id'] ?? null;
// Require phone for listing type 3
if ($listingTypeId == 3) {
$phone = $formData['fields']['jr_phone'] ?? '';
if (empty($phone)) {
$params['validator']->errors()->add('jr_phone', 'Phone number is required for this listing type');
}
}
}, 20);
Example 4: Review Permission Based on Listing Data
V5:
Clickfwd\Hook\Filter::add('can_create_user_review_for_listing', function($permission, $params) {
$listing = $params['listing'];
// Disable reviews for closed listings
$status = $listing['Field']['jr_status'] ?? '';
if ($status == 'closed') {
return false;
}
// Disable reviews for listing type 5
$listingTypeId = $listing['ListingType']['listing_type_id'];
if ($listingTypeId == 5) {
return false;
}
return $permission;
}, 10);
V6:
fwd_add_filter('jreviews:permission:comment.create_user_comment', function($permission, $params) {
$listing = $params['listing'];
// Disable reviews for closed listings
$status = $listing->getFieldValue('jr_status') ?? '';
if ($status == 'closed') {
return false;
}
// Disable reviews for listing type 5
$listingTypeId = $listing->listing_type_id;
if ($listingTypeId == 5) {
return false;
}
return $permission;
}, 20);
Example 5: Custom Field Output Override
V5:
// Override output for jr_status field
Clickfwd\Hook\Filter::add('field_output:jr_status', function($output, $field, $entry, $instance, $name) {
$value = $entry['Field']['jr_status'];
$listingId = $entry['Listing']['listing_id'];
$badges = [
'available' => '<span class="badge badge-green">Available</span>',
'pending' => '<span class="badge badge-yellow">Pending</span>',
'sold' => '<span class="badge badge-red">Sold</span>',
];
return $badges[$value] ?? $output;
}, 10);
V6:
// Override output for jr_status field
fwd_add_filter('jreviews:custom_field.output:jr_status', function($output, $params) {
$listing = $params['listing'];
$value = $listing->getFieldValue('jr_status');
$listingId = $listing->id;
$badges = [
'available' => '<span class="badge badge-green">Available</span>',
'pending' => '<span class="badge badge-yellow">Pending</span>',
'sold' => '<span class="badge badge-red">Sold</span>',
];
return $badges[$value] ?? $output;
}, 20);
Example 6: Auto-publish Based on User
V5:
Clickfwd\Hook\Filter::add('trusted_on_create_listing', function($trusted, $params) {
$auth = S2Object::make('auth');
// Auto-publish for specific user groups
$trustedGroups = [8, 9, 10]; // Admin, Editor, Publisher
foreach ($auth->groups as $groupId) {
if (in_array($groupId, $trustedGroups)) {
return true;
}
}
return $trusted;
}, 10);
V6:
fwd_add_filter('jreviews:permission:listing.autopublish', function($trusted, $params) {
$auth = fwd_auth();
// Auto-publish for specific user groups
$trustedGroups = [8, 9, 10]; // Admin, Editor, Publisher
foreach ($auth->groups as $groupId) {
if (in_array($groupId, $trustedGroups)) {
return true;
}
}
return $trusted;
}, 20);
Example 7: Add Content to Form
V5:
Clickfwd\Hook\Action::add('listing_form_bottom', function($params) {
$listing = $params['listing'] ?? null;
$listingTypeId = $params['listing_type_id'];
if ($listingTypeId == 3) {
echo '<div class="custom-notice">
<p>Please ensure all contact information is accurate.</p>
</div>';
}
}, 10);
V6:
fwd_add_action('jreviews:listing_form.bottom', function($params) {
$listing = $params['listing'] ?? null;
$listingTypeId = $params['listing_type_id'];
if ($listingTypeId == 3) {
echo '<div class="custom-notice">
<p>Please ensure all contact information is accurate.</p>
</div>';
}
}, 20);
Listing Permission Hooks
Permission hooks control who can perform actions on listings.
| V5 Hook | V6 Hook | Notes |
|---|---|---|
can_create_listing |
jreviews:permission:listing.create |
|
can_update_listing |
jreviews:permission:listing.update |
|
can_delete_listing |
jreviews:permission:listing.delete |
|
can_publish_listing |
jreviews:permission:listing.publish |
|
can_claim_listing |
jreviews:permission:listing.claim |
|
can_favorite_listing |
jreviews:permission:listing.favorite |
|
can_feature_listing |
jreviews:permission:listing.feature |
|
can_send_listing_inquiry |
jreviews:permission:listing.inquire |
|
can_update_listing_media |
jreviews:permission:listing.update_listing_media |
|
can_upload_listing_media |
jreviews:permission:listing.upload_media |
Check $mediaType param |
can_upload_listing_photo |
jreviews:permission:listing.upload_media |
Check $mediaType === 'photo' |
can_upload_listing_video |
jreviews:permission:listing.upload_media |
Check $mediaType === 'video' |
can_upload_listing_audio |
jreviews:permission:listing.upload_media |
Check $mediaType === 'audio' |
can_upload_listing_attachment |
jreviews:permission:listing.upload_media |
Check $mediaType === 'attachment' |
can_upload_media_from_url_in_listing |
jreviews:permission:listing.url_media_upload |
|
can_use_editor_in_listing |
jreviews:permission:listing.allows_html_in_summary_description |
|
can_add_listing_metadata |
jreviews:permission:listing.modify_metadata_fields |
|
trusted_on_create_listing |
jreviews:permission:listing.autopublish |
|
listing_allows_claims |
jreviews:permission:listing.claim |
Check listing type config |
listing_allows_favorites |
jreviews:permission:listing.favorite |
Check listing type config |
listing_allows_inquiries |
jreviews:permission:listing.inquire |
Check listing type config |
listing_allows_user_reviews |
jreviews:permission:comment.create_user_comment |
Terminology change |
listing_allows_editor_reviews |
jreviews:permission:comment.create_editorial_comment |
Terminology change |
New V6 Listing Permission Hooks
| V6 Hook | Description |
|---|---|
jreviews:permission:listing.preview_draft |
Permission to preview draft listings |
jreviews:permission:listing.set_listing_title |
Permission to set custom title |
jreviews:permission:listing.set_listing_title_alias |
Permission to set URL alias |
jreviews:permission:listing.set_listing_publication_date |
Permission to set publication date |
jreviews:permission:listing.set_listing_expiration_date |
Permission to set expiration date |
jreviews:permission:listing.link_video |
Permission to link videos |
jreviews:permission:listing.manage_media |
Permission to manage media |
jreviews:permission:listing.media.autopublish |
Auto-publish listing media |
jreviews:permission:listing.set_main_media |
Permission to set main media |
Comment/Review Permission Hooks
| V5 Hook | V6 Hook | Notes |
|---|---|---|
can_create_user_review_for_listing |
jreviews:permission:comment.create_user_comment |
|
can_create_editor_review_for_listing |
jreviews:permission:comment.create_editorial_comment |
|
can_update_review |
jreviews:permission:comment.update |
|
can_delete_review |
jreviews:permission:comment.delete |
|
can_vote_on_review |
jreviews:permission:comment.vote |
|
can_report_review |
jreviews:permission:comment.report |
|
can_reply_to_review |
jreviews:permission:comment.reply_as_owner |
|
can_upload_review_media |
jreviews:permission:comment.upload_media |
Check $mediaType param |
can_upload_review_photo |
jreviews:permission:comment.upload_media |
Check $mediaType === 'photo' |
can_upload_review_video |
jreviews:permission:comment.upload_media |
Check $mediaType === 'video' |
can_upload_review_audio |
jreviews:permission:comment.upload_media |
Check $mediaType === 'audio' |
can_upload_review_attachment |
jreviews:permission:comment.upload_media |
Check $mediaType === 'attachment' |
can_upload_media_from_url_in_review |
jreviews:permission:comment.url_media_upload |
|
review_allows_voting |
jreviews:permission:comment.see_vote_widget |
Config-based |
review_allows_discussions |
jreviews:permission:comment_discussion.create |
|
review_allows_replies |
jreviews:permission:comment.reply_as_owner |
|
review_allows_report |
jreviews:permission:comment.report |
|
trusted_on_create_user_review |
jreviews:permission:comment.autopublish |
|
trusted_on_create_editor_review |
jreviews:permission:comment.autopublish |
|
trusted_on_update_user_review |
jreviews:permission:comment.autopublish |
|
trusted_on_update_editor_review |
jreviews:permission:comment.autopublish |
|
trusted_on_create_review_owner_reply |
jreviews:permission:comment.owner_reply.autopublish |
New V6 Comment Permission Hooks
| V6 Hook | Description |
|---|---|
jreviews:permission:comment.access_upload_form |
Permission to access media upload form |
jreviews:permission:comment.allows_html_in_comment |
Allow HTML in comments |
jreviews:permission:comment.link_video |
Permission to link videos |
jreviews:permission:comment.manage_media |
Permission to manage comment media |
jreviews:permission:comment.media.autopublish |
Auto-publish comment media |
jreviews:permission:comment.see_comments_field |
Permission to see comments field |
jreviews:permission:comment.update_editorial_comment |
Update editorial comments |
jreviews:permission:comment.update_user_comment |
Update user comments |
Comment Discussion Hooks
| V5 Hook | V6 Hook |
|---|---|
can_delete_review_discussion |
jreviews:permission:comment_discussion.delete |
can_update_review_discussion |
jreviews:permission:comment_discussion.update |
can_report_review_discussion |
(removed) |
trusted_on_create_review_discussion |
jreviews:permission:comment_discussion.autopublish |
trusted_on_update_review_discussion |
jreviews:permission:comment_discussion.autopublish |
review_discussion_allows_report |
(removed) |
New V6 Comment Discussion Hooks
| V6 Hook | Description |
|---|---|
jreviews:permission:comment_discussion.create |
Permission to create discussions |
jreviews:permission:comment_discussion.allows_html_in_comment_discussion |
Allow HTML |
Media Permission Hooks
| V5 Hook | V6 Hook |
|---|---|
can_delete_media_in_listing |
jreviews:permission:media.delete |
can_update_media_in_listing |
(use media.delete + re-upload) |
can_publish_media_in_listing |
jreviews:permission:media.publish |
can_download_attachment |
jreviews:permission:media.download |
can_set_main_media |
jreviews:permission:media.set_main_media |
can_vote_on_media |
jreviews:permission:media.like |
can_report_media |
jreviews:permission:media.report |
media_allows_voting |
jreviews:permission:media.like |
media_allows_report |
jreviews:permission:media.report |
trusted_on_create_photo |
jreviews:permission:listing.media.autopublish |
trusted_on_create_video |
jreviews:permission:listing.media.autopublish |
trusted_on_create_audio |
jreviews:permission:listing.media.autopublish |
trusted_on_create_attachment |
jreviews:permission:listing.media.autopublish |
New V6 Media Hooks
| V6 Hook | Description |
|---|---|
jreviews:permission:media.set_media_function |
Set media function (cover, gallery, etc.) |
Field Permission Hooks
| V5 Hook | V6 Hook |
|---|---|
can_read_field |
jreviews:permission:field.read |
can_write_field |
jreviews:permission:field.write |
can_view_field_in_detail_page |
jreviews:permission:field.read |
can_view_field_in_list_page |
jreviews:permission:field.read |
can_view_field_in_comparison_page |
jreviews:permission:field.read |
New V6 Field Hooks
| V6 Hook | Description |
|---|---|
jreviews:permission:field.search |
Permission to use field in search |
Form Hooks
Form hooks allow adding content and validating form submissions.
Listing Form
| V5 Hook | V6 Hook | Type |
|---|---|---|
listing_form_bottom |
jreviews:listing_form.bottom |
Action |
listing_submit_validation |
jreviews:listing_form.validation |
Action |
listing_save_pre |
jreviews:listing.data_before_save |
Filter |
New V6 Listing Form Hooks
| V6 Hook | Type | Description |
|---|---|---|
jreviews:listing_form.top |
Action | Content at top of form |
jreviews:listing_form.before_field: |
Action | Before specific field |
jreviews:listing_form.after_field: |
Action | After specific field |
jreviews:listing_form.custom_fields |
Filter | Filter custom fields collection |
jreviews:listing_form.custom_fields:{:name} |
Filter | Filter specific field |
Comment/Review Form
| V5 Hook | V6 Hook | Type |
|---|---|---|
review_form_bottom |
jreviews:comment_form.bottom |
Action |
review_submit_validation |
jreviews:comment_form.validation |
Action |
review_save_pre |
(use events) | Use CommentWasCreated event |
New V6 Comment Form Hooks
| V6 Hook | Type | Description |
|---|---|---|
jreviews:comment_form.before_comment |
Action | Content before comment field |
jreviews:comment_form.before_field: |
Action | Before specific field |
jreviews:comment_form.after_field: |
Action | After specific field |
Owner Reply Form
| V5 Hook | V6 Hook |
|---|---|
owner_reply_form_bottom |
jreviews:comment_owner_reply_form.bottom |
owner_reply_submit_validation |
jreviews:comment_owner_reply_form.validation |
Other Forms
| V5 Hook | V6 Hook |
|---|---|
claim_form_bottom |
jreviews:listing_claim_form.bottom |
claim_submit_validation |
jreviews:listing_claim_form.validation |
inquiry_form_bottom |
jreviews:listing_inquiry_form.bottom |
inquiry_submit_validation |
jreviews:listing_inquiry_form.validation |
report_form_bottom |
jreviews:comment_report_form.bottom / jreviews:media_report_form.bottom |
report_submit_validation |
jreviews:comment_report_form.validation / jreviews:media_report_form.validation |
discussion_form_bottom |
(removed) |
mylists_form_bottom |
mylists:list_form.bottom |
mylists_submit_validation |
mylists:list_form.validation |
resources_form_bottom |
listingresources:resource_form.bottom |
resources_submit_validation |
listingresources:resource_form.validation |
Custom Field Hooks
| V5 Hook | V6 Hook | Notes |
|---|---|---|
field_output{:name} |
jreviews:custom_field.output:{:name} |
Replace {:name} with field name |
field_form{:name|:type} |
(see listing form hooks) | Use form field hooks |
Template Hooks
| V5 Hook | V6 Hook | Notes |
|---|---|---|
before_theme_render_viewvars |
jreviews:view_data |
View data filtering for all views |
template_listings.detail:{position}-description |
jreviews:listing.below-description |
Position-specific |
template_listings.{page}:after-title |
(use template overrides) | |
template_directory:after-directory{-name} |
(use template overrides) |
New V6 Template Position Hooks
| V6 Hook | Description |
|---|---|
jreviews:listing.below-description |
After listing description |
jreviews:listing.below-fields |
After custom fields |
jreviews:listing.below-userreviews |
After user reviews |
jreviews:listing.below-editorreviews |
After editor reviews |
jreviews:listing.below-bottommedia |
After bottom media |
jreviews:listing.below-socialbookmarks |
After social bookmarks |
jreviews:listing.detail.cover_photo |
Cover photo area |
jreviews:listing.detail.map |
Map area |
jreviews:listing:before_render |
Before listing renders |
Meta Tags & SEO Hooks
V6 uses the unified jreviews:page_meta:{:name} hook pattern for all meta tags. Replace {:name} with the meta tag name.
| V5 Hook | V6 Hook |
|---|---|
page_canonical_metatag |
jreviews:page_meta:canonical_url |
page_title_metatag |
jreviews:page_meta:title |
page_description_metatag |
jreviews:page_meta:description |
page_keywords_metatag |
(removed) Keywords meta tag deprecated in modern SEO |
page_robots_metatag |
jreviews:page_meta:robots |
page_next_metatag |
(removed) Pagination handled differently |
page_prev_metatag |
(removed) Pagination handled differently |
open_graph_tags_before_parse |
jreviews:page_meta:og:title, jreviews:page_meta:og:description, jreviews:page_meta:og:image |
open_graph_tags_after_parse |
(use hooks above) Same hooks, adjust priority |
twitter_cards_before_parse |
jreviews:page_meta:twitter:title, jreviews:page_meta:twitter:description, jreviews:page_meta:twitter:image |
twitter_cards_after_parse |
(use hooks above) Same hooks, adjust priority |
list_page_ld_json_structured_data |
jreviews:listing:structured_data |
Open Graph / Twitter Cards Migration Example
V5:
Clickfwd\Hook\Filter::add('open_graph_tags_before_parse', function($tags, $params) {
$listing = $params['listing'] ?? null;
if ($listing && $listing['Listing']['featured']) {
$tags['og:title'] = 'Featured: ' . $listing['Listing']['title'];
}
return $tags;
}, 10);
V6:
// In V6, each Open Graph/Twitter tag has its own hook
fwd_add_filter('jreviews:page_meta:og:title', function($value, $name, $routeName, $attributes) {
$listing = $attributes['listing'] ?? null;
if ($listing && $listing->featured) {
return 'Featured: ' . $listing->title;
}
return $value;
}, 20);
// Twitter cards work the same way
fwd_add_filter('jreviews:page_meta:twitter:title', function($value, $name, $routeName, $attributes) {
$listing = $attributes['listing'] ?? null;
if ($listing && $listing->featured) {
return 'Featured: ' . $listing->title;
}
return $value;
}, 20);
// Customize OG image for specific categories
fwd_add_filter('jreviews:page_meta:og:image', function($value, $name, $routeName, $attributes) {
$listing = $attributes['listing'] ?? null;
if ($listing && $listing->cat_id == 5) {
// Use category-specific default image if listing has no main photo
if (! $listing->hasMainPhoto()) {
return 'https://example.com/images/category-5-default.jpg';
}
}
return $value;
}, 20);
System Hooks
| V5 Hook | V6 Hook | Notes |
|---|---|---|
site_init |
(removed) | Use service providers |
admin_init |
(removed) | Use service providers |
render |
(removed) | Use view composers |
before_filter_request |
(removed) | Use middleware |
after_filter_output |
(removed) | Use middleware |
before_theme_render_request |
(removed) | Use middleware |
cron_tasks |
(unchanged) | Still available |
cookie_consent |
jreviews:cookie_consent |
|
enable_captcha |
(removed) | Configure in settings |
enable_image_lazyloading |
(removed) | Configure in settings |
New V6 Route Hooks
| V6 Hook | Description |
|---|---|
jreviews:route_matched:{:name} |
Fires when a frontend route matches |
jreviews:admin_route_matched:{:name} |
Fires when an admin route matches |
PaidListings Hook Examples
PaidListings hooks demonstrate the data access pattern changes. Note how $listing['Paid'] array access in V5 becomes $listing->paid in V6.
Enable Claims For Paid Listings
V5:
Clickfwd\Hook\Filter::add('listing_allows_claims', function($allow, $params) {
$listing = $params['listing'];
$premiumPlanIds = [1, 2, 3];
$allow = isset($listing['Paid']) && array_intersect($premiumPlanIds, $listing['Paid']['plan_ids']);
return $allow;
}, 10);
V6:
fwd_add_filter('jreviews:permission:listing.claim', function($allow, $params) {
$listing = $params['listing'];
$premiumPlanIds = [1, 2, 3];
// $listing->paid is the Paid array, same structure as V5
$allow = ! empty($listing->paid) && array_intersect($premiumPlanIds, $listing->paid['plan_ids']);
return $allow;
}, 20);
Enable Inquiries For Paid Listings
V5:
Clickfwd\Hook\Filter::add('listing_allows_inquiries', function($allow, $params) {
$listing = $params['listing'];
$premiumPlanIds = [1, 2, 3];
$allow = isset($listing['Paid']) && array_intersect($premiumPlanIds, $listing['Paid']['plan_ids']);
return $allow;
}, 10);
V6:
fwd_add_filter('jreviews:permission:listing.inquire', function($allow, $params) {
$listing = $params['listing'];
$premiumPlanIds = [1, 2, 3];
$allow = ! empty($listing->paid) && array_intersect($premiumPlanIds, $listing->paid['plan_ids']);
return $allow;
}, 20);
Enable Favorites For Paid Listings
V5:
Clickfwd\Hook\Filter::add('listing_allows_favorites', function($allow, $params) {
$listing = $params['listing'];
$premiumPlanIds = [1, 2, 3];
$allow = isset($listing['Paid']) && array_intersect($premiumPlanIds, $listing['Paid']['plan_ids']);
return $allow;
}, 10);
V6:
fwd_add_filter('jreviews:permission:listing.favorite', function($allow, $params) {
$listing = $params['listing'];
$premiumPlanIds = [1, 2, 3];
$allow = ! empty($listing->paid) && array_intersect($premiumPlanIds, $listing->paid['plan_ids']);
return $allow;
}, 20);
Add Custom Plan Labels For Paid Listings
V5:
function paid_plan_labels($labels, $params)
{
$listing = $params['listing'];
$planIds = $listing['Paid']['plan_ids'] ?? [];
if (empty($planIds)) {
return $labels;
}
$basicPlanId = 1;
$premiumPlanId = 2;
// Label color CSS classes: jrRed, jrOrange, jrBlue, jrGreen, jrBrown, jrPurple
if (in_array($basicPlanId, $planIds)) {
$labels['basic'] = [
'class' => 'jrStatusLabel jrPurple',
'text' => 'Basic Plan'
];
}
if (in_array($premiumPlanId, $planIds)) {
$labels['premium'] = [
'class' => 'jrStatusLabel jrGreen',
'text' => 'Premium Plan'
];
}
return $labels;
}
Clickfwd\Hook\Filter::add('listing_status_labels', 'paid_plan_labels', 10);
V6:
fwd_add_filter('jreviews:listing.status_labels', function($labels, $params) {
$listing = $params['listing'];
$planIds = $listing->paid['plan_ids'] ?? [];
if (empty($planIds)) {
return $labels;
}
$basicPlanId = 1;
$premiumPlanId = 2;
if (in_array($basicPlanId, $planIds)) {
$labels['basic'] = [
'class' => 'jrStatusLabel jrPurple',
'text' => 'Basic Plan'
];
}
if (in_array($premiumPlanId, $planIds)) {
$labels['premium'] = [
'class' => 'jrStatusLabel jrGreen',
'text' => 'Premium Plan'
];
}
return $labels;
}, 20);
Custom Meta Description For Paid Listings
V5:
Clickfwd\Hook\Filter::add('page_description_metatag', function($value, $params) {
$listing = $params['listing'] ?? null;
// Only continue if it's a listing detail page
if (! $listing) {
return $value;
}
// Only continue if listing is in a paid category
if (empty($listing['Paid'])) {
return $value;
}
// Only continue if it's a featured listing
if (! $listing['Listing']['featured']) {
return "Generic meta description for listing {$listing['Listing']['title']}";
}
// Featured listings show the custom meta description or if empty the listing summary
return $listing['Listing']['metadesc'] ?: substr($listing['Listing']['summary'], 0, 150).'...';
}, 10);
V6:
fwd_add_filter('jreviews:page_meta:description', function($value, $name, $routeName, $attributes) {
$listing = $attributes['listing'] ?? null;
// Only continue if it's a listing detail page
if (! $listing) {
return $value;
}
// Only continue if listing is in a paid category
if (empty($listing->paid)) {
return $value;
}
// Only continue if it's a featured listing
if (! $listing->featured) {
return "Generic meta description for listing {$listing->title}";
}
// Featured listings show the custom meta description or if empty the listing summary
return $listing->metadesc ?: substr($listing->summary, 0, 150).'...';
}, 20);
Using PaidHelper in V6
The PaidHelper class works the same way in V6, but listing access uses arrow syntax:
V5:
<?php if (PaidHelper::getVar('inquiries', $listing) == 1): ?>
// Enable inquiries feature
<?php endif; ?>
// Check plan IDs
if (array_intersect([1,2,3], $listing['Paid']['plan_ids'])) {
// Premium plan features
}
V6:
<?php if (PaidHelper::getVar('inquiries', $listing) == 1): ?>
// Enable inquiries feature
<?php endif; ?>
// Check plan IDs - note the arrow syntax for paid array
if (! empty($listing->paid) && array_intersect([1,2,3], $listing->paid['plan_ids'])) {
// Premium plan features
}
Add-on Specific Hooks
MyLists
| V5 Hook | V6 Hook |
|---|---|
can_create_user_list |
mylists:permission:list.create_user_list |
can_update_user_list |
mylists:permission:list.update |
can_delete_user_list |
mylists:permission:list.delete |
can_publish_user_list |
mylists:permission:list.publish |
can_make_user_list_private |
mylists:permission:list.make_private |
listing_allows_user_lists |
mylists:permission:list.manage_listings |
trusted_on_user_list_create |
mylists:permission:list.autopublish |
ListingResources
| V5 Hook | V6 Hook |
|---|---|
can_create_listing_resource |
listingresources:permission:resource.create |
can_update_listing_resource |
listingresources:permission:resource.update |
can_delete_listing_resource |
listingresources:permission:resource.delete |
listing_allows_resources |
(check listing type config) |
trusted_on_listing_resource_create |
listingresources:permission:resource.autopublish |
Events Calendar
| V5 Hook | V6 Hook |
|---|---|
eventscalendar:day_view.after_title |
eventscalendar:day_view.after_title |
New V6 Events Calendar Hooks
| V6 Hook | Description |
|---|---|
eventscalendar:day-view.after-last-field |
After last field in day view |
eventscalendar:month-view.before-event-title |
Before event title in month view |
eventscalendar:month-view.after-event-title |
After event title in month view |
eventscalendar:status-badge.before-status |
Before status badge |
eventscalendar:status-badge.after-status |
After status badge |
Removed V5 Hooks
The following hooks have been removed and do not have direct v6 equivalents:
| V5 Hook | Reason / Alternative |
|---|---|
site_init |
Use service providers or middleware |
admin_init |
Use service providers or middleware |
render |
Use Blade view composers |
before_filter_request |
Use middleware |
after_filter_output |
Use middleware |
before_theme_render_request |
Use middleware |
page_keywords_metatag |
Keywords meta tag deprecated in modern SEO |
page_next_metatag |
Pagination handled differently |
page_prev_metatag |
Pagination handled differently |
enable_captcha |
Configure via settings |
enable_image_lazyloading |
Configure via settings |
can_add_review_on_listing_create |
Configure via listing type settings |
listing_editor_reviews_open |
Configure via listing type settings |
listing_user_reviews_open |
Configure via listing type settings |
signup_modal_benefits_desc |
Use jreviews:user_registration.signup_benefits |
community |
(removed) |
configure:community.register_url |
(removed) |
Complete V6 Hooks Reference
For the complete list of v6 hooks with detailed documentation, see the V6 Hooks Directory.