search ]

Using Advanced Custom Fields without Frontend Dependency

The plugin Advanced Custom Fields provides a simple, visual interface for creating metaboxes. The result is intuitive and easy for clients to edit. ACF includes several functions for pulling field values in your templates, but I recommend not using them on the frontend.

For certain field types, such as images, ACF functions generate additional database queries. Core WordPress functions achieve the same result with significantly fewer queries.

You can monitor the number of database queries on any page using the Query Monitor plugin. In testing, switching from ACF functions to get_post_meta() reduced database queries from 146 to 22 on a single page.

Use get_post_meta Instead of get_field

There is no reason to use get_field() when you can use the WordPress core function get_post_meta().

Beyond the performance cost, ACF functions create a frontend dependency. If the plugin is deactivated or removed for any reason, visitors will see a fatal error and a blank page instead of your site.

Wrapping all ACF function calls in function_exists() prevents the fatal error, but visitors still will not see any of the metadata you entered through ACF – even though it remains in the database.

If you use core WordPress functions instead, your site continues to display all metadata normally even when ACF is inactive. The only thing you lose is the admin editing interface.

A site that shows content without an admin editing UI is far less severe than a site that does not load at all. Using ACF functions on the frontend creates a hard dependency on the plugin being active. Core WordPress functions eliminate this risk entirely.

The examples below show how to retrieve ACF data using get_post_meta() and get_option() instead of ACF functions. This approach is straightforward for standard fields but requires understanding how ACF stores data for more complex field types.

Repeater Field with get_post_meta

Suppose you allowed the client to add videos using the ACF Repeater Field, with fields for title, video URL, and thumbnail image.

Calling the repeater’s meta key returns the number of items in the repeater:

get_post_meta( get_the_ID(), 'my_videos', true );

You can then loop through each item and access its sub-field values. Here is how to display the videos without using get_field():

$videos = get_post_meta( get_the_ID(), 'my_videos', true );
if ( $videos ) {
    for ( $i = 0; $i < $videos; $i++ ) {
        $title     = esc_html( get_post_meta( get_the_ID(), 'my_videos_' . $i . '_title', true ) );
        $video     = esc_url( get_post_meta( get_the_ID(), 'my_videos_' . $i . '_video', true ) );
        $thumbnail = (int) get_post_meta( get_the_ID(), 'my_videos_' . $i . '_thumbnail', true );

        $thumbnail = $thumbnail
            ? wp_get_attachment_image( $thumbnail, 'medium' )
            : '<img src="' . get_stylesheet_directory_uri() . '/images/default-video.png" />';

        $class = ( 0 === $i % 2 ) ? 'one-half first' : 'one-half';

        echo '<div class="' . $class . '"><a href="' . $video . '">' . $thumbnail . '</a>' . $title . '</div>';
    }
}

Notice how the ACF Image field stores the attachment ID in the database. You retrieve the actual image markup using the WordPress function wp_get_attachment_image():

wp_get_attachment_image( $image_id, 'image_size' );

Options Page Data

When you add metaboxes to an ACF Options Page, the data is stored in the wp_options table, not as post meta. The key is your field name prefixed with options_.

If your options page has three fields, retrieve them like this:

$title       = esc_html( get_option( 'options_title' ) );
$button_text = esc_html( get_option( 'options_button_text' ) );
$button_url  = esc_url( get_option( 'options_button_url' ) );

if ( $title && $button_text && $button_url ) {
    echo '<div class="call-to-action"><div class="wrap"><p>' . $title . '</p><p><a href="' . $button_url . '" class="button">' . $button_text . '</a></p></div></div>';
}

Term Metadata

If you added a custom field called “Secondary Title” to categories, ACF stores this data in the wp_termmeta table (since ACF 5.5 and WordPress 4.4+). You can retrieve it using get_term_meta():

if ( ! is_category() ) {
    return;
}

$category = get_queried_object();
$subtitle = esc_html( get_term_meta( $category->term_id, 'my_subtitle', true ) );

if ( $subtitle ) {
    echo '<p class="subtitle">' . $subtitle . '</p>';
}

In ACF versions before 5.5, term metadata was stored in the wp_options table with the format [taxonomy]_[term_id]_[field_name]. Since ACF 5.5, term data is stored in the wp_termmeta table, accessible via the standard WordPress function get_term_meta().

FAQs

Common questions about using ACF without frontend dependency:

Is get_post_meta faster than get_field in ACF?
Yes. get_post_meta() retrieves the raw value directly from the database cache, while get_field() runs additional formatting logic and may trigger extra database queries depending on the field type. For image fields and repeater fields, the difference is most significant.
What happens to my site if ACF is deactivated?
If your templates use get_field() and ACF is deactivated, visitors will see a fatal error and a blank page. If you use get_post_meta() instead, your site continues to work normally because the data still exists in the database and WordPress core functions are always available.
How does ACF store repeater field data in the database?
ACF stores repeater field data as individual wp_postmeta rows. The parent repeater key stores the count of items. Each sub-field is stored with the pattern [repeater_name]_[index]_[sub_field_name]. For example, a repeater called my_videos with 3 items stores the count as my_videos = 3 and each title as my_videos_0_title, my_videos_1_title, etc.
Where does ACF store Options Page data?
ACF stores Options Page data in the wp_options table with your field name prefixed by options_. For example, a field named title is stored as options_title. Retrieve it using the WordPress function get_option('options_title') instead of get_field('title', 'option').
Does wrapping ACF functions in function_exists solve the dependency problem?
Partially. Wrapping ACF calls in function_exists('get_field') prevents the fatal error if ACF is deactivated, but all custom field data will simply not appear on the frontend. Using get_post_meta() instead means the data is always displayed regardless of whether ACF is active.

Summary

Using core WordPress functions like get_post_meta(), get_option(), and get_term_meta() instead of ACF’s get_field() eliminates the frontend dependency on the plugin, reduces database queries, and ensures your site continues to display content even if ACF is deactivated.

The trade-off is that you need to understand how ACF stores data in the database for each field type – but once you do, the approach is straightforward and more performant.

Here are some relevant posts:

Join the Discussion
2 Comments  ]
  • Pepin 2 June 2024, 17:38

    Thanks for this awesome tips. I use ACF a lot in my designs so this helps a lot. I have one question with Repeater. What if the repeater is in the ACF options page, how would I access it using the native WordPress functions.

    Do I call it say

    $social_links = get_option( ‘options_social_links’ ) ;

    Thanks
    PC

    • רועי יוסף 2 June 2024, 19:04

      Hi Pepin,

      Yes, Thats how you call it. You will obviously need to loop through the values of the repeater field after. So if you have a field named txt in the repeater field you can display it like that:

      $social_links = esc_html( get_option( 'options_social_links' ) );
      for( $i = 0; $i < $social_links; $i++ ) {
      	$txt = esc_html( get_post_meta( get_the_ID(), 'options_social_links_' . $i . '_txt', true ) );
      	echo $txt;
      }

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!

Savvy WordPress Development official logo