Dynamic Dropdown Fields in ACF

Advanced Custom Fields is a powerful tool for building metaboxes, theme settings, custom blocks, and more.

The acf/load_field filter lets you customize a field before it loads. I often use it for dynamically populating dropdown lists.

These code snippets can go in your theme’s functions.php file or a Core Functionality plugin.

Selecting an icon

On my homepage I have an Industries block with an icon for each industry.

WordPress Developer for…

Publishers

Your website needs a captivating design that keeps readers engaged and loads fast at scale.

Food Bloggers

Your website needs a recipe-centric design that allows your content to shine and projects your unique voice.

Businesses

Your website needs flexible landing pages that are easy to build, showcase your brand, and optimized to convert.

Attorneys

Your website needs to reflect the quality and professionalism of your practice, and rank high in local search results.

The icons are stored as SVGs in my theme’s /assets/icons/category directory. In the ACF block metabox, the select dropdown dynamically lists all icons in that directory.

I have multiple groups of icons in the /assets/icons/ directory. I name my ACF field dynamic_icon_{group} to specify which group of icons I want. In the above example, I want icons from the “category” group, so the field name is dynamic_icon_category.

/**
 * Dynamically select icon in ACF
 * @link https://www.billerickson.net/dynamic-dropdown-fields-in-acf/
 * @author Bill Erickson
 *
 * @param array $field, the field settings array 
 * @return array $field
 */
function be_acf_dynamic_icons( $field ) {

	if( 0 !== strpos( $field['name'], 'dynamic_icon_' ) )
		return $field;

	$type = str_replace( 'dynamic_icon_', '', $field['name'] );
	$icons = be_get_theme_icons( $type );

	$field['choices'] = [ 0 => '(None)' ];
	foreach( $icons as $icon ) {
		$field['choices'][ $icon ] = $icon;
	}

	return $field;
}
add_filter( 'acf/load_field', 'be_acf_dynamic_icons' );

/**
 * Get Theme Icons
 * Refresh cache by bumping CHILD_THEME_VERSION
 */
function be_get_theme_icons( $directory = 'utility' ) {
	$icons = get_option( 'be_theme_icons_' . $directory );
	$version = get_option( 'be_theme_icons_' . $directory . '_version' );
	if( empty( $icons ) || ( defined( 'CHILD_THEME_VERSION' ) && version_compare( CHILD_THEME_VERSION, $version ) ) ) {
		$icons = scandir( get_stylesheet_directory() . '/assets/icons/' . $directory );
		$icons = array_diff( $icons, array( '..', '.' ) );
		$icons = array_values( $icons );
		if( empty( $icons ) )
			return $icons;
		// remove the .svg
		foreach( $icons as $i => $icon ) {
			$icons[ $i ] = substr( $icon, 0, -4 );
		}
		update_option( 'be_theme_icons_' . $directory, $icons );
		if( defined( 'CHILD_THEME_VERSION' ) )
			update_option( 'be_theme_icons_' . $directory . '_version', CHILD_THEME_VERSION );
	}
	return $icons;
}

To display the icon, we use the ea_icon() function in our theme (see here).

$icon = get_field( 'icon' );
if( !empty( $icon ) )
	echo ea_icon( array( 'icon' => $icon, 'group' => 'category' ) );

More specific field targeting

The acf/load_field filter runs for every field. In my example above this makes sense because my code can apply to multiple different field names (dynamic_icon_category, dynamic_icon_utility…).

But if you’re only looking to modify a specific field, you can use one of the more specific filters:

  • acf/load_field Applies to all fields.
  • acf/load_field/type={$type} Applies to all fields of a specific type.
  • acf/load_field/name={$name} Applies to all fields of a specific name.
  • acf/load_field/key={$key} Applies to all fields of a specific key.

Bill Erickson

Bill Erickson is a freelance WordPress developer and a contributing developer to the Genesis framework. For the past 14 years he has worked with attorneys, publishers, corporations, and non-profits, building custom websites tailored to their needs and goals.

Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments

  1. Cisco says

    Hi Bill,

    I’m starting with ACF to create Gutemberg Blocks. My goal is to create a block where the editor can create a list of resource links. These links can be external or internal resources (for this last one, it can be a link to a page or a link to a media from the library). I’m trying to find a way to dynamically display the relevant icon depending of the file format of the resource (usually .pdf, .doc or .xls) and also a different icon if the resource is external or internal. What is the best approach ? Doing it conditioning with ACF or programming with a php function ? Thanks in advance if you have a clue or a resource (internal or external i’m ok 🙂

    • Bill Erickson says

      I’d use PHP code in your theme to do that. In ACF you’d probably have a dropdown with three options: page link, media file, or external link. If they select a media file, ACF will give you the attachment ID and you can use get_post_mime_type() to figure out what type of attachment it is (more information).

  2. Daniel Florian says

    Hi Bill,
    Very new to ACF. Trying to achieve a dynamic select field and not sure where to start. All the info I can find refers to pulling data from an existing ‘Options’ page – which I don’t have (or need – I think 😉 )
    I want to pull data directly from a database table (i.e.: wp_student_meta) then populate the dropdown based on what is available in certain columns of that table

    The SQL query would look something like:
    SELECT * FROM ‘wp_student_meta’ WHERE ‘key’ = ‘dojang’

    Can you give me any idea how to achieve this (or point me to a site/tutorial on achieving the desired result)

    Appreciate any help you can offer

Leave A Reply