Skip to content

Commit 8856aa9

Browse files
committed
Handle field name ambiguities
1 parent 887086d commit 8856aa9

File tree

9 files changed

+168
-37
lines changed

9 files changed

+168
-37
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
ACF Customizer
22
==============
33

4+
0.3.0
5+
-----
6+
- Better handling of ambigous field names
7+
- Fix: values not appearin in preview if never been saved before
8+
49
0.2.15
510
------
611
- Support bundled with ACF. (Kudos to [@sebastianthulin](https://github.com/sebastianthulin))

README.md

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Supported ACF versions: 5.6 – 5.9
77
Tested with WordPress 4.9 – 5.6
88

99
This plugin is currently in beta stadium.
10-
Any Help testing and bugfixing is highly appreciated.
10+
Any Help testing and bugfixing is highly appreciated (and bundled with my premature apologies for late responses).
1111

1212
Installation
1313
------------
@@ -35,13 +35,6 @@ Installation
3535
- Install and activate it like any other WordPress plugin
3636
- As long as the plugin is active, it will check for updates
3737

38-
Developing
39-
----------
40-
This plugin uses gulp.
41-
42-
To get started `cd` in the plugin directory,
43-
run `npm install` then `gulp`
44-
4538
Usage
4639
-----
4740
There is some documentation in the [wiki](../../wiki).

include/ACFCustomizer/Compat/ACF/ACF.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,107 @@ protected function __construct() {
3636

3737
}
3838

39+
/**
40+
* Return proper field key for field in context of $post_id.
41+
*
42+
* @param Array $field Minimum ACF field [ 'name' => 'some-name' ]
43+
* @param String|Integer $post_id
44+
* @return String a proper field key if applicable, field name otherwise
45+
*/
46+
public function ensure_field_key( $field, $post_id ) {
47+
if ( ! empty( $field['key'] ) ) {
48+
return $field['key'];
49+
}
50+
global $wpdb;
51+
$local_fields = acf_get_local_store( 'fields' )->query(array(
52+
'name' => $field['name']
53+
));
54+
$candidates = array_keys( $local_fields );
55+
$candidates = array_merge( $candidates, $wpdb->get_col( $wpdb->prepare(
56+
"SELECT post_name FROM $wpdb->posts WHERE post_excerpt = %s",
57+
$field['name']
58+
)));
59+
$candidates = array_unique( $candidates );
60+
61+
if ( 1 === count( $candidates ) ) {
62+
return $candidates[0];
63+
}
64+
$acf = ACF::instance();
65+
// ambigous ...
66+
67+
foreach ( $candidates as $candidate_key ) {
68+
$candidate_field = acf_get_field( $candidate_key );
69+
$is_handling = $acf->acf_field_is_handling_post_id( $candidate_field, $post_id );
70+
if ( $is_handling ) {
71+
return $candidate_key;
72+
}
73+
// check if $candidate_field is responsible for handling $post_id
74+
}
75+
76+
return $field['name'];
77+
}
78+
79+
/**
80+
* returns whether an ACF field is handling data for specified post_id
81+
*/
82+
public function acf_field_is_handling_post_id( $acf_field, $post_id ) {
83+
84+
$decoded_post_id = acf_decode_post_id( $post_id );
85+
if ( ! in_array( $decoded_post_id['type'], [ 'post', 'term', 'option' ] ) ) {
86+
return false;
87+
}
88+
89+
$field_group = $this->get_acf_field_root( $acf_field );
90+
if ( ! $field_group ) {
91+
return false;
92+
}
93+
$locations = $field_group['location'];
94+
$locations = array_filter( $locations, [ $this, 'filter_customizer_locations'] );
95+
96+
foreach ( $locations as $location ) {
97+
foreach ( $location as $loc ) {
98+
99+
if ( $section = acf_get_customizer_section( $loc['value'] ) ) {
100+
if ( $section['storage_type'] !== 'option' && $section['storage_type'] === $decoded_post_id['type'] ) {
101+
return true;
102+
}
103+
if ( $section['storage_type'] === 'option' && $section['storage_type'] === $decoded_post_id['type'] && $section['post_id'] === $post_id ) {
104+
return true;
105+
}
106+
}
107+
}
108+
}
109+
return false;
110+
}
111+
112+
/**
113+
* array_filter callback
114+
*/
115+
private function filter_customizer_locations( $location ) {
116+
foreach ( $location as $loc ) {
117+
if ( $loc[ 'param' ] === 'customizer' ) {
118+
return true;
119+
}
120+
}
121+
return false;
122+
}
123+
124+
/**
125+
* Get root field group for field
126+
*
127+
* @param Array $acf_field
128+
* @return Array acf field group
129+
*/
130+
public function get_acf_field_root( $acf_field ) {
131+
while ( $acf_field ) {
132+
if ( 0 === strpos( $acf_field['parent'], 'group_' ) ) {
133+
return acf_get_field_group( $acf_field['parent'] );
134+
}
135+
$acf_field = acf_get_field( $acf_field['parent'] );
136+
}
137+
return false;
138+
}
139+
39140
/**
40141
* @action acf/include_location_rules
41142
*/

include/ACFCustomizer/Compat/ACF/CustomizePreview.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ private function build_path( $selector = null, $post_id = null ) {
7979
$is_loop = $acf_loop->is_loop();
8080

8181
$customize = Customize::instance();
82+
$acf = ACF::instance();
8283

8384
if ( is_null( $post_id ) ) {
8485
if ( $is_loop ) {
@@ -95,13 +96,15 @@ private function build_path( $selector = null, $post_id = null ) {
9596
if ( ! is_null( $selector ) ) {
9697

9798
if ( $is_loop ) {
98-
if ( $field = get_sub_field_object( $selector, $post_id ) ) {
99-
$path[] = $field['key'];
100-
}
99+
$field = get_sub_field_object( $selector, $post_id );
101100
} else {
102-
if ( $field = get_field_object( $selector, $post_id ) ) {
103-
$path[] = $field['key'];
104-
}
101+
$field = get_field_object( $selector, $post_id );
102+
}
103+
if ( $field ) {
104+
$path[] = $field['key'];
105+
} else {
106+
$field = get_field_object( $acf->ensure_field_key( [ 'name' => $selector ], $post_id ), $post_id );
107+
$path[] = $field['key'];
105108
}
106109
}
107110

@@ -115,9 +118,14 @@ private function build_path( $selector = null, $post_id = null ) {
115118
$path[] = $loop['i'];
116119
$path[] = $field['key'];
117120
}
118-
} else {
119-
$field = get_field_object( $selector, $post_id );
121+
// } else {
122+
// $field = acf_get_field( $acf->ensure_field_key( [ 'name' => $selector ], $post_id ), $post_id );
120123
}
124+
if ( ! $field ) {
125+
var_dump($loops);
126+
var_dump($path);
127+
var_dump($acf->ensure_field_key( [ 'name' => $selector ], $post_id ));
128+
}
121129
$field_group_key = $field['parent'];
122130

123131
$path[] = $field_group_key; // field group

include/ACFCustomizer/Compat/ACF/Storage/Option.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ protected function __construct() {
2727
public function pre_load_value( $value, $post_id, $field ) {
2828

2929
if ( $this->has_setting_id( $post_id ) ) {
30-
return $this->get_changeset_value( $field['key'], $value, $post_id );
30+
return $this->get_changeset_value( $field, $value, $post_id );
3131
}
3232

3333
return $value;

include/ACFCustomizer/Compat/ACF/Storage/Post.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ protected function __construct() {
2626
* @filter acf/pre_load_value
2727
*/
2828
public function pre_load_value( $value, $post_id, $field ) {
29-
3029
if ( $this->is_context( $post_id, 'post' ) ) {
31-
return $this->get_changeset_value( $field['key'], $value );
30+
return $this->get_changeset_value( $field, $value, $post_id );
3231
}
3332

3433
return $value;

include/ACFCustomizer/Compat/ACF/Storage/Storage.php

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace ACFCustomizer\Compat\ACF\Storage;
44

55
use ACFCustomizer\Core;
6+
use ACFCustomizer\Compat\ACF\ACF;
67

78
abstract class Storage extends Core\Singleton {
89

@@ -40,6 +41,8 @@ protected function __construct() {
4041
$this->set_context();
4142
}
4243

44+
45+
4346
/**
4447
* register a post id
4548
*
@@ -160,29 +163,46 @@ public function permitted() {
160163
* @param string $fallback What to return if no changeset data found
161164
* @return mixed
162165
*/
163-
protected function get_changeset_value( $field_key, $fallback = null, $post_id = null ) {
164-
165-
$changeset_data = false;
166-
/*
167-
TODO
168-
Fix WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
169-
Fix WordPress.Security.NonceVerification.Missing
170-
*/
166+
protected function get_changeset_value( $field, $fallback = null, $post_id = null ) {
167+
168+
$field_key = ACF::instance()->ensure_field_key( $field, $post_id );
169+
170+
$decoded_post_id = acf_decode_post_id( $post_id );
171+
$changeset_data = $this->manager->changeset_data();
172+
$changeset_data = array_map( [ $this, '_flatten_value' ], $changeset_data );
173+
171174
if ( isset( $_POST['customized'] ) ) {
172-
$changeset_data = json_decode( wp_unslash( $_POST['customized'] ), true );
175+
$posted_changeset = json_decode( wp_unslash( $_POST['customized'] ), true );
176+
$changeset_data = $posted_changeset + $changeset_data;
173177
}
174178

179+
$value = $this->find_in_changeset( $changeset_data, $field_key, $decoded_post_id['type'] === 'option' ? $post_id : null );
175180

176-
if ( ! $changeset_data ) {
177-
$changeset_data = $this->manager->changeset_data();
178-
$changeset_data = array_map( [ $this, '_flatten_value' ], $changeset_data );
181+
if ( is_null( $value ) ) {
182+
return $fallback;
179183
}
180-
// options an theme_mods are stored under their post id
184+
185+
return $value;
186+
}
187+
188+
189+
190+
/**
191+
* Find value for field key in changeset data
192+
*
193+
* @param Array $changeset_data
194+
* @param String $field_key
195+
* @param Mixed $post_id
196+
*
197+
* @return Mixed
198+
*/
199+
private function find_in_changeset( $changeset_data, $field_key, $post_id ) {
200+
// options and theme_mods are stored under their post id
181201
if ( ! is_null( $post_id ) ) {
182202
if ( isset( $changeset_data[ $post_id ] ) && isset( $changeset_data[ $post_id ][ $field_key ] ) ) {
183203
return $changeset_data[ $post_id ][ $field_key ];
184204
}
185-
return $fallback;
205+
return null;
186206
}
187207
foreach ( $changeset_data as $key => $data ) {
188208

@@ -191,9 +211,14 @@ protected function get_changeset_value( $field_key, $fallback = null, $post_id =
191211
return $data[ $field_key ];
192212
}
193213
}
194-
return $fallback;
214+
return null;
195215
}
196-
216+
/**
217+
* array_map() callback
218+
*
219+
* @param Array $el
220+
* @return Mixed $el['value']
221+
*/
197222
private function _flatten_value( $el ) {
198223
if ( isset( $el['value'] ) ) {
199224
return $el['value'];

include/ACFCustomizer/Compat/ACF/Storage/Term.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ protected function __construct() {
3030
public function pre_load_value( $value, $post_id, $field ) {
3131

3232
if ( $this->is_context( $post_id, 'term' ) ) {
33-
return $this->get_changeset_value( $field, $value );
33+
return $this->get_changeset_value( $field, $value, $post_id );
3434
}
3535

3636
return $value;

test/templates/template-parts/acf/basic.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<dl>
99
<?php
1010

11-
foreach ( [ 'text', 'textarea', 'number', 'range', 'e-mail', 'url' ] as $selector ) {
11+
foreach ( [ 'text', 'textarea', 'number', 'range', 'e-mail', 'url', 'ambigous_name' ] as $selector ) {
1212
?>
1313
<dt><?php
1414
do_action( 'acf_customizer_field', $selector, $acf_test_post_id );

0 commit comments

Comments
 (0)