Skip to content

Chris SilichCreative Technologist

WordPress ACF Menu Picker


Posted Thursday, October 26, 2023

I needed the ability for a CMS user to choose a standard WordPress menu via an ACF field. Here’s the solution.

  1. Make your field. In my example, it’s called navigation_menu.
  2. Add the below filter hook to your functions.php
/**
 * Create an ACF field for selecting a menu
 */
function namespace_populate_menus_field( array $field ): array {

  // Reset choices
  $field['choices'] = [];

  // Get all registered menus and add them to the field with slug as value and name as label
  foreach ( wp_get_nav_menus() as $menu ) {
    $field['choices'][ $menu->slug ] = $menu->name;
  }

  // Sort choices alphabetically
  ksort( $field['choices'] );

  return $field;
}
add_filter( 'acf/load_field/name=navigation_menu', 'namespace_populate_menus_field', 10, 1 );

And voila. Your select should automatically be populated with all the menus you’ve already got in WordPress.

If you’d prefer to only offer the menus that aren’t already assigned to a menu “location,” here’s how to modify the code to find all the locations and all the relationships between menus and locations, and filter out the assigned ones.

function namespace_populate_menus_field( array $field ): array {

  // Reset choices
  $field['choices'] = [];

  // Retrieves all registered navigation menu locations and the menus assigned to them
  $all_locations = get_nav_menu_locations();

  // Returns all navigation menu objects
  $all_menus = wp_get_nav_menus();

  // Get registered menu IDs
  $registered_ids = [];

  // Loop through all registered navigation menu locations in the theme
  foreach ( array_keys( get_registered_nav_menus() ) as $menu ) {

    // If the menu has been assigned to a location add the menu ID to the array of registered menu IDs
    if ( isset( $all_locations[ $menu ] ) ) {
      array_push( $registered_ids, $all_locations[ $menu ] );
    }
  }

  // Loop through all navigation menus
  foreach ( $all_menus as $menu ) {
    $menu_id = $menu->term_id;

    // If the menu is not registered then add as a choice
    if ( ! in_array( $menu_id, $registered_ids ) ) {
      $field['choices'][ $menu->slug ] = $menu->name;
    }

  }

  // Sort choices alphabetically
  ksort( $field['choices'] );

  return $field;

}

add_filter( 'acf/load_field/name=navigation_menu', 'namespace_populate_menus_field', 10, 1 );

← Back to Blog Archive