PluginProbe
bbPress / trunk
bbPress vtrunk
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 2.2 2.2.1 2.2.2 All 71 releases
bbpress / bbpress.php

bbpress.php in bbPress trunk, at bbpress.php

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