├── 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 |
--------------------------------------------------------------------------------