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/bbpc_attachments/code/public.php +216 -82 1.3.0 → 2.5.1 View file →
@@ -1,82 +1,216 @@
1 -<?php
2 -if ( ! defined( 'ABSPATH' ) ) {
3 - exit;
4 -}
5 -
6 -/**
7 - * Get the list of attachments for a post.
8 - *
9 - * @param int $post_id topic or reply ID to get attachments for
10 - *
11 - * @return array list of attachments objects
12 - */
13 -function bbpc_get_post_attachments( $post_id ) {
14 - $args = [
15 - 'post_type' => 'attachment',
16 - 'numberposts' => -1,
17 - 'post_status' => null,
18 - 'post_parent' => $post_id,
19 - 'orderby' => 'ID',
20 - 'order' => 'ASC',
21 - ];
22 -
23 - return get_posts( $args );
24 -}
25 -
26 -/**
27 - * Count attachments for the forum topic. It can include topic replies in the count.
28 - *
29 - * @param int $topic_id id of the topic to count attachments for
30 - * @param bool $include_replies true, to include reply attachments
31 - *
32 - * @return int number of attachments
33 - */
34 -function bbpc_topic_attachments_count( $topic_id, $include_replies = false ) {
35 - global $wpdb;
36 -
37 - $sql = 'select ID from ' . $wpdb->posts . ' where post_parent = ' . $topic_id . " and post_type = 'attachment'";
38 -
39 - if ( $include_replies ) {
40 - $sql = '(' . $sql . ') union (select ID from ' . $wpdb->posts . ' where post_parent in (select ID from ' . $wpdb->posts . ' where post_parent = ' . $topic_id . " and post_type = 'reply') and post_type = 'attachment')";
41 - }
42 -
43 - $attachments = $wpdb->get_results( $sql );
44 - return count( $attachments );
45 -}
46 -
47 -/**
48 - * Handle upload file error.
49 - *
50 - * @param string $file file with error
51 - * @param string $message error message
52 - *
53 - * @return WP_Error error message
54 - */
55 -function bbpc_bbattachment_handle_upload_error( &$file, $message ) {
56 - return new WP_Error( 'wp_upload_error', $message );
57 -}
58 -
59 -/**
60 - * Get current page forum ID. Handles the edge cases with the edit forms.
61 - *
62 - * @return int
63 - */
64 -function bbpc_get_forum_id() {
65 - $forum_id = bbp_get_forum_id();
66 -
67 - if ( $forum_id == 0 ) {
68 - if ( bbp_is_topic_edit() ) {
69 - $topic_id = bbp_get_topic_id();
70 - $forum_id = bbp_get_topic_forum_id( $topic_id );
71 - } elseif ( bbp_is_reply_edit() ) {
72 - $reply_id = bbp_get_reply_id();
73 - $forum_id = bbp_get_reply_forum_id( $reply_id );
74 - }
75 - }
76 -
77 - return $forum_id;
78 -}
79 -
80 -function bbpc_bba_o( $name ) {
81 - return BBPCATTCore::instance()->o[ $name ];
82 -}
1 +<?php
2 +if ( ! defined( 'ABSPATH' ) ) {
3 + exit;
4 +}
5 +
6 +/**
7 + * Get the list of attachments for a post.
8 + *
9 + * @param int $post_id topic or reply ID to get attachments for
10 + *
11 + * @return array list of attachments objects
12 + */
13 +function forumax_get_post_attachments( $post_id ) {
14 + $post_id = (int) $post_id;
15 + $store = &forumax_post_attachments_store();
16 +
17 + if ( ! isset( $store[ $post_id ] ) ) {
18 + // Prime the whole topic/reply loop in one query instead of one per post.
19 + forumax_prime_post_attachments( array_merge( [ $post_id ], forumax_current_loop_post_ids() ) );
20 + }
21 +
22 + return $store[ $post_id ] ?? [];
23 +}
24 +
25 +/**
26 + * Per-request attachment store, keyed by parent post ID.
27 + *
28 + * @return array
29 + */
30 +function &forumax_post_attachments_store() {
31 + static $store = [];
32 + return $store;
33 +}
34 +
35 +/**
36 + * IDs of the topics/replies in the active bbPress loops.
37 + *
38 + * @return int[]
39 + */
40 +function forumax_current_loop_post_ids() {
41 + $ids = [];
42 +
43 + if ( ! function_exists( 'bbpress' ) ) {
44 + return $ids;
45 + }
46 +
47 + foreach ( [ 'reply_query', 'topic_query' ] as $prop ) {
48 + $query = bbpress()->{$prop} ?? null;
49 + if ( $query instanceof WP_Query && ! empty( $query->posts ) ) {
50 + $ids = array_merge( $ids, forumax_query_post_ids( $query ) );
51 + }
52 + }
53 +
54 + return $ids;
55 +}
56 +
57 +/**
58 + * Post IDs of a query, whether it fetched objects or IDs.
59 + *
60 + * @param WP_Query $query Query.
61 + * @return int[]
62 + */
63 +function forumax_query_post_ids( $query ) {
64 + return array_map(
65 + static function ( $post ) {
66 + return is_object( $post ) ? (int) $post->ID : (int) $post;
67 + },
68 + (array) $query->posts
69 + );
70 +}
71 +
72 +/**
73 + * Fetch attachments for many parent posts in a single query.
74 + *
75 + * @param int[] $post_ids Topic or reply IDs.
76 + * @return void
77 + */
78 +function forumax_prime_post_attachments( array $post_ids ) {
79 + $store = &forumax_post_attachments_store();
80 + $post_ids = array_values( array_diff( array_unique( array_filter( array_map( 'intval', $post_ids ) ) ), array_keys( $store ) ) );
81 +
82 + if ( empty( $post_ids ) ) {
83 + return;
84 + }
85 +
86 + foreach ( $post_ids as $id ) {
87 + $store[ $id ] = [];
88 + }
89 +
90 + // No row cap: the parent set is already bounded by the current loop, and a
91 + // cap would silently drop attachments of the posts past it (each of them
92 + // is marked as loaded above).
93 + $attachments = get_posts(
94 + [
95 + 'post_type' => 'attachment',
96 + 'numberposts' => -1,
97 + 'post_status' => 'inherit',
98 + 'post_parent__in' => $post_ids,
99 + 'orderby' => 'ID',
100 + 'order' => 'ASC',
101 + 'update_post_term_cache' => false,
102 + ]
103 + );
104 +
105 + foreach ( $attachments as $attachment ) {
106 + $store[ (int) $attachment->post_parent ][] = $attachment;
107 + }
108 +}
109 +
110 +/**
111 + * Forget a parent's cached attachments when one is added or removed.
112 + *
113 + * @param int $attachment_id Attachment ID.
114 + * @return void
115 + */
116 +function forumax_flush_post_attachments_store( $attachment_id ) {
117 + $store = &forumax_post_attachments_store();
118 + $parent = (int) wp_get_post_parent_id( $attachment_id );
119 + unset( $store[ $parent ] );
120 +}
121 +add_action( 'add_attachment', 'forumax_flush_post_attachments_store' );
122 +add_action( 'delete_attachment', 'forumax_flush_post_attachments_store' );
123 +
124 +/**
125 + * Count attachments for the forum topic. It can include topic replies in the count.
126 + *
127 + * Counts for every topic in the current loop are fetched together, so the
128 + * topic list costs two queries instead of one per topic.
129 + *
130 + * @param int $topic_id id of the topic to count attachments for
131 + * @param bool $include_replies true, to include reply attachments
132 + *
133 + * @return int number of attachments
134 + */
135 +function forumax_topic_attachments_count( $topic_id, $include_replies = false ) {
136 + global $wpdb;
137 + static $counts = [];
138 +
139 + $topic_id = (int) $topic_id;
140 + $key = $include_replies ? 'all' : 'own';
141 +
142 + if ( $topic_id <= 0 ) {
143 + return 0;
144 + }
145 +
146 + if ( isset( $counts[ $key ][ $topic_id ] ) ) {
147 + return $counts[ $key ][ $topic_id ];
148 + }
149 +
150 + $topic_ids = [ $topic_id ];
151 + if ( function_exists( 'bbpress' ) && bbpress()->topic_query instanceof WP_Query ) {
152 + $topic_ids = array_merge( $topic_ids, forumax_query_post_ids( bbpress()->topic_query ) );
153 + }
154 + $topic_ids = array_values( array_unique( array_filter( $topic_ids ) ) );
155 +
156 + foreach ( $topic_ids as $id ) {
157 + $counts[ $key ][ $id ] = 0;
158 + }
159 +
160 + $placeholders = implode( ',', array_fill( 0, count( $topic_ids ), '%d' ) );
161 +
162 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
163 + $rows = $wpdb->get_results( $wpdb->prepare( "SELECT post_parent AS topic_id, COUNT(*) AS total FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent IN ($placeholders) GROUP BY post_parent", $topic_ids ) );
164 +
165 + if ( $include_replies ) {
166 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
167 + $reply_rows = $wpdb->get_results( $wpdb->prepare( "SELECT r.post_parent AS topic_id, COUNT(*) AS total FROM {$wpdb->posts} r INNER JOIN {$wpdb->posts} a ON a.post_parent = r.ID AND a.post_type = 'attachment' WHERE r.post_type = 'reply' AND r.post_parent IN ($placeholders) GROUP BY r.post_parent", $topic_ids ) );
168 + $rows = array_merge( $rows, $reply_rows );
169 + }
170 +
171 + foreach ( $rows as $row ) {
172 + $counts[ $key ][ (int) $row->topic_id ] += (int) $row->total;
173 + }
174 +
175 + return $counts[ $key ][ $topic_id ];
176 +}
177 +
178 +/**
179 + * Handle upload file error.
180 + *
181 + * @param string $file file with error
182 + * @param string $message error message
183 + *
184 + * @return WP_Error error message
185 + */
186 +function forumax_bbattachment_handle_upload_error( &$file, $message ) {
187 + return new WP_Error( 'wp_upload_error', $message );
188 +}
189 +
190 +/**
191 + * Get current page forum ID. Handles the edge cases with the edit forms.
192 + *
193 + * @return int
194 + */
195 +function forumax_get_forum_id() {
196 + $forum_id = bbp_get_forum_id();
197 +
198 + if ( $forum_id == 0 ) {
199 + if ( bbp_is_topic_edit() ) {
200 + $topic_id = bbp_get_topic_id();
201 + $forum_id = bbp_get_topic_forum_id( $topic_id );
202 + } elseif ( bbp_is_reply_edit() ) {
203 + $reply_id = bbp_get_reply_id();
204 + $forum_id = bbp_get_reply_forum_id( $reply_id );
205 + }
206 + }
207 +
208 + return $forum_id;
209 +}
210 +
211 +function forumax_bba_o( $name ) {
212 + $opts = BBPCATTCore::instance()->o;
213 + // Return the option value if present, otherwise null.
214 + return isset( $opts[ $name ] ) ? $opts[ $name ] : null;
215 +}
216 +