ProShell v2.0
Dashboard
Server Info
Server: 158.106.128.192
PHP: 8.2.33
home
planet5
public_html
bansibaba.com
wp-includes
2026-09-12 12:09:03
Editing: states.php
Cancel
Save Changes
<?php /** * Block state support for frontend CSS generation. * * Generates scoped CSS for per-instance state styles declared in block attributes, * including pseudo-states (e.g., `style[':hover']`) and responsive states * (e.g., `style['@mobile']` and `style['@mobile'][':hover']`). * * @package WordPress * @since 7.1.0 */ /** * Converts internal preset references to CSS custom property references. * * State styles are emitted as CSS rules and cannot rely on preset classnames. * Converting `var:preset|color|contrast` to * `var(--wp--preset--color--contrast)` ensures preset values are emitted as * declarations by the style engine. * * @since 7.1.0 * * @param mixed $value Style value to normalize. * @return mixed Normalized style value. */ function wp_normalize_state_preset_vars( $value ) { if ( is_array( $value ) ) { foreach ( $value as $key => $nested_value ) { $value[ $key ] = wp_normalize_state_preset_vars( $nested_value ); } return $value; } if ( ! is_string( $value ) || ! str_starts_with( $value, 'var:preset|' ) ) { return $value; } $unwrapped_name = str_replace( '|', '--', substr( $value, strlen( 'var:' ) ) ); return "var(--wp--$unwrapped_name)"; } /** * Normalizes a state style object before generating CSS declarations. * * @since 7.1.0 * * @param array $style State style object. * @return array Normalized state style object. */ function wp_normalize_state_style_for_css_output( $style ) { // Layout is processed separately by wp_render_layout_support_flag(), so we remove it before declaration generation. unset( $style['layout'] ); $style = wp_normalize_state_preset_vars( $style ); return $style; } /** * Adds fallback border-style declarations for visible border declarations. * * CSS does not render border color or width unless a border style is also set. * State styles are emitted as stylesheet rules rather than inline styles, so * they cannot rely on the block-library inline-style attribute fallback rules. * * @since 7.1.0 * * @param array $declarations CSS declarations generated by the style engine. * @return array CSS declarations with fallback border styles applied where needed. */ function wp_get_state_declarations_with_fallback_border_styles( $declarations ) { if ( ! is_array( $declarations ) ) { return $declarations; } $has_border_style = isset( $declarations['border-style'] ) && '' !== $declarations['border-style']; $has_border_color = isset( $declarations['border-color'] ) && '' !== $declarations['border-color']; $has_border_width = isset( $declarations['border-width'] ) && '' !== $declarations['border-width']; if ( ! $has_border_style && ( $has_border_color || $has_border_width ) ) { $declarations['border-style'] = 'solid'; } $sides = array( 'top', 'right', 'bottom', 'left' ); foreach ( $sides as $side ) { $side_style_property = "border-$side-style"; $side_color_property = "border-$side-color"; $side_width_property = "border-$side-width"; $has_side_style = isset( $declarations[ $side_style_property ] ) && '' !== $declarations[ $side_style_property ]; $has_side_color = isset( $declarations[ $side_color_property ] ) && '' !== $declarations[ $side_color_property ]; $has_side_width = isset( $declarations[ $side_width_property ] ) && '' !== $declarations[ $side_width_property ]; if ( ! $has_border_style && ! $has_side_style && ( $has_side_color || $has_side_width ) ) { $declarations[ $side_style_property ] = 'solid'; } } return $declarations; } /** * Adds background reset declarations to prevent gradient/solid color conflicts. * * When a state sets a solid background-color, any gradient applied to the * default state (via `background` shorthand or `background-image`) must be * explicitly cleared. Without this, the gradient image layer remains visible * on top of the solid hover color even when `!important` is used, because * `background-color` and `background-image` are separate CSS properties. * * @since 7.1.0 * * @param array $declarations CSS declarations generated by the style engine. * @return array CSS declarations with background resets applied where needed. */ function wp_get_state_declarations_with_background_resets( $declarations ) { if ( ! is_array( $declarations ) ) { return $declarations; } $has_background_color = isset( $declarations['background-color'] ) && '' !== $declarations['background-color']; $has_background = isset( $declarations['background'] ) && '' !== $declarations['background']; $has_background_image = isset( $declarations['background-image'] ) && '' !== $declarations['background-image']; /* * When the state sets a solid background-color but no gradient of its own, * emit `background-image: unset` to clear any gradient (whether stored as * the `background` shorthand or as `background-image`) that was applied to * the default / normal state via an inline style attribute. The declaration * is marked important when the state rule is registered with the style engine. */ if ( $has_background_color && ! $has_background && ! $has_background_image ) { $declarations['background-image'] = 'unset'; } return $declarations; } /** * Adds fallback dimension styles for aspectRatio and height block-support values. * * @since 7.1.0 * * @param array $state_style State style object. * @return array State style object with fallback dimension styles applied where needed. */ function wp_get_state_style_with_fallback_dimension_styles( $state_style ) { if ( ! is_array( $state_style ) ) { return $state_style; } $dimensions = isset( $state_style['dimensions'] ) && is_array( $state_style['dimensions'] ) ? $state_style['dimensions'] : array(); if ( empty( $dimensions ) ) { return $state_style; } if ( wp_is_explicit_aspect_ratio_value( $dimensions['aspectRatio'] ?? null ) ) { return array_replace_recursive( $state_style, array( 'dimensions' => array( 'minHeight' => 'unset', 'height' => 'unset', ), ) ); } $has_min_height = isset( $dimensions['minHeight'] ) && ( is_string( $dimensions['minHeight'] ) || is_numeric( $dimensions['minHeight'] ) ) && '' !== trim( (string) $dimensions['minHeight'] ); $has_height = isset( $dimensions['height'] ) && ( is_string( $dimensions['height'] ) || is_numeric( $dimensions['height'] ) ) && '' !== trim( (string) $dimensions['height'] ); if ( $has_min_height || $has_height ) { return array_replace_recursive( $state_style, array( 'dimensions' => array( 'aspectRatio' => 'unset', ), ) ); } return $state_style; } /** * Adds a style fragment to a selector-keyed state style group. * * @since 7.1.0 * * @param array $groups Selector-keyed style groups. * @param string|null $selector Block or feature selector. * @param array $style Style fragment. */ function wp_add_state_style_group( &$groups, $selector, $style ) { $key = is_string( $selector ) ? $selector : ''; if ( ! isset( $groups[ $key ] ) ) { $groups[ $key ] = array( 'selector' => $selector, 'style' => array(), ); } $groups[ $key ]['style'] = array_replace_recursive( $groups[ $key ]['style'], $style ); } /** * Splits a state style object into groups based on block feature selectors. * * @since 7.1.0 * * @param array $state_style State style object. * @param array $block_selectors Block selectors metadata. * @return array[] Selector/style groups. */ function wp_get_state_style_groups( $state_style, $block_selectors ) { $groups = array(); foreach ( $state_style as $feature => $feature_styles ) { $feature_selectors = $block_selectors[ $feature ] ?? null; if ( is_string( $feature_selectors ) ) { wp_add_state_style_group( $groups, $feature_selectors, array( $feature => $feature_styles ) ); continue; } if ( is_array( $feature_selectors ) && is_array( $feature_styles ) ) { $remaining_styles = $feature_styles; foreach ( $feature_selectors as $subfeature => $subfeature_selector ) { if ( 'root' === $subfeature || ! is_string( $subfeature_selector ) || ! array_key_exists( $subfeature, $feature_styles ) ) { continue; } wp_add_state_style_group( $groups, $subfeature_selector, array( $feature => array( $subfeature => $feature_styles[ $subfeature ], ), ) ); unset( $remaining_styles[ $subfeature ] ); } if ( array() !== $remaining_styles ) { wp_add_state_style_group( $groups, $feature_selectors['root'] ?? ( $block_selectors['root'] ?? null ), array( $feature => $remaining_styles ) ); } continue; } wp_add_state_style_group( $groups, $block_selectors['root'] ?? null, array( $feature => $feature_styles ) ); } return array_values( $groups ); } /** * Returns a style object with nested state keys removed. * * @since 7.1.0 * * @param array $state_style State style object. * @param array $nested_keys Keys to remove from the root style object. * @return array Root-only style object. */ function wp_get_root_state_style( $state_style, $nested_keys ) { if ( ! is_array( $state_style ) ) { return $state_style; } $root_style = $state_style; foreach ( $nested_keys as $key ) { unset( $root_style[ $key ] ); } return $root_style; } /** * Generates all element selectors for a block root selector. * * @since 7.1.0 * * @param string $root_selector The block root CSS selector. * @return string[] Element selectors keyed by element name. */ function wp_get_block_state_element_selectors( $root_selector ) { if ( ! is_string( $root_selector ) || '' === trim( $root_selector ) ) { return array(); } $block_selectors = wp_split_selector_list( $root_selector ); $element_selectors = array(); foreach ( WP_Theme_JSON::ELEMENTS as $element_name => $element_selector ) { $selectors = array(); foreach ( $block_selectors as $block_selector ) { $block_selector = trim( $block_selector ); if ( '' === $block_selector ) { continue; } if ( $block_selector === $element_selector ) { $selectors = array( $element_selector ); break; } $selector_prefix = "$block_selector "; if ( ! str_contains( $element_selector, ',' ) ) { $selectors[] = $selector_prefix . $element_selector; continue; } $prepended_selectors = array(); foreach ( wp_split_selector_list( $element_selector ) as $selector ) { $prepended_selectors[] = $selector_prefix . $selector; } $selectors[] = implode( ',', $prepended_selectors ); } if ( ! empty( $selectors ) ) { $element_selectors[ $element_name ] = implode( ',', $selectors ); } } return $element_selectors; } /** * Adds a compiled state style rule to a rule list. * * @since 7.1.0 * * @param array $css_rules Style rules. * @param string $state Pseudo-state selector. * @param string|null $selector Block, feature, or element selector. * @param array $style Style object. * @param string|null $rules_group Optional CSS grouping rule, e.g. a media query. */ function wp_add_block_state_style_rule( &$css_rules, $state, $selector, $style, $rules_group = null ) { if ( empty( $style ) || ! is_array( $style ) ) { return; } $compiled = wp_style_engine_get_styles( wp_normalize_state_style_for_css_output( $style ) ); $declarations = $compiled['declarations'] ?? array(); $text_align = $style['typography']['textAlign'] ?? null; // Base text alignment is class-based, so state styles need a declaration. if ( is_string( $text_align ) && '' !== trim( $text_align ) ) { $declarations['text-align'] = $text_align; } if ( empty( $declarations ) ) { return; } $css_rules[] = array( 'state' => $state, 'selector' => $selector, 'declarations' => $declarations, ); if ( ! empty( $rules_group ) ) { $css_rules[ count( $css_rules ) - 1 ]['rules_group'] = $rules_group; } } /** * Builds compiled state style rules, preserving the selector each rule targets. * * @since 7.1.0 * * @param array $state_styles Map of state to style array. * @param WP_Block_Type $block_type Block type. * @param string|null $rules_group Optional CSS grouping rule, e.g. a media query. * @return array[] State style rules. */ function wp_get_block_state_style_rules( $state_styles, $block_type, $rules_group = null ) { $css_rules = array(); $block_selectors = isset( $block_type->selectors ) && is_array( $block_type->selectors ) ? $block_type->selectors : array(); foreach ( $state_styles as $state => $state_style ) { if ( empty( $state_style ) || ! is_array( $state_style ) ) { continue; } foreach ( wp_get_state_style_groups( $state_style, $block_selectors ) as $group ) { wp_add_block_state_style_rule( $css_rules, $state, $group['selector'], $group['style'], $rules_group ); } } return $css_rules; } /** * Returns a unique class for a set of state style rules. * * @since 7.1.0 * * @param string $block_name Block name. * @param array $css_rules State style rules. * @return string Unique class name. */ function wp_get_block_state_unique_class( $block_name, $css_rules ) { return 'wp-states-' . substr( md5( wp_json_encode( array( 'blockName' => $block_name, 'rules' => $css_rules, ) ) ), 0, 8 ); } /** * Splits a selector list by top-level commas. * * @since 7.1.0 * * @param string $selector CSS selector list. * @return string[] Selectors. */ function wp_split_selector_list( $selector ) { if ( ! str_contains( $selector, ',' ) ) { return array( $selector ); } $selectors = array(); $current_selector = ''; $parentheses_depth = 0; $selector_length = strlen( $selector ); for ( $i = 0; $i < $selector_length; $i++ ) { $char = $selector[ $i ]; if ( '(' === $char ) { ++$parentheses_depth; } elseif ( ')' === $char && $parentheses_depth > 0 ) { --$parentheses_depth; } elseif ( ',' === $char && 0 === $parentheses_depth ) { $selectors[] = $current_selector; $current_selector = ''; continue; } $current_selector .= $char; } $selectors[] = $current_selector; return $selectors; } /** * Builds a scoped selector from a block selector and optional pseudo-state. * * @since 7.1.0 * * @param string $base_selector Block-instance scoping selector. * @param string|null $block_selector Block or feature selector from metadata. * @param string $state Pseudo-state selector. * @return string Scoped selector. */ function wp_build_state_selector( $base_selector, $block_selector, $state ) { if ( ! is_string( $block_selector ) || '' === trim( $block_selector ) ) { return $base_selector . $state; } $selectors = wp_split_selector_list( $block_selector ); $scoped_selectors = array(); foreach ( $selectors as $selector ) { $selector = trim( $selector ); if ( '' === $selector ) { continue; } /* * Replace only the leading block selector part (e.g. class name, * attribute selector, ID, or tag name) with the block instance selector. * Preserve anything after that prefix, including modifier classes on the * same element and combinators without spaces. */ if ( preg_match( '/^([.#]?[-_a-zA-Z0-9]+|\[[^\]]+\])/', $selector, $matches ) ) { $scoped_selectors[] = $base_selector . substr( $selector, strlen( $matches[0] ) ) . $state; continue; } $scoped_selectors[] = $base_selector . $state; } return empty( $scoped_selectors ) ? $base_selector . $state : implode( ', ', $scoped_selectors ); } /** * Renders per-instance state styles on the frontend. * * @since 7.1.0 * * @param string $block_content The block's rendered HTML. * @param array $block The block data including blockName and attrs. * @return string Modified block content with injected state styles. */ function wp_render_block_states_support( $block_content, $block ) { if ( empty( $block['blockName'] ) || empty( $block_content ) ) { return $block_content; } $block_name = $block['blockName']; $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name ); if ( ! $block_type ) { return $block_content; } $supported_pseudo_states = WP_Theme_JSON::VALID_BLOCK_PSEUDO_SELECTORS[ $block_name ] ?? array(); $style = $block['attrs']['style'] ?? array(); $css_rules = array(); $viewport_settings = wp_get_global_settings( array( 'viewport' ) ); $responsive_media_queries = WP_Theme_JSON::get_viewport_media_queries( $viewport_settings ); foreach ( $supported_pseudo_states as $pseudo_state ) { if ( empty( $style[ $pseudo_state ] ) || ! is_array( $style[ $pseudo_state ] ) ) { continue; } $css_rules = array_merge( $css_rules, wp_get_block_state_style_rules( array( $pseudo_state => $style[ $pseudo_state ] ), $block_type ) ); } foreach ( $responsive_media_queries as $breakpoint => $media_query ) { if ( empty( $style[ $breakpoint ] ) || ! is_array( $style[ $breakpoint ] ) ) { continue; } $root_state_style = wp_get_root_state_style( $style[ $breakpoint ], array_merge( array( 'elements' ), $supported_pseudo_states ) ); if ( ! empty( $root_state_style ) ) { $css_rules = array_merge( $css_rules, wp_get_block_state_style_rules( array( '' => $root_state_style ), $block_type, $media_query ) ); } if ( ! empty( $style[ $breakpoint ]['elements'] ) && is_array( $style[ $breakpoint ]['elements'] ) ) { $element_selectors = wp_get_block_state_element_selectors( wp_get_block_css_selector( $block_type ) ); foreach ( $style[ $breakpoint ]['elements'] as $element_name => $element_style ) { if ( empty( $element_style ) || ! is_array( $element_style ) || empty( $element_selectors[ $element_name ] ) ) { continue; } $element_pseudo_states = WP_Theme_JSON::VALID_ELEMENT_PSEUDO_SELECTORS[ $element_name ] ?? array(); $root_element_style = wp_get_root_state_style( $element_style, $element_pseudo_states ); wp_add_block_state_style_rule( $css_rules, '', $element_selectors[ $element_name ], $root_element_style, $media_query ); foreach ( $element_pseudo_states as $pseudo_state ) { if ( empty( $element_style[ $pseudo_state ] ) || ! is_array( $element_style[ $pseudo_state ] ) ) { continue; } wp_add_block_state_style_rule( $css_rules, $pseudo_state, $element_selectors[ $element_name ], $element_style[ $pseudo_state ], $media_query ); } } } foreach ( $supported_pseudo_states as $pseudo_state ) { if ( empty( $style[ $breakpoint ][ $pseudo_state ] ) || ! is_array( $style[ $breakpoint ][ $pseudo_state ] ) ) { continue; } $css_rules = array_merge( $css_rules, wp_get_block_state_style_rules( array( $pseudo_state => $style[ $breakpoint ][ $pseudo_state ] ), $block_type, $media_query ) ); } } if ( empty( $css_rules ) ) { return $block_content; } $unique_class = wp_get_block_state_unique_class( $block_name, $css_rules ); /* * Register each state's CSS rules with the block-supports style engine store. * The store deduplicates rules by selector — two block instances with identical * state styles share the same hash class and therefore the same selector, * so only one CSS rule is emitted. The store is flushed to the page by * wp_enqueue_stored_styles() rather than injected inline here. * * State declarations need !important to apply reliably over inline styles and * preset utility classes such as .has-accent-3-background-color. * * Layout-driven state styles (responsive layout, blockGap, child layout) are * handled by wp_render_layout_support_flag() so they share a selector with * the base layout and target the correct (inner) wrapper element. */ $style_rules = array(); foreach ( $css_rules as $rule ) { $declarations = $rule['declarations']; $important_declaration_values = wp_get_state_declarations_with_background_resets( $declarations ); $important_declarations = new WP_Style_Engine_CSS_Declarations(); foreach ( $important_declaration_values as $property => $value ) { $important_declarations->add_declaration( $property, $value, array( 'important' => true, ) ); } $selector = wp_build_state_selector( ".$unique_class", $rule['selector'], $rule['state'] ); $important_style_rule = array( 'selector' => $selector, 'declarations' => $important_declarations, ); if ( ! empty( $rule['rules_group'] ) ) { $important_style_rule['rules_group'] = $rule['rules_group']; } $style_rules[] = $important_style_rule; $fallback_declarations = wp_get_state_declarations_with_fallback_border_styles( $declarations ); foreach ( array_keys( $declarations ) as $property ) { unset( $fallback_declarations[ $property ] ); } if ( empty( $fallback_declarations ) ) { continue; } $fallback_style_rule = array( 'selector' => $selector, 'declarations' => $fallback_declarations, ); if ( ! empty( $rule['rules_group'] ) ) { $fallback_style_rule['rules_group'] = $rule['rules_group']; } $style_rules[] = $fallback_style_rule; } wp_style_engine_get_stylesheet_from_css_rules( $style_rules, array( 'context' => 'block-supports', 'prettify' => false, ) ); $processor = new WP_HTML_Tag_Processor( $block_content ); if ( $processor->next_tag() ) { $processor->add_class( $unique_class ); } return $processor->get_updated_html(); } add_filter( 'render_block', 'wp_render_block_states_support', 10, 2 );
Upload Files
Cancel
Upload
Create New
Cancel
Create
Change Permissions
Cancel
Save
Change Date
Cancel
Save
Rename Item
Cancel
Save
Confirm Delete
Are you sure you want to delete the selected items?
Cancel
Delete