'#FFFFFF', // Twitter Light: white 'bg_card' => '#F5F8FA', // Twitter Light: card background 'bg_card_hover' => '#EBEEF0', // Twitter Light: hover state 'bg_input' => '#F5F8FA', // Twitter Light: input fields // Colors - Text 'text_primary' => '#0F1419', // Twitter Light: main text (near black) 'text_secondary' => '#536471', // Twitter Light: muted text 'text_link' => '#1D9BF0', // Twitter Light: links (Twitter blue) // Colors - Borders & Dividers 'border_color' => '#EFF3F4', // Twitter Light: borders and dividers 'border_hover' => '#CBD0D4', // Twitter Light: hover border // Colors - Interactive 'color_like' => '#F91880', // Like heart (Twitter pink) 'color_repost' => '#00BA7C', // Repost green 'color_reply' => '#1D9BF0', // Reply blue 'color_quote' => '#1D9BF0', // Quote blue 'color_poll' => '#1D9BF0', // Poll blue // Colors - Buttons 'btn_primary_bg' => '#1D9BF0', // Primary button background 'btn_primary_text' => '#FFFFFF', // Primary button text 'btn_secondary_bg' => '#2F3336', // Secondary button background 'btn_secondary_text' => '#E7E9EA', // Secondary button text // Colors - Avatar Ring 'avatar_ring' => '#2F3336', // Avatar ring color // Branding 'logo_url' => '', // Custom logo URL 'icon_url' => '', // Custom icon URL (favicon) 'site_name' => 'Beep', // Or 'X' or 'Twitter' 'tagline' => 'Messages from', // Layout 'feed_max_width' => '600px', // Max width of feed 'feed_padding' => '16px', // Feed padding 'post_padding' => '14px 20px', // Post padding 'avatar_size' => '48px', // Avatar dimensions 'gap_between_posts' => '12px', // Gap between posts // Border Radius 'radius_card' => '16px', // Card border radius 'radius_avatar' => '9999px', // Avatar circle 'radius_button' => '9999px', // Buttons/pills 'radius_input' => '4px', // Input fields // Typography 'font_family' => '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif', 'font_size_base' => '15px', // Base font size 'font_size_small' => '13px', // Small text (timestamps) 'font_size_large' => '20px', // Large text (names) // Features (on/off) 'enable_likes' => '1', 'enable_reposts' => '1', 'enable_quotes' => '1', 'enable_polls' => '1', 'enable_follows' => '1', 'enable_media' => '1', 'enable_replies' => '1', // Behavior 'character_limit' => '280', 'posts_per_page' => '20', 'auto_refresh' => '0', // Auto refresh interval (0 = off) 'public_posting' => '0', // Allow public posting without login // Content 'show_avatar' => '1', 'show_stats' => '1', // Show reply/like counts 'show_timestamps' => '1', // Show relative time 'show_gravatar' => '1', // Show Gravatar 'show_public_notice' => '1', // Show "sign in to post" notice // Animation 'animation_speed' => '150', // Transition speed in ms ]; /** * Initialize settings */ public static function init() { add_action('admin_init', [__CLASS__, 'register_settings']); add_action('admin_menu', [__CLASS__, 'add_settings_page']); add_filter('plugin_action_links_' . plugin_basename(BEEP_FILE), [__CLASS__, 'add_settings_link']); add_action('wp_head', [__CLASS__, 'inject_css_variables'], 100); } /** * Get all settings with defaults */ public static function get_settings() { $saved = get_option(self::OPTION_KEY, []); return wp_parse_args($saved, self::$defaults); } /** * Get a single setting */ public static function get($key, $default = null) { $settings = self::get_settings(); return isset($settings[$key]) ? $settings[$key] : ($default ?? (self::$defaults[$key] ?? null)); } /** * Register settings with WordPress */ public static function register_settings() { register_setting( self::OPTION_KEY, self::OPTION_KEY, [ 'type' => 'array', 'sanitize_callback' => [__CLASS__, 'sanitize_settings'], 'default' => [], ] ); // === Section: Colors - Backgrounds === add_settings_section( 'beep_colors_bg', 'Colors - Backgrounds', [__CLASS__, 'section_colors_bg_description'], 'beep-settings' ); add_settings_field( 'bg_main', 'Main Background', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_bg', ['key' => 'bg_main', 'label' => 'Feed/Page background'] ); add_settings_field( 'bg_card', 'Card Background', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_bg', ['key' => 'bg_card', 'label' => 'Post cards & containers'] ); add_settings_field( 'bg_card_hover', 'Card Hover Background', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_bg', ['key' => 'bg_card_hover', 'label' => 'Hover state for cards'] ); add_settings_field( 'bg_input', 'Input Background', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_bg', ['key' => 'bg_input', 'label' => 'Textarea/input fields'] ); // === Section: Colors - Text === add_settings_section( 'beep_colors_text', 'Colors - Text', [__CLASS__, 'section_colors_text_description'], 'beep-settings' ); add_settings_field( 'text_primary', 'Primary Text', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_text', ['key' => 'text_primary', 'label' => 'Main text color'] ); add_settings_field( 'text_secondary', 'Secondary Text', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_text', ['key' => 'text_secondary', 'label' => 'Muted/timestamp text'] ); add_settings_field( 'text_link', 'Link Color', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_text', ['key' => 'text_link', 'label' => 'Links & buttons'] ); // === Section: Colors - Interactive === add_settings_section( 'beep_colors_interactive', 'Colors - Interactive Elements', [__CLASS__, 'section_colors_interactive_description'], 'beep-settings' ); add_settings_field( 'color_like', 'Like Heart Color', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_interactive', ['key' => 'color_like', 'label' => 'Heart/like button'] ); add_settings_field( 'color_repost', 'Repost Color', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_interactive', ['key' => 'color_repost', 'label' => 'Repost button'] ); add_settings_field( 'color_reply', 'Reply Color', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_interactive', ['key' => 'color_reply', 'label' => 'Reply button'] ); add_settings_field( 'border_color', 'Border Color', [__CLASS__, 'field_color_picker'], 'beep-settings', 'beep_colors_interactive', ['key' => 'border_color', 'label' => 'Dividers & borders'] ); // === Section: Layout === add_settings_section( 'beep_layout', 'Layout & Spacing', [__CLASS__, 'section_layout_description'], 'beep-settings' ); add_settings_field( 'feed_max_width', 'Feed Max Width', [__CLASS__, 'field_text'], 'beep-settings', 'beep_layout', ['key' => 'feed_max_width', 'label' => 'e.g. 600px or 100%'] ); add_settings_field( 'feed_padding', 'Feed Padding', [__CLASS__, 'field_text'], 'beep-settings', 'beep_layout', ['key' => 'feed_padding', 'label' => 'e.g. 16px'] ); add_settings_field( 'post_padding', 'Post Padding', [__CLASS__, 'field_text'], 'beep-settings', 'beep_layout', ['key' => 'post_padding', 'label' => 'e.g. 14px 20px'] ); add_settings_field( 'avatar_size', 'Avatar Size', [__CLASS__, 'field_text'], 'beep-settings', 'beep_layout', ['key' => 'avatar_size', 'label' => 'e.g. 48px'] ); // === Section: Border Radius === add_settings_section( 'beep_radius', 'Border Radius', [__CLASS__, 'section_radius_description'], 'beep-settings' ); add_settings_field( 'radius_card', 'Card Radius', [__CLASS__, 'field_text'], 'beep-settings', 'beep_radius', ['key' => 'radius_card', 'label' => 'e.g. 16px for cards, 0 for sharp edges'] ); add_settings_field( 'radius_avatar', 'Avatar Radius', [__CLASS__, 'field_text'], 'beep-settings', 'beep_radius', ['key' => 'radius_avatar', 'label' => 'e.g. 9999px for circle'] ); // === Section: Typography === add_settings_section( 'beep_typography', 'Typography', [__CLASS__, 'section_typography_description'], 'beep-settings' ); add_settings_field( 'font_family', 'Font Family', [__CLASS__, 'field_text'], 'beep-settings', 'beep_typography', ['key' => 'font_family', 'label' => 'CSS font-family value'] ); add_settings_field( 'font_size_base', 'Base Font Size', [__CLASS__, 'field_text'], 'beep-settings', 'beep_typography', ['key' => 'font_size_base', 'label' => 'e.g. 15px'] ); // === Section: Branding & Media === add_settings_section( 'beep_branding', 'Branding & Media', [__CLASS__, 'section_branding_description'], 'beep-settings' ); add_settings_field( 'logo_url', 'Logo Image', [__CLASS__, 'field_media_upload'], 'beep-settings', 'beep_branding', ['key' => 'logo_url', 'label' => 'Upload a logo image. Leave empty to use text.'] ); add_settings_field( 'icon_url', 'Icon Image', [__CLASS__, 'field_media_upload'], 'beep-settings', 'beep_branding', ['key' => 'icon_url', 'label' => 'Upload an icon/favicon image.'] ); add_settings_field( 'site_name', 'Site Name', [__CLASS__, 'field_text'], 'beep-settings', 'beep_branding', ['key' => 'site_name', 'label' => 'e.g. Beep, X, or Twitter'] ); add_settings_field( 'tagline', 'Tagline', [__CLASS__, 'field_text'], 'beep-settings', 'beep_branding', ['key' => 'tagline', 'label' => 'Text above logo, e.g. "Messages from"'] ); // === Section: Features === add_settings_section( 'beep_features', 'Features', [__CLASS__, 'section_features_description'], 'beep-settings' ); add_settings_field( 'enable_likes', 'Enable Likes', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_features', ['key' => 'enable_likes', 'label' => 'Show like button on posts'] ); add_settings_field( 'enable_reposts', 'Enable Reposts', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_features', ['key' => 'enable_reposts', 'label' => 'Show repost button'] ); add_settings_field( 'enable_quotes', 'Enable Quotes', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_features', ['key' => 'enable_quotes', 'label' => 'Show quote button'] ); add_settings_field( 'enable_replies', 'Enable Replies', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_features', ['key' => 'enable_replies', 'label' => 'Allow replying to posts'] ); add_settings_field( 'enable_media', 'Enable Media', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_features', ['key' => 'enable_media', 'label' => 'Allow image attachments'] ); add_settings_field( 'enable_polls', 'Enable Polls', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_features', ['key' => 'enable_polls', 'label' => 'Allow poll creation'] ); // === Section: Behavior === add_settings_section( 'beep_behavior', 'Behavior', [__CLASS__, 'section_behavior_description'], 'beep-settings' ); add_settings_field( 'character_limit', 'Character Limit', [__CLASS__, 'field_text'], 'beep-settings', 'beep_behavior', ['key' => 'character_limit', 'label' => 'Max characters per post (default 280)'] ); add_settings_field( 'posts_per_page', 'Posts Per Page', [__CLASS__, 'field_text'], 'beep-settings', 'beep_behavior', ['key' => 'posts_per_page', 'label' => 'Number of posts to load'] ); add_settings_field( 'public_posting', 'Allow Public Posting', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_behavior', ['key' => 'public_posting', 'label' => 'Allow posting without logging in'] ); // === Section: Content Display === add_settings_section( 'beep_content', 'Content Display', [__CLASS__, 'section_content_description'], 'beep-settings' ); add_settings_field( 'show_avatar', 'Show Avatars', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_content', ['key' => 'show_avatar', 'label' => 'Display user profile pictures'] ); add_settings_field( 'show_stats', 'Show Statistics', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_content', ['key' => 'show_stats', 'label' => 'Display reply/like counts'] ); add_settings_field( 'show_timestamps', 'Show Timestamps', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_content', ['key' => 'show_timestamps', 'label' => 'Display relative time'] ); add_settings_field( 'show_public_notice', 'Show Public Notice', [__CLASS__, 'field_checkbox'], 'beep-settings', 'beep_content', ['key' => 'show_public_notice', 'label' => 'Show "Sign in to post" notice'] ); } /** * Add settings page to admin menu */ public static function add_settings_page() { add_options_page( 'Beep Settings', 'Beep', 'manage_options', 'beep-settings', [__CLASS__, 'render_settings_page'] ); } /** * Add settings link on Plugins page */ public static function add_settings_link($links) { $settings_link = '' . __('Settings') . ''; array_unshift($links, $settings_link); return $links; } /** * Sanitize settings on save */ public static function sanitize_settings($input) { $sanitized = []; foreach (self::$defaults as $key => $default) { if (is_bool($default)) { $sanitized[$key] = !empty($input[$key]) ? '1' : '0'; } elseif (is_int($default)) { $sanitized[$key] = isset($input[$key]) ? intval($input[$key]) : $default; } else { $sanitized[$key] = isset($input[$key]) ? sanitize_text_field($input[$key]) : $default; } } return $sanitized; } /** * Render the settings page */ public static function render_settings_page() { if (!current_user_can('manage_options')) { return; } ?>
Customize the appearance and behavior of your Beep feed. Changes take effect immediately.
Quick Presets:
Text colors throughout the feed.
'; } public static function section_colors_interactive_description() { echo 'Colors for interactive elements like buttons and icons.
'; } public static function section_layout_description() { echo 'Spacing and layout dimensions.
'; } public static function section_radius_description() { echo 'Border radius for rounded corners. Use 0px for sharp edges (Twitter style), 16px for rounded cards.
Font settings.
'; } public static function section_branding_description() { echo 'Logo, icon, and site name settings.
'; } public static function section_features_description() { echo 'Toggle features on or off.
'; } public static function section_behavior_description() { echo 'How the feed behaves.
'; } public static function section_content_description() { echo 'What to show/hide in the feed.
'; } // === Field Renderers === public static function field_color_picker($args) { $key = $args['key']; $label = $args['label']; $value = self::get($key); ?>