$routes REST server route map. * @return array> */ public static function flatten( array $routes ): array { $out = array(); foreach ( $routes as $route => $handlers ) { if ( self::is_sensitive_route( (string) $route ) ) { continue; } $methods = array(); $callbacks = array(); $owners = array(); foreach ( is_array( $handlers ) ? $handlers : array() as $handler ) { if ( ! is_array( $handler ) || ! isset( $handler['methods'] ) ) { continue; } $value = $handler['methods']; if ( is_string( $value ) ) { $methods = array_merge( $methods, array_map( 'trim', explode( '|', $value ) ) ); } elseif ( is_array( $value ) ) { foreach ( $value as $method => $enabled ) { if ( is_string( $method ) && $enabled ) { $methods[] = $method; } elseif ( is_scalar( $enabled ) ) { $methods[] = (string) $enabled; } } } if ( isset( $handler['callback'] ) ) { $callbacks[] = self::callback_label( $handler['callback'] ); $owner = self::callback_owner( $handler['callback'] ); if ( array() !== $owner ) { $owners[ (string) wp_json_encode( $owner ) ] = $owner; } } } $methods = array_values( array_unique( array_filter( array_map( 'strtoupper', $methods ) ) ) ); $callbacks = array_values( array_unique( array_filter( $callbacks ) ) ); sort( $methods ); $out[] = array( 'route' => (string) $route, 'methods' => $methods, 'callbacks' => array_slice( $callbacks, 0, 8 ), 'owners' => array_values( $owners ), ); } usort( $out, static fn ( array $a, array $b ): int => strcmp( $a['route'], $b['route'] ) ); return $out; } private static function is_sensitive_route( string $route ): bool { foreach ( self::SENSITIVE_ROUTE_PATTERNS as $pattern ) { if ( preg_match( $pattern, $route ) ) { return true; } } return false; } private static function callback_label( $callback ): string { if ( is_string( $callback ) ) { return $callback; } if ( is_array( $callback ) && isset( $callback[0], $callback[1] ) ) { $owner = is_object( $callback[0] ) ? get_class( $callback[0] ) : (string) $callback[0]; return $owner . '::' . (string) $callback[1]; } if ( $callback instanceof \Closure ) { return 'closure'; } if ( is_object( $callback ) && method_exists( $callback, '__invoke' ) ) { return get_class( $callback ) . '::__invoke'; } return ''; } private static function callback_owner( $callback ): array { $file = self::callback_file( $callback ); if ( '' === $file ) { return array(); } return CodeOwnerEvidence::from_absolute_file( $file ); } private static function callback_file( $callback ): string { try { if ( is_string( $callback ) && function_exists( $callback ) ) { return (string) ( new \ReflectionFunction( $callback ) )->getFileName(); } if ( $callback instanceof \Closure ) { return (string) ( new \ReflectionFunction( $callback ) )->getFileName(); } if ( is_array( $callback ) && isset( $callback[0], $callback[1] ) ) { return (string) ( new \ReflectionMethod( $callback[0], (string) $callback[1] ) )->getFileName(); } if ( is_object( $callback ) && method_exists( $callback, '__invoke' ) ) { return (string) ( new \ReflectionMethod( $callback, '__invoke' ) )->getFileName(); } } catch ( \ReflectionException ) { return ''; } return ''; } }