type (core|plugin|mu-plugin|theme|unknown), slug, name, routes, ai. */ public static function namespaces() { $server = rest_get_server(); $settings = ThreeDoor_Settings::get(); $votes = array(); $routes = array(); foreach ( $server->get_namespaces() as $ns ) { $votes[ $ns ] = array(); $routes[ $ns ] = 0; } foreach ( $server->get_routes() as $route => $handlers ) { $options = $server->get_route_options( $route ); $ns = isset( $options['namespace'] ) ? (string) $options['namespace'] : ''; if ( '' === $ns || ! isset( $routes[ $ns ] ) ) { continue; } // The namespace index is served by core for every namespace and says nothing about its owner. if ( '/' . $ns === $route ) { continue; } $routes[ $ns ]++; foreach ( (array) $handlers as $handler ) { if ( ! is_array( $handler ) || empty( $handler['callback'] ) ) { continue; } $file = self::file_of( $handler['callback'] ); if ( $file ) { $key = wp_json_encode( self::classify( $file ) ); $votes[ $ns ][ $key ] = isset( $votes[ $ns ][ $key ] ) ? $votes[ $ns ][ $key ] + 1 : 1; } } } $result = array(); foreach ( $routes as $ns => $count ) { $origin = array( 'type' => 'unknown', 'slug' => '' ); if ( ! empty( $votes[ $ns ] ) ) { arsort( $votes[ $ns ] ); $origin = json_decode( (string) key( $votes[ $ns ] ), true ); } $result[ $ns ] = array( 'type' => $origin['type'], 'slug' => $origin['slug'], 'name' => self::name_of( $origin['type'], $origin['slug'] ), 'routes' => $count, 'ai' => ThreeDoor_Rules::is_ai( '/' . $ns, $settings ), ); } ksort( $result ); return $result; } /** * File that defines a callback. * * @param mixed $callback Callback. * @return string */ private static function file_of( $callback ) { try { if ( is_string( $callback ) && false !== strpos( $callback, '::' ) ) { $callback = explode( '::', $callback, 2 ); } if ( is_array( $callback ) && 2 === count( $callback ) ) { $ref = new ReflectionMethod( $callback[0], (string) $callback[1] ); } elseif ( $callback instanceof Closure || is_string( $callback ) ) { $ref = new ReflectionFunction( $callback ); } elseif ( is_object( $callback ) && method_exists( $callback, '__invoke' ) ) { $ref = new ReflectionMethod( $callback, '__invoke' ); } else { return ''; } $file = $ref->getFileName(); return $file ? wp_normalize_path( (string) $file ) : ''; } catch ( ReflectionException $e ) { return ''; } } /** * Classify a file path. * * @param string $file File. * @return array type, slug. */ private static function classify( $file ) { $places = array( 'plugin' => wp_normalize_path( WP_PLUGIN_DIR ) . '/', 'mu-plugin' => wp_normalize_path( WPMU_PLUGIN_DIR ) . '/', 'theme' => wp_normalize_path( get_theme_root() ) . '/', ); foreach ( $places as $type => $base ) { if ( 0 === strpos( $file, $base ) ) { $rest = substr( $file, strlen( $base ) ); $slug = strtok( $rest, '/' ); return array( 'type' => $type, 'slug' => false === $slug ? '' : $slug ); } } $abspath = wp_normalize_path( ABSPATH ); if ( 0 === strpos( $file, $abspath . WPINC . '/' ) || 0 === strpos( $file, $abspath . 'wp-admin/' ) ) { return array( 'type' => 'core', 'slug' => '' ); } return array( 'type' => 'unknown', 'slug' => '' ); } /** * Readable name of an origin. * * @param string $type Type. * @param string $slug Slug (folder or file name). * @return string */ private static function name_of( $type, $slug ) { if ( 'core' === $type ) { return 'WordPress'; } if ( 'plugin' === $type ) { if ( ! function_exists( 'get_plugins' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } foreach ( get_plugins() as $file => $data ) { if ( 0 === strpos( $file, $slug . '/' ) || $file === $slug ) { return (string) $data['Name']; } } } if ( 'theme' === $type ) { $theme = wp_get_theme( $slug ); if ( $theme->exists() ) { return (string) $theme->get( 'Name' ); } } return (string) $slug; } }