PageRenderTime 61ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/public/frontend/wp-includes/theme.php

https://bitbucket.org/floppyxyz/musical
PHP | 1677 lines | 858 code | 228 blank | 591 comment | 215 complexity | fe35c7804407fa0a516b050cabba1afd MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1

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

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