WordPress.org

Make WordPress Core

Ticket #28441: wp-plugin-paths.php

File wp-plugin-paths.php, 2.8 KB (added by jdgrimes, 6 years ago)

Example solution, implmented as a static class

Line 
1<?php
2
3/**
4 * Store and resolve plugin paths.
5 *
6 * Used to make symlinked plugins work correctly.
7 *
8 * @since 4.2.0
9 */
10final class WP_Plugin_Paths {
11
12        /**
13         * The path to the plugins directory.
14         *
15         * @since 4.2.0
16         *
17         * @var string
18         */
19        private static $plugins_dir;
20
21        /**
22         * The registered plugin paths.
23         *
24         * Each element has the following keys:
25         * - 'plugin_path' The path to the plugin directory.
26         * - 'plugin_realpath' The path to the plugin directory, with symlinks resolved.
27         * - 'realpath_length' The string length of the realpath.
28         *
29         * @since 4.2.0
30         *
31         * @var array
32         */
33        private static $paths = array();
34
35        /**
36         * Whether the paths have been sorted.
37         *
38         * Saves us from sorting them multiple times.
39         *
40         * @since 4.2.0
41         *
42         * @var bool $paths_sorted
43         */
44        private static $paths_sorted = false;
45
46        /**
47         * Register a plugin's real path.
48         *
49         * The real path is used to resolve symlinked plugins.
50         *
51         * Single-file plugin's symlinks aren't resolved, because they don't include any
52         * assets, so they have no need to get the URL relative to themselves.
53         *
54         * @since 4.2.0
55         *
56         * @param string $file The known path to the plugin's main file.
57         *
58         * @return bool Whether the path was able to be registered.
59         */
60        public static function register( $file ) {
61
62                $file = wp_normalize_path( $file );
63
64                // We store this so that we don't have to keep normalizing a constant value.
65                if ( ! isset( self::$plugins_dir ) ) {
66                        self::$plugins_dir = wp_normalize_path( WP_PLUGINS_DIR );
67                }
68
69                $plugin_path = wp_normalize_path( dirname( $file ) );
70
71                // It was a single-file plugin.
72                if ( $plugin_path . '/' === self::$plugins_dir ) {
73                        return false;
74                }
75
76                $plugin_realpath = wp_normalize_path( dirname( realpath( $file ) ) );
77
78                if ( $plugin_path !== $plugin_realpath ) {
79
80                        $realpath_length = strlen( $plugin_realpath );
81
82                        // Use unique keys, but still easy to sort by realpath length.
83                        self::$paths[ $realpath_length . '-' . $plugin_path ] = array(
84                                'plugin_path'     => $plugin_path,
85                                'plugin_realpath' => $plugin_realpath,
86                                'realpath_length' => $realpath_length,
87                        );
88
89                        self::$paths_sorted = false;
90                }
91
92                return true;
93        }
94
95        /**
96         * Reverse resolve a plugin symlink path from the realpath.
97         *
98         * @since 4.2.0
99         *
100         * @param string $file The real path of the main plugin file.
101         *
102         * @return string The path to the symlink in the plugins directory.
103         */
104        public static function resolve( $file ) {
105
106                $file = wp_normalize_path( $file );
107
108                // Sort the paths by the realpath length, see https://core.trac.wordpress.org/ticket/28441.
109                if ( ! self::$paths_sorted ) {
110                        krsort( self::$paths );
111                        self::$paths_sorted = true;
112                }
113
114                foreach ( self::$paths as $path ) {
115                        if ( 0 === strpos( $file, $path['plugin_realpath'] ) ) {
116                                $file = $path['plugin_path'] . substr( $file, $path['realpath_length'] );
117                        }
118                }
119
120                return $file;
121        }
122}