PluginProbe
wpForo Forum / 3.0.5
wpForo Forum v3.0.5
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.5, at classes/Members.php

4,301 lines 177.8 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 $secondary_groupids = WPF()->usergroup->get_secondary_groupids();
817 foreach( $sgids as $sgid ) {
818 if( in_array( $sgid, [ 1, 2, 4 ], true ) ) {
819 $user['secondary_groupids'] = array_diff( $user['secondary_groupids'], [ $sgid ] );
820 }
821 if( ! in_array( $sgid, $secondary_groupids ) ) {
822 $user['secondary_groupids'] = array_diff( $user['secondary_groupids'], [ $sgid ] );
823 }
824 }
825 }
826 } else {
827 unset( $user['secondary_groupids'] );
828 }
829 }
830
831 //Sanitize fields
832 $user = WPF()->form->sanitize( $user, $form_fields );
833
834 //Update User Fields
835 if( ! empty( $user ) && ( in_array( 'full', $type ) || in_array( 'user', $type ) ) ) {
836 $result_user = $this->update_user_fields( $userid, $user, false );
837 }
838
839 //Update Profile Fields
840 if( ! empty( $user ) && ( in_array( 'full', $type ) || in_array( 'profile', $type ) ) ) {
841 $result_profile = $this->update_profile_fields( $userid, $user, false );
842 }
843
844 //Password field validation and update
845 $result_password = WPF()->form->validate_password( $user );
846 if( $result_password === false ) {
847 $result_password = true;
848 }
849 if( wpfval( $result_password, 'error' ) ) {
850 WPF()->notice->add( $result_password['error'], 'error' );
851 $result_password = false;
852 }
853 if( $result_password && wpfval( $user, 'old_pass' ) && wpfval( $user, 'user_pass1' ) ) {
854 $result_password = $this->change_password( $user['old_pass'], $user['user_pass1'], $userid );
855 }
856
857 //Upload avatar
858 if( wpfval( $user, 'avatar_type' ) === 'custom' ) {
859 $this->upload_avatar( $userid );
860 }
861
862 //Update Custom Fields
863 if( ! empty( $custom_fields ) && ( in_array( 'full', $type ) || in_array( 'custom_fields', $type ) ) ) {
864 $result_fields = $this->update_custom_fields( $userid, $custom_fields, false );
865 }
866
867 //Upload Files from Custom Fields
868 if( wpfval( $file_fields, 'files' ) ) {
869 $this->upload_files( $file_fields['files'] );
870 }
871
872 //Reset this user cache
873 $this->reset( $userid );
874
875 if( $result_user === false || $result_profile === false || $result_fields === false || $result_password === false ) {
876 return false;
877 } else {
878 WPF()->notice->add( 'Profile updated successfully', 'success' );
879 do_action( 'wpforo_update_profile_after', $user );
880
881 return $user;
882 }
883 }
884
885 return false;
886 }
887
888 public function update_user_fields( $userid, $data, $check_permissions = true ) {
889 $result_user = true;
890 if( $check_permissions ) WPF()->perm->can_edit_user( $userid );
891
892 //User Fields
893 if( wpfkey( $data, 'display_name' ) ) {
894 $user_fields['display_name'] = $data['display_name'];
895 $user_fields_types[] = '%s';
896 }
897 if( wpfkey( $data, 'user_email' ) ) {
898 $user_fields['user_email'] = $data['user_email'];
899 $user_fields_types[] = '%s';
900 }
901 if( wpfkey( $data, 'user_nicename' ) ) {
902 if( ! wpfval( $data, 'user_nicename' ) ) {
903 $user_info = get_userdata( $userid );
904 $data['user_nicename'] = sanitize_title( sanitize_user( $user_info->user_nicename, true ) );
905 }
906 $user_fields['user_nicename'] = $data['user_nicename'];
907 $user_fields_types[] = '%s';
908 update_user_meta( $userid, 'nickname', $data['user_nicename'] );
909 }
910 if( wpfkey( $data, 'first_name' ) ) {
911 update_user_meta( $userid, 'first_name', $data['first_name'] );
912 }
913 if( wpfkey( $data, 'last_name' ) ) {
914 update_user_meta( $userid, 'last_name', $data['last_name'] );
915 }
916 if( wpfkey( $data, 'user_url' ) ) {
917 $user_fields['user_url'] = $data['user_url'];
918 $user_fields_types[] = '%s';
919 }
920
921 if( ! empty( $user_fields ) && ! empty( $user_fields_types ) ) {
922 $result_user = WPF()->db->update(
923 WPF()->db->users,
924 $user_fields,
925 [ 'ID' => $userid ],
926 $user_fields_types,
927 [ '%d' ]
928 );
929 if( false === $result_user ) {
930 WPF()->notice->add( 'User data update failed', 'error' );
931 if( WPF()->db->last_error ) {
932 WPF()->notice->add( sanitize_text_field( WPF()->db->last_error ), 'error' );
933 }
934 } else {
935 clean_user_cache( $userid );
936 }
937 }
938
939 if( $result_user ) $this->reset( $userid );
940
941 return $result_user;
942 }
943
944 public function update_profile_field( $userid, $key, $value ) {
945 $r = false;
946 if( $key && ! is_null( $value ) ) {
947 $member = $this->encode( [ $key => $value ] );
948 if( wpfkey( $member, $key ) ) {
949 $r = WPF()->db->update(
950 WPF()->tables->profiles,
951 [ $key => $value ],
952 [ 'userid' => $userid ],
953 [ wpforo_db_data_format( $member[ $key ] ) ], [ '%d' ]
954 );
955
956 if( $r ) $this->reset( $userid );
957 }
958 }
959
960 return $r;
961 }
962
963 public function update_profile_fields( $userid, $data, $check_permissions = true ) {
964 $result_profile = true;
965
966 if( $check_permissions ) {
967 WPF()->perm->can_edit_user( $userid );
968 }
969
970 $member = $this->encode( $data );
971
972 $profile_fields = [];
973 $profile_fields_types = [];
974
975 //Profile Fields
976 if( wpfkey( $data, 'groupid' ) ) {
977 $profile_fields['groupid'] = $member['groupid'];
978 $profile_fields_types[] = '%d';
979 }
980 if( wpfkey( $data, 'title' ) ) {
981 $profile_fields['title'] = $member['title'];
982 $profile_fields_types[] = '%s';
983 }
984 if( wpfkey( $data, 'signature' ) ) {
985 $profile_fields['signature'] = $member['signature'];
986 $profile_fields_types[] = '%s';
987 }
988 if( wpfkey( $data, 'about' ) ) {
989 $profile_fields['about'] = $member['about'];
990 $profile_fields_types[] = '%s';
991 update_user_meta( $userid, 'description', $member['about'] );
992 }
993 if( wpfkey( $data, 'occupation' ) ) {
994 $profile_fields['occupation'] = $member['occupation'];
995 $profile_fields_types[] = '%s';
996 }
997 if( wpfkey( $data, 'location' ) ) {
998 $profile_fields['location'] = $member['location'];
999 $profile_fields_types[] = '%s';
1000 }
1001 if( wpfkey( $data, 'timezone' ) ) {
1002 $profile_fields['timezone'] = $member['timezone'];
1003 $profile_fields_types[] = '%s';
1004 }
1005 if( wpfkey( $data, 'avatar_type' ) && $data['avatar_type'] !== 'gravatar' && wpfval( $data, 'avatar_url' ) ) {
1006 $profile_fields['avatar'] = esc_url( trim( (string) $data['avatar_url'] ) );
1007 $profile_fields_types[] = '%s';
1008 }
1009 if( wpfkey( $data, 'avatar_type' ) && $data['avatar_type'] === 'gravatar' ) {
1010 $profile_fields['avatar'] = '';
1011 $profile_fields_types[] = '%s';
1012 }
1013 if( wpfkey( $data, 'cover' ) ) {
1014 $profile_fields['cover'] = $member['cover'];
1015 $profile_fields_types[] = '%s';
1016 }
1017 if( wpfkey( $data, 'secondary_groupids' ) ) {
1018 $profile_fields['secondary_groupids'] = $member['secondary_groupids'];
1019 $profile_fields_types[] = '%s';
1020 }
1021 if( wpfkey( $data, 'custom_points' ) ) {
1022 $profile_fields['custom_points'] = $member['custom_points'];
1023 $profile_fields_types[] = '%d';
1024 }
1025 if( wpfkey( $data, 'online_time' ) ) {
1026 $profile_fields['online_time'] = $member['online_time'];
1027 $profile_fields_types[] = '%d';
1028 }
1029 if( wpfkey( $data, 'status' ) ) {
1030 $profile_fields['status'] = $member['status'];
1031 $profile_fields_types[] = '%s';
1032 }
1033 if( wpfkey( $data, 'is_email_confirmed' ) ) {
1034 $profile_fields['is_email_confirmed'] = $member['is_email_confirmed'];
1035 $profile_fields_types[] = '%d';
1036 }
1037 if( wpfkey( $data, 'is_mention_muted' ) ) {
1038 $profile_fields['is_mention_muted'] = $member['is_mention_muted'];
1039 $profile_fields_types[] = '%d';
1040 }
1041
1042 $profile_fields = apply_filters(
1043 'wpforo_before_update_profile_fields',
1044 $profile_fields,
1045 $userid,
1046 $data,
1047 $check_permissions
1048 );
1049
1050 if( ! empty( $profile_fields ) ) {
1051 $result_profile = WPF()->db->update(
1052 WPF()->tables->profiles,
1053 $profile_fields,
1054 [ 'userid' => intval( $userid ) ],
1055 $profile_fields_types,
1056 [ '%d' ]
1057 );
1058 if( false === $result_profile ) {
1059 WPF()->notice->add( 'User profile update failed', 'error' );
1060 if( WPF()->db->last_error ) {
1061 WPF()->notice->add( sanitize_text_field( WPF()->db->last_error ), 'error' );
1062 }
1063 }
1064 }
1065 do_action( 'wpforo_update_profile_fields', $userid, $data, $result_profile );
1066
1067 if( $result_profile ) $this->reset( $userid );
1068
1069 return $result_profile;
1070 }
1071
1072 public function update_custom_field( $userid, $field_name, $field_value = null ) {
1073 $result = false;
1074 $fields = $this->get_custom_fields( $userid );
1075 if( ! empty( $fields ) && $field_name && ! is_null( $field_value ) ) {
1076 foreach( $fields as $name => $value ) {
1077 if( $name == $field_name ) {
1078 $fields[ $name ] = $field_value;
1079 }
1080 }
1081 $custom_fields = array_filter( $fields );
1082 $custom_fields = wpforo_unslashe( $custom_fields );
1083 $custom_fields = wpforo_decode( $custom_fields );
1084 $custom_fields = wpforo_encode( $custom_fields );
1085 $fields_json = wp_json_encode( $custom_fields, JSON_UNESCAPED_UNICODE );
1086 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `fields` = %s WHERE `userid` = %d;";
1087 $sql = WPF()->db->prepare( $sql, $fields_json, $userid );
1088 $result = WPF()->db->query( $sql );
1089 }
1090
1091 if( $result ) $this->reset( $userid );
1092
1093 return $result;
1094 }
1095
1096 public function update_custom_fields( $userid, $custom_fields, $check_permissions = true ) {
1097
1098 $result_fields = true;
1099
1100 if( ! empty( $custom_fields ) ) {
1101 if( $check_permissions ) {
1102 WPF()->perm->can_edit_user( $userid );
1103 }
1104 $custom_fields = wpforo_unslashe( $custom_fields );
1105 $custom_fields = wpforo_decode( $custom_fields );
1106 $custom_fields = wpforo_encode( $custom_fields );
1107 $data_old = $this->get_custom_fields( $userid );
1108 if( $data_old && is_array( $data_old ) ) {
1109 $custom_fields = wp_parse_args( $custom_fields, $data_old );
1110 }
1111 $fields_json = wp_json_encode( $custom_fields, JSON_UNESCAPED_UNICODE );
1112 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `fields` = %s WHERE `userid` = %d;";
1113 $sql = WPF()->db->prepare( $sql, $fields_json, $userid );
1114 $result_fields = WPF()->db->query( $sql );
1115 if( false === $result_fields ) {
1116 WPF()->notice->add( 'User custom field update failed', 'error' );
1117 if( WPF()->db->last_error ) {
1118 WPF()->notice->add( sanitize_text_field( WPF()->db->last_error ), 'error' );
1119 }
1120 }
1121 }
1122
1123 if( $result_fields ) $this->reset( $userid );
1124
1125 return $result_fields;
1126 }
1127
1128 public function upload_avatar( $userid = 0 ) {
1129 $userid = intval( $userid );
1130
1131 $_FILES['avatar'] = wpforo_check_for_svg( $_FILES['avatar'] );
1132
1133 if( wpfval( WPF()->current_object, 'template' ) ) {
1134 $template = WPF()->current_object['template'];
1135 if( $template === 'account' ) {
1136 if( ! WPF()->usergroup->can( 'upa' ) ) return false;
1137 }
1138 }
1139
1140 if( ! $user = $this->get_member( $userid ) ) return false;
1141 $user_nicename = urldecode( (string) $user['user_nicename'] );
1142 if( isset( $_FILES['avatar'] ) && ! empty( $_FILES['avatar'] ) && isset( $_FILES['avatar']['name'] ) && $_FILES['avatar']['name'] ) {
1143 $name = sanitize_file_name( $_FILES['avatar']['name'] ); //myimg.png
1144 $tmp_name = sanitize_text_field( $_FILES['avatar']['tmp_name'] ); //D:\wamp\tmp\php986B.tmp
1145 $error = sanitize_text_field( $_FILES['avatar']['error'] ); //0
1146 $size = intval( $_FILES['avatar']['size'] ); //6112
1147
1148 $upload_max_filesize = apply_filters( 'wpforo_avatar_upload_max_filesize', 2 * 1048576 );
1149 if( $size > $upload_max_filesize ) {
1150 WPF()->notice->clear();
1151 WPF()->notice->add(
1152 'Avatar image is too big maximum allowed size is %s',
1153 'error',
1154 wpforo_print_size( $upload_max_filesize )
1155 );
1156
1157 return false;
1158 }
1159
1160 if( $error ) {
1161 $error = wpforo_file_upload_error( $error );
1162 WPF()->notice->clear();
1163 WPF()->notice->add( $error, 'error' );
1164
1165 return false;
1166 }
1167
1168 $avatar_dir = WPF()->folders['avatars']['dir'];
1169 if( ! is_dir( $avatar_dir ) ) wp_mkdir_p( $avatar_dir );
1170
1171 $ext = pathinfo( $name, PATHINFO_EXTENSION );
1172 if( ! wpforo_is_image( $ext ) ) {
1173 WPF()->notice->clear();
1174 WPF()->notice->add( 'Incorrect file format. Allowed formats: jpeg, jpg, png, gif.', 'error' );
1175
1176 return false;
1177 }
1178
1179 $fnm = pathinfo( $user_nicename, PATHINFO_FILENAME );
1180 $fnm = str_replace( ' ', '-', $fnm );
1181 while( strpos( (string) $fnm, '--' ) !== false ) $fnm = str_replace( '--', '-', $fnm );
1182 $fnm = preg_replace( "/[^-a-zA-Z0-9]/", "", (string) $fnm );
1183 $fnm = trim( (string) $fnm, "-" );
1184
1185 $avatar_fname = $fnm . ( $fnm ? '_' : '' ) . $userid . "." . strtolower( (string) $ext );
1186 $avatar_fname_orig = $fnm . ( $fnm ? '_' : '' ) . $userid . "." . $ext;
1187 $avatar_path = $avatar_dir . DIRECTORY_SEPARATOR . $avatar_fname;
1188 $avatar_path_orig = $avatar_dir . DIRECTORY_SEPARATOR . $avatar_fname_orig;
1189
1190 if( is_dir( $avatar_dir ) ) {
1191 if( move_uploaded_file( $tmp_name, $avatar_path ) ) {
1192 $image = wp_get_image_editor( $avatar_path );
1193 if( ! is_wp_error( $image ) ) {
1194 $image->resize( 150, 150, true );
1195 $saved = $image->save( $avatar_path );
1196 if( ! is_wp_error( $saved ) && $avatar_fname != $avatar_fname_orig ) {
1197 if( defined( PHP_OS ) && strtoupper( substr( PHP_OS, 0, 3 ) ) !== 'WIN' ) {
1198 unlink(
1199 $avatar_path_orig
1200 );
1201 }
1202 }
1203 }
1204 WPF()->db->update(
1205 WPF()->tables->profiles,
1206 [ 'avatar' => WPF()->folders['avatars']['url//'] . "/" . $avatar_fname ],
1207 [ 'userid' => intval( $userid ) ],
1208 [ '%s' ],
1209 [ '%d' ]
1210 );
1211 $this->reset( $userid );
1212
1213 return true;
1214 }
1215 }
1216 }
1217
1218 return false;
1219 }
1220
1221 public function upload_files( $file_fields ) {
1222 if( ! empty( $file_fields ) ) {
1223 foreach( $file_fields as $field_name => $file_path ) {
1224 if( wpfval( $_FILES, 'data', 'tmp_name', $field_name ) && ! move_uploaded_file(
1225 $_FILES['data']['tmp_name'][ $field_name ],
1226 $file_path
1227 ) ) {
1228 WPF()->notice->add( 'Sorry, there was an error uploading attached file', 'error' );
1229 }
1230 }
1231 }
1232 }
1233
1234 public function get_custom_field( $userid, $field_name ) {
1235 $field_value = '';
1236 if( $userid ) {
1237 $sql = WPF()->db->prepare(
1238 "SELECT `fields` FROM `" . WPF()->tables->profiles . "` WHERE userid = %d",
1239 $userid
1240 );
1241 $fields = WPF()->db->get_var( $sql );
1242 if( $fields ) {
1243 $data = (array) json_decode( $fields, true );
1244 if( ! empty( $data ) ) {
1245 $data = wpforo_unslashe( $data );
1246 if( wpfkey( $data, $field_name ) ) {
1247 $field_value = $data[ $field_name ];
1248 }
1249 }
1250 }
1251 }
1252
1253 return $field_value;
1254 }
1255
1256 public function get_custom_fields( $userid ) {
1257 $data = [];
1258 if( $userid ) {
1259 $sql = WPF()->db->prepare(
1260 "SELECT `fields` FROM `" . WPF()->tables->profiles . "` WHERE userid = %d",
1261 $userid
1262 );
1263 $fields = WPF()->db->get_var( $sql );
1264 if( $fields ) {
1265 $data = (array) json_decode( $fields, true );
1266 }
1267 $data = wpforo_unslashe( $data );
1268 }
1269
1270 return $data;
1271 }
1272
1273 public function change_password( $old_passw, $new_passw, $userid ) {
1274 if( ! ( $userid = wpforo_bigintval( $userid ) ) || ! ( $user = $this->get_member( $userid ) ) ) {
1275 WPF()->notice->clear();
1276 WPF()->notice->add( 'Userid is wrong', 'error' );
1277
1278 return false;
1279 }
1280
1281 $user['user_pass'] = ( $userdata = get_userdata( $userid ) ) ? $userdata->user_pass : '';
1282
1283 if( ! apply_filters( 'wpforo_change_password_validate', true, $old_passw, $new_passw, $user ) ) return false;
1284
1285 if( wp_check_password( $old_passw, $user['user_pass'], $userid ) ) {
1286 wp_set_password( $new_passw, $userid );
1287 if( ! wpforo_is_owner( $userid ) ) $this->inactive_to_active( $userid );
1288
1289 /**
1290 * Login user after change password with new pass
1291 */
1292 if( wpforo_is_owner( $userid ) ) {
1293 wp_signon( [ 'user_login' => sanitize_user( $user['user_login'] ), 'user_password' => $new_passw ] );
1294 }
1295
1296 WPF()->notice->add( 'Password successfully changed', 'success' );
1297
1298 return true;
1299 }
1300
1301 WPF()->notice->clear();
1302 WPF()->notice->add( 'Old password is wrong', 'error' );
1303
1304 return false;
1305 }
1306
1307 public function get_status( $userid ) {
1308 return WPF()->db->get_var(
1309 WPF()->db->prepare(
1310 "SELECT `status`
1311 FROM " . WPF()->tables->profiles . "
1312 WHERE `userid` = %d",
1313 $userid
1314 )
1315 );
1316 }
1317
1318 public function inactive_to_active( $userid, $user_login = '', $raw = false ) {
1319 if( $this->get_status( $userid ) === 'inactive' ) {
1320 if( $raw || ! wpforo_setting( 'authorization', 'manually_approval' ) ) {
1321 $this->update_profile_fields( $userid, [ 'status' => 'active' ], false );
1322 } else {
1323 wp_safe_redirect( wpforo_url( '', 'cantlogin' ) );
1324 exit();
1325 }
1326 }
1327 }
1328
1329 public function synchronize_user( $userid, $roles_usergroups = [] ) {
1330 $groupid = false;
1331 if( ! $userid || ! ( $user = get_userdata( $userid ) ) ) return false;
1332 $user->roles = (array) $user->roles;
1333
1334 //Don't synchronize User Roles with Usergroups if the option is disabled
1335 if( wpforo_setting( 'authorization', 'role_synch' ) ) {
1336 if( ! $roles_usergroups ) $roles_usergroups = WPF()->usergroup->get_role_usergroup_relation();
1337 if( ! empty( $roles_usergroups ) && ! empty( $user->roles ) ) {
1338 foreach( $user->roles as $role ) {
1339 if( isset( $roles_usergroups[ $role ] ) ) {
1340 $groupid = $roles_usergroups[ $role ];
1341 break;
1342 }
1343 }
1344 }
1345 }
1346
1347 if( ! $groupid ) {
1348 if( is_super_admin( $userid ) || in_array( 'administrator', $user->roles ) ) {
1349 $groupid = 1;
1350 } elseif( in_array( 'editor', $user->roles ) ) {
1351 $groupid = 2;
1352 } elseif( in_array( 'customer', $user->roles ) ) {
1353 $groupid = 5;
1354 } else {
1355 $groupid = WPF()->usergroup->default_groupid;
1356 }
1357 }
1358 $insert_groupid = ( isset( $_POST['wpforo_usergroup'] ) && ! wpforo_setting(
1359 'authorization',
1360 'role_synch'
1361 ) ) ? intval( $_POST['wpforo_usergroup'] ) : $groupid;
1362 $insert_timezone = ( isset( $_POST['wpforo_usertimezone'] ) ) ? sanitize_text_field(
1363 $_POST['wpforo_usertimezone']
1364 ) : '';
1365 $about = get_user_meta( $userid, 'description', true );
1366 $return = $this->add_profile( [
1367 'userid' => wpforo_bigintval( $userid ),
1368 'groupid' => intval( $insert_groupid ),
1369 'timezone' => sanitize_text_field( $insert_timezone ),
1370 'about' => stripslashes(
1371 wpforo_kses( trim( (string) $about ), 'user_description' )
1372 ),
1373 ] );
1374
1375 if( $return !== false && ( $secondary_groupids = wpfval( $_POST, 'wpforo_secondary_groupids' ) ) ) {
1376 $this->set_secondary_groupids( $userid, $secondary_groupids );
1377 }
1378
1379 return $return;
1380 }
1381
1382 public function synchronize_users( $limit = null ) {
1383
1384 if( is_multisite() ) {
1385 $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(
1386 )->tables->profiles . "` ) ORDER BY `user_id` ASC";
1387 } else {
1388 $sql = "SELECT `ID` as user_id FROM `" . WPF()->db->users . "` WHERE `ID` NOT IN( SELECT `userid` FROM `" . WPF()->tables->profiles . "` ) ORDER BY `ID` ASC";
1389 }
1390 if( ! is_null( $limit ) ) {
1391 $sql .= " LIMIT " . intval( $limit );
1392 }
1393
1394 $userids = WPF()->db->get_col( $sql );
1395 if( ! empty( $userids ) ) {
1396 $roles_usergroups = WPF()->usergroup->get_role_usergroup_relation();
1397 foreach( $userids as $userid ) {
1398 $this->synchronize_user( $userid, $roles_usergroups );
1399 }
1400
1401 return false;
1402 }
1403
1404 ## -- START -- delete profiles where not participant on multisite blog
1405 if( is_multisite() ) {
1406 $sql = "DELETE FROM `" . WPF()->tables->profiles . "` WHERE `userid` NOT IN( SELECT `user_id` FROM `" . WPF()->db->usermeta . "` WHERE `meta_key` LIKE '" . WPF(
1407 )->blog_prefix . "capabilities' )";
1408 WPF()->db->query( $sql );
1409 }
1410
1411 ## -- END -- delete profiles where not participant on multisite blog
1412
1413 return true;
1414 }
1415
1416 public function _get_member( $args ) {
1417 if( ! $args ) return $this->get_guest();
1418
1419 $default = [
1420 'userid' => null, // $userid
1421 'user_nicename' => '', // $user_nicename
1422 ];
1423
1424 if( wpforo_is_id( $args ) ) {
1425 $args = [ 'userid' => $args ];
1426 } elseif( ! is_array( $args ) ) {
1427 $args = [ 'user_nicename' => $args ];
1428 }
1429
1430 $args = wpforo_parse_args( $args, $default );
1431
1432 // Security: extract only expected keys instead of extract()
1433 $userid = $args['userid'];
1434 $user_nicename = $args['user_nicename'];
1435
1436 $userid = wpforo_bigintval( $userid );
1437
1438 $user_meta_obj = true;
1439 if( $user_nicename ) {
1440 $user_obj = get_user_by( 'user_nicename', $user_nicename );
1441 if( ! empty( $user_obj ) ) $userid = $user_obj->ID;
1442 }
1443 $member = get_user_meta( $userid, '_wpf_member_obj', true );
1444
1445 if( empty( $member ) ) {
1446 $user_meta_obj = false;
1447 $sql = "SELECT *,
1448 ug.`name` AS group_name,
1449 ug.`color` AS group_color,
1450 fn.`meta_value` AS first_name,
1451 ln.`meta_value` AS last_name
1452 FROM `" . WPF()->db->users . "` u
1453 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`
1454 LEFT JOIN `" . WPF()->tables->usergroups . "` ug ON ug.`groupid` = p.`groupid`
1455 LEFT JOIN `" . WPF()->db->usermeta . "` fn ON fn.`user_id` = u.`ID` AND fn.`meta_key` LIKE 'first_name'
1456 LEFT JOIN `" . WPF()->db->usermeta . "` ln ON ln.`user_id` = u.`ID` AND ln.`meta_key` LIKE 'last_name'";
1457 $wheres = [];
1458 if( $userid ) $wheres[] = "`ID` = $userid";
1459 if( $user_nicename ) $wheres[] = "`user_nicename` = '" . esc_sql( $user_nicename ) . "'";
1460 if( ! empty( $wheres ) ) $sql .= " WHERE " . implode( " AND ", $wheres );
1461 $member = WPF()->db->get_row( $sql, ARRAY_A );
1462 }
1463
1464 if( ! empty( $member ) && ! $user_meta_obj ) update_user_meta( $userid, '_wpf_member_obj', $member );
1465
1466 if( $member ) $member = $this->decode( $member );
1467
1468 return $member;
1469 }
1470
1471 public function get_member( $args ) {
1472 return wpforo_ram_get( [ $this, '_get_member' ], $args );
1473 }
1474
1475 public function get_members( $args = [], &$items_count = 0 ) {
1476 $default = [
1477 'include' => [], // array( 2, 10, 25 )
1478 'exclude' => [], // array( 2, 10, 25 )
1479 'status' => [ 'active', 'inactive', 'banned' ], // 'active', 'blocked', 'trashed', 'spamer'
1480 'groupid' => null, // groupid
1481 'online_time' => null, // groupid
1482 'orderby' => 'userid', //
1483 'order' => 'ASC', // ASC DESC
1484 'offset' => 0, // OFFSET
1485 'row_count' => null, // ROW COUNT
1486 'groupids' => [], // array( 1, 2 )
1487 ];
1488
1489 $args = wpforo_parse_args( $args, $default );
1490
1491 // Security: extract only expected keys instead of extract()
1492 $include = $args['include'];
1493 $exclude = $args['exclude'];
1494 $status = $args['status'];
1495 $groupid = $args['groupid'];
1496 $online_time = $args['online_time'];
1497 $orderby = $args['orderby'];
1498 $order = $args['order'];
1499 $offset = $args['offset'];
1500 $row_count = $args['row_count'];
1501 $groupids = $args['groupids'];
1502
1503 $include = wpforo_parse_args( $include );
1504 $exclude = wpforo_parse_args( $exclude );
1505
1506 $sql = "SELECT *,
1507 ug.`name` AS group_name,
1508 ug.`color` AS group_color,
1509 fn.`meta_value` AS first_name,
1510 ln.`meta_value` AS last_name
1511 FROM `" . WPF()->db->users . "` u
1512 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`
1513 LEFT JOIN `" . WPF()->tables->usergroups . "` ug ON ug.`groupid` = p.`groupid`
1514 LEFT JOIN `" . WPF()->db->usermeta . "` fn ON fn.`user_id` = u.`ID` AND fn.`meta_key` LIKE 'first_name'
1515 LEFT JOIN `" . WPF()->db->usermeta . "` ln ON ln.`user_id` = u.`ID` AND fn.`meta_key` LIKE 'last_name'";
1516
1517 $sql_count = "SELECT count(*)
1518 FROM `" . WPF()->db->users . "` u
1519 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`
1520 LEFT JOIN `" . WPF()->tables->usergroups . "` ug ON ug.`groupid` = p.`groupid`";
1521
1522
1523 $wheres = [];
1524 if( ! empty( $include ) ) $wheres[] = " u.`ID` IN(" . implode( ', ', array_map( 'intval', $include ) ) . ")";
1525 if( ! empty( $exclude ) ) {
1526 $wheres[] = " u.`ID` NOT IN(" . implode(
1527 ', ',
1528 array_map( 'intval', $exclude )
1529 ) . ")";
1530 }
1531 if( ! empty( $status ) ) {
1532 $wheres[] = " p.`status` IN('" . implode(
1533 "','",
1534 array_map(
1535 'esc_sql',
1536 array_map(
1537 'sanitize_text_field',
1538 $status
1539 )
1540 )
1541 ) . "')";
1542 }
1543 if( ! empty( $groupids ) ) {
1544 $wheres[] = " (p.`groupid` IN(" . implode(
1545 ', ',
1546 array_map( 'intval', $groupids )
1547 ) . ") OR CONCAT(',', p.`secondary_groupids`, ',') REGEXP ',(" . implode(
1548 '|',
1549 array_map(
1550 'intval',
1551 $groupids
1552 )
1553 ) . "),' )";
1554 }
1555 if( ! is_null( $groupid ) ) {
1556 $wheres[] = " (p.`groupid` = " . intval( $groupid ) . " OR FIND_IN_SET(" . intval(
1557 $groupid
1558 ) . ", p.`secondary_groupids`) ) ";
1559 }
1560 if( ! is_null( $online_time ) ) $wheres[] = " p.`online_time` > " . intval( $online_time );
1561
1562 if( ! empty( $wheres ) ) {
1563 $sql .= " WHERE " . implode( " AND ", $wheres );
1564 $sql_count .= " WHERE " . implode( " AND ", $wheres );
1565 }
1566
1567 $item_count_sql = preg_replace( '#ORDER.+$#is', '', $sql_count );
1568 if( $item_count_sql ) $items_count = WPF()->db->get_var( $item_count_sql );
1569
1570 if( $orderby === 'groupid' ) $orderby = 'p.`groupid`';
1571 $sql .= esc_sql( " ORDER BY $orderby " . $order );
1572
1573 $offset = absint( $offset );
1574 $limit = absint( $row_count );
1575 if( $limit ) $sql .= esc_sql( " LIMIT {$offset},{$limit}" );
1576
1577 return array_map( [ $this, 'decode' ], WPF()->db->get_results( $sql, ARRAY_A ) );
1578 }
1579
1580 public function search( $needle, $fields = [], $limit = null, $orderby = null ) {
1581 if( $needle ) {
1582 $needle = sanitize_text_field( $needle );
1583 if( empty( $fields ) ) {
1584 $fields = [
1585 'title',
1586 'user_nicename',
1587 'user_email',
1588 'signature',
1589 ];
1590 }
1591
1592 $sql = "SELECT `ID` FROM `" . WPF()->db->users . "` u
1593 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`";
1594 $wheres = [];
1595
1596 foreach( $fields as $field ) {
1597 $f = $this->get_field( $field );
1598 $field = sanitize_text_field( $field );
1599 if( $f['isDefault'] ) {
1600 if( $f['fieldKey'] === 'title' ) {
1601 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '" . esc_sql( $needle ) . "'";
1602 } else {
1603 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '%" . esc_sql( $needle ) . "%'";
1604 }
1605 } else {
1606 $needle = preg_quote( preg_quote( $needle ) );
1607 if( in_array( $f['type'], [ 'text', 'search', 'textarea' ], true ) ) {
1608 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"[^\"]*" . esc_sql(
1609 $needle
1610 ) . "[^\"]*\"'";
1611 } else {
1612 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"" . esc_sql(
1613 $needle
1614 ) . "\"'";
1615 }
1616 }
1617 }
1618
1619 if( ! empty( $wheres ) ) {
1620 $sql .= " WHERE " . implode( " OR ", $wheres );
1621 if( ! is_null( $orderby ) ) {
1622 $sql .= " ORDER BY " . implode( ', ', (array) $orderby );
1623 }
1624 if( $limit ) $sql .= " LIMIT " . intval( $limit );
1625
1626 return WPF()->db->get_col( $sql );
1627 } else {
1628 return [];
1629 }
1630 } else {
1631 return [];
1632 }
1633
1634 }
1635
1636 public function filter( $args, $limit = null, $orderby = null ) {
1637 if( $args && is_array( $args ) ) {
1638 $sql = "SELECT `ID` FROM `" . WPF()->db->users . "` u
1639 INNER JOIN `" . WPF()->tables->profiles . "` p ON p.`userid` = u.`ID`";
1640 $wheres = [];
1641
1642 foreach( $args as $field => $needle ) {
1643 $f = $this->get_field( $field );
1644 $field = sanitize_text_field( $field );
1645 if( $f['isDefault'] ) {
1646 if( is_scalar( $needle ) ) {
1647 $needle = sanitize_text_field( $needle );
1648 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '%" . esc_sql( $needle ) . "%'";
1649 } elseif( is_array( $needle ) ) {
1650 foreach( $needle as $n ) {
1651 $n = sanitize_text_field( $n );
1652 $wheres[] = "`" . esc_sql( $field ) . "` LIKE '%" . esc_sql( $n ) . "%'";
1653 }
1654 }
1655 } else {
1656 if( in_array( $f['type'], [ 'text', 'search', 'textarea' ], true ) ) {
1657 if( is_scalar( $needle ) ) {
1658 $needle = preg_quote( preg_quote( wpforo_encode( $needle ) ) );
1659 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"[^\"]*" . esc_sql(
1660 $needle
1661 ) . "[^\"]*\"'";
1662 } elseif( is_array( $needle ) ) {
1663 foreach( $needle as $n ) {
1664 $n = preg_quote( preg_quote( wpforo_encode( $n ) ) );
1665 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"[^\"]*" . esc_sql(
1666 $n
1667 ) . "[^\"]*\"'";
1668 }
1669 }
1670 } else {
1671 if( is_scalar( $needle ) ) {
1672 $needle = preg_quote( preg_quote( wpforo_encode( $needle ) ) );
1673 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"" . esc_sql(
1674 $needle
1675 ) . "\"'";
1676 } elseif( is_array( $needle ) ) {
1677 foreach( $needle as $n ) {
1678 $n = preg_quote( preg_quote( wpforo_encode( $n ) ) );
1679 $wheres[] = "`fields` REGEXP '[{,]\"" . $field . "\":(\\\[[^\\\[]*)?\"" . esc_sql(
1680 $n
1681 ) . "\"'";
1682 }
1683 }
1684 }
1685 }
1686 }
1687
1688 if( $wheres ) {
1689 $sql .= " WHERE " . implode( " AND ", $wheres );
1690 if( ! is_null( $orderby ) ) {
1691 $sql .= " ORDER BY " . implode( ', ', (array) $orderby );
1692 }
1693 if( $limit ) $sql .= " LIMIT " . intval( $limit );
1694
1695 return WPF()->db->get_col( $sql );
1696 }
1697 }
1698
1699 return [];
1700 }
1701
1702 public function ban( $userid ) {
1703 if( $userid == WPF()->current_userid ) {
1704 WPF()->notice->add( 'You can\'t make yourself banned user', 'error' );
1705
1706 return false;
1707 }
1708 if( ! WPF()->usergroup->can( 'bm' ) || ! WPF()->perm->user_can_manage_user(
1709 WPF()->current_userid,
1710 intval( $userid )
1711 ) ) {
1712 WPF()->notice->add( 'Permission denied for this action', 'error' );
1713
1714 return false;
1715 }
1716 if( false !== WPF()->db->update(
1717 WPF()->tables->profiles,
1718 [ 'status' => 'banned' ],
1719 [ 'userid' => intval( $userid ) ],
1720 [ '%s' ],
1721 [ '%d' ]
1722 ) ) {
1723 do_action( 'wpforo_after_ban_user', $userid );
1724 $this->reset( $userid );
1725 WPF()->notice->add( 'User successfully banned from wpforo', 'success' );
1726
1727 return true;
1728 }
1729
1730 WPF()->notice->add( 'User ban action error', 'error' );
1731
1732 return false;
1733 }
1734
1735 public function unban( $userid ) {
1736 if( ! WPF()->usergroup->can( 'bm' ) || ! WPF()->perm->user_can_manage_user(
1737 WPF()->current_userid,
1738 intval( $userid )
1739 ) ) {
1740 WPF()->notice->add( 'Permission denied for this action', 'error' );
1741
1742 return false;
1743 }
1744 if( false !== WPF()->db->update(
1745 WPF()->tables->profiles,
1746 [ 'status' => 'active' ],
1747 [ 'userid' => intval( $userid ) ],
1748 [ '%s' ],
1749 [ '%d' ]
1750 ) ) {
1751 do_action( 'wpforo_after_unban_user', $userid );
1752 $this->reset( $userid );
1753 WPF()->notice->add( 'User successfully unbanned from wpforo', 'success' );
1754
1755 return true;
1756 }
1757
1758 WPF()->notice->add( 'User unban action error', 'error' );
1759
1760 return false;
1761 }
1762
1763 public function activate( $userid ) {
1764 if( false !== WPF()->db->update(
1765 WPF()->tables->profiles,
1766 [ 'status' => 'active' ],
1767 [ 'userid' => intval( $userid ) ],
1768 [ '%s' ],
1769 [ '%d' ]
1770 ) ) {
1771 do_action( 'wpforo_after_activate_user', $userid );
1772 $this->reset( $userid );
1773 WPF()->notice->add( 'User successfully activated from wpforo', 'success' );
1774
1775 return true;
1776 }
1777
1778 WPF()->notice->add( 'User activate action error', 'error' );
1779
1780 return false;
1781 }
1782
1783 public function deactivate( $userid ) {
1784 if( false !== WPF()->db->update(
1785 WPF()->tables->profiles,
1786 [ 'status' => 'inactive' ],
1787 [ 'userid' => intval( $userid ) ],
1788 [ '%s' ],
1789 [ '%d' ]
1790 ) ) {
1791 do_action( 'wpforo_after_deactivate_user', $userid );
1792 $this->reset( $userid );
1793 WPF()->notice->add( 'User successfully deactivated from wpforo', 'success' );
1794
1795 return true;
1796 }
1797
1798 WPF()->notice->add( 'User deactivate action error', 'error' );
1799
1800 return false;
1801 }
1802
1803 /**
1804 *
1805 * @param int $userid
1806 * @param int $reassign
1807 *
1808 * @return bool true | false if user successfully deleted
1809 */
1810 public function delete( $userid, $reassign = null ) {
1811 if( ! ( $userid = wpforo_bigintval( $userid ) ) ) return false;
1812 do_action( 'wpforo_before_delete_user', $userid, $reassign );
1813
1814 if( false !== WPF()->db->delete( WPF()->tables->profiles, [ 'userid' => $userid ], [ '%d' ] ) ) {
1815 do_action( 'wpforo_after_delete_user', $userid, $reassign );
1816
1817 WPF()->notice->add( 'User successfully deleted', 'success' );
1818
1819 return true;
1820 }
1821
1822 WPF()->notice->add( 'User delete error', 'error' );
1823
1824 return false;
1825 }
1826
1827 /**
1828 * @deprecated since 2.1.6 version instead of this use $this->_get_avatar() method
1829 */
1830 public function _avatar( $user, $attr = '', $size = 96 ) {
1831 return $this->_get_avatar( $user, $size, $attr );
1832 }
1833
1834 /**
1835 * @deprecated since 2.1.6 version instead of this use $this->get_avatar() method
1836 */
1837 public function avatar( $user, $attr = '', $size = 96 ) {
1838 return wpforo_ram_get( [ $this, '_avatar' ], $user, $attr, $size );
1839 }
1840
1841 public function _get_avatar( $user, $size = 96, $attr = '' ) {
1842 return $this->get_avatar_html( $this->get_avatar_url( $user ), $user, $size, $attr );
1843 }
1844
1845 public function get_avatar( $user, $size = 96, $attr = '' ) {
1846 return wpforo_ram_get( [ $this, '_get_avatar' ], $user, $size, $attr );
1847 }
1848
1849 public function _get_avatar_url( $user ) {
1850 $cache = WPF()->cache->on( 'avatar' );
1851
1852 if( is_scalar( $user ) ) {
1853 $userid = wpforo_bigintval( $user );
1854 $cache_avatar = apply_filters( 'wpforo_avatar_cache', true, $userid );
1855 if( $cache && $cache_avatar && $avatar_url = WPF()->cache->get_item( $userid, 'avatar' ) ) {
1856 return str_replace( '#', '', (string) $avatar_url );
1857 }
1858 $avatar_url = (string) WPF()->db->get_var(
1859 WPF()->db->prepare(
1860 "SELECT `avatar` FROM `" . WPF()->tables->profiles . "` WHERE `userid` = %d",
1861 wpforo_bigintval( $userid )
1862 )
1863 );
1864 } else {
1865 $avatar_url = (string) wpfval( $user, 'avatar' );
1866 $userid = wpforo_bigintval( wpfval( $user, 'userid' ) );
1867 }
1868
1869 if( $cache && $userid ) {
1870 WPF()->cache->create( 'item', [ $userid => $avatar_url ?: '#' ], 'avatar' );
1871 }
1872
1873 return apply_filters( 'wpforo_avatar_url', $avatar_url, $userid );
1874 }
1875
1876 public function get_avatar_url( $user ) {
1877 return wpforo_ram_get( [ $this, '_get_avatar_url' ], $user );
1878 }
1879
1880 public function get_avatar_html( $url, $user = [], $size = 96, $attr = '' ) {
1881 $size = intval( $size );
1882 if( $url && wpforo_setting( 'profiles', 'custom_avatars' ) ) {
1883 $url = apply_filters( 'wpforo_avatar_url', $url, $user );
1884 $dname = ! is_scalar( $user ) ? wpforo_user_dname( $user ) : $this->get_member( $user )['dname'];
1885 if( strpos( (string) $attr, 'alt=' ) === false ) $attr .= ' ' . sprintf( 'alt="%1$s"', esc_attr( $dname ) );
1886 if( strpos( (string) $attr, 'title=' ) === false ) {
1887 $attr .= ' ' . sprintf(
1888 'title="%1$s"',
1889 esc_attr( $dname )
1890 );
1891 }
1892 if( strpos( (string) $attr, 'height=' ) === false ) $attr .= ' ' . sprintf( 'height="%1$d"', $size );
1893 if( strpos( (string) $attr, 'width=' ) === false ) $attr .= ' ' . sprintf( 'width="%1$d"', $size );
1894 $img = '<img class="avatar" src="' . esc_url( (string) $url ) . '" ' . $attr . ' >';
1895 } else {
1896 $userid = is_scalar( $user ) ? wpforo_bigintval( $user ) : ( wpforo_bigintval(
1897 wpfval( $user, 'userid' )
1898 ) ?: (string) wpfval( $user, 'user_email' ) );
1899 $img = get_avatar( $userid, $size );
1900 if( $attr ) $img = str_replace( '<img', '<img ' . $attr, $img );
1901 }
1902
1903 return $img;
1904 }
1905
1906 /**
1907 * @param array|int|string $arg
1908 * @param string $template
1909 *
1910 * @return string
1911 */
1912 public function get_profile_url( $arg, $template = 'profile', $ram_cache = true ) {
1913 $user = is_scalar( $arg ) ? ( $ram_cache ? $this->get_member(
1914 intval( basename( (string) $arg ) )
1915 ) : $this->_get_member(
1916 intval( basename( (string) $arg ) )
1917 ) ) ?: [ 'user_nicename' => basename( (string) $arg ) ] : $arg;
1918 if( wpfkey( $user, 'userid' ) && wpfkey( $user, 'user_nicename' ) ) {
1919 $user_slug = ( wpforo_setting(
1920 'profiles',
1921 'url_structure'
1922 ) === 'id' ? $user['userid'] : $user['user_nicename'] );
1923 if( $template === 'profile' ) {
1924 $profile_url = wpforo_url( $user_slug, 'member' );
1925 } else {
1926 $template_slug = wpforo_settings_get_slug( $template );
1927 $profile_url = wpforo_url( "$user_slug/$template_slug", 'member' );
1928 }
1929 } else {
1930 $profile_url = wpforo_home_url();
1931 }
1932
1933 return apply_filters( 'wpforo_member_profile_url', $profile_url, $user, $template );
1934 }
1935
1936 /**
1937 * @param float $points
1938 *
1939 * @return array
1940 */
1941 public function calc_rating( float $points ): array {
1942 $rating = $this->default->member['rating'];
1943
1944 $rating['level'] = $this->rating_level( floatval( $points ), false );
1945 $rating['percent'] = $rating['level'] * 10;
1946 $rating['title'] = $this->rating( $rating['level'], 'title' );
1947 $rating['color'] = $this->rating( $rating['level'], 'color' );
1948 $rating['badge'] = $this->rating( $rating['level'], 'icon' );
1949
1950 return $rating;
1951 }
1952
1953 /**
1954 * @param $member
1955 *
1956 * @return float
1957 */
1958 private function calc_points( $member ): float {
1959 $topic_points = intval( $member['topics'] ) * wpforo_setting( 'rating', 'topic_points' );
1960 $post_points = intval( $member['posts'] ) * wpforo_setting( 'rating', 'post_points' );
1961 $like_points = intval( wpfval( $member, 'reactions_in', 'up' ) ) * wpforo_setting( 'rating', 'like_points' );
1962 $dislike_points = intval( wpfval( $member, 'reactions_in', 'down' ) ) * wpforo_setting(
1963 'rating',
1964 'dislike_points'
1965 );
1966
1967 $topic_points = (float) apply_filters( 'wpforo_member_get_points_topic_points', $topic_points, $member );
1968 $post_points = (float) apply_filters( 'wpforo_member_get_points_post_points', $post_points, $member );
1969 $like_points = (float) apply_filters( 'wpforo_member_get_points_like_points', $like_points, $member );
1970 $dislike_points = (float) apply_filters( 'wpforo_member_get_points_dislike_points', $dislike_points, $member );
1971 $other_points = (float) apply_filters( 'wpforo_member_get_points_other_points', 0, $member );
1972
1973 return $topic_points + $post_points + $like_points + $dislike_points + $other_points;
1974 }
1975
1976 public function get_count( $args = [] ): int {
1977 $sql = "SELECT SQL_NO_CACHE COUNT(*) FROM `" . WPF()->tables->profiles . "` p
1978 INNER JOIN `" . WPF()->db->users . "` u ON u.`ID` = p.`userid` WHERE p.`status` NOT LIKE 'trashed'";
1979 if( $args ) {
1980 $wheres = [];
1981 foreach( $args as $key => $value ) {
1982 if( is_array( $value ) ) {
1983 $wheres[] = "$key IN('" . implode( "','", array_map( 'esc_sql', $value ) ) . "')";
1984 } else {
1985 $wheres[] = "$key = '" . esc_sql( $value ) . "'";
1986 }
1987 }
1988 if( $wheres ) $sql .= " AND " . implode( ' AND ', $wheres );
1989 }
1990
1991 return (int) WPF()->db->get_var( $sql );
1992 }
1993
1994 public function _is_online( $userid, $duration = null ) {
1995 if( ! $duration ) $duration = wpforo_setting( 'profiles', 'online_status_timeout' );
1996 $sql = "SELECT `online_time` FROM `" . WPF()->tables->profiles . "` WHERE `userid` = %d";
1997 $sql = WPF()->db->prepare( $sql, $userid );
1998 $online_time = intval( WPF()->db->get_var( $sql ) );
1999 $current_time = time();
2000
2001 return ( $current_time - $online_time ) < $duration;
2002 }
2003
2004 public function is_online( $userid, $duration = null ) {
2005 return wpforo_ram_get( [ $this, '_is_online' ], $userid, $duration );
2006 }
2007
2008 public function show_online_indicator( $userid, $ico = true ) {
2009 if( $this->is_online( $userid ) ) : ?>
2010
2011 <?php if( $ico ) : ?>
2012 <i class="fas fa-circle wpfsx wpfcl-8" title="<?php wpforo_phrase( 'Online' ) ?>"></i>
2013 <?php else : wpforo_phrase( 'Online' ); endif ?>
2014
2015 <?php else : ?>
2016
2017 <?php if( $ico ) : ?>
2018 <i class="fas fa-circle wpfsx wpfcl-0" title="<?php wpforo_phrase( 'Offline' ) ?>"></i>
2019 <?php else : wpforo_phrase( 'Offline' ); endif ?>
2020
2021 <?php endif;
2022 }
2023
2024 public function online_members_count( $duration = null ) {
2025 if( ! ( $duration = intval( $duration ) ) ) {
2026 $duration = (int) wpforo_setting(
2027 'profiles',
2028 'online_status_timeout'
2029 );
2030 }
2031 $online_timeframe = time() - $duration;
2032 $key = [ 'member', 'online_members_count', $online_timeframe ];
2033 if( WPF()->ram_cache->exists( $key ) ) return WPF()->ram_cache->get( $key );
2034 $sql = "SELECT COUNT(DISTINCT `userid`, `ip`) AS total FROM `" . WPF()->tables->visits . "` WHERE `time` > %d";
2035 $var = (int) WPF()->db->get_var( WPF()->db->prepare( $sql, $online_timeframe ) );
2036 if( ! $var ) {
2037 $sql = "SELECT COUNT(*) FROM `" . WPF()->tables->profiles . "` WHERE `online_time` > %d";
2038 $var = (int) WPF()->db->get_var( WPF()->db->prepare( $sql, $online_timeframe ) );
2039 }
2040 WPF()->ram_cache->set( $key, $var );
2041
2042 return $var;
2043 }
2044
2045 public function get_online_members( $count = 1, $groupids = [], $duration = null ) {
2046 if( ! $duration ) $duration = wpforo_setting( 'profiles', 'online_status_timeout' );
2047 $current_time = time();
2048 $online_timeframe = $current_time - $duration;
2049 $groupids = array_filter((array)$groupids);
2050 $args = [
2051 'groupids' => $groupids,
2052 'online_time' => $online_timeframe, // $current_time - $duration
2053 'orderby' => 'userid', // forumid, order, parentid
2054 'row_count' => $count,
2055 'order' => 'ASC', // ASC DESC
2056 ];
2057
2058 return $this->get_members( $args );
2059 }
2060
2061 public function levels() {
2062 $max_rating_levels = (int) apply_filters( 'wpforo_max_rating_levels', 10 );
2063
2064 return range( 0, $max_rating_levels );
2065 }
2066
2067 public function rating( $level = null, $var = '' ) {
2068 if( is_null( $level ) ) return wpforo_setting( 'rating', 'levels' );
2069 $_levels = wpforo_setting( 'rating', 'levels' );
2070 if( ! wpfkey( $_levels, $level ) ) $level = 0;
2071 if( ! $var ) return wpforo_setting( 'rating', 'levels', $level );
2072
2073 return wpforo_setting( 'rating', 'levels', $level, $var );
2074 }
2075
2076 /**
2077 * @param int $points
2078 * @param bool $percent
2079 *
2080 * @return int
2081 */
2082 public function rating_level( $points, $percent = true ) {
2083 $points = intval( $points );
2084 $max_rating_levels = (int) apply_filters( 'wpforo_max_rating_levels', 10 );
2085 $increment = 100 / $max_rating_levels;
2086 for( $level = 1; $level <= $max_rating_levels; $level ++ ) {
2087 if( $points < $this->rating( $level, 'points' ) ) {
2088 $bar = ( $level - 1 ) * $increment;
2089 break;
2090 }
2091 }
2092 // If the points are greater than or equal to the highest level's points, set $bar to 100
2093 if( ! isset( $bar ) ) $bar = 100;
2094
2095 return $percent ? $bar : (int) floor( $bar / ( 100 / $max_rating_levels ) );
2096 }
2097
2098
2099 public function rating_badge( $level = 0, $view = 'short' ) {
2100
2101 $max_rating_levels = (int) apply_filters( 'wpforo_max_rating_levels', 10 );
2102 $level = ( $level > $max_rating_levels ) ? floor( $level / $max_rating_levels ) : $level;
2103
2104 if( $level === 0 ) {
2105 return '<i class="' . $this->rating( $level, 'icon' ) . '"></i>';
2106 } elseif( $level > 0 && $level < 6 ) {
2107 if( $view == 'full' ) {
2108 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', $level );
2109 } else {
2110 return '<span>' . esc_html( $level ) . '</span> <i class="' . $this->rating(
2111 $level,
2112 'icon'
2113 ) . '"></i>';
2114 }
2115 } elseif( $level > 5 && $level < 9 ) {
2116 if( $view == 'full' ) {
2117 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', ( $level - 5 ) );
2118 } else {
2119 return '<span>' . esc_html( $level - 5 ) . '</span> <i class="' . $this->rating(
2120 $level,
2121 'icon'
2122 ) . '"></i>';
2123 }
2124 }
2125
2126 if( $max_rating_levels > 10 ) {
2127 if( $level < 12 ) {
2128 if( $view == 'full' ) {
2129 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', ( $level - 8 ) );
2130 } else {
2131 return '<span>' . esc_html( $level - 8 ) . '</span> <i class="' . $this->rating(
2132 $level,
2133 'icon'
2134 ) . '"></i>';
2135 }
2136 } elseif( $level < 15 ) {
2137 if( $view == 'full' ) {
2138 return str_repeat( ' <i class="' . $this->rating( $level, 'icon' ) . '"></i> ', ( $level - 11 ) );
2139 } else {
2140 return '<span>' . esc_html( $level - 11 ) . '</span> <i class="' . $this->rating(
2141 $level,
2142 'icon'
2143 ) . '"></i>';
2144 }
2145 }
2146 } else {
2147 if( $level > 8 ) {
2148 return '<i class="' . $this->rating( $level, 'icon' ) . '"></i>';
2149 }
2150 }
2151
2152 return '';
2153 }
2154
2155 public function reset( $userid ) {
2156 if( ! $userid ) return;
2157 wpforo_clean_cache( 'avatar', $userid );
2158 delete_user_meta( intval( $userid ), '_wpf_member_obj' );
2159 if( wpforo_setting( 'seo', 'seo_profile' ) ) WPF()->seo->clear_cache();
2160 }
2161
2162 public function clear_db_cache() {
2163 WPF()->db->query( "DELETE FROM `" . WPF()->db->usermeta . "` WHERE `meta_key` = '_wpf_member_obj'" );
2164 }
2165
2166 private function update_online_time( $userid = null ) {
2167 if( ! $userid ) $userid = WPF()->current_userid;
2168 if( ! $userid ) return false;
2169 $current_timestamp = time();
2170 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `online_time` = %d WHERE `userid` = %d";
2171 $sql = WPF()->db->prepare( $sql, $current_timestamp, wpforo_bigintval( $userid ) );
2172 if( false !== WPF()->db->query( $sql ) ) return $current_timestamp;
2173
2174 return false;
2175 }
2176
2177 public function init_current_user() {
2178 WPF()->wp_current_user = $current_user = wp_get_current_user();
2179 if( $current_user->exists() ) {
2180 WPF()->current_userid = $current_user->ID;
2181 WPF()->current_user_login = $current_user->user_login;
2182 WPF()->current_user_email = $current_user->user_email;
2183 WPF()->current_user_display_name = $current_user->display_name;
2184
2185 $user = $this->get_member( $current_user->ID );
2186 if( ! wpfkey( $user, 'groupid' ) ) {
2187 $this->synchronize_user( $current_user->ID );
2188 $user = $this->get_member( $current_user->ID );
2189 }
2190 $user_meta = get_user_meta( $current_user->ID );
2191 WPF()->current_user = $user;
2192 WPF()->current_usermeta = $user_meta;
2193 WPF()->current_user_groupid = WPF()->current_user['groupid'];
2194 WPF()->current_user_secondary_groupids = WPF()->current_user['secondary_groupids'];
2195 WPF()->current_user_groupids = WPF()->current_user['groupids'];
2196 WPF()->current_user_status = (string) wpfval( $user, 'status' );
2197 $this->update_online_time();
2198 } elseif( $guest = $this->get_guest_cookies() ) {
2199 WPF()->current_userid = 0;
2200 WPF()->current_user_login = '';
2201 WPF()->current_user_email = $guest['email'];
2202 WPF()->current_user_display_name = $guest['name'];
2203 WPF()->current_user = $this->get_guest( $guest );
2204 WPF()->current_usermeta = [];
2205 WPF()->current_user_groupid = 4;
2206 WPF()->current_user_groupids = [ 4 ];
2207 WPF()->current_user_secondary_groupids = [];
2208 WPF()->current_user_status = '';
2209 WPF()->current_user_accesses = [];
2210 }
2211
2212 WPF()->usergroup->init_current();
2213
2214 if( function_exists( 'wp_get_session_token' ) && function_exists( 'wp_parse_auth_cookie' ) ) {
2215 WPF()->session_token = wp_get_session_token();
2216 }
2217 if( ! WPF()->session_token ) {
2218 $secret_key = defined( 'SECRET_KEY' ) && SECRET_KEY ? SECRET_KEY : 'wpforo';
2219 WPF()->session_token = hash_hmac(
2220 'sha256',
2221 md5( (string) wpfval( $_SERVER, 'HTTP_USER_AGENT' ) ) . md5(
2222 (string) wpfval( $_SERVER, 'REMOTE_ADDR' )
2223 ) . md5(
2224 (string) wpfval( $_SERVER, 'SERVER_ADDR' )
2225 ),
2226 $secret_key
2227 );
2228 }
2229
2230 do_action(
2231 'wpforo_after_init_current_user',
2232 WPF()->current_user,
2233 WPF()->current_usermeta,
2234 WPF()->current_user_groupid,
2235 WPF()->current_user_secondary_groupids,
2236 WPF()->current_user_groupids
2237 );
2238 }
2239
2240 public function blog_posts( $userid ) {
2241 if( isset( $userid ) && $userid ) return count_user_posts( $userid );
2242
2243 return 0;
2244 }
2245
2246 public function blog_comments( $userid, $user_email ) {
2247 global $wpdb;
2248 if( ! $userid || ! $user_email ) return 0;
2249
2250 return (int) $wpdb->get_var(
2251 "SELECT COUNT(*) FROM " . $wpdb->comments . " WHERE `user_id` = " . intval(
2252 $userid
2253 ) . " OR `comment_author_email` = '" . esc_sql( $user_email ) . "'"
2254 );
2255 }
2256
2257 public function show_delete_form( $current_user, $userids ) {
2258 if( empty( $current_user ) || empty( $userids ) ) return;
2259
2260 $userids = array_diff( $userids, [ $current_user->ID ] );
2261 $users_have_content = false;
2262 if( WPF()->db->get_var(
2263 "SELECT `postid` FROM `" . WPF()->tables->posts . "` WHERE `userid` IN( " . implode(
2264 ',',
2265 array_map( 'intval', $userids )
2266 ) . " ) LIMIT 1"
2267 ) ) {
2268 $users_have_content = true;
2269 }
2270 ?>
2271 <hr/><strong>#wpForo</strong>
2272 <?php if( ! $users_have_content ) : ?>
2273 <input type="hidden" name="wpforo_user_delete_option" value="delete"/>
2274 <?php else: ?>
2275 <?php if( 1 == count( $userids ) ) : ?>
2276 <fieldset>
2277 <legend><?php _e( 'What should be done with wpForo content owned by this user?', 'wpforo' ); ?></legend>
2278 <?php else : ?>
2279 <fieldset>
2280 <legend><?php _e(
2281 'What should be done with wpForo content owned by these users?',
2282 'wpforo'
2283 ); ?></legend>
2284 <?php endif; ?>
2285 <ul style="list-style:none;">
2286 <li><label><input type="radio" id="wpforo_delete_option0" name="wpforo_user_delete_option"
2287 value="delete">
2288 <?php _e( 'Delete all wpForo content.', 'wpforo' ); ?></label></li>
2289 <li><input type="radio" id="wpforo_delete_option1" name="wpforo_user_delete_option" value="reassign">
2290 <label for="wpforo_delete_option1"><?php _e( 'Attribute all content to:' ) ?></label>
2291 <?php
2292 wp_dropdown_users( [
2293 'name' => 'wpforo_reassign_userid',
2294 'exclude' => $userids,
2295 'show' => 'display_name_with_login',
2296 ] );
2297 ?>
2298 </li>
2299 </ul></fieldset>
2300 <script type="text/javascript">
2301 jQuery(document).ready(function ($) {
2302 $('#wpforo_reassign_userid').on('focus', function () {
2303 $('#wpforo_delete_option1').prop('checked', true).trigger('change');
2304 });
2305 });
2306 </script>
2307 <?php endif;
2308 }
2309
2310 public function autoban( $userid ) {
2311 if( ! WPF()->usergroup->can( 'em' ) ) {
2312 WPF()->db->update(
2313 WPF()->tables->profiles,
2314 [ 'status' => 'banned' ],
2315 [ 'userid' => intval( $userid ) ],
2316 [ '%s' ],
2317 [ '%d' ]
2318 );
2319 }
2320 }
2321
2322 public function member_approved_posts( $member = [] ) {
2323 if( is_numeric( $member ) ) {
2324 if( $userid = wpforo_bigintval( $member ) ) {
2325 if( $userid === WPF()->current_userid ) return WPF()->current_user['posts'];
2326
2327 return (int) WPF()->db->get_var(
2328 WPF()->db->prepare(
2329 "SELECT COUNT(*) as posts
2330 FROM `" . WPF()->tables->posts . "`
2331 WHERE `status` = 0
2332 AND `userid` = %d",
2333 $userid
2334 )
2335 );
2336 }
2337 }
2338
2339 return (int) wpfval( $member, 'posts' );
2340 }
2341
2342 public function current_user_is_new() {
2343 if( WPF()->usergroup->can( 'em' ) ) {
2344 //This is an admin or moderator. The number of posts doesn't matter.
2345 return false;
2346 } else {
2347 $new_user_max_posts = wpforo_setting( 'antispam', 'new_user_max_posts' );
2348 $posts = $this->member_approved_posts( WPF()->current_userid );
2349 if( $new_user_max_posts && $posts <= $new_user_max_posts ) {
2350 return true;
2351 } else {
2352 return false;
2353 }
2354 }
2355 }
2356
2357 /**
2358 * @return int
2359 */
2360 public function banned_count() {
2361 $key = [ 'member', 'banned_count' ];
2362 if( WPF()->ram_cache->exists( $key ) ) return WPF()->ram_cache->get( $key );
2363 $var = (int) WPF()->db->get_var(
2364 "SELECT count(*) FROM `" . WPF()->tables->profiles . "` WHERE `status` = 'banned'"
2365 );
2366 WPF()->ram_cache->set( $key, $var );
2367
2368 return $var;
2369 }
2370
2371 public function _get_guest_posts( $email ) {
2372 $sqls = [];
2373 foreach( WPF()->get_active_boards_tables( 'posts' ) as $table ) {
2374 $sqls[] = WPF()->db->prepare(
2375 "SELECT *
2376 FROM `$table`
2377 WHERE `status` = 0
2378 AND `email` = %s",
2379 $email
2380 );
2381 }
2382
2383 if( $sqls ) {
2384 return (array) WPF()->db->get_results(
2385 implode( ' UNION ALL ', $sqls ) . " ORDER BY `created` ASC, `postid` ASC",
2386 ARRAY_A
2387 );
2388 }
2389
2390 return [];
2391 }
2392
2393 public function get_guest_posts( $email ) {
2394 return wpforo_ram_get( [ $this, '_get_guest_posts' ], $email );
2395 }
2396
2397 public function _get_guest( $args = [] ) {
2398 if( ! wpfval( $args, 'name' ) ) $args['name'] = wpforo_phrase( 'Anonymous', false );
2399 if( ! wpfval( $args, 'email' ) ) $args['email'] = 'anonymous@example.com';
2400
2401 $args['name'] = strip_tags( (string) $args['name'] );
2402 $args['email'] = sanitize_email( $args['email'] );
2403 $args['user_registered'] = current_time( 'mysql', 1 );
2404 $args['posts'] = 0;
2405
2406 if( $args['email'] && $args['email'] !== 'anonymous@example.com' ) {
2407 if( $posts = $this->get_guest_posts( $args['email'] ) ) {
2408 $args['posts'] = count( $posts );
2409 if( $first_post_created = wpfval(
2410 $posts,
2411 0,
2412 'created'
2413 ) ) {
2414 $args['user_registered'] = $first_post_created;
2415 }
2416 }
2417 }
2418
2419 $guest = wpforo_array_args_cast_and_merge(
2420 [
2421 'groupid' => 4,
2422 'group_name' => wpforo_phrase( 'Guest', false ),
2423 'user_login' => $args['name'],
2424 'user_nicename' => sanitize_text_field( $args['name'] ),
2425 'user_email' => $args['email'],
2426 'user_registered' => $args['user_registered'],
2427 'display_name' => $args['name'],
2428 'posts' => $args['posts'],
2429 'status' => 'active',
2430 ],
2431 $this->default->member
2432 );
2433
2434 return $this->decode( $guest );
2435 }
2436
2437 public function get_guest( $args = [] ) {
2438 return wpforo_ram_get( [ $this, '_get_guest' ], $args );
2439 }
2440
2441 public function init_fields() {
2442 if( ! empty( $this->fields ) ) return;
2443
2444 $this->init_countries();
2445 $this->init_timezones();
2446
2447 $this->fields = apply_filters( 'wpforo_member_before_init_fields', $this->fields );
2448
2449 $usergroupids = [];
2450 $usergroups = WPF()->usergroup->get_usergroups();
2451 foreach( $usergroups as $usergroup ) {
2452 $usergroupids[] = $usergroup['groupid'];
2453 }
2454 $usergroupids_can_edit_fields = WPF()->usergroup->get_groupids_by_can( 'em' );
2455 $usergroupids_can_view_social_net = WPF()->usergroup->get_groupids_by_can( 'vmsn' );
2456
2457 /**
2458 * start init tinymce settings
2459 */
2460 $wp_editor_settings = WPF()->tpl->editor_buttons();
2461 $wp_editor_settings['tinymce']['toolbar1'] = 'bold,italic,link,unlink,undo,redo,source_code,emoticons';
2462 $wp_editor_settings['plugins'] = '';
2463 unset(
2464 $wp_editor_settings['external_plugins']['wpforo_pre_button'], $wp_editor_settings['external_plugins']['wpforo_spoiler_button']
2465 );
2466 $wp_editor_settings = apply_filters( 'wpforo_members_init_fields_tinymce_settings', $wp_editor_settings );
2467
2468 $this->fields['user_login'] = [
2469 'fieldKey' => 'user_login',
2470 'type' => 'text',
2471 'isDefault' => 1,
2472 'isRemovable' => 0,
2473 'isRequired' => 1,
2474 'isEditable' => 0,
2475 'label' => wpforo_phrase( 'Username', false ),
2476 'title' => wpforo_phrase( 'Username', false ),
2477 'placeholder' => wpforo_phrase( 'Username', false ),
2478 'description' => wpforo_phrase( 'Length must be between 3 characters and 15 characters.', false ),
2479 'minLength' => 3,
2480 'maxLength' => 30,
2481 'faIcon' => 'fas fa-user',
2482 'name' => 'user_login',
2483 'cantBeInactive' => [ 'register' ],
2484 'canEdit' => [],
2485 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmu' ),
2486 'can' => 'vmu',
2487 'isSearchable' => 0,
2488 ];
2489
2490 $this->fields['user_email'] = [
2491 'fieldKey' => 'user_email',
2492 'type' => 'email',
2493 'isDefault' => 1,
2494 'isRemovable' => 0,
2495 'isRequired' => 1,
2496 'isEditable' => 1,
2497 'label' => wpforo_phrase( 'Email', false ),
2498 'title' => wpforo_phrase( 'Email', false ),
2499 'placeholder' => wpforo_phrase( 'Email', false ),
2500 'minLength' => 0,
2501 'maxLength' => 0,
2502 'faIcon' => 'fas fa-envelope',
2503 'name' => 'user_email',
2504 'cantBeInactive' => [ 'register' ],
2505 'canEdit' => $usergroupids_can_edit_fields,
2506 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmm' ),
2507 'can' => 'vmm',
2508 'isSearchable' => 1,
2509 ];
2510
2511 $this->fields['user_pass'] = [
2512 'fieldKey' => 'user_pass',
2513 'type' => 'password',
2514 'isDefault' => 1,
2515 'isRemovable' => 0,
2516 'isRequired' => 1,
2517 'isEditable' => 1,
2518 'label' => wpforo_phrase( 'Password', false ),
2519 'title' => wpforo_phrase( 'Password', false ),
2520 'placeholder' => wpforo_phrase( 'Password', false ),
2521 'description' => wpforo_phrase( 'Must be minimum 6 characters.', false ),
2522 'minLength' => 6,
2523 'maxLength' => 20,
2524 'faIcon' => 'fas fa-key',
2525 'name' => 'user_pass',
2526 'cantBeInactive' => [
2527 'account',
2528 'register',
2529 ],
2530 'canEdit' => $usergroupids_can_edit_fields,
2531 'canView' => [],
2532 'can' => '',
2533 'isSearchable' => 0,
2534 ];
2535
2536 $this->fields['display_name'] = [
2537 'fieldKey' => 'display_name',
2538 'type' => 'text',
2539 'isDefault' => 1,
2540 'isRemovable' => 0,
2541 'isRequired' => 1,
2542 'isEditable' => 1,
2543 'label' => wpforo_phrase( 'Display Name', false ),
2544 'title' => wpforo_phrase( 'Display Name', false ),
2545 'placeholder' => wpforo_phrase( 'Display Name', false ),
2546 'faIcon' => 'fas fa-user',
2547 'name' => 'display_name',
2548 'cantBeInactive' => [],
2549 'canEdit' => $usergroupids_can_edit_fields,
2550 'canView' => $usergroupids,
2551 'can' => '',
2552 'isSearchable' => 1,
2553 ];
2554
2555 $this->fields['user_nicename'] = [
2556 'fieldKey' => 'user_nicename',
2557 'type' => 'text',
2558 'isDefault' => 1,
2559 'isRemovable' => 0,
2560 'isRequired' => 1,
2561 'isEditable' => 1,
2562 'label' => wpforo_phrase( 'Nickname', false ),
2563 'title' => wpforo_phrase( 'Nickname', false ),
2564 'placeholder' => wpforo_phrase( 'Nickname', false ),
2565 'description' => wpforo_phrase( 'URL Address Identifier', false ),
2566 'minLength' => 0,
2567 'maxLength' => 0,
2568 'faIcon' => 'fas fa-link',
2569 'name' => 'user_nicename',
2570 'cantBeInactive' => [],
2571 'canEdit' => $usergroupids_can_edit_fields,
2572 'canView' => $usergroupids,
2573 'can' => '',
2574 'isSearchable' => 1,
2575 ];
2576
2577 $this->fields['first_name'] = [
2578 'fieldKey' => 'first_name',
2579 'type' => 'text',
2580 'isDefault' => 1,
2581 'isRemovable' => 0,
2582 'isRequired' => 0,
2583 'isEditable' => 1,
2584 'label' => wpforo_phrase( 'First Name', false ),
2585 'title' => wpforo_phrase( 'First Name', false ),
2586 'placeholder' => wpforo_phrase( 'First Name', false ),
2587 'faIcon' => 'fas fa-address-card',
2588 'name' => 'first_name',
2589 'cantBeInactive' => [],
2590 'canEdit' => $usergroupids_can_edit_fields,
2591 'canView' => $usergroupids,
2592 'can' => '',
2593 'isSearchable' => 0,
2594 ];
2595
2596 $this->fields['last_name'] = [
2597 'fieldKey' => 'last_name',
2598 'type' => 'text',
2599 'isDefault' => 1,
2600 'isRemovable' => 0,
2601 'isRequired' => 0,
2602 'isEditable' => 1,
2603 'label' => wpforo_phrase( 'Last Name', false ),
2604 'title' => wpforo_phrase( 'Last Name', false ),
2605 'placeholder' => wpforo_phrase( 'Last Name', false ),
2606 'faIcon' => 'fas fa-address-card',
2607 'name' => 'last_name',
2608 'cantBeInactive' => [],
2609 'canEdit' => $usergroupids_can_edit_fields,
2610 'canView' => $usergroupids,
2611 'can' => '',
2612 'isSearchable' => 0,
2613 ];
2614
2615 $this->fields['title'] = [
2616 'fieldKey' => 'title',
2617 'type' => 'text',
2618 'isDefault' => 1,
2619 'isRemovable' => 0,
2620 'isRequired' => 1,
2621 'isEditable' => 1,
2622 'label' => wpforo_phrase( 'Title', false ),
2623 'title' => wpforo_phrase( 'Title', false ),
2624 'placeholder' => wpforo_phrase( 'Title', false ),
2625 'minLength' => 0,
2626 'maxLength' => 0,
2627 'faIcon' => 'fas fa-user',
2628 'name' => 'title',
2629 'cantBeInactive' => [],
2630 'canEdit' => $usergroupids_can_edit_fields,
2631 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmt' ),
2632 'can' => 'vmt',
2633 'isSearchable' => 1,
2634 ];
2635
2636 $this->fields['groupid'] = [
2637 'fieldKey' => 'groupid',
2638 'type' => 'usergroup',
2639 'isDefault' => 1,
2640 'isRemovable' => 0,
2641 'isRequired' => 1,
2642 'isEditable' => 1,
2643 'label' => wpforo_phrase( 'User Group', false ),
2644 'title' => wpforo_phrase( 'User Group', false ),
2645 'placeholder' => wpforo_phrase( 'User Group', false ),
2646 'faIcon' => 'fas fa-users',
2647 'name' => 'groupid',
2648 'allowedGroupIds' => [ 3, 5 ],
2649 'cantBeInactive' => [],
2650 'canEdit' => $usergroupids_can_edit_fields,
2651 'canView' => $usergroupids,
2652 'can' => '',
2653 'isSearchable' => 1,
2654 ];
2655
2656 $this->fields['secondary_groupids'] = [
2657 'fieldKey' => 'secondary_groupids',
2658 'type' => 'secondary_groups',
2659 'isWrapItem' => 1,
2660 'isDefault' => 1,
2661 'isRemovable' => 0,
2662 'isRequired' => 0,
2663 'isEditable' => 1,
2664 'label' => wpforo_phrase( 'User Groups Secondary', false ),
2665 'title' => wpforo_phrase( 'User Groups Secondary', false ),
2666 'placeholder' => '',
2667 'faIcon' => '',
2668 'values' => '',
2669 'name' => 'secondary_groupids',
2670 'allowedGroupIds' => WPF()->usergroup->get_secondary_groupids(),
2671 'cantBeInactive' => [],
2672 'canEdit' => $usergroupids_can_edit_fields,
2673 'canView' => $usergroupids,
2674 'can' => '',
2675 'isSearchable' => 1,
2676 ];
2677
2678 $this->fields['avatar'] = [
2679 'fieldKey' => 'avatar',
2680 'type' => 'avatar',
2681 'isDefault' => 1,
2682 'isRemovable' => 0,
2683 'isRequired' => 0,
2684 'isEditable' => 1,
2685 'label' => wpforo_phrase( 'Avatar', false ),
2686 'title' => wpforo_phrase( 'Avatar', false ),
2687 'placeholder' => wpforo_phrase( 'Avatar', false ),
2688 'name' => 'avatar',
2689 'cantBeInactive' => [],
2690 'canEdit' => $usergroupids_can_edit_fields,
2691 'canView' => WPF()->usergroup->get_groupids_by_can( 'va' ),
2692 'can' => 'va',
2693 'isSearchable' => 0,
2694 ];
2695
2696 $this->fields['user_url'] = [
2697 'fieldKey' => 'user_url',
2698 'type' => 'url',
2699 'isDefault' => 1,
2700 'isRemovable' => 0,
2701 'isRequired' => 0,
2702 'isEditable' => 1,
2703 'label' => wpforo_phrase( 'Website', false ),
2704 'title' => wpforo_phrase( 'Website', false ),
2705 'placeholder' => wpforo_phrase( 'Website', false ),
2706 'faIcon' => 'fas fa-sitemap',
2707 'name' => 'user_url',
2708 'cantBeInactive' => [],
2709 'canEdit' => $usergroupids_can_edit_fields,
2710 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmw' ),
2711 'can' => 'vmw',
2712 'isSearchable' => 1,
2713 ];
2714
2715 $this->fields['facebook'] = [
2716 'fieldKey' => 'facebook',
2717 'type' => 'url',
2718 'isDefault' => 0,
2719 'isRemovable' => 1,
2720 'isRequired' => 0,
2721 'isEditable' => 1,
2722 'label' => wpforo_phrase( 'Facebook', false ),
2723 'title' => wpforo_phrase( 'Facebook', false ),
2724 'placeholder' => wpforo_phrase( 'Facebook', false ),
2725 'faIcon' => 'fab fa-facebook',
2726 'name' => 'facebook',
2727 'cantBeInactive' => [],
2728 'canEdit' => $usergroupids_can_edit_fields,
2729 'canView' => $usergroupids_can_view_social_net,
2730 'can' => 'vmsn',
2731 'isSearchable' => 1,
2732 ];
2733
2734 $this->fields['twitter'] = [
2735 'fieldKey' => 'twitter',
2736 'type' => 'url',
2737 'isDefault' => 0,
2738 'isRemovable' => 1,
2739 'isRequired' => 0,
2740 'isEditable' => 1,
2741 'label' => wpforo_phrase( 'X.com', false ),
2742 'title' => wpforo_phrase( 'X.com', false ),
2743 'placeholder' => wpforo_phrase( 'X.com', false ),
2744 'faIcon' => 'fa-brands fa-square-x-twitter',
2745 'name' => 'twitter',
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['youtube'] = [
2754 'fieldKey' => 'youtube',
2755 'type' => 'url',
2756 'isDefault' => 0,
2757 'isRemovable' => 1,
2758 'isRequired' => 0,
2759 'isEditable' => 1,
2760 'label' => wpforo_phrase( 'YouTube', false ),
2761 'title' => wpforo_phrase( 'YouTube', false ),
2762 'placeholder' => wpforo_phrase( 'YouTube', false ),
2763 'faIcon' => 'fab fa-youtube',
2764 'name' => 'youtube',
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['vkontakte'] = [
2773 'fieldKey' => 'vkontakte',
2774 'type' => 'url',
2775 'isDefault' => 0,
2776 'isRemovable' => 1,
2777 'isRequired' => 0,
2778 'isEditable' => 1,
2779 'label' => wpforo_phrase( 'VKontakte', false ),
2780 'title' => wpforo_phrase( 'VKontakte', false ),
2781 'placeholder' => wpforo_phrase( 'VKontakte', false ),
2782 'faIcon' => 'fab fa-vk',
2783 'name' => 'vkontakte',
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['linkedin'] = [
2792 'fieldKey' => 'linkedin',
2793 'type' => 'url',
2794 'isDefault' => 0,
2795 'isRemovable' => 1,
2796 'isRequired' => 0,
2797 'isEditable' => 1,
2798 'label' => wpforo_phrase( 'LinkedIn', false ),
2799 'title' => wpforo_phrase( 'LinkedIn', false ),
2800 'placeholder' => wpforo_phrase( 'LinkedIn', false ),
2801 'faIcon' => 'fab fa-linkedin-in',
2802 'name' => 'linkedin',
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['telegram'] = [
2811 'fieldKey' => 'telegram',
2812 'type' => 'text',
2813 'isDefault' => 0,
2814 'isRemovable' => 1,
2815 'isRequired' => 0,
2816 'isEditable' => 1,
2817 'label' => wpforo_phrase( 'Telegram', false ),
2818 'title' => wpforo_phrase( 'Telegram', false ),
2819 'placeholder' => wpforo_phrase( 'Telegram', false ),
2820 'faIcon' => 'fab fa-telegram-plane',
2821 'name' => 'telegram',
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['instagram'] = [
2830 'fieldKey' => 'instagram',
2831 'type' => 'url',
2832 'isDefault' => 0,
2833 'isRemovable' => 1,
2834 'isRequired' => 0,
2835 'isEditable' => 1,
2836 'label' => wpforo_phrase( 'Instagram', false ),
2837 'title' => wpforo_phrase( 'Instagram', false ),
2838 'placeholder' => wpforo_phrase( 'Instagram', false ),
2839 'faIcon' => 'fab fa-instagram',
2840 'name' => 'instagram',
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['skype'] = [
2849 'fieldKey' => 'skype',
2850 'type' => 'text',
2851 'isDefault' => 0,
2852 'isRemovable' => 1,
2853 'isRequired' => 0,
2854 'isEditable' => 1,
2855 'label' => wpforo_phrase( 'Skype', false ),
2856 'title' => wpforo_phrase( 'Skype', false ),
2857 'placeholder' => wpforo_phrase( 'Skype', false ),
2858 'faIcon' => 'fab fa-skype',
2859 'name' => 'skype',
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['location'] = [
2868 'fieldKey' => 'location',
2869 'type' => 'select',
2870 'isDefault' => 1,
2871 'isRemovable' => 0,
2872 'isRequired' => 0,
2873 'isEditable' => 1,
2874 'label' => wpforo_phrase( 'Location', false ),
2875 'title' => wpforo_phrase( 'Location', false ),
2876 'placeholder' => wpforo_phrase( 'Location', false ),
2877 'faIcon' => 'fas fa-globe',
2878 'values' => $this->countries,
2879 'name' => 'location',
2880 'cantBeInactive' => [],
2881 'canEdit' => $usergroupids_can_edit_fields,
2882 'canView' => WPF()->usergroup->get_groupids_by_can( 'vml' ),
2883 'can' => 'vml',
2884 'isSearchable' => 1,
2885 ];
2886
2887 $this->fields['timezone'] = [
2888 'fieldKey' => 'timezone',
2889 'type' => 'select',
2890 'isDefault' => 1,
2891 'isRemovable' => 0,
2892 'isRequired' => 0,
2893 'isEditable' => 1,
2894 'label' => wpforo_phrase( 'Timezone', false ),
2895 'title' => wpforo_phrase( 'Timezone', false ),
2896 'placeholder' => wpforo_phrase( 'Timezone', false ),
2897 'faIcon' => 'fas fa-globe',
2898 'values' => $this->timezones,
2899 'name' => 'timezone',
2900 'cantBeInactive' => [],
2901 'canEdit' => $usergroupids_can_edit_fields,
2902 'canView' => $usergroupids,
2903 'can' => '',
2904 'isSearchable' => 1,
2905 ];
2906
2907 $this->fields['occupation'] = [
2908 'fieldKey' => 'occupation',
2909 'type' => 'text',
2910 'isDefault' => 1,
2911 'isRemovable' => 0,
2912 'isRequired' => 0,
2913 'isEditable' => 1,
2914 'label' => wpforo_phrase( 'Occupation', false ),
2915 'title' => wpforo_phrase( 'Occupation', false ),
2916 'placeholder' => wpforo_phrase( 'Occupation', false ),
2917 'faIcon' => 'fas fa-address-card',
2918 'name' => 'occupation',
2919 'cantBeInactive' => [],
2920 'canEdit' => $usergroupids_can_edit_fields,
2921 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmo' ),
2922 'can' => 'vmo',
2923 'isSearchable' => 1,
2924 ];
2925
2926 $this->fields['signature'] = [
2927 'fieldKey' => 'signature',
2928 'type' => 'tinymce',
2929 'wp_editor_settings' => $wp_editor_settings,
2930 'isDefault' => 1,
2931 'isRemovable' => 0,
2932 'isRequired' => 0,
2933 'isEditable' => 1,
2934 'label' => wpforo_phrase( 'Signature', false ),
2935 'title' => wpforo_phrase( 'Signature', false ),
2936 'placeholder' => wpforo_phrase( 'Signature', false ),
2937 'faIcon' => 'fas fa-address-card',
2938 'name' => 'signature',
2939 'cantBeInactive' => [],
2940 'canEdit' => $usergroupids_can_edit_fields,
2941 'canView' => WPF()->usergroup->get_groupids_by_can( 'vms' ),
2942 'can' => 'vms',
2943 'isSearchable' => 1,
2944 ];
2945
2946 $this->fields['about'] = [
2947 'fieldKey' => 'about',
2948 'type' => 'tinymce',
2949 'wp_editor_settings' => $wp_editor_settings,
2950 'isDefault' => 1,
2951 'isRemovable' => 0,
2952 'isRequired' => 0,
2953 'isEditable' => 1,
2954 'label' => wpforo_phrase( 'About Me', false ),
2955 'title' => wpforo_phrase( 'About Me', false ),
2956 'placeholder' => wpforo_phrase( 'About Me', false ),
2957 'faIcon' => 'fas fa-address-card',
2958 'name' => 'about',
2959 'cantBeInactive' => [],
2960 'canEdit' => $usergroupids_can_edit_fields,
2961 'canView' => WPF()->usergroup->get_groupids_by_can( 'vmam' ),
2962 'can' => 'vmam',
2963 'isSearchable' => 1,
2964 ];
2965
2966 $this->fields['html_soc_net'] = [
2967 'fieldKey' => 'html_soc_net',
2968 'type' => 'html',
2969 'isDefault' => 1,
2970 'isRemovable' => 0,
2971 'isRequired' => 0,
2972 'isEditable' => 1,
2973 'label' => wpforo_phrase( 'Social Networks', false ),
2974 'title' => wpforo_phrase( 'Social Networks', false ),
2975 'placeholder' => wpforo_phrase( 'Social Networks', false ),
2976 'description' => wpforo_phrase( 'Social Networks', false ),
2977 'html' => '<div class="wpf-label">' . wpforo_phrase( 'Social Networks', false ) . '</div>',
2978 'name' => 'html_soc_net',
2979 'cantBeInactive' => [],
2980 'canEdit' => $usergroupids_can_edit_fields,
2981 'canView' => $usergroupids_can_view_social_net,
2982 'can' => 'vmsn',
2983 'isSearchable' => 0,
2984 ];
2985
2986 $this->fields = apply_filters( 'wpforo_member_after_init_fields', $this->fields );
2987 }
2988
2989 private function init_countries() {
2990 $this->countries = [
2991 "Afghanistan",
2992 "�
2993 land Islands",
2994 "Albania",
2995 "Algeria",
2996 "American Samoa",
2997 "Andorra",
2998 "Angola",
2999 "Anguilla",
3000 "Antarctica",
3001 "Antigua and Barbuda",
3002 "Argentina",
3003 "Armenia",
3004 "Aruba",
3005 "Australia",
3006 "Austria",
3007 "Azerbaijan",
3008 "Bahamas",
3009 "Bahrain",
3010 "Bangladesh",
3011 "Barbados",
3012 "Belarus",
3013 "Belgium",
3014 "Belize",
3015 "Benin",
3016 "Bermuda",
3017 "Bhutan",
3018 "Bolivia",
3019 "Bosnia and Herzegovina",
3020 "Botswana",
3021 "Bouvet Island",
3022 "Brazil",
3023 "British Indian Ocean Territory",
3024 "Brunei Darussalam",
3025 "Bulgaria",
3026 "Burkina Faso",
3027 "Burundi",
3028 "Cambodia",
3029 "Cameroon",
3030 "Canada",
3031 "Cape Verde",
3032 "Cayman Islands",
3033 "Central African Republic",
3034 "Chad",
3035 "Chile",
3036 "China",
3037 "Christmas Island",
3038 "Cocos (Keeling) Islands",
3039 "Colombia",
3040 "Comoros",
3041 "Congo",
3042 "Congo, The Democratic Republic of The",
3043 "Cook Islands",
3044 "Costa Rica",
3045 "Cote D'ivoire",
3046 "Croatia",
3047 "Cuba",
3048 "Cyprus",
3049 "Czech Republic",
3050 "Denmark",
3051 "Djibouti",
3052 "Dominica",
3053 "Dominican Republic",
3054 "Ecuador",
3055 "Egypt",
3056 "El Salvador",
3057 "Equatorial Guinea",
3058 "Eritrea",
3059 "Estonia",
3060 "Ethiopia",
3061 "Falkland Islands (Malvinas)",
3062 "Faroe Islands",
3063 "Fiji",
3064 "Finland",
3065 "France",
3066 "French Guiana",
3067 "French Polynesia",
3068 "French Southern Territories",
3069 "Gabon",
3070 "Gambia",
3071 "Georgia",
3072 "Germany",
3073 "Ghana",
3074 "Gibraltar",
3075 "Greece",
3076 "Greenland",
3077 "Grenada",
3078 "Guadeloupe",
3079 "Guam",
3080 "Guatemala",
3081 "Guernsey",
3082 "Guinea",
3083 "Guinea-bissau",
3084 "Guyana",
3085 "Haiti",
3086 "Heard Island and Mcdonald Islands",
3087 "Holy See (Vatican City State)",
3088 "Honduras",
3089 "Hong Kong",
3090 "Hungary",
3091 "Iceland",
3092 "India",
3093 "Indonesia",
3094 "Iran, Islamic Republic of",
3095 "Iraq",
3096 "Ireland",
3097 "Isle of Man",
3098 "Israel",
3099 "Italy",
3100 "Jamaica",
3101 "Japan",
3102 "Jersey",
3103 "Jordan",
3104 "Kazakhstan",
3105 "Kenya",
3106 "Kiribati",
3107 "Korea, Democratic People's Republic of",
3108 "Korea, Republic of",
3109 "Kuwait",
3110 "Kyrgyzstan",
3111 "Lao People's Democratic Republic",
3112 "Latvia",
3113 "Lebanon",
3114 "Lesotho",
3115 "Liberia",
3116 "Libyan Arab Jamahiriya",
3117 "Liechtenstein",
3118 "Lithuania",
3119 "Luxembourg",
3120 "Macao",
3121 "Macedonia, The Former Yugoslav Republic of",
3122 "Madagascar",
3123 "Malawi",
3124 "Malaysia",
3125 "Maldives",
3126 "Mali",
3127 "Malta",
3128 "Marshall Islands",
3129 "Martinique",
3130 "Mauritania",
3131 "Mauritius",
3132 "Mayotte",
3133 "Mexico",
3134 "Micronesia, Federated States of",
3135 "Moldova, Republic of",
3136 "Monaco",
3137 "Mongolia",
3138 "Montenegro",
3139 "Montserrat",
3140 "Morocco",
3141 "Mozambique",
3142 "Myanmar",
3143 "Namibia",
3144 "Nauru",
3145 "Nepal",
3146 "Netherlands",
3147 "Netherlands Antilles",
3148 "New Caledonia",
3149 "New Zealand",
3150 "Nicaragua",
3151 "Niger",
3152 "Nigeria",
3153 "Niue",
3154 "Norfolk Island",
3155 "Northern Mariana Islands",
3156 "Norway",
3157 "Oman",
3158 "Pakistan",
3159 "Palau",
3160 "Palestinian Territory, Occupied",
3161 "Panama",
3162 "Papua New Guinea",
3163 "Paraguay",
3164 "Peru",
3165 "Philippines",
3166 "Pitcairn",
3167 "Poland",
3168 "Portugal",
3169 "Puerto Rico",
3170 "Qatar",
3171 "Reunion",
3172 "Romania",
3173 "Russian Federation",
3174 "Rwanda",
3175 "Saint Helena",
3176 "Saint Kitts and Nevis",
3177 "Saint Lucia",
3178 "Saint Pierre and Miquelon",
3179 "Saint Vincent and The Grenadines",
3180 "Samoa",
3181 "San Marino",
3182 "Sao Tome and Principe",
3183 "Saudi Arabia",
3184 "Senegal",
3185 "Serbia",
3186 "Seychelles",
3187 "Sierra Leone",
3188 "Singapore",
3189 "Slovakia",
3190 "Slovenia",
3191 "Solomon Islands",
3192 "Somalia",
3193 "South Africa",
3194 "South Georgia and The South Sandwich Islands",
3195 "Spain",
3196 "Sri Lanka",
3197 "Sudan",
3198 "Suriname",
3199 "Svalbard and Jan Mayen",
3200 "Swaziland",
3201 "Sweden",
3202 "Switzerland",
3203 "Syrian Arab Republic",
3204 "Taiwan, Province of China",
3205 "Tajikistan",
3206 "Tanzania, United Republic of",
3207 "Thailand",
3208 "Timor-leste",
3209 "Togo",
3210 "Tokelau",
3211 "Tonga",
3212 "Trinidad and Tobago",
3213 "Tunisia",
3214 "Turkey",
3215 "Turkmenistan",
3216 "Turks and Caicos Islands",
3217 "Tuvalu",
3218 "Uganda",
3219 "Ukraine",
3220 "United Arab Emirates",
3221 "United Kingdom",
3222 "United States",
3223 "United States Minor Outlying Islands",
3224 "Uruguay",
3225 "Uzbekistan",
3226 "Vanuatu",
3227 "Venezuela",
3228 "Viet Nam",
3229 "Virgin Islands, British",
3230 "Virgin Islands, U.S.",
3231 "Wallis and Futuna",
3232 "Western Sahara",
3233 "Yemen",
3234 "Zambia",
3235 "Zimbabwe",
3236 ];
3237 }
3238
3239 private function init_timezones() {
3240 $this->timezones = timezone_identifiers_list();
3241 $offset_range = [
3242 - 12,
3243 - 11.5,
3244 - 11,
3245 - 10.5,
3246 - 10,
3247 - 9.5,
3248 - 9,
3249 - 8.5,
3250 - 8,
3251 - 7.5,
3252 - 7,
3253 - 6.5,
3254 - 6,
3255 - 5.5,
3256 - 5,
3257 - 4.5,
3258 - 4,
3259 - 3.5,
3260 - 3,
3261 - 2.5,
3262 - 2,
3263 - 1.5,
3264 - 1,
3265 - 0.5,
3266 0,
3267 0.5,
3268 1,
3269 1.5,
3270 2,
3271 2.5,
3272 3,
3273 3.5,
3274 4,
3275 4.5,
3276 5,
3277 5.5,
3278 5.75,
3279 6,
3280 6.5,
3281 7,
3282 7.5,
3283 8,
3284 8.5,
3285 8.75,
3286 9,
3287 9.5,
3288 10,
3289 10.5,
3290 11,
3291 11.5,
3292 12,
3293 12.75,
3294 13,
3295 13.75,
3296 14,
3297 ];
3298 foreach( $offset_range as $offset ) {
3299 if( 0 <= $offset ) {
3300 $offset_name = '+' . $offset;
3301 } else {
3302 $offset_name = (string) $offset;
3303 }
3304
3305 $offset_value = $offset_name;
3306 $offset_value = 'UTC' . $offset_value;
3307 $this->timezones[] = 'UTC/' . $offset_value;
3308 }
3309
3310 $zones = $this->timezones;
3311 $timezones = [];
3312 foreach( $zones as $zone ) {
3313 if( strpos( (string) $zone, '/' ) === false ) continue;
3314
3315 $zone = str_replace( '_', ' ', $zone );
3316
3317 $group = function_exists( 'mb_substr' ) ? mb_substr(
3318 (string) $zone,
3319 0,
3320 strpos( (string) $zone, '/' )
3321 ) : substr( (string) $zone, 0, strpos( (string) $zone, '/' ) );
3322 $index = function_exists( 'mb_strlen' ) ? mb_strlen( (string) $group ) + 1 : strlen(
3323 (string) $group
3324 ) + 1;
3325 $optionValue = substr( (string) $zone, $index );
3326
3327 if( strpos( (string) $optionValue, 'UTC' ) !== false ) {
3328 $optionTitle = str_replace( [ '.25', '.5', '.75', ], [ ':15', ':30', ':45', ], $optionValue );
3329 $optionValue = "$optionValue=>$optionTitle";
3330 } else {
3331 $optionValue = "$zone=>$optionValue";
3332 }
3333
3334 $timezones[ $group ][] = $optionValue;
3335 }
3336
3337 $this->timezones = $timezones;
3338 }
3339
3340 public function get_fields( $only_defaults = false ) {
3341 $this->init_fields();
3342 $fields = $this->fields;
3343 if( $only_defaults ) {
3344 foreach( $fields as $k => $v ) if( ! wpfval( $v, 'isDefault' ) ) unset( $fields[ $k ] );
3345 } else {
3346 $this->fields = $fields = apply_filters( 'wpforo_get_fields', $fields );
3347 }
3348
3349 return $fields;
3350 }
3351
3352 public function get_field( $key ) {
3353 if( is_string( $key ) ) {
3354 $this->init_fields();
3355
3356 return (array) wpfval( $this->fields, $key );
3357 } elseif( $this->is_field( $key ) ) {
3358 return $key;
3359 }
3360
3361 return [];
3362 }
3363
3364 public function is_field( $field ) {
3365 return wpfval( $field, 'fieldKey' ) && wpfval( $field, 'type' ) && wpfkey( $field, 'isDefault' );
3366 }
3367
3368 public function get_field_key( $field ) {
3369 return is_string( $field ) ? $field : (string) wpfval( $field, 'fieldKey' );
3370 }
3371
3372 public function fields_structure_full_array( $fields, $need_password = null ) {
3373 if( is_string( $fields ) ) $fields = maybe_unserialize( $fields );
3374 $fs = [ [ [] ] ];
3375 if( ! is_array( $fields ) ) return $fs;
3376 if( is_null( $need_password ) ) {
3377 foreach( $fields as $kr => $row ) {
3378 if( is_array( $row ) ) {
3379 foreach( $row as $kc => $cols ) {
3380 if( is_array( $cols ) ) {
3381 foreach( $cols as $field ) {
3382 $field_key = $this->get_field_key( $field );
3383 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3384 }
3385 }
3386 }
3387 }
3388 }
3389 } else {
3390 $has_password = false;
3391 foreach( $fields as $kr => $row ) {
3392 if( is_array( $row ) ) {
3393 foreach( $row as $kc => $cols ) {
3394 if( is_array( $cols ) ) {
3395 foreach( $cols as $field ) {
3396 $field_key = $this->get_field_key( $field );
3397 if( $field_key === 'user_pass' ) {
3398 if( $need_password ) {
3399 $has_password = true;
3400 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3401 }
3402 } else {
3403 $fs[ $kr ][ $kc ][ $field_key ] = $this->get_field( $field );
3404 }
3405 }
3406 }
3407 }
3408 }
3409 }
3410 if( $need_password && ! $has_password ) $fs[][][] = $this->get_field( 'user_pass' );
3411 }
3412
3413 return $fs;
3414 }
3415
3416 public function get_register_fields_structure( $only_defaults = false ) {
3417 $need_password = ! wpforo_setting( 'authorization', 'user_register_email_confirm' );
3418 $regform = [ 'user_login', 'user_email' ];
3419 if( $need_password ) $regform[] = 'user_pass';
3420 $fields = [ [ $regform ] ];
3421 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_register_fields', $fields );
3422
3423 return $fields;
3424 }
3425
3426 public function get_register_fields( $only_defaults = false ) {
3427 return $this->fields_structure_full_array(
3428 $this->get_register_fields_structure( $only_defaults ),
3429 ! wpforo_setting( 'authorization', 'user_register_email_confirm' )
3430 );
3431 }
3432
3433 public function get_account_fields_structure( $only_defaults = false ) {
3434 $fields = [
3435 [
3436 [
3437 'user_login',
3438 'display_name',
3439 'user_nicename',
3440 'user_email',
3441 'title',
3442 'groupid',
3443 'avatar',
3444 'about',
3445 'user_url',
3446 'occupation',
3447 'signature',
3448 ],
3449 ],
3450 [
3451 [
3452 'html_soc_net',
3453 ],
3454 [
3455 'facebook',
3456 'linkedin',
3457 'instagram',
3458 'vkontakte',
3459 ],
3460 [
3461 'twitter',
3462 'youtube',
3463 'telegram',
3464 'skype',
3465 ],
3466 ],
3467 [
3468 [
3469 'location',
3470 'timezone',
3471 'user_pass',
3472 ],
3473 ],
3474 ];
3475 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_account_fields', $fields );
3476
3477 return $fields;
3478 }
3479
3480 public function get_account_fields( $only_defaults = false ) {
3481 return $this->fields_structure_full_array( $this->get_account_fields_structure( $only_defaults ) );
3482 }
3483
3484 public function get_profile_fields_structure( $only_defaults = false ) {
3485 $fields = [
3486 [
3487 [
3488 'about',
3489 'user_url',
3490 ],
3491 ],
3492 [
3493 [
3494 'location',
3495 'timezone',
3496 'occupation',
3497 'signature',
3498 ],
3499 ],
3500 [
3501 [
3502 'html_soc_net',
3503 ],
3504 ],
3505 [
3506 [
3507 'facebook',
3508 'linkedin',
3509 'instagram',
3510 'vkontakte',
3511 ],
3512 [
3513 'twitter',
3514 'youtube',
3515 'telegram',
3516 'skype',
3517 ],
3518 ],
3519 ];
3520 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_profile_fields', $fields );
3521
3522 return $fields;
3523 }
3524
3525 public function get_profile_fields( $only_defaults = false ) {
3526 return $this->fields_structure_full_array( $this->get_profile_fields_structure( $only_defaults ) );
3527 }
3528
3529 public function get_search_fields_structure( $only_defaults = false ) {
3530 $fields = [ [ [ 'display_name', 'user_nicename' ] ] ];
3531 if( ! $only_defaults ) $fields = apply_filters( 'wpforo_get_search_fields', $fields );
3532
3533 return $fields;
3534 }
3535
3536 public function get_search_fields( $only_defaults = false ) {
3537 $fields = $this->fields_structure_full_array( $this->get_search_fields_structure( $only_defaults ) );
3538 foreach( $fields as $row_key => $row ) {
3539 foreach( $row as $col_key => $col ) {
3540 foreach( $col as $field_key => $field ) {
3541 if( $this->is_field( $field ) ) {
3542 $fields[ $row_key ][ $col_key ][ $field_key ]['isRequired'] = 0;
3543 $fields[ $row_key ][ $col_key ][ $field_key ]['class'] = 'wpf-member-search-field';
3544 if( in_array( $field['type'], [ 'text', 'textarea', 'email', 'url' ], true ) ) {
3545 $fields[ $row_key ][ $col_key ][ $field_key ]['type'] = 'search';
3546 }
3547 }
3548 }
3549 }
3550 }
3551
3552 return $fields;
3553 }
3554
3555 public function get_search_fields_names( $only_defaults = false ) {
3556 $names = [];
3557 $fields = $this->get_search_fields( $only_defaults );
3558
3559 foreach( $fields as $row ) {
3560 foreach( $row as $col ) {
3561 foreach( $col as $field ) {
3562 if( $only_defaults && ! $field['isDefault'] ) continue;
3563 $names[] = $field['name'];
3564 }
3565 }
3566 }
3567
3568 return $names;
3569 }
3570
3571 public function get_participant_fields_list( $fields, $only_defaults = false ): array {
3572 $names = [];
3573
3574 foreach( $fields as $row ) {
3575 foreach( $row as $col ) {
3576 foreach( $col as $field ) {
3577 if( $only_defaults && ! $field['isDefault'] ) continue;
3578 $names[] = $field['name'];
3579 }
3580 }
3581 }
3582
3583 return $names;
3584 }
3585
3586 public function set_guest_cookies( $args ) {
3587 if( ! wpforo_setting( 'legal', 'cookies' ) ) return;
3588 if( isset( $args['name'] ) && isset( $args['email'] ) ) {
3589 $comment_cookie_lifetime = apply_filters( 'comment_cookie_lifetime', 30000000 );
3590 $secure = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );
3591 setcookie(
3592 'comment_author_' . COOKIEHASH,
3593 $args['name'],
3594 time() + $comment_cookie_lifetime,
3595 COOKIEPATH,
3596 COOKIE_DOMAIN,
3597 $secure
3598 );
3599 setcookie(
3600 'comment_author_email_' . COOKIEHASH,
3601 $args['email'],
3602 time() + $comment_cookie_lifetime,
3603 COOKIEPATH,
3604 COOKIE_DOMAIN,
3605 $secure
3606 );
3607
3608 WPF()->current_user_display_name = $args['name'];
3609 WPF()->current_user_email = $args['email'];
3610 }
3611 }
3612
3613 public function get_guest_cookies() {
3614 $guest = [ 'name' => '', 'email' => '' ];
3615 if( wpforo_setting( 'legal', 'cookies' ) ) {
3616 if( ! WPF()->current_userid && WPF()->current_user_email ) {
3617 $guest['name'] = WPF()->current_user_display_name;
3618 $guest['email'] = WPF()->current_user_email;
3619 } else {
3620 $guest_cookies = wp_get_current_commenter();
3621 $guest['name'] = ( isset( $guest_cookies['comment_author'] ) ) ? $guest_cookies['comment_author'] : '';
3622 $guest['email'] = ( isset( $guest_cookies['comment_author_email'] ) ) ? $guest_cookies['comment_author_email'] : '';
3623 }
3624 }
3625
3626 return $guest;
3627 }
3628
3629 public function set_is_email_confirmed( $userid, $status ) {
3630 if( false !== WPF()->db->update(
3631 WPF()->tables->profiles,
3632 [ 'is_email_confirmed' => intval( $status ) ],
3633 [ 'userid' => wpforo_bigintval( $userid ) ],
3634 [ '%d' ],
3635 [ '%d' ]
3636 ) ) {
3637 WPF()->notice->add( 'Email has been confirmed', 'success' );
3638
3639 return true;
3640 }
3641 WPF()->notice->add( 'Email confirm error', 'error' );
3642
3643 return false;
3644 }
3645
3646 public function get_is_email_confirmed( $userid ) {
3647 $sql = "SELECT `is_email_confirmed` FROM `" . WPF()->tables->profiles . "` WHERE `userid` = %d";
3648
3649 return (bool) WPF()->db->get_var( WPF()->db->prepare( $sql, $userid ) );
3650 }
3651
3652 /**
3653 * @param int $userid
3654 *
3655 * @return int
3656 */
3657 public function get_groupid( $userid ) {
3658 return (int) WPF()->db->get_var(
3659 WPF()->db->prepare(
3660 "SELECT `groupid`
3661 FROM `" . WPF()->tables->profiles . "`
3662 WHERE `userid` = %d",
3663 $userid
3664 )
3665 );
3666 }
3667
3668
3669 /**
3670 * @param int $userid
3671 * @param boolean $array
3672 *
3673 * @return string|array|null
3674 */
3675 public function get_secondary_groupids( $userid, $array = true ) {
3676 $secondary_groupids = WPF()->db->get_var(
3677 WPF()->db->prepare(
3678 "SELECT `secondary_groupids`
3679 FROM `" . WPF()->tables->profiles . "`
3680 WHERE `userid` = %d",
3681 $userid
3682 )
3683 );
3684
3685 if( $array && ! empty( $secondary_groupids ) ) return explode( ',', $secondary_groupids );
3686
3687 return $secondary_groupids;
3688 }
3689
3690 public function set_groupid( $userid, $groupid ) {
3691 $userid = wpforo_bigintval( $userid );
3692 $groupid = intval( $groupid );
3693 if( $userid && $groupid ) {
3694 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `groupid` = %d WHERE `userid` = %d";
3695 if( false !== WPF()->db->query( WPF()->db->prepare( $sql, $groupid, $userid ) ) ) {
3696 $this->reset( $userid );
3697 do_action( 'wpforo_set_groupid', $userid, $groupid );
3698
3699 return true;
3700 }
3701 }
3702
3703 return false;
3704 }
3705
3706 /**
3707 * @param int $userid
3708 * @param array|int $groupids
3709 *
3710 * @return bool
3711 */
3712 public function set_secondary_groupids( $userid, $groupids ) {
3713 $userid = wpforo_bigintval( $userid );
3714 if( $userid ) {
3715 $groupids = implode( ',', array_unique( array_filter( array_map( 'intval', (array) $groupids ) ) ) );
3716 $sql = "UPDATE `" . WPF()->tables->profiles . "` SET `secondary_groupids` = %s WHERE `userid` = %d";
3717 if( false !== WPF()->db->query( WPF()->db->prepare( $sql, $groupids, $userid ) ) ) {
3718 $this->reset( $userid );
3719
3720 return true;
3721 }
3722 }
3723
3724 return false;
3725 }
3726
3727 /**
3728 * @param int $userid
3729 * @param array|int $groupids
3730 *
3731 * @return bool
3732 */
3733 public function append_secondary_groupids( $userid, $groupids ) {
3734 $userid = wpforo_bigintval( $userid );
3735 if( $userid ) {
3736 if( $member = $this->get_member( $userid ) ) {
3737 $groupids = array_filter( array_map( 'intval', (array) $groupids ) );
3738 $groupids = array_merge( $member['secondary_groupids'], $groupids );
3739
3740 return $this->set_secondary_groupids( $userid, $groupids );
3741 }
3742 }
3743
3744 return false;
3745 }
3746
3747 public function after_register_new_user( $userid ) {
3748 if( wpforo_setting( 'authorization', 'manually_approval' ) || (int) trim(
3749 (string) get_user_meta( $userid, 'default_password_nag', true )
3750 ) ) {
3751 $this->update_profile_fields( $userid, [ 'status' => 'inactive' ], false );
3752 }
3753 }
3754
3755 public function after_password_reset( $user ) {
3756 $status = $this->get_status( $user->ID );
3757 if( $status !== 'banned' ) {
3758 $data = [ 'status' => 'active', 'is_email_confirmed' => 1 ];
3759 if( wpforo_setting( 'authorization', 'manually_approval' ) ) $data['status'] = $status;
3760 $this->update_profile_fields( $user->ID, $data, false );
3761 $this->reset( $user->ID );
3762 }
3763 }
3764
3765 public function wp_login( $user_login, $user ) {
3766 $this->inactive_to_active( wpforo_bigintval( $user->ID ), $user_login );
3767 }
3768
3769 public function get_distinct_status() {
3770 $sql = "SELECT DISTINCT `status` as statuses FROM `" . WPF()->tables->profiles . "`";
3771
3772 return WPF()->db->get_col( $sql );
3773 }
3774
3775 /**
3776 * @param array $args
3777 *
3778 * @return array selected userids
3779 */
3780 public function get_userids( $args ) {
3781 $sql = "SELECT `userid` FROM `" . WPF()->tables->profiles . "`";
3782 if( $args ) {
3783 $wheres = [];
3784 foreach( $args as $field => $value ) {
3785 $wheres[] = "`" . $field . "` = '" . esc_sql( $value ) . "'";
3786 }
3787 if( $wheres ) $sql .= " WHERE " . implode( " AND ", $wheres );
3788 }
3789
3790 $userids = WPF()->db->get_col( $sql );
3791
3792 return apply_filters( 'wpforo_member_after_get_userids', $userids );
3793 }
3794
3795 public function get_inlist_enabled_statuses() {
3796 return wpforo_setting( 'members', 'hide_inactive' ) ? [ 'active' ] : [ 'active', 'inactive', 'banned' ];
3797 }
3798
3799 /**
3800 * @param int $userid
3801 *
3802 * @return int
3803 */
3804 public function calc_approved_posts( $userid ) {
3805 if( $userid = wpforo_bigintval( $userid ) ) {
3806 $sqls = [];
3807 foreach( WPF()->get_active_boards_tables( 'posts' ) as $table ) {
3808 $sqls[] = WPF()->db->prepare(
3809 "SELECT COUNT(*)
3810 FROM `$table`
3811 WHERE `status` = 0
3812 AND `userid` = %d",
3813 $userid
3814 );
3815 }
3816
3817 if( $sqls ) {
3818 return (int) WPF()->db->get_var(
3819 "SELECT SUM(`COUNT(*)`) FROM (" . implode( ' UNION ALL ', $sqls ) . ") AS temp"
3820 );
3821 }
3822 }
3823
3824 return 0;
3825 }
3826
3827 /**
3828 * @param int $userid
3829 *
3830 * @return int
3831 */
3832 public function calc_approved_topics( $userid ) {
3833 if( $userid = wpforo_bigintval( $userid ) ) {
3834 $sqls = [];
3835 foreach( WPF()->get_active_boards_tables( 'topics' ) as $table ) {
3836 $sqls[] = WPF()->db->prepare(
3837 "SELECT COUNT(*)
3838 FROM `$table`
3839 WHERE `status` = 0
3840 AND `userid` = %d",
3841 $userid
3842 );
3843 }
3844
3845 if( $sqls ) {
3846 return (int) WPF()->db->get_var(
3847 "SELECT SUM(`COUNT(*)`) FROM (" . implode( ' UNION ALL ', $sqls ) . ") AS temp"
3848 );
3849 }
3850 }
3851
3852 return 0;
3853 }
3854
3855 /**
3856 * @param int $userid
3857 *
3858 * @return int
3859 */
3860 public function calc_approved_questions( $userid ) {
3861 if( $userid = wpforo_bigintval( $userid ) ) {
3862 $sqls = [];
3863 foreach( WPF()->get_active_boards_tables( 'topics' ) as $table ) {
3864 if( $forumids = Forums::get_forumids( str_replace( 'topics', 'forums', $table ), 3 ) ) {
3865 $sqls[] = WPF()->db->prepare(
3866 "SELECT COUNT(*)
3867 FROM `$table`
3868 WHERE `status` = 0
3869 AND `userid` = %d
3870 AND `forumid` IN( " . implode( ',', $forumids ) . " )",
3871 $userid
3872 );
3873 }
3874 }
3875
3876 if( $sqls ) {
3877 return (int) WPF()->db->get_var(
3878 "SELECT SUM(`COUNT(*)`) FROM (" . implode( ' UNION ALL ', $sqls ) . ") AS temp"
3879 );
3880 }
3881 }
3882
3883 return 0;
3884 }
3885
3886 /**
3887 * @param int $userid
3888 *
3889 * @return int
3890 */
3891 public function calc_approved_answers( $userid ) {
3892 if( $userid = wpforo_bigintval( $userid ) ) {
3893 $sqls = [];
3894 foreach( WPF()->get_active_boards_tables( 'posts' ) as $table ) {
3895 if( $forumids = Forums::get_forumids( str_replace( 'posts', 'forums', $table ), 3 ) ) {
3896 $sqls[] = WPF()->db->prepare(
3897 "SELECT COUNT(*)
3898 FROM `$table`
3899 WHERE `status` = 0
3900 AND `is_first_post` = 0
3901 AND `parentid` = 0
3902 AND `userid` = %d
3903 AND `forumid` IN( " . implode( ',', $forumids ) . " )",
3904 $userid
3905 );
3906 }
3907 }
3908
3909 if( $sqls ) {
3910 return (int) WPF()->db->get_var(
3911 "SELECT SUM(`COUNT(*)`) FROM (" . implode( ' UNION ALL ', $sqls ) . ") AS temp"
3912 );
3913 }
3914 }
3915
3916 return 0;
3917 }
3918
3919 /**
3920 * @param int $userid
3921 *
3922 * @return int
3923 */
3924 public function calc_approved_comments( $userid ) {
3925 if( $userid = wpforo_bigintval( $userid ) ) {
3926 $sqls = [];
3927 foreach( WPF()->get_active_boards_tables( 'posts' ) as $table ) {
3928 if( $forumids = Forums::get_forumids( str_replace( 'posts', 'forums', $table ), 3 ) ) {
3929 $sqls[] = WPF()->db->prepare(
3930 "SELECT COUNT(*)
3931 FROM `$table`
3932 WHERE `status` = 0
3933 AND `is_first_post` = 0
3934 AND `parentid` <> 0
3935 AND `userid` = %d
3936 AND `forumid` IN( " . implode( ',', $forumids ) . " )",
3937 $userid
3938 );
3939 }
3940 }
3941
3942 if( $sqls ) {
3943 return (int) WPF()->db->get_var(
3944 "SELECT SUM(`COUNT(*)`) FROM (" . implode( ' UNION ALL ', $sqls ) . ") AS temp"
3945 );
3946 }
3947 }
3948
3949 return 0;
3950 }
3951
3952 /**
3953 * @param int $userid
3954 *
3955 * @return array
3956 */
3957 public function calc_reactions_in( int $userid ): array {
3958 $reactions_in = array_map( '__return_zero', array_flip( Reactions::get_type_list() ) );
3959 if( $userid = wpforo_bigintval( $userid ) ) {
3960 $sqls = [];
3961 foreach( WPF()->get_active_boards_tables( 'reactions' ) as $table ) {
3962 $sqls[] = WPF()->db->prepare(
3963 "SELECT `type`
3964 FROM `$table`
3965 WHERE `post_userid` = %d",
3966 $userid
3967 );
3968 }
3969
3970 if( $sqls ) {
3971 $r = (array) WPF()->db->get_results(
3972 "SELECT `type`, COUNT(`type`) as `count` FROM (" . implode(
3973 ' UNION ALL ',
3974 $sqls
3975 ) . ") AS temp GROUP BY `type`",
3976 ARRAY_A
3977 );
3978 foreach( $r as $_r ) $reactions_in[ $_r['type'] ] = intval( $_r['count'] );
3979 }
3980 }
3981
3982 return $reactions_in;
3983 }
3984
3985 /**
3986 * @param int $userid
3987 *
3988 * @return array
3989 */
3990 public function calc_reactions_out( int $userid ): array {
3991 $reactions_out = array_map( '__return_zero', array_flip( Reactions::get_type_list() ) );
3992 if( $userid = wpforo_bigintval( $userid ) ) {
3993 $sqls = [];
3994 foreach( WPF()->get_active_boards_tables( 'reactions' ) as $table ) {
3995 $sqls[] = WPF()->db->prepare(
3996 "SELECT `type`
3997 FROM `$table`
3998 WHERE `userid` = %d",
3999 $userid
4000 );
4001 }
4002
4003 if( $sqls ) {
4004 $r = (array) WPF()->db->get_results(
4005 "SELECT `type`, COUNT(`type`) as `count` FROM (" . implode(
4006 ' UNION ALL ',
4007 $sqls
4008 ) . ") AS temp GROUP BY `type`",
4009 ARRAY_A
4010 );
4011 foreach( $r as $_r ) $reactions_out[ $_r['type'] ] = intval( $_r['count'] );
4012 }
4013 }
4014
4015 return $reactions_out;
4016 }
4017
4018 /**
4019 * @param int $userid
4020 *
4021 * @return void
4022 */
4023 public function rebuild_stats( int $userid ) {
4024 $posts = $this->calc_approved_posts( $userid );
4025 $topics = $this->calc_approved_topics( $userid );
4026 $questions = $this->calc_approved_questions( $userid );
4027 $answers = $this->calc_approved_answers( $userid );
4028 $comments = $this->calc_approved_comments( $userid );
4029 $reactions_in = $this->calc_reactions_in( $userid );
4030 $reactions_out = $this->calc_reactions_out( $userid );
4031 $points = $this->calc_points(
4032 compact( 'posts', 'topics', 'questions', 'answers', 'comments', 'reactions_in', 'reactions_out' )
4033 );
4034
4035 if( WPF()->db->update(
4036 WPF()->tables->profiles,
4037 [
4038 'posts' => $posts,
4039 'topics' => $topics,
4040 'questions' => $questions,
4041 'answers' => $answers,
4042 'comments' => $comments,
4043 'reactions_in' => wp_json_encode( $reactions_in ),
4044 'reactions_out' => wp_json_encode( $reactions_out ),
4045 'points' => $points,
4046 ],
4047 [ 'userid' => $userid ],
4048 [ '%d', '%d', '%d', '%d', '%d', '%s', '%s', '%d' ],
4049 '%d'
4050 ) ) {
4051 $this->reset( $userid );
4052 }
4053 }
4054
4055 public function after_add_topic( $topic ) {
4056 if( ! intval( $topic['status'] ) ) $this->rebuild_stats( $topic['userid'] );
4057 }
4058
4059 public function after_delete_topic( $topic ) {
4060 if( ! intval( $topic['status'] ) ) $this->rebuild_stats( $topic['userid'] );
4061 }
4062
4063 public function after_topic_status_update( $topic ) {
4064 $this->rebuild_stats( $topic['userid'] );
4065 }
4066
4067 public function before_merge_topic( $target, $current, $postids ) {
4068 $sql = "SELECT DISTINCT `userid` FROM `" . WPF()->tables->posts . "` WHERE `topicid` = %d";
4069 $sql = WPF()->db->prepare( $sql, $current['topicid'] );
4070 if( $postids ) $sql .= " AND `postid` IN(" . implode( ',', $postids ) . ")";
4071 $this->touched_userids = array_merge( $this->touched_userids, WPF()->db->get_col( $sql ) );
4072 }
4073
4074 public function after_merge_topic() {
4075 foreach( array_unique( array_filter( $this->touched_userids ) ) as $userid ) $this->rebuild_stats( $userid );
4076 }
4077
4078 public function after_move_topic( $topic ) {
4079 $sql = "SELECT DISTINCT `userid` FROM `" . WPF()->tables->posts . "` WHERE `topicid` = %d";
4080 $sql = WPF()->db->prepare( $sql, $topic['topicid'] );
4081 foreach( WPF()->db->get_col( $sql ) as $userid ) $this->rebuild_stats( $userid );
4082 }
4083
4084 public function after_add_post( $post ) {
4085 if( ! intval( $post['status'] ) ) $this->rebuild_stats( $post['userid'] );
4086 }
4087
4088 public function after_delete_post( $post ) {
4089 if( ! intval( $post['status'] ) ) $this->rebuild_stats( $post['userid'] );
4090 }
4091
4092 public function after_post_status_update( $post ) {
4093 $this->rebuild_stats( $post['userid'] );
4094 }
4095
4096 public function after_add_reaction( $reaction ) {
4097 $this->rebuild_stats( $reaction['userid'] );
4098 $this->rebuild_stats( $reaction['post_userid'] );
4099 }
4100
4101 public function after_edit_reaction( $fields, $where ) {
4102 $field_userid = wpfval( $fields, 'userid' );
4103 $field_post_userid = wpfval( $fields, 'post_userid' );
4104 if( $field_userid || $field_post_userid ) {
4105 $userids = [
4106 $field_userid,
4107 $field_post_userid,
4108 wpfval( $where, 'userid' ),
4109 wpfval( $where, 'post_userid' ),
4110 ];
4111 $userids = array_filter( $userids );
4112 $userids = array_unique( $userids );
4113 foreach( $userids as $userid ) $this->rebuild_stats( $userid );
4114 }
4115 }
4116
4117 public function before_delete_reaction( $args, $operator ) {
4118 $reactions = WPF()->reaction->get_reactions( $args, $operator );
4119 foreach( $reactions as $reaction ) {
4120 $this->touched_userids[] = $reaction['userid'];
4121 $this->touched_userids[] = $reaction['post_userid'];
4122 }
4123 }
4124
4125 public function after_delete_reaction() {
4126 foreach( array_unique( array_filter( $this->touched_userids ) ) as $userid ) $this->rebuild_stats( $userid );
4127 }
4128
4129 public function after_delete_user( $userid, $reassign ) {
4130 if( $reassign ) $this->rebuild_stats( $reassign );
4131 }
4132
4133 public function after_activate_user( $userid ) {
4134 $user = get_user_by( 'ID', $userid );
4135 if( $user ) {
4136 $sbj = wpforo_setting( 'email', 'after_user_approve_email_subject' );
4137 $msg = wpforo_setting( 'email', 'after_user_approve_email_message' );
4138 $blogname = get_option( 'blogname', '' );
4139 $login_url = wpforo_login_url( '' );
4140 $login_link = sprintf( '<a href="%1$s">%2$s</a>', $login_url, $blogname );
4141
4142 $sbj = str_replace( [ '[blogname]', '[user_login]', '[login_link]', '[login_url]' ],
4143 [ $blogname, $user->user_login, $login_link, $login_url ],
4144 $sbj );
4145 $msg = str_replace( [ '[blogname]', '[user_login]', '[login_link]', '[login_url]' ],
4146 [ $blogname, $user->user_login, $login_link, $login_url ],
4147 $msg );
4148 wpforo_send_email( $user->user_email, $sbj, $msg );
4149 }
4150 }
4151
4152 public function get_activity_url( $filter = '', $boardid = null, $arg = null ) {
4153 if( ! $arg ) $arg = WPF()->current_object['user'];
4154 $url = rtrim( $this->get_profile_url( $arg, 'activity' ), '/' );
4155 if( is_wpforo_multiboard() ) {
4156 if( is_null( $boardid ) ) {
4157 $boardid = wpfkey( WPF()->GET, 'boardid' ) ? (int) wpfval(
4158 WPF()->GET,
4159 'boardid'
4160 ) : WPF()->board->get_current( 'boardid' );
4161 }
4162 if( $filter ) {
4163 $url .= sprintf( '/?boardid=%1$d&filter=%2$s', $boardid, $filter );
4164 } else {
4165 $url .= sprintf( '/?boardid=%1$d', $boardid );
4166 }
4167 } elseif( $filter ) {
4168 $url .= sprintf( '/?filter=%1$s', $filter );
4169 }
4170
4171 return WPF()->user_trailingslashit( $url );
4172 }
4173
4174 public function get_favored_url( $filter = '', $boardid = null, $arg = null ) {
4175 if( ! $arg ) $arg = WPF()->current_object['user'];
4176 $url = rtrim( $this->get_profile_url( $arg, 'favored' ), '/' );
4177 if( is_wpforo_multiboard() ) {
4178 if( is_null( $boardid ) ) {
4179 $boardid = wpfkey( WPF()->GET, 'boardid' ) ? (int) wpfval(
4180 WPF()->GET,
4181 'boardid'
4182 ) : WPF()->board->get_current( 'boardid' );
4183 }
4184 if( $filter ) {
4185 $url .= sprintf( '/?boardid=%1$d&filter=%2$s', $boardid, $filter );
4186 } else {
4187 $url .= sprintf( '/?boardid=%1$d', $boardid );
4188 }
4189 } elseif( $filter ) {
4190 $url .= sprintf( '/?filter=%1$s', $filter );
4191 }
4192
4193 return WPF()->user_trailingslashit( $url );
4194 }
4195
4196 public function get_newest_member( $status_filter = true ) {
4197 if( ! ( $visible_usergroup_ids = WPF()->usergroup->get_visible_usergroup_ids() ) ) return [];
4198
4199 $groupids = implode( ", ", $visible_usergroup_ids );
4200
4201 if( $status_filter ) {
4202 $status = implode( "', '", $this->get_inlist_enabled_statuses() );
4203 $sql = "SELECT `userid` FROM `" . WPF()->tables->profiles . "`
4204 WHERE `status` IN ('" . $status . "')
4205 AND `groupid` IN (" . $groupids . ")
4206 ORDER BY `userid` DESC LIMIT 1";
4207 } else {
4208 $sql = "SELECT `userid` FROM `" . WPF()->tables->profiles . "`
4209 WHERE `groupid` IN (" . $groupids . ")
4210 ORDER BY `userid` DESC LIMIT 1";
4211 }
4212
4213 $memberid = WPF()->db->get_var( $sql );
4214 $member = wpforo_member( $memberid );
4215
4216 if( empty( $member ) ) {
4217
4218 WPF()->db->query(
4219 "DELETE p FROM `" . WPF()->tables->profiles . "` p LEFT JOIN `" . WPF()->db->users . "` u ON u.ID = p.userid WHERE u.ID IS NULL"
4220 );
4221
4222 $memberid = WPF()->db->get_var( $sql );
4223 $member = wpforo_member( $memberid );
4224
4225 if( empty( $member ) ) {
4226 if( $status_filter ) {
4227 $members = $this->get_members(
4228 [
4229 'orderby' => 'userid',
4230 'status' => [ 'active' ],
4231 'order' => 'DESC',
4232 'row_count' => 1,
4233 'groupids' => $visible_usergroup_ids,
4234 ]
4235 );
4236 } else {
4237 $members = $this->get_members(
4238 [
4239 'orderby' => 'userid',
4240 'order' => 'DESC',
4241 'row_count' => 1,
4242 'groupids' => $visible_usergroup_ids,
4243 ]
4244 );
4245 }
4246 if( isset( $members[0] ) && ! empty( $members[0] ) ) {
4247 $member = $members[0];
4248 } else {
4249 $member = [];
4250 }
4251 }
4252 }
4253 $member['profile_url'] = wpfval( $member, 'profile_url' ) ?: $this->get_profile_url( $memberid );
4254
4255 return $member;
4256 }
4257
4258 public function buffer_before_front_delete_user( $user ) {
4259 // Buffer email content before the user is deleted so shortcodes resolve to the real user, not guest
4260 if( wpfval( $user, 'userid' ) === WPF()->current_userid ) {
4261 if( wpforo_setting( 'authorization', 'send_email_after_user_delete' ) ) {
4262 $sbj = wpforo_setting( 'email', 'after_user_delete_notification_email_admin_subject' );
4263 $sbj = str_replace(
4264 [ '[datetime]', '[blogname]' ],
4265 [ _wpforo_date( 0, 'mysql', 'wp' ), '[' . get_bloginfo( 'name' ) . ']' ],
4266 $sbj
4267 );
4268 $sbj = wpforo_apply_email_shortcodes( $sbj, [], [], [], $user, '' );
4269
4270 $msg = wpforo_setting( 'email', 'after_user_delete_notification_email_admin_message' );
4271 $msg = str_replace(
4272 [ '[datetime]', '[blogname]' ],
4273 [ _wpforo_date( 0, 'mysql', 'wp' ), '[' . get_bloginfo( 'name' ) . ']' ],
4274 $msg
4275 );
4276 $msg = wpforo_apply_email_shortcodes( $msg, [], [], [], $user, '' );
4277 $msg = wpautop( $msg );
4278
4279 $this->front_delete_email_buffer = [
4280 'subject' => $sbj,
4281 'message' => $msg,
4282 ];
4283 }
4284 }
4285 }
4286
4287 public function after_front_delete_user( $user ) {
4288 if( wpfval( $user, 'userid' ) === WPF()->current_userid ) {
4289 if( wpforo_setting( 'authorization', 'send_email_after_user_delete' ) ) {
4290 // Prefer buffered email if available
4291 if( is_array( $this->front_delete_email_buffer ) ) {
4292 $sbj = (string) wpfval( $this->front_delete_email_buffer, 'subject' );
4293 $msg = (string) wpfval( $this->front_delete_email_buffer, 'message' );
4294 wpforo_send_email( wpforo_setting( 'email', 'admin_emails' ), $sbj, $msg );
4295 $this->front_delete_email_buffer = null; // clear buffer
4296 }
4297 }
4298 }
4299 }
4300 }
4301