PluginProbe
wpForo Forum / 3.1.4
wpForo Forum v3.1.4
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 / Actions.php

Actions.php in wpForo Forum 3.1.4, at classes/Actions.php

3,463 lines 113.7 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 // Exit if accessed directly
6 if( ! defined( 'ABSPATH' ) ) exit();
7
8 class Actions {
9 /**
10 * wpForoAction constructor.
11 */
12 public function __construct() {
13 $this->init_hooks();
14 }
15
16 /**
17 * method for initializing all necessary hooks
18 */
19 public function init_hooks() {
20 add_action( 'wpforo_after_init_classes', function() { if( WPF()->need_activation() ) wpforo_activation(); }, 0 );
21
22 add_action( 'wpforo_after_init', [ $this, 'do_actions' ], 999 );
23 add_action( 'wpforo_action_user_delete', [ $this, 'user_delete' ] );
24 add_action( 'deleted_user', [ $this, 'deleted_user' ], 10, 2 );
25
26 add_action( 'wp_ajax_wpforo_profiles_default_cover_upload', [ $this, 'profiles_default_cover_upload' ] );
27 add_action( 'wp_ajax_wpforo_deactivate', [ $this, 'deactivate' ] );
28
29 if( ! wpforo_is_admin() ) {
30 add_action( 'wpforo_actions', function() {
31 if( wpfval( $_REQUEST, 'wpfaction' ) === 'topic_add' ) unregister_post_type( 'topic' );
32 } );
33
34 add_action( 'wpforo_actions', [ $this, 'init_default_attach_hooks' ] );
35 add_action( 'wpforo_actions', [ $this, 'init_wp_emoji_hooks' ] );
36
37 add_action( 'wpforo_actions', [ $this, 'feed_rss2' ] );
38 add_action( 'wpforo_actions', [ $this, 'mark_all_read' ] );
39 add_action( 'wpforo_actions', [ $this, 'mark_notification_read' ] );
40
41 add_action( 'wpforo_action_registration', [ $this, 'registration' ] );
42 add_action( 'wpforo_action_login', [ $this, 'login' ] );
43 add_action( 'wpforo_action_lostpassword', [ $this, 'lostpassword' ] );
44 add_action( 'wpforo_action_resetpassword_form', [ $this, 'resetpassword_form' ] );
45 add_action( 'wpforo_action_resetpassword', [ $this, 'resetpassword' ] );
46 add_action( 'wpforo_action_profile_update', [ $this, 'profile_update' ] );
47 add_action( 'wpforo_action_ucf_file_delete', [ $this, 'ucf_file_delete' ] );
48 add_action( 'wpforo_action_cantlogin_contact', [ $this, 'cantlogin_contact' ] );
49
50 add_action( 'wpforo_action_topic_add', [ $this, 'topic_add' ] );
51 add_action( 'wpforo_action_topic_edit', [ $this, 'topic_edit' ] );
52 add_action( 'wpforo_action_topic_move', [ $this, 'topic_move' ] );
53 add_action( 'wpforo_action_topic_merge', [ $this, 'topic_merge' ] );
54 add_action( 'wpforo_action_topic_split', [ $this, 'topic_split' ] );
55
56 add_action( 'wpforo_action_post_add', [ $this, 'post_add' ] );
57 add_action( 'wpforo_action_post_edit', [ $this, 'post_edit' ] );
58
59 ## ajax actions ##
60 add_action( 'wp_ajax_wpforo_dissmiss_recaptcha_note', [ $this, 'dissmiss_recaptcha_note' ] );
61 add_action( 'wp_ajax_wpforo_acp_toggle', [ $this, 'acp_toggle' ] );
62 add_action( 'wp_ajax_wpforo_clear_all_notifications', [ $this, 'clear_all_notifications' ] );
63 add_action( 'wp_ajax_wpforo_profile_cover_upload', [ $this, 'profile_cover_upload' ] );
64 add_action( 'wp_ajax_wpforo_profile_cover_delete', [ $this, 'profile_cover_delete' ] );
65 add_action( 'wp_ajax_wpforo_get_topic_head_more_info', [ $this, 'get_topic_head_more_info' ] );
66 add_action( 'wp_ajax_nopriv_wpforo_get_topic_head_more_info', [ $this, 'get_topic_head_more_info' ] );
67 add_action( 'wp_ajax_wpforo_get_topic_overview_chunk', [ $this, 'get_topic_overview_chunk' ] );
68 add_action( 'wp_ajax_nopriv_wpforo_get_topic_overview_chunk', [ $this, 'get_topic_overview_chunk' ] );
69 add_action( 'wp_ajax_wpforo_get_overview', [ $this, 'get_overview' ] );
70 add_action( 'wp_ajax_nopriv_wpforo_get_overview', [ $this, 'get_overview' ] );
71 add_action( 'wp_ajax_wpforo_user_ban', [ $this, 'user_ban_ajax' ] );
72 add_action( 'wp_ajax_wpforo_get_member_template', [ $this, 'get_member_template' ] );
73 add_action( 'wp_ajax_nopriv_wpforo_get_member_template', [ $this, 'get_member_template' ] );
74 add_action( 'wp_ajax_wpforo_search_existed_topics', [ $this, 'search_existed_topics' ] );
75 add_action( 'wp_ajax_nopriv_wpforo_search_existed_topics', [ $this, 'search_existed_topics' ] );
76 add_action( 'wp_ajax_wpforo_confirm_current_user_password', [ $this, 'confirm_current_user_password' ] );
77
78 // AI Features admin AJAX handlers
79 add_action( 'wp_ajax_wpforo_ai_store_checkout_mapping', [ $this, 'ai_store_checkout_mapping' ] );
80 add_action( 'wp_ajax_wpforo_ai_get_legal_document', [ $this, 'ai_get_legal_document' ] );
81 } else {
82 add_action( 'wpforo_actions', [ $this, 'check_dashboard_permissions' ], 1 );
83 add_action( 'wpforo_actions', [ $this, 'repair_lost_main_shortcode_page' ] );
84
85 add_action( 'wpforo_action_synch_user_profiles', [ $this, 'synch_user_profiles' ] );
86 add_action( 'wpforo_action_reset_user_cache', [ $this, 'reset_user_cache' ] );
87 add_action( 'wpforo_action_reset_forums_stats', [ $this, 'reset_forums_stats' ] );
88 add_action( 'wpforo_action_reset_topics_stats', [ $this, 'reset_topics_stats' ] );
89 add_action( 'wpforo_action_reset_users_stats', [ $this, 'reset_users_stats' ] );
90 add_action( 'wpforo_action_rebuild_threads', [ $this, 'rebuild_threads' ] );
91 add_action( 'wpforo_action_reset_phrase_cache', [ $this, 'reset_phrase_cache' ] );
92 add_action( 'wpforo_action_recrawl_phrases', [ $this, 'recrawl_phrases' ] );
93 add_action( 'wpforo_action_clean_up', [ $this, 'clean_up' ] );
94 add_action( 'wpforo_action_flush_permalinks', [ $this, 'flush_permalinks' ] );
95
96 add_action( 'wpforo_action_base_slugs_settings_save', [ $this, 'base_slugs_settings_save' ] );
97 add_action( 'wpforo_action_general_settings_save', [ $this, 'general_settings_save' ] );
98
99 add_action( 'wpforo_action_slugs_settings_save', [ $this, 'slugs_settings_save' ] );
100 add_action( 'wpforo_action_board_settings_save', [ $this, 'board_settings_save' ] );
101
102 add_action( 'wpforo_action_akismet_settings_save', [ $this, 'akismet_settings_save' ] );
103 add_action( 'wpforo_action_antispam_settings_save', [ $this, 'antispam_settings_save' ] );
104 add_action( 'wpforo_action_authorization_settings_save', [ $this, 'authorization_settings_save' ] );
105 add_action( 'wpforo_action_buddypress_settings_save', [ $this, 'buddypress_settings_save' ] );
106 add_action( 'wpforo_action_components_settings_save', [ $this, 'components_settings_save' ] );
107 add_action( 'wpforo_action_email_settings_save', [ $this, 'email_settings_save' ] );
108 add_action( 'wpforo_action_forums_settings_save', [ $this, 'forums_settings_save' ] );
109 add_action( 'wpforo_action_logging_settings_save', [ $this, 'logging_settings_save' ] );
110 add_action( 'wpforo_action_activity_settings_save', [ $this, 'activity_settings_save' ] );
111 add_action( 'wpforo_action_members_settings_save', [ $this, 'members_settings_save' ] );
112 add_action( 'wpforo_action_notifications_settings_save', [ $this, 'notifications_settings_save' ] );
113 add_action( 'wpforo_action_posting_settings_save', [ $this, 'posting_settings_save' ] );
114 add_action( 'wpforo_action_profiles_settings_save', [ $this, 'profiles_settings_save' ] );
115 add_action( 'wpforo_action_rating_settings_save', [ $this, 'rating_settings_save' ] );
116 add_action( 'wpforo_action_recaptcha_settings_save', [ $this, 'recaptcha_settings_save' ] );
117 add_action( 'wpforo_action_rss_settings_save', [ $this, 'rss_settings_save' ] );
118 add_action( 'wpforo_action_seo_settings_save', [ $this, 'seo_settings_save' ] );
119 add_action( 'wpforo_action_social_settings_save', [ $this, 'social_settings_save' ] );
120 add_action( 'wpforo_action_styles_settings_save', [ $this, 'styles_settings_save' ] );
121 add_action( 'wpforo_action_tags_settings_save', [ $this, 'tags_settings_save' ] );
122 add_action( 'wpforo_action_topics_settings_save', [ $this, 'topics_settings_save' ] );
123 add_action( 'wpforo_action_um_settings_save', [ $this, 'um_settings_save' ] );
124 add_action( 'wpforo_action_legal_settings_save', [ $this, 'legal_settings_save' ] );
125 add_action( 'wpforo_action_ai_settings_save', [ $this, 'ai_settings_save' ] );
126 add_action( 'wpforo_action_settings_export', [ $this, 'settings_export' ] );
127 add_action( 'wpforo_action_settings_import', [ $this, 'settings_import' ] );
128
129 add_action( 'wpforo_action_board_add', [ $this, 'board_add' ] );
130 add_action( 'wpforo_action_board_edit', [ $this, 'board_edit' ] );
131 add_action( 'wpforo_action_board_repair', [ $this, 'board_repair' ] );
132 add_action( 'wpforo_action_board_delete', [ $this, 'board_delete' ] );
133
134 add_action( 'wpforo_action_add_new_xml_translation', [ $this, 'add_new_xml_translation' ] );
135 add_action( 'wpforo_action_phrases_change_lang', [ $this, 'phrases_change_lang' ] );
136 add_action( 'wpforo_action_dashboard_options_save', [ $this, 'dashboard_options_save' ] );
137 add_action( 'wpforo_action_colors_css_download', [ $this, 'colors_css_download' ] );
138 // add_action( 'wpforo_action_cleanup_options_save', [ $this, 'cleanup_options_save' ] );
139 add_action( 'wpforo_action_misc_options_save', [ $this, 'misc_options_save' ] );
140 add_action( 'wpforo_action_legal_options_save', [ $this, 'legal_options_save' ] );
141 add_action( 'wpforo_action_delete_spam_file', [ $this, 'delete_spam_file' ] );
142 add_action( 'wpforo_action_delete_all_spam_files', [ $this, 'delete_all_spam_files' ] );
143 add_action( 'wpforo_action_database_update', [ $this, 'database_update' ] );
144
145 add_action( 'wpforo_action_forum_copy', [ $this, 'forum_copy' ] );
146 add_action( 'wpforo_action_forum_add', [ $this, 'forum_add' ] );
147 add_action( 'wpforo_action_forum_edit', [ $this, 'forum_edit' ] );
148 add_action( 'wpforo_action_forum_delete', [ $this, 'forum_delete' ] );
149 add_action( 'wpforo_action_forum_hierarchy_save', [ $this, 'forum_hierarchy_save' ] );
150
151 add_action( 'wpforo_action_dashboard_post_unapprove', [ $this, 'dashboard_post_unapprove' ] );
152 add_action( 'wpforo_action_dashboard_post_approve', [ $this, 'dashboard_post_approve' ] );
153 add_action( 'wpforo_action_dashboard_post_delete', [ $this, 'dashboard_post_delete' ] );
154 add_action( 'wpforo_action_bulk_moderation', [ $this, 'bulk_moderation' ] );
155
156 add_action( 'wpforo_action_phrase_add', [ $this, 'phrase_add' ] );
157 add_action( 'wpforo_action_phrase_edit_form', [ $this, 'phrase_edit_form' ] );
158 add_action( 'wpforo_action_phrase_edit', [ $this, 'phrase_edit' ] );
159
160 add_action( 'wpforo_action_user_ban', [ $this, 'user_ban' ] );
161 add_action( 'wpforo_action_user_unban', [ $this, 'user_unban' ] );
162 add_action( 'wpforo_action_user_activate', [ $this, 'user_activate' ] );
163 add_action( 'wpforo_action_user_deactivate', [ $this, 'user_deactivate' ] );
164 add_action( 'wpforo_action_bulk_members', [ $this, 'bulk_members' ] );
165
166 add_action( 'wpforo_action_usergroup_add', [ $this, 'usergroup_add' ] );
167 add_action( 'wpforo_action_usergroup_edit', [ $this, 'usergroup_edit' ] );
168 add_action( 'wpforo_action_usergroup_delete', [ $this, 'usergroup_delete' ] );
169 add_action( 'wpforo_action_default_groupid_change', [ $this, 'default_groupid_change' ] );
170 add_action( 'wpforo_action_usergroup_delete_form', [ $this, 'usergroup_delete_form' ] );
171
172 add_action( 'wpforo_action_access_add', [ $this, 'access_add' ] );
173 add_action( 'wpforo_action_access_edit', [ $this, 'access_edit' ] );
174 add_action( 'wpforo_action_access_delete', [ $this, 'access_delete' ] );
175
176 add_action( 'wpforo_action_theme_activate', [ $this, 'theme_activate' ] );
177 add_action( 'wpforo_action_theme_delete', [ $this, 'theme_delete' ] );
178
179 add_action( 'wpforo_action_update_addons_css', [ $this, 'update_addons_css' ] );
180 add_action( 'wpforo_action_dissmiss_poll_version_is_old', [ $this, 'dissmiss_poll_version_is_old' ] );
181
182 add_action( 'wpforo_action_uninstall', [ $this, 'uninstall' ] );
183 }
184 add_action( 'wpforo_action_reset_all_caches', [ $this, 'reset_all_caches' ] );
185 }
186
187 /**
188 * wpforo main actions doing place
189 */
190 public function do_actions() {
191 do_action( 'wpforo_actions' );
192 $wpforo_actions = array_unique(
193 array_merge( (array) wpfval( $_POST, 'wpfaction' ), (array) wpfval( WPF()->GET, 'wpfaction' ) )
194 );
195 if( ! empty( $wpforo_actions ) ) {
196 foreach( $wpforo_actions as $wpforo_action ) {
197 $wpforo_action = sanitize_title( $wpforo_action );
198 do_action( "wpforo_action_{$wpforo_action}" );
199 }
200 }
201 do_action( 'wpforo_actions_end' );
202 }
203
204 /**
205 * init wpforo default attachments system when wpforo advanced attachments addon has not exists
206 */
207 public function init_default_attach_hooks() {
208 add_action( 'delete_attachment', 'wpforo_delete_attachment', 10 );
209 if( has_action( 'wpforo_topic_form_extra_fields_after', [ WPF()->tpl, 'add_default_attach_input' ] ) ) {
210 add_filter( 'wpforo_add_topic_data_filter', 'wpforo_add_default_attachment' );
211 add_filter( 'wpforo_edit_topic_data_filter', 'wpforo_add_default_attachment' );
212 add_filter( 'wpforo_add_post_data_filter', 'wpforo_add_default_attachment' );
213 add_filter( 'wpforo_edit_post_data_filter', 'wpforo_add_default_attachment' );
214 add_filter( 'wpforo_body_text_filter', 'wpforo_default_attachments_filter' );
215 }
216 }
217
218 /**
219 * init wp emojis when wpforo emoticons addon has not exists
220 */
221 public function init_wp_emoji_hooks() {
222 if( ! class_exists( 'wpForoSmiles' ) ) {
223 add_filter( 'wpforo_body_text_filter', 'wp_encode_emoji', 9 );
224 add_filter( 'wpforo_body_text_filter', 'convert_smilies' );
225 }
226 }
227
228 /**
229 * get request_uri redirect to url with concatenation of &can_do=do
230 * @return bool true if you can do action now | false if you can not do action now
231 */
232 private function can_do() {
233 if( wpfval( $_GET, 'can_do' ) === 'do' ) return true;
234
235 $refresh_url = preg_replace( '#&can_do=?[^=?&\r\n]*#isu', '', wpforo_get_request_uri() );
236 $refresh_url .= '&can_do=do';
237 header( "refresh:0.1;url=" . $refresh_url );
238
239 add_filter( 'wpforo_admin_loading', '__return_true' );
240
241 return false;
242 }
243
244 /**
245 * @return string $u_action return union bulk action
246 */
247 private function get_current_bulk_action() {
248 $u_action = '';
249 if( ! empty( $_GET['action'] ) && $_GET['action'] !== '-1' ) {
250 $u_action = sanitize_textarea_field( $_GET['action'] );
251 } elseif( ! empty( $_GET['action2'] ) && $_GET['action2'] !== '-1' ) {
252 $u_action = sanitize_textarea_field( $_GET['action2'] );
253 }
254
255 return $u_action;
256 }
257
258 /**
259 * catch if rss url show rss feed for given arguments
260 */
261 public function feed_rss2() {
262 if( wpfval( WPF()->GET, 'type' ) === 'rss2' ) {
263 $forum_rss_items = apply_filters( 'wpforo_forum_feed_limit', 10 );
264 $topic_rss_items = apply_filters( 'wpforo_topic_feed_limit', 10 );
265
266 $forumid = intval( wpfval( WPF()->GET, 'forum' ) );
267 if( ! $forumid ) {
268 $forum = [];
269 $forum['forumurl'] = wpforo_home_url();
270 $forum['title'] = '';
271 } elseif( $forum = wpforo_forum( $forumid ) ) {
272 $forum['forumurl'] = $forum['url'];
273 }
274
275 if( wpfval( WPF()->GET, 'topic' ) ) {
276 $topicid = intval( WPF()->GET['topic'] );
277 if( ! $topicid ) {
278 $posts = WPF()->post->get_posts( [
279 'row_count' => $topic_rss_items,
280 'orderby' => '`created` DESC, `postid` DESC',
281 'check_private' => true,
282 'status' => 0,
283 ] );
284 $topic['title'] = '';
285 $topic['topicurl'] = wpforo_home_url();
286 } else {
287 $topic = wpforo_topic( $topicid );
288 if( ! empty( $topic ) && ( intval( wpfval( $topic, 'private' ) ) || intval( wpfval( $topic, 'status' ) ) ) ) {
289 $topic = [];
290 }
291 if( empty( $topic ) ) {
292 WPF()->feed->rss2_topic( $forum, [], [] );
293 }
294 $topic['topicurl'] = ( wpfval( $topic, 'url' ) ) ? $topic['url'] : WPF()->topic->get_url( $topicid );
295 $posts = WPF()->post->get_posts( [
296 'topicid' => $topicid,
297 'row_count' => $topic_rss_items,
298 'orderby' => '`created` DESC, `postid` DESC',
299 'check_private' => true,
300 'status' => 0,
301 ] );
302 }
303 foreach( $posts as $key => $post ) {
304 $member = wpforo_member( $post );
305 $posts[ $key ]['description'] = wpforo_text( trim( strip_tags( (string) $post['body'] ) ), 190, false );
306 $posts[ $key ]['content'] = trim( (string) $post['body'] );
307 $posts[ $key ]['posturl'] = WPF()->post->get_url( $post['postid'] );
308 $posts[ $key ]['author'] = $member['display_name'];
309 }
310 WPF()->feed->rss2_topic( $forum, $topic, $posts );
311 } else {
312 if( ! $forumid ) {
313 $topics = WPF()->topic->get_topics( [
314 'row_count' => $forum_rss_items,
315 'orderby' => 'created',
316 'order' => 'DESC',
317 'private' => 0,
318 'status' => 0,
319 ] );
320 } else {
321 $topics = WPF()->topic->get_topics( [
322 'forumid' => $forumid,
323 'row_count' => $forum_rss_items,
324 'orderby' => 'created',
325 'order' => 'DESC',
326 'private' => 0,
327 'status' => 0,
328 ] );
329 }
330 foreach( $topics as $key => $topic ) {
331 $post = wpforo_post( $topic['first_postid'] );
332 $member = wpforo_member( $topic );
333 $topics[ $key ]['description'] = wpforo_text( trim( strip_tags( (string) $post['body'] ) ), 190, false );
334 $topics[ $key ]['content'] = trim( (string) $post['body'] );
335 $topics[ $key ]['topicurl'] = WPF()->topic->get_url( $topic['topicid'] );
336 $topics[ $key ]['author'] = $member['display_name'];
337 }
338 WPF()->feed->rss2_forum( $forum, $topics );
339 }
340 exit();
341 }
342 }
343
344 /**
345 * ucf_file_delete delete /wp-content/uploads/UCFFILENAME
346 */
347 public function ucf_file_delete() {
348 $userid = 0;
349 if( wpfval( WPF()->GET, 'foro_f' ) && wpfval( WPF()->GET, 'foro_u' ) && wpfval( WPF()->GET, 'foro_n' ) ) {
350 if( wp_verify_nonce( WPF()->GET['foro_n'], 'wpforo_delete_profile_field' ) ) {
351 $userid = intval( WPF()->GET['foro_u'] );
352 $field = sanitize_title( WPF()->GET['foro_f'] );
353
354 // Security: Check if current user can edit target user's account
355 if( ! WPF()->perm->user_can_edit_account( $userid ) ) {
356 WPF()->notice->add( 'You do not have permission to edit this profile', 'error' );
357 wp_safe_redirect( wpforo_home_url() );
358 exit();
359 }
360
361 if( $file = WPF()->member->get_custom_field( $userid, $field ) ) {
362 $file = wpforo_fix_upload_dir( $file );
363 $result = WPF()->member->update_custom_field( $userid, $field, '' );
364 if( $result ) {
365 // Security: Only delete files within wpforo upload directory (realpath validation)
366 if( $file ) {
367 $realpath = realpath( $file );
368 $upload_base = realpath( WPF()->folders['wp_upload']['dir'] );
369 if( $realpath && $upload_base && strpos( $realpath, $upload_base . DIRECTORY_SEPARATOR . 'wpforo' ) === 0 ) {
370 wp_delete_file( $file );
371 }
372 }
373 WPF()->phrase->clear_cache();
374 WPF()->notice->add( 'Deleted Successfully!', 'success' );
375 } else {
376 WPF()->notice->clear();
377 WPF()->notice->add( 'Sorry, this file cannot be deleted', 'error' );
378 }
379 }
380 }
381 }
382
383 wp_safe_redirect( $userid ? WPF()->member->get_profile_url( $userid, 'account' ) : wpforo_home_url() );
384 exit();
385 }
386
387 /**
388 * mark all bold forum topics as read
389 */
390 public function mark_all_read() {
391 if( wpfval( WPF()->GET, 'foro' ) === 'allread' ) {
392 if( wpfval( WPF()->GET, 'foro_n' ) && wp_verify_nonce( WPF()->GET['foro_n'], 'wpforo_mark_all_read' ) ) {
393 WPF()->log->mark_all_read();
394 $current_url = wpforo_get_request_uri();
395 $current_url = strtok( $current_url, '?' );
396 wp_safe_redirect( $current_url );
397 exit();
398 }
399 }
400 }
401
402 /**
403 * Open/Close Frontend Admin CPanel
404 */
405 public function acp_toggle() {
406 wpforo_verify_nonce( 'wpforo_acp_toggle' );
407 $toggle_status = wpfval( $_POST, 'toggle_status' );
408 if( in_array( $toggle_status, [ 'open', 'close' ] ) ) {
409 update_user_meta( WPF()->current_userid, 'wpf-acp-toggle', $toggle_status );
410 wp_send_json_success();
411 } else {
412 wp_send_json_error();
413 }
414 }
415
416 /**
417 * set a notification read
418 */
419 public function mark_notification_read() {
420 if( wpfval( WPF()->GET, '_nread' ) && is_user_logged_in() ) {
421 if( wpfval( WPF()->GET, 'foro_n' ) && wp_verify_nonce( WPF()->GET['foro_n'], 'wpforo_mark_notification_read' ) ) {
422 $id = intval( WPF()->GET['_nread'] );
423 WPF()->activity->read_notification( $id );
424 $current_url = wpforo_get_request_uri();
425 $current_url = strtok( $current_url, '?' );
426 wp_safe_redirect( $current_url );
427 exit();
428 }
429 }
430 }
431
432 /**
433 * clear all notifications
434 */
435 public function clear_all_notifications() {
436 if( wpfval( $_POST, 'foro_n' ) && wp_verify_nonce( $_POST['foro_n'], 'wpforo_clear_notifications' ) ) {
437 WPF()->activity->clear_notifications();
438 echo WPF()->activity->get_no_notifications_html();
439 }
440 exit();
441 }
442
443 public function profile_cover_upload() {
444 wpforo_verify_nonce( 'wpforo_profile_cover_upload' );
445 if( WPF()->current_object['user'] && WPF()->usergroup->can( 'upc' ) && WPF()->perm->user_can_edit_account(
446 WPF()->current_object['user']
447 ) && ( $image_blob = wpfval(
448 $_POST,
449 'image_blob'
450 ) ) ) {
451 $data = explode( ',', $image_blob );
452 if( preg_match(
453 '#^data:image/(?:png|jpe?g|gif);base64$#iu',
454 (string) $data[0]
455 ) && ( $file_content = isset( $data[1] ) ? base64_decode( $data[1] ) : '' ) ) {
456 $file_basename = uniqid() . '_' . WPF()->current_object['user']['userid'] . '.jpg';
457 $file_dir = WPF()->folders['covers']['dir'] . DIRECTORY_SEPARATOR . $file_basename;
458 $file_url = WPF()->folders['covers']['url//'] . '/' . $file_basename;
459 if( file_put_contents( $file_dir, $file_content ) ) {
460 WPF()->member->update_profile_field( WPF()->current_object['user']['userid'], 'cover', $file_url );
461 wp_send_json_success();
462 }
463 }
464 }
465 wp_send_json_error();
466 }
467
468 public function profile_cover_delete() {
469 wpforo_verify_nonce( 'wpforo_profile_cover_delete' );
470
471 if( WPF()->current_object['user'] && WPF()->usergroup->can( 'upc' ) && WPF()->perm->user_can_edit_account(
472 WPF()->current_object['user']
473 ) ) {
474 WPF()->member->update_profile_field( WPF()->current_object['user']['userid'], 'cover', '' );
475 wp_send_json_success( [ 'background_url' => wpforo_setting( 'profiles', 'default_cover' ) ] );
476 }
477 wp_send_json_error();
478 }
479
480 public function profiles_default_cover_upload() {
481 wpforo_verify_nonce( 'wpforo_profiles_default_cover_upload' );
482 if( ( wpforo_current_user_is( 'admin' ) || WPF()->usergroup->can( 'ms' ) ) && $image_blob = wpfval(
483 $_POST,
484 'image_blob'
485 ) ) {
486 $data = explode( ',', $image_blob );
487 if( preg_match(
488 '#^data:image/(?:png|jpe?g|gif);base64$#iu',
489 $data[0]
490 ) && ( $file_content = isset( $data[1] ) ? base64_decode( $data[1] ) : '' ) ) {
491 $file_basename = 'profiles_custom_default_cover.jpg';
492 $file_dir = WPF()->folders['covers']['dir'] . DIRECTORY_SEPARATOR . $file_basename;
493 $file_url = WPF()->folders['covers']['url//'] . '/' . $file_basename;
494 if( file_put_contents( $file_dir, $file_content ) ) {
495 WPF()->settings->profiles['default_cover'] = $file_url;
496 wpforo_update_option( 'wpforo_profiles', WPF()->settings->profiles );
497 wp_send_json_success();
498 }
499 }
500 }
501 wp_send_json_error();
502 }
503
504 public function get_topic_head_more_info() {
505 wpforo_verify_nonce( 'wpforo_get_topic_head_more_info' );
506 if( $topicid = wpforo_bigintval( wpfval( $_POST, 'topicid' ) ) ) {
507 if( ( $topic = WPF()->topic->get_topic( $topicid, false ) ) && WPF()->topic->view_access( $topic ) ) {
508 wp_send_json_success(
509 [ 'html' => wpforo_topic_active_participants( $topicid ) . wpforo_topic_overview( $topicid ) ]
510 );
511 }
512 }
513
514 wp_send_json_error();
515 }
516
517 public function get_topic_overview_chunk() {
518 wpforo_verify_nonce( 'wpforo_get_topic_overview_chunk' );
519 if( $topicid = wpforo_bigintval( wpfval( $_POST, 'topicid' ) ) ) {
520 if( ( $topic = WPF()->topic->get_topic( $topicid, false ) ) && WPF()->topic->view_access( $topic ) ) {
521 if( ! ( $chunksize = (int) wpfval( $_POST, 'chunksize' ) ) ) $chunksize = 5;
522 $offset = (int) wpfval( $_POST, 'offset' );
523
524 wp_send_json_success( wpforo_get_topic_overview_chunk( $topicid, $chunksize, $offset ) );
525 }
526 }
527
528 wp_send_json_error();
529 }
530
531 public function get_overview() {
532 wpforo_verify_nonce( 'wpforo_get_overview' );
533 if( $postid = wpforo_bigintval( wpfval( $_POST, 'postid' ) ) ) {
534 if( ( $post = wpforo_post( $postid ) ) && WPF()->post->view_access( $post ) ) {
535 wp_send_json_success(
536 [
537 'title' => '<i class="fas fa-user"></i> &nbsp;' . wpforo_phrase(
538 'Posted by ',
539 false
540 ) . ' ' . wpforo_member_link(
541 wpforo_member( $post ),
542 '',
543 20,
544 '',
545 false
546 ) . '&nbsp;&bullet;&nbsp;' . ' ' . wpforo_date( $post['created'], 'ago', false ),
547 'content' => trim( (string) wpforo_content( $post, false ) ),
548 ]
549 );
550 }
551 }
552
553 wp_send_json_error();
554 }
555
556 /**
557 * registration form submit action
558 */
559 public function registration() {
560 if( ! empty( $_POST['wpfreg'] ) ) {
561 wpforo_verify_form( 'wpforo_user_register' );
562 if( $userid = WPF()->member->create( $_POST ) ) {
563 if( wpforo_setting( 'authorization', 'redirect_url_after_register' ) ) {
564 $redirect_url = wpforo_setting( 'authorization', 'redirect_url_after_register' );
565 } elseif( ( $redirect_to = wpfval( $_GET, 'redirect_to' ) ) && wpforo_is_url_internal(
566 urldecode( (string) $redirect_to )
567 ) ) {
568 $redirect_url = urldecode( (string) $redirect_to );
569 } elseif( is_wpforo_url() ) {
570 $redirect_url = preg_replace( '#\?.*$#is', '', wpforo_get_request_uri() );
571 } else {
572 if( function_exists( 'pll_current_language' ) && $pll_lang = pll_current_language( 'locale' ) ) {
573 $redirect_url = wpforo_get_home_url_for_language( $pll_lang );
574 } else {
575 $redirect_url = ( wpforo_setting( 'authorization', 'user_register_email_confirm' ) ? wpforo_home_url() : WPF()->member->get_profile_url( $userid, 'account' ) );
576 }
577 }
578
579 wp_safe_redirect( $redirect_url );
580 exit();
581 }
582 }
583 }
584
585 /**
586 * login form submit action
587 */
588 public function login() {
589 wpforo_verify_form( 'login' );
590 if( isset( $_POST['wpforologin'] ) && isset( $_POST['log'] ) && isset( $_POST['pwd'] ) ) {
591 if( ! is_wp_error( $user = wp_signon() ) ) {
592 $wpf_login_times = intval( get_user_meta( $user->ID, '_wpf_login_times', true ) );
593 if( isset( $user->ID ) && $wpf_login_times >= 1 ) {
594 $name = ( isset( $user->data->display_name ) ) ? $user->data->display_name : '';
595 WPF()->notice->add( 'Welcome back %s!', 'success', $name );
596 } else {
597 WPF()->notice->add( 'Welcome to our Community!', 'success' );
598 }
599 $wpf_login_times ++;
600 update_user_meta( $user->ID, '_wpf_login_times', $wpf_login_times );
601 if( wpforo_setting( 'authorization', 'redirect_url_after_login' ) ) {
602 $redirect_url = wpforo_setting( 'authorization', 'redirect_url_after_login' );
603 } elseif( ( $redirect_to = wpfval( $_GET, 'redirect_to' ) ) && wpforo_is_url_internal(
604 urldecode( (string) $redirect_to )
605 ) ) {
606 $redirect_url = urldecode( (string) $redirect_to );
607 } elseif( is_wpforo_url() ) {
608 $redirect_url = preg_replace( '#\?.*$#is', '', wpforo_get_request_uri() );
609 } else {
610 if( function_exists( 'pll_current_language' ) && $pll_lang = pll_current_language( 'locale' ) ) {
611 $redirect_url = wpforo_get_home_url_for_language( $pll_lang );
612 } else {
613 $redirect_url = wpforo_home_url();
614 }
615 }
616 wp_safe_redirect( $redirect_url );
617 } else {
618 $args = [];
619 foreach( $user->errors as $u_err ) $args[] = $u_err[0];
620 WPF()->notice->add( $args, 'error' );
621 wp_safe_redirect( wpforo_get_request_uri() );
622 }
623 exit();
624 }
625 }
626
627 public function lostpassword() {
628 wpforo_verify_form( 'lostpassword' );
629 $redirect_url = wp_get_raw_referer();
630 if( wpfval( $_POST, 'user_login' ) ) {
631 $errors = retrieve_password();
632 if( is_wp_error( $errors ) ) {
633 $redirect_url = wpforo_lostpassword_url();
634 WPF()->notice->add( implode( ',', $errors->get_error_messages() ), 'error' );
635 } else {
636 $redirect_url = wpforo_login_url();
637 WPF()->notice->add( 'Email has been sent', 'success' );
638 }
639 }
640
641 wp_safe_redirect( $redirect_url );
642 exit();
643 }
644
645 public function resetpassword_form() {
646 $rp_key = sanitize_text_field( wp_unslash( $_REQUEST['rp_key'] ) );
647 $rp_login = sanitize_user( wp_unslash( $_REQUEST['rp_login'] ) );
648 $user = check_password_reset_key( $rp_key, $rp_login );
649 if( ! $user || is_wp_error( $user ) ) {
650 if( $user && $user->get_error_code() === 'expired_key' ) {
651 WPF()->notice->add( 'The key is expired', 'error' );
652 } else {
653 WPF()->notice->add( 'The key is invalid', 'error' );
654 }
655 wp_safe_redirect( wpforo_login_url() );
656 exit();
657 }
658 }
659
660 public function resetpassword() {
661 $this->resetpassword_form();
662
663 $pass1 = wpfval( $_POST, 'pass1' );
664 $pass2 = wpfval( $_POST, 'pass2' );
665
666 if( ! $pass1 ) {
667 WPF()->notice->add( 'The password reset empty', 'error' );
668 wp_safe_redirect( wp_get_raw_referer() );
669 exit();
670 }
671
672 if( strlen( (string) $pass1 ) < WPF()->member->pass_min_length || strlen( (string) $pass1 ) > WPF()->member->pass_max_length ) {
673 WPF()->notice->add( 'Password length must be between %d characters and %d characters.', 'error', [
674 WPF()->member->pass_min_length,
675 WPF()->member->pass_max_length,
676 ] );
677 wp_safe_redirect( wp_get_raw_referer() );
678 exit();
679 }
680
681 if( $pass1 !== $pass2 ) {
682 WPF()->notice->add( 'The password reset mismatch', 'error' );
683 wp_safe_redirect( wp_get_raw_referer() );
684 exit();
685 }
686
687 $rp_login = sanitize_user( wp_unslash( $_REQUEST['rp_login'] ) );
688 reset_password( get_user_by( 'login', $rp_login ), $pass1 );
689 wp_signon( [ 'user_login' => $rp_login, 'user_password' => $pass1 ] );
690
691 WPF()->notice->add( 'The password has been changed', 'success' );
692 wp_safe_redirect( wpforo_home_url() );
693 exit();
694 }
695
696 public function logout() {
697 wpforo_verify_nonce( 'wpforo_logout', 'full' );
698 wp_logout();
699 $redirect_url = wpforo_home_url();
700 if( ( $redirect_to = wpfval( $_GET, 'redirect_to' ) ) && wpforo_is_url_internal( urldecode( (string) $redirect_to ) ) ) {
701 $redirect_url = urldecode( (string) $redirect_to );
702 if( strpos( $redirect_url, 'lostpassword' ) !== false ) $redirect_url = wpforo_login_url();
703 }
704 wp_safe_redirect( $redirect_url );
705 exit();
706 }
707
708 /**
709 * profile_update form submit action
710 */
711 public function profile_update() {
712 if( wpfval( $_POST, 'member', 'userid' ) ) {
713 wpforo_verify_form();
714 $uid = intval( $_POST['member']['userid'] );
715 if( ! ( $uid === WPF()->current_userid || ( WPF()->usergroup->can( 'em' ) && WPF()->perm->user_can_manage_user(
716 WPF()->current_userid,
717 $uid
718 ) ) ) ) {
719 WPF()->notice->clear();
720 WPF()->notice->add( 'Permission denied', 'error' );
721 wp_safe_redirect( wpforo_get_request_uri() );
722 exit();
723 }
724 if( WPF()->member->update( $_POST ) ) {
725 if( $profile_url = WPF()->member->get_profile_url( $uid, 'account', false ) ) {
726 wp_safe_redirect( $profile_url );
727 exit();
728 }
729 }
730 }
731
732 wp_safe_redirect( wpforo_get_request_uri() );
733 exit();
734 }
735
736 public function cantlogin_contact() {
737 if( wpforo_setting( 'authorization', 'manually_approval_contact_form' ) && ( $msg = wpfval( $_POST, 'msg' ) ) ) {
738 $admin_emails = wpforo_setting( 'email', 'admin_emails' );
739 $admin_email = wpfval( $admin_emails, 0 );
740 $sbj = wpforo_phrase( 'Request for account approval', false ) . ' ( ' . wpfval(
741 $_POST,
742 'user_login'
743 ) . ' )';
744
745 add_filter( 'wp_mail_content_type', 'wpforo_set_html_content_type', 999 );
746 if( @wpforo_send_email( $admin_email, $sbj, $msg, wpforo_admin_mail_headers(), 'approval_request' ) ) {
747 WPF()->notice->add( 'Message has been sent', 'success' );
748 } else {
749 WPF()->notice->add( 'Can\'t send report email', 'error' );
750 }
751 remove_filter( 'wp_mail_content_type', 'wpforo_set_html_content_type' );
752 }
753
754 wp_safe_redirect( wpforo_home_url() );
755 exit();
756 }
757
758 /**
759 * topic_add form submit action
760 */
761 public function topic_add() {
762 wpforo_verify_form();
763 $args = $_REQUEST['thread'];
764 $args['postmetas'] = (array) wpfval( $_REQUEST, 'data' );
765 if( $topicid = WPF()->topic->add( $args ) ) {
766 wp_safe_redirect( WPF()->topic->get_url( $topicid ) );
767 exit();
768 }
769 wp_safe_redirect( wpforo_get_request_uri() );
770 exit();
771 }
772
773 /**
774 * topic_edit form submit action
775 */
776 public function topic_edit() {
777 wpforo_verify_form();
778 $args = $_REQUEST['thread'];
779 $args['postmetas'] = (array) wpfval( $_REQUEST, 'data' );
780 if( $topicid = WPF()->topic->edit( $args ) ) {
781 wp_safe_redirect( WPF()->topic->get_url( $topicid ) );
782 exit();
783 }
784 wp_safe_redirect( wpforo_get_request_uri() );
785 exit();
786 }
787
788 /**
789 * post_add form submit action
790 */
791 public function post_add() {
792 wpforo_verify_form();
793 $args = $_REQUEST['post'];
794 $args['postmetas'] = (array) wpfval( $_REQUEST, 'data' );
795 if( $postid = WPF()->post->add( $args ) ) {
796 wp_safe_redirect( WPF()->post->get_url( $postid ) );
797 exit();
798 }
799 wp_safe_redirect( wpforo_get_request_uri() );
800 exit();
801 }
802
803 /**
804 * post_edit form submit action
805 */
806 public function post_edit() {
807 wpforo_verify_form();
808 $args = $_REQUEST['post'];
809 $args['postmetas'] = (array) wpfval( $_REQUEST, 'data' );
810 if( $postid = WPF()->post->edit( $args ) ) {
811 wp_safe_redirect( WPF()->post->get_url( $postid ) );
812 exit();
813 }
814 wp_safe_redirect( wpforo_get_request_uri() );
815 exit();
816 }
817
818 /**
819 * topic_move form submit action
820 */
821 public function topic_move() {
822 if( ! empty( $_POST['topic_move'] ) ) {
823 wpforo_verify_form();
824 $topicid = intval( wpfval( $_POST['topic_move'], 'topicid' ) );
825 $forumid = intval( wpfval( $_POST['topic_move'], 'forumid' ) );
826 if( $topicid && $forumid ) {
827 $topic = WPF()->topic->get_topic( $topicid );
828 if( ! $topic || ! WPF()->perm->forum_can( 'mt', $topic['forumid'] ) ) {
829 wp_safe_redirect( wpforo_get_request_uri() );
830 exit();
831 }
832 WPF()->topic->move( $topicid, $forumid );
833 $url = WPF()->topic->get_url( $topicid, [], false );
834 wpforo_clean_cache();
835 wp_safe_redirect( $url );
836 exit();
837 }
838 }
839
840 wp_safe_redirect( wpforo_get_request_uri() );
841 exit();
842 }
843
844 /**
845 * topic_merge form submit action
846 */
847 public function topic_merge() {
848 wpforo_verify_form();
849 $redirect_to = wpforo_get_request_uri();
850 if( ! WPF()->current_object['topic'] || ! WPF()->perm->forum_can( 'mt', WPF()->current_object['topic']['forumid'] ) ) {
851 wp_safe_redirect( $redirect_to );
852 exit();
853 }
854 if( WPF()->current_object['topic'] && ! empty( $_POST['wpforo'] ) && ! empty( $_POST['wpforo']['target_topic_url'] ) ) {
855 $target_slug = wpforo_get_topic_slug_from_url( esc_url( (string) $_POST['wpforo']['target_topic_url'] ) );
856 if( ! is_null( $target_slug ) && $target = WPF()->topic->get_topic( $target_slug ) ) {
857 $append = ( empty( $_POST['wpforo']['update_date_and_append'] ) ? 0 : 1 );
858 $to_target_title = ( empty( $_POST['wpforo']['to_target_title'] ) ? 0 : 1 );
859
860 if( WPF()->topic->merge( $target, WPF()->current_object['topic'], [], $to_target_title, $append ) ) {
861 $redirect_to = WPF()->topic->get_url( $target, [], false );
862 wpforo_clean_cache();
863 }
864 } else {
865 WPF()->notice->add( 'Target Topic not found', 'error' );
866 }
867 }
868 wp_safe_redirect( $redirect_to );
869 exit();
870 }
871
872 /**
873 * topic_split form submit action
874 */
875 public function topic_split() {
876 wpforo_verify_form();
877 $redirect_to = wpforo_get_request_uri();
878 if( ! WPF()->current_object['topic'] || ! WPF()->perm->forum_can( 'mt', WPF()->current_object['topic']['forumid'] ) ) {
879 wp_safe_redirect( $redirect_to );
880 exit();
881 }
882 if( WPF()->current_object['topic'] && ! empty( $_POST['wpforo'] ) ) {
883 if( ! empty( $_POST['wpforo']['create_new'] ) ) {
884 $args = [
885 'title' => sanitize_text_field( $_POST['wpforo']['new_topic_title'] ),
886 'forumid' => intval( $_POST['wpforo']['new_topic_forumid'] ),
887 'postids' => array_map( 'intval', $_POST['wpforo']['posts'] ),
888 ];
889 $to_target_title = ( empty( $_POST['wpforo']['to_target_title'] ) ? 0 : 1 );
890 if( $topicid = WPF()->topic->split( $args, $to_target_title ) ) {
891 $redirect_to = WPF()->topic->get_url( $topicid );
892 }
893 } else {
894 if( ! empty( $_POST['wpforo']['target_topic_url'] ) && ! empty( $_POST['wpforo']['posts'] ) ) {
895 $target_slug = wpforo_get_topic_slug_from_url( esc_url( (string) $_POST['wpforo']['target_topic_url'] ) );
896 if( ! is_null( $target_slug ) && $target = WPF()->topic->get_topic( $target_slug ) ) {
897 $append = ( empty( $_POST['wpforo']['update_date_and_append'] ) ? 0 : 1 );
898 $to_target_title = ( empty( $_POST['wpforo']['to_target_title'] ) ? 0 : 1 );
899 $postids = array_map( 'intval', $_POST['wpforo']['posts'] );
900 if( WPF()->topic->merge(
901 $target,
902 WPF()->current_object['topic'],
903 $postids,
904 $to_target_title,
905 $append
906 ) ) {
907 $redirect_to = WPF()->topic->get_url( $target );
908 }
909 } else {
910 WPF()->notice->add( 'Target Topic not found', 'error' );
911 }
912 }
913 }
914 }
915 wp_safe_redirect( $redirect_to );
916 exit();
917 }
918
919 /**
920 * board add action
921 */
922 public function board_add() {
923 check_admin_referer( 'wpforo-board-add' );
924 if( $board = wp_unslash( (array) wpfval( $_POST, 'board' ) ) ) {
925 if( ! ( $board['locale'] = trim( (string) $board['locale'] ) ) ) $board['locale'] = 'en_US';
926 $status = wpfkey( $board, 'status' ) ? (int) wpfval( $board, 'status' ) : 1;
927 if( $boardid = WPF()->board->add( $board ) ) {
928 // Handle translation installation.
929 if( $status && $board['locale'] && current_user_can( 'install_languages' ) ) {
930 require_once ABSPATH . 'wp-admin/includes/file.php';
931 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
932 if( wp_can_install_language_pack() ) wp_download_language_pack( $board['locale'] );
933 }
934
935 if( ( $board = WPF()->board->_get_board( $boardid ) ) && $status ) {
936 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-' . $boardid . '-settings' ) );
937 exit();
938 }
939 }
940 }
941
942 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-boards' ) );
943 exit();
944 }
945
946 /**
947 * board edit action
948 */
949 public function board_edit() {
950 check_admin_referer( 'wpforo-board-edit' );
951 if( $board = wp_unslash( (array) wpfval( $_POST, 'board' ) ) ) {
952 $boardid = (int) wpfval( $board, 'boardid' );
953 $status = wpfkey( $board, 'status' ) ? (int) wpfval( $board, 'status' ) : 1;
954 if( ! ( $board['locale'] = trim( (string) $board['locale'] ) ) ) $board['locale'] = 'en_US';
955 if( WPF()->board->edit( $board, $boardid ) ) {
956 if( $status && ! is_wpforo_multiboard() ) {
957 wp_update_post(
958 [
959 'ID' => $board['pageid'],
960 'post_name' => $board['slug'],
961 ]
962 );
963 }
964 // Handle translation installation.
965 if( $status && $board['locale'] && current_user_can( 'install_languages' ) ) {
966 require_once ABSPATH . 'wp-admin/includes/file.php';
967 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
968 if( wp_can_install_language_pack() ) wp_download_language_pack( $board['locale'] );
969 }
970 }
971 }
972
973 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-boards' ) );
974 exit();
975 }
976
977 /**
978 * board delete action
979 */
980 public function board_repair() {
981 $boardid = (int) wpfval( $_GET, 'boardid' );
982 if( $boardid === WPF()->board->get_current( 'boardid' ) ) {
983 check_admin_referer( 'wpforo-board-repair-' . $boardid );
984 wpforo_board_repair( $boardid );
985 }
986
987 wp_safe_redirect( wp_get_raw_referer() );
988 exit();
989 }
990
991 /**
992 * board delete action
993 */
994 public function board_delete() {
995 if( ( $boardid = (int) wpfval( $_GET, 'boardid' ) ) && $boardid === WPF()->board->get_current( 'boardid' ) ) {
996 check_admin_referer( 'wpforo-board-delete-' . $boardid );
997 wpforo_board_uninstall( $boardid );
998 }
999
1000 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-boards' ) );
1001 exit();
1002 }
1003
1004 /**
1005 * action to synchronize wp_users to wp_wpforo_profiles
1006 */
1007 public function synch_user_profiles() {
1008 check_admin_referer( 'wpforo_synch_user_profiles' );
1009
1010 if( $this->can_do() ) {
1011 wpforo_set_max_execution_time();
1012 wp_raise_memory_limit();
1013
1014 if( WPF()->member->synchronize_users( apply_filters( 'wpforo_rebuild_per_request', 200 ) ) ) {
1015 WPF()->member->clear_db_cache();
1016 wpforo_clean_cache();
1017 WPF()->notice->add( 'Synched Successfully!', 'success' );
1018 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-overview' ) );
1019 } else {
1020 wp_safe_redirect(
1021 htmlspecialchars_decode(
1022 wp_nonce_url(
1023 admin_url( 'admin.php?page=wpforo-overview&wpfaction=synch_user_profiles' ),
1024 'wpforo_synch_user_profiles'
1025 )
1026 )
1027 );
1028 }
1029 exit();
1030 }
1031 }
1032
1033 /**
1034 * reset user caches
1035 */
1036 public function reset_user_cache() {
1037 check_admin_referer( 'wpforo_reset_user_cache' );
1038
1039 if( ! current_user_can( 'administrator' ) ) {
1040 WPF()->notice->add( 'Permission denied', 'error' );
1041 wp_safe_redirect( admin_url() );
1042 exit();
1043 }
1044
1045 wpforo_set_max_execution_time();
1046 wp_raise_memory_limit();
1047
1048 WPF()->member->clear_db_cache();
1049 WPF()->notice->add( 'Deleted Successfully!', 'success' );
1050
1051 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-overview' ) );
1052 exit();
1053 }
1054
1055 /**
1056 * rebuild forums statistics first|last posts etc.
1057 */
1058 public function reset_forums_stats() {
1059 check_admin_referer( 'wpforo_reset_forums_stat' );
1060
1061 if( ! current_user_can( 'administrator' ) ) {
1062 WPF()->notice->add( 'Permission denied', 'error' );
1063 wp_safe_redirect( admin_url() );
1064 exit();
1065 }
1066
1067 wpforo_set_max_execution_time();
1068 wp_raise_memory_limit();
1069
1070 $forumids = WPF()->db->get_col(
1071 "SELECT `forumid` FROM " . WPF()->tables->forums . " WHERE `is_cat` = 0 ORDER BY `forumid` ASC"
1072 );
1073 if( ! empty( $forumids ) ) {
1074 foreach( $forumids as $forumid ) {
1075 WPF()->forum->rebuild_stats( $forumid );
1076 WPF()->forum->rebuild_last_infos( $forumid, false );
1077 }
1078 WPF()->statistic_cache_clean();
1079 WPF()->forum->delete_tree_cache();
1080 wpforo_clean_cache();
1081 WPF()->notice->add( 'Updated Successfully!', 'success' );
1082 }
1083
1084 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
1085 exit();
1086 }
1087
1088 /**
1089 * rebuild topics statistics first|last posts etc.
1090 */
1091 public function reset_topics_stats() {
1092 check_admin_referer( 'wpforo_reset_topics_stat' );
1093
1094 if( ! current_user_can( 'administrator' ) ) {
1095 WPF()->notice->add( 'Permission denied', 'error' );
1096 wp_safe_redirect( admin_url() );
1097 exit();
1098 }
1099
1100 if( $this->can_do() ) {
1101 wpforo_set_max_execution_time();
1102 wp_raise_memory_limit();
1103
1104 $lastid = (int) wpfval( $_GET, 'topic_lastid' );
1105 $sql = "SELECT `topicid` FROM " . WPF()->tables->topics . " WHERE `topicid` > %d ORDER BY `topicid` ASC LIMIT %d";
1106 $topicids = WPF()->db->get_col(
1107 WPF()->db->prepare( $sql, $lastid, apply_filters( 'wpforo_rebuild_per_request', 200 ) )
1108 );
1109 if( $topicids ) {
1110 foreach( $topicids as $topicid ) {
1111 $topic = WPF()->topic->get_topic( $topicid );
1112 WPF()->topic->rebuild_first_last( $topic );
1113 WPF()->topic->rebuild_stats( $topic );
1114 }
1115 wp_safe_redirect(
1116 htmlspecialchars_decode(
1117 wp_nonce_url(
1118 admin_url(
1119 'admin.php?page=' . wpforo_prefix_slug(
1120 'dashboard'
1121 ) . '&wpfaction=reset_topics_stats&topic_lastid=' . end( $topicids )
1122 ),
1123 'wpforo_reset_topics_stat'
1124 )
1125 )
1126 );
1127 } else {
1128 @WPF()->db->query(
1129 "UPDATE `" . WPF()->tables->topics . "` t
1130 INNER JOIN `" . WPF()->tables->posts . "` p ON p.`topicid` = t.`topicid` AND p.`is_answer` = 1
1131 SET t.`solved` = 1
1132 WHERE t.`solved` = 0"
1133 );
1134 WPF()->statistic_cache_clean();
1135 WPF()->notice->add( 'Updated Successfully!', 'success' );
1136 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
1137 }
1138 exit();
1139 }
1140 }
1141
1142 /**
1143 * rebuild users statistics etc.
1144 */
1145 public function reset_users_stats() {
1146 check_admin_referer( 'wpforo_reset_users_stat' );
1147
1148 if( ! current_user_can( 'administrator' ) ) {
1149 WPF()->notice->add( 'Permission denied', 'error' );
1150 wp_safe_redirect( admin_url() );
1151 exit();
1152 }
1153
1154 if( $this->can_do() ) {
1155 wpforo_set_max_execution_time();
1156 wp_raise_memory_limit();
1157
1158 $lastid = (int) wpfval( $_GET, 'user_lastid' );
1159 $sql = "SELECT `userid` FROM " . WPF()->tables->profiles . " WHERE `userid` > %d ORDER BY `userid` ASC LIMIT %d";
1160 $userids = WPF()->db->get_col(
1161 WPF()->db->prepare( $sql, $lastid, apply_filters( 'wpforo_rebuild_per_request', 200 ) )
1162 );
1163 if( $userids ) {
1164 foreach( $userids as $userid ) {
1165 WPF()->member->rebuild_stats( $userid );
1166 }
1167
1168 wp_safe_redirect(
1169 htmlspecialchars_decode(
1170 wp_nonce_url(
1171 admin_url(
1172 'admin.php?page=wpforo-overview&wpfaction=reset_users_stats&user_lastid=' . end( $userids )
1173 ),
1174 'wpforo_reset_users_stat'
1175 )
1176 )
1177 );
1178 } else {
1179 WPF()->notice->add( 'Updated Successfully!', 'success' );
1180 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-overview' ) );
1181 }
1182 exit();
1183 }
1184 }
1185
1186 /**
1187 * rebuild 4 layout forum topics threads root
1188 */
1189 public function rebuild_threads() {
1190 check_admin_referer( 'wpforo_rebuild_threads' );
1191
1192 if( ! current_user_can( 'administrator' ) ) {
1193 WPF()->notice->add( 'Permission denied', 'error' );
1194 wp_safe_redirect( admin_url() );
1195 exit();
1196 }
1197
1198 wpforo_set_max_execution_time( 3600 );
1199 wp_raise_memory_limit();
1200
1201 WPF()->topic->rebuild_forum_threads();
1202 wpforo_clean_cache();
1203 WPF()->notice->add( 'Threads rebuilt successfully', 'success' );
1204
1205 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
1206 exit();
1207 }
1208
1209 /**
1210 * reset phrases cache from db
1211 */
1212 public function reset_phrase_cache() {
1213 check_admin_referer( 'wpforo_reset_phrase_cache' );
1214
1215 if( ! current_user_can( 'administrator' ) ) {
1216 WPF()->notice->add( 'Permission denied', 'error' );
1217 wp_safe_redirect( admin_url() );
1218 exit();
1219 }
1220
1221 wpforo_set_max_execution_time();
1222 wp_raise_memory_limit();
1223
1224 WPF()->phrase->clear_cache();
1225 WPF()->notice->add( 'Deleted Successfully!', 'success' );
1226
1227 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
1228 exit();
1229 }
1230
1231 /**
1232 * recrawling phrases from all wpforo, wpforo-addons code files
1233 */
1234 public function recrawl_phrases() {
1235 check_admin_referer( 'wpforo_recrawl_phrases' );
1236
1237 if( ! current_user_can( 'administrator' ) ) {
1238 WPF()->notice->add( 'Permission denied', 'error' );
1239 wp_safe_redirect( admin_url() );
1240 exit();
1241 }
1242
1243 wpforo_set_max_execution_time();
1244 wp_raise_memory_limit();
1245
1246 WPF()->phrase->crawl_phrases();
1247 WPF()->phrase->clear_cache();
1248 WPF()->notice->clear();
1249 WPF()->notice->add( 'Rebuilt Successfully!', 'success' );
1250
1251 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
1252 exit();
1253 }
1254
1255 /**
1256 * reset wpforo all caches (phrase, user, forum, post, stats, AI) etc.
1257 */
1258 public function reset_all_caches() {
1259 check_admin_referer( 'wpforo_reset_cache' );
1260
1261 if( ! current_user_can( 'administrator' ) ) {
1262 WPF()->notice->add( 'Permission denied', 'error' );
1263 wp_safe_redirect( admin_url() );
1264 exit();
1265 }
1266
1267 wpforo_set_max_execution_time();
1268 wp_raise_memory_limit();
1269
1270 WPF()->member->clear_db_cache();
1271 wpforo_clean_cache();
1272
1273 // Clear AI Cache (translations, summaries, embeddings cache)
1274 $this->clear_ai_cache();
1275
1276 // Flush WordPress Cache
1277 wp_cache_flush();
1278
1279 WPF()->notice->add( 'Deleted Successfully!', 'success' );
1280
1281 $redirect = ( is_admin() ) ? admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) : wpforo_home_url();
1282 wp_safe_redirect( $redirect );
1283 exit();
1284 }
1285
1286 /**
1287 * Clear AI-related caches (translations, summaries, embeddings cache)
1288 *
1289 * Clears:
1290 * - ai_cache table (translations, topic summaries)
1291 * - ai_embeddings_cache table (similarity search cache)
1292 *
1293 * Does NOT clear:
1294 * - ai_embeddings (indexed content - expensive to regenerate)
1295 * - ai_chat_* tables (user conversation history)
1296 * - ai_logs (audit logs)
1297 * - ai_moderation (moderation history)
1298 */
1299 private function clear_ai_cache() {
1300 global $wpdb;
1301
1302 // Clear AI cache table (translations, summaries)
1303 if ( ! empty( WPF()->tables->ai_cache ) ) {
1304 $wpdb->query( "TRUNCATE TABLE `" . WPF()->tables->ai_cache . "`" );
1305 }
1306
1307 // Clear AI embeddings cache table (similarity search results cache)
1308 if ( ! empty( WPF()->tables->ai_embeddings_cache ) ) {
1309 $wpdb->query( "TRUNCATE TABLE `" . WPF()->tables->ai_embeddings_cache . "`" );
1310 }
1311 }
1312
1313 /**
1314 * Clean Up damaged content in database
1315 */
1316 public function clean_up() {
1317 check_admin_referer( 'wpforo_clean_up' );
1318
1319 if( ! current_user_can( 'administrator' ) ) {
1320 WPF()->notice->add( 'Permission denied', 'error' );
1321 wp_safe_redirect( admin_url() );
1322 exit();
1323 }
1324
1325 wpforo_set_max_execution_time();
1326 wp_raise_memory_limit();
1327
1328 wpforo_clean_up();
1329 WPF()->notice->add( 'Cleaned Up!', 'success' );
1330
1331 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
1332 exit();
1333 }
1334
1335 /**
1336 * Flush Permalinks
1337 */
1338 public function flush_permalinks() {
1339 check_admin_referer( 'wpforo_flush_permalinks' );
1340
1341 if( ! current_user_can( 'administrator' ) ) {
1342 WPF()->notice->add( 'Permission denied', 'error' );
1343 wp_safe_redirect( admin_url() );
1344 exit();
1345 }
1346
1347 wpforo_set_max_execution_time();
1348 wp_raise_memory_limit();
1349
1350 if( 'hard' === wpfval( WPF()->GET, 'flush_type' ) ) {
1351 $bk_time = time();
1352 $current = get_option( 'rewrite_rules' );
1353 update_option( 'rewrite_rules_bk_' . $bk_time, $current );
1354 copy( ABSPATH . '/.htaccess', ABSPATH . '/.htaccess-bk-' . $bk_time );
1355 flush_rewrite_rules( true );
1356 delete_option( 'rewrite_rules' );
1357 } else {
1358 flush_rewrite_rules( false );
1359 }
1360
1361 WPF()->phrase->clear_cache();
1362 WPF()->notice->clear();
1363 WPF()->notice->add( 'Flushed Successfully!', 'success' );
1364
1365 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
1366 exit();
1367 }
1368
1369 /**
1370 * dashboard_options_save form submit action
1371 */
1372 public function dashboard_options_save() {
1373 if( ! current_user_can( 'administrator' ) ) {
1374 WPF()->notice->add( 'Permission denied', 'error' );
1375 wp_safe_redirect( admin_url() );
1376 exit();
1377 }
1378 if( $dashboard_count_per_page = (int) wpfval( $_POST, 'wpforo_dashboard_count_per_page' ) ) {
1379 wpforo_update_option( 'count_per_page', $dashboard_count_per_page );
1380 }
1381 wp_safe_redirect( wpforo_get_request_uri() );
1382 exit();
1383 }
1384
1385 /**
1386 * checking accesses to forum admin menu pages settings etc...
1387 */
1388 public function check_dashboard_permissions() {
1389 $page = wpfval( WPF()->GET, 'page' );
1390 if( $page === wpforo_prefix_slug( 'settings' ) ) {
1391 if( ! WPF()->usergroup->can( 'ms' ) ) {
1392 WPF()->notice->add( 'Permission denied', 'error' );
1393 wp_safe_redirect( admin_url() );
1394 exit();
1395 }
1396 }
1397 }
1398
1399 /**
1400 * check if [wpforo] page has been deleted, restore or create new [wpforo] page
1401 */
1402 public function repair_lost_main_shortcode_page() {
1403 if( wpfval( WPF()->GET, 'page' ) === wpforo_prefix_slug( 'settings' ) ) wpforo_repair_main_shortcode_page();
1404 }
1405
1406 /**
1407 * add_new_xml_translation form submit action
1408 */
1409 public function add_new_xml_translation() {
1410 check_admin_referer( 'wpforo-settings-language' );
1411
1412 if( ! WPF()->usergroup->can( 'ms' ) ) {
1413 WPF()->notice->add( 'Permission denied', 'error' );
1414 wp_safe_redirect( admin_url() );
1415 exit();
1416 }
1417
1418 if( ! empty( $_FILES['add_lang'] ) ) {
1419 WPF()->phrase->add_lang();
1420 wpforo_clean_cache();
1421 }
1422 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'settings' ) . '&tab=general' ) );
1423 exit();
1424 }
1425
1426 /**
1427 * add_new_xml_translation form submit action
1428 */
1429 public function phrases_change_lang() {
1430 check_admin_referer( 'wpforo-phrases-change-language' );
1431
1432 if( $langid = (int) wpfval( $_POST, 'langid' ) ) {
1433 if( WPF()->phrase->set_language_status( $langid ) ) {
1434 WPF()->notice->add( 'Successfully updated', 'success' );
1435 } else {
1436 WPF()->notice->add( 'Invalid request!', 'error' );
1437 }
1438 }
1439
1440 wp_safe_redirect( wp_get_raw_referer() );
1441 exit();
1442 }
1443
1444 /**
1445 * colors.css download action
1446 */
1447 public function colors_css_download() {
1448 check_admin_referer( 'dynamic_css_download' );
1449
1450 if( ! WPF()->usergroup->can( 'ms' ) ) {
1451 WPF()->notice->add( 'Permission denied', 'error' );
1452 wp_safe_redirect( admin_url() );
1453 exit();
1454 }
1455
1456 $dynamic_css = WPF()->tpl->generate_dynamic_css();
1457 header( 'Content-Type: application/download' );
1458 header( 'Content-Disposition: attachment; filename="colors.css"' );
1459 header( 'Content-Transfer-Encoding: binary' );
1460 header( "Content-Length: " . strlen( $dynamic_css ) );
1461 echo $dynamic_css;
1462 exit();
1463 }
1464
1465
1466 /**
1467 * cleanup_options_save form submit action
1468 */
1469 public function cleanup_options_save() {
1470 check_admin_referer( 'wpforo-tools-cleanup' );
1471
1472 if( ! WPF()->usergroup->can( 'mt' ) ) {
1473 WPF()->notice->add( 'Permission denied', 'error' );
1474 wp_safe_redirect( admin_url() );
1475 exit();
1476 }
1477
1478 if( ! wpfkey( $_POST, 'reset' ) ) {
1479 if( $options = wpfval( $_POST, 'wpforo_tools_cleanup' ) ) {
1480 if( wpforo_update_option( 'tools_cleanup', $options ) ) {
1481 WPF()->notice->add( 'Settings successfully updated', 'success' );
1482 }
1483 }
1484 } else {
1485 wpforo_delete_option( 'tools_cleanup' );
1486 WPF()->notice->add( 'Cleanup options reset successfully', 'success' );
1487 }
1488
1489 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) . '&tab=cleanup' ) );
1490 exit();
1491 }
1492
1493 /**
1494 * misc_options_save form submit action
1495 */
1496 public function misc_options_save() {
1497 check_admin_referer( 'wpforo-tools-misc' );
1498
1499 if( ! WPF()->usergroup->can( 'mt' ) ) {
1500 WPF()->notice->add( 'Permission denied', 'error' );
1501 wp_safe_redirect( admin_url() );
1502 exit();
1503 }
1504
1505 if( ! wpfkey( $_POST, 'reset' ) ) {
1506 if( $options = wpfval( $_POST, 'wpforo_tools_misc' ) ) {
1507 $options['admin_note'] = wpforo_kses( $options['admin_note'] );
1508 $options['admin_note_groups'] = ( wpfval( $_POST, 'wpforo_tools_misc', 'admin_note_groups' ) ) ? array_map(
1509 'intval',
1510 $options['admin_note_groups']
1511 ) : [];
1512 $options['admin_note_pages'] = ( wpfval( $_POST, 'wpforo_tools_misc', 'admin_note_pages' ) ) ? array_map(
1513 'sanitize_textarea_field',
1514 $options['admin_note_pages']
1515 ) : [];
1516 if( wpforo_update_option( 'tools_misc', $options ) ) {
1517 wpforo_clean_cache( 'forum-soft' );
1518 WPF()->notice->add( 'Settings successfully updated', 'success' );
1519 }
1520 }
1521 } else {
1522 wpforo_delete_option( 'tools_misc' );
1523 WPF()->notice->add( 'Misc options reset successfully', 'success' );
1524 }
1525
1526 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) . '&tab=misc' ) );
1527 exit();
1528 }
1529
1530 /**
1531 * legal_options_save form submit action
1532 */
1533 public function legal_options_save() {
1534 check_admin_referer( 'wpforo-tools-legal' );
1535
1536 if( ! WPF()->usergroup->can( 'mt' ) ) {
1537 WPF()->notice->add( 'Permission denied', 'error' );
1538 wp_safe_redirect( admin_url() );
1539 exit();
1540 }
1541
1542 if( ! wpfkey( $_POST, 'reset' ) ) {
1543 if( $options = wpfval( $_POST, 'wpforo_tools_legal' ) ) {
1544 $options['contact_page_url'] = esc_url( (string) $options['contact_page_url'] );
1545 $options['checkbox_terms_privacy'] = intval( $options['checkbox_terms_privacy'] );
1546 $options['checkbox_email_password'] = intval( $options['checkbox_email_password'] );
1547 $options['page_terms'] = esc_url( (string) $options['page_terms'] );
1548 $options['page_privacy'] = esc_url( (string) $options['page_privacy'] );
1549 $options['checkbox_forum_privacy'] = intval( $options['checkbox_forum_privacy'] );
1550 $options['forum_privacy_text'] = wpforo_kses( $options['forum_privacy_text'], 'post' );
1551 $options['cookies'] = intval( $options['cookies'] );
1552 $options['rules_checkbox'] = intval( $options['rules_checkbox'] );
1553 $options['rules_text'] = wpforo_kses( $options['rules_text'], 'post' );
1554 if( wpforo_update_option( 'tools_legal', $options ) ) {
1555 WPF()->notice->add( 'Settings successfully updated', 'success' );
1556 }
1557 }
1558 } else {
1559 wpforo_delete_option( 'tools_legal' );
1560 WPF()->notice->add( 'Settings reset successfully', 'success' );
1561 }
1562
1563 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) . '&tab=legal' ) );
1564 exit();
1565 }
1566
1567 /**
1568 * delete detected spam file
1569 */
1570 public function delete_spam_file() {
1571 check_admin_referer( 'wpforo_tools_antispam_files' );
1572
1573 if( ! WPF()->usergroup->can( 'mt' ) ) {
1574 WPF()->notice->add( 'Permission denied', 'error' );
1575 wp_safe_redirect( admin_url() );
1576 exit();
1577 }
1578
1579 if( $filename = trim( (string) wpfval( $_GET, 'sfname' ) ) ) {
1580 $filename = str_replace( [ '../', './', '/' ], '', sanitize_file_name( $filename ) );
1581 $filename = urldecode( (string) $filename );
1582 if( $filename ) {
1583 $attachmentid = WPF()->post->get_attachment_id( '/' . $filename );
1584 if( ! wp_delete_attachment( $attachmentid ) ) {
1585 @unlink( WPF()->folders['default_attachments']['dir'] . DIRECTORY_SEPARATOR . $filename );
1586 }
1587 WPF()->notice->add( 'Deleted', 'success' );
1588 }
1589 }
1590
1591 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) . '&tab=antispam' ) );
1592 exit();
1593 }
1594
1595 /**
1596 * delete_all_spam_files all detected spam file using level attribute
1597 */
1598 public function delete_all_spam_files() {
1599 check_admin_referer( 'wpforo_tools_antispam_files' );
1600
1601 if( ! WPF()->usergroup->can( 'mt' ) ) {
1602 WPF()->notice->add( 'Permission denied', 'error' );
1603 wp_safe_redirect( admin_url() );
1604 exit();
1605 }
1606
1607 if( $delete_level = (int) wpfval( $_GET, 'level' ) ) {
1608 $default_attachments_dir = WPF()->folders['default_attachments']['dir'];
1609 if( is_dir( $default_attachments_dir ) ) {
1610 if( $handle = opendir( $default_attachments_dir ) ) {
1611 while( false !== ( $filename = readdir( $handle ) ) ) {
1612 if( $filename === '.' || $filename === '..' ) continue;
1613 if( ! $level = WPF()->moderation->spam_file( $filename ) ) continue;
1614 if( $delete_level === $level ) {
1615 $attachmentid = WPF()->post->get_attachment_id( '/' . $filename );
1616 if( ! wp_delete_attachment( $attachmentid ) ) {
1617 @unlink( $default_attachments_dir . DIRECTORY_SEPARATOR . $filename );
1618 }
1619 }
1620 }
1621 closedir( $handle );
1622 WPF()->notice->add( 'Deleted', 'success' );
1623 }
1624 }
1625 }
1626
1627 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) . '&tab=antispam' ) );
1628 exit();
1629 }
1630
1631 /**
1632 * do database alter fixing using install.sql db-strukture
1633 */
1634 public function database_update() {
1635 check_admin_referer( 'wpforo_update_database' );
1636
1637 if( ! WPF()->usergroup->can( 'mt' ) ) {
1638 WPF()->notice->add( 'Permission denied', 'error' );
1639 wp_safe_redirect( admin_url() );
1640 exit();
1641 }
1642
1643 wpforo_set_max_execution_time( 3600 );
1644
1645 wpforo_update_db();
1646
1647 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) . '&tab=debug&view=tables' ) );
1648 exit();
1649 }
1650
1651 public function forum_copy() {
1652 wpforo_verify_nonce( 'forum_copy', 'full' );
1653
1654 if( ! WPF()->usergroup->can_manage_forum() ) {
1655 WPF()->notice->add( 'Permission denied', 'error' );
1656 wp_safe_redirect( admin_url() );
1657 exit();
1658 }
1659
1660 $forumid = (int) wpfval( $_GET, 'forumid' );
1661
1662 if( $forumid ) {
1663 WPF()->forum->copy( $forumid );
1664 }
1665
1666 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) ) );
1667 exit();
1668 }
1669
1670 /**
1671 * forum_add form submit action
1672 */
1673 public function forum_add() {
1674 check_admin_referer( 'wpforo-forum-add' );
1675
1676 if( ! WPF()->usergroup->can_manage_forum() ) {
1677 WPF()->notice->add( 'Permission denied', 'error' );
1678 wp_safe_redirect( admin_url() );
1679 exit();
1680 }
1681
1682 if( ! empty( $_REQUEST['forum'] ) ) {
1683 WPF()->forum->add();
1684 }
1685
1686 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) ) );
1687 exit();
1688 }
1689
1690 /**
1691 * forum_edit form submit action
1692 */
1693 public function forum_edit() {
1694 check_admin_referer( 'wpforo-forum-edit' );
1695
1696 if( ! WPF()->usergroup->can_manage_forum() ) {
1697 WPF()->notice->add( 'Permission denied', 'error' );
1698 wp_safe_redirect( admin_url() );
1699 exit();
1700 }
1701
1702 if( ! empty( $_REQUEST['forum'] ) ) {
1703 WPF()->forum->edit();
1704 }
1705
1706 wp_safe_redirect( wpforo_get_request_uri() );
1707 exit();
1708 }
1709
1710 /**
1711 * forum_delete form submit action
1712 */
1713 public function forum_delete() {
1714 check_admin_referer( 'wpforo-forum-delete' );
1715
1716 if( ! WPF()->usergroup->can_manage_forum() ) {
1717 WPF()->notice->add( 'Permission denied', 'error' );
1718 wp_safe_redirect( admin_url() );
1719 exit();
1720 }
1721
1722 $delete = (int) wpfval( $_REQUEST, 'forum', 'delete' );
1723 if( $delete === 1 ) {
1724 WPF()->forum->delete( 0, false );
1725 } elseif( $delete === 0 ) {
1726 WPF()->forum->merge();
1727 }
1728
1729 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) ) );
1730 exit();
1731 }
1732
1733 /**
1734 * forum_hierarchy_save form submit action
1735 */
1736 public function forum_hierarchy_save() {
1737 check_admin_referer( 'wpforo-forums-hierarchy' );
1738
1739 if( ! WPF()->usergroup->can_manage_forum() ) {
1740 WPF()->notice->add( 'Permission denied', 'error' );
1741 wp_safe_redirect( admin_url() );
1742 exit();
1743 }
1744
1745 if( ! empty( $_REQUEST['forum'] ) ) {
1746 WPF()->forum->update_hierarchy();
1747 wpforo_clean_cache( 'forum' );
1748 }
1749
1750 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) ) );
1751 exit();
1752 }
1753
1754 /**
1755 * dashboard_post_unapprove action
1756 */
1757 public function dashboard_post_unapprove() {
1758 $postid = wpfval( $_GET, 'postid' );
1759 check_admin_referer( "wpforo-unapprove-post-{$postid}" );
1760
1761 if( ! WPF()->usergroup->can( 'aum' ) ) {
1762 WPF()->notice->add( 'Permission denied', 'error' );
1763 wp_safe_redirect( admin_url() );
1764 exit();
1765 }
1766
1767 WPF()->moderation->post_unapprove( $postid );
1768 wpforo_clean_cache( 'post', $postid );
1769
1770 wp_safe_redirect( wp_get_referer() );
1771 exit();
1772 }
1773
1774 /**
1775 * dashboard_post_approve action
1776 */
1777 public function dashboard_post_approve() {
1778 $postid = wpfval( $_GET, 'postid' );
1779 check_admin_referer( "wpforo-approve-post-{$postid}" );
1780
1781 if( ! WPF()->usergroup->can( 'aum' ) ) {
1782 WPF()->notice->add( 'Permission denied', 'error' );
1783 wp_safe_redirect( admin_url() );
1784 exit();
1785 }
1786
1787 WPF()->moderation->post_approve( $postid );
1788 wpforo_clean_cache( 'post', $postid );
1789
1790 wp_safe_redirect( wp_get_referer() );
1791 exit();
1792 }
1793
1794 /**
1795 * dashboard_post_delete action
1796 */
1797 public function dashboard_post_delete() {
1798 $postid = wpfval( $_GET, 'postid' );
1799 check_admin_referer( "wpforo-delete-post-{$postid}" );
1800
1801 if( ! WPF()->usergroup->can( 'aum' ) ) {
1802 WPF()->notice->add( 'Permission denied', 'error' );
1803 wp_safe_redirect( admin_url() );
1804 exit();
1805 }
1806
1807 WPF()->post->delete( $postid );
1808
1809 wp_safe_redirect( wp_get_referer() );
1810 exit();
1811 }
1812
1813 /**
1814 * doing bulk moderation actions ( approve, unapprove, delete )
1815 */
1816 public function bulk_moderation() {
1817 check_admin_referer( 'bulk-moderations' );
1818
1819 if( ! WPF()->usergroup->can( 'aum' ) ) {
1820 WPF()->notice->add( 'Permission denied', 'error' );
1821 wp_safe_redirect( admin_url() );
1822 exit();
1823 }
1824
1825 $u_action = $this->get_current_bulk_action();
1826 $postids = (array) wpfval( $_GET, 'postids' );
1827 if( $u_action && ! empty( $postids ) ) {
1828 if( $u_action === 'delete' ) {
1829 foreach( $postids as $postid ) WPF()->post->delete( $postid );
1830 } elseif( $u_action === 'approve' ) {
1831 foreach( $postids as $postid ) WPF()->moderation->post_approve( $postid );
1832 } elseif( $u_action === 'unapprove' ) {
1833 foreach( $postids as $postid ) WPF()->moderation->post_unapprove( $postid );
1834 }
1835 }
1836
1837 wp_safe_redirect( wp_get_referer() );
1838 exit();
1839 }
1840
1841 /**
1842 * phrase_add form submit action
1843 */
1844 public function phrase_add() {
1845 check_admin_referer( 'wpforo-phrase-add' );
1846
1847 if( ! WPF()->usergroup->can( 'mp' ) ) {
1848 WPF()->notice->add( 'Permission denied', 'error' );
1849 wp_safe_redirect( admin_url() );
1850 exit();
1851 }
1852
1853 if( ! empty( $_POST['phrase'] ) ) {
1854 WPF()->phrase->add();
1855 }
1856
1857 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) ) );
1858 exit();
1859 }
1860
1861 /**
1862 * phrase_edit_form action redirect to phrase list page when phraseid(s) not chosen
1863 */
1864 public function phrase_edit_form() {
1865 $phraseids = array_filter(
1866 array_map( 'intval', array_merge( (array) wpfval( $_GET, 'phraseid' ), (array) wpfval( $_GET, 'phraseids' ) ) )
1867 );
1868 if( ! $phraseids ) {
1869 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) ) );
1870 exit();
1871 }
1872 }
1873
1874 /**
1875 * phrase_edit form submit action
1876 */
1877 public function phrase_edit() {
1878 check_admin_referer( 'wpforo-phrases-edit' );
1879
1880 if( ! WPF()->usergroup->can( 'mp' ) ) {
1881 WPF()->notice->add( 'Permission denied', 'error' );
1882 wp_safe_redirect( admin_url() );
1883 exit();
1884 }
1885
1886 if( ! empty( $_POST['phrases'] ) ) {
1887 WPF()->phrase->edit();
1888 }
1889
1890 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) ) );
1891 exit();
1892 }
1893
1894 /**
1895 * user_ban action
1896 */
1897 public function user_ban() {
1898 $userid = intval( wpfval( $_GET, 'userid' ) );
1899 check_admin_referer( 'wpforo-user-ban-' . $userid );
1900
1901 if( ! WPF()->usergroup->can( 'vm' ) || ! WPF()->usergroup->can( 'bm' ) || $userid === WPF()->current_userid ) {
1902 WPF()->notice->add( 'Permission denied', 'error' );
1903 wp_safe_redirect( admin_url() );
1904 exit();
1905 }
1906
1907 WPF()->member->ban( $userid );
1908 wpforo_clean_cache( 'user' );
1909
1910 wp_safe_redirect( wp_get_referer() );
1911 exit();
1912 }
1913
1914 /**
1915 * user_unban action
1916 */
1917 public function user_unban() {
1918 $userid = intval( wpfval( $_GET, 'userid' ) );
1919 check_admin_referer( 'wpforo-user-unban-' . $userid );
1920
1921 if( ! WPF()->usergroup->can( 'vm' ) || ! WPF()->usergroup->can( 'bm' ) || $userid === WPF()->current_userid ) {
1922 WPF()->notice->add( 'Permission denied', 'error' );
1923 wp_safe_redirect( admin_url() );
1924 exit();
1925 }
1926
1927 WPF()->member->unban( $userid );
1928 wpforo_clean_cache( 'user' );
1929
1930 wp_safe_redirect( wp_get_referer() );
1931 exit();
1932 }
1933
1934 /**
1935 * user_activate action
1936 */
1937 public function user_activate() {
1938 $userid = intval( wpfval( $_GET, 'userid' ) );
1939 check_admin_referer( 'wpforo-user-activate-' . $userid );
1940
1941 if( ! WPF()->usergroup->can( 'vm' ) || ! WPF()->usergroup->can( 'bm' ) || $userid === WPF()->current_userid ) {
1942 WPF()->notice->add( 'Permission denied', 'error' );
1943 wp_safe_redirect( admin_url() );
1944 exit();
1945 }
1946
1947 WPF()->member->activate( $userid );
1948
1949 wp_safe_redirect( wp_get_referer() );
1950 exit();
1951 }
1952
1953 /**
1954 * user_deactivate action
1955 */
1956 public function user_deactivate() {
1957 $userid = intval( wpfval( $_GET, 'userid' ) );
1958 check_admin_referer( 'wpforo-user-deactivate-' . $userid );
1959
1960 if( ! WPF()->usergroup->can( 'vm' ) || ! WPF()->usergroup->can( 'bm' ) || $userid === WPF()->current_userid ) {
1961 WPF()->notice->add( 'Permission denied', 'error' );
1962 wp_safe_redirect( admin_url() );
1963 exit();
1964 }
1965
1966 WPF()->member->deactivate( $userid );
1967
1968 wp_safe_redirect( wp_get_referer() );
1969 exit();
1970 }
1971
1972 public function user_ban_ajax() {
1973 wpforo_verify_nonce( 'wpforo_user_ban' );
1974 $userid = WPF()->current_object['user']['userid'];
1975 $currentstate = (int) wpfval( $_POST, 'currentstate' );
1976 if( $currentstate ) {
1977 $r = WPF()->member->unban( $userid );
1978 } else {
1979 $r = WPF()->member->ban( $userid );
1980 }
1981
1982 if( $r ) {
1983 wp_send_json_success( [
1984 'currentstate' => (int) ! $currentstate,
1985 'notice' => WPF()->notice->get_notices(),
1986 ] );
1987 } else {
1988 wp_send_json_error( [ 'notice' => WPF()->notice->get_notices() ] );
1989 }
1990 }
1991
1992 public function get_member_template() {
1993 wpforo_verify_nonce( 'wpforo_get_member_template' );
1994 $href = wpfval( $_POST, 'href' );
1995 WPF()->init_current_url( $href );
1996 WPF()->init_current_object();
1997 if( wpforo_is_member_template() ) {
1998 if( ( $template = WPF()->tpl->get_template(
1999 WPF()->current_object['template']
2000 ) ) && $template['type'] === 'callback' && is_callable( $template['callback_for_page'] ) ) {
2001 ob_start();
2002 echo call_user_func( $template['callback_for_page'], $template );
2003 wp_send_json_success( [ 'html' => ob_get_clean() ] );
2004 }
2005 }
2006 wp_send_json_error();
2007 }
2008
2009 public function search_existed_topics() {
2010 if( ! apply_filters( 'wpforo_topic_suggestion', true ) ) {
2011 wp_send_json_error();
2012 }
2013 wpforo_verify_nonce( 'wpforo_search_existed_topics' );
2014 $title = trim( (string) wpfval( $_POST, 'title' ) );
2015 $topicids = WPF()->topic->search( $title, 'title' );
2016 if( $topicids ) {
2017 $topics = WPF()->topic->get_topics(
2018 [
2019 'include' => $topicids,
2020 'row_count' => apply_filters( 'wpforo_suggested_topics_limit', 5 ),
2021 'orderby' => 'created',
2022 ]
2023 );
2024 if( $topics ) {
2025 $topics = array_map( function( $topic ) {
2026 $topic['url'] = WPF()->topic->get_url( $topic );
2027
2028 return $topic;
2029 }, $topics );
2030
2031 wp_send_json_success( $topics );
2032 }
2033 }
2034
2035 wp_send_json_error();
2036 }
2037
2038 public function confirm_current_user_password() {
2039 wpforo_verify_nonce( 'wpforo_confirm_current_user_password' );
2040 $pwd = wpfval( $_POST, 'pwd' );
2041 if( wp_check_password( $pwd, WPF()->current_user['user_pass'], WPF()->current_user['userid'] ) ) {
2042 wp_send_json_success();
2043 } else {
2044 wp_send_json_error();
2045 }
2046 }
2047
2048 /**
2049 * Handle frontend user delete action
2050 *
2051 * Fires two hooks:
2052 * - wpforo_before_front_delete_user: before the user is deleted, passes the current user array
2053 * - wpforo_after_front_delete_user: after the user is deleted, passes the (previous) user array
2054 */
2055 public function user_delete() {
2056 wpforo_verify_nonce( 'user_delete', 'full' );
2057 if( WPF()->current_object['user'] && ( $action = WPF()->member->get_action(
2058 WPF()->current_object['user'],
2059 'delete'
2060 ) ) && is_callable( $action['callback_for_can'] ) && call_user_func(
2061 $action['callback_for_can']
2062 ) ) {
2063
2064 if( $pwd = wpfval( $_GET, 'pwd' ) ) {
2065 if( wp_check_password( $pwd, WPF()->current_user['user_pass'], WPF()->current_user['userid'] ) ) {
2066 // Fire an action before the frontend user deletion happens so integrators can capture user data
2067 do_action( 'wpforo_before_front_delete_user', WPF()->current_object['user'] );
2068 if( ! function_exists( 'wp_delete_user' ) ) require_once ABSPATH . "wp-admin/includes/user.php";
2069 if( wp_delete_user( WPF()->current_object['user']['userid'] ) ) {
2070
2071 do_action( 'wpforo_after_front_delete_user', WPF()->current_object['user'] );
2072
2073 WPF()->notice->add( 'User successfully deleted', 'success' );
2074 } else {
2075 WPF()->notice->add( 'User delete error', 'error' );
2076 }
2077 } else {
2078 WPF()->notice->add( 'User deletion error: The password you entered is incorrect.', 'error' );
2079 }
2080 } else {
2081 WPF()->notice->add( 'User delete error: missing argument.', 'error' );
2082 }
2083 } else {
2084 WPF()->notice->add( 'Permission denied for this action', 'error' );
2085 }
2086
2087 wp_safe_redirect( wpforo_url( '', 'members' ) );
2088 exit();
2089 }
2090
2091 /**
2092 * action after WordPress native deleted_user hook
2093 *
2094 * @param int $userid already deleted user ID
2095 */
2096 public function deleted_user( $userid, $reassign = null ) {
2097 if( wpfval( $_REQUEST, 'wpforo_user_delete_option' ) === 'reassign' ) {
2098 WPF()->member->delete( $userid, wpforo_bigintval( wpfval( $_REQUEST, 'wpforo_reassign_userid' ) ) );
2099 } elseif( wpfval( $_REQUEST, 'wpforo_user_delete_option' ) === 'delete' ) {
2100 WPF()->member->delete( $userid );
2101 } elseif( $reassign ) {
2102 WPF()->member->delete( $userid, $reassign );
2103 } else {
2104 WPF()->member->delete( $userid, ( wpforo_setting( 'authorization', 'user_delete_method' ) === 'soft' ? 0 : null ) );
2105 }
2106 WPF()->notice->clear();
2107 }
2108
2109 /**
2110 * doing bulk member actions ( ban, unban, delete )
2111 */
2112 public function bulk_members() {
2113 check_admin_referer( 'bulk-members' );
2114
2115 if( ! WPF()->usergroup->can( 'vm' ) ) {
2116 WPF()->notice->add( 'Permission denied', 'error' );
2117 wp_safe_redirect( admin_url() );
2118 exit();
2119 }
2120
2121 $new_groupid = - 1;
2122 if( ! empty( $_GET['new_groupid'] ) && $_GET['new_groupid'] !== '-1' ) {
2123 $new_groupid = intval( $_GET['new_groupid'] );
2124 } elseif( ! empty( $_GET['new_groupid2'] ) && $_GET['new_groupid2'] !== '-1' ) {
2125 $new_groupid = intval( $_GET['new_groupid2'] );
2126 }
2127
2128 $u_action = $this->get_current_bulk_action();
2129 if( in_array( $u_action, [ 'ban', 'unban', 'activate', 'deactivate' ] ) && ! WPF()->usergroup->can( 'bm' ) ) {
2130 WPF()->notice->add( 'Permission denied', 'error' );
2131 wp_safe_redirect( admin_url() );
2132 exit();
2133 } elseif( $u_action === 'delete' && ! WPF()->usergroup->can( 'dm' ) ) {
2134 WPF()->notice->add( 'Permission denied', 'error' );
2135 wp_safe_redirect( admin_url() );
2136 exit();
2137 }
2138
2139 $userids = (array) wpfval( $_GET, 'userids' );
2140 $userids = array_filter( array_map( 'wpforo_bigintval', $userids ) );
2141 $userids = array_diff( $userids, (array) WPF()->current_userid );
2142 if( $u_action && ! empty( $userids ) ) {
2143 if( $u_action === 'delete' ) {
2144 $url = self_admin_url( 'users.php?action=delete&users[]=' . implode( '&users[]=', $userids ) );
2145 $url = str_replace( '&amp;', '&', wp_nonce_url( $url, 'bulk-users' ) );
2146 wp_safe_redirect( $url );
2147 exit();
2148 } elseif( $u_action === 'ban' ) {
2149 foreach( $userids as $userid ) {
2150 WPF()->member->ban( $userid );
2151 }
2152 } elseif( $u_action === 'unban' ) {
2153 foreach( $userids as $userid ) {
2154 WPF()->member->unban( $userid );
2155 }
2156 } elseif( $u_action === 'activate' ) {
2157 foreach( $userids as $userid ) {
2158 WPF()->member->activate( $userid );
2159 }
2160 } elseif( $u_action === 'deactivate' ) {
2161 foreach( $userids as $userid ) {
2162 WPF()->member->deactivate( $userid );
2163 }
2164 }
2165 } elseif( ! $u_action && wpfkey( $_GET, 'change_group' ) ) {
2166 if( ! empty( $userids ) && $new_groupid !== - 1 ) {
2167 $status = WPF()->usergroup->set_users_groupid( [ $new_groupid => $userids ] );
2168 if( $status['success'] ) WPF()->notice->add( 'Usergroup is successfully changed for selected users', 'success' );
2169 } else {
2170 WPF()->notice->add( 'Please select users and usergroup', 'error' );
2171 }
2172 }
2173 wpforo_clean_cache( 'user' );
2174
2175 wp_safe_redirect( wp_get_referer() );
2176 exit();
2177 }
2178
2179 /**
2180 * usergroup_add form submit action
2181 */
2182 public function usergroup_add() {
2183 check_admin_referer( 'wpforo-usergroup-add' );
2184
2185 if( ! WPF()->usergroup->can( 'vmg' ) ) {
2186 WPF()->notice->add( 'Permission denied', 'error' );
2187 wp_safe_redirect( admin_url() );
2188 exit();
2189 }
2190
2191 if( ! empty( $_POST['usergroup'] ) ) {
2192 $group = WPF()->usergroup->fix_group( $_POST['usergroup'] );
2193 $color = wpfval( $group, 'wpfugc' ) ? '' : sanitize_text_field( $group['color'] );
2194 $groupid = WPF()->usergroup->add(
2195 $group['name'],
2196 $group['cans'],
2197 $group['description'],
2198 $group['role'],
2199 $group['access'],
2200 $color,
2201 $group['visible'],
2202 $group['secondary']
2203 );
2204 if( $groupid ) wpforo_clean_cache( 'loop', $groupid );
2205 }
2206
2207 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) ) );
2208 exit();
2209 }
2210
2211 /**
2212 * usergroup_edit form submit action
2213 */
2214 public function usergroup_edit() {
2215 check_admin_referer( 'wpforo-usergroup-edit' );
2216
2217 if( ! WPF()->usergroup->can( 'vmg' ) ) {
2218 WPF()->notice->add( 'Permission denied', 'error' );
2219 wp_safe_redirect( admin_url() );
2220 exit();
2221 }
2222
2223 if( ! empty( $_POST['usergroup'] ) ) {
2224 $group = WPF()->usergroup->fix_group( $_POST['usergroup'] );
2225 $color = wpfval( $group, 'wpfugc' ) ? '' : sanitize_text_field( $group['color'] );
2226 WPF()->usergroup->edit(
2227 $group['groupid'],
2228 $group['name'],
2229 $group['cans'],
2230 $group['description'],
2231 $group['role'],
2232 null,
2233 $color,
2234 $group['visible'],
2235 $group['secondary']
2236 );
2237 wpforo_clean_cache( 'loop', $group['groupid'] );
2238 }
2239
2240 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) ) );
2241 exit();
2242 }
2243
2244 /**
2245 * usergroup_delete form submit action
2246 */
2247 public function usergroup_delete() {
2248 check_admin_referer( 'wpforo-usergroup-delete' );
2249
2250 if( ! WPF()->usergroup->can( 'vmg' ) ) {
2251 WPF()->notice->add( 'Permission denied', 'error' );
2252 wp_safe_redirect( admin_url() );
2253 exit();
2254 }
2255
2256 if( wpfval( $_POST, 'usergroup', 'delete' ) ) {
2257 $args = [ 'groupid' => wpfval( $_POST, 'usergroup', 'groupid' ) ];
2258 if( $userids = WPF()->member->get_userids( $args ) ) {
2259 $redirect_to = self_admin_url( 'users.php?action=delete&users[]=' . implode( '&users[]=', $userids ) );
2260 $redirect_to = str_replace( '&amp;', '&', wp_nonce_url( $redirect_to, 'bulk-users' ) );
2261 wp_safe_redirect( $redirect_to );
2262 exit();
2263 }
2264 }
2265
2266 if( ! empty( $_POST['usergroup'] ) ) {
2267 WPF()->usergroup->delete( wpfval( $_POST['usergroup'], 'groupid' ), wpfval( $_POST['usergroup'], 'mergeid' ) );
2268 wpforo_clean_cache( 'user' );
2269 }
2270
2271 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) ) );
2272 exit();
2273 }
2274
2275 /**
2276 * default_groupid_change action
2277 */
2278 public function default_groupid_change() {
2279 $default_groupid = intval( wpfval( $_GET, 'default_groupid' ) );
2280 check_admin_referer( 'wpforo-default-groupid-change-' . $default_groupid );
2281
2282 if( ! WPF()->usergroup->can( 'vmg' ) ) {
2283 WPF()->notice->add( 'Permission denied', 'error' );
2284 wp_safe_redirect( admin_url() );
2285 exit();
2286 }
2287
2288 if( $default_groupid ) WPF()->usergroup->set_default( $default_groupid );
2289
2290 wp_safe_redirect( wp_get_raw_referer() );
2291 exit();
2292 }
2293
2294 /**
2295 * prevent to show usergroup delete form when !$groupid || $groupid <= 5
2296 */
2297 public function usergroup_delete_form() {
2298 if( intval( wpfval( $_GET, 'groupid' ) ) <= 5 ) {
2299 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) ) );
2300 exit();
2301 }
2302 }
2303
2304 /**
2305 * access_add form submit action
2306 */
2307 public function access_add() {
2308 check_admin_referer( 'wpforo-access-add' );
2309
2310 if( ! WPF()->usergroup->can( 'ms' ) ) {
2311 WPF()->notice->add( 'Permission denied', 'error' );
2312 wp_safe_redirect( admin_url() );
2313 exit();
2314 }
2315
2316 if( ! empty( $_POST['access'] ) ) {
2317 WPF()->perm->add( WPF()->perm->fix_access( $_POST['access'] ) );
2318 }
2319
2320 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'accesses' ) ) );
2321 exit();
2322 }
2323
2324 /**
2325 * access_edit form submit action
2326 */
2327 public function access_edit() {
2328 check_admin_referer( 'wpforo-access-edit' );
2329
2330 if( ! WPF()->usergroup->can( 'ms' ) ) {
2331 WPF()->notice->add( 'Permission denied', 'error' );
2332 wp_safe_redirect( admin_url() );
2333 exit();
2334 }
2335
2336 if( ! empty( $_POST['access'] ) ) {
2337 WPF()->perm->edit( WPF()->perm->fix_access( $_POST['access'] ) );
2338 wpforo_clean_cache( 'loop' );
2339 }
2340
2341 wp_safe_redirect( wp_get_raw_referer() );
2342 exit();
2343 }
2344
2345 /**
2346 * access_delete form submit action
2347 */
2348 public function access_delete() {
2349 $accessid = intval( wpfval( $_GET, 'accessid' ) );
2350 check_admin_referer( 'wpforo-access-delete-' . $accessid );
2351
2352 if( ! WPF()->usergroup->can( 'ms' ) ) {
2353 WPF()->notice->add( 'Permission denied', 'error' );
2354 wp_safe_redirect( admin_url() );
2355 exit();
2356 }
2357
2358 WPF()->perm->delete( $accessid );
2359 wpforo_clean_cache( 'loop' );
2360
2361 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'accesses' ) ) );
2362 exit();
2363 }
2364
2365 public function theme_activate() {
2366 check_admin_referer( 'wpforo-theme-activate' );
2367
2368 if( ! WPF()->usergroup->can( 'mth' ) ) {
2369 WPF()->notice->add( 'Permission denied', 'error' );
2370 wp_safe_redirect( admin_url() );
2371 exit();
2372 }
2373
2374 $notice = __( 'Theme file not readable', 'wpforo' );
2375 $notice_type = 'error';
2376 if( ( $theme = trim( sanitize_text_field( (string) wpfval( $_GET, 'theme' ) ) ) ) && WPF()->tpl->theme_exists(
2377 $theme
2378 ) ) {
2379 $general = WPF()->settings->general;
2380 $general['current_theme'] = $theme;
2381 wpforo_update_option( 'wpforo_general', $general );
2382 $notice = __( 'Theme Successfully Activated', 'wpforo' );
2383 $notice_type = 'success';
2384 }
2385
2386 WPF()->notice->add( $notice, $notice_type );
2387 wp_safe_redirect( wp_get_raw_referer() );
2388 exit();
2389 }
2390
2391 /**
2392 * theme_delete action
2393 */
2394 public function theme_delete() {
2395 check_admin_referer( 'wpforo-theme-delete' );
2396
2397 if( ! WPF()->usergroup->can( 'mth' ) ) {
2398 WPF()->notice->add( 'Permission denied', 'error' );
2399 wp_safe_redirect( admin_url() );
2400 exit();
2401 }
2402
2403 $notice = __( 'Theme delete error', 'wpforo' );
2404 $notice_type = 'error';
2405 if( $theme = trim( sanitize_text_field( (string) wpfval( $_GET, 'theme' ) ) ) ) {
2406 if( WPF()->tpl->theme !== $theme ) {
2407 $remove_dir = WPFORO_THEME_DIR . '/' . $theme;
2408 if( is_dir( $remove_dir ) ) {
2409 wpforo_remove_directory( $remove_dir );
2410 $notice = __( 'Theme delete success', 'wpforo' );
2411 $notice_type = 'success';
2412 }
2413 }
2414 }
2415
2416 WPF()->notice->add( $notice, $notice_type );
2417 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'themes' ) ) );
2418 exit();
2419 }
2420
2421 /**
2422 * update wpForo addons CSS styles to make compatible with the current version of wpForo
2423 */
2424 function update_addons_css() {
2425 check_admin_referer( 'wpforo-update-addons-css' );
2426 wpforo_wrap_in_all_addons_css();
2427 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'settings' ) ) );
2428 exit();
2429 }
2430
2431 /**
2432 * dissmiss the poll version is old notification for admins
2433 */
2434 public function dissmiss_poll_version_is_old() {
2435 check_admin_referer( 'wpforo-dissmiss-poll-version-is-old' );
2436 WPF()->dissmissed['poll_version_is_old'] = 1;
2437 wpforo_update_option( 'dissmissed', WPF()->dissmissed );
2438 wp_safe_redirect( admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ) );
2439 exit();
2440 }
2441
2442 /**
2443 * dissmiss the recaptcha not configured notification for admins
2444 */
2445 public function dissmiss_recaptcha_note() {
2446 if( wpfval( $_POST, 'backend' ) ) {
2447 WPF()->dissmissed['recaptcha_backend_note'] = 1;
2448 } else {
2449 WPF()->dissmissed['recaptcha_note'] = 1;
2450 }
2451 $response = wpforo_update_option( 'dissmissed', WPF()->dissmissed );
2452 if( $response ) {
2453 wp_send_json_success();
2454 } else {
2455 wp_send_json_error();
2456 }
2457 }
2458
2459 /**
2460 * wpforo before deactivate action
2461 */
2462 public function deactivate() {
2463 $response = [ 'code' => 0 ];
2464 $json = filter_input( INPUT_POST, 'deactivateData' );
2465 if( $json ) {
2466 parse_str( $json, $data );
2467
2468 $blogTitle = get_option( 'blogname' );
2469 $to = 'feedback@wpforo.com';
2470 $subject = '[wpForo Feedback - ' . WPFORO_VERSION . ']';
2471 $headers = [];
2472 $contentType = 'text/html';
2473 $fromName = apply_filters( 'wp_mail_from_name', $blogTitle );
2474 $fromName = html_entity_decode( $fromName, ENT_QUOTES );
2475 $siteUrl = get_site_url();
2476 $parsedUrl = parse_url( $siteUrl );
2477 $domain = isset( $parsedUrl['host'] ) ? $parsedUrl['host'] : '';
2478 $fromEmail = 'no-reply@' . $domain;
2479 $headers[] = "Content-Type: $contentType; charset=UTF-8";
2480 $headers[] = "From: " . $fromName . " <" . $fromEmail . "> \r\n";
2481 $message = "Dismiss and never show again";
2482
2483 if( isset( $data['never_show'] ) && ( $v = intval( $data['never_show'] ) ) ) {
2484 wpforo_update_option( 'deactivation_dialog_never_show', $v );
2485 $response['code'] = 'dismiss_and_deactivate';
2486 } elseif( isset( $data['deactivation_reason'] ) && ( $reason = trim( (string) $data['deactivation_reason'] ) ) ) {
2487 $subject .= ' - ' . $reason;
2488 $message = "<strong>Deactivation reason:</strong> " . $reason . "\r\n" . "<br/>";
2489 if( isset( $data['deactivation_reason_desc'] ) && ( $reasonDesc = trim(
2490 (string) $data['deactivation_reason_desc']
2491 ) ) ) {
2492 $message .= "<strong>Deactivation reason description:</strong> " . $reasonDesc . "\r\n" . "<br/>";
2493 }
2494 if( isset( $data['deactivation_feedback_email'] ) && ( $feedback_email = trim(
2495 (string) $data['deactivation_feedback_email']
2496 ) ) ) {
2497 $to = 'support@wpforo.com';
2498 $message .= "<strong>Feedback Email:</strong> " . $feedback_email . "\r\n" . "<br/>";
2499 }
2500 $subject = html_entity_decode( $subject, ENT_QUOTES );
2501 $message = html_entity_decode( $message, ENT_QUOTES );
2502 $response['code'] = 'send_and_deactivate';
2503 }
2504
2505 wp_mail( $to, $subject, $message, $headers );
2506 }
2507 wp_die( wp_json_encode( $response ) );
2508 }
2509
2510 /**
2511 * base_slugs_settings_save from submit action
2512 *
2513 * @return void
2514 */
2515 public function base_slugs_settings_save() {
2516 check_admin_referer( 'wpforo_settings_save_general' );
2517
2518 if( wpfkey( $_POST, 'reset' ) ) {
2519 wpforo_delete_option( 'wpforo_base_slugs' );
2520 WPF()->notice->add( 'Successfully Done', 'success' );
2521 } else {
2522 $slugs = wpforo_array_args_cast_and_merge(
2523 array_filter( array_map( 'sanitize_title', wp_unslash( $_POST['slugs'] ) ) ),
2524 WPF()->settings->_slugs
2525 );
2526 $slugs = array_intersect_key( $slugs, WPF()->settings->_slugs );
2527 $slugs = array_diff_key( $slugs, WPF()->tpl->templates );
2528 if( $slugs == array_unique( $slugs ) ) {
2529 wpforo_update_option( 'wpforo_base_slugs', $slugs );
2530 WPF()->notice->add( 'Successfully Done', 'success' );
2531 } else {
2532 WPF()->notice->add( 'Please save "Forum template slugs" uniqueness', 'error' );
2533 }
2534 }
2535
2536 /*wp_safe_redirect( wp_get_raw_referer() );
2537 exit();*/
2538 }
2539
2540 /**
2541 * general_settings_save from submit action
2542 *
2543 * @return void
2544 */
2545 public function general_settings_save() {
2546 check_admin_referer( 'wpforo_settings_save_general' );
2547
2548 if( wpfkey( $_POST, 'reset' ) ) {
2549 wpforo_delete_option( 'wpforo_general' );
2550 } else {
2551 $general = wpforo_array_args_cast_and_merge(
2552 wp_unslash( $_POST['general'] ),
2553 WPF()->settings->_general
2554 );
2555 $general['admin_bar'] = array_map( 'intval', (array) wpfval( $_POST['general'], 'admin_bar' ) );
2556 $general['current_theme'] = WPF()->tpl->theme;
2557 wpforo_update_option( 'wpforo_general', $general );
2558 }
2559
2560 WPF()->notice->add( 'Successfully Done', 'success' );
2561 wp_safe_redirect( wp_get_raw_referer() );
2562 exit();
2563 }
2564
2565 /**
2566 * base_slugs_settings_save from submit action
2567 *
2568 * @return void
2569 */
2570 public function slugs_settings_save() {
2571 check_admin_referer( 'wpforo_settings_save_board' );
2572
2573 if( wpfkey( $_POST, 'reset' ) ) {
2574 wpforo_delete_option( 'slugs' );
2575 WPF()->notice->add( 'Successfully Done', 'success' );
2576 } else {
2577 $slugs = wpforo_array_args_cast_and_merge(
2578 array_filter( array_map( 'sanitize_title', wp_unslash( $_POST['slugs'] ) ) ),
2579 WPF()->settings->_slugs
2580 );
2581 $slugs = array_intersect_key( $slugs, WPF()->tpl->templates );
2582 if( $slugs == array_unique( $slugs ) ) {
2583 foreach( $this->generate_option_names( 'slugs' ) as $option_name ) {
2584 wpforo_update_option( $option_name, $slugs );
2585 }
2586 WPF()->notice->add( 'Successfully Done', 'success' );
2587 } else {
2588 WPF()->notice->add( 'Please save "Forum template slugs" uniqueness', 'error' );
2589 }
2590 }
2591
2592 /*wp_safe_redirect( wp_get_raw_referer() );
2593 exit();*/
2594 }
2595
2596 /**
2597 * general_settings_save from submit action
2598 *
2599 * @return void
2600 */
2601 public function board_settings_save() {
2602 check_admin_referer( 'wpforo_settings_save_board' );
2603
2604 if( wpfkey( $_POST, 'reset' ) ) {
2605 wpforo_delete_option( 'board' );
2606 } else {
2607 $board = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['board'] ), WPF()->settings->_board );
2608 foreach( $this->generate_option_names( 'board' ) as $option_name ) {
2609 wpforo_update_option( $option_name, $board );
2610 }
2611 }
2612
2613 wpforo_clean_cache();
2614
2615 WPF()->notice->add( 'Successfully Done', 'success' );
2616 wp_safe_redirect( wp_get_raw_referer() );
2617 exit();
2618 }
2619
2620 /**
2621 * akismet_settings_save from submit action
2622 *
2623 * @return void
2624 */
2625 public function akismet_settings_save() {
2626 check_admin_referer( 'wpforo_settings_save_akismet' );
2627
2628 if( wpfkey( $_POST, 'reset' ) ) {
2629 wpforo_delete_option( 'akismet' );
2630 } else {
2631 $akismet = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['akismet'] ), WPF()->settings->_akismet );
2632 foreach( $this->generate_option_names( 'akismet' ) as $option_name ) {
2633 wpforo_update_option( $option_name, $akismet );
2634 }
2635 }
2636
2637 WPF()->notice->add( 'Successfully Done', 'success' );
2638 wp_safe_redirect( wp_get_raw_referer() );
2639 exit();
2640 }
2641
2642 /**
2643 * antispam_settings_save from submit action
2644 *
2645 * @return void
2646 */
2647 public function antispam_settings_save() {
2648 check_admin_referer( 'wpforo_settings_save_antispam' );
2649
2650 if( wpfkey( $_POST, 'reset' ) ) {
2651 wpforo_delete_option( 'antispam' );
2652 } else {
2653 $antispam = wp_unslash( $_POST['antispam'] );
2654 $antispam['limited_file_ext'] = array_unique(
2655 array_filter(
2656 preg_split(
2657 '#\s*\|\s*|\s*,\s*|\s+#',
2658 trim( sanitize_textarea_field( (string) wpfval( $antispam, 'limited_file_ext' ) ) )
2659 )
2660 )
2661 );
2662 $antispam['exclude_file_ext'] = array_unique(
2663 array_filter(
2664 preg_split(
2665 '#\s*\|\s*|\s*,\s*|\s+#',
2666 trim( sanitize_textarea_field( (string) wpfval( $antispam, 'exclude_file_ext' ) ) )
2667 )
2668 )
2669 );
2670 $_antispam = WPF()->settings->_antispam;
2671 $_antispam['limited_file_ext'] = $_antispam['exclude_file_ext'] = [];
2672 $antispam = wpforo_array_args_cast_and_merge( $antispam, $_antispam );
2673 foreach( $this->generate_option_names( 'antispam' ) as $option_name ) {
2674 wpforo_update_option( $option_name, $antispam );
2675 }
2676 }
2677
2678 WPF()->notice->add( 'Successfully Done', 'success' );
2679 wp_safe_redirect( wp_get_raw_referer() );
2680 exit();
2681 }
2682
2683 /**
2684 * authorization_settings_save after submit action
2685 *
2686 * @return void
2687 */
2688 public function authorization_settings_save() {
2689 check_admin_referer( 'wpforo_settings_save_authorization' );
2690
2691 if( wpfkey( $_POST, 'reset' ) ) {
2692 wpforo_delete_option( 'wpforo_authorization' );
2693 } else {
2694 $authorization = wpforo_array_args_cast_and_merge(
2695 wp_unslash( $_POST['authorization'] ),
2696 WPF()->settings->_authorization
2697 );
2698
2699 if( preg_match( '#^https?://\S+$#iu', (string) $authorization['login_url'] ) ) $authorization['login_url'] = '';
2700 if( preg_match( '#^https?://\S+$#iu', (string) $authorization['register_url'] ) ) $authorization['register_url'] = '';
2701 if( preg_match(
2702 '#^https?://\S+$#iu',
2703 (string) $authorization['lost_password_url']
2704 ) ) {
2705 $authorization['lost_password_url'] = '';
2706 }
2707
2708 if( ! preg_match(
2709 '#^https?://\S+$#iu',
2710 (string) $authorization['redirect_url_after_login']
2711 ) ) {
2712 $authorization['redirect_url_after_login'] = '';
2713 }
2714 if( ! preg_match(
2715 '#^https?://\S+$#iu',
2716 (string) $authorization['redirect_url_after_register']
2717 ) ) {
2718 $authorization['redirect_url_after_register'] = '';
2719 }
2720 if( ! preg_match(
2721 '#^https?://\S+$#iu',
2722 (string) $authorization['redirect_url_after_confirm_sbscrb']
2723 ) ) {
2724 $authorization['redirect_url_after_confirm_sbscrb'] = '';
2725 }
2726
2727 $authorization['login_url'] = esc_url_raw( (string) $authorization['login_url'] );
2728 $authorization['register_url'] = esc_url_raw( (string) $authorization['register_url'] );
2729 $authorization['lost_password_url'] = esc_url_raw( (string) $authorization['lost_password_url'] );
2730 $authorization['redirect_url_after_login'] = esc_url_raw(
2731 (string) $authorization['redirect_url_after_login']
2732 );
2733 $authorization['redirect_url_after_register'] = esc_url_raw(
2734 (string) $authorization['redirect_url_after_register']
2735 );
2736 $authorization['redirect_url_after_confirm_sbscrb'] = esc_url_raw(
2737 (string) $authorization['redirect_url_after_confirm_sbscrb']
2738 );
2739
2740 wpforo_update_option( 'wpforo_authorization', $authorization );
2741 }
2742
2743 WPF()->notice->add( 'Successfully Done', 'success' );
2744 wp_safe_redirect( wp_get_raw_referer() );
2745 exit();
2746 }
2747
2748 /**
2749 * buddypress_settings_save from submit action
2750 *
2751 * @return void
2752 */
2753 public function buddypress_settings_save() {
2754 check_admin_referer( 'wpforo_settings_save_buddypress' );
2755
2756 if( wpfkey( $_POST, 'reset' ) ) {
2757 wpforo_delete_option( 'wpforo_buddypress' );
2758 } else {
2759 $buddypress = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['buddypress'] ), WPF()->settings->_buddypress );
2760 wpforo_update_option( 'wpforo_buddypress', $buddypress );
2761 }
2762
2763 WPF()->notice->add( 'Successfully Done', 'success' );
2764 wp_safe_redirect( wp_get_raw_referer() );
2765 exit();
2766 }
2767
2768 /**
2769 * components_settings_save from submit action
2770 *
2771 * @return void
2772 */
2773 public function components_settings_save() {
2774 check_admin_referer( 'wpforo_settings_save_components' );
2775
2776 if( wpfkey( $_POST, 'reset' ) ) {
2777 wpforo_delete_option( 'components' );
2778 } else {
2779 $components = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['components'] ), WPF()->settings->_components );
2780 foreach( $this->generate_option_names( 'components' ) as $option_name ) {
2781 wpforo_update_option( $option_name, $components );
2782 }
2783 }
2784
2785 WPF()->notice->add( 'Successfully Done', 'success' );
2786 wp_safe_redirect( wp_get_raw_referer() );
2787 exit();
2788 }
2789
2790 /**
2791 * email_settings_save from submit action
2792 *
2793 * @return void
2794 */
2795 public function email_settings_save() {
2796 check_admin_referer( 'wpforo_settings_save_email' );
2797
2798 if( wpfkey( $_POST, 'reset' ) ) {
2799 wpforo_delete_option( 'wpforo_email' );
2800 } else {
2801 $email = wp_unslash( $_POST['email'] );
2802 $email['admin_emails'] = sanitize_text_field( (string) $email['admin_emails'] );
2803 $email['admin_emails'] = array_map( 'sanitize_email', preg_split( '#\s*,\s*#u', trim( $email['admin_emails'] ) ) );
2804 $email['admin_emails'] = array_filter( $email['admin_emails'] );
2805 if( ! $email['admin_emails'] ) $email['admin_emails'] = (array) get_option( 'admin_email' );
2806 $email = wpforo_array_args_cast_and_merge( $email, WPF()->settings->_email );
2807
2808 $email['from_name'] = sanitize_text_field( $email['from_name'] );
2809 $email['from_email'] = sanitize_text_field( $email['from_email'] );
2810 $email['report_email_subject'] = sanitize_text_field( $email['report_email_subject'] );
2811 $email['report_email_message'] = wpforo_kses( $email['report_email_message'], 'email' );
2812 $email['wp_new_user_notification_email_admin_subject'] = sanitize_text_field(
2813 $email['wp_new_user_notification_email_admin_subject']
2814 );
2815 $email['wp_new_user_notification_email_admin_message'] = wpforo_kses(
2816 $email['wp_new_user_notification_email_admin_message'],
2817 'email'
2818 );
2819 $email['wp_new_user_notification_email_subject'] = sanitize_text_field(
2820 $email['wp_new_user_notification_email_subject']
2821 );
2822 $email['wp_new_user_notification_email_message'] = wpforo_kses(
2823 $email['wp_new_user_notification_email_message'],
2824 'email'
2825 );
2826 $email['reset_password_email_message'] = wpforo_kses(
2827 $email['reset_password_email_message'],
2828 'email'
2829 );
2830 $email['after_user_approve_email_subject'] = sanitize_text_field(
2831 $email['after_user_approve_email_subject']
2832 );
2833 $email['after_user_approve_email_message'] = wpforo_kses(
2834 $email['after_user_approve_email_message'],
2835 'email'
2836 );
2837
2838 wpforo_update_option( 'wpforo_email', $email );
2839 }
2840
2841 WPF()->notice->add( 'Successfully Done', 'success' );
2842 wp_safe_redirect( wp_get_raw_referer() );
2843 exit();
2844 }
2845
2846 /**
2847 * forums_settings_save from submit action
2848 *
2849 * @return void
2850 */
2851 public function forums_settings_save() {
2852 check_admin_referer( 'wpforo_settings_save_forums' );
2853
2854 if( wpfkey( $_POST, 'reset' ) ) {
2855 wpforo_delete_option( 'forums' );
2856 } else {
2857 $forums = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['forums'] ), WPF()->settings->_forums );
2858 foreach( $this->generate_option_names( 'forums' ) as $option_name ) {
2859 wpforo_update_option( $option_name, $forums );
2860 }
2861 }
2862
2863 WPF()->notice->add( 'Successfully Done', 'success' );
2864 wp_safe_redirect( wp_get_raw_referer() );
2865 exit();
2866 }
2867
2868 /**
2869 * logging_settings_save from submit action
2870 *
2871 * @return void
2872 */
2873 public function logging_settings_save() {
2874 check_admin_referer( 'wpforo_settings_save_logging' );
2875
2876 if( wpfkey( $_POST, 'reset' ) ) {
2877 wpforo_delete_option( 'logging' );
2878 } else {
2879 $logging = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['logging'] ), WPF()->settings->_logging );
2880 foreach( $this->generate_option_names( 'logging' ) as $option_name ) {
2881 wpforo_update_option( $option_name, $logging );
2882 }
2883 }
2884
2885 WPF()->notice->add( 'Successfully Done', 'success' );
2886 wp_safe_redirect( wp_get_raw_referer() );
2887 exit();
2888 }
2889
2890 /**
2891 * activity_settings_save from submit action
2892 *
2893 * @return void
2894 */
2895 public function activity_settings_save() {
2896 check_admin_referer( 'wpforo_settings_save_activity' );
2897
2898 if( wpfkey( $_POST, 'reset' ) ) {
2899 wpforo_delete_option( 'activity' );
2900 // Unschedule cleanup cron when settings are reset
2901 WPF()->activity->unschedule_cleanup();
2902 } else {
2903 $activity = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['activity'] ), WPF()->settings->_activity );
2904 $activity['enabled_types'] = array_map( 'sanitize_text_field', (array) wpfval( $_POST['activity'], 'enabled_types' ) );
2905 foreach( $this->generate_option_names( 'activity' ) as $option_name ) {
2906 wpforo_update_option( $option_name, $activity );
2907 }
2908
2909 // Handle activity cleanup cron based on retention_days setting
2910 $retention_days = isset( $activity['retention_days'] ) ? (int) $activity['retention_days'] : 365;
2911 if( $retention_days > 0 ) {
2912 WPF()->activity->schedule_cleanup();
2913 } else {
2914 WPF()->activity->unschedule_cleanup();
2915 }
2916 }
2917
2918 WPF()->notice->add( 'Successfully Done', 'success' );
2919 wp_safe_redirect( wp_get_raw_referer() );
2920 exit();
2921 }
2922
2923 /**
2924 * members_settings_save from submit action
2925 *
2926 * @return void
2927 */
2928 public function members_settings_save() {
2929 check_admin_referer( 'wpforo_settings_save_members' );
2930
2931 if( wpfkey( $_POST, 'reset' ) ) {
2932 wpforo_delete_option( 'wpforo_members' );
2933 } else {
2934 $members = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['members'] ), WPF()->settings->_members );
2935 wpforo_update_option( 'wpforo_members', $members );
2936 }
2937
2938 WPF()->notice->add( 'Successfully Done', 'success' );
2939 wp_safe_redirect( wp_get_raw_referer() );
2940 exit();
2941 }
2942
2943 /**
2944 * notifications_settings_save from submit action
2945 *
2946 * @return void
2947 */
2948 public function notifications_settings_save() {
2949 check_admin_referer( 'wpforo_settings_save_notifications' );
2950
2951 if( wpfkey( $_POST, 'reset' ) ) {
2952 wpforo_delete_option( 'notifications' );
2953 } else {
2954 $notifications = wpforo_array_args_cast_and_merge(
2955 wp_unslash( $_POST['notifications'] ),
2956 WPF()->settings->_notifications
2957 );
2958 foreach( $this->generate_option_names( 'notifications' ) as $option_name ) {
2959 wpforo_update_option( $option_name, $notifications );
2960 }
2961 }
2962
2963 WPF()->notice->add( 'Successfully Done', 'success' );
2964 wp_safe_redirect( wp_get_raw_referer() );
2965 exit();
2966 }
2967
2968 /**
2969 * posting_settings_save from submit action
2970 *
2971 * @return void
2972 */
2973 public function posting_settings_save() {
2974 check_admin_referer( 'wpforo_settings_save_posting' );
2975
2976 if( wpfkey( $_POST, 'reset' ) ) {
2977 wpforo_delete_option( 'posting' );
2978 } else {
2979 $posting = wpforo_array_args_cast_and_merge(
2980 wp_unslash( $_POST['posting'] ),
2981 WPF()->settings->_posting
2982 );
2983 $posting['max_upload_size'] = $posting['max_upload_size'] * 1024 * 1024;
2984 $posting['edit_own_topic_durr'] = $posting['edit_own_topic_durr'] * 60;
2985 $posting['delete_own_topic_durr'] = $posting['delete_own_topic_durr'] * 60;
2986 $posting['edit_own_post_durr'] = $posting['edit_own_post_durr'] * 60;
2987 $posting['delete_own_post_durr'] = $posting['delete_own_post_durr'] * 60;
2988 $posting['extra_html_tags'] = sanitize_textarea_field( $posting['extra_html_tags'] );
2989 foreach( $this->generate_option_names( 'posting' ) as $option_name ) {
2990 wpforo_update_option( $option_name, $posting );
2991 }
2992 }
2993
2994 WPF()->notice->add( 'Successfully Done', 'success' );
2995 wp_safe_redirect( wp_get_raw_referer() );
2996 exit();
2997 }
2998
2999 /**
3000 * profiles_settings_save from submit action
3001 *
3002 * @return void
3003 */
3004 public function profiles_settings_save() {
3005 check_admin_referer( 'wpforo_settings_save_profiles' );
3006
3007 if( wpfkey( $_POST, 'reset' ) ) {
3008 wpforo_delete_option( 'wpforo_profiles' );
3009 } else {
3010 $profiles = wpforo_array_args_cast_and_merge(
3011 wp_unslash( $_POST['profiles'] ),
3012 WPF()->settings->_profiles
3013 );
3014 $profiles['default_cover'] = WPF()->settings->profiles['default_cover'];
3015 $profiles['default_title'] = sanitize_text_field( $profiles['default_title'] );
3016 $profiles['online_status_timeout'] = $profiles['online_status_timeout'] * 60;
3017 $profiles['title_groupids'] = array_map( 'intval', (array) wpfval( $_POST['profiles'], 'title_groupids' ) );
3018 $profiles['title_secondary_groupids'] = array_map(
3019 'intval',
3020 (array) wpfval( $_POST['profiles'], 'title_secondary_groupids' )
3021 );
3022 wpforo_update_option( 'wpforo_profiles', $profiles );
3023 }
3024
3025 WPF()->notice->add( 'Successfully Done', 'success' );
3026 wp_safe_redirect( wp_get_raw_referer() );
3027 exit();
3028 }
3029
3030 /**
3031 * rating_settings_save from submit action
3032 *
3033 * @return void
3034 */
3035 public function rating_settings_save() {
3036 check_admin_referer( 'wpforo_settings_save_rating' );
3037
3038 if( wpfkey( $_POST, 'reset' ) ) {
3039 wpforo_delete_option( 'wpforo_rating' );
3040 } else {
3041 $rating = wpforo_array_args_cast_and_merge(
3042 wp_unslash( $_POST['rating'] ),
3043 WPF()->settings->_rating
3044 );
3045 $rating['rating_title_ug'] = array_map( 'intval', (array) wpfval( $_POST['rating'], 'rating_title_ug' ) );
3046 $rating['rating_badge_ug'] = array_map( 'intval', (array) wpfval( $_POST['rating'], 'rating_badge_ug' ) );
3047 wpforo_update_option( 'wpforo_rating', $rating );
3048 }
3049
3050 WPF()->notice->add( 'Successfully Done', 'success' );
3051 wp_safe_redirect( wp_get_raw_referer() );
3052 exit();
3053 }
3054
3055 /**
3056 * recaptcha_settings_save from submit action
3057 *
3058 * @return void
3059 */
3060 public function recaptcha_settings_save() {
3061 check_admin_referer( 'wpforo_settings_save_recaptcha' );
3062
3063 if( wpfkey( $_POST, 'reset' ) ) {
3064 wpforo_delete_option( 'wpforo_recaptcha' );
3065 } else {
3066 $recaptcha = wpforo_array_args_cast_and_merge(
3067 wp_unslash( $_POST['recaptcha'] ),
3068 WPF()->settings->_recaptcha
3069 );
3070 $recaptcha['site_key'] = sanitize_text_field( $recaptcha['site_key'] );
3071 $recaptcha['secret_key'] = sanitize_text_field( $recaptcha['secret_key'] );
3072 wpforo_update_option( 'wpforo_recaptcha', $recaptcha );
3073 }
3074
3075 WPF()->notice->add( 'Successfully Done', 'success' );
3076 wp_safe_redirect( wp_get_raw_referer() );
3077 exit();
3078 }
3079
3080 /**
3081 * rss_settings_save from submit action
3082 *
3083 * @return void
3084 */
3085 public function rss_settings_save() {
3086 check_admin_referer( 'wpforo_settings_save_rss' );
3087
3088 if( wpfkey( $_POST, 'reset' ) ) {
3089 wpforo_delete_option( 'rss' );
3090 } else {
3091 $rss = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['rss'] ), WPF()->settings->_rss );
3092 foreach( $this->generate_option_names( 'rss' ) as $option_name ) {
3093 wpforo_update_option( $option_name, $rss );
3094 }
3095 }
3096
3097 WPF()->notice->add( 'Successfully Done', 'success' );
3098 wp_safe_redirect( wp_get_raw_referer() );
3099 exit();
3100 }
3101
3102 /**
3103 * seo_settings_save from submit action
3104 *
3105 * @return void
3106 */
3107 public function seo_settings_save() {
3108 check_admin_referer( 'wpforo_settings_save_seo' );
3109
3110 if( wpfkey( $_POST, 'reset' ) ) {
3111 wpforo_delete_option( 'seo' );
3112 } else {
3113 $seo = wp_unslash( $_POST['seo'] );
3114 $seo['dofollow'] = array_filter(
3115 preg_split( '#\s+#', sanitize_textarea_field( (string) wpfval( $seo, 'dofollow' ) ) )
3116 );
3117 $seo['noindex'] = array_filter(
3118 preg_split( '#\s+#', sanitize_textarea_field( (string) wpfval( $seo, 'noindex' ) ) )
3119 );
3120 $seo['noindex'] = array_map( 'esc_url_raw', $seo['noindex'] );
3121 $seo = wpforo_array_args_cast_and_merge( $seo, WPF()->settings->_seo );
3122 foreach( $this->generate_option_names( 'seo' ) as $option_name ) {
3123 wpforo_update_option( $option_name, $seo );
3124 }
3125 wpforo_clean_cache( 'forum-soft' );
3126 }
3127
3128 WPF()->notice->add( 'Successfully Done', 'success' );
3129 wp_safe_redirect( wp_get_raw_referer() );
3130 exit();
3131 }
3132
3133 /**
3134 * social_settings_save from submit action
3135 *
3136 * @return void
3137 */
3138 public function social_settings_save() {
3139 check_admin_referer( 'wpforo_settings_save_social' );
3140
3141 if( wpfkey( $_POST, 'reset' ) ) {
3142 wpforo_delete_option( 'social' );
3143 } else {
3144 $social = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['social'] ), WPF()->settings->_social );
3145 $social['sb'] = wpforo_array_args_cast_and_merge(
3146 (array) wpfval( $_POST['social'], 'sb' ),
3147 array_map( '__return_false', WPF()->settings->_social['sb'] )
3148 );
3149 $social['sb_location'] = wpforo_array_args_cast_and_merge(
3150 (array) wpfval( $_POST['social'], 'sb_location' ),
3151 array_map(
3152 '__return_false',
3153 WPF()->settings->_social['sb_location']
3154 )
3155 );
3156 foreach( $this->generate_option_names( 'social' ) as $option_name ) {
3157 wpforo_update_option( $option_name, $social );
3158 }
3159 }
3160
3161 WPF()->notice->add( 'Successfully Done', 'success' );
3162 wp_safe_redirect( wp_get_raw_referer() );
3163 exit();
3164 }
3165
3166 /**
3167 * styles_settings_save from submit action
3168 *
3169 * @return void
3170 */
3171 public function styles_settings_save() {
3172 check_admin_referer( 'wpforo_settings_save_styles' );
3173
3174 if( wpfkey( $_POST, 'reset' ) ) {
3175 wpforo_delete_option( 'styles_' . WPF()->tpl->theme );
3176 } else {
3177 $styles = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['styles'] ), WPF()->settings->_styles );
3178 $styles['custom_css'] = sanitize_textarea_field( $styles['custom_css'] );
3179 foreach( $this->generate_option_names( 'styles_' . WPF()->tpl->theme ) as $option_name ) {
3180 wpforo_update_option( $option_name, $styles );
3181 }
3182 }
3183
3184 WPF()->notice->add( 'Successfully Done', 'success' );
3185 wp_safe_redirect( wp_get_raw_referer() );
3186 exit();
3187 }
3188
3189 /**
3190 * tags_settings_save from submit action
3191 *
3192 * @return void
3193 */
3194 public function tags_settings_save() {
3195 check_admin_referer( 'wpforo_settings_save_tags' );
3196
3197 if( wpfkey( $_POST, 'reset' ) ) {
3198 wpforo_delete_option( 'tags' );
3199 } else {
3200 $tags = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['tags'] ), WPF()->settings->_tags );
3201 foreach( $this->generate_option_names( 'tags' ) as $option_name ) {
3202 wpforo_update_option( $option_name, $tags );
3203 }
3204 }
3205
3206 WPF()->notice->add( 'Successfully Done', 'success' );
3207 wp_safe_redirect( wp_get_raw_referer() );
3208 exit();
3209 }
3210
3211 /**
3212 * topics_settings_save from submit action
3213 *
3214 * @return void
3215 */
3216 public function topics_settings_save() {
3217 check_admin_referer( 'wpforo_settings_save_topics' );
3218
3219 if( wpfkey( $_POST, 'reset' ) ) {
3220 wpforo_delete_option( 'topics' );
3221 } else {
3222 $topics = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['topics'] ), WPF()->settings->_topics );
3223 foreach( $this->generate_option_names( 'topics' ) as $option_name ) {
3224 wpforo_update_option( $option_name, $topics );
3225 }
3226 }
3227
3228 WPF()->notice->add( 'Successfully Done', 'success' );
3229 wp_safe_redirect( wp_get_raw_referer() );
3230 exit();
3231 }
3232
3233 /**
3234 * um_settings_save from submit action
3235 *
3236 * @return void
3237 */
3238 public function um_settings_save() {
3239 check_admin_referer( 'wpforo_settings_save_um' );
3240
3241 if( wpfkey( $_POST, 'reset' ) ) {
3242 wpforo_delete_option( 'wpforo_um' );
3243 } else {
3244 $um = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['um'] ), WPF()->settings->_um );
3245 wpforo_update_option( 'wpforo_um', $um );
3246 }
3247
3248 WPF()->notice->add( 'Successfully Done', 'success' );
3249 wp_safe_redirect( wp_get_raw_referer() );
3250 exit();
3251 }
3252
3253 /**
3254 * um_settings_save from submit action
3255 *
3256 * @return void
3257 */
3258 public function legal_settings_save() {
3259 check_admin_referer( 'wpforo_settings_save_legal' );
3260
3261 if( wpfkey( $_POST, 'reset' ) ) {
3262 wpforo_delete_option( 'wpforo_legal' );
3263 } else {
3264 $legal = wpforo_array_args_cast_and_merge( wp_unslash( $_POST['legal'] ), WPF()->settings->_legal );
3265 wpforo_update_option( 'wpforo_legal', $legal );
3266 }
3267
3268 WPF()->notice->add( 'Successfully Done', 'success' );
3269 wp_safe_redirect( wp_get_raw_referer() );
3270 exit();
3271 }
3272
3273 /**
3274 * ai_settings_save from submit action
3275 *
3276 * @return void
3277 */
3278 public function ai_settings_save() {
3279 check_admin_referer( 'wpforo_settings_save_ai' );
3280
3281 if( wpfkey( $_POST, 'reset' ) ) {
3282 wpforo_delete_option( 'ai' );
3283 } else {
3284 $post_ai = wp_unslash( $_POST['ai'] );
3285 $ai = wpforo_array_args_cast_and_merge( $post_ai, WPF()->settings->_ai );
3286 // Ensure max_results is within bounds
3287 $ai['search_max_results'] = max( 1, min( 10, intval( $ai['search_max_results'] ) ) );
3288 // Fix checkbox array fields: wpforo_array_args_cast_and_merge re-adds default
3289 // values for missing numeric keys, so we must override with the actual POST data.
3290 // When all checkboxes are unchecked the key is absent from POST, meaning empty array.
3291 $ai['chatbot_allowed_groups'] = array_map( 'intval', (array) wpfval( $post_ai, 'chatbot_allowed_groups' ) );
3292 $ai['bot_reply_includes'] = array_map( 'sanitize_text_field', (array) wpfval( $post_ai, 'bot_reply_includes' ) );
3293 // Filter out Guest usergroup (groupid 4) - guests cannot use chatbot (login required)
3294 $ai['chatbot_allowed_groups'] = array_values( array_filter( $ai['chatbot_allowed_groups'], function( $gid ) {
3295 return $gid !== 4;
3296 } ) );
3297 foreach( $this->generate_option_names( 'ai' ) as $option_name ) {
3298 wpforo_update_option( $option_name, $ai );
3299 }
3300 }
3301
3302 WPF()->notice->add( 'Successfully Done', 'success' );
3303 wp_safe_redirect( wp_get_raw_referer() );
3304 exit();
3305 }
3306
3307 public function settings_export() {
3308 check_admin_referer( 'wpforo_settings_export' );
3309
3310 if( $groups = (array) wpfval( $_POST, 'groups' ) ) {
3311 WPF()->settings->export( $groups );
3312 } else {
3313 WPF()->notice->add( 'Invalid groups: One or more checkboxes must be selected.', 'error' );
3314 }
3315
3316 wp_safe_redirect( wp_get_raw_referer() );
3317 exit();
3318 }
3319
3320 public function settings_import() {
3321 check_admin_referer( 'wpforo_settings_import' );
3322
3323 if( wpfval( $_FILES, 'wpfsimpjson', 'tmp_name' ) && wpfval( $_FILES, 'wpfsimpjson', 'type' ) === 'application/json' ) {
3324 $json = file_get_contents( $_FILES['wpfsimpjson']['tmp_name'] );
3325 if( $json ) {
3326 json_decode( $json );
3327 if( json_last_error() == JSON_ERROR_NONE ) {
3328 if( ( $groups = (array) wpfval( $_POST, 'groups' ) ) ) {
3329 WPF()->settings->import( $json, $groups );
3330 WPF()->notice->add( 'Successfully Done', 'success' );
3331 wp_safe_redirect( wp_get_raw_referer() );
3332 exit();
3333 } else {
3334 WPF()->notice->add( 'Invalid groups: One or more checkboxes must be selected.', 'error' );
3335 wp_safe_redirect( wp_get_raw_referer() );
3336 exit();
3337 }
3338 }
3339 }
3340 }
3341
3342 WPF()->notice->add( 'You should choose the right JSON file.', 'error' );
3343 wp_safe_redirect( wp_get_raw_referer() );
3344 exit();
3345 }
3346
3347 /**
3348 * @return array with all boardids where need to save options
3349 */
3350 private function get_boardids_to_be_saved() {
3351 $boardids = (array) WPF()->board->get_current( 'boardid' );
3352 if( wpfkey( $_POST, 'save_for_all' ) ) {
3353 $boardids = array_unique( array_merge( $boardids, WPF()->board->get_active_boardids() ) );
3354 }
3355
3356 return $boardids;
3357 }
3358
3359 /**
3360 * @param string $basename
3361 *
3362 * @return string[]
3363 */
3364 public function generate_option_names( $basename ) {
3365 return array_map(
3366 function( $boardid ) use ( $basename ) {
3367 return 'wpforo_' . ( $boardid ? $boardid . '_' : '' ) . $basename;
3368 },
3369 $this->get_boardids_to_be_saved()
3370 );
3371 }
3372
3373 /**
3374 * uninstall all wpforo
3375 */
3376 public function uninstall() {
3377 check_admin_referer( 'wpforo_uninstall' );
3378 if( current_user_can( 'administrator' ) && current_user_can( 'activate_plugins' ) ) {
3379 wpforo_uninstall();
3380 }
3381 wp_safe_redirect( wp_get_referer() );
3382 exit();
3383 }
3384
3385 /**
3386 * Store checkout mapping for Freemius webhook lookup
3387 *
3388 * This is primarily a validation step before opening checkout.
3389 * The actual tenant lookup in the webhook will be done by matching
3390 * the WordPress site URL from the Freemius install object.
3391 */
3392 public function ai_store_checkout_mapping() {
3393 // Verify nonce
3394 check_ajax_referer( 'wpforo_ai_features_nonce', 'nonce' );
3395
3396 // Check permissions
3397 if ( ! wpforo_current_user_is( 'admin' ) && ! WPF()->usergroup->can( 'ms' ) ) {
3398 wp_send_json_error( [ 'message' => 'Insufficient permissions' ], 403 );
3399 }
3400
3401 // Get parameters
3402 $email = isset( $_POST['email'] ) ? sanitize_email( $_POST['email'] ) : '';
3403 $tenant_id = isset( $_POST['tenant_id'] ) ? sanitize_text_field( $_POST['tenant_id'] ) : '';
3404
3405 if ( empty( $email ) || empty( $tenant_id ) ) {
3406 wp_send_json_error( [ 'message' => 'Email and tenant_id are required' ], 400 );
3407 }
3408
3409 // The webhook will look up tenant_id by matching the WordPress site URL
3410 // No need to store mapping here - just validate and proceed
3411 wp_send_json_success( [
3412 'message' => 'Checkout ready',
3413 'email' => $email,
3414 'tenant_id' => $tenant_id,
3415 'site_url' => home_url()
3416 ] );
3417 }
3418
3419 /**
3420 * AJAX handler for loading legal documents (Terms of Service, Privacy Policy)
3421 * Used by the AI Features settings page modal
3422 */
3423 public function ai_get_legal_document() {
3424 // Verify nonce
3425 check_ajax_referer( 'wpforo_ai_features_nonce', 'nonce' );
3426
3427 // Check permissions - admin only
3428 if ( ! wpforo_current_user_is( 'admin' ) && ! WPF()->usergroup->can( 'ms' ) ) {
3429 wp_send_json_error( [ 'message' => 'Insufficient permissions' ], 403 );
3430 }
3431
3432 // Get document type
3433 $document = isset( $_POST['document'] ) ? sanitize_text_field( $_POST['document'] ) : '';
3434
3435 // Map document type to file
3436 $document_files = [
3437 'terms' => 'terms-of-service.php',
3438 'privacy' => 'privacy-policy.php',
3439 ];
3440
3441 if ( empty( $document ) || ! isset( $document_files[ $document ] ) ) {
3442 wp_send_json_error( [ 'message' => 'Invalid document type' ], 400 );
3443 }
3444
3445 // Build file path
3446 $file_path = WPFORO_DIR . '/admin/pages/legal/' . $document_files[ $document ];
3447
3448 if ( ! file_exists( $file_path ) ) {
3449 wp_send_json_error( [ 'message' => 'Document not found' ], 404 );
3450 }
3451
3452 // Capture the output of the PHP file
3453 ob_start();
3454 include $file_path;
3455 $content = ob_get_clean();
3456
3457 wp_send_json_success( [
3458 'content' => $content,
3459 'title' => $document === 'terms' ? __( 'Terms of Service', 'wpforo' ) : __( 'Privacy Policy', 'wpforo' ),
3460 ] );
3461 }
3462 }
3463