PluginProbe
wpForo Forum / 2.3.0
wpForo Forum v2.3.0
3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 1.4.2 All 137 releases
wpforo / classes / Members.php

Members.php in wpForo Forum 2.3.0, at classes/Members.php

3,773 lines 129.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace wpforo\classes;
4
5 use stdClass;
6 use WP_Error;
7 use wpforo\admin\listtables\Members as MembersListTable;
8 use wpforo\modules\reactions\Reactions;
9
10 // Exit if accessed directly
11 if( ! defined( 'ABSPATH' ) ) exit;
12
13
14 class Members {
15 private $default;
16 private $fields;
17 private $countries;
18 private $timezones;
19 public $login_min_length;
20 public $login_max_length;
21 public $pass_min_length;
22 public $pass_max_length;
23 public $list_table;
24 private $touched_userids = [];
25
26 function __construct() {
27 $this->init_defaults();
28 $this->init_hooks();
29 }
30
31 private function init_defaults() {
32 $this->login_min_length = 3;
33 $this->login_max_length = 30;
34 $this->pass_min_length = 6;
35 $this->pass_max_length = 20;
36 $this->default = new stdClass();
37 $this->default->member = [
38 'user_login' => '',
39 'user_nicename' => '',
40 'user_email' => '',
41 'user_url' => '',
42 'user_registered' => '0000-00-00 00:00:00',
43 'user_activation_key' => '',
44 'display_name' => '',
45
46 'first_name' => '',
47 'last_name' => '',
48
49 'userid' => 0,
50 'title' => '',
51 'groupid' => 0,
52 'secondary_groupids' => [],
53 'groupids' => [],
54 'avatar' => '',
55 'cover' => '',
56
57 'posts' => 0,
58 'topics' => 0,
59 'questions' => 0,
60 'answers' => 0,
61 'comments' => 0,
62 'reactions_in' => [],
63 'reactions_out' => [],
64 'points' => 0,
65 'custom_points' => 0,
66
67 'online_time' => 0,
68 'timezone' => '',
69 'location' => '',
70 'signature' => '',
71 'occupation' => '',
72 'about' => '',
73 'status' => 'inactive',
74 'is_email_confirmed' => 0,
75 'is_mention_muted' => 0,
76
77 'fields' => [],
78
79 'group_name' => '',
80 'group_color' => '',
81
82 'profile_url' => '',
83 'dname' => '',
84 'rating' => [
85 'level' => 0,
86 'percent' => 0,
87 'color' => $this->rating( 0, 'color' ),
88 'title' => $this->rating( 0, 'title' ),
89 'badge' => $this->rating( 0, 'icon' ),
90 ],
91 ];
92 $this->default->action = [
93 'label' => 'Action Button',
94 'ico' => '<i class="fas fa-user"></i>',
95 'callback_for_can' => '',
96 'callback_for_get_url' => '',
97 'data' => [],
98 'confirm_msg' => '',
99 ];
100 }
101
102 private function init_hooks() {
103 if( is_admin() ) add_action( 'wpforo_after_init', [ $this, 'init_list_table' ] );
104 add_action( 'delete_user_form', [ $this, 'show_delete_form' ], 10, 2 );
105 add_action( 'register_new_user', [ $this, 'after_register_new_user' ] );
106 add_action( 'after_password_reset', [ $this, 'after_password_reset' ] );
107 add_action( 'wp_login', [ $this, 'wp_login' ], 10, 2 );
108 add_action( 'set_current_user', [ $this, 'init_current_user' ] );
109 add_action( 'clean_user_cache', function( $userid ){ $this->reset( $userid ); } );
110 add_action( 'init', function() { if( ! WPF()->current_userid ) $this->init_current_user(); } );
111 add_action( 'set_logged_in_cookie', function( $logged_in_cookie ) {
112 $cookie = explode( '|', $logged_in_cookie );
113 WPF()->session_token = (string) wpfval( $cookie, 2 );
114 } );
115
116 add_action( 'wpforo_after_add_topic', [$this, 'after_add_topic'] );
117 add_action( 'wpforo_after_delete_topic', [$this, 'after_delete_topic'] );
118 add_action( 'wpforo_topic_status_update', [$this, 'after_topic_status_update'] );
119 add_action( 'wpforo_before_merge_topic', [$this, 'before_merge_topic'], 10, 3 );
120 add_action( 'wpforo_after_merge_topic', [$this, 'after_merge_topic'] );
121 add_action( 'wpforo_after_move_topic', [$this, 'after_move_topic'] );
122
123 add_action( 'wpforo_after_add_post', [$this, 'after_add_post'] );
124 add_action( 'wpforo_after_delete_post', [$this, 'after_delete_post'] );
125 add_action( 'wpforo_post_status_update', [$this, 'after_post_status_update'] );
126
127 add_action( 'wpforo_after_add_reaction', [$this, 'after_add_reaction'] );
128 add_action( 'wpforo_after_edit_reaction', [$this, 'after_edit_reaction'], 10, 2 );
129 add_action( 'wpforo_before_delete_reaction', [$this, 'before_delete_reaction'], 10, 2 );
130 add_action( 'wpforo_after_delete_reaction', [$this, 'after_delete_reaction'] );
131
132 add_action( 'wpforo_after_delete_user', [$this, 'after_delete_user'], 11, 2 );
133
134 add_action( 'wpforo_after_activate_user', [$this, 'after_activate_user'] );
135 }
136
137 public function init_list_table() {
138 if( wpfval( $_GET, 'page' ) === wpforo_prefix_slug( 'members' ) ) {
139 $this->list_table = new MembersListTable();
140 $this->list_table->prepare_items();
141 }
142 }
143
144 /**
145 * @param array $member
146 *
147 * @return array
148 */
149 public function decode( $member ) {
150 $reaction_types = array_map( '__return_zero', array_flip( Reactions::get_type_list() ) );
151 $member = array_merge( $this->default->member, (array) $member );
152 $member['userid'] = wpforo_bigintval( $member['userid'] );
153 $member['first_name'] = trim( strip_tags( (string) $member['first_name'] ) );
154 $member['last_name'] = trim( strip_tags( (string) $member['last_name'] ) );
155 $member['groupid'] = intval( $member['groupid'] );
156 $member['secondary_groupids'] = array_map( 'intval', (array) ( is_scalar( $member['secondary_groupids'] ) ? explode( ',', $member['secondary_groupids'] ) : $member['secondary_groupids'] ) );
157 $member['secondary_groupids'] = array_diff( $member['secondary_groupids'], (array) $member['groupid'] );
158 $member['groupids'] = array_unique( array_filter( array_merge( (array) $member['groupid'], $member['secondary_groupids'] ) ) );
159 $member['avatar'] = preg_replace( '#^https?://#iu', '//', esc_url( (string) $member['avatar'] ) );
160 $member['cover'] = preg_replace( '#^https?://#iu', '//', esc_url( (string) $member['cover'] ) );
161 $member['topics'] = intval( $member['topics'] );
162 $member['posts'] = intval( $member['posts'] );
163 $member['questions'] = intval( $member['questions'] );
164 $member['answers'] = intval( $member['answers'] );
165 $member['comments'] = intval( $member['comments'] );
166
167 $member['reactions_in'] = array_map( 'intval', (array) ( wpforo_is_json( $member['reactions_in'] ) ? json_decode( $member['reactions_in'], true ) : $member['reactions_in'] ) );
168 $member['reactions_in']['__ALL__'] = 0;
169 foreach( $member['reactions_in'] as $r ) $member['reactions_in']['__ALL__'] += $r;
170 $member['reactions_in'] = array_merge( $reaction_types, $member['reactions_in'] );
171
172 $member['reactions_out'] = array_map( 'intval', (array) ( wpforo_is_json( $member['reactions_out'] ) ? json_decode( $member['reactions_out'], true ) : $member['reactions_out'] ) );
173 $member['reactions_out']['__ALL__'] = 0;
174 foreach( $member['reactions_out'] as $r ) $member['reactions_out']['__ALL__'] += $r;
175 $member['reactions_out'] = array_merge( $reaction_types, $member['reactions_out'] );
176
177 $member['custom_points'] = floatval( $member['custom_points'] );
178 $member['points'] = $member['custom_points'] ?: $this->calc_points( $member );
179 $member['rating'] = $this->calc_rating( $member['points'] );
180
181 $member['online_time'] = (int) ( $member['online_time'] && !is_numeric( $member['online_time'] ) ? strtotime( (string) $member['online_time'] . ' GMT' ) : $member['online_time'] );
182 $member['is_email_confirmed'] = (bool) (int) $member['is_email_confirmed'];
183 $member['is_mention_muted'] = (bool) (int) $member['is_mention_muted'];
184
185 $member['title'] = trim( strip_tags( (string) $member['title'] ) );
186 $member['profile_url'] = $this->get_profile_url( $member );
187 $member['dname'] = wpforo_user_dname( $member );
188
189 $member['fields'] = (array) ( wpforo_is_json( $member['fields'] ) ? json_decode( $member['fields'], true ) : $member['fields'] );
190 $member = wpforo_array_ordered_intersect_key( $member, $this->default->member );
191
192 if( ! $member['userid'] ) $member['timezone'] = '';
193
194 return array_merge( $member['fields'], $member );
195 }
196
197 /** @TODO use this function for member all insert|update queries
198 * @param $member
199 *
200 * @return array
201 */
202 private function encode( $member ) {
203 $member = $this->decode( $member );
204 $member['secondary_groupids'] = implode( ',', $member['secondary_groupids'] );
205 $member['groupids'] = implode( ',', $member['groupids'] );
206 unset( $member['reactions_in']['__ALL__'], $member['reactions_out']['__ALL__'] );
207 $member['reactions_in'] = json_encode( $member['reactions_in'] );
208 $member['reactions_out'] = json_encode( $member['reactions_out'] );
209 $member['is_email_confirmed'] = intval( $member['is_email_confirmed'] );
210 $member['is_mention_muted'] = intval( $member['is_mention_muted'] );
211 $member['fields'] = json_encode( $member['fields'] );
212
213 return $member;
214 }
215
216 private function fix_action( $action ){
217 return array_merge( $this->default->action, $action );
218 }
219
220 private function _get_actions( $user ) {
221 $userid = wpforo_bigintval( $user['userid'] );
222 $actions = [
223 'edit' => [
224 'label' => wpforo_phrase( 'Edit Account Information', false ),
225 'ico' => '<i class="fas fa-user-gear"></i>',
226 'callback_for_can' => function(){
227 return WPF()->perm->user_can_edit_account();
228 },
229 'callback_for_get_url' => function() use ( $user ){
230 return WPF()->member->get_profile_url( $user, 'account' );
231 }
232 ],
233 'edit_dash' => [
234 'label' => wpforo_phrase( 'Edit User in Dashboard', false ),
235 'ico' => '<i class="fas fa-user-pen"></i>',
236 'callback_for_can' => function(){
237 return current_user_can( 'administrator' );
238 },
239 'callback_for_get_url' => function() use ( $userid ) {
240 return admin_url( "user-edit.php?user_id=" . $userid );
241 }
242 ],
243 'ban' => [
244 'label' => ( $user['status'] === 'banned' ? wpforo_phrase( 'Unban User', false ) : wpforo_phrase( 'Ban User', false ) ),
245 'ico' => '<i class="fas fa-user-lock"></i>',
246 'callback_for_can' => function() use ( $userid ){
247 return $userid !== WPF()->current_userid && (WPF()->usergroup->can('bm') || wpforo_current_user_is( 'admin' ));
248 },
249 'callback_for_get_url' => function() use ( $userid ){
250 return '';
251 },
252 'data' => [
253 'currentstate' => (int) ($user['status'] === 'banned'),
254 'active_label' => wpforo_phrase( 'Unban User', false ),
255 'inactive_label' => wpforo_phrase( 'Ban User', false ),
256 ],
257 'confirm_msg' => wpforo_phrase( 'Please confirm you want to do this action?', false ),
258 ],
259 'delete' => [
260 'label' => wpforo_phrase( 'Delete Account', false ),
261 'ico' => '<i class="fas fa-user-xmark"></i>',
262 'callback_for_can' => function() use ($userid){
263 return (
264 ( current_user_can( 'administrator' ) || WPF()->usergroup->can( 'dm' ) )
265 && WPF()->perm->user_can_manage_user( WPF()->current_userid, $userid )
266 )
267 && (
268 $userid !== WPF()->current_userid
269 || ( !is_super_admin( $userid ) && apply_filters('wpforo_can_user_self_delete', true) )
270 );
271 },
272 'callback_for_get_url' => function() use ( $userid ){
273 return wp_nonce_url( trim( WPF()->member->get_profile_url( $userid ), '/' ) . '/?wpfaction=user_delete', 'user_delete', '_wpfnonce' );
274 },
275 'confirm_msg' => wpforo_phrase( 'Please confirm you want to do this action?', false ),
276 ],
277 'delete_dash' => [
278 'label' => wpforo_phrase( 'Delete User in Dashboard', false ),
279 'ico' => '<i class="fa-solid fa-user-large-slash"></i>',
280 'callback_for_can' => function() use ($userid){
281 return (current_user_can('administrator')
282 && WPF()->perm->user_can_manage_user( WPF()->current_userid, $userid )
283 && $userid !== WPF()->current_userid);
284 },
285 'callback_for_get_url' => function() use ( $userid ){
286 return admin_url( wp_nonce_url( "users.php?action=delete&user=" . $userid, 'bulk-users' ) );
287 }
288 ],
289 ];
290
291 return array_map( [$this, 'fix_action'], apply_filters( 'wpforo_member_get_actions', $actions, $user ) );
292 }
293
294 public function get_action( $user, $key ) {
295 $actions = $this->_get_actions( $user );
296 return wpfval( $actions, $key );
297 }
298
299 public function get_actions( $user ) {
300 $actions = $this->_get_actions( $user );
301 return array_filter($actions, function( $action ) use ( $user ){
302 if( is_callable( $action['callback_for_can'] ) ) return call_user_func( $action['callback_for_can'] );
303 return true;
304 });
305 }
306
307 private function add_profile( $args ) {
308 if( !$userid = wpforo_bigintval( wpfval( $args, 'userid' ) ) ) return false;
309 $sql = "INSERT IGNORE INTO `" . WPF()->tables->profiles . "` (`userid`, `title`, `groupid`, `timezone`, `about`) VALUES ( %d, %s, %d, %s, %s )";
310 $sql = WPF()->db->prepare(
311 $sql,
312 $userid,
313 sanitize_text_field( wpfval( $args, 'title' ) ) ?: wpforo_setting( 'profiles', 'default_title' ),
314 (int) wpfval( $args, 'groupid' ) ?: WPF()->usergroup->default_groupid,
315 sanitize_text_field( wpfval( $args, 'timezone' ) ) ?: '',
316 stripslashes( wpforo_kses( trim( (string) wpfval( $args, 'about' ) ), 'user_description' ) ) ?: ''
317 );
318
319 $r = WPF()->db->query( $sql );
320 $this->reset( $userid );
321 return $r;
322 }
323
324 function create( $data ) {
325 if( ! wpforo_setting( 'authorization', 'user_register' ) ) {
326 WPF()->notice->add( 'User registration is disabled.', 'error' );
327
328 return false;
329 }
330
331 $user_fields = [];
332 if( ! empty( $data ) ) {
333 if( wpfval( $data, 'wpfreg' ) ) {
334 $user_fields = $data['wpfreg'];
335 } else {
336 $user_fields = $data;
337 }
338 }
339
340 //-- START -- copied from update code
341 //Define $user
342 $user = $user_fields;
343
344 //Define $userid
345 $userid = intval( wpfval( $user, 'userid' ) );
346
347 //Check custom fields and merge to $user array
348 if( wpfval( $data, 'data' ) && is_array( $data['data'] ) && ! empty( $data['data'] ) ) {
349 $custom_fields = $data['data'];
350 $user = array_merge( $custom_fields, $user );
351 }
352
353 //Check file uploading custom fields and merge to $user array
354 $file_data = isset( $_FILES['data']['name'] ) && $_FILES['data']['name'] && is_array( $_FILES['data']['name'] ) ? array_filter( $_FILES['data']['name'] ) : [];
355 $file_fields = WPF()->form->prepare_file_args( $file_data, $userid );
356 if( wpfval( $file_fields, 'fields' ) ) {
357 $user = array_merge( $file_fields['fields'], $user );
358 }
359
360 //Validate fields
361 $form_fields = $this->get_register_fields();
362 $result = WPF()->form->validate( $user, $form_fields );
363 if( wpfval( $result, 'error' ) ) {
364 if( wpforo_is_admin() && wpfval( $result['error'], 0 ) ) {
365 wp_die( $result['error'][0] );
366 } else {
367 WPF()->notice->add( $result['error'], 'error' );
368
369 return false;
370 }
371 }
372 //-- END -- copied from update code
373
374 $user_fields = apply_filters( 'wpforo_create_profile', $user_fields );
375
376 if( ! $user_fields ) {
377 WPF()->notice->add( 'Empty fields', 'error' );
378
379 return false;
380 } elseif( wpfval( $user_fields, 'error' ) ) {
381 WPF()->notice->add( sanitize_text_field( $user_fields['error'] ), 'error' );
382
383 return false;
384 }
385
386 $this->login_min_length = apply_filters( 'wpforo_login_min_length', $this->login_min_length );
387 $this->login_max_length = apply_filters( 'wpforo_login_max_length', $this->login_max_length );
388 $this->pass_min_length = apply_filters( 'wpforo_pass_min_length', $this->pass_min_length );
389 $this->pass_max_length = apply_filters( 'wpforo_pass_max_length', $this->pass_max_length );
390
391 if( ! wpforo_setting( 'authorization', 'user_register_email_confirm' ) && ! empty( $user_fields ) && is_array( $user_fields ) && ! empty( $user_fields['user_pass1'] ) ) {
392
393 remove_action( 'register_new_user', 'wp_send_new_user_notifications' );
394 remove_action( 'register_new_user', 'wpforo_send_new_user_notifications' );
395 add_action( 'register_new_user', function( $user_id ) {
396 wpforo_send_new_user_notifications( $user_id, 'admin' );
397 } );
398
399 do_action( 'wpforo_create_profile_before', $user_fields );
400
401 $errors = new WP_Error();
402
403 extract( $user_fields, EXTR_OVERWRITE );
404 $sanitized_user_login = sanitize_user( $user_login );
405 $user_email = apply_filters( 'user_registration_email', $user_email );
406 $user_pass1 = trim( substr( (string) $user_pass1, 0, 100 ) );
407 $user_pass2 = trim( substr( (string) $user_pass2, 0, 100 ) );
408 $illegal_user_logins = array_map( 'strtolower', (array) apply_filters( 'illegal_user_logins', [] ) );
409
410 if( $sanitized_user_login == '' ) {
411 $errors->add( 'empty_username', __( '<strong>ERROR</strong>: Please enter a username.' ) );
412 WPF()->notice->add( 'Username is missed.', 'error' );
413
414 return false;
415 } elseif( ! validate_username( $user_login ) ) {
416 $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ) );
417 WPF()->notice->add( 'Illegal character in username.', 'error' );
418
419 return false;
420 } elseif( strlen( (string) $user_login ) < $this->login_min_length || strlen( (string) $user_login ) > $this->login_max_length ) {
421 WPF()->notice->add( 'Username length must be between %d characters and %d characters.', 'error', [ $this->login_min_length, $this->login_max_length ] );
422
423 return false;
424 } elseif( username_exists( $sanitized_user_login ) ) {
425 $errors->add( 'username_exists', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ) );
426 WPF()->notice->add( 'Username exists. Please insert another.', 'error' );
427
428 return false;
429 } elseif( in_array( strtolower( $sanitized_user_login ), $illegal_user_logins ) ) {
430 $errors->add( 'invalid_username', __( '<strong>ERROR</strong>: Sorry, that username is not allowed.' ) );
431 WPF()->notice->add( 'ERROR: invalid_username. Sorry, that username is not allowed. Please insert another.', 'error' );
432
433 return false;
434 } elseif( $user_email == '' ) {
435 $errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please type your email address.' ) );
436 WPF()->notice->add( 'Insert your Email address.', 'error' );
437
438 return false;
439 } elseif( ! is_email( $user_email ) ) {
440 $errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ) );
441 WPF()->notice->add( 'Invalid Email address', 'error' );
442
443 return false;
444 } elseif( email_exists( $user_email ) ) {
445 $errors->add( 'email_exists', __( '<strong>ERROR</strong>: This email is already registered, please choose another one.' ) );
446 WPF()->notice->add( 'Email address exists. Please insert another.', 'error' );
447
448 return false;
449 } elseif( strlen( $user_pass1 ) < $this->pass_min_length || strlen( $user_pass1 ) > $this->pass_max_length ) {
450 WPF()->notice->add( 'Password length must be between %d characters and %d characters.', 'error', [ $this->pass_min_length, $this->pass_max_length ] );
451
452 return false;
453 } elseif( $user_pass1 != $user_pass2 ) {
454 WPF()->notice->add( 'Password mismatch.', 'error' );
455
456 return false;
457 } else {
458 do_action( 'register_post', $sanitized_user_login, $user_email, $errors );
459 $errors = apply_filters( 'registration_errors', $errors, $sanitized_user_login, $user_email );
460 if( $errors->get_error_code() ) {
461 $user_fields = [];
462 foreach( $errors->errors as $u_err ) $user_fields[] = $u_err[0];
463 WPF()->notice->add( $user_fields, 'error' );
464
465 return false;
466 }
467 $user_id = wp_create_user( $sanitized_user_login, $user_pass1, $user_email );
468 if( ! is_wp_error( $user_id ) && $user_id ) {
469 do_action( 'register_new_user', $user_id );
470 do_action( 'wpforo_create_user_after', $data );
471 wp_signon( [ 'user_login' => $sanitized_user_login, 'user_password' => $user_pass1 ] );
472 WPF()->notice->clear();
473 WPF()->notice->add( 'Success!', 'success' );
474
475 return $user_id;
476 }
477 }
478 } elseif( wpforo_setting( 'authorization', 'user_register_email_confirm' ) && ! empty( $user_fields['user_login'] ) && ! empty( $user_fields['user_email'] ) ) {
479 if( strlen( (string) $user_fields['user_login'] ) < $this->login_min_length || strlen( (string) $user_fields['user_login'] ) > $this->login_max_length ) {
480 WPF()->notice->add( 'Username length must be between %d characters and %d characters.', 'error', [ $this->login_min_length, $this->login_max_length ] );
481
482 return false;
483 }
484 if( is_multisite() && apply_filters( 'wpforo_mu_signup', false ) ) {
485 wpmu_signup_user( $user_fields['user_login'], $user_fields['user_email'] );
486 WPF()->notice->clear();
487 WPF()->notice->add( 'Success! Please check your mail for confirmation.', 'success' );
488
489 return true;
490 } else {
491 $user_id = register_new_user( $user_fields['user_login'], $user_fields['user_email'] );
492 }
493 if( ! is_wp_error( $user_id ) && $user_id ) {
494 do_action( 'wpforo_create_user_after', $data );
495 WPF()->notice->clear();
496 WPF()->notice->add( 'Success! Please check your mail for confirmation.', 'success' );
497
498 return $user_id;
499 }
500 }
501
502 if( ! empty( $user_id->errors ) ) {
503 $user_fields = [];
504 foreach( $user_id->errors as $u_err ) $user_fields[] = $u_err[0];
505 WPF()->notice->add( $user_fields, 'error' );
506
507 return false;
508 }
509
510 WPF()->notice->add( 'Registration Error', 'error' );
511
512 return false;
513 }
514
515 /**
516 * Updates user data
517 *
518 * @param array $data - User data as a simple array( field => value ) OR
519 * $data['member'] = array( field => value ) user and profile fields - Account form
520 * $data['wpfreg'] = array( field => value ) user and profile fields - Registration form
521 * $data['data'] = array( field => value ) user custom fields
522 *
523 * $data['member']['userid'] or $data['userid'] is required
524 *
525 * @param string|array $type User data update types (comma separated)
526 * $type = 'full' user fields, profile fields, custom fields
527 * $type = 'user' only user fields (wp_users table)
528 * $type = 'profile' only profile fields (wp_wpforo_profiles table)
529 * $type = 'custom_fields' only custom fields (wp_wpforo_profiles table > fields column)
530 * $type = 'profile, custom_fields'
531 *
532 * @param boolean $check_permissions Whether check the current editor permissions or not
533 *
534 * @return false|array wpForo User array
535 * @since 1.5.0
536 *
537 */
538 public function update( $data, $type = 'full', $check_permissions = true ) {
539 $type = (array) $type;
540
541 switch( WPF()->current_object['template'] ) {
542 case 'register':
543 $form = 'wpfreg';
544 $form_fields = $this->get_register_fields();
545 break;
546 default:
547 $form = 'member';
548 $form_fields = $this->get_account_fields();
549 break;
550 }
551 if( ! $form_fields ) {
552 WPF()->notice->add( 'Form template not found', 'error' );
553
554 return false;
555 }
556
557 if( ! wpfkey( $data, $form ) ) {
558 if( in_array( 'custom_fields', $type ) && count( $type ) === 1 ) {
559 if( ! wpfval( $data, 'data' ) ) {
560 $data['data'] = $data;
561 if( wpfkey( $data, 'data', 'userid' ) ) unset( $data['data']['userid'] );
562 }
563 } else {
564 $data[ $form ] = $data;
565 }
566 }
567 if( wpfval( $data, 'userid' ) && ! wpfval( $data, $form, 'userid' ) ) $data[ $form ]['userid'] = $data['userid'];
568
569 if( wpfval( $data, $form, 'userid' ) ) {
570 $result_user = true;
571 $result_fields = true;
572 $result_profile = true;
573 $custom_fields = [];
574
575 //Define $user
576 $user = $data[ $form ];
577
578 //Define $userid
579 $userid = intval( $data[ $form ]['userid'] );
580
581 //Check profile editor permissions
582 if( $check_permissions ) WPF()->perm->can_edit_user( $userid );
583
584 //Check custom fields and merge to $user array
585 if( wpfkey( $data, 'data' ) && is_array( $data['data'] ) && ! empty( $data['data'] ) ) {
586 $custom_fields = $data['data'];
587 $user = array_merge( $custom_fields, $user );
588 }
589
590 //Check file uploading custom fields and merge to $user array
591 $file_data = isset( $_FILES['data']['name'] ) && $_FILES['data']['name'] && is_array( $_FILES['data']['name'] )
592 ? array_filter( $_FILES['data']['name'], function( $key ){
593 if( trim((string) $key) && ($field = $this->get_field( $key )) ){
594 if( wpfval( $field, 'type' ) === 'file' ){
595 $mime_type = wpfval( $_FILES, 'data', 'type', $key );
596 $mime_types = wp_get_mime_types();
597 $allowed_mime_types = get_allowed_mime_types();
598 $name = wpfval( $_FILES, 'data', 'name', $key );
599 $ext = pathinfo( $name, PATHINFO_EXTENSION );
600 $size = intval( $field['fileSize'] );
601 $fileExtensions = array_filter( (array) (is_scalar( $field['fileExtensions'] ) ? explode( ',', trim( (string) $field['fileExtensions'] ) ) : $field['fileExtensions']) );
602 if( $fileExtensions ) {
603 if( in_array( $ext, $fileExtensions ) ) {
604 $extensions = explode( '|', array_search( $mime_type, $mime_types ) );
605 $e = in_array( $ext, $extensions );
606 } else {
607 $e = false;
608 }
609 } else {
610 $extensions = explode( '|', array_search( $mime_type, $allowed_mime_types ) );
611 $e = in_array( $ext, $extensions );
612 }
613
614 return ! empty( $e ) && wpfval( $_FILES, 'data', 'size', $key ) <= ( $size * 1024 * 1024 );
615 }
616 }
617 return false;
618 }, ARRAY_FILTER_USE_KEY )
619 : [];
620 $file_fields = WPF()->form->prepare_file_args( $file_data, $userid );
621 if( wpfval( $file_fields, 'fields' ) ) {
622 $user = array_merge( $file_fields['fields'], $user );
623 $custom_fields = ( ! empty( $custom_fields ) ) ? array_merge( $custom_fields, $file_fields['fields'] ) : $file_fields['fields'];
624 }
625
626 //Hooks
627 $user = apply_filters( 'wpforo_update_profile', $user );
628 do_action( 'wpforo_update_profile_before', $user );
629 if( wpfval( $user, 'error' ) || empty( $user ) ) {
630 $error_message = ( wpfval( $user, 'error_message' ) ) ? sanitize_text_field( $user['error_message'] ) : 'Unknown error in profile editing hook. Please disable all plugins and check it again.';
631 WPF()->notice->add( $error_message, 'error' );
632
633 return false;
634 }
635
636 //Validate avatar_url
637 if( wpfval($user, 'avatar_type') === 'remote' && wpfval( $user, 'avatar_url' ) ){
638 if( empty( getimagesize( $user['avatar_url'] ) ) ){
639 WPF()->notice->add( 'The avatar URL is not an image file.', 'error' );
640
641 return false;
642 }
643 }
644
645 //Validate fields
646 $result = WPF()->form->validate( $user, $form_fields );
647 if( wpfval( $result, 'error' ) ) {
648 if( is_admin() && wpfval( $result['error'], 0 ) ) {
649 wp_die( $result['error'][0] );
650 } else {
651 WPF()->notice->add( $result['error'], 'error' );
652
653 return false;
654 }
655 }
656
657 if( $gid = (int) wpfval( $user, 'groupid' ) ){
658 $err = '';
659 if( WPF()->current_object['template'] !== 'register' ) {
660 if( WPF()->form->owner() || ! wpforo_current_user_is( 'admin' ) ) {
661 $err = 'You have no permission to edit Usergroup field';
662 }
663 } else {
664 if( in_array( $gid, [ 1, 2, 4 ], true ) ) {
665 $err = 'Admin and Moderator Usergroups are not permitted';
666 } else {
667 $f = $this->get_field('groupid');
668 if( wpfval( $f, 'allowedGroupIds' ) ) {
669 $allowedGroupIds = wpforo_parse_args( $f['allowedGroupIds'] );
670 if( ! in_array( $gid, $allowedGroupIds, true ) ) {
671 $err = 'The selected Usergroup cannot be set';
672 }
673 } else {
674 $err = 'The selected Usergroup is not found in allowed list';
675 }
676 }
677 }
678
679 if( $err ){
680 unset( $user['groupid'] );
681 }
682 }
683
684 if( $sgids = array_filter( array_map( 'intval', (array) wpfval( $user, 'secondary_groupids' ) ) ) ){
685 $f = $this->get_field('secondary_groupids');
686 if( WPF()->current_object['template'] === 'register' || ( WPF()->form->owner() && $f['isEditable'] ) || ( ! WPF()->form->owner() && in_array( WPF()->current_user_groupid, (array) $f['canEdit'] ) ) || wpforo_current_user_is( 'admin' ) ) {
687 if( ! empty( $sgids ) ) {
688 $secondary_groupids = WPF()->usergroup->get_secondary_groupids();
689 foreach( $sgids as $sgid ) {
690 if( in_array( $sgid, [ 1, 2, 4 ], true ) ) {
691 $user['secondary_groupids'] = array_diff( $user['secondary_groupids'], [$sgid] );
692 }
693 if( ! in_array( $sgid, $secondary_groupids ) ) {
694 $user['secondary_groupids'] = array_diff( $user['secondary_groupids'], [$sgid] );
695 }
696 }
697 }
698 } else {
699 unset( $user['secondary_groupids'] );
700 }
701 }
702
703 //Sanitize fields
704 $user = WPF()->form->sanitize( $user, $form_fields );
705
706 //Update User Fields
707 if( ! empty( $user ) && ( in_array( 'full', $type ) || in_array( 'user', $type ) ) ) {
708 $result_user = $this->update_user_fields( $userid, $user, false );
709 }
710
711 //Update Profile Fields
712 if( ! empty( $user ) && ( in_array( 'full', $type ) || in_array( 'profile', $type ) ) ) {
713 $result_profile = $this->update_profile_fields( $userid, $user, false );
714 }
715
716 //Password field validation and update
717 $result_password = WPF()->form->validate_password( $user );
718 if( $result_password === false ) {
719 $result_password = true;
720 }
721 if( wpfval( $result_password, 'error' ) ) {
722 WPF()->notice->add( $result_password['error'], 'error' );
723 $result_password = false;
724 }
725 if( $result_password && wpfval( $user, 'old_pass' ) && wpfval( $user, 'user_pass1' ) ) {
726 $result_password = $this->change_password( $user['old_pass'], $user['user_pass1'], $userid );
727 }
728
729 //Upload avatar
730 if( wpfval( $user, 'avatar_type' ) === 'custom' ) {
731 $this->upload_avatar( $userid );
732 }
733
734 //Update Custom Fields
735 if( ! empty( $custom_fields ) && ( in_array( 'full', $type ) || in_array( 'custom_fields', $type ) ) ) {
736 $result_fields = $this->update_custom_fields( $userid, $custom_fields, false );
737 }
738
739 //Upload Files from Custom Fields
740 if( wpfval( $file_fields, 'files' ) ) {
741 $this->upload_files( $file_fields['files'] );
742 }
743
744 //Reset this user cache
745 $this->reset( $userid );
746
747 if( $result_user === false || $result_profile === false || $result_fields === false || $result_password === false ) {
748 return false;
749 } else {
750 WPF()->notice->add( 'Profile updated successfully', 'success' );
751 do_action( 'wpforo_update_profile_after', $user );
752
753 return $user;
754 }
755 }
756
757 return false;
758 }
759
760 public function update_user_fields( $userid, $data, $check_permissions = true ) {
761 $result_user = true;
762 if( $check_permissions ) WPF()->perm->can_edit_user( $userid );
763
764 //User Fields
765 if( wpfkey( $data, 'display_name' ) ) {
766 $user_fields['display_name'] = $data['display_name'];
767 $user_fields_types[] = '%s';
768 }
769 if( wpfkey( $data, 'user_email' ) ) {
770 $user_fields['user_email'] = $data['user_email'];
771 $user_fields_types[] = '%s';
772 }
773 if( wpfkey( $data, 'user_nicename' ) ) {
774 if( ! wpfval( $data, 'user_nicename' ) ) {
775 $user_info = get_userdata( $userid );
776 $data['user_nicename'] = sanitize_title( sanitize_user( $user_info->user_nicename, true ) );
777 }
778 $user_fields['user_nicename'] = $data['user_nicename'];
779 $user_fields_types[] = '%s';
780 update_user_meta( $userid, 'nickname', $data['user_nicename'] );
781 }
782 if( wpfkey( $data, 'first_name' ) ) {
783 update_user_meta( $userid, 'first_name', $data['first_name'] );
784 }
785 if( wpfkey( $data, 'last_name' ) ) {
786 update_user_meta( $userid, 'last_name', $data['last_name'] );
787 }
788 if( wpfkey( $data, 'user_url' ) ) {
789 $user_fields['user_url'] = $data['user_url'];
790 $user_fields_types[] = '%s';
791 }
792
793 if( ! empty( $user_fields ) && ! empty( $user_fields_types ) ) {
794 $result_user = WPF()->db->update( WPF()->db->users, $user_fields, [ 'ID' => $userid ], $user_fields_types, [ '%d' ] );
795 if( false === $result_user ) {
796 WPF()->notice->add( 'User data update failed', 'error' );
797 if( WPF()->db->last_error ) {
798 WPF()->notice->add( sanitize_text_field( WPF()->db->last_error ), 'error' );
799 }
800 } else {
801 clean_user_cache( $userid );
802 }
803 }
804
805 if( $result_user ) $this->reset( $userid );
806
807 return $result_user;
808 }
809
810 public function update_profile_field( $userid, $key, $value ) {
811 $r = false;
812 if( $key && ! is_null( $value ) ) {
813 $member = $this->encode( [ $key => $value ] );
814 if( wpfkey( $member, $key ) ){
815 $r = WPF()->db->update(
816 WPF()->tables->profiles,
817 [ $key => $value ],
818 [ 'userid' => $userid ],
819 [ wpforo_db_data_format( $member[ $key ] ) ],
820 [ '%d' ]
821 );
822
823 if( $r ) $this->reset( $userid );
824 }
825 }
826
827 return $r;
828 }
829
830 public function update_profile_fields( $userid, $data, $check_permissions = true ) {
831 $result_profile = true;
832
833 if( $check_permissions ) {
834 WPF()->perm->can_edit_user( $userid );
835 }
836
837 $member = $this->encode( $data );
838
839 $profile_fields = [];
840 $profile_fields_types = [];
841
842 //Profile Fields
843 if( wpfkey( $data, 'groupid' ) ) {
844 $profile_fields['groupid'] = $member['groupid'];
845 $profile_fields_types[] = '%d';
846 }
847 if( wpfkey( $data, 'title' ) ) {
848 $profile_fields['title'] = $member['title'];
849 $profile_fields_types[] = '%s';
850 }
851 if( wpfkey( $data, 'signature' ) ) {
852 $profile_fields['signature'] = $member['signature'];
853 $profile_fields_types[] = '%s';
854 }
855 if( wpfkey( $data, 'about' ) ) {
856 $profile_fields['about'] = $member['about'];
857 $profile_fields_types[] = '%s';
858 update_user_meta( $userid, 'description', $member['about'] );
859 }
860 if( wpfkey( $data, 'occupation' ) ) {
861 $profile_fields['occupation'] = $member['occupation'];
862 $profile_fields_types[] = '%s';
863 }
864 if( wpfkey( $data, 'location' ) ) {
865 $profile_fields['location'] = $member['location'];
866 $profile_fields_types[] = '%s';
867 }
868 if( wpfkey( $data, 'timezone' ) ) {
869 $profile_fields['timezone'] = $member['timezone'];
870 $profile_fields_types[] = '%s';
871 }
872 if( wpfkey( $data, 'avatar_type' ) && $data['avatar_type'] !== 'gravatar' && wpfval( $data, 'avatar_url' ) ) {
873 $profile_fields['avatar'] = esc_url( trim( (string) $data['avatar_url'] ) );
874 $profile_fields_types[] = '%s';
875 }
876 if( wpfkey( $data, 'avatar_type' ) && $data['avatar_type'] === 'gravatar' ) {
877 $profile_fields['avatar'] = '';
878 $profile_fields_types[] = '%s';
879 }
880 if( wpfkey( $data, 'cover' ) ) {
881 $profile_fields['cover'] = $member['cover'];
882 $profile_fields_types[] = '%s';
883 }
884 if( wpfkey( $data, 'secondary_groupids' ) ) {
885 $profile_fields['secondary_groupids'] = $member['secondary_groupids'];
886 $profile_fields_types[] = '%s';
887 }
888 if( wpfkey( $data, 'custom_points' ) ) {
889 $profile_fields['custom_points'] = $member['custom_points'];
890 $profile_fields_types[] = '%d';
891 }
892 if( wpfkey( $data, 'online_time' ) ) {
893 $profile_fields['online_time'] = $member['online_time'];
894 $profile_fields_types[] = '%d';
895 }
896 if( wpfkey( $data, 'status' ) ) {
897 $profile_fields['status'] = $member['status'];
898 $profile_fields_types[] = '%s';
899 }
900 if( wpfkey( $data, 'is_email_confirmed' ) ) {
901 $profile_fields['is_email_confirmed'] = $member['is_email_confirmed'];
902 $profile_fields_types[] = '%d';
903 }
904 if( wpfkey( $data, 'is_mention_muted' ) ) {
905 $profile_fields['is_mention_muted'] = $member['is_mention_muted'];
906 $profile_fields_types[] = '%d';
907 }
908
909 $profile_fields = apply_filters( 'wpforo_before_update_profile_fields', $profile_fields, $userid, $data, $check_permissions );
910
911 if( ! empty( $profile_fields ) ) {
912 $result_profile = WPF()->db->update( WPF()->tables->profiles, $profile_fields, [ 'userid' => intval( $userid ) ], $profile_fields_types, [ '%d' ] );
913 if( false === $result_profile ) {
914 WPF()->notice->add( 'User profile update failed', 'error' );
915 if( WPF()->db->last_error ) {
916 WPF()->notice->add( sanitize_text_field( WPF()->db->last_error ), 'error' );
917 }
918 }
919 }
920 do_action( 'wpforo_update_profile_fields', $userid, $data, $result_profile );
921
922 if( $result_profile ) $this->reset( $userid );
923
924 return $result_profile;
925 }
926
927 public function update_custom_field( $userid, $field_name, $field_value = null ) {
928 $result = false;
929 $fields = $this->get_custom_fields( $userid );
930 if( ! empty( $fields ) && $field_name && ! is_null( $field_value ) ) {
931 foreach( $fields as $name => $value ) {
932 if( $name == $field_name ) {
933 $fields[ $name ] = $field_value;
934 }
935 }
936 $custom_fields = array_filter( $fields );
937 $custom_fields = wpforo_unslashe( $custom_fields );
938 $custom_fields = wpforo_decode( $custom_fields );
939 $custom_fields = wpforo_encode( $custom_fields );
940 $fields_json = json_encode( $custom_fields, JSON_UNESCAPED_UNICODE );
941 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `fields` = %s WHERE `userid` = %d;";
942 $sql = WPF()->db->prepare( $sql, $fields_json, $userid );
943 $result = WPF()->db->query( $sql );
944 }
945
946 if( $result ) $this->reset( $userid );
947
948 return $result;
949 }
950
951 public function update_custom_fields( $userid, $custom_fields, $check_permissions = true ) {
952
953 $result_fields = true;
954
955 if( ! empty( $custom_fields ) ) {
956 if( $check_permissions ) {
957 WPF()->perm->can_edit_user( $userid );
958 }
959 $custom_fields = wpforo_unslashe( $custom_fields );
960 $custom_fields = wpforo_decode( $custom_fields );
961 $custom_fields = wpforo_encode( $custom_fields );
962 $data_old = $this->get_custom_fields( $userid );
963 if( $data_old && is_array( $data_old ) ) {
964 $custom_fields = wp_parse_args( $custom_fields, $data_old );
965 }
966 $fields_json = json_encode( $custom_fields, JSON_UNESCAPED_UNICODE );
967 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `fields` = %s WHERE `userid` = %d;";
968 $sql = WPF()->db->prepare( $sql, $fields_json, $userid );
969 $result_fields = WPF()->db->query( $sql );
970 if( false === $result_fields ) {
971 WPF()->notice->add( 'User custom field update failed', 'error' );
972 if( WPF()->db->last_error ) {
973 WPF()->notice->add( sanitize_text_field( WPF()->db->last_error ), 'error' );
974 }
975 }
976 }
977
978 if( $result_fields ) $this->reset( $userid );
979
980 return $result_fields;
981 }
982
983 public function upload_avatar( $userid = 0 ) {
984 $userid = intval( $userid );
985
986 $_FILES['avatar'] = wpforo_check_for_svg( $_FILES['avatar'] );
987
988 if( wpfval( WPF()->current_object, 'template' ) ) {
989 $template = WPF()->current_object['template'];
990 if( $template === 'account' ) {
991 if( ! WPF()->usergroup->can( 'upa' ) ) return false;
992 }
993 }
994
995 if( ! $user = $this->get_member( $userid ) ) return false;
996 $user_nicename = urldecode( (string) $user['user_nicename'] );
997 if( isset( $_FILES['avatar'] ) && ! empty( $_FILES['avatar'] ) && isset( $_FILES['avatar']['name'] ) && $_FILES['avatar']['name'] ) {
998 $name = sanitize_file_name( $_FILES['avatar']['name'] ); //myimg.png
999 $tmp_name = sanitize_text_field( $_FILES['avatar']['tmp_name'] ); //D:\wamp\tmp\php986B.tmp
1000 $error = sanitize_text_field( $_FILES['avatar']['error'] ); //0
1001 $size = intval( $_FILES['avatar']['size'] ); //6112
1002
1003 $upload_max_filesize = apply_filters( 'wpforo_avatar_upload_max_filesize', 2 * 1048576 );
1004 if( $size > $upload_max_filesize ) {
1005 WPF()->notice->clear();
1006 WPF()->notice->add( 'Avatar image is too big maximum allowed size is %s', 'error', wpforo_print_size( $upload_max_filesize ) );
1007
1008 return false;
1009 }
1010
1011 if( $error ) {
1012 $error = wpforo_file_upload_error( $error );
1013 WPF()->notice->clear();
1014 WPF()->notice->add( $error, 'error' );
1015
1016 return false;
1017 }
1018
1019 $avatar_dir = WPF()->folders['avatars']['dir'];
1020 if( ! is_dir( $avatar_dir ) ) wp_mkdir_p( $avatar_dir );
1021
1022 $ext = pathinfo( $name, PATHINFO_EXTENSION );
1023 if( ! wpforo_is_image( $ext ) ) {
1024 WPF()->notice->clear();
1025 WPF()->notice->add( 'Incorrect file format. Allowed formats: jpeg, jpg, png, gif.', 'error' );
1026
1027 return false;
1028 }
1029
1030 $fnm = pathinfo( $user_nicename, PATHINFO_FILENAME );
1031 $fnm = str_replace( ' ', '-', $fnm );
1032 while( strpos( (string) $fnm, '--' ) !== false ) $fnm = str_replace( '--', '-', $fnm );
1033 $fnm = preg_replace( "/[^-a-zA-Z0-9]/", "", (string) $fnm );
1034 $fnm = trim( (string) $fnm, "-" );
1035
1036 $avatar_fname = $fnm . ( $fnm ? '_' : '' ) . $userid . "." . strtolower( (string) $ext );
1037 $avatar_fname_orig = $fnm . ( $fnm ? '_' : '' ) . $userid . "." . $ext;
1038 $avatar_path = $avatar_dir . DIRECTORY_SEPARATOR . $avatar_fname;
1039 $avatar_path_orig = $avatar_dir . DIRECTORY_SEPARATOR . $avatar_fname_orig;
1040
1041 if( is_dir( $avatar_dir ) ) {
1042 if( move_uploaded_file( $tmp_name, $avatar_path ) ) {
1043 $image = wp_get_image_editor( $avatar_path );
1044 if( ! is_wp_error( $image ) ) {
1045 $image->resize( 150, 150, true );
1046 $saved = $image->save( $avatar_path );
1047 if( ! is_wp_error( $saved ) && $avatar_fname != $avatar_fname_orig ) {
1048 if( defined( PHP_OS ) && strtoupper( substr( PHP_OS, 0, 3 ) ) !== 'WIN' ) unlink( $avatar_path_orig );
1049 }
1050 }
1051 WPF()->db->update( WPF()->tables->profiles, [ 'avatar' => WPF()->folders['avatars']['url//'] . "/" . $avatar_fname ], [ 'userid' => intval( $userid ) ], [ '%s' ], [ '%d' ] );
1052 $this->reset( $userid );
1053
1054 return true;
1055 }
1056 }
1057 }
1058
1059 return false;
1060 }
1061
1062 public function upload_files( $file_fields ) {
1063 if( ! empty( $file_fields ) ) {
1064 foreach( $file_fields as $field_name => $file_path ) {
1065 if( wpfval( $_FILES, 'data', 'tmp_name', $field_name ) && ! move_uploaded_file( $_FILES['data']['tmp_name'][ $field_name ], $file_path ) ) {
1066 WPF()->notice->add( 'Sorry, there was an error uploading attached file', 'error' );
1067 }
1068 }
1069 }
1070 }
1071
1072 public function get_custom_field( $userid, $field_name ) {
1073 $field_value = '';
1074 if( $userid ) {
1075 $sql = WPF()->db->prepare( "SELECT `fields` FROM `" . WPF()->tables->profiles . "` WHERE userid = %d", $userid );
1076 $fields = WPF()->db->get_var( $sql );
1077 if( $fields ) {
1078 $data = (array) json_decode( $fields, true );
1079 if( ! empty( $data ) ) {
1080 $data = wpforo_unslashe( $data );
1081 if( wpfkey( $data, $field_name ) ) {
1082 $field_value = $data[ $field_name ];
1083 }
1084 }
1085 }
1086 }
1087
1088 return $field_value;
1089 }
1090
1091 public function get_custom_fields( $userid ) {
1092 $data = [];
1093 if( $userid ) {
1094 $sql = WPF()->db->prepare( "SELECT `fields` FROM `" . WPF()->tables->profiles . "` WHERE userid = %d", $userid );
1095 $fields = WPF()->db->get_var( $sql );
1096 if( $fields ) {
1097 $data = (array) json_decode( $fields, true );
1098 }
1099 $data = wpforo_unslashe( $data );
1100 }
1101
1102 return $data;
1103 }
1104
1105 public function change_password( $old_passw, $new_passw, $userid ) {
1106 if( ! ($userid = wpforo_bigintval( $userid )) || ! ($user = $this->get_member( $userid )) ) {
1107 WPF()->notice->clear();
1108 WPF()->notice->add( 'Userid is wrong', 'error' );
1109
1110 return false;
1111 }
1112
1113 $user['user_pass'] = ( $userdata = get_userdata( $userid ) ) ? $userdata->user_pass : '';
1114
1115 if( ! apply_filters( 'wpforo_change_password_validate', true, $old_passw, $new_passw, $user ) ) return false;
1116
1117 if( wp_check_password( $old_passw, $user['user_pass'], $userid ) ) {
1118 wp_set_password( $new_passw, $userid );
1119 if( ! wpforo_is_owner( $userid ) ) $this->inactive_to_active( $userid );
1120
1121 /**
1122 * Login user after change password with new pass
1123 */
1124 if( wpforo_is_owner( $userid ) ) {
1125 wp_signon( [ 'user_login' => sanitize_user( $user['user_login'] ), 'user_password' => $new_passw ] );
1126 }
1127
1128 WPF()->notice->add( 'Password successfully changed', 'success' );
1129
1130 return true;
1131 }
1132
1133 WPF()->notice->clear();
1134 WPF()->notice->add( 'Old password is wrong', 'error' );
1135
1136 return false;
1137 }
1138
1139 public function get_status( $userid ) {
1140 return WPF()->db->get_var(
1141 WPF()->db->prepare(
1142 "SELECT `status`
1143 FROM " . WPF()->tables->profiles . "
1144 WHERE `userid` = %d",
1145 $userid
1146 )
1147 );
1148 }
1149
1150 public function inactive_to_active( $userid, $user_login = '', $raw = false ) {
1151 if( $this->get_status( $userid ) === 'inactive' ) {
1152 if( $raw || !wpforo_setting( 'authorization', 'manually_approval' ) ){
1153 $this->update_profile_fields( $userid, [ 'status' => 'active' ], false );
1154 }else{
1155 wp_safe_redirect( wpforo_url( '', 'cantlogin' ) );
1156 exit();
1157 }
1158 }
1159 }
1160
1161 public function synchronize_user( $userid, $roles_usergroups = [] ) {
1162 $groupid = false;
1163 if( ! $userid || ! ($user = get_userdata( $userid )) ) return false;
1164 $user->roles = (array) $user->roles;
1165
1166 //Don't synchronize User Roles with Usergroups if the option is disabled
1167 if( wpforo_setting( 'authorization', 'role_synch' ) ) {
1168 if( ! $roles_usergroups ) $roles_usergroups = WPF()->usergroup->get_role_usergroup_relation();
1169 if( ! empty( $roles_usergroups ) && ! empty( $user->roles ) ) {
1170 foreach( $user->roles as $role ) {
1171 if( isset( $roles_usergroups[ $role ] ) ) {
1172 $groupid = $roles_usergroups[ $role ];
1173 break;
1174 }
1175 }
1176 }
1177 }
1178
1179 if( ! $groupid ) {
1180 if( is_super_admin( $userid ) || in_array( 'administrator', $user->roles ) ) {
1181 $groupid = 1;
1182 } elseif( in_array( 'editor', $user->roles ) ) {
1183 $groupid = 2;
1184 } elseif( in_array( 'customer', $user->roles ) ) {
1185 $groupid = 5;
1186 } else {
1187 $groupid = WPF()->usergroup->default_groupid;
1188 }
1189 }
1190 $insert_groupid = ( isset( $_POST['wpforo_usergroup'] ) && ! wpforo_setting( 'authorization', 'role_synch' ) ) ? intval( $_POST['wpforo_usergroup'] ) : $groupid;
1191 $insert_timezone = ( isset( $_POST['wpforo_usertimezone'] ) ) ? sanitize_text_field( $_POST['wpforo_usertimezone'] ) : '';
1192 $about = get_user_meta( $userid, 'description', true );
1193 $return = $this->add_profile( [
1194 'userid' => wpforo_bigintval( $userid ),
1195 'groupid' => intval( $insert_groupid ),
1196 'timezone' => sanitize_text_field( $insert_timezone ),
1197 'about' => stripslashes( wpforo_kses( trim( (string) $about ), 'user_description' ) ),
1198 ] );
1199
1200 if( $return !== false && ( $secondary_groupids = wpfval( $_POST, 'wpforo_secondary_groupids' ) ) ) {
1201 $this->set_secondary_groupids( $userid, $secondary_groupids );
1202 }
1203
1204 return $return;
1205 }
1206
1207 public function synchronize_users( $limit = null ) {
1208
1209 if( is_multisite() ) {
1210 $sql = "SELECT `user_id` FROM `" . WPF()->db->usermeta . "` WHERE `meta_key` LIKE '" . WPF()->blog_prefix . "capabilities' AND `user_id` NOT IN( SELECT `userid` FROM `" . WPF()->tables->profiles . "` ) ORDER BY `user_id` ASC";
1211 } else {
1212 $sql = "SELECT `ID` as user_id FROM `" . WPF()->db->users . "` WHERE `ID` NOT IN( SELECT `userid` FROM `" . WPF()->tables->profiles . "` ) ORDER BY `ID` ASC";
1213 }
1214 if( ! is_null( $limit ) ) {
1215 $sql .= " LIMIT " . intval( $limit );
1216 }
1217
1218 $userids = WPF()->db->get_col( $sql );
1219 if( ! empty( $userids ) ) {
1220 $roles_usergroups = WPF()->usergroup->get_role_usergroup_relation();
1221 foreach( $userids as $userid ) {
1222 $this->synchronize_user( $userid, $roles_usergroups );
1223 }
1224
1225 return false;
1226 }
1227
1228 ## -- START -- delete profiles where not participant on multisite blog
1229 if( is_multisite() ) {
1230 $sql = "DELETE FROM `" . WPF()->tables->profiles . "` WHERE `userid` NOT IN( SELECT `user_id` FROM `" . WPF()->db->usermeta . "` WHERE `meta_key` LIKE '" . WPF()->blog_prefix . "capabilities' )";
1231 WPF()->db->query( $sql );
1232 }
1233
1234 ## -- END -- delete profiles where not participant on multisite blog
1235
1236 return true;
1237 }
1238
1239 public function _get_member( $args ) {
1240 if( ! $args ) return $this->get_guest();
1241
1242 $default = [
1243 'userid' => null, // $userid
1244 'user_nicename' => '' // $user_nicename
1245 ];
1246
1247 if( is_numeric( $args ) ) {
1248 $args = [ 'userid' => $args ];
1249 } elseif( ! is_array( $args ) ) {
1250 $args = [ 'user_nicename' => $args ];
1251 }
1252
1253 $args = wpforo_parse_args( $args, $default );
1254
1255 extract( $args );
1256
1257 $userid = wpforo_bigintval( $userid );
1258
1259 $user_meta_obj = true;
1260 if( $user_nicename ) {
1261 $user_obj = get_user_by( 'user_nicename', $user_nicename );
1262 if( ! empty( $user_obj ) ) $userid = $user_obj->ID;
1263 }
1264 $member = get_user_meta( $userid, '_wpf_member_obj', true );
1265
1266 if( empty( $member ) ) {
1267 $user_meta_obj = false;
1268 $sql = "SELECT *,
1269 ug.`name` AS group_name,
1270 ug.`color` AS group_color,
1271 fn.`meta_value` AS first_name,
1272 ln.`meta_value` AS last_name
1273 FROM `" . WPF()->db->users . "` u
1274 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`
1275 LEFT JOIN `" . WPF()->tables->usergroups . "` ug ON ug.`groupid` = p.`groupid`
1276 LEFT JOIN `" . WPF()->db->usermeta . "` fn ON fn.`user_id` = u.`ID` AND fn.`meta_key` LIKE 'first_name'
1277 LEFT JOIN `" . WPF()->db->usermeta . "` ln ON ln.`user_id` = u.`ID` AND ln.`meta_key` LIKE 'last_name'";
1278 $wheres = [];
1279 if( $userid ) $wheres[] = "`ID` = $userid";
1280 if( $user_nicename ) $wheres[] = "`user_nicename` = '" . esc_sql( $user_nicename ) . "'";
1281 if( ! empty( $wheres ) ) $sql .= " WHERE " . implode( " AND ", $wheres );
1282 $member = WPF()->db->get_row( $sql, ARRAY_A );
1283 }
1284
1285 if( ! empty( $member ) && ! $user_meta_obj ) update_user_meta( $userid, '_wpf_member_obj', $member );
1286
1287 if( $member ) $member = $this->decode( $member );
1288
1289 return $member;
1290 }
1291
1292 public function get_member( $args ) {
1293 return wpforo_ram_get( [$this, '_get_member'], $args );
1294 }
1295
1296 public function get_members( $args = [], &$items_count = 0 ) {
1297 $default = [
1298 'include' => [], // array( 2, 10, 25 )
1299 'exclude' => [], // array( 2, 10, 25 )
1300 'status' => [ 'active', 'inactive', 'banned' ], // 'active', 'blocked', 'trashed', 'spamer'
1301 'groupid' => null, // groupid
1302 'online_time' => null, // groupid
1303 'orderby' => 'userid', //
1304 'order' => 'ASC', // ASC DESC
1305 'offset' => 0, // OFFSET
1306 'row_count' => null, // ROW COUNT
1307 'groupids' => [], // array( 1, 2 )
1308 ];
1309
1310 $args = wpforo_parse_args( $args, $default );
1311 extract( $args, EXTR_OVERWRITE );
1312
1313 $include = wpforo_parse_args( $include );
1314 $exclude = wpforo_parse_args( $exclude );
1315
1316 $sql = "SELECT *,
1317 ug.`name` AS group_name,
1318 ug.`color` AS group_color,
1319 fn.`meta_value` AS first_name,
1320 ln.`meta_value` AS last_name
1321 FROM `" . WPF()->db->users . "` u
1322 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`
1323 LEFT JOIN `" . WPF()->tables->usergroups . "` ug ON ug.`groupid` = p.`groupid`
1324 LEFT JOIN `" . WPF()->db->usermeta . "` fn ON fn.`user_id` = u.`ID` AND fn.`meta_key` LIKE 'first_name'
1325 LEFT JOIN `" . WPF()->db->usermeta . "` ln ON ln.`user_id` = u.`ID` AND fn.`meta_key` LIKE 'last_name'";
1326 $wheres = [];
1327 if( ! empty( $include ) ) $wheres[] = " u.`ID` IN(" . implode( ', ', array_map( 'intval', $include ) ) . ")";
1328 if( ! empty( $exclude ) ) $wheres[] = " u.`ID` NOT IN(" . implode( ', ', array_map( 'intval', $exclude ) ) . ")";
1329 if( ! empty( $status ) ) $wheres[] = " p.`status` IN('" . implode( "','", array_map( 'esc_sql', array_map( 'sanitize_text_field', $status ) ) ) . "')";
1330 if( ! empty( $groupids ) ) $wheres[] = " (p.`groupid` IN(" . implode( ', ', array_map( 'intval', $groupids ) ) . ") OR CONCAT(',', p.`secondary_groupids`, ',') REGEXP ',(" . implode( '|', array_map( 'intval', $groupids ) ) . "),' )";
1331 if( ! is_null( $groupid ) ) $wheres[] = " (p.`groupid` = " . intval( $groupid ) . " OR FIND_IN_SET(" . intval( $groupid ) . ", p.`secondary_groupids`) ) ";
1332 if( ! is_null( $online_time ) ) $wheres[] = " p.`online_time` > " . intval( $online_time );
1333
1334 if( ! empty( $wheres ) ) $sql .= " WHERE " . implode( " AND ", $wheres );
1335
1336 $item_count_sql = preg_replace( '#SELECT.+?FROM#isu', 'SELECT count(*) FROM', $sql );
1337 $item_count_sql = preg_replace( '#ORDER.+$#is', '', $item_count_sql );
1338 if( $item_count_sql ) $items_count = WPF()->db->get_var( $item_count_sql );
1339
1340 if( $orderby === 'groupid' ) $orderby = 'p.`groupid`';
1341 $sql .= esc_sql( " ORDER BY $orderby " . $order );
1342 if( $row_count ) $sql .= esc_sql( " LIMIT $offset,$row_count" );
1343
1344 return array_map( [$this, 'decode'], WPF()->db->get_results( $sql, ARRAY_A ) );
1345 }
1346
1347 public function search( $needle, $fields = [], $limit = null ) {
1348 if( $needle ) {
1349 $needle = sanitize_text_field( $needle );
1350 if( empty( $fields ) ) {
1351 $fields = [
1352 'title',
1353 'user_nicename',
1354 'user_email',
1355 'signature',
1356 ];
1357 }
1358
1359 $sql = "SELECT `ID` FROM `" . WPF()->db->users . "` u
1360 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`";
1361 $wheres = [];
1362
1363 foreach( $fields as $field ) {
1364 $f = $this->get_field( $field );
1365 $field = sanitize_text_field( $field );
1366 if( $f['isDefault'] ) {
1367 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '%" . esc_sql( $needle ) . "%'";
1368 } else {
1369 $needle = preg_quote( preg_quote( $needle ) );
1370 if( in_array( $f['type'], [ 'text', 'search', 'textarea' ], true ) ) {
1371 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"[^\"]*" . esc_sql( $needle ) . "[^\"]*\"'";
1372 } else {
1373 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"" . esc_sql( $needle ) . "\"'";
1374 }
1375 }
1376 }
1377
1378 if( ! empty( $wheres ) ) {
1379 $sql .= " WHERE " . implode( " OR ", $wheres );
1380 if( $limit ) $sql .= " LIMIT " . intval( $limit );
1381
1382 return WPF()->db->get_col( $sql );
1383 } else {
1384 return [];
1385 }
1386 } else {
1387 return [];
1388 }
1389
1390 }
1391
1392 public function filter( $args, $limit = null ) {
1393 if( $args && is_array( $args ) ) {
1394 $sql = "SELECT `ID` FROM `" . WPF()->db->users . "` u
1395 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`";
1396 $wheres = [];
1397
1398 foreach( $args as $field => $needle ) {
1399 $f = $this->get_field( $field );
1400 $field = sanitize_text_field( $field );
1401 if( $f['isDefault'] ) {
1402 if( is_scalar( $needle ) ) {
1403 $needle = sanitize_text_field( $needle );
1404 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '%" . esc_sql( $needle ) . "%'";
1405 } elseif( is_array( $needle ) ) {
1406 foreach( $needle as $n ) {
1407 $n = sanitize_text_field( $n );
1408 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '%" . esc_sql( $n ) . "%'";
1409 }
1410 }
1411 } else {
1412 if( in_array( $f['type'], [ 'text', 'search', 'textarea' ], true ) ) {
1413 if( is_scalar( $needle ) ) {
1414 $needle = preg_quote( preg_quote( wpforo_encode( $needle ) ) );
1415 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"[^\"]*" . esc_sql( $needle ) . "[^\"]*\"'";
1416 } elseif( is_array( $needle ) ) {
1417 foreach( $needle as $n ) {
1418 $n = preg_quote( preg_quote( wpforo_encode( $n ) ) );
1419 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"[^\"]*" . esc_sql( $n ) . "[^\"]*\"'";
1420 }
1421 }
1422 } else {
1423 if( is_scalar( $needle ) ) {
1424 $needle = preg_quote( preg_quote( wpforo_encode( $needle ) ) );
1425 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"" . esc_sql( $needle ) . "\"'";
1426 } elseif( is_array( $needle ) ) {
1427 foreach( $needle as $n ) {
1428 $n = preg_quote( preg_quote( wpforo_encode( $n ) ) );
1429 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"" . esc_sql( $n ) . "\"'";
1430 }
1431 }
1432 }
1433 }
1434 }
1435
1436 if( $wheres ) {
1437 $sql .= " WHERE " . implode( " AND ", $wheres );
1438 if( $limit ) $sql .= " LIMIT " . intval( $limit );
1439
1440 return WPF()->db->get_col( $sql );
1441 }
1442 }
1443
1444 return [];
1445 }
1446
1447 public function ban( $userid ) {
1448 if( $userid == WPF()->current_userid ) {
1449 WPF()->notice->add( 'You can\'t make yourself banned user', 'error' );
1450
1451 return false;
1452 }
1453 if( ! WPF()->usergroup->can( 'bm' ) || ! WPF()->perm->user_can_manage_user( WPF()->current_userid, intval( $userid ) ) ) {
1454 WPF()->notice->add( 'Permission denied for this action', 'error' );
1455
1456 return false;
1457 }
1458 if( false !== WPF()->db->update( WPF()->tables->profiles, [ 'status' => 'banned' ], [ 'userid' => intval( $userid ) ], [ '%s' ], [ '%d' ] ) ) {
1459 do_action( 'wpforo_after_ban_user', $userid );
1460 $this->reset( $userid );
1461 WPF()->notice->add( 'User successfully banned from wpforo', 'success' );
1462
1463 return true;
1464 }
1465
1466 WPF()->notice->add( 'User ban action error', 'error' );
1467
1468 return false;
1469 }
1470
1471 public function unban( $userid ) {
1472 if( ! WPF()->usergroup->can( 'bm' ) || ! WPF()->perm->user_can_manage_user( WPF()->current_userid, intval( $userid ) ) ) {
1473 WPF()->notice->add( 'Permission denied for this action', 'error' );
1474
1475 return false;
1476 }
1477 if( false !== WPF()->db->update( WPF()->tables->profiles, [ 'status' => 'active' ], [ 'userid' => intval( $userid ) ], [ '%s' ], [ '%d' ] ) ) {
1478 do_action( 'wpforo_after_unban_user', $userid );
1479 $this->reset( $userid );
1480 WPF()->notice->add( 'User successfully unbanned from wpforo', 'success' );
1481
1482 return true;
1483 }
1484
1485 WPF()->notice->add( 'User unban action error', 'error' );
1486
1487 return false;
1488 }
1489
1490 public function activate( $userid ) {
1491 if( false !== WPF()->db->update( WPF()->tables->profiles, [ 'status' => 'active' ], [ 'userid' => intval( $userid ) ], [ '%s' ], [ '%d' ] ) ) {
1492 do_action( 'wpforo_after_activate_user', $userid );
1493 $this->reset( $userid );
1494 WPF()->notice->add( 'User successfully activated from wpforo', 'success' );
1495 return true;
1496 }
1497
1498 WPF()->notice->add( 'User activate action error', 'error' );
1499 return false;
1500 }
1501
1502 public function deactivate( $userid ) {
1503 if( false !== WPF()->db->update( WPF()->tables->profiles, [ 'status' => 'inactive' ], [ 'userid' => intval( $userid ) ], [ '%s' ], [ '%d' ] ) ) {
1504 do_action( 'wpforo_after_deactivate_user', $userid );
1505 $this->reset( $userid );
1506 WPF()->notice->add( 'User successfully deactivated from wpforo', 'success' );
1507 return true;
1508 }
1509
1510 WPF()->notice->add( 'User deactivate action error', 'error' );
1511 return false;
1512 }
1513
1514 /**
1515 *
1516 * @param int $userid
1517 * @param int $reassign
1518 *
1519 * @return bool true | false if user successfully deleted
1520 */
1521 public function delete( $userid, $reassign = null ) {
1522 if( ! ( $userid = wpforo_bigintval( $userid ) ) ) return false;
1523 do_action( 'wpforo_before_delete_user', $userid, $reassign );
1524
1525 if( false !== WPF()->db->delete( WPF()->tables->profiles, [ 'userid' => $userid ], [ '%d' ] ) ) {
1526 do_action( 'wpforo_after_delete_user', $userid, $reassign );
1527
1528 WPF()->notice->add( 'User successfully deleted', 'success' );
1529 return true;
1530 }
1531
1532 WPF()->notice->add( 'User delete error', 'error' );
1533 return false;
1534 }
1535
1536 /**
1537 * @deprecated since 2.1.6 version instead of this use $this->_get_avatar() method
1538 */
1539 public function _avatar( $user, $attr = '', $size = 96 ) {
1540 return $this->_get_avatar( $user, $size, $attr );
1541 }
1542
1543 /**
1544 * @deprecated since 2.1.6 version instead of this use $this->get_avatar() method
1545 */
1546 public function avatar( $user, $attr = '', $size = 96 ) {
1547 return wpforo_ram_get( [ $this, '_avatar' ], $user, $attr, $size );
1548 }
1549
1550 public function _get_avatar( $user, $size = 96, $attr = '' ) {
1551 return $this->get_avatar_html( $this->get_avatar_url( $user ), $user, $size, $attr );
1552 }
1553
1554 public function get_avatar( $user, $size = 96, $attr = '' ) {
1555 return wpforo_ram_get( [ $this, '_get_avatar' ], $user, $size, $attr );
1556 }
1557
1558 public function _get_avatar_url( $user ) {
1559 $cache = WPF()->cache->on( 'avatar' );
1560
1561 if ( is_scalar( $user ) ) {
1562 $userid = wpforo_bigintval( $user );
1563 $cache_avatar = apply_filters( 'wpforo_avatar_cache', true, $userid );
1564 if ( $cache && $cache_avatar && $avatar_url = WPF()->cache->get_item( $userid, 'avatar' ) ) {
1565 return str_replace( '#', '', (string) $avatar_url );
1566 }
1567 $avatar_url = (string) WPF()->db->get_var( WPF()->db->prepare( "SELECT `avatar` FROM `" . WPF()->tables->profiles . "` WHERE `userid` = %d", wpforo_bigintval( $userid ) ) );
1568 } else {
1569 $avatar_url = (string) wpfval( $user, 'avatar' );
1570 $userid = wpforo_bigintval( wpfval( $user, 'userid' ) );
1571 }
1572
1573 if ( $cache && $userid ) {
1574 WPF()->cache->create( 'item', [ $userid => $avatar_url ?: '#' ], 'avatar' );
1575 }
1576
1577 return apply_filters( 'wpforo_avatar_url', $avatar_url, $userid );
1578 }
1579
1580 public function get_avatar_url( $user ) {
1581 return wpforo_ram_get( [ $this, '_get_avatar_url' ], $user );
1582 }
1583
1584 public function get_avatar_html( $url, $user = [], $size = 96, $attr = '' ) {
1585 $size = intval( $size );
1586 if( $url && wpforo_setting( 'profiles', 'custom_avatars' ) ) {
1587 $url = apply_filters( 'wpforo_avatar_url', $url, $user );
1588 $dname = ! is_scalar( $user ) ? wpforo_user_dname( $user ) : $this->get_member( $user )['dname'];
1589 if( strpos( (string) $attr, 'alt=' ) === false ) $attr .= ' ' . sprintf('alt="%1$s"', esc_attr( $dname ));
1590 if( strpos( (string) $attr, 'title=' ) === false ) $attr .= ' ' . sprintf('title="%1$s"', esc_attr( $dname ));
1591 if( strpos( (string) $attr, 'height=' ) === false ) $attr .= ' ' . sprintf('height="%1$d"', $size);
1592 if( strpos( (string) $attr, 'width=' ) === false ) $attr .= ' ' . sprintf('width="%1$d"', $size);
1593 $img = '<img class="avatar" src="' . esc_url( (string) $url ) . '" ' . $attr . ' >';
1594 } else {
1595 $userid = is_scalar( $user ) ? wpforo_bigintval( $user ) : (wpforo_bigintval( wpfval( $user, 'userid' ) ) ?: (string) wpfval( $user, 'user_email' ));
1596 $img = get_avatar( $userid, $size );
1597 if( $attr ) $img = str_replace( '<img', '<img ' . $attr, $img );
1598 }
1599
1600 return $img;
1601 }
1602
1603 /**
1604 * @param array|int|string $arg
1605 * @param string $template
1606 *
1607 * @return string
1608 */
1609 public function get_profile_url( $arg, $template = 'profile', $ram_cache = true ) {
1610 $user = is_scalar( $arg ) ? ( $ram_cache ? $this->get_member( intval( basename( (string) $arg ) ) ) : $this->_get_member( intval( basename( (string) $arg ) ) ) ) ?: [ 'user_nicename' => basename( (string) $arg ) ] : $arg;
1611 if( wpfkey( $user, 'userid' ) && wpfkey( $user, 'user_nicename' ) ){
1612 $user_slug = ( wpforo_setting( 'profiles', 'url_structure' ) === 'id' ? $user['userid'] : $user['user_nicename'] );
1613 if( $template === 'profile' ){
1614 $profile_url = wpforo_url( $user_slug, 'member' );
1615 }else{
1616 $template_slug = wpforo_settings_get_slug( $template );
1617 $profile_url = wpforo_url( "$user_slug/$template_slug", 'member' );
1618 }
1619 }else{
1620 $profile_url = wpforo_home_url();
1621 }
1622
1623 return apply_filters( 'wpforo_member_profile_url', $profile_url, $user, $template );
1624 }
1625
1626 /**
1627 * @param float $points
1628 *
1629 * @return array
1630 */
1631 public function calc_rating( $points ) {
1632 $rating = $this->default->member['rating'];
1633
1634 $rating['level'] = $this->rating_level( floatval( $points ), false );
1635 $rating['percent'] = $rating['level'] * 10;
1636 $rating['title'] = $this->rating( $rating['level'], 'title' );
1637 $rating['color'] = $this->rating( $rating['level'], 'color' );
1638 $rating['badge'] = $this->rating( $rating['level'], 'icon' );
1639
1640 return $rating;
1641 }
1642
1643 /**
1644 * @param $member
1645 *
1646 * @return float
1647 */
1648 private function calc_points( $member ) {
1649 $topic_points = intval( $member['topics'] ) * wpforo_setting( 'rating', 'topic_points' );
1650 $post_points = intval( $member['posts'] ) * wpforo_setting( 'rating', 'post_points' );
1651 $like_points = intval( wpfval( $member, 'reactions_in', 'up') ) * wpforo_setting( 'rating', 'like_points' );
1652 $dislike_points = intval( wpfval( $member, 'reactions_in', 'down') ) * wpforo_setting( 'rating', 'dislike_points' );
1653
1654 $topic_points = (float) apply_filters( 'wpforo_member_get_points_topic_points', $topic_points, $member );
1655 $post_points = (float) apply_filters( 'wpforo_member_get_points_post_points', $post_points, $member );
1656 $like_points = (float) apply_filters( 'wpforo_member_get_points_like_points', $like_points, $member );
1657 $dislike_points = (float) apply_filters( 'wpforo_member_get_points_dislike_points', $dislike_points, $member );
1658
1659 return $topic_points + $post_points + $like_points + $dislike_points;
1660 }
1661
1662 public function get_count( $args = [] ) {
1663 $sql = "SELECT SQL_NO_CACHE COUNT(*) FROM `" . WPF()->tables->profiles . "` p
1664 INNER JOIN `" . WPF()->db->users . "` u ON u.`ID` = p.`userid` WHERE p.`status` NOT LIKE 'trashed'";
1665 if( $args ) {
1666 $wheres = [];
1667 foreach( $args as $key => $value ) {
1668 if( is_array( $value ) ) {
1669 $wheres[] = "$key IN('" . implode( "','", array_map( 'esc_sql', $value ) ) . "')";
1670 } else {
1671 $wheres[] = "$key = '" . esc_sql( $value ) . "'";
1672 }
1673 }
1674 if( $wheres ) $sql .= " AND " . implode( ' AND ', $wheres );
1675 }
1676
1677 return (int) WPF()->db->get_var( $sql );
1678 }
1679
1680 public function _is_online( $userid, $duration = null ) {
1681 if( ! $duration ) $duration = wpforo_setting( 'profiles', 'online_status_timeout' );
1682 $sql = "SELECT `online_time` FROM `" . WPF()->tables->profiles . "` WHERE `userid` = %d";
1683 $sql = WPF()->db->prepare( $sql, $userid );
1684 $online_time = intval( WPF()->db->get_var( $sql ) );
1685 $current_time = time();
1686
1687 return ( $current_time - $online_time ) < $duration;
1688 }
1689
1690 public function is_online( $userid, $duration = null ) {
1691 return wpforo_ram_get( [ $this, '_is_online' ], $userid, $duration );
1692 }
1693
1694 public function show_online_indicator( $userid, $ico = true ) {
1695 if( $this->is_online( $userid ) ) : ?>
1696
1697 <?php if( $ico ) : ?>
1698 <i class="fas fa-circle wpfsx wpfcl-8" title="<?php wpforo_phrase( 'Online' ) ?>"></i>
1699 <?php else : wpforo_phrase( 'Online' ); endif ?>
1700
1701 <?php else : ?>
1702
1703 <?php if( $ico ) : ?>
1704 <i class="fas fa-circle wpfsx wpfcl-0" title="<?php wpforo_phrase( 'Offline' ) ?>"></i>
1705 <?php else : wpforo_phrase( 'Offline' ); endif ?>
1706
1707 <?php endif;
1708 }
1709
1710 public function online_members_count( $duration = null ) {
1711 if( ! ( $duration = intval( $duration ) ) ) $duration = (int) wpforo_setting( 'profiles', 'online_status_timeout' );
1712 $online_timeframe = time() - $duration;
1713 $key = [ 'member', 'online_members_count', $online_timeframe ];
1714 if( WPF()->ram_cache->exists( $key ) ) return WPF()->ram_cache->get( $key );
1715 $sql = "SELECT COUNT(DISTINCT `userid`, `ip`) AS total FROM `" . WPF()->tables->visits . "` WHERE `time` > %d";
1716 $var = (int) WPF()->db->get_var( WPF()->db->prepare( $sql, $online_timeframe ) );
1717 if( ! $var ) {
1718 $sql = "SELECT COUNT(*) FROM `" . WPF()->tables->profiles . "` WHERE `online_time` > %d";
1719 $var = (int) WPF()->db->get_var( WPF()->db->prepare( $sql, $online_timeframe ) );
1720 }
1721 WPF()->ram_cache->set( $key, $var );
1722
1723 return $var;
1724 }
1725
1726 public function get_online_members( $count = 1, $groupids = [], $duration = null ) {
1727 if( ! $duration ) $duration = wpforo_setting( 'profiles', 'online_status_timeout' );
1728 $current_time = time();
1729 $online_timeframe = $current_time - $duration;
1730 $groupids = array_filter( wpforo_parse_args( $groupids ) );
1731 $args = [
1732 'groupids' => $groupids,
1733 'online_time' => $online_timeframe, // $current_time - $duration
1734 'orderby' => 'userid', // forumid, order, parentid
1735 'row_count' => $count,
1736 'order' => 'ASC', // ASC DESC
1737 ];
1738
1739 return $this->get_members( $args );
1740 }
1741
1742 public function levels() {
1743 $max_rating_levels = (int) apply_filters('wpforo_max_rating_levels', 10);
1744 return range(0, $max_rating_levels);
1745 }
1746
1747 public function rating( $level = null, $var = '' ) {
1748 if( is_null( $level ) ) return wpforo_setting( 'rating', 'levels' );
1749 $_levels = wpforo_setting( 'rating', 'levels' );
1750 if( ! wpfkey( $_levels, $level ) ) $level = 0;
1751 if( ! $var ) return wpforo_setting( 'rating', 'levels', $level );
1752
1753 return wpforo_setting( 'rating', 'levels', $level, $var );
1754 }
1755
1756 /**
1757 * @param int $points
1758 * @param bool $percent
1759 *
1760 * @return int
1761 */
1762 public function rating_level($points, $percent = true) {
1763 $points = intval($points);
1764 $max_rating_levels = (int) apply_filters('wpforo_max_rating_levels', 10);
1765 $increment = 100 / $max_rating_levels;
1766 for ($level = 1; $level <= $max_rating_levels; $level++) {
1767 if ( $points < $this->rating($level, 'points') ) {
1768 $bar = ( $level - 1 ) * $increment;
1769 break;
1770 }
1771 }
1772 // If the points are greater than or equal to the highest level's points, set $bar to 100
1773 if ( !isset( $bar ) ) $bar = 100;
1774 return $percent ? $bar : (int)floor($bar / (100 / $max_rating_levels) );
1775 }
1776
1777
1778
1779 public function rating_badge( $level = 0, $view = 'short' ) {
1780
1781 $max_rating_levels = (int) apply_filters('wpforo_max_rating_levels', 10);
1782 $level = ( $level > $max_rating_levels ) ? floor( $level / $max_rating_levels ) : $level;
1783
1784 if( $level === 0 ) {
1785 return '<i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1786 } elseif( $level > 0 && $level < 6 ) {
1787 if( $view == 'full' ) {
1788 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', $level );
1789 } else {
1790 return '<span>' . esc_html( $level ) . '</span> <i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1791 }
1792 } elseif( $level > 5 && $level < 9 ) {
1793 if( $view == 'full' ) {
1794 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', ( $level - 5 ) );
1795 } else {
1796 return '<span>' . esc_html( $level - 5 ) . '</span> <i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1797 }
1798 }
1799
1800 if( $max_rating_levels > 10 ){
1801 if( $level < 12 ) {
1802 if( $view == 'full' ) {
1803 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', ( $level - 8 ) );
1804 } else {
1805 return '<span>' . esc_html( $level - 8 ) . '</span> <i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1806 }
1807 } elseif( $level < 15 ) {
1808 if( $view == 'full' ) {
1809 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', ( $level - 11 ) );
1810 } else {
1811 return '<span>' . esc_html( $level - 11 ) . '</span> <i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1812 }
1813 }
1814 } else {
1815 if( $level > 8 ) {
1816 return '<i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1817 }
1818 }
1819 return '';
1820 }
1821
1822 public function reset( $userid ) {
1823 if( ! $userid ) return;
1824 wpforo_clean_cache( 'avatar', $userid );
1825 delete_user_meta( intval( $userid ), '_wpf_member_obj' );
1826 if( wpforo_setting( 'seo', 'seo_profile' ) ) WPF()->seo->clear_cache();
1827 }
1828
1829 public function clear_db_cache() {
1830 WPF()->db->query( "DELETE FROM `" . WPF()->db->usermeta . "` WHERE `meta_key` = '_wpf_member_obj'" );
1831 }
1832
1833 private function update_online_time( $userid = null ) {
1834 if( ! $userid ) $userid = WPF()->current_userid;
1835 if( ! $userid ) return false;
1836 $current_timestamp = time();
1837 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `online_time` = %d WHERE `userid` = %d";
1838 $sql = WPF()->db->prepare( $sql, $current_timestamp, wpforo_bigintval( $userid ) );
1839 if( false !== WPF()->db->query( $sql ) ) return $current_timestamp;
1840
1841 return false;
1842 }
1843
1844 public function init_current_user() {
1845 WPF()->wp_current_user = $current_user = wp_get_current_user();
1846 if( $current_user->exists() ) {
1847 WPF()->current_userid = $current_user->ID;
1848 WPF()->current_user_login = $current_user->user_login;
1849 WPF()->current_user_email = $current_user->user_email;
1850 WPF()->current_user_display_name = $current_user->display_name;
1851
1852 $user = $this->get_member( $current_user->ID );
1853 if( ! wpfkey( $user, 'groupid' ) ) {
1854 $this->synchronize_user( $current_user->ID );
1855 $user = $this->get_member( $current_user->ID );
1856 }
1857 $user_meta = get_user_meta( $current_user->ID );
1858 WPF()->current_user = $user;
1859 WPF()->current_usermeta = $user_meta;
1860 WPF()->current_user_groupid = WPF()->current_user['groupid'];
1861 WPF()->current_user_secondary_groupids = WPF()->current_user['secondary_groupids'];
1862 WPF()->current_user_groupids = array_unique( array_filter( array_merge( (array) WPF()->current_user_groupid, (array) WPF()->current_user_secondary_groupids ) ) );
1863 WPF()->current_user_status = (string) wpfval($user, 'status');
1864 $this->update_online_time();
1865 } elseif( $guest = $this->get_guest_cookies() ) {
1866 WPF()->current_userid = 0;
1867 WPF()->current_user_login = '';
1868 WPF()->current_user_email = $guest['email'];
1869 WPF()->current_user_display_name = $guest['name'];
1870 WPF()->current_user = $this->get_guest( $guest );
1871 WPF()->current_usermeta = [];
1872 WPF()->current_user_groupid = 4;
1873 WPF()->current_user_groupids = [ 4 ];
1874 WPF()->current_user_secondary_groupids = [];
1875 WPF()->current_user_status = '';
1876 WPF()->current_user_accesses = [];
1877 }
1878
1879 WPF()->usergroup->init_current();
1880
1881 if( function_exists( 'wp_get_session_token' ) && function_exists( 'wp_parse_auth_cookie' ) ) WPF()->session_token = wp_get_session_token();
1882 if( ! WPF()->session_token ) {
1883 $secret_key = defined( 'SECRET_KEY' ) && SECRET_KEY ? SECRET_KEY : 'wpforo';
1884 WPF()->session_token = hash_hmac( 'sha256', md5( (string) wpfval( $_SERVER, 'HTTP_USER_AGENT' ) ) . md5( (string) wpfval( $_SERVER, 'REMOTE_ADDR' ) ) . md5( (string) wpfval( $_SERVER, 'SERVER_ADDR' ) ), $secret_key );
1885 }
1886
1887 do_action( 'wpforo_after_init_current_user', WPF()->current_user, WPF()->current_usermeta, WPF()->current_user_groupid, WPF()->current_user_secondary_groupids, WPF()->current_user_groupids );
1888 }
1889
1890 public function blog_posts( $userid ) {
1891 if( isset( $userid ) && $userid ) return count_user_posts( $userid );
1892
1893 return 0;
1894 }
1895
1896 public function blog_comments( $userid, $user_email ) {
1897 global $wpdb;
1898 if( ! $userid || ! $user_email ) return 0;
1899
1900 return (int) $wpdb->get_var( "SELECT COUNT(*) FROM " . $wpdb->comments . " WHERE `user_id` = " . intval( $userid ) . " OR `comment_author_email` = '" . esc_sql( $user_email ) . "'" );
1901 }
1902
1903 public function show_delete_form( $current_user, $userids ) {
1904 if( empty( $current_user ) || empty( $userids ) ) return;
1905
1906 $userids = array_diff( $userids, [ $current_user->ID ] );
1907 $users_have_content = false;
1908 if( WPF()->db->get_var( "SELECT `postid` FROM `" . WPF()->tables->posts . "` WHERE `userid` IN( " . implode( ',', array_map( 'intval', $userids ) ) . " ) LIMIT 1" ) ) {
1909 $users_have_content = true;
1910 }
1911 ?>
1912 <hr/><strong>#wpForo</strong>
1913 <?php if( ! $users_have_content ) : ?>
1914 <input type="hidden" name="wpforo_user_delete_option" value="delete"/>
1915 <?php else: ?>
1916 <?php if( 1 == count( $userids ) ) : ?>
1917 <fieldset>
1918 <legend><?php _e( 'What should be done with wpForo content owned by this user?', 'wpforo' ); ?></legend>
1919 <?php else : ?>
1920 <fieldset>
1921 <legend><?php _e( 'What should be done with wpForo content owned by these users?', 'wpforo' ); ?></legend>
1922 <?php endif; ?>
1923 <ul style="list-style:none;">
1924 <li><label><input type="radio" id="wpforo_delete_option0" name="wpforo_user_delete_option" value="delete">
1925 <?php _e( 'Delete all wpForo content.', 'wpforo' ); ?></label></li>
1926 <li><input type="radio" id="wpforo_delete_option1" name="wpforo_user_delete_option" value="reassign">
1927 <label for="wpforo_delete_option1"><?php _e( 'Attribute all content to:' ) ?></label>
1928 <?php
1929 wp_dropdown_users( [
1930 'name' => 'wpforo_reassign_userid',
1931 'exclude' => $userids,
1932 'show' => 'display_name_with_login',
1933 ] );
1934 ?>
1935 </li>
1936 </ul></fieldset>
1937 <script type="text/javascript">
1938 jQuery(document).ready(function ($) {
1939 $('#wpforo_reassign_userid').on('focus', function () {
1940 $('#wpforo_delete_option1').prop('checked', true).trigger('change')
1941 })
1942 })
1943 </script>
1944 <?php endif;
1945 }
1946
1947 public function autoban( $userid ) {
1948 if( ! WPF()->usergroup->can( 'em' ) ) {
1949 WPF()->db->update( WPF()->tables->profiles, [ 'status' => 'banned' ], [ 'userid' => intval( $userid ) ], [ '%s' ], [ '%d' ] );
1950 }
1951 }
1952
1953 public function member_approved_posts( $member = [] ) {
1954 if( is_numeric( $member ) ) {
1955 if( $userid = wpforo_bigintval( $member ) ) {
1956 if( $userid === WPF()->current_userid ) return WPF()->current_user['posts'];
1957 return (int) WPF()->db->get_var(
1958 WPF()->db->prepare(
1959 "SELECT COUNT(*) as posts
1960 FROM `" . WPF()->tables->posts . "`
1961 WHERE `status` = 0
1962 AND `userid` = %d",
1963 $userid
1964 )
1965 );
1966 }
1967 }
1968
1969 return (int) wpfval( $member, 'posts' );
1970 }
1971
1972 public function current_user_is_new() {
1973 if( WPF()->usergroup->can( 'em' ) ) {
1974 //This is an admin or moderator. The number of posts doesn't matter.
1975 return false;
1976 } else {
1977 $new_user_max_posts = wpforo_setting( 'antispam', 'new_user_max_posts' );
1978 $posts = $this->member_approved_posts( WPF()->current_userid );
1979 if( $new_user_max_posts && $posts <= $new_user_max_posts ) {
1980 return true;
1981 } else {
1982 return false;
1983 }
1984 }
1985 }
1986
1987 /**
1988 * @return int
1989 */
1990 public function banned_count() {
1991 $key = [ 'member', 'banned_count' ];
1992 if( WPF()->ram_cache->exists( $key ) ) return WPF()->ram_cache->get( $key );
1993 $var = (int) WPF()->db->get_var( "SELECT count(*) FROM `" . WPF()->tables->profiles . "` WHERE `status` = 'banned'" );
1994 WPF()->ram_cache->set( $key, $var );
1995
1996 return $var;
1997 }
1998
1999 public function _get_guest_posts( $email ) {
2000 $sqls = [];
2001 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
2002 $sqls[] = WPF()->db->prepare(
2003 "SELECT *
2004 FROM `$table`
2005 WHERE `status` = 0
2006 AND `email` = %s",
2007 $email
2008 );
2009 }
2010
2011 if( $sqls ){
2012 return (array) WPF()->db->get_results(
2013 implode( ' UNION ALL ', $sqls ) . " ORDER BY `created` ASC, `postid` ASC",
2014 ARRAY_A
2015 );
2016 }
2017
2018 return [];
2019 }
2020
2021 public function get_guest_posts( $email ) {
2022 return wpforo_ram_get( [ $this, '_get_guest_posts' ], $email );
2023 }
2024
2025 public function _get_guest( $args = [] ) {
2026 if( !wpfval( $args, 'name' ) ) $args['name'] = wpforo_phrase( 'Anonymous', false );
2027 if( !wpfval( $args, 'email' ) ) $args['email'] = 'anonymous@example.com';
2028
2029 $args['name'] = strip_tags( (string) $args['name'] );
2030 $args['email'] = sanitize_email( $args['email'] );
2031 $args['user_registered'] = current_time( 'mysql', 1 );
2032 $args['posts'] = 0;
2033
2034 if( $args['email'] && $args['email'] !== 'anonymous@example.com' ) {
2035 if( $posts = $this->get_guest_posts( $args['email'] ) ) {
2036 $args['posts'] = count( $posts );
2037 if( $first_post_created = wpfval( $posts, 0, 'created' ) ) $args['user_registered'] = $first_post_created;
2038 }
2039 }
2040
2041 $guest = wpforo_array_args_cast_and_merge(
2042 [
2043 'groupid' => 4,
2044 'group_name' => wpforo_phrase( 'Guest', false ),
2045 'user_login' => $args['name'],
2046 'user_nicename' => sanitize_text_field( $args['name'] ),
2047 'user_email' => $args['email'],
2048 'user_registered' => $args['user_registered'],
2049 'display_name' => $args['name'],
2050 'posts' => $args['posts'],
2051 'status' => 'active',
2052 ],
2053 $this->default->member
2054 );
2055
2056 return $this->decode( $guest );
2057 }
2058
2059 public function get_guest( $args = [] ) {
2060 return wpforo_ram_get( [ $this, '_get_guest' ], $args );
2061 }
2062
2063 public function init_fields() {
2064 if( ! empty( $this->fields ) ) return;
2065
2066 $this->init_countries();
2067 $this->init_timezones();
2068
2069 $this->fields = apply_filters( 'wpforo_member_before_init_fields', $this->fields );
2070
2071 $usergroupids = [];
2072 $usergroups = WPF()->usergroup->get_usergroups();
2073 foreach( $usergroups as $usergroup ) {
2074 $usergroupids[] = $usergroup['groupid'];
2075 }
2076 $usergroupids_can_edit_fields = WPF()->usergroup->get_groupids_by_can( 'em' );
2077 $usergroupids_can_view_social_net = WPF()->usergroup->get_groupids_by_can( 'vmsn' );
2078
2079 /**
2080 * start init tinymce settings
2081 */
2082 $wp_editor_settings = WPF()->tpl->editor_buttons();
2083 $wp_editor_settings['tinymce']['toolbar1'] = 'bold,italic,link,unlink,undo,redo,source_code,emoticons';
2084 $wp_editor_settings['plugins'] = '';
2085 unset(
2086 $wp_editor_settings['external_plugins']['wpforo_pre_button'], $wp_editor_settings['external_plugins']['wpforo_spoiler_button']
2087 );
2088 $wp_editor_settings = apply_filters( 'wpforo_members_init_fields_tinymce_settings', $wp_editor_settings );
2089
2090 $this->fields['user_login'] = [
2091 'fieldKey' => 'user_login',
2092 'type' => 'text',
2093 'isDefault' => 1,
2094 'isRemovable' => 0,
2095 'isRequired' => 1,
2096 'isEditable' => 0,
2097 'label' => wpforo_phrase( 'Username', false ),
2098 'title' => wpforo_phrase( 'Username', false ),
2099 'placeholder' => wpforo_phrase( 'Username', false ),
2100 'description' => wpforo_phrase( 'Length must be between 3 characters and 15 characters.', false ),
2101 'minLength' => 3,
2102 'maxLength' => 30,
2103 'faIcon' => 'fas fa-user',
2104 'name' => 'user_login',
2105 'cantBeInactive' => [ 'register' ],
2106 'canEdit' => [],
2107 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmu' ),
2108 'can' => 'vmu',
2109 'isSearchable' => 0,
2110 ];
2111
2112 $this->fields['user_email'] = [
2113 'fieldKey' => 'user_email',
2114 'type' => 'email',
2115 'isDefault' => 1,
2116 'isRemovable' => 0,
2117 'isRequired' => 1,
2118 'isEditable' => 1,
2119 'label' => wpforo_phrase( 'Email', false ),
2120 'title' => wpforo_phrase( 'Email', false ),
2121 'placeholder' => wpforo_phrase( 'Email', false ),
2122 'minLength' => 0,
2123 'maxLength' => 0,
2124 'faIcon' => 'fas fa-envelope',
2125 'name' => 'user_email',
2126 'cantBeInactive' => [ 'register' ],
2127 'canEdit' => $usergroupids_can_edit_fields,
2128 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmm' ),
2129 'can' => 'vmm',
2130 'isSearchable' => 1,
2131 ];
2132
2133 $this->fields['user_pass'] = [
2134 'fieldKey' => 'user_pass',
2135 'type' => 'password',
2136 'isDefault' => 1,
2137 'isRemovable' => 0,
2138 'isRequired' => 1,
2139 'isEditable' => 1,
2140 'label' => wpforo_phrase( 'Password', false ),
2141 'title' => wpforo_phrase( 'Password', false ),
2142 'placeholder' => wpforo_phrase( 'Password', false ),
2143 'description' => wpforo_phrase( 'Must be minimum 6 characters.', false ),
2144 'minLength' => 6,
2145 'maxLength' => 20,
2146 'faIcon' => 'fas fa-key',
2147 'name' => 'user_pass',
2148 'cantBeInactive' => [
2149 'account',
2150 'register',
2151 ],
2152 'canEdit' => $usergroupids_can_edit_fields,
2153 'canView' => [],
2154 'can' => '',
2155 'isSearchable' => 0,
2156 ];
2157
2158 $this->fields['display_name'] = [
2159 'fieldKey' => 'display_name',
2160 'type' => 'text',
2161 'isDefault' => 1,
2162 'isRemovable' => 0,
2163 'isRequired' => 1,
2164 'isEditable' => 1,
2165 'label' => wpforo_phrase( 'Display Name', false ),
2166 'title' => wpforo_phrase( 'Display Name', false ),
2167 'placeholder' => wpforo_phrase( 'Display Name', false ),
2168 'faIcon' => 'fas fa-user',
2169 'name' => 'display_name',
2170 'cantBeInactive' => [],
2171 'canEdit' => $usergroupids_can_edit_fields,
2172 'canView' => $usergroupids,
2173 'can' => '',
2174 'isSearchable' => 1,
2175 ];
2176
2177 $this->fields['user_nicename'] = [
2178 'fieldKey' => 'user_nicename',
2179 'type' => 'text',
2180 'isDefault' => 1,
2181 'isRemovable' => 0,
2182 'isRequired' => 1,
2183 'isEditable' => 1,
2184 'label' => wpforo_phrase( 'Nickname', false ),
2185 'title' => wpforo_phrase( 'Nickname', false ),
2186 'placeholder' => wpforo_phrase( 'Nickname', false ),
2187 'description' => wpforo_phrase( 'URL Address Identifier', false ),
2188 'minLength' => 0,
2189 'maxLength' => 0,
2190 'faIcon' => 'fas fa-link',
2191 'name' => 'user_nicename',
2192 'cantBeInactive' => [],
2193 'canEdit' => $usergroupids_can_edit_fields,
2194 'canView' => $usergroupids,
2195 'can' => '',
2196 'isSearchable' => 1,
2197 ];
2198
2199 $this->fields['first_name'] = [
2200 'fieldKey' => 'first_name',
2201 'type' => 'text',
2202 'isDefault' => 1,
2203 'isRemovable' => 0,
2204 'isRequired' => 0,
2205 'isEditable' => 1,
2206 'label' => wpforo_phrase( 'First Name', false ),
2207 'title' => wpforo_phrase( 'First Name', false ),
2208 'placeholder' => wpforo_phrase( 'First Name', false ),
2209 'faIcon' => 'fas fa-address-card',
2210 'name' => 'first_name',
2211 'cantBeInactive' => [],
2212 'canEdit' => $usergroupids_can_edit_fields,
2213 'canView' => $usergroupids,
2214 'can' => '',
2215 'isSearchable' => 0,
2216 ];
2217
2218 $this->fields['last_name'] = [
2219 'fieldKey' => 'last_name',
2220 'type' => 'text',
2221 'isDefault' => 1,
2222 'isRemovable' => 0,
2223 'isRequired' => 0,
2224 'isEditable' => 1,
2225 'label' => wpforo_phrase( 'Last Name', false ),
2226 'title' => wpforo_phrase( 'Last Name', false ),
2227 'placeholder' => wpforo_phrase( 'Last Name', false ),
2228 'faIcon' => 'fas fa-address-card',
2229 'name' => 'last_name',
2230 'cantBeInactive' => [],
2231 'canEdit' => $usergroupids_can_edit_fields,
2232 'canView' => $usergroupids,
2233 'can' => '',
2234 'isSearchable' => 0,
2235 ];
2236
2237 $this->fields['title'] = [
2238 'fieldKey' => 'title',
2239 'type' => 'text',
2240 'isDefault' => 1,
2241 'isRemovable' => 0,
2242 'isRequired' => 1,
2243 'isEditable' => 1,
2244 'label' => wpforo_phrase( 'Title', false ),
2245 'title' => wpforo_phrase( 'Title', false ),
2246 'placeholder' => wpforo_phrase( 'Title', false ),
2247 'minLength' => 0,
2248 'maxLength' => 0,
2249 'faIcon' => 'fas fa-user',
2250 'name' => 'title',
2251 'cantBeInactive' => [],
2252 'canEdit' => $usergroupids_can_edit_fields,
2253 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmt' ),
2254 'can' => 'vmt',
2255 'isSearchable' => 1,
2256 ];
2257
2258 $this->fields['groupid'] = [
2259 'fieldKey' => 'groupid',
2260 'type' => 'usergroup',
2261 'isDefault' => 1,
2262 'isRemovable' => 0,
2263 'isRequired' => 1,
2264 'isEditable' => 1,
2265 'label' => wpforo_phrase( 'User Group', false ),
2266 'title' => wpforo_phrase( 'User Group', false ),
2267 'placeholder' => wpforo_phrase( 'User Group', false ),
2268 'faIcon' => 'fas fa-users',
2269 'name' => 'groupid',
2270 'allowedGroupIds' => [ 3, 5 ],
2271 'cantBeInactive' => [],
2272 'canEdit' => $usergroupids_can_edit_fields,
2273 'canView' => $usergroupids,
2274 'can' => '',
2275 'isSearchable' => 1,
2276 ];
2277
2278 $this->fields['secondary_groupids'] = [
2279 'fieldKey' => 'secondary_groupids',
2280 'type' => 'secondary_groups',
2281 'isWrapItem' => 1,
2282 'isDefault' => 1,
2283 'isRemovable' => 0,
2284 'isRequired' => 0,
2285 'isEditable' => 1,
2286 'label' => wpforo_phrase( 'User Groups Secondary', false ),
2287 'title' => wpforo_phrase( 'User Groups Secondary', false ),
2288 'placeholder' => '',
2289 'faIcon' => '',
2290 'values' => '',
2291 'name' => 'secondary_groupids',
2292 'allowedGroupIds' => WPF()->usergroup->get_secondary_groupids(),
2293 'cantBeInactive' => [],
2294 'canEdit' => $usergroupids_can_edit_fields,
2295 'canView' => $usergroupids,
2296 'can' => '',
2297 'isSearchable' => 1,
2298 ];
2299
2300 $this->fields['avatar'] = [
2301 'fieldKey' => 'avatar',
2302 'type' => 'avatar',
2303 'isDefault' => 1,
2304 'isRemovable' => 0,
2305 'isRequired' => 0,
2306 'isEditable' => 1,
2307 'label' => wpforo_phrase( 'Avatar', false ),
2308 'title' => wpforo_phrase( 'Avatar', false ),
2309 'placeholder' => wpforo_phrase( 'Avatar', false ),
2310 'name' => 'avatar',
2311 'cantBeInactive' => [],
2312 'canEdit' => $usergroupids_can_edit_fields,
2313 'canView' => WPF()->usergroup->get_groupids_by_can( 'va' ),
2314 'can' => 'va',
2315 'isSearchable' => 0,
2316 ];
2317
2318 $this->fields['user_url'] = [
2319 'fieldKey' => 'user_url',
2320 'type' => 'url',
2321 'isDefault' => 1,
2322 'isRemovable' => 0,
2323 'isRequired' => 0,
2324 'isEditable' => 1,
2325 'label' => wpforo_phrase( 'Website', false ),
2326 'title' => wpforo_phrase( 'Website', false ),
2327 'placeholder' => wpforo_phrase( 'Website', false ),
2328 'faIcon' => 'fas fa-sitemap',
2329 'name' => 'user_url',
2330 'cantBeInactive' => [],
2331 'canEdit' => $usergroupids_can_edit_fields,
2332 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmw' ),
2333 'can' => 'vmw',
2334 'isSearchable' => 1,
2335 ];
2336
2337 $this->fields['facebook'] = [
2338 'fieldKey' => 'facebook',
2339 'type' => 'url',
2340 'isDefault' => 0,
2341 'isRemovable' => 1,
2342 'isRequired' => 0,
2343 'isEditable' => 1,
2344 'label' => wpforo_phrase( 'Facebook', false ),
2345 'title' => wpforo_phrase( 'Facebook', false ),
2346 'placeholder' => wpforo_phrase( 'Facebook', false ),
2347 'faIcon' => 'fab fa-facebook',
2348 'name' => 'facebook',
2349 'cantBeInactive' => [],
2350 'canEdit' => $usergroupids_can_edit_fields,
2351 'canView' => $usergroupids_can_view_social_net,
2352 'can' => 'vmsn',
2353 'isSearchable' => 1,
2354 ];
2355
2356 $this->fields['twitter'] = [
2357 'fieldKey' => 'twitter',
2358 'type' => 'url',
2359 'isDefault' => 0,
2360 'isRemovable' => 1,
2361 'isRequired' => 0,
2362 'isEditable' => 1,
2363 'label' => wpforo_phrase( 'X.com', false ),
2364 'title' => wpforo_phrase( 'X.com', false ),
2365 'placeholder' => wpforo_phrase( 'X.com', false ),
2366 'faIcon' => 'fa-brands fa-square-x-twitter',
2367 'name' => 'twitter',
2368 'cantBeInactive' => [],
2369 'canEdit' => $usergroupids_can_edit_fields,
2370 'canView' => $usergroupids_can_view_social_net,
2371 'can' => 'vmsn',
2372 'isSearchable' => 1,
2373 ];
2374
2375 $this->fields['youtube'] = [
2376 'fieldKey' => 'youtube',
2377 'type' => 'url',
2378 'isDefault' => 0,
2379 'isRemovable' => 1,
2380 'isRequired' => 0,
2381 'isEditable' => 1,
2382 'label' => wpforo_phrase( 'YouTube', false ),
2383 'title' => wpforo_phrase( 'YouTube', false ),
2384 'placeholder' => wpforo_phrase( 'YouTube', false ),
2385 'faIcon' => 'fab fa-youtube',
2386 'name' => 'youtube',
2387 'cantBeInactive' => [],
2388 'canEdit' => $usergroupids_can_edit_fields,
2389 'canView' => $usergroupids_can_view_social_net,
2390 'can' => 'vmsn',
2391 'isSearchable' => 1,
2392 ];
2393
2394 $this->fields['vkontakte'] = [
2395 'fieldKey' => 'vkontakte',
2396 'type' => 'url',
2397 'isDefault' => 0,
2398 'isRemovable' => 1,
2399 'isRequired' => 0,
2400 'isEditable' => 1,
2401 'label' => wpforo_phrase( 'VKontakte', false ),
2402 'title' => wpforo_phrase( 'VKontakte', false ),
2403 'placeholder' => wpforo_phrase( 'VKontakte', false ),
2404 'faIcon' => 'fab fa-vk',
2405 'name' => 'vkontakte',
2406 'cantBeInactive' => [],
2407 'canEdit' => $usergroupids_can_edit_fields,
2408 'canView' => $usergroupids_can_view_social_net,
2409 'can' => 'vmsn',
2410 'isSearchable' => 1,
2411 ];
2412
2413 $this->fields['linkedin'] = [
2414 'fieldKey' => 'linkedin',
2415 'type' => 'url',
2416 'isDefault' => 0,
2417 'isRemovable' => 1,
2418 'isRequired' => 0,
2419 'isEditable' => 1,
2420 'label' => wpforo_phrase( 'LinkedIn', false ),
2421 'title' => wpforo_phrase( 'LinkedIn', false ),
2422 'placeholder' => wpforo_phrase( 'LinkedIn', false ),
2423 'faIcon' => 'fab fa-linkedin-in',
2424 'name' => 'linkedin',
2425 'cantBeInactive' => [],
2426 'canEdit' => $usergroupids_can_edit_fields,
2427 'canView' => $usergroupids_can_view_social_net,
2428 'can' => 'vmsn',
2429 'isSearchable' => 1,
2430 ];
2431
2432 $this->fields['telegram'] = [
2433 'fieldKey' => 'telegram',
2434 'type' => 'text',
2435 'isDefault' => 0,
2436 'isRemovable' => 1,
2437 'isRequired' => 0,
2438 'isEditable' => 1,
2439 'label' => wpforo_phrase( 'Telegram', false ),
2440 'title' => wpforo_phrase( 'Telegram', false ),
2441 'placeholder' => wpforo_phrase( 'Telegram', false ),
2442 'faIcon' => 'fab fa-telegram-plane',
2443 'name' => 'telegram',
2444 'cantBeInactive' => [],
2445 'canEdit' => $usergroupids_can_edit_fields,
2446 'canView' => $usergroupids_can_view_social_net,
2447 'can' => 'vmsn',
2448 'isSearchable' => 1,
2449 ];
2450
2451 $this->fields['instagram'] = [
2452 'fieldKey' => 'instagram',
2453 'type' => 'url',
2454 'isDefault' => 0,
2455 'isRemovable' => 1,
2456 'isRequired' => 0,
2457 'isEditable' => 1,
2458 'label' => wpforo_phrase( 'Instagram', false ),
2459 'title' => wpforo_phrase( 'Instagram', false ),
2460 'placeholder' => wpforo_phrase( 'Instagram', false ),
2461 'faIcon' => 'fab fa-instagram',
2462 'name' => 'instagram',
2463 'cantBeInactive' => [],
2464 'canEdit' => $usergroupids_can_edit_fields,
2465 'canView' => $usergroupids_can_view_social_net,
2466 'can' => 'vmsn',
2467 'isSearchable' => 1,
2468 ];
2469
2470 $this->fields['skype'] = [
2471 'fieldKey' => 'skype',
2472 'type' => 'text',
2473 'isDefault' => 0,
2474 'isRemovable' => 1,
2475 'isRequired' => 0,
2476 'isEditable' => 1,
2477 'label' => wpforo_phrase( 'Skype', false ),
2478 'title' => wpforo_phrase( 'Skype', false ),
2479 'placeholder' => wpforo_phrase( 'Skype', false ),
2480 'faIcon' => 'fab fa-skype',
2481 'name' => 'skype',
2482 'cantBeInactive' => [],
2483 'canEdit' => $usergroupids_can_edit_fields,
2484 'canView' => $usergroupids_can_view_social_net,
2485 'can' => 'vmsn',
2486 'isSearchable' => 1,
2487 ];
2488
2489 $this->fields['location'] = [
2490 'fieldKey' => 'location',
2491 'type' => 'select',
2492 'isDefault' => 1,
2493 'isRemovable' => 0,
2494 'isRequired' => 0,
2495 'isEditable' => 1,
2496 'label' => wpforo_phrase( 'Location', false ),
2497 'title' => wpforo_phrase( 'Location', false ),
2498 'placeholder' => wpforo_phrase( 'Location', false ),
2499 'faIcon' => 'fas fa-globe',
2500 'values' => $this->countries,
2501 'name' => 'location',
2502 'cantBeInactive' => [],
2503 'canEdit' => $usergroupids_can_edit_fields,
2504 'canView' => WPF()->usergroup->get_groupids_by_can( 'vml' ),
2505 'can' => 'vml',
2506 'isSearchable' => 1,
2507 ];
2508
2509 $this->fields['timezone'] = [
2510 'fieldKey' => 'timezone',
2511 'type' => 'select',
2512 'isDefault' => 1,
2513 'isRemovable' => 0,
2514 'isRequired' => 0,
2515 'isEditable' => 1,
2516 'label' => wpforo_phrase( 'Timezone', false ),
2517 'title' => wpforo_phrase( 'Timezone', false ),
2518 'placeholder' => wpforo_phrase( 'Timezone', false ),
2519 'faIcon' => 'fas fa-globe',
2520 'values' => $this->timezones,
2521 'name' => 'timezone',
2522 'cantBeInactive' => [],
2523 'canEdit' => $usergroupids_can_edit_fields,
2524 'canView' => $usergroupids,
2525 'can' => '',
2526 'isSearchable' => 1,
2527 ];
2528
2529 $this->fields['occupation'] = [
2530 'fieldKey' => 'occupation',
2531 'type' => 'text',
2532 'isDefault' => 1,
2533 'isRemovable' => 0,
2534 'isRequired' => 0,
2535 'isEditable' => 1,
2536 'label' => wpforo_phrase( 'Occupation', false ),
2537 'title' => wpforo_phrase( 'Occupation', false ),
2538 'placeholder' => wpforo_phrase( 'Occupation', false ),
2539 'faIcon' => 'fas fa-address-card',
2540 'name' => 'occupation',
2541 'cantBeInactive' => [],
2542 'canEdit' => $usergroupids_can_edit_fields,
2543 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmo' ),
2544 'can' => 'vmo',
2545 'isSearchable' => 1,
2546 ];
2547
2548 $this->fields['signature'] = [
2549 'fieldKey' => 'signature',
2550 'type' => 'tinymce',
2551 'wp_editor_settings' => $wp_editor_settings,
2552 'isDefault' => 1,
2553 'isRemovable' => 0,
2554 'isRequired' => 0,
2555 'isEditable' => 1,
2556 'label' => wpforo_phrase( 'Signature', false ),
2557 'title' => wpforo_phrase( 'Signature', false ),
2558 'placeholder' => wpforo_phrase( 'Signature', false ),
2559 'faIcon' => 'fas fa-address-card',
2560 'name' => 'signature',
2561 'cantBeInactive' => [],
2562 'canEdit' => $usergroupids_can_edit_fields,
2563 'canView' => WPF()->usergroup->get_groupids_by_can( 'vms' ),
2564 'can' => 'vms',
2565 'isSearchable' => 1,
2566 ];
2567
2568 $this->fields['about'] = [
2569 'fieldKey' => 'about',
2570 'type' => 'tinymce',
2571 'wp_editor_settings' => $wp_editor_settings,
2572 'isDefault' => 1,
2573 'isRemovable' => 0,
2574 'isRequired' => 0,
2575 'isEditable' => 1,
2576 'label' => wpforo_phrase( 'About Me', false ),
2577 'title' => wpforo_phrase( 'About Me', false ),
2578 'placeholder' => wpforo_phrase( 'About Me', false ),
2579 'faIcon' => 'fas fa-address-card',
2580 'name' => 'about',
2581 'cantBeInactive' => [],
2582 'canEdit' => $usergroupids_can_edit_fields,
2583 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmam' ),
2584 'can' => 'vmam',
2585 'isSearchable' => 1,
2586 ];
2587
2588 $this->fields['html_soc_net'] = [
2589 'fieldKey' => 'html_soc_net',
2590 'type' => 'html',
2591 'isDefault' => 1,
2592 'isRemovable' => 0,
2593 'isRequired' => 0,
2594 'isEditable' => 1,
2595 'label' => wpforo_phrase( 'Social Networks', false ),
2596 'title' => wpforo_phrase( 'Social Networks', false ),
2597 'placeholder' => wpforo_phrase( 'Social Networks', false ),
2598 'description' => wpforo_phrase( 'Social Networks', false ),
2599 'html' => '<div class="wpf-label">' . wpforo_phrase( 'Social Networks', false ) . '</div>',
2600 'name' => 'html_soc_net',
2601 'cantBeInactive' => [],
2602 'canEdit' => $usergroupids_can_edit_fields,
2603 'canView' => $usergroupids_can_view_social_net,
2604 'can' => 'vmsn',
2605 'isSearchable' => 0,
2606 ];
2607
2608 $this->fields = apply_filters( 'wpforo_member_after_init_fields', $this->fields );
2609 }
2610
2611 private function init_countries() {
2612 $this->countries = [
2613 "Afghanistan",
2614 "�
2615 land Islands",
2616 "Albania",
2617 "Algeria",
2618 "American Samoa",
2619 "Andorra",
2620 "Angola",
2621 "Anguilla",
2622 "Antarctica",
2623 "Antigua and Barbuda",
2624 "Argentina",
2625 "Armenia",
2626 "Aruba",
2627 "Australia",
2628 "Austria",
2629 "Azerbaijan",
2630 "Bahamas",
2631 "Bahrain",
2632 "Bangladesh",
2633 "Barbados",
2634 "Belarus",
2635 "Belgium",
2636 "Belize",
2637 "Benin",
2638 "Bermuda",
2639 "Bhutan",
2640 "Bolivia",
2641 "Bosnia and Herzegovina",
2642 "Botswana",
2643 "Bouvet Island",
2644 "Brazil",
2645 "British Indian Ocean Territory",
2646 "Brunei Darussalam",
2647 "Bulgaria",
2648 "Burkina Faso",
2649 "Burundi",
2650 "Cambodia",
2651 "Cameroon",
2652 "Canada",
2653 "Cape Verde",
2654 "Cayman Islands",
2655 "Central African Republic",
2656 "Chad",
2657 "Chile",
2658 "China",
2659 "Christmas Island",
2660 "Cocos (Keeling) Islands",
2661 "Colombia",
2662 "Comoros",
2663 "Congo",
2664 "Congo, The Democratic Republic of The",
2665 "Cook Islands",
2666 "Costa Rica",
2667 "Cote D'ivoire",
2668 "Croatia",
2669 "Cuba",
2670 "Cyprus",
2671 "Czech Republic",
2672 "Denmark",
2673 "Djibouti",
2674 "Dominica",
2675 "Dominican Republic",
2676 "Ecuador",
2677 "Egypt",
2678 "El Salvador",
2679 "Equatorial Guinea",
2680 "Eritrea",
2681 "Estonia",
2682 "Ethiopia",
2683 "Falkland Islands (Malvinas)",
2684 "Faroe Islands",
2685 "Fiji",
2686 "Finland",
2687 "France",
2688 "French Guiana",
2689 "French Polynesia",
2690 "French Southern Territories",
2691 "Gabon",
2692 "Gambia",
2693 "Georgia",
2694 "Germany",
2695 "Ghana",
2696 "Gibraltar",
2697 "Greece",
2698 "Greenland",
2699 "Grenada",
2700 "Guadeloupe",
2701 "Guam",
2702 "Guatemala",
2703 "Guernsey",
2704 "Guinea",
2705 "Guinea-bissau",
2706 "Guyana",
2707 "Haiti",
2708 "Heard Island and Mcdonald Islands",
2709 "Holy See (Vatican City State)",
2710 "Honduras",
2711 "Hong Kong",
2712 "Hungary",
2713 "Iceland",
2714 "India",
2715 "Indonesia",
2716 "Iran, Islamic Republic of",
2717 "Iraq",
2718 "Ireland",
2719 "Isle of Man",
2720 "Israel",
2721 "Italy",
2722 "Jamaica",
2723 "Japan",
2724 "Jersey",
2725 "Jordan",
2726 "Kazakhstan",
2727 "Kenya",
2728 "Kiribati",
2729 "Korea, Democratic People's Republic of",
2730 "Korea, Republic of",
2731 "Kuwait",
2732 "Kyrgyzstan",
2733 "Lao People's Democratic Republic",
2734 "Latvia",
2735 "Lebanon",
2736 "Lesotho",
2737 "Liberia",
2738 "Libyan Arab Jamahiriya",
2739 "Liechtenstein",
2740 "Lithuania",
2741 "Luxembourg",
2742 "Macao",
2743 "Macedonia, The Former Yugoslav Republic of",
2744 "Madagascar",
2745 "Malawi",
2746 "Malaysia",
2747 "Maldives",
2748 "Mali",
2749 "Malta",
2750 "Marshall Islands",
2751 "Martinique",
2752 "Mauritania",
2753 "Mauritius",
2754 "Mayotte",
2755 "Mexico",
2756 "Micronesia, Federated States of",
2757 "Moldova, Republic of",
2758 "Monaco",
2759 "Mongolia",
2760 "Montenegro",
2761 "Montserrat",
2762 "Morocco",
2763 "Mozambique",
2764 "Myanmar",
2765 "Namibia",
2766 "Nauru",
2767 "Nepal",
2768 "Netherlands",
2769 "Netherlands Antilles",
2770 "New Caledonia",
2771 "New Zealand",
2772 "Nicaragua",
2773 "Niger",
2774 "Nigeria",
2775 "Niue",
2776 "Norfolk Island",
2777 "Northern Mariana Islands",
2778 "Norway",
2779 "Oman",
2780 "Pakistan",
2781 "Palau",
2782 "Palestinian Territory, Occupied",
2783 "Panama",
2784 "Papua New Guinea",
2785 "Paraguay",
2786 "Peru",
2787 "Philippines",
2788 "Pitcairn",
2789 "Poland",
2790 "Portugal",
2791 "Puerto Rico",
2792 "Qatar",
2793 "Reunion",
2794 "Romania",
2795 "Russian Federation",
2796 "Rwanda",
2797 "Saint Helena",
2798 "Saint Kitts and Nevis",
2799 "Saint Lucia",
2800 "Saint Pierre and Miquelon",
2801 "Saint Vincent and The Grenadines",
2802 "Samoa",
2803 "San Marino",
2804 "Sao Tome and Principe",
2805 "Saudi Arabia",
2806 "Senegal",
2807 "Serbia",
2808 "Seychelles",
2809 "Sierra Leone",
2810 "Singapore",
2811 "Slovakia",
2812 "Slovenia",
2813 "Solomon Islands",
2814 "Somalia",
2815 "South Africa",
2816 "South Georgia and The South Sandwich Islands",
2817 "Spain",
2818 "Sri Lanka",
2819 "Sudan",
2820 "Suriname",
2821 "Svalbard and Jan Mayen",
2822 "Swaziland",
2823 "Sweden",
2824 "Switzerland",
2825 "Syrian Arab Republic",
2826 "Taiwan, Province of China",
2827 "Tajikistan",
2828 "Tanzania, United Republic of",
2829 "Thailand",
2830 "Timor-leste",
2831 "Togo",
2832 "Tokelau",
2833 "Tonga",
2834 "Trinidad and Tobago",
2835 "Tunisia",
2836 "Turkey",
2837 "Turkmenistan",
2838 "Turks and Caicos Islands",
2839 "Tuvalu",
2840 "Uganda",
2841 "Ukraine",
2842 "United Arab Emirates",
2843 "United Kingdom",
2844 "United States",
2845 "United States Minor Outlying Islands",
2846 "Uruguay",
2847 "Uzbekistan",
2848 "Vanuatu",
2849 "Venezuela",
2850 "Viet Nam",
2851 "Virgin Islands, British",
2852 "Virgin Islands, U.S.",
2853 "Wallis and Futuna",
2854 "Western Sahara",
2855 "Yemen",
2856 "Zambia",
2857 "Zimbabwe",
2858 ];
2859 }
2860
2861 private function init_timezones() {
2862 $this->timezones = timezone_identifiers_list();
2863 $offset_range = [
2864 - 12,
2865 - 11.5,
2866 - 11,
2867 - 10.5,
2868 - 10,
2869 - 9.5,
2870 - 9,
2871 - 8.5,
2872 - 8,
2873 - 7.5,
2874 - 7,
2875 - 6.5,
2876 - 6,
2877 - 5.5,
2878 - 5,
2879 - 4.5,
2880 - 4,
2881 - 3.5,
2882 - 3,
2883 - 2.5,
2884 - 2,
2885 - 1.5,
2886 - 1,
2887 - 0.5,
2888 0,
2889 0.5,
2890 1,
2891 1.5,
2892 2,
2893 2.5,
2894 3,
2895 3.5,
2896 4,
2897 4.5,
2898 5,
2899 5.5,
2900 5.75,
2901 6,
2902 6.5,
2903 7,
2904 7.5,
2905 8,
2906 8.5,
2907 8.75,
2908 9,
2909 9.5,
2910 10,
2911 10.5,
2912 11,
2913 11.5,
2914 12,
2915 12.75,
2916 13,
2917 13.75,
2918 14,
2919 ];
2920 foreach( $offset_range as $offset ) {
2921 if( 0 <= $offset ) {
2922 $offset_name = '+' . $offset;
2923 } else {
2924 $offset_name = (string) $offset;
2925 }
2926
2927 $offset_value = $offset_name;
2928 $offset_value = 'UTC' . $offset_value;
2929 $this->timezones[] = 'UTC/' . $offset_value;
2930 }
2931
2932 $zones = $this->timezones;
2933 $timezones = [];
2934 foreach( $zones as $zone ) {
2935 if( strpos( (string) $zone, '/' ) === false ) continue;
2936
2937 $zone = str_replace( '_', ' ', $zone );
2938
2939 $group = function_exists( 'mb_substr' ) ? mb_substr( (string) $zone, 0, strpos( (string) $zone, '/' ) ) : substr( (string) $zone, 0, strpos( (string) $zone, '/' ) );
2940 $index = function_exists( 'mb_strlen' ) ? mb_strlen( (string) $group ) + 1 : strlen( (string) $group ) + 1;
2941 $optionValue = substr( (string) $zone, $index );
2942
2943 if( strpos( (string) $optionValue, 'UTC' ) !== false ) {
2944 $optionTitle = str_replace( [ '.25', '.5', '.75', ], [ ':15', ':30', ':45', ], $optionValue );
2945 $optionValue = "$optionValue=>$optionTitle";
2946 } else {
2947 $optionValue = "$zone=>$optionValue";
2948 }
2949
2950 $timezones[ $group ][] = $optionValue;
2951 }
2952
2953 $this->timezones = $timezones;
2954 }
2955
2956 public function get_fields( $only_defaults = false ) {
2957 $this->init_fields();
2958 $fields = $this->fields;
2959 if( $only_defaults ) {
2960 foreach( $fields as $k => $v ) if( ! wpfval( $v, 'isDefault' ) ) unset( $fields[ $k ] );
2961 } else {
2962 $this->fields = $fields = apply_filters( 'wpforo_get_fields', $fields );
2963 }
2964
2965 return $fields;
2966 }
2967
2968 public function get_field( $key ) {
2969 if( is_string( $key ) ) {
2970 $this->init_fields();
2971
2972 return (array) wpfval( $this->fields, $key );
2973 } elseif( $this->is_field( $key ) ) {
2974 return $key;
2975 }
2976
2977 return [];
2978 }
2979
2980 public function is_field( $field ) {
2981 return wpfval( $field, 'fieldKey' ) && wpfval( $field, 'type' ) && wpfkey( $field, 'isDefault' );
2982 }
2983
2984 public function get_field_key( $field ) {
2985 return is_string( $field ) ? $field : (string) wpfval( $field, 'fieldKey' );
2986 }
2987
2988 public function fields_structure_full_array( $fields, $need_password = null ) {
2989 if( is_string( $fields ) ) $fields = maybe_unserialize( $fields );
2990 $fs = [ [ [] ] ];
2991 if( ! is_array( $fields ) ) return $fs;
2992 if( is_null( $need_password ) ) {
2993 foreach( $fields as $kr => $row ) {
2994 if( is_array( $row ) ) {
2995 foreach( $row as $kc => $cols ) {
2996 if( is_array( $cols ) ) {
2997 foreach( $cols as $field ) {
2998 $field_key = $this->get_field_key( $field );
2999 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3000 }
3001 }
3002 }
3003 }
3004 }
3005 } else {
3006 $has_password = false;
3007 foreach( $fields as $kr => $row ) {
3008 if( is_array( $row ) ) {
3009 foreach( $row as $kc => $cols ) {
3010 if( is_array( $cols ) ) {
3011 foreach( $cols as $field ) {
3012 $field_key = $this->get_field_key( $field );
3013 if( $field_key === 'user_pass' ) {
3014 if( $need_password ) {
3015 $has_password = true;
3016 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3017 }
3018 } else {
3019 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3020 }
3021 }
3022 }
3023 }
3024 }
3025 }
3026 if( $need_password && ! $has_password ) $fs[][][] = $this->get_field( 'user_pass' );
3027 }
3028
3029 return $fs;
3030 }
3031
3032 public function get_register_fields_structure( $only_defaults = false ) {
3033 $need_password = ! wpforo_setting( 'authorization', 'user_register_email_confirm' );
3034 $regform = [ 'user_login', 'user_email' ];
3035 if( $need_password ) $regform[] = 'user_pass';
3036 $fields = [ [ $regform ] ];
3037 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_register_fields', $fields );
3038
3039 return $fields;
3040 }
3041
3042 public function get_register_fields( $only_defaults = false ) {
3043 return $this->fields_structure_full_array( $this->get_register_fields_structure( $only_defaults ), ! wpforo_setting( 'authorization', 'user_register_email_confirm' ) );
3044 }
3045
3046 public function get_account_fields_structure( $only_defaults = false ) {
3047 $fields = [
3048 [
3049 [
3050 'user_login',
3051 'display_name',
3052 'user_nicename',
3053 'user_email',
3054 'title',
3055 'groupid',
3056 'avatar',
3057 'about',
3058 'user_url',
3059 'occupation',
3060 'signature',
3061 ],
3062 ],
3063 [
3064 [
3065 'html_soc_net',
3066 ],
3067 [
3068 'facebook',
3069 'linkedin',
3070 'instagram',
3071 'vkontakte',
3072 ],
3073 [
3074 'twitter',
3075 'youtube',
3076 'telegram',
3077 'skype',
3078 ],
3079 ],
3080 [
3081 [
3082 'location',
3083 'timezone',
3084 'user_pass',
3085 ],
3086 ],
3087 ];
3088 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_account_fields', $fields );
3089
3090 return $fields;
3091 }
3092
3093 public function get_account_fields( $only_defaults = false ) {
3094 return $this->fields_structure_full_array( $this->get_account_fields_structure( $only_defaults ) );
3095 }
3096
3097 public function get_profile_fields_structure( $only_defaults = false ) {
3098 $fields = [
3099 [
3100 [
3101 'about',
3102 'user_url',
3103 ],
3104 ],
3105 [
3106 [
3107 'location',
3108 'timezone',
3109 'occupation',
3110 'signature',
3111 ],
3112 ],
3113 [
3114 [
3115 'html_soc_net',
3116 ],
3117 ],
3118 [
3119 [
3120 'facebook',
3121 'linkedin',
3122 'instagram',
3123 'vkontakte',
3124 ],
3125 [
3126 'twitter',
3127 'youtube',
3128 'telegram',
3129 'skype',
3130 ],
3131 ],
3132 ];
3133 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_profile_fields', $fields );
3134
3135 return $fields;
3136 }
3137
3138 public function get_profile_fields( $only_defaults = false ) {
3139 return $this->fields_structure_full_array( $this->get_profile_fields_structure( $only_defaults ) );
3140 }
3141
3142 public function get_search_fields_structure( $only_defaults = false ) {
3143 $fields = [ [ [ 'display_name', 'user_nicename' ] ] ];
3144 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_search_fields', $fields );
3145
3146 return $fields;
3147 }
3148
3149 public function get_search_fields( $only_defaults = false ) {
3150 $fields = $this->fields_structure_full_array( $this->get_search_fields_structure( $only_defaults ) );
3151 foreach( $fields as $row_key => $row ) {
3152 foreach( $row as $col_key => $col ) {
3153 foreach( $col as $field_key => $field ) {
3154 if( $this->is_field( $field ) ) {
3155 $fields[ $row_key ][ $col_key ][ $field_key ]['isRequired'] = 0;
3156 $fields[ $row_key ][ $col_key ][ $field_key ]['class'] = 'wpf-member-search-field';
3157 if( in_array( $field['type'], [ 'text', 'textarea', 'email', 'url' ], true ) ) {
3158 $fields[ $row_key ][ $col_key ][ $field_key ]['type'] = 'search';
3159 }
3160 }
3161 }
3162 }
3163 }
3164
3165 return $fields;
3166 }
3167
3168 public function get_search_fields_names( $only_defaults = false ) {
3169 $names = [];
3170 $fields = $this->get_search_fields( $only_defaults );
3171
3172 foreach( $fields as $row ) {
3173 foreach( $row as $col ) {
3174 foreach( $col as $field ) {
3175 if( $only_defaults && ! $field['isDefault'] ) continue;
3176 $names[] = $field['name'];
3177 }
3178 }
3179 }
3180
3181 return $names;
3182 }
3183
3184 public function set_guest_cookies( $args ) {
3185 if( ! wpforo_setting( 'legal', 'cookies' ) ) return;
3186 if( isset( $args['name'] ) && isset( $args['email'] ) ) {
3187 $comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
3188 $secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
3189 setcookie( 'comment_author_' . COOKIEHASH, $args['name'], time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
3190 setcookie( 'comment_author_email_' . COOKIEHASH, $args['email'], time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
3191
3192 WPF()->current_user_display_name = $args['name'];
3193 WPF()->current_user_email = $args['email'];
3194 }
3195 }
3196
3197 public function get_guest_cookies() {
3198 $guest = [ 'name' => '', 'email' => '' ];
3199 if( wpforo_setting( 'legal', 'cookies' ) ) {
3200 if( ! WPF()->current_userid && WPF()->current_user_email ) {
3201 $guest['name'] = WPF()->current_user_display_name;
3202 $guest['email'] = WPF()->current_user_email;
3203 } else {
3204 $guest_cookies = wp_get_current_commenter();
3205 $guest['name'] = ( isset( $guest_cookies['comment_author'] ) ) ? $guest_cookies['comment_author'] : '';
3206 $guest['email'] = ( isset( $guest_cookies['comment_author_email'] ) ) ? $guest_cookies['comment_author_email'] : '';
3207 }
3208 }
3209
3210 return $guest;
3211 }
3212
3213 public function set_is_email_confirmed( $userid, $status ) {
3214 if( false !== WPF()->db->update( WPF()->tables->profiles, [ 'is_email_confirmed' => intval( $status ) ], [ 'userid' => wpforo_bigintval( $userid ) ], [ '%d' ], [ '%d' ] ) ) {
3215 WPF()->notice->add( 'Email has been confirmed', 'success' );
3216
3217 return true;
3218 }
3219 WPF()->notice->add( 'Email confirm error', 'error' );
3220
3221 return false;
3222 }
3223
3224 public function get_is_email_confirmed( $userid ) {
3225 $sql = "SELECT `is_email_confirmed` FROM `" . WPF()->tables->profiles . "` WHERE `userid` = %d";
3226
3227 return (bool) WPF()->db->get_var( WPF()->db->prepare( $sql, $userid ) );
3228 }
3229
3230 /**
3231 * @param int $userid
3232 *
3233 * @return int
3234 */
3235 public function get_groupid( $userid ) {
3236 return (int) WPF()->db->get_var(
3237 WPF()->db->prepare(
3238 "SELECT `groupid`
3239 FROM `" . WPF()->tables->profiles . "`
3240 WHERE `userid` = %d",
3241 $userid
3242 )
3243 );
3244 }
3245
3246
3247 /**
3248 * @param int $userid
3249 * @param boolean $array
3250 *
3251 * @return string|array|null
3252 */
3253 public function get_secondary_groupids( $userid, $array = true ) {
3254 $secondary_groupids = WPF()->db->get_var(
3255 WPF()->db->prepare( "SELECT `secondary_groupids`
3256 FROM `" . WPF()->tables->profiles . "`
3257 WHERE `userid` = %d",
3258 $userid
3259 )
3260 );
3261
3262 if( $array && !empty($secondary_groupids) ) return explode( ',', $secondary_groupids );
3263
3264 return $secondary_groupids;
3265 }
3266
3267 public function set_groupid( $userid, $groupid ) {
3268 $userid = wpforo_bigintval( $userid );
3269 $groupid = intval( $groupid );
3270 if( $userid && $groupid ) {
3271 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `groupid` = %d WHERE `userid` = %d";
3272 if( false !== WPF()->db->query( WPF()->db->prepare( $sql, $groupid, $userid ) ) ) {
3273 $this->reset( $userid );
3274 do_action( 'wpforo_set_groupid', $userid, $groupid );
3275
3276 return true;
3277 }
3278 }
3279
3280 return false;
3281 }
3282
3283 /**
3284 * @param int $userid
3285 * @param array|int $groupids
3286 *
3287 * @return bool
3288 */
3289 public function set_secondary_groupids( $userid, $groupids ) {
3290 $userid = wpforo_bigintval( $userid );
3291 if( $userid ) {
3292 $groupids = implode( ',', array_unique( array_filter( array_map( 'intval', (array) $groupids ) ) ) );
3293 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `secondary_groupids` = %s WHERE `userid` = %d";
3294 if( false !== WPF()->db->query( WPF()->db->prepare( $sql, $groupids, $userid ) ) ) {
3295 $this->reset( $userid );
3296
3297 return true;
3298 }
3299 }
3300
3301 return false;
3302 }
3303
3304 /**
3305 * @param int $userid
3306 * @param array|int $groupids
3307 *
3308 * @return bool
3309 */
3310 public function append_secondary_groupids( $userid, $groupids ) {
3311 $userid = wpforo_bigintval( $userid );
3312 if( $userid ) {
3313 if( $member = $this->get_member( $userid ) ) {
3314 $groupids = array_filter( array_map( 'intval', (array) $groupids ) );
3315 $groupids = array_merge( $member['secondary_groupids'], $groupids );
3316
3317 return $this->set_secondary_groupids( $userid, $groupids );
3318 }
3319 }
3320
3321 return false;
3322 }
3323
3324 public function after_register_new_user( $userid ) {
3325 if(
3326 wpforo_setting( 'authorization', 'manually_approval' )
3327 || (int) trim( (string) get_user_meta( $userid, 'default_password_nag', true ) )
3328 ){
3329 $this->update_profile_fields( $userid, [ 'status' => 'inactive' ], false );
3330 }
3331 }
3332
3333 public function after_password_reset( $user ) {
3334 $status = $this->get_status( $user->ID );
3335 if( $status !== 'banned' ){
3336 $data = [ 'status' => 'active', 'is_email_confirmed' => 1 ];
3337 if( wpforo_setting( 'authorization', 'manually_approval' ) ) $data['status'] = $status;
3338 $this->update_profile_fields( $user->ID, $data, false );
3339 $this->reset( $user->ID );
3340 }
3341 }
3342
3343 public function wp_login( $user_login, $user ) {
3344 $this->inactive_to_active( wpforo_bigintval( $user->ID ), $user_login );
3345 }
3346
3347 public function get_distinct_status() {
3348 $sql = "SELECT DISTINCT `status` as statuses FROM `" . WPF()->tables->profiles . "`";
3349
3350 return WPF()->db->get_col( $sql );
3351 }
3352
3353 /**
3354 * @param array $args
3355 *
3356 * @return array selected userids
3357 */
3358 public function get_userids( $args ) {
3359 $sql = "SELECT `userid` FROM `" . WPF()->tables->profiles . "`";
3360 if( $args ) {
3361 $wheres = [];
3362 foreach( $args as $field => $value ) {
3363 $wheres[] = "`" . $field . "` = '" . esc_sql( $value ) . "'";
3364 }
3365 if( $wheres ) $sql .= " WHERE " . implode( " AND ", $wheres );
3366 }
3367
3368 $userids = WPF()->db->get_col( $sql );
3369
3370 return apply_filters( 'wpforo_member_after_get_userids', $userids );
3371 }
3372
3373 public function get_inlist_enabled_statuses(){
3374 return wpforo_setting( 'members', 'hide_inactive' ) ? ['active'] : ['active', 'inactive', 'banned'];
3375 }
3376
3377 /**
3378 * @param int $userid
3379 *
3380 * @return int
3381 */
3382 public function calc_approved_posts( $userid ) {
3383 if( $userid = wpforo_bigintval( $userid ) ){
3384 $sqls = [];
3385 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
3386 $sqls[] = WPF()->db->prepare(
3387 "SELECT COUNT(*)
3388 FROM `$table`
3389 WHERE `status` = 0
3390 AND `userid` = %d",
3391 $userid
3392 );
3393 }
3394
3395 if( $sqls ){
3396 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3397 }
3398 }
3399
3400 return 0;
3401 }
3402
3403 /**
3404 * @param int $userid
3405 *
3406 * @return int
3407 */
3408 public function calc_approved_topics( $userid ) {
3409 if( $userid = wpforo_bigintval( $userid ) ){
3410 $sqls = [];
3411 foreach( WPF()->get_active_boards_tables( 'topics') as $table ){
3412 $sqls[] = WPF()->db->prepare(
3413 "SELECT COUNT(*)
3414 FROM `$table`
3415 WHERE `status` = 0
3416 AND `userid` = %d",
3417 $userid
3418 );
3419 }
3420
3421 if( $sqls ){
3422 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3423 }
3424 }
3425
3426 return 0;
3427 }
3428
3429 /**
3430 * @param int $userid
3431 *
3432 * @return int
3433 */
3434 public function calc_approved_questions( $userid ) {
3435 if( $userid = wpforo_bigintval( $userid ) ){
3436 $sqls = [];
3437 foreach( WPF()->get_active_boards_tables( 'topics') as $table ){
3438 if( $forumids = Forums::get_forumids( str_replace( 'topics', 'forums', $table ), 3 ) ){
3439 $sqls[] = WPF()->db->prepare(
3440 "SELECT COUNT(*)
3441 FROM `$table`
3442 WHERE `status` = 0
3443 AND `userid` = %d
3444 AND `forumid` IN( ". implode(',', $forumids) ." )",
3445 $userid
3446 );
3447 }
3448 }
3449
3450 if( $sqls ){
3451 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3452 }
3453 }
3454
3455 return 0;
3456 }
3457
3458 /**
3459 * @param int $userid
3460 *
3461 * @return int
3462 */
3463 public function calc_approved_answers( $userid ) {
3464 if( $userid = wpforo_bigintval( $userid ) ){
3465 $sqls = [];
3466 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
3467 if( $forumids = Forums::get_forumids( str_replace( 'posts', 'forums', $table ), 3 ) ){
3468 $sqls[] = WPF()->db->prepare(
3469 "SELECT COUNT(*)
3470 FROM `$table`
3471 WHERE `status` = 0
3472 AND `is_first_post` = 0
3473 AND `parentid` = 0
3474 AND `userid` = %d
3475 AND `forumid` IN( ". implode(',', $forumids) ." )",
3476 $userid
3477 );
3478 }
3479 }
3480
3481 if( $sqls ){
3482 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3483 }
3484 }
3485
3486 return 0;
3487 }
3488
3489 /**
3490 * @param int $userid
3491 *
3492 * @return int
3493 */
3494 public function calc_approved_comments( $userid ) {
3495 if( $userid = wpforo_bigintval( $userid ) ){
3496 $sqls = [];
3497 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
3498 if( $forumids = Forums::get_forumids( str_replace( 'posts', 'forums', $table ), 3 ) ){
3499 $sqls[] = WPF()->db->prepare(
3500 "SELECT COUNT(*)
3501 FROM `$table`
3502 WHERE `status` = 0
3503 AND `is_first_post` = 0
3504 AND `parentid` <> 0
3505 AND `userid` = %d
3506 AND `forumid` IN( ". implode(',', $forumids) ." )",
3507 $userid
3508 );
3509 }
3510 }
3511
3512 if( $sqls ){
3513 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3514 }
3515 }
3516
3517 return 0;
3518 }
3519
3520 /**
3521 * @param int $userid
3522 *
3523 * @return array
3524 */
3525 public function calc_reactions_in( $userid ) {
3526 $reactions_in = array_map( '__return_zero', array_flip( Reactions::get_type_list() ) );
3527 if( $userid = wpforo_bigintval( $userid ) ){
3528 $sqls = [];
3529 foreach( WPF()->get_active_boards_tables( 'reactions') as $table ){
3530 $sqls[] = WPF()->db->prepare(
3531 "SELECT `type`
3532 FROM `$table`
3533 WHERE `post_userid` = %d",
3534 $userid
3535 );
3536 }
3537
3538 if( $sqls ){
3539 $r = (array) WPF()->db->get_results( "SELECT `type`, COUNT(`type`) as `count` FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp GROUP BY `type`", ARRAY_A );
3540 foreach( $r as $_r ) $reactions_in[$_r['type']] = intval( $_r['count'] );
3541 }
3542 }
3543
3544 return $reactions_in;
3545 }
3546
3547 /**
3548 * @param int $userid
3549 *
3550 * @return array
3551 */
3552 public function calc_reactions_out( $userid ) {
3553 $reactions_out = array_map( '__return_zero', array_flip( Reactions::get_type_list() ) );
3554 if( $userid = wpforo_bigintval( $userid ) ){
3555 $sqls = [];
3556 foreach( WPF()->get_active_boards_tables( 'reactions') as $table ){
3557 $sqls[] = WPF()->db->prepare(
3558 "SELECT `type`
3559 FROM `$table`
3560 WHERE `userid` = %d",
3561 $userid
3562 );
3563 }
3564
3565 if( $sqls ){
3566 $r = (array) WPF()->db->get_results( "SELECT `type`, COUNT(`type`) as `count` FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp GROUP BY `type`", ARRAY_A );
3567 foreach( $r as $_r ) $reactions_out[$_r['type']] = intval( $_r['count'] );
3568 }
3569 }
3570
3571 return $reactions_out;
3572 }
3573
3574 /**
3575 * @param int $userid
3576 *
3577 * @return void
3578 */
3579 public function rebuild_stats( $userid ) {
3580 $posts = $this->calc_approved_posts( $userid );
3581 $topics = $this->calc_approved_topics( $userid );
3582 $questions = $this->calc_approved_questions( $userid );
3583 $answers = $this->calc_approved_answers( $userid );
3584 $comments = $this->calc_approved_comments( $userid );
3585 $reactions_in = $this->calc_reactions_in( $userid );
3586 $reactions_out = $this->calc_reactions_out( $userid );
3587 $points = $this->calc_points( compact( 'posts', 'topics', 'questions', 'answers', 'comments', 'reactions_in', 'reactions_out' ) );
3588
3589 if(WPF()->db->update(
3590 WPF()->tables->profiles,
3591 [
3592 'posts' => $posts,
3593 'topics' => $topics,
3594 'questions' => $questions,
3595 'answers' => $answers,
3596 'comments' => $comments,
3597 'reactions_in' => json_encode( $reactions_in ),
3598 'reactions_out' => json_encode( $reactions_out ),
3599 'points' => $points,
3600 ],
3601 [ 'userid' => $userid ],
3602 ['%d','%d','%d','%d','%d','%s','%s','%d'],
3603 '%d'
3604 )){
3605 $this->reset( $userid );
3606 }
3607 }
3608
3609 public function after_add_topic( $topic ) {
3610 if( !intval($topic['status']) ) $this->rebuild_stats( $topic['userid'] );
3611 }
3612
3613 public function after_delete_topic( $topic ) {
3614 if( !intval($topic['status']) ) $this->rebuild_stats( $topic['userid'] );
3615 }
3616
3617 public function after_topic_status_update( $topic ) {
3618 $this->rebuild_stats( $topic['userid'] );
3619 }
3620
3621 public function before_merge_topic( $target, $current, $postids ){
3622 $sql = "SELECT DISTINCT `userid` FROM `". WPF()->tables->posts ."` WHERE `topicid` = %d";
3623 $sql = WPF()->db->prepare( $sql, $current['topicid'] );
3624 if( $postids ) $sql .= " AND `postid` IN(" . implode( ',', $postids ) . ")";
3625 $this->touched_userids = array_merge( $this->touched_userids, WPF()->db->get_col( $sql ) );
3626 }
3627
3628 public function after_merge_topic(){
3629 foreach( array_unique(array_filter( $this->touched_userids )) as $userid ) $this->rebuild_stats( $userid );
3630 }
3631
3632 public function after_move_topic( $topic ) {
3633 $sql = "SELECT DISTINCT `userid` FROM `". WPF()->tables->posts ."` WHERE `topicid` = %d";
3634 $sql = WPF()->db->prepare( $sql, $topic['topicid'] );
3635 foreach( WPF()->db->get_col( $sql ) as $userid ) $this->rebuild_stats( $userid );
3636 }
3637
3638 public function after_add_post( $post ){
3639 if( !intval( $post['status'] ) ) $this->rebuild_stats( $post['userid'] );
3640 }
3641
3642 public function after_delete_post( $post ) {
3643 if( !intval( $post['status'] ) ) $this->rebuild_stats( $post['userid'] );
3644 }
3645
3646 public function after_post_status_update( $post ) {
3647 $this->rebuild_stats( $post['userid'] );
3648 }
3649
3650 public function after_add_reaction( $reaction ) {
3651 $this->rebuild_stats( $reaction['userid'] );
3652 $this->rebuild_stats( $reaction['post_userid'] );
3653 }
3654
3655 public function after_edit_reaction( $fields, $where ) {
3656 $field_userid = wpfval( $fields, 'userid' );
3657 $field_post_userid = wpfval( $fields, 'post_userid' );
3658 if( $field_userid || $field_post_userid ){
3659 $userids = [ $field_userid, $field_post_userid, wpfval( $where, 'userid' ), wpfval( $where, 'post_userid' ) ];
3660 $userids = array_filter( $userids );
3661 $userids = array_unique( $userids );
3662 foreach( $userids as $userid ) $this->rebuild_stats( $userid );
3663 }
3664 }
3665
3666 public function before_delete_reaction( $args, $operator ){
3667 $reactions = WPF()->reaction->get_reactions( $args, $operator );
3668 foreach( $reactions as $reaction ) {
3669 $this->touched_userids[] = $reaction['userid'];
3670 $this->touched_userids[] = $reaction['post_userid'];
3671 }
3672 }
3673
3674 public function after_delete_reaction(){
3675 foreach( array_unique(array_filter( $this->touched_userids )) as $userid ) $this->rebuild_stats( $userid );
3676 }
3677
3678 public function after_delete_user( $userid, $reassign ) {
3679 if( $reassign ) $this->rebuild_stats( $reassign );
3680 }
3681
3682 public function after_activate_user( $userid ){
3683 $user = get_user_by( 'ID', $userid );
3684 if( $user ){
3685 $sbj = wpforo_setting( 'email', 'after_user_approve_email_subject' );
3686 $msg = wpforo_setting( 'email', 'after_user_approve_email_message' );
3687 $blogname = get_option('blogname', '');
3688 $login_url = wpforo_login_url( '' );
3689 $login_link = sprintf( '<a href="%1$s">%2$s</a>', $login_url, $blogname );
3690
3691 $sbj = str_replace( [ '[blogname]', '[user_login]', '[login_link]', '[login_url]' ], [ $blogname, $user->user_login, $login_link, $login_url ], $sbj );
3692 $msg = str_replace( [ '[blogname]', '[user_login]', '[login_link]', '[login_url]' ], [ $blogname, $user->user_login, $login_link, $login_url ], $msg );
3693 wpforo_send_email( $user->user_email, $sbj, $msg );
3694 }
3695 }
3696
3697 public function get_activity_url( $filter = '', $boardid = null, $arg = null ) {
3698 if( !$arg ) $arg = WPF()->current_object['user'];
3699 $url = rtrim( $this->get_profile_url( $arg, 'activity' ), '/' );
3700 if( is_wpforo_multiboard() ){
3701 if( is_null( $boardid ) ) $boardid = wpfkey( WPF()->GET, 'boardid' ) ? (int) wpfval( WPF()->GET, 'boardid' ) : WPF()->board->get_current( 'boardid' );
3702 if( $filter ){
3703 $url .= sprintf( '/?boardid=%1$d&filter=%2$s', $boardid, $filter);
3704 }else{
3705 $url .= sprintf( '/?boardid=%1$d', $boardid);
3706 }
3707 }elseif( $filter ){
3708 $url .= sprintf( '/?filter=%1$s', $filter);
3709 }
3710 return WPF()->user_trailingslashit( $url );
3711 }
3712
3713 public function get_favored_url( $filter = '', $boardid = null, $arg = null ) {
3714 if( !$arg ) $arg = WPF()->current_object['user'];
3715 $url = rtrim( $this->get_profile_url( $arg, 'favored' ), '/' );
3716 if( is_wpforo_multiboard() ){
3717 if( is_null( $boardid ) ) $boardid = wpfkey( WPF()->GET, 'boardid' ) ? (int) wpfval( WPF()->GET, 'boardid' ) : WPF()->board->get_current( 'boardid' );
3718 if( $filter ){
3719 $url .= sprintf( '/?boardid=%1$d&filter=%2$s', $boardid, $filter);
3720 }else{
3721 $url .= sprintf( '/?boardid=%1$d', $boardid);
3722 }
3723 }elseif( $filter ){
3724 $url .= sprintf( '/?filter=%1$s', $filter);
3725 }
3726 return WPF()->user_trailingslashit( $url );
3727 }
3728
3729 public function get_newest_member( $status_filter = true ){
3730 if( ! ($visible_usergroup_ids = WPF()->usergroup->get_visible_usergroup_ids()) ) return [];
3731
3732 $groupids = implode( ", ", $visible_usergroup_ids );
3733
3734 if( $status_filter ){
3735 $status = implode( "', '", $this->get_inlist_enabled_statuses() );
3736 $sql = "SELECT `userid` FROM `". WPF()->tables->profiles ."`
3737 WHERE `status` IN ('" . $status . "')
3738 AND `groupid` IN (" . $groupids . ")
3739 ORDER BY `userid` DESC LIMIT 1";
3740 } else {
3741 $sql = "SELECT `userid` FROM `". WPF()->tables->profiles ."`
3742 WHERE `groupid` IN (" . $groupids . ")
3743 ORDER BY `userid` DESC LIMIT 1";
3744 }
3745
3746 $memberid = WPF()->db->get_var( $sql );
3747 $member = wpforo_member( $memberid );
3748
3749 if( empty( $member ) ){
3750
3751 WPF()->db->query("DELETE p FROM `". WPF()->tables->profiles ."` p LEFT JOIN `". WPF()->db->users ."` u ON u.ID = p.userid WHERE u.ID IS NULL");
3752
3753 $memberid = WPF()->db->get_var( $sql );
3754 $member = wpforo_member( $memberid );
3755
3756 if( empty( $member ) ){
3757 if( $status_filter ){
3758 $members = $this->get_members( [ 'orderby' => 'userid', 'status' => [ 'active' ], 'order' => 'DESC', 'row_count' => 1, 'groupids' => $visible_usergroup_ids ] );
3759 } else {
3760 $members = $this->get_members( [ 'orderby' => 'userid', 'order' => 'DESC', 'row_count' => 1, 'groupids' => $visible_usergroup_ids ] );
3761 }
3762 if( isset( $members[0] ) && ! empty( $members[0] ) ) {
3763 $member = $members[0];
3764 } else {
3765 $member = [];
3766 }
3767 }
3768 }
3769 $member['profile_url'] = wpfval($member, 'profile_url') ?: $this->get_profile_url( $memberid );
3770 return $member;
3771 }
3772 }
3773