run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄class-wp-plugin-dependencies.php
1<?php
2/**
3 * WordPress Plugin Administration API: WP_Plugin_Dependencies class
4 *
5 * @package WordPress
6 * @subpackage Administration
7 * @since 6.5.0
8 */
9
10/**
11 * Core class for installing plugin dependencies.
12 *
13 * It is designed to add plugin dependencies as designated in the
14 * `Requires Plugins` header to a new view in the plugins install page.
15 */
16class WP_Plugin_Dependencies {
17
18 /**
19 * Holds 'get_plugins()'.
20 *
21 * @since 6.5.0
22 *
23 * @var array
24 */
25 protected static $plugins;
26
27 /**
28 * Holds plugin directory names to compare with cache.
29 *
30 * @since 6.5.0
31 *
32 * @var array
33 */
34 protected static $plugin_dirnames;
35
36 /**
37 * Holds sanitized plugin dependency slugs.
38 *
39 * Keyed on the dependent plugin's filepath,
40 * relative to the plugins directory.
41 *
42 * @since 6.5.0
43 *
44 * @var array
45 */
46 protected static $dependencies;
47
48 /**
49 * Holds an array of sanitized plugin dependency slugs.
50 *
51 * @since 6.5.0
52 *
53 * @var array
54 */
55 protected static $dependency_slugs;
56
57 /**
58 * Holds an array of dependent plugin slugs.
59 *
60 * Keyed on the dependent plugin's filepath,
61 * relative to the plugins directory.
62 *
63 * @since 6.5.0
64 *
65 * @var array
66 */
67 protected static $dependent_slugs;
68
69 /**
70 * Holds 'plugins_api()' data for plugin dependencies.
71 *
72 * @since 6.5.0
73 *
74 * @var array
75 */
76 protected static $dependency_api_data;
77
78 /**
79 * Holds plugin dependency filepaths, relative to the plugins directory.
80 *
81 * Keyed on the dependency's slug.
82 *
83 * @since 6.5.0
84 *
85 * @var string[]
86 */
87 protected static $dependency_filepaths;
88
89 /**
90 * An array of circular dependency pairings.
91 *
92 * @since 6.5.0
93 *
94 * @var array[]
95 */
96 protected static $circular_dependencies_pairs;
97
98 /**
99 * An array of circular dependency slugs.
100 *
101 * @since 6.5.0
102 *
103 * @var string[]
104 */
105 protected static $circular_dependencies_slugs;
106
107 /**
108 * Whether Plugin Dependencies have been initialized.
109 *
110 * @since 6.5.0
111 *
112 * @var bool
113 */
114 protected static $initialized = false;
115
116 /**
117 * Initializes by fetching plugin header and plugin API data.
118 *
119 * @since 6.5.0
120 */
121 public static function initialize() {
122 if ( false === self::$initialized ) {
123 self::read_dependencies_from_plugin_headers();
124 self::get_dependency_api_data();
125 self::$initialized = true;
126 }
127 }
128
129 /**
130 * Determines whether the plugin has plugins that depend on it.
131 *
132 * @since 6.5.0
133 *
134 * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
135 * @return bool Whether the plugin has plugins that depend on it.
136 */
137 public static function has_dependents( $plugin_file ) {
138 return in_array( self::convert_to_slug( $plugin_file ), (array) self::$dependency_slugs, true );
139 }
140
141 /**
142 * Determines whether the plugin has plugin dependencies.
143 *
144 * @since 6.5.0
145 *
146 * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
147 * @return bool Whether a plugin has plugin dependencies.
148 */
149 public static function has_dependencies( $plugin_file ) {
150 return isset( self::$dependencies[ $plugin_file ] );
151 }
152
153 /**
154 * Determines whether the plugin has active dependents.
155 *
156 * @since 6.5.0
157 *
158 * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
159 * @return bool Whether the plugin has active dependents.
160 */
161 public static function has_active_dependents( $plugin_file ) {
162 require_once ABSPATH . 'wp-admin/includes/plugin.php';
163
164 $dependents = self::get_dependents( self::convert_to_slug( $plugin_file ) );
165 foreach ( $dependents as $dependent ) {
166 if ( is_plugin_active( $dependent ) ) {
167 return true;
168 }
169 }
170
171 return false;
172 }
173
174 /**
175 * Gets filepaths of plugins that require the dependency.
176 *
177 * @since 6.5.0
178 *
179 * @param string $slug The dependency's slug.
180 * @return array An array of dependent plugin filepaths, relative to the plugins directory.
181 */
182 public static function get_dependents( $slug ) {
183 $dependents = array();
184
185 foreach ( (array) self::$dependencies as $dependent => $dependencies ) {
186 if ( in_array( $slug, $dependencies, true ) ) {
187 $dependents[] = $dependent;
188 }
189 }
190
191 return $dependents;
192 }
193
194 /**
195 * Gets the slugs of plugins that the dependent requires.
196 *
197 * @since 6.5.0
198 *
199 * @param string $plugin_file The dependent plugin's filepath, relative to the plugins directory.
200 * @return array An array of dependency plugin slugs.
201 */
202 public static function get_dependencies( $plugin_file ) {
203 if ( isset( self::$dependencies[ $plugin_file ] ) ) {
204 return self::$dependencies[ $plugin_file ];
205 }
206
207 return array();
208 }
209
210 /**
211 * Gets a dependent plugin's filepath.
212 *
213 * @since 6.5.0
214 *
215 * @param string $slug The dependent plugin's slug.
216 * @return string|false The dependent plugin's filepath, relative to the plugins directory,
217 * or false if the plugin has no dependencies.
218 */
219 public static function get_dependent_filepath( $slug ) {
220 $filepath = array_search( $slug, self::$dependent_slugs, true );
221
222 return $filepath ? $filepath : false;
223 }
224
225 /**
226 * Determines whether the plugin has unmet dependencies.
227 *
228 * @since 6.5.0
229 *
230 * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
231 * @return bool Whether the plugin has unmet dependencies.
232 */
233 public static function has_unmet_dependencies( $plugin_file ) {
234 if ( ! isset( self::$dependencies[ $plugin_file ] ) ) {
235 return false;
236 }
237
238 require_once ABSPATH . 'wp-admin/includes/plugin.php';
239
240 foreach ( self::$dependencies[ $plugin_file ] as $dependency ) {
241 $dependency_filepath = self::get_dependency_filepath( $dependency );
242
243 if ( false === $dependency_filepath || is_plugin_inactive( $dependency_filepath ) ) {
244 return true;
245 }
246 }
247
248 return false;
249 }
250
251 /**
252 * Determines whether the plugin has a circular dependency.
253 *
254 * @since 6.5.0
255 *
256 * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
257 * @return bool Whether the plugin has a circular dependency.
258 */
259 public static function has_circular_dependency( $plugin_file ) {
260 if ( ! is_array( self::$circular_dependencies_slugs ) ) {
261 self::get_circular_dependencies();
262 }
263
264 if ( ! empty( self::$circular_dependencies_slugs ) ) {
265 $slug = self::convert_to_slug( $plugin_file );
266
267 if ( in_array( $slug, self::$circular_dependencies_slugs, true ) ) {
268 return true;
269 }
270 }
271
272 return false;
273 }
274
275 /**
276 * Gets the names of plugins that require the plugin.
277 *
278 * @since 6.5.0
279 *
280 * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
281 * @return array An array of dependent names.
282 */
283 public static function get_dependent_names( $plugin_file ) {
284 $dependent_names = array();
285 $plugins = self::get_plugins();
286 $slug = self::convert_to_slug( $plugin_file );
287
288 foreach ( self::get_dependents( $slug ) as $dependent ) {
289 $dependent_names[ $dependent ] = $plugins[ $dependent ]['Name'];
290 }
291 sort( $dependent_names );
292
293 return $dependent_names;
294 }
295
296 /**
297 * Gets the names of plugins required by the plugin.
298 *
299 * @since 6.5.0
300 *
301 * @param string $plugin_file The dependent plugin's filepath, relative to the plugins directory.
302 * @return array An array of dependency names.
303 */
304 public static function get_dependency_names( $plugin_file ) {
305 $dependency_api_data = self::get_dependency_api_data();
306 $dependencies = self::get_dependencies( $plugin_file );
307 $plugins = self::get_plugins();
308
309 $dependency_names = array();
310 foreach ( $dependencies as $dependency ) {
311 // Use the name if it's available, otherwise fall back to the slug.
312 if ( isset( $dependency_api_data[ $dependency ]['name'] ) ) {
313 $name = $dependency_api_data[ $dependency ]['name'];
314 } else {
315 $dependency_filepath = self::get_dependency_filepath( $dependency );
316 if ( false !== $dependency_filepath ) {
317 $name = $plugins[ $dependency_filepath ]['Name'];
318 } else {
319 $name = $dependency;
320 }
321 }
322
323 $dependency_names[ $dependency ] = $name;
324 }
325
326 return $dependency_names;
327 }
328
329 /**
330 * Gets the filepath for a dependency, relative to the plugin's directory.
331 *
332 * @since 6.5.0
333 *
334 * @param string $slug The dependency's slug.
335 * @return string|false If installed, the dependency's filepath relative to the plugins directory, otherwise false.
336 */
337 public static function get_dependency_filepath( $slug ) {
338 $dependency_filepaths = self::get_dependency_filepaths();
339
340 if ( ! isset( $dependency_filepaths[ $slug ] ) ) {
341 return false;
342 }
343
344 return $dependency_filepaths[ $slug ];
345 }
346
347 /**
348 * Returns API data for the dependency.
349 *
350 * @since 6.5.0
351 *
352 * @param string $slug The dependency's slug.
353 * @return array|false The dependency's API data on success, otherwise false.
354 */
355 public static function get_dependency_data( $slug ) {
356 $dependency_api_data = self::get_dependency_api_data();
357
358 if ( isset( $dependency_api_data[ $slug ] ) ) {
359 return $dependency_api_data[ $slug ];
360 }
361
362 return false;
363 }
364
365 /**
366 * Displays an admin notice if dependencies are not installed.
367 *
368 * @since 6.5.0
369 */
370 public static function display_admin_notice_for_unmet_dependencies() {
371 if ( in_array( false, self::get_dependency_filepaths(), true ) ) {
372 $error_message = __( 'Some required plugins are missing or inactive.' );
373
374 if ( is_multisite() ) {
375 if ( current_user_can( 'manage_network_plugins' ) ) {
376 $error_message .= ' ' . sprintf(
377 /* translators: %s: Link to the network plugins page. */
378 __( '<a href="%s">Manage plugins</a>.' ),
379 esc_url( network_admin_url( 'plugins.php' ) )
380 );
381 } else {
382 $error_message .= ' ' . __( 'Please contact your network administrator.' );
383 }
384 } elseif ( 'plugins' !== get_current_screen()->base ) {
385 $error_message .= ' ' . sprintf(
386 /* translators: %s: Link to the plugins page. */
387 __( '<a href="%s">Manage plugins</a>.' ),
388 esc_url( admin_url( 'plugins.php' ) )
389 );
390 }
391
392 wp_admin_notice(
393 $error_message,
394 array(
395 'type' => 'warning',
396 )
397 );
398 }
399 }
400
401 /**
402 * Displays an admin notice if circular dependencies are installed.
403 *
404 * @since 6.5.0
405 */
406 public static function display_admin_notice_for_circular_dependencies() {
407 $circular_dependencies = self::get_circular_dependencies();
408 if ( ! empty( $circular_dependencies ) && count( $circular_dependencies ) > 1 ) {
409 $circular_dependencies = array_unique( $circular_dependencies, SORT_REGULAR );
410 $plugins = self::get_plugins();
411 $plugin_dirnames = self::get_plugin_dirnames();
412
413 // Build output lines.
414 $circular_dependency_lines = '';
415 foreach ( $circular_dependencies as $circular_dependency ) {
416 $first_filepath = $plugin_dirnames[ $circular_dependency[0] ];
417 $second_filepath = $plugin_dirnames[ $circular_dependency[1] ];
418 $circular_dependency_lines .= sprintf(
419 /* translators: 1: First plugin name, 2: Second plugin name. */
420 '<li>' . _x( '%1$s requires %2$s', 'The first plugin requires the second plugin.' ) . '</li>',
421 '<strong>' . esc_html( $plugins[ $first_filepath ]['Name'] ) . '</strong>',
422 '<strong>' . esc_html( $plugins[ $second_filepath ]['Name'] ) . '</strong>'
423 );
424 }
425
426 wp_admin_notice(
427 sprintf(
428 '<p>%1$s</p><ul>%2$s</ul><p>%3$s</p>',
429 __( 'These plugins cannot be activated because their requirements are invalid.' ),
430 $circular_dependency_lines,
431 __( 'Please contact the plugin authors for more information.' )
432 ),
433 array(
434 'type' => 'warning',
435 'paragraph_wrap' => false,
436 )
437 );
438 }
439 }
440
441 /**
442 * Checks plugin dependencies after a plugin is installed via AJAX.
443 *
444 * @since 6.5.0
445 */
446 public static function check_plugin_dependencies_during_ajax() {
447 check_ajax_referer( 'updates' );
448
449 if ( empty( $_POST['slug'] ) ) {
450 wp_send_json_error(
451 array(
452 'slug' => '',
453 'pluginName' => '',
454 'errorCode' => 'no_plugin_specified',
455 'errorMessage' => __( 'No plugin specified.' ),
456 )
457 );
458 }
459
460 $slug = sanitize_key( wp_unslash( $_POST['slug'] ) );
461 $status = array( 'slug' => $slug );
462
463 self::get_plugins();
464 self::get_plugin_dirnames();
465
466 if ( ! isset( self::$plugin_dirnames[ $slug ] ) ) {
467 $status['errorCode'] = 'plugin_not_installed';
468 $status['errorMessage'] = __( 'The plugin is not installed.' );
469 wp_send_json_error( $status );
470 }
471
472 $plugin_file = self::$plugin_dirnames[ $slug ];
473 $status['pluginName'] = self::$plugins[ $plugin_file ]['Name'];
474 $status['plugin'] = $plugin_file;
475
476 if ( current_user_can( 'activate_plugin', $plugin_file ) && is_plugin_inactive( $plugin_file ) ) {
477 $status['activateUrl'] = add_query_arg(
478 array(
479 '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $plugin_file ),
480 'action' => 'activate',
481 'plugin' => $plugin_file,
482 ),
483 is_multisite() ? network_admin_url( 'plugins.php' ) : admin_url( 'plugins.php' )
484 );
485 }
486
487 if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
488 $status['activateUrl'] = add_query_arg( array( 'networkwide' => 1 ), $status['activateUrl'] );
489 }
490
491 self::initialize();
492 $dependencies = self::get_dependencies( $plugin_file );
493 if ( empty( $dependencies ) ) {
494 $status['message'] = __( 'The plugin has no required plugins.' );
495 wp_send_json_success( $status );
496 }
497
498 require_once ABSPATH . 'wp-admin/includes/plugin.php';
499
500 $inactive_dependencies = array();
501 foreach ( $dependencies as $dependency ) {
502 if ( false === self::$plugin_dirnames[ $dependency ] || is_plugin_inactive( self::$plugin_dirnames[ $dependency ] ) ) {
503 $inactive_dependencies[] = $dependency;
504 }
505 }
506
507 if ( ! empty( $inactive_dependencies ) ) {
508 $inactive_dependency_names = array_map(
509 function ( $dependency ) {
510 if ( isset( self::$dependency_api_data[ $dependency ]['Name'] ) ) {
511 $inactive_dependency_name = self::$dependency_api_data[ $dependency ]['Name'];
512 } else {
513 $inactive_dependency_name = $dependency;
514 }
515 return $inactive_dependency_name;
516 },
517 $inactive_dependencies
518 );
519
520 $status['errorCode'] = 'inactive_dependencies';
521 $status['errorMessage'] = sprintf(
522 /* translators: %s: A list of inactive dependency plugin names. */
523 __( 'The following plugins must be activated first: %s.' ),
524 implode( ', ', $inactive_dependency_names )
525 );
526 $status['errorData'] = array_combine( $inactive_dependencies, $inactive_dependency_names );
527
528 wp_send_json_error( $status );
529 }
530
531 $status['message'] = __( 'All required plugins are installed and activated.' );
532 wp_send_json_success( $status );
533 }
534
535 /**
536 * Gets data for installed plugins.
537 *
538 * @since 6.5.0
539 *
540 * @return array An array of plugin data.
541 */
542 protected static function get_plugins() {
543 if ( is_array( self::$plugins ) ) {
544 return self::$plugins;
545 }
546
547 require_once ABSPATH . 'wp-admin/includes/plugin.php';
548 self::$plugins = get_plugins();
549
550 return self::$plugins;
551 }
552
553 /**
554 * Reads and stores dependency slugs from a plugin's 'Requires Plugins' header.
555 *
556 * @since 6.5.0
557 */
558 protected static function read_dependencies_from_plugin_headers() {
559 self::$dependencies = array();
560 self::$dependency_slugs = array();
561 self::$dependent_slugs = array();
562 $plugins = self::get_plugins();
563 foreach ( $plugins as $plugin => $header ) {
564 if ( '' === $header['RequiresPlugins'] ) {
565 continue;
566 }
567
568 $dependency_slugs = self::sanitize_dependency_slugs( $header['RequiresPlugins'] );
569 self::$dependencies[ $plugin ] = $dependency_slugs;
570 self::$dependency_slugs = array_merge( self::$dependency_slugs, $dependency_slugs );
571
572 $dependent_slug = self::convert_to_slug( $plugin );
573 self::$dependent_slugs[ $plugin ] = $dependent_slug;
574 }
575 self::$dependency_slugs = array_unique( self::$dependency_slugs );
576 }
577
578 /**
579 * Sanitizes slugs.
580 *
581 * @since 6.5.0
582 *
583 * @param string $slugs A comma-separated string of plugin dependency slugs.
584 * @return array An array of sanitized plugin dependency slugs.
585 */
586 protected static function sanitize_dependency_slugs( $slugs ) {
587 $sanitized_slugs = array();
588 $slugs = explode( ',', $slugs );
589
590 foreach ( $slugs as $slug ) {
591 $slug = trim( $slug );
592
593 /**
594 * Filters a plugin dependency's slug before matching to
595 * the WordPress.org slug format.
596 *
597 * Can be used to switch between free and premium plugin slugs, for example.
598 *
599 * @since 6.5.0
600 *
601 * @param string $slug The slug.
602 */
603 $slug = apply_filters( 'wp_plugin_dependencies_slug', $slug );
604
605 // Match to WordPress.org slug format.
606 if ( preg_match( '/^[a-z0-9]+(-[a-z0-9]+)*$/mu', $slug ) ) {
607 $sanitized_slugs[] = $slug;
608 }
609 }
610 $sanitized_slugs = array_unique( $sanitized_slugs );
611 sort( $sanitized_slugs );
612
613 return $sanitized_slugs;
614 }
615
616 /**
617 * Gets the filepath of installed dependencies.
618 * If a dependency is not installed, the filepath defaults to false.
619 *
620 * @since 6.5.0
621 *
622 * @return array An array of install dependencies filepaths, relative to the plugins directory.
623 */
624 protected static function get_dependency_filepaths() {
625 if ( is_array( self::$dependency_filepaths ) ) {
626 return self::$dependency_filepaths;
627 }
628
629 if ( null === self::$dependency_slugs ) {
630 return array();
631 }
632
633 self::$dependency_filepaths = array();
634
635 $plugin_dirnames = self::get_plugin_dirnames();
636 foreach ( self::$dependency_slugs as $slug ) {
637 if ( isset( $plugin_dirnames[ $slug ] ) ) {
638 self::$dependency_filepaths[ $slug ] = $plugin_dirnames[ $slug ];
639 continue;
640 }
641
642 self::$dependency_filepaths[ $slug ] = false;
643 }
644
645 return self::$dependency_filepaths;
646 }
647
648 /**
649 * Retrieves and stores dependency plugin data from the WordPress.org Plugin API.
650 *
651 * @since 6.5.0
652 *
653 * @global string $pagenow The filename of the current screen.
654 *
655 * @return array|void An array of dependency API data, or void on early exit.
656 */
657 protected static function get_dependency_api_data() {
658 global $pagenow;
659
660 if ( ! is_admin() || ( 'plugins.php' !== $pagenow && 'plugin-install.php' !== $pagenow ) ) {
661 return;
662 }
663
664 if ( is_array( self::$dependency_api_data ) ) {
665 return self::$dependency_api_data;
666 }
667
668 $plugins = self::get_plugins();
669 self::$dependency_api_data = (array) get_site_transient( 'wp_plugin_dependencies_plugin_data' );
670 foreach ( self::$dependency_slugs as $slug ) {
671 // Set transient for individual data, remove from self::$dependency_api_data if transient expired.
672 if ( ! get_site_transient( "wp_plugin_dependencies_plugin_timeout_{$slug}" ) ) {
673 unset( self::$dependency_api_data[ $slug ] );
674 set_site_transient( "wp_plugin_dependencies_plugin_timeout_{$slug}", true, 12 * HOUR_IN_SECONDS );
675 }
676
677 if ( isset( self::$dependency_api_data[ $slug ] ) ) {
678 if ( false === self::$dependency_api_data[ $slug ] ) {
679 $dependency_file = self::get_dependency_filepath( $slug );
680
681 if ( false === $dependency_file ) {
682 self::$dependency_api_data[ $slug ] = array( 'Name' => $slug );
683 } else {
684 self::$dependency_api_data[ $slug ] = array( 'Name' => $plugins[ $dependency_file ]['Name'] );
685 }
686 continue;
687 }
688
689 // Don't hit the Plugin API if data exists.
690 if ( ! empty( self::$dependency_api_data[ $slug ]['last_updated'] ) ) {
691 continue;
692 }
693 }
694
695 if ( ! function_exists( 'plugins_api' ) ) {
696 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
697 }
698
699 $information = plugins_api(
700 'plugin_information',
701 array(
702 'slug' => $slug,
703 'fields' => array(
704 'short_description' => true,
705 'icons' => true,
706 ),
707 )
708 );
709
710 if ( is_wp_error( $information ) ) {
711 continue;
712 }
713
714 self::$dependency_api_data[ $slug ] = (array) $information;
715 // plugins_api() returns 'name' not 'Name'.
716 self::$dependency_api_data[ $slug ]['Name'] = self::$dependency_api_data[ $slug ]['name'];
717 set_site_transient( 'wp_plugin_dependencies_plugin_data', self::$dependency_api_data, 0 );
718 }
719
720 // Remove from self::$dependency_api_data if slug no longer a dependency.
721 $differences = array_diff( array_keys( self::$dependency_api_data ), self::$dependency_slugs );
722 foreach ( $differences as $difference ) {
723 unset( self::$dependency_api_data[ $difference ] );
724 }
725
726 ksort( self::$dependency_api_data );
727 // Remove empty elements.
728 self::$dependency_api_data = array_filter( self::$dependency_api_data );
729 set_site_transient( 'wp_plugin_dependencies_plugin_data', self::$dependency_api_data, 0 );
730
731 return self::$dependency_api_data;
732 }
733
734 /**
735 * Gets plugin directory names.
736 *
737 * @since 6.5.0
738 *
739 * @return array An array of plugin directory names.
740 */
741 protected static function get_plugin_dirnames() {
742 if ( is_array( self::$plugin_dirnames ) ) {
743 return self::$plugin_dirnames;
744 }
745
746 self::$plugin_dirnames = array();
747
748 $plugin_files = array_keys( self::get_plugins() );
749 foreach ( $plugin_files as $plugin_file ) {
750 $slug = self::convert_to_slug( $plugin_file );
751 self::$plugin_dirnames[ $slug ] = $plugin_file;
752 }
753
754 return self::$plugin_dirnames;
755 }
756
757 /**
758 * Gets circular dependency data.
759 *
760 * @since 6.5.0
761 *
762 * @return array[] An array of circular dependency pairings.
763 */
764 protected static function get_circular_dependencies() {
765 if ( is_array( self::$circular_dependencies_pairs ) ) {
766 return self::$circular_dependencies_pairs;
767 }
768
769 if ( null === self::$dependencies ) {
770 return array();
771 }
772
773 self::$circular_dependencies_slugs = array();
774
775 self::$circular_dependencies_pairs = array();
776 foreach ( self::$dependencies as $dependent => $dependencies ) {
777 /*
778 * $dependent is in 'a/a.php' format. Dependencies are stored as slugs, i.e. 'a'.
779 *
780 * Convert $dependent to slug format for checking.
781 */
782 $dependent_slug = self::convert_to_slug( $dependent );
783
784 self::$circular_dependencies_pairs = array_merge(
785 self::$circular_dependencies_pairs,
786 self::check_for_circular_dependencies( array( $dependent_slug ), $dependencies )
787 );
788 }
789
790 return self::$circular_dependencies_pairs;
791 }
792
793 /**
794 * Checks for circular dependencies.
795 *
796 * @since 6.5.0
797 *
798 * @param array $dependents Array of dependent plugins.
799 * @param array $dependencies Array of plugins dependencies.
800 * @return array A circular dependency pairing, or an empty array if none exists.
801 */
802 protected static function check_for_circular_dependencies( $dependents, $dependencies ) {
803 $circular_dependencies_pairs = array();
804
805 // Check for a self-dependency.
806 $dependents_location_in_its_own_dependencies = array_intersect( $dependents, $dependencies );
807 if ( ! empty( $dependents_location_in_its_own_dependencies ) ) {
808 foreach ( $dependents_location_in_its_own_dependencies as $self_dependency ) {
809 self::$circular_dependencies_slugs[] = $self_dependency;
810 $circular_dependencies_pairs[] = array( $self_dependency, $self_dependency );
811
812 // No need to check for itself again.
813 unset( $dependencies[ array_search( $self_dependency, $dependencies, true ) ] );
814 }
815 }
816
817 /*
818 * Check each dependency to see:
819 * 1. If it has dependencies.
820 * 2. If its list of dependencies includes one of its own dependents.
821 */
822 foreach ( $dependencies as $dependency ) {
823 // Check if the dependency is also a dependent.
824 $dependency_location_in_dependents = array_search( $dependency, self::$dependent_slugs, true );
825
826 if ( false !== $dependency_location_in_dependents ) {
827 $dependencies_of_the_dependency = self::$dependencies[ $dependency_location_in_dependents ];
828
829 foreach ( $dependents as $dependent ) {
830 // Check if its dependencies includes one of its own dependents.
831 $dependent_location_in_dependency_dependencies = array_search(
832 $dependent,
833 $dependencies_of_the_dependency,
834 true
835 );
836
837 if ( false !== $dependent_location_in_dependency_dependencies ) {
838 self::$circular_dependencies_slugs[] = $dependent;
839 self::$circular_dependencies_slugs[] = $dependency;
840 $circular_dependencies_pairs[] = array( $dependent, $dependency );
841
842 // Remove the dependent from its dependency's dependencies.
843 unset( $dependencies_of_the_dependency[ $dependent_location_in_dependency_dependencies ] );
844 }
845 }
846
847 $dependents[] = $dependency;
848
849 /*
850 * Now check the dependencies of the dependency's dependencies for the dependent.
851 *
852 * Yes, that does make sense.
853 */
854 $circular_dependencies_pairs = array_merge(
855 $circular_dependencies_pairs,
856 self::check_for_circular_dependencies( $dependents, array_unique( $dependencies_of_the_dependency ) )
857 );
858 }
859 }
860
861 return $circular_dependencies_pairs;
862 }
863
864 /**
865 * Converts a plugin filepath to a slug.
866 *
867 * @since 6.5.0
868 *
869 * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
870 * @return string The plugin's slug.
871 */
872 protected static function convert_to_slug( $plugin_file ) {
873 if ( 'hello.php' === $plugin_file ) {
874 return 'hello-dolly';
875 }
876 return str_contains( $plugin_file, '/' ) ? dirname( $plugin_file ) : str_replace( '.php', '', $plugin_file );
877 }
878}
879
Ui Ux Design – Teachers Night Out

Get in Touch

© 2024 Teachers Night Out. All Rights Reserved.