PluginProbe
wpForo Forum / 3.0.7
wpForo Forum v3.0.7
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 / includes / hooks.php

hooks.php in wpForo Forum 3.0.7, at includes/hooks.php

3,700 lines 136.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Exit if accessed directly
3 if( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 add_filter( 'plugin_action_links_' . WPFORO_BASENAME, function( $links ) {
8 $uninstall_url = wp_nonce_url( admin_url( 'plugins.php?wpfaction=uninstall' ), 'wpforo_uninstall' );
9 $links[] = '<a href="' . esc_url(
10 (string) $uninstall_url
11 ) . '" class="wpforo-uninstall" style="color:#a00;" onclick="return confirm(\'' . __(
12 'IMPORTANT! Uninstall is not a simple deactivation action. This action will permanently remove all forum data (forums, topics, replies, attachments...) from database. Please backup database before this action, you may need this forum data in future. If you are sure that you want to delete all forum data please confirm. If not, just cancel it, then you can deactivate this plugin, that will not remove forum data.',
13 'wpforo'
14 ) . '\')">' . __( 'Uninstall', 'wpforo' ) . '</a>';
15 $settings_link = '<a href="' . esc_url( (string) admin_url( 'admin.php?page=wpforo-boards' ) ) . '">' . __(
16 'Boards',
17 'wpforo'
18 ) . '</a>';
19 array_unshift( $links, $settings_link );
20
21 return $links;
22 } );
23
24 function wpforo_notice_show() {
25 WPF()->notice->show();
26 }
27
28 add_action( 'wp_footer', 'wpforo_notice_show' );
29
30 add_action( 'show_admin_bar', function( $show_admin_bar ) {
31 if( ! is_super_admin() && is_user_logged_in() && WPF()->wp_current_user && ! array_intersect(
32 [ 'editor', 'administrator', 'author', ],
33 (array) WPF()->wp_current_user->roles
34 ) ) {
35 $show_admin_bar = (bool) array_intersect(
36 (array) WPF()->current_user_groupids,
37 (array) wpforo_setting( 'general', 'admin_bar' )
38 );
39 }
40
41 return $show_admin_bar;
42 } );
43
44 add_action( 'admin_notices', function() {
45 if( strpos( wpforo_get_request_uri(), 'nav-menus.php' ) !== false ) {
46 $message = '';
47 foreach(
48 WPF()->tpl->menu as $key => $value
49 ) {
50 $message .= "<tr><td> " . $value['label'] . ": </td><td> /%$key%/ </td></tr>";
51 }
52 $message .= "<tr><td> " . wpforo_phrase( 'register', false ) . ": </td><td> /%wpforo-register%/ </td></tr>
53 <tr><td> " . wpforo_phrase( 'login', false ) . ": </td><td> /%wpforo-login%/ </td></tr>";
54 printf(
55 '<div class="notice notice-warning wpforo-menu-shortcodes">
56 <p class="wpforo-menu-shortcodes-head" style="cursor: pointer;">wpForo Menu Shortcodes hint <span class="dashicons dashicons-arrow-down-alt2"></span></p>
57 <div class="wpforo-menu-shortcodes-body" style="display: none;">
58 <hr/><table>%1$s</table>
59 </div>
60 </div>',
61 $message
62 );
63 ?>
64 <script>
65 jQuery(document).ready(function ($) {
66 $('body').on('click', '.wpforo-menu-shortcodes .wpforo-menu-shortcodes-head', {}, function () {
67 var $this = $(this);
68 var wrap = $this.closest('.wpforo-menu-shortcodes');
69 var body = $('.wpforo-menu-shortcodes-body', wrap);
70 body.toggle();
71 });
72 });
73 </script>
74 <?php
75 }
76 } );
77
78 add_filter( 'comments_open', function( $open ) {
79 if( is_wpforo_page() ) $open = false;
80
81 return $open;
82 } );
83
84 add_filter( 'comments_array', function( $comments ) {
85 if( is_wpforo_page() ) $comments = [];
86
87 return $comments;
88 }, 10, 2 );
89
90 add_action( 'wpforo_actions_end', function() {
91 if( is_wpforo_page() ) {
92 remove_post_type_support( 'post', 'comments' );
93 remove_post_type_support( 'page', 'comments' );
94 }
95 }, 100 );
96
97 add_action( 'wpforo_actions_end', function() {
98 if( ! WPF()->board->get_current( 'is_standalone' ) && ! is_front_page() && ! is_home() && is_wpforo_url() ) {
99 global $wp_query, $post;
100 $pageid = WPF()->board->get_current( 'pageid' );
101 if( is_a( $post, 'WP_Post' ) && $post->ID !== $pageid ) {
102 $args = [
103 'post_count' => 1,
104 'found_posts' => 1,
105 'max_num_pages' => 0,
106 'is_404' => false,
107 'is_page' => true,
108 'is_singular' => true,
109 ];
110
111 $target_post = get_post( $pageid );
112 if( ! is_a( $target_post, 'WP_Post' ) ) {
113 return;
114 }
115
116 $post = $target_post;
117
118 $wp_query->posts = [ $post ];
119 $wp_query->queried_object_id = $post->ID;
120 $wp_query->queried_object = $post;
121
122 foreach( $args as $key => $value ) {
123 $wp_query->$key = $value;
124 }
125
126 setup_postdata( $post );
127 }
128 }
129 } );
130
131 add_filter( 'author_link', function( $link, $author_id ) {
132 if( wpforo_setting( 'profiles', 'profile' ) === 'wpforo' ) return WPF()->member->get_profile_url( $author_id );
133
134 return $link;
135 }, 10, 2 );
136
137 add_filter( 'get_comment_author_url', function( $link, $ID = 0, $object = null ) {
138 if( isset( $object->user_id ) && $object->user_id && wpforo_setting(
139 'profiles',
140 'profile'
141 ) === 'wpforo' ) {
142 return WPF()->member->get_profile_url(
143 $object->user_id
144 );
145 }
146
147 return $link;
148 }, 10, 3 );
149
150 add_filter( 'register_url', function( $register_url ) {
151 if( wpforo_setting( 'authorization', 'use_our_register_url' ) ) $register_url = wpforo_register_url();
152
153 return $register_url;
154 } );
155
156 add_filter( 'login_url', function( $login_url ) {
157 if( wpforo_setting( 'authorization', 'use_our_login_url' ) && strpos(
158 (string) $_SERVER['REQUEST_URI'],
159 '/wp-json/'
160 ) !== 0 && strpos(
161 (string) wp_debug_backtrace_summary(),
162 'wp_auth_check_html, wp_login_url,'
163 ) === false ) {
164 $login_url = wpforo_login_url();
165 }
166
167 return $login_url;
168 } );
169
170 add_filter( 'logout_url', function( $logout_url ) {
171 if( wpforo_setting( 'authorization', 'use_our_login_url' ) ) $logout_url = wpforo_logout_url();
172
173 return $logout_url;
174 } );
175
176 add_filter( 'pre_trash_post', function( $check, $post ) {
177 if( in_array( $post->ID, WPF()->board->get_boards_pageids(), true ) ) {
178 $check = false;
179 WPF()->notice->add( 'DO NOT DELETE WPFORO PAGE!!!', 'error' );
180 }
181
182 return $check;
183 }, 10, 2 );
184
185 add_filter( 'wp_dropdown_pages', function( $output, $r ) {
186 $pageids = WPF()->board->get_boards_pageids();
187 if( $r['name'] === 'page_for_posts' || ( $r['name'] === 'page_on_front' && wpforo_get_shortcode_pageid(
188 $pageids
189 ) ) ) {
190 $pattern = '#[\r\n\t\s]*<option[^<>]*?value=[\'"](' . implode(
191 '|',
192 $pageids
193 ) . ')[\'"][^<>]*?>[^<>]*?</option>#isu';
194 $output = preg_replace( $pattern, '', (string) $output );
195 }
196
197 return $output;
198 }, 10, 2 );
199
200 add_filter( 'pre_update_option', function( $value, $option, $old_value ) {
201 if( $option === 'page_on_front' ) {
202 $pageids = WPF()->board->get_boards_pageids();
203 if( in_array( wpforo_bigintval( $value ), $pageids, true ) ) {
204 if( ! $page_id = wpforo_get_shortcode_pageid( $pageids ) ) {
205 $page_id = wp_insert_post(
206 [
207 'post_date' => current_time( 'mysql', 1 ),
208 'post_date_gmt' => current_time( 'mysql', 1 ),
209 'post_content' => '[wpforo]',
210 'post_title' => 'Forum page_on_front',
211 'post_status' => 'publish',
212 'comment_status' => 'close',
213 'ping_status' => 'close',
214 'post_name' => 'front-community',
215 'post_modified' => current_time( 'mysql', 1 ),
216 'post_modified_gmt' => current_time( 'mysql', 1 ),
217 'post_parent' => 0,
218 'menu_order' => 0,
219 'post_type' => 'page',
220 ]
221 );
222 }
223 $value = ( $page_id && ! is_wp_error( $page_id ) ? $page_id : $old_value );
224 }
225 }
226
227 return $value;
228 }, 10, 3 );
229
230 function wpftpl_url( $filename ) {
231 $tpl_url = '';
232 if( $filename ) {
233 if( $tpl_url = locate_template( 'wpforo/' . $filename ) ) {
234 $tpl_url = get_template_directory_uri() . '/wpforo/' . $filename;
235 }
236 if( ! $tpl_url ) $tpl_url = WPF()->tpl->template_url . '/' . $filename;
237 }
238
239 return apply_filters( 'wpforo_wpftpl_url', $tpl_url, $filename );
240 }
241
242 function wpftpl( $filename ) {
243 $tpl = '';
244 if( $filename ) {
245 $tpl = locate_template( 'wpforo/' . $filename );
246 if( ! $tpl ) $tpl = WPF()->tpl->template_dir . '/' . $filename;
247 }
248
249 return apply_filters( 'wpforo_wpftpl', $tpl, $filename );
250 }
251
252 add_shortcode( 'wpforo', function( $atts ) {
253 wpforo_include_once_theme_functions();
254 if( defined( 'REST_REQUEST' ) && REST_REQUEST ) return '';
255 if( ! is_wpforo_url() ) {
256 if( ! $atts ) $atts = [ 'item' => 'forum' ];
257 WPF()->init_current_url( $atts );
258 WPF()->init_current_object();
259 wpforo_frontend_enqueue_scripts();
260 }
261 if( apply_filters( 'on_wpforo_load_remove_the_content_all_filters', false ) ) {
262 remove_all_filters( 'the_content' );
263 }
264
265 ob_start();
266 if( wpforo_current_user_is( 'admin' ) || ! wpforo_setting( 'board', 'under_construction' ) ) {
267 include( wpftpl( 'index.php' ) );
268 } else {
269 include( wpftpl( 'uc.php' ) );
270 }
271 $output = ob_get_clean();
272 $output = trim( (string) $output );
273 if( ! $output ) $output = wpforo_hook_usage( 'the_content' );
274
275 return $output;
276 } );
277
278 function wpforo_hook_usage( $hook = '' ) {
279 global $wp_filter;
280
281 $output = '<div style="color: #990000; font-size: 16px;">Notice: a plugin conflict has been detected. wpForo forums are affected by other plugin errors.
282 Please deactivate all plugins, delete all caches and test again.
283 Then activate all plugins back one by one and find the conflict maker plugin.</div>
284 <pre style="display: none;">' . ( empty( $hook ) || ! isset( $wp_filter[ $hook ] ) ? 'No hook usage' : print_r(
285 $wp_filter[ $hook ],
286 true
287 ) ) . '</pre>';
288
289 return $output;
290 }
291
292 add_action( 'wpforo_actions_end', 'wpforo_set_header_status' );
293 function wpforo_set_header_status() {
294 if( is_wpforo_page() ) {
295 global $wp_query;
296
297 $status = ( WPF()->current_object['is_404'] ? 404 : 200 );
298 status_header( $status );
299 if( $status === 404 ) nocache_headers();
300 $wp_query->is_404 = false;
301 }
302 }
303
304 add_filter( 'pre_handle_404', function( $bypass ) {
305 if( is_wpforo_page() ) return true;
306
307 return $bypass;
308 } );
309
310 add_action( 'wpforo_actions_end', function() {
311 if( is_wpforo_page() && WPF()->board->get_current( 'is_standalone' ) ) {
312 add_rewrite_rule( '(.*)', 'index.php?page_id=' . WPF()->board->get_current( 'pageid' ), 'top' );
313 add_filter( 'template_include', function( $template ) {
314 if( is_wpforo_page() && ! is_wpforo_shortcode_page() && ( $wpforo_template = wpftpl(
315 'index.php'
316 ) ) ) {
317 return $wpforo_template;
318 }
319
320 return $template;
321 } );
322 }
323 } );
324
325 add_filter( 'rewrite_rules_array', function( $rules ) {
326 $rewrite_prefix = '(?:([a-z]{2,3})/)?';
327 if( function_exists( 'pll_languages_list' ) ) {
328 $rewrite_prefix = '(?:(' . implode(
329 '|',
330 pll_languages_list()
331 ) . ')/)?';
332 }
333
334 if( ! WPF()->board->get_current( 'is_standalone' ) ) {
335 $pageid = 0;
336 $boards = WPF()->board->get_boards( [ 'status' => true ] );
337 foreach( $boards as $board ) {
338 if( $board['boardid'] === 0 ) $pageid = $board['pageid'];
339 $route = urldecode( (string) $board['slug'] );
340 $route = preg_replace( '#^/?index\.php/?#iu', '', $route );
341 $route = trim( (string) $route, '/' );
342 $pattern = $rewrite_prefix . preg_quote( $route ) . '(?:/|$).*$';
343 $to_url = 'index.php?lang=$matches[1]&page_id=' . $board['pageid'];
344 if( ! array_key_exists( $pattern, $rules ) ) $rules = array_merge( [ $pattern => $to_url ], $rules );
345 }
346
347 if( ! $pageid ) $pageid = wpforo_get_option( 'wpforo_pageid', 0 );
348 foreach( WPF()->board->routes as $route ) {
349 // $route = utf8_uri_encode( urldecode( (string) $route ) );
350 $route = urldecode( (string) $route );
351 $route = preg_replace( '#^/?index\.php/?#isu', '', $route );
352 $route = trim( (string) $route, '/' );
353 $pattern = $rewrite_prefix . preg_quote( $route ) . '(?:/|$).*$';
354 $to_url = 'index.php?lang=$matches[1]&page_id=' . $pageid;
355 if( ! array_key_exists( $pattern, $rules ) ) $rules = array_merge( [ $pattern => $to_url ], $rules );
356 }
357 }
358
359 return $rules;
360 } );
361
362 add_action( 'wpforo_actions_end', function() {
363 $pageid = WPF()->board->get_current( 'pageid' );
364 if( is_wpforo_url() && $pageid && WPF()->board->route && get_the_ID() !== $pageid ) {
365 wpforo_repair_main_shortcode_page();
366 }
367 } );
368
369
370 function wpforo_include_once_theme_functions() {
371 $path = wpftpl( 'functions.php' );
372 if( file_exists( $path ) ) include_once( $path );
373
374 $path = wpftpl( 'functions-wp.php' );
375 if( file_exists( $path ) ) include_once( $path );
376 }
377
378 add_action( 'wpforo_after_init', 'wpforo_include_once_theme_functions' );
379
380 function wpforo_meta_title( $title ) {
381 $meta_title = [];
382
383 if( ! wpforo_setting( 'seo', 'seo_title' ) ) return $title;
384
385 if( is_wpforo_page() ) {
386 $template = WPF()->current_object['template'];
387 if( ! WPF()->current_object['is_404'] ) {
388 $paged = ( WPF()->current_object['paged'] > 1 ) ? wpforo_phrase( 'page', false ) . ' ' . WPF()->current_object['paged'] . ' ' : '';
389 if( ! empty( WPF()->current_object['forum'] ) ) {
390 $forum = WPF()->current_object['forum'];
391 }
392 if( ! empty( WPF()->current_object['topic'] ) ) {
393 $topic = WPF()->current_object['topic'];
394 }
395 if( ! empty( WPF()->current_object['user'] ) ) {
396 $user = WPF()->current_object['user'];
397 }
398 if( isset( $topic['title'] ) && isset( $forum['title'] ) && isset(
399 WPF()->board->get_current(
400 'settings'
401 )['title']
402 ) ) {
403 $meta_title = [
404 $topic['title'],
405 $paged,
406 $forum['title'],
407 WPF()->board->get_current( 'settings' )['title'],
408 ];
409 $meta_title = apply_filters( 'wpforo_seo_topic_title', $meta_title );
410 } elseif( ! isset( $topic['title'] ) && isset( $forum['title'] ) && isset(
411 WPF()->board->get_current(
412 'settings'
413 )['title']
414 ) ) {
415 $meta_title = [ $forum['title'], $paged, WPF()->board->get_current( 'settings' )['title'] ];
416 $meta_title = apply_filters( 'wpforo_seo_forum_title', $meta_title );
417 } elseif( ! in_array( $template, [ 'forum', 'topic', 'post' ], true ) ) {
418 if( wpforo_is_member_template( $template ) ) {
419 if( isset( $user['display_name'] ) ) {
420 $meta_title = [
421 $user['display_name'],
422 wpforo_phrase( ucfirst( (string) $template ), false ),
423 WPF()->board->get_current( 'settings' )['title'],
424 $paged,
425 ];
426 } elseif( isset( WPF()->current_object['user_nicename'] ) ) {
427 $meta_title = [
428 WPF()->current_object['user_nicename'],
429 wpforo_phrase( ucfirst( (string) $template ), false ),
430 WPF()->board->get_current( 'settings' )['title'],
431 $paged,
432 ];
433 } else {
434 $meta_title = [
435 wpforo_phrase( 'Member', false ),
436 wpforo_phrase( ucfirst( (string) $template ), false ),
437 WPF()->board->get_current( 'settings' )['title'],
438 $paged,
439 ];
440 }
441 $meta_title = apply_filters( 'wpforo_seo_profile_title', $meta_title );
442 } elseif( $template === 'recent' ) {
443 $wpfpaged = ( isset( $_GET['wpfpaged'] ) && $_GET['wpfpaged'] > 1 ) ? ' - ' . wpforo_phrase(
444 'page',
445 false
446 ) . ' ' . $_GET['wpfpaged'] . ' ' : '';
447 $view = wpfval( $_GET, 'view' );
448 if( $view == 'unread' ) {
449 $main_title = wpforo_phrase( 'Unread Posts', false );
450 } elseif( $view == 'prefix' ) {
451 $main_title = wpforo_phrase( 'Topic Prefix', false );
452 } else {
453 $main_title = wpforo_phrase( 'Recent Posts', false );
454 }
455 $meta_title = [ $main_title . $wpfpaged, WPF()->board->get_current( 'settings' )['title'] ];
456 $meta_title = apply_filters( 'wpforo_seo_recent_posts_title', $meta_title );
457 } elseif( $template === 'tags' ) {
458 $wpfpaged = ( isset( $_GET['wpfpaged'] ) && $_GET['wpfpaged'] > 1 ) ? ' - ' . wpforo_phrase(
459 'page',
460 false
461 ) . ' ' . $_GET['wpfpaged'] . ' ' : '';
462 $meta_title = [
463 wpforo_phrase( 'Tags', false ) . $wpfpaged,
464 WPF()->board->get_current( 'settings' )['title'],
465 ];
466 $meta_title = apply_filters( 'wpforo_seo_tags_title', $meta_title );
467 } elseif( $template === 'search' && wpfval( $_GET, 'wpfin' ) && wpfval(
468 $_GET,
469 'wpfs'
470 ) && $_GET['wpfin'] === 'tag' ) {
471 $wpfpaged = ( isset( $_GET['wpfpaged'] ) && $_GET['wpfpaged'] > 1 ) ? ' - ' . wpforo_phrase(
472 'page',
473 false
474 ) . ' ' . $_GET['wpfpaged'] . ' ' : '';
475 $meta_title = [
476 wpforo_phrase( 'Topic Tag:', false ) . ' ' . esc_html( $_GET['wpfs'] ),
477 $wpfpaged,
478 WPF()->board->get_current( 'settings' )['title'],
479 ];
480 $meta_title = apply_filters( 'wpforo_seo_tag_title', $meta_title );
481 } elseif( $template ) {
482 $wpfpaged = ( isset( $_GET['wpfpaged'] ) && $_GET['wpfpaged'] > 1 ) ? ' - ' . wpforo_phrase(
483 'page',
484 false
485 ) . ' ' . $_GET['wpfpaged'] . ' ' : '';
486 $meta_title = [
487 wpforo_phrase( ucfirst( (string) $template ), false ) . $wpfpaged,
488 WPF()->board->get_current( 'settings' )['title'],
489 ];
490 $meta_title = apply_filters( 'wpforo_seo_template_title', $meta_title );
491 } elseif( $title ) {
492 $meta_title = ( is_array( $title ) ) ? $title : [ $title ];
493 $meta_title = apply_filters( 'wpforo_seo_x_title', $meta_title );
494 } else {
495 $meta_title = [ wpforo_phrase( 'Forum', false ), get_bloginfo( 'name' ) ];
496 $meta_title = apply_filters( 'wpforo_seo_general_title', $meta_title );
497 }
498 } elseif( isset( WPF()->board->get_current( 'settings' )['title'] ) && WPF()->board->get_current(
499 'settings'
500 )['title'] ) {
501 $meta_title = [ WPF()->board->get_current( 'settings' )['title'], get_bloginfo( 'name' ) ];
502 $meta_title = apply_filters( 'wpforo_seo_main_title', $meta_title );
503 } elseif( $title ) {
504 $meta_title = ( is_array( $title ) ) ? $title : [ $title ];
505 $meta_title = apply_filters( 'wpforo_seo_x_title', $meta_title );
506 } else {
507 $meta_title = [ wpforo_phrase( 'Forum', false ), get_bloginfo( 'name' ) ];
508 $meta_title = apply_filters( 'wpforo_seo_general_title', $meta_title );
509 }
510 } else {
511 $meta_title = [
512 wpforo_phrase( '404 - Page not found', false ),
513 WPF()->board->get_current( 'settings' )['title'],
514 ];
515 $meta_title = apply_filters( 'wpforo_seo_404_title', $meta_title );
516 }
517 }
518 if( ! empty( $meta_title ) ) {
519 return $meta_title;
520 } else {
521 return $title;
522 }
523 }
524
525 add_filter( 'document_title_parts', 'wpforo_meta_title', 100 );
526
527 function wpforo_meta_wp_title( $title ) {
528 if( ! wpforo_setting( 'seo', 'seo_title' ) ) return $title;
529 $meta_title = wpforo_meta_title( $title );
530 if( is_array( $meta_title ) && ! empty( $meta_title ) ) {
531 $title = implode( ' &#8211; ', $meta_title );
532 }
533
534 return $title;
535 }
536
537 add_filter( 'wp_title', 'wpforo_meta_wp_title', 100 );
538
539 function wpforo_add_meta_tags() {
540 if( ! wpforo_setting( 'seo', 'seo_meta' ) ) {
541 return;
542 }
543
544 if( is_wpforo_page() && ! is_wpforo_shortcode_page() ) {
545 $title = '';
546 $og_img = '';
547 $tw_img = '';
548 $schema = '';
549 $noindex = '';
550 $template = '';
551 $description = '';
552 $udata = [];
553 if( preg_match( '#\?.*$#is', (string) WPF()->canonical_url, $requests ) ) {
554 if( strpos( (string) $requests[0], 'orderby' ) !== false ) {
555 $canonical = preg_replace( '#\?.*$#is', '', (string) WPF()->canonical_url );
556 } else {
557 $canonical = wpforo_home_url( $requests[0] );
558 }
559 } else {
560 $canonical = WPF()->canonical_url;
561 }
562 $noindex_urls = wpforo_setting( 'seo', 'noindex' );
563 $image = '';
564 foreach( $noindex_urls as $noindex_url ) {
565 $noindex_url = strtok( $noindex_url, "#" );
566 if( strpos( (string) $noindex_url, '*' ) !== false ) {
567 $noindex_url = strtok( $noindex_url, "*" );
568 if( preg_match( '|^' . preg_quote( $noindex_url ) . '|is', (string) $canonical ) ) {
569 $noindex = "<meta name=\"robots\" content=\"noindex\">\r\n";
570 break;
571 }
572 } elseif( $canonical == $noindex_url ) {
573 $noindex = "<meta name=\"robots\" content=\"noindex\">\r\n";
574 break;
575 }
576 }
577 $paged = ( WPF()->current_object['paged'] > 1 ) ? wpforo_phrase( 'page', false ) . ' ' . WPF()->current_object['paged'] . ' | ' : '';
578 if( isset( WPF()->current_object['template'] ) ) {
579 $template = WPF()->current_object['template'];
580 }
581 if( ! empty( WPF()->current_object['forum'] ) ) {
582 $forum = WPF()->current_object['forum'];
583 }
584 if( ! empty( WPF()->current_object['topic'] ) ) {
585 $topic = WPF()->current_object['topic'];
586 }
587 if( ! empty( WPF()->current_object['user'] ) ) {
588 $user = WPF()->current_object['user'];
589 }
590 if( isset( WPF()->current_object ) ) {
591 if( wpfval( WPF()->current_object, 'forumid' ) && ! wpfval( WPF()->current_object, 'topicid' ) ) {
592 if( isset( $forum['title'] ) ) {
593 $title = $forum['title'];
594 }
595 if( isset( WPF()->current_object['forum_meta_desc'] ) && WPF()->current_object['forum_meta_desc'] != '' ) {
596 $description = $paged . WPF()->current_object['forum_meta_desc'];
597 } elseif( isset( WPF()->current_object['forum_desc'] ) && WPF()->current_object['forum_desc'] != '' ) {
598 $description = $paged . WPF()->current_object['forum_desc'];
599 }
600 } elseif( isset( WPF()->current_object['topicid'] ) && isset( $topic['first_postid'] ) ) {
601 $post = WPF()->post->get_post( $topic['first_postid'] );
602 $content = wpforo_content( $post, false );
603 $image = wpforo_find_image_urls( $content, true, 'og:image' );
604 if( isset( $post['title'] ) ) {
605 $title = wpforo_text( $paged . $post['title'], 60, false );
606 }
607 if( isset( $post['body'] ) ) {
608 $description = wpforo_text( $paged . $post['body'], 150, false );
609 }
610 if( isset( $post['body'] ) ) {
611 $schema = wpforo_schema( $forum, $topic, $post );
612 }
613 } elseif( wpforo_is_member_template( $template ) ) {
614 if( isset( WPF()->board->get_current( 'settings' )['title'] ) ) {
615 $title = $paged . WPF()->board->get_current( 'settings' )['title'];
616 }
617 $udata['name'] = ( isset( $user['display_name'] ) && $user['display_name'] ) ? wpforo_phrase(
618 'User',
619 false
620 ) . ': ' . $user['display_name'] : '';
621 $udata['title'] = ( isset( $user['rating']['title'] ) && $user['rating']['title'] ) ? wpforo_phrase(
622 'Title',
623 false
624 ) . ': ' . $user['rating']['title'] : '';
625 $udata['about'] = ( isset( $user['about'] ) && $user['about'] ) ? wpforo_phrase(
626 'About',
627 false
628 ) . ': ' . wpforo_text(
629 $user['about'],
630 150,
631 false
632 ) : '';
633 $description = $title . ' - ' . wpforo_phrase( 'Member Profile', false ) . ' &gt; ' . wpforo_phrase(
634 ucfirst( (string) $template ),
635 false
636 ) . ' ' . wpforo_phrase( 'Page', false ) . '. ' . implode( ', ', $udata );
637 if( ! wpforo_setting( 'seo', 'seo_profile' ) ) {
638 $noindex = "<meta name=\"robots\" content=\"noindex\">\r\n";
639 }
640 } elseif( isset( WPF()->current_object['template'] ) && WPF()->current_object['template'] === 'member' ) {
641 $wpfpaged = ( isset( $_GET['wpfpaged'] ) && $_GET['wpfpaged'] > 1 ) ? wpforo_phrase(
642 'Page',
643 false
644 ) . ' ' . $_GET['wpfpaged'] . ' | ' : '';
645 $description = $wpfpaged . wpforo_phrase( 'Forum Members List', false );
646 } elseif( isset( WPF()->current_object['template'] ) && WPF()->current_object['template'] === 'recent' ) {
647 $wpfpaged = ( isset( $_GET['wpfpaged'] ) && $_GET['wpfpaged'] > 1 ) ? wpforo_phrase(
648 'Page',
649 false
650 ) . ' ' . $_GET['wpfpaged'] . ' | ' : '';
651 $description = $wpfpaged . wpforo_phrase( 'Recent Posts', false );
652 } elseif( isset( WPF()->current_object['template'] ) && WPF()->current_object['template'] === 'tags' ) {
653 $wpfpaged = ( isset( $_GET['wpfpaged'] ) && $_GET['wpfpaged'] > 1 ) ? wpforo_phrase(
654 'Page',
655 false
656 ) . ' ' . $_GET['wpfpaged'] . ' | ' : '';
657 $description = $wpfpaged . wpforo_phrase( 'Tags', false );
658 } else {
659 if( isset( WPF()->board->get_current( 'settings' )['title'] ) ) {
660 $title = $paged . WPF()->board->get_current( 'settings' )['title'];
661 }
662 if( isset( WPF()->board->get_current( 'settings' )['desc'] ) ) {
663 $description = $paged . WPF()->board->get_current( 'settings' )['desc'];
664 }
665 if( isset( WPF()->current_object['template'] ) && ( WPF()->current_object['template'] == 'login' || WPF()->current_object['template'] == 'register' ) ) {
666 $noindex = "<meta name=\"robots\" content=\"noindex\">\r\n";
667 }
668 }
669 $description = strip_tags( str_replace( '>', '> ', $description ) );
670 $description = preg_replace( '#[\t\r\n]+#iu', ' ', $description );
671 if( $image ) {
672 $og_img = '<meta property="og:image" content="' . $image . '" />' . "\r\n";
673 $tw_img = '<meta property="twitter:image" content="' . $image . '" />' . "\r\n";
674 }
675 $meta_tags = "\r\n<!-- wpForo SEO -->\r\n" . $noindex . "<link rel=\"canonical\" href=\"" . $canonical . "\" />\r\n<meta name=\"description\" content=\"" . esc_html(
676 $description
677 ) . "\" />\r\n<meta property=\"og:title\" content=\"" . esc_html(
678 $title
679 ) . "\" />\r\n<meta property=\"og:description\" content=\"" . esc_html(
680 $description
681 ) . "\" />\r\n<meta property=\"og:url\" content=\"" . $canonical . "\" />\r\n<meta property=\"og:locale\" content=\"" . WPF(
682 )->locale . "\" />\r\n" . $og_img . "<meta property=\"og:site_name\" content=\"" . get_bloginfo(
683 'name'
684 ) . "\" />\r\n<meta property=\"og:type\" content=\"website\" />\r\n<meta name=\"twitter:description\" content=\"" . esc_html(
685 $description
686 ) . "\"/>\r\n<meta name=\"twitter:title\" content=\"" . esc_html(
687 $title
688 ) . "\" />\r\n<meta property=\"twitter:card\" content=\"summary_large_image\" />\r\n" . $tw_img . "<!-- wpForo SEO End -->\r\n\r\n";
689 $schema = "<!-- wpForo Schema -->" . $schema . "\r\n<!-- wpForo Schema End -->\r\n\r\n";
690 echo apply_filters( 'wpforo_seo_meta_tags', $meta_tags . $schema );
691 }
692 }
693 }
694
695 add_action( 'wp_head', 'wpforo_add_meta_tags', 1 );
696
697 add_action( 'wp_ajax_wpforo_answer_ajax', 'wpf_answer' );
698 function wpf_answer() {
699 wpforo_verify_nonce( 'wpforo_answer_ajax' );
700 $response = [ 'notice' => WPF()->notice->get_notices() ];
701 if( ! is_user_logged_in() ) {
702 WPF()->notice->add( wpforo_get_login_or_register_notice_text() );
703 $response['notice'] = WPF()->notice->get_notices();
704 wp_send_json_error( $response );
705 }
706 if( ! isset( $_POST['answerstatus'] ) || ! isset( $_POST['postid'] ) || ! $postid = intval( $_POST['postid'] ) ) {
707 WPF()->notice->add( 'action error', 'error' );
708 $response['notice'] = WPF()->notice->get_notices();
709 wp_send_json_error( $response );
710 }
711 if( ! $post = WPF()->post->get_post( $postid ) ) {
712 WPF()->notice->add( 'post not found', 'error' );
713 $response['notice'] = WPF()->notice->get_notices();
714 wp_send_json_error( $response );
715 }
716 if( ! $topic = WPF()->topic->get_topic( $post['topicid'] ) ) {
717 WPF()->notice->add( 'topic not found', 'error' );
718 $response['notice'] = WPF()->notice->get_notices();
719 wp_send_json_error( $response );
720 }
721 if( ! ( WPF()->perm->forum_can( 'at', $post['forumid'] ) || ( WPF()->perm->forum_can(
722 'oat',
723 $post['forumid']
724 ) && WPF()->current_userid == $topic['userid'] ) ) ) {
725 WPF()->notice->add( 'You don\'t have permission to make topic answered', 'error' );
726 $response['notice'] = WPF()->notice->get_notices();
727 wp_send_json_error( $response );
728 }
729 if( intval( $_POST['answerstatus'] ) && WPF()->topic->has_is_answer_post( $topic['topicid'] ) ) {
730 WPF()->notice->add( 'You don\'t have permission to make two best answers for one topic', 'error' );
731 $response['notice'] = WPF()->notice->get_notices();
732 wp_send_json_error( $response );
733 }
734 if( false !== WPF()->db->query(
735 "UPDATE " . WPF()->tables->posts . " SET is_answer = " . intval(
736 $_POST['answerstatus']
737 ) . " WHERE postid = " . intval( $postid )
738 ) ) {
739 wpforo_clean_cache( 'post', $postid, $post );
740 WPF()->db->query(
741 "UPDATE " . WPF()->tables->topics . " SET `solved` = " . intval(
742 $_POST['answerstatus']
743 ) . " WHERE `topicid` = " . intval( $post['topicid'] )
744 );
745 do_action( 'wpforo_answer', intval( $_POST['answerstatus'] ), $post );
746 WPF()->notice->add( 'done', 'success' );
747 $response['notice'] = WPF()->notice->get_notices();
748 wp_send_json_success( $response );
749 }
750 wp_send_json_error( $response );
751 }
752
753 add_action( 'wp_ajax_wpforo_quote_ajax', 'wpf_quote' );
754 add_action( 'wp_ajax_nopriv_wpforo_quote_ajax', 'wpf_quote' );
755 function wpf_quote() {
756 wpforo_verify_nonce( 'wpforo_quote_ajax' );
757 if( ! $current_topicid = wpforo_bigintval( WPF()->current_object['topicid'] ) ) {
758 exit();
759 }
760 $post = WPF()->db->get_row(
761 'SELECT * FROM ' . WPF()->tables->posts . ' WHERE topicid = ' . $current_topicid . ' AND postid =' . wpforo_bigintval(
762 $_POST['postid']
763 ),
764 ARRAY_A
765 );
766 if( ! ( WPF()->perm->forum_can( 'cr', $post['forumid'] ) || ( wpforo_is_owner(
767 wpfval(
768 WPF()->current_object['topic'],
769 'userid'
770 ),
771 wpfval( WPF()->current_object['topic'], 'email' )
772 ) && WPF()->perm->forum_can(
773 'ocr',
774 $post['forumid']
775 ) ) ) ) {
776 return;
777 }
778 $post = apply_filters( 'wpforo_quote_post_ajax', $post );
779 $response = sprintf(
780 '[quote data-userid="%1$d" data-postid="%2$d"]%3$s[/quote]<p></p>',
781 $post['userid'],
782 $post['postid'],
783 wpautop( $post['body'] )
784 );
785 wp_send_json_success( $response );
786 }
787
788 add_action( 'wp_ajax_wpforo_report_ajax', 'wpf_report' );
789 function wpf_report() {
790 wpforo_verify_nonce( 'wpforo_report_ajax' );
791 if( ! is_user_logged_in() ) {
792 WPF()->notice->add( wpforo_get_login_or_register_notice_text() );
793 wp_send_json_error( WPF()->notice->get_notices() );
794 }
795
796 if( ! isset( $_POST['reportmsg'] ) || ! $_POST['reportmsg'] || ! isset( $_POST['postid'] ) || ! $_POST['postid'] ) {
797 WPF()->notice->add( 'Error: please insert some text to report.', 'error' );
798 wp_send_json_error( WPF()->notice->get_notices() );
799 }
800
801 $postid = intval( $_POST['postid'] );
802 $forumid = wpforo_post( $postid, 'forumid' );
803
804 if( ! WPF()->perm->can_report( $forumid ) ) {
805 WPF()->notice->add( 'You are not allowed to report.', 'error' );
806 wp_send_json_error( WPF()->notice->get_notices() );
807 }
808
809 ############### Sending Email ##################
810 $report_text = substr( strip_tags( (string) $_POST['reportmsg'] ), 0, 1000 );
811 $reporter = '<a href="' . WPF()->current_user['profile_url'] . '">' . ( WPF()->current_user['display_name'] ? WPF()->current_user['display_name'] : urldecode(
812 (string) WPF()->current_user['user_nicename']
813 ) ) . '</a>';
814 $reportmsg = wpforo_kses( $report_text, 'email' );
815 $post_url = WPF()->post->get_url( $postid );
816
817 $subject = wpforo_setting( 'email', 'report_email_subject' );
818 $message = wpforo_setting( 'email', 'report_email_message' );
819
820 $from_tags = [ "[reporter]", "[message]", "[post_url]" ];
821 $to_words = [
822 sanitize_text_field( $reporter ),
823 $reportmsg,
824 '<a target="_blank" href="' . esc_url( (string) $post_url ) . '">' . esc_url( (string) $post_url ) . '</a>',
825 ];
826
827 $subject = stripslashes( strip_tags( str_replace( $from_tags, $to_words, (string) $subject ) ) );
828 $message = stripslashes( str_replace( $from_tags, $to_words, (string) $message ) );
829
830 $admin_emails = wpforo_setting( 'email', 'admin_emails' );
831 $admin_email = wpfval( $admin_emails, 0 );
832 $headers = wpforo_admin_mail_headers();
833
834 add_filter( 'wp_mail_content_type', 'wpforo_set_html_content_type', 999 );
835 if( ! @wp_mail( $admin_email, $subject, $message, $headers ) ) {
836 WPF()->notice->add( 'Can\'t send report email', 'error' );
837 wp_send_json_error( WPF()->notice->get_notices() );
838 }
839 remove_filter( 'wp_mail_content_type', 'wpforo_set_html_content_type' );
840
841 ############### Sending Email end ##############
842 do_action( 'wpforo_after_post_report', $postid, $forumid, $_POST['reportmsg'] );
843 WPF()->notice->add( 'Message has been sent', 'success' );
844 wp_send_json_success( WPF()->notice->get_notices() );
845 }
846
847 add_action( 'wp_ajax_wpforo_sticky_ajax', 'wpf_sticky' );
848 add_action( 'wp_ajax_nopriv_wpforo_sticky_ajax', 'wpf_sticky' );
849 function wpf_sticky() {
850 wpforo_verify_nonce( 'wpforo_sticky_ajax' );
851 WPF()->notice->add( 'wrong data', 'error' );
852 $response = [ 'notice' => WPF()->notice->get_notices() ];
853 if( ! $topicid = wpforo_bigintval( wpfval( $_POST, 'topicid' ) ) ) {
854 wp_send_json_error( $response );
855 }
856
857 $sql = "SELECT `forumid` FROM `" . WPF()->tables->topics . "` WHERE `topicid` = $topicid";
858 $forumid = WPF()->db->get_var( $sql );
859 if( ! WPF()->perm->forum_can( 's', $forumid ) ) {
860 WPF()->notice->add( 'You don\'t have permission to do this action from this forum', 'error' );
861 $response['notice'] = WPF()->notice->get_notices();
862 wp_send_json_error( $response );
863 }
864 $status = wpfval( $_POST, 'status' );
865 if( $status === 'sticky' ) {
866 $sql = "UPDATE `" . WPF()->tables->topics . "` SET `type` = 1 WHERE `topicid` = $topicid";
867 if( false !== WPF()->db->query( $sql ) ) {
868 wpforo_clean_cache( 'topic-first-post', $topicid );
869 WPF()->notice->add( 'Done!', 'success' );
870 $response['notice'] = WPF()->notice->get_notices();
871 wp_send_json_success( $response );
872 }
873 } elseif( $status === 'unsticky' ) {
874 $sql = "UPDATE `" . WPF()->tables->topics . "` SET `type` = 0 WHERE `topicid` = $topicid";
875 if( false !== WPF()->db->query( $sql ) ) {
876 wpforo_clean_cache( 'topic-first-post', $topicid );
877 WPF()->notice->add( 'Done!', 'success' );
878 $response['notice'] = WPF()->notice->get_notices();
879 wp_send_json_success( $response );
880 }
881 }
882 wp_send_json_error( $response );
883 }
884
885 add_action( 'wp_ajax_wpforo_private_ajax', 'wpf_private' );
886 function wpf_private() {
887 wpforo_verify_nonce( 'wpforo_private_ajax' );
888 if( ! WPF()->current_userid ) {
889 wp_send_json_error();
890 }
891 if( ! ( $topicid = wpforo_bigintval( wpfval( $_POST, 'topicid' ) ) ) ) {
892 wp_send_json_error();
893 }
894 if( ! ( $topic = WPF()->topic->get_topic( $topicid ) ) ) {
895 wp_send_json_error();
896 }
897 if( ! ( WPF()->perm->forum_can( 'p', $topic['forumid'] ) || ( WPF()->current_userid == $topic['userid'] && WPF()->perm->forum_can( 'op', $topic['forumid'] ) ) ) ) {
898 wp_send_json_error();
899 }
900 $status = wpfval( $_POST, 'status' );
901 if( $status === 'private' ) {
902 WPF()->topic->wprivate( $topicid, 1 );
903 wp_send_json_success();
904 } elseif( $status === 'public' ) {
905 WPF()->topic->wprivate( $topicid, 0 );
906 wp_send_json_success();
907 }
908 wp_send_json_error();
909 }
910
911 add_action( 'wp_ajax_wpforo_solved_ajax', 'wpf_solved' );
912 add_action( 'wp_ajax_nopriv_wpforo_solved_ajax', 'wpf_solved' );
913 function wpf_solved() {
914 wpforo_verify_nonce( 'wpforo_solved_ajax' );
915 if( ! WPF()->current_userid ) {
916 wp_send_json_error();
917 }
918 if( ! $postid = wpforo_bigintval( wpfval( $_POST, 'postid' ) ) ) {
919 wp_send_json_error();
920 }
921 if( $post = WPF()->post->get_post( $postid ) ) {
922 if( WPF()->perm->forum_can( 'sv', $post['forumid'] ) || ( WPF()->current_userid == $post['userid'] && WPF()->perm->forum_can( 'osv', $post['forumid'] ) ) ) {
923 $solved = ( wpfval( $_POST, 'status' ) === 'solved' ? 1 : 0 );
924 $sql = "UPDATE " . WPF()->tables->topics . " SET `solved` = %d WHERE `topicid` = %d";
925 WPF()->db->query( WPF()->db->prepare( $sql, $solved, $post['topicid'] ) );
926 wpforo_clean_cache( 'topic-first-post', $post['topicid'] );
927
928 // Fire action hook for topic solved/unsolved
929 $topic = WPF()->topic->get_topic( $post['topicid'] );
930 if( $topic ) {
931 if( $solved ) {
932 do_action( 'wpforo_topic_solved', $topic, $post );
933 } else {
934 do_action( 'wpforo_topic_unsolved', $topic, $post );
935 }
936 }
937
938 wp_send_json_success();
939 }
940 }
941 wp_send_json_error();
942 }
943
944 add_action( 'wp_ajax_wpforo_approve_ajax', 'wpf_approve' );
945 function wpf_approve() {
946 wpforo_verify_nonce( 'wpforo_approve_ajax' );
947 if( ! WPF()->current_userid ) {
948 WPF()->notice->add( wpforo_get_login_or_register_notice_text() );
949 wp_send_json_error();
950 }
951 if( ! $postid = wpforo_bigintval( wpfval( $_POST, 'postid' ) ) ) {
952 wp_send_json_error();
953 }
954 $post = WPF()->post->get_post( $postid );
955 if( ! $post || ! WPF()->perm->forum_can( 'au', $post['forumid'] ) ) {
956 wp_send_json_error();
957 }
958 $status = wpfval( $_POST, 'status' );
959 if( $status === 'approve' ) {
960 WPF()->moderation->post_approve( $postid );
961 wp_send_json_success();
962 } elseif( $status === 'unapprove' ) {
963 WPF()->moderation->post_unapprove( $postid );
964 wp_send_json_success();
965 }
966 wp_send_json_error();
967 }
968
969 add_action( 'wp_ajax_wpforo_close_ajax', 'wpf_close' );
970 function wpf_close() {
971 wpforo_verify_nonce( 'wpforo_close_ajax' );
972 if( ! WPF()->current_userid ) {
973 wp_send_json_error();
974 }
975
976 if( ! $topicid = wpforo_bigintval( wpfval( $_POST, 'topicid' ) ) ) {
977 wp_send_json_error();
978 }
979 $topic = WPF()->topic->get_topic( $topicid );
980 if( ! $topic || ! WPF()->perm->forum_can( 'cot', $topic['forumid'] ) ) {
981 wp_send_json_error();
982 }
983 $status = wpfval( $_POST, 'status' );
984 $topic = WPF()->topic->get_topic( $topicid );
985
986 if( $status === 'closed' ) {
987 WPF()->topic->open( $topicid );
988 if( $topic ) {
989 do_action( 'wpforo_topic_opened', $topic );
990 }
991 wp_send_json_success();
992 } elseif( $status === 'close' ) {
993 WPF()->topic->close( $topicid );
994 if( $topic ) {
995 do_action( 'wpforo_topic_closed', $topic );
996 }
997 wp_send_json_success();
998 }
999 wp_send_json_error();
1000 }
1001
1002 add_action( 'wp_ajax_wpforo_post_edit', 'wpforo_post_edit' );
1003 add_action( 'wp_ajax_nopriv_wpforo_post_edit', 'wpforo_post_edit' );
1004 function wpforo_post_edit() {
1005 wpforo_verify_nonce( 'wpforo_post_edit' );
1006 $r = [ 'html' => '' ];
1007 if( $postid = wpforo_bigintval( wpfval( $_POST, 'postid' ) ) ) {
1008 if( $post = WPF()->post->get_post( $postid, false ) ) {
1009 if( WPF()->perm->forum_can( 'eor', $post['forumid'] ) || WPF()->perm->forum_can(
1010 'eot',
1011 $post['forumid']
1012 ) ) {
1013 if( $topic = WPF()->topic->get_topic( $post['topicid'] ) ) {
1014 $postmetas = (array) WPF()->postmeta->get_postmeta( $postid, '', true );
1015 $post['body'] = htmlspecialchars( $post['body'], ENT_NOQUOTES );
1016 $values = array_merge( $post, $topic, $postmetas );
1017 $values = apply_filters( 'wpforo_edit_post_ajax', $values, $post, $topic, $postmetas );
1018 ob_start();
1019 if( intval( $post['is_first_post'] ) ) {
1020 WPF()->form->current['varname'] = 'thread';
1021 WPF()->tpl->topic_form( $post['forumid'], $values );
1022 } else {
1023 WPF()->form->current['varname'] = 'post';
1024 if( trim( (string) $post['title'] ) ) {
1025 $values['title'] = $post['title'];
1026 }
1027 WPF()->tpl->reply_form( $topic, $values );
1028 }
1029 $r['html'] = ob_get_clean();
1030 wp_send_json_success( $r );
1031 }
1032 }
1033 }
1034 }
1035 wp_send_json_error( $r );
1036 }
1037
1038 add_action( 'wp_ajax_wpforo_delete_ajax', 'wpf_delete' );
1039 function wpf_delete() {
1040 wpforo_verify_nonce( 'wpforo_delete_ajax' );
1041 $resp = [];
1042 $status = (string) wpfval( $_POST, 'status' );
1043 $postid = (int) wpfval( $_POST, 'postid' );
1044 if( $status === 'topic' ) {
1045 if( WPF()->topic->delete( $postid ) ) {
1046 $forumid = (int) wpfval( $_POST, 'forumid' );
1047 $resp = [
1048 'postid' => $postid,
1049 'location' => $forumid ? WPF()->forum->get_forum_url( $forumid ) : wpforo_home_url(),
1050 ];
1051 $resp['notice'] = WPF()->notice->get_notices();
1052 wp_send_json_success( $resp );
1053 }
1054 } elseif( $status === 'reply' ) {
1055 if( WPF()->post->delete( $postid ) ) {
1056 $root = (int) WPF()->post->get_root( $postid );
1057 $root_replies_count = (int) WPF()->post->get_root_replies_count( $root );
1058 $resp = [
1059 'postid' => $postid,
1060 'root' => $root,
1061 'root_count' => $root_replies_count,
1062 ];
1063 $resp['notice'] = WPF()->notice->get_notices();
1064 wp_send_json_success( $resp );
1065 }
1066 }
1067
1068 $resp['notice'] = WPF()->notice->get_notices();
1069 wp_send_json_error( $resp );
1070 }
1071
1072 add_action( 'wp_ajax_wpforo_layout4_loadmore', 'wpfl4_loadmore' );
1073 add_action( 'wp_ajax_nopriv_wpforo_layout4_loadmore', 'wpfl4_loadmore' );
1074 function wpfl4_loadmore() {
1075 wpforo_verify_nonce( 'wpforo_layout4_loadmore' );
1076 $success = false;
1077 WPF()->notice->add( 'wrong data', 'error' );
1078 $response = [ 'no_more' => 0, 'output_html' => '', 'notice' => WPF()->notice->get_notices() ];
1079 $request = [
1080 'forumid' => 0,
1081 'filter' => 'newest',
1082 'paged' => 1,
1083 ];
1084 $request = array_merge( $request, $_POST );
1085
1086 if( $forumid = intval( $request['forumid'] ) ) {
1087 $items_count = 0;
1088 $childs = WPF()->forum->get_childs( $forumid );
1089 $childs[] = $forumid;
1090 $args = [
1091 'offset' => ( $request['paged'] - 1 ) * wpforo_setting( 'forums', 'layout_threaded_intro_topics_count' ),
1092 'row_count' => wpforo_setting( 'forums', 'layout_threaded_intro_topics_count' ),
1093 'forumids' => $childs,
1094 'orderby' => 'type, modified',
1095 'order' => 'DESC',
1096 ];
1097
1098 switch( $request['filter'] ) {
1099 case 'solved':
1100 $args['solved'] = 1;
1101 $args['type'] = 0;
1102 break;
1103 case 'unsolved':
1104 $args['solved'] = 0;
1105 $args['type'] = 0;
1106 $args['closed'] = 0;
1107 break;
1108 case 'hottest':
1109 $args['orderby'] = 'posts';
1110 break;
1111 }
1112
1113 $topics = WPF()->topic->get_topics( $args, $items_count );
1114 if( $topics ) {
1115 ob_start();
1116 if( function_exists( 'wpforo_thread_forum_template' ) ) {
1117 foreach( $topics as $topic ) {
1118 wpforo_thread_forum_template( $topic['topicid'] );
1119 }
1120 }
1121 $response['output_html'] = ob_get_clean();
1122 $success = true;
1123 $response['notice'] = '';
1124 if( count( $topics ) < wpforo_setting( 'forums', 'layout_threaded_intro_topics_count' ) ) {
1125 $response['no_more'] = 1;
1126 }
1127 } else {
1128 $response['no_more'] = 1;
1129 }
1130
1131 if( $response['no_more'] ) {
1132 WPF()->notice->add( 'all topics has been loaded in this list', 'success' );
1133 $response['notice'] = WPF()->notice->get_notices();
1134 }
1135 }
1136
1137 if( $success ) {
1138 wp_send_json_success( $response );
1139 } else {
1140 wp_send_json_error( $response );
1141 }
1142 }
1143
1144 add_action( 'wp_ajax_wpforo_load_more_activities', 'wpforo_load_more_activities' );
1145 add_action( 'wp_ajax_nopriv_wpforo_load_more_activities', 'wpforo_load_more_activities' );
1146 function wpforo_load_more_activities() {
1147 wpforo_verify_nonce( 'wpforo_load_more_activities' );
1148
1149 $items_per_page = 20;
1150 $page = ! empty( $_POST['page'] ) ? intval( $_POST['page'] ) : 1;
1151 $activity_type = ! empty( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : 'all';
1152 $period = ! empty( $_POST['period'] ) ? sanitize_text_field( $_POST['period'] ) : 'week';
1153
1154 // Calculate date_from based on period
1155 $date_from = null;
1156 switch( $period ) {
1157 case 'day':
1158 $date_from = time() - ( 24 * 60 * 60 );
1159 break;
1160 case 'week':
1161 $date_from = time() - ( 7 * 24 * 60 * 60 );
1162 break;
1163 case 'month':
1164 $date_from = time() - ( 30 * 24 * 60 * 60 );
1165 break;
1166 case 'all':
1167 default:
1168 $date_from = null;
1169 break;
1170 }
1171
1172 // Get enabled activity types from settings
1173 $enabled_types = WPF()->settings->activity['enabled_types'] ?? [];
1174
1175 // Build activity query args
1176 $args = [
1177 'types_exclude' => [ 'new_reply' ], // Exclude notification-only types
1178 'orderby' => 'date',
1179 'order' => 'DESC',
1180 'offset' => ( $page - 1 ) * $items_per_page,
1181 'row_count' => $items_per_page,
1182 'date_from' => $date_from,
1183 ];
1184
1185 // Filter by activity type
1186 if( $activity_type !== 'all' ) {
1187 $type_mapping = [
1188 'topic' => [ 'wpforo_topic', 'edit_topic' ],
1189 'reply' => [ 'wpforo_post', 'edit_post' ],
1190 'reaction' => [ 'new_like', 'new_dislike', 'new_up_vote', 'new_down_vote', 'new_reaction' ],
1191 'favorite' => [ 'new_favorite' ],
1192 'solved' => [ 'topic_solved' ],
1193 'closed' => [ 'topic_closed' ],
1194 'answer' => [ 'post_answer' ],
1195 ];
1196 if( isset( $type_mapping[ $activity_type ] ) ) {
1197 // Intersect with enabled types to respect settings
1198 $args['types_include'] = array_intersect( $type_mapping[ $activity_type ], $enabled_types );
1199 }
1200 } else {
1201 // Show all enabled types
1202 if( ! empty( $enabled_types ) ) {
1203 $args['types_include'] = $enabled_types;
1204 }
1205 }
1206
1207 $items_count = 0;
1208 $activities = WPF()->activity->get_activities( $args, $items_count, true, true );
1209 $has_more = ( $page * $items_per_page ) < $items_count;
1210
1211 // Generate HTML for timeline items
1212 $html = '';
1213 if( ! empty( $activities ) ) {
1214 $index = 0;
1215 foreach( $activities as $activity ) {
1216 // For non-content actions (reactions, favorites, votes, etc.), the actor is in itemid_second
1217 $actor_actions = [ 'new_like', 'new_dislike', 'new_up_vote', 'new_down_vote', 'new_reaction', 'new_mention', 'new_favorite', 'topic_solved', 'topic_closed', 'post_answer' ];
1218 $actor_userid = in_array( $activity['type'], $actor_actions ) && ! empty( $activity['itemid_second'] )
1219 ? $activity['itemid_second']
1220 : $activity['userid'];
1221 $member = wpforo_member( $actor_userid );
1222 $icon = wpforo_activity_icon( $activity['type'] );
1223 $info_html = wpforo_activity_info_html( $activity, $member );
1224 $show_excerpt = in_array( $activity['type'], [ 'wpforo_topic', 'wpforo_post' ] );
1225 $excerpt = '';
1226 if( $show_excerpt && $activity['itemid'] ) {
1227 // For wpforo_topic, itemid is topicid - get first post via topic's first_postid
1228 if( $activity['type'] === 'wpforo_topic' ) {
1229 $topic_data = WPF()->topic->get_topic( $activity['itemid'] );
1230 if( $topic_data && ! empty( $topic_data['first_postid'] ) ) {
1231 $first_post = WPF()->post->get_post( $topic_data['first_postid'] );
1232 if( $first_post && ! empty( $first_post['body'] ) ) {
1233 $excerpt = wp_trim_words( strip_tags( $first_post['body'] ), 20 );
1234 }
1235 }
1236 } else {
1237 $post = WPF()->post->get_post( $activity['itemid'] );
1238 if( $post && ! empty( $post['body'] ) ) {
1239 $excerpt = wp_trim_words( strip_tags( $post['body'] ), 20 );
1240 }
1241 }
1242 }
1243
1244 $html .= '<div class="wpf-timeline-item wpf-timeline-' . esc_attr( $activity['type'] ) . '" data-activity-id="' . esc_attr( $activity['id'] ) . '" style="--delay: ' . ( $index * 0.1 ) . 's">';
1245 $html .= '<div class="wpf-timeline-left">';
1246 if( WPF()->usergroup->can( 'va' ) && wpforo_setting( 'profiles', 'avatars' ) ) {
1247 $html .= '<div class="wpf-timeline-avatar">' . wpforo_user_avatar( $member, 40 ) . '</div>';
1248 }
1249 $html .= '<div class="wpf-timeline-user">';
1250 ob_start();
1251 wpforo_member_link( $member );
1252 $html .= ob_get_clean();
1253 $html .= '</div>';
1254 $html .= '<div class="wpf-timeline-date">';
1255 ob_start();
1256 wpforo_date( $activity['date'], 'ago' );
1257 $html .= ob_get_clean();
1258 $html .= '</div>';
1259 $html .= '</div>';
1260 $html .= '<div class="wpf-timeline-node"><div class="wpf-timeline-icon">' . $icon . '</div></div>';
1261 $html .= '<div class="wpf-timeline-right"><div class="wpf-timeline-card">';
1262 if( WPF()->usergroup->can( 'aum' ) ) {
1263 $html .= '<button type="button" class="wpf-activity-delete" title="' . esc_attr( wpforo_phrase( 'Delete Activity', false ) ) . '"><i class="fas fa-trash-alt"></i></button>';
1264 }
1265 $html .= '<div class="wpf-timeline-activity">' . $info_html . '</div>';
1266 if( $show_excerpt && $excerpt ) {
1267 $html .= '<div class="wpf-timeline-excerpt">' . esc_html( $excerpt ) . '</div>';
1268 }
1269 $html .= '</div></div>';
1270 $html .= '</div>';
1271
1272 $index++;
1273 }
1274 }
1275
1276 wp_send_json_success( [
1277 'html' => $html,
1278 'has_more' => $has_more,
1279 ] );
1280 }
1281
1282 add_action( 'wp_ajax_wpforo_delete_activity', 'wpforo_delete_activity' );
1283 function wpforo_delete_activity() {
1284 wpforo_verify_nonce( 'wpforo_delete_activity' );
1285
1286 // Permission check
1287 if( ! WPF()->usergroup->can( 'aum' ) ) {
1288 wp_send_json_error( [ 'message' => wpforo_phrase( 'Permission denied', false ) ] );
1289 }
1290
1291 $activity_id = ! empty( $_POST['activity_id'] ) ? wpforo_bigintval( $_POST['activity_id'] ) : 0;
1292 if( ! $activity_id ) {
1293 wp_send_json_error( [ 'message' => wpforo_phrase( 'Invalid activity', false ) ] );
1294 }
1295
1296 if( WPF()->activity->delete_activity( $activity_id ) ) {
1297 wp_send_json_success( [ 'message' => wpforo_phrase( 'Activity deleted', false ) ] );
1298 } else {
1299 wp_send_json_error( [ 'message' => wpforo_phrase( 'Failed to delete activity', false ) ] );
1300 }
1301 }
1302
1303 add_action( 'wp_ajax_wpforo_topic_portable_form', 'wpforo_topic_portable_form' );
1304 add_action( 'wp_ajax_nopriv_wpforo_topic_portable_form', 'wpforo_topic_portable_form' );
1305 function wpforo_topic_portable_form() {
1306 wpforo_verify_nonce( 'wpforo_topic_portable_form' );
1307 $html = '';
1308 if( $forumid = wpfval( $_POST, 'forumid' ) ) {
1309 WPF()->form->current['varname'] = 'thread';
1310 ob_start();
1311 WPF()->tpl->topic_form( $forumid );
1312 do_action( 'wpforo_topic_portable_form_extra_html', $forumid );
1313 $html = trim( (string) ob_get_clean() );
1314 }
1315 if( $html ) {
1316 wp_send_json_success( $html );
1317 } else {
1318 wp_send_json_error();
1319 }
1320 }
1321
1322 add_action( 'wp_ajax_wpforo_qa_comment_loadrest', 'wpforo_qa_comment_loadrest' );
1323 add_action( 'wp_ajax_nopriv_wpforo_qa_comment_loadrest', 'wpforo_qa_comment_loadrest' );
1324 function wpforo_qa_comment_loadrest() {
1325 wpforo_verify_nonce( 'wpforo_qa_comment_loadrest' );
1326 WPF()->notice->add( 'wrong data', 'error' );
1327 $response = [ 'output_html' => '', 'notice' => WPF()->notice->get_notices() ];
1328 if( $parentid = wpfval( $_POST, 'parentid' ) ) {
1329 $args = [
1330 'root' => $parentid,
1331 'offset' => wpforo_setting( 'topics', 'layout_qa_comments_limit_count' ),
1332 'row_count' => PHP_INT_MAX,
1333 ];
1334 if( ! wpforo_root_exist() ) {
1335 unset( $args['root'] );
1336 $args['parentid'] = $parentid;
1337 }
1338 if( $comments = WPF()->post->get_posts( $args ) ) {
1339 ob_start();
1340 include_once( wpftpl( 'layouts/3/comment.php' ) );
1341 ob_clean();
1342
1343 foreach( $comments as $comment ) {
1344 wpforo_qa_comment_template( $comment );
1345 }
1346
1347 $response['output_html'] = ob_get_clean();
1348 $response['notice'] = '';
1349 wp_send_json_success( $response );
1350 }
1351 }
1352 wp_send_json_error( $response );
1353 }
1354
1355 add_action( 'wp_ajax_wpforo_post_url_fixer', 'wpforo_post_url_fixer' );
1356 add_action( 'wp_ajax_nopriv_wpforo_post_url_fixer', 'wpforo_post_url_fixer' );
1357 function wpforo_post_url_fixer() {
1358 wpforo_verify_nonce( 'wpforo_post_url_fixer' );
1359 if( ( $postid = wpforo_bigintval( wpfval( $_POST, 'postid' ) ) ) && ( $referer = wpfval( $_POST, 'referer' ) ) ) {
1360 if( is_wpforo_url( $referer ) ) {
1361 $diff = 100;
1362 $referer_hash = md5( $referer . $postid );
1363 $nowtime = time();
1364 if( $lasttime = (int) get_transient( 'wpforo_post_url_fixer' . $referer_hash ) ) {
1365 $diff = $nowtime - $lasttime;
1366 }
1367 if( $diff <= 8 ) {
1368 exit();
1369 }
1370 set_transient( 'wpforo_post_url_fixer' . $referer_hash, $nowtime, 1000 );
1371 if( $post = WPF()->post->get_post( $postid ) ) {
1372 echo WPF()->post->get_url( $post );
1373 }
1374 }
1375 }
1376 exit();
1377 }
1378
1379 add_action( 'wp_ajax_wpforo_update_database', 'wpforo_ajax_update_database' );
1380 function wpforo_ajax_update_database() {
1381 check_admin_referer( 'wpforo_update_database' );
1382 wpforo_set_max_execution_time();
1383 wpforo_update_db();
1384 exit();
1385 }
1386
1387 ############### Sending Email ##################
1388 function wpforo_set_html_content_type() {
1389 return apply_filters( 'wpforo_emails_content_type', 'text/html' );
1390 }
1391
1392 function __wpforo_set_html_content_type() {
1393 return 'text/html';
1394 }
1395
1396 function wpforo_mail_from_name() {
1397 return wpforo_setting( 'email', 'from_name' ) ?: get_option( 'blogname' );
1398 }
1399
1400 function wpforo_mail_from_email() {
1401 return wpforo_setting( 'email', 'from_email' ) ?: get_option( 'admin_email' );
1402 }
1403
1404 function wpforo_mail_headers( $from_name = '', $from_email = '', $cc = [], $bcc = [] ) {
1405 $H = [];
1406 if( ! $from_name ) {
1407 $from_name = wpforo_mail_from_name();
1408 }
1409 if( ! $from_email ) {
1410 $from_email = wpforo_mail_from_email();
1411 }
1412 $H[] = 'From: ' . $from_name . ' <' . $from_email . '>';
1413 if( ! empty( $cc ) ) {
1414 foreach( $cc as $c ) {
1415 $c = sanitize_email( $c );
1416 $H[] = 'CC: ' . $c;
1417 }
1418 }
1419 if( ! empty( $bcc ) ) {
1420 foreach( $bcc as $b ) {
1421 $b = sanitize_email( $b );
1422 $H[] = 'BCC: ' . $b;
1423 }
1424 }
1425
1426 return $H;
1427 }
1428
1429 function wpforo_admin_mail_headers( $from_name = '', $from_email = '', $cc = [], $bcc = [] ) {
1430 $H = [];
1431 if( ! $from_name ) {
1432 $from_name = wpforo_mail_from_name();
1433 }
1434 if( ! $from_email ) {
1435 $from_email = wpforo_mail_from_email();
1436 }
1437 $H[] = 'From: ' . $from_name . ' <' . $from_email . '>';
1438 if( empty( $cc ) ) $cc = wpforo_setting( 'email', 'admin_emails' );
1439 if( ! empty( $cc ) ) {
1440 foreach( $cc as $c ) {
1441 $c = sanitize_email( $c );
1442 $H[] = 'CC: ' . $c;
1443 }
1444 }
1445 if( ! empty( $bcc ) ) {
1446 foreach( $bcc as $b ) {
1447 $b = sanitize_email( $b );
1448 $H[] = 'BCC: ' . $b;
1449 }
1450 }
1451
1452 return $H;
1453 }
1454
1455 function wpforo_get_login_or_register_notice_text() {
1456 $popup_html = '';
1457 if( ! wpforo_is_bot() ) {
1458 $popup_html = sprintf(
1459 wpforo_phrase( 'Please %s or %s', false ),
1460 '<a href="' . wpforo_login_url() . '" rel="noindex,nofollow">' . wpforo_phrase(
1461 'Login',
1462 false
1463 ) . '</a>',
1464 '<a href="' . wpforo_register_url() . '" rel="noindex,nofollow">' . wpforo_phrase(
1465 'Register',
1466 false
1467 ) . '</a>'
1468 );
1469 }
1470
1471 return apply_filters( 'wpforo_login_or_register_popup_message', $popup_html );
1472 }
1473
1474 function wpforo_dynamic_phrases_register() {
1475 if( ! $js = WPF()->phrase->get_wpforo_phrases_inline_js() ) {
1476 return;
1477 }
1478 $md5_js = md5( $js );
1479
1480 $inline = false;
1481 $dynamic_js_file = WPF()->folders['assets']['dir'] . DIRECTORY_SEPARATOR . 'phrases.js';
1482 if( ! file_exists( $dynamic_js_file ) || $md5_js !== md5_file( $dynamic_js_file ) ) {
1483 $result = wpforo_write_file( $dynamic_js_file, $js );
1484 if( wpfval( $result, 'error' ) ) {
1485 $inline = true;
1486 }
1487 }
1488
1489 wp_register_script(
1490 'wpforo-dynamic-phrases',
1491 WPF()->folders['assets']['url'] . '/phrases.js',
1492 false,
1493 WPFORO_VERSION . '.' . $md5_js
1494 );
1495 if( $inline ) {
1496 $js = preg_replace( '|[\r\n\t]+|', '', $js );
1497 wp_add_inline_script( 'wpforo-dynamic-phrases', $js );
1498 }
1499 }
1500
1501 function wpforo_dynamic_style_enqueue() {
1502 if( ! $css = WPF()->tpl->generate_dynamic_css() ) {
1503 return;
1504 }
1505 $md5_css = md5( $css );
1506
1507 $inline = false;
1508 $dynamic_css_file = WPF()->folders['assets']['dir'] . DIRECTORY_SEPARATOR . 'colors.css';
1509 if( ! file_exists( $dynamic_css_file ) || $md5_css !== md5_file( $dynamic_css_file ) ) {
1510 $result = wpforo_write_file( $dynamic_css_file, $css );
1511 if( wpfval( $result, 'error' ) ) {
1512 $inline = true;
1513 }
1514 }
1515
1516 wp_register_style(
1517 'wpforo-dynamic-style',
1518 WPF()->folders['assets']['url'] . '/colors.css',
1519 false,
1520 WPFORO_VERSION . '.' . $md5_css
1521 );
1522 if( $inline ) {
1523 $css = preg_replace( '|[\r\n\t]+|', '', $css );
1524 wp_add_inline_style( 'wpforo-dynamic-style', $css );
1525 }
1526
1527 wp_enqueue_style( 'wpforo-dynamic-style' );
1528 }
1529
1530 add_action( 'wp_enqueue_scripts', 'wpforo_dynamic_style_enqueue', 999 );
1531
1532 function wpforo_frontend_register_scripts() {
1533 wp_register_style(
1534 'wpforo-font-awesome',
1535 WPFORO_URL . '/assets/css/font-awesome/css/fontawesome-all.min.css',
1536 false,
1537 '6.1.1'
1538 );
1539 //wp_register_style( 'wpforo-font-awesome-rtl', WPFORO_URL . '/assets/css/font-awesome/css/font-awesome-rtl.css', [ 'wpforo-font-awesome' ], WPFORO_VERSION );
1540 wpforo_dynamic_phrases_register();
1541 wp_register_script( 'wpforo-frontend-js', WPFORO_URL . '/assets/js/frontend.js', [
1542 'jquery',
1543 'wpforo-dynamic-phrases',
1544 ], WPFORO_VERSION, true );
1545 wp_localize_script( 'wpforo-frontend-js', 'wpforo', [
1546 'ajax_url' => wpforo_get_ajax_url(),
1547 'nonces' => wpforo_generate_ajax_nonces(),
1548 'settings_slugs' => WPF()->settings->slugs,
1549 'editor_settings' => WPF()->tpl->editor_buttons( 'post' ),
1550 'revision_options' => WPF()->settings->posting,
1551 'notice' => [
1552 'login_or_register' => wpforo_get_login_or_register_notice_text(),
1553 'timeouts' => WPF()->notice->get_timeouts(),
1554 ],
1555 ] );
1556 // Register AI features script if AI service is available and any frontend AI feature is enabled
1557 // ai-features.js handles: assistant widget, translation, topic summary, topic suggestions, bot reply
1558 if( isset( WPF()->ai_client ) && WPF()->ai_client->is_service_available() && (
1559 wpforo_setting( 'ai', 'assistant' ) ||
1560 wpforo_setting( 'ai', 'translation' ) ||
1561 wpforo_setting( 'ai', 'topic_summary' ) ||
1562 wpforo_setting( 'ai', 'topic_suggestions' ) ||
1563 wpforo_setting( 'ai', 'bot_reply' )
1564 ) ) {
1565 wp_register_script( 'wpforo-ai-features-js', WPFORO_URL . '/assets/js/ai-features.js', [
1566 'wpforo-frontend-js',
1567 ], WPFORO_VERSION, true );
1568 }
1569 // Register AI Chatbot script separately (can be large, loaded conditionally)
1570 if( isset( WPF()->ai_chatbot ) && WPF()->ai_chatbot->is_enabled() ) {
1571 wp_register_script( 'wpforo-ai-chatbot-js', WPFORO_URL . '/assets/js/ai-chatbot.js', [
1572 'wpforo-frontend-js',
1573 ], WPFORO_VERSION, true );
1574 wp_localize_script( 'wpforo-ai-chatbot-js', 'wpforo_ai_chatbot', [
1575 'ajax_url' => wpforo_get_ajax_url(),
1576 'nonce' => wp_create_nonce( 'wpforo_ai_chatbot' ),
1577 'welcome_message' => wpforo_setting( 'ai', 'chatbot_welcome_message' ),
1578 'use_rag' => (bool) wpforo_setting( 'ai', 'chatbot_use_rag' ),
1579 'use_local_context' => (bool) wpforo_setting( 'ai', 'chatbot_use_local_context' ),
1580 'phrases' => [
1581 'new_conversation' => wpforo_phrase( 'New Conversation', false ),
1582 'send_message' => wpforo_phrase( 'Send a message...', false ),
1583 'delete_confirm' => wpforo_phrase( 'Delete this conversation?', false ),
1584 'error_sending' => wpforo_phrase( 'Error sending message. Please try again.', false ),
1585 'typing' => wpforo_phrase( 'AI is thinking...', false ),
1586 'no_conversations' => wpforo_phrase( 'No conversations yet', false ),
1587 'start_conversation' => wpforo_phrase( 'Start a new conversation to chat with the AI assistant.', false ),
1588 ],
1589 ] );
1590 }
1591 wp_register_script( 'wpforo-ajax', WPFORO_URL . '/assets/js/ajax.js', [
1592 'suggest',
1593 'wpforo-frontend-js',
1594 ], WPFORO_VERSION, true );
1595 wp_register_style( 'wpforo-style', wpftpl_url( 'style.css' ), false, WPFORO_VERSION );
1596 wp_register_style( 'wpforo-style-rtl', wpftpl_url( 'style-rtl.css' ), false, WPFORO_VERSION );
1597 wp_register_style( 'wpforo-widgets', wpftpl_url( 'widgets.css' ), [], WPFORO_VERSION );
1598 wp_register_style( 'wpforo-widgets-rtl', wpftpl_url( 'widgets-rtl.css' ), [], WPFORO_VERSION );
1599 wp_register_script( 'wpforo-widgets-js', WPFORO_URL . '/assets/js/widgets.js', [ 'jquery' ], WPFORO_VERSION, true );
1600 $wpforo_widgets = [
1601 'ajax_url' => wpforo_get_ajax_url(),
1602 'is_live_notifications_on' => 0,
1603 'live_notifications_start' => 30000,
1604 'live_notifications_interval' => 60000,
1605 ];
1606 if( WPF()->current_userid && wpforo_setting( 'notifications', 'notifications' ) && wpforo_setting(
1607 'notifications',
1608 'notifications_live'
1609 ) ) {
1610 $start = apply_filters( 'wpforo_notifications_list', 30000 );
1611 $interval = apply_filters( 'wpforo_notifications_list', 60000 );
1612 if( $interval < 10000 ) {
1613 $interval = 10000;
1614 }
1615 $wpforo_widgets['is_live_notifications_on'] = 1;
1616 $wpforo_widgets['live_notifications_start'] = $start;
1617 $wpforo_widgets['live_notifications_interval'] = $interval;
1618 }
1619 wp_localize_script( 'wpforo-widgets-js', 'wpforo_widgets', $wpforo_widgets );
1620
1621 if( ! WPF()->perm->forum_can( 'va' ) || ! WPF()->usergroup->can( 'caa' ) ) {
1622 wp_add_inline_script(
1623 'wpforo-frontend-js',
1624 "jQuery(document).ready(function($){
1625 $('#wpforo-wrap').on('click', '.attach_cant_view', function(){
1626 wpforo_notice_show(
1627 '<p>" . addslashes(
1628 (string) ( is_user_logged_in() ? wpforo_phrase(
1629 'You are not permitted to view this attachment',
1630 false
1631 ) : wpforo_get_login_or_register_notice_text() )
1632 ) . "</p>'
1633 );
1634 });
1635 })"
1636 );
1637 }
1638
1639 do_action( 'wpforo_frontend_register_scripts' );
1640
1641 wpforo_frontend_enqueue_scripts();
1642 }
1643
1644 add_action( 'wp_enqueue_scripts', 'wpforo_frontend_register_scripts' );
1645
1646 function wpforo_frontend_enqueue_scripts() {
1647 $fontawesome = wpforo_setting( 'general', 'fontawesome' );
1648 if( $fontawesome === 'sitewide' || ( $fontawesome === 'forum' && is_wpforo_page() ) ) {
1649 wp_enqueue_style( 'wpforo-font-awesome' );
1650 //if( is_rtl() ) wp_enqueue_style( 'wpforo-font-awesome-rtl' );
1651 }
1652
1653 if( is_wpforo_page() ) {
1654 wp_enqueue_script( 'wpforo-dynamic-phrases' );
1655 wp_enqueue_script( 'wpforo-frontend-js' );
1656 // Enqueue AI features script if AI service is available and any frontend AI feature is enabled
1657 if( isset( WPF()->ai_client ) && WPF()->ai_client->is_service_available() && (
1658 wpforo_setting( 'ai', 'assistant' ) ||
1659 wpforo_setting( 'ai', 'translation' ) ||
1660 wpforo_setting( 'ai', 'topic_summary' ) ||
1661 wpforo_setting( 'ai', 'topic_suggestions' ) ||
1662 wpforo_setting( 'ai', 'bot_reply' )
1663 ) ) {
1664 wp_enqueue_script( 'wpforo-ai-features-js' );
1665 }
1666 // Enqueue AI Chatbot script if enabled and user can chat
1667 if( isset( WPF()->ai_chatbot ) && WPF()->ai_chatbot->is_enabled() && WPF()->ai_chatbot->user_can_chat() ) {
1668 wp_enqueue_script( 'wpforo-ai-chatbot-js' );
1669 }
1670 wp_enqueue_script( 'wpforo-ajax' );
1671 if( is_rtl() ) {
1672 wp_enqueue_style( 'wpforo-style-rtl' );
1673 } else {
1674 wp_enqueue_style( 'wpforo-style' );
1675 }
1676 }
1677
1678 if( is_rtl() ) {
1679 wp_enqueue_style( 'wpforo-widgets-rtl' );
1680 } else {
1681 wp_enqueue_style( 'wpforo-widgets' );
1682 }
1683
1684 do_action( 'wpforo_frontend_enqueue_scripts' );
1685 }
1686
1687 function wpforo_style_options( $css ) {
1688 $css .= "\r\n#wpforo-wrap .wpforo-forum-title{font-size: " . wpforo_setting(
1689 'styles',
1690 'font_size_forum'
1691 ) . "px!important; line-height: " . ( wpforo_setting( 'styles', 'font_size_forum' ) + 1 ) . "px!important;}";
1692 $css .= "\r\n#wpforo-wrap .wpforo-topic-title a { font-size: " . wpforo_setting(
1693 'styles',
1694 'font_size_topic'
1695 ) . "px!important; }";
1696 $css .= "\r\n#wpforo-wrap .wpforo-post .wpf-right .wpforo-post-content {font-size: " . wpforo_setting(
1697 'styles',
1698 'font_size_post_content'
1699 ) . "px!important;}\r\n#wpforo-wrap .wpforo-post .wpf-right .wpforo-post-content p {font-size: " . wpforo_setting(
1700 'styles',
1701 'font_size_post_content'
1702 ) . "px;}";
1703
1704 if( 'bottom' === wpforo_setting( 'posting', 'topic_editor_toolbar_location' ) ) {
1705 $css .= "\r\n
1706 #wpforo #wpforo-wrap .wpf-topic-create .mce-container-body{display: flex; flex-direction: column;}
1707 #wpforo #wpforo-wrap .wpf-topic-create .mce-top-part{order: 1}
1708 #wpforo #wpforo-wrap .wpf-topic-create .wpf-field-wrap > .wpf-extra-fields,
1709 #wpforo #wpforo-wrap .wpforo-portable-form-wrap .wpf-extra-fields,
1710 #wpforo #wpforo-wrap .wpforo-messages-content .wpfpm-main .wpfpm-form-wrapper .wpf-extra-fields{ margin-top: 10px !important; }";
1711 }
1712 if( 'bottom' === wpforo_setting( 'posting', 'reply_editor_toolbar_location' ) ) {
1713 $css .= "\r\n
1714 #wpforo #wpforo-wrap .wpf-post-create .mce-container-body{display: flex; flex-direction: column;}
1715 #wpforo #wpforo-wrap .wpf-post-create .mce-top-part{order: 1}
1716 #wpforo #wpforo-wrap .wpf-post-create .wpf-field-wrap > .wpf-extra-fields,
1717 #wpforo #wpforo-wrap .wpforo-portable-form-wrap .wpf-extra-fields,
1718 #wpforo #wpforo-wrap .wpforo-messages-content .wpfpm-main .wpfpm-form-wrapper .wpf-extra-fields{ margin-top: 10px !important; }";
1719 }
1720 if( wpforo_setting( 'ai', 'assistant_highlight' ) ) {
1721 $css .= "\r\n
1722 #wpforo #wpforo-wrap .wpf-ai-helper-toggle.wpf-ai-highlight{ background:__WPFCOLOR_12__; color:__WPFCOLOR_1__;}
1723 #wpforo #wpforo-wrap .wpf-ai-helper-toggle.wpf-ai-highlight .wpf-ai-sparkle-icon{ fill:__WPFCOLOR_1__;}
1724 #wpforo #wpforo-wrap .wpf-ai-helper-toggle.wpf-ai-highlight:hover{ background:__WPFCOLOR_12__; color:__WPFCOLOR_1__; opacity: 0.85;}";
1725 }
1726 if( $ccss = wpforo_setting( 'styles', 'custom_css' ) ) $css .= "\r\n" . stripslashes( (string) $ccss );
1727
1728 return $css;
1729 }
1730
1731 add_filter( 'wpforo_dynamic_css_filter', 'wpforo_style_options' );
1732
1733 function wpforo_admin_enqueue() {
1734 wp_register_style(
1735 'wpforo-font-awesome',
1736 WPFORO_URL . '/assets/css/font-awesome/css/fontawesome-all.min.css',
1737 false,
1738 '6.1.1'
1739 );
1740 wp_register_style(
1741 'wpforo-iconpicker-css',
1742 WPFORO_URL . '/admin/assets/third-party/iconpicker/fontawesome-iconpicker.min.css',
1743 [ 'wpforo-font-awesome' ],
1744 '2.0.0'
1745 );
1746 wp_register_script(
1747 'wpforo-iconpicker-js',
1748 WPFORO_URL . '/admin/assets/third-party/iconpicker/fontawesome-iconpicker.js',
1749 [ 'jquery' ],
1750 '2.0.0',
1751 true
1752 );
1753 wp_register_style( 'wpforo-admin', WPFORO_URL . '/admin/assets/css/admin.css', false, WPFORO_VERSION );
1754 wp_localize_script( 'wp-color-picker', 'wpColorPickerL10n', [
1755 'clear' => __( 'Clear' ),
1756 'defaultString' => __( 'Default' ),
1757 'pick' => __( 'Select Color' ),
1758 ] );
1759 wp_register_script(
1760 'wpforo-contenthover-addons',
1761 WPFORO_URL . '/admin/assets/js/contenthover/jquery.contenthover.min.js',
1762 [ 'jquery' ],
1763 WPFORO_VERSION,
1764 false
1765 );
1766 wp_register_script(
1767 'wpforo-backend-widgets-js',
1768 WPFORO_URL . '/admin/assets/js/widgets.js',
1769 [ 'jquery' ],
1770 WPFORO_VERSION,
1771 true
1772 );
1773 wp_register_script(
1774 'wpforo-backend-js',
1775 WPFORO_URL . '/admin/assets/js/backend.js',
1776 [ 'jquery' ],
1777 WPFORO_VERSION,
1778 false
1779 );
1780 wp_localize_script( 'wpforo-backend-js', 'wpforo_admin', [
1781 'phrases' => [
1782 'move' => __( 'Move', 'wpforo' ),
1783 'delete' => __( 'Delete', 'wpforo' ),
1784 ],
1785 ] );
1786 WPF()->settings->init_info();
1787 wp_localize_script(
1788 'wpforo-backend-js',
1789 'wpforo',
1790 [
1791 'ajax_url' => wpforo_get_ajax_url(),
1792 'nonces' => wpforo_generate_ajax_nonces(),
1793 'board' => [ 'has_more_boards' => is_wpforo_multiboard() ],
1794 'settings' => [
1795 'info' => [
1796 'core' => WPF()->settings->info->core,
1797 'addons' => WPF()->settings->info->addons,
1798 ],
1799 ],
1800 ]
1801 );
1802 wp_register_style(
1803 'wpforo-deactivation-css',
1804 WPFORO_URL . '/admin/assets/css/deactivation-dialog.css',
1805 [],
1806 WPFORO_VERSION
1807 );
1808 wp_register_script(
1809 'wpforo-deactivation-js',
1810 WPFORO_URL . '/admin/assets/js/deactivation-dialog.js',
1811 [ 'jquery' ],
1812 WPFORO_VERSION
1813 );
1814 wp_localize_script( 'wpforo-deactivation-js', 'wpforo_deactivation_obj', [
1815 'msgReasonRequired' => __( 'Please choose one reasons before sending a feedback!', 'wpforo' ),
1816 'msgReasonDescRequired' => __( 'Please provide more information', 'wpforo' ),
1817 'msgFeedbackHasEmailNoCheckbox' => __(
1818 'With the email address, please check the "I agree to receive email" checkbox to proceed.',
1819 'wpforo'
1820 ),
1821 'msgFeedbackHasCheckboxNoEmail' => __( 'Please fill your email address for feedback', 'wpforo' ),
1822 'msgFeedbackNotValidEmail' => __( 'Your email address is not valid', 'wpforo' ),
1823 'adminUrl' => get_admin_url(),
1824 ] );
1825 wp_register_script( 'wpforo-iris', admin_url( 'js/iris.min.js' ), [
1826 'jquery-ui-draggable',
1827 'jquery-ui-slider',
1828 'jquery-touch-punch',
1829 ], false, true );
1830
1831 // Register AI Features admin assets
1832 wp_register_style(
1833 'wpforo-ai-features',
1834 WPFORO_URL . '/admin/assets/css/ai-features.css',
1835 false,
1836 WPFORO_VERSION
1837 );
1838 wp_register_script(
1839 'wpforo-ai-features-js',
1840 WPFORO_URL . '/admin/assets/js/ai-features.js',
1841 [ 'jquery' ],
1842 WPFORO_VERSION,
1843 true
1844 );
1845
1846 do_action( 'wpforo_admin_register_scripts' );
1847
1848 if( ! empty( $_GET['page'] ) && strpos( (string) $_GET['page'], 'wpforo' ) === 0 ) {
1849 wp_enqueue_style( 'wpforo-admin' );
1850 wp_enqueue_script( 'wpforo-backend-js' );
1851 wp_enqueue_style( 'wpforo-iconpicker-css' );
1852 wp_enqueue_script( 'wpforo-iconpicker-js' );
1853 wp_enqueue_style( 'wpforo-font-awesome' );
1854 wp_enqueue_script( 'jquery' );
1855 wp_enqueue_script( 'jquery-ui-core' );
1856 wp_enqueue_script( 'jquery-ui-widget' );
1857 wp_enqueue_script( 'jquery-ui-mouse' );
1858 wp_enqueue_script( 'jquery-ui-position' );
1859 wp_enqueue_script( 'jquery-ui-draggable' );
1860 wp_enqueue_script( 'jquery-ui-droppable' );
1861 wp_enqueue_script( 'jquery-ui-menu' );
1862 wp_enqueue_script( 'jquery-ui-sortable' );
1863 wp_enqueue_script( 'jquery-color' );
1864 wp_enqueue_script( 'wp-lists' );
1865 if( preg_match( '#^wpforo-(?:\d+-)?forums$#iu', (string) $_GET['page'] ) ) {
1866 if( ! empty( $_GET['action'] ) ) {
1867 //Just for excluding 'nav-menu' js loading//
1868 wp_enqueue_script( 'postbox' );
1869 wp_enqueue_script( 'link' );
1870 wp_enqueue_style( 'wp-color-picker' );
1871 wp_enqueue_script( 'wp-color-picker' );
1872 wp_enqueue_script( 'wp-color-picker-script-handle' );
1873 } else {
1874 wp_enqueue_script( 'nav-menu' );
1875 }
1876 } elseif( preg_match(
1877 '#^wpforo-(?:\d+-)?settings$#iu',
1878 (string) $_GET['page']
1879 ) && ! empty( $_GET['wpf_tab'] ) && $_GET['wpf_tab'] === 'styles' ) {
1880 wp_enqueue_style( 'wp-color-picker' );
1881 wp_enqueue_script( 'wpforo-iris' );
1882 wp_enqueue_script( 'wp-color-picker' );
1883 } elseif( $_GET['page'] === wpforo_prefix_slug( 'dashboard' ) || $_GET['page'] === 'wpforo-overview' ) {
1884 wp_enqueue_script( 'postbox' );
1885 wp_enqueue_script( 'link' );
1886 } elseif( preg_match( '#^wpforo-(?:\d+-)?addons$#iu', (string) $_GET['page'] ) ) {
1887 wp_enqueue_script( 'wpforo-contenthover-addons' );
1888 } elseif( $_GET['page'] === 'wpforo-ai' ) {
1889 wp_enqueue_style( 'wpforo-ai-features' );
1890 wp_enqueue_script( 'wpforo-ai-features-js' );
1891 } elseif( preg_match(
1892 '#^wpforo-(?:\d+-)?settings$#iu',
1893 (string) $_GET['page']
1894 ) && ! empty( $_GET['wpf_tab'] ) && $_GET['wpf_tab'] === 'ai' ) {
1895 // Load AI features scripts on Settings > AI tab for bot user autocomplete
1896 wp_enqueue_style( 'wpforo-ai-features' );
1897 wp_enqueue_script( 'wpforo-ai-features-js' );
1898 }
1899 }
1900 if( ! wpforo_get_option( 'deactivation_dialog_never_show', false, false ) && ( strpos(
1901 wpforo_get_request_uri(),
1902 '/plugins.php'
1903 ) !== false ) ) {
1904 wp_enqueue_style( 'wpforo-deactivation-css' );
1905 wp_enqueue_script( 'wpforo-deactivation-js' );
1906 }
1907
1908 $screen = get_current_screen();
1909 if( ( 'user-edit' === $screen->id || 'profile' === $screen->id ) ) {
1910 wp_enqueue_style( 'wpforo-font-awesome' );
1911 }
1912
1913 if( $screen->id === 'widgets' ) {
1914 wp_enqueue_script( 'wpforo-backend-widgets-js' );
1915 }
1916
1917 do_action( 'wpforo_admin_enqueue_scripts' );
1918 }
1919
1920 add_action( 'admin_enqueue_scripts', 'wpforo_admin_enqueue' );
1921
1922 function wpforo_admin_permalink_notice() {
1923 $permalink_structure = get_option( 'permalink_structure' );
1924 if( ! $permalink_structure ) {
1925 $class = 'notice notice-warning';
1926 $message = __(
1927 'IMPORTANT: wpForo can\'t work with default permalink, please change permalink structure',
1928 'wpforo'
1929 );
1930 printf( '<div class="%1$s"><p>%2$s</p></div>', $class, $message );
1931 }
1932 }
1933
1934 add_action( 'admin_notices', 'wpforo_admin_permalink_notice' );
1935
1936 function wpforo_userform_to_wpuser_html_form( $wp_user ) {
1937 if( is_super_admin() ) {
1938 $userid = 0;
1939 $groupid = 0;
1940 $timezone = '';
1941 $secondary_groupids = [];
1942 if( is_object( $wp_user ) ) {
1943 $userid = $wp_user->ID;
1944 $user = WPF()->member->get_member( $wp_user->ID );
1945 $groupid = $user['groupid'];
1946 $timezone = sanitize_text_field( $user['timezone'] );
1947 $secondary_groupids = $user['secondary_groupids'];
1948 }
1949 ?>
1950 <style>
1951 #wpf-rating-table {
1952 width: 100%;
1953 font-size: 12px;
1954 }
1955
1956 #wpf-rating-table h4 {
1957 margin: 0;
1958 padding: 0;
1959 font-size: 14px;
1960 font-weight: bold;
1961 white-space: nowrap;
1962 }
1963
1964 #wpf-rating-table .wpf-badge-full {
1965 color: #FFFFFF;
1966 white-space: nowrap;
1967 font-size: 15px;
1968 line-height: 16px;
1969 font-weight: bold;
1970 text-align: center;
1971 display: inline-block;
1972 padding: 2px 8px;
1973 min-width: 30px;
1974 }
1975
1976 #wpf-rating-table .wpf-badge-full.wpf-badge-level-6, #wpf-rating-table .wpf-badge-full.wpf-badge-level-7, #wpf-rating-table .wpf-badge-full.wpf-badge-level-8 {
1977 font-size: 18px !important;
1978 }
1979
1980 #wpf-rating-table .wpf-badge-full.wpf-badge-level-9, #wpf-rating-table .wpf-badge-full.wpf-badge-level-10 {
1981 font-size: 22px !important;
1982 }
1983
1984 #wpf-rating-table th, #wpf-rating-table td {
1985 padding: 5px 10px;
1986 text-align: left;
1987 vertical-align: top;
1988 }
1989
1990 #wpf-rating-table tr:nth-child(odd) {
1991 background: #f5f5f5;
1992 }
1993
1994 #wpf-rating-table tr:nth-child(even) {
1995 background: #FFFFFF;
1996 }
1997
1998 #wpf-rating-table th {
1999 text-transform: uppercase;
2000 font-size: 12px;
2001 padding: 10px;
2002 }
2003
2004 .wpforo-profile-table input[type=checkbox] {
2005 width: auto !important;
2006 }
2007
2008 @media screen and (max-width: 700px) {
2009 #wpf-rating-table th, #wpf-rating-table td {
2010 display: table-cell !important;
2011 }
2012 }
2013 </style>
2014 <h2 style="margin-bottom: 30px; margin-top: 50px;"><?php _e( 'Forum Profile Fields - wpForo' ); ?></h2>
2015 <table class="form-table wpforo-profile-table"
2016 style="box-shadow: 1px 1px 6px #cccccc; background: #f7f7f7; margin-bottom: 30px; width: 97%;">
2017 <tr>
2018 <td colspan="2" style="padding: 5px;"></td>
2019 </tr>
2020 <tr class="form-field">
2021 <th scope="row" style="padding: 10px 20px 10px 20px; width: 30%;">
2022 <label for="wpforo_usergroup">
2023 <?php _e( 'Forum - Usergroup', 'wpforo' ); ?>
2024 </label>
2025 <?php if( wpforo_setting( 'authorization', 'role_synch' ) ): ?>
2026 <p class="description" style="font-weight: normal;">
2027 <?php $wpforo_synch_table = admin_url(
2028 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' )
2029 ) ?>
2030 <?php echo sprintf(
2031 __(
2032 'Forum Usergroups are synched with User Roles based on the %s. When you change this user Role the Usergroup is automatically changed according to that table.',
2033 'wpforo'
2034 ),
2035 '<a href="' . $wpforo_synch_table . '" target="_blank">Role-Usergroup synchronization table</a>'
2036 ); ?>
2037 </p>
2038 <?php endif; ?>
2039 </th>
2040 <td style="padding: 15px 20px 10px 20px; vertical-align: top;">
2041 <?php if( wpforo_setting( 'authorization', 'role_synch' ) ): ?>
2042 <select id="wpforo_usergroup" disabled="disabled">
2043 <option value="0"><?php _e( 'Synced with user role', 'wpforo' ); ?></option>
2044 <?php WPF()->usergroup->show_selectbox( $groupid ); ?>
2045 </select>
2046 <input type="hidden" name="wpforo_usergroup" value="<?php echo $groupid; ?>">
2047 &nbsp; <span
2048 style="color: green"><?php _e(
2049 'Role-Usergroup Synchronization is Turned ON!',
2050 'wpforo'
2051 ); ?></span>
2052 <br/>
2053 <p class="description"
2054 style="font-weight: normal; font-size: 13px; line-height: 18px;"><?php _e(
2055 'This user Usergroup is automatically changed according to current Role. If you want to disable Role-Usergroup synchronization and manage Usergroups and User Roles independently, please navigate to <b>Dashboard > wpForo > Settings > Login & Registration</b> admin page and disable "Role-Usergroup Synchronization" option.',
2056 'wpforo'
2057 ); ?></p>
2058 <?php else: ?>
2059 <select id="wpforo_usergroup"
2060 name="wpforo_usergroup"<?php if( wpforo_is_owner( $userid ) || ! current_user_can(
2061 'administrator'
2062 ) ) {
2063 echo ' disabled="disabled"';
2064 } ?>>
2065 <?php WPF()->usergroup->show_selectbox( $groupid ?: WPF()->usergroup->default_groupid ); ?>
2066 </select>
2067 <?php endif; ?>
2068 </td>
2069 </tr>
2070 <tr class="form-field">
2071 <th scope="row" style="padding: 10px 20px 10px 20px;">
2072 <label for="wpforo_usergroup">
2073 <?php _e( 'Forum - Secondary Usergroups', 'wpforo' ); ?>
2074 </label>
2075 </th>
2076 <td style="padding: 15px 20px 10px 20px; vertical-align: top;">
2077 <?php $usergroups = WPF()->usergroup->get_secondary_groups(); ?>
2078 <?php if( ! empty( $usergroups ) ): ?>
2079 <?php foreach( $usergroups as $usergroup ): ?>
2080 <?php if( $usergroup['groupid'] == 1 || $usergroup['groupid'] == 4 ) {
2081 continue;
2082 } //|| $usergroup['groupid'] == $groupid ?>
2083 <label style="min-width: 20%; display: inline-block; padding-bottom: 5px;">
2084 <input type="checkbox"
2085 name="wpforo_secondary_groupids[]"
2086 value="<?php echo intval( $usergroup['groupid'] ) ?>"
2087 <?php checked(
2088 in_array( (int) $usergroup['groupid'], (array) $secondary_groupids, true )
2089 ); ?>>&nbsp;
2090 <?php echo esc_html( $usergroup['name'] ); ?>
2091 </label>
2092 <?php endforeach; ?>
2093 <?php endif; ?>
2094 <input name="wpforo_secondary_groupids[]" value="0" type="hidden">
2095 </td>
2096 </tr>
2097 <tr class="form-field">
2098 <th scope="row" style="padding: 10px 20px 10px 20px;">
2099 <label for="wpforo_usertimezone"><?php _e( 'Forum - User Timezone', 'wpforo' ); ?></label>
2100 </th>
2101 <td style="padding: 15px 20px 10px 20px; vertical-align: top;">
2102 <select name="wpforo_usertimezone" id="wpforo_usertimezone">
2103 <?php echo wp_timezone_choice( $timezone ); ?>
2104 </select>
2105 </td>
2106 </tr>
2107 <?php if( ! empty( $user ) ) : ?>
2108 <tr class="form-field">
2109 <th scope="row" style="padding: 10px 20px 10px 20px;">
2110 <label><?php _e( 'User Reputation', 'wpforo' ); ?></label>
2111 <p class="description"
2112 style="font-weight: normal;"><?php _e(
2113 'By default all members get rating badges and titles based on number of posts. However, using this option you can grant lower or higher rating to certain user (this user). The default member reputation badges, titles and points can be managed in Forums > Settings > Members Tab.',
2114 'wpforo'
2115 ) ?></p>
2116 </th>
2117 <td style="padding: 15px 20px 10px 20px; vertical-align: top;">
2118 <div style="padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px dashed #cccccc;">
2119 <label><input type="radio" id="wpf-user-rating-default"
2120 name="wpforo_use_member_custom_points"
2121 value="0" <?php checked( ! $user['custom_points'] ) ?>> <?php _e(
2122 'Default Rating',
2123 'wpforo'
2124 ) ?></label>
2125 &nbsp;&nbsp;
2126 <label><input type="radio" id="wpf-user-rating-custom"
2127 name="wpforo_use_member_custom_points"
2128 value="1" <?php checked( $user['custom_points'] ) ?>> <?php _e(
2129 'Custom Rating',
2130 'wpforo'
2131 ) ?></label>
2132 </div>
2133
2134 <table id="wpf-rating-table" cellspacing="0" cellpadding="0" border="0"
2135 style="display: block; width: 100%; height: 150px; overflow-y: scroll; hidden; border: 1px solid #ccc; border-top: none; border-bottom: none; <?php if( ! $user['custom_points'] ) echo 'opacity:0.5;' ?>">
2136 <tr>
2137 <th style="text-align: center; width: 5%;">#</th>
2138 <th style="width: 30%"><?php _e( 'Rating Level', 'wpforo' ); ?></th>
2139 <th style="width: 35%"><?php _e( 'Rating Title', 'wpforo' ); ?></th>
2140 <th style="width: 30%;text-align:center;"><?php _e( 'Rating Badge', 'wpforo' ); ?></th>
2141 </tr>
2142 <?php $levels = WPF()->member->levels(); ?>
2143 <?php foreach( $levels as $level ): $points = WPF()->member->rating( $level, 'points' );
2144 $bgx = $level === $user['rating']['level'] ? 'background-color: #feff88' : ''; ?>
2145 <tr>
2146 <td style="text-align: center;<?php echo $bgx ?>"><input type="radio"
2147 name="wpforo_member_custom_points"
2148 id="wpf-user-rating-<?php echo intval(
2149 $points
2150 ) ?>"
2151 value="<?php echo intval(
2152 $points
2153 ) ?>" <?php checked(
2154 $level === $user['rating']['level']
2155 ) ?>></td>
2156 <td style="<?php echo $bgx ?>"><h4><label
2157 for="wpf-user-rating-<?php echo intval( $points ) ?>"><?php _e(
2158 'Level',
2159 'wpforo'
2160 ); ?><?php echo esc_html( $level ) ?></label>
2161 </h4></td>
2162 <td style="<?php echo $bgx ?>"><?php echo WPF()->member->rating(
2163 $level,
2164 'title'
2165 ) ?></td>
2166 <td style="text-align:center;<?php echo $bgx ?>">
2167 <div class="wpf-badge-full wpf-badge-level-<?php echo esc_attr( $level ) ?>"
2168 style="color:<?php echo WPF()->member->rating(
2169 $level,
2170 'color'
2171 ) ?>;"><?php echo WPF()->member->rating_badge( $level, 'full' ); ?></div>
2172 </td>
2173 </tr>
2174 <?php endforeach; ?>
2175 </table>
2176 </td>
2177 </tr>
2178 <?php endif; ?>
2179 <tr>
2180 <td colspan="2" style="padding: 5px;"></td>
2181 </tr>
2182 </table>
2183 <script>
2184 jQuery(document).ready(function ($) {
2185 $('#wpf-user-rating-default').change(function () {if (this.checked) {$('#wpf-rating-table').css('opacity', 0.5);}});
2186 $('#wpf-user-rating-custom').change(function () {if (this.checked) { $('#wpf-rating-table').css('opacity', 1);}});
2187 });
2188 </script>
2189 <?php
2190 }
2191 }
2192
2193 add_action( 'user_new_form', 'wpforo_userform_to_wpuser_html_form' );
2194 add_action( 'show_user_profile', 'wpforo_userform_to_wpuser_html_form' );
2195 add_action( 'edit_user_profile', 'wpforo_userform_to_wpuser_html_form' );
2196
2197 add_action( 'register_form', function() {
2198 wp_nonce_field( 'wpforo_user_register', '_wpfnonce' );
2199 }, 21 );
2200
2201 function wpforo_do_hook_user_register( $userid ) {
2202 WPF()->member->synchronize_user( $userid );
2203 if( wpfval( $_POST, 'wpfreg' ) ) {
2204 $data = $_POST;
2205 $data['userid'] = $userid;
2206 $data['wpfreg'] = wpforo_clear_array( $data['wpfreg'], [
2207 'user_login',
2208 'user_email',
2209 'user_pass1',
2210 'user_pass2',
2211 ], 'key' );
2212 WPF()->member->update( $data, 'full', false );
2213 }
2214 }
2215
2216 add_action( 'user_register', 'wpforo_do_hook_user_register', 10, 1 );
2217
2218 function wpforo_do_hook_update_profile( $userid ) {
2219 if( $userid ) {
2220 if( current_user_can( 'create_users' ) || current_user_can( 'edit_user' ) ) {
2221 if( wpfval( $_POST, 'wpforo_usergroup' ) || wpfkey( $_POST, 'wpforo_usertimezone' ) ) {
2222 $member = wpforo_member( $userid );
2223 $can_change_own_rating = true;
2224 if( wpfval( $member, 'userid' ) ) {
2225 $groupid = $member['groupid'];
2226 $secondary_groupids = $member['secondary_groupids'];
2227 if( current_user_can( 'administrator' ) ) {
2228 if( wpfval( $_POST, 'wpforo_usergroup' ) ) {
2229 if( $userid != 1 && ! wpforo_is_owner( $userid ) && current_user_can( 'administrator' ) ) {
2230 $groupid = intval( $_POST['wpforo_usergroup'] );
2231 }
2232 }
2233 if( wpfval( $_POST, 'wpforo_secondary_groupids' ) ) {
2234 if( ! empty( $_POST['wpforo_secondary_groupids'] ) ) {
2235 $secondary_groupids = array_filter(
2236 array_map( 'intval', $_POST['wpforo_secondary_groupids'] )
2237 );
2238 }
2239 }
2240 } else {
2241 if( wpforo_is_owner( $userid ) ) {
2242 $can_change_own_rating = false;
2243 }
2244 }
2245
2246 $custom_points = ( $can_change_own_rating && wpfval(
2247 $_POST,
2248 'wpforo_use_member_custom_points'
2249 ) ) ? (int) wpfval( $_POST, 'wpforo_member_custom_points' ) : 0;
2250
2251 $args = [
2252 'groupid' => intval( $groupid ),
2253 'about' => wpforo_kses( $_POST['description'], 'user_description' ),
2254 'timezone' => ( isset( $_POST['wpforo_usertimezone'] ) ? sanitize_text_field(
2255 $_POST['wpforo_usertimezone']
2256 ) : '' ),
2257 'secondary_groupids' => $secondary_groupids,
2258 'custom_points' => $custom_points,
2259 ];
2260 WPF()->member->update_profile_fields( $userid, $args, false );
2261
2262 if( ! wpforo_is_owner( $userid ) ) {
2263 WPF()->member->inactive_to_active( $userid );
2264 }
2265 }
2266 }
2267 }
2268 }
2269 }
2270
2271 add_action( 'personal_options_update', 'wpforo_do_hook_update_profile' );
2272 add_action( 'edit_user_profile_update', 'wpforo_do_hook_update_profile' );
2273
2274 function wpforo_avatar( $avatar, $id_or_email, $size, $default, $alt ) {
2275 if( ! wpforo_setting( 'profiles', 'replace_avatar' ) ) {
2276 return $avatar;
2277 }
2278 $user = false;
2279 if( wpforo_is_id( $id_or_email ) ) {
2280 $id = (int) $id_or_email;
2281 $user = get_user_by( 'id', $id );
2282 } elseif( is_object( $id_or_email ) ) {
2283 if( ! empty( $id_or_email->user_id ) ) {
2284 $id = (int) $id_or_email->user_id;
2285 $user = get_user_by( 'id', $id );
2286 } elseif( ! empty( $id_or_email->ID ) ) {
2287 $id = (int) $id_or_email->ID;
2288 $user = get_user_by( 'id', $id );
2289 }
2290 } else {
2291 $user = get_user_by( 'email', $id_or_email );
2292 }
2293
2294 if( $user && is_object( $user ) ) {
2295 if( $src = WPF()->member->get_avatar_url( $user->data->ID ) ) {
2296 $avatar = "<img alt='" . esc_attr( $alt ) . "' src='" . esc_url(
2297 (string) $src
2298 ) . "' class='avatar avatar-" . esc_attr( $size ) . " photo' height='" . esc_attr(
2299 $size
2300 ) . "' width='" . esc_attr( $size ) . "' />";
2301 }
2302 }
2303
2304 return $avatar;
2305 }
2306
2307 add_filter( 'get_avatar', 'wpforo_avatar', 10, 5 );
2308
2309 function wpforo_pre_get_avatar_data( $args, $id_or_email ) {
2310 if( wpforo_setting( 'profiles', 'replace_avatar' ) ) {
2311 $key = [ 'wpforo_pre_get_avatar_data', $id_or_email ];
2312 if( WPF()->ram_cache->exists( $key ) ) {
2313 $args['url'] = WPF()->ram_cache->get( $key );
2314 } else {
2315 $user = false;
2316 if( is_object( $id_or_email ) && isset( $id_or_email->comment_ID ) ) {
2317 $id_or_email = get_comment( $id_or_email );
2318 }
2319 // Process the user identifier.
2320 if( wpforo_is_id( $id_or_email ) ) {
2321 $user = get_user_by( 'id', absint( $id_or_email ) );
2322 } elseif( is_string( $id_or_email ) ) {
2323 if( ! strpos( (string) $id_or_email, '@md5.gravatar.com' ) ) {
2324 $user = get_user_by( 'email', $id_or_email );
2325 }
2326 } elseif( $id_or_email instanceof WP_User ) {
2327 // User Object
2328 $user = $id_or_email;
2329 } elseif( $id_or_email instanceof WP_Post ) {
2330 // Post Object
2331 $user = get_user_by( 'id', (int) $id_or_email->post_author );
2332 } elseif( function_exists( 'is_avatar_comment_type' ) && $id_or_email instanceof WP_Comment ) {
2333 if( is_avatar_comment_type( get_comment_type( $id_or_email ) ) ) {
2334 if( ! empty( $id_or_email->user_id ) ) {
2335 $user = get_user_by( 'id', (int) $id_or_email->user_id );
2336 }
2337 if( ( ! $user || is_wp_error( $user ) ) && ! empty( $id_or_email->comment_author_email ) ) {
2338 $user = get_user_by( 'email', $id_or_email->comment_author_email );
2339 }
2340 }
2341 }
2342
2343 if( $user && is_object( $user ) ) {
2344 if( $avatar_url = WPF()->member->get_avatar_url( $user->data->ID ) ) {
2345 WPF()->ram_cache->set( $key, $avatar_url );
2346 $args['url'] = $avatar_url;
2347 }
2348 }
2349 }
2350 }
2351
2352 return $args;
2353 }
2354
2355 add_filter( 'pre_get_avatar_data', 'wpforo_pre_get_avatar_data', 10, 2 );
2356
2357 function wpforo_move_uploded_default_attach( $argname, $return = 'html' ) {
2358 if( ! empty( $_FILES[ $argname ] ) && ! empty( $_FILES[ $argname ]['name'] ) ) {
2359 $name = sanitize_file_name( $_FILES[ $argname ]['name'] ); //myimg.png
2360 $type = sanitize_mime_type( $_FILES[ $argname ]['type'] ); //image/png
2361 $tmp_name = sanitize_text_field( $_FILES[ $argname ]['tmp_name'] ); //D:\wamp\tmp\php986B.tmp
2362 $error = intval( $_FILES[ $argname ]['error'] ); //0
2363 $size = intval( $_FILES[ $argname ]['size'] ); //6112
2364
2365 $phpFileUploadErrors = [
2366 0 => 'There is no error, the file uploaded with success',
2367 1 => 'The uploaded file size is too big',
2368 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
2369 3 => 'The uploaded file was only partially uploaded',
2370 4 => 'No file was uploaded',
2371 6 => 'Missing a temporary folder',
2372 7 => 'Failed to write file to disk.',
2373 8 => 'A PHP extension stopped the file upload.',
2374 ];
2375
2376 if( $error ) {
2377 WPF()->notice->add( $phpFileUploadErrors[ $error ], 'error' );
2378
2379 return '';
2380 } elseif( $size > wpforo_setting( 'posting', 'max_upload_size' ) ) {
2381 WPF()->notice->add( 'The uploaded file size is too big', 'error' );
2382
2383 return '';
2384 }
2385
2386 if( function_exists( 'pathinfo' ) ) {
2387 $ext = pathinfo( $name, PATHINFO_EXTENSION );
2388 } else {
2389 $ext = substr( strrchr( (string) $name, '.' ), 1 );
2390 }
2391 $ext = strtolower( (string) $ext );
2392 $mime_types = get_allowed_mime_types();
2393 $mime_types = array_flip( $mime_types );
2394 if( ! empty( $mime_types ) ) {
2395 $allowed_types = implode( '|', $mime_types );
2396 $expld = explode( '|', $allowed_types );
2397 if( ! in_array( $ext, $expld ) ) {
2398 WPF()->notice->add( 'File type is not allowed', 'error' );
2399
2400 return '';
2401 }
2402 if( ! WPF()->perm->can_attach_file_type( $ext ) ) {
2403 WPF()->notice->add( 'You are not allowed to attach this file type', 'error' );
2404
2405 return '';
2406 }
2407 }
2408
2409 $attach_dir = WPF()->folders['default_attachments']['dir'];
2410 $attach_url = WPF()->folders['default_attachments']['url//'];
2411 if( ! is_dir( $attach_dir ) ) wp_mkdir_p( $attach_dir );
2412
2413 $fnm = pathinfo( $name, PATHINFO_FILENAME );
2414 $fnm = str_replace( ' ', '-', $fnm );
2415 while( strpos( (string) $fnm, '--' ) !== false ) {
2416 $fnm = str_replace( '--', '-', $fnm );
2417 }
2418 $fnm = preg_replace( "/[^-a-zA-Z0-9_]/", "", (string) $fnm );
2419 $fnm = trim( (string) $fnm, "-" );
2420 $fnm_empty = ! $fnm;
2421
2422 $file_name = $fnm . "." . $ext;
2423
2424 $attach_fname = time() . ( ! $fnm_empty ? '-' : '' ) . $file_name;
2425 $attach_path = $attach_dir . DIRECTORY_SEPARATOR . $attach_fname;
2426
2427 if( is_dir( $attach_dir ) && move_uploaded_file( $tmp_name, $attach_path ) ) {
2428 $attach_id = wpforo_insert_to_media_library( $attach_path, $fnm );
2429 if( $return === 'html' ) {
2430 return "\r\n" . '<div id="wpfa-' . $attach_id . '" class="wpforo-attached-file"><a class="wpforo-default-attachment" href="' . esc_url(
2431 (string) $attach_url . '/' . $attach_fname
2432 ) . '" target="_blank" title="' . esc_attr(
2433 basename( (string) $name )
2434 ) . '"><i class="fas fa-paperclip"></i>&nbsp;' . esc_html(
2435 basename( (string) $name )
2436 ) . '</a></div>';
2437 } else {
2438 return [
2439 'fileurl' => $attach_url . '/' . $attach_fname,
2440 'filename' => basename( (string) $name ),
2441 'mediaid' => $attach_id,
2442 ];
2443 }
2444 } else {
2445 WPF()->notice->add( 'Can\'t upload file', 'error' );
2446 }
2447 }
2448
2449 return '';
2450 }
2451
2452 function wpforo_add_default_attachment( $args ) {
2453 if( ! empty( $_FILES['attachfile'] ) && ! empty( $_FILES['attachfile']['name'] ) ) {
2454 if( WPF()->perm->can_attach( wpfval( $args, 'forumid' ) ) ) {
2455 if( $default_attach = wpforo_move_uploded_default_attach( 'attachfile' ) ) {
2456 $args['body'] .= $default_attach;
2457 $args['has_attach'] = 1;
2458 }
2459 }
2460 }
2461
2462 return $args;
2463 }
2464
2465 function wpforo_delete_attachment( $attach_post_id ) {
2466 if( ! $attach_post_id ) {
2467 return;
2468 }
2469 $posts = WPF()->db->get_results(
2470 "SELECT `postid`, `body` FROM `" . WPF()->tables->posts . "` WHERE `body` LIKE '%wpfa-" . intval(
2471 $attach_post_id
2472 ) . "%'",
2473 ARRAY_A
2474 );
2475 if( ! empty( $posts ) || is_array( $posts ) ) {
2476 foreach( $posts as $post ) {
2477 $body = preg_replace(
2478 '|<div[^><]*id=[\'\"]+wpfa-' . $attach_post_id . '[\'\"]+[^><]*>.+?</div>|is',
2479 '<div class="wpforo-attached-file wpfa-deleted">' . wpforo_phrase(
2480 'Attachment removed',
2481 false
2482 ) . '</div>',
2483 (string) $post['body']
2484 );
2485 if( $body ) {
2486 WPF()->db->query(
2487 "UPDATE `" . WPF()->tables->posts . "` SET `body` = '" . esc_sql(
2488 $body
2489 ) . "' WHERE `postid` = " . intval( $post['postid'] )
2490 );
2491 }
2492 }
2493 }
2494 }
2495
2496 function wpforo_default_attachments_filter( $text ) {
2497 if( preg_match_all(
2498 '#<a[^<>]*class=[\'"]wpforo-default-attachment[\'"][^<>]*href=[\'"]([^\'"]+)[\'"][^<>]*>[\r\n\t\s\0]*(?:<i[^<>]*>[\r\n\t\s\0]*</i>[\r\n\t\s\0]*)?([^<>]*)</a>#iu',
2499 (string) $text,
2500 $matches,
2501 PREG_SET_ORDER
2502 ) ) {
2503 foreach( $matches as $match ) {
2504 $attach_html = '';
2505 if( file_exists( wpforo_fix_upload_dir( $match[1] ) ) ) {
2506 if( ! WPF()->perm->forum_can( 'va' ) || ! WPF()->usergroup->can( 'caa' ) ) {
2507 $attach_html .= '<br/><div class="wpfa-item wpfa-file"><a class="attach_cant_view" style="cursor: pointer;"><span style="color: #666;">' . wpforo_phrase(
2508 'Attachment',
2509 false
2510 ) . ' : </span> ' . urldecode( basename( $match[2] ) ) . '</a></div>';
2511 }
2512 }
2513 if( $attach_html ) {
2514 $attach_html .= '<br/>';
2515 $text = str_replace( $match[0], $attach_html, $text );
2516 }
2517 }
2518 }
2519
2520 return $text;
2521 }
2522
2523 function wpforo_content_enable_do_shortcode() {
2524 if( wpforo_setting( 'posting', 'content_do_shortcode' ) ) {
2525 add_filter( 'wpforo_content_after', 'do_shortcode', 20 );
2526 }
2527 }
2528
2529 add_action( 'wpforo_after_init', 'wpforo_content_enable_do_shortcode' );
2530
2531 add_filter( 'wpforo_content_after', function( $text ) {
2532 return wpforo_strip_shortcodes( $text, true );
2533 }, 999 );
2534
2535 add_filter( 'wpforo_body_text_filter', function( $text ) {
2536 if( apply_filters( 'wpforo_allow_replace_3asterisk', true ) ) {
2537 $text = preg_replace(
2538 '#\*{3}([^*]+?)\*{3}#',
2539 '<span style="color: red; font-weight: bold;">$1</span>',
2540 (string) $text
2541 );
2542 }
2543
2544 return $text;
2545 } );
2546
2547 add_action( 'wp_footer', function() { WPF()->cache->create(); } );
2548
2549 add_filter( 'retrieve_password_message', function( $message, $key, $user_login, $user_data ) {
2550 $reset_password_url = '';
2551 if( preg_match( wpforo_get_wprp_url_pattern(), (string) $message, $match ) ) {
2552 if( wpforo_setting( 'authorization', 'use_our_lostpassword_url' ) ) {
2553 $reset_password_url = wpforo_resetpassword_url( $key, $user_login );
2554 $message = str_replace( $match[0], $reset_password_url, $message );
2555 } else {
2556 $reset_password_url = $match[0];
2557 }
2558 }
2559
2560 if( wpforo_setting( 'email', 'overwrite_reset_password_email' ) && $reset_password_url ) {
2561 $message = str_replace(
2562 [ '[user_login]', '[reset_password_url]' ],
2563 [ $user_login, $reset_password_url, ],
2564 wpforo_setting( 'email', 'reset_password_email_message' )
2565 );
2566 $message = _wpforo_apply_email_shortcodes( $message, [ 'user' => [ 'userid' => $user_data->ID ] ] );
2567 add_filter( 'wp_mail_content_type', '__wpforo_set_html_content_type', 999 );
2568 }
2569
2570 return $message;
2571 }, 999, 4 );
2572
2573 function wpforo_user_field_shortcode_to_value( $shortcode, $userid = null, $implode = true, $separator = ',' ) {
2574 $value = null;
2575
2576 if( $shortcode && ( $field = preg_replace(
2577 '#^\s*\[?\s*(?:user_|owner_)?(?:fields_)?([^\[\]]+?)\s*]?\s*$#iu',
2578 '$1',
2579 (string) $shortcode
2580 ) ) ) {
2581 if( ! $userid ) $userid = WPF()->current_userid;
2582 if( in_array(
2583 $field,
2584 [ 'login', 'pass', 'nicename', 'email', 'url', 'registered', 'activation_key', 'status' ],
2585 true
2586 ) ) {
2587 $field = 'user_' . $field;
2588 }
2589 $value = wpforo_member( $userid, $field );
2590 if( $implode && wpforo_is_array_of_scalars( $value ) ) $value = implode( $separator, $value );
2591 }
2592
2593 return $value;
2594 }
2595
2596 function wpforo_forum_field_shortcode_to_value( $shortcode, $forumid, $implode = true, $separator = ',' ) {
2597 $value = null;
2598
2599 if( $forumid ) {
2600 if( $shortcode && ( $field = preg_replace(
2601 '#^\s*\[?\s*(?:forum_)?(?:fields_)?([^\[\]]+?)\s*]?\s*$#iu',
2602 '$1',
2603 (string) $shortcode
2604 ) ) ) {
2605 if( $field === 'link' ) {
2606 $value = sprintf(
2607 '<a target="_blank" href="%1$s">%2$s</a>',
2608 esc_url( (string) _wpforo_forum( $forumid, 'url' ) ),
2609 sanitize_text_field( _wpforo_forum( $forumid, 'title' ) )
2610 );
2611 $value = stripslashes( (string) $value );
2612 } else {
2613 $value = _wpforo_forum( $forumid, $field );
2614 if( $implode && wpforo_is_array_of_scalars( $value ) ) $value = implode( $separator, $value );
2615 }
2616 }
2617 }
2618
2619 return $value;
2620 }
2621
2622 function wpforo_topic_field_shortcode_to_value( $shortcode, $topicid, $implode = true, $separator = ',' ) {
2623 $value = null;
2624
2625 if( $topicid ) {
2626 if( $shortcode && ( $field = preg_replace(
2627 '#^\s*\[?\s*(?:topic_)?(?:fields_)?([^\[\]]+?)\s*]?\s*$#iu',
2628 '$1',
2629 (string) $shortcode
2630 ) ) ) {
2631 if( $field === 'link' ) {
2632 $value = sprintf(
2633 '<a target="_blank" href="%1$s">%2$s</a>',
2634 esc_url( (string) _wpforo_topic( $topicid, 'short_url' ) ),
2635 sanitize_text_field( _wpforo_topic( $topicid, 'title' ) )
2636 );
2637 $value = stripslashes( $value );
2638 } else {
2639 $value = _wpforo_topic( $topicid, $field );
2640 if( $implode && wpforo_is_array_of_scalars( $value ) ) $value = implode( $separator, $value );
2641 }
2642 }
2643 }
2644
2645 return $value;
2646 }
2647
2648 function wpforo_post_field_shortcode_to_value( $shortcode, $postid, $implode = true, $separator = ',' ) {
2649 $value = null;
2650
2651 if( $postid ) {
2652 if( $shortcode && ( $field = preg_replace(
2653 '#^\s*\[?\s*(?:post_)?(?:fields_)?([^\[\]]+?)\s*]?\s*$#iu',
2654 '$1',
2655 (string) $shortcode
2656 ) ) ) {
2657 if( $field === 'link' ) {
2658 $value = sprintf(
2659 '<a target="_blank" href="%1$s">%2$s</a>',
2660 esc_url( (string) _wpforo_post( $postid, 'short_url' ) ),
2661 sanitize_text_field( _wpforo_post( $postid, 'title' ) )
2662 );
2663 $value = stripslashes( $value );
2664 } else {
2665 $value = _wpforo_post( $postid, $field );
2666 if( $implode && wpforo_is_array_of_scalars( $value ) ) $value = implode( $separator, $value );
2667 }
2668 }
2669 }
2670
2671 return $value;
2672 }
2673
2674 function wpforo_new_user_notification_email_admin( $wp_new_user_notification_email_admin, $user, $blogname ) {
2675 if( wpforo_setting( 'email', 'overwrite_new_user_notification_admin' ) ) {
2676 $wp_new_user_notification_email_admin['subject'] = str_replace(
2677 '[blogname]',
2678 '[' . $blogname . ']',
2679 wpforo_setting(
2680 'email',
2681 'wp_new_user_notification_email_admin_subject'
2682 )
2683 );
2684 $wp_new_user_notification_email_admin['message'] = str_replace(
2685 '[blogname]',
2686 $blogname,
2687 wpforo_setting(
2688 'email',
2689 'wp_new_user_notification_email_admin_message'
2690 )
2691 );
2692 add_filter( 'wp_mail_content_type', '__wpforo_set_html_content_type', 999 );
2693 }
2694 $userid = $user->ID;
2695 $wp_new_user_notification_email_admin['message'] = preg_replace_callback(
2696 '#\[[^\[\]]+?]#isu',
2697 function( $match ) use ( $userid ) {
2698 $value = wpforo_user_field_shortcode_to_value( $match[0], $userid );
2699 if( ! $value || ! ( is_string( $value ) || is_numeric( $value ) ) ) $value = '';
2700
2701 return $value;
2702 },
2703 (string) $wp_new_user_notification_email_admin['message']
2704 );
2705
2706 return $wp_new_user_notification_email_admin;
2707 }
2708
2709 add_filter( 'wp_new_user_notification_email_admin', 'wpforo_new_user_notification_email_admin', 999, 3 );
2710
2711 function wpforo_new_user_notification_email( $wp_new_user_notification_email, $user, $blogname ) {
2712 $set_password_url = '';
2713 if( preg_match( wpforo_get_wprp_url_pattern(), (string) $wp_new_user_notification_email['message'], $match ) ) {
2714 if( wpforo_setting( 'authorization', 'use_our_lostpassword_url' ) ) {
2715 $set_password_url = wpforo_resetpassword_url( $match['key'], $user->user_login );
2716 $wp_new_user_notification_email['message'] = str_replace(
2717 $match[0],
2718 $set_password_url,
2719 $wp_new_user_notification_email['message']
2720 );
2721 } else {
2722 $set_password_url = $match[0];
2723 }
2724 }
2725
2726 if( wpforo_setting( 'email', 'overwrite_new_user_notification' ) && $set_password_url ) {
2727 $wp_new_user_notification_email['subject'] = str_replace(
2728 '[blogname]',
2729 '[' . $blogname . ']',
2730 wpforo_setting(
2731 'email',
2732 'wp_new_user_notification_email_subject'
2733 )
2734 );
2735 $wp_new_user_notification_email['message'] = str_replace(
2736 [ '[user_login]', '[set_password_url]' ],
2737 [ $user->user_login, $set_password_url ],
2738 wpforo_setting( 'email', 'wp_new_user_notification_email_message' )
2739 );
2740 add_filter( 'wp_mail_content_type', '__wpforo_set_html_content_type', 999 );
2741 }
2742
2743 return $wp_new_user_notification_email;
2744 }
2745
2746 add_filter( 'wp_new_user_notification_email', 'wpforo_new_user_notification_email', 999, 3 );
2747
2748 function wpforo_get_wprp_url_pattern() {
2749 return '#(?:<\s*)?https?://\S+?wp-login\.php(?:[?&]action=rp|[?&]login=[^?&=\s]+)?[?&]key=(?<key>[^?&=\s]+)(?:[?&]action=rp|[?&]login=[^?&=\s]+)?(?:\s*>)?#isu';
2750 }
2751
2752 function wpforo_synch_user_roles( $userid ) {
2753
2754 $user = get_userdata( $userid );
2755
2756 if( ! empty( $user ) && ! empty( $user->roles ) ) {
2757 $role_usergroups = WPF()->usergroup->get_role_usergroup_relation();
2758
2759 if( ! empty( $role_usergroups ) ) {
2760 $append_second_groups = apply_filters( 'wpforo_synch_user_roles_append_secondary_groups', false );
2761 $ug_users_array = WPF()->usergroup->build_users_groupid_array( $role_usergroups, [ $user ] );
2762
2763 if( wpfval( $ug_users_array, 'user_prime_group' ) ) {
2764 $userid_groupids = current( $ug_users_array['user_prime_group'] );
2765 if( ! empty( $userid_groupids ) ) {
2766 $groupid = current( $userid_groupids );
2767 if( $groupid ) WPF()->member->set_groupid( $userid, $groupid );
2768 }
2769 }
2770
2771 if( wpfval( $ug_users_array, 'user_second_groups' ) ) {
2772 foreach( $ug_users_array['user_second_groups'] as $userid => $secondary_usergroups ) {
2773 if( ! empty( $secondary_usergroups ) ) {
2774 if( $append_second_groups ) {
2775 // Merges current secondary groups with new secondary groups
2776 WPF()->member->append_secondary_groupids( $userid, $secondary_usergroups );
2777 } else {
2778 // Removes current secondary groups and sets new secondary groups
2779 WPF()->member->set_secondary_groupids( $userid, $secondary_usergroups );
2780 }
2781 }
2782 }
2783 } elseif( ! $append_second_groups && ! wpfval( $ug_users_array, 'user_second_groups' ) ) {
2784 WPF()->member->set_secondary_groupids( $userid, [] );
2785 }
2786
2787 delete_user_meta( intval( $userid ), '_wpf_member_obj' );
2788 }
2789 }
2790 }
2791
2792
2793 function wpforo_synch_roles() {
2794 if( ! current_user_can( 'manage_options' ) ) {
2795 wp_send_json_error( [ 'message' => 'Permission denied' ] );
2796 }
2797
2798 $status = [
2799 'progress' => 0,
2800 'error' => 0,
2801 'start' => 0,
2802 'step' => 1,
2803 'left' => 0,
2804 'total' => 0,
2805 'id' => 0,
2806 ];
2807
2808 $wpforo_synch_roles_data = isset( $_POST['wpforo_synch_roles_data'] ) ? $_POST['wpforo_synch_roles_data'] : '';
2809
2810 if( $wpforo_synch_roles_data ) {
2811 parse_str( $wpforo_synch_roles_data, $data );
2812 check_ajax_referer( 'wpforo_synch_roles', 'checkthis' );
2813 $limit = apply_filters( 'wpforo_synch_roles_step_limit', 20 );
2814 $append_second_groups = apply_filters( 'wpforo_synch_roles_append_secondary_groups', true );
2815 $success = false;
2816 $group_users = [];
2817 $user_prime_group = [];
2818 $user_second_groups = [];
2819 $options = wpforo_get_option( 'synch_roles' );
2820 $step = isset( $data['wpf-step'] ) ? intval( $data['wpf-step'] ) : 1;
2821 $left = isset( $data['wpf-left-users'] ) ? intval( $data['wpf-left-users'] ) : 0;
2822 $id = isset( $data['wpf-start-id'] ) ? intval( $data['wpf-start-id'] ) : 0;
2823 $start = isset( $data['wpf-start'] ) ? intval( $data['wpf-start'] ) : 0;
2824 $ug_role = isset( $data['wpf_synch_roles'] ) ? $data['wpf_synch_roles'] : [];
2825 if( ! empty( $ug_role ) ) {
2826 /////////////////////////////////////////////////////
2827 /// Update Roles of Usergroups in usergroups table
2828 WPF()->usergroup->set_ug_roles( $ug_role );
2829 /////////////////////////////////////////////////////
2830 if( ! is_array( $options ) || $left > 0 ) {
2831 $args = [ 'orderby' => 'ID', 'order' => 'ASC', 'offset' => $start, 'number' => $limit ];
2832 $users = get_users( $args );
2833 ////////////////////////////////////////////////////////////////////////////////////
2834 /// Builds associative array of Usergroup ID => Users ID array()
2835 $ug_users_array = WPF()->usergroup->build_users_groupid_array( $ug_role, $users, true );
2836 ////////////////////////////////////////////////////////////////////////////////////
2837 if( wpfval( $ug_users_array, 'group_users' ) ) {
2838 $group_users = $ug_users_array['group_users'];
2839 }
2840 if( wpfval( $ug_users_array, 'user_prime_group' ) ) {
2841 $user_prime_group = $ug_users_array['user_prime_group'];
2842 }
2843 if( wpfval( $ug_users_array, 'user_second_groups' ) ) {
2844 foreach( $ug_users_array['user_second_groups'] as $userid => $secondary_usergroups ) {
2845 if( ! empty( $secondary_usergroups ) ) {
2846 if( $append_second_groups ) {
2847 // Merges current secondary groups with new secondary groups
2848 WPF()->member->append_secondary_groupids( $userid, $secondary_usergroups );
2849 } else {
2850 // Removes current secondary groups and sets new secondary groups
2851 WPF()->member->set_secondary_groupids( $userid, $secondary_usergroups );
2852 }
2853 }
2854 }
2855 }
2856 if( ! empty( $group_users ) ) {
2857 /////////////////////////////////////////////////////////////////
2858 /// Updates users Usergroup Ids in profiles table
2859 $return = WPF()->usergroup->set_users_groupid( $group_users );
2860 /////////////////////////////////////////////////////////////////
2861 $success = ( wpfval( $return, 'success' ) ) ? $return['success'] : $success;
2862 $status['error'] = ( wpfval( $return, 'error' ) ) ? $return['error'] : $status['error'];
2863 if( $success ) {
2864 end( $users );
2865 $key = key( $users );
2866 $status['id'] = $users[ $key ]->ID;
2867 $result = count_users();
2868 $status['total'] = ( wpfval( $result, 'total_users' ) ) ? intval(
2869 $result['total_users']
2870 ) : 0;
2871 $status['start'] = $step * $limit;
2872 $status['left'] = ( $status['total'] > $status['start'] ) ? ( $status['total'] - $status['start'] ) : 0;
2873 $status['step'] = $step + 1;
2874 $progress = ( $status['total'] > $status['start'] ) ? ( $status['start'] * 100 ) / $status['total'] : 100;
2875 $status['progress'] = round( $progress );
2876 if( $progress == 100 ) {
2877 wpforo_delete_option( 'synch_roles' );
2878 } else {
2879 wpforo_update_option( 'synch_roles', $status );
2880 }
2881 }
2882 } else {
2883 $status['total'] = 0;
2884 $status['start'] = 0;
2885 $status['left'] = 0;
2886 $status['step'] = 1;
2887 $status['progress'] = 100;
2888 wpforo_delete_option( 'synch_roles' );
2889 }
2890 } else {
2891 $result = count_users();
2892 $status['total'] = ( wpfval( $result, 'total_users' ) ) ? intval( $result['total_users'] ) : 0;
2893 $status['start'] = $step * $limit;
2894 $status['left'] = 0;
2895 $status['step'] = 1;
2896 $status['progress'] = 100;
2897 wpforo_delete_option( 'synch_roles' );
2898 }
2899 }
2900 }
2901
2902 if( intval( wpfval( $status, 'progress' ) ) === 100 ) {
2903 WPF()->notice->add( 'Role-Usergroup synchronization is complete!', 'success' );
2904 }
2905
2906 wp_die( wp_json_encode( $status ) );
2907 }
2908
2909 add_action( 'wp_ajax_wpforo_synch_roles', 'wpforo_synch_roles' );
2910
2911
2912 function wpforo_update_usergroup_on_role_change( $userid, $new_role, $old_roles = [] ) {
2913 if( wpforo_setting( 'authorization', 'role_synch' ) ) {
2914 wpforo_synch_user_roles( $userid );
2915 }
2916 }
2917
2918 add_action( 'add_user_role', 'wpforo_update_usergroup_on_role_change', 99, 2 );
2919 add_action( 'set_user_role', 'wpforo_update_usergroup_on_role_change', 99, 3 );
2920
2921
2922 function wpforo_wp_admin_bar_red_circle_number( $number ) {
2923 $number = intval( $number );
2924 if( $number ) {
2925 return sprintf(
2926 '<div class="wp-core-ui wp-ui-notification wpforo-menu-notification-counter">%1$d</div>',
2927 $number
2928 );
2929 }
2930
2931 return '';
2932 }
2933
2934 function wpforo_get_memb_attention_count(): int {
2935 return WPF()->member->get_count( [ 'p.status' => [ 'banned', 'inactive' ] ] );
2936 }
2937
2938 function wpforo_get_admin_bar_numbers(): array {
2939 $all_count = 0;
2940 $mod_count = WPF()->post->unapproved_count();
2941 $all_count += $mod_count;
2942
2943 return compact( 'all_count', 'mod_count' );
2944 }
2945
2946 function wpforo_admin_bar_menu( $wp_admin_bar ) {
2947 $admin_bar_numbers = wpforo_get_admin_bar_numbers();
2948
2949 if( wpforo_current_user_is( 'admin' ) ) {
2950 $args = [
2951 'id' => 'new-forum',
2952 'title' => '&#43;&nbsp;&nbsp;' . __( 'Add New Forum', 'wpforo' ),
2953 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) . '&action=add' ),
2954 'parent' => 'new-content',
2955 ];
2956 $wp_admin_bar->add_node( $args );
2957 $args = [
2958 'id' => 'new-ugroup',
2959 'title' => '&#43;&nbsp;&nbsp;' . __( 'Add New User Group', 'wpforo' ),
2960 'href' => admin_url(
2961 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) . '&wpfaction=wpforo_usergroup_save_form'
2962 ),
2963 'parent' => 'new-content',
2964 ];
2965 $wp_admin_bar->add_node( $args );
2966 $args = [
2967 'id' => 'new-phrase',
2968 'title' => '&#43;&nbsp;&nbsp;' . __( 'Add New Phrase', 'wpforo' ),
2969 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) . '&wpfaction=phrase_add_form' ),
2970 'parent' => 'new-content',
2971 ];
2972 $wp_admin_bar->add_node( $args );
2973 }
2974
2975 $args = [
2976 'id' => 'wpforo-home',
2977 'title' => __( 'Visit Forum', 'wpforo' ),
2978 'href' => wpforo_home_url(),
2979 'parent' => 'wpf-community',
2980 // 'meta' => [ 'target' => '_blank' ]
2981 ];
2982 $wp_admin_bar->add_node( $args );
2983
2984 if( wpforo_current_user_is( 'admin' ) || WPF()->usergroup->can( 'mf' ) || WPF()->usergroup->can( 'ms' ) || WPF()->usergroup->can( 'vm' ) || WPF()->usergroup->can( 'mp' ) || WPF()->usergroup->can(
2985 'aum'
2986 ) || WPF()->usergroup->can( 'vmg' ) || WPF()->usergroup->can( 'mth' ) ) {
2987 $args = [
2988 'id' => 'wpf-community',
2989 'title' => __( 'Forum Dashboard', 'wpforo' ) . wpforo_wp_admin_bar_red_circle_number(
2990 $admin_bar_numbers['all_count']
2991 ),
2992 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ),
2993 ];
2994 $wp_admin_bar->add_node( $args );
2995 }
2996 if( WPF()->usergroup->can( 'mf' ) || wpforo_current_user_is( 'admin' ) ) {
2997 $args = [
2998 'id' => 'wpf-forums',
2999 'title' => '' . __( 'Forums', 'wpforo' ),
3000 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) ),
3001 'parent' => 'wpf-community',
3002 ];
3003 $wp_admin_bar->add_node( $args );
3004 $args = [
3005 'id' => 'wpf-new-forum',
3006 'title' => '' . __( 'Add New Forum', 'wpforo' ),
3007 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) . '&action=add' ),
3008 'parent' => 'wpf-forums',
3009 ];
3010 $wp_admin_bar->add_node( $args );
3011 }
3012 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3013 $args = [
3014 'id' => 'wpf-settings',
3015 'title' => '' . __( 'Settings', 'wpforo' ),
3016 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'settings' ) ),
3017 'parent' => 'wpf-community',
3018 ];
3019 $wp_admin_bar->add_node( $args );
3020 }
3021 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3022 $args = [
3023 'id' => 'wpf-ai',
3024 'title' => '' . __( 'AI Features', 'wpforo' ),
3025 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'ai' ) ),
3026 'parent' => 'wpf-community',
3027 ];
3028 $wp_admin_bar->add_node( $args );
3029 }
3030 if( WPF()->usergroup->can( 'mt' ) || wpforo_current_user_is( 'admin' ) ) {
3031 $args = [
3032 'id' => 'wpf-tools',
3033 'title' => '' . __( 'Tools', 'wpforo' ),
3034 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) ),
3035 'parent' => 'wpf-community',
3036 ];
3037 $wp_admin_bar->add_node( $args );
3038 }
3039 if( WPF()->usergroup->can( 'aum' ) || wpforo_current_user_is( 'admin' ) ) {
3040 $args = [
3041 'id' => 'wpf-moderation',
3042 'title' => '' . __( 'Moderation', 'wpforo' ) . wpforo_wp_admin_bar_red_circle_number(
3043 $admin_bar_numbers['mod_count']
3044 ),
3045 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'moderations' ) ),
3046 'parent' => 'wpf-community',
3047 ];
3048 $wp_admin_bar->add_node( $args );
3049 }
3050 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3051 $args = [
3052 'id' => 'wpforo-accesses',
3053 'title' => '' . __( 'Accesses', 'wpforo' ),
3054 'href' => admin_url( 'admin.php?page=wpforo-accesses' ),
3055 'parent' => 'wpf-community',
3056 ];
3057 $wp_admin_bar->add_node( $args );
3058 $args = [
3059 'id' => 'wpforo-new-accesses',
3060 'title' => '' . __( 'Add New Forum Access', 'wpforo' ),
3061 'href' => admin_url( 'admin.php?page=wpforo-accesses&wpfaction=wpforo_access_save_form' ),
3062 'parent' => 'wpforo-accesses',
3063 ];
3064 $wp_admin_bar->add_node( $args );
3065 }
3066 if( WPF()->usergroup->can( 'vm' ) || wpforo_current_user_is( 'admin' ) ) {
3067 $args = [
3068 'id' => 'wpf-members',
3069 'title' => '' . __( 'Members', 'wpforo' ) . wpforo_wp_admin_bar_red_circle_number(
3070 wpforo_get_memb_attention_count()
3071 ),
3072 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'members' ) ),
3073 'parent' => 'wpf-community',
3074 ];
3075 $wp_admin_bar->add_node( $args );
3076 }
3077 if( WPF()->usergroup->can( 'vmg' ) || wpforo_current_user_is( 'admin' ) ) {
3078 $args = [
3079 'id' => 'wpf-usergroups',
3080 'title' => '' . __( 'Usergroups', 'wpforo' ),
3081 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) ),
3082 'parent' => 'wpf-community',
3083 ];
3084 $wp_admin_bar->add_node( $args );
3085 $args = [
3086 'id' => 'wpf-new-ugroup',
3087 'title' => '' . __( 'Add New Usergroup', 'wpforo' ),
3088 'href' => admin_url(
3089 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) . '&wpfaction=wpforo_usergroup_save_form'
3090 ),
3091 'parent' => 'wpf-usergroups',
3092 ];
3093 $wp_admin_bar->add_node( $args );
3094 }
3095 if( WPF()->usergroup->can( 'mp' ) || wpforo_current_user_is( 'admin' ) ) {
3096 $args = [
3097 'id' => 'wpf-phrases',
3098 'title' => '' . __( 'Phrases', 'wpforo' ),
3099 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) ),
3100 'parent' => 'wpf-community',
3101 ];
3102 $wp_admin_bar->add_node( $args );
3103 $args = [
3104 'id' => 'wpf-new-phrase',
3105 'title' => '' . __( 'Add New Phrase', 'wpforo' ),
3106 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) . '&wpfaction=phrase_add_form' ),
3107 'parent' => 'wpf-phrases',
3108 ];
3109 $wp_admin_bar->add_node( $args );
3110 }
3111 if( WPF()->usergroup->can( 'mth' ) || wpforo_current_user_is( 'admin' ) ) {
3112 $args = [
3113 'id' => 'wpf-themes',
3114 'title' => '' . __( 'Themes', 'wpforo' ),
3115 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'themes' ) ),
3116 'parent' => 'wpf-community',
3117 ];
3118 $wp_admin_bar->add_node( $args );
3119 }
3120 if( wpforo_current_user_is( 'admin' ) ) {
3121 $args = [
3122 'id' => 'wpf-addons',
3123 'title' => '' . __( 'Addons', 'wpforo' ),
3124 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'addons' ) ),
3125 'parent' => 'wpf-community',
3126 ];
3127 $wp_admin_bar->add_node( $args );
3128 }
3129 }
3130
3131 function wpforo_multiboard_admin_bar_menu( $wp_admin_bar ) {
3132 $bds_bar_numbers = [];
3133 if( wpforo_current_user_is( 'admin' ) ) {
3134 $args = [
3135 'id' => 'wpforo-new-content',
3136 'title' => 'wpForo',
3137 'href' => admin_url( 'admin.php?page=wpforo-overview' ),
3138 'parent' => 'new-content',
3139 ];
3140 $wp_admin_bar->add_node( $args );
3141
3142 if( $boardids = WPF()->board->get_active_boardids() ) {
3143 foreach( $boardids as $boardid ) {
3144 WPF()->change_board( $boardid );
3145 $current = WPF()->board->get_current();
3146 $bds_bar_numbers[ $boardid ] = wpforo_get_admin_bar_numbers();
3147
3148 $menuid = 'wpforo-new-content-' . $current['slug'];
3149 $args = [
3150 'id' => $menuid,
3151 'title' => $current['title'],
3152 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ),
3153 'parent' => 'wpforo-new-content',
3154 ];
3155 $wp_admin_bar->add_node( $args );
3156 ## ---------------------------------------------------------------------------------- ####
3157 $args = [
3158 'id' => $menuid . 'new-forum',
3159 'title' => '' . __( 'Add New Forum', 'wpforo' ),
3160 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) . '&action=add' ),
3161 'parent' => $menuid,
3162 ];
3163 $wp_admin_bar->add_node( $args );
3164 $args = [
3165 'id' => $menuid . 'new-ugroup',
3166 'title' => '' . __( 'Add New User Group', 'wpforo' ),
3167 'href' => admin_url(
3168 'admin.php?page=' . wpforo_prefix_slug( 'usergroups' ) . '&wpfaction=wpforo_usergroup_save_form'
3169 ),
3170 'parent' => $menuid,
3171 ];
3172 $wp_admin_bar->add_node( $args );
3173 $args = [
3174 'id' => $menuid . 'new-phrase',
3175 'title' => '' . __( 'Add New Phrase', 'wpforo' ),
3176 'href' => admin_url(
3177 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) . '&wpfaction=phrase_add_form'
3178 ),
3179 'parent' => $menuid,
3180 ];
3181 $wp_admin_bar->add_node( $args );
3182
3183 }
3184 }
3185 }
3186
3187 if( wpforo_current_user_is( 'admin' ) || WPF()->usergroup->can( 'mf' ) || WPF()->usergroup->can( 'ms' ) || WPF()->usergroup->can( 'vm' ) || WPF()->usergroup->can( 'mp' ) || WPF()->usergroup->can(
3188 'aum'
3189 ) || WPF()->usergroup->can( 'vmg' ) || WPF()->usergroup->can( 'mth' ) ) {
3190 $bds_bar_all = 0;
3191 foreach( $bds_bar_numbers as $x ) $bds_bar_all += $x['all_count'];
3192 $args = [
3193 'id' => 'wpforo',
3194 'title' => 'wpForo' . wpforo_wp_admin_bar_red_circle_number( $bds_bar_all ),
3195 'href' => admin_url( 'admin.php?page=wpforo-overview' ),
3196 ];
3197 $wp_admin_bar->add_node( $args );
3198
3199
3200 if( $boardids = WPF()->board->get_active_boardids() ) {
3201 foreach( $boardids as $boardid ) {
3202 WPF()->change_board( $boardid );
3203 $current = WPF()->board->get_current();
3204
3205 $menuid = 'wpforo-' . $current['slug'];
3206 $args = [
3207 'id' => $menuid,
3208 'title' => '' . $current['title'] . ' (' . strtok(
3209 $current['locale'],
3210 '_'
3211 ) . ')' . wpforo_wp_admin_bar_red_circle_number( $bds_bar_numbers[ $boardid ]['all_count'] ),
3212 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) ),
3213 'parent' => 'wpforo',
3214 ];
3215 $wp_admin_bar->add_node( $args );
3216
3217 ## ---------------------------------------------------------------------------------- ####
3218
3219 $args = [
3220 'id' => $menuid . '-home',
3221 'title' => '' . __( 'Visit Forum', 'wpforo' ),
3222 'href' => wpforo_home_url(),
3223 'parent' => $menuid,
3224 // 'meta' => [ 'target' => '_blank' ]
3225 ];
3226 $wp_admin_bar->add_node( $args );
3227
3228 if( WPF()->usergroup->can( 'mf' ) || wpforo_current_user_is( 'admin' ) ) {
3229 $args = [
3230 'id' => $menuid . '-forums',
3231 'title' => '' . __( 'Forums', 'wpforo' ),
3232 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) ),
3233 'parent' => $menuid,
3234 ];
3235 $wp_admin_bar->add_node( $args );
3236 $args = [
3237 'id' => $menuid . '-new-forum',
3238 'title' => '' . __( 'Add New Forum', 'wpforo' ),
3239 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'forums' ) . '&action=add' ),
3240 'parent' => $menuid . '-forums',
3241 ];
3242 $wp_admin_bar->add_node( $args );
3243 }
3244 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3245 $args = [
3246 'id' => $menuid . '-settings',
3247 'title' => '' . __( 'Settings', 'wpforo' ),
3248 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'settings' ) ),
3249 'parent' => $menuid,
3250 ];
3251 $wp_admin_bar->add_node( $args );
3252 }
3253 if( WPF()->usergroup->can( 'mt' ) || wpforo_current_user_is( 'admin' ) ) {
3254 $args = [
3255 'id' => $menuid . '-tools',
3256 'title' => '' . __( 'Tools', 'wpforo' ),
3257 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) ),
3258 'parent' => $menuid,
3259 ];
3260 $wp_admin_bar->add_node( $args );
3261 }
3262 if( WPF()->usergroup->can( 'aum' ) || wpforo_current_user_is( 'admin' ) ) {
3263 $args = [
3264 'id' => $menuid . '-moderation',
3265 'title' => '' . __(
3266 'Moderation',
3267 'wpforo'
3268 ) . wpforo_wp_admin_bar_red_circle_number( $bds_bar_numbers[ $boardid ]['mod_count'] ),
3269 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'moderations' ) ),
3270 'parent' => $menuid,
3271 ];
3272 $wp_admin_bar->add_node( $args );
3273 }
3274 if( WPF()->usergroup->can( 'mp' ) || wpforo_current_user_is( 'admin' ) ) {
3275 $args = [
3276 'id' => $menuid . '-phrases',
3277 'title' => '' . __( 'Phrases', 'wpforo' ),
3278 'href' => admin_url( 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) ),
3279 'parent' => $menuid,
3280 ];
3281 $wp_admin_bar->add_node( $args );
3282 $args = [
3283 'id' => $menuid . '-new-phrase',
3284 'title' => '' . __( 'Add New Phrase', 'wpforo' ),
3285 'href' => admin_url(
3286 'admin.php?page=' . wpforo_prefix_slug( 'phrases' ) . '&wpfaction=phrase_add_form'
3287 ),
3288 'parent' => $menuid . '-phrases',
3289 ];
3290 $wp_admin_bar->add_node( $args );
3291 }
3292 }
3293 }
3294
3295 ##### -- ##### ----- $ ----- ###
3296
3297 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3298 $args = [
3299 'id' => 'wpforo-boards',
3300 'title' => '' . __( 'Boards', 'wpforo' ),
3301 'href' => admin_url( 'admin.php?page=wpforo-boards' ),
3302 'parent' => 'wpforo',
3303 ];
3304 $wp_admin_bar->add_node( $args );
3305 $args = [
3306 'id' => 'wpforo-new-board',
3307 'title' => '' . __( 'Add New Board', 'wpforo' ),
3308 'href' => admin_url( 'admin.php?page=wpforo-boards&wpfaction=wpforo_board_save_form' ),
3309 'parent' => 'wpforo-boards',
3310 ];
3311 $wp_admin_bar->add_node( $args );
3312 }
3313 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3314 $args = [
3315 'id' => 'wpforo-accesses',
3316 'title' => '' . __( 'Accesses', 'wpforo' ),
3317 'href' => admin_url( 'admin.php?page=wpforo-accesses' ),
3318 'parent' => 'wpforo',
3319 ];
3320 $wp_admin_bar->add_node( $args );
3321 $args = [
3322 'id' => 'wpforo-new-accesses',
3323 'title' => '' . __( 'Add New Forum Access', 'wpforo' ),
3324 'href' => admin_url( 'admin.php?page=wpforo-accesses&wpfaction=wpforo_access_save_form' ),
3325 'parent' => 'wpforo-accesses',
3326 ];
3327 $wp_admin_bar->add_node( $args );
3328 }
3329 if( WPF()->usergroup->can( 'vmg' ) || wpforo_current_user_is( 'admin' ) ) {
3330 $args = [
3331 'id' => 'wpforo-usergroups',
3332 'title' => '' . __( 'Usergroups', 'wpforo' ),
3333 'href' => admin_url( 'admin.php?page=wpforo-usergroups' ),
3334 'parent' => 'wpforo',
3335 ];
3336 $wp_admin_bar->add_node( $args );
3337 $args = [
3338 'id' => 'wpforo-new-ugroup',
3339 'title' => '' . __( 'Add New Usergroup', 'wpforo' ),
3340 'href' => admin_url( 'admin.php?page=wpforo-usergroups&wpfaction=wpforo_usergroup_save_form' ),
3341 'parent' => 'wpforo-usergroups',
3342 ];
3343 $wp_admin_bar->add_node( $args );
3344 }
3345 if( WPF()->usergroup->can( 'vm' ) || wpforo_current_user_is( 'admin' ) ) {
3346 $args = [
3347 'id' => 'wpforo-members',
3348 'title' => '' . __( 'Members', 'wpforo' ) . wpforo_wp_admin_bar_red_circle_number(
3349 wpforo_get_memb_attention_count()
3350 ),
3351 'href' => admin_url( 'admin.php?page=wpforo-members' ),
3352 'parent' => 'wpforo',
3353 ];
3354 $wp_admin_bar->add_node( $args );
3355 }
3356 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3357 $args = [
3358 'id' => 'wpforo-base-settings',
3359 'title' => '' . __( 'Settings', 'wpforo' ),
3360 'href' => admin_url( 'admin.php?page=wpforo-base-settings' ),
3361 'parent' => 'wpforo',
3362 ];
3363 $wp_admin_bar->add_node( $args );
3364 }
3365 if( WPF()->usergroup->can( 'ms' ) || wpforo_current_user_is( 'admin' ) ) {
3366 $args = [
3367 'id' => 'wpforo-ai',
3368 'title' => '' . __( 'AI Features', 'wpforo' ),
3369 'href' => admin_url( 'admin.php?page=wpforo-ai' ),
3370 'parent' => 'wpforo',
3371 ];
3372 $wp_admin_bar->add_node( $args );
3373 }
3374 if( WPF()->usergroup->can( 'mth' ) || wpforo_current_user_is( 'admin' ) ) {
3375 $args = [
3376 'id' => 'wpforo-themes',
3377 'title' => '' . __( 'Themes', 'wpforo' ),
3378 'href' => admin_url( 'admin.php?page=wpforo-themes' ),
3379 'parent' => 'wpforo',
3380 ];
3381 $wp_admin_bar->add_node( $args );
3382 }
3383 if( wpforo_current_user_is( 'admin' ) ) {
3384 $args = [
3385 'id' => 'wpforo-addons',
3386 'title' => '' . __( 'Addons', 'wpforo' ),
3387 'href' => admin_url( 'admin.php?page=wpforo-addons' ),
3388 'parent' => 'wpforo',
3389 ];
3390 $wp_admin_bar->add_node( $args );
3391 }
3392 }
3393 }
3394
3395 add_action( 'admin_bar_menu', function( $wp_admin_bar ) {
3396 if( is_wpforo_multiboard() ) {
3397 wpforo_multiboard_admin_bar_menu( $wp_admin_bar );
3398 WPF()->change_board();
3399 } else {
3400 wpforo_admin_bar_menu( $wp_admin_bar );
3401 }
3402 echo '<style>
3403 #wpadminbar .wpforo-menu-notification-counter,
3404 #wpadminbar .wpforo-menu-notification-indicator{
3405 background-color: #d63638;
3406 color: #ffffff;
3407 }
3408
3409 #wpadminbar .wpforo-menu-notification-counter{
3410 display: inline-block;
3411 min-width: 18px;
3412 height: 18px;
3413 border-radius: 50%;
3414 margin: 5px 5px 0 5px;
3415 vertical-align: top;
3416 font-size: 11px;
3417 line-height: 1.6;
3418 text-align: center;
3419 }
3420 </style>';
3421 }, 999 );
3422
3423 function wpforo_tag_search() {
3424 $s = wp_unslash( $_GET['q'] );
3425 $tag_separator = ( strpos( $s, '،' ) !== false ) ? '،' : ',';
3426 $tag_separator = apply_filters( 'wpforo_tag_separator', $tag_separator );
3427 if( false !== strpos( (string) $s, $tag_separator ) ) {
3428 $s = str_replace( $tag_separator, ',', $s );
3429 $s = explode( ',', $s );
3430 $s = $s[ count( $s ) - 1 ];
3431 }
3432 $s = trim( (string) $s );
3433 $tag_search_min_chars = apply_filters( 'wpforo_tag_search_min_chars', 2 );
3434 if( wpforo_strlen( $s ) >= $tag_search_min_chars ) {
3435 $limit = wpforo_setting( 'tags', 'suggest_limit' );
3436 $results = WPF()->db->get_col(
3437 "SELECT `tag` FROM `" . WPF()->tables->tags . "` WHERE `tag` LIKE '" . esc_sql( $s ) . "%' LIMIT " . $limit
3438 );
3439 if( ! empty( $results ) ) {
3440 echo implode( "\n", $results );
3441 }
3442 }
3443 wp_die();
3444 }
3445
3446 add_action( 'wp_ajax_wpforo_tag_search', 'wpforo_tag_search' );
3447 add_action( 'wp_ajax_nopriv_wpforo_tag_search', 'wpforo_tag_search' );
3448
3449 function wpforo_add_to_footer() {
3450 if( WPF()->current_object['load_tinymce'] ) {
3451 wp_enqueue_editor();
3452 }
3453 }
3454
3455 add_action( 'wpforo_bottom_hook', 'wpforo_add_to_footer' );
3456
3457 function wpforo_check_notifications() {
3458 $data = [ 'alerts' => 0, 'notifications' => '' ];
3459 if( is_user_logged_in() && wpforo_setting( 'notifications', 'notifications' ) ) {
3460 $data['alerts'] = count( WPF()->activity->notifications );
3461 if( wpfval( $_POST, 'getdata' ) ) {
3462 $data['notifications'] = WPF()->activity->notifications_list( false );
3463 }
3464 wp_send_json_success( $data );
3465 }
3466 wp_send_json_error( $data );
3467 }
3468
3469 add_action( 'wp_ajax_wpforo_notifications', 'wpforo_check_notifications' );
3470
3471 function wpforo_can_display_recaptcha_note() {
3472 $d = wpforo_is_admin() ? 'recaptcha_backend_note' : 'recaptcha_note';
3473
3474 return ! WPF()->dissmissed[ $d ] && current_user_can( 'administrator' ) && ! wp_is_mobile() && wpforo_setting(
3475 'authorization',
3476 'user_register'
3477 ) && ! wpforo_setting( 'authorization', 'register_url' ) && ! wpforo_is_recaptcha_configured();
3478 }
3479
3480 add_action( 'wpforo_header_hook', 'wpforo_recaptcha_note' );
3481 function wpforo_recaptcha_note() {
3482 if( wpforo_can_display_recaptcha_note() ) {
3483 ?>
3484 <div class="wpforo-rcn-wrap">
3485 <div class="wpforo-rcn-body">
3486 <span class="wpforo-rcn-head"><i
3487 class="fas fa-user-secret"></i> <?php wpforo_phrase(
3488 'Protect your forum from spam user registration!'
3489 ); ?></span>
3490 <?php printf(
3491 wpforo_phrase(
3492 'wpForo has not found any protection solution against spam user registration on the forum registration form. Please %1$s and enable the %2$s antibot protection in %3$s or install other alternative %4$s to avoid registration of spam users.',
3493 false,
3494 'native'
3495 ),
3496 '<a class="wpf-rcnl" href="' . admin_url(
3497 'admin.php?page=' . wpforo_prefix_slug(
3498 'base-settings'
3499 ) . '&wpf_tab=recaptcha#wpf-settings-tab'
3500 ) . '" target="_blank">' . wpforo_phrase( 'configure', false, 'lower' ) . '</a>',
3501 '<a class="wpf-rcngl" href="https://developers.google.com/recaptcha" target="_blank">Google reCAPTCHA</a>',
3502 '<a href="' . admin_url(
3503 'admin.php?page=' . wpforo_prefix_slug(
3504 'base-settings'
3505 ) . '&wpf_tab=recaptcha#wpf-settings-tab'
3506 ) . '">' . wpforo_phrase( 'Settings &gt; Spam Protection Tab', false ) . '</a>',
3507 '<a class="wpf-rcnwl" href="https://wordpress.org/plugins/search/spam+users/" target="_blank">' . wpforo_phrase(
3508 'WordPress plugin',
3509 false
3510 ) . '</a>'
3511 )
3512 ?>
3513 </div>
3514 <div class="wpforo-rcn-footer">
3515 <div class="wpforo-rcn-info">
3516 <?php wpforo_phrase(
3517 'This notification is only visible for the website administrators. It will be automatically disabled once some antispam solution is enabled. If you don\'t use wpForo registration form or you\'re sure, that you have an antispam solution just click the [dismiss] button.'
3518 ); ?>
3519 </div>
3520 <div class="wpforo-rcn-dismiss">
3521 <span class="wpforo-rcn-dismiss-button"
3522 wpf-tooltip="<?php wpforo_phrase( 'I got it, please dismiss this message' ) ?>"
3523 wpf-tooltip-size="long"><?php wpforo_phrase( 'Dismiss' ) ?></span>
3524 </div>
3525 </div>
3526 </div>
3527 <?php
3528 }
3529 }
3530
3531 //add_action('admin_notices', 'wpforo_admin_notice_recaptcha');
3532 function wpforo_admin_notice_recaptcha() {
3533 if( wpforo_can_display_recaptcha_note() ) {
3534 wp_enqueue_script( 'wpforo-backend-js' );
3535 $class = 'notice notice-error is-dismissible';
3536 $message = __(
3537 'IMPORTANT! The forum registration form is probably under risk of spam attacks. Please configure wpForo built-in %s antibot for registration form to avoid spam registrations. If you don\'t use the forum registration form or you are sure that your registration forms are secured, just click on (x) button to dismiss this message.',
3538 'wpforo'
3539 );
3540 $message = sprintf(
3541 $message,
3542 '<a href="' . admin_url(
3543 'admin.php?page=' . wpforo_prefix_slug( 'tools' ) . '&tab=antispam#wpf-recaptcha'
3544 ) . '" target="_blank" style="text-decoration:none;">' . __(
3545 'Google reCAPTCHA',
3546 'wpforo'
3547 ) . '</a>'
3548 );
3549 printf( '<div id="wpforo-admin-notice-recaptcha" class="%1$s"><p>%2$s</p></div>', $class, $message );
3550 }
3551 }
3552
3553 function wpforo_is_recaptcha_configured() {
3554 return wpforo_setting( 'recaptcha', 'wpf_reg_form' ) && wpforo_setting( 'recaptcha', 'site_key' ) && wpforo_setting(
3555 'recaptcha',
3556 'secret_key'
3557 );
3558 }
3559
3560
3561 /*add_action( 'plugins_loaded', function() {
3562 if( ! (int) wpfval( WPF()->dissmissed, 'poll_version_is_old' ) && function_exists( 'WPF_POLL' ) ) {
3563 if( version_compare( WPFORO_VERSION, '1.7.7', '>' ) && version_compare( WPFOROPOLL_VERSION, '1.0.5', '<=' ) ) {
3564 remove_action( 'widgets_init', [ WPF_POLL(), 'init_widgets' ] );
3565 remove_action( 'wpforo_before_init', [ WPF_POLL(), 'init' ] );
3566
3567 WPF()->dissmissed['poll_version_is_old'] = 0;
3568 wpforo_update_option( 'dissmissed', WPF()->dissmissed );
3569 } else {
3570 WPF()->dissmissed['poll_version_is_old'] = 1;
3571 wpforo_update_option( 'dissmissed', WPF()->dissmissed );
3572 }
3573 }
3574 } );*/
3575
3576 add_action( 'admin_notices', function() {
3577 if( wpfkey( WPF()->dissmissed, 'poll_version_is_old' ) && ! (int) WPF()->dissmissed['poll_version_is_old'] ) {
3578 $class = 'notice notice-error';
3579 $message = '<div style="font-size: 16px; padding: 10px 0;"><strong>' . __(
3580 'wpForo Polls addon is disabled!',
3581 'wpforo'
3582 ) . '</strong><p style="font-size:15px; margin-bottom:0;">' . __(
3583 ' Your addon version is not compatible with the current version of wpForo. Please update the addon or downgrade wpForo to 1.7.7',
3584 'wpforo'
3585 ) . '</p></div>';
3586 $message .= ' <a href="' . admin_url(
3587 wp_nonce_url(
3588 'admin.php?page=' . wpforo_prefix_slug( 'dashboard' ) . '&wpfaction=dissmiss_poll_version_is_old',
3589 'wpforo-dissmiss-poll-version-is-old'
3590 )
3591 ) . '">[' . __( 'dismiss', 'wpforo' ) . ']</a>';
3592 printf( '<div class="%1$s"><p>%2$s</p></div>', $class, $message );
3593 }
3594 } );
3595
3596 add_action( 'wpforo_update_option', function() {
3597 wpforo_clean_folder(
3598 WPF()->folders['cache']['dir'] . DIRECTORY_SEPARATOR . 'item' . DIRECTORY_SEPARATOR . 'option'
3599 );
3600 } );
3601
3602 add_action( 'wpforo_after_init', function() {
3603 add_action( 'wp_ajax_dismiss_wpforo_addon_note', [ WPF()->notice, 'dismissAddonNote' ] );
3604 add_action( 'admin_notices', [ WPF()->notice, 'addonNote' ] );
3605 } );
3606
3607 add_action( 'wpforo_after_init', function() {
3608 add_action( 'wp_ajax_dismiss_wpforo_cache_conflict_note', [ WPF()->notice, 'dismissCacheConflict' ] );
3609 } );
3610
3611 add_action( 'admin_enqueue_scripts', 'wpforo_cat_cover_js' );
3612
3613 function wpforo_cat_cover_js() {
3614 if( wpfval( $_GET, 'page' ) === wpforo_prefix_slug( 'forums' ) && ! did_action( 'wp_enqueue_media' ) ) {
3615 wp_enqueue_media();
3616 }
3617 }
3618
3619 function wpforo_esc_html( $var ) {
3620 if( is_scalar( $var ) ) {
3621 $var = esc_html( $var );
3622 } else {
3623 $var = wpforo_esc_html( $var );
3624 }
3625
3626 return $var;
3627 }
3628
3629 add_action( 'wpforo_bottom_hook', 'wpforo_debug' );
3630 function wpforo_debug() {
3631 if( wpforo_setting( 'general', 'debug_mode' ) ) : ?>
3632 <div id="wpforo-debug" style="display:none">
3633 <h4>Super Globals</h4>
3634 <textarea style="width:100%; height:300px;">
3635 Requests: <?php //print_r( array_map( 'wpforo_esc_html', $_REQUEST ) ); ?>
3636 Server: <?php //print_r( $_SERVER ); ?>
3637 </textarea>
3638 <h4>Options and Features</h4>
3639 <textarea style="width:100%; height:300px;">
3640 <?php echo @ 'route: ' . WPF()->board->route . "\r\n";
3641 echo @ 'use_home_url: ' . WPF()->board->get_current( 'is_standalone' ) . "\r\n";
3642 echo @ 'url: ' . wpforo_home_url() . "\r\n";
3643 echo @ 'pageid:' . WPF()->board->get_current( 'pageid' ) . "\r\n";
3644 echo @ 'default_groupid: ' . WPF()->usergroup->default_groupid . "\r\n";
3645 @print_r( WPF()->tpl->theme ) . "\r\n";
3646 ?>
3647 </textarea>
3648 </div>
3649 <?php
3650 endif;
3651 }
3652
3653 add_filter( 'wpforo_topic_list_args', function( $args ) {
3654 if( wpforo_setting( 'topics', 'include_subforums_topics' ) ) {
3655 $forumid = (int) $args['forumid'];
3656 $forumids = WPF()->forum->get_forumid_and_childids( $forumid );
3657 unset( $args['forumid'] );
3658 $args['forumids'] = $forumids;
3659 }
3660
3661 return $args;
3662 } );
3663
3664 function wpf_body_wp_encode_emoji( $post ) {
3665 if( wpfkey( $post, 'title' ) ) $post['title'] = wp_encode_emoji( $post['title'] );
3666 if( wpfkey( $post, 'body' ) ) $post['body'] = wp_encode_emoji( $post['body'] );
3667
3668 return $post;
3669 }
3670
3671 add_filter( 'wpforo_add_post_data_filter', 'wpf_body_wp_encode_emoji' );
3672 add_filter( 'wpforo_edit_post_data_filter', 'wpf_body_wp_encode_emoji' );
3673 add_filter( 'wpforo_add_topic_data_filter', 'wpf_body_wp_encode_emoji' );
3674 add_filter( 'wpforo_edit_topic_data_filter', 'wpf_body_wp_encode_emoji' );
3675
3676 // Feature Introduction Modal - AJAX dismiss handler (must be in hooks.php, not admin/index.php, because wpforo_is_admin() excludes AJAX)
3677 add_action( 'wp_ajax_wpforo_dismiss_feature_intro', function() {
3678 \wpforo\classes\FeatureIntro::ajax_dismiss_static();
3679 } );
3680
3681 // Feature Introduction Modal - redirect to wpForo Overview after update/activation
3682 add_action( 'admin_init', function() {
3683 if( wp_doing_ajax() || wp_doing_cron() ) return;
3684 if( is_network_admin() ) return;
3685 if( isset( $_GET['activate-multi'] ) ) return;
3686 if( ! current_user_can( 'manage_options' ) ) return;
3687
3688 $intro_version = \wpforo\classes\FeatureIntro::CURRENT_INTRO;
3689 $version_option = \wpforo\classes\FeatureIntro::VERSION_OPTION;
3690 $last_intro = get_option( $version_option, '' );
3691
3692 if( version_compare( $last_intro, $intro_version, '<' ) ) {
3693 update_option( $version_option, $intro_version );
3694 // Don't redirect if already on a wpForo page
3695 if( isset( $_GET['page'] ) && strpos( sanitize_text_field( $_GET['page'] ), 'wpforo' ) !== false ) return;
3696 wp_safe_redirect( admin_url( 'admin.php?page=wpforo-overview' ) );
3697 exit;
3698 }
3699 }, 1 );
3700