[ Index ]

PHP Cross Reference of BBPress

title

Body

[close]

/src/includes/forums/ -> functions.php (source)

   1  <?php
   2  
   3  /**
   4   * bbPress Forum Functions
   5   *
   6   * @package bbPress
   7   * @subpackage Functions
   8   */
   9  
  10  // Exit if accessed directly
  11  defined( 'ABSPATH' ) || exit;
  12  
  13  /** Insert ********************************************************************/
  14  
  15  /**
  16   * A wrapper for wp_insert_post() that also includes the necessary meta values
  17   * for the forum to function properly.
  18   *
  19   * @since 2.0.0 bbPress (r3349)
  20   *
  21   * @param array $forum_data Forum post data
  22   * @param arrap $forum_meta Forum meta data
  23   */
  24  function bbp_insert_forum( $forum_data = array(), $forum_meta = array() ) {
  25  
  26      // Forum
  27      $forum_data = bbp_parse_args( $forum_data, array(
  28          'post_parent'    => 0, // forum ID
  29          'post_status'    => bbp_get_public_status_id(),
  30          'post_type'      => bbp_get_forum_post_type(),
  31          'post_author'    => bbp_get_current_user_id(),
  32          'post_password'  => '',
  33          'post_content'   => '',
  34          'post_title'     => '',
  35          'menu_order'     => 0,
  36          'comment_status' => 'closed'
  37      ), 'insert_forum' );
  38  
  39      // Insert forum
  40      $forum_id = wp_insert_post( $forum_data, false );
  41  
  42      // Bail if no forum was added
  43      if ( empty( $forum_id ) ) {
  44          return false;
  45      }
  46  
  47      // Forum meta
  48      $forum_meta = bbp_parse_args( $forum_meta, array(
  49          'forum_type'           => 'forum',
  50          'status'               => 'open',
  51          'reply_count'          => 0,
  52          'topic_count'          => 0,
  53          'topic_count_hidden'   => 0,
  54          'total_reply_count'    => 0,
  55          'total_topic_count'    => 0,
  56          'last_topic_id'        => 0,
  57          'last_reply_id'        => 0,
  58          'last_active_id'       => 0,
  59          'last_active_time'     => 0,
  60          'forum_subforum_count' => 0,
  61      ), 'insert_forum_meta' );
  62  
  63      // Insert forum meta
  64      foreach ( $forum_meta as $meta_key => $meta_value ) {
  65  
  66          // Prefix if not prefixed
  67          if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) {
  68              $meta_key = '_bbp_' . $meta_key;
  69          }
  70  
  71          // Update the meta
  72          update_post_meta( $forum_id, $meta_key, $meta_value );
  73      }
  74  
  75      // Update the forum and hierarchy
  76      bbp_update_forum( array(
  77          'forum_id'    => $forum_id,
  78          'post_parent' => $forum_data['post_parent']
  79      ) );
  80  
  81      // Maybe make private
  82      if ( bbp_is_forum_private( $forum_id, false ) ) {
  83          bbp_privatize_forum( $forum_id );
  84  
  85      // Maybe make hidden
  86      } elseif ( bbp_is_forum_hidden( $forum_id, false ) ) {
  87          bbp_hide_forum( $forum_id );
  88  
  89      // Publicize
  90      } else {
  91          bbp_publicize_forum( $forum_id );
  92      }
  93  
  94      /**
  95       * Fires after forum has been inserted via `bbp_insert_forum`.
  96       *
  97       * @since 2.6.0 bbPress (r6036)
  98       *
  99       * @param int $forum_id The forum id.
 100       */
 101      do_action( 'bbp_insert_forum', (int) $forum_id );
 102  
 103      // Bump the last changed cache
 104      wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
 105  
 106      // Return forum_id
 107      return $forum_id;
 108  }
 109  
 110  /** Post Form Handlers ********************************************************/
 111  
 112  /**
 113   * Handles the front end forum submission
 114   *
 115   * @param string $action The requested action to compare this function to
 116   */
 117  function bbp_new_forum_handler( $action = '' ) {
 118  
 119      // Bail if action is not bbp-new-forum
 120      if ( 'bbp-new-forum' !== $action ) {
 121          return;
 122      }
 123  
 124      // Nonce check
 125      if ( ! bbp_verify_nonce_request( 'bbp-new-forum' ) ) {
 126          bbp_add_error( 'bbp_new_forum_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
 127          return;
 128      }
 129  
 130      // Define local variable(s)
 131      $view_all = false;
 132      $forum_parent_id = $forum_author = 0;
 133      $forum_title = $forum_content = '';
 134      $anonymous_data = array();
 135  
 136      /** Forum Author **********************************************************/
 137  
 138      // User cannot create forums
 139      if ( ! current_user_can( 'publish_forums' ) ) {
 140          bbp_add_error( 'bbp_forum_permission', __( '<strong>ERROR</strong>: You do not have permission to create new forums.', 'bbpress' ) );
 141          return;
 142      }
 143  
 144      // Forum author is current user
 145      $forum_author = bbp_get_current_user_id();
 146  
 147      // Remove kses filters from title and content for capable users and if the nonce is verified
 148      if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && wp_create_nonce( 'bbp-unfiltered-html-forum_new' ) === $_POST['_bbp_unfiltered_html_forum'] ) {
 149          remove_filter( 'bbp_new_forum_pre_title',   'wp_filter_kses'      );
 150          remove_filter( 'bbp_new_forum_pre_content', 'bbp_encode_bad',  10 );
 151          remove_filter( 'bbp_new_forum_pre_content', 'bbp_filter_kses', 30 );
 152      }
 153  
 154      /** Forum Title ***********************************************************/
 155  
 156      if ( ! empty( $_POST['bbp_forum_title'] ) ) {
 157          $forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
 158      }
 159  
 160      // Filter and sanitize
 161      $forum_title = apply_filters( 'bbp_new_forum_pre_title', $forum_title );
 162  
 163      // No forum title
 164      if ( empty( $forum_title ) ) {
 165          bbp_add_error( 'bbp_forum_title', __( '<strong>ERROR</strong>: Your forum needs a title.', 'bbpress' ) );
 166      }
 167  
 168      // Title too long
 169      if ( bbp_is_title_too_long( $forum_title ) ) {
 170          bbp_add_error( 'bbp_forum_title', __( '<strong>ERROR</strong>: Your title is too long.', 'bbpress' ) );
 171      }
 172  
 173      /** Forum Content *********************************************************/
 174  
 175      if ( ! empty( $_POST['bbp_forum_content'] ) ) {
 176          $forum_content = $_POST['bbp_forum_content'];
 177      }
 178  
 179      // Filter and sanitize
 180      $forum_content = apply_filters( 'bbp_new_forum_pre_content', $forum_content );
 181  
 182      // No forum content
 183      if ( empty( $forum_content ) ) {
 184          bbp_add_error( 'bbp_forum_content', __( '<strong>ERROR</strong>: Your forum description cannot be empty.', 'bbpress' ) );
 185      }
 186  
 187      /** Forum Parent **********************************************************/
 188  
 189      // Forum parent was passed (the norm)
 190      if ( ! empty( $_POST['bbp_forum_parent_id'] ) ) {
 191          $forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
 192      }
 193  
 194      // Filter and sanitize
 195      $forum_parent_id = apply_filters( 'bbp_new_forum_pre_parent_id', $forum_parent_id );
 196  
 197      // No forum parent was passed (should never happen)
 198      if ( empty( $forum_parent_id ) ) {
 199          bbp_add_error( 'bbp_new_forum_missing_parent', __( '<strong>ERROR</strong>: Your forum must have a parent.', 'bbpress' ) );
 200  
 201      // Forum exists
 202      } elseif ( ! empty( $forum_parent_id ) ) {
 203  
 204          // Forum is a category
 205          if ( bbp_is_forum_category( $forum_parent_id ) ) {
 206              bbp_add_error( 'bbp_new_forum_forum_category', __( '<strong>ERROR</strong>: This forum is a category. No forums can be created in this forum.', 'bbpress' ) );
 207          }
 208  
 209          // Forum is closed and user cannot access
 210          if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
 211              bbp_add_error( 'bbp_new_forum_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new forums.', 'bbpress' ) );
 212          }
 213  
 214          // Forum is private and user cannot access
 215          if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
 216              bbp_add_error( 'bbp_new_forum_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
 217          }
 218  
 219          // Forum is hidden and user cannot access
 220          if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
 221              bbp_add_error( 'bbp_new_forum_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
 222          }
 223      }
 224  
 225      /** Forum Flooding ********************************************************/
 226  
 227      if ( ! bbp_check_for_flood( $anonymous_data, $forum_author ) ) {
 228          bbp_add_error( 'bbp_forum_flood', __( '<strong>ERROR</strong>: Slow down; you move too fast.', 'bbpress' ) );
 229      }
 230  
 231      /** Forum Duplicate *******************************************************/
 232  
 233      if ( ! bbp_check_for_duplicate( array( 'post_type' => bbp_get_forum_post_type(), 'post_author' => $forum_author, 'post_content' => $forum_content, 'anonymous_data' => $anonymous_data ) ) ) {
 234          bbp_add_error( 'bbp_forum_duplicate', __( '<strong>ERROR</strong>: This forum already exists.', 'bbpress' ) );
 235      }
 236  
 237      /** Forum Bad Words *******************************************************/
 238  
 239      if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content, true ) ) {
 240          bbp_add_error( 'bbp_forum_moderation', __( '<strong>ERROR</strong>: Your forum cannot be created at this time.', 'bbpress' ) );
 241      }
 242  
 243      /** Forum Moderation ******************************************************/
 244  
 245      $post_status = bbp_get_public_status_id();
 246      if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content ) ) {
 247          $post_status = bbp_get_pending_status_id();
 248      }
 249  
 250      /** Additional Actions (Before Save) **************************************/
 251  
 252      do_action( 'bbp_new_forum_pre_extras', $forum_parent_id );
 253  
 254      // Bail if errors
 255      if ( bbp_has_errors() ) {
 256          return;
 257      }
 258  
 259      /** No Errors *************************************************************/
 260  
 261      // Add the content of the form to $forum_data as an array
 262      // Just in time manipulation of forum data before being created
 263      $forum_data = apply_filters( 'bbp_new_forum_pre_insert', array(
 264          'post_author'    => $forum_author,
 265          'post_title'     => $forum_title,
 266          'post_content'   => $forum_content,
 267          'post_parent'    => $forum_parent_id,
 268          'post_status'    => $post_status,
 269          'post_type'      => bbp_get_forum_post_type(),
 270          'comment_status' => 'closed'
 271      ) );
 272  
 273      // Insert forum
 274      $forum_id = wp_insert_post( $forum_data, true );
 275  
 276      /** No Errors *************************************************************/
 277  
 278      if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {
 279  
 280          /** Trash Check *******************************************************/
 281  
 282          // If the forum is trash, or the forum_status is switched to
 283          // trash, trash it properly
 284          if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( $forum_data['post_status'] === bbp_get_trash_status_id() ) ) {
 285  
 286              // Trash the reply
 287              wp_trash_post( $forum_id );
 288  
 289              // Force view=all
 290              $view_all = true;
 291          }
 292  
 293          /** Spam Check ********************************************************/
 294  
 295          // If reply or forum are spam, officially spam this reply
 296          if ( $forum_data['post_status'] === bbp_get_spam_status_id() ) {
 297              add_post_meta( $forum_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );
 298  
 299              // Force view=all
 300              $view_all = true;
 301          }
 302  
 303          /** Update counts, etc... *********************************************/
 304  
 305          do_action( 'bbp_new_forum', array(
 306              'forum_id'           => $forum_id,
 307              'post_parent'        => $forum_parent_id,
 308              'forum_author'       => $forum_author,
 309              'last_topic_id'      => 0,
 310              'last_reply_id'      => 0,
 311              'last_active_id'     => 0,
 312              'last_active_time'   => 0,
 313              'last_active_status' => bbp_get_public_status_id()
 314          ) );
 315  
 316          /** Additional Actions (After Save) ***********************************/
 317  
 318          do_action( 'bbp_new_forum_post_extras', $forum_id );
 319  
 320          /** Redirect **********************************************************/
 321  
 322          // Redirect to
 323          $redirect_to  = bbp_get_redirect_to();
 324  
 325          // Get the forum URL
 326          $redirect_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
 327  
 328          // Add view all?
 329          if ( bbp_get_view_all() || ! empty( $view_all ) ) {
 330  
 331              // User can moderate, so redirect to forum with view all set
 332              if ( current_user_can( 'moderate', $forum_id ) ) {
 333                  $redirect_url = bbp_add_view_all( $redirect_url );
 334  
 335              // User cannot moderate, so redirect to forum
 336              } else {
 337                  $redirect_url = bbp_get_forum_permalink( $forum_id );
 338              }
 339          }
 340  
 341          // Allow to be filtered
 342          $redirect_url = apply_filters( 'bbp_new_forum_redirect_to', $redirect_url, $redirect_to );
 343  
 344          /** Successful Save ***************************************************/
 345  
 346          // Redirect back to new forum
 347          bbp_redirect( $redirect_url );
 348  
 349      /** Errors ****************************************************************/
 350  
 351      // WP_Error
 352      } elseif ( is_wp_error( $forum_id ) ) {
 353          bbp_add_error( 'bbp_forum_error', sprintf( __( '<strong>ERROR</strong>: The following problem(s) occurred: %s', 'bbpress' ), $forum_id->get_error_message() ) );
 354  
 355      // Generic error
 356      } else {
 357          bbp_add_error( 'bbp_forum_error', __( '<strong>ERROR</strong>: The forum was not created.', 'bbpress' ) );
 358      }
 359  }
 360  
 361  /**
 362   * Handles the front end edit forum submission
 363   *
 364   * @param string $action The requested action to compare this function to
 365   */
 366  function bbp_edit_forum_handler( $action = '' ) {
 367  
 368      // Bail if action is not bbp-edit-forum
 369      if ( 'bbp-edit-forum' !== $action ) {
 370          return;
 371      }
 372  
 373      // Define local variable(s)
 374      $anonymous_data = array();
 375      $forum = $forum_id = $forum_parent_id = 0;
 376      $forum_title = $forum_content = $forum_edit_reason = '';
 377  
 378      /** Forum *****************************************************************/
 379  
 380      // Forum id was not passed
 381      if ( empty( $_POST['bbp_forum_id'] ) ) {
 382          bbp_add_error( 'bbp_edit_forum_id', __( '<strong>ERROR</strong>: Forum ID not found.', 'bbpress' ) );
 383          return;
 384  
 385      // Forum id was passed
 386      } elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
 387          $forum_id = (int) $_POST['bbp_forum_id'];
 388          $forum    = bbp_get_forum( $forum_id );
 389      }
 390  
 391      // Nonce check
 392      if ( ! bbp_verify_nonce_request( 'bbp-edit-forum_' . $forum_id ) ) {
 393          bbp_add_error( 'bbp_edit_forum_nonce', __( '<strong>ERROR</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
 394          return;
 395  
 396      // Forum does not exist
 397      } elseif ( empty( $forum ) ) {
 398          bbp_add_error( 'bbp_edit_forum_not_found', __( '<strong>ERROR</strong>: The forum you want to edit was not found.', 'bbpress' ) );
 399          return;
 400  
 401      // User cannot edit this forum
 402      } elseif ( ! current_user_can( 'edit_forum', $forum_id ) ) {
 403          bbp_add_error( 'bbp_edit_forum_permission', __( '<strong>ERROR</strong>: You do not have permission to edit that forum.', 'bbpress' ) );
 404          return;
 405      }
 406  
 407      // Remove kses filters from title and content for capable users and if the nonce is verified
 408      if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-forum_' . $forum_id ) === $_POST['_bbp_unfiltered_html_forum'] ) ) {
 409          remove_filter( 'bbp_edit_forum_pre_title',   'wp_filter_kses'      );
 410          remove_filter( 'bbp_edit_forum_pre_content', 'bbp_encode_bad',  10 );
 411          remove_filter( 'bbp_edit_forum_pre_content', 'bbp_filter_kses', 30 );
 412      }
 413  
 414      /** Forum Parent ***********************************************************/
 415  
 416      // Forum parent id was passed
 417      if ( ! empty( $_POST['bbp_forum_parent_id'] ) ) {
 418          $forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
 419      }
 420  
 421      // Current forum this forum is in
 422      $current_parent_forum_id = bbp_get_forum_parent_id( $forum_id );
 423  
 424      // Forum exists
 425      if ( ! empty( $forum_parent_id ) && ( $forum_parent_id !== $current_parent_forum_id ) ) {
 426  
 427          // Forum is closed and user cannot access
 428          if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
 429              bbp_add_error( 'bbp_edit_forum_forum_closed', __( '<strong>ERROR</strong>: This forum has been closed to new forums.', 'bbpress' ) );
 430          }
 431  
 432          // Forum is private and user cannot access
 433          if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
 434              bbp_add_error( 'bbp_edit_forum_forum_private', __( '<strong>ERROR</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
 435          }
 436  
 437          // Forum is hidden and user cannot access
 438          if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
 439              bbp_add_error( 'bbp_edit_forum_forum_hidden', __( '<strong>ERROR</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
 440          }
 441      }
 442  
 443      /** Forum Title ***********************************************************/
 444  
 445      if ( ! empty( $_POST['bbp_forum_title'] ) ) {
 446          $forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
 447      }
 448  
 449      // Filter and sanitize
 450      $forum_title = apply_filters( 'bbp_edit_forum_pre_title', $forum_title, $forum_id );
 451  
 452      // No forum title
 453      if ( empty( $forum_title ) ) {
 454          bbp_add_error( 'bbp_edit_forum_title', __( '<strong>ERROR</strong>: Your forum needs a title.', 'bbpress' ) );
 455      }
 456  
 457      // Title too long
 458      if ( bbp_is_title_too_long( $forum_title ) ) {
 459          bbp_add_error( 'bbp_forum_title', __( '<strong>ERROR</strong>: Your title is too long.', 'bbpress' ) );
 460      }
 461  
 462      /** Forum Content *********************************************************/
 463  
 464      if ( ! empty( $_POST['bbp_forum_content'] ) ) {
 465          $forum_content = $_POST['bbp_forum_content'];
 466      }
 467  
 468      // Filter and sanitize
 469      $forum_content = apply_filters( 'bbp_edit_forum_pre_content', $forum_content, $forum_id );
 470  
 471      // No forum content
 472      if ( empty( $forum_content ) ) {
 473          bbp_add_error( 'bbp_edit_forum_content', __( '<strong>ERROR</strong>: Your forum description cannot be empty.', 'bbpress' ) );
 474      }
 475  
 476      /** Forum Bad Words *******************************************************/
 477  
 478      if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content, true ) ) {
 479          bbp_add_error( 'bbp_forum_moderation', __( '<strong>ERROR</strong>: Your forum cannot be edited at this time.', 'bbpress' ) );
 480      }
 481  
 482      /** Forum Moderation ******************************************************/
 483  
 484      $post_status = bbp_get_public_status_id();
 485      if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) ) {
 486          $post_status = bbp_get_pending_status_id();
 487      }
 488  
 489      /** Additional Actions (Before Save) **************************************/
 490  
 491      do_action( 'bbp_edit_forum_pre_extras', $forum_id );
 492  
 493      // Bail if errors
 494      if ( bbp_has_errors() ) {
 495          return;
 496      }
 497  
 498      /** No Errors *************************************************************/
 499  
 500      // Add the content of the form to $forum_data as an array
 501      // Just in time manipulation of forum data before being edited
 502      $forum_data = apply_filters( 'bbp_edit_forum_pre_insert', array(
 503          'ID'           => $forum_id,
 504          'post_title'   => $forum_title,
 505          'post_content' => $forum_content,
 506          'post_status'  => $post_status,
 507          'post_parent'  => $forum_parent_id
 508      ) );
 509  
 510      // Insert forum
 511      $forum_id = wp_update_post( $forum_data );
 512  
 513      /** No Errors *************************************************************/
 514  
 515      if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {
 516  
 517          // Update counts, etc...
 518          do_action( 'bbp_edit_forum', array(
 519              'forum_id'           => $forum_id,
 520              'post_parent'        => $forum_parent_id,
 521              'forum_author'       => $forum->post_author,
 522              'last_topic_id'      => 0,
 523              'last_reply_id'      => 0,
 524              'last_active_id'     => 0,
 525              'last_active_time'   => 0,
 526              'last_active_status' => bbp_get_public_status_id()
 527          ) );
 528  
 529          /** Revisions *********************************************************/
 530  
 531          // Update locks
 532          update_post_meta( $forum_id, '_edit_last', bbp_get_current_user_id() );
 533          delete_post_meta( $forum_id, '_edit_lock' );
 534  
 535          /**
 536           * @todo omitted for now
 537          // Revision Reason
 538          if ( ! empty( $_POST['bbp_forum_edit_reason'] ) )
 539              $forum_edit_reason = sanitize_text_field( $_POST['bbp_forum_edit_reason'] );
 540  
 541          // Update revision log
 542          if ( ! empty( $_POST['bbp_log_forum_edit'] ) && ( "1" === $_POST['bbp_log_forum_edit'] ) && ( $revision_id = wp_save_post_revision( $forum_id ) ) ) {
 543              bbp_update_forum_revision_log( array(
 544                  'forum_id'    => $forum_id,
 545                  'revision_id' => $revision_id,
 546                  'author_id'   => bbp_get_current_user_id(),
 547                  'reason'      => $forum_edit_reason
 548              ) );
 549          }
 550  
 551          // If the new forum parent id is not equal to the old forum parent
 552          // id, run the bbp_move_forum action and pass the forum's parent id
 553          // as the first argument and new forum parent id as the second.
 554          // @todo implement
 555          if ( $forum_id !== $forum->post_parent ) {
 556              bbp_move_forum_handler( $forum_parent_id, $forum->post_parent, $forum_id );
 557          }
 558  
 559          */
 560  
 561          /** Additional Actions (After Save) ***********************************/
 562  
 563          do_action( 'bbp_edit_forum_post_extras', $forum_id );
 564  
 565          /** Redirect **********************************************************/
 566  
 567          // Redirect to
 568          $redirect_to = bbp_get_redirect_to();
 569  
 570          // View all?
 571          $view_all = bbp_get_view_all();
 572  
 573          // Get the forum URL
 574          $forum_url = bbp_get_forum_permalink( $forum_id, $redirect_to );
 575  
 576          // Add view all?
 577          if ( ! empty( $view_all ) ) {
 578              $forum_url = bbp_add_view_all( $forum_url );
 579          }
 580  
 581          // Allow to be filtered
 582          $forum_url = apply_filters( 'bbp_edit_forum_redirect_to', $forum_url, $view_all, $redirect_to );
 583  
 584          /** Successful Edit ***************************************************/
 585  
 586          // Redirect back to new forum
 587          bbp_redirect( $forum_url );
 588  
 589      /** Errors ****************************************************************/
 590  
 591      } else {
 592          $append_error = ( is_wp_error( $forum_id ) && $forum_id->get_error_message() ) ? $forum_id->get_error_message() . ' ' : '';
 593          bbp_add_error( 'bbp_forum_error', __( '<strong>ERROR</strong>: The following problem(s) have been found with your forum:' . $append_error . 'Please try again.', 'bbpress' ) );
 594      }
 595  }
 596  
 597  /**
 598   * Handle the saving of core forum metadata (Status, Visibility, and Type)
 599   *
 600   * @since 2.1.0 bbPress (r3678)
 601   *
 602   * @param int $forum_id
 603   * @return If forum ID is empty
 604   */
 605  function bbp_save_forum_extras( $forum_id = 0 ) {
 606  
 607      // Validate the forum ID
 608      $forum_id = bbp_get_forum_id( $forum_id );
 609  
 610      // Bail if forum ID is empty
 611      if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
 612          return;
 613      }
 614  
 615      /** Forum Status **********************************************************/
 616  
 617      if ( ! empty( $_POST['bbp_forum_status'] ) && in_array( $_POST['bbp_forum_status'], array( 'open', 'closed' ), true ) ) {
 618          if ( 'closed' === $_POST['bbp_forum_status'] && ! bbp_is_forum_closed( $forum_id, false ) ) {
 619              bbp_close_forum( $forum_id );
 620          } elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_open( $forum_id, false ) ) {
 621              bbp_open_forum( $forum_id );
 622          } elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_closed( $forum_id, false ) ) {
 623              bbp_open_forum( $forum_id );
 624          }
 625      }
 626  
 627      /** Forum Type ************************************************************/
 628  
 629      if ( ! empty( $_POST['bbp_forum_type'] ) && in_array( $_POST['bbp_forum_type'], array( 'forum', 'category' ), true ) ) {
 630          if ( 'category' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
 631              bbp_categorize_forum( $forum_id );
 632          } elseif ( 'forum' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
 633              bbp_normalize_forum( $forum_id );
 634          } elseif ( 'forum' === $_POST['bbp_forum_type'] && bbp_is_forum_category( $forum_id ) ) {
 635              bbp_normalize_forum( $forum_id );
 636          }
 637      }
 638  
 639      /** Forum Visibility ******************************************************/
 640  
 641      if ( ! empty( $_POST['bbp_forum_visibility'] ) && in_array( $_POST['bbp_forum_visibility'], array_keys( bbp_get_forum_visibilities() ), true ) ) {
 642  
 643          // Get forums current visibility
 644          $old_visibility = bbp_get_forum_visibility( $forum_id );
 645  
 646          // Sanitize the new visibility
 647          $new_visibility = sanitize_key( $_POST['bbp_forum_visibility'] );
 648  
 649          // What is the new forum visibility setting?
 650          switch ( $new_visibility ) {
 651  
 652              // Hidden
 653              case bbp_get_hidden_status_id()  :
 654                  bbp_hide_forum( $forum_id, $old_visibility );
 655                  break;
 656  
 657              // Private
 658              case bbp_get_private_status_id() :
 659                  bbp_privatize_forum( $forum_id, $old_visibility );
 660                  break;
 661  
 662              // Publish (default)
 663              case bbp_get_public_status_id()  :
 664              default :
 665                  bbp_publicize_forum( $forum_id, $old_visibility );
 666                  break;
 667          }
 668  
 669          /**
 670           * Allow custom forum visibility save actions
 671           *
 672           * @since 2.6.0 bbPress (r5855)
 673           *
 674           * @param int    $forum_id       The forum ID
 675           * @param string $old_visibility The current forum visibility
 676           * @param string $new_visibility The new forum visibility
 677           */
 678          do_action( 'bbp_update_forum_visibility', $forum_id, $old_visibility, $new_visibility );
 679      }
 680  
 681      /** Forum Moderators ******************************************************/
 682  
 683      // Either replace terms
 684      if ( bbp_allow_forum_mods() ) {
 685          if ( current_user_can( 'assign_moderators' ) && ! empty( $_POST['bbp_moderators'] ) ) {
 686  
 687              // Escape tag input
 688              $users    = sanitize_text_field( $_POST['bbp_moderators'] );
 689              $user_ids = bbp_get_user_ids_from_nicenames( $users );
 690  
 691              // Update forum moderators
 692              if ( ! empty( $user_ids ) ) {
 693  
 694                  // Remove all moderators
 695                  bbp_remove_moderator( $forum_id, null );
 696  
 697                  // Add moderators
 698                  foreach ( $user_ids as $user_id ) {
 699                      bbp_add_moderator( $forum_id, $user_id );
 700                  }
 701              }
 702  
 703          // ...or remove them.
 704          } elseif ( isset( $_POST['bbp_moderators'] ) ) {
 705              bbp_remove_moderator( $forum_id, null );
 706          }
 707      }
 708  }
 709  
 710  /** Forum Open/Close **********************************************************/
 711  
 712  /**
 713   * Closes a forum
 714   *
 715   * @since 2.0.0 bbPress (r2746)
 716   *
 717   * @param int $forum_id forum id
 718   * @return mixed False or {@link WP_Error} on failure, forum id on success
 719   */
 720  function bbp_close_forum( $forum_id = 0 ) {
 721  
 722      $forum_id = bbp_get_forum_id( $forum_id );
 723  
 724      do_action( 'bbp_close_forum',  $forum_id );
 725  
 726      update_post_meta( $forum_id, '_bbp_status', 'closed' );
 727  
 728      do_action( 'bbp_closed_forum', $forum_id );
 729  
 730      return $forum_id;
 731  }
 732  
 733  /**
 734   * Opens a forum
 735   *
 736   * @since 2.0.0 bbPress (r2746)
 737   *
 738   * @param int $forum_id forum id
 739   * @return mixed False or {@link WP_Error} on failure, forum id on success
 740   */
 741  function bbp_open_forum( $forum_id = 0 ) {
 742  
 743      $forum_id = bbp_get_forum_id( $forum_id );
 744  
 745      do_action( 'bbp_open_forum',   $forum_id );
 746  
 747      update_post_meta( $forum_id, '_bbp_status', 'open' );
 748  
 749      do_action( 'bbp_opened_forum', $forum_id );
 750  
 751      return $forum_id;
 752  }
 753  
 754  /** Forum Type ****************************************************************/
 755  
 756  /**
 757   * Make the forum a category
 758   *
 759   * @since 2.0.0 bbPress (r2746)
 760   *
 761   * @param int $forum_id Optional. Forum id
 762   * @return bool False on failure, true on success
 763   */
 764  function bbp_categorize_forum( $forum_id = 0 ) {
 765  
 766      $forum_id = bbp_get_forum_id( $forum_id );
 767  
 768      do_action( 'bbp_categorize_forum',  $forum_id );
 769  
 770      update_post_meta( $forum_id, '_bbp_forum_type', 'category' );
 771  
 772      do_action( 'bbp_categorized_forum', $forum_id );
 773  
 774      return $forum_id;
 775  }
 776  
 777  /**
 778   * Remove the category status from a forum
 779   *
 780   * @since 2.0.0 bbPress (r2746)
 781   *
 782   * @param int $forum_id Optional. Forum id
 783   * @return bool False on failure, true on success
 784   */
 785  function bbp_normalize_forum( $forum_id = 0 ) {
 786  
 787      $forum_id = bbp_get_forum_id( $forum_id );
 788  
 789      do_action( 'bbp_normalize_forum',  $forum_id );
 790  
 791      update_post_meta( $forum_id, '_bbp_forum_type', 'forum' );
 792  
 793      do_action( 'bbp_normalized_forum', $forum_id );
 794  
 795      return $forum_id;
 796  }
 797  
 798  /** Forum Visibility **********************************************************/
 799  
 800  /**
 801   * Mark the forum as public
 802   *
 803   * @since 2.0.0 bbPress (r2746)
 804   *
 805   * @param int $forum_id Optional. Forum id
 806   * @return bool False on failure, true on success
 807   */
 808  function bbp_publicize_forum( $forum_id = 0, $current_visibility = '' ) {
 809  
 810      $forum_id = bbp_get_forum_id( $forum_id );
 811  
 812      do_action( 'bbp_publicize_forum',  $forum_id );
 813  
 814      // Get private forums
 815      $private = bbp_get_private_forum_ids();
 816  
 817      // Find this forum in the array
 818      if ( in_array( $forum_id, $private, true ) ) {
 819  
 820          $offset = array_search( $forum_id, $private, true );
 821  
 822          // Splice around it
 823          array_splice( $private, $offset, 1 );
 824  
 825          // Update private forums minus this one
 826          update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
 827      }
 828  
 829      // Get hidden forums
 830      $hidden = bbp_get_hidden_forum_ids();
 831  
 832      // Find this forum in the array
 833      if ( in_array( $forum_id, $hidden, true ) ) {
 834  
 835          $offset = array_search( $forum_id, $hidden, true );
 836  
 837          // Splice around it
 838          array_splice( $hidden, $offset, 1 );
 839  
 840          // Update hidden forums minus this one
 841          update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
 842      }
 843  
 844      // Only run queries if visibility is changing
 845      if ( bbp_get_public_status_id() !== $current_visibility ) {
 846          $bbp_db = bbp_db();
 847          $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_public_status_id() ), array( 'ID' => $forum_id ) );
 848          wp_transition_post_status( bbp_get_public_status_id(), $current_visibility, get_post( $forum_id ) );
 849          clean_post_cache( $forum_id );
 850      }
 851  
 852      do_action( 'bbp_publicized_forum', $forum_id );
 853  
 854      return $forum_id;
 855  }
 856  
 857  /**
 858   * Mark the forum as private
 859   *
 860   * @since 2.0.0 bbPress (r2746)
 861   *
 862   * @param int $forum_id Optional. Forum id
 863   * @return bool False on failure, true on success
 864   */
 865  function bbp_privatize_forum( $forum_id = 0, $current_visibility = '' ) {
 866  
 867      $forum_id = bbp_get_forum_id( $forum_id );
 868  
 869      do_action( 'bbp_privatize_forum',  $forum_id );
 870  
 871      // Only run queries if visibility is changing
 872      if ( bbp_get_private_status_id() !== $current_visibility ) {
 873  
 874          // Get hidden forums
 875          $hidden = bbp_get_hidden_forum_ids();
 876  
 877          // Find this forum in the array
 878          if ( in_array( $forum_id, $hidden, true ) ) {
 879  
 880              $offset = array_search( $forum_id, $hidden, true );
 881  
 882              // Splice around it
 883              array_splice( $hidden, $offset, 1 );
 884  
 885              // Update hidden forums minus this one
 886              update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
 887          }
 888  
 889          // Add to '_bbp_private_forums' site option
 890          $private   = bbp_get_private_forum_ids();
 891          $private[] = $forum_id;
 892          update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
 893  
 894          // Update forums visibility setting
 895          $bbp_db = bbp_db();
 896          $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_private_status_id() ), array( 'ID' => $forum_id ) );
 897          wp_transition_post_status( bbp_get_private_status_id(), $current_visibility, get_post( $forum_id ) );
 898          clean_post_cache( $forum_id );
 899      }
 900  
 901      do_action( 'bbp_privatized_forum', $forum_id );
 902  
 903      return $forum_id;
 904  }
 905  
 906  /**
 907   * Mark the forum as hidden
 908   *
 909   * @since 2.0.0 bbPress (r2996)
 910   *
 911   * @param int $forum_id Optional. Forum id
 912   * @return bool False on failure, true on success
 913   */
 914  function bbp_hide_forum( $forum_id = 0, $current_visibility = '' ) {
 915  
 916      $forum_id = bbp_get_forum_id( $forum_id );
 917  
 918      do_action( 'bbp_hide_forum', $forum_id );
 919  
 920      // Only run queries if visibility is changing
 921      if ( bbp_get_hidden_status_id() !== $current_visibility ) {
 922  
 923          // Get private forums
 924          $private = bbp_get_private_forum_ids();
 925  
 926          // Find this forum in the array
 927          if ( in_array( $forum_id, $private, true ) ) {
 928  
 929              $offset = array_search( $forum_id, $private, true );
 930  
 931              // Splice around it
 932              array_splice( $private, $offset, 1 );
 933  
 934              // Update private forums minus this one
 935              update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
 936          }
 937  
 938          // Add to '_bbp_hidden_forums' site option
 939          $hidden   = bbp_get_hidden_forum_ids();
 940          $hidden[] = $forum_id;
 941          update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
 942  
 943          // Update forums visibility setting
 944          $bbp_db = bbp_db();
 945          $bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_hidden_status_id() ), array( 'ID' => $forum_id ) );
 946          wp_transition_post_status( bbp_get_hidden_status_id(), $current_visibility, get_post( $forum_id ) );
 947          clean_post_cache( $forum_id );
 948      }
 949  
 950      do_action( 'bbp_hid_forum',  $forum_id );
 951  
 952      return $forum_id;
 953  }
 954  
 955  /**
 956   * Recaches the private and hidden forums
 957   *
 958   * @since 2.4.0 bbPress (r5017)
 959   *
 960   * @return array An array of the status code and the message
 961   */
 962  function bbp_repair_forum_visibility() {
 963  
 964      // First, delete everything.
 965      delete_option( '_bbp_private_forums' );
 966      delete_option( '_bbp_hidden_forums'  );
 967  
 968      /**
 969       * Don't search for both private/hidden statuses. Since 'pre_get_posts' is an
 970       * action, it's not removed by suppress_filters. We need to make sure that
 971       * we're only searching for the supplied post_status.
 972       *
 973       * @see https://bbpress.trac.wordpress.org/ticket/2512
 974       */
 975      remove_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );
 976  
 977      // Query for private forums
 978      $private_forums = new WP_Query( array(
 979          'fields'         => 'ids',
 980          'post_type'      => bbp_get_forum_post_type(),
 981          'post_status'    => bbp_get_private_status_id(),
 982          'posts_per_page' => -1,
 983  
 984          // Performance
 985          'nopaging'               => true,
 986          'suppress_filters'       => true,
 987          'update_post_term_cache' => false,
 988          'update_post_meta_cache' => false,
 989          'ignore_sticky_posts'    => true,
 990          'no_found_rows'          => true
 991      ) );
 992  
 993      // Query for hidden forums
 994      $hidden_forums = new WP_Query( array(
 995          'fields'           => 'ids',
 996          'suppress_filters' => true,
 997          'post_type'        => bbp_get_forum_post_type(),
 998          'post_status'      => bbp_get_hidden_status_id(),
 999          'posts_per_page'   => -1,
1000  
1001          // Performance
1002          'nopaging'               => true,
1003          'suppress_filters'       => true,
1004          'update_post_term_cache' => false,
1005          'update_post_meta_cache' => false,
1006          'ignore_sticky_posts'    => true,
1007          'no_found_rows'          => true
1008      ) );
1009  
1010      // Enable forum visibilty normalization
1011      add_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );
1012  
1013      // Reset the $post global
1014      wp_reset_postdata();
1015  
1016      // Private
1017      if ( ! is_wp_error( $private_forums ) ) {
1018          update_option( '_bbp_private_forums', $private_forums->posts );
1019      }
1020  
1021      // Hidden forums
1022      if ( ! is_wp_error( $hidden_forums ) ) {
1023          update_option( '_bbp_hidden_forums',  $hidden_forums->posts  );
1024      }
1025  
1026      // Complete results
1027      return true;
1028  }
1029  
1030  /** Subscriptions *************************************************************/
1031  
1032  /**
1033   * Remove a deleted forum from all user subscriptions
1034   *
1035   * @since 2.5.0 bbPress (r5156)
1036   *
1037   * @param int $forum_id Get the forum ID to remove
1038   */
1039  function bbp_remove_forum_from_all_subscriptions( $forum_id = 0 ) {
1040  
1041      // Subscriptions are not active
1042      if ( ! bbp_is_subscriptions_active() ) {
1043          return;
1044      }
1045  
1046      // Bail if no forum
1047      $forum_id = bbp_get_forum_id( $forum_id );
1048      if ( empty( $forum_id ) ) {
1049          return;
1050      }
1051  
1052      // Remove forum from all subscriptions
1053      return bbp_remove_object_from_all_users( $forum_id, '_bbp_subscription', 'post' );
1054  }
1055  
1056  /** Count Bumpers *************************************************************/
1057  
1058  /**
1059   * Bump the total topic count of a forum
1060   *
1061   * @since 2.1.0 bbPress (r3825)
1062   *
1063   * @param int $forum_id Optional. Forum id.
1064   * @param int $difference Optional. Default 1
1065   * @param bool $update_ancestors Optional. Default true
1066   *
1067   * @return int Forum topic count
1068   */
1069  function bbp_bump_forum_topic_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1070  
1071      // Bail if no bump
1072      if ( empty( $difference ) ) {
1073          return false;
1074      }
1075  
1076      // Get some counts
1077      $forum_id          = bbp_get_forum_id( $forum_id );
1078      $topic_count       = bbp_get_forum_topic_count( $forum_id, false, true );
1079      $total_topic_count = bbp_get_forum_topic_count( $forum_id, true,  true );
1080      $difference        = (int) $difference;
1081  
1082      // Update this forum id
1083      update_post_meta( $forum_id, '_bbp_topic_count',       (int) ( $topic_count       + $difference ) );
1084      update_post_meta( $forum_id, '_bbp_total_topic_count', (int) ( $total_topic_count + $difference ) );
1085  
1086      // Check for ancestors
1087      if ( true === $update_ancestors ) {
1088  
1089          // Get post ancestors
1090          $forum     = get_post( $forum_id );
1091          $ancestors = get_post_ancestors( $forum );
1092  
1093          // If has ancestors, loop through them...
1094          if ( ! empty( $ancestors ) ) {
1095              foreach ( (array) $ancestors as $parent_forum_id ) {
1096  
1097                  // Only update topic count when an ancestor is not a category.
1098                  if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1099  
1100                      $parent_topic_count = bbp_get_forum_topic_count( $parent_forum_id, false, true );
1101                      update_post_meta( $parent_forum_id, '_bbp_topic_count', (int) ( $parent_topic_count + $difference ) );
1102                  }
1103  
1104                  // Update the total topic count.
1105                  $parent_total_topic_count = bbp_get_forum_topic_count( $parent_forum_id, true,  true );
1106                  update_post_meta( $parent_forum_id, '_bbp_total_topic_count', (int) ( $parent_total_topic_count + $difference ) );
1107              }
1108          }
1109      }
1110  
1111      $forum_topic_count = (int) ( $total_topic_count + $difference );
1112  
1113      // Filter & return
1114      return (int) apply_filters( 'bbp_bump_forum_topic_count', $forum_topic_count, $forum_id, $difference, $update_ancestors );
1115  }
1116  
1117  /**
1118   * Increase the total topic count of a forum by one.
1119   *
1120   * @since 2.6.0 bbPress (r6036)
1121   *
1122   * @param int $forum_id The forum id.
1123   * @return void
1124   */
1125  function bbp_increase_forum_topic_count( $forum_id = 0 ) {
1126  
1127      // Bail early if no id is passed.
1128      if ( empty( $forum_id ) ) {
1129          return;
1130      }
1131  
1132      // If it's a topic, get the forum id.
1133      if ( bbp_is_topic( $forum_id ) ) {
1134          $topic_id = $forum_id;
1135          $forum_id = bbp_get_topic_forum_id( $topic_id );
1136  
1137          // Bail if not public.
1138          if ( ! bbp_is_topic_public( $topic_id ) ) {
1139              bbp_increase_forum_topic_count_hidden( $forum_id );
1140              return;
1141          }
1142      }
1143  
1144      bbp_bump_forum_topic_count( $forum_id );
1145  }
1146  
1147  /**
1148   * Decrease the total topic count of a forum by one.
1149   *
1150   * @since 2.6.0 bbPress (r6036)
1151   *
1152   * @param int $forum_id The forum id.
1153   *
1154   * @return void
1155   */
1156  function bbp_decrease_forum_topic_count( $forum_id = 0 ) {
1157  
1158      // Bail early if no id is passed.
1159      if ( empty( $forum_id ) ) {
1160          return;
1161      }
1162  
1163      // If it's a topic, get the forum id.
1164      if ( bbp_is_topic( $forum_id ) ) {
1165          $forum_id = bbp_get_topic_forum_id( $forum_id );
1166      }
1167  
1168      bbp_bump_forum_topic_count( $forum_id, -1 );
1169  }
1170  
1171  /**
1172   * Bump the total hidden topic count of a forum
1173   *
1174   * @since 2.1.0 bbPress (r3825)
1175   *
1176   * @param int $forum_id Optional. Forum id.
1177   * @param int $difference Optional. Default 1
1178   *
1179   * @return int Forum hidden topic count
1180   */
1181  function bbp_bump_forum_topic_count_hidden( $forum_id = 0, $difference = 1 ) {
1182  
1183      // Bail if no bump
1184      if ( empty( $difference ) ) {
1185          return false;
1186      }
1187  
1188      // Get some counts
1189      $forum_id    = bbp_get_forum_id( $forum_id );
1190      $topic_count = bbp_get_forum_topic_count_hidden( $forum_id, true );
1191      $difference  = (int) $difference;
1192      $new_count   = (int) ( $topic_count + $difference );
1193  
1194      // Update this forum id
1195      update_post_meta( $forum_id, '_bbp_topic_count_hidden', $new_count );
1196  
1197      // Filter & return
1198      return (int) apply_filters( 'bbp_bump_forum_topic_count_hidden', $new_count, $forum_id, $difference );
1199  }
1200  
1201  /**
1202   * Increase the total hidden topic count of a forum by one.
1203   *
1204   * @since 2.6.0 bbPress (r6036)
1205   *
1206   * @param int $forum_id The forum id.
1207   *
1208   * @return void
1209   */
1210  function bbp_increase_forum_topic_count_hidden( $forum_id = 0 ) {
1211  
1212      // Bail early if no id is passed.
1213      if ( empty( $forum_id ) ) {
1214          return;
1215      }
1216  
1217      // If it's a topic, get the forum id.
1218      if ( bbp_is_topic( $forum_id ) ) {
1219          $forum_id = bbp_get_topic_forum_id( $forum_id );
1220      }
1221  
1222      bbp_bump_forum_topic_count_hidden( $forum_id );
1223  }
1224  
1225  /**
1226   * Decrease the total hidden topic count of a forum by one.
1227   *
1228   * @since 2.6.0 bbPress (r6036)
1229   *
1230   * @param int $forum_id The forum id.
1231   *
1232   * @return void
1233   */
1234  function bbp_decrease_forum_topic_count_hidden( $forum_id = 0 ) {
1235  
1236      // Bail early if no id is passed.
1237      if ( empty( $forum_id ) ) {
1238          return;
1239      }
1240  
1241      // If it's a topic, get the forum id.
1242      if ( bbp_is_topic( $forum_id ) ) {
1243          $forum_id = bbp_get_topic_forum_id( $forum_id );
1244      }
1245  
1246      bbp_bump_forum_topic_count_hidden( $forum_id, -1 );
1247  }
1248  
1249  /**
1250   * Bump the total topic count of a forum
1251   *
1252   * @since 2.1.0 bbPress (r3825)
1253   *
1254   * @param int $forum_id Optional. Forum id.
1255   * @param int $difference Optional. Default 1
1256   * @param bool $update_ancestors Optional. Default true
1257   *
1258   * @return int Forum topic count
1259   */
1260  function bbp_bump_forum_reply_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {
1261  
1262      // Bail if no bump
1263      if ( empty( $difference ) ) {
1264          return false;
1265      }
1266  
1267      // Get some counts
1268      $forum_id          = bbp_get_forum_id( $forum_id );
1269      $topic_count       = bbp_get_forum_reply_count( $forum_id, false, true );
1270      $total_reply_count = bbp_get_forum_reply_count( $forum_id, true,  true );
1271      $difference        = (int) $difference;
1272  
1273      // Update this forum id
1274      update_post_meta( $forum_id, '_bbp_reply_count',       (int) ( $topic_count       + $difference ) );
1275      update_post_meta( $forum_id, '_bbp_total_reply_count', (int) ( $total_reply_count + $difference ) );
1276  
1277      // Check for ancestors
1278      if ( true === $update_ancestors ) {
1279  
1280          // Get post ancestors
1281          $forum     = get_post( $forum_id );
1282          $ancestors = get_post_ancestors( $forum );
1283  
1284          // If has ancestors, loop through them...
1285          if ( ! empty( $ancestors ) ) {
1286              foreach ( (array) $ancestors as $parent_forum_id ) {
1287  
1288                  // Only update reply count when an ancestor is not a category.
1289                  if ( ! bbp_is_forum_category( $parent_forum_id ) ) {
1290  
1291                      $parent_reply_count = bbp_get_forum_reply_count( $parent_forum_id, false, true );
1292                      update_post_meta( $parent_forum_id, '_bbp_reply_count', (int) ( $parent_reply_count + $difference ) );
1293                  }
1294  
1295                  // Update the total reply count.
1296                  $parent_total_reply_count = bbp_get_forum_reply_count( $parent_forum_id, true,  true );
1297                  update_post_meta( $parent_forum_id, '_bbp_total_reply_count', (int) ( $parent_total_reply_count + $difference ) );
1298              }
1299          }
1300      }
1301  
1302      $forum_reply_count = (int) ( $total_reply_count + $difference );
1303  
1304      // Filter & return
1305      return (int) apply_filters( 'bbp_bump_forum_reply_count', $forum_reply_count, $forum_id, $difference, $update_ancestors );
1306  }
1307  
1308  /**
1309   * Increase the total reply count of a forum by one.
1310   *
1311   * @since 2.6.0 bbPress (r6036)
1312   *
1313   * @param int $forum_id The forum id.
1314   *
1315   * @return void
1316   */
1317  function bbp_increase_forum_reply_count( $forum_id = 0 ) {
1318  
1319      // Bail early if no id is passed.
1320      if ( empty( $forum_id ) ) {
1321          return;
1322      }
1323  
1324      // If it's a reply, get the forum id.
1325      if ( bbp_is_reply( $forum_id ) ) {
1326          $forum_id = bbp_get_reply_forum_id( $forum_id );
1327      }
1328  
1329      bbp_bump_forum_reply_count( $forum_id );
1330  }
1331  
1332  /**
1333   * Decrease the total reply count of a forum by one.
1334   *
1335   * @since 2.6.0 bbPress (r6036)
1336   *
1337   * @param int $forum_id The forum id.
1338   *
1339   * @return void
1340   */
1341  function bbp_decrease_forum_reply_count( $forum_id = 0 ) {
1342  
1343      // Bail early if no id is passed.
1344      if ( empty( $forum_id ) ) {
1345          return;
1346      }
1347  
1348      // If it's a reply, get the forum id.
1349      if ( bbp_is_reply( $forum_id ) ) {
1350          $forum_id = bbp_get_reply_forum_id( $forum_id );
1351      }
1352  
1353      bbp_bump_forum_reply_count( $forum_id, -1 );
1354  }
1355  
1356  /**
1357   * Update forum reply counts when a topic is approved or unapproved.
1358   *
1359   * @since 2.6.0 bbPress (r6036)
1360   *
1361   * @param int $topic_id The topic id.
1362   *
1363   * @return void
1364   */
1365  function bbp_approved_unapproved_topic_update_forum_reply_count( $topic_id = 0 ) {
1366  
1367      // Bail early if we don't have a topic id.
1368      if ( empty( $topic_id ) ) {
1369          return;
1370      }
1371  
1372      // Get the topic's replies.
1373      $count = bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() );
1374  
1375      // If we're unapproving, set count to negative.
1376      if ( 'bbp_unapproved_topic' === current_filter() ) {
1377          $count = -$count;
1378      }
1379  
1380      // Update counts.
1381      bbp_bump_forum_reply_count( bbp_get_topic_forum_id( $topic_id ), $count );
1382  }
1383  
1384  /** Forum Updaters ************************************************************/
1385  
1386  /**
1387   * Update the forum last topic id
1388   *
1389   * @since 2.0.0 bbPress (r2625)
1390   *
1391   * @param int $forum_id Optional. Forum id.
1392   * @param int $topic_id Optional. Topic id.
1393   * @return int Id of the forums most recent topic
1394   */
1395  function bbp_update_forum_last_topic_id( $forum_id = 0, $topic_id = 0 ) {
1396      $forum_id = bbp_get_forum_id( $forum_id );
1397  
1398      // Define local variable(s)
1399      $children_last_topic = 0;
1400  
1401      // Do some calculation if not manually set
1402      if ( empty( $topic_id ) ) {
1403  
1404          // Loop through children and add together forum reply counts
1405          $children = bbp_forum_query_subforum_ids( $forum_id );
1406          if ( ! empty( $children ) ) {
1407              foreach ( $children as $child ) {
1408                  $children_last_topic = bbp_update_forum_last_topic_id( $child ); // Recursive
1409              }
1410          }
1411  
1412          // Setup recent topic query vars
1413          $post_vars = array(
1414              'post_parent' => $forum_id,
1415              'post_type'   => bbp_get_topic_post_type(),
1416              'meta_key'    => '_bbp_last_active_time',
1417              'meta_type'   => 'DATETIME',
1418              'orderby'     => 'meta_value',
1419              'numberposts' => 1
1420          );
1421  
1422          // Get the most recent topic in this forum_id
1423          $recent_topic = get_posts( $post_vars );
1424          if ( ! empty( $recent_topic ) ) {
1425              $topic_id = $recent_topic[0]->ID;
1426          }
1427      }
1428  
1429      // Cast as integer in case of empty or string
1430      $topic_id            = (int) $topic_id;
1431      $children_last_topic = (int) $children_last_topic;
1432  
1433      // If child forums have higher id, use that instead
1434      if ( ! empty( $children ) && ( $children_last_topic > $topic_id ) ) {
1435          $topic_id = $children_last_topic;
1436      }
1437  
1438      // Update the last public topic ID
1439      if ( bbp_is_topic_published( $topic_id ) ) {
1440          update_post_meta( $forum_id, '_bbp_last_topic_id', $topic_id );
1441      }
1442  
1443      // Filter & return
1444      return (int) apply_filters( 'bbp_update_forum_last_topic_id', $topic_id, $forum_id );
1445  }
1446  
1447  /**
1448   * Update the forum last reply id
1449   *
1450   * @since 2.0.0 bbPress (r2625)
1451   *
1452   * @param int $forum_id Optional. Forum id.
1453   * @param int $reply_id Optional. Reply id.
1454   * @return int Id of the forums most recent reply
1455   */
1456  function bbp_update_forum_last_reply_id( $forum_id = 0, $reply_id = 0 ) {
1457      $forum_id = bbp_get_forum_id( $forum_id );
1458  
1459      // Define local variable(s)
1460      $children_last_reply = 0;
1461  
1462      // Do some calculation if not manually set
1463      if ( empty( $reply_id ) ) {
1464  
1465          // Loop through children and get the most recent reply id
1466          $children = bbp_forum_query_subforum_ids( $forum_id );
1467          if ( ! empty( $children ) ) {
1468              foreach ( $children as $child ) {
1469                  $children_last_reply = bbp_update_forum_last_reply_id( $child ); // Recursive
1470              }
1471          }
1472  
1473          // If this forum has topics...
1474          $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1475          if ( ! empty( $topic_ids ) ) {
1476  
1477              // ...get the most recent reply from those topics...
1478              $reply_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
1479  
1480              // ...and compare it to the most recent topic id...
1481              $reply_id = ( $reply_id > max( $topic_ids ) ) ? $reply_id : max( $topic_ids );
1482          }
1483      }
1484  
1485      // Cast as integer in case of empty or string
1486      $reply_id            = (int) $reply_id;
1487      $children_last_reply = (int) $children_last_reply;
1488  
1489      // If child forums have higher ID, check for newer reply id
1490      if ( ! empty( $children ) && ( $children_last_reply > $reply_id ) ) {
1491          $reply_id = $children_last_reply;
1492      }
1493  
1494      // Update the last public reply ID
1495      if ( bbp_is_reply_published( $reply_id ) ) {
1496          update_post_meta( $forum_id, '_bbp_last_reply_id', $reply_id );
1497      }
1498  
1499      // Filter & return
1500      return (int) apply_filters( 'bbp_update_forum_last_reply_id', $reply_id, $forum_id );
1501  }
1502  
1503  /**
1504   * Update the forum last active post id
1505   *
1506   * @since 2.0.0 bbPress (r2860)
1507   *
1508   * @param int $forum_id Optional. Forum id.
1509   * @param int $active_id Optional. Active post id.
1510   * @return int Id of the forums last active post
1511   */
1512  function bbp_update_forum_last_active_id( $forum_id = 0, $active_id = 0 ) {
1513  
1514      $forum_id = bbp_get_forum_id( $forum_id );
1515  
1516      // Define local variable(s)
1517      $children_last_active = 0;
1518  
1519      // Do some calculation if not manually set
1520      if ( empty( $active_id ) ) {
1521  
1522          // Loop through children and add together forum reply counts
1523          $children = bbp_forum_query_subforum_ids( $forum_id );
1524          if ( ! empty( $children ) ) {
1525              foreach ( $children as $child ) {
1526                  $children_last_active = bbp_update_forum_last_active_id( $child, $active_id );
1527              }
1528          }
1529  
1530          // Don't count replies if the forum is a category
1531          $topic_ids = bbp_forum_query_topic_ids( $forum_id );
1532          if ( ! empty( $topic_ids ) ) {
1533              $active_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
1534              $active_id = $active_id > max( $topic_ids ) ? $active_id : max( $topic_ids );
1535  
1536          // Forum has no topics
1537          } else {
1538              $active_id = 0;
1539          }
1540      }
1541  
1542      // Cast as integer in case of empty or string
1543      $active_id            = (int) $active_id;
1544      $children_last_active = (int) $children_last_active;
1545  
1546      // If child forums have higher id, use that instead
1547      if ( ! empty( $children ) && ( $children_last_active > $active_id ) ) {
1548          $active_id = $children_last_active;
1549      }
1550  
1551      // Update only if published
1552      if ( bbp_get_public_status_id() === get_post_status( $active_id ) ) {
1553          update_post_meta( $forum_id, '_bbp_last_active_id', $active_id );
1554      }
1555  
1556      // Filter & return
1557      return (int) apply_filters( 'bbp_update_forum_last_active_id', $active_id, $forum_id );
1558  }
1559  
1560  /**
1561   * Update the forums last active date/time (aka freshness)
1562   *
1563   * @since 2.0.0 bbPress (r2680)
1564   *
1565   * @param int    $forum_id Optional. Topic id.
1566   * @param string $new_time Optional. New time in mysql format.
1567   *
1568   * @return string MySQL timestamp of last active topic or reply
1569   */
1570  function bbp_update_forum_last_active_time( $forum_id = 0, $new_time = '' ) {
1571      $forum_id = bbp_get_forum_id( $forum_id );
1572  
1573      // Check time and use current if empty
1574      if ( empty( $new_time ) ) {
1575          $new_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $forum_id ) );
1576      }
1577  
1578      // Update only if there is a time
1579      if ( ! empty( $new_time ) ) {
1580          update_post_meta( $forum_id, '_bbp_last_active_time', $new_time );
1581      }
1582  
1583      // Filter & return
1584      return apply_filters( 'bbp_update_forum_last_active', $new_time, $forum_id );
1585  }
1586  
1587  /**
1588   * Update the forum sub-forum count
1589   *
1590   * @since 2.0.0 bbPress (r2625)
1591   *
1592   * @param int $forum_id Optional. Forum id
1593   * @return bool True on success, false on failure
1594   */
1595  function bbp_update_forum_subforum_count( $forum_id = 0, $subforums = 0 ) {
1596      $forum_id = bbp_get_forum_id( $forum_id );
1597  
1598      // Maybe query for counts
1599      if ( empty( $subforums ) ) {
1600          $subforums = bbp_get_public_child_count( $forum_id, bbp_get_forum_post_type() );
1601      }
1602  
1603      $subforums = (int) $subforums;
1604  
1605      update_post_meta( $forum_id, '_bbp_forum_subforum_count', $subforums );
1606  
1607      // Filter & return
1608      return (int) apply_filters( 'bbp_update_forum_subforum_count', $subforums, $forum_id );
1609  }
1610  
1611  /**
1612   * Adjust the total topic count of a forum
1613   *
1614   * @since 2.0.0 bbPress (r2464)
1615   *
1616   * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
1617   *                       is a topic or a forum. If it's a topic, its parent,
1618   *                       i.e. the forum is automatically retrieved.
1619   * @param bool $total_count Optional. To return the total count or normal count?
1620   * @return int Forum topic count
1621   */
1622  function bbp_update_forum_topic_count( $forum_id = 0 ) {
1623      $forum_id = bbp_get_forum_id( $forum_id );
1624      $children_topic_count = 0;
1625  
1626      // Loop through subforums and add together forum topic counts
1627      $children = bbp_forum_query_subforum_ids( $forum_id );
1628      if ( ! empty( $children ) ) {
1629          foreach ( $children as $child ) {
1630              $children_topic_count += bbp_update_forum_topic_count( $child ); // Recursive
1631          }
1632      }
1633  
1634      // Get total topics for this forum
1635      $topics = bbp_get_public_child_count( $forum_id, bbp_get_topic_post_type() );
1636  
1637      // Calculate total topics in this forum
1638      $total_topics = (int) ( $topics + $children_topic_count );
1639  
1640      // Update the count
1641      update_post_meta( $forum_id, '_bbp_topic_count',       $topics       );
1642      update_post_meta( $forum_id, '_bbp_total_topic_count', $total_topics );
1643  
1644      // Filter & return
1645      return (int) apply_filters( 'bbp_update_forum_topic_count', $total_topics, $forum_id );
1646  }
1647  
1648  /**
1649   * Adjust the total hidden topic count of a forum (hidden includes trashed,
1650   * spammed and pending topics)
1651   *
1652   * @since 2.0.0 bbPress (r2888)
1653   * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
1654   *
1655   * @param int $forum_id Optional. Topic id to update.
1656   * @param int $topic_count Optional. Set the topic count manually.
1657   *
1658   * @return int Topic hidden topic count
1659   */
1660  function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = 0 ) {
1661  
1662      // If topic_id was passed as $forum_id, then get its forum
1663      if ( bbp_is_topic( $forum_id ) ) {
1664          $topic_id = bbp_get_topic_id( $forum_id );
1665          $forum_id = bbp_get_topic_forum_id( $topic_id );
1666  
1667      // $forum_id is not a topic_id, so validate and proceed
1668      } else {
1669          $forum_id = bbp_get_forum_id( $forum_id );
1670      }
1671  
1672      // Can't update what isn't there
1673      if ( ! empty( $forum_id ) ) {
1674  
1675          // Get topics of forum
1676          if ( empty( $topic_count ) ) {
1677              $query = new WP_Query( array(
1678                  'fields'         => 'ids',
1679                  'post_parent'    => $forum_id,
1680                  'post_status'    => bbp_get_non_public_topic_statuses(),
1681                  'post_type'      => bbp_get_topic_post_type(),
1682                  'posts_per_page' => -1,
1683  
1684                  // Performance
1685                  'nopaging'               => true,
1686                  'suppress_filters'       => true,
1687                  'update_post_term_cache' => false,
1688                  'update_post_meta_cache' => false,
1689                  'ignore_sticky_posts'    => true,
1690                  'no_found_rows'          => true
1691              ) );
1692              $topic_count = $query->post_count;
1693              unset( $query );
1694          }
1695  
1696          $topic_count = (int) $topic_count;
1697  
1698          // Update the count
1699          update_post_meta( $forum_id, '_bbp_topic_count_hidden', $topic_count );
1700      }
1701  
1702      // Filter & return
1703      return (int) apply_filters( 'bbp_update_forum_topic_count_hidden', $topic_count, $forum_id );
1704  }
1705  
1706  /**
1707   * Adjust the total reply count of a forum
1708   *
1709   * @since 2.0.0 bbPress (r2464)
1710   * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
1711   *
1712   * @param int  $forum_id Optional. Forum id or topic id. It is checked whether it
1713   *                       is a topic or a forum. If it's a topic, its parent,
1714   *                       i.e. the forum is automatically retrieved.
1715   *
1716   * @return int Forum reply count
1717   */
1718  function bbp_update_forum_reply_count( $forum_id = 0 ) {
1719  
1720      $forum_id = bbp_get_forum_id( $forum_id );
1721      $children_reply_count = 0;
1722  
1723      // Loop through children and add together forum reply counts
1724      $children = bbp_forum_query_subforum_ids( $forum_id );
1725      if ( ! empty( $children ) ) {
1726          foreach ( (array) $children as $child ) {
1727              $children_reply_count += bbp_update_forum_reply_count( $child );
1728          }
1729      }
1730  
1731      // Don't count replies if the forum is a category
1732      $reply_count = 0;
1733      $topic_ids   = bbp_forum_query_topic_ids( $forum_id );
1734      if ( ! empty( $topic_ids ) ) {
1735          $reply_count = bbp_get_public_child_count( $forum_id, bbp_get_reply_post_type() );
1736      }
1737  
1738      // Calculate total replies in this forum
1739      $total_replies = (int) ( $reply_count + $children_reply_count );
1740  
1741      // Update the count
1742      update_post_meta( $forum_id, '_bbp_reply_count',       $reply_count   );
1743      update_post_meta( $forum_id, '_bbp_total_reply_count', $total_replies );
1744  
1745      // Filter & return
1746      return (int) apply_filters( 'bbp_update_forum_reply_count', $total_replies, $forum_id );
1747  }
1748  
1749  /**
1750   * Updates the counts of a forum.
1751   *
1752   * This calls a few internal functions that all run manual queries against the
1753   * database to get their results. As such, this function can be costly to run
1754   * but is necessary to keep everything accurate.
1755   *
1756   * @since 2.0.0 bbPress (r2908)
1757   *
1758   * @param array $args Supports these arguments:
1759   *  - forum_id: Forum id
1760   *  - last_topic_id: Last topic id
1761   *  - last_reply_id: Last reply id
1762   *  - last_active_id: Last active post id
1763   *  - last_active_time: last active time
1764   */
1765  function bbp_update_forum( $args = array() ) {
1766  
1767      // Parse arguments against default values
1768      $r = bbp_parse_args( $args, array(
1769          'forum_id'           => 0,
1770          'post_parent'        => 0,
1771          'last_topic_id'      => 0,
1772          'last_reply_id'      => 0,
1773          'last_active_id'     => 0,
1774          'last_active_time'   => 0,
1775          'last_active_status' => bbp_get_public_status_id()
1776      ), 'update_forum' );
1777  
1778      // Update the forum parent
1779      bbp_update_forum_id( $r['forum_id'], $r['post_parent'] );
1780  
1781      // Last topic and reply ID's
1782      bbp_update_forum_last_topic_id( $r['forum_id'], $r['last_topic_id'] );
1783      bbp_update_forum_last_reply_id( $r['forum_id'], $r['last_reply_id'] );
1784  
1785      // Active dance
1786      $r['last_active_id'] = bbp_update_forum_last_active_id( $r['forum_id'], $r['last_active_id'] );
1787  
1788      // If no active time was passed, get it from the last_active_id
1789      if ( empty( $r['last_active_time'] ) ) {
1790          $r['last_active_time'] = get_post_field( 'post_date', $r['last_active_id'] );
1791      }
1792  
1793      if ( bbp_get_public_status_id() === $r['last_active_status'] ) {
1794          bbp_update_forum_last_active_time( $r['forum_id'], $r['last_active_time'] );
1795      }
1796  
1797      // Counts
1798      bbp_update_forum_subforum_count( $r['forum_id'] );
1799  
1800      // Only update topic count if we're deleting a topic, or in the dashboard.
1801      if ( in_array( current_filter(), array( 'bbp_delete_topic', 'save_post' ), true ) ) {
1802          bbp_update_forum_reply_count(        $r['forum_id'] );
1803          bbp_update_forum_topic_count(        $r['forum_id'] );
1804          bbp_update_forum_topic_count_hidden( $r['forum_id'] );
1805      }
1806  
1807      // Update the parent forum if one was passed
1808      if ( ! empty( $r['post_parent'] ) && is_numeric( $r['post_parent'] ) ) {
1809          bbp_update_forum( array(
1810              'forum_id'    => $r['post_parent'],
1811              'post_parent' => get_post_field( 'post_parent', $r['post_parent'] )
1812          ) );
1813      }
1814  
1815      // Bump the custom query cache
1816      wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
1817  }
1818  
1819  /** Helpers *******************************************************************/
1820  
1821  /**
1822   * Return an associative array of available topic statuses
1823   *
1824   * @since 2.4.0 bbPress (r5059)
1825   *
1826   * @param int $forum_id   Optional. Forum id.
1827   *
1828   * @return array
1829   */
1830  function bbp_get_forum_statuses( $forum_id = 0 ) {
1831  
1832      // Filter & return
1833      return (array) apply_filters( 'bbp_get_forum_statuses', array(
1834          'open'   => _x( 'Open',    'Open the forum',  'bbpress' ),
1835          'closed' => _x( 'Closed',  'Close the forum', 'bbpress' )
1836      ), $forum_id );
1837  }
1838  
1839  /**
1840   * Return an associative array of forum types
1841   *
1842   * @since 2.4.0 bbPress (r5059)
1843   *
1844   * @param int $forum_id   Optional. Forum id.
1845   *
1846   * @return array
1847   */
1848  function bbp_get_forum_types( $forum_id = 0 ) {
1849  
1850      // Filter & return
1851      return (array) apply_filters( 'bbp_get_forum_types', array(
1852          'forum'    => _x( 'Forum',    'Forum accepts new topics', 'bbpress' ),
1853          'category' => _x( 'Category', 'Forum is a category',      'bbpress' )
1854      ), $forum_id );
1855  }
1856  
1857  /**
1858   * Return an associative array of forum visibility
1859   *
1860   * @since 2.4.0 bbPress (r5059)
1861   *
1862   * @param int $forum_id   Optional. Forum id.
1863   *
1864   * @return array
1865   */
1866  function bbp_get_forum_visibilities( $forum_id = 0) {
1867  
1868      // Filter & return
1869      return (array) apply_filters( 'bbp_get_forum_visibilities', array(
1870          bbp_get_public_status_id()  => _x( 'Public',  'Make forum public',  'bbpress' ),
1871          bbp_get_private_status_id() => _x( 'Private', 'Make forum private', 'bbpress' ),
1872          bbp_get_hidden_status_id()  => _x( 'Hidden',  'Make forum hidden',  'bbpress' )
1873      ), $forum_id );
1874  }
1875  
1876  /** Queries *******************************************************************/
1877  
1878  /**
1879   * Returns the hidden forum ids
1880   *
1881   * Only hidden forum ids are returned. Public and private ids are not.
1882   *
1883   * @since 2.0.0 bbPress (r3007)
1884   */
1885  function bbp_get_hidden_forum_ids() {
1886      $forum_ids = get_option( '_bbp_hidden_forums', array() );
1887      $forum_ids = ! empty( $forum_ids )
1888          ? wp_parse_id_list( $forum_ids )
1889          : array();
1890  
1891      // Filter & return
1892      return (array) apply_filters( 'bbp_get_hidden_forum_ids', $forum_ids );
1893  }
1894  
1895  /**
1896   * Returns the private forum ids
1897   *
1898   * Only private forum ids are returned. Public and hidden ids are not.
1899   *
1900   * @since 2.0.0 bbPress (r3007)
1901   */
1902  function bbp_get_private_forum_ids() {
1903      $forum_ids = get_option( '_bbp_private_forums', array() );
1904      $forum_ids = ! empty( $forum_ids )
1905          ? wp_parse_id_list( $forum_ids )
1906          : array();
1907  
1908      // Filter & return
1909      return (array) apply_filters( 'bbp_get_private_forum_ids', $forum_ids );
1910  }
1911  
1912  /**
1913   * Returns the forum IDs that should be excluded from various views & queries,
1914   * based on the current user's capabilities.
1915   *
1916   * @since 2.6.0 bbPress (r6425)
1917   *
1918   * @return array Forum IDs to exclude, or an empty array
1919   */
1920  function bbp_get_excluded_forum_ids() {
1921  
1922      // Private forums
1923      $private = ! current_user_can( 'read_private_forums' )
1924          ? bbp_get_private_forum_ids()
1925          : array();
1926  
1927      // Hidden forums
1928      $hidden = ! current_user_can( 'read_hidden_forums' )
1929          ? bbp_get_hidden_forum_ids()
1930          : array();
1931  
1932      // Merge private & hidden forums together, and remove any empties
1933      $forum_ids = ( ! empty( $private ) || ! empty( $hidden ) )
1934          ? array_filter( wp_parse_id_list( array_merge( $private, $hidden ) ) )
1935          : array();
1936  
1937      // Filter & return
1938      return (array) apply_filters( 'bbp_get_excluded_forum_ids', $forum_ids, $private, $hidden );
1939  }
1940  
1941  /**
1942   * Returns a meta_query that either includes or excludes hidden forum IDs
1943   * from a query.
1944   *
1945   * @since 2.0.0 bbPress (r3291)
1946   *
1947   * @param string Optional. The type of value to return. (string|array|meta_query)
1948   */
1949  function bbp_exclude_forum_ids( $type = 'string' ) {
1950  
1951      // Setup arrays
1952      $forum_ids = array();
1953  
1954      // Types
1955      $types = array(
1956          'array'      => array(),
1957          'string'     => '',
1958          'meta_query' => array()
1959      );
1960  
1961      // Exclude for everyone but keymasters
1962      if ( ! bbp_is_user_keymaster() ) {
1963  
1964          // Get forum IDs to exclude
1965          $forum_ids = bbp_get_excluded_forum_ids();
1966  
1967          // Store return values in static types array
1968          if ( ! empty( $forum_ids ) ) {
1969  
1970              // Comparison
1971              $compare = ( 1 < count( $forum_ids ) )
1972                  ? 'NOT IN'
1973                  : '!=';
1974  
1975              // Setup types
1976              $types['array']      = $forum_ids;
1977              $types['string']     = implode( ',', $forum_ids );
1978              $types['meta_query'] = array(
1979                  'key'     => '_bbp_forum_id',
1980                  'value'   => $types['string'],
1981                  'type'    => 'NUMERIC',
1982                  'compare' => $compare
1983              );
1984          }
1985      }
1986  
1987      // There are forums that need to be excluded
1988      $retval = $types[ $type ];
1989  
1990      // Filter & return
1991      return apply_filters( 'bbp_exclude_forum_ids', $retval, $forum_ids, $type );
1992  }
1993  
1994  /**
1995   * Adjusts forum, topic, and reply queries to exclude items that might be
1996   * contained inside hidden or private forums that the user does not have the
1997   * capability to view.
1998   *
1999   * Doing it with an action allows us to trap all WP_Query's rather than needing
2000   * to hardcode this logic into each query. It also protects forum content for
2001   * plugins that might be doing their own queries.
2002   *
2003   * @since 2.0.0 bbPress (r3291)
2004   *
2005   * @param WP_Query $posts_query
2006   *
2007   * @return WP_Query
2008   */
2009  function bbp_pre_get_posts_normalize_forum_visibility( $posts_query = null ) {
2010  
2011      // Bail if all forums are explicitly allowed
2012      if ( true === apply_filters( 'bbp_include_all_forums', false, $posts_query ) ) {
2013          return;
2014      }
2015  
2016      // Bail if $posts_query is not an object or of incorrect class
2017      if ( ! is_object( $posts_query ) || ! is_a( $posts_query, 'WP_Query' ) ) {
2018          return;
2019      }
2020  
2021      // Get query post types array .
2022      $post_types = (array) $posts_query->get( 'post_type' );
2023  
2024      // Forums
2025      if ( bbp_get_forum_post_type() === implode( '', $post_types ) ) {
2026  
2027          // Prevent accidental wp-admin post_row override
2028          if ( is_admin() && isset( $_REQUEST['post_status'] ) ) {
2029              return;
2030          }
2031  
2032          /** Default ***********************************************************/
2033  
2034          // Add all supported forum visibilities
2035          $posts_query->set( 'post_status', array_keys( bbp_get_forum_visibilities() ) );
2036  
2037          // Get forums to exclude
2038          $hidden_ids = bbp_exclude_forum_ids( 'array' );
2039  
2040          // Bail if no forums to exclude
2041          if ( empty( $hidden_ids ) ) {
2042              return;
2043          }
2044  
2045          // Get any existing meta queries
2046          $not_in = $posts_query->get( 'post__not_in', array() );
2047  
2048          // Add our meta query to existing
2049          $not_in = array_unique( array_merge( $not_in, $hidden_ids ) );
2050  
2051          // Set the meta_query var
2052          $posts_query->set( 'post__not_in', $not_in );
2053  
2054      // Some other post type besides Forums, Topics, or Replies
2055      } elseif ( ! array_diff( $post_types, bbp_get_post_types() ) ) {
2056  
2057          // Get forums to exclude
2058          $forum_ids = bbp_exclude_forum_ids( 'meta_query' );
2059  
2060          // Bail if no forums to exclude
2061          if ( empty( $forum_ids ) ) {
2062              return;
2063          }
2064  
2065          // Get any existing meta queries
2066          $meta_query   = (array) $posts_query->get( 'meta_query', array() );
2067  
2068          // Add our meta query to existing
2069          $meta_query[] = $forum_ids;
2070  
2071          // Set the meta_query var
2072          $posts_query->set( 'meta_query', $meta_query );
2073      }
2074  }
2075  
2076  /**
2077   * Returns the forum's topic ids
2078   *
2079   * Only topics with published and closed statuses are returned
2080   *
2081   * @since 2.0.0 bbPress (r2908)
2082   *
2083   * @param int $forum_id Forum id
2084   */
2085  function bbp_forum_query_topic_ids( $forum_id ) {
2086      $topic_ids = bbp_get_public_child_ids( $forum_id, bbp_get_topic_post_type() );
2087  
2088      // Filter & return
2089      return (array) apply_filters( 'bbp_forum_query_topic_ids', $topic_ids, $forum_id );
2090  }
2091  
2092  /**
2093   * Returns the forum's subforum ids
2094   *
2095   * Only forums with published status are returned
2096   *
2097   * @since 2.0.0 bbPress (r2908)
2098   *
2099   * @param int $forum_id Forum id
2100   */
2101  function bbp_forum_query_subforum_ids( $forum_id ) {
2102      $subforum_ids = bbp_get_all_child_ids( $forum_id, bbp_get_forum_post_type() );
2103  
2104      // Filter & return
2105      return (array) apply_filters( 'bbp_forum_query_subforum_ids', $subforum_ids, $forum_id );
2106  }
2107  
2108  /**
2109   * Returns the forum's last reply id
2110   *
2111   * @since 2.0.0 bbPress (r2908)
2112   * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
2113   *
2114   * @param int $forum_id Forum id.
2115   * @param int $topic_ids Optional. Topic ids.
2116   */
2117  function bbp_forum_query_last_reply_id( $forum_id = 0, $topic_ids = 0 ) {
2118  
2119      // Validate forum
2120      $forum_id = bbp_get_forum_id( $forum_id );
2121  
2122      // Get topic ID's if none were passed
2123      if ( empty( $topic_ids ) ) {
2124          $topic_ids = bbp_forum_query_topic_ids( $forum_id );
2125      }
2126  
2127      $query = new WP_Query( array(
2128          'fields'           => 'ids',
2129          'suppress_filters' => true,
2130          'post_parent__in'  => $topic_ids,
2131          'post_status'      => bbp_get_public_status_id(),
2132          'post_type'        => bbp_get_reply_post_type(),
2133          'posts_per_page'   => 1,
2134          'orderby'          => array(
2135              'post_date' => 'DESC',
2136              'ID'        => 'DESC'
2137          ),
2138  
2139          // Performance
2140          'update_post_term_cache' => false,
2141          'update_post_meta_cache' => false,
2142          'ignore_sticky_posts'    => true,
2143          'no_found_rows'          => true
2144      ) );
2145      $reply_id = array_shift( $query->posts );
2146      unset( $query );
2147  
2148      // Filter & return
2149      return (int) apply_filters( 'bbp_forum_query_last_reply_id', $reply_id, $forum_id );
2150  }
2151  
2152  /** Listeners *****************************************************************/
2153  
2154  /**
2155   * Check if it's a hidden forum or a topic or reply of a hidden forum and if
2156   * the user can't view it, then sets a 404
2157   *
2158   * @since 2.0.0 bbPress (r2996)
2159   */
2160  function bbp_forum_enforce_hidden() {
2161  
2162      // Bail if not viewing a single item or if user has caps
2163      if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_hidden_forums' ) ) {
2164          return;
2165      }
2166  
2167      // Define local variables
2168      $forum_id = 0;
2169      $wp_query = bbp_get_wp_query();
2170  
2171      // Check post type
2172      switch ( $wp_query->get( 'post_type' ) ) {
2173  
2174          // Forum
2175          case bbp_get_forum_post_type() :
2176              $forum_id = bbp_get_forum_id( $wp_query->post->ID );
2177              break;
2178  
2179          // Topic
2180          case bbp_get_topic_post_type() :
2181              $forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
2182              break;
2183  
2184          // Reply
2185          case bbp_get_reply_post_type() :
2186              $forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
2187              break;
2188      }
2189  
2190      // If forum is explicitly hidden and user not capable, set 404
2191      if ( ! empty( $forum_id ) && bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
2192          bbp_set_404( $wp_query );
2193      }
2194  }
2195  
2196  /**
2197   * Check if it's a private forum or a topic or reply of a private forum and if
2198   * the user can't view it, then sets a 404
2199   *
2200   * @since 2.0.0 bbPress (r2996)
2201   */
2202  function bbp_forum_enforce_private() {
2203  
2204      // Bail if not viewing a single item or if user has caps
2205      if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_private_forums' ) ) {
2206          return;
2207      }
2208  
2209      // Define local variables
2210      $forum_id = 0;
2211      $wp_query = bbp_get_wp_query();
2212  
2213      // Check post type
2214      switch ( $wp_query->get( 'post_type' ) ) {
2215  
2216          // Forum
2217          case bbp_get_forum_post_type() :
2218              $forum_id = bbp_get_forum_id( $wp_query->post->ID );
2219              break;
2220  
2221          // Topic
2222          case bbp_get_topic_post_type() :
2223              $forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
2224              break;
2225  
2226          // Reply
2227          case bbp_get_reply_post_type() :
2228              $forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
2229              break;
2230  
2231      }
2232  
2233      // If forum is explicitly hidden and user not capable, set 404
2234      if ( ! empty( $forum_id ) && bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
2235          bbp_set_404( $wp_query );
2236      }
2237  }
2238  
2239  /** Permissions ***************************************************************/
2240  
2241  /**
2242   * Redirect if unauthorized user is attempting to edit a forum
2243   *
2244   * @since 2.1.0 bbPress (r3607)
2245   */
2246  function bbp_check_forum_edit() {
2247  
2248      // Bail if not editing a topic
2249      if ( ! bbp_is_forum_edit() ) {
2250          return;
2251      }
2252  
2253      // User cannot edit topic, so redirect back to reply
2254      if ( ! current_user_can( 'edit_forum', bbp_get_forum_id() ) ) {
2255          bbp_redirect( bbp_get_forum_permalink() );
2256      }
2257  }
2258  
2259  /**
2260   * Delete all topics (and their replies) for a specific forum ID
2261   *
2262   * @since 2.1.0 bbPress (r3668)
2263   *
2264   * @param int $forum_id
2265   * @return If forum is not valid
2266   */
2267  function bbp_delete_forum_topics( $forum_id = 0 ) {
2268  
2269      // Validate forum ID
2270      $forum_id = bbp_get_forum_id( $forum_id );
2271      if ( empty( $forum_id ) ) {
2272          return;
2273      }
2274  
2275      // Forum is being permanently deleted, so its content has go too
2276      // Note that we get all post statuses here
2277      $topics = new WP_Query( array(
2278          'fields'         => 'id=>parent',
2279          'post_type'      => bbp_get_topic_post_type(),
2280          'post_parent'    => $forum_id,
2281          'post_status'    => array_keys( get_post_stati() ),
2282          'posts_per_page' => -1,
2283  
2284          // Performance
2285          'nopaging'               => true,
2286          'suppress_filters'       => true,
2287          'update_post_term_cache' => false,
2288          'update_post_meta_cache' => false,
2289          'ignore_sticky_posts'    => true,
2290          'no_found_rows'          => true
2291      ) );
2292  
2293      // Loop through and delete child topics. Topic replies will get deleted by
2294      // the bbp_delete_topic() action.
2295      if ( ! empty( $topics->posts ) ) {
2296          foreach ( $topics->posts as $topic ) {
2297              wp_delete_post( $topic->ID, true );
2298          }
2299  
2300          // Reset the $post global
2301          wp_reset_postdata();
2302      }
2303  
2304      // Cleanup
2305      unset( $topics );
2306  }
2307  
2308  /**
2309   * Trash all topics inside a forum
2310   *
2311   * @since 2.1.0 bbPress (r3668)
2312   *
2313   * @param int $forum_id
2314   * @return If forum is not valid
2315   */
2316  function bbp_trash_forum_topics( $forum_id = 0 ) {
2317  
2318      // Validate forum ID
2319      $forum_id = bbp_get_forum_id( $forum_id );
2320      if ( empty( $forum_id ) ) {
2321          return;
2322      }
2323  
2324      // Allowed post statuses to pre-trash
2325      $post_stati = array(
2326          bbp_get_public_status_id(),
2327          bbp_get_closed_status_id(),
2328          bbp_get_pending_status_id()
2329      );
2330  
2331      // Forum is being trashed, so its topics (and replies) are trashed too
2332      $topics = new WP_Query( array(
2333          'fields'         => 'id=>parent',
2334          'post_type'      => bbp_get_topic_post_type(),
2335          'post_parent'    => $forum_id,
2336          'post_status'    => $post_stati,
2337          'posts_per_page' => -1,
2338  
2339          // Performance
2340          'nopaging'               => true,
2341          'suppress_filters'       => true,
2342          'update_post_term_cache' => false,
2343          'update_post_meta_cache' => false,
2344          'ignore_sticky_posts'    => true,
2345          'no_found_rows'          => true
2346      ) );
2347  
2348      // Loop through and trash child topics. Topic replies will get trashed by
2349      // the bbp_trash_topic() action.
2350      if ( ! empty( $topics->posts ) ) {
2351  
2352          // Prevent debug notices
2353          $pre_trashed_topics = array();
2354  
2355          // Loop through topics, trash them, and add them to array
2356          foreach ( $topics->posts as $topic ) {
2357              wp_trash_post( $topic->ID, true );
2358              $pre_trashed_topics[] = $topic->ID;
2359          }
2360  
2361          // Set a post_meta entry of the topics that were trashed by this action.
2362          // This is so we can possibly untrash them, without untrashing topics
2363          // that were purposefully trashed before.
2364          update_post_meta( $forum_id, '_bbp_pre_trashed_topics', $pre_trashed_topics );
2365  
2366          // Reset the $post global
2367          wp_reset_postdata();
2368      }
2369  
2370      // Cleanup
2371      unset( $topics );
2372  }
2373  
2374  /**
2375   * Untrash all topics inside a forum
2376   *
2377   * @since 2.1.0 bbPress (r3668)
2378   *
2379   * @param int $forum_id
2380   * @return If forum is not valid
2381   */
2382  function bbp_untrash_forum_topics( $forum_id = 0 ) {
2383  
2384      // Validate forum ID
2385      $forum_id = bbp_get_forum_id( $forum_id );
2386  
2387      if ( empty( $forum_id ) ) {
2388          return;
2389      }
2390  
2391      // Get the topics that were not previously trashed
2392      $pre_trashed_topics = get_post_meta( $forum_id, '_bbp_pre_trashed_topics', true );
2393  
2394      // There are topics to untrash
2395      if ( ! empty( $pre_trashed_topics ) ) {
2396  
2397          // Maybe reverse the trashed topics array
2398          if ( is_array( $pre_trashed_topics ) ) {
2399              $pre_trashed_topics = array_reverse( $pre_trashed_topics );
2400          }
2401  
2402          // Loop through topics
2403          foreach ( (array) $pre_trashed_topics as $topic ) {
2404              wp_untrash_post( $topic );
2405          }
2406      }
2407  }
2408  
2409  /** Before Delete/Trash/Untrash ***********************************************/
2410  
2411  /**
2412   * Called before deleting a forum.
2413   *
2414   * This function is supplemental to the actual forum deletion which is
2415   * handled by WordPress core API functions. It is used to clean up after
2416   * a forum that is being deleted.
2417   *
2418   * @since 2.1.0 bbPress (r3668)
2419   */
2420  function bbp_delete_forum( $forum_id = 0 ) {
2421      $forum_id = bbp_get_forum_id( $forum_id );
2422  
2423      if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2424          return false;
2425      }
2426  
2427      do_action( 'bbp_delete_forum', $forum_id );
2428  }
2429  
2430  /**
2431   * Called before trashing a forum
2432   *
2433   * This function is supplemental to the actual forum being trashed which is
2434   * handled by WordPress core API functions. It is used to clean up after
2435   * a forum that is being trashed.
2436   *
2437   * @since 2.1.0 bbPress (r3668)
2438   */
2439  function bbp_trash_forum( $forum_id = 0 ) {
2440      $forum_id = bbp_get_forum_id( $forum_id );
2441  
2442      if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2443          return false;
2444      }
2445  
2446      do_action( 'bbp_trash_forum', $forum_id );
2447  }
2448  
2449  /**
2450   * Called before untrashing a forum
2451   *
2452   * @since 2.1.0 bbPress (r3668)
2453   */
2454  function bbp_untrash_forum( $forum_id = 0 ) {
2455      $forum_id = bbp_get_forum_id( $forum_id );
2456  
2457      if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2458          return false;
2459      }
2460  
2461      do_action( 'bbp_untrash_forum', $forum_id );
2462  }
2463  
2464  /** After Delete/Trash/Untrash ************************************************/
2465  
2466  /**
2467   * Called after deleting a forum
2468   *
2469   * Try not to use this action. All meta & taxonomy terms have already been
2470   * deleted, making them impossible to use.
2471   *
2472   * @since 2.1.0 bbPress (r3668)
2473   * @since 2.6.0 bbPress (r6526) Not recommend for usage
2474   */
2475  function bbp_deleted_forum( $forum_id = 0 ) {
2476      $forum_id = bbp_get_forum_id( $forum_id );
2477  
2478      if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2479          return false;
2480      }
2481  
2482      do_action( 'bbp_deleted_forum', $forum_id );
2483  }
2484  
2485  /**
2486   * Called after trashing a forum
2487   *
2488   * @since 2.1.0 bbPress (r3668)
2489   */
2490  function bbp_trashed_forum( $forum_id = 0 ) {
2491      $forum_id = bbp_get_forum_id( $forum_id );
2492  
2493      if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2494          return false;
2495      }
2496  
2497      do_action( 'bbp_trashed_forum', $forum_id );
2498  }
2499  
2500  /**
2501   * Called after untrashing a forum
2502   *
2503   * @since 2.1.0 bbPress (r3668)
2504   */
2505  function bbp_untrashed_forum( $forum_id = 0 ) {
2506      $forum_id = bbp_get_forum_id( $forum_id );
2507  
2508      if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
2509          return false;
2510      }
2511  
2512      do_action( 'bbp_untrashed_forum', $forum_id );
2513  }


Generated: Tue Jul 16 01:01:32 2019 Cross-referenced by PHPXref 0.7.1