I’ll build this as a reusable WordPress theme options module for inc/options/color-options.php, focused on Customizer color controls, CSS variables, sanitization, presets, gradients, dark mode, Gutenberg/editor support, and front-end output.
Below is an advanced inc/options/color-options.php file for your rx theme. It adds many color features using the WordPress Customizer, CSS variables, live preview support, dark mode options, gradients, button colors, header/footer colors, link colors, border colors, form colors, block editor palette support, and front-end dynamic CSS.
Create this file:
mkdir -p inc/options
touch inc/options/color-options.php
Then paste this full code inside:
<?php
/**
* RX Theme Color Options
*
* File: inc/options/color-options.php
*
* Advanced color customization system for RX Theme.
*
* Features:
* - WordPress Customizer color options
* - Global CSS variables
* - Light and dark mode color sets
* - Header, footer, sidebar, card, form, button, link, border colors
* - Gradient options
* - Preset color palette
* - Gutenberg editor color palette support
* - Dynamic inline CSS output
* - Sanitization helpers
* - Live preview support
*
* @package RX_Theme
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'RX_Color_Options' ) ) :
final class RX_Color_Options {
/**
* Theme option prefix.
*
* @var string
*/
const PREFIX = 'rx_';
/**
* Constructor.
*/
public function __construct() {
add_action( 'customize_register', array( $this, 'register_customizer_options' ) );
add_action( 'customize_preview_init', array( $this, 'customizer_live_preview' ) );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_dynamic_colors' ), 30 );
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor_dynamic_colors' ), 30 );
add_action( 'after_setup_theme', array( $this, 'register_editor_color_palette' ), 20 );
add_action( 'wp_head', array( $this, 'print_color_scheme_meta' ), 1 );
}
/**
* Default color values.
*
* @return array
*/
public static function defaults() {
return array(
/*
|--------------------------------------------------------------------------
| Base Colors
|--------------------------------------------------------------------------
*/
'color_primary' => '#2563eb',
'color_primary_hover' => '#1d4ed8',
'color_primary_light' => '#dbeafe',
'color_primary_dark' => '#1e40af',
'color_secondary' => '#0f766e',
'color_secondary_hover' => '#115e59',
'color_secondary_light' => '#ccfbf1',
'color_secondary_dark' => '#134e4a',
'color_accent' => '#f97316',
'color_accent_hover' => '#ea580c',
'color_accent_light' => '#ffedd5',
'color_accent_dark' => '#c2410c',
/*
|--------------------------------------------------------------------------
| Body / Text
|--------------------------------------------------------------------------
*/
'color_body_bg' => '#ffffff',
'color_body_text' => '#111827',
'color_body_text_muted' => '#6b7280',
'color_heading' => '#0f172a',
'color_paragraph' => '#374151',
'color_selection_bg' => '#2563eb',
'color_selection_text' => '#ffffff',
/*
|--------------------------------------------------------------------------
| Links
|--------------------------------------------------------------------------
*/
'color_link' => '#2563eb',
'color_link_hover' => '#1d4ed8',
'color_link_visited' => '#7c3aed',
'color_link_underline' => '#93c5fd',
/*
|--------------------------------------------------------------------------
| Header
|--------------------------------------------------------------------------
*/
'color_header_bg' => '#ffffff',
'color_header_text' => '#111827',
'color_header_link' => '#111827',
'color_header_link_hover' => '#2563eb',
'color_header_border' => '#e5e7eb',
'color_header_top_bg' => '#0f172a',
'color_header_top_text' => '#ffffff',
/*
|--------------------------------------------------------------------------
| Navigation
|--------------------------------------------------------------------------
*/
'color_nav_bg' => '#ffffff',
'color_nav_link' => '#111827',
'color_nav_link_hover' => '#2563eb',
'color_nav_active' => '#2563eb',
'color_nav_dropdown_bg' => '#ffffff',
'color_nav_dropdown_text' => '#111827',
'color_nav_dropdown_hover' => '#eff6ff',
/*
|--------------------------------------------------------------------------
| Footer
|--------------------------------------------------------------------------
*/
'color_footer_bg' => '#0f172a',
'color_footer_text' => '#cbd5e1',
'color_footer_heading' => '#ffffff',
'color_footer_link' => '#bfdbfe',
'color_footer_link_hover' => '#ffffff',
'color_footer_border' => '#1e293b',
'color_footer_bottom_bg' => '#020617',
'color_footer_bottom_text' => '#94a3b8',
/*
|--------------------------------------------------------------------------
| Buttons
|--------------------------------------------------------------------------
*/
'color_button_bg' => '#2563eb',
'color_button_text' => '#ffffff',
'color_button_hover_bg' => '#1d4ed8',
'color_button_hover_text' => '#ffffff',
'color_button_border' => '#2563eb',
'color_button_secondary_bg' => '#0f766e',
'color_button_secondary_text' => '#ffffff',
'color_button_secondary_hover_bg' => '#115e59',
'color_button_secondary_hover_text' => '#ffffff',
'color_button_outline_text' => '#2563eb',
'color_button_outline_border' => '#2563eb',
'color_button_outline_hover_bg' => '#2563eb',
'color_button_outline_hover_text' => '#ffffff',
/*
|--------------------------------------------------------------------------
| Cards / Containers
|--------------------------------------------------------------------------
*/
'color_card_bg' => '#ffffff',
'color_card_text' => '#111827',
'color_card_border' => '#e5e7eb',
'color_card_shadow' => 'rgba(15, 23, 42, 0.08)',
'color_box_bg' => '#f9fafb',
'color_box_border' => '#e5e7eb',
/*
|--------------------------------------------------------------------------
| Sidebar / Widgets
|--------------------------------------------------------------------------
*/
'color_sidebar_bg' => '#ffffff',
'color_sidebar_text' => '#374151',
'color_sidebar_heading' => '#111827',
'color_sidebar_link' => '#2563eb',
'color_sidebar_link_hover' => '#1d4ed8',
'color_widget_bg' => '#ffffff',
'color_widget_border' => '#e5e7eb',
/*
|--------------------------------------------------------------------------
| Forms
|--------------------------------------------------------------------------
*/
'color_input_bg' => '#ffffff',
'color_input_text' => '#111827',
'color_input_placeholder' => '#9ca3af',
'color_input_border' => '#d1d5db',
'color_input_focus_border' => '#2563eb',
'color_input_focus_shadow' => 'rgba(37, 99, 235, 0.20)',
'color_label_text' => '#374151',
/*
|--------------------------------------------------------------------------
| Tables
|--------------------------------------------------------------------------
*/
'color_table_header_bg' => '#f3f4f6',
'color_table_header_text' => '#111827',
'color_table_border' => '#e5e7eb',
'color_table_stripe_bg' => '#f9fafb',
'color_table_hover_bg' => '#eff6ff',
/*
|--------------------------------------------------------------------------
| Alerts
|--------------------------------------------------------------------------
*/
'color_success' => '#16a34a',
'color_success_bg' => '#dcfce7',
'color_warning' => '#d97706',
'color_warning_bg' => '#fef3c7',
'color_danger' => '#dc2626',
'color_danger_bg' => '#fee2e2',
'color_info' => '#0284c7',
'color_info_bg' => '#e0f2fe',
/*
|--------------------------------------------------------------------------
| Medical / Health Brand Colors
|--------------------------------------------------------------------------
*/
'color_medical_blue' => '#0284c7',
'color_medical_green' => '#059669',
'color_medical_red' => '#dc2626',
'color_medical_purple' => '#7c3aed',
'color_medical_soft_bg' => '#f0f9ff',
/*
|--------------------------------------------------------------------------
| Breadcrumb / Pagination
|--------------------------------------------------------------------------
*/
'color_breadcrumb_text' => '#6b7280',
'color_breadcrumb_link' => '#2563eb',
'color_pagination_bg' => '#ffffff',
'color_pagination_text' => '#111827',
'color_pagination_border' => '#e5e7eb',
'color_pagination_active_bg' => '#2563eb',
'color_pagination_active_text' => '#ffffff',
/*
|--------------------------------------------------------------------------
| Code / Pre
|--------------------------------------------------------------------------
*/
'color_code_bg' => '#f3f4f6',
'color_code_text' => '#be123c',
'color_pre_bg' => '#0f172a',
'color_pre_text' => '#e5e7eb',
/*
|--------------------------------------------------------------------------
| Gradients
|--------------------------------------------------------------------------
*/
'gradient_primary_start' => '#2563eb',
'gradient_primary_end' => '#7c3aed',
'gradient_secondary_start' => '#0f766e',
'gradient_secondary_end' => '#06b6d4',
'gradient_accent_start' => '#f97316',
'gradient_accent_end' => '#ef4444',
'gradient_hero_start' => '#eff6ff',
'gradient_hero_end' => '#ffffff',
/*
|--------------------------------------------------------------------------
| Dark Mode
|--------------------------------------------------------------------------
*/
'dark_color_body_bg' => '#020617',
'dark_color_body_text' => '#e5e7eb',
'dark_color_heading' => '#ffffff',
'dark_color_paragraph' => '#cbd5e1',
'dark_color_card_bg' => '#0f172a',
'dark_color_card_border' => '#1e293b',
'dark_color_header_bg' => '#020617',
'dark_color_header_text' => '#ffffff',
'dark_color_footer_bg' => '#020617',
'dark_color_footer_text' => '#cbd5e1',
'dark_color_input_bg' => '#0f172a',
'dark_color_input_text' => '#e5e7eb',
'dark_color_input_border' => '#334155',
/*
|--------------------------------------------------------------------------
| Controls
|--------------------------------------------------------------------------
*/
'enable_dark_mode' => false,
'enable_system_dark_mode' => true,
'enable_color_css_variables' => true,
'enable_editor_palette' => true,
'color_preset' => 'default',
);
}
/**
* Color labels for Customizer.
*
* @return array
*/
private function color_fields() {
return array(
'color_primary' => __( 'Primary Color', 'rx-theme' ),
'color_primary_hover' => __( 'Primary Hover Color', 'rx-theme' ),
'color_primary_light' => __( 'Primary Light Color', 'rx-theme' ),
'color_primary_dark' => __( 'Primary Dark Color', 'rx-theme' ),
'color_secondary' => __( 'Secondary Color', 'rx-theme' ),
'color_secondary_hover' => __( 'Secondary Hover Color', 'rx-theme' ),
'color_secondary_light' => __( 'Secondary Light Color', 'rx-theme' ),
'color_secondary_dark' => __( 'Secondary Dark Color', 'rx-theme' ),
'color_accent' => __( 'Accent Color', 'rx-theme' ),
'color_accent_hover' => __( 'Accent Hover Color', 'rx-theme' ),
'color_accent_light' => __( 'Accent Light Color', 'rx-theme' ),
'color_accent_dark' => __( 'Accent Dark Color', 'rx-theme' ),
'color_body_bg' => __( 'Body Background', 'rx-theme' ),
'color_body_text' => __( 'Body Text', 'rx-theme' ),
'color_body_text_muted' => __( 'Muted Text', 'rx-theme' ),
'color_heading' => __( 'Heading Text', 'rx-theme' ),
'color_paragraph' => __( 'Paragraph Text', 'rx-theme' ),
'color_selection_bg' => __( 'Selection Background', 'rx-theme' ),
'color_selection_text' => __( 'Selection Text', 'rx-theme' ),
'color_link' => __( 'Link Color', 'rx-theme' ),
'color_link_hover' => __( 'Link Hover Color', 'rx-theme' ),
'color_link_visited' => __( 'Visited Link Color', 'rx-theme' ),
'color_link_underline' => __( 'Link Underline Color', 'rx-theme' ),
'color_header_bg' => __( 'Header Background', 'rx-theme' ),
'color_header_text' => __( 'Header Text', 'rx-theme' ),
'color_header_link' => __( 'Header Link', 'rx-theme' ),
'color_header_link_hover' => __( 'Header Link Hover', 'rx-theme' ),
'color_header_border' => __( 'Header Border', 'rx-theme' ),
'color_header_top_bg' => __( 'Header Top Background', 'rx-theme' ),
'color_header_top_text' => __( 'Header Top Text', 'rx-theme' ),
'color_nav_bg' => __( 'Navigation Background', 'rx-theme' ),
'color_nav_link' => __( 'Navigation Link', 'rx-theme' ),
'color_nav_link_hover' => __( 'Navigation Link Hover', 'rx-theme' ),
'color_nav_active' => __( 'Navigation Active Link', 'rx-theme' ),
'color_nav_dropdown_bg' => __( 'Dropdown Background', 'rx-theme' ),
'color_nav_dropdown_text' => __( 'Dropdown Text', 'rx-theme' ),
'color_nav_dropdown_hover' => __( 'Dropdown Hover Background', 'rx-theme' ),
'color_footer_bg' => __( 'Footer Background', 'rx-theme' ),
'color_footer_text' => __( 'Footer Text', 'rx-theme' ),
'color_footer_heading' => __( 'Footer Heading', 'rx-theme' ),
'color_footer_link' => __( 'Footer Link', 'rx-theme' ),
'color_footer_link_hover' => __( 'Footer Link Hover', 'rx-theme' ),
'color_footer_border' => __( 'Footer Border', 'rx-theme' ),
'color_footer_bottom_bg' => __( 'Footer Bottom Background', 'rx-theme' ),
'color_footer_bottom_text' => __( 'Footer Bottom Text', 'rx-theme' ),
'color_button_bg' => __( 'Button Background', 'rx-theme' ),
'color_button_text' => __( 'Button Text', 'rx-theme' ),
'color_button_hover_bg' => __( 'Button Hover Background', 'rx-theme' ),
'color_button_hover_text' => __( 'Button Hover Text', 'rx-theme' ),
'color_button_border' => __( 'Button Border', 'rx-theme' ),
'color_button_secondary_bg' => __( 'Secondary Button Background', 'rx-theme' ),
'color_button_secondary_text' => __( 'Secondary Button Text', 'rx-theme' ),
'color_button_secondary_hover_bg' => __( 'Secondary Button Hover Background', 'rx-theme' ),
'color_button_secondary_hover_text'=> __( 'Secondary Button Hover Text', 'rx-theme' ),
'color_button_outline_text' => __( 'Outline Button Text', 'rx-theme' ),
'color_button_outline_border' => __( 'Outline Button Border', 'rx-theme' ),
'color_button_outline_hover_bg' => __( 'Outline Button Hover Background', 'rx-theme' ),
'color_button_outline_hover_text' => __( 'Outline Button Hover Text', 'rx-theme' ),
'color_card_bg' => __( 'Card Background', 'rx-theme' ),
'color_card_text' => __( 'Card Text', 'rx-theme' ),
'color_card_border' => __( 'Card Border', 'rx-theme' ),
'color_box_bg' => __( 'Box Background', 'rx-theme' ),
'color_box_border' => __( 'Box Border', 'rx-theme' ),
'color_sidebar_bg' => __( 'Sidebar Background', 'rx-theme' ),
'color_sidebar_text' => __( 'Sidebar Text', 'rx-theme' ),
'color_sidebar_heading' => __( 'Sidebar Heading', 'rx-theme' ),
'color_sidebar_link' => __( 'Sidebar Link', 'rx-theme' ),
'color_sidebar_link_hover' => __( 'Sidebar Link Hover', 'rx-theme' ),
'color_widget_bg' => __( 'Widget Background', 'rx-theme' ),
'color_widget_border' => __( 'Widget Border', 'rx-theme' ),
'color_input_bg' => __( 'Input Background', 'rx-theme' ),
'color_input_text' => __( 'Input Text', 'rx-theme' ),
'color_input_placeholder' => __( 'Input Placeholder', 'rx-theme' ),
'color_input_border' => __( 'Input Border', 'rx-theme' ),
'color_input_focus_border' => __( 'Input Focus Border', 'rx-theme' ),
'color_label_text' => __( 'Label Text', 'rx-theme' ),
'color_table_header_bg' => __( 'Table Header Background', 'rx-theme' ),
'color_table_header_text' => __( 'Table Header Text', 'rx-theme' ),
'color_table_border' => __( 'Table Border', 'rx-theme' ),
'color_table_stripe_bg' => __( 'Table Stripe Background', 'rx-theme' ),
'color_table_hover_bg' => __( 'Table Hover Background', 'rx-theme' ),
'color_success' => __( 'Success Color', 'rx-theme' ),
'color_success_bg' => __( 'Success Background', 'rx-theme' ),
'color_warning' => __( 'Warning Color', 'rx-theme' ),
'color_warning_bg' => __( 'Warning Background', 'rx-theme' ),
'color_danger' => __( 'Danger Color', 'rx-theme' ),
'color_danger_bg' => __( 'Danger Background', 'rx-theme' ),
'color_info' => __( 'Info Color', 'rx-theme' ),
'color_info_bg' => __( 'Info Background', 'rx-theme' ),
'color_medical_blue' => __( 'Medical Blue', 'rx-theme' ),
'color_medical_green' => __( 'Medical Green', 'rx-theme' ),
'color_medical_red' => __( 'Medical Red', 'rx-theme' ),
'color_medical_purple' => __( 'Medical Purple', 'rx-theme' ),
'color_medical_soft_bg' => __( 'Medical Soft Background', 'rx-theme' ),
'color_breadcrumb_text' => __( 'Breadcrumb Text', 'rx-theme' ),
'color_breadcrumb_link' => __( 'Breadcrumb Link', 'rx-theme' ),
'color_pagination_bg' => __( 'Pagination Background', 'rx-theme' ),
'color_pagination_text' => __( 'Pagination Text', 'rx-theme' ),
'color_pagination_border' => __( 'Pagination Border', 'rx-theme' ),
'color_pagination_active_bg' => __( 'Pagination Active Background', 'rx-theme' ),
'color_pagination_active_text' => __( 'Pagination Active Text', 'rx-theme' ),
'color_code_bg' => __( 'Inline Code Background', 'rx-theme' ),
'color_code_text' => __( 'Inline Code Text', 'rx-theme' ),
'color_pre_bg' => __( 'Code Block Background', 'rx-theme' ),
'color_pre_text' => __( 'Code Block Text', 'rx-theme' ),
'gradient_primary_start' => __( 'Primary Gradient Start', 'rx-theme' ),
'gradient_primary_end' => __( 'Primary Gradient End', 'rx-theme' ),
'gradient_secondary_start' => __( 'Secondary Gradient Start', 'rx-theme' ),
'gradient_secondary_end' => __( 'Secondary Gradient End', 'rx-theme' ),
'gradient_accent_start' => __( 'Accent Gradient Start', 'rx-theme' ),
'gradient_accent_end' => __( 'Accent Gradient End', 'rx-theme' ),
'gradient_hero_start' => __( 'Hero Gradient Start', 'rx-theme' ),
'gradient_hero_end' => __( 'Hero Gradient End', 'rx-theme' ),
'dark_color_body_bg' => __( 'Dark Body Background', 'rx-theme' ),
'dark_color_body_text' => __( 'Dark Body Text', 'rx-theme' ),
'dark_color_heading' => __( 'Dark Heading Text', 'rx-theme' ),
'dark_color_paragraph' => __( 'Dark Paragraph Text', 'rx-theme' ),
'dark_color_card_bg' => __( 'Dark Card Background', 'rx-theme' ),
'dark_color_card_border' => __( 'Dark Card Border', 'rx-theme' ),
'dark_color_header_bg' => __( 'Dark Header Background', 'rx-theme' ),
'dark_color_header_text' => __( 'Dark Header Text', 'rx-theme' ),
'dark_color_footer_bg' => __( 'Dark Footer Background', 'rx-theme' ),
'dark_color_footer_text' => __( 'Dark Footer Text', 'rx-theme' ),
'dark_color_input_bg' => __( 'Dark Input Background', 'rx-theme' ),
'dark_color_input_text' => __( 'Dark Input Text', 'rx-theme' ),
'dark_color_input_border' => __( 'Dark Input Border', 'rx-theme' ),
);
}
/**
* Register Customizer settings and controls.
*
* @param WP_Customize_Manager $wp_customize Customizer object.
* @return void
*/
public function register_customizer_options( $wp_customize ) {
$wp_customize->add_panel(
'rx_color_panel',
array(
'title' => __( 'RX Color System', 'rx-theme' ),
'description' => __( 'Advanced color options for the RX Theme.', 'rx-theme' ),
'priority' => 30,
)
);
$sections = array(
'rx_color_global_section' => array(
'title' => __( 'Global Brand Colors', 'rx-theme' ),
'description' => __( 'Primary, secondary, accent, and base brand colors.', 'rx-theme' ),
'priority' => 10,
),
'rx_color_text_section' => array(
'title' => __( 'Body and Text Colors', 'rx-theme' ),
'description' => __( 'Background, headings, paragraph, muted text, and selection colors.', 'rx-theme' ),
'priority' => 20,
),
'rx_color_link_section' => array(
'title' => __( 'Link Colors', 'rx-theme' ),
'description' => __( 'Normal, hover, visited, and underline link colors.', 'rx-theme' ),
'priority' => 30,
),
'rx_color_header_section' => array(
'title' => __( 'Header Colors', 'rx-theme' ),
'description' => __( 'Header, top bar, border, and header link colors.', 'rx-theme' ),
'priority' => 40,
),
'rx_color_nav_section' => array(
'title' => __( 'Navigation Colors', 'rx-theme' ),
'description' => __( 'Menu, active menu, dropdown, and hover colors.', 'rx-theme' ),
'priority' => 50,
),
'rx_color_footer_section' => array(
'title' => __( 'Footer Colors', 'rx-theme' ),
'description' => __( 'Footer background, text, headings, links, and bottom bar.', 'rx-theme' ),
'priority' => 60,
),
'rx_color_button_section' => array(
'title' => __( 'Button Colors', 'rx-theme' ),
'description' => __( 'Primary, secondary, and outline button colors.', 'rx-theme' ),
'priority' => 70,
),
'rx_color_content_section' => array(
'title' => __( 'Cards, Boxes, Sidebar and Widgets', 'rx-theme' ),
'description' => __( 'Content containers, cards, sidebar, and widget colors.', 'rx-theme' ),
'priority' => 80,
),
'rx_color_form_section' => array(
'title' => __( 'Form Colors', 'rx-theme' ),
'description' => __( 'Input, textarea, select, placeholder, border, and focus colors.', 'rx-theme' ),
'priority' => 90,
),
'rx_color_table_section' => array(
'title' => __( 'Table Colors', 'rx-theme' ),
'description' => __( 'Table header, border, stripe, and hover colors.', 'rx-theme' ),
'priority' => 100,
),
'rx_color_status_section' => array(
'title' => __( 'Status and Medical Colors', 'rx-theme' ),
'description' => __( 'Success, warning, danger, info, and medical brand colors.', 'rx-theme' ),
'priority' => 110,
),
'rx_color_extra_section' => array(
'title' => __( 'Breadcrumb, Pagination and Code Colors', 'rx-theme' ),
'description' => __( 'Breadcrumb, pagination, inline code, and code block colors.', 'rx-theme' ),
'priority' => 120,
),
'rx_color_gradient_section' => array(
'title' => __( 'Gradient Colors', 'rx-theme' ),
'description' => __( 'Hero, primary, secondary, and accent gradient colors.', 'rx-theme' ),
'priority' => 130,
),
'rx_color_dark_section' => array(
'title' => __( 'Dark Mode Colors', 'rx-theme' ),
'description' => __( 'Dark mode and system dark mode color settings.', 'rx-theme' ),
'priority' => 140,
),
'rx_color_advanced_section' => array(
'title' => __( 'Advanced Color Controls', 'rx-theme' ),
'description' => __( 'Color presets, CSS variables, and editor palette options.', 'rx-theme' ),
'priority' => 150,
),
);
foreach ( $sections as $section_id => $section ) {
$wp_customize->add_section(
$section_id,
array(
'title' => $section['title'],
'description' => $section['description'],
'panel' => 'rx_color_panel',
'priority' => $section['priority'],
)
);
}
$defaults = self::defaults();
$fields = $this->color_fields();
foreach ( $fields as $key => $label ) {
$section = $this->get_section_for_color_key( $key );
$wp_customize->add_setting(
self::PREFIX . $key,
array(
'default' => isset( $defaults[ $key ] ) ? $defaults[ $key ] : '',
'type' => 'theme_mod',
'sanitize_callback' => array( $this, 'sanitize_color_value' ),
'transport' => 'postMessage',
)
);
$wp_customize->add_control(
new WP_Customize_Color_Control(
$wp_customize,
self::PREFIX . $key,
array(
'label' => $label,
'section' => $section,
'settings' => self::PREFIX . $key,
'description' => sprintf(
/* translators: %s: color option key */
__( 'CSS variable: --rx-%s', 'rx-theme' ),
esc_html( str_replace( '_', '-', $key ) )
),
)
)
);
}
/*
|--------------------------------------------------------------------------
| Preset selector
|--------------------------------------------------------------------------
*/
$wp_customize->add_setting(
self::PREFIX . 'color_preset',
array(
'default' => $defaults['color_preset'],
'type' => 'theme_mod',
'sanitize_callback' => array( $this, 'sanitize_color_preset' ),
'transport' => 'refresh',
)
);
$wp_customize->add_control(
self::PREFIX . 'color_preset',
array(
'label' => __( 'Color Preset', 'rx-theme' ),
'description' => __( 'Choose a starter color style. Individual color settings can still override it.', 'rx-theme' ),
'section' => 'rx_color_advanced_section',
'type' => 'select',
'choices' => $this->color_preset_choices(),
)
);
/*
|--------------------------------------------------------------------------
| Boolean toggles
|--------------------------------------------------------------------------
*/
$boolean_controls = array(
'enable_dark_mode' => array(
'label' => __( 'Enable Manual Dark Mode Class Support', 'rx-theme' ),
'description' => __( 'Adds support for body.rx-dark-mode or html.rx-dark-mode.', 'rx-theme' ),
'section' => 'rx_color_dark_section',
),
'enable_system_dark_mode' => array(
'label' => __( 'Enable System Dark Mode', 'rx-theme' ),
'description' => __( 'Uses dark colors when the visitor device prefers dark mode.', 'rx-theme' ),
'section' => 'rx_color_dark_section',
),
'enable_color_css_variables' => array(
'label' => __( 'Enable CSS Color Variables', 'rx-theme' ),
'description' => __( 'Outputs global --rx-* CSS variables in the front end.', 'rx-theme' ),
'section' => 'rx_color_advanced_section',
),
'enable_editor_palette' => array(
'label' => __( 'Enable Block Editor Color Palette', 'rx-theme' ),
'description' => __( 'Registers the RX color palette inside Gutenberg editor.', 'rx-theme' ),
'section' => 'rx_color_advanced_section',
),
);
foreach ( $boolean_controls as $key => $control ) {
$wp_customize->add_setting(
self::PREFIX . $key,
array(
'default' => isset( $defaults[ $key ] ) ? $defaults[ $key ] : false,
'type' => 'theme_mod',
'sanitize_callback' => array( $this, 'sanitize_checkbox' ),
'transport' => 'refresh',
)
);
$wp_customize->add_control(
self::PREFIX . $key,
array(
'label' => $control['label'],
'description' => $control['description'],
'section' => $control['section'],
'type' => 'checkbox',
)
);
}
}
/**
* Decide which Customizer section a color belongs to.
*
* @param string $key Color key.
* @return string
*/
private function get_section_for_color_key( $key ) {
if ( 0 === strpos( $key, 'gradient_' ) ) {
return 'rx_color_gradient_section';
}
if ( 0 === strpos( $key, 'dark_' ) ) {
return 'rx_color_dark_section';
}
if (
false !== strpos( $key, 'primary' ) ||
false !== strpos( $key, 'secondary' ) ||
false !== strpos( $key, 'accent' )
) {
return 'rx_color_global_section';
}
if (
false !== strpos( $key, 'body' ) ||
false !== strpos( $key, 'heading' ) ||
false !== strpos( $key, 'paragraph' ) ||
false !== strpos( $key, 'selection' )
) {
return 'rx_color_text_section';
}
if ( false !== strpos( $key, 'link' ) && false === strpos( $key, 'header' ) && false === strpos( $key, 'footer' ) && false === strpos( $key, 'sidebar' ) ) {
return 'rx_color_link_section';
}
if ( false !== strpos( $key, 'header' ) ) {
return 'rx_color_header_section';
}
if ( false !== strpos( $key, 'nav' ) || false !== strpos( $key, 'dropdown' ) ) {
return 'rx_color_nav_section';
}
if ( false !== strpos( $key, 'footer' ) ) {
return 'rx_color_footer_section';
}
if ( false !== strpos( $key, 'button' ) ) {
return 'rx_color_button_section';
}
if (
false !== strpos( $key, 'card' ) ||
false !== strpos( $key, 'box' ) ||
false !== strpos( $key, 'sidebar' ) ||
false !== strpos( $key, 'widget' )
) {
return 'rx_color_content_section';
}
if (
false !== strpos( $key, 'input' ) ||
false !== strpos( $key, 'placeholder' ) ||
false !== strpos( $key, 'label' )
) {
return 'rx_color_form_section';
}
if ( false !== strpos( $key, 'table' ) ) {
return 'rx_color_table_section';
}
if (
false !== strpos( $key, 'success' ) ||
false !== strpos( $key, 'warning' ) ||
false !== strpos( $key, 'danger' ) ||
false !== strpos( $key, 'info' ) ||
false !== strpos( $key, 'medical' )
) {
return 'rx_color_status_section';
}
return 'rx_color_extra_section';
}
/**
* Color preset choices.
*
* @return array
*/
private function color_preset_choices() {
return array(
'default' => __( 'Default Blue Medical', 'rx-theme' ),
'green_health' => __( 'Green Health', 'rx-theme' ),
'purple_care' => __( 'Purple Care', 'rx-theme' ),
'red_emergency' => __( 'Red Emergency', 'rx-theme' ),
'dark_clinic' => __( 'Dark Clinic', 'rx-theme' ),
'soft_clean' => __( 'Soft Clean', 'rx-theme' ),
);
}
/**
* Preset color values.
*
* @return array
*/
public static function presets() {
return array(
'default' => array(
'color_primary' => '#2563eb',
'color_secondary' => '#0f766e',
'color_accent' => '#f97316',
'color_body_bg' => '#ffffff',
'color_heading' => '#0f172a',
),
'green_health' => array(
'color_primary' => '#059669',
'color_primary_hover' => '#047857',
'color_primary_light' => '#d1fae5',
'color_secondary' => '#0284c7',
'color_accent' => '#84cc16',
'color_link' => '#059669',
'color_button_bg' => '#059669',
'color_button_hover_bg' => '#047857',
),
'purple_care' => array(
'color_primary' => '#7c3aed',
'color_primary_hover' => '#6d28d9',
'color_primary_light' => '#ede9fe',
'color_secondary' => '#2563eb',
'color_accent' => '#ec4899',
'color_link' => '#7c3aed',
'color_button_bg' => '#7c3aed',
'color_button_hover_bg' => '#6d28d9',
),
'red_emergency' => array(
'color_primary' => '#dc2626',
'color_primary_hover' => '#b91c1c',
'color_primary_light' => '#fee2e2',
'color_secondary' => '#0f766e',
'color_accent' => '#f97316',
'color_link' => '#dc2626',
'color_button_bg' => '#dc2626',
'color_button_hover_bg' => '#b91c1c',
),
'dark_clinic' => array(
'color_primary' => '#38bdf8',
'color_primary_hover' => '#0ea5e9',
'color_body_bg' => '#020617',
'color_body_text' => '#e5e7eb',
'color_heading' => '#ffffff',
'color_card_bg' => '#0f172a',
'color_card_border' => '#1e293b',
'color_header_bg' => '#020617',
'color_footer_bg' => '#020617',
),
'soft_clean' => array(
'color_primary' => '#0284c7',
'color_primary_hover' => '#0369a1',
'color_primary_light' => '#e0f2fe',
'color_secondary' => '#14b8a6',
'color_accent' => '#f59e0b',
'color_body_bg' => '#f8fafc',
'color_card_bg' => '#ffffff',
'color_box_bg' => '#f1f5f9',
),
);
}
/**
* Get theme mod with default and preset support.
*
* @param string $key Color key.
* @return mixed
*/
public static function get_option( $key ) {
$defaults = self::defaults();
$preset = get_theme_mod( self::PREFIX . 'color_preset', $defaults['color_preset'] );
$presets = self::presets();
$default_value = isset( $defaults[ $key ] ) ? $defaults[ $key ] : '';
if ( isset( $presets[ $preset ][ $key ] ) ) {
$default_value = $presets[ $preset ][ $key ];
}
return get_theme_mod( self::PREFIX . $key, $default_value );
}
/**
* Sanitize normal hex, rgba, transparent, or CSS-safe color.
*
* @param string $value Color value.
* @return string
*/
public function sanitize_color_value( $value ) {
$value = trim( (string) $value );
if ( '' === $value ) {
return '';
}
if ( 'transparent' === strtolower( $value ) ) {
return 'transparent';
}
if ( false !== strpos( $value, 'rgba' ) || false !== strpos( $value, 'rgb' ) ) {
return $this->sanitize_rgb_or_rgba( $value );
}
$hex = sanitize_hex_color( $value );
if ( $hex ) {
return $hex;
}
return '';
}
/**
* Sanitize RGB or RGBA color value.
*
* @param string $value RGB/RGBA value.
* @return string
*/
private function sanitize_rgb_or_rgba( $value ) {
$value = preg_replace( '/\s+/', '', $value );
if ( preg_match( '/^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/', $value, $matches ) ) {
$r = min( 255, max( 0, absint( $matches[1] ) ) );
$g = min( 255, max( 0, absint( $matches[2] ) ) );
$b = min( 255, max( 0, absint( $matches[3] ) ) );
return "rgb({$r}, {$g}, {$b})";
}
if ( preg_match( '/^rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),([0-9.]+)\)$/', $value, $matches ) ) {
$r = min( 255, max( 0, absint( $matches[1] ) ) );
$g = min( 255, max( 0, absint( $matches[2] ) ) );
$b = min( 255, max( 0, absint( $matches[3] ) ) );
$a = min( 1, max( 0, (float) $matches[4] ) );
return "rgba({$r}, {$g}, {$b}, {$a})";
}
return '';
}
/**
* Sanitize checkbox.
*
* @param mixed $checked Checked value.
* @return bool
*/
public function sanitize_checkbox( $checked ) {
return (bool) $checked;
}
/**
* Sanitize color preset.
*
* @param string $value Preset.
* @return string
*/
public function sanitize_color_preset( $value ) {
$choices = $this->color_preset_choices();
return isset( $choices[ $value ] ) ? $value : 'default';
}
/**
* Convert option key to CSS variable name.
*
* @param string $key Option key.
* @return string
*/
private static function css_var_name( $key ) {
return '--rx-' . str_replace( '_', '-', $key );
}
/**
* Build CSS variable declarations.
*
* @return string
*/
public static function build_css_variables() {
$defaults = self::defaults();
$css = '';
foreach ( $defaults as $key => $default ) {
if ( 0 === strpos( $key, 'enable_' ) || 'color_preset' === $key ) {
continue;
}
$value = self::get_option( $key );
if ( '' === $value ) {
continue;
}
$css .= sprintf(
"%s:%s;\n",
esc_html( self::css_var_name( $key ) ),
esc_html( $value )
);
}
$css .= "--rx-gradient-primary:linear-gradient(135deg,var(--rx-gradient-primary-start),var(--rx-gradient-primary-end));\n";
$css .= "--rx-gradient-secondary:linear-gradient(135deg,var(--rx-gradient-secondary-start),var(--rx-gradient-secondary-end));\n";
$css .= "--rx-gradient-accent:linear-gradient(135deg,var(--rx-gradient-accent-start),var(--rx-gradient-accent-end));\n";
$css .= "--rx-gradient-hero:linear-gradient(135deg,var(--rx-gradient-hero-start),var(--rx-gradient-hero-end));\n";
return $css;
}
/**
* Build front-end dynamic CSS.
*
* @return string
*/
public static function build_dynamic_css() {
$enable_vars = self::get_option( 'enable_color_css_variables' );
$enable_dark = self::get_option( 'enable_dark_mode' );
$enable_system_dark = self::get_option( 'enable_system_dark_mode' );
$css = '';
if ( $enable_vars ) {
$css .= ":root{\n";
$css .= self::build_css_variables();
$css .= "}\n";
}
$css .= "
html {
color-scheme: light;
}
body {
background: var(--rx-color-body-bg);
color: var(--rx-color-body-text);
}
::selection {
background: var(--rx-color-selection-bg);
color: var(--rx-color-selection-text);
}
h1, h2, h3, h4, h5, h6,
.entry-title,
.page-title,
.site-title {
color: var(--rx-color-heading);
}
p,
.entry-content,
.site-content {
color: var(--rx-color-paragraph);
}
a {
color: var(--rx-color-link);
text-decoration-color: var(--rx-color-link-underline);
}
a:hover,
a:focus {
color: var(--rx-color-link-hover);
}
a:visited {
color: var(--rx-color-link-visited);
}
.site-header,
.rx-header {
background: var(--rx-color-header-bg);
color: var(--rx-color-header-text);
border-bottom-color: var(--rx-color-header-border);
}
.site-header a,
.rx-header a {
color: var(--rx-color-header-link);
}
.site-header a:hover,
.site-header a:focus,
.rx-header a:hover,
.rx-header a:focus {
color: var(--rx-color-header-link-hover);
}
.rx-top-bar {
background: var(--rx-color-header-top-bg);
color: var(--rx-color-header-top-text);
}
.main-navigation,
.rx-navigation,
.rx-menu {
background: var(--rx-color-nav-bg);
}
.main-navigation a,
.rx-navigation a,
.rx-menu a {
color: var(--rx-color-nav-link);
}
.main-navigation a:hover,
.main-navigation a:focus,
.rx-navigation a:hover,
.rx-navigation a:focus,
.rx-menu a:hover,
.rx-menu a:focus,
.current-menu-item > a,
.current_page_item > a {
color: var(--rx-color-nav-active);
}
.main-navigation ul ul,
.rx-navigation ul ul,
.rx-menu ul ul {
background: var(--rx-color-nav-dropdown-bg);
color: var(--rx-color-nav-dropdown-text);
}
.main-navigation ul ul a:hover,
.rx-navigation ul ul a:hover,
.rx-menu ul ul a:hover {
background: var(--rx-color-nav-dropdown-hover);
}
.site-footer,
.rx-footer {
background: var(--rx-color-footer-bg);
color: var(--rx-color-footer-text);
border-top-color: var(--rx-color-footer-border);
}
.site-footer h1,
.site-footer h2,
.site-footer h3,
.site-footer h4,
.rx-footer h1,
.rx-footer h2,
.rx-footer h3,
.rx-footer h4 {
color: var(--rx-color-footer-heading);
}
.site-footer a,
.rx-footer a {
color: var(--rx-color-footer-link);
}
.site-footer a:hover,
.site-footer a:focus,
.rx-footer a:hover,
.rx-footer a:focus {
color: var(--rx-color-footer-link-hover);
}
.rx-footer-bottom {
background: var(--rx-color-footer-bottom-bg);
color: var(--rx-color-footer-bottom-text);
}
button,
input[type='button'],
input[type='submit'],
input[type='reset'],
.wp-block-button__link,
.rx-btn,
.button {
background: var(--rx-color-button-bg);
color: var(--rx-color-button-text);
border-color: var(--rx-color-button-border);
}
button:hover,
button:focus,
input[type='button']:hover,
input[type='button']:focus,
input[type='submit']:hover,
input[type='submit']:focus,
input[type='reset']:hover,
input[type='reset']:focus,
.wp-block-button__link:hover,
.wp-block-button__link:focus,
.rx-btn:hover,
.rx-btn:focus,
.button:hover,
.button:focus {
background: var(--rx-color-button-hover-bg);
color: var(--rx-color-button-hover-text);
}
.rx-btn-secondary {
background: var(--rx-color-button-secondary-bg);
color: var(--rx-color-button-secondary-text);
}
.rx-btn-secondary:hover,
.rx-btn-secondary:focus {
background: var(--rx-color-button-secondary-hover-bg);
color: var(--rx-color-button-secondary-hover-text);
}
.rx-btn-outline {
background: transparent;
color: var(--rx-color-button-outline-text);
border-color: var(--rx-color-button-outline-border);
}
.rx-btn-outline:hover,
.rx-btn-outline:focus {
background: var(--rx-color-button-outline-hover-bg);
color: var(--rx-color-button-outline-hover-text);
}
.card,
.rx-card,
.post-card,
.wp-block-group.is-style-card {
background: var(--rx-color-card-bg);
color: var(--rx-color-card-text);
border-color: var(--rx-color-card-border);
box-shadow: 0 10px 30px var(--rx-color-card-shadow);
}
.rx-box,
.rx-highlight-box,
.wp-block-group.is-style-rx-box {
background: var(--rx-color-box-bg);
border-color: var(--rx-color-box-border);
}
.sidebar,
.rx-sidebar {
background: var(--rx-color-sidebar-bg);
color: var(--rx-color-sidebar-text);
}
.sidebar h1,
.sidebar h2,
.sidebar h3,
.sidebar h4,
.sidebar .widget-title,
.rx-sidebar h1,
.rx-sidebar h2,
.rx-sidebar h3,
.rx-sidebar h4,
.rx-sidebar .widget-title {
color: var(--rx-color-sidebar-heading);
}
.sidebar a,
.rx-sidebar a {
color: var(--rx-color-sidebar-link);
}
.sidebar a:hover,
.rx-sidebar a:hover {
color: var(--rx-color-sidebar-link-hover);
}
.widget,
.rx-widget {
background: var(--rx-color-widget-bg);
border-color: var(--rx-color-widget-border);
}
input,
textarea,
select {
background: var(--rx-color-input-bg);
color: var(--rx-color-input-text);
border-color: var(--rx-color-input-border);
}
input::placeholder,
textarea::placeholder {
color: var(--rx-color-input-placeholder);
}
input:focus,
textarea:focus,
select:focus {
border-color: var(--rx-color-input-focus-border);
box-shadow: 0 0 0 3px var(--rx-color-input-focus-shadow);
outline: none;
}
label {
color: var(--rx-color-label-text);
}
table,
.wp-block-table table {
border-color: var(--rx-color-table-border);
}
thead,
.wp-block-table thead {
background: var(--rx-color-table-header-bg);
color: var(--rx-color-table-header-text);
}
td,
th {
border-color: var(--rx-color-table-border);
}
tbody tr:nth-child(even) {
background: var(--rx-color-table-stripe-bg);
}
tbody tr:hover {
background: var(--rx-color-table-hover-bg);
}
.rx-alert-success {
color: var(--rx-color-success);
background: var(--rx-color-success-bg);
}
.rx-alert-warning {
color: var(--rx-color-warning);
background: var(--rx-color-warning-bg);
}
.rx-alert-danger {
color: var(--rx-color-danger);
background: var(--rx-color-danger-bg);
}
.rx-alert-info {
color: var(--rx-color-info);
background: var(--rx-color-info-bg);
}
.rx-medical-box {
background: var(--rx-color-medical-soft-bg);
border-left-color: var(--rx-color-medical-blue);
}
.rx-medical-blue {
color: var(--rx-color-medical-blue);
}
.rx-medical-green {
color: var(--rx-color-medical-green);
}
.rx-medical-red {
color: var(--rx-color-medical-red);
}
.rx-medical-purple {
color: var(--rx-color-medical-purple);
}
.breadcrumb,
.rx-breadcrumb {
color: var(--rx-color-breadcrumb-text);
}
.breadcrumb a,
.rx-breadcrumb a {
color: var(--rx-color-breadcrumb-link);
}
.pagination a,
.pagination span,
.nav-links a,
.nav-links span,
.page-numbers {
background: var(--rx-color-pagination-bg);
color: var(--rx-color-pagination-text);
border-color: var(--rx-color-pagination-border);
}
.pagination .current,
.nav-links .current,
.page-numbers.current {
background: var(--rx-color-pagination-active-bg);
color: var(--rx-color-pagination-active-text);
}
code,
kbd,
tt,
var {
background: var(--rx-color-code-bg);
color: var(--rx-color-code-text);
}
pre {
background: var(--rx-color-pre-bg);
color: var(--rx-color-pre-text);
}
.rx-gradient-primary {
background: var(--rx-gradient-primary);
}
.rx-gradient-secondary {
background: var(--rx-gradient-secondary);
}
.rx-gradient-accent {
background: var(--rx-gradient-accent);
}
.rx-hero,
.rx-gradient-hero {
background: var(--rx-gradient-hero);
}
.has-rx-primary-color {
color: var(--rx-color-primary) !important;
}
.has-rx-primary-background-color {
background-color: var(--rx-color-primary) !important;
}
.has-rx-secondary-color {
color: var(--rx-color-secondary) !important;
}
.has-rx-secondary-background-color {
background-color: var(--rx-color-secondary) !important;
}
.has-rx-accent-color {
color: var(--rx-color-accent) !important;
}
.has-rx-accent-background-color {
background-color: var(--rx-color-accent) !important;
}
";
if ( $enable_dark ) {
$css .= "
html.rx-dark-mode,
body.rx-dark-mode {
color-scheme: dark;
--rx-color-body-bg: var(--rx-dark-color-body-bg);
--rx-color-body-text: var(--rx-dark-color-body-text);
--rx-color-heading: var(--rx-dark-color-heading);
--rx-color-paragraph: var(--rx-dark-color-paragraph);
--rx-color-card-bg: var(--rx-dark-color-card-bg);
--rx-color-card-border: var(--rx-dark-color-card-border);
--rx-color-header-bg: var(--rx-dark-color-header-bg);
--rx-color-header-text: var(--rx-dark-color-header-text);
--rx-color-footer-bg: var(--rx-dark-color-footer-bg);
--rx-color-footer-text: var(--rx-dark-color-footer-text);
--rx-color-input-bg: var(--rx-dark-color-input-bg);
--rx-color-input-text: var(--rx-dark-color-input-text);
--rx-color-input-border: var(--rx-dark-color-input-border);
}
";
}
if ( $enable_system_dark ) {
$css .= "
@media (prefers-color-scheme: dark) {
html:not(.rx-light-mode) {
color-scheme: dark;
--rx-color-body-bg: var(--rx-dark-color-body-bg);
--rx-color-body-text: var(--rx-dark-color-body-text);
--rx-color-heading: var(--rx-dark-color-heading);
--rx-color-paragraph: var(--rx-dark-color-paragraph);
--rx-color-card-bg: var(--rx-dark-color-card-bg);
--rx-color-card-border: var(--rx-dark-color-card-border);
--rx-color-header-bg: var(--rx-dark-color-header-bg);
--rx-color-header-text: var(--rx-dark-color-header-text);
--rx-color-footer-bg: var(--rx-dark-color-footer-bg);
--rx-color-footer-text: var(--rx-dark-color-footer-text);
--rx-color-input-bg: var(--rx-dark-color-input-bg);
--rx-color-input-text: var(--rx-dark-color-input-text);
--rx-color-input-border: var(--rx-dark-color-input-border);
}
}
";
}
return trim( $css );
}
/**
* Enqueue dynamic CSS on frontend.
*
* @return void
*/
public function enqueue_dynamic_colors() {
$handle = 'rx-theme-style';
if ( ! wp_style_is( $handle, 'enqueued' ) ) {
wp_register_style( 'rx-color-options', false, array(), wp_get_theme()->get( 'Version' ) );
wp_enqueue_style( 'rx-color-options' );
$handle = 'rx-color-options';
}
wp_add_inline_style( $handle, self::build_dynamic_css() );
}
/**
* Enqueue dynamic CSS inside block editor.
*
* @return void
*/
public function enqueue_editor_dynamic_colors() {
wp_register_style( 'rx-editor-color-options', false, array(), wp_get_theme()->get( 'Version' ) );
wp_enqueue_style( 'rx-editor-color-options' );
$css = "
.editor-styles-wrapper {
background: var(--rx-color-body-bg);
color: var(--rx-color-body-text);
}
.editor-styles-wrapper h1,
.editor-styles-wrapper h2,
.editor-styles-wrapper h3,
.editor-styles-wrapper h4,
.editor-styles-wrapper h5,
.editor-styles-wrapper h6 {
color: var(--rx-color-heading);
}
" . self::build_dynamic_css();
wp_add_inline_style( 'rx-editor-color-options', $css );
}
/**
* Register Gutenberg editor color palette.
*
* @return void
*/
public function register_editor_color_palette() {
if ( ! self::get_option( 'enable_editor_palette' ) ) {
return;
}
add_theme_support(
'editor-color-palette',
array(
array(
'name' => __( 'RX Primary', 'rx-theme' ),
'slug' => 'rx-primary',
'color' => self::get_option( 'color_primary' ),
),
array(
'name' => __( 'RX Secondary', 'rx-theme' ),
'slug' => 'rx-secondary',
'color' => self::get_option( 'color_secondary' ),
),
array(
'name' => __( 'RX Accent', 'rx-theme' ),
'slug' => 'rx-accent',
'color' => self::get_option( 'color_accent' ),
),
array(
'name' => __( 'RX Heading', 'rx-theme' ),
'slug' => 'rx-heading',
'color' => self::get_option( 'color_heading' ),
),
array(
'name' => __( 'RX Text', 'rx-theme' ),
'slug' => 'rx-text',
'color' => self::get_option( 'color_body_text' ),
),
array(
'name' => __( 'RX Muted', 'rx-theme' ),
'slug' => 'rx-muted',
'color' => self::get_option( 'color_body_text_muted' ),
),
array(
'name' => __( 'RX Medical Blue', 'rx-theme' ),
'slug' => 'rx-medical-blue',
'color' => self::get_option( 'color_medical_blue' ),
),
array(
'name' => __( 'RX Medical Green', 'rx-theme' ),
'slug' => 'rx-medical-green',
'color' => self::get_option( 'color_medical_green' ),
),
array(
'name' => __( 'RX Medical Red', 'rx-theme' ),
'slug' => 'rx-medical-red',
'color' => self::get_option( 'color_medical_red' ),
),
array(
'name' => __( 'RX Light Background', 'rx-theme' ),
'slug' => 'rx-light-bg',
'color' => self::get_option( 'color_box_bg' ),
),
)
);
add_theme_support(
'editor-gradient-presets',
array(
array(
'name' => __( 'RX Primary Gradient', 'rx-theme' ),
'gradient' => sprintf(
'linear-gradient(135deg, %s, %s)',
self::get_option( 'gradient_primary_start' ),
self::get_option( 'gradient_primary_end' )
),
'slug' => 'rx-primary-gradient',
),
array(
'name' => __( 'RX Secondary Gradient', 'rx-theme' ),
'gradient' => sprintf(
'linear-gradient(135deg, %s, %s)',
self::get_option( 'gradient_secondary_start' ),
self::get_option( 'gradient_secondary_end' )
),
'slug' => 'rx-secondary-gradient',
),
array(
'name' => __( 'RX Accent Gradient', 'rx-theme' ),
'gradient' => sprintf(
'linear-gradient(135deg, %s, %s)',
self::get_option( 'gradient_accent_start' ),
self::get_option( 'gradient_accent_end' )
),
'slug' => 'rx-accent-gradient',
),
)
);
}
/**
* Customizer live preview JS.
*
* @return void
*/
public function customizer_live_preview() {
wp_enqueue_script(
'rx-color-customizer-preview',
get_template_directory_uri() . '/assets/js/customizer-color-preview.js',
array( 'customize-preview' ),
wp_get_theme()->get( 'Version' ),
true
);
}
/**
* Print browser color-scheme meta.
*
* @return void
*/
public function print_color_scheme_meta() {
$enable_system_dark = self::get_option( 'enable_system_dark_mode' );
if ( $enable_system_dark ) {
echo '<meta name="color-scheme" content="light dark">' . "\n";
} else {
echo '<meta name="color-scheme" content="light">' . "\n";
}
$theme_color = self::get_option( 'color_primary' );
if ( $theme_color ) {
printf(
'<meta name="theme-color" content="%s">' . "\n",
esc_attr( $theme_color )
);
}
}
endif;
/**
* Initialize RX color options.
*/
if ( class_exists( 'RX_Color_Options' ) ) {
new RX_Color_Options();
}
/**
* Helper function: get RX color option.
*
* Usage:
* rx_get_color_option( 'color_primary' );
*
* @param string $key Color option key.
* @return mixed
*/
if ( ! function_exists( 'rx_get_color_option' ) ) {
function rx_get_color_option( $key ) {
if ( class_exists( 'RX_Color_Options' ) ) {
return RX_Color_Options::get_option( $key );
}
return '';
}
}
/**
* Helper function: output inline style color.
*
* Usage:
* echo rx_color_style( 'color_primary', 'color' );
*
* @param string $key Color key.
* @param string $property CSS property.
* @return string
*/
if ( ! function_exists( 'rx_color_style' ) ) {
function rx_color_style( $key, $property = 'color' ) {
$value = rx_get_color_option( $key );
if ( ! $value ) {
return '';
}
return sprintf(
'%s:%s;',
esc_attr( $property ),
esc_attr( $value )
);
}
}
/**
* Helper function: return CSS variable.
*
* Usage:
* color: <?php echo esc_attr( rx_css_var( 'color_primary' ) ); ?>;
*
* @param string $key Color key.
* @return string
*/
if ( ! function_exists( 'rx_css_var' ) ) {
function rx_css_var( $key ) {
return 'var(--rx-' . str_replace( '_', '-', sanitize_key( $key ) ) . ')';
}
}
Now include it inside your theme functions.php:
/**
* RX Theme Color Options
*/
require_once get_template_directory() . '/inc/options/color-options.php';
Optional live preview JS file:
Create:
mkdir -p assets/js
touch assets/js/customizer-color-preview.js
Paste this:
(function ($) {
'use strict';
const rxColorMap = {
rx_color_primary: '--rx-color-primary',
rx_color_primary_hover: '--rx-color-primary-hover',
rx_color_primary_light: '--rx-color-primary-light',
rx_color_primary_dark: '--rx-color-primary-dark',
rx_color_secondary: '--rx-color-secondary',
rx_color_secondary_hover: '--rx-color-secondary-hover',
rx_color_secondary_light: '--rx-color-secondary-light',
rx_color_secondary_dark: '--rx-color-secondary-dark',
rx_color_accent: '--rx-color-accent',
rx_color_accent_hover: '--rx-color-accent-hover',
rx_color_accent_light: '--rx-color-accent-light',
rx_color_accent_dark: '--rx-color-accent-dark',
rx_color_body_bg: '--rx-color-body-bg',
rx_color_body_text: '--rx-color-body-text',
rx_color_body_text_muted: '--rx-color-body-text-muted',
rx_color_heading: '--rx-color-heading',
rx_color_paragraph: '--rx-color-paragraph',
rx_color_link: '--rx-color-link',
rx_color_link_hover: '--rx-color-link-hover',
rx_color_link_visited: '--rx-color-link-visited',
rx_color_link_underline: '--rx-color-link-underline',
rx_color_header_bg: '--rx-color-header-bg',
rx_color_header_text: '--rx-color-header-text',
rx_color_header_link: '--rx-color-header-link',
rx_color_header_link_hover: '--rx-color-header-link-hover',
rx_color_header_border: '--rx-color-header-border',
rx_color_footer_bg: '--rx-color-footer-bg',
rx_color_footer_text: '--rx-color-footer-text',
rx_color_footer_heading: '--rx-color-footer-heading',
rx_color_footer_link: '--rx-color-footer-link',
rx_color_footer_link_hover: '--rx-color-footer-link-hover',
rx_color_button_bg: '--rx-color-button-bg',
rx_color_button_text: '--rx-color-button-text',
rx_color_button_hover_bg: '--rx-color-button-hover-bg',
rx_color_button_hover_text: '--rx-color-button-hover-text',
rx_color_card_bg: '--rx-color-card-bg',
rx_color_card_text: '--rx-color-card-text',
rx_color_card_border: '--rx-color-card-border',
rx_color_input_bg: '--rx-color-input-bg',
rx_color_input_text: '--rx-color-input-text',
rx_color_input_border: '--rx-color-input-border',
rx_color_input_focus_border: '--rx-color-input-focus-border',
rx_gradient_primary_start: '--rx-gradient-primary-start',
rx_gradient_primary_end: '--rx-gradient-primary-end',
rx_gradient_secondary_start: '--rx-gradient-secondary-start',
rx_gradient_secondary_end: '--rx-gradient-secondary-end',
rx_gradient_accent_start: '--rx-gradient-accent-start',
rx_gradient_accent_end: '--rx-gradient-accent-end',
rx_gradient_hero_start: '--rx-gradient-hero-start',
rx_gradient_hero_end: '--rx-gradient-hero-end'
};
Object.keys(rxColorMap).forEach(function (settingKey) {
wp.customize(settingKey, function (value) {
value.bind(function (newColor) {
document.documentElement.style.setProperty(rxColorMap[settingKey], newColor);
});
});
});
})(jQuery);
Use these CSS variables anywhere in your theme:
.example-box {
background: var(--rx-color-card-bg);
color: var(--rx-color-card-text);
border: 1px solid var(--rx-color-card-border);
}
.example-button {
background: var(--rx-color-primary);
color: #fff;
}
.example-hero {
background: var(--rx-gradient-hero);
}
This file gives your RX theme a strong, scalable color system.