├── README.md ├── acf-sync.php ├── admin └── views │ └── json-import.php ├── composer.json └── lang ├── acfsync-fr_FR.mo └── acfsync-fr_FR.po /README.md: -------------------------------------------------------------------------------- 1 | ACF Sync 2 | =============== 3 | 4 | > **Author Note** : Since 5.1.5, ACF now includes its own [manual syncing feature](http://www.advancedcustomfields.com/blog/acf-pro-v5-1-5-update/) ! 5 | > I recommend using this feature instead of the *ACF Sync* plugin for manual synchronization. 6 | > *ACF Sync* is still relevant if you need automatic synchronization between different environments, especially on production instances where the ACF UI shouldn't be accessible to users. 7 | > I will release soon a 2.0 version that will take advantage of the 5.1.5 features and will drop the manual synchronization feature 8 | 9 | *ACF Sync* is a little WordPress plugin that let you keep your ACF field groups synchronized between different environments. 10 | 11 | It ensures you to always have up-to-date fields across different development and production environments without the need to export/import your ACF fields manually. 12 | 13 | This was inspired from this [nice article](http://seanbutze.com/automated-exporting-for-advanced-custom-fields/) from Sean Butze about deploying ACF field groups, except it has been adapted to work with ACF 5 and its new [local JSON Feature](http://www.advancedcustomfields.com/resources/local-json/). 14 | 15 | 16 | ### Installation 17 | 18 | Install this plugin along with ACF > 5.0.0. 19 | 20 | - Using git clone : `git clone https://github.com/FreshFlesh/ACF-Sync.git` 21 | - Using composer : `composer require freshflesh/acf-sync` 22 | 23 | 24 | 25 | ### How does it work ? 26 | 27 | To synchronize your field groups across your dev team, you need to version the JSON files produced by ACF with GIT or any other SCM tool. 28 | 29 | See [here](http://www.advancedcustomfields.com/resources/local-json/) to learn more about the local JSON functionality and how to activate it on your website. 30 | 31 | ##### Auto Sync 32 | 33 | You can automatically synchronize your field groups by defining a `ACF_FIELDS_VERSION` constant somewhere in your code. 34 | 35 | It should contain your field groups version, following the [version_compare](http://php.net/manual/en/function.version-compare.php) php function format. 36 | 37 | Example : `define('ACF_FIELDS_VERSION', '1.0.0');` 38 | 39 | You might want to put this constant with your Custom Post Type definitions, for example : 40 | - in a project core plugin 41 | - in a project config file 42 | - in your theme functions.php 43 | 44 | Whenever you update your fields in the WordPress admin, update the `ACF_FIELDS_VERSION` constant to a new version ; for example `1.0.0` to `1.1.0`. 45 | 46 | When another developer of your team will fetch your changes and new JSON files, *ACF Sync* will know they are newer than the ones in database, and will automatically import them back in database when accessing the WordPress Admin. 47 | 48 | Of course *ACF Sync* can also be used to synchronize fields groups between development and production environments. 49 | 50 | 51 | ##### Manual Sync 52 | 53 | Aside from the Auto Sync feature, *ACF Sync* lets you synchronize your field groups manually if your prefer to have more control on how and when field groups should be imported. 54 | 55 | When activated, it simply add a new option on the Import/Export setting page of ACF. 56 | 57 | 58 | ### Environment based configuration 59 | 60 | *ACF Sync* also optionally lets you use a `WP_ENV` constant to disable saving to JSON and hide the ACF UI on staging and production environment to avoid mistakes on non-development environments. 61 | 62 | If you use the [Bedrock WordPress stack](http://roots.io/wordpress-stack/), `WP_ENV` is already defined in the config, otherwise you can define it yourself in your wp-config.php. 63 | 64 | 65 | ### Licence 66 | 67 | MIT 68 | -------------------------------------------------------------------------------- /acf-sync.php: -------------------------------------------------------------------------------- 1 | 0 ) { 105 | 106 | $success = $this->import_json_field_groups(); 107 | 108 | if ( $success ) { 109 | update_option( 'acf_fields_version', ACF_FIELDS_VERSION ); 110 | } 111 | 112 | } 113 | 114 | } 115 | 116 | } 117 | 118 | 119 | /* 120 | * render_admin_view 121 | * 122 | * Render admin form on ACF settings-export page 123 | * 124 | * @param n/a 125 | * @return n/a 126 | */ 127 | 128 | public function render_admin_view() { 129 | 130 | if ( !acf_get_setting('json') ) return; 131 | 132 | include( 'admin/views/json-import.php' ); 133 | 134 | } 135 | 136 | /* 137 | * manual_sync_action 138 | * 139 | * Validate form data and import field groups 140 | * 141 | * @param n/a 142 | * @return n/a 143 | */ 144 | 145 | public function manual_sync_action() { 146 | 147 | if ( ! wp_verify_nonce( $_POST[ '_acfnonce' ], 'acfsync' ) ) { 148 | die( 'Invalid nonce.' ); 149 | } 150 | 151 | $success = $this->import_json_field_groups(); 152 | 153 | if ( $success ) { 154 | if ( defined( 'ACF_FIELDS_VERSION' ) ) { 155 | update_option( 'acf_fields_version', ACF_FIELDS_VERSION ); 156 | } 157 | } 158 | 159 | $url = add_query_arg( array( 'fields-sync' => $success ), $_SERVER['HTTP_REFERER'] ); 160 | 161 | wp_safe_redirect( $url ); 162 | 163 | exit; 164 | 165 | } 166 | 167 | 168 | /* 169 | * admin_notices 170 | * 171 | * Display relevant admin notice after manual import 172 | * 173 | * @param n/a 174 | * @return n/a 175 | */ 176 | 177 | public function admin_notices() { 178 | 179 | if ( !isset( $_GET['fields-sync']) ) return; 180 | 181 | if ( $_GET['fields-sync'] == true ) { 182 | echo '

' . esc_html__( 'Field groups updated !', 'acfsync' ) . '

'; 183 | } 184 | else { 185 | echo '

' . esc_html__( 'Sorry, unable to sync your field groups. Make sure you have the local JSON feature enabled and that your JSON folder is readable.', 'acfsync' ) . '

'; 186 | } 187 | 188 | } 189 | 190 | 191 | /* 192 | * import_json_field_groups 193 | * 194 | * Parse json load points paths and import all JSON files 195 | * 196 | * @param n/a 197 | * @return bool 198 | */ 199 | 200 | private function import_json_field_groups() { 201 | 202 | if ( !acf_get_setting('json') ) return false; 203 | 204 | // Check if JSON paths are readable 205 | $json_paths = acf_get_setting('load_json'); 206 | 207 | foreach ($json_paths as $json_path) { 208 | if ( !is_readable( $json_path ) ) { 209 | return false; 210 | } 211 | } 212 | 213 | // Tell ACF NOT to save to local JSON while we delete groups in DB 214 | add_filter('acf/settings/save_json', '__return_null', 99 ); 215 | 216 | // Remove previous field groups 217 | $args = array( 218 | 'post_type' => 'acf-field-group', 219 | 'post_status' => 'any', 220 | 'posts_per_page' => -1 221 | ); 222 | 223 | $query = new WP_Query( $args ); 224 | 225 | foreach ( $query->posts as $acf_group ) { 226 | wp_delete_post( $acf_group->ID, true); 227 | } 228 | 229 | // Parse local JSON load points directories 230 | foreach ($json_paths as $json_path) { 231 | 232 | $dir = new DirectoryIterator( $json_path ); 233 | 234 | foreach( $dir as $file ) { 235 | 236 | if ( !$file->isDot() && 'json' == $file->getExtension() ) { 237 | 238 | $json = json_decode( file_get_contents( $file->getPathname() ), true ); 239 | $this->import_json_field_group( $json ); 240 | 241 | } 242 | 243 | } 244 | 245 | } 246 | 247 | return true; 248 | 249 | } 250 | 251 | 252 | /* 253 | * import_json_field_group 254 | * 255 | * import ACF field group from JSON data 256 | * 257 | * @param $json (array) 258 | * @return n/a 259 | */ 260 | 261 | private function import_json_field_group( $json ) { 262 | 263 | // What follows is basically a copy of import() in ACF admin/settings-export.php 264 | 265 | // if importing an auto-json, wrap field group in array 266 | if( isset($json['key']) ) { 267 | $json = array( $json ); 268 | } 269 | 270 | // vars 271 | $added = array(); 272 | $ignored = array(); 273 | $ref = array(); 274 | $order = array(); 275 | 276 | foreach( $json as $field_group ) { 277 | 278 | // remove fields 279 | $fields = acf_extract_var($field_group, 'fields'); 280 | 281 | // format fields 282 | $fields = acf_prepare_fields_for_import( $fields ); 283 | 284 | // save field group 285 | $field_group = acf_update_field_group( $field_group ); 286 | 287 | // add to ref 288 | $ref[ $field_group['key'] ] = $field_group['ID']; 289 | 290 | // add to order 291 | $order[ $field_group['ID'] ] = 0; 292 | 293 | 294 | // add fields 295 | foreach( $fields as $field ) { 296 | 297 | // add parent 298 | if( empty($field['parent']) ) { 299 | 300 | $field['parent'] = $field_group['ID']; 301 | 302 | } elseif( isset($ref[ $field['parent'] ]) ) { 303 | 304 | $field['parent'] = $ref[ $field['parent'] ]; 305 | 306 | } 307 | 308 | // add field menu_order 309 | if( !isset($order[ $field['parent'] ]) ) { 310 | 311 | $order[ $field['parent'] ] = 0; 312 | 313 | } 314 | 315 | $field['menu_order'] = $order[ $field['parent'] ]; 316 | $order[ $field['parent'] ]++; 317 | 318 | // save field 319 | $field = acf_update_field( $field ); 320 | 321 | // add to ref 322 | $ref[ $field['key'] ] = $field['ID']; 323 | 324 | } 325 | 326 | } 327 | } 328 | 329 | } 330 | 331 | new ACFSync(); 332 | -------------------------------------------------------------------------------- /admin/views/json-import.php: -------------------------------------------------------------------------------- 1 | 21 | 22 | 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "freshflesh/acf-sync", 3 | "description": "Keep your ACF field groups synchronized between different environments", 4 | "version": "1.1.2", 5 | "type" : "wordpress-plugin", 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Thomas Charbit", 10 | "email": "thomas.charbit@gmail.com" 11 | } 12 | ], 13 | "require": { 14 | "php": ">=5.3.0", 15 | "wordpress/wordpress": ">=3.5" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lang/acfsync-fr_FR.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomascharbit/acf-sync/95a87bba7ce4d3f7866a76fb0e4b1e10aaf16a6c/lang/acfsync-fr_FR.mo -------------------------------------------------------------------------------- /lang/acfsync-fr_FR.po: -------------------------------------------------------------------------------- 1 | msgid "" 2 | msgstr "" 3 | "Project-Id-Version: acfsync\n" 4 | "POT-Creation-Date: 2014-11-19 19:40+0100\n" 5 | "PO-Revision-Date: 2014-11-19 20:04+0100\n" 6 | "Last-Translator: Thomas Charbit \n" 7 | "Language-Team: \n" 8 | "Language: fr_FR\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=UTF-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "X-Generator: Poedit 1.6.10\n" 13 | "X-Poedit-Basepath: .\n" 14 | "Plural-Forms: nplurals=2; plural=(n > 1);\n" 15 | "X-Poedit-KeywordsList: __;_e;esc_html__\n" 16 | "X-Poedit-SearchPath-0: ..\n" 17 | 18 | #: ../acf-sync.php:173 19 | msgid "Field groups updated !" 20 | msgstr "Les groupes de champs ont été correctement importés !" 21 | 22 | #: ../acf-sync.php:176 23 | msgid "" 24 | "Sorry, unable to sync your field groups. Make sure you have the local JSON " 25 | "feature enabled and that your JSON folder is readable." 26 | msgstr "" 27 | "Désolé, impossible de synchroniser vos groupes de champs. Vérifiez que la " 28 | "fonctionnalité local JSON est activée et que le dossier JSON est accessible " 29 | "en lecture. " 30 | 31 | #: ../admin/views/json-import.php:4 32 | msgid "Import field groups from local JSON" 33 | msgstr "Importer les groupes de champs depuis local JSON" 34 | 35 | #: ../admin/views/json-import.php:7 36 | msgid "Import manually the field groups from your local JSON folder." 37 | msgstr "" 38 | "Importer manuellement les groupes de champs depuis le dossier de sauvegarde " 39 | "JSON." 40 | 41 | #: ../admin/views/json-import.php:14 42 | msgid "Sync field groups" 43 | msgstr "Synchroniser" 44 | --------------------------------------------------------------------------------