@@ -296,6 +296,179 @@ public function wpcom_get_site( string $site_id_or_url ): array {
296296 return (array ) $ site ;
297297 }
298298
299+ /**
300+ * Report the status of the Atlantis plugin and its modules across
301+ * Jetpack-connected WordPress.com sites.
302+ *
303+ * When `$site_id_or_url` is provided, returns the status for that single
304+ * site only and `$exclude_staging` is ignored. Otherwise queries the full
305+ * Jetpack-connected fleet. Sites without Atlantis are reported with
306+ * `atlantis_installed: false`.
307+ *
308+ * @param string|null $site_id_or_url Optional. Single site URL or WPCOM numeric ID.
309+ * @param string|null $module Optional. Restrict the report to a single module column. One of: messages, colophon, tracking, autoupdates.
310+ * @param bool $exclude_staging Exclude sites whose URL contains "staging" (case-insensitive). Ignored in single-site mode.
311+ * @param bool $issues_only Only return sites where Atlantis is not installed or at least one module is not on.
312+ * @param bool $with_messages_only Only return sites that have at least one stored Atlantis custom message.
313+ */
314+ #[McpTool( name: 'wpcom_get_atlantis_status ' )]
315+ public function wpcom_get_atlantis_status (
316+ ?string $ site_id_or_url = null ,
317+ ?string $ module = null ,
318+ bool $ exclude_staging = false ,
319+ bool $ issues_only = false ,
320+ bool $ with_messages_only = false
321+ ): array {
322+ $ identity_error = self ::ensure_identity ();
323+ if ( $ identity_error ) {
324+ return $ identity_error ;
325+ }
326+
327+ // Keep this list in sync with WPCOM_Atlantis_Status::KNOWN_MODULE_KEYS.
328+ $ known_modules = array ( 'messages ' , 'colophon ' , 'tracking ' , 'autoupdates ' );
329+
330+ $ module_keys = $ known_modules ;
331+ if ( ! \is_null ( $ module ) ) {
332+ $ module = \strtolower ( $ module );
333+ if ( ! \in_array ( $ module , $ known_modules , true ) ) {
334+ return array (
335+ 'error ' => "Unknown module ' $ module'. Accepted values: " . \implode ( ', ' , $ known_modules ) . '. ' ,
336+ );
337+ }
338+ $ module_keys = array ( $ module );
339+ }
340+
341+ $ sites = get_wpcom_jetpack_sites ();
342+ if ( null === $ sites ) {
343+ return array ( 'error ' => 'Failed to fetch Jetpack-connected sites. ' );
344+ }
345+
346+ if ( ! \is_null ( $ site_id_or_url ) ) {
347+ $ lookup = $ site_id_or_url ;
348+ $ host = \parse_url ( $ lookup , PHP_URL_HOST );
349+ if ( ! \is_string ( $ host ) || '' === $ host ) {
350+ $ host = \parse_url ( 'https:// ' . \ltrim ( $ lookup , '/ ' ), PHP_URL_HOST );
351+ }
352+ if ( \is_string ( $ host ) && '' !== $ host ) {
353+ $ lookup = $ host ;
354+ }
355+
356+ $ matched = null ;
357+ if ( \ctype_digit ( $ lookup ) ) {
358+ $ matched = $ sites [ (int ) $ lookup ] ?? null ;
359+ } else {
360+ $ lookup_lc = \strtolower ( $ lookup );
361+ foreach ( $ sites as $ site ) {
362+ $ candidate_host = \parse_url ( (string ) ( $ site ->siteurl ?? '' ), PHP_URL_HOST );
363+ if ( \is_string ( $ candidate_host ) && \strtolower ( $ candidate_host ) === $ lookup_lc ) {
364+ $ matched = $ site ;
365+ break ;
366+ }
367+ }
368+ }
369+
370+ if ( null === $ matched ) {
371+ return array ( 'error ' => "Site ' $ site_id_or_url' is not in the connected Jetpack sites list. " );
372+ }
373+
374+ $ site_id = (int ) ( $ matched ->userblog_id ?? 0 );
375+ if ( 0 === $ site_id ) {
376+ return array ( 'error ' => "Resolved site ' $ site_id_or_url' has no usable ID. " );
377+ }
378+
379+ $ sites = array ( $ site_id => $ matched );
380+ } elseif ( $ exclude_staging ) {
381+ $ sites = \array_filter (
382+ $ sites ,
383+ static fn ( $ site ) => false === \stripos ( (string ) ( $ site ->siteurl ?? '' ), 'staging ' )
384+ );
385+ }
386+
387+ $ errors = array ();
388+ $ statuses = get_wpcom_sites_atlantis_status_batch ( \array_column ( $ sites , 'userblog_id ' ), $ errors );
389+ if ( null === $ statuses ) {
390+ return array ( 'error ' => 'Failed to fetch Atlantis status batch. ' );
391+ }
392+
393+ $ rows = array ();
394+ $ installed_count = 0 ;
395+ $ issue_count = 0 ;
396+ $ sites_with_messages_count = 0 ;
397+ $ module_enabled_counts = \array_fill_keys ( $ module_keys , 0 );
398+
399+ foreach ( $ sites as $ site_id => $ site ) {
400+ $ status = $ statuses [ $ site_id ] ?? null ;
401+
402+ $ row = array (
403+ 'site_id ' => (int ) $ site ->userblog_id ,
404+ 'site_url ' => $ site ->siteurl ?? null ,
405+ 'atlantis_installed ' => false ,
406+ 'atlantis_version ' => null ,
407+ 'custom_messages_count ' => null ,
408+ 'modules ' => \array_fill_keys ( $ module_keys , null ),
409+ );
410+
411+ $ has_issue = true ;
412+ $ messages_count = 0 ;
413+
414+ if ( \is_object ( $ status ) ) {
415+ ++$ installed_count ;
416+ $ has_issue = false ;
417+ $ row ['atlantis_installed ' ] = true ;
418+ $ row ['atlantis_version ' ] = $ status ->plugin ->version ?? 'unknown ' ;
419+
420+ $ count_raw = $ status ->modules ->messages ->count ?? null ;
421+ if ( \is_int ( $ count_raw ) || ( \is_string ( $ count_raw ) && \ctype_digit ( $ count_raw ) ) ) {
422+ $ messages_count = (int ) $ count_raw ;
423+ $ row ['custom_messages_count ' ] = $ messages_count ;
424+ if ( $ messages_count > 0 ) {
425+ ++$ sites_with_messages_count ;
426+ }
427+ }
428+
429+ foreach ( $ module_keys as $ module_key ) {
430+ $ enabled = $ status ->modules ->$ module_key ->enabled ?? null ;
431+ if ( true === $ enabled ) {
432+ $ row ['modules ' ][ $ module_key ] = 'on ' ;
433+ ++$ module_enabled_counts [ $ module_key ];
434+ } elseif ( false === $ enabled ) {
435+ $ row ['modules ' ][ $ module_key ] = 'off ' ;
436+ $ has_issue = true ;
437+ } else {
438+ $ has_issue = true ;
439+ }
440+ }
441+ }
442+
443+ if ( $ has_issue ) {
444+ ++$ issue_count ;
445+ }
446+
447+ if ( $ issues_only && ! $ has_issue ) {
448+ continue ;
449+ }
450+ if ( $ with_messages_only && $ messages_count <= 0 ) {
451+ continue ;
452+ }
453+
454+ $ rows [] = $ row ;
455+ }
456+
457+ return array (
458+ 'count ' => count ( $ rows ),
459+ 'sites ' => $ rows ,
460+ 'errors ' => $ errors ,
461+ 'summary ' => array (
462+ 'total_sites_queried ' => count ( $ sites ),
463+ 'sites_with_atlantis ' => $ installed_count ,
464+ 'sites_with_issues ' => $ issue_count ,
465+ 'sites_with_messages ' => $ sites_with_messages_count ,
466+ 'modules_on ' => $ module_enabled_counts ,
467+ 'errors_count ' => count ( $ errors ),
468+ ),
469+ );
470+ }
471+
299472 /**
300473 * List plugins installed on a specific WordPress.com or Jetpack-connected site.
301474 *
0 commit comments