web/wp-includes/theme.php
branchwordpress
changeset 109 03b0d1493584
child 132 4d4862461b8d
equal deleted inserted replaced
-1:000000000000 109:03b0d1493584
       
     1 <?php
       
     2 /**
       
     3  * Theme, template, and stylesheet functions.
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage Template
       
     7  */
       
     8 
       
     9 /**
       
    10  * Retrieve name of the current stylesheet.
       
    11  *
       
    12  * The theme name that the administrator has currently set the front end theme
       
    13  * as.
       
    14  *
       
    15  * For all extensive purposes, the template name and the stylesheet name are
       
    16  * going to be the same for most cases.
       
    17  *
       
    18  * @since 1.5.0
       
    19  * @uses apply_filters() Calls 'stylesheet' filter on stylesheet name.
       
    20  *
       
    21  * @return string Stylesheet name.
       
    22  */
       
    23 function get_stylesheet() {
       
    24 	return apply_filters('stylesheet', get_option('stylesheet'));
       
    25 }
       
    26 
       
    27 /**
       
    28  * Retrieve stylesheet directory path for current theme.
       
    29  *
       
    30  * @since 1.5.0
       
    31  * @uses apply_filters() Calls 'stylesheet_directory' filter on stylesheet directory and theme name.
       
    32  *
       
    33  * @return string Path to current theme directory.
       
    34  */
       
    35 function get_stylesheet_directory() {
       
    36 	$stylesheet = get_stylesheet();
       
    37 	$stylesheet_dir = get_theme_root() . "/$stylesheet";
       
    38 	return apply_filters('stylesheet_directory', $stylesheet_dir, $stylesheet);
       
    39 }
       
    40 
       
    41 /**
       
    42  * Retrieve stylesheet directory URI.
       
    43  *
       
    44  * @since 1.5.0
       
    45  *
       
    46  * @return string
       
    47  */
       
    48 function get_stylesheet_directory_uri() {
       
    49 	$stylesheet = get_stylesheet();
       
    50 	$stylesheet_dir_uri = get_theme_root_uri() . "/$stylesheet";
       
    51 	return apply_filters('stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet);
       
    52 }
       
    53 
       
    54 /**
       
    55  * Retrieve URI of current theme stylesheet.
       
    56  *
       
    57  * The stylesheet file name is 'style.css' which is appended to {@link
       
    58  * get_stylesheet_directory_uri() stylesheet directory URI} path.
       
    59  *
       
    60  * @since 1.5.0
       
    61  * @uses apply_filters() Calls 'stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
       
    62  *
       
    63  * @return string
       
    64  */
       
    65 function get_stylesheet_uri() {
       
    66 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
       
    67 	$stylesheet_uri = $stylesheet_dir_uri . "/style.css";
       
    68 	return apply_filters('stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
       
    69 }
       
    70 
       
    71 /**
       
    72  * Retrieve localized stylesheet URI.
       
    73  *
       
    74  * The stylesheet directory for the localized stylesheet files are located, by
       
    75  * default, in the base theme directory. The name of the locale file will be the
       
    76  * locale followed by '.css'. If that does not exist, then the text direction
       
    77  * stylesheet will be checked for existence, for example 'ltr.css'.
       
    78  *
       
    79  * The theme may change the location of the stylesheet directory by either using
       
    80  * the 'stylesheet_directory_uri' filter or the 'locale_stylesheet_uri' filter.
       
    81  * If you want to change the location of the stylesheet files for the entire
       
    82  * WordPress workflow, then change the former. If you just have the locale in a
       
    83  * separate folder, then change the latter.
       
    84  *
       
    85  * @since 2.1.0
       
    86  * @uses apply_filters() Calls 'locale_stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
       
    87  *
       
    88  * @return string
       
    89  */
       
    90 function get_locale_stylesheet_uri() {
       
    91 	global $wp_locale;
       
    92 	$stylesheet_dir_uri = get_stylesheet_directory_uri();
       
    93 	$dir = get_stylesheet_directory();
       
    94 	$locale = get_locale();
       
    95 	if ( file_exists("$dir/$locale.css") )
       
    96 		$stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
       
    97 	elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
       
    98 		$stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
       
    99 	else
       
   100 		$stylesheet_uri = '';
       
   101 	return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
       
   102 }
       
   103 
       
   104 /**
       
   105  * Retrieve name of the current theme.
       
   106  *
       
   107  * @since 1.5.0
       
   108  * @uses apply_filters() Calls 'template' filter on template option.
       
   109  *
       
   110  * @return string Template name.
       
   111  */
       
   112 function get_template() {
       
   113 	return apply_filters('template', get_option('template'));
       
   114 }
       
   115 
       
   116 /**
       
   117  * Retrieve current theme directory.
       
   118  *
       
   119  * @since 1.5.0
       
   120  * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
       
   121  *
       
   122  * @return string Template directory path.
       
   123  */
       
   124 function get_template_directory() {
       
   125 	$template = get_template();
       
   126 	$template_dir = get_theme_root() . "/$template";
       
   127 	return apply_filters('template_directory', $template_dir, $template);
       
   128 }
       
   129 
       
   130 /**
       
   131  * Retrieve theme directory URI.
       
   132  *
       
   133  * @since 1.5.0
       
   134  * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
       
   135  *
       
   136  * @return string Template directory URI.
       
   137  */
       
   138 function get_template_directory_uri() {
       
   139 	$template = get_template();
       
   140 	$template_dir_uri = get_theme_root_uri() . "/$template";
       
   141 	return apply_filters('template_directory_uri', $template_dir_uri, $template);
       
   142 }
       
   143 
       
   144 /**
       
   145  * Retrieve theme data from parsed theme file.
       
   146  *
       
   147  * The description will have the tags filtered with the following HTML elements
       
   148  * whitelisted. The <b>'a'</b> element with the <em>href</em> and <em>title</em>
       
   149  * attributes. The <b>abbr</b> element with the <em>title</em> attribute. The
       
   150  * <b>acronym<b> element with the <em>title</em> attribute allowed. The
       
   151  * <b>code</b>, <b>em</b>, and <b>strong</b> elements also allowed.
       
   152  *
       
   153  * The style.css file must contain theme name, theme URI, and description. The
       
   154  * data can also contain author URI, author, template (parent template),
       
   155  * version, status, and finally tags. Some of these are not used by WordPress
       
   156  * administration panels, but are used by theme directory web sites which list
       
   157  * the theme.
       
   158  *
       
   159  * @since 1.5.0
       
   160  *
       
   161  * @param string $theme_file Theme file path.
       
   162  * @return array Theme data.
       
   163  */
       
   164 function get_theme_data( $theme_file ) {
       
   165 	$themes_allowed_tags = array(
       
   166 		'a' => array(
       
   167 			'href' => array(),'title' => array()
       
   168 			),
       
   169 		'abbr' => array(
       
   170 			'title' => array()
       
   171 			),
       
   172 		'acronym' => array(
       
   173 			'title' => array()
       
   174 			),
       
   175 		'code' => array(),
       
   176 		'em' => array(),
       
   177 		'strong' => array()
       
   178 	);
       
   179 
       
   180 	$theme_data = implode( '', file( $theme_file ) );
       
   181 	$theme_data = str_replace ( '\r', '\n', $theme_data );
       
   182 	if ( preg_match( '|Theme Name:(.*)$|mi', $theme_data, $theme_name ) )
       
   183 		$name = $theme = wp_kses( _cleanup_header_comment($theme_name[1]), $themes_allowed_tags );
       
   184 	else
       
   185 		$name = $theme = '';
       
   186 
       
   187 	if ( preg_match( '|Theme URI:(.*)$|mi', $theme_data, $theme_uri ) )
       
   188 		$theme_uri = esc_url( _cleanup_header_comment($theme_uri[1]) );
       
   189 	else
       
   190 		$theme_uri = '';
       
   191 
       
   192 	if ( preg_match( '|Description:(.*)$|mi', $theme_data, $description ) )
       
   193 		$description = wptexturize( wp_kses( _cleanup_header_comment($description[1]), $themes_allowed_tags ) );
       
   194 	else
       
   195 		$description = '';
       
   196 
       
   197 	if ( preg_match( '|Author URI:(.*)$|mi', $theme_data, $author_uri ) )
       
   198 		$author_uri = esc_url( _cleanup_header_comment($author_uri[1]) );
       
   199 	else
       
   200 		$author_uri = '';
       
   201 
       
   202 	if ( preg_match( '|Template:(.*)$|mi', $theme_data, $template ) )
       
   203 		$template = wp_kses( _cleanup_header_comment($template[1]), $themes_allowed_tags );
       
   204 	else
       
   205 		$template = '';
       
   206 
       
   207 	if ( preg_match( '|Version:(.*)|i', $theme_data, $version ) )
       
   208 		$version = wp_kses( _cleanup_header_comment($version[1]), $themes_allowed_tags );
       
   209 	else
       
   210 		$version = '';
       
   211 
       
   212 	if ( preg_match('|Status:(.*)|i', $theme_data, $status) )
       
   213 		$status = wp_kses( _cleanup_header_comment($status[1]), $themes_allowed_tags );
       
   214 	else
       
   215 		$status = 'publish';
       
   216 
       
   217 	if ( preg_match('|Tags:(.*)|i', $theme_data, $tags) )
       
   218 		$tags = array_map( 'trim', explode( ',', wp_kses( _cleanup_header_comment($tags[1]), array() ) ) );
       
   219 	else
       
   220 		$tags = array();
       
   221 
       
   222 	if ( preg_match( '|Author:(.*)$|mi', $theme_data, $author_name ) ) {
       
   223 		if ( empty( $author_uri ) ) {
       
   224 			$author = wp_kses( _cleanup_header_comment($author_name[1]), $themes_allowed_tags );
       
   225 		} else {
       
   226 			$author = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $author_uri, __( 'Visit author homepage' ), wp_kses( _cleanup_header_comment($author_name[1]), $themes_allowed_tags ) );
       
   227 		}
       
   228 	} else {
       
   229 		$author = __('Anonymous');
       
   230 	}
       
   231 
       
   232 	return array( 'Name' => $name, 'Title' => $theme, 'URI' => $theme_uri, 'Description' => $description, 'Author' => $author, 'Version' => $version, 'Template' => $template, 'Status' => $status, 'Tags' => $tags );
       
   233 }
       
   234 
       
   235 /**
       
   236  * Retrieve list of themes with theme data in theme directory.
       
   237  *
       
   238  * The theme is broken, if it doesn't have a parent theme and is missing either
       
   239  * style.css and, or index.php. If the theme has a parent theme then it is
       
   240  * broken, if it is missing style.css; index.php is optional. The broken theme
       
   241  * list is saved in the {@link $wp_broken_themes} global, which is displayed on
       
   242  * the theme list in the administration panels.
       
   243  *
       
   244  * @since 1.5.0
       
   245  * @global array $wp_broken_themes Stores the broken themes.
       
   246  * @global array $wp_themes Stores the working themes.
       
   247  *
       
   248  * @return array Theme list with theme data.
       
   249  */
       
   250 function get_themes() {
       
   251 	global $wp_themes, $wp_broken_themes;
       
   252 
       
   253 	if ( isset($wp_themes) )
       
   254 		return $wp_themes;
       
   255 
       
   256 	$themes = array();
       
   257 	$wp_broken_themes = array();
       
   258 	$theme_loc = $theme_root = get_theme_root();
       
   259 	if ( '/' != WP_CONTENT_DIR ) // don't want to replace all forward slashes, see Trac #4541
       
   260 		$theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
       
   261 
       
   262 	// Files in wp-content/themes directory and one subdir down
       
   263 	$themes_dir = @ opendir($theme_root);
       
   264 	if ( !$themes_dir )
       
   265 		return false;
       
   266 
       
   267 	while ( ($theme_dir = readdir($themes_dir)) !== false ) {
       
   268 		if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
       
   269 			if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
       
   270 				continue;
       
   271 			$stylish_dir = @ opendir($theme_root . '/' . $theme_dir);
       
   272 			$found_stylesheet = false;
       
   273 			while ( ($theme_file = readdir($stylish_dir)) !== false ) {
       
   274 				if ( $theme_file == 'style.css' ) {
       
   275 					$theme_files[] = $theme_dir . '/' . $theme_file;
       
   276 					$found_stylesheet = true;
       
   277 					break;
       
   278 				}
       
   279 			}
       
   280 			@closedir($stylish_dir);
       
   281 			if ( !$found_stylesheet ) { // look for themes in that dir
       
   282 				$subdir = "$theme_root/$theme_dir";
       
   283 				$subdir_name = $theme_dir;
       
   284 				$theme_subdir = @ opendir( $subdir );
       
   285 				while ( ($theme_dir = readdir($theme_subdir)) !== false ) {
       
   286 					if ( is_dir( $subdir . '/' . $theme_dir) && is_readable($subdir . '/' . $theme_dir) ) {
       
   287 						if ( $theme_dir{0} == '.' || $theme_dir == '..' || $theme_dir == 'CVS' )
       
   288 							continue;
       
   289 						$stylish_dir = @ opendir($subdir . '/' . $theme_dir);
       
   290 						$found_stylesheet = false;
       
   291 						while ( ($theme_file = readdir($stylish_dir)) !== false ) {
       
   292 							if ( $theme_file == 'style.css' ) {
       
   293 								$theme_files[] = $subdir_name . '/' . $theme_dir . '/' . $theme_file;
       
   294 								$found_stylesheet = true;
       
   295 								break;
       
   296 							}
       
   297 						}
       
   298 						@closedir($stylish_dir);
       
   299 					}
       
   300 				}
       
   301 				@closedir($theme_subdir);
       
   302 				$wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
       
   303 			}
       
   304 		}
       
   305 	}
       
   306 	if ( is_dir( $theme_dir ) )
       
   307 		@closedir( $theme_dir );
       
   308 
       
   309 	if ( !$themes_dir || !$theme_files )
       
   310 		return $themes;
       
   311 
       
   312 	sort($theme_files);
       
   313 
       
   314 	foreach ( (array) $theme_files as $theme_file ) {
       
   315 		if ( !is_readable("$theme_root/$theme_file") ) {
       
   316 			$wp_broken_themes[$theme_file] = array('Name' => $theme_file, 'Title' => $theme_file, 'Description' => __('File not readable.'));
       
   317 			continue;
       
   318 		}
       
   319 
       
   320 		$theme_data = get_theme_data("$theme_root/$theme_file");
       
   321 
       
   322 		$name        = $theme_data['Name'];
       
   323 		$title       = $theme_data['Title'];
       
   324 		$description = wptexturize($theme_data['Description']);
       
   325 		$version     = $theme_data['Version'];
       
   326 		$author      = $theme_data['Author'];
       
   327 		$template    = $theme_data['Template'];
       
   328 		$stylesheet  = dirname($theme_file);
       
   329 
       
   330 		$screenshot = false;
       
   331 		foreach ( array('png', 'gif', 'jpg', 'jpeg') as $ext ) {
       
   332 			if (file_exists("$theme_root/$stylesheet/screenshot.$ext")) {
       
   333 				$screenshot = "screenshot.$ext";
       
   334 				break;
       
   335 			}
       
   336 		}
       
   337 
       
   338 		if ( empty($name) ) {
       
   339 			$name = dirname($theme_file);
       
   340 			$title = $name;
       
   341 		}
       
   342 
       
   343 		if ( empty($template) ) {
       
   344 			if ( file_exists(dirname("$theme_root/$theme_file/index.php")) )
       
   345 				$template = dirname($theme_file);
       
   346 			else
       
   347 				continue;
       
   348 		}
       
   349 
       
   350 		$template = trim($template);
       
   351 
       
   352 		if ( !file_exists("$theme_root/$template/index.php") ) {
       
   353 			$parent_dir = dirname(dirname($theme_file));
       
   354 			if ( file_exists("$theme_root/$parent_dir/$template/index.php") ) {
       
   355 				$template = "$parent_dir/$template";
       
   356 			} else {
       
   357 				$wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => __('Template is missing.'));
       
   358 				continue;
       
   359 			}
       
   360 		}
       
   361 
       
   362 		$stylesheet_files = array();
       
   363 		$template_files = array();
       
   364 
       
   365 		$stylesheet_dir = @ dir("$theme_root/$stylesheet");
       
   366 		if ( $stylesheet_dir ) {
       
   367 			while ( ($file = $stylesheet_dir->read()) !== false ) {
       
   368 				if ( !preg_match('|^\.+$|', $file) ) {
       
   369 					if ( preg_match('|\.css$|', $file) )
       
   370 						$stylesheet_files[] = "$theme_loc/$stylesheet/$file";
       
   371 					elseif ( preg_match('|\.php$|', $file) )
       
   372 						$template_files[] = "$theme_loc/$stylesheet/$file";
       
   373 				}
       
   374 			}
       
   375 			@ $stylesheet_dir->close();
       
   376 		}
       
   377 
       
   378 		$template_dir = @ dir("$theme_root/$template");
       
   379 		if ( $template_dir ) {
       
   380 			while ( ($file = $template_dir->read()) !== false ) {
       
   381 				if ( preg_match('|^\.+$|', $file) )
       
   382 					continue;
       
   383 				if ( preg_match('|\.php$|', $file) ) {
       
   384 					$template_files[] = "$theme_loc/$template/$file";
       
   385 				} elseif ( is_dir("$theme_root/$template/$file") ) {
       
   386 					$template_subdir = @ dir("$theme_root/$template/$file");
       
   387 					while ( ($subfile = $template_subdir->read()) !== false ) {
       
   388 						if ( preg_match('|^\.+$|', $subfile) )
       
   389 							continue;
       
   390 						if ( preg_match('|\.php$|', $subfile) )
       
   391 							$template_files[] = "$theme_loc/$template/$file/$subfile";
       
   392 					}
       
   393 					@ $template_subdir->close();
       
   394 				}
       
   395 			}
       
   396 			@ $template_dir->close();
       
   397 		}
       
   398 
       
   399 		$template_dir = dirname($template_files[0]);
       
   400 		$stylesheet_dir = dirname($stylesheet_files[0]);
       
   401 
       
   402 		if ( empty($template_dir) )
       
   403 			$template_dir = '/';
       
   404 		if ( empty($stylesheet_dir) )
       
   405 			$stylesheet_dir = '/';
       
   406 
       
   407 		// Check for theme name collision.  This occurs if a theme is copied to
       
   408 		// a new theme directory and the theme header is not updated.  Whichever
       
   409 		// theme is first keeps the name.  Subsequent themes get a suffix applied.
       
   410 		// The Default and Classic themes always trump their pretenders.
       
   411 		if ( isset($themes[$name]) ) {
       
   412 			if ( ('WordPress Default' == $name || 'WordPress Classic' == $name) &&
       
   413 					 ('default' == $stylesheet || 'classic' == $stylesheet) ) {
       
   414 				// If another theme has claimed to be one of our default themes, move
       
   415 				// them aside.
       
   416 				$suffix = $themes[$name]['Stylesheet'];
       
   417 				$new_name = "$name/$suffix";
       
   418 				$themes[$new_name] = $themes[$name];
       
   419 				$themes[$new_name]['Name'] = $new_name;
       
   420 			} else {
       
   421 				$name = "$name/$stylesheet";
       
   422 			}
       
   423 		}
       
   424 
       
   425 		$themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => $description, 'Author' => $author, 'Version' => $version, 'Template' => $template, 'Stylesheet' => $stylesheet, 'Template Files' => $template_files, 'Stylesheet Files' => $stylesheet_files, 'Template Dir' => $template_dir, 'Stylesheet Dir' => $stylesheet_dir, 'Status' => $theme_data['Status'], 'Screenshot' => $screenshot, 'Tags' => $theme_data['Tags']);
       
   426 	}
       
   427 
       
   428 	// Resolve theme dependencies.
       
   429 	$theme_names = array_keys($themes);
       
   430 
       
   431 	foreach ( (array) $theme_names as $theme_name ) {
       
   432 		$themes[$theme_name]['Parent Theme'] = '';
       
   433 		if ( $themes[$theme_name]['Stylesheet'] != $themes[$theme_name]['Template'] ) {
       
   434 			foreach ( (array) $theme_names as $parent_theme_name ) {
       
   435 				if ( ($themes[$parent_theme_name]['Stylesheet'] == $themes[$parent_theme_name]['Template']) && ($themes[$parent_theme_name]['Template'] == $themes[$theme_name]['Template']) ) {
       
   436 					$themes[$theme_name]['Parent Theme'] = $themes[$parent_theme_name]['Name'];
       
   437 					break;
       
   438 				}
       
   439 			}
       
   440 		}
       
   441 	}
       
   442 
       
   443 	$wp_themes = $themes;
       
   444 
       
   445 	return $themes;
       
   446 }
       
   447 
       
   448 /**
       
   449  * Retrieve theme data.
       
   450  *
       
   451  * @since 1.5.0
       
   452  *
       
   453  * @param string $theme Theme name.
       
   454  * @return array|null Null, if theme name does not exist. Theme data, if exists.
       
   455  */
       
   456 function get_theme($theme) {
       
   457 	$themes = get_themes();
       
   458 
       
   459 	if ( array_key_exists($theme, $themes) )
       
   460 		return $themes[$theme];
       
   461 
       
   462 	return null;
       
   463 }
       
   464 
       
   465 /**
       
   466  * Retrieve current theme display name.
       
   467  *
       
   468  * If the 'current_theme' option has already been set, then it will be returned
       
   469  * instead. If it is not set, then each theme will be iterated over until both
       
   470  * the current stylesheet and current template name.
       
   471  *
       
   472  * @since 1.5.0
       
   473  *
       
   474  * @return string
       
   475  */
       
   476 function get_current_theme() {
       
   477 	if ( $theme = get_option('current_theme') )
       
   478 		return $theme;
       
   479 
       
   480 	$themes = get_themes();
       
   481 	$theme_names = array_keys($themes);
       
   482 	$current_template = get_option('template');
       
   483 	$current_stylesheet = get_option('stylesheet');
       
   484 	$current_theme = 'WordPress Default';
       
   485 
       
   486 	if ( $themes ) {
       
   487 		foreach ( (array) $theme_names as $theme_name ) {
       
   488 			if ( $themes[$theme_name]['Stylesheet'] == $current_stylesheet &&
       
   489 					$themes[$theme_name]['Template'] == $current_template ) {
       
   490 				$current_theme = $themes[$theme_name]['Name'];
       
   491 				break;
       
   492 			}
       
   493 		}
       
   494 	}
       
   495 
       
   496 	update_option('current_theme', $current_theme);
       
   497 
       
   498 	return $current_theme;
       
   499 }
       
   500 
       
   501 /**
       
   502  * Retrieve path to themes directory.
       
   503  *
       
   504  * Does not have trailing slash.
       
   505  *
       
   506  * @since 1.5.0
       
   507  * @uses apply_filters() Calls 'theme_root' filter on path.
       
   508  *
       
   509  * @return string Theme path.
       
   510  */
       
   511 function get_theme_root() {
       
   512 	return apply_filters('theme_root', WP_CONTENT_DIR . "/themes");
       
   513 }
       
   514 
       
   515 /**
       
   516  * Retrieve URI for themes directory.
       
   517  *
       
   518  * Does not have trailing slash.
       
   519  *
       
   520  * @since 1.5.0
       
   521  *
       
   522  * @return string Themes URI.
       
   523  */
       
   524 function get_theme_root_uri() {
       
   525 	return apply_filters('theme_root_uri', content_url('themes'), get_option('siteurl'));
       
   526 }
       
   527 
       
   528 /**
       
   529  * Retrieve path to file without the use of extension.
       
   530  *
       
   531  * Used to quickly retrieve the path of file without including the file
       
   532  * extension. It will also check the parent template, if the file exists, with
       
   533  * the use of {@link locate_template()}. Allows for more generic file location
       
   534  * without the use of the other get_*_template() functions.
       
   535  *
       
   536  * Can be used with include() or require() to retrieve path.
       
   537  * <code>
       
   538  * if( '' != get_query_template( '404' ) )
       
   539  *     include( get_query_template( '404' ) );
       
   540  * </code>
       
   541  * or the same can be accomplished with
       
   542  * <code>
       
   543  * if( '' != get_404_template() )
       
   544  *     include( get_404_template() );
       
   545  * </code>
       
   546  *
       
   547  * @since 1.5.0
       
   548  *
       
   549  * @param string $type Filename without extension.
       
   550  * @return string Full path to file.
       
   551  */
       
   552 function get_query_template($type) {
       
   553 	$type = preg_replace( '|[^a-z0-9-]+|', '', $type );
       
   554 	return apply_filters("{$type}_template", locate_template(array("{$type}.php")));
       
   555 }
       
   556 
       
   557 /**
       
   558  * Retrieve path of 404 template in current or parent template.
       
   559  *
       
   560  * @since 1.5.0
       
   561  *
       
   562  * @return string
       
   563  */
       
   564 function get_404_template() {
       
   565 	return get_query_template('404');
       
   566 }
       
   567 
       
   568 /**
       
   569  * Retrieve path of archive template in current or parent template.
       
   570  *
       
   571  * @since 1.5.0
       
   572  *
       
   573  * @return string
       
   574  */
       
   575 function get_archive_template() {
       
   576 	return get_query_template('archive');
       
   577 }
       
   578 
       
   579 /**
       
   580  * Retrieve path of author template in current or parent template.
       
   581  *
       
   582  * @since 1.5.0
       
   583  *
       
   584  * @return string
       
   585  */
       
   586 function get_author_template() {
       
   587 	return get_query_template('author');
       
   588 }
       
   589 
       
   590 /**
       
   591  * Retrieve path of category template in current or parent template.
       
   592  *
       
   593  * Works by retrieving the current category ID, for example 'category-1.php' and
       
   594  * will fallback to category.php template, if the ID category file doesn't
       
   595  * exist.
       
   596  *
       
   597  * @since 1.5.0
       
   598  * @uses apply_filters() Calls 'category_template' on file path of category template.
       
   599  *
       
   600  * @return string
       
   601  */
       
   602 function get_category_template() {
       
   603 	$template = locate_template(array("category-" . absint( get_query_var('cat') ) . '.php', 'category.php'));
       
   604 	return apply_filters('category_template', $template);
       
   605 }
       
   606 
       
   607 /**
       
   608  * Retrieve path of tag template in current or parent template.
       
   609  *
       
   610  * Works by retrieving the current tag name, for example 'tag-wordpress.php' and will
       
   611  * fallback to tag.php template, if the name tag file doesn't exist.
       
   612  *
       
   613  * @since 2.3.0
       
   614  * @uses apply_filters() Calls 'tag_template' on file path of tag template.
       
   615  *
       
   616  * @return string
       
   617  */
       
   618 function get_tag_template() {
       
   619 	$template = locate_template(array("tag-" . get_query_var('tag') . '.php', 'tag.php'));
       
   620 	return apply_filters('tag_template', $template);
       
   621 }
       
   622 
       
   623 /**
       
   624  * Retrieve path of taxonomy template in current or parent template.
       
   625  *
       
   626  * Retrieves the taxonomy and term, if term is available. The template is
       
   627  * prepended with 'taxonomy-' and followed by both the taxonomy string and
       
   628  * the taxonomy string followed by a dash and then followed by the term.
       
   629  *
       
   630  * The taxonomy and term template is checked and used first, if it exists.
       
   631  * Second, just the taxonomy template is checked, and then finally, taxonomy.php
       
   632  * template is used. If none of the files exist, then it will fall back on to
       
   633  * index.php.
       
   634  *
       
   635  * @since unknown (2.6.0 most likely)
       
   636  * @uses apply_filters() Calls 'taxonomy_template' filter on found path.
       
   637  *
       
   638  * @return string
       
   639  */
       
   640 function get_taxonomy_template() {
       
   641 	$taxonomy = get_query_var('taxonomy');
       
   642 	$term = get_query_var('term');
       
   643 
       
   644 	$templates = array();
       
   645 	if ( $taxonomy && $term )
       
   646 		$templates[] = "taxonomy-$taxonomy-$term.php";
       
   647 	if ( $taxonomy )
       
   648 		$templates[] = "taxonomy-$taxonomy.php";
       
   649 
       
   650 	$templates[] = "taxonomy.php";
       
   651 
       
   652 	$template = locate_template($templates);
       
   653 	return apply_filters('taxonomy_template', $template);
       
   654 }
       
   655 
       
   656 /**
       
   657  * Retrieve path of date template in current or parent template.
       
   658  *
       
   659  * @since 1.5.0
       
   660  *
       
   661  * @return string
       
   662  */
       
   663 function get_date_template() {
       
   664 	return get_query_template('date');
       
   665 }
       
   666 
       
   667 /**
       
   668  * Retrieve path of home template in current or parent template.
       
   669  *
       
   670  * Attempts to locate 'home.php' first before falling back to 'index.php'.
       
   671  *
       
   672  * @since 1.5.0
       
   673  * @uses apply_filters() Calls 'home_template' on file path of home template.
       
   674  *
       
   675  * @return string
       
   676  */
       
   677 function get_home_template() {
       
   678 	$template = locate_template(array('home.php', 'index.php'));
       
   679 	return apply_filters('home_template', $template);
       
   680 }
       
   681 
       
   682 /**
       
   683  * Retrieve path of page template in current or parent template.
       
   684  *
       
   685  * First attempt is to look for the file in the '_wp_page_template' page meta
       
   686  * data. The second attempt, if the first has a file and is not empty, is to
       
   687  * look for 'page.php'.
       
   688  *
       
   689  * @since 1.5.0
       
   690  *
       
   691  * @return string
       
   692  */
       
   693 function get_page_template() {
       
   694 	global $wp_query;
       
   695 
       
   696 	$id = (int) $wp_query->post->ID;
       
   697 	$template = get_post_meta($id, '_wp_page_template', true);
       
   698 
       
   699 	if ( 'default' == $template )
       
   700 		$template = '';
       
   701 
       
   702 	$templates = array();
       
   703 	if ( !empty($template) && !validate_file($template) )
       
   704 		$templates[] = $template;
       
   705 
       
   706 	$templates[] = "page.php";
       
   707 
       
   708 	return apply_filters('page_template', locate_template($templates));
       
   709 }
       
   710 
       
   711 /**
       
   712  * Retrieve path of paged template in current or parent template.
       
   713  *
       
   714  * @since 1.5.0
       
   715  *
       
   716  * @return string
       
   717  */
       
   718 function get_paged_template() {
       
   719 	return get_query_template('paged');
       
   720 }
       
   721 
       
   722 /**
       
   723  * Retrieve path of search template in current or parent template.
       
   724  *
       
   725  * @since 1.5.0
       
   726  *
       
   727  * @return string
       
   728  */
       
   729 function get_search_template() {
       
   730 	return get_query_template('search');
       
   731 }
       
   732 
       
   733 /**
       
   734  * Retrieve path of single template in current or parent template.
       
   735  *
       
   736  * @since 1.5.0
       
   737  *
       
   738  * @return string
       
   739  */
       
   740 function get_single_template() {
       
   741 	return get_query_template('single');
       
   742 }
       
   743 
       
   744 /**
       
   745  * Retrieve path of attachment template in current or parent template.
       
   746  *
       
   747  * The attachment path first checks if the first part of the mime type exists.
       
   748  * The second check is for the second part of the mime type. The last check is
       
   749  * for both types separated by an underscore. If neither are found then the file
       
   750  * 'attachment.php' is checked and returned.
       
   751  *
       
   752  * Some examples for the 'text/plain' mime type are 'text.php', 'plain.php', and
       
   753  * finally 'text_plain.php'.
       
   754  *
       
   755  * @since 2.0.0
       
   756  *
       
   757  * @return string
       
   758  */
       
   759 function get_attachment_template() {
       
   760 	global $posts;
       
   761 	$type = explode('/', $posts[0]->post_mime_type);
       
   762 	if ( $template = get_query_template($type[0]) )
       
   763 		return $template;
       
   764 	elseif ( $template = get_query_template($type[1]) )
       
   765 		return $template;
       
   766 	elseif ( $template = get_query_template("$type[0]_$type[1]") )
       
   767 		return $template;
       
   768 	else
       
   769 		return get_query_template('attachment');
       
   770 }
       
   771 
       
   772 /**
       
   773  * Retrieve path of comment popup template in current or parent template.
       
   774  *
       
   775  * Checks for comment popup template in current template, if it exists or in the
       
   776  * parent template. If it doesn't exist, then it retrieves the comment-popup.php
       
   777  * file from the default theme. The default theme must then exist for it to
       
   778  * work.
       
   779  *
       
   780  * @since 1.5.0
       
   781  * @uses apply_filters() Calls 'comments_popup_template' filter on path.
       
   782  *
       
   783  * @return string
       
   784  */
       
   785 function get_comments_popup_template() {
       
   786 	$template = locate_template(array("comments-popup.php"));
       
   787 	if ('' == $template)
       
   788 		$template = get_theme_root() . '/default/comments-popup.php';
       
   789 
       
   790 	return apply_filters('comments_popup_template', $template);
       
   791 }
       
   792 
       
   793 /**
       
   794  * Retrieve the name of the highest priority template file that exists.
       
   795  *
       
   796  * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
       
   797  * inherit from a parent theme can just overload one file.
       
   798  *
       
   799  * @since 2.7.0
       
   800  *
       
   801  * @param array $template_names Array of template files to search for in priority order.
       
   802  * @param bool $load If true the template file will be loaded if it is found.
       
   803  * @return string The template filename if one is located.
       
   804  */
       
   805 function locate_template($template_names, $load = false) {
       
   806 	if (!is_array($template_names))
       
   807 		return '';
       
   808 
       
   809 	$located = '';
       
   810 	foreach($template_names as $template_name) {
       
   811 		if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
       
   812 			$located = STYLESHEETPATH . '/' . $template_name;
       
   813 			break;
       
   814 		} else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
       
   815 			$located = TEMPLATEPATH . '/' . $template_name;
       
   816 			break;
       
   817 		}
       
   818 	}
       
   819 
       
   820 	if ($load && '' != $located)
       
   821 		load_template($located);
       
   822 
       
   823 	return $located;
       
   824 }
       
   825 
       
   826 /**
       
   827  * Require once the template file with WordPress environment.
       
   828  *
       
   829  * The globals are set up for the template file to ensure that the WordPress
       
   830  * environment is available from within the function. The query variables are
       
   831  * also available.
       
   832  *
       
   833  * @since 1.5.0
       
   834  *
       
   835  * @param string $_template_file Path to template file.
       
   836  */
       
   837 function load_template($_template_file) {
       
   838 	global $posts, $post, $wp_did_header, $wp_did_template_redirect, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
       
   839 
       
   840 	if ( is_array($wp_query->query_vars) )
       
   841 		extract($wp_query->query_vars, EXTR_SKIP);
       
   842 
       
   843 	require_once($_template_file);
       
   844 }
       
   845 
       
   846 /**
       
   847  * Display localized stylesheet link element.
       
   848  *
       
   849  * @since 2.1.0
       
   850  */
       
   851 function locale_stylesheet() {
       
   852 	$stylesheet = get_locale_stylesheet_uri();
       
   853 	if ( empty($stylesheet) )
       
   854 		return;
       
   855 	echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
       
   856 }
       
   857 
       
   858 /**
       
   859  * Start preview theme output buffer.
       
   860  *
       
   861  * Will only preform task if the user has permissions and template and preview
       
   862  * query variables exist.
       
   863  *
       
   864  * @since 2.5.0
       
   865  */
       
   866 function preview_theme() {
       
   867 	if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
       
   868 		return;
       
   869 
       
   870 	if ( !current_user_can( 'switch_themes' ) )
       
   871 		return;
       
   872 
       
   873 	$_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
       
   874 
       
   875 	if ( validate_file($_GET['template']) )
       
   876 		return;
       
   877 
       
   878 	add_filter( 'template', '_preview_theme_template_filter' );
       
   879 
       
   880 	if ( isset($_GET['stylesheet']) ) {
       
   881 		$_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
       
   882 		if ( validate_file($_GET['stylesheet']) )
       
   883 			return;
       
   884 		add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
       
   885 	}
       
   886 
       
   887 	// Prevent theme mods to current theme being used on theme being previewed
       
   888 	add_filter( 'pre_option_mods_' . get_current_theme(), create_function( '', "return array();" ) );
       
   889 
       
   890 	ob_start( 'preview_theme_ob_filter' );
       
   891 }
       
   892 add_action('setup_theme', 'preview_theme');
       
   893 
       
   894 /**
       
   895  * Private function to modify the current template when previewing a theme
       
   896  * 
       
   897  * @return string
       
   898  */
       
   899 function _preview_theme_template_filter() {
       
   900 	return isset($_GET['template']) ? $_GET['template'] : '';
       
   901 }
       
   902 
       
   903 /**
       
   904  * Private function to modify the current stylesheet when previewing a theme
       
   905  * 
       
   906  * @return string
       
   907  */
       
   908 function _preview_theme_stylesheet_filter() {
       
   909 	return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
       
   910 }
       
   911 
       
   912 /**
       
   913  * Callback function for ob_start() to capture all links in the theme.
       
   914  *
       
   915  * @since unknown
       
   916  * @access private
       
   917  *
       
   918  * @param string $content
       
   919  * @return string
       
   920  */
       
   921 function preview_theme_ob_filter( $content ) {
       
   922 	return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
       
   923 }
       
   924 
       
   925 /**
       
   926  * Manipulates preview theme links in order to control and maintain location.
       
   927  *
       
   928  * Callback function for preg_replace_callback() to accept and filter matches.
       
   929  *
       
   930  * @since unknown
       
   931  * @access private
       
   932  *
       
   933  * @param array $matches
       
   934  * @return string
       
   935  */
       
   936 function preview_theme_ob_filter_callback( $matches ) {
       
   937 	if ( strpos($matches[4], 'onclick') !== false )
       
   938 		$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.
       
   939 	if (
       
   940 		( false !== strpos($matches[3], '/wp-admin/') )
       
   941 	||
       
   942 		( false !== strpos($matches[3], '://') && 0 !== strpos($matches[3], get_option('home')) )
       
   943 	||
       
   944 		( false !== strpos($matches[3], '/feed/') )
       
   945 	||
       
   946 		( false !== strpos($matches[3], '/trackback/') )
       
   947 	)
       
   948 		return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
       
   949 
       
   950 	$link = add_query_arg( array('preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'] ), $matches[3] );
       
   951 	if ( 0 === strpos($link, 'preview=1') )
       
   952 		$link = "?$link";
       
   953 	return $matches[1] . esc_attr( $link ) . $matches[4];
       
   954 }
       
   955 
       
   956 /**
       
   957  * Switches current theme to new template and stylesheet names.
       
   958  *
       
   959  * @since unknown
       
   960  * @uses do_action() Calls 'switch_theme' action on updated theme display name.
       
   961  *
       
   962  * @param string $template Template name
       
   963  * @param string $stylesheet Stylesheet name.
       
   964  */
       
   965 function switch_theme($template, $stylesheet) {
       
   966 	update_option('template', $template);
       
   967 	update_option('stylesheet', $stylesheet);
       
   968 	delete_option('current_theme');
       
   969 	$theme = get_current_theme();
       
   970 	do_action('switch_theme', $theme);
       
   971 }
       
   972 
       
   973 /**
       
   974  * Checks that current theme files 'index.php' and 'style.css' exists.
       
   975  *
       
   976  * Does not check the 'default' theme. The 'default' theme should always exist
       
   977  * or should have another theme renamed to that template name and directory
       
   978  * path. Will switch theme to default if current theme does not validate.
       
   979  * You can use the 'validate_current_theme' filter to return FALSE to
       
   980  * disable this functionality.
       
   981  *
       
   982  * @since 1.5.0
       
   983  *
       
   984  * @return bool
       
   985  */
       
   986 function validate_current_theme() {
       
   987 	// Don't validate during an install/upgrade.
       
   988 	if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
       
   989 		return true;
       
   990 
       
   991 	if ( get_template() != 'default' && !file_exists(get_template_directory() . '/index.php') ) {
       
   992 		switch_theme('default', 'default');
       
   993 		return false;
       
   994 	}
       
   995 
       
   996 	if ( get_stylesheet() != 'default' && !file_exists(get_template_directory() . '/style.css') ) {
       
   997 		switch_theme('default', 'default');
       
   998 		return false;
       
   999 	}
       
  1000 
       
  1001 	return true;
       
  1002 }
       
  1003 
       
  1004 /**
       
  1005  * Retrieve theme modification value for the current theme.
       
  1006  *
       
  1007  * If the modification name does not exist, then the $default will be passed
       
  1008  * through {@link http://php.net/sprintf sprintf()} PHP function with the first
       
  1009  * string the template directory URI and the second string the stylesheet
       
  1010  * directory URI.
       
  1011  *
       
  1012  * @since 2.1.0
       
  1013  * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
       
  1014  *
       
  1015  * @param string $name Theme modification name.
       
  1016  * @param bool|string $default
       
  1017  * @return string
       
  1018  */
       
  1019 function get_theme_mod($name, $default = false) {
       
  1020 	$theme = get_current_theme();
       
  1021 
       
  1022 	$mods = get_option("mods_$theme");
       
  1023 
       
  1024 	if ( isset($mods[$name]) )
       
  1025 		return apply_filters( "theme_mod_$name", $mods[$name] );
       
  1026 
       
  1027 	return apply_filters( "theme_mod_$name", sprintf($default, get_template_directory_uri(), get_stylesheet_directory_uri()) );
       
  1028 }
       
  1029 
       
  1030 /**
       
  1031  * Update theme modification value for the current theme.
       
  1032  *
       
  1033  * @since 2.1.0
       
  1034  *
       
  1035  * @param string $name Theme modification name.
       
  1036  * @param string $value theme modification value.
       
  1037  */
       
  1038 function set_theme_mod($name, $value) {
       
  1039 	$theme = get_current_theme();
       
  1040 
       
  1041 	$mods = get_option("mods_$theme");
       
  1042 
       
  1043 	$mods[$name] = $value;
       
  1044 
       
  1045 	update_option("mods_$theme", $mods);
       
  1046 	wp_cache_delete("mods_$theme", 'options');
       
  1047 }
       
  1048 
       
  1049 /**
       
  1050  * Remove theme modification name from current theme list.
       
  1051  *
       
  1052  * If removing the name also removes all elements, then the entire option will
       
  1053  * be removed.
       
  1054  *
       
  1055  * @since 2.1.0
       
  1056  *
       
  1057  * @param string $name Theme modification name.
       
  1058  * @return null
       
  1059  */
       
  1060 function remove_theme_mod( $name ) {
       
  1061 	$theme = get_current_theme();
       
  1062 
       
  1063 	$mods = get_option("mods_$theme");
       
  1064 
       
  1065 	if ( !isset($mods[$name]) )
       
  1066 		return;
       
  1067 
       
  1068 	unset($mods[$name]);
       
  1069 
       
  1070 	if ( empty($mods) )
       
  1071 		return remove_theme_mods();
       
  1072 
       
  1073 	update_option("mods_$theme", $mods);
       
  1074 	wp_cache_delete("mods_$theme", 'options');
       
  1075 }
       
  1076 
       
  1077 /**
       
  1078  * Remove theme modifications option for current theme.
       
  1079  *
       
  1080  * @since 2.1.0
       
  1081  */
       
  1082 function remove_theme_mods() {
       
  1083 	$theme = get_current_theme();
       
  1084 
       
  1085 	delete_option("mods_$theme");
       
  1086 }
       
  1087 
       
  1088 /**
       
  1089  * Retrieve text color for custom header.
       
  1090  *
       
  1091  * @since 2.1.0
       
  1092  * @uses HEADER_TEXTCOLOR
       
  1093  *
       
  1094  * @return string
       
  1095  */
       
  1096 function get_header_textcolor() {
       
  1097 	return get_theme_mod('header_textcolor', HEADER_TEXTCOLOR);
       
  1098 }
       
  1099 
       
  1100 /**
       
  1101  * Display text color for custom header.
       
  1102  *
       
  1103  * @since 2.1.0
       
  1104  */
       
  1105 function header_textcolor() {
       
  1106 	echo get_header_textcolor();
       
  1107 }
       
  1108 
       
  1109 /**
       
  1110  * Retrieve header image for custom header.
       
  1111  *
       
  1112  * @since 2.1.0
       
  1113  * @uses HEADER_IMAGE
       
  1114  *
       
  1115  * @return string
       
  1116  */
       
  1117 function get_header_image() {
       
  1118 	return get_theme_mod('header_image', HEADER_IMAGE);
       
  1119 }
       
  1120 
       
  1121 /**
       
  1122  * Display header image path.
       
  1123  *
       
  1124  * @since 2.1.0
       
  1125  */
       
  1126 function header_image() {
       
  1127 	echo get_header_image();
       
  1128 }
       
  1129 
       
  1130 /**
       
  1131  * Add callbacks for image header display.
       
  1132  *
       
  1133  * The parameter $header_callback callback will be required to display the
       
  1134  * content for the 'wp_head' action. The parameter $admin_header_callback
       
  1135  * callback will be added to Custom_Image_Header class and that will be added
       
  1136  * to the 'admin_menu' action.
       
  1137  *
       
  1138  * @since 2.1.0
       
  1139  * @uses Custom_Image_Header Sets up for $admin_header_callback for administration panel display.
       
  1140  *
       
  1141  * @param callback $header_callback Call on 'wp_head' action.
       
  1142  * @param callback $admin_header_callback Call on administration panels.
       
  1143  */
       
  1144 function add_custom_image_header($header_callback, $admin_header_callback) {
       
  1145 	if ( ! empty($header_callback) )
       
  1146 		add_action('wp_head', $header_callback);
       
  1147 
       
  1148 	if ( ! is_admin() )
       
  1149 		return;
       
  1150 	require_once(ABSPATH . 'wp-admin/custom-header.php');
       
  1151 	$GLOBALS['custom_image_header'] =& new Custom_Image_Header($admin_header_callback);
       
  1152 	add_action('admin_menu', array(&$GLOBALS['custom_image_header'], 'init'));
       
  1153 }
       
  1154 
       
  1155 ?>