33 | -------------------------------------------------------------------------------- /assets/js/customize.js: -------------------------------------------------------------------------------- 1 | /* global twentytwentyoneGetHexLum */ 2 | 3 | ( function() { 4 | // Wait until the customizer has finished loading. 5 | wp.customize.bind( 'ready', function() { 6 | // Hide the "respect_user_color_preference" setting if the background-color is dark. 7 | if ( 127 > twentytwentyoneGetHexLum( wp.customize( 'background_color' ).get() ) ) { 8 | wp.customize.control( 'respect_user_color_preference' ).deactivate(); 9 | wp.customize.control( 'respect_user_color_preference_notice' ).deactivate(); 10 | } 11 | 12 | // Handle changes to the background-color. 13 | wp.customize( 'background_color', function( setting ) { 14 | setting.bind( function( value ) { 15 | if ( 127 > twentytwentyoneGetHexLum( value ) ) { 16 | wp.customize.control( 'respect_user_color_preference' ).deactivate(); 17 | wp.customize.control( 'respect_user_color_preference_notice' ).activate(); 18 | } else { 19 | wp.customize.control( 'respect_user_color_preference' ).activate(); 20 | wp.customize.control( 'respect_user_color_preference_notice' ).deactivate(); 21 | } 22 | } ); 23 | } ); 24 | } ); 25 | }() ); 26 | -------------------------------------------------------------------------------- /archive.php: -------------------------------------------------------------------------------- 1 | 16 | 17 | 18 | 19 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /assets/js/customize-helpers.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Get luminance from a HEX color. 3 | * 4 | * @param {string} hex - The hex color. 5 | * 6 | * @return {number} - Returns the luminance, number between 0 and 255. 7 | */ 8 | function twentytwentyoneGetHexLum( hex ) { // eslint-disable-line no-unused-vars 9 | var rgb = twentytwentyoneGetRgbFromHex( hex ); 10 | return Math.round( ( 0.2126 * rgb.r ) + ( 0.7152 * rgb.g ) + ( 0.0722 * rgb.b ) ); 11 | } 12 | 13 | /** 14 | * Get RGB from HEX. 15 | * 16 | * @param {string} hex - The hex color. 17 | * 18 | * @return {Object} - Returns an object {r, g, b} 19 | */ 20 | function twentytwentyoneGetRgbFromHex( hex ) { 21 | var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i, 22 | result; 23 | 24 | // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF"). 25 | hex = hex.replace( shorthandRegex, function( m, r, g, b ) { 26 | return r.toString() + r.toString() + g.toString() + g.toString() + b.toString() + b.toString(); 27 | } ); 28 | 29 | result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec( hex ); 30 | return result ? { 31 | r: parseInt( result[1], 16 ), 32 | g: parseInt( result[2], 16 ), 33 | b: parseInt( result[3], 16 ) 34 | } : null; 35 | } 36 | -------------------------------------------------------------------------------- /template-parts/post/author-bio.php: -------------------------------------------------------------------------------- 1 | 11 | 12 |
13 | 14 |
15 |

16 |

17 | ' . esc_html__( 'View all of %2$s\'s posts.', 'twentytwentyone' ) . '', 21 | esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ), 22 | get_the_author() 23 | ); 24 | ?> 25 |
26 |
27 | 28 | -------------------------------------------------------------------------------- /assets/js/polyfills.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File polyfills.js. 3 | * 4 | * Polyfills for IE11. 5 | */ 6 | 7 | /** 8 | * Polyfill for Element.closest() because we need to support IE11. 9 | * 10 | * @see https://developer.mozilla.org/en-US/docs/Web/API/Element/closest 11 | */ 12 | if ( ! Element.prototype.matches ) { 13 | Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; 14 | } 15 | 16 | if ( ! Element.prototype.closest ) { 17 | Element.prototype.closest = function( s ) { 18 | var el = this; 19 | do { 20 | if ( Element.prototype.matches.call( el, s ) ) { 21 | return el; 22 | } 23 | el = el.parentElement || el.parentNode; 24 | } while ( el !== null && el.nodeType === 1 ); 25 | return null; 26 | }; 27 | } 28 | 29 | /** 30 | * Polyfill for NodeList.foreach() because we need to support IE11. 31 | * 32 | * @see https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach 33 | */ 34 | if ( window.NodeList && ! NodeList.prototype.forEach ) { 35 | NodeList.prototype.forEach = function( callback, thisArg ) { 36 | var i; 37 | thisArg = thisArg || window; 38 | for ( i = 0; i < this.length; i++ ) { 39 | callback.call( thisArg, this[i], i, this ); 40 | } 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /classes/class-twenty-twenty-one-customize-notice-control.php: -------------------------------------------------------------------------------- 1 | 40 |
41 |

42 |

43 | 44 |

45 |
46 | elements, depending on their width & height props. 9 | * 10 | * @since 1.0.0 11 | * 12 | * @return {void} 13 | */ 14 | function twentytwentyoneResponsiveEmbeds() { 15 | var proportion, parentWidth; 16 | 17 | // Loop iframe elements. 18 | document.querySelectorAll( 'iframe' ).forEach( function( iframe ) { 19 | // Only continue if the iframe has a width & height defined. 20 | if ( iframe.width && iframe.height ) { 21 | // Calculate the proportion/ratio based on the width & height. 22 | proportion = parseFloat( iframe.width ) / parseFloat( iframe.height ); 23 | // Get the parent element's width. 24 | parentWidth = parseFloat( window.getComputedStyle( iframe.parentElement, null ).width.replace( 'px', '' ) ); 25 | // Set the max-width & height. 26 | iframe.style.maxWidth = '100%'; 27 | iframe.style.maxHeight = Math.round( parentWidth / proportion ).toString() + 'px'; 28 | } 29 | } ); 30 | } 31 | 32 | // Run on initial load. 33 | twentytwentyoneResponsiveEmbeds(); 34 | 35 | // Run on resize. 36 | window.onresize = twentytwentyoneResponsiveEmbeds; 37 | -------------------------------------------------------------------------------- /template-parts/content/content-single.php: -------------------------------------------------------------------------------- 1 | 13 | 14 |
> 15 | 16 |
17 | ', '' ); ?> 18 | 19 |
20 | 21 |
22 | '', 29 | /* translators: %: page number. */ 30 | 'pagelink' => esc_html__( 'Page %', 'twentytwentyone' ), 31 | ) 32 | ); 33 | ?> 34 |
35 | 36 |
37 | 38 |
39 | 40 | 41 | 42 | 43 | 44 |
45 | -------------------------------------------------------------------------------- /inc/custom-css.php: -------------------------------------------------------------------------------- 1 | tags and can only be interpreted as CSS on the browser. 37 | * Using wp_strip_all_tags() here is sufficient escaping to avoid 38 | * malicious attempts to close and open a '; 391 | } 392 | 393 | /** 394 | * Adds information to the privacy policy. 395 | * 396 | * @access public 397 | * 398 | * @since 1.0.0 399 | * 400 | * @return void 401 | */ 402 | public function add_privacy_policy_content() { 403 | if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { 404 | return; 405 | } 406 | $content = '

' . __( 'Twenty Twenty-One uses LocalStorage when Dark Mode support is enabled.', 'twentytwentyone' ) . '

' 407 | . '' . __( 'Suggested text:', 'twentytwentyone' ) . ' ' 408 | . __( 'This website uses LocalStorage to save the setting when Dark Mode support is turned on or off.
LocalStorage is necessary for the setting to work and is only used when a user clicks on the Dark Mode button.
No data is saved in the database or transferred.', 'twentytwentyone' ); 409 | wp_add_privacy_policy_content( 'Twenty Twenty-One', wp_kses_post( wpautop( $content, false ) ) ); 410 | } 411 | 412 | } 413 | -------------------------------------------------------------------------------- /inc/template-functions.php: -------------------------------------------------------------------------------- 1 | '; 67 | } 68 | } 69 | add_action( 'wp_head', 'twenty_twenty_one_pingback_header' ); 70 | 71 | /** 72 | * Remove the `no-js` class from body if JS is supported. 73 | * 74 | * @since 1.0.0 75 | * 76 | * @return void 77 | */ 78 | function twenty_twenty_one_supports_js() { 79 | echo ''; 80 | } 81 | add_action( 'wp_footer', 'twenty_twenty_one_supports_js' ); 82 | 83 | /** 84 | * Changes comment form default fields. 85 | * 86 | * @since 1.0.0 87 | * 88 | * @param array $defaults The form defaults. 89 | * 90 | * @return array 91 | */ 92 | function twenty_twenty_one_comment_form_defaults( $defaults ) { 93 | 94 | // Adjust height of comment form. 95 | $defaults['comment_field'] = preg_replace( '/rows="\d+"/', 'rows="5"', $defaults['comment_field'] ); 96 | 97 | return $defaults; 98 | } 99 | add_filter( 'comment_form_defaults', 'twenty_twenty_one_comment_form_defaults' ); 100 | 101 | /** 102 | * Determines if post thumbnail can be displayed. 103 | * 104 | * @since 1.0.0 105 | * 106 | * @return bool 107 | */ 108 | function twenty_twenty_one_can_show_post_thumbnail() { 109 | return apply_filters( 110 | 'twenty_twenty_one_can_show_post_thumbnail', 111 | ! post_password_required() && ! is_attachment() && has_post_thumbnail() 112 | ); 113 | } 114 | 115 | /** 116 | * Returns the size for avatars used in the theme. 117 | * 118 | * @since 1.0.0 119 | * 120 | * @return int 121 | */ 122 | function twenty_twenty_one_get_avatar_size() { 123 | return 60; 124 | } 125 | 126 | /** 127 | * Creates continue reading text 128 | */ 129 | function twenty_twenty_one_continue_reading_text() { 130 | $continue_reading = sprintf( 131 | /* translators: %s: Name of current post. */ 132 | esc_html__( 'Continue reading %s', 'twentytwentyone' ), 133 | the_title( '', '', false ) 134 | ); 135 | 136 | return $continue_reading; 137 | } 138 | 139 | /** 140 | * Create the continue reading link for excerpt. 141 | */ 142 | function twenty_twenty_one_continue_reading_link_excerpt() { 143 | if ( ! is_admin() ) { 144 | return '… ' . twenty_twenty_one_continue_reading_text() . ''; 145 | } 146 | } 147 | 148 | // Filter the excerpt more link. 149 | add_filter( 'excerpt_more', 'twenty_twenty_one_continue_reading_link_excerpt' ); 150 | 151 | /** 152 | * Create the continue reading link. 153 | */ 154 | function twenty_twenty_one_continue_reading_link() { 155 | if ( ! is_admin() ) { 156 | return ''; 157 | } 158 | } 159 | 160 | // Filter the excerpt more link. 161 | add_filter( 'the_content_more_link', 'twenty_twenty_one_continue_reading_link' ); 162 | 163 | if ( ! function_exists( 'twenty_twenty_one_post_title' ) ) { 164 | /** 165 | * Add a title to posts and pages that are missing titles. 166 | * 167 | * @since 1.0.0 168 | * 169 | * @param string $title The title. 170 | * 171 | * @return string 172 | */ 173 | function twenty_twenty_one_post_title( $title ) { 174 | return '' === $title ? esc_html_x( 'Untitled', 'Added to posts and pages that are missing titles', 'twentytwentyone' ) : $title; 175 | } 176 | } 177 | add_filter( 'the_title', 'twenty_twenty_one_post_title' ); 178 | 179 | /** 180 | * Gets the SVG code for a given icon. 181 | * 182 | * @since 1.0.0 183 | * 184 | * @param string $group The icon group. 185 | * @param string $icon The icon. 186 | * @param int $size The icon size in pixels. 187 | * 188 | * @return string 189 | */ 190 | function twenty_twenty_one_get_icon_svg( $group, $icon, $size = 24 ) { 191 | return Twenty_Twenty_One_SVG_Icons::get_svg( $group, $icon, $size ); 192 | } 193 | 194 | /** 195 | * Changes the default navigation arrows to svg icons 196 | * 197 | * @param string $calendar_output The generated HTML of the calendar. 198 | * 199 | * @return string 200 | */ 201 | function twenty_twenty_one_change_calendar_nav_arrows( $calendar_output ) { 202 | $calendar_output = str_replace( '« ', is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ), $calendar_output ); 203 | $calendar_output = str_replace( ' »', is_rtl() ? twenty_twenty_one_get_icon_svg( 'ui', 'arrow_left' ) : twenty_twenty_one_get_icon_svg( 'ui', 'arrow_right' ), $calendar_output ); 204 | return $calendar_output; 205 | } 206 | add_filter( 'get_calendar', 'twenty_twenty_one_change_calendar_nav_arrows' ); 207 | 208 | /** 209 | * Get custom CSS. 210 | * 211 | * Return CSS for non-latin language, if available, or null 212 | * 213 | * @param string $type Whether to return CSS for the "front-end", "block-editor" or "classic-editor". 214 | * 215 | * @return string 216 | */ 217 | function twenty_twenty_one_get_non_latin_css( $type = 'front-end' ) { 218 | 219 | // Fetch site locale. 220 | $locale = get_bloginfo( 'language' ); 221 | 222 | // Define fallback fonts for non-latin languages. 223 | $font_family = apply_filters( 224 | 'twenty_twenty_one_get_localized_font_family_types', 225 | array( 226 | 227 | // Arabic. 228 | 'ar' => array( 'Tahoma', 'Arial', 'sans-serif' ), 229 | 'ary' => array( 'Tahoma', 'Arial', 'sans-serif' ), 230 | 'azb' => array( 'Tahoma', 'Arial', 'sans-serif' ), 231 | 'ckb' => array( 'Tahoma', 'Arial', 'sans-serif' ), 232 | 'fa-IR' => array( 'Tahoma', 'Arial', 'sans-serif' ), 233 | 'haz' => array( 'Tahoma', 'Arial', 'sans-serif' ), 234 | 'ps' => array( 'Tahoma', 'Arial', 'sans-serif' ), 235 | 236 | // Chinese Simplified (China) - Noto Sans SC. 237 | 'zh-CN' => array( '\'PingFang SC\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ), 238 | 239 | // Chinese Traditional (Taiwan) - Noto Sans TC. 240 | 'zh-TW' => array( '\'PingFang TC\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ), 241 | 242 | // Chinese (Hong Kong) - Noto Sans HK. 243 | 'zh-HK' => array( '\'PingFang HK\'', '\'Helvetica Neue\'', '\'Microsoft YaHei New\'', '\'STHeiti Light\'', 'sans-serif' ), 244 | 245 | // Cyrillic. 246 | 'bel' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 247 | 'bg-BG' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 248 | 'kk' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 249 | 'mk-MK' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 250 | 'mn' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 251 | 'ru-RU' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 252 | 'sah' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 253 | 'sr-RS' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 254 | 'tt-RU' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 255 | 'uk' => array( '\'Helvetica Neue\'', 'Helvetica', '\'Segoe UI\'', 'Arial', 'sans-serif' ), 256 | 257 | // Devanagari. 258 | 'bn-BD' => array( 'Arial', 'sans-serif' ), 259 | 'hi-IN' => array( 'Arial', 'sans-serif' ), 260 | 'mr' => array( 'Arial', 'sans-serif' ), 261 | 'ne-NP' => array( 'Arial', 'sans-serif' ), 262 | 263 | // Greek. 264 | 'el' => array( '\'Helvetica Neue\', Helvetica, Arial, sans-serif' ), 265 | 266 | // Gujarati. 267 | 'gu' => array( 'Arial', 'sans-serif' ), 268 | 269 | // Hebrew. 270 | 'he-IL' => array( '\'Arial Hebrew\'', 'Arial', 'sans-serif' ), 271 | 272 | // Japanese. 273 | 'ja' => array( 'sans-serif' ), 274 | 275 | // Korean. 276 | 'ko-KR' => array( '\'Apple SD Gothic Neo\'', '\'Malgun Gothic\'', '\'Nanum Gothic\'', 'Dotum', 'sans-serif' ), 277 | 278 | // Thai. 279 | 'th' => array( '\'Sukhumvit Set\'', '\'Helvetica Neue\'', 'Helvetica', 'Arial', 'sans-serif' ), 280 | 281 | // Vietnamese. 282 | 'vi' => array( '\'Libre Franklin\'', 'sans-serif' ), 283 | 284 | ) 285 | ); 286 | 287 | // Return if the selected language has no fallback fonts. 288 | if ( empty( $font_family[ $locale ] ) ) { 289 | return ''; 290 | } 291 | 292 | // Define elements to apply fallback fonts to. 293 | $elements = apply_filters( 294 | 'twenty_twenty_one_get_localized_font_family_elements', 295 | array( 296 | 'front-end' => array( 'body', 'input', 'textarea', 'button', '.button', '.faux-button', '.wp-block-button__link', '.wp-block-file__button', '.has-drop-cap:not(:focus)::first-letter', '.has-drop-cap:not(:focus)::first-letter', '.entry-content .wp-block-archives', '.entry-content .wp-block-categories', '.entry-content .wp-block-cover-image', '.entry-content .wp-block-latest-comments', '.entry-content .wp-block-latest-posts', '.entry-content .wp-block-pullquote', '.entry-content .wp-block-quote.is-large', '.entry-content .wp-block-quote.is-style-large', '.entry-content .wp-block-archives *', '.entry-content .wp-block-categories *', '.entry-content .wp-block-latest-posts *', '.entry-content .wp-block-latest-comments *', '.entry-content p', '.entry-content ol', '.entry-content ul', '.entry-content dl', '.entry-content dt', '.entry-content cite', '.entry-content figcaption', '.entry-content .wp-caption-text', '.comment-content p', '.comment-content ol', '.comment-content ul', '.comment-content dl', '.comment-content dt', '.comment-content cite', '.comment-content figcaption', '.comment-content .wp-caption-text', '.widget_text p', '.widget_text ol', '.widget_text ul', '.widget_text dl', '.widget_text dt', '.widget-content .rssSummary', '.widget-content cite', '.widget-content figcaption', '.widget-content .wp-caption-text' ), 297 | 'block-editor' => array( '.editor-styles-wrapper > *', '.editor-styles-wrapper p', '.editor-styles-wrapper ol', '.editor-styles-wrapper ul', '.editor-styles-wrapper dl', '.editor-styles-wrapper dt', '.editor-post-title__block .editor-post-title__input', '.editor-styles-wrapper .wp-block h1', '.editor-styles-wrapper .wp-block h2', '.editor-styles-wrapper .wp-block h3', '.editor-styles-wrapper .wp-block h4', '.editor-styles-wrapper .wp-block h5', '.editor-styles-wrapper .wp-block h6', '.editor-styles-wrapper .has-drop-cap:not(:focus)::first-letter', '.editor-styles-wrapper cite', '.editor-styles-wrapper figcaption', '.editor-styles-wrapper .wp-caption-text' ), 298 | 'classic-editor' => array( 'body#tinymce.wp-editor', 'body#tinymce.wp-editor p', 'body#tinymce.wp-editor ol', 'body#tinymce.wp-editor ul', 'body#tinymce.wp-editor dl', 'body#tinymce.wp-editor dt', 'body#tinymce.wp-editor figcaption', 'body#tinymce.wp-editor .wp-caption-text', 'body#tinymce.wp-editor .wp-caption-dd', 'body#tinymce.wp-editor cite', 'body#tinymce.wp-editor table' ), 299 | ) 300 | ); 301 | 302 | // Return if the specified type doesn't exist. 303 | if ( empty( $elements[ $type ] ) ) { 304 | return ''; 305 | } 306 | 307 | // Include file if function doesn't exist. 308 | if ( ! function_exists( 'twenty_twenty_one_generate_css' ) ) { 309 | require_once get_theme_file_path( 'inc/custom-css.php' ); // phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound 310 | } 311 | 312 | // Return the specified styles. 313 | return twenty_twenty_one_generate_css( // @phpstan-ignore-line. 314 | implode( ',', $elements[ $type ] ), 315 | 'font-family', 316 | implode( ',', $font_family[ $locale ] ), 317 | null, 318 | null, 319 | false 320 | ); 321 | } 322 | 323 | /** 324 | * Print the first instance of a block in the content, and then break away. 325 | * 326 | * @since 1.0.0 327 | * 328 | * @param string $block_name The full block type name, or a partial match. 329 | * Example: `core/image`, `core-embed/*`. 330 | * @param string|null $content The content to search in. Use null for get_the_content(). 331 | * @param int $instances How many instances of the block will be printed (max). Defaults to 1. 332 | * 333 | * @return bool Returns true if a block was located & printed, otherwise false. 334 | */ 335 | function twenty_twenty_one_print_first_instance_of_block( $block_name, $content = null, $instances = 1 ) { 336 | $instances_count = 0; 337 | $blocks_content = ''; 338 | 339 | if ( ! $content ) { 340 | $content = get_the_content(); 341 | } 342 | 343 | // Parse blocks in the content. 344 | $blocks = parse_blocks( $content ); 345 | 346 | // Loop blocks. 347 | foreach ( $blocks as $block ) { 348 | 349 | // Sanity check. 350 | if ( ! isset( $block['blockName'] ) ) { 351 | continue; 352 | } 353 | 354 | // Check if this the block matches the $block_name. 355 | $is_matching_block = false; 356 | 357 | // If the block ends with *, try to match the first portion. 358 | if ( '*' === $block_name[-1] ) { 359 | $is_matching_block = 0 === strpos( $block['blockName'], rtrim( $block_name, '*' ) ); 360 | } else { 361 | $is_matching_block = $block_name === $block['blockName']; 362 | } 363 | 364 | if ( $is_matching_block ) { 365 | // Increment count. 366 | $instances_count++; 367 | 368 | // Add the block HTML. 369 | $blocks_content .= render_block( $block ); 370 | 371 | // Break the loop if the $instances count was reached. 372 | if ( $instances_count >= $instances ) { 373 | break; 374 | } 375 | } 376 | } 377 | 378 | if ( $blocks_content ) { 379 | echo apply_filters( 'the_content', $blocks_content ); // phpcs:ignore WordPress.Security.EscapeOutput 380 | return true; 381 | } 382 | 383 | return false; 384 | } 385 | 386 | /** 387 | * Retrieve protected post password form content. 388 | * 389 | * @since 1.0.0 390 | * 391 | * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. 392 | * @return string HTML content for password form for password protected post. 393 | */ 394 | function twenty_twenty_one_password_form( $post = 0 ) { 395 | $post = get_post( $post ); 396 | $label = 'pwbox-' . ( empty( $post->ID ) ? wp_rand() : $post->ID ); 397 | $output = '

' . esc_html__( 'This content is password protected. Please enter a password to view.', 'twentytwentyone' ) . '

398 |
399 |
400 | '; 401 | return $output; 402 | } 403 | add_filter( 'the_password_form', 'twenty_twenty_one_password_form' ); 404 | 405 | /** 406 | * Filters the list of attachment image attributes. 407 | * 408 | * @since 1.0.0 409 | * 410 | * @param array $attr Array of attribute values for the image markup, keyed by attribute name. 411 | * See wp_get_attachment_image(). 412 | * @param WP_Post $attachment Image attachment post. 413 | * @param string|array $size Requested size. Image size or array of width and height values 414 | * (in that order). Default 'thumbnail'. 415 | * 416 | * @return array 417 | */ 418 | function twenty_twenty_one_get_attachment_image_attributes( $attr, $attachment, $size ) { 419 | 420 | if ( isset( $attr['class'] ) && false !== strpos( $attr['class'], 'custom-logo' ) ) { 421 | return $attr; 422 | } 423 | 424 | $width = false; 425 | $height = false; 426 | 427 | if ( is_array( $size ) ) { 428 | $width = (int) $size[0]; 429 | $height = (int) $size[1]; 430 | } elseif ( $attachment && is_object( $attachment ) && $attachment->ID ) { 431 | $meta = wp_get_attachment_metadata( $attachment->ID ); 432 | if ( $meta['width'] && $meta['height'] ) { 433 | $width = (int) $meta['width']; 434 | $height = (int) $meta['height']; 435 | } 436 | } 437 | 438 | if ( $width && $height ) { 439 | 440 | // Add style. 441 | $attr['style'] = isset( $attr['style'] ) ? $attr['style'] : ''; 442 | $attr['style'] = 'width:100%;height:' . round( 100 * $height / $width, 2 ) . '%;max-width:' . $width . 'px;' . $attr['style']; 443 | } 444 | 445 | return $attr; 446 | } 447 | add_filter( 'wp_get_attachment_image_attributes', 'twenty_twenty_one_get_attachment_image_attributes', 10, 3 ); 448 | -------------------------------------------------------------------------------- /inc/block-patterns.php: -------------------------------------------------------------------------------- 1 | esc_html__( 'Twenty Twenty-One', 'twentytwentyone' ) ) 21 | ); 22 | } 23 | 24 | /** 25 | * Register Block Patterns. 26 | */ 27 | if ( function_exists( 'register_block_pattern' ) ) { 28 | 29 | // Large Text. 30 | register_block_pattern( 31 | 'twentytwentyone/large-text', 32 | array( 33 | 'title' => esc_html__( 'Large text', 'twentytwentyone' ), 34 | 'categories' => array( 'twentytwentyone' ), 35 | 'viewportWidth' => 1440, 36 | 'content' => '

' . esc_html__( 'A new portfolio default theme for WordPress', 'twentytwentyone' ) . '

', 37 | ) 38 | ); 39 | 40 | // Links Area. 41 | register_block_pattern( 42 | 'twentytwentyone/links-area', 43 | array( 44 | 'title' => esc_html__( 'Links area', 'twentytwentyone' ), 45 | 'categories' => array( 'twentytwentyone' ), 46 | 'viewportWidth' => 1440, 47 | 'description' => esc_html_x( 'A huge text followed by social networks and email address links.', 'Block pattern description', 'twentytwentyone' ), 48 | 'content' => '

', 49 | ) 50 | ); 51 | 52 | // Media & Text Article Title. 53 | register_block_pattern( 54 | 'twentytwentyone/media-text-article-title', 55 | array( 56 | 'title' => esc_html__( 'Media and text article title', 'twentytwentyone' ), 57 | 'categories' => array( 'twentytwentyone' ), 58 | 'viewportWidth' => 1440, 59 | 'description' => esc_html_x( 'A Media & Text block with a big image on the left and a heading on the right. The heading is followed by a separator and a description paragraph.', 'Block pattern description', 'twentytwentyone' ), 60 | 'content' => '
' . esc_attr__( '“Playing in the Sand” by Berthe Morisot', 'twentytwentyone' ) . '

' . esc_html__( 'Playing in the Sand', 'twentytwentyone' ) . '


' . wp_kses_post( __( 'Berthe Morisot
(French, 1841-1895)', 'twentytwentyone' ) ) . '

', 61 | ) 62 | ); 63 | 64 | // Overlapping Images. 65 | register_block_pattern( 66 | 'twentytwentyone/overlapping-images', 67 | array( 68 | 'title' => esc_html__( 'Overlapping images', 'twentytwentyone' ), 69 | 'categories' => array( 'twentytwentyone' ), 70 | 'viewportWidth' => 1024, 71 | 'description' => esc_html_x( 'Three images inside an overlapping columns block.', 'Block pattern description', 'twentytwentyone' ), 72 | 'content' => '
' . esc_attr__( '“Roses Tremieres” by Berthe Morisot', 'twentytwentyone' ) . '
' . esc_attr__( '“In the Bois de Boulogne” by Berthe Morisot', 'twentytwentyone' ) . '
' . esc_attr__( '“Young Woman in Mauve” by Berthe Morisot', 'twentytwentyone' ) . '
', 73 | ) 74 | ); 75 | 76 | // Two Images Showcase. 77 | register_block_pattern( 78 | 'twentytwentyone/two-images-showcase', 79 | array( 80 | 'title' => esc_html__( 'Two images showcase', 'twentytwentyone' ), 81 | 'categories' => array( 'twentytwentyone' ), 82 | 'viewportWidth' => 1440, 83 | 'description' => esc_html_x( 'A media & text block with a big image on the left and a smaller one with bordered frame on the right.', 'Block pattern description', 'twentytwentyone' ), 84 | 'content' => '
' . esc_attr__( '“Daffodils” by Berthe Morisot', 'twentytwentyone' ) . '
' . esc_attr__( '“Self portrait” by Berthe Morisot', 'twentytwentyone' ) . '
', 85 | ) 86 | ); 87 | 88 | // Overlapping Images and Text. 89 | register_block_pattern( 90 | 'twentytwentyone/overlapping-images-and-text', 91 | array( 92 | 'title' => esc_html__( 'Overlapping images and text', 'twentytwentyone' ), 93 | 'categories' => array( 'twentytwentyone' ), 94 | 'viewportWidth' => 1440, 95 | 'description' => esc_html_x( 'An overlapping columns block with two images and a text description.', 'Block pattern description', 'twentytwentyone' ), 96 | 'content' => '
' . esc_attr__( '“The Garden at Bougival” by Berthe Morisot', 'twentytwentyone' ) . '

' . esc_html__( 'Beautiful gardens painted by Berthe Morisot in the late 1800s', 'twentytwentyone' ) . '

' . esc_attr__( '“Villa with Orange Trees, Nice” by Berthe Morisot', 'twentytwentyone' ) . '
', 97 | ) 98 | ); 99 | 100 | // Portfolio List. 101 | register_block_pattern( 102 | 'twentytwentyone/portfolio-list', 103 | array( 104 | 'title' => esc_html__( 'Portfolio list', 'twentytwentyone' ), 105 | 'categories' => array( 'twentytwentyone' ), 106 | 'description' => esc_html_x( 'A list of projects with thumbnail images.', 'Block pattern description', 'twentytwentyone' ), 107 | 'content' => '






', 108 | ) 109 | ); 110 | 111 | register_block_pattern( 112 | 'twentytwentyone/contact-information', 113 | array( 114 | 'title' => esc_html__( 'Contact information', 'twentytwentyone' ), 115 | 'categories' => array( 'twentytwentyone' ), 116 | 'description' => esc_html_x( 'A block with 3 columns that display contact information and social media links.', 'Block pattern description', 'twentytwentyone' ), 117 | 'content' => '

' . esc_html_x( 'example@example.com', 'Block pattern sample content', 'twentytwentyone' ) . '
' . esc_html_x( '123-456-7890', 'Block pattern sample content', 'twentytwentyone' ) . '

' . esc_html_x( '123 Main Street', 'Block pattern sample content', 'twentytwentyone' ) . '
' . esc_html_x( 'Cambridge, MA, 02139', 'Block pattern sample content', 'twentytwentyone' ) . '

', 118 | ) 119 | ); 120 | } 121 | -------------------------------------------------------------------------------- /functions.php: -------------------------------------------------------------------------------- 1 | tag in the document head, 44 | * WordPress will provide it for us. 45 | */ 46 | add_theme_support( 'title-tag' ); 47 | 48 | /** 49 | * Add post-formats support. 50 | */ 51 | add_theme_support( 52 | 'post-formats', 53 | array( 54 | 'link', 55 | 'aside', 56 | 'gallery', 57 | 'image', 58 | 'quote', 59 | 'status', 60 | 'video', 61 | 'audio', 62 | 'chat', 63 | ) 64 | ); 65 | 66 | /* 67 | * Enable support for Post Thumbnails on posts and pages. 68 | * 69 | * @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/ 70 | */ 71 | add_theme_support( 'post-thumbnails' ); 72 | set_post_thumbnail_size( 1568, 9999 ); 73 | 74 | register_nav_menus( 75 | array( 76 | 'primary' => esc_html__( 'Primary menu', 'twentytwentyone' ), 77 | 'footer' => __( 'Secondary menu', 'twentytwentyone' ), 78 | ) 79 | ); 80 | 81 | /* 82 | * Switch default core markup for search form, comment form, and comments 83 | * to output valid HTML5. 84 | */ 85 | add_theme_support( 86 | 'html5', 87 | array( 88 | 'comment-form', 89 | 'comment-list', 90 | 'gallery', 91 | 'caption', 92 | 'style', 93 | 'script', 94 | 'navigation-widgets', 95 | ) 96 | ); 97 | 98 | /** 99 | * Add support for core custom logo. 100 | * 101 | * @link https://codex.wordpress.org/Theme_Logo 102 | */ 103 | $logo_width = 300; 104 | $logo_height = 100; 105 | 106 | add_theme_support( 107 | 'custom-logo', 108 | array( 109 | 'height' => $logo_height, 110 | 'width' => $logo_width, 111 | 'flex-width' => true, 112 | 'flex-height' => true, 113 | 'unlink-homepage-logo' => true, 114 | ) 115 | ); 116 | 117 | // Add theme support for selective refresh for widgets. 118 | add_theme_support( 'customize-selective-refresh-widgets' ); 119 | 120 | // Add support for Block Styles. 121 | add_theme_support( 'wp-block-styles' ); 122 | 123 | // Add support for full and wide align images. 124 | add_theme_support( 'align-wide' ); 125 | 126 | // Add support for editor styles. 127 | add_theme_support( 'editor-styles' ); 128 | $background_color = get_theme_mod( 'background_color', 'D1E4DD' ); 129 | if ( 127 > Twenty_Twenty_One_Custom_Colors::get_relative_luminance_from_hex( $background_color ) ) { 130 | add_theme_support( 'dark-editor-style' ); 131 | } 132 | 133 | $editor_stylesheet_path = './assets/css/style-editor.css'; 134 | 135 | // Note, the is_IE global variable is defined by WordPress and is used 136 | // to detect if the current browser is internet explorer. 137 | global $is_IE; 138 | if ( $is_IE ) { 139 | $editor_stylesheet_path = './assets/css/ie-editor.css'; 140 | } 141 | 142 | // Enqueue editor styles. 143 | add_editor_style( $editor_stylesheet_path ); 144 | 145 | // Add custom editor font sizes. 146 | add_theme_support( 147 | 'editor-font-sizes', 148 | array( 149 | array( 150 | 'name' => esc_html__( 'Extra small', 'twentytwentyone' ), 151 | 'shortName' => esc_html_x( 'XS', 'Font size', 'twentytwentyone' ), 152 | 'size' => 16, 153 | 'slug' => 'extra-small', 154 | ), 155 | array( 156 | 'name' => esc_html__( 'Small', 'twentytwentyone' ), 157 | 'shortName' => esc_html_x( 'S', 'Font size', 'twentytwentyone' ), 158 | 'size' => 18, 159 | 'slug' => 'small', 160 | ), 161 | array( 162 | 'name' => esc_html__( 'Normal', 'twentytwentyone' ), 163 | 'shortName' => esc_html_x( 'M', 'Font size', 'twentytwentyone' ), 164 | 'size' => 20, 165 | 'slug' => 'normal', 166 | ), 167 | array( 168 | 'name' => esc_html__( 'Large', 'twentytwentyone' ), 169 | 'shortName' => esc_html_x( 'L', 'Font size', 'twentytwentyone' ), 170 | 'size' => 24, 171 | 'slug' => 'large', 172 | ), 173 | array( 174 | 'name' => esc_html__( 'Extra large', 'twentytwentyone' ), 175 | 'shortName' => esc_html_x( 'XL', 'Font size', 'twentytwentyone' ), 176 | 'size' => 40, 177 | 'slug' => 'extra-large', 178 | ), 179 | array( 180 | 'name' => esc_html__( 'Huge', 'twentytwentyone' ), 181 | 'shortName' => esc_html_x( 'XXL', 'Font size', 'twentytwentyone' ), 182 | 'size' => 96, 183 | 'slug' => 'huge', 184 | ), 185 | array( 186 | 'name' => esc_html__( 'Gigantic', 'twentytwentyone' ), 187 | 'shortName' => esc_html_x( 'XXXL', 'Font size', 'twentytwentyone' ), 188 | 'size' => 144, 189 | 'slug' => 'gigantic', 190 | ), 191 | ) 192 | ); 193 | 194 | // Custom background color. 195 | add_theme_support( 196 | 'custom-background', 197 | array( 198 | 'default-color' => 'd1e4dd', 199 | ) 200 | ); 201 | 202 | // Editor color palette. 203 | $black = '#000000'; 204 | $dark_gray = '#28303D'; 205 | $gray = '#39414D'; 206 | $green = '#D1E4DD'; 207 | $blue = '#D1DFE4'; 208 | $purple = '#D1D1E4'; 209 | $red = '#E4D1D1'; 210 | $orange = '#E4DAD1'; 211 | $yellow = '#EEEADD'; 212 | $white = '#FFFFFF'; 213 | 214 | add_theme_support( 215 | 'editor-color-palette', 216 | array( 217 | array( 218 | 'name' => esc_html__( 'Black', 'twentytwentyone' ), 219 | 'slug' => 'black', 220 | 'color' => $black, 221 | ), 222 | array( 223 | 'name' => esc_html__( 'Dark gray', 'twentytwentyone' ), 224 | 'slug' => 'dark-gray', 225 | 'color' => $dark_gray, 226 | ), 227 | array( 228 | 'name' => esc_html__( 'Gray', 'twentytwentyone' ), 229 | 'slug' => 'gray', 230 | 'color' => $gray, 231 | ), 232 | array( 233 | 'name' => esc_html__( 'Green', 'twentytwentyone' ), 234 | 'slug' => 'green', 235 | 'color' => $green, 236 | ), 237 | array( 238 | 'name' => esc_html__( 'Blue', 'twentytwentyone' ), 239 | 'slug' => 'blue', 240 | 'color' => $blue, 241 | ), 242 | array( 243 | 'name' => esc_html__( 'Purple', 'twentytwentyone' ), 244 | 'slug' => 'purple', 245 | 'color' => $purple, 246 | ), 247 | array( 248 | 'name' => esc_html__( 'Red', 'twentytwentyone' ), 249 | 'slug' => 'red', 250 | 'color' => $red, 251 | ), 252 | array( 253 | 'name' => esc_html__( 'Orange', 'twentytwentyone' ), 254 | 'slug' => 'orange', 255 | 'color' => $orange, 256 | ), 257 | array( 258 | 'name' => esc_html__( 'Yellow', 'twentytwentyone' ), 259 | 'slug' => 'yellow', 260 | 'color' => $yellow, 261 | ), 262 | array( 263 | 'name' => esc_html__( 'White', 'twentytwentyone' ), 264 | 'slug' => 'white', 265 | 'color' => $white, 266 | ), 267 | ) 268 | ); 269 | 270 | add_theme_support( 271 | 'editor-gradient-presets', 272 | array( 273 | array( 274 | 'name' => esc_html__( 'Purple to yellow', 'twentytwentyone' ), 275 | 'gradient' => 'linear-gradient(160deg, ' . $purple . ' 0%, ' . $yellow . ' 100%)', 276 | 'slug' => 'purple-to-yellow', 277 | ), 278 | array( 279 | 'name' => esc_html__( 'Yellow to purple', 'twentytwentyone' ), 280 | 'gradient' => 'linear-gradient(160deg, ' . $yellow . ' 0%, ' . $purple . ' 100%)', 281 | 'slug' => 'yellow-to-purple', 282 | ), 283 | array( 284 | 'name' => esc_html__( 'Green to yellow', 'twentytwentyone' ), 285 | 'gradient' => 'linear-gradient(160deg, ' . $green . ' 0%, ' . $yellow . ' 100%)', 286 | 'slug' => 'green-to-yellow', 287 | ), 288 | array( 289 | 'name' => esc_html__( 'Yellow to green', 'twentytwentyone' ), 290 | 'gradient' => 'linear-gradient(160deg, ' . $yellow . ' 0%, ' . $green . ' 100%)', 291 | 'slug' => 'yellow-to-green', 292 | ), 293 | array( 294 | 'name' => esc_html__( 'Red to yellow', 'twentytwentyone' ), 295 | 'gradient' => 'linear-gradient(160deg, ' . $red . ' 0%, ' . $yellow . ' 100%)', 296 | 'slug' => 'red-to-yellow', 297 | ), 298 | array( 299 | 'name' => esc_html__( 'Yellow to red', 'twentytwentyone' ), 300 | 'gradient' => 'linear-gradient(160deg, ' . $yellow . ' 0%, ' . $red . ' 100%)', 301 | 'slug' => 'yellow-to-red', 302 | ), 303 | array( 304 | 'name' => esc_html__( 'Purple to red', 'twentytwentyone' ), 305 | 'gradient' => 'linear-gradient(160deg, ' . $purple . ' 0%, ' . $red . ' 100%)', 306 | 'slug' => 'purple-to-red', 307 | ), 308 | array( 309 | 'name' => esc_html__( 'Red to purple', 'twentytwentyone' ), 310 | 'gradient' => 'linear-gradient(160deg, ' . $red . ' 0%, ' . $purple . ' 100%)', 311 | 'slug' => 'red-to-purple', 312 | ), 313 | ) 314 | ); 315 | 316 | /* 317 | * Adds starter content to highlight the theme on fresh sites. 318 | * This is done conditionally to avoid loading the starter content on every 319 | * page load, as it is a one-off operation only needed once in the customizer. 320 | */ 321 | if ( is_customize_preview() ) { 322 | require get_template_directory() . '/inc/starter-content.php'; 323 | add_theme_support( 'starter-content', twenty_twenty_one_get_starter_content() ); 324 | } 325 | 326 | // Add support for responsive embedded content. 327 | add_theme_support( 'responsive-embeds' ); 328 | 329 | // Add support for custom line height controls. 330 | add_theme_support( 'custom-line-height' ); 331 | 332 | // Add support for experimental link color control. 333 | add_theme_support( 'experimental-link-color' ); 334 | 335 | // Add support for experimental cover block spacing. 336 | add_theme_support( 'custom-spacing' ); 337 | 338 | // Add support for custom units. 339 | // This was removed in WordPress 5.6 but is still required to properly support WP 5.5. 340 | add_theme_support( 'custom-units' ); 341 | } 342 | } 343 | add_action( 'after_setup_theme', 'twenty_twenty_one_setup' ); 344 | 345 | /** 346 | * Register widget area. 347 | * 348 | * @since 1.0.0 349 | * 350 | * @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar 351 | * 352 | * @return void 353 | */ 354 | function twenty_twenty_one_widgets_init() { 355 | 356 | register_sidebar( 357 | array( 358 | 'name' => esc_html__( 'Footer', 'twentytwentyone' ), 359 | 'id' => 'sidebar-1', 360 | 'description' => esc_html__( 'Add widgets here to appear in your footer.', 'twentytwentyone' ), 361 | 'before_widget' => '
', 362 | 'after_widget' => '
', 363 | 'before_title' => '

', 364 | 'after_title' => '

', 365 | ) 366 | ); 367 | } 368 | add_action( 'widgets_init', 'twenty_twenty_one_widgets_init' ); 369 | 370 | /** 371 | * Set the content width in pixels, based on the theme's design and stylesheet. 372 | * 373 | * Priority 0 to make it available to lower priority callbacks. 374 | * 375 | * @since 1.0.0 376 | * 377 | * @global int $content_width Content width. 378 | * 379 | * @return void 380 | */ 381 | function twenty_twenty_one_content_width() { 382 | // This variable is intended to be overruled from themes. 383 | // Open WPCS issue: {@link https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/issues/1043}. 384 | // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound 385 | $GLOBALS['content_width'] = apply_filters( 'twenty_twenty_one_content_width', 750 ); 386 | } 387 | add_action( 'after_setup_theme', 'twenty_twenty_one_content_width', 0 ); 388 | 389 | /** 390 | * Enqueue scripts and styles. 391 | * 392 | * @since 1.0.0 393 | * 394 | * @return void 395 | */ 396 | function twenty_twenty_one_scripts() { 397 | // Note, the is_IE global variable is defined by WordPress and is used 398 | // to detect if the current browser is internet explorer. 399 | global $is_IE; 400 | if ( $is_IE ) { 401 | // If IE 11 or below, use a flattened stylesheet with static values replacing CSS Variables. 402 | wp_enqueue_style( 'twenty-twenty-one-style', get_template_directory_uri() . '/assets/css/ie.css', array(), wp_get_theme()->get( 'Version' ) ); 403 | } else { 404 | // If not IE, use the standard stylesheet. 405 | wp_enqueue_style( 'twenty-twenty-one-style', get_template_directory_uri() . '/style.css', array(), wp_get_theme()->get( 'Version' ) ); 406 | } 407 | 408 | // RTL styles. 409 | wp_style_add_data( 'twenty-twenty-one-style', 'rtl', 'replace' ); 410 | 411 | // Print styles. 412 | wp_enqueue_style( 'twenty-twenty-one-print-style', get_template_directory_uri() . '/assets/css/print.css', array(), wp_get_theme()->get( 'Version' ), 'print' ); 413 | 414 | // Threaded comment reply styles. 415 | if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) { 416 | wp_enqueue_script( 'comment-reply' ); 417 | } 418 | 419 | wp_register_script( 420 | 'twenty-twenty-one-ie11-polyfills', 421 | get_template_directory_uri() . '/assets/js/polyfills.js', 422 | array(), 423 | wp_get_theme()->get( 'Version' ), 424 | true 425 | ); 426 | 427 | // Main navigation scripts. 428 | if ( has_nav_menu( 'primary' ) ) { 429 | wp_enqueue_script( 430 | 'twenty-twenty-one-primary-navigation-script', 431 | get_template_directory_uri() . '/assets/js/primary-navigation.js', 432 | array( 'twenty-twenty-one-ie11-polyfills' ), 433 | wp_get_theme()->get( 'Version' ), 434 | true 435 | ); 436 | } 437 | 438 | // Responsive embeds script. 439 | wp_enqueue_script( 440 | 'twenty-twenty-one-responsive-embeds-script', 441 | get_template_directory_uri() . '/assets/js/responsive-embeds.js', 442 | array( 'twenty-twenty-one-ie11-polyfills' ), 443 | wp_get_theme()->get( 'Version' ), 444 | true 445 | ); 446 | } 447 | add_action( 'wp_enqueue_scripts', 'twenty_twenty_one_scripts' ); 448 | 449 | /** 450 | * Enqueue block editor script. 451 | * 452 | * @since 1.0.0 453 | * 454 | * @return void 455 | */ 456 | function twentytwentyone_block_editor_script() { 457 | 458 | wp_enqueue_script( 'twentytwentyone-editor', get_theme_file_uri( '/assets/js/editor.js' ), array( 'wp-blocks', 'wp-dom' ), wp_get_theme()->get( 'Version' ), true ); 459 | } 460 | 461 | add_action( 'enqueue_block_editor_assets', 'twentytwentyone_block_editor_script' ); 462 | 463 | /** 464 | * Fix skip link focus in IE11. 465 | * 466 | * This does not enqueue the script because it is tiny and because it is only for IE11, 467 | * thus it does not warrant having an entire dedicated blocking script being loaded. 468 | * 469 | * @link https://git.io/vWdr2 470 | */ 471 | function twenty_twenty_one_skip_link_focus_fix() { 472 | 473 | // If SCRIPT_DEBUG is defined and true, print the unminified file. 474 | if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) { 475 | echo ''; 478 | } 479 | 480 | // The following is minified via `npx terser --compress --mangle -- assets/js/skip-link-focus-fix.js`. 481 | ?> 482 | 485 | get( 'Version' ), 547 | true 548 | ); 549 | 550 | wp_enqueue_script( 551 | 'twentytwentyone-customize-preview', 552 | get_theme_file_uri( '/assets/js/customize-preview.js' ), 553 | array( 'customize-preview', 'customize-selective-refresh', 'jquery', 'twentytwentyone-customize-helpers' ), 554 | wp_get_theme()->get( 'Version' ), 555 | true 556 | ); 557 | } 558 | add_action( 'customize_preview_init', 'twentytwentyone_customize_preview_init' ); 559 | 560 | /** 561 | * Enqueue scripts for the customizer. 562 | * 563 | * @since 1.0.0 564 | * 565 | * @return void 566 | */ 567 | function twentytwentyone_customize_controls_enqueue_scripts() { 568 | 569 | wp_enqueue_script( 570 | 'twentytwentyone-customize-helpers', 571 | get_theme_file_uri( '/assets/js/customize-helpers.js' ), 572 | array(), 573 | wp_get_theme()->get( 'Version' ), 574 | true 575 | ); 576 | } 577 | add_action( 'customize_controls_enqueue_scripts', 'twentytwentyone_customize_controls_enqueue_scripts' ); 578 | 579 | /** 580 | * Calculate classes for the main element. 581 | * 582 | * @since 1.0.0 583 | * 584 | * @return void 585 | */ 586 | function twentytwentyone_the_html_classes() { 587 | $classes = apply_filters( 'twentytwentyone_html_classes', '' ); 588 | if ( ! $classes ) { 589 | return; 590 | } 591 | echo 'class="' . esc_attr( $classes ) . '"'; 592 | } 593 | 594 | /** 595 | * Add "is-IE" class to body if the user is on Internet Explorer. 596 | * 597 | * @since 1.0.0 598 | * 599 | * @return void 600 | */ 601 | function twentytwentyone_add_ie_class() { 602 | ?> 603 | 608 |