); } $webfont['src'] = $src_ordered; return $webfont; }; /** * Compiles the 'src' into valid CSS. * * @since 6.0.0 * @since 6.2.0 Removed local() CSS. * * @param string $font_family Font family. * @param array $value Value to process. * @return string The CSS. */ $fn_compile_src = static function( $font_family, array $value ) { $src = ''; foreach ( $value as $item ) { $src .= ( 'data' === $item['format'] ) ? ", url({$item['url']})" : ", url('{$item['url']}') format('{$item['format']}')"; } $src = ltrim( $src, ', ' ); return $src; }; /** * Compiles the font variation settings. * * @since 6.0.0 * * @param array $font_variation_settings Array of font variation settings. * @return string The CSS. */ $fn_compile_variations = static function( array $font_variation_settings ) { $variations = ''; foreach ( $font_variation_settings as $key => $value ) { $variations .= "$key $value"; } return $variations; }; /** * Builds the font-family's CSS. * * @since 6.0.0 * * @uses $fn_compile_src To run the function that compiles the src. * @uses $fn_compile_variations To run the function that compiles the variations. * * @param array $webfont Webfont to process. * @return string This font-family's CSS. */ $fn_build_font_face_css = static function( array $webfont ) use ( $fn_compile_src, $fn_compile_variations ) { $css = ''; // Wrap font-family in quotes if it contains spaces. if ( str_contains( $webfont['font-family'], ' ' ) && ! str_contains( $webfont['font-family'], '"' ) && ! str_contains( $webfont['font-family'], "'" ) ) { $webfont['font-family'] = '"' . $webfont['font-family'] . '"'; } foreach ( $webfont as $key => $value ) { /* * Skip "provider", since it's for internal API use, * and not a valid CSS property. */ if ( 'provider' === $key ) { continue; } // Compile the "src" parameter. if ( 'src' === $key ) { $value = $fn_compile_src( $webfont['font-family'], $value ); } // If font-variation-settings is an array, convert it to a string. if ( 'font-variation-settings' === $key && is_array( $value ) ) { $value = $fn_compile_variations( $value ); } if ( ! empty( $value ) ) { $css .= "$key:$value;"; } } return $css; }; /** * Gets the '@font-face' CSS styles for locally-hosted font files. * * @since 6.0.0 * * @uses $registered_webfonts To access and update the registered webfonts registry (passed by reference). * @uses $fn_order_src To run the function that orders the src. * @uses $fn_build_font_face_css To run the function that builds the font-face CSS. * * @return string The `@font-face` CSS. */ $fn_get_css = static function() use ( &$registered_webfonts, $fn_order_src, $fn_build_font_face_css ) { $css = ''; foreach ( $registered_webfonts as $webfont ) { // Order the webfont's `src` items to optimize for browser support. $webfont = $fn_order_src( $webfont ); // Build the @font-face CSS for this webfont. $css .= '@font-face{' . $fn_build_font_face_css( $webfont ) . '}'; } return $css; }; /** * Generates and enqueues webfonts styles. * * @since 6.0.0 * * @uses $fn_get_css To run the function that gets the CSS. */ $fn_generate_and_enqueue_styles = static function() use ( $fn_get_css ) { // Generate the styles. $styles = $fn_get_css(); // Bail out if there are no styles to enqueue. if ( '' === $styles ) { return; } // Enqueue the stylesheet. wp_register_style( 'wp-webfonts', '' ); wp_enqueue_style( 'wp-webfonts' ); // Add the styles to the stylesheet. wp_add_inline_style( 'wp-webfonts', $styles ); }; /** * Generates and enqueues editor styles. * * @since 6.0.0 * * @uses $fn_get_css To run the function that gets the CSS. */ $fn_generate_and_enqueue_editor_styles = static function() use ( $fn_get_css ) { // Generate the styles. $styles = $fn_get_css(); // Bail out if there are no styles to enqueue. if ( '' === $styles ) { return; } wp_add_inline_style( 'wp-block-library', $styles ); }; add_action( 'wp_loaded', $fn_register_webfonts ); add_action( 'wp_enqueue_scripts', $fn_generate_and_enqueue_styles ); add_action( 'admin_init', $fn_generate_and_enqueue_editor_styles ); } /** * Loads classic theme styles on classic themes in the frontend. * * This is needed for backwards compatibility for button blocks specifically. * * @since 6.1.0 */ function wp_enqueue_classic_theme_styles() { if ( ! wp_theme_has_theme_json() ) { $suffix = wp_scripts_get_suffix(); wp_register_style( 'classic-theme-styles', '/' . WPINC . "/css/classic-themes$suffix.css" ); wp_style_add_data( 'classic-theme-styles', 'path', ABSPATH . WPINC . "/css/classic-themes$suffix.css" ); wp_enqueue_style( 'classic-theme-styles' ); } } /** * Loads classic theme styles on classic themes in the editor. * * This is needed for backwards compatibility for button blocks specifically. * * @since 6.1.0 * * @param array $editor_settings The array of editor settings. * @return array A filtered array of editor settings. */ function wp_add_editor_classic_theme_styles( $editor_settings ) { if ( wp_theme_has_theme_json() ) { return $editor_settings; } $suffix = wp_scripts_get_suffix(); $classic_theme_styles = ABSPATH . WPINC . "/css/classic-themes$suffix.css"; /* * This follows the pattern of get_block_editor_theme_styles, * but we can't use get_block_editor_theme_styles directly as it * only handles external files or theme files. */ $classic_theme_styles_settings = array( 'css' => file_get_contents( $classic_theme_styles ), '__unstableType' => 'core', 'isGlobalStyles' => false, ); // Add these settings to the start of the array so that themes can override them. array_unshift( $editor_settings['styles'], $classic_theme_styles_settings ); return $editor_settings; } * @param string $id The class name. * @param bool $new True to generate a new instance even if the class was registered as shared. * * @return object An instance of the requested class. * @throws ContainerException Attempt to get an instance of a non-namespaced class. */ public function get( $id, bool $new = false ) { if ( false === strpos( $id, '\\' ) ) { throw new ContainerException( "Attempt to get an instance of the non-namespaced class '$id' from the container, did you forget to add a namespace import?" ); } return parent::get( $id, $new ); } /** * Gets the class from the concrete regardless of type. * * @param mixed $concrete The concrete that we want the class from.. * * @return string|null The class from the concrete if one is available, null otherwise. */ protected function get_class_from_concrete( $concrete ) { if ( is_object( $concrete ) && ! is_callable( $concrete ) ) { if ( $concrete instanceof DefinitionInterface ) { return $this->get_class_from_concrete( $concrete->getConcrete() ); } return get_class( $concrete ); } if ( is_string( $concrete ) && class_exists( $concrete ) ) { return $concrete; } return null; } /** * Checks to see whether or not a class is allowed to be registered. * * @param string $class_name The class to check. * * @return bool True if the class is allowed to be registered, false otherwise. */ protected function is_class_allowed( string $class_name ): bool { return StringUtil::starts_with( $class_name, $this->woocommerce_namespace, false ) || in_array( $class_name, $this->registration_whitelist, true ); } /** * Check if a class name corresponds to an anonymous class. * * @param string $class_name The class name to check. * @return bool True if the name corresponds to an anonymous class. */ protected function is_anonymous_class( string $class_name ): bool { return StringUtil::starts_with( $class_name, 'class@anonymous' ); } }