web/wp-content/plugins/bbpress/includes/common/functions.php
changeset 196 5e8dcbe22c24
equal deleted inserted replaced
195:c7c0fbc09788 196:5e8dcbe22c24
       
     1 <?php
       
     2 
       
     3 /**
       
     4  * bbPress Common Functions
       
     5  *
       
     6  * Common functions are ones that are used by more than one component, like
       
     7  * forums, topics, replies, users, topic tags, etc...
       
     8  *
       
     9  * @package bbPress
       
    10  * @subpackage Functions
       
    11  */
       
    12 
       
    13 // Exit if accessed directly
       
    14 if ( !defined( 'ABSPATH' ) ) exit;
       
    15 
       
    16 /** Formatting ****************************************************************/
       
    17 
       
    18 /**
       
    19  * A bbPress specific method of formatting numeric values
       
    20  *
       
    21  * @since bbPress (r2486)
       
    22  *
       
    23  * @param string $number Number to format
       
    24  * @param string $decimals Optional. Display decimals
       
    25  * @uses apply_filters() Calls 'bbp_number_format' with the formatted values,
       
    26  *                        number and display decimals bool
       
    27  * @return string Formatted string
       
    28  */
       
    29 function bbp_number_format( $number = 0, $decimals = false, $dec_point = '.', $thousands_sep = ',' ) {
       
    30 
       
    31 	// If empty, set $number to (int) 0
       
    32 	if ( ! is_numeric( $number ) )
       
    33 		$number = 0;
       
    34 
       
    35 	return apply_filters( 'bbp_number_format', number_format( $number, $decimals, $dec_point, $thousands_sep ), $number, $decimals, $dec_point, $thousands_sep );
       
    36 }
       
    37 
       
    38 /**
       
    39  * A bbPress specific method of formatting numeric values
       
    40  *
       
    41  * @since bbPress (r3857)
       
    42  *
       
    43  * @param string $number Number to format
       
    44  * @param string $decimals Optional. Display decimals
       
    45  * @uses apply_filters() Calls 'bbp_number_format' with the formatted values,
       
    46  *                        number and display decimals bool
       
    47  * @return string Formatted string
       
    48  */
       
    49 function bbp_number_format_i18n( $number = 0, $decimals = false ) {
       
    50 
       
    51 	// If empty, set $number to (int) 0
       
    52 	if ( ! is_numeric( $number ) )
       
    53 		$number = 0;
       
    54 
       
    55 	return apply_filters( 'bbp_number_format_i18n', number_format_i18n( $number, $decimals ), $number, $decimals );
       
    56 }
       
    57 
       
    58 /**
       
    59  * Convert time supplied from database query into specified date format.
       
    60  *
       
    61  * @since bbPress (r2455)
       
    62  *
       
    63  * @param int|object $post Optional. Default is global post object. A post_id or
       
    64  *                          post object
       
    65  * @param string $d Optional. Default is 'U'. Either 'G', 'U', or php date
       
    66  *                             format
       
    67  * @param bool $translate Optional. Default is false. Whether to translate the
       
    68  *                                   result
       
    69  * @uses mysql2date() To convert the format
       
    70  * @uses apply_filters() Calls 'bbp_convert_date' with the time, date format
       
    71  *                        and translate bool
       
    72  * @return string Returns timestamp
       
    73  */
       
    74 function bbp_convert_date( $time, $d = 'U', $translate = false ) {
       
    75 	$time = mysql2date( $d, $time, $translate );
       
    76 
       
    77 	return apply_filters( 'bbp_convert_date', $time, $d, $translate );
       
    78 }
       
    79 
       
    80 /**
       
    81  * Output formatted time to display human readable time difference.
       
    82  *
       
    83  * @since bbPress (r2544)
       
    84  *
       
    85  * @param string $older_date Unix timestamp from which the difference begins.
       
    86  * @param string $newer_date Optional. Unix timestamp from which the
       
    87  *                            difference ends. False for current time.
       
    88  * @uses bbp_get_time_since() To get the formatted time
       
    89  */
       
    90 function bbp_time_since( $older_date, $newer_date = false ) {
       
    91 	echo bbp_get_time_since( $older_date, $newer_date = false );
       
    92 }
       
    93 	/**
       
    94 	 * Return formatted time to display human readable time difference.
       
    95 	 *
       
    96 	 * @since bbPress (r2544)
       
    97 	 *
       
    98 	 * @param string $older_date Unix timestamp from which the difference begins.
       
    99 	 * @param string $newer_date Optional. Unix timestamp from which the
       
   100 	 *                            difference ends. False for current time.
       
   101 	 * @uses current_time() To get the current time in mysql format
       
   102 	 * @uses human_time_diff() To get the time differene in since format
       
   103 	 * @uses apply_filters() Calls 'bbp_get_time_since' with the time
       
   104 	 *                        difference and time
       
   105 	 * @return string Formatted time
       
   106 	 */
       
   107 	function bbp_get_time_since( $older_date, $newer_date = false ) {
       
   108 		
       
   109 		// Setup the strings
       
   110 		$unknown_text   = apply_filters( 'bbp_core_time_since_unknown_text',   __( 'sometime',  'bbpress' ) );
       
   111 		$right_now_text = apply_filters( 'bbp_core_time_since_right_now_text', __( 'right now', 'bbpress' ) );
       
   112 		$ago_text       = apply_filters( 'bbp_core_time_since_ago_text',       __( '%s ago',    'bbpress' ) );
       
   113 
       
   114 		// array of time period chunks
       
   115 		$chunks = array(
       
   116 			array( 60 * 60 * 24 * 365 , __( 'year',   'bbpress' ), __( 'years',   'bbpress' ) ),
       
   117 			array( 60 * 60 * 24 * 30 ,  __( 'month',  'bbpress' ), __( 'months',  'bbpress' ) ),
       
   118 			array( 60 * 60 * 24 * 7,    __( 'week',   'bbpress' ), __( 'weeks',   'bbpress' ) ),
       
   119 			array( 60 * 60 * 24 ,       __( 'day',    'bbpress' ), __( 'days',    'bbpress' ) ),
       
   120 			array( 60 * 60 ,            __( 'hour',   'bbpress' ), __( 'hours',   'bbpress' ) ),
       
   121 			array( 60 ,                 __( 'minute', 'bbpress' ), __( 'minutes', 'bbpress' ) ),
       
   122 			array( 1,                   __( 'second', 'bbpress' ), __( 'seconds', 'bbpress' ) )
       
   123 		);
       
   124 
       
   125 		if ( !empty( $older_date ) && !is_numeric( $older_date ) ) {
       
   126 			$time_chunks = explode( ':', str_replace( ' ', ':', $older_date ) );
       
   127 			$date_chunks = explode( '-', str_replace( ' ', '-', $older_date ) );
       
   128 			$older_date  = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
       
   129 		}
       
   130 
       
   131 		// $newer_date will equal false if we want to know the time elapsed
       
   132 		// between a date and the current time. $newer_date will have a value if
       
   133 		// we want to work out time elapsed between two known dates.
       
   134 		$newer_date = ( !$newer_date ) ? strtotime( current_time( 'mysql' ) ) : $newer_date;
       
   135 
       
   136 		// Difference in seconds
       
   137 		$since = $newer_date - $older_date;
       
   138 
       
   139 		// Something went wrong with date calculation and we ended up with a negative date.
       
   140 		if ( 0 > $since ) {
       
   141 			$output = $unknown_text;
       
   142 
       
   143 		// We only want to output two chunks of time here, eg:
       
   144 		//     x years, xx months
       
   145 		//     x days, xx hours
       
   146 		// so there's only two bits of calculation below:
       
   147 		} else {
       
   148 
       
   149 			// Step one: the first chunk
       
   150 			for ( $i = 0, $j = count( $chunks ); $i < $j; ++$i ) {
       
   151 				$seconds = $chunks[$i][0];
       
   152 
       
   153 				// Finding the biggest chunk (if the chunk fits, break)
       
   154 				$count = floor( $since / $seconds );
       
   155 				if ( 0 != $count ) {
       
   156 					break;
       
   157 				}
       
   158 			}
       
   159 
       
   160 			// If $i iterates all the way to $j, then the event happened 0 seconds ago
       
   161 			if ( !isset( $chunks[$i] ) ) {
       
   162 				$output = $right_now_text;
       
   163 
       
   164 			} else {
       
   165 
       
   166 				// Set output var
       
   167 				$output = ( 1 == $count ) ? '1 '. $chunks[$i][1] : $count . ' ' . $chunks[$i][2];
       
   168 
       
   169 				// Step two: the second chunk
       
   170 				if ( $i + 2 < $j ) {
       
   171 					$seconds2 = $chunks[$i + 1][0];
       
   172 					$name2    = $chunks[$i + 1][1];
       
   173 					$count2   = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );
       
   174 
       
   175 					// Add to output var
       
   176 					if ( 0 != $count2 ) {
       
   177 						$output .= ( 1 == $count2 ) ? _x( ',', 'Separator in time since', 'bbpress' ) . ' 1 '. $name2 : _x( ',', 'Separator in time since', 'bbpress' ) . ' ' . $count2 . ' ' . $chunks[$i + 1][2];
       
   178 					}
       
   179 				}
       
   180 
       
   181 				// No output, so happened right now
       
   182 				if ( ! (int) trim( $output ) ) {
       
   183 					$output = $right_now_text;
       
   184 				}
       
   185 			}
       
   186 		}
       
   187 
       
   188 		// Append 'ago' to the end of time-since if not 'right now'
       
   189 		if ( $output != $right_now_text ) {
       
   190 			$output = sprintf( $ago_text, $output );
       
   191 		}
       
   192 
       
   193 		return apply_filters( 'bbp_get_time_since', $output, $older_date, $newer_date );
       
   194 	}
       
   195 
       
   196 /**
       
   197  * Formats the reason for editing the topic/reply.
       
   198  *
       
   199  * Does these things:
       
   200  *  - Trimming
       
   201  *  - Removing periods from the end of the string
       
   202  *  - Trimming again
       
   203  *
       
   204  * @since bbPress (r2782)
       
   205  *
       
   206  * @param int $topic_id Optional. Topic id
       
   207  * @return string Status of topic
       
   208  */
       
   209 function bbp_format_revision_reason( $reason = '' ) {
       
   210 	$reason = (string) $reason;
       
   211 
       
   212 	// Format reason for proper display
       
   213 	if ( empty( $reason ) )
       
   214 		return $reason;
       
   215 
       
   216 	// Trimming
       
   217 	$reason = trim( $reason );
       
   218 
       
   219 	// We add our own full stop.
       
   220 	while ( substr( $reason, -1 ) == '.' )
       
   221 		$reason = substr( $reason, 0, -1 );
       
   222 
       
   223 	// Trim again
       
   224 	$reason = trim( $reason );
       
   225 
       
   226 	return $reason;
       
   227 }
       
   228 
       
   229 /** Misc **********************************************************************/
       
   230 
       
   231 /**
       
   232  * Append 'view=all' to query string if it's already there from referer
       
   233  *
       
   234  * @since bbPress (r3325)
       
   235  *
       
   236  * @param string $original_link Original Link to be modified
       
   237  * @param bool $force Override bbp_get_view_all() check
       
   238  * @uses current_user_can() To check if the current user can moderate
       
   239  * @uses add_query_arg() To add args to the url
       
   240  * @uses apply_filters() Calls 'bbp_add_view_all' with the link and original link
       
   241  * @return string The link with 'view=all' appended if necessary
       
   242  */
       
   243 function bbp_add_view_all( $original_link = '', $force = false ) {
       
   244 
       
   245 	// Are we appending the view=all vars?
       
   246 	if ( bbp_get_view_all() || !empty( $force ) )
       
   247 		$link = add_query_arg( array( 'view' => 'all' ), $original_link );
       
   248 	else
       
   249 		$link = $original_link;
       
   250 
       
   251 	return apply_filters( 'bbp_add_view_all', $link, $original_link );
       
   252 }
       
   253 
       
   254 /**
       
   255  * Remove 'view=all' from query string
       
   256  *
       
   257  * @since bbPress (r3325)
       
   258  *
       
   259  * @param string $original_link Original Link to be modified
       
   260  * @uses current_user_can() To check if the current user can moderate
       
   261  * @uses add_query_arg() To add args to the url
       
   262  * @uses apply_filters() Calls 'bbp_add_view_all' with the link and original link
       
   263  * @return string The link with 'view=all' appended if necessary
       
   264  */
       
   265 function bbp_remove_view_all( $original_link = '' ) {
       
   266 	return apply_filters( 'bbp_add_view_all', remove_query_arg( 'view', $original_link ), $original_link );
       
   267 }
       
   268 
       
   269 /**
       
   270  * If current user can and is vewing all topics/replies
       
   271  *
       
   272  * @since bbPress (r3325)
       
   273  *
       
   274  * @uses current_user_can() To check if the current user can moderate
       
   275  * @uses apply_filters() Calls 'bbp_get_view_all' with the link and original link
       
   276  * @return bool Whether current user can and is viewing all
       
   277  */
       
   278 function bbp_get_view_all( $cap = 'moderate' ) {
       
   279 	$retval = ( ( !empty( $_GET['view'] ) && ( 'all' == $_GET['view'] ) && current_user_can( $cap ) ) );
       
   280 	return apply_filters( 'bbp_get_view_all', (bool) $retval );
       
   281 }
       
   282 
       
   283 /**
       
   284  * Assist pagination by returning correct page number
       
   285  *
       
   286  * @since bbPress (r2628)
       
   287  *
       
   288  * @uses get_query_var() To get the 'paged' value
       
   289  * @return int Current page number
       
   290  */
       
   291 function bbp_get_paged() {
       
   292 	global $wp_query;
       
   293 
       
   294 	// Check the query var
       
   295 	if ( get_query_var( 'paged' ) ) {
       
   296 		$paged = get_query_var( 'paged' );
       
   297 
       
   298 	// Check query paged
       
   299 	} elseif ( !empty( $wp_query->query['paged'] ) ) {
       
   300 		$paged = $wp_query->query['paged'];
       
   301 	}
       
   302 
       
   303 	// Paged found
       
   304 	if ( !empty( $paged ) )
       
   305 		return (int) $paged;
       
   306 
       
   307 	// Default to first page
       
   308 	return 1;
       
   309 }
       
   310 
       
   311 /**
       
   312  * Fix post author id on post save
       
   313  *
       
   314  * When a logged in user changes the status of an anonymous reply or topic, or
       
   315  * edits it, the post_author field is set to the logged in user's id. This
       
   316  * function fixes that.
       
   317  *
       
   318  * @since bbPress (r2734)
       
   319  *
       
   320  * @param array $data Post data
       
   321  * @param array $postarr Original post array (includes post id)
       
   322  * @uses bbp_get_topic_post_type() To get the topic post type
       
   323  * @uses bbp_get_reply_post_type() To get the reply post type
       
   324  * @uses bbp_is_topic_anonymous() To check if the topic is by an anonymous user
       
   325  * @uses bbp_is_reply_anonymous() To check if the reply is by an anonymous user
       
   326  * @return array Data
       
   327  */
       
   328 function bbp_fix_post_author( $data = array(), $postarr = array() ) {
       
   329 
       
   330 	// Post is not being updated or the post_author is already 0, return
       
   331 	if ( empty( $postarr['ID'] ) || empty( $data['post_author'] ) )
       
   332 		return $data;
       
   333 
       
   334 	// Post is not a topic or reply, return
       
   335 	if ( !in_array( $data['post_type'], array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ) ) )
       
   336 		return $data;
       
   337 
       
   338 	// Is the post by an anonymous user?
       
   339 	if ( ( bbp_get_topic_post_type() == $data['post_type'] && !bbp_is_topic_anonymous( $postarr['ID'] ) ) ||
       
   340 	     ( bbp_get_reply_post_type() == $data['post_type'] && !bbp_is_reply_anonymous( $postarr['ID'] ) ) )
       
   341 		return $data;
       
   342 
       
   343 	// The post is being updated. It is a topic or a reply and is written by an anonymous user.
       
   344 	// Set the post_author back to 0
       
   345 	$data['post_author'] = 0;
       
   346 
       
   347 	return $data;
       
   348 }
       
   349 
       
   350 /**
       
   351  * Check the date against the _bbp_edit_lock setting.
       
   352  *
       
   353  * @since bbPress (r3133)
       
   354  *
       
   355  * @param string $post_date_gmt
       
   356  *
       
   357  * @uses get_option() Get the edit lock time
       
   358  * @uses current_time() Get the current time
       
   359  * @uses strtotime() Convert strings to time
       
   360  * @uses apply_filters() Allow output to be manipulated
       
   361  *
       
   362  * @return bool
       
   363  */
       
   364 function bbp_past_edit_lock( $post_date_gmt ) {
       
   365 
       
   366 	// Assume editing is allowed
       
   367 	$retval = false;
       
   368 
       
   369 	// Bail if empty date
       
   370 	if ( ! empty( $post_date_gmt ) ) {
       
   371 
       
   372 		// Period of time
       
   373 		$lockable  = '+' . get_option( '_bbp_edit_lock', '5' ) . ' minutes';
       
   374 
       
   375 		// Now
       
   376 		$cur_time  = current_time( 'timestamp', true );
       
   377 
       
   378 		// Add lockable time to post time
       
   379 		$lock_time = strtotime( $lockable, strtotime( $post_date_gmt ) );
       
   380 
       
   381 		// Compare
       
   382 		if ( $cur_time >= $lock_time ) {
       
   383 			$retval = true;
       
   384 		}
       
   385 	}
       
   386 
       
   387 	return apply_filters( 'bbp_past_edit_lock', (bool) $retval, $cur_time, $lock_time, $post_date_gmt );
       
   388 }
       
   389 
       
   390 /** Statistics ****************************************************************/
       
   391 
       
   392 /**
       
   393  * Get the forum statistics
       
   394  *
       
   395  * @since bbPress (r2769)
       
   396  *
       
   397  * @param mixed $args Optional. The function supports these arguments (all
       
   398  *                     default to true):
       
   399  *  - count_users: Count users?
       
   400  *  - count_forums: Count forums?
       
   401  *  - count_topics: Count topics? If set to false, private, spammed and trashed
       
   402  *                   topics are also not counted.
       
   403  *  - count_private_topics: Count private topics? (only counted if the current
       
   404  *                           user has read_private_topics cap)
       
   405  *  - count_spammed_topics: Count spammed topics? (only counted if the current
       
   406  *                           user has edit_others_topics cap)
       
   407  *  - count_trashed_topics: Count trashed topics? (only counted if the current
       
   408  *                           user has view_trash cap)
       
   409  *  - count_replies: Count replies? If set to false, private, spammed and
       
   410  *                   trashed replies are also not counted.
       
   411  *  - count_private_replies: Count private replies? (only counted if the current
       
   412  *                           user has read_private_replies cap)
       
   413  *  - count_spammed_replies: Count spammed replies? (only counted if the current
       
   414  *                           user has edit_others_replies cap)
       
   415  *  - count_trashed_replies: Count trashed replies? (only counted if the current
       
   416  *                           user has view_trash cap)
       
   417  *  - count_tags: Count tags? If set to false, empty tags are also not counted
       
   418  *  - count_empty_tags: Count empty tags?
       
   419  * @uses bbp_count_users() To count the number of registered users
       
   420  * @uses bbp_get_forum_post_type() To get the forum post type
       
   421  * @uses bbp_get_topic_post_type() To get the topic post type
       
   422  * @uses bbp_get_reply_post_type() To get the reply post type
       
   423  * @uses wp_count_posts() To count the number of forums, topics and replies
       
   424  * @uses wp_count_terms() To count the number of topic tags
       
   425  * @uses current_user_can() To check if the user is capable of doing things
       
   426  * @uses number_format_i18n() To format the number
       
   427  * @uses apply_filters() Calls 'bbp_get_statistics' with the statistics and args
       
   428  * @return object Walked forum tree
       
   429  */
       
   430 function bbp_get_statistics( $args = '' ) {
       
   431 
       
   432 	$defaults = array (
       
   433 		'count_users'           => true,
       
   434 		'count_forums'          => true,
       
   435 		'count_topics'          => true,
       
   436 		'count_private_topics'  => true,
       
   437 		'count_spammed_topics'  => true,
       
   438 		'count_trashed_topics'  => true,
       
   439 		'count_replies'         => true,
       
   440 		'count_private_replies' => true,
       
   441 		'count_spammed_replies' => true,
       
   442 		'count_trashed_replies' => true,
       
   443 		'count_tags'            => true,
       
   444 		'count_empty_tags'      => true
       
   445 	);
       
   446 	$r = bbp_parse_args( $args, $defaults, 'get_statistics' );
       
   447 	extract( $r );
       
   448 
       
   449 	// Users
       
   450 	if ( !empty( $count_users ) )
       
   451 		$user_count = bbp_get_total_users();
       
   452 
       
   453 	// Forums
       
   454 	if ( !empty( $count_forums ) ) {
       
   455 		$forum_count = wp_count_posts( bbp_get_forum_post_type() );
       
   456 		$forum_count = $forum_count->publish;
       
   457 	}
       
   458 
       
   459 	// Post statuses
       
   460 	$private = bbp_get_private_status_id();
       
   461 	$spam    = bbp_get_spam_status_id();
       
   462 	$trash   = bbp_get_trash_status_id();
       
   463 	$closed  = bbp_get_closed_status_id();
       
   464 
       
   465 	// Topics
       
   466 	if ( !empty( $count_topics ) ) {
       
   467 
       
   468 		$all_topics  = wp_count_posts( bbp_get_topic_post_type() );
       
   469 
       
   470 		// Published (publish + closed)
       
   471 		$topic_count = $all_topics->publish + $all_topics->{$closed};
       
   472 
       
   473 		if ( current_user_can( 'read_private_topics' ) || current_user_can( 'edit_others_topics' ) || current_user_can( 'view_trash' ) ) {
       
   474 
       
   475 			// Private
       
   476 			$topics['private'] = ( !empty( $count_private_topics ) && current_user_can( 'read_private_topics' ) ) ? (int) $all_topics->{$private} : 0;
       
   477 
       
   478 			// Spam
       
   479 			$topics['spammed'] = ( !empty( $count_spammed_topics ) && current_user_can( 'edit_others_topics'  ) ) ? (int) $all_topics->{$spam}    : 0;
       
   480 
       
   481 			// Trash
       
   482 			$topics['trashed'] = ( !empty( $count_trashed_topics ) && current_user_can( 'view_trash'          ) ) ? (int) $all_topics->{$trash}   : 0;
       
   483 
       
   484 			// Total hidden (private + spam + trash)
       
   485 			$topic_count_hidden = $topics['private'] + $topics['spammed'] + $topics['trashed'];
       
   486 
       
   487 			// Generate the hidden topic count's title attribute
       
   488 			$topic_titles[] = !empty( $topics['private'] ) ? sprintf( __( 'Private: %s', 'bbpress' ), number_format_i18n( $topics['private'] ) ) : '';
       
   489 			$topic_titles[] = !empty( $topics['spammed'] ) ? sprintf( __( 'Spammed: %s', 'bbpress' ), number_format_i18n( $topics['spammed'] ) ) : '';
       
   490 			$topic_titles[] = !empty( $topics['trashed'] ) ? sprintf( __( 'Trashed: %s', 'bbpress' ), number_format_i18n( $topics['trashed'] ) ) : '';
       
   491 
       
   492 			// Compile the hidden topic title
       
   493 			$hidden_topic_title = implode( ' | ', array_filter( $topic_titles ) );
       
   494 		}
       
   495 	}
       
   496 
       
   497 	// Replies
       
   498 	if ( !empty( $count_replies ) ) {
       
   499 
       
   500 		$all_replies = wp_count_posts( bbp_get_reply_post_type() );
       
   501 
       
   502 		// Published
       
   503 		$reply_count = $all_replies->publish;
       
   504 
       
   505 		if ( current_user_can( 'read_private_replies' ) || current_user_can( 'edit_others_replies' ) || current_user_can( 'view_trash' ) ) {
       
   506 
       
   507 			// Private
       
   508 			$replies['private'] = ( !empty( $count_private_replies ) && current_user_can( 'read_private_replies' ) ) ? (int) $all_replies->{$private} : 0;
       
   509 
       
   510 			// Spam
       
   511 			$replies['spammed'] = ( !empty( $count_spammed_replies ) && current_user_can( 'edit_others_replies'  ) ) ? (int) $all_replies->{$spam}    : 0;
       
   512 
       
   513 			// Trash
       
   514 			$replies['trashed'] = ( !empty( $count_trashed_replies ) && current_user_can( 'view_trash'           ) ) ? (int) $all_replies->{$trash}   : 0;
       
   515 
       
   516 			// Total hidden (private + spam + trash)
       
   517 			$reply_count_hidden = $replies['private'] + $replies['spammed'] + $replies['trashed'];
       
   518 
       
   519 			// Generate the hidden topic count's title attribute
       
   520 			$reply_titles[] = !empty( $replies['private'] ) ? sprintf( __( 'Private: %s', 'bbpress' ), number_format_i18n( $replies['private'] ) ) : '';
       
   521 			$reply_titles[] = !empty( $replies['spammed'] ) ? sprintf( __( 'Spammed: %s', 'bbpress' ), number_format_i18n( $replies['spammed'] ) ) : '';
       
   522 			$reply_titles[] = !empty( $replies['trashed'] ) ? sprintf( __( 'Trashed: %s', 'bbpress' ), number_format_i18n( $replies['trashed'] ) ) : '';
       
   523 
       
   524 			// Compile the hidden replies title
       
   525 			$hidden_reply_title = implode( ' | ', array_filter( $reply_titles ) );
       
   526 
       
   527 		}
       
   528 	}
       
   529 
       
   530 	// Topic Tags
       
   531 	if ( !empty( $count_tags ) && bbp_allow_topic_tags() ) {
       
   532 
       
   533 		// Get the count
       
   534 		$topic_tag_count = wp_count_terms( bbp_get_topic_tag_tax_id(), array( 'hide_empty' => true ) );
       
   535 
       
   536 		// Empty tags
       
   537 		if ( !empty( $count_empty_tags ) && current_user_can( 'edit_topic_tags' ) ) {
       
   538 			$empty_topic_tag_count = wp_count_terms( bbp_get_topic_tag_tax_id() ) - $topic_tag_count;
       
   539 		}
       
   540 	}
       
   541 
       
   542 	// Tally the tallies
       
   543 	$statistics = compact( 'user_count', 'forum_count', 'topic_count', 'topic_count_hidden', 'reply_count', 'reply_count_hidden', 'topic_tag_count', 'empty_topic_tag_count' );
       
   544 	$statistics = array_map( 'absint',             $statistics );
       
   545 	$statistics = array_map( 'number_format_i18n', $statistics );
       
   546 
       
   547 	// Add the hidden (topic/reply) count title attribute strings because we don't need to run the math functions on these (see above)
       
   548 	if ( isset( $hidden_topic_title ) )
       
   549 		$statistics['hidden_topic_title'] = $hidden_topic_title;
       
   550 
       
   551 	if ( isset( $hidden_reply_title ) )
       
   552 		$statistics['hidden_reply_title'] = $hidden_reply_title;
       
   553 
       
   554 	return apply_filters( 'bbp_get_statistics', $statistics, $args );
       
   555 }
       
   556 
       
   557 /** New/edit topic/reply helpers **********************************************/
       
   558 
       
   559 /**
       
   560  * Filter anonymous post data
       
   561  *
       
   562  * We use REMOTE_ADDR here directly. If you are behind a proxy, you should
       
   563  * ensure that it is properly set, such as in wp-config.php, for your
       
   564  * environment. See {@link http://core.trac.wordpress.org/ticket/9235}
       
   565  *
       
   566  * Note that bbp_pre_anonymous_filters() is responsible for sanitizing each
       
   567  * of the filtered core anonymous values here.
       
   568  *
       
   569  * If there are any errors, those are directly added to {@link bbPress:errors}
       
   570  *
       
   571  * @since bbPress (r2734)
       
   572  *
       
   573  * @param mixed $args Optional. If no args are there, then $_POST values are
       
   574  *                     used.
       
   575  * @uses apply_filters() Calls 'bbp_pre_anonymous_post_author_name' with the
       
   576  *                        anonymous user name
       
   577  * @uses apply_filters() Calls 'bbp_pre_anonymous_post_author_email' with the
       
   578  *                        anonymous user email
       
   579  * @uses apply_filters() Calls 'bbp_pre_anonymous_post_author_website' with the
       
   580  *                        anonymous user website
       
   581  * @return bool|array False on errors, values in an array on success
       
   582  */
       
   583 function bbp_filter_anonymous_post_data( $args = '' ) {
       
   584 
       
   585 	// Assign variables
       
   586 	$defaults = array (
       
   587 		'bbp_anonymous_name'    => !empty( $_POST['bbp_anonymous_name']    ) ? $_POST['bbp_anonymous_name']    : false,
       
   588 		'bbp_anonymous_email'   => !empty( $_POST['bbp_anonymous_email']   ) ? $_POST['bbp_anonymous_email']   : false,
       
   589 		'bbp_anonymous_website' => !empty( $_POST['bbp_anonymous_website'] ) ? $_POST['bbp_anonymous_website'] : false,
       
   590 	);
       
   591 	$r = bbp_parse_args( $args, $defaults, 'filter_anonymous_post_data' );
       
   592 	extract( $r );
       
   593 
       
   594 	// Filter variables and add errors if necessary
       
   595 	$bbp_anonymous_name = apply_filters( 'bbp_pre_anonymous_post_author_name',  $bbp_anonymous_name  );
       
   596 	if ( empty( $bbp_anonymous_name ) )
       
   597 		bbp_add_error( 'bbp_anonymous_name',  __( '<strong>ERROR</strong>: Invalid author name submitted!',   'bbpress' ) );
       
   598 
       
   599 	$bbp_anonymous_email = apply_filters( 'bbp_pre_anonymous_post_author_email', $bbp_anonymous_email );
       
   600 	if ( empty( $bbp_anonymous_email ) )
       
   601 		bbp_add_error( 'bbp_anonymous_email', __( '<strong>ERROR</strong>: Invalid email address submitted!', 'bbpress' ) );
       
   602 
       
   603 	// Website is optional
       
   604 	$bbp_anonymous_website = apply_filters( 'bbp_pre_anonymous_post_author_website', $bbp_anonymous_website );
       
   605 
       
   606 	if ( !bbp_has_errors() )
       
   607 		$retval = compact( 'bbp_anonymous_name', 'bbp_anonymous_email', 'bbp_anonymous_website' );
       
   608 	else
       
   609 		$retval = false;
       
   610 
       
   611 	// Finally, return sanitized data or false
       
   612 	return apply_filters( 'bbp_filter_anonymous_post_data', $retval, $args );
       
   613 }
       
   614 
       
   615 /**
       
   616  * Check for duplicate topics/replies
       
   617  *
       
   618  * Check to make sure that a user is not making a duplicate post
       
   619  *
       
   620  * @since bbPress (r2763)
       
   621  *
       
   622  * @param array $post_data Contains information about the comment
       
   623  * @uses current_user_can() To check if the current user can throttle
       
   624  * @uses get_meta_sql() To generate the meta sql for checking anonymous email
       
   625  * @uses apply_filters() Calls 'bbp_check_for_duplicate_query' with the
       
   626  *                        duplicate check query and post data
       
   627  * @uses wpdb::get_var() To execute our query and get the var back
       
   628  * @uses get_post_meta() To get the anonymous user email post meta
       
   629  * @uses do_action() Calls 'bbp_post_duplicate_trigger' with the post data when
       
   630  *                    it is found that it is a duplicate
       
   631  * @return bool True if it is not a duplicate, false if it is
       
   632  */
       
   633 function bbp_check_for_duplicate( $post_data ) {
       
   634 
       
   635 	// No duplicate checks for those who can throttle
       
   636 	if ( current_user_can( 'throttle' ) )
       
   637 		return true;
       
   638 
       
   639 	global $wpdb;
       
   640 
       
   641 	extract( $post_data, EXTR_SKIP );
       
   642 
       
   643 	// Check for anonymous post
       
   644 	if ( empty( $post_author ) && ( isset( $anonymous_data ) && !empty( $anonymous_data['bbp_anonymous_email'] ) ) ) {
       
   645 		$clauses = get_meta_sql( array( array(
       
   646 			'key'   => '_bbp_anonymous_email',
       
   647 			'value' => $anonymous_data['bbp_anonymous_email']
       
   648 		) ), 'post', $wpdb->posts, 'ID' );
       
   649 
       
   650 		$join    = $clauses['join'];
       
   651 		$where   = $clauses['where'];
       
   652 	} else{
       
   653 		$join    = $where = '';
       
   654 	}
       
   655 
       
   656 	// Simple duplicate check
       
   657 	// Expected slashed ($post_type, $post_parent, $post_author, $post_content, $anonymous_data)
       
   658 	$status = bbp_get_trash_status_id();
       
   659 	$dupe   = "SELECT ID FROM {$wpdb->posts} {$join} WHERE post_type = '{$post_type}' AND post_status != '{$status}' AND post_author = {$post_author} AND post_content = '{$post_content}' {$where}";
       
   660 	$dupe  .= !empty( $post_parent ) ? " AND post_parent = '{$post_parent}'" : '';
       
   661 	$dupe  .= " LIMIT 1";
       
   662 	$dupe   = apply_filters( 'bbp_check_for_duplicate_query', $dupe, $post_data );
       
   663 
       
   664 	if ( $wpdb->get_var( $dupe ) ) {
       
   665 		do_action( 'bbp_check_for_duplicate_trigger', $post_data );
       
   666 		return false;
       
   667 	}
       
   668 
       
   669 	return true;
       
   670 }
       
   671 
       
   672 /**
       
   673  * Check for flooding
       
   674  *
       
   675  * Check to make sure that a user is not making too many posts in a short amount
       
   676  * of time.
       
   677  *
       
   678  * @since bbPress (r2734)
       
   679  *
       
   680  * @param false|array $anonymous_data Optional - if it's an anonymous post. Do
       
   681  *                                     not supply if supplying $author_id.
       
   682  *                                     Should have key 'bbp_author_ip'.
       
   683  *                                     Should be sanitized (see
       
   684  *                                     {@link bbp_filter_anonymous_post_data()}
       
   685  *                                     for sanitization)
       
   686  * @param int $author_id Optional. Supply if it's a post by a logged in user.
       
   687  *                        Do not supply if supplying $anonymous_data.
       
   688  * @uses get_option() To get the throttle time
       
   689  * @uses get_transient() To get the last posted transient of the ip
       
   690  * @uses bbp_get_user_last_posted() To get the last posted time of the user
       
   691  * @uses current_user_can() To check if the current user can throttle
       
   692  * @return bool True if there is no flooding, false if there is
       
   693  */
       
   694 function bbp_check_for_flood( $anonymous_data = false, $author_id = 0 ) {
       
   695 
       
   696 	// Option disabled. No flood checks.
       
   697 	$throttle_time = get_option( '_bbp_throttle_time' );
       
   698 	if ( empty( $throttle_time ) )
       
   699 		return true;
       
   700 
       
   701 	// User is anonymous, so check a transient based on the IP
       
   702 	if ( !empty( $anonymous_data ) && is_array( $anonymous_data ) ) {
       
   703 		$last_posted = get_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted' );
       
   704 
       
   705 		if ( !empty( $last_posted ) && time() < $last_posted + $throttle_time ) {
       
   706 			return false;
       
   707 		}
       
   708 		
       
   709 	// User is logged in, so check their last posted time
       
   710 	} elseif ( !empty( $author_id ) ) {
       
   711 		$author_id   = (int) $author_id;
       
   712 		$last_posted = bbp_get_user_last_posted( $author_id );
       
   713 
       
   714 		if ( isset( $last_posted ) && time() < $last_posted + $throttle_time && !current_user_can( 'throttle' ) ) {
       
   715 			return false;
       
   716 		}
       
   717 	} else {
       
   718 		return false;
       
   719 	}
       
   720 
       
   721 	return true;
       
   722 }
       
   723 
       
   724 /**
       
   725  * Checks topics and replies against the discussion moderation of blocked keys
       
   726  *
       
   727  * @since bbPress (r3581)
       
   728  *
       
   729  * @param array $anonymous_data Anonymous user data
       
   730  * @param int $author_id Topic or reply author ID
       
   731  * @param string $title The title of the content
       
   732  * @param string $content The content being posted
       
   733  * @uses is_super_admin() Allow super admins to bypass blacklist
       
   734  * @uses bbp_current_author_ip() To get current user IP address
       
   735  * @uses bbp_current_author_ua() To get current user agent
       
   736  * @return bool True if test is passed, false if fail
       
   737  */
       
   738 function bbp_check_for_moderation( $anonymous_data = false, $author_id = 0, $title = '', $content = '' ) {
       
   739 
       
   740 	// Bail if super admin is author
       
   741 	if ( is_super_admin( $author_id ) )
       
   742 		return true;
       
   743 
       
   744 	// Define local variable(s)
       
   745 	$_post     = array();
       
   746 	$match_out = '';
       
   747 
       
   748 	/** Blacklist *************************************************************/
       
   749 
       
   750 	// Get the moderation keys
       
   751 	$blacklist = trim( get_option( 'moderation_keys' ) );
       
   752 
       
   753 	// Bail if blacklist is empty
       
   754 	if ( empty( $blacklist ) )
       
   755 		return true;
       
   756 
       
   757 	/** User Data *************************************************************/
       
   758 
       
   759 	// Map anonymous user data
       
   760 	if ( !empty( $anonymous_data ) ) {
       
   761 		$_post['author'] = $anonymous_data['bbp_anonymous_name'];
       
   762 		$_post['email']  = $anonymous_data['bbp_anonymous_email'];
       
   763 		$_post['url']    = $anonymous_data['bbp_anonymous_website'];
       
   764 
       
   765 	// Map current user data
       
   766 	} elseif ( !empty( $author_id ) ) {
       
   767 
       
   768 		// Get author data
       
   769 		$user = get_userdata( $author_id );
       
   770 
       
   771 		// If data exists, map it
       
   772 		if ( !empty( $user ) ) {
       
   773 			$_post['author'] = $user->display_name;
       
   774 			$_post['email']  = $user->user_email;
       
   775 			$_post['url']    = $user->user_url;
       
   776 		}
       
   777 	}
       
   778 
       
   779 	// Current user IP and user agent
       
   780 	$_post['user_ip'] = bbp_current_author_ip();
       
   781 	$_post['user_ua'] = bbp_current_author_ua();
       
   782 
       
   783 	// Post title and content
       
   784 	$_post['title']   = $title;
       
   785 	$_post['content'] = $content;
       
   786 
       
   787 	/** Max Links *************************************************************/
       
   788 
       
   789 	$max_links = get_option( 'comment_max_links' );
       
   790 	if ( !empty( $max_links ) ) {
       
   791 
       
   792 		// How many links?
       
   793 		$num_links = preg_match_all( '/<a [^>]*href/i', $content, $match_out );
       
   794 
       
   795 		// Allow for bumping the max to include the user's URL
       
   796 		$num_links = apply_filters( 'comment_max_links_url', $num_links, $_post['url'] );
       
   797 
       
   798 		// Das ist zu viele links!
       
   799 		if ( $num_links >= $max_links ) {
       
   800 			return false;
       
   801 		}
       
   802 	}
       
   803 
       
   804 	/** Words *****************************************************************/
       
   805 
       
   806 	// Get words separated by new lines
       
   807 	$words = explode( "\n", $blacklist );
       
   808 
       
   809 	// Loop through words
       
   810 	foreach ( (array) $words as $word ) {
       
   811 
       
   812 		// Trim the whitespace from the word
       
   813 		$word = trim( $word );
       
   814 
       
   815 		// Skip empty lines
       
   816 		if ( empty( $word ) ) { continue; }
       
   817 
       
   818 		// Do some escaping magic so that '#' chars in the
       
   819 		// spam words don't break things:
       
   820 		$word    = preg_quote( $word, '#' );
       
   821 		$pattern = "#$word#i";
       
   822 
       
   823 		// Loop through post data
       
   824 		foreach( $_post as $post_data ) {
       
   825 
       
   826 			// Check each user data for current word
       
   827 			if ( preg_match( $pattern, $post_data ) ) {
       
   828 
       
   829 				// Post does not pass
       
   830 				return false;
       
   831 			}
       
   832 		}
       
   833 	}
       
   834 
       
   835 	// Check passed successfully
       
   836 	return true;
       
   837 }
       
   838 
       
   839 /**
       
   840  * Checks topics and replies against the discussion blacklist of blocked keys
       
   841  *
       
   842  * @since bbPress (r3446)
       
   843  *
       
   844  * @param array $anonymous_data Anonymous user data
       
   845  * @param int $author_id Topic or reply author ID
       
   846  * @param string $title The title of the content
       
   847  * @param string $content The content being posted
       
   848  * @uses is_super_admin() Allow super admins to bypass blacklist
       
   849  * @uses bbp_current_author_ip() To get current user IP address
       
   850  * @uses bbp_current_author_ua() To get current user agent
       
   851  * @return bool True if test is passed, false if fail
       
   852  */
       
   853 function bbp_check_for_blacklist( $anonymous_data = false, $author_id = 0, $title = '', $content = '' ) {
       
   854 
       
   855 	// Bail if super admin is author
       
   856 	if ( is_super_admin( $author_id ) )
       
   857 		return true;
       
   858 
       
   859 	// Define local variable
       
   860 	$_post = array();
       
   861 
       
   862 	/** Blacklist *************************************************************/
       
   863 
       
   864 	// Get the moderation keys
       
   865 	$blacklist = trim( get_option( 'blacklist_keys' ) );
       
   866 
       
   867 	// Bail if blacklist is empty
       
   868 	if ( empty( $blacklist ) )
       
   869 		return true;
       
   870 
       
   871 	/** User Data *************************************************************/
       
   872 
       
   873 	// Map anonymous user data
       
   874 	if ( !empty( $anonymous_data ) ) {
       
   875 		$_post['author'] = $anonymous_data['bbp_anonymous_name'];
       
   876 		$_post['email']  = $anonymous_data['bbp_anonymous_email'];
       
   877 		$_post['url']    = $anonymous_data['bbp_anonymous_website'];
       
   878 
       
   879 	// Map current user data
       
   880 	} elseif ( !empty( $author_id ) ) {
       
   881 
       
   882 		// Get author data
       
   883 		$user = get_userdata( $author_id );
       
   884 
       
   885 		// If data exists, map it
       
   886 		if ( !empty( $user ) ) {
       
   887 			$_post['author'] = $user->display_name;
       
   888 			$_post['email']  = $user->user_email;
       
   889 			$_post['url']    = $user->user_url;
       
   890 		}
       
   891 	}
       
   892 
       
   893 	// Current user IP and user agent
       
   894 	$_post['user_ip'] = bbp_current_author_ip();
       
   895 	$_post['user_ua'] = bbp_current_author_ua();
       
   896 
       
   897 	// Post title and content
       
   898 	$_post['title']   = $title;
       
   899 	$_post['content'] = $content;
       
   900 
       
   901 	/** Words *****************************************************************/
       
   902 
       
   903 	// Get words separated by new lines
       
   904 	$words = explode( "\n", $blacklist );
       
   905 
       
   906 	// Loop through words
       
   907 	foreach ( (array) $words as $word ) {
       
   908 
       
   909 		// Trim the whitespace from the word
       
   910 		$word = trim( $word );
       
   911 
       
   912 		// Skip empty lines
       
   913 		if ( empty( $word ) ) { continue; }
       
   914 
       
   915 		// Do some escaping magic so that '#' chars in the
       
   916 		// spam words don't break things:
       
   917 		$word    = preg_quote( $word, '#' );
       
   918 		$pattern = "#$word#i";
       
   919 
       
   920 		// Loop through post data
       
   921 		foreach( $_post as $post_data ) {
       
   922 
       
   923 			// Check each user data for current word
       
   924 			if ( preg_match( $pattern, $post_data ) ) {
       
   925 
       
   926 				// Post does not pass
       
   927 				return false;
       
   928 			}
       
   929 		}
       
   930 	}
       
   931 
       
   932 	// Check passed successfully
       
   933 	return true;
       
   934 }
       
   935 
       
   936 /** Subscriptions *************************************************************/
       
   937 
       
   938 /**
       
   939  * Sends notification emails for new posts
       
   940  *
       
   941  * Gets new post's ID and check if there are subscribed users to that topic, and
       
   942  * if there are, send notifications
       
   943  *
       
   944  * @since bbPress (r2668)
       
   945  *
       
   946  * @param int $reply_id ID of the newly made reply
       
   947  * @uses bbp_is_subscriptions_active() To check if the subscriptions are active
       
   948  * @uses bbp_get_reply_id() To validate the reply ID
       
   949  * @uses bbp_get_reply() To get the reply
       
   950  * @uses bbp_get_reply_topic_id() To get the topic ID of the reply
       
   951  * @uses bbp_is_reply_published() To make sure the reply is published
       
   952  * @uses bbp_get_topic_id() To validate the topic ID
       
   953  * @uses bbp_get_topic() To get the reply's topic
       
   954  * @uses bbp_is_topic_published() To make sure the topic is published
       
   955  * @uses get_the_author_meta() To get the author's display name
       
   956  * @uses do_action() Calls 'bbp_pre_notify_subscribers' with the reply id and
       
   957  *                    topic id
       
   958  * @uses bbp_get_topic_subscribers() To get the topic subscribers
       
   959  * @uses apply_filters() Calls 'bbp_subscription_mail_message' with the
       
   960  *                        message, reply id, topic id and user id
       
   961  * @uses get_userdata() To get the user data
       
   962  * @uses wp_mail() To send the mail
       
   963  * @uses do_action() Calls 'bbp_post_notify_subscribers' with the reply id
       
   964  *                    and topic id
       
   965  * @return bool True on success, false on failure
       
   966  */
       
   967 function bbp_notify_subscribers( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = false, $reply_author = 0 ) {
       
   968 
       
   969 	// Bail if subscriptions are turned off
       
   970 	if ( !bbp_is_subscriptions_active() )
       
   971 		return false;
       
   972 
       
   973 	/** Validation ************************************************************/
       
   974 
       
   975 	$reply_id = bbp_get_reply_id( $reply_id );
       
   976 	$topic_id = bbp_get_topic_id( $topic_id );
       
   977 	$forum_id = bbp_get_forum_id( $forum_id );
       
   978 
       
   979 	/** Reply *****************************************************************/
       
   980 
       
   981 	// Bail if reply is not published
       
   982 	if ( !bbp_is_reply_published( $reply_id ) )
       
   983 		return false;
       
   984 
       
   985 	/** Topic *****************************************************************/
       
   986 
       
   987 	// Bail if topic is not published
       
   988 	if ( !bbp_is_topic_published( $topic_id ) )
       
   989 		return false;
       
   990 
       
   991 	/** User ******************************************************************/
       
   992 
       
   993 	// Get subscribers and bail if empty
       
   994 	$user_ids = bbp_get_topic_subscribers( $topic_id, true );
       
   995 	if ( empty( $user_ids ) )
       
   996 		return false;
       
   997 
       
   998 	// Poster name
       
   999 	$reply_author_name = bbp_get_reply_author_display_name( $reply_id );
       
  1000 
       
  1001 	/** Mail ******************************************************************/
       
  1002 
       
  1003 	do_action( 'bbp_pre_notify_subscribers', $reply_id, $topic_id, $user_ids );
       
  1004 
       
  1005 	// Remove filters from reply content and topic title to prevent content
       
  1006 	// from being encoded with HTML entities, wrapped in paragraph tags, etc...
       
  1007 	remove_all_filters( 'bbp_get_reply_content' );
       
  1008 	remove_all_filters( 'bbp_get_topic_title'   );
       
  1009 
       
  1010 	// Strip tags from text
       
  1011 	$topic_title   = strip_tags( bbp_get_topic_title( $topic_id ) );
       
  1012 	$reply_content = strip_tags( bbp_get_reply_content( $reply_id ) );
       
  1013 	$reply_url     = bbp_get_reply_url( $reply_id );
       
  1014 	$blog_name     = get_option( 'blogname' );
       
  1015 
       
  1016 	// Loop through users
       
  1017 	foreach ( (array) $user_ids as $user_id ) {
       
  1018 
       
  1019 		// Don't send notifications to the person who made the post
       
  1020 		if ( !empty( $reply_author ) && (int) $user_id == (int) $reply_author )
       
  1021 			continue;
       
  1022 
       
  1023 		// For plugins to filter messages per reply/topic/user
       
  1024 		$message = sprintf( __( '%1$s wrote:
       
  1025 
       
  1026 %2$s
       
  1027 			
       
  1028 Post Link: %3$s
       
  1029 
       
  1030 -----------
       
  1031 
       
  1032 You are receiving this email because you subscribed to a forum topic.
       
  1033 
       
  1034 Login and visit the topic to unsubscribe from these emails.', 'bbpress' ),
       
  1035 				
       
  1036 			$reply_author_name,
       
  1037 			$reply_content,
       
  1038 			$reply_url
       
  1039 		);
       
  1040 
       
  1041 		$message = apply_filters( 'bbp_subscription_mail_message', $message, $reply_id, $topic_id, $user_id );
       
  1042 		if ( empty( $message ) )
       
  1043 			continue;
       
  1044 
       
  1045 		// For plugins to filter titles per reply/topic/user
       
  1046 		$subject = apply_filters( 'bbp_subscription_mail_title', '[' . $blog_name . '] ' . $topic_title, $reply_id, $topic_id, $user_id );
       
  1047 		if ( empty( $subject ) )
       
  1048 			continue;
       
  1049 
       
  1050 		// Custom headers
       
  1051 		$headers = apply_filters( 'bbp_subscription_mail_headers', array() );
       
  1052 
       
  1053 		// Get user data of this user
       
  1054 		$user = get_userdata( $user_id );
       
  1055 
       
  1056 		// Send notification email
       
  1057 		wp_mail( $user->user_email, $subject, $message, $headers );
       
  1058 	}
       
  1059 
       
  1060 	do_action( 'bbp_post_notify_subscribers', $reply_id, $topic_id, $user_ids );
       
  1061 
       
  1062 	return true;
       
  1063 }
       
  1064 
       
  1065 /** Login *********************************************************************/
       
  1066 
       
  1067 /**
       
  1068  * Return a clean and reliable logout URL
       
  1069  *
       
  1070  * @param string $url URL
       
  1071  * @param string $redirect_to Where to redirect to?
       
  1072  * @uses add_query_arg() To add args to the url
       
  1073  * @uses apply_filters() Calls 'bbp_logout_url' with the url and redirect to
       
  1074  * @return string The url
       
  1075  */
       
  1076 function bbp_logout_url( $url = '', $redirect_to = '' ) {
       
  1077 
       
  1078 	// Make sure we are directing somewhere
       
  1079 	if ( empty( $redirect_to ) && !strstr( $url, 'redirect_to' ) ) {
       
  1080 
       
  1081 		// Rejig the $redirect_to
       
  1082 		if ( !isset( $_SERVER['REDIRECT_URL'] ) || ( $redirect_to != home_url( $_SERVER['REDIRECT_URL'] ) ) ) {
       
  1083 			$redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : '';
       
  1084 		}
       
  1085 
       
  1086 		$redirect_to = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
       
  1087 
       
  1088 		// Sanitize $redirect_to and add it to full $url
       
  1089 		$redirect_to = add_query_arg( array( 'loggedout'   => 'true'                    ), esc_url( $redirect_to ) );
       
  1090 		$url         = add_query_arg( array( 'redirect_to' => urlencode( $redirect_to ) ), $url                    );
       
  1091 	}
       
  1092 
       
  1093 	// Filter and return
       
  1094 	return apply_filters( 'bbp_logout_url', $url, $redirect_to );
       
  1095 }
       
  1096 
       
  1097 /** Queries *******************************************************************/
       
  1098 
       
  1099 /**
       
  1100  * Merge user defined arguments into defaults array.
       
  1101  *
       
  1102  * This function is used throughout bbPress to allow for either a string or array
       
  1103  * to be merged into another array. It is identical to wp_parse_args() except
       
  1104  * it allows for arguments to be passively or aggressively filtered using the
       
  1105  * optional $filter_key parameter.
       
  1106  *
       
  1107  * @since bbPress (r3839)
       
  1108  *
       
  1109  * @param string|array $args Value to merge with $defaults
       
  1110  * @param array $defaults Array that serves as the defaults.
       
  1111  * @param string $filter_key String to key the filters from
       
  1112  * @return array Merged user defined values with defaults.
       
  1113  */
       
  1114 function bbp_parse_args( $args, $defaults = '', $filter_key = '' ) {
       
  1115 
       
  1116 	// Setup a temporary array from $args
       
  1117 	if ( is_object( $args ) )
       
  1118 		$r = get_object_vars( $args );
       
  1119 	elseif ( is_array( $args ) )
       
  1120 		$r =& $args;
       
  1121 	else
       
  1122 		wp_parse_str( $args, $r );
       
  1123 
       
  1124 	// Passively filter the args before the parse
       
  1125 	if ( !empty( $filter_key ) )
       
  1126 		$r = apply_filters( 'bbp_before_' . $filter_key . '_parse_args', $r );
       
  1127 
       
  1128 	// Parse
       
  1129 	if ( is_array( $defaults ) )
       
  1130 		$r = array_merge( $defaults, $r );
       
  1131 
       
  1132 	// Aggressively filter the args after the parse
       
  1133 	if ( !empty( $filter_key ) )
       
  1134 		$r = apply_filters( 'bbp_after_' . $filter_key . '_parse_args', $r );
       
  1135 
       
  1136 	// Return the parsed results
       
  1137 	return $r;
       
  1138 }
       
  1139 
       
  1140 /**
       
  1141  * Adds ability to include or exclude specific post_parent ID's
       
  1142  *
       
  1143  * @since bbPress (r2996)
       
  1144  *
       
  1145  * @global DB $wpdb
       
  1146  * @global WP $wp
       
  1147  * @param string $where
       
  1148  * @param WP_Query $object
       
  1149  * @return string
       
  1150  */
       
  1151 function bbp_query_post_parent__in( $where, $object = '' ) {
       
  1152 	global $wpdb, $wp;
       
  1153 
       
  1154 	// Noop if WP core supports this already
       
  1155 	if ( in_array( 'post_parent__in', $wp->private_query_vars ) )
       
  1156 		return $where;
       
  1157 
       
  1158 	// Bail if no object passed
       
  1159 	if ( empty( $object ) )
       
  1160 		return $where;
       
  1161 
       
  1162 	// Only 1 post_parent so return $where
       
  1163 	if ( is_numeric( $object->query_vars['post_parent'] ) )
       
  1164 		return $where;
       
  1165 
       
  1166 	// Including specific post_parent's
       
  1167 	if ( ! empty( $object->query_vars['post_parent__in'] ) ) {
       
  1168 		$ids    = implode( ',', array_map( 'absint', $object->query_vars['post_parent__in'] ) );
       
  1169 		$where .= " AND $wpdb->posts.post_parent IN ($ids)";
       
  1170 
       
  1171 	// Excluding specific post_parent's
       
  1172 	} elseif ( ! empty( $object->query_vars['post_parent__not_in'] ) ) {
       
  1173 		$ids    = implode( ',', array_map( 'absint', $object->query_vars['post_parent__not_in'] ) );
       
  1174 		$where .= " AND $wpdb->posts.post_parent NOT IN ($ids)";
       
  1175 	}
       
  1176 
       
  1177 	// Return possibly modified $where
       
  1178 	return $where;
       
  1179 }
       
  1180 
       
  1181 /**
       
  1182  * Query the DB and get the last public post_id that has parent_id as post_parent
       
  1183  *
       
  1184  * @param int $parent_id Parent id
       
  1185  * @param string $post_type Post type. Defaults to 'post'
       
  1186  * @uses bbp_get_topic_post_type() To get the topic post type
       
  1187  * @uses wp_cache_get() To check if there is a cache of the last child id
       
  1188  * @uses wpdb::prepare() To prepare the query
       
  1189  * @uses wpdb::get_var() To get the result of the query in a variable
       
  1190  * @uses wp_cache_set() To set the cache for future use
       
  1191  * @uses apply_filters() Calls 'bbp_get_public_child_last_id' with the child
       
  1192  *                        id, parent id and post type
       
  1193  * @return int The last active post_id
       
  1194  */
       
  1195 function bbp_get_public_child_last_id( $parent_id = 0, $post_type = 'post' ) {
       
  1196 	global $wpdb;
       
  1197 
       
  1198 	// Bail if nothing passed
       
  1199 	if ( empty( $parent_id ) )
       
  1200 		return false;
       
  1201 
       
  1202 	// The ID of the cached query
       
  1203 	$cache_id    = 'bbp_parent_' . $parent_id . '_type_' . $post_type . '_child_last_id';
       
  1204 	$post_status = array( bbp_get_public_status_id() );
       
  1205 
       
  1206 	// Add closed status if topic post type
       
  1207 	if ( $post_type == bbp_get_topic_post_type() )
       
  1208 		$post_status[] = bbp_get_closed_status_id();
       
  1209 
       
  1210 	// Join post statuses together
       
  1211 	$post_status = "'" . join( "', '", $post_status ) . "'";
       
  1212 
       
  1213 	// Check for cache and set if needed
       
  1214 	$child_id = wp_cache_get( $cache_id, 'bbpress' );
       
  1215 	if ( empty( $child_id ) ) {
       
  1216 		$child_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s' ORDER BY ID DESC LIMIT 1;", $parent_id, $post_type ) );
       
  1217 		wp_cache_set( $cache_id, $child_id, 'bbpress' );
       
  1218 	}
       
  1219 
       
  1220 	// Filter and return
       
  1221 	return apply_filters( 'bbp_get_public_child_last_id', (int) $child_id, (int) $parent_id, $post_type );
       
  1222 }
       
  1223 
       
  1224 /**
       
  1225  * Query the DB and get a count of public children
       
  1226  *
       
  1227  * @param int $parent_id Parent id
       
  1228  * @param string $post_type Post type. Defaults to 'post'
       
  1229  * @uses bbp_get_topic_post_type() To get the topic post type
       
  1230  * @uses wp_cache_get() To check if there is a cache of the children count
       
  1231  * @uses wpdb::prepare() To prepare the query
       
  1232  * @uses wpdb::get_var() To get the result of the query in a variable
       
  1233  * @uses wp_cache_set() To set the cache for future use
       
  1234  * @uses apply_filters() Calls 'bbp_get_public_child_count' with the child
       
  1235  *                        count, parent id and post type
       
  1236  * @return int The number of children
       
  1237  */
       
  1238 function bbp_get_public_child_count( $parent_id = 0, $post_type = 'post' ) {
       
  1239 	global $wpdb;
       
  1240 
       
  1241 	// Bail if nothing passed
       
  1242 	if ( empty( $parent_id ) )
       
  1243 		return false;
       
  1244 
       
  1245 	// The ID of the cached query
       
  1246 	$cache_id    = 'bbp_parent_' . $parent_id . '_type_' . $post_type . '_child_count';
       
  1247 	$post_status = array( bbp_get_public_status_id() );
       
  1248 
       
  1249 	// Add closed status if topic post type
       
  1250 	if ( $post_type == bbp_get_topic_post_type() )
       
  1251 		$post_status[] = bbp_get_closed_status_id();
       
  1252 
       
  1253 	// Join post statuses together
       
  1254 	$post_status = "'" . join( "', '", $post_status ) . "'";
       
  1255 
       
  1256 	// Check for cache and set if needed
       
  1257 	$child_count = wp_cache_get( $cache_id, 'bbpress' );
       
  1258 	if ( empty( $child_count ) ) {
       
  1259 		$child_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s';", $parent_id, $post_type ) );
       
  1260 		wp_cache_set( $cache_id, $child_count, 'bbpress' );
       
  1261 	}
       
  1262 
       
  1263 	// Filter and return
       
  1264 	return apply_filters( 'bbp_get_public_child_count', (int) $child_count, (int) $parent_id, $post_type );
       
  1265 }
       
  1266 
       
  1267 /**
       
  1268  * Query the DB and get a the child id's of public children
       
  1269  *
       
  1270  * @param int $parent_id Parent id
       
  1271  * @param string $post_type Post type. Defaults to 'post'
       
  1272  * @uses bbp_get_topic_post_type() To get the topic post type
       
  1273  * @uses wp_cache_get() To check if there is a cache of the children
       
  1274  * @uses wpdb::prepare() To prepare the query
       
  1275  * @uses wpdb::get_col() To get the result of the query in an array
       
  1276  * @uses wp_cache_set() To set the cache for future use
       
  1277  * @uses apply_filters() Calls 'bbp_get_public_child_ids' with the child ids,
       
  1278  *                        parent id and post type
       
  1279  * @return array The array of children
       
  1280  */
       
  1281 function bbp_get_public_child_ids( $parent_id = 0, $post_type = 'post' ) {
       
  1282 	global $wpdb;
       
  1283 
       
  1284 	// Bail if nothing passed
       
  1285 	if ( empty( $parent_id ) )
       
  1286 		return false;
       
  1287 
       
  1288 	// The ID of the cached query
       
  1289 	$cache_id    = 'bbp_parent_public_' . $parent_id . '_type_' . $post_type . '_child_ids';
       
  1290 	$post_status = array( bbp_get_public_status_id() );
       
  1291 
       
  1292 	// Add closed status if topic post type
       
  1293 	if ( $post_type == bbp_get_topic_post_type() )
       
  1294 		$post_status[] = bbp_get_closed_status_id();
       
  1295 
       
  1296 	// Join post statuses together
       
  1297 	$post_status = "'" . join( "', '", $post_status ) . "'";
       
  1298 
       
  1299 	// Check for cache and set if needed
       
  1300 	$child_ids = wp_cache_get( $cache_id, 'bbpress' );
       
  1301 	if ( empty( $child_ids ) ) {
       
  1302 		$child_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s' ORDER BY ID DESC;", $parent_id, $post_type ) );
       
  1303 		wp_cache_set( $cache_id, $child_ids, 'bbpress' );
       
  1304 	}
       
  1305 
       
  1306 	// Filter and return
       
  1307 	return apply_filters( 'bbp_get_public_child_ids', $child_ids, (int) $parent_id, $post_type );
       
  1308 }
       
  1309 /**
       
  1310  * Query the DB and get a the child id's of all children
       
  1311  *
       
  1312  * @param int $parent_id Parent id
       
  1313  * @param string $post_type Post type. Defaults to 'post'
       
  1314  * @uses bbp_get_topic_post_type() To get the topic post type
       
  1315  * @uses wp_cache_get() To check if there is a cache of the children
       
  1316  * @uses wpdb::prepare() To prepare the query
       
  1317  * @uses wpdb::get_col() To get the result of the query in an array
       
  1318  * @uses wp_cache_set() To set the cache for future use
       
  1319  * @uses apply_filters() Calls 'bbp_get_public_child_ids' with the child ids,
       
  1320  *                        parent id and post type
       
  1321  * @return array The array of children
       
  1322  */
       
  1323 function bbp_get_all_child_ids( $parent_id = 0, $post_type = 'post' ) {
       
  1324 	global $wpdb;
       
  1325 
       
  1326 	// Bail if nothing passed
       
  1327 	if ( empty( $parent_id ) )
       
  1328 		return false;
       
  1329 
       
  1330 	// The ID of the cached query
       
  1331 	$cache_id    = 'bbp_parent_all_' . $parent_id . '_type_' . $post_type . '_child_ids';
       
  1332 	$post_status = array( bbp_get_public_status_id() );
       
  1333 
       
  1334 	// Extra post statuses based on post type
       
  1335 	switch ( $post_type ) {
       
  1336 
       
  1337 		// Forum
       
  1338 		case bbp_get_forum_post_type() :
       
  1339 			$post_status[] = bbp_get_private_status_id();
       
  1340 			$post_status[] = bbp_get_hidden_status_id();
       
  1341 			break;
       
  1342 
       
  1343 		// Topic
       
  1344 		case bbp_get_topic_post_type() :
       
  1345 			$post_status[] = bbp_get_closed_status_id();
       
  1346 			$post_status[] = bbp_get_trash_status_id();
       
  1347 			$post_status[] = bbp_get_spam_status_id();
       
  1348 			break;
       
  1349 
       
  1350 		// Reply
       
  1351 		case bbp_get_reply_post_type() :
       
  1352 			$post_status[] = bbp_get_trash_status_id();
       
  1353 			$post_status[] = bbp_get_spam_status_id();
       
  1354 			break;
       
  1355 	}
       
  1356 
       
  1357 	// Join post statuses together
       
  1358 	$post_status = "'" . join( "', '", $post_status ) . "'";
       
  1359 
       
  1360 	// Check for cache and set if needed
       
  1361 	$child_ids = wp_cache_get( $cache_id, 'bbpress' );
       
  1362 	if ( empty( $child_ids ) ) {
       
  1363 		$child_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent = %d AND post_status IN ( {$post_status} ) AND post_type = '%s' ORDER BY ID DESC;", $parent_id, $post_type ) );
       
  1364 		wp_cache_set( $cache_id, $child_ids, 'bbpress' );
       
  1365 	}
       
  1366 
       
  1367 	// Filter and return
       
  1368 	return apply_filters( 'bbp_get_all_child_ids', $child_ids, (int) $parent_id, $post_type );
       
  1369 }
       
  1370 
       
  1371 /** Globals *******************************************************************/
       
  1372 
       
  1373 /**
       
  1374  * Get the unfiltered value of a global $post's key
       
  1375  *
       
  1376  * Used most frequently when editing a forum/topic/reply
       
  1377  *
       
  1378  * @since bbPress (r3694)
       
  1379  *
       
  1380  * @global WP_Query $post
       
  1381  * @param string $field Name of the key
       
  1382  * @param string $context How to sanitize - raw|edit|db|display|attribute|js
       
  1383  * @return string Field value
       
  1384  */
       
  1385 function bbp_get_global_post_field( $field = 'ID', $context = 'edit' ) {
       
  1386 	global $post;
       
  1387 
       
  1388 	$retval = isset( $post->$field ) ? $post->$field : '';
       
  1389 	$retval = sanitize_post_field( $field, $retval, $post->ID, $context );
       
  1390 
       
  1391 	return apply_filters( 'bbp_get_global_post_field', $retval, $post );
       
  1392 }
       
  1393 
       
  1394 /** Nonces ********************************************************************/
       
  1395 
       
  1396 /**
       
  1397  * Makes sure the user requested an action from another page on this site.
       
  1398  *
       
  1399  * To avoid security exploits within the theme.
       
  1400  *
       
  1401  * @since bbPress (r4022)
       
  1402  *
       
  1403  * @uses do_action() Calls 'bbp_check_referer' on $action.
       
  1404  * @param string $action Action nonce
       
  1405  * @param string $query_arg where to look for nonce in $_REQUEST
       
  1406  */
       
  1407 function bbp_verify_nonce_request( $action = '', $query_arg = '_wpnonce' ) {
       
  1408 
       
  1409 	// Get the home URL
       
  1410 	$home_url      = strtolower( home_url() );
       
  1411 
       
  1412 	// Build the currently requested URL
       
  1413 	$scheme        = is_ssl() ? 'https://' : 'http://';
       
  1414 	$requested_url = strtolower( $scheme . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
       
  1415 
       
  1416 	// Filter the requested URL, for configurations like reverse proxying
       
  1417 	$matched_url   = apply_filters( 'bbp_verify_nonce_request_url', $requested_url );
       
  1418 
       
  1419 	// Check the nonce
       
  1420 	$result = isset( $_REQUEST[$query_arg] ) ? wp_verify_nonce( $_REQUEST[$query_arg], $action ) : false;
       
  1421 
       
  1422 	// Nonce check failed
       
  1423 	if ( empty( $result ) || empty( $action ) || ( strpos( $matched_url, $home_url ) !== 0 ) )
       
  1424 		$result = false;
       
  1425 
       
  1426 	// Do extra things
       
  1427 	do_action( 'bbp_verify_nonce_request', $action, $result );
       
  1428 
       
  1429 	return $result;
       
  1430 }
       
  1431 
       
  1432 /** Feeds *********************************************************************/
       
  1433 
       
  1434 /**
       
  1435  * This function is hooked into the WordPress 'request' action and is
       
  1436  * responsible for sniffing out the query vars and serving up RSS2 feeds if
       
  1437  * the stars align and the user has requested a feed of any bbPress type.
       
  1438  *
       
  1439  * @since bbPress (r3171)
       
  1440  *
       
  1441  * @param array $query_vars
       
  1442  * @return array
       
  1443  */
       
  1444 function bbp_request_feed_trap( $query_vars = array() ) {
       
  1445 
       
  1446 	// Looking at a feed
       
  1447 	if ( isset( $query_vars['feed'] ) ) {
       
  1448 
       
  1449 		// Forum/Topic/Reply Feed
       
  1450 		if ( isset( $query_vars['post_type'] ) ) {
       
  1451 
       
  1452 			// What bbPress post type are we looking for feeds on?
       
  1453 			switch ( $query_vars['post_type'] ) {
       
  1454 
       
  1455 				// Forum
       
  1456 				case bbp_get_forum_post_type() :
       
  1457 
       
  1458 					// Define local variable(s)
       
  1459 					$meta_query = array();
       
  1460 
       
  1461 					// Single forum
       
  1462 					if ( isset( $query_vars[bbp_get_forum_post_type()] ) ) {
       
  1463 
       
  1464 						// Get the forum by the path
       
  1465 						$forum    = get_page_by_path( $query_vars[bbp_get_forum_post_type()], OBJECT, bbp_get_forum_post_type() );
       
  1466 						$forum_id = $forum->ID;
       
  1467 
       
  1468 						// Load up our own query
       
  1469 						query_posts( array(
       
  1470 							'post_type' => bbp_get_forum_post_type(),
       
  1471 							'ID'        => $forum_id,
       
  1472 							'feed'      => true
       
  1473 						) );
       
  1474 
       
  1475 						// Restrict to specific forum ID
       
  1476 						$meta_query = array( array(
       
  1477 							'key'     => '_bbp_forum_id',
       
  1478 							'value'   => $forum_id,
       
  1479 							'type'    => 'numeric',
       
  1480 							'compare' => '='
       
  1481 						) );
       
  1482 					}
       
  1483 
       
  1484 					// Only forum replies
       
  1485 					if ( !empty( $_GET['type'] ) && ( bbp_get_reply_post_type() == $_GET['type'] ) ) {
       
  1486 
       
  1487 						// The query
       
  1488 						$the_query = array(
       
  1489 							'author'         => 0,
       
  1490 							'feed'           => true,
       
  1491 							'post_type'      => bbp_get_reply_post_type(),
       
  1492 							'post_parent'    => 'any',
       
  1493 							'post_status'    => join( ',', array( bbp_get_public_status_id(), bbp_get_closed_status_id() ) ),
       
  1494 							'posts_per_page' => bbp_get_replies_per_rss_page(),
       
  1495 							'order'          => 'DESC',
       
  1496 							'meta_query'     => $meta_query
       
  1497 						);
       
  1498 
       
  1499 						// Output the feed
       
  1500 						bbp_display_replies_feed_rss2( $the_query );
       
  1501 
       
  1502 					// Only forum topics
       
  1503 					} elseif ( !empty( $_GET['type'] ) && ( bbp_get_topic_post_type() == $_GET['type'] ) ) {
       
  1504 
       
  1505 						// The query
       
  1506 						$the_query = array(
       
  1507 							'author'         => 0,
       
  1508 							'feed'           => true,
       
  1509 							'post_type'      => bbp_get_topic_post_type(),
       
  1510 							'post_parent'    => $forum_id,
       
  1511 							'post_status'    => join( ',', array( bbp_get_public_status_id(), bbp_get_closed_status_id() ) ),
       
  1512 							'posts_per_page' => bbp_get_topics_per_rss_page(),
       
  1513 							'order'          => 'DESC'
       
  1514 						);
       
  1515 
       
  1516 						// Output the feed
       
  1517 						bbp_display_topics_feed_rss2( $the_query );
       
  1518 
       
  1519 					// All forum topics and replies
       
  1520 					} else {
       
  1521 
       
  1522 						// Exclude private/hidden forums if not looking at single
       
  1523 						if ( empty( $query_vars['forum'] ) )
       
  1524 							$meta_query = array( bbp_exclude_forum_ids( 'meta_query' ) );
       
  1525 
       
  1526 						// The query
       
  1527 						$the_query = array(
       
  1528 							'author'         => 0,
       
  1529 							'feed'           => true,
       
  1530 							'post_type'      => array( bbp_get_reply_post_type(), bbp_get_topic_post_type() ),
       
  1531 							'post_parent'    => 'any',
       
  1532 							'post_status'    => join( ',', array( bbp_get_public_status_id(), bbp_get_closed_status_id() ) ),
       
  1533 							'posts_per_page' => bbp_get_replies_per_rss_page(),
       
  1534 							'order'          => 'DESC',
       
  1535 							'meta_query'     => $meta_query
       
  1536 						);
       
  1537 
       
  1538 						// Output the feed
       
  1539 						bbp_display_replies_feed_rss2( $the_query );
       
  1540 					}
       
  1541 
       
  1542 					break;
       
  1543 
       
  1544 				// Topic feed - Show replies
       
  1545 				case bbp_get_topic_post_type() :
       
  1546 
       
  1547 					// Single topic
       
  1548 					if ( isset( $query_vars[bbp_get_topic_post_type()] ) ) {
       
  1549 
       
  1550 						// Load up our own query
       
  1551 						query_posts( array(
       
  1552 							'post_type' => bbp_get_topic_post_type(),
       
  1553 							'name'      => $query_vars[bbp_get_topic_post_type()],
       
  1554 							'feed'      => true
       
  1555 						) );
       
  1556 
       
  1557 						// Output the feed
       
  1558 						bbp_display_replies_feed_rss2( array( 'feed' => true ) );
       
  1559 
       
  1560 					// All topics
       
  1561 					} else {
       
  1562 
       
  1563 						// The query
       
  1564 						$the_query = array(
       
  1565 							'author'         => 0,
       
  1566 							'feed'           => true,
       
  1567 							'post_parent'    => 'any',
       
  1568 							'posts_per_page' => bbp_get_topics_per_rss_page(),
       
  1569 							'show_stickies'  => false
       
  1570 						);
       
  1571 
       
  1572 						// Output the feed
       
  1573 						bbp_display_topics_feed_rss2( $the_query );
       
  1574 					}
       
  1575 
       
  1576 					break;
       
  1577 
       
  1578 				// Replies
       
  1579 				case bbp_get_reply_post_type() :
       
  1580 
       
  1581 					// The query
       
  1582 					$the_query = array(
       
  1583 						'posts_per_page' => bbp_get_replies_per_rss_page(),
       
  1584 						'meta_query'     => array( array( ) ),
       
  1585 						'feed'           => true
       
  1586 					);
       
  1587 
       
  1588 					// All replies
       
  1589 					if ( !isset( $query_vars[bbp_get_reply_post_type()] ) ) {
       
  1590 						bbp_display_replies_feed_rss2( $the_query );
       
  1591 					}
       
  1592 
       
  1593 					break;
       
  1594 			}
       
  1595 
       
  1596 		// Single Topic Vview
       
  1597 		} elseif ( isset( $query_vars['bbp_view'] ) ) {
       
  1598 
       
  1599 			// Get the view
       
  1600 			$view = $query_vars['bbp_view'];
       
  1601 
       
  1602 			// We have a view to display a feed
       
  1603 			if ( !empty( $view ) ) {
       
  1604 
       
  1605 				// Get the view query
       
  1606 				$the_query = bbp_get_view_query_args( $view );
       
  1607 
       
  1608 				// Output the feed
       
  1609 				bbp_display_topics_feed_rss2( $the_query );
       
  1610 			}
       
  1611 		}
       
  1612 
       
  1613 		// @todo User profile feeds
       
  1614 	}
       
  1615 
       
  1616 	// No feed so continue on
       
  1617 	return $query_vars;
       
  1618 }
       
  1619 
       
  1620 /** Templates ******************************************************************/
       
  1621 
       
  1622 /**
       
  1623  * Used to guess if page exists at requested path
       
  1624  *
       
  1625  * @since bbPress (r3304)
       
  1626  *
       
  1627  * @uses get_option() To see if pretty permalinks are enabled
       
  1628  * @uses get_page_by_path() To see if page exists at path
       
  1629  *
       
  1630  * @param string $path
       
  1631  * @return mixed False if no page, Page object if true
       
  1632  */
       
  1633 function bbp_get_page_by_path( $path = '' ) {
       
  1634 
       
  1635 	// Default to false
       
  1636 	$retval = false;
       
  1637 
       
  1638 	// Path is not empty
       
  1639 	if ( !empty( $path ) ) {
       
  1640 
       
  1641 		// Pretty permalinks are on so path might exist
       
  1642 		if ( get_option( 'permalink_structure' ) ) {
       
  1643 			$retval = get_page_by_path( $path );
       
  1644 		}
       
  1645 	}
       
  1646 
       
  1647 	return apply_filters( 'bbp_get_page_by_path', $retval, $path );
       
  1648 }
       
  1649 
       
  1650 /**
       
  1651  * Sets the 404 status.
       
  1652  *
       
  1653  * Used primarily with topics/replies inside hidden forums.
       
  1654  *
       
  1655  * @since bbPress (r3051)
       
  1656  *
       
  1657  * @global WP_Query $wp_query
       
  1658  * @uses WP_Query::set_404()
       
  1659  */
       
  1660 function bbp_set_404() {
       
  1661 	global $wp_query;
       
  1662 
       
  1663 	if ( ! isset( $wp_query ) ) {
       
  1664 		_doing_it_wrong( __FUNCTION__, __( 'Conditional query tags do not work before the query is run. Before then, they always return false.', 'bbpress' ), '3.1' );
       
  1665 		return false;
       
  1666 	}
       
  1667 
       
  1668 	$wp_query->set_404();
       
  1669 }