Skip to content

Instantly share code, notes, and snippets.

@rheinardkorf
Last active October 1, 2021 16:02
Embed
What would you like to do?
Out of the box ACF is taxing on your site performance, but also CPU load if you have large sites (think 10k+ posts). There are ways to improve ACF by doing things like batch writes or pre-fetching values into the ACF Store. As I create some of these techniques I will add them to this Gist. This will work okay'ish without an object cache, but its…
<?php
/**
* This file contains some hooks to improve ACF performance.
*
* @package rheinardkorf
*/
add_filter(
'acf/pre_load_value',
function( $meta, $post_id, $field ) {
$store = acf_get_store( 'values' );
// Prefetch options into ACF Store.
if ( 'options' === $post_id ) {
// Prefetch site options.
if ( ! $store->has( 'prefetched:options' ) ) {
global $wpdb;
$like = 'option_%';
$prefetch_cache_key = md5( 'acf/pre_load_value/prefetched:options' );
$results = wp_cache_get( $prefetch_cache_key );
if ( empty( $results ) ) {
$results = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->options WHERE option_name LIKE %s", $like ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
// Let the Object Cache LRU take care of expiry.
wp_cache_set( $prefetch_cache_key, $results );
}
foreach ( $results as $result ) {
$key = str_replace( 'options_', '', $result->option_name );
$key = "options:$key";
$store->set( $key, $result->option_value );
}
$store->set( 'prefetched:options', true );
}
} else {
// Prefetch object meta.
if ( ! $store->has( "prefetched:$post_id" ) ) {
$decoded = acf_decode_post_id( $post_id );
$meta_id = $decoded['id'];
$meta_type = $decoded['type'];
$prefetch_cache_key = md5( "acf/pre_load_value/prefetched:$post_id" );
$meta_data = wp_cache_get( $prefetch_cache_key );
if ( empty( $meta_data ) ) {
$meta_data = get_metadata( $meta_type, $meta_id );
// Let the Object Cache LRU take care of expiry.
wp_cache_set( $prefetch_cache_key, $meta_data );
}
foreach ( $meta_data as $field_name => $value ) {
$real_value = is_array( $value ) && 1 === count( $value ) ? array_pop( $value ) : $value;
// Ignore hidden keys.
if ( preg_match( '/^_/', $field_name ) ) {
continue;
}
$store->set( "$post_id:$field_name", $real_value );
}
$store->set( "prefetched:$post_id", true );
}
}
// If value is already fetched then return that value.
$field_name = $field['name'];
if ( $store->has( "$post_id:$field_name" ) ) {
return $store->get( "$post_id:$field_name" );
}
// Fallback.
return $meta;
},
10,
3
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment