PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.2.0
Forumax – AI Powered Advanced Community Forum Plugin v2.2.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
← All changes | includes/features/bbp_voting/frontend.php +350 -349 1.3.32.2.0 View file →
@@ -1,349 +1,350 @@
1 -<?php
2 -if ( ! defined( 'ABSPATH' ) ) {
3 - exit; // Exit if accessed directly.
4 -}
5 -
6 -// Vote Buttons and Score hooks.
7 -add_action( 'bbp_theme_after_topic_author_details', 'bbp_voting_buttons' ); // ✅ New Hook
8 -add_action( 'bbp_theme_after_reply_author_details', 'bbp_voting_buttons' );
9 -add_action( 'bbp_voting_cpt', 'bbp_voting_buttons', 10, 1 );
10 -
11 -function bbp_voting_buttons( $post_obj = false ) {
12 - // Don't show voting buttons on user profile pages
13 - if ( function_exists( 'bbp_is_single_user' ) && bbp_is_single_user() ) {
14 - return;
15 - }
16 -
17 - $current_action = current_action();
18 - $topic_post_type = bbp_get_topic_post_type();
19 - $reply_post_type = bbp_get_reply_post_type();
20 - $this_post_type = '';
21 - $post = null;
22 -
23 - // Get post object based on context
24 - if ( $current_action === 'bbp_voting_cpt' ) {
25 - if ( ! $post_obj ) return;
26 - $post = $post_obj;
27 - } else {
28 - // Determine post type from current action
29 - if ( in_array( $current_action, [
30 - 'bbp_theme_before_topic_title',
31 - 'bbp_template_before_lead_topic',
32 - 'bbp_theme_after_topic_author_details'
33 - ] ) ) {
34 - $this_post_type = $topic_post_type;
35 - $post = bbpress()->topic_query->post;
36 - } elseif ( in_array( $current_action, [
37 - 'bbp_theme_before_reply_content',
38 - 'bbp_theme_after_reply_author_details'
39 - ] ) ) {
40 - $this_post_type = bbp_voting_get_current_post_type();
41 - $post = bbpress()->reply_query->post;
42 - }
43 -
44 - // Exit if unknown context or no post
45 - if ( empty( $this_post_type ) || empty( $post ) ) return;
46 -
47 - // Check forum settings
48 - $forum_id = ($this_post_type === $topic_post_type)
49 - ? bbp_get_topic_forum_id( $post->ID )
50 - : bbp_get_reply_forum_id( $post->ID );
51 -
52 - // Check if voting is allowed on this forum
53 - if ( ! apply_filters( 'bbp_voting_allowed_on_forum', true, $forum_id ) ) return;
54 -
55 - // Get post-specific settings
56 - $post_setting = ($this_post_type === $topic_post_type)
57 - ? get_post_meta( $forum_id, 'bbp_voting_forum_enable_topics', true )
58 - : get_post_meta( $forum_id, 'bbp_voting_forum_enable_replies', true );
59 -
60 - $broad_disable = ($this_post_type === $topic_post_type)
61 - ? bbpc_get_opt( 'is_voting_disabled_topics', 0 )
62 - : bbpc_get_opt( 'is_voting_disabled_replies', 0 );
63 -
64 - // Check if voting is disabled
65 - if ( ! empty( $post_setting ) && $post_setting === 'false' ) return;
66 - if ( empty( $post_setting ) && $broad_disable === '0' ) return;
67 - }
68 -
69 - $post_id = $post->ID;
70 -
71 - $score = (int) get_post_meta( $post_id, 'bbp_voting_score', true );
72 - $ups = (int) get_post_meta( $post_id, 'bbp_voting_ups', true );
73 - $downs = (int) get_post_meta( $post_id, 'bbp_voting_downs', true );
74 -
75 - $calc_score = $ups + $downs;
76 - if ( $score > $calc_score ) {
77 - $diff = $score - $calc_score;
78 - $ups += $diff;
79 - update_post_meta( $post_id, 'bbp_voting_ups', $ups );
80 - }
81 -
82 - $voting_log = get_post_meta( $post_id, 'bbp_voting_log', true );
83 - $voting_log = is_array( $voting_log ) ? $voting_log : [];
84 - $client_ip = $_SERVER['REMOTE_ADDR'];
85 - $identifier = is_user_logged_in() ? get_current_user_id() : $client_ip;
86 - $existing_vote = $voting_log[ $identifier ] ?? 0;
87 -
88 - // Check if admin can bypass voting restrictions
89 - $admin_bypass = current_user_can( 'administrator' ) &&
90 - bbpc_get_opt( 'is_admin_can_vote_unlimited', false );
91 -
92 - // Determine if this is view-only mode
93 - $view_only = ! is_user_logged_in() &&
94 - bbpc_get_opt( 'is_disabled_voting_for_non_logged_users', false );
95 -
96 - // Additional view-only checks for regular context (not CPT)
97 - if ( ! $view_only && $current_action !== 'bbp_voting_cpt' ) {
98 - // Check if topic is closed and voting on closed topics is disabled
99 - $topic_id = ( $this_post_type === $topic_post_type ) ?
100 - $post_id : bbp_get_reply_topic_id( $post_id );
101 -
102 - if ( get_post_status( $topic_id ) === 'closed' &&
103 - bbpc_get_opt( 'is_disabled_voting_closed_topics', false ) ) {
104 - $view_only = true;
105 - }
106 -
107 - // Check if voting on own posts is disabled
108 - if ( ! $view_only &&
109 - bbpc_get_opt( 'is_disabled_voting_own_topic_reply', false ) &&
110 - $post->post_author == get_current_user_id() ) {
111 - $view_only = true;
112 - }
113 - }
114 -
115 - $disable_down = bbpc_get_opt( 'is_down_votes_disabled', 0 );
116 - $vote_number_display = bbpc_get_opt( 'vote_numbers_display', 'hover' );
117 - $display_vote_nums = 'num-' . $vote_number_display;
118 -
119 - // Determine if floating style should be applied
120 - $float = in_array( $current_action, [
121 - 'bbp_theme_before_reply_content',
122 - 'bbp_voting_cpt'
123 - ] );
124 -
125 - // Build CSS classes for the voting container
126 - $vote_classes = [
127 - 'bbp-voting',
128 - 'bbp-voting-post-' . $post_id,
129 - get_post_type( $post_id )
130 - ];
131 -
132 - if ( $view_only ) {
133 - $vote_classes[] = 'view-only';
134 - } elseif ( $existing_vote == 1 ) {
135 - $vote_classes[] = 'voted-up';
136 - } elseif ( $existing_vote == -1 ) {
137 - $vote_classes[] = 'voted-down';
138 - }
139 -
140 - if ( $admin_bypass ) $vote_classes[] = 'admin-bypass';
141 - if ( $float ) $vote_classes[] = 'bbp-voting-float';
142 -
143 - // Start building HTML
144 - $html = '<div class="' . implode(' ', $vote_classes) . '">';
145 -
146 - // Add label if enabled
147 - $is_label = bbpc_get_opt( 'is_label', true );
148 - if ( $is_label ) {
149 - $upvote_label = bbpc_get_opt( 'upvote_label' );
150 - if ( $upvote_label ) {
151 - $html .= '<div class="bbp-voting-label helpful">' . esc_html( $upvote_label ) . '</div>';
152 - }
153 - }
154 -
155 - // Generate voting HTML based on whether we're in AMP mode or not
156 - if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
157 - // AMP version of voting buttons
158 - $post_url = admin_url( 'admin-ajax.php' );
159 - $plusups = $ups ? '+' . $ups : ' ';
160 -
161 - // Upvote form
162 - $html .= sprintf(
163 - '<form name="amp-form%1$s" method="post" action-xhr="%2$s" target="_top" on="submit-success: AMP.setState({\'voteup%1$s\': %3$s})">
164 - <input type="hidden" name="action" value="bbpress_post_vote_link_clicked">
165 - <input type="hidden" name="post_id" value="%4$s" />
166 - <input type="hidden" name="direction" value="1" />
167 - <input type="submit" class="nobutton upvote-amp" value="🔺" />
168 - <span class="vote up" [text]="voteup%1$s ? \'+\' + voteup%1$s : \'%5$s\'">%5$s</span>
169 - </form>',
170 - $post_id,
171 - esc_url( $post_url ),
172 - ( $ups + 1 ),
173 - esc_attr( $post_id ),
174 - esc_html( $plusups )
175 - );
176 -
177 - // Downvote form (if enabled)
178 - if ( $disable_down === '1' ) {
179 - $html .= sprintf(
180 - '<form name="amp-form%1$s" method="post" action-xhr="%2$s" target="_top" on="submit-success: AMP.setState({\'votedown%1$s\': %3$s})">
181 - <input type="hidden" name="action" value="bbpress_post_vote_link_clicked">
182 - <input type="hidden" name="post_id" value="%4$s" />
183 - <input type="hidden" name="direction" value="-1" />
184 - <input type="submit" class="nobutton downvote-amp" value="🔻" />
185 - <span class="vote down" [text]="votedown%1$s || \'%5$s\'">%6$s</span>
186 - </form>',
187 - $post_id,
188 - esc_url( $post_url ),
189 - ( $downs - 1 ),
190 - esc_attr( $post_id ),
191 - esc_html( $downs ? $downs : ' ' ),
192 - esc_html( $downs ? $downs : '' )
193 - );
194 - }
195 - } else {
196 - // Standard version of voting buttons
197 - $html .= '<a class="vote up ' . esc_attr( $display_vote_nums ) . '" data-votes="' .
198 - ( $ups ? '+' . $ups : '' ) . '" onclick="bbpress_post_vote_link_clicked(' .
199 - $post_id . ', 1); return false;">Up</a>';
200 -
201 - $html .= '<div class="score">' . $score . '</div>';
202 -
203 - if ( $disable_down === '1' ) {
204 - $html .= '<a class="vote down ' . esc_attr( $display_vote_nums ) . '" data-votes="' .
205 - ( $downs ? $downs : '' ) . '" onclick="bbpress_post_vote_link_clicked(' .
206 - $post_id . ', -1); return false;">Down</a>';
207 - }
208 - }
209 -
210 - if ( $disable_down === '1' && $is_label ) {
211 - $downvote_label = bbpc_get_opt( 'downvote_label' );
212 - if ( $downvote_label ) {
213 - $html .= '<div class="bbp-voting-label not-helpful">' . esc_html( $downvote_label ) . '</div>';
214 - }
215 - }
216 -
217 - // Apply filter for reply voting buttons
218 - if ( $this_post_type === $reply_post_type ) {
219 - $html = apply_filters( 'bbp_voting_after_reply_voting_buttons', $html, $post_id );
220 - }
221 -
222 - // Close the voting container
223 - $html .= '</div><span style="display:none;">::</span>';
224 -
225 - echo $html;
226 -}
227 -
228 -
229 -// Sort by Votes
230 -
231 -add_filter( 'bbp_has_topics_query', 'sort_bbpress_posts_by_votes', 99 );
232 -add_filter( 'bbp_has_replies_query', 'sort_bbpress_posts_by_votes', 99 );
233 -
234 -function sort_bbpress_posts_by_votes( $args = [] ) {
235 - $forum_id = bbp_get_forum_id();
236 - $forum_post_type = bbp_get_forum_post_type();
237 - $topic_post_type = bbp_get_topic_post_type();
238 -
239 - // Determine post type and settings based on current filter
240 - $current_filter = current_filter();
241 - switch ( $current_filter ) {
242 - case 'bbp_has_topics_query':
243 - $this_post_type = $forum_post_type;
244 - $post_setting = get_post_meta( $forum_id, 'sort_bbpress_topics_by_votes_on_forum', true );
245 - $broad_enable = bbpc_get_opt( 'is_sort_topic_by_votes', 0 );
246 - break;
247 - case 'bbp_has_replies_query':
248 - $this_post_type = $topic_post_type;
249 - $post_setting = get_post_meta( $forum_id, 'sort_bbpress_replies_by_votes_on_forum', true );
250 - $broad_enable = bbpc_get_opt( 'is_sort_reply_by_votes', 0 );
251 - break;
252 - default:
253 - return $args;
254 - }
255 -
256 - // Check if we should apply vote sorting
257 - $apply_sorting = false;
258 -
259 - // Check URL parameter first
260 - if ( isset( $_GET['bbp-voting-sort'] ) ) {
261 - if ( $_GET['bbp-voting-sort'] === 'best' ) {
262 - $apply_sorting = true;
263 - } elseif ( $_GET['bbp-voting-sort'] === 'default' || $_GET['bbp-voting-sort'] === '' ) {
264 - return $args;
265 - }
266 - } else {
267 - // Check forum settings
268 - if ( ! empty( $post_setting ) ) {
269 - if ( $post_setting !== 'false' ) {
270 - $apply_sorting = true;
271 - }
272 - } elseif ( $broad_enable !== '1' ) {
273 - $apply_sorting = true;
274 - }
275 -
276 - // Check if voting is allowed on this forum
277 - if ( ! apply_filters( 'bbp_voting_allowed_on_forum', true, $forum_id ) ) {
278 - $apply_sorting = false;
279 - }
280 - }
281 -
282 - // Return original args if sorting should not be applied
283 - if ( ! $apply_sorting ) {
284 - return $args;
285 - }
286 -
287 - // Get the meta key to sort by
288 - $sort_meta_key = apply_filters( 'bbp_voting_sort_meta_key', 'bbp_voting_score' );
289 -
290 - // Find and fill any posts missing the sort meta key
291 - $missing_meta_query = [
292 - 'meta_query' => [
293 - [
294 - 'key' => $sort_meta_key,
295 - 'compare' => 'NOT EXISTS',
296 - 'value' => '',
297 - ],
298 - ],
299 - ];
300 -
301 - $query = new WP_Query( array_merge( $args, $missing_meta_query ) );
302 - foreach ( $query->posts as $post ) {
303 - $default_value = apply_filters( 'bbp_voting_sort_meta_key_default_value', '0', $post->ID );
304 - update_post_meta( $post->ID, $sort_meta_key, $default_value );
305 - }
306 -
307 - // Clear existing sort parameters
308 - $args = array_diff_key( $args, array_flip( ['meta_key', 'meta_type', 'orderby', 'order'] ) );
309 -
310 - // Set up meta query for sorting
311 - $args['meta_query'] = [
312 - 'relation' => 'AND',
313 - 'score_clause' => [
314 - 'key' => $sort_meta_key,
315 - 'compare' => 'EXISTS',
316 - ],
317 - ];
318 -
319 - // Set numeric type for score meta if using the default key
320 - if ( $sort_meta_key === 'bbp_voting_score' ) {
321 - $args['meta_query']['score_clause']['type'] = 'NUMERIC';
322 - }
323 -
324 - // Set up orderby parameters
325 - $args['orderby'] = [
326 - 'post_type' => 'DESC',
327 - 'score_clause' => 'DESC',
328 - ];
329 -
330 - // Add additional sorting parameters based on post type
331 - if ( $this_post_type === $topic_post_type ) {
332 - $args['orderby']['date'] = 'ASC';
333 - } elseif ( $this_post_type === $forum_post_type ) {
334 - $args['meta_query']['orderby_freshness'] = [
335 - 'key' => '_bbp_last_active_time',
336 - 'type' => 'DATETIME',
337 - ];
338 - $args['orderby']['orderby_freshness'] = 'DESC';
339 - }
340 -
341 - return $args;
342 -}
343 -
344 -add_action( 'init', 'bbp_voting_lead_topic' );
345 -function bbp_voting_lead_topic() {
346 - if ( bbpc_get_opt( 'is_lead_topic_broken', false ) ) {
347 - add_filter( 'bbp_show_lead_topic', '__return_true' );
348 - }
349 -}
1 +<?php
2 +if ( ! defined( 'ABSPATH' ) ) {
3 + exit; // Exit if accessed directly.
4 +}
5 +
6 +// Vote Buttons and Score hooks.
7 +add_action( 'bbp_theme_after_topic_author_details', 'bbp_voting_buttons' ); // ✅ New Hook
8 +add_action( 'bbp_theme_after_reply_author_details', 'bbp_voting_buttons' );
9 +add_action( 'bbp_voting_cpt', 'bbp_voting_buttons', 10, 1 );
10 +
11 +function bbp_voting_buttons( $post_obj = false ) {
12 + // Don't show voting buttons on user profile pages
13 + if ( function_exists( 'bbp_is_single_user' ) && bbp_is_single_user() ) {
14 + return;
15 + }
16 +
17 + $current_action = current_action();
18 + $topic_post_type = bbp_get_topic_post_type();
19 + $reply_post_type = bbp_get_reply_post_type();
20 + $this_post_type = '';
21 + $post = null;
22 +
23 + // Get post object based on context
24 + if ( $current_action === 'bbp_voting_cpt' ) {
25 + if ( ! $post_obj ) return;
26 + $post = $post_obj;
27 + } else {
28 + // Determine post type from current action
29 + if ( in_array( $current_action, [
30 + 'bbp_theme_before_topic_title',
31 + 'bbp_template_before_lead_topic',
32 + 'bbp_theme_after_topic_author_details'
33 + ] ) ) {
34 + $this_post_type = $topic_post_type;
35 + $post = bbpress()->topic_query->post;
36 + } elseif ( in_array( $current_action, [
37 + 'bbp_theme_before_reply_content',
38 + 'bbp_theme_after_reply_author_details'
39 + ] ) ) {
40 + $this_post_type = bbp_voting_get_current_post_type();
41 + $post = bbpress()->reply_query->post;
42 + }
43 +
44 + // Exit if unknown context or no post
45 + if ( empty( $this_post_type ) || empty( $post ) ) return;
46 +
47 + // Check forum settings
48 + $forum_id = ($this_post_type === $topic_post_type)
49 + ? bbp_get_topic_forum_id( $post->ID )
50 + : bbp_get_reply_forum_id( $post->ID );
51 +
52 + // Check if voting is allowed on this forum
53 + if ( ! apply_filters( 'bbp_voting_allowed_on_forum', true, $forum_id ) ) return;
54 +
55 + // Get post-specific settings
56 + $post_setting = ($this_post_type === $topic_post_type)
57 + ? get_post_meta( $forum_id, 'bbp_voting_forum_enable_topics', true )
58 + : get_post_meta( $forum_id, 'bbp_voting_forum_enable_replies', true );
59 +
60 + $broad_disable = ($this_post_type === $topic_post_type)
61 + ? forumax_get_opt( 'is_voting_disabled_topics', 0 )
62 + : forumax_get_opt( 'is_voting_disabled_replies', 0 );
63 +
64 + // Check if voting is disabled
65 + if ( ! empty( $post_setting ) && $post_setting === 'false' ) return;
66 + if ( empty( $post_setting ) && $broad_disable === '0' ) return;
67 + }
68 +
69 + $post_id = $post->ID;
70 +
71 + $score = (int) get_post_meta( $post_id, 'bbp_voting_score', true );
72 + $ups = (int) get_post_meta( $post_id, 'bbp_voting_ups', true );
73 + $downs = (int) get_post_meta( $post_id, 'bbp_voting_downs', true );
74 +
75 + $calc_score = $ups + $downs;
76 + if ( $score > $calc_score ) {
77 + $diff = $score - $calc_score;
78 + $ups += $diff;
79 + update_post_meta( $post_id, 'bbp_voting_ups', $ups );
80 + }
81 +
82 + $voting_log = get_post_meta( $post_id, 'bbp_voting_log', true );
83 + $voting_log = is_array( $voting_log ) ? $voting_log : [];
84 + $client_ip = $_SERVER['REMOTE_ADDR'];
85 + $identifier = is_user_logged_in() ? get_current_user_id() : $client_ip;
86 + $existing_vote = $voting_log[ $identifier ] ?? 0;
87 +
88 + // Check if admin can bypass voting restrictions
89 + $admin_bypass = current_user_can( 'administrator' ) &&
90 + forumax_get_opt( 'is_admin_can_vote_unlimited', false );
91 +
92 + // Determine if this is view-only mode
93 + $view_only = ! is_user_logged_in() &&
94 + forumax_get_opt( 'is_disabled_voting_for_non_logged_users', false );
95 +
96 + // Additional view-only checks for regular context (not CPT)
97 + if ( ! $view_only && $current_action !== 'bbp_voting_cpt' ) {
98 + // Check if topic is closed and voting on closed topics is disabled
99 + $topic_id = ( $this_post_type === $topic_post_type ) ?
100 + $post_id : bbp_get_reply_topic_id( $post_id );
101 +
102 + if ( get_post_status( $topic_id ) === 'closed' &&
103 + forumax_get_opt( 'is_disabled_voting_closed_topics', false ) ) {
104 + $view_only = true;
105 + }
106 +
107 + // Check if voting on own posts is disabled
108 + if ( ! $view_only &&
109 + forumax_get_opt( 'is_disabled_voting_own_topic_reply', false ) &&
110 + $post->post_author == get_current_user_id() ) {
111 + $view_only = true;
112 + }
113 + }
114 +
115 + $disable_down = forumax_get_opt( 'is_down_votes_disabled', 0 );
116 + $vote_number_display = forumax_get_opt( 'vote_numbers_display', 'hover' );
117 + $display_vote_nums = 'num-' . $vote_number_display;
118 +
119 + // Determine if floating style should be applied
120 + $float = in_array( $current_action, [
121 + 'bbp_theme_before_reply_content',
122 + 'bbp_voting_cpt'
123 + ] );
124 +
125 + // Build CSS classes for the voting container
126 + $vote_classes = [
127 + 'bbp-voting',
128 + 'bbp-voting-post-' . $post_id,
129 + get_post_type( $post_id )
130 + ];
131 +
132 + if ( $view_only ) {
133 + $vote_classes[] = 'view-only';
134 + } elseif ( $existing_vote == 1 ) {
135 + $vote_classes[] = 'voted-up';
136 + } elseif ( $existing_vote == -1 ) {
137 + $vote_classes[] = 'voted-down';
138 + }
139 +
140 + if ( $admin_bypass ) $vote_classes[] = 'admin-bypass';
141 + if ( $float ) $vote_classes[] = 'bbp-voting-float';
142 +
143 + // Start building HTML
144 + $html = '<div class="' . implode(' ', $vote_classes) . '">';
145 +
146 + // Add label if enabled
147 + $is_label = forumax_get_opt( 'is_label', true );
148 + if ( $is_label ) {
149 + $upvote_label = forumax_get_opt( 'upvote_label' );
150 + if ( $upvote_label ) {
151 + $html .= '<div class="bbp-voting-label helpful">' . esc_html( $upvote_label ) . '</div>';
152 + }
153 + }
154 +
155 + // Generate voting HTML based on whether we're in AMP mode or not
156 + if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
157 + // AMP version of voting buttons
158 + $post_url = admin_url( 'admin-ajax.php' );
159 + $plusups = $ups ? '+' . $ups : ' ';
160 +
161 + // Upvote form
162 + $html .= sprintf(
163 + '<form name="amp-form%1$s" method="post" action-xhr="%2$s" target="_top" on="submit-success: AMP.setState({\'voteup%1$s\': %3$s})">
164 + <input type="hidden" name="action" value="bbpress_post_vote_link_clicked">
165 + <input type="hidden" name="post_id" value="%4$s" />
166 + <input type="hidden" name="direction" value="1" />
167 + <input type="submit" class="nobutton upvote-amp" value="🔺" />
168 + <span class="vote up" [text]="voteup%1$s ? \'+\' + voteup%1$s : \'%5$s\'">%5$s</span>
169 + </form>',
170 + $post_id,
171 + esc_url( $post_url ),
172 + ( $ups + 1 ),
173 + esc_attr( $post_id ),
174 + esc_html( $plusups )
175 + );
176 +
177 +
178 + // Downvote form (if enabled)
179 + if ( $disable_down == 1 ) {
180 + $html .= sprintf(
181 + '<form name="amp-form%1$s" method="post" action-xhr="%2$s" target="_top" on="submit-success: AMP.setState({\'votedown%1$s\': %3$s})">
182 + <input type="hidden" name="action" value="bbpress_post_vote_link_clicked">
183 + <input type="hidden" name="post_id" value="%4$s" />
184 + <input type="hidden" name="direction" value="-1" />
185 + <input type="submit" class="nobutton downvote-amp" value="🔻" />
186 + <span class="vote down" [text]="votedown%1$s || \'%5$s\'">%6$s</span>
187 + </form>',
188 + $post_id,
189 + esc_url( $post_url ),
190 + ( $downs - 1 ),
191 + esc_attr( $post_id ),
192 + esc_html( $downs ? $downs : ' ' ),
193 + esc_html( $downs ? $downs : '' )
194 + );
195 + }
196 + } else {
197 + // Standard version of voting buttons
198 + $html .= '<a class="vote up ' . esc_attr( $display_vote_nums ) . '" data-votes="' .
199 + ( $ups ? '+' . $ups : '' ) . '" onclick="bbpress_post_vote_link_clicked(' .
200 + $post_id . ', 1); return false;">Up</a>';
201 +
202 + $html .= '<div class="score">' . $score . '</div>';
203 +
204 + if ( $disable_down == 1 ) {
205 + $html .= '<a class="vote down ' . esc_attr( $display_vote_nums ) . '" data-votes="' .
206 + ( $downs ? $downs : '' ) . '" onclick="bbpress_post_vote_link_clicked(' .
207 + $post_id . ', -1); return false;">Down</a>';
208 + }
209 + }
210 +
211 + if ( $disable_down == 1 && $is_label ) {
212 + $downvote_label = forumax_get_opt( 'downvote_label' );
213 + if ( $downvote_label ) {
214 + $html .= '<div class="bbp-voting-label not-helpful">' . esc_html( $downvote_label ) . '</div>';
215 + }
216 + }
217 +
218 + // Apply filter for reply voting buttons
219 + if ( $this_post_type === $reply_post_type ) {
220 + $html = apply_filters( 'bbp_voting_after_reply_voting_buttons', $html, $post_id );
221 + }
222 +
223 + // Close the voting container
224 + $html .= '</div>';
225 +
226 + echo $html;
227 +}
228 +
229 +
230 +// Sort by Votes
231 +
232 +add_filter( 'bbp_has_topics_query', 'sort_bbpress_posts_by_votes', 99 );
233 +add_filter( 'bbp_has_replies_query', 'sort_bbpress_posts_by_votes', 99 );
234 +
235 +function sort_bbpress_posts_by_votes( $args = [] ) {
236 + $forum_id = bbp_get_forum_id();
237 + $forum_post_type = bbp_get_forum_post_type();
238 + $topic_post_type = bbp_get_topic_post_type();
239 +
240 + // Determine post type and settings based on current filter
241 + $current_filter = current_filter();
242 + switch ( $current_filter ) {
243 + case 'bbp_has_topics_query':
244 + $this_post_type = $forum_post_type;
245 + $post_setting = get_post_meta( $forum_id, 'sort_bbpress_topics_by_votes_on_forum', true );
246 + $broad_enable = forumax_get_opt( 'is_sort_topic_by_votes', false );
247 + break;
248 + case 'bbp_has_replies_query':
249 + $this_post_type = $topic_post_type;
250 + $post_setting = get_post_meta( $forum_id, 'sort_bbpress_replies_by_votes_on_forum', true );
251 + $broad_enable = forumax_get_opt( 'is_sort_reply_by_votes', false );
252 + break;
253 + default:
254 + return $args;
255 + }
256 +
257 + // Check if we should apply vote sorting
258 + $apply_sorting = false;
259 +
260 + // Check URL parameter first
261 + if ( isset( $_GET['bbp-voting-sort'] ) ) {
262 + if ( $_GET['bbp-voting-sort'] === 'best' ) {
263 + $apply_sorting = true;
264 + } elseif ( $_GET['bbp-voting-sort'] === 'default' || $_GET['bbp-voting-sort'] === '' ) {
265 + return $args;
266 + }
267 + } else {
268 + // Check forum settings
269 + if ( ! empty( $post_setting ) ) {
270 + if ( $post_setting !== 'false' ) {
271 + $apply_sorting = true;
272 + }
273 + } elseif ( $broad_enable !== '1' ) {
274 + $apply_sorting = true;
275 + }
276 +
277 + // Check if voting is allowed on this forum
278 + if ( ! apply_filters( 'bbp_voting_allowed_on_forum', true, $forum_id ) ) {
279 + $apply_sorting = false;
280 + }
281 + }
282 +
283 + // Return original args if sorting should not be applied
284 + if ( ! $apply_sorting ) {
285 + return $args;
286 + }
287 +
288 + // Get the meta key to sort by
289 + $sort_meta_key = apply_filters( 'bbp_voting_sort_meta_key', 'bbp_voting_score' );
290 +
291 + // Find and fill any posts missing the sort meta key
292 + $missing_meta_query = [
293 + 'meta_query' => [
294 + [
295 + 'key' => $sort_meta_key,
296 + 'compare' => 'NOT EXISTS',
297 + 'value' => '',
298 + ],
299 + ],
300 + ];
301 +
302 + $query = new WP_Query( array_merge( $args, $missing_meta_query ) );
303 + foreach ( $query->posts as $post ) {
304 + $default_value = apply_filters( 'bbp_voting_sort_meta_key_default_value', '0', $post->ID );
305 + update_post_meta( $post->ID, $sort_meta_key, $default_value );
306 + }
307 +
308 + // Clear existing sort parameters
309 + $args = array_diff_key( $args, array_flip( ['meta_key', 'meta_type', 'orderby', 'order'] ) );
310 +
311 + // Set up meta query for sorting
312 + $args['meta_query'] = [
313 + 'relation' => 'AND',
314 + 'score_clause' => [
315 + 'key' => $sort_meta_key,
316 + 'compare' => 'EXISTS',
317 + ],
318 + ];
319 +
320 + // Set numeric type for score meta if using the default key
321 + if ( $sort_meta_key === 'bbp_voting_score' ) {
322 + $args['meta_query']['score_clause']['type'] = 'NUMERIC';
323 + }
324 +
325 + // Set up orderby parameters
326 + $args['orderby'] = [
327 + 'post_type' => 'DESC',
328 + 'score_clause' => 'DESC',
329 + ];
330 +
331 + // Add additional sorting parameters based on post type
332 + if ( $this_post_type === $topic_post_type ) {
333 + $args['orderby']['date'] = 'ASC';
334 + } elseif ( $this_post_type === $forum_post_type ) {
335 + $args['meta_query']['orderby_freshness'] = [
336 + 'key' => '_bbp_last_active_time',
337 + 'type' => 'DATETIME',
338 + ];
339 + $args['orderby']['orderby_freshness'] = 'DESC';
340 + }
341 +
342 + return $args;
343 +}
344 +
345 +add_action( 'init', 'bbp_voting_lead_topic' );
346 +function bbp_voting_lead_topic() {
347 + if ( forumax_get_opt( 'is_lead_topic_broken', false ) ) {
348 + add_filter( 'bbp_show_lead_topic', '__return_true' );
349 + }
350 +}