4
4
*/
5
5
6
6
/**
7
- * Data source for WordPress Posts , for autocomplete and option types.
7
+ * Data source for WordPress Users , for autocomplete and option types.
8
8
* @package Fieldmanager_Datasource
9
9
*/
10
10
class Fieldmanager_Datasource_User extends Fieldmanager_Datasource {
@@ -35,6 +35,25 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource {
35
35
*/
36
36
public $ display_property = 'display_name ' ;
37
37
38
+ /**
39
+ * @var array
40
+ * Allowed display properties for validation.
41
+ */
42
+ protected $ allowed_display_properties = array ( 'display_name ' , 'user_login ' , 'user_email ' , 'user_nicename ' );
43
+
44
+ /**
45
+ * @var string
46
+ * Store property. Defaults to ID, but can also be 'user_login', 'user_email',
47
+ * or 'user_nicename'.
48
+ */
49
+ public $ store_property = 'ID ' ;
50
+
51
+ /**
52
+ * @var array
53
+ * Allowed store properties for validation.
54
+ */
55
+ protected $ allowed_store_properties = array ( 'ID ' , 'user_login ' , 'user_email ' , 'user_nicename ' );
56
+
38
57
/**
39
58
* @var string
40
59
* Capability required to refer to a user via this datasource.
@@ -44,23 +63,66 @@ class Fieldmanager_Datasource_User extends Fieldmanager_Datasource {
44
63
45
64
/**
46
65
* @var string|Null
47
- * If not empty, set this post 's ID as a value on the user. This is used to
66
+ * If not empty, set this object 's ID as a value on the user. This is used to
48
67
* establish two-way relationships.
49
68
*/
50
69
public $ reciprocal = Null ;
51
70
52
- // constructor not required for this datasource; options are just set to keys,
53
- // which Fieldmanager_Datasource does.
71
+ /**
72
+ * Constructor. Used for validation.
73
+ */
74
+ public function __construct ( $ options = array () ) {
75
+ parent ::__construct ( $ options );
76
+
77
+ // Validate improper usage of store property
78
+ if ( ! in_array ( $ this ->store_property , $ this ->allowed_store_properties ) ) {
79
+ throw new FM_Developer_Exception ( sprintf (
80
+ __ ( 'Store property %s is invalid. Must be one of %s. ' , 'fieldmanager ' ),
81
+ $ this ->store_property ,
82
+ implode ( ', ' , $ this ->allowed_store_properties )
83
+ ) );
84
+ }
85
+
86
+ if ( ! empty ( $ this ->reciprocal ) && 'ID ' != $ this ->store_property ) {
87
+ throw new FM_Developer_Exception ( __ ( 'You cannot use reciprocal relationships with FM_Datasource_User if store_property is not set to ID. ' , 'fieldmanager ' ) );
88
+ }
89
+
90
+ // Validate improper usage of display property
91
+ if ( ! in_array ( $ this ->display_property , $ this ->allowed_display_properties ) ) {
92
+ throw new FM_Developer_Exception ( sprintf (
93
+ __ ( 'Display property %s is invalid. Must be one of %s. ' , 'fieldmanager ' ),
94
+ $ this ->display_property ,
95
+ implode ( ', ' , $ this ->allowed_display_properties )
96
+ ) );
97
+ }
98
+ }
54
99
55
100
/**
56
- * Get a post title by post ID
101
+ * Get a user by the specified field.
57
102
* @param int $value post_id
58
- * @return string post title
103
+ * @return int| string
59
104
*/
60
105
public function get_value ( $ value ) {
61
- $ id = intval ( $ value );
62
- $ user = get_userdata ( $ id );
63
- return $ user ? $ user ->{$ this ->display_property } : '' ;
106
+ switch ( $ this ->store_property ) {
107
+ case 'ID ' :
108
+ $ field = 'id ' ;
109
+ break ;
110
+ case 'user_nicename ' :
111
+ $ field = 'slug ' ;
112
+ break ;
113
+ case 'user_email ' :
114
+ $ field = 'email ' ;
115
+ break ;
116
+ case 'user_login ' :
117
+ $ field = 'login ' ;
118
+ break ;
119
+ }
120
+
121
+ // Sanitize the value
122
+ $ value = $ this ->sanitize_value ( $ value );
123
+
124
+ $ user = get_user_by ( $ field , $ value );
125
+ return $ user ? $ user ->{$ this ->display_property } : '' ;
64
126
}
65
127
66
128
/**
@@ -73,14 +135,20 @@ public function get_items( $fragment = Null ) {
73
135
if ( is_callable ( $ this ->query_callback ) ) {
74
136
return call_user_func ( $ this ->query_callback , $ fragment );
75
137
}
138
+
76
139
$ default_args = array ();
77
140
$ user_args = array_merge ( $ default_args , $ this ->query_args );
78
141
$ ret = array ();
79
- if ( $ fragment ) $ user_args ['search ' ] = $ fragment ;
142
+
143
+ if ( $ fragment ) {
144
+ $ user_args ['search ' ] = $ fragment ;
145
+ }
146
+
80
147
$ users = get_users ( $ user_args );
81
148
foreach ( $ users as $ u ) {
82
- $ ret [$ u ->ID ] = $ u ->{$ this ->display_property };
149
+ $ ret [ $ u ->{ $ this -> store_property } ] = $ u ->{$ this ->display_property };
83
150
}
151
+
84
152
return $ ret ;
85
153
}
86
154
@@ -98,44 +166,57 @@ public function get_ajax_action() {
98
166
}
99
167
100
168
/**
101
- * For post relationships, delete reciprocal post metadata prior to saving (presave will re-add)
169
+ * Delete reciprocal user metadata prior to saving (presave will re-add).
170
+ * Reciprocal relationships are not possible if we are not storing by ID.
102
171
* @param array $values new post values
103
172
* @param array $current_values existing post values
104
173
*/
105
174
public function presave_alter_values ( Fieldmanager_Field $ field , $ values , $ current_values ) {
106
- if ( $ field ->data_type != 'post ' || !$ this ->reciprocal ) return $ values ;
107
- foreach ( $ current_values as $ user_id ) {
108
- delete_user_meta ( $ user_id , $ this ->reciprocal , $ field ->data_id );
109
- }
175
+ if ( $ field ->data_type != 'post ' || ! $ this ->reciprocal || 'ID ' != $ this ->store_property ) {
176
+ return $ values ;
177
+ }
178
+
179
+ if ( ! empty ( $ current_values ) ) {
180
+ foreach ( $ current_values as $ user_id ) {
181
+ delete_user_meta ( $ user_id , $ this ->reciprocal , $ field ->data_id );
182
+ }
183
+ }
184
+
110
185
return $ values ;
111
186
}
112
187
113
188
/**
114
- * Handle reciprocal postmeta
189
+ * Handle reciprocal usermeta.
190
+ * Reciprocal relationships are not possible if we are not storing by ID.
115
191
* @param int $value
116
192
* @return string
117
193
*/
118
194
public function presave ( Fieldmanager_Field $ field , $ value , $ current_value ) {
119
- if ( empty ( $ value ) ) return ;
195
+ if ( empty ( $ value ) ) {
196
+ return ;
197
+ }
198
+
120
199
$ return_single = False ;
121
200
if ( !is_array ( $ value ) ) {
122
201
$ return_single = True ;
123
202
$ value = array ( $ value );
124
203
}
204
+
125
205
foreach ( $ value as $ i => $ v ) {
126
- $ value [$ i ] = intval ( $ v );
127
- if ( !current_user_can ( $ this ->capability , $ v ) ) {
206
+ $ value [$ i ] = $ this -> sanitize_value ( $ v );
207
+ if ( ! current_user_can ( $ this ->capability , $ v ) ) {
128
208
wp_die ( esc_html ( sprintf ( __ ( 'Tried to refer to user "%s" which current user cannot edit. ' , 'fieldmanager ' ), $ v ) ) );
129
209
}
130
- if ( $ this ->reciprocal ) {
210
+ if ( $ this ->reciprocal && ' ID ' == $ this -> store_property ) {
131
211
add_user_meta ( $ v , $ this ->reciprocal , $ field ->data_id );
132
212
}
133
213
}
214
+
134
215
return $ return_single ? $ value [0 ] : $ value ;
135
216
}
136
217
137
218
/**
138
- * Get view link for a user
219
+ * Get view link for a user.
139
220
* @param int $value
140
221
* @return string
141
222
*/
@@ -144,7 +225,7 @@ public function get_view_link( $value ) {
144
225
}
145
226
146
227
/**
147
- * Get edit link for a user
228
+ * Get edit link for a user.
148
229
* @param int $value
149
230
* @return string
150
231
*/
@@ -156,4 +237,25 @@ public function get_edit_link( $value ) {
156
237
esc_html__ ( 'Edit ' , 'fieldmanager ' )
157
238
);
158
239
}
159
- }
240
+
241
+ /**
242
+ * Sanitize the value based on store_property.
243
+ * @param int|string $value
244
+ * @return int|string
245
+ */
246
+ protected function sanitize_value ( $ value ) {
247
+ switch ( $ this ->store_property ) {
248
+ case 'ID ' :
249
+ $ value = intval ( $ value );
250
+ break ;
251
+ case 'user_email ' :
252
+ $ value = sanitize_email ( $ value );
253
+ break ;
254
+ default :
255
+ $ value = sanitize_text_field ( $ value );
256
+ break ;
257
+ }
258
+
259
+ return $ value ;
260
+ }
261
+ }
0 commit comments