Update 8/30/12: As Sean Butze pointed out in the comments, the $id
parameter of grunwell_get_custom_field()
should be able to accept strings as well as integers to work with the ACF Options Page add-on. Furthermore, the_repeater_field()
has been deprecated since ACF version 3.3.4.
If you regularly build WordPress sites and haven’t tried Elliot Condon’s Advanced Custom Fields plugin, I’d highly recommend checking it out as it will forever change the way you use WordPress.
With Advanced Custom Fields, you can easily define custom field templates for particular post types, page templates, or even individual posts/pages. With the help of some paid add-ons, you can quickly add support for repeaters (useful for carousels/sliders), a site options page (hello Google Analytics profile ID), or any of a dozen other official and third-party add-ons.
Advanced Custom Fields particularly shines when handling WordPress custom post types. If you look at the source of this site, I’m using a custom post type of grunwell_portfolio
for all of my portfolio entries. With Advanced Custom Fields I’m able to register metaboxes for client information, agency information, and manage the screenshot carousel from the post edit screen.
Wrapper functions
In order to retrieve ACF data, Elliot has built-in the get_field()
, the_repeater_field()
, and the_sub_field()
functions. They work fine, but since a lot of my projects are client sites that may not always be under my control, it’s important to ensure that if ACF is ever broken or deactivated for any reason the site won’t completely blow up. In order to achieve this, I have a couple wrapper functions that I’ve written and refined over several projects to streamline the process:
Individual custom fields
Since I use ACF so heavily, it’s not really feasible to wrap every call in if ( function_exists( 'get_field' ) ) :
. Instead, I wrote this wrapper function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
/** * Get a custom field stored in the Advanced * Custom Fields plugin. * * By running it through this function, we ensure * that we don't die if the plugin is uninstalled or * disabled (and thus the function is undefined). * * @global $post * * @param string $key The key to look for. * @param mixed $id The post ID (int|str, * defaults to $post->ID). * @param mixed $default What to return if there's * nothing found. * @return mixed (dependent upon $echo) */ function grunwell_get_custom_field( $key, $id = false, $default = '' ) { global $post; $key = trim( filter_var( $key, FILTER_SANITIZE_STRING ) ); $result = ''; if ( function_exists( 'get_field' ) ) { $result = ( isset( $post->ID ) && ! $id ? get_field( $key ) : get_field( $key, $id ) ); if ( $result == '' ) { $result = $default; } } else { /* * get_field() is undefined, most likely due to * the plugin being inactive. */ $result = $default; } return $result; } |
This makes it simple to access a custom field with key $key
, regardless of the current loop’s post ID. With the $default
parameter, I can even specify a value to return if the custom field is undefined, null, or the plugin is inactive. In practice, about 90% of the time my $default
parameter is a boolean false
, which makes it easy to test for a custom field:
1 2 3 4 5 6 |
<?php if ( $address = grunwell_get_custom_field( 'address', 123, false ) ) { // Echo the value of the address custom field on post ID 123. echo $address; } ?> |
I also like to add the following function to prevent having to type echo grunwell_get_custom_field(...)
over and over
1 2 3 4 5 6 7 8 9 10 11 12 |
/** * Shortcut for 'echo grunwell_get_custom_field()'. * * @param string $key The meta key. * @param int|string $id Optional. The post ID. * Default is $post->ID. * @param mixed $default What to return if there's no * value for the custom field. */ function grunwell_custom_field( $key, $id = false, $default = '' ) { echo grunwell_get_custom_field( $key, $id, $default ); } |
Repeater content
When dealing with repeater fields, I use the following function:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
/** * Get specified $fields from the repeater with * slug $key. * * @global $post * * @param string $key The custom field slug of the repeater. * @param int $id The post ID (will use global $post if * not specified) * @param array $fields The sub-fields to retrieve * @return array */ function grunwell_get_repeater_content( $key, $id = null, $fields = array() ) { global $post; if ( ! $id ) $id = $post->ID; $values = array(); if ( grunwell_get_custom_field( $key, $id, false ) && function_exists( 'has_sub_field' ) && function_exists( 'get_sub_field' ) ) { while ( has_sub_field( $key, $id ) ) { $value = array(); foreach ( $fields as $field ){ $value[$field] = get_sub_field( $field ); } if( ! empty( $value ) ) { $values[] = $value; } } } return $values; } |
By running my repeater requests through grunwell_get_repeater_content()
, I accomplish three things:
- Specify what keys I expect to retrieve (which helps remind me of my field names as I’m iterating over the retrieved content)
- Ensure that my page won’t break if ACF is disabled or the repeater add-on is disabled
- Most importantly, I eliminate the need to check the type of the returned content. My function will always return an array, which means I’ll never risk passing an invalid data type to a
foreach
statement.
Example
Let’s say I have a carousel where each slide had the following pieces of data: an image, a caption, and a link. I might create a repeater field named slides
with the following sub-fields: slide_image
, slide_caption
, slide_link
where slide_image
is an attachment and the other two are text fields. To retrieve this data, my code might look something like this:
1 2 3 4 5 6 7 8 9 10 |
<?php // Build our slider $slides = grunwell_get_repeater_content( 'slides', null, array( 'slide_image', 'slide_caption', 'slide_link' ) ); ?> if ( ! empty ( $slides ) ) { foreach ( $slides as $slide ) { // Format our slide using $slide['slide_image'], $slide['slide_caption'], and $slide['slide_link'] } } else { // Don't build a slider } } |
Additional resources
- Advanced Custom Fields in the WordPress plugin repo
- Code examples page on AdvancedCustomFields.com
- Elliot Condon, the plugin author, regularly features ACF tips and tricks in his blog
Wrapping up
If you haven’t used Advanced Custom Fields yet, I’d suggest looking into it on your next project. It’s really a well-built plugin that receives regular updates and enhancements.
Have you used Advanced Custom Fields on a project? What are some of the cool things you’ve done with it?
Sean
Really awesome! I’ve got quite a few sites that rely heavily on ACF and these wrapper functions will definitely help put me at ease.
A couple of suggestions:
1) get_field() needs to be able to accept IDs in string format to accommodate the Options Panel addon. I changed the conditional on line 17 to:
if ( isset( $post->ID ) && !$id ) {
$result = get_field( $key );
} else {
$result = get_field( $key, $id );
And that seemed to do the trick.
2) the_repeated_field() is depreciated. ACF now uses has_sub_field, get_sub_field & the_sub_field
Thanks for sharing.
Steve
Hey Sean,
Thanks for your input, I’ve updated the code accordingly!
Eric Arrington
This is sweet. It has always been a concern of mine. You never know what your clients might do when you turn the site over to them!!
mupdated
am using the_field() in wordpress loop via query_post () on index page. but its now working. only displaying value of field in very last post from loop ? any solution for this?
Steve
It sounds like there’s a problem in your loop. Check the codex (http://codex.wordpress.org/The_Loop) to make sure you’re properly setting your loop’s context.
mupdated
Oops! Got it. Thanks
Lore
Having an issue where, if I deactivate ACF, I can no longer manually enter a new custom field name on a regular page.
If you’ve had this issue, would love to see solution expanded.
Thanks.
Steve
It’s likely that the Custom Fields meta box is just hidden. Locate the “Screen Options” pull-down menu on the post edit screen (it should be in the top right corner just below the admin bar where it says “Howdy, Lore”) and enable the “Custom Fields” checkbox. That should restore the meta box to its usual place.
Bo
Hi Works great thanks
But facing an issue with the repeater code example . I have a select box as one of my repeater fields , it does not get both the value and choice ? how would I make that work ?
Can you check on a fieldtype ?
so instead of get_sub_field( $field )
I guess it should be like below for a select: ( just can’t get it working )
$field = get_field_object(‘field_name’);
$value = get_field(‘field_name’);
$label = $field[‘choices’][ $value ];
Can you help me get this working ?
Cheers