changeset 7 | cf61fcea0001 |
parent 5 | 5e2f62d02dcd |
child 9 | 177826044cd9 |
6:490d5cc509ed | 7:cf61fcea0001 |
---|---|
2 /** |
2 /** |
3 * WP_Theme Class |
3 * WP_Theme Class |
4 * |
4 * |
5 * @package WordPress |
5 * @package WordPress |
6 * @subpackage Theme |
6 * @subpackage Theme |
7 * @since 3.4.0 |
|
7 */ |
8 */ |
8 |
|
9 final class WP_Theme implements ArrayAccess { |
9 final class WP_Theme implements ArrayAccess { |
10 |
10 |
11 /** |
11 /** |
12 * Whether the theme has been marked as updateable. |
|
13 * |
|
14 * @since 4.4.0 |
|
15 * @var bool |
|
16 * |
|
17 * @see WP_MS_Themes_List_Table |
|
18 */ |
|
19 public $update = false; |
|
20 |
|
21 /** |
|
12 * Headers for style.css files. |
22 * Headers for style.css files. |
13 * |
23 * |
14 * @static |
24 * @static |
15 * @access private |
|
16 * @var array |
25 * @var array |
17 */ |
26 */ |
18 private static $file_headers = array( |
27 private static $file_headers = array( |
19 'Name' => 'Theme Name', |
28 'Name' => 'Theme Name', |
20 'ThemeURI' => 'Theme URI', |
29 'ThemeURI' => 'Theme URI', |
31 |
40 |
32 /** |
41 /** |
33 * Default themes. |
42 * Default themes. |
34 * |
43 * |
35 * @static |
44 * @static |
36 * @access private |
|
37 * @var array |
45 * @var array |
38 */ |
46 */ |
39 private static $default_themes = array( |
47 private static $default_themes = array( |
40 'classic' => 'WordPress Classic', |
48 'classic' => 'WordPress Classic', |
41 'default' => 'WordPress Default', |
49 'default' => 'WordPress Default', |
42 'twentyten' => 'Twenty Ten', |
50 'twentyten' => 'Twenty Ten', |
43 'twentyeleven' => 'Twenty Eleven', |
51 'twentyeleven' => 'Twenty Eleven', |
44 'twentytwelve' => 'Twenty Twelve', |
52 'twentytwelve' => 'Twenty Twelve', |
45 'twentythirteen' => 'Twenty Thirteen', |
53 'twentythirteen' => 'Twenty Thirteen', |
46 'twentyfourteen' => 'Twenty Fourteen', |
54 'twentyfourteen' => 'Twenty Fourteen', |
47 'twentyfifteen' => 'Twenty Fifteen', |
55 'twentyfifteen' => 'Twenty Fifteen', |
56 'twentysixteen' => 'Twenty Sixteen', |
|
57 'twentyseventeen' => 'Twenty Seventeen', |
|
48 ); |
58 ); |
49 |
59 |
50 /** |
60 /** |
51 * Renamed theme tags. |
61 * Renamed theme tags. |
62 * |
|
63 * @static |
|
64 * @var array |
|
52 */ |
65 */ |
53 private static $tag_map = array( |
66 private static $tag_map = array( |
54 'fixed-width' => 'fixed-layout', |
67 'fixed-width' => 'fixed-layout', |
55 'flexible-width' => 'fluid-layout', |
68 'flexible-width' => 'fluid-layout', |
56 ); |
69 ); |
57 |
70 |
58 /** |
71 /** |
59 * Absolute path to the theme root, usually wp-content/themes |
72 * Absolute path to the theme root, usually wp-content/themes |
60 * |
73 * |
61 * @access private |
|
62 * @var string |
74 * @var string |
63 */ |
75 */ |
64 private $theme_root; |
76 private $theme_root; |
65 |
77 |
66 /** |
78 /** |
67 * Header data from the theme's style.css file. |
79 * Header data from the theme's style.css file. |
68 * |
80 * |
69 * @access private |
|
70 * @var array |
81 * @var array |
71 */ |
82 */ |
72 private $headers = array(); |
83 private $headers = array(); |
73 |
84 |
74 /** |
85 /** |
75 * Header data from the theme's style.css file after being sanitized. |
86 * Header data from the theme's style.css file after being sanitized. |
76 * |
87 * |
77 * @access private |
|
78 * @var array |
88 * @var array |
79 */ |
89 */ |
80 private $headers_sanitized; |
90 private $headers_sanitized; |
81 |
91 |
82 /** |
92 /** |
83 * Header name from the theme's style.css after being translated. |
93 * Header name from the theme's style.css after being translated. |
84 * |
94 * |
85 * Cached due to sorting functions running over the translated name. |
95 * Cached due to sorting functions running over the translated name. |
96 * |
|
97 * @var string |
|
86 */ |
98 */ |
87 private $name_translated; |
99 private $name_translated; |
88 |
100 |
89 /** |
101 /** |
90 * Errors encountered when initializing the theme. |
102 * Errors encountered when initializing the theme. |
91 * |
103 * |
92 * @access private |
|
93 * @var WP_Error |
104 * @var WP_Error |
94 */ |
105 */ |
95 private $errors; |
106 private $errors; |
96 |
107 |
97 /** |
108 /** |
98 * The directory name of the theme's files, inside the theme root. |
109 * The directory name of the theme's files, inside the theme root. |
99 * |
110 * |
100 * In the case of a child theme, this is directory name of the child theme. |
111 * In the case of a child theme, this is directory name of the child theme. |
101 * Otherwise, 'stylesheet' is the same as 'template'. |
112 * Otherwise, 'stylesheet' is the same as 'template'. |
102 * |
113 * |
103 * @access private |
|
104 * @var string |
114 * @var string |
105 */ |
115 */ |
106 private $stylesheet; |
116 private $stylesheet; |
107 |
117 |
108 /** |
118 /** |
109 * The directory name of the theme's files, inside the theme root. |
119 * The directory name of the theme's files, inside the theme root. |
110 * |
120 * |
111 * In the case of a child theme, this is the directory name of the parent theme. |
121 * In the case of a child theme, this is the directory name of the parent theme. |
112 * Otherwise, 'template' is the same as 'stylesheet'. |
122 * Otherwise, 'template' is the same as 'stylesheet'. |
113 * |
123 * |
114 * @access private |
|
115 * @var string |
124 * @var string |
116 */ |
125 */ |
117 private $template; |
126 private $template; |
118 |
127 |
119 /** |
128 /** |
120 * A reference to the parent theme, in the case of a child theme. |
129 * A reference to the parent theme, in the case of a child theme. |
121 * |
130 * |
122 * @access private |
|
123 * @var WP_Theme |
131 * @var WP_Theme |
124 */ |
132 */ |
125 private $parent; |
133 private $parent; |
126 |
134 |
127 /** |
135 /** |
128 * URL to the theme root, usually an absolute URL to wp-content/themes |
136 * URL to the theme root, usually an absolute URL to wp-content/themes |
129 * |
137 * |
130 * @access private |
138 * @var string |
131 * var string |
|
132 */ |
139 */ |
133 private $theme_root_uri; |
140 private $theme_root_uri; |
134 |
141 |
135 /** |
142 /** |
136 * Flag for whether the theme's textdomain is loaded. |
143 * Flag for whether the theme's textdomain is loaded. |
137 * |
144 * |
138 * @access private |
|
139 * @var bool |
145 * @var bool |
140 */ |
146 */ |
141 private $textdomain_loaded; |
147 private $textdomain_loaded; |
142 |
148 |
143 /** |
149 /** |
144 * Stores an md5 hash of the theme root, to function as the cache key. |
150 * Stores an md5 hash of the theme root, to function as the cache key. |
145 * |
151 * |
146 * @access private |
|
147 * @var string |
152 * @var string |
148 */ |
153 */ |
149 private $cache_hash; |
154 private $cache_hash; |
150 |
155 |
151 /** |
156 /** |
152 * Flag for whether the themes cache bucket should be persistently cached. |
157 * Flag for whether the themes cache bucket should be persistently cached. |
153 * |
158 * |
154 * Default is false. Can be set with the wp_cache_themes_persistently filter. |
159 * Default is false. Can be set with the {@see 'wp_cache_themes_persistently'} filter. |
155 * |
160 * |
156 * @access private |
161 * @static |
157 * @var bool |
162 * @var bool |
158 */ |
163 */ |
159 private static $persistently_cache; |
164 private static $persistently_cache; |
160 |
165 |
161 /** |
166 /** |
162 * Expiration time for the themes cache bucket. |
167 * Expiration time for the themes cache bucket. |
163 * |
168 * |
164 * By default the bucket is not cached, so this value is useless. |
169 * By default the bucket is not cached, so this value is useless. |
165 * |
170 * |
166 * @access private |
171 * @static |
167 * @var bool |
172 * @var bool |
168 */ |
173 */ |
169 private static $cache_expiration = 1800; |
174 private static $cache_expiration = 1800; |
170 |
175 |
171 /** |
176 /** |
172 * Constructor for WP_Theme. |
177 * Constructor for WP_Theme. |
178 * |
|
179 * @since 3.4.0 |
|
180 * |
|
181 * @global array $wp_theme_directories |
|
173 * |
182 * |
174 * @param string $theme_dir Directory of the theme within the theme_root. |
183 * @param string $theme_dir Directory of the theme within the theme_root. |
175 * @param string $theme_root Theme root. |
184 * @param string $theme_root Theme root. |
176 * @param WP_Error|null $_child If this theme is a parent theme, the child may be passed for validation purposes. |
185 * @param WP_Error|void $_child If this theme is a parent theme, the child may be passed for validation purposes. |
177 */ |
186 */ |
178 public function __construct( $theme_dir, $theme_root, $_child = null ) { |
187 public function __construct( $theme_dir, $theme_root, $_child = null ) { |
179 global $wp_theme_directories; |
188 global $wp_theme_directories; |
180 |
189 |
181 // Initialize caching on first run. |
190 // Initialize caching on first run. |
215 if ( isset( $cache['theme_root_template'] ) ) |
224 if ( isset( $cache['theme_root_template'] ) ) |
216 $theme_root_template = $cache['theme_root_template']; |
225 $theme_root_template = $cache['theme_root_template']; |
217 } elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) { |
226 } elseif ( ! file_exists( $this->theme_root . '/' . $theme_file ) ) { |
218 $this->headers['Name'] = $this->stylesheet; |
227 $this->headers['Name'] = $this->stylesheet; |
219 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) ) |
228 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet ) ) |
220 $this->errors = new WP_Error( 'theme_not_found', sprintf( __( 'The theme directory "%s" does not exist.' ), $this->stylesheet ) ); |
229 $this->errors = new WP_Error( 'theme_not_found', sprintf( __( 'The theme directory "%s" does not exist.' ), esc_html( $this->stylesheet ) ) ); |
221 else |
230 else |
222 $this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) ); |
231 $this->errors = new WP_Error( 'theme_no_stylesheet', __( 'Stylesheet is missing.' ) ); |
223 $this->template = $this->stylesheet; |
232 $this->template = $this->stylesheet; |
224 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
233 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
225 if ( ! file_exists( $this->theme_root ) ) // Don't cache this one. |
234 if ( ! file_exists( $this->theme_root ) ) // Don't cache this one. |
239 if ( basename( $this->stylesheet ) != $default_theme_slug ) |
248 if ( basename( $this->stylesheet ) != $default_theme_slug ) |
240 $this->headers['Name'] .= '/' . $this->stylesheet; |
249 $this->headers['Name'] .= '/' . $this->stylesheet; |
241 } |
250 } |
242 } |
251 } |
243 |
252 |
253 if ( ! $this->template && $this->stylesheet === $this->headers['Template'] ) { |
|
254 /* translators: %s: Template */ |
|
255 $this->errors = new WP_Error( 'theme_child_invalid', sprintf( __( 'The theme defines itself as its parent theme. Please check the %s header.' ), '<code>Template</code>' ) ); |
|
256 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet ) ); |
|
257 |
|
258 return; |
|
259 } |
|
260 |
|
244 // (If template is set from cache [and there are no errors], we know it's good.) |
261 // (If template is set from cache [and there are no errors], we know it's good.) |
245 if ( ! $this->template && ! ( $this->template = $this->headers['Template'] ) ) { |
262 if ( ! $this->template && ! ( $this->template = $this->headers['Template'] ) ) { |
246 $this->template = $this->stylesheet; |
263 $this->template = $this->stylesheet; |
247 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet . '/index.php' ) ) { |
264 if ( ! file_exists( $this->theme_root . '/' . $this->stylesheet . '/index.php' ) ) { |
248 $this->errors = new WP_Error( 'theme_no_index', __( 'Template is missing.' ) ); |
265 $error_message = sprintf( |
266 /* translators: 1: index.php, 2: Codex URL, 3: style.css */ |
|
267 __( 'Template is missing. Standalone themes need to have a %1$s template file. <a href="%2$s">Child themes</a> need to have a Template header in the %3$s stylesheet.' ), |
|
268 '<code>index.php</code>', |
|
269 __( 'https://codex.wordpress.org/Child_Themes' ), |
|
270 '<code>style.css</code>' |
|
271 ); |
|
272 $this->errors = new WP_Error( 'theme_no_index', $error_message ); |
|
249 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
273 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
250 return; |
274 return; |
251 } |
275 } |
252 } |
276 } |
253 |
277 |
262 // Look for the template in the search_theme_directories() results, in case it is in another theme root. |
286 // Look for the template in the search_theme_directories() results, in case it is in another theme root. |
263 // We don't look into directories of themes, just the theme root. |
287 // We don't look into directories of themes, just the theme root. |
264 $theme_root_template = $directories[ $this->template ]['theme_root']; |
288 $theme_root_template = $directories[ $this->template ]['theme_root']; |
265 } else { |
289 } else { |
266 // Parent theme is missing. |
290 // Parent theme is missing. |
267 $this->errors = new WP_Error( 'theme_no_parent', sprintf( __( 'The parent theme is missing. Please install the "%s" parent theme.' ), $this->template ) ); |
291 $this->errors = new WP_Error( 'theme_no_parent', sprintf( __( 'The parent theme is missing. Please install the "%s" parent theme.' ), esc_html( $this->template ) ) ); |
268 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
292 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
269 $this->parent = new WP_Theme( $this->template, $this->theme_root, $this ); |
293 $this->parent = new WP_Theme( $this->template, $this->theme_root, $this ); |
270 return; |
294 return; |
271 } |
295 } |
272 } |
296 } |
274 // Set the parent, if we're a child theme. |
298 // Set the parent, if we're a child theme. |
275 if ( $this->template != $this->stylesheet ) { |
299 if ( $this->template != $this->stylesheet ) { |
276 // If we are a parent, then there is a problem. Only two generations allowed! Cancel things out. |
300 // If we are a parent, then there is a problem. Only two generations allowed! Cancel things out. |
277 if ( $_child instanceof WP_Theme && $_child->template == $this->stylesheet ) { |
301 if ( $_child instanceof WP_Theme && $_child->template == $this->stylesheet ) { |
278 $_child->parent = null; |
302 $_child->parent = null; |
279 $_child->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), $_child->template ) ); |
303 $_child->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $_child->template ) ) ); |
280 $_child->cache_add( 'theme', array( 'headers' => $_child->headers, 'errors' => $_child->errors, 'stylesheet' => $_child->stylesheet, 'template' => $_child->template ) ); |
304 $_child->cache_add( 'theme', array( 'headers' => $_child->headers, 'errors' => $_child->errors, 'stylesheet' => $_child->stylesheet, 'template' => $_child->template ) ); |
281 // The two themes actually reference each other with the Template header. |
305 // The two themes actually reference each other with the Template header. |
282 if ( $_child->stylesheet == $this->template ) { |
306 if ( $_child->stylesheet == $this->template ) { |
283 $this->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), $this->template ) ); |
307 $this->errors = new WP_Error( 'theme_parent_invalid', sprintf( __( 'The "%s" theme is not a valid parent theme.' ), esc_html( $this->template ) ) ); |
284 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
308 $this->cache_add( 'theme', array( 'headers' => $this->headers, 'errors' => $this->errors, 'stylesheet' => $this->stylesheet, 'template' => $this->template ) ); |
285 } |
309 } |
286 return; |
310 return; |
287 } |
311 } |
288 // Set the parent. Pass the current instance so we can do the crazy checks above and assess errors. |
312 // Set the parent. Pass the current instance so we can do the crazy checks above and assess errors. |
300 } |
324 } |
301 |
325 |
302 /** |
326 /** |
303 * When converting the object to a string, the theme name is returned. |
327 * When converting the object to a string, the theme name is returned. |
304 * |
328 * |
329 * @since 3.4.0 |
|
330 * |
|
305 * @return string Theme name, ready for display (translated) |
331 * @return string Theme name, ready for display (translated) |
306 */ |
332 */ |
307 public function __toString() { |
333 public function __toString() { |
308 return (string) $this->display('Name'); |
334 return (string) $this->display('Name'); |
309 } |
335 } |
310 |
336 |
311 /** |
337 /** |
312 * __isset() magic method for properties formerly returned by current_theme_info() |
338 * __isset() magic method for properties formerly returned by current_theme_info() |
339 * |
|
340 * @staticvar array $properties |
|
341 * |
|
342 * @since 3.4.0 |
|
343 * |
|
344 * @param string $offset Property to check if set. |
|
345 * @return bool Whether the given property is set. |
|
313 */ |
346 */ |
314 public function __isset( $offset ) { |
347 public function __isset( $offset ) { |
315 static $properties = array( |
348 static $properties = array( |
316 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', |
349 'name', 'title', 'version', 'parent_theme', 'template_dir', 'stylesheet_dir', 'template', 'stylesheet', |
317 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', |
350 'screenshot', 'description', 'author', 'tags', 'theme_root', 'theme_root_uri', |
320 return in_array( $offset, $properties ); |
353 return in_array( $offset, $properties ); |
321 } |
354 } |
322 |
355 |
323 /** |
356 /** |
324 * __get() magic method for properties formerly returned by current_theme_info() |
357 * __get() magic method for properties formerly returned by current_theme_info() |
358 * |
|
359 * @since 3.4.0 |
|
360 * |
|
361 * @param string $offset Property to get. |
|
362 * @return mixed Property value. |
|
325 */ |
363 */ |
326 public function __get( $offset ) { |
364 public function __get( $offset ) { |
327 switch ( $offset ) { |
365 switch ( $offset ) { |
328 case 'name' : |
366 case 'name' : |
329 case 'title' : |
367 case 'title' : |
359 } |
397 } |
360 } |
398 } |
361 |
399 |
362 /** |
400 /** |
363 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
401 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
402 * |
|
403 * @since 3.4.0 |
|
404 * |
|
405 * @param mixed $offset |
|
406 * @param mixed $value |
|
364 */ |
407 */ |
365 public function offsetSet( $offset, $value ) {} |
408 public function offsetSet( $offset, $value ) {} |
366 |
409 |
367 /** |
410 /** |
368 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
411 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
412 * |
|
413 * @since 3.4.0 |
|
414 * |
|
415 * @param mixed $offset |
|
369 */ |
416 */ |
370 public function offsetUnset( $offset ) {} |
417 public function offsetUnset( $offset ) {} |
371 |
418 |
372 /** |
419 /** |
373 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
420 * Method to implement ArrayAccess for keys formerly returned by get_themes() |
421 * |
|
422 * @staticvar array $keys |
|
423 * |
|
424 * @since 3.4.0 |
|
425 * |
|
426 * @param mixed $offset |
|
427 * @return bool |
|
374 */ |
428 */ |
375 public function offsetExists( $offset ) { |
429 public function offsetExists( $offset ) { |
376 static $keys = array( |
430 static $keys = array( |
377 'Name', 'Version', 'Status', 'Title', 'Author', 'Author Name', 'Author URI', 'Description', |
431 'Name', 'Version', 'Status', 'Title', 'Author', 'Author Name', 'Author URI', 'Description', |
378 'Template', 'Stylesheet', 'Template Files', 'Stylesheet Files', 'Template Dir', 'Stylesheet Dir', |
432 'Template', 'Stylesheet', 'Template Files', 'Stylesheet Files', 'Template Dir', 'Stylesheet Dir', |
379 'Screenshot', 'Tags', 'Theme Root', 'Theme Root URI', 'Parent Theme', |
433 'Screenshot', 'Tags', 'Theme Root', 'Theme Root URI', 'Parent Theme', |
380 ); |
434 ); |
381 |
435 |
382 return in_array( $offset, $keys ); |
436 return in_array( $offset, $keys ); |
383 } |
437 } |
384 |
438 |
387 * |
441 * |
388 * Author, Author Name, Author URI, and Description did not previously return |
442 * Author, Author Name, Author URI, and Description did not previously return |
389 * translated data. We are doing so now as it is safe to do. However, as |
443 * translated data. We are doing so now as it is safe to do. However, as |
390 * Name and Title could have been used as the key for get_themes(), both remain |
444 * Name and Title could have been used as the key for get_themes(), both remain |
391 * untranslated for back compatibility. This means that ['Name'] is not ideal, |
445 * untranslated for back compatibility. This means that ['Name'] is not ideal, |
392 * and care should be taken to use $theme->display('Name') to get a properly |
446 * and care should be taken to use `$theme::display( 'Name' )` to get a properly |
393 * translated header. |
447 * translated header. |
448 * |
|
449 * @since 3.4.0 |
|
450 * |
|
451 * @param mixed $offset |
|
452 * @return mixed |
|
394 */ |
453 */ |
395 public function offsetGet( $offset ) { |
454 public function offsetGet( $offset ) { |
396 switch ( $offset ) { |
455 switch ( $offset ) { |
397 case 'Name' : |
456 case 'Name' : |
398 case 'Title' : |
457 case 'Title' : |
399 // See note above about using translated data. get() is not ideal. |
458 /* |
400 // It is only for backwards compatibility. Use display(). |
459 * See note above about using translated data. get() is not ideal. |
460 * It is only for backward compatibility. Use display(). |
|
461 */ |
|
401 return $this->get('Name'); |
462 return $this->get('Name'); |
402 case 'Author' : |
463 case 'Author' : |
403 return $this->display( 'Author'); |
464 return $this->display( 'Author'); |
404 case 'Author Name' : |
465 case 'Author Name' : |
405 return $this->display( 'Author', false); |
466 return $this->display( 'Author', false); |
439 |
500 |
440 /** |
501 /** |
441 * Returns errors property. |
502 * Returns errors property. |
442 * |
503 * |
443 * @since 3.4.0 |
504 * @since 3.4.0 |
444 * @access public |
505 * |
445 * |
506 * @return WP_Error|false WP_Error if there are errors, or false. |
446 * @return WP_Error|bool WP_Error if there are errors, or false. |
|
447 */ |
507 */ |
448 public function errors() { |
508 public function errors() { |
449 return is_wp_error( $this->errors ) ? $this->errors : false; |
509 return is_wp_error( $this->errors ) ? $this->errors : false; |
450 } |
510 } |
451 |
511 |
454 * |
514 * |
455 * A theme with errors exists. A theme with the error of 'theme_not_found', |
515 * A theme with errors exists. A theme with the error of 'theme_not_found', |
456 * meaning that the theme's directory was not found, does not exist. |
516 * meaning that the theme's directory was not found, does not exist. |
457 * |
517 * |
458 * @since 3.4.0 |
518 * @since 3.4.0 |
459 * @access public |
|
460 * |
519 * |
461 * @return bool Whether the theme exists. |
520 * @return bool Whether the theme exists. |
462 */ |
521 */ |
463 public function exists() { |
522 public function exists() { |
464 return ! ( $this->errors() && in_array( 'theme_not_found', $this->errors()->get_error_codes() ) ); |
523 return ! ( $this->errors() && in_array( 'theme_not_found', $this->errors()->get_error_codes() ) ); |
466 |
525 |
467 /** |
526 /** |
468 * Returns reference to the parent theme. |
527 * Returns reference to the parent theme. |
469 * |
528 * |
470 * @since 3.4.0 |
529 * @since 3.4.0 |
471 * @access public |
530 * |
472 * |
531 * @return WP_Theme|false Parent theme, or false if the current theme is not a child theme. |
473 * @return WP_Theme|bool Parent theme, or false if the current theme is not a child theme. |
|
474 */ |
532 */ |
475 public function parent() { |
533 public function parent() { |
476 return isset( $this->parent ) ? $this->parent : false; |
534 return isset( $this->parent ) ? $this->parent : false; |
477 } |
535 } |
478 |
536 |
479 /** |
537 /** |
480 * Adds theme data to cache. |
538 * Adds theme data to cache. |
481 * |
539 * |
482 * Cache entries keyed by the theme and the type of data. |
540 * Cache entries keyed by the theme and the type of data. |
483 * |
541 * |
484 * @access private |
542 * @since 3.4.0 |
485 * @since 3.4.0 |
543 * |
486 * |
544 * @param string $key Type of data to store (theme, screenshot, headers, post_templates) |
487 * @param string $key Type of data to store (theme, screenshot, headers, page_templates) |
|
488 * @param string $data Data to store |
545 * @param string $data Data to store |
489 * @return bool Return value from wp_cache_add() |
546 * @return bool Return value from wp_cache_add() |
490 */ |
547 */ |
491 private function cache_add( $key, $data ) { |
548 private function cache_add( $key, $data ) { |
492 return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'themes', self::$cache_expiration ); |
549 return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'themes', self::$cache_expiration ); |
495 /** |
552 /** |
496 * Gets theme data from cache. |
553 * Gets theme data from cache. |
497 * |
554 * |
498 * Cache entries are keyed by the theme and the type of data. |
555 * Cache entries are keyed by the theme and the type of data. |
499 * |
556 * |
500 * @access private |
557 * @since 3.4.0 |
501 * @since 3.4.0 |
558 * |
502 * |
559 * @param string $key Type of data to retrieve (theme, screenshot, headers, post_templates) |
503 * @param string $key Type of data to retrieve (theme, screenshot, headers, page_templates) |
|
504 * @return mixed Retrieved data |
560 * @return mixed Retrieved data |
505 */ |
561 */ |
506 private function cache_get( $key ) { |
562 private function cache_get( $key ) { |
507 return wp_cache_get( $key . '-' . $this->cache_hash, 'themes' ); |
563 return wp_cache_get( $key . '-' . $this->cache_hash, 'themes' ); |
508 } |
564 } |
509 |
565 |
510 /** |
566 /** |
511 * Clears the cache for the theme. |
567 * Clears the cache for the theme. |
512 * |
568 * |
513 * @access public |
|
514 * @since 3.4.0 |
569 * @since 3.4.0 |
515 */ |
570 */ |
516 public function cache_delete() { |
571 public function cache_delete() { |
517 foreach ( array( 'theme', 'screenshot', 'headers', 'page_templates' ) as $key ) |
572 foreach ( array( 'theme', 'screenshot', 'headers', 'post_templates' ) as $key ) |
518 wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' ); |
573 wp_cache_delete( $key . '-' . $this->cache_hash, 'themes' ); |
519 $this->template = $this->textdomain_loaded = $this->theme_root_uri = $this->parent = $this->errors = $this->headers_sanitized = $this->name_translated = null; |
574 $this->template = $this->textdomain_loaded = $this->theme_root_uri = $this->parent = $this->errors = $this->headers_sanitized = $this->name_translated = null; |
520 $this->headers = array(); |
575 $this->headers = array(); |
521 $this->__construct( $this->stylesheet, $this->theme_root ); |
576 $this->__construct( $this->stylesheet, $this->theme_root ); |
522 } |
577 } |
530 * Use the get_template() method, not the 'Template' header, for finding the template. |
585 * Use the get_template() method, not the 'Template' header, for finding the template. |
531 * The 'Template' header is only good for what was written in the style.css, while |
586 * The 'Template' header is only good for what was written in the style.css, while |
532 * get_template() takes into account where WordPress actually located the theme and |
587 * get_template() takes into account where WordPress actually located the theme and |
533 * whether it is actually valid. |
588 * whether it is actually valid. |
534 * |
589 * |
535 * @access public |
|
536 * @since 3.4.0 |
590 * @since 3.4.0 |
537 * |
591 * |
538 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
592 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
539 * @return string|bool String on success, false on failure. |
593 * @return string|false String on success, false on failure. |
540 */ |
594 */ |
541 public function get( $header ) { |
595 public function get( $header ) { |
542 if ( ! isset( $this->headers[ $header ] ) ) |
596 if ( ! isset( $this->headers[ $header ] ) ) |
543 return false; |
597 return false; |
544 |
598 |
564 } |
618 } |
565 |
619 |
566 /** |
620 /** |
567 * Gets a theme header, formatted and translated for display. |
621 * Gets a theme header, formatted and translated for display. |
568 * |
622 * |
569 * @access public |
|
570 * @since 3.4.0 |
623 * @since 3.4.0 |
571 * |
624 * |
572 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
625 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
573 * @param bool $markup Optional. Whether to mark up the header. Defaults to true. |
626 * @param bool $markup Optional. Whether to mark up the header. Defaults to true. |
574 * @param bool $translate Optional. Whether to translate the header. Defaults to true. |
627 * @param bool $translate Optional. Whether to translate the header. Defaults to true. |
575 * @return string|bool Processed header, false on failure. |
628 * @return string|false Processed header, false on failure. |
576 */ |
629 */ |
577 public function display( $header, $markup = true, $translate = true ) { |
630 public function display( $header, $markup = true, $translate = true ) { |
578 $value = $this->get( $header ); |
631 $value = $this->get( $header ); |
579 if ( false === $value ) { |
632 if ( false === $value ) { |
580 return false; |
633 return false; |
593 } |
646 } |
594 |
647 |
595 /** |
648 /** |
596 * Sanitize a theme header. |
649 * Sanitize a theme header. |
597 * |
650 * |
651 * @since 3.4.0 |
|
652 * |
|
653 * @staticvar array $header_tags |
|
654 * @staticvar array $header_tags_with_a |
|
655 * |
|
598 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
656 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
599 * @param string $value Value to sanitize. |
657 * @param string $value Value to sanitize. |
658 * @return mixed |
|
600 */ |
659 */ |
601 private function sanitize_header( $header, $value ) { |
660 private function sanitize_header( $header, $value ) { |
602 switch ( $header ) { |
661 switch ( $header ) { |
603 case 'Status' : |
662 case 'Status' : |
604 if ( ! $value ) { |
663 if ( ! $value ) { |
645 } |
704 } |
646 |
705 |
647 /** |
706 /** |
648 * Mark up a theme header. |
707 * Mark up a theme header. |
649 * |
708 * |
650 * @access private |
709 * @since 3.4.0 |
651 * @since 3.4.0 |
710 * |
711 * @staticvar string $comma |
|
652 * |
712 * |
653 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
713 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
654 * @param string $value Value to mark up. |
714 * @param string $value Value to mark up. |
655 * @param string $translate Whether the header has been translated. |
715 * @param string $translate Whether the header has been translated. |
656 * @return string Value, marked up. |
716 * @return string Value, marked up. |
657 */ |
717 */ |
658 private function markup_header( $header, $value, $translate ) { |
718 private function markup_header( $header, $value, $translate ) { |
659 switch ( $header ) { |
719 switch ( $header ) { |
660 case 'Name' : |
720 case 'Name' : |
661 if ( empty( $value ) ) |
721 if ( empty( $value ) ) { |
662 $value = $this->get_stylesheet(); |
722 $value = esc_html( $this->get_stylesheet() ); |
723 } |
|
663 break; |
724 break; |
664 case 'Description' : |
725 case 'Description' : |
665 $value = wptexturize( $value ); |
726 $value = wptexturize( $value ); |
666 break; |
727 break; |
667 case 'Author' : |
728 case 'Author' : |
689 } |
750 } |
690 |
751 |
691 /** |
752 /** |
692 * Translate a theme header. |
753 * Translate a theme header. |
693 * |
754 * |
694 * @access private |
755 * @since 3.4.0 |
695 * @since 3.4.0 |
756 * |
757 * @staticvar array $tags_list |
|
696 * |
758 * |
697 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
759 * @param string $header Theme header. Name, Description, Author, Version, ThemeURI, AuthorURI, Status, Tags. |
698 * @param string $value Value to translate. |
760 * @param string $value Value to translate. |
699 * @return string Translated value. |
761 * @return string Translated value. |
700 */ |
762 */ |
705 if ( isset( $this->name_translated ) ) |
767 if ( isset( $this->name_translated ) ) |
706 return $this->name_translated; |
768 return $this->name_translated; |
707 $this->name_translated = translate( $value, $this->get('TextDomain' ) ); |
769 $this->name_translated = translate( $value, $this->get('TextDomain' ) ); |
708 return $this->name_translated; |
770 return $this->name_translated; |
709 case 'Tags' : |
771 case 'Tags' : |
710 if ( empty( $value ) || ! function_exists( 'get_theme_feature_list' ) ) |
772 if ( empty( $value ) || ! function_exists( 'get_theme_feature_list' ) ) { |
711 return $value; |
773 return $value; |
774 } |
|
712 |
775 |
713 static $tags_list; |
776 static $tags_list; |
714 if ( ! isset( $tags_list ) ) { |
777 if ( ! isset( $tags_list ) ) { |
715 $tags_list = array(); |
778 $tags_list = array( |
779 // As of 4.6, deprecated tags which are only used to provide translation for older themes. |
|
780 'black' => __( 'Black' ), 'blue' => __( 'Blue' ), 'brown' => __( 'Brown' ), |
|
781 'gray' => __( 'Gray' ), 'green' => __( 'Green' ), 'orange' => __( 'Orange' ), |
|
782 'pink' => __( 'Pink' ), 'purple' => __( 'Purple' ), 'red' => __( 'Red' ), |
|
783 'silver' => __( 'Silver' ), 'tan' => __( 'Tan' ), 'white' => __( 'White' ), |
|
784 'yellow' => __( 'Yellow' ), 'dark' => __( 'Dark' ), 'light' => __( 'Light' ), |
|
785 'fixed-layout' => __( 'Fixed Layout' ), 'fluid-layout' => __( 'Fluid Layout' ), |
|
786 'responsive-layout' => __( 'Responsive Layout' ), 'blavatar' => __( 'Blavatar' ), |
|
787 'photoblogging' => __( 'Photoblogging' ), 'seasonal' => __( 'Seasonal' ), |
|
788 ); |
|
789 |
|
716 $feature_list = get_theme_feature_list( false ); // No API |
790 $feature_list = get_theme_feature_list( false ); // No API |
717 foreach ( $feature_list as $tags ) |
791 foreach ( $feature_list as $tags ) { |
718 $tags_list += $tags; |
792 $tags_list += $tags; |
793 } |
|
719 } |
794 } |
720 |
795 |
721 foreach ( $value as &$tag ) { |
796 foreach ( $value as &$tag ) { |
722 if ( isset( $tags_list[ $tag ] ) ) { |
797 if ( isset( $tags_list[ $tag ] ) ) { |
723 $tag = $tags_list[ $tag ]; |
798 $tag = $tags_list[ $tag ]; |
739 * |
814 * |
740 * In the case of a child theme, this is directory name of the child theme. |
815 * In the case of a child theme, this is directory name of the child theme. |
741 * Otherwise, get_stylesheet() is the same as get_template(). |
816 * Otherwise, get_stylesheet() is the same as get_template(). |
742 * |
817 * |
743 * @since 3.4.0 |
818 * @since 3.4.0 |
744 * @access public |
|
745 * |
819 * |
746 * @return string Stylesheet |
820 * @return string Stylesheet |
747 */ |
821 */ |
748 public function get_stylesheet() { |
822 public function get_stylesheet() { |
749 return $this->stylesheet; |
823 return $this->stylesheet; |
754 * |
828 * |
755 * In the case of a child theme, this is the directory name of the parent theme. |
829 * In the case of a child theme, this is the directory name of the parent theme. |
756 * Otherwise, the get_template() is the same as get_stylesheet(). |
830 * Otherwise, the get_template() is the same as get_stylesheet(). |
757 * |
831 * |
758 * @since 3.4.0 |
832 * @since 3.4.0 |
759 * @access public |
|
760 * |
833 * |
761 * @return string Template |
834 * @return string Template |
762 */ |
835 */ |
763 public function get_template() { |
836 public function get_template() { |
764 return $this->template; |
837 return $this->template; |
769 * |
842 * |
770 * In the case of a child theme, this is the absolute path to the directory |
843 * In the case of a child theme, this is the absolute path to the directory |
771 * of the child theme's files. |
844 * of the child theme's files. |
772 * |
845 * |
773 * @since 3.4.0 |
846 * @since 3.4.0 |
774 * @access public |
|
775 * |
847 * |
776 * @return string Absolute path of the stylesheet directory. |
848 * @return string Absolute path of the stylesheet directory. |
777 */ |
849 */ |
778 public function get_stylesheet_directory() { |
850 public function get_stylesheet_directory() { |
779 if ( $this->errors() && in_array( 'theme_root_missing', $this->errors()->get_error_codes() ) ) |
851 if ( $this->errors() && in_array( 'theme_root_missing', $this->errors()->get_error_codes() ) ) |
787 * |
859 * |
788 * In the case of a child theme, this is the absolute path to the directory |
860 * In the case of a child theme, this is the absolute path to the directory |
789 * of the parent theme's files. |
861 * of the parent theme's files. |
790 * |
862 * |
791 * @since 3.4.0 |
863 * @since 3.4.0 |
792 * @access public |
|
793 * |
864 * |
794 * @return string Absolute path of the template directory. |
865 * @return string Absolute path of the template directory. |
795 */ |
866 */ |
796 public function get_template_directory() { |
867 public function get_template_directory() { |
797 if ( $this->parent() ) |
868 if ( $this->parent() ) |
807 * |
878 * |
808 * In the case of a child theme, this is the URL to the directory of the |
879 * In the case of a child theme, this is the URL to the directory of the |
809 * child theme's files. |
880 * child theme's files. |
810 * |
881 * |
811 * @since 3.4.0 |
882 * @since 3.4.0 |
812 * @access public |
|
813 * |
883 * |
814 * @return string URL to the stylesheet directory. |
884 * @return string URL to the stylesheet directory. |
815 */ |
885 */ |
816 public function get_stylesheet_directory_uri() { |
886 public function get_stylesheet_directory_uri() { |
817 return $this->get_theme_root_uri() . '/' . str_replace( '%2F', '/', rawurlencode( $this->stylesheet ) ); |
887 return $this->get_theme_root_uri() . '/' . str_replace( '%2F', '/', rawurlencode( $this->stylesheet ) ); |
822 * |
892 * |
823 * In the case of a child theme, this is the URL to the directory of the |
893 * In the case of a child theme, this is the URL to the directory of the |
824 * parent theme's files. |
894 * parent theme's files. |
825 * |
895 * |
826 * @since 3.4.0 |
896 * @since 3.4.0 |
827 * @access public |
|
828 * |
897 * |
829 * @return string URL to the template directory. |
898 * @return string URL to the template directory. |
830 */ |
899 */ |
831 public function get_template_directory_uri() { |
900 public function get_template_directory_uri() { |
832 if ( $this->parent() ) |
901 if ( $this->parent() ) |
841 * The absolute path to the directory of the theme root. |
910 * The absolute path to the directory of the theme root. |
842 * |
911 * |
843 * This is typically the absolute path to wp-content/themes. |
912 * This is typically the absolute path to wp-content/themes. |
844 * |
913 * |
845 * @since 3.4.0 |
914 * @since 3.4.0 |
846 * @access public |
|
847 * |
915 * |
848 * @return string Theme root. |
916 * @return string Theme root. |
849 */ |
917 */ |
850 public function get_theme_root() { |
918 public function get_theme_root() { |
851 return $this->theme_root; |
919 return $this->theme_root; |
854 /** |
922 /** |
855 * Returns the URL to the directory of the theme root. |
923 * Returns the URL to the directory of the theme root. |
856 * |
924 * |
857 * This is typically the absolute URL to wp-content/themes. This forms the basis |
925 * This is typically the absolute URL to wp-content/themes. This forms the basis |
858 * for all other URLs returned by WP_Theme, so we pass it to the public function |
926 * for all other URLs returned by WP_Theme, so we pass it to the public function |
859 * get_theme_root_uri() and allow it to run the theme_root_uri filter. |
927 * get_theme_root_uri() and allow it to run the {@see 'theme_root_uri'} filter. |
860 * |
928 * |
861 * @since 3.4.0 |
929 * @since 3.4.0 |
862 * @access public |
|
863 * |
930 * |
864 * @return string Theme root URI. |
931 * @return string Theme root URI. |
865 */ |
932 */ |
866 public function get_theme_root_uri() { |
933 public function get_theme_root_uri() { |
867 if ( ! isset( $this->theme_root_uri ) ) |
934 if ( ! isset( $this->theme_root_uri ) ) |
876 * |
943 * |
877 * Screenshots for a theme must be in the stylesheet directory. (In the case of child |
944 * Screenshots for a theme must be in the stylesheet directory. (In the case of child |
878 * themes, parent theme screenshots are not inherited.) |
945 * themes, parent theme screenshots are not inherited.) |
879 * |
946 * |
880 * @since 3.4.0 |
947 * @since 3.4.0 |
881 * @access public |
|
882 * |
948 * |
883 * @param string $uri Type of URL to return, either 'relative' or an absolute URI. Defaults to absolute URI. |
949 * @param string $uri Type of URL to return, either 'relative' or an absolute URI. Defaults to absolute URI. |
884 * @return mixed Screenshot file. False if the theme does not have a screenshot. |
950 * @return string|false Screenshot file. False if the theme does not have a screenshot. |
885 */ |
951 */ |
886 public function get_screenshot( $uri = 'uri' ) { |
952 public function get_screenshot( $uri = 'uri' ) { |
887 $screenshot = $this->cache_get( 'screenshot' ); |
953 $screenshot = $this->cache_get( 'screenshot' ); |
888 if ( $screenshot ) { |
954 if ( $screenshot ) { |
889 if ( 'relative' == $uri ) |
955 if ( 'relative' == $uri ) |
908 |
974 |
909 /** |
975 /** |
910 * Return files in the theme's directory. |
976 * Return files in the theme's directory. |
911 * |
977 * |
912 * @since 3.4.0 |
978 * @since 3.4.0 |
913 * @access public |
|
914 * |
979 * |
915 * @param mixed $type Optional. Array of extensions to return. Defaults to all files (null). |
980 * @param mixed $type Optional. Array of extensions to return. Defaults to all files (null). |
916 * @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). -1 depth is infinite. |
981 * @param int $depth Optional. How deep to search for files. Defaults to a flat scan (0 depth). -1 depth is infinite. |
917 * @param bool $search_parent Optional. Whether to return parent files. Defaults to false. |
982 * @param bool $search_parent Optional. Whether to return parent files. Defaults to false. |
918 * @return array Array of files, keyed by the path to the file relative to the theme's directory, with the values |
983 * @return array Array of files, keyed by the path to the file relative to the theme's directory, with the values |
919 * being absolute paths. |
984 * being absolute paths. |
920 */ |
985 */ |
921 public function get_files( $type = null, $depth = 0, $search_parent = false ) { |
986 public function get_files( $type = null, $depth = 0, $search_parent = false ) { |
922 $files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth ); |
987 $files = (array) self::scandir( $this->get_stylesheet_directory(), $type, $depth ); |
923 |
988 |
924 if ( $search_parent && $this->parent() ) |
989 if ( $search_parent && $this->parent() ) { |
925 $files += (array) self::scandir( $this->get_template_directory(), $type, $depth ); |
990 $files += (array) self::scandir( $this->get_template_directory(), $type, $depth ); |
991 } |
|
926 |
992 |
927 return $files; |
993 return $files; |
928 } |
994 } |
929 |
995 |
930 /** |
996 /** |
931 * Returns the theme's page templates. |
997 * Returns the theme's post templates. |
932 * |
998 * |
933 * @since 3.4.0 |
999 * @since 4.7.0 |
934 * @access public |
1000 * |
935 * |
1001 * @return array Array of page templates, keyed by filename and post type, |
936 * @param WP_Post|null $post Optional. The post being edited, provided for context. |
1002 * with the value of the translated header name. |
1003 */ |
|
1004 public function get_post_templates() { |
|
1005 // If you screw up your current theme and we invalidate your parent, most things still work. Let it slide. |
|
1006 if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) { |
|
1007 return array(); |
|
1008 } |
|
1009 |
|
1010 $post_templates = $this->cache_get( 'post_templates' ); |
|
1011 |
|
1012 if ( ! is_array( $post_templates ) ) { |
|
1013 $post_templates = array(); |
|
1014 |
|
1015 $files = (array) $this->get_files( 'php', 1, true); |
|
1016 |
|
1017 foreach ( $files as $file => $full_path ) { |
|
1018 if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) { |
|
1019 continue; |
|
1020 } |
|
1021 |
|
1022 $types = array( 'page' ); |
|
1023 if ( preg_match( '|Template Post Type:(.*)$|mi', file_get_contents( $full_path ), $type ) ) { |
|
1024 $types = explode( ',', _cleanup_header_comment( $type[1] ) ); |
|
1025 } |
|
1026 |
|
1027 foreach ( $types as $type ) { |
|
1028 $type = sanitize_key( $type ); |
|
1029 if ( ! isset( $post_templates[ $type ] ) ) { |
|
1030 $post_templates[ $type ] = array(); |
|
1031 } |
|
1032 |
|
1033 $post_templates[ $type ][ $file ] = _cleanup_header_comment( $header[1] ); |
|
1034 } |
|
1035 } |
|
1036 |
|
1037 $this->cache_add( 'post_templates', $post_templates ); |
|
1038 } |
|
1039 |
|
1040 if ( $this->load_textdomain() ) { |
|
1041 foreach ( $post_templates as &$post_type ) { |
|
1042 foreach ( $post_type as &$post_template ) { |
|
1043 $post_template = $this->translate_header( 'Template Name', $post_template ); |
|
1044 } |
|
1045 } |
|
1046 } |
|
1047 |
|
1048 return $post_templates; |
|
1049 } |
|
1050 |
|
1051 /** |
|
1052 * Returns the theme's post templates for a given post type. |
|
1053 * |
|
1054 * @since 3.4.0 |
|
1055 * @since 4.7.0 Added the `$post_type` parameter. |
|
1056 * |
|
1057 * @param WP_Post|null $post Optional. The post being edited, provided for context. |
|
1058 * @param string $post_type Optional. Post type to get the templates for. Default 'page'. |
|
1059 * If a post is provided, its post type is used. |
|
937 * @return array Array of page templates, keyed by filename, with the value of the translated header name. |
1060 * @return array Array of page templates, keyed by filename, with the value of the translated header name. |
938 */ |
1061 */ |
939 public function get_page_templates( $post = null ) { |
1062 public function get_page_templates( $post = null, $post_type = 'page' ) { |
940 // If you screw up your current theme and we invalidate your parent, most things still work. Let it slide. |
1063 if ( $post ) { |
941 if ( $this->errors() && $this->errors()->get_error_codes() !== array( 'theme_parent_invalid' ) ) |
1064 $post_type = get_post_type( $post ); |
942 return array(); |
1065 } |
943 |
1066 |
944 $page_templates = $this->cache_get( 'page_templates' ); |
1067 $post_templates = $this->get_post_templates(); |
945 |
1068 $post_templates = isset( $post_templates[ $post_type ] ) ? $post_templates[ $post_type ] : array(); |
946 if ( ! is_array( $page_templates ) ) { |
|
947 $page_templates = array(); |
|
948 |
|
949 $files = (array) $this->get_files( 'php', 1 ); |
|
950 |
|
951 foreach ( $files as $file => $full_path ) { |
|
952 if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) |
|
953 continue; |
|
954 $page_templates[ $file ] = _cleanup_header_comment( $header[1] ); |
|
955 } |
|
956 |
|
957 $this->cache_add( 'page_templates', $page_templates ); |
|
958 } |
|
959 |
|
960 if ( $this->load_textdomain() ) { |
|
961 foreach ( $page_templates as &$page_template ) { |
|
962 $page_template = $this->translate_header( 'Template Name', $page_template ); |
|
963 } |
|
964 } |
|
965 |
|
966 if ( $this->parent() ) |
|
967 $page_templates += $this->parent()->get_page_templates( $post ); |
|
968 |
1069 |
969 /** |
1070 /** |
970 * Filter list of page templates for a theme. |
1071 * Filters list of page templates for a theme. |
971 * |
1072 * |
972 * This filter does not currently allow for page templates to be added. |
1073 * @since 4.9.6 |
973 * |
1074 * |
974 * @since 3.9.0 |
1075 * @param string[] $post_templates Array of page templates. Keys are filenames, |
975 * |
|
976 * @param array $page_templates Array of page templates. Keys are filenames, |
|
977 * values are translated names. |
1076 * values are translated names. |
978 * @param WP_Theme $this The theme object. |
1077 * @param WP_Theme $this The theme object. |
979 * @param WP_Post|null $post The post being edited, provided for context, or null. |
1078 * @param WP_Post|null $post The post being edited, provided for context, or null. |
1079 * @param string $post_type Post type to get the templates for. |
|
980 */ |
1080 */ |
981 $return = apply_filters( 'theme_page_templates', $page_templates, $this, $post ); |
1081 $post_templates = (array) apply_filters( 'theme_templates', $post_templates, $this, $post, $post_type ); |
982 |
1082 |
983 return array_intersect_assoc( $return, $page_templates ); |
1083 /** |
1084 * Filters list of page templates for a theme. |
|
1085 * |
|
1086 * The dynamic portion of the hook name, `$post_type`, refers to the post type. |
|
1087 * |
|
1088 * @since 3.9.0 |
|
1089 * @since 4.4.0 Converted to allow complete control over the `$page_templates` array. |
|
1090 * @since 4.7.0 Added the `$post_type` parameter. |
|
1091 * |
|
1092 * @param array $post_templates Array of page templates. Keys are filenames, |
|
1093 * values are translated names. |
|
1094 * @param WP_Theme $this The theme object. |
|
1095 * @param WP_Post|null $post The post being edited, provided for context, or null. |
|
1096 * @param string $post_type Post type to get the templates for. |
|
1097 */ |
|
1098 $post_templates = (array) apply_filters( "theme_{$post_type}_templates", $post_templates, $this, $post, $post_type ); |
|
1099 |
|
1100 return $post_templates; |
|
984 } |
1101 } |
985 |
1102 |
986 /** |
1103 /** |
987 * Scans a directory for files of a certain extension. |
1104 * Scans a directory for files of a certain extension. |
988 * |
1105 * |
989 * @since 3.4.0 |
1106 * @since 3.4.0 |
990 * @access private |
1107 * |
991 * |
1108 * @static |
992 * @param string $path Absolute path to search. |
1109 * |
993 * @param mixed Array of extensions to find, string of a single extension, or null for all extensions. |
1110 * @param string $path Absolute path to search. |
994 * @param int $depth How deep to search for files. Optional, defaults to a flat scan (0 depth). -1 depth is infinite. |
1111 * @param array|string|null $extensions Optional. Array of extensions to find, string of a single extension, |
995 * @param string $relative_path The basename of the absolute path. Used to control the returned path |
1112 * or null for all extensions. Default null. |
996 * for the found files, particularly when this function recurses to lower depths. |
1113 * @param int $depth Optional. How many levels deep to search for files. Accepts 0, 1+, or |
1114 * -1 (infinite depth). Default 0. |
|
1115 * @param string $relative_path Optional. The basename of the absolute path. Used to control the |
|
1116 * returned path for the found files, particularly when this function |
|
1117 * recurses to lower depths. Default empty. |
|
1118 * @return array|false Array of files, keyed by the path to the file relative to the `$path` directory prepended |
|
1119 * with `$relative_path`, with the values being absolute paths. False otherwise. |
|
997 */ |
1120 */ |
998 private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) { |
1121 private static function scandir( $path, $extensions = null, $depth = 0, $relative_path = '' ) { |
999 if ( ! is_dir( $path ) ) |
1122 if ( ! is_dir( $path ) ) { |
1000 return false; |
1123 return false; |
1124 } |
|
1001 |
1125 |
1002 if ( $extensions ) { |
1126 if ( $extensions ) { |
1003 $extensions = (array) $extensions; |
1127 $extensions = (array) $extensions; |
1004 $_extensions = implode( '|', $extensions ); |
1128 $_extensions = implode( '|', $extensions ); |
1005 } |
1129 } |
1006 |
1130 |
1007 $relative_path = trailingslashit( $relative_path ); |
1131 $relative_path = trailingslashit( $relative_path ); |
1008 if ( '/' == $relative_path ) |
1132 if ( '/' == $relative_path ) { |
1009 $relative_path = ''; |
1133 $relative_path = ''; |
1134 } |
|
1010 |
1135 |
1011 $results = scandir( $path ); |
1136 $results = scandir( $path ); |
1012 $files = array(); |
1137 $files = array(); |
1013 |
1138 |
1139 /** |
|
1140 * Filters the array of excluded directories and files while scanning theme folder. |
|
1141 * |
|
1142 * @since 4.7.4 |
|
1143 * |
|
1144 * @param array $exclusions Array of excluded directories and files. |
|
1145 */ |
|
1146 $exclusions = (array) apply_filters( 'theme_scandir_exclusions', array( 'CVS', 'node_modules', 'vendor', 'bower_components' ) ); |
|
1147 |
|
1014 foreach ( $results as $result ) { |
1148 foreach ( $results as $result ) { |
1015 if ( '.' == $result[0] ) |
1149 if ( '.' == $result[0] || in_array( $result, $exclusions, true ) ) { |
1016 continue; |
1150 continue; |
1151 } |
|
1017 if ( is_dir( $path . '/' . $result ) ) { |
1152 if ( is_dir( $path . '/' . $result ) ) { |
1018 if ( ! $depth || 'CVS' == $result ) |
1153 if ( ! $depth ) { |
1019 continue; |
1154 continue; |
1155 } |
|
1020 $found = self::scandir( $path . '/' . $result, $extensions, $depth - 1 , $relative_path . $result ); |
1156 $found = self::scandir( $path . '/' . $result, $extensions, $depth - 1 , $relative_path . $result ); |
1021 $files = array_merge_recursive( $files, $found ); |
1157 $files = array_merge_recursive( $files, $found ); |
1022 } elseif ( ! $extensions || preg_match( '~\.(' . $_extensions . ')$~', $result ) ) { |
1158 } elseif ( ! $extensions || preg_match( '~\.(' . $_extensions . ')$~', $result ) ) { |
1023 $files[ $relative_path . $result ] = $path . '/' . $result; |
1159 $files[ $relative_path . $result ] = $path . '/' . $result; |
1024 } |
1160 } |
1032 * |
1168 * |
1033 * Translation files are not inherited from the parent theme. Todo: if this fails for the |
1169 * Translation files are not inherited from the parent theme. Todo: if this fails for the |
1034 * child theme, it should probably try to load the parent theme's translations. |
1170 * child theme, it should probably try to load the parent theme's translations. |
1035 * |
1171 * |
1036 * @since 3.4.0 |
1172 * @since 3.4.0 |
1037 * @access public |
|
1038 * |
1173 * |
1039 * @return bool True if the textdomain was successfully loaded or has already been loaded. |
1174 * @return bool True if the textdomain was successfully loaded or has already been loaded. |
1040 * False if no textdomain was specified in the file headers, or if the domain could not be loaded. |
1175 * False if no textdomain was specified in the file headers, or if the domain could not be loaded. |
1041 */ |
1176 */ |
1042 public function load_textdomain() { |
1177 public function load_textdomain() { |
1066 |
1201 |
1067 /** |
1202 /** |
1068 * Whether the theme is allowed (multisite only). |
1203 * Whether the theme is allowed (multisite only). |
1069 * |
1204 * |
1070 * @since 3.4.0 |
1205 * @since 3.4.0 |
1071 * @access public |
|
1072 * |
1206 * |
1073 * @param string $check Optional. Whether to check only the 'network'-wide settings, the 'site' |
1207 * @param string $check Optional. Whether to check only the 'network'-wide settings, the 'site' |
1074 * settings, or 'both'. Defaults to 'both'. |
1208 * settings, or 'both'. Defaults to 'both'. |
1075 * @param int $blog_id Optional. Ignored if only network-wide settings are checked. Defaults to current blog. |
1209 * @param int $blog_id Optional. Ignored if only network-wide settings are checked. Defaults to current site. |
1076 * @return bool Whether the theme is allowed for the network. Returns true in single-site. |
1210 * @return bool Whether the theme is allowed for the network. Returns true in single-site. |
1077 */ |
1211 */ |
1078 public function is_allowed( $check = 'both', $blog_id = null ) { |
1212 public function is_allowed( $check = 'both', $blog_id = null ) { |
1079 if ( ! is_multisite() ) |
1213 if ( ! is_multisite() ) |
1080 return true; |
1214 return true; |
1093 |
1227 |
1094 return false; |
1228 return false; |
1095 } |
1229 } |
1096 |
1230 |
1097 /** |
1231 /** |
1232 * Determines the latest WordPress default theme that is installed. |
|
1233 * |
|
1234 * This hits the filesystem. |
|
1235 * |
|
1236 * @since 4.4.0 |
|
1237 * |
|
1238 * @return WP_Theme|false Object, or false if no theme is installed, which would be bad. |
|
1239 */ |
|
1240 public static function get_core_default_theme() { |
|
1241 foreach ( array_reverse( self::$default_themes ) as $slug => $name ) { |
|
1242 $theme = wp_get_theme( $slug ); |
|
1243 if ( $theme->exists() ) { |
|
1244 return $theme; |
|
1245 } |
|
1246 } |
|
1247 return false; |
|
1248 } |
|
1249 |
|
1250 /** |
|
1098 * Returns array of stylesheet names of themes allowed on the site or network. |
1251 * Returns array of stylesheet names of themes allowed on the site or network. |
1099 * |
1252 * |
1100 * @since 3.4.0 |
1253 * @since 3.4.0 |
1101 * @access public |
1254 * |
1102 * |
1255 * @static |
1103 * @param int $blog_id Optional. Defaults to current blog. |
1256 * |
1257 * @param int $blog_id Optional. ID of the site. Defaults to the current site. |
|
1104 * @return array Array of stylesheet names. |
1258 * @return array Array of stylesheet names. |
1105 */ |
1259 */ |
1106 public static function get_allowed( $blog_id = null ) { |
1260 public static function get_allowed( $blog_id = null ) { |
1107 /** |
1261 /** |
1108 * Filter the array of themes allowed on the site or network. |
1262 * Filters the array of themes allowed on the network. |
1109 * |
1263 * |
1110 * @since MU |
1264 * Site is provided as context so that a list of network allowed themes can |
1265 * be filtered further. |
|
1266 * |
|
1267 * @since 4.5.0 |
|
1268 * |
|
1269 * @param array $allowed_themes An array of theme stylesheet names. |
|
1270 * @param int $blog_id ID of the site. |
|
1271 */ |
|
1272 $network = (array) apply_filters( 'network_allowed_themes', self::get_allowed_on_network(), $blog_id ); |
|
1273 return $network + self::get_allowed_on_site( $blog_id ); |
|
1274 } |
|
1275 |
|
1276 /** |
|
1277 * Returns array of stylesheet names of themes allowed on the network. |
|
1278 * |
|
1279 * @since 3.4.0 |
|
1280 * |
|
1281 * @static |
|
1282 * |
|
1283 * @staticvar array $allowed_themes |
|
1284 * |
|
1285 * @return array Array of stylesheet names. |
|
1286 */ |
|
1287 public static function get_allowed_on_network() { |
|
1288 static $allowed_themes; |
|
1289 if ( ! isset( $allowed_themes ) ) { |
|
1290 $allowed_themes = (array) get_site_option( 'allowedthemes' ); |
|
1291 } |
|
1292 |
|
1293 /** |
|
1294 * Filters the array of themes allowed on the network. |
|
1295 * |
|
1296 * @since MU (3.0.0) |
|
1111 * |
1297 * |
1112 * @param array $allowed_themes An array of theme stylesheet names. |
1298 * @param array $allowed_themes An array of theme stylesheet names. |
1113 */ |
1299 */ |
1114 $network = (array) apply_filters( 'allowed_themes', self::get_allowed_on_network() ); |
1300 $allowed_themes = apply_filters( 'allowed_themes', $allowed_themes ); |
1115 return $network + self::get_allowed_on_site( $blog_id ); |
1301 |
1116 } |
|
1117 |
|
1118 /** |
|
1119 * Returns array of stylesheet names of themes allowed on the network. |
|
1120 * |
|
1121 * @since 3.4.0 |
|
1122 * @access public |
|
1123 * |
|
1124 * @return array Array of stylesheet names. |
|
1125 */ |
|
1126 public static function get_allowed_on_network() { |
|
1127 static $allowed_themes; |
|
1128 if ( ! isset( $allowed_themes ) ) |
|
1129 $allowed_themes = (array) get_site_option( 'allowedthemes' ); |
|
1130 return $allowed_themes; |
1302 return $allowed_themes; |
1131 } |
1303 } |
1132 |
1304 |
1133 /** |
1305 /** |
1134 * Returns array of stylesheet names of themes allowed on the site. |
1306 * Returns array of stylesheet names of themes allowed on the site. |
1135 * |
1307 * |
1136 * @since 3.4.0 |
1308 * @since 3.4.0 |
1137 * @access public |
1309 * |
1138 * |
1310 * @static |
1139 * @param int $blog_id Optional. Defaults to current blog. |
1311 * |
1312 * @staticvar array $allowed_themes |
|
1313 * |
|
1314 * @param int $blog_id Optional. ID of the site. Defaults to the current site. |
|
1140 * @return array Array of stylesheet names. |
1315 * @return array Array of stylesheet names. |
1141 */ |
1316 */ |
1142 public static function get_allowed_on_site( $blog_id = null ) { |
1317 public static function get_allowed_on_site( $blog_id = null ) { |
1143 static $allowed_themes = array(); |
1318 static $allowed_themes = array(); |
1144 |
1319 |
1145 if ( ! $blog_id || ! is_multisite() ) |
1320 if ( ! $blog_id || ! is_multisite() ) |
1146 $blog_id = get_current_blog_id(); |
1321 $blog_id = get_current_blog_id(); |
1147 |
1322 |
1148 if ( isset( $allowed_themes[ $blog_id ] ) ) |
1323 if ( isset( $allowed_themes[ $blog_id ] ) ) { |
1149 return $allowed_themes[ $blog_id ]; |
1324 /** |
1325 * Filters the array of themes allowed on the site. |
|
1326 * |
|
1327 * @since 4.5.0 |
|
1328 * |
|
1329 * @param array $allowed_themes An array of theme stylesheet names. |
|
1330 * @param int $blog_id ID of the site. Defaults to current site. |
|
1331 */ |
|
1332 return (array) apply_filters( 'site_allowed_themes', $allowed_themes[ $blog_id ], $blog_id ); |
|
1333 } |
|
1150 |
1334 |
1151 $current = $blog_id == get_current_blog_id(); |
1335 $current = $blog_id == get_current_blog_id(); |
1152 |
1336 |
1153 if ( $current ) { |
1337 if ( $current ) { |
1154 $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' ); |
1338 $allowed_themes[ $blog_id ] = get_option( 'allowedthemes' ); |
1192 restore_current_blog(); |
1376 restore_current_blog(); |
1193 } |
1377 } |
1194 } |
1378 } |
1195 } |
1379 } |
1196 |
1380 |
1197 return (array) $allowed_themes[ $blog_id ]; |
1381 /** This filter is documented in wp-includes/class-wp-theme.php */ |
1198 } |
1382 return (array) apply_filters( 'site_allowed_themes', $allowed_themes[ $blog_id ], $blog_id ); |
1199 |
1383 } |
1200 /** |
1384 |
1201 * Sort themes by name. |
1385 /** |
1202 * |
1386 * Enables a theme for all sites on the current network. |
1203 * @since 3.4.0 |
1387 * |
1204 * @access public |
1388 * @since 4.6.0 |
1389 * @static |
|
1390 * |
|
1391 * @param string|array $stylesheets Stylesheet name or array of stylesheet names. |
|
1392 */ |
|
1393 public static function network_enable_theme( $stylesheets ) { |
|
1394 if ( ! is_multisite() ) { |
|
1395 return; |
|
1396 } |
|
1397 |
|
1398 if ( ! is_array( $stylesheets ) ) { |
|
1399 $stylesheets = array( $stylesheets ); |
|
1400 } |
|
1401 |
|
1402 $allowed_themes = get_site_option( 'allowedthemes' ); |
|
1403 foreach ( $stylesheets as $stylesheet ) { |
|
1404 $allowed_themes[ $stylesheet ] = true; |
|
1405 } |
|
1406 |
|
1407 update_site_option( 'allowedthemes', $allowed_themes ); |
|
1408 } |
|
1409 |
|
1410 /** |
|
1411 * Disables a theme for all sites on the current network. |
|
1412 * |
|
1413 * @since 4.6.0 |
|
1414 * @static |
|
1415 * |
|
1416 * @param string|array $stylesheets Stylesheet name or array of stylesheet names. |
|
1417 */ |
|
1418 public static function network_disable_theme( $stylesheets ) { |
|
1419 if ( ! is_multisite() ) { |
|
1420 return; |
|
1421 } |
|
1422 |
|
1423 if ( ! is_array( $stylesheets ) ) { |
|
1424 $stylesheets = array( $stylesheets ); |
|
1425 } |
|
1426 |
|
1427 $allowed_themes = get_site_option( 'allowedthemes' ); |
|
1428 foreach ( $stylesheets as $stylesheet ) { |
|
1429 if ( isset( $allowed_themes[ $stylesheet ] ) ) { |
|
1430 unset( $allowed_themes[ $stylesheet ] ); |
|
1431 } |
|
1432 } |
|
1433 |
|
1434 update_site_option( 'allowedthemes', $allowed_themes ); |
|
1435 } |
|
1436 |
|
1437 /** |
|
1438 * Sorts themes by name. |
|
1439 * |
|
1440 * @since 3.4.0 |
|
1441 * |
|
1442 * @static |
|
1443 * |
|
1444 * @param array $themes Array of themes to sort (passed by reference). |
|
1205 */ |
1445 */ |
1206 public static function sort_by_name( &$themes ) { |
1446 public static function sort_by_name( &$themes ) { |
1207 if ( 0 === strpos( get_locale(), 'en_' ) ) { |
1447 if ( 0 === strpos( get_user_locale(), 'en_' ) ) { |
1208 uasort( $themes, array( 'WP_Theme', '_name_sort' ) ); |
1448 uasort( $themes, array( 'WP_Theme', '_name_sort' ) ); |
1209 } else { |
1449 } else { |
1210 uasort( $themes, array( 'WP_Theme', '_name_sort_i18n' ) ); |
1450 uasort( $themes, array( 'WP_Theme', '_name_sort_i18n' ) ); |
1211 } |
1451 } |
1212 } |
1452 } |
1216 * |
1456 * |
1217 * Accesses the Name header directly from the class for maximum speed. |
1457 * Accesses the Name header directly from the class for maximum speed. |
1218 * Would choke on HTML but we don't care enough to slow it down with strip_tags(). |
1458 * Would choke on HTML but we don't care enough to slow it down with strip_tags(). |
1219 * |
1459 * |
1220 * @since 3.4.0 |
1460 * @since 3.4.0 |
1221 * @access private |
1461 * |
1462 * @static |
|
1463 * |
|
1464 * @param string $a First name. |
|
1465 * @param string $b Second name. |
|
1466 * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. |
|
1467 * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). |
|
1222 */ |
1468 */ |
1223 private static function _name_sort( $a, $b ) { |
1469 private static function _name_sort( $a, $b ) { |
1224 return strnatcasecmp( $a->headers['Name'], $b->headers['Name'] ); |
1470 return strnatcasecmp( $a->headers['Name'], $b->headers['Name'] ); |
1225 } |
1471 } |
1226 |
1472 |
1227 /** |
1473 /** |
1228 * Name sort (with translation). |
1474 * Name sort (with translation). |
1229 * |
1475 * |
1230 * @since 3.4.0 |
1476 * @since 3.4.0 |
1231 * @access private |
1477 * |
1478 * @static |
|
1479 * |
|
1480 * @param string $a First name. |
|
1481 * @param string $b Second name. |
|
1482 * @return int Negative if `$a` falls lower in the natural order than `$b`. Zero if they fall equally. |
|
1483 * Greater than 0 if `$a` falls higher in the natural order than `$b`. Used with usort(). |
|
1232 */ |
1484 */ |
1233 private static function _name_sort_i18n( $a, $b ) { |
1485 private static function _name_sort_i18n( $a, $b ) { |
1234 // Don't mark up; Do translate. |
1486 // Don't mark up; Do translate. |
1235 return strnatcasecmp( $a->display( 'Name', false, true ), $b->display( 'Name', false, true ) ); |
1487 return strnatcasecmp( $a->display( 'Name', false, true ), $b->display( 'Name', false, true ) ); |
1236 } |
1488 } |