PluginProbe
wpForo Forum / 3.2.0
wpForo Forum v3.2.0
3.2.0 3.1.7 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 All 140 releases
wpforo / wpforo.php

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

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