1 && substr( $file, -strlen( $tail ) ) === $tail ) { return substr( $file, 0, -strlen( $tail ) ); } } return dirname( $file, 2 ); } /** * The URL the plugins directory is served from, no trailing slash. * * Derived from this plugin's own URL (plugins_url() relative to the main file), * so it follows a relocated or renamed plugins directory. Used only to recognise * plugin asset URLs and to test whether the directory lists its contents; never * to locate one of our own files. * * @return string */ public static function plugins_url_base(): string { return dirname( untrailingslashit( plugins_url( '', CSDT_PLUGIN_FILE ) ) ); } /** * The content directory (the parent of the plugins directory), no trailing slash. * * Used to locate core-defined siblings of the plugins directory that have no * accessor of their own: drop-ins such as object-cache.php, the upgrade/ tree, * and the default debug.log location. Never used for writing plugin data; that * goes under wp_upload_dir(). * * @since 1.10.837 * @return string */ public static function content_dir(): string { // The content directory itself, not dirname( plugins_dir() ): a site that relocates // its plugins directory outside the content directory (a documented WordPress // arrangement) would otherwise be told its uploads, mu-plugins and drop-ins // live beside the plugins, and every path built from here would be wrong. if ( defined( 'WP_CONTENT_DIR' ) && '' !== (string) WP_CONTENT_DIR ) { return rtrim( (string) WP_CONTENT_DIR, '/\\' ); } return dirname( self::plugins_dir() ); } /** * The must-use plugins directory, no trailing slash. * * If any mu-plugin is installed, its real directory is taken from * wp_get_mu_plugins(), core's own listing. Otherwise the default sibling of * the plugins directory is returned. * * @since 1.10.837 * @return string */ public static function mu_plugins_dir(): string { if ( function_exists( 'wp_get_mu_plugins' ) ) { $mu = wp_get_mu_plugins(); if ( ! empty( $mu[0] ) && is_string( $mu[0] ) ) { return dirname( self::slash( $mu[0] ) ); } } return self::content_dir() . '/mu-plugins'; } /** * The languages directory, no trailing slash. * * @since 1.10.837 * @return string */ public static function lang_dir(): string { return self::content_dir() . '/languages'; } /** * The WordPress install root (where wp-load.php lives), no trailing slash. * * The single read of the core constant in this plugin; see the file header. * * @since 1.10.837 * @return string */ public static function site_root(): string { return rtrim( self::slash( (string) ABSPATH ), '/' ); } /** * A file inside the install root. * * @since 1.10.837 * @param string $rel Path relative to the root, no leading slash. * @return string */ public static function root_file( string $rel ): string { return self::site_root() . '/' . ltrim( $rel, '/' ); } /** * Where wp-config.php actually is. * * Mirrors core's own rule in wp-load.php: the root first, then one level up * when that level is not itself a WordPress install. Earlier code assumed the * root and silently reported "missing" on the documented parent-directory * layout. * * @since 1.10.837 * @return string Absolute path. Not guaranteed to exist; callers must check. */ public static function wp_config_path(): string { $root = self::site_root(); if ( file_exists( $root . '/wp-config.php' ) ) { return $root . '/wp-config.php'; } $parent = dirname( $root ); if ( file_exists( $parent . '/wp-config.php' ) && ! file_exists( $parent . '/wp-settings.php' ) ) { return $parent . '/wp-config.php'; } return $root . '/wp-config.php'; } /** * A path relative to the install root, for display. * * @since 1.10.837 * @param string $abs Absolute path. * @return string The path with the root removed, or unchanged when outside it. */ public static function relative_to_root( string $abs ): string { $abs = self::slash( $abs ); $root = self::site_root() . '/'; if ( 0 === strpos( $abs, $root ) ) { return substr( $abs, strlen( $root ) ); } return $abs; } } }