PluginProbe
ZIP AI – AI Website Builder & AI Agent / 0.0.13
ZIP AI – AI Website Builder & AI Agent v0.0.13
0.0.14 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 +103 -58 0.0.5 → 0.0.13 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,90 @@
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 +
123 + // AOS hover handover — after a scroll entrance, an element's own hover eases again.
124 + \ZipAI\MCP\Classes\Core\Aos_Hover_Handover::init();
125 +
99 126 // Privacy policy disclosure (WordPress Guideline 7).
100 127 add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) );
101 128 }
102 129
103 130 /**
131 + * Plugin autoloader — single runtime autoloader for everything the
132 + * plugin ships: its own classes (inc/) and the bundled
133 + * composer-managed libraries in lib/ (mcp-adapter, php-mcp-schema).
134 + * Composer's vendor/autoload.php is dev-tooling only and is never
135 + * loaded at runtime.
136 + *
137 + * @param string $class Fully qualified class name to load.
138 + * @return void
139 + */
140 + public static function autoload( string $class ): void {
141 + // Own classes — WordPress-style file names: namespace path
142 + // lowercased, CamelCase split with hyphens, underscores as hyphens.
143 + // ZipAI\MCP\Classes\Abilities\Core\RunWpCli -> inc/abilities/core/run-wp-cli.php.
144 + $own_prefix = 'ZipAI\MCP\Classes\\';
145 + if ( 0 === strpos( $class, $own_prefix ) ) {
146 + $filename = preg_replace(
147 + array( '/([a-z])([A-Z])/', '/_/', '/\\\\/' ),
148 + array( '$1-$2', '-', '/' ),
149 + substr( $class, strlen( $own_prefix ) )
150 + );
151 +
152 + if ( is_string( $filename ) ) {
153 + $file = __DIR__ . '/inc/' . strtolower( $filename ) . '.php';
154 +
155 + if ( is_readable( $file ) ) {
156 + require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Path is derived from the class name.
157 + }
158 + }
159 + return;
160 + }
161 +
162 + // Bundled lib/ packages — strict PSR-4, directory case preserved.
163 + $psr4 = array(
164 + 'WP\MCP\\' => 'lib/mcp-adapter/includes/',
165 + 'WP\McpSchema\\' => 'lib/php-mcp-schema/src/',
166 + );
167 +
168 + foreach ( $psr4 as $prefix => $base_dir ) {
169 + if ( 0 === strpos( $class, $prefix ) ) {
170 + $file = __DIR__ . '/' . $base_dir . str_replace( '\\', '/', substr( $class, strlen( $prefix ) ) ) . '.php';
171 +
172 + if ( is_readable( $file ) ) {
173 + require_once $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Path is derived from a fixed prefix map.
174 + }
175 + return;
176 + }
177 + }
178 + }
179 +
180 + /**
104 181 * Register Service Providers.
182 + *
183 + * @return void
105 184 */
106 185 private function register_services() {
107 186 $this->providers[] = new Core_Service_Provider( $this->container );
108 187 $this->providers[] = new Abilities_Service_Provider( $this->container );
@@ -113,8 +192,10 @@
113 192 }
114 193
115 194 /**
116 195 * Boot Service Providers.
196 + *
197 + * @return void
117 198 */
118 199 public function boot_services() {
119 200 $this->load_vendor_dependencies();
120 201
@@ -132,14 +213,14 @@
132 213 public function define_constants() {
133 214 define( 'ZIPAI_MCP_FILE', __DIR__ . '/zip-ai.php' );
134 215 define( 'ZIPAI_MCP_DIR', plugin_dir_path( ZIPAI_MCP_FILE ) );
135 216 define( 'ZIPAI_MCP_URL', plugins_url( '/', ZIPAI_MCP_FILE ) );
136 - define( 'ZIPAI_MCP_VERSION', '0.0.5');
217 + define( 'ZIPAI_MCP_VERSION', '0.0.13' );
137 218 define( 'ZIPAI_MCP_MENU_SLUG', 'zip-ai' );
138 219
139 - // Base URL for ZIP AI credit server (Laravel app).
220 + // Base URL for ZIP AI credit server.
140 221 if ( ! defined( 'ZIPAI_MCP_BASE_URL' ) ) {
141 - define( 'ZIPAI_MCP_BASE_URL', 'https://credits.startertemplates.com' );
222 + define( 'ZIPAI_MCP_BASE_URL', 'https://credits.zipwp.com' );
142 223 }
143 224
144 225 if ( ! defined( 'ZIPAI_MCP_MIDDLEWARE' ) ) {
145 226 define( 'ZIPAI_MCP_MIDDLEWARE', 'https://app.zipwp.com/auth/' );
@@ -148,13 +229,12 @@
148 229 if ( ! defined( 'ZIPAI_API_BASE' ) ) {
149 230 define( 'ZIPAI_API_BASE', 'https://api.zipwp.com/api/' );
150 231 }
151 232
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.
233 + // Base URL for direct server calls (e.g. inline-edit). Override via
234 + // wp-config.php or the `zipai_brain_url` filter.
155 235 if ( ! defined( 'ZIPAI_BRAIN_URL' ) ) {
156 - define( 'ZIPAI_BRAIN_URL', 'https://brain.startertemplates.com' );
236 + define( 'ZIPAI_BRAIN_URL', 'https://brain.zipwp.com' );
157 237 }
158 238
159 239 // API endpoint for credit server.
160 240 if ( ! defined( 'ZIPAI_MCP_CREDIT_SERVER_API' ) ) {
@@ -159,30 +239,30 @@
159 239 // API endpoint for credit server.
160 240 if ( ! defined( 'ZIPAI_MCP_CREDIT_SERVER_API' ) ) {
161 241 define( 'ZIPAI_MCP_CREDIT_SERVER_API', ZIPAI_MCP_BASE_URL . '/api/' );
162 242 }
163 -
164 243 }
165 244
166 245 /**
167 - * Load vendor dependencies (mcp-adapter).
246 + * Load bundled dependencies (mcp-adapter).
168 247 *
169 248 * @since 1.0.0
170 249 * @return void
171 250 */
172 251 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().
252 + // Initialize mcp-adapter plugin if not already loaded. It is vendored
253 + // in lib/mcp-adapter (git-committed) and its classes are served by the
254 + // plugin autoloader (Plugin::autoload). The library self-bootstraps
255 + // (defines its own constants, runs its autoloader and calls
256 + // \WP\MCP\Plugin::instance()) on require, and its self-autoload expects
257 + // a nested vendor/ it doesn't have — so we tell it to skip it, else it
258 + // prints a false "Composer autoloader was not found" admin notice and
259 + // bails before Plugin::instance().
180 260 if ( ! defined( 'WP_MCP_AUTOLOAD' ) ) {
181 261 define( 'WP_MCP_AUTOLOAD', false );
182 262 }
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';
263 + if ( ! defined( 'WP_MCP_VERSION' ) && file_exists( ZIPAI_MCP_DIR . 'lib/mcp-adapter/mcp-adapter.php' ) ) {
264 + require_once ZIPAI_MCP_DIR . 'lib/mcp-adapter/mcp-adapter.php';
185 265 }
186 266 }
187 267
188 268 /**
@@ -204,11 +284,8 @@
204 284 */
205 285 public function plugin_activated() {
206 286 // Add the required capability to administrator role.
207 287 $this->add_plugin_capabilities();
208 -
209 - // Generate and register shared secret with Laravel on activation.
210 - $this->register_hmac_secret();
211 288 }
212 289
213 290 /**
214 291 * Plugin deactivation callback.
@@ -226,9 +303,9 @@
226 303
227 304 /**
228 305 * Suggest privacy policy content per WordPress Guideline 7.
229 306 *
230 - * Discloses what data is sent to the ZIP AI SaaS platform.
307 + * Discloses what data is sent to the ZIP AI cloud service.
231 308 *
232 309 * @since 1.0.0
233 310 * @return void
234 311 */
@@ -303,40 +380,8 @@
303 380 if ( $role->has_cap( 'manage_zip_mcp_assistant' ) ) {
304 381 $role->remove_cap( 'manage_zip_mcp_assistant' );
305 382 }
306 383 }
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 384 }
340 385 }
341 386
342 387 /**