Skip to content

Plugins

Advanced Custom Fields (ACF 5)

Advanced Custom Fields (ACF) is a popular plugin that many VIP clients choose to use on their sites. However, ACF has not undergone a full, line-byline review for use on WordPress VIP. Clients wishing to use ACF accept the security and performance risks of using it. This page outlines some additional steps needed to make ACF more secure and performant, but should not be interpreted as the equivalent of a line-by-line review, or VIP’s approval of the plugin.

Please note that while ACF version 5 can be used on most VIP Go sites (at customer discretion), ACF 4 should not be used.

Steps to avoid performance issues

When using ACF 5 and ACF 5 Pro, several additional steps are needed in order to make ACF secure, and avoid performance issues:

  • Hide the Admin UI
  • Define fields in PHP
  • Use taxonomies for searchable fields
  • Avoid the_field and escape all output via get_field
  • Secure fields that allow arbitrary output

Hide the ACF Admin UI

The fields UI can be used to add arbitrary fields, including unsafe fields. For example it can allow an admin to display the passwords of users. You can disable the UI using this filter:

add_filter( 'acf/settings/show_admin', '__return_false' );

Define fields in PHP

In order to make sure that all ACF usage is secure, define the fields in PHP or local JSON, rather than at runtime. This way they remain versioned and safe. This can be done via the import export menu of a local developer environment to set up the fields available and export them to PHP.

Documentation on how to do this can be found on the ACF website.

Alternatively, fields can be defined via the local JSON feature as described here, but keep in mind: saving local JSON will not work because the WordPress VIP filesystem is read only, and it would also bypass the security benefits

Being mindful of taxonomy term storage

If an ACF field is going to be queried, filtered, or searched for in a post query, use the taxonomy data checkbox so that the field is stored as a term, not a post meta value. This ensures performance is not impacted by expensive post meta queries while generating HTML for readers.

the_field and output escaping

the_field (which echoes field values) has no ability to know the context it’s called in, so it doesn’t know if it should be using esc_url, esc_attr or wp_kses_post, which makes it a security risk; it should never be used. Instead, use get_field in combination with an escaping function:

$url = get_field( 'custom_link' );
echo esc_url( $url );

Flexible content is the exception to this, and should be clearly marked when used in code via inline comments.

Fields that use arbitrary output

If field types that allow arbitrary output are to be used, they must be accounted for in the acf/format_value and equivalent filters such as acf/format_value/type=textarea.

For example:

function vip_make_acf_text_areas_safe( $value, $post_id, $field ) {
	return wp_kses_post( $value );
}

add_filter( 'acf/format_value/type=textarea', 'vip_make_acf_text_areas_safe', 10, 3 );

This way, different escaping can be applied via different '$field' values. Alternatively, if all fields of that type use the same escaping, this can be done instead:

add_filter( 'acf/format_value/type=textarea', 'wp_kses_post', 10, 1 );

More information on format_value can be found here.

Working with image fields

Due to how VIP Go handles intermediate image sizes, when working with image fields that use ‘Image Array’ or ‘Image ID’ return format, the ‘sizes’ array will be empty in the field value. So instead of directly accessing your preferred file size URL with $field_value['sizes']['large'], themes will need to use the returned image ID to retrieve the correct URL:

<?php

$my_image_field = get_field('image');

?>

<img src="<?php echo esc_url( wp_get_attachment_image_src( $my_image_field['ID'], 'large' )[0] );?>" alt="<?php echo esc_attr( $my_image_field['alt'] ); ?>" />

Last updated: March 16, 2022