key() ); $generated_at = $payload['generated_at'] ?? null; if ( ! is_array( $payload ) || ( $payload['schema'] ?? null ) !== 1 || ! is_int( $generated_at ) || $generated_at < time() - self::TTL - 60 || $generated_at > time() + 60 || ! is_array( $payload['graph'] ?? null ) ) { if ( $payload !== false ) { $this->invalidate(); } return null; } try { $graph = new Graph(); $data = $payload['graph']; if ( ! is_array( $data['nodes'] ?? null ) || ! is_array( $data['edges'] ?? null ) ) { throw new \UnexpectedValueException(); } foreach ( $data['nodes'] as $node ) { if ( ! is_array( $node ) || array_diff( array( 'id', 'type', 'category', 'label', 'status', 'severity', 'metadata' ), array_keys( $node ) ) || ( ! is_array( $node['metadata'] ) && ! is_object( $node['metadata'] ) ) ) { throw new \UnexpectedValueException(); } $graph->addNode( new Node( $node['id'], $node['type'], $node['category'], $node['label'], $node['status'], $node['severity'], (array) $node['metadata'] ) ); } foreach ( $data['edges'] as $edge ) { if ( ! is_array( $edge ) || array_diff( array( 'id', 'source', 'target', 'relationship', 'confidence' ), array_keys( $edge ) ) ) { throw new \UnexpectedValueException(); } $graph->addEdge( new Edge( $edge['id'], $edge['source'], $edge['target'], $edge['relationship'], $edge['confidence'], (array) ( $edge['metadata'] ?? array() ) ) ); } return array( 'graph' => $graph, 'generated_at' => $payload['generated_at'] ); } catch ( \Throwable $error ) { $this->invalidate(); return null; } } public function set( Graph $graph ): int { $generated_at = time(); set_transient( $this->key(), array( 'schema' => 1, 'generated_at' => $generated_at, 'graph' => $graph->jsonSerialize() ), self::TTL ); return $generated_at; } public function invalidate( ...$unused ): void { delete_transient( $this->key() ); } public function registerInvalidationHooks(): void { foreach ( array( 'activated_plugin', 'deactivated_plugin', 'switch_theme', 'upgrader_process_complete', 'update_option_active_plugins', 'update_site_option_active_sitewide_plugins' ) as $hook ) { add_action( $hook, array( $this, 'invalidate' ) ); } } private function key(): string { if ( ! is_multisite() ) { return self::KEY; } $network_plugins = get_site_option( 'active_sitewide_plugins', array() ); $network_plugins = is_array( $network_plugins ) ? $network_plugins : array(); ksort( $network_plugins ); return self::KEY . '_' . md5( wp_json_encode( $network_plugins ) ); } }