PageRenderTime 359ms CodeModel.GetById 91ms app.highlight 177ms RepoModel.GetById 74ms app.codeStats 1ms

/wp-includes/theme.php

https://bitbucket.org/Wallynm/iptb
PHP | 2010 lines | 969 code | 268 blank | 773 comment | 229 complexity | c1d5899e047e7806bd7028180aed0a98 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1<?php
   2/**
   3 * Theme, template, and stylesheet functions.
   4 *
   5 * @package WordPress
   6 * @subpackage Template
   7 */
   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 **/
  16function 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 */
  34function 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 */
  46function 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 */
  61function 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 */
  80function 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 */
 105function 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 */
 127function 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 */
 139function 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 */
 155function 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 */
 183function 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 */
 264function 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		// The Twenty Eleven, Twenty Ten, Default and Classic themes always trump
 400		// their pretenders.
 401		if ( isset($wp_themes[$name]) ) {
 402			$trump_cards = array(
 403				'classic'      => 'WordPress Classic',
 404				'default'      => 'WordPress Default',
 405				'twentyten'    => 'Twenty Ten',
 406				'twentyeleven' => 'Twenty Eleven',
 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 */
 474function get_theme_roots() {
 475	global $wp_theme_directories;
 476
 477	if ( count($wp_theme_directories) <= 1 )
 478		return '/themes';
 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 */
 496function 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 */
 516function 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 */
 550function register_theme_directory( $directory) {
 551	global $wp_theme_directories;
 552
 553	/* If this folder does not exist, return and do not register */
 554	if ( !file_exists( $directory ) )
 555			/* Try prepending as the theme directory could be relative to the content directory */
 556		$registered_directory = WP_CONTENT_DIR . '/' . $directory;
 557	else
 558		$registered_directory = $directory;
 559
 560	/* If this folder does not exist, return and do not register */
 561	if ( !file_exists( $registered_directory ) )
 562		return false;
 563
 564	$wp_theme_directories[] = $registered_directory;
 565
 566	return true;
 567}
 568
 569/**
 570 * Search all registered theme directories for complete and valid themes.
 571 *
 572 * @since 2.9.0
 573 *
 574 * @return array Valid themes found
 575 */
 576function search_theme_directories() {
 577	global $wp_theme_directories, $wp_broken_themes;
 578	if ( empty( $wp_theme_directories ) )
 579		return false;
 580
 581	$theme_files = array();
 582	$wp_broken_themes = array();
 583
 584	/* Loop the registered theme directories and extract all themes */
 585	foreach ( (array) $wp_theme_directories as $theme_root ) {
 586		$theme_loc = $theme_root;
 587
 588		/* We don't want to replace all forward slashes, see Trac #4541 */
 589		if ( '/' != WP_CONTENT_DIR )
 590			$theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
 591
 592		/* Files in the root of the current theme directory and one subdir down */
 593		$themes_dir = @ opendir($theme_root);
 594
 595		if ( !$themes_dir )
 596			return false;
 597
 598		while ( ($theme_dir = readdir($themes_dir)) !== false ) {
 599			if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
 600				if ( $theme_dir[0] == '.' || $theme_dir == 'CVS' )
 601					continue;
 602
 603				$stylish_dir = @opendir($theme_root . '/' . $theme_dir);
 604				$found_stylesheet = false;
 605
 606				while ( ($theme_file = readdir($stylish_dir)) !== false ) {
 607					if ( $theme_file == 'style.css' ) {
 608						$theme_files[$theme_dir] = array( 'theme_file' => $theme_dir . '/' . $theme_file, 'theme_root' => $theme_root );
 609						$found_stylesheet = true;
 610						break;
 611					}
 612				}
 613				@closedir($stylish_dir);
 614
 615				if ( !$found_stylesheet ) { // look for themes in that dir
 616					$subdir = "$theme_root/$theme_dir";
 617					$subdir_name = $theme_dir;
 618					$theme_subdirs = @opendir( $subdir );
 619
 620					$found_subdir_themes = false;
 621					while ( ($theme_subdir = readdir($theme_subdirs)) !== false ) {
 622						if ( is_dir( $subdir . '/' . $theme_subdir) && is_readable($subdir . '/' . $theme_subdir) ) {
 623							if ( $theme_subdir[0] == '.' || $theme_subdir == 'CVS' )
 624								continue;
 625
 626							$stylish_dir = @opendir($subdir . '/' . $theme_subdir);
 627							$found_stylesheet = false;
 628
 629							while ( ($theme_file = readdir($stylish_dir)) !== false ) {
 630								if ( $theme_file == 'style.css' ) {
 631									$theme_files["$theme_dir/$theme_subdir"] = array( 'theme_file' => $subdir_name . '/' . $theme_subdir . '/' . $theme_file, 'theme_root' => $theme_root );
 632									$found_stylesheet = true;
 633									$found_subdir_themes = true;
 634									break;
 635								}
 636							}
 637							@closedir($stylish_dir);
 638						}
 639					}
 640					@closedir($theme_subdirs);
 641					if ( !$found_subdir_themes )
 642						$wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
 643				}
 644			}
 645		}
 646		@closedir( $themes_dir );
 647	}
 648	return $theme_files;
 649}
 650
 651/**
 652 * Retrieve path to themes directory.
 653 *
 654 * Does not have trailing slash.
 655 *
 656 * @since 1.5.0
 657 * @uses apply_filters() Calls 'theme_root' filter on path.
 658 *
 659 * @param string $stylesheet_or_template The stylesheet or template name of the theme
 660 * @return string Theme path.
 661 */
 662function get_theme_root( $stylesheet_or_template = false ) {
 663	if ( $stylesheet_or_template ) {
 664		if ( $theme_root = get_raw_theme_root($stylesheet_or_template) )
 665			$theme_root = WP_CONTENT_DIR . $theme_root;
 666		else
 667			$theme_root = WP_CONTENT_DIR . '/themes';
 668	} else {
 669		$theme_root = WP_CONTENT_DIR . '/themes';
 670	}
 671
 672	return apply_filters( 'theme_root', $theme_root );
 673}
 674
 675/**
 676 * Retrieve URI for themes directory.
 677 *
 678 * Does not have trailing slash.
 679 *
 680 * @since 1.5.0
 681 *
 682 * @param string $stylesheet_or_template The stylesheet or template name of the theme
 683 * @return string Themes URI.
 684 */
 685function get_theme_root_uri( $stylesheet_or_template = false ) {
 686	if ( $stylesheet_or_template ) {
 687		if ( $theme_root = get_raw_theme_root($stylesheet_or_template) )
 688			$theme_root_uri = content_url( $theme_root );
 689		else
 690			$theme_root_uri = content_url( 'themes' );
 691	} else {
 692		$theme_root_uri = content_url( 'themes' );
 693	}
 694
 695	return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
 696}
 697
 698/**
 699 * Get the raw theme root relative to the content directory with no filters applied.
 700 *
 701 * @since 3.1.0
 702 *
 703 * @param string $stylesheet_or_template The stylesheet or template name of the theme
 704 * @return string Theme root
 705 */
 706function get_raw_theme_root( $stylesheet_or_template, $no_cache = false ) {
 707	global $wp_theme_directories;
 708
 709	if ( count($wp_theme_directories) <= 1 )
 710		return '/themes';
 711
 712	$theme_root = false;
 713
 714	// If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
 715	if ( !$no_cache ) {
 716		if ( get_option('stylesheet') == $stylesheet_or_template )
 717			$theme_root = get_option('stylesheet_root');
 718		elseif ( get_option('template') == $stylesheet_or_template )
 719			$theme_root = get_option('template_root');
 720	}
 721
 722	if ( empty($theme_root) ) {
 723		$theme_roots = get_theme_roots();
 724		if ( !empty($theme_roots[$stylesheet_or_template]) )
 725			$theme_root = $theme_roots[$stylesheet_or_template];
 726	}
 727
 728	return $theme_root;
 729}
 730
 731/**
 732 * Retrieve path to a template
 733 *
 734 * Used to quickly retrieve the path of a template without including the file
 735 * extension. It will also check the parent theme, if the file exists, with
 736 * the use of {@link locate_template()}. Allows for more generic template location
 737 * without the use of the other get_*_template() functions.
 738 *
 739 * @since 1.5.0
 740 *
 741 * @param string $type Filename without extension.
 742 * @param array $templates An optional list of template candidates
 743 * @return string Full path to file.
 744 */
 745function get_query_template( $type, $templates = array() ) {
 746	$type = preg_replace( '|[^a-z0-9-]+|', '', $type );
 747
 748	if ( empty( $templates ) )
 749		$templates = array("{$type}.php");
 750
 751	return apply_filters( "{$type}_template", locate_template( $templates ) );
 752}
 753
 754/**
 755 * Retrieve path of index template in current or parent template.
 756 *
 757 * @since 3.0.0
 758 *
 759 * @return string
 760 */
 761function get_index_template() {
 762	return get_query_template('index');
 763}
 764
 765/**
 766 * Retrieve path of 404 template in current or parent template.
 767 *
 768 * @since 1.5.0
 769 *
 770 * @return string
 771 */
 772function get_404_template() {
 773	return get_query_template('404');
 774}
 775
 776/**
 777 * Retrieve path of archive template in current or parent template.
 778 *
 779 * @since 1.5.0
 780 *
 781 * @return string
 782 */
 783function get_archive_template() {
 784	$post_type = get_query_var( 'post_type' );
 785
 786	$templates = array();
 787
 788	if ( $post_type )
 789		$templates[] = "archive-{$post_type}.php";
 790	$templates[] = 'archive.php';
 791
 792	return get_query_template( 'archive', $templates );
 793}
 794
 795/**
 796 * Retrieve path of author template in current or parent template.
 797 *
 798 * @since 1.5.0
 799 *
 800 * @return string
 801 */
 802function get_author_template() {
 803	$author = get_queried_object();
 804
 805	$templates = array();
 806
 807	$templates[] = "author-{$author->user_nicename}.php";
 808	$templates[] = "author-{$author->ID}.php";
 809	$templates[] = 'author.php';
 810
 811	return get_query_template( 'author', $templates );
 812}
 813
 814/**
 815 * Retrieve path of category template in current or parent template.
 816 *
 817 * Works by first retrieving the current slug for example 'category-default.php' and then
 818 * trying category ID, for example 'category-1.php' and will finally fallback to category.php
 819 * template, if those files don't exist.
 820 *
 821 * @since 1.5.0
 822 * @uses apply_filters() Calls 'category_template' on file path of category template.
 823 *
 824 * @return string
 825 */
 826function get_category_template() {
 827	$category = get_queried_object();
 828
 829	$templates = array();
 830
 831	$templates[] = "category-{$category->slug}.php";
 832	$templates[] = "category-{$category->term_id}.php";
 833	$templates[] = 'category.php';
 834
 835	return get_query_template( 'category', $templates );
 836}
 837
 838/**
 839 * Retrieve path of tag template in current or parent template.
 840 *
 841 * Works by first retrieving the current tag name, for example 'tag-wordpress.php' and then
 842 * trying tag ID, for example 'tag-1.php' and will finally fallback to tag.php
 843 * template, if those files don't exist.
 844 *
 845 * @since 2.3.0
 846 * @uses apply_filters() Calls 'tag_template' on file path of tag template.
 847 *
 848 * @return string
 849 */
 850function get_tag_template() {
 851	$tag = get_queried_object();
 852
 853	$templates = array();
 854
 855	$templates[] = "tag-{$tag->slug}.php";
 856	$templates[] = "tag-{$tag->term_id}.php";
 857	$templates[] = 'tag.php';
 858
 859	return get_query_template( 'tag', $templates );
 860}
 861
 862/**
 863 * Retrieve path of taxonomy template in current or parent template.
 864 *
 865 * Retrieves the taxonomy and term, if term is available. The template is
 866 * prepended with 'taxonomy-' and followed by both the taxonomy string and
 867 * the taxonomy string followed by a dash and then followed by the term.
 868 *
 869 * The taxonomy and term template is checked and used first, if it exists.
 870 * Second, just the taxonomy template is checked, and then finally, taxonomy.php
 871 * template is used. If none of the files exist, then it will fall back on to
 872 * index.php.
 873 *
 874 * @since 2.5.0
 875 * @uses apply_filters() Calls 'taxonomy_template' filter on found path.
 876 *
 877 * @return string
 878 */
 879function get_taxonomy_template() {
 880	$term = get_queried_object();
 881	$taxonomy = $term->taxonomy;
 882
 883	$templates = array();
 884
 885	$templates[] = "taxonomy-$taxonomy-{$term->slug}.php";
 886	$templates[] = "taxonomy-$taxonomy.php";
 887	$templates[] = 'taxonomy.php';
 888
 889	return get_query_template( 'taxonomy', $templates );
 890}
 891
 892/**
 893 * Retrieve path of date template in current or parent template.
 894 *
 895 * @since 1.5.0
 896 *
 897 * @return string
 898 */
 899function get_date_template() {
 900	return get_query_template('date');
 901}
 902
 903/**
 904 * Retrieve path of home template in current or parent template.
 905 *
 906 * This is the template used for the page containing the blog posts
 907 *
 908 * Attempts to locate 'home.php' first before falling back to 'index.php'.
 909 *
 910 * @since 1.5.0
 911 * @uses apply_filters() Calls 'home_template' on file path of home template.
 912 *
 913 * @return string
 914 */
 915function get_home_template() {
 916	$templates = array( 'home.php', 'index.php' );
 917
 918	return get_query_template( 'home', $templates );
 919}
 920
 921/**
 922 * Retrieve path of front-page template in current or parent template.
 923 *
 924 * Looks for 'front-page.php'.
 925 *
 926 * @since 3.0.0
 927 * @uses apply_filters() Calls 'front_page_template' on file path of template.
 928 *
 929 * @return string
 930 */
 931function get_front_page_template() {
 932	$templates = array('front-page.php');
 933
 934	return get_query_template( 'front_page', $templates );
 935}
 936
 937/**
 938 * Retrieve path of page template in current or parent template.
 939 *
 940 * Will first look for the specifically assigned page template
 941 * The will search for 'page-{slug}.php' followed by 'page-id.php'
 942 * and finally 'page.php'
 943 *
 944 * @since 1.5.0
 945 *
 946 * @return string
 947 */
 948function get_page_template() {
 949	$id = get_queried_object_id();
 950	$template = get_post_meta($id, '_wp_page_template', true);
 951	$pagename = get_query_var('pagename');
 952
 953	if ( !$pagename && $id > 0 ) {
 954		// If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
 955		$post = get_queried_object();
 956		$pagename = $post->post_name;
 957	}
 958
 959	if ( 'default' == $template )
 960		$template = '';
 961
 962	$templates = array();
 963	if ( !empty($template) && !validate_file($template) )
 964		$templates[] = $template;
 965	if ( $pagename )
 966		$templates[] = "page-$pagename.php";
 967	if ( $id )
 968		$templates[] = "page-$id.php";
 969	$templates[] = 'page.php';
 970
 971	return get_query_template( 'page', $templates );
 972}
 973
 974/**
 975 * Retrieve path of paged template in current or parent template.
 976 *
 977 * @since 1.5.0
 978 *
 979 * @return string
 980 */
 981function get_paged_template() {
 982	return get_query_template('paged');
 983}
 984
 985/**
 986 * Retrieve path of search template in current or parent template.
 987 *
 988 * @since 1.5.0
 989 *
 990 * @return string
 991 */
 992function get_search_template() {
 993	return get_query_template('search');
 994}
 995
 996/**
 997 * Retrieve path of single template in current or parent template.
 998 *
 999 * @since 1.5.0
1000 *
1001 * @return string
1002 */
1003function get_single_template() {
1004	$object = get_queried_object();
1005
1006	$templates = array();
1007
1008	$templates[] = "single-{$object->post_type}.php";
1009	$templates[] = "single.php";
1010
1011	return get_query_template( 'single', $templates );
1012}
1013
1014/**
1015 * Retrieve path of attachment template in current or parent template.
1016 *
1017 * The attachment path first checks if the first part of the mime type exists.
1018 * The second check is for the second part of the mime type. The last check is
1019 * for both types separated by an underscore. If neither are found then the file
1020 * 'attachment.php' is checked and returned.
1021 *
1022 * Some examples for the 'text/plain' mime type are 'text.php', 'plain.php', and
1023 * finally 'text_plain.php'.
1024 *
1025 * @since 2.0.0
1026 *
1027 * @return string
1028 */
1029function get_attachment_template() {
1030	global $posts;
1031	$type = explode('/', $posts[0]->post_mime_type);
1032	if ( $template = get_query_template($type[0]) )
1033		return $template;
1034	elseif ( $template = get_query_template($type[1]) )
1035		return $template;
1036	elseif ( $template = get_query_template("$type[0]_$type[1]") )
1037		return $template;
1038	else
1039		return get_query_template('attachment');
1040}
1041
1042/**
1043 * Retrieve path of comment popup template in current or parent template.
1044 *
1045 * Checks for comment popup template in current template, if it exists or in the
1046 * parent template.
1047 *
1048 * @since 1.5.0
1049 * @uses apply_filters() Calls 'comments_popup_template' filter on path.
1050 *
1051 * @return string
1052 */
1053function get_comments_popup_template() {
1054	$template = get_query_template( 'comments_popup', array( 'comments-popup.php' ) );
1055
1056	// Backward compat code will be removed in a future release
1057	if ('' == $template)
1058		$template = ABSPATH . WPINC . '/theme-compat/comments-popup.php';
1059
1060	return $template;
1061}
1062
1063/**
1064 * Retrieve the name of the highest priority template file that exists.
1065 *
1066 * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
1067 * inherit from a parent theme can just overload one file.
1068 *
1069 * @since 2.7.0
1070 *
1071 * @param string|array $template_names Template file(s) to search for, in order.
1072 * @param bool $load If true the template file will be loaded if it is found.
1073 * @param bool $require_once Whether to require_once or require. Default true. Has no effect if $load is false.
1074 * @return string The template filename if one is located.
1075 */
1076function locate_template($template_names, $load = false, $require_once = true ) {
1077	$located = '';
1078	foreach ( (array) $template_names as $template_name ) {
1079		if ( !$template_name )
1080			continue;
1081		if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
1082			$located = STYLESHEETPATH . '/' . $template_name;
1083			break;
1084		} else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
1085			$located = TEMPLATEPATH . '/' . $template_name;
1086			break;
1087		}
1088	}
1089
1090	if ( $load && '' != $located )
1091		load_template( $located, $require_once );
1092
1093	return $located;
1094}
1095
1096/**
1097 * Require the template file with WordPress environment.
1098 *
1099 * The globals are set up for the template file to ensure that the WordPress
1100 * environment is available from within the function. The query variables are
1101 * also available.
1102 *
1103 * @since 1.5.0
1104 *
1105 * @param string $_template_file Path to template file.
1106 * @param bool $require_once Whether to require_once or require. Default true.
1107 */
1108function load_template( $_template_file, $require_once = true ) {
1109	global $posts, $post, $wp_did_header, $wp_did_template_redirect, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
1110
1111	if ( is_array( $wp_query->query_vars ) )
1112		extract( $wp_query->query_vars, EXTR_SKIP );
1113
1114	if ( $require_once )
1115		require_once( $_template_file );
1116	else
1117		require( $_template_file );
1118}
1119
1120/**
1121 * Display localized stylesheet link element.
1122 *
1123 * @since 2.1.0
1124 */
1125function locale_stylesheet() {
1126	$stylesheet = get_locale_stylesheet_uri();
1127	if ( empty($stylesheet) )
1128		return;
1129	echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
1130}
1131
1132/**
1133 * Start preview theme output buffer.
1134 *
1135 * Will only preform task if the user has permissions and template and preview
1136 * query variables exist.
1137 *
1138 * @since 2.6.0
1139 */
1140function preview_theme() {
1141	if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
1142		return;
1143
1144	if ( !current_user_can( 'switch_themes' ) )
1145		return;
1146
1147	// Admin Thickbox requests
1148	if ( isset( $_GET['preview_iframe'] ) )
1149		show_admin_bar( false );
1150
1151	$_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
1152
1153	if ( validate_file($_GET['template']) )
1154		return;
1155
1156	add_filter( 'template', '_preview_theme_template_filter' );
1157
1158	if ( isset($_GET['stylesheet']) ) {
1159		$_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
1160		if ( validate_file($_GET['stylesheet']) )
1161			return;
1162		add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
1163	}
1164
1165	// Prevent theme mods to current theme being used on theme being previewed
1166	add_filter( 'pre_option_mods_' . get_current_theme(), '__return_empty_array' );
1167
1168	ob_start( 'preview_theme_ob_filter' );
1169}
1170add_action('setup_theme', 'preview_theme');
1171
1172/**
1173 * Private function to modify the current template when previewing a theme
1174 *
1175 * @since 2.9.0
1176 * @access private
1177 *
1178 * @return string
1179 */
1180function _preview_theme_template_filter() {
1181	return isset($_GET['template']) ? $_GET['template'] : '';
1182}
1183
1184/**
1185 * Private function to modify the current stylesheet when previewing a theme
1186 *
1187 * @since 2.9.0
1188 * @access private
1189 *
1190 * @return string
1191 */
1192function _preview_theme_stylesheet_filter() {
1193	return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
1194}
1195
1196/**
1197 * Callback function for ob_start() to capture all links in the theme.
1198 *
1199 * @since 2.6.0
1200 * @access private
1201 *
1202 * @param string $content
1203 * @return string
1204 */
1205function preview_theme_ob_filter( $content ) {
1206	return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
1207}
1208
1209/**
1210 * Manipulates preview theme links in order to control and maintain location.
1211 *
1212 * Callback function for preg_replace_callback() to accept and filter matches.
1213 *
1214 * @since 2.6.0
1215 * @access private
1216 *
1217 * @param array $matches
1218 * @return string
1219 */
1220function preview_theme_ob_filter_callback( $matches ) {
1221	if ( strpos($matches[4], 'onclick') !== false )
1222		$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.
1223	if (
1224		( false !== strpos($matches[3], '/wp-admin/') )
1225	||
1226		( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
1227	||
1228		( false !== strpos($matches[3], '/feed/') )
1229	||
1230		( false !== strpos($matches[3], '/trackback/') )
1231	)
1232		return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
1233
1234	$link = add_query_arg( array('preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'] ), $matches[3] );
1235	if ( 0 === strpos($link, 'preview=1') )
1236		$link = "?$link";
1237	return $matches[1] . esc_attr( $link ) . $matches[4];
1238}
1239
1240/**
1241 * Switches current theme to new template and stylesheet names.
1242 *
1243 * @since 2.5.0
1244 * @uses do_action() Calls 'switch_theme' action on updated theme display name.
1245 *
1246 * @param string $template Template name
1247 * @param string $stylesheet Stylesheet name.
1248 */
1249function switch_theme($template, $stylesheet) {
1250	global $wp_theme_directories, $sidebars_widgets;
1251
1252	if ( is_array( $sidebars_widgets ) )
1253		set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $sidebars_widgets ) );
1254
1255	$old_theme = get_current_theme();
1256
1257	update_option('template', $template);
1258	update_option('stylesheet', $stylesheet);
1259
1260	if ( count($wp_theme_directories) > 1 ) {
1261		update_option('template_root', get_raw_theme_root($template, true));
1262		update_option('stylesheet_root', get_raw_theme_root($stylesheet, true));
1263	}
1264
1265	delete_option('current_theme');
1266	$theme = get_current_theme();
1267
1268	if ( is_admin() && false === get_option( "theme_mods_$stylesheet" ) ) {
1269		$default_theme_mods = (array) get_option( "mods_$theme" );
1270		add_option( "theme_mods_$stylesheet", $default_theme_mods );
1271	}
1272
1273	update_option( 'theme_switched', $old_theme );
1274	do_action( 'switch_theme', $theme );
1275}
1276
1277/**
1278 * Checks that current theme files 'index.php' and 'style.css' exists.
1279 *
1280 * Does not check the default theme, which is the fallback and should always exist.
1281 * Will switch theme to the fallback theme if current theme does not validate.
1282 * You can use the 'validate_current_theme' filter to return FALSE to
1283 * disable this functionality.
1284 *
1285 * @since 1.5.0
1286 * @see WP_DEFAULT_THEME
1287 *
1288 * @return bool
1289 */
1290function validate_current_theme() {
1291	// Don't validate during an install/upgrade.
1292	if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
1293		return true;
1294
1295	if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
1296		switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
1297		return false;
1298	}
1299
1300	if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
1301		switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
1302		return false;
1303	}
1304
1305	if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
1306		switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
1307		return false;
1308	}
1309
1310	return true;
1311}
1312
1313/**
1314 * Retrieve all theme modifications.
1315 *
1316 * @since 3.1.0
1317 *
1318 * @return array Theme modifications.
1319 */
1320function get_theme_mods() {
1321	$theme_slug = get_option( 'stylesheet' );
1322	if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
1323		$theme_name = get_current_theme();
1324		$mods = get_option( "mods_$theme_name" ); // Deprecated location.
1325		if ( is_admin() && false !== $mods ) {
1326			update_option( "theme_mods_$theme_slug", $mods );
1327			delete_option( "mods_$theme_name" );
1328		}
1329	}
1330	return $mods;
1331}
1332
1333/**
1334 * Retrieve theme modification value for the current theme.
1335 *
1336 * If the modification name does not exist, then the $default will be passed
1337 * through {@link http://php.net/sprintf sprintf()} PHP function with the first
1338 * string the template directory URI and the second string the stylesheet
1339 * directory URI.
1340 *
1341 * @since 2.1.0
1342 * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
1343 *
1344 * @param string $name Theme modification name.
1345 * @param bool|string $default
1346 * @return string
1347 */
1348function get_theme_mod( $name, $default = false ) {
1349	$mods = get_theme_mods();
1350
1351	if ( isset( $mods[ $name ] ) )
1352		return apply_filters( "theme_mod_$name", $mods[ $name ] );
1353
1354	return apply_filters( "theme_mod_$name", sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() ) );
1355}
1356
1357/**
1358 * Update theme modification value for the current theme.
1359 *
1360 * @since 2.1.0
1361 *
1362 * @param string $name Theme modification name.
1363 * @param string $value theme modification value.
1364 */
1365function set_theme_mod( $name, $value ) {
1366	$mods = get_theme_mods();
1367
1368	$mods[ $name ] = $value;
1369
1370	$theme = get_option( 'stylesheet' );
1371	update_option( "theme_mods_$theme", $mods );
1372}
1373
1374/**
1375 * Remove theme modification name from current theme list.
1376 *
1377 * If removing the name also removes all elements, then the entire option will
1378 * be removed.
1379 *
1380 * @since 2.1.0
1381 *
1382 * @param string $name Theme modification name.
1383 * @return null
1384 */
1385function remove_theme_mod( $name ) {
1386	$mods = get_theme_mods();
1387
1388	if ( ! isset( $mods[ $name ] ) )
1389		return;
1390
1391	unset( $mods[ $name ] );
1392
1393	if ( empty( $mods ) )
1394		return remove_theme_mods();
1395
1396	$theme = get_option( 'stylesheet' );
1397	update_option( "theme_mods_$theme", $mods );
1398}
1399
1400/**
1401 * Remove theme modifications option for current theme.
1402 *
1403 * @since 2.1.0
1404 */
1405function remove_theme_mods() {
1406	delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
1407	delete_option( 'mods_' . get_current_theme() );
1408}
1409
1410/**
1411 * Retrieve text color for custom header.
1412 *
1413 * @since 2.1.0
1414 * @uses HEADER_TEXTCOLOR
1415 *
1416 * @return string
1417 */
1418function get_header_textcolor() {
1419	$default = defined('HEADER_TEXTCOLOR') ? HEADER_TEXTCOLOR : '';
1420
1421	return get_theme_mod('header_textcolor', $default);
1422}
1423
1424/**
1425 * Display text color for custom header.
1426 *
1427 * @since 2.1.0
1428 */
1429function header_textcolor() {
1430	echo get_header_textcolor();
1431}
1432
1433/**
1434 * Retrieve header image for custom header.
1435 *
1436 * @since 2.1.0
1437 * @uses HEADER_IMAGE
1438 *
1439 * @return string
1440 */
1441function get_header_image() {
1442	$default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
1443	$url = get_theme_mod( 'header_image', $default );
1444
1445	if ( 'remove-header' == $url )
1446		return false;
1447
1448	if ( is_random_header_image() )
1449		$url = get_random_header_image();
1450
1451	if ( is_ssl() )
1452		$url = str_replace( 'http://', 'https://', $url );
1453	else
1454		$url = str_replace( 'https://', 'http://', $url );
1455
1456	return esc_url_raw( $url );
1457}
1458
1459/**
1460 * Get random header image from registered images in theme.
1461 *
1462 * @since 3.2.0
1463 *
1464 * @return string Path to header image
1465 */
1466function get_random_header_image() {
1467	global $_wp_default_headers;
1468
1469	$header_image_mod = get_theme_mod( 'header_image', '' );
1470	$headers = array();
1471
1472	if ( 'random-uploaded-image' == $header_image_mod )
1473		$headers = get_uploaded_header_images();
1474	elseif ( ! empty( $_wp_default_headers ) ) {
1475		if ( 'random-default-image' == $header_image_mod ) {
1476			$headers = $_wp_default_headers;
1477		} else {
1478			$is_random = get_theme_support( 'custom-header' );
1479			if ( isset( $is_random[ 0 ] ) && !empty( $is_random[ 0 ][ 'random-default' ] ) )
1480				$headers = $_wp_default_headers;
1481		}
1482	}
1483
1484	if ( empty( $headers ) )
1485		return '';
1486
1487	$random_image = array_rand( $headers );
1488	$header_url = sprintf( $headers[$random_image]['url'], get_template_directory_uri(), get_stylesheet_directory_uri() );
1489
1490	return $header_url;
1491}
1492
1493/**
1494 * Check if random header image is in use.
1495 *
1496 * Always true if user expressly chooses the option in Appearance > Header.
1497 * Also true if theme has multiple header images registered, no specific header image
1498 * is chosen, and theme turns on random headers with add_theme_support().
1499 *
1500 * @since 3.2.0
1501 * @uses HEADER_IMAGE
1502 *
1503 * @param string $type The random pool to use. any|default|uploaded
1504 * @return boolean
1505 */
1506function is_random_header_image( $type = 'any' ) {
1507	$default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
1508	$header_image_mod = get_theme_mod( 'header_image', $default );
1509
1510	if ( 'any' == $type ) {
1511		if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
1512			return true;
1513	} else {
1514		if ( "random-$type-image" == $header_image_mod )
1515			return true;
1516		elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
1517			return true;
1518	}
1519
1520	return false;
1521}
1522
1523/**
1524 * Display header image path.
1525 *
1526 * @since 2.1.0
1527 */
1528function header_image() {
1529	echo get_header_image();
1530}
1531
1532/**
1533 * Get the header images uploaded for the current theme.
1534 *
1535 * @since 3.2.0
1536 *
1537 * @return array
1538 */
1539function get_uploaded_header_images() {
1540	$header_images = array();
1541
1542	// @todo caching
1543	$headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
1544
1545	if ( empty( $headers ) )
1546		return array();
1547
1548	foreach ( (array) $headers as $header ) {
1549		$url = esc_url_raw( $header->guid );
1550		$header = basename($url);
1551		$header_images[$header] = array();
1552		$header_images[$header]['url'] =  $url;
1553		$header_images[$header]['thumbnail_url'] =  $url;
1554		$header_images[$header]['uploaded'] = true;
1555	}
1556
1557	return $header_images;
1558}
1559
1560/**
1561 * Add callbacks for image header display.
1562 *
1563 * The parameter $header_callback callback will be required to display the
1564 * content for the 'wp_head' action. The parameter $admin_header_callback
1565 * callback will be added to Custom_Image_Header class and that will be added
1566 * to the 'admin_menu' action.
1567 *
1568 * @since 2.1.0
1569 * @uses Custom_Image_Header Sets up for $admin_header_callback for administration panel display.
1570 *
1571 * @param callback $header_callback Call on 'wp_head' action.
1572 * @param callback $admin_header_callback Call on custom header administration screen.
1573 * @param callback $admin_image_div_callback Output a custom header image div on the custom header administration screen. Optional.
1574 */
1575function add_custom_image_header( $header_callback, $admin_header_callback, $admin_image_div_callback = '' ) {
1576	if ( ! empty( $header_callback ) )
1577		add_action('wp_head', $header_callback);
1578
1579	$support = array( 'callback' => $header_callback );
1580	$theme_support = get_theme_support( 'custom-header' );
1581	if ( ! empty( $theme_support ) && is_array( $theme_support[ 0 ] ) )
1582		$support = array_merge( $theme_support[ 0 ], $support );
1583	add_theme_support( 'custom-header',  $support );
1584	add_theme_support( 'custom-header-uploads' );
1585
1586	if ( ! is_admin() )
1587		return;
1588
1589	global $custom_image_header;
1590
1591	require_once( ABSPATH . 'wp-admin/custom-header.php' );
1592	$custom_image_header = new Custom_Image_Header( $admin_header_callback, $admin_image_div_callback );
1593	add_action( 'admin_menu', array( &$custom_image_header, 'init' ) );
1594}
1595
1596/**
1597 * Remove image header support.
1598 *
1599 * @since 3.1.0
1600 * @see add_custom_image_header()
1601 *
1602 * @return bool Whether support was removed.
1603 */
1604function remove_custom_image_header() {
1605	if ( ! current_theme_supports( 'custom-header' ) )
1606		return false;
1607
1608	$callback = get_theme_support( 'custom-header' );
1609	remove_action( 'wp_head', $callback[0]['callback'] );
1610	_remove_theme_support( 'custom-header' );
1611	remove_theme_support( 'custom-header-uploads' );
1612
1613	if ( is_admin() ) {
1614		remove_action( 'admin_menu', array( &$GLOBALS['custom_image_header'], 'init' ) );
1615		unset( $GLOBALS['custom_image_header'] );
1616	}
1617
1618	return true;
1619}
1620
1621/**
1622 * Register a selection of default headers to be displayed by the custom header admin UI.
1623 *
1624 * @since 3.0.0
1625 *
1626 * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
1627 */
1628function register_default_headers( $headers ) {
1629	global $_wp_default_headers;
1630
1631	$_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
1632}
1633
1634/**
1635 * Unregister default headers.
1636 *
1637 * This function must be called after register_default_headers() has already added the
1638 * header you want to remove.
1639 *
1640 * @see register_default_headers()
1641 * @since 3.0.0
1642 *
1643 * @param string|array $header The header string id (key of array) to remove, or an array thereof.
1644 * @return True on success, false on failure.
1645 */
1646function unregister_default_headers( $header ) {
1647	global $_wp_default_headers;
1648	if ( is_array( $header ) ) {
1649		array_map( 'unregister_default_headers', $header );
1650	} elseif ( isset( $_wp_default_headers[ $header ] ) ) {
1651		unset( $_wp_default_headers[ $header ] );
1652		return true;
1653	} else {
1654		return false;
1655	}
1656}
1657
1658/**
1659 * Retrieve background image for custom background.
1660 *
1661 * @since 3.0.0
1662 *
1663 * @return string
1664 */
1665function get_background_image() {
1666	$default = defined('BACKGROUND_IMAGE') ? BACKGROUND_IMAGE : '';
1667
1668	return get_theme_mod('background_image', $default);
1669}
1670
1671/**
1672 * Display background image path.
1673 *
1674 * @since 3.0.0
1675 */
1676function background_image() {
1677	echo get_background_image();
1678}
1679
1680/**
1681 * Retrieve value for custom background color.
1682 *
1683 * @since 3.0.0
1684 * @uses BACKGROUND_COLOR
1685 *
1686 * @return string
1687 */
1688function get_background_color() {
1689	$default = defined('BACKGROUND_COLOR') ? BACKGROUND_COLOR : '';
1690
1691	return get_theme_mod('background_color', $default);
1692}
1693
1694/**
1695 * Display background color value.
1696 *
1697 * @since 3.0.0
1698 */
1699function background_color() {
1700	echo get_background_color();
1701}
1702
1703/**
1704 * Add callbacks for background image display.
1705 *
1706 * The parameter $header_callback callback will be required to display the
1707 * content for the 'wp_head' action. The parameter $admin_header_callback
1708 * callback will be added to Custom_Background class and that will be added
1709 * to the 'admin_menu' action.
1710 *
1711 * @since 3.0.0
1712 * @uses Custom_Background Sets up for $admin_header_callback for administration panel display.
1713 *
1714 * @param callback $header_callback Call on 'wp_head' action.
1715 * @param callback $admin_header_callback Call on custom background administration screen.
1716 * @param callback $admin_image_div_callback Output a custom background image div on the custom background administration screen. Optional.
1717 */
1718function add_custom_background( $header_callback = '', $admin_header_cal…

Large files files are truncated, but you can click here to view the full file