get( 'Version' ) ); } endif; add_action( 'enqueue_block_editor_assets', 'serial_editor_ui_styles' ); if ( ! function_exists( 'serial_styles' ) ) : /** * Enqueue styles. * * @since serial 1.0 * @return void */ function serial_styles() { // Register theme stylesheet. wp_register_style( 'serial-style', get_template_directory_uri() . '/style.css', array(), wp_get_theme()->get( 'Version' ) ); // Enqueue theme stylesheet. wp_enqueue_style( 'serial-style' ); // Re-send Jetpack like widget styles when OS color scheme changes. wp_add_inline_script( 'jetpack_likes_queuehandler', "window.matchMedia( '(prefers-color-scheme: dark)' ).addEventListener( 'change', function() { var masterFrame = window.frames[ 'likes-master' ]; if ( ! masterFrame ) { return; } var sdText = document.querySelector( '.sd-text-color' ); var sdLink = document.querySelector( '.sd-link-color' ); var textStyles = sdText ? getComputedStyle( sdText ) : {}; var linkStyles = sdLink ? getComputedStyle( sdLink ) : {}; // Update the cached styles in likes-master. masterFrame.postMessage( JSON.stringify( { type: 'likesMessage', data: { event: 'injectStyles', textStyles: { color: textStyles.color, fontFamily: textStyles['font-family'], fontSize: textStyles['font-size'], direction: textStyles.direction, fontWeight: textStyles['font-weight'], fontStyle: textStyles['font-style'], textDecoration: textStyles['text-decoration'], }, linkStyles: { color: linkStyles.color, fontFamily: linkStyles['font-family'], fontSize: linkStyles['font-size'], textDecoration: linkStyles['text-decoration'], fontWeight: linkStyles['font-weight'], fontStyle: linkStyles['font-style'], }, }, } ), '*' ); // Trigger a re-render of each widget so applyInjectedStyles runs with the new styles. document.querySelectorAll( 'iframe.jetpack-likes-widget' ).forEach( function( iframe ) { masterFrame.postMessage( JSON.stringify( { type: 'likesMessage', data: { event: 'loadLikeWidget', name: iframe.name, width: iframe.offsetWidth, }, } ), '*' ); } ); } );", 'after' ); } endif; add_action( 'wp_enqueue_scripts', 'serial_styles' ); if ( ! function_exists( 'serial_block_stylesheets' ) ) : /** * Enqueue custom block stylesheets * * @since serial 1.0 * @return void */ function serial_block_stylesheets() { $serial_styled_blocks = array( 'core/accordion' => 'accordion', 'core/archives' => 'archives', 'core/audio' => 'audio', 'core/button' => 'button', 'core/calendar' => 'calendar', 'core/categories' => 'categories', 'core/comment-content' => 'comment-content', 'core/comments-pagination' => 'comments-pagination', 'core/file' => 'file', 'core/latest-comments' => 'latest-comments', 'core/latest-posts' => 'latest-posts', 'core/list' => 'list', 'core/loginout' => 'loginout', 'core/navigation' => 'navigation', 'core/page-list' => 'page-list', 'core/post-author' => 'post-author', 'core/post-author-name' => 'post-author-name', 'core/post-comments-form' => 'post-comments-form', 'core/post-comments-link' => 'post-comments-link', 'core/post-date' => 'post-date', 'core/post-excerpt' => 'post-excerpt', 'core/post-featured-image' => 'post-featured-image', 'core/post-navigation-link' => 'post-navigation-link', 'core/post-terms' => 'post-terms', 'core/post-title' => 'post-title', 'core/pullquote' => 'pullquote', 'core/query-pagination-numbers' => 'query-pagination-numbers', 'core/query-pagination' => 'query-pagination', 'core/quote' => 'quote', 'core/read-more' => 'read-more', 'core/rss' => 'rss', 'core/search' => 'search', 'core/separator' => 'separator', 'core/site-title' => 'site-title', 'core/social-links' => 'social-links', 'core/table' => 'table', 'core/tag-cloud' => 'tag-cloud', 'core/table-of-contents' => 'table-of-contents', 'core/tabs' => 'tabs', 'core/term-description' => 'term-description', 'core/terms-query' => 'terms-query', 'jetpack/ai-chat' => 'jetpack-ai-chat', 'jetpack/contact-form' => 'jetpack-contact-form', 'jetpack/podcast-episode' => 'jetpack-podcast-episode', ); foreach ( $serial_styled_blocks as $block_name_with_namespace => $block_name ) { $block_style_path = get_template_directory() . '/assets/css/blocks/' . $block_name . '.css'; wp_enqueue_block_style( $block_name_with_namespace, array( 'handle' => 'serial-' . $block_name, 'src' => get_template_directory_uri() . '/assets/css/blocks/' . $block_name . '.css', 'path' => $block_style_path, 'ver' => wp_get_theme()->get( 'Version' ), ) ); } } endif; add_action( 'init', 'serial_block_stylesheets' ); if ( ! function_exists( 'serial_preload_fonts' ) ) : /** * Preloads the Inter variable font files to reduce flash of unstyled text. * * Only the default body font is preloaded. Typography variation fonts are * not preloaded since only a subset of sites use each one. * * @since serial 1.0 * @return void */ function serial_preload_fonts() { $fonts = array( 'InterVariable.woff2', 'InterVariable-Italic.woff2', ); foreach ( $fonts as $font ) { echo '' . "\n"; } } endif; add_action( 'wp_head', 'serial_preload_fonts', 1 ); if ( ! function_exists( 'serial_post_featured_image_placeholder' ) ) : /** * Renders a placeholder for the Post Featured Image block when a post has no thumbnail. * * Mirrors the editor's placeholder so card-style layouts don't collapse on * posts without a featured image. * * @since serial 1.0 * * @param string $block_content The rendered block content. * @param array $parsed_block The parsed block. * @return string Modified block content. */ function serial_post_featured_image_placeholder( $block_content, $parsed_block ) { if ( 'core/post-featured-image' !== ( $parsed_block['blockName'] ?? '' ) || ! empty( $block_content ) ) { return $block_content; } $attrs = $parsed_block['attrs'] ?? array(); $aspect = $attrs['aspectRatio'] ?? ''; if ( ! $aspect || 'auto' === $aspect ) { return $block_content; } $style = 'aspect-ratio:' . $aspect . ';'; foreach ( array( 'height', 'width' ) as $prop ) { if ( ! empty( $attrs[ $prop ] ) ) { $style .= $prop . ':' . $attrs[ $prop ] . ';'; } } $radius = $attrs['style']['border']['radius'] ?? wp_get_global_styles( array( 'blocks', 'core/post-featured-image', 'border', 'radius' ) ); if ( is_array( $radius ) ) { foreach ( $radius as $corner => $value ) { if ( $value ) { $style .= 'border-' . strtolower( preg_replace( '/[A-Z]/', '-$0', $corner ) ) . '-radius:' . $value . ';'; } } } elseif ( $radius ) { $style .= 'border-radius:' . $radius . ';'; } $classes = 'wp-block-post-featured-image is-placeholder'; if ( ! empty( $attrs['className'] ) ) { $classes .= ' ' . $attrs['className']; } $transparent = ''; $overlay = ''; $inner = '' . $overlay; if ( ! empty( $attrs['isLink'] ) ) { $inner = '' . $inner . ''; } return sprintf( '
%s
', esc_attr( $classes ), esc_attr( $style ), $inner ); } endif; add_filter( 'render_block', 'serial_post_featured_image_placeholder', 11, 2 ); if ( ! function_exists( 'serial_add_category_to_template_hierarchy' ) ) : /** * Adds a category-specific template to the single post template hierarchy. * * Prioritizes 'single-blog' template for posts in the category with the * 'blog' slug, the same category 'category-blog' applies to. A template * chosen for the post in the editor still wins. * * @since serial 1.0 * * @param array $templates List of template files to search for. * @return array Modified list of template files. */ function serial_add_category_to_template_hierarchy( $templates ) { $post = get_queried_object(); if ( ! $post instanceof WP_Post || get_page_template_slug( $post ) ) { return $templates; } $blog_category = get_category_by_slug( 'blog' ); if ( $blog_category && has_category( $blog_category->term_id, $post ) ) { array_unshift( $templates, 'single-blog' ); } return $templates; } endif; add_filter( 'single_template_hierarchy', 'serial_add_category_to_template_hierarchy' ); if ( ! function_exists( 'serial_podcast_episode_preload_metadata' ) ) : /** * Preloads audio metadata in the Podcast Episode block player. * * The block outputs preload="none", so the player shows 0:00 as the * length until playback starts. Metadata preloading shows the real * length up front, matching the core Audio block behavior. * * @since serial 1.0 * * @param string $block_content The block markup. * @return string Modified block markup. */ function serial_podcast_episode_preload_metadata( $block_content ) { return str_replace( 'preload="none"', 'preload="metadata"', $block_content ); } endif; add_filter( 'render_block_jetpack/podcast-episode', 'serial_podcast_episode_preload_metadata' ); if ( ! function_exists( 'serial_podcast_episode_critical_styles' ) ) : /** * Prints minimal Podcast Episode poster sizing in the document head. * * Critical-CSS optimizers such as Jetpack Boost defer the block's * stylesheet, so the first paint renders the poster at its injected * width/height attribute size — a flash of a huge cover image. This * head-inlined guard holds the poster at its intended size until the * full stylesheet arrives; once loaded, the block's own higher- * specificity rules take over. * * @since serial 1.0 * @return void */ function serial_podcast_episode_critical_styles() { if ( ! is_singular() || ! has_block( 'jetpack/podcast-episode' ) ) { return; } echo '' . "\n"; } endif; add_action( 'wp_head', 'serial_podcast_episode_critical_styles', 7 ); if ( ! function_exists( 'serial_read_more_listen_label' ) ) : /** * Names icon-only Read More links "Listen: {post title}". * * The theme's icon Read More styles show a play icon with no visible * text (content set to a single space). Core then names the link only * by its screen-reader span, ": {post title}", which starts with a * colon and doesn't say what the link does. An aria-label replaces * that name. Links with visible text keep core's name. * * @since serial 1.0 * * @param string $block_content Rendered block markup. * @param array $block Parsed block. * @param WP_Block $instance Block instance. * @return string Modified block markup. */ function serial_read_more_listen_label( $block_content, $block, $instance ) { if ( ! isset( $block['attrs']['content'] ) || '' !== trim( wp_strip_all_tags( $block['attrs']['content'] ) ) ) { return $block_content; } $post_id = isset( $instance->context['postId'] ) ? (int) $instance->context['postId'] : 0; $title = $post_id ? trim( wp_strip_all_tags( get_the_title( $post_id ) ) ) : ''; if ( '' === $title ) { return $block_content; } $tags = new WP_HTML_Tag_Processor( $block_content ); if ( ! $tags->next_tag( 'a' ) ) { return $block_content; } /* translators: %s: post title. */ $label = sprintf( __( 'Listen: %s', 'serial' ), html_entity_decode( $title, ENT_QUOTES, get_bloginfo( 'charset' ) ) ); $tags->set_attribute( 'aria-label', $label ); return $tags->get_updated_html(); } endif; add_filter( 'render_block_core/read-more', 'serial_read_more_listen_label', 10, 3 );