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 the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

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

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

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

  3. Gaurav Sharma says

    Hi Bill, I am creating a custom gutenberg block using acf and in this block I want to cascade two select lists. For example, in the first select list I want to display all post types type and I am doing this with acf/load_field/name=post_type filter. And in the second select list, I want to display the posts of post type selected in the first select list.

    What I have tried so for:
    1. I have tried to put the acf/load_field/name=post (filter for second select list) inside the render_template php file of the block but it does not work. I noticed that the filter gets fired only once and that too when I reload the page but whole code inside this render_template php files gets executed multiple times as soon as any changes made to the block.

    Any help would be highly appreciated. Thanks!

    • Bill Erickson says

      I think the easiest approach is to add a dropdown for each post type’s posts and use conditional logic on the main dropdown to toggle visibility on these secondary ones.

      • Gaurav Sharma says

        Hi Bill, first of all many many thanks for the reply.

        But that will not solve my problem, because what I mentioned above as my requirement is not the exact requirement.
        It was just to better explain the need.

        However, the exact requirement is complicated and is as following:

        In the first select list, I want to display the list of pages and for the second select list I want to display the custom post(news) linked/attached to that page.

        How they are linked? For every custom post(news), page id/ids are stored as post meta, which can be meta queried on the selection of page from the first select to populate the second list and on the top of it, I want to use this combination in a repeater field.

        Some more info: I have already created this block without using acf but due to lack of experience and knowledge in JSX, Gutenberg and wordpress in all, I have performance issues with that block because I was not able to build something similar to repeater field, that’s why I coded that set of select lists as many times as I needed which is very bad and secondly I couldn’t find any Gutenberg component that can offer searchable select list.

        Thanks again for replying to my previous comment and any guidance will be highly appreciated.

  4. Bill Erickson says

    In that case you’ll likely need to use JS to query the REST API and dynamically update the options as the first dropdown changes. I’ve never done something like that so unfortunately I can’t provide any guidance on how to do it. You might try reaching out to ACF support to see if they have any examples.

  5. Stuart says

    Hi Bill,

    How are you creating the block hover areas?

    I can’t see any CSS. Is it javascript?