24

I’m using Advanced Custom Fields with post-type. I have some select custom fields, and I want to show all the label choices from each field.

I’ve tried this way.

$field = get_field_object('hair_color');
$hair = $field["choices"];
    foreach($hair as $value){

Doing a

var_dump($field)

it appears empty:

array(18) { 
   ["key"] => string(16) "field_hair_color" 
   ["label"] => string(0) "" 
   ["name"] => string(10) "hair_color" 
   ["_name"] => string(10) "hair_color" 
   ["type"]=> string(4) "text" 
   ["order_no"]=> int(1) 
   ["instructions"]=> string(0) "" 
   ["required"]=> int(0) 
   ["id"] => string(20) "acf-field-hair_color" 
   ["class"] => string(4) "text" 
   ["conditional_logic"] => array(3) { 
        ["status"] => int(0) 
        ["allorany"]=> string(3) "all" 
        ["rules"]=> int(0) 
   } 
   ["default_value"] => string(0) "" 
   ["formatting"] => string(4) "html" 
   ["maxlength"] => string(0) "" 
   ["placeholder"] => string(0) "" 
   ["prepend"] => string(0) "" 
   ["append"] => string(0) "" 
   ["value"] => bool(false) 
}

The only way to get it full is that:

get_field_object('field_51ac9d333d704');

array(17) { 
   ["key"] => string(19) "field_51ac9d333d704" 
   ["label"] => string(13) "Color de pelo" 
   ["name"] => string(10) "hair_color" 
   ["_name"] => string(10) "hair_color" 
   ["type"] => string(6) "select" 
   ["order_no"] => int(9) 
   ["instructions"] => string(27) "Selecciona el color de pelo" 
   ["required"] => int(0) 
   ["id"] => string(20) "acf-field-hair_color" 
   ["class"] => string(6) "select" 
   ["conditional_logic"] => array(3) { 
       ["status"] => int(0) 
       ["rules"] => array(1) { 
           [0] => array(3) { 
               ["field"] => string(19) "field_5195ef9879361" 
               ["operator"] => string(2) "==" 
               ["value"] => string(5) "small" 
           } 
       } 
       ["allorany"] => string(3) "all" 
   } 
   ["choices"] => array(5) { 
        ["bald"] => string(5) "Calvo" 
        ["brown"] => string(8) "Castaño" 
        ["brunette"] => string(6) "Moreno" 
        ["red"] => string(9) "Pelirrojo" 
        ["blonde"] => string(5) "Rubio" 
    } 
    ["default_value"] => string(0) "" 
    ["allow_null"] => int(1) 
    ["multiple"] => int(0) 
    ["field_group"] => int(90679) 
    ["value"]=> bool(false) 
}

But I have 3 environment, and I don’t want to hardcode the field key.

Is there any solution? Thanks in advance.

Sinister Beard
  • 3,570
  • 12
  • 59
  • 95
user1432966
  • 523
  • 1
  • 9
  • 20
  • 1
    I've done it this way: `$pageme = get_page_by_title('post_title', OBJECT, 'post_type' ); $field = get_field_object('hair_color', $pageme->ID); $pais = $field["choices"];` It works fine. – user1432966 Feb 22 '14 at 23:22

8 Answers8

8

Just trying to do this myself so I did some investigation. Seems each field and field group for ACF are stored in the wp_posts table in the database as custom post types. fields are 'acf-field' and groups are 'acf-field-group'.

I was able to use this function to get the field key to then use update_field($field_key, $value) on posts that didn't have the field already.

function get_acf_key($field_name){
    global $wpdb;

    return $wpdb->get_var("
        SELECT post_name
        FROM $wpdb->posts
        WHERE post_type='acf-field' AND post_excerpt='$field_name';
    ");
}

Then I was able to use:

update_field(get_acf_key('my_field_name'), 'some value', $post_id);

To either update the field for posts that had it already or add the field and it's key reference to posts that did not already have the field.

aaron.cimolini
  • 123
  • 1
  • 6
  • I think you must be working with an older version of Advanced Custom Fields - fields are no longer kept in the posts table, so unfortunately this won't work. – Sinister Beard Sep 29 '15 at 10:55
  • 2
    I am using the latest version. The data for describing the fields is in the posts table as a custom post type. The fields with their related data is stored in the postmeta table. The original question was just how to get the key for a named field. – aaron.cimolini Sep 30 '15 at 18:13
  • Those fields are definitely not in posts. Only the field groups are kept in posts. – Sinister Beard Oct 01 '15 at 07:16
  • 3
    Version 5.3.7 (April 2016) (pro) DOES include acf-field as a post_type in wp_posts. – Tom Auger Apr 22 '16 at 21:08
  • 1
    This is a bit off topic but if you want to verify/error detect that ACF update_field has worked (it doesn't offer this out of the box) you can do the following: `$field_key = get_acf_key('my_field_name') update_field($field_key, 'some value', $post_id); $verified_value = get_field($field_key, $post_id); if ($value !== $verified_value) : $errors[] = 'Error updating field'; endif;` – Davey Jan 26 '17 at 10:45
  • Thanks! Your solution worked for me while everybody else's didn't. – user2662680 Mar 22 '19 at 16:17
8

Here is a modified version of answer provided by @BFDatabaseAdmin matching the exact meta_value in "LIKE"

function get_acf_key($field_name) {
  global $wpdb;
  $length = strlen($field_name);
  $sql = "
    SELECT `meta_key`
    FROM {$wpdb->postmeta}
    WHERE `meta_key` LIKE 'field_%' AND `meta_value` LIKE '%\"name\";s:$length:\"$field_name\";%';
    ";
  return $wpdb->get_var($sql);
}
Hivenfour
  • 651
  • 6
  • 6
6

I'm throwing another option into the mix. I think the existing answers are good, but unless you look at the parent group, you will never get a reliable field key because the field name can exist across multiple groups.

For example, lets say you have two custom groups - one for post type books, and one for custom post type movies. Both groups have added a field called title.

In the database, both are stored with post_except = 'title' and post_type = 'acf-field'. Two entries with the same post_except, so any query relying only on post_except will be wrong, wildcard or not.

Any query relying on post id is not great either, as a post might not always exist to pass in.

So you need to pass in a combination of field and group to get the field key from the name. This snippet works well for me:

if (! function_exists('acf_field_from_name')) {

    function acf_field_from_name($field, $group)
    {
        global $wpdb;

        return $wpdb->get_var($wpdb->prepare("
            SELECT post.post_name as field_name
            FROM $wpdb->posts AS post
            LEFT JOIN $wpdb->posts AS parent
                ON post.post_parent = parent.id
            WHERE post.post_excerpt = %s
                AND post.post_type = 'acf-field'
                AND parent.post_excerpt = %s
                AND parent.post_type = 'acf-field-group'
        ", $field, $group));
    }
}

Will return the field key from name and group, or null if none exists.

Usage:

acf_field_from_name('title', 'movie-fields'); // returns field_3333333333333

acf_field_from_name('title', 'book-fields'); // returns field_4444444444444

acf_field_from_name('plumbus', 'movie'); // returns null
Chris
  • 54,599
  • 30
  • 149
  • 186
5

ACF provides some easy ways to help keep multiple environments in sync - you can register your fields with PHP or a local JSON file. Doing this would allow you to keep using get_field_object() with a single field key across multiple environments. See:

http://www.advancedcustomfields.com/resources/register-fields-via-php/

http://www.advancedcustomfields.com/resources/local-json/

I usually do my ACF development with the user interface and then export all of my fields groups as PHP to deploy across multiple environments.

UPDATE with a simple example: You could add this to functions.php or a custom plugin to add your field to multiple environments programmatically .. then you call get_field_object() with a common field_key across all environments

add_action('acf/init', 'wp123_add_local_acf_fields');
function wp123_add_local_acf_fields() {

    acf_add_local_field_group(array(
        'key' => 'group_1',
        'title' => 'My Group',
        'fields' => array (
            array (
                'key' => 'field_51ac9d333d704',
                'label' => 'Color de pelo',
                'name' => 'hair_color',
                'type' => 'select',
                'instructions' => 'Selecciona el color de pelo'
                'required' => 0,
                'choices' => array (
                    'bald' => 'Calvo',
                    'brown' => 'Castaño',
                    'brunette' => 'Moreno',
                    'red' => 'Pelirrojo',
                    'blonde' => 'Rubio',
                ),
                'default_value' => array (
                ),
                'allow_null' => 1,
                'multiple' => 0,
            )
        ),
        'location' => array (
            array (
                array (
                    'param' => 'post_type',
                    'operator' => '==',
                    'value' => 'post',
                ),
            ),
        ),
    ));

}
locomo
  • 211
  • 2
  • 3
3

The way ACF works you really should use the key.

from (http://www.advancedcustomfields.com/resources/get_field_object/)

"You can and should use the $field_key 100% of the time.

The problem with using $field_name is that if the reference does not already exist, ACF will not be able to find the field object and will not be able to save the value. This situation would occur if you had used code to insert a post.

Also, it is more efficient to use the field_key as the first parameter in the update_field function as it bypasses the reference look up."

Nigel Fish
  • 31
  • 4
  • 4
    There must be a way of finding out the field_key from the field_name. I don't use field_keys as they are different across my different databases. – Phil Aug 27 '15 at 19:31
  • 1
    There's no reliable way, because the plugin gets the name from the key rather than the other way around; I've posted a solution that works with some (hefty) caveats. – Sinister Beard Sep 29 '15 at 11:30
  • 1
    @Phil_1984_ We use WP Sync DB to sync our separate environments to keep the keys the same, FYI. – Nick Pickering Feb 05 '16 at 14:42
3

The right way is to use acf_maybe_get_field function, just like that:

acf_maybe_get_field( 'field_name', false, false );

The arguments are: field name, post id (defaults to current post) and the most important strict which defaults to true, but we set it to false here to get field object even when it does not yet exist for the post.

Refers to Get ACF field key programmatically by field name

  • 1
    Yup, this worked. Remember though that you're targeting a field name which can be the same for various custom fields (like "Rating" field for both Movies & Books custom post type - one can have 1 out of 10 select field assigned to the "rating" field name, while the other can have "good/bad" checkbox), so this is a bit of a risk. What I did is hardcoded the field key and then if there were no results, I used `acf_maybe_get_field`. – Chris Trynkiewicz Oct 15 '19 at 13:48
  • Please see my comment on the same referred topic. – Mindaugas Jakubauskas Oct 17 '19 at 06:11
2

There's no way to reliably retrieve the key using the name, because the name is metadata, and hence open to change, whereas the key (at least without editing the database manually) isn't.

However, this function will work with the most recent version of ACF, with a couple of caveats. ACF creates field groups within posts as a custom post type of ACF, but all the data about the fields themselves is held within the post_meta table.

function get_acf_key($field_name) {

    global $wpdb;

    return $wpdb->get_var("
        SELECT `meta_key`
        FROM $wpdb->postmeta
        WHERE `meta_key` LIKE 'field_%' AND `meta_value` LIKE '%$field_name%';
    ");

}

A warning: because the field name is stored as part of an array, when finding it via SQL you have to rely on a wildcard search, which is open to errors. As long as all your fields have entirely different names, you're fine, but if for example you have one field called "farm" and another called "farmer", this will error because it will find both fields.

The only reliable way to update fields is to manually code the key, though this is admittedly clunky, which is what led me here to begin with.

Sinister Beard
  • 3,570
  • 12
  • 59
  • 95
  • Thanks for this - is there any update on how to do this? – dama_do_bling Apr 15 '16 at 16:18
  • Not as far as I know, no. The official line from ACF (and the safest way) is to use the key rather than the name. – Sinister Beard Apr 18 '16 at 09:40
  • 1
    Be aware that if you're hard-coding your ACF fields in PHP using the export function (as opposed to using the DB field definitions) then this method won't work. However, if the field is hard-coded, then presumably the key won't change and will stay the same across multiple environments. – Tom Auger Apr 22 '16 at 20:56
-1

Had same problem, also ended up using key which lead me just to another dead end with no normal way to get key value, but luckily encountered this.

Taken from - https://wordpress.stackexchange.com/questions/248006/acf-add-fields-values-to-newly-inserted-post

function acf_getValue($fieldname, $post_id){
    if(($value = get_field($fieldname, $post_id)))
        return $value;
    $value = get_post_meta($post_id, $fieldname);
    return $value[0];
}
function acf_updateValue($fieldname, $value, $post_id){
    $field_key = 'field_' . uniqid();
    update_post_meta($post_id, $fieldname, $value);
    update_post_meta($post_id, '_'.$fieldname, $field_key);
    update_field($field_key, $value, $post_id);
}

Where acf_updateValue simulates how its done by ACF itself when you manually save. Since only update_field is not enough for ACF columns

Jiro Matchonson
  • 875
  • 1
  • 17
  • 24