PageRenderTime 63ms CodeModel.GetById 30ms RepoModel.GetById 0ms 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
Possible License(s): LGPL-2.1, AGPL-1.0, GPL-2.0, GPL-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 array 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 ( is_array( $themes ) && 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. $current_theme = 'Twenty Eleven';
  460. if ( $themes ) {
  461. $theme_names = array_keys( $themes );
  462. $current_template = get_option( 'template' );
  463. $current_stylesheet = get_option( 'stylesheet' );
  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, $sidebars_widgets;
  1090. if ( is_array( $sidebars_widgets ) )
  1091. set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $sidebars_widgets ) );
  1092. $old_theme = get_current_theme();
  1093. update_option('template', $template);
  1094. update_option('stylesheet', $stylesheet);
  1095. if ( count($wp_theme_directories) > 1 ) {
  1096. update_option('template_root', get_raw_theme_root($template, true));
  1097. update_option('stylesheet_root', get_raw_theme_root($stylesheet, true));
  1098. }
  1099. delete_option('current_theme');
  1100. $theme = get_current_theme();
  1101. if ( is_admin() && false === get_option( "theme_mods_$stylesheet" ) ) {
  1102. $default_theme_mods = (array) get_option( "mods_$theme" );
  1103. add_option( "theme_mods_$stylesheet", $default_theme_mods );
  1104. }
  1105. update_option( 'theme_switched', $old_theme );
  1106. do_action( 'switch_theme', $theme );
  1107. }
  1108. /**
  1109. * Checks that current theme files 'index.php' and 'style.css' exists.
  1110. *
  1111. * Does not check the default theme, which is the fallback and should always exist.
  1112. * Will switch theme to the fallback theme if current theme does not validate.
  1113. * You can use the 'validate_current_theme' filter to return FALSE to
  1114. * disable this functionality.
  1115. *
  1116. * @since 1.5.0
  1117. * @see WP_DEFAULT_THEME
  1118. *
  1119. * @return bool
  1120. */
  1121. function validate_current_theme() {
  1122. // Don't validate during an install/upgrade.
  1123. if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
  1124. return true;
  1125. if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
  1126. switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
  1127. return false;
  1128. }
  1129. if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
  1130. switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
  1131. return false;
  1132. }
  1133. if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
  1134. switch_theme( WP_DEFAULT_THEME, WP_DEFAULT_THEME );
  1135. return false;
  1136. }
  1137. return true;
  1138. }
  1139. /**
  1140. * Retrieve all theme modifications.
  1141. *
  1142. * @since 3.1.0
  1143. *
  1144. * @return array Theme modifications.
  1145. */
  1146. function get_theme_mods() {
  1147. $theme_slug = get_option( 'stylesheet' );
  1148. if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
  1149. $theme_name = get_current_theme();
  1150. $mods = get_option( "mods_$theme_name" ); // Deprecated location.
  1151. if ( is_admin() && false !== $mods ) {
  1152. update_option( "theme_mods_$theme_slug", $mods );
  1153. delete_option( "mods_$theme_name" );
  1154. }
  1155. }
  1156. return $mods;
  1157. }
  1158. /**
  1159. * Retrieve theme modification value for the current theme.
  1160. *
  1161. * If the modification name does not exist, then the $default will be passed
  1162. * through {@link http://php.net/sprintf sprintf()} PHP function with the first
  1163. * string the template directory URI and the second string the stylesheet
  1164. * directory URI.
  1165. *
  1166. * @since 2.1.0
  1167. * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
  1168. *
  1169. * @param string $name Theme modification name.
  1170. * @param bool|string $default
  1171. * @return string
  1172. */
  1173. function get_theme_mod( $name, $default = false ) {
  1174. $mods = get_theme_mods();
  1175. if ( isset( $mods[ $name ] ) )
  1176. return apply_filters( "theme_mod_$name", $mods[ $name ] );
  1177. return apply_filters( "theme_mod_$name", sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() ) );
  1178. }
  1179. /**
  1180. * Update theme modification value for the current theme.
  1181. *
  1182. * @since 2.1.0
  1183. *
  1184. * @param string $name Theme modification name.
  1185. * @param string $value theme modification value.
  1186. */
  1187. function set_theme_mod( $name, $value ) {
  1188. $mods = get_theme_mods();
  1189. $mods[ $name ] = $value;
  1190. $theme = get_option( 'stylesheet' );
  1191. update_option( "theme_mods_$theme", $mods );
  1192. }
  1193. /**
  1194. * Remove theme modification name from current theme list.
  1195. *
  1196. * If removing the name also removes all elements, then the entire option will
  1197. * be removed.
  1198. *
  1199. * @since 2.1.0
  1200. *
  1201. * @param string $name Theme modification name.
  1202. * @return null
  1203. */
  1204. function remove_theme_mod( $name ) {
  1205. $mods = get_theme_mods();
  1206. if ( ! isset( $mods[ $name ] ) )
  1207. return;
  1208. unset( $mods[ $name ] );
  1209. if ( empty( $mods ) )
  1210. return remove_theme_mods();
  1211. $theme = get_option( 'stylesheet' );
  1212. update_option( "theme_mods_$theme", $mods );
  1213. }
  1214. /**
  1215. * Remove theme modifications option for current theme.
  1216. *
  1217. * @since 2.1.0
  1218. */
  1219. function remove_theme_mods() {
  1220. delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
  1221. delete_option( 'mods_' . get_current_theme() );
  1222. }
  1223. /**
  1224. * Retrieve text color for custom header.
  1225. *
  1226. * @since 2.1.0
  1227. * @uses HEADER_TEXTCOLOR
  1228. *
  1229. * @return string
  1230. */
  1231. function get_header_textcolor() {
  1232. $default = defined('HEADER_TEXTCOLOR') ? HEADER_TEXTCOLOR : '';
  1233. return get_theme_mod('header_textcolor', $default);
  1234. }
  1235. /**
  1236. * Display text color for custom header.
  1237. *
  1238. * @since 2.1.0
  1239. */
  1240. function header_textcolor() {
  1241. echo get_header_textcolor();
  1242. }
  1243. /**
  1244. * Retrieve header image for custom header.
  1245. *
  1246. * @since 2.1.0
  1247. * @uses HEADER_IMAGE
  1248. *
  1249. * @return string
  1250. */
  1251. function get_header_image() {
  1252. $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
  1253. $url = get_theme_mod( 'header_image', $default );
  1254. if ( 'remove-header' == $url )
  1255. return false;
  1256. if ( is_random_header_image() )
  1257. $url = get_random_header_image();
  1258. if ( is_ssl() )
  1259. $url = str_replace( 'http://', 'https://', $url );
  1260. else
  1261. $url = str_replace( 'https://', 'http://', $url );
  1262. return esc_url_raw( $url );
  1263. }
  1264. /**
  1265. * Get random header image from registered images in theme.
  1266. *
  1267. * @since 3.2.0
  1268. *
  1269. * @return string Path to header image
  1270. */
  1271. function get_random_header_image() {
  1272. global $_wp_default_headers;
  1273. $header_image_mod = get_theme_mod( 'header_image', '' );
  1274. $headers = array();
  1275. if ( 'random-uploaded-image' == $header_image_mod )
  1276. $headers = get_uploaded_header_images();
  1277. elseif ( ! empty( $_wp_default_headers ) ) {
  1278. if ( 'random-default-image' == $header_image_mod ) {
  1279. $headers = $_wp_default_headers;
  1280. } else {
  1281. $is_random = get_theme_support( 'custom-header' );
  1282. if ( isset( $is_random[ 0 ] ) && !empty( $is_random[ 0 ][ 'random-default' ] ) )
  1283. $headers = $_wp_default_headers;
  1284. }
  1285. }
  1286. if ( empty( $headers ) )
  1287. return '';
  1288. $random_image = array_rand( $headers );
  1289. $header_url = sprintf( $headers[$random_image]['url'], get_template_directory_uri(), get_stylesheet_directory_uri() );
  1290. return $header_url;
  1291. }
  1292. /**
  1293. * Check if random header image is in use.
  1294. *
  1295. * Always true if user expressly chooses the option in Appearance > Header.
  1296. * Also true if theme has multiple header images registered, no specific header image
  1297. * is chosen, and theme turns on random headers with add_theme_support().
  1298. *
  1299. * @since 3.2.0
  1300. * @uses HEADER_IMAGE
  1301. *
  1302. * @param string $type The random pool to use. any|default|uploaded
  1303. * @return boolean
  1304. */
  1305. function is_random_header_image( $type = 'any' ) {
  1306. $default = defined( 'HEADER_IMAGE' ) ? HEADER_IMAGE : '';
  1307. $header_image_mod = get_theme_mod( 'header_image', $default );
  1308. if ( 'any' == $type ) {
  1309. if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
  1310. return true;
  1311. } else {
  1312. if ( "random-$type-image" == $header_image_mod )
  1313. return true;
  1314. elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
  1315. return true;
  1316. }
  1317. return false;
  1318. }
  1319. /**
  1320. * Display header image path.
  1321. *
  1322. * @since 2.1.0
  1323. */
  1324. function header_image() {
  1325. echo get_header_image();
  1326. }
  1327. /**
  1328. * Get the header images uploaded for the current theme.
  1329. *
  1330. * @since 3.2.0
  1331. *
  1332. * @return array
  1333. */
  1334. function get_uploaded_header_images() {
  1335. $header_images = array();
  1336. // @todo caching
  1337. $headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
  1338. if ( empty( $headers ) )
  1339. return array();
  1340. foreach ( (array) $headers as $header ) {
  1341. $url = esc_url_raw( $header->guid );
  1342. $header = basename($url);
  1343. $header_images[$header] = array();
  1344. $header_images[$header]['url'] = $url;
  1345. $header_images[$header]['thumbnail_url'] = $url;
  1346. $header_images[$header]['uploaded'] = true;
  1347. }
  1348. return $header_images;
  1349. }
  1350. /**
  1351. * Add callbacks for image header display.
  1352. *
  1353. * The parameter $header_callback callback will be required to display the
  1354. * content for the 'wp_head' action. The parameter $admin_header_callback
  1355. * callback will be added to Custom_Image_Header class and that will be added
  1356. * to the 'admin_menu' action.
  1357. *
  1358. * @since 2.1.0
  1359. * @uses Custom_Image_Header Sets up for $admin_header_callback for administration panel display.
  1360. *
  1361. * @param callback $header_callback Call on 'wp_head' action.
  1362. * @param callback $admin_header_callback Call on custom header administration screen.
  1363. * @param callback $admin_image_div_callback Output a custom header image div on the custom header administration screen. Optional.
  1364. */
  1365. function add_custom_image_header( $header_callback, $admin_header_callback, $admin_image_div_callback = '' ) {
  1366. if ( ! empty( $header_callback ) )
  1367. add_action('wp_head', $header_callback);
  1368. $support = array( 'callback' => $header_callback );
  1369. $theme_support = get_theme_support( 'custom-header' );
  1370. if ( ! empty( $theme_support ) && is_array( $theme_support[ 0 ] ) )
  1371. $support = array_merge( $theme_support[ 0 ], $support );
  1372. add_theme_support( 'custom-header', $support );
  1373. add_theme_support( 'custom-header-uploads' );
  1374. if ( ! is_admin() )
  1375. return;
  1376. global $custom_image_header;
  1377. require_once( ABSPATH . 'wp-admin/custom-header.php' );
  1378. $custom_image_header = new Custom_Image_Header( $admin_header_callback, $admin_image_div_callback );
  1379. add_action( 'admin_menu', array( &$custom_image_header, 'init' ) );
  1380. }
  1381. /**
  1382. * Remove image header support.
  1383. *
  1384. * @since 3.1.0
  1385. * @see add_custom_image_header()
  1386. *
  1387. * @return bool Whether support was removed.
  1388. */
  1389. function remove_custom_image_header() {
  1390. if ( ! current_theme_supports( 'custom-header' ) )
  1391. return false;
  1392. $callback = get_theme_support( 'custom-header' );
  1393. remove_action( 'wp_head', $callback[0]['callback'] );
  1394. _remove_theme_support( 'custom-header' );
  1395. remove_theme_support( 'custom-header-uploads' );
  1396. if ( is_admin() ) {
  1397. remove_action( 'admin_menu', array( &$GLOBALS['custom_image_header'], 'init' ) );
  1398. unset( $GLOBALS['custom_image_header'] );
  1399. }
  1400. return true;
  1401. }
  1402. /**
  1403. * Register a selection of default headers to be displayed by the custom header admin UI.
  1404. *
  1405. * @since 3.0.0
  1406. *
  1407. * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
  1408. */
  1409. function register_default_headers( $headers ) {
  1410. global $_wp_default_headers;
  1411. $_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
  1412. }
  1413. /**
  1414. * Unregister default headers.
  1415. *
  1416. * This function must be called after register_default_headers() has already added the
  1417. * header you want to remove.
  1418. *
  1419. * @see register_default_headers()
  1420. * @since 3.0.0
  1421. *
  1422. * @param string|array $header The header string id (key of array) to remove, or an array thereof.
  1423. * @return True on success, false on failure.
  1424. */
  1425. function unregister_default_headers( $header ) {
  1426. global $_wp_default_headers;
  1427. if ( is_array( $header ) ) {
  1428. array_map( 'unregister_default_headers', $header );
  1429. } elseif ( isset( $_wp_default_headers[ $header ] ) ) {
  1430. unset( $_wp_default_headers[ $header ] );
  1431. return true;
  1432. } else {
  1433. return false;
  1434. }
  1435. }
  1436. /**
  1437. * Retrieve background image for custom background.
  1438. *
  1439. * @since 3.0.0
  1440. *
  1441. * @return string
  1442. */
  1443. function get_background_image() {
  1444. $default = defined('BACKGROUND_IMAGE') ? BACKGROUND_IMAGE : '';
  1445. return get_theme_mod('background_image', $default);
  1446. }
  1447. /**
  1448. * Display background image path.
  1449. *
  1450. * @since 3.0.0
  1451. */
  1452. function background_image() {
  1453. echo get_background_image();
  1454. }
  1455. /**
  1456. * Retrieve value for custom background color.
  1457. *
  1458. * @since 3.0.0
  1459. * @uses BACKGROUND_COLOR
  1460. *
  1461. * @return string
  1462. */
  1463. function get_background_color() {
  1464. $default = defined('BACKGROUND_COLOR') ? BACKGROUND_COLOR : '';
  1465. return get_theme_mod('background_color', $default);
  1466. }
  1467. /**
  1468. * Display background color value.
  1469. *
  1470. * @since 3.0.0
  1471. */
  1472. function background_color() {
  1473. echo get_background_color();
  1474. }
  1475. /**
  1476. * Add callbacks for background image display.
  1477. *
  1478. * The parameter $header_callback callback will be required to display the
  1479. * content for the 'wp_head' action. The parameter $admin_header_callback
  1480. * callback will be added to Custom_Background class and that will be added
  1481. * to the 'admin_menu' action.
  1482. *
  1483. * @since 3.0.0
  1484. * @uses Custom_Background Sets up for $admin_header_callback for administration panel display.
  1485. *
  1486. * @param callback $header_callback Call on 'wp_head' action.
  1487. * @param callback $admin_header_callback Call on custom background administration screen.
  1488. * @param callback $admin_image_div_callback Output a custom background image div on the custom background administration screen. Optional.
  1489. */
  1490. function add_custom_background( $header_callback = '', $admin_header_cal

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