*/ public static function roots(): array { $roots = array(); if ( defined( 'WPMU_PLUGIN_DIR' ) ) { $roots[] = array( 'type' => 'mu-plugin', 'path' => (string) WPMU_PLUGIN_DIR, ); } if ( defined( 'WP_PLUGIN_DIR' ) ) { $roots[] = array( 'type' => 'plugin', 'path' => (string) WP_PLUGIN_DIR, ); } if ( function_exists( 'get_stylesheet_directory' ) ) { $roots[] = array( 'type' => 'theme', 'path' => (string) get_stylesheet_directory(), ); } return $roots; } /** * Classify an absolute callback/source file path. * * @return array */ public static function from_absolute_file( string $file ): array { if ( '' === $file ) { return array(); } $file_real = realpath( $file ); $normalized = str_replace( '\\', '/', false !== $file_real ? $file_real : $file ); foreach ( self::roots() as $root ) { $root_real = realpath( $root['path'] ); $root_path = rtrim( str_replace( '\\', '/', false !== $root_real ? $root_real : $root['path'] ), '/' ); if ( '' === $root_path || ! str_starts_with( $normalized, $root_path . '/' ) ) { continue; } $relative = ltrim( substr( $normalized, strlen( $root_path ) ), '/' ); return array( 'type' => $root['type'], 'slug' => self::slug_from_relative_path( $relative, $root['type'] ), 'path' => $relative, ); } if ( defined( 'ABSPATH' ) ) { $root_path = rtrim( str_replace( '\\', '/', (string) ABSPATH ), '/' ); if ( str_starts_with( $normalized, $root_path . '/wp-includes/' ) || str_starts_with( $normalized, $root_path . '/wp-admin/' ) ) { return array( 'type' => 'core', 'slug' => 'wordpress', 'path' => ltrim( substr( $normalized, strlen( $root_path ) ), '/' ), ); } } return array( 'type' => 'unknown', 'slug' => '', 'path' => basename( $normalized ), ); } public static function slug_from_relative_path( string $relative, string $type ): string { $first = strtok( $relative, '/' ); if ( false === $first ) { return ''; } if ( 'mu-plugin' === $type && ! str_contains( $relative, '/' ) ) { return preg_replace( '/\.php$/i', '', (string) $first ) ?? (string) $first; } return (string) $first; } }