Support

Account

Home Forums Bug Reports Fields on acf/pre_submit_form does not receive format_values treatment

Solving

Fields on acf/pre_submit_form does not receive format_values treatment

  • Consider a field group with a “Select” field configured to return Both (Array) in the value. Suppose the entries are:

    
    foo : My Foo
    

    While intercepting a form using acf/pre_submit_form, when getting a field value with get_field('test', 'option'), the result is returned just as foo. If instead I use the filter acf/pre_save_post, it returns ['foo' => 'My Foo'] as expected.

    Looking at ACF code, the likely solution is setting the GLOBAL before and after calling the filter:

    
    // add global for backwards compatibility
    $GLOBALS['acf_form'] = $form;
    
    // filter
    $form = apply_filters( 'acf/pre_submit_form', $form );
    
    // Re-set the form in case it was filtered
    $GLOBALS['acf_form'] = $form;
    

    On \acf_form_front::submit_form, or advanced-custom-fields-pro/includes/forms/form-front.php:411

  • This reply has been marked as private.
  • This might also be related with a possible issue with acf_get_store and switch_to_blog.

    After using switch_to_blog, the acf_get_store('values') returns the same data store as it did from the main site, therefore not finding my formatting rules for the field registered in the multi-site instance.

  • Yes, I can confirm that ACF is having a hard time loading formatted values in a multi-site field when running during the context of a acf/load_field/name=.

    1. Request starts at main site
    2. I have a filter such as: add_filter('acf/load_field/name=schools', function($field) {});
    3. Inside the closure of this filter, I run switch_to_blog(3) and then get_field('state', 'options');

    Where state is a field of type “Select” such as:

    
    ny : New York
    fl : Florida
    

    And is configured to return Both (Array). But due to a probable issue with ACF, likely at the values data store, it returns the unformatted value ny only.

    What I had to do was a dirty workaround:

    
    // Pre-load the school state value in the "plugins_loaded" context
    add_action('plugins_loaded', function() {
      if (!is_not_editing_schools()) {
        return;
      }
      switch_to_blog(3);
      global $school_state;
      $school_state = get_field('state', 'options'); // ['ny' => 'New York'], as expected
    });
    
    add_filter('acf/load_field/name=schools', function($field) {
    global $school_state;
    // Now I have ['ny' => 'New York'] here, while in this context I was only able to get 'ny' out of get_field after switch_to_blog.
    });
    
  • This is part of how ACF works. ACF loads field groups for the current site and it does not load field groups for other sites. This means that any field that you want to access when using switch_to_blog() must exist in the field groups on both sites. Values do not need to be present but the field definition must exist.

  • Thanks for the response @hube2, but why does it work at plugins_loaded?

    There’s a changelog entry for a fix on 5.7.12 that seems to intend to fix this issue: * Fix - Fixed bug causing incorrect value retrieval after switch_to_blog().

    I believe this is related to this code:

    
    /**
     * acf_switch_stores
     *
     * Triggered when switching between sites on a multisite installation.
     *
     * @date    13/2/19
     * @since   5.7.11
     *
     * @param   int                           $site_id New blog ID.
     * @param   int prev_blog_id Prev blog ID.
     * @return  void
     */
    function acf_switch_stores( $site_id, $prev_site_id ) {
    
    	// Loop over stores and call switch_site().
    	global $acf_stores;
    	foreach ( $acf_stores as $store ) {
    		$store->switch_site( $site_id, $prev_site_id );
    	}
    }
    add_action( 'switch_blog', 'acf_switch_stores', 10, 2 );
    

    So the ACF Stores would format the values when retrieving it with get_field, which is exactly what I need. But I don’t understand why that works in plugins_loaded, but not in filters like acf/load_field/name= and acf/pre_submit_form.

    Does that make sense?

  • Thanks for the response @hube2, I’m trying to understand why does it work when hooked at plugins_loaded, though?

    There’s a changelog entry for a fix on 5.7.12 that seems to intend to fix this issue:

    * Fix - Fixed bug causing incorrect value retrieval after switch_to_blog().

    I believe it’s related to this code:

    
    /**
     * acf_switch_stores
     *
     * Triggered when switching between sites on a multisite installation.
     *
     * @date    13/2/19
     * @since   5.7.11
     *
     * @param   int                           $site_id New blog ID.
     * @param   int prev_blog_id Prev blog ID.
     * @return  void
     */
    function acf_switch_stores( $site_id, $prev_site_id ) {
    
    	// Loop over stores and call switch_site().
    	global $acf_stores;
    	foreach ( $acf_stores as $store ) {
    		$store->switch_site( $site_id, $prev_site_id );
    	}
    }
    add_action( 'switch_blog', 'acf_switch_stores', 10, 2 );
    

    So the ACF Stores would format the values when retrieving it with get_field, which is exactly what I need. But I don’t understand why that works in plugins_loaded, but not in filters like acf/load_field/name= and acf/pre_submit_form.

    Does that make sense?

  • the acf/load_field and acf/pre_submit_form happen before you switch to blog.

    acf/load_field happens when the field groups are loaded. ACF does not retroactively load field groups for the site when you switch_to_blog().

    plugins_loaded happens before init. ACF initializes field groups on init. What you are doing by calling get_field() before the init hook is causing ACF to prematurely initialize on the blog you are switching to during that action. ACF may or may not correct things when the init hook fires.

    Why is the field not formatted correctly?
    The rules for formatting are in the field definition. return Both from your code. ACF cannot do this formatting if it cannot find the field definition. ACF cannot find the field definition because it is not loaded. Therefor ACF returns whatever is in the DB, in this case it is a text value because the field is either a select field that only allows one value or it is a radio type field.

  • @hube2 That makes sense, thank you.

    I understand that the value formatting (eg: return Both) comes from the ACF Store “Values”, therefore the function acf_switch_stores being called on switch_blog should update ACF Stores to point to the multi-site instance after the switch.

    So, this is what I think is happening:

    1. Request starts at main site
    2. ACF initializes naturally, which triggers acf_register_store('values')
    3. I run switch_to_blog(2) on the context of filtering a field value, which fires the hook acf_switch_stores
    4. ACF switches to that multisite instance store, but the store isn’t initialized in this site instance, so the values store is empty

    It works at plugins_loaded because:

    1. Request starts at main site
    2. On plugins_loaded, I call switch_to_blog and then get_field, which internally calls ACF->initialize() on the context of the switched multi-site instance, therefore initializing the stores on the context of that site instance

    Would it make sense for ACF to register the stores again on the acf_switch_stores function, if they are not registered yet?

  • this, as far as I am aware, switches the ACF cache acf_switch_stores() and has nothing to do with what field groups are loaded.

    ACF loads the field groups for the current blog on init. ACF would need to load the field groups from the other blog when switch_to_blog is called. Doing this cold have unintended side effects unless ACF also deleted all field groups and then loaded all field groups on every site switch, basically it would need to re-initialize each time.

    I have done this in the past working with multi site. The only solution was to have the field groups used by multiple sites created for every site that will use those field groups so that they are defined when a site tries to get a field from another site.

  • @hube2 Thanks for taking some brain time to parse and process my response in an intelligent and mindful way 🙂

    That makes sense. It would be really nice if ACF could re-initialize when switching to blog, so that it can fetch the fields from whatever site is being used on a multi-site at runtime. I understand this is not possible now.

    I’ll try the field definition approach, but I’d like to ask for the above as a feature request, who knows, perhaps it might be easy to re-init after switching to blog? I wouldn’t know.

    But thank you once again for your attention!

  • I can’t process feature requests, you might want to contact the developers https://www.advancedcustomfields.com/contact/

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

You must be logged in to reply to this topic.