PluginProbe
ZIP AI – AI Website Builder & AI Agent / 0.0.12
ZIP AI – AI Website Builder & AI Agent v0.0.12
0.0.13 0.0.12 0.0.11 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 +98 -56 0.0.7 → 0.0.12 View file →
@@ -15,10 +15,10 @@
15 15
16 16 use ZipAI\MCP\Classes\Core\Container;
17 17 use ZipAI\MCP\Classes\Providers\Core_Service_Provider;
18 18 use ZipAI\MCP\Classes\Providers\Abilities_Service_Provider;
19 -use ZipAI\MCP\Classes\Cli\CLI_Commands;
20 19 use ZipAI\MCP\Classes\Core\Helper;
20 +use ZipAI\MCP\Classes\Core\Service_Provider;
21 21
22 22 if ( ! class_exists( '\ZipAI\MCP\Plugin' ) ) {
23 23 /**
24 24 * Plugin Class
@@ -30,9 +30,9 @@
30 30 /**
31 31 * Instance
32 32 *
33 33 * @access private
34 - * @var object Class Instance.
34 + * @var self|null Class Instance.
35 35 * @since 1.0.0
36 36 */
37 37 private static $instance;
38 38
@@ -45,9 +45,9 @@
45 45
46 46 /**
47 47 * Service Providers.
48 48 *
49 - * @var array
49 + * @var array<int, Service_Provider>
50 50 */
51 51 protected $providers = array();
52 52
53 53 /**
@@ -68,8 +68,12 @@
68 68 *
69 69 * @since 1.0.0
70 70 */
71 71 public function __construct() {
72 + // Must be first — everything below (Container included) autoloads
73 + // through it.
74 + spl_autoload_register( array( __CLASS__, 'autoload' ) );
75 +
72 76 $this->container = new Container();
73 77
74 78 $this->define_constants();
75 79
@@ -79,9 +83,8 @@
79 83 // Boot Services.
80 84 add_action( 'plugins_loaded', array( $this, 'boot_services' ), 5 );
81 85
82 86 $this->setup_activation_hooks();
83 - $this->register_cli_commands();
84 87
85 88 // Site scanner — event-driven memory enrichment (after auth).
86 89 // \ZipAI\MCP\Classes\Core\Site_Scanner::register_hooks(); // TODO: class not yet committed.
87 90
@@ -95,14 +98,87 @@
95 98 // path (server-side ability, browser-proxied REST, admin UI,
96 99 // WP-CLI). Idempotent + slug-map gated.
97 100 \ZipAI\MCP\Classes\Core\Plugin_Abilities_Toggler::init();
98 101
102 + // Abilities input normalizer — lets the chat call no-input readonly
103 + // abilities over the browser Abilities run-route (GET can't carry a
104 + // JSON object, so a schema without a top-level `default` — e.g. Astra's
105 + // typography abilities — would 400 "input is not of type object").
106 + \ZipAI\MCP\Classes\Core\Abilities_Input_Normalizer::init();
107 +
108 + // Imported-chrome reader — renders imported header/footer template
109 + // parts verbatim on ANY classic theme via a `template_include`
110 + // canvas takeover when `zipai_chrome_mode === 'takeover'` (written
111 + // by the importer) or a page carries the standalone marker meta.
112 + // Inert on block themes (FSE renders the parts natively) and on
113 + // sites that never imported. Registering the option doubles as the
114 + // backend's capability probe.
115 + \ZipAI\MCP\Classes\Core\Imported_Chrome::init();
116 +
117 + // Site blueprint — the plan the site was built from; never autoloads.
118 + \ZipAI\MCP\Classes\Core\Site_Blueprint::init();
119 +
120 + // JSON-LD — the build's schema.org blocks, printed in `<head>`.
121 + \ZipAI\MCP\Classes\Core\Json_Ld::init();
122 +
99 123 // Privacy policy disclosure (WordPress Guideline 7).
100 124 add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) );
101 125 }
102 126
103 127 /**
128 + * Plugin autoloader — single runtime autoloader for everything the
129 + * plugin ships: its own classes (inc/) and the bundled
130 + * composer-managed libraries in lib/ (mcp-adapter, php-mcp-schema).
131 + * Composer's vendor/autoload.php is dev-tooling only and is never
132 + * loaded at runtime.
133 + *
134 + * @param string $class Fully qualified class name to load.
135 + * @return void
136 + */
137 + public static function autoload( string $class ): void {
138 + // Own classes — WordPress-style file names: namespace path
139 + // lowercased, CamelCase split with hyphens, underscores as hyphens.
140 + // ZipAI\MCP\Classes\Abilities\Core\RunWpCli -> inc/abilities/core/run-wp-cli.php.
141 + $own_prefix = 'ZipAI\MCP\Classes\\';
142 + if ( 0 === strpos( $class, $own_prefix ) ) {
143 + $filename = preg_replace(
144 + array( '/([a-z])([A-Z])/', '/_/', '/\\\\/' ),
145 + array( '$1-$2', '-', '/' ),
146 + substr( $class, strlen( $own_prefix ) )
147 + );
148 +
149 + if ( is_string( $filename ) ) {
150 + $file = __DIR__ . '/inc/' . strtolower( $filename ) . '.php';
151 +
152 + if ( is_readable( $file ) ) {
153 + require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Path is derived from the class name.
154 + }
155 + }
156 + return;
157 + }
158 +
159 + // Bundled lib/ packages — strict PSR-4, directory case preserved.
160 + $psr4 = array(
161 + 'WP\MCP\\' => 'lib/mcp-adapter/includes/',
162 + 'WP\McpSchema\\' => 'lib/php-mcp-schema/src/',
163 + );
164 +
165 + foreach ( $psr4 as $prefix => $base_dir ) {
166 + if ( 0 === strpos( $class, $prefix ) ) {
167 + $file = __DIR__ . '/' . $base_dir . str_replace( '\\', '/', substr( $class, strlen( $prefix ) ) ) . '.php';
168 +
169 + if ( is_readable( $file ) ) {
170 + require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Path is derived from a fixed prefix map.
171 + }
172 + return;
173 + }
174 + }
175 + }
176 +
177 + /**
104 178 * Register Service Providers.
179 + *
180 + * @return void
105 181 */
106 182 private function register_services() {
107 183 $this->providers[] = new Core_Service_Provider( $this->container );
108 184 $this->providers[] = new Abilities_Service_Provider( $this->container );
@@ -113,8 +189,10 @@
113 189 }
114 190
115 191 /**
116 192 * Boot Service Providers.
193 + *
194 + * @return void
117 195 */
118 196 public function boot_services() {
119 197 $this->load_vendor_dependencies();
120 198
@@ -132,12 +210,12 @@
132 210 public function define_constants() {
133 211 define( 'ZIPAI_MCP_FILE', __DIR__ . '/zip-ai.php' );
134 212 define( 'ZIPAI_MCP_DIR', plugin_dir_path( ZIPAI_MCP_FILE ) );
135 213 define( 'ZIPAI_MCP_URL', plugins_url( '/', ZIPAI_MCP_FILE ) );
136 - define( 'ZIPAI_MCP_VERSION', '0.0.7');
214 + define( 'ZIPAI_MCP_VERSION', '0.0.12' );
137 215 define( 'ZIPAI_MCP_MENU_SLUG', 'zip-ai' );
138 216
139 - // Base URL for ZIP AI credit server (Laravel app).
217 + // Base URL for ZIP AI credit server.
140 218 if ( ! defined( 'ZIPAI_MCP_BASE_URL' ) ) {
141 219 define( 'ZIPAI_MCP_BASE_URL', 'https://credits.zipwp.com' );
142 220 }
143 221
@@ -148,11 +226,10 @@
148 226 if ( ! defined( 'ZIPAI_API_BASE' ) ) {
149 227 define( 'ZIPAI_API_BASE', 'https://api.zipwp.com/api/' );
150 228 }
151 229
152 - // Brain base URL for direct-to-brain calls (e.g. inline-edit),
153 - // bypassing the Laravel relay. Override via wp-config.php or the
154 - // `zipai_brain_url` filter.
230 + // Base URL for direct server calls (e.g. inline-edit). Override via
231 + // wp-config.php or the `zipai_brain_url` filter.
155 232 if ( ! defined( 'ZIPAI_BRAIN_URL' ) ) {
156 233 define( 'ZIPAI_BRAIN_URL', 'https://brain.zipwp.com' );
157 234 }
158 235
@@ -159,30 +236,30 @@
159 236 // API endpoint for credit server.
160 237 if ( ! defined( 'ZIPAI_MCP_CREDIT_SERVER_API' ) ) {
161 238 define( 'ZIPAI_MCP_CREDIT_SERVER_API', ZIPAI_MCP_BASE_URL . '/api/' );
162 239 }
163 -
164 240 }
165 241
166 242 /**
167 - * Load vendor dependencies (mcp-adapter).
243 + * Load bundled dependencies (mcp-adapter).
168 244 *
169 245 * @since 1.0.0
170 246 * @return void
171 247 */
172 248 private function load_vendor_dependencies() {
173 - // Initialize mcp-adapter plugin if not already loaded. The library
174 - // self-bootstraps (defines its own constants, runs its autoloader and
175 - // calls \WP\MCP\Plugin::instance()) on require. Since it's bundled as a
176 - // Composer dependency, its classes are already registered via our root
177 - // vendor/autoload.php and it has no nested vendor/ of its own — so we
178 - // tell it to skip its self-autoload, else it prints a false "Composer
179 - // autoloader was not found" admin notice and bails before Plugin::instance().
249 + // Initialize mcp-adapter plugin if not already loaded. It is vendored
250 + // in lib/mcp-adapter (git-committed) and its classes are served by the
251 + // plugin autoloader (Plugin::autoload). The library self-bootstraps
252 + // (defines its own constants, runs its autoloader and calls
253 + // \WP\MCP\Plugin::instance()) on require, and its self-autoload expects
254 + // a nested vendor/ it doesn't have — so we tell it to skip it, else it
255 + // prints a false "Composer autoloader was not found" admin notice and
256 + // bails before Plugin::instance().
180 257 if ( ! defined( 'WP_MCP_AUTOLOAD' ) ) {
181 258 define( 'WP_MCP_AUTOLOAD', false );
182 259 }
183 - if ( ! defined( 'WP_MCP_VERSION' ) && file_exists( ZIPAI_MCP_DIR . 'vendor/wordpress/mcp-adapter/mcp-adapter.php' ) ) {
184 - require_once ZIPAI_MCP_DIR . 'vendor/wordpress/mcp-adapter/mcp-adapter.php';
260 + if ( ! defined( 'WP_MCP_VERSION' ) && file_exists( ZIPAI_MCP_DIR . 'lib/mcp-adapter/mcp-adapter.php' ) ) {
261 + require_once ZIPAI_MCP_DIR . 'lib/mcp-adapter/mcp-adapter.php';
185 262 }
186 263 }
187 264
188 265 /**
@@ -204,11 +281,8 @@
204 281 */
205 282 public function plugin_activated() {
206 283 // Add the required capability to administrator role.
207 284 $this->add_plugin_capabilities();
208 -
209 - // Generate and register shared secret with Laravel on activation.
210 - $this->register_hmac_secret();
211 285 }
212 286
213 287 /**
214 288 * Plugin deactivation callback.
@@ -226,9 +300,9 @@
226 300
227 301 /**
228 302 * Suggest privacy policy content per WordPress Guideline 7.
229 303 *
230 - * Discloses what data is sent to the ZIP AI SaaS platform.
304 + * Discloses what data is sent to the ZIP AI cloud service.
231 305 *
232 306 * @since 1.0.0
233 307 * @return void
234 308 */
@@ -303,40 +377,8 @@
303 377 if ( $role->has_cap( 'manage_zip_mcp_assistant' ) ) {
304 378 $role->remove_cap( 'manage_zip_mcp_assistant' );
305 379 }
306 380 }
307 - }
308 -
309 - /**
310 - * Register HMAC shared secret with Laravel server.
311 - *
312 - * @since 1.0.0
313 - * @return void
314 - */
315 - private function register_hmac_secret() {
316 - // Only register if not already registered.
317 - if ( ! Helper::is_hmac_registered() ) {
318 - $registration_result = Helper::register_shared_secret_with_laravel();
319 -
320 - if ( isset( $registration_result['error'] ) ) {
321 - // Note: Error logging removed for production.
322 - unset( $registration_result );
323 - }
324 - }
325 - }
326 -
327 - /**
328 - * Register WP-CLI commands.
329 - *
330 - * @since 1.0.0
331 - * @return void
332 - */
333 - private function register_cli_commands() {
334 - if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
335 - return;
336 - }
337 -
338 - \WP_CLI::add_command( 'zip-ai', CLI_Commands::class );
339 381 }
340 382 }
341 383
342 384 /**