JReviews logo Docs
Menu
Version

jreviews:listing:structured_data

Allows filtering the Schema.org structured-data array before JSON-LD conversion. The array represents the complete assembled output for the listing's primary schema type plus admin-configured enrichments; modify or remove entries to control what's emitted.

Filter
System
Since 6.0.0

You need to have a working knowledge of Hooks before you get started.

Fires when adding Schema.org structured data to listing detail pages, after data is generated but before JSON-LD conversion

Parameters

Name Type Description
$schemaArray array The assembled structured data array, before JSON-LD conversion
$listing \JReviews\App\Models\Listing The listing model being displayed

Boilerplate Code

Use the boilerplate code to start using the filter, and add your own logic to modify the first argument and return it.

fwd_add_filter('jreviews:listing:structured_data', function($schemaArray, $listing)
{
    // Your code here
    
    return $schemaArray;
}, 20, 2);

The , 20, N after your callback are the hook priority and the number of arguments your callback accepts. By default, a hook passes your callback only its first argument; for a filter, that is the value being filtered, so a simple function($value) { ... } needs nothing extra. If your callback declares more parameters, such as function($value, $listing) { ... }, you must add N (the parameter count, 2 here). Because N is the fourth argument to fwd_add_filter() or fwd_add_action(), you must also pass the priority (20 is the default). Leaving these off when your callback expects extra parameters causes a Too few arguments to function ... fatal error.

Development & Support
Customizations are not included with support. We provide this information to make it easier for developers to extend the functionality. From time to time we may have some availability for custom work. Get in touch to see if there's an opportunity to work together.

Examples

Add amenity features from a checkbox field

Convert selected checkbox option labels into Schema.org LocationFeatureSpecification entries under amenityFeature.

fwd_add_filter('jreviews:listing:structured_data', function (array $schemaArray, $listing): array {
    // Replace 6 with the listing type ID that owns your amenities field.
    // This guard prevents the customization from changing every listing type.
    $targetListingTypeId = 6;

    if ((int) ($listing->listing_type_id ?? 0) !== $targetListingTypeId) {
        return $schemaArray;
    }

    // Replace jr_amenities with your checkbox or multi-select custom field name.
    // getFieldText returns the selected option labels, not the stored option values.
    $amenityLabels = (array) $listing->getFieldText('jr_amenities', []);

    $features = [];

    foreach ($amenityLabels as $label) {
        $label = trim(strip_tags((string) $label));

        if ($label === '') {
            continue;
        }

        $features[] = [
            '@type' => 'LocationFeatureSpecification',
            'name' => $label,
            'value' => true,
        ];
    }

    if ($features === []) {
        return $schemaArray;
    }

    $existing = $schemaArray['amenityFeature'] ?? [];

    if ($existing && isset($existing['@type'])) {
        $existing = [$existing];
    }

    $schemaArray['amenityFeature'] = array_values(array_merge(
        (array) $existing,
        $features
    ));

    return $schemaArray;
}, 20, 2);

Merge official profile URLs into sameAs without replacing values already generated by JReviews or another customization.

fwd_add_filter('jreviews:listing:structured_data', function (array $schemaArray, $listing): array {
    // Replace 6 with the listing type ID that has these profile fields.
    $targetListingTypeId = 6;
    // Only listings from that type should receive these profile links.

    if ((int) ($listing->listing_type_id ?? 0) !== $targetListingTypeId) {
        return $schemaArray;
    }

    // Use fields that store official profile or same-entity URLs.
    $profileFields = ['jr_facebook', 'jr_instagram', 'jr_youtube'];
    $sameAs = (array) ($schemaArray['sameAs'] ?? []);

    foreach ($profileFields as $fieldName) {
        $url = trim((string) $listing->getFieldValue($fieldName, ''));

        if ($url !== '') {
            $sameAs[] = $url;
        }
    }

    if ($sameAs !== []) {
        $schemaArray['sameAs'] = array_values(array_unique($sameAs));
    }

    return $schemaArray;
}, 20, 2);

Add a measured additional property

Create one PropertyValue for a numeric custom field when the value needs to be calculated or controlled in code.

fwd_add_filter('jreviews:listing:structured_data', function (array $schemaArray, $listing): array {
    // Replace 6 with the listing type ID that has the measurement field.
    $targetListingTypeId = 6;
    // Only listings from that type should receive this measured property.

    if ((int) ($listing->listing_type_id ?? 0) !== $targetListingTypeId) {
        return $schemaArray;
    }

    // Replace jr_wall_height with your numeric custom field name.
    $height = $listing->getFieldValue('jr_wall_height');

    if (! is_numeric($height)) {
        return $schemaArray;
    }

    $properties = $schemaArray['additionalProperty'] ?? [];

    if ($properties && isset($properties['@type'])) {
        $properties = [$properties];
    }

    $properties[] = [
        '@type' => 'PropertyValue',
        'name' => 'Max. wall height',
        'value' => (float) $height,
        // MTR is the UN/CEFACT unit code for meters.
        'unitCode' => 'MTR',
        'unitText' => 'm',
    ];

    $schemaArray['additionalProperty'] = array_values((array) $properties);

    return $schemaArray;
}, 20, 2);

Source Files

  • app/Actions/AddListingDetailStructuredDataAction.php