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
← All changes | includes/template-functions.php +35 -311 trunk2.2.0 View file →
@@ -13,41 +13,60 @@
13 13 */
14 14 add_action( 'after_setup_theme', 'forumax_register_external_templates', 5 );
15 15 function forumax_register_external_templates() {
16 16
17 - /**
18 - * Forumax plugin templates - HIGH PRIORITY
19 - * These are the main Forumax styled templates
17 + /**
18 + * External templates (themes + plugins) - HIGHEST PRIORITY
19 + * This allows theme templates to override plugin templates
20 + * @return void
20 21 */
21 - bbp_register_template_stack( fn() => trailingslashit( FORUMAX_PATH . 'templates' ), 1 );
22 + foreach ( forumax_get_external_template_dirs() as $dir ) {
23 + bbp_register_template_stack( fn() => trailingslashit( $dir ), 1 );
24 + }
22 25
23 26 /**
24 - * Theme override templates (only /forumax/ folder) - HIGHEST PRIORITY
25 - * Allows themes to customize Forumax templates if needed
27 + * Plugin fallback templates - LOWER PRIORITY
28 + * (runs if theme doesn't override)
29 + * @return void
26 30 */
27 - foreach ( forumax_get_theme_override_dirs() as $dir ) {
28 - bbp_register_template_stack( fn() => trailingslashit( $dir ), 0 );
29 - }
31 + bbp_register_template_stack( fn() => trailingslashit( FORUMAX_PATH . 'templates' ), 5 );
30 32 }
31 33
32 34 /**
33 - * Get theme template directories that can override Forumax templates.
34 - * Only checks for /forumax/ folder - theme's /bbpress/ folder is NOT used
35 - * because Forumax provides its own styled templates.
35 + * Get template directories from themes, child themes, and plugins
36 + * using /forumax or /bbpress folders (when supported).
36 37 *
37 38 * @return array
38 39 */
39 -function forumax_get_theme_override_dirs() {
40 +function forumax_get_external_template_dirs() {
40 41 $dirs = [];
42 + $slugs = [ 'forumax', 'bbpress' ];
41 43 $themes = [ get_template_directory(), get_stylesheet_directory() ];
42 44
45 + // === Themes ===
43 46 foreach ( array_unique( $themes ) as $theme ) {
44 - $path = trailingslashit( $theme ) . 'forumax/';
45 - if ( is_dir( $path ) ) {
46 - $dirs[] = $path;
47 + foreach ( $slugs as $slug ) {
48 + $path = trailingslashit( $theme ) . $slug . '/';
49 + if ( is_dir( $path ) ) {
50 + $dirs[] = $path;
51 + }
47 52 }
48 53 }
49 54
55 + // === Plugins ===
56 + foreach ( glob( WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR ) as $plugin ) {
57 + if ( 'forumax' === basename( $plugin ) ) {
58 + continue;
59 + }
60 +
61 + foreach ( $slugs as $slug ) {
62 + $path = trailingslashit( $plugin ) . $slug . '/';
63 + if ( is_dir( $path ) ) {
64 + $dirs[] = $path;
65 + }
66 + }
67 + }
68 +
50 69 return $dirs;
51 70 }
52 71
53 72 /**
@@ -62,303 +81,8 @@
62 81 }
63 82 }
64 83
65 84 return $locations;
66 -}
67 -
68 -/**
69 - * Detect Hello theme family (Hello Elementor, Hello Biz, and child themes).
70 - *
71 - * @return bool
72 - */
73 -function forumax_is_hello_theme() {
74 - $theme = wp_get_theme();
75 - $stylesheet = $theme->get_stylesheet();
76 - $template = $theme->get_template();
77 -
78 - $hello_slugs = array( 'hello-elementor', 'hello-biz' );
79 -
80 - foreach ( $hello_slugs as $slug ) {
81 - if ( $slug === $template || 0 === strpos( $template, $slug ) ) {
82 - return true;
83 - }
84 -
85 - if ( $slug === $stylesheet || 0 === strpos( $stylesheet, $slug ) ) {
86 - return true;
87 - }
88 - }
89 -
90 - return false;
91 -}
92 -
93 -/**
94 - * Ensure Forumax templates are preferred on Hello theme.
95 - *
96 - * @param array $stack Template stack locations.
97 - * @return array
98 - */
99 -add_filter( 'bbp_get_template_stack', 'forumax_force_templates_on_hello', 1 );
100 -function forumax_force_templates_on_hello( $stack ) {
101 - if ( ! forumax_is_hello_theme() || ! function_exists( 'bbp_add_template_stack_locations' ) ) {
102 - return $stack;
103 - }
104 -
105 - $paths = bbp_add_template_stack_locations( array( trailingslashit( FORUMAX_PATH . 'templates' ) ) );
106 - foreach ( array_reverse( (array) $paths ) as $path ) {
107 - array_unshift( $stack, $path );
108 - }
109 -
110 - return array_values( array_unique( $stack ) );
111 -}
112 -
113 -/**
114 - * Force Forumax forum archive template on Hello theme.
115 - *
116 - * Uses template_include filter (which runs after all template hierarchy filters)
117 - * because Hello Elementor doesn't have archive.php, so archive_template filter
118 - * never fires - WordPress falls back to index.php directly.
119 - *
120 - * @param string $template Current template path.
121 - * @return string
122 - */
123 -add_filter( 'template_include', 'forumax_force_forum_archive_template_on_hello', 99 );
124 -function forumax_force_forum_archive_template_on_hello( $template ) {
125 - if ( ! forumax_is_hello_theme() || ! function_exists( 'bbp_is_forum_archive' ) ) {
126 - return $template;
127 - }
128 -
129 - // Only override on bbPress forum archive pages.
130 - if ( bbp_is_forum_archive() ) {
131 - $hello_template = FORUMAX_PATH . 'templates/hello-archive-forum.php';
132 - if ( file_exists( $hello_template ) ) {
133 - return $hello_template;
134 - }
135 - }
136 -
137 - return $template;
138 -}
139 -
140 -/**
141 - * Force Forumax bbPress user profile template on Hello themes.
142 - *
143 - * Hello Elementor/Hello Biz can fall back to their 404 template when bbPress
144 - * user rewrite rules are missing/out-of-date. This guarantees rendering of
145 - * the user profile screen for URLs like `/forums/users/<nicename>/`.
146 - *
147 - * @param string $template Current template path.
148 - * @return string
149 - */
150 -add_filter( 'template_include', 'forumax_force_user_profile_template_on_hello', 98 );
151 -function forumax_force_user_profile_template_on_hello( $template ) {
152 - if ( ! forumax_is_hello_theme() || ! function_exists( 'bbp_get_root_slug' ) ) {
153 - return $template;
154 - }
155 -
156 - if ( ! isset( $_SERVER['REQUEST_URI'] ) ) {
157 - return $template;
158 - }
159 -
160 - $path = (string) wp_parse_url( (string) $_SERVER['REQUEST_URI'], PHP_URL_PATH );
161 - $path = trim( $path, '/' );
162 - if ( '' === $path ) {
163 - return $template;
164 - }
165 -
166 - $root_slug = trim( (string) bbp_get_root_slug(), '/' );
167 - if ( '' === $root_slug ) {
168 - return $template;
169 - }
170 -
171 - // Require /{root}/ prefix.
172 - $root_prefix = $root_slug . '/';
173 - if ( 0 !== strpos( $path, $root_prefix ) ) {
174 - return $template;
175 - }
176 -
177 - $after_root = substr( $path, strlen( $root_prefix ) );
178 - $parts = array_values( array_filter( explode( '/', (string) $after_root ) ) );
179 - if ( count( $parts ) < 2 ) {
180 - return $template;
181 - }
182 -
183 - $user_base = trim( (string) get_option( '_bbp_user_slug', 'users' ), '/' );
184 - if ( '' === $user_base ) {
185 - $user_base = 'users';
186 - }
187 -
188 - $alt_base = ( 'users' === $user_base ) ? 'user' : 'users';
189 - if ( $parts[0] !== $user_base && $parts[0] !== $alt_base ) {
190 - return $template;
191 - }
192 -
193 - $user_nicename = sanitize_title( (string) $parts[1] );
194 - if ( '' === $user_nicename ) {
195 - return $template;
196 - }
197 -
198 - $the_user = get_user_by( 'slug', $user_nicename );
199 - if ( empty( $the_user ) || empty( $the_user->ID ) || ( function_exists( 'bbp_user_has_profile' ) && ! bbp_user_has_profile( $the_user->ID ) ) ) {
200 - return $template;
201 - }
202 -
203 - // Pass data to the template.
204 - set_query_var( 'forumax_hello_user_id', (int) $the_user->ID );
205 - set_query_var( 'forumax_hello_user_section', isset( $parts[2] ) ? sanitize_title( (string) $parts[2] ) : '' );
206 -
207 - $hello_template = FORUMAX_PATH . 'templates/hello-single-user.php';
208 - if ( file_exists( $hello_template ) ) {
209 - return $hello_template;
210 - }
211 -
212 - return $template;
213 -}
214 -
215 -/**
216 - * Add rewrite aliases for bbPress user profiles.
217 - *
218 - * Some setups (or migrations) end up with links like `/forums/users/admin/`
219 - * while the active bbPress "User base" might be `user` (or vice versa).
220 - * Injecting aliases at runtime avoids 404s without requiring a rewrite flush.
221 - *
222 - * @param array $rules
223 - * @return array
224 - */
225 -add_filter( 'rewrite_rules_array', 'forumax_add_bbpress_user_rewrite_aliases', 20 );
226 -function forumax_add_bbpress_user_rewrite_aliases( $rules ) {
227 - if ( ! function_exists( 'bbp_get_root_slug' ) || ! function_exists( 'bbp_get_user_rewrite_id' ) ) {
228 - return $rules;
229 - }
230 -
231 - $root_slug = trim( (string) bbp_get_root_slug(), '/' );
232 - if ( '' === $root_slug ) {
233 - return $rules;
234 - }
235 -
236 - $user_base = trim( (string) get_option( '_bbp_user_slug', 'users' ), '/' );
237 - if ( '' === $user_base ) {
238 - $user_base = 'users';
239 - }
240 -
241 - $alt_base = ( 'users' === $user_base ) ? 'user' : 'users';
242 -
243 - $root_regex = preg_quote( $root_slug, '!' );
244 - $bases = array_values( array_unique( array( $user_base, $alt_base ) ) );
245 - $add = array();
246 -
247 - foreach ( $bases as $base ) {
248 - $base_regex = preg_quote( $base, '!' );
249 -
250 - // User profile root: /{root}/{users|user}/{nicename}/
251 - $profile_rule = '^' . $root_regex . '/' . $base_regex . '/([^/]+)/?$';
252 - if ( ! isset( $rules[ $profile_rule ] ) ) {
253 - $add[ $profile_rule ] = 'index.php?' . bbp_get_user_rewrite_id() . '=$matches[1]';
254 - }
255 - }
256 -
257 - return $add + $rules;
258 -}
259 -
260 -/**
261 - * Map bbPress user profile URLs at runtime (no rewrite flush).
262 - *
263 - * When rewrite rules are missing/out-of-date, Hello themes often fall through
264 - * to their 404 template for URLs like `/forums/users/<nicename>/`. Other themes
265 - * may mask the issue by having alternate templates/routes.
266 - *
267 - * This ensures Hello themes always populate bbPress query vars early enough
268 - * for bbPress's `bbp_parse_query()` to flag the request as a user profile.
269 - *
270 - * @param WP $wp
271 - * @return void
272 - */
273 -add_action( 'parse_request', 'forumax_map_bbpress_user_request_on_hello', 1 );
274 -function forumax_map_bbpress_user_request_on_hello( $wp ) {
275 - if ( ! forumax_is_hello_theme() || is_admin() ) {
276 - return;
277 - }
278 -
279 - if ( ! ( $wp instanceof WP ) ) {
280 - return;
281 - }
282 -
283 - if ( ! function_exists( 'bbp_get_root_slug' ) || ! function_exists( 'bbp_get_user_rewrite_id' ) ) {
284 - return;
285 - }
286 -
287 - $user_rewrite_id = bbp_get_user_rewrite_id();
288 - if ( empty( $user_rewrite_id ) ) {
289 - return;
290 - }
291 -
292 - // If bbPress already matched, don't interfere.
293 - if ( ! empty( $wp->query_vars[ $user_rewrite_id ] ) ) {
294 - return;
295 - }
296 -
297 - $request = isset( $wp->request ) ? trim( (string) $wp->request, '/' ) : '';
298 - if ( '' === $request ) {
299 - return;
300 - }
301 -
302 - $root_slug = trim( (string) bbp_get_root_slug(), '/' );
303 - if ( '' === $root_slug ) {
304 - return;
305 - }
306 -
307 - $root_prefix = $root_slug . '/';
308 - if ( 0 !== strpos( $request, $root_prefix ) ) {
309 - return;
310 - }
311 -
312 - $after_root = substr( $request, strlen( $root_prefix ) );
313 - if ( '' === $after_root ) {
314 - return;
315 - }
316 -
317 - $user_base = trim( (string) get_option( '_bbp_user_slug', 'users' ), '/' );
318 - if ( '' === $user_base ) {
319 - $user_base = 'users';
320 - }
321 -
322 - $alt_base = ( 'users' === $user_base ) ? 'user' : 'users';
323 -
324 - // Match: (users|user)/{nicename}/(optional section)
325 - $base_regex = '(?:' . preg_quote( $user_base, '!' ) . '|' . preg_quote( $alt_base, '!' ) . ')';
326 - if ( ! preg_match( '!' . '^' . $base_regex . '/([^/]+)(?:/(.*))?$' . '!' , $after_root, $m ) ) {
327 - return;
328 - }
329 -
330 - $user_nicename = sanitize_title( $m[1] );
331 - $section = isset( $m[2] ) ? trim( (string) $m[2], '/' ) : '';
332 -
333 - if ( '' === $user_nicename ) {
334 - return;
335 - }
336 -
337 - // Set the primary bbPress user query var.
338 - $wp->query_vars[ $user_rewrite_id ] = $user_nicename;
339 -
340 - // Also set the bbPress query name for consistency.
341 - $wp->query_vars['_bbp_query_name'] = 'bbp_single_user';
342 -
343 - // Map optional sections (favorites/subscriptions/topics/replies/engagements/edit).
344 - if ( '' !== $section ) {
345 - $section_first = explode( '/', $section )[0];
346 -
347 - if ( function_exists( 'bbp_get_edit_slug' ) && ( bbp_get_edit_slug() === $section_first ) ) {
348 - $wp->query_vars[ bbp_get_edit_rewrite_id() ] = '1';
349 - } elseif ( function_exists( 'bbp_get_user_favorites_slug' ) && ( bbp_get_user_favorites_slug() === $section_first ) ) {
350 - $wp->query_vars[ bbp_get_user_favorites_rewrite_id() ] = bbp_get_user_favorites_slug();
351 - } elseif ( function_exists( 'bbp_get_user_subscriptions_slug' ) && ( bbp_get_user_subscriptions_slug() === $section_first ) ) {
352 - $wp->query_vars[ bbp_get_user_subscriptions_rewrite_id() ] = bbp_get_user_subscriptions_slug();
353 - } elseif ( function_exists( 'bbp_get_topic_archive_slug' ) && ( bbp_get_topic_archive_slug() === $section_first ) ) {
354 - $wp->query_vars[ bbp_get_user_topics_rewrite_id() ] = '1';
355 - } elseif ( function_exists( 'bbp_get_reply_archive_slug' ) && ( bbp_get_reply_archive_slug() === $section_first ) ) {
356 - $wp->query_vars[ bbp_get_user_replies_rewrite_id() ] = '1';
357 - } elseif ( function_exists( 'bbp_get_user_engagements_slug' ) && ( bbp_get_user_engagements_slug() === $section_first ) ) {
358 - $wp->query_vars[ bbp_get_user_engagements_rewrite_id() ] = '1';
359 - }
360 - }
361 85 }
362 86
363 87 /**
364 88 * Banner preset background styles