true, 'background-color' => true, 'font-family' => true, 'font-size' => true, 'font-style' => true, 'font-weight' => true, 'line-height' => true, 'letter-spacing' => true, 'word-spacing' => true, 'text-align' => true, 'text-decoration' => true, 'text-transform' => true, 'margin' => true, 'margin-top' => true, 'margin-right' => true, 'margin-bottom' => true, 'margin-left' => true, 'padding' => true, 'padding-top' => true, 'padding-right' => true, 'padding-bottom' => true, 'padding-left' => true, 'display' => true, 'width' => true, 'height' => true, 'max-width' => true, 'min-width' => true, 'border' => true, 'border-radius' => true, 'object-fit' => true, 'vertical-align' => true, ]; $safe = []; foreach ( explode( ';', (string) $style ) as $declaration ) { $parts = explode( ':', $declaration, 2 ); if ( 2 !== count( $parts ) ) continue; $property = strtolower( trim( $parts[0] ) ); $value = trim( $parts[1] ); if ( ! isset( $allowed[ $property ] ) || '' === $value || preg_match( '/[<>\\{}@]|url\\s*\\(|expression\\s*\\(|var\\s*\\(|\/\\*|\\*\\//i', $value ) || false !== strpos( $value, '\\' ) ) continue; $safe[] = $property . ': ' . $value; } return implode( '; ', $safe ); } private static function extract_token( $class, $prefix ) { if ( empty( $class ) || ! is_string( $class ) ) { return ''; } if ( preg_match( '/' . preg_quote( $prefix, '/' ) . '-[0-9]+/', $class, $m ) ) { return $m[0]; } return ''; } private static function css_decl( $prop, $value ) { if ( null === $value || '' === $value ) { return ''; } return $prop . ':' . $value . ';'; } private static function format_font_family( $value, $fallback = 'sans-serif' ) { if ( null === $value || '' === $value ) { return ''; } $raw = trim( (string) $value ); if ( '' === $raw ) { return ''; } if ( 0 === strpos( $raw, 'var(' ) ) { return $raw; } $parts = array_map( 'trim', explode( ',', $raw ) ); $parts = array_filter( $parts, function ( $p ) { return $p !== ''; } ); if ( empty( $parts ) ) { return ''; } $normalized = []; foreach ( $parts as $p ) { $p = trim( $p, "\"'" ); $p = "'" . str_replace( "'", "\\'", $p ) . "'"; $normalized[] = $p; } if ( $fallback && count( $normalized ) === 1 ) { $normalized[] = $fallback; } return implode( ', ', $normalized ); } private static function normalize_font_family( $value ) { if ( null === $value || '' === $value ) { return ''; } $raw = trim( (string) $value ); if ( '' === $raw || 0 === strpos( $raw, 'var(' ) ) { return ''; } $parts = explode( ',', $raw ); $first = trim( (string) ( $parts[0] ?? '' ) ); $starts_quoted = '' !== $first && in_array( $first[0], [ '"', "'" ], true ); $ends_quoted = '' !== $first && in_array( substr( $first, -1 ), [ '"', "'" ], true ); if ( $starts_quoted || $ends_quoted ) { if ( ! $starts_quoted || ! $ends_quoted || $first[0] !== substr( $first, -1 ) ) { return ''; } $first = substr( $first, 1, -1 ); } if ( strlen( $first ) > 120 || ! preg_match( '/^[\p{L}\p{N}][\p{L}\p{N}\p{M} _-]*$/u', $first ) ) { return ''; } return $first; } private static function build_typography_from_prefix( $settings, $prefix ) { if ( ! is_array( $settings ) || '' === $prefix ) { return ''; } $safe = self::sanitize_style_css_settings( [ 'fontFamily' => $settings[ $prefix . 'FontFamily' ] ?? '', 'fontSize' => $settings[ $prefix . 'FontSize' ] ?? '', 'fontWeight' => $settings[ $prefix . 'FontWeight' ] ?? '', 'fontStyle' => $settings[ $prefix . 'FontStyle' ] ?? '', 'lineHeight' => $settings[ $prefix . 'LineHeight' ] ?? '', 'letterSpacing' => $settings[ $prefix . 'LetterSpacing' ] ?? '', 'wordSpacing' => $settings[ $prefix . 'WordSpacing' ] ?? '', 'textAlign' => $settings[ $prefix . 'TextAlign' ] ?? '', 'textDecoration'=> $settings[ $prefix . 'TextDecoration' ] ?? '', 'textTransform' => $settings[ $prefix . 'TextTransform' ] ?? '', 'color' => $settings[ $prefix . 'Color' ] ?? '', ] ); $decls = ''; $font_family = trim( (string) ( $safe['fontFamily'] ?? '' ) ); $trusted_font_family_tokens = [ 'var(--nyxonn-builder-font-family)', 'var(--nx-heading-font-family)', 'var(--nx-button-font-family)', 'var(--nx-font-family)', ]; $safe_literal_font_family = strlen( $font_family ) <= 120 && ( preg_match( '/^[a-z0-9 ,_-]+$/i', $font_family ) || preg_match( "~^(?:\"[a-z0-9 ,_-]+\"|'[a-z0-9 ,_-]+')$~i", $font_family ) ); $safe['fontFamily'] = ( in_array( $font_family, $trusted_font_family_tokens, true ) || $safe_literal_font_family ) ? $font_family : ''; if ( $safe['fontFamily'] !== '' ) { $decls .= self::css_decl( 'font-family', self::format_font_family( $safe['fontFamily'] ) ); } if ( '' !== $safe['fontSize'] ) { $decls .= self::css_decl( 'font-size', esc_attr( $safe['fontSize'] ) ); } if ( ! empty( $safe['fontWeight'] ) ) { $decls .= self::css_decl( 'font-weight', esc_attr( $safe['fontWeight'] ) ); } $font_style = $safe['fontStyle']; if ( $font_style ) { $decls .= self::css_decl( 'font-style', $font_style ); } if ( '' !== $safe['lineHeight'] ) { $decls .= self::css_decl( 'line-height', esc_attr( $safe['lineHeight'] ) ); } if ( '' !== $safe['letterSpacing'] ) { $decls .= self::css_decl( 'letter-spacing', esc_attr( $safe['letterSpacing'] ) ); } if ( '' !== $safe['wordSpacing'] ) { $decls .= self::css_decl( 'word-spacing', esc_attr( $safe['wordSpacing'] ) ); } if ( ! empty( $safe['textAlign'] ) ) { $decls .= self::css_decl( 'text-align', esc_attr( $safe['textAlign'] ) ); } if ( ! empty( $safe['textDecoration'] ) ) { $decls .= self::css_decl( 'text-decoration', esc_attr( $safe['textDecoration'] ) ); } if ( ! empty( $safe['textTransform'] ) ) { $decls .= self::css_decl( 'text-transform', esc_attr( $safe['textTransform'] ) ); } if ( ! empty( $safe['color'] ) ) { $decls .= self::css_decl( 'color', esc_attr( $safe['color'] ) ); } return $decls; } private static function build_google_font_links( $layout ) { if ( class_exists( Performance_Settings::class ) && Performance_Settings::google_fonts_disabled() ) { return ''; } $settings = Global_Settings::get_settings(); $typography = $settings['typography'] ?? []; $fonts = []; // Keep this list in sync with SYSTEM_FONT_FAMILIES in fontStore.js. // PHP needs the same classification when building frontend requests. $system_fonts = array_fill_keys( array_map( 'strtolower', [ 'Arial', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Georgia', 'Impact', 'Lucida Console', 'Lucida Sans Unicode', 'Palatino Linotype', 'Tahoma', 'Times New Roman', 'Trebuchet MS', 'Verdana', 'system-ui', 'ui-sans-serif', 'ui-serif', 'ui-monospace', 'monospace', 'serif', 'sans-serif', ] ), true ); $generic_fonts = array_fill_keys( [ 'serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui', 'ui-serif', 'ui-sans-serif', 'ui-monospace', 'ui-rounded', 'math', 'emoji', 'fangsong', '-apple-system', 'blinkmacsystemfont', 'inherit', 'initial', 'unset', 'revert', 'revert-layer', ], true ); $custom_fonts = []; if ( class_exists( Assets_Manager::class ) ) { foreach ( Assets_Manager::get_fonts() as $font ) { if ( is_array( $font ) ) { $custom_name = self::normalize_font_family( $font['family'] ?? '' ); if ( $custom_name ) { $custom_fonts[ strtolower( $custom_name ) ] = true; } } } } $add = function ( $value ) use ( &$fonts, $system_fonts, $generic_fonts, $custom_fonts ) { $name = self::normalize_font_family( $value ); if ( ! $name ) { return; } $key = strtolower( $name ); if ( isset( $system_fonts[ $key ] ) || isset( $generic_fonts[ $key ] ) || isset( $custom_fonts[ $key ] ) ) { return; } if ( isset( $fonts[ $key ] ) ) { return; } $fonts[ $key ] = $name; }; $add( $typography['fontFamily'] ?? '' ); $add( $typography['headingFontFamily'] ?? '' ); $add( $typography['buttonFontFamily'] ?? '' ); $elements = $typography['elements'] ?? []; if ( is_array( $elements ) ) { foreach ( $elements as $el ) { if ( is_array( $el ) ) { if ( ! empty( $el['fontFamily'] ) ) { $add( $el['fontFamily'] ); } $responsive = $el['responsive'] ?? []; if ( is_array( $responsive ) ) { if ( ! empty( $responsive['tablet']['fontFamily'] ) ) { $add( $responsive['tablet']['fontFamily'] ); } if ( ! empty( $responsive['mobile']['fontFamily'] ) ) { $add( $responsive['mobile']['fontFamily'] ); } } } } } if ( is_array( $layout ) ) { foreach ( $layout as $section ) { $rows = $section['rows'] ?? []; if ( ! is_array( $rows ) ) { continue; } foreach ( $rows as $row ) { $columns = $row['columns'] ?? []; if ( ! is_array( $columns ) ) { continue; } foreach ( $columns as $col ) { $modules = $col['modules'] ?? []; if ( ! is_array( $modules ) ) { continue; } foreach ( $modules as $module ) { $m_settings = $module['settings'] ?? []; if ( is_array( $m_settings ) ) { $font_keys = [ 'fontFamily', 'iconBoxTitleFontFamily', 'iconBoxDescFontFamily', 'navMenuFontFamily' ]; foreach ( $font_keys as $font_key ) { if ( ! empty( $m_settings[ $font_key ] ) ) { $add( $m_settings[ $font_key ] ); } } $responsive = $m_settings['responsive'] ?? []; if ( is_array( $responsive ) ) { foreach ( $font_keys as $font_key ) { if ( ! empty( $responsive['tablet'][ $font_key ] ) ) { $add( $responsive['tablet'][ $font_key ] ); } if ( ! empty( $responsive['mobile'][ $font_key ] ) ) { $add( $responsive['mobile'][ $font_key ] ); } } } } } } } } } if ( empty( $fonts ) ) { return ''; } $weights = '300;400;600;700'; $families = array_values( $fonts ); sort( $families ); if ( Performance_Settings::is_enabled( 'optimize_google_fonts' ) ) { $queries = []; foreach ( $families as $family ) { $queries[] = 'family=' . str_replace( '%20', '+', rawurlencode( $family ) ) . ':wght@' . $weights; } wp_enqueue_style( 'nyxonn-builder-google-fonts', esc_url_raw( 'https://fonts.googleapis.com/css2?' . implode( '&', $queries ) . '&display=swap' ), [], NYXONN_BUILDER_VERSION ); return ''; } foreach ( $families as $family ) { $family_param = str_replace( '%20', '+', rawurlencode( $family ) ); wp_enqueue_style( 'nyxonn-builder-font-' . md5( $family ), esc_url_raw( 'https://fonts.googleapis.com/css2?family=' . $family_param . ':wght@' . $weights . '&display=swap' ), [], NYXONN_BUILDER_VERSION ); } return ''; } /** Allow only the markup and attributes needed by core Heading and Icon Box modules. */ private static function core_module_render_allowed_html() { $style_attribute = [ 'style' => true ]; return [ 'a' => [ 'href' => true, 'target' => true, 'rel' => true, 'class' => true, 'id' => true, 'title' => true, 'aria-label' => true, 'aria-describedby' => true, ], 'div' => array_merge( [ 'class' => true, 'id' => true, 'title' => true, 'role' => true, 'aria-hidden' => true, 'aria-label' => true ], $style_attribute ), 'span' => array_merge( [ 'class' => true, 'id' => true, 'title' => true, 'role' => true, 'aria-hidden' => true, 'aria-label' => true ], $style_attribute ), 'p' => array_merge( [ 'class' => true, 'id' => true, 'title' => true ], $style_attribute ), 'br' => [], 'strong' => [ 'class' => true ], 'b' => [ 'class' => true ], 'em' => [ 'class' => true ], 'i' => [ 'class' => true, 'aria-hidden' => true, 'role' => true ], 'img' => [ 'src' => true, 'alt' => true, 'width' => true, 'height' => true, 'loading' => true, 'decoding' => true, 'class' => true, 'id' => true, 'title' => true ], 'h1' => array_merge( [ 'class' => true, 'id' => true ], $style_attribute ), 'h2' => array_merge( [ 'class' => true, 'id' => true ], $style_attribute ), 'h3' => array_merge( [ 'class' => true, 'id' => true ], $style_attribute ), 'h4' => array_merge( [ 'class' => true, 'id' => true ], $style_attribute ), 'h5' => array_merge( [ 'class' => true, 'id' => true ], $style_attribute ), 'h6' => array_merge( [ 'class' => true, 'id' => true ], $style_attribute ), ]; } /** Apply the narrow inline-style policy after WordPress has sanitized the HTML structure. */ private static function sanitize_core_module_render_styles( $markup ) { return preg_replace_callback( '/<([a-z][^<>]*)>/i', static function ( $tag_match ) { $tag = preg_replace_callback( '/\sstyle="([^"]*)"/i', static function ( $style_match ) { $style = html_entity_decode( $style_match[1], ENT_QUOTES | ENT_HTML5, 'UTF-8' ); $safe = self::sanitize_core_module_style( $style ); return '' === $safe ? '' : ' style="' . esc_attr( $safe ) . '"'; }, $tag_match[1] ); return '<' . $tag . '>'; }, $markup ); } private static function with_unit( $value, $unit ) { if ( null === $value || '' === $value ) { return ''; } $raw = (string) $value; if ( preg_match( '/[a-z%]/i', $raw ) ) { return $raw; } return $raw . $unit; } private static function safe_layout_length( $value, $keywords = [] ) { if ( null === $value || '' === $value ) { return ''; } $raw = strtolower( trim( (string) $value ) ); if ( in_array( $raw, $keywords, true ) ) { return $raw; } return strlen( $raw ) <= 40 && preg_match( '/^(?:0|(?:\d+(?:\.\d+)?|\.\d+)(?:px|%|vw|vh|em|rem))$/i', $raw ) ? $raw : ''; } private static function safe_layout_number( $value ) { if ( null === $value || '' === $value ) { return ''; } $raw = trim( (string) $value ); return strlen( $raw ) <= 20 && preg_match( '/^(?:0|\d+(?:\.\d+)?)$/', $raw ) ? $raw : ''; } private static function safe_layout_integer( $value, $min = 0, $max = 999 ) { $raw = self::safe_layout_number( $value ); if ( '' === $raw || ! ctype_digit( $raw ) ) { return ''; } $number = intval( $raw ); return $number >= $min && $number <= $max ? (string) $number : ''; } private static function safe_position_integer( $value, $min = -9999, $max = 9999 ) { if ( null === $value || '' === $value ) { return ''; } $raw = trim( (string) $value ); if ( ! preg_match( '/^-?\d+$/', $raw ) ) { return ''; } $number = intval( $raw ); return $number >= $min && $number <= $max ? (string) $number : ''; } private static function safe_grid_track_list( $value ) { if ( null === $value || '' === $value ) { return ''; } $raw = strtolower( preg_replace( '/\s+/', ' ', trim( (string) $value ) ) ); if ( '' === $raw || strlen( $raw ) > 180 || preg_match( '/[;{}<>"\'\\\\]/', $raw ) || ! preg_match( '/^[a-z0-9%.,()\-+*\/\s]+$/', $raw ) ) { return ''; } preg_match_all( '/[a-z-]+/', $raw, $matches ); $allowed = [ 'repeat', 'minmax', 'auto', 'min-content', 'max-content', 'fit-content', 'fr', 'px', 'em', 'rem', 'vw', 'vh' ]; foreach ( $matches[0] as $word ) { if ( ! in_array( $word, $allowed, true ) ) { return ''; } } return $raw; } private static function safe_layout_option( $value, $allowed ) { return is_string( $value ) && in_array( $value, $allowed, true ) ? $value : ''; } private static function sanitize_layout_css_settings( $s ) { if ( ! is_array( $s ) ) { return []; } $alignment = [ '', 'normal', 'stretch', 'start', 'center', 'end', 'flex-start', 'flex-end', 'baseline', 'space-between', 'space-around', 'space-evenly', 'left', 'right' ]; $s['display'] = self::safe_layout_option( $s['display'] ?? '', [ '', 'block', 'flex', 'grid' ] ); $s['flexDirection'] = self::safe_layout_option( $s['flexDirection'] ?? '', [ '', 'row', 'row-reverse', 'column', 'column-reverse' ] ); $s['flexWrap'] = self::safe_layout_option( $s['flexWrap'] ?? '', [ '', 'nowrap', 'wrap', 'wrap-reverse' ] ); foreach ( [ 'justifyContent', 'alignItems', 'alignContent', 'gridJustifyItems', 'gridAlignItems', 'gridJustifyContent', 'gridAlignContent' ] as $key ) { $s[ $key ] = self::safe_layout_option( $s[ $key ] ?? '', $alignment ); } $s['overflow'] = self::safe_layout_option( $s['overflow'] ?? '', [ '', 'visible', 'hidden', 'auto', 'scroll' ] ); $s['alignSelf'] = self::safe_layout_option( $s['alignSelf'] ?? '', [ '', 'auto', 'stretch', 'start', 'center', 'end', 'flex-start', 'flex-end', 'baseline' ] ); $s['justifySelf'] = self::safe_layout_option( $s['justifySelf'] ?? '', [ '', 'auto', 'stretch', 'start', 'center', 'end' ] ); $s['gridColumns'] = self::safe_grid_track_list( $s['gridColumns'] ?? '' ); $s['gridRows'] = self::safe_grid_track_list( $s['gridRows'] ?? '' ); $s['gridAutoFlow'] = self::safe_layout_option( $s['gridAutoFlow'] ?? '', [ '', 'row', 'column', 'dense', 'row dense', 'column dense' ] ); $s['gridAutoColumns'] = self::safe_grid_track_list( $s['gridAutoColumns'] ?? '' ); $s['gridAutoRows'] = self::safe_grid_track_list( $s['gridAutoRows'] ?? '' ); $s['rowAlign'] = self::safe_layout_option( $s['rowAlign'] ?? '', [ '', 'left', 'center', 'right' ] ); $s['position'] = self::safe_layout_option( $s['position'] ?? '', [ '', 'static', 'relative', 'absolute', 'fixed', 'sticky' ] ); foreach ( [ 'top', 'right', 'bottom', 'left' ] as $key ) { $raw = strtolower( trim( (string) ( $s[ $key ] ?? '' ) ) ); $s[ $key ] = 'auto' === $raw ? 'auto' : self::safe_style_length( $raw, true ); } $s['zIndex'] = self::safe_position_integer( $s['zIndex'] ?? '' ); foreach ( [ 'hideDesktop', 'hideTablet', 'hideMobile' ] as $key ) { $s[ $key ] = true === ( $s[ $key ] ?? false ) || 1 === ( $s[ $key ] ?? false ) || '1' === ( $s[ $key ] ?? false ) || 'true' === ( $s[ $key ] ?? false ); } $s['stickyEnabled'] = true === ( $s['stickyEnabled'] ?? false ) || 1 === ( $s['stickyEnabled'] ?? false ) || '1' === ( $s['stickyEnabled'] ?? false ) || 'true' === ( $s['stickyEnabled'] ?? false ); $s['stickySide'] = self::safe_layout_option( $s['stickySide'] ?? '', [ '', 'top', 'bottom' ] ); $s['stickyScope'] = self::safe_layout_option( $s['stickyScope'] ?? '', [ '', 'parent', 'column', 'section', 'page' ] ); $s['stickyDevices'] = self::safe_layout_option( $s['stickyDevices'] ?? '', [ '', 'desktop', 'desktop-tablet', 'tablet-mobile', 'mobile', 'all' ] ); foreach ( [ 'stickyTop', 'stickyBottom' ] as $key ) { $s[ $key ] = self::safe_style_length( $s[ $key ] ?? '', true ); } $s['stickyZIndex'] = self::safe_position_integer( $s['stickyZIndex'] ?? '', 0, 9999 ); $s['widthValue'] = self::safe_layout_length( $s['widthValue'] ?? '', [ 'auto' ] ); $s['minWidth'] = self::safe_layout_length( $s['minWidth'] ?? '' ); $s['maxWidthValue'] = self::safe_layout_length( $s['maxWidthValue'] ?? '', [ 'none' ] ); $s['heightValue'] = self::safe_layout_length( $s['heightValue'] ?? '', [ 'auto' ] ); $s['minHeight'] = self::safe_layout_length( $s['minHeight'] ?? '' ); $s['maxHeight'] = self::safe_layout_length( $s['maxHeight'] ?? '', [ 'none' ] ); $s['flexGrow'] = self::safe_layout_number( $s['flexGrow'] ?? '' ); $s['flexShrink'] = self::safe_layout_number( $s['flexShrink'] ?? '' ); $s['order'] = self::safe_layout_integer( $s['order'] ?? '' ); $s['gridColumnSpan'] = self::safe_layout_integer( $s['gridColumnSpan'] ?? '', 1, 12 ); $s['gridRowSpan'] = self::safe_layout_integer( $s['gridRowSpan'] ?? '', 1, 12 ); return $s; } private static function safe_style_length( $value, $allow_negative = false ) { if ( null === $value || '' === $value ) { return ''; } $raw = strtolower( trim( (string) $value ) ); if ( '0' === $raw ) { return '0'; } $sign = $allow_negative ? '-?' : ''; return strlen( $raw ) <= 40 && preg_match( '/^' . $sign . '(?:\d+(?:\.\d+)?|\.\d+)(?:px|%|em|rem|vw|vh)$/i', $raw ) ? $raw : ''; } private static function safe_style_number( $value, $min, $max ) { if ( null === $value || '' === $value ) { return ''; } $raw = trim( (string) $value ); if ( ! preg_match( '/^-?(?:\d+(?:\.\d+)?|\.\d+)$/', $raw ) ) { return ''; } $number = (float) $raw; return $number >= $min && $number <= $max ? (string) $raw : ''; } private static function safe_style_color( $value ) { $raw = trim( (string) ( $value ?? '' ) ); if ( '' === $raw || strlen( $raw ) > 120 || preg_match( '/[;{}<>"\'\\\\]/', $raw ) ) { return ''; } return preg_match( '/^(?:#[0-9a-f]{3,8}|(?:rgb|rgba|hsl|hsla)\([0-9.%+\-\s,]+\)|transparent|currentcolor|var\(--nx-[a-z0-9_-]+\))$/i', $raw ) ? $raw : ''; } private static function safe_style_angle( $value ) { $raw = strtolower( trim( (string) ( $value ?? '' ) ) ); return strlen( $raw ) <= 30 && preg_match( '/^-?(?:\d+(?:\.\d+)?|\.\d+)deg$/', $raw ) ? $raw : ''; } private static function sanitize_style_css_settings( $s ) { $s = self::sanitize_layout_css_settings( is_array( $s ) ? $s : [] ); foreach ( [ 'color', 'bgColor', 'btnTextColor', 'btnBgColor', 'btnHoverBgColor', 'navMenuItemColor', 'navMenuItemBg', 'navMenuItemHoverColor', 'navMenuItemActiveColor', 'navMenuItemHoverBg', 'navMenuItemActiveBg', 'iconBoxIconColor', 'iconBoxIconBg', 'dividerColor', 'borderColor', 'stickyBg' ] as $key ) { $s[ $key ] = self::safe_style_color( $s[ $key ] ?? '' ); } $s['bgType'] = self::safe_layout_option( $s['bgType'] ?? '', [ '', 'none', 'color', 'solid', 'gradient', 'image', 'video' ] ); $s['bgSize'] = self::safe_layout_option( $s['bgSize'] ?? '', [ '', 'auto', 'cover', 'contain' ] ); $s['bgPosition'] = self::safe_layout_option( $s['bgPosition'] ?? '', [ '', 'center', 'center center', 'top left', 'top center', 'top right', 'center left', 'center right', 'bottom left', 'bottom center', 'bottom right', 'left top', 'center top', 'right top', 'left center', 'right center', 'left bottom', 'center bottom', 'right bottom' ] ); $s['bgRepeat'] = self::safe_layout_option( $s['bgRepeat'] ?? '', [ '', 'no-repeat', 'repeat', 'repeat-x', 'repeat-y', 'space', 'round' ] ); $s['bgAttachment'] = self::safe_layout_option( $s['bgAttachment'] ?? '', [ '', 'scroll', 'fixed', 'local' ] ); $s['bgGradientKind'] = self::safe_layout_option( $s['bgGradientKind'] ?? '', [ '', 'linear', 'radial' ] ); $s['bgGradientDirection'] = self::safe_layout_option( $s['bgGradientDirection'] ?? '', [ '', 'to top', 'to right', 'to bottom', 'to left', 'to top right', 'to bottom right', 'to bottom left', 'to top left' ] ); $s['bgGradientAngle'] = self::safe_style_angle( $s['bgGradientAngle'] ?? '' ); $s['bgGradientRadialShape'] = self::safe_layout_option( $s['bgGradientRadialShape'] ?? '', [ '', 'circle', 'ellipse' ] ); $s['bgGradientRadialPosition'] = self::safe_layout_option( $s['bgGradientRadialPosition'] ?? '', [ '', 'center', 'top', 'right', 'bottom', 'left', 'top left', 'top right', 'bottom left', 'bottom right' ] ); $s['bgGradientStart'] = self::safe_style_color( $s['bgGradientStart'] ?? '' ); $s['bgGradientEnd'] = self::safe_style_color( $s['bgGradientEnd'] ?? '' ); $safe_stops = []; foreach ( array_slice( is_array( $s['bgGradientStops'] ?? null ) ? $s['bgGradientStops'] : [], 0, 12 ) as $stop ) { $color = self::safe_style_color( $stop['color'] ?? '' ); $pos = self::safe_style_number( $stop['pos'] ?? '', 0, 100 ); if ( $color ) { $safe_stops[] = [ 'color' => $color, 'pos' => $pos ]; } } $s['bgGradientStops'] = $safe_stops; $s['borderStyle'] = self::safe_layout_option( $s['borderStyle'] ?? '', [ '', 'none', 'solid', 'dashed', 'dotted', 'double' ] ); foreach ( [ 'borderRadius', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius', 'paddingTop', 'paddingRight', 'paddingBottom', 'paddingLeft' ] as $key ) { $s[ $key ] = self::safe_style_length( $s[ $key ] ?? '' ); } foreach ( [ 'marginTop', 'marginRight', 'marginBottom', 'marginLeft' ] as $key ) { $s[ $key ] = self::safe_style_length( $s[ $key ] ?? '', true ); } foreach ( [ 'imgWidth', 'imgMaxWidth', 'imgHeight', 'galleryGap', 'galleryRowGap', 'galleryRadius', 'dividerWidth', 'dividerHeight', 'iconBoxIconSize', 'iconBoxImageWidth', 'iconBoxGap', 'iconSpacing', 'btnPaddingTop', 'btnPaddingRight', 'btnPaddingBottom', 'btnPaddingLeft' ] as $key ) { $s[ $key ] = self::safe_style_length( $s[ $key ] ?? '' ); } $s['objectFit'] = self::safe_layout_option( $s['objectFit'] ?? '', [ '', 'cover', 'contain', 'fill', 'none', 'scale-down' ] ); $s['objectPosition'] = self::safe_layout_option( $s['objectPosition'] ?? '', [ '', 'center', 'center center', 'top', 'right', 'bottom', 'left', 'top left', 'top right', 'bottom left', 'bottom right' ] ); $s['opacity'] = self::safe_style_number( $s['opacity'] ?? '', 0, 1 ); $s['fontStyle'] = self::safe_layout_option( $s['fontStyle'] ?? '', [ '', 'normal', 'italic', 'oblique' ] ); $font_family = trim( (string) ( $s['fontFamily'] ?? '' ) ); $trusted_font_family_tokens = [ 'var(--nyxonn-builder-font-family)', 'var(--nx-heading-font-family)', 'var(--nx-button-font-family)', 'var(--nx-font-family)', ]; $safe_literal_font_family = strlen( $font_family ) <= 120 && ( preg_match( '/^[a-z0-9 ,_-]+$/i', $font_family ) || preg_match( "~^(?:\"[a-z0-9 ,_-]+\"|'[a-z0-9 ,_-]+')$~i", $font_family ) ); $s['fontFamily'] = ( in_array( $font_family, $trusted_font_family_tokens, true ) || $safe_literal_font_family ) ? $font_family : ''; $font_weight = trim( (string) ( $s['fontWeight'] ?? '' ) ); $s['fontWeight'] = ( preg_match( '/^(?:normal|bold|[1-9]00)$/', $font_weight ) || preg_match( '/^var\(--nx-[a-z0-9_-]+\)$/i', $font_weight ) ) ? $font_weight : ''; $s['fontSize'] = self::safe_style_length( $s['fontSize'] ?? '' ); $s['lineHeight'] = self::safe_style_number( $s['lineHeight'] ?? '', 0, 10 ) ?: self::safe_style_length( $s['lineHeight'] ?? '' ); $s['letterSpacing'] = self::safe_style_length( $s['letterSpacing'] ?? '', true ); $s['wordSpacing'] = self::safe_style_length( $s['wordSpacing'] ?? '', true ); $s['textAlign'] = self::safe_layout_option( $s['textAlign'] ?? '', [ '', 'left', 'center', 'right', 'justify', 'start', 'end' ] ); $s['textDecoration'] = self::safe_layout_option( $s['textDecoration'] ?? '', [ '', 'none', 'underline', 'line-through', 'overline' ] ); $s['textTransform'] = self::safe_layout_option( $s['textTransform'] ?? '', [ '', 'none', 'uppercase', 'lowercase', 'capitalize' ] ); return $s; } private static function build_extension_style_decls( $s, $context = [] ) { $decls = apply_filters( 'nyxonn_fx_render_style_effect_declarations', '', is_array( $s ) ? $s : [], is_array( $context ) ? $context : [] ); return is_string( $decls ) ? $decls : ''; } private static function infer_layout_display( $s, $fallback = '' ) { $s = self::sanitize_layout_css_settings( $s ); if ( ! empty( $s['display'] ) ) { return $s['display']; } if ( in_array( $fallback, [ 'block', 'flex', 'grid' ], true ) ) { return $fallback; } if ( ! empty( $s['gridColumns'] ) || ! empty( $s['gridRows'] ) ) { return 'grid'; } if ( ! empty( $s['flexDirection'] ) || ! empty( $s['flexWrap'] ) || ! empty( $s['justifyContent'] ) || ! empty( $s['alignItems'] ) || ! empty( $s['alignContent'] ) ) { return 'flex'; } return $fallback; } private static function build_container_decls( $s, $inherited_display = '' ) { $s = self::sanitize_layout_css_settings( $s ); $decls = ''; $display = $s['display'] ?? ''; if ( '' === $display && in_array( $inherited_display, [ 'block', 'flex', 'grid' ], true ) ) { $display = $inherited_display; } if ( '' === $display ) { $has_grid = ! empty( $s['gridColumns'] ) || ! empty( $s['gridRows'] ) || ! empty( $s['gridAutoFlow'] ) || ! empty( $s['gridAutoColumns'] ) || ! empty( $s['gridAutoRows'] ) || ! empty( $s['gridJustifyItems'] ) || ! empty( $s['gridAlignItems'] ) || ! empty( $s['gridJustifyContent'] ) || ! empty( $s['gridAlignContent'] ); $has_flex = ! empty( $s['flexDirection'] ) || ! empty( $s['flexWrap'] ) || ! empty( $s['justifyContent'] ) || ! empty( $s['alignItems'] ); if ( $has_grid ) { $display = 'grid'; } elseif ( $has_flex ) { $display = 'flex'; } } if ( in_array( $display, [ 'flex', 'grid', 'block' ], true ) ) { $decls .= self::css_decl( 'display', esc_attr( $display ) ); } else { return $decls; } if ( 'flex' === $display ) { $decls .= self::css_decl( 'flex-direction', esc_attr( $s['flexDirection'] ?? 'row' ) ); $decls .= self::css_decl( 'flex-wrap', esc_attr( $s['flexWrap'] ?? 'nowrap' ) ); $decls .= self::css_decl( 'justify-content', esc_attr( $s['justifyContent'] ?? 'flex-start' ) ); $decls .= self::css_decl( 'align-items', esc_attr( $s['alignItems'] ?? 'stretch' ) ); if ( ! empty( $s['alignContent'] ) ) { $decls .= self::css_decl( 'align-content', esc_attr( $s['alignContent'] ) ); } } if ( 'grid' === $display ) { if ( ! empty( $s['gridColumns'] ) ) { $decls .= self::css_decl( 'grid-template-columns', esc_attr( $s['gridColumns'] ) ); } if ( ! empty( $s['gridRows'] ) ) { $decls .= self::css_decl( 'grid-template-rows', esc_attr( $s['gridRows'] ) ); } if ( ! empty( $s['gridAutoFlow'] ) ) { $decls .= self::css_decl( 'grid-auto-flow', esc_attr( $s['gridAutoFlow'] ) ); } if ( ! empty( $s['gridAutoColumns'] ) ) { $decls .= self::css_decl( 'grid-auto-columns', esc_attr( $s['gridAutoColumns'] ) ); } if ( ! empty( $s['gridAutoRows'] ) ) { $decls .= self::css_decl( 'grid-auto-rows', esc_attr( $s['gridAutoRows'] ) ); } if ( ! empty( $s['gridJustifyItems'] ) ) { $decls .= self::css_decl( 'justify-items', esc_attr( $s['gridJustifyItems'] ) ); } if ( ! empty( $s['gridAlignItems'] ) ) { $decls .= self::css_decl( 'align-items', esc_attr( $s['gridAlignItems'] ) ); } if ( ! empty( $s['gridJustifyContent'] ) ) { $decls .= self::css_decl( 'justify-content', esc_attr( $s['gridJustifyContent'] ) ); } if ( ! empty( $s['gridAlignContent'] ) ) { $decls .= self::css_decl( 'align-content', esc_attr( $s['gridAlignContent'] ) ); } } $requested_gap_unit = $s['gapUnit'] ?? 'px'; $gap_unit = in_array( $requested_gap_unit, [ 'px', '%', 'vw', 'vh', 'em', 'rem' ], true ) ? $requested_gap_unit : 'px'; $has_row_gap = isset( $s['rowGap'] ) && '' !== $s['rowGap']; $has_column_gap = isset( $s['columnGap'] ) && '' !== $s['columnGap']; if ( ! $has_row_gap && ! $has_column_gap && isset( $s['gap'] ) && '' !== $s['gap'] ) { $gap = self::safe_layout_length( preg_match( '/[a-z%]/i', (string) $s['gap'] ) ? $s['gap'] : $s['gap'] . $gap_unit ); if ( '' !== $gap ) { $decls .= self::css_decl( 'gap', esc_attr( $gap ) ); } } if ( $has_row_gap ) { $value = self::safe_layout_length( self::with_unit( $s['rowGap'], $gap_unit ) ); if ( '' !== $value ) { $decls .= self::css_decl( 'row-gap', esc_attr( $value ) ); } } if ( $has_column_gap ) { $value = self::safe_layout_length( self::with_unit( $s['columnGap'], $gap_unit ) ); if ( '' !== $value ) { $decls .= self::css_decl( 'column-gap', esc_attr( $value ) ); } } return $decls; } private static function build_box_decls( $s ) { $s = self::sanitize_style_css_settings( $s ); $decls = ''; if ( ! empty( $s['bgColor'] ) ) { $decls .= self::css_decl( 'background-color', esc_attr( $s['bgColor'] ) ); } $bg_type = $s['bgType'] ?? ''; if ( '' === $bg_type ) { $has_stops = isset( $s['bgGradientStops'] ) && is_array( $s['bgGradientStops'] ) && count( $s['bgGradientStops'] ) >= 2; $has_legacy = ! empty( $s['bgGradientStart'] ) || ! empty( $s['bgGradientEnd'] ); if ( $has_stops || $has_legacy ) { $bg_type = 'gradient'; } elseif ( ! empty( $s['bgImage'] ) ) { $bg_type = 'image'; } } $bg_image_value = ''; if ( 'gradient' === $bg_type ) { $kind = $s['bgGradientKind'] ?? 'linear'; $stops_raw = $s['bgGradientStops'] ?? []; $stops = []; if ( is_array( $stops_raw ) && count( $stops_raw ) >= 2 ) { $count = count( $stops_raw ); foreach ( array_values( $stops_raw ) as $i => $st ) { if ( ! is_array( $st ) || empty( $st['color'] ) ) { continue; } $pos = $st['pos'] ?? null; if ( null === $pos || '' === $pos ) { $pos = ( $count > 1 ) ? round( ( $i / ( $count - 1 ) ) * 100 ) : 0; } $pos = max( 0, min( 100, floatval( $pos ) ) ); $stops[] = trim( (string) $st['color'] ) . ' ' . $pos . '%'; } } if ( count( $stops ) < 2 ) { $start = ! empty( $s['bgGradientStart'] ) ? (string) $s['bgGradientStart'] : '#000000'; $end = ! empty( $s['bgGradientEnd'] ) ? (string) $s['bgGradientEnd'] : '#ffffff'; $stops = [ trim( $start ) . ' 0%', trim( $end ) . ' 100%' ]; } if ( 'radial' === $kind ) { $shape = ! empty( $s['bgGradientRadialShape'] ) ? $s['bgGradientRadialShape'] : 'ellipse'; $at = ! empty( $s['bgGradientRadialPosition'] ) ? ' at ' . (string) $s['bgGradientRadialPosition'] : ''; $bg_image_value = 'radial-gradient(' . $shape . $at . ', ' . implode( ', ', $stops ) . ')'; } else { $angle = trim( (string) ( $s['bgGradientAngle'] ?? '' ) ); $dir = ! empty( $s['bgGradientDirection'] ) ? $s['bgGradientDirection'] : 'to bottom'; $bg_image_value = 'linear-gradient(' . ( $angle ? $angle : (string) $dir ) . ', ' . implode( ', ', $stops ) . ')'; } } elseif ( 'image' === $bg_type || ( empty( $bg_type ) && ! empty( $s['bgImage'] ) ) ) { if ( ! empty( $s['bgImage'] ) ) { $bg_image_value = 'url(' . esc_url( $s['bgImage'] ) . ')'; } } if ( '' !== $bg_image_value ) { $decls .= self::css_decl( 'background-image', esc_attr( $bg_image_value ) ); $decls .= self::css_decl( 'background-size', esc_attr( $s['bgSize'] ?? 'cover' ) ); $decls .= self::css_decl( 'background-position', esc_attr( $s['bgPosition'] ?? 'center' ) ); $decls .= self::css_decl( 'background-repeat', esc_attr( $s['bgRepeat'] ?? 'no-repeat' ) ); } if ( isset( $s['widthValue'] ) && '' !== $s['widthValue'] ) { $decls .= self::css_decl( 'width', esc_attr( $s['widthValue'] ) ); } if ( isset( $s['heightValue'] ) && '' !== $s['heightValue'] ) { $decls .= self::css_decl( 'height', esc_attr( $s['heightValue'] ) ); } foreach ( [ 'Top', 'Right', 'Bottom', 'Left' ] as $side ) { $k = 'padding' . $side; if ( ! empty( $s[ $k ] ) ) { $decls .= self::css_decl( 'padding-' . strtolower( $side ), esc_attr( $s[ $k ] ) ); } } foreach ( [ 'Top', 'Right', 'Bottom', 'Left' ] as $side ) { $k = 'margin' . $side; if ( ! empty( $s[ $k ] ) ) { $decls .= self::css_decl( 'margin-' . strtolower( $side ), esc_attr( $s[ $k ] ) ); } } if ( ! empty( $s['padding'] ) ) { $decls .= self::css_decl( 'padding', esc_attr( $s['padding'] ) ); } if ( ! empty( $s['margin'] ) ) { $decls .= self::css_decl( 'margin', esc_attr( $s['margin'] ) ); } if ( ! empty( $s['border'] ) ) { $decls .= self::css_decl( 'border', esc_attr( $s['border'] ) ); } if ( ! empty( $s['borderRadius'] ) ) { $decls .= self::css_decl( 'border-radius', esc_attr( $s['borderRadius'] ) ); } if ( ! empty( $s['borderStyle'] ) ) { $decls .= self::css_decl( 'border-style', esc_attr( $s['borderStyle'] ) ); } if ( ! empty( $s['borderColor'] ) ) { $decls .= self::css_decl( 'border-color', esc_attr( $s['borderColor'] ) ); } $has_explicit_border_width = false; foreach ( [ 'Top', 'Right', 'Bottom', 'Left' ] as $side ) { $k = 'border' . $side . 'Width'; if ( ! empty( $s[ $k ] ) ) { $has_explicit_border_width = true; $decls .= self::css_decl( 'border-' . strtolower( $side ) . '-width', esc_attr( $s[ $k ] ) ); } } if ( $has_explicit_border_width ) { if ( empty( $s['borderStyle'] ) ) { $decls .= self::css_decl( 'border-style', 'solid' ); } if ( empty( $s['borderColor'] ) ) { $decls .= self::css_decl( 'border-color', '#000000' ); } } if ( ! empty( $s['position'] ) ) { $decls .= self::css_decl( 'position', esc_attr( $s['position'] ) ); } foreach ( [ 'top', 'right', 'bottom', 'left' ] as $offset_side ) { if ( isset( $s[ $offset_side ] ) && '' !== $s[ $offset_side ] ) { $decls .= self::css_decl( $offset_side, esc_attr( $s[ $offset_side ] ) ); } } if ( isset( $s['zIndex'] ) && '' !== $s['zIndex'] ) { $decls .= self::css_decl( 'z-index', esc_attr( (string) $s['zIndex'] ) ); } if ( isset( $s['overflow'] ) && '' !== $s['overflow'] ) { $decls .= self::css_decl( 'overflow', esc_attr( $s['overflow'] ) ); } if ( isset( $s['minHeight'] ) && '' !== $s['minHeight'] ) { $decls .= self::css_decl( 'min-height', esc_attr( $s['minHeight'] ) ); } if ( isset( $s['minWidth'] ) && '' !== $s['minWidth'] ) { $decls .= self::css_decl( 'min-width', esc_attr( $s['minWidth'] ) ); } if ( isset( $s['maxWidthValue'] ) && '' !== $s['maxWidthValue'] ) { $decls .= self::css_decl( 'max-width', esc_attr( $s['maxWidthValue'] ) ); } if ( isset( $s['maxHeight'] ) && '' !== $s['maxHeight'] ) { $decls .= self::css_decl( 'max-height', esc_attr( $s['maxHeight'] ) ); } if ( ! empty( $s['stickyTop'] ) ) { $decls .= self::css_decl( '--nx-sticky-top', esc_attr( $s['stickyTop'] ) ); } if ( ! empty( $s['stickyBottom'] ) ) { $decls .= self::css_decl( '--nx-sticky-bottom', esc_attr( $s['stickyBottom'] ) ); } if ( isset( $s['stickyZIndex'] ) && '' !== $s['stickyZIndex'] ) { $decls .= self::css_decl( '--nx-sticky-z-index', esc_attr( (string) $s['stickyZIndex'] ) ); } if ( ! empty( $s['stickyBg'] ) ) { $decls .= self::css_decl( '--nx-sticky-bg', esc_attr( $s['stickyBg'] ) ); } if ( ! empty( $s['stickyEnabled'] ) && 'page' !== ( $s['stickyScope'] ?? 'parent' ) ) { $sticky_side = ( $s['stickySide'] ?? 'top' ) === 'bottom' ? 'bottom' : 'top'; $decls .= self::css_decl( 'position', 'sticky' ); if ( 'bottom' === $sticky_side ) { $decls .= self::css_decl( 'bottom', esc_attr( $s['stickyBottom'] ?? '0px' ) ); $decls .= self::css_decl( 'top', 'auto' ); } else { $decls .= self::css_decl( 'top', esc_attr( $s['stickyTop'] ?? '0px' ) ); $decls .= self::css_decl( 'bottom', 'auto' ); } $decls .= self::css_decl( 'z-index', esc_attr( (string) ( $s['stickyZIndex'] ?? '1000' ) ) ); if ( ! empty( $s['stickyBg'] ) ) { $decls .= self::css_decl( 'background-color', esc_attr( $s['stickyBg'] ) ); } } foreach ( [ 'font-style' => 'fontStyle', 'background-attachment' => 'bgAttachment', 'border-top-left-radius' => 'borderTopLeftRadius', 'border-top-right-radius' => 'borderTopRightRadius', 'border-bottom-right-radius' => 'borderBottomRightRadius', 'border-bottom-left-radius' => 'borderBottomLeftRadius', 'opacity' => 'opacity' ] as $property => $key ) { if ( isset( $s[ $key ] ) && '' !== $s[ $key ] ) $decls .= self::css_decl( $property, esc_attr( (string) $s[ $key ] ) ); } $decls .= self::build_extension_style_decls( $s ); if ( ! empty( $s['color'] ) ) { $decls .= self::css_decl( 'color', esc_attr( $s['color'] ) ); } if ( ! empty( $s['fontFamily'] ) ) { $decls .= self::css_decl( 'font-family', self::format_font_family( $s['fontFamily'] ) ); } if ( '' !== $s['fontSize'] ) { $decls .= self::css_decl( 'font-size', esc_attr( $s['fontSize'] ) ); } if ( ! empty( $s['fontWeight'] ) ) { $decls .= self::css_decl( 'font-weight', esc_attr( $s['fontWeight'] ) ); } if ( ! empty( $s['textAlign'] ) ) { $decls .= self::css_decl( 'text-align', esc_attr( $s['textAlign'] ) ); } return $decls; } private static function build_layout_item_decls( $s, $parent_display ) { $s = self::sanitize_layout_css_settings( $s ); $decls = ''; if ( 'grid' === $parent_display ) { if ( '' !== $s['gridColumnSpan'] ) { $decls .= self::css_decl( 'grid-column', 'span ' . $s['gridColumnSpan'] ); } if ( '' !== $s['gridRowSpan'] ) { $decls .= self::css_decl( 'grid-row', 'span ' . $s['gridRowSpan'] ); } if ( '' !== $s['justifySelf'] ) { $decls .= self::css_decl( 'justify-self', $s['justifySelf'] ); } if ( '' !== $s['alignSelf'] ) { $decls .= self::css_decl( 'align-self', $s['alignSelf'] ); } return $decls; } if ( 'flex' !== $parent_display ) { return $decls; } if ( '' === $s['widthValue'] ) { if ( '' !== $s['flexGrow'] ) { $decls .= self::css_decl( 'flex-grow', $s['flexGrow'] ); } if ( '' !== $s['flexShrink'] ) { $decls .= self::css_decl( 'flex-shrink', $s['flexShrink'] ); } } if ( '' !== $s['alignSelf'] ) { $decls .= self::css_decl( 'align-self', $s['alignSelf'] ); } if ( '' !== $s['order'] ) { $decls .= self::css_decl( 'order', $s['order'] ); } return $decls; } private static function build_section_width_decls( $s ) { if ( empty( $s ) || ! is_array( $s ) ) { return ''; } $has_width = isset( $s['width'] ) && '' !== $s['width']; $has_max = isset( $s['maxWidth'] ) && '' !== $s['maxWidth']; if ( ! $has_width && ! $has_max ) { return ''; } $decls = self::css_decl( 'width', '100%' ); if ( ( $s['width'] ?? '' ) === 'full' ) { $decls .= self::css_decl( 'max-width', '100%' ); $decls .= self::css_decl( 'margin-left', '0' ); $decls .= self::css_decl( 'margin-right', '0' ); return $decls; } $mw = ! empty( $s['maxWidth'] ) ? self::safe_layout_length( self::with_unit( $s['maxWidth'], 'px' ) ) : '1080px'; if ( '' === $mw ) { return $decls; } $decls .= self::css_decl( 'max-width', esc_attr( $mw ) ); $decls .= self::css_decl( 'margin-left', 'auto' ); $decls .= self::css_decl( 'margin-right', 'auto' ); return $decls; } private static function build_row_align_decls( $s, $fallback = [], $global_layout = [] ) { $width = $s['widthValue'] ?? ( $fallback['widthValue'] ?? '100%' ); $width = self::safe_layout_length( $width, [ 'auto' ] ); $max_width = $s['maxWidthValue'] ?? ( $fallback['maxWidthValue'] ?? ( $global_layout['containerMaxWidth'] ?? '1080px' ) ); $max_width = self::safe_layout_length( $max_width, [ 'none' ] ); $align = $s['rowAlign'] ?? ( $fallback['rowAlign'] ?? ( $global_layout['rowAlignment'] ?? 'center' ) ); $align = self::safe_layout_option( $align, [ 'left', 'center', 'right' ] ) ?: 'center'; $has_left = ( isset( $s['marginLeft'] ) && '' !== $s['marginLeft'] ) || ( isset( $fallback['marginLeft'] ) && '' !== $fallback['marginLeft'] ); $has_right = ( isset( $s['marginRight'] ) && '' !== $s['marginRight'] ) || ( isset( $fallback['marginRight'] ) && '' !== $fallback['marginRight'] ); $decls = self::css_decl( 'width', $width ?: '100%' ); if ( ! empty( $max_width ) ) { $decls .= self::css_decl( 'max-width', esc_attr( self::with_unit( $max_width, 'px' ) ) ); } if ( 'center' === $align ) { if ( ! $has_left ) { $decls .= self::css_decl( 'margin-left', 'auto' ); } if ( ! $has_right ) { $decls .= self::css_decl( 'margin-right', 'auto' ); } } elseif ( 'right' === $align ) { if ( ! $has_left ) { $decls .= self::css_decl( 'margin-left', 'auto' ); } if ( ! $has_right ) { $decls .= self::css_decl( 'margin-right', '0' ); } } else { if ( ! $has_left ) { $decls .= self::css_decl( 'margin-left', '0' ); } if ( ! $has_right ) { $decls .= self::css_decl( 'margin-right', '0' ); } } return $decls; } private static function has_responsive_values( $value ) { if ( null === $value ) { return false; } if ( is_string( $value ) ) { return '' !== trim( $value ); } if ( is_numeric( $value ) || is_bool( $value ) ) { return true; } if ( is_array( $value ) ) { foreach ( $value as $v ) { if ( self::has_responsive_values( $v ) ) { return true; } } } return false; } private static function has_meaningful_typography_value( $value ) { if ( null === $value ) { return false; } if ( is_string( $value ) ) { return '' !== trim( $value ); } if ( is_numeric( $value ) || is_bool( $value ) ) { return true; } if ( is_array( $value ) ) { foreach ( $value as $item ) { if ( self::has_meaningful_typography_value( $item ) ) { return true; } } } return false; } private static function module_has_typography_override( $type, $settings ) { if ( ! is_array( $settings ) ) { return false; } return ! empty( $settings['disableGlobalTypography'] ); } private static function build_row_decls( $s ) { $s = is_array( $s ) ? $s : []; $has_mode = ! empty( $s['display'] ) || ! empty( $s['gridColumns'] ) || ! empty( $s['gridRows'] ) || ! empty( $s['flexDirection'] ) || ! empty( $s['flexWrap'] ) || ! empty( $s['justifyContent'] ) || ! empty( $s['alignItems'] ); if ( ! $has_mode ) { $s['display'] = 'flex'; } return self::build_container_decls( $s ); } private static function build_hover_style_decls( $type, $hover, $child_target = false ) { if ( ! is_array( $hover ) ) { return ''; } $allowed = [ 'color', 'bgType', 'bgColor', 'bgImage', 'bgSize', 'bgPosition', 'bgRepeat', 'bgAttachment', 'bgGradientKind', 'bgGradientDirection', 'bgGradientAngle', 'bgGradientRadialShape', 'bgGradientRadialPosition', 'bgGradientStart', 'bgGradientEnd', 'bgGradientStops', 'borderStyle', 'borderColor', 'borderRadius', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius', 'opacity', 'fontStyle' ]; $picked = []; foreach ( $allowed as $key ) { if ( array_key_exists( $key, $hover ) ) { $picked[ $key ] = $hover[ $key ]; } } if ( $child_target ) { $child = []; if ( 'button' === $type ) { $child['color'] = $hover['btnTextColor'] ?? ( $hover['color'] ?? '' ); $child['bgColor'] = $hover['btnBgColor'] ?? ( $hover['bgColor'] ?? '' ); foreach ( [ 'borderStyle', 'borderColor', 'borderRadius', 'borderTopWidth', 'borderRightWidth', 'borderBottomWidth', 'borderLeftWidth', 'borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius' ] as $key ) { if ( array_key_exists( $key, $hover ) ) { $child[ $key ] = $hover[ $key ]; } } } elseif ( 'navmenu' === $type ) { $child['color'] = $hover['navMenuItemColor'] ?? ( $hover['color'] ?? '' ); $child['bgColor'] = $hover['navMenuItemBg'] ?? ( $hover['bgColor'] ?? '' ); } elseif ( 'iconbox' === $type ) { $child['color'] = $hover['iconBoxIconColor'] ?? ( $hover['color'] ?? '' ); } elseif ( 'divider' === $type ) { $child['borderColor'] = $hover['dividerColor'] ?? ( $hover['borderColor'] ?? '' ); } else { $child['color'] = $hover['color'] ?? ''; } foreach ( [ 'fontStyle' ] as $key ) { if ( array_key_exists( $key, $hover ) ) { $child[ $key ] = $hover[ $key ]; } } return self::build_box_decls( $child ) . self::build_extension_style_decls( $hover, [ 'hover' => true, 'child_target' => true, 'type' => $type ] ); } if ( $type && ! in_array( $type, [ 'section', 'row', 'column' ], true ) ) { unset( $picked['color'] ); } if ( in_array( $type, [ 'button', 'navmenu' ], true ) ) { unset( $picked['bgColor'] ); } return self::build_box_decls( $picked ) . self::build_extension_style_decls( $hover, [ 'hover' => true, 'type' => $type ] ); } private static function hover_selector( $base, $type ) { if ( 'text' === $type ) { $selectors = []; foreach ( [ '.nx-text', '.nx-text p', '.nx-text li', '.nx-text a', '.nx-text h1', '.nx-text h2', '.nx-text h3', '.nx-text h4', '.nx-text h5', '.nx-text h6' ] as $target ) { $selectors[] = $base . ':hover ' . $target; } return implode( ',', $selectors ); } $suffixes = [ 'heading' => ' .nx-heading', 'text' => ' .nx-text', 'button' => ' .nx-btn', 'divider' => ' .nx-divider-line', 'iconbox' => ' .nx-iconbox-icon', 'navmenu' => ' .nx-nav-menu>.nx-nav-main>.nx-nav-menu-panel>.nx-nav-menu-panel-inner>.nx-nav-menu-list>li>a', ]; return $base . ':hover' . ( $suffixes[ $type ] ?? '' ); } private static function style_child_selector( $base, $type ) { if ( 'text' === $type ) { $selectors = []; foreach ( [ '.nx-text', '.nx-text p', '.nx-text li', '.nx-text a', '.nx-text h1', '.nx-text h2', '.nx-text h3', '.nx-text h4', '.nx-text h5', '.nx-text h6' ] as $target ) { $selectors[] = $base . ' ' . $target; } return implode( ',', $selectors ); } $suffixes = [ 'heading' => '.nx-heading', 'button' => '.nx-btn', 'divider' => '.nx-divider-line', 'iconbox' => '.nx-iconbox-icon', 'navmenu' => '.nx-nav-menu>.nx-nav-main>.nx-nav-menu-panel>.nx-nav-menu-panel-inner>.nx-nav-menu-list>li>a', ]; return isset( $suffixes[ $type ] ) ? $base . ' ' . $suffixes[ $type ] : ''; } private static function style_transition_decls( $settings ) { return self::build_extension_style_decls( $settings, [ 'transition_only' => true ] ); } private static function append_hover_state_rules( &$rules, &$tablet_rules, &$mobile_rules, $base, $type, $settings ) { if ( ! is_array( $settings ) || ! $base ) { return; } $child_selector = self::hover_selector( $base, $type ); $has_child_target = 'text' === $type || $child_selector !== $base . ':hover'; $normal_child_selector = self::style_child_selector( $base, $type ); $transition = $normal_child_selector ? self::style_transition_decls( $settings ) : ''; if ( $transition ) { $rules[] = $normal_child_selector . '{' . $transition . '}'; } $decls = self::build_hover_style_decls( $type, $settings['hover'] ?? [], false ); if ( $decls ) { $rules[] = $base . ':hover{' . $decls . '}'; } $child_decls = $has_child_target ? self::build_hover_style_decls( $type, $settings['hover'] ?? [], true ) : ''; if ( $child_decls ) { $rules[] = $child_selector . '{' . $child_decls . '}'; } $responsive = is_array( $settings['responsive'] ?? null ) ? $settings['responsive'] : []; $tablet_transition = $normal_child_selector ? self::style_transition_decls( $responsive['tablet'] ?? [] ) : ''; if ( $tablet_transition ) { $tablet_rules[] = $normal_child_selector . '{' . $tablet_transition . '}'; } $tablet = self::build_hover_style_decls( $type, $responsive['tablet']['hover'] ?? [], false ); if ( $tablet ) { $tablet_rules[] = $base . ':hover{' . $tablet . '}'; } $tablet_child = $has_child_target ? self::build_hover_style_decls( $type, $responsive['tablet']['hover'] ?? [], true ) : ''; if ( $tablet_child ) { $tablet_rules[] = $child_selector . '{' . $tablet_child . '}'; } $mobile_transition = $normal_child_selector ? self::style_transition_decls( $responsive['mobile'] ?? [] ) : ''; if ( $mobile_transition ) { $mobile_rules[] = $normal_child_selector . '{' . $mobile_transition . '}'; } $mobile = self::build_hover_style_decls( $type, $responsive['mobile']['hover'] ?? [], false ); if ( $mobile ) { $mobile_rules[] = $base . ':hover{' . $mobile . '}'; } $mobile_child = $has_child_target ? self::build_hover_style_decls( $type, $responsive['mobile']['hover'] ?? [], true ) : ''; if ( $mobile_child ) { $mobile_rules[] = $child_selector . '{' . $mobile_child . '}'; } } private static function append_visibility_rules( &$visibility_rules, $selector, $settings ) { if ( ! $selector || ! is_array( $settings ) ) { return; } $safe = self::sanitize_layout_css_settings( $settings ); $hidden = self::css_decl( 'display', 'none !important' ); if ( $safe['hideDesktop'] ) { $visibility_rules[] = '@media (min-width:981px){' . $selector . '{' . $hidden . '}}'; } if ( $safe['hideTablet'] && $safe['hideMobile'] ) { $visibility_rules[] = '@media (max-width:980px){' . $selector . '{' . $hidden . '}}'; return; } if ( $safe['hideTablet'] ) { $visibility_rules[] = '@media (min-width:768px) and (max-width:980px){' . $selector . '{' . $hidden . '}}'; } if ( $safe['hideMobile'] ) { $visibility_rules[] = '@media (max-width:767px){' . $selector . '{' . $hidden . '}}'; } } private static function position_is_explicit( $settings ) { $safe = self::sanitize_layout_css_settings( is_array( $settings ) ? $settings : [] ); return '' !== $safe['position']; } private static function build_overlay_decls( $s ) { $safe = self::sanitize_style_css_settings( [ 'bgType' => $s['overlayType'] ?? '', 'bgColor' => $s['overlayColor'] ?? '', 'bgImage' => $s['overlayImage'] ?? '', 'bgGradientKind' => $s['overlayGradientKind'] ?? '', 'bgGradientDirection' => $s['overlayGradientDirection'] ?? '', 'bgGradientAngle' => $s['overlayGradientAngle'] ?? '', 'bgGradientRadialShape' => $s['overlayGradientRadialShape'] ?? '', 'bgGradientRadialPosition' => $s['overlayGradientRadialPosition'] ?? '', 'bgGradientStart' => $s['overlayGradientStart'] ?? '', 'bgGradientEnd' => $s['overlayGradientEnd'] ?? '', 'bgGradientStops' => $s['overlayGradientStops'] ?? [], 'opacity' => $s['overlayOpacity'] ?? '', ] ); $s['overlayType'] = $safe['bgType']; $s['overlayColor'] = $safe['bgColor']; $s['overlayImage'] = ! empty( $s['overlayImage'] ) ? esc_url_raw( $s['overlayImage'] ) : ''; $s['overlayGradientKind'] = $safe['bgGradientKind']; $s['overlayGradientDirection'] = $safe['bgGradientDirection']; $s['overlayGradientAngle'] = $safe['bgGradientAngle']; $s['overlayGradientRadialShape'] = $safe['bgGradientRadialShape']; $s['overlayGradientRadialPosition'] = $safe['bgGradientRadialPosition']; $s['overlayGradientStart'] = $safe['bgGradientStart']; $s['overlayGradientEnd'] = $safe['bgGradientEnd']; $s['overlayGradientStops'] = $safe['bgGradientStops']; $s['overlayOpacity'] = $safe['opacity']; $has_gradient_stops = ( isset( $s['overlayGradientStops'] ) && is_array( $s['overlayGradientStops'] ) && count( $s['overlayGradientStops'] ) ); if ( empty( $s['overlayColor'] ) && empty( $s['overlayGradientStart'] ) && ! $has_gradient_stops && empty( $s['overlayImage'] ) ) { return ''; } $decls = 'position:absolute !important;inset:0 !important;pointer-events:none !important;z-index:0 !important;border-radius:inherit !important;'; $type = $s['overlayType'] ?? ''; if ( '' === $type ) { $has_legacy = ! empty( $s['overlayGradientStart'] ) || ! empty( $s['overlayGradientEnd'] ); if ( $has_gradient_stops || $has_legacy ) { $type = 'gradient'; } elseif ( ! empty( $s['overlayImage'] ) ) { $type = 'image'; } else { $type = 'color'; } } $opacity = isset( $s['overlayOpacity'] ) && '' !== $s['overlayOpacity'] ? $s['overlayOpacity'] : '0.5'; if ( 'gradient' === $type ) { $kind = $s['overlayGradientKind'] ?? 'linear'; $stops_raw = $s['overlayGradientStops'] ?? []; $stops = []; if ( is_array( $stops_raw ) && count( $stops_raw ) >= 2 ) { $count = count( $stops_raw ); foreach ( array_values( $stops_raw ) as $i => $st ) { if ( ! is_array( $st ) || empty( $st['color'] ) ) { continue; } $pos = $st['pos'] ?? null; if ( null === $pos || '' === $pos ) { $pos = ( $count > 1 ) ? round( ( $i / ( $count - 1 ) ) * 100 ) : 0; } $pos = max( 0, min( 100, floatval( $pos ) ) ); $stops[] = trim( (string) $st['color'] ) . ' ' . $pos . '%'; } } if ( count( $stops ) < 2 ) { $start = $s['overlayGradientStart'] ?? '#000'; $end = $s['overlayGradientEnd'] ?? '#fff'; $stops = [ (string) $start . ' 0%', (string) $end . ' 100%' ]; } if ( 'radial' === $kind ) { $shape = ! empty( $s['overlayGradientRadialShape'] ) ? $s['overlayGradientRadialShape'] : 'ellipse'; $at = ! empty( $s['overlayGradientRadialPosition'] ) ? ' at ' . (string) $s['overlayGradientRadialPosition'] : ''; $decls .= self::css_decl( 'background-image', 'radial-gradient(' . esc_attr( $shape . $at ) . ', ' . esc_attr( implode( ', ', $stops ) ) . ')' ); } else { $angle = trim( (string) ( $s['overlayGradientAngle'] ?? '' ) ); $direction = ! empty( $s['overlayGradientDirection'] ) ? $s['overlayGradientDirection'] : 'to bottom'; $first = $angle ? $angle : (string) $direction; $decls .= self::css_decl( 'background-image', 'linear-gradient(' . esc_attr( $first ) . ', ' . esc_attr( implode( ', ', $stops ) ) . ')' ); } } elseif ( 'image' === $type && ! empty( $s['overlayImage'] ) ) { $decls .= self::css_decl( 'background-image', 'url(' . esc_url( $s['overlayImage'] ) . ')' ); $decls .= self::css_decl( 'background-size', 'cover' ); } else { $decls .= self::css_decl( 'background-color', esc_attr( $s['overlayColor'] ?? '#000' ) ); } $decls .= self::css_decl( 'opacity', esc_attr( (string) $opacity ) ); $blend = self::safe_layout_option( $s['overlayBlendMode'] ?? 'normal', [ 'normal', 'multiply', 'screen', 'overlay', 'darken', 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity' ] ) ?: 'normal'; $decls .= self::css_decl( 'mix-blend-mode', $blend ); return $decls; } private static function generate_frontend_css( $json ) { if ( ! is_array( $json ) ) { return ''; } $rules = []; $tablet_rules = []; $mobile_rules = []; $visibility_rules = []; $global_layout = Global_Settings::get_settings()['layout'] ?? []; foreach ( $json as $section ) { if ( empty( $section['type'] ) || 'section' !== $section['type'] ) { continue; } $s = $section['settings'] ?? []; $section_token = self::extract_token( $s['className'] ?? '', 'nx-section' ); $row_token = self::extract_token( $s['rowClass'] ?? '', 'nx-row' ); if ( $section_token ) { $section_selector = '.nx-section.' . $section_token; $overlay_decls = self::build_overlay_decls( $s ); $decls = self::build_container_decls( $s ) . self::build_box_decls( $s ); if ( $overlay_decls && ! self::position_is_explicit( $s ) ) { $decls .= self::css_decl( 'position', 'relative' ); } $decls .= self::build_section_width_decls( $s ); if ( $decls ) { $rules[] = $section_selector . '{' . $decls . '}'; } if ( $overlay_decls ) { $rules[] = $section_selector . '>.nx-overlay{' . $overlay_decls . '}'; $rules[] = $section_selector . '>.nx-row{position:relative;z-index:1;}'; } $responsive = isset( $s['responsive'] ) && is_array( $s['responsive'] ) ? $s['responsive'] : []; $st = isset( $responsive['tablet'] ) && is_array( $responsive['tablet'] ) ? $responsive['tablet'] : []; $sm = isset( $responsive['mobile'] ) && is_array( $responsive['mobile'] ) ? $responsive['mobile'] : []; $tablet_decls = self::build_container_decls( $st ) . self::build_box_decls( $st ) . self::build_section_width_decls( $st ); if ( $tablet_decls ) { $tablet_rules[] = $section_selector . '{' . $tablet_decls . '}'; } $mobile_decls = self::build_container_decls( $sm ) . self::build_box_decls( $sm ) . self::build_section_width_decls( $sm ); if ( $mobile_decls ) { $mobile_rules[] = $section_selector . '{' . $mobile_decls . '}'; } self::append_hover_state_rules( $rules, $tablet_rules, $mobile_rules, $section_selector, 'section', $s ); self::append_visibility_rules( $visibility_rules, $section_selector, $s ); } if ( $row_token ) { $section_row_selector = '.nx-row.' . $row_token; $decls = self::build_row_decls( $s ); if ( $decls ) { $rules[] = $section_row_selector . '{' . $decls . '}'; } $responsive = isset( $s['responsive'] ) && is_array( $s['responsive'] ) ? $s['responsive'] : []; $st = isset( $responsive['tablet'] ) && is_array( $responsive['tablet'] ) ? $responsive['tablet'] : []; $sm = isset( $responsive['mobile'] ) && is_array( $responsive['mobile'] ) ? $responsive['mobile'] : []; $tablet_row = self::build_row_decls( $st ); if ( $tablet_row ) { $tablet_rules[] = $section_row_selector . '{' . $tablet_row . '}'; } $mobile_row = self::build_row_decls( $sm ); if ( $mobile_row ) { $mobile_rules[] = $section_row_selector . '{' . $mobile_row . '}'; } } $rows = ! empty( $section['rows'] ) && is_array( $section['rows'] ) ? $section['rows'] : []; foreach ( $rows as $row ) { $rs = $row['settings'] ?? []; $row_item_token = self::extract_token( $rs['className'] ?? '', 'nx-row-item' ); if ( $row_item_token ) { $row_selector = '.nx-row.' . $row_item_token; $row_decls = self::build_container_decls( $rs ) . self::build_box_decls( $rs ) . self::build_row_align_decls( $rs, [], $global_layout ); $col_count = ! empty( $row['columns'] ) && is_array( $row['columns'] ) ? count( $row['columns'] ) : 0; if ( $col_count > 0 ) { $row_decls .= self::css_decl( '--nx-row-col-count', (string) $col_count ); $gap_unit = $rs['gapUnit'] ?? ( $s['gapUnit'] ?? 'px' ); $raw_gap = $rs['columnGap'] ?? ( $s['columnGap'] ?? ( $rs['gap'] ?? ( $s['gap'] ?? ( $rs['rowGap'] ?? ( $s['rowGap'] ?? '' ) ) ) ) ); $gap_value = ( '' !== $raw_gap && null !== $raw_gap ) ? self::safe_layout_length( preg_match( '/[a-z%]/i', (string) $raw_gap ) ? (string) $raw_gap : (string) $raw_gap . $gap_unit ) : self::DEFAULT_ROW_GAP; $gap_value = $gap_value ?: self::DEFAULT_ROW_GAP; $row_decls .= self::css_decl( '--nx-row-gap', esc_attr( $gap_value ) ); } $row_overlay_decls = self::build_overlay_decls( $rs ); if ( $row_overlay_decls && ! self::position_is_explicit( $rs ) ) { $row_decls .= self::css_decl( 'position', 'relative' ); } if ( $row_decls ) { $rules[] = $row_selector . '{' . $row_decls . '}'; } if ( $row_overlay_decls ) { $rules[] = $row_selector . '>.nx-overlay{' . $row_overlay_decls . '}'; $rules[] = $row_selector . '>.nx-column{position:relative;z-index:1;}'; } $responsive = isset( $rs['responsive'] ) && is_array( $rs['responsive'] ) ? $rs['responsive'] : []; $rst = isset( $responsive['tablet'] ) && is_array( $responsive['tablet'] ) ? $responsive['tablet'] : []; $rsm = isset( $responsive['mobile'] ) && is_array( $responsive['mobile'] ) ? $responsive['mobile'] : []; $row_display = self::infer_layout_display( $rs, self::infer_layout_display( $s, 'flex' ) ); $tablet_display = self::infer_layout_display( $rst, $row_display ); $tablet_row_decls = self::build_container_decls( $rst, $row_display ) . self::build_box_decls( $rst ) . self::build_row_align_decls( $rst, $rs, $global_layout ); $tablet_gap_unit = $rst['gapUnit'] ?? ( $rs['gapUnit'] ?? ( $s['gapUnit'] ?? 'px' ) ); $tablet_raw_gap = $rst['columnGap'] ?? ( $rst['gap'] ?? ( $rst['rowGap'] ?? '' ) ); $tablet_gap_value = ( '' !== $tablet_raw_gap && null !== $tablet_raw_gap ) ? self::safe_layout_length( preg_match( '/[a-z%]/i', (string) $tablet_raw_gap ) ? (string) $tablet_raw_gap : (string) $tablet_raw_gap . $tablet_gap_unit ) : self::DEFAULT_ROW_GAP; $tablet_gap_value = $tablet_gap_value ?: self::DEFAULT_ROW_GAP; $tablet_row_decls .= self::css_decl( '--nx-row-gap', esc_attr( $tablet_gap_value ) ); if ( $tablet_row_decls ) { $tablet_rules[] = $row_selector . '{' . $tablet_row_decls . '}'; } $mobile_row_decls = self::build_container_decls( $rsm, $tablet_display ) . self::build_box_decls( $rsm ) . self::build_row_align_decls( $rsm, $rs, $global_layout ); $mobile_gap_unit = $rsm['gapUnit'] ?? ( $rs['gapUnit'] ?? ( $s['gapUnit'] ?? 'px' ) ); $mobile_raw_gap = $rsm['columnGap'] ?? ( $rsm['gap'] ?? ( $rsm['rowGap'] ?? '' ) ); $mobile_gap_value = ( '' !== $mobile_raw_gap && null !== $mobile_raw_gap ) ? self::safe_layout_length( preg_match( '/[a-z%]/i', (string) $mobile_raw_gap ) ? (string) $mobile_raw_gap : (string) $mobile_raw_gap . $mobile_gap_unit ) : self::DEFAULT_ROW_GAP; $mobile_gap_value = $mobile_gap_value ?: self::DEFAULT_ROW_GAP; $mobile_row_decls .= self::css_decl( '--nx-row-gap', esc_attr( $mobile_gap_value ) ); if ( $mobile_row_decls ) { $mobile_rules[] = $row_selector . '{' . $mobile_row_decls . '}'; } self::append_hover_state_rules( $rules, $tablet_rules, $mobile_rules, $row_selector, 'row', $rs ); self::append_visibility_rules( $visibility_rules, $row_selector, $rs ); if ( $col_count > 0 ) { $row_display = $rs['display'] ?? ( $s['display'] ?? 'flex' ); $row_tablet_has = self::has_responsive_values( $rst ); $col_tablet_has = false; $columns = ! empty( $row['columns'] ) && is_array( $row['columns'] ) ? $row['columns'] : []; foreach ( $columns as $column ) { $cset = $column['settings'] ?? []; $cres = isset( $cset['responsive'] ) && is_array( $cset['responsive'] ) ? $cset['responsive'] : []; $ct = isset( $cres['tablet'] ) && is_array( $cres['tablet'] ) ? $cres['tablet'] : []; $cm = isset( $cres['mobile'] ) && is_array( $cres['mobile'] ) ? $cres['mobile'] : []; if ( self::has_responsive_values( $ct ) ) { $col_tablet_has = true; } } if ( ! $row_tablet_has && ! $col_tablet_has ) { $tablet_cols = ( $col_count >= 3 ) ? 2 : $col_count; if ( $tablet_cols > 0 ) { if ( 'grid' === $row_display ) { $tablet_rules[] = $row_selector . '{' . self::css_decl( 'grid-template-columns', 'repeat(' . $tablet_cols . ', minmax(0, 1fr))' ) . '}'; } else { $basis = 'calc(' . ( 100 / $tablet_cols ) . '% - (var(--nx-row-gap, ' . self::DEFAULT_ROW_GAP . ') * (' . ( $tablet_cols - 1 ) . ') / ' . $tablet_cols . '))'; $tablet_rules[] = $row_selector . '>.nx-column{' . self::css_decl( 'width', '100% !important' ) . self::css_decl( 'flex', '0 0 ' . $basis . ' !important' ) . self::css_decl( 'max-width', $basis . ' !important' ) . self::css_decl( 'min-width', '0 !important' ) . '}'; } } } $tablet_display = self::infer_layout_display( $rst, $row_display ); $mobile_display = self::infer_layout_display( $rsm, $tablet_display ); if ( 'grid' === $mobile_display ) { if ( ! self::has_responsive_values( $rsm['gridColumns'] ?? null ) ) { $mobile_rules[] = $row_selector . '{' . self::css_decl( 'grid-template-columns', 'repeat(1, minmax(0, 1fr))' ) . '}'; } } elseif ( 'flex' === $mobile_display ) { $explicit_mobile_direction = self::has_responsive_values( $rsm['flexDirection'] ?? null ); $mobile_direction = $explicit_mobile_direction ? $rsm['flexDirection'] : 'column'; if ( ! $explicit_mobile_direction ) { $mobile_rules[] = $row_selector . '{' . self::css_decl( 'flex-direction', 'column' ) . '}'; } if ( in_array( $mobile_direction, [ 'column', 'column-reverse' ], true ) ) { $basis = 'calc(100% - (var(--nx-row-gap, ' . self::DEFAULT_ROW_GAP . ') * (1 - 1) / 1))'; foreach ( $columns as $column_index => $column ) { $column_settings = $column['settings'] ?? []; $column_responsive = isset( $column_settings['responsive'] ) && is_array( $column_settings['responsive'] ) ? $column_settings['responsive'] : []; $column_mobile = isset( $column_responsive['mobile'] ) && is_array( $column_responsive['mobile'] ) ? $column_responsive['mobile'] : []; if ( self::has_responsive_values( $column_mobile['widthValue'] ?? null ) ) { continue; } $column_token = self::extract_token( $column_settings['className'] ?? '', 'nx-column' ); $column_selector = $column_token ? $row_selector . '>.' . $column_token : $row_selector . '>.nx-column:nth-child(' . ( $column_index + 1 ) . ')'; $mobile_rules[] = $column_selector . '{' . self::css_decl( 'width', '100% !important' ) . self::css_decl( 'flex', '0 0 ' . $basis . ' !important' ) . self::css_decl( 'max-width', $basis . ' !important' ) . self::css_decl( 'min-width', '0 !important' ) . '}'; } } } } } $columns = ! empty( $row['columns'] ) && is_array( $row['columns'] ) ? $row['columns'] : []; $parent_display = self::infer_layout_display( $rs, self::infer_layout_display( $s, 'flex' ) ); $row_responsive = isset( $rs['responsive'] ) && is_array( $rs['responsive'] ) ? $rs['responsive'] : []; $parent_tablet_display = self::infer_layout_display( $row_responsive['tablet'] ?? [], $parent_display ); $parent_mobile_display = self::infer_layout_display( $row_responsive['mobile'] ?? [], $parent_tablet_display ); foreach ( $columns as $column ) { if ( empty( $column['type'] ) || 'column' !== $column['type'] ) { continue; } $c = $column['settings'] ?? []; $safe_c = self::sanitize_layout_css_settings( $c ); $col_token = self::extract_token( $c['className'] ?? '', 'nx-column' ); if ( $col_token ) { $responsive_col_selector = $row_item_token ? '.' . $row_item_token . '>.' . $col_token : '.' . $col_token; $overlay_decls = self::build_overlay_decls( $c ); $decls = self::build_container_decls( $c ) . self::build_box_decls( $c ) . self::build_layout_item_decls( $c, $parent_display ); if ( 'grid' !== $parent_display && '' !== $safe_c['widthValue'] ) { $w = $safe_c['widthValue']; if ( strpos( $w, '%' ) !== false ) { $w = 'calc(' . $w . ' - (var(--nx-row-gap, ' . self::DEFAULT_ROW_GAP . ') * (var(--nx-row-col-count, 1) - 1) / var(--nx-row-col-count, 1)))'; } $decls .= self::css_decl( 'flex', ( $safe_c['flexGrow'] ?: '0' ) . ' ' . ( $safe_c['flexShrink'] ?: '0' ) . ' ' . $w ); if ( '' === $safe_c['maxWidthValue'] ) { $decls .= self::css_decl( 'max-width', $w ); } $decls .= self::css_decl( 'min-width', '0' ); } if ( $overlay_decls && ! self::position_is_explicit( $c ) ) { $decls .= self::css_decl( 'position', 'relative' ); } if ( $decls ) { $rules[] = '.' . $col_token . '{' . $decls . '}'; } if ( $overlay_decls ) { $rules[] = '.' . $col_token . '>.nx-overlay{' . $overlay_decls . '}'; $rules[] = '.' . $col_token . '>.nx-module-wrapper{position:relative;z-index:1;}'; } $responsive = isset( $c['responsive'] ) && is_array( $c['responsive'] ) ? $c['responsive'] : []; $ct = isset( $responsive['tablet'] ) && is_array( $responsive['tablet'] ) ? $responsive['tablet'] : []; $cm = isset( $responsive['mobile'] ) && is_array( $responsive['mobile'] ) ? $responsive['mobile'] : []; $safe_ct = self::sanitize_layout_css_settings( $ct ); $tablet_col_decls = self::build_container_decls( $ct ) . self::build_box_decls( $ct ) . self::build_layout_item_decls( $ct, $parent_tablet_display ); if ( 'grid' !== $parent_tablet_display && '' !== $safe_ct['widthValue'] ) { $w = $safe_ct['widthValue']; if ( strpos( $w, '%' ) !== false ) { $w = 'calc(' . $w . ' - (var(--nx-row-gap, ' . self::DEFAULT_ROW_GAP . ') * (var(--nx-row-col-count, 1) - 1) / var(--nx-row-col-count, 1)))'; } $tablet_col_decls .= self::css_decl( 'flex', ( $safe_ct['flexGrow'] ?: '0' ) . ' ' . ( $safe_ct['flexShrink'] ?: '0' ) . ' ' . $w ); if ( '' === $safe_ct['maxWidthValue'] ) { $tablet_col_decls .= self::css_decl( 'max-width', $w ); } $tablet_col_decls .= self::css_decl( 'min-width', '0' ); } if ( $tablet_col_decls ) { $tablet_rules[] = $responsive_col_selector . '{' . $tablet_col_decls . '}'; } $safe_cm = self::sanitize_layout_css_settings( $cm ); $mobile_col_decls = self::build_container_decls( $cm ) . self::build_box_decls( $cm ) . self::build_layout_item_decls( $cm, $parent_mobile_display ); if ( 'grid' !== $parent_mobile_display && '' !== $safe_cm['widthValue'] ) { $w = $safe_cm['widthValue']; if ( strpos( $w, '%' ) !== false ) { $w = 'calc(' . $w . ' - (var(--nx-row-gap, ' . self::DEFAULT_ROW_GAP . ') * (var(--nx-row-col-count, 1) - 1) / var(--nx-row-col-count, 1)))'; } $mobile_col_decls .= self::css_decl( 'flex', ( $safe_cm['flexGrow'] ?: '0' ) . ' ' . ( $safe_cm['flexShrink'] ?: '0' ) . ' ' . $w ); if ( '' === $safe_cm['maxWidthValue'] ) { $mobile_col_decls .= self::css_decl( 'max-width', $w ); } $mobile_col_decls .= self::css_decl( 'min-width', '0' ); } if ( $mobile_col_decls ) { $mobile_rules[] = $responsive_col_selector . '{' . $mobile_col_decls . '}'; } self::append_hover_state_rules( $rules, $tablet_rules, $mobile_rules, '.' . $col_token, 'column', $c ); self::append_visibility_rules( $visibility_rules, '.' . $col_token, $c ); } $children = ! empty( $column['modules'] ) && is_array( $column['modules'] ) ? $column['modules'] : ( ! empty( $column['children'] ) && is_array( $column['children'] ) ? $column['children'] : [] ); foreach ( $children as $child ) { $w = self::sanitize_style_css_settings( $child['settings'] ?? [] ); $widget_token = self::extract_token( $w['className'] ?? '', 'nx-module' ); if ( $widget_token ) { $overlay_decls = self::build_overlay_decls( $w ); $decls = self::build_container_decls( $w ) . self::build_box_decls( $w ); if ( $overlay_decls && ! self::position_is_explicit( $w ) ) { $decls .= self::css_decl( 'position', 'relative' ); } if ( $decls ) { $rules[] = '.' . $widget_token . '{' . $decls . '}'; } if ( $overlay_decls ) { $rules[] = '.' . $widget_token . '>.nx-overlay{' . $overlay_decls . '}'; $rules[] = '.' . $widget_token . '>.nx-module-inner{position:relative;z-index:1;}'; } $responsive = isset( $w['responsive'] ) && is_array( $w['responsive'] ) ? $w['responsive'] : []; $wt = self::sanitize_style_css_settings( isset( $responsive['tablet'] ) && is_array( $responsive['tablet'] ) ? $responsive['tablet'] : [] ); $wm = self::sanitize_style_css_settings( isset( $responsive['mobile'] ) && is_array( $responsive['mobile'] ) ? $responsive['mobile'] : [] ); $module_selector = '.nx-wrapper .nx-module-wrapper.' . $widget_token; $module_typography_selectors = [ $module_selector . ':not(.nx-no-global-typo)', $module_selector . '.nx-no-global-typo', ]; $tablet_decls = self::build_container_decls( $wt ) . self::build_box_decls( $wt ); if ( $tablet_decls ) { $tablet_rules[] = '.' . $widget_token . '{' . $tablet_decls . '}'; } $mobile_decls = self::build_container_decls( $wm ) . self::build_box_decls( $wm ); if ( $mobile_decls ) { $mobile_rules[] = '.' . $widget_token . '{' . $mobile_decls . '}'; } self::append_hover_state_rules( $rules, $tablet_rules, $mobile_rules, '.' . $widget_token, $child['type'] ?? '', $w ); self::append_visibility_rules( $visibility_rules, '.' . $widget_token, $w ); if ( ( $child['type'] ?? '' ) === 'heading' ) { $tag = ''; if ( ! empty( $w['tag'] ) ) { $tag = strtolower( (string) $w['tag'] ); if ( ! in_array( $tag, [ 'h1','h2','h3','h4','h5','h6','p' ], true ) ) { $tag = ''; } } $heading_selector = implode( ',', array_map( static function ( $selector ) use ( $tag ) { return $selector . ' .nx-heading' . ( $tag ? '.nx-' . $tag : '' ); }, $module_typography_selectors ) ); $h = ''; if ( ! empty( $w['fontFamily'] ) ) { $h .= self::css_decl( 'font-family', self::format_font_family( $w['fontFamily'] ) ); } if ( '' !== $w['fontSize'] ) { $h .= self::css_decl( 'font-size', esc_attr( $w['fontSize'] ) ); } if ( ! empty( $w['fontWeight'] ) ) { $h .= self::css_decl( 'font-weight', esc_attr( $w['fontWeight'] ) ); } if ( ! empty( $w['fontStyle'] ) ) { $h .= self::css_decl( 'font-style', $w['fontStyle'] ); } if ( '' !== $w['lineHeight'] ) { $h .= self::css_decl( 'line-height', esc_attr( $w['lineHeight'] ) ); } if ( '' !== $w['letterSpacing'] ) { $h .= self::css_decl( 'letter-spacing', esc_attr( $w['letterSpacing'] ) ); } if ( '' !== $w['wordSpacing'] ) { $h .= self::css_decl( 'word-spacing', esc_attr( $w['wordSpacing'] ) ); } if ( ! empty( $w['textAlign'] ) ) { $h .= self::css_decl( 'text-align', esc_attr( $w['textAlign'] ) ); } if ( ! empty( $w['textDecoration'] ) ) { $h .= self::css_decl( 'text-decoration', esc_attr( $w['textDecoration'] ) ); } if ( ! empty( $w['textTransform'] ) ) { $h .= self::css_decl( 'text-transform', esc_attr( $w['textTransform'] ) ); } if ( ! empty( $w['color'] ) ) { $h .= self::css_decl( 'color', esc_attr( $w['color'] ) ); } if ( $h ) { $rules[] = $heading_selector . '{' . $h . '}'; } $ht = ''; if ( ! empty( $wt['fontFamily'] ) ) { $ht .= self::css_decl( 'font-family', self::format_font_family( $wt['fontFamily'] ) ); } if ( '' !== $wt['fontSize'] ) { $ht .= self::css_decl( 'font-size', esc_attr( $wt['fontSize'] ) ); } if ( ! empty( $wt['fontWeight'] ) ) { $ht .= self::css_decl( 'font-weight', esc_attr( $wt['fontWeight'] ) ); } if ( ! empty( $wt['fontStyle'] ) ) { $ht .= self::css_decl( 'font-style', $wt['fontStyle'] ); } if ( '' !== $wt['lineHeight'] ) { $ht .= self::css_decl( 'line-height', esc_attr( $wt['lineHeight'] ) ); } if ( '' !== $wt['letterSpacing'] ) { $ht .= self::css_decl( 'letter-spacing', esc_attr( $wt['letterSpacing'] ) ); } if ( '' !== $wt['wordSpacing'] ) { $ht .= self::css_decl( 'word-spacing', esc_attr( $wt['wordSpacing'] ) ); } if ( ! empty( $wt['textAlign'] ) ) { $ht .= self::css_decl( 'text-align', esc_attr( $wt['textAlign'] ) ); } if ( ! empty( $wt['textDecoration'] ) ) { $ht .= self::css_decl( 'text-decoration', esc_attr( $wt['textDecoration'] ) ); } if ( ! empty( $wt['textTransform'] ) ) { $ht .= self::css_decl( 'text-transform', esc_attr( $wt['textTransform'] ) ); } if ( ! empty( $wt['color'] ) ) { $ht .= self::css_decl( 'color', esc_attr( $wt['color'] ) ); } if ( $ht ) { $tablet_rules[] = $heading_selector . '{' . $ht . '}'; } $hm = ''; if ( ! empty( $wm['fontFamily'] ) ) { $hm .= self::css_decl( 'font-family', self::format_font_family( $wm['fontFamily'] ) ); } if ( '' !== $wm['fontSize'] ) { $hm .= self::css_decl( 'font-size', esc_attr( $wm['fontSize'] ) ); } if ( ! empty( $wm['fontWeight'] ) ) { $hm .= self::css_decl( 'font-weight', esc_attr( $wm['fontWeight'] ) ); } if ( ! empty( $wm['fontStyle'] ) ) { $hm .= self::css_decl( 'font-style', $wm['fontStyle'] ); } if ( '' !== $wm['lineHeight'] ) { $hm .= self::css_decl( 'line-height', esc_attr( $wm['lineHeight'] ) ); } if ( '' !== $wm['letterSpacing'] ) { $hm .= self::css_decl( 'letter-spacing', esc_attr( $wm['letterSpacing'] ) ); } if ( '' !== $wm['wordSpacing'] ) { $hm .= self::css_decl( 'word-spacing', esc_attr( $wm['wordSpacing'] ) ); } if ( ! empty( $wm['textAlign'] ) ) { $hm .= self::css_decl( 'text-align', esc_attr( $wm['textAlign'] ) ); } if ( ! empty( $wm['textDecoration'] ) ) { $hm .= self::css_decl( 'text-decoration', esc_attr( $wm['textDecoration'] ) ); } if ( ! empty( $wm['textTransform'] ) ) { $hm .= self::css_decl( 'text-transform', esc_attr( $wm['textTransform'] ) ); } if ( ! empty( $wm['color'] ) ) { $hm .= self::css_decl( 'color', esc_attr( $wm['color'] ) ); } if ( $hm ) { $mobile_rules[] = $heading_selector . '{' . $hm . '}'; } } if ( ( $child['type'] ?? '' ) === 'text' ) { $text_targets = [ '.nx-text', '.nx-text p', '.nx-text li', '.nx-text a', '.nx-text h1', '.nx-text h2', '.nx-text h3', '.nx-text h4', '.nx-text h5', '.nx-text h6' ]; $text_selectors = []; foreach ( $module_typography_selectors as $module_typography_selector ) { foreach ( $text_targets as $text_target ) { $text_selectors[] = $module_typography_selector . ' ' . $text_target; } } $text_selector = implode( ',', $text_selectors ); $t = ''; if ( ! empty( $w['fontFamily'] ) ) { $t .= self::css_decl( 'font-family', self::format_font_family( $w['fontFamily'] ) ); } if ( '' !== $w['fontSize'] ) { $t .= self::css_decl( 'font-size', esc_attr( $w['fontSize'] ) ); } if ( ! empty( $w['fontWeight'] ) ) { $t .= self::css_decl( 'font-weight', esc_attr( $w['fontWeight'] ) ); } if ( ! empty( $w['fontStyle'] ) ) { $t .= self::css_decl( 'font-style', $w['fontStyle'] ); } if ( '' !== $w['lineHeight'] ) { $t .= self::css_decl( 'line-height', esc_attr( $w['lineHeight'] ) ); } if ( '' !== $w['letterSpacing'] ) { $t .= self::css_decl( 'letter-spacing', esc_attr( $w['letterSpacing'] ) ); } if ( '' !== $w['wordSpacing'] ) { $t .= self::css_decl( 'word-spacing', esc_attr( $w['wordSpacing'] ) ); } if ( ! empty( $w['textAlign'] ) ) { $t .= self::css_decl( 'text-align', esc_attr( $w['textAlign'] ) ); } if ( ! empty( $w['textDecoration'] ) ) { $t .= self::css_decl( 'text-decoration', esc_attr( $w['textDecoration'] ) ); } if ( ! empty( $w['textTransform'] ) ) { $t .= self::css_decl( 'text-transform', esc_attr( $w['textTransform'] ) ); } if ( ! empty( $w['color'] ) ) { $t .= self::css_decl( 'color', esc_attr( $w['color'] ) ); } if ( $t ) { $rules[] = $text_selector . '{' . $t . '}'; } $tt = ''; if ( ! empty( $wt['fontFamily'] ) ) { $tt .= self::css_decl( 'font-family', self::format_font_family( $wt['fontFamily'] ) ); } if ( '' !== $wt['fontSize'] ) { $tt .= self::css_decl( 'font-size', esc_attr( $wt['fontSize'] ) ); } if ( ! empty( $wt['fontWeight'] ) ) { $tt .= self::css_decl( 'font-weight', esc_attr( $wt['fontWeight'] ) ); } if ( ! empty( $wt['fontStyle'] ) ) { $tt .= self::css_decl( 'font-style', $wt['fontStyle'] ); } if ( '' !== $wt['lineHeight'] ) { $tt .= self::css_decl( 'line-height', esc_attr( $wt['lineHeight'] ) ); } if ( '' !== $wt['letterSpacing'] ) { $tt .= self::css_decl( 'letter-spacing', esc_attr( $wt['letterSpacing'] ) ); } if ( '' !== $wt['wordSpacing'] ) { $tt .= self::css_decl( 'word-spacing', esc_attr( $wt['wordSpacing'] ) ); } if ( ! empty( $wt['textAlign'] ) ) { $tt .= self::css_decl( 'text-align', esc_attr( $wt['textAlign'] ) ); } if ( ! empty( $wt['textDecoration'] ) ) { $tt .= self::css_decl( 'text-decoration', esc_attr( $wt['textDecoration'] ) ); } if ( ! empty( $wt['textTransform'] ) ) { $tt .= self::css_decl( 'text-transform', esc_attr( $wt['textTransform'] ) ); } if ( ! empty( $wt['color'] ) ) { $tt .= self::css_decl( 'color', esc_attr( $wt['color'] ) ); } if ( $tt ) { $tablet_rules[] = $text_selector . '{' . $tt . '}'; } $tm = ''; if ( ! empty( $wm['fontFamily'] ) ) { $tm .= self::css_decl( 'font-family', self::format_font_family( $wm['fontFamily'] ) ); } if ( '' !== $wm['fontSize'] ) { $tm .= self::css_decl( 'font-size', esc_attr( $wm['fontSize'] ) ); } if ( ! empty( $wm['fontWeight'] ) ) { $tm .= self::css_decl( 'font-weight', esc_attr( $wm['fontWeight'] ) ); } if ( ! empty( $wm['fontStyle'] ) ) { $tm .= self::css_decl( 'font-style', $wm['fontStyle'] ); } if ( '' !== $wm['lineHeight'] ) { $tm .= self::css_decl( 'line-height', esc_attr( $wm['lineHeight'] ) ); } if ( '' !== $wm['letterSpacing'] ) { $tm .= self::css_decl( 'letter-spacing', esc_attr( $wm['letterSpacing'] ) ); } if ( '' !== $wm['wordSpacing'] ) { $tm .= self::css_decl( 'word-spacing', esc_attr( $wm['wordSpacing'] ) ); } if ( ! empty( $wm['textAlign'] ) ) { $tm .= self::css_decl( 'text-align', esc_attr( $wm['textAlign'] ) ); } if ( ! empty( $wm['textDecoration'] ) ) { $tm .= self::css_decl( 'text-decoration', esc_attr( $wm['textDecoration'] ) ); } if ( ! empty( $wm['textTransform'] ) ) { $tm .= self::css_decl( 'text-transform', esc_attr( $wm['textTransform'] ) ); } if ( ! empty( $wm['color'] ) ) { $tm .= self::css_decl( 'color', esc_attr( $wm['color'] ) ); } if ( $tm ) { $mobile_rules[] = $text_selector . '{' . $tm . '}'; } } if ( ( $child['type'] ?? '' ) === 'divider' ) { $line = '.' . $widget_token . ' .nx-divider-line'; $d = ''; if ( ! empty( $w['dividerWidth'] ) ) { $d .= self::css_decl( 'width', esc_attr( $w['dividerWidth'] ) ); } if ( ! empty( $w['dividerHeight'] ) ) { $d .= self::css_decl( 'border-top-width', esc_attr( $w['dividerHeight'] ) ); } if ( ! empty( $w['dividerStyle'] ) ) { $d .= self::css_decl( 'border-top-style', esc_attr( $w['dividerStyle'] ) ); } if ( ! empty( $w['dividerColor'] ) ) { $d .= self::css_decl( 'border-top-color', esc_attr( $w['dividerColor'] ) ); } $d .= self::css_decl( 'height', '0' ); if ( $d ) { $rules[] = $line . '{' . $d . '}'; } if ( ! empty( $w['dividerAlign'] ) ) { $align = $w['dividerAlign']; $a = ''; if ( 'center' === $align ) { $a .= self::css_decl( 'margin-left', 'auto' ); $a .= self::css_decl( 'margin-right', 'auto' ); } elseif ( 'right' === $align ) { $a .= self::css_decl( 'margin-left', 'auto' ); $a .= self::css_decl( 'margin-right', '0' ); } else { $a .= self::css_decl( 'margin-right', 'auto' ); $a .= self::css_decl( 'margin-left', '0' ); } $rules[] = $line . '{' . $a . '}'; } if ( ! empty( $wt['dividerWidth'] ) ) $tablet_rules[] = $line . '{' . self::css_decl( 'width', esc_attr( $wt['dividerWidth'] ) ) . '}'; if ( ! empty( $wm['dividerWidth'] ) ) $mobile_rules[] = $line . '{' . self::css_decl( 'width', esc_attr( $wm['dividerWidth'] ) ) . '}'; } if ( ( $child['type'] ?? '' ) === 'gallery' ) { $grid = '.' . $widget_token . ' .nx-gallery-grid'; if ( ! empty( $w['galleryColumns'] ) ) { $rules[] = $grid . '{' . self::css_decl( 'grid-template-columns', 'repeat(' . intval( $w['galleryColumns'] ) . ', minmax(0, 1fr))' ) . '}'; } if ( ! empty( $w['galleryGap'] ) ) { $rules[] = $grid . '{' . self::css_decl( 'gap', esc_attr( $w['galleryGap'] ) ) . '}'; } if ( ! empty( $w['galleryRowGap'] ) ) { $rules[] = $grid . '{' . self::css_decl( 'row-gap', esc_attr( $w['galleryRowGap'] ) ) . '}'; } if ( ! empty( $w['galleryColumnsTablet'] ) ) { $tablet_rules[] = $grid . '{' . self::css_decl( 'grid-template-columns', 'repeat(' . max( 1, min( 6, intval( $w['galleryColumnsTablet'] ) ) ) . ', minmax(0, 1fr))' ) . '}'; } if ( ! empty( $w['galleryColumnsMobile'] ) ) { $mobile_rules[] = $grid . '{' . self::css_decl( 'grid-template-columns', 'repeat(' . max( 1, min( 6, intval( $w['galleryColumnsMobile'] ) ) ) . ', minmax(0, 1fr))' ) . '}'; } if ( ! empty( $w['galleryRadius'] ) ) { $rules[] = $grid . ' .nx-gallery-item{' . self::css_decl( 'border-radius', esc_attr( $w['galleryRadius'] ) ) . '}'; } $gallery_image = ''; if ( ! empty( $w['galleryAspect'] ) && in_array( $w['galleryAspect'], [ '1 / 1', '4 / 3', '16 / 9', '3 / 4' ], true ) ) $gallery_image .= self::css_decl( 'aspect-ratio', $w['galleryAspect'] ); if ( ! empty( $w['galleryObjectFit'] ) && in_array( $w['galleryObjectFit'], [ 'cover', 'contain', 'fill', 'none', 'scale-down' ], true ) ) $gallery_image .= self::css_decl( 'object-fit', $w['galleryObjectFit'] ); if ( ! empty( $w['galleryObjectPosition'] ) && in_array( $w['galleryObjectPosition'], [ 'center center', 'top', 'bottom', 'left', 'right' ], true ) ) $gallery_image .= self::css_decl( 'object-position', $w['galleryObjectPosition'] ); if ( $gallery_image ) $rules[] = $grid . ' .nx-gallery-item{' . $gallery_image . '}'; if ( ! empty( $w['galleryHover'] ) && 'zoom' === $w['galleryHover'] ) { $rules[] = $grid . ' .nx-gallery-item{transition:transform 0.2s ease;}'; $rules[] = $grid . ' .nx-gallery-item:hover{transform:scale(1.05);}'; } } if ( ( $child['type'] ?? '' ) === 'iconbox' ) { $base = '.' . $widget_token . ' .nx-iconbox'; if ( ! empty( $w['iconBoxAlign'] ) ) { $rules[] = $base . '{' . self::css_decl( 'text-align', esc_attr( $w['iconBoxAlign'] ) ) . '}'; } if ( ! empty( $w['iconBoxGap'] ) ) { $rules[] = $base . '{' . self::css_decl( 'gap', esc_attr( $w['iconBoxGap'] ) ) . '}'; } $icon = ''; if ( ! empty( $w['iconBoxIconSize'] ) ) { $icon .= self::css_decl( 'font-size', esc_attr( $w['iconBoxIconSize'] ) ); } if ( ! empty( $w['iconBoxIconColor'] ) ) { $icon .= self::css_decl( 'color', esc_attr( $w['iconBoxIconColor'] ) ); } if ( ! empty( $w['iconBoxIconBg'] ) ) { $icon .= self::css_decl( 'background-color', esc_attr( $w['iconBoxIconBg'] ) ); } if ( $icon ) { $rules[] = $base . ' .nx-iconbox-icon{' . $icon . '}'; } if ( ! empty( $w['iconBoxImageWidth'] ) ) { $rules[] = $base . ' .nx-iconbox-image{' . self::css_decl( 'width', esc_attr( $w['iconBoxImageWidth'] ) ) . '}'; } $title = self::build_typography_from_prefix( $w, 'iconBoxTitle' ); if ( $title ) { $rules[] = $base . ' .nx-iconbox-title{' . $title . '}'; } $title_t = self::build_typography_from_prefix( $wt, 'iconBoxTitle' ); if ( $title_t ) { $tablet_rules[] = $base . ' .nx-iconbox-title{' . $title_t . '}'; } $title_m = self::build_typography_from_prefix( $wm, 'iconBoxTitle' ); if ( $title_m ) { $mobile_rules[] = $base . ' .nx-iconbox-title{' . $title_m . '}'; } $desc = self::build_typography_from_prefix( $w, 'iconBoxDesc' ); if ( $desc ) { $rules[] = $base . ' .nx-iconbox-desc{' . $desc . '}'; } $desc_t = self::build_typography_from_prefix( $wt, 'iconBoxDesc' ); if ( $desc_t ) { $tablet_rules[] = $base . ' .nx-iconbox-desc{' . $desc_t . '}'; } $desc_m = self::build_typography_from_prefix( $wm, 'iconBoxDesc' ); if ( $desc_m ) { $mobile_rules[] = $base . ' .nx-iconbox-desc{' . $desc_m . '}'; } } if ( ( $child['type'] ?? '' ) === 'spacer' ) { if ( ! empty( $w['spacerHeight'] ) ) { $rules[] = '.' . $widget_token . ' .nx-spacer{' . self::css_decl( 'height', esc_attr( $w['spacerHeight'] ) ) . '}'; } if ( ! empty( $wt['spacerHeight'] ) ) { $tablet_rules[] = '.' . $widget_token . ' .nx-spacer{' . self::css_decl( 'height', esc_attr( $wt['spacerHeight'] ) ) . '}'; } if ( ! empty( $wm['spacerHeight'] ) ) { $mobile_rules[] = '.' . $widget_token . ' .nx-spacer{' . self::css_decl( 'height', esc_attr( $wm['spacerHeight'] ) ) . '}'; } } if ( ( $child['type'] ?? '' ) === 'navmenu' ) { $base = '.' . $widget_token . ' .nx-nav-menu'; $links = $base . ' > .nx-nav-main > .nx-nav-menu-panel > .nx-nav-menu-panel-inner > .nx-nav-menu-list > li > a'; $submenu = $base . ' .sub-menu'; $panel_inner = $base . ' .nx-nav-menu-panel-inner'; $wrap = ''; if ( ! empty( $w['navMobileBreakpoint'] ) ) { $wrap .= self::css_decl( '--nx-nav-breakpoint', esc_attr( self::with_unit( $w['navMobileBreakpoint'], 'px' ) ) ); } if ( ! empty( $w['navMenuItemGap'] ) ) { $wrap .= self::css_decl( '--nx-nav-item-gap', esc_attr( $w['navMenuItemGap'] ) ); } if ( ! empty( $w['navLogoGap'] ) ) { $wrap .= self::css_decl( '--nx-nav-logo-gap', esc_attr( $w['navLogoGap'] ) ); } if ( ! empty( $w['navLogoWidth'] ) ) { $wrap .= self::css_decl( '--nx-nav-logo-width', esc_attr( $w['navLogoWidth'] ) ); } if ( ! empty( $w['navBurgerLineThickness'] ) ) { $wrap .= self::css_decl( '--nx-nav-burger-line-thickness', esc_attr( $w['navBurgerLineThickness'] ) ); } if ( ! empty( $w['navMobilePanelOffset'] ) ) { $wrap .= self::css_decl( '--nx-nav-mobile-panel-offset', esc_attr( $w['navMobilePanelOffset'] ) ); } if ( isset( $w['navZIndex'] ) && '' !== $w['navZIndex'] ) { $wrap .= self::css_decl( '--nx-nav-z-index', esc_attr( $w['navZIndex'] ) ); } if ( ! empty( $w['navStickyTop'] ) ) { $wrap .= self::css_decl( '--nx-nav-sticky-top', esc_attr( $w['navStickyTop'] ) ); } if ( ! empty( $w['navDropdownWidth'] ) ) { $wrap .= self::css_decl( '--nx-nav-dropdown-width', esc_attr( $w['navDropdownWidth'] ) ); } if ( ! empty( $w['navDropdownOffset'] ) ) { $wrap .= self::css_decl( '--nx-nav-dropdown-offset', esc_attr( $w['navDropdownOffset'] ) ); } if ( ! empty( $w['navMobilePanelBg'] ) ) { $wrap .= self::css_decl( '--nx-nav-mobile-panel-bg', esc_attr( $w['navMobilePanelBg'] ) ); } if ( ! empty( $w['navMobilePanelRadius'] ) ) { $wrap .= self::css_decl( '--nx-nav-mobile-panel-radius', esc_attr( $w['navMobilePanelRadius'] ) ); } if ( $wrap ) { $rules[] = $base . '{' . $wrap . '}'; } $main_decl = ''; if ( ! empty( $w['navWrapPaddingTop'] ) ) { $main_decl .= self::css_decl( 'padding-top', esc_attr( $w['navWrapPaddingTop'] ) ); } if ( ! empty( $w['navWrapPaddingRight'] ) ) { $main_decl .= self::css_decl( 'padding-right', esc_attr( $w['navWrapPaddingRight'] ) ); } if ( ! empty( $w['navWrapPaddingBottom'] ) ) { $main_decl .= self::css_decl( 'padding-bottom', esc_attr( $w['navWrapPaddingBottom'] ) ); } if ( ! empty( $w['navWrapPaddingLeft'] ) ) { $main_decl .= self::css_decl( 'padding-left', esc_attr( $w['navWrapPaddingLeft'] ) ); } if ( $main_decl ) { $rules[] = $base . ' .nx-nav-main{' . $main_decl . '}'; } if ( ! empty( $w['navSticky'] ) ) { $sticky_decl = self::css_decl( 'position', 'sticky' ); $sticky_decl .= self::css_decl( 'top', esc_attr( $w['navStickyTop'] ?? '0px' ) ); $sticky_decl .= self::css_decl( 'z-index', esc_attr( $w['navZIndex'] ?? '1000' ) ); $rules[] = $base . '{' . $sticky_decl . '}'; } elseif ( isset( $w['navZIndex'] ) && '' !== $w['navZIndex'] ) { $rules[] = $base . '{' . self::css_decl( 'z-index', esc_attr( $w['navZIndex'] ) ) . '}'; } $link = self::build_typography_from_prefix( $w, 'navMenu' ); if ( ! empty( $w['navMenuItemColor'] ) ) { $link .= self::css_decl( 'color', esc_attr( $w['navMenuItemColor'] ) ); } if ( ! empty( $w['navMenuItemBg'] ) ) { $link .= self::css_decl( 'background-color', esc_attr( $w['navMenuItemBg'] ) ); } if ( ! empty( $w['navMenuItemPaddingTop'] ) ) { $link .= self::css_decl( 'padding-top', esc_attr( $w['navMenuItemPaddingTop'] ) ); } if ( ! empty( $w['navMenuItemPaddingRight'] ) ) { $link .= self::css_decl( 'padding-right', esc_attr( $w['navMenuItemPaddingRight'] ) ); } if ( ! empty( $w['navMenuItemPaddingBottom'] ) ) { $link .= self::css_decl( 'padding-bottom', esc_attr( $w['navMenuItemPaddingBottom'] ) ); } if ( ! empty( $w['navMenuItemPaddingLeft'] ) ) { $link .= self::css_decl( 'padding-left', esc_attr( $w['navMenuItemPaddingLeft'] ) ); } if ( ! empty( $w['navMenuItemMarginTop'] ) ) { $link .= self::css_decl( 'margin-top', esc_attr( $w['navMenuItemMarginTop'] ) ); } if ( ! empty( $w['navMenuItemMarginRight'] ) ) { $link .= self::css_decl( 'margin-right', esc_attr( $w['navMenuItemMarginRight'] ) ); } if ( ! empty( $w['navMenuItemMarginBottom'] ) ) { $link .= self::css_decl( 'margin-bottom', esc_attr( $w['navMenuItemMarginBottom'] ) ); } if ( ! empty( $w['navMenuItemMarginLeft'] ) ) { $link .= self::css_decl( 'margin-left', esc_attr( $w['navMenuItemMarginLeft'] ) ); } if ( $link ) { $rules[] = $links . '{' . $link . '}'; } $hover = ''; if ( ! empty( $w['navMenuItemHoverColor'] ) ) { $hover .= self::css_decl( 'color', esc_attr( $w['navMenuItemHoverColor'] ) ); } if ( ! empty( $w['navMenuItemHoverBg'] ) ) { $hover .= self::css_decl( 'background-color', esc_attr( $w['navMenuItemHoverBg'] ) ); } if ( $hover ) { $rules[] = $links . ':hover{' . $hover . '}'; } $active = ''; if ( ! empty( $w['navMenuItemActiveColor'] ) ) { $active .= self::css_decl( 'color', esc_attr( $w['navMenuItemActiveColor'] ) ); } if ( ! empty( $w['navMenuItemActiveBg'] ) ) { $active .= self::css_decl( 'background-color', esc_attr( $w['navMenuItemActiveBg'] ) ); } if ( $active ) { $rules[] = $base . ' .current-menu-item > a{' . $active . '}'; $rules[] = $base . ' .current-menu-ancestor > a{' . $active . '}'; } $sub = ''; if ( ! empty( $w['navDropdownBg'] ) ) { $sub .= self::css_decl( 'background-color', esc_attr( $w['navDropdownBg'] ) ); } if ( ! empty( $w['navDropdownRadius'] ) ) { $sub .= self::css_decl( 'border-radius', esc_attr( $w['navDropdownRadius'] ) ); } if ( ! empty( $w['navDropdownItemSpacing'] ) ) { $sub .= self::css_decl( 'gap', esc_attr( $w['navDropdownItemSpacing'] ) ); } if ( ! empty( $w['navDropdownWidth'] ) ) { $sub .= self::css_decl( 'min-width', esc_attr( $w['navDropdownWidth'] ) ); } if ( ! empty( $w['navDropdownOffset'] ) ) { $sub .= self::css_decl( 'margin-top', esc_attr( $w['navDropdownOffset'] ) ); } $has_sub_shadow = ( isset( $w['navDropdownShadowX'] ) && '' !== $w['navDropdownShadowX'] ) || ( isset( $w['navDropdownShadowY'] ) && '' !== $w['navDropdownShadowY'] ) || ( isset( $w['navDropdownShadowBlur'] ) && '' !== $w['navDropdownShadowBlur'] ) || ( isset( $w['navDropdownShadowSpread'] ) && '' !== $w['navDropdownShadowSpread'] ) || ( ! empty( $w['navDropdownShadowColor'] ) ); if ( $has_sub_shadow ) { $x = self::with_unit( $w['navDropdownShadowX'] ?? 0, 'px' ); $y = self::with_unit( $w['navDropdownShadowY'] ?? 8, 'px' ); $b = self::with_unit( $w['navDropdownShadowBlur'] ?? 20, 'px' ); $s_spread = self::with_unit( $w['navDropdownShadowSpread'] ?? 0, 'px' ); $color = esc_attr( $w['navDropdownShadowColor'] ?? 'rgba(0,0,0,0.15)' ); $sub .= self::css_decl( 'box-shadow', esc_attr( trim( $x . ' ' . $y . ' ' . $b . ' ' . $s_spread . ' ' . $color ) ) ); } if ( $sub ) { $rules[] = $submenu . '{' . $sub . '}'; } if ( ! empty( $w['navBurgerColor'] ) ) { $rules[] = $base . ' .nx-nav-toggle{' . self::css_decl( 'color', esc_attr( $w['navBurgerColor'] ) ) . '}'; $rules[] = $base . ' .nx-nav-toggle span{' . self::css_decl( 'background-color', esc_attr( $w['navBurgerColor'] ) ) . '}'; } if ( ! empty( $w['navBurgerSize'] ) ) { $rules[] = $base . ' .nx-nav-toggle{' . self::css_decl( 'width', esc_attr( $w['navBurgerSize'] ) ) . self::css_decl( 'height', esc_attr( $w['navBurgerSize'] ) ) . '}'; } if ( ! empty( $w['navBurgerLineThickness'] ) ) { $rules[] = $base . ' .nx-nav-toggle span{' . self::css_decl( 'height', esc_attr( $w['navBurgerLineThickness'] ) ) . '}'; } if ( ! empty( $w['navMobileOverlayBg'] ) ) { $rules[] = $base . ' .nx-nav-menu-panel{' . self::css_decl( '--nx-nav-overlay-bg', esc_attr( $w['navMobileOverlayBg'] ) ) . '}'; } $logo_decl = ''; if ( ! empty( $w['navLogoWidth'] ) ) { $logo_decl .= self::css_decl( 'width', esc_attr( $w['navLogoWidth'] ) ); } if ( ! empty( $w['navLogoRadius'] ) ) { $logo_decl .= self::css_decl( 'border-radius', esc_attr( $w['navLogoRadius'] ) ); } if ( $logo_decl ) { $rules[] = $base . ' .nx-nav-logo-image{' . $logo_decl . '}'; } $panel_inner_decl = ''; if ( ! empty( $w['navMobilePanelBg'] ) ) { $panel_inner_decl .= self::css_decl( 'background-color', esc_attr( $w['navMobilePanelBg'] ) ); } if ( ! empty( $w['navMobilePanelRadius'] ) ) { $panel_inner_decl .= self::css_decl( 'border-radius', esc_attr( $w['navMobilePanelRadius'] ) ); } if ( $panel_inner_decl ) { $rules[] = $panel_inner . '{' . $panel_inner_decl . '}'; } $link_t = self::build_typography_from_prefix( $wt, 'navMenu' ); if ( $link_t ) { $tablet_rules[] = $links . '{' . $link_t . '}'; } $link_m = self::build_typography_from_prefix( $wm, 'navMenu' ); if ( $link_m ) { $mobile_rules[] = $links . '{' . $link_m . '}'; } } if ( ( $child['type'] ?? '' ) === 'image' ) { $img = ''; if ( ! empty( $w['imgWidth'] ) ) { $img .= self::css_decl( 'width', esc_attr( $w['imgWidth'] ) ); } if ( ! empty( $w['imgMaxWidth'] ) ) { $img .= self::css_decl( 'max-width', esc_attr( $w['imgMaxWidth'] ) ); } if ( ! empty( $w['imgHeight'] ) ) { $img .= self::css_decl( 'height', esc_attr( $w['imgHeight'] ) ); } if ( ! empty( $w['objectFit'] ) ) { $img .= self::css_decl( 'object-fit', esc_attr( $w['objectFit'] ) ); } if ( ! empty( $w['objectPosition'] ) ) { $img .= self::css_decl( 'object-position', esc_attr( $w['objectPosition'] ) ); } if ( $img ) { $rules[] = '.' . $widget_token . ' img{' . $img . '}'; } $imgt = ''; if ( ! empty( $wt['imgWidth'] ) ) { $imgt .= self::css_decl( 'width', esc_attr( $wt['imgWidth'] ) ); } if ( ! empty( $wt['imgMaxWidth'] ) ) { $imgt .= self::css_decl( 'max-width', esc_attr( $wt['imgMaxWidth'] ) ); } if ( ! empty( $wt['imgHeight'] ) ) { $imgt .= self::css_decl( 'height', esc_attr( $wt['imgHeight'] ) ); } if ( ! empty( $wt['objectFit'] ) ) { $imgt .= self::css_decl( 'object-fit', esc_attr( $wt['objectFit'] ) ); } if ( ! empty( $wt['objectPosition'] ) ) { $imgt .= self::css_decl( 'object-position', esc_attr( $wt['objectPosition'] ) ); } if ( $imgt ) { $tablet_rules[] = '.' . $widget_token . ' img{' . $imgt . '}'; } $imgm = ''; if ( ! empty( $wm['imgWidth'] ) ) { $imgm .= self::css_decl( 'width', esc_attr( $wm['imgWidth'] ) ); } if ( ! empty( $wm['imgMaxWidth'] ) ) { $imgm .= self::css_decl( 'max-width', esc_attr( $wm['imgMaxWidth'] ) ); } if ( ! empty( $wm['imgHeight'] ) ) { $imgm .= self::css_decl( 'height', esc_attr( $wm['imgHeight'] ) ); } if ( ! empty( $wm['objectFit'] ) ) { $imgm .= self::css_decl( 'object-fit', esc_attr( $wm['objectFit'] ) ); } if ( ! empty( $wm['objectPosition'] ) ) { $imgm .= self::css_decl( 'object-position', esc_attr( $wm['objectPosition'] ) ); } if ( $imgm ) { $mobile_rules[] = '.' . $widget_token . ' img{' . $imgm . '}'; } } if ( ( $child['type'] ?? '' ) === 'button' ) { $btn = ''; if ( ! empty( $w['btnTextColor'] ) ) { $btn .= self::css_decl( 'color', esc_attr( $w['btnTextColor'] ) ); } elseif ( ! empty( $w['color'] ) ) { $btn .= self::css_decl( 'color', esc_attr( $w['color'] ) ); } if ( ! empty( $w['btnBgColor'] ) ) { $btn .= self::css_decl( 'background-color', esc_attr( $w['btnBgColor'] ) ); } if ( ! empty( $w['fontFamily'] ) ) { $btn .= self::css_decl( 'font-family', self::format_font_family( $w['fontFamily'] ) ); } if ( '' !== $w['fontSize'] ) { $btn .= self::css_decl( 'font-size', esc_attr( $w['fontSize'] ) ); } if ( ! empty( $w['fontWeight'] ) ) { $btn .= self::css_decl( 'font-weight', esc_attr( $w['fontWeight'] ) ); } if ( ! empty( $w['fontStyle'] ) ) { $btn .= self::css_decl( 'font-style', $w['fontStyle'] ); } if ( '' !== $w['lineHeight'] ) { $btn .= self::css_decl( 'line-height', esc_attr( $w['lineHeight'] ) ); } if ( '' !== $w['letterSpacing'] ) { $btn .= self::css_decl( 'letter-spacing', esc_attr( $w['letterSpacing'] ) ); } if ( ! empty( $w['textTransform'] ) ) { $btn .= self::css_decl( 'text-transform', esc_attr( $w['textTransform'] ) ); } if ( ! empty( $w['textDecoration'] ) ) { $btn .= self::css_decl( 'text-decoration', esc_attr( $w['textDecoration'] ) ); } if ( ! empty( $w['iconSpacing'] ) ) { $btn .= self::css_decl( '--nx-button-icon-spacing', esc_attr( $w['iconSpacing'] ) ); } if ( ! empty( $w['btnPaddingTop'] ) ) { $btn .= self::css_decl( 'padding-top', esc_attr( $w['btnPaddingTop'] ) ); } if ( ! empty( $w['btnPaddingRight'] ) ) { $btn .= self::css_decl( 'padding-right', esc_attr( $w['btnPaddingRight'] ) ); } if ( ! empty( $w['btnPaddingBottom'] ) ) { $btn .= self::css_decl( 'padding-bottom', esc_attr( $w['btnPaddingBottom'] ) ); } if ( ! empty( $w['btnPaddingLeft'] ) ) { $btn .= self::css_decl( 'padding-left', esc_attr( $w['btnPaddingLeft'] ) ); } if ( ! empty( $w['borderStyle'] ) ) { $btn .= self::css_decl( 'border-style', esc_attr( $w['borderStyle'] ) ); } if ( ! empty( $w['borderColor'] ) ) { $btn .= self::css_decl( 'border-color', esc_attr( $w['borderColor'] ) ); } if ( ! empty( $w['borderTopWidth'] ) ) { $btn .= self::css_decl( 'border-top-width', esc_attr( $w['borderTopWidth'] ) ); } if ( ! empty( $w['borderRightWidth'] ) ) { $btn .= self::css_decl( 'border-right-width', esc_attr( $w['borderRightWidth'] ) ); } if ( ! empty( $w['borderBottomWidth'] ) ) { $btn .= self::css_decl( 'border-bottom-width', esc_attr( $w['borderBottomWidth'] ) ); } if ( ! empty( $w['borderLeftWidth'] ) ) { $btn .= self::css_decl( 'border-left-width', esc_attr( $w['borderLeftWidth'] ) ); } if ( ! empty( $w['borderRadius'] ) ) { $btn .= self::css_decl( 'border-radius', esc_attr( $w['borderRadius'] ) ); } if ( $btn ) { $rules[] = '.' . $widget_token . ' .nx-btn{' . $btn . '}'; } if ( ! empty( $w['btnHoverBgColor'] ) ) { $rules[] = '.' . $widget_token . ' .nx-btn:hover{' . self::css_decl( 'background-color', esc_attr( $w['btnHoverBgColor'] ) ) . '}'; } $bt = ''; if ( ! empty( $wt['btnTextColor'] ) ) { $bt .= self::css_decl( 'color', esc_attr( $wt['btnTextColor'] ) ); } elseif ( ! empty( $wt['color'] ) ) { $bt .= self::css_decl( 'color', esc_attr( $wt['color'] ) ); } if ( ! empty( $wt['btnBgColor'] ) ) { $bt .= self::css_decl( 'background-color', esc_attr( $wt['btnBgColor'] ) ); } if ( ! empty( $wt['fontFamily'] ) ) { $bt .= self::css_decl( 'font-family', self::format_font_family( $wt['fontFamily'] ) ); } if ( '' !== $wt['fontSize'] ) { $bt .= self::css_decl( 'font-size', esc_attr( $wt['fontSize'] ) ); } if ( ! empty( $wt['fontWeight'] ) ) { $bt .= self::css_decl( 'font-weight', esc_attr( $wt['fontWeight'] ) ); } if ( ! empty( $wt['fontStyle'] ) ) { $bt .= self::css_decl( 'font-style', $wt['fontStyle'] ); } if ( '' !== $wt['lineHeight'] ) { $bt .= self::css_decl( 'line-height', esc_attr( $wt['lineHeight'] ) ); } if ( '' !== $wt['letterSpacing'] ) { $bt .= self::css_decl( 'letter-spacing', esc_attr( $wt['letterSpacing'] ) ); } if ( ! empty( $wt['textTransform'] ) ) { $bt .= self::css_decl( 'text-transform', esc_attr( $wt['textTransform'] ) ); } if ( ! empty( $wt['textDecoration'] ) ) { $bt .= self::css_decl( 'text-decoration', esc_attr( $wt['textDecoration'] ) ); } if ( ! empty( $wt['btnPaddingTop'] ) ) { $bt .= self::css_decl( 'padding-top', esc_attr( $wt['btnPaddingTop'] ) ); } if ( ! empty( $wt['btnPaddingRight'] ) ) { $bt .= self::css_decl( 'padding-right', esc_attr( $wt['btnPaddingRight'] ) ); } if ( ! empty( $wt['btnPaddingBottom'] ) ) { $bt .= self::css_decl( 'padding-bottom', esc_attr( $wt['btnPaddingBottom'] ) ); } if ( ! empty( $wt['btnPaddingLeft'] ) ) { $bt .= self::css_decl( 'padding-left', esc_attr( $wt['btnPaddingLeft'] ) ); } if ( ! empty( $wt['borderStyle'] ) ) { $bt .= self::css_decl( 'border-style', esc_attr( $wt['borderStyle'] ) ); } if ( ! empty( $wt['borderColor'] ) ) { $bt .= self::css_decl( 'border-color', esc_attr( $wt['borderColor'] ) ); } if ( ! empty( $wt['borderTopWidth'] ) ) { $bt .= self::css_decl( 'border-top-width', esc_attr( $wt['borderTopWidth'] ) ); } if ( ! empty( $wt['borderRightWidth'] ) ) { $bt .= self::css_decl( 'border-right-width', esc_attr( $wt['borderRightWidth'] ) ); } if ( ! empty( $wt['borderBottomWidth'] ) ) { $bt .= self::css_decl( 'border-bottom-width', esc_attr( $wt['borderBottomWidth'] ) ); } if ( ! empty( $wt['borderLeftWidth'] ) ) { $bt .= self::css_decl( 'border-left-width', esc_attr( $wt['borderLeftWidth'] ) ); } if ( ! empty( $wt['borderRadius'] ) ) { $bt .= self::css_decl( 'border-radius', esc_attr( $wt['borderRadius'] ) ); } if ( $bt ) { $tablet_rules[] = '.' . $widget_token . ' .nx-btn{' . $bt . '}'; } $bm = ''; if ( ! empty( $wm['btnTextColor'] ) ) { $bm .= self::css_decl( 'color', esc_attr( $wm['btnTextColor'] ) ); } elseif ( ! empty( $wm['color'] ) ) { $bm .= self::css_decl( 'color', esc_attr( $wm['color'] ) ); } if ( ! empty( $wm['btnBgColor'] ) ) { $bm .= self::css_decl( 'background-color', esc_attr( $wm['btnBgColor'] ) ); } if ( ! empty( $wm['fontFamily'] ) ) { $bm .= self::css_decl( 'font-family', self::format_font_family( $wm['fontFamily'] ) ); } if ( '' !== $wm['fontSize'] ) { $bm .= self::css_decl( 'font-size', esc_attr( $wm['fontSize'] ) ); } if ( ! empty( $wm['fontWeight'] ) ) { $bm .= self::css_decl( 'font-weight', esc_attr( $wm['fontWeight'] ) ); } if ( ! empty( $wm['fontStyle'] ) ) { $bm .= self::css_decl( 'font-style', $wm['fontStyle'] ); } if ( '' !== $wm['lineHeight'] ) { $bm .= self::css_decl( 'line-height', esc_attr( $wm['lineHeight'] ) ); } if ( '' !== $wm['letterSpacing'] ) { $bm .= self::css_decl( 'letter-spacing', esc_attr( $wm['letterSpacing'] ) ); } if ( ! empty( $wm['textTransform'] ) ) { $bm .= self::css_decl( 'text-transform', esc_attr( $wm['textTransform'] ) ); } if ( ! empty( $wm['textDecoration'] ) ) { $bm .= self::css_decl( 'text-decoration', esc_attr( $wm['textDecoration'] ) ); } if ( ! empty( $wm['btnPaddingTop'] ) ) { $bm .= self::css_decl( 'padding-top', esc_attr( $wm['btnPaddingTop'] ) ); } if ( ! empty( $wm['btnPaddingRight'] ) ) { $bm .= self::css_decl( 'padding-right', esc_attr( $wm['btnPaddingRight'] ) ); } if ( ! empty( $wm['btnPaddingBottom'] ) ) { $bm .= self::css_decl( 'padding-bottom', esc_attr( $wm['btnPaddingBottom'] ) ); } if ( ! empty( $wm['btnPaddingLeft'] ) ) { $bm .= self::css_decl( 'padding-left', esc_attr( $wm['btnPaddingLeft'] ) ); } if ( ! empty( $wm['borderStyle'] ) ) { $bm .= self::css_decl( 'border-style', esc_attr( $wm['borderStyle'] ) ); } if ( ! empty( $wm['borderColor'] ) ) { $bm .= self::css_decl( 'border-color', esc_attr( $wm['borderColor'] ) ); } if ( ! empty( $wm['borderTopWidth'] ) ) { $bm .= self::css_decl( 'border-top-width', esc_attr( $wm['borderTopWidth'] ) ); } if ( ! empty( $wm['borderRightWidth'] ) ) { $bm .= self::css_decl( 'border-right-width', esc_attr( $wm['borderRightWidth'] ) ); } if ( ! empty( $wm['borderBottomWidth'] ) ) { $bm .= self::css_decl( 'border-bottom-width', esc_attr( $wm['borderBottomWidth'] ) ); } if ( ! empty( $wm['borderLeftWidth'] ) ) { $bm .= self::css_decl( 'border-left-width', esc_attr( $wm['borderLeftWidth'] ) ); } if ( ! empty( $wm['borderRadius'] ) ) { $bm .= self::css_decl( 'border-radius', esc_attr( $wm['borderRadius'] ) ); } if ( $bm ) { $mobile_rules[] = '.' . $widget_token . ' .nx-btn{' . $bm . '}'; } } } } } } } if ( ! empty( $tablet_rules ) ) { $rules[] = '@media (max-width: 980px){' . implode( '', $tablet_rules ) . '}'; } if ( ! empty( $mobile_rules ) ) { $rules[] = '@media (max-width: 767px){' . implode( '', $mobile_rules ) . '}'; } $extension_css = Module_Registry::generate_frontend_css( $json ); if ( $extension_css ) { $rules[] = $extension_css; } if ( ! empty( $visibility_rules ) ) { $rules = array_merge( $rules, $visibility_rules ); } if ( empty( $rules ) ) { return ''; } return "/* Nyxonn Builder frontend styles */\n" . implode( "\n", $rules ) . "\n"; } /** Generate sanitized request CSS for a trusted saved layout without persistence. */ public static function generate_layout_css( $layout ) { $json = is_array( $layout ) ? $layout : json_decode( (string) $layout, true ); return is_array( $json ) ? self::generate_frontend_css( $json ) : ''; } /** Enqueue all request fonts early enough for WordPress to print them in the document head. */ public static function enqueue_google_fonts_for_layouts( $layouts ) { $merged = []; foreach ( (array) $layouts as $layout ) { $json = is_array( $layout ) ? $layout : json_decode( (string) $layout, true ); if ( is_array( $json ) ) { $merged = array_merge( $merged, $json ); } } if ( $merged ) { self::build_google_font_links( $merged ); } } /** Attach request layout CSS to WordPress style handles before the document head is printed. */ public static function enqueue_layout_styles( $layout_contexts ) { $critical_css = []; $deferred_css = []; $normal_css = []; $split_enabled = Performance_Settings::is_enabled( 'critical_css' ); foreach ( (array) $layout_contexts as $item ) { $layout = is_array( $item ) && array_key_exists( 'layout', $item ) ? $item['layout'] : $item; $context = is_array( $item ) ? sanitize_key( $item['context'] ?? 'content' ) : 'content'; if ( ! $split_enabled ) { $css = self::generate_layout_css( $layout ); if ( $css ) $normal_css[] = $css; continue; } if ( 'header' === $context ) { $split = [ 'critical' => self::generate_layout_css( $layout ), 'deferred' => '' ]; } elseif ( 'footer' === $context ) { $split = [ 'critical' => '', 'deferred' => self::generate_layout_css( $layout ) ]; } else { $split = self::split_critical_css( $layout ); } if ( $split['critical'] ) $critical_css[] = $split['critical']; if ( $split['deferred'] ) $deferred_css[] = $split['deferred']; } if ( $normal_css ) { wp_add_inline_style( 'nyxonn-builder-frontend-css', self::sanitize_inline_css_text( implode( "\n", $normal_css ) ) ); } if ( $critical_css ) { wp_register_style( 'nyxonn-builder-critical-css', false, [], NYXONN_BUILDER_VERSION ); wp_enqueue_style( 'nyxonn-builder-critical-css' ); wp_add_inline_style( 'nyxonn-builder-critical-css', self::sanitize_inline_css_text( implode( "\n", $critical_css ) ) ); } if ( $deferred_css ) { // WordPress has no API for a noscript wrapper around inline CSS. Loading this // handle normally preserves the no-JavaScript fallback without an onload handler. wp_register_style( 'nyxonn-builder-deferred-css', false, [ 'nyxonn-builder-frontend-css' ], NYXONN_BUILDER_VERSION ); wp_enqueue_style( 'nyxonn-builder-deferred-css' ); wp_add_inline_style( 'nyxonn-builder-deferred-css', self::sanitize_inline_css_text( implode( "\n", $deferred_css ) ) ); } } /** Split generated CSS by initial section estimates; static frontend CSS is never deferred. */ public static function split_critical_css( $layout, $threshold = null ) { $json = is_array( $layout ) ? $layout : json_decode( (string) $layout, true ); if ( ! is_array( $json ) || ! $json ) { return [ 'critical' => '', 'deferred' => '' ]; } $threshold = null === $threshold ? Performance_Settings::get_critical_threshold_pixels() : max( 1, absint( $threshold ) ); $critical = []; $deferred = []; $estimated_height = 0; foreach ( $json as $index => $section ) { if ( 0 === $index || $estimated_height < $threshold ) { $critical[] = $section; $estimated_height += self::estimate_section_height( $section ); } else { $deferred[] = $section; } } return [ 'critical' => self::generate_frontend_css( $critical ), 'deferred' => self::generate_frontend_css( $deferred ), ]; } private static function estimate_section_height( $section ) { $settings = is_array( $section ) && isset( $section['settings'] ) && is_array( $section['settings'] ) ? $section['settings'] : []; foreach ( [ 'minHeight', 'height' ] as $key ) { $value = trim( (string) ( $settings[ $key ] ?? '' ) ); if ( preg_match( '/^(\d+(?:\.\d+)?)px$/i', $value, $matches ) ) { return max( 1, (int) round( (float) $matches[1] ) ); } } return 600; } /* ========================= MAIN RENDER ========================== */ public static function render( $content ) { $preview_flag = isset( $_GET['nx_preview'] ) ? sanitize_text_field( wp_unslash( $_GET['nx_preview'] ) ) : ''; $is_preview_request = '1' === $preview_flag; $post_id = get_the_ID(); if ( ! $post_id ) { return $content; } if ( ! is_singular() && ! $is_preview_request ) { return $content; } if ( ! \NyxonnBuilder\Save::is_enabled( $post_id ) && ! $is_preview_request ) { return $content; } $layout = \NyxonnBuilder\Save::get_layout_for_post( $post_id ); if ( empty( $layout ) ) { return $content; } return self::render_layout( $layout, $content, 'content' ); } /** * Render a Nyxonn Builder layout JSON (string or array) and return HTML. * * @param string|array $layout Layout JSON string or decoded array. * @param string $fallback Fallback HTML if layout invalid. * @return string */ public static function render_layout( $layout, $fallback = '', $context = 'content' ) { $json = is_array( $layout ) ? $layout : json_decode( (string) $layout, true ); if ( ! is_array( $json ) ) { return $fallback; } ob_start(); self::build_google_font_links( $json ); $context = sanitize_key( (string) $context ); if ( ! in_array( $context, [ 'content', 'header', 'footer', 'template' ], true ) ) { $context = 'content'; } $wrapper_tag = 'div'; if ( 'header' === $context ) { $wrapper_tag = self::layout_has_semantic_root( $json, 'header' ) ? 'div' : 'header'; } elseif ( 'footer' === $context ) { $wrapper_tag = self::layout_has_semantic_root( $json, 'footer' ) ? 'div' : 'footer'; } $page_attributes = ''; $wrapper_classes = 'nx-wrapper nx-wrapper--' . $context; if ( 'content' === $context && class_exists( Page_Settings::class ) ) { $page_id = get_the_ID(); $attributes = Page_Settings::wrapper_attributes( $page_id ); $wrapper_classes .= ' ' . $attributes['classes']; $page_attributes .= ' data-nx-page-id="' . intval( $attributes['postId'] ) . '"'; if ( $attributes['id'] ) $page_attributes .= ' id="' . esc_attr( $attributes['id'] ) . '"'; } printf( '<%1$s class="%2$s" data-nx-area="%3$s"%4$s>', esc_attr( $wrapper_tag ), esc_attr( trim( $wrapper_classes ) ), esc_attr( $context ), $page_attributes // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Attribute values escaped above. ); foreach ( $json as $section ) { self::render_section( $section ); } printf( '%s>', esc_attr( $wrapper_tag ) ); return ob_get_clean(); } /** Avoid invalid nested header/footer landmarks when the layout owns its semantic root. */ private static function layout_has_semantic_root( $layout, $tag ) { foreach ( (array) $layout as $node ) { if ( is_array( $node ) && 'section' === ( $node['type'] ?? '' ) && $tag === strtolower( (string) ( $node['settings']['semanticTag'] ?? '' ) ) ) return true; } return false; } /* ========================= SECTION ========================= */ private static function build_extension_attributes( $settings, $element_type ) { $attributes = apply_filters( 'nyxonn_fx_render_element_attributes', [], is_array( $settings ) ? $settings : [], sanitize_key( $element_type ) ); if ( ! is_array( $attributes ) ) return ''; $html = ''; foreach ( $attributes as $name => $value ) { $name = strtolower( (string) $name ); if ( ! preg_match( '/^data-[a-z0-9][a-z0-9-]*$/', $name ) || ! is_scalar( $value ) ) continue; $html .= ' ' . $name . '=' . chr( 34 ) . esc_attr( (string) $value ) . chr( 34 ); } return $html; } protected static function render_section( $section ) { if ( empty( $section['type'] ) || $section['type'] !== 'section' ) { return; } $section = self::resolve_linked_section( $section ); $settings = $section['settings'] ?? []; $section_class = 'nx-section'; if ( ! empty( $settings['className'] ) ) { $section_class .= ' ' . self::sanitize_html_class_list( $settings['className'] ); } if ( ! empty( $settings['isGlobalSection'] ) ) { $section_class .= ' nx-global-section'; } if ( ! empty( $settings['stickyEnabled'] ) ) { $section_class .= ' nx-sticky-enabled'; } $section_id = ! empty( $settings['id'] ) ? sanitize_html_class( $settings['id'] ) : ''; $sticky_attrs = ''; if ( ! empty( $settings['stickyEnabled'] ) ) { $sticky_attrs .= ' data-nx-sticky="true"'; $sticky_attrs .= ' data-nx-sticky-devices="' . esc_attr( $settings['stickyDevices'] ?? 'desktop' ) . '"'; $sticky_attrs .= ' data-nx-sticky-scope="' . esc_attr( $settings['stickyScope'] ?? 'parent' ) . '"'; $sticky_attrs .= ' data-nx-sticky-side="' . esc_attr( $settings['stickySide'] ?? 'top' ) . '"'; $sticky_attrs .= ' data-nx-sticky-top="' . esc_attr( $settings['stickyTop'] ?? '0px' ) . '"'; $sticky_attrs .= ' data-nx-sticky-bottom="' . esc_attr( $settings['stickyBottom'] ?? '0px' ) . '"'; $sticky_attrs .= ' data-nx-sticky-z="' . esc_attr( $settings['stickyZIndex'] ?? '1000' ) . '"'; if ( ! empty( $settings['stickyBg'] ) ) { $sticky_attrs .= ' data-nx-sticky-bg="' . esc_attr( $settings['stickyBg'] ) . '"'; } } $sticky_attrs .= self::build_extension_attributes( $settings, 'section' ); $semantic_tag = strtolower( (string) ( $settings['semanticTag'] ?? 'section' ) ); if ( ! in_array( $semantic_tag, [ 'section', 'div', 'header', 'footer', 'main', 'article', 'aside' ], true ) ) { $semantic_tag = 'section'; } if ( $section_id ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Tag is allowlisted and every assembled attribute value is escaped above. printf( '<%1$s class="%2$s" id="%3$s"%4$s>', esc_attr( $semantic_tag ), esc_attr( $section_class ), esc_attr( $section_id ), $sticky_attrs ); } else { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Tag is allowlisted and every assembled attribute value is escaped above. printf( '<%1$s class="%2$s"%3$s>', esc_attr( $semantic_tag ), esc_attr( $section_class ), $sticky_attrs ); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Helper returns fixed markup with every URL and attribute escaped. echo self::render_background_video_html( $settings ); /* Overlay */ $has_overlay_stops = isset( $settings['overlayGradientStops'] ) && is_array( $settings['overlayGradientStops'] ) && count( $settings['overlayGradientStops'] ); if ( ! empty( $settings['overlayColor'] ) || ! empty( $settings['overlayGradientStart'] ) || $has_overlay_stops || ! empty( $settings['overlayImage'] ) ) { echo '
'; } /* ROW */ $row_class = ! empty( $settings['rowClass'] ) ? self::sanitize_html_class_list( $settings['rowClass'] ) : ''; if ( ! empty( $section['rows'] ) && is_array( $section['rows'] ) ) { foreach ( $section['rows'] as $row ) { $row_settings = $row['settings'] ?? []; $row_item_class = ! empty( $row_settings['className'] ) ? self::sanitize_html_class_list( $row_settings['className'] ) : ''; $row_classes = trim( 'nx-row ' . $row_class . ' ' . $row_item_class . ( ! empty( $row_settings['stickyEnabled'] ) ? ' nx-sticky-enabled' : '' ) ); $row_sticky_attrs = ''; if ( ! empty( $row_settings['stickyEnabled'] ) ) { $row_sticky_attrs .= ' data-nx-sticky="true"'; $row_sticky_attrs .= ' data-nx-sticky-devices="' . esc_attr( $row_settings['stickyDevices'] ?? 'desktop' ) . '"'; $row_sticky_attrs .= ' data-nx-sticky-scope="' . esc_attr( $row_settings['stickyScope'] ?? 'parent' ) . '"'; $row_sticky_attrs .= ' data-nx-sticky-side="' . esc_attr( $row_settings['stickySide'] ?? 'top' ) . '"'; $row_sticky_attrs .= ' data-nx-sticky-top="' . esc_attr( $row_settings['stickyTop'] ?? '0px' ) . '"'; $row_sticky_attrs .= ' data-nx-sticky-bottom="' . esc_attr( $row_settings['stickyBottom'] ?? '0px' ) . '"'; $row_sticky_attrs .= ' data-nx-sticky-z="' . esc_attr( $row_settings['stickyZIndex'] ?? '1000' ) . '"'; if ( ! empty( $row_settings['stickyBg'] ) ) { $row_sticky_attrs .= ' data-nx-sticky-bg="' . esc_attr( $row_settings['stickyBg'] ) . '"'; } } $row_sticky_attrs .= self::build_extension_attributes( $row_settings, 'row' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Every assembled attribute value is escaped above. printf( '