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