DEV Community

Josh Nederveld
Josh Nederveld

Posted on

3 2

WordPress enqueues don't support Google Fonts with more than one font-family.

The current Google Fonts stylesheet URLs syntax looks like this:

https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400;0,700;1,400;1,700&family=Montserrat:wght@700;800&display=swap

If you use more than one font-family, the "family" parameter is reused. If you're using wp_register_style and wp_enqueue_style to add this stylesheet link to your site, you'll get this:

https://fonts.googleapis.com/css2?family=Montserrat:wght@700;800&display=swap&ver=5.4.1

The code that adds the version query string parameter uses parse_str, which returns code like this:

<?php
$str = "family=Lora:ital,wght@0,400;0,700;1,400;1,700&family=Montserrat:wght@700;800&display=swap";

parse_str($str, $output);
echo $output['family'];  // Montserrat:wght@700;800
echo $output['display']; // swap

I'm not sure why add_query_arg has to deconstruct the entire query string and rebuild it in order to add another query string parameter. In my opinion, WordPress also does a bad job of giving devs the opportunity to prevent this behavior with hooks. Consider this snippet from do_item in class.wp-styles.php:

$href = $this->_css_href( $src, $ver, $handle );
....
$tag = apply_filters( 'style_loader_tag', $tag, $handle, $href, $media );

The original $src variable is never accessible through hooks after being changed into $href. Consider _css_href, which do_item calls. This is where the query string arg is added:

if ( ! empty( $ver ) ) {
    $src = add_query_arg( 'ver', $ver, $src );
}

$src = apply_filters( 'style_loader_src', $src, $handle );
return esc_url( $src );

We're given a filter, but it doesn't include the original $src, because it's been overwritten by add_query_arg. If the original variables were preserved and passed in these hooks, then we'd be able to prevent this behavior.

Another way to do it is to change the behavior of wp_parse_str. There's a good comment on php.net outlining the issue from Evan K from 12 years ago:

It bears mentioning that the parse_str builtin does NOT process a query string in the CGI standard way, when it comes to duplicate fields. If multiple fields of the same name exist in a query string, every other web processing language would read them into an array, but PHP silently overwrites them:

<?php
# silently fails to handle multiple values
parse_str('foo=1&foo=2&foo=3');

# the above produces:
$foo = array('foo' => '3');
?>

Instead, PHP uses a non-standards compliant practice of including brackets in fieldnames to achieve the same effect.

<?php
# bizarre php-specific behavior
parse_str('foo[]=1&foo[]=2&foo[]=3');

# the above produces:
$foo = array('foo' => array('1', '2', '3') );
?>

This can be confusing for anyone who's used to the CGI standard, so keep it in mind.

But of course, changing the Google Fonts URL to https://fonts.googleapis.com/css2?family[]=Lora:ital,wght@0,400;0,700;1,400;1,700&family[]=Montserrat:wght@700;800&display=swap results in a 404, so there's no easy fix there.

How to Fix

There are a few ways to fix this. I grabbed Evan's proper_parse_str function and plugged it into wp_parse_str and it worked fine for this case, but I don't know where all else wp_parse_str is used, so it makes me hesitant to propose that as a solution.

For the meantime, we can:

  1. Set $ver to null when registering and/or enqueueing the stylesheet.
  2. Enqueue fonts in separate files, rather than one.
  3. Petition WordPress to change the behavior of wp_parse_str.

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (1)

Collapse
 
jilljj profile image
Jill Johnson

Yep. I blew up my site a few times trying to find the solution we used to have with html original version.

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay