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