'System', 'design' => 'Themes / Design', 'commerce' => 'Commerce', 'booking' => 'Booking', 'forms' => 'Forms', 'email' => 'Email', 'seo' => 'SEO', 'performance' => 'Performance', 'security' => 'Security', 'analytics' => 'Analytics', 'marketing' => 'Marketing', 'social' => 'Social', 'content' => 'Content', 'integrations' => 'Integrations', ); public function group( Graph $source ): Graph { $data = $source->jsonSerialize(); $nodes = array(); foreach ( $data['nodes'] as $node ) { $nodes[ $node['id'] ] = $node; } $assigned = array(); foreach ( $nodes as $id => $node ) { $group = $this->directGroup( $id, $node ); if ( $group !== null ) { $assigned[ $id ] = $group; } } // Explicit relationships let extensions inherit the subsystem of their known base. for ( $pass = 0; $pass < 4; ++$pass ) { foreach ( $data['edges'] as $edge ) { if ( ! in_array( $edge['relationship'], array( 'depends_on', 'extends', 'provides', 'integrates_with', 'child_of' ), true ) ) { continue; } if ( ! isset( $assigned[ $edge['source'] ], $assigned[ $edge['target'] ] ) && isset( $assigned[ $edge['target'] ] ) && ( $nodes[ $edge['source'] ]['type'] ?? null ) !== 'wordpress' ) { $assigned[ $edge['source'] ] = $assigned[ $edge['target'] ]; } } } foreach ( $nodes as $id => $node ) { if ( ! isset( $assigned[ $id ] ) && $node['type'] === 'plugin' ) { $assigned[ $id ] = 'integrations'; } } $members = array(); foreach ( $assigned as $id => $group ) { $members[ $group ][] = $id; } $display = new Graph(); if ( isset( $nodes['wordpress:installation'] ) ) { $display->addNode( $this->copyNode( $nodes['wordpress:installation'], null ) ); } foreach ( self::GROUPS as $id => $label ) { if ( empty( $members[ $id ] ) ) { continue; } $counts = array_fill_keys( array( 'critical', 'warning', 'info', 'healthy', 'inactive', 'unknown' ), 0 ); $presentation_counts = array_fill_keys( array( 'critical', 'problem', 'recommended', 'maintenance', 'review', 'healthy', 'not_checked' ), 0 ); $maintenance = 0; foreach ( $members[ $id ] as $member ) { ++$counts[ $nodes[ $member ]['status'] ]; $maintenance += $this->hasMaintenance( $nodes[ $member ] ) ? 1 : 0; ++$presentation_counts[ $this->presentationState( $nodes[ $member ] ) ]; } list( $status, $severity ) = $this->groupStatus( $counts ); $display->addNode( new Node( 'group:' . $id, 'group', 'subsystem', $label, $status, $severity, array( 'subsystem' => $id, 'component_count' => count( $members[ $id ] ), 'status_counts' => $counts, 'maintenance_count' => $maintenance, 'presentation_counts' => $presentation_counts, 'presentation_status' => $this->presentationStatus( $presentation_counts ), 'collapsed' => true, ) ) ); } foreach ( $nodes as $id => $node ) { if ( $id !== 'wordpress:installation' ) { $display->addNode( $this->copyNode( $node, $assigned[ $id ] ?? null ) ); } } foreach ( $data['edges'] as $edge ) { if ( $edge['source'] === 'wordpress:installation' && isset( $assigned[ $edge['target'] ] ) && in_array( $edge['relationship'], array( 'contains', 'uses' ), true ) ) { continue; } $display->addEdge( new Edge( $edge['id'], $edge['source'], $edge['target'], $edge['relationship'], $edge['confidence'], (array) ( $edge['metadata'] ?? array() ) ) ); } foreach ( $members as $group => $ids ) { $groupId = 'group:' . $group; if ( isset( $nodes['wordpress:installation'] ) ) { $display->addEdge( $this->edge( 'wordpress:installation', $groupId ) ); } foreach ( $ids as $id ) { $display->addEdge( $this->edge( $groupId, $id ) ); } } return $display; } private function directGroup( string $id, array $node ): ?string { if ( in_array( $id, array( 'system:php', 'system:database', 'system:cron' ), true ) ) { return 'system'; } if ( $node['type'] === 'theme' ) { return 'design'; } $integrations = array( 'woocommerce' => 'commerce', 'elementor' => 'design', 'smtp' => 'email', 'seo' => 'seo', 'caching' => 'performance', 'security' => 'security' ); if ( strpos( $id, 'integration:' ) === 0 ) { return $integrations[ substr( $id, 12 ) ] ?? 'integrations'; } $map = array( 'plugin:woocommerce/woocommerce.php' => 'commerce', 'plugin:elementor/elementor.php' => 'design', 'plugin:elementor-pro/elementor-pro.php' => 'design', 'plugin:motopress-hotel-booking/motopress-hotel-booking.php' => 'booking', 'plugin:motopress-hotel-booking-lite/motopress-hotel-booking.php' => 'booking', 'plugin:mphb-mailchimp/mphb-mailchimp.php' => 'booking', 'plugin:mphb-checkout-fields/mphb-checkout-fields.php' => 'booking', 'plugin:mphb-multi-currency/mphb-multi-currency.php' => 'booking', 'plugin:mphb-notifier/mphb-notifier.php' => 'booking', 'plugin:mphb-payment-request/mphb-payment-request.php' => 'booking', 'plugin:mphb-invoices/mphb-invoices.php' => 'booking', 'plugin:mphb-reviews/mphb-reviews.php' => 'booking', 'plugin:mphb-styles/mphb-styles.php' => 'booking', 'plugin:mphb-elementor/mphb-elementor.php' => 'booking', 'plugin:mphb-woocommerce/mphb-woocommerce.php' => 'booking', 'plugin:mphb-woocommerce-payments/mphb-woocommerce-payments.php' => 'booking', 'plugin:salient-core/salient-core.php' => 'design', 'plugin:salient-portfolio/salient-portfolio.php' => 'design', 'plugin:salient-widgets/salient-widgets.php' => 'design', 'plugin:salient-shortcodes/salient-shortcodes.php' => 'design', 'plugin:salient-home-slider/salient-home-slider.php' => 'design', 'plugin:salient-wpbakery/salient-wpbakery.php' => 'design', 'plugin:hoteller-elementor/hoteller-elementor.php' => 'design', 'plugin:hoteller-custom-post-type/hoteller-custom-post-type.php' => 'design', 'plugin:contact-form-7/wp-contact-form-7.php' => 'forms', 'plugin:wpforms-lite/wpforms.php' => 'forms', 'plugin:gravityforms/gravityforms.php' => 'forms', 'plugin:ninja-forms/ninja-forms.php' => 'forms', 'plugin:mailchimp-for-wp/mc4wp.php' => 'marketing', 'plugin:mailchimp-for-woocommerce/mailchimp-woocommerce.php' => 'marketing', 'plugin:google-analytics-for-wordpress/googleanalytics.php' => 'analytics', 'plugin:duracelltomi-google-tag-manager/duracelltomi-google-tag-manager-for-wordpress.php' => 'analytics', 'plugin:add-to-any/add-to-any.php' => 'social', 'plugin:classic-editor/classic-editor.php' => 'content', 'plugin:advanced-custom-fields/acf.php' => 'content', 'plugin:advanced-custom-fields-pro/acf.php' => 'content', ); if ( isset( $map[ $id ] ) ) { return $map[ $id ]; } return null; } private function copyNode( array $node, ?string $group ): Node { $metadata = (array) $node['metadata']; if ( $group !== null ) { $metadata['semantic_group'] = $group; } return new Node( $node['id'], $node['type'], $node['category'], $node['label'], $node['status'], $node['severity'], $metadata ); } private function edge( string $source, string $target ): Edge { return new Edge( 'edge:group:' . hash( 'sha256', $source . "\0" . $target ), $source, $target, 'contains', 'high', array( 'evidence' => 'semantic_grouping' ) ); } private function hasMaintenance( array $node ): bool { $metadata = (array) $node['metadata']; $health = (array) ( $metadata['health'] ?? array() ); foreach ( $health['findings'] ?? array() as $finding ) { if ( is_array( $finding ) && ( $finding['classification'] ?? null ) === 'maintenance' ) { return true; } } return false; } private function groupStatus( array $counts ): array { if ( $counts['critical'] ) { return array( 'critical', 3 ); } if ( $counts['warning'] ) { return array( 'warning', 2 ); } if ( $counts['info'] ) { return array( 'info', 1 ); } if ( $counts['unknown'] ) { return array( 'unknown', 0 ); } if ( $counts['healthy'] ) { return array( 'healthy', 0 ); } return array( 'inactive', 0 ); } private function presentationState( array $node ): string { if ( ( $node['status'] ?? null ) === 'critical' ) { return 'critical'; } $metadata = (array) ( $node['metadata'] ?? array() ); $health = (array) ( $metadata['health'] ?? array() ); $states = array(); foreach ( is_array( $health['findings'] ?? null ) ? $health['findings'] : array() as $finding ) { $classification = $finding['classification'] ?? ''; if ( in_array( $classification, array( 'runtime', 'security', 'availability' ), true ) ) { $states['problem'] = true; } elseif ( in_array( $classification, array( 'configuration', 'compatibility' ), true ) ) { $states['recommended'] = true; } elseif ( $classification === 'maintenance' ) { $states['maintenance'] = true; } } foreach ( array( 'problem', 'recommended', 'maintenance' ) as $state ) { if ( isset( $states[ $state ] ) ) { return $state; } } if ( ( $node['status'] ?? null ) === 'inactive' ) { return 'review'; } if ( ( $node['status'] ?? null ) === 'healthy' ) { return 'healthy'; } if ( ( $node['status'] ?? null ) === 'unknown' ) { return 'not_checked'; } return 'review'; } private function presentationStatus( array $counts ): string { if ( $counts['critical'] ) { return 'Critical'; } if ( $counts['problem'] ) { return 'Problem'; } if ( $counts['review'] ) { return 'Review'; } if ( $counts['recommended'] ) { return 'Recommended'; } if ( $counts['maintenance'] ) { return 'Maintenance'; } if ( $counts['not_checked'] > $counts['healthy'] ) { return 'Not Checked'; } if ( $counts['healthy'] ) { return 'Healthy'; } return 'Not Checked'; } }