Make WordPress Core


Ignore:
Timestamp:
02/28/2012 01:49:49 AM (13 years ago)
Author:
nacin
Message:

Move the template loading functions from wp-includes/theme.php to wp-includes/template.php. This includes get_query_template(), locate_template(), and friends. see #20103.

File:
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/template.php

    r20001 r20002  
    11<?php
    22/**
    3  * Theme, template, and stylesheet functions.
     3 * Template loading functions.
    44 *
    55 * @package WordPress
    66 * @subpackage Template
    77 */
    8 
    9 /**
    10  * Whether a child theme is in use.
    11  *
    12  * @since 3.0.0
    13  *
    14  * @return bool true if a child theme is in use, false otherwise.
    15  **/
    16 function is_child_theme() {
    17     return ( TEMPLATEPATH !== STYLESHEETPATH );
    18 }
    19 
    20 /**
    21  * Retrieve name of the current stylesheet.
    22  *
    23  * The theme name that the administrator has currently set the front end theme
    24  * as.
    25  *
    26  * For all extensive purposes, the template name and the stylesheet name are
    27  * going to be the same for most cases.
    28  *
    29  * @since 1.5.0
    30  * @uses apply_filters() Calls 'stylesheet' filter on stylesheet name.
    31  *
    32  * @return string Stylesheet name.
    33  */
    34 function get_stylesheet() {
    35     return apply_filters('stylesheet', get_option('stylesheet'));
    36 }
    37 
    38 /**
    39  * Retrieve stylesheet directory path for current theme.
    40  *
    41  * @since 1.5.0
    42  * @uses apply_filters() Calls 'stylesheet_directory' filter on stylesheet directory and theme name.
    43  *
    44  * @return string Path to current theme directory.
    45  */
    46 function get_stylesheet_directory() {
    47     $stylesheet = get_stylesheet();
    48     $theme_root = get_theme_root( $stylesheet );
    49     $stylesheet_dir = "$theme_root/$stylesheet";
    50 
    51     return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
    52 }
    53 
    54 /**
    55  * Retrieve stylesheet directory URI.
    56  *
    57  * @since 1.5.0
    58  *
    59  * @return string
    60  */
    61 function get_stylesheet_directory_uri() {
    62     $stylesheet = get_stylesheet();
    63     $theme_root_uri = get_theme_root_uri( $stylesheet );
    64     $stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
    65 
    66     return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
    67 }
    68 
    69 /**
    70  * Retrieve URI of current theme stylesheet.
    71  *
    72  * The stylesheet file name is 'style.css' which is appended to {@link
    73  * get_stylesheet_directory_uri() stylesheet directory URI} path.
    74  *
    75  * @since 1.5.0
    76  * @uses apply_filters() Calls 'stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
    77  *
    78  * @return string
    79  */
    80 function get_stylesheet_uri() {
    81     $stylesheet_dir_uri = get_stylesheet_directory_uri();
    82     $stylesheet_uri = $stylesheet_dir_uri . '/style.css';
    83     return apply_filters('stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
    84 }
    85 
    86 /**
    87  * Retrieve localized stylesheet URI.
    88  *
    89  * The stylesheet directory for the localized stylesheet files are located, by
    90  * default, in the base theme directory. The name of the locale file will be the
    91  * locale followed by '.css'. If that does not exist, then the text direction
    92  * stylesheet will be checked for existence, for example 'ltr.css'.
    93  *
    94  * The theme may change the location of the stylesheet directory by either using
    95  * the 'stylesheet_directory_uri' filter or the 'locale_stylesheet_uri' filter.
    96  * If you want to change the location of the stylesheet files for the entire
    97  * WordPress workflow, then change the former. If you just have the locale in a
    98  * separate folder, then change the latter.
    99  *
    100  * @since 2.1.0
    101  * @uses apply_filters() Calls 'locale_stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
    102  *
    103  * @return string
    104  */
    105 function get_locale_stylesheet_uri() {
    106     global $wp_locale;
    107     $stylesheet_dir_uri = get_stylesheet_directory_uri();
    108     $dir = get_stylesheet_directory();
    109     $locale = get_locale();
    110     if ( file_exists("$dir/$locale.css") )
    111         $stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
    112     elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
    113         $stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
    114     else
    115         $stylesheet_uri = '';
    116     return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
    117 }
    118 
    119 /**
    120  * Retrieve name of the current theme.
    121  *
    122  * @since 1.5.0
    123  * @uses apply_filters() Calls 'template' filter on template option.
    124  *
    125  * @return string Template name.
    126  */
    127 function get_template() {
    128     return apply_filters('template', get_option('template'));
    129 }
    130 
    131 /**
    132  * Retrieve current theme directory.
    133  *
    134  * @since 1.5.0
    135  * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
    136  *
    137  * @return string Template directory path.
    138  */
    139 function get_template_directory() {
    140     $template = get_template();
    141     $theme_root = get_theme_root( $template );
    142     $template_dir = "$theme_root/$template";
    143 
    144     return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
    145 }
    146 
    147 /**
    148  * Retrieve theme directory URI.
    149  *
    150  * @since 1.5.0
    151  * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
    152  *
    153  * @return string Template directory URI.
    154  */
    155 function get_template_directory_uri() {
    156     $template = get_template();
    157     $theme_root_uri = get_theme_root_uri( $template );
    158     $template_dir_uri = "$theme_root_uri/$template";
    159 
    160     return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
    161 }
    162 
    163 /**
    164  * Retrieve theme data from parsed theme file.
    165  *
    166  * The description will have the tags filtered with the following HTML elements
    167  * whitelisted. The <b>'a'</b> element with the <em>href</em> and <em>title</em>
    168  * attributes. The <b>abbr</b> element with the <em>title</em> attribute. The
    169  * <b>acronym</b> element with the <em>title</em> attribute allowed. The
    170  * <b>code</b>, <b>em</b>, and <b>strong</b> elements also allowed.
    171  *
    172  * The style.css file must contain theme name, theme URI, and description. The
    173  * data can also contain author URI, author, template (parent template),
    174  * version, status, and finally tags. Some of these are not used by WordPress
    175  * administration panels, but are used by theme directory web sites which list
    176  * the theme.
    177  *
    178  * @since 1.5.0
    179  *
    180  * @param string $theme_file Theme file path.
    181  * @return array Theme data.
    182  */
    183 function get_theme_data( $theme_file ) {
    184     $default_headers = array(
    185         'Name' => 'Theme Name',
    186         'URI' => 'Theme URI',
    187         'Description' => 'Description',
    188         'Author' => 'Author',
    189         'AuthorURI' => 'Author URI',
    190         'Version' => 'Version',
    191         'Template' => 'Template',
    192         'Status' => 'Status',
    193         'Tags' => 'Tags'
    194         );
    195 
    196     $themes_allowed_tags = array(
    197         'a' => array(
    198             'href' => array(),'title' => array()
    199             ),
    200         'abbr' => array(
    201             'title' => array()
    202             ),
    203         'acronym' => array(
    204             'title' => array()
    205             ),
    206         'code' => array(),
    207         'em' => array(),
    208         'strong' => array()
    209     );
    210 
    211     $theme_data = get_file_data( $theme_file, $default_headers, 'theme' );
    212 
    213     $theme_data['Name'] = $theme_data['Title'] = wp_kses( $theme_data['Name'], $themes_allowed_tags );
    214 
    215     $theme_data['URI'] = esc_url( $theme_data['URI'] );
    216 
    217     $theme_data['Description'] = wptexturize( wp_kses( $theme_data['Description'], $themes_allowed_tags ) );
    218 
    219     $theme_data['AuthorURI'] = esc_url( $theme_data['AuthorURI'] );
    220 
    221     $theme_data['Template'] = wp_kses( $theme_data['Template'], $themes_allowed_tags );
    222 
    223     $theme_data['Version'] = wp_kses( $theme_data['Version'], $themes_allowed_tags );
    224 
    225     if ( $theme_data['Status'] == '' )
    226         $theme_data['Status'] = 'publish';
    227     else
    228         $theme_data['Status'] = wp_kses( $theme_data['Status'], $themes_allowed_tags );
    229 
    230     if ( $theme_data['Tags'] == '' )
    231         $theme_data['Tags'] = array();
    232     else
    233         $theme_data['Tags'] = array_map( 'trim', explode( ',', wp_kses( $theme_data['Tags'], array() ) ) );
    234 
    235     if ( $theme_data['Author'] == '' ) {
    236         $theme_data['Author'] = $theme_data['AuthorName'] = __('Anonymous');
    237     } else {
    238         $theme_data['AuthorName'] = wp_kses( $theme_data['Author'], $themes_allowed_tags );
    239         if ( empty( $theme_data['AuthorURI'] ) ) {
    240             $theme_data['Author'] = $theme_data['AuthorName'];
    241         } else {
    242             $theme_data['Author'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $theme_data['AuthorURI'], esc_attr__( 'Visit author homepage' ), $theme_data['AuthorName'] );
    243         }
    244     }
    245 
    246     return $theme_data;
    247 }
    248 
    249 /**
    250  * Retrieve list of themes with theme data in theme directory.
    251  *
    252  * The theme is broken, if it doesn't have a parent theme and is missing either
    253  * style.css and, or index.php. If the theme has a parent theme then it is
    254  * broken, if it is missing style.css; index.php is optional. The broken theme
    255  * list is saved in the {@link $wp_broken_themes} global, which is displayed on
    256  * the theme list in the administration panels.
    257  *
    258  * @since 1.5.0
    259  * @global array $wp_broken_themes Stores the broken themes.
    260  * @global array $wp_themes Stores the working themes.
    261  *
    262  * @return array Theme list with theme data.
    263  */
    264 function get_themes() {
    265     global $wp_themes, $wp_broken_themes;
    266 
    267     if ( isset($wp_themes) )
    268         return $wp_themes;
    269 
    270     if ( !$theme_files = search_theme_directories() )
    271         return false;
    272 
    273     asort( $theme_files );
    274 
    275     $wp_themes = array();
    276 
    277     foreach ( (array) $theme_files as $theme_file ) {
    278         $theme_root = $theme_file['theme_root'];
    279         $theme_file = $theme_file['theme_file'];
    280 
    281         if ( !is_readable("$theme_root/$theme_file") ) {
    282             $wp_broken_themes[$theme_file] = array('Name' => $theme_file, 'Title' => $theme_file, 'Description' => __('File not readable.'));
    283             continue;
    284         }
    285 
    286         $theme_data = get_theme_data("$theme_root/$theme_file");
    287 
    288         $name        = $theme_data['Name'];
    289         $title       = $theme_data['Title'];
    290         $description = wptexturize($theme_data['Description']);
    291         $version     = $theme_data['Version'];
    292         $author      = $theme_data['Author'];
    293         $template    = $theme_data['Template'];
    294         $stylesheet  = dirname($theme_file);
    295 
    296         $screenshot = false;
    297         foreach ( array('png', 'gif', 'jpg', 'jpeg') as $ext ) {
    298             if (file_exists("$theme_root/$stylesheet/screenshot.$ext")) {
    299                 $screenshot = "screenshot.$ext";
    300                 break;
    301             }
    302         }
    303 
    304         if ( empty($name) ) {
    305             $name = dirname($theme_file);
    306             $title = $name;
    307         }
    308 
    309         $parent_template = $template;
    310 
    311         if ( empty($template) ) {
    312             if ( file_exists("$theme_root/$stylesheet/index.php") )
    313                 $template = $stylesheet;
    314             else
    315                 continue;
    316         }
    317 
    318         $template = trim( $template );
    319 
    320         if ( !file_exists("$theme_root/$template/index.php") ) {
    321             $parent_dir = dirname(dirname($theme_file));
    322             if ( file_exists("$theme_root/$parent_dir/$template/index.php") ) {
    323                 $template = "$parent_dir/$template";
    324                 $template_directory = "$theme_root/$template";
    325             } else {
    326                 /**
    327                  * The parent theme doesn't exist in the current theme's folder or sub folder
    328                  * so lets use the theme root for the parent template.
    329                  */
    330                 if ( isset($theme_files[$template]) && file_exists( $theme_files[$template]['theme_root'] . "/$template/index.php" ) ) {
    331                     $template_directory = $theme_files[$template]['theme_root'] . "/$template";
    332                 } else {
    333                     if ( empty( $parent_template) )
    334                         $wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => __('Template is missing.'), 'error' => 'no_template');
    335                     else
    336                         $wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => sprintf( __('The parent theme is missing. Please install the "%s" parent theme.'),  $parent_template ), 'error' => 'no_parent', 'parent' => $parent_template );
    337                     continue;
    338                 }
    339 
    340             }
    341         } else {
    342             $template_directory = trim( $theme_root . '/' . $template );
    343         }
    344 
    345         $stylesheet_files = array();
    346         $template_files = array();
    347 
    348         $stylesheet_dir = @ dir("$theme_root/$stylesheet");
    349         if ( $stylesheet_dir ) {
    350             while ( ($file = $stylesheet_dir->read()) !== false ) {
    351                 if ( !preg_match('|^\.+$|', $file) ) {
    352                     if ( preg_match('|\.css$|', $file) )
    353                         $stylesheet_files[] = "$theme_root/$stylesheet/$file";
    354                     elseif ( preg_match('|\.php$|', $file) )
    355                         $template_files[] = "$theme_root/$stylesheet/$file";
    356                 }
    357             }
    358             @ $stylesheet_dir->close();
    359         }
    360 
    361         $template_dir = @ dir("$template_directory");
    362         if ( $template_dir ) {
    363             while ( ($file = $template_dir->read()) !== false ) {
    364                 if ( preg_match('|^\.+$|', $file) )
    365                     continue;
    366                 if ( preg_match('|\.php$|', $file) ) {
    367                     $template_files[] = "$template_directory/$file";
    368                 } elseif ( is_dir("$template_directory/$file") ) {
    369                     $template_subdir = @ dir("$template_directory/$file");
    370                     if ( !$template_subdir )
    371                         continue;
    372                     while ( ($subfile = $template_subdir->read()) !== false ) {
    373                         if ( preg_match('|^\.+$|', $subfile) )
    374                             continue;
    375                         if ( preg_match('|\.php$|', $subfile) )
    376                             $template_files[] = "$template_directory/$file/$subfile";
    377                     }
    378                     @ $template_subdir->close();
    379                 }
    380             }
    381             @ $template_dir->close();
    382         }
    383 
    384         //Make unique and remove duplicates when stylesheet and template are the same i.e. most themes
    385         $template_files = array_unique($template_files);
    386         $stylesheet_files = array_unique($stylesheet_files);
    387 
    388         $template_dir = $template_directory;
    389         $stylesheet_dir = $theme_root . '/' . $stylesheet;
    390 
    391         if ( empty($template_dir) )
    392             $template_dir = '/';
    393         if ( empty($stylesheet_dir) )
    394             $stylesheet_dir = '/';
    395 
    396         // Check for theme name collision. This occurs if a theme is copied to
    397         // a new theme directory and the theme header is not updated. Whichever
    398         // theme is first keeps the name. Subsequent themes get a suffix applied.
    399         // Default themes themes always trump their pretenders.
    400         if ( isset($wp_themes[$name]) ) {
    401             $trump_cards = array(
    402                 'classic'      => 'WordPress Classic',
    403                 'default'      => 'WordPress Default',
    404                 'twentyten'    => 'Twenty Ten',
    405                 'twentyeleven' => 'Twenty Eleven',
    406                 'twentytwelve' => 'Twenty Twelve',
    407             );
    408             if ( isset( $trump_cards[ $stylesheet ] ) && $name == $trump_cards[ $stylesheet ] ) {
    409                 // If another theme has claimed to be one of our default themes, move
    410                 // them aside.
    411                 $suffix = $wp_themes[$name]['Stylesheet'];
    412                 $new_name = "$name/$suffix";
    413                 $wp_themes[$new_name] = $wp_themes[$name];
    414                 $wp_themes[$new_name]['Name'] = $new_name;
    415             } else {
    416                 $name = "$name/$stylesheet";
    417             }
    418         }
    419 
    420         $theme_roots[$stylesheet] = str_replace( WP_CONTENT_DIR, '', $theme_root );
    421         $wp_themes[$name] = array(
    422             'Name' => $name,
    423             'Title' => $title,
    424             'Description' => $description,
    425             'Author' => $author,
    426             'Author Name' => $theme_data['AuthorName'],
    427             'Author URI' => $theme_data['AuthorURI'],
    428             'Version' => $version,
    429             'Template' => $template,
    430             'Stylesheet' => $stylesheet,
    431             'Template Files' => $template_files,
    432             'Stylesheet Files' => $stylesheet_files,
    433             'Template Dir' => $template_dir,
    434             'Stylesheet Dir' => $stylesheet_dir,
    435             'Status' => $theme_data['Status'],
    436             'Screenshot' => $screenshot,
    437             'Tags' => $theme_data['Tags'],
    438             'Theme Root' => $theme_root,
    439             'Theme Root URI' => str_replace( WP_CONTENT_DIR, content_url(), $theme_root ),
    440         );
    441     }
    442 
    443     unset($theme_files);
    444 
    445     /* Store theme roots in the DB */
    446     if ( get_site_transient( 'theme_roots' ) != $theme_roots )
    447         set_site_transient( 'theme_roots', $theme_roots, 7200 ); // cache for two hours
    448     unset($theme_roots);
    449 
    450     /* Resolve theme dependencies. */
    451     $theme_names = array_keys( $wp_themes );
    452     foreach ( (array) $theme_names as $theme_name ) {
    453         $wp_themes[$theme_name]['Parent Theme'] = '';
    454         if ( $wp_themes[$theme_name]['Stylesheet'] != $wp_themes[$theme_name]['Template'] ) {
    455             foreach ( (array) $theme_names as $parent_theme_name ) {
    456                 if ( ($wp_themes[$parent_theme_name]['Stylesheet'] == $wp_themes[$parent_theme_name]['Template']) && ($wp_themes[$parent_theme_name]['Template'] == $wp_themes[$theme_name]['Template']) ) {
    457                     $wp_themes[$theme_name]['Parent Theme'] = $wp_themes[$parent_theme_name]['Name'];
    458                     break;
    459                 }
    460             }
    461         }
    462     }
    463 
    464     return $wp_themes;
    465 }
    466 
    467 /**
    468  * Retrieve theme roots.
    469  *
    470  * @since 2.9.0
    471  *
    472  * @return array|string An array of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root.
    473  */
    474 function get_theme_roots() {
    475     global $wp_theme_directories;
    476 
    477     if ( count($wp_theme_directories) <= 1 )
    478         return get_theme_root();
    479 
    480     $theme_roots = get_site_transient( 'theme_roots' );
    481     if ( false === $theme_roots ) {
    482         get_themes();
    483         $theme_roots = get_site_transient( 'theme_roots' ); // this is set in get_theme()
    484     }
    485     return $theme_roots;
    486 }
    487 
    488 /**
    489  * Retrieve theme data.
    490  *
    491  * @since 1.5.0
    492  *
    493  * @param string $theme Theme name.
    494  * @return array|null Null, if theme name does not exist. Theme data, if exists.
    495  */
    496 function get_theme($theme) {
    497     $themes = get_themes();
    498 
    499     if ( is_array( $themes ) && array_key_exists( $theme, $themes ) )
    500         return $themes[$theme];
    501 
    502     return null;
    503 }
    504 
    505 /**
    506  * Retrieve current theme display name.
    507  *
    508  * If the 'current_theme' option has already been set, then it will be returned
    509  * instead. If it is not set, then each theme will be iterated over until both
    510  * the current stylesheet and current template name.
    511  *
    512  * @since 1.5.0
    513  *
    514  * @return string
    515  */
    516 function get_current_theme() {
    517     if ( $theme = get_option('current_theme') )
    518         return $theme;
    519 
    520     $themes = get_themes();
    521     $current_theme = 'Twenty Eleven';
    522 
    523     if ( $themes ) {
    524         $theme_names = array_keys( $themes );
    525         $current_template = get_option( 'template' );
    526         $current_stylesheet = get_option( 'stylesheet' );
    527 
    528         foreach ( (array) $theme_names as $theme_name ) {
    529             if ( $themes[$theme_name]['Stylesheet'] == $current_stylesheet &&
    530                     $themes[$theme_name]['Template'] == $current_template ) {
    531                 $current_theme = $themes[$theme_name]['Name'];
    532                 break;
    533             }
    534         }
    535     }
    536 
    537     update_option('current_theme', $current_theme);
    538 
    539     return $current_theme;
    540 }
    541 
    542 /**
    543  * Register a directory that contains themes.
    544  *
    545  * @since 2.9.0
    546  *
    547  * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR
    548  * @return bool
    549  */
    550 function register_theme_directory( $directory ) {
    551     global $wp_theme_directories;
    552 
    553     if ( ! file_exists( $directory ) ) {
    554         // Try prepending as the theme directory could be relative to the content directory
    555         $directory = WP_CONTENT_DIR . '/' . $directory;
    556         // If this directory does not exist, return and do not register
    557         if ( ! file_exists( $directory ) )
    558             return false;
    559     }
    560 
    561     $wp_theme_directories[] = $directory;
    562 
    563     return true;
    564 }
    565 
    566 /**
    567  * Search all registered theme directories for complete and valid themes.
    568  *
    569  * @since 2.9.0
    570  *
    571  * @return array Valid themes found
    572  */
    573 function search_theme_directories() {
    574     global $wp_theme_directories, $wp_broken_themes;
    575     if ( empty( $wp_theme_directories ) )
    576         return false;
    577 
    578     $theme_files = array();
    579     $wp_broken_themes = array();
    580 
    581     /* Loop the registered theme directories and extract all themes */
    582     foreach ( (array) $wp_theme_directories as $theme_root ) {
    583         $theme_loc = $theme_root;
    584 
    585         /* We don't want to replace all forward slashes, see Trac #4541 */
    586         if ( '/' != WP_CONTENT_DIR )
    587             $theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
    588 
    589         /* Files in the root of the current theme directory and one subdir down */
    590         $themes_dir = @ opendir($theme_root);
    591 
    592         if ( !$themes_dir )
    593             return false;
    594 
    595         while ( ($theme_dir = readdir($themes_dir)) !== false ) {
    596             if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
    597                 if ( $theme_dir[0] == '.' || $theme_dir == 'CVS' )
    598                     continue;
    599 
    600                 $stylish_dir = @opendir($theme_root . '/' . $theme_dir);
    601                 $found_stylesheet = false;
    602 
    603                 while ( ($theme_file = readdir($stylish_dir)) !== false ) {
    604                     if ( $theme_file == 'style.css' ) {
    605                         $theme_files[$theme_dir] = array( 'theme_file' => $theme_dir . '/' . $theme_file, 'theme_root' => $theme_root );
    606                         $found_stylesheet = true;
    607                         break;
    608                     }
    609                 }
    610                 @closedir($stylish_dir);
    611 
    612                 if ( !$found_stylesheet ) { // look for themes in that dir
    613                     $subdir = "$theme_root/$theme_dir";
    614                     $subdir_name = $theme_dir;
    615                     $theme_subdirs = @opendir( $subdir );
    616 
    617                     $found_subdir_themes = false;
    618                     while ( ($theme_subdir = readdir($theme_subdirs)) !== false ) {
    619                         if ( is_dir( $subdir . '/' . $theme_subdir) && is_readable($subdir . '/' . $theme_subdir) ) {
    620                             if ( $theme_subdir[0] == '.' || $theme_subdir == 'CVS' )
    621                                 continue;
    622 
    623                             $stylish_dir = @opendir($subdir . '/' . $theme_subdir);
    624                             $found_stylesheet = false;
    625 
    626                             while ( ($theme_file = readdir($stylish_dir)) !== false ) {
    627                                 if ( $theme_file == 'style.css' ) {
    628                                     $theme_files["$theme_dir/$theme_subdir"] = array( 'theme_file' => $subdir_name . '/' . $theme_subdir . '/' . $theme_file, 'theme_root' => $theme_root );
    629                                     $found_stylesheet = true;
    630                                     $found_subdir_themes = true;
    631                                     break;
    632                                 }
    633                             }
    634                             @closedir($stylish_dir);
    635                         }
    636                     }
    637                     @closedir($theme_subdirs);
    638                     if ( !$found_subdir_themes )
    639                         $wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
    640                 }
    641             }
    642         }
    643         @closedir( $themes_dir );
    644     }
    645     return $theme_files;
    646 }
    647 
    648 /**
    649  * Retrieve path to themes directory.
    650  *
    651  * Does not have trailing slash.
    652  *
    653  * @since 1.5.0
    654  * @uses apply_filters() Calls 'theme_root' filter on path.
    655  *
    656  * @param string $stylesheet_or_template The stylesheet or template name of the theme
    657  * @return string Theme path.
    658  */
    659 function get_theme_root( $stylesheet_or_template = false ) {
    660     if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) )
    661         $theme_root = $theme_root;
    662     else
    663         $theme_root = WP_CONTENT_DIR . '/themes';
    664 
    665     return apply_filters( 'theme_root', $theme_root );
    666 }
    667 
    668 /**
    669  * Retrieve URI for themes directory.
    670  *
    671  * Does not have trailing slash.
    672  *
    673  * @since 1.5.0
    674  *
    675  * @param string $stylesheet_or_template The stylesheet or template name of the theme
    676  * @return string Themes URI.
    677  */
    678 function get_theme_root_uri( $stylesheet_or_template = false ) {
    679     if ( $stylesheet_or_template ) {
    680         if ( $theme_root = get_raw_theme_root($stylesheet_or_template) )
    681             $theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
    682         else
    683             $theme_root_uri = content_url( 'themes' );
    684     } else {
    685         $theme_root_uri = content_url( 'themes' );
    686     }
    687 
    688     return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
    689 }
    690 
    691 /**
    692  * Get the raw theme root with no filters applied.
    693  *
    694  * @since 3.1.0
    695  *
    696  * Before 3.4.0, this incorrectly returned a path relative to the content directory ("/themes") when
    697  * only one theme directory was registered. Absolute paths are now always returned.
    698  *
    699  * @param string $stylesheet_or_template The stylesheet or template name of the theme
    700  * @return string Theme root
    701  */
    702 function get_raw_theme_root( $stylesheet_or_template, $no_cache = false ) {
    703     global $wp_theme_directories;
    704 
    705     if ( count($wp_theme_directories) <= 1 )
    706         return WP_CONTENT_DIR . '/themes';
    707 
    708     $theme_root = false;
    709 
    710     // If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
    711     if ( !$no_cache ) {
    712         if ( get_option('stylesheet') == $stylesheet_or_template )
    713             $theme_root = get_option('stylesheet_root');
    714         elseif ( get_option('template') == $stylesheet_or_template )
    715             $theme_root = get_option('template_root');
    716     }
    717 
    718     if ( empty($theme_root) ) {
    719         $theme_roots = get_theme_roots();
    720         if ( !empty($theme_roots[$stylesheet_or_template]) )
    721             $theme_root = $theme_roots[$stylesheet_or_template];
    722     }
    723 
    724     return $theme_root;
    725 }
    7268
    7279/**
     
    1114396}
    1115397
    1116 /**
    1117  * Display localized stylesheet link element.
    1118  *
    1119  * @since 2.1.0
    1120  */
    1121 function locale_stylesheet() {
    1122     $stylesheet = get_locale_stylesheet_uri();
    1123     if ( empty($stylesheet) )
    1124         return;
    1125     echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
    1126 }
    1127 
    1128 /**
    1129  * Start preview theme output buffer.
    1130  *
    1131  * Will only preform task if the user has permissions and template and preview
    1132  * query variables exist.
    1133  *
    1134  * @since 2.6.0
    1135  */
    1136 function preview_theme() {
    1137     if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
    1138         return;
    1139 
    1140     if ( !current_user_can( 'switch_themes' ) )
    1141         return;
    1142 
    1143     // Admin Thickbox requests
    1144     if ( isset( $_GET['preview_iframe'] ) )
    1145         show_admin_bar( false );
    1146 
    1147     $_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
    1148 
    1149     if ( validate_file($_GET['template']) )
    1150         return;
    1151 
    1152     add_filter( 'template', '_preview_theme_template_filter' );
    1153 
    1154     if ( isset($_GET['stylesheet']) ) {
    1155         $_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
    1156         if ( validate_file($_GET['stylesheet']) )
    1157             return;
    1158         add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
    1159     }
    1160 
    1161     // Prevent theme mods to current theme being used on theme being previewed
    1162     add_filter( 'pre_option_mods_' . get_current_theme(), '__return_empty_array' );
    1163 
    1164     ob_start( 'preview_theme_ob_filter' );
    1165 }
    1166 add_action('setup_theme', 'preview_theme');
    1167 
    1168 /**
    1169  * Private function to modify the current template when previewing a theme
    1170  *
    1171  * @since 2.9.0
    1172  * @access private
    1173  *
    1174  * @return string
    1175  */
    1176 function _preview_theme_template_filter() {
    1177     return isset($_GET['template']) ? $_GET['template'] : '';
    1178 }
    1179 
    1180 /**
    1181  * Private function to modify the current stylesheet when previewing a theme
    1182  *
    1183  * @since 2.9.0
    1184  * @access private
    1185  *
    1186  * @return string
    1187  */
    1188 function _preview_theme_stylesheet_filter() {
    1189     return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
    1190 }
    1191 
    1192 /**
    1193  * Callback function for ob_start() to capture all links in the theme.
    1194  *
    1195  * @since 2.6.0
    1196  * @access private
    1197  *
    1198  * @param string $content
    1199  * @return string
    1200  */
    1201 function preview_theme_ob_filter( $content ) {
    1202     return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
    1203 }
    1204 
    1205 /**
    1206  * Manipulates preview theme links in order to control and maintain location.
    1207  *
    1208  * Callback function for preg_replace_callback() to accept and filter matches.
    1209  *
    1210  * @since 2.6.0
    1211  * @access private
    1212  *
    1213  * @param array $matches
    1214  * @return string
    1215  */
    1216 function preview_theme_ob_filter_callback( $matches ) {
    1217     if ( strpos($matches[4], 'onclick') !== false )
    1218         $matches[4] = preg_replace('#onclick=([\'"]).*?(?<!\\\)\\1#i', '', $matches[4]); //Strip out any onclicks from rest of <a>. (?<!\\\) means to ignore the '" if its escaped by \  to prevent breaking mid-attribute.
    1219     if (
    1220         ( false !== strpos($matches[3], '/wp-admin/') )
    1221     ||
    1222         ( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
    1223     ||
    1224         ( false !== strpos($matches[3], '/feed/') )
    1225     ||
    1226         ( false !== strpos($matches[3], '/trackback/') )
    1227     )
    1228         return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
    1229 
    1230     $link = add_query_arg( array( 'preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'], 'preview_iframe' => 1 ), $matches[3] );
    1231     if ( 0 === strpos($link, 'preview=1') )
    1232         $link = "?$link";
    1233     return $matches[1] . esc_attr( $link ) . $matches[4];
    1234 }
    1235 
    1236 /**
    1237  * Switches current theme to new template and stylesheet names.
    1238  *
    1239  * @since 2.5.0
    1240  * @uses do_action() Calls 'switch_theme' action on updated theme display name.
    1241  *
    1242  * @param string $template Template name
    1243  * @param string $stylesheet Stylesheet name.
    1244  */
    1245 function switch_theme($template, $stylesheet) {
    1246     global $wp_theme_directories, $sidebars_widgets;
    1247 
    1248     if ( is_array( $sidebars_widgets ) )
    1249         set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $sidebars_widgets ) );
    1250 
    1251     $old_theme = get_current_theme();
    1252 
    1253     update_option('template', $template);
    1254     update_option('stylesheet', $stylesheet);
    1255 
    1256     if ( count($wp_theme_directories) > 1 ) {
    1257         update_option('template_root', get_raw_theme_root($template, true));
    1258         update_option('stylesheet_root', get_raw_theme_root($stylesheet, true));
    1259     }
    1260 
    1261     delete_option('current_theme');
    1262     $theme = get_current_theme();
    1263 
    1264     if ( is_admin() && false === get_option( "theme_mods_$stylesheet" ) ) {
    1265         $default_theme_mods = (array) get_option( "mods_$theme" );
    1266         add_option( "theme_mods_$stylesheet", $default_theme_mods );
    1267     }
    1268 
    1269     update_option( 'theme_switched', $old_theme );
    1270     do_action( 'switch_theme', $theme );
    1271 }
    1272 
    1273 /**
    1274  * Checks that current theme files 'index.php' and 'style.css' exists.
    1275  *
    1276  * Does not check the default theme, which is the fallback and should always exist.
    1277  * Will switch theme to the fallback theme if current theme does not validate.
    1278  * You can use the 'validate_current_theme' filter to return false to
    1279  * disable this functionality.
    1280  *
    1281  * @since 1.5.0
    1282  * @see WP_DEFAULT_THEME
    1283  *
    1284  * @return bool
    1285  */
    1286 function validate_current_theme() {
    1287     // Don't validate during an install/upgrade.
    1288     if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
    1289         return true;
    1290 
    1291     if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
    1292         switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
    1293         return false;
    1294     }
    1295 
    1296     if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
    1297         switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
    1298         return false;
    1299     }
    1300 
    1301     if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
    1302         switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
    1303         return false;
    1304     }
    1305 
    1306     return true;
    1307 }
    1308 
    1309 /**
    1310  * Retrieve all theme modifications.
    1311  *
    1312  * @since 3.1.0
    1313  *
    1314  * @return array Theme modifications.
    1315  */
    1316 function get_theme_mods() {
    1317     $theme_slug = get_option( 'stylesheet' );
    1318     if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
    1319         $theme_name = get_current_theme();
    1320         $mods = get_option( "mods_$theme_name" ); // Deprecated location.
    1321         if ( is_admin() && false !== $mods ) {
    1322             update_option( "theme_mods_$theme_slug", $mods );
    1323             delete_option( "mods_$theme_name" );
    1324         }
    1325     }
    1326     return $mods;
    1327 }
    1328 
    1329 /**
    1330  * Retrieve theme modification value for the current theme.
    1331  *
    1332  * If the modification name does not exist, then the $default will be passed
    1333  * through {@link http://php.net/sprintf sprintf()} PHP function with the first
    1334  * string the template directory URI and the second string the stylesheet
    1335  * directory URI.
    1336  *
    1337  * @since 2.1.0
    1338  * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
    1339  *
    1340  * @param string $name Theme modification name.
    1341  * @param bool|string $default
    1342  * @return string
    1343  */
    1344 function get_theme_mod( $name, $default = false ) {
    1345     $mods = get_theme_mods();
    1346 
    1347     if ( isset( $mods[ $name ] ) )
    1348         return apply_filters( "theme_mod_$name", $mods[ $name ] );
    1349 
    1350     if ( is_string( $default ) )
    1351         $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
    1352 
    1353     return apply_filters( "theme_mod_$name", $default );
    1354 }
    1355 
    1356 /**
    1357  * Update theme modification value for the current theme.
    1358  *
    1359  * @since 2.1.0
    1360  *
    1361  * @param string $name Theme modification name.
    1362  * @param string $value theme modification value.
    1363  */
    1364 function set_theme_mod( $name, $value ) {
    1365     $mods = get_theme_mods();
    1366 
    1367     $mods[ $name ] = $value;
    1368 
    1369     $theme = get_option( 'stylesheet' );
    1370     update_option( "theme_mods_$theme", $mods );
    1371 }
    1372 
    1373 /**
    1374  * Remove theme modification name from current theme list.
    1375  *
    1376  * If removing the name also removes all elements, then the entire option will
    1377  * be removed.
    1378  *
    1379  * @since 2.1.0
    1380  *
    1381  * @param string $name Theme modification name.
    1382  * @return null
    1383  */
    1384 function remove_theme_mod( $name ) {
    1385     $mods = get_theme_mods();
    1386 
    1387     if ( ! isset( $mods[ $name ] ) )
    1388         return;
    1389 
    1390     unset( $mods[ $name ] );
    1391 
    1392     if ( empty( $mods ) )
    1393         return remove_theme_mods();
    1394 
    1395     $theme = get_option( 'stylesheet' );
    1396     update_option( "theme_mods_$theme", $mods );
    1397 }
    1398 
    1399 /**
    1400  * Remove theme modifications option for current theme.
    1401  *
    1402  * @since 2.1.0
    1403  */
    1404 function remove_theme_mods() {
    1405     delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
    1406     delete_option( 'mods_' . get_current_theme() );
    1407 }
    1408 
    1409 /**
    1410  * Retrieve text color for custom header.
    1411  *
    1412  * @since 2.1.0
    1413  * @uses HEADER_TEXTCOLOR
    1414  *
    1415  * @return string
    1416  */
    1417 function get_header_textcolor() {
    1418     $default = defined('HEADER_TEXTCOLOR') ? HEADER_TEXTCOLOR : '';
    1419 
    1420     return get_theme_mod('header_textcolor', $default);
    1421 }
    1422 
    1423 /**
    1424  * Display text color for custom header.
    1425  *
    1426  * @since 2.1.0
    1427  */
    1428 function header_textcolor() {
    1429     echo get_header_textcolor();
    1430 }
    1431 
    1432 /**
    1433  * Retrieve header image for custom header.
    1434  *
    1435  * @since 2.1.0
    1436  * @uses HEADER_IMAGE
    1437  *
    1438  * @return string
    1439  */
    1440 function get_header_image() {
    1441     $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
    1442     $url = get_theme_mod( 'header_image', $default );
    1443 
    1444     if ( 'remove-header' == $url )
    1445         return false;
    1446 
    1447     if ( is_random_header_image() )
    1448         $url = get_random_header_image();
    1449 
    1450     if ( is_ssl() )
    1451         $url = str_replace( 'http://', 'https://', $url );
    1452     else
    1453         $url = str_replace( 'https://', 'http://', $url );
    1454 
    1455     return esc_url_raw( $url );
    1456 }
    1457 
    1458 /**
    1459  * Get random header image data from registered images in theme.
    1460  *
    1461  * @since 3.4.0
    1462  *
    1463  * @access private
    1464  *
    1465  * @return string Path to header image
    1466  */
    1467 
    1468 function _get_random_header_data() {
    1469     static $_wp_random_header;
    1470 
    1471     if ( empty( $_wp_random_header ) ) {
    1472         global $_wp_default_headers;
    1473         $header_image_mod = get_theme_mod( 'header_image', '' );
    1474         $headers = array();
    1475 
    1476         if ( 'random-uploaded-image' == $header_image_mod )
    1477             $headers = get_uploaded_header_images();
    1478         elseif ( ! empty( $_wp_default_headers ) ) {
    1479             if ( 'random-default-image' == $header_image_mod ) {
    1480                 $headers = $_wp_default_headers;
    1481             } else {
    1482                 $is_random = get_theme_support( 'custom-header' );
    1483                 if ( isset( $is_random[ 0 ] ) && !empty( $is_random[ 0 ][ 'random-default' ] ) )
    1484                     $headers = $_wp_default_headers;
    1485             }
    1486         }
    1487 
    1488         if ( empty( $headers ) )
    1489             return new stdClass;
    1490 
    1491         $_wp_random_header = (object) $headers[ array_rand( $headers ) ];
    1492 
    1493         $_wp_random_header->url =  sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() );
    1494         $_wp_random_header->thumbnail_url =  sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() );
    1495     }
    1496     return $_wp_random_header;
    1497 }
    1498 
    1499 /**
    1500  * Get random header image url from registered images in theme.
    1501  *
    1502  * @since 3.2.0
    1503  *
    1504  * @return string Path to header image
    1505  */
    1506 
    1507 function get_random_header_image() {
    1508     $random_image = _get_random_header_data();
    1509     if ( empty( $random_image->url ) )
    1510         return '';
    1511     return $random_image->url;
    1512 }
    1513 
    1514 /**
    1515  * Check if random header image is in use.
    1516  *
    1517  * Always true if user expressly chooses the option in Appearance > Header.
    1518  * Also true if theme has multiple header images registered, no specific header image
    1519  * is chosen, and theme turns on random headers with add_theme_support().
    1520  *
    1521  * @since 3.2.0
    1522  * @uses HEADER_IMAGE
    1523  *
    1524  * @param string $type The random pool to use. any|default|uploaded
    1525  * @return boolean
    1526  */
    1527 function is_random_header_image( $type = 'any' ) {
    1528     $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
    1529     $header_image_mod = get_theme_mod( 'header_image', $default );
    1530 
    1531     if ( 'any' == $type ) {
    1532         if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
    1533             return true;
    1534     } else {
    1535         if ( "random-$type-image" == $header_image_mod )
    1536             return true;
    1537         elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
    1538             return true;
    1539     }
    1540 
    1541     return false;
    1542 }
    1543 
    1544 /**
    1545  * Display header image path.
    1546  *
    1547  * @since 2.1.0
    1548  */
    1549 function header_image() {
    1550     echo get_header_image();
    1551 }
    1552 
    1553 /**
    1554  * Get the header images uploaded for the current theme.
    1555  *
    1556  * @since 3.2.0
    1557  *
    1558  * @return array
    1559  */
    1560 function get_uploaded_header_images() {
    1561     $header_images = array();
    1562 
    1563     // @todo caching
    1564     $headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
    1565 
    1566     if ( empty( $headers ) )
    1567         return array();
    1568 
    1569     foreach ( (array) $headers as $header ) {
    1570         $url = esc_url_raw( $header->guid );
    1571         $header_data = wp_get_attachment_metadata( $header->ID );
    1572         $header_index = basename($url);
    1573         $header_images[$header_index] = array();
    1574         $header_images[$header_index]['attachment_id'] =  $header->ID;
    1575         $header_images[$header_index]['url'] =  $url;
    1576         $header_images[$header_index]['thumbnail_url'] =  $url;
    1577         $header_images[$header_index]['width'] = $header_data['width'];
    1578         $header_images[$header_index]['height'] = $header_data['height'];
    1579     }
    1580 
    1581     return $header_images;
    1582 }
    1583 
    1584 /**
    1585  * Get the header image data.
    1586  *
    1587  * @since 3.4.0
    1588  *
    1589  * @return object
    1590  */
    1591 function get_current_header_data() {
    1592     $data = is_random_header_image()? _get_random_header_data() : get_theme_mod( 'header_image_data' );
    1593     $default = array(
    1594         'url'           => '',
    1595         'thumbnail_url' => '',
    1596         'width'         => '',
    1597         'height'        => '',
    1598     );
    1599     return (object) wp_parse_args( $data, $default );
    1600 }
    1601 
    1602 /**
    1603  * Get the header image width.
    1604  *
    1605  * @since 3.4.0
    1606  *
    1607  * @return int
    1608  */
    1609 function get_header_image_width() {
    1610     return empty( get_current_header_data()->width )? HEADER_IMAGE_WIDTH : get_current_header_data()->width;
    1611 }
    1612 
    1613 /**
    1614  * Get the header image height.
    1615  *
    1616  * @since 3.4.0
    1617  *
    1618  * @return int
    1619  */
    1620 function get_header_image_height() {
    1621     return empty( get_current_header_data()->height )? HEADER_IMAGE_HEIGHT : get_current_header_data()->height;
    1622 }
    1623 
    1624 /**
    1625  * Add callbacks for image header display.
    1626  *
    1627  * The parameter $header_callback callback will be required to display the
    1628  * content for the 'wp_head' action. The parameter $admin_header_callback
    1629  * callback will be added to Custom_Image_Header class and that will be added
    1630  * to the 'admin_menu' action.
    1631  *
    1632  * @since 2.1.0
    1633  * @uses Custom_Image_Header Sets up for $admin_header_callback for administration panel display.
    1634  *
    1635  * @param callback $header_callback Call on 'wp_head' action.
    1636  * @param callback $admin_header_callback Call on custom header administration screen.
    1637  * @param callback $admin_image_div_callback Output a custom header image div on the custom header administration screen. Optional.
    1638  */
    1639 function add_custom_image_header( $header_callback, $admin_header_callback, $admin_image_div_callback = '' ) {
    1640     if ( ! empty( $header_callback ) )
    1641         add_action('wp_head', $header_callback);
    1642 
    1643     $support = array( 'callback' => $header_callback );
    1644     $theme_support = get_theme_support( 'custom-header' );
    1645     if ( ! empty( $theme_support ) && is_array( $theme_support[ 0 ] ) )
    1646         $support = array_merge( $theme_support[ 0 ], $support );
    1647     add_theme_support( 'custom-header',  $support );
    1648     add_theme_support( 'custom-header-uploads' );
    1649 
    1650     if ( ! is_admin() )
    1651         return;
    1652 
    1653     global $custom_image_header;
    1654 
    1655     require_once( ABSPATH . 'wp-admin/custom-header.php' );
    1656     $custom_image_header = new Custom_Image_Header( $admin_header_callback, $admin_image_div_callback );
    1657     add_action( 'admin_menu', array( &$custom_image_header, 'init' ) );
    1658 }
    1659 
    1660 /**
    1661  * Remove image header support.
    1662  *
    1663  * @since 3.1.0
    1664  * @see add_custom_image_header()
    1665  *
    1666  * @return bool Whether support was removed.
    1667  */
    1668 function remove_custom_image_header() {
    1669     if ( ! current_theme_supports( 'custom-header' ) )
    1670         return false;
    1671 
    1672     $callback = get_theme_support( 'custom-header' );
    1673     remove_action( 'wp_head', $callback[0]['callback'] );
    1674     _remove_theme_support( 'custom-header' );
    1675     remove_theme_support( 'custom-header-uploads' );
    1676 
    1677     if ( is_admin() ) {
    1678         remove_action( 'admin_menu', array( &$GLOBALS['custom_image_header'], 'init' ) );
    1679         unset( $GLOBALS['custom_image_header'] );
    1680     }
    1681 
    1682     return true;
    1683 }
    1684 
    1685 /**
    1686  * Register a selection of default headers to be displayed by the custom header admin UI.
    1687  *
    1688  * @since 3.0.0
    1689  *
    1690  * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
    1691  */
    1692 function register_default_headers( $headers ) {
    1693     global $_wp_default_headers;
    1694 
    1695     $_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
    1696 }
    1697 
    1698 /**
    1699  * Unregister default headers.
    1700  *
    1701  * This function must be called after register_default_headers() has already added the
    1702  * header you want to remove.
    1703  *
    1704  * @see register_default_headers()
    1705  * @since 3.0.0
    1706  *
    1707  * @param string|array $header The header string id (key of array) to remove, or an array thereof.
    1708  * @return True on success, false on failure.
    1709  */
    1710 function unregister_default_headers( $header ) {
    1711     global $_wp_default_headers;
    1712     if ( is_array( $header ) ) {
    1713         array_map( 'unregister_default_headers', $header );
    1714     } elseif ( isset( $_wp_default_headers[ $header ] ) ) {
    1715         unset( $_wp_default_headers[ $header ] );
    1716         return true;
    1717     } else {
    1718         return false;
    1719     }
    1720 }
    1721 
    1722 /**
    1723  * Retrieve background image for custom background.
    1724  *
    1725  * @since 3.0.0
    1726  *
    1727  * @return string
    1728  */
    1729 function get_background_image() {
    1730     $default = defined('BACKGROUND_IMAGE') ? BACKGROUND_IMAGE : '';
    1731 
    1732     return get_theme_mod('background_image', $default);
    1733 }
    1734 
    1735 /**
    1736  * Display background image path.
    1737  *
    1738  * @since 3.0.0
    1739  */
    1740 function background_image() {
    1741     echo get_background_image();
    1742 }
    1743 
    1744 /**
    1745  * Retrieve value for custom background color.
    1746  *
    1747  * @since 3.0.0
    1748  * @uses BACKGROUND_COLOR
    1749  *
    1750  * @return string
    1751  */
    1752 function get_background_color() {
    1753     $default = defined('BACKGROUND_COLOR') ? BACKGROUND_COLOR : '';
    1754 
    1755     return get_theme_mod('background_color', $default);
    1756 }
    1757 
    1758 /**
    1759  * Display background color value.
    1760  *
    1761  * @since 3.0.0
    1762  */
    1763 function background_color() {
    1764     echo get_background_color();
    1765 }
    1766 
    1767 /**
    1768  * Add callbacks for background image display.
    1769  *
    1770  * The parameter $header_callback callback will be required to display the
    1771  * content for the 'wp_head' action. The parameter $admin_header_callback
    1772  * callback will be added to Custom_Background class and that will be added
    1773  * to the 'admin_menu' action.
    1774  *
    1775  * @since 3.0.0
    1776  * @uses Custom_Background Sets up for $admin_header_callback for administration panel display.
    1777  *
    1778  * @param callback $header_callback Call on 'wp_head' action.
    1779  * @param callback $admin_header_callback Call on custom background administration screen.
    1780  * @param callback $admin_image_div_callback Output a custom background image div on the custom background administration screen. Optional.
    1781  */
    1782 function add_custom_background( $header_callback = '', $admin_header_callback = '', $admin_image_div_callback = '' ) {
    1783     if ( isset( $GLOBALS['custom_background'] ) )
    1784         return;
    1785 
    1786     if ( empty( $header_callback ) )
    1787         $header_callback = '_custom_background_cb';
    1788 
    1789     add_action( 'wp_head', $header_callback );
    1790 
    1791     add_theme_support( 'custom-background', array( 'callback' => $header_callback ) );
    1792 
    1793     if ( ! is_admin() )
    1794         return;
    1795     require_once( ABSPATH . 'wp-admin/custom-background.php' );
    1796     $GLOBALS['custom_background'] = new Custom_Background( $admin_header_callback, $admin_image_div_callback );
    1797     add_action( 'admin_menu', array( &$GLOBALS['custom_background'], 'init' ) );
    1798 }
    1799 
    1800 /**
    1801  * Remove custom background support.
    1802  *
    1803  * @since 3.1.0
    1804  * @see add_custom_background()
    1805  *
    1806  * @return bool Whether support was removed.
    1807  */
    1808 function remove_custom_background() {
    1809     if ( ! current_theme_supports( 'custom-background' ) )
    1810         return false;
    1811 
    1812     $callback = get_theme_support( 'custom-background' );
    1813     remove_action( 'wp_head', $callback[0]['callback'] );
    1814     _remove_theme_support( 'custom-background' );
    1815 
    1816     if ( is_admin() ) {
    1817         remove_action( 'admin_menu', array( &$GLOBALS['custom_background'], 'init' ) );
    1818         unset( $GLOBALS['custom_background'] );
    1819     }
    1820 
    1821     return true;
    1822 }
    1823 
    1824 /**
    1825  * Default custom background callback.
    1826  *
    1827  * @since 3.0.0
    1828  * @see add_custom_background()
    1829  * @access protected
    1830  */
    1831 function _custom_background_cb() {
    1832     $background = get_background_image();
    1833     $color = get_background_color();
    1834     if ( ! $background && ! $color )
    1835         return;
    1836 
    1837     $style = $color ? "background-color: #$color;" : '';
    1838 
    1839     if ( $background ) {
    1840         $image = " background-image: url('$background');";
    1841 
    1842         $repeat = get_theme_mod( 'background_repeat', 'repeat' );
    1843         if ( ! in_array( $repeat, array( 'no-repeat', 'repeat-x', 'repeat-y', 'repeat' ) ) )
    1844             $repeat = 'repeat';
    1845         $repeat = " background-repeat: $repeat;";
    1846 
    1847         $position = get_theme_mod( 'background_position_x', 'left' );
    1848         if ( ! in_array( $position, array( 'center', 'right', 'left' ) ) )
    1849             $position = 'left';
    1850         $position = " background-position: top $position;";
    1851 
    1852         $attachment = get_theme_mod( 'background_attachment', 'scroll' );
    1853         if ( ! in_array( $attachment, array( 'fixed', 'scroll' ) ) )
    1854             $attachment = 'scroll';
    1855         $attachment = " background-attachment: $attachment;";
    1856 
    1857         $style .= $image . $repeat . $position . $attachment;
    1858     }
    1859 ?>
    1860 <style type="text/css">
    1861 body.custom-background { <?php echo trim( $style ); ?> }
    1862 </style>
    1863 <?php
    1864 }
    1865 
    1866 /**
    1867  * Add callback for custom TinyMCE editor stylesheets.
    1868  *
    1869  * The parameter $stylesheet is the name of the stylesheet, relative to
    1870  * the theme root. It also accepts an array of stylesheets.
    1871  * It is optional and defaults to 'editor-style.css'.
    1872  *
    1873  * Supports RTL stylesheets automatically by searching for the -rtl prefix, e.g.
    1874  * editor-style-rtl.css. If an array of stylesheets is passed to add_editor_style(),
    1875  * RTL is only added for the first stylesheet.
    1876  *
    1877  * @since 3.0.0
    1878  *
    1879  * @param mixed $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
    1880  *  Defaults to 'editor-style.css'
    1881  */
    1882 function add_editor_style( $stylesheet = 'editor-style.css' ) {
    1883 
    1884     add_theme_support( 'editor-style' );
    1885 
    1886     if ( ! is_admin() )
    1887         return;
    1888 
    1889     global $editor_styles;
    1890     $editor_styles = (array) $editor_styles;
    1891     $stylesheet    = (array) $stylesheet;
    1892     if ( is_rtl() ) {
    1893         $rtl_stylesheet = str_replace('.css', '-rtl.css', $stylesheet[0]);
    1894         $stylesheet[] = $rtl_stylesheet;
    1895     }
    1896 
    1897     $editor_styles = array_merge( $editor_styles, $stylesheet );
    1898 }
    1899 
    1900 /**
    1901  * Removes all visual editor stylesheets.
    1902  *
    1903  * @since 3.1.0
    1904  *
    1905  * @return bool True on success, false if there were no stylesheets to remove.
    1906  */
    1907 function remove_editor_styles() {
    1908     if ( ! current_theme_supports( 'editor-style' ) )
    1909         return false;
    1910     _remove_theme_support( 'editor-style' );
    1911     if ( is_admin() )
    1912         $GLOBALS['editor_styles'] = array();
    1913     return true;
    1914 }
    1915 
    1916 /**
    1917  * Allows a theme to register its support of a certain feature
    1918  *
    1919  * Must be called in the theme's functions.php file to work.
    1920  * If attached to a hook, it must be after_setup_theme.
    1921  * The init hook may be too late for some features.
    1922  *
    1923  * @since 2.9.0
    1924  * @param string $feature the feature being added
    1925  */
    1926 function add_theme_support( $feature ) {
    1927     global $_wp_theme_features;
    1928 
    1929     if ( func_num_args() == 1 )
    1930         $_wp_theme_features[$feature] = true;
    1931     else
    1932         $_wp_theme_features[$feature] = array_slice( func_get_args(), 1 );
    1933 
    1934     if ( $feature == 'post-formats' && is_array( $_wp_theme_features[$feature][0] ) )
    1935         $_wp_theme_features[$feature][0] = array_intersect( $_wp_theme_features[$feature][0], array_keys( get_post_format_slugs() ) );
    1936 }
    1937 
    1938 /**
    1939  * Gets the theme support arguments passed when registering that support
    1940  *
    1941  * @since 3.1
    1942  * @param string $feature the feature to check
    1943  * @return array The array of extra arguments
    1944  */
    1945 function get_theme_support( $feature ) {
    1946     global $_wp_theme_features;
    1947     if ( !isset( $_wp_theme_features[$feature] ) )
    1948         return false;
    1949     else
    1950         return $_wp_theme_features[$feature];
    1951 }
    1952 
    1953 /**
    1954  * Allows a theme to de-register its support of a certain feature
    1955  *
    1956  * Should be called in the theme's functions.php file. Generally would
    1957  * be used for child themes to override support from the parent theme.
    1958  *
    1959  * @since 3.0.0
    1960  * @see add_theme_support()
    1961  * @param string $feature the feature being added
    1962  * @return bool Whether feature was removed.
    1963  */
    1964 function remove_theme_support( $feature ) {
    1965     // Blacklist: for internal registrations not used directly by themes.
    1966     if ( in_array( $feature, array( 'custom-background', 'custom-header', 'editor-style', 'widgets', 'menus' ) ) )
    1967         return false;
    1968     return _remove_theme_support( $feature );
    1969 }
    1970 
    1971 /**
    1972  * Do not use. Removes theme support internally, ignorant of the blacklist.
    1973  *
    1974  * @access private
    1975  * @since 3.1.0
    1976  */
    1977 function _remove_theme_support( $feature ) {
    1978     global $_wp_theme_features;
    1979 
    1980     if ( ! isset( $_wp_theme_features[$feature] ) )
    1981         return false;
    1982     unset( $_wp_theme_features[$feature] );
    1983     return true;
    1984 }
    1985 
    1986 /**
    1987  * Checks a theme's support for a given feature
    1988  *
    1989  * @since 2.9.0
    1990  * @param string $feature the feature being checked
    1991  * @return boolean
    1992  */
    1993 function current_theme_supports( $feature ) {
    1994     global $_wp_theme_features;
    1995 
    1996     if ( !isset( $_wp_theme_features[$feature] ) )
    1997         return false;
    1998 
    1999     // If no args passed then no extra checks need be performed
    2000     if ( func_num_args() <= 1 )
    2001         return true;
    2002 
    2003     $args = array_slice( func_get_args(), 1 );
    2004 
    2005     switch ( $feature ) {
    2006         case 'post-thumbnails':
    2007             // post-thumbnails can be registered for only certain content/post types by passing
    2008             // an array of types to add_theme_support(). If no array was passed, then
    2009             // any type is accepted
    2010             if ( true === $_wp_theme_features[$feature] )  // Registered for all types
    2011                 return true;
    2012             $content_type = $args[0];
    2013             return in_array( $content_type, $_wp_theme_features[$feature][0] );
    2014             break;
    2015 
    2016         case 'post-formats':
    2017             // specific post formats can be registered by passing an array of types to
    2018             // add_theme_support()
    2019             $post_format = $args[0];
    2020             return in_array( $post_format, $_wp_theme_features[$feature][0] );
    2021             break;
    2022 
    2023         case 'custom-header':
    2024             // specific custom header capabilities can be registered by passing
    2025             // an array to add_theme_support()
    2026             $header_support = $args[0];
    2027             return ( isset( $_wp_theme_features[$feature][0][$header_support] ) && $_wp_theme_features[$feature][0][$header_support] );
    2028             break;
    2029     }
    2030 
    2031     return apply_filters('current_theme_supports-' . $feature, true, $args, $_wp_theme_features[$feature]);
    2032 }
    2033 
    2034 /**
    2035  * Checks a theme's support for a given feature before loading the functions which implement it.
    2036  *
    2037  * @since 2.9.0
    2038  * @param string $feature the feature being checked
    2039  * @param string $include the file containing the functions that implement the feature
    2040  */
    2041 function require_if_theme_supports( $feature, $include) {
    2042     if ( current_theme_supports( $feature ) )
    2043         require ( $include );
    2044 }
    2045 
    2046 /**
    2047  * Checks an attachment being deleted to see if it's a header or background image.
    2048  *
    2049  * If true it removes the theme modification which would be pointing at the deleted
    2050  * attachment
    2051  *
    2052  * @access private
    2053  * @since 3.0.0
    2054  * @param int $id the attachment id
    2055  */
    2056 function _delete_attachment_theme_mod( $id ) {
    2057     $attachment_image = wp_get_attachment_url( $id );
    2058     $header_image = get_header_image();
    2059     $background_image = get_background_image();
    2060 
    2061     if ( $header_image && $header_image == $attachment_image )
    2062         remove_theme_mod( 'header_image' );
    2063 
    2064     if ( $background_image && $background_image == $attachment_image )
    2065         remove_theme_mod( 'background_image' );
    2066 }
    2067 
    2068 add_action( 'delete_attachment', '_delete_attachment_theme_mod' );
    2069 
    2070 /**
    2071  * Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load
    2072  *
    2073  * @since 3.3.0
    2074  */
    2075 function check_theme_switched() {
    2076     if ( false !== ( $old_theme = get_option( 'theme_switched' ) ) && !empty( $old_theme ) ) {
    2077         do_action( 'after_switch_theme', $old_theme );
    2078         update_option( 'theme_switched', false );
    2079     }
    2080 }
    2081 
    2082 function wp_customize_load() {
    2083     // Load on themes.php or ?customize=on
    2084     if ( ! ( isset( $_REQUEST['customize'] ) && 'on' == $_REQUEST['customize'] ) && 'themes.php' != $GLOBALS['pagenow'] )
    2085         return;
    2086 
    2087     require( ABSPATH . WPINC . '/class-wp-customize.php' );
    2088     // Init Customize class
    2089     // @todo Dependency injection instead
    2090     $GLOBALS['customize'] = new WP_Customize;
    2091 }
    2092 add_action( 'plugins_loaded', 'wp_customize_load' );
Note: See TracChangeset for help on using the changeset viewer.