PluginProbe
wpForo Forum / 3.0.9
wpForo Forum v3.0.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 3.0.9, at classes/Members.php

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