# bbp-core/2.5.0/includes/topic-render-guard.php

Forumax – AI Powered Advanced Community Forum Plugin, version 2.5.0. 220 lines.

- Page: https://pluginprobe.com/plugins/bbp-core/2.5.0/code/includes/topic-render-guard.php
- Raw: https://pluginprobe.com/plugins/bbp-core/2.5.0/raw/includes/topic-render-guard.php
- Modified: 2026-10-06T10:18:02+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/bbp-core/2.5.0/code/includes/topic-render-guard.php#L10-L20`.

```php
<?php
/**
 * Single-topic render guards.
 *
 * Theme-compat runs display_topic() during template_include. If
 * bbp_is_single_topic() is false at that moment, bbp_has_replies() defaults
 * to post_parent=any and can load every topic and reply. Capability mapping
 * then fans out until PHP hits the memory limit.
 *
 * @package Forumax
 */

defined( 'ABSPATH' ) || exit;

/**
 * Resolve the topic being rendered, without calling bbp_is_single_topic().
 *
 * @return int Topic ID or 0.
 */
function forumax_resolve_current_topic_id() {
	if ( function_exists( 'bbpress' ) ) {
		$current = (int) bbpress()->current_topic_id;
		if ( $current > 0 ) {
			return $current;
		}
	}

	$object = get_queried_object();
	if ( $object instanceof WP_Post && function_exists( 'bbp_get_topic_post_type' ) && bbp_get_topic_post_type() === $object->post_type ) {
		return (int) $object->ID;
	}

	return 0;
}

/**
 * Seed current_topic_id as soon as the main query is a topic.
 *
 * @return void
 */
function forumax_prime_current_topic_id() {
	if ( ! function_exists( 'bbpress' ) || ! function_exists( 'bbp_get_topic_post_type' ) ) {
		return;
	}

	if ( ! empty( bbpress()->current_topic_id ) ) {
		return;
	}

	if ( is_singular( bbp_get_topic_post_type() ) ) {
		$topic_id = (int) get_queried_object_id();
		if ( $topic_id > 0 ) {
			bbpress()->current_topic_id = $topic_id;
		}
	}
}
add_action( 'wp', 'forumax_prime_current_topic_id', 1 );

/**
 * Treat a primed topic ID as a single-topic view.
 *
 * @param bool $is_single_topic Current detection result.
 * @return bool
 */
function forumax_filter_is_single_topic( $is_single_topic ) {
	if ( $is_single_topic ) {
		return true;
	}

	if ( function_exists( 'bbp_is_topic_edit' ) && bbp_is_topic_edit() ) {
		return false;
	}

	return forumax_resolve_current_topic_id() > 0;
}
add_filter( 'bbp_is_single_topic', 'forumax_filter_is_single_topic' );

/**
 * Fall back to the primed / queried topic when bbPress cannot resolve one.
 *
 * @param int $topic_id   Resolved topic ID.
 * @param int $requested  ID passed into bbp_get_topic_id().
 * @return int
 */
function forumax_filter_get_topic_id( $topic_id, $requested ) {
	if ( ! empty( $requested ) && is_numeric( $requested ) ) {
		return (int) $topic_id;
	}

	if ( (int) $topic_id > 0 ) {
		return (int) $topic_id;
	}

	return forumax_resolve_current_topic_id();
}
add_filter( 'bbp_get_topic_id', 'forumax_filter_get_topic_id', 10, 2 );

/**
 * Never run an unscoped replies query while a topic is being rendered.
 *
 * User-profile and author queries keep post_parent=any. Hierarchical
 * site-wide queries are also refused so posts_per_page cannot become -1.
 *
 * @param array $args Reply query args after parse.
 * @return array
 */
function forumax_scope_has_replies_query( $args ) {
	if ( ! is_array( $args ) ) {
		return $args;
	}

	$explicit_parent = isset( $args['post_parent'] ) && is_numeric( $args['post_parent'] ) && (int) $args['post_parent'] > 0;
	$is_author_query = ! empty( $args['author'] ) || ! empty( $args['author__in'] );
	$is_id_query     = ! empty( $args['post__in'] ) || ! empty( $args['post__not_in'] );

	if ( ! $explicit_parent && ! $is_author_query && ! $is_id_query ) {
		$topic_id = forumax_resolve_current_topic_id();
		if ( $topic_id > 0 ) {
			$args['post_parent'] = $topic_id;
		}
	}

	$parent = isset( $args['post_parent'] ) ? $args['post_parent'] : '';
	if ( ! empty( $args['hierarchical'] ) && ( ! is_numeric( $parent ) || (int) $parent < 1 ) ) {
		$args['hierarchical'] = false;
		if ( isset( $args['posts_per_page'] ) && (int) $args['posts_per_page'] < 1 ) {
			$args['posts_per_page'] = function_exists( 'bbp_get_replies_per_page' ) ? (int) bbp_get_replies_per_page() : 20;
		}
	}

	return $args;
}
add_filter( 'bbp_has_replies_query', 'forumax_scope_has_replies_query', 1 );

/**
 * Build a cache key fragment for a map_meta_cap argument.
 *
 * Gutenberg passes objects such as WP_Block_Editor_Context. Those cannot be
 * cast with strval() and must not fatal the post editor.
 *
 * @param mixed $arg Raw map_meta_cap argument.
 * @return string
 */
function forumax_map_meta_cap_arg_fragment( $arg ) {
	if ( is_null( $arg ) || is_bool( $arg ) || is_int( $arg ) || is_float( $arg ) || is_string( $arg ) ) {
		return (string) $arg;
	}

	if ( is_object( $arg ) ) {
		return get_class( $arg ) . '#' . spl_object_id( $arg );
	}

	if ( is_array( $arg ) ) {
		$parts = array();
		foreach ( $arg as $key => $value ) {
			$parts[] = forumax_map_meta_cap_arg_fragment( $key ) . '=' . forumax_map_meta_cap_arg_fragment( $value );
		}

		return '[' . implode( ',', $parts ) . ']';
	}

	return gettype( $arg );
}

/**
 * Cache bbPress meta-cap maps for the current request and break re-entry.
 *
 * The bundled mappers call user_can() from inside map_meta_cap. On a topic
 * page that repeats the same checks per reply/admin link until memory dies.
 *
 * @param string[] $caps    Primitive caps.
 * @param string   $cap     Meta capability.
 * @param int      $user_id User ID.
 * @param array    $args    Extra arguments (usually a post ID).
 * @return string[]
 */
function forumax_cache_bbp_map_meta_caps( $caps, $cap, $user_id, $args ) {
	static $cache = array();
	static $stack = array();

	$arg_key = '';
	if ( ! empty( $args ) && is_array( $args ) ) {
		$arg_key = implode( ',', array_map( 'forumax_map_meta_cap_arg_fragment', $args ) );
	}

	$key = (int) $user_id . '|' . (string) $cap . '|' . $arg_key;

	if ( isset( $cache[ $key ] ) ) {
		return $cache[ $key ];
	}

	// Same cap is already being mapped further up the stack.
	if ( isset( $stack[ $key ] ) ) {
		return $caps;
	}

	$stack[ $key ] = true;
	$mapped        = bbp_map_meta_caps( $caps, $cap, $user_id, $args );
	unset( $stack[ $key ] );

	$cache[ $key ] = $mapped;

	return $mapped;
}

/**
 * Replace the stock bbPress map_meta_cap aggregator with a cached wrapper.
 *
 * @return void
 */
function forumax_install_map_meta_cap_cache() {
	if ( ! function_exists( 'bbp_map_meta_caps' ) ) {
		return;
	}

	remove_filter( 'map_meta_cap', 'bbp_map_meta_caps', 10 );
	add_filter( 'map_meta_cap', 'forumax_cache_bbp_map_meta_caps', 10, 4 );
}
forumax_install_map_meta_cap_cache();

```
