Server : Apache System : Linux pod-100823:apache2_74:v0.5.7 5.4.0-1138-gcp #147~18.04.1-Ubuntu SMP Mon Oct 7 21:46:26 UTC 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.33.7 Disable Function : apache_child_terminate,apache_get_modules,apache_get_version,apache_getenv,apache_note,apache_setenv,disk_free_space,disk_total_space,diskfreespace,dl,exec,fastcgi_finish_request,link,opcache_compile_file,opcache_get_configuration,opcache_invalidate,opcache_is_script_cached,opcache_reset,passthru,pclose,pcntl_exec,popen,posix_getpid,posix_getppid,posix_getpwuid,posix_kill,posix_mkfifo,posix_setegid,posix_seteuid,posix_setgid,posix_setpgid,posix_setsid,posix_setuid,posix_uname,proc_close,proc_get_status,proc_nice,proc_open,proc_terminate,realpath_cache_get,shell_exec,show_source,symlink,system Directory : /nas/content/live/attorneyexperi/wp-content/plugins/diva/src/ |
<?php /** * Class ReaderThemeSupportFeatures. * * @package AmpProject\AmpWP */ namespace AmpProject\AmpWP; use AmpProject\AmpWP\Infrastructure\Registerable; use AmpProject\AmpWP\Infrastructure\Service; use AMP_Options_Manager; use Theme_Upgrader; /** * Stores the primary theme's theme support features when Reader template mode is active and then adds the necessary styles to support them. * * Note that this service is not conditional based on whether Reader mode is selected because it needs to run logic * when transitioning from non-reader to Reader mode. * * @package AmpProject\AmpWP * @since 2.1 * @internal */ final class ReaderThemeSupportFeatures implements Service, Registerable { /** * Theme feature slug for editor-color-palette. * * @var string */ const FEATURE_EDITOR_COLOR_PALETTE = 'editor-color-palette'; /** * Theme feature slug for editor-gradient-presets. * * @var string */ const FEATURE_EDITOR_GRADIENT_PRESETS = 'editor-gradient-presets'; /** * Theme feature slug for editor-font-sizes. * * @var string */ const FEATURE_EDITOR_FONT_SIZES = 'editor-font-sizes'; /** * Key slug. * * @var string */ const KEY_SLUG = 'slug'; /** * Key size. * * @var string */ const KEY_SIZE = 'size'; /** * Key color. * * @var string */ const KEY_COLOR = 'color'; /** * Key gradient. * * @var string */ const KEY_GRADIENT = 'gradient'; /** * Key gradients. * * @var string */ const KEY_GRADIENTS = 'gradients'; /** * Key palette. * * @var string */ const KEY_PALETTE = 'palette'; /** * Key fontSizes. * * @var string */ const KEY_FONT_SIZES = 'fontSizes'; /** * Key typography. * * @var string */ const KEY_TYPOGRAPHY = 'typography'; /** * Key for `theme` presets in block editor. * Key for `theme` context in `wp_get_global_settings()`. * * @var string */ const KEY_THEME = 'theme'; /** * Key for `default` presets in block editor. * * @var string */ const KEY_DEFAULT = 'default'; /** * Key for `spacing` presets in theme.json. * * @var string */ const KEY_SPACING = 'spacing'; /** * Key for `steps` presets in theme.json. * * @var string */ const KEY_STEPS = 'steps'; /** * Key for `spacingSizes` presets in theme.json. * * @var string */ const KEY_SPACING_SIZES = 'spacingSizes'; /** * Key for `spacingScale` presets in theme.json. * * @var string */ const KEY_SPACING_SCALE = 'spacingScale'; /** * Key for `customSpacingSize` presets in theme.json. * * @var string */ const KEY_CUSTOM_SPACING_SIZE = 'customSpacingSize'; /** * Action fired when the cached primary_theme_support should be updated. * * @var string */ const ACTION_UPDATE_CACHED_PRIMARY_THEME_SUPPORT = 'amp_update_cached_primary_theme_support'; /** * Supported features. * * @var array[] */ const SUPPORTED_FEATURES = [ self::FEATURE_EDITOR_COLOR_PALETTE => [ self::KEY_SLUG, self::KEY_COLOR ], self::FEATURE_EDITOR_GRADIENT_PRESETS => [ self::KEY_SLUG, self::KEY_GRADIENT ], self::FEATURE_EDITOR_FONT_SIZES => [ self::KEY_SLUG, self::KEY_SIZE ], ]; /** * The theme.json paths mapping to be fetched using `wp_get_global_settings()`. * * @var array[] */ const SUPPORTED_THEME_JSON_FEATURES = [ self::FEATURE_EDITOR_COLOR_PALETTE => [ self::KEY_COLOR, self::KEY_PALETTE ], self::FEATURE_EDITOR_GRADIENT_PRESETS => [ self::KEY_COLOR, self::KEY_GRADIENTS ], self::FEATURE_EDITOR_FONT_SIZES => [ self::KEY_TYPOGRAPHY, self::KEY_FONT_SIZES ], ]; /** * Reader theme loader. * * @var ReaderThemeLoader */ private $reader_theme_loader; /** * ReaderThemeLoader constructor. * * @param ReaderThemeLoader $reader_theme_loader Reader theme loader. */ public function __construct( ReaderThemeLoader $reader_theme_loader ) { $this->reader_theme_loader = $reader_theme_loader; } /** * Register the service with the system. * * @return void */ public function register() { add_filter( 'amp_options_updating', [ $this, 'filter_amp_options_updating' ] ); add_action( 'after_switch_theme', [ $this, 'handle_theme_update' ] ); add_action( self::ACTION_UPDATE_CACHED_PRIMARY_THEME_SUPPORT, [ $this, 'update_cached_theme_support' ] ); add_action( 'upgrader_process_complete', function ( $upgrader ) { if ( $upgrader instanceof Theme_Upgrader ) { $this->update_cached_theme_support(); } } ); add_action( 'amp_post_template_head', [ $this, 'print_theme_support_styles' ] ); add_action( 'wp_head', [ $this, 'print_theme_support_styles' ], 9 // Because wp_print_styles happens at priority 8, and we want the primary theme's colors to override any conflicting theme color assignments. ); } /** * Check whether all the required props are present for a given feature item. * * @param string $feature Feature name. * @param array $props Props to check. * * @return bool Whether all are present. */ public function has_required_feature_props( $feature, $props ) { if ( empty( $props ) || ! is_array( $props ) ) { return false; } foreach ( self::SUPPORTED_FEATURES[ $feature ] as $required_prop ) { if ( ! array_key_exists( $required_prop, $props ) ) { return false; } } return true; } /** * Filter the AMP options when they are updated to add the primary theme's features. * * @param array $options Options. * @return array Options. */ public function filter_amp_options_updating( $options ) { if ( $this->reader_theme_loader->is_enabled( $options ) ) { $options[ Option::PRIMARY_THEME_SUPPORT ] = $this->get_theme_support_features( true ); } else { $options[ Option::PRIMARY_THEME_SUPPORT ] = null; } return $options; } /** * Handle updating the cached primary_theme_support after updating/switching theme. * * In the case of switching the theme via WP-CLI, it could be that the next request is for an AMP page and * the `check_theme_switched()` function will run in the context of a Reader theme being loaded. In that case, * the added theme support won't be for the primary theme and we need to schedule an immediate event in WP-Cron to * try again in the context of a cron request in which a Reader theme will never be overriding the primary theme. */ public function handle_theme_update() { if ( $this->reader_theme_loader->is_theme_overridden() ) { wp_schedule_single_event( time(), self::ACTION_UPDATE_CACHED_PRIMARY_THEME_SUPPORT ); } else { $this->update_cached_theme_support(); } } /** * Update primary theme's cached theme support. */ public function update_cached_theme_support() { if ( $this->reader_theme_loader->is_enabled() ) { AMP_Options_Manager::update_option( Option::PRIMARY_THEME_SUPPORT, $this->get_theme_support_features( true ) ); } else { AMP_Options_Manager::update_option( Option::PRIMARY_THEME_SUPPORT, null ); } } /** * Get the theme support features. * * @param bool $reduced Whether to reduce the feature props down to just what is required. * @return array Theme support features. */ public function get_theme_support_features( $reduced = false ) { $features = []; foreach ( array_keys( self::SUPPORTED_FEATURES ) as $feature_key ) { if ( $this->theme_has_theme_json() && function_exists( 'wp_get_global_settings' ) ) { $feature_value = []; $global_settings = wp_get_global_settings( self::SUPPORTED_THEME_JSON_FEATURES[ $feature_key ], self::KEY_THEME ); if ( isset( $global_settings[ self::KEY_THEME ] ) ) { $feature_value = array_merge( $feature_value, $global_settings[ self::KEY_THEME ] ); } if ( isset( $global_settings[ self::KEY_DEFAULT ] ) ) { $feature_value = array_merge( $feature_value, $global_settings[ self::KEY_DEFAULT ] ); } } else { $feature_value = current( (array) get_theme_support( $feature_key ) ); } if ( ! is_array( $feature_value ) || empty( $feature_value ) ) { continue; } // Avoid reducing font sizes if theme.json is used for the sake of fluid typography. if ( $this->theme_has_theme_json() && self::FEATURE_EDITOR_FONT_SIZES === $feature_key ) { $reduced = false; } if ( $reduced ) { $features[ $feature_key ] = []; foreach ( $feature_value as $item ) { if ( $this->has_required_feature_props( $feature_key, $item ) ) { $features[ $feature_key ][] = wp_array_slice_assoc( $item, self::SUPPORTED_FEATURES[ $feature_key ] ); } } } else { $features[ $feature_key ] = $feature_value; } } return $features; } /** * Determines whether the request is for an AMP page in Reader mode. * * @return bool Whether AMP Reader request. */ public function is_reader_request() { return ( ( amp_is_legacy() || $this->reader_theme_loader->is_theme_overridden() ) && amp_is_request() ); } /** * Print theme support styles. */ public function print_theme_support_styles() { if ( ! $this->is_reader_request() ) { return; } $features = []; if ( $this->reader_theme_loader->is_enabled() ) { $features = AMP_Options_Manager::get_option( Option::PRIMARY_THEME_SUPPORT ); } elseif ( amp_is_legacy() ) { $features = $this->get_theme_support_features(); } if ( empty( $features ) ) { return; } foreach ( array_keys( self::SUPPORTED_FEATURES ) as $feature ) { if ( empty( $features[ $feature ] ) || ! is_array( $features[ $feature ] ) ) { continue; } $value = $features[ $feature ]; switch ( $feature ) { case self::FEATURE_EDITOR_COLOR_PALETTE: $this->print_editor_color_palette_styles( $value ); break; case self::FEATURE_EDITOR_FONT_SIZES: $this->print_editor_font_sizes_styles( $value ); break; case self::FEATURE_EDITOR_GRADIENT_PRESETS: $this->print_editor_gradient_presets_styles( $value ); break; } } // Print the custom properties for the spacing sizes. if ( $this->theme_has_theme_json() && function_exists( 'wp_get_global_settings' ) ) { $this->print_spacing_sizes_custom_properties(); } } /** * Print editor-color-palette styles. * * @param array $color_palette Color palette. */ private function print_editor_color_palette_styles( array $color_palette ) { echo '<style id="amp-wp-theme-support-editor-color-palette">'; foreach ( $color_palette as $color_option ) { if ( ! $this->has_required_feature_props( self::FEATURE_EDITOR_COLOR_PALETTE, $color_option ) ) { continue; } // If not a valid hex color, skip it. if ( ! preg_match( '/^[0-9a-f]{3}[0-9a-f]{3}?$/i', ltrim( $color_option[ self::KEY_COLOR ], '#' ) ) ) { continue; } // There is no standard way to retrieve or derive the `color` style property when the editor color is being used // for the background, so the best alternative at the moment is to guess a good default value based on the // luminance of the editor color. $text_color = 127 > $this->get_relative_luminance_from_hex( $color_option[ self::KEY_COLOR ] ) ? '#fff' : '#000'; printf( ':root .has-%1$s-background-color { background-color: %2$s; color: %3$s; }', sanitize_key( $color_option[ self::KEY_SLUG ] ), $color_option[ self::KEY_COLOR ], // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $text_color // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ); } foreach ( $color_palette as $color_option ) { if ( ! isset( $color_option[ self::KEY_SLUG ], $color_option[ self::KEY_COLOR ] ) ) { continue; } printf( ':root .has-%1$s-color { color: %2$s; }', sanitize_key( $color_option[ self::KEY_SLUG ] ), $color_option[ self::KEY_COLOR ] // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ); } echo '</style>'; } /** * Print editor-font-sizes styles. * * @param array $font_sizes Font sizes. */ private function print_editor_font_sizes_styles( array $font_sizes ) { echo '<style id="amp-wp-theme-support-editor-font-sizes">'; foreach ( $font_sizes as $font_size ) { if ( ! $this->has_required_feature_props( self::FEATURE_EDITOR_FONT_SIZES, $font_size ) ) { continue; } // Just in case the font size is not in the expected format. $font_size[ self::KEY_SIZE ] = $this->get_typography_value_and_unit( $font_size[ self::KEY_SIZE ] ); if ( ! is_array( $font_size[ self::KEY_SIZE ] ) || empty( $font_size[ self::KEY_SIZE ] ) ) { continue; } // Normalize the font size value to a string. $font_size[ self::KEY_SIZE ] = $font_size[ self::KEY_SIZE ]['value'] . $font_size[ self::KEY_SIZE ]['unit']; if ( ! is_string( $font_size[ self::KEY_SIZE ] ) ) { continue; } printf( ':root .is-%1$s-text, :root .has-%1$s-font-size { font-size: %2$s; }', sanitize_key( $font_size[ self::KEY_SLUG ] ), function_exists( 'wp_get_typography_font_size_value' ) // phpcs:disable WordPressVIPMinimum.Functions.StripTags.StripTagsOneParameter ? strip_tags( wp_get_typography_font_size_value( $font_size ) ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped : strip_tags( $font_size[ self::KEY_SIZE ] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped // phpcs:enable WordPressVIPMinimum.Functions.StripTags.StripTagsOneParameter ); } echo '</style>'; } /** * Print editor-gradient-presets styles. * * @param array $gradient_presets Gradient presets. */ private function print_editor_gradient_presets_styles( array $gradient_presets ) { echo '<style id="amp-wp-theme-support-editor-gradient-presets">'; foreach ( $gradient_presets as $gradient_preset ) { if ( ! $this->has_required_feature_props( self::FEATURE_EDITOR_GRADIENT_PRESETS, $gradient_preset ) ) { continue; } printf( '.has-%s-gradient-background { background: %s; }', sanitize_key( $gradient_preset[ self::KEY_SLUG ] ), $gradient_preset[ self::KEY_GRADIENT ] // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ); } echo '</style>'; } /** * Print spacing sizes custom properties. */ private function print_spacing_sizes_custom_properties() { $custom_properties = []; $spacing_sizes = wp_get_global_settings( [ self::KEY_SPACING, self::KEY_SPACING_SIZES ], self::KEY_THEME ); $is_wp_generating_spacing_sizes = 0 !== wp_get_global_settings( [ self::KEY_SPACING, self::KEY_SPACING_SCALE ], self::KEY_THEME )[ self::KEY_STEPS ]; $custom_spacing_size = wp_get_global_settings( [ self::KEY_SPACING, self::KEY_CUSTOM_SPACING_SIZE ], self::KEY_THEME ); if ( ! $is_wp_generating_spacing_sizes && $custom_spacing_size ) { if ( isset( $spacing_sizes[ self::KEY_THEME ] ) ) { $custom_properties = array_merge( $custom_properties, $spacing_sizes[ self::KEY_THEME ] ); } } else { if ( isset( $spacing_sizes[ self::KEY_DEFAULT ] ) ) { $custom_properties = array_merge( $custom_properties, $spacing_sizes[ self::KEY_DEFAULT ] ); } } if ( empty( $custom_properties ) ) { return; } echo '<style id="amp-wp-theme-support-spacing-sizes-custom-properties">'; echo ':root {'; foreach ( $custom_properties as $custom_property ) { if ( ! isset( $custom_property[ self::KEY_SIZE ], $custom_property[ self::KEY_SLUG ] ) ) { continue; } printf( '--wp--preset--spacing--%1$s: %2$s;', sanitize_key( $custom_property[ self::KEY_SLUG ] ), // phpcs:disable WordPressVIPMinimum.Functions.StripTags.StripTagsOneParameter strip_tags( $custom_property[ self::KEY_SIZE ] ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped // phpcs:enable WordPressVIPMinimum.Functions.StripTags.StripTagsOneParameter ); } echo '}'; echo '</style>'; } /** * Get relative luminance from color hex value. * * Copied from `\Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex()`. * * @see https://github.com/WordPress/wordpress-develop/blob/acbbbd18b32b5429264622141a6d058b64f3a5ad/src/wp-content/themes/twentytwentyone/classes/class-twenty-twenty-one-custom-colors.php#L138-L156 * * @param string $hex Color hex value. * @return int Relative luminance value. */ public function get_relative_luminance_from_hex( $hex ) { // Remove the "#" symbol from the beginning of the color. $hex = ltrim( $hex, '#' ); // Make sure there are 6 digits for the below calculations. if ( 3 === strlen( $hex ) ) { $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; } // Get red, green, blue. $red = hexdec( substr( $hex, 0, 2 ) ); $green = hexdec( substr( $hex, 2, 2 ) ); $blue = hexdec( substr( $hex, 4, 2 ) ); // Calculate the luminance. $lum = ( 0.2126 * $red ) + ( 0.7152 * $green ) + ( 0.0722 * $blue ); return (int) round( $lum ); } /** * Checks whether a theme or its parent has a theme.json file. * Checks if `wp_get_global_settings()` exists and bail for WP < 5.9. * * Copied from `wp_theme_has_theme_json()` * * @codeCoverageIgnore * * @see https://github.com/WordPress/wordpress-develop/blob/200868214a1ae0a108dac491677ba82e7541fc8d/src/wp-includes/global-styles-and-settings.php#L384 * * @since 2.4.1 * * @return bool False if `wp_get_global_settings()` not exists or theme.json not found, true otherwise. */ private function theme_has_theme_json() { if ( function_exists( 'wp_theme_has_theme_json' ) ) { return wp_theme_has_theme_json(); } static $theme_has_support = []; $stylesheet = get_stylesheet(); if ( isset( $theme_has_support[ $stylesheet ] ) && /* * Ignore static cache when `WP_DEBUG` is enabled. Why? To avoid interfering with * the theme developer's workflow. Note that core uses a newer wp_get_development_mode() check. */ ! ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ) { return $theme_has_support[ $stylesheet ]; } $stylesheet_directory = get_stylesheet_directory(); $template_directory = get_template_directory(); // This is the same as get_theme_file_path(), which isn't available in load-styles.php context. if ( $stylesheet_directory !== $template_directory && file_exists( $stylesheet_directory . '/theme.json' ) ) { $path = $stylesheet_directory . '/theme.json'; } else { $path = $template_directory . '/theme.json'; } /** This filter is documented in wp-includes/link-template.php */ $path = apply_filters( 'theme_file_path', $path, 'theme.json' ); $theme_has_support[ $stylesheet ] = file_exists( $path ); return $theme_has_support[ $stylesheet ]; } /** * Checks a string for a unit and value and returns an array * consisting of `'value'` and `'unit'`, e.g. array( '42', 'rem' ). * * Copied from `wp_get_typography_value_and_unit()` * * @codeCoverageIgnore * * @see https://github.com/WordPress/WordPress/blob/9caf1c4adeddff2577c24d622ebbbf278a671271/wp-includes/block-supports/typography.php#L297 * * @since 2.4.1 * * @param string|int|float $raw_value Raw size value from theme.json. * @param array $options { * Optional. An associative array of options. Default is empty array. * * @type string $coerce_to Coerce the value to rem or px. Default `'rem'`. * @type int $root_size_value Value of root font size for rem|em <-> px conversion. Default `16`. * @type string[] $acceptable_units An array of font size units. Default `array( 'rem', 'px', 'em' )`; * } * @return array|null The value and unit, or null if the value is empty. */ private function get_typography_value_and_unit( $raw_value, $options = [] ) { if ( function_exists( 'wp_get_typography_value_and_unit' ) ) { return wp_get_typography_value_and_unit( $raw_value, $options ); } if ( ! is_string( $raw_value ) && ! is_int( $raw_value ) && ! is_float( $raw_value ) ) { _doing_it_wrong( __METHOD__, esc_html__( 'Raw size value must be a string, integer, or float.', 'default' ), '2.4.1' ); return null; } if ( empty( $raw_value ) ) { return null; } // Converts numbers to pixel values by default. if ( is_numeric( $raw_value ) ) { $raw_value = $raw_value . 'px'; } $defaults = [ 'coerce_to' => '', 'root_size_value' => 16, 'acceptable_units' => [ 'rem', 'px', 'em' ], ]; $options = wp_parse_args( $options, $defaults ); $acceptable_units_group = implode( '|', $options['acceptable_units'] ); $pattern = '/^(\d*\.?\d+)(' . $acceptable_units_group . '){1,1}$/'; preg_match( $pattern, $raw_value, $matches ); // Bails out if not a number value and a px or rem unit. if ( ! isset( $matches[1] ) || ! isset( $matches[2] ) ) { return null; } $value = $matches[1]; $unit = $matches[2]; /* * Default browser font size. Later, possibly could inject some JS to * compute this `getComputedStyle( document.querySelector( "html" ) ).fontSize`. */ if ( 'px' === $options['coerce_to'] && ( 'em' === $unit || 'rem' === $unit ) ) { $value = $value * $options['root_size_value']; $unit = $options['coerce_to']; } if ( 'px' === $unit && ( 'em' === $options['coerce_to'] || 'rem' === $options['coerce_to'] ) ) { $value = $value / $options['root_size_value']; $unit = $options['coerce_to']; } /* * No calculation is required if swapping between em and rem yet, * since we assume a root size value. Later we might like to differentiate between * :root font size (rem) and parent element font size (em) relativity. */ if ( ( 'em' === $options['coerce_to'] || 'rem' === $options['coerce_to'] ) && ( 'em' === $unit || 'rem' === $unit ) ) { $unit = $options['coerce_to']; } return [ 'value' => round( $value, 3 ), 'unit' => $unit, ]; } }