| @@ -1,268 +1,445 @@ | ||
| 1 | -<?php | |
| 2 | - | |
| 3 | -/** | |
| 4 | - * bbPress Replies | |
| 5 | - */ | |
| 6 | -add_filter('bbp_show_lead_topic', function () { | |
| 7 | - $show_lead[] = 'true'; | |
| 8 | - return $show_lead; | |
| 9 | -}); | |
| 10 | - | |
| 11 | -/** | |
| 12 | - * bbPress User Role | |
| 13 | - */ | |
| 14 | -if ( ! function_exists( 'forumax_bbp_user_role_icon' ) ) { | |
| 15 | - function forumax_bbp_user_role_icon() { | |
| 16 | - $author_role = bbp_get_user_display_role( bbp_get_reply_author_id() ); | |
| 17 | - switch ( $author_role ) { | |
| 18 | - case 'Keymaster': | |
| 19 | - get_image_from_settings( 'keymaster_icon' ); | |
| 20 | - break; | |
| 21 | - case 'Moderator': | |
| 22 | - get_image_from_settings( 'moderator_icon' ); | |
| 23 | - break; | |
| 24 | - case 'Participant': | |
| 25 | - get_image_from_settings( 'participant_icon' ); | |
| 26 | - break; | |
| 27 | - case 'Spectator': | |
| 28 | - get_image_from_settings( 'spectator_icon' ); | |
| 29 | - break; | |
| 30 | - case 'Blocked': | |
| 31 | - get_image_from_settings( 'blocked_icon' ); | |
| 32 | - break; | |
| 33 | - } | |
| 34 | - } | |
| 35 | -} | |
| 36 | - | |
| 37 | -/** | |
| 38 | - * Get author role | |
| 39 | - */ | |
| 40 | -if (!function_exists('forumax_get_bbp_user_role')) { | |
| 41 | -function forumax_get_bbp_user_role() { | |
| 42 | - $role = bbp_get_topic_author_role( array( | |
| 43 | - 'topic_id' => get_the_ID(), | |
| 44 | - 'before' => '', | |
| 45 | - 'after' => '', | |
| 46 | - )); | |
| 47 | - return $role; | |
| 48 | -} | |
| 49 | -} | |
| 50 | - | |
| 51 | -/** | |
| 52 | - * Get topic reply count | |
| 53 | - */ | |
| 54 | -if (!function_exists('forumax_topic_reply_count')) { | |
| 55 | -function forumax_topic_reply_count() { | |
| 56 | - $get_reply = get_post_meta( get_the_ID(), '_bbp_reply_count', true ); | |
| 57 | - $_reply_count = isset( $get_reply ) && !empty( $get_reply ) ? $get_reply : 0; | |
| 58 | - echo esc_html( $_reply_count ); | |
| 59 | -} | |
| 60 | -} | |
| 61 | - | |
| 62 | -/** | |
| 63 | - * Display bbp_reply_admin_links() as a dropdown list. The dropdown will be shown on click on a vertical three dots icon. | |
| 64 | - * Create a new function to display the dropdown. | |
| 65 | - */ | |
| 66 | -if ( ! function_exists( 'forumax_get_reply_admin_links' ) ) { | |
| 67 | -function forumax_get_reply_admin_links( $args = array() ) { | |
| 68 | - | |
| 69 | - // Parse arguments against default values | |
| 70 | - $r = bbp_parse_args( $args, array( | |
| 71 | - 'id' => 0, | |
| 72 | - 'before' => '<div class="bbp-admin-links-dropdown">', | |
| 73 | - 'after' => '</div>', | |
| 74 | - 'sep' => '', | |
| 75 | - 'links' => array() | |
| 76 | - ), 'get_reply_admin_links' ); | |
| 77 | - | |
| 78 | - $r['id'] = bbp_get_reply_id( $r['id'] ); | |
| 79 | - | |
| 80 | - // If post is a topic, return the topic admin links instead | |
| 81 | - if ( bbp_is_topic( $r['id'] ) ) { | |
| 82 | - return forumax_get_topic_admin_links( $args ); | |
| 83 | - } | |
| 84 | - | |
| 85 | - // If post is not a reply, return | |
| 86 | - if ( ! bbp_is_reply( $r['id'] ) ) { | |
| 87 | - return; | |
| 88 | - } | |
| 89 | - | |
| 90 | - // If topic is trashed, do not show admin links | |
| 91 | - if ( bbp_is_topic_trash( bbp_get_reply_topic_id( $r['id'] ) ) ) { | |
| 92 | - return; | |
| 93 | - } | |
| 94 | - | |
| 95 | - // If no links were passed, default to the standard | |
| 96 | - if ( empty( $r['links'] ) ) { | |
| 97 | - $r['links'] = apply_filters( 'bbp_reply_admin_links', array( | |
| 98 | - 'edit' => bbp_get_reply_edit_link ( $r ), | |
| 99 | - 'move' => bbp_get_reply_move_link ( $r ), | |
| 100 | - 'split' => bbp_get_topic_split_link ( $r ), | |
| 101 | - 'trash' => bbp_get_reply_trash_link ( $r ), | |
| 102 | - 'spam' => bbp_get_reply_spam_link ( $r ), | |
| 103 | - 'approve' => bbp_get_reply_approve_link( $r ), | |
| 104 | - 'reply' => bbp_get_reply_to_link ( $r ) | |
| 105 | - ), $r['id'] ); | |
| 106 | - } | |
| 107 | - | |
| 108 | - // See if links need to be unset | |
| 109 | - $reply_status = bbp_get_reply_status( $r['id'] ); | |
| 110 | - if ( in_array( $reply_status, array( bbp_get_spam_status_id(), bbp_get_trash_status_id(), bbp_get_pending_status_id() ), true ) ) { | |
| 111 | - | |
| 112 | - // Spam link shouldn't be visible on trashed topics | |
| 113 | - if ( bbp_get_trash_status_id() === $reply_status ) { | |
| 114 | - unset( $r['links']['spam'] ); | |
| 115 | - | |
| 116 | - // Trash link shouldn't be visible on spam topics | |
| 117 | - } elseif ( bbp_get_spam_status_id() === $reply_status ) { | |
| 118 | - unset( $r['links']['trash'] ); | |
| 119 | - } | |
| 120 | - } | |
| 121 | - | |
| 122 | - // Build our dropdown menu structure | |
| 123 | - $menu = '<select name="reply-admin-links" class="nice-select bbp-admin-dropdown-menu" onchange="if(this.value) window.location.href=this.value;">'; | |
| 124 | - | |
| 125 | - // Process each link as a menu item | |
| 126 | - $menu .= '<option value="" disabled selected>' . esc_html__( 'Select an option', 'forumax' ) . '</option>'; | |
| 127 | - foreach ( array_filter( $r['links'] ) as $link ) { | |
| 128 | - // Extract href attribute from the link | |
| 129 | - preg_match('/href=(["\'])([^"\']+)\\1/', $link, $matches); | |
| 130 | - $href = !empty($matches[2]) ? $matches[2] : ''; | |
| 131 | - | |
| 132 | - // Add the option with value attribute containing the URL | |
| 133 | - $menu .= '<option value="' . esc_url($href) . '" class="bbp-admin-dropdown-item">' . wp_strip_all_tags($link) . '</option>'; | |
| 134 | - } | |
| 135 | - | |
| 136 | - $menu .= '</select>'; | |
| 137 | - | |
| 138 | - $retval = $r['before'] . $menu . $r['after']; | |
| 139 | - | |
| 140 | - // Filter & return | |
| 141 | - if ( is_user_logged_in() ) { | |
| 142 | - return apply_filters( 'forumax_bbp_get_reply_admin_links', $retval, $r, $args ); | |
| 143 | - } | |
| 144 | -} | |
| 145 | -} | |
| 146 | - | |
| 147 | -/** | |
| 148 | - * Similar function for topics - to handle the case where a topic is passed to the reply function | |
| 149 | - */ | |
| 150 | -if ( ! function_exists( 'forumax_get_topic_admin_links' ) ) { | |
| 151 | - function forumax_get_topic_admin_links( $args = array() ) { | |
| 152 | - // Parse arguments against default values | |
| 153 | - $r = bbp_parse_args( $args, array( | |
| 154 | - 'id' => 0, | |
| 155 | - 'before' => '<div class="bbp-admin-links-dropdown">', | |
| 156 | - 'after' => '</div>', | |
| 157 | - 'sep' => '', | |
| 158 | - 'links' => array() | |
| 159 | - ), 'get_topic_admin_links' ); | |
| 160 | - | |
| 161 | - $r['id'] = bbp_get_topic_id( $r['id'] ); | |
| 162 | - | |
| 163 | - // If not a topic, then return | |
| 164 | - if ( ! bbp_is_topic( $r['id'] ) ) { | |
| 165 | - return; | |
| 166 | - } | |
| 167 | - | |
| 168 | - // If no links were passed, get the default ones | |
| 169 | - if ( empty( $r['links'] ) ) { | |
| 170 | - $r['links'] = apply_filters( 'bbp_topic_admin_links', array( | |
| 171 | - 'edit' => bbp_get_topic_edit_link ( $r ), | |
| 172 | - 'close' => bbp_get_topic_close_link ( $r ), | |
| 173 | - 'stick' => bbp_get_topic_stick_link ( $r ), | |
| 174 | - 'merge' => bbp_get_topic_merge_link ( $r ), | |
| 175 | - 'trash' => bbp_get_topic_trash_link ( $r ), | |
| 176 | - 'spam' => bbp_get_topic_spam_link ( $r ), | |
| 177 | - 'approve' => bbp_get_topic_approve_link( $r ), | |
| 178 | - 'reply' => bbp_get_topic_reply_link ( $r ) | |
| 179 | - ), $r['id'] ); | |
| 180 | - } | |
| 181 | - | |
| 182 | - // See if links need to be unset | |
| 183 | - $topic_status = bbp_get_topic_status( $r['id'] ); | |
| 184 | - if ( in_array( $topic_status, array( bbp_get_spam_status_id(), bbp_get_trash_status_id(), bbp_get_pending_status_id() ), true ) ) { | |
| 185 | - | |
| 186 | - // Spam link shouldn't be visible on trashed topics | |
| 187 | - if ( bbp_get_trash_status_id() === $topic_status ) { | |
| 188 | - unset( $r['links']['spam'] ); | |
| 189 | - | |
| 190 | - // Trash link shouldn't be visible on spam topics | |
| 191 | - } elseif ( bbp_get_spam_status_id() === $topic_status ) { | |
| 192 | - unset( $r['links']['trash'] ); | |
| 193 | - } | |
| 194 | - } | |
| 195 | - | |
| 196 | - // Build our dropdown menu structure | |
| 197 | - $menu = '<select name="topic-admin-links" class="nice-select bbp-admin-dropdown-menu" onchange="if(this.value) window.location.href=this.value;">'; | |
| 198 | - $menu .= '<option value="" disabled selected>Select an option</option>'; | |
| 199 | - | |
| 200 | - // Process each link as a menu item | |
| 201 | - foreach ( array_filter( $r['links'] ) as $link ) { | |
| 202 | - // Extract href attribute from the link | |
| 203 | - preg_match('/href=(["\'])([^"\']+)\\1/', $link, $matches); | |
| 204 | - $href = !empty($matches[2]) ? $matches[2] : ''; | |
| 205 | - | |
| 206 | - // Add the option with value attribute containing the URL | |
| 207 | - $menu .= '<option value="' . esc_url($href) . '" class="bbp-admin-dropdown-item">' . wp_strip_all_tags($link) . '</option>'; | |
| 208 | - } | |
| 209 | - | |
| 210 | - $menu .= '</select>'; | |
| 211 | - | |
| 212 | - $retval = $r['before'] . $menu . $r['after']; | |
| 213 | - | |
| 214 | - // Filter & return | |
| 215 | - return apply_filters( 'forumax_bbp_get_topic_admin_links', $retval, $r, $args ); | |
| 216 | - } | |
| 217 | -} | |
| 218 | -/** | |
| 219 | - * Enqueue the script for sorting bbPress replies | |
| 220 | - */ | |
| 221 | -if ( ! function_exists( 'forumax_enqueue_bbp_replies_sorting_script' ) ) { | |
| 222 | - function forumax_enqueue_bbp_replies_sorting_script() { | |
| 223 | - wp_localize_script('bbp-replies-sorting', 'bbp_reply_ajax_obj', array( | |
| 224 | - 'ajax_url' => admin_url('admin-ajax.php'), | |
| 225 | - 'bbp_topic_id' => get_the_ID(), | |
| 226 | - )); | |
| 227 | - } | |
| 228 | - add_action('wp_enqueue_scripts', 'forumax_enqueue_bbp_replies_sorting_script'); | |
| 229 | -} | |
| 230 | - | |
| 231 | -if ( ! function_exists( 'forumax_ajax_sort_bbp_replies' ) ) { | |
| 232 | - function forumax_ajax_sort_bbp_replies() { | |
| 233 | - if (empty($_POST['topic_id'])) { | |
| 234 | - wp_send_json_error(['message' => 'No topic ID provided.']); | |
| 235 | - } | |
| 236 | - $topic_id = intval($_POST['topic_id']); | |
| 237 | - $sort = isset($_POST['sort']) ? sanitize_text_field($_POST['sort']) : 'desc'; | |
| 238 | - // Set $_GET['sort'] for the filter to pick up | |
| 239 | - $_GET['sort'] = $sort; | |
| 240 | - | |
| 241 | - // Start output buffering to capture the replies loop HTML | |
| 242 | - ob_start(); | |
| 243 | - // Set up bbPress replies loop manually for AJAX context | |
| 244 | - $replies_args = array( | |
| 245 | - 'post_parent' => $topic_id, | |
| 246 | - 'post_type' => bbp_get_reply_post_type(), | |
| 247 | - 'orderby' => ($sort === 'vote' ? 'meta_value_num' : 'date'), | |
| 248 | - 'order' => ($sort === 'asc' ? 'ASC' : 'DESC'), | |
| 249 | - 'meta_key' => ($sort === 'vote' ? 'bbp_voting_score' : ''), | |
| 250 | - 'posts_per_page' => -1, | |
| 251 | - ); | |
| 252 | - if (bbp_has_replies($replies_args)) { | |
| 253 | - while (bbp_replies()) : bbp_the_reply(); | |
| 254 | - $template_file = plugin_dir_path( __FILE__ ) . '../templates/loop-single-reply.php'; | |
| 255 | - if ( file_exists( $template_file ) ) { | |
| 256 | - include $template_file; | |
| 257 | - } | |
| 258 | - endwhile; | |
| 259 | - } else { | |
| 260 | - echo '<div>No replies found.</div>'; | |
| 261 | - } | |
| 262 | - $html = ob_get_clean(); | |
| 263 | - | |
| 264 | - wp_send_json_success(['html' => $html]); | |
| 265 | - } | |
| 266 | - add_action('wp_ajax_sort_bbp_replies', 'forumax_ajax_sort_bbp_replies'); | |
| 267 | - add_action('wp_ajax_nopriv_sort_bbp_replies', 'forumax_ajax_sort_bbp_replies'); | |
| 268 | -} | |
| 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( ' | ', '', $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 ); | |