fix: Custom Fonts Preload Only One Font Weight Instead of All Variants

Hey everyone, we are developers at JDI and currently working on our own website using Bricks Builder. Recently we stucked with the same issue as these people on the forum:

We debugged Bricks parent theme, found the issue and fixed it on our side, so here is explanation and solution.

Bug Description:
When using custom fonts with multiple weights and styles (e.g., Poppins with weights 100-900 plus italic variants), the preload_custom_fonts() function only generates one <link rel="preload"> tag instead of preloading all available font variants. This results in poor performance as only one font weight is cached upfront.

Expected Behavior:
The function should preload ALL font variants for each custom font used on the page, including different weights (100, 200, 300, 400, 500, 600, 700, 800, 900) and styles (normal, italic).

Current Behavior:
Only generates preload tags for the specific font-weight/font-style combinations that are explicitly set in the current page elements, missing most font variants.

Affected Files:
/includes/custom-fonts.php - preload_custom_fonts() method

How to Fix

Step 1: Backup Your File (optional)

Make a backup of /includes/custom-fonts.php

Step 2: Locate the Function

Find the preload_custom_fonts() method (around line 300 in v2.0.1)

Step 3: Replace the Function

Replace the entire preload_custom_fonts() method with this corrected version:

/**
 * Preload custom fonts in wp_head
 *
 * Hook priority 1 to ensure it runs before other styles/scripts.
 *
 * @see https://web.dev/articles/codelab-preload-web-fonts
 * @since 2.0
 */
public function preload_custom_fonts() {
    $fonts = self::get_custom_fonts();

    if ( ! $fonts ) {
        return;
    }

    // Collect all theme style and element settings that use custom fonts
    $all_elements = array();

    // Get active theme styles
    $theme_styles = Theme_Styles::$settings_by_id;

    if ( is_array( $theme_styles ) && ! empty( $theme_styles ) ) {
        // Loop through each theme style to check for custom fonts
        foreach ( $theme_styles as $theme_style_id => $theme_style_settings ) {
            if ( is_array( $theme_style_settings ) ) {
                foreach ( $theme_style_settings as $group => $settings ) {
                    if ( is_array( $settings ) ) {
                        foreach ( $settings as $setting_key => $setting_value ) {
                            if ( ! empty( $setting_value['font-family'] ) && strpos( $setting_value['font-family'], 'custom_font_' ) === 0 ) {
                                // If the font-family is a custom font, add it to the all_elements array
                                $all_elements[] = array(
                                    'settings' => array(
                                        $setting_key => $setting_value,
                                    ),
                                );
                            }
                        }
                    }
                }
            }
        }
    }

    $header_elements  = Database::get_template_data( 'header' );
    $content_elements = Database::get_template_data( 'content' );
    $footer_elements  = Database::get_template_data( 'footer' );

    if ( is_array( $header_elements ) ) {
        $all_elements = array_merge( $all_elements, $header_elements );
    }

    if ( is_array( $content_elements ) ) {
        $all_elements = array_merge( $all_elements, $content_elements );
    }

    if ( is_array( $footer_elements ) ) {
        $all_elements = array_merge( $all_elements, $footer_elements );
    }

    $link_tags_preloaded = array();
    $preloaded_font_urls = array(); // Track already preloaded URLs to avoid duplicates

    // Get unique custom fonts used in the current page
    $used_custom_fonts = array();
    foreach ( $all_elements as $element ) {
        $element_settings = ! empty( $element['settings'] ) && is_array( $element['settings'] ) ? $element['settings'] : array();

        foreach ( $element_settings as $key => $value ) {
            $font_family = $value['font-family'] ?? '';
            if ( ! empty( $font_family ) && strpos( $font_family, 'custom_font_' ) === 0 ) {
                $used_custom_fonts[ $font_family ] = true;
            }
        }
    }

    // Preload ALL font variants for each used custom font
    foreach ( $used_custom_fonts as $font_family => $used ) {
        $custom_font = $fonts[ $font_family ] ?? null;

        if ( $custom_font && ! empty( $custom_font['fontFaces'] ) ) {
            $font_faces = $custom_font['fontFaces'];

            // Split by @font-face to get individual font-face rules
            $font_face_rules = explode( '@font-face', $font_faces );

            foreach ( $font_face_rules as $font_face_rule ) {
                if ( empty( trim( $font_face_rule ) ) ) {
                    continue;
                }

                // Extract all font URLs from this font-face rule
                preg_match_all( '/url\((.*?)\)/', $font_face_rule, $matches );
                $font_urls = $matches[1] ?? array();

                // Process all font URLs for this variant
                foreach ( $font_urls as $font_url ) {
                    // Skip if already preloaded
                    if ( in_array( $font_url, $preloaded_font_urls, true ) ) {
                        continue;
                    }

                    $preloaded_font_urls[] = $font_url;

                    // Get file format from the URL
                    $file_extension = pathinfo( $font_url, PATHINFO_EXTENSION );

                    // Add preload link tag for the font URL
                    if ( $font_url && in_array( $file_extension, array( 'woff2', 'woff', 'ttf' ), true ) ) {
                        $link_tags_preloaded[] = sprintf(
                            '<link rel="preload" href="%s" as="font" type="font/%s" crossorigin="anonymous">',
                            esc_url( $font_url ),
                            esc_attr( $file_extension )
                        );
                    }
                }
            }
        }
    }

    // Return: No custom fonts to preload
    if ( empty( $link_tags_preloaded ) ) {
        return;
    }

    // Output the preload link tags
    echo implode( "\n", $link_tags_preloaded ) . "\n";
}

Step 4: Test the Fix

  1. Clear any caching plugins
  2. Refresh your page
  3. View page source and search for <link rel="preload" tags
  4. You should now see multiple preload tags for all font weights and styles

What the Fix Does

Before: The function only preloaded fonts based on specific weight/style combinations found in page elements, missing most variants.

After: The function now:

  1. Detects which custom fonts are used on the page
  2. Processes ALL @font-face rules for each font
  3. Extracts ALL font URLs (woff2, woff, ttf)
  4. Generates preload tags for every unique font file
  5. Avoids duplicate preload tags

Result: All font variants are preloaded, improving performance and ensuring fonts are cached regardless of which weights/styles are currently displayed.

Affected Versions

  • Bricks 2.0+
  • Custom fonts with multiple weights/styles

Note: This is a core functionality issue that affects all sites using custom fonts with multiple variants. The fix ensures optimal font loading performance.