JReviews logo Docs
Menu
Version

Custom Field Output Formatting

Customize one field’s output with the shared Output Format setting, Early Access Blade templates, or Legacy PHP formatting—and migrate existing PHP customizations safely.

Overview

Development & Support
Customizations are not included with support. This reference is intended for developers who are comfortable testing and maintaining custom code.

This article covers formatting the output of one custom field from its Advanced Settings. It does not control how fields and field groups are positioned on a page. For page-level placement, see Customize Layout of Custom Fields.

JReviews provides three approaches:

Approach Best for Availability
Output Format Simple HTML using tags such as {fieldtext} and {listing_id} Legacy and Early Access
Blade formatting Conditions, loops, calculations, and reusable templates Early Access listing detail page
PHP formatting Existing complex formatting on legacy pages Legacy pages

The Blade and PHP settings can both remain visible in the control panel. The renderer used by the page determines which settings take effect. When the Early Access listing detail page renders a field, legacy PHP output format and Field output template customizations are not executed.

Choose a Formatting Approach

Start with Output Format when tags and HTML are enough. It works in both rendering systems and requires no migration.

Use Blade template code for short Early Access customizations stored with a field. Use a Field output Blade template file when code is longer or shared by several fields.

Keep PHP output format or a legacy Field output template only for pages that still use the legacy renderer. If you are enabling Early Access, follow the migration guide.

The settings are located under Custom Fields → Edit Field → Advanced Settings.

Formatting System Reference

Choose the rendering system used by the page you are customizing. Early Access is shown by default.

Early Access Blade Formatting

Prerequisite
The Early Access listing detail page must be enabled for Blade field formatting to render. Enable and test it on a staging site first.

The two Blade settings are:

  • Blade template code — write Blade directly in the field settings.
  • Field output Blade template — select a reusable .blade.php file from your overrides.

Inline Blade Template Code

Inline code receives the same variables as a template file. It does not need an @props declaration.

<span class="field-value">{{ $value }}</span>

Blade escapes {{ }} output. Use {!! !!} only when the value deliberately contains trusted HTML.

Reusable Blade Template Files

Place field-output templates in the namespace-mirrored component override directory.

Joomla

templates/jreviews_overrides/resources/views/components/field-output/my-template.blade.php

WordPress

jreviews_overrides/resources/views/components/field-output/my-template.blade.php

New files are discovered by a live directory scan and should appear in the dropdown without clearing a file registry.

Use a descriptive filename such as price-summary.blade.php. A template selected in the dropdown is resolved using its hyphenated name first and its original name second.

JReviews resolves Blade formatting in this order:

  1. Inline Blade template code
  2. The selected Field output Blade template file
  3. An automatic file named after the field, such as jr_price.blade.php
  4. The field's normal Output Format when no Blade override is selected or found

Inline code therefore takes precedence if both inline code and a template file are configured.

Available Blade Variables

Variable Value
$attributes ComponentAttributeBag containing output attributes
$field The current Field model; for example, $field->name and $field->title
$data JSON-decoded data when the stored value is valid JSON; otherwise the normalized field value
$value The current field value returned by the model
$route The string 'listing.detail' on the listing detail route, otherwise null
$listing Listing model for listing custom fields
$comment Comment model for review/comment custom fields

These variables are injected by the renderer. @props can document defaults in reusable files, but it does not create the variables.

Read Current and Related Fields

For the current field, use $value for its stored value or read its display text from the model:

{{ $listing->getFieldTextString($field->name) }}

Listing field methods include:

Method Result
$listing->getFieldValue('jr_name') Stored value; an array for multiple-value fields
$listing->getFieldText('jr_name') Display label or an array of labels
$listing->getFieldTextString('jr_name') Display labels joined with commas
$listing->getFieldOptionImage('jr_name') Selected option image where supported
$listing->getField('jr_name') Field model
$listing->getFields() Field collection

The same methods are available on $comment for review fields:

{{ $comment->getFieldTextString('jr_recommend') }}

From a review field, access a field belonging to its listing through the related model:

{{ $comment->listing->getFieldTextString('jr_neighborhood') }}

There is no pre-populated sibling-fields variable. Read sibling fields from $listing or $comment.

Common Listing and Comment Attributes

The models also normalize commonly used attributes across Joomla and WordPress. Access them with object syntax:

Listing example Value
$listing->id Listing ID
$listing->title Title
$listing->alias URL alias
$listing->url Listing URL
$listing->summary Summary HTML
$listing->description Description HTML
$listing->featured Featured status as a boolean
$listing->views View count
$listing->owner_id Owner user ID
$listing->owner_name Normalized owner or guest name
$listing->owner_email Normalized owner or guest email
$listing->created, $listing->updated Date objects or null
$listing->category_title Category title when loaded
Comment example Value
$comment->id Comment/review ID
$comment->title Comment/review title
$comment->comments Comment/review body
$comment->rating Normalized overall rating or null
$comment->url Comment/review URL
$comment->comment_type Editor or user comment type
$comment->listing_id Associated listing ID
$comment->owner_id Author user ID
$comment->owner_name Normalized author or guest name
$comment->owner_email Normalized author or guest email
$comment->created, $comment->updated Date objects or null

Relationships use the same object syntax:

<a href="{{ $comment->listing->url }}">
    {{ $comment->listing->title }}
</a>

@if ($comment->isUserComment())
    <span>{{ $comment->owner_name }}</span>
@endif

<time datetime="{{ $listing->created?->toAtomString() }}">
    {{ $listing->created?->format('M j, Y') }}
</time>

Other useful relations include $listing->user, $listing->listing_type, $comment->user, and $comment->listing_type. A relation or selected column may depend on how the model was loaded, so guard optional data and do not assume an undocumented property exists.

Blade Syntax

{{-- Escaped output --}}
{{ $value }}

{{-- Conditional --}}
@if ($listing->featured)
    <span>Featured</span>
@endif

{{-- Multiple values --}}
@foreach ((array) $listing->getFieldText('jr_amenities') as $amenity)
    <span>{{ $amenity }}</span>
@endforeach

{{-- PHP calculation --}}
@php
    $count = count((array) $listing->getFieldValue('jr_amenities'));
@endphp

<span>{{ $count }} amenities</span>

Blade Recipes

Show output based on another field

@php
    $deliveryMethods = (array) $listing->getFieldValue('jr_delivery_methods');
@endphp

@if (in_array('local-delivery', $deliveryMethods, true))
    <span>{{ $listing->getFieldTextString($field->name) }}</span>
@endif

Combine several optional fields

@php
    $parts = array_filter([
        $listing->getFieldValue('jr_address'),
        $listing->getFieldValue('jr_city'),
        $listing->getFieldValue('jr_postcode'),
    ], fn ($part) => $part !== null && $part !== '');
@endphp

@if ($parts)
    <span>{{ implode(', ', $parts) }}</span>
@endif

Calculate a percentage from sibling fields

@php
    $regularPrice = (float) $listing->getFieldValue('jr_regular_price');
    $salePrice = (float) $listing->getFieldValue('jr_sale_price');

    $discountPercentage = $regularPrice > 0
        ? (($regularPrice - $salePrice) / $regularPrice) * 100
        : null;
@endphp

@if ($discountPercentage !== null && $discountPercentage > 0)
    <span class="discount">-{{ number_format($discountPercentage, 2) }}%</span>
@endif

This uses explicit numeric casts and protects against division by zero. Use names that describe what the fields contain; do not preserve a misleading legacy variable name merely because the old code used it.

Iterate FormBuilder data

@foreach (($data['items'] ?? $data ?? []) as $item)
    <div class="inventory-item">
        <span>{{ $item['name'] ?? '' }}</span>
        <span>{{ number_format((float) ($item['price'] ?? 0), 2) }}</span>
    </div>
@endforeach

Blade Limitations and Empty Values

  • A writable field with a genuinely blank value is rejected before its Blade template runs. A Blade @else block cannot provide placeholder text for that case through this formatting path.
  • A template that renders an empty string hides the complete field wrapper.
  • $route is a string or null, not a route object.
  • The renderer does not inject legacy $output, $params, $fields, $image, or $CustomFields variables.
  • Returning the legacy default $output has no direct Blade equivalent. Blade creates the output instead of receiving prebuilt default markup.

Legacy PHP Formatting

Legacy Pages
These settings apply to pages that still use the legacy renderer. They are ignored by the Early Access listing detail page.

The two legacy settings are:

  • PHP output format — write PHP in the field settings. The editor already starts in PHP mode, so do not add an opening <?php tag.
  • Field output template — select a reusable legacy .thtml template.

Inline PHP Output Format

Return a string:

return "<span>Label:</span> <span>{$text}</span>";

Or close PHP before writing markup:

?>
<span>Label:</span> <span><?php echo $text; ?></span>

Reusable Legacy Templates

Legacy field-format templates belong in the active legacy theme's fields_phpformat directory.

Joomla

templates/jreviews_overrides/views/themes/{your-theme}/fields_phpformat/my-template.thtml

WordPress

jreviews_overrides/views/themes/{your-theme}/fields_phpformat/my-template.thtml

Available Legacy Variables

Variable Value
$name Custom field name
$entry Associated listing or review array
$listing Listing array for listing fields
$review Review array for review fields
$field Field configuration array
$fields Fields data for the entry
$value Selected stored value or array of values
$text Current display text or array of text values
$image Current option image name or array of names
$output Standard prebuilt output
$params Page context including route, controller, action, view variables, suffix, and list/detail context
$CustomFields Legacy custom-fields helper

$value, $text, and $image are arrays for checkbox and multiple-select fields and strings for single-value fields.

Legacy Recipes

Read another field

$city = $CustomFields->fieldValue('jr_city', $entry);
return $city ?: false;

Show output when another option is selected

$methods = (array) $CustomFields->fieldValue('jr_delivery_methods', $entry);
return in_array('local-delivery', $methods, true) ? $output : false;

Combine several fields

$parts = array_filter([
    $CustomFields->fieldValue('jr_address', $entry),
    $CustomFields->fieldValue('jr_city', $entry),
    $CustomFields->fieldValue('jr_postcode', $entry),
]);

return $parts ? implode(', ', $parts) : false;

Calculate a value from two fields

$price = (float) $CustomFields->fieldValue('jr_price', $entry);
$quantity = (float) $CustomFields->fieldValue('jr_quantity', $entry);
$total = $price * $quantity;

return $total > 0 ? number_format($total, 2) : false;

Legacy recipes that return $output, construct routes with legacy helpers, or emit inline JavaScript require design decisions during migration; they are not mechanical syntax conversions.

Blade and Legacy PHP Compared

Concern Early Access Blade Legacy PHP
Inline setting Blade template code PHP output format
Reusable file .blade.php under resources/views/components/field-output .thtml under the legacy theme's fields_phpformat
Listing context $listing model $listing / $entry array
Review context $comment model $review / $entry array
Output Blade renders the output Code can return or echo output
FormBuilder JSON Decoded in $data when valid JSON Decode $text manually
Escaping {{ }} escapes by default The customization must escape output explicitly

Migration Guide

Only fields with custom code in PHP output format or a selected legacy Field output template need migration. Fields that use only Output Format continue working.

When the Early Access listing detail page is enabled, legacy PHP formatting is ignored. The field falls back to its normal Output Format until a Blade override is configured.

Inventory Before Enabling Early Access

On a staging copy of the site:

  1. Open every listing and review field's Advanced Settings.
  2. Record fields containing PHP output format code or a selected Field output template.
  3. Save a copy of the code and note whether each field belongs to a listing or review.
  4. Record the field type and every sibling field, helper, route, or script the code uses.
  5. Include examples with blank, single, and multiple values in the test plan.

Legacy-to-Blade Variable Mapping

Legacy use Blade replacement Migration note
$name $field->name $field is now a model
$value $value Close match, normalized by the model
$text getFieldText() / getFieldTextString() Decide whether the old code needs stored data or display labels
$entry $listing or $comment Choose based on field ownership
$listing array $listing model Replace array access with object methods/properties
$review $comment model Review context was renamed
$field array $field model Array-key access is not portable
$CustomFields->fieldValue() $listing->getFieldValue() or $comment->getFieldValue() Reads stored values
$CustomFields->field() Usually getFieldText() Check whether legacy click-to-search or output reformatting was intended
$image getFieldOptionImage() when appropriate No injected variable
$fields ->getFields() or ->getField() No injected variable
$output No direct equivalent Redesign the fallback because Blade creates the output
$params No direct equivalent Only the limited $route string or null is injected

Do not mechanically rename $text, $field, $fields, $image, $output, or $params. Their meaning or shape changes and may require redesign.

Migration Workflow

  1. Decide whether the code belongs in inline Blade template code or a reusable file.
  2. Replace legacy field reads with methods on $listing or $comment.
  3. Replace array access with model properties and methods.
  4. Choose stored values (getFieldValue) or display labels (getFieldText) intentionally.
  5. Add guards for missing data, invalid numbers, division by zero, and multiple-value arrays.
  6. Escape output with {{ }} unless trusted HTML is explicitly required.
  7. Flag legacy routes, helper classes, JavaScript, $output, and $params for manual redesign.
  8. Enable Early Access on staging, add the Blade code, and test all recorded scenarios.

Migration Example: Sibling-Field Calculation

Legacy PHP

$regularPrice = $CustomFields->fieldValue('jr_regular_price', $entry);
$salePrice = $CustomFields->fieldValue('jr_sale_price', $entry);
$discount = (($regularPrice - $salePrice) / $regularPrice) * 100;

return '<span class="discount">-'.number_format($discount, 2).'%</span>';

Early Access Blade

@php
    $regularPrice = (float) $listing->getFieldValue('jr_regular_price');
    $salePrice = (float) $listing->getFieldValue('jr_sale_price');

    $discount = $regularPrice > 0
        ? (($regularPrice - $salePrice) / $regularPrice) * 100
        : null;
@endphp

@if ($discount !== null && $discount > 0)
    <span class="discount">-{{ number_format($discount, 2) }}%</span>
@endif

Migration Example: FormBuilder JSON

Legacy PHP

$items = json_decode($text, true);

foreach ($items as $item) {
    echo '<div>'.htmlspecialchars($item['name']).'</div>';
}

Early Access Blade

@foreach (($data['items'] ?? $data ?? []) as $item)
    <div>{{ $item['name'] ?? '' }}</div>
@endforeach

AI-Assisted Migration

AI can produce a useful first draft, but it cannot infer field ownership, field types, stored values, or the intent of an undocumented helper. Give it those details and review every unsupported dependency it identifies.

Copy this prompt and add the requested information and legacy code:

Convert the JReviews legacy custom-field PHP formatting below to Early Access Blade.

Context I will provide:
1. Is this a listing field or a review/comment field?
2. What is the current field name and field type?
3. For every sibling field used: field name, field type, and whether the code needs its stored value or display label.
4. Is the result going into inline "Blade template code" or a reusable .blade.php file?

JReviews Blade runtime rules:
- $listing and $comment are models, never legacy arrays.
- Use $listing->getFieldValue('jr_name') or $comment->getFieldValue('jr_name') for stored values.
- Use getFieldText(), getFieldTextString(), or getFieldOptionImage() only when their display result matches the legacy intent.
- A review field can read a listing field through $comment->listing.
- $field is a Field model, not the legacy field array.
- $data contains JSON-decoded data when the stored value is valid JSON; otherwise it is the normalized value.
- $route is 'listing.detail' or null, not a route object.
- There is no direct injected equivalent for legacy $output, $params, $fields, or $image. Flag each use for manual redesign unless a verified model method solves the exact requirement.
- Do not assume $text maps directly to $data. Decide whether it represented a stored value or a display label.
- A genuinely blank writable field is rejected before the Blade template runs, so the template cannot create a placeholder for that case.

Verified model attributes and relationships:
- Listing: $listing->id, title, alias, url, summary, description, featured, views, owner_id, owner_name, owner_email, created, updated, and category_title.
- Comment/review: $comment->id, title, comments (the body), rating, url, comment_type, listing_id, owner_id, owner_name, owner_email, created, and updated.
- Relationships: $comment->listing->title, $comment->listing->url, $listing->user, $listing->listing_type, $comment->user, and $comment->listing_type.
- Dates are date objects or null. Guard them, for example: $listing->created?->format('M j, Y').
- Useful model checks include $listing->isPublished(), $listing->isPending(), $comment->isPublished(), $comment->isUserComment(), and $comment->isEditorComment().
- Use only attributes or methods listed here or elsewhere in the supplied documentation. If the legacy code needs another property, mark it "needs model/API verification" instead of inventing a replacement.

Conversion requirements:
- Use object access and the documented model methods; never use legacy array syntax.
- Escape output with {{ }} by default. Use {!! !!} only for deliberately trusted HTML and explain why.
- Guard nulls, invalid numeric data, multiple-value arrays, and division by zero.
- Preserve the behavior, but improve misleading variable names when the calculation reveals their real meaning.
- Flag legacy helper classes, route builders, inline scripts, click-to-search behavior, and unsupported variables instead of inventing replacements.
- If any unsupported dependency remains, say that the conversion is incomplete.

Return:
1. The converted Blade code.
2. A mapping of every legacy variable/helper to its replacement or "manual redesign required."
3. Assumptions and unresolved items.
4. Test cases covering blank, normal, invalid, and multiple values where relevant, plus listing and review context where relevant.

Field context:
[DESCRIBE FIELD OWNERSHIP, TYPES, AND SIBLING FIELDS]

Legacy PHP code:
[PASTE CODE HERE]

Verify an AI Conversion

Before using converted code on production, confirm:

  • [ ] No legacy array access remains on $listing, $comment, or $field.
  • [ ] Every field read intentionally uses a stored value or display label.
  • [ ] $output, $params, $fields, $image, route helpers, and scripts were redesigned or explicitly removed.
  • [ ] Arithmetic handles blank, non-numeric, zero, and negative values appropriately.
  • [ ] Multiple-value fields are treated as arrays.
  • [ ] Dynamic output is escaped unless trusted HTML is required.
  • [ ] Listing and review fields use the correct model.
  • [ ] The result was tested on staging with Early Access enabled.