[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-styles.php (source)

   1  <?php
   2  /**
   3   * Dependencies API: WP_Styles class
   4   *
   5   * @since 2.6.0
   6   *
   7   * @package WordPress
   8   * @subpackage Dependencies
   9   */
  10  
  11  /**
  12   * Core class used to register styles.
  13   *
  14   * @since 2.6.0
  15   *
  16   * @see WP_Dependencies
  17   */
  18  class WP_Styles extends WP_Dependencies {
  19      /**
  20       * Base URL for styles.
  21       *
  22       * Full URL with trailing slash.
  23       *
  24       * @since 2.6.0
  25       * @see wp_default_styles()
  26       * @var string|null
  27       */
  28      public $base_url;
  29  
  30      /**
  31       * URL of the content directory.
  32       *
  33       * @since 2.8.0
  34       * @see wp_default_styles()
  35       * @var string|null
  36       */
  37      public $content_url;
  38  
  39      /**
  40       * Default version string for stylesheets.
  41       *
  42       * @since 2.6.0
  43       * @see wp_default_styles()
  44       * @var string|null
  45       */
  46      public $default_version;
  47  
  48      /**
  49       * The current text direction.
  50       *
  51       * @since 2.6.0
  52       * @see wp_default_styles()
  53       * @var string
  54       */
  55      public $text_direction = 'ltr';
  56  
  57      /**
  58       * Holds a list of style handles which will be concatenated.
  59       *
  60       * @since 2.8.0
  61       * @deprecated 7.2.0 Styles are no longer concatenated.
  62       * @var string
  63       */
  64      public $concat = '';
  65  
  66      /**
  67       * Holds a string which contains style handles and their version.
  68       *
  69       * @since 2.8.0
  70       * @deprecated 3.4.0
  71       * @var string
  72       */
  73      public $concat_version = '';
  74  
  75      /**
  76       * Whether to perform concatenation.
  77       *
  78       * @since 2.8.0
  79       * @deprecated 7.2.0 Styles are no longer concatenated.
  80       * @var bool
  81       */
  82      public $do_concat = false;
  83  
  84      /**
  85       * Holds HTML markup of styles and additional data if concatenation
  86       * is enabled.
  87       *
  88       * @since 2.8.0
  89       * @deprecated 7.2.0 Styles are no longer concatenated.
  90       * @var string
  91       */
  92      public $print_html = '';
  93  
  94      /**
  95       * Holds inline styles if concatenation is enabled.
  96       *
  97       * @since 3.3.0
  98       * @deprecated 7.2.0 Styles are no longer concatenated.
  99       * @var string
 100       */
 101      public $print_code = '';
 102  
 103      /**
 104       * List of default directories.
 105       *
 106       * Only the deprecated {@see WP_Styles::in_default_dir()} reads this, but
 107       * {@see wp_default_styles()} still sets it for plugins that read it.
 108       *
 109       * @since 2.8.0
 110       * @deprecated 7.2.0 Styles are no longer concatenated.
 111       * @see WP_Styles::in_default_dir()
 112       * @see wp_default_styles()
 113       * @var string[]|null
 114       */
 115      public $default_dirs;
 116  
 117      /**
 118       * Constructor.
 119       *
 120       * @since 2.6.0
 121       */
 122  	public function __construct() {
 123          /**
 124           * Fires when the WP_Styles instance is initialized.
 125           *
 126           * @since 2.6.0
 127           *
 128           * @param WP_Styles $wp_styles WP_Styles instance (passed by reference).
 129           */
 130          do_action_ref_array( 'wp_default_styles', array( &$this ) );
 131      }
 132  
 133      /**
 134       * Processes a style dependency.
 135       *
 136       * @since 2.6.0
 137       * @since 5.5.0 Added the `$group` parameter.
 138       *
 139       * @see WP_Dependencies::do_item()
 140       *
 141       * @param string    $handle The style's registered handle.
 142       * @param int|false $group  Optional. Group level: level (int), no groups (false).
 143       *                          Default false.
 144       * @return bool True on success, false on failure.
 145       */
 146  	public function do_item( $handle, $group = false ) {
 147          if ( ! parent::do_item( $handle ) ) {
 148              return false;
 149          }
 150  
 151          $obj = $this->registered[ $handle ];
 152          if ( $obj->extra['conditional'] ?? false ) {
 153  
 154              return false;
 155          }
 156  
 157          $src          = $obj->src;
 158          $inline_style = $this->print_inline_style( $handle, false );
 159  
 160          if ( $inline_style ) {
 161              $processor = new WP_HTML_Tag_Processor( '<style></style>' );
 162              $processor->next_tag();
 163              $processor->set_attribute( 'id', "{$handle}-inline-css" );
 164              $processor->set_modifiable_text( "\n{$inline_style}\n" );
 165              $inline_style_tag = "{$processor->get_updated_html()}\n";
 166          } else {
 167              $inline_style_tag = '';
 168          }
 169  
 170          $media = $obj->args ?? 'all';
 171  
 172          // A single item may alias a set of items, by having dependencies, but no source.
 173          if ( ! $src ) {
 174              if ( $inline_style_tag ) {
 175                  echo $inline_style_tag;
 176              }
 177  
 178              return true;
 179          }
 180  
 181          $href = $this->_css_href( $src, $obj->ver, $handle );
 182          if ( ! $href ) {
 183              return true;
 184          }
 185  
 186          $rel   = isset( $obj->extra['alt'] ) && $obj->extra['alt'] ? 'alternate stylesheet' : 'stylesheet';
 187          $title = $obj->extra['title'] ?? '';
 188  
 189          $tag = sprintf(
 190              "<link rel='%s' id='%s-css'%s href='%s' media='%s' />\n",
 191              $rel,
 192              esc_attr( $handle ),
 193              $title ? sprintf( " title='%s'", esc_attr( $title ) ) : '',
 194              $href,
 195              esc_attr( $media )
 196          );
 197  
 198          /**
 199           * Filters the HTML link tag of an enqueued style.
 200           *
 201           * @since 2.6.0
 202           * @since 4.3.0 Introduced the `$href` parameter.
 203           * @since 4.5.0 Introduced the `$media` parameter.
 204           *
 205           * @param string $tag    The link tag for the enqueued style.
 206           * @param string $handle The style's registered handle.
 207           * @param string $href   The stylesheet's source URL.
 208           * @param string $media  The stylesheet's media attribute.
 209           */
 210          $tag = apply_filters( 'style_loader_tag', $tag, $handle, $href, $media );
 211  
 212          $rtl_src = $this->get_rtl_src( $handle );
 213  
 214          if ( null !== $rtl_src ) {
 215              $rtl_href = esc_url( $rtl_src );
 216              $rtl_tag  = sprintf(
 217                  "<link rel='%s' id='%s-rtl-css'%s href='%s' media='%s' />\n",
 218                  $rel,
 219                  esc_attr( $handle ),
 220                  $title ? sprintf( " title='%s'", esc_attr( $title ) ) : '',
 221                  $rtl_href,
 222                  esc_attr( $media )
 223              );
 224  
 225              /** This filter is documented in wp-includes/class-wp-styles.php */
 226              $rtl_tag = apply_filters( 'style_loader_tag', $rtl_tag, $handle, $rtl_href, $media );
 227  
 228              if ( 'replace' === $obj->extra['rtl'] ) {
 229                  $tag = $rtl_tag;
 230              } else {
 231                  $tag .= $rtl_tag;
 232              }
 233          }
 234  
 235          echo $tag;
 236          echo $inline_style_tag;
 237  
 238          return true;
 239      }
 240  
 241      /**
 242       * Gets the URL of the right-to-left stylesheet for a registered style.
 243       *
 244       * On a right-to-left locale, a style registered with `rtl` data is served by a separate
 245       * stylesheet, which either replaces its left-to-right one (when the data is `'replace'`)
 246       * or loads alongside it.
 247       *
 248       * Like {@see WP_Styles::get_src()}, the URL is neither sanitized nor escaped, so a caller can
 249       * pass it through esc_url() to print it, or esc_url_raw() otherwise, once.
 250       *
 251       * @since 7.2.0
 252       *
 253       * @param string $handle The style's registered handle.
 254       * @return string|null URL of the right-to-left stylesheet, after the {@see 'style_loader_src'}
 255       *                     filter. Null when the text direction is not right-to-left, or the style is
 256       *                     not registered, has no source of its own, or has no right-to-left variant.
 257       */
 258  	public function get_rtl_src( string $handle ): ?string {
 259          if ( 'rtl' !== $this->text_direction || ! isset( $this->registered[ $handle ] ) ) {
 260              return null;
 261          }
 262  
 263          $obj = $this->registered[ $handle ];
 264  
 265          if ( ! $obj->src || ! isset( $obj->extra['rtl'] ) || ! $obj->extra['rtl'] ) {
 266              return null;
 267          }
 268  
 269          /*
 270           * The version and the handle's added arguments are those of the left-to-right stylesheet,
 271           * appended the same way, while the filter is passed the handle with `-rtl` appended, as it
 272           * always has been.
 273           */
 274          if ( is_bool( $obj->extra['rtl'] ) || 'replace' === $obj->extra['rtl'] ) {
 275              $suffix = isset( $obj->extra['suffix'] ) && is_string( $obj->extra['suffix'] ) ? $obj->extra['suffix'] : '';
 276  
 277              return str_replace( "{$suffix}.css", "-rtl{$suffix}.css", $this->build_src( $obj->src, $obj->ver, $handle, "$handle-rtl" ) );
 278          }
 279  
 280          // Any other value is the URL of the right-to-left stylesheet itself.
 281          if ( ! is_string( $obj->extra['rtl'] ) ) {
 282              return null;
 283          }
 284  
 285          return $this->build_src( $obj->extra['rtl'], $obj->ver, $handle, "$handle-rtl" );
 286      }
 287  
 288      /**
 289       * Adds extra CSS styles to a registered stylesheet.
 290       *
 291       * @since 3.3.0
 292       *
 293       * @param string $handle The style's registered handle.
 294       * @param string $code   String containing the CSS styles to be added.
 295       * @return bool True on success, false on failure.
 296       */
 297  	public function add_inline_style( $handle, $code ) {
 298          if ( ! $code ) {
 299              return false;
 300          }
 301  
 302          $after = $this->get_data( $handle, 'after' );
 303          if ( ! $after ) {
 304              $after = array();
 305          }
 306  
 307          $after[] = $code;
 308  
 309          return $this->add_data( $handle, 'after', $after );
 310      }
 311  
 312      /**
 313       * Prints extra CSS styles of a registered stylesheet.
 314       *
 315       * @since 3.3.0
 316       *
 317       * @param string $handle  The style's registered handle.
 318       * @param bool   $display Optional. Whether to print the inline style
 319       *                        instead of just returning it. Default true.
 320       * @return string|bool False if no data exists, inline styles if `$display` is false,
 321       *                     true otherwise.
 322       * @phpstan-return ( $display is true ? bool : string|false )
 323       */
 324  	public function print_inline_style( $handle, $display = true ) {
 325          $output = $this->get_data( $handle, 'after' );
 326  
 327          if ( empty( $output ) || ! is_array( $output ) ) {
 328              return false;
 329          }
 330  
 331          // Obtain the original `src` for a stylesheet possibly inlined by wp_maybe_inline_styles().
 332          $inlined_src = $this->get_data( $handle, 'inlined_src' );
 333  
 334          // If there's only one `after` inline style, and that inline style had been inlined, then use the $inlined_src
 335          // as the sourceURL. Otherwise, if there is more than one inline `after` style associated with the handle,
 336          // then resort to using the handle to construct the sourceURL since there isn't a single source.
 337          if ( count( $output ) === 1 && is_string( $inlined_src ) && strlen( $inlined_src ) > 0 ) {
 338              $source_url = esc_url_raw( $inlined_src );
 339          } else {
 340              $source_url = rawurlencode( "{$handle}-inline-css" );
 341          }
 342  
 343          $output[] = sprintf(
 344              '/*# sourceURL=%s */',
 345              $source_url
 346          );
 347  
 348          $output = implode( "\n", $output );
 349  
 350          if ( ! $display ) {
 351              return $output;
 352          }
 353  
 354          $processor = new WP_HTML_Tag_Processor( '<style></style>' );
 355          $processor->next_tag();
 356          $processor->set_attribute( 'id', "{$handle}-inline-css" );
 357          $processor->set_modifiable_text( "\n{$output}\n" );
 358          echo "{$processor->get_updated_html()}\n";
 359  
 360          return true;
 361      }
 362  
 363      /**
 364       * Overrides the add_data method from WP_Dependencies, to allow unsetting dependencies for conditional styles.
 365       *
 366       * @since 6.9.0
 367       *
 368       * @param string $handle Name of the item. Should be unique.
 369       * @param string $key    The data key.
 370       * @param mixed  $value  The data value.
 371       * @return bool True on success, false on failure.
 372       */
 373  	public function add_data( $handle, $key, $value ) {
 374          if ( ! isset( $this->registered[ $handle ] ) ) {
 375              return false;
 376          }
 377  
 378          if ( 'conditional' === $key ) {
 379              $this->registered[ $handle ]->deps = array();
 380          }
 381  
 382          return parent::add_data( $handle, $key, $value );
 383      }
 384  
 385      /**
 386       * Determines style dependencies.
 387       *
 388       * @since 2.6.0
 389       *
 390       * @see WP_Dependencies::all_deps()
 391       *
 392       * @param string|string[] $handles   Item handle (string) or item handles (array of strings).
 393       * @param bool            $recursion Optional. Internal flag that function is calling itself.
 394       *                                   Default false.
 395       * @param int|false       $group     Optional. Group level: level (int), no groups (false).
 396       *                                   Default false.
 397       * @return bool True on success, false on failure.
 398       */
 399  	public function all_deps( $handles, $recursion = false, $group = false ) {
 400          $result = parent::all_deps( $handles, $recursion, $group );
 401          if ( ! $recursion ) {
 402              /**
 403               * Filters the array of enqueued styles before processing for output.
 404               *
 405               * @since 2.6.0
 406               *
 407               * @param string[] $to_do The list of enqueued style handles about to be processed.
 408               */
 409              $this->to_do = apply_filters( 'print_styles_array', $this->to_do );
 410          }
 411          return $result;
 412      }
 413  
 414      /**
 415       * Generates an enqueued style's fully-qualified URL.
 416       *
 417       * @since 2.6.0
 418       *
 419       * @param string            $src    The source of the enqueued style.
 420       * @param string|false|null $ver    The version of the enqueued style.
 421       * @param string            $handle The style's registered handle.
 422       * @return string Style's fully-qualified URL, escaped for use in an HTML attribute.
 423       */
 424  	public function _css_href( $src, $ver, $handle ) {
 425          return esc_url( $this->build_src( $src, $ver, (string) $handle ) );
 426      }
 427  
 428      /**
 429       * Gets the URL a registered style is loaded from.
 430       *
 431       * This is the URL printed in the stylesheet's `href` attribute, including the version query
 432       * argument and any arguments added to the handle, after the {@see 'style_loader_src'} filter.
 433       * Unlike {@see WP_Styles::_css_href()}, it is neither sanitized nor escaped, so a caller can
 434       * pass it through esc_url() to print it, or esc_url_raw() otherwise, once. This is the same as
 435       * {@see WP_Script_Modules::get_src()}.
 436       *
 437       * @since 7.2.0
 438       *
 439       * @param string $handle The style's registered handle.
 440       * @return string Style URL, or an empty string when the style is not registered, has no
 441       *                source of its own because it only aliases other styles, or was filtered away.
 442       */
 443  	public function get_src( string $handle ): string {
 444          if ( ! isset( $this->registered[ $handle ] ) ) {
 445              return '';
 446          }
 447  
 448          $obj = $this->registered[ $handle ];
 449  
 450          /*
 451           * An alias, with no source of its own, has no URL. A source of `true`, like that of `colors`,
 452           * gets past this, since its URL comes from the 'style_loader_src' filter in build_src(), as
 453           * it does when WP_Styles::do_item() prints the stylesheet.
 454           */
 455          if ( ! $obj->src ) {
 456              return '';
 457          }
 458  
 459          return $this->build_src( $obj->src, $obj->ver, $handle );
 460      }
 461  
 462      /**
 463       * Builds a style's fully-qualified URL and passes it through the 'style_loader_src' filter.
 464       *
 465       * The result is not escaped, so callers can escape it for where it is used.
 466       *
 467       * @since 7.2.0
 468       *
 469       * @param string|true       $src    The source of the style, or true for one whose URL comes
 470       *                                  from the {@see 'style_loader_src'} filter.
 471       * @param string|false|null $ver           The version of the style.
 472       * @param string            $handle        The style's registered handle, whose added arguments
 473       *                                         are appended.
 474       * @param string|null       $filter_handle Optional. The handle passed to the
 475       *                                         {@see 'style_loader_src'} filter, such as
 476       *                                         `{$handle}-rtl` for a right-to-left stylesheet.
 477       *                                         Default `$handle`.
 478       * @return string The filtered URL, or an empty string when the filter returns anything other
 479       *                than a string.
 480       */
 481  	private function build_src( $src, $ver, string $handle, ?string $filter_handle = null ): string {
 482          if ( ! is_bool( $src ) && ! preg_match( '|^(https?:)?//|', $src ) && ! ( $this->content_url && str_starts_with( $src, $this->content_url ) ) ) {
 483              $src = $this->base_url . $src;
 484          }
 485  
 486          $ver_to_add = '';
 487          if ( empty( $ver ) && null !== $ver && is_string( $this->default_version ) ) {
 488              $ver_to_add = $this->default_version;
 489          } elseif ( is_scalar( $ver ) ) {
 490              $ver_to_add = (string) $ver;
 491          }
 492  
 493          $added_args = (string) ( $this->args[ $handle ] ?? '' );
 494  
 495          if ( '' !== $ver_to_add || '' !== $added_args ) {
 496              $fragment = strstr( $src, '#' );
 497              if ( false !== $fragment ) {
 498                  $src = substr( $src, 0, -strlen( $fragment ) );
 499              }
 500  
 501              if ( '' !== $ver_to_add ) {
 502                  $src .= ( str_contains( $src, '?' ) ? '&' : '?' ) . 'ver=' . rawurlencode( $ver_to_add );
 503              }
 504              if ( '' !== $added_args ) {
 505                  $src .= ( str_contains( $src, '?' ) ? '&' : '?' ) . $added_args;
 506              }
 507  
 508              if ( false !== $fragment ) {
 509                  $src .= $fragment;
 510              }
 511          }
 512  
 513          /**
 514           * Filters an enqueued style's fully-qualified URL.
 515           *
 516           * @since 2.6.0
 517           *
 518           * @param string $src    The source URL of the enqueued style.
 519           * @param string $handle The style's registered handle.
 520           */
 521          $src = apply_filters( 'style_loader_src', $src, $filter_handle ?? $handle );
 522  
 523          return is_string( $src ) ? $src : '';
 524      }
 525  
 526      /**
 527       * Whether a handle's source is in a default directory.
 528       *
 529       * @since 2.8.0
 530       * @deprecated 7.2.0 Styles are no longer concatenated.
 531       *
 532       * @param string $src The source of the enqueued style.
 533       * @return bool True if found, false if not.
 534       */
 535  	public function in_default_dir( $src ) {
 536          _deprecated_function( __METHOD__, '7.2.0' );
 537  
 538          if ( ! $this->default_dirs ) {
 539              return true;
 540          }
 541  
 542          return array_any( (array) $this->default_dirs, fn( $test ) => str_starts_with( $src, $test ) );
 543      }
 544  
 545      /**
 546       * Processes items and dependencies for the footer group.
 547       *
 548       * HTML 5 allows styles in the body, grab late enqueued items and output them in the footer.
 549       *
 550       * @since 3.3.0
 551       *
 552       * @see WP_Dependencies::do_items()
 553       *
 554       * @return string[] Handles of items that have been processed.
 555       */
 556  	public function do_footer_items() {
 557          $this->do_items( false, 1 );
 558          return $this->done;
 559      }
 560  
 561      /**
 562       * Resets class properties.
 563       *
 564       * @since 3.3.0
 565       */
 566  	public function reset() {
 567          $this->do_concat      = false;
 568          $this->concat         = '';
 569          $this->concat_version = '';
 570          $this->print_html     = '';
 571      }
 572  
 573      /**
 574       * Gets a style-specific dependency warning message.
 575       *
 576       * @since 6.9.1
 577       *
 578       * @param string   $handle                     Style handle with missing dependencies.
 579       * @param string[] $missing_dependency_handles Missing dependency handles.
 580       * @return string Formatted, localized warning message.
 581       */
 582  	protected function get_dependency_warning_message( $handle, $missing_dependency_handles ) {
 583          return sprintf(
 584              /* translators: 1: Style handle, 2: List of missing dependency handles. */
 585              __( 'The style with the handle "%1$s" was enqueued with dependencies that are not registered: %2$s.' ),
 586              $handle,
 587              implode( wp_get_list_item_separator(), $missing_dependency_handles )
 588          );
 589      }
 590  }


Generated : Tue Nov 3 08:20:36 2026 Cross-referenced by PHPXref