PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.5.0
Forumax – AI Powered Advanced Community Forum Plugin v2.5.0
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 2.0.0 All 30 releases
← All changes | includes/template-functions.php +398 -122 2.0.0 → 2.5.0 View file →
@@ -1,122 +1,398 @@
1 -<?php
2 -/**
3 - * Template Functions for Forumax
4 - *
5 - * @package Forumax
6 - */
7 -
8 -defined( 'ABSPATH' ) || exit;
9 -
10 -/**
11 - * Register external template stack locations
12 - * @return void
13 - */
14 -add_action( 'after_setup_theme', 'forumax_register_external_templates', 5 );
15 -function forumax_register_external_templates() {
16 -
17 - /**
18 - * External templates (themes + plugins) - HIGHEST PRIORITY
19 - * This allows theme templates to override plugin templates
20 - * @return void
21 - */
22 - foreach ( forumax_get_external_template_dirs() as $dir ) {
23 - bbp_register_template_stack( fn() => trailingslashit( $dir ), 1 );
24 - }
25 -
26 - /**
27 - * Plugin fallback templates - LOWER PRIORITY
28 - * (runs if theme doesn't override)
29 - * @return void
30 - */
31 - bbp_register_template_stack( fn() => trailingslashit( FORUMAX_PATH . 'templates' ), 5 );
32 -}
33 -
34 -/**
35 - * Get template directories from themes, child themes, and plugins
36 - * using /forumax or /bbpress folders (when supported).
37 - *
38 - * @return array
39 - */
40 -function forumax_get_external_template_dirs() {
41 - $dirs = [];
42 - $slugs = [ 'forumax', 'bbpress' ];
43 - $themes = [ get_template_directory(), get_stylesheet_directory() ];
44 -
45 - // === Themes ===
46 - foreach ( array_unique( $themes ) as $theme ) {
47 - foreach ( $slugs as $slug ) {
48 - $path = trailingslashit( $theme ) . $slug . '/';
49 - if ( is_dir( $path ) ) {
50 - $dirs[] = $path;
51 - }
52 - }
53 - }
54 -
55 - // === Plugins ===
56 - foreach ( glob( WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR ) as $plugin ) {
57 - if ( basename( $plugin ) === 'forumax' ) {
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 -
69 - return $dirs;
70 -}
71 -
72 -/**
73 - * Extend bbPress template locations
74 - */
75 -add_filter( 'bbp_get_template_locations', 'forumax_extend_template_locations', 10, 2 );
76 -function forumax_extend_template_locations( $locations ) {
77 -
78 - foreach ( [ 'forumax', 'bbpress' ] as $slug ) {
79 - if ( ! in_array( $slug, $locations, true ) ) {
80 - array_unshift( $locations, $slug );
81 - }
82 - }
83 -
84 - return $locations;
85 -}
86 -
87 -/**
88 - * Banner preset background styles
89 - *
90 - * @return array[]|string[]
91 - */
92 -function forumax_banner_bg_style() {
93 - return array(
94 - 'color' => FORUMAX_IMG . '/options/color.png',
95 - 'faded-sun' => FORUMAX_IMG . '/options/faded-sun.jpg',
96 - 'happy-journey' => FORUMAX_IMG . '/options/happy-journey.jpg',
97 - 'apparent-circle' => FORUMAX_IMG . '/options/apparent-circle.jpg',
98 - 'soft-weather' => FORUMAX_IMG . '/options/soft-weather.jpg',
99 - 'romantic-sun' => FORUMAX_IMG . '/options/romantic-sun.jpg',
100 - 'teal-eclipse' => FORUMAX_IMG . '/options/teal-eclipse.jpg',
101 - );
102 -}
103 -
104 -
105 -
106 -/**
107 -* Image from Settings
108 -*
109 -* @param string $option_id
110 -* @param string $class
111 -* @param string $alt
112 -*/
113 -function get_image_from_settings( string $option_id = '', string $class = '', string $alt = '' ):void {
114 - $image = forumax_get_opt($option_id) ?? '';
115 -
116 - // Check if the image has an 'id' or a 'url' and display accordingly
117 - if ( ! empty($image['id']) ) {
118 - echo wp_get_attachment_image($image['id'], 'full', '' );
119 - } elseif ( !empty($image['url']) ) {
120 - echo "<img src='{$image['url']}'>";
121 - }
122 -}
1 +<?php
2 +/**
3 + * Template Functions for Forumax
4 + *
5 + * @package Forumax
6 + */
7 +
8 +defined( 'ABSPATH' ) || exit;
9 +
10 +/**
11 + * Register external template stack locations
12 + * @return void
13 + */
14 +add_action( 'after_setup_theme', 'forumax_register_external_templates', 5 );
15 +function forumax_register_external_templates() {
16 +
17 + /**
18 + * Forumax plugin templates - HIGH PRIORITY
19 + * These are the main Forumax styled templates
20 + */
21 + bbp_register_template_stack( fn() => trailingslashit( FORUMAX_PATH . 'templates' ), 1 );
22 +
23 + /**
24 + * Theme override templates (only /forumax/ folder) - HIGHEST PRIORITY
25 + * Allows themes to customize Forumax templates if needed
26 + */
27 + foreach ( forumax_get_theme_override_dirs() as $dir ) {
28 + bbp_register_template_stack( fn() => trailingslashit( $dir ), 0 );
29 + }
30 +}
31 +
32 +/**
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.
36 + *
37 + * @return array
38 + */
39 +function forumax_get_theme_override_dirs() {
40 + $dirs = [];
41 + $themes = [ get_template_directory(), get_stylesheet_directory() ];
42 +
43 + foreach ( array_unique( $themes ) as $theme ) {
44 + $path = trailingslashit( $theme ) . 'forumax/';
45 + if ( is_dir( $path ) ) {
46 + $dirs[] = $path;
47 + }
48 + }
49 +
50 + return $dirs;
51 +}
52 +
53 +/**
54 + * Extend bbPress template locations
55 + */
56 +add_filter( 'bbp_get_template_locations', 'forumax_extend_template_locations', 10, 2 );
57 +function forumax_extend_template_locations( $locations ) {
58 +
59 + foreach ( [ 'forumax', 'bbpress' ] as $slug ) {
60 + if ( ! in_array( $slug, $locations, true ) ) {
61 + array_unshift( $locations, $slug );
62 + }
63 + }
64 +
65 + 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 +}
362 +
363 +/**
364 + * Banner preset background styles
365 + *
366 + * @return array[]|string[]
367 + */
368 +function forumax_banner_bg_style() {
369 + return [
370 + 'color' => FORUMAX_IMG . '/options/color.png',
371 + 'faded-sun' => FORUMAX_IMG . '/options/faded-sun.jpg',
372 + 'happy-journey' => FORUMAX_IMG . '/options/happy-journey.jpg',
373 + 'apparent-circle' => FORUMAX_IMG . '/options/apparent-circle.jpg',
374 + 'soft-weather' => FORUMAX_IMG . '/options/soft-weather.jpg',
375 + 'romantic-sun' => FORUMAX_IMG . '/options/romantic-sun.jpg',
376 + 'teal-eclipse' => FORUMAX_IMG . '/options/teal-eclipse.jpg',
377 + ];
378 +}
379 +
380 +
381 +
382 +/**
383 +* Image from Settings
384 +*
385 +* @param string $option_id
386 +* @param string $class
387 +* @param string $alt
388 +*/
389 +function get_image_from_settings( string $option_id = '', string $class = '', string $alt = '' ):void {
390 + $image = forumax_get_opt($option_id) ?? '';
391 +
392 + // Check if the image has an 'id' or a 'url' and display accordingly
393 + if ( ! empty($image['id']) ) {
394 + echo wp_get_attachment_image($image['id'], 'full', '' );
395 + } elseif ( !empty($image['url']) ) {
396 + echo "<img src='{$image['url']}'>";
397 + }
398 +}