Support

Account

Home Forums Add-ons Repeater Field get_field() for repeater returning string instead of array

Solving

get_field() for repeater returning string instead of array

  • I’ve seen many posts all looking for a solution for this, and none with any degree of solution except for a few guesses, and things that work for some people and not others. I’m hoping this will be a definitive answer for some, as well as help for the ACF developers to give better QA when people ask for help an easy thing to look for.

    For those people winding up here, I had a problem where the get_field function was returning a string containing the number of rows of a repeater field, instead of an array of values like you would expect.

    what you would expect

    
    array(2) {
      [0]=>
      array(3) {
        ["percentage"]=>
        string(2) "53"
        ["content_part"]=>
        object(WP_Term)#56179 (11) {
          ["term_id"]=>
          int(298)
          ["name"]=>
          string(21) "Worsted EthEco® Wool"
          ["slug"]=>
          string(19) "worsted-etheco-wool"
          ["term_group"]=>
          int(0)
          ["term_taxonomy_id"]=>
          int(298)
          ["taxonomy"]=>
          string(15) "product_content"
          ["description"]=>
          string(0) ""
          ["parent"]=>
          int(0)
          ["count"]=>
          int(1)
          ["filter"]=>
          string(3) "raw"
          ["term_order"]=>
          string(1) "0"
        }
        ["content_side"]=>
        string(4) "face"
      }
      [1]=>
      array(3) {
        ["percentage"]=>
        string(2) "47"
        ["content_part"]=>
        object(WP_Term)#56173 (11) {
          ["term_id"]=>
          int(99)
          ["name"]=>
          string(13) "EthEco® Wool"
          ["slug"]=>
          string(12) "ethecho-wool"
          ["term_group"]=>
          int(0)
          ["term_taxonomy_id"]=>
          int(99)
          ["taxonomy"]=>
          string(15) "product_content"
          ["description"]=>
          string(0) ""
          ["parent"]=>
          int(0)
          ["count"]=>
          int(0)
          ["filter"]=>
          string(3) "raw"
          ["term_order"]=>
          string(1) "0"
        }
        ["content_side"]=>
        string(4) "face"
      }
    }
    

    what you actually get

    
    string(1) "2"
    

    The problem as I diagnosed it, is that the field_key is not what it should be. If you goto your Field Groups setup, and enable viewing Field Keys, (Screen Options at the top right, the check the box for “Field Keys”), that will show you the proper field keys for your custom fields.
    showing field key

    If you look at your database in the wp_postmeta table under the post/s that you’re having problem with, I think you’ll find that the meta_value for the special meta_key (custom field with underscore preceeding it) associated with your custom field is incorrect.
    showing meta_value

    This can happen for any number of reasons. Deleting a custom field, and creating a new custom field with the same field name will retain the values, but will generate a different field key. Exporting / Importing data using the built-in WordPress functions can sometimes generate new field_keys. Having the same field name for two different field groups will generate different field keys.

    If you’re running into the same issue, first thing i’d check before anything else is the field_key to make sure it’s what it should be.

    As a foot note, if you edit a post through the GUI, and then Update/Save it, the field_key will always be updated to what it should be currently.

  • This anomaly can happen for several reasons. For example, if there are two fields with the same name on the same page that have two different field types. I’m sure there are other things that can cause this, like you said.

  • Incase it’s useful to anyone looking. I troubleshooted this issue down to a specific behavior in my project.

    The bug
    In a plugin I was authoring, I called get_field on repeater too early which caused a whole host of problems with ACF including the repeater field returning only it’s count as a string, and data seemingly not saving to the repeater when pressing the Update button.
    (in reality, ACF was saving the edits properly to the database but displaying an empty repeater in the post editor as a result of this error).

    The solution was to hook my ACF-dependent logic to the acf/init action instead found here:
    https://www.advancedcustomfields.com/resources/acf-init/

    Without hooking into acf/init, you would expect PHP to throw a fatal error and say get_field() is not a function in this case, but that didn’t happen.

    I’m thinking get_field() was being called in some intermediary matter– after the get_field() function was registered, but before other functions in its call stack were available– resulting in a half-baked instantiation for that particular repeater’s data.

    ¯\_(ツ)_/¯.

  • @rkirkner in your case, the functions like get_field() are defined when the files for ACF are loaded, but ACF does not load any field type definitions until the WP init hook and many of the functions that do the work are not defined until have this as well, for example the field classes that define each field type are not initialized. ACF has another hook that fires during init, this is the action acf/include_field_types. This hook fires somewhere during the initialization phase of ACF and no field types are defined before this happens. This can cause the error that your seeing because the “repeater” is not defined so ACF does not know how to handle the content of the field value that is returned by get_field(). The main reason that nothing can really be done before the acf/init hook is fired is that ACF can be included in the theme and the good place for ACF to start it’s magic is on the init hook.

    If you need to do things before this, for example you need an option value to initialize something in your plugin, then it is better to use something like get_option() or even get_post_meta()

  • How would one use get_post_meta() to retrieve a Repeater? When looking in the database, it appears that the sub-fields are saved as individual rows instead of being saved as the array that get_field() normally returns.

  • 
    // get repeater using get_post_meta()
    $repeater = 'repeater'; // name of repeater field
    $sub_fields = array(
      // holds names of all sub fields
      'sub_field_1',
      'sub_field_2',
      'sub_field_3'
    );
    // init rows
    $rows = array();
    // repeater meta holds number of rows
    $count = intval(get_post_meta($post_id, $repeater, true);
    for ($i=0; $i<$count; $i++) {
      // build row
      $row = array();
      foreach ($sub_fields as $sub_field) {
        $row[$sub_field] = get_post_meta($post_id, $repeater.'_'.$i.'_'.$sub_field, true);
      }
      $rows[] = $row;
    }
    
  • Hi!

    Thanks to this post i was able to figure out what was going on. In case it helps anyone out there:

    In my website settings I have defined a series of one-column repeaters that hold values that the user can enter. When I was getting these options in hooks that attached to ‘acf/load_field/key=’ getting the repeater yielded the expected behaviour, but sometimes it just returned the size of the repeater.

    To get around this, I wrote this code that takes in the repeater name and the column you are after. It uses the ACF API when possible or otherwise falls back on the WordPress API to obtain the value.

    Makes me wonder if I should just stick to the WP API to improve performance? 🤔

    
    	public function get_repeater_option_values( $repeater_name = '', $repeater_column_name = '' ) {
    		$associative_array = array();
    		$repeater_instance = \get_field( $repeater_name, 'option' );
    
    		if ( \is_array( $repeater_instance ) ) { // get_field( 'repeater_name', 'option') gets a repeater instance.
    			$repeater_instance = \get_field( $repeater_name, 'option' );
    			$setting_values    = array_column( $repeater_instance, $repeater_column_name );
    			foreach ( $setting_values as $key => $value ) {
    				$associative_array[ str_replace( ' ', '_', strtolower( $value ) ) ] = $value;
    			}
    		} else { // get_field( 'repeater_name', 'option' ) returns the repeater size.
    			$repeater_size = $repeater_instance;
    			for( $i = 0; $i < $repeater_size; $i++ ) {
    				$value =  \get_option( "options_{$repeater_name}_{$i}_{$repeater_column_name}" );
    				$associative_array[ str_replace( ' ', '_', strtolower( $value ) ) ] = $value;
    			}
    		}
    		return $associative_array;
    	}
    
  • I’ve had this issue before and this time I figured it out. I found while using get_field, it was returning “11”. I dug into the source code and found the field was returning false for “acf_get_field”. The chain looks like:

    get_field() -> acf_maybe_get_field() -> acf_get_meta_field() -> acf_get_field()

    It was failing because I deleted the field at one point. I added it back in with all the same settings, but the field key changed.

    I didn’t have anything tied to the field key so I thought it was alright.

    But the problem is existing posts saved with an old field key will not load the new field correctly. For example if I create a “subtitle” acf field I might get the key “field_000001”. And if I delete that and create a new “subtitle” field, it is now key “field_000002”.

    And that matters because when your post saves “subtitle = cats” it also saves “_subtitle = field_000001” (with the underscore).

    Even though you have a new field group with a new subtitle field, it’s not looking for “subtitle”. It is looking for “field_000001”.

    The solution is to update all of the affected posts, there is probably better solutions.

    I hope this helps people in the future, I think it is a bug but so very niche.

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

The topic ‘get_field() for repeater returning string instead of array’ is closed to new replies.