Support

Account

Home Forums General Issues get_field() returns false until post is resaved, but i have 1000+ posts!

Solving

get_field() returns false until post is resaved, but i have 1000+ posts!

  • Every once in a while (usually when migrating databases), ACF stops outputting metadata (aka get_field() returns false) until I manually resave the post.

    This time however, I have over 1000 posts that simultaneously need the ACF metadata to be regenerated.

    Is there any way to auto-regenerate the acf metadata?

    (I tried looping through wp_update_post(), but it didnt do anything. Neither did a bulk-edit update.. So far only a manual save seems to work)

  • This depends on how you are migrating the database and the types of fields involved.

    Every meta value for a post has a corresponding acf field reference meta value. For example, if you have a field named “my_field” there are 2 entries in the database.

    
    meta_key  | meta_value 
    my_field  | value of acf field
    _my_field | field_1234xyz
    

    More than likely, however it is that you are migrating the data the field value is being migrated, but the field key reference is not. This will work for simple text based fields (that are not in a repeater or flex field), but anything more complicated that this and ACF will be unable to get the value of the field.

    The other possibly is that the field keys on one site do not match the field keys for the same field on the second site. This is only likely if you manually created the field groups on both sites independently.

  • So the question is now that my site is like this, how do I regenerate all the info without going post by post just to click the ‘update’ button… What hook does acf use to rebind the metadata to the acf field value?

  • TLDR; You can’t trigger ACF to rebuild the field key references. You need to redo the migration so that the correct field key references are also moved.

    Long answer

    ACF doesn’t rebuild the metadata.

    Internally, ACF uses the field key. The field name is changeable and can be duplicated. The field name is only for our convenience.

    When displaying the fields for editing, ACF has the field key because it uses the field keys to display the fields for each post. It looks at the field key, gets the field object for that key, gets the field name from the field object and then uses get_post_meta() on that field name in combination with the current post ID to get the value of that field. This is why it can successfully get the values in the admin. It has both the post ID and the field key to work with.

    With more complex fields, like repeater sub fields ACF is recursing into the repeater and using additional information to generate the meta names that it uses to get the values.

    When you save a post in the admin the value/field you submit uses the field key, not the field name. Again, ACF already has the post ID and the field key. For each field submitted acf calls update_field($field_key, ). This causes ACF to get the field object and extract the name and then update both meta values.

    This has been asked here before and as far as I’m aware, no one has successfully created a way to rebuild all of the field key references for every post. To get ACF to add the correct field key reference you need to supply it with the field key, the post ID and then value for the field. If you are dealing with repeaters or other fields that have sub field you also need to provide the rows with “field key => value” pairs. And since the field key references either do not exist or are incorrect, you can’t use ACF to get the values in order to update them correctly. There is a viscous circle here which could potentially be overcome as long as you don’t have any repeaters, clones, flex fields or any other type of field that has sub fields. Thne you can loop over these groups and get the field in them, get each field name, get the value and then use ACF to update the field.

    
    $groups = acf_get_field_groups(array('post_id' => $post_id));
    foreach ($groups as $group) {
      $fields = acf_get_fields($group_key);
      foreach ($fields as $field) {
        $value = get_post_meta($post_id, $field['name'], true);
        update_field($field['key'], $value, $post_id); 
      }
    }
    

    But this falls apart as soon as you start dealing with sub fields. This would require building a recursive function on each field checking for field types that include sub fields. Each type of field would need to be handled independently. As to examples I will use a repeater vs a flex field. When you use get_post_meta() as above on a repeater field it returns a number that represents the number of rows in the repeater. When you get the value of a flex field it will return an array where each element of the array is the layout name used for that row. Based on this it would also need to check each sub field for it’s type and recurse again based on this, finally returning all of the values of all sub fields so that it can be correctly updated.

    And in the end, with a site with 1000+ posts, all this work would likely time out or exceed the max execution time do the the number of queries that WP would need to perform.

  • First of wow! Thanks for the super helpful and detailed explanation 🙂

    Here’s what I’m not understanding:

    If I go to one of my posts now, I see all the wp_metadata that I originally saved to the post with ACF sitting in the correct acf form fields.
    When I manually click update, acf grabs the [field]wp_metadata, and as you described, passes it to the the acf function that updates the associated the acf field key to point to the metadata.

    Am I right so far?

    That function is tied to clicking the update button, and theres an add_action that triggers it.

    So shouldn’t I be able to just call that action programmatically and pass the post object to it?

  • Only if you submit all of the ACF data. When you click on update an array is submitted, it looks something like this

    
    $_POST['acf'] = array(
      // field key value pair for a simple text field
      'field_12345' => 'text value here',
      // field key value pair for a repeater fields
      'field_23456' => array(
        // each row of the repeater is a nested array
        array(
          // each sub field key value pair
          'field_34567' => 'some value',
          'field_45678' => 'another value'
        )
      ),
    );
    

    If you constructed the above array in $_POST for all of your fields and trigger update_post, ACF would do the work. Building this array would not be an easy process.

    It all goes back to the data not being migrated properly. I’m not sure how you got the data from one site to the other, but there are ways to do this that do not create this issue.

    One example is wP All Import Pro with the ACF add on. http://www.wpallimport.com/. This solution can be used where the field keys on one site do not match the field keys on the second site it this is part of the issues.

    When I migrate a site I export the DB using phpMyAdmin and then import it into a new site with the same tool.

    There are also various site migration tools available.

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

The topic ‘get_field() returns false until post is resaved, but i have 1000+ posts!’ is closed to new replies.