PluginProbe
wpForo Forum / 2.2.9
wpForo Forum v2.2.9
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.2.9, at classes/Members.php

3,766 lines 129.3 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) ( !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 return [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
1744 }
1745
1746 public function rating( $level = null, $var = '' ) {
1747 if( is_null( $level ) ) return wpforo_setting( 'rating', 'levels' );
1748 $_levels = wpforo_setting( 'rating', 'levels' );
1749 if( ! wpfkey( $_levels, $level ) ) $level = 0;
1750 if( ! $var ) return wpforo_setting( 'rating', 'levels', $level );
1751
1752 return wpforo_setting( 'rating', 'levels', $level, $var );
1753 }
1754
1755 /**
1756 * @param int $points
1757 * @param bool $percent
1758 *
1759 * @return int
1760 */
1761 public function rating_level( $points, $percent = true ) {
1762 $points = intval( $points );
1763 if( $points < $this->rating( 1, 'points' ) ) {
1764 $bar = 0;
1765 } elseif( $points < $this->rating( 2, 'points' ) ) {
1766 $bar = 10;
1767 } elseif( $points < $this->rating( 3, 'points' ) ) {
1768 $bar = 20;
1769 } elseif( $points < $this->rating( 4, 'points' ) ) {
1770 $bar = 30;
1771 } elseif( $points < $this->rating( 5, 'points' ) ) {
1772 $bar = 40;
1773 } elseif( $points < $this->rating( 6, 'points' ) ) {
1774 $bar = 50;
1775 } elseif( $points < $this->rating( 7, 'points' ) ) {
1776 $bar = 60;
1777 } elseif( $points < $this->rating( 8, 'points' ) ) {
1778 $bar = 70;
1779 } elseif( $points < $this->rating( 9, 'points' ) ) {
1780 $bar = 80;
1781 } elseif( $points < $this->rating( 10, 'points' ) ) {
1782 $bar = 90;
1783 } else {
1784 $bar = 100;
1785 }
1786
1787 return $percent ? $bar : (int) floor( $bar / 10 );
1788 }
1789
1790 public function rating_badge( $level = 0, $view = 'short' ) {
1791
1792 $level = ( $level > 10 ) ? floor( $level / 10 ) : $level;
1793
1794 if( $level == 0 ) {
1795 return '<i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1796 } elseif( $level > 0 && $level < 6 ) {
1797 if( $view == 'full' ) {
1798 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', $level );
1799 } else {
1800 return '<span>' . esc_html( $level ) . '</span> <i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1801 }
1802 } elseif( $level > 5 && $level < 9 ) {
1803 if( $view == 'full' ) {
1804 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', ( $level - 5 ) );
1805 } else {
1806 return '<span>' . esc_html( $level - 5 ) . '</span> <i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1807 }
1808 } elseif( $level > 8 ) {
1809 return '<i class="' . $this->rating( $level, 'icon' ) . '"></i>';
1810 } else {
1811 return '';
1812 }
1813 }
1814
1815 public function reset( $userid ) {
1816 if( ! $userid ) return;
1817 wpforo_clean_cache( 'avatar', $userid );
1818 delete_user_meta( intval( $userid ), '_wpf_member_obj' );
1819 if( wpforo_setting( 'seo', 'seo_profile' ) ) WPF()->seo->clear_cache();
1820 }
1821
1822 public function clear_db_cache() {
1823 WPF()->db->query( "DELETE FROM `" . WPF()->db->usermeta . "` WHERE `meta_key` = '_wpf_member_obj'" );
1824 }
1825
1826 private function update_online_time( $userid = null ) {
1827 if( ! $userid ) $userid = WPF()->current_userid;
1828 if( ! $userid ) return false;
1829 $current_timestamp = time();
1830 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `online_time` = %d WHERE `userid` = %d";
1831 $sql = WPF()->db->prepare( $sql, $current_timestamp, wpforo_bigintval( $userid ) );
1832 if( false !== WPF()->db->query( $sql ) ) return $current_timestamp;
1833
1834 return false;
1835 }
1836
1837 public function init_current_user() {
1838 WPF()->wp_current_user = $current_user = wp_get_current_user();
1839 if( $current_user->exists() ) {
1840 WPF()->current_userid = $current_user->ID;
1841 WPF()->current_user_login = $current_user->user_login;
1842 WPF()->current_user_email = $current_user->user_email;
1843 WPF()->current_user_display_name = $current_user->display_name;
1844
1845 $user = $this->get_member( $current_user->ID );
1846 if( ! wpfkey( $user, 'groupid' ) ) {
1847 $this->synchronize_user( $current_user->ID );
1848 $user = $this->get_member( $current_user->ID );
1849 }
1850 $user_meta = get_user_meta( $current_user->ID );
1851 WPF()->current_user = $user;
1852 WPF()->current_usermeta = $user_meta;
1853 WPF()->current_user_groupid = WPF()->current_user['groupid'];
1854 WPF()->current_user_secondary_groupids = WPF()->current_user['secondary_groupids'];
1855 WPF()->current_user_groupids = array_unique( array_filter( array_merge( (array) WPF()->current_user_groupid, (array) WPF()->current_user_secondary_groupids ) ) );
1856 WPF()->current_user_status = (string) wpfval($user, 'status');
1857 $this->update_online_time();
1858 } elseif( $guest = $this->get_guest_cookies() ) {
1859 WPF()->current_userid = 0;
1860 WPF()->current_user_login = '';
1861 WPF()->current_user_email = $guest['email'];
1862 WPF()->current_user_display_name = $guest['name'];
1863 WPF()->current_user = $this->get_guest( $guest );
1864 WPF()->current_usermeta = [];
1865 WPF()->current_user_groupid = 4;
1866 WPF()->current_user_groupids = [ 4 ];
1867 WPF()->current_user_secondary_groupids = [];
1868 WPF()->current_user_status = '';
1869 WPF()->current_user_accesses = [];
1870 }
1871
1872 WPF()->usergroup->init_current();
1873
1874 if( function_exists( 'wp_get_session_token' ) && function_exists( 'wp_parse_auth_cookie' ) ) WPF()->session_token = wp_get_session_token();
1875 if( ! WPF()->session_token ) {
1876 $secret_key = defined( 'SECRET_KEY' ) && SECRET_KEY ? SECRET_KEY : 'wpforo';
1877 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 );
1878 }
1879
1880 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 );
1881 }
1882
1883 public function blog_posts( $userid ) {
1884 if( isset( $userid ) && $userid ) return count_user_posts( $userid );
1885
1886 return 0;
1887 }
1888
1889 public function blog_comments( $userid, $user_email ) {
1890 global $wpdb;
1891 if( ! $userid || ! $user_email ) return 0;
1892
1893 return (int) $wpdb->get_var( "SELECT COUNT(*) FROM " . $wpdb->comments . " WHERE `user_id` = " . intval( $userid ) . " OR `comment_author_email` = '" . esc_sql( $user_email ) . "'" );
1894 }
1895
1896 public function show_delete_form( $current_user, $userids ) {
1897 if( empty( $current_user ) || empty( $userids ) ) return;
1898
1899 $userids = array_diff( $userids, [ $current_user->ID ] );
1900 $users_have_content = false;
1901 if( WPF()->db->get_var( "SELECT `postid` FROM `" . WPF()->tables->posts . "` WHERE `userid` IN( " . implode( ',', array_map( 'intval', $userids ) ) . " ) LIMIT 1" ) ) {
1902 $users_have_content = true;
1903 }
1904 ?>
1905 <hr/><strong>#wpForo</strong>
1906 <?php if( ! $users_have_content ) : ?>
1907 <input type="hidden" name="wpforo_user_delete_option" value="delete"/>
1908 <?php else: ?>
1909 <?php if( 1 == count( $userids ) ) : ?>
1910 <fieldset>
1911 <legend><?php _e( 'What should be done with wpForo content owned by this user?', 'wpforo' ); ?></legend>
1912 <?php else : ?>
1913 <fieldset>
1914 <legend><?php _e( 'What should be done with wpForo content owned by these users?', 'wpforo' ); ?></legend>
1915 <?php endif; ?>
1916 <ul style="list-style:none;">
1917 <li><label><input type="radio" id="wpforo_delete_option0" name="wpforo_user_delete_option" value="delete">
1918 <?php _e( 'Delete all wpForo content.', 'wpforo' ); ?></label></li>
1919 <li><input type="radio" id="wpforo_delete_option1" name="wpforo_user_delete_option" value="reassign">
1920 <label for="wpforo_delete_option1"><?php _e( 'Attribute all content to:' ) ?></label>
1921 <?php
1922 wp_dropdown_users( [
1923 'name' => 'wpforo_reassign_userid',
1924 'exclude' => $userids,
1925 'show' => 'display_name_with_login',
1926 ] );
1927 ?>
1928 </li>
1929 </ul></fieldset>
1930 <script type="text/javascript">
1931 jQuery(document).ready(function ($) {
1932 $('#wpforo_reassign_userid').on('focus', function () {
1933 $('#wpforo_delete_option1').prop('checked', true).trigger('change')
1934 })
1935 })
1936 </script>
1937 <?php endif;
1938 }
1939
1940 public function autoban( $userid ) {
1941 if( ! WPF()->usergroup->can( 'em' ) ) {
1942 WPF()->db->update( WPF()->tables->profiles, [ 'status' => 'banned' ], [ 'userid' => intval( $userid ) ], [ '%s' ], [ '%d' ] );
1943 }
1944 }
1945
1946 public function member_approved_posts( $member = [] ) {
1947 if( is_numeric( $member ) ) {
1948 if( $userid = wpforo_bigintval( $member ) ) {
1949 if( $userid === WPF()->current_userid ) return WPF()->current_user['posts'];
1950 return (int) WPF()->db->get_var(
1951 WPF()->db->prepare(
1952 "SELECT COUNT(*) as posts
1953 FROM `" . WPF()->tables->posts . "`
1954 WHERE `status` = 0
1955 AND `userid` = %d",
1956 $userid
1957 )
1958 );
1959 }
1960 }
1961
1962 return (int) wpfval( $member, 'posts' );
1963 }
1964
1965 public function current_user_is_new() {
1966 if( WPF()->usergroup->can( 'em' ) ) {
1967 //This is an admin or moderator. The number of posts doesn't matter.
1968 return false;
1969 } else {
1970 $new_user_max_posts = wpforo_setting( 'antispam', 'new_user_max_posts' );
1971 $posts = $this->member_approved_posts( WPF()->current_userid );
1972 if( $new_user_max_posts && $posts <= $new_user_max_posts ) {
1973 return true;
1974 } else {
1975 return false;
1976 }
1977 }
1978 }
1979
1980 /**
1981 * @return int
1982 */
1983 public function banned_count() {
1984 $key = [ 'member', 'banned_count' ];
1985 if( WPF()->ram_cache->exists( $key ) ) return WPF()->ram_cache->get( $key );
1986 $var = (int) WPF()->db->get_var( "SELECT count(*) FROM `" . WPF()->tables->profiles . "` WHERE `status` = 'banned'" );
1987 WPF()->ram_cache->set( $key, $var );
1988
1989 return $var;
1990 }
1991
1992 public function _get_guest_posts( $email ) {
1993 $sqls = [];
1994 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
1995 $sqls[] = WPF()->db->prepare(
1996 "SELECT *
1997 FROM `$table`
1998 WHERE `status` = 0
1999 AND `email` = %s",
2000 $email
2001 );
2002 }
2003
2004 if( $sqls ){
2005 return (array) WPF()->db->get_results(
2006 implode( ' UNION ALL ', $sqls ) . " ORDER BY `created` ASC, `postid` ASC",
2007 ARRAY_A
2008 );
2009 }
2010
2011 return [];
2012 }
2013
2014 public function get_guest_posts( $email ) {
2015 return wpforo_ram_get( [ $this, '_get_guest_posts' ], $email );
2016 }
2017
2018 public function _get_guest( $args = [] ) {
2019 if( !wpfval( $args, 'name' ) ) $args['name'] = wpforo_phrase( 'Anonymous', false );
2020 if( !wpfval( $args, 'email' ) ) $args['email'] = 'anonymous@example.com';
2021
2022 $args['name'] = strip_tags( (string) $args['name'] );
2023 $args['email'] = sanitize_email( $args['email'] );
2024 $args['user_registered'] = current_time( 'mysql', 1 );
2025 $args['posts'] = 0;
2026
2027 if( $args['email'] && $args['email'] !== 'anonymous@example.com' ) {
2028 if( $posts = $this->get_guest_posts( $args['email'] ) ) {
2029 $args['posts'] = count( $posts );
2030 if( $first_post_created = wpfval( $posts, 0, 'created' ) ) $args['user_registered'] = $first_post_created;
2031 }
2032 }
2033
2034 $guest = wpforo_array_args_cast_and_merge(
2035 [
2036 'groupid' => 4,
2037 'group_name' => wpforo_phrase( 'Guest', false ),
2038 'user_login' => $args['name'],
2039 'user_nicename' => sanitize_text_field( $args['name'] ),
2040 'user_email' => $args['email'],
2041 'user_registered' => $args['user_registered'],
2042 'display_name' => $args['name'],
2043 'posts' => $args['posts'],
2044 'status' => 'active',
2045 ],
2046 $this->default->member
2047 );
2048
2049 return $this->decode( $guest );
2050 }
2051
2052 public function get_guest( $args = [] ) {
2053 return wpforo_ram_get( [ $this, '_get_guest' ], $args );
2054 }
2055
2056 public function init_fields() {
2057 if( ! empty( $this->fields ) ) return;
2058
2059 $this->init_countries();
2060 $this->init_timezones();
2061
2062 $this->fields = apply_filters( 'wpforo_member_before_init_fields', $this->fields );
2063
2064 $usergroupids = [];
2065 $usergroups = WPF()->usergroup->get_usergroups();
2066 foreach( $usergroups as $usergroup ) {
2067 $usergroupids[] = $usergroup['groupid'];
2068 }
2069 $usergroupids_can_edit_fields = WPF()->usergroup->get_groupids_by_can( 'em' );
2070 $usergroupids_can_view_social_net = WPF()->usergroup->get_groupids_by_can( 'vmsn' );
2071
2072 /**
2073 * start init tinymce settings
2074 */
2075 $wp_editor_settings = WPF()->tpl->editor_buttons();
2076 $wp_editor_settings['tinymce']['toolbar1'] = 'bold,italic,link,unlink,undo,redo,source_code,emoticons';
2077 $wp_editor_settings['plugins'] = '';
2078 unset(
2079 $wp_editor_settings['external_plugins']['wpforo_pre_button'], $wp_editor_settings['external_plugins']['wpforo_spoiler_button']
2080 );
2081 $wp_editor_settings = apply_filters( 'wpforo_members_init_fields_tinymce_settings', $wp_editor_settings );
2082
2083 $this->fields['user_login'] = [
2084 'fieldKey' => 'user_login',
2085 'type' => 'text',
2086 'isDefault' => 1,
2087 'isRemovable' => 0,
2088 'isRequired' => 1,
2089 'isEditable' => 0,
2090 'label' => wpforo_phrase( 'Username', false ),
2091 'title' => wpforo_phrase( 'Username', false ),
2092 'placeholder' => wpforo_phrase( 'Username', false ),
2093 'description' => wpforo_phrase( 'Length must be between 3 characters and 15 characters.', false ),
2094 'minLength' => 3,
2095 'maxLength' => 30,
2096 'faIcon' => 'fas fa-user',
2097 'name' => 'user_login',
2098 'cantBeInactive' => [ 'register' ],
2099 'canEdit' => [],
2100 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmu' ),
2101 'can' => 'vmu',
2102 'isSearchable' => 0,
2103 ];
2104
2105 $this->fields['user_email'] = [
2106 'fieldKey' => 'user_email',
2107 'type' => 'email',
2108 'isDefault' => 1,
2109 'isRemovable' => 0,
2110 'isRequired' => 1,
2111 'isEditable' => 1,
2112 'label' => wpforo_phrase( 'Email', false ),
2113 'title' => wpforo_phrase( 'Email', false ),
2114 'placeholder' => wpforo_phrase( 'Email', false ),
2115 'minLength' => 0,
2116 'maxLength' => 0,
2117 'faIcon' => 'fas fa-envelope',
2118 'name' => 'user_email',
2119 'cantBeInactive' => [ 'register' ],
2120 'canEdit' => $usergroupids_can_edit_fields,
2121 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmm' ),
2122 'can' => 'vmm',
2123 'isSearchable' => 1,
2124 ];
2125
2126 $this->fields['user_pass'] = [
2127 'fieldKey' => 'user_pass',
2128 'type' => 'password',
2129 'isDefault' => 1,
2130 'isRemovable' => 0,
2131 'isRequired' => 1,
2132 'isEditable' => 1,
2133 'label' => wpforo_phrase( 'Password', false ),
2134 'title' => wpforo_phrase( 'Password', false ),
2135 'placeholder' => wpforo_phrase( 'Password', false ),
2136 'description' => wpforo_phrase( 'Must be minimum 6 characters.', false ),
2137 'minLength' => 6,
2138 'maxLength' => 20,
2139 'faIcon' => 'fas fa-key',
2140 'name' => 'user_pass',
2141 'cantBeInactive' => [
2142 'account',
2143 'register',
2144 ],
2145 'canEdit' => $usergroupids_can_edit_fields,
2146 'canView' => [],
2147 'can' => '',
2148 'isSearchable' => 0,
2149 ];
2150
2151 $this->fields['display_name'] = [
2152 'fieldKey' => 'display_name',
2153 'type' => 'text',
2154 'isDefault' => 1,
2155 'isRemovable' => 0,
2156 'isRequired' => 1,
2157 'isEditable' => 1,
2158 'label' => wpforo_phrase( 'Display Name', false ),
2159 'title' => wpforo_phrase( 'Display Name', false ),
2160 'placeholder' => wpforo_phrase( 'Display Name', false ),
2161 'faIcon' => 'fas fa-user',
2162 'name' => 'display_name',
2163 'cantBeInactive' => [],
2164 'canEdit' => $usergroupids_can_edit_fields,
2165 'canView' => $usergroupids,
2166 'can' => '',
2167 'isSearchable' => 1,
2168 ];
2169
2170 $this->fields['user_nicename'] = [
2171 'fieldKey' => 'user_nicename',
2172 'type' => 'text',
2173 'isDefault' => 1,
2174 'isRemovable' => 0,
2175 'isRequired' => 1,
2176 'isEditable' => 1,
2177 'label' => wpforo_phrase( 'Nickname', false ),
2178 'title' => wpforo_phrase( 'Nickname', false ),
2179 'placeholder' => wpforo_phrase( 'Nickname', false ),
2180 'description' => wpforo_phrase( 'URL Address Identifier', false ),
2181 'minLength' => 0,
2182 'maxLength' => 0,
2183 'faIcon' => 'fas fa-link',
2184 'name' => 'user_nicename',
2185 'cantBeInactive' => [],
2186 'canEdit' => $usergroupids_can_edit_fields,
2187 'canView' => $usergroupids,
2188 'can' => '',
2189 'isSearchable' => 1,
2190 ];
2191
2192 $this->fields['first_name'] = [
2193 'fieldKey' => 'first_name',
2194 'type' => 'text',
2195 'isDefault' => 1,
2196 'isRemovable' => 0,
2197 'isRequired' => 0,
2198 'isEditable' => 1,
2199 'label' => wpforo_phrase( 'First Name', false ),
2200 'title' => wpforo_phrase( 'First Name', false ),
2201 'placeholder' => wpforo_phrase( 'First Name', false ),
2202 'faIcon' => 'fas fa-address-card',
2203 'name' => 'first_name',
2204 'cantBeInactive' => [],
2205 'canEdit' => $usergroupids_can_edit_fields,
2206 'canView' => $usergroupids,
2207 'can' => '',
2208 'isSearchable' => 0,
2209 ];
2210
2211 $this->fields['last_name'] = [
2212 'fieldKey' => 'last_name',
2213 'type' => 'text',
2214 'isDefault' => 1,
2215 'isRemovable' => 0,
2216 'isRequired' => 0,
2217 'isEditable' => 1,
2218 'label' => wpforo_phrase( 'Last Name', false ),
2219 'title' => wpforo_phrase( 'Last Name', false ),
2220 'placeholder' => wpforo_phrase( 'Last Name', false ),
2221 'faIcon' => 'fas fa-address-card',
2222 'name' => 'last_name',
2223 'cantBeInactive' => [],
2224 'canEdit' => $usergroupids_can_edit_fields,
2225 'canView' => $usergroupids,
2226 'can' => '',
2227 'isSearchable' => 0,
2228 ];
2229
2230 $this->fields['title'] = [
2231 'fieldKey' => 'title',
2232 'type' => 'text',
2233 'isDefault' => 1,
2234 'isRemovable' => 0,
2235 'isRequired' => 1,
2236 'isEditable' => 1,
2237 'label' => wpforo_phrase( 'Title', false ),
2238 'title' => wpforo_phrase( 'Title', false ),
2239 'placeholder' => wpforo_phrase( 'Title', false ),
2240 'minLength' => 0,
2241 'maxLength' => 0,
2242 'faIcon' => 'fas fa-user',
2243 'name' => 'title',
2244 'cantBeInactive' => [],
2245 'canEdit' => $usergroupids_can_edit_fields,
2246 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmt' ),
2247 'can' => 'vmt',
2248 'isSearchable' => 1,
2249 ];
2250
2251 $this->fields['groupid'] = [
2252 'fieldKey' => 'groupid',
2253 'type' => 'usergroup',
2254 'isDefault' => 1,
2255 'isRemovable' => 0,
2256 'isRequired' => 1,
2257 'isEditable' => 1,
2258 'label' => wpforo_phrase( 'User Group', false ),
2259 'title' => wpforo_phrase( 'User Group', false ),
2260 'placeholder' => wpforo_phrase( 'User Group', false ),
2261 'faIcon' => 'fas fa-users',
2262 'name' => 'groupid',
2263 'allowedGroupIds' => [ 3, 5 ],
2264 'cantBeInactive' => [],
2265 'canEdit' => $usergroupids_can_edit_fields,
2266 'canView' => $usergroupids,
2267 'can' => '',
2268 'isSearchable' => 1,
2269 ];
2270
2271 $this->fields['secondary_groupids'] = [
2272 'fieldKey' => 'secondary_groupids',
2273 'type' => 'secondary_groups',
2274 'isWrapItem' => 1,
2275 'isDefault' => 1,
2276 'isRemovable' => 0,
2277 'isRequired' => 0,
2278 'isEditable' => 1,
2279 'label' => wpforo_phrase( 'User Groups Secondary', false ),
2280 'title' => wpforo_phrase( 'User Groups Secondary', false ),
2281 'placeholder' => '',
2282 'faIcon' => '',
2283 'values' => '',
2284 'name' => 'secondary_groupids',
2285 'allowedGroupIds' => WPF()->usergroup->get_secondary_groupids(),
2286 'cantBeInactive' => [],
2287 'canEdit' => $usergroupids_can_edit_fields,
2288 'canView' => $usergroupids,
2289 'can' => '',
2290 'isSearchable' => 1,
2291 ];
2292
2293 $this->fields['avatar'] = [
2294 'fieldKey' => 'avatar',
2295 'type' => 'avatar',
2296 'isDefault' => 1,
2297 'isRemovable' => 0,
2298 'isRequired' => 0,
2299 'isEditable' => 1,
2300 'label' => wpforo_phrase( 'Avatar', false ),
2301 'title' => wpforo_phrase( 'Avatar', false ),
2302 'placeholder' => wpforo_phrase( 'Avatar', false ),
2303 'name' => 'avatar',
2304 'cantBeInactive' => [],
2305 'canEdit' => $usergroupids_can_edit_fields,
2306 'canView' => WPF()->usergroup->get_groupids_by_can( 'va' ),
2307 'can' => 'va',
2308 'isSearchable' => 0,
2309 ];
2310
2311 $this->fields['user_url'] = [
2312 'fieldKey' => 'user_url',
2313 'type' => 'url',
2314 'isDefault' => 1,
2315 'isRemovable' => 0,
2316 'isRequired' => 0,
2317 'isEditable' => 1,
2318 'label' => wpforo_phrase( 'Website', false ),
2319 'title' => wpforo_phrase( 'Website', false ),
2320 'placeholder' => wpforo_phrase( 'Website', false ),
2321 'faIcon' => 'fas fa-sitemap',
2322 'name' => 'user_url',
2323 'cantBeInactive' => [],
2324 'canEdit' => $usergroupids_can_edit_fields,
2325 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmw' ),
2326 'can' => 'vmw',
2327 'isSearchable' => 1,
2328 ];
2329
2330 $this->fields['facebook'] = [
2331 'fieldKey' => 'facebook',
2332 'type' => 'url',
2333 'isDefault' => 0,
2334 'isRemovable' => 1,
2335 'isRequired' => 0,
2336 'isEditable' => 1,
2337 'label' => wpforo_phrase( 'Facebook', false ),
2338 'title' => wpforo_phrase( 'Facebook', false ),
2339 'placeholder' => wpforo_phrase( 'Facebook', false ),
2340 'faIcon' => 'fab fa-facebook',
2341 'name' => 'facebook',
2342 'cantBeInactive' => [],
2343 'canEdit' => $usergroupids_can_edit_fields,
2344 'canView' => $usergroupids_can_view_social_net,
2345 'can' => 'vmsn',
2346 'isSearchable' => 1,
2347 ];
2348
2349 $this->fields['twitter'] = [
2350 'fieldKey' => 'twitter',
2351 'type' => 'url',
2352 'isDefault' => 0,
2353 'isRemovable' => 1,
2354 'isRequired' => 0,
2355 'isEditable' => 1,
2356 'label' => wpforo_phrase( 'X.com', false ),
2357 'title' => wpforo_phrase( 'X.com', false ),
2358 'placeholder' => wpforo_phrase( 'X.com', false ),
2359 'faIcon' => 'fa-brands fa-square-x-twitter',
2360 'name' => 'twitter',
2361 'cantBeInactive' => [],
2362 'canEdit' => $usergroupids_can_edit_fields,
2363 'canView' => $usergroupids_can_view_social_net,
2364 'can' => 'vmsn',
2365 'isSearchable' => 1,
2366 ];
2367
2368 $this->fields['youtube'] = [
2369 'fieldKey' => 'youtube',
2370 'type' => 'url',
2371 'isDefault' => 0,
2372 'isRemovable' => 1,
2373 'isRequired' => 0,
2374 'isEditable' => 1,
2375 'label' => wpforo_phrase( 'YouTube', false ),
2376 'title' => wpforo_phrase( 'YouTube', false ),
2377 'placeholder' => wpforo_phrase( 'YouTube', false ),
2378 'faIcon' => 'fab fa-youtube',
2379 'name' => 'youtube',
2380 'cantBeInactive' => [],
2381 'canEdit' => $usergroupids_can_edit_fields,
2382 'canView' => $usergroupids_can_view_social_net,
2383 'can' => 'vmsn',
2384 'isSearchable' => 1,
2385 ];
2386
2387 $this->fields['vkontakte'] = [
2388 'fieldKey' => 'vkontakte',
2389 'type' => 'url',
2390 'isDefault' => 0,
2391 'isRemovable' => 1,
2392 'isRequired' => 0,
2393 'isEditable' => 1,
2394 'label' => wpforo_phrase( 'VKontakte', false ),
2395 'title' => wpforo_phrase( 'VKontakte', false ),
2396 'placeholder' => wpforo_phrase( 'VKontakte', false ),
2397 'faIcon' => 'fab fa-vk',
2398 'name' => 'vkontakte',
2399 'cantBeInactive' => [],
2400 'canEdit' => $usergroupids_can_edit_fields,
2401 'canView' => $usergroupids_can_view_social_net,
2402 'can' => 'vmsn',
2403 'isSearchable' => 1,
2404 ];
2405
2406 $this->fields['linkedin'] = [
2407 'fieldKey' => 'linkedin',
2408 'type' => 'url',
2409 'isDefault' => 0,
2410 'isRemovable' => 1,
2411 'isRequired' => 0,
2412 'isEditable' => 1,
2413 'label' => wpforo_phrase( 'LinkedIn', false ),
2414 'title' => wpforo_phrase( 'LinkedIn', false ),
2415 'placeholder' => wpforo_phrase( 'LinkedIn', false ),
2416 'faIcon' => 'fab fa-linkedin-in',
2417 'name' => 'linkedin',
2418 'cantBeInactive' => [],
2419 'canEdit' => $usergroupids_can_edit_fields,
2420 'canView' => $usergroupids_can_view_social_net,
2421 'can' => 'vmsn',
2422 'isSearchable' => 1,
2423 ];
2424
2425 $this->fields['telegram'] = [
2426 'fieldKey' => 'telegram',
2427 'type' => 'text',
2428 'isDefault' => 0,
2429 'isRemovable' => 1,
2430 'isRequired' => 0,
2431 'isEditable' => 1,
2432 'label' => wpforo_phrase( 'Telegram', false ),
2433 'title' => wpforo_phrase( 'Telegram', false ),
2434 'placeholder' => wpforo_phrase( 'Telegram', false ),
2435 'faIcon' => 'fab fa-telegram-plane',
2436 'name' => 'telegram',
2437 'cantBeInactive' => [],
2438 'canEdit' => $usergroupids_can_edit_fields,
2439 'canView' => $usergroupids_can_view_social_net,
2440 'can' => 'vmsn',
2441 'isSearchable' => 1,
2442 ];
2443
2444 $this->fields['instagram'] = [
2445 'fieldKey' => 'instagram',
2446 'type' => 'url',
2447 'isDefault' => 0,
2448 'isRemovable' => 1,
2449 'isRequired' => 0,
2450 'isEditable' => 1,
2451 'label' => wpforo_phrase( 'Instagram', false ),
2452 'title' => wpforo_phrase( 'Instagram', false ),
2453 'placeholder' => wpforo_phrase( 'Instagram', false ),
2454 'faIcon' => 'fab fa-instagram',
2455 'name' => 'instagram',
2456 'cantBeInactive' => [],
2457 'canEdit' => $usergroupids_can_edit_fields,
2458 'canView' => $usergroupids_can_view_social_net,
2459 'can' => 'vmsn',
2460 'isSearchable' => 1,
2461 ];
2462
2463 $this->fields['skype'] = [
2464 'fieldKey' => 'skype',
2465 'type' => 'text',
2466 'isDefault' => 0,
2467 'isRemovable' => 1,
2468 'isRequired' => 0,
2469 'isEditable' => 1,
2470 'label' => wpforo_phrase( 'Skype', false ),
2471 'title' => wpforo_phrase( 'Skype', false ),
2472 'placeholder' => wpforo_phrase( 'Skype', false ),
2473 'faIcon' => 'fab fa-skype',
2474 'name' => 'skype',
2475 'cantBeInactive' => [],
2476 'canEdit' => $usergroupids_can_edit_fields,
2477 'canView' => $usergroupids_can_view_social_net,
2478 'can' => 'vmsn',
2479 'isSearchable' => 1,
2480 ];
2481
2482 $this->fields['location'] = [
2483 'fieldKey' => 'location',
2484 'type' => 'select',
2485 'isDefault' => 1,
2486 'isRemovable' => 0,
2487 'isRequired' => 0,
2488 'isEditable' => 1,
2489 'label' => wpforo_phrase( 'Location', false ),
2490 'title' => wpforo_phrase( 'Location', false ),
2491 'placeholder' => wpforo_phrase( 'Location', false ),
2492 'faIcon' => 'fas fa-globe',
2493 'values' => $this->countries,
2494 'name' => 'location',
2495 'cantBeInactive' => [],
2496 'canEdit' => $usergroupids_can_edit_fields,
2497 'canView' => WPF()->usergroup->get_groupids_by_can( 'vml' ),
2498 'can' => 'vml',
2499 'isSearchable' => 1,
2500 ];
2501
2502 $this->fields['timezone'] = [
2503 'fieldKey' => 'timezone',
2504 'type' => 'select',
2505 'isDefault' => 1,
2506 'isRemovable' => 0,
2507 'isRequired' => 0,
2508 'isEditable' => 1,
2509 'label' => wpforo_phrase( 'Timezone', false ),
2510 'title' => wpforo_phrase( 'Timezone', false ),
2511 'placeholder' => wpforo_phrase( 'Timezone', false ),
2512 'faIcon' => 'fas fa-globe',
2513 'values' => $this->timezones,
2514 'name' => 'timezone',
2515 'cantBeInactive' => [],
2516 'canEdit' => $usergroupids_can_edit_fields,
2517 'canView' => $usergroupids,
2518 'can' => '',
2519 'isSearchable' => 1,
2520 ];
2521
2522 $this->fields['occupation'] = [
2523 'fieldKey' => 'occupation',
2524 'type' => 'text',
2525 'isDefault' => 1,
2526 'isRemovable' => 0,
2527 'isRequired' => 0,
2528 'isEditable' => 1,
2529 'label' => wpforo_phrase( 'Occupation', false ),
2530 'title' => wpforo_phrase( 'Occupation', false ),
2531 'placeholder' => wpforo_phrase( 'Occupation', false ),
2532 'faIcon' => 'fas fa-address-card',
2533 'name' => 'occupation',
2534 'cantBeInactive' => [],
2535 'canEdit' => $usergroupids_can_edit_fields,
2536 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmo' ),
2537 'can' => 'vmo',
2538 'isSearchable' => 1,
2539 ];
2540
2541 $this->fields['signature'] = [
2542 'fieldKey' => 'signature',
2543 'type' => 'tinymce',
2544 'wp_editor_settings' => $wp_editor_settings,
2545 'isDefault' => 1,
2546 'isRemovable' => 0,
2547 'isRequired' => 0,
2548 'isEditable' => 1,
2549 'label' => wpforo_phrase( 'Signature', false ),
2550 'title' => wpforo_phrase( 'Signature', false ),
2551 'placeholder' => wpforo_phrase( 'Signature', false ),
2552 'faIcon' => 'fas fa-address-card',
2553 'name' => 'signature',
2554 'cantBeInactive' => [],
2555 'canEdit' => $usergroupids_can_edit_fields,
2556 'canView' => WPF()->usergroup->get_groupids_by_can( 'vms' ),
2557 'can' => 'vms',
2558 'isSearchable' => 1,
2559 ];
2560
2561 $this->fields['about'] = [
2562 'fieldKey' => 'about',
2563 'type' => 'tinymce',
2564 'wp_editor_settings' => $wp_editor_settings,
2565 'isDefault' => 1,
2566 'isRemovable' => 0,
2567 'isRequired' => 0,
2568 'isEditable' => 1,
2569 'label' => wpforo_phrase( 'About Me', false ),
2570 'title' => wpforo_phrase( 'About Me', false ),
2571 'placeholder' => wpforo_phrase( 'About Me', false ),
2572 'faIcon' => 'fas fa-address-card',
2573 'name' => 'about',
2574 'cantBeInactive' => [],
2575 'canEdit' => $usergroupids_can_edit_fields,
2576 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmam' ),
2577 'can' => 'vmam',
2578 'isSearchable' => 1,
2579 ];
2580
2581 $this->fields['html_soc_net'] = [
2582 'fieldKey' => 'html_soc_net',
2583 'type' => 'html',
2584 'isDefault' => 1,
2585 'isRemovable' => 0,
2586 'isRequired' => 0,
2587 'isEditable' => 1,
2588 'label' => wpforo_phrase( 'Social Networks', false ),
2589 'title' => wpforo_phrase( 'Social Networks', false ),
2590 'placeholder' => wpforo_phrase( 'Social Networks', false ),
2591 'description' => wpforo_phrase( 'Social Networks', false ),
2592 'html' => '<div class="wpf-label">' . wpforo_phrase( 'Social Networks', false ) . '</div>',
2593 'name' => 'html_soc_net',
2594 'cantBeInactive' => [],
2595 'canEdit' => $usergroupids_can_edit_fields,
2596 'canView' => $usergroupids_can_view_social_net,
2597 'can' => 'vmsn',
2598 'isSearchable' => 0,
2599 ];
2600
2601 $this->fields = apply_filters( 'wpforo_member_after_init_fields', $this->fields );
2602 }
2603
2604 private function init_countries() {
2605 $this->countries = [
2606 "Afghanistan",
2607 "�
2608 land Islands",
2609 "Albania",
2610 "Algeria",
2611 "American Samoa",
2612 "Andorra",
2613 "Angola",
2614 "Anguilla",
2615 "Antarctica",
2616 "Antigua and Barbuda",
2617 "Argentina",
2618 "Armenia",
2619 "Aruba",
2620 "Australia",
2621 "Austria",
2622 "Azerbaijan",
2623 "Bahamas",
2624 "Bahrain",
2625 "Bangladesh",
2626 "Barbados",
2627 "Belarus",
2628 "Belgium",
2629 "Belize",
2630 "Benin",
2631 "Bermuda",
2632 "Bhutan",
2633 "Bolivia",
2634 "Bosnia and Herzegovina",
2635 "Botswana",
2636 "Bouvet Island",
2637 "Brazil",
2638 "British Indian Ocean Territory",
2639 "Brunei Darussalam",
2640 "Bulgaria",
2641 "Burkina Faso",
2642 "Burundi",
2643 "Cambodia",
2644 "Cameroon",
2645 "Canada",
2646 "Cape Verde",
2647 "Cayman Islands",
2648 "Central African Republic",
2649 "Chad",
2650 "Chile",
2651 "China",
2652 "Christmas Island",
2653 "Cocos (Keeling) Islands",
2654 "Colombia",
2655 "Comoros",
2656 "Congo",
2657 "Congo, The Democratic Republic of The",
2658 "Cook Islands",
2659 "Costa Rica",
2660 "Cote D'ivoire",
2661 "Croatia",
2662 "Cuba",
2663 "Cyprus",
2664 "Czech Republic",
2665 "Denmark",
2666 "Djibouti",
2667 "Dominica",
2668 "Dominican Republic",
2669 "Ecuador",
2670 "Egypt",
2671 "El Salvador",
2672 "Equatorial Guinea",
2673 "Eritrea",
2674 "Estonia",
2675 "Ethiopia",
2676 "Falkland Islands (Malvinas)",
2677 "Faroe Islands",
2678 "Fiji",
2679 "Finland",
2680 "France",
2681 "French Guiana",
2682 "French Polynesia",
2683 "French Southern Territories",
2684 "Gabon",
2685 "Gambia",
2686 "Georgia",
2687 "Germany",
2688 "Ghana",
2689 "Gibraltar",
2690 "Greece",
2691 "Greenland",
2692 "Grenada",
2693 "Guadeloupe",
2694 "Guam",
2695 "Guatemala",
2696 "Guernsey",
2697 "Guinea",
2698 "Guinea-bissau",
2699 "Guyana",
2700 "Haiti",
2701 "Heard Island and Mcdonald Islands",
2702 "Holy See (Vatican City State)",
2703 "Honduras",
2704 "Hong Kong",
2705 "Hungary",
2706 "Iceland",
2707 "India",
2708 "Indonesia",
2709 "Iran, Islamic Republic of",
2710 "Iraq",
2711 "Ireland",
2712 "Isle of Man",
2713 "Israel",
2714 "Italy",
2715 "Jamaica",
2716 "Japan",
2717 "Jersey",
2718 "Jordan",
2719 "Kazakhstan",
2720 "Kenya",
2721 "Kiribati",
2722 "Korea, Democratic People's Republic of",
2723 "Korea, Republic of",
2724 "Kuwait",
2725 "Kyrgyzstan",
2726 "Lao People's Democratic Republic",
2727 "Latvia",
2728 "Lebanon",
2729 "Lesotho",
2730 "Liberia",
2731 "Libyan Arab Jamahiriya",
2732 "Liechtenstein",
2733 "Lithuania",
2734 "Luxembourg",
2735 "Macao",
2736 "Macedonia, The Former Yugoslav Republic of",
2737 "Madagascar",
2738 "Malawi",
2739 "Malaysia",
2740 "Maldives",
2741 "Mali",
2742 "Malta",
2743 "Marshall Islands",
2744 "Martinique",
2745 "Mauritania",
2746 "Mauritius",
2747 "Mayotte",
2748 "Mexico",
2749 "Micronesia, Federated States of",
2750 "Moldova, Republic of",
2751 "Monaco",
2752 "Mongolia",
2753 "Montenegro",
2754 "Montserrat",
2755 "Morocco",
2756 "Mozambique",
2757 "Myanmar",
2758 "Namibia",
2759 "Nauru",
2760 "Nepal",
2761 "Netherlands",
2762 "Netherlands Antilles",
2763 "New Caledonia",
2764 "New Zealand",
2765 "Nicaragua",
2766 "Niger",
2767 "Nigeria",
2768 "Niue",
2769 "Norfolk Island",
2770 "Northern Mariana Islands",
2771 "Norway",
2772 "Oman",
2773 "Pakistan",
2774 "Palau",
2775 "Palestinian Territory, Occupied",
2776 "Panama",
2777 "Papua New Guinea",
2778 "Paraguay",
2779 "Peru",
2780 "Philippines",
2781 "Pitcairn",
2782 "Poland",
2783 "Portugal",
2784 "Puerto Rico",
2785 "Qatar",
2786 "Reunion",
2787 "Romania",
2788 "Russian Federation",
2789 "Rwanda",
2790 "Saint Helena",
2791 "Saint Kitts and Nevis",
2792 "Saint Lucia",
2793 "Saint Pierre and Miquelon",
2794 "Saint Vincent and The Grenadines",
2795 "Samoa",
2796 "San Marino",
2797 "Sao Tome and Principe",
2798 "Saudi Arabia",
2799 "Senegal",
2800 "Serbia",
2801 "Seychelles",
2802 "Sierra Leone",
2803 "Singapore",
2804 "Slovakia",
2805 "Slovenia",
2806 "Solomon Islands",
2807 "Somalia",
2808 "South Africa",
2809 "South Georgia and The South Sandwich Islands",
2810 "Spain",
2811 "Sri Lanka",
2812 "Sudan",
2813 "Suriname",
2814 "Svalbard and Jan Mayen",
2815 "Swaziland",
2816 "Sweden",
2817 "Switzerland",
2818 "Syrian Arab Republic",
2819 "Taiwan, Province of China",
2820 "Tajikistan",
2821 "Tanzania, United Republic of",
2822 "Thailand",
2823 "Timor-leste",
2824 "Togo",
2825 "Tokelau",
2826 "Tonga",
2827 "Trinidad and Tobago",
2828 "Tunisia",
2829 "Turkey",
2830 "Turkmenistan",
2831 "Turks and Caicos Islands",
2832 "Tuvalu",
2833 "Uganda",
2834 "Ukraine",
2835 "United Arab Emirates",
2836 "United Kingdom",
2837 "United States",
2838 "United States Minor Outlying Islands",
2839 "Uruguay",
2840 "Uzbekistan",
2841 "Vanuatu",
2842 "Venezuela",
2843 "Viet Nam",
2844 "Virgin Islands, British",
2845 "Virgin Islands, U.S.",
2846 "Wallis and Futuna",
2847 "Western Sahara",
2848 "Yemen",
2849 "Zambia",
2850 "Zimbabwe",
2851 ];
2852 }
2853
2854 private function init_timezones() {
2855 $this->timezones = timezone_identifiers_list();
2856 $offset_range = [
2857 - 12,
2858 - 11.5,
2859 - 11,
2860 - 10.5,
2861 - 10,
2862 - 9.5,
2863 - 9,
2864 - 8.5,
2865 - 8,
2866 - 7.5,
2867 - 7,
2868 - 6.5,
2869 - 6,
2870 - 5.5,
2871 - 5,
2872 - 4.5,
2873 - 4,
2874 - 3.5,
2875 - 3,
2876 - 2.5,
2877 - 2,
2878 - 1.5,
2879 - 1,
2880 - 0.5,
2881 0,
2882 0.5,
2883 1,
2884 1.5,
2885 2,
2886 2.5,
2887 3,
2888 3.5,
2889 4,
2890 4.5,
2891 5,
2892 5.5,
2893 5.75,
2894 6,
2895 6.5,
2896 7,
2897 7.5,
2898 8,
2899 8.5,
2900 8.75,
2901 9,
2902 9.5,
2903 10,
2904 10.5,
2905 11,
2906 11.5,
2907 12,
2908 12.75,
2909 13,
2910 13.75,
2911 14,
2912 ];
2913 foreach( $offset_range as $offset ) {
2914 if( 0 <= $offset ) {
2915 $offset_name = '+' . $offset;
2916 } else {
2917 $offset_name = (string) $offset;
2918 }
2919
2920 $offset_value = $offset_name;
2921 $offset_value = 'UTC' . $offset_value;
2922 $this->timezones[] = 'UTC/' . $offset_value;
2923 }
2924
2925 $zones = $this->timezones;
2926 $timezones = [];
2927 foreach( $zones as $zone ) {
2928 if( strpos( (string) $zone, '/' ) === false ) continue;
2929
2930 $zone = str_replace( '_', ' ', $zone );
2931
2932 $group = function_exists( 'mb_substr' ) ? mb_substr( (string) $zone, 0, strpos( (string) $zone, '/' ) ) : substr( (string) $zone, 0, strpos( (string) $zone, '/' ) );
2933 $index = function_exists( 'mb_strlen' ) ? mb_strlen( (string) $group ) + 1 : strlen( (string) $group ) + 1;
2934 $optionValue = substr( (string) $zone, $index );
2935
2936 if( strpos( (string) $optionValue, 'UTC' ) !== false ) {
2937 $optionTitle = str_replace( [ '.25', '.5', '.75', ], [ ':15', ':30', ':45', ], $optionValue );
2938 $optionValue = "$optionValue=>$optionTitle";
2939 } else {
2940 $optionValue = "$zone=>$optionValue";
2941 }
2942
2943 $timezones[ $group ][] = $optionValue;
2944 }
2945
2946 $this->timezones = $timezones;
2947 }
2948
2949 public function get_fields( $only_defaults = false ) {
2950 $this->init_fields();
2951 $fields = $this->fields;
2952 if( $only_defaults ) {
2953 foreach( $fields as $k => $v ) if( ! wpfval( $v, 'isDefault' ) ) unset( $fields[ $k ] );
2954 } else {
2955 $this->fields = $fields = apply_filters( 'wpforo_get_fields', $fields );
2956 }
2957
2958 return $fields;
2959 }
2960
2961 public function get_field( $key ) {
2962 if( is_string( $key ) ) {
2963 $this->init_fields();
2964
2965 return (array) wpfval( $this->fields, $key );
2966 } elseif( $this->is_field( $key ) ) {
2967 return $key;
2968 }
2969
2970 return [];
2971 }
2972
2973 public function is_field( $field ) {
2974 return wpfval( $field, 'fieldKey' ) && wpfval( $field, 'type' ) && wpfkey( $field, 'isDefault' );
2975 }
2976
2977 public function get_field_key( $field ) {
2978 return is_string( $field ) ? $field : (string) wpfval( $field, 'fieldKey' );
2979 }
2980
2981 public function fields_structure_full_array( $fields, $need_password = null ) {
2982 if( is_string( $fields ) ) $fields = maybe_unserialize( $fields );
2983 $fs = [ [ [] ] ];
2984 if( ! is_array( $fields ) ) return $fs;
2985 if( is_null( $need_password ) ) {
2986 foreach( $fields as $kr => $row ) {
2987 if( is_array( $row ) ) {
2988 foreach( $row as $kc => $cols ) {
2989 if( is_array( $cols ) ) {
2990 foreach( $cols as $field ) {
2991 $field_key = $this->get_field_key( $field );
2992 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
2993 }
2994 }
2995 }
2996 }
2997 }
2998 } else {
2999 $has_password = false;
3000 foreach( $fields as $kr => $row ) {
3001 if( is_array( $row ) ) {
3002 foreach( $row as $kc => $cols ) {
3003 if( is_array( $cols ) ) {
3004 foreach( $cols as $field ) {
3005 $field_key = $this->get_field_key( $field );
3006 if( $field_key === 'user_pass' ) {
3007 if( $need_password ) {
3008 $has_password = true;
3009 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3010 }
3011 } else {
3012 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3013 }
3014 }
3015 }
3016 }
3017 }
3018 }
3019 if( $need_password && ! $has_password ) $fs[][][] = $this->get_field( 'user_pass' );
3020 }
3021
3022 return $fs;
3023 }
3024
3025 public function get_register_fields_structure( $only_defaults = false ) {
3026 $need_password = ! wpforo_setting( 'authorization', 'user_register_email_confirm' );
3027 $regform = [ 'user_login', 'user_email' ];
3028 if( $need_password ) $regform[] = 'user_pass';
3029 $fields = [ [ $regform ] ];
3030 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_register_fields', $fields );
3031
3032 return $fields;
3033 }
3034
3035 public function get_register_fields( $only_defaults = false ) {
3036 return $this->fields_structure_full_array( $this->get_register_fields_structure( $only_defaults ), ! wpforo_setting( 'authorization', 'user_register_email_confirm' ) );
3037 }
3038
3039 public function get_account_fields_structure( $only_defaults = false ) {
3040 $fields = [
3041 [
3042 [
3043 'user_login',
3044 'display_name',
3045 'user_nicename',
3046 'user_email',
3047 'title',
3048 'groupid',
3049 'avatar',
3050 'about',
3051 'user_url',
3052 'occupation',
3053 'signature',
3054 ],
3055 ],
3056 [
3057 [
3058 'html_soc_net',
3059 ],
3060 [
3061 'facebook',
3062 'linkedin',
3063 'instagram',
3064 'vkontakte',
3065 ],
3066 [
3067 'twitter',
3068 'youtube',
3069 'telegram',
3070 'skype',
3071 ],
3072 ],
3073 [
3074 [
3075 'location',
3076 'timezone',
3077 'user_pass',
3078 ],
3079 ],
3080 ];
3081 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_account_fields', $fields );
3082
3083 return $fields;
3084 }
3085
3086 public function get_account_fields( $only_defaults = false ) {
3087 return $this->fields_structure_full_array( $this->get_account_fields_structure( $only_defaults ) );
3088 }
3089
3090 public function get_profile_fields_structure( $only_defaults = false ) {
3091 $fields = [
3092 [
3093 [
3094 'about',
3095 'user_url',
3096 ],
3097 ],
3098 [
3099 [
3100 'location',
3101 'timezone',
3102 'occupation',
3103 'signature',
3104 ],
3105 ],
3106 [
3107 [
3108 'html_soc_net',
3109 ],
3110 ],
3111 [
3112 [
3113 'facebook',
3114 'linkedin',
3115 'instagram',
3116 'vkontakte',
3117 ],
3118 [
3119 'twitter',
3120 'youtube',
3121 'telegram',
3122 'skype',
3123 ],
3124 ],
3125 ];
3126 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_profile_fields', $fields );
3127
3128 return $fields;
3129 }
3130
3131 public function get_profile_fields( $only_defaults = false ) {
3132 return $this->fields_structure_full_array( $this->get_profile_fields_structure( $only_defaults ) );
3133 }
3134
3135 public function get_search_fields_structure( $only_defaults = false ) {
3136 $fields = [ [ [ 'display_name', 'user_nicename' ] ] ];
3137 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_search_fields', $fields );
3138
3139 return $fields;
3140 }
3141
3142 public function get_search_fields( $only_defaults = false ) {
3143 $fields = $this->fields_structure_full_array( $this->get_search_fields_structure( $only_defaults ) );
3144 foreach( $fields as $row_key => $row ) {
3145 foreach( $row as $col_key => $col ) {
3146 foreach( $col as $field_key => $field ) {
3147 if( $this->is_field( $field ) ) {
3148 $fields[ $row_key ][ $col_key ][ $field_key ]['isRequired'] = 0;
3149 $fields[ $row_key ][ $col_key ][ $field_key ]['class'] = 'wpf-member-search-field';
3150 if( in_array( $field['type'], [ 'text', 'textarea', 'email', 'url' ], true ) ) {
3151 $fields[ $row_key ][ $col_key ][ $field_key ]['type'] = 'search';
3152 }
3153 }
3154 }
3155 }
3156 }
3157
3158 return $fields;
3159 }
3160
3161 public function get_search_fields_names( $only_defaults = false ) {
3162 $names = [];
3163 $fields = $this->get_search_fields( $only_defaults );
3164
3165 foreach( $fields as $row ) {
3166 foreach( $row as $col ) {
3167 foreach( $col as $field ) {
3168 if( $only_defaults && ! $field['isDefault'] ) continue;
3169 $names[] = $field['name'];
3170 }
3171 }
3172 }
3173
3174 return $names;
3175 }
3176
3177 public function set_guest_cookies( $args ) {
3178 if( ! wpforo_setting( 'legal', 'cookies' ) ) return;
3179 if( isset( $args['name'] ) && isset( $args['email'] ) ) {
3180 $comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
3181 $secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
3182 setcookie( 'comment_author_' . COOKIEHASH, $args['name'], time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
3183 setcookie( 'comment_author_email_' . COOKIEHASH, $args['email'], time() + $comment_cookie_lifetime, COOKIEPATH, COOKIE_DOMAIN, $secure );
3184
3185 WPF()->current_user_display_name = $args['name'];
3186 WPF()->current_user_email = $args['email'];
3187 }
3188 }
3189
3190 public function get_guest_cookies() {
3191 $guest = [ 'name' => '', 'email' => '' ];
3192 if( wpforo_setting( 'legal', 'cookies' ) ) {
3193 if( ! WPF()->current_userid && WPF()->current_user_email ) {
3194 $guest['name'] = WPF()->current_user_display_name;
3195 $guest['email'] = WPF()->current_user_email;
3196 } else {
3197 $guest_cookies = wp_get_current_commenter();
3198 $guest['name'] = ( isset( $guest_cookies['comment_author'] ) ) ? $guest_cookies['comment_author'] : '';
3199 $guest['email'] = ( isset( $guest_cookies['comment_author_email'] ) ) ? $guest_cookies['comment_author_email'] : '';
3200 }
3201 }
3202
3203 return $guest;
3204 }
3205
3206 public function set_is_email_confirmed( $userid, $status ) {
3207 if( false !== WPF()->db->update( WPF()->tables->profiles, [ 'is_email_confirmed' => intval( $status ) ], [ 'userid' => wpforo_bigintval( $userid ) ], [ '%d' ], [ '%d' ] ) ) {
3208 WPF()->notice->add( 'Email has been confirmed', 'success' );
3209
3210 return true;
3211 }
3212 WPF()->notice->add( 'Email confirm error', 'error' );
3213
3214 return false;
3215 }
3216
3217 public function get_is_email_confirmed( $userid ) {
3218 $sql = "SELECT `is_email_confirmed` FROM `" . WPF()->tables->profiles . "` WHERE `userid` = %d";
3219
3220 return (bool) WPF()->db->get_var( WPF()->db->prepare( $sql, $userid ) );
3221 }
3222
3223 /**
3224 * @param int $userid
3225 *
3226 * @return int
3227 */
3228 public function get_groupid( $userid ) {
3229 return (int) WPF()->db->get_var(
3230 WPF()->db->prepare(
3231 "SELECT `groupid`
3232 FROM `" . WPF()->tables->profiles . "`
3233 WHERE `userid` = %d",
3234 $userid
3235 )
3236 );
3237 }
3238
3239
3240 /**
3241 * @param int $userid
3242 * @param boolean $array
3243 *
3244 * @return string|array|null
3245 */
3246 public function get_secondary_groupids( $userid, $array = true ) {
3247 $secondary_groupids = WPF()->db->get_var(
3248 WPF()->db->prepare( "SELECT `secondary_groupids`
3249 FROM `" . WPF()->tables->profiles . "`
3250 WHERE `userid` = %d",
3251 $userid
3252 )
3253 );
3254
3255 if( $array && !empty($secondary_groupids) ) return explode( ',', $secondary_groupids );
3256
3257 return $secondary_groupids;
3258 }
3259
3260 public function set_groupid( $userid, $groupid ) {
3261 $userid = wpforo_bigintval( $userid );
3262 $groupid = intval( $groupid );
3263 if( $userid && $groupid ) {
3264 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `groupid` = %d WHERE `userid` = %d";
3265 if( false !== WPF()->db->query( WPF()->db->prepare( $sql, $groupid, $userid ) ) ) {
3266 $this->reset( $userid );
3267 do_action( 'wpforo_set_groupid', $userid, $groupid );
3268
3269 return true;
3270 }
3271 }
3272
3273 return false;
3274 }
3275
3276 /**
3277 * @param int $userid
3278 * @param array|int $groupids
3279 *
3280 * @return bool
3281 */
3282 public function set_secondary_groupids( $userid, $groupids ) {
3283 $userid = wpforo_bigintval( $userid );
3284 if( $userid ) {
3285 $groupids = implode( ',', array_unique( array_filter( array_map( 'intval', (array) $groupids ) ) ) );
3286 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `secondary_groupids` = %s WHERE `userid` = %d";
3287 if( false !== WPF()->db->query( WPF()->db->prepare( $sql, $groupids, $userid ) ) ) {
3288 $this->reset( $userid );
3289
3290 return true;
3291 }
3292 }
3293
3294 return false;
3295 }
3296
3297 /**
3298 * @param int $userid
3299 * @param array|int $groupids
3300 *
3301 * @return bool
3302 */
3303 public function append_secondary_groupids( $userid, $groupids ) {
3304 $userid = wpforo_bigintval( $userid );
3305 if( $userid ) {
3306 if( $member = $this->get_member( $userid ) ) {
3307 $groupids = array_filter( array_map( 'intval', (array) $groupids ) );
3308 $groupids = array_merge( $member['secondary_groupids'], $groupids );
3309
3310 return $this->set_secondary_groupids( $userid, $groupids );
3311 }
3312 }
3313
3314 return false;
3315 }
3316
3317 public function after_register_new_user( $userid ) {
3318 if(
3319 wpforo_setting( 'authorization', 'manually_approval' )
3320 || (int) trim( (string) get_user_meta( $userid, 'default_password_nag', true ) )
3321 ){
3322 $this->update_profile_fields( $userid, [ 'status' => 'inactive' ], false );
3323 }
3324 }
3325
3326 public function after_password_reset( $user ) {
3327 $status = $this->get_status( $user->ID );
3328 if( $status !== 'banned' ){
3329 $data = [ 'status' => 'active', 'is_email_confirmed' => 1 ];
3330 if( wpforo_setting( 'authorization', 'manually_approval' ) ) $data['status'] = $status;
3331 $this->update_profile_fields( $user->ID, $data, false );
3332 $this->reset( $user->ID );
3333 }
3334 }
3335
3336 public function wp_login( $user_login, $user ) {
3337 $this->inactive_to_active( wpforo_bigintval( $user->ID ), $user_login );
3338 }
3339
3340 public function get_distinct_status() {
3341 $sql = "SELECT DISTINCT `status` as statuses FROM `" . WPF()->tables->profiles . "`";
3342
3343 return WPF()->db->get_col( $sql );
3344 }
3345
3346 /**
3347 * @param array $args
3348 *
3349 * @return array selected userids
3350 */
3351 public function get_userids( $args ) {
3352 $sql = "SELECT `userid` FROM `" . WPF()->tables->profiles . "`";
3353 if( $args ) {
3354 $wheres = [];
3355 foreach( $args as $field => $value ) {
3356 $wheres[] = "`" . $field . "` = '" . esc_sql( $value ) . "'";
3357 }
3358 if( $wheres ) $sql .= " WHERE " . implode( " AND ", $wheres );
3359 }
3360
3361 $userids = WPF()->db->get_col( $sql );
3362
3363 return apply_filters( 'wpforo_member_after_get_userids', $userids );
3364 }
3365
3366 public function get_inlist_enabled_statuses(){
3367 return wpforo_setting( 'members', 'hide_inactive' ) ? ['active'] : ['active', 'inactive', 'banned'];
3368 }
3369
3370 /**
3371 * @param int $userid
3372 *
3373 * @return int
3374 */
3375 public function calc_approved_posts( $userid ) {
3376 if( $userid = wpforo_bigintval( $userid ) ){
3377 $sqls = [];
3378 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
3379 $sqls[] = WPF()->db->prepare(
3380 "SELECT COUNT(*)
3381 FROM `$table`
3382 WHERE `status` = 0
3383 AND `userid` = %d",
3384 $userid
3385 );
3386 }
3387
3388 if( $sqls ){
3389 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3390 }
3391 }
3392
3393 return 0;
3394 }
3395
3396 /**
3397 * @param int $userid
3398 *
3399 * @return int
3400 */
3401 public function calc_approved_topics( $userid ) {
3402 if( $userid = wpforo_bigintval( $userid ) ){
3403 $sqls = [];
3404 foreach( WPF()->get_active_boards_tables( 'topics') as $table ){
3405 $sqls[] = WPF()->db->prepare(
3406 "SELECT COUNT(*)
3407 FROM `$table`
3408 WHERE `status` = 0
3409 AND `userid` = %d",
3410 $userid
3411 );
3412 }
3413
3414 if( $sqls ){
3415 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3416 }
3417 }
3418
3419 return 0;
3420 }
3421
3422 /**
3423 * @param int $userid
3424 *
3425 * @return int
3426 */
3427 public function calc_approved_questions( $userid ) {
3428 if( $userid = wpforo_bigintval( $userid ) ){
3429 $sqls = [];
3430 foreach( WPF()->get_active_boards_tables( 'topics') as $table ){
3431 if( $forumids = Forums::get_forumids( str_replace( 'topics', 'forums', $table ), 3 ) ){
3432 $sqls[] = WPF()->db->prepare(
3433 "SELECT COUNT(*)
3434 FROM `$table`
3435 WHERE `status` = 0
3436 AND `userid` = %d
3437 AND `forumid` IN( ". implode(',', $forumids) ." )",
3438 $userid
3439 );
3440 }
3441 }
3442
3443 if( $sqls ){
3444 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3445 }
3446 }
3447
3448 return 0;
3449 }
3450
3451 /**
3452 * @param int $userid
3453 *
3454 * @return int
3455 */
3456 public function calc_approved_answers( $userid ) {
3457 if( $userid = wpforo_bigintval( $userid ) ){
3458 $sqls = [];
3459 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
3460 if( $forumids = Forums::get_forumids( str_replace( 'posts', 'forums', $table ), 3 ) ){
3461 $sqls[] = WPF()->db->prepare(
3462 "SELECT COUNT(*)
3463 FROM `$table`
3464 WHERE `status` = 0
3465 AND `is_first_post` = 0
3466 AND `parentid` = 0
3467 AND `userid` = %d
3468 AND `forumid` IN( ". implode(',', $forumids) ." )",
3469 $userid
3470 );
3471 }
3472 }
3473
3474 if( $sqls ){
3475 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3476 }
3477 }
3478
3479 return 0;
3480 }
3481
3482 /**
3483 * @param int $userid
3484 *
3485 * @return int
3486 */
3487 public function calc_approved_comments( $userid ) {
3488 if( $userid = wpforo_bigintval( $userid ) ){
3489 $sqls = [];
3490 foreach( WPF()->get_active_boards_tables( 'posts') as $table ){
3491 if( $forumids = Forums::get_forumids( str_replace( 'posts', 'forums', $table ), 3 ) ){
3492 $sqls[] = WPF()->db->prepare(
3493 "SELECT COUNT(*)
3494 FROM `$table`
3495 WHERE `status` = 0
3496 AND `is_first_post` = 0
3497 AND `parentid` <> 0
3498 AND `userid` = %d
3499 AND `forumid` IN( ". implode(',', $forumids) ." )",
3500 $userid
3501 );
3502 }
3503 }
3504
3505 if( $sqls ){
3506 return (int) WPF()->db->get_var( "SELECT SUM(`COUNT(*)`) FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp" );
3507 }
3508 }
3509
3510 return 0;
3511 }
3512
3513 /**
3514 * @param int $userid
3515 *
3516 * @return array
3517 */
3518 public function calc_reactions_in( $userid ) {
3519 $reactions_in = array_map( '__return_zero', array_flip( Reactions::get_type_list() ) );
3520 if( $userid = wpforo_bigintval( $userid ) ){
3521 $sqls = [];
3522 foreach( WPF()->get_active_boards_tables( 'reactions') as $table ){
3523 $sqls[] = WPF()->db->prepare(
3524 "SELECT `type`
3525 FROM `$table`
3526 WHERE `post_userid` = %d",
3527 $userid
3528 );
3529 }
3530
3531 if( $sqls ){
3532 $r = (array) WPF()->db->get_results( "SELECT `type`, COUNT(`type`) as `count` FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp GROUP BY `type`", ARRAY_A );
3533 foreach( $r as $_r ) $reactions_in[$_r['type']] = intval( $_r['count'] );
3534 }
3535 }
3536
3537 return $reactions_in;
3538 }
3539
3540 /**
3541 * @param int $userid
3542 *
3543 * @return array
3544 */
3545 public function calc_reactions_out( $userid ) {
3546 $reactions_out = array_map( '__return_zero', array_flip( Reactions::get_type_list() ) );
3547 if( $userid = wpforo_bigintval( $userid ) ){
3548 $sqls = [];
3549 foreach( WPF()->get_active_boards_tables( 'reactions') as $table ){
3550 $sqls[] = WPF()->db->prepare(
3551 "SELECT `type`
3552 FROM `$table`
3553 WHERE `userid` = %d",
3554 $userid
3555 );
3556 }
3557
3558 if( $sqls ){
3559 $r = (array) WPF()->db->get_results( "SELECT `type`, COUNT(`type`) as `count` FROM (". implode( ' UNION ALL ', $sqls ) .") AS temp GROUP BY `type`", ARRAY_A );
3560 foreach( $r as $_r ) $reactions_out[$_r['type']] = intval( $_r['count'] );
3561 }
3562 }
3563
3564 return $reactions_out;
3565 }
3566
3567 /**
3568 * @param int $userid
3569 *
3570 * @return void
3571 */
3572 public function rebuild_stats( $userid ) {
3573 $posts = $this->calc_approved_posts( $userid );
3574 $topics = $this->calc_approved_topics( $userid );
3575 $questions = $this->calc_approved_questions( $userid );
3576 $answers = $this->calc_approved_answers( $userid );
3577 $comments = $this->calc_approved_comments( $userid );
3578 $reactions_in = $this->calc_reactions_in( $userid );
3579 $reactions_out = $this->calc_reactions_out( $userid );
3580 $points = $this->calc_points( compact( 'posts', 'topics', 'questions', 'answers', 'comments', 'reactions_in', 'reactions_out' ) );
3581
3582 if(WPF()->db->update(
3583 WPF()->tables->profiles,
3584 [
3585 'posts' => $posts,
3586 'topics' => $topics,
3587 'questions' => $questions,
3588 'answers' => $answers,
3589 'comments' => $comments,
3590 'reactions_in' => json_encode( $reactions_in ),
3591 'reactions_out' => json_encode( $reactions_out ),
3592 'points' => $points,
3593 ],
3594 [ 'userid' => $userid ],
3595 ['%d','%d','%d','%d','%d','%s','%s','%d'],
3596 '%d'
3597 )){
3598 $this->reset( $userid );
3599 }
3600 }
3601
3602 public function after_add_topic( $topic ) {
3603 if( !intval($topic['status']) ) $this->rebuild_stats( $topic['userid'] );
3604 }
3605
3606 public function after_delete_topic( $topic ) {
3607 if( !intval($topic['status']) ) $this->rebuild_stats( $topic['userid'] );
3608 }
3609
3610 public function after_topic_status_update( $topic ) {
3611 $this->rebuild_stats( $topic['userid'] );
3612 }
3613
3614 public function before_merge_topic( $target, $current, $postids ){
3615 $sql = "SELECT DISTINCT `userid` FROM `". WPF()->tables->posts ."` WHERE `topicid` = %d";
3616 $sql = WPF()->db->prepare( $sql, $current['topicid'] );
3617 if( $postids ) $sql .= " AND `postid` IN(" . implode( ',', $postids ) . ")";
3618 $this->touched_userids = array_merge( $this->touched_userids, WPF()->db->get_col( $sql ) );
3619 }
3620
3621 public function after_merge_topic(){
3622 foreach( array_unique(array_filter( $this->touched_userids )) as $userid ) $this->rebuild_stats( $userid );
3623 }
3624
3625 public function after_move_topic( $topic ) {
3626 $sql = "SELECT DISTINCT `userid` FROM `". WPF()->tables->posts ."` WHERE `topicid` = %d";
3627 $sql = WPF()->db->prepare( $sql, $topic['topicid'] );
3628 foreach( WPF()->db->get_col( $sql ) as $userid ) $this->rebuild_stats( $userid );
3629 }
3630
3631 public function after_add_post( $post ){
3632 if( !intval( $post['status'] ) ) $this->rebuild_stats( $post['userid'] );
3633 }
3634
3635 public function after_delete_post( $post ) {
3636 if( !intval( $post['status'] ) ) $this->rebuild_stats( $post['userid'] );
3637 }
3638
3639 public function after_post_status_update( $post ) {
3640 $this->rebuild_stats( $post['userid'] );
3641 }
3642
3643 public function after_add_reaction( $reaction ) {
3644 $this->rebuild_stats( $reaction['userid'] );
3645 $this->rebuild_stats( $reaction['post_userid'] );
3646 }
3647
3648 public function after_edit_reaction( $fields, $where ) {
3649 $field_userid = wpfval( $fields, 'userid' );
3650 $field_post_userid = wpfval( $fields, 'post_userid' );
3651 if( $field_userid || $field_post_userid ){
3652 $userids = [ $field_userid, $field_post_userid, wpfval( $where, 'userid' ), wpfval( $where, 'post_userid' ) ];
3653 $userids = array_filter( $userids );
3654 $userids = array_unique( $userids );
3655 foreach( $userids as $userid ) $this->rebuild_stats( $userid );
3656 }
3657 }
3658
3659 public function before_delete_reaction( $args, $operator ){
3660 $reactions = WPF()->reaction->get_reactions( $args, $operator );
3661 foreach( $reactions as $reaction ) {
3662 $this->touched_userids[] = $reaction['userid'];
3663 $this->touched_userids[] = $reaction['post_userid'];
3664 }
3665 }
3666
3667 public function after_delete_reaction(){
3668 foreach( array_unique(array_filter( $this->touched_userids )) as $userid ) $this->rebuild_stats( $userid );
3669 }
3670
3671 public function after_delete_user( $userid, $reassign ) {
3672 if( $reassign ) $this->rebuild_stats( $reassign );
3673 }
3674
3675 public function after_activate_user( $userid ){
3676 $user = get_user_by( 'ID', $userid );
3677 if( $user ){
3678 $sbj = wpforo_setting( 'email', 'after_user_approve_email_subject' );
3679 $msg = wpforo_setting( 'email', 'after_user_approve_email_message' );
3680 $blogname = get_option('blogname', '');
3681 $login_url = wpforo_login_url( '' );
3682 $login_link = sprintf( '<a href="%1$s">%2$s</a>', $login_url, $blogname );
3683
3684 $sbj = str_replace( [ '[blogname]', '[user_login]', '[login_link]', '[login_url]' ], [ $blogname, $user->user_login, $login_link, $login_url ], $sbj );
3685 $msg = str_replace( [ '[blogname]', '[user_login]', '[login_link]', '[login_url]' ], [ $blogname, $user->user_login, $login_link, $login_url ], $msg );
3686 wpforo_send_email( $user->user_email, $sbj, $msg );
3687 }
3688 }
3689
3690 public function get_activity_url( $filter = '', $boardid = null, $arg = null ) {
3691 if( !$arg ) $arg = WPF()->current_object['user'];
3692 $url = rtrim( $this->get_profile_url( $arg, 'activity' ), '/' );
3693 if( is_wpforo_multiboard() ){
3694 if( is_null( $boardid ) ) $boardid = wpfkey( WPF()->GET, 'boardid' ) ? (int) wpfval( WPF()->GET, 'boardid' ) : WPF()->board->get_current( 'boardid' );
3695 if( $filter ){
3696 $url .= sprintf( '/?boardid=%1$d&filter=%2$s', $boardid, $filter);
3697 }else{
3698 $url .= sprintf( '/?boardid=%1$d', $boardid);
3699 }
3700 }elseif( $filter ){
3701 $url .= sprintf( '/?filter=%1$s', $filter);
3702 }
3703 return WPF()->user_trailingslashit( $url );
3704 }
3705
3706 public function get_favored_url( $filter = '', $boardid = null, $arg = null ) {
3707 if( !$arg ) $arg = WPF()->current_object['user'];
3708 $url = rtrim( $this->get_profile_url( $arg, 'favored' ), '/' );
3709 if( is_wpforo_multiboard() ){
3710 if( is_null( $boardid ) ) $boardid = wpfkey( WPF()->GET, 'boardid' ) ? (int) wpfval( WPF()->GET, 'boardid' ) : WPF()->board->get_current( 'boardid' );
3711 if( $filter ){
3712 $url .= sprintf( '/?boardid=%1$d&filter=%2$s', $boardid, $filter);
3713 }else{
3714 $url .= sprintf( '/?boardid=%1$d', $boardid);
3715 }
3716 }elseif( $filter ){
3717 $url .= sprintf( '/?filter=%1$s', $filter);
3718 }
3719 return WPF()->user_trailingslashit( $url );
3720 }
3721
3722 public function get_newest_member( $status_filter = true ){
3723 if( ! ($visible_usergroup_ids = WPF()->usergroup->get_visible_usergroup_ids()) ) return [];
3724
3725 $groupids = implode( ", ", $visible_usergroup_ids );
3726
3727 if( $status_filter ){
3728 $status = implode( "', '", $this->get_inlist_enabled_statuses() );
3729 $sql = "SELECT `userid` FROM `". WPF()->tables->profiles ."`
3730 WHERE `status` IN ('" . $status . "')
3731 AND `groupid` IN (" . $groupids . ")
3732 ORDER BY `userid` DESC LIMIT 1";
3733 } else {
3734 $sql = "SELECT `userid` FROM `". WPF()->tables->profiles ."`
3735 WHERE `groupid` IN (" . $groupids . ")
3736 ORDER BY `userid` DESC LIMIT 1";
3737 }
3738
3739 $memberid = WPF()->db->get_var( $sql );
3740 $member = wpforo_member( $memberid );
3741
3742 if( empty( $member ) ){
3743
3744 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");
3745
3746 $memberid = WPF()->db->get_var( $sql );
3747 $member = wpforo_member( $memberid );
3748
3749 if( empty( $member ) ){
3750 if( $status_filter ){
3751 $members = $this->get_members( [ 'orderby' => 'userid', 'status' => [ 'active' ], 'order' => 'DESC', 'row_count' => 1, 'groupids' => $visible_usergroup_ids ] );
3752 } else {
3753 $members = $this->get_members( [ 'orderby' => 'userid', 'order' => 'DESC', 'row_count' => 1, 'groupids' => $visible_usergroup_ids ] );
3754 }
3755 if( isset( $members[0] ) && ! empty( $members[0] ) ) {
3756 $member = $members[0];
3757 } else {
3758 $member = [];
3759 }
3760 }
3761 }
3762 $member['profile_url'] = wpfval($member, 'profile_url') ?: $this->get_profile_url( $memberid );
3763 return $member;
3764 }
3765 }
3766