Changeset 3734304
- Timestamp:
- 10/08/2026 10:41:59 AM (2 weeks ago)
- Location:
- zoofiai-mcp-connector
- Files:
-
- 33 added
- 6 edited
-
tags/2.1.0 (added)
-
tags/2.1.0/assets (added)
-
tags/2.1.0/assets/admin.css (added)
-
tags/2.1.0/assets/admin.js (added)
-
tags/2.1.0/includes (added)
-
tags/2.1.0/includes/class-zoofi-api.php (added)
-
tags/2.1.0/includes/class-zoofi-audit.php (added)
-
tags/2.1.0/includes/class-zoofi-autonomous.php (added)
-
tags/2.1.0/includes/class-zoofi-backup.php (added)
-
tags/2.1.0/includes/class-zoofi-bulk.php (added)
-
tags/2.1.0/includes/class-zoofi-cli.php (added)
-
tags/2.1.0/includes/class-zoofi-cloud.php (added)
-
tags/2.1.0/includes/class-zoofi-content-engine.php (added)
-
tags/2.1.0/includes/class-zoofi-control.php (added)
-
tags/2.1.0/includes/class-zoofi-diagnostics.php (added)
-
tags/2.1.0/includes/class-zoofi-durable-jobs.php (added)
-
tags/2.1.0/includes/class-zoofi-error.php (added)
-
tags/2.1.0/includes/class-zoofi-file-ops.php (added)
-
tags/2.1.0/includes/class-zoofi-plugin-file-ops.php (added)
-
tags/2.1.0/includes/class-zoofi-pro-ops.php (added)
-
tags/2.1.0/includes/class-zoofi-product.php (added)
-
tags/2.1.0/includes/class-zoofi-receipts.php (added)
-
tags/2.1.0/includes/class-zoofi-secrets.php (added)
-
tags/2.1.0/includes/class-zoofi-smart.php (added)
-
tags/2.1.0/includes/class-zoofi-theme-drafts.php (added)
-
tags/2.1.0/includes/class-zoofi-updater.php (added)
-
tags/2.1.0/includes/class-zoofi-white-label.php (added)
-
tags/2.1.0/languages (added)
-
tags/2.1.0/languages/index.php (added)
-
tags/2.1.0/readme.txt (added)
-
tags/2.1.0/uninstall.php (added)
-
tags/2.1.0/zoofiai-mcp-connector.php (added)
-
trunk/includes/class-zoofi-api.php (modified) (4 diffs)
-
trunk/includes/class-zoofi-cli.php (modified) (5 diffs)
-
trunk/includes/class-zoofi-content-engine.php (added)
-
trunk/includes/class-zoofi-smart.php (modified) (1 diff)
-
trunk/includes/class-zoofi-theme-drafts.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/zoofiai-mcp-connector.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
zoofiai-mcp-connector/trunk/includes/class-zoofi-api.php
r3711936 r3734304 299 299 'methods' => 'POST', 'callback' => array( __CLASS__, 'theme_draft_file_search' ), 'permission_callback' => static function () { return current_user_can( 'manage_options' ); }, 300 300 ) ); 301 register_rest_route( self::NS, '/theme-drafts/(?P<id>[A-Za-z0-9_-]+)/files/outline', array( 302 'methods' => 'POST', 'callback' => array( __CLASS__, 'theme_draft_file_outline' ), 'permission_callback' => static function () { return current_user_can( 'manage_options' ); }, 303 ) ); 301 304 register_rest_route( self::NS, '/theme-drafts/(?P<id>[A-Za-z0-9_-]+)/files/write', array( 302 305 'methods' => 'POST', 'callback' => array( __CLASS__, 'theme_draft_file_write' ), 'permission_callback' => static function () { return current_user_can( 'manage_options' ); }, … … 313 316 register_rest_route( self::NS, '/theme-drafts/(?P<id>[A-Za-z0-9_-]+)/rollback', array( 314 317 'methods' => 'POST', 'callback' => array( __CLASS__, 'theme_draft_rollback' ), 'permission_callback' => static function () { return current_user_can( 'manage_options' ); }, 318 ) ); 319 320 321 // --- Builder-aware surgical content engine: inspect -> search -> exact edit --- 322 register_rest_route( self::NS, '/content/profile/(?P<id>\d+)', array( 323 'methods' => 'GET', 'callback' => array( __CLASS__, 'content_profile' ), 'permission_callback' => static function () { return current_user_can( 'edit_posts' ); }, 324 ) ); 325 register_rest_route( self::NS, '/content/search', array( 326 'methods' => 'POST', 'callback' => array( __CLASS__, 'content_search' ), 'permission_callback' => static function () { return current_user_can( 'edit_posts' ) || current_user_can( 'manage_options' ); }, 327 ) ); 328 register_rest_route( self::NS, '/content/edit', array( 329 'methods' => 'POST', 'callback' => array( __CLASS__, 'content_edit' ), 'permission_callback' => static function () { return current_user_can( 'edit_posts' ) || current_user_can( 'manage_options' ); }, 315 330 ) ); 316 331 … … 1103 1118 'pro_ops_features' => array( 'diagnostics', 'change_history', 'local_capabilities', 'restore_points', 'bulk_ops', 'scheduled_tasks', 'site_security_audit', 'broken_links', 'seo_bulk', 'database_toolkit' ), 1104 1119 'change_checkpoints' => class_exists( 'Zoofi_Smart' ), 1120 'content_surgical_engine' => class_exists( 'Zoofi_Content_Engine' ), 1121 'content_builder_profiles' => array( 'elementor', 'divi', 'bricks', 'breakdance', 'beaver_builder', 'gutenberg', 'classic' ), 1122 'serialized_builder_structural_edit' => class_exists( 'Zoofi_Content_Engine' ), 1123 'theme_draft_outline' => class_exists( 'Zoofi_Theme_Drafts' ), 1124 'theme_draft_publish_validation' => class_exists( 'Zoofi_Theme_Drafts' ), 1125 'cli_extended_management' => true, 1105 1126 'background_tasks' => class_exists( 'Zoofi_Smart' ), 1106 1127 'durable_jobs' => class_exists( 'Zoofi_Durable_Jobs' ), … … 1514 1535 $json = $request->get_json_params(); 1515 1536 $result = Zoofi_Theme_Drafts::search_files( sanitize_key( (string) $request['id'] ), (string) ( $json['needle'] ?? '' ), ! empty( $json['case_sensitive'] ), isset( $json['max'] ) ? absint( $json['max'] ) : 100 ); 1537 return is_wp_error( $result ) ? $result : rest_ensure_response( $result ); 1538 } 1539 1540 public static function theme_draft_file_outline( $request ) { 1541 $json = (array) $request->get_json_params(); 1542 $result = Zoofi_Theme_Drafts::outline_file( sanitize_key( (string) $request['id'] ), (string) ( $json['file'] ?? '' ) ); 1543 return is_wp_error( $result ) ? $result : rest_ensure_response( $result ); 1544 } 1545 1546 public static function content_profile( $request ) { 1547 $result = Zoofi_Content_Engine::profile( absint( $request['id'] ) ); 1548 return is_wp_error( $result ) ? $result : rest_ensure_response( $result ); 1549 } 1550 1551 public static function content_search( $request ) { 1552 $result = Zoofi_Content_Engine::search( (array) $request->get_json_params() ); 1553 return is_wp_error( $result ) ? $result : rest_ensure_response( $result ); 1554 } 1555 1556 public static function content_edit( $request ) { 1557 $result = Zoofi_Content_Engine::edit( (array) $request->get_json_params() ); 1516 1558 return is_wp_error( $result ) ? $result : rest_ensure_response( $result ); 1517 1559 } -
zoofiai-mcp-connector/trunk/includes/class-zoofi-cli.php
r3706882 r3734304 79 79 'user list' => array( 'handler' => 'cmd_user_list', 'tier' => 'read', 'cap' => 'list_users' ), 80 80 'user get' => array( 'handler' => 'cmd_user_get', 'tier' => 'read', 'cap' => 'list_users' ), 81 'user meta get' => array( 'handler' => 'cmd_user_meta_get', 'tier' => 'read', 'cap' => 'list_users' ), 82 'user meta list' => array( 'handler' => 'cmd_user_meta_list', 'tier' => 'read', 'cap' => 'list_users' ), 81 83 'post list' => array( 'handler' => 'cmd_post_list', 'tier' => 'read', 'cap' => 'edit_posts' ), 82 84 'post get' => array( 'handler' => 'cmd_post_get', 'tier' => 'read', 'cap' => 'edit_posts' ), 83 85 'taxonomy list' => array( 'handler' => 'cmd_taxonomy_list', 'tier' => 'read', 'cap' => 'edit_posts' ), 84 86 'term list' => array( 'handler' => 'cmd_term_list', 'tier' => 'read', 'cap' => 'manage_categories' ), 87 'option pluck' => array( 'handler' => 'cmd_option_pluck', 'tier' => 'read', 'cap' => 'manage_options' ), 88 'cron test' => array( 'handler' => 'cmd_cron_test', 'tier' => 'read', 'cap' => 'manage_options' ), 85 89 'media list' => array( 'handler' => 'cmd_media_list', 'tier' => 'read', 'cap' => 'upload_files' ), 86 90 'comment list' => array( 'handler' => 'cmd_comment_list', 'tier' => 'read', 'cap' => 'moderate_comments' ), … … 122 126 'theme delete' => array( 'handler' => 'cmd_theme_delete', 'tier' => 'write', 'cap' => 'delete_themes', 'check_file_mods' => true, 'destructive' => true ), 123 127 'option update' => array( 'handler' => 'cmd_option_update', 'tier' => 'write', 'cap' => 'manage_options' ), 128 'option patch update' => array( 'handler' => 'cmd_option_patch_update', 'tier' => 'write', 'cap' => 'manage_options' ), 124 129 'option add' => array( 'handler' => 'cmd_option_add', 'tier' => 'write', 'cap' => 'manage_options' ), 125 130 'option delete' => array( 'handler' => 'cmd_option_delete', 'tier' => 'write', 'cap' => 'manage_options', 'destructive' => true ), … … 129 134 'user create' => array( 'handler' => 'cmd_user_create', 'tier' => 'write', 'cap' => 'create_users' ), 130 135 'user update' => array( 'handler' => 'cmd_user_update', 'tier' => 'write', 'cap' => 'edit_users' ), 136 'user meta add' => array( 'handler' => 'cmd_user_meta_add', 'tier' => 'write', 'cap' => 'edit_users' ), 137 'user meta update' => array( 'handler' => 'cmd_user_meta_update', 'tier' => 'write', 'cap' => 'edit_users' ), 138 'user meta delete' => array( 'handler' => 'cmd_user_meta_delete', 'tier' => 'write', 'cap' => 'edit_users', 'destructive' => true ), 131 139 'user delete' => array( 'handler' => 'cmd_user_delete', 'tier' => 'write', 'cap' => 'delete_users', 'destructive' => true ), 132 140 'post create' => array( 'handler' => 'cmd_post_create', 'tier' => 'write', 'cap' => 'edit_posts' ), … … 136 144 'post meta add' => array( 'handler' => 'cmd_post_meta_update', 'tier' => 'write', 'cap' => 'edit_posts' ), 137 145 'post meta delete' => array( 'handler' => 'cmd_post_meta_delete', 'tier' => 'write', 'cap' => 'edit_posts', 'destructive' => true ), 146 'term create' => array( 'handler' => 'cmd_term_create', 'tier' => 'write', 'cap' => 'manage_categories' ), 147 'term update' => array( 'handler' => 'cmd_term_update', 'tier' => 'write', 'cap' => 'manage_categories' ), 148 'term delete' => array( 'handler' => 'cmd_term_delete', 'tier' => 'write', 'cap' => 'manage_categories', 'destructive' => true ), 149 'post term set' => array( 'handler' => 'cmd_post_term_set', 'tier' => 'write', 'cap' => 'edit_posts' ), 150 'post term add' => array( 'handler' => 'cmd_post_term_add', 'tier' => 'write', 'cap' => 'edit_posts' ), 151 'post term remove' => array( 'handler' => 'cmd_post_term_remove', 'tier' => 'write', 'cap' => 'edit_posts' ), 152 'theme mod set' => array( 'handler' => 'cmd_theme_mod_set', 'tier' => 'write', 'cap' => 'edit_theme_options' ), 153 'role create' => array( 'handler' => 'cmd_role_create', 'tier' => 'write', 'cap' => 'promote_users' ), 154 'role delete' => array( 'handler' => 'cmd_role_delete', 'tier' => 'write', 'cap' => 'promote_users', 'destructive' => true ), 155 'cap add' => array( 'handler' => 'cmd_cap_add', 'tier' => 'write', 'cap' => 'promote_users' ), 156 'cap remove' => array( 'handler' => 'cmd_cap_remove', 'tier' => 'write', 'cap' => 'promote_users', 'destructive' => true ), 157 'cron event run' => array( 'handler' => 'cmd_cron_event_run', 'tier' => 'write', 'cap' => 'manage_options' ), 158 'cron event delete' => array( 'handler' => 'cmd_cron_event_delete', 'tier' => 'write', 'cap' => 'manage_options', 'destructive' => true ), 138 159 'core update' => array( 'handler' => 'cmd_core_update', 'tier' => 'write', 'cap' => 'update_core', 'check_file_mods' => true, 'destructive' => true ), 139 160 'search-replace' => array( 'handler' => 'cmd_search_replace', 'tier' => 'write', 'cap' => 'manage_options', 'destructive' => true ), … … 2186 2207 * @return string|false 2187 2208 */ 2209 2210 /** User meta helpers. */ 2211 private static function cmd_user_meta_get( array $pos, array $assoc ) { 2212 $user_id = absint( $pos[0] ?? 0 ); $key = (string) ( $pos[1] ?? '' ); 2213 if ( ! $user_id || '' === $key ) return array( 'ok' => false, 'message' => 'Usage: user meta get <user-id> <key>', 'data' => array() ); 2214 if ( self::sensitive_meta_key( $key ) ) return array( 'ok' => false, 'message' => 'Sensitive user meta key is blocked.', 'data' => array() ); 2215 return array( 'ok' => true, 'message' => 'User meta read', 'data' => array( 'user_id' => $user_id, 'key' => $key, 'value' => get_user_meta( $user_id, $key, true ) ) ); 2216 } 2217 private static function cmd_user_meta_list( array $pos, array $assoc ) { 2218 $user_id = absint( $pos[0] ?? 0 ); if ( ! $user_id ) return array( 'ok' => false, 'message' => 'Usage: user meta list <user-id>', 'data' => array() ); 2219 $all = get_user_meta( $user_id ); $safe = array(); 2220 foreach ( $all as $key => $values ) if ( ! self::sensitive_meta_key( $key ) ) $safe[ $key ] = array_map( 'maybe_unserialize', $values ); 2221 return array( 'ok' => true, 'message' => 'User meta listed', 'data' => $safe ); 2222 } 2223 private static function cmd_user_meta_add( array $pos, array $assoc ) { 2224 $user_id = absint( $pos[0] ?? 0 ); $key = (string) ( $pos[1] ?? '' ); $value = $pos[2] ?? ''; 2225 if ( ! $user_id || '' === $key || self::sensitive_meta_key( $key ) ) return array( 'ok' => false, 'message' => 'Invalid or protected user meta target.', 'data' => array() ); 2226 $id = add_user_meta( $user_id, $key, $value, ! empty( $assoc['unique'] ) ); 2227 return array( 'ok' => false !== $id, 'message' => false !== $id ? 'User meta added' : 'User meta add failed', 'data' => array( 'meta_id' => $id ) ); 2228 } 2229 private static function cmd_user_meta_update( array $pos, array $assoc ) { 2230 $user_id = absint( $pos[0] ?? 0 ); $key = (string) ( $pos[1] ?? '' ); $value = $pos[2] ?? ''; 2231 if ( ! $user_id || '' === $key || self::sensitive_meta_key( $key ) ) return array( 'ok' => false, 'message' => 'Invalid or protected user meta target.', 'data' => array() ); 2232 $ok = update_user_meta( $user_id, $key, $value ); return array( 'ok' => false !== $ok, 'message' => 'User meta updated', 'data' => array( 'user_id' => $user_id, 'key' => $key ) ); 2233 } 2234 private static function cmd_user_meta_delete( array $pos, array $assoc ) { 2235 $user_id = absint( $pos[0] ?? 0 ); $key = (string) ( $pos[1] ?? '' ); 2236 if ( ! $user_id || '' === $key || self::sensitive_meta_key( $key ) ) return array( 'ok' => false, 'message' => 'Invalid or protected user meta target.', 'data' => array() ); 2237 $ok = delete_user_meta( $user_id, $key ); return array( 'ok' => (bool) $ok, 'message' => $ok ? 'User meta deleted' : 'User meta not changed', 'data' => array() ); 2238 } 2239 private static function sensitive_meta_key( $key ) { 2240 $key = strtolower( (string) $key ); 2241 return false !== strpos( $key, 'password' ) || false !== strpos( $key, 'secret' ) || false !== strpos( $key, 'token' ) || false !== strpos( $key, 'session' ) || false !== strpos( $key, 'application_password' ); 2242 } 2243 2244 /** Option pluck/patch without round-tripping the entire object. */ 2245 private static function cmd_option_pluck( array $pos, array $assoc ) { 2246 $name = (string) ( $pos[0] ?? '' ); $path = (string) ( $pos[1] ?? '' ); 2247 if ( ! $name || ! $path || in_array( $name, self::READABLE_BLOCKED_OPTIONS, true ) ) return array( 'ok' => false, 'message' => 'Usage: option pluck <name> <dot.path>', 'data' => array() ); 2248 $value = get_option( $name ); foreach ( explode( '.', $path ) as $part ) { if ( ! is_array( $value ) || ! array_key_exists( $part, $value ) ) return array( 'ok' => false, 'message' => 'Path not found', 'data' => array() ); $value = $value[ $part ]; } 2249 return array( 'ok' => true, 'message' => 'Option value plucked', 'data' => $value ); 2250 } 2251 private static function cmd_option_patch_update( array $pos, array $assoc ) { 2252 $name = (string) ( $pos[0] ?? '' ); $path = (string) ( $pos[1] ?? '' ); $value = $pos[2] ?? ''; 2253 if ( ! $name || ! $path || in_array( $name, self::READABLE_BLOCKED_OPTIONS, true ) ) return array( 'ok' => false, 'message' => 'Usage: option patch update <name> <dot.path> <value>', 'data' => array() ); 2254 $root = get_option( $name ); if ( ! is_array( $root ) ) return array( 'ok' => false, 'message' => 'Option is not an array/object and cannot be patched.', 'data' => array() ); 2255 $ref =& $root; $parts = explode( '.', $path ); $last = array_pop( $parts ); foreach ( $parts as $part ) { if ( ! isset( $ref[ $part ] ) || ! is_array( $ref[ $part ] ) ) $ref[ $part ] = array(); $ref =& $ref[ $part ]; } $ref[ $last ] = $value; 2256 $ok = update_option( $name, $root ); return array( 'ok' => false !== $ok, 'message' => 'Option patched', 'data' => array( 'name' => $name, 'path' => $path ) ); 2257 } 2258 2259 /** Taxonomy/term operations. */ 2260 private static function cmd_term_create( array $pos, array $assoc ) { 2261 $taxonomy = (string) ( $pos[0] ?? '' ); $name = (string) ( $pos[1] ?? '' ); if ( ! $taxonomy || ! $name ) return array( 'ok' => false, 'message' => 'Usage: term create <taxonomy> <name>', 'data' => array() ); 2262 $args = array(); if ( isset( $assoc['slug'] ) ) $args['slug'] = sanitize_title( $assoc['slug'] ); if ( isset( $assoc['description'] ) ) $args['description'] = (string) $assoc['description']; if ( isset( $assoc['parent'] ) ) $args['parent'] = absint( $assoc['parent'] ); 2263 $r = wp_insert_term( $name, $taxonomy, $args ); if ( is_wp_error( $r ) ) return array( 'ok' => false, 'message' => $r->get_error_message(), 'data' => array() ); return array( 'ok' => true, 'message' => 'Term created', 'data' => $r ); 2264 } 2265 private static function cmd_term_update( array $pos, array $assoc ) { 2266 $taxonomy = (string) ( $pos[0] ?? '' ); $term_id = absint( $pos[1] ?? 0 ); if ( ! $taxonomy || ! $term_id ) return array( 'ok' => false, 'message' => 'Usage: term update <taxonomy> <term-id> [--name=...]', 'data' => array() ); 2267 $args = array(); foreach ( array( 'name','slug','description','parent' ) as $k ) if ( isset( $assoc[ $k ] ) ) $args[ $k ] = 'parent' === $k ? absint( $assoc[ $k ] ) : (string) $assoc[ $k ]; if ( ! $args ) return array( 'ok' => false, 'message' => 'No term fields supplied.', 'data' => array() ); 2268 $r = wp_update_term( $term_id, $taxonomy, $args ); if ( is_wp_error( $r ) ) return array( 'ok' => false, 'message' => $r->get_error_message(), 'data' => array() ); return array( 'ok' => true, 'message' => 'Term updated', 'data' => $r ); 2269 } 2270 private static function cmd_term_delete( array $pos, array $assoc ) { 2271 $taxonomy = (string) ( $pos[0] ?? '' ); $term_id = absint( $pos[1] ?? 0 ); if ( ! $taxonomy || ! $term_id ) return array( 'ok' => false, 'message' => 'Usage: term delete <taxonomy> <term-id>', 'data' => array() ); 2272 $r = wp_delete_term( $term_id, $taxonomy ); if ( is_wp_error( $r ) ) return array( 'ok' => false, 'message' => $r->get_error_message(), 'data' => array() ); return array( 'ok' => (bool) $r, 'message' => 'Term deleted', 'data' => $r ); 2273 } 2274 private static function cmd_post_term_set( array $pos, array $assoc ) { return self::post_term_change( $pos, 'set' ); } 2275 private static function cmd_post_term_add( array $pos, array $assoc ) { return self::post_term_change( $pos, 'add' ); } 2276 private static function cmd_post_term_remove( array $pos, array $assoc ) { return self::post_term_change( $pos, 'remove' ); } 2277 private static function post_term_change( array $pos, $mode ) { 2278 $post_id = absint( $pos[0] ?? 0 ); $taxonomy = (string) ( $pos[1] ?? '' ); $raw = (string) ( $pos[2] ?? '' ); if ( ! $post_id || ! $taxonomy || '' === $raw ) return array( 'ok' => false, 'message' => 'Usage: post term ' . $mode . ' <post-id> <taxonomy> <comma-separated ids/slugs>', 'data' => array() ); 2279 $terms = array_values( array_filter( array_map( 'trim', explode( ',', $raw ) ), 'strlen' ) ); $terms = array_map( static function( $v ) { return ctype_digit( $v ) ? (int) $v : $v; }, $terms ); 2280 if ( 'remove' === $mode ) { $existing = wp_get_object_terms( $post_id, $taxonomy, array( 'fields' => 'all' ) ); if ( is_wp_error( $existing ) ) return array( 'ok' => false, 'message' => $existing->get_error_message(), 'data' => array() ); $remove_ids = array(); foreach ( $existing as $term ) if ( in_array( $term->term_id, $terms, true ) || in_array( $term->slug, $terms, true ) ) $remove_ids[] = $term->term_id; $r = wp_remove_object_terms( $post_id, $remove_ids, $taxonomy ); } 2281 else $r = wp_set_object_terms( $post_id, $terms, $taxonomy, 'add' === $mode ); 2282 if ( is_wp_error( $r ) ) return array( 'ok' => false, 'message' => $r->get_error_message(), 'data' => array() ); return array( 'ok' => true, 'message' => 'Post terms updated', 'data' => $r ); 2283 } 2284 2285 private static function cmd_theme_mod_set( array $pos, array $assoc ) { $name=(string)($pos[0]??''); $value=$pos[1]??''; if(!$name)return array('ok'=>false,'message'=>'Usage: theme mod set <name> <value>','data'=>array()); set_theme_mod($name,$value); return array('ok'=>true,'message'=>'Theme mod set','data'=>array('name'=>$name)); } 2286 private static function cmd_role_create( array $pos, array $assoc ) { $slug=sanitize_key($pos[0]??''); $name=(string)($pos[1]??$slug); if(!$slug)return array('ok'=>false,'message'=>'Usage: role create <slug> <name>','data'=>array()); $role=add_role($slug,$name,array('read'=>true)); return array('ok'=>(bool)$role,'message'=>$role?'Role created':'Role already exists or could not be created','data'=>array('role'=>$slug)); } 2287 private static function cmd_role_delete( array $pos, array $assoc ) { $slug=sanitize_key($pos[0]??''); if(!$slug||in_array($slug,array('administrator','editor','author','contributor','subscriber'),true))return array('ok'=>false,'message'=>'Core roles cannot be deleted.','data'=>array()); remove_role($slug); return array('ok'=>true,'message'=>'Role deleted','data'=>array('role'=>$slug)); } 2288 private static function cmd_cap_add( array $pos, array $assoc ) { return self::role_cap_change($pos,true); } 2289 private static function cmd_cap_remove( array $pos, array $assoc ) { return self::role_cap_change($pos,false); } 2290 private static function role_cap_change( array $pos, $add ) { $role=get_role(sanitize_key($pos[0]??'')); $cap=sanitize_key($pos[1]??''); if(!$role||!$cap)return array('ok'=>false,'message'=>'Usage: cap '.($add?'add':'remove').' <role> <capability>','data'=>array()); if($add)$role->add_cap($cap,true);else $role->remove_cap($cap); return array('ok'=>true,'message'=>'Capability '.($add?'added':'removed'),'data'=>array('capability'=>$cap)); } 2291 2292 private static function cmd_cron_test( array $pos, array $assoc ) { $disabled=defined('DISABLE_WP_CRON')&&DISABLE_WP_CRON; return array('ok'=>!$disabled,'message'=>$disabled?'WP-Cron is disabled by DISABLE_WP_CRON.':'WP-Cron is available.','data'=>array('disabled'=>$disabled,'next_scheduled_events'=>count(_get_cron_array()))); } 2293 private static function cmd_cron_event_run( array $pos, array $assoc ) { $hook=(string)($pos[0]??''); if(!$hook)return array('ok'=>false,'message'=>'Usage: cron event run <hook>','data'=>array()); do_action($hook); return array('ok'=>true,'message'=>'Cron hook executed','data'=>array('hook'=>$hook)); } 2294 private static function cmd_cron_event_delete( array $pos, array $assoc ) { $hook=(string)($pos[0]??''); if(!$hook)return array('ok'=>false,'message'=>'Usage: cron event delete <hook>','data'=>array()); $count=0; while(false!==($ts=wp_next_scheduled($hook))){ wp_unschedule_event($ts,$hook); $count++; if($count>1000)break; } return array('ok'=>true,'message'=>'Cron events removed','data'=>array('hook'=>$hook,'count'=>$count)); } 2295 2188 2296 private static function resolve_plugin_file( $slug ) { 2189 2297 if ( ! function_exists( 'get_plugins' ) ) { -
zoofiai-mcp-connector/trunk/includes/class-zoofi-smart.php
r3706882 r3734304 320 320 $id = wp_generate_password( 24, false, false ); 321 321 $meta = array(); 322 $builder_meta = array( '_elementor_data', '_elementor_edit_mode', '_bricks_page_content_2', '_bricks_page_header_2', '_bricks_page_footer_2', '_breakdance_data', '_fl_builder_data', '_fl_builder_draft' ); 322 323 foreach ( get_post_meta( $post_id ) as $key => $values ) { 323 if ( '_thumbnail_id' === $key || '_wp_page_template' === $key || 0 === strpos( $key, 'rank_math_' ) || 0 === strpos( $key, '_yoast_wpseo_' ) ) {324 if ( '_thumbnail_id' === $key || '_wp_page_template' === $key || in_array( $key, $builder_meta, true ) || 0 === strpos( $key, 'rank_math_' ) || 0 === strpos( $key, '_yoast_wpseo_' ) ) { 324 325 $meta[ $key ] = array_map( 'maybe_unserialize', $values ); 325 326 } -
zoofiai-mcp-connector/trunk/includes/class-zoofi-theme-drafts.php
r3706882 r3734304 176 176 } 177 177 178 /** Structural outline of a draft file without reading the whole source. */ 179 public static function outline_file( $id, $file ) { 180 $record = self::record( $id ); 181 if ( is_wp_error( $record ) ) return $record; 182 $result = Zoofi_File_Ops::outline( $record['draft_slug'], $file ); 183 if ( ! is_wp_error( $result ) ) { 184 $result['draft_id'] = $id; 185 $result['live_theme_unchanged'] = true; 186 } 187 return $result; 188 } 189 178 190 /** Write only inside a draft clone. */ 179 191 public static function write_file( $id, $file, $content ) { … … 208 220 if ( is_wp_error( $current ) ) return $current; 209 221 $body = (string) ( $current['content'] ?? '' ); 210 if ( false === strpos( $body, (string) $old_content ) ) return Zoofi_Error::invalid( 'old_not_found', 'old_content was not found in the draft file.' ); 211 $result = self::write_file( $id, $file, str_replace( (string) $old_content, (string) $new_content, $body ) ); 222 $matches = substr_count( $body, (string) $old_content ); 223 if ( 0 === $matches ) return Zoofi_Error::invalid( 'old_not_found', 'old_content was not found in the draft file.' ); 224 if ( 1 !== $matches ) return Zoofi_Error::invalid( 'multiple_matches', 'old_content matched more than once. Add surrounding context so the edit is unambiguous.', array( 'status' => 409, 'matches' => $matches ) ); 225 $pos = strpos( $body, (string) $old_content ); 226 $updated = substr( $body, 0, $pos ) . (string) $new_content . substr( $body, $pos + strlen( (string) $old_content ) ); 227 $result = self::write_file( $id, $file, $updated ); 212 228 if ( ! is_wp_error( $result ) ) $result['mode'] = 'edit'; 213 229 return $result; … … 277 293 if ( is_wp_error( $check ) ) $errors[] = array( 'file' => $relative, 'message' => $check->get_error_message() ); 278 294 } 279 return array( 'ok' => empty( $errors ), 'draft_id' => $id, 'php_files_checked' => $checked, 'errors' => $errors ); 295 $summary = self::summary( $id ); 296 $required = array( 'style.css' ); 297 if ( empty( $record['is_child'] ) ) $required[] = 'index.php'; 298 $missing_required = array(); 299 foreach ( $required as $required_file ) if ( ! is_file( trailingslashit( $dir ) . $required_file ) ) $missing_required[] = $required_file; 300 if ( $missing_required ) $errors[] = array( 'file' => implode( ', ', $missing_required ), 'message' => 'Required theme file(s) missing.' ); 301 return array( 'ok' => empty( $errors ), 'draft_id' => $id, 'php_files_checked' => $checked, 'errors' => $errors, 'missing_required_files' => $missing_required, 'changes' => is_wp_error( $summary ) ? null : $summary['changes'], 'publish_ready' => empty( $errors ) ); 280 302 } 281 303 -
zoofiai-mcp-connector/trunk/readme.txt
r3711936 r3734304 5 5 Tested up to: 7.1 6 6 Requires PHP: 7.4 7 Stable tag: 2. 0.27 Stable tag: 2.1.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Securely connect WordPress to ZoofiAI and MCP-compatible AI clients for audited content, media, settings, plugin/theme management, and bulk workflows. Version 2. 0 is a mega update withDurable Jobs for persistent, resumable long AI workflows.11 Securely connect WordPress to ZoofiAI and MCP-compatible AI clients for audited content, media, settings, plugin/theme management, and bulk workflows. Version 2.1 adds builder-aware surgical editing, stronger theme-draft validation/outlines and expanded safe WP-CLI coverage while retaining Durable Jobs for persistent, resumable long AI workflows. 12 12 13 13 == Description == … … 60 60 == Changelog == 61 61 62 = 2.1.0 = 63 * Advanced Theme Lab: structural draft-file outlines, exact-match editing, publish-readiness validation, live-theme conflict detection, private preview, full publish backup and reversible rollback. 64 * Builder-aware surgical content engine for Elementor, Divi, Bricks, Breakdance, Beaver Builder, Gutenberg and classic editor content. Large payloads stay on WordPress; AI receives only matching snippets. 65 * Safe structural replacement for recognized serialized builder arrays; serialization byte lengths are regenerated instead of raw byte replacement. Object graphs remain blocked. 66 * Automatic content checkpoints now include supported page-builder meta so builder edits can be rolled back with Zoofi checkpoints. 67 * Expanded WP-CLI emulator coverage: user meta, option pluck/patch, taxonomy terms, post-term assignments, theme mods, custom roles/capabilities, cron test/run/delete, alongside existing plugin/theme/post/user/cache/database operations. 68 * Full Administrator signed connections continue to execute authorized operations without per-operation preview-token prompts. 69 70 62 71 = 2.0.2 = 63 * Updated plugin icon. 64 * Performance optimizations. 65 * Bug fixes. 72 * Fixed an activation regression where the connector could treat its own plugin basename as a conflicting Zoofi edition and immediately deactivate itself after WordPress reported “Plugin activated.” 73 * Edition switching now skips the current plugin and only deactivates an actually different Zoofi edition. 74 * Renamed the custom app.zoofiai.com plugin-row link from “View details” to “ZoofiAI Dashboard” so it no longer duplicates WordPress's built-in “View details” link. 75 * Preserves the 2.0.1 Full Administrator no-preview-token execution behavior and all existing pairing/security controls. 66 76 67 77 = 2.0.1 = -
zoofiai-mcp-connector/trunk/zoofiai-mcp-connector.php
r3711936 r3734304 3 3 * Plugin Name: ZoofiAI – Connect Your Site with ChatGPT, Claude & Any AI Agent via MCP 4 4 * Description: Securely connect WordPress to ZoofiAI and authorized MCP-compatible AI clients for content, media, settings, plugin/theme management, bulk workflows, diagnostics, and audited automation. 5 * Version: 2. 0.25 * Version: 2.1.0 6 6 * Plugin URI: https://app.zoofiai.com/ 7 7 * Author: Zoofi … … 159 159 160 160 if ( zoofi_private_runtime_allowed() ) { 161 define( 'ZOOFI_VERSION', '2. 0.2' );161 define( 'ZOOFI_VERSION', '2.1.0' ); 162 162 define( 'ZOOFI_PLUGIN_FILE', __FILE__ ); 163 163 define( 'ZOOFI_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); … … 171 171 require_once ZOOFI_PLUGIN_DIR . 'includes/class-zoofi-file-ops.php'; 172 172 require_once ZOOFI_PLUGIN_DIR . 'includes/class-zoofi-theme-drafts.php'; 173 require_once ZOOFI_PLUGIN_DIR . 'includes/class-zoofi-content-engine.php'; 173 174 require_once ZOOFI_PLUGIN_DIR . 'includes/class-zoofi-plugin-file-ops.php'; 174 175 require_once ZOOFI_PLUGIN_DIR . 'includes/class-zoofi-receipts.php';
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)