PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 3.8.9
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v3.8.9
4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 All 200 releases
← All changes | includes/Plugin.php +348 -483 4.9.03.8.9 View file →
@@ -2,9 +2,9 @@
2 2
3 3 namespace WPDeveloper\BetterDocs;
4 4
5 5 if ( ! defined( 'ABSPATH' ) ) {
6 - exit; // Exit if accessed directly
6 + exit; // Exit if accessed directly
7 7 }
8 8
9 9 use WPDeveloper\BetterDocs\Admin\Analytics;
10 10 use WPDeveloper\BetterDocs\Admin\Customizer\Customizer;
@@ -10,10 +10,8 @@
10 10 use WPDeveloper\BetterDocs\Admin\Customizer\Customizer;
11 11 use WPDeveloper\BetterDocs\Admin\HelpScoutMigration;
12 12 use WPDeveloper\BetterDocs\Admin\ReportEmail;
13 13 use WPDeveloper\BetterDocs\Core\Admin;
14 -use WPDeveloper\BetterDocs\Core\AnalyticsTracker;
15 -use WPDeveloper\BetterDocs\Core\AnalyticsRetention;
16 14 use WPDeveloper\BetterDocs\Core\BaseAPI;
17 15 use WPDeveloper\BetterDocs\Core\Install;
18 16 use WPDeveloper\BetterDocs\Core\KBMigration;
19 17 use WPDeveloper\BetterDocs\Core\Query;
@@ -23,21 +21,13 @@
23 21 use WPDeveloper\BetterDocs\Core\Scripts;
24 22 use WPDeveloper\BetterDocs\Core\Settings;
25 23 use WPDeveloper\BetterDocs\Core\ShortcodeFactory;
26 24 use WPDeveloper\BetterDocs\Core\WriteWithAI;
27 -use WPDeveloper\BetterDocs\Core\ArticleSummary;
28 -use WPDeveloper\BetterDocs\Core\ArticleQualityScore;
29 -use WPDeveloper\BetterDocs\Core\UnifiedMetabox;
30 -use WPDeveloper\BetterDocs\Core\DocsAISuite;
31 25 use WPDeveloper\BetterDocs\Dependencies\DI\Container;
32 26 use WPDeveloper\BetterDocs\Dependencies\DI\ContainerBuilder;
33 27 use WPDeveloper\BetterDocs\Editors\Editor;
34 28 use WPDeveloper\BetterDocs\FrontEnd\FrontEnd;
35 -use WPDeveloper\BetterDocs\FrontEnd\SearchExtender;
36 29 use WPDeveloper\BetterDocs\FrontEnd\TemplateTags;
37 -use WPDeveloper\BetterDocs\FrontEnd\WooProductFAQ;
38 -use WPDeveloper\BetterDocs\Abilities\AbilitiesRegistrar;
39 -use WPDeveloper\BetterDocs\Mcp\MCPManager;
40 30 use WPDeveloper\BetterDocs\Modules\StyleHandler as ModulesStyleHandler;
41 31 use WPDeveloper\BetterDocs\Utils\Database;
42 32 use WPDeveloper\BetterDocs\Utils\Enqueue;
43 33 use WPDeveloper\BetterDocs\Utils\Helper;
@@ -43,539 +33,414 @@
43 33 use WPDeveloper\BetterDocs\Utils\Helper;
44 34 use WPDeveloper\BetterDocs\Utils\Views;
45 35
46 36 final class Plugin {
47 - private static $_instance = null;
48 - /**
49 - * Assets manager
50 - *
51 - * @var Enqueue
52 - */
53 - public $assets;
54 - /**
55 - * View manager
56 - *
57 - * @var Views
58 - */
59 - public $views;
60 - /**
61 - * Container Manager
62 - *
63 - * @var Container
64 - */
65 - public $container;
66 - /**
67 - * Editor Manager
68 - * @var Editor
69 - */
70 - public $editor;
71 - /**
72 - * Helper class
73 - * @var Helper
74 - */
75 - public $helper;
76 - /**
77 - * KBMigration class
78 - * @var KBMigration
79 - */
80 - public $kbmigration;
81 - /**
82 - * KBMigration class
83 - * @var Admin
84 - */
85 - public $admin;
86 - /**
87 - * Helper class
88 - * @var Database
89 - */
90 - public $database;
91 - /**
92 - * Helper class
93 - * @var Settings
94 - */
95 - public $settings;
96 - /**
97 - * Helper class
98 - * @var TemplateTags
99 - */
100 - public $template_helper;
101 - /**
102 - * Article Summary class
103 - * @var ArticleSummary
104 - */
105 - public $article_summary;
106 - /**
107 - * Customizer class
108 - * @var Customizer
109 - */
110 - public $customizer;
111 - /**
112 - * Query class
113 - * @var Query
114 - */
115 - public $query;
116 - /**
117 - * Rewrite Class
118 - * @var Rewrite
119 - */
120 - public $rewrite;
121 - /**
122 - * Request Class
123 - * @var Request
124 - */
125 - public $request;
126 - /**
127 - * Analytics Class
128 - * @var Analytics
129 - */
130 - public $analytics;
131 - /**
132 - * Plugin Version
133 - * @var string
134 - */
135 - public $version = '4.9.0';
37 + private static $_instance = null;
38 + /**
39 + * Assets manager
40 + *
41 + * @var Enqueue
42 + */
43 + public $assets;
44 + /**
45 + * View manager
46 + *
47 + * @var Views
48 + */
49 + public $views;
50 + /**
51 + * Container Manager
52 + *
53 + * @var Container
54 + */
55 + public $container;
56 + /**
57 + * Editor Manager
58 + * @var Editor
59 + */
60 + public $editor;
61 + /**
62 + * Helper class
63 + * @var Helper
64 + */
65 + public $helper;
66 + /**
67 + * KBMigration class
68 + * @var KBMigration
69 + */
70 + public $kbmigration;
71 + /**
72 + * KBMigration class
73 + * @var Admin
74 + */
75 + public $admin;
76 + /**
77 + * Helper class
78 + * @var Database
79 + */
80 + public $database;
81 + /**
82 + * Helper class
83 + * @var Settings
84 + */
85 + public $settings;
86 + /**
87 + * Helper class
88 + * @var TemplateTags
89 + */
90 + public $template_helper;
91 + /**
92 + * Customizer class
93 + * @var Customizer
94 + */
95 + public $customizer;
96 + /**
97 + * Query class
98 + * @var Query
99 + */
100 + public $query;
101 + /**
102 + * Rewrite Class
103 + * @var Rewrite
104 + */
105 + public $rewrite;
106 + /**
107 + * Request Class
108 + * @var Request
109 + */
110 + public $request;
111 + /**
112 + * Analytics Class
113 + * @var Analytics
114 + */
115 + public $analytics;
116 + /**
117 + * Plugin Version
118 + * @var string
119 + */
120 + public $version = '3.8.9';
136 121
137 - /**
138 - * WriteWithAI Class
139 - * @var string
140 - */
141 - public $ai_autowrtie;
142 - public $backgroundProccessor;
122 + /**
123 + * WriteWithAI Class
124 + * @var string
125 + */
126 + public $ai_autowrtie;
127 + public $backgroundProccessor;
143 128
144 - /**
145 - * ArticleQualityScore Class
146 - * @var ArticleQualityScore
147 - */
148 - public $article_quality_score;
129 + /**
130 + * Plugin DB Version
131 + * @var string
132 + */
133 + public $db_version = '1.0.1';
149 134
150 - /**
151 - * Plugin DB Version
152 - * @var string
153 - */
154 - public $db_version = '1.0.2';
135 + public function __construct() {
136 + $this->define_constants();
155 137
156 - public function __construct() {
157 - $this->define_constants();
138 + do_action( 'betterdocs_init_before' );
158 139
159 - do_action( 'betterdocs_init_before' );
140 + $this->setup_container();
141 + /**
142 + * Register activation and deactivation hooks
143 + * and version updates check
144 + */
145 + $this->container->get( Install::class );
160 146
161 - $this->setup_container();
162 - /**
163 - * Register activation and deactivation hooks
164 - * and version updates check
165 - */
166 - $this->container->get( Install::class );
147 + add_action( 'init', [ $this, 'initialize' ], 0 );
167 148
168 - /**
169 - * Abilities API registrar.
170 - *
171 - * Resolved here, at plugin load, and not from initialize(): both the
172 - * bundled Abilities API and WordPress core's build their registry as a
173 - * lazy singleton and fire `wp_abilities_api_init` from it, at or after
174 - * `init`, the first time anything reads the registry. Our listeners
175 - * therefore have to be attached before that first read, whenever it
176 - * happens — and a container resolve on `init` would already be too late
177 - * for a plugin that reads the registry earlier in the same hook.
178 - */
179 - $this->container->get( AbilitiesRegistrar::class );
149 + /**
150 + * Initialize API
151 + */
152 + add_action( 'rest_api_init', [ $this, 'api_initialization' ] );
180 153
181 - add_action( 'init', array( $this, 'initialize' ), 0 );
154 + /**
155 + * For admin only
156 + */
157 + add_action( 'admin_init', [ $this, 'admin_init' ], 0 );
182 158
183 - /**
184 - * Initialize API
185 - */
186 - add_action( 'rest_api_init', array( $this, 'api_initialization' ) );
159 + /**
160 + * For AJAX only
161 + */
162 + $this->ajax();
187 163
188 - /**
189 - * For admin only
190 - */
191 - add_action( 'admin_init', array( $this, 'admin_init' ), 0 );
164 + /**
165 + * Style Handler For Parsing and Saving Styles as file.
166 + */
167 + ModulesStyleHandler::init();
168 + }
192 169
193 - /**
194 - * For AJAX only
195 - */
196 - $this->ajax();
170 + private function define_constants() {
171 + $this->define( 'BETTERDOCS_VERSION', $this->version );
172 + $this->define( 'BETTERDOCS_DB_VERSION', $this->db_version );
173 + $this->define( 'BETTERDOCS_ABSPATH', dirname( BETTERDOCS_PLUGIN_FILE ) . '/' );
174 + $this->define( 'BETTERDOCS_ABSURL', plugin_dir_url( BETTERDOCS_PLUGIN_FILE ) );
175 + $this->define( 'BETTERDOCS_PLUGIN_BASENAME', plugin_basename( BETTERDOCS_PLUGIN_FILE ) );
176 + $this->define( 'BETTERDOCS_BLOCKS_DIRECTORY', BETTERDOCS_ABSPATH . 'assets/blocks/' );
177 + $this->define( 'BETTERDOCS_ROOT_DIR_PATH', plugin_dir_path( BETTERDOCS_PLUGIN_FILE ) );
178 + $this->define( 'BETTERDOCS_FSE_TEMPLATES_PATH', BETTERDOCS_ROOT_DIR_PATH . 'views/templates/fse' );
197 179
198 - /**
199 - * Style Handler For Parsing and Saving Styles as file.
200 - */
201 - ModulesStyleHandler::init();
202 - }
180 + /**
181 + * Third Party Constants
182 + * @since 2.5.0
183 + *
184 + * WPML compatibility with Polylang
185 + */
186 + if ( Helper::is_plugin_active( 'polylang/polylang.php' ) ) {
187 + define( 'PLL_WPML_COMPAT', false );
188 + }
189 + }
203 190
204 - private function define_constants() {
205 - $this->define( 'BETTERDOCS_VERSION', $this->version );
206 - $this->define( 'BETTERDOCS_DB_VERSION', $this->db_version );
207 - $this->define( 'BETTERDOCS_ABSPATH', dirname( BETTERDOCS_PLUGIN_FILE ) . '/' );
208 - $this->define( 'BETTERDOCS_ABSURL', plugin_dir_url( BETTERDOCS_PLUGIN_FILE ) );
209 - $this->define( 'BETTERDOCS_PLUGIN_BASENAME', plugin_basename( BETTERDOCS_PLUGIN_FILE ) );
210 - // Compiled block metadata lives under assets/build/ since the Node 24 asset
211 - // restructure; register_block_type() fails silently if this path is wrong.
212 - $this->define( 'BETTERDOCS_BLOCKS_DIRECTORY', BETTERDOCS_ABSPATH . 'assets/build/blocks/' );
213 - $this->define( 'BETTERDOCS_ROOT_DIR_PATH', plugin_dir_path( BETTERDOCS_PLUGIN_FILE ) );
214 - $this->define( 'BETTERDOCS_FSE_TEMPLATES_PATH', BETTERDOCS_ROOT_DIR_PATH . 'views/templates/fse' );
191 + /**
192 + * Define constant if not already set.
193 + *
194 + * @param string $name Constant name.
195 + * @param string|bool $value Constant value.
196 + */
197 + private function define( $name, $value ) {
198 + if ( ! defined( $name ) ) {
199 + define( $name, $value );
200 + }
201 + }
215 202
216 - /**
217 - * Third Party Constants
218 - * @since 2.5.0
219 - *
220 - * WPML compatibility with Polylang
221 - */
222 - if ( Helper::is_plugin_active( 'polylang/polylang.php' ) ) {
223 - // Polylang's documented integration constant — must use the upstream-defined name.
224 - // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
225 - define( 'PLL_WPML_COMPAT', false );
226 - }
227 - }
203 + public function setup_container() {
204 + $config_array = require_once BETTERDOCS_ABSPATH . 'includes/config.php';
205 + $config = apply_filters( 'betterdocs_container_config', $config_array );
206 + $builder = new ContainerBuilder();
228 207
229 - /**
230 - * Define constant if not already set.
231 - *
232 - * @param string $name Constant name.
233 - * @param string|bool $value Constant value.
234 - */
235 - private function define( $name, $value ) {
236 - if ( ! defined( $name ) ) {
237 - // Caller passes plugin-prefixed names (BETTERDOCS_*); $name comes from a controlled internal allowlist.
238 - // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.VariableConstantNameFound
239 - define( $name, $value );
240 - }
241 - }
208 + $builder->addDefinitions( $config );
209 + $this->container = $builder->build();
210 + }
242 211
243 - public function setup_container() {
244 - $config_array = require_once BETTERDOCS_ABSPATH . 'includes/config.php';
245 - $config = apply_filters( 'betterdocs_container_config', $config_array );
246 - $builder = new ContainerBuilder();
212 + public function initialize() {
247 213
248 - $builder->addDefinitions( $config );
249 - $this->container = $builder->build();
250 - }
214 + /**
215 + * Setup localization.
216 + */
217 + $this->load_plugin_textdomain();
251 218
252 - public function initialize() {
219 + $this->container->get( Scripts::class );
220 + $this->rewrite = $this->container->get( Rewrite::class );
221 + $this->request = $this->container->get( Request::class );
222 + $this->query = $this->container->get( Query::class );
253 223
254 - /**
255 - * Setup localization.
256 - */
257 - $this->load_plugin_textdomain();
224 + // Initialize background process
225 + $this->backgroundProccessor = $this->container->get( HelpScoutMigration::class );
258 226
259 - $this->container->get( Scripts::class );
260 - $this->rewrite = $this->container->get( Rewrite::class );
261 - $this->request = $this->container->get( Request::class );
262 - $this->query = $this->container->get( Query::class );
227 + $this->rewrite->init();
228 + $this->request->init();
263 229
264 - // Initialize background process
265 - $this->backgroundProccessor = $this->container->get( HelpScoutMigration::class );
230 + $this->assets = $this->container->get( Enqueue::class );
231 + $this->views = $this->container->get( Views::class );
232 + $this->helper = $this->container->get( Helper::class );
233 + $this->kbmigration = $this->container->get( KBMigration::class );
234 + $this->admin = $this->container->get( Admin::class );
235 + $this->database = $this->container->get( Database::class );
236 + $this->settings = $this->container->get( Settings::class );
237 + $this->analytics = $this->container->get( Analytics::class );
266 238
267 - $this->rewrite->init();
268 - $this->request->init();
239 + $this->template_helper = $this->container->get( TemplateTags::class );
240 + $this->customizer = $this->container->get( Customizer::class );
241 + $this->editor = $this->container->get( Editor::class );
242 + $this->ai_autowrtie = $this->container->get( WriteWithAI::class );
269 243
270 - $this->assets = $this->container->get( Enqueue::class );
271 - $this->views = $this->container->get( Views::class );
272 - $this->helper = $this->container->get( Helper::class );
273 - $this->kbmigration = $this->container->get( KBMigration::class );
274 - $this->admin = $this->container->get( Admin::class );
275 - $this->database = $this->container->get( Database::class );
276 - $this->settings = $this->container->get( Settings::class );
277 - $this->analytics = $this->container->get( Analytics::class );
278 - // Free analytics collectors: the frontend view/scroll tracker and the
279 - // daily retention purge. Each self-registers its hooks on construct.
280 - $this->container->get( AnalyticsTracker::class );
281 - $this->container->get( AnalyticsRetention::class );
244 + $this->container->get( Admin::class );
245 + $this->container->get( Roles::class );
246 + $this->container->get( ReportEmail::class );
282 247
283 - $this->template_helper = $this->container->get( TemplateTags::class );
284 - $this->customizer = $this->container->get( Customizer::class );
285 - $this->editor = $this->container->get( Editor::class );
286 - $this->ai_autowrtie = $this->container->get( WriteWithAI::class );
287 - $this->article_summary = $this->container->get( ArticleSummary::class );
248 + /**
249 + * Initialize Shortcode
250 + * Make sure you have listed out all shortcode in shortcode factory.
251 + */
252 + $this->container->get( ShortcodeFactory::class )->init();
288 253
289 - // Initialize unified metabox before individual features
290 - $this->container->get( UnifiedMetabox::class );
291 - $this->article_quality_score = $this->container->get( ArticleQualityScore::class );
254 + $this->container->get( FrontEnd::class );
292 255
293 - // Editor "Suggest Categories / Tags / Glossaries" AI actions on the docs
294 - // post type (gated by enable_docs_ai_suite + an OpenAI key inside the class).
295 - $this->container->get( DocsAISuite::class );
256 + do_action( 'betterdocs_init' );
296 257
297 - $this->container->get( Admin::class );
298 - $this->container->get( Roles::class );
258 + $this->editor->init();
259 + }
299 260
300 - /**
301 - * MCP transport: rewrite rules, the pretty endpoint, OAuth discovery
302 - * and every REST route. Resolved here rather than at plugin load
303 - * (where the abilities registrar has to be) because its earliest hook
304 - * is `init`, which is what this method already runs on.
305 - */
306 - $this->container->get( MCPManager::class );
261 + /**
262 + * Load plugins textdomain `betterdocs` into actions.
263 + * @return void
264 + */
265 + public function load_plugin_textdomain( $textdomain = 'betterdocs', $plugin_file = BETTERDOCS_PLUGIN_FILE ) {
266 + $locale = determine_locale();
307 267
308 - $this->container->get( ReportEmail::class );
309 - // Usage-analytics collector. Registered here (runs on every request, incl.
310 - // WP-Cron) rather than in Admin so its `betterdocs_insights_data` filter
311 - // callback is present whenever the tracking payload is built.
312 - $this->container->get( \WPDeveloper\BetterDocs\Insights\Collector::class );
313 - /**
314 - * Initialize Shortcode
315 - * Make sure you have listed out all shortcode in shortcode factory.
316 - */
317 - $this->container->get( ShortcodeFactory::class )->init();
268 + /**
269 + * Filter to adjust the BetterDocs locale to use for translations.
270 + */
271 + $locale = apply_filters( 'plugin_locale', $locale, $textdomain );
318 272
319 - $this->container->get( FrontEnd::class );
320 - $this->container->get( SearchExtender::class );
273 + if ( file_exists( WP_LANG_DIR . "/$textdomain-" . $locale . '.mo' ) ) {
274 + unload_textdomain( $textdomain );
275 + load_textdomain( $textdomain, WP_LANG_DIR . "/$textdomain-" . $locale . '.mo' );
276 + }
321 277
322 - /**
323 - * Single-product FAQ rendering (WooCommerce). The class itself bails when
324 - * WooCommerce is inactive or the feature is disabled.
325 - */
326 - $this->container->get( WooProductFAQ::class );
278 + load_plugin_textdomain( $textdomain, false, plugin_basename( dirname( $plugin_file ) ) . '/languages' );
279 + }
327 280
328 - do_action( 'betterdocs_init' );
281 + /**
282 + * For AJAX Only
283 + * @return void
284 + */
285 + public function ajax() {
286 + }
329 287
330 - $this->editor->init();
331 - }
288 + /**
289 + * Create a plugin instance.
290 + *
291 + * @param mixed ...$args
292 + *
293 + * @return static
294 + *
295 + * @suppress PHP0441
296 + * @since 2.5.0
297 + */
298 + public static function get_instance() {
299 + if ( self::$_instance == null ) {
300 + self::$_instance = new self();
332 301
333 - /**
334 - * Load plugins textdomain `betterdocs` into actions.
335 - * @return void
336 - */
337 - public function load_plugin_textdomain( $textdomain = 'betterdocs', $plugin_file = BETTERDOCS_PLUGIN_FILE ) {
338 - $locale = determine_locale();
302 + do_action( 'betterdocs_loaded' );
303 + }
339 304
340 - /**
341 - * Filter to adjust the BetterDocs locale to use for translations.
342 - */
343 - // 'plugin_locale' is a WP-core filter; using its documented name is required.
344 - // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
345 - $locale = apply_filters( 'plugin_locale', $locale, $textdomain );
305 + return self::$_instance;
306 + }
346 307
347 - if ( file_exists( WP_LANG_DIR . "/$textdomain-" . $locale . '.mo' ) ) {
348 - unload_textdomain( $textdomain );
349 - load_textdomain( $textdomain, WP_LANG_DIR . "/$textdomain-" . $locale . '.mo' );
350 - }
351 - }
308 + /**
309 + * Hooked with `admin_init` action.
310 + * @return void
311 + */
312 + public function admin_init() {
313 + /**
314 + * Maybe Redirect
315 + * for setup related settings.
316 + */
317 + $this->maybe_redirect();
318 + }
352 319
353 - /**
354 - * For AJAX Only
355 - * @return void
356 - */
357 - public function ajax() {
358 - }
320 + /**
321 + * Summary of maybe_redirect
322 + * @return void
323 + */
324 + public function maybe_redirect() {
325 + // Bail if no activation transient is set.
326 + if ( ! $this->database->get_transient( 'betterdocs_maybe_redirect' ) ) {
327 + return;
328 + }
359 329
360 - /**
361 - * Create a plugin instance.
362 - *
363 - * @param mixed ...$args
364 - *
365 - * @return static
366 - *
367 - * @suppress PHP0441
368 - * @since 2.5.0
369 - */
370 - public static function get_instance() {
371 - if ( null == self::$_instance ) {
372 - self::$_instance = new self();
330 + // Delete the activation transient.
331 + $this->database->delete_transient( 'betterdocs_maybe_redirect' );
373 332
374 - do_action( 'betterdocs_loaded' );
375 - }
333 + if ( ! is_multisite() ) {
334 + $betterdocs_settings = get_option( 'betterdocs_settings' );
335 + if ( $betterdocs_settings ) {
336 + wp_safe_redirect( add_query_arg( [ 'page' => 'betterdocs-settings' ], admin_url( 'admin.php' ) ) );
337 + } else {
338 + wp_safe_redirect( add_query_arg( [ 'page' => 'betterdocs-setup' ], admin_url( 'admin.php' ) ) );
339 + }
340 + }
341 + }
376 342
377 - return self::$_instance;
378 - }
343 + /**
344 + * Is Pro Plugin Is Installed?
345 + * @return bool
346 + */
347 + public function is_pro_installed() {
348 + return $this->helper->get_plugins( 'betterdocs-pro/betterdocs-pro.php' );
349 + }
379 350
380 - /**
381 - * Hooked with `admin_init` action.
382 - * @return void
383 - */
384 - public function admin_init() {
385 - /**
386 - * Maybe Redirect
387 - * for setup related settings.
388 - */
389 - $this->maybe_redirect();
390 - }
351 + /**
352 + * Is Pro Plugin Is Active?
353 + * @return bool
354 + */
355 + public function pro_file() {
356 + return WP_PLUGIN_DIR . '/betterdocs-pro/betterdocs-pro.php';
357 + }
391 358
392 - /**
393 - * Summary of maybe_redirect
394 - * @return void
395 - */
396 - public function maybe_redirect() {
397 - // Bail if no activation transient is set.
398 - if ( ! $this->database->get_transient( 'betterdocs_maybe_redirect' ) ) {
399 - return;
400 - }
359 + public function is_pro_active() {
360 + if ( file_exists( $this->pro_file() ) ) {
361 + return $this->helper->is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' );
362 + }
401 363
402 - // Delete the activation transient.
403 - $this->database->delete_transient( 'betterdocs_maybe_redirect' );
364 + return false;
365 + }
404 366
405 - if ( ! is_multisite() ) {
406 - $betterdocs_settings = get_option( 'betterdocs_settings' );
407 - if ( $betterdocs_settings ) {
408 - wp_safe_redirect( add_query_arg( array( 'page' => 'betterdocs-settings' ), admin_url( 'admin.php' ) ) );
409 - } else {
410 - wp_safe_redirect( add_query_arg( array( 'page' => 'betterdocs-setup' ), admin_url( 'admin.php' ) ) );
411 - }
412 - // This runs at `admin_init` priority 0. Without exiting, the rest of
413 - // admin_init still executes and can mutate the very state the redirect
414 - // target depends on before the browser ever follows the Location header.
415 - exit;
416 - }
417 - }
367 + public function pro_version() {
368 + if ( ! $this->is_pro_active() ) {
369 + return false;
370 + }
418 371
419 - /**
420 - * Is Pro Plugin Is Installed?
421 - * @return bool
422 - */
423 - public function is_pro_installed() {
424 - return $this->helper->get_plugins( 'betterdocs-pro/betterdocs-pro.php' );
425 - }
372 + if ( ! function_exists( 'get_plugin_data' ) ) {
373 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
374 + }
426 375
427 - /**
428 - * Is Pro Plugin Is Active?
429 - * @return bool
430 - */
431 - public function pro_file() {
432 - return WP_PLUGIN_DIR . '/betterdocs-pro/betterdocs-pro.php';
433 - }
376 + $plugin_data = get_plugin_data( $this->pro_file() );
434 377
435 - public function is_pro_active() {
436 - if ( file_exists( $this->pro_file() ) ) {
437 - return $this->helper->is_plugin_active( 'betterdocs-pro/betterdocs-pro.php' );
438 - }
378 + return $plugin_data['Version'];
379 + }
439 380
440 - return false;
441 - }
381 + /**
382 + * Get all the API initialized.
383 + * @return void
384 + */
385 + public function api_initialization() {
386 + $_api_classes = scandir( __DIR__ . DIRECTORY_SEPARATOR . 'REST' );
442 387
443 - public function chatbot_file() {
444 - return WP_PLUGIN_DIR . '/betterdocs-ai-chatbot/betterdocs-ai-chatbot.php';
445 - }
388 + if ( ! empty( $_api_classes ) && is_array( $_api_classes ) ) {
389 + foreach ( $_api_classes as $class ) {
390 + if ( $class == '.' || $class == '..' || strpos( $class, '.' ) === 0 ) {
391 + continue;
392 + }
446 393
447 - public function is_chatbot_active() {
448 - if ( file_exists( $this->chatbot_file() ) ) {
449 - return $this->helper->is_plugin_active( 'betterdocs-ai-chatbot/betterdocs-ai-chatbot.php' );
450 - }
394 + $classname = basename( $class, '.php' );
395 + $classname = '\\' . __NAMESPACE__ . "\\REST\\$classname";
396 + $_api_class = $this->container->get( $classname );
451 397
452 - return false;
453 - }
398 + if ( $_api_class instanceof BaseAPI ) {
399 + $_api_class->register();
400 + }
401 + }
402 + }
403 + }
454 404
455 - /**
456 - * Whether Pro provides the real API Documentation screen.
457 - *
458 - * Pro flips this via `betterdocs_pro_has_api_docs`; the class_exists() default
459 - * keeps the gate correct against a Pro build that predates that filter.
460 - *
461 - * @return bool
462 - */
463 - public function has_api_docs() {
464 - return (bool) apply_filters(
465 - 'betterdocs_pro_has_api_docs',
466 - class_exists( '\\WPDeveloper\\BetterDocsPro\\Core\\ApiReferences' )
467 - );
468 - }
405 + public function is_betterdocs_screen( $hook, $admin_check = true ): bool {
406 + $screens = [
407 + 'betterdocs_page_betterdocs-settings',
408 + 'toplevel_page_betterdocs-admin',
409 + 'betterdocs_page_betterdocs-analytics',
410 + 'betterdocs_page_betterdocs-faq',
411 + 'betterdocs_page_betterdocs-glossaries',
412 + 'betterdocs_page_betterdocs-ai-chatbot',
469 413
470 - /**
471 - * Whether Free should show its locked API Docs teaser.
472 - *
473 - * Only without Pro. An older Pro has already paid, so they get nothing here —
474 - * they need a plugin update, not an upsell.
475 - *
476 - * @return bool
477 - */
478 - public function show_api_docs_teaser() {
479 - return ! $this->is_pro_active() && ! $this->has_api_docs();
480 - }
414 + ];
481 415
482 - public function pro_version() {
483 - if ( ! $this->is_pro_active() ) {
484 - return false;
485 - }
416 + if ( $admin_check ) {
417 + if ( in_array( $hook, $screens ) ) {
418 + return true;
419 + }
486 420
487 - if ( ! function_exists( 'get_plugin_data' ) ) {
488 - require_once ABSPATH . 'wp-admin/includes/plugin.php';
489 - }
421 + return false;
422 + }
490 423
491 - $plugin_data = get_plugin_data( $this->pro_file() );
424 + return false;
425 + }
492 426
493 - return $plugin_data[ 'Version' ];
494 - }
495 -
496 - /**
497 - * Get all the API initialized.
498 - * @return void
499 - */
500 - public function api_initialization() {
501 - $_api_classes = scandir( __DIR__ . DIRECTORY_SEPARATOR . 'REST' );
502 -
503 - if ( ! empty( $_api_classes ) && is_array( $_api_classes ) ) {
504 - foreach ( $_api_classes as $class ) {
505 - if ( '.' == $class || '..' == $class || strpos( $class, '.' ) === 0 ) {
506 - continue;
507 - }
508 -
509 - $classname = basename( $class, '.php' );
510 - $classname = '\\' . __NAMESPACE__ . "\\REST\\$classname";
511 - $_api_class = $this->container->get( $classname );
512 -
513 - if ( $_api_class instanceof BaseAPI ) {
514 - $_api_class->register();
515 - }
516 - }
517 - }
518 - }
519 -
520 - public function is_betterdocs_screen( $hook, $admin_check = true ): bool {
521 - /**
522 - * Filter the list of admin screen hook suffixes treated as BetterDocs
523 - * screens (controls whether the React admin bundle + styles load).
524 - * Pro/add-ons can register their own React pages here, e.g. the
525 - * Knowledge Base admin page.
526 - *
527 - * @param string[] $screens Full hook suffixes (e.g. betterdocs_page_betterdocs-foo).
528 - */
529 - $screens = apply_filters( 'betterdocs_admin_screens', array(
530 - 'toplevel_page_betterdocs-dashboard',
531 - 'toplevel_page_betterdocs-admin',
532 - 'admin_page_betterdocs-admin',
533 - 'betterdocs_page_betterdocs-admin',
534 - 'betterdocs_page_betterdocs-analytics',
535 - 'betterdocs_page_betterdocs-settings',
536 - 'betterdocs_page_betterdocs-mcp',
537 - 'betterdocs_page_betterdocs-faq',
538 - 'betterdocs_page_betterdocs-glossaries',
427 + public function get_betterdocs_screen() {
428 + $registered_screens = [
429 + 'toplevel_page_betterdocs-admin',
430 + 'betterdocs_page_betterdocs-settings',
431 + 'betterdocs_page_betterdocs-analytics',
432 + 'betterdocs_page_betterdocs-faq',
433 + 'betterdocs_page_betterdocs-glossaries',
539 434 'betterdocs_page_betterdocs-ai-chatbot',
540 - 'betterdocs_page_betterdocs-api-docs',
541 - 'betterdocs_page_betterdocs-doc-categories',
542 - 'betterdocs_page_betterdocs-doc-tags',
543 - ) );
544 435
545 - if ( $admin_check ) {
546 - if ( in_array( $hook, $screens ) ) {
547 - return true;
548 - }
436 + ];
549 437
550 - return false;
551 - }
438 + $current_screen_id = get_current_screen() != null ? get_current_screen()->id : '';
552 439
553 - return false;
554 - }
440 + if ( in_array( $current_screen_id, $registered_screens ) ) {
441 + return $current_screen_id;
442 + }
555 443
556 - public function get_betterdocs_screen() {
557 - $registered_screens = array(
558 - 'toplevel_page_betterdocs-dashboard',
559 - 'admin_page_betterdocs-admin',
560 - 'betterdocs_page_betterdocs-admin',
561 - 'betterdocs_page_betterdocs-settings',
562 - 'betterdocs_page_betterdocs-mcp',
563 - 'betterdocs_page_betterdocs-analytics',
564 - 'betterdocs_page_betterdocs-faq',
565 - 'betterdocs_page_betterdocs-glossaries',
566 - 'betterdocs_page_betterdocs-ai-chatbot',
567 - 'betterdocs_page_betterdocs-api-docs',
568 - 'betterdocs_page_betterdocs-doc-categories',
569 - 'betterdocs_page_betterdocs-doc-tags',
570 - 'edit-docs'
571 - );
572 -
573 - $current_screen_id = get_current_screen() != null ? get_current_screen()->id : '';
574 -
575 - if ( in_array( $current_screen_id, $registered_screens ) ) {
576 - return $current_screen_id;
577 - }
578 -
579 - return false;
580 - }
444 + return false;
445 + }
581 446 }