| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Dark Mode Class 4 * 5 * @package WordPress 6 * @subpackage Twenty_Twenty_One 7 * @since Twenty Twenty-One 1.0 8 */ 9 10 /** 11 * This class is in charge of Dark Mode. 12 */ 13 class Twenty_Twenty_One_Dark_Mode { 14 15 /** 16 * Instantiates the object. 17 * 18 * @since Twenty Twenty-One 1.0 19 */ 20 public function __construct() { 21 22 // Enqueue assets for the block-editor. 23 if ( is_admin() ) { 24 add_action( 'enqueue_block_assets', array( $this, 'editor_custom_color_variables' ) ); 25 } 26 27 // Add styles for dark-mode. 28 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); 29 30 // Add scripts for customizer controls. 31 add_action( 'customize_controls_enqueue_scripts', array( $this, 'customize_controls_enqueue_scripts' ) ); 32 33 // Add customizer controls. 34 add_action( 'customize_register', array( $this, 'customizer_controls' ) ); 35 36 // Add HTML classes. 37 add_filter( 'twentytwentyone_html_classes', array( $this, 'html_classes' ) ); 38 39 // Add classes to <body> in the dashboard. 40 add_filter( 'admin_body_class', array( $this, 'admin_body_classes' ) ); 41 42 // Add the switch on the frontend & customizer. 43 add_action( 'wp_footer', array( $this, 'the_switch' ) ); 44 45 // Add the privacy policy content. 46 add_action( 'admin_init', array( $this, 'add_privacy_policy_content' ) ); 47 } 48 49 /** 50 * Enqueues editor custom color variables & scripts. 51 * 52 * @since Twenty Twenty-One 1.0 53 * 54 * @return void 55 */ 56 public function editor_custom_color_variables() { 57 if ( ! $this->switch_should_render() ) { 58 return; 59 } 60 $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); 61 $should_respect_color_scheme = get_theme_mod( 'respect_user_color_preference', false ); 62 if ( $should_respect_color_scheme && Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) > 127 ) { 63 // Add Dark Mode variable overrides. 64 wp_add_inline_style( 65 'twenty-twenty-one-custom-color-overrides', 66 '.is-dark-theme.is-dark-theme .editor-styles-wrapper { --global--color-background: var(--global--color-dark-gray); --global--color-primary: var(--global--color-light-gray); --global--color-secondary: var(--global--color-light-gray); --button--color-text: var(--global--color-background); --button--color-text-hover: var(--global--color-secondary); --button--color-text-active: var(--global--color-secondary); --button--color-background: var(--global--color-secondary); --button--color-background-active: var(--global--color-background); --global--color-border: #9ea1a7; --table--stripes-border-color: rgba(240, 240, 240, 0.15); --table--stripes-background-color: rgba(240, 240, 240, 0.15); }' 67 ); 68 } 69 wp_enqueue_script( 70 'twentytwentyone-dark-mode-support-toggle', 71 get_template_directory_uri() . '/assets/js/dark-mode-toggler.js', 72 array(), 73 '1.0.0', 74 array( 'in_footer' => true ) 75 ); 76 77 wp_enqueue_script( 78 'twentytwentyone-editor-dark-mode-support', 79 get_template_directory_uri() . '/assets/js/editor-dark-mode-support.js', 80 array( 'twentytwentyone-dark-mode-support-toggle' ), 81 '1.0.0', 82 array( 'in_footer' => true ) 83 ); 84 } 85 86 /** 87 * Enqueues scripts and styles. 88 * 89 * @since Twenty Twenty-One 1.0 90 * 91 * @return void 92 */ 93 public function enqueue_scripts() { 94 if ( ! $this->switch_should_render() ) { 95 return; 96 } 97 $url = get_template_directory_uri() . '/assets/css/style-dark-mode.css'; 98 if ( is_rtl() ) { 99 $url = get_template_directory_uri() . '/assets/css/style-dark-mode-rtl.css'; 100 } 101 wp_enqueue_style( 'tt1-dark-mode', $url, array( 'twenty-twenty-one-style' ), wp_get_theme()->get( 'Version' ) ); // @phpstan-ignore-line. Version is always a string. 102 } 103 104 /** 105 * Enqueues scripts for the customizer. 106 * 107 * @since Twenty Twenty-One 1.0 108 * 109 * @return void 110 */ 111 public function customize_controls_enqueue_scripts() { 112 if ( ! $this->switch_should_render() ) { 113 return; 114 } 115 wp_enqueue_script( 116 'twentytwentyone-customize-controls', 117 get_template_directory_uri() . '/assets/js/customize.js', 118 array( 'customize-base', 'customize-controls', 'underscore', 'jquery', 'twentytwentyone-customize-helpers' ), 119 '1.0.0', 120 array( 'in_footer' => true ) 121 ); 122 } 123 124 /** 125 * Registers customizer options. 126 * 127 * @since Twenty Twenty-One 1.0 128 * 129 * @param WP_Customize_Manager $wp_customize Theme Customizer object. 130 * @return void 131 */ 132 public function customizer_controls( $wp_customize ) { 133 134 $colors_section = $wp_customize->get_section( 'colors' ); 135 if ( is_object( $colors_section ) ) { 136 $colors_section->title = __( 'Colors & Dark Mode', 'twentytwentyone' ); 137 } 138 139 // Custom notice control. 140 require_once get_theme_file_path( 'classes/class-twenty-twenty-one-customize-notice-control.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound 141 142 $wp_customize->add_setting( 143 'respect_user_color_preference_notice', 144 array( 145 'capability' => 'edit_theme_options', 146 'default' => '', 147 'sanitize_callback' => '__return_empty_string', 148 ) 149 ); 150 151 $wp_customize->add_control( 152 new Twenty_Twenty_One_Customize_Notice_Control( 153 $wp_customize, 154 'respect_user_color_preference_notice', 155 array( 156 'section' => 'colors', 157 'priority' => 100, 158 'active_callback' => static function () { 159 return 127 >= Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( get_theme_mod( 'background_color', 'D1E4DD' ) ); 160 }, 161 ) 162 ) 163 ); 164 165 $wp_customize->add_setting( 166 'respect_user_color_preference', 167 array( 168 'capability' => 'edit_theme_options', 169 'default' => false, 170 'sanitize_callback' => static function ( $value ) { 171 return (bool) $value; 172 }, 173 ) 174 ); 175 176 $description = '<p>'; 177 $description .= sprintf( 178 /* translators: %s: Twenty Twenty-One support article URL. */ 179 __( 'Dark Mode is a device setting. If a visitor to your site requests it, your site will be shown with a dark background and light text. <a href="%s">Learn more about Dark Mode.</a>', 'twentytwentyone' ), 180 esc_url( __( 'https://wordpress.org/documentation/article/twenty-twenty-one/#dark-mode-support', 'twentytwentyone' ) ) 181 ); 182 $description .= '</p>'; 183 $description .= '<p>' . __( 'Dark Mode can also be turned on and off with a button that you can find in the bottom corner of the page.', 'twentytwentyone' ) . '</p>'; 184 185 $wp_customize->add_control( 186 'respect_user_color_preference', 187 array( 188 'type' => 'checkbox', 189 'section' => 'colors', 190 'label' => esc_html__( 'Dark Mode support', 'twentytwentyone' ), 191 'priority' => 110, 192 'description' => $description, 193 'active_callback' => static function ( $value ) { 194 return 127 < Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( get_theme_mod( 'background_color', 'D1E4DD' ) ); 195 }, 196 ) 197 ); 198 199 // Add partial for background_color. 200 $wp_customize->selective_refresh->add_partial( 201 'background_color', 202 array( 203 'selector' => '#dark-mode-toggler', 204 'container_inclusive' => true, 205 'render_callback' => function () { 206 $attrs = ( $this->switch_should_render() ) ? array() : array( 'style' => 'display:none;' ); 207 $this->the_html( $attrs ); 208 }, 209 ) 210 ); 211 } 212 213 /** 214 * Calculates classes for the main <html> element. 215 * 216 * @since Twenty Twenty-One 1.0 217 * 218 * @param string $classes The classes for <html> element. 219 * @return string 220 */ 221 public function html_classes( $classes ) { 222 if ( ! $this->switch_should_render() ) { 223 return $classes; 224 } 225 226 $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); 227 $should_respect_color_scheme = get_theme_mod( 'respect_user_color_preference', false ); 228 if ( $should_respect_color_scheme && 127 <= Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) ) { 229 return ( $classes ) ? ' respect-color-scheme-preference' : 'respect-color-scheme-preference'; 230 } 231 232 return $classes; 233 } 234 235 /** 236 * Adds a class to the <body> element in the editor to accommodate dark-mode. 237 * 238 * @since Twenty Twenty-One 1.0 239 * 240 * @global WP_Screen $current_screen WordPress current screen object. 241 * 242 * @param string $classes The admin body-classes. 243 * @return string 244 */ 245 public function admin_body_classes( $classes ) { 246 if ( ! $this->switch_should_render() ) { 247 return $classes; 248 } 249 250 global $current_screen; 251 if ( empty( $current_screen ) ) { 252 set_current_screen(); 253 } 254 255 if ( $current_screen->is_block_editor() ) { 256 $should_respect_color_scheme = get_theme_mod( 'respect_user_color_preference', false ); 257 $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); 258 259 if ( $should_respect_color_scheme && Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) > 127 ) { 260 $classes .= ' twentytwentyone-supports-dark-theme'; 261 } 262 } 263 264 return $classes; 265 } 266 267 /** 268 * Determines if we want to print the dark-mode switch or not. 269 * 270 * @since Twenty Twenty-One 1.0 271 * 272 * @global bool $is_IE 273 * 274 * @return bool 275 */ 276 public function switch_should_render() { 277 global $is_IE; 278 return ( 279 get_theme_mod( 'respect_user_color_preference', false ) && 280 ! $is_IE && 281 127 <= Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( get_theme_mod( 'background_color', 'D1E4DD' ) ) 282 ); 283 } 284 285 /** 286 * Adds night/day switch. 287 * 288 * @since Twenty Twenty-One 1.0 289 * 290 * @return void 291 */ 292 public function the_switch() { 293 if ( ! $this->switch_should_render() ) { 294 return; 295 } 296 $this->the_html(); 297 $this->the_script(); 298 } 299 300 /** 301 * Prints the dark-mode switch HTML. 302 * 303 * Inspired from https://codepen.io/aaroniker/pen/KGpXZo (MIT-licensed) 304 * 305 * @since Twenty Twenty-One 1.0 306 * 307 * @param array $attrs The attributes to add to our <button> element. 308 * @return void 309 */ 310 public function the_html( $attrs = array() ) { 311 $attrs = wp_parse_args( 312 $attrs, 313 array( 314 'id' => 'dark-mode-toggler', 315 'class' => 'fixed-bottom', 316 'aria-pressed' => 'false', 317 'onClick' => 'toggleDarkMode()', 318 ) 319 ); 320 echo '<button'; 321 foreach ( $attrs as $key => $val ) { 322 echo ' ' . esc_attr( $key ) . '="' . esc_attr( $val ) . '"'; 323 } 324 echo '>'; 325 printf( 326 /* translators: %s: On/Off */ 327 esc_html__( 'Dark Mode: %s', 'twentytwentyone' ), 328 '<span aria-hidden="true"></span>' 329 ); 330 echo '</button>'; 331 ?> 332 <style> 333 #dark-mode-toggler > span { 334 margin-<?php echo is_rtl() ? 'right' : 'left'; ?>: 5px; 335 } 336 #dark-mode-toggler > span::before { 337 content: '<?php esc_attr_e( 'Off', 'twentytwentyone' ); ?>'; 338 } 339 #dark-mode-toggler[aria-pressed="true"] > span::before { 340 content: '<?php esc_attr_e( 'On', 'twentytwentyone' ); ?>'; 341 } 342 <?php if ( is_admin() || wp_is_json_request() ) : ?> 343 .components-editor-notices__pinned ~ .edit-post-visual-editor #dark-mode-toggler { 344 z-index: 20; 345 } 346 .is-dark-theme.is-dark-theme #dark-mode-toggler:not(:hover):not(:focus) { 347 color: var(--global--color-primary); 348 } 349 @media only screen and (max-width: 782px) { 350 #dark-mode-toggler { 351 margin-top: 32px; 352 } 353 } 354 <?php endif; ?> 355 </style> 356 357 <?php 358 } 359 360 /** 361 * Prints the dark-mode switch script. 362 * 363 * @since Twenty Twenty-One 1.0 364 * 365 * @return void 366 */ 367 public function the_script() { 368 $path = 'assets/js/dark-mode-toggler.js'; 369 $js = rtrim( file_get_contents( trailingslashit( get_template_directory() ) . $path ) ); 370 $js .= "\n//# sourceURL=" . esc_url_raw( trailingslashit( get_template_directory_uri() ) . $path ); 371 if ( function_exists( 'wp_print_inline_script_tag' ) ) { 372 wp_print_inline_script_tag( $js ); 373 } else { 374 printf( "<script>%s</script>\n", $js ); 375 } 376 } 377 378 /** 379 * Adds information to the privacy policy. 380 * 381 * @since Twenty Twenty-One 1.0 382 * 383 * @return void 384 */ 385 public function add_privacy_policy_content() { 386 if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { 387 return; 388 } 389 $content = '<p class="privacy-policy-tutorial">' . __( 'Twenty Twenty-One uses LocalStorage when Dark Mode support is enabled.', 'twentytwentyone' ) . '</p>' 390 . '<strong class="privacy-policy-tutorial">' . __( 'Suggested text:', 'twentytwentyone' ) . '</strong> ' 391 . __( 'This website uses LocalStorage to save the setting when Dark Mode support is turned on or off.<br> LocalStorage is necessary for the setting to work and is only used when a user clicks on the Dark Mode button.<br> No data is saved in the database or transferred.', 'twentytwentyone' ); 392 wp_add_privacy_policy_content( __( 'Twenty Twenty-One', 'twentytwentyone' ), wp_kses_post( wpautop( $content, false ) ) ); 393 } 394 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Mon May 25 08:20:05 2026 | Cross-referenced by PHPXref |