Wordpress 3.3
[autoinstalls/wordpress.git] / wp-admin / includes / theme.php
1 <?php
2 /**
3  * WordPress Theme Administration API
4  *
5  * @package WordPress
6  * @subpackage Administration
7  */
8
9 /**
10  * {@internal Missing Short Description}}
11  *
12  * @since 2.0.0
13  *
14  * @return unknown
15  */
16 function current_theme_info() {
17         $themes = get_themes();
18         $current_theme = get_current_theme();
19
20         if ( ! $themes ) {
21                 $ct = new stdClass;
22                 $ct->name = $current_theme;
23                 return $ct;
24         }
25
26         if ( ! isset( $themes[$current_theme] ) ) {
27                 delete_option( 'current_theme' );
28                 $current_theme = get_current_theme();
29         }
30
31         $ct = new stdClass;
32         $ct->name = $current_theme;
33         $ct->title = $themes[$current_theme]['Title'];
34         $ct->version = $themes[$current_theme]['Version'];
35         $ct->parent_theme = $themes[$current_theme]['Parent Theme'];
36         $ct->template_dir = $themes[$current_theme]['Template Dir'];
37         $ct->stylesheet_dir = $themes[$current_theme]['Stylesheet Dir'];
38         $ct->template = $themes[$current_theme]['Template'];
39         $ct->stylesheet = $themes[$current_theme]['Stylesheet'];
40         $ct->screenshot = $themes[$current_theme]['Screenshot'];
41         $ct->description = $themes[$current_theme]['Description'];
42         $ct->author = $themes[$current_theme]['Author'];
43         $ct->tags = $themes[$current_theme]['Tags'];
44         $ct->theme_root = $themes[$current_theme]['Theme Root'];
45         $ct->theme_root_uri = $themes[$current_theme]['Theme Root URI'];
46         return $ct;
47 }
48
49 /**
50  * Remove a theme
51  *
52  * @since 2.8.0
53  *
54  * @param string $template Template directory of the theme to delete
55  * @param string $redirect Redirect to page when complete.
56  * @return mixed
57  */
58 function delete_theme($template, $redirect = '') {
59         global $wp_filesystem;
60
61         if ( empty($template) )
62                 return false;
63
64         ob_start();
65         if ( empty( $redirect ) )
66                 $redirect = wp_nonce_url('themes.php?action=delete&template=' . $template, 'delete-theme_' . $template);
67         if ( false === ($credentials = request_filesystem_credentials($redirect)) ) {
68                 $data = ob_get_contents();
69                 ob_end_clean();
70                 if ( ! empty($data) ){
71                         include_once( ABSPATH . 'wp-admin/admin-header.php');
72                         echo $data;
73                         include( ABSPATH . 'wp-admin/admin-footer.php');
74                         exit;
75                 }
76                 return;
77         }
78
79         if ( ! WP_Filesystem($credentials) ) {
80                 request_filesystem_credentials($url, '', true); // Failed to connect, Error and request again
81                 $data = ob_get_contents();
82                 ob_end_clean();
83                 if ( ! empty($data) ) {
84                         include_once( ABSPATH . 'wp-admin/admin-header.php');
85                         echo $data;
86                         include( ABSPATH . 'wp-admin/admin-footer.php');
87                         exit;
88                 }
89                 return;
90         }
91
92
93         if ( ! is_object($wp_filesystem) )
94                 return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
95
96         if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
97                 return new WP_Error('fs_error', __('Filesystem error.'), $wp_filesystem->errors);
98
99         //Get the base plugin folder
100         $themes_dir = $wp_filesystem->wp_themes_dir();
101         if ( empty($themes_dir) )
102                 return new WP_Error('fs_no_themes_dir', __('Unable to locate WordPress theme directory.'));
103
104         $themes_dir = trailingslashit( $themes_dir );
105         $theme_dir = trailingslashit($themes_dir . $template);
106         $deleted = $wp_filesystem->delete($theme_dir, true);
107
108         if ( ! $deleted )
109                 return new WP_Error('could_not_remove_theme', sprintf(__('Could not fully remove the theme %s.'), $template) );
110
111         // Force refresh of theme update information
112         delete_site_transient('update_themes');
113
114         return true;
115 }
116
117 /**
118  * {@internal Missing Short Description}}
119  *
120  * @since 1.5.0
121  *
122  * @return unknown
123  */
124 function get_broken_themes() {
125         global $wp_broken_themes;
126
127         get_themes();
128         return $wp_broken_themes;
129 }
130
131 /**
132  * Get the allowed themes for the current blog.
133  *
134  * @since 3.0.0
135  *
136  * @uses get_themes()
137  * @uses current_theme_info()
138  * @uses get_site_allowed_themes()
139  * @uses wpmu_get_blog_allowedthemes
140  *
141  * @return array $themes Array of allowed themes.
142  */
143 function get_allowed_themes() {
144         if ( !is_multisite() )
145                 return get_themes();
146
147         $themes = get_themes();
148         $ct = current_theme_info();
149         $allowed_themes = apply_filters("allowed_themes", get_site_allowed_themes() );
150         if ( $allowed_themes == false )
151                 $allowed_themes = array();
152
153         $blog_allowed_themes = wpmu_get_blog_allowedthemes();
154         if ( is_array( $blog_allowed_themes ) )
155                 $allowed_themes = array_merge( $allowed_themes, $blog_allowed_themes );
156
157         if ( isset( $allowed_themes[ esc_html( $ct->stylesheet ) ] ) == false )
158                 $allowed_themes[ esc_html( $ct->stylesheet ) ] = true;
159
160         reset( $themes );
161         foreach ( $themes as $key => $theme ) {
162                 if ( isset( $allowed_themes[ esc_html( $theme[ 'Stylesheet' ] ) ] ) == false )
163                         unset( $themes[ $key ] );
164         }
165         reset( $themes );
166
167         return $themes;
168 }
169
170 /**
171  * Get the Page Templates available in this theme
172  *
173  * @since 1.5.0
174  *
175  * @return array Key is the template name, value is the filename of the template
176  */
177 function get_page_templates() {
178         $themes = get_themes();
179         $theme = get_current_theme();
180         $templates = $themes[$theme]['Template Files'];
181         $page_templates = array();
182
183         if ( is_array( $templates ) ) {
184                 $base = array( trailingslashit(get_template_directory()), trailingslashit(get_stylesheet_directory()) );
185
186                 foreach ( $templates as $template ) {
187                         $basename = str_replace($base, '', $template);
188
189                         // don't allow template files in subdirectories
190                         if ( false !== strpos($basename, '/') )
191                                 continue;
192
193                         if ( 'functions.php' == $basename )
194                                 continue;
195
196                         $template_data = implode( '', file( $template ));
197
198                         $name = '';
199                         if ( preg_match( '|Template Name:(.*)$|mi', $template_data, $name ) )
200                                 $name = _cleanup_header_comment($name[1]);
201
202                         if ( !empty( $name ) ) {
203                                 $page_templates[trim( $name )] = $basename;
204                         }
205                 }
206         }
207
208         return $page_templates;
209 }
210
211 /**
212  * Tidies a filename for url display by the theme editor.
213  *
214  * @since 2.9.0
215  * @access private
216  *
217  * @param string $fullpath Full path to the theme file
218  * @param string $containingfolder Path of the theme parent folder
219  * @return string
220  */
221 function _get_template_edit_filename($fullpath, $containingfolder) {
222         return str_replace(dirname(dirname( $containingfolder )) , '', $fullpath);
223 }
224
225 /**
226  * Check if there is an update for a theme available.
227  *
228  * Will display link, if there is an update available.
229  *
230  * @since 2.7.0
231  *
232  * @param object $theme Theme data object.
233  * @return bool False if no valid info was passed.
234  */
235 function theme_update_available( $theme ) {
236         static $themes_update;
237
238         if ( !current_user_can('update_themes' ) )
239                 return;
240
241         if ( !isset($themes_update) )
242                 $themes_update = get_site_transient('update_themes');
243
244         if ( is_object($theme) && isset($theme->stylesheet) )
245                 $stylesheet = $theme->stylesheet;
246         elseif ( is_array($theme) && isset($theme['Stylesheet']) )
247                 $stylesheet = $theme['Stylesheet'];
248         else
249                 return false; //No valid info passed.
250
251         if ( isset($themes_update->response[ $stylesheet ]) ) {
252                 $update = $themes_update->response[ $stylesheet ];
253                 $theme_name = is_object($theme) ? $theme->name : (is_array($theme) ? $theme['Name'] : '');
254                 $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.
255                 $update_url = wp_nonce_url('update.php?action=upgrade-theme&amp;theme=' . urlencode($stylesheet), 'upgrade-theme_' . $stylesheet);
256                 $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;"';
257
258                 if ( !is_multisite() ) {
259                         if ( ! current_user_can('update_themes') )
260                                 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']);
261                         else if ( empty($update['package']) )
262                                 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']);
263                         else
264                                 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 automatically</a>.') . '</strong></p>', $theme_name, $details_url, $update['new_version'], $update_url, $update_onclick );
265                 }
266         }
267 }
268
269 /**
270  * Retrieve list of WordPress theme features (aka theme tags)
271  *
272  * @since 3.1.0
273  *
274  * @return array  Array of features keyed by category with translations keyed by slug.
275  */
276 function get_theme_feature_list() {
277         // Hard-coded list is used if api not accessible.
278         $features = array(
279                         __('Colors') => array(
280                                 'black'   => __( 'Black' ),
281                                 'blue'    => __( 'Blue' ),
282                                 'brown'   => __( 'Brown' ),
283                                 'gray'    => __( 'Gray' ),
284                                 'green'   => __( 'Green' ),
285                                 'orange'  => __( 'Orange' ),
286                                 'pink'    => __( 'Pink' ),
287                                 'purple'  => __( 'Purple' ),
288                                 'red'     => __( 'Red' ),
289                                 'silver'  => __( 'Silver' ),
290                                 'tan'     => __( 'Tan' ),
291                                 'white'   => __( 'White' ),
292                                 'yellow'  => __( 'Yellow' ),
293                                 'dark'    => __( 'Dark' ),
294                                 'light'   => __( 'Light ')
295                         ),
296
297                 __('Columns') => array(
298                         'one-column'    => __( 'One Column' ),
299                         'two-columns'   => __( 'Two Columns' ),
300                         'three-columns' => __( 'Three Columns' ),
301                         'four-columns'  => __( 'Four Columns' ),
302                         'left-sidebar'  => __( 'Left Sidebar' ),
303                         'right-sidebar' => __( 'Right Sidebar' )
304                 ),
305
306                 __('Width') => array(
307                         'fixed-width'    => __( 'Fixed Width' ),
308                         'flexible-width' => __( 'Flexible Width' )
309                 ),
310
311                 __( 'Features' ) => array(
312                         'blavatar'              => __( 'Blavatar' ),
313                         'buddypress'            => __( 'BuddyPress' ),
314                         'custom-background'     => __( 'Custom Background' ),
315                         'custom-colors'         => __( 'Custom Colors' ),
316                         'custom-header'         => __( 'Custom Header' ),
317                         'custom-menu'           => __( 'Custom Menu' ),
318                         'editor-style'          => __( 'Editor Style' ),
319                         'featured-image-header' => __( 'Featured Image Header' ),
320                         'featured-images'       => __( 'Featured Images' ),
321                         'front-page-post-form'  => __( 'Front Page Posting' ),
322                         'full-width-template'   => __( 'Full Width Template' ),
323                         'microformats'          => __( 'Microformats' ),
324                         'post-formats'          => __( 'Post Formats' ),
325                         'rtl-language-support'  => __( 'RTL Language Support' ),
326                         'sticky-post'           => __( 'Sticky Post' ),
327                         'theme-options'         => __( 'Theme Options' ),
328                         'threaded-comments'     => __( 'Threaded Comments' ),
329                         'translation-ready'     => __( 'Translation Ready' )
330                 ),
331
332                 __( 'Subject' )  => array(
333                         'holiday'       => __( 'Holiday' ),
334                         'photoblogging' => __( 'Photoblogging' ),
335                         'seasonal'      => __( 'Seasonal' )
336                 )
337         );
338
339         if ( !current_user_can('install_themes') )
340                 return $features;
341
342         if ( !$feature_list = get_site_transient( 'wporg_theme_feature_list' ) )
343                 set_site_transient( 'wporg_theme_feature_list', array( ),  10800);
344
345         if ( !$feature_list ) {
346                 $feature_list = themes_api( 'feature_list', array( ) );
347                 if ( is_wp_error( $feature_list ) )
348                         return $features;
349         }
350
351         if ( !$feature_list )
352                 return $features;
353
354         set_site_transient( 'wporg_theme_feature_list', $feature_list, 10800 );
355
356         $category_translations = array( 'Colors' => __('Colors'), 'Columns' => __('Columns'), 'Width' => __('Width'),
357                                                                    'Features' => __('Features'), 'Subject' => __('Subject') );
358
359         // Loop over the wporg canonical list and apply translations
360         $wporg_features = array();
361         foreach ( (array) $feature_list as $feature_category => $feature_items ) {
362                 if ( isset($category_translations[$feature_category]) )
363                         $feature_category = $category_translations[$feature_category];
364                 $wporg_features[$feature_category] = array();
365
366                 foreach ( $feature_items as $feature ) {
367                         if ( isset($features[$feature_category][$feature]) )
368                                 $wporg_features[$feature_category][$feature] = $features[$feature_category][$feature];
369                         else
370                                 $wporg_features[$feature_category][$feature] = $feature;
371                 }
372         }
373
374         return $wporg_features;
375 }
376
377 /**
378  * Retrieve theme installer pages from WordPress Themes API.
379  *
380  * It is possible for a theme to override the Themes API result with three
381  * filters. Assume this is for themes, which can extend on the Theme Info to
382  * offer more choices. This is very powerful and must be used with care, when
383  * overridding the filters.
384  *
385  * The first filter, 'themes_api_args', is for the args and gives the action as
386  * the second parameter. The hook for 'themes_api_args' must ensure that an
387  * object is returned.
388  *
389  * The second filter, 'themes_api', is the result that would be returned.
390  *
391  * @since 2.8.0
392  *
393  * @param string $action
394  * @param array|object $args Optional. Arguments to serialize for the Theme Info API.
395  * @return mixed
396  */
397 function themes_api($action, $args = null) {
398
399         if ( is_array($args) )
400                 $args = (object)$args;
401
402         if ( !isset($args->per_page) )
403                 $args->per_page = 24;
404
405         $args = apply_filters('themes_api_args', $args, $action); //NOTE: Ensure that an object is returned via this filter.
406         $res = apply_filters('themes_api', false, $action, $args); //NOTE: Allows a theme to completely override the builtin WordPress.org API.
407
408         if ( ! $res ) {
409                 $request = wp_remote_post('http://api.wordpress.org/themes/info/1.0/', array( 'body' => array('action' => $action, 'request' => serialize($args))) );
410                 if ( is_wp_error($request) ) {
411                         $res = new WP_Error('themes_api_failed', __('An Unexpected HTTP Error occurred during the API request.'), $request->get_error_message() );
412                 } else {
413                         $res = unserialize( wp_remote_retrieve_body( $request ) );
414                         if ( ! $res )
415                         $res = new WP_Error('themes_api_failed', __('An unknown error occurred.'), wp_remote_retrieve_body( $request ) );
416                 }
417         }
418         //var_dump(array($args, $res));
419         return apply_filters('themes_api_result', $res, $action, $args);
420 }
421
422 ?>