# bbp-core/2.4.1/widgets/Forumax_Active_Members.php

Forumax – AI Powered Advanced Community Forum Plugin, version 2.4.1. 250 lines.

- Page: https://pluginprobe.com/plugins/bbp-core/2.4.1/code/widgets/Forumax_Active_Members.php
- Raw: https://pluginprobe.com/plugins/bbp-core/2.4.1/raw/widgets/Forumax_Active_Members.php
- Modified: 2026-06-13T02:52:04+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.4.1/code/widgets/Forumax_Active_Members.php#L10-L20`.

```php
<?php
namespace Forumax\WpWidgets;

use WP_Widget;

/**
 * Class Forumax_Active_Members
 * Displays a list of recently active members who participated in the current topic.
 * This widget is only visible on single topic pages.
 *
 * @package Forumax\WpWidgets
 */
class Forumax_Active_Members extends WP_Widget {

	/**
	 * Forumax Active Members Widget
	 *
	 * Registers the active members widget.
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'forumax_active_members_widget_options', array(
			'classname'                   => 'forumax_active_members_widget',
			'description'                 => esc_html__( 'Displays members who participated in the current topic. Only visible on single topic pages.', 'forumax' ),
			'customize_selective_refresh' => true,
		) );

		parent::__construct(
			'forumax_active_members',
			esc_html__( '(Forumax) Active Members', 'forumax' ),
			$widget_ops
		);
	}

	/**
	 * Register the widget.
	 */
	public static function register_widget() {
		register_widget( __CLASS__ );
	}

	/**
	 * Displays the output — list of active members in the current topic.
	 *
	 * Only renders on single topic pages. On all other pages,
	 * the widget silently returns without any output.
	 *
	 * @param array $args     Widget display arguments.
	 * @param array $instance Widget instance settings.
	 */
	public function widget( $args = array(), $instance = array() ) {

		wp_enqueue_style( 'bbpc-forum' );

		// Only display on single topic pages.
		if ( ! function_exists( 'bbp_is_single_topic' ) || ! bbp_is_single_topic() ) {
			return;
		}

		$topic_id = bbp_get_topic_id();

		if ( empty( $topic_id ) ) {
			return;
		}

		// Get widget settings.
		$settings = $this->parse_settings( $instance );

		// Apply standard WordPress title filter.
		$settings['title'] = apply_filters( 'widget_title', $settings['title'], $instance, $this->id_base );

		// Forumax-specific filter.
		$settings['title'] = apply_filters( 'forumax_active_members_widget_title', $settings['title'], $instance, $this->id_base );

		// Fetch unique participant user IDs for this topic.
		$member_ids = $this->get_topic_participants( $topic_id, (int) $settings['max_shown'] );

		// Bail if no participants found.
		if ( empty( $member_ids ) ) {
			return;
		}

		$avatar_size = absint( $settings['avatar_size'] );

		echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		}
		?>

		<ul class="frmx-active-members frmx-list-unstyled">

			<?php foreach ( $member_ids as $user_id ) :
				$user = get_userdata( $user_id );

				if ( ! $user ) {
					continue;
				}

				$profile_url  = function_exists( 'bbp_get_user_profile_url' )
					? bbp_get_user_profile_url( $user_id )
					: get_author_posts_url( $user_id );
				$display_name = $user->display_name;
				?>

				<li class="frmx-active-member-item" data-frmx-tooltip="<?php echo esc_attr( $display_name ); ?>">
					<a href="<?php echo esc_url( $profile_url ); ?>"
						class="frmx-active-member-link"
						style="width: <?php echo esc_attr( $avatar_size ); ?>px; height: <?php echo esc_attr( $avatar_size ); ?>px;">
						<?php echo get_avatar( $user_id, $avatar_size ); ?>
					</a>
				</li>

			<?php endforeach; ?>

		</ul>

		<?php
		echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}

	/**
	 * Get unique participant IDs for a given topic.
	 *
	 * Combines the topic author with reply authors, returns unique IDs
	 * ordered by most recent activity (latest reply first).
	 *
	 * @param int $topic_id  The topic ID.
	 * @param int $max_shown Maximum number of members to return.
	 * @return array Array of unique user IDs.
	 */
	private function get_topic_participants( $topic_id, $max_shown ) {
		global $wpdb;

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$results = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT DISTINCT post_author
				FROM {$wpdb->posts}
				WHERE post_parent = %d
				AND post_type = %s
				AND post_status IN ( 'publish', 'closed' )
				ORDER BY post_date DESC",
				$topic_id,
				bbp_get_reply_post_type()
			)
		);

		// Include the topic author at the beginning.
		$topic_author = get_post_field( 'post_author', $topic_id );

		if ( ! empty( $topic_author ) ) {
			// Remove topic author from results if already present, then prepend.
			$results = array_diff( $results, array( $topic_author ) );
			array_unshift( $results, $topic_author );
		}

		// Remove invalid (0) IDs and limit.
		$results = array_filter( $results );
		$results = array_slice( $results, 0, $max_shown );

		return array_map( 'absint', $results );
	}

	/**
	 * Update the widget options.
	 *
	 * @param array $new_instance The new instance options.
	 * @param array $old_instance The old instance options.
	 * @return array Updated instance.
	 */
	public function update( $new_instance = array(), $old_instance = array() ) {
		$instance                = $old_instance;
		$instance['title']       = strip_tags( $new_instance['title'] );
		$instance['max_shown']   = (int) $new_instance['max_shown'];
		$instance['avatar_size'] = absint( $new_instance['avatar_size'] );

		return $instance;
	}

	/**
	 * Output the widget options form.
	 *
	 * @param array $instance Current widget instance settings.
	 */
	public function form( $instance = array() ) {

		// Get widget settings.
		$settings = $this->parse_settings( $instance );
		?>

		<p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
				<?php esc_html_e( 'Title:', 'forumax' ); ?>
				<input class="widefat"
					id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
					name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
					type="text"
					value="<?php echo esc_attr( $settings['title'] ); ?>" />
			</label>
		</p>

		<p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'max_shown' ) ); ?>">
				<?php esc_html_e( 'Maximum members to show:', 'forumax' ); ?>
				<input class="widefat"
					id="<?php echo esc_attr( $this->get_field_id( 'max_shown' ) ); ?>"
					name="<?php echo esc_attr( $this->get_field_name( 'max_shown' ) ); ?>"
					type="number"
					min="1"
					max="50"
					value="<?php echo esc_attr( $settings['max_shown'] ); ?>" />
			</label>
		</p>

		<p>
			<label for="<?php echo esc_attr( $this->get_field_id( 'avatar_size' ) ); ?>">
				<?php esc_html_e( 'Avatar size (px):', 'forumax' ); ?>
				<input class="widefat"
					id="<?php echo esc_attr( $this->get_field_id( 'avatar_size' ) ); ?>"
					name="<?php echo esc_attr( $this->get_field_name( 'avatar_size' ) ); ?>"
					type="number"
					min="16"
					max="96"
					value="<?php echo esc_attr( $settings['avatar_size'] ); ?>" />
			</label>
		</p>

		<p>
			<small><?php esc_html_e( 'This widget is only visible on single topic pages.', 'forumax' ); ?></small>
		</p>

		<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @param array $instance Current instance settings.
	 * @return array Parsed settings with defaults applied.
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title'       => esc_html__( 'Active Members', 'forumax' ),
			'max_shown'   => 8,
			'avatar_size' => 60,
		), 'forumax_active_members_widget_settings' );
	}
}

```
