2007-05-25 09:16:21 +02:00
< ? php
2008-10-02 03:03:26 +02:00
/**
* WordPress Theme Administration API
*
* @ package WordPress
* @ subpackage Administration
*/
2007-05-25 09:16:21 +02:00
2009-03-05 20:15:56 +01:00
/**
* Remove a theme
*
* @ since 2.8 . 0
*
2012-06-06 22:34:24 +02:00
* @ param string $stylesheet Stylesheet of the theme to delete
2011-01-07 20:01:34 +01:00
* @ param string $redirect Redirect to page when complete .
2009-03-05 20:15:56 +01:00
* @ return mixed
*/
2012-06-06 22:34:24 +02:00
function delete_theme ( $stylesheet , $redirect = '' ) {
2009-03-05 20:15:56 +01:00
global $wp_filesystem ;
2012-06-06 22:34:24 +02:00
if ( empty ( $stylesheet ) )
2009-03-05 20:15:56 +01:00
return false ;
ob_start ();
2011-01-07 20:01:34 +01:00
if ( empty ( $redirect ) )
2012-09-05 00:35:12 +02:00
$redirect = wp_nonce_url ( 'themes.php?action=delete&stylesheet=' . urlencode ( $stylesheet ), 'delete-theme_' . $stylesheet );
2011-01-07 20:01:34 +01:00
if ( false === ( $credentials = request_filesystem_credentials ( $redirect )) ) {
2009-03-05 20:15:56 +01:00
$data = ob_get_contents ();
ob_end_clean ();
if ( ! empty ( $data ) ){
include_once ( ABSPATH . 'wp-admin/admin-header.php' );
echo $data ;
include ( ABSPATH . 'wp-admin/admin-footer.php' );
exit ;
}
return ;
}
if ( ! WP_Filesystem ( $credentials ) ) {
2013-07-08 19:10:47 +02:00
request_filesystem_credentials ( $redirect , '' , true ); // Failed to connect, Error and request again
2009-03-05 20:15:56 +01:00
$data = ob_get_contents ();
ob_end_clean ();
2010-01-18 21:34:48 +01:00
if ( ! empty ( $data ) ) {
2009-03-05 20:15:56 +01:00
include_once ( ABSPATH . 'wp-admin/admin-header.php' );
echo $data ;
include ( ABSPATH . 'wp-admin/admin-footer.php' );
exit ;
}
return ;
}
if ( ! is_object ( $wp_filesystem ) )
return new WP_Error ( 'fs_unavailable' , __ ( 'Could not access filesystem.' ));
2009-04-19 21:36:28 +02:00
if ( is_wp_error ( $wp_filesystem -> errors ) && $wp_filesystem -> errors -> get_error_code () )
2010-01-21 22:37:43 +01:00
return new WP_Error ( 'fs_error' , __ ( 'Filesystem error.' ), $wp_filesystem -> errors );
2009-03-05 20:15:56 +01:00
//Get the base plugin folder
$themes_dir = $wp_filesystem -> wp_themes_dir ();
if ( empty ( $themes_dir ) )
return new WP_Error ( 'fs_no_themes_dir' , __ ( 'Unable to locate WordPress theme directory.' ));
$themes_dir = trailingslashit ( $themes_dir );
2012-06-06 22:34:24 +02:00
$theme_dir = trailingslashit ( $themes_dir . $stylesheet );
2009-03-05 20:15:56 +01:00
$deleted = $wp_filesystem -> delete ( $theme_dir , true );
if ( ! $deleted )
2012-06-06 22:34:24 +02:00
return new WP_Error ( 'could_not_remove_theme' , sprintf ( __ ( 'Could not fully remove the theme %s.' ), $stylesheet ) );
2009-03-05 20:15:56 +01:00
// Force refresh of theme update information
2010-01-08 21:49:55 +01:00
delete_site_transient ( 'update_themes' );
2009-03-05 20:15:56 +01:00
return true ;
}
2008-10-02 03:03:26 +02:00
/**
2009-11-13 23:40:40 +01:00
* Get the Page Templates available in this theme
2008-10-02 03:03:26 +02:00
*
2010-12-01 20:24:38 +01:00
* @ since 1.5 . 0
2008-10-02 03:03:26 +02:00
*
2011-04-13 13:50:27 +02:00
* @ return array Key is the template name , value is the filename of the template
2008-10-02 03:03:26 +02:00
*/
2007-05-25 09:16:21 +02:00
function get_page_templates () {
2012-02-29 21:18:53 +01:00
return array_flip ( wp_get_theme () -> get_page_templates () );
2007-05-25 09:16:21 +02:00
}
2009-10-19 23:39:04 +02:00
/**
* Tidies a filename for url display by the theme editor .
2010-01-15 23:11:12 +01:00
*
2009-10-19 23:39:04 +02:00
* @ since 2.9 . 0
2010-05-03 15:27:15 +02:00
* @ access private
2010-01-15 23:11:12 +01:00
*
2009-10-19 23:39:04 +02:00
* @ param string $fullpath Full path to the theme file
* @ param string $containingfolder Path of the theme parent folder
* @ return string
*/
function _get_template_edit_filename ( $fullpath , $containingfolder ) {
return str_replace ( dirname ( dirname ( $containingfolder )) , '' , $fullpath );
}
2010-05-03 15:29:15 +02:00
/**
* Check if there is an update for a theme available .
*
* Will display link , if there is an update available .
*
* @ since 2.7 . 0
*
* @ param object $theme Theme data object .
* @ return bool False if no valid info was passed .
*/
function theme_update_available ( $theme ) {
static $themes_update ;
if ( ! current_user_can ( 'update_themes' ) )
return ;
if ( ! isset ( $themes_update ) )
$themes_update = get_site_transient ( 'update_themes' );
Introduce WP_Theme, wp_get_themes(), and wp_get_theme() to replace get_themes(), get_theme(), get_theme_data(), current_theme_info(), and others.
* Getters and Helpers: Introduces a series of methods to allow for easy generation of headers for display, and other theme metadata, including page templates.
* Screenshots: Handles support for multiple screenshots. (see # Additional screenshots must be PNG and start with screenshot-2.png, and be sequential to be counted. see #19816.
* Error Handling: Broken themes have a WP_Error object attached to them.
* Caching: Introduces a wp_cache_themes_persistently filter (also in [20020]) to enable persistent caching of all filesystem and sanitization operations normally handled by WP_Theme (and formerly get_file_data() and get_themes()). Themes are cached individually and across five different cache keys for different data pieces.
* Compatibility: A WP_Theme object is backwards compatible with a theme's array formerly returned by get_themes() and get_theme(), and an stdClass object formerly returned by current_theme_info().
* i18n/L10n: Theme headers are now localizable with proper Text Domain and Domain Path headers, like plugins. (Language packs may remove the requirement for headers.) For page templates, see #6007 (not fixed yet, but will be easy now). For headers, fixes #15858.
* PHP and CSS files: New methods that fetch a list of theme files (for the theme editor) only on demand, rather than only loading them into memory. fixes #11214.
Functions deprecated:
* get_themes(), get_allowed_themes() and get_broken_themes() -- use wp_get_themes()
* get_theme() and current_theme_info() -- use wp_get_theme()
* get_site_allowed_themes() -- use WP_Theme::get_allowed_on_network()
* wpmu_get_blog_allowedthemes() -- use WP_theme::get_allowed_on_site()
see also [20016], [20018], [20019], [20020], [20021], [20022], [20025], [20026], [20027]. also fixes #19244.
see #20103.
git-svn-id: http://svn.automattic.com/wordpress/trunk@20029 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2012-02-28 22:24:44 +01:00
if ( ! is_a ( $theme , 'WP_Theme' ) )
return ;
$stylesheet = $theme -> get_stylesheet ();
2010-05-03 15:29:15 +02:00
if ( isset ( $themes_update -> response [ $stylesheet ]) ) {
$update = $themes_update -> response [ $stylesheet ];
2012-05-07 18:16:17 +02:00
$theme_name = $theme -> display ( 'Name' );
2010-05-03 15:29:15 +02:00
$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.
$update_url = wp_nonce_url ( 'update.php?action=upgrade-theme&theme=' . urlencode ( $stylesheet ), 'upgrade-theme_' . $stylesheet );
2011-12-14 00:45:31 +01:00
$update_onclick = 'onclick="if ( confirm(\'' . esc_js ( __ ( " Updating this theme will lose any customizations you have made. 'Cancel' to stop, 'OK' to update. " ) ) . '\') ) {return true;}return false;"' ;
2010-05-03 15:29:15 +02:00
2010-11-30 04:03:40 +01:00
if ( ! is_multisite () ) {
if ( ! current_user_can ( 'update_themes' ) )
printf ( '<p><strong>' . __ ( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%1$s">View version %3$s details</a>.' ) . '</strong></p>' , $theme_name , $details_url , $update [ 'new_version' ]);
else if ( empty ( $update [ 'package' ]) )
2010-12-02 22:45:47 +01:00
printf ( '<p><strong>' . __ ( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%1$s">View version %3$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ) . '</strong></p>' , $theme_name , $details_url , $update [ 'new_version' ]);
2010-11-30 04:03:40 +01:00
else
2012-03-21 17:19:27 +01:00
printf ( '<p><strong>' . __ ( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox" title="%1$s">View version %3$s details</a> or <a href="%4$s" %5$s>update now</a>.' ) . '</strong></p>' , $theme_name , $details_url , $update [ 'new_version' ], $update_url , $update_onclick );
2010-11-30 04:03:40 +01:00
}
2010-05-03 15:29:15 +02:00
}
}
2010-09-24 17:28:28 +02:00
/**
* Retrieve list of WordPress theme features ( aka theme tags )
*
* @ since 3.1 . 0
*
2012-02-28 21:38:09 +01:00
* @ param bool $api Optional . Whether try to fetch tags from the WP . org API . Defaults to true .
2011-12-14 18:36:38 +01:00
* @ return array Array of features keyed by category with translations keyed by slug .
2010-09-24 17:28:28 +02:00
*/
2012-02-28 21:38:09 +01:00
function get_theme_feature_list ( $api = true ) {
2010-09-24 17:28:28 +02:00
// Hard-coded list is used if api not accessible.
$features = array (
2012-08-24 17:22:14 +02:00
__ ( 'Colors' ) => array (
2010-09-24 17:28:28 +02:00
'black' => __ ( 'Black' ),
'blue' => __ ( 'Blue' ),
'brown' => __ ( 'Brown' ),
2011-06-22 21:45:21 +02:00
'gray' => __ ( 'Gray' ),
2010-09-24 17:28:28 +02:00
'green' => __ ( 'Green' ),
'orange' => __ ( 'Orange' ),
'pink' => __ ( 'Pink' ),
'purple' => __ ( 'Purple' ),
'red' => __ ( 'Red' ),
'silver' => __ ( 'Silver' ),
'tan' => __ ( 'Tan' ),
'white' => __ ( 'White' ),
'yellow' => __ ( 'Yellow' ),
'dark' => __ ( 'Dark' ),
2012-02-28 21:38:09 +01:00
'light' => __ ( 'Light' ),
2010-09-24 17:28:28 +02:00
),
2012-08-24 17:22:14 +02:00
__ ( 'Columns' ) => array (
2010-09-24 17:28:28 +02:00
'one-column' => __ ( 'One Column' ),
'two-columns' => __ ( 'Two Columns' ),
'three-columns' => __ ( 'Three Columns' ),
'four-columns' => __ ( 'Four Columns' ),
'left-sidebar' => __ ( 'Left Sidebar' ),
2012-02-28 21:38:09 +01:00
'right-sidebar' => __ ( 'Right Sidebar' ),
2010-09-24 17:28:28 +02:00
),
2012-08-24 17:22:14 +02:00
__ ( 'Width' ) => array (
2010-09-24 17:28:28 +02:00
'fixed-width' => __ ( 'Fixed Width' ),
2012-02-28 21:38:09 +01:00
'flexible-width' => __ ( 'Flexible Width' ),
2010-09-24 17:28:28 +02:00
),
__ ( 'Features' ) => array (
2011-06-22 21:45:21 +02:00
'blavatar' => __ ( 'Blavatar' ),
'buddypress' => __ ( 'BuddyPress' ),
'custom-background' => __ ( 'Custom Background' ),
'custom-colors' => __ ( 'Custom Colors' ),
'custom-header' => __ ( 'Custom Header' ),
'custom-menu' => __ ( 'Custom Menu' ),
'editor-style' => __ ( 'Editor Style' ),
'featured-image-header' => __ ( 'Featured Image Header' ),
'featured-images' => __ ( 'Featured Images' ),
2012-08-24 17:22:14 +02:00
'flexible-header' => __ ( 'Flexible Header' ),
2011-06-22 21:45:21 +02:00
'front-page-post-form' => __ ( 'Front Page Posting' ),
'full-width-template' => __ ( 'Full Width Template' ),
'microformats' => __ ( 'Microformats' ),
'post-formats' => __ ( 'Post Formats' ),
'rtl-language-support' => __ ( 'RTL Language Support' ),
'sticky-post' => __ ( 'Sticky Post' ),
'theme-options' => __ ( 'Theme Options' ),
'threaded-comments' => __ ( 'Threaded Comments' ),
2012-02-28 21:38:09 +01:00
'translation-ready' => __ ( 'Translation Ready' ),
2010-09-24 17:28:28 +02:00
),
__ ( 'Subject' ) => array (
2011-06-22 21:45:21 +02:00
'holiday' => __ ( 'Holiday' ),
2010-09-24 17:28:28 +02:00
'photoblogging' => __ ( 'Photoblogging' ),
2012-02-28 21:38:09 +01:00
'seasonal' => __ ( 'Seasonal' ),
2010-09-24 17:28:28 +02:00
)
);
2012-02-28 21:38:09 +01:00
if ( ! $api || ! current_user_can ( 'install_themes' ) )
2010-09-24 17:28:28 +02:00
return $features ;
if ( ! $feature_list = get_site_transient ( 'wporg_theme_feature_list' ) )
2013-01-04 11:13:51 +01:00
set_site_transient ( 'wporg_theme_feature_list' , array (), 10800 );
2010-09-24 17:28:28 +02:00
if ( ! $feature_list ) {
2013-01-04 11:13:51 +01:00
$feature_list = themes_api ( 'feature_list' , array () );
2010-09-24 17:28:28 +02:00
if ( is_wp_error ( $feature_list ) )
return $features ;
}
if ( ! $feature_list )
return $features ;
set_site_transient ( 'wporg_theme_feature_list' , $feature_list , 10800 );
$category_translations = array ( 'Colors' => __ ( 'Colors' ), 'Columns' => __ ( 'Columns' ), 'Width' => __ ( 'Width' ),
'Features' => __ ( 'Features' ), 'Subject' => __ ( 'Subject' ) );
// Loop over the wporg canonical list and apply translations
$wporg_features = array ();
foreach ( ( array ) $feature_list as $feature_category => $feature_items ) {
if ( isset ( $category_translations [ $feature_category ]) )
$feature_category = $category_translations [ $feature_category ];
$wporg_features [ $feature_category ] = array ();
foreach ( $feature_items as $feature ) {
if ( isset ( $features [ $feature_category ][ $feature ]) )
$wporg_features [ $feature_category ][ $feature ] = $features [ $feature_category ][ $feature ];
else
$wporg_features [ $feature_category ][ $feature ] = $feature ;
}
}
return $wporg_features ;
}
2010-10-05 15:24:41 +02:00
/**
* Retrieve theme installer pages from WordPress Themes API .
*
* It is possible for a theme to override the Themes API result with three
* filters . Assume this is for themes , which can extend on the Theme Info to
* offer more choices . This is very powerful and must be used with care , when
* overridding the filters .
*
* The first filter , 'themes_api_args' , is for the args and gives the action as
* the second parameter . The hook for 'themes_api_args' must ensure that an
* object is returned .
*
* The second filter , 'themes_api' , is the result that would be returned .
*
* @ since 2.8 . 0
*
2013-10-30 15:39:10 +01:00
* @ param string $action The requested action . Likely values are 'theme_information' ,
* 'feature_list' , or 'query_themes' .
* @ param array | object $args Optional . Arguments to serialize for the Theme Info API .
2010-10-05 15:24:41 +02:00
* @ return mixed
*/
2013-10-30 15:39:10 +01:00
function themes_api ( $action , $args = null ) {
2010-10-05 15:24:41 +02:00
if ( is_array ( $args ) )
$args = ( object ) $args ;
if ( ! isset ( $args -> per_page ) )
$args -> per_page = 24 ;
2013-10-30 15:39:10 +01:00
/**
* Filter arguments used to query for installer pages from the WordPress . org Themes API .
*
* Important : An object MUST be returned to this filter .
*
* @ since 2.8 . 0
*
* @ param object $args Arguments used to query for installer pages from the WordPress . org Themes API .
* @ param string $action Requested action . Likely values are 'theme_information' ,
* 'feature_list' , or 'query_themes' .
*/
$args = apply_filters ( 'themes_api_args' , $args , $action );
/**
* Filter whether to override the WordPress . org Themes API .
*
* Returning a value of true to this filter allows a theme to completely
* override the built - in WordPress . org API .
*
* @ since 2.8 . 0
*
* @ param bool $bool Whether to override the WordPress . org Themes API . Default false .
* @ param string $action Requested action . Likely values are 'theme_information' ,
* 'feature_list' , or 'query_themes' .
* @ param object $args Arguments used to query for installer pages from the Themes API .
*/
$res = apply_filters ( 'themes_api' , false , $action , $args );
2010-10-05 15:24:41 +02:00
if ( ! $res ) {
2013-10-27 22:09:10 +01:00
$url = $http_url = 'http://api.wordpress.org/themes/info/1.0/' ;
if ( $ssl = wp_http_supports ( array ( 'ssl' ) ) )
2013-09-09 09:54:11 +02:00
$url = set_url_scheme ( $url , 'https' );
2013-10-27 22:09:10 +01:00
$args = array (
2013-09-09 09:54:11 +02:00
'body' => array (
'action' => $action ,
'request' => serialize ( $args )
)
2013-10-27 22:09:10 +01:00
);
$request = wp_remote_post ( $url , $args );
if ( $ssl && is_wp_error ( $request ) ) {
trigger_error ( __ ( '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="http://wordpress.org/support/">support forums</a>.' ) . ' ' . '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' , headers_sent () || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
$request = wp_remote_post ( $http_url , $args );
}
2013-09-09 09:54:11 +02:00
2010-10-05 15:24:41 +02:00
if ( is_wp_error ( $request ) ) {
2012-05-09 17:55:59 +02:00
$res = new WP_Error ( 'themes_api_failed' , __ ( '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="http://wordpress.org/support/">support forums</a>.' ), $request -> get_error_message () );
2010-10-05 15:24:41 +02:00
} else {
2012-01-08 04:48:05 +01:00
$res = maybe_unserialize ( wp_remote_retrieve_body ( $request ) );
if ( ! is_object ( $res ) && ! is_array ( $res ) )
2012-05-09 17:55:59 +02:00
$res = new WP_Error ( 'themes_api_failed' , __ ( '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="http://wordpress.org/support/">support forums</a>.' ), wp_remote_retrieve_body ( $request ) );
2010-10-05 15:24:41 +02:00
}
}
2012-01-08 04:48:05 +01:00
2013-10-30 15:39:10 +01:00
/**
* Filter the returned WordPress . org Themes API response .
*
* @ since 2.8 . 0
*
* @ param array | object $res WordPress . org Themes API response .
* @ param string $action Requested action . Likely values are 'theme_information' ,
* 'feature_list' , or 'query_themes' .
* @ param object $args Arguments used to query for installer pages from the WordPress . org Themes API .
*/
return apply_filters ( 'themes_api_result' , $res , $action , $args );
2010-10-05 15:24:41 +02:00
}
2013-11-13 21:58:05 +01:00
/**
* Prepare themes for JavaScript .
*
* @ since 3.8 . 0
*
* @ param array $themes Optional . Array of WP_Theme objects to prepare .
* Defaults to all allowed themes .
*
* @ return array An associative array of theme data .
*/
function wp_prepare_themes_for_js ( $themes = null ) {
if ( null === $themes ) {
$themes = wp_get_themes ( array ( 'allowed' => true ) );
}
$prepared_themes = array ();
$current_theme = get_stylesheet ();
$updates = array ();
if ( current_user_can ( 'update_themes' ) ) {
$updates = get_site_transient ( 'update_themes' );
$updates = $updates -> response ;
}
foreach ( $themes as $slug => $theme ) {
$parent = false ;
if ( $theme -> parent () ) {
$parent = $theme -> parent () -> display ( 'Name' );
}
$encoded_slug = urlencode ( $slug );
$prepared_themes [] = array (
'id' => $slug ,
'name' => $theme -> display ( 'Name' ),
'screenshot' => array ( $theme -> get_screenshot () ), // @todo multiple
'description' => $theme -> display ( 'Description' ),
'author' => $theme -> get ( 'Author' ),
'authorURI' => $theme -> get ( 'AuthorURI' ),
'version' => $theme -> get ( 'Version' ),
'tags' => $theme -> get ( 'Tags' ),
'parent' => $parent ,
'active' => $slug === $current_theme ,
'hasUpdate' => isset ( $updates [ $slug ] ),
'update' => 'New version available' , // @todo complete this
'actions' => array (
'activate' => wp_nonce_url ( 'themes.php?action=activate&stylesheet=' . $encoded_slug , 'switch-theme_' . $slug ),
'customize' => admin_url ( 'customize.php?theme=' . $encoded_slug ),
'delete' => wp_nonce_url ( 'themes.php?action=delete&stylesheet=' . $encoded_slug , 'delete-theme_' . $slug ),
),
);
}
return $prepared_themes ;
}