PluginProbe ʕ •ᴥ•ʔ
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress / 3.2.7
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress v3.2.7
4.17.2 4.17.1 4.17.0 4.16.19 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 / AbstractMemberDirectoryTheme.php
wp-user-avatar / src / Themes / DragDrop Last commit date
EditProfile 5 years ago Login 5 years ago MemberDirectory 4 years ago PasswordReset 5 years ago Registration 5 years ago UserProfile 4 years ago AbstractBuildScratch.php 5 years ago AbstractMemberDirectoryTheme.php 4 years ago AbstractTheme.php 4 years ago FieldListing.php 4 years ago MemberDirectoryListing.php 5 years ago ProfileFieldListing.php 4 years ago ThemeInterface.php 5 years ago ThemesRepository.php 5 years ago index.php 5 years ago
AbstractMemberDirectoryTheme.php
980 lines
1 <?php
2
3 namespace ProfilePress\Core\Themes\DragDrop;
4
5 use ProfilePress\Core\Classes\ExtensionManager as EM;
6 use ProfilePress\Core\Classes\PROFILEPRESS_sql;
7 use ProfilePress\Core\ShortcodeParser\Builder\FieldsShortcodeCallback;
8 use WP_User_Query;
9
10 abstract class AbstractMemberDirectoryTheme extends AbstractTheme
11 {
12 public function __construct($form_id, $form_type)
13 {
14 parent::__construct($form_id, $form_type);
15
16 add_action('ppress_drag_drop_builder_admin_page', [$this, 'js_script']);
17 }
18
19 abstract function form_wrapper_class();
20
21 abstract function directory_structure();
22
23 public function form_structure()
24 {
25 $wp_user_query = $this->wp_user_query();
26
27 $total_users_found = $wp_user_query['total_users_found'];
28
29 $query_params = $this->search_filter_query_params();
30
31 ob_start();
32
33 printf('[pp-form-wrapper class="%s"]', $this->form_wrapper_class());
34
35 $this->search_filter_sort_structure();
36
37 if ( ! $this->is_result_after_search_enabled() || (isset($query_params['ppmd-search']) && $query_params['ppmd-search'] == $this->form_id)) {
38
39 if (0 === $total_users_found) { ?>
40
41 <div class="ppressmd-members-total-wrap">
42 <div class="ppressmd-members-total">
43 <?= $this->get_no_result_text() ?>
44 </div>
45 </div>
46
47 <?php
48
49 } else {
50
51 if ( ! empty($query_params[$this->search_query_key()])) { ?>
52
53 <div class="ppressmd-members-total-wrap">
54 <div class="ppressmd-members-total">
55
56 <?= str_replace(
57 '{total_users}', $total_users_found,
58 $total_users_found > 1 ? $this->get_results_text() : $this->get_single_result_text()
59 ) ?>
60 </div>
61 </div>
62
63 <?php
64 }
65 }
66
67 if ($total_users_found > 0) {
68
69 $this->directory_structure();
70
71 $this->display_pagination($total_users_found);
72 }
73 }
74
75 echo '[/pp-form-wrapper]';
76
77 return ob_get_clean();
78 }
79
80 public function js_script()
81 {
82 ?>
83 <script type="text/javascript">
84 (function ($) {
85
86 var run = function () {
87 $('#ppress_md_enable_custom_sort').change(function () {
88 $('.ppress_md_sort_method_fields_wrap').toggle(this.checked);
89 }).trigger('change');
90
91 $('#ppress_md_enable_search').change(function () {
92 $('.ppress_md_search_fields_wrap').toggle(this.checked);
93 $('.ppress_md_enable_filters_wrap').toggle(this.checked);
94 $('.ppress_md_filter_fields_wrap').toggle(this.checked);
95 }).trigger('change');
96 };
97
98 $(run);
99
100 })(jQuery);
101 </script>
102 <?php
103 }
104
105 public function default_metabox_settings()
106 {
107 $data = parent::default_metabox_settings();
108 $data['ppress_md_user_roles'] = [];
109 $data['ppress_md_specific_users'] = '';
110 $data['ppress_md_exclude_users'] = '';
111
112 $data['ppress_md_sort_default'] = 'newest';
113 $data['ppress_md_enable_custom_sort'] = 'false';
114 $data['ppress_md_sort_method_fields'] = [];
115
116 $data['ppress_md_enable_search'] = 'true';
117 $data['ppress_md_search_fields'] = ['pp_email_address', 'pp_website_url', 'pp_display_name', 'first_name', 'last_name'];
118 $data['ppress_md_enable_filters'] = 'false';
119 $data['ppress_md_filter_fields'] = [];
120
121 $data['ppress_md_enable_result_after_search'] = 'false';
122 $data['ppress_md_result_number_per_page'] = '9';
123 $data['ppress_md_results_text'] = sprintf(esc_html__('%s Members', 'wp-user-avatar'), '{total_users}');
124 $data['ppress_md_single_result_text'] = sprintf(esc_html__('%s Member', 'wp-user-avatar'), '{total_users}');
125 $data['ppress_md_no_result_text'] = esc_html__('We could not find any user that matches your search criteria', 'wp-user-avatar');
126
127 $data['ppress_md_search_filter_field_text_color'] = '#666666';
128 $data['ppress_md_search_filter_field_border_color'] = '#dddddd';
129
130 $data['ppress_md_pagination_link_color'] = '#666666';
131 $data['ppress_md_pagination_active_link_color'] = '#ffffff';
132 $data['ppress_md_pagination_active_background_color'] = '#007bff';
133
134 return $data;
135 }
136
137 public function appearance_settings($settings)
138 {
139 $settings[] = [
140 'id' => 'ppress_md_user_roles',
141 'type' => 'select2',
142 'label' => esc_html__('User Roles to Display', 'wp-user-avatar'),
143 'description' => esc_html__('If you do not want to show all members, select the user roles to appear in this directory.', 'wp-user-avatar'),
144 'options' => ppress_wp_roles_key_value(false),
145 'priority' => 5
146 ];
147
148 $settings[] = [
149 'id' => 'ppress_md_specific_users',
150 'type' => 'textarea',
151 'placeholder' => esc_html__('Example: 1, 6, 32', 'wp-user-avatar'),
152 'label' => esc_html__('Comma Separated List of Users ID to Only Show', 'wp-user-avatar'),
153 'priority' => 10
154 ];
155
156 $settings[] = [
157 'id' => 'ppress_md_exclude_users',
158 'type' => 'textarea',
159 'placeholder' => esc_html__('Example: 1, 6, 32', 'wp-user-avatar'),
160 'label' => esc_html__('Comma Separated List of Users ID to Exclude', 'wp-user-avatar'),
161 'priority' => 10
162 ];
163
164 return $settings;
165 }
166
167 public function color_settings($settings)
168 {
169 $settings2 = [
170 [
171 'id' => 'ppress_md_search_filter_field_text_color',
172 'type' => 'color',
173 'label' => esc_html__('Search & Filter Fields Text', 'wp-user-avatar')
174 ],
175 [
176 'id' => 'ppress_md_search_filter_field_border_color',
177 'type' => 'color',
178 'label' => esc_html__('Search & Filter Fields Border', 'wp-user-avatar')
179 ],
180 [
181 'id' => 'ppress_md_pagination_link_color',
182 'type' => 'color',
183 'label' => esc_html__('Pagination Links', 'wp-user-avatar')
184 ],
185 [
186 'id' => 'ppress_md_pagination_active_link_color',
187 'type' => 'color',
188 'label' => esc_html__('Pagination Active Link Color', 'wp-user-avatar')
189 ],
190 [
191 'id' => 'ppress_md_pagination_active_background_color',
192 'type' => 'color',
193 'label' => esc_html__('Pagination Active Link Background', 'wp-user-avatar')
194 ]
195 ];
196
197 return array_merge($settings, $settings2);
198 }
199
200 public function metabox_settings($settings, $form_type, $DragDropBuilderInstance)
201 {
202 $sorting_options = [esc_html__('Standard Fields', 'wp-user-avatar') => $this->md_standard_sort_fields()];
203
204 $search_options = [
205 esc_html__('Standard', 'wp-user-avatar') => [
206 'pp_email_address' => esc_html__('Email Address', 'wp-user-avatar'),
207 'pp_website_url' => esc_html__('Website', 'wp-user-avatar'),
208 'pp_display_name' => esc_html__('Display Name', 'wp-user-avatar'),
209 'first_name' => esc_html__('First Name', 'wp-user-avatar'),
210 'last_name' => esc_html__('Last Name', 'wp-user-avatar'),
211 'description' => esc_html__('Biography', 'wp-user-avatar')
212 ]
213 ];
214
215 if (EM::is_enabled(EM::CUSTOM_FIELDS)) {
216 $cf_label = esc_html__('Custom Fields', 'wp-user-avatar');
217 $sorting_options[$cf_label] = ppress_custom_fields_key_value_pair(true);
218 $search_options[$cf_label] = ppress_custom_fields_key_value_pair(true);
219 }
220
221 $new_settings['ppress_md_sorting'] = [
222 'tab_title' => esc_html__('Sorting', 'wp-user-avatar'),
223 [
224 'id' => 'ppress_md_sort_default',
225 'label' => esc_html__('Default Sorting method', 'wp-user-avatar'),
226 'type' => 'select',
227 'options' => $sorting_options
228 ],
229 [
230 'id' => 'ppress_md_enable_custom_sort',
231 'label' => esc_html__('Enable custom sorting', 'wp-user-avatar'),
232 'type' => 'checkbox',
233 ],
234 [
235 'id' => 'ppress_md_sort_method_fields',
236 'label' => esc_html__('Sorting Method Fields', 'wp-user-avatar'),
237 'type' => 'select2',
238 'options' => $sorting_options,
239 'description' => esc_html__('Fields to show in sorting dropdown menu', 'wp-user-avatar')
240 ],
241 ];
242
243 $new_settings['ppress_md_search'] = [
244 'tab_title' => esc_html__('Search', 'wp-user-avatar'),
245 [
246 'id' => 'ppress_md_enable_search',
247 'label' => esc_html__('Display Search Form', 'wp-user-avatar'),
248 'type' => 'checkbox'
249 ],
250 [
251 'id' => 'ppress_md_search_fields',
252 'label' => esc_html__('Search Fields', 'wp-user-avatar'),
253 'type' => 'select2',
254 'options' => $search_options,
255 'description' => esc_html__('Select fields to search in.', 'wp-user-avatar')
256 ]
257 ];
258
259
260 if (EM::is_enabled(EM::CUSTOM_FIELDS)) {
261
262 $new_settings['ppress_md_search'][] = [
263 'id' => 'ppress_md_enable_filters',
264 'label' => esc_html__('Enable Filters', 'wp-user-avatar'),
265 'type' => 'checkbox',
266 'description' => esc_html__('If enabled, users will be able to filter members in this directory', 'wp-user-avatar')
267 ];
268
269 $new_settings['ppress_md_search'][] = [
270 'id' => 'ppress_md_filter_fields',
271 'label' => esc_html__('Filter Fields', 'wp-user-avatar'),
272 'type' => 'select2',
273 'options' => array_reduce(PROFILEPRESS_sql::get_profile_custom_fields_by_types(['select', 'checkbox', 'radio', 'country', 'date']), function ($carry, $item) {
274 $carry[$item->field_key] = ppress_woocommerce_field_transform($item->field_key, $item->label_name);
275
276 return $carry;
277 }, []),
278 'description' => esc_html__('Select custom fields that members can be filtered by. Only Select, Checkbox, Radio, Country and Date/Time fields are supported.', 'wp-user-avatar')
279 ];
280 }
281
282 if ( ! EM::is_enabled(EM::CUSTOM_FIELDS)) {
283 $upgrade_url = 'https://profilepress.net/pricing/?utm_source=wp_dashboard&utm_medium=upgrade&utm_campaign=md_custom_field_upsell';
284 $new_settings['ppress_md_search'][] = [
285 'id' => 'ppress_md_search_filter_upsell',
286 'label' => '',
287 'type' => 'custom',
288 'content' => sprintf(
289 esc_html__('%sUpgrade to ProfilePress premium%s if you don\'t have the custom field addon so you can enable search and filtering by custom fields.', 'wp-user-avatar'),
290 '<a href="' . $upgrade_url . '" target="_blank">', '</a>'
291 ),
292 ];
293 }
294
295 $new_settings['ppress_md_result_pagination'] = [
296 'tab_title' => esc_html__('Result & Pagination', 'wp-user-avatar'),
297 [
298 'id' => 'ppress_md_enable_result_after_search',
299 'label' => esc_html__('Show Results Only After a Search', 'wp-user-avatar'),
300 'type' => 'checkbox',
301 'description' => esc_html__('Enable to only show members after a search is performed', 'wp-user-avatar')
302 ],
303 [
304 'id' => 'ppress_md_result_number_per_page',
305 'label' => esc_html__('Number of Members per Page', 'wp-user-avatar'),
306 'type' => 'number'
307 ],
308 [
309 'id' => 'ppress_md_results_text',
310 'label' => esc_html__('Results Text', 'wp-user-avatar'),
311 'type' => 'text'
312 ],
313 [
314 'id' => 'ppress_md_single_result_text',
315 'label' => esc_html__('Single Result Text', 'wp-user-avatar'),
316 'type' => 'text'
317 ],
318 [
319 'id' => 'ppress_md_no_result_text',
320 'label' => esc_html__('No Result Text', 'wp-user-avatar'),
321 'type' => 'text'
322 ],
323 ];
324
325 return $new_settings;
326 }
327
328 protected function search_query_key()
329 {
330 return 'search-' . $this->form_id;
331 }
332
333 protected function get_current_page()
334 {
335 return absint(max(1, ppressGET_var('mdpage' . $this->form_id, 1, true)));
336 }
337
338 protected function wp_user_query()
339 {
340 static $cache = [];
341
342 if ( ! isset($cache[$this->form_id])) {
343
344 $search_q_key = self::search_query_key();
345
346 $current_page = $this->get_current_page();
347
348 $users_per_page = $this->get_default_result_number_per_page();
349
350 $roles = array_filter($this->get_meta('ppress_md_user_roles'));
351
352 $include_user_ids = $this->get_meta('ppress_md_specific_users');
353
354 $exclude_user_ids = $this->get_meta('ppress_md_exclude_users');
355
356 $default_sort_method = $this->get_meta('ppress_md_sort_default');
357
358 if (empty($include_user_ids)) {
359 $include_user_ids = [];
360 } else {
361 $include_user_ids = array_map(function ($val) {
362 return absint(trim($val));
363 }, explode(',', $include_user_ids));
364 }
365
366 if (empty($exclude_user_ids)) {
367 $exclude_user_ids = [];
368 } else {
369 $exclude_user_ids = array_map(function ($val) {
370 return absint(trim($val));
371 }, explode(',', $exclude_user_ids));
372 }
373
374 $search_field_harsh_map = [
375 'pp_email_address' => 'user_email',
376 'pp_website_url' => 'user_url',
377 'pp_display_name' => 'display_name'
378 ];
379
380 $db_search_fields = array_filter($this->get_meta('ppress_md_search_fields'), function ($item) {
381 return ! empty($item);
382 });
383
384 // get meta fields to be used by meta query of WP_User_Query
385 $meta_fields = array_filter($db_search_fields, function ($item) use ($search_field_harsh_map) {
386 return ! in_array($item, array_keys($search_field_harsh_map));
387 });
388
389 // get wp_user table columns to use in searching for users
390 $search_columns = array_reduce($db_search_fields, function ($carry, $item) use ($search_field_harsh_map) {
391
392 if (isset($search_field_harsh_map[$item])) {
393 $carry[] = $search_field_harsh_map[$item];
394 }
395
396 return $carry;
397
398 }, ['user_login']);
399
400 $sort_method = ppress_var($_GET, 'sortby' . $this->form_id, $default_sort_method, true);
401
402 $query_params = $this->search_filter_query_params();
403
404 $offset = $current_page > 1 ? ($current_page - 1) * $users_per_page : 0;
405
406 $wp_user_query = $this->member_directory_users([
407 'number' => $users_per_page,
408 'paged' => $current_page,
409 'offset' => $offset,
410 'roles' => $roles,
411 'include_user_ids' => $include_user_ids,
412 'exclude_user_ids' => $exclude_user_ids,
413 'sort_method' => $sort_method,
414 'search_columns' => $search_columns,
415 'search_meta_fields' => $meta_fields,
416 'filter_meta_fields' => isset($query_params['filters']) ? array_filter(
417 array_map('ppress_recursive_trim', ppress_var($query_params, 'filters', [], true))
418 ) : [],
419 'is_search_query' => ! empty($query_params['ppmd-search']),
420 'search_q' => isset($query_params[$search_q_key]) ? sanitize_text_field($query_params[$search_q_key]) : ''
421 ]);
422
423 $users = (array)$wp_user_query->get_results();
424
425 $total_users_found = $wp_user_query->get_total();
426
427 $cache[$this->form_id] = [
428 'users' => $users,
429 'total_users_found' => $total_users_found
430 ];
431 }
432
433 return $cache[$this->form_id];
434 }
435
436 protected function search_filter_query_params()
437 {
438
439 static $cache = [];
440
441 if ( ! isset($cache[$this->form_id])) {
442
443 $query_params = [];
444
445 if (empty($query_params) && ! empty($_GET['filter' . $this->form_id])) {
446 $query_params = json_decode(base64_decode($_GET['filter' . $this->form_id]), true);
447 }
448
449 $cache[$this->form_id] = $query_params;
450 }
451
452 return $cache[$this->form_id];
453 }
454
455 public function md_standard_sort_fields()
456 {
457 return [
458 'newest' => esc_html__('Newest Users First', 'wp-user-avatar'),
459 'oldest' => esc_html__('Oldest Users First', 'wp-user-avatar'),
460 'display-name' => esc_html__('Display Name', 'wp-user-avatar'),
461 'first-name' => esc_html__('First Name', 'wp-user-avatar'),
462 'last-name' => esc_html__('Last Name', 'wp-user-avatar'),
463 'username' => esc_html__('Username', 'wp-user-avatar')
464 ];
465 }
466
467 public function get_sort_field_label($field)
468 {
469 $pp_custom_fields = ppress_custom_fields_key_value_pair(true);
470
471 return ppress_var($this->md_standard_sort_fields(), $field, ppress_var($pp_custom_fields, $field));
472 }
473
474 /**
475 * @param array $parsed_args
476 *
477 * @return WP_User_Query
478 */
479 public function member_directory_users($parsed_args = [])
480 {
481 $parsed_args = apply_filters('ppress_member_directory_parsed_args', wp_parse_args($parsed_args, [
482 'number' => 9,
483 'paged' => 1,
484 'offset' => 0,
485 'roles' => [],
486 'include_user_ids' => [],
487 'exclude_user_ids' => [],
488 'count_total' => true,
489 'sort_method' => 'newest',
490 'is_search_query' => false,
491 'search_q' => '',
492 'search_columns' => ['user_login', 'user_email', 'user_url', 'display_name'],
493 'search_meta_fields' => ['first_name', 'last_name'],
494 'filter_meta_fields' => []
495 ]));
496
497 $args = [
498 'number' => $parsed_args['number'],
499 'paged' => $parsed_args['paged'],
500 'offset' => $parsed_args['offset'],
501 'role__in' => $parsed_args['roles'],
502 'include' => $parsed_args['include_user_ids'],
503 'exclude' => $parsed_args['exclude_user_ids']
504 ];
505
506 // no check for username because it's the default orderby
507 switch ($parsed_args['sort_method']) {
508 case 'newest':
509 $args['orderby'] = 'user_registered';
510 $args['order'] = 'DESC';
511 break;
512 case 'oldest':
513 $args['orderby'] = 'user_registered';
514 break;
515 case 'username':
516 $args['orderby'] = 'user_login';
517 break;
518 case 'display-name':
519 $args['meta_key'] = 'display_name';
520 $args['orderby'] = 'meta_value';
521 $args['order'] = 'ASC';
522 break;
523 case 'first-name':
524 $args['meta_key'] = 'first_name';
525 $args['orderby'] = 'meta_value';
526 $args['order'] = 'ASC';
527 break;
528 case 'last-name':
529 $args['meta_key'] = 'last_name';
530 $args['orderby'] = 'meta_value';
531 $args['order'] = 'ASC';
532 break;
533 default:
534 $args['meta_key'] = $parsed_args['sort_method'];
535 $args['orderby'] = 'meta_value';
536 $args['order'] = 'ASC';
537 }
538
539 if ($parsed_args['is_search_query'] === true) {
540
541 $search_term = sanitize_text_field($parsed_args['search_q']);
542
543 $search_columns = $parsed_args['search_columns'];
544
545 $filter_meta_fields = $parsed_args['filter_meta_fields'];
546
547 $args['search'] = '*' . $search_term . '*';
548
549 // we need to empty out the search column so wp user query doesn't restrict the search only
550 // to supplied search columns. We want to also check usermeta too.
551 add_filter('user_search_columns', '__return_empty_array', 999999999);
552
553 add_action('pre_user_query', function ($query) {
554 // removes "AND ()" from query which causes the sql to be invalid.
555 // SELECT DISTINCT wp_users.* FROM wp_users INNER JOIN wp_usermeta ON
556 // ( wp_users.ID = wp_usermeta.user_id ) WHERE 1=1 AND ( wp_users.user_nicename LIKE '%little%' OR
557 // wp_users.user_email LIKE '%little%' OR ( ( wp_usermeta.meta_key = 'first_name' AND wp_usermeta.meta_value LIKE '%little%' )
558 // OR ( wp_usermeta.meta_key = 'last_name' AND wp_usermeta.meta_value LIKE '%little%' ) OR ( wp_usermeta.meta_key = 'twitter'
559 // AND wp_usermeta.meta_value LIKE '%little%' ) ) ) AND () ORDER BY user_registered DESC
560 $query->query_where = str_replace('AND ()', '', $query->query_where);
561 });
562
563 /**
564 * Modifies the query so we can tactically include searching of $search_columns in wp_users table
565 * @see https://wordpress.stackexchange.com/a/248674/59917
566 */
567 add_filter('get_meta_sql', function ($sql) use ($search_term, $search_columns, $filter_meta_fields) {
568
569 global $wpdb;
570
571 // Only run once:
572 static $nr = 0;
573
574 if (0 != $nr++) return $sql;
575
576 $OR_placeholders = [];
577 $queries = [];
578
579
580 if (is_array($search_columns) && ! empty($search_columns)) {
581
582 foreach ($search_columns as $search_column) {
583
584 $OR_placeholders[] = '%s';
585
586 $queries[] = $wpdb->prepare("{$wpdb->users}.$search_column LIKE %s", '%' . $wpdb->esc_like($search_term) . '%');
587 }
588 }
589
590 $OR_placeholders[] = '%s';
591
592 $queries[] = ppress_mb_function(
593 ['mb_substr', 'substr'],
594 [
595 $sql['where'],
596 5,
597 ppress_mb_function(['mb_strlen', 'strlen'], [$sql['where']])
598 ]
599 );
600
601
602 $filter_queries = '';
603
604 /** @see https://stackoverflow.com/a/65653006/2648410 */
605 if ( ! empty($filter_meta_fields)) {
606
607 foreach ($filter_meta_fields as $meta_key => $meta_value) {
608
609 $filter_queries .= "AND EXISTS ( SELECT 1 FROM {$wpdb->usermeta} WHERE {$wpdb->users}.ID = {$wpdb->usermeta}.user_id AND ";
610
611 $filter_queries .= '(';
612
613 if (is_array($meta_value)) {
614
615 $meta_value_count = count($meta_value);
616
617 foreach ($meta_value as $index2 => $value) {
618 $index2++;
619
620 $filter_queries .= $wpdb->prepare(
621 "({$wpdb->usermeta}.meta_key = %s AND {$wpdb->usermeta}.meta_value LIKE %s)",
622 $meta_key,
623 '%' . $wpdb->esc_like($value) . '%'
624 );
625
626 if ($index2 != $meta_value_count) {
627 $filter_queries .= ' OR ';
628 }
629 }
630
631 } else {
632
633 $filter_queries .= $wpdb->prepare(
634 "({$wpdb->usermeta}.meta_key = %s AND {$wpdb->usermeta}.meta_value = %s)",
635 $meta_key,
636 $meta_value
637 );
638 }
639
640 $filter_queries .= ')';
641
642 $filter_queries .= ')';
643 }
644 }
645
646 $queries[] = $filter_queries;
647
648 $where = vsprintf(
649 " AND ((" . implode(' OR ', $OR_placeholders) . " ) %s )",
650 $queries
651 );
652
653 $sql['where'] = $where;
654
655 return $sql;
656 });
657
658 if (is_array($parsed_args['search_meta_fields']) && ! empty($parsed_args['search_meta_fields'])) {
659
660 $args['meta_query'][0]['relation'] = 'OR';
661
662 foreach ($parsed_args['search_meta_fields'] as $search_meta_field) {
663
664 $args['meta_query'][0][] = [
665 'key' => $search_meta_field,
666 'value' => $search_term,
667 'compare' => 'LIKE'
668 ];
669 }
670 }
671 }
672
673 return new WP_User_Query(apply_filters('ppress_member_directory_wp_user_args', $args, $this->form_id, $this));
674 }
675
676 protected function sort_method_dropdown_menu()
677 {
678 $sortby_query_key = 'sortby' . $this->form_id;
679
680 $custom_sort_enabled = $this->get_meta('ppress_md_enable_custom_sort') == 'true';
681
682 $default_sort_field = ppress_var($_GET, $sortby_query_key, $this->get_meta('ppress_md_sort_default'), true);
683
684 $custom_sort_fields = array_filter($this->get_meta('ppress_md_sort_method_fields'), function ($item) use ($default_sort_field) {
685 return ! empty($item) && $item != $default_sort_field;
686 });
687
688 if ( ! $custom_sort_enabled || empty($custom_sort_fields)) return;
689
690 ?>
691 <div class="ppressmd-member-directory-sorting">
692 <span><?= esc_html__('Sort by', 'wp-user-avatar') ?>:&nbsp;</span>
693 <div class="ppressmd-member-directory-sorting-a">
694 <a href=" <?= esc_url(add_query_arg([$sortby_query_key => $default_sort_field])) ?>" class="ppressmd-member-directory-sorting-a-text">
695 <?= $this->get_sort_field_label($default_sort_field) ?>
696 <span class="ppress-material-icons">keyboard_arrow_down</span>
697 </a>
698
699 <div class="ppressmd-new-dropdown">
700 <ul>
701 <?php foreach ($custom_sort_fields as $field) : ?>
702 <li>
703 <a href="<?= esc_url(add_query_arg([$sortby_query_key => $field])) ?>">
704 <?= $this->get_sort_field_label($field) ?>
705 </a>
706 </li>
707 <?php endforeach; ?>
708 </ul>
709 </div>
710 </div>
711 </div>
712 <?php
713 }
714
715 protected function filter_structure($show_filter_fields = false)
716 {
717 $filter_enabled = $this->get_meta('ppress_md_enable_filters') == 'true';
718
719 $filter_fields = array_filter($this->get_meta('ppress_md_filter_fields'), function ($item) {
720 return ! empty($item);
721 });
722
723 if ( ! $filter_enabled || empty($filter_fields)) return;
724
725 if ( ! $show_filter_fields) : ?>
726 <span class="ppressmd-member-directory-filters">
727 <span class="ppressmd-member-directory-filters-a">
728 <a href="#">
729 <?= esc_html__('More Filters', 'wp-user-avatar') ?>
730 <span class="ppress-material-icons ppress-up">keyboard_arrow_up</span>
731 <span class="ppress-material-icons ppress-down">keyboard_arrow_down</span>
732 </a>
733 </span>
734 </span>
735 <?php endif;
736
737 if ($show_filter_fields) : $query_params = $this->search_filter_query_params(); ?>
738
739 <div class="ppressmd-member-directory-header-row ppressmd-member-directory-filters-bar">
740
741 <div class="ppressmd-search ppressmd-search-invisible">
742
743 <?php foreach ($filter_fields as $field_key) : ?>
744
745 <?php $custom_field = PROFILEPRESS_sql::get_profile_custom_field_by_key($field_key); ?>
746
747 <div class="ppressmd-search-filter ppressmd-text-filter-type">
748
749 <?php
750
751 switch ($custom_field['type']) {
752 case 'select' :
753 case 'checkbox' :
754 case 'radio' :
755 case 'country' :
756
757 if ( ! empty($custom_field['options'])) {
758
759 $is_multiple = false;
760
761 if ($custom_field['type'] == 'select') {
762 $is_multiple = ppress_is_select_field_multi_selectable($field_key);
763
764 }
765
766 if ($custom_field['type'] == 'checkbox') $is_multiple = true;
767
768 printf(
769 '<select name="%s" data-placeholder="%s" class="ppressmd-form-field ppmd-select2"%s>',
770 $is_multiple ? 'filters[' . $field_key . '][]' : 'filters[' . $field_key . ']',
771 $custom_field['label_name'],
772 $is_multiple ? ' multiple' : ' data-allow-clear="true"'
773 );
774
775 $options = array_map('trim', explode(',', $custom_field['options']));
776
777 if ( ! $is_multiple) {
778 echo '<option></option>';
779 }
780
781 foreach ($options as $option) {
782 $bucket = ppress_var(ppress_var($query_params, 'filters', []), $field_key);
783 printf(
784 '<option value="%1$s" %2$s>%1$s</option>',
785 $option,
786 ! $is_multiple ? selected($option, $bucket, false) : (is_array($bucket) && in_array($option, $bucket) ? 'selected=selected' : '')
787 );
788 }
789
790 echo '</select>';
791 }
792 break;
793
794 case 'date' :
795
796 $dateFormat = ! empty($custom_field['options']) ? $custom_field['options'] : 'Y-m-d';
797
798 $config = FieldsShortcodeCallback::date_picker_config($field_key, $dateFormat);
799
800 printf(
801 '<input type="text" name="%1$s" placeholder="%2$s" value="%4$s" class="ppressmd-form-field ppmd-date" data-config="%3$s">',
802 'filters[' . $custom_field['field_key'] . ']',
803 $custom_field['label_name'],
804 esc_attr(json_encode($config)),
805 ppress_var(ppress_var($query_params, 'filters', []), $field_key)
806 );
807 break;
808 }
809 ?>
810
811 </div>
812
813 <?php endforeach; ?>
814
815 </div>
816
817 </div>
818 <?php endif;
819 }
820
821 protected function search_form()
822 {
823 if ($this->get_meta('ppress_md_enable_search') != 'true') return;
824
825 $search_string = esc_html__('Search', 'wp-user-avatar');
826
827 $entered_search_term = ppress_var($this->search_filter_query_params(), 'search-' . $this->form_id, '');
828
829 ?>
830 <div class="ppressmd-member-directory-header-row ppressmd-member-directory-search-row">
831 <div class="ppressmd-member-directory-search-line">
832 <label>
833 <input name="search-<?= $this->form_id ?>" type="search" class="ppressmd-search-line" placeholder="<?= $search_string ?>" value="<?= $entered_search_term ?>">
834 </label>
835 <input type="submit" class="ppressmd-do-search ppressmd-button" value="<?= $search_string ?>">
836 </div>
837 </div>
838 <?php
839 }
840
841 protected function display_pagination($total_users_found)
842 {
843 $current_page = $this->get_current_page();
844
845 $users_per_page = $this->get_default_result_number_per_page();
846
847 $total_pages = ceil($total_users_found / $users_per_page);
848
849 if ($total_pages > 1) {
850
851 echo '<div class="ppmd-pagination-wrap">';
852
853 // from https://wordpress.stackexchange.com/questions/275527/paginate-links-ignore-my-format
854 echo paginate_links([
855 //'base' => '%_%', somehow with this enabled, pagination breaks where page 1 link becomes the current page url
856 'total' => $total_pages,
857 'current' => $current_page,
858 'format' => '?mdpage' . $this->form_id . '=%#%',
859 'prev_text' => '<span class="ppress-material-icons">keyboard_arrow_left</span>',
860 'next_text' => '<span class="ppress-material-icons">keyboard_arrow_right</span>',
861 ]);
862
863 echo '</div>';
864 }
865 }
866
867 protected function search_filter_sort_structure()
868 {
869 $is_filters_expanded = false;
870
871 $query_params = $this->search_filter_query_params();
872
873 if (isset($query_params['filters']) && ! empty(array_filter($query_params['filters']))) {
874 $is_filters_expanded = true;
875 }
876 ?>
877
878 <div class="ppressmd-member-directory-header ppressmd-form<?= $is_filters_expanded ? ' ppmd-filters-expand' : ''; ?>">
879
880 <form action="<?= ppress_get_current_url_query_string() ?>" method="get">
881
882 <?php $this->search_form(); ?>
883
884 <div class="ppressmd-member-directory-header-row">
885 <div class="ppressmd-member-directory-nav-line">
886
887 <?php $this->sort_method_dropdown_menu(); ?>
888
889 <?php $this->filter_structure(); ?>
890
891 </div>
892 </div>
893
894 <?php $this->filter_structure(true) ?>
895
896 <input type="hidden" name="ppmd-search" value="<?= $this->form_id ?>">
897
898 </form>
899
900 </div>
901 <?php
902 }
903
904 protected function is_result_after_search_enabled()
905 {
906 return $this->get_meta('ppress_md_enable_result_after_search') == 'true';
907 }
908
909 protected function get_results_text()
910 {
911 return esc_html($this->get_meta('ppress_md_results_text'));
912 }
913
914 protected function get_single_result_text()
915 {
916 return esc_html($this->get_meta('ppress_md_single_result_text'));
917 }
918
919 protected function get_no_result_text()
920 {
921 return esc_html($this->get_meta('ppress_md_no_result_text'));
922 }
923
924 protected function get_default_result_number_per_page()
925 {
926 static $cache = [];
927
928 if ( ! isset($cache[$this->form_id])) {
929 $cache[$this->form_id] = absint($this->get_meta('ppress_md_result_number_per_page'));
930 }
931
932 return $cache[$this->form_id];
933 }
934
935 /**
936 * @return MemberDirectoryListing
937 */
938 protected function directory_listing($user_id = false)
939 {
940 return (new MemberDirectoryListing($this->form_id, $user_id))->defaults($this->default_fields_settings());
941 }
942
943 public function form_css()
944 {
945 $form_id = $this->form_id;
946 $form_type = $this->form_type;
947
948 $search_filter_field_text_color = $this->get_meta('ppress_md_search_filter_field_text_color');
949 $search_filter_field_border_color = $this->get_meta('ppress_md_search_filter_field_border_color');
950
951 $pagination_link_color = $this->get_meta('ppress_md_pagination_link_color');
952 $pagination_active_link_color = $this->get_meta('ppress_md_pagination_active_link_color');
953 $pagination_active_bg_color = $this->get_meta('ppress_md_pagination_active_background_color');
954
955 return <<<CSS
956 #pp-$form_type-$form_id.pp-member-directory .ppressmd-member-directory-header .ppressmd-member-directory-header-row .ppressmd-member-directory-search-line label .ppressmd-search-line,
957 #pp-$form_type-$form_id.pp-member-directory .ppressmd-member-directory-header .ppressmd-member-directory-header-row .ppressmd-search .ppressmd-search-filter.ppressmd-text-filter-type input:not(.select2-search__field),
958 #pp-$form_type-$form_id.pp-member-directory .ppressmd-member-directory-header .select2.select2-container .select2-selection {
959 border: 1px solid $search_filter_field_border_color !important;
960 }
961
962 #pp-$form_type-$form_id.pp-member-directory .ppressmd-member-directory-header .ppressmd-member-directory-header-row .ppressmd-search .ppressmd-search-filter.ppressmd-text-filter-type input,
963 #pp-$form_type-$form_id.pp-member-directory .ppressmd-member-directory-header .ppressmd-member-directory-header-row .ppressmd-member-directory-search-line label .ppressmd-search-line,
964 #pp-$form_type-$form_id.pp-member-directory .ppressmd-member-directory-header .ppressmd-member-directory-header-row .ppressmd-member-directory-nav-line .ppress-material-icons,
965 #pp-$form_type-$form_id.pp-member-directory .ppressmd-member-directory-header .select2.select2-container .select2-selection__rendered {
966 color: $search_filter_field_text_color !important;
967 }
968
969 #pp-$form_type-$form_id.pp-member-directory .ppmd-pagination-wrap .page-numbers {
970 color: $pagination_link_color !important;
971 }
972
973 #pp-$form_type-$form_id.pp-member-directory .ppmd-pagination-wrap .page-numbers.current {
974 background: $pagination_active_bg_color !important;
975 color: $pagination_active_link_color !important;
976 }
977 CSS;
978
979 }
980 }