Support

Account

Home Forums ACF PRO Multiple Save Locations for JSON?

Solved

Multiple Save Locations for JSON?

  • Hi Guys,

    Say for arguments sake i have two directories

    theme/modules/header/field_xxxx.json
    theme/modules/footer/field_zzzz.json

    Looking at the documentation, setting up separate load locations for each of these seems possible using acf/settings/load_json, however can the same be done with save locations? I would ideally like field group field_xxxx.json to save into the header directory when updated and visa versa.

    We’re currently using php to include our field groups which is great for modularising projects, however can be a real pain when wanting to update fields.

    Is this possible!?

    Thanks,
    Sami

  • Someone has created a plugin to alter the save path by plugins/themes. I’m sure that if you take a look at what they’re doing it’s possible. https://github.com/khromov/acf-local-json-manager

    Basically you need to create a filter on acf/settings/save_json and alter the path where the file should be saved based on the field key.

  • Thanks John.

    I’m not sure how to get the saved field key to run my check using acf/settings/load_json?

    Sami.

  • Actually, it would be a bit more complicated now that I’ve looked into it a little more. It’s going to take a combination of hooks to change the save path based on a specific field group and a way to keep track of what field is being saved.

    Please note that I have not tested this at all. It should work if I have not missed anything. I thought it was interesting and something that people might use. Please read the comments in my example.

    
    <?php 
      
      // for this I am creating a class so that we can
      // easily store infomation in one filter and then
      // retrieve it in another
      
      new acf_save_json_based_on_group_key();
      
      class acf_save_json_based_on_group_key {
        
        // $groups is an array of field group key => path pairs
        // these will be set later
        private $groups = array();
        
        // this variable will store the current group key
        // that is being saved so that we can retrieve it later
        private $current_group_being_saved;
        
        public function __construct() {
          
          // this init action will set up the save paths
          add_action('admin_init', array($this, 'admin_init'));
          
          // this action is called by ACF before saving a field group
          // the priority is set to 1 so that it runs before the internal ACF action
          add_action('acf/update_field_group', array($this, 'update_field_group'), 1, 1);
          
        } // end public function __construct
        
        public function admin_init() {
          
          // in this function we set up the paths where we want to store JSON files
          // in this example we're creating two folders in the theme header and footer
          // change the field groups and keys based on your groups
          $footer = get_stylesheet_directory().'/modules/footer';
          $header = get_stylesheet_directory().'/modules/header';
          $this->groups = array(
            'group_584d5b7986f02' => $header,
            'group_584d5b7986f03' => $footer
          );
          
        } // end public function admin_init
        
        public function update_field_group($group) {
          // the purpose of this function is to see if we want to
          // change the location where this group is saved
          // and if we to to add a filter to alter the save path
          
          // first check to see if this is one of our groups
          if (!isset($this->groups[$group['key']])) {
            // not one or our groups
            return $group;
          }
          
          // store the group key and add action
          $this->current_group_being_saved = $group['key'];
          add_action('acf/settings/save_json',  array($this, 'override_json_location'), 9999);
          
          // don't forget to return the groups
          return $group;
          
        } // end public function update_field_group
        
        public function override_json_location($path) {
          
          // alter the path based on group being saved and
          // our save locations
          $path = $this->groups[$this->current_group_being_saved];
          
          return $path;
          
        } // end public function override_json_location
        
      } // end class acf_save_json_based_on_group_key
      
      
    ?>
    
  • Thanks a bunch, this was very helpful! 🙂

  • Thank you John, this was incredibly helpful. I used this to ensure that only specific field groups get saved to a specific plugin // theme I am writing. That way I can and edit all plugins and themes at the same time without worrying about the json getting mixed up.

  • Sorry to dredge this up again; I wanted to share some code I wrote that may benefit others who find this question. I was looking for a solution a bit lighter than the suggested plugin and a bit more user-configurable than John’s (excellent) solution above, and came up with the following.

    I used a lot of PHP7+ syntax here—you may need to do a little translating if you’re running a lower version on your server!

    
    new acf_custom_json_save_path_setting();
    
    class acf_custom_json_save_path_setting {
        // This will store the preferred save path for the group for later retrieval.
        private $preferred_save_path;
    
        public function __construct() {
            // Add the "JSON Save Path" setting to all field groups.
            add_action('acf/render_field_group_settings', [$this, 'add_json_save_path_setting']);
    
            // Call an early bird (priority 1) action before saving the field group.
            add_action('acf/update_field_group', [$this, 'set_up_save_path'], 1, 1);
        }
    
        public function add_json_save_path_setting($field_group) {
            // Create our custom setting field with the specified options.
            acf_render_field_wrap([
                'label'        => 'JSON Save Path',
                'instructions' => 'Determines where the field group\'s JSON file will be saved, relative to the active theme\'s directory.',
                'type'         => 'text',
                'name'         => 'json_save_path',
                'prefix'       => 'acf_field_group',
                'prepend'      => '/',
                'placeholder'  => 'Use default path',
                'value'        => $field_group['json_save_path'] ?? '',
            ]);
        }
    
        public function set_up_save_path($group) {
            // Get the preferred save path, if set.
            $preferred_save_path = $group['json_save_path'] ?? null;
    
            // If not set (or set to an empty string), do nothing.
            if (!$preferred_save_path) {
                return $group;
            }
    
            // Set aside the preferred path and add an override action.
            $this->preferred_save_path = get_stylesheet_directory() . "/$preferred_save_path";
            add_action('acf/settings/save_json', [$this, 'save_to_preferred_save_path'], 9999);
    
            // Return the group for updating as usual.
            return $group;
        }
    
        public function save_to_preferred_save_path($path) {
            // Ensure this field group is saved to the preferred save path.
            $path = $this->preferred_save_path;
    
            return $path;
        }
    }
    

    The code above will add a simple “JSON Save Path” text field to each field group’s Settings section, in which you can enter a path where you’d like to save the group’s JSON file. The path is relative to the active theme’s directory (I felt like that was a safe default), but you can use standard directory traversal methods like ../ to go up a few levels if you’re, say, trying to save something to a plugin directory.

    And as a reminder, this code doesn’t do anything to load from your custom save points. I looked into it, but ensuring the array of load points always has the correct paths in it gets complicated quickly. Thankfully, it’s very simple (and much more transparent) to manage your load points manually via the acf/settings/load_json filter.

  • Sorry to dredge this up again; I wanted to share some code I wrote that may benefit others who find this question. I was looking for a solution a bit lighter than the suggested plugin and a bit more user-configurable than John’s (excellent) solution above, and came up with the following.

    I used a lot of PHP7+ syntax here—you may need to do a little translating if you’re running a lower version on your server!

    
    new acf_custom_json_save_path_setting();
    
    class acf_custom_json_save_path_setting {
        // This will store the preferred save path for the group for later retrieval.
        private $preferred_save_path;
    
        public function __construct() {
            // Add the "JSON Save Path" setting to all field groups.
            add_action('acf/render_field_group_settings', [$this, 'add_json_save_path_setting']);
    
            // Call an early bird (priority 1) action before saving the field group.
            add_action('acf/update_field_group', [$this, 'set_up_save_path'], 1, 1);
        }
    
        public function add_json_save_path_setting($field_group) {
            // Create our custom setting field with the specified options.
            acf_render_field_wrap([
                'label'        => 'JSON Save Path',
                'instructions' => 'Determines where the field group\'s JSON file will be saved, relative to the active theme\'s directory.',
                'type'         => 'text',
                'name'         => 'json_save_path',
                'prefix'       => 'acf_field_group',
                'prepend'      => '/',
                'placeholder'  => 'Use default path',
                'value'        => $field_group['json_save_path'] ?? '',
            ]);
        }
    
        public function set_up_save_path($group) {
            // Get the preferred save path, if set.
            $preferred_save_path = $group['json_save_path'] ?? null;
    
            // If not set (or set to an empty string), do nothing.
            if (!$preferred_save_path) {
                return $group;
            }
    
            // Set aside the preferred path and add an override action.
            $this->preferred_save_path = get_stylesheet_directory() . "/$preferred_save_path";
            add_action('acf/settings/save_json', [$this, 'save_to_preferred_save_path'], 9999);
    
            // Return the group for updating as usual.
            return $group;
        }
    
        public function save_to_preferred_save_path($path) {
            // Ensure this field group is saved to the preferred save path.
            $path = $this->preferred_save_path;
    
            return $path;
        }
    }
    

    The code above will add a simple “JSON Save Path” text field to each field group’s Settings section, in which you can enter a path where you’d like to save the group’s JSON file. The path is relative to the active theme’s directory (I felt like that was a safe default), but you can use standard directory traversal methods like ../ to go up a few levels if you’re, say, trying to save something to a plugin directory.

    And as a reminder, this code doesn’t do anything to load from your custom save points. I looked into it, but ensuring the array of load points always has the correct paths in it gets complicated quickly. Thankfully, it’s very simple (and much more transparent) to manage your load points manually via the acf/settings/load_json filter.

  • @infinimbal I’ve added a select box for paths to your code. Filled with load_json points.

    https://gist.github.com/toscani/635a0ef618fd199d069550f124fe68e6

    It works the same. Two bugs I’ve found so far, in both our versions:

    1. If you edit a FG and change the JSON Save Path the FG does get saved there, but the one in the old path remains. We need to write or use a function that deletes the old.

    2. The path selected/entered is also saved in the DB and the JSON under the json_save_path key. We’re hooking into acf/update_field_group which happens at line 551 in acf-field-group-functions.php. If you scroll up a bit there we have $save being built with $_field_group in it, and then being saved before our code runs. So even if we remove it before returning $field_group it won’t help. We could instead use the hook acf/validate_field_group, which runs much earlier, but I haven’t tested this yet.

  • @infinimbal I’ve added a select box for paths to your code. Filled with load_json points.

    https://gist.github.com/toscani/635a0ef618fd199d069550f124fe68e6

    It works the same. Two bugs I’ve found so far, in both our versions:

    1. If you edit a FG and change the JSON Save Path the FG does get saved there, but the one in the old path remains. We need to write or use a function that deletes the old.

    2. The path selected/entered is also saved in the DB and the JSON under the json_save_path key. We’re hooking into acf/update_field_group which happens at line 551 in acf-field-group-functions.php. If you scroll up a bit there we have $save being built with $_field_group in it, and then being saved before our code runs. So even if we remove it before returning $field_group it won’t help. We can instead use the hook acf/validate_field_group, which runs much earlier, but I haven’t tested this yet, or another hook.

  • Test? My replies seem to go missing if I edit them twice.

  • ……………..


    @infinimbal
    I’ve added a select box for paths to your code. Filled with load_json points.

    https://gist.github.com/toscani/635a0ef618fd199d069550f124fe68e6

    It works the same. Two bugs I’ve found so far, in both our versions:

    1. If you edit a FG and change the JSON Save Path the FG does get saved there, but the one in the old path remains. We need to write or use a function that deletes the old.

    2. The path selected/entered is also saved in the DB and the JSON under the json_save_path key. We’re hooking into acf/update_field_group which happens at line 551 in acf-field-group-functions.php. If you scroll up a bit there we have $save being built with $_field_group in it, and then being saved before our code runs. So even if we remove it before returning $field_group it won’t help. We can instead use the hook acf/validate_field_group, which runs much earlier, but I haven’t tested this yet, or another hook.

  • I’ve un-OO’ed my gist, merged it into my Auto Sync plugin, and found a way around the bugs I mentioned. Feel free to copy if you’re not looking to adopt auto syncing: https://github.com/Brugman/acf-agency-workflow

    I’ve still got to polish the repo into a clean plugin, but I think it should work at this stage. Here’s my goal for this plugin: https://support.advancedcustomfields.com/forums/topic/workflow-hassle-for-multiple-developers-making-a-theme-and-plugins/

  • This reply has been marked as private.
  • @dominikkucharski I’ve reuploaded it. I removed it because it was buggy, and I fixed those bugs in my ACF Agency Workflow repo. Though that also has an added sync function. If you search that source code for the hooks and other essential parts of the snippets people previously posted in this thread you’ll find my latest implementation of them.

  • Is there any thought about adding this functionality into the core of ACF? Saving field groups to the same location from which they were loaded would make life way easier for all these instances where things use ACF separately but are in active development together, such as site-specific plugins that are developed at the same time as a theme.

    Perhaps there could be two directories, like acf-json and acf-json-sync, where acf-json would be the distribution directory and acf-json-sync would be the development directory. Files in acf-json would not be editable and only be loaded if acf-json-sync does not exist. Files in acf-json-sync would take priority if they exist, and field groups loaded from there would be editable, syncable, etc. Field groups would be saved back to the same acf-json-sync directory they were loaded from as well as to the neighboring acf-json directory. That way we could develop with the GUI normally and then simply exclude the acf-json-sync directory in the distribution version of the plugin/theme.

    Or perhaps one directory and some other way to tell ACF whether it’s dealing with a dev or dist version, whatever works best.

    Other than that there could just be a dropdown select in the field group settings where we could select from the available save locations.

    In any case… seems like this all could be a bit more development-friendly.

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

The topic ‘Multiple Save Locations for JSON?’ is closed to new replies.