PluginProbe
ZIP AI – AI Website Builder & AI Agent (Beta) / trunk
ZIP AI – AI Website Builder & AI Agent (Beta) vtrunk
0.0.10 0.0.9 trunk 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8
← All changes | loader.php +306 -221 0.0.4trunk View file →
@@ -2,12 +2,12 @@
2 2 /**
3 3 * Plugin Class.
4 4 *
5 5 * @package zip-ai
6 - * @since 0.0.1
6 + * @since 1.0.0
7 7 */
8 8
9 -namespace ZipAI;
9 +namespace ZipAI\MCP;
10 10
11 11 // Exit if accessed directly.
12 12 if ( ! defined( 'ABSPATH' ) ) {
13 13 exit;
@@ -12,221 +12,301 @@
12 12 if ( ! defined( 'ABSPATH' ) ) {
13 13 exit;
14 14 }
15 15
16 -use ZipAI\Classes\Core\Container;
17 -use ZipAI\Classes\Providers\Core_Service_Provider;
18 -use ZipAI\Classes\Providers\Abilities_Service_Provider;
19 -use ZipAI\Classes\Cli\CLI_Commands;
20 -use ZipAI\Classes\Core\Helper;
16 +use ZipAI\MCP\Classes\Core\Container;
17 +use ZipAI\MCP\Classes\Providers\Core_Service_Provider;
18 +use ZipAI\MCP\Classes\Providers\Abilities_Service_Provider;
19 +use ZipAI\MCP\Classes\Core\Helper;
20 +use ZipAI\MCP\Classes\Core\Service_Provider;
21 21
22 -/**
23 - * Plugin Class
24 - *
25 - * @since 0.0.1
26 - */
27 -class Plugin {
28 -
22 +if ( ! class_exists( '\ZipAI\MCP\Plugin' ) ) {
29 23 /**
30 - * Instance
24 + * Plugin Class
31 25 *
32 - * @access private
33 - * @var object Class Instance.
34 - * @since 0.0.1
26 + * @since 1.0.0
35 27 */
36 - private static $instance;
28 + class Plugin {
37 29
38 - /**
39 - * The dependency injection container.
40 - *
41 - * @var Container
42 - */
43 - protected $container;
30 + /**
31 + * Instance
32 + *
33 + * @access private
34 + * @var self|null Class Instance.
35 + * @since 1.0.0
36 + */
37 + private static $instance;
44 38
45 - /**
46 - * Service Providers.
47 - *
48 - * @var array
49 - */
50 - protected $providers = array();
39 + /**
40 + * The dependency injection container.
41 + *
42 + * @var Container
43 + */
44 + protected $container;
51 45
52 - /**
53 - * Initiator
54 - *
55 - * @since 0.0.1
56 - * @return object initialized object of class.
57 - */
58 - public static function get_instance() {
59 - if ( ! isset( self::$instance ) ) {
60 - self::$instance = new self();
46 + /**
47 + * Service Providers.
48 + *
49 + * @var array<int, Service_Provider>
50 + */
51 + protected $providers = array();
52 +
53 + /**
54 + * Initiator
55 + *
56 + * @since 1.0.0
57 + * @return object initialized object of class.
58 + */
59 + public static function get_instance() {
60 + if ( ! isset( self::$instance ) ) {
61 + self::$instance = new self();
62 + }
63 + return self::$instance;
61 64 }
62 - return self::$instance;
63 - }
64 65
65 - /**
66 - * Constructor
67 - *
68 - * @since 0.0.1
69 - */
70 - public function __construct() {
71 - $this->container = new Container();
66 + /**
67 + * Constructor
68 + *
69 + * @since 1.0.0
70 + */
71 + public function __construct() {
72 + // Must be first — everything below (Container included) autoloads
73 + // through it.
74 + spl_autoload_register( array( __CLASS__, 'autoload' ) );
72 75
73 - $this->define_constants();
74 -
75 - // Register Services.
76 - $this->register_services();
76 + $this->container = new Container();
77 77
78 - // Boot Services.
79 - add_action( 'plugins_loaded', array( $this, 'boot_services' ), 5 );
78 + $this->define_constants();
79 +
80 + // Register Services.
81 + $this->register_services();
80 82
81 - $this->setup_activation_hooks();
82 - $this->register_cli_commands();
83 + // Boot Services.
84 + add_action( 'plugins_loaded', array( $this, 'boot_services' ), 5 );
83 85
84 - // Translations: WordPress.org auto-loads the plugin text domain
85 - // on-demand since 4.6, so we no longer call
86 - // `load_plugin_textdomain()` explicitly. Shipped `.pot` lives in
87 - // `/languages/zip-ai.pot`; `.mo` files are delivered by
88 - // GlotPress via the standard plugin update channel.
86 + $this->setup_activation_hooks();
89 87
90 - // Site scanner — event-driven memory enrichment (after auth).
91 - // \ZipAI\Classes\Core\Site_Scanner::register_hooks(); // TODO: class not yet committed.
88 + // Site scanner — event-driven memory enrichment (after auth).
89 + // \ZipAI\MCP\Classes\Core\Site_Scanner::register_hooks(); // TODO: class not yet committed.
92 90
93 - // Privacy policy disclosure (WordPress Guideline 7).
94 - add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) );
95 - }
91 + // Code snippet executor — runs AI-created snippets (PHP/JS/CSS/HTML).
92 + // This is the ONLY persistent hook needed — it auto-loads all snippets
93 + // created by any tool (cookie consent, tracking codes, custom CSS, etc.)
94 + \ZipAI\MCP\Classes\Core\Snippet_Executor::init();
96 95
97 - /**
98 - * Register Service Providers.
99 - */
100 - private function register_services() {
101 - $this->providers[] = new Core_Service_Provider( $this->container );
102 - $this->providers[] = new Abilities_Service_Provider( $this->container );
96 + // Plugin abilities toggler — listens for `activated_plugin` and
97 + // enables MCP abilities for mapped slugs regardless of activation
98 + // path (server-side ability, browser-proxied REST, admin UI,
99 + // WP-CLI). Idempotent + slug-map gated.
100 + \ZipAI\MCP\Classes\Core\Plugin_Abilities_Toggler::init();
103 101
104 - foreach ( $this->providers as $provider ) {
105 - $provider->register();
102 + // Imported-chrome reader — renders imported header/footer template
103 + // parts verbatim on ANY classic theme via a `template_include`
104 + // canvas takeover when `zipai_chrome_mode === 'takeover'` (written
105 + // by the importer) or a page carries the standalone marker meta.
106 + // Inert on block themes (FSE renders the parts natively) and on
107 + // sites that never imported. Registering the option doubles as the
108 + // backend's capability probe.
109 + \ZipAI\MCP\Classes\Core\Imported_Chrome::init();
110 +
111 + // Privacy policy disclosure (WordPress Guideline 7).
112 + add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) );
106 113 }
107 - }
108 114
109 - /**
110 - * Boot Service Providers.
111 - */
112 - public function boot_services() {
113 - $this->load_vendor_dependencies();
115 + /**
116 + * Plugin autoloader — single runtime autoloader for everything the
117 + * plugin ships: its own classes (inc/) and the bundled
118 + * composer-managed libraries in lib/ (mcp-adapter, php-mcp-schema).
119 + * Composer's vendor/autoload.php is dev-tooling only and is never
120 + * loaded at runtime.
121 + *
122 + * @param string $class Fully qualified class name to load.
123 + * @return void
124 + */
125 + public static function autoload( string $class ): void {
126 + // Own classes — WordPress-style file names: namespace path
127 + // lowercased, CamelCase split with hyphens, underscores as hyphens.
128 + // ZipAI\MCP\Classes\Abilities\Core\RunWpCli -> inc/abilities/core/run-wp-cli.php.
129 + $own_prefix = 'ZipAI\MCP\Classes\\';
130 + if ( 0 === strpos( $class, $own_prefix ) ) {
131 + $filename = preg_replace(
132 + array( '/([a-z])([A-Z])/', '/_/', '/\\\\/' ),
133 + array( '$1-$2', '-', '/' ),
134 + substr( $class, strlen( $own_prefix ) )
135 + );
114 136
115 - foreach ( $this->providers as $provider ) {
116 - $provider->boot();
137 + if ( is_string( $filename ) ) {
138 + $file = __DIR__ . '/inc/' . strtolower( $filename ) . '.php';
139 +
140 + if ( is_readable( $file ) ) {
141 + require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Path is derived from the class name.
142 + }
143 + }
144 + return;
145 + }
146 +
147 + // Bundled lib/ packages — strict PSR-4, directory case preserved.
148 + $psr4 = array(
149 + 'WP\MCP\\' => 'lib/mcp-adapter/includes/',
150 + 'WP\McpSchema\\' => 'lib/php-mcp-schema/src/',
151 + );
152 +
153 + foreach ( $psr4 as $prefix => $base_dir ) {
154 + if ( 0 === strpos( $class, $prefix ) ) {
155 + $file = __DIR__ . '/' . $base_dir . str_replace( '\\', '/', substr( $class, strlen( $prefix ) ) ) . '.php';
156 +
157 + if ( is_readable( $file ) ) {
158 + require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Path is derived from a fixed prefix map.
159 + }
160 + return;
161 + }
162 + }
117 163 }
118 - }
119 164
120 - /**
121 - * Define the required constants.
122 - *
123 - * @since 0.0.1
124 - * @return void
125 - */
126 - public function define_constants() {
127 - define( 'ZIP_AI_FILE', __DIR__ . '/zip-ai.php' );
128 - define( 'ZIP_AI_DIR', plugin_dir_path( ZIP_AI_FILE ) );
129 - define( 'ZIP_AI_URL', plugins_url( '/', ZIP_AI_FILE ) );
130 - define( 'ZIP_AI_VERSION', '0.0.4' );
131 - define( 'ZIP_AI_MENU_SLUG', 'zip-ai' );
165 + /**
166 + * Register Service Providers.
167 + *
168 + * @return void
169 + */
170 + private function register_services() {
171 + $this->providers[] = new Core_Service_Provider( $this->container );
172 + $this->providers[] = new Abilities_Service_Provider( $this->container );
132 173
133 - // Base URL for Zip AI credit server (Laravel app).
134 - if ( ! defined( 'ZIP_AI_BASE_URL' ) ) {
135 - define( 'ZIP_AI_BASE_URL', 'https://credits.startertemplates.com' );
174 + foreach ( $this->providers as $provider ) {
175 + $provider->register();
176 + }
136 177 }
137 178
138 - if ( ! defined( 'ZIP_AI_MIDDLEWARE' ) ) {
139 - define( 'ZIP_AI_MIDDLEWARE', 'https://app.zipwp.com/auth/' );
179 + /**
180 + * Boot Service Providers.
181 + *
182 + * @return void
183 + */
184 + public function boot_services() {
185 + $this->load_vendor_dependencies();
186 +
187 + foreach ( $this->providers as $provider ) {
188 + $provider->boot();
189 + }
140 190 }
141 191
142 - if ( ! defined( 'ZIP_AI_API_BASE' ) ) {
143 - define( 'ZIP_AI_API_BASE', 'https://api.zipwp.com/api/' );
192 + /**
193 + * Define the required constants.
194 + *
195 + * @since 1.0.0
196 + * @return void
197 + */
198 + public function define_constants() {
199 + define( 'ZIPAI_MCP_FILE', __DIR__ . '/zip-ai.php' );
200 + define( 'ZIPAI_MCP_DIR', plugin_dir_path( ZIPAI_MCP_FILE ) );
201 + define( 'ZIPAI_MCP_URL', plugins_url( '/', ZIPAI_MCP_FILE ) );
202 + define( 'ZIPAI_MCP_VERSION', '0.0.10' );
203 + define( 'ZIPAI_MCP_MENU_SLUG', 'zip-ai' );
204 +
205 + // Base URL for ZIP AI credit server.
206 + if ( ! defined( 'ZIPAI_MCP_BASE_URL' ) ) {
207 + define( 'ZIPAI_MCP_BASE_URL', 'https://credits.zipwp.com' );
208 + }
209 +
210 + if ( ! defined( 'ZIPAI_MCP_MIDDLEWARE' ) ) {
211 + define( 'ZIPAI_MCP_MIDDLEWARE', 'https://app.zipwp.com/auth/' );
212 + }
213 +
214 + if ( ! defined( 'ZIPAI_API_BASE' ) ) {
215 + define( 'ZIPAI_API_BASE', 'https://api.zipwp.com/api/' );
216 + }
217 +
218 + // Base URL for direct server calls (e.g. inline-edit). Override via
219 + // wp-config.php or the `zipai_brain_url` filter.
220 + if ( ! defined( 'ZIPAI_BRAIN_URL' ) ) {
221 + define( 'ZIPAI_BRAIN_URL', 'https://brain.zipwp.com' );
222 + }
223 +
224 + // API endpoint for credit server.
225 + if ( ! defined( 'ZIPAI_MCP_CREDIT_SERVER_API' ) ) {
226 + define( 'ZIPAI_MCP_CREDIT_SERVER_API', ZIPAI_MCP_BASE_URL . '/api/' );
227 + }
144 228 }
145 229
146 - // API endpoint for credit server.
147 - if ( ! defined( 'ZIP_AI_CREDIT_SERVER_API' ) ) {
148 - define( 'ZIP_AI_CREDIT_SERVER_API', ZIP_AI_BASE_URL . '/api/' );
230 + /**
231 + * Load bundled dependencies (mcp-adapter).
232 + *
233 + * @since 1.0.0
234 + * @return void
235 + */
236 + private function load_vendor_dependencies() {
237 + // Initialize mcp-adapter plugin if not already loaded. It is vendored
238 + // in lib/mcp-adapter (git-committed) and its classes are served by the
239 + // plugin autoloader (Plugin::autoload). The library self-bootstraps
240 + // (defines its own constants, runs its autoloader and calls
241 + // \WP\MCP\Plugin::instance()) on require, and its self-autoload expects
242 + // a nested vendor/ it doesn't have — so we tell it to skip it, else it
243 + // prints a false "Composer autoloader was not found" admin notice and
244 + // bails before Plugin::instance().
245 + if ( ! defined( 'WP_MCP_AUTOLOAD' ) ) {
246 + define( 'WP_MCP_AUTOLOAD', false );
247 + }
248 + if ( ! defined( 'WP_MCP_VERSION' ) && file_exists( ZIPAI_MCP_DIR . 'lib/mcp-adapter/mcp-adapter.php' ) ) {
249 + require_once ZIPAI_MCP_DIR . 'lib/mcp-adapter/mcp-adapter.php';
250 + }
149 251 }
150 - }
151 252
152 - /**
153 - * Load vendor dependencies (mcp-adapter).
154 - *
155 - * @since 0.0.1
156 - * @return void
157 - */
158 - private function load_vendor_dependencies() {
159 - // Boot the upstream `wordpress/mcp-adapter` library directly via its
160 - // Plugin singleton. We skip its own `mcp-adapter.php` bootstrap because
161 - // that file (a) defines `WP_MCP_*` constants that conflict with the
162 - // reserved `WP_` prefix and (b) runs its own Autoloader which expects a
163 - // nested `vendor/autoload.php` that does not exist after Composer
164 - // flattens dependencies. Our parent classmap (composer.json) already
165 - // includes every `\WP\MCP\*` class via PSR-4, so calling
166 - // `Plugin::instance()` triggers the library's setup directly.
167 - if ( class_exists( \WP\MCP\Plugin::class ) ) {
168 - \WP\MCP\Plugin::instance();
253 + /**
254 + * Setup plugin activation and deactivation hooks.
255 + *
256 + * @since 1.0.0
257 + * @return void
258 + */
259 + public function setup_activation_hooks() {
260 + register_activation_hook( ZIPAI_MCP_FILE, array( $this, 'plugin_activated' ) );
261 + register_deactivation_hook( ZIPAI_MCP_FILE, array( $this, 'plugin_deactivated' ) );
169 262 }
170 - }
171 263
172 - /**
173 - * Setup plugin activation and deactivation hooks.
174 - *
175 - * @since 0.0.1
176 - * @return void
177 - */
178 - public function setup_activation_hooks() {
179 - register_activation_hook( ZIP_AI_FILE, array( $this, 'plugin_activated' ) );
180 - register_deactivation_hook( ZIP_AI_FILE, array( $this, 'plugin_deactivated' ) );
181 - }
264 + /**
265 + * Plugin activation callback.
266 + *
267 + * @since 1.0.0
268 + * @return void
269 + */
270 + public function plugin_activated() {
271 + // Add the required capability to administrator role.
272 + $this->add_plugin_capabilities();
182 273
183 - /**
184 - * Plugin activation callback.
185 - *
186 - * @since 0.0.1
187 - * @return void
188 - */
189 - public function plugin_activated() {
190 - // Add the required capability to administrator role.
191 - // HMAC shared-secret registration with the remote credit server is
192 - // deferred until the user explicitly authenticates (see
193 - // AJAX_Handlers::zip_ai_save_auth_settings). Nothing is sent to any
194 - // external service on activation.
195 - $this->add_plugin_capabilities();
196 - }
274 + // Generate and register shared secret with the server on activation.
275 + $this->register_hmac_secret();
276 + }
197 277
198 - /**
199 - * Plugin deactivation callback.
200 - *
201 - * @since 0.0.1
202 - * @return void
203 - */
204 - public function plugin_deactivated() {
205 - // Remove the plugin capabilities from all roles.
206 - $this->remove_plugin_capabilities();
278 + /**
279 + * Plugin deactivation callback.
280 + *
281 + * @since 1.0.0
282 + * @return void
283 + */
284 + public function plugin_deactivated() {
285 + // Remove the plugin capabilities from all roles.
286 + $this->remove_plugin_capabilities();
207 287
208 - // Clear scheduled site scan.
209 - \ZipAI\Classes\Core\Site_Scanner::unschedule();
210 - }
288 + // Clear scheduled site scan.
289 + \ZipAI\MCP\Classes\Core\Site_Scanner::unschedule();
290 + }
211 291
212 - /**
213 - * Suggest privacy policy content per WordPress Guideline 7.
214 - *
215 - * Discloses what data is sent to the Zip AI SaaS platform.
216 - *
217 - * @since 0.0.1
218 - * @return void
219 - */
220 - public function add_privacy_policy_content() {
221 - $policy_text = '<h2>Zip AI</h2>
222 -<p>This site uses the Zip AI plugin, which connects to a cloud-based AI service operated by Starter Templates (Starter Templates, a Brainstorm Force product).</p>
292 + /**
293 + * Suggest privacy policy content per WordPress Guideline 7.
294 + *
295 + * Discloses what data is sent to the ZIP AI cloud service.
296 + *
297 + * @since 1.0.0
298 + * @return void
299 + */
300 + public function add_privacy_policy_content() {
301 + $policy_text = '<h2>ZIP AI Assistant</h2>
302 +<p>This site uses the ZIP AI Assistant plugin ("ZIP AI"), which connects to a cloud-based AI service operated by Starter Templates (Starter Templates, a Brainstorm Force product).</p>
223 303
224 304 <h3>What data is collected</h3>
225 -<p>When authenticated and actively using Zip AI, the following data may be sent to our servers:</p>
305 +<p>When authenticated and actively using ZIP AI, the following data may be sent to our servers:</p>
226 306 <ul>
227 307 <li><strong>Chat messages</strong> — Messages you send to the AI assistant and the assistant\'s responses.</li>
228 -<li><strong>Site structure data</strong> — Page titles, post counts, active plugin names, active theme name, and content categories. This helps Zip AI understand your site and provide relevant suggestions.</li>
308 +<li><strong>Site structure data</strong> — Page titles, post counts, active plugin names, active theme name, and content categories. This helps ZIP AI understand your site and provide relevant suggestions.</li>
229 309 <li><strong>Site identity</strong> — Site title, tagline, language, and domain name.</li>
230 310 <li><strong>E-commerce data</strong> (if applicable) — Product counts, product categories, currency, and whether reviews are enabled. No individual product details, prices, or customer data is sent.</li>
231 311 </ul>
232 312
@@ -239,74 +319,79 @@
239 319 <li>Analytics or traffic data</li>
240 320 </ul>
241 321
242 322 <h3>How data is used</h3>
243 -<p>Data is used solely to power the AI assistant\'s responses and to build a memory of your site preferences so you don\'t have to repeat yourself across conversations. You can clear all stored memory at any time via the "Clear Site Memory" option in the Zip AI menu.</p>
323 +<p>Data is used solely to power the AI assistant\'s responses and to build a memory of your site preferences so you don\'t have to repeat yourself across conversations. You can clear all stored memory at any time via the "Clear Site Memory" option in the ZIP AI menu.</p>
244 324
245 325 <h3>Data retention</h3>
246 326 <p>Chat messages and memory data are stored on our servers for as long as your account is active. You can request deletion at any time by clearing your site memory or contacting support.</p>
247 327
248 328 <h3>Third-party services</h3>
249 -<p>Zip AI uses AI language models (such as Google Gemini and Anthropic Claude) to process your messages. Your messages may be sent to these providers for processing. Please refer to their respective privacy policies:</p>
329 +<p>ZIP AI uses AI language models (such as Google Gemini and Anthropic Claude) to process your messages. Your messages may be sent to these providers for processing. Please refer to their respective privacy policies:</p>
250 330 <ul>
251 331 <li><a href="https://policies.google.com/privacy">Google Privacy Policy</a></li>
252 332 <li><a href="https://www.anthropic.com/privacy">Anthropic Privacy Policy</a></li>
253 333 </ul>
254 334
255 -<p>For more information, please see our <a href="https://store.brainstormforce.com/privacy-policy/">Privacy Policy</a>.</p>';
335 +<p>For more information, please see our <a href="https://developer.brainstormforce.com/privacy-policy/">Privacy Policy</a>.</p>';
256 336
257 - wp_add_privacy_policy_content( 'Zip AI', $policy_text );
258 - }
337 + wp_add_privacy_policy_content( 'ZIP AI Assistant', $policy_text );
338 + }
259 339
260 - /**
261 - * Add required capabilities to administrator role.
262 - *
263 - * @since 0.0.1
264 - * @return void
265 - */
266 - private function add_plugin_capabilities() {
267 - // Get the administrator role.
268 - $admin_role = get_role( 'administrator' );
340 + /**
341 + * Add required capabilities to administrator role.
342 + *
343 + * @since 1.0.0
344 + * @return void
345 + */
346 + private function add_plugin_capabilities() {
347 + // Get the administrator role.
348 + $admin_role = get_role( 'administrator' );
269 349
270 - if ( $admin_role ) {
271 - // Add the required capability for ZipWP MCP management.
272 - $admin_role->add_cap( 'manage_zip_ai_assistant', true );
350 + if ( $admin_role ) {
351 + // Add the required capability for ZipWP MCP management.
352 + $admin_role->add_cap( 'manage_zip_mcp_assistant', true );
353 + }
273 354 }
274 - }
275 355
276 - /**
277 - * Remove plugin capabilities from all roles.
278 - *
279 - * @since 0.0.1
280 - * @return void
281 - */
282 - private function remove_plugin_capabilities() {
283 - // Get all roles.
284 - $roles = wp_roles();
356 + /**
357 + * Remove plugin capabilities from all roles.
358 + *
359 + * @since 1.0.0
360 + * @return void
361 + */
362 + private function remove_plugin_capabilities() {
363 + // Get all roles.
364 + $roles = wp_roles();
285 365
286 - // Remove the capability from all roles that have it.
287 - foreach ( $roles->role_objects as $role ) {
288 - if ( $role->has_cap( 'manage_zip_ai_assistant' ) ) {
289 - $role->remove_cap( 'manage_zip_ai_assistant' );
366 + // Remove the capability from all roles that have it.
367 + foreach ( $roles->role_objects as $role ) {
368 + if ( $role->has_cap( 'manage_zip_mcp_assistant' ) ) {
369 + $role->remove_cap( 'manage_zip_mcp_assistant' );
370 + }
290 371 }
291 372 }
373 +
374 + /**
375 + * Register HMAC shared secret with the server.
376 + *
377 + * @since 1.0.0
378 + * @return void
379 + */
380 + private function register_hmac_secret() {
381 + // Only register if not already registered.
382 + if ( ! Helper::is_hmac_registered() ) {
383 + $registration_result = Helper::register_shared_secret_with_laravel();
384 +
385 + if ( isset( $registration_result['error'] ) ) {
386 + // Note: Error logging removed for production.
387 + unset( $registration_result );
388 + }
389 + }
390 + }
292 391 }
293 392
294 393 /**
295 - * Register WP-CLI commands.
296 - *
297 - * @since 0.0.1
298 - * @return void
394 + * Kicking this off by calling 'get_instance()' method
299 395 */
300 - private function register_cli_commands() {
301 - if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
302 - return;
303 - }
304 -
305 - \WP_CLI::add_command( 'zip-ai', CLI_Commands::class );
306 - }
396 + Plugin::get_instance();
307 397 }
308 -
309 -/**
310 - * Kicking this off by calling 'get_instance()' method
311 - */
312 -Plugin::get_instance();