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

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

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