* Twenty Twenty functions and definitions
* @link https://developer.wordpress.org/themes/basics/theme-functions/
* @subpackage Twenty_Twenty
* @since Twenty Twenty 1.0
* Enqueue Block Editor Assets
* Enqueue Classic Editor Styles
* Sets up theme defaults and registers support for various WordPress features.
* Note that this function is hooked into the after_setup_theme hook, which
* runs before the init hook. The init hook is too late for some features, such
* as indicating support for post thumbnails.
function twentytwenty_theme_support() {
// Add default posts and comments RSS feed links to head.
add_theme_support( 'automatic-feed-links' );
// Custom background color.
'default-color' => 'f5efe0',
if ( ! isset( $content_width ) ) {
* Enable support for Post Thumbnails on posts and pages.
* @link https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/
add_theme_support( 'post-thumbnails' );
// Set post thumbnail size.
set_post_thumbnail_size( 1200, 9999 );
// Add custom image size used in Cover Template.
add_image_size( 'twentytwenty-fullscreen', 1980, 9999 );
// If the retina setting is active, double the recommended width and height.
if ( get_theme_mod( 'retina_logo', false ) ) {
$logo_width = floor( $logo_width * 2 );
$logo_height = floor( $logo_height * 2 );
'height' => $logo_height,
* Let WordPress manage the document title.
* By adding theme support, we declare that this theme does not use a
* hard-coded <title> tag in the document head, and expect WordPress to
add_theme_support( 'title-tag' );
* Switch default core markup for search form, comment form, and comments
* Make theme available for translation.
* Translations can be filed in the /languages/ directory.
* If you're building a theme based on Twenty Twenty, use a find and replace
* to change 'twentytwenty' to the name of your theme in all the template files.
load_theme_textdomain( 'twentytwenty' );
// Add support for full and wide align images.
add_theme_support( 'align-wide' );
// Add support for responsive embeds.
add_theme_support( 'responsive-embeds' );
* Adds starter content to highlight the theme on fresh sites.
* This is done conditionally to avoid loading the starter content on every
* page load, as it is a one-off operation only needed once in the customizer.
if ( is_customize_preview() ) {
require get_template_directory() . '/inc/starter-content.php';
add_theme_support( 'starter-content', twentytwenty_get_starter_content() );
// Add theme support for selective refresh for widgets.
add_theme_support( 'customize-selective-refresh-widgets' );
* Adds `async` and `defer` support for scripts registered or enqueued
$loader = new TwentyTwenty_Script_Loader();
add_filter( 'script_loader_tag', array( $loader, 'filter_script_loader_tag' ), 10, 2 );
add_action( 'after_setup_theme', 'twentytwenty_theme_support' );
* Include required files.
require get_template_directory() . '/inc/template-tags.php';
require get_template_directory() . '/classes/class-twentytwenty-svg-icons.php';
require get_template_directory() . '/inc/svg-icons.php';
// Handle Customizer settings.
require get_template_directory() . '/classes/class-twentytwenty-customize.php';
// Require Separator Control class.
require get_template_directory() . '/classes/class-twentytwenty-separator-control.php';
// Custom comment walker.
require get_template_directory() . '/classes/class-twentytwenty-walker-comment.php';
require get_template_directory() . '/classes/class-twentytwenty-walker-page.php';
// Custom script loader class.
require get_template_directory() . '/classes/class-twentytwenty-script-loader.php';
// Non-latin language handling.
require get_template_directory() . '/classes/class-twentytwenty-non-latin-languages.php';
require get_template_directory() . '/inc/custom-css.php';
require get_template_directory() . '/inc/block-patterns.php';
* Register and Enqueue Styles.
function twentytwenty_register_styles() {
$theme_version = wp_get_theme()->get( 'Version' );
wp_enqueue_style( 'twentytwenty-style', get_stylesheet_uri(), array(), $theme_version );
wp_style_add_data( 'twentytwenty-style', 'rtl', 'replace' );
// Add output of Customizer settings as inline style.
wp_add_inline_style( 'twentytwenty-style', twentytwenty_get_customizer_css( 'front-end' ) );
wp_enqueue_style( 'twentytwenty-print-style', get_template_directory_uri() . '/print.css', null, $theme_version, 'print' );
add_action( 'wp_enqueue_scripts', 'twentytwenty_register_styles' );
* Register and Enqueue Scripts.
function twentytwenty_register_scripts() {
$theme_version = wp_get_theme()->get( 'Version' );
if ( ( ! is_admin() ) && is_singular() && comments_open() && get_option( 'thread_comments' ) ) {
wp_enqueue_script( 'comment-reply' );
wp_enqueue_script( 'twentytwenty-js', get_template_directory_uri() . '/assets/js/index.js', array(), $theme_version, false );
wp_script_add_data( 'twentytwenty-js', 'async', true );
add_action( 'wp_enqueue_scripts', 'twentytwenty_register_scripts' );
* Fix skip link focus in IE11.
* This does not enqueue the script because it is tiny and because it is only for IE11,
* thus it does not warrant having an entire dedicated blocking script being loaded.
* @link https://git.io/vWdr2
function twentytwenty_skip_link_focus_fix() {
// The following is minified via `terser --compress --mangle -- assets/js/skip-link-focus-fix.js`.
/(trident|msie)/i.test(navigator.userAgent)&&document.getElementById&&window.addEventListener&&window.addEventListener("hashchange",function(){var t,e=location.hash.substring(1);/^[A-z0-9_-]+$/.test(e)&&(t=document.getElementById(e))&&(/^(?:a|select|input|button|textarea)$/i.test(t.tagName)||(t.tabIndex=-1),t.focus())},!1);
add_action( 'wp_print_footer_scripts', 'twentytwenty_skip_link_focus_fix' );
/** Enqueue non-latin language styles
* @since Twenty Twenty 1.0
function twentytwenty_non_latin_languages() {
$custom_css = TwentyTwenty_Non_Latin_Languages::get_non_latin_css( 'front-end' );
wp_add_inline_style( 'twentytwenty-style', $custom_css );
add_action( 'wp_enqueue_scripts', 'twentytwenty_non_latin_languages' );
* Register navigation menus uses wp_nav_menu in five places.
function twentytwenty_menus() {
'primary' => __( 'Desktop Horizontal Menu', 'twentytwenty' ),
'expanded' => __( 'Desktop Expanded Menu', 'twentytwenty' ),
'mobile' => __( 'Mobile Menu', 'twentytwenty' ),
'footer' => __( 'Footer Menu', 'twentytwenty' ),
'social' => __( 'Social Menu', 'twentytwenty' ),
register_nav_menus( $locations );
add_action( 'init', 'twentytwenty_menus' );
* Get the information about the logo.
* @param string $html The HTML output from get_custom_logo (core function).
function twentytwenty_get_custom_logo( $html ) {
$logo_id = get_theme_mod( 'custom_logo' );
$logo = wp_get_attachment_image_src( $logo_id, 'full' );
$logo_width = esc_attr( $logo[1] );
$logo_height = esc_attr( $logo[2] );
// If the retina logo setting is active, reduce the width/height by half.
if ( get_theme_mod( 'retina_logo', false ) ) {
$logo_width = floor( $logo_width / 2 );
$logo_height = floor( $logo_height / 2 );
"width=\"{$logo_width}\"",
"height=\"{$logo_height}\"",
// Add a style attribute with the height, or append the height to the style attribute if the style attribute already exists.
if ( strpos( $html, ' style=' ) === false ) {
$replace[] = "style=\"height: {$logo_height}px;\" src=";
$search[] = '/(style="[^"]*)/';
$replace[] = "$1 height: {$logo_height}px;";
$html = preg_replace( $search, $replace, $html );
add_filter( 'get_custom_logo', 'twentytwenty_get_custom_logo' );
if ( ! function_exists( 'wp_body_open' ) ) {
* Shim for wp_body_open, ensuring backward compatibility with versions of WordPress older than 5.2.
function wp_body_open() {
do_action( 'wp_body_open' );
* Include a skip to content link at the top of the page so that users can bypass the menu.
function twentytwenty_skip_link() {
echo '<a class="skip-link screen-reader-text" href="#site-content">' . __( 'Skip to the content', 'twentytwenty' ) . '</a>';
add_action( 'wp_body_open', 'twentytwenty_skip_link', 5 );
* @link https://developer.wordpress.org/themes/functionality/sidebars/#registering-a-sidebar
function twentytwenty_sidebar_registration() {
// Arguments used in all register_sidebar() calls.
'before_title' => '<h2 class="widget-title subheading heading-size-3">',
'after_title' => '</h2>',
'before_widget' => '<div class="widget %2$s"><div class="widget-content">',
'after_widget' => '</div></div>',
'name' => __( 'Footer #1', 'twentytwenty' ),
'description' => __( 'Widgets in this area will be displayed in the first column in the footer.', 'twentytwenty' ),
'name' => __( 'Footer #2', 'twentytwenty' ),
'description' => __( 'Widgets in this area will be displayed in the second column in the footer.', 'twentytwenty' ),
add_action( 'widgets_init', 'twentytwenty_sidebar_registration' );
* Enqueue supplemental block editor styles.
function twentytwenty_block_editor_styles() {
// Enqueue the editor styles.
wp_enqueue_style( 'twentytwenty-block-editor-styles', get_theme_file_uri( '/assets/css/editor-style-block.css' ), array(), wp_get_theme()->get( 'Version' ), 'all' );
wp_style_add_data( 'twentytwenty-block-editor-styles', 'rtl', 'replace' );
// Add inline style from the Customizer.
wp_add_inline_style( 'twentytwenty-block-editor-styles', twentytwenty_get_customizer_css( 'block-editor' ) );
// Add inline style for non-latin fonts.
wp_add_inline_style( 'twentytwenty-block-editor-styles', TwentyTwenty_Non_Latin_Languages::get_non_latin_css( 'block-editor' ) );
// Enqueue the editor script.
wp_enqueue_script( 'twentytwenty-block-editor-script', get_theme_file_uri( '/assets/js/editor-script-block.js' ), array( 'wp-blocks', 'wp-dom' ), wp_get_theme()->get( 'Version' ), true );
add_action( 'enqueue_block_editor_assets', 'twentytwenty_block_editor_styles', 1, 1 );
* Enqueue classic editor styles.
function twentytwenty_classic_editor_styles() {
$classic_editor_styles = array(
'/assets/css/editor-style-classic.css',
add_editor_style( $classic_editor_styles );
add_action( 'init', 'twentytwenty_classic_editor_styles' );
* Output Customizer settings in the classic editor.
* Adds styles to the head of the TinyMCE iframe. Kudos to @Otto42 for the original solution.
* @param array $mce_init TinyMCE styles.
* @return array TinyMCE styles.
function twentytwenty_add_classic_editor_customizer_styles( $mce_init ) {
$styles = twentytwenty_get_customizer_css( 'classic-editor' );
if ( ! isset( $mce_init['content_style'] ) ) {
$mce_init['content_style'] = $styles . ' ';
$mce_init['content_style'] .= ' ' . $styles . ' ';
add_filter( 'tiny_mce_before_init', 'twentytwenty_add_classic_editor_customizer_styles' );
* Output non-latin font styles in the classic editor.
* Adds styles to the head of the TinyMCE iframe. Kudos to @Otto42 for the original solution.
* @param array $mce_init TinyMCE styles.
* @return array TinyMCE styles.
function twentytwenty_add_classic_editor_non_latin_styles( $mce_init ) {
$styles = TwentyTwenty_Non_Latin_Languages::get_non_latin_css( 'classic-editor' );
// Return if there are no styles to add.
if ( ! isset( $mce_init['content_style'] ) ) {
$mce_init['content_style'] = $styles . ' ';
$mce_init['content_style'] .= ' ' . $styles . ' ';
add_filter( 'tiny_mce_before_init', 'twentytwenty_add_classic_editor_non_latin_styles' );
* Add custom colors and font sizes to the block editor.
function twentytwenty_block_editor_settings() {
$editor_color_palette = array(
'name' => __( 'Accent Color', 'twentytwenty' ),
'color' => twentytwenty_get_color_for_area( 'content', 'accent' ),
'name' => _x( 'Primary', 'color', 'twentytwenty' ),
'color' => twentytwenty_get_color_for_area( 'content', 'text' ),
'name' => _x( 'Secondary', 'color', 'twentytwenty' ),
'color' => twentytwenty_get_color_for_area( 'content', 'secondary' ),