PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.5.0
Forumax – AI Powered Advanced Community Forum Plugin v2.5.0
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 2.0.0 All 30 releases
bbp-core / includes / bbpress-config.php

bbpress-config.php in Forumax – AI Powered Advanced Community Forum Plugin 2.5.0, at includes/bbpress-config.php

446 lines 14.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * bbPress configuration for Forumax
4 *
5 * @package Forumax
6 */
7
8 defined( 'ABSPATH' ) || exit;
9
10 /**
11 * bbPress Replies
12 */
13 add_filter( 'bbp_show_lead_topic', function () {
14 $show_lead[] = 'true';
15 return $show_lead;
16 } );
17
18 /**
19 * bbPress User Role
20 */
21 if ( ! function_exists( 'forumax_bbp_user_role_icon' ) ) {
22 /**
23 * Get modern inline SVG icon markup for a bbPress role.
24 *
25 * @param string $author_role User role label.
26 * @return string
27 */
28 function forumax_get_bbp_role_icon_svg( $author_role = '' ) {
29 switch ( $author_role ) {
30 case 'Keymaster':
31 return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M3 8l4 4 5-7 5 7 4-4-2 11H5L3 8z"></path><path d="M8 18h8"></path></svg>';
32 case 'Moderator':
33 return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M12 3l7 3v6c0 4.5-3 7.7-7 9-4-1.3-7-4.5-7-9V6l7-3z"></path><path d="M9 12l2 2 4-4"></path></svg>';
34 case 'Participant':
35 return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="8.5" r="2.5"></circle><path d="M6.5 17.5c1.3-2.4 3.2-3.5 5.5-3.5s4.2 1.1 5.5 3.5"></path></svg>';
36 case 'Member':
37 return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="8" r="2.75"></circle><path d="M6.5 18c1.2-2.6 3.1-3.8 5.5-3.8s4.3 1.2 5.5 3.8"></path><path d="M18.5 6.5l.9.6 1-.1-.6.9.1 1-.9-.6-.9.6.1-1-.6-.9 1 .1z"></path></svg>';
38 case 'Spectator':
39 return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><path d="M2 12s3.5-6 10-6 10 6 10 6-3.5 6-10 6-10-6-10-6z"></path><circle cx="12" cy="12" r="2.5"></circle></svg>';
40 case 'Blocked':
41 return '<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="9"></circle><path d="M8.5 8.5l7 7"></path></svg>';
42 default:
43 return '';
44 }
45 }
46
47 /**
48 * Display user role icon based on bbPress role.
49 */
50 function forumax_bbp_user_role_icon() {
51 $author_id = 0;
52
53 if ( bbp_get_reply_id() ) {
54 $author_id = bbp_get_reply_author_id( bbp_get_reply_id() );
55 } elseif ( bbp_get_topic_id() ) {
56 $author_id = bbp_get_topic_author_id( bbp_get_topic_id() );
57 }
58
59 $author_role = ! empty( $author_id ) ? bbp_get_user_display_role( $author_id ) : '';
60 $icon_svg = forumax_get_bbp_role_icon_svg( $author_role );
61
62 if ( ! empty( $icon_svg ) ) {
63 echo '<span class="forumax-role-icon forumax-role-icon--' . esc_attr( sanitize_title( $author_role ) ) . '" aria-hidden="true">' . $icon_svg . '</span>';
64 }
65 }
66 }
67
68 /**
69 * Get author role
70 */
71 if ( ! function_exists( 'forumax_get_bbp_user_role' ) ) {
72 /**
73 * Get the author role for the current topic.
74 *
75 * @return string The author role.
76 */
77 function forumax_get_bbp_user_role( $topic_id = 0 ) {
78 $role = bbp_get_topic_author_role( [
79 'topic_id' => $topic_id,
80 'before' => '',
81 'after' => '',
82 ]);
83 return $role;
84 }
85 }
86
87 /**
88 * Get reply author role
89 */
90 if ( ! function_exists( 'forumax_get_bbp_reply_user_role' ) ) {
91 /**
92 * Get the author role for the current reply.
93 *
94 * @param int $reply_id Reply ID.
95 * @return string The author role.
96 */
97 function forumax_get_bbp_reply_user_role( $reply_id = 0 ) {
98 $role = bbp_get_reply_author_role( [
99 'reply_id' => $reply_id,
100 'before' => '',
101 'after' => '',
102 ] );
103 return $role;
104 }
105 }
106
107 /**
108 * Get topic reply count
109 */
110 if ( ! function_exists( 'forumax_topic_reply_count' ) ) {
111 /**
112 * Output the topic reply count.
113 */
114 function forumax_topic_reply_count() {
115 $get_reply = get_post_meta( get_the_ID(), '_bbp_reply_count', true );
116 $_reply_count = isset( $get_reply ) && ! empty( $get_reply ) ? $get_reply : 0;
117 echo esc_html( $_reply_count );
118 }
119 }
120
121 /**
122 * Display bbp_reply_admin_links() as a dropdown list.
123 */
124 if ( ! function_exists( 'forumax_get_reply_admin_links' ) ) {
125 /**
126 * Get reply admin links as a dropdown.
127 *
128 * @param array $args Arguments for the admin links.
129 * @return string|void Admin links HTML.
130 */
131 function forumax_get_reply_admin_links( $args = [] ) {
132
133 // Parse arguments against default values
134 $r = bbp_parse_args( $args, [
135 'id' => 0,
136 'before' => '<div class="bbp-admin-links-dropdown">',
137 'after' => '</div>',
138 'sep' => '',
139 'links' => [],
140 ], 'get_reply_admin_links' );
141
142 $r['id'] = bbp_get_reply_id( $r['id'] );
143
144 // If post is a topic, return the topic admin links instead
145 if ( bbp_is_topic( $r['id'] ) ) {
146 return forumax_get_topic_admin_links( $args );
147 }
148
149 // If post is not a reply, return
150 if ( ! bbp_is_reply( $r['id'] ) ) {
151 return;
152 }
153
154 // If topic is trashed, do not show admin links
155 if ( bbp_is_topic_trash( bbp_get_reply_topic_id( $r['id'] ) ) ) {
156 return;
157 }
158
159 // If no links were passed, default to the standard
160 if ( empty( $r['links'] ) ) {
161 $r['links'] = apply_filters( 'bbp_reply_admin_links', [
162 'edit' => bbp_get_reply_edit_link( $r ),
163 'move' => bbp_get_reply_move_link( $r ),
164 'split' => bbp_get_topic_split_link( $r ),
165 'trash' => bbp_get_reply_trash_link( $r ),
166 'spam' => bbp_get_reply_spam_link( $r ),
167 'approve' => bbp_get_reply_approve_link( $r ),
168 'reply' => bbp_get_reply_to_link( $r ),
169 ], $r['id'] );
170 }
171
172 if ( bbp_get_user_role( get_current_user_id() ) === bbp_get_participant_role() ) {
173 unset( $r['links']['edit'] );
174 }
175
176 // See if links need to be unset
177 $reply_status = bbp_get_reply_status( $r['id'] );
178 if ( in_array( $reply_status, [ bbp_get_spam_status_id(), bbp_get_trash_status_id(), bbp_get_pending_status_id() ], true ) ) {
179
180 // Spam link shouldn't be visible on trashed topics
181 if ( bbp_get_trash_status_id() === $reply_status ) {
182 unset( $r['links']['spam'] );
183
184 // Trash link shouldn't be visible on spam topics
185 } elseif ( bbp_get_spam_status_id() === $reply_status ) {
186 unset( $r['links']['trash'] );
187 }
188 }
189
190 // Build our dropdown menu structure.
191 $menu = '<select name="reply-admin-links" class="frmx-nice-select bbp-admin-dropdown-menu" onchange="if(this.value && this.options[this.selectedIndex].getAttribute(\'data-action\') !== \'edit\') window.location.href=this.value;">';
192
193 // Placeholder (hidden trigger label).
194 $menu .= '<option value="" disabled selected data-action="trigger">' . esc_html__( 'Actions', 'forumax' ) . '</option>';
195
196 // Split links into primary and destructive groups.
197 $destructive_keys = [ 'trash', 'spam', 'approve' ];
198 $primary_links = [];
199 $danger_links = [];
200
201 foreach ( array_filter( $r['links'] ) as $key => $link ) {
202 if ( in_array( $key, $destructive_keys, true ) ) {
203 $danger_links[ $key ] = $link;
204 } else {
205 $primary_links[ $key ] = $link;
206 }
207 }
208
209 // Render primary actions.
210 foreach ( $primary_links as $key => $link ) {
211 preg_match( '/href=(["\'])([^"\']+)\\1/', $link, $matches );
212 $href = ! empty( $matches[2] ) ? $matches[2] : '';
213 $menu .= '<option value="' . esc_url( $href ) . '" class="bbp-admin-dropdown-item" data-action="' . esc_attr( $key ) . '">' . wp_strip_all_tags( $link ) . '</option>';
214 }
215
216 // Visual separator between primary and destructive groups.
217 if ( ! empty( $danger_links ) && ! empty( $primary_links ) ) {
218 $menu .= '<option disabled data-action="separator">──────</option>';
219 }
220
221 // Render destructive actions.
222 foreach ( $danger_links as $key => $link ) {
223 preg_match( '/href=(["\'])([^"\']+)\\1/', $link, $matches );
224 $href = ! empty( $matches[2] ) ? $matches[2] : '';
225 $menu .= '<option value="' . esc_url( $href ) . '" class="bbp-admin-dropdown-item" data-action="' . esc_attr( $key ) . '">' . wp_strip_all_tags( $link ) . '</option>';
226 }
227
228 $menu .= '</select>';
229
230 $retval = $r['before'] . $menu . $r['after'];
231
232 // Filter & return
233 if ( is_user_logged_in() ) {
234 return apply_filters( 'forumax_bbp_get_reply_admin_links', $retval, $r, $args );
235 }
236 }
237 }
238
239 /**
240 * Similar function for topics - to handle the case where a topic is passed to the reply function
241 */
242 if ( ! function_exists( 'forumax_get_topic_admin_links' ) ) {
243 /**
244 * Get topic admin links as a dropdown.
245 *
246 * @param array $args Arguments for the admin links.
247 * @return string|void Admin links HTML.
248 */
249 function forumax_get_topic_admin_links( $args = [] ) {
250 // Parse arguments against default values
251 $r = bbp_parse_args( $args, [
252 'id' => 0,
253 'before' => '<div class="bbp-admin-links-dropdown">',
254 'after' => '</div>',
255 'sep' => '',
256 'links' => [],
257 ], 'get_topic_admin_links' );
258
259 $r['id'] = bbp_get_topic_id( $r['id'] );
260
261 // If not a topic, then return
262 if ( ! bbp_is_topic( $r['id'] ) ) {
263 return;
264 }
265
266 // If no links were passed, get the default ones
267 if ( empty( $r['links'] ) ) {
268 $r['links'] = apply_filters( 'bbp_topic_admin_links', [
269 'edit' => bbp_get_topic_edit_link( $r ),
270 'close' => bbp_get_topic_close_link( $r ),
271 'stick' => bbp_get_topic_stick_link( $r ),
272 'merge' => bbp_get_topic_merge_link( $r ),
273 'trash' => bbp_get_topic_trash_link( $r ),
274 'spam' => bbp_get_topic_spam_link( $r ),
275 'approve' => bbp_get_topic_approve_link( $r ),
276 'reply' => bbp_get_topic_reply_link( $r ),
277 ], $r['id'] );
278 }
279
280 if ( bbp_get_user_role( get_current_user_id() ) === bbp_get_participant_role() ) {
281 unset( $r['links']['edit'] );
282 }
283
284 // See if links need to be unset
285 $topic_status = bbp_get_topic_status( $r['id'] );
286 if ( in_array( $topic_status, [ bbp_get_spam_status_id(), bbp_get_trash_status_id(), bbp_get_pending_status_id() ], true ) ) {
287
288 // Spam link shouldn't be visible on trashed topics
289 if ( bbp_get_trash_status_id() === $topic_status ) {
290 unset( $r['links']['spam'] );
291
292 // Trash link shouldn't be visible on spam topics
293 } elseif ( bbp_get_spam_status_id() === $topic_status ) {
294 unset( $r['links']['trash'] );
295 }
296 }
297
298 // Build our dropdown menu structure.
299 $menu = '<select name="topic-admin-links" class="frmx-nice-select bbp-admin-dropdown-menu" onchange="if(this.value && this.options[this.selectedIndex].getAttribute(\'data-action\') !== \'edit\') window.location.href=this.value;">';
300
301 // Placeholder (hidden trigger label).
302 $menu .= '<option value="" disabled selected data-action="trigger">' . esc_html__( 'Actions', 'forumax' ) . '</option>';
303
304 // Split links into primary and destructive groups.
305 $destructive_keys = [ 'trash', 'spam', 'approve' ];
306 $primary_links = [];
307 $danger_links = [];
308
309 foreach ( array_filter( $r['links'] ) as $key => $link ) {
310 if ( in_array( $key, $destructive_keys, true ) ) {
311 $danger_links[ $key ] = $link;
312 } else {
313 $primary_links[ $key ] = $link;
314 }
315 }
316
317 // Render primary actions.
318 foreach ( $primary_links as $key => $link ) {
319 preg_match( '/href=(["\'])([^"\']+)\\1/', $link, $matches );
320 $href = ! empty( $matches[2] ) ? $matches[2] : '';
321 $menu .= '<option value="' . esc_url( $href ) . '" class="bbp-admin-dropdown-item" data-action="' . esc_attr( $key ) . '">' . wp_strip_all_tags( $link ) . '</option>';
322 }
323
324 // Visual separator between primary and destructive groups.
325 if ( ! empty( $danger_links ) && ! empty( $primary_links ) ) {
326 $menu .= '<option disabled data-action="separator">──────</option>';
327 }
328
329 // Render destructive actions.
330 foreach ( $danger_links as $key => $link ) {
331 preg_match( '/href=(["\'])([^"\']+)\\1/', $link, $matches );
332 $href = ! empty( $matches[2] ) ? $matches[2] : '';
333 $menu .= '<option value="' . esc_url( $href ) . '" class="bbp-admin-dropdown-item" data-action="' . esc_attr( $key ) . '">' . wp_strip_all_tags( $link ) . '</option>';
334 }
335
336 $menu .= '</select>';
337
338 $retval = $r['before'] . $menu . $r['after'];
339
340 // Filter & return
341 return apply_filters( 'forumax_bbp_get_topic_admin_links', $retval, $r, $args );
342 }
343 }
344
345 /**
346 * Enqueue the script for sorting bbPress replies
347 */
348 if ( ! function_exists( 'forumax_enqueue_bbp_replies_sorting_script' ) ) {
349 /**
350 * Enqueue replies sorting script.
351 */
352 function forumax_enqueue_bbp_replies_sorting_script() {
353 wp_localize_script( 'bbp-replies-sorting', 'bbp_reply_ajax_obj', [
354 'ajax_url' => admin_url( 'admin-ajax.php' ),
355 'bbp_topic_id' => get_the_ID(),
356 ] );
357 }
358 add_action( 'wp_enqueue_scripts', 'forumax_enqueue_bbp_replies_sorting_script' );
359 }
360
361 if ( ! function_exists( 'forumax_ajax_sort_bbp_replies' ) ) {
362 /**
363 * AJAX handler for sorting replies.
364 */
365 function forumax_ajax_sort_bbp_replies() {
366 check_ajax_referer( 'forumax-nonce', 'nonce' );
367
368 if ( empty( $_POST['topic_id'] ) ) {
369 wp_send_json_error( [ 'message' => 'No topic ID provided.' ] );
370 }
371 $topic_id = intval( $_POST['topic_id'] );
372 $sort = isset( $_POST['sort'] ) ? sanitize_text_field( wp_unslash( $_POST['sort'] ) ) : 'desc';
373
374 // Set $_GET['sort'] for the filter to pick up
375 $_GET['sort'] = $sort;
376
377 // Start output buffering to capture the replies loop HTML
378 ob_start();
379 // Set up bbPress replies loop manually for AJAX context
380 $replies_args = [
381 'post_parent' => $topic_id,
382 'post_type' => bbp_get_reply_post_type(),
383 'orderby' => ( 'vote' === $sort ? 'meta_value_num' : 'date' ),
384 'order' => ( 'asc' === $sort ? 'ASC' : 'DESC' ),
385 'meta_key' => ( 'vote' === $sort ? 'bbp_voting_score' : '' ),
386 'posts_per_page' => -1,
387 ];
388 if ( bbp_has_replies( $replies_args ) ) {
389 while ( bbp_replies() ) :
390 bbp_the_reply();
391 $template_file = plugin_dir_path( __FILE__ ) . '../templates/loop-single-reply.php';
392 if ( file_exists( $template_file ) ) {
393 include $template_file;
394 }
395 endwhile;
396 } else {
397 echo '<div>No replies found.</div>';
398 }
399 $html = ob_get_clean();
400
401 wp_send_json_success( [ 'html' => $html ] );
402 }
403 add_action( 'wp_ajax_sort_bbp_replies', 'forumax_ajax_sort_bbp_replies' );
404 add_action( 'wp_ajax_nopriv_sort_bbp_replies', 'forumax_ajax_sort_bbp_replies' );
405 }
406
407 /**
408 * Remove unnecessary pipe separator from bbPress subscription links.
409 */
410 add_filter( 'bbp_get_user_subscribe_link', 'forumax_remove_subscribe_separator', 10, 1 );
411
412 /**
413 * Remove subscribe separator.
414 *
415 * @param string $html The HTML.
416 * @return string Modified HTML.
417 */
418 function forumax_remove_subscribe_separator( $html ) {
419 $html = str_replace( '&nbsp;|&nbsp;', '', $html );
420 return $html;
421 }
422
423 /**
424 * Restrict visibility of the "modified" notice to the author only.
425 *
426 * @param string $log The log output.
427 * @param int $post_id The post ID.
428 * @return string The log if allowed, empty string otherwise.
429 */
430 function forumax_restrict_revision_log_visibility( $log, $post_id ) {
431 if ( ! is_user_logged_in() ) {
432 return '';
433 }
434
435 $current_user_id = bbp_get_current_user_id();
436 $post = get_post( $post_id );
437
438 if ( ! empty( $post ) && ( int ) $post->post_author === ( int ) $current_user_id ) {
439 return $log;
440 }
441
442 return '';
443 }
444 add_filter( 'bbp_get_reply_revision_log', 'forumax_restrict_revision_log_visibility', 10, 2 );
445 add_filter( 'bbp_get_topic_revision_log', 'forumax_restrict_revision_log_visibility', 10, 2 );
446