PluginProbe ʕ •ᴥ•ʔ
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress / trunk
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress vtrunk
4.16.18 4.16.17 4.16.16 trunk 1.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5a 1.1.6 1.1.7 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4 1.4.1 1.4.2 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.7 1.7.1 1.7.2 1.8 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.1.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.2 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 3.0 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.13.4 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.15.0 4.15.1 4.15.10 4.15.11 4.15.12 4.15.13 4.15.14 4.15.15 4.15.16 4.15.17 4.15.18 4.15.19 4.15.2 4.15.20 4.15.20.1 4.15.21 4.15.22 4.15.23 4.15.24 4.15.25 4.15.3 4.15.4 4.15.5 4.15.6 4.15.7 4.15.8 4.15.9 4.16.0 4.16.1 4.16.10 4.16.11 4.16.12 4.16.13 4.16.14 4.16.15 4.16.2 4.16.3 4.16.4 4.16.5 4.16.6 4.16.7 4.16.8 4.16.9 4.2.0 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.7.0 4.8.0 4.9.0
wp-user-avatar / src / Themes / DragDrop / MemberDirectoryTrait.php
wp-user-avatar / src / Themes / DragDrop Last commit date
EditProfile 5 years ago Login 3 years ago MemberDirectory 7 months ago PasswordReset 5 years ago Registration 3 years ago UserProfile 1 year ago AbstractBuildScratch.php 7 months ago AbstractMemberDirectoryTheme.php 4 months ago AbstractTheme.php 11 months ago FieldListing.php 7 months ago MemberDirectoryListing.php 2 months ago MemberDirectoryTrait.php 1 year ago ProfileFieldListing.php 2 months ago ThemeInterface.php 5 years ago ThemesRepository.php 1 year ago index.php 5 years ago
MemberDirectoryTrait.php
411 lines
1 <?php
2
3 namespace ProfilePress\Core\Themes\DragDrop;
4
5 use WP_User;
6 use WP_User_Query;
7
8 trait MemberDirectoryTrait
9 {
10 protected int $_form_id;
11
12 protected array $args;
13
14 public function initializeMemberDirectoryTrait($_form_id, $args)
15 {
16 $this->_form_id = $_form_id;
17
18 $this->args = $args;
19 }
20
21 protected function search_query_key(): string
22 {
23 return 'search-' . $this->_form_id;
24 }
25
26 protected function search_filter_query_params()
27 {
28 static $cache = [];
29
30 if ( ! isset($cache[$this->_form_id])) {
31
32 $query_params = [];
33
34 if (empty($query_params) && ! empty($_GET['filter' . $this->_form_id])) {
35 $query_params = json_decode(base64_decode($_GET['filter' . $this->_form_id]), true);
36 }
37
38 $cache[$this->_form_id] = $query_params;
39 }
40
41 return $cache[$this->_form_id];
42 }
43
44 protected function wp_user_query()
45 {
46 static $cache = [];
47
48 if ( ! isset($cache[$this->_form_id])) {
49
50 $search_q_key = self::search_query_key();
51
52 $current_page = $this->get_current_page();
53
54 $users_per_page = $this->args['users_per_page'] ?: 9;
55
56 $roles = array_filter($this->args['user_roles'] ?? []);
57
58 $include_user_ids = $this->args['specific_users'] ?? '';
59
60 $exclude_user_ids = $this->args['exclude_users'] ?? '';
61
62 $default_sort_method = $this->args['sort_default'] ?? 'newest';
63
64 if (empty($include_user_ids)) {
65 $include_user_ids = [];
66 } else {
67 $include_user_ids = array_map(function ($val) {
68 return absint(trim($val));
69 }, explode(',', $include_user_ids));
70 }
71
72 if (empty($exclude_user_ids)) {
73 $exclude_user_ids = [];
74 } else {
75 $exclude_user_ids = array_map(function ($val) {
76 return absint(trim($val));
77 }, explode(',', $exclude_user_ids));
78 }
79
80 $search_field_harsh_map = [
81 'pp_email_address' => 'user_email',
82 'pp_website_url' => 'user_url',
83 'pp_display_name' => 'display_name'
84 ];
85
86 $db_search_fields = array_filter($this->args['search_fields'] ?? [], function ($item) {
87 return ! empty($item);
88 });
89
90 // get meta fields to be used by meta query of WP_User_Query
91 $meta_fields = array_filter($db_search_fields, function ($item) use ($search_field_harsh_map) {
92 return ! in_array($item, array_keys($search_field_harsh_map));
93 });
94
95 // get wp_user table columns to use in searching for users
96 $search_columns = array_reduce($db_search_fields, function ($carry, $item) use ($search_field_harsh_map) {
97
98 if (isset($search_field_harsh_map[$item])) {
99 $carry[] = $search_field_harsh_map[$item];
100 }
101
102 return $carry;
103
104 }, ['user_login']);
105
106 $sort_method = ppress_var($_GET, 'sortby' . $this->_form_id, $default_sort_method, true);
107
108 $query_params = $this->search_filter_query_params();
109
110 $offset = $current_page > 1 ? ($current_page - 1) * $users_per_page : 0;
111
112 $filter_meta_fields = isset($query_params['filters']) ? array_filter(
113 array_map('ppress_recursive_trim', ppress_var($query_params, 'filters', [], true))
114 ) : [];
115
116 if ( ! empty($filter_meta_fields['ppress_user_role'])) {
117 $roles = [sanitize_text_field($filter_meta_fields['ppress_user_role'])];
118 }
119
120 $wp_user_query = $this->member_directory_users([
121 'number' => $users_per_page,
122 'paged' => $current_page,
123 'offset' => $offset,
124 'roles' => $roles,
125 'include_user_ids' => $include_user_ids,
126 'exclude_user_ids' => $exclude_user_ids,
127 'sort_method' => $sort_method,
128 'search_columns' => $search_columns,
129 'search_meta_fields' => $meta_fields,
130 'filter_meta_fields' => $filter_meta_fields,
131 'is_search_query' => ! empty($query_params['ppmd-search']),
132 'search_q' => isset($query_params[$search_q_key]) ? sanitize_text_field($query_params[$search_q_key]) : ''
133 ]);
134
135 $users = $wp_user_query->get_results();
136
137 $total_users_found = $wp_user_query->get_total();
138
139 if (
140 apply_filters('ppress_member_directory_enable_user_role_array_filtering', false) &&
141 ! empty($roles) &&
142 ! empty($query_params['ppmd-search']) &&
143 is_array($users) &&
144 ! empty($users)
145 ) {
146
147 /**
148 * @var int $key
149 * @var WP_User $user
150 */
151 foreach ($users as $key => $user) {
152
153 if (empty(array_intersect($user->roles, $roles))) {
154 unset($users[$key]);
155 }
156 }
157
158 $total_users_found = count($users);
159
160 // only necessary because if filtering by role, LIMIT is removed from query.
161 // limit is removed in pre_user_query action callback.
162 $users = array_slice($users, $offset, $users_per_page);
163 }
164
165 $cache[$this->_form_id] = [
166 'users' => $users,
167 'total_users_found' => $total_users_found
168 ];
169 }
170
171 return $cache[$this->_form_id];
172 }
173
174 public function member_directory_users(array $parsed_args = []): WP_User_Query
175 {
176 $parsed_args = apply_filters('ppress_member_directory_parsed_args', wp_parse_args($parsed_args, [
177 'number' => 9,
178 'paged' => 1,
179 'offset' => 0,
180 'roles' => [],
181 'include_user_ids' => [],
182 'exclude_user_ids' => [],
183 'count_total' => true,
184 'sort_method' => 'newest',
185 'is_search_query' => false,
186 'search_q' => '',
187 'search_columns' => ['user_login', 'user_email', 'user_url', 'display_name'],
188 'search_meta_fields' => ['first_name', 'last_name'],
189 'filter_meta_fields' => []
190 ]));
191
192 $args = [
193 'number' => $parsed_args['number'],
194 'paged' => $parsed_args['paged'],
195 'offset' => $parsed_args['offset'],
196 'role__in' => $parsed_args['roles'],
197 'include' => $parsed_args['include_user_ids'],
198 'exclude' => $parsed_args['exclude_user_ids']
199 ];
200
201 // no check for username because it's the default orderby
202 switch ($parsed_args['sort_method']) {
203 case 'newest':
204 $args['orderby'] = 'user_registered';
205 $args['order'] = 'DESC';
206 break;
207 case 'oldest':
208 $args['orderby'] = 'user_registered';
209 break;
210 case 'username':
211 $args['orderby'] = 'user_login';
212 break;
213 case 'first-name':
214 $args['meta_key'] = 'first_name';
215 $args['orderby'] = 'meta_value';
216 $args['order'] = 'ASC';
217 break;
218 case 'last-name':
219 $args['meta_key'] = 'last_name';
220 $args['orderby'] = 'meta_value';
221 $args['order'] = 'ASC';
222 break;
223 default:
224 $args['meta_key'] = $parsed_args['sort_method'];
225 $args['orderby'] = 'meta_value';
226 $args['order'] = 'ASC';
227 }
228
229 if ($parsed_args['is_search_query'] === true) {
230
231 $search_term = sanitize_text_field($parsed_args['search_q']);
232
233 $search_columns = $parsed_args['search_columns'];
234
235 $roles = $parsed_args['roles'];
236
237 $filter_meta_fields = array_filter($parsed_args['filter_meta_fields'], function ($v, $k) {
238 return $k != 'ppress_user_role';
239 }, ARRAY_FILTER_USE_BOTH);
240
241 if ( ! empty($search_term)) {
242 $args['search'] = '*' . $search_term . '*';
243 }
244
245 // we need to empty out the search column so wp user query doesn't restrict the search only
246 // to supplied search columns. We want to also check usermeta too.
247 add_filter('user_search_columns', '__return_empty_array', 999999999);
248
249 add_action('pre_user_query', function ($query) use ($roles) {
250 // removes "AND ()" from query which causes the sql to be invalid.
251 // SELECT DISTINCT wp_users.* FROM wp_users INNER JOIN wp_usermeta ON
252 // ( wp_users.ID = wp_usermeta.user_id ) WHERE 1=1 AND ( wp_users.user_nicename LIKE '%little%' OR
253 // wp_users.user_email LIKE '%little%' OR ( ( wp_usermeta.meta_key = 'first_name' AND wp_usermeta.meta_value LIKE '%little%' )
254 // OR ( wp_usermeta.meta_key = 'last_name' AND wp_usermeta.meta_value LIKE '%little%' ) OR ( wp_usermeta.meta_key = 'twitter'
255 // AND wp_usermeta.meta_value LIKE '%little%' ) ) ) AND () ORDER BY user_registered DESC
256 $query->query_where = str_replace('AND ()', '', $query->query_where);
257
258 if ( apply_filters('ppress_member_directory_enable_user_role_array_filtering', false) && ! empty($roles)) {
259 // remove query LIMIT so we can get actual total number of result when filitering by roles
260 unset($query->query_limit);
261 }
262 });
263
264 /**
265 * Modifies the query so we can tactically include searching of $search_columns in wp_users table
266 * @see https://wordpress.stackexchange.com/a/248674/59917
267 */
268 add_filter('get_meta_sql', function ($sql) use ($search_term, $search_columns, $filter_meta_fields) {
269
270 global $wpdb;
271
272 // Only run once:
273 static $nr = 0;
274
275 if (0 != $nr++) return $sql;
276
277 $OR_placeholders = [];
278 $queries = [];
279
280
281 if (is_array($search_columns) && ! empty($search_columns)) {
282
283 foreach ($search_columns as $search_column) {
284
285 if ( ! empty($search_term)) {
286 $OR_placeholders[] = '%s';
287 $queries[] = $wpdb->prepare("{$wpdb->users}.$search_column LIKE %s", '%' . $wpdb->esc_like($search_term) . '%');
288 }
289 }
290 }
291
292 $OR_placeholders[] = '%s';
293
294 $queries[] = ppress_mb_function(
295 ['mb_substr', 'substr'],
296 [
297 $sql['where'],
298 5,
299 ppress_mb_function(['mb_strlen', 'strlen'], [$sql['where']])
300 ]
301 );
302
303 $filter_queries = '';
304
305 /** @see https://stackoverflow.com/a/65653006/2648410 */
306 if ( ! empty($filter_meta_fields)) {
307
308 foreach ($filter_meta_fields as $meta_key => $meta_value) {
309
310 $filter_queries .= "AND EXISTS ( SELECT 1 FROM {$wpdb->usermeta} WHERE {$wpdb->users}.ID = {$wpdb->usermeta}.user_id AND ";
311
312 $filter_queries .= '(';
313
314 if (is_array($meta_value)) {
315
316 $meta_value_count = count($meta_value);
317
318 foreach ($meta_value as $index2 => $value) {
319 $index2++;
320
321 $filter_queries .= $wpdb->prepare(
322 "({$wpdb->usermeta}.meta_key = %s AND {$wpdb->usermeta}.meta_value LIKE %s)",
323 $meta_key,
324 '%' . $wpdb->esc_like($value) . '%'
325 );
326
327 if ($index2 != $meta_value_count) {
328 $filter_queries .= ' OR ';
329 }
330 }
331
332 } else {
333
334 $filter_queries .= $wpdb->prepare(
335 "({$wpdb->usermeta}.meta_key = %s AND {$wpdb->usermeta}.meta_value = %s)",
336 $meta_key,
337 $meta_value
338 );
339 }
340
341 $filter_queries .= ')';
342
343 $filter_queries .= ')';
344 }
345 }
346
347 $queries[] = $filter_queries;
348
349 $where = vsprintf(
350 " AND ((" . implode(' OR ', $OR_placeholders) . " ) %s )",
351 $queries
352 );
353
354 $sql['where'] = $where;
355
356 return $sql;
357 });
358
359 if (is_array($parsed_args['search_meta_fields']) && ! empty($parsed_args['search_meta_fields']) && ! empty($search_term)) {
360
361 $args['meta_query'][0]['relation'] = 'OR';
362
363 foreach ($parsed_args['search_meta_fields'] as $search_meta_field) {
364
365 $args['meta_query'][0][] = [
366 'key' => $search_meta_field,
367 'value' => $search_term,
368 'compare' => 'LIKE'
369 ];
370 }
371 }
372 }
373
374 return new WP_User_Query(apply_filters('ppress_member_directory_wp_user_args', $args, $this->_form_id, $this));
375 }
376
377 protected function get_current_page(): int
378 {
379 return absint(max(1, ppressGET_var('mdpage' . $this->_form_id, 1, true)));
380 }
381
382 protected function display_pagination(
383 $total_users_found,
384 $users_per_page,
385 $prev_text = '<span class="ppress-material-icons">keyboard_arrow_left</span>',
386 $next_text = '<span class="ppress-material-icons">keyboard_arrow_right</span>'
387 )
388 {
389 $current_page = $this->get_current_page();
390
391 $total_pages = ceil($total_users_found / ($users_per_page ?: 9));
392
393 if ($total_pages > 1) {
394
395 echo '<div class="ppmd-pagination-wrap">';
396
397 // from https://wordpress.stackexchange.com/questions/275527/paginate-links-ignore-my-format
398 echo paginate_links([
399 //'base' => '%_%', somehow with this enabled, pagination breaks where page 1 link becomes the current page url
400 'total' => $total_pages,
401 'current' => $current_page,
402 'format' => '?mdpage' . $this->_form_id . '=%#%',
403 'prev_text' => $prev_text,
404 'next_text' => $next_text
405 ]);
406
407 echo '</div>';
408 }
409 }
410 }
411