PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.14
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.14
2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 All 139 releases
metasync / wp-mcp-server / tools / class-mcp-tool-custom-pages.php

class-mcp-tool-custom-pages.php in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.14, at wp-mcp-server/tools/class-mcp-tool-custom-pages.php

687 lines 27.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * MCP Tools for Custom HTML Pages Operations
4 *
5 * Provides MCP tools for managing custom HTML pages.
6 *
7 * @package MetaSync
8 * @subpackage MCP_Server/Tools
9 */
10
11 if (!defined('ABSPATH')) {
12 exit;
13 }
14
15 require_once plugin_dir_path(dirname(__FILE__)) . 'class-mcp-tool-base.php';
16
17 /**
18 * Create Custom Page Tool
19 *
20 * Creates a new custom HTML page
21 */
22 class MCP_Tool_Create_Custom_Page extends MCP_Tool_Base {
23
24 public function get_name() {
25 return 'wordpress_create_custom_page';
26 }
27
28 public function get_description() {
29 return 'Create a new custom HTML page with raw HTML content';
30 }
31
32 public function get_input_schema() {
33 return [
34 'type' => 'object',
35 'properties' => [
36 'title' => [
37 'type' => 'string',
38 'description' => 'Page title',
39 ],
40 'slug' => [
41 'type' => 'string',
42 'description' => 'Page slug (URL-friendly name, optional)',
43 ],
44 'html_content' => [
45 'type' => 'string',
46 'description' => 'Raw HTML content for the page',
47 ],
48 'status' => [
49 'type' => 'string',
50 'enum' => ['publish', 'draft', 'pending'],
51 'description' => 'Page status (default: publish)',
52 ],
53 'enable_raw_html' => [
54 'type' => 'boolean',
55 'description' => 'Enable raw HTML mode to bypass theme (default: true)',
56 ],
57 'filename' => [
58 'type' => 'string',
59 'description' => 'Original HTML filename for reference (optional)',
60 ],
61 ],
62 'required' => ['title', 'html_content'],
63 ];
64 }
65
66 public function execute($params) {
67 $this->validate_params($params);
68 $this->require_capability('edit_pages');
69
70 // Load custom pages class constants
71 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages.php';
72
73 // Prepare page data
74 $page_data = [
75 'post_title' => sanitize_text_field($params['title']),
76 'post_type' => 'page',
77 'post_status' => isset($params['status']) ? sanitize_text_field($params['status']) : 'publish',
78 'post_content' => '', // HTML stored in meta
79 ];
80
81 // Set slug if provided
82 if (!empty($params['slug'])) {
83 $page_data['post_name'] = sanitize_title($params['slug']);
84
85 // Check if page with same slug already exists
86 $existing_page = get_page_by_path($page_data['post_name'], OBJECT, 'page');
87 if ($existing_page) {
88 throw new Exception('A page with this slug already exists');
89 }
90 }
91
92 // Insert the page
93 $page_id = wp_insert_post($page_data, true);
94
95 if (is_wp_error($page_id)) {
96 throw new Exception('Failed to create page: ' . $page_id->get_error_message());
97 }
98
99 // Mark as custom HTML page
100 update_post_meta($page_id, Metasync_Custom_Pages::META_IS_CUSTOM_HTML_PAGE, '1');
101
102 // Mark as created via API
103 update_post_meta($page_id, Metasync_Custom_Pages::META_CREATED_VIA_API, '1');
104
105 // Enable raw HTML mode
106 $enable_raw_html = isset($params['enable_raw_html']) ? (bool)$params['enable_raw_html'] : true;
107 update_post_meta($page_id, Metasync_Custom_Pages::META_HTML_ENABLED, $enable_raw_html ? '1' : '0');
108
109 // Store HTML content (no sanitization - admin users are trusted)
110 update_post_meta($page_id, Metasync_Custom_Pages::META_HTML_CONTENT, wp_unslash($params['html_content']));
111
112 // Store filename if provided
113 if (!empty($params['filename'])) {
114 update_post_meta($page_id, Metasync_Custom_Pages::META_HTML_FILENAME, sanitize_file_name($params['filename']));
115 }
116
117 // Clear cache
118 wp_cache_delete($page_id, 'posts');
119 wp_cache_delete($page_id, 'post_meta');
120
121 return $this->success([
122 'page_id' => $page_id,
123 'title' => get_the_title($page_id),
124 'slug' => get_post_field('post_name', $page_id),
125 'url' => get_permalink($page_id),
126 'edit_url' => get_edit_post_link($page_id, 'raw'),
127 'status' => get_post_status($page_id),
128 'raw_html_enabled' => $enable_raw_html,
129 'html_length' => strlen($params['html_content']),
130 'created_at' => get_post_field('post_date', $page_id),
131 'message' => 'Custom HTML page created successfully',
132 ]);
133 }
134 }
135
136 /**
137 * Get Custom Page Tool
138 *
139 * Retrieves a custom HTML page
140 */
141 class MCP_Tool_Get_Custom_Page extends MCP_Tool_Base {
142
143 public function get_name() {
144 return 'wordpress_get_custom_page';
145 }
146
147 public function get_description() {
148 return 'Get a custom HTML page by ID or slug';
149 }
150
151 public function get_input_schema() {
152 return [
153 'type' => 'object',
154 'properties' => [
155 'page_id' => [
156 'type' => 'integer',
157 'description' => 'Page ID',
158 ],
159 'slug' => [
160 'type' => 'string',
161 'description' => 'Page slug',
162 ],
163 ],
164 ];
165 }
166
167 public function execute($params) {
168 $this->validate_params($params);
169 $this->require_capability('edit_pages');
170
171 // Load custom pages class constants
172 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages.php';
173
174 $page_id = isset($params['page_id']) ? intval($params['page_id']) : null;
175 $slug = isset($params['slug']) ? sanitize_text_field($params['slug']) : null;
176
177 if (empty($page_id) && empty($slug)) {
178 throw new Exception('Either page_id or slug must be provided');
179 }
180
181 // Get page by ID or slug
182 if (!empty($page_id)) {
183 $page = get_post($page_id);
184 } else {
185 $page = get_page_by_path($slug, OBJECT, 'page');
186 }
187
188 if (!$page || $page->post_type !== 'page') {
189 throw new Exception('Page not found');
190 }
191
192 // Verify it's a custom HTML page
193 $is_custom_html_page = get_post_meta($page->ID, Metasync_Custom_Pages::META_IS_CUSTOM_HTML_PAGE, true);
194 if ($is_custom_html_page !== '1') {
195 throw new Exception('This page is not a custom HTML page');
196 }
197
198 // Get HTML content and metadata
199 $html_content = get_post_meta($page->ID, Metasync_Custom_Pages::META_HTML_CONTENT, true);
200 $html_enabled = get_post_meta($page->ID, Metasync_Custom_Pages::META_HTML_ENABLED, true);
201 $html_filename = get_post_meta($page->ID, Metasync_Custom_Pages::META_HTML_FILENAME, true);
202
203 return $this->success([
204 'page_id' => $page->ID,
205 'title' => $page->post_title,
206 'slug' => $page->post_name,
207 'url' => get_permalink($page->ID),
208 'edit_url' => get_edit_post_link($page->ID, 'raw'),
209 'status' => $page->post_status,
210 'raw_html_enabled' => $html_enabled === '1',
211 'html_content' => $html_content,
212 'html_filename' => $html_filename,
213 'html_length' => strlen($html_content),
214 'created_at' => $page->post_date,
215 'updated_at' => $page->post_modified,
216 ]);
217 }
218 }
219
220 /**
221 * List Custom Pages Tool
222 *
223 * Lists all custom HTML pages
224 */
225 class MCP_Tool_List_Custom_Pages extends MCP_Tool_Base {
226
227 public function get_name() {
228 return 'wordpress_list_custom_pages';
229 }
230
231 public function get_description() {
232 return 'List all custom HTML pages';
233 }
234
235 public function get_input_schema() {
236 return [
237 'type' => 'object',
238 'properties' => [
239 'status' => [
240 'type' => 'string',
241 'enum' => ['publish', 'draft', 'pending', 'all'],
242 'description' => 'Filter by page status (default: all)',
243 ],
244 ],
245 ];
246 }
247
248 public function execute($params) {
249 $this->validate_params($params);
250 $this->require_capability('edit_pages');
251
252 // Load custom pages class
253 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages.php';
254
255 // Build query args
256 $args = [];
257 if (isset($params['status']) && $params['status'] !== 'all') {
258 $args['post_status'] = sanitize_text_field($params['status']);
259 }
260
261 $pages = Metasync_Custom_Pages::get_custom_pages($args);
262
263 $pages_data = [];
264 foreach ($pages as $page) {
265 $html_enabled = get_post_meta($page->ID, Metasync_Custom_Pages::META_HTML_ENABLED, true);
266 $html_content = get_post_meta($page->ID, Metasync_Custom_Pages::META_HTML_CONTENT, true);
267 $html_filename = get_post_meta($page->ID, Metasync_Custom_Pages::META_HTML_FILENAME, true);
268
269 $pages_data[] = [
270 'page_id' => $page->ID,
271 'title' => $page->post_title,
272 'slug' => $page->post_name,
273 'url' => get_permalink($page->ID),
274 'edit_url' => get_edit_post_link($page->ID, 'raw'),
275 'status' => $page->post_status,
276 'raw_html_enabled' => $html_enabled === '1',
277 'html_filename' => $html_filename,
278 'html_length' => strlen($html_content),
279 'created_at' => $page->post_date,
280 'updated_at' => $page->post_modified,
281 ];
282 }
283
284 return $this->success([
285 'count' => count($pages_data),
286 'pages' => $pages_data,
287 ]);
288 }
289 }
290
291 /**
292 * Update Custom Page Tool
293 *
294 * Updates an existing custom HTML page
295 */
296 class MCP_Tool_Update_Custom_Page extends MCP_Tool_Base {
297
298 public function get_name() {
299 return 'wordpress_update_custom_page';
300 }
301
302 public function get_description() {
303 return 'Update an existing custom HTML page';
304 }
305
306 public function get_input_schema() {
307 return [
308 'type' => 'object',
309 'properties' => [
310 'page_id' => [
311 'type' => 'integer',
312 'description' => 'Page ID to update',
313 ],
314 'title' => [
315 'type' => 'string',
316 'description' => 'Page title (optional)',
317 ],
318 'slug' => [
319 'type' => 'string',
320 'description' => 'Page slug (optional)',
321 ],
322 'html_content' => [
323 'type' => 'string',
324 'description' => 'Raw HTML content (optional)',
325 ],
326 'status' => [
327 'type' => 'string',
328 'enum' => ['publish', 'draft', 'pending'],
329 'description' => 'Page status (optional)',
330 ],
331 'enable_raw_html' => [
332 'type' => 'boolean',
333 'description' => 'Enable raw HTML mode (optional)',
334 ],
335 'filename' => [
336 'type' => 'string',
337 'description' => 'HTML filename (optional)',
338 ],
339 ],
340 'required' => ['page_id'],
341 ];
342 }
343
344 public function execute($params) {
345 $this->validate_params($params);
346 $this->require_capability('edit_pages');
347
348 // Load custom pages class constants
349 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages.php';
350
351 $page_id = intval($params['page_id']);
352
353 // Verify page exists
354 $page = get_post($page_id);
355 if (!$page || $page->post_type !== 'page') {
356 throw new Exception(sprintf("Page not found with ID: %d", absint($page_id)));
357 }
358
359 // Verify it's a custom HTML page
360 $is_custom_html_page = get_post_meta($page_id, Metasync_Custom_Pages::META_IS_CUSTOM_HTML_PAGE, true);
361 if ($is_custom_html_page !== '1') {
362 throw new Exception('This page is not a custom HTML page');
363 }
364
365 // Update page data if provided
366 $update_data = ['ID' => $page_id];
367
368 if (isset($params['title'])) {
369 $update_data['post_title'] = sanitize_text_field($params['title']);
370 }
371
372 if (isset($params['slug'])) {
373 $update_data['post_name'] = sanitize_title($params['slug']);
374 }
375
376 if (isset($params['status'])) {
377 $update_data['post_status'] = sanitize_text_field($params['status']);
378 }
379
380 // Update page if there are changes
381 if (count($update_data) > 1) {
382 $result = wp_update_post($update_data, true);
383 if (is_wp_error($result)) {
384 throw new Exception('Failed to update page: ' . $result->get_error_message());
385 }
386 }
387
388 // Update HTML content if provided
389 if (isset($params['html_content'])) {
390 update_post_meta($page_id, Metasync_Custom_Pages::META_HTML_CONTENT, wp_unslash($params['html_content']));
391 }
392
393 // Update raw HTML mode if provided
394 if (isset($params['enable_raw_html'])) {
395 $enable_raw_html = (bool)$params['enable_raw_html'];
396 update_post_meta($page_id, Metasync_Custom_Pages::META_HTML_ENABLED, $enable_raw_html ? '1' : '0');
397 }
398
399 // Update filename if provided
400 if (isset($params['filename'])) {
401 update_post_meta($page_id, Metasync_Custom_Pages::META_HTML_FILENAME, sanitize_file_name($params['filename']));
402 }
403
404 // Clear cache
405 wp_cache_delete($page_id, 'posts');
406 wp_cache_delete($page_id, 'post_meta');
407
408 return $this->success([
409 'page_id' => $page_id,
410 'title' => get_the_title($page_id),
411 'slug' => get_post_field('post_name', $page_id),
412 'url' => get_permalink($page_id),
413 'edit_url' => get_edit_post_link($page_id, 'raw'),
414 'status' => get_post_status($page_id),
415 'raw_html_enabled' => get_post_meta($page_id, Metasync_Custom_Pages::META_HTML_ENABLED, true) === '1',
416 'html_length' => strlen(get_post_meta($page_id, Metasync_Custom_Pages::META_HTML_CONTENT, true)),
417 'updated_at' => get_post_field('post_modified', $page_id),
418 'message' => 'Custom HTML page updated successfully',
419 ]);
420 }
421 }
422
423 /**
424 * Delete Custom Page Tool
425 *
426 * Deletes a custom HTML page
427 */
428 class MCP_Tool_Delete_Custom_Page extends MCP_Tool_Base {
429
430 public function get_name() {
431 return 'wordpress_delete_custom_page';
432 }
433
434 public function get_description() {
435 return 'Delete a custom HTML page permanently';
436 }
437
438 public function get_input_schema() {
439 return [
440 'type' => 'object',
441 'properties' => [
442 'page_id' => [
443 'type' => 'integer',
444 'description' => 'Page ID to delete',
445 ],
446 ],
447 'required' => ['page_id'],
448 ];
449 }
450
451 public function execute($params) {
452 $this->validate_params($params);
453 $this->require_capability('delete_pages');
454
455 // Delegate to the shared REST/MCP delete implementation so both paths
456 // perform identical asset cleanup and front-page reset.
457 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages.php';
458 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages-api.php';
459
460 $page_id = intval($params['page_id']);
461
462 $api = new Metasync_Custom_Pages_API();
463 $result = $api->delete_custom_page_with_cleanup($page_id);
464
465 if (is_wp_error($result)) {
466 throw new Exception($result->get_error_message());
467 }
468
469 return $this->success(array_merge($result, [
470 'message' => 'Custom HTML page deleted successfully',
471 ]));
472 }
473 }
474
475 /**
476 * Import LPS Page Tool
477 *
478 * Imports an LPS (Landing Page Studio) ZIP export into WordPress as a custom
479 * HTML page, extracting bundled assets to wp-content/uploads/metasync-pages/{slug}/.
480 * Re-importing with the same slug overwrites the previous page and assets.
481 */
482 class MCP_Tool_Import_LPS_Page extends MCP_Tool_Base {
483
484 public function get_name() {
485 return 'wordpress_import_lps_page';
486 }
487
488 public function get_description() {
489 return 'Import an LPS (Landing Page Studio) ZIP export into WordPress as a custom HTML page, extracting assets to uploads/metasync-pages/{slug}/';
490 }
491
492 public function get_input_schema() {
493 return [
494 'type' => 'object',
495 'properties' => [
496 'download_url' => [
497 'type' => 'string',
498 'description' => 'URL to download the LPS ZIP from.',
499 ],
500 'title' => [
501 'type' => 'string',
502 'description' => 'Page title (single-page imports only). Ignored for multi-page bundles, which take titles from pages.manifest.json.',
503 ],
504 'slug' => [
505 'type' => 'string',
506 'description' => 'URL slug (single-page imports only). Required when the ZIP has no pages.manifest.json; ignored for multi-page bundles. Re-importing with the same slug overwrites the previous LPS page.',
507 ],
508 'assets_folder' => [
509 'type' => 'string',
510 'description' => 'On-disk folder name the bundle is extracted to (under uploads/metasync-pages/). This is the path LPS bakes into the asset URLs at build time and is intentionally separate from the slug. Defaults to the slug when omitted.',
511 ],
512 'external_ref' => [
513 'type' => 'string',
514 'description' => 'LPS project UUID (stable per-project identifier). When provided, used as the primary home-page dedup key instead of assets_folder.',
515 ],
516 'overwrite' => [
517 'type' => 'boolean',
518 'description' => 'When true (default), an existing page with the same slug is overwritten.',
519 ],
520 'status' => [
521 'type' => 'string',
522 'enum' => ['publish', 'draft', 'pending'],
523 'description' => 'Page status (default: publish)',
524 ],
525 ],
526 'required' => ['download_url'],
527 ];
528 }
529
530 public function execute($params) {
531 $this->validate_params($params);
532 $this->require_capability('edit_pages');
533
534 if (empty($params['download_url'])) {
535 throw new Exception('download_url is required.');
536 }
537
538 $raw_slug = isset($params['slug']) ? $params['slug'] : '';
539 if (is_string($raw_slug) && (strpos($raw_slug, '..') !== false || strpos($raw_slug, '/') !== false || strpos($raw_slug, '\\') !== false)) {
540 throw new Exception('Slug must not contain path separators or parent references.');
541 }
542
543 $tmp_file = null;
544 $max_zip_bytes = 50 * 1024 * 1024;
545
546 // --- Audit tracking (one persistent record on success and failure paths) ---
547 $_lps_start_ms = (int) round(microtime(true) * 1000);
548 $_lps_success = false;
549 $_lps_result_data = null;
550 $_lps_exc = null;
551 $_lps_err_status = 0;
552 $_lps_downloaded = 0;
553 $_lps_af = isset($params['assets_folder']) ? $params['assets_folder'] : (isset($params['slug']) ? $params['slug'] : '');
554 $_lps_external_ref = isset($params['external_ref']) ? sanitize_text_field($params['external_ref']) : '';
555
556 try {
557 // wp_tempnam() lives in wp-admin/includes/file.php, which is NOT loaded
558 // during a normal REST/MCP request — load it so this works in any context.
559 if (!function_exists('wp_tempnam')) {
560 require_once ABSPATH . 'wp-admin/includes/file.php';
561 }
562 $tmp_file = wp_tempnam('lps_import_');
563 if (!$tmp_file) {
564 throw new Exception('Failed to allocate a temporary file for the ZIP.');
565 }
566
567 $response = wp_safe_remote_get($params['download_url'], [
568 'timeout' => 60,
569 'stream' => true,
570 'filename' => $tmp_file,
571 ]);
572 if (is_wp_error($response)) {
573 throw new Exception('Failed to download ZIP: ' . $response->get_error_message());
574 }
575 $code = wp_remote_retrieve_response_code($response);
576 if ((int) $code !== 200) {
577 throw new Exception('ZIP download returned HTTP ' . intval($code));
578 }
579 $content_type = strtolower((string) wp_remote_retrieve_header($response, 'content-type'));
580 if ($content_type !== '' && strpos($content_type, 'zip') === false && strpos($content_type, 'octet-stream') === false) {
581 throw new Exception('Downloaded ZIP has unexpected Content-Type: ' . $content_type);
582 }
583 $downloaded_size = file_exists($tmp_file) ? filesize($tmp_file) : 0;
584 $_lps_downloaded = $downloaded_size;
585 if ($downloaded_size === 0) {
586 throw new Exception('Downloaded ZIP file is empty.');
587 }
588 if ($downloaded_size > $max_zip_bytes) {
589 throw new Exception('Downloaded ZIP exceeds the maximum allowed size (' . intval($max_zip_bytes / 1024 / 1024) . ' MB).');
590 }
591
592 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages.php';
593 require_once plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages-api.php';
594
595 $slug = isset($params['slug']) ? sanitize_title($params['slug']) : '';
596 $title = isset($params['title']) ? sanitize_text_field($params['title']) : '';
597 $status = isset($params['status']) ? sanitize_text_field($params['status']) : 'publish';
598 $overwrite = isset($params['overwrite']) ? (bool) $params['overwrite'] : true;
599 $assets_folder = isset($params['assets_folder']) ? $params['assets_folder'] : '';
600 $external_ref = isset($params['external_ref']) ? sanitize_text_field($params['external_ref']) : '';
601
602 $api = new Metasync_Custom_Pages_API();
603 $result = $api->extract_and_create_lps_page($tmp_file, $slug, $title, $status, $overwrite, $assets_folder, $external_ref);
604
605 if (is_wp_error($result)) {
606 $_lps_err_data = $result->get_error_data();
607 $_lps_err_status = (is_array($_lps_err_data) && isset($_lps_err_data['status'])) ? (int) $_lps_err_data['status'] : 0;
608 throw new Exception($result->get_error_message());
609 }
610
611 // Surface the helper's full data payload — the shape differs for single
612 // (page_id/url/status) vs multi (created/updated/failed) imports.
613 $data = isset($result['data']) && is_array($result['data']) ? $result['data'] : [];
614 $data['message'] = isset($result['message']) ? $result['message'] : 'LPS ZIP imported successfully';
615
616 // Capture for the audit record now so the per-page breakdown survives
617 // even when the all-failed multi-page case throws below.
618 $_lps_result_data = $data;
619
620 // For a multi-page import where EVERY page failed, the helper still
621 // returns a non-WP_Error array. Surface that as a failure to the agent
622 // (mirrors the REST endpoint's 422) instead of reporting false success.
623 if (isset($data['mode']) && $data['mode'] === 'multi') {
624 $succeeded = count(isset($data['created']) ? $data['created'] : [])
625 + count(isset($data['updated']) ? $data['updated'] : []);
626 $failed = isset($data['failed']) ? $data['failed'] : [];
627 if ($succeeded === 0 && count($failed) > 0) {
628 $reasons = array();
629 foreach ($failed as $f) {
630 $reasons[] = (isset($f['slug']) ? $f['slug'] : '?') . ': ' . (isset($f['code']) ? $f['code'] : 'failed');
631 }
632 throw new Exception('LPS import failed for all pages — ' . implode('; ', $reasons));
633 }
634 }
635
636 $_lps_success = true;
637 return $this->success($data);
638 } catch (Exception $e) {
639 $_lps_exc = $e;
640 throw $e;
641 } finally {
642 if (!empty($tmp_file) && file_exists($tmp_file)) {
643 @unlink($tmp_file);
644 }
645
646 // Write exactly one persistent audit record (success or failure),
647 // regardless of WP_DEBUG. Load the API class if an early exception
648 // fired before the require_once above ran.
649 if (!class_exists('Metasync_Custom_Pages_API')) {
650 $api_class_path = plugin_dir_path(dirname(dirname(__FILE__))) . 'custom-pages/class-metasync-custom-pages-api.php';
651 if (file_exists($api_class_path)) {
652 require_once $api_class_path;
653 }
654 }
655 if (class_exists('Metasync_Custom_Pages_API')) {
656 // Derive HTTP status from the captured data when available (covers the
657 // success path AND the all-failed multi-page case that throws → 422).
658 // A null payload means an early exception (download/extract) → 500.
659 if (is_array($_lps_result_data)) {
660 $_s = count(isset($_lps_result_data['created']) ? $_lps_result_data['created'] : array())
661 + count(isset($_lps_result_data['updated']) ? $_lps_result_data['updated'] : array());
662 $_f = count(isset($_lps_result_data['failed']) ? $_lps_result_data['failed'] : array());
663 $_lps_http = ($_f > 0 && $_s > 0) ? 207 : (($_f > 0 && $_s === 0) ? 422 : 200);
664 } else {
665 $_lps_http = $_lps_err_status > 0 ? $_lps_err_status : 500;
666 }
667
668 Metasync_Custom_Pages_API::write_lps_import_audit(array(
669 'result' => is_array($_lps_result_data) ? array('success' => $_lps_success, 'data' => $_lps_result_data) : null,
670 'http_status' => $_lps_http,
671 'input' => array(
672 'source_type' => 'download_url',
673 'zip_size_bytes' => $_lps_downloaded,
674 'assets_folder' => $_lps_af,
675 'external_ref' => $_lps_external_ref,
676 'pages_in_manifest' => ($_lps_success && isset($_lps_result_data['pages_total'])) ? (int) $_lps_result_data['pages_total'] : null,
677 ),
678 'start_ms' => $_lps_start_ms,
679 'auth_method' => 'mcp-capability',
680 'api_key_prefix' => '',
681 'error_message' => $_lps_exc ? $_lps_exc->getMessage() : '',
682 ));
683 }
684 }
685 }
686 }
687