PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.5.1
Forumax – AI Powered Advanced Community Forum Plugin v2.5.1
2.5.1 2.5.0 2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 trunk 1.0.8 1.1.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 All 31 releases
bbp-core / widgets / Forumax_Active_Members.php

Forumax_Active_Members.php in Forumax – AI Powered Advanced Community Forum Plugin 2.5.1, at widgets/Forumax_Active_Members.php

255 lines 7.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Forumax\WpWidgets;
3
4 use WP_Widget;
5
6 /**
7 * Class Forumax_Active_Members
8 * Displays a list of recently active members who participated in the current topic.
9 * This widget is only visible on single topic pages.
10 *
11 * @package Forumax\WpWidgets
12 */
13 class Forumax_Active_Members extends WP_Widget {
14
15 /**
16 * Forumax Active Members Widget
17 *
18 * Registers the active members widget.
19 */
20 public function __construct() {
21 $widget_ops = apply_filters( 'forumax_active_members_widget_options', array(
22 'classname' => 'forumax_active_members_widget',
23 'description' => esc_html__( 'Displays members who participated in the current topic. Only visible on single topic pages.', 'forumax' ),
24 'customize_selective_refresh' => true,
25 ) );
26
27 parent::__construct(
28 'forumax_active_members',
29 esc_html__( '(Forumax) Active Members', 'forumax' ),
30 $widget_ops
31 );
32 }
33
34 /**
35 * Register the widget.
36 */
37 public static function register_widget() {
38 register_widget( __CLASS__ );
39 }
40
41 /**
42 * Displays the output — list of active members in the current topic.
43 *
44 * Only renders on single topic pages. On all other pages,
45 * the widget silently returns without any output.
46 *
47 * @param array $args Widget display arguments.
48 * @param array $instance Widget instance settings.
49 */
50 public function widget( $args = array(), $instance = array() ) {
51
52 wp_enqueue_style( 'bbpc-forum' );
53
54 // Only display on single topic pages.
55 if ( ! function_exists( 'bbp_is_single_topic' ) || ! bbp_is_single_topic() ) {
56 return;
57 }
58
59 $topic_id = bbp_get_topic_id();
60
61 if ( empty( $topic_id ) ) {
62 return;
63 }
64
65 // Get widget settings.
66 $settings = $this->parse_settings( $instance );
67
68 // Apply standard WordPress title filter.
69 $settings['title'] = apply_filters( 'widget_title', $settings['title'], $instance, $this->id_base );
70
71 // Forumax-specific filter.
72 $settings['title'] = apply_filters( 'forumax_active_members_widget_title', $settings['title'], $instance, $this->id_base );
73
74 // Fetch unique participant user IDs for this topic.
75 $member_ids = $this->get_topic_participants( $topic_id, (int) $settings['max_shown'] );
76
77 // Bail if no participants found.
78 if ( empty( $member_ids ) ) {
79 return;
80 }
81
82 $avatar_size = absint( $settings['avatar_size'] );
83
84 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
85
86 if ( ! empty( $settings['title'] ) ) {
87 echo $args['before_title'] . $settings['title'] . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
88 }
89 ?>
90
91 <ul class="frmx-active-members frmx-list-unstyled">
92
93 <?php foreach ( $member_ids as $user_id ) :
94 $user = get_userdata( $user_id );
95
96 if ( ! $user ) {
97 continue;
98 }
99
100 $profile_url = function_exists( 'bbp_get_user_profile_url' )
101 ? bbp_get_user_profile_url( $user_id )
102 : get_author_posts_url( $user_id );
103 $display_name = $user->display_name;
104 ?>
105
106 <li class="frmx-active-member-item" data-frmx-tooltip="<?php echo esc_attr( $display_name ); ?>">
107 <a href="<?php echo esc_url( $profile_url ); ?>"
108 class="frmx-active-member-link"
109 style="width: <?php echo esc_attr( $avatar_size ); ?>px; height: <?php echo esc_attr( $avatar_size ); ?>px;">
110 <?php echo get_avatar( $user_id, $avatar_size ); ?>
111 </a>
112 </li>
113
114 <?php endforeach; ?>
115
116 </ul>
117
118 <?php
119 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
120 }
121
122 /**
123 * Get unique participant IDs for a given topic.
124 *
125 * Combines the topic author with reply authors, returns unique IDs
126 * ordered by most recent activity (latest reply first).
127 *
128 * @param int $topic_id The topic ID.
129 * @param int $max_shown Maximum number of members to return.
130 * @return array Array of unique user IDs.
131 */
132 private function get_topic_participants( $topic_id, $max_shown ) {
133 global $wpdb;
134
135 // GROUP BY + MAX() instead of DISTINCT ... ORDER BY post_date, which
136 // MySQL 5.7+/8 rejects (ORDER BY column not in the SELECT list).
137 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
138 $results = $wpdb->get_col(
139 $wpdb->prepare(
140 "SELECT post_author
141 FROM {$wpdb->posts}
142 WHERE post_parent = %d
143 AND post_type = %s
144 AND post_status IN ( 'publish', 'closed' )
145 GROUP BY post_author
146 ORDER BY MAX( post_date ) DESC
147 LIMIT %d",
148 $topic_id,
149 bbp_get_reply_post_type(),
150 $max_shown > 0 ? $max_shown + 1 : 1000
151 )
152 );
153
154 // Include the topic author at the beginning.
155 $topic_author = get_post_field( 'post_author', $topic_id );
156
157 if ( ! empty( $topic_author ) ) {
158 // Remove topic author from results if already present, then prepend.
159 $results = array_diff( $results, array( $topic_author ) );
160 array_unshift( $results, $topic_author );
161 }
162
163 // Remove invalid (0) IDs and limit.
164 $results = array_filter( $results );
165 $results = array_slice( $results, 0, $max_shown );
166
167 return array_map( 'absint', $results );
168 }
169
170 /**
171 * Update the widget options.
172 *
173 * @param array $new_instance The new instance options.
174 * @param array $old_instance The old instance options.
175 * @return array Updated instance.
176 */
177 public function update( $new_instance = array(), $old_instance = array() ) {
178 $instance = $old_instance;
179 $instance['title'] = strip_tags( $new_instance['title'] );
180 $instance['max_shown'] = (int) $new_instance['max_shown'];
181 $instance['avatar_size'] = absint( $new_instance['avatar_size'] );
182
183 return $instance;
184 }
185
186 /**
187 * Output the widget options form.
188 *
189 * @param array $instance Current widget instance settings.
190 */
191 public function form( $instance = array() ) {
192
193 // Get widget settings.
194 $settings = $this->parse_settings( $instance );
195 ?>
196
197 <p>
198 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
199 <?php esc_html_e( 'Title:', 'forumax' ); ?>
200 <input class="widefat"
201 id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
202 name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
203 type="text"
204 value="<?php echo esc_attr( $settings['title'] ); ?>" />
205 </label>
206 </p>
207
208 <p>
209 <label for="<?php echo esc_attr( $this->get_field_id( 'max_shown' ) ); ?>">
210 <?php esc_html_e( 'Maximum members to show:', 'forumax' ); ?>
211 <input class="widefat"
212 id="<?php echo esc_attr( $this->get_field_id( 'max_shown' ) ); ?>"
213 name="<?php echo esc_attr( $this->get_field_name( 'max_shown' ) ); ?>"
214 type="number"
215 min="1"
216 max="50"
217 value="<?php echo esc_attr( $settings['max_shown'] ); ?>" />
218 </label>
219 </p>
220
221 <p>
222 <label for="<?php echo esc_attr( $this->get_field_id( 'avatar_size' ) ); ?>">
223 <?php esc_html_e( 'Avatar size (px):', 'forumax' ); ?>
224 <input class="widefat"
225 id="<?php echo esc_attr( $this->get_field_id( 'avatar_size' ) ); ?>"
226 name="<?php echo esc_attr( $this->get_field_name( 'avatar_size' ) ); ?>"
227 type="number"
228 min="16"
229 max="96"
230 value="<?php echo esc_attr( $settings['avatar_size'] ); ?>" />
231 </label>
232 </p>
233
234 <p>
235 <small><?php esc_html_e( 'This widget is only visible on single topic pages.', 'forumax' ); ?></small>
236 </p>
237
238 <?php
239 }
240
241 /**
242 * Merge the widget settings into defaults array.
243 *
244 * @param array $instance Current instance settings.
245 * @return array Parsed settings with defaults applied.
246 */
247 public function parse_settings( $instance = array() ) {
248 return bbp_parse_args( $instance, array(
249 'title' => esc_html__( 'Active Members', 'forumax' ),
250 'max_shown' => 8,
251 'avatar_size' => 60,
252 ), 'forumax_active_members_widget_settings' );
253 }
254 }
255