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 | forumax.php +700 -304 2.0.0 → 2.5.0 View file →
@@ -1,304 +1,700 @@
1 -<?php
2 -/*
3 -Plugin Name: Forumax
4 -Plugin URI: https://forumax.spider-themes.net/
5 -Description: Expand bbPress powered forums with useful features like - private reply, solved topics ...
6 -Author: spider-themes
7 -Author URI: https://forumax.spider-themes.net/
8 -Text Domain: forumax
9 -Version: 2.0.0
10 -Requires at least: 5.0
11 -Tested up to: 6.8
12 -Requires PHP: 7.4
13 -License: GPLv3 or later
14 -License URI: https://www.gnu.org/licenses/gpl-3.0.html
15 -*/
16 -
17 -defined( 'ABSPATH' ) || exit;
18 -
19 -// Load bbPress very early so other plugins (like docy-core) can detect it
20 -// This must happen before the Forumax class to ensure proper load order
21 -if ( ! class_exists( 'bbPress' ) ) {
22 - require_once __DIR__ . '/vendor/bbpress/bbpress.php';
23 -}
24 -
25 -if ( ! function_exists( 'bc_fs' ) ) {
26 - // Create a helper function for easy SDK access.
27 - function bc_fs() {
28 - global $bc_fs;
29 -
30 - if ( ! isset( $bc_fs ) ) {
31 - // Include Freemius SDK.
32 - require_once dirname( __FILE__ ) . '/vendor/fs/start.php';
33 -
34 - $bc_fs = fs_dynamic_init( [
35 - 'id' => '10864',
36 - 'slug' => 'forumax',
37 - 'type' => 'plugin',
38 - 'public_key' => 'pk_41277ad11125f6e2a1b4e66f40164',
39 - 'is_premium' => false,
40 - 'is_premium_only' => false,
41 - 'has_addons' => false,
42 - 'has_paid_plans' => true,
43 - 'trial' => [
44 - 'days' => 14,
45 - 'is_require_payment' => true,
46 - ],
47 - 'menu' => [
48 - 'slug' => 'forumax',
49 - 'contact' => false,
50 - 'support' => false,
51 - 'first-path' => 'admin.php?page=forumax',
52 - ],
53 - 'parallel_activation' => array(
54 - 'enabled' => true,
55 - 'premium_version_basename' => 'forumax-pro/forumax.php',
56 - ),
57 - ] );
58 - }
59 -
60 - return $bc_fs;
61 - }
62 -
63 - // Add filter to hide the Freemius badge from the plugin page.
64 - bc_fs()->add_filter( 'hide_freemius_powered_by', '__return_true' );
65 -
66 - // Signal that SDK was initiated.
67 - do_action( 'bc_fs_loaded' );
68 -}
69 -
70 -require_once __DIR__ . '/autoloader.php';
71 -
72 -/**
73 - * Plugin's heart
74 - */
75 -final class Forumax {
76 - const VERSION = '2.0.0';
77 -
78 - /**
79 - * Class constructor.
80 - */
81 - public function __construct() {
82 -
83 - $this->define_constants();
84 - $this->core_includes();
85 -
86 - register_activation_hook( __FILE__, [ $this, 'activate' ] );
87 - add_action( 'plugins_loaded', [ $this, 'init_plugin' ] );
88 - add_action( 'after_setup_theme', [ $this, 'load_csf_files' ], 20 );
89 -
90 - // Added Documentation links to plugin row meta
91 - add_filter( 'plugin_row_meta', [ $this, 'forumax_row_meta' ], 10, 2 );
92 -
93 - /**
94 - * Removes admin notices on the Forumax Forum builder page.
95 - *
96 - * @return void
97 - */
98 - add_action( 'admin_head', function () {
99 - // Get the current screen
100 - $screen = get_current_screen();
101 -
102 - // Check if the current screen is for your plugin page
103 - if ( isset( $_GET['page'] ) && in_array( $_GET['page'], [ 'forumax' ] ) ) {
104 - // Remove admin notices
105 - remove_all_actions( 'admin_notices' );
106 - remove_all_actions( 'all_admin_notices' );
107 -
108 - // Re-add a specific notice
109 - if ( ! forumax_is_premium() && forumax_is_plugin_installed_for_days( 12 ) ) {
110 - add_action( 'admin_notices', 'forumax_offer_notice' );
111 - }
112 - }
113 - } );
114 - }
115 -
116 - /**
117 - * Define Plugin Constants.
118 - *
119 - * @return void
120 - */
121 - public function define_constants() {
122 - define( 'FORUMAX_VERSION', self::VERSION );
123 - define( 'FORUMAX_FILE', __FILE__ );
124 - define( 'FORUMAX_DIR', __DIR__ . '/' );
125 - define( 'FORUMAX_PATH', FORUMAX_DIR );
126 - define( 'FORUMAX_URL', plugins_url( '/', __FILE__ ) );
127 - define( 'FORUMAX_ASSETS', FORUMAX_URL . 'assets/' );
128 - define( 'FORUMAX_FRONT_ASS', FORUMAX_URL . 'assets/frontend/' );
129 - define( 'FORUMAX_ADMIN_ASS', FORUMAX_ASSETS . 'admin/' );
130 - define( 'FORUMAX_IMG', FORUMAX_ASSETS . 'img/' );
131 - define( 'FORUMAX_VEND', FORUMAX_ASSETS . 'vendors/' );
132 - }
133 -
134 - /**
135 - * File includes.
136 - */
137 - public function core_includes() {
138 - require_once __DIR__ . '/includes/functions.php';
139 -
140 - require_once __DIR__ . '/includes/template-functions.php';
141 - require_once __DIR__ . '/includes/bbpress-config.php';
142 -
143 - require_once __DIR__ . '/includes/admin/menu/Approve_Topic.php';
144 - require_once __DIR__ . '/includes/admin/menu/Create_Forum.php';
145 - require_once __DIR__ . '/includes/admin/menu/Create_Topic.php';
146 - require_once __DIR__ . '/includes/admin/menu/Delete_Forum.php';
147 - require_once __DIR__ . '/includes/admin/menu/Delete_Topic.php';
148 - require_once __DIR__ . '/includes/Elementor/Forumax_Widgets.php';
149 - require_once __DIR__ . '/includes/ajax_actions.php';
150 - include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
151 -
152 - require_once __DIR__ . '/widgets/widgets.php';
153 - require_once __DIR__ . '/includes/Blocks/Blocks_Register.php';
154 - new \admin\Blocks\Blocks_Register();
155 - require_once __DIR__ . '/includes/Elementor/inc/forum-ajax.php';
156 -
157 - // Core installer notice
158 - require_once __DIR__ . '/includes/admin/notices/_notices.php';
159 -
160 - //Register Pro Widgets
161 - $theme = wp_get_theme();
162 -
163 - if ( $theme->get( 'Name' ) != 'Ama' || ! forumax_is_premium() ) {
164 - require_once __DIR__ . '/includes/admin/Pro_El_Widget_Map.php';
165 - require_once __DIR__ . '/includes/admin/Pro_El_Widget_Service.php';
166 - }
167 -
168 - // Hooks
169 - require FORUMAX_DIR . 'includes/hooks/actions.php';
170 - require FORUMAX_DIR . 'includes/hooks/image_sizes.php';
171 - require FORUMAX_DIR . 'includes/login-form.php';
172 -
173 - require FORUMAX_DIR . '/includes/classes/Forumax_Forum_Class.php';
174 - }
175 -
176 - /**
177 - * Initializing Forumax class.
178 - *
179 - * @return \Forumax
180 - */
181 - static function init() {
182 - static $instance = false;
183 -
184 - if ( ! $instance ) {
185 - $instance = new self();
186 - }
187 - }
188 -
189 - /**
190 - * Actions on plugin activation.
191 - *
192 - * @return void
193 - */
194 - public function activate() {
195 - $installed = get_option( 'bbpc_installed' );
196 - if ( ! $installed ) {
197 - update_option( 'bbpc_installed', time() );
198 - }
199 -
200 - update_option( 'bbpc_version', FORUMAX_VERSION );
201 - // Ensure default option for forumax_settings
202 - $defaults = array(
203 - 'is_bbpc_insert_media' => true,
204 - );
205 -
206 - $current = get_option( 'bbp_core_settings', array() );
207 - $updated = wp_parse_args( $current, $defaults );
208 -
209 - update_option( 'bbp_core_settings', $updated );
210 - }
211 -
212 - /**
213 - * Initialize the plugin functionality.
214 - *
215 - * @return void
216 - */
217 - public function init_plugin() {
218 -
219 - $this->load_features();
220 -
221 - if ( is_admin() ) {
222 - new Admin();
223 - new admin\Admin_Assets();
224 - } elseif ( ! is_admin() ) {
225 - new Frontend\Frontend_Assets();
226 - }
227 -
228 - // If bbPress is not active, don't load assets and widgets.
229 - if ( ! class_exists( 'bbPress' ) || ! class_exists( 'Forumax' ) ) {
230 - return;
231 - }
232 -
233 - new admin\Elementor\Forumax_Widgets();
234 - }
235 -
236 - /**
237 - * Include CSF files include
238 - */
239 - public function load_csf_files(){
240 - require FORUMAX_DIR . 'vendor/csf/classes/setup.class.php';
241 - require FORUMAX_DIR . 'includes/admin/options/settings.php';
242 - }
243 -
244 - /**
245 - * Load different features.
246 - *
247 - * @return void
248 - */
249 - public function load_features() {
250 - define( 'FORUMAX_FEAT_PATH', plugin_dir_path( __FILE__ ) . 'includes/features/' );
251 -
252 - if ( forumax_get_opt( 'is_solved_topics', true ) ) {
253 - require FORUMAX_FEAT_PATH . 'bbp_solved_topic.php';
254 - }
255 -
256 - if ( forumax_get_opt( 'is_private_replies', true ) ) {
257 - require FORUMAX_FEAT_PATH . 'bbp-private-replies.php';
258 - }
259 -
260 - if ( forumax_is_premium() || class_exists( 'BBPC_GEO_ROLES' ) ) {
261 - if ( forumax_get_opt( 'agree_disagree_voting' ) ) {
262 - require FORUMAX_FEAT_PATH . 'bbp_voting/agree-disagree/init.php';
263 - require FORUMAX_FEAT_PATH . 'bbp_voting/agree-disagree/actions.php';
264 - }
265 - }
266 -
267 - if ( forumax_get_opt( 'is_votes', true ) ) {
268 - new features\bbp_voting();
269 - }
270 -
271 - if ( forumax_get_opt( 'is_attachment', true ) ) {
272 - new features\bbp_attachments();
273 - }
274 - }
275 -
276 - /**
277 - * Documentation links to plugin row meta
278 - */
279 - public function forumax_row_meta( $links, $file ) {
280 - // Check if this is your plugin
281 - if ( plugin_basename( __FILE__ ) === $file ) {
282 - // Add your custom links
283 - $plugin_links = array(
284 - '<a href="https://helpdesk.spider-themes.net/docs/forumax-wordpress-plugin/" target="_blank">' . esc_html__('Documentation', 'forumax') . '</a>'
285 - );
286 - // Merge the custom links with the existing links
287 - $links = array_merge( $links, $plugin_links );
288 - }
289 -
290 - return $links;
291 - }
292 -}
293 -
294 -/**
295 - * Initialize the Forumax plugin.
296 - *
297 - * @return \Forumax
298 - */
299 -function forumax() {
300 - return Forumax::init();
301 -}
302 -
303 -forumax();
304 -
1 +<?php
2 +/*
3 +Plugin Name: Forumax
4 +Plugin URI: https://forumax.spider-themes.net/
5 +Description: Forumax is forum software for community discussions with public and private replies, private chats, voting, solved topics and more.
6 +Author: spider-themes
7 +Author URI: https://forumax.spider-themes.net/
8 +Text Domain: forumax
9 +Version: 2.5.0
10 +Requires at least: 5.0
11 +Tested up to: 7.1.2
12 +Requires PHP: 7.4
13 +License: GPLv3 or later
14 +License URI: https://www.gnu.org/licenses/gpl-3.0.html
15 +*/
16 +
17 +defined( 'ABSPATH' ) || exit;
18 +
19 +// Load bbPress very early so other plugins (like docy-core) can detect it
20 +// This must happen before the Forumax class to ensure proper load order
21 +if ( ! class_exists( 'bbPress' ) ) {
22 + require_once __DIR__ . '/lib/bbpress/bbpress.php';
23 +}
24 +
25 +if ( function_exists( 'bc_fs' ) ) {
26 + // Forumax Pro already booted the Freemius SDK. Register this (free) plugin's
27 + // file with the shared instance instead of initializing a second time. This
28 + // keeps the free/premium pairing working regardless of which plugin loads first.
29 + bc_fs()->set_basename( false, __FILE__ );
30 +} else {
31 + // Create a helper function for easy SDK access.
32 + function bc_fs() {
33 + global $bc_fs;
34 +
35 + if ( ! isset( $bc_fs ) ) {
36 + // Include Freemius SDK.
37 + require_once __DIR__ . '/vendor/freemius/wordpress-sdk/start.php';
38 +
39 + $bc_fs = fs_dynamic_init(
40 + array(
41 + 'id' => '10864',
42 + 'slug' => 'forumax',
43 + 'premium_slug' => 'forumax-premium',
44 + 'type' => 'plugin',
45 + 'public_key' => 'pk_41277ad11125f6e2a1b4e66f40164',
46 + 'is_premium' => false,
47 + 'premium_suffix' => 'Pro',
48 + 'has_premium_version' => true,
49 + 'has_addons' => false,
50 + 'has_paid_plans' => true,
51 + 'parallel_activation' => array(
52 + 'enabled' => true,
53 + 'premium_version_basename' => 'forumax-premium/forumax.php',
54 + ),
55 + 'trial' => array(
56 + 'days' => 14,
57 + 'is_require_payment' => true,
58 + ),
59 + 'menu' => array(
60 + 'slug' => 'forumax',
61 + 'contact' => false,
62 + 'support' => false,
63 + 'first-path' => 'admin.php?page=forumax',
64 + ),
65 + )
66 + );
67 + }
68 +
69 + return $bc_fs;
70 + }
71 +
72 + // Add filter to hide the Freemius badge from the plugin page.
73 + bc_fs()->add_filter( 'hide_freemius_powered_by', '__return_true' );
74 +
75 + // Disclose that opting in also pre-fills the in-plugin support chat
76 + // (see the Support Assistant class). The on-update screen falls back to this filter.
77 + bc_fs()->add_filter( 'connect_message', function ( $message ) {
78 + return $message . '<br><br>' . esc_html__( 'Opting in also pre-fills your name and email in the Forumax support chat, so you can get help without typing them. They are only sent to our helpdesk when you open the chat.', 'forumax' );
79 + } );
80 +
81 + // Keep the free and premium versions from auto-deactivating each other.
82 + bc_fs()->add_filter( 'deactivate_on_activation', '__return_false' );
83 +
84 + // Suppress Freemius update row modification to avoid double notices or licensing nags on the plugins page.
85 + add_action(
86 + 'admin_init',
87 + function () {
88 + if ( function_exists( 'bc_fs' ) ) {
89 + $updater = FS_Plugin_Updater::instance( bc_fs() );
90 + $basename = bc_fs()->get_plugin_basename();
91 + remove_action( "after_plugin_row_{$basename}", array( $updater, 'catch_plugin_update_row' ), 9 );
92 + remove_action( "after_plugin_row_{$basename}", array( $updater, 'edit_and_echo_plugin_update_row' ), 11 );
93 + }
94 + }
95 + );
96 +
97 + // Signal that SDK was initiated.
98 + do_action( 'bc_fs_loaded' );
99 +}
100 +
101 +require_once __DIR__ . '/autoloader.php';
102 +
103 +/**
104 + * Plugin's heart
105 + */
106 +final class Forumax {
107 +
108 + const VERSION = '2.5.0';
109 +
110 + /**
111 + * Class constructor.
112 + */
113 + public function __construct() {
114 +
115 + $this->define_constants();
116 + $this->core_includes();
117 +
118 + register_activation_hook( __FILE__, array( $this, 'activate' ) );
119 + register_deactivation_hook( __FILE__, array( $this, 'deactivate' ) );
120 + add_action( 'plugins_loaded', array( $this, 'init_plugin' ) );
121 + add_action( 'after_setup_theme', array( $this, 'load_csf_files' ), 20 );
122 + add_action( 'admin_init', array( $this, 'redirect_to_setup_wizard' ) );
123 + add_action( 'upgrader_process_complete', array( $this, 'migrate_plugin_basename' ), 10, 2 );
124 +
125 + // Added Documentation links to plugin row meta
126 + add_filter( 'plugin_row_meta', array( $this, 'forumax_row_meta' ), 10, 2 );
127 +
128 + // Prevent deactivation if Forumax Pro is active
129 + add_action( 'admin_init', array( $this, 'prevent_deactivation_if_pro_active' ) );
130 + add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'modify_deactivate_link' ), 10, 4 );
131 +
132 + /**
133 + * Removes admin notices on the Forumax Forum builder page.
134 + *
135 + * @return void
136 + */
137 + add_action(
138 + 'admin_head',
139 + function () {
140 + // Get the current screen
141 + $screen = get_current_screen();
142 +
143 + // Check if the current screen is for your plugin page
144 + if ( isset( $_GET['page'] ) && in_array( $_GET['page'], array( 'forumax', 'forumax-builder', 'forumax-settings' ), true ) ) {
145 + // Remove admin notices
146 + remove_all_actions( 'admin_notices' );
147 + remove_all_actions( 'all_admin_notices' );
148 +
149 + // Re-add a specific notice
150 + if ( ! forumax_is_premium() && forumax_is_plugin_installed_for_days( 12 ) ) {
151 + add_action( 'admin_notices', 'forumax_offer_notice' );
152 + }
153 + }
154 + }
155 + );
156 + }
157 +
158 + /**
159 + * Define Plugin Constants.
160 + *
161 + * @return void
162 + */
163 + public function define_constants() {
164 + define( 'FORUMAX_VERSION', self::VERSION );
165 + define( 'FORUMAX_FILE', __FILE__ );
166 + define( 'FORUMAX_DIR', __DIR__ . '/' );
167 + define( 'FORUMAX_PATH', FORUMAX_DIR );
168 + define( 'FORUMAX_URL', plugins_url( '/', __FILE__ ) );
169 + define( 'FORUMAX_ASSETS', FORUMAX_URL . 'assets/' );
170 + define( 'FORUMAX_FRONT_ASS', FORUMAX_URL . 'assets/frontend/' );
171 + define( 'FORUMAX_ADMIN_ASS', FORUMAX_ASSETS . 'admin/' );
172 + define( 'FORUMAX_STYLES', FORUMAX_URL . 'build/styles/' );
173 + define( 'FORUMAX_IMG', FORUMAX_ASSETS . 'img/' );
174 + define( 'FORUMAX_VEND', FORUMAX_ASSETS . 'vendors/' );
175 + }
176 +
177 + /**
178 + * File includes.
179 + */
180 + public function core_includes() {
181 + // Smart bbPress nVerify compatibility layer
182 + require_once __DIR__ . '/includes/sbv-compatibility.php';
183 +
184 + // Docy Core compatibility layer (fixes Forums widget class not found error)
185 + require_once __DIR__ . '/includes/docy-core-compatibility.php';
186 +
187 + // Keep single-topic theme-compat from loading every topic/reply.
188 + require_once __DIR__ . '/includes/topic-render-guard.php';
189 +
190 + // Stop EazyDocs is_super_admin() from recursing during author cap checks.
191 + require_once __DIR__ . '/includes/eazydocs-compatibility.php';
192 +
193 + require_once __DIR__ . '/includes/functions.php';
194 +
195 + require_once __DIR__ . '/includes/template-functions.php';
196 + require_once __DIR__ . '/includes/bbpress-config.php';
197 +
198 + // Full Site Editing (block theme) compatibility – fixes blank page with Twenty Twenty-Five etc.
199 + require_once __DIR__ . '/includes/fse-compatibility.php';
200 +
201 + require_once __DIR__ . '/includes/admin/menu/Approve_Topic.php';
202 + require_once __DIR__ . '/includes/admin/menu/Create_Forum.php';
203 + require_once __DIR__ . '/includes/admin/menu/Create_Topic.php';
204 + require_once __DIR__ . '/includes/admin/menu/Delete_Forum.php';
205 + require_once __DIR__ . '/includes/admin/menu/Delete_Topic.php';
206 + require_once __DIR__ . '/includes/Elementor/Forumax_Widgets.php';
207 + require_once __DIR__ . '/includes/ajax_actions.php';
208 + include_once ABSPATH . 'wp-admin/includes/plugin.php';
209 +
210 + require_once __DIR__ . '/widgets/widgets.php';
211 + require_once __DIR__ . '/includes/Blocks/Blocks_Register.php';
212 + new \admin\Blocks\Blocks_Register();
213 + require_once __DIR__ . '/includes/Elementor/inc/forum-ajax.php';
214 +
215 + // Core installer notice
216 + require_once __DIR__ . '/includes/admin/notices/_notices.php';
217 +
218 + // Register Pro Widgets
219 + $theme = wp_get_theme();
220 +
221 + if ( 'Ama' !== $theme->get( 'Name' ) || ! forumax_is_premium() ) {
222 + require_once __DIR__ . '/includes/admin/Pro_El_Widget_Map.php';
223 + require_once __DIR__ . '/includes/admin/Pro_El_Widget_Service.php';
224 + }
225 +
226 + // Hooks
227 + require FORUMAX_DIR . 'includes/hooks/actions.php';
228 + require FORUMAX_DIR . 'includes/hooks/image_sizes.php';
229 + require FORUMAX_DIR . 'includes/login-form.php';
230 +
231 + require FORUMAX_DIR . '/includes/classes/Forumax_Forum_Class.php';
232 + }
233 +
234 + /**
235 + * Initializing Forumax class.
236 + *
237 + * @return \Forumax
238 + */
239 + static function init() {
240 + static $instance = false;
241 +
242 + if ( ! $instance ) {
243 + $instance = new self();
244 + }
245 + }
246 +
247 + /**
248 + * Actions on plugin activation.
249 + *
250 + * @return void
251 + */
252 + public function activate() {
253 + $installed = get_option( 'bbpc_installed' );
254 + if ( ! $installed ) {
255 + update_option( 'bbpc_installed', time() );
256 + }
257 +
258 + update_option( 'bbpc_version', FORUMAX_VERSION );
259 +
260 + // Ensure default option for forumax_settings
261 + $defaults = array(
262 + 'is_bbpc_insert_media' => false,
263 + );
264 +
265 + $current = get_option( 'bbp_core_settings', array() );
266 + $updated = wp_parse_args( $current, $defaults );
267 +
268 + update_option( 'bbp_core_settings', $updated );
269 +
270 + // Migrate old docy-core widgets to Forumax widgets
271 + $this->migrate_docy_core_widgets();
272 +
273 + // Set transient to redirect to setup wizard
274 + set_transient( 'forumax_activation_redirect', true, 30 );
275 + }
276 +
277 + /**
278 + * Actions on plugin deactivation.
279 + *
280 + * @return void
281 + */
282 + public function deactivate() {
283 + wp_clear_scheduled_hook( 'frmx_auto_close_stale_topics' );
284 + }
285 +
286 + /**
287 + * Redirect to setup wizard after plugin activation.
288 + *
289 + * @return void
290 + */
291 + public function redirect_to_setup_wizard() {
292 + // Check if we should redirect
293 + if ( ! get_transient( 'forumax_activation_redirect' ) ) {
294 + return;
295 + }
296 +
297 + // Don't redirect if activating multiple plugins or doing ajax
298 + if ( isset( $_GET['activate-multi'] ) || wp_doing_ajax() ) {
299 + delete_transient( 'forumax_activation_redirect' );
300 + return;
301 + }
302 +
303 + // Don't redirect if user doesn't have permission
304 + if ( ! current_user_can( 'manage_options' ) ) {
305 + delete_transient( 'forumax_activation_redirect' );
306 + return;
307 + }
308 +
309 + // Don't redirect while Freemius SDK is in activation/opt-in mode.
310 + // Freemius removes all submenu pages during activation mode, so
311 + // redirecting to forumax-setup would hit a non-existent page and
312 + // trigger "Sorry, you are not allowed to access this page."
313 + // The transient is preserved so the redirect fires after the
314 + // user completes or skips the Freemius opt-in.
315 + if ( function_exists( 'bc_fs' ) && bc_fs()->is_activation_mode() ) {
316 + return;
317 + }
318 +
319 + // Delete the transient so we don't redirect again
320 + delete_transient( 'forumax_activation_redirect' );
321 +
322 + // Redirect to setup wizard
323 + wp_safe_redirect( admin_url( 'admin.php?page=forumax-setup' ) );
324 + exit;
325 + }
326 +
327 + /**
328 + * Migrate plugin basename if the folder name changes during update.
329 + *
330 + * @param WP_Upgrader $upgrader_object
331 + * @param array $options
332 + * @return void
333 + */
334 + public function migrate_plugin_basename( $upgrader_object, $options ) {
335 + if ( isset( $options['action'] ) && $options['action'] === 'update' && isset( $options['type'] ) && $options['type'] === 'plugin' ) {
336 + $active_plugins = get_option( 'active_plugins' );
337 + if ( ! is_array( $active_plugins ) ) {
338 + return;
339 + }
340 +
341 + $changed = false;
342 + $migrations = array(
343 + 'bbp-core/bbp-core.php' => 'forumax/forumax.php',
344 + 'bbp-core/forumax.php' => 'forumax/forumax.php',
345 + 'bbp-core-pro/bbp-core.php' => 'forumax-pro/forumax.php',
346 + 'forumax-premium/bbp-core.php' => 'forumax-pro/forumax.php',
347 + 'forumax-premium/forumax.php' => 'forumax-pro/forumax.php',
348 + );
349 +
350 + foreach ( $migrations as $old_basename => $new_basename ) {
351 + $key = array_search( $old_basename, $active_plugins, true );
352 + if ( false !== $key ) {
353 + // Only migrate if the new file actually exists.
354 + if ( file_exists( WP_PLUGIN_DIR . '/' . $new_basename ) ) {
355 + $active_plugins[ $key ] = $new_basename;
356 + $changed = true;
357 + }
358 + }
359 + }
360 +
361 + if ( $changed ) {
362 + update_option( 'active_plugins', array_values( $active_plugins ) );
363 + }
364 + }
365 + }
366 +
367 + /**
368 + * Migrate old Docy Core Forums widgets to Forumax widgets
369 + *
370 + * This function automatically converts any existing docy-core Forums widgets
371 + * to the new Forumax Forums List widgets to ensure seamless transition.
372 + *
373 + * @return void
374 + */
375 + private function migrate_docy_core_widgets() {
376 + // Get all sidebars and their widgets
377 + $sidebars_widgets = get_option( 'sidebars_widgets', array() );
378 + $widget_migrated = false;
379 +
380 + // Get old docy-core widget settings
381 + // WordPress stores widget settings with lowercase class name and hyphens
382 + $old_widget_option_key = 'widget_docycore-wpwidgets-forums';
383 + $old_widget_options = get_option( $old_widget_option_key, array() );
384 +
385 + // New Forumax widget option key
386 + $new_widget_option_key = 'widget_forumax-wpwidgets-forumax_forums_list';
387 + $new_widget_options = get_option( $new_widget_option_key, array() );
388 +
389 + // Loop through each sidebar
390 + foreach ( $sidebars_widgets as $sidebar_id => $widgets ) {
391 + if ( $sidebar_id === 'wp_inactive_widgets' || $sidebar_id === 'array_version' || ! is_array( $widgets ) ) {
392 + continue;
393 + }
394 +
395 + // Loop through widgets in this sidebar
396 + foreach ( $widgets as $key => $widget_id ) {
397 + // WordPress widget ID format: {widget_base_id}-{instance_number}
398 + // Example: docycore-wpwidgets-forums-2
399 +
400 + // Check if this is an old docy-core Forums widget
401 + // Possible formats:
402 + // - docycore-wpwidgets-forums-{number}
403 + // - widget_docycore-wpwidgets-forums-{number}
404 + if ( preg_match( '/^(widget_)?docycore-wpwidgets-forums-(\d+)$/', $widget_id, $matches ) ) {
405 + $instance_number = $matches[2];
406 +
407 + // Check if old widget has settings
408 + if ( isset( $old_widget_options[ $instance_number ] ) ) {
409 + // Copy settings to new Forumax widget
410 + $new_widget_options[ $instance_number ] = $old_widget_options[ $instance_number ];
411 +
412 + // Update the widget ID in sidebar
413 + // New format: forumax-wpwidgets-forumax_forums_list-{number}
414 + $new_widget_id = 'forumax-wpwidgets-forumax_forums_list-' . $instance_number;
415 + $sidebars_widgets[ $sidebar_id ][ $key ] = $new_widget_id;
416 +
417 + $widget_migrated = true;
418 +
419 + // Log migration (for debugging)
420 + error_log(
421 + sprintf(
422 + 'Forumax: Migrated widget from "%s" to "%s" in sidebar "%s"',
423 + $widget_id,
424 + $new_widget_id,
425 + $sidebar_id
426 + )
427 + );
428 + }
429 + }
430 + }
431 + }
432 +
433 + // Save updated widget options and sidebars if any widget was migrated
434 + if ( $widget_migrated ) {
435 + update_option( $new_widget_option_key, $new_widget_options );
436 + update_option( 'sidebars_widgets', $sidebars_widgets );
437 +
438 + // Log successful migration
439 + error_log( 'Forumax: Widget migration completed successfully' );
440 + }
441 + }
442 +
443 +
444 + /**
445 + * Initialize the plugin functionality.
446 + *
447 + * @return void
448 + */
449 + public function init_plugin() {
450 +
451 + $this->load_features();
452 +
453 + if ( is_admin() ) {
454 + new Admin();
455 + new admin\Admin_Assets();
456 +
457 + // Helpdesk docs assistant on Forumax admin pages.
458 + require_once __DIR__ . '/includes/admin/class-support-assistant.php';
459 + \Forumax_Support_Assistant::get_instance();
460 +
461 + // Check for widget migration on every admin load (once per session)
462 + // This catches cases where plugins were updated in wrong order
463 + add_action( 'admin_init', array( $this, 'check_widget_migration' ), 5 );
464 + } elseif ( ! is_admin() ) {
465 + new Frontend\Frontend_Assets();
466 + }
467 +
468 + // If bbPress is not active, don't load assets and widgets.
469 + if ( ! class_exists( 'bbPress' ) || ! class_exists( 'Forumax' ) ) {
470 + return;
471 + }
472 +
473 + new admin\Elementor\Forumax_Widgets();
474 + }
475 +
476 + /**
477 + * Check and run widget migration if needed
478 + *
479 + * This runs on admin_init to catch widgets that need migration
480 + * even if the plugin was updated in the wrong order.
481 + *
482 + * @return void
483 + */
484 + public function check_widget_migration() {
485 +
486 + /**
487 + * forumax list widget id update
488 + *
489 + * @var mixed
490 + */
491 +
492 + $new_id = 'forumax_forums_list';
493 + $new_option_name = 'widget_' . $new_id;
494 + $new_data = get_option( $new_option_name );
495 +
496 + if ( empty( $new_data ) || ( is_array( $new_data ) && count( $new_data ) <= 1 ) ) {
497 +
498 + $docy_data = get_option( 'widget_forums' );
499 +
500 + $docly_data = get_option( 'widget_doclycore\\wpwidgets\\forums_widget' );
501 +
502 + $ama_data = get_option( 'widget_amacore\\wpwidgets\\forums_widget' );
503 +
504 + if ( ! empty( $docy_data ) && is_array( $docy_data ) && count( $docy_data ) > 1 ) {
505 + update_option( $new_option_name, $docy_data );
506 + } elseif ( ! empty( $docly_data ) && is_array( $docly_data ) && count( $docly_data ) > 1 ) {
507 + update_option( $new_option_name, $docly_data );
508 + } elseif ( ! empty( $ama_data ) && is_array( $ama_data ) && count( $ama_data ) > 1 ) {
509 + update_option( $new_option_name, $ama_data );
510 + }
511 + }
512 +
513 + // Check if migration has already been done
514 + $migration_done = get_option( 'forumax_widget_migration_done', false );
515 +
516 + if ( $migration_done ) {
517 + return; // Already migrated
518 + }
519 +
520 + // Check if there are any old docy-core widgets that need migration
521 + $sidebars_widgets = get_option( 'sidebars_widgets', array() );
522 + $needs_migration = false;
523 +
524 + foreach ( $sidebars_widgets as $sidebar_id => $widgets ) {
525 + if ( $sidebar_id === 'wp_inactive_widgets' || $sidebar_id === 'array_version' || ! is_array( $widgets ) ) {
526 + continue;
527 + }
528 +
529 + foreach ( $widgets as $widget_id ) {
530 + if ( preg_match( '/^(widget_)?docycore-wpwidgets-forums-(\d+)$/', $widget_id ) ) {
531 + $needs_migration = true;
532 + break 2; // Break out of both loops
533 + }
534 + }
535 + }
536 +
537 + if ( $needs_migration ) {
538 + // Run migration
539 + $this->migrate_docy_core_widgets();
540 +
541 + // Mark as done
542 + update_option( 'forumax_widget_migration_done', true );
543 +
544 + // Add admin notice
545 + add_action(
546 + 'admin_notices',
547 + function () {
548 + ?>
549 + <div class="notice notice-success is-dismissible">
550 + <p>
551 + <strong><?php esc_html_e( 'Forumax:', 'forumax' ); ?></strong>
552 + <?php esc_html_e( 'Your widgets have been automatically migrated from Docy Core to Forumax.', 'forumax' ); ?>
553 + </p>
554 + </div>
555 + <?php
556 + }
557 + );
558 + } else {
559 + // No migration needed, mark as done
560 + update_option( 'forumax_widget_migration_done', true );
561 + }
562 + }
563 +
564 +
565 + /**
566 + * Include CSF files include
567 + */
568 + public function load_csf_files() {
569 + require FORUMAX_DIR . 'lib/csf/classes/setup.class.php';
570 + require FORUMAX_DIR . 'includes/admin/options/settings.php';
571 + }
572 +
573 + /**
574 + * Load different features.
575 + *
576 + * @return void
577 + */
578 + public function load_features() {
579 + define( 'FORUMAX_FEAT_PATH', plugin_dir_path( __FILE__ ) . 'includes/features/' );
580 +
581 + if ( forumax_get_opt( 'is_solved_topics', true ) ) {
582 + require FORUMAX_FEAT_PATH . 'bbp_solved_topic.php';
583 + }
584 +
585 + // Auto Close Stale Topics
586 + require FORUMAX_FEAT_PATH . 'forumax_auto_close.php';
587 +
588 + if ( forumax_get_opt( 'is_private_replies', true ) ) {
589 + require FORUMAX_FEAT_PATH . 'bbp-private-replies.php';
590 + }
591 +
592 + if ( forumax_get_opt( 'is_votes', true ) ) {
593 + new features\bbp_voting();
594 + }
595 +
596 + if ( forumax_get_opt( 'is_attachment', true ) ) {
597 + new features\bbp_attachments();
598 + }
599 +
600 + /**
601 + * Action hook for Forumax premium plugin to load
602 + * premium-only features (Gamification, Nested Replies,
603 + * Agree/Disagree Voting, etc.).
604 + *
605 + * @since 2.3.0
606 + */
607 + do_action( 'forumax_load_premium_features' );
608 +
609 + // Custom Profile Avatar Upload.
610 + require_once FORUMAX_FEAT_PATH . 'frmx-profile-avatar.php';
611 +
612 + // Inline AJAX editing for topics.
613 + require_once FORUMAX_FEAT_PATH . 'frmx-inline-edit.php';
614 + }
615 +
616 + /**
617 + * Documentation links to plugin row meta
618 + */
619 + public function forumax_row_meta( $links, $file ) {
620 + // Check if this is your plugin
621 + if ( plugin_basename( __FILE__ ) === $file ) {
622 + // Add your custom links
623 + $plugin_links = array(
624 + '<a href="https://helpdesk.spider-themes.net/docs/forumax-wordpress-plugin/" target="_blank">' . esc_html__( 'Documentation', 'forumax' ) . '</a>',
625 + );
626 + // Merge the custom links with the existing links
627 + $links = array_merge( $links, $plugin_links );
628 + }
629 +
630 + return $links;
631 + }
632 +
633 + /**
634 + * Prevent deactivation of Forumax if Forumax Pro is active
635 + * Users must deactivate Forumax Pro first before deactivating Forumax
636 + *
637 + * @return void
638 + */
639 + public function prevent_deactivation_if_pro_active() {
640 + // Check if we're on the plugins page
641 + if ( ! isset( $_SERVER['REQUEST_URI'] ) || strpos( $_SERVER['REQUEST_URI'], 'plugins.php' ) === false ) {
642 + return;
643 + }
644 +
645 + // Check if user is trying to deactivate this plugin
646 + if ( isset( $_GET['action'] ) && $_GET['action'] === 'deactivate' &&
647 + isset( $_GET['plugin'] ) && $_GET['plugin'] === plugin_basename( __FILE__ ) ) {
648 +
649 + // Check if Forumax Pro is active
650 + if ( is_plugin_active( 'forumax-premium/forumax.php' ) ) {
651 + // Prevent deactivation
652 + wp_die(
653 + '<h1>' . esc_html__( 'Cannot Deactivate Forumax', 'forumax' ) . '</h1>' .
654 + '<p>' . esc_html__( 'You cannot deactivate Forumax while Forumax Pro is active.', 'forumax' ) . '</p>' .
655 + '<p>' . esc_html__( 'Please deactivate Forumax Pro first, then you can deactivate Forumax.', 'forumax' ) . '</p>',
656 + esc_html__( 'Plugin Dependency Error', 'forumax' ),
657 + array( 'back_link' => true )
658 + );
659 + }
660 + }
661 + }
662 +
663 + /**
664 + * Modify the deactivate link to show a disabled state when Forumax Pro is active
665 + *
666 + * @param array $actions An array of plugin action links.
667 + * @param string $plugin_file Path to the plugin file relative to the plugins directory.
668 + * @param array $plugin_data An array of plugin data.
669 + * @param string $context The plugin context (active, inactive, etc).
670 + * @return array Modified action links
671 + */
672 + public function modify_deactivate_link( $actions, $plugin_file, $plugin_data, $context ) {
673 + // Check if Forumax Pro is active
674 + if ( is_plugin_active( 'forumax-premium/forumax.php' ) ) {
675 + // Remove the default deactivate link
676 + if ( isset( $actions['deactivate'] ) ) {
677 + unset( $actions['deactivate'] );
678 +
679 + // Add a disabled deactivate message
680 + $actions['deactivate_disabled'] = '<span style="color: #a0a5aa; cursor: not-allowed;" title="' .
681 + esc_attr__( 'Please deactivate Forumax Pro first', 'forumax' ) . '">' .
682 + esc_html__( 'Deactivate', 'forumax' ) .
683 + '</span>';
684 + }
685 + }
686 +
687 + return $actions;
688 + }
689 +}
690 +
691 +/**
692 + * Initialize the Forumax plugin.
693 + *
694 + * @return \Forumax
695 + */
696 +function forumax() {
697 + return Forumax::init();
698 +}
699 +
700 +forumax();