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