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


Generated : Wed Oct 14 08:20:33 2026 Cross-referenced by PHPXref