PluginProbe
wpForo Forum / 3.0.8
wpForo Forum v3.0.8
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.8, at wpforo.php

1,645 lines 61.8 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.8
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.8' );
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'] = array_merge(
944 (array) wpfval( $this->form->current, 'value' ),
945 (array) wpfval( $_POST, 'wpfreg' ),
946 (array) wpfval( $_POST, 'data' )
947 );
948 $this->form->current['value']['user_login'] = sanitize_user( (string) wpfval( $_POST, 'wpfreg', 'user_login' ) );
949 $this->form->current['value']['user_email'] = sanitize_email( (string) wpfval( $_POST, 'wpfreg', 'user_email' ) );
950 $this->form->current['varname'] = 'wpfreg';
951 } elseif( $this->current_object['template'] === 'logout' && $this->current_userid ) {
952 $this->action->logout();
953 }
954 }
955
956 if( $this->current_userid && in_array( $this->current_object['template'], [ 'register', 'login', 'lostpassword' ], true ) && ! wpforo_is_admin() ) wpforo_redirect_to();
957 }
958 $wpf_url_parse = array_reverse( $wpf_url_parse );
959
960 if( in_array( wpforo_settings_get_slug( 'paged' ), $wpf_url_parse ) ) {
961 foreach( $wpf_url_parse as $key => $value ) {
962 if( $value === wpforo_settings_get_slug( 'paged' ) ) {
963 unset( $wpf_url_parse[ $key ] );
964 break;
965 }
966 if( is_numeric( $value ) ) $paged = intval( $value );
967
968 unset( $wpf_url_parse[ $key ] );
969 }
970 }
971 if( $_paged = intval( wpfval( $get, 'wpfpaged' ) ) ) $paged = $_paged;
972 $current_object['paged'] = ( isset( $paged ) && $paged > 0 ) ? $paged : 1;
973 $current_object['orderby'] = wpfval( $get, 'orderby' );
974
975 $wpf_url_parse = array_values( $wpf_url_parse );
976
977 if( ! $this->current_object['template'] ) {
978 $current_object = apply_filters( 'wpforo_before_init_current_object', $current_object, $wpf_url_parse );
979 if( wpfkey( $current_object, 'template' ) ) $this->current_object['template'] = (string) wpfval( $current_object, 'template' );
980 }
981
982 if( ! $this->current_object['template'] ) {
983 $templates = $template_key === 'member' ? $this->tpl->get_member_templates_list() : $this->tpl->get_templates_list();
984 if( $templates ) {
985 if( $template_key === 'member' ) {
986 if( count( $wpf_url_parse ) > 1 ) {
987 $nickname = end( $wpf_url_parse );
988 $profile_route = prev( $wpf_url_parse );
989 array_pop( $wpf_url_parse );
990 array_pop( $wpf_url_parse );
991 array_push( $wpf_url_parse, $nickname, $profile_route );
992 } else {
993 if( ! in_array( end( $wpf_url_parse ), array_map( 'wpforo_settings_get_slug', $templates ) ) ) $wpf_url_parse[] = wpforo_settings_get_slug( 'profile' );
994 }
995 }
996 $__slug = end( $wpf_url_parse );
997 foreach( $templates as $template ) {
998 if( $__slug === wpforo_settings_get_slug( $template ) ) {
999 $this->current_object['template'] = $template;
1000 $current_object['qvars'] = $wpf_url_parse;
1001 array_pop( $current_object['qvars'] );
1002 $current_object['qvars'] = array_reverse( $current_object['qvars'] );
1003 break;
1004 }
1005 }
1006
1007 if( $template_key === 'member' ) {
1008 if( ! $this->current_object['template'] && ! $wpf_url_parse ) {
1009 if( $this->current_userid ) {
1010 $this->current_object['template'] = 'profile';
1011 } else {
1012 wp_safe_redirect( wpforo_login_url() );
1013 exit();
1014 }
1015 } elseif( ! wpforo_is_member_template( $this->current_object['template'] ) ) {
1016 $this->current_object['template'] = '';
1017 $current_object['qvars'] = [];
1018 }
1019 }
1020 }
1021 }
1022
1023 if( ! $this->current_object['template'] ) {
1024 $this->current_object['template'] = 'forum';
1025 $this->form->current['varname'] = 'thread';
1026 if( isset( $wpf_url_parse[0] ) ) {
1027 if( isset( $wpf_url_parse[1] ) ) {
1028 $current_object['topic_slug'] = $wpf_url_parse[0];
1029 $current_object['forum_slug'] = $wpf_url_parse[1];
1030 $this->current_object['template'] = 'post';
1031 $this->form->current['varname'] = 'post';
1032 } else {
1033 $current_object['forum_slug'] = $wpf_url_parse[0];
1034 $this->current_object['template'] = 'topic';
1035 $this->form->current['varname'] = 'thread';
1036 }
1037 }
1038 }
1039
1040 $current_object = apply_filters( 'wpforo_after_init_current_template', $current_object, $wpf_url_parse, $get );
1041 if( wpfkey( $current_object, 'template' ) ) $this->current_object['template'] = (string) wpfval( $current_object, 'template' );
1042
1043 if( $this->current_object['template'] ) {
1044 if( wpforo_is_member_template( $this->current_object['template'] ) ) {
1045 if( ! wpfval( $current_object, 'userid' ) && ! wpfval( $current_object, 'user_nicename' ) ) {
1046 if( $qvar0 = wpfval( $current_object['qvars'], 0 ) ) {
1047 if( wpforo_setting( 'profiles', 'url_structure' ) === 'id' ) {
1048 $current_object['userid'] = $qvar0;
1049 } else {
1050 $current_object['user_nicename'] = $qvar0;
1051 }
1052 } else {
1053 if( $this->current_userid ) {
1054 $current_object['userid'] = $this->current_userid;
1055 } else {
1056 wp_safe_redirect( wpforo_login_url() );
1057 exit();
1058 }
1059 }
1060 }
1061
1062 // redirect old type of member urls to new one
1063 if( $template_key !== 'member' ) {
1064 if( count( $current_object['qvars'] ) === 1 ) {
1065 $redirect = wpforo_url(
1066 array_shift( $current_object['qvars'] ) . ( $this->current_object['template'] !== 'profile' ? '/' . wpforo_settings_get_slug( $this->current_object['template'] ) : '' ),
1067 'member'
1068 );
1069 } else {
1070 $redirect = wpforo_url(
1071 array_shift( $current_object['qvars'] ) . '/' . wpforo_settings_get_slug( $this->current_object['template'] ) . '/' . implode( '/', $current_object['qvars'] ),
1072 'member'
1073 );
1074 }
1075 wp_safe_redirect( $redirect );
1076 exit();
1077 }
1078 // redirection
1079
1080 } elseif( $this->current_object['template'] === 'search' ) {
1081 $args = [
1082 'needle' => sanitize_text_field( wpfval( $get, 'wpfs' ) ),
1083 'type' => sanitize_text_field( wpfval( $get, 'wpfin' ) ),
1084 'date_period' => intval( wpfval( $get, 'wpfd' ) ),
1085 'forumids' => (array) wpfval( $get, 'wpff' ),
1086 'offset' => ( $current_object['paged'] - 1 ) * $this->current_object['items_per_page'],
1087 'row_count' => $this->current_object['items_per_page'],
1088 'orderby' => 'relevancy',
1089 'order' => 'desc',
1090 'postids' => [],
1091 ];
1092 if( ! empty( $get['wpfob'] ) ) {
1093 $args['orderby'] = wpforo_sanitize_orderby( $get['wpfob'], 'search', 'relevancy' );
1094 } elseif( in_array( wpfval( $args, 'type' ), [ 'tag', 'user-posts', 'user-topics' ], true ) ) {
1095 $args['orderby'] = 'date';
1096 }
1097 $wpfo = strtolower( (string) wpfval( $get, 'wpfo' ) );
1098 if( in_array( $wpfo, [ 'asc', 'desc' ], true ) ) $args['order'] = $wpfo;
1099 $sdata = array_filter( (array) wpfval( $get, 'data' ) );
1100 $args['postids'] = $this->postmeta->search( $sdata );
1101 $current_object['args'] = $args;
1102 if( $sdata && ! $args['postids'] ) {
1103 $current_object['items_count'] = 0;
1104 $current_object['posts'] = [];
1105 } else {
1106 $current_object['posts'] = $this->post->search( $args, $current_object['items_count'] );
1107 }
1108 } elseif( $this->current_object['template'] === 'recent' ) {
1109 $args = [];
1110 $view = false;
1111 $current_object['items_count'] = 0;
1112 if( ! empty( WPF()->GET['view'] ) ) $view = sanitize_title( WPF()->GET['view'] );
1113 if( ! empty( WPF()->GET['wpff'] ) ) $args['forumid'] = intval( WPF()->GET['wpff'] );
1114 if( ! empty( WPF()->GET['prefixid'] ) ) {
1115 $args['prefixid'] = intval( WPF()->GET['prefixid'] );
1116 }
1117
1118 $type = ( $view && $view !== 'unapproved' ? 'topics' : wpforo_setting( 'topics', 'recent_posts_type' ) );
1119 if( $view === 'unapproved' ) $type = 'posts';
1120 if( $view === 'prefix' ) $type = 'topics';
1121
1122 if( ! WPF()->current_userid || ! WPF()->usergroup->can( 'aum' ) ) {
1123 $args['private'] = 0;
1124 $args['status'] = 0;
1125 }
1126 $days = apply_filters( 'wpforo_recent_posts_limit', 30 );
1127
1128 $end_date = time() - ( intval( $days ) * 24 * 60 * 60 );
1129 if( $type === 'topics' ) {
1130 $current_object['items_per_page'] = wpforo_setting( 'topics', 'topics_per_page' );
1131
1132 if( wpfval( $args, 'prefixid' ) ) $args['prefix'] = (int) wpfval( $args, 'prefixid' );
1133 $args['where'] = "`modified` > '" . gmdate( 'Y-m-d H:i:s', $end_date ) . "'";
1134 $args['orderby'] = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'topics', 'modified' ) : 'modified';
1135 $args['order'] = 'DESC';
1136 $args['offset'] = ( $current_object['paged'] - 1 ) * $current_object['items_per_page'];
1137 $args['row_count'] = $current_object['items_per_page'];
1138
1139 switch( $view ) {
1140 case 'unread':
1141 $args['read'] = false;
1142 break;
1143 case 'no-replies':
1144 $args['where'] = null;
1145 $args['include'] = wpforo_get_not_replied_topicids();
1146 break;
1147 case 'solved':
1148 $args['solved'] = 1;
1149 break;
1150 case 'unsolved':
1151 $args['solved'] = 0;
1152 break;
1153 case 'closed':
1154 $args['closed'] = 1;
1155 break;
1156 case 'opened':
1157 $args['closed'] = 0;
1158 break;
1159 case 'sticky':
1160 $args['type'] = 1;
1161 break;
1162 case 'private':
1163 $args['private'] = 1;
1164 break;
1165 case 'unapproved':
1166 $args['status'] = 1;
1167 break;
1168 case 'prefix':
1169 $args['where'] = null;
1170 break;
1171 }
1172 $topics = $view === 'no-replies' && empty( $args['include'] ) ? [] : WPF()->topic->get_topics( $args, $current_object['items_count'] );
1173 if( $topics ) {
1174 $intro_posts = wpforo_setting( 'topics', 'layout_extended_intro_posts_count' );
1175 if( $intro_posts < 1 ) {
1176 $intro_posts = null;
1177 } else {
1178 $intro_posts = ( $intro_posts > 1 ) ? ( $intro_posts - 1 ) : 0;
1179 }
1180 foreach( $topics as $key => $topic ) {
1181 $topics[ $key ]['replies'] = [];
1182 $topics[ $key ]['member'] = wpforo_member( $topic );
1183 $topics[ $key ]['forum'] = wpforo_forum( $topic['forumid'] );
1184 if( isset( $topic['last_post'] ) && $topic['last_post'] != 0 ) {
1185 $topics[ $key ]['last_post'] = wpforo_post( $topic['last_post'] );
1186 $topics[ $key ]['last_poster'] = wpforo_member( $topics[ $key ]['last_post'] );
1187 }
1188 if( isset( $topic['first_postid'] ) && $topic['first_postid'] != 0 ) {
1189 $topics[ $key ]['first_post'] = wpforo_post( $topic['first_postid'] );
1190
1191 $topics[ $key ]['first_poster'] = wpforo_member( $topics[ $key ]['first_post'] );
1192 if( ! $view && apply_filters( 'wpforo_recent_topics_intro', true, $topic ) ) {
1193 $topics[ $key ]['replies'] = WPF()->post->get_posts(
1194 [ 'topicid' => $topic['topicid'], 'orderby' => '`is_first_post` ASC, `created` DESC, `postid` DESC', 'row_count' => $intro_posts ]
1195 );
1196 }
1197 }
1198 $topics[ $key ]['topic_url'] = wpforo_topic( $topic['topicid'], 'url' );
1199 $topics[ $key ]['topic_posturl'] = ( $view === 'unread' && wpfval( $topics[ $key ]['last_post'], 'url' ) ) ? $topics[ $key ]['last_post']['url'] : WPF()->topic->get_url(
1200 $topic['topicid']
1201 );
1202 }
1203 $args['intro_posts'] = $intro_posts;
1204 }
1205 $current_object['topics'] = $topics;
1206 } else {
1207 $current_object['items_per_page'] = wpforo_setting( 'topics', 'posts_per_page' );
1208
1209 if( $view !== 'unapproved' ) $args['where'] = "`created` > '" . gmdate( 'Y-m-d H:i:s', $end_date ) . "'";
1210 $args['orderby'] = ( ! empty( WPF()->GET['wpfob'] ) ) ? wpforo_sanitize_orderby( WPF()->GET['wpfob'], 'posts', 'created' ) : 'created';
1211 $args['order'] = 'DESC';
1212 $args['offset'] = ( $current_object['paged'] - 1 ) * $current_object['items_per_page'];
1213 $args['row_count'] = $current_object['items_per_page'];
1214 if( $view === 'unapproved' ) {
1215 $args['status'] = 1;
1216 }
1217 $current_object['posts'] = WPF()->post->get_posts( $args, $current_object['items_count'] );
1218 }
1219 $args['view'] = $view;
1220 $args['type'] = $type;
1221 $current_object['args'] = $args;
1222 } elseif( $this->current_object['template'] === 'recent-activity' ) {
1223 $current_object['items_per_page'] = 20;
1224 $current_object['items_count'] = 0;
1225
1226 // Get filter parameters from URL
1227 $activity_type = ! empty( WPF()->GET['type'] ) ? sanitize_text_field( WPF()->GET['type'] ) : 'all';
1228 $period = ! empty( WPF()->GET['period'] ) ? sanitize_text_field( WPF()->GET['period'] ) : 'week';
1229
1230 // Calculate date_from based on period
1231 $date_from = null;
1232 switch( $period ) {
1233 case 'day':
1234 $date_from = time() - ( 24 * 60 * 60 );
1235 break;
1236 case 'week':
1237 $date_from = time() - ( 7 * 24 * 60 * 60 );
1238 break;
1239 case 'month':
1240 $date_from = time() - ( 30 * 24 * 60 * 60 );
1241 break;
1242 case 'all':
1243 default:
1244 $date_from = null;
1245 break;
1246 }
1247
1248 // Get enabled activity types from settings
1249 $enabled_types = WPF()->settings->activity['enabled_types'] ?? [];
1250
1251 // Build activity query args
1252 $args = [
1253 'types_exclude' => [ 'new_reply' ], // Exclude notification-only types
1254 'orderby' => 'date',
1255 'order' => 'DESC',
1256 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1257 'row_count' => $current_object['items_per_page'],
1258 'date_from' => $date_from,
1259 ];
1260
1261 // Filter by activity type
1262 if( $activity_type !== 'all' ) {
1263 $type_mapping = [
1264 'topic' => [ 'wpforo_topic', 'edit_topic' ],
1265 'reply' => [ 'wpforo_post', 'edit_post' ],
1266 'reaction' => [ 'new_like', 'new_dislike', 'new_up_vote', 'new_down_vote', 'new_reaction' ],
1267 'favorite' => [ 'new_favorite' ],
1268 'solved' => [ 'topic_solved' ],
1269 'closed' => [ 'topic_closed' ],
1270 'answer' => [ 'post_answer' ],
1271 ];
1272 if( isset( $type_mapping[ $activity_type ] ) ) {
1273 // Intersect with enabled types to respect settings
1274 $args['types_include'] = array_intersect( $type_mapping[ $activity_type ], $enabled_types );
1275 }
1276 } else {
1277 // Show all enabled types
1278 if( ! empty( $enabled_types ) ) {
1279 $args['types_include'] = $enabled_types;
1280 }
1281 }
1282
1283 $current_object['activities'] = WPF()->activity->get_activities( $args, $current_object['items_count'], true, true );
1284 $current_object['args'] = [
1285 'activity_type' => $activity_type,
1286 'period' => $period,
1287 ];
1288 } elseif( $this->current_object['template'] === 'tags' ) {
1289 $current_object['items_per_page'] = wpforo_setting( 'tags', 'per_page' );
1290 $args = [
1291 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1292 'row_count' => $current_object['items_per_page'],
1293 ];
1294 $current_object['tags'] = $this->topic->get_tags( $args, $current_object['items_count'] );
1295 } elseif( $this->current_object['template'] === 'members' ) {
1296 $current_object['items_per_page'] = wpforo_setting( 'members', 'members_per_page' );
1297
1298 $this->form->current['template'] = 'members';
1299 $this->form->current['value'] = $get;
1300 $this->form->current['varname'] = '';
1301
1302 if( ! empty( $get['_wpfms'] ) ) {
1303 $users_include = [];
1304 $search_fields_names = $this->member->get_search_fields_names();
1305
1306 $wpfms = ( isset( $get['wpfms'] ) ) ? sanitize_text_field( $get['wpfms'] ) : '';
1307 if( $wpfms ) {
1308 if( apply_filters( 'wpforo_member_search_provider', false, $wpfms, $search_fields_names, $get ) ) {
1309 $users_include = apply_filters( 'wpforo_search_by_provider', [], $wpfms, $search_fields_names, $get );
1310 } else {
1311 $users_include = $this->member->search( $wpfms, $search_fields_names );
1312 }
1313 } else {
1314 if( $filters = array_filter( $get, function( $v ) { return ! ( is_null( $v ) || $v === false || $v === '' ); } ) ) {
1315 $filters = array_merge( array_filter( (array) wpfval( $get, 'data' ), function( $v ) { return ! ( is_null( $v ) || $v === false || $v === '' ); } ), $filters );
1316 unset( $filters['data'] );
1317 $args = [];
1318 foreach( $filters as $filter_key => $filter ) {
1319 if( in_array( $filter_key, $search_fields_names ) ) {
1320 $args[ $filter_key ] = $filter;
1321 }
1322 }
1323 if( apply_filters( 'wpforo_member_filter_provider', false, $args, $get ) ) {
1324 $users_include = apply_filters( 'wpforo_filter_by_provider', [], $args, $get );
1325 } else {
1326 $users_include = $this->member->filter( $args );
1327 }
1328 }
1329 }
1330
1331 $users_include = apply_filters( 'wpforo_member_search_users_include', $users_include );
1332 }
1333 $member_status = $this->member->get_inlist_enabled_statuses();
1334 $args = [
1335 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1336 'row_count' => $current_object['items_per_page'],
1337 'status' => $member_status,
1338 'groupids' => $this->usergroup->get_visible_usergroup_ids(),
1339 ];
1340
1341 $orderby = wpfval( $get, 'wpfob' ) ? sanitize_text_field( $get['wpfob'] ) : wpforo_setting( 'members', 'list_order' );
1342
1343 switch( $orderby ) {
1344 case 'online_time':
1345 $args['orderby'] = 'online_time';
1346 $args['order'] = 'desc';
1347 break;
1348 case 'posts__asc':
1349 $args['orderby'] = 'posts';
1350 $args['order'] = 'ASC';
1351 break;
1352 case 'user_registered__asc':
1353 $args['orderby'] = 'user_registered';
1354 $args['order'] = 'ASC';
1355 break;
1356 case 'user_registered__desc':
1357 $args['orderby'] = 'user_registered';
1358 $args['order'] = 'DESC';
1359 break;
1360 case 'display_name__asc':
1361 $args['orderby'] = 'display_name';
1362 $args['order'] = 'ASC';
1363 break;
1364 case 'display_name__desc':
1365 $args['orderby'] = 'display_name';
1366 $args['order'] = 'DESC';
1367 break;
1368 default:
1369 $args['orderby'] = 'posts';
1370 $args['order'] = 'DESC';
1371 break;
1372 }
1373 if( ! empty( $users_include ) ) $args['include'] = $users_include;
1374 $args = apply_filters( 'wpforo_current_object_members_args_filter', $args, $get );
1375 $current_object['members'] = $this->member->get_members( $args, $current_object['items_count'] );
1376 if( isset( $users_include ) && empty( $users_include ) ) {
1377 $current_object['members'] = [];
1378 $current_object['items_count'] = 0;
1379 }
1380 } elseif( $this->current_object['template'] === 'add-topic' ) {
1381 if( $qvar0 = (int) wpfval( $current_object['qvars'], 0 ) ) {
1382 $forum = (array) $this->forum->get_forum( $qvar0 );
1383 if( ! $forum || (int) wpfval( $forum, 'is_cat' ) ) {
1384 wp_safe_redirect( wpforo_home_url( wpforo_settings_get_slug( 'add-topic' ) ), 301 );
1385 exit();
1386 }
1387 }
1388 }
1389 }
1390
1391 if( wpfval( $current_object, 'userid' ) || wpfval( $current_object, 'user_nicename' ) ) {
1392 $args = [];
1393 if( isset( $current_object['userid'] ) ) $args['userid'] = $current_object['userid'];
1394 if( isset( $current_object['user_nicename'] ) ) $args['user_nicename'] = $current_object['user_nicename'];
1395 $selected_user = $this->member->get_member( $args );
1396 if( isset( $current_object['userid'] ) && empty( $selected_user ) ) $selected_user = $this->member->get_member( [ 'user_nicename' => $current_object['userid'] ] );
1397 $selected_user = apply_filters( 'wpforo_init_current_selected_user', $selected_user );
1398 if( $selected_user ) {
1399 $current_object['user'] = $selected_user;
1400 $current_object['userid'] = $selected_user['userid'];
1401 $current_object['user_nicename'] = $selected_user['user_nicename'];
1402 $current_object['user_is_same_current_user'] = ! empty( $this->current_userid ) && $selected_user['userid'] === $this->current_userid;
1403
1404 if( $this->tpl->can_view_template( $this->current_object['template'], $current_object['user'] ) ) {
1405 switch( $this->current_object['template'] ) {
1406 case 'activity':
1407 $args = [
1408 'offset' => ( $current_object['paged'] - 1 ) * $this->current_object['items_per_page'],
1409 'row_count' => $this->current_object['items_per_page'],
1410 'userid' => $current_object['userid'],
1411 'orderby' => '`created` DESC, `postid` DESC',
1412 'check_private' => true,
1413 'is_first_post' => wpfval( $this->GET, 'filter' ) ? $this->GET['filter'] === 'topics' : null,
1414 ];
1415 $current_object['items_count'] = 0;
1416 $current_object['activities'] = $this->post->get_posts( $args, $current_object['items_count'] );
1417 break;
1418 case 'favored':
1419 $current_object['filter'] = strtolower( (string) wpfval( WPF()->GET, 'filter' ) );
1420 if( ! in_array( $current_object['filter'], [ 'likes', 'dislikes' ], true ) ) $current_object['filter'] = 'bookmarks';
1421 if( $current_object['filter'] === 'likes' ) {
1422 $postids = $this->reaction->get_reactions_col(
1423 'postid',
1424 [
1425 'userid' => $current_object['userid'],
1426 'type_include' => 'up',
1427 ]
1428 );
1429 } elseif( $current_object['filter'] === 'dislikes' ) {
1430 $postids = $this->reaction->get_reactions_col(
1431 'postid',
1432 [
1433 'userid' => $current_object['userid'],
1434 'type_include' => 'down',
1435 ]
1436 );
1437 } else {
1438 $postids = $this->bookmark->get_bookmarks_col(
1439 'postid',
1440 [
1441 'userid' => $current_object['userid'],
1442 'boardid' => $this->board->get_current( 'boardid' ),
1443 'status' => true,
1444 ]
1445 );
1446 }
1447
1448 if( $postids ) {
1449 $args = [
1450 'offset' => ( $current_object['paged'] - 1 ) * $this->current_object['items_per_page'],
1451 'row_count' => $this->current_object['items_per_page'],
1452 'orderby' => '`created` DESC, `postid` DESC',
1453 'check_private' => true,
1454 'include' => $postids,
1455 ];
1456 $current_object['items_count'] = 0;
1457 $current_object['favored_posts'] = $this->post->get_posts( $args, $current_object['items_count'] );
1458 } else {
1459 $current_object['items_count'] = 0;
1460 $current_object['favored_posts'] = [];
1461 }
1462 break;
1463 case 'account':
1464 $this->form->current['template'] = 'account';
1465 $this->form->current['varname'] = 'member';
1466 $this->form->current['value'] = array_merge( $current_object['user'], (array) wpfval( $_POST, 'member' ) );
1467 break;
1468 default:
1469 $this->form->current['template'] = 'profile';
1470 $this->form->current['value'] = $current_object['user'];
1471 break;
1472 }
1473 } else {
1474 if( ! $this->current_userid ) {
1475 wp_safe_redirect( wpforo_login_url() );
1476 exit();
1477 }
1478 $current_object['is_404'] = true;
1479 }
1480
1481 } else {
1482 $current_object['is_404'] = true;
1483 }
1484 }
1485
1486 if( wpfval( $current_object, 'topic_slug' ) ) {
1487 $topic = $this->topic->get_topic( [ 'slug' => $current_object['topic_slug'] ], false );
1488 if( ! empty( $topic ) ) {
1489 $topic_forumid = intval( wpfval( $topic, 'forumid' ) );
1490 $is_owner = wpforo_is_owner( $topic['userid'], $topic['email'] );
1491
1492 if( apply_filters( 'wpforo_current_object_topic_protect', true, $topic ) && $topic_forumid && ( ! $this->perm->forum_can(
1493 'vf',
1494 $topic_forumid
1495 ) || ( ! $is_owner && ! $this->perm->forum_can( 'vt', $topic_forumid ) ) || ( wpfval( $topic, 'private' ) && ! $is_owner && ! $this->perm->forum_can(
1496 'vp',
1497 $topic_forumid
1498 ) ) || ( wpfval( $topic, 'status' ) && ! $is_owner && ! $this->perm->forum_can( 'au', $topic_forumid ) ) ) ) {
1499 if( ! $this->current_userid ) {
1500 wp_safe_redirect( wpforo_login_url() );
1501 exit();
1502 }
1503 $current_object['is_404'] = true;
1504 } else {
1505 $current_object['topic'] = $topic;
1506 $current_object['topicid'] = $topic['topicid'];
1507 $current_object['og_text'] = (string) wpfval( $topic, 'title' );
1508 }
1509 } else {
1510 $current_object['is_404'] = true;
1511 }
1512 }
1513
1514 if( wpfval( $current_object, 'forum_slug' ) ) {
1515 $args = ( empty( $topic ) ? [ 'slug' => $current_object['forum_slug'] ] : $topic['forumid'] );
1516 if( $forum = $this->forum->get_forum( $args ) ) {
1517 if( ! empty( $topic ) && strtolower( (string) $current_object['forum_slug'] ) !== strtolower( (string) $forum['slug'] ) ) {
1518 wp_safe_redirect( $this->topic->get_url( $topic, $forum ), 301 );
1519 exit();
1520 }
1521 if( $forum['is_cat'] ) $this->current_object['template'] = 'forum';
1522 $current_object['forum'] = $forum;
1523 $current_object['forumid'] = $forum['forumid'];
1524 $current_object['forum_desc'] = $forum['description'];
1525 $current_object['forum_meta_key'] = $forum['meta_key'];
1526 $current_object['forum_meta_desc'] = $forum['meta_desc'];
1527 $current_object['og_text'] = $forum['title'];
1528 $current_object['layout'] = $this->forum->get_layout( $forum );
1529
1530 if( $this->current_object['template'] === 'topic' ) {
1531 $current_object['items_per_page'] = wpforo_setting( 'topics', 'topics_per_page' );
1532 $args = [
1533 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1534 'row_count' => $current_object['items_per_page'],
1535 'forumid' => $current_object['forumid'],
1536 'orderby' => 'type, modified',
1537 'order' => 'DESC',
1538 ];
1539 $args = apply_filters( 'wpforo_topic_list_args', $args );
1540 $current_object['topics'] = $this->topic->get_topics( $args, $current_object['items_count'] );
1541 }
1542 } else {
1543 $current_object['is_404'] = true;
1544 }
1545 }
1546
1547 if( in_array( $this->current_object['template'], [ 'forum', 'topic' ] ) ) {
1548 if( ! empty( $forum ) ) {
1549 $current_object['categories'] = [ $forum ];
1550 } else {
1551 $current_object['categories'] = $this->forum->get_forums( [ "type" => 'category' ] );
1552 }
1553 }
1554
1555 if( $this->current_object['template'] === 'post' && ! empty( $forum ) && ! empty( $topic ) ) {
1556 $current_object['items_per_page'] = $this->post->get_option_items_per_page( $current_object['layout'] );
1557
1558 $args = [
1559 'forumid' => $forum['forumid'],
1560 'topicid' => $topic['topicid'],
1561 'offset' => ( $current_object['paged'] - 1 ) * $current_object['items_per_page'],
1562 'row_count' => $current_object['items_per_page'],
1563 ];
1564 if( $current_object['layout'] == 4 ) {
1565 $args['parentid'] = 0;
1566 } elseif( $current_object['layout'] == 3 ) {
1567 $args['parentid'] = 0;
1568 switch( $current_object['orderby'] ) {
1569 case 'oldest':
1570 $args['orderby'] = '`is_first_post` DESC, `is_answer` DESC, `created` ASC, `postid` ASC';
1571 break;
1572 case 'newest':
1573 $args['orderby'] = '`is_first_post` DESC, `is_answer` DESC, `modified` DESC, `postid` DESC';
1574 break;
1575 default:
1576 $args['orderby'] = '`is_first_post` DESC, `is_answer` DESC, `votes` DESC, `created` ASC, `postid` ASC';
1577 break;
1578 }
1579 }
1580 if( $this->post->get_option_union_first_post( $current_object['layout'] ) ) $args['union_first_post'] = true;
1581 $args = apply_filters( 'wpforo_post_list_args', $args );
1582 $current_object['posts'] = $this->post->get_posts( $args, $current_object['items_count'] );
1583 }
1584
1585 $this->current_object = wpforo_parse_args( $current_object, $this->current_object );
1586
1587 $this->current_object = apply_filters( 'wpforo_after_init_current_object', $this->current_object, $wpf_url_parse );
1588
1589 if( $this->current_object['template'] ) {
1590 /**
1591 * redirect not logged-in users to login page when that user no access to this page
1592 */
1593 if( ! $this->current_userid && $this->current_object['forumid'] && ( ( in_array( $this->current_object['template'], [ 'forum', 'topic' ] ) && ! $this->perm->forum_can(
1594 'vf',
1595 $this->current_object['forumid']
1596 ) ) || ( $this->current_object['template'] === 'post' && ! $this->perm->forum_can( 'vt', $this->current_object['forumid'] ) ) ) ) {
1597 wp_safe_redirect( wpforo_login_url() );
1598 exit();
1599 }
1600
1601 if( $this->current_object['template'] === 'cantlogin' ) {
1602 if( $this->current_userid ) {
1603 if( $this->current_user['status'] !== 'active' ) {
1604 WPF()->ram_cache->set( 'USER_LOGIN_REFERER', WPF()->current_user_login );
1605 wp_logout();
1606 } else {
1607 wp_safe_redirect( wpforo_home_url() );
1608 }
1609 } else {
1610 wp_safe_redirect( wpforo_login_url() );
1611 exit();
1612 }
1613 }
1614
1615 /**
1616 * redirect to the first page when paged var is greater items_count
1617 */
1618 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'] ) {
1619 wp_safe_redirect( $this->strip_url_paged_var( $this->current_url ), 301 );
1620 exit();
1621 }
1622 } else {
1623 $this->current_object['is_404'] = true;
1624 }
1625 }
1626
1627 public function get_version() {
1628 return wpforo_get_option( 'version', null, false );
1629 }
1630
1631 public function need_activation() {
1632 return WPFORO_VERSION !== $this->get_version();
1633 }
1634
1635 public function is_installed() {
1636 return (bool) $this->get_version();
1637 }
1638
1639 public function can_use_this_slug( $slug ) {
1640 $return = ! in_array( $slug, $this->settings->slugs, true ) && ! in_array( $slug, array_keys( $this->settings->slugs ), true );
1641
1642 return apply_filters( 'wpforo_can_use_this_slug', $return, $slug );
1643 }
1644 }
1645