Skip to content

Instantly share code, notes, and snippets.

@arenagroove
Created March 17, 2026 05:29
Show Gist options
  • Select an option

  • Save arenagroove/1cf3d9746623b6c9cb1e41ee202f4aa1 to your computer and use it in GitHub Desktop.

Select an option

Save arenagroove/1cf3d9746623b6c9cb1e41ee202f4aa1 to your computer and use it in GitHub Desktop.
LR ACF Suite, MU utility plugin for managing ACF/ACFE behavior across projects.
<?php
/**
* Plugin Name: LR ACF Suite
* Description: ACF/ACFE management — performance, field-group collapse, permissions and HTML escaping. Configurable via Settings → LR ACF Suite.
* Version: 1.1.1
* Author: Luis Martinez
* Author URI: https://www.lessrain.com
*/
if ( ! defined( 'ABSPATH' ) ) exit;
// =============================================================================
// 0 Constants
// =============================================================================
define( 'LR_ACF_SUITE_VER', '1.1.1' );
define( 'LR_ACF_SUITE_OPTION', 'lr_acf_suite' );
define( 'LR_ACF_SUITE_NONCE', 'lr_acf_suite_save' );
// =============================================================================
// 1 Settings helpers
// =============================================================================
function lr_acf_suite_defaults(): array {
return [
// Performance
'perf_remove_autop' => 1,
'perf_remove_autoformat' => 1,
'perf_disable_media' => 1,
'perf_disable_shortcodes' => 1,
'perf_acf_json' => 1,
'perf_disable_post_types' => 1,
'perf_disable_options_ui' => 1,
'perf_disable_field_tabs' => 1,
'perf_disable_script_translations' => 1,
'perf_disable_clone_templates' => 1,
// Collapse
'collapse_enabled' => 1,
'collapse_groups' => implode( "\n", [
'group_67375c2b7e4bb',
'group_67a0d08aa55b0',
'group_65681cb6122f8',
'group_665fe96c7c14a',
'group_645e45603884f',
'group_694cd3f4199e5',
] ),
// Permissions
'perms_caps_enabled' => 1,
'perms_user_role_fix' => 1,
// Escaping
'escape_unsafe_html' => 0,
];
}
/**
* Load saved settings merged with defaults.
* Pass $refresh = true to bust the static cache (e.g. after an option update
* within the same request).
*/
function lr_acf_suite_settings( bool $refresh = false ): array {
static $cache = null;
if ( $refresh || $cache === null ) {
$saved = get_option( LR_ACF_SUITE_OPTION, [] );
$cache = array_merge( lr_acf_suite_defaults(), is_array( $saved ) ? $saved : [] );
}
return $cache;
}
function lr_acf_suite_get( string $key ) {
return lr_acf_suite_settings()[ $key ] ?? null;
}
/**
* Parse the collapse_groups textarea into a normalised array of 'group_xxx' IDs.
* Accepts both 'group_xxx' and 'acf-group_xxx' — strips the 'acf-' prefix if present.
* FIX v1.1.1: validates each entry against the expected ACF key pattern before
* accepting it, making the schema explicit rather than just stripping bad chars.
* Result is statically cached for the request.
*/
function lr_acf_suite_collapse_ids(): array {
static $ids = null;
if ( $ids !== null ) return $ids;
$raw = (string) lr_acf_suite_get( 'collapse_groups' );
$ids = [];
foreach ( explode( "\n", $raw ) as $line ) {
$id = trim( $line );
if ( $id === '' ) continue;
if ( strpos( $id, 'acf-' ) === 0 ) {
$id = substr( $id, 4 );
}
// Only accept valid ACF group key format: group_[alphanumeric]
if ( ! preg_match( '/^group_[a-z0-9]+$/i', $id ) ) continue;
$ids[] = $id;
}
$ids = array_values( array_unique( $ids ) );
return $ids;
}
// =============================================================================
// 2 Performance
// =============================================================================
// Attached at file load — before scripts are registered — intentionally outside
// any hook. MU plugins load early enough that this is safe and correct.
if ( lr_acf_suite_get( 'perf_disable_script_translations' ) ) {
add_filter( 'load_script_translations', '__return_false' );
}
add_action( 'plugins_loaded', function () {
if ( ! function_exists( 'acf' ) ) return;
$s = lr_acf_suite_settings();
if ( $s['perf_remove_autop'] )
add_filter( 'acf/settings/remove_wp_autop', '__return_true' );
if ( $s['perf_remove_autoformat'] )
add_filter( 'acf/settings/remove_wp_autoformat', '__return_true' );
if ( $s['perf_disable_media'] )
add_filter( 'acf/settings/enqueue_media', '__return_false' );
if ( $s['perf_disable_shortcodes'] )
add_filter( 'acf/settings/enable_shortcode_support', '__return_false' );
if ( $s['perf_acf_json'] ) {
add_filter( 'acf/settings/save_json', function () {
return get_stylesheet_directory() . '/acf-json';
} );
// Append to the existing path list rather than replacing it, so other
// plugins or parent themes can still register their own JSON paths.
// FIX v1.1.1: also guard against duplicates if the filter runs more
// than once (e.g. theme + plugin both registering the same helper).
add_filter( 'acf/settings/load_json', function ( array $paths ) {
$path = get_stylesheet_directory() . '/acf-json';
if ( ! in_array( $path, $paths, true ) ) {
$paths[] = $path;
}
return $paths;
} );
}
if ( $s['perf_disable_post_types'] )
add_filter( 'acf/settings/enable_post_types', '__return_false' );
if ( $s['perf_disable_options_ui'] )
add_filter( 'acf/settings/enable_options_pages_ui', '__return_false' );
if ( $s['perf_disable_field_tabs'] )
add_filter( 'acf/field_group/disable_field_settings_tabs', '__return_true' );
if ( $s['perf_disable_clone_templates'] )
add_filter( 'acf/settings/clone', '__return_false' );
} );
// =============================================================================
// 3 Collapse Groups
// =============================================================================
add_action( 'current_screen', function ( WP_Screen $screen ) {
if ( ! lr_acf_suite_get( 'collapse_enabled' ) ) return;
if ( $screen->base !== 'post' && $screen->base !== 'post-new' ) return;
$ids = lr_acf_suite_collapse_ids();
if ( empty( $ids ) ) return;
// WordPress stores metabox open/closed state as 'acf-group_xxx'
$metabox_ids = array_map( fn( $id ) => 'acf-' . $id, $ids );
add_filter(
'get_user_option_closedpostboxes_' . $screen->id,
function ( $closed ) use ( $metabox_ids ) {
if ( ! is_array( $closed ) ) $closed = [];
foreach ( $metabox_ids as $box_id ) {
if ( ! in_array( $box_id, $closed, true ) ) {
$closed[] = $box_id;
}
}
return $closed;
}
);
// Conditionally attach JS fallback only on relevant screens — avoids running
// get_current_screen() inside the footer hook on every admin page.
add_action( 'admin_print_footer_scripts', 'lr_acf_suite_collapse_js' );
} );
/**
* JS fallback: re-collapses any group that another script may have re-opened
* after DOMContentLoaded. Registered only on post/post-new screens (see above).
*/
function lr_acf_suite_collapse_js(): void {
$ids = lr_acf_suite_collapse_ids();
if ( empty( $ids ) ) return;
?>
<script>
(function () {
var ids = <?php echo wp_json_encode( $ids ); ?>;
function collapseGroups() {
ids.forEach( function ( id ) {
var box = document.getElementById( 'acf-' + id );
if ( ! box ) return;
box.classList.add( 'closed' );
var btn = box.querySelector( '.handlediv' );
if ( btn ) btn.setAttribute( 'aria-expanded', 'false' );
} );
}
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', collapseGroups );
} else {
collapseGroups();
}
}());
</script>
<?php
}
// =============================================================================
// 4 Permissions
// =============================================================================
add_action( 'init', function () {
if ( ! lr_acf_suite_get( 'perms_caps_enabled' ) ) return;
$role = get_role( 'administrator' );
if ( ! $role ) return;
// Guard with has_cap() to avoid a DB write (update_option on wp_user_roles)
// on every request when capabilities are already present.
foreach ( [ 'acf_edit_fields', 'acf_edit_field_groups', 'acfe_admin_settings', 'acfe_admin_tools' ] as $cap ) {
if ( ! $role->has_cap( $cap ) ) {
$role->add_cap( $cap );
}
}
} );
add_filter( 'acf/location/rule_match/user_role', function ( $match, $rule, $screen ) {
if ( ! lr_acf_suite_get( 'perms_user_role_fix' ) ) return $match;
if ( ! is_user_logged_in() ) return false;
$roles = (array) wp_get_current_user()->roles;
return $rule['operator'] === '=='
? in_array( $rule['value'], $roles, true )
: ! in_array( $rule['value'], $roles, true );
}, 10, 3 );
// =============================================================================
// 5 HTML Escaping
// =============================================================================
add_action( 'plugins_loaded', function () {
if ( ! lr_acf_suite_get( 'escape_unsafe_html' ) ) return;
add_filter( 'acf/shortcode/allow_unsafe_html', '__return_true' );
add_filter( 'acf/the_field/allow_unsafe_html', '__return_true' );
} );
// =============================================================================
// 6 Admin — menu + save handler
// =============================================================================
add_action( 'admin_menu', function () {
add_options_page(
'LR ACF Suite',
'LR ACF Suite',
'manage_options',
'lr-acf-suite',
'lr_acf_suite_render_page'
);
} );
add_action( 'admin_init', function () {
if ( ! isset( $_POST['lr_acf_suite_submit'] ) ) return;
if ( ! check_admin_referer( LR_ACF_SUITE_NONCE ) ) wp_die( 'Security check failed.' );
if ( ! current_user_can( 'manage_options' ) ) wp_die( 'Insufficient permissions.' );
$bool_keys = [
'perf_remove_autop', 'perf_remove_autoformat', 'perf_disable_media',
'perf_disable_shortcodes', 'perf_acf_json', 'perf_disable_post_types',
'perf_disable_options_ui', 'perf_disable_field_tabs',
'perf_disable_script_translations', 'perf_disable_clone_templates',
'collapse_enabled', 'perms_caps_enabled', 'perms_user_role_fix',
'escape_unsafe_html',
];
$new = [];
foreach ( $bool_keys as $key ) {
$new[ $key ] = isset( $_POST[ $key ] ) ? 1 : 0;
}
// Strip characters outside the ACF group key alphabet before storing.
// The pattern-level validation in lr_acf_suite_collapse_ids() is the real
// gate; this just keeps the stored value clean.
$raw_groups = wp_unslash( $_POST['collapse_groups'] ?? '' );
$new['collapse_groups'] = preg_replace( '/[^a-zA-Z0-9_\n\-]/', '', $raw_groups );
update_option( LR_ACF_SUITE_OPTION, $new );
wp_safe_redirect( admin_url( 'options-general.php?page=lr-acf-suite&saved=1' ) );
exit;
} );
// =============================================================================
// 7 Admin — styles (only injected on the plugin page)
// =============================================================================
add_action( 'admin_head', function () {
$screen = get_current_screen();
if ( ! $screen || $screen->id !== 'settings_page_lr-acf-suite' ) return;
echo '<style>' . lr_acf_suite_css() . '</style>';
} );
function lr_acf_suite_css(): string { return '
.lr-suite{max-width:860px}
.lr-suite h1{display:flex;align-items:center;gap:10px;font-size:1.4rem;margin-bottom:4px}
.lr-suite__version{font-size:11px;background:#e8f0fe;color:#2271b1;padding:2px 9px;border-radius:99px;font-weight:600;letter-spacing:.02em}
.lr-suite__subtitle{color:#646970;margin-top:0;margin-bottom:28px}
.lr-suite__card{background:#fff;border:1px solid #dcdcde;border-radius:6px;margin-bottom:20px;overflow:hidden}
.lr-suite__card-head{display:flex;align-items:center;gap:14px;padding:16px 22px;border-bottom:1px solid #f0f0f1}
.lr-suite__card-icon{width:34px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.lr-suite__card-icon svg{width:18px;height:18px}
.lr-suite__card-title{font-size:.9375rem;font-weight:600;margin:0;color:#1d2327;line-height:1.3}
.lr-suite__card-desc{font-size:12px;color:#646970;margin:3px 0 0;line-height:1.4}
.lr-suite__card-body{padding:4px 0}
.lr-suite__card--perf .lr-suite__card-icon{background:#e8f0fe;color:#2271b1}
.lr-suite__card--collapse .lr-suite__card-icon{background:#f0ebff;color:#7c3aed}
.lr-suite__card--perms .lr-suite__card-icon{background:#e8faf1;color:#0d7a4e}
.lr-suite__card--escape .lr-suite__card-icon{background:#fff3cd;color:#9a6700}
.lr-row{display:flex;align-items:flex-start;gap:16px;padding:11px 22px;border-bottom:1px solid #f6f7f7}
.lr-row:last-child{border-bottom:0}
.lr-row__label{flex:1;min-width:0}
.lr-row__name{font-size:13px;font-weight:500;color:#1d2327;display:block;line-height:1.4}
.lr-row__hint{font-size:11.5px;color:#646970;display:block;margin-top:2px;line-height:1.5}
.lr-row__hint code,.lr-groups-hint code,.lr-warning code{font-size:11px;background:#f6f7f7;padding:1px 5px;border-radius:3px;color:#50575e}
.lr-toggle{position:relative;display:inline-flex;align-items:center;cursor:pointer;flex-shrink:0;margin-top:2px}
.lr-toggle input{position:absolute;opacity:0;width:0;height:0;pointer-events:none}
.lr-toggle__track{width:38px;height:20px;background:#c3c4c7;border-radius:10px;position:relative;transition:background .15s ease}
.lr-toggle__track::after{content:"";position:absolute;top:3px;left:3px;width:14px;height:14px;background:#fff;border-radius:50%;box-shadow:0 1px 3px rgba(0,0,0,.25);transition:transform .15s ease}
.lr-toggle input:checked + .lr-toggle__track{background:#2271b1}
.lr-toggle input:checked + .lr-toggle__track::after{transform:translateX(18px)}
.lr-toggle input:focus-visible + .lr-toggle__track{outline:2px solid #2271b1;outline-offset:2px}
.lr-toggle--danger input:checked + .lr-toggle__track{background:#b32d2e}
.lr-groups-area{padding:14px 22px 18px;border-bottom:1px solid #f6f7f7}
.lr-groups-area label{display:block;font-size:11px;font-weight:700;color:#50575e;margin-bottom:6px;text-transform:uppercase;letter-spacing:.05em}
.lr-groups-area textarea{width:100%;max-width:420px;font-family:monospace;font-size:12.5px;border:1px solid #dcdcde;border-radius:4px;padding:8px 10px;resize:vertical;color:#1d2327;line-height:1.75}
.lr-groups-area textarea:focus{border-color:#2271b1;outline:2px solid #2271b1;outline-offset:0;box-shadow:none}
.lr-groups-hint{font-size:11.5px;color:#646970;margin-top:7px;line-height:1.5}
.lr-warning{display:flex;gap:10px;background:#fff8e5;border:1px solid #f0c33c;border-radius:4px;padding:10px 14px;margin:14px 22px 4px;font-size:12px;color:#7a5c00;line-height:1.5}
.lr-warning svg{flex-shrink:0;width:15px;height:15px;margin-top:1px}
.lr-suite__footer{display:flex;align-items:center;gap:14px;padding:6px 0 28px}
.lr-suite__footer .button-primary{padding:0 20px;height:36px;font-size:13px}
.lr-saved{font-size:12.5px;color:#0d7a4e;font-weight:500}
.lr-saved::before{content:"✓ "}
'; }
// =============================================================================
// 8 Admin — page render
// =============================================================================
function lr_acf_suite_render_page(): void {
if ( ! current_user_can( 'manage_options' ) ) return;
$s = lr_acf_suite_settings();
$saved = isset( $_GET['saved'] );
$icon = [
'perf' => '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z" clip-rule="evenodd"/></svg>',
'collapse'=> '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M14.707 12.707a1 1 0 01-1.414 0L10 9.414l-3.293 3.293a1 1 0 01-1.414-1.414l4-4a1 1 0 011.414 0l4 4a1 1 0 010 1.414z" clip-rule="evenodd"/></svg>',
'perms' => '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 2a5 5 0 00-5 5v1H4a2 2 0 00-2 2v6a2 2 0 002 2h12a2 2 0 002-2v-6a2 2 0 00-2-2h-1V7a5 5 0 00-5-5zm3 6V7a3 3 0 10-6 0v1h6zm-3 3a1 1 0 011 1v2a1 1 0 11-2 0v-2a1 1 0 011-1z" clip-rule="evenodd"/></svg>',
'escape' => '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/></svg>',
'warn' => '<svg viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"/></svg>',
];
$allowed_hint = [ 'code' => [] ];
?>
<div class="wrap lr-suite">
<h1>
LR ACF Suite
<span class="lr-suite__version">v<?php echo esc_html( LR_ACF_SUITE_VER ); ?></span>
</h1>
<p class="lr-suite__subtitle">Unified ACF/ACFE configuration — Less Rain projects.</p>
<?php if ( $saved ): ?>
<div class="notice notice-success is-dismissible"><p>Settings saved.</p></div>
<?php endif; ?>
<form method="post">
<?php wp_nonce_field( LR_ACF_SUITE_NONCE ); ?>
<?php
$row = function ( string $key, string $name, string $hint ) use ( $s, $allowed_hint ): void {
printf(
'<div class="lr-row">
<div class="lr-row__label">
<span class="lr-row__name">%s</span>
<span class="lr-row__hint">%s</span>
</div>
<label class="lr-toggle">
<input type="checkbox" name="%s" value="1"%s>
<span class="lr-toggle__track"></span>
</label>
</div>',
esc_html( $name ),
wp_kses( $hint, $allowed_hint ),
esc_attr( $key ),
checked( $s[ $key ] ?? 0, 1, false )
);
};
?>
<!-- ── PERFORMANCE ─────────────────────────────────────────── -->
<div class="lr-suite__card lr-suite__card--perf">
<div class="lr-suite__card-head">
<div class="lr-suite__card-icon"><?php echo $icon['perf']; ?></div>
<div>
<p class="lr-suite__card-title">Performance</p>
<p class="lr-suite__card-desc">Reduce ACF admin overhead in large Flexible Content setups. All settings are admin-only — no front-end impact.</p>
</div>
</div>
<div class="lr-suite__card-body">
<?php
$row( 'perf_remove_autop', 'Remove wpautop', 'Strips WordPress automatic paragraph formatting from the WYSIWYG editor.' );
$row( 'perf_remove_autoformat', 'Remove autoformat', 'Disables ACF\'s automatic text formatting on field values.' );
$row( 'perf_disable_media', 'Disable media library enqueue', 'Skips loading WP media scripts on edit screens. Speeds up editor load when no image/file fields are visible.' );
$row( 'perf_disable_shortcodes', 'Disable shortcode support', 'Turns off ACF\'s built-in shortcode parser.' );
$row( 'perf_acf_json', 'Enable ACF JSON sync', 'Appends <code>theme/acf-json/</code> to ACF\'s JSON load paths and sets it as the save target. Other registered paths (plugins, child themes) are preserved. Duplicate paths are deduplicated automatically.' );
$row( 'perf_disable_post_types', 'Disable Post Types UI', 'Hides the ACF Post Types registration panel from the admin menu.' );
$row( 'perf_disable_options_ui', 'Disable Options Pages UI', 'Hides the ACF Options Pages registration panel from the admin menu.' );
$row( 'perf_disable_field_tabs', 'Disable field settings tabs', 'Removes tab navigation inside the field settings panel, reducing DOM weight in large field groups.' );
$row( 'perf_disable_script_translations','Disable script translations', 'Prevents WordPress loading <code>.json</code> translation files for scripts. Reduces HTTP requests in multilingual setups.' );
$row( 'perf_disable_clone_templates', 'Remove hidden clone templates', 'Stops ACF outputting hidden clone HTML templates — reduces DOM weight when using the Clone field.' );
?>
</div>
</div>
<!-- ── COLLAPSE GROUPS ─────────────────────────────────────── -->
<div class="lr-suite__card lr-suite__card--collapse">
<div class="lr-suite__card-head">
<div class="lr-suite__card-icon"><?php echo $icon['collapse']; ?></div>
<div>
<p class="lr-suite__card-title">Collapse Field Groups</p>
<p class="lr-suite__card-desc">Force specific ACF field groups to load in a collapsed state — instantly, without flicker.</p>
</div>
</div>
<div class="lr-suite__card-body">
<?php $row( 'collapse_enabled', 'Enable collapse', 'Activates the PHP user-option override (no flicker) plus a JS fallback for all group IDs listed below.' ); ?>
<div class="lr-groups-area">
<label for="lr-collapse-groups">Field Group IDs — one per line</label>
<textarea id="lr-collapse-groups" name="collapse_groups" rows="7" spellcheck="false"><?php echo esc_textarea( $s['collapse_groups'] ?? '' ); ?></textarea>
<p class="lr-groups-hint">
Use the ACF group key, e.g. <code>group_645e45603884f</code>. The <code>acf-</code> prefix is accepted and stripped automatically. Lines not matching <code>group_[alphanumeric]</code> are silently ignored.<br>
Find the key in the URL when editing a field group (<code>?post=NNN</code>), or inside your <code>acf-json/*.json</code> files under the <code>"key"</code> property.
</p>
</div>
</div>
</div>
<!-- ── PERMISSIONS ─────────────────────────────────────────── -->
<div class="lr-suite__card lr-suite__card--perms">
<div class="lr-suite__card-head">
<div class="lr-suite__card-icon"><?php echo $icon['perms']; ?></div>
<div>
<p class="lr-suite__card-title">Permissions</p>
<p class="lr-suite__card-desc">Missing ACF/ACFE capability fixes for the administrator role and location rules.</p>
</div>
</div>
<div class="lr-suite__card-body">
<?php
$row(
'perms_caps_enabled',
'Add ACF/ACFE capabilities to Administrator',
'Grants <code>acf_edit_fields</code>, <code>acf_edit_field_groups</code>, <code>acfe_admin_settings</code> and <code>acfe_admin_tools</code> — only writes to the DB if a capability is not already present. Disabling stops re-adding them but does not revoke existing capabilities.'
);
$row(
'perms_user_role_fix',
'Fix user_role location rules globally',
'Extends ACF\'s location rule matching so <code>user_role</code> conditions evaluate correctly on all admin screens, not only the user profile screen.'
);
?>
</div>
</div>
<!-- ── HTML ESCAPING ───────────────────────────────────────── -->
<div class="lr-suite__card lr-suite__card--escape">
<div class="lr-suite__card-head">
<div class="lr-suite__card-icon"><?php echo $icon['escape']; ?></div>
<div>
<p class="lr-suite__card-title">HTML Escaping</p>
<p class="lr-suite__card-desc">Control ACF's security escaping for field output.</p>
</div>
</div>
<div class="lr-suite__card-body">
<div class="lr-warning">
<?php echo $icon['warn']; ?>
<span>Enabling this allows raw HTML — including <code>&lt;script&gt;</code> tags — to be output by <code>the_field()</code> and ACF shortcodes. Only enable if all field content is entered by trusted editors.</span>
</div>
<div class="lr-row">
<div class="lr-row__label">
<span class="lr-row__name">Allow unsafe HTML in ACF output</span>
<span class="lr-row__hint">Bypasses ACF's <code>esc_html()</code> sanitization via <code>acf/the_field/allow_unsafe_html</code> and <code>acf/shortcode/allow_unsafe_html</code>. Off by default.</span>
</div>
<label class="lr-toggle lr-toggle--danger">
<input type="checkbox" name="escape_unsafe_html" value="1" <?php checked( $s['escape_unsafe_html'] ?? 0, 1 ); ?>>
<span class="lr-toggle__track"></span>
</label>
</div>
</div>
</div>
<!-- ── FOOTER ──────────────────────────────────────────────── -->
<div class="lr-suite__footer">
<button type="submit" name="lr_acf_suite_submit" class="button button-primary button-large">Save Settings</button>
<?php if ( $saved ): ?>
<span class="lr-saved">Settings saved</span>
<?php endif; ?>
</div>
</form>
</div>
<?php
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment