parent_class = ''; if ( isset( $attributes['_custom_css'] ) ) { $this->custom_css = $attributes['_custom_css']; } } public function add_class_styles( $class_name, $desktop_styles, $tablet_styles = [], $mobile_styles = [] ) { $this->class_styles[] = [ 'class_name' => $class_name, 'desktop_styles' => $desktop_styles, 'tablet_styles' => $tablet_styles, 'mobile_styles' => $mobile_styles ]; } public function generate_css() { $css_output = ''; foreach ( $this->class_styles as $class_style ) { $desktop_styles = $this->remove_empty_css( $class_style['desktop_styles'] ); $tablet_styles = $this->filter_responsive_styles( $desktop_styles, $class_style['tablet_styles'] ); $mobile_styles = $this->filter_responsive_styles( array_merge( $desktop_styles, $tablet_styles ), $class_style['mobile_styles'] ); $desktop_raw = $this->generate_css_for_media_query( 'desktop', $desktop_styles ); $tablet_raw = $this->generate_css_for_media_query( 'tablet', $tablet_styles ); $mobile_raw = $this->generate_css_for_media_query( 'mobile', $mobile_styles ); $desktop_css = AssetsGenerator::minify_css( $desktop_raw ); $tablet_css = AssetsGenerator::minify_css( $tablet_raw ); $mobile_css = AssetsGenerator::minify_css( $mobile_raw ); $parent_selector = $this->get_parent_selector( $class_style['class_name'] ); $css_blocks = []; $addToCssBlocks = function ( $mediaQuery, $max_width, $css ) use ( &$css_blocks, $parent_selector ) { if ( ! empty( $css ) ) { $css_blocks[] = ( '' !== $mediaQuery ) ? "@media screen and (max-width: $max_width) {\n$parent_selector {\n$css\n}\n}" : "$parent_selector {\n$css\n}"; } }; // Always add desktop CSS $addToCssBlocks( '', '', $desktop_css ); // Only add tablet CSS if it differs from desktop if ( $tablet_raw !== $desktop_raw ) { $addToCssBlocks( 'tablet', $this->get_breakpoint( 'tablet' ), $tablet_css ); } // Only add mobile CSS if it differs from desktop AND tablet if ( $mobile_raw !== $tablet_raw ) { $addToCssBlocks( 'mobile', $this->get_breakpoint( 'mobile' ), $mobile_css ); } $css_output .= implode( "\n\n", $css_blocks ) . "\n\n"; }//end foreach $css_output .= $this->get_custom_css(); return preg_replace( '/\s+/', ' ', $css_output ); } public function get_custom_css() { return preg_replace( '/\bselector\b/', $this->parent_class, $this->custom_css ); } public function generate_css_for_media_query( $media_query, $styles ) { if ( empty( $styles ) ) { return ''; } $css_string = implode("\n", array_map( function ( $property, $value ) { return "$property: $value;"; }, array_keys( $styles ), $styles )); return $css_string . "\n"; } public function get_breakpoint( $media_query ) { switch ( $media_query ) { case 'tablet': return '800px'; case 'mobile': return '480px'; default: return '1200px'; } } public function get_parent_selector( $class_name ) { return $this->parent_class ? str_replace( '{{WRAPPER}}', $this->parent_class, $class_name ) : $class_name; } private function remove_empty_css( $base_styles ) { if ( empty( $base_styles ) || ! is_array( $base_styles ) || ( is_array( $base_styles ) && ! count( $base_styles ) ) ) { return []; } $styles = []; foreach ( $base_styles as $prop => $value ) { if ( 'font-family' === $prop ) { // Safety net for styles that bypass the Typography control and set a // bare family name directly. FontStack leaves finished values alone. $value = FontStack::build( $value ); } // Trim value to avoid whitespace-only entries $trimmed = trim( $value ); // // Remove if empty, or if it matches only a unit (like 'px', '%', 'em') without any number if ( $trimmed === '' || preg_match( '/^(px|em|rem|vh|vw|vmin|vmax|cm|mm|in|pt|pc|%)$/i', $trimmed ) ) { continue; } $styles[ $prop ] = $trimmed; } return $styles; } private function filter_responsive_styles( $base_styles, $responsive_styles ) { if ( empty( $responsive_styles ) || ! is_array( $responsive_styles ) ) { return []; } $difference = []; foreach ( $responsive_styles as $prop => $value ) { $trimmed = trim( $value ); // // Remove if empty, or if it matches only a unit (like 'px', '%', 'em') without any number if ( $trimmed === '' || preg_match( '/^(px|em|rem|vh|vw|vmin|vmax|cm|mm|in|pt|pc|%)$/i', $trimmed ) ) { continue; } // Only include if the value is different from base styles if ( ! isset( $base_styles[ $prop ] ) || $base_styles[ $prop ] !== $trimmed ) { $difference[ $prop ] = $trimmed; } } return $difference; } public function get_font_family_css( string $font_name, string $category = '' ): string { // Kept for back-compat; the stack is built centrally now. return FontStack::build( $font_name ); } // Global CSS necessary method public function get_body_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_body_text_color'] ) ) { $css['color'] = $attributes ['global_body_text_color']; } return array_merge( $css, Typography::get_css( $attributes['global_body_typography'], '', $device ) ); } public function get_body_paragraph_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_body_paragraph_space'] ) ) { return Range::get_css([ 'attributeValue' => (array) $attributes ['global_body_paragraph_space'], 'isResponsive' => true, 'defaultValue' => '', 'defaultValueTablet' => '', 'defaultValueMobile' => '', 'hasUnit' => true, 'unitDefaultValue' => 'px', 'property' => 'margin-block-end' ]); } return $css; } public function get_body_anchor_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_link_color'] ) ) { $css['color'] = $attributes ['global_link_color']; } return array_merge( $css, Typography::get_css( $attributes['global_link_typography'], '', $device ) ); } public function get_body_anchor_hover_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_link_hover_color'] ) ) { $css['color'] = $attributes ['global_link_hover_color']; } return array_merge( $css, Typography::get_css( $attributes['global_link_hover_typography'], '', $device ) ); } public function get_global_h1_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_h1_color'] ) ) { $css['color'] = $attributes ['global_h1_color']; } return array_merge( $css, Typography::get_css( $attributes['global_h1_typography'], '', $device ) ); } public function get_global_h2_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_h2_color'] ) ) { $css['color'] = $attributes ['global_h2_color']; } return array_merge( $css, Typography::get_css( $attributes['global_h2_typography'], '', $device ) ); } public function get_global_h3_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_h3_color'] ) ) { $css['color'] = $attributes ['global_h3_color']; } return array_merge( $css, Typography::get_css( $attributes['global_h3_typography'], '', $device ) ); } public function get_global_h4_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_h4_color'] ) ) { $css['color'] = $attributes ['global_h4_color']; } return array_merge( $css, Typography::get_css( $attributes['global_h4_typography'], '', $device ) ); } public function get_global_h5_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_h5_color'] ) ) { $css['color'] = $attributes ['global_h5_color']; } return array_merge( $css, Typography::get_css( $attributes['global_h5_typography'], '', $device ) ); } public function get_global_h6_css( $attributes, $device = '' ) { $css = []; if ( ! empty( $attributes ['global_h6_color'] ) ) { $css['color'] = $attributes ['global_h6_color']; } return array_merge( $css, Typography::get_css( $attributes['global_h6_typography'], '', $device ) ); } }