9 /** |
9 /** |
10 * Remove a theme |
10 * Remove a theme |
11 * |
11 * |
12 * @since 2.8.0 |
12 * @since 2.8.0 |
13 * |
13 * |
14 * @global WP_Filesystem_Base $wp_filesystem Subclass |
14 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. |
15 * |
15 * |
16 * @param string $stylesheet Stylesheet of the theme to delete |
16 * @param string $stylesheet Stylesheet of the theme to delete. |
17 * @param string $redirect Redirect to page when complete. |
17 * @param string $redirect Redirect to page when complete. |
18 * @return void|bool|WP_Error When void, echoes content. |
18 * @return bool|null|WP_Error True on success, false if `$stylesheet` is empty, WP_Error on failure. |
19 */ |
19 * Null if filesystem credentials are required to proceed. |
20 function delete_theme($stylesheet, $redirect = '') { |
20 */ |
|
21 function delete_theme( $stylesheet, $redirect = '' ) { |
21 global $wp_filesystem; |
22 global $wp_filesystem; |
22 |
23 |
23 if ( empty($stylesheet) ) |
24 if ( empty( $stylesheet ) ) { |
24 return false; |
25 return false; |
|
26 } |
25 |
27 |
26 if ( empty( $redirect ) ) { |
28 if ( empty( $redirect ) ) { |
27 $redirect = wp_nonce_url('themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet); |
29 $redirect = wp_nonce_url( 'themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet ); |
28 } |
30 } |
29 |
31 |
30 ob_start(); |
32 ob_start(); |
31 $credentials = request_filesystem_credentials( $redirect ); |
33 $credentials = request_filesystem_credentials( $redirect ); |
32 $data = ob_get_clean(); |
34 $data = ob_get_clean(); |
33 |
35 |
34 if ( false === $credentials ) { |
36 if ( false === $credentials ) { |
35 if ( ! empty( $data ) ){ |
37 if ( ! empty( $data ) ) { |
36 include_once( ABSPATH . 'wp-admin/admin-header.php'); |
38 include_once( ABSPATH . 'wp-admin/admin-header.php' ); |
37 echo $data; |
39 echo $data; |
38 include( ABSPATH . 'wp-admin/admin-footer.php'); |
40 include( ABSPATH . 'wp-admin/admin-footer.php' ); |
39 exit; |
41 exit; |
40 } |
42 } |
41 return; |
43 return; |
42 } |
44 } |
43 |
45 |
44 if ( ! WP_Filesystem( $credentials ) ) { |
46 if ( ! WP_Filesystem( $credentials ) ) { |
45 ob_start(); |
47 ob_start(); |
46 request_filesystem_credentials( $redirect, '', true ); // Failed to connect, Error and request again. |
48 request_filesystem_credentials( $redirect, '', true ); // Failed to connect, Error and request again. |
47 $data = ob_get_clean(); |
49 $data = ob_get_clean(); |
48 |
50 |
49 if ( ! empty($data) ) { |
51 if ( ! empty( $data ) ) { |
50 include_once( ABSPATH . 'wp-admin/admin-header.php'); |
52 include_once( ABSPATH . 'wp-admin/admin-header.php' ); |
51 echo $data; |
53 echo $data; |
52 include( ABSPATH . 'wp-admin/admin-footer.php'); |
54 include( ABSPATH . 'wp-admin/admin-footer.php' ); |
53 exit; |
55 exit; |
54 } |
56 } |
55 return; |
57 return; |
56 } |
58 } |
57 |
59 |
58 if ( ! is_object($wp_filesystem) ) |
60 if ( ! is_object( $wp_filesystem ) ) { |
59 return new WP_Error('fs_unavailable', __('Could not access filesystem.')); |
61 return new WP_Error( 'fs_unavailable', __( 'Could not access filesystem.' ) ); |
60 |
62 } |
61 if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() ) |
63 |
62 return new WP_Error('fs_error', __('Filesystem error.'), $wp_filesystem->errors); |
64 if ( is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) { |
|
65 return new WP_Error( 'fs_error', __( 'Filesystem error.' ), $wp_filesystem->errors ); |
|
66 } |
63 |
67 |
64 // Get the base plugin folder. |
68 // Get the base plugin folder. |
65 $themes_dir = $wp_filesystem->wp_themes_dir(); |
69 $themes_dir = $wp_filesystem->wp_themes_dir(); |
66 if ( empty( $themes_dir ) ) { |
70 if ( empty( $themes_dir ) ) { |
67 return new WP_Error( 'fs_no_themes_dir', __( 'Unable to locate WordPress theme directory.' ) ); |
71 return new WP_Error( 'fs_no_themes_dir', __( 'Unable to locate WordPress theme directory.' ) ); |
68 } |
72 } |
69 |
73 |
70 $themes_dir = trailingslashit( $themes_dir ); |
74 $themes_dir = trailingslashit( $themes_dir ); |
71 $theme_dir = trailingslashit( $themes_dir . $stylesheet ); |
75 $theme_dir = trailingslashit( $themes_dir . $stylesheet ); |
72 $deleted = $wp_filesystem->delete( $theme_dir, true ); |
76 $deleted = $wp_filesystem->delete( $theme_dir, true ); |
73 |
77 |
74 if ( ! $deleted ) { |
78 if ( ! $deleted ) { |
75 return new WP_Error( 'could_not_remove_theme', sprintf( __( 'Could not fully remove the theme %s.' ), $stylesheet ) ); |
79 return new WP_Error( 'could_not_remove_theme', sprintf( __( 'Could not fully remove the theme %s.' ), $stylesheet ) ); |
76 } |
80 } |
77 |
81 |
153 * @return false|string HTML for the update link, or false if invalid info was passed. |
162 * @return false|string HTML for the update link, or false if invalid info was passed. |
154 */ |
163 */ |
155 function get_theme_update_available( $theme ) { |
164 function get_theme_update_available( $theme ) { |
156 static $themes_update = null; |
165 static $themes_update = null; |
157 |
166 |
158 if ( !current_user_can('update_themes' ) ) |
167 if ( ! current_user_can( 'update_themes' ) ) { |
159 return false; |
168 return false; |
160 |
169 } |
161 if ( !isset($themes_update) ) |
170 |
162 $themes_update = get_site_transient('update_themes'); |
171 if ( ! isset( $themes_update ) ) { |
|
172 $themes_update = get_site_transient( 'update_themes' ); |
|
173 } |
163 |
174 |
164 if ( ! ( $theme instanceof WP_Theme ) ) { |
175 if ( ! ( $theme instanceof WP_Theme ) ) { |
165 return false; |
176 return false; |
166 } |
177 } |
167 |
178 |
168 $stylesheet = $theme->get_stylesheet(); |
179 $stylesheet = $theme->get_stylesheet(); |
169 |
180 |
170 $html = ''; |
181 $html = ''; |
171 |
182 |
172 if ( isset($themes_update->response[ $stylesheet ]) ) { |
183 if ( isset( $themes_update->response[ $stylesheet ] ) ) { |
173 $update = $themes_update->response[ $stylesheet ]; |
184 $update = $themes_update->response[ $stylesheet ]; |
174 $theme_name = $theme->display('Name'); |
185 $theme_name = $theme->display( 'Name' ); |
175 $details_url = add_query_arg(array('TB_iframe' => 'true', 'width' => 1024, 'height' => 800), $update['url']); //Theme browser inside WP? replace this, Also, theme preview JS will override this on the available list. |
186 $details_url = add_query_arg( |
176 $update_url = wp_nonce_url( admin_url( 'update.php?action=upgrade-theme&theme=' . urlencode( $stylesheet ) ), 'upgrade-theme_' . $stylesheet ); |
187 array( |
177 |
188 'TB_iframe' => 'true', |
178 if ( !is_multisite() ) { |
189 'width' => 1024, |
179 if ( ! current_user_can('update_themes') ) { |
190 'height' => 800, |
|
191 ), |
|
192 $update['url'] |
|
193 ); //Theme browser inside WP? replace this, Also, theme preview JS will override this on the available list. |
|
194 $update_url = wp_nonce_url( admin_url( 'update.php?action=upgrade-theme&theme=' . urlencode( $stylesheet ) ), 'upgrade-theme_' . $stylesheet ); |
|
195 |
|
196 if ( ! is_multisite() ) { |
|
197 if ( ! current_user_can( 'update_themes' ) ) { |
180 /* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number */ |
198 /* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number */ |
181 $html = sprintf( '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ) . '</strong></p>', |
199 $html = sprintf( |
|
200 '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>.' ) . '</strong></p>', |
182 $theme_name, |
201 $theme_name, |
183 esc_url( $details_url ), |
202 esc_url( $details_url ), |
184 sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', |
203 sprintf( |
|
204 'class="thickbox open-plugin-details-modal" aria-label="%s"', |
185 /* translators: 1: theme name, 2: version number */ |
205 /* translators: 1: theme name, 2: version number */ |
186 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ) |
206 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ) |
187 ), |
207 ), |
188 $update['new_version'] |
208 $update['new_version'] |
189 ); |
209 ); |
190 } elseif ( empty( $update['package'] ) ) { |
210 } elseif ( empty( $update['package'] ) ) { |
191 /* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number */ |
211 /* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number */ |
192 $html = sprintf( '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ) . '</strong></p>', |
212 $html = sprintf( |
|
213 '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ) . '</strong></p>', |
193 $theme_name, |
214 $theme_name, |
194 esc_url( $details_url ), |
215 esc_url( $details_url ), |
195 sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', |
216 sprintf( |
|
217 'class="thickbox open-plugin-details-modal" aria-label="%s"', |
196 /* translators: 1: theme name, 2: version number */ |
218 /* translators: 1: theme name, 2: version number */ |
197 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ) |
219 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ) |
198 ), |
220 ), |
199 $update['new_version'] |
221 $update['new_version'] |
200 ); |
222 ); |
201 } else { |
223 } else { |
202 /* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number, 5: update URL, 6: additional link attributes */ |
224 /* translators: 1: theme name, 2: theme details URL, 3: additional link attributes, 4: version number, 5: update URL, 6: additional link attributes */ |
203 $html = sprintf( '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ) . '</strong></p>', |
225 $html = sprintf( |
|
226 '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" %3$s>View version %4$s details</a> or <a href="%5$s" %6$s>update now</a>.' ) . '</strong></p>', |
204 $theme_name, |
227 $theme_name, |
205 esc_url( $details_url ), |
228 esc_url( $details_url ), |
206 sprintf( 'class="thickbox open-plugin-details-modal" aria-label="%s"', |
229 sprintf( |
|
230 'class="thickbox open-plugin-details-modal" aria-label="%s"', |
207 /* translators: 1: theme name, 2: version number */ |
231 /* translators: 1: theme name, 2: version number */ |
208 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ) |
232 esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ) |
209 ), |
233 ), |
210 $update['new_version'], |
234 $update['new_version'], |
211 $update_url, |
235 $update_url, |
212 sprintf( 'aria-label="%s" id="update-theme" data-slug="%s"', |
236 sprintf( |
|
237 'aria-label="%s" id="update-theme" data-slug="%s"', |
213 /* translators: %s: theme name */ |
238 /* translators: %s: theme name */ |
214 esc_attr( sprintf( __( 'Update %s now' ), $theme_name ) ), |
239 esc_attr( sprintf( __( 'Update %s now' ), $theme_name ) ), |
215 $stylesheet |
240 $stylesheet |
216 ) |
241 ) |
217 ); |
242 ); |
260 'post-formats' => __( 'Post Formats' ), |
285 'post-formats' => __( 'Post Formats' ), |
261 'sticky-post' => __( 'Sticky Post' ), |
286 'sticky-post' => __( 'Sticky Post' ), |
262 'theme-options' => __( 'Theme Options' ), |
287 'theme-options' => __( 'Theme Options' ), |
263 ), |
288 ), |
264 |
289 |
265 __( 'Layout' ) => array( |
290 __( 'Layout' ) => array( |
266 'grid-layout' => __( 'Grid Layout' ), |
291 'grid-layout' => __( 'Grid Layout' ), |
267 'one-column' => __( 'One Column' ), |
292 'one-column' => __( 'One Column' ), |
268 'two-columns' => __( 'Two Columns' ), |
293 'two-columns' => __( 'Two Columns' ), |
269 'three-columns' => __( 'Three Columns' ), |
294 'three-columns' => __( 'Three Columns' ), |
270 'four-columns' => __( 'Four Columns' ), |
295 'four-columns' => __( 'Four Columns' ), |
271 'left-sidebar' => __( 'Left Sidebar' ), |
296 'left-sidebar' => __( 'Left Sidebar' ), |
272 'right-sidebar' => __( 'Right Sidebar' ), |
297 'right-sidebar' => __( 'Right Sidebar' ), |
273 ) |
298 ), |
274 |
299 |
275 ); |
300 ); |
276 |
301 |
277 if ( ! $api || ! current_user_can( 'install_themes' ) ) |
302 if ( ! $api || ! current_user_can( 'install_themes' ) ) { |
278 return $features; |
303 return $features; |
279 |
304 } |
280 if ( !$feature_list = get_site_transient( 'wporg_theme_feature_list' ) ) |
305 |
|
306 if ( ! $feature_list = get_site_transient( 'wporg_theme_feature_list' ) ) { |
281 set_site_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS ); |
307 set_site_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS ); |
282 |
308 } |
283 if ( !$feature_list ) { |
309 |
|
310 if ( ! $feature_list ) { |
284 $feature_list = themes_api( 'feature_list', array() ); |
311 $feature_list = themes_api( 'feature_list', array() ); |
285 if ( is_wp_error( $feature_list ) ) |
312 if ( is_wp_error( $feature_list ) ) { |
286 return $features; |
313 return $features; |
287 } |
314 } |
288 |
315 } |
289 if ( !$feature_list ) |
316 |
|
317 if ( ! $feature_list ) { |
290 return $features; |
318 return $features; |
|
319 } |
291 |
320 |
292 set_site_transient( 'wporg_theme_feature_list', $feature_list, 3 * HOUR_IN_SECONDS ); |
321 set_site_transient( 'wporg_theme_feature_list', $feature_list, 3 * HOUR_IN_SECONDS ); |
293 |
322 |
294 $category_translations = array( |
323 $category_translations = array( |
295 'Layout' => __( 'Layout' ), |
324 'Layout' => __( 'Layout' ), |
395 * @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the |
426 * @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the |
396 * {@link https://developer.wordpress.org/reference/functions/themes_api/ function reference article} |
427 * {@link https://developer.wordpress.org/reference/functions/themes_api/ function reference article} |
397 * for more information on the make-up of possible return objects depending on the value of `$action`. |
428 * for more information on the make-up of possible return objects depending on the value of `$action`. |
398 */ |
429 */ |
399 function themes_api( $action, $args = array() ) { |
430 function themes_api( $action, $args = array() ) { |
|
431 // include an unmodified $wp_version |
|
432 include( ABSPATH . WPINC . '/version.php' ); |
400 |
433 |
401 if ( is_array( $args ) ) { |
434 if ( is_array( $args ) ) { |
402 $args = (object) $args; |
435 $args = (object) $args; |
403 } |
436 } |
404 |
437 |
405 if ( ! isset( $args->per_page ) ) { |
438 if ( 'query_themes' == $action ) { |
406 $args->per_page = 24; |
439 if ( ! isset( $args->per_page ) ) { |
|
440 $args->per_page = 24; |
|
441 } |
407 } |
442 } |
408 |
443 |
409 if ( ! isset( $args->locale ) ) { |
444 if ( ! isset( $args->locale ) ) { |
410 $args->locale = get_user_locale(); |
445 $args->locale = get_user_locale(); |
|
446 } |
|
447 |
|
448 if ( ! isset( $args->wp_version ) ) { |
|
449 $args->wp_version = substr( $wp_version, 0, 3 ); // X.y |
411 } |
450 } |
412 |
451 |
413 /** |
452 /** |
414 * Filters arguments used to query for installer pages from the WordPress.org Themes API. |
453 * Filters arguments used to query for installer pages from the WordPress.org Themes API. |
415 * |
454 * |
439 * @param object $args Arguments used to query for installer pages from the Themes API. |
478 * @param object $args Arguments used to query for installer pages from the Themes API. |
440 */ |
479 */ |
441 $res = apply_filters( 'themes_api', false, $action, $args ); |
480 $res = apply_filters( 'themes_api', false, $action, $args ); |
442 |
481 |
443 if ( ! $res ) { |
482 if ( ! $res ) { |
444 // include an unmodified $wp_version |
483 $url = 'http://api.wordpress.org/themes/info/1.2/'; |
445 include( ABSPATH . WPINC . '/version.php' ); |
484 $url = add_query_arg( |
446 |
485 array( |
447 $url = $http_url = 'http://api.wordpress.org/themes/info/1.0/'; |
486 'action' => $action, |
448 if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) |
487 'request' => $args, |
|
488 ), |
|
489 $url |
|
490 ); |
|
491 |
|
492 $http_url = $url; |
|
493 if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) { |
449 $url = set_url_scheme( $url, 'https' ); |
494 $url = set_url_scheme( $url, 'https' ); |
|
495 } |
450 |
496 |
451 $http_args = array( |
497 $http_args = array( |
452 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url( '/' ), |
498 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url( '/' ), |
453 'body' => array( |
|
454 'action' => $action, |
|
455 'request' => serialize( $args ) |
|
456 ) |
|
457 ); |
499 ); |
458 $request = wp_remote_post( $url, $http_args ); |
500 $request = wp_remote_get( $url, $http_args ); |
459 |
501 |
460 if ( $ssl && is_wp_error( $request ) ) { |
502 if ( $ssl && is_wp_error( $request ) ) { |
461 if ( ! wp_doing_ajax() ) { |
503 if ( ! wp_doing_ajax() ) { |
462 trigger_error( |
504 trigger_error( |
463 sprintf( |
505 sprintf( |
466 __( 'https://wordpress.org/support/' ) |
508 __( 'https://wordpress.org/support/' ) |
467 ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), |
509 ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), |
468 headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE |
510 headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE |
469 ); |
511 ); |
470 } |
512 } |
471 $request = wp_remote_post( $http_url, $http_args ); |
513 $request = wp_remote_get( $http_url, $http_args ); |
472 } |
514 } |
473 |
515 |
474 if ( is_wp_error($request) ) { |
516 if ( is_wp_error( $request ) ) { |
475 $res = new WP_Error( 'themes_api_failed', |
517 $res = new WP_Error( |
|
518 'themes_api_failed', |
476 sprintf( |
519 sprintf( |
477 /* translators: %s: support forums URL */ |
520 /* translators: %s: support forums URL */ |
478 __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), |
521 __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), |
479 __( 'https://wordpress.org/support/' ) |
522 __( 'https://wordpress.org/support/' ) |
480 ), |
523 ), |
481 $request->get_error_message() |
524 $request->get_error_message() |
482 ); |
525 ); |
483 } else { |
526 } else { |
484 $res = maybe_unserialize( wp_remote_retrieve_body( $request ) ); |
527 $res = json_decode( wp_remote_retrieve_body( $request ), true ); |
485 if ( ! is_object( $res ) && ! is_array( $res ) ) { |
528 if ( is_array( $res ) ) { |
486 $res = new WP_Error( 'themes_api_failed', |
529 // Object casting is required in order to match the info/1.0 format. |
|
530 $res = (object) $res; |
|
531 } elseif ( null === $res ) { |
|
532 $res = new WP_Error( |
|
533 'themes_api_failed', |
487 sprintf( |
534 sprintf( |
488 /* translators: %s: support forums URL */ |
535 /* translators: %s: support forums URL */ |
489 __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), |
536 __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server’s configuration. If you continue to have problems, please try the <a href="%s">support forums</a>.' ), |
490 __( 'https://wordpress.org/support/' ) |
537 __( 'https://wordpress.org/support/' ) |
491 ), |
538 ), |
492 wp_remote_retrieve_body( $request ) |
539 wp_remote_retrieve_body( $request ) |
493 ); |
540 ); |
494 } |
541 } |
|
542 |
|
543 if ( isset( $res->error ) ) { |
|
544 $res = new WP_Error( 'themes_api_failed', $res->error ); |
|
545 } |
|
546 } |
|
547 |
|
548 // Back-compat for info/1.2 API, upgrade the theme objects in query_themes to objects. |
|
549 if ( 'query_themes' == $action ) { |
|
550 foreach ( $res->themes as $i => $theme ) { |
|
551 $res->themes[ $i ] = (object) $theme; |
|
552 } |
|
553 } |
|
554 // Back-compat for info/1.2 API, downgrade the feature_list result back to an array. |
|
555 if ( 'feature_list' == $action ) { |
|
556 $res = (array) $res; |
495 } |
557 } |
496 } |
558 } |
497 |
559 |
498 /** |
560 /** |
499 * Filters the returned WordPress.org Themes API response. |
561 * Filters the returned WordPress.org Themes API response. |
560 WP_Theme::sort_by_name( $themes ); |
622 WP_Theme::sort_by_name( $themes ); |
561 |
623 |
562 $parents = array(); |
624 $parents = array(); |
563 |
625 |
564 foreach ( $themes as $theme ) { |
626 foreach ( $themes as $theme ) { |
565 $slug = $theme->get_stylesheet(); |
627 $slug = $theme->get_stylesheet(); |
566 $encoded_slug = urlencode( $slug ); |
628 $encoded_slug = urlencode( $slug ); |
567 |
629 |
568 $parent = false; |
630 $parent = false; |
569 if ( $theme->parent() ) { |
631 if ( $theme->parent() ) { |
570 $parent = $theme->parent(); |
632 $parent = $theme->parent(); |
571 $parents[ $slug ] = $parent->get_stylesheet(); |
633 $parents[ $slug ] = $parent->get_stylesheet(); |
572 $parent = $parent->display( 'Name' ); |
634 $parent = $parent->display( 'Name' ); |
573 } |
635 } |
574 |
636 |
575 $customize_action = null; |
637 $customize_action = null; |
576 if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { |
638 if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) { |
577 $customize_action = esc_url( add_query_arg( |
639 $customize_action = esc_url( |
578 array( |
640 add_query_arg( |
579 'return' => urlencode( esc_url_raw( remove_query_arg( wp_removable_query_args(), wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ), |
641 array( |
580 ), |
642 'return' => urlencode( esc_url_raw( remove_query_arg( wp_removable_query_args(), wp_unslash( $_SERVER['REQUEST_URI'] ) ) ) ), |
581 wp_customize_url( $slug ) |
643 ), |
582 ) ); |
644 wp_customize_url( $slug ) |
|
645 ) |
|
646 ); |
583 } |
647 } |
584 |
648 |
585 $prepared_themes[ $slug ] = array( |
649 $prepared_themes[ $slug ] = array( |
586 'id' => $slug, |
650 'id' => $slug, |
587 'name' => $theme->display( 'Name' ), |
651 'name' => $theme->display( 'Name' ), |
592 'version' => $theme->display( 'Version' ), |
656 'version' => $theme->display( 'Version' ), |
593 'tags' => $theme->display( 'Tags' ), |
657 'tags' => $theme->display( 'Tags' ), |
594 'parent' => $parent, |
658 'parent' => $parent, |
595 'active' => $slug === $current_theme, |
659 'active' => $slug === $current_theme, |
596 'hasUpdate' => isset( $updates[ $slug ] ), |
660 'hasUpdate' => isset( $updates[ $slug ] ), |
597 'hasPackage' => isset( $updates[ $slug ] ) && ! empty( $updates[ $slug ][ 'package' ] ), |
661 'hasPackage' => isset( $updates[ $slug ] ) && ! empty( $updates[ $slug ]['package'] ), |
598 'update' => get_theme_update_available( $theme ), |
662 'update' => get_theme_update_available( $theme ), |
599 'actions' => array( |
663 'actions' => array( |
600 'activate' => current_user_can( 'switch_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=activate&stylesheet=' . $encoded_slug ), 'switch-theme_' . $slug ) : null, |
664 'activate' => current_user_can( 'switch_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=activate&stylesheet=' . $encoded_slug ), 'switch-theme_' . $slug ) : null, |
601 'customize' => $customize_action, |
665 'customize' => $customize_action, |
602 'delete' => current_user_can( 'delete_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=delete&stylesheet=' . $encoded_slug ), 'delete-theme_' . $slug ) : null, |
666 'delete' => current_user_can( 'delete_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=delete&stylesheet=' . $encoded_slug ), 'delete-theme_' . $slug ) : null, |
603 ), |
667 ), |
604 ); |
668 ); |
605 } |
669 } |
606 |
670 |
607 // Remove 'delete' action if theme has an active child |
671 // Remove 'delete' action if theme has an active child |
702 </div> |
771 </div> |
703 </div> |
772 </div> |
704 </script> |
773 </script> |
705 <?php |
774 <?php |
706 } |
775 } |
|
776 |
|
777 /** |
|
778 * Determines whether a theme is technically active but was paused while |
|
779 * loading. |
|
780 * |
|
781 * For more information on this and similar theme functions, check out |
|
782 * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/ |
|
783 * Conditional Tags} article in the Theme Developer Handbook. |
|
784 * |
|
785 * @since 5.2.0 |
|
786 * |
|
787 * @param string $theme Path to the theme directory relative to the themes directory. |
|
788 * @return bool True, if in the list of paused themes. False, not in the list. |
|
789 */ |
|
790 function is_theme_paused( $theme ) { |
|
791 if ( ! isset( $GLOBALS['_paused_themes'] ) ) { |
|
792 return false; |
|
793 } |
|
794 |
|
795 if ( get_stylesheet() !== $theme && get_template() !== $theme ) { |
|
796 return false; |
|
797 } |
|
798 |
|
799 return array_key_exists( $theme, $GLOBALS['_paused_themes'] ); |
|
800 } |
|
801 |
|
802 /** |
|
803 * Gets the error that was recorded for a paused theme. |
|
804 * |
|
805 * @since 5.2.0 |
|
806 * |
|
807 * @param string $theme Path to the theme directory relative to the themes |
|
808 * directory. |
|
809 * @return array|false Array of error information as it was returned by |
|
810 * `error_get_last()`, or false if none was recorded. |
|
811 */ |
|
812 function wp_get_theme_error( $theme ) { |
|
813 if ( ! isset( $GLOBALS['_paused_themes'] ) ) { |
|
814 return false; |
|
815 } |
|
816 |
|
817 if ( ! array_key_exists( $theme, $GLOBALS['_paused_themes'] ) ) { |
|
818 return false; |
|
819 } |
|
820 |
|
821 return $GLOBALS['_paused_themes'][ $theme ]; |
|
822 } |
|
823 |
|
824 /** |
|
825 * Tries to resume a single theme. |
|
826 * |
|
827 * If a redirect was provided and a functions.php file was found, we first ensure that |
|
828 * functions.php file does not throw fatal errors anymore. |
|
829 * |
|
830 * The way it works is by setting the redirection to the error before trying to |
|
831 * include the file. If the theme fails, then the redirection will not be overwritten |
|
832 * with the success message and the theme will not be resumed. |
|
833 * |
|
834 * @since 5.2.0 |
|
835 * |
|
836 * @param string $theme Single theme to resume. |
|
837 * @param string $redirect Optional. URL to redirect to. Default empty string. |
|
838 * @return bool|WP_Error True on success, false if `$theme` was not paused, |
|
839 * `WP_Error` on failure. |
|
840 */ |
|
841 function resume_theme( $theme, $redirect = '' ) { |
|
842 list( $extension ) = explode( '/', $theme ); |
|
843 |
|
844 /* |
|
845 * We'll override this later if the theme could be resumed without |
|
846 * creating a fatal error. |
|
847 */ |
|
848 if ( ! empty( $redirect ) ) { |
|
849 $functions_path = ''; |
|
850 if ( strpos( STYLESHEETPATH, $extension ) ) { |
|
851 $functions_path = STYLESHEETPATH . '/functions.php'; |
|
852 } elseif ( strpos( TEMPLATEPATH, $extension ) ) { |
|
853 $functions_path = TEMPLATEPATH . '/functions.php'; |
|
854 } |
|
855 |
|
856 if ( ! empty( $functions_path ) ) { |
|
857 wp_redirect( |
|
858 add_query_arg( |
|
859 '_error_nonce', |
|
860 wp_create_nonce( 'theme-resume-error_' . $theme ), |
|
861 $redirect |
|
862 ) |
|
863 ); |
|
864 |
|
865 // Load the theme's functions.php to test whether it throws a fatal error. |
|
866 ob_start(); |
|
867 if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) { |
|
868 define( 'WP_SANDBOX_SCRAPING', true ); |
|
869 } |
|
870 include $functions_path; |
|
871 ob_clean(); |
|
872 } |
|
873 } |
|
874 |
|
875 $result = wp_paused_themes()->delete( $extension ); |
|
876 |
|
877 if ( ! $result ) { |
|
878 return new WP_Error( |
|
879 'could_not_resume_theme', |
|
880 __( 'Could not resume the theme.' ) |
|
881 ); |
|
882 } |
|
883 |
|
884 return true; |
|
885 } |
|
886 |
|
887 /** |
|
888 * Renders an admin notice in case some themes have been paused due to errors. |
|
889 * |
|
890 * @since 5.2.0 |
|
891 */ |
|
892 function paused_themes_notice() { |
|
893 if ( 'themes.php' === $GLOBALS['pagenow'] ) { |
|
894 return; |
|
895 } |
|
896 |
|
897 if ( ! current_user_can( 'resume_themes' ) ) { |
|
898 return; |
|
899 } |
|
900 |
|
901 if ( ! isset( $GLOBALS['_paused_themes'] ) || empty( $GLOBALS['_paused_themes'] ) ) { |
|
902 return; |
|
903 } |
|
904 |
|
905 printf( |
|
906 '<div class="notice notice-error"><p><strong>%s</strong><br>%s</p><p><a href="%s">%s</a></p></div>', |
|
907 __( 'One or more themes failed to load properly.' ), |
|
908 __( 'You can find more details and make changes on the Themes screen.' ), |
|
909 esc_url( admin_url( 'themes.php' ) ), |
|
910 __( 'Go to the Themes screen' ) |
|
911 ); |
|
912 } |