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

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

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