PluginProbe
wpForo Forum / 3.1.6
wpForo Forum v3.1.6
3.1.6 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 All 138 releases
wpforo / wpforo.php

wpforo.php in wpForo Forum 3.1.6, at wpforo.php

1,657 lines 62.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * Plugin Name: wpForo
4 * Plugin URI: https://wpforo.com
5 * Description: WordPress Forum plugin. wpForo is the only AI powered forum solution for your community. Modern design and 5 forum layouts.
6 * Author: gVectors Team
7 * Author URI: https://gvectors.com/
8 * Version: 3.1.6
9 * Requires at least: 5.2
10 * Requires PHP: 7.1
11 * Text Domain: wpforo
12 * Domain Path: /languages
13 */
14
15 namespace wpforo;
16
17 define( 'WPFORO_VERSION', '3.1.6' );
18
19 //Exit if accessed directly
20 if( ! defined( 'ABSPATH' ) ) exit;
21
22 define( 'WPFORO_DIR', rtrim( plugin_dir_path( __FILE__ ), '/' ) );
23 define( 'WPFORO_URL', rtrim( plugins_url( '', __FILE__ ), '/' ) );
24 define( 'WPFORO_BASENAME', plugin_basename( __FILE__ ) ); //wpforo/wpforo.php
25
26 require_once WPFORO_DIR . "/autoload.php";
27
28 use stdClass;
29 use wpdb;
30 use wpforo\classes\Actions;
31 use wpforo\classes\Activity;
32 use wpforo\classes\AIChatbot;
33 use wpforo\classes\AIClient;
34 use wpforo\classes\AIContentModeration;
35 use wpforo\classes\AILogs;
36 use wpforo\classes\AIWordPressIndexer;
37 use wpforo\classes\API;
38 use wpforo\classes\Blocks;
39 use wpforo\classes\Boards;
40 use wpforo\classes\Cache;
41 use wpforo\classes\Feed;
42 use wpforo\classes\Forms;
43 use wpforo\classes\Forums;
44 use wpforo\classes\Logs;
45 use wpforo\classes\Members;
46 use wpforo\classes\Moderation;
47 use wpforo\classes\Notices;
48 use wpforo\classes\Permissions;
49 use wpforo\classes\Phrases;
50 use wpforo\classes\PostMeta;
51 use wpforo\classes\Posts;
52 use wpforo\classes\RamCache;
53 use wpforo\classes\SEO;
54 use wpforo\classes\Settings;
55 use wpforo\classes\TaskManager;
56 use wpforo\classes\EmailQueue;
57 use wpforo\classes\Template;
58 use wpforo\classes\Topics;
59 use wpforo\classes\VectorStorageManager;
60 use wpforo\classes\UserGroups;
61 use wpforo\modules\bookmarks\Bookmarks;
62 use wpforo\modules\reactions\Reactions;
63 use wpforo\modules\revisions\Revisions;
64 use wpforo\modules\subscriptions\Subscriptions;
65
66 final class wpforo {
67 private static $_instance = null;
68
69 /** @var wpdb * */
70 public $db;
71 public $default;
72
73 public $blog_prefix = "wp_";
74 public $base_prefix = "wpforo_";
75 public $prefix = "wpforo_";
76 public $_base_tables = [
77 'boards',
78 'usergroups',
79 'profiles',
80 'logs',
81 'follows',
82 'bookmarks',
83 'accesses',
84 'email_queue',
85 ];
86 public $_tables = [
87 'activity',
88 'ai_cache',
89 'ai_chat_conversations',
90 'ai_chat_messages',
91 'ai_embeddings',
92 'ai_embeddings_cache',
93 'ai_logs',
94 'ai_moderation',
95 'ai_tasks',
96 'ai_task_logs',
97 'forums',
98 'languages',
99 'phrases',
100 'postmeta',
101 'posts',
102 'post_revisions',
103 'subscribes',
104 'topics',
105 'tags',
106 'visits',
107 'reactions',
108 ];
109 public $tables;
110 private $_folders = [
111 'assets',
112 'attachments',
113 'avatars',
114 'covers',
115 'cache',
116 'default_attachments',
117 'emoticons',
118 ];
119 public $folders = [];
120
121 public $current_url;
122 public $canonical_url;
123 public $GET = [];
124 public $current_object;
125
126 public $wp_current_user = null;
127 public $current_user = [];
128 public $current_usermeta = [];
129 public $current_user_groupid = 4;
130 public $current_user_groupids = [ 4 ];
131 public $current_user_secondary_groupids = [];
132 public $current_userid = 0;
133 public $current_user_login = '';
134 public $current_user_email = '';
135 public $current_user_display_name = '';
136 public $current_user_status = '';
137 public $current_user_accesses = [];
138 public $session_token = '';
139
140 public $tools_cleanup;
141 public $tools_misc;
142 public $locale = 'en_US';
143
144 public $dissmissed;
145
146 /** @var Settings */
147 public $settings;
148 /** @var Actions */
149 public $action;
150 /** @var Activity */
151 public $activity;
152 /** @var API */
153 public $api;
154 /** @var AIClient */
155 public $ai_client;
156 /** @var AIChatbot */
157 public $ai_chatbot;
158 /** @var VectorStorageManager */
159 public $vector_storage;
160 /** @var TaskManager */
161 public $task_manager;
162 /** @var AIContentModeration */
163 public $ai_content_moderation;
164 /** @var AILogs */
165 public $ai_logs;
166 /** @var AIWordPressIndexer */
167 public $ai_wp_indexer;
168 /** @var Boards */
169 public $board;
170 /** @var Cache */
171 public $cache;
172 /** @var Feed */
173 public $feed;
174 /** @var Forms */
175 public $form;
176 /** @var Forums */
177 public $forum;
178 /** @var Logs */
179 public $log;
180 /** @var Members */
181 public $member;
182 /** @var Moderation */
183 public $moderation;
184 /** @var Notices */
185 public $notice;
186 /** @var Permissions */
187 public $perm;
188 /** @var Phrases */
189 public $phrase;
190 /** @var PostMeta */
191 public $postmeta;
192 /** @var Posts */
193 public $post;
194 /** @var Blocks */
195 public $blocks;
196 /** @var RamCache */
197 public $ram_cache;
198 /** @var Revisions */
199 public $revision;
200 /** @var Reactions */
201 public $reaction;
202 /** @var Bookmarks */
203 public $bookmark;
204 /** @var SEO */
205 public $seo;
206 /** @var Subscriptions */
207 public $sbscrb;
208 /** @var EmailQueue */
209 public $email_queue;
210 /** @var Template */
211 public $tpl;
212 /** @var Topics */
213 public $topic;
214 /** @var UserGroups */
215 public $usergroup;
216
217 public static function instance() {
218 if( is_null( self::$_instance ) ) self::$_instance = new self();
219
220 return self::$_instance;
221 }
222
223 private function init_db() {
224 global $wpdb;
225 $this->db = $wpdb;
226 }
227
228 public function is_db_mysql8() {
229 if( preg_match( '#([\d.]+)-MariaDB#iu', (string) $this->db->get_var( "SELECT VERSION()" ), $match ) ) {
230 $use_mysql8 = version_compare( $match[1], '10.2.6', '>=' );
231 } else {
232 $use_mysql8 = version_compare( $this->db->db_version(), '8.0.0', '>=' );
233 }
234
235 return apply_filters( 'wpforo_use_mysql8', $use_mysql8 );
236 }
237
238 private function __construct() {
239 $this->init_db();
240 $this->init_hooks();
241 }
242
243 public function generate_prefix( $boardid ) {
244 $boardid = intval( $boardid );
245
246 return $this->base_prefix . ( $boardid ? $boardid . '_' : '' );
247 }
248
249 private function init_prefix() {
250 $boardid = $this->board->get_current( 'boardid' );
251 $this->prefix = $this->generate_prefix( $boardid );
252 }
253
254 public function change_board( $args = [] ) {
255 if( is_null( $this->board ) ) return;
256
257 do_action( 'wpforo_before_change_board', $args );
258
259 $boardid = $this->board->get_current( 'boardid' );
260 $is_inited = (bool) wpfval( $this->board->is_inited, $boardid );
261 $this->board->init_current( $args );
262
263 if( ! $is_inited || $boardid !== $this->board->get_current( 'boardid' ) ) {
264 $this->ram_cache->reset();
265
266 $this->init_prefix();
267 $this->init_tables();
268 $this->init_folders();
269 $this->init_options();
270
271 do_action( 'wpforo_after_change_board', $args );
272 }
273 }
274
275 private function init_base_classes() {
276 $this->requires();
277 $this->init_defaults();
278 $this->reset_current_object();
279 $this->init_base_tables();
280 $this->init_folders();
281
282 do_action( 'wpforo_before_init_base_classes' );
283
284 $this->settings = new Settings();
285 $this->tpl = new Template();
286 $this->ram_cache = new RamCache();
287 $this->cache = new Cache();
288 $this->action = new Actions();
289 $this->board = new Boards();
290 $this->usergroup = new UserGroups();
291 $this->member = new Members();
292 $this->perm = new Permissions();
293 $this->notice = new Notices();
294
295 $this->moderation = new Moderation();
296 $this->phrase = new Phrases();
297 $this->blocks = new Blocks();
298
299 do_action( 'wpforo_after_init_base_classes' );
300 }
301
302 private function init_classes() {
303 do_action( 'wpforo_before_init_classes' );
304
305 $this->activity = new Activity();
306 $this->api = new API();
307 // AIClient: Initialize globally for both admin and front-end features
308 // (semantic search, antispam, auto-translation, etc.)
309 $this->ai_client = new AIClient();
310 // AIChatbot: AI-powered chat functionality in AI Assistant widget
311 $this->ai_chatbot = new AIChatbot();
312 // VectorStorageManager: Unified abstraction for vector storage (local/cloud)
313 $this->vector_storage = new VectorStorageManager();
314 // TaskManager: Initialize for AI task scheduling and execution
315 $this->task_manager = new TaskManager();
316 // AIContentModeration: Central class for AI-powered content moderation
317 $this->ai_content_moderation = AIContentModeration::get_instance();
318 // AILogs: Logging of all AI actions for admin visibility
319 $this->ai_logs = new AILogs();
320 // AIWordPressIndexer: WordPress content type indexing for AI search
321 $this->ai_wp_indexer = new AIWordPressIndexer();
322 $this->feed = new Feed();
323 $this->form = new Forms();
324 $this->forum = new Forums();
325 $this->log = new Logs();
326 $this->postmeta = new PostMeta();
327 $this->post = new Posts();
328 $this->seo = new SEO();
329 $this->topic = new Topics();
330 $this->reaction = new Reactions();
331 $this->bookmark = new Bookmarks();
332 $this->sbscrb = new Subscriptions();
333 $this->email_queue = new EmailQueue();
334 if( wpforo_is_module_enabled( 'revisions' ) ) $this->revision = new Revisions();
335
336 do_action( 'wpforo_after_init_classes' );
337 }
338
339 public function set_locale( $locale ) {
340 $this->locale = $locale;
341 do_action( 'wpforo_after_set_locale', $locale );
342 }
343
344 private function init_hooks() {
345 add_action( 'wpforo_after_init_folders', function( $folders ) {
346 $this->create_folders( $folders );
347 }, 9999 );
348 add_action(
349 'after_setup_theme',
350 function() {
351 do_action( 'wpforo_before_base_init' );
352 $this->init_base_classes();
353 if( ! $this->is_installed() ) $this->init();
354 },
355 0
356 );
357 add_action( 'change_locale', [ $this, 'set_locale' ] );
358 add_action( 'init', function() { $this->set_locale( get_locale() ); } );
359 add_action( 'widgets_init', function() {
360 $boards = $this->board->get_boards( [ 'status' => true ] );
361 foreach( $boards as $board ) {
362 register_sidebar(
363 [
364 'id' => sprintf(
365 'wpforo_%1$ssidebar',
366 $board['boardid'] ? $board['boardid'] . '_' : ''
367 ),
368 'name' => __( 'wpForo Sidebar', 'wpforo' ) . ' - ( ' . $board['title'] . ' )',
369 'description' => __( "NOTE: If you're going to add widgets in this sidebar, please use 'Full Width' template for wpForo index page to avoid sidebar duplication.", 'wpforo' ),
370 'before_widget' => '<aside id="%1$s" class="footer-widget-col %2$s clearfix">',
371 'after_widget' => '</aside>',
372 'before_title' => '<h3 class="widget-title">',
373 'after_title' => '</h3>',
374 ]
375 );
376 }
377
378 register_widget( 'wpforo\widgets\Forums' );
379 register_widget( 'wpforo\widgets\Profile' );
380 register_widget( 'wpforo\widgets\Search' );
381 register_widget( 'wpforo\widgets\OnlineMembers' );
382 register_widget( 'wpforo\widgets\RecentTopics' );
383 register_widget( 'wpforo\widgets\RecentPosts' );
384 register_widget( 'wpforo\widgets\Tags' );
385 } );
386 add_filter( 'plugin_locale', function( $locale, $domain ) {
387 if( $domain === 'wpforo' && defined( 'DOING_AJAX' ) && DOING_AJAX ) $locale = $this->locale;
388
389 return $locale;
390 }, 10, 2 );
391 add_action( 'wpforo_after_init_classes', function() {
392 if( wpforo_setting( 'email', 'disable_new_user_admin_notification' ) ) {
393 remove_action( 'after_password_reset', 'wp_password_change_notification' );
394
395 remove_action( 'register_new_user', 'wp_send_new_user_notifications' );
396 add_action( 'register_new_user', 'wpforo_send_new_user_notifications' );
397
398 remove_action( 'edit_user_created_user', 'wp_send_new_user_notifications' );
399 add_action( 'edit_user_created_user', 'wpforo_send_new_user_notifications', 10, 2 );
400
401 remove_action( 'network_site_new_created_user', 'wp_send_new_user_notifications' );
402 add_action( 'network_site_new_created_user', 'wpforo_send_new_user_notifications' );
403
404 remove_action( 'network_site_users_created_user', 'wp_send_new_user_notifications' );
405 add_action( 'network_site_new_created_user', 'wpforo_send_new_user_notifications' );
406
407 remove_action( 'network_user_new_created_user', 'wp_send_new_user_notifications' );
408 add_action( 'network_user_new_created_user', 'wpforo_send_new_user_notifications' );
409 }
410 } );
411
412 // WP Cron: Ensure classes are initialized early for cron hook callbacks
413 if ( wp_doing_cron() || isset( $_GET['doing_wp_cron'] ) ) {
414 add_action( 'init', [ $this, 'init' ], 1 ); // Priority 1 - before cron runs
415 } elseif( is_admin() || strpos( (string) $_SERVER['REQUEST_URI'], '/peepsoajax/' ) === 0 || preg_match(
416 '#^/?(?:([^\s/?&=<>:\'\"*\\\|]*/)(?1)*)?[^\s/?&=<>:\'\"*\\\|]+\.(?:php|js|css|jpe?g|png|gif|bmp|webp|svg|tiff)/?(?:\?[^/]*)?$#iu',
417 (string) $_SERVER['REQUEST_URI']
418 ) ) {
419 add_action( 'init', [ $this, 'init' ], 99 );
420 add_action( 'admin_init', [ $this, 'admin_init' ] );
421 } elseif( strpos( (string) $_SERVER['REQUEST_URI'], '/wp-json/' ) !== false ) {
422 add_filter( 'rest_authentication_errors', function( $r ) {
423 $this->init();
424
425 return $r;
426 }, 9999 );
427 } else {
428 add_action( 'wp', [ $this, 'init' ], 99 );
429 }
430 add_action( 'switch_blog', [ $this, 'after_switch_blog' ], 10, 2 );
431 add_action( 'wpforo_before_init', [ $this, 'change_board' ] );
432 add_action( 'wpforo_after_init_current_url', [ $this, 'change_board' ] );
433 }
434
435 public function after_switch_blog( $new_blog_id, $prev_blog_id ) {
436 if( intval( $new_blog_id ) !== intval( $prev_blog_id ) ) {
437 $this->init_base_tables();
438 $this->init_tables();
439 $this->init_folders();
440 }
441 }
442
443 private function init_base_tables() {
444 $this->db->query( "SET SESSION group_concat_max_len = 1000000" );
445 $blog_id = apply_filters( 'wpforo_current_blog_id', 0 );
446 $this->tables = new stdClass;
447 if( ! $blog_id ) $blog_id = $this->db->blogid;
448 $this->blog_prefix = $this->db->get_blog_prefix( $blog_id );
449 $this->_base_tables = apply_filters( 'wpforo_init_base_tables', $this->_base_tables );
450 foreach( $this->_base_tables as $table ) $this->tables->$table = $this->fix_table_name( $table );
451 }
452
453 private function init_tables() {
454 $this->_tables = apply_filters( 'wpforo_init_tables', $this->_tables );
455 foreach( $this->_tables as $table ) $this->tables->$table = $this->fix_table_name( $table );
456 }
457
458 public function get_active_boards_tables( $basename ) {
459 $tables = [];
460 if( $boardids = $this->board->get_active_boardids() ) {
461 foreach( $boardids as $boardid ) $tables[] = $this->fix_table_name( $basename, $this->generate_prefix( $boardid ) );
462 }
463
464 return array_unique( $tables );
465 }
466
467 /**
468 * @param string $basename
469 *
470 * @return string
471 */
472 public function fix_table_name( $basename, $prefix = null ) {
473 return $this->blog_prefix . ( in_array( $basename, $this->_base_tables, true ) ? $this->base_prefix : ( is_null( $prefix ) ? $this->prefix : $prefix ) ) . $basename;
474 }
475
476 public function fix_dir_sep( $dir ) {
477 $dir = str_replace( [ '/', '\\', '\\\\' ], DIRECTORY_SEPARATOR, $dir );
478
479 return rtrim( trim( (string) $dir ), DIRECTORY_SEPARATOR );
480 }
481
482 public function fix_url_sep( $url ) {
483 return trim( str_replace( [ '/', '\\', '\\\\' ], '/', (string) $url ) );
484 }
485
486 private function init_folders() {
487 $this->_folders = apply_filters( 'wpforo_init_folders', $this->_folders );
488 $boardid = ( is_callable( [ $this->board, 'get_current' ] ) ? $this->board->get_current( 'boardid' ) : 0 );
489 $upload_dir = wp_get_upload_dir();
490
491 // In many cases people leave the website URL protocol as http, but website works with https
492 // In this case colors.css and phrases.js are not loaded because of http blocking by browser
493 $upload_dir['baseurl'] = is_ssl() ? str_replace( 'http://', 'https://', $upload_dir['baseurl'] ) : $upload_dir['baseurl'];
494
495 $this->folders['wp_upload'] = [
496 'dir' => $this->fix_dir_sep( $upload_dir['basedir'] ),
497 'url' => $this->fix_url_sep( $upload_dir['baseurl'] ),
498 ];
499 $this->folders['wp_upload']['url//'] = preg_replace( '#^https?:#i', '', (string) $this->folders['wp_upload']['url'] );
500 $this->folders['upload'] = [
501 'dir' => $this->folders['wp_upload']['dir'] . DIRECTORY_SEPARATOR . "wpforo" . ( $boardid ? '_' . $boardid : '' ),
502 'url' => $this->folders['wp_upload']['url'] . "/wpforo" . ( $boardid ? '_' . $boardid : '' ),
503 'url//' => $this->folders['wp_upload']['url//'] . "/wpforo" . ( $boardid ? '_' . $boardid : '' ),
504 ];
505 foreach( $this->_folders as $folder ) {
506 $this->folders[ $folder ] = [
507 'dir' => $this->folders['upload']['dir'] . DIRECTORY_SEPARATOR . trim( $this->fix_dir_sep( (string) $folder ), DIRECTORY_SEPARATOR ),
508 'url' => $this->folders['upload']['url'] . "/" . trim( $this->fix_url_sep( (string) $folder ), '/' ),
509 'url//' => $this->folders['upload']['url//'] . "/" . trim( $this->fix_url_sep( (string) $folder ), '/' ),
510 ];
511 }
512
513 $this->folders = apply_filters( 'wpforo_working_folders', $this->folders );
514
515 do_action( 'wpforo_after_init_folders', $this->folders );
516 }
517
518 private function create_folders( array $folders = [] ): void {
519 if( ! $folders ) $folders = WPF()->folders;
520 foreach( $folders as $folder ) {
521 $dir = ( is_scalar( $folder ) ? $folder : ( array_key_exists( 'dir', $folder ) ? (string) $folder['dir'] : '' ) );
522 if( $dir && ! is_dir( $dir ) ) {
523 if( wp_mkdir_p( $dir ) ) {
524 wpforo_write_file( "$dir/index.html", "" );
525 wpforo_write_file( "$dir/robots.txt", "User-agent: *\nDisallow: /" );
526 }
527 }
528 }
529 }
530
531 private function requires() {
532 require_once WPFORO_DIR . '/includes/functions.php';
533 require_once WPFORO_DIR . '/includes/functions-template.php';
534 require_once WPFORO_DIR . '/includes/hooks.php';
535 require_once WPFORO_DIR . '/includes/installation.php';
536 require_once WPFORO_DIR . '/integrations/functions.php';
537 if( wpforo_is_admin() ) require_once WPFORO_DIR . '/admin/index.php';
538 }
539
540 public function admin_init() {
541 if( wpforo_is_admin() ) {
542 $this->change_board();
543
544 $this->check_issues();
545
546 if( strpos( wpforo_get_request_uri(), 'user-new.php' ) === false ) {
547 if( ! $this->member->get_groupid( $this->current_userid ) ) {
548 $this->member->synchronize_user( $this->current_userid );
549 }
550 }
551
552 if( ! $this->usergroup->can_manage_forum() && wpforo_current_user_is( 'admin' ) ) {
553 $this->member->set_groupid( $this->current_userid, 1 );
554 }
555 }
556 }
557
558 public function check_issues() {
559 //Make sure all users profiles are created
560 if( $this->is_installed() ) {
561 if( apply_filters( 'wpforo_profile_synchronization_notice', true ) ) {
562 if( is_multisite() ) {
563 $sql = "SELECT COUNT(`user_id`) FROM `" . WPF()->db->usermeta . "` WHERE `meta_key` LIKE '" . WPF(
564 )->blog_prefix . "capabilities' AND `user_id` NOT IN( SELECT `userid` FROM `" . WPF()->tables->profiles . "` )";
565 } else {
566 $sql = "SELECT COUNT(`ID`) as user_id FROM `" . WPF()->db->users . "` WHERE `ID` NOT IN( SELECT `userid` FROM `" . WPF()->tables->profiles . "` )";
567 }
568 if( (int) $this->db->get_var( $sql ) ) add_action( 'admin_notices', 'wpforo_profile_notice', 10 );
569 }
570 }
571 //Make sure tables structures are correct for current version
572 $wpforo_version_db = wpforo_get_option( 'version_db', null, false );
573 if( ! $wpforo_version_db || version_compare( $wpforo_version_db, WPFORO_VERSION, '<' ) || wpforo_setting( 'general', 'debug_mode' ) ) {
574 if( 'tables' !== wpfval( $_GET, 'view' ) ) {
575 $db_note = false;
576 $problems = wpforo_database_check();
577 if( ! empty( $problems ) ) {
578 foreach( $problems as $key => $problem ) {
579 if( wpfval( $problem, 'fields' ) ) $db_note = true;
580 if( wpfval( $problem, 'exists' ) ) $db_note = true;
581 if( $key === 'data' ) $db_note = true;
582 }
583 if( $db_note ) {
584 add_action( 'admin_notices', 'wpforo_database_notice', 10 );
585 }
586 } else {
587 wpforo_update_option( 'version_db', WPFORO_VERSION );
588 }
589 }
590 }
591 //Check cache plugins
592 $not_excluded_plugins = WPF()->cache->cache_plugins_status();
593 if( ! empty( $not_excluded_plugins ) ) {
594 add_action( 'admin_notices', 'wpforo_cache_information', 10 );
595 }
596 }
597
598 public function init() {
599 do_action( 'wpforo_before_init' );
600 $this->init_classes();
601 $this->init_current_url();
602 do_action( 'wpforo_core_inited' );
603 $this->init_current_object();
604 do_action( 'wpforo_after_init' );
605 }
606
607 public function shortcode_atts_to_url( $atts ) {
608 if( is_null( $this->forum ) ) $this->init_classes();
609
610 $url = wpforo_home_url();
611
612 $args = shortcode_atts(
613 [
614 'boardid' => 0,
615 'item' => 'forum',
616 'id' => 0,
617 'slug' => '',
618 ],
619 (array) $atts
620 );
621
622 WPF()->change_board( $args['boardid'] );
623
624 if( $args['item'] === 'profile' && ! $args['id'] ) $args['id'] = $this->current_userid;
625
626 if( $args['item'] === 'add-topic' ) {
627 $forum = $this->forum->get_forum( ( $args['slug'] ?: $args['id'] ) );
628 $forumid = (int) wpfval( $forum, 'is_cat' ) ? 0 : (int) wpfval( $forum, 'forumid' );
629 $url = wpforo_home_url( wpforo_settings_get_slug( 'add-topic' ) . '/' . $forumid );
630 } elseif( $args['item'] === 'recent' ) {
631 $url = wpforo_settings_get_slug( 'recent' ) . '/';
632 if( trim( (string) $args['slug'] ) ) $url .= '?view=' . wpforo_settings_get_slug( $args['slug'] );
633 $url = wpforo_home_url( $url );
634 } elseif( $args['item'] === 'members' ) {
635 $url = wpforo_members_url();
636 } elseif( $args['id'] || $args['slug'] ) {
637 $getid = ( $args['slug'] ?: $args['id'] );
638 if( $args['item'] === 'topic' ) {
639 $url = $this->topic->get_url( $getid );
640 } elseif( $args['item'] === 'profile' ) {
641 $url = $this->member->get_profile_url( $getid );
642 } elseif( $args['item'] === 'account' ) {
643 $url = $this->member->get_profile_url( $getid, 'account' );
644 } elseif( $args['item'] === 'activity' ) {
645 $url = $this->member->get_profile_url( $getid, 'activity' );
646 } elseif( $args['item'] === 'favored' ) {
647 $url = $this->member->get_profile_url( $getid, 'favored' );
648 } elseif( $args['item'] === 'subscriptions' ) {
649 $url = $this->member->get_profile_url( $getid, 'subscriptions' );
650 } elseif( $args['item'] === 'messages' ) {
651 $url = $this->member->get_profile_url( $getid, 'messages' );
652 } else {
653 $url = $this->forum->get_forum_url( $getid );
654 }
655 } elseif( $args['item'] === 'login' ) {
656 $url = wpforo_login_url();
657 } elseif( $args['item'] === 'register' ) {
658 $url = wpforo_register_url();
659 } elseif( $args['item'] === 'lostpassword' ) {
660 $url = wpforo_lostpassword_url();
661 }
662
663 return $url;
664 }
665
666 public function init_current_url( $atts = [] ) {
667 if( is_null( $this->post ) ) $this->init_classes();
668
669 if( is_scalar( $atts ) ) {
670 $url = $atts;
671 $atts = [];
672 } else {
673 $url = wpforo_get_request_uri();
674 }
675 if( $atts || is_wpforo_shortcode_page( $url ) ) {
676 if( $atts || ( $atts = get_wpforo_shortcode_atts( '', $url ) ) ) {
677 $url = $this->shortcode_atts_to_url( $atts );
678 } else {
679 $url = wpforo_home_url();
680 }
681 }
682
683 if( is_wpforo_url( $url ) && preg_match( '#/' . preg_quote( wpforo_settings_get_slug( 'postid' ) ) . '/(\d+)/?$#isu', strtok( $url, '?' ), $matches ) ) {
684 $post_url = $this->post->get_full_url( $matches[1] );
685 if( $post_url !== wpforo_home_url() ) {
686 $url = $post_url;
687 $this->canonical_url = $this->post->get_url( $matches[1] );
688 }
689 } elseif( is_wpforo_url( $url ) && preg_match( '#/' . preg_quote( wpforo_settings_get_slug( 'topicid' ) ) . '/(\d+)/?$#isu', strtok( $url, '?' ), $matches ) ) {
690 $topic_url = $this->topic->get_full_url( $matches[1] );
691 if( $topic_url !== wpforo_home_url() ) {
692 $url = $topic_url;
693 $this->canonical_url = $this->topic->get_url( $matches[1] );
694 }
695 }
696
697 if( function_exists( 'pll_default_language' ) ) {
698 $qvar = wpforo_get_url_query_vars_str( $url );
699 $qvar = preg_replace( '#^' . preg_quote( pll_default_language() ) . '/#', '', $qvar );
700 $url = $this->user_trailingslashit( home_url( $qvar ) );
701 }
702
703 $url = wpforo_fix_url( $url );
704 $url = preg_replace( '#\#[^/?&]*$#iu', '', $url );
705 parse_str( (string) parse_url( $url, PHP_URL_QUERY ), $get );
706 $get = array_merge( (array) $get, $_GET );
707 $get = wp_unslash( $get );
708
709 if( ! $this->canonical_url ) $this->canonical_url = $this->current_url;
710
711 $this->current_url = apply_filters( 'wpforo_init_current_url', $url );
712 $this->GET = apply_filters( 'wpforo_init_current_url_GET', $get );
713
714 if( ! $this->canonical_url ) $this->canonical_url = $this->current_url;
715 if( strpos( $this->canonical_url, '?wpfin=tag' ) === false && strpos( $this->canonical_url, '?view=' ) === false ) {
716 $this->canonical_url = preg_replace( '#\?.*$#isu', '', $this->canonical_url );
717 }
718 $this->canonical_url = apply_filters( 'wpforo_init_canonical_url', $this->canonical_url );
719
720 do_action( 'wpforo_after_init_current_url', $atts );
721 }
722
723 private function init_defaults() {
724 $this->default = new stdClass;
725
726 $this->default->current_object = [
727 'route' => '',
728 'template' => '',
729 'qvars' => [],
730 'args' => [],
731 'layout' => 1,
732 'og_text' => '',
733 'paged' => 1,
734 'items_count' => 0,
735 'items_per_page' => 15,
736 'is_404' => false,
737 'user_is_same_current_user' => false,
738 'orderby' => null,
739 'members' => [],
740 'categories' => [],
741 'topics' => [],
742 'posts' => [],
743 'user' => [],
744 'userid' => 0,
745 'user_nicename' => '',
746 'forum' => [],
747 'forumid' => 0,
748 'forum_slug' => '',
749 'forum_desc' => '',
750 'forum_meta_key' => '',
751 'forum_meta_desc' => '',
752 'topic' => [],
753 'topicid' => 0,
754 'topic_slug' => '',
755 'tags' => [],
756 'load_tinymce' => false,
757 ];
758
759 $this->default->tools_cleanup = [
760 'user_reg_days_ago' => 7,
761 'auto_cleanup_users' => 0,
762 'usergroup' => [ 1 => '0', 5 => '0', 2 => '1', 3 => '0' ],
763 ];
764
765 $this->default->tools_misc = [
766 'admin_note' => '',
767 'admin_note_groups' => [ 1, 2, 3, 4, 5 ],
768 'admin_note_pages' => [ 'forum' ],
769 ];
770
771 $this->default->stats = [
772 'forums' => 0,
773 'topics' => 0,
774 'posts' => 0,
775 'members' => 0,
776 'online_members_count' => 0,
777 'last_post_title' => '',
778 'last_post_url' => '',
779 'newest_member' => [],
780 'newest_member_dname' => '',
781 'newest_member_profile_url' => '',
782 ];
783
784 $this->default->dissmissed = [
785 'recaptcha_backend_note' => 0,
786 'recaptcha_note' => 0,
787 'addons_css_update' => 0,
788 ];
789 }
790
791 private function reset_current_object() {
792 $this->current_object = $this->default->current_object;
793 }
794
795 private function init_options() {
796 $this->tools_cleanup = wpforo_get_option( 'tools_cleanup', $this->default->tools_cleanup );
797 $this->tools_misc = wpforo_get_option( 'tools_misc', $this->default->tools_misc );
798 $this->dissmissed = wpforo_get_option( 'dissmissed', $this->default->dissmissed );
799 }
800
801 public function can_use_trailing_slashes() {
802 return '/' === substr( (string) get_option( 'permalink_structure', '' ), - 1, 1 );
803 }
804
805 public function user_trailingslashit( $url ) {
806 $rtrimed_url = '';
807 $url_append_vars = '';
808 if( preg_match( '#^(.+?)(/?[?&].*)?$#isu', $url, $match ) ) {
809 if( wpfval( $match, 1 ) ) $rtrimed_url = rtrim( $match[1], '/\\' );
810 if( wpfval( $match, 2 ) ) $url_append_vars = '?' . trim( $match[2], '?&/\\' );
811 if( $rtrimed_url ) {
812 $home_url = rtrim( preg_replace( '#/?\?.*$#isu', '', home_url() ), '/\\' );
813 if( $rtrimed_url == $home_url ) {
814 $url = $rtrimed_url . '/';
815 } else {
816 $url = $rtrimed_url . ( wpforo_ram_get( [ $this, 'can_use_trailing_slashes' ] ) ? '/' : '' );
817 }
818 }
819 }
820
821 return $url . $url_append_vars;
822 }
823
824 public function strip_url_paged_var( $url ) {
825 $patterns = [
826 '#/' . preg_quote( wpforo_settings_get_slug( 'paged' ) ) . '/?\d*/?#isu',
827 '#[&?]wpfpaged=\d*#iu',
828 ];
829 $url = preg_replace( $patterns, '', (string) $url );
830
831 return $this->user_trailingslashit( $url );
832 }
833
834 public function statistic_cache_clean() {
835 $this->db->query( "DELETE FROM `" . $this->db->options . "` WHERE `option_name` REGEXP '^" . wpforo_prefix( 'stat_[0-9]+' ) . "'" );
836 }
837
838 public function statistic( $mode = 'get', $template = 'all' ) {
839 $key = 'stat_' . $this->current_user_groupid;
840 if( $mode === 'get' ) {
841 if( $cached_stat = wpforo_get_option( $key, [], false ) ) {
842 $cached_stat['online_members_count'] = $this->member->online_members_count();
843 if( wpfkey( $cached_stat, 'forums' ) && wpfkey( $cached_stat, 'topics' ) && wpfkey( $cached_stat, 'posts' ) ) {
844 return wpforo_array_args_cast_and_merge( $cached_stat, $this->default->stats );
845 }
846 }
847 }
848
849 if( $mode === 'get' || $template === 'all' ) {
850 $stats['forums'] = $this->forum->get_count( [ 'is_cat' => 0 ] );
851 $stats['topics'] = $this->topic->get_count();
852 $stats['posts'] = $this->post->get_count();
853 $member_status = [ 'p.`status`' => $this->member->get_inlist_enabled_statuses() ];
854 $stats['members'] = $this->member->get_count( $member_status );
855 $stats['online_members_count'] = $this->member->online_members_count();
856 $row_count = apply_filters( 'wpforo_get_statistic_row_count', 1 );
857
858 $posts = $this->topic->get_topics( [ 'orderby' => 'modified', 'order' => 'DESC', 'row_count' => $row_count, 'private' => 0, 'status' => 0, 'permgroup' => 4 ] );
859 $first = key( $posts );
860 if( !is_null( $first ) && ! empty( $posts[ $first ] ) && $this->perm->forum_can( 'vf', $posts[ $first ]['forumid'] ) ) {
861 $stats['last_post_title'] = $posts[ $first ]['title'];
862 $stats['last_post_url'] = $this->post->get_url( $posts[ $first ]['last_post'] );
863 }
864
865 $newest_member = $this->member->get_newest_member();
866 if( ! empty( $newest_member ) ) {
867 $stats['newest_member'] = $newest_member;
868 $stats['newest_member_dname'] = wpforo_user_dname( $newest_member );
869 $stats['newest_member_profile_url'] = $newest_member['profile_url'];
870 }
871 } else {
872 $stats = wpforo_get_option( $key, $this->default->stats, false );
873 switch( $template ) {
874 case 'forum':
875 $stats['forums'] = $this->forum->get_count( [ 'is_cat' => 0 ] );
876 break;
877 case 'topic':
878 $stats['topics'] = $this->topic->get_count();
879 $posts = $this->topic->get_topics( [ 'orderby' => 'modified', 'order' => 'DESC', 'row_count' => 1 ] );
880 if( isset( $posts[0] ) && ! empty( $posts[0] ) && $this->perm->forum_can( 'vf', $posts[0]['forumid'] ) ) {
881 $stats['last_post_title'] = $posts[0]['title'];
882 $stats['last_post_url'] = $this->post->get_url( $posts[0]['last_post'] );
883 }
884 break;
885 case 'post':
886 $stats['posts'] = $this->post->get_count();
887 $posts = $this->topic->get_topics( [ 'orderby' => 'modified', 'order' => 'DESC', 'row_count' => 1 ] );
888 if( isset( $posts[0] ) && ! empty( $posts[0] ) && $this->perm->forum_can( 'vf', $posts[0]['forumid'] ) ) {
889 $stats['last_post_title'] = $posts[0]['title'];
890 $stats['last_post_url'] = $this->post->get_url( $posts[0]['last_post'] );
891 }
892 break;
893 case 'user':
894 //$member_status = [ 'p.`status`' => $this->member->get_inlist_enabled_statuses() ];
895 //$stats['members'] = $this->member->get_count( $member_status );
896 $stats['members'] = $this->member->get_count();
897 $stats['online_members_count'] = $this->member->online_members_count();
898
899 $newest_member = $this->member->get_newest_member( false );
900 if( ! empty( $newest_member ) ) {
901 $stats['newest_member'] = $newest_member;
902 $stats['newest_member_dname'] = wpforo_user_dname( $newest_member );
903 $stats['newest_member_profile_url'] = $newest_member['profile_url'];
904 }
905 break;
906 }
907 }
908
909 $stats = apply_filters( 'wpforo_get_statistic_array_filter', $stats );
910 $stats = wpforo_array_args_cast_and_merge( $stats, $this->default->stats );
911 wpforo_update_option( $key, $stats );
912
913 return $stats;
914 }
915
916 public function init_current_object() {
917 $this->reset_current_object();
918 $this->current_object['items_per_page'] = $this->post->get_option_items_per_page();
919 $url = $this->current_url;
920 $get = $this->GET;
921
922 if( ! is_wpforo_page( $url ) ) return;
923
924 $current_url = wpforo_get_url_query_vars_str( $url );
925
926 $current_object = [];
927 if( wpfkey( $get, 'wpfs' ) || wpfval( $get, 'foro' ) === 'search' ) $this->current_object['template'] = 'search';
928 if( wpfval( $get, 'wpforo' ) || wpfval( $get, 'foro' ) ) {
929 $request = ( wpfval( $get, 'wpforo' ) ) ? wpfval( $get, 'wpforo' ) : wpfval( $get, 'foro' );
930 if( $request === 'page' ) $this->current_object['template'] = 'page';
931 }
932
933 $template_key = '';
934 $wpf_url = preg_replace( '#/?\?.*$#isu', '', $current_url );
935 $wpf_url_parse = array_values( array_filter( explode( '/', trim( (string) $wpf_url, '/' ) ) ) );
936 if( array_key_exists( 0, $wpf_url_parse ) && in_array( $wpf_url_parse[0], $this->board->routes ) ) {
937 $this->current_object['route'] = $wpf_url_parse[0];
938 unset( $wpf_url_parse[0] );
939
940 if( in_array( $this->current_object['route'], $this->board->base_routes, true ) ) {
941 $this->current_object['template'] = ( $template_key = wpforo_settings_get_slug_key( $this->current_object['route'] ) ) !== 'member' ? $template_key : '';
942
943 $current_object['qvars'] = $wpf_url_parse;
944 $current_object['qvars'] = array_values( $current_object['qvars'] );
945
946 if( $this->current_object['template'] === 'register' ) {
947 $this->form->current['template'] = 'register';
948 $this->form->current['value'] = array_merge(
949 (array) wpfval( $this->form->current, 'value' ),
950 (array) wpfval( $_POST, 'wpfreg' ),
951 (array) wpfval( $_POST, 'data' )
952 );
953 $this->form->current['value']['user_login'] = sanitize_user( (string) wpfval( $_POST, 'wpfreg', 'user_login' ) );
954 $this->form->current['value']['user_email'] = sanitize_email( (string) wpfval( $_POST, 'wpfreg', 'user_email' ) );
955 $this->form->current['varname'] = 'wpfreg';
956 } elseif( $this->current_object['template'] === 'logout' && $this->current_userid ) {
957 $this->action->logout();
958 }
959 }
960
961 if( $this->current_userid && in_array( $this->current_object['template'], [ 'register', 'login', 'lostpassword' ], true ) && ! wpforo_is_admin() ) wpforo_redirect_to();
962 }
963 $wpf_url_parse = array_reverse( $wpf_url_parse );
964
965 if( in_array( wpforo_settings_get_slug( 'paged' ), $wpf_url_parse ) ) {
966 foreach( $wpf_url_parse as $key => $value ) {
967 if( $value === wpforo_settings_get_slug( 'paged' ) ) {
968 unset( $wpf_url_parse[ $key ] );
969 break;
970 }
971 if( is_numeric( $value ) ) $paged = intval( $value );
972
973 unset( $wpf_url_parse[ $key ] );
974 }
975 }
976 if( $_paged = intval( wpfval( $get, 'wpfpaged' ) ) ) $paged = $_paged;
977 $current_object['paged'] = ( isset( $paged ) && $paged > 0 ) ? $paged : 1;
978 $current_object['orderby'] = wpfval( $get, 'orderby' );
979
980 $wpf_url_parse = array_values( $wpf_url_parse );
981
982 if( ! $this->current_object['template'] ) {
983 $current_object = apply_filters( 'wpforo_before_init_current_object', $current_object, $wpf_url_parse );
984 if( wpfkey( $current_object, 'template' ) ) $this->current_object['template'] = (string) wpfval( $current_object, 'template' );
985 }
986
987 if( ! $this->current_object['template'] ) {
988 $templates = $template_key === 'member' ? $this->tpl->get_member_templates_list() : $this->tpl->get_templates_list();
989 if( $templates ) {
990 if( $template_key === 'member' ) {
991 if( count( $wpf_url_parse ) > 1 ) {
992 $nickname = end( $wpf_url_parse );
993 $profile_route = prev( $wpf_url_parse );
994 array_pop( $wpf_url_parse );
995 array_pop( $wpf_url_parse );
996 array_push( $wpf_url_parse, $nickname, $profile_route );
997 } else {
998 if( ! in_array( end( $wpf_url_parse ), array_map( 'wpforo_settings_get_slug', $templates ) ) ) $wpf_url_parse[] = wpforo_settings_get_slug( 'profile' );
999 }
1000 }
1001 $__slug = end( $wpf_url_parse );
1002 foreach( $templates as $template ) {
1003 if( $__slug === wpforo_settings_get_slug( $template ) ) {
1004 $this->current_object['template'] = $template;
1005 $current_object['qvars'] = $wpf_url_parse;
1006 array_pop( $current_object['qvars'] );
1007 $current_object['qvars'] = array_reverse( $current_object['qvars'] );
1008 break;
1009 }
1010 }
1011
1012 if( $template_key === 'member' ) {
1013 if( ! $this->current_object['template'] && ! $wpf_url_parse ) {
1014 if( $this->current_userid ) {
1015 $this->current_object['template'] = 'profile';
1016 } else {
1017 wp_safe_redirect( wpforo_login_url() );
1018 exit();
1019 }
1020 } elseif( ! wpforo_is_member_template( $this->current_object['template'] ) ) {
1021 $this->current_object['template'] = '';
1022 $current_object['qvars'] = [];
1023 }
1024 }
1025 }
1026 }
1027
1028 if( ! $this->current_object['template'] ) {
1029 $this->current_object['template'] = 'forum';
1030 $this->form->current['varname'] = 'thread';
1031 if( isset( $wpf_url_parse[0] ) ) {
1032 if( isset( $wpf_url_parse[1] ) ) {
1033 $current_object['topic_slug'] = $wpf_url_parse[0];
1034 $current_object['forum_slug'] = $wpf_url_parse[1];
1035 $this->current_object['template'] = 'post';
1036 $this->form->current['varname'] = 'post';
1037 } else {
1038 $current_object['forum_slug'] = $wpf_url_parse[0];
1039 $this->current_object['template'] = 'topic';
1040 $this->form->current['varname'] = 'thread';
1041 }
1042 }
1043 }
1044
1045 $current_object = apply_filters( 'wpforo_after_init_current_template', $current_object, $wpf_url_parse, $get );
1046 if( wpfkey( $current_object, 'template' ) ) $this->current_object['template'] = (string) wpfval( $current_object, 'template' );
1047
1048 if( $this->current_object['template'] ) {
1049 if( wpforo_is_member_template( $this->current_object['template'] ) ) {
1050 if( ! wpfval( $current_object, 'userid' ) && ! wpfval( $current_object, 'user_nicename' ) ) {
1051 if( $qvar0 = wpfval( $current_object['qvars'], 0 ) ) {
1052 if( wpforo_setting( 'profiles', 'url_structure' ) === 'id' ) {
1053 $current_object['userid'] = $qvar0;
1054 } else {
1055 $current_object['user_nicename'] = $qvar0;
1056 }
1057 } else {
1058 if( $this->current_userid ) {
1059 $current_object['userid'] = $this->current_userid;
1060 } else {
1061 wp_safe_redirect( wpforo_login_url() );
1062 exit();
1063 }
1064 }
1065 }
1066
1067 // redirect old type of member urls to new one
1068 if( $template_key !== 'member' ) {
1069 if( count( $current_object['qvars'] ) === 1 ) {
1070 $redirect = wpforo_url(
1071 array_shift( $current_object['qvars'] ) . ( $this->current_object['template'] !== 'profile' ? '/' . wpforo_settings_get_slug( $this->current_object['template'] ) : '' ),
1072 'member'
1073 );
1074 } else {
1075 $redirect = wpforo_url(
1076 array_shift( $current_object['qvars'] ) . '/' . wpforo_settings_get_slug( $this->current_object['template'] ) . '/' . implode( '/', $current_object['qvars'] ),
1077 'member'
1078 );
1079 }
1080 wp_safe_redirect( $redirect );
1081 exit();
1082 }
1083 // redirection
1084
1085 } elseif( $this->current_object['template'] === 'search' ) {
1086 $args = [
1087 'needle' => sanitize_text_field( wpfval( $get, 'wpfs' ) ),
1088 'type' => sanitize_text_field( wpfval( $get, 'wpfin' ) ),
1089 'date_period' => intval( wpfval( $get, 'wpfd' ) ),
1090 'forumids' => (array) wpfval( $get, 'wpff' ),
1091 'offset' => ( $current_object['paged'] - 1 ) * $this->current_object['items_per_page'],
1092 'row_count' => $this->current_object['items_per_page'],
1093 'orderby' => 'relevancy',
1094 'order' => 'desc',
1095 'postids' => [],
1096 ];
1097 if( ! empty( $get['wpfob'] ) ) {
1098 $args['orderby'] = wpforo_sanitize_orderby( $get['wpfob'], 'search', 'relevancy' );
1099 } elseif( in_array( wpfval( $args, 'type' ), [ 'tag', 'user-posts', 'user-topics' ], true ) ) {
1100 $args['orderby'] = 'date';
1101 }
1102 $wpfo = strtolower( (string) wpfval( $get, 'wpfo' ) );
1103 if( in_array( $wpfo, [ 'asc', 'desc' ], true ) ) $args['order'] = $wpfo;
1104 $sdata = array_filter( (array) wpfval( $get, 'data' ) );
1105 $args['postids'] = $this->postmeta->search( $sdata );
1106 $current_object['args'] = $args;
1107 if( $sdata && ! $args['postids'] ) {
1108 $current_object['items_count'] = 0;
1109 $current_object['posts'] = [];
1110 } else {
1111 $current_object['posts'] = $this->post->search( $args, $current_object['items_count'] );
1112 }
1113 } elseif( $this->current_object['template'] === 'recent' ) {
1114 $args = [];
1115 $view = false;
1116 $current_object['items_count'] = 0;
1117 if( ! empty( WPF()->GET['view'] ) ) $view = sanitize_title( WPF()->GET['view'] );
1118 if( ! empty( WPF()->GET['wpff'] ) ) $args['forumid'] = intval( WPF()->GET['wpff'] );
1119 if( ! empty( WPF()->GET['prefixid'] ) ) {
1120 $args['prefixid'] = intval( WPF()->GET['prefixid'] );
1121 }
1122
1123 $type = ( $view && $view !== 'unapproved' ? 'topics' : wpforo_setting( 'topics', 'recent_posts_type' ) );
1124 if( $view === 'unapproved' ) $type = 'posts';
1125 if( $view === 'prefix' ) $type = 'topics';
1126
1127 if( ! WPF()->current_userid || ! WPF()->usergroup->can( 'aum' ) ) {
1128 $args['private'] = 0;
1129 $args['status'] = 0;
1130 }
1131 $days = apply_filters( 'wpforo_recent_posts_limit', 30 );
1132
1133 $end_date = time() - ( intval( $days ) * 24 * 60 * 60 );
1134 if( $type === 'topics' ) {
1135 $current_object['items_per_page'] = wpforo_setting( 'topics', 'topics_per_page' );
1136
1137 if( wpfval( $args, 'prefixid' ) ) $args['prefix'] = (int) wpfval( $args, 'prefixid' );
1138 $args['where'] = "`modified` > '" . gmdate( 'Y-m-d H:i:s', $end_date ) . "'";
1139 $args['orderby'] = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'topics', 'modified' ) : 'modified';
1140 $args['order'] = 'DESC';
1141 $args['offset'] = ( $current_object['paged'] - 1 ) * $current_object['items_per_page'];
1142 $args['row_count'] = $current_object['items_per_page'];
1143
1144 switch( $view ) {
1145 case 'unread':
1146 $args['read'] = false;
1147 break;
1148 case 'no-replies':
1149 $args['where'] = null;
1150 $args['include'] = wpforo_get_not_replied_topicids();
1151 break;
1152 case 'solved':
1153 $args['solved'] = 1;
1154 break;
1155 case 'unsolved':
1156 $args['solved'] = 0;
1157 break;
1158 case 'closed':
1159 $args['closed'] = 1;
1160 break;
1161 case 'opened':
1162 $args['closed'] = 0;
1163 break;
1164 case 'sticky':
1165 $args['type'] = 1;
1166 break;
1167 case 'private':
1168 $args['private'] = 1;
1169 break;
1170 case 'unapproved':
1171 $args['status'] = 1;
1172 break;
1173 case 'prefix':
1174 $args['where'] = null;
1175 break;
1176 }
1177 $topics = $view === 'no-replies' && empty( $args['include'] ) ? [] : WPF()->topic->get_topics( $args, $current_object['items_count'] );
1178 if( $topics ) {
1179 $intro_posts = wpforo_setting( 'topics', 'layout_extended_intro_posts_count' );
1180 if( $intro_posts < 1 ) {
1181 $intro_posts = null;
1182 } else {
1183 $intro_posts = ( $intro_posts > 1 ) ? ( $intro_posts - 1 ) : 0;
1184 }
1185 foreach( $topics as $key => $topic ) {
1186 $topics[ $key ]['replies'] = [];
1187 $topics[ $key ]['member'] = wpforo_member( $topic );
1188 $topics[ $key ]['forum'] = wpforo_forum( $topic['forumid'] );
1189 if( isset( $topic['last_post'] ) && $topic['last_post'] != 0 ) {
1190 $topics[ $key ]['last_post'] = wpforo_post( $topic['last_post'] );
1191 $topics[ $key ]['last_poster'] = wpforo_member( $topics[ $key ]['last_post'] );
1192 }
1193 if( isset( $topic['first_postid'] ) && $topic['first_postid'] != 0 ) {
1194 $topics[ $key ]['first_post'] = wpforo_post( $topic['first_postid'] );
1195
1196 $topics[ $key ]['first_poster'] = wpforo_member( $topics[ $key ]['first_post'] );
1197 if( ! $view && apply_filters( 'wpforo_recent_topics_intro', true, $topic ) ) {
1198 $topics[ $key ]['replies'] = WPF()->post->get_posts(
1199 [ 'topicid' => $topic['topicid'], 'orderby' => '`is_first_post` ASC, `created` DESC, `postid` DESC', 'row_count' => $intro_posts ]
1200 );
1201 }
1202 }
1203 $topics[ $key ]['topic_url'] = wpforo_topic( $topic['topicid'], 'url' );
1204 $topics[ $key ]['topic_posturl'] = ( $view === 'unread' && wpfval( $topics[ $key ]['last_post'], 'url' ) ) ? $topics[ $key ]['last_post']['url'] : WPF()->topic->get_url(
1205 $topic['topicid']
1206 );
1207 }
1208 $args['intro_posts'] = $intro_posts;
1209 }
1210 $current_object['topics'] = $topics;
1211 } else {
1212 $current_object['items_per_page'] = wpforo_setting( 'topics', 'posts_per_page' );
1213
1214 if( $view !== 'unapproved' ) $args['where'] = "`created` > '" . gmdate( 'Y-m-d H:i:s', $end_date ) . "'";
1215 $args['orderby'] = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'posts', 'created' ) : 'created';
1216 $args['order'] = 'DESC';
1217 $args['offset'] = ( $current_object['paged'] - 1 ) * $current_object['items_per_page'];
1218 $args['row_count'] = $current_object['items_per_page'];
1219 if( $view === 'unapproved' ) {
1220 $args['status'] = 1;
1221 }
1222 $current_object['posts'] = WPF()->post->get_posts( $args, $current_object['items_count'] );
1223 }
1224 $args['view'] = $view;
1225 $args['type'] = $type;
1226 $current_object['args'] = $args;
1227 } elseif( $this->current_object['template'] === 'recent-activity' ) {
1228 $current_object['items_per_page'] = 20;
1229 $current_object['items_count'] = 0;
1230
1231 // Get filter parameters from URL
1232 $activity_type = ! empty( WPF()->GET['type'] ) ? sanitize_text_field( WPF()->GET['type'] ) : 'all';
1233 $period = ! empty( WPF()->GET['period'] ) ? sanitize_text_field( WPF()->GET['period'] ) : 'week';
1234
1235 // Calculate date_from based on period
1236 $date_from = null;
1237 switch( $period ) {
1238 case 'day':
1239 $date_from = time() - ( 24 * 60 * 60 );
1240 break;
1241 case 'week':
1242 $date_from = time() - ( 7 * 24 * 60 * 60 );
1243 break;
1244 case 'month':
1245 $date_from = time() - ( 30 * 24 * 60 * 60 );
1246 break;
1247 case 'all':
1248 default:
1249 $date_from = null;
1250 break;
1251 }
1252
1253 // Get enabled activity types from settings
1254 $enabled_types = WPF()->settings->activity['enabled_types'] ?? [];
1255
1256 // Build activity query args
1257 $args = [
1258 'types_exclude' => [ 'new_reply' ], // Exclude notification-only types
1259 'orderby' => 'date',
1260 'order' => 'DESC',
1261 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1262 'row_count' => $current_object['items_per_page'],
1263 'date_from' => $date_from,
1264 ];
1265
1266 // Filter by activity type
1267 if( $activity_type !== 'all' ) {
1268 $type_mapping = [
1269 'topic' => [ 'wpforo_topic', 'edit_topic' ],
1270 'reply' => [ 'wpforo_post', 'edit_post' ],
1271 'reaction' => [ 'new_like', 'new_dislike', 'new_up_vote', 'new_down_vote', 'new_reaction' ],
1272 'favorite' => [ 'new_favorite' ],
1273 'solved' => [ 'topic_solved' ],
1274 'closed' => [ 'topic_closed' ],
1275 'answer' => [ 'post_answer' ],
1276 ];
1277 if( isset( $type_mapping[ $activity_type ] ) ) {
1278 // Intersect with enabled types to respect settings
1279 $args['types_include'] = array_intersect( $type_mapping[ $activity_type ], $enabled_types );
1280 }
1281 } else {
1282 // Show all enabled types
1283 if( ! empty( $enabled_types ) ) {
1284 $args['types_include'] = $enabled_types;
1285 }
1286 }
1287
1288 $current_object['activities'] = WPF()->activity->get_activities( $args, $current_object['items_count'], true, true );
1289 $current_object['args'] = [
1290 'activity_type' => $activity_type,
1291 'period' => $period,
1292 ];
1293 } elseif( $this->current_object['template'] === 'tags' ) {
1294 $current_object['items_per_page'] = wpforo_setting( 'tags', 'per_page' );
1295 // Tag sort: whitelist the URL key, then map to orderby/order. Never pass raw input to get_tags().
1296 $tag_sort_map = [ 'count' => [ 'count', 'DESC' ], 'az' => [ 'tag', 'ASC' ], 'za' => [ 'tag', 'DESC' ] ];
1297 $tag_sort_key = sanitize_key( (string) wpfval( $_GET, 'wpf_tag_sort' ) );
1298 if( ! isset( $tag_sort_map[ $tag_sort_key ] ) ) $tag_sort_key = 'count';
1299 $current_object['tag_sort'] = $tag_sort_key;
1300 $args = [
1301 'orderby' => $tag_sort_map[ $tag_sort_key ][0],
1302 'order' => $tag_sort_map[ $tag_sort_key ][1],
1303 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1304 'row_count' => $current_object['items_per_page'],
1305 ];
1306 $current_object['tags'] = $this->topic->get_tags( $args, $current_object['items_count'] );
1307 } elseif( $this->current_object['template'] === 'members' ) {
1308 $current_object['items_per_page'] = wpforo_setting( 'members', 'members_per_page' );
1309
1310 $this->form->current['template'] = 'members';
1311 $this->form->current['value'] = $get;
1312 $this->form->current['varname'] = '';
1313
1314 if( ! empty( $get['_wpfms'] ) ) {
1315 $users_include = [];
1316 $search_fields_names = $this->member->get_search_fields_names();
1317
1318 $wpfms = ( isset( $get['wpfms'] ) ) ? sanitize_text_field( $get['wpfms'] ) : '';
1319 if( $wpfms ) {
1320 if( apply_filters( 'wpforo_member_search_provider', false, $wpfms, $search_fields_names, $get ) ) {
1321 $users_include = apply_filters( 'wpforo_search_by_provider', [], $wpfms, $search_fields_names, $get );
1322 } else {
1323 $users_include = $this->member->search( $wpfms, $search_fields_names );
1324 }
1325 } else {
1326 if( $filters = array_filter( $get, function( $v ) { return ! ( is_null( $v ) || $v === false || $v === '' ); } ) ) {
1327 $filters = array_merge( array_filter( (array) wpfval( $get, 'data' ), function( $v ) { return ! ( is_null( $v ) || $v === false || $v === '' ); } ), $filters );
1328 unset( $filters['data'] );
1329 $args = [];
1330 foreach( $filters as $filter_key => $filter ) {
1331 if( in_array( $filter_key, $search_fields_names ) ) {
1332 $args[ $filter_key ] = $filter;
1333 }
1334 }
1335 if( apply_filters( 'wpforo_member_filter_provider', false, $args, $get ) ) {
1336 $users_include = apply_filters( 'wpforo_filter_by_provider', [], $args, $get );
1337 } else {
1338 $users_include = $this->member->filter( $args );
1339 }
1340 }
1341 }
1342
1343 $users_include = apply_filters( 'wpforo_member_search_users_include', $users_include );
1344 }
1345 $member_status = $this->member->get_inlist_enabled_statuses();
1346 $args = [
1347 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1348 'row_count' => $current_object['items_per_page'],
1349 'status' => $member_status,
1350 'groupids' => $this->usergroup->get_visible_usergroup_ids(),
1351 ];
1352
1353 $orderby = wpfval( $get, 'wpfob' ) ? sanitize_text_field( $get['wpfob'] ) : wpforo_setting( 'members', 'list_order' );
1354
1355 switch( $orderby ) {
1356 case 'online_time':
1357 $args['orderby'] = 'online_time';
1358 $args['order'] = 'desc';
1359 break;
1360 case 'posts__asc':
1361 $args['orderby'] = 'posts';
1362 $args['order'] = 'ASC';
1363 break;
1364 case 'user_registered__asc':
1365 $args['orderby'] = 'user_registered';
1366 $args['order'] = 'ASC';
1367 break;
1368 case 'user_registered__desc':
1369 $args['orderby'] = 'user_registered';
1370 $args['order'] = 'DESC';
1371 break;
1372 case 'display_name__asc':
1373 $args['orderby'] = 'display_name';
1374 $args['order'] = 'ASC';
1375 break;
1376 case 'display_name__desc':
1377 $args['orderby'] = 'display_name';
1378 $args['order'] = 'DESC';
1379 break;
1380 default:
1381 $args['orderby'] = 'posts';
1382 $args['order'] = 'DESC';
1383 break;
1384 }
1385 if( ! empty( $users_include ) ) $args['include'] = $users_include;
1386 $args = apply_filters( 'wpforo_current_object_members_args_filter', $args, $get );
1387 $current_object['members'] = $this->member->get_members( $args, $current_object['items_count'] );
1388 if( isset( $users_include ) && empty( $users_include ) ) {
1389 $current_object['members'] = [];
1390 $current_object['items_count'] = 0;
1391 }
1392 } elseif( $this->current_object['template'] === 'add-topic' ) {
1393 if( $qvar0 = (int) wpfval( $current_object['qvars'], 0 ) ) {
1394 $forum = (array) $this->forum->get_forum( $qvar0 );
1395 if( ! $forum || (int) wpfval( $forum, 'is_cat' ) ) {
1396 wp_safe_redirect( wpforo_home_url( wpforo_settings_get_slug( 'add-topic' ) ), 301 );
1397 exit();
1398 }
1399 }
1400 }
1401 }
1402
1403 if( wpfval( $current_object, 'userid' ) || wpfval( $current_object, 'user_nicename' ) ) {
1404 $args = [];
1405 if( isset( $current_object['userid'] ) ) $args['userid'] = $current_object['userid'];
1406 if( isset( $current_object['user_nicename'] ) ) $args['user_nicename'] = $current_object['user_nicename'];
1407 $selected_user = $this->member->get_member( $args );
1408 if( isset( $current_object['userid'] ) && empty( $selected_user ) ) $selected_user = $this->member->get_member( [ 'user_nicename' => $current_object['userid'] ] );
1409 $selected_user = apply_filters( 'wpforo_init_current_selected_user', $selected_user );
1410 if( $selected_user ) {
1411 $current_object['user'] = $selected_user;
1412 $current_object['userid'] = $selected_user['userid'];
1413 $current_object['user_nicename'] = $selected_user['user_nicename'];
1414 $current_object['user_is_same_current_user'] = ! empty( $this->current_userid ) && $selected_user['userid'] === $this->current_userid;
1415
1416 if( $this->tpl->can_view_template( $this->current_object['template'], $current_object['user'] ) ) {
1417 switch( $this->current_object['template'] ) {
1418 case 'activity':
1419 $args = [
1420 'offset' => ( $current_object['paged'] - 1 ) * $this->current_object['items_per_page'],
1421 'row_count' => $this->current_object['items_per_page'],
1422 'userid' => $current_object['userid'],
1423 'orderby' => '`created` DESC, `postid` DESC',
1424 'check_private' => true,
1425 'is_first_post' => wpfval( $this->GET, 'filter' ) ? $this->GET['filter'] === 'topics' : null,
1426 ];
1427 $current_object['items_count'] = 0;
1428 $current_object['activities'] = $this->post->get_posts( $args, $current_object['items_count'] );
1429 break;
1430 case 'favored':
1431 $current_object['filter'] = strtolower( (string) wpfval( WPF()->GET, 'filter' ) );
1432 if( ! in_array( $current_object['filter'], [ 'likes', 'dislikes' ], true ) ) $current_object['filter'] = 'bookmarks';
1433 if( $current_object['filter'] === 'likes' ) {
1434 $postids = $this->reaction->get_reactions_col(
1435 'postid',
1436 [
1437 'userid' => $current_object['userid'],
1438 'type_include' => 'up',
1439 ]
1440 );
1441 } elseif( $current_object['filter'] === 'dislikes' ) {
1442 $postids = $this->reaction->get_reactions_col(
1443 'postid',
1444 [
1445 'userid' => $current_object['userid'],
1446 'type_include' => 'down',
1447 ]
1448 );
1449 } else {
1450 $postids = $this->bookmark->get_bookmarks_col(
1451 'postid',
1452 [
1453 'userid' => $current_object['userid'],
1454 'boardid' => $this->board->get_current( 'boardid' ),
1455 'status' => true,
1456 ]
1457 );
1458 }
1459
1460 if( $postids ) {
1461 $args = [
1462 'offset' => ( $current_object['paged'] - 1 ) * $this->current_object['items_per_page'],
1463 'row_count' => $this->current_object['items_per_page'],
1464 'orderby' => '`created` DESC, `postid` DESC',
1465 'check_private' => true,
1466 'include' => $postids,
1467 ];
1468 $current_object['items_count'] = 0;
1469 $current_object['favored_posts'] = $this->post->get_posts( $args, $current_object['items_count'] );
1470 } else {
1471 $current_object['items_count'] = 0;
1472 $current_object['favored_posts'] = [];
1473 }
1474 break;
1475 case 'account':
1476 $this->form->current['template'] = 'account';
1477 $this->form->current['varname'] = 'member';
1478 $this->form->current['value'] = array_merge( $current_object['user'], (array) wpfval( $_POST, 'member' ) );
1479 break;
1480 default:
1481 $this->form->current['template'] = 'profile';
1482 $this->form->current['value'] = $current_object['user'];
1483 break;
1484 }
1485 } else {
1486 if( ! $this->current_userid ) {
1487 wp_safe_redirect( wpforo_login_url() );
1488 exit();
1489 }
1490 $current_object['is_404'] = true;
1491 }
1492
1493 } else {
1494 $current_object['is_404'] = true;
1495 }
1496 }
1497
1498 if( wpfval( $current_object, 'topic_slug' ) ) {
1499 $topic = $this->topic->get_topic( [ 'slug' => $current_object['topic_slug'] ], false );
1500 if( ! empty( $topic ) ) {
1501 $topic_forumid = intval( wpfval( $topic, 'forumid' ) );
1502 $is_owner = wpforo_is_owner( $topic['userid'], $topic['email'] );
1503
1504 if( apply_filters( 'wpforo_current_object_topic_protect', true, $topic ) && $topic_forumid && ( ! $this->perm->forum_can(
1505 'vf',
1506 $topic_forumid
1507 ) || ( ! $is_owner && ! $this->perm->forum_can( 'vt', $topic_forumid ) ) || ( wpfval( $topic, 'private' ) && ! $is_owner && ! $this->perm->forum_can(
1508 'vp',
1509 $topic_forumid
1510 ) ) || ( wpfval( $topic, 'status' ) && ! $is_owner && ! $this->perm->forum_can( 'au', $topic_forumid ) ) ) ) {
1511 if( ! $this->current_userid ) {
1512 wp_safe_redirect( wpforo_login_url() );
1513 exit();
1514 }
1515 $current_object['is_404'] = true;
1516 } else {
1517 $current_object['topic'] = $topic;
1518 $current_object['topicid'] = $topic['topicid'];
1519 $current_object['og_text'] = (string) wpfval( $topic, 'title' );
1520 }
1521 } else {
1522 $current_object['is_404'] = true;
1523 }
1524 }
1525
1526 if( wpfval( $current_object, 'forum_slug' ) ) {
1527 $args = ( empty( $topic ) ? [ 'slug' => $current_object['forum_slug'] ] : $topic['forumid'] );
1528 if( $forum = $this->forum->get_forum( $args ) ) {
1529 if( ! empty( $topic ) && strtolower( (string) $current_object['forum_slug'] ) !== strtolower( (string) $forum['slug'] ) ) {
1530 wp_safe_redirect( $this->topic->get_url( $topic, $forum ), 301 );
1531 exit();
1532 }
1533 if( $forum['is_cat'] ) $this->current_object['template'] = 'forum';
1534 $current_object['forum'] = $forum;
1535 $current_object['forumid'] = $forum['forumid'];
1536 $current_object['forum_desc'] = $forum['description'];
1537 $current_object['forum_meta_key'] = $forum['meta_key'];
1538 $current_object['forum_meta_desc'] = $forum['meta_desc'];
1539 $current_object['og_text'] = $forum['title'];
1540 $current_object['layout'] = $this->forum->get_layout( $forum );
1541
1542 if( $this->current_object['template'] === 'topic' ) {
1543 $current_object['items_per_page'] = wpforo_setting( 'topics', 'topics_per_page' );
1544 $args = [
1545 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1546 'row_count' => $current_object['items_per_page'],
1547 'forumid' => $current_object['forumid'],
1548 'orderby' => 'type, modified',
1549 'order' => 'DESC',
1550 ];
1551 $args = apply_filters( 'wpforo_topic_list_args', $args );
1552 $current_object['topics'] = $this->topic->get_topics( $args, $current_object['items_count'] );
1553 }
1554 } else {
1555 $current_object['is_404'] = true;
1556 }
1557 }
1558
1559 if( in_array( $this->current_object['template'], [ 'forum', 'topic' ] ) ) {
1560 if( ! empty( $forum ) ) {
1561 $current_object['categories'] = [ $forum ];
1562 } else {
1563 $current_object['categories'] = $this->forum->get_forums( [ "type" => 'category' ] );
1564 }
1565 }
1566
1567 if( $this->current_object['template'] === 'post' && ! empty( $forum ) && ! empty( $topic ) ) {
1568 $current_object['items_per_page'] = $this->post->get_option_items_per_page( $current_object['layout'] );
1569
1570 $args = [
1571 'forumid' => $forum['forumid'],
1572 'topicid' => $topic['topicid'],
1573 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1574 'row_count' => $current_object['items_per_page'],
1575 ];
1576 if( $current_object['layout'] == 4 ) {
1577 $args['parentid'] = 0;
1578 } elseif( $current_object['layout'] == 3 ) {
1579 $args['parentid'] = 0;
1580 switch( $current_object['orderby'] ) {
1581 case 'oldest':
1582 $args['orderby'] = '`is_first_post` DESC, `is_answer` DESC, `created` ASC, `postid` ASC';
1583 break;
1584 case 'newest':
1585 $args['orderby'] = '`is_first_post` DESC, `is_answer` DESC, `modified` DESC, `postid` DESC';
1586 break;
1587 default:
1588 $args['orderby'] = '`is_first_post` DESC, `is_answer` DESC, `votes` DESC, `created` ASC, `postid` ASC';
1589 break;
1590 }
1591 }
1592 if( $this->post->get_option_union_first_post( $current_object['layout'] ) ) $args['union_first_post'] = true;
1593 $args = apply_filters( 'wpforo_post_list_args', $args );
1594 $current_object['posts'] = $this->post->get_posts( $args, $current_object['items_count'] );
1595 }
1596
1597 $this->current_object = wpforo_parse_args( $current_object, $this->current_object );
1598
1599 $this->current_object = apply_filters( 'wpforo_after_init_current_object', $this->current_object, $wpf_url_parse );
1600
1601 if( $this->current_object['template'] ) {
1602 /**
1603 * redirect not logged-in users to login page when that user no access to this page
1604 */
1605 if( ! $this->current_userid && $this->current_object['forumid'] && ( ( in_array( $this->current_object['template'], [ 'forum', 'topic' ] ) && ! $this->perm->forum_can(
1606 'vf',
1607 $this->current_object['forumid']
1608 ) ) || ( $this->current_object['template'] === 'post' && ! $this->perm->forum_can( 'vt', $this->current_object['forumid'] ) ) ) ) {
1609 wp_safe_redirect( wpforo_login_url() );
1610 exit();
1611 }
1612
1613 if( $this->current_object['template'] === 'cantlogin' ) {
1614 if( $this->current_userid ) {
1615 if( $this->current_user['status'] !== 'active' ) {
1616 WPF()->ram_cache->set( 'USER_LOGIN_REFERER', WPF()->current_user_login );
1617 wp_logout();
1618 } else {
1619 wp_safe_redirect( wpforo_home_url() );
1620 }
1621 } else {
1622 wp_safe_redirect( wpforo_login_url() );
1623 exit();
1624 }
1625 }
1626
1627 /**
1628 * redirect to the first page when paged var is greater items_count
1629 */
1630 if( $this->current_object['items_count'] && $this->current_object['paged'] > 1 && ( ( $this->current_object['paged'] - 1 ) * $this->current_object['items_per_page'] ) >= $this->current_object['items_count'] ) {
1631 wp_safe_redirect( $this->strip_url_paged_var( $this->current_url ), 301 );
1632 exit();
1633 }
1634 } else {
1635 $this->current_object['is_404'] = true;
1636 }
1637 }
1638
1639 public function get_version() {
1640 return wpforo_get_option( 'version', null, false );
1641 }
1642
1643 public function need_activation() {
1644 return WPFORO_VERSION !== $this->get_version();
1645 }
1646
1647 public function is_installed() {
1648 return (bool) $this->get_version();
1649 }
1650
1651 public function can_use_this_slug( $slug ) {
1652 $return = ! in_array( $slug, $this->settings->slugs, true ) && ! in_array( $slug, array_keys( $this->settings->slugs ), true );
1653
1654 return apply_filters( 'wpforo_can_use_this_slug', $return, $slug );
1655 }
1656 }
1657