Advanced Custom Fields: Extended - Version 0.8.6.6

Version Description

  • Module: Multilang - Fixed WPML front-end language detection for custom languages
  • Module: Settings - Added "Multilang" & "Single Meta" settings in the UI
  • Module: Settings - Fixed l10n_textdomain which wasn't correctly displayed
  • Module: Dev Mode - Fixed option "Edit" action link
  • Module: PHP AutoSync - Added l10n support
  • Module: Single Meta - Enhanced "Delete Orphan Meta" setting logic & performance
  • Field: Taxonomy Terms - Added "Term (All childs)" to display any childs level terms
  • Field: Taxonomy Terms - Renamed "Term (Childs)" to "Term (Direct childs)" to avoid confusion with the new filter
  • Field: Taxonomy Terms - Fixed "Term (Direct childs)" which could be duplicated in some cases
Download this release

Release Info

Developer hwk-fr
Plugin Icon 128x128 Advanced Custom Fields: Extended
Version 0.8.6.6
Comparing to
See all releases

Code changes from version 0.8.6.5 to 0.8.6.6

acf-extended.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Plugin Name: Advanced Custom Fields: Extended
4
  * Description: Enhancement Suite which improves Advanced Custom Fields administration
5
- * Version: 0.8.6.5
6
  * Author: ACF Extended
7
  * Author URI: https://www.acf-extended.com
8
  * Text Domain: acfe
@@ -16,7 +16,7 @@ if(!class_exists('ACFE')):
16
  class ACFE{
17
 
18
  // Version
19
- var $version = '0.8.6.5';
20
 
21
  // Settings
22
  var $settings = array();
2
  /**
3
  * Plugin Name: Advanced Custom Fields: Extended
4
  * Description: Enhancement Suite which improves Advanced Custom Fields administration
5
+ * Version: 0.8.6.6
6
  * Author: ACF Extended
7
  * Author URI: https://www.acf-extended.com
8
  * Text Domain: acfe
16
  class ACFE{
17
 
18
  // Version
19
+ var $version = '0.8.6.6';
20
 
21
  // Settings
22
  var $settings = array();
includes/admin/settings.php CHANGED
@@ -144,7 +144,7 @@ function acfe_admin_settings_html(){
144
  array(
145
  'name' => 'l10n_textdomain',
146
  'label' => 'l10n Textdomain',
147
- 'value' => '<code>' . (acf_get_setting('l10n') ? __('True'): __('False')) . '</code>',
148
  'description' => 'Sets the text domain used when translating field and field group settings.<br />Defaults to ”. Strings will not be translated if this setting is empty'
149
  ),
150
  array(
@@ -169,7 +169,7 @@ function acfe_admin_settings_html(){
169
  'name' => 'google_api_client',
170
  'label' => 'Google API Key',
171
  'value' => '<code>' . acf_get_setting('google_api_client') . '</code>',
172
- 'description' => 'Specify a Google Maps API Client ID to prevent usage limits.<br />Not needed if using google_api_key. Defaults to ”'
173
  ),
174
  array(
175
  'name' => 'enqueue_google_maps',
@@ -281,12 +281,24 @@ function acfe_admin_settings_html(){
281
  'value' => '<code>' . (acf_get_setting('acfe/modules/dynamic_options_pages', true) ? __('True'): __('False')) . '</code>',
282
  'description' => 'Show/hide the Options Pages module. Defaults to true'
283
  ),
 
 
 
 
 
 
284
  array(
285
  'name' => 'acfe/modules/options',
286
  'label' => 'Module: Options',
287
  'value' => '<code>' . (acf_get_setting('acfe/modules/options', true) ? __('True'): __('False')) . '</code>',
288
  'description' => 'Show/hide the Options module. Defaults to true'
289
  ),
 
 
 
 
 
 
290
  array(
291
  'name' => 'acfe/modules/ui',
292
  'label' => 'Module: UI Enhancements',
144
  array(
145
  'name' => 'l10n_textdomain',
146
  'label' => 'l10n Textdomain',
147
+ 'value' => '<code>' . print_r(acf_get_setting('l10n_textdomain'), true) . '</code>',
148
  'description' => 'Sets the text domain used when translating field and field group settings.<br />Defaults to ”. Strings will not be translated if this setting is empty'
149
  ),
150
  array(
169
  'name' => 'google_api_client',
170
  'label' => 'Google API Key',
171
  'value' => '<code>' . acf_get_setting('google_api_client') . '</code>',
172
+ 'description' => 'Specify a Google Maps API Client ID to prevent usage limits.<br />Not needed if using <code>google_api_key</code>. Defaults to ”'
173
  ),
174
  array(
175
  'name' => 'enqueue_google_maps',
281
  'value' => '<code>' . (acf_get_setting('acfe/modules/dynamic_options_pages', true) ? __('True'): __('False')) . '</code>',
282
  'description' => 'Show/hide the Options Pages module. Defaults to true'
283
  ),
284
+ array(
285
+ 'name' => 'acfe/modules/multilang',
286
+ 'label' => 'Module: Multilang',
287
+ 'value' => '<code>' . (acf_get_setting('acfe/modules/multilang', true) ? __('True'): __('False')) . '</code>',
288
+ 'description' => 'Enable/disable Multilang compatibility module for WPML & Polylang. Defaults to true'
289
+ ),
290
  array(
291
  'name' => 'acfe/modules/options',
292
  'label' => 'Module: Options',
293
  'value' => '<code>' . (acf_get_setting('acfe/modules/options', true) ? __('True'): __('False')) . '</code>',
294
  'description' => 'Show/hide the Options module. Defaults to true'
295
  ),
296
+ array(
297
+ 'name' => 'acfe/modules/single_meta',
298
+ 'label' => 'Module: Single Meta',
299
+ 'value' => '<code>' . (acf_get_setting('acfe/modules/single_meta', true) ? __('True'): __('False')) . '</code>',
300
+ 'description' => 'Enable/disable Single Meta Save module. Defaults to false'
301
+ ),
302
  array(
303
  'name' => 'acfe/modules/ui',
304
  'label' => 'Module: UI Enhancements',
includes/core/multilang.php CHANGED
@@ -50,6 +50,24 @@ class acfe_multilang{
50
 
51
  }
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  /**
54
  * PolyLang
55
  * https://polylang.pro/doc/filter-reference/
@@ -79,34 +97,29 @@ class acfe_multilang{
79
 
80
  function polylang_get_languages($pluck = 'locale'){
81
 
 
82
  require_once ABSPATH . 'wp-admin/includes/translation-install.php';
83
 
84
  $languages = include PLL_SETTINGS_INC . '/languages.php';
85
  $translations = wp_get_available_translations();
86
-
87
- // Keep only languages with existing WP language pack
88
- // Unless the transient has expired and we don't have an internet connection to refresh it
89
- if ( ! empty( $translations ) ) {
90
- $translations['en_US'] = ''; // Languages packs don't include en_US
91
- $languages = array_intersect_key( $languages, $translations );
92
  }
93
-
94
- /**
95
- * Filter the list of predefined languages
96
- *
97
- * @since 1.7.10
98
- * @since 2.3 The languages arrays use associative keys instead of numerical keys
99
- * @see settings/languages.php
100
- *
101
- * @param array $languages
102
- */
103
- $languages = apply_filters( 'pll_predefined_languages', $languages );
104
-
105
- // Keep only languages with all necessary informations
106
- foreach ( $languages as $k => $lang ) {
107
- if ( ! isset( $lang['code'], $lang['locale'], $lang['name'], $lang['dir'], $lang['flag'] ) ) {
108
- unset( $languages[ $k ] );
109
  }
 
110
  }
111
 
112
  if($pluck){
@@ -119,6 +132,24 @@ class acfe_multilang{
119
 
120
  }
121
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  /**
123
  * ACF Options Post ID
124
  */
@@ -153,66 +184,42 @@ class acfe_multilang{
153
  }
154
 
155
  function is_post_id_localized($post_id){
156
-
157
- // Polylang
158
- if($this->is_polylang){
159
-
160
- // Check var'_en_US'
161
- preg_match('/_[a-z]{2}_[A-Z]{2}$/', $post_id, $found_locale);
162
-
163
- if(!empty($found_locale)){
164
-
165
- // Remove first '_'
166
- $found_locale = substr($found_locale[0], 1);
167
-
168
- // Get Polylang Languages List
169
- $languages = $this->polylang_get_languages('locale');
170
-
171
- // Language Locale found in Post ID
172
- if(in_array($found_locale, $languages))
173
- return true;
174
-
175
-
176
- }
177
-
178
- // Check var'_en'
179
- preg_match('/_[a-z]{2}$/', $post_id, $found_code);
180
-
181
- if(!empty($found_code)){
182
-
183
- // Remove first '_'
184
- $found_code = substr($found_code[0], 1);
185
 
186
- // Get Polylang Languages List
187
- $languages = $this->polylang_get_languages('code');
188
 
189
- // Language Locale found in Post ID
190
- if(in_array($found_code, $languages))
191
- return true;
192
-
193
- }
194
-
195
- }
196
 
197
- // WPML
198
- elseif($this->is_wpml){
 
 
 
 
 
 
 
 
 
 
 
199
 
200
- // Check var'_en'
201
- preg_match('/_[a-z]{2}$/', $post_id, $found_code);
202
 
203
- if(!empty($found_code)){
204
-
205
- // Remove first '_'
206
- $found_code = substr($found_code[0], 1);
207
 
208
- // Get WPML Languages List
209
- $languages = icl_get_languages_codes();
 
210
 
211
- // Language Locale found in Post ID
212
- if(in_array($found_code, $languages))
213
- return true;
214
 
215
- }
 
 
216
 
217
  }
218
 
50
 
51
  }
52
 
53
+ function wpml_get_languages($pluck = 'locale'){
54
+
55
+ // https://wpml.org/wpml-hook/wpml_active_languages/
56
+ if($pluck === 'locale')
57
+ $pluck = 'default_locale';
58
+
59
+ $languages = apply_filters('wpml_active_languages', null, array('skip_missing' => 0));
60
+
61
+ if($pluck){
62
+
63
+ $languages = wp_list_pluck($languages, $pluck, true);
64
+
65
+ }
66
+
67
+ return $languages;
68
+
69
+ }
70
+
71
  /**
72
  * PolyLang
73
  * https://polylang.pro/doc/filter-reference/
97
 
98
  function polylang_get_languages($pluck = 'locale'){
99
 
100
+ // Copy from wp-content/plugins/polylang-pro/settings/settings.php:363
101
  require_once ABSPATH . 'wp-admin/includes/translation-install.php';
102
 
103
  $languages = include PLL_SETTINGS_INC . '/languages.php';
104
  $translations = wp_get_available_translations();
105
+
106
+ if (!empty($translations)){
107
+
108
+ $translations['en_US'] = '';
109
+ $languages = array_intersect_key($languages, $translations);
110
+
111
  }
112
+
113
+ $languages = apply_filters('pll_predefined_languages', $languages);
114
+
115
+ foreach($languages as $k => $lang){
116
+
117
+ if (!isset( $lang['code'], $lang['locale'], $lang['name'], $lang['dir'], $lang['flag'])){
118
+
119
+ unset($languages[$k]);
120
+
 
 
 
 
 
 
 
121
  }
122
+
123
  }
124
 
125
  if($pluck){
132
 
133
  }
134
 
135
+ function get_languages($pluck = 'code', $plugin = false){
136
+
137
+ // Polylang
138
+ if($this->is_polylang || $plugin === 'polylang'){
139
+
140
+ return $this->polylang_get_languages($pluck);
141
+
142
+ // WPML
143
+ }elseif($this->is_wpml || $plugin === 'wpml'){
144
+
145
+ return $this->wpml_get_languages($pluck);
146
+
147
+ }
148
+
149
+ return array();
150
+
151
+ }
152
+
153
  /**
154
  * ACF Options Post ID
155
  */
184
  }
185
 
186
  function is_post_id_localized($post_id){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
+ // Check if ends with '-en_US' || '_en_US'
189
+ preg_match('/[_\-][A-Za-z]{2}_[A-Za-z]{2}$/', $post_id, $found);
190
 
191
+ if(!empty($found)){
 
 
 
 
 
 
192
 
193
+ // Remove first '_'
194
+ $found = substr($found[0], 1);
195
+ $found = strtolower($found);
196
+
197
+ // Get Languages List
198
+ $languages = $this->get_languages('locale');
199
+ $languages = array_map('strtolower', $languages);
200
+
201
+ // Language Locale found in Post ID
202
+ if(in_array($found, $languages))
203
+ return true;
204
+
205
+ }
206
 
207
+ // Check if ends with '-en' || '_en'
208
+ preg_match('/[_\-][A-Za-z]{2}$/', $post_id, $found);
209
 
210
+ if(!empty($found)){
 
 
 
211
 
212
+ // Remove first '_'
213
+ $found = substr($found[0], 1);
214
+ $found = strtolower($found);
215
 
216
+ // Get Languages List
217
+ $languages = $this->get_languages('code');
218
+ $languages = array_map('strtolower', $languages);
219
 
220
+ // Language Code found in Post ID
221
+ if(in_array($found, $languages))
222
+ return true;
223
 
224
  }
225
 
includes/fields/field-taxonomy-terms.php CHANGED
@@ -119,6 +119,8 @@ class acfe_field_taxonomy_terms extends acf_field{
119
  'children' => array()
120
  );
121
 
 
 
122
  // append to $data
123
  $i=0; foreach($terms as $term_id => $name){ $i++;
124
 
@@ -141,7 +143,7 @@ class acfe_field_taxonomy_terms extends acf_field{
141
 
142
  $data['children'][] = array(
143
  'id' => $id,
144
- 'text' => '<strong>' . $text . '</strong>'
145
  );
146
 
147
  }
@@ -150,12 +152,31 @@ class acfe_field_taxonomy_terms extends acf_field{
150
 
151
  $_term = get_term($term->parent);
152
 
153
- $_term_choice = acf_get_choice_from_term($_term, 'name');
154
-
155
- $data['children'][] = array(
156
- 'id' => $_term->term_id . '_childs',
157
- 'text' => '<strong>' . $_term_choice['text'] . ': Childs</strong>'
158
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
 
160
  }
161
 
@@ -301,8 +322,47 @@ class acfe_field_taxonomy_terms extends acf_field{
301
  $terms = array_merge($terms, acf_array($keep));
302
 
303
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
 
305
- // Terms childs
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  elseif(acfe_ends_with($id, '_childs')){
307
 
308
  $term_id = substr($id, 0, -7);
@@ -364,7 +424,8 @@ class acfe_field_taxonomy_terms extends acf_field{
364
  if(!empty($terms)){
365
 
366
  $terms = acf_get_grouped_terms(array(
367
- 'include' => $terms
 
368
  ));
369
 
370
  $choices = acf_get_choices_from_grouped_terms($terms, 'name');
@@ -426,25 +487,37 @@ class acfe_field_taxonomy_terms extends acf_field{
426
 
427
  if(!empty($terms)){
428
 
 
 
 
 
 
 
429
  foreach($terms as $taxonomy => $term){
430
 
431
  $data = array(
432
  'text' => $taxonomy,
433
  'children' => array()
434
  );
435
-
436
- foreach($term as $term_id => $term_name){
437
 
 
 
438
  $data['children'][] = array(
439
  'id' => $term_id,
440
  'text' => $term_name
441
  );
442
-
443
  }
444
-
445
  $results[] = $data;
446
 
447
  }
 
 
 
 
 
 
448
 
449
  }
450
 
@@ -476,7 +549,18 @@ class acfe_field_taxonomy_terms extends acf_field{
476
  // Normal choices
477
  if($field['type'] !== 'select' || !$field['ui'] || !$field['ajax']){
478
 
479
- $field['choices'] = $this->get_terms($field);
 
 
 
 
 
 
 
 
 
 
 
480
 
481
  // Ajax choices
482
  }else{
@@ -588,9 +672,23 @@ class acfe_field_taxonomy_terms extends acf_field{
588
  continue;
589
 
590
  $taxonomy = get_taxonomy($taxonomy);
591
- $value = '<strong>All ' . $level . $taxonomy->label . '</strong>';
592
 
593
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
594
 
595
  // Terms childs
596
  elseif(acfe_ends_with($id, '_childs')){
@@ -602,7 +700,7 @@ class acfe_field_taxonomy_terms extends acf_field{
602
  if(!empty($field['taxonomy']) && !in_array($taxonomy, acf_array($field['taxonomy'])))
603
  continue;
604
 
605
- $value = '<strong>' . $term->name . ': childs</strong>';
606
 
607
  }
608
 
119
  'children' => array()
120
  );
121
 
122
+ $done = array();
123
+
124
  // append to $data
125
  $i=0; foreach($terms as $term_id => $name){ $i++;
126
 
143
 
144
  $data['children'][] = array(
145
  'id' => $id,
146
+ 'text' => '(' . $text . ')'
147
  );
148
 
149
  }
152
 
153
  $_term = get_term($term->parent);
154
 
155
+ if(!in_array($_term->term_id . '_childs', $done)){
156
+
157
+ $_term_choice = acf_get_choice_from_term($_term, 'name');
158
+
159
+ $data['children'][] = array(
160
+ 'id' => $_term->term_id . '_childs',
161
+ 'text' => $_term_choice['text'] . ' (Direct childs)'
162
+ );
163
+
164
+ $done[] = $_term->term_id . '_childs';
165
+
166
+ }
167
+
168
+ if(!in_array($_term->term_id . '_all_childs', $done)){
169
+
170
+ $_term_choice = acf_get_choice_from_term($_term, 'name');
171
+
172
+ $data['children'][] = array(
173
+ 'id' => $_term->term_id . '_all_childs',
174
+ 'text' => $_term_choice['text'] . ' (All childs)'
175
+ );
176
+
177
+ $done[] = $_term->term_id . '_all_childs';
178
+
179
+ }
180
 
181
  }
182
 
322
  $terms = array_merge($terms, acf_array($keep));
323
 
324
  }
325
+
326
+ // Terms all childs
327
+ elseif(acfe_ends_with($id, '_all_childs')){
328
+
329
+ $term_id = substr($id, 0, -11);
330
+ $term = get_term($term_id);
331
+ $taxonomy = $term->taxonomy;
332
+
333
+ if(!empty($field['taxonomy']) && !in_array($taxonomy, acf_array($field['taxonomy'])))
334
+ continue;
335
+
336
+ $keep = array();
337
+
338
+ foreach($all_terms as $all_term){
339
+
340
+ if($all_term->taxonomy !== $taxonomy)
341
+ continue;
342
+
343
+ $term_childs = get_term_children($term_id, $taxonomy);
344
+
345
+ if(!in_array($all_term->term_id, $term_childs))
346
+ continue;
347
 
348
+ $keep[] = $all_term;
349
+
350
+ }
351
+
352
+ $is_hierarchical = is_taxonomy_hierarchical($taxonomy);
353
+
354
+ // sort into hierachial order
355
+ if($is_hierarchical){
356
+
357
+ $keep = _get_term_children($id, $keep, $taxonomy);
358
+
359
+ }
360
+
361
+ $terms = array_merge($terms, acf_array($keep));
362
+
363
+ }
364
+
365
+ // Terms direct childs
366
  elseif(acfe_ends_with($id, '_childs')){
367
 
368
  $term_id = substr($id, 0, -7);
424
  if(!empty($terms)){
425
 
426
  $terms = acf_get_grouped_terms(array(
427
+ 'include' => $terms,
428
+ 'orderby' => 'include'
429
  ));
430
 
431
  $choices = acf_get_choices_from_grouped_terms($terms, 'name');
487
 
488
  if(!empty($terms)){
489
 
490
+ $keys = array_keys($terms);
491
+ $single_taxonomy = false;
492
+
493
+ if(count($keys) === 1)
494
+ $single_taxonomy = true;
495
+
496
  foreach($terms as $taxonomy => $term){
497
 
498
  $data = array(
499
  'text' => $taxonomy,
500
  'children' => array()
501
  );
 
 
502
 
503
+ foreach($term as $term_id => $term_name){
504
+
505
  $data['children'][] = array(
506
  'id' => $term_id,
507
  'text' => $term_name
508
  );
509
+
510
  }
511
+
512
  $results[] = $data;
513
 
514
  }
515
+
516
+ if($single_taxonomy){
517
+
518
+ $results = $results[0]['children'];
519
+
520
+ }
521
 
522
  }
523
 
549
  // Normal choices
550
  if($field['type'] !== 'select' || !$field['ui'] || !$field['ajax']){
551
 
552
+ $choices = $this->get_terms($field);
553
+
554
+ $keys = array_keys($choices);
555
+
556
+ // Single Term
557
+ if(count($keys) === 1){
558
+
559
+ $choices = $choices[$keys[0]];
560
+
561
+ }
562
+
563
+ $field['choices'] = $choices;
564
 
565
  // Ajax choices
566
  }else{
672
  continue;
673
 
674
  $taxonomy = get_taxonomy($taxonomy);
675
+ $value = '(All ' . $level . $taxonomy->label . ')';
676
 
677
  }
678
+
679
+ // Terms all childs
680
+ elseif(acfe_ends_with($id, '_all_childs')){
681
+
682
+ $term_id = substr($id, 0, -11);
683
+ $term = get_term($term_id);
684
+ $taxonomy = $term->taxonomy;
685
+
686
+ if(!empty($field['taxonomy']) && !in_array($taxonomy, acf_array($field['taxonomy'])))
687
+ continue;
688
+
689
+ $value = $term->name . ' (All childs)';
690
+
691
+ }
692
 
693
  // Terms childs
694
  elseif(acfe_ends_with($id, '_childs')){
700
  if(!empty($field['taxonomy']) && !in_array($taxonomy, acf_array($field['taxonomy'])))
701
  continue;
702
 
703
+ $value = $term->name . ' (Direct childs)';
704
 
705
  }
706
 
includes/modules/autosync.php CHANGED
@@ -101,7 +101,6 @@ function acfe_autosync_php_update_field_group($field_group){
101
  if(!acfe_has_field_group_autosync($field_group, 'php'))
102
  return;
103
 
104
- $field_group['fields'] = acf_get_fields($field_group);
105
  acfe_autosync_write_php($field_group);
106
 
107
  }
@@ -141,6 +140,30 @@ function acfe_autosync_write_php($field_group){
141
  // bail early if dir does not exist
142
  if(!is_writable($path))
143
  return false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
 
145
  // prepare for export
146
  $id = acf_extract_var($field_group, 'ID');
@@ -148,8 +171,7 @@ function acfe_autosync_write_php($field_group){
148
 
149
  // add modified time
150
  $field_group['modified'] = get_post_modified_time('U', true, $id, true);
151
-
152
-
153
  // Prepare
154
  $str_replace = array(
155
  " " => "\t",
@@ -172,18 +194,12 @@ function acfe_autosync_write_php($field_group){
172
  // code
173
  $code = var_export($field_group, true);
174
 
175
-
176
  // change double spaces to tabs
177
  $code = str_replace( array_keys($str_replace), array_values($str_replace), $code );
178
 
179
-
180
  // correctly formats "=> array("
181
  $code = preg_replace( array_keys($preg_replace), array_values($preg_replace), $code );
182
 
183
-
184
- // esc_textarea
185
- $code = $code;
186
-
187
  // echo
188
  echo "acf_add_local_field_group({$code});" . "\r\n" . "\r\n";
189
 
101
  if(!acfe_has_field_group_autosync($field_group, 'php'))
102
  return;
103
 
 
104
  acfe_autosync_write_php($field_group);
105
 
106
  }
140
  // bail early if dir does not exist
141
  if(!is_writable($path))
142
  return false;
143
+
144
+ // Translation
145
+ $l10n = acf_get_setting('l10n');
146
+ $l10n_textdomain = acf_get_setting('l10n_textdomain');
147
+
148
+ if(!$l10n || !$l10n_textdomain){
149
+
150
+ $field_group['fields'] = acf_get_fields($field_group);
151
+
152
+ }else{
153
+
154
+ acf_update_setting('l10n_var_export', true);
155
+
156
+ $field_group = acf_translate_field_group($field_group);
157
+
158
+ // Reset store to allow fields translation
159
+ $store = acf_get_store('fields');
160
+ $store->reset();
161
+
162
+ $field_group['fields'] = acf_get_fields($field_group);
163
+
164
+ acf_update_setting('l10n_var_export', false);
165
+
166
+ }
167
 
168
  // prepare for export
169
  $id = acf_extract_var($field_group, 'ID');
171
 
172
  // add modified time
173
  $field_group['modified'] = get_post_modified_time('U', true, $id, true);
174
+
 
175
  // Prepare
176
  $str_replace = array(
177
  " " => "\t",
194
  // code
195
  $code = var_export($field_group, true);
196
 
 
197
  // change double spaces to tabs
198
  $code = str_replace( array_keys($str_replace), array_values($str_replace), $code );
199
 
 
200
  // correctly formats "=> array("
201
  $code = preg_replace( array_keys($preg_replace), array_values($preg_replace), $code );
202
 
 
 
 
 
203
  // echo
204
  echo "acf_add_local_field_group({$code});" . "\r\n" . "\r\n";
205
 
includes/modules/dev.php CHANGED
@@ -270,7 +270,7 @@ class acfe_dev{
270
 
271
  <?php if($is_options){ ?>
272
  <span class="edit">
273
- <a href="<?php echo admin_url('options-general.php?page=acfe-options&action=edit&option=' . $meta_id); ?>>"><?php _e('Edit'); ?></a> |
274
  </span>
275
  <?php } ?>
276
 
270
 
271
  <?php if($is_options){ ?>
272
  <span class="edit">
273
+ <a href="<?php echo admin_url('options-general.php?page=acfe-options&action=edit&option=' . $meta_id); ?>"><?php _e('Edit'); ?></a> |
274
  </span>
275
  <?php } ?>
276
 
includes/modules/single-meta.php CHANGED
@@ -3,13 +3,13 @@
3
  if(!defined('ABSPATH'))
4
  exit;
5
 
 
 
 
6
  // Check setting
7
  if(!acf_get_setting('acfe/modules/single_meta'))
8
  return;
9
 
10
- // Register notices store.
11
- acf_register_store('acfe/meta')->prop('multisite', true);
12
-
13
  if(!class_exists('acfe_single_meta')):
14
 
15
  class acfe_single_meta{
@@ -29,17 +29,17 @@ class acfe_single_meta{
29
  $this->options = apply_filters('acfe/modules/single_meta/options', false);
30
 
31
  // Field Objects
32
- add_filter('acf/pre_load_meta', array($this, 'load_meta'), 999, 2);
33
 
34
  // Values
35
- add_filter('acf/pre_load_metadata', array($this, 'load_metadata'), 999, 4);
36
- add_filter('acf/update_value', array($this, 'update_value'), 999, 3);
37
- add_filter('acf/pre_update_metadata', array($this, 'update_metadata'), 999, 5);
38
- add_filter('acf/pre_delete_metadata', array($this, 'delete_metadata'), 999, 4);
39
 
40
  // Save Post
41
- add_action('acf/save_post', array($this, 'pre_save_post'), 0);
42
- add_action('acf/save_post', array($this, 'save_post'), 999);
43
 
44
  // Settings
45
  add_action('acf/render_field_settings', array($this, 'field_setting'));
@@ -62,9 +62,9 @@ class acfe_single_meta{
62
 
63
  }
64
 
65
- function load_meta($return, $post_id){
66
 
67
- if(acf_is_filter_enabled('acfe/load_meta'))
68
  return $return;
69
 
70
  // Validate Post ID
@@ -84,7 +84,7 @@ class acfe_single_meta{
84
  /*
85
  * Load Metadata
86
  */
87
- function load_metadata($return, $post_id, $name, $hidden){
88
 
89
  if($name === 'acf')
90
  return $return;
@@ -122,11 +122,11 @@ class acfe_single_meta{
122
  */
123
  function update_value($value, $post_id, $field){
124
 
125
- acf_disable_filter('acfe/save');
126
 
127
  if(acf_maybe_get($field, 'acfe_save_meta')){
128
 
129
- acf_enable_filter('acfe/save');
130
 
131
  }
132
 
@@ -137,7 +137,7 @@ class acfe_single_meta{
137
  /*
138
  * Update Metadata
139
  */
140
- function update_metadata($return, $post_id, $name, $value, $hidden){
141
 
142
  if($name === 'acf')
143
  return $return;
@@ -151,9 +151,6 @@ class acfe_single_meta{
151
  // Get store
152
  $store = $this->get_store($post_id);
153
  $acf = $store->get("$post_id:acf");
154
-
155
- // Decode $post_id for $type and $id.
156
- extract(acf_decode_post_id($post_id));
157
 
158
  // Prefix
159
  $prefix = $hidden ? '_' : '';
@@ -163,35 +160,27 @@ class acfe_single_meta{
163
 
164
  // Update store
165
  $store->set("$post_id:acf", $acf);
166
-
167
- // Update option
168
- if($type === 'option'){
169
-
170
- $acf = wp_unslash($acf);
171
- $autoload = (bool) acf_get_setting('autoload');
172
-
173
- update_option($id, $acf, $autoload);
174
-
175
- // Update meta
176
- }else{
177
-
178
- acf_update_metadata($post_id, 'acf', $acf);
179
 
 
 
 
 
 
180
  }
181
 
182
  // Save normally
183
- if(acf_is_filter_enabled('acfe/save')){
184
 
185
  return null;
186
 
187
  }
188
 
189
- // Delete Native ACF field
190
- acf_enable_filter('acfe/delete');
191
 
192
  acf_delete_metadata($post_id, $name, $hidden);
193
 
194
- acf_disable_filter('acfe/delete');
195
 
196
  // Do not save as meta
197
  return true;
@@ -201,9 +190,9 @@ class acfe_single_meta{
201
  /*
202
  * Delete Metadata
203
  */
204
- function delete_metadata($return, $post_id, $name, $hidden){
205
 
206
- if($name === 'acf' || acf_is_filter_enabled('acfe/delete'))
207
  return $return;
208
 
209
  // Validate Post ID
@@ -219,9 +208,6 @@ class acfe_single_meta{
219
  // Bail early if empty
220
  if(empty($acf))
221
  return $return;
222
-
223
- // Decode $post_id for $type and $id.
224
- extract(acf_decode_post_id($post_id));
225
 
226
  // Prefix
227
  $prefix = $hidden ? '_' : '';
@@ -234,20 +220,7 @@ class acfe_single_meta{
234
  // Update store
235
  $store->set("$post_id:acf", $acf);
236
 
237
- // Update option
238
- if($type === 'option'){
239
-
240
- $acf = wp_unslash($acf);
241
- $autoload = (bool) acf_get_setting('autoload');
242
-
243
- update_option($id, $acf, $autoload);
244
-
245
- // Update meta
246
- }else{
247
-
248
- acf_update_metadata($post_id, 'acf', $acf);
249
-
250
- }
251
 
252
  }
253
 
@@ -269,12 +242,13 @@ class acfe_single_meta{
269
  if(!$validate)
270
  return;
271
 
272
- // Reset ACF
273
- $acf = array();
 
274
 
275
- // Check store.
276
  $store = acf_get_store('acfe/meta');
277
- $store->set("$post_id:acf", $acf);
278
 
279
  }
280
 
@@ -283,45 +257,55 @@ class acfe_single_meta{
283
  */
284
  function save_post($post_id = 0){
285
 
286
- if(!acf_maybe_get_POST('acfe_clean_meta'))
287
  return;
288
 
289
  // Validate Post ID
290
  $validate = $this->validate_post_id($post_id);
291
-
292
  if(!$validate)
293
  return;
294
-
295
  $store = $this->get_store($post_id);
296
  $acf = $store->get("$post_id:acf");
297
 
298
- acf_enable_filter('acfe/load_meta');
299
 
 
 
 
 
 
300
  $meta = acf_get_meta($post_id);
 
 
 
 
 
 
 
 
 
 
301
 
302
- acf_disable_filter('acfe/load_meta');
 
 
303
 
304
- if(empty($meta))
305
- return;
306
-
307
- acf_enable_filter('acfe/delete');
308
 
309
- foreach($meta as $key => $value){
310
-
311
- // bail if not ACF field
312
- if(!isset($meta["_$key"]))
313
- continue;
314
-
315
- // Bail early if exists in Single Value array
316
- if(isset($acf[$key]))
317
- continue;
318
-
319
- acf_delete_metadata($post_id, $key);
320
- acf_delete_metadata($post_id, $key, true);
321
 
322
  }
323
 
324
- acf_disable_filter('acfe/delete');
325
 
326
  }
327
 
@@ -395,22 +379,10 @@ class acfe_single_meta{
395
 
396
  // Store found
397
  if(!$store->has("$post_id:acf")){
398
-
399
- // Decode $post_id for $type and $id.
400
- extract(acf_decode_post_id($post_id));
401
-
402
- // Get option
403
- if($type === 'option'){
404
-
405
- $acf = get_option($id, null);
406
-
407
- // Get meta
408
- }else{
409
-
410
- $acf = acf_get_metadata($post_id, 'acf');
411
-
412
- }
413
 
 
 
 
414
  // Set Store: ACF meta
415
  $store->set("$post_id:acf", $acf);
416
 
@@ -420,6 +392,49 @@ class acfe_single_meta{
420
 
421
  }
422
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
  /*
424
  * Field Setting
425
  */
3
  if(!defined('ABSPATH'))
4
  exit;
5
 
6
+ // Register store
7
+ acf_register_store('acfe/meta')->prop('multisite', true);
8
+
9
  // Check setting
10
  if(!acf_get_setting('acfe/modules/single_meta'))
11
  return;
12
 
 
 
 
13
  if(!class_exists('acfe_single_meta')):
14
 
15
  class acfe_single_meta{
29
  $this->options = apply_filters('acfe/modules/single_meta/options', false);
30
 
31
  // Field Objects
32
+ add_filter('acf/pre_load_meta', array($this, 'pre_load_meta'), 999, 2);
33
 
34
  // Values
35
+ add_filter('acf/pre_load_metadata', array($this, 'pre_load_metadata'), 999, 4);
36
+ add_filter('acf/update_value', array($this, 'update_value'), 999, 3);
37
+ add_filter('acf/pre_update_metadata', array($this, 'pre_update_metadata'), 999, 5);
38
+ add_filter('acf/pre_delete_metadata', array($this, 'pre_delete_metadata'), 999, 4);
39
 
40
  // Save Post
41
+ add_action('acf/save_post', array($this, 'pre_save_post'), 0);
42
+ add_action('acf/save_post', array($this, 'save_post'), 999);
43
 
44
  // Settings
45
  add_action('acf/render_field_settings', array($this, 'field_setting'));
62
 
63
  }
64
 
65
+ function pre_load_meta($return, $post_id){
66
 
67
+ if(acf_is_filter_enabled('acfe/meta/native_load'))
68
  return $return;
69
 
70
  // Validate Post ID
84
  /*
85
  * Load Metadata
86
  */
87
+ function pre_load_metadata($return, $post_id, $name, $hidden){
88
 
89
  if($name === 'acf')
90
  return $return;
122
  */
123
  function update_value($value, $post_id, $field){
124
 
125
+ acf_disable_filter('acfe/meta/native_save');
126
 
127
  if(acf_maybe_get($field, 'acfe_save_meta')){
128
 
129
+ acf_enable_filter('acfe/meta/native_save');
130
 
131
  }
132
 
137
  /*
138
  * Update Metadata
139
  */
140
+ function pre_update_metadata($return, $post_id, $name, $value, $hidden){
141
 
142
  if($name === 'acf')
143
  return $return;
151
  // Get store
152
  $store = $this->get_store($post_id);
153
  $acf = $store->get("$post_id:acf");
 
 
 
154
 
155
  // Prefix
156
  $prefix = $hidden ? '_' : '';
160
 
161
  // Update store
162
  $store->set("$post_id:acf", $acf);
 
 
 
 
 
 
 
 
 
 
 
 
 
163
 
164
+ // Update if not compiling
165
+ if(!acf_is_filter_enabled("acfe/meta/compile/{$post_id}")){
166
+
167
+ $this->update_meta('acf', $acf, $post_id);
168
+
169
  }
170
 
171
  // Save normally
172
+ if(acf_is_filter_enabled('acfe/meta/native_save')){
173
 
174
  return null;
175
 
176
  }
177
 
178
+ // Delete Native ACF field if it already exists
179
+ acf_enable_filter('acfe/meta/native_delete');
180
 
181
  acf_delete_metadata($post_id, $name, $hidden);
182
 
183
+ acf_disable_filter('acfe/meta/native_delete');
184
 
185
  // Do not save as meta
186
  return true;
190
  /*
191
  * Delete Metadata
192
  */
193
+ function pre_delete_metadata($return, $post_id, $name, $hidden){
194
 
195
+ if($name === 'acf' || acf_is_filter_enabled('acfe/meta/native_delete'))
196
  return $return;
197
 
198
  // Validate Post ID
208
  // Bail early if empty
209
  if(empty($acf))
210
  return $return;
 
 
 
211
 
212
  // Prefix
213
  $prefix = $hidden ? '_' : '';
220
  // Update store
221
  $store->set("$post_id:acf", $acf);
222
 
223
+ $this->update_meta('acf', $acf, $post_id);
 
 
 
 
 
 
 
 
 
 
 
 
 
224
 
225
  }
226
 
242
  if(!$validate)
243
  return;
244
 
245
+ // Enable filter
246
+ acf_enable_filter("acfe/meta/compile/{$post_id}");
247
+ acf_enable_filter("acfe/meta/clean/{$post_id}");
248
 
249
+ // Check store
250
  $store = acf_get_store('acfe/meta');
251
+ $store->set("$post_id:acf", array());
252
 
253
  }
254
 
257
  */
258
  function save_post($post_id = 0){
259
 
260
+ if(!acf_is_filter_enabled("acfe/meta/compile/{$post_id}"))
261
  return;
262
 
263
  // Validate Post ID
264
  $validate = $this->validate_post_id($post_id);
265
+
266
  if(!$validate)
267
  return;
268
+
269
  $store = $this->get_store($post_id);
270
  $acf = $store->get("$post_id:acf");
271
 
272
+ $this->update_meta('acf', $acf, $post_id);
273
 
274
+ // Clean
275
+ if(acf_is_filter_enabled("acfe/meta/clean/{$post_id}")){
276
+
277
+ acf_enable_filter('acfe/meta/native_load');
278
+
279
  $meta = acf_get_meta($post_id);
280
+
281
+ acf_disable_filter('acfe/meta/native_load');
282
+
283
+ // Bail early if no meta to clean
284
+ if(empty($meta))
285
+ return;
286
+
287
+ acf_enable_filter('acfe/meta/native_delete');
288
+
289
+ foreach($meta as $key => $value){
290
 
291
+ // bail if not ACF field
292
+ if(!isset($meta["_$key"]))
293
+ continue;
294
 
295
+ // Bail early if exists in Single Value array
296
+ if(isset($acf[$key]))
297
+ continue;
 
298
 
299
+ acf_delete_metadata($post_id, $key);
300
+ acf_delete_metadata($post_id, $key, true);
301
+
302
+ }
303
+
304
+ acf_disable_filter('acfe/meta/native_delete');
 
 
 
 
 
 
305
 
306
  }
307
 
308
+
309
 
310
  }
311
 
379
 
380
  // Store found
381
  if(!$store->has("$post_id:acf")){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
+ // Get meta
384
+ $acf = $this->get_meta('acf', $post_id);
385
+
386
  // Set Store: ACF meta
387
  $store->set("$post_id:acf", $acf);
388
 
392
 
393
  }
394
 
395
+ function get_meta($name, $post_id){
396
+
397
+ // Decode $post_id for $type and $id.
398
+ extract(acf_decode_post_id($post_id));
399
+
400
+ // Get option
401
+ if($type === 'option'){
402
+
403
+ $value = get_option($id, null);
404
+
405
+ // Get meta
406
+ }else{
407
+
408
+ $value = acf_get_metadata($post_id, $name);
409
+
410
+ }
411
+
412
+ return $value;
413
+
414
+ }
415
+
416
+ function update_meta($name, $value, $post_id){
417
+
418
+ // Decode $post_id for $type and $id.
419
+ extract(acf_decode_post_id($post_id));
420
+
421
+ // Update option
422
+ if($type === 'option'){
423
+
424
+ $value = wp_unslash($value);
425
+ $autoload = (bool) acf_get_setting('autoload');
426
+
427
+ return update_option($id, $value, $autoload);
428
+
429
+ // Update meta
430
+ }else{
431
+
432
+ return acf_update_metadata($post_id, $name, $value);
433
+
434
+ }
435
+
436
+ }
437
+
438
  /*
439
  * Field Setting
440
  */
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: acf, custom fields, meta, admin, fields, form, repeater, content
5
  Requires at least: 4.9
6
  Tested up to: 5.4
7
  Requires PHP: 5.6
8
- Stable tag: 0.8.6.5
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -846,6 +846,17 @@ function my_acfe_modules(){
846
 
847
  == Changelog ==
848
 
 
 
 
 
 
 
 
 
 
 
 
849
  = 0.8.6.5 =
850
  * General: Added WPML & Polylang compatibility for Options Pages with custom post ids. ie: `my-theme` post id will be translated to `my-theme_en` with WPML & `my-theme_en_US` with Polylang
851
  * Modules: Dynamic Post Types, Taxonomies, Options Pages & Block Types - Added Multilingual compatibility for WPML & Polylang. Items are automatically registered as strings for both WPML & Polylang plugins
5
  Requires at least: 4.9
6
  Tested up to: 5.4
7
  Requires PHP: 5.6
8
+ Stable tag: 0.8.6.6
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
846
 
847
  == Changelog ==
848
 
849
+ = 0.8.6.6 =
850
+ * Module: Multilang - Fixed WPML front-end language detection for custom languages
851
+ * Module: Settings - Added "Multilang" & "Single Meta" settings in the UI
852
+ * Module: Settings - Fixed `l10n_textdomain` which wasn't correctly displayed
853
+ * Module: Dev Mode - Fixed option "Edit" action link
854
+ * Module: PHP AutoSync - Added l10n support
855
+ * Module: Single Meta - Enhanced "Delete Orphan Meta" setting logic & performance
856
+ * Field: Taxonomy Terms - Added "Term (All childs)" to display any childs level terms
857
+ * Field: Taxonomy Terms - Renamed "Term (Childs)" to "Term (Direct childs)" to avoid confusion with the new filter
858
+ * Field: Taxonomy Terms - Fixed "Term (Direct childs)" which could be duplicated in some cases
859
+
860
  = 0.8.6.5 =
861
  * General: Added WPML & Polylang compatibility for Options Pages with custom post ids. ie: `my-theme` post id will be translated to `my-theme_en` with WPML & `my-theme_en_US` with Polylang
862
  * Modules: Dynamic Post Types, Taxonomies, Options Pages & Block Types - Added Multilingual compatibility for WPML & Polylang. Items are automatically registered as strings for both WPML & Polylang plugins