Read Only
4 min read
Description #
Displays a read-only value while still saving the field normally.
The field renders a locked UI but persists its value using a hidden input, ensuring full compatibility with ACF saving logic, REST API output, and frontend forms.
Use Cases #
- Display system-generated values
- Show calculated or derived data
- Expose synchronized API values
- Prevent accidental edits on critical fields
- Display technical identifiers such as IDs, tokens, or hashes
Field Preview #
Locked value rendered as a box, inline text, or code block.
The value is visible but not editable.
How to Use #
- Add the Read Only (Locked) field to a Field Group
- Choose the desired Display style
- Optionally enable the Copy button
- Optionally select another field as the display source
- Save the Field Group and edit a post
No custom code is required.
Field Settings #
| Setting | Description | Default |
|---|---|---|
| Display style | Visual rendering mode (box, inline, code) | box |
| Placeholder | Text shown when the value is empty | Empty |
| Show copy button | Enables copy-to-clipboard button | Enabled |
| Display source | Select which value is displayed | This field value |
| Other field name/key | Field to mirror (display-only) | Empty |
Value & Storage #
- Saved as: Post meta
- Storage type: Hidden input
- Return format:
string | null - Formatting: Display-only formatting does not affect stored value
Arrays and objects are automatically converted to JSON strings.
Output Examples #
PHP (Theme / Plugin) #
$value = get_field('my_read_only_field');
echo esc_html($value);
Twig #
{{ fn('get_field', 'my_read_only_field') }}
Compatibility #
- Repeaters
- Flexible Content
- Options Pages
- Frontend forms (
acf_form) - REST API
- Multisite
Hooks (Developer) #
Hooks Summary #
| Hook | Type | Purpose |
|---|---|---|
cfb/field/read_only/defaults | Filter | Modify default settings |
cfb/field/read_only/supports | Filter | Modify ACF support flags |
cfb/field/read_only/field_type_info | Filter | Override field metadata |
cfb/field/read_only/save_value | Filter | Modify value before saving |
cfb/field/read_only/display_value_raw | Filter | Modify raw display value |
cfb/field/read_only/display_value_string | Filter | Modify final display output |
cfb/field/read_only/show_copy | Filter | Control copy button visibility |
cfb/field/read_only/effective_post_id | Filter | Control display context |
cfb/field/read_only/before_render | Action | Run logic before render |
cfb/field/read_only/after_render | Action | Run logic after render |
Filters #
Defaults #
Filter: cfb/field/read_only/defaults
Purpose: Override default field configuration globally
When: You want consistent defaults across all instances
add_filter('cfb/field/read_only/defaults', function ($defaults) {
$defaults['display_style'] = 'inline';
$defaults['show_copy'] = 0;
return $defaults;
});
Supports #
Filter: cfb/field/read_only/supports
Purpose: Control ACF support flags such as required
When: Validation or compatibility needs adjustment
add_filter('cfb/field/read_only/supports', function ($supports) {
$supports['required'] = false;
return $supports;
});
Field Type Info #
Filter: cfb/field/read_only/field_type_info
Purpose: Override field metadata such as visibility or REST support
When: Customizing how the field appears in the picker
add_filter('cfb/field/read_only/field_type_info', function ($info) {
$info['public'] = false;
return $info;
});
Save Value #
Filter: cfb/field/read_only/save_value
Purpose: Modify the value before it is saved
When: Normalizing or sanitizing data
add_filter(
'cfb/field/read_only/save_value',
fn ($value) => strtoupper($value)
);
Display Value (Raw) #
Filter: cfb/field/read_only/display_value_raw
Purpose: Modify the value before string conversion
When: Working with numbers, arrays, or objects
add_filter(
'cfb/field/read_only/display_value_raw',
fn ($display) => is_numeric($display) ? number_format($display) : $display
);
Display Value (String) #
Filter: cfb/field/read_only/display_value_string
Purpose: Modify the final displayed string
When: Adding prefixes, labels, or formatting
add_filter(
'cfb/field/read_only/display_value_string',
fn ($display) => 'ID: ' . $display
);
Copy Button #
Filter: cfb/field/read_only/show_copy
Purpose: Control copy button visibility
When: Restricting copy access by role or context
add_filter(
'cfb/field/read_only/show_copy',
fn () => current_user_can('manage_options')
);
Effective Post ID #
Filter: cfb/field/read_only/effective_post_id
Purpose: Define the context used to read mirrored fields
When: Working with options pages, users, or terms
add_filter(
'cfb/field/read_only/effective_post_id',
fn () => 'options'
);
Actions #
Before Render #
Action: cfb/field/read_only/before_render
Runs immediately before rendering the field UI
add_action('cfb/field/read_only/before_render', function ($field) {
// Pre-render logic
});
After Render #
Action: cfb/field/read_only/after_render
Runs after the field UI has been rendered
add_action(
'cfb/field/read_only/after_render',
function ($field, $value, $display) {
// Post-render logic
},
10,
3
);
Assets #
Scripts and styles are automatically enqueued for admin edit screens and frontend forms using acf_form().
Customization #
add_filter(
'cfb/field/read_only/enqueue_script_args',
function ($args) {
$args['deps'][] = 'acf-input';
return $args;
}
);
REST API #
- Schema:
string | null - Output: Raw stored value
{
"my_read_only_field": "ABC-123"
}
Security & Escaping #
- Output is escaped internally
escaping_htmlsupport is enabled- Template output should still be escaped when applicable
Notes / Limitations #
- Not a disabled input
- Display source does not overwrite stored value
- Formatting affects display only
Changelog #
- 1.0.0 — Initial release