add_panel( 'plugetune_panel', array( 'title' => __( 'PlugeTune Settings', 'plugetune' ), 'description' => __( 'Customize PlugeTune video player and layout.', 'plugetune' ), 'priority' => 30, ) ); $wp_customize->add_section( 'plugetune_single_layout', array( 'title' => __( 'Single Video Layout', 'plugetune' ), 'description' => __( 'Customize the layout of single video pages.', 'plugetune' ), 'panel' => 'plugetune_panel', 'priority' => 10, ) ); $wp_customize->add_setting( 'plugetune_single_layout_preset', array( 'default' => 'narrow', 'sanitize_callback' => 'sanitize_key', 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_layout_preset', array( 'label' => __( 'Layout Preset', 'plugetune' ), 'description' => __( 'Choose a preset for the single video page width.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'select', 'choices' => array( 'narrow' => __( 'Narrow (900px) — Best for reading', 'plugetune' ), 'boxed' => __( 'Boxed (1100px) — Balanced', 'plugetune' ), 'wide' => __( 'Wide (1400px) — Big player', 'plugetune' ), 'full' => __( 'Full Width (100%) — Edge-to-edge', 'plugetune' ), ), ) ); $wp_customize->add_setting( 'plugetune_single_card_style', array( 'default' => 'card', 'sanitize_callback' => 'sanitize_key', 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_card_style', array( 'label' => __( 'Container Style', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'select', 'choices' => array( 'card' => __( 'Card (white box with shadow)', 'plugetune' ), 'flat' => __( 'Flat (no shadow)', 'plugetune' ), 'plain' => __( 'Plain (no bg, no border)', 'plugetune' ), ), ) ); $wp_customize->add_setting( 'plugetune_single_elements_gap', array( 'default' => 16, 'sanitize_callback' => array( $this, 'sanitize_spacing' ), 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_elements_gap', array( 'label' => __( 'Elements Gap (px)', 'plugetune' ), 'description' => __( 'Spacing between breadcrumbs, title, meta, and description. Default: 16px. Range: 0–60.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'number', 'input_attrs' => array( 'min' => 0, 'max' => 60, 'step' => 1, ), ) ); $wp_customize->add_setting( 'plugetune_single_container_padding', array( 'default' => 24, 'sanitize_callback' => array( $this, 'sanitize_spacing' ), 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_container_padding', array( 'label' => __( 'Container Padding (px)', 'plugetune' ), 'description' => __( 'Padding around the video player. Default: 24px. Range: 0–60.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'number', 'input_attrs' => array( 'min' => 0, 'max' => 60, 'step' => 1, ), ) ); $wp_customize->add_setting( 'plugetune_single_content_padding', array( 'default' => 32, 'sanitize_callback' => array( $this, 'sanitize_spacing' ), 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_content_padding', array( 'label' => __( 'Content Padding (px)', 'plugetune' ), 'description' => __( 'Inner padding around content. Default: 32px.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'number', 'input_attrs' => array( 'min' => 0, 'max' => 80, 'step' => 1, ), ) ); $wp_customize->add_setting( 'plugetune_single_font_family', array( 'default' => 'inherit', 'sanitize_callback' => 'sanitize_text_field', 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_font_family', array( 'label' => __( 'Font Family', 'plugetune' ), 'description' => __( 'Font family for title, description, meta, and breadcrumbs.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'select', 'choices' => array( 'inherit' => __( 'Inherit from theme', 'plugetune' ), 'system-ui' => __( 'System UI (native)', 'plugetune' ), 'arial' => __( 'Arial', 'plugetune' ), 'helvetica' => __( 'Helvetica', 'plugetune' ), 'georgia' => __( 'Georgia (serif)', 'plugetune' ), 'times' => __( 'Times New Roman (serif)', 'plugetune' ), 'verdana' => __( 'Verdana', 'plugetune' ), 'tahoma' => __( 'Tahoma', 'plugetune' ), 'trebuchet' => __( 'Trebuchet MS', 'plugetune' ), 'courier' => __( 'Courier New (monospace)', 'plugetune' ), 'inter' => __( 'Inter (if loaded)', 'plugetune' ), 'roboto' => __( 'Roboto (if loaded)', 'plugetune' ), 'open-sans' => __( 'Open Sans (if loaded)', 'plugetune' ), 'lato' => __( 'Lato (if loaded)', 'plugetune' ), 'montserrat' => __( 'Montserrat (if loaded)', 'plugetune' ), 'poppins' => __( 'Poppins (if loaded)', 'plugetune' ), ), ) ); $wp_customize->add_setting( 'plugetune_single_title_font_size', array( 'default' => 32, 'sanitize_callback' => array( $this, 'sanitize_font_size' ), 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_title_font_size', array( 'label' => __( 'Title Font Size (px)', 'plugetune' ), 'description' => __( 'Default: 32px. Range: 16–64.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'number', 'input_attrs' => array( 'min' => 16, 'max' => 64, 'step' => 1, ), ) ); $wp_customize->add_setting( 'plugetune_single_desc_font_size', array( 'default' => 16, 'sanitize_callback' => array( $this, 'sanitize_font_size' ), 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_desc_font_size', array( 'label' => __( 'Description Font Size (px)', 'plugetune' ), 'description' => __( 'Default: 16px. Range: 12–32.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'number', 'input_attrs' => array( 'min' => 12, 'max' => 32, 'step' => 1, ), ) ); $wp_customize->add_setting( 'plugetune_single_meta_font_size', array( 'default' => 14, 'sanitize_callback' => array( $this, 'sanitize_font_size' ), 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_meta_font_size', array( 'label' => __( 'Meta Font Size (px)', 'plugetune' ), 'description' => __( 'Date, author, category, breadcrumbs. Default: 14px. Range: 10–20.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'number', 'input_attrs' => array( 'min' => 10, 'max' => 20, 'step' => 1, ), ) ); $wp_customize->add_setting( 'plugetune_single_bg_color', array( 'default' => '#f8fafc', 'sanitize_callback' => 'sanitize_hex_color', 'transport' => 'refresh', ) ); $wp_customize->add_control( new WP_Customize_Color_Control( $wp_customize, 'plugetune_single_bg_color', array( 'label' => __( 'Page Background', 'plugetune' ), 'section' => 'plugetune_single_layout', ) ) ); $wp_customize->add_setting( 'plugetune_single_show_sidebar', array( 'default' => false, 'sanitize_callback' => 'rest_sanitize_boolean', 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_show_sidebar', array( 'label' => __( 'Show Sidebar', 'plugetune' ), 'description' => __( 'Enable the theme sidebar on single video pages.', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'checkbox', ) ); $wp_customize->add_setting( 'plugetune_single_show_breadcrumbs', array( 'default' => true, 'sanitize_callback' => 'rest_sanitize_boolean', 'transport' => 'refresh', ) ); $wp_customize->add_control( 'plugetune_single_show_breadcrumbs', array( 'label' => __( 'Show Breadcrumbs', 'plugetune' ), 'section' => 'plugetune_single_layout', 'type' => 'checkbox', ) ); } /** * Sanitize a spacing value (padding/margin). * * @param mixed $value Raw input value. * @return int Sanitized value (0–80). */ public function sanitize_spacing( $value ) { $value = absint( $value ); return max( 0, min( 80, $value ) ); } /** * Sanitize a font size value. * * @param mixed $value Raw input value. * @return int Sanitized value (10–64). */ public function sanitize_font_size( $value ) { $value = absint( $value ); return max( 10, min( 64, $value ) ); } /** * Map a font-family choice key to a full CSS font-family stack. * * @param string $key Font family key. * @return string CSS font-family value. */ public function get_font_family_stack( $key ) { $stacks = array( 'inherit' => '', 'system-ui' => '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif', 'arial' => 'Arial, Helvetica, sans-serif', 'helvetica' => 'Helvetica, Arial, sans-serif', 'georgia' => 'Georgia, "Times New Roman", serif', 'times' => '"Times New Roman", Times, serif', 'verdana' => 'Verdana, Geneva, sans-serif', 'tahoma' => 'Tahoma, Geneva, sans-serif', 'trebuchet' => '"Trebuchet MS", Helvetica, sans-serif', 'courier' => '"Courier New", Courier, monospace', 'inter' => '"Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', 'roboto' => '"Roboto", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', 'open-sans' => '"Open Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', 'lato' => '"Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', 'montserrat' => '"Montserrat", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', 'poppins' => '"Poppins", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif', ); return isset( $stacks[ $key ] ) ? $stacks[ $key ] : ''; } /** * Resolve the effective layout width based on the selected preset. * * @param string|null $preset Optional preset override. * @return string CSS width value. */ public static function get_layout_width( $preset = null ) { if ( null === $preset ) { $preset = get_theme_mod( 'plugetune_single_layout_preset', 'narrow' ); } switch ( $preset ) { case 'full': return '100%'; case 'wide': return '1400px'; case 'boxed': return '1100px'; case 'narrow': default: return '900px'; } } /** * Enqueue the frontend styles and add the dynamic customizer CSS. * * Static styles live in assets/css/plugetune_customizer-static.css. The dynamic * rules that depend on theme_mod values are generated here and injected * via wp_add_inline_style() — the recommended WordPress.org pattern. * * @return void */ public function enqueue_styles() { if ( ! is_singular( 'plugetune_video' ) ) { return; } wp_enqueue_style( 'plugetune-frontend', PLUGETUNE_URL . 'assets/css/plugetune_frontend.css', array(), PLUGETUNE_VERSION ); wp_enqueue_style( 'plugetune-customizer-static', PLUGETUNE_URL . 'assets/css/plugetune_customizer-static.css', array( 'plugetune-frontend' ), PLUGETUNE_VERSION ); $max_width = self::get_layout_width(); $elements_gap = max( 0, min( 60, absint( get_theme_mod( 'plugetune_single_elements_gap', 16 ) ) ) ); $container_pad = max( 0, min( 60, absint( get_theme_mod( 'plugetune_single_container_padding', 24 ) ) ) ); $padding = max( 0, min( 80, absint( get_theme_mod( 'plugetune_single_content_padding', 32 ) ) ) ); $font_key = get_theme_mod( 'plugetune_single_font_family', 'inherit' ); $title_size = max( 16, min( 64, absint( get_theme_mod( 'plugetune_single_title_font_size', 32 ) ) ) ); $desc_size = max( 12, min( 32, absint( get_theme_mod( 'plugetune_single_desc_font_size', 16 ) ) ) ); $meta_size = max( 10, min( 20, absint( get_theme_mod( 'plugetune_single_meta_font_size', 14 ) ) ) ); $bg_color = get_theme_mod( 'plugetune_single_bg_color', '#f8fafc' ); $show_sidebar = get_theme_mod( 'plugetune_single_show_sidebar', false ); $layout_preset = get_theme_mod( 'plugetune_single_layout_preset', 'narrow' ); $card_style = get_theme_mod( 'plugetune_single_card_style', 'card' ); $font_family_css = ''; $font_stack = $this->get_font_family_stack( $font_key ); if ( ! empty( $font_stack ) ) { $font_family_css = 'font-family: ' . $font_stack . ' !important;'; } $padding_mobile = max( 16, intval( $padding / 1.5 ) ); $container_pad_mobile = max( 12, intval( $container_pad / 2 ) ); $custom_css = " .plugetune-single-page { background: " . esc_attr( $bg_color ) . " !important; width: 100vw !important; max-width: 100vw !important; position: relative !important; left: 50% !important; margin-left: -50vw !important; --plugetune-content-padding-mobile: " . absint( $padding_mobile ) . "px; --plugetune-container-padding-mobile: " . absint( $container_pad_mobile ) . "px; " . $font_family_css . " } .plugetune-single-wrapper { display: flex !important; justify-content: center !important; align-items: flex-start !important; width: 100% !important; margin: 0 auto !important; } .plugetune-single-main { width: 100% !important; max-width: " . esc_attr( $max_width ) . " !important; margin: 0 auto !important; flex: 0 1 auto !important; } .plugetune-single-container { width: 100% !important; max-width: " . esc_attr( $max_width ) . " !important; margin-left: auto !important; margin-right: auto !important; } .plugetune-single-info { padding: " . absint( $padding ) . "px !important; } .plugetune-single-player { padding: " . absint( $container_pad ) . "px " . absint( $container_pad ) . "px 0 !important; } .plugetune-single-comments { padding: 0 " . absint( $padding ) . "px " . absint( $padding ) . "px !important; } .plugetune-breadcrumbs { font-size: " . absint( $meta_size ) . "px !important; margin-bottom: " . absint( $elements_gap ) . "px !important; } .plugetune-single-title { font-size: " . absint( $title_size ) . "px !important; margin-top: 0 !important; margin-bottom: " . absint( $elements_gap ) . "px !important; } .plugetune-single-meta { font-size: " . absint( $meta_size ) . "px !important; margin-bottom: " . absint( $elements_gap ) . "px !important; } .plugetune-single-meta .plugetune-meta-item { font-size: " . absint( $meta_size ) . "px !important; display: inline-flex !important; align-items: center !important; vertical-align: middle !important; gap: 6px; } .plugetune-single-meta .plugetune-meta-item svg { flex-shrink: 0; display: block; } @media screen and (max-width: 768px) { .plugetune-single-title { font-size: 20px !important; } } .plugetune-single-description { font-size: " . absint( $desc_size ) . "px !important; margin-top: " . absint( $elements_gap ) . "px !important; } .plugetune-single-description p { font-size: " . absint( $desc_size ) . "px !important; } .plugetune-single-description p + p { margin-top: " . absint( $elements_gap ) . "px !important; } "; wp_add_inline_style( 'plugetune-customizer-static', $custom_css ); add_filter( 'body_class', function ( $classes ) use ( $layout_preset, $card_style, $show_sidebar ) { if ( ! $show_sidebar ) { $classes[] = 'plugetune-no-sidebar'; } $classes[] = 'plugetune-layout-' . sanitize_html_class( $layout_preset ); $classes[] = 'plugetune-card-' . sanitize_html_class( $card_style ); return $classes; } ); } /** * Determine whether the single video sidebar should be displayed. * * @return bool */ public static function should_show_sidebar() { return (bool) get_theme_mod( 'plugetune_single_show_sidebar', false ); } /** * Determine whether the single video breadcrumbs should be displayed. * * @return bool */ public static function should_show_breadcrumbs() { return (bool) get_theme_mod( 'plugetune_single_show_breadcrumbs', true ); } } PlugeTune_Customizer::get_instance();