| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | namespace features; |
| 3 | 3 | |
| 4 | -class bbp_solved_topic { | |
| 4 | +class forumax_solve_topic { | |
| 5 | 5 | |
| 6 | 6 | /** |
| 7 | 7 | * The capability required to view private posts. |
| 8 | 8 | * |
| @@ -41,13 +41,42 @@ | ||
| 41 | 41 | |
| 42 | 42 | add_filter( 'bbp_theme_before_topic_title', [ $this, 'solved_badge' ], 999, 2 ); |
| 43 | 43 | add_filter( 'bbp_topic_admin_links', [ $this, 'add_topic_admin_link' ], 10, 2 ); |
| 44 | 44 | |
| 45 | + add_action( 'template_redirect', [ $this, 'handle_solve_action' ] ); | |
| 46 | + | |
| 45 | 47 | // add a class name indicating the read status |
| 46 | 48 | add_filter( 'post_class', [ $this, 'reply_post_class' ] ); |
| 47 | 49 | } |
| 48 | 50 | |
| 49 | 51 | /** |
| 52 | + * Handle the solve/unsolve action via GET request | |
| 53 | + * | |
| 54 | + * @since 2.2.0 | |
| 55 | + */ | |
| 56 | + public function handle_solve_action() { | |
| 57 | + if ( ! isset( $_GET['solve_topic'] ) && ! isset( $_GET['unsolve_topic'] ) ) { | |
| 58 | + return; | |
| 59 | + } | |
| 60 | + | |
| 61 | + $topic_id = bbp_get_topic_id(); | |
| 62 | + $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : ''; | |
| 63 | + | |
| 64 | + if ( isset( $_GET['solve_topic'] ) ) { | |
| 65 | + // Verify nonce | |
| 66 | + if ( ! wp_verify_nonce( $nonce, 'forumax_solve_topic_' . $topic_id ) ) { | |
| 67 | + wp_die( esc_html__( 'Security check failed.', 'forumax' ) ); | |
| 68 | + } | |
| 69 | + $this->solve_topic( $topic_id ); | |
| 70 | + } elseif ( isset( $_GET['unsolve_topic'] ) ) { | |
| 71 | + if ( ! wp_verify_nonce( $nonce, 'forumax_unsolve_topic_' . $topic_id ) ) { | |
| 72 | + wp_die( esc_html__( 'Security check failed.', 'forumax' ) ); | |
| 73 | + } | |
| 74 | + $this->unsolve_topic( $topic_id ); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + | |
| 78 | + /** | |
| 50 | 79 | * Admin links |
| 51 | 80 | */ |
| 52 | 81 | public function add_topic_admin_link( $links, $topic_id ) { |
| 53 | 82 | |
| @@ -52,20 +81,18 @@ | ||
| 52 | 81 | public function add_topic_admin_link( $links, $topic_id ) { |
| 53 | 82 | |
| 54 | 83 | $topic_author = bbp_get_topic_author_id( bbp_get_topic_id() ); |
| 55 | 84 | if ( ( current_user_can( $this->capability ) ) || ( $topic_author == get_current_user_id() ) ) { |
| 56 | - if ( isset( $_GET['unsolve_topic'] ) ) { | |
| 57 | - $this->unsolve_topic( bbp_get_topic_id() ); | |
| 58 | - $links['solved'] = '<a href="' . bbp_get_topic_permalink() . '?solve_topic">' . esc_html__( 'Mark as solved', 'ama-core' ) . '</a>'; | |
| 59 | - } elseif ( isset( $_GET['solve_topic'] ) ) { | |
| 60 | - $this->solve_topic( bbp_get_topic_id() ); | |
| 61 | - $links['unsolved'] = '<a href="' . bbp_get_topic_permalink() . '?unsolve_topic">' . esc_html__( 'Mark as unsolved', 'ama-core' ) . '</a>'; | |
| 85 | + if ( $this->is_solved( bbp_get_topic_id() ) ) { | |
| 86 | + $links['unsolved'] = '<a href="' . wp_nonce_url( | |
| 87 | + add_query_arg( 'unsolve_topic', '1', bbp_get_topic_permalink() ), | |
| 88 | + 'forumax_unsolve_topic_' . bbp_get_topic_id() | |
| 89 | + ) . '">' . esc_html__( 'Mark as unsolved', 'forumax' ) . '</a>'; | |
| 62 | 90 | } else { |
| 63 | - if ( $this->is_solved( bbp_get_topic_id() ) ) { | |
| 64 | - $links['unsolved'] = '<a href="' . bbp_get_topic_permalink() . '?unsolve_topic">' . esc_html__( 'Mark as unsolved', 'ama-core' ) . '</a>'; | |
| 65 | - } else { | |
| 66 | - $links['solved'] = '<a href="' . bbp_get_topic_permalink() . '?solve_topic">' . esc_html__( 'Mark as solved', 'ama-core' ) . '</a>'; | |
| 67 | - } | |
| 91 | + $links['solved'] = '<a href="' . wp_nonce_url( | |
| 92 | + add_query_arg( 'solve_topic', '1', bbp_get_topic_permalink() ), | |
| 93 | + 'forumax_solve_topic_' . bbp_get_topic_id() | |
| 94 | + ) . '">' . esc_html__( 'Mark as solved', 'forumax' ) . '</a>'; | |
| 68 | 95 | } |
| 69 | 96 | } |
| 70 | 97 | return $links; |
| 71 | 98 | } |
| @@ -73,12 +100,13 @@ | ||
| 73 | 100 | public function solve_topic( $topic_id = 0 ) { |
| 74 | 101 | $topic_author = bbp_get_topic_author_id( $topic_id ); |
| 75 | 102 | if ( ( current_user_can( $this->capability ) ) || ( $topic_author == get_current_user_id() ) ) { |
| 76 | 103 | update_post_meta( $topic_id, '_bbp_topic_is_solved', '1' ); |
| 77 | - $redirect = remove_query_arg( [ 'solve_topic' ] ); | |
| 104 | + $redirect = remove_query_arg( [ 'solve_topic', '_wpnonce' ] ); | |
| 78 | 105 | wp_safe_redirect( $redirect ); |
| 106 | + exit; | |
| 79 | 107 | } else { |
| 80 | - wp_die( esc_html__( 'You do not have the permission to do that!', 'ama-core' ) ); | |
| 108 | + wp_die( esc_html__( 'You do not have the permission to do that!', 'forumax' ) ); | |
| 81 | 109 | } |
| 82 | 110 | |
| 83 | 111 | } |
| 84 | 112 | |
| @@ -85,12 +113,13 @@ | ||
| 85 | 113 | public function unsolve_topic( $topic_id = 0 ) { |
| 86 | 114 | $topic_author = bbp_get_topic_author_id( $topic_id ); |
| 87 | 115 | if ( ( current_user_can( $this->capability ) ) || ( $topic_author == get_current_user_id() ) ) { |
| 88 | 116 | delete_post_meta( $topic_id, '_bbp_topic_is_solved' ); |
| 89 | - $redirect = remove_query_arg( [ 'unsolve_topic' ] ); | |
| 117 | + $redirect = remove_query_arg( [ 'unsolve_topic', '_wpnonce' ] ); | |
| 90 | 118 | wp_safe_redirect( $redirect ); |
| 119 | + exit; | |
| 91 | 120 | } else { |
| 92 | - wp_die( esc_html__( 'You do not have the permission to do that!', 'ama-core' ) ); | |
| 121 | + wp_die( esc_html__( 'You do not have the permission to do that!', 'forumax' ) ); | |
| 93 | 122 | } |
| 94 | 123 | } |
| 95 | 124 | |
| 96 | 125 | /** |
| @@ -101,9 +130,9 @@ | ||
| 101 | 130 | * |
| 102 | 131 | * @return void |
| 103 | 132 | */ |
| 104 | 133 | public function filter_capability() { |
| 105 | - $this->capability = apply_filters( 'bbp_solved_topic_capability', $this->capability ); | |
| 134 | + $this->capability = apply_filters( 'forumax_solve_topic_capability', $this->capability ); | |
| 106 | 135 | } |
| 107 | 136 | |
| 108 | 137 | /** |
| 109 | 138 | * Solved topic badge |
| @@ -133,9 +162,9 @@ | ||
| 133 | 162 | if ( ( ! $has_best_answer ) || ( $is_best_answer ) ) { |
| 134 | 163 | ?> |
| 135 | 164 | <p> |
| 136 | 165 | <input name="bbp_best_answer" id="bbp_best_answer" type="checkbox"<?php checked( '1', $is_best_answer ); ?> value="1" tabindex="<?php bbp_tab_index(); ?>" /> |
| 137 | - <label for="bbp_best_answer"><?php esc_html_e( 'Set this reply as Best Answer.', 'ama-core' ); ?></label> | |
| 166 | + <label for="bbp_best_answer"><?php esc_html_e( 'Set this reply as Best Answer.', 'forumax' ); ?></label> | |
| 138 | 167 | </p> |
| 139 | 168 | <?php |
| 140 | 169 | } |
| 141 | 170 | } |
| @@ -152,10 +181,10 @@ | ||
| 152 | 181 | $topic_author = bbp_get_topic_author_id( bbp_get_topic_id() ); |
| 153 | 182 | if ( bbp_is_topic_edit() && ( ( current_user_can( $this->capability ) ) || ( $topic_author == get_current_user_id() ) ) ) { |
| 154 | 183 | ?> |
| 155 | 184 | <p> |
| 156 | - <input name="bbp_solved_topic" id="bbp_solved_topic" type="checkbox"<?php checked( '1', $this->is_solved( bbp_get_topic_id() ) ); ?> value="1" tabindex="<?php bbp_tab_index(); ?>" /> | |
| 157 | - <label for="bbp_solved_topic"><?php esc_html_e( 'Set this post as solved.', 'ama-core' ); ?></label> | |
| 185 | + <input name="forumax_solve_topic" id="forumax_solve_topic" type="checkbox"<?php checked( '1', $this->is_solved( bbp_get_topic_id() ) ); ?> value="1" tabindex="<?php bbp_tab_index(); ?>" /> | |
| 186 | + <label for="forumax_solve_topic"><?php esc_html_e( 'Set this post as solved.', 'forumax' ); ?></label> | |
| 158 | 187 | </p> |
| 159 | 188 | <?php |
| 160 | 189 | } |
| 161 | 190 | |
| @@ -182,9 +211,11 @@ | ||
| 182 | 211 | if ( ! $get_topic_meta ) { |
| 183 | 212 | update_post_meta( $topic_id, '_bbp_topic_has_best_answer', '1' ); |
| 184 | 213 | } |
| 185 | 214 | update_post_meta( $reply_id, '_bbp_reply_is_best_answer', '1' ); |
| 186 | - } else { | |
| 215 | + } elseif ( get_post_meta( $reply_id, '_bbp_reply_is_best_answer', true ) ) { | |
| 216 | + // Only clear the topic flag when this reply was the best answer; | |
| 217 | + // saving any other reply must not wipe it. | |
| 187 | 218 | delete_post_meta( $reply_id, '_bbp_reply_is_best_answer' ); |
| 188 | 219 | delete_post_meta( $topic_id, '_bbp_topic_has_best_answer' ); |
| 189 | 220 | } |
| 190 | 221 | |
| @@ -201,9 +232,9 @@ | ||
| 201 | 232 | * @return void |
| 202 | 233 | */ |
| 203 | 234 | public function update_topic( $topic_id = 0, $is_edit = false ) { |
| 204 | 235 | |
| 205 | - if ( isset( $_POST['bbp_solved_topic'] ) ) { | |
| 236 | + if ( isset( $_POST['forumax_solve_topic'] ) ) { | |
| 206 | 237 | update_post_meta( $topic_id, '_bbp_topic_is_solved', '1' ); |
| 207 | 238 | } else { |
| 208 | 239 | delete_post_meta( $topic_id, '_bbp_topic_is_solved' ); |
| 209 | 240 | } |
| @@ -288,9 +319,15 @@ | ||
| 288 | 319 | * |
| 289 | 320 | * @return bool |
| 290 | 321 | */ |
| 291 | 322 | public function has_best_answer( $topic_id = 0 ) { |
| 323 | + | |
| 324 | + // if bbpress is not active, return the classes | |
| 292 | 325 | |
| 326 | + if ( ! function_exists( 'bbp_get_topic_id' ) ) { | |
| 327 | + return false; | |
| 328 | + } | |
| 329 | + | |
| 293 | 330 | $retval = false; |
| 294 | 331 | |
| 295 | 332 | // Checking a specific reply id. |
| 296 | 333 | if ( ! empty( $topic_id ) ) { |
| @@ -332,9 +369,9 @@ | ||
| 332 | 369 | |
| 333 | 370 | $topic_id = bbp_get_topic_id(); |
| 334 | 371 | |
| 335 | 372 | if ( $this->is_best_answer( $reply_id ) ) { |
| 336 | - $content = '<div class="solved-topic-bar" id="best-answer"><span class="badge"><i class="icon_check"></i> ' . esc_html__( 'Best Answer', 'ama-core' ) . '</span></div>' . $content; | |
| 373 | + $content = '<div class="solved-topic-bar" id="best-answer"><span class="badge"><i class="icon_check"></i> ' . esc_html__( 'Best Answer', 'forumax' ) . '</span></div>' . $content; | |
| 337 | 374 | } |
| 338 | 375 | |
| 339 | 376 | return $content; |
| 340 | 377 | } |
| @@ -365,9 +402,9 @@ | ||
| 365 | 402 | $close = '</div>'; |
| 366 | 403 | } |
| 367 | 404 | |
| 368 | 405 | if ( $this->is_solved( $topic_id ) ) { |
| 369 | - $resolved = '<span class="accepted-ans-mark"><i class="icon_check_alt"></i> ' . esc_html__( 'Resolved', 'ama-core' ) . '</span>'; | |
| 406 | + $resolved = '<span class="accepted-ans-mark badge"><i class="icon_check_alt"></i> ' . esc_html__( 'Resolved', 'forumax' ) . '</span>'; | |
| 370 | 407 | } |
| 371 | 408 | |
| 372 | 409 | $content = $content . $open . $resolved . $has_best_answer . $close; |
| 373 | 410 | |
| @@ -383,8 +420,14 @@ | ||
| 383 | 420 | * |
| 384 | 421 | * @return bool |
| 385 | 422 | */ |
| 386 | 423 | public function reply_post_class( $classes ) { |
| 424 | + | |
| 425 | + // if bbpress is not active, return the classes | |
| 426 | + if ( ! function_exists( 'bbp_get_reply_id' ) ) { | |
| 427 | + return $classes; | |
| 428 | + } | |
| 429 | + | |
| 387 | 430 | $reply_id = bbp_get_reply_id(); |
| 388 | 431 | |
| 389 | 432 | // Only apply the class to replies. |
| 390 | 433 | if ( bbp_get_reply_post_type() != get_post_type( $reply_id ) ) { |
| @@ -399,9 +442,21 @@ | ||
| 399 | 442 | } |
| 400 | 443 | } |
| 401 | 444 | |
| 402 | 445 | // Instantiate the class. |
| 403 | -$GLOBALS['bbp_solved_topic'] = new bbp_solved_topic(); | |
| 446 | +$GLOBALS['forumax_solve_topic'] = new forumax_solve_topic(); | |
| 404 | 447 | |
| 405 | -function bbp_solved_topic(): bbp_solved_topic { | |
| 406 | - return new bbp_solved_topic(); | |
| 448 | +/** | |
| 449 | + * Shared solved-topic instance. | |
| 450 | + * | |
| 451 | + * Constructing a new instance re-registers every hook, so repeated calls | |
| 452 | + * (once per topic in a loop) duplicated badges and filters. | |
| 453 | + * | |
| 454 | + * @return forumax_solve_topic | |
| 455 | + */ | |
| 456 | +function forumax_solve_topic(): forumax_solve_topic { | |
| 457 | + if ( ! ( $GLOBALS['forumax_solve_topic'] ?? null ) instanceof forumax_solve_topic ) { | |
| 458 | + $GLOBALS['forumax_solve_topic'] = new forumax_solve_topic(); | |
| 459 | + } | |
| 460 | + | |
| 461 | + return $GLOBALS['forumax_solve_topic']; | |
| 407 | 462 | } |