build_css( $settings ); if ( '' === trim( $css ) ) { return; } $deps = array(); foreach ( array( 'c7wp', 'commerce7', 'c7-base', 'c7css', 'wp-commerce7', 'c7dbt-google-fonts' ) as $handle ) { if ( wp_style_is( $handle, 'registered' ) || wp_style_is( $handle, 'enqueued' ) ) { $deps[] = $handle; } } wp_register_style( 'c7dbt-branding', false, $deps, C7DBT_VERSION ); wp_enqueue_style( 'c7dbt-branding' ); wp_add_inline_style( 'c7dbt-branding', $css ); } /** * Build :root CSS variable overrides + extras. * * @param array $settings Settings. * @return string */ public function build_css( array $settings ) { $map = C7DBT_Settings::brand_css_map(); $brand = isset( $settings['brand'] ) && is_array( $settings['brand'] ) ? $settings['brand'] : array(); $scope = isset( $settings['brand_scope'] ) ? $settings['brand_scope'] : array(); $rules = array(); $button_keys = array( 'primary_button_bg', 'primary_button_bg_hover', 'primary_button_text_color', 'alt_button_bg', 'alt_button_bg_hover', 'alt_button_text_color', 'button_border_radius', 'primary_color', 'primary_color_dark', 'primary_color_focus' ); $text_keys = array( 'text_color', 'alt_text_color', 'link_color', 'header_text_color', 'heading_text_color', 'heading_font_family', 'font_family', 'font_size' ); $form_keys = array( 'field_border_radius', 'field_border_color', 'field_focus_color', 'block_bg', 'block_border_color', 'block_border_radius', 'modal_shadow', 'overlay_bg', 'bg_alt' ); $cart_keys = array( 'cart_count_bg', 'cart_count_text_color', 'header_text_color' ); foreach ( $map as $key => $css_var ) { if ( empty( $brand[ $key ] ) ) { continue; } if ( in_array( $key, $button_keys, true ) && empty( $scope['buttons'] ) ) { continue; } if ( in_array( $key, $text_keys, true ) && empty( $scope['text'] ) ) { continue; } if ( in_array( $key, $form_keys, true ) && empty( $scope['forms'] ) ) { continue; } if ( in_array( $key, $cart_keys, true ) && empty( $scope['cart'] ) && ! in_array( $key, $text_keys, true ) ) { continue; } $val = $brand[ $key ]; if ( false !== strpos( $key, 'font_family' ) || false !== strpos( $key, 'heading_font' ) ) { $val = $this->format_font_stack( $val ); } elseif ( false !== strpos( $key, 'radius' ) || 'font_size' === $key ) { $val = $this->format_size( $val ); } else { // Hex / rgba / shadow tokens — block CSS injection. $hex = sanitize_hex_color( $val ); if ( $hex ) { $val = $hex; } elseif ( preg_match( '/^(rgba?|hsla?)\(\s*[\d.%,\s\/]+\)$/i', trim( (string) $val ) ) ) { $val = trim( (string) $val ); } elseif ( 'modal_shadow' === $key ) { $val = preg_replace( '/[<>{};]/', '', (string) $val ); } else { $val = preg_replace( '/[<>{};]/', '', (string) $val ); } } if ( '' === $val ) { continue; } $rules[] = $css_var . ': ' . $val . ';'; } $css = ''; if ( $rules ) { $css .= ":root {\n\t" . implode( "\n\t", $rules ) . "\n}\n"; } // Font library keys override Brand Kit text fields when set. $font_rules = array(); $hf = ''; $bf = ''; if ( ! empty( $settings['font_heading_key'] ) && class_exists( 'C7DBT_Fonts', false ) ) { $hf = C7DBT_Fonts::css_family( $settings['font_heading_key'] ); if ( $hf ) { $font_rules[] = '--c7-heading-font-family: ' . $hf . ';'; } } if ( ! empty( $settings['font_body_key'] ) && class_exists( 'C7DBT_Fonts', false ) ) { $bf = C7DBT_Fonts::css_family( $settings['font_body_key'] ); if ( $bf ) { $font_rules[] = '--c7-font-family: ' . $bf . ';'; } } if ( ! empty( $brand['text_color'] ) ) { $hex = sanitize_hex_color( $brand['text_color'] ); if ( $hex ) { $font_rules[] = '--c7-text-color: ' . $hex . ';'; $font_rules[] = '--c7-body-text-color: ' . $hex . ';'; } } if ( $font_rules ) { $css .= ":root {\n\t" . implode( "\n\t", $font_rules ) . "\n}\n"; } // Direct selectors — C7 doesn't always consume CSS variables for every text node. if ( $hf || $bf ) { if ( $hf ) { $css .= "#c7-content .c7-product__title,\n#c7-content .c7-h1,\n#c7-content .c7-h2,\n#c7-content .c7-h3,\n"; $css .= "#c7-content h1, #c7-content h2, #c7-content h3,\n#c7-content .c7-product-detail .c7-product__title {\n"; $css .= "\tfont-family: {$hf} !important;\n}\n"; } if ( $bf ) { $css .= "#c7-content,\n#c7-content .c7-product,\n#c7-content .c7-product__teaser,\n#c7-content .c7-product__subtitle,\n"; $css .= "#c7-content .c7-product__details,\n#c7-content .c7-product__info,\n#c7-content .c7-btn,\n#c7-content button,\n#c7-content input,\n#c7-content select {\n"; $css .= "\tfont-family: {$bf} !important;\n}\n"; } } // Force readable body/muted text on light C7 surfaces (featured cards use --c7-bg-alt). $body_hex = ! empty( $brand['text_color'] ) ? sanitize_hex_color( $brand['text_color'] ) : ''; $alt_hex = ! empty( $brand['alt_text_color'] ) ? sanitize_hex_color( $brand['alt_text_color'] ) : ''; $head_hex = ! empty( $brand['heading_text_color'] ) ? sanitize_hex_color( $brand['heading_text_color'] ) : $body_hex; if ( $body_hex || $alt_hex || $head_hex ) { if ( $body_hex ) { $css .= "#c7-content,\n#c7-content .c7-product,\n#c7-content .c7-product__details,\n#c7-content .c7-product__teaser,\n"; $css .= "#c7-content .c7-product__content,\n#c7-content .c7-product__add-to-cart__price {\n"; $css .= "\tcolor: {$body_hex} !important;\n}\n"; } if ( $alt_hex ) { $css .= "#c7-content .c7-product__subtitle,\n#c7-content .c7-alt-text {\n"; $css .= "\tcolor: {$alt_hex} !important;\n}\n"; } if ( $head_hex ) { $css .= "#c7-content .c7-product__title,\n#c7-content .c7-product__title a,\n#c7-content h1,\n#c7-content .c7-h1 {\n"; $css .= "\tcolor: {$head_hex} !important;\n}\n"; } } if ( ! empty( $settings['hide_floating_cart_mobile'] ) ) { $css .= "@media (max-width: 768px) {\n\t#c7wp-cart-box { display: none !important; }\n}\n"; } $tone = isset( $settings['cart_box_tone'] ) ? $settings['cart_box_tone'] : 'auto'; if ( 'light' === $tone ) { $css .= "#c7wp-cart-box { background: #ffffff; color: #232324; box-shadow: 0 2px 12px rgba(0,0,0,.12); }\n"; } elseif ( 'dark' === $tone ) { $css .= "#c7wp-cart-box { background: #1a1a1a; color: #f5f5f5; box-shadow: 0 2px 12px rgba(0,0,0,.35); }\n"; $css .= "#c7wp-cart-box .c7-login, #c7wp-cart-box .c7-cart { color: inherit; }\n"; } /** * Filter generated branding CSS. * * @param string $css CSS. * @param array $settings Settings. */ return apply_filters( 'c7dbt_branding_css', $css, $settings ); } /** * Format font family value. * * @param string $font Font. * @return string */ private function format_font_stack( $font ) { $font = trim( wp_strip_all_tags( (string) $font ) ); if ( '' === $font ) { return $font; } // Already a stack or quoted family — keep as-is after stripping risky chars. if ( false !== strpos( $font, ',' ) || ( isset( $font[0] ) && ( '"' === $font[0] || "'" === $font[0] ) ) ) { return preg_replace( '/[<>{};]/', '', $font ); } $font = preg_replace( '/[^a-zA-Z0-9\s\-_]/', '', $font ); return '"' . $font . '", sans-serif'; } /** * Ensure size has unit. * * @param string $size Size. * @return string */ private function format_size( $size ) { $size = trim( $size ); if ( '' === $size ) { return $size; } if ( is_numeric( $size ) ) { return $size . 'px'; } return sanitize_text_field( $size ); } /** * Copy theme reference colors into brand kit. * * @return array Updated settings. */ public function match_theme_to_brand() { $settings = C7DBT_Settings::get(); $brand = $settings['brand']; if ( ! empty( $settings['theme_primary'] ) ) { $brand['primary_color'] = $settings['theme_primary']; $brand['primary_button_bg'] = $settings['theme_primary']; $brand['primary_button_bg_hover'] = $settings['theme_primary']; $brand['primary_color_dark'] = $settings['theme_primary']; $brand['primary_color_focus'] = $settings['theme_primary']; $brand['cart_count_bg'] = $settings['theme_primary']; $brand['link_color'] = $settings['theme_primary']; $brand['field_focus_color'] = $settings['theme_primary']; } if ( ! empty( $settings['theme_button_text'] ) ) { $brand['primary_button_text_color'] = $settings['theme_button_text']; $brand['cart_count_text_color'] = $settings['theme_button_text']; } if ( ! empty( $settings['theme_text'] ) ) { $brand['text_color'] = $settings['theme_text']; $brand['header_text_color'] = $settings['theme_text']; } if ( ! empty( $settings['theme_link'] ) ) { $brand['link_color'] = $settings['theme_link']; } if ( ! empty( $settings['theme_heading_font'] ) ) { $brand['heading_font_family'] = $settings['theme_heading_font']; } if ( ! empty( $settings['theme_body_font'] ) ) { $brand['font_family'] = $settings['theme_body_font']; } if ( ! empty( $settings['theme_button_radius'] ) ) { $brand['button_border_radius'] = $settings['theme_button_radius']; $brand['field_border_radius'] = $settings['theme_button_radius']; } $elementor = $this->read_elementor_kit(); if ( empty( $brand['primary_button_bg'] ) && ! empty( $elementor['primary'] ) ) { $brand['primary_color'] = $elementor['primary']; $brand['primary_button_bg'] = $elementor['primary']; $brand['link_color'] = $elementor['primary']; $brand['cart_count_bg'] = $elementor['primary']; } if ( empty( $brand['text_color'] ) && ! empty( $elementor['text'] ) ) { $brand['text_color'] = $elementor['text']; $brand['header_text_color'] = $elementor['text']; } if ( empty( $brand['heading_font_family'] ) && ! empty( $elementor['heading_font'] ) ) { $brand['heading_font_family'] = $elementor['heading_font']; } if ( empty( $brand['font_family'] ) && ! empty( $elementor['body_font'] ) ) { $brand['font_family'] = $elementor['body_font']; } return C7DBT_Settings::update( array( 'brand' => $brand, 'branding_enabled' => 1, ) ); } /** * Pull Elementor kit into theme_* reference fields (without applying brand yet). * * @return array Updated settings. */ public function detect_theme_references() { $el = $this->read_elementor_kit(); $partial = array(); $settings = C7DBT_Settings::get(); if ( ! empty( $el['primary'] ) ) { $partial['theme_primary'] = $el['primary']; } if ( ! empty( $el['text'] ) ) { $partial['theme_text'] = $el['text']; } if ( ! empty( $el['accent'] ) && empty( $partial['theme_link'] ) ) { $partial['theme_link'] = $el['accent']; } elseif ( ! empty( $el['primary'] ) ) { $partial['theme_link'] = $el['primary']; } if ( ! empty( $el['heading_font'] ) ) { $partial['theme_heading_font'] = $el['heading_font']; } if ( ! empty( $el['body_font'] ) ) { $partial['theme_body_font'] = $el['body_font']; } if ( empty( $settings['theme_button_text'] ) ) { $partial['theme_button_text'] = '#ffffff'; } return C7DBT_Settings::update( $partial ); } /** * Best-effort Elementor kit colors + fonts. * * @return array */ public function read_elementor_kit() { $out = array( 'primary' => '', 'text' => '', 'accent' => '', 'heading_font' => '', 'body_font' => '', ); $mod = get_theme_mod( 'primary_color', '' ); if ( $mod ) { $out['primary'] = C7DBT_Helpers::sanitize_hex_color( $mod ); } if ( ! class_exists( '\Elementor\Plugin' ) ) { return $out; } $kit_id = get_option( 'elementor_active_kit' ); if ( ! $kit_id ) { return $out; } $meta = get_post_meta( $kit_id, '_elementor_page_settings', true ); if ( ! is_array( $meta ) ) { return $out; } if ( ! empty( $meta['system_colors'] ) && is_array( $meta['system_colors'] ) ) { foreach ( $meta['system_colors'] as $color ) { if ( empty( $color['_id'] ) || empty( $color['color'] ) ) { continue; } $hex = C7DBT_Helpers::sanitize_hex_color( $color['color'] ); if ( 'primary' === $color['_id'] ) { $out['primary'] = $hex; } if ( in_array( $color['_id'], array( 'text', 'secondary' ), true ) && empty( $out['text'] ) ) { $out['text'] = $hex; } if ( 'accent' === $color['_id'] ) { $out['accent'] = $hex; } } } if ( ! empty( $meta['system_typography'] ) && is_array( $meta['system_typography'] ) ) { foreach ( $meta['system_typography'] as $typo ) { if ( empty( $typo['_id'] ) ) { continue; } $family = ''; if ( ! empty( $typo['typography_font_family'] ) ) { $family = $typo['typography_font_family']; } if ( 'primary' === $typo['_id'] || 'heading' === $typo['_id'] ) { $out['heading_font'] = $family ? $family : $out['heading_font']; } if ( 'secondary' === $typo['_id'] || 'text' === $typo['_id'] || 'body' === $typo['_id'] ) { $out['body_font'] = $family ? $family : $out['body_font']; } } } return $out; } /** * Export brand kit as array for JSON download. * * @return array */ public function export_payload() { $settings = C7DBT_Settings::get(); return array( 'plugin' => '7labs-debug-branding-for-commerce7', 'version' => C7DBT_VERSION, 'exported_at' => gmdate( 'c' ), 'brand' => $settings['brand'], 'brand_scope' => $settings['brand_scope'], 'theme' => array( 'theme_primary' => $settings['theme_primary'], 'theme_button_text' => $settings['theme_button_text'], 'theme_text' => $settings['theme_text'], 'theme_link' => $settings['theme_link'], 'theme_heading_font' => $settings['theme_heading_font'], 'theme_body_font' => $settings['theme_body_font'], 'theme_button_radius' => $settings['theme_button_radius'], ), ); } /** * Import brand payload. * * @param array $data Data. * @return bool */ public function import_payload( array $data ) { $partial = array(); if ( ! empty( $data['brand'] ) && is_array( $data['brand'] ) ) { $partial['brand'] = array_merge( C7DBT_Settings::default_brand(), array_intersect_key( $data['brand'], C7DBT_Settings::default_brand() ) ); $partial['branding_enabled'] = 1; } if ( ! empty( $data['brand_scope'] ) && is_array( $data['brand_scope'] ) ) { $partial['brand_scope'] = $data['brand_scope']; } if ( ! empty( $data['theme'] ) && is_array( $data['theme'] ) ) { $partial = array_merge( $partial, $data['theme'] ); } if ( empty( $partial ) ) { return false; } C7DBT_Settings::update( C7DBT_Settings::sanitize( $partial ) ); return true; } /** * Status. * * @return array */ public function status() { $settings = C7DBT_Settings::get(); if ( empty( $settings['branding_enabled'] ) ) { return array( 'status' => 'warn', 'label' => __( 'Branding overrides off', '7labs-debug-branding-for-commerce7' ), 'detail' => __( 'Enable Brand Kit to match C7 widgets to your theme.', '7labs-debug-branding-for-commerce7' ), ); } $filled = 0; foreach ( $settings['brand'] as $v ) { if ( '' !== (string) $v ) { ++$filled; } } if ( 0 === $filled ) { return array( 'status' => 'warn', 'label' => __( 'No brand colors set', '7labs-debug-branding-for-commerce7' ), 'detail' => __( 'Apply a preset, detect Elementor colors, or edit Brand Kit manually.', '7labs-debug-branding-for-commerce7' ), ); } return array( 'status' => 'ok', 'label' => __( 'Brand Kit active', '7labs-debug-branding-for-commerce7' ), 'detail' => sprintf( /* translators: %d: count */ __( '%d style overrides applied on the front end.', '7labs-debug-branding-for-commerce7' ), $filled ), ); } }