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
bbp-core / includes / classes / Forumax_Forum_Class.php

Forumax_Forum_Class.php in Forumax – AI Powered Advanced Community Forum Plugin 2.2.0, at includes/classes/Forumax_Forum_Class.php

355 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Forumax theme helper functions and resources
4 */
5 if ( !class_exists( 'Forumax_Forum_Class' ) ) {
6 class Forumax_Forum_Class {
7 /**
8 * Hold an instance of Forumax_Forum_Class class.
9 * @var Forumax_Forum_Class
10 */
11 protected static $instance = null;
12
13 /**
14 * Main Forumax_Forum_Class instance.
15 * @return Forumax_Forum_Class - Main instance.
16 */
17 public static function instance() {
18
19 if ( null === self::$instance ) {
20 self::$instance = new Forumax_Forum_Class();
21 }
22
23 return self::$instance;
24 }
25 /**
26 * Adds a reference of this object to $instance, populates default strings,
27 * @see __construct
28 */
29 public function __construct() {
30 add_filter( 'the_posts', [ $this, 'inject_sticky_topics' ], 10, 2 );
31
32 // Cache invalidation hooks
33 add_action( 'bbp_new_topic', [ $this, 'invalidate_forum_caches' ], 10, 2 );
34 add_action( 'bbp_edit_topic', [ $this, 'invalidate_forum_caches' ], 10, 2 );
35 add_action( 'bbp_closed_topic', [ $this, 'invalidate_forum_caches' ], 10, 2 );
36 add_action( 'bbp_opened_topic', [ $this, 'invalidate_forum_caches' ], 10, 2 );
37 add_action( 'bbp_trash_topic', [ $this, 'maybe_invalidate_forum_caches' ] );
38 add_action( 'bbp_untrash_topic', [ $this, 'maybe_invalidate_forum_caches' ] );
39 add_action( 'bbp_deleted_topic', [ $this, 'maybe_invalidate_forum_caches' ] );
40 }
41
42 /**
43 * Authors Name
44 *
45 * @return string
46 */
47 public static function forum_topics_authors() {
48 global $wpdb;
49
50 $forum_id = get_queried_object_id();
51 $cache_key = 'frmx_authors_data_' . $forum_id;
52 $display_authors = get_transient( $cache_key );
53
54 if ( false === $display_authors ) {
55 $d_users = [];
56 $forumusers = get_users();
57
58 if ( $forumusers ) {
59 foreach ( $forumusers as $forumuser ) {
60 $post_count = count_user_posts( $forumuser->ID, 'topic' );
61 $d_users[$forumuser->ID] = $post_count;
62 }
63 arsort( $d_users );
64
65 // Optimization: Fetch all counts for the current parent in one query
66 $author_counts = [];
67 if ( ! empty( $d_users ) ) {
68 $sql = $wpdb->prepare( "
69 SELECT post_author, COUNT(*) as count
70 FROM $wpdb->posts
71 WHERE post_type = 'topic'
72 AND post_status = 'publish'
73 AND post_parent = %d
74 GROUP BY post_author
75 ", $forum_id );
76
77 $results = $wpdb->get_results( $sql );
78 if ( $results ) {
79 foreach ( $results as $row ) {
80 $author_counts[ $row->post_author ] = $row->count;
81 }
82 }
83 }
84
85 $display_authors = [];
86 foreach ( $d_users as $key => $value ) {
87 // Use pre-fetched count
88 $users_post_count = isset( $author_counts[ $key ] ) ? $author_counts[ $key ] : 0;
89
90 if ( $users_post_count > 0 ) {
91 $display_authors[] = [
92 'ID' => $key,
93 'count' => $users_post_count
94 ];
95 }
96 }
97
98 set_transient( $cache_key, $display_authors, HOUR_IN_SECONDS );
99 }
100 }
101
102 if ( ! empty( $display_authors ) ) {
103 foreach ( $display_authors as $author_data ) {
104 $user_id = $author_data['ID'];
105 $user = get_userdata( $user_id );
106
107 if ( ! $user ) {
108 continue;
109 }
110
111 $post_count = $author_data['count'];
112
113 echo '<div class="userlist">';
114 echo '<a class="frmx-dropdown-item current-user forumax-data data-auth" data-nonce="' . wp_create_nonce( 'forumax-nonce' ) . '" data-rel="' . esc_attr( $user->display_name ) . '" data-type="author" data-count="' . esc_attr( $post_count ) . '" data-parent="' . esc_attr( $forum_id ) . '" data-id="' . intval( $user_id ) . '" href="#' . esc_attr( $user->display_name ) . '">
115 <img src="' . esc_url( get_avatar_url( $user_id ) ) . '" alt="' . esc_attr( $user->display_name ) . '">' . esc_html( $user->display_name ) . '<span class="count">' . esc_html( $post_count ) . '</span>
116 </a>';
117 echo '</div>';
118 }
119 }
120 }
121
122 /**
123 * Tag Name
124 *
125 * @return string
126 */
127 public static function forum_topics_tags() {
128 global $wpdb;
129
130 $forum_id = get_queried_object_id();
131 $cache_key = 'frmx_tags_data_' . $forum_id;
132 $tags = get_transient( $cache_key );
133
134 if ( false === $tags ) {
135 $tags = $wpdb->get_results( $wpdb->prepare(
136 "SELECT DISTINCT t.term_id, t.name, t.slug, tt.count
137 FROM {$wpdb->terms} AS t
138 INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
139 INNER JOIN {$wpdb->term_relationships} AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
140 INNER JOIN {$wpdb->posts} AS p ON tr.object_id = p.ID
141 WHERE tt.taxonomy = 'topic-tag'
142 AND p.post_type = 'topic'
143 AND p.post_parent = %d
144 AND p.post_status = 'publish'
145 ORDER BY t.name ASC",
146 $forum_id
147 ) );
148
149 set_transient( $cache_key, $tags, HOUR_IN_SECONDS );
150 }
151
152 if ( $tags ) {
153 foreach ( $tags as $tag ) {
154 $post_count = $tag->count;
155 echo '<div class="tagList" id="' . esc_attr( $tag->slug ) . '">';
156 echo '<a class="frmx-dropdown-item forumax-data data-tag" data-parent="' . esc_attr( $forum_id ) . '" data-nonce="' . wp_create_nonce( 'forumax-nonce' ) . '" data-rel="' . esc_attr( $tag->slug ) . '" data-type="tag" data-count="' . esc_attr( $post_count ) . '" data-id="' . intval( $tag->term_id ) . '" href="#' . esc_attr( $tag->slug ) . '"><span class="color-purple"></span>' . esc_html( $tag->name ) . '</a>';
157 echo '</div>';
158 }
159 }
160 }
161
162 /**
163 * Invalidate forum caches when a topic is updated.
164 *
165 * @param int $topic_id Topic ID.
166 * @param int $forum_id Optional. Forum ID.
167 */
168 public function invalidate_forum_caches( $topic_id, $forum_id = 0 ) {
169 if ( ! $forum_id ) {
170 $forum_id = bbp_get_topic_forum_id( $topic_id );
171 }
172
173 if ( $forum_id ) {
174 delete_transient( 'frmx_authors_data_' . $forum_id );
175 delete_transient( 'frmx_tags_data_' . $forum_id );
176 delete_transient( 'frmx_topic_count_publish_' . $forum_id );
177 delete_transient( 'frmx_topic_count_closed_' . $forum_id );
178 }
179 }
180
181 /**
182 * Maybe invalidate forum caches when a post is trashed/untrashed/deleted.
183 *
184 * @param int $post_id Post ID.
185 */
186 public function maybe_invalidate_forum_caches( $post_id ) {
187 if ( 'topic' === get_post_type( $post_id ) ) {
188 $this->invalidate_forum_caches( $post_id );
189 }
190 }
191
192 /**
193 * Tag Name
194 *
195 * @return void
196 */
197 public static function forum_topics_open_close(): void
198 {
199 $is_queried_obj = is_singular('forum') ? get_queried_object_id() : false;
200 $user_id = is_singular('forum') ? false : bbp_get_displayed_user_field('ID');
201
202 // Get the active tab from the URL or default to 'open'
203 $active_tab = isset($_GET['tab']) && in_array($_GET['tab'], ['open', 'closed'], true) ? sanitize_text_field($_GET['tab']) : 'open';
204
205 // Count open and closed topics efficiently
206 $open_count = forumax_get_topic_count_by_status('publish', $is_queried_obj);
207 $closed_count = forumax_get_topic_count_by_status('closed', $is_queried_obj);
208
209 if ( in_array('bbp-user-page', get_body_class(), true) ) :
210 ?>
211 <ul class="support-total-info">
212 <li class="open-ticket">
213 <?php esc_html_e( 'TOPIC', 'forumax' ); ?>
214 </li>
215 </ul>
216 <ul class="category-menu">
217 <li> <?php esc_html_e( 'Comments', 'forumax' ); ?> </li>
218 <li> <?php esc_html_e( 'Favorites', 'forumax' ); ?> </li>
219 </ul>
220 <?php
221 else :
222 ?>
223 <ul class="support-total-info">
224 <li class="open-ticket <?php echo 'open' === $active_tab ? 'active' : ''; ?>">
225 <i class="icon_info_alt"></i>
226 <a href="?tab=open"
227 class="open-data"
228 data-nonce="<?php echo wp_create_nonce( 'forumax-nonce' );?>"
229 data-type="open"
230 data-userid="<?php echo esc_attr($user_id); ?>"
231 data-parent="<?php echo esc_attr($is_queried_obj); ?>">
232 <?php echo esc_html($open_count) . esc_html__(' Open', 'forumax'); ?>
233 </a>
234 </li>
235 <li class="close-ticket <?php echo 'closed' === $active_tab ? 'active' : ''; ?>">
236 <i class="icon_check"></i>
237 <a href="?tab=closed"
238 class="open-data"
239 data-nonce="<?php echo wp_create_nonce( 'forumax-nonce' );?>"
240 data-type="closed"
241 data-parent="<?php echo esc_attr($is_queried_obj); ?>"
242 data-userid="<?php echo esc_attr($user_id); ?>">
243 <?php echo esc_html($closed_count) . esc_html__(' Closed', 'forumax'); ?>
244 </a>
245 </li>
246 </ul>
247 <?php
248 endif;
249 }
250
251 function topic_badges() {
252 if( bbp_is_topic_sticky(get_the_ID()) ) { ?>
253 <span class="badge badge-success">
254 <?php esc_html_e( 'Sticky', 'forumax' ); ?>
255 </span>
256 <?php }
257 if ( bbp_is_topic_closed( get_the_ID() ) ) { ?>
258 <span class="badge badge-danger">
259 <?php esc_html_e( 'Closed', 'forumax' ); ?>
260 </span>
261 <?php }
262 }
263
264 /**
265 * Inject sticky topics into the main topic loop
266 *
267 * @param array $posts The array of retrieved posts.
268 * @param WP_Query $query The WP_Query instance.
269 */
270 public function inject_sticky_topics( $posts, $query ) {
271 if ( is_admin() || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ) {
272 return $posts;
273 }
274
275 // Identify the target query: Topics ordered by ID (as in loop-topics.php )
276 if ( $query->get( 'post_type' ) !== 'topic' || $query->get( 'orderby' ) !== 'ID' ) {
277 return $posts;
278 }
279
280 // Only on first page
281 if ( $query->get( 'paged' ) > 1 ) {
282 return $posts;
283 }
284
285 // Prevent recursion
286 remove_filter( 'the_posts', [$this, 'inject_sticky_topics'], 10 );
287
288 $sticky_ids = [];
289
290 // Get Super Stickies
291 $super_stickies = bbp_get_super_stickies();
292
293 // Get Forum Stickies
294 $forum_id = 0;
295 if ( is_singular( 'forum' ) ) {
296 $forum_id = get_queried_object_id();
297 } elseif ( $query->get( 'post_parent' ) ) {
298 $post_parent = $query->get( 'post_parent' );
299 if ( is_numeric( $post_parent ) && $post_parent > 0 ) {
300 $forum_id = $post_parent;
301 }
302 }
303
304 $stickies = bbp_get_stickies( $forum_id );
305
306 $sticky_ids = array_unique(array_merge( $super_stickies, $stickies ) );
307
308 if ( ! empty( $sticky_ids ) ) {
309 $sticky_args = [
310 'post_type' => 'topic',
311 'post_parent' => 'any',
312 'post__in' => $sticky_ids,
313 'posts_per_page' => -1,
314 'orderby' => 'post__in',
315 'ignore_sticky_posts' => 1,
316 'no_found_rows' => true,
317 ];
318
319 $sticky_query = new WP_Query( $sticky_args );
320
321 if ( $sticky_query->have_posts() ) {
322 $sticky_posts = $sticky_query->posts;
323
324 // Filter out stickies from the main posts to avoid duplicates
325 $posts = array_filter( $posts, function ( $p ) use ( $sticky_ids ) {
326 return !in_array( $p->ID, $sticky_ids, true );
327 });
328
329 // Prepend stickies
330 $posts = array_merge( $sticky_posts, $posts );
331 }
332 }
333
334 add_filter( 'the_posts', [ $this, 'inject_sticky_topics'], 10, 2 );
335
336 return $posts;
337 }
338 }
339 }
340
341 /**
342 * Get Forumax Forum Class instance
343 * Works with or without Forumax theme active
344 *
345 * @return Forumax_Forum_Class|null
346 */
347 if ( ! function_exists( 'Forumax_Forum' ) ) {
348 function Forumax_Forum() {
349 if ( class_exists( 'Forumax_Forum_Class' ) ) {
350 return Forumax_Forum_Class::instance();
351 }
352 return null;
353 }
354 }
355