Support

Account

Home Forums General Issues get_field() doesn't return a value when fields are created with update_field()

Solved

get_field() doesn't return a value when fields are created with update_field()

  • I’m not sure is it a bug or am I doing something wrong.

    1. I create a post using wp_insert_post();
    2. wp_insert_post() function returns the post ID
    3. Then I use the ID to create several custom fields in a loop:

    
    $customFields = [...] // Associative array of field's names and values
    $postId = wp_inser_post([...]);
    foreach ($customFields as $field => $value) {
        update_field($field, $value, $postId);
    }
    

    Everything looks fine. Posts gets created, when I go to post edit page I can see that ACF fields exist. But when I try to use get_field() function then it looks like the fields are empty.

    When I go to post edit page and re-save the post then it starts to work fine.

    I’ve read the documentation for update_field(). The issue seems to be related to field_key(). But I don’t get it. Why do I need a key? Isn’t it possible to somehow get the key by the custom field name?

    What happens when I manually re-save the post? Is it possible to do the same programmatically?

    // EDIT:
    I could parse JSON files saved in the acf-json directory. But there must be a simpler solution.

  • The problem is that the post and the custom fields associated with the post do not exist yet so update_field() is not able to set the field key properly. You also can’t get the field object using the field name for the same reason.

    I think that the documentation explains it all pretty well. http://www.advancedcustomfields.com/resources/update_field/

    All you really need to do is edit

    
    $customFields = [...] // Associative array of field's names and values
    

    to use field keys instead of field names.

  • Thanks.

    This is what I’ve already done and it works of course. But it’s a bit annoying, especially when you have plenty of custom fields.

    I’ve read the documentation before posting the first post, but the explanation isn’t 100% clear to me. I still don’t fully understand the following issues:

    1. Why the post don’t exist yet when it’s created with wp_insert_post()? wp_insert_post returns the post ID, so I assume that post is already created.
    2. When I use fields names instead of fields keys then I can see fields values when I enter the post edit page in the WP admin. How is it possible?
    3. When I re-save the post manually then values set previously by update_field() function (using fields names, not keys!) are properly saved. How is it happening? What happens when I save the post manually, and why it can’t be done programmatically? I assume it’s not any magic 🙂

  • 1) Let’s say that the field name is “field_name”. When you use update field using the field name ACF looks in the database for a matching “_field_name” in order to get the field key. Since the field has never been inserted before it does not find one and does not know how to treat the value. Since it does not know what field key to use it does not insert any.

    2) The value for “field_name” gets inserted into the database but the matching “_field_name” entry with the field key value does not because ACF does not know what it’s supposed to be. When you open the editor ACF finds the value for “field”name” and shows that value. ACF will do the same thing for per-existing custom fields. Let’s say you created a custom field using some other method and named it “some_other_field_name”, if you add this field name to a field group that is attached to the post where this value exists, the first time that you edit the post with that custom field ACF will convert it to an ACF field and add the proper field key to the database.

    3) When you save the post again ACF saves the matching “_field_name” entry with the correct field key because at this point it knows that the field key is supposed to be.

    While field names are important and let you get values using them, ACF does not actually use the field name by itself. When you use get_field('field_name‘);` ACF looks up that field key for that field that is associated with the post. It it does not find the field key then it does not know how to treat the value. Sometimes it will work but in a lot of cases you will not get what you expect to get because you’ll just get whatever value is stored in the database. For example, if you have an image field, the ID of the attachment is stored. If ACF can’t find the field key then it does not know that you want to get an image array and just returns the ID value.

    Hope that clears things up for you

  • Since this is such a common issue for ACF users, it raises the question – why is there no way to associate field keys with a programmatically generated post? There is nothing special about manually saving a post that means it should be the only way for ACF to generate these meta values.

  • @dabernathy89

    There is nothing special about manually saving a post that means it should be the only way for ACF to generate these meta values.

    This is exactly what made me to write this post!

    @hube2
    Thank’s for very detailed explanation. But I’m still wondering is it possible to programmatically do the same “magic” which happens when the post is saved manually.

  • I’m not the developer of this plugin, I just help out around here on the forum, so take what follows as just the views of another user that happens to also be a developer that build similar thing and spends a lot of time weighing the pros and cons of different approaches to a problem.

    Could it be possible? Yes. You can get the field groups, loop through them and find the field and then extract the key.

    The problem is, you can have multiple fields with the same name, but they will have unique keys. If there is more than one field matching the name you’re looking for, which one do you use?

    After the post is inserted, you can possibly get only the field groups that would be on that post. This requires invoking all of the location rule logic which will slow the process down. Then you still need to loop through all the field groups and fields to find the one you’re looking for. There will still be the problem of what to do if you find more than one field with the same name.

    The problem with the ability to have multiple fields with the same name is more than likely the main reason why ACF does not do this. The second someone had multiple fields with the same name and the values get screwed up because ACF used the wrong field key someone would be here reporting a bug that would really have no solution other than Elliot telling you that you can never have more than one field with the same field name. I don’t think that would be very popular.

    Searching thought fields is the second reason, it’s just not practical. ACF stores fields by the field key. Using the field key you can go straight to the field in question instead of searching for it. Once a post is updated this can be done by doing a database query to get the field key. It is still faster to use the field key directly because the removes the need to do te second query. There are already complaints about the speed that ACF works, searching for and matching up field names with keys would create additional losses in performance.

    I don’t really see this as any kind of a problem to be honest. Instead of copying the field name I copy the field key. Since I usually have the field group displayed on one screen while I’m coding on another I just copy what I need. And even if I was using the field name I still copy and paste. Why? because it reduces the coding errors due to my dyslexic typing.

    What do I do when I need to use field keys for something? Here’s an example of something I recently used in a project:

    
    $fields = array(
      'equipment_condition' => 'field_568ad9d81e788',
      'equipment_year' => 'field_568ada4e1e789',
      'equipment_manufacturer' => 'field_568ad61835f56',
      'equipment_model' => 'field_568adac11e78a',
      'equipment_category' => 'field_568ad6d535f57',
      'equipment_serial_number' => 'field_568adba61e78d',
      'equipment_desc' => 'field_568bf44e39b14',
      'equipment_short_desc' => 'field_568bf47639b15',
      'equipment_spec_relationship' => 'field_568bff47e0c3b'
    );
    

    Using the above array I can now refer to the field I want using the name
    update_field($fields['equipment_manufacturer'], $value. $post_id);

    As far as ACF saving a post, have you ever looked at the fields that ACF generates on a post edit screen? If you do you’ll notice that the name used for the input field is the field key and not the field name. ACF uses the same method for updating fields, using the field keys, because it is the only value that uniquely identifies the field.

    I look at it this way, the only real purpose that the field name has is to make it easier to get the values on the front end because they are easier to remember and type than the field keys. The only reason that ACF needs dual entries in the database is to provide developers with this easier method to display values and it also makes it so that you can use get_post_meta() using the same name if you chose to do so. It exists for the 90% of the people using ACF that will never modify field using code. For the 10% of us that want to do more complicated things we’re expected to do a bit more work.

  • I didn’t expect such detailed explanation. Thank you very much.

  • I think there is still the question, though, of why the same method that saves the field keys when you manually save a post in the WordPress admin could not be replicated for when you create a post programmatically.

    I understand why the field keys are faster, but sometimes you don’t want to hard code those values. It makes it harder to read the code (imagine handing your code over to a new developer, who has to determine what all those field keys are referring to), and it’s not as portable.

  • @dabernathy89
    According to what @hube2 said it’s possible, bot not implemented because of:
    1. The complexity (it requires much more effort to “guess” the field name: more DB queries and matching location rules, etc).
    2. Possible performance issues.

    IMO it would be great if such feature was implemented. There could be a function like: acf_get_field_name_by_key();

  • Hi,

    I’m not sure if it’s valid for this conversation, but…. I just wanted to update You. I found a solution, to what was my problem.

    The context
    I got at WordPress site with WooCommerce. Since adding and updating products one by one get tiresom if you got a few hundred products, I make changes and import new products via plugin ‘WP AllImport’.

    There’s where my problem emerges. ACF wont show labels and values for advanced custom fields that have been “filled”/imported via a service like WP AllImport (is that what is called a programmatic import?). Unless, I open every product and re-save it. Just re-save, nothing more, for the labels and values to show. But I can’t (more won’t) oper an re-save hundreds (in some cases thousands) of products and re-save them every time I make an product update.

    All I wanted to do was to dynamically show the values from a fieldgroup, in order, in a tab on my productpages.

    The possible solution
    After a few days searching in ACF documentation (i’m not a developer, so I takes me more time), and contact with ACFsupport, I found an article on this supportforum. In other words’https://support.advancedcustomfields.com/forums/topic/show-an-entire-specific-field-group-in-frontend/’.

    My solution
    With that article, I was able to do what I wanted. See attached image. That specific code adds an tab to the single product page created by WooCommerce, and it places the values from my hardcoded fieldgroup (row with $group_ID = 3438).

    add_filter( 'woocommerce_product_tabs', 'woo_new_product_tab' );
    function woo_new_product_tab( $tabs ) {
    
    	// Adds the new tab
    
    	$tabs['test_tab'] = array(
    		'title' 	=> __( 'Teknisk data', 'woocommerce' ),
    		'priority' 	=> 50,
    		'callback' 	=> 'woo_new_product_tab_content'
    	);
    
    	return $tabs;
    
    }
    function woo_new_product_tab_content() {
    	echo '<table class="shop_attributes">';
    	echo '  <tbody>';
    
    	$class = '';
    	$group_ID = 3438;
    
    	$fields = array();
    	$fields = apply_filters('acf/field_group/get_fields', $fields, $group_ID);
    	if ( $fields ){
    		foreach ($fields as $field){
    			$value = get_field( $field['name'] );
    		  if (strlen($value) > 0){
    		    echo '    <tr class="' . $class . '">';
    		    echo '      <th>' . $field['label'] . '</th>';
    		    echo '      <td><p>' . $value . '</p></td>';
    		    echo '    </tr>';
    
    		    $class = $class === '' ? 'alt' : '';
    		  }
    		}
    	}
    	echo '  </tbody>';
    	echo '</table>';
    }

    The snippet also skippes rows without values, so You can have 10 rows in one product and just 5 on another.

    The snippet also uses the themes alternative color on every other row(made to work with Enfoldin this case)

    The snippet is placed in file ‘functions.php’, in my child theme.

    Best regards
    Christian

  • My greatest gratitude to John Huebner (@hube2) for explaining the ins and outs of ACF.
    The documentation is good, but these explanations are golden. Over the years almost all the answers to my dilemma’s have been already answered by this man. It saves a lot of time and pain.

    So, after all these years, I just registered on this site so I could thank you for all the support issues you’ve answered (some very detailed). So thank you. =)

Viewing 12 posts - 1 through 12 (of 12 total)

You must be logged in to reply to this topic.