PageRenderTime 62ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-includes/theme.php

https://bitbucket.org/crypticrod/sr_wp_code
PHP | 1985 lines | 959 code | 260 blank | 766 comment | 226 complexity | e8c2f717da863a2c2b2a7bc26f547f37 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.1, GPL-3.0, LGPL-2.0, AGPL-3.0

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. * Whether a child theme is in use.
  10. *
  11. * @since 3.0.0
  12. *
  13. * @return bool true if a child theme is in use, false otherwise.
  14. **/
  15. function is_child_theme() {
  16. return ( TEMPLATEPATH !== STYLESHEETPATH );
  17. }
  18. /**
  19. * Retrieve name of the current stylesheet.
  20. *
  21. * The theme name that the administrator has currently set the front end theme
  22. * as.
  23. *
  24. * For all extensive purposes, the template name and the stylesheet name are
  25. * going to be the same for most cases.
  26. *
  27. * @since 1.5.0
  28. * @uses apply_filters() Calls 'stylesheet' filter on stylesheet name.
  29. *
  30. * @return string Stylesheet name.
  31. */
  32. function get_stylesheet() {
  33. return apply_filters('stylesheet', get_option('stylesheet'));
  34. }
  35. /**
  36. * Retrieve stylesheet directory path for current theme.
  37. *
  38. * @since 1.5.0
  39. * @uses apply_filters() Calls 'stylesheet_directory' filter on stylesheet directory and theme name.
  40. *
  41. * @return string Path to current theme directory.
  42. */
  43. function get_stylesheet_directory() {
  44. $stylesheet = get_stylesheet();
  45. $theme_root = get_theme_root( $stylesheet );
  46. $stylesheet_dir = "$theme_root/$stylesheet";
  47. return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
  48. }
  49. /**
  50. * Retrieve stylesheet directory URI.
  51. *
  52. * @since 1.5.0
  53. *
  54. * @return string
  55. */
  56. function get_stylesheet_directory_uri() {
  57. $stylesheet = get_stylesheet();
  58. $theme_root_uri = get_theme_root_uri( $stylesheet );
  59. $stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
  60. return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
  61. }
  62. /**
  63. * Retrieve URI of current theme stylesheet.
  64. *
  65. * The stylesheet file name is 'style.css' which is appended to {@link
  66. * get_stylesheet_directory_uri() stylesheet directory URI} path.
  67. *
  68. * @since 1.5.0
  69. * @uses apply_filters() Calls 'stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
  70. *
  71. * @return string
  72. */
  73. function get_stylesheet_uri() {
  74. $stylesheet_dir_uri = get_stylesheet_directory_uri();
  75. $stylesheet_uri = $stylesheet_dir_uri . '/style.css';
  76. return apply_filters('stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
  77. }
  78. /**
  79. * Retrieve localized stylesheet URI.
  80. *
  81. * The stylesheet directory for the localized stylesheet files are located, by
  82. * default, in the base theme directory. The name of the locale file will be the
  83. * locale followed by '.css'. If that does not exist, then the text direction
  84. * stylesheet will be checked for existence, for example 'ltr.css'.
  85. *
  86. * The theme may change the location of the stylesheet directory by either using
  87. * the 'stylesheet_directory_uri' filter or the 'locale_stylesheet_uri' filter.
  88. * If you want to change the location of the stylesheet files for the entire
  89. * WordPress workflow, then change the former. If you just have the locale in a
  90. * separate folder, then change the latter.
  91. *
  92. * @since 2.1.0
  93. * @uses apply_filters() Calls 'locale_stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
  94. *
  95. * @return string
  96. */
  97. function get_locale_stylesheet_uri() {
  98. global $wp_locale;
  99. $stylesheet_dir_uri = get_stylesheet_directory_uri();
  100. $dir = get_stylesheet_directory();
  101. $locale = get_locale();
  102. if ( file_exists("$dir/$locale.css") )
  103. $stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
  104. elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
  105. $stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
  106. else
  107. $stylesheet_uri = '';
  108. return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
  109. }
  110. /**
  111. * Retrieve name of the current theme.
  112. *
  113. * @since 1.5.0
  114. * @uses apply_filters() Calls 'template' filter on template option.
  115. *
  116. * @return string Template name.
  117. */
  118. function get_template() {
  119. return apply_filters('template', get_option('template'));
  120. }
  121. /**
  122. * Retrieve current theme directory.
  123. *
  124. * @since 1.5.0
  125. * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
  126. *
  127. * @return string Template directory path.
  128. */
  129. function get_template_directory() {
  130. $template = get_template();
  131. $theme_root = get_theme_root( $template );
  132. $template_dir = "$theme_root/$template";
  133. return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
  134. }
  135. /**
  136. * Retrieve theme directory URI.
  137. *
  138. * @since 1.5.0
  139. * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
  140. *
  141. * @return string Template directory URI.
  142. */
  143. function get_template_directory_uri() {
  144. $template = get_template();
  145. $theme_root_uri = get_theme_root_uri( $template );
  146. $template_dir_uri = "$theme_root_uri/$template";
  147. return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
  148. }
  149. /**
  150. * Retrieve theme data from parsed theme file.
  151. *
  152. * The description will have the tags filtered with the following HTML elements
  153. * whitelisted. The <b>'a'</b> element with the <em>href</em> and <em>title</em>
  154. * attributes. The <b>abbr</b> element with the <em>title</em> attribute. The
  155. * <b>acronym</b> element with the <em>title</em> attribute allowed. The
  156. * <b>code</b>, <b>em</b>, and <b>strong</b> elements also allowed.
  157. *
  158. * The style.css file must contain theme name, theme URI, and description. The
  159. * data can also contain author URI, author, template (parent template),
  160. * version, status, and finally tags. Some of these are not used by WordPress
  161. * administration panels, but are used by theme directory web sites which list
  162. * the theme.
  163. *
  164. * @since 1.5.0
  165. *
  166. * @param string $theme_file Theme file path.
  167. * @return array Theme data.
  168. */
  169. function get_theme_data( $theme_file ) {
  170. $default_headers = array(
  171. 'Name' => 'Theme Name',
  172. 'URI' => 'Theme URI',
  173. 'Description' => 'Description',
  174. 'Author' => 'Author',
  175. 'AuthorURI' => 'Author URI',
  176. 'Version' => 'Version',
  177. 'Template' => 'Template',
  178. 'Status' => 'Status',
  179. 'Tags' => 'Tags'
  180. );
  181. $themes_allowed_tags = array(
  182. 'a' => array(
  183. 'href' => array(),'title' => array()
  184. ),
  185. 'abbr' => array(
  186. 'title' => array()
  187. ),
  188. 'acronym' => array(
  189. 'title' => array()
  190. ),
  191. 'code' => array(),
  192. 'em' => array(),
  193. 'strong' => array()
  194. );
  195. $theme_data = get_file_data( $theme_file, $default_headers, 'theme' );
  196. $theme_data['Name'] = $theme_data['Title'] = wp_kses( $theme_data['Name'], $themes_allowed_tags );
  197. $theme_data['URI'] = esc_url( $theme_data['URI'] );
  198. $theme_data['Description'] = wptexturize( wp_kses( $theme_data['Description'], $themes_allowed_tags ) );
  199. $theme_data['AuthorURI'] = esc_url( $theme_data['AuthorURI'] );
  200. $theme_data['Template'] = wp_kses( $theme_data['Template'], $themes_allowed_tags );
  201. $theme_data['Version'] = wp_kses( $theme_data['Version'], $themes_allowed_tags );
  202. if ( $theme_data['Status'] == '' )
  203. $theme_data['Status'] = 'publish';
  204. else
  205. $theme_data['Status'] = wp_kses( $theme_data['Status'], $themes_allowed_tags );
  206. if ( $theme_data['Tags'] == '' )
  207. $theme_data['Tags'] = array();
  208. else
  209. $theme_data['Tags'] = array_map( 'trim', explode( ',', wp_kses( $theme_data['Tags'], array() ) ) );
  210. if ( $theme_data['Author'] == '' ) {
  211. $theme_data['Author'] = $theme_data['AuthorName'] = __('Anonymous');
  212. } else {
  213. $theme_data['AuthorName'] = wp_kses( $theme_data['Author'], $themes_allowed_tags );
  214. if ( empty( $theme_data['AuthorURI'] ) ) {
  215. $theme_data['Author'] = $theme_data['AuthorName'];
  216. } else {
  217. $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'] );
  218. }
  219. }
  220. return $theme_data;
  221. }
  222. /**
  223. * Retrieve list of themes with theme data in theme directory.
  224. *
  225. * The theme is broken, if it doesn't have a parent theme and is missing either
  226. * style.css and, or index.php. If the theme has a parent theme then it is
  227. * broken, if it is missing style.css; index.php is optional. The broken theme
  228. * list is saved in the {@link $wp_broken_themes} global, which is displayed on
  229. * the theme list in the administration panels.
  230. *
  231. * @since 1.5.0
  232. * @global array $wp_broken_themes Stores the broken themes.
  233. * @global array $wp_themes Stores the working themes.
  234. *
  235. * @return array Theme list with theme data.
  236. */
  237. function get_themes() {
  238. global $wp_themes, $wp_broken_themes;
  239. if ( isset($wp_themes) )
  240. return $wp_themes;
  241. if ( !$theme_files = search_theme_directories() )
  242. return false;
  243. asort( $theme_files );
  244. $wp_themes = array();
  245. foreach ( (array) $theme_files as $theme_file ) {
  246. $theme_root = $theme_file['theme_root'];
  247. $theme_file = $theme_file['theme_file'];
  248. if ( !is_readable("$theme_root/$theme_file") ) {
  249. $wp_broken_themes[$theme_file] = array('Name' => $theme_file, 'Title' => $theme_file, 'Description' => __('File not readable.'));
  250. continue;
  251. }
  252. $theme_data = get_theme_data("$theme_root/$theme_file");
  253. $name = $theme_data['Name'];
  254. $title = $theme_data['Title'];
  255. $description = wptexturize($theme_data['Description']);
  256. $version = $theme_data['Version'];
  257. $author = $theme_data['Author'];
  258. $template = $theme_data['Template'];
  259. $stylesheet = dirname($theme_file);
  260. $screenshot = false;
  261. foreach ( array('png', 'gif', 'jpg', 'jpeg') as $ext ) {
  262. if (file_exists("$theme_root/$stylesheet/screenshot.$ext")) {
  263. $screenshot = "screenshot.$ext";
  264. break;
  265. }
  266. }
  267. if ( empty($name) ) {
  268. $name = dirname($theme_file);
  269. $title = $name;
  270. }
  271. $parent_template = $template;
  272. if ( empty($template) ) {
  273. if ( file_exists("$theme_root/$stylesheet/index.php") )
  274. $template = $stylesheet;
  275. else
  276. continue;
  277. }
  278. $template = trim( $template );
  279. if ( !file_exists("$theme_root/$template/index.php") ) {
  280. $parent_dir = dirname(dirname($theme_file));
  281. if ( file_exists("$theme_root/$parent_dir/$template/index.php") ) {
  282. $template = "$parent_dir/$template";
  283. $template_directory = "$theme_root/$template";
  284. } else {
  285. /**
  286. * The parent theme doesn't exist in the current theme's folder or sub folder
  287. * so lets use the theme root for the parent template.
  288. */
  289. if ( isset($theme_files[$template]) && file_exists( $theme_files[$template]['theme_root'] . "/$template/index.php" ) ) {
  290. $template_directory = $theme_files[$template]['theme_root'] . "/$template";
  291. } else {
  292. if ( empty( $parent_template) )
  293. $wp_broken_themes[$name] = array('Name' => $name, 'Title' => $title, 'Description' => __('Template is missing.'), 'error' => 'no_template');
  294. else
  295. $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 );
  296. continue;
  297. }
  298. }
  299. } else {
  300. $template_directory = trim( $theme_root . '/' . $template );
  301. }
  302. $stylesheet_files = array();
  303. $template_files = array();
  304. $stylesheet_dir = @ dir("$theme_root/$stylesheet");
  305. if ( $stylesheet_dir ) {
  306. while ( ($file = $stylesheet_dir->read()) !== false ) {
  307. if ( !preg_match('|^\.+$|', $file) ) {
  308. if ( preg_match('|\.css$|', $file) )
  309. $stylesheet_files[] = "$theme_root/$stylesheet/$file";
  310. elseif ( preg_match('|\.php$|', $file) )
  311. $template_files[] = "$theme_root/$stylesheet/$file";
  312. }
  313. }
  314. @ $stylesheet_dir->close();
  315. }
  316. $template_dir = @ dir("$template_directory");
  317. if ( $template_dir ) {
  318. while ( ($file = $template_dir->read()) !== false ) {
  319. if ( preg_match('|^\.+$|', $file) )
  320. continue;
  321. if ( preg_match('|\.php$|', $file) ) {
  322. $template_files[] = "$template_directory/$file";
  323. } elseif ( is_dir("$template_directory/$file") ) {
  324. $template_subdir = @ dir("$template_directory/$file");
  325. if ( !$template_subdir )
  326. continue;
  327. while ( ($subfile = $template_subdir->read()) !== false ) {
  328. if ( preg_match('|^\.+$|', $subfile) )
  329. continue;
  330. if ( preg_match('|\.php$|', $subfile) )
  331. $template_files[] = "$template_directory/$file/$subfile";
  332. }
  333. @ $template_subdir->close();
  334. }
  335. }
  336. @ $template_dir->close();
  337. }
  338. //Make unique and remove duplicates when stylesheet and template are the same i.e. most themes
  339. $template_files = array_unique($template_files);
  340. $stylesheet_files = array_unique($stylesheet_files);
  341. $template_dir = $template_directory;
  342. $stylesheet_dir = $theme_root . '/' . $stylesheet;
  343. if ( empty($template_dir) )
  344. $template_dir = '/';
  345. if ( empty($stylesheet_dir) )
  346. $stylesheet_dir = '/';
  347. // Check for theme name collision. This occurs if a theme is copied to
  348. // a new theme directory and the theme header is not updated. Whichever
  349. // theme is first keeps the name. Subsequent themes get a suffix applied.
  350. // The Twenty Eleven, Twenty Ten, Default and Classic themes always trump
  351. // their pretenders.
  352. if ( isset($wp_themes[$name]) ) {
  353. $trump_cards = array(
  354. 'classic' => 'WordPress Classic',
  355. 'default' => 'WordPress Default',
  356. 'twentyten' => 'Twenty Ten',
  357. 'twentyeleven' => 'Twenty Eleven',
  358. );
  359. if ( isset( $trump_cards[ $stylesheet ] ) && $name == $trump_cards[ $stylesheet ] ) {
  360. // If another theme has claimed to be one of our default themes, move
  361. // them aside.
  362. $suffix = $wp_themes[$name]['Stylesheet'];
  363. $new_name = "$name/$suffix";
  364. $wp_themes[$new_name] = $wp_themes[$name];
  365. $wp_themes[$new_name]['Name'] = $new_name;
  366. } else {
  367. $name = "$name/$stylesheet";
  368. }
  369. }
  370. $theme_roots[$stylesheet] = str_replace( WP_CONTENT_DIR, '', $theme_root );
  371. $wp_themes[$name] = array(
  372. 'Name' => $name,
  373. 'Title' => $title,
  374. 'Description' => $description,
  375. 'Author' => $author,
  376. 'Author Name' => $theme_data['AuthorName'],
  377. 'Author URI' => $theme_data['AuthorURI'],
  378. 'Version' => $version,
  379. 'Template' => $template,
  380. 'Stylesheet' => $stylesheet,
  381. 'Template Files' => $template_files,
  382. 'Stylesheet Files' => $stylesheet_files,
  383. 'Template Dir' => $template_dir,
  384. 'Stylesheet Dir' => $stylesheet_dir,
  385. 'Status' => $theme_data['Status'],
  386. 'Screenshot' => $screenshot,
  387. 'Tags' => $theme_data['Tags'],
  388. 'Theme Root' => $theme_root,
  389. 'Theme Root URI' => str_replace( WP_CONTENT_DIR, content_url(), $theme_root ),
  390. );
  391. }
  392. unset($theme_files);
  393. /* Store theme roots in the DB */
  394. if ( get_site_transient( 'theme_roots' ) != $theme_roots )
  395. set_site_transient( 'theme_roots', $theme_roots, 7200 ); // cache for two hours
  396. unset($theme_roots);
  397. /* Resolve theme dependencies. */
  398. $theme_names = array_keys( $wp_themes );
  399. foreach ( (array) $theme_names as $theme_name ) {
  400. $wp_themes[$theme_name]['Parent Theme'] = '';
  401. if ( $wp_themes[$theme_name]['Stylesheet'] != $wp_themes[$theme_name]['Template'] ) {
  402. foreach ( (array) $theme_names as $parent_theme_name ) {
  403. if ( ($wp_themes[$parent_theme_name]['Stylesheet'] == $wp_themes[$parent_theme_name]['Template']) && ($wp_themes[$parent_theme_name]['Template'] == $wp_themes[$theme_name]['Template']) ) {
  404. $wp_themes[$theme_name]['Parent Theme'] = $wp_themes[$parent_theme_name]['Name'];
  405. break;
  406. }
  407. }
  408. }
  409. }
  410. return $wp_themes;
  411. }
  412. /**
  413. * Retrieve theme roots.
  414. *
  415. * @since 2.9.0
  416. *
  417. * @return array|string An arry of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root.
  418. */
  419. function get_theme_roots() {
  420. global $wp_theme_directories;
  421. if ( count($wp_theme_directories) <= 1 )
  422. return '/themes';
  423. $theme_roots = get_site_transient( 'theme_roots' );
  424. if ( false === $theme_roots ) {
  425. get_themes();
  426. $theme_roots = get_site_transient( 'theme_roots' ); // this is set in get_theme()
  427. }
  428. return $theme_roots;
  429. }
  430. /**
  431. * Retrieve theme data.
  432. *
  433. * @since 1.5.0
  434. *
  435. * @param string $theme Theme name.
  436. * @return array|null Null, if theme name does not exist. Theme data, if exists.
  437. */
  438. function get_theme($theme) {
  439. $themes = get_themes();
  440. if ( array_key_exists($theme, $themes) )
  441. return $themes[$theme];
  442. return null;
  443. }
  444. /**
  445. * Retrieve current theme display name.
  446. *
  447. * If the 'current_theme' option has already been set, then it will be returned
  448. * instead. If it is not set, then each theme will be iterated over until both
  449. * the current stylesheet and current template name.
  450. *
  451. * @since 1.5.0
  452. *
  453. * @return string
  454. */
  455. function get_current_theme() {
  456. if ( $theme = get_option('current_theme') )
  457. return $theme;
  458. $themes = get_themes();
  459. $theme_names = array_keys($themes);
  460. $current_template = get_option('template');
  461. $current_stylesheet = get_option('stylesheet');
  462. $current_theme = 'Twenty Ten';
  463. if ( $themes ) {
  464. foreach ( (array) $theme_names as $theme_name ) {
  465. if ( $themes[$theme_name]['Stylesheet'] == $current_stylesheet &&
  466. $themes[$theme_name]['Template'] == $current_template ) {
  467. $current_theme = $themes[$theme_name]['Name'];
  468. break;
  469. }
  470. }
  471. }
  472. update_option('current_theme', $current_theme);
  473. return $current_theme;
  474. }
  475. /**
  476. * Register a directory that contains themes.
  477. *
  478. * @since 2.9.0
  479. *
  480. * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR
  481. * @return bool
  482. */
  483. function register_theme_directory( $directory) {
  484. global $wp_theme_directories;
  485. /* If this folder does not exist, return and do not register */
  486. if ( !file_exists( $directory ) )
  487. /* Try prepending as the theme directory could be relative to the content directory */
  488. $registered_directory = WP_CONTENT_DIR . '/' . $directory;
  489. else
  490. $registered_directory = $directory;
  491. /* If this folder does not exist, return and do not register */
  492. if ( !file_exists( $registered_directory ) )
  493. return false;
  494. $wp_theme_directories[] = $registered_directory;
  495. return true;
  496. }
  497. /**
  498. * Search all registered theme directories for complete and valid themes.
  499. *
  500. * @since 2.9.0
  501. *
  502. * @return array Valid themes found
  503. */
  504. function search_theme_directories() {
  505. global $wp_theme_directories, $wp_broken_themes;
  506. if ( empty( $wp_theme_directories ) )
  507. return false;
  508. $theme_files = array();
  509. $wp_broken_themes = array();
  510. /* Loop the registered theme directories and extract all themes */
  511. foreach ( (array) $wp_theme_directories as $theme_root ) {
  512. $theme_loc = $theme_root;
  513. /* We don't want to replace all forward slashes, see Trac #4541 */
  514. if ( '/' != WP_CONTENT_DIR )
  515. $theme_loc = str_replace(WP_CONTENT_DIR, '', $theme_root);
  516. /* Files in the root of the current theme directory and one subdir down */
  517. $themes_dir = @ opendir($theme_root);
  518. if ( !$themes_dir )
  519. return false;
  520. while ( ($theme_dir = readdir($themes_dir)) !== false ) {
  521. if ( is_dir($theme_root . '/' . $theme_dir) && is_readable($theme_root . '/' . $theme_dir) ) {
  522. if ( $theme_dir[0] == '.' || $theme_dir == 'CVS' )
  523. continue;
  524. $stylish_dir = @opendir($theme_root . '/' . $theme_dir);
  525. $found_stylesheet = false;
  526. while ( ($theme_file = readdir($stylish_dir)) !== false ) {
  527. if ( $theme_file == 'style.css' ) {
  528. $theme_files[$theme_dir] = array( 'theme_file' => $theme_dir . '/' . $theme_file, 'theme_root' => $theme_root );
  529. $found_stylesheet = true;
  530. break;
  531. }
  532. }
  533. @closedir($stylish_dir);
  534. if ( !$found_stylesheet ) { // look for themes in that dir
  535. $subdir = "$theme_root/$theme_dir";
  536. $subdir_name = $theme_dir;
  537. $theme_subdirs = @opendir( $subdir );
  538. $found_subdir_themes = false;
  539. while ( ($theme_subdir = readdir($theme_subdirs)) !== false ) {
  540. if ( is_dir( $subdir . '/' . $theme_subdir) && is_readable($subdir . '/' . $theme_subdir) ) {
  541. if ( $theme_subdir[0] == '.' || $theme_subdir == 'CVS' )
  542. continue;
  543. $stylish_dir = @opendir($subdir . '/' . $theme_subdir);
  544. $found_stylesheet = false;
  545. while ( ($theme_file = readdir($stylish_dir)) !== false ) {
  546. if ( $theme_file == 'style.css' ) {
  547. $theme_files["$theme_dir/$theme_subdir"] = array( 'theme_file' => $subdir_name . '/' . $theme_subdir . '/' . $theme_file, 'theme_root' => $theme_root );
  548. $found_stylesheet = true;
  549. $found_subdir_themes = true;
  550. break;
  551. }
  552. }
  553. @closedir($stylish_dir);
  554. }
  555. }
  556. @closedir($theme_subdirs);
  557. if ( !$found_subdir_themes )
  558. $wp_broken_themes[$theme_dir] = array('Name' => $theme_dir, 'Title' => $theme_dir, 'Description' => __('Stylesheet is missing.'));
  559. }
  560. }
  561. }
  562. @closedir( $themes_dir );
  563. }
  564. return $theme_files;
  565. }
  566. /**
  567. * Retrieve path to themes directory.
  568. *
  569. * Does not have trailing slash.
  570. *
  571. * @since 1.5.0
  572. * @uses apply_filters() Calls 'theme_root' filter on path.
  573. *
  574. * @param string $stylesheet_or_template The stylesheet or template name of the theme
  575. * @return string Theme path.
  576. */
  577. function get_theme_root( $stylesheet_or_template = false ) {
  578. if ( $stylesheet_or_template ) {
  579. if ( $theme_root = get_raw_theme_root($stylesheet_or_template) )
  580. $theme_root = WP_CONTENT_DIR . $theme_root;
  581. else
  582. $theme_root = WP_CONTENT_DIR . '/themes';
  583. } else {
  584. $theme_root = WP_CONTENT_DIR . '/themes';
  585. }
  586. return apply_filters( 'theme_root', $theme_root );
  587. }
  588. /**
  589. * Retrieve URI for themes directory.
  590. *
  591. * Does not have trailing slash.
  592. *
  593. * @since 1.5.0
  594. *
  595. * @param string $stylesheet_or_template The stylesheet or template name of the theme
  596. * @return string Themes URI.
  597. */
  598. function get_theme_root_uri( $stylesheet_or_template = false ) {
  599. if ( $stylesheet_or_template ) {
  600. if ( $theme_root = get_raw_theme_root($stylesheet_or_template) )
  601. $theme_root_uri = content_url( $theme_root );
  602. else
  603. $theme_root_uri = content_url( 'themes' );
  604. } else {
  605. $theme_root_uri = content_url( 'themes' );
  606. }
  607. return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
  608. }
  609. /**
  610. * Get the raw theme root relative to the content directory with no filters applied.
  611. *
  612. * @since 3.1.0
  613. *
  614. * @param string $stylesheet_or_template The stylesheet or template name of the theme
  615. * @return string Theme root
  616. */
  617. function get_raw_theme_root( $stylesheet_or_template, $no_cache = false ) {
  618. global $wp_theme_directories;
  619. if ( count($wp_theme_directories) <= 1 )
  620. return '/themes';
  621. $theme_root = false;
  622. // If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
  623. if ( !$no_cache ) {
  624. if ( get_option('stylesheet') == $stylesheet_or_template )
  625. $theme_root = get_option('stylesheet_root');
  626. elseif ( get_option('template') == $stylesheet_or_template )
  627. $theme_root = get_option('template_root');
  628. }
  629. if ( empty($theme_root) ) {
  630. $theme_roots = get_theme_roots();
  631. if ( !empty($theme_roots[$stylesheet_or_template]) )
  632. $theme_root = $theme_roots[$stylesheet_or_template];
  633. }
  634. return $theme_root;
  635. }
  636. /**
  637. * Retrieve path to a template
  638. *
  639. * Used to quickly retrieve the path of a template without including the file
  640. * extension. It will also check the parent theme, if the file exists, with
  641. * the use of {@link locate_template()}. Allows for more generic template location
  642. * without the use of the other get_*_template() functions.
  643. *
  644. * @since 1.5.0
  645. *
  646. * @param string $type Filename without extension.
  647. * @param array $templates An optional list of template candidates
  648. * @return string Full path to file.
  649. */
  650. function get_query_template( $type, $templates = array() ) {
  651. $type = preg_replace( '|[^a-z0-9-]+|', '', $type );
  652. if ( empty( $templates ) )
  653. $templates = array("{$type}.php");
  654. return apply_filters( "{$type}_template", locate_template( $templates ) );
  655. }
  656. /**
  657. * Retrieve path of index template in current or parent template.
  658. *
  659. * @since 3.0.0
  660. *
  661. * @return string
  662. */
  663. function get_index_template() {
  664. return get_query_template('index');
  665. }
  666. /**
  667. * Retrieve path of 404 template in current or parent template.
  668. *
  669. * @since 1.5.0
  670. *
  671. * @return string
  672. */
  673. function get_404_template() {
  674. return get_query_template('404');
  675. }
  676. /**
  677. * Retrieve path of archive template in current or parent template.
  678. *
  679. * @since 1.5.0
  680. *
  681. * @return string
  682. */
  683. function get_archive_template() {
  684. $post_type = get_query_var( 'post_type' );
  685. $templates = array();
  686. if ( $post_type )
  687. $templates[] = "archive-{$post_type}.php";
  688. $templates[] = 'archive.php';
  689. return get_query_template( 'archive', $templates );
  690. }
  691. /**
  692. * Retrieve path of author template in current or parent template.
  693. *
  694. * @since 1.5.0
  695. *
  696. * @return string
  697. */
  698. function get_author_template() {
  699. $author = get_queried_object();
  700. $templates = array();
  701. $templates[] = "author-{$author->user_nicename}.php";
  702. $templates[] = "author-{$author->ID}.php";
  703. $templates[] = 'author.php';
  704. return get_query_template( 'author', $templates );
  705. }
  706. /**
  707. * Retrieve path of category template in current or parent template.
  708. *
  709. * Works by first retrieving the current slug for example 'category-default.php' and then
  710. * trying category ID, for example 'category-1.php' and will finally fallback to category.php
  711. * template, if those files don't exist.
  712. *
  713. * @since 1.5.0
  714. * @uses apply_filters() Calls 'category_template' on file path of category template.
  715. *
  716. * @return string
  717. */
  718. function get_category_template() {
  719. $category = get_queried_object();
  720. $templates = array();
  721. $templates[] = "category-{$category->slug}.php";
  722. $templates[] = "category-{$category->term_id}.php";
  723. $templates[] = 'category.php';
  724. return get_query_template( 'category', $templates );
  725. }
  726. /**
  727. * Retrieve path of tag template in current or parent template.
  728. *
  729. * Works by first retrieving the current tag name, for example 'tag-wordpress.php' and then
  730. * trying tag ID, for example 'tag-1.php' and will finally fallback to tag.php
  731. * template, if those files don't exist.
  732. *
  733. * @since 2.3.0
  734. * @uses apply_filters() Calls 'tag_template' on file path of tag template.
  735. *
  736. * @return string
  737. */
  738. function get_tag_template() {
  739. $tag = get_queried_object();
  740. $templates = array();
  741. $templates[] = "tag-{$tag->slug}.php";
  742. $templates[] = "tag-{$tag->term_id}.php";
  743. $templates[] = 'tag.php';
  744. return get_query_template( 'tag', $templates );
  745. }
  746. /**
  747. * Retrieve path of taxonomy template in current or parent template.
  748. *
  749. * Retrieves the taxonomy and term, if term is available. The template is
  750. * prepended with 'taxonomy-' and followed by both the taxonomy string and
  751. * the taxonomy string followed by a dash and then followed by the term.
  752. *
  753. * The taxonomy and term template is checked and used first, if it exists.
  754. * Second, just the taxonomy template is checked, and then finally, taxonomy.php
  755. * template is used. If none of the files exist, then it will fall back on to
  756. * index.php.
  757. *
  758. * @since 2.5.0
  759. * @uses apply_filters() Calls 'taxonomy_template' filter on found path.
  760. *
  761. * @return string
  762. */
  763. function get_taxonomy_template() {
  764. $term = get_queried_object();
  765. $taxonomy = $term->taxonomy;
  766. $templates = array();
  767. $templates[] = "taxonomy-$taxonomy-{$term->slug}.php";
  768. $templates[] = "taxonomy-$taxonomy.php";
  769. $templates[] = 'taxonomy.php';
  770. return get_query_template( 'taxonomy', $templates );
  771. }
  772. /**
  773. * Retrieve path of date template in current or parent template.
  774. *
  775. * @since 1.5.0
  776. *
  777. * @return string
  778. */
  779. function get_date_template() {
  780. return get_query_template('date');
  781. }
  782. /**
  783. * Retrieve path of home template in current or parent template.
  784. *
  785. * This is the template used for the page containing the blog posts
  786. *
  787. * Attempts to locate 'home.php' first before falling back to 'index.php'.
  788. *
  789. * @since 1.5.0
  790. * @uses apply_filters() Calls 'home_template' on file path of home template.
  791. *
  792. * @return string
  793. */
  794. function get_home_template() {
  795. $templates = array( 'home.php', 'index.php' );
  796. return get_query_template( 'home', $templates );
  797. }
  798. /**
  799. * Retrieve path of front-page template in current or parent template.
  800. *
  801. * Looks for 'front-page.php'.
  802. *
  803. * @since 3.0.0
  804. * @uses apply_filters() Calls 'front_page_template' on file path of template.
  805. *
  806. * @return string
  807. */
  808. function get_front_page_template() {
  809. $templates = array('front-page.php');
  810. return get_query_template( 'front_page', $templates );
  811. }
  812. /**
  813. * Retrieve path of page template in current or parent template.
  814. *
  815. * Will first look for the specifically assigned page template
  816. * The will search for 'page-{slug}.php' followed by 'page-id.php'
  817. * and finally 'page.php'
  818. *
  819. * @since 1.5.0
  820. *
  821. * @return string
  822. */
  823. function get_page_template() {
  824. $id = get_queried_object_id();
  825. $template = get_post_meta($id, '_wp_page_template', true);
  826. $pagename = get_query_var('pagename');
  827. if ( !$pagename && $id > 0 ) {
  828. // If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
  829. $post = get_queried_object();
  830. $pagename = $post->post_name;
  831. }
  832. if ( 'default' == $template )
  833. $template = '';
  834. $templates = array();
  835. if ( !empty($template) && !validate_file($template) )
  836. $templates[] = $template;
  837. if ( $pagename )
  838. $templates[] = "page-$pagename.php";
  839. if ( $id )
  840. $templates[] = "page-$id.php";
  841. $templates[] = 'page.php';
  842. return get_query_template( 'page', $templates );
  843. }
  844. /**
  845. * Retrieve path of paged template in current or parent template.
  846. *
  847. * @since 1.5.0
  848. *
  849. * @return string
  850. */
  851. function get_paged_template() {
  852. return get_query_template('paged');
  853. }
  854. /**
  855. * Retrieve path of search template in current or parent template.
  856. *
  857. * @since 1.5.0
  858. *
  859. * @return string
  860. */
  861. function get_search_template() {
  862. return get_query_template('search');
  863. }
  864. /**
  865. * Retrieve path of single template in current or parent template.
  866. *
  867. * @since 1.5.0
  868. *
  869. * @return string
  870. */
  871. function get_single_template() {
  872. $object = get_queried_object();
  873. $templates = array();
  874. $templates[] = "single-{$object->post_type}.php";
  875. $templates[] = "single.php";
  876. return get_query_template( 'single', $templates );
  877. }
  878. /**
  879. * Retrieve path of attachment template in current or parent template.
  880. *
  881. * The attachment path first checks if the first part of the mime type exists.
  882. * The second check is for the second part of the mime type. The last check is
  883. * for both types separated by an underscore. If neither are found then the file
  884. * 'attachment.php' is checked and returned.
  885. *
  886. * Some examples for the 'text/plain' mime type are 'text.php', 'plain.php', and
  887. * finally 'text_plain.php'.
  888. *
  889. * @since 2.0.0
  890. *
  891. * @return string
  892. */
  893. function get_attachment_template() {
  894. global $posts;
  895. $type = explode('/', $posts[0]->post_mime_type);
  896. if ( $template = get_query_template($type[0]) )
  897. return $template;
  898. elseif ( $template = get_query_template($type[1]) )
  899. return $template;
  900. elseif ( $template = get_query_template("$type[0]_$type[1]") )
  901. return $template;
  902. else
  903. return get_query_template('attachment');
  904. }
  905. /**
  906. * Retrieve path of comment popup template in current or parent template.
  907. *
  908. * Checks for comment popup template in current template, if it exists or in the
  909. * parent template.
  910. *
  911. * @since 1.5.0
  912. * @uses apply_filters() Calls 'comments_popup_template' filter on path.
  913. *
  914. * @return string
  915. */
  916. function get_comments_popup_template() {
  917. $template = get_query_template( 'comments_popup', array( 'comments-popup.php' ) );
  918. // Backward compat code will be removed in a future release
  919. if ('' == $template)
  920. $template = ABSPATH . WPINC . '/theme-compat/comments-popup.php';
  921. return $template;
  922. }
  923. /**
  924. * Retrieve the name of the highest priority template file that exists.
  925. *
  926. * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
  927. * inherit from a parent theme can just overload one file.
  928. *
  929. * @since 2.7.0
  930. *
  931. * @param string|array $template_names Template file(s) to search for, in order.
  932. * @param bool $load If true the template file will be loaded if it is found.
  933. * @param bool $require_once Whether to require_once or require. Default true. Has no effect if $load is false.
  934. * @return string The template filename if one is located.
  935. */
  936. function locate_template($template_names, $load = false, $require_once = true ) {
  937. $located = '';
  938. foreach ( (array) $template_names as $template_name ) {
  939. if ( !$template_name )
  940. continue;
  941. if ( file_exists(STYLESHEETPATH . '/' . $template_name)) {
  942. $located = STYLESHEETPATH . '/' . $template_name;
  943. break;
  944. } else if ( file_exists(TEMPLATEPATH . '/' . $template_name) ) {
  945. $located = TEMPLATEPATH . '/' . $template_name;
  946. break;
  947. }
  948. }
  949. if ( $load && '' != $located )
  950. load_template( $located, $require_once );
  951. return $located;
  952. }
  953. /**
  954. * Require the template file with WordPress environment.
  955. *
  956. * The globals are set up for the template file to ensure that the WordPress
  957. * environment is available from within the function. The query variables are
  958. * also available.
  959. *
  960. * @since 1.5.0
  961. *
  962. * @param string $_template_file Path to template file.
  963. * @param bool $require_once Whether to require_once or require. Default true.
  964. */
  965. function load_template( $_template_file, $require_once = true ) {
  966. global $posts, $post, $wp_did_header, $wp_did_template_redirect, $wp_query, $wp_rewrite, $wpdb, $wp_version, $wp, $id, $comment, $user_ID;
  967. if ( is_array( $wp_query->query_vars ) )
  968. extract( $wp_query->query_vars, EXTR_SKIP );
  969. if ( $require_once )
  970. require_once( $_template_file );
  971. else
  972. require( $_template_file );
  973. }
  974. /**
  975. * Display localized stylesheet link element.
  976. *
  977. * @since 2.1.0
  978. */
  979. function locale_stylesheet() {
  980. $stylesheet = get_locale_stylesheet_uri();
  981. if ( empty($stylesheet) )
  982. return;
  983. echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
  984. }
  985. /**
  986. * Start preview theme output buffer.
  987. *
  988. * Will only preform task if the user has permissions and template and preview
  989. * query variables exist.
  990. *
  991. * @since 2.6.0
  992. */
  993. function preview_theme() {
  994. if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
  995. return;
  996. if ( !current_user_can( 'switch_themes' ) )
  997. return;
  998. // Admin Thickbox requests
  999. if ( isset( $_GET['preview_iframe'] ) )
  1000. show_admin_bar( false );
  1001. $_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
  1002. if ( validate_file($_GET['template']) )
  1003. return;
  1004. add_filter( 'template', '_preview_theme_template_filter' );
  1005. if ( isset($_GET['stylesheet']) ) {
  1006. $_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
  1007. if ( validate_file($_GET['stylesheet']) )
  1008. return;
  1009. add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
  1010. }
  1011. // Prevent theme mods to current theme being used on theme being previewed
  1012. add_filter( 'pre_option_mods_' . get_current_theme(), '__return_empty_array' );
  1013. ob_start( 'preview_theme_ob_filter' );
  1014. }
  1015. add_action('setup_theme', 'preview_theme');
  1016. /**
  1017. * Private function to modify the current template when previewing a theme
  1018. *
  1019. * @since 2.9.0
  1020. * @access private
  1021. *
  1022. * @return string
  1023. */
  1024. function _preview_theme_template_filter() {
  1025. return isset($_GET['template']) ? $_GET['template'] : '';
  1026. }
  1027. /**
  1028. * Private function to modify the current stylesheet when previewing a theme
  1029. *
  1030. * @since 2.9.0
  1031. * @access private
  1032. *
  1033. * @return string
  1034. */
  1035. function _preview_theme_stylesheet_filter() {
  1036. return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
  1037. }
  1038. /**
  1039. * Callback function for ob_start() to capture all links in the theme.
  1040. *
  1041. * @since 2.6.0
  1042. * @access private
  1043. *
  1044. * @param string $content
  1045. * @return string
  1046. */
  1047. function preview_theme_ob_filter( $content ) {
  1048. return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
  1049. }
  1050. /**
  1051. * Manipulates preview theme links in order to control and maintain location.
  1052. *
  1053. * Callback function for preg_replace_callback() to accept and filter matches.
  1054. *
  1055. * @since 2.6.0
  1056. * @access private
  1057. *
  1058. * @param array $matches
  1059. * @return string
  1060. */
  1061. function preview_theme_ob_filter_callback( $matches ) {
  1062. if ( strpos($matches[4], 'onclick') !== false )
  1063. $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.
  1064. if (
  1065. ( false !== strpos($matches[3], '/wp-admin/') )
  1066. ||
  1067. ( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
  1068. ||
  1069. ( false !== strpos($matches[3], '/feed/') )
  1070. ||
  1071. ( false !== strpos($matches[3], '/trackback/') )
  1072. )
  1073. return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
  1074. $link = add_query_arg( array('preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'] ), $matches[3] );
  1075. if ( 0 === strpos($link, 'preview=1') )
  1076. $link = "?$link";
  1077. return $matches[1] . esc_attr( $link ) . $matches[4];
  1078. }
  1079. /**
  1080. * Switches current theme to new template and stylesheet names.
  1081. *
  1082. * @since 2.5.0
  1083. * @uses do_action() Calls 'switch_theme' action on updated theme display name.
  1084. *
  1085. * @param string $template Template name
  1086. * @param string $stylesheet Stylesheet name.
  1087. */
  1088. function switch_theme($template, $stylesheet) {
  1089. global $wp_theme_directories;
  1090. update_option('template', $template);
  1091. update_option('stylesheet', $stylesheet);
  1092. if ( count($wp_theme_directories) > 1 ) {
  1093. update_option('template_root', get_raw_theme_root($template, true));
  1094. update_option('stylesheet_root', get_raw_theme_root($stylesheet, true));
  1095. }
  1096. delete_option('current_theme');
  1097. $theme = get_current_theme();
  1098. if ( is_admin() && false === get_option( "theme_mods_$stylesheet" ) ) {
  1099. $default_theme_mods = (array) get_option( "mods_$theme" );
  1100. add_option( "theme_mods_$stylesheet", $default_theme_mods );
  1101. }
  1102. do_action('switch_theme', $theme);
  1103. }
  1104. /**
  1105. * Checks that current theme files 'index.php' and 'style.css' exists.
  1106. *
  1107. * Does not check the default theme, which is the fallback and should always exist.
  1108. * Will switch theme to the fallback theme if current theme does not validate.
  1109. * You can use the 'validate_current_theme' filter to return FALSE to
  1110. * disable this functionality.
  1111. *
  1112. * @since 1.5.0
  1113. * @see WP_DEFAULT_THEME
  1114. *
  1115. * @return bool
  1116. */
  1117. function validate_current_theme() {
  1118. // Don't validate during an install/upgrade.
  1119. if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
  1120. return true;
  1121. if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
  1122. switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
  1123. return false;
  1124. }
  1125. if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
  1126. switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
  1127. return false;
  1128. }
  1129. if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
  1130. switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
  1131. return false;
  1132. }
  1133. return true;
  1134. }
  1135. /**
  1136. * Retrieve all theme modifications.
  1137. *
  1138. * @since 3.1.0
  1139. *
  1140. * @return array Theme modifications.
  1141. */
  1142. function get_theme_mods() {
  1143. $theme_slug = get_option( 'stylesheet' );
  1144. if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
  1145. $theme_name = get_current_theme();
  1146. $mods = get_option( "mods_$theme_name" ); // Deprecated location.
  1147. if ( is_admin() && false !== $mods ) {
  1148. update_option( "theme_mods_$theme_slug", $mods );
  1149. delete_option( "mods_$theme_name" );
  1150. }
  1151. }
  1152. return $mods;
  1153. }
  1154. /**
  1155. * Retrieve theme modification value for the current theme.
  1156. *
  1157. * If the modification name does not exist, then the $default will be passed
  1158. * through {@link http://php.net/sprintf sprintf()} PHP function with the first
  1159. * string the template directory URI and the second string the stylesheet
  1160. * directory URI.
  1161. *
  1162. * @since 2.1.0
  1163. * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
  1164. *
  1165. * @param string $name Theme modification name.
  1166. * @param bool|string $default
  1167. * @return string
  1168. */
  1169. function get_theme_mod( $name, $default = false ) {
  1170. $mods = get_theme_mods();
  1171. if ( isset( $mods[ $name ] ) )
  1172. return apply_filters( "theme_mod_$name", $mods[ $name ] );
  1173. return apply_filters( "theme_mod_$name", sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() ) );
  1174. }
  1175. /**
  1176. * Update theme modification value for the current theme.
  1177. *
  1178. * @since 2.1.0
  1179. *
  1180. * @param string $name Theme modification name.
  1181. * @param string $value theme modification value.
  1182. */
  1183. function set_theme_mod( $name, $value ) {
  1184. $mods = get_theme_mods();
  1185. $mods[ $name ] = $value;
  1186. $theme = get_option( 'stylesheet' );
  1187. update_option( "theme_mods_$theme", $mods );
  1188. }
  1189. /**
  1190. * Remove theme modification name from current theme list.
  1191. *
  1192. * If removing the name also removes all elements, then the entire option will
  1193. * be removed.
  1194. *
  1195. * @since 2.1.0
  1196. *
  1197. * @param string $name Theme modification name.
  1198. * @return null
  1199. */
  1200. function remove_theme_mod( $name ) {
  1201. $mods = get_theme_mods();
  1202. if ( ! isset( $mods[ $name ] ) )
  1203. return;
  1204. unset( $mods[ $name ] );
  1205. if ( empty( $mods ) )
  1206. return remove_theme_mods();
  1207. $theme = get_option( 'stylesheet' );
  1208. update_option( "theme_mods_$theme", $mods );
  1209. }
  1210. /**
  1211. * Remove theme modifications option for current theme.
  1212. *
  1213. * @since 2.1.0
  1214. */
  1215. function remove_theme_mods() {
  1216. delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
  1217. delete_option( 'mods_' . get_current_theme() );
  1218. }
  1219. /**
  1220. * Retrieve text color for custom header.
  1221. *
  1222. * @since 2.1.0
  1223. * @uses HEADER_TEXTCOLOR
  1224. *
  1225. * @return string
  1226. */
  1227. function get_header_textcolor() {
  1228. $default = defined('HEADER_TEXTCOLOR') ? HEADER_TEXTCOLOR : '';
  1229. return get_theme_mod('header_textcolor', $default);
  1230. }
  1231. /**
  1232. * Display text color for custom header.
  1233. *
  1234. * @since 2.1.0
  1235. */
  1236. function header_textcolor() {
  1237. echo get_header_textcolor();
  1238. }
  1239. /**
  1240. * Retrieve header image for custom header.
  1241. *
  1242. * @since 2.1.0
  1243. * @uses HEADER_IMAGE
  1244. *
  1245. * @return string
  1246. */
  1247. function get_header_image() {
  1248. $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
  1249. $url = get_theme_mod( 'header_image', $default );
  1250. if ( 'remove-header' == $url )
  1251. return false;
  1252. if ( is_random_header_image() )
  1253. $url = get_random_header_image();
  1254. if ( is_ssl() )
  1255. $url = str_replace( 'http://', 'https://', $url );
  1256. else
  1257. $url = str_replace( 'https://', 'http://', $url );
  1258. return esc_url_raw( $url );
  1259. }
  1260. /**
  1261. * Get random header image from registered images in theme.
  1262. *
  1263. * @since 3.2.0
  1264. *
  1265. * @return string Path to header image
  1266. */
  1267. function get_random_header_image() {
  1268. global $_wp_default_headers;
  1269. $header_image_mod = get_theme_mod( 'header_image', '' );
  1270. $headers = array();
  1271. if ( 'random-uploaded-image' == $header_image_mod )
  1272. $headers = get_uploaded_header_images();
  1273. elseif ( ! empty( $_wp_default_headers ) ) {
  1274. if ( 'random-default-image' == $header_image_mod ) {
  1275. $headers = $_wp_default_headers;
  1276. } else {
  1277. $is_random = get_theme_support( 'custom-header' );
  1278. if ( isset( $is_random[ 0 ] ) && !empty( $is_random[ 0 ][ 'random-default' ] ) )
  1279. $headers = $_wp_default_headers;
  1280. }
  1281. }
  1282. if ( empty( $headers ) )
  1283. return '';
  1284. $random_image = array_rand( $headers );
  1285. $header_url = sprintf( $headers[$random_image]['url'], get_template_directory_uri(), get_stylesheet_directory_uri() );
  1286. return $header_url;
  1287. }
  1288. /**
  1289. * Check if random header image is in use.
  1290. *
  1291. * Always true if user expressly chooses the option in Appearance > Header.
  1292. * Also true if theme has multiple header images registered, no specific header image
  1293. * is chosen, and theme turns on random headers with add_theme_support().
  1294. *
  1295. * @since 3.2.0
  1296. * @uses HEADER_IMAGE
  1297. *
  1298. * @param string $type The random pool to use. any|default|uploaded
  1299. * @return boolean
  1300. */
  1301. function is_random_header_image( $type = 'any' ) {
  1302. $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
  1303. $header_image_mod = get_theme_mod( 'header_image', $default );
  1304. if ( 'any' == $type ) {
  1305. if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
  1306. return true;
  1307. } else {
  1308. if ( "random-$type-image" == $header_image_mod )
  1309. return true;
  1310. elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
  1311. return true;
  1312. }
  1313. return false;
  1314. }
  1315. /**
  1316. * Display header image path.
  1317. *
  1318. * @since 2.1.0
  1319. */
  1320. function header_image() {
  1321. echo get_header_image();
  1322. }
  1323. /**
  1324. * Get the header images uploaded for the current theme.
  1325. *
  1326. * @since 3.2.0
  1327. *
  1328. * @return array
  1329. */
  1330. function get_uploaded_header_images() {
  1331. $header_images = array();
  1332. // @todo caching
  1333. $headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
  1334. if ( empty( $headers ) )
  1335. return array();
  1336. foreach ( (array) $headers as $header ) {
  1337. $url = esc_url_raw( $header->guid );
  1338. $header = basename($url);
  1339. $header_images[$header] = array();
  1340. $header_images[$header]['url'] = $url;
  1341. $header_images[$header]['thumbnail_url'] = $url;
  1342. $header_images[$header]['uploaded'] = true;
  1343. }
  1344. return $header_images;
  1345. }
  1346. /**
  1347. * Add callbacks for image header display.
  1348. *
  1349. * The parameter $header_callback callback will be required to display the
  1350. * content for the 'wp_head' action. The parameter $admin_header_callback
  1351. * callback will be added to Custom_Image_Header class and that will be added
  1352. * to the 'admin_menu' action.
  1353. *
  1354. * @since 2.1.0
  1355. * @uses Custom_Image_Header Sets up for $admin_header_callback for administration panel display.
  1356. *
  1357. * @param callback $header_callback Call on 'wp_head' action.
  1358. * @param callback $admin_header_callback Call on custom header administration screen.
  1359. * @param callback $admin_image_div_callback Output a custom header image div on the custom header administration screen. Optional.
  1360. */
  1361. function add_custom_image_header( $header_callback, $admin_header_callback, $admin_image_div_callback = '' ) {
  1362. if ( ! empty( $header_callback ) )
  1363. add_action('wp_head', $header_callback);
  1364. $support = array( 'callback' => $header_callback );
  1365. $theme_support = get_theme_support( 'custom-header' );
  1366. if ( ! empty( $theme_support ) && is_array( $theme_support[ 0 ] ) )
  1367. $support = array_merge( $theme_support[ 0 ], $support );
  1368. add_theme_support( 'custom-header', $support );
  1369. add_theme_support( 'custom-header-uploads' );
  1370. if ( ! is_admin() )
  1371. return;
  1372. global $custom_image_header;
  1373. require_once( ABSPATH . 'wp-admin/custom-header.php' );
  1374. $custom_image_header = new Custom_Image_Header( $admin_header_callback, $admin_image_div_callback );
  1375. add_action( 'admin_menu', array( &$custom_image_header, 'init' ) );
  1376. }
  1377. /**
  1378. * Remove image header support.
  1379. *
  1380. * @since 3.1.0
  1381. * @see add_custom_image_header()
  1382. *
  1383. * @return bool Whether support was removed.
  1384. */
  1385. function remove_custom_image_header() {
  1386. if ( ! current_theme_supports( 'custom-header' ) )
  1387. return false;
  1388. $callback = get_theme_support( 'custom-header' );
  1389. remove_action( 'wp_head', $callback[0]['callback'] );
  1390. _remove_theme_support( 'custom-header' );
  1391. remove_theme_support( 'custom-header-uploads' );
  1392. if ( is_admin() ) {
  1393. remove_action( 'admin_menu', array( &$GLOBALS['custom_image_header'], 'init' ) );
  1394. unset( $GLOBALS['custom_image_header'] );
  1395. }
  1396. return true;
  1397. }
  1398. /**
  1399. * Register a selection of default headers to be displayed by the custom header admin UI.
  1400. *
  1401. * @since 3.0.0
  1402. *
  1403. * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
  1404. */
  1405. function register_default_headers( $headers ) {
  1406. global $_wp_default_headers;
  1407. $_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
  1408. }
  1409. /**
  1410. * Unregister default headers.
  1411. *
  1412. * This function must be called after register_default_headers() has already added the
  1413. * header you want to remove.
  1414. *
  1415. * @see register_default_headers()
  1416. * @since 3.0.0
  1417. *
  1418. * @param string|array $header The header string id (key of array) to remove, or an array thereof.
  1419. * @return True on success, false on failure.
  1420. */
  1421. function unregister_default_headers( $header ) {
  1422. global $_wp_default_headers;
  1423. if ( is_array( $header ) ) {
  1424. array_map( 'unregister_default_headers', $header );
  1425. } elseif ( isset( $_wp_default_headers[ $header ] ) ) {
  1426. unset( $_wp_default_headers[ $header ] );
  1427. return true;
  1428. } else {
  1429. return false;
  1430. }
  1431. }
  1432. /**
  1433. * Retrieve background image for custom background.
  1434. *
  1435. * @since 3.0.0
  1436. *
  1437. * @return string
  1438. */
  1439. function get_background_image() {
  1440. $default = defined('BACKGROUND_IMAGE') ? BACKGROUND_IMAGE : '';
  1441. retu

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