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/ajax_actions.php +135 -91 2.4.0 → 2.5.1 View file →
@@ -13,8 +13,43 @@
13 13 add_action( 'wp_ajax_forumax_search_data_fetch', 'forumax_search_data_fetch' );
14 14 add_action( 'wp_ajax_nopriv_forumax_search_data_fetch', 'forumax_search_data_fetch' );
15 15
16 16 /**
17 + * Build the ancestor "breadcrumb" trail for a search result, mirroring the
18 + * EazyDocs search UI (e.g. Forum › Topic for a reply).
19 + *
20 + * @param int $post_id Post ID.
21 + * @param string $type Post type of the result.
22 + * @return array List of ancestor titles, ordered from top-most down.
23 + */
24 +function forumax_search_result_breadcrumb( $post_id, $type ) {
25 + $crumbs = array();
26 +
27 + if ( 'reply' === $type && function_exists( 'bbp_get_reply_forum_id' ) ) {
28 + $forum_id = bbp_get_reply_forum_id( $post_id );
29 + $topic_id = bbp_get_reply_topic_id( $post_id );
30 + if ( $forum_id ) {
31 + $crumbs[] = get_the_title( $forum_id );
32 + }
33 + if ( $topic_id ) {
34 + $crumbs[] = get_the_title( $topic_id );
35 + }
36 + } elseif ( 'topic' === $type && function_exists( 'bbp_get_topic_forum_id' ) ) {
37 + $forum_id = bbp_get_topic_forum_id( $post_id );
38 + if ( $forum_id ) {
39 + $crumbs[] = get_the_title( $forum_id );
40 + }
41 + } else {
42 + // Generic hierarchy fallback (forums with parents, docs, pages, etc.).
43 + foreach ( array_reverse( get_post_ancestors( $post_id ) ) as $ancestor_id ) {
44 + $crumbs[] = get_the_title( $ancestor_id );
45 + }
46 + }
47 +
48 + return array_values( array_filter( $crumbs ) );
49 +}
50 +
51 +/**
17 52 * Fetch search data.
18 53 */
19 54 function forumax_search_data_fetch() {
20 55
@@ -20,31 +55,77 @@
20 55
21 56 // Check nonce.
22 57 check_ajax_referer( 'forumax-nonce', 'nonce' );
23 58
24 - $opt = get_option( 'bbpc_opt' );
25 - $is_ajax_search_tab = $opt['is_ajax_search_tab'] ?? '';
59 + // Sanitize keyword.
60 + $keyword = isset( $_POST['keyword'] ) ? sanitize_text_field( wp_unslash( $_POST['keyword'] ) ) : '';
61 + $post_type = isset( $_POST['post_type'] ) ? sanitize_text_field( wp_unslash( $_POST['post_type'] ) ) : '';
26 62
27 - // Sanitize keyword.
28 - $keyword = isset( $_POST['keyword'] ) ? sanitize_text_field( $_POST['keyword'] ) : '';
29 - $post_type = isset( $_POST['post_type'] ) ? sanitize_text_field( $_POST['post_type'] ) : '';
63 + // Determine which post types to query. An explicit single post type narrows
64 + // the search; 'all' (or no value) searches the whole forum: forums, topics
65 + // and replies, so content matches from any of them are returned.
66 + // Only public post types may be searched; anything else falls back to the
67 + // forum-wide search instead of exposing non-public content.
68 + $post_type_object = ( ! empty( $post_type ) && 'all' !== $post_type ) ? get_post_type_object( $post_type ) : null;
30 69
31 - // Determine which post types to query.
32 - if ( ! empty( $post_type ) ) {
70 + if ( $post_type_object && $post_type_object->public ) {
33 71 $query_post_types = array( $post_type );
34 72 } elseif ( class_exists( 'bbPress' ) ) {
35 - $query_post_types = array( 'forum', 'topic' );
73 + $query_post_types = array( 'forum', 'topic', 'reply' );
36 74 } else {
37 75 $query_post_types = array( 'post' );
38 76 }
39 77
78 + // Determine which statuses to include. bbPress stores closed topics with the
79 + // 'closed' post status, which WP_Query's default 'publish'-only behavior skips.
80 + // Private/hidden forums are only searchable by users allowed to read them.
81 + if ( class_exists( 'bbPress' ) ) {
82 + $query_post_status = array( 'publish', 'closed' );
83 +
84 + if ( current_user_can( 'read_private_forums' ) ) {
85 + $query_post_status[] = 'private';
86 + }
87 +
88 + if ( current_user_can( 'read_hidden_forums' ) ) {
89 + $query_post_status[] = 'hidden';
90 + }
91 + } else {
92 + $query_post_status = array( 'publish' );
93 + }
94 +
95 + // Force the search to match BOTH the title and the content. This overrides
96 + // any other plugin/theme `posts_search` filter that may otherwise restrict
97 + // matching to titles only, so content keywords return results too.
98 + $bbpc_search_clause = static function ( $search, $wp_query ) use ( $keyword ) {
99 + global $wpdb;
100 +
101 + if ( '' === $keyword || ! $wp_query->get( 'bbpc_ajax_search' ) ) {
102 + return $search;
103 + }
104 +
105 + $like = '%' . $wpdb->esc_like( $keyword ) . '%';
106 +
107 + return $wpdb->prepare(
108 + " AND ( {$wpdb->posts}.post_title LIKE %s OR {$wpdb->posts}.post_content LIKE %s ) ",
109 + $like,
110 + $like
111 + );
112 + };
113 +
114 + add_filter( 'posts_search', $bbpc_search_clause, 999, 2 );
115 +
40 116 // Main results query.
41 117 $results = new \WP_Query( array(
42 - 'post_type' => $query_post_types,
43 - 's' => $keyword,
44 - 'posts_per_page' => 10,
118 + 'post_type' => $query_post_types,
119 + 'post_status' => $query_post_status,
120 + 's' => $keyword,
121 + 'posts_per_page' => 10,
122 + 'bbpc_ajax_search' => true,
123 + 'update_post_term_cache' => false,
45 124 ) );
46 125
126 + remove_filter( 'posts_search', $bbpc_search_clause, 999 );
127 +
47 128 $results_count = $results->found_posts;
48 129
49 130 if ( $results_count > 0 ) {
50 131 $nsoresult = 'data-result=';
@@ -68,11 +149,12 @@
68 149 if ( ! isset( $grouped[ $type ] ) ) {
69 150 $grouped[ $type ] = array();
70 151 }
71 152 $grouped[ $type ][] = array(
72 - 'id' => get_the_ID(),
73 - 'title' => get_the_title(),
74 - 'url' => get_the_permalink(),
153 + 'id' => get_the_ID(),
154 + 'title' => get_the_title(),
155 + 'url' => get_the_permalink(),
156 + 'breadcrumb' => forumax_search_result_breadcrumb( get_the_ID(), $type ),
75 157 );
76 158 endwhile;
77 159 wp_reset_postdata();
78 160
@@ -79,96 +161,58 @@
79 161 // Render grouped results.
80 162 $type_labels = array(
81 163 'forum' => __( 'Forums', 'forumax' ),
82 164 'topic' => __( 'Topics', 'forumax' ),
165 + 'reply' => __( 'Replies', 'forumax' ),
83 166 'docs' => __( 'Documentation', 'forumax' ),
84 167 'post' => __( 'Posts', 'forumax' ),
85 168 );
86 169
170 + // Document icon shared by every result row.
171 + $result_icon = '<svg class="bbpc-result-icon" width="16" height="16" viewBox="0 0 17 17" fill="currentColor" role="img" aria-hidden="true"><path d="M14.72,0H2.28A2.28,2.28,0,0,0,0,2.28V14.72A2.28,2.28,0,0,0,2.28,17H14.72A2.28,2.28,0,0,0,17,14.72V2.28A2.28,2.28,0,0,0,14.72,0ZM2.28,1H14.72A1.28,1.28,0,0,1,16,2.28V5.33H1V2.28A1.28,1.28,0,0,1,2.28,1ZM1,14.72V6.33H5.33V16H2.28A1.28,1.28,0,0,1,1,14.72ZM14.72,16H6.33V6.33H16v8.39A1.28,1.28,0,0,1,14.72,16Z"></path></svg>';
172 +
173 + // Result type tabs (All / Forums / Topics / Replies), mirroring EazyDocs.
174 + ?>
175 + <div class="bbpc-result-tabs">
176 + <button type="button" class="bbpc-tab active" data-tab="all"><?php esc_html_e( 'All', 'forumax' ); ?></button>
177 + <?php foreach ( $grouped as $type => $posts ) :
178 + $tab_label = isset( $type_labels[ $type ] ) ? $type_labels[ $type ] : ucfirst( $type );
179 + ?>
180 + <button type="button" class="bbpc-tab" data-tab="<?php echo esc_attr( $type ); ?>"><?php echo esc_html( $tab_label ); ?></button>
181 + <?php endforeach; ?>
182 + </div>
183 + <?php
184 +
87 185 foreach ( $grouped as $type => $posts ) :
88 186 $label = isset( $type_labels[ $type ] ) ? $type_labels[ $type ] : ucfirst( $type );
89 - echo '<h2 class="bbpc-search-title">' . esc_html( $label ) . '</h2>';
90 - foreach ( $posts as $post_item ) :
91 - ?>
92 - <div class="search-result-item forum" onclick="document.location='<?php echo esc_url( $post_item['url'] ); ?>'">
93 - <a href="<?php echo esc_url( $post_item['url'] ); ?>">
94 - <?php echo esc_html( $post_item['title'] ); ?>
95 - </a>
96 - </div>
97 - <?php
98 - endforeach;
187 + ?>
188 + <div class="bbpc-result-group" data-type="<?php echo esc_attr( $type ); ?>">
189 + <div class="bbpc-result-group-label"><?php echo esc_html( $label ); ?></div>
190 + <?php foreach ( $posts as $post_item ) : ?>
191 + <div class="search-result-item" data-url="<?php echo esc_url( $post_item['url'] ); ?>" onclick="document.location='<?php echo esc_url( $post_item['url'] ); ?>'">
192 + <a href="<?php echo esc_url( $post_item['url'] ); ?>" class="bbpc-result-link">
193 + <?php echo $result_icon; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static markup. ?>
194 + <span class="bbpc-result-body">
195 + <span class="bbpc-result-title"><?php echo esc_html( $post_item['title'] ); ?></span>
196 + <span class="bbpc-result-type"><?php echo esc_html( $label ); ?></span>
197 + </span>
198 + </a>
199 + <?php if ( ! empty( $post_item['breadcrumb'] ) ) : ?>
200 + <ol class="bbpc-result-breadcrumb">
201 + <?php foreach ( $post_item['breadcrumb'] as $crumb ) : ?>
202 + <li class="bbpc-breadcrumb-item"><?php echo esc_html( $crumb ); ?></li>
203 + <?php endforeach; ?>
204 + </ol>
205 + <?php endif; ?>
206 + </div>
207 + <?php endforeach; ?>
208 + </div>
209 + <?php
99 210 endforeach;
100 211 endif;
101 212
102 213 echo '</div>';
103 - echo '<h5 class="not-found-text">' . esc_html__( 'Not Found Result!', 'forumax' ) . '</h5>';
104 214 echo '</div>';
105 - wp_die();
106 -}
107 -
108 -/**
109 - * Forum Search results
110 - */
111 -add_action( 'wp_ajax_forumax_search_data_forum', 'forumax_search_data_forum' );
112 -add_action( 'wp_ajax_nopriv_forumax_search_data_forum', 'forumax_search_data_forum' );
113 -
114 -/**
115 - * Search data forum.
116 - */
117 -function forumax_search_data_forum() {
118 -
119 - // Check nonce
120 - check_ajax_referer( 'forumax-nonce', 'nonce' );
121 -
122 - // Sanitize keyword
123 - $keyword = isset( $_POST['keyword'] ) ? sanitize_text_field( $_POST['keyword'] ) : '';
124 -
125 - // Forums query
126 - if ( class_exists( 'bbPress' ) ) :
127 -
128 - echo '<div class="search-results-tab show" id="search-forum-results">';
129 -
130 - $forum = new WP_Query( [
131 - 'post_type' => 'forum',
132 - 's' => $keyword,
133 - 'posts_per_page' => 5,
134 - ] );
135 -
136 - if ( $forum->have_posts() ) :
137 - echo '<h2 class="bbpc-search-title">' . esc_html__( 'Forums', 'forumax' ) . '</h2>';
138 - while ( $forum->have_posts() ) : $forum->the_post();
139 - ?>
140 - <div class="search-result-item forum" onclick="document.location='<?php echo esc_url( get_the_permalink( get_the_ID() ) ); ?>'">
141 - <a href="<?php echo esc_url( get_the_permalink( get_the_ID() ) ); ?>">
142 - <?php the_title(); ?>
143 - </a>
144 - </div>
145 - <?php
146 - endwhile;
147 - wp_reset_postdata();
148 - endif;
149 -
150 - $topics = new WP_Query( [
151 - 'post_type' => 'topic',
152 - 's' => $keyword,
153 - 'posts_per_page' => 5,
154 - ] );
155 -
156 - if ( $topics->have_posts() ) :
157 - echo '<h2 class="bbpc-search-title">' . esc_html__( 'Topics', 'forumax' ) . '</h2>';
158 - while ( $topics->have_posts() ) : $topics->the_post();
159 - ?>
160 - <div class="search-result-item forum" onclick="document.location='<?php echo esc_url( get_the_permalink( get_the_ID() ) ); ?>'">
161 - <a href="<?php echo esc_url( get_the_permalink( get_the_ID() ) ); ?>">
162 - <?php the_title(); ?>
163 - </a>
164 - </div>
165 - <?php
166 - endwhile;
167 - wp_reset_postdata();
168 - endif;
169 - echo '</div>';
170 - endif;
171 215 wp_die();
172 216 }
173 217
174 218 /**