PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.4.0
Forumax – AI Powered Advanced Community Forum Plugin v2.4.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 2.0.0 2.1.0 All 29 releases
bbp-core / widgets / Forumax_Active_Members.php

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

248 lines 7.3 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 // Only display on single topic pages.
53 if ( ! function_exists( 'bbp_is_single_topic' ) || ! bbp_is_single_topic() ) {
54 return;
55 }
56
57 $topic_id = bbp_get_topic_id();
58
59 if ( empty( $topic_id ) ) {
60 return;
61 }
62
63 // Get widget settings.
64 $settings = $this->parse_settings( $instance );
65
66 // Apply standard WordPress title filter.
67 $settings['title'] = apply_filters( 'widget_title', $settings['title'], $instance, $this->id_base );
68
69 // Forumax-specific filter.
70 $settings['title'] = apply_filters( 'forumax_active_members_widget_title', $settings['title'], $instance, $this->id_base );
71
72 // Fetch unique participant user IDs for this topic.
73 $member_ids = $this->get_topic_participants( $topic_id, (int) $settings['max_shown'] );
74
75 // Bail if no participants found.
76 if ( empty( $member_ids ) ) {
77 return;
78 }
79
80 $avatar_size = absint( $settings['avatar_size'] );
81
82 echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
83
84 if ( ! empty( $settings['title'] ) ) {
85 echo $args['before_title'] . $settings['title'] . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
86 }
87 ?>
88
89 <ul class="frmx-active-members frmx-list-unstyled">
90
91 <?php foreach ( $member_ids as $user_id ) :
92 $user = get_userdata( $user_id );
93
94 if ( ! $user ) {
95 continue;
96 }
97
98 $profile_url = function_exists( 'bbp_get_user_profile_url' )
99 ? bbp_get_user_profile_url( $user_id )
100 : get_author_posts_url( $user_id );
101 $display_name = $user->display_name;
102 ?>
103
104 <li class="frmx-active-member-item" data-frmx-tooltip="<?php echo esc_attr( $display_name ); ?>">
105 <a href="<?php echo esc_url( $profile_url ); ?>"
106 class="frmx-active-member-link"
107 style="width: <?php echo esc_attr( $avatar_size ); ?>px; height: <?php echo esc_attr( $avatar_size ); ?>px;">
108 <?php echo get_avatar( $user_id, $avatar_size ); ?>
109 </a>
110 </li>
111
112 <?php endforeach; ?>
113
114 </ul>
115
116 <?php
117 echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
118 }
119
120 /**
121 * Get unique participant IDs for a given topic.
122 *
123 * Combines the topic author with reply authors, returns unique IDs
124 * ordered by most recent activity (latest reply first).
125 *
126 * @param int $topic_id The topic ID.
127 * @param int $max_shown Maximum number of members to return.
128 * @return array Array of unique user IDs.
129 */
130 private function get_topic_participants( $topic_id, $max_shown ) {
131 global $wpdb;
132
133 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
134 $results = $wpdb->get_col(
135 $wpdb->prepare(
136 "SELECT DISTINCT post_author
137 FROM {$wpdb->posts}
138 WHERE post_parent = %d
139 AND post_type = %s
140 AND post_status IN ( 'publish', 'closed' )
141 ORDER BY post_date DESC",
142 $topic_id,
143 bbp_get_reply_post_type()
144 )
145 );
146
147 // Include the topic author at the beginning.
148 $topic_author = get_post_field( 'post_author', $topic_id );
149
150 if ( ! empty( $topic_author ) ) {
151 // Remove topic author from results if already present, then prepend.
152 $results = array_diff( $results, array( $topic_author ) );
153 array_unshift( $results, $topic_author );
154 }
155
156 // Remove invalid (0) IDs and limit.
157 $results = array_filter( $results );
158 $results = array_slice( $results, 0, $max_shown );
159
160 return array_map( 'absint', $results );
161 }
162
163 /**
164 * Update the widget options.
165 *
166 * @param array $new_instance The new instance options.
167 * @param array $old_instance The old instance options.
168 * @return array Updated instance.
169 */
170 public function update( $new_instance = array(), $old_instance = array() ) {
171 $instance = $old_instance;
172 $instance['title'] = strip_tags( $new_instance['title'] );
173 $instance['max_shown'] = (int) $new_instance['max_shown'];
174 $instance['avatar_size'] = absint( $new_instance['avatar_size'] );
175
176 return $instance;
177 }
178
179 /**
180 * Output the widget options form.
181 *
182 * @param array $instance Current widget instance settings.
183 */
184 public function form( $instance = array() ) {
185
186 // Get widget settings.
187 $settings = $this->parse_settings( $instance );
188 ?>
189
190 <p>
191 <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
192 <?php esc_html_e( 'Title:', 'forumax' ); ?>
193 <input class="widefat"
194 id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
195 name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
196 type="text"
197 value="<?php echo esc_attr( $settings['title'] ); ?>" />
198 </label>
199 </p>
200
201 <p>
202 <label for="<?php echo esc_attr( $this->get_field_id( 'max_shown' ) ); ?>">
203 <?php esc_html_e( 'Maximum members to show:', 'forumax' ); ?>
204 <input class="widefat"
205 id="<?php echo esc_attr( $this->get_field_id( 'max_shown' ) ); ?>"
206 name="<?php echo esc_attr( $this->get_field_name( 'max_shown' ) ); ?>"
207 type="number"
208 min="1"
209 max="50"
210 value="<?php echo esc_attr( $settings['max_shown'] ); ?>" />
211 </label>
212 </p>
213
214 <p>
215 <label for="<?php echo esc_attr( $this->get_field_id( 'avatar_size' ) ); ?>">
216 <?php esc_html_e( 'Avatar size (px):', 'forumax' ); ?>
217 <input class="widefat"
218 id="<?php echo esc_attr( $this->get_field_id( 'avatar_size' ) ); ?>"
219 name="<?php echo esc_attr( $this->get_field_name( 'avatar_size' ) ); ?>"
220 type="number"
221 min="16"
222 max="96"
223 value="<?php echo esc_attr( $settings['avatar_size'] ); ?>" />
224 </label>
225 </p>
226
227 <p>
228 <small><?php esc_html_e( 'This widget is only visible on single topic pages.', 'forumax' ); ?></small>
229 </p>
230
231 <?php
232 }
233
234 /**
235 * Merge the widget settings into defaults array.
236 *
237 * @param array $instance Current instance settings.
238 * @return array Parsed settings with defaults applied.
239 */
240 public function parse_settings( $instance = array() ) {
241 return bbp_parse_args( $instance, array(
242 'title' => esc_html__( 'Active Members', 'forumax' ),
243 'max_shown' => 8,
244 'avatar_size' => 60,
245 ), 'forumax_active_members_widget_settings' );
246 }
247 }
248