PluginProbe
bbPress / 2.6.19
bbPress v2.6.19
2.6.19 2.6.18 2.6.17 trunk 2.0 2.0-beta-1 2.0-beta-2b 2.0-beta-3 2.0-beta-3b 2.0-rc-2 2.0-rc-3 2.0-rc-4 2.0-rc-5 2.0.1 2.0.2 2.0.3 2.1 2.1-beta-1 2.1-rc1 2.1-rc2 2.1-rc3 2.1-rc4 2.1.1 2.1.2 2.1.3 All 74 releases
bbpress / bbpress.php

bbpress.php in bbPress 2.6.19, at bbpress.php

1,148 lines 39.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * The bbPress Plugin
5 *
6 * bbPress is forum software with a twist from the creators of WordPress.
7 *
8 * $Id: bbpress.php 7745 2026-09-29 23:33:24Z johnjamesjacoby $
9 *
10 * @package bbPress
11 * @subpackage Main
12 */
13
14 /**
15 * Plugin Name: bbPress
16 * Plugin URI: https://bbpress.org
17 * Description: bbPress is forum software with a twist from the creators of WordPress.
18 * Author: The bbPress Contributors
19 * Author URI: https://bbpress.org
20 * License: GNU General Public License v2 or later
21 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
22 * Text Domain: bbpress
23 * Domain Path: /languages/
24 * Requires PHP: 7.2
25 * Requires at least: 6.0
26 * Tested up to: 7.1
27 * Version: 2.6.19
28 */
29
30 // Exit if accessed directly
31 defined( 'ABSPATH' ) || exit;
32
33 if ( ! class_exists( 'bbPress' ) ) :
34 /**
35 * Main bbPress Class
36 *
37 * "Word hard. Stay bumble."
38 *
39 * @since 2.0.0 bbPress (r2594)
40 */
41 final class bbPress {
42
43 /** Magic *****************************************************************/
44
45 /**
46 * bbPress uses many variables, several of which can be filtered to
47 * customize the way it operates. Most of these variables are stored in a
48 * private array that gets updated with the help of PHP magic methods.
49 *
50 * This is a precautionary measure, to avoid potential errors produced by
51 * unanticipated direct manipulation of run-time data.
52 *
53 * @see bbPress::setup_globals()
54 * @var array
55 */
56 private $data;
57
58 /** Not Magic *************************************************************/
59
60 /**
61 * @var mixed False when not logged in; WP_User object when logged in
62 */
63 public $current_user = false;
64
65 /**
66 * @var stdClass Add-ons append to this (Akismet, BuddyPress, etc...)
67 */
68 public $extend;
69
70 /**
71 * @var array Topic views
72 */
73 public $views = array();
74
75 /**
76 * @var array Overloads get_option()
77 */
78 public $options = array();
79
80 /**
81 * @var array Storage of options not in the database
82 */
83 public $not_options = array();
84
85 /**
86 * @var array Overloads get_user_meta()
87 */
88 public $user_options = array();
89
90 /**
91 * @var array Dynamically initialized user roles
92 */
93 public $roles = array();
94
95 /** Singleton *************************************************************/
96
97 /**
98 * Main bbPress Instance
99 *
100 * bbPress is fun
101 * Please load it only one time
102 * For this, we thank you
103 *
104 * Insures that only one instance of bbPress exists in memory at any one
105 * time. Also prevents needing to define globals all over the place.
106 *
107 * @since 2.1.0 bbPress (r3758)
108 *
109 * @staticvar object $instance
110 * @see bbpress()
111 * @return bbPress The one true bbPress
112 */
113 public static function instance() {
114
115 // Store the instance locally to avoid private static replication
116 static $instance = null;
117
118 // Only run these methods if they haven't been ran previously
119 if ( null === $instance ) {
120 $instance = new bbPress();
121 $instance->setup_environment();
122 $instance->includes();
123 $instance->setup_variables();
124 $instance->setup_actions();
125 }
126
127 // Always return the instance
128 return $instance;
129 }
130
131 /** Magic Methods *********************************************************/
132
133 /**
134 * A dummy constructor to prevent bbPress from being loaded more than once.
135 *
136 * @since 2.0.0 bbPress (r3071)
137 *
138 * @see bbPress::instance()
139 * @see bbpress();
140 */
141 private function __construct() {
142 /* Do nothing here */
143 }
144
145 /**
146 * A dummy magic method to prevent bbPress from being cloned
147 *
148 * @since 2.1.0 bbPress (r3758)
149 */
150 public function __clone() {
151 _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'bbpress' ), '2.1' );
152 }
153
154 /**
155 * A dummy magic method to prevent bbPress from being unserialized
156 *
157 * @since 2.1.0 bbPress (r3758)
158 */
159 public function __wakeup() {
160 _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'bbpress' ), '2.1' );
161 }
162
163 /**
164 * Magic method for checking the existence of a certain custom field
165 *
166 * @since 2.1.0 bbPress (r3951)
167 */
168 public function __isset( $key ) {
169 return isset( $this->data[ $key ] );
170 }
171
172 /**
173 * Magic method for getting bbPress variables
174 *
175 * @since 2.1.0 bbPress (r3951)
176 */
177 public function __get( $key ) {
178 return isset( $this->data[ $key ] )
179 ? $this->data[ $key ]
180 : null;
181 }
182
183 /**
184 * Magic method for setting bbPress variables
185 *
186 * @since 2.1.0 bbPress (r3951)
187 */
188 public function __set( $key, $value ) {
189 $this->data[ $key ] = $value;
190 }
191
192 /**
193 * Magic method for unsetting bbPress variables
194 *
195 * @since 2.3.0 bbPress (r4629)
196 */
197 public function __unset( $key ) {
198 if ( isset( $this->data[ $key ] ) ) {
199 unset( $this->data[ $key ] );
200 }
201 }
202
203 /**
204 * Magic method to prevent notices and errors from invalid method calls
205 *
206 * @since 2.2.0 bbPress (r4253)
207 */
208 public function __call( $name = '', $args = array() ) {
209 unset( $name, $args );
210 return null;
211 }
212
213 /** Private Methods *******************************************************/
214
215 /**
216 * Setup the environment variables to allow the rest of bbPress to function
217 * more easily.
218 *
219 * @since 2.6.0 bbPress (r6331)
220 *
221 * @access private
222 */
223 private function setup_environment() {
224
225 /** Versions **********************************************************/
226
227 $this->version = '2.6.19';
228 $this->db_version = '264';
229
230 /** Paths *************************************************************/
231
232 // File & base
233 $this->file = __FILE__;
234 $this->basename = apply_filters( 'bbp_plugin_basename', str_replace( array( 'build/', 'src/' ), '', plugin_basename( $this->file ) ) );
235 $this->basepath = apply_filters( 'bbp_plugin_basepath', trailingslashit( dirname( $this->basename ) ) );
236
237 // Path and URL
238 $this->plugin_dir = apply_filters( 'bbp_plugin_dir_path', plugin_dir_path( $this->file ) );
239 $this->plugin_url = apply_filters( 'bbp_plugin_dir_url', plugin_dir_url ( $this->file ) );
240
241 // Includes
242 $this->includes_dir = apply_filters( 'bbp_includes_dir', trailingslashit( $this->plugin_dir . 'includes' ) );
243 $this->includes_url = apply_filters( 'bbp_includes_url', trailingslashit( $this->plugin_url . 'includes' ) );
244
245 // Languages
246 $this->lang_base = apply_filters( 'bbp_lang_base', trailingslashit( $this->basepath . 'languages' ) );
247 $this->lang_dir = apply_filters( 'bbp_lang_dir', trailingslashit( $this->plugin_dir . 'languages' ) );
248
249 // Templates
250 $this->themes_dir = apply_filters( 'bbp_themes_dir', trailingslashit( $this->plugin_dir . 'templates' ) );
251 $this->themes_url = apply_filters( 'bbp_themes_url', trailingslashit( $this->plugin_url . 'templates' ) );
252 }
253
254 /**
255 * Smart defaults to many bbPress specific class variables.
256 *
257 * @since 2.6.0 bbPress (r6331)
258 */
259 private function setup_variables() {
260
261 /** Identifiers *******************************************************/
262
263 // Post type identifiers
264 $this->forum_post_type = apply_filters( 'bbp_forum_post_type', 'forum' );
265 $this->topic_post_type = apply_filters( 'bbp_topic_post_type', 'topic' );
266 $this->topic_tag_tax_id = apply_filters( 'bbp_topic_tag_tax_id', 'topic-tag' );
267 $this->reply_post_type = apply_filters( 'bbp_reply_post_type', 'reply' );
268
269 // Status identifiers
270 $this->spam_status_id = apply_filters( 'bbp_spam_post_status', 'spam' );
271 $this->closed_status_id = apply_filters( 'bbp_closed_post_status', 'closed' );
272 $this->orphan_status_id = apply_filters( 'bbp_orphan_post_status', 'orphan' );
273 $this->public_status_id = apply_filters( 'bbp_public_post_status', 'publish' );
274 $this->pending_status_id = apply_filters( 'bbp_pending_post_status', 'pending' );
275 $this->private_status_id = apply_filters( 'bbp_private_post_status', 'private' );
276 $this->hidden_status_id = apply_filters( 'bbp_hidden_post_status', 'hidden' );
277 $this->trash_status_id = apply_filters( 'bbp_trash_post_status', 'trash' );
278
279 // Other identifiers
280 $this->user_id = apply_filters( 'bbp_user_id', 'bbp_user' );
281 $this->tops_id = apply_filters( 'bbp_tops_id', 'bbp_tops' );
282 $this->reps_id = apply_filters( 'bbp_reps_id', 'bbp_reps' );
283 $this->favs_id = apply_filters( 'bbp_favs_id', 'bbp_favs' );
284 $this->subs_id = apply_filters( 'bbp_subs_id', 'bbp_subs' );
285 $this->view_id = apply_filters( 'bbp_view_id', 'bbp_view' );
286 $this->edit_id = apply_filters( 'bbp_edit_id', 'edit' );
287 $this->paged_id = apply_filters( 'bbp_paged_id', 'paged' );
288 $this->search_id = apply_filters( 'bbp_search_id', 'bbp_search' );
289 $this->engagements_id = apply_filters( 'bbp_engagements_id', 'bbp_engagements' );
290
291 /** Queries ***********************************************************/
292
293 $this->current_view_id = 0; // Current view id
294 $this->current_forum_id = 0; // Current forum id
295 $this->current_topic_id = 0; // Current topic id
296 $this->current_reply_id = 0; // Current reply id
297 $this->current_topic_tag_id = 0; // Current topic tag id
298 $this->current_user_id = 0; // Current topic tag id
299
300 $this->forum_query = new WP_Query(); // Main forum query
301 $this->topic_query = new WP_Query(); // Main topic query
302 $this->reply_query = new WP_Query(); // Main reply query
303 $this->search_query = new WP_Query(); // Main search query
304 $this->user_query = new BBP_User_Query(); // Main user query
305
306 /** Theme Compat ******************************************************/
307
308 $this->theme_compat = new stdClass(); // Base theme compatibility class
309 $this->filters = new stdClass(); // Used when adding/removing filters
310
311 /** Users *************************************************************/
312
313 $this->current_user = new WP_User(); // Currently logged in user
314 $this->displayed_user = new WP_User(); // Currently displayed user
315
316 /** Misc **************************************************************/
317
318 $this->domain = 'bbpress'; // Unique identifier for retrieving translated strings
319 $this->extend = new stdClass(); // Plugins add data here
320 $this->errors = new WP_Error(); // Feedback
321
322 /** Deprecated ********************************************************/
323
324 $this->tab_index = apply_filters( 'bbp_default_tab_index', 100 );
325 }
326
327 /**
328 * Include required files
329 *
330 * @since 2.0.0 bbPress (r3334)
331 *
332 * @access private
333 */
334 private function includes() {
335
336 /** Core **************************************************************/
337
338 require $this->includes_dir . 'core/abstraction.php';
339 require $this->includes_dir . 'core/sub-actions.php';
340 require $this->includes_dir . 'core/functions.php';
341 require $this->includes_dir . 'core/cache.php';
342 require $this->includes_dir . 'core/options.php';
343 require $this->includes_dir . 'core/capabilities.php';
344 require $this->includes_dir . 'core/update.php';
345 require $this->includes_dir . 'core/template-functions.php';
346 require $this->includes_dir . 'core/template-loader.php';
347 require $this->includes_dir . 'core/theme-compat.php';
348
349 /** Components ********************************************************/
350
351 // Common
352 require $this->includes_dir . 'common/ajax.php';
353 require $this->includes_dir . 'common/classes.php';
354 require $this->includes_dir . 'common/engagements.php';
355 require $this->includes_dir . 'common/functions.php';
356 require $this->includes_dir . 'common/formatting.php';
357 require $this->includes_dir . 'common/locale.php';
358 require $this->includes_dir . 'common/locks.php';
359 require $this->includes_dir . 'common/rest.php';
360 require $this->includes_dir . 'common/xmlrpc.php';
361 require $this->includes_dir . 'common/template.php';
362 require $this->includes_dir . 'common/widgets.php';
363 require $this->includes_dir . 'common/shortcodes.php';
364
365 // Forums
366 require $this->includes_dir . 'forums/capabilities.php';
367 require $this->includes_dir . 'forums/functions.php';
368 require $this->includes_dir . 'forums/template.php';
369
370 // Topics
371 require $this->includes_dir . 'topics/capabilities.php';
372 require $this->includes_dir . 'topics/functions.php';
373 require $this->includes_dir . 'topics/template.php';
374
375 // Replies
376 require $this->includes_dir . 'replies/capabilities.php';
377 require $this->includes_dir . 'replies/functions.php';
378 require $this->includes_dir . 'replies/template.php';
379
380 // Search
381 require $this->includes_dir . 'search/functions.php';
382 require $this->includes_dir . 'search/template.php';
383
384 // Users
385 require $this->includes_dir . 'users/capabilities.php';
386 require $this->includes_dir . 'users/engagements.php';
387 require $this->includes_dir . 'users/functions.php';
388 require $this->includes_dir . 'users/template.php';
389 require $this->includes_dir . 'users/options.php';
390 require $this->includes_dir . 'users/signups.php';
391
392 /** Hooks *************************************************************/
393
394 require $this->includes_dir . 'core/extend.php';
395 require $this->includes_dir . 'core/actions.php';
396 require $this->includes_dir . 'core/filters.php';
397
398 /** Admin *************************************************************/
399
400 // Quick admin check and load if needed
401 if ( is_admin() ) {
402 require $this->includes_dir . 'admin/actions.php';
403 }
404 }
405
406 /**
407 * Setup the default hooks and actions
408 *
409 * @since 2.0.0 bbPress (r3334)
410 *
411 * @access private
412 */
413 private function setup_actions() {
414
415 // Add actions to plugin activation and deactivation hooks
416 add_action( 'activate_' . $this->basename, 'bbp_activation' );
417 add_action( 'deactivate_' . $this->basename, 'bbp_deactivation' );
418
419 // If bbPress is being deactivated, do not add any actions
420 if ( bbp_is_deactivation( $this->basename ) ) {
421 return;
422 }
423
424 // Array of bbPress core actions
425 $actions = array(
426 'setup_theme', // Setup the default theme compat
427 'setup_current_user', // Setup currently logged in user
428 'setup_engagements', // Setup user engagements strategy
429 'roles_init', // User roles init
430 'register_meta', // Register meta (forum|topic|reply|user)
431 'register_post_types', // Register post types (forum|topic|reply)
432 'register_post_statuses', // Register post statuses (closed|spam|orphan|hidden)
433 'register_taxonomies', // Register taxonomies (topic-tag)
434 'register_shortcodes', // Register shortcodes (bbp-login)
435 'register_views', // Register the views (no-replies)
436 'register_theme_packages', // Register bundled theme packages (bbp-theme-compat/bbp-themes)
437 'load_textdomain', // Load textdomain (bbpress)
438 'add_rewrite_tags', // Add rewrite tags (view|user|edit|search)
439 'add_rewrite_rules', // Generate rewrite rules (view|edit|paged|search)
440 'add_permastructs' // Add permalink structures (view|user|search)
441 );
442
443 // Add the actions
444 foreach ( $actions as $class_action ) {
445 add_action( 'bbp_' . $class_action, array( $this, $class_action ), 5 );
446 }
447
448 // All bbPress actions are setup (includes bbp-core-hooks.php)
449 do_action_ref_array( 'bbp_after_setup_actions', array( &$this ) );
450 }
451
452 /** Public Methods ********************************************************/
453
454 /**
455 * Register bundled theme packages
456 *
457 * Note that since we currently have complete control over bbp-themes and
458 * the bbp-theme-compat folders, it's fine to hardcode these here. If at a
459 * later date we need to automate this, and API will need to be built.
460 *
461 * @since 2.1.0 bbPress (r3830)
462 */
463 public function register_theme_packages() {
464
465 // Register the basic theme stack. This is really dope.
466 bbp_register_template_stack( 'get_stylesheet_directory', 6 );
467 bbp_register_template_stack( 'get_template_directory', 8 );
468
469 // Register the default theme compatibility package
470 bbp_register_theme_package(
471 array(
472 'id' => 'default',
473 'name' => 'bbPress Default',
474 'version' => bbp_get_version(),
475 'dir' => trailingslashit( $this->themes_dir . 'default' ),
476 'url' => trailingslashit( $this->themes_url . 'default' )
477 )
478 );
479 }
480
481 /**
482 * Setup the default bbPress theme compatibility location.
483 *
484 * @since 2.1.0 bbPress (r3779)
485 */
486 public function setup_theme() {
487 bbp_setup_theme_compat( bbp_get_theme_package_id() );
488 }
489
490 /**
491 * Load the translation file for current language. Checks the deprecated
492 * languages folder inside the bbPress plugin first, and then the default
493 * WordPress languages folder.
494 *
495 * Note that custom translation files inside the bbPress plugin folder
496 * will be removed on bbPress updates. If you're creating custom
497 * translation files, please use the global language folder.
498 *
499 * @since 2.0.0 bbPress (r3333)
500 */
501 public function load_textdomain() {
502
503 // Define the old directory
504 $old_dir = WP_LANG_DIR . '/bbpress/';
505
506 // Old location, deprecated in 2.6.0
507 if ( is_dir( $old_dir ) ) {
508
509 // Get locale & file-name
510 $type = is_admin() ? get_user_locale() : get_locale();
511 $locale = apply_filters( 'plugin_locale', $type, $this->domain );
512 $mofile = sprintf( '%1$s-%2$s.mo', $this->domain, $locale );
513
514 // Look in global /wp-content/languages/bbpress/ folder
515 load_textdomain( $this->domain, $old_dir . $mofile );
516 }
517
518 // Look in global /wp-content/languages/plugins/
519 load_plugin_textdomain( $this->domain, false, $this->lang_base );
520 }
521
522 /**
523 * Setup the post types for forums, topics and replies
524 *
525 * @since 2.0.0 bbPress (r2597)
526 */
527 public static function register_post_types() {
528
529 /** Forums ************************************************************/
530
531 // Register Forum content type
532 register_post_type(
533 bbp_get_forum_post_type(),
534 apply_filters(
535 'bbp_register_forum_post_type',
536 array(
537 'labels' => bbp_get_forum_post_type_labels(),
538 'rewrite' => bbp_get_forum_post_type_rewrite(),
539 'supports' => bbp_get_forum_post_type_supports(),
540 'description' => esc_html__( 'bbPress Forums', 'bbpress' ),
541 'capabilities' => bbp_get_forum_caps(),
542 'capability_type' => array( 'forum', 'forums' ),
543 'menu_position' => 555555,
544 'has_archive' => bbp_get_root_slug(),
545 'exclude_from_search' => true,
546 'show_in_nav_menus' => true,
547 'public' => true,
548 'show_ui' => current_user_can( 'bbp_forums_admin' ),
549 'rest_controller_class' => 'BBP_REST_Posts_Controller',
550 'can_export' => true,
551 'hierarchical' => true,
552 'query_var' => true,
553 'menu_icon' => '',
554 'source' => 'bbpress',
555 )
556 )
557 );
558
559 /** Topics ************************************************************/
560
561 // Register Topic content type
562 register_post_type(
563 bbp_get_topic_post_type(),
564 apply_filters(
565 'bbp_register_topic_post_type',
566 array(
567 'labels' => bbp_get_topic_post_type_labels(),
568 'rewrite' => bbp_get_topic_post_type_rewrite(),
569 'supports' => bbp_get_topic_post_type_supports(),
570 'description' => esc_html__( 'bbPress Topics', 'bbpress' ),
571 'capabilities' => bbp_get_topic_caps(),
572 'capability_type' => array( 'topic', 'topics' ),
573 'menu_position' => 555555,
574 'has_archive' => ( 'forums' === bbp_show_on_root() ) ? bbp_get_topic_archive_slug() : false,
575 'exclude_from_search' => true,
576 'show_in_nav_menus' => false,
577 'public' => true,
578 'show_ui' => current_user_can( 'bbp_topics_admin' ),
579 'rest_controller_class' => 'BBP_REST_Posts_Controller',
580 'can_export' => true,
581 'hierarchical' => false,
582 'query_var' => true,
583 'menu_icon' => '',
584 'source' => 'bbpress',
585 )
586 )
587 );
588
589 /** Replies ***********************************************************/
590
591 // Register reply content type
592 register_post_type(
593 bbp_get_reply_post_type(),
594 apply_filters(
595 'bbp_register_reply_post_type',
596 array(
597 'labels' => bbp_get_reply_post_type_labels(),
598 'rewrite' => bbp_get_reply_post_type_rewrite(),
599 'supports' => bbp_get_reply_post_type_supports(),
600 'description' => esc_html__( 'bbPress Replies', 'bbpress' ),
601 'capabilities' => bbp_get_reply_caps(),
602 'capability_type' => array( 'reply', 'replies' ),
603 'menu_position' => 555555,
604 'exclude_from_search' => true,
605 'has_archive' => false,
606 'show_in_nav_menus' => false,
607 'public' => true,
608 'show_ui' => current_user_can( 'bbp_replies_admin' ),
609 'rest_controller_class' => 'BBP_REST_Posts_Controller',
610 'can_export' => true,
611 'hierarchical' => false,
612 'query_var' => true,
613 'menu_icon' => '',
614 'source' => 'bbpress',
615 )
616 )
617 );
618 }
619
620 /**
621 * Register the post statuses used by bbPress
622 *
623 * We do some manipulation of the 'trash' status so trashed topics and
624 * replies can be viewed from within the theme.
625 *
626 * @since 2.0.0 bbPress (r2727)
627 */
628 public static function register_post_statuses() {
629
630 // Closed
631 register_post_status(
632 bbp_get_closed_status_id(),
633 apply_filters(
634 'bbp_register_closed_post_status',
635 array(
636 'label' => _x( 'Closed', 'post', 'bbpress' ),
637 /* translators: %s: Number of closed items */
638 'label_count' => _nx_noop( 'Closed <span class="count">(%s)</span>', 'Closed <span class="count">(%s)</span>', 'post', 'bbpress' ),
639 'public' => true,
640 'show_in_admin_status_list' => true,
641 'show_in_admin_all_list' => true,
642 'source' => 'bbpress'
643 )
644 )
645 );
646
647 // Spam
648 register_post_status(
649 bbp_get_spam_status_id(),
650 apply_filters(
651 'bbp_register_spam_post_status',
652 array(
653 'label' => _x( 'Spam', 'post', 'bbpress' ),
654 /* translators: %s: Number of spammed items */
655 'label_count' => _nx_noop( 'Spam <span class="count">(%s)</span>', 'Spam <span class="count">(%s)</span>', 'post', 'bbpress' ),
656 'protected' => true,
657 'exclude_from_search' => true,
658 'show_in_admin_status_list' => true,
659 'show_in_admin_all_list' => false,
660 'source' => 'bbpress'
661 )
662 )
663 );
664
665 // Orphan
666 register_post_status(
667 bbp_get_orphan_status_id(),
668 apply_filters(
669 'bbp_register_orphan_post_status',
670 array(
671 'label' => _x( 'Orphan', 'post', 'bbpress' ),
672 /* translators: %s: Number of orphaned items */
673 'label_count' => _nx_noop( 'Orphan <span class="count">(%s)</span>', 'Orphans <span class="count">(%s)</span>', 'post', 'bbpress' ),
674 'protected' => true,
675 'exclude_from_search' => true,
676 'show_in_admin_status_list' => true,
677 'show_in_admin_all_list' => false,
678 'source' => 'bbpress'
679 )
680 )
681 );
682
683 // Hidden
684 register_post_status(
685 bbp_get_hidden_status_id(),
686 apply_filters(
687 'bbp_register_hidden_post_status',
688 array(
689 'label' => _x( 'Hidden', 'post', 'bbpress' ),
690 /* translators: %s: Number of hidden items */
691 'label_count' => _nx_noop( 'Hidden <span class="count">(%s)</span>', 'Hidden <span class="count">(%s)</span>', 'post', 'bbpress' ),
692 'private' => true,
693 'exclude_from_search' => true,
694 'show_in_admin_status_list' => true,
695 'show_in_admin_all_list' => true,
696 'source' => 'bbpress'
697 )
698 )
699 );
700
701 /**
702 * Trash fix.
703 *
704 * We need to remove the internal arg and change that to
705 * protected so that the users with 'view_trash' cap can view
706 * single trashed topics/replies in the front-end as wp_query
707 * doesn't allow any hack for the trashed topics to be viewed.
708 */
709 global $wp_post_statuses;
710
711 if ( ! empty( $wp_post_statuses['trash'] ) ) {
712
713 // User can view trash so set internal to false
714 if ( current_user_can( 'view_trash' ) ) {
715 $wp_post_statuses['trash']->internal = false;
716 $wp_post_statuses['trash']->protected = true;
717
718 // User cannot view trash so set internal to true
719 } else {
720 $wp_post_statuses['trash']->internal = true;
721 }
722 }
723 }
724
725 /**
726 * Register the topic tag and forum moderator taxonomies
727 *
728 * @since 2.0.0 bbPress (r2753) Added bbp_get_topic_tag_tax_id() taxonomy
729 */
730 public static function register_taxonomies() {
731
732 // Register the topic-tag taxonomy.
733 register_taxonomy(
734 bbp_get_topic_tag_tax_id(),
735 bbp_get_topic_post_type(),
736 apply_filters(
737 'bbp_register_topic_taxonomy',
738 array(
739 'labels' => bbp_get_topic_tag_tax_labels(),
740 'rewrite' => bbp_get_topic_tag_tax_rewrite(),
741 'capabilities' => bbp_get_topic_tag_caps(),
742 'update_count_callback' => 'bbp_update_topic_tag_count',
743 'query_var' => true,
744 'show_tagcloud' => true,
745 'hierarchical' => false,
746 'show_in_nav_menus' => false,
747 'public' => true,
748 'show_ui' => bbp_allow_topic_tags() && current_user_can( 'bbp_topic_tags_admin' ),
749 'source' => 'bbpress'
750 )
751 )
752 );
753 }
754
755 /**
756 * Register the bbPress views
757 *
758 * @since 2.0.0 bbPress (r2789)
759 */
760 public static function register_views() {
761
762 // Popular topics
763 bbp_register_view(
764 'popular',
765 esc_html__( 'Most popular topics', 'bbpress' ),
766 apply_filters(
767 'bbp_register_view_popular',
768 array(
769 'meta_key' => '_bbp_reply_count',
770 'meta_type' => 'NUMERIC',
771 'max_num_pages' => 1,
772 'orderby' => 'meta_value_num',
773 'show_stickies' => false
774 )
775 )
776 );
777
778 // Topics with no replies
779 bbp_register_view(
780 'no-replies',
781 esc_html__( 'Topics with no replies', 'bbpress' ),
782 apply_filters(
783 'bbp_register_view_no_replies',
784 array(
785 'meta_key' => '_bbp_reply_count',
786 'meta_type' => 'NUMERIC',
787 'meta_value' => 1,
788 'meta_compare' => '<',
789 'orderby' => '',
790 'show_stickies' => false
791 )
792 )
793 );
794 }
795
796 /**
797 * Register the bbPress shortcodes
798 *
799 * @since 2.2.0 bbPress (r4212)
800 */
801 public function register_shortcodes() {
802 $this->shortcodes = new BBP_Shortcodes();
803 }
804
805 /**
806 * Register bbPress meta-data
807 *
808 * Counts added in 2.6.0 to avoid negative values
809 *
810 * @since 2.6.0 bbPress (r6302)
811 */
812 public function register_meta() {
813
814 // Define "count" meta-type array
815 $count = array(
816
817 // Counts are always integers
818 'type' => 'integer',
819
820 // Generic count description
821 'description' => esc_html__( 'bbPress Item Count', 'bbpress' ),
822
823 // Counts are single values
824 'single' => true,
825
826 // Public counts should be made available in REST
827 'show_in_rest' => true,
828
829 // Never allow counts to go negative
830 'sanitize_callback' => 'bbp_number_not_negative',
831
832 // Derived counts cannot be edited through metadata endpoints
833 'auth_callback' => '__return_false'
834 );
835
836 /** Post **************************************************************/
837
838 // Counts
839 register_meta( 'post', '_bbp_topic_count', $count );
840 register_meta( 'post', '_bbp_reply_count', $count );
841 register_meta( 'post', '_bbp_total_topic_count', $count );
842 register_meta( 'post', '_bbp_total_reply_count', $count );
843 register_meta( 'post', '_bbp_voice_count', $count );
844 register_meta( 'post', '_bbp_anonymous_reply_count', $count );
845 // Hidden counts must stay private if custom fields are exposed in REST.
846 $hidden_count = $count;
847 $hidden_count['show_in_rest'] = false;
848 register_meta( 'post', '_bbp_topic_count_hidden', $hidden_count );
849 register_meta( 'post', '_bbp_reply_count_hidden', $hidden_count );
850 register_meta( 'post', '_bbp_total_topic_count_hidden', $hidden_count );
851 register_meta( 'post', '_bbp_total_reply_count_hidden', $hidden_count );
852 register_meta( 'post', '_bbp_forum_subforum_count', $count );
853
854 /** User **************************************************************/
855
856 // Counts
857 register_meta( 'user', '_bbp_topic_count', $count );
858 register_meta( 'user', '_bbp_reply_count', $count );
859
860 // Activity
861 register_meta(
862 'user',
863 '_bbp_last_posted',
864 array(
865 'type' => 'integer',
866 'description' => esc_html__( 'bbPress User Activity', 'bbpress' ),
867 'single' => true,
868 'show_in_rest' => true,
869 'sanitize_callback' => 'bbp_number_not_negative',
870 'auth_callback' => '__return_false'
871 )
872 );
873 }
874
875 /**
876 * Setup the currently logged-in user
877 *
878 * @since 2.0.0 bbPress (r2697)
879 */
880 public function setup_current_user() {
881 $this->current_user = wp_get_current_user();
882 }
883
884 /**
885 * Setup the user engagements strategy
886 *
887 * @since 2.6.0 bbPress (r6876)
888 */
889 public function setup_engagements() {
890
891 // Setup the class name
892 $strategy = ucwords( bbp_engagements_strategy() );
893 $class_name = "BBP_User_Engagements_{$strategy}";
894
895 // Setup the engagements interface
896 $this->engagements = new $class_name();
897 }
898
899 /**
900 * Initialize forum-specific roles
901 *
902 * @since 2.6.0 bbPress (r6118)
903 */
904 public function roles_init() {
905
906 // Get role IDs
907 $keymaster = bbp_get_keymaster_role();
908 $moderator = bbp_get_moderator_role();
909 $participant = bbp_get_participant_role();
910 $spectator = bbp_get_spectator_role();
911 $blocked = bbp_get_blocked_role();
912
913 // Build the roles into one useful array
914 // phpcs:disable WordPress.Arrays.ArrayKeySpacingRestrictions.TooMuchSpaceAfterKey
915 $this->roles[ $keymaster ] = new WP_Role( 'Keymaster', bbp_get_caps_for_role( $keymaster ) );
916 $this->roles[ $moderator ] = new WP_Role( 'Moderator', bbp_get_caps_for_role( $moderator ) );
917 $this->roles[ $participant ] = new WP_Role( 'Participant', bbp_get_caps_for_role( $participant ) );
918 $this->roles[ $spectator ] = new WP_Role( 'Spectator', bbp_get_caps_for_role( $spectator ) );
919 $this->roles[ $blocked ] = new WP_Role( 'Blocked', bbp_get_caps_for_role( $blocked ) );
920 // phpcs:enable
921 }
922
923 /** Custom Rewrite Rules **************************************************/
924
925 /**
926 * Add the bbPress-specific rewrite tags
927 *
928 * @since 2.0.0 bbPress (r2753)
929 */
930 public static function add_rewrite_tags() {
931 add_rewrite_tag( '%' . bbp_get_view_rewrite_id() . '%', '([^/]+)' ); // View Page tag
932 add_rewrite_tag( '%' . bbp_get_edit_rewrite_id() . '%', '([1]{1,})' ); // Edit Page tag
933 add_rewrite_tag( '%' . bbp_get_search_rewrite_id() . '%', '([^/]+)' ); // Search Results tag
934 add_rewrite_tag( '%' . bbp_get_user_rewrite_id() . '%', '([^/]+)' ); // User Profile tag
935 add_rewrite_tag( '%' . bbp_get_user_favorites_rewrite_id() . '%', '([1]{1,})' ); // User Favorites tag
936 add_rewrite_tag( '%' . bbp_get_user_subscriptions_rewrite_id() . '%', '([1]{1,})' ); // User Subscriptions tag
937 add_rewrite_tag( '%' . bbp_get_user_engagements_rewrite_id() . '%', '([1]{1,})' ); // User Engagements tag
938 add_rewrite_tag( '%' . bbp_get_user_topics_rewrite_id() . '%', '([1]{1,})' ); // User Topics Tag
939 add_rewrite_tag( '%' . bbp_get_user_replies_rewrite_id() . '%', '([1]{1,})' ); // User Replies Tag
940 }
941
942 /**
943 * Add bbPress-specific rewrite rules for uri's that are not
944 * setup for us by way of custom post types or taxonomies. This includes:
945 * - Front-end editing
946 * - Topic views
947 * - User profiles
948 *
949 * @since 2.4.0 bbPress (r4930)
950 *
951 * @todo Extract into an API
952 */
953 public static function add_rewrite_rules() {
954
955 /** Setup *************************************************************/
956
957 // Add rules to top or bottom?
958 $priority = 'top';
959
960 // Single Slugs
961 $forum_slug = bbp_get_forum_slug();
962 $topic_slug = bbp_get_topic_slug();
963 $reply_slug = bbp_get_reply_slug();
964 $ttag_slug = bbp_get_topic_tag_tax_slug();
965
966 // Archive Slugs
967 $user_slug = bbp_get_user_slug();
968 $view_slug = bbp_get_view_slug();
969 $search_slug = bbp_get_search_slug();
970 $topic_archive_slug = bbp_get_topic_archive_slug();
971 $reply_archive_slug = bbp_get_reply_archive_slug();
972
973 // Tertiary Slugs
974 $feed_slug = 'feed';
975 $edit_slug = bbp_get_edit_slug();
976 $paged_slug = bbp_get_paged_slug();
977 $user_favs_slug = bbp_get_user_favorites_slug();
978 $user_subs_slug = bbp_get_user_subscriptions_slug();
979 $user_engs_slug = bbp_get_user_engagements_slug();
980
981 // Unique rewrite ID's
982 $feed_id = 'feed';
983 $edit_id = bbp_get_edit_rewrite_id();
984 $view_id = bbp_get_view_rewrite_id();
985 $paged_id = bbp_get_paged_rewrite_id();
986 $search_id = bbp_get_search_rewrite_id();
987 $user_id = bbp_get_user_rewrite_id();
988 $user_favs_id = bbp_get_user_favorites_rewrite_id();
989 $user_subs_id = bbp_get_user_subscriptions_rewrite_id();
990 $user_tops_id = bbp_get_user_topics_rewrite_id();
991 $user_reps_id = bbp_get_user_replies_rewrite_id();
992 $user_engs_id = bbp_get_user_engagements_rewrite_id();
993
994 // Rewrite rule matches used repeatedly below
995 $root_rule = '/([^/]+)/?$';
996 $feed_rule = '/([^/]+)/' . $feed_slug . '/?$';
997 $edit_rule = '/([^/]+)/' . $edit_slug . '/?$';
998 $paged_rule = '/([^/]+)/' . $paged_slug . '/?([0-9]{1,})/?$';
999
1000 // Search rules (without slug check)
1001 $search_root_rule = '/?$';
1002 $search_paged_rule = '/' . $paged_slug . '/?([0-9]{1,})/?$';
1003
1004 /** Add ***************************************************************/
1005
1006 // User profile rules
1007 $tops_rule = '/([^/]+)/' . $topic_archive_slug . '/?$';
1008 $reps_rule = '/([^/]+)/' . $reply_archive_slug . '/?$';
1009 $favs_rule = '/([^/]+)/' . $user_favs_slug . '/?$';
1010 $subs_rule = '/([^/]+)/' . $user_subs_slug . '/?$';
1011 $engs_rule = '/([^/]+)/' . $user_engs_slug . '/?$';
1012 $tops_paged_rule = '/([^/]+)/' . $topic_archive_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
1013 $reps_paged_rule = '/([^/]+)/' . $reply_archive_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
1014 $favs_paged_rule = '/([^/]+)/' . $user_favs_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
1015 $subs_paged_rule = '/([^/]+)/' . $user_subs_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
1016 $engs_paged_rule = '/([^/]+)/' . $user_engs_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
1017
1018 // Edit Forum|Topic|Reply|Topic-tag
1019 add_rewrite_rule( $forum_slug . $edit_rule, 'index.php?' . bbp_get_forum_post_type() . '=$matches[1]&' . $edit_id . '=1', $priority );
1020 add_rewrite_rule( $topic_slug . $edit_rule, 'index.php?' . bbp_get_topic_post_type() . '=$matches[1]&' . $edit_id . '=1', $priority );
1021 add_rewrite_rule( $reply_slug . $edit_rule, 'index.php?' . bbp_get_reply_post_type() . '=$matches[1]&' . $edit_id . '=1', $priority );
1022 add_rewrite_rule( $ttag_slug . $edit_rule, 'index.php?' . bbp_get_topic_tag_tax_id() . '=$matches[1]&' . $edit_id . '=1', $priority );
1023
1024 // User Pagination|Edit|View
1025 add_rewrite_rule( $user_slug . $tops_paged_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_tops_id . '=1&' . $paged_id . '=$matches[2]', $priority );
1026 add_rewrite_rule( $user_slug . $reps_paged_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_reps_id . '=1&' . $paged_id . '=$matches[2]', $priority );
1027 add_rewrite_rule( $user_slug . $favs_paged_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_favs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
1028 add_rewrite_rule( $user_slug . $subs_paged_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_subs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
1029 add_rewrite_rule( $user_slug . $engs_paged_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_engs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
1030 add_rewrite_rule( $user_slug . $tops_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_tops_id . '=1', $priority );
1031 add_rewrite_rule( $user_slug . $reps_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_reps_id . '=1', $priority );
1032 add_rewrite_rule( $user_slug . $favs_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_favs_id . '=1', $priority );
1033 add_rewrite_rule( $user_slug . $subs_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_subs_id . '=1', $priority );
1034 add_rewrite_rule( $user_slug . $engs_rule, 'index.php?' . $user_id . '=$matches[1]&' . $user_engs_id . '=1', $priority );
1035 add_rewrite_rule( $user_slug . $edit_rule, 'index.php?' . $user_id . '=$matches[1]&' . $edit_id . '=1', $priority );
1036 add_rewrite_rule( $user_slug . $root_rule, 'index.php?' . $user_id . '=$matches[1]', $priority );
1037
1038 // Topic-View Pagination|Feed|View
1039 add_rewrite_rule( $view_slug . $paged_rule, 'index.php?' . $view_id . '=$matches[1]&' . $paged_id . '=$matches[2]', $priority );
1040 add_rewrite_rule( $view_slug . $feed_rule, 'index.php?' . $view_id . '=$matches[1]&' . $feed_id . '=$matches[2]', $priority );
1041 add_rewrite_rule( $view_slug . $root_rule, 'index.php?' . $view_id . '=$matches[1]', $priority );
1042
1043 // Search All
1044 add_rewrite_rule( $search_slug . $search_paged_rule, 'index.php?' . $paged_id .'=$matches[1]', $priority );
1045 add_rewrite_rule( $search_slug . $search_root_rule, 'index.php?' . $search_id, $priority );
1046 }
1047
1048 /**
1049 * Add permalink structures for new archive-style destinations.
1050 *
1051 * - Users
1052 * - Topic Views
1053 * - Search
1054 *
1055 * @since 2.4.0 bbPress (r4930)
1056 */
1057 public static function add_permastructs() {
1058
1059 // Get unique ID's
1060 $user_id = bbp_get_user_rewrite_id();
1061 $view_id = bbp_get_view_rewrite_id();
1062 $search_id = bbp_get_search_rewrite_id();
1063
1064 // Get root slugs
1065 $user_slug = bbp_get_user_slug();
1066 $view_slug = bbp_get_view_slug();
1067 $search_slug = bbp_get_search_slug();
1068
1069 // User Permastruct
1070 add_permastruct(
1071 $user_id,
1072 $user_slug . '/%' . $user_id . '%',
1073 array(
1074 'with_front' => false,
1075 'ep_mask' => EP_NONE,
1076 'paged' => false,
1077 'feed' => false,
1078 'forcomments' => false,
1079 'walk_dirs' => true,
1080 'endpoints' => false,
1081 )
1082 );
1083
1084 // Topic View Permastruct
1085 add_permastruct(
1086 $view_id,
1087 $view_slug . '/%' . $view_id . '%',
1088 array(
1089 'with_front' => false,
1090 'ep_mask' => EP_NONE,
1091 'paged' => false,
1092 'feed' => false,
1093 'forcomments' => false,
1094 'walk_dirs' => true,
1095 'endpoints' => false,
1096 )
1097 );
1098
1099 // Search Permastruct
1100 add_permastruct(
1101 $search_id,
1102 $search_slug . '/%' . $search_id . '%',
1103 array(
1104 'with_front' => false,
1105 'ep_mask' => EP_NONE,
1106 'paged' => true,
1107 'feed' => false,
1108 'forcomments' => false,
1109 'walk_dirs' => true,
1110 'endpoints' => false,
1111 )
1112 );
1113 }
1114 }
1115
1116 /**
1117 * The main function responsible for returning the one true bbPress Instance
1118 * to functions everywhere.
1119 *
1120 * Use this function like you would a global variable, except without needing
1121 * to declare the global.
1122 *
1123 * Example: <?php $bbp = bbpress(); ?>
1124 *
1125 * @since 2.1.0 bbPress (r3758)
1126 *
1127 * @return bbPress The one true bbPress Instance
1128 */
1129 function bbpress() {
1130 return bbPress::instance();
1131 }
1132
1133 /**
1134 * Hook bbPress early onto the 'plugins_loaded' action.
1135 *
1136 * This gives all other plugins the chance to load before bbPress, to get their
1137 * actions, filters, and overrides setup without bbPress being in the way.
1138 */
1139 if ( defined( 'BBPRESS_LATE_LOAD' ) ) {
1140 add_action( 'plugins_loaded', 'bbpress', (int) BBPRESS_LATE_LOAD );
1141
1142 // "And now here's something we hope you'll really like!"
1143 } else {
1144 bbpress();
1145 }
1146
1147 endif; // class_exists check
1148