PageRenderTime 57ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/theme.php

https://bitbucket.org/julianelve/vendor-wordpress
PHP | 1724 lines | 894 code | 232 blank | 598 comment | 226 complexity | a8d5c539832c0ae661ca85f99d6dee38 MD5 | raw file
Possible License(s): AGPL-1.0, LGPL-2.1, GPL-2.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 Theme
  7. */
  8. /**
  9. * Returns an array of WP_Theme objects based on the arguments.
  10. *
  11. * Despite advances over get_themes(), this function is quite expensive, and grows
  12. * linearly with additional themes. Stick to wp_get_theme() if possible.
  13. *
  14. * @since 3.4.0
  15. *
  16. * @param array $args The search arguments. Optional.
  17. * - errors mixed True to return themes with errors, false to return themes without errors, null
  18. * to return all themes. Defaults to false.
  19. * - allowed mixed (Multisite) True to return only allowed themes for a site. False to return only
  20. * disallowed themes for a site. 'site' to return only site-allowed themes. 'network'
  21. * to return only network-allowed themes. Null to return all themes. Defaults to null.
  22. * - blog_id int (Multisite) The blog ID used to calculate which themes are allowed. Defaults to 0,
  23. * synonymous for the current blog.
  24. * @return Array of WP_Theme objects.
  25. */
  26. function wp_get_themes( $args = array() ) {
  27. global $wp_theme_directories;
  28. $defaults = array( 'errors' => false, 'allowed' => null, 'blog_id' => 0 );
  29. $args = wp_parse_args( $args, $defaults );
  30. $theme_directories = search_theme_directories();
  31. if ( count( $wp_theme_directories ) > 1 ) {
  32. // Make sure the current theme wins out, in case search_theme_directories() picks the wrong
  33. // one in the case of a conflict. (Normally, last registered theme root wins.)
  34. $current_theme = get_stylesheet();
  35. if ( isset( $theme_directories[ $current_theme ] ) ) {
  36. $root_of_current_theme = get_raw_theme_root( $current_theme );
  37. if ( ! in_array( $root_of_current_theme, $wp_theme_directories ) )
  38. $root_of_current_theme = WP_CONTENT_DIR . $root_of_current_theme;
  39. $theme_directories[ $current_theme ]['theme_root'] = $root_of_current_theme;
  40. }
  41. }
  42. if ( empty( $theme_directories ) )
  43. return array();
  44. if ( is_multisite() && null !== $args['allowed'] ) {
  45. $allowed = $args['allowed'];
  46. if ( 'network' === $allowed )
  47. $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_network() );
  48. elseif ( 'site' === $allowed )
  49. $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed_on_site( $args['blog_id'] ) );
  50. elseif ( $allowed )
  51. $theme_directories = array_intersect_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
  52. else
  53. $theme_directories = array_diff_key( $theme_directories, WP_Theme::get_allowed( $args['blog_id'] ) );
  54. }
  55. $themes = array();
  56. static $_themes = array();
  57. foreach ( $theme_directories as $theme => $theme_root ) {
  58. if ( isset( $_themes[ $theme_root['theme_root'] . '/' . $theme ] ) )
  59. $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ];
  60. else
  61. $themes[ $theme ] = $_themes[ $theme_root['theme_root'] . '/' . $theme ] = new WP_Theme( $theme, $theme_root['theme_root'] );
  62. }
  63. if ( null !== $args['errors'] ) {
  64. foreach ( $themes as $theme => $wp_theme ) {
  65. if ( $wp_theme->errors() != $args['errors'] )
  66. unset( $themes[ $theme ] );
  67. }
  68. }
  69. return $themes;
  70. }
  71. /**
  72. * Gets a WP_Theme object for a theme.
  73. *
  74. * @since 3.4.0
  75. *
  76. * @param string $stylesheet Directory name for the theme. Optional. Defaults to current theme.
  77. * @param string $theme_root Absolute path of the theme root to look in. Optional. If not specified, get_raw_theme_root()
  78. * is used to calculate the theme root for the $stylesheet provided (or current theme).
  79. * @return WP_Theme Theme object. Be sure to check the object's exists() method if you need to confirm the theme's existence.
  80. */
  81. function wp_get_theme( $stylesheet = null, $theme_root = null ) {
  82. global $wp_theme_directories;
  83. if ( empty( $stylesheet ) )
  84. $stylesheet = get_stylesheet();
  85. if ( empty( $theme_root ) ) {
  86. $theme_root = get_raw_theme_root( $stylesheet );
  87. if ( false === $theme_root )
  88. $theme_root = WP_CONTENT_DIR . '/themes';
  89. elseif ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
  90. $theme_root = WP_CONTENT_DIR . $theme_root;
  91. }
  92. return new WP_Theme( $stylesheet, $theme_root );
  93. }
  94. /**
  95. * Clears the cache held by get_theme_roots() and WP_Theme.
  96. *
  97. * @since 3.5.0
  98. */
  99. function wp_clean_themes_cache() {
  100. delete_site_transient('update_themes');
  101. search_theme_directories( true );
  102. foreach ( wp_get_themes( array( 'errors' => null ) ) as $theme )
  103. $theme->cache_delete();
  104. }
  105. /**
  106. * Whether a child theme is in use.
  107. *
  108. * @since 3.0.0
  109. *
  110. * @return bool true if a child theme is in use, false otherwise.
  111. **/
  112. function is_child_theme() {
  113. return ( TEMPLATEPATH !== STYLESHEETPATH );
  114. }
  115. /**
  116. * Retrieve name of the current stylesheet.
  117. *
  118. * The theme name that the administrator has currently set the front end theme
  119. * as.
  120. *
  121. * For all extensive purposes, the template name and the stylesheet name are
  122. * going to be the same for most cases.
  123. *
  124. * @since 1.5.0
  125. * @uses apply_filters() Calls 'stylesheet' filter on stylesheet name.
  126. *
  127. * @return string Stylesheet name.
  128. */
  129. function get_stylesheet() {
  130. return apply_filters('stylesheet', get_option('stylesheet'));
  131. }
  132. /**
  133. * Retrieve stylesheet directory path for current theme.
  134. *
  135. * @since 1.5.0
  136. * @uses apply_filters() Calls 'stylesheet_directory' filter on stylesheet directory and theme name.
  137. *
  138. * @return string Path to current theme directory.
  139. */
  140. function get_stylesheet_directory() {
  141. $stylesheet = get_stylesheet();
  142. $theme_root = get_theme_root( $stylesheet );
  143. $stylesheet_dir = "$theme_root/$stylesheet";
  144. return apply_filters( 'stylesheet_directory', $stylesheet_dir, $stylesheet, $theme_root );
  145. }
  146. /**
  147. * Retrieve stylesheet directory URI.
  148. *
  149. * @since 1.5.0
  150. *
  151. * @return string
  152. */
  153. function get_stylesheet_directory_uri() {
  154. $stylesheet = get_stylesheet();
  155. $theme_root_uri = get_theme_root_uri( $stylesheet );
  156. $stylesheet_dir_uri = "$theme_root_uri/$stylesheet";
  157. return apply_filters( 'stylesheet_directory_uri', $stylesheet_dir_uri, $stylesheet, $theme_root_uri );
  158. }
  159. /**
  160. * Retrieve URI of current theme stylesheet.
  161. *
  162. * The stylesheet file name is 'style.css' which is appended to {@link
  163. * get_stylesheet_directory_uri() stylesheet directory URI} path.
  164. *
  165. * @since 1.5.0
  166. * @uses apply_filters() Calls 'stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
  167. *
  168. * @return string
  169. */
  170. function get_stylesheet_uri() {
  171. $stylesheet_dir_uri = get_stylesheet_directory_uri();
  172. $stylesheet_uri = $stylesheet_dir_uri . '/style.css';
  173. return apply_filters('stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
  174. }
  175. /**
  176. * Retrieve localized stylesheet URI.
  177. *
  178. * The stylesheet directory for the localized stylesheet files are located, by
  179. * default, in the base theme directory. The name of the locale file will be the
  180. * locale followed by '.css'. If that does not exist, then the text direction
  181. * stylesheet will be checked for existence, for example 'ltr.css'.
  182. *
  183. * The theme may change the location of the stylesheet directory by either using
  184. * the 'stylesheet_directory_uri' filter or the 'locale_stylesheet_uri' filter.
  185. * If you want to change the location of the stylesheet files for the entire
  186. * WordPress workflow, then change the former. If you just have the locale in a
  187. * separate folder, then change the latter.
  188. *
  189. * @since 2.1.0
  190. * @uses apply_filters() Calls 'locale_stylesheet_uri' filter on stylesheet URI path and stylesheet directory URI.
  191. *
  192. * @return string
  193. */
  194. function get_locale_stylesheet_uri() {
  195. global $wp_locale;
  196. $stylesheet_dir_uri = get_stylesheet_directory_uri();
  197. $dir = get_stylesheet_directory();
  198. $locale = get_locale();
  199. if ( file_exists("$dir/$locale.css") )
  200. $stylesheet_uri = "$stylesheet_dir_uri/$locale.css";
  201. elseif ( !empty($wp_locale->text_direction) && file_exists("$dir/{$wp_locale->text_direction}.css") )
  202. $stylesheet_uri = "$stylesheet_dir_uri/{$wp_locale->text_direction}.css";
  203. else
  204. $stylesheet_uri = '';
  205. return apply_filters('locale_stylesheet_uri', $stylesheet_uri, $stylesheet_dir_uri);
  206. }
  207. /**
  208. * Retrieve name of the current theme.
  209. *
  210. * @since 1.5.0
  211. * @uses apply_filters() Calls 'template' filter on template option.
  212. *
  213. * @return string Template name.
  214. */
  215. function get_template() {
  216. return apply_filters('template', get_option('template'));
  217. }
  218. /**
  219. * Retrieve current theme directory.
  220. *
  221. * @since 1.5.0
  222. * @uses apply_filters() Calls 'template_directory' filter on template directory path and template name.
  223. *
  224. * @return string Template directory path.
  225. */
  226. function get_template_directory() {
  227. $template = get_template();
  228. $theme_root = get_theme_root( $template );
  229. $template_dir = "$theme_root/$template";
  230. return apply_filters( 'template_directory', $template_dir, $template, $theme_root );
  231. }
  232. /**
  233. * Retrieve theme directory URI.
  234. *
  235. * @since 1.5.0
  236. * @uses apply_filters() Calls 'template_directory_uri' filter on template directory URI path and template name.
  237. *
  238. * @return string Template directory URI.
  239. */
  240. function get_template_directory_uri() {
  241. $template = get_template();
  242. $theme_root_uri = get_theme_root_uri( $template );
  243. $template_dir_uri = "$theme_root_uri/$template";
  244. return apply_filters( 'template_directory_uri', $template_dir_uri, $template, $theme_root_uri );
  245. }
  246. /**
  247. * Retrieve theme roots.
  248. *
  249. * @since 2.9.0
  250. *
  251. * @return array|string An array of theme roots keyed by template/stylesheet or a single theme root if all themes have the same root.
  252. */
  253. function get_theme_roots() {
  254. global $wp_theme_directories;
  255. if ( count($wp_theme_directories) <= 1 )
  256. return '/themes';
  257. $theme_roots = get_site_transient( 'theme_roots' );
  258. if ( false === $theme_roots ) {
  259. search_theme_directories( true ); // Regenerate the transient.
  260. $theme_roots = get_site_transient( 'theme_roots' );
  261. }
  262. return $theme_roots;
  263. }
  264. /**
  265. * Register a directory that contains themes.
  266. *
  267. * @since 2.9.0
  268. *
  269. * @param string $directory Either the full filesystem path to a theme folder or a folder within WP_CONTENT_DIR
  270. * @return bool
  271. */
  272. function register_theme_directory( $directory ) {
  273. global $wp_theme_directories;
  274. if ( ! file_exists( $directory ) ) {
  275. // Try prepending as the theme directory could be relative to the content directory
  276. $directory = WP_CONTENT_DIR . '/' . $directory;
  277. // If this directory does not exist, return and do not register
  278. if ( ! file_exists( $directory ) )
  279. return false;
  280. }
  281. $wp_theme_directories[] = $directory;
  282. return true;
  283. }
  284. /**
  285. * Search all registered theme directories for complete and valid themes.
  286. *
  287. * @since 2.9.0
  288. *
  289. * @param bool $force Optional. Whether to force a new directory scan. Defaults to false.
  290. * @return array Valid themes found
  291. */
  292. function search_theme_directories( $force = false ) {
  293. global $wp_theme_directories;
  294. if ( empty( $wp_theme_directories ) )
  295. return false;
  296. static $found_themes;
  297. if ( ! $force && isset( $found_themes ) )
  298. return $found_themes;
  299. $found_themes = array();
  300. $wp_theme_directories = (array) $wp_theme_directories;
  301. // Set up maybe-relative, maybe-absolute array of theme directories.
  302. // We always want to return absolute, but we need to cache relative
  303. // use in for get_theme_root().
  304. foreach ( $wp_theme_directories as $theme_root ) {
  305. if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
  306. $relative_theme_roots[ str_replace( WP_CONTENT_DIR, '', $theme_root ) ] = $theme_root;
  307. else
  308. $relative_theme_roots[ $theme_root ] = $theme_root;
  309. }
  310. if ( $cache_expiration = apply_filters( 'wp_cache_themes_persistently', false, 'search_theme_directories' ) ) {
  311. $cached_roots = get_site_transient( 'theme_roots' );
  312. if ( is_array( $cached_roots ) ) {
  313. foreach ( $cached_roots as $theme_dir => $theme_root ) {
  314. // A cached theme root is no longer around, so skip it.
  315. if ( ! isset( $relative_theme_roots[ $theme_root ] ) )
  316. continue;
  317. $found_themes[ $theme_dir ] = array(
  318. 'theme_file' => $theme_dir . '/style.css',
  319. 'theme_root' => $relative_theme_roots[ $theme_root ], // Convert relative to absolute.
  320. );
  321. }
  322. return $found_themes;
  323. }
  324. if ( ! is_int( $cache_expiration ) )
  325. $cache_expiration = 1800; // half hour
  326. } else {
  327. $cache_expiration = 1800; // half hour
  328. }
  329. /* Loop the registered theme directories and extract all themes */
  330. foreach ( $wp_theme_directories as $theme_root ) {
  331. // Start with directories in the root of the current theme directory.
  332. $dirs = @ scandir( $theme_root );
  333. if ( ! $dirs )
  334. return false;
  335. foreach ( $dirs as $dir ) {
  336. if ( ! is_dir( $theme_root . '/' . $dir ) || $dir[0] == '.' || $dir == 'CVS' )
  337. continue;
  338. if ( file_exists( $theme_root . '/' . $dir . '/style.css' ) ) {
  339. // wp-content/themes/a-single-theme
  340. // wp-content/themes is $theme_root, a-single-theme is $dir
  341. $found_themes[ $dir ] = array(
  342. 'theme_file' => $dir . '/style.css',
  343. 'theme_root' => $theme_root,
  344. );
  345. } else {
  346. $found_theme = false;
  347. // wp-content/themes/a-folder-of-themes/*
  348. // wp-content/themes is $theme_root, a-folder-of-themes is $dir, then themes are $sub_dirs
  349. $sub_dirs = @ scandir( $theme_root . '/' . $dir );
  350. if ( ! $sub_dirs )
  351. return false;
  352. foreach ( $sub_dirs as $sub_dir ) {
  353. if ( ! is_dir( $theme_root . '/' . $dir . '/' . $sub_dir ) || $dir[0] == '.' || $dir == 'CVS' )
  354. continue;
  355. if ( ! file_exists( $theme_root . '/' . $dir . '/' . $sub_dir . '/style.css' ) )
  356. continue;
  357. $found_themes[ $dir . '/' . $sub_dir ] = array(
  358. 'theme_file' => $dir . '/' . $sub_dir . '/style.css',
  359. 'theme_root' => $theme_root,
  360. );
  361. $found_theme = true;
  362. }
  363. // Never mind the above, it's just a theme missing a style.css.
  364. // Return it; WP_Theme will catch the error.
  365. if ( ! $found_theme )
  366. $found_themes[ $dir ] = array(
  367. 'theme_file' => $dir . '/style.css',
  368. 'theme_root' => $theme_root,
  369. );
  370. }
  371. }
  372. }
  373. asort( $found_themes );
  374. $theme_roots = array();
  375. $relative_theme_roots = array_flip( $relative_theme_roots );
  376. foreach ( $found_themes as $theme_dir => $theme_data ) {
  377. $theme_roots[ $theme_dir ] = $relative_theme_roots[ $theme_data['theme_root'] ]; // Convert absolute to relative.
  378. }
  379. if ( $theme_roots != get_site_transient( 'theme_roots' ) )
  380. set_site_transient( 'theme_roots', $theme_roots, $cache_expiration );
  381. return $found_themes;
  382. }
  383. /**
  384. * Retrieve path to themes directory.
  385. *
  386. * Does not have trailing slash.
  387. *
  388. * @since 1.5.0
  389. * @uses apply_filters() Calls 'theme_root' filter on path.
  390. *
  391. * @param string $stylesheet_or_template The stylesheet or template name of the theme
  392. * @return string Theme path.
  393. */
  394. function get_theme_root( $stylesheet_or_template = false ) {
  395. global $wp_theme_directories;
  396. if ( $stylesheet_or_template && $theme_root = get_raw_theme_root( $stylesheet_or_template ) ) {
  397. // Always prepend WP_CONTENT_DIR unless the root currently registered as a theme directory.
  398. // This gives relative theme roots the benefit of the doubt when things go haywire.
  399. if ( ! in_array( $theme_root, (array) $wp_theme_directories ) )
  400. $theme_root = WP_CONTENT_DIR . $theme_root;
  401. } else {
  402. $theme_root = WP_CONTENT_DIR . '/themes';
  403. }
  404. return apply_filters( 'theme_root', $theme_root );
  405. }
  406. /**
  407. * Retrieve URI for themes directory.
  408. *
  409. * Does not have trailing slash.
  410. *
  411. * @since 1.5.0
  412. *
  413. * @param string $stylesheet_or_template Optional. The stylesheet or template name of the theme.
  414. * Default is to leverage the main theme root.
  415. * @param string $theme_root Optional. The theme root for which calculations will be based, preventing
  416. * the need for a get_raw_theme_root() call.
  417. * @return string Themes URI.
  418. */
  419. function get_theme_root_uri( $stylesheet_or_template = false, $theme_root = false ) {
  420. global $wp_theme_directories;
  421. if ( $stylesheet_or_template && ! $theme_root )
  422. $theme_root = get_raw_theme_root( $stylesheet_or_template );
  423. if ( $stylesheet_or_template && $theme_root ) {
  424. if ( in_array( $theme_root, (array) $wp_theme_directories ) ) {
  425. // Absolute path. Make an educated guess. YMMV -- but note the filter below.
  426. if ( 0 === strpos( $theme_root, WP_CONTENT_DIR ) )
  427. $theme_root_uri = content_url( str_replace( WP_CONTENT_DIR, '', $theme_root ) );
  428. elseif ( 0 === strpos( $theme_root, ABSPATH ) )
  429. $theme_root_uri = site_url( str_replace( ABSPATH, '', $theme_root ) );
  430. elseif ( 0 === strpos( $theme_root, WP_PLUGIN_DIR ) || 0 === strpos( $theme_root, WPMU_PLUGIN_DIR ) )
  431. $theme_root_uri = plugins_url( basename( $theme_root ), $theme_root );
  432. else
  433. $theme_root_uri = $theme_root;
  434. } else {
  435. $theme_root_uri = content_url( $theme_root );
  436. }
  437. } else {
  438. $theme_root_uri = content_url( 'themes' );
  439. }
  440. return apply_filters( 'theme_root_uri', $theme_root_uri, get_option('siteurl'), $stylesheet_or_template );
  441. }
  442. /**
  443. * Get the raw theme root relative to the content directory with no filters applied.
  444. *
  445. * @since 3.1.0
  446. *
  447. * @param string $stylesheet_or_template The stylesheet or template name of the theme
  448. * @param bool $skip_cache Optional. Whether to skip the cache. Defaults to false, meaning the cache is used.
  449. * @return string Theme root
  450. */
  451. function get_raw_theme_root( $stylesheet_or_template, $skip_cache = false ) {
  452. global $wp_theme_directories;
  453. if ( count($wp_theme_directories) <= 1 )
  454. return '/themes';
  455. $theme_root = false;
  456. // If requesting the root for the current theme, consult options to avoid calling get_theme_roots()
  457. if ( ! $skip_cache ) {
  458. if ( get_option('stylesheet') == $stylesheet_or_template )
  459. $theme_root = get_option('stylesheet_root');
  460. elseif ( get_option('template') == $stylesheet_or_template )
  461. $theme_root = get_option('template_root');
  462. }
  463. if ( empty($theme_root) ) {
  464. $theme_roots = get_theme_roots();
  465. if ( !empty($theme_roots[$stylesheet_or_template]) )
  466. $theme_root = $theme_roots[$stylesheet_or_template];
  467. }
  468. return $theme_root;
  469. }
  470. /**
  471. * Display localized stylesheet link element.
  472. *
  473. * @since 2.1.0
  474. */
  475. function locale_stylesheet() {
  476. $stylesheet = get_locale_stylesheet_uri();
  477. if ( empty($stylesheet) )
  478. return;
  479. echo '<link rel="stylesheet" href="' . $stylesheet . '" type="text/css" media="screen" />';
  480. }
  481. /**
  482. * Start preview theme output buffer.
  483. *
  484. * Will only preform task if the user has permissions and template and preview
  485. * query variables exist.
  486. *
  487. * @since 2.6.0
  488. */
  489. function preview_theme() {
  490. if ( ! (isset($_GET['template']) && isset($_GET['preview'])) )
  491. return;
  492. if ( !current_user_can( 'switch_themes' ) )
  493. return;
  494. // Admin Thickbox requests
  495. if ( isset( $_GET['preview_iframe'] ) )
  496. show_admin_bar( false );
  497. $_GET['template'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['template']);
  498. if ( validate_file($_GET['template']) )
  499. return;
  500. add_filter( 'template', '_preview_theme_template_filter' );
  501. if ( isset($_GET['stylesheet']) ) {
  502. $_GET['stylesheet'] = preg_replace('|[^a-z0-9_./-]|i', '', $_GET['stylesheet']);
  503. if ( validate_file($_GET['stylesheet']) )
  504. return;
  505. add_filter( 'stylesheet', '_preview_theme_stylesheet_filter' );
  506. }
  507. // Prevent theme mods to current theme being used on theme being previewed
  508. add_filter( 'pre_option_theme_mods_' . get_option( 'stylesheet' ), '__return_empty_array' );
  509. ob_start( 'preview_theme_ob_filter' );
  510. }
  511. add_action('setup_theme', 'preview_theme');
  512. /**
  513. * Private function to modify the current template when previewing a theme
  514. *
  515. * @since 2.9.0
  516. * @access private
  517. *
  518. * @return string
  519. */
  520. function _preview_theme_template_filter() {
  521. return isset($_GET['template']) ? $_GET['template'] : '';
  522. }
  523. /**
  524. * Private function to modify the current stylesheet when previewing a theme
  525. *
  526. * @since 2.9.0
  527. * @access private
  528. *
  529. * @return string
  530. */
  531. function _preview_theme_stylesheet_filter() {
  532. return isset($_GET['stylesheet']) ? $_GET['stylesheet'] : '';
  533. }
  534. /**
  535. * Callback function for ob_start() to capture all links in the theme.
  536. *
  537. * @since 2.6.0
  538. * @access private
  539. *
  540. * @param string $content
  541. * @return string
  542. */
  543. function preview_theme_ob_filter( $content ) {
  544. return preg_replace_callback( "|(<a.*?href=([\"']))(.*?)([\"'].*?>)|", 'preview_theme_ob_filter_callback', $content );
  545. }
  546. /**
  547. * Manipulates preview theme links in order to control and maintain location.
  548. *
  549. * Callback function for preg_replace_callback() to accept and filter matches.
  550. *
  551. * @since 2.6.0
  552. * @access private
  553. *
  554. * @param array $matches
  555. * @return string
  556. */
  557. function preview_theme_ob_filter_callback( $matches ) {
  558. if ( strpos($matches[4], 'onclick') !== false )
  559. $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.
  560. if (
  561. ( false !== strpos($matches[3], '/wp-admin/') )
  562. ||
  563. ( false !== strpos( $matches[3], '://' ) && 0 !== strpos( $matches[3], home_url() ) )
  564. ||
  565. ( false !== strpos($matches[3], '/feed/') )
  566. ||
  567. ( false !== strpos($matches[3], '/trackback/') )
  568. )
  569. return $matches[1] . "#$matches[2] onclick=$matches[2]return false;" . $matches[4];
  570. $link = add_query_arg( array( 'preview' => 1, 'template' => $_GET['template'], 'stylesheet' => @$_GET['stylesheet'], 'preview_iframe' => 1 ), $matches[3] );
  571. if ( 0 === strpos($link, 'preview=1') )
  572. $link = "?$link";
  573. return $matches[1] . esc_attr( $link ) . $matches[4];
  574. }
  575. /**
  576. * Switches the theme.
  577. *
  578. * Accepts one argument: $stylesheet of the theme. It also accepts an additional function signature
  579. * of two arguments: $template then $stylesheet. This is for backwards compatibility.
  580. *
  581. * @since 2.5.0
  582. * @uses do_action() Calls 'switch_theme' action, passing the new theme.
  583. *
  584. * @param string $stylesheet Stylesheet name
  585. */
  586. function switch_theme( $stylesheet ) {
  587. global $wp_theme_directories, $sidebars_widgets;
  588. if ( is_array( $sidebars_widgets ) )
  589. set_theme_mod( 'sidebars_widgets', array( 'time' => time(), 'data' => $sidebars_widgets ) );
  590. $old_theme = wp_get_theme();
  591. $new_theme = wp_get_theme( $stylesheet );
  592. if ( func_num_args() > 1 ) {
  593. $template = $stylesheet;
  594. $stylesheet = func_get_arg( 1 );
  595. } else {
  596. $template = $new_theme->get_template();
  597. }
  598. update_option( 'template', $template );
  599. update_option( 'stylesheet', $stylesheet );
  600. if ( count( $wp_theme_directories ) > 1 ) {
  601. update_option( 'template_root', get_raw_theme_root( $template, true ) );
  602. update_option( 'stylesheet_root', get_raw_theme_root( $stylesheet, true ) );
  603. } else {
  604. delete_option( 'template_root' );
  605. delete_option( 'stylesheet_root' );
  606. }
  607. $new_name = $new_theme->get('Name');
  608. update_option( 'current_theme', $new_name );
  609. if ( is_admin() && false === get_option( 'theme_mods_' . $stylesheet ) ) {
  610. $default_theme_mods = (array) get_option( 'mods_' . $new_name );
  611. add_option( "theme_mods_$stylesheet", $default_theme_mods );
  612. }
  613. update_option( 'theme_switched', $old_theme->get_stylesheet() );
  614. do_action( 'switch_theme', $new_name, $new_theme );
  615. }
  616. /**
  617. * Checks that current theme files 'index.php' and 'style.css' exists.
  618. *
  619. * Does not check the default theme, which is the fallback and should always exist.
  620. * Will switch theme to the fallback theme if current theme does not validate.
  621. * You can use the 'validate_current_theme' filter to return false to
  622. * disable this functionality.
  623. *
  624. * @since 1.5.0
  625. * @see WP_DEFAULT_THEME
  626. *
  627. * @return bool
  628. */
  629. function validate_current_theme() {
  630. // Don't validate during an install/upgrade.
  631. if ( defined('WP_INSTALLING') || !apply_filters( 'validate_current_theme', true ) )
  632. return true;
  633. if ( get_template() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/index.php') ) {
  634. switch_theme( WP_DEFAULT_THEME );
  635. return false;
  636. }
  637. if ( get_stylesheet() != WP_DEFAULT_THEME && !file_exists(get_template_directory() . '/style.css') ) {
  638. switch_theme( WP_DEFAULT_THEME );
  639. return false;
  640. }
  641. if ( is_child_theme() && ! file_exists( get_stylesheet_directory() . '/style.css' ) ) {
  642. switch_theme( WP_DEFAULT_THEME );
  643. return false;
  644. }
  645. return true;
  646. }
  647. /**
  648. * Retrieve all theme modifications.
  649. *
  650. * @since 3.1.0
  651. *
  652. * @return array Theme modifications.
  653. */
  654. function get_theme_mods() {
  655. $theme_slug = get_option( 'stylesheet' );
  656. if ( false === ( $mods = get_option( "theme_mods_$theme_slug" ) ) ) {
  657. $theme_name = get_option( 'current_theme' );
  658. if ( false === $theme_name )
  659. $theme_name = wp_get_theme()->get('Name');
  660. $mods = get_option( "mods_$theme_name" ); // Deprecated location.
  661. if ( is_admin() && false !== $mods ) {
  662. update_option( "theme_mods_$theme_slug", $mods );
  663. delete_option( "mods_$theme_name" );
  664. }
  665. }
  666. return $mods;
  667. }
  668. /**
  669. * Retrieve theme modification value for the current theme.
  670. *
  671. * If the modification name does not exist, then the $default will be passed
  672. * through {@link http://php.net/sprintf sprintf()} PHP function with the first
  673. * string the template directory URI and the second string the stylesheet
  674. * directory URI.
  675. *
  676. * @since 2.1.0
  677. * @uses apply_filters() Calls 'theme_mod_$name' filter on the value.
  678. *
  679. * @param string $name Theme modification name.
  680. * @param bool|string $default
  681. * @return string
  682. */
  683. function get_theme_mod( $name, $default = false ) {
  684. $mods = get_theme_mods();
  685. if ( isset( $mods[ $name ] ) )
  686. return apply_filters( "theme_mod_$name", $mods[ $name ] );
  687. if ( is_string( $default ) )
  688. $default = sprintf( $default, get_template_directory_uri(), get_stylesheet_directory_uri() );
  689. return apply_filters( "theme_mod_$name", $default );
  690. }
  691. /**
  692. * Update theme modification value for the current theme.
  693. *
  694. * @since 2.1.0
  695. *
  696. * @param string $name Theme modification name.
  697. * @param string $value theme modification value.
  698. */
  699. function set_theme_mod( $name, $value ) {
  700. $mods = get_theme_mods();
  701. $mods[ $name ] = $value;
  702. $theme = get_option( 'stylesheet' );
  703. update_option( "theme_mods_$theme", $mods );
  704. }
  705. /**
  706. * Remove theme modification name from current theme list.
  707. *
  708. * If removing the name also removes all elements, then the entire option will
  709. * be removed.
  710. *
  711. * @since 2.1.0
  712. *
  713. * @param string $name Theme modification name.
  714. * @return null
  715. */
  716. function remove_theme_mod( $name ) {
  717. $mods = get_theme_mods();
  718. if ( ! isset( $mods[ $name ] ) )
  719. return;
  720. unset( $mods[ $name ] );
  721. if ( empty( $mods ) )
  722. return remove_theme_mods();
  723. $theme = get_option( 'stylesheet' );
  724. update_option( "theme_mods_$theme", $mods );
  725. }
  726. /**
  727. * Remove theme modifications option for current theme.
  728. *
  729. * @since 2.1.0
  730. */
  731. function remove_theme_mods() {
  732. delete_option( 'theme_mods_' . get_option( 'stylesheet' ) );
  733. // Old style.
  734. $theme_name = get_option( 'current_theme' );
  735. if ( false === $theme_name )
  736. $theme_name = wp_get_theme()->get('Name');
  737. delete_option( 'mods_' . $theme_name );
  738. }
  739. /**
  740. * Retrieve text color for custom header.
  741. *
  742. * @since 2.1.0
  743. *
  744. * @return string
  745. */
  746. function get_header_textcolor() {
  747. return get_theme_mod('header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
  748. }
  749. /**
  750. * Display text color for custom header.
  751. *
  752. * @since 2.1.0
  753. */
  754. function header_textcolor() {
  755. echo get_header_textcolor();
  756. }
  757. /**
  758. * Whether to display the header text.
  759. *
  760. * @since 3.4.0
  761. *
  762. * @return bool
  763. */
  764. function display_header_text() {
  765. if ( ! current_theme_supports( 'custom-header', 'header-text' ) )
  766. return false;
  767. $text_color = get_theme_mod( 'header_textcolor', get_theme_support( 'custom-header', 'default-text-color' ) );
  768. return 'blank' != $text_color;
  769. }
  770. /**
  771. * Retrieve header image for custom header.
  772. *
  773. * @since 2.1.0
  774. *
  775. * @return string
  776. */
  777. function get_header_image() {
  778. $url = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  779. if ( 'remove-header' == $url )
  780. return false;
  781. if ( is_random_header_image() )
  782. $url = get_random_header_image();
  783. return esc_url_raw( set_url_scheme( $url ) );
  784. }
  785. /**
  786. * Get random header image data from registered images in theme.
  787. *
  788. * @since 3.4.0
  789. *
  790. * @access private
  791. *
  792. * @return string Path to header image
  793. */
  794. function _get_random_header_data() {
  795. static $_wp_random_header;
  796. if ( empty( $_wp_random_header ) ) {
  797. global $_wp_default_headers;
  798. $header_image_mod = get_theme_mod( 'header_image', '' );
  799. $headers = array();
  800. if ( 'random-uploaded-image' == $header_image_mod )
  801. $headers = get_uploaded_header_images();
  802. elseif ( ! empty( $_wp_default_headers ) ) {
  803. if ( 'random-default-image' == $header_image_mod ) {
  804. $headers = $_wp_default_headers;
  805. } else {
  806. if ( current_theme_supports( 'custom-header', 'random-default' ) )
  807. $headers = $_wp_default_headers;
  808. }
  809. }
  810. if ( empty( $headers ) )
  811. return new stdClass;
  812. $_wp_random_header = (object) $headers[ array_rand( $headers ) ];
  813. $_wp_random_header->url = sprintf( $_wp_random_header->url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  814. $_wp_random_header->thumbnail_url = sprintf( $_wp_random_header->thumbnail_url, get_template_directory_uri(), get_stylesheet_directory_uri() );
  815. }
  816. return $_wp_random_header;
  817. }
  818. /**
  819. * Get random header image url from registered images in theme.
  820. *
  821. * @since 3.2.0
  822. *
  823. * @return string Path to header image
  824. */
  825. function get_random_header_image() {
  826. $random_image = _get_random_header_data();
  827. if ( empty( $random_image->url ) )
  828. return '';
  829. return $random_image->url;
  830. }
  831. /**
  832. * Check if random header image is in use.
  833. *
  834. * Always true if user expressly chooses the option in Appearance > Header.
  835. * Also true if theme has multiple header images registered, no specific header image
  836. * is chosen, and theme turns on random headers with add_theme_support().
  837. *
  838. * @since 3.2.0
  839. *
  840. * @param string $type The random pool to use. any|default|uploaded
  841. * @return boolean
  842. */
  843. function is_random_header_image( $type = 'any' ) {
  844. $header_image_mod = get_theme_mod( 'header_image', get_theme_support( 'custom-header', 'default-image' ) );
  845. if ( 'any' == $type ) {
  846. if ( 'random-default-image' == $header_image_mod || 'random-uploaded-image' == $header_image_mod || ( '' != get_random_header_image() && empty( $header_image_mod ) ) )
  847. return true;
  848. } else {
  849. if ( "random-$type-image" == $header_image_mod )
  850. return true;
  851. elseif ( 'default' == $type && empty( $header_image_mod ) && '' != get_random_header_image() )
  852. return true;
  853. }
  854. return false;
  855. }
  856. /**
  857. * Display header image path.
  858. *
  859. * @since 2.1.0
  860. */
  861. function header_image() {
  862. echo get_header_image();
  863. }
  864. /**
  865. * Get the header images uploaded for the current theme.
  866. *
  867. * @since 3.2.0
  868. *
  869. * @return array
  870. */
  871. function get_uploaded_header_images() {
  872. $header_images = array();
  873. // @todo caching
  874. $headers = get_posts( array( 'post_type' => 'attachment', 'meta_key' => '_wp_attachment_is_custom_header', 'meta_value' => get_option('stylesheet'), 'orderby' => 'none', 'nopaging' => true ) );
  875. if ( empty( $headers ) )
  876. return array();
  877. foreach ( (array) $headers as $header ) {
  878. $url = esc_url_raw( $header->guid );
  879. $header_data = wp_get_attachment_metadata( $header->ID );
  880. $header_index = basename($url);
  881. $header_images[$header_index] = array();
  882. $header_images[$header_index]['attachment_id'] = $header->ID;
  883. $header_images[$header_index]['url'] = $url;
  884. $header_images[$header_index]['thumbnail_url'] = $url;
  885. $header_images[$header_index]['width'] = $header_data['width'];
  886. $header_images[$header_index]['height'] = $header_data['height'];
  887. }
  888. return $header_images;
  889. }
  890. /**
  891. * Get the header image data.
  892. *
  893. * @since 3.4.0
  894. *
  895. * @return object
  896. */
  897. function get_custom_header() {
  898. global $_wp_default_headers;
  899. if ( is_random_header_image() ) {
  900. $data = _get_random_header_data();
  901. } else {
  902. $data = get_theme_mod( 'header_image_data' );
  903. if ( ! $data && current_theme_supports( 'custom-header', 'default-image' ) ) {
  904. $directory_args = array( get_template_directory_uri(), get_stylesheet_directory_uri() );
  905. $data = array();
  906. $data['url'] = $data['thumbnail_url'] = vsprintf( get_theme_support( 'custom-header', 'default-image' ), $directory_args );
  907. if ( ! empty( $_wp_default_headers ) ) {
  908. foreach ( (array) $_wp_default_headers as $default_header ) {
  909. $url = vsprintf( $default_header['url'], $directory_args );
  910. if ( $data['url'] == $url ) {
  911. $data = $default_header;
  912. $data['url'] = $url;
  913. $data['thumbnail_url'] = vsprintf( $data['thumbnail_url'], $directory_args );
  914. break;
  915. }
  916. }
  917. }
  918. }
  919. }
  920. $default = array(
  921. 'url' => '',
  922. 'thumbnail_url' => '',
  923. 'width' => get_theme_support( 'custom-header', 'width' ),
  924. 'height' => get_theme_support( 'custom-header', 'height' ),
  925. );
  926. return (object) wp_parse_args( $data, $default );
  927. }
  928. /**
  929. * Register a selection of default headers to be displayed by the custom header admin UI.
  930. *
  931. * @since 3.0.0
  932. *
  933. * @param array $headers Array of headers keyed by a string id. The ids point to arrays containing 'url', 'thumbnail_url', and 'description' keys.
  934. */
  935. function register_default_headers( $headers ) {
  936. global $_wp_default_headers;
  937. $_wp_default_headers = array_merge( (array) $_wp_default_headers, (array) $headers );
  938. }
  939. /**
  940. * Unregister default headers.
  941. *
  942. * This function must be called after register_default_headers() has already added the
  943. * header you want to remove.
  944. *
  945. * @see register_default_headers()
  946. * @since 3.0.0
  947. *
  948. * @param string|array $header The header string id (key of array) to remove, or an array thereof.
  949. * @return True on success, false on failure.
  950. */
  951. function unregister_default_headers( $header ) {
  952. global $_wp_default_headers;
  953. if ( is_array( $header ) ) {
  954. array_map( 'unregister_default_headers', $header );
  955. } elseif ( isset( $_wp_default_headers[ $header ] ) ) {
  956. unset( $_wp_default_headers[ $header ] );
  957. return true;
  958. } else {
  959. return false;
  960. }
  961. }
  962. /**
  963. * Retrieve background image for custom background.
  964. *
  965. * @since 3.0.0
  966. *
  967. * @return string
  968. */
  969. function get_background_image() {
  970. return get_theme_mod('background_image', get_theme_support( 'custom-background', 'default-image' ) );
  971. }
  972. /**
  973. * Display background image path.
  974. *
  975. * @since 3.0.0
  976. */
  977. function background_image() {
  978. echo get_background_image();
  979. }
  980. /**
  981. * Retrieve value for custom background color.
  982. *
  983. * @since 3.0.0
  984. *
  985. * @return string
  986. */
  987. function get_background_color() {
  988. return get_theme_mod('background_color', get_theme_support( 'custom-background', 'default-color' ) );
  989. }
  990. /**
  991. * Display background color value.
  992. *
  993. * @since 3.0.0
  994. */
  995. function background_color() {
  996. echo get_background_color();
  997. }
  998. /**
  999. * Default custom background callback.
  1000. *
  1001. * @since 3.0.0
  1002. * @access protected
  1003. */
  1004. function _custom_background_cb() {
  1005. // $background is the saved custom image, or the default image.
  1006. $background = set_url_scheme( get_background_image() );
  1007. // $color is the saved custom color.
  1008. // A default has to be specified in style.css. It will not be printed here.
  1009. $color = get_theme_mod( 'background_color' );
  1010. if ( ! $background && ! $color )
  1011. return;
  1012. $style = $color ? "background-color: #$color;" : '';
  1013. if ( $background ) {
  1014. $image = " background-image: url('$background');";
  1015. $repeat = get_theme_mod( 'background_repeat', 'repeat' );
  1016. if ( ! in_array( $repeat, array( 'no-repeat', 'repeat-x', 'repeat-y', 'repeat' ) ) )
  1017. $repeat = 'repeat';
  1018. $repeat = " background-repeat: $repeat;";
  1019. $position = get_theme_mod( 'background_position_x', 'left' );
  1020. if ( ! in_array( $position, array( 'center', 'right', 'left' ) ) )
  1021. $position = 'left';
  1022. $position = " background-position: top $position;";
  1023. $attachment = get_theme_mod( 'background_attachment', 'scroll' );
  1024. if ( ! in_array( $attachment, array( 'fixed', 'scroll' ) ) )
  1025. $attachment = 'scroll';
  1026. $attachment = " background-attachment: $attachment;";
  1027. $style .= $image . $repeat . $position . $attachment;
  1028. }
  1029. ?>
  1030. <style type="text/css" id="custom-background-css">
  1031. body.custom-background { <?php echo trim( $style ); ?> }
  1032. </style>
  1033. <?php
  1034. }
  1035. /**
  1036. * Add callback for custom TinyMCE editor stylesheets.
  1037. *
  1038. * The parameter $stylesheet is the name of the stylesheet, relative to
  1039. * the theme root. It also accepts an array of stylesheets.
  1040. * It is optional and defaults to 'editor-style.css'.
  1041. *
  1042. * This function automatically adds another stylesheet with -rtl prefix, e.g. editor-style-rtl.css.
  1043. * If that file doesn't exist, it is removed before adding the stylesheet(s) to TinyMCE.
  1044. * If an array of stylesheets is passed to add_editor_style(),
  1045. * RTL is only added for the first stylesheet.
  1046. *
  1047. * Since version 3.4 the TinyMCE body has .rtl CSS class.
  1048. * It is a better option to use that class and add any RTL styles to the main stylesheet.
  1049. *
  1050. * @since 3.0.0
  1051. *
  1052. * @param mixed $stylesheet Optional. Stylesheet name or array thereof, relative to theme root.
  1053. * Defaults to 'editor-style.css'
  1054. */
  1055. function add_editor_style( $stylesheet = 'editor-style.css' ) {
  1056. add_theme_support( 'editor-style' );
  1057. if ( ! is_admin() )
  1058. return;
  1059. global $editor_styles;
  1060. $editor_styles = (array) $editor_styles;
  1061. $stylesheet = (array) $stylesheet;
  1062. if ( is_rtl() ) {
  1063. $rtl_stylesheet = str_replace('.css', '-rtl.css', $stylesheet[0]);
  1064. $stylesheet[] = $rtl_stylesheet;
  1065. }
  1066. $editor_styles = array_merge( $editor_styles, $stylesheet );
  1067. }
  1068. /**
  1069. * Removes all visual editor stylesheets.
  1070. *
  1071. * @since 3.1.0
  1072. *
  1073. * @return bool True on success, false if there were no stylesheets to remove.
  1074. */
  1075. function remove_editor_styles() {
  1076. if ( ! current_theme_supports( 'editor-style' ) )
  1077. return false;
  1078. _remove_theme_support( 'editor-style' );
  1079. if ( is_admin() )
  1080. $GLOBALS['editor_styles'] = array();
  1081. return true;
  1082. }
  1083. /**
  1084. * Allows a theme to register its support of a certain feature
  1085. *
  1086. * Must be called in the theme's functions.php file to work.
  1087. * If attached to a hook, it must be after_setup_theme.
  1088. * The init hook may be too late for some features.
  1089. *
  1090. * @since 2.9.0
  1091. * @param string $feature the feature being added
  1092. */
  1093. function add_theme_support( $feature ) {
  1094. global $_wp_theme_features;
  1095. if ( func_num_args() == 1 )
  1096. $args = true;
  1097. else
  1098. $args = array_slice( func_get_args(), 1 );
  1099. switch ( $feature ) {
  1100. case 'post-formats' :
  1101. if ( is_array( $args[0] ) )
  1102. $args[0] = array_intersect( $args[0], array_keys( get_post_format_slugs() ) );
  1103. break;
  1104. case 'custom-header-uploads' :
  1105. return add_theme_support( 'custom-header', array( 'uploads' => true ) );
  1106. break;
  1107. case 'custom-header' :
  1108. if ( ! is_array( $args ) )
  1109. $args = array( 0 => array() );
  1110. $defaults = array(
  1111. 'default-image' => '',
  1112. 'random-default' => false,
  1113. 'width' => 0,
  1114. 'height' => 0,
  1115. 'flex-height' => false,
  1116. 'flex-width' => false,
  1117. 'default-text-color' => '',
  1118. 'header-text' => true,
  1119. 'uploads' => true,
  1120. 'wp-head-callback' => '',
  1121. 'admin-head-callback' => '',
  1122. 'admin-preview-callback' => '',
  1123. );
  1124. $jit = isset( $args[0]['__jit'] );
  1125. unset( $args[0]['__jit'] );
  1126. // Merge in data from previous add_theme_support() calls.
  1127. // The first value registered wins. (A child theme is set up first.)
  1128. if ( isset( $_wp_theme_features['custom-header'] ) )
  1129. $args[0] = wp_parse_args( $_wp_theme_features['custom-header'][0], $args[0] );
  1130. // Load in the defaults at the end, as we need to insure first one wins.
  1131. // This will cause all constants to be defined, as each arg will then be set to the default.
  1132. if ( $jit )
  1133. $args[0] = wp_parse_args( $args[0], $defaults );
  1134. // If a constant was defined, use that value. Otherwise, define the constant to ensure
  1135. // the constant is always accurate (and is not defined later, overriding our value).
  1136. // As stated above, the first value wins.
  1137. // Once we get to wp_loaded (just-in-time), define any constants we haven't already.
  1138. // Constants are lame. Don't reference them. This is just for backwards compatibility.
  1139. if ( defined( 'NO_HEADER_TEXT' ) )
  1140. $args[0]['header-text'] = ! NO_HEADER_TEXT;
  1141. elseif ( isset( $args[0]['header-text'] ) )
  1142. define( 'NO_HEADER_TEXT', empty( $args[0]['header-text'] ) );
  1143. if ( defined( 'HEADER_IMAGE_WIDTH' ) )
  1144. $args[0]['width'] = (int) HEADER_IMAGE_WIDTH;
  1145. elseif ( isset( $args[0]['width'] ) )
  1146. define( 'HEADER_IMAGE_WIDTH', (int) $args[0]['width'] );
  1147. if ( defined( 'HEADER_IMAGE_HEIGHT' ) )
  1148. $args[0]['height'] = (int) HEADER_IMAGE_HEIGHT;
  1149. elseif ( isset( $args[0]['height'] ) )
  1150. define( 'HEADER_IMAGE_HEIGHT', (int) $args[0]['height'] );
  1151. if ( defined( 'HEADER_TEXTCOLOR' ) )
  1152. $args[0]['default-text-color'] = HEADER_TEXTCOLOR;
  1153. elseif ( isset( $args[0]['default-text-color'] ) )
  1154. define( 'HEADER_TEXTCOLOR', $args[0]['default-text-color'] );
  1155. if ( defined( 'HEADER_IMAGE' ) )
  1156. $args[0]['default-image'] = HEADER_IMAGE;
  1157. elseif ( isset( $args[0]['default-image'] ) )
  1158. define( 'HEADER_IMAGE', $args[0]['default-image'] );
  1159. if ( $jit && ! empty( $args[0]['default-image'] ) )
  1160. $args[0]['random-default'] = false;
  1161. // If headers are supported, and we still don't have a defined width or height,
  1162. // we have implicit flex sizes.
  1163. if ( $jit ) {
  1164. if ( empty( $args[0]['width'] ) && empty( $args[0]['flex-width'] ) )
  1165. $args[0]['flex-width'] = true;
  1166. if ( empty( $args[0]['height'] ) && empty( $args[0]['flex-height'] ) )
  1167. $args[0]['flex-height'] = true;
  1168. }
  1169. break;
  1170. case 'custom-background' :
  1171. if ( ! is_array( $args ) )
  1172. $args = array( 0 => array() );
  1173. $defaults = array(
  1174. 'default-image' => '',
  1175. 'default-color' => '',
  1176. 'wp-head-callback' => '_custom_background_cb',
  1177. 'admin-head-callback' => '',
  1178. 'admin-preview-callback' => '',
  1179. );
  1180. $jit = isset( $args[0]['__jit'] );
  1181. unset( $args[0]['__jit'] );
  1182. // Merge in data from previous add_theme_support() calls. The first value registered wins.
  1183. if ( isset( $_wp_theme_features['custom-background'] ) )
  1184. $args[0] = wp_parse_args( $_wp_theme_features['custom-background'][0], $args[0] );
  1185. if ( $jit )
  1186. $args[0] = wp_parse_args( $args[0], $defaults );
  1187. if ( defined( 'BACKGROUND_COLOR' ) )
  1188. $args[0]['default-color'] = BACKGROUND_COLOR;
  1189. elseif ( isset( $args[0]['default-color'] ) || $jit )
  1190. define( 'BACKGROUND_COLOR', $args[0]['default-color'] );
  1191. if ( defined( 'BACKGROUND_IMAGE' ) )
  1192. $args[0]['default-image'] = BACKGROUND_IMAGE;
  1193. elseif ( isset( $args[0]['default-image'] ) || $jit )
  1194. define( 'BACKGROUND_IMAGE', $args[0]['default-image'] );
  1195. break;
  1196. }
  1197. $_wp_theme_features[ $feature ] = $args;
  1198. }
  1199. /**
  1200. * Registers the internal custom header and background routines.
  1201. *
  1202. * @since 3.4.0
  1203. * @access private
  1204. */
  1205. function _custom_header_background_just_in_time() {
  1206. global $custom_image_header, $custom_background;
  1207. if ( current_theme_supports( 'custom-header' ) ) {
  1208. // In case any constants were defined after an add_custom_image_header() call, re-run.
  1209. add_theme_support( 'custom-header', array( '__jit' => true ) );
  1210. $args = get_theme_support( 'custom-header' );
  1211. if ( $args[0]['wp-head-callback'] )
  1212. add_action( 'wp_head', $args[0]['wp-head-callback'] );
  1213. if ( is_admin() ) {
  1214. require_once( ABSPATH . 'wp-admin/custom-header.php' );
  1215. $custom_image_header = new Custom_Image_Header( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  1216. }
  1217. }
  1218. if ( current_theme_supports( 'custom-background' ) ) {
  1219. // In case any constants were defined after an add_custom_background() call, re-run.
  1220. add_theme_support( 'custom-background', array( '__jit' => true ) );
  1221. $args = get_theme_support( 'custom-background' );
  1222. add_action( 'wp_head', $args[0]['wp-head-callback'] );
  1223. if ( is_admin() ) {
  1224. require_once( ABSPATH . 'wp-admin/custom-background.php' );
  1225. $custom_background = new Custom_Background( $args[0]['admin-head-callback'], $args[0]['admin-preview-callback'] );
  1226. }
  1227. }
  1228. }
  1229. add_action( 'wp_loaded', '_custom_header_background_just_in_time' );
  1230. /**
  1231. * Gets the theme support arguments passed when registering that support
  1232. *
  1233. * @since 3.1
  1234. * @param string $feature the feature to check
  1235. * @return array The array of extra arguments
  1236. */
  1237. function get_theme_support( $feature ) {
  1238. global $_wp_theme_features;
  1239. if ( ! isset( $_wp_theme_features[ $feature ] ) )
  1240. return false;
  1241. if ( func_num_args() <= 1 )
  1242. return $_wp_theme_features[ $feature ];
  1243. $args = array_slice( func_get_args(), 1 );
  1244. switch ( $feature ) {
  1245. case 'custom-header' :
  1246. case 'custom-background' :
  1247. if ( isset( $_wp_theme_features[ $feature ][0][ $args[0] ] ) )
  1248. return $_wp_theme_features[ $feature ][0][ $args[0] ];
  1249. return false;
  1250. break;
  1251. default :
  1252. return $_wp_theme_features[ $feature ];
  1253. break;
  1254. }
  1255. }
  1256. /**
  1257. * Allows a theme to de-register its support of a certain feature
  1258. *
  1259. * Should be called in the theme's functions.php file. Generally would
  1260. * be used for child themes to override support from the parent theme.
  1261. *
  1262. * @since 3.0.0
  1263. * @see add_theme_support()
  1264. * @param string $feature the feature being added
  1265. * @return bool Whether feature was removed.
  1266. */
  1267. function remove_theme_support( $feature ) {
  1268. // Blacklist: for internal registrations not used directly by themes.
  1269. if ( in_array( $feature, array( 'editor-style', 'widgets', 'menus' ) ) )
  1270. return false;
  1271. return _remove_theme_support( $feature );
  1272. }
  1273. /**
  1274. * Do not use. Removes theme support internally, ignorant of the blacklist.
  1275. *
  1276. * @access private
  1277. * @since 3.1.0
  1278. */
  1279. function _remove_theme_support( $feature ) {
  1280. global $_wp_theme_features;
  1281. switch ( $feature ) {
  1282. case 'custom-header-uploads' :
  1283. if ( ! isset( $_wp_theme_features['custom-header'] ) )
  1284. return false;
  1285. add_theme_support( 'custom-header', array( 'uploads' => false ) );
  1286. return; // Do not continue - custom-header-uploads no longer exists.
  1287. }
  1288. if ( ! isset( $_wp_theme_features[ $feature ] ) )
  1289. return false;
  1290. switch ( $feature ) {
  1291. case 'custom-header' :
  1292. if ( false === did_action( 'wp_loaded', '_custom_header_background_just_in_time' ) )
  1293. break;
  1294. $support = get_theme_support( 'custom-header' );
  1295. if ( $support[0]['wp-head-callback'] )
  1296. remove_action( 'wp_head', $support[0]['wp-head-callback'] );
  1297. remove_action( 'admin_menu', array( $GLOBALS['custom_image_header'], 'init' ) );
  1298. unset( $GLOBALS['custom_image_header'] );
  1299. break;
  1300. case 'custom-background' :
  1301. if ( false === did_action( 'wp_loaded', '_custom_header_background_just_in_time' ) )
  1302. break;
  1303. $support = get_theme_support( 'custom-background' );
  1304. remove_action( 'wp_head', $support[0]['wp-head-callback'] );
  1305. remove_action( 'admin_menu', array( $GLOBALS['custom_background'], 'init' ) );
  1306. unset( $GLOBALS['custom_background'] );
  1307. break;
  1308. }
  1309. unset( $_wp_theme_features[ $feature ] );
  1310. return true;
  1311. }
  1312. /**
  1313. * Checks a theme's support for a given feature
  1314. *
  1315. * @since 2.9.0
  1316. * @param string $feature the feature being checked
  1317. * @return boolean
  1318. */
  1319. function current_theme_supports( $feature ) {
  1320. global $_wp_theme_features;
  1321. if ( 'custom-header-uploads' == $feature )
  1322. return current_theme_supports( 'custom-header', 'uploads' );
  1323. if ( !isset( $_wp_theme_features[$feature] ) )
  1324. return false;
  1325. // If no args passed then no extra checks need be performed
  1326. if ( func_num_args() <= 1 )
  1327. return true;
  1328. $args = array_slice( func_get_args(), 1 );
  1329. switch ( $feature ) {
  1330. case 'post-thumbnails':
  1331. // post-thumbnails can be registered for only certain content/post types by passing
  1332. // an array of types to add_theme_support(). If no array was passed, then
  1333. // any type is accepted
  1334. if ( true === $_wp_theme_features[$feature] ) // Registered for all types
  1335. return true;
  1336. $content_type = $args[0];
  1337. return in_array( $content_type, $_wp_theme_features[$feature][0] );
  1338. break;
  1339. case 'post-formats':
  1340. // specific post formats can be registered by passing an array of types to
  1341. // add_theme_support()
  1342. $post_format = $args[0];
  1343. return in_array( $post_format, $_wp_theme_features[$feature][0] );
  1344. break;
  1345. case 'custom-header':
  1346. case 'custom-background' :
  1347. // specific custom header and background capabilities can be registered by passing
  1348. // an array to add_theme_support()
  1349. $header_support = $args[0];
  1350. return ( isset( $_wp_theme_features[$feature][0][$header_support] ) && $_wp_theme_features[$feature][0][$header_support] );
  1351. break;
  1352. }
  1353. return apply_filters('current_theme_supports-' . $feature, true, $args, $_wp_theme_features[$feature]);
  1354. }
  1355. /**
  1356. * Checks a theme's support for a given feature before loading the functions which implement it.
  1357. *
  1358. * @since 2.9.0
  1359. * @param string $feature the feature being checked
  1360. * @param string $include the file containing the functions that implement the feature
  1361. */
  1362. function require_if_theme_supports( $feature, $include) {
  1363. if ( current_theme_supports( $feature ) )
  1364. require ( $include );
  1365. }
  1366. /**
  1367. * Checks an attachment being deleted to see if it's a header or background image.
  1368. *
  1369. * If true it removes the theme modification which would be pointing at the deleted
  1370. * attachment
  1371. *
  1372. * @access private
  1373. * @since 3.0.0
  1374. * @param int $id the attachment id
  1375. */
  1376. function _delete_attachment_theme_mod( $id ) {
  1377. $attachment_image = wp_get_attachment_url( $id );
  1378. $header_image = get_header_image();
  1379. $background_image = get_background_image();
  1380. if ( $header_image && $header_image == $attachment_image )
  1381. remove_theme_mod( 'header_image' );
  1382. if ( $background_image && $background_image == $attachment_image )
  1383. remove_theme_mod( 'background_image' );
  1384. }
  1385. add_action( 'delete_attachment', '_delete_attachment_theme_mod' );
  1386. /**
  1387. * Checks if a theme has been changed and runs 'after_switch_theme' hook on the next WP load
  1388. *
  1389. * @since 3.3.0
  1390. */
  1391. function check_theme_switched() {
  1392. if ( $stylesheet = get_option( 'theme_switched' ) ) {
  1393. $old_theme = wp_get_theme( $stylesheet );
  1394. if ( $old_theme->exists() )
  1395. do_action( 'after_switch_theme', $old_theme->get('Name'), $old_theme );
  1396. else
  1397. do_action( 'after_switch_theme', $stylesheet );
  1398. update_option( 'theme_switched', false );
  1399. }
  1400. }
  1401. /**
  1402. * Includes and instantiates the WP_Customize_Manager class.
  1403. *
  1404. * Fires when ?wp_customize=on or on wp-admin/customize.php.
  1405. *
  1406. * @since 3.4.0
  1407. */
  1408. function _wp_customize_include() {
  1409. if ( ! ( ( isset( $_RE

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