Plugin Directory


Ignore:
Timestamp:
10/13/2026 10:00:51 AM (2 weeks ago)
Author:
shiponkarmakar
Message:

Release v1.1.0

File:
1 edited

Legend:

Unmodified
Added
Removed
  • optimazz/trunk/includes/Modules/Fonts/FontsModule.php

    r3715895 r3743505  
    2121
    2222class FontsModule extends AbstractModule {
     23
     24        /**
     25         * Whether parse_css2() repaired an invalid (CSS1-style) family request on
     26         * the current page, so the rebuilt URL must be output even when nothing
     27         * else changes.
     28         *
     29         * @var bool
     30         */
     31        private static $repaired = false;
    2332
    2433        public function id() {
    … …  
    157166                        return $html;
    158167                }
     168                self::$repaired = false;
    159169
    160170                $links    = array(); // Tags we will merge (in document order).
    … …  
    173183                        }
    174184                        $query  = (string) wp_parse_url( html_entity_decode( $m[2], ENT_QUOTES ), PHP_URL_QUERY ); // decode first: "&" contains a "#" that would truncate the query.
     185                        $was    = self::$repaired;
    175186                        $parsed = 'css2' === strtolower( $m[3] ) ? self::parse_css2( $query ) : self::parse_css1( $query );
    176187                        if ( null === $parsed ) {
     188                                self::$repaired = $was; // This link is left as-is, so nothing was repaired.
    177189                                continue; // unsupported form — keep as-is.
    178190                        }
    … …  
    197209                }
    198210                $trim = (bool) $this->option( 'trim_weights', true );
    199                 // One link and nothing to trim — nothing to gain.
    200                 if ( 1 === count( $links ) && ! $trim ) {
     211                $disp = '' !== $display ? $display : $orig_display;
     212                // Non-blocking load only with swap / fallback. Those swap the font in
     213                // anyway; 'optional' is chosen for zero layout shift, and loading its
     214                // stylesheet late would make a cached font swap in after first paint.
     215                $async = in_array( $disp, array( 'swap', 'fallback' ), true ) && $this->option( 'async_google', true );
     216                // One link, nothing to trim, nothing repaired and no async loading —
     217                // rebuilding the URL would gain nothing (and would drop its other
     218                // attributes and parameters).
     219                if ( 1 === count( $links ) && ! $trim && ! $async && ! self::$repaired ) {
    201220                        return $html;
    202221                }
    … …  
    208227                        $params[] = 'family=' . str_replace( '%20', '+', rawurlencode( $name ) ) . self::css2_axis( $spec, $used );
    209228                }
    210                 $disp = '' !== $display ? $display : $orig_display;
    211229                if ( '' !== $disp ) {
    212230                        $params[] = 'display=' . $disp;
    213231                }
    214                 $url = 'https://fonts.googleapis.com/css2?' . implode( '&', $params );
    215                 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet -- rewriting existing output-buffer markup, not enqueueing.
    216                 $new = '<link rel="stylesheet" id="optimazz-google-fonts" href="' . esc_url( $url ) . '" media="all">';
     232                $url  = esc_url( 'https://fonts.googleapis.com/css2?' . implode( '&', $params ) );
     233                // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet -- rewriting existing output-buffer markup, not enqueueing.
     234                if ( $async ) {
     235                        // With swap/fallback the text renders in a fallback font first
     236                        // anyway, so the font stylesheet need not block the page: on
     237                        // mobile it otherwise holds back the first paint by the full round
     238                        // trip to Google. Preload it, apply it when loaded, and keep a
     239                        // <noscript> copy for visitors without JavaScript.
     240                        $new = '<link rel="preload" as="style" href="' . $url . '">'
     241                                . '<link rel="stylesheet" id="optimazz-google-fonts" href="' . $url . '" media="print" onload="this.media=\'all\'">'
     242                                . '<noscript><link rel="stylesheet" href="' . $url . '"></noscript>';
     243                } else {
     244                        $new = '<link rel="stylesheet" id="optimazz-google-fonts" href="' . $url . '" media="all">';
     245                }
     246                // phpcs:enable WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet
    217247
    218248                // Swap the first link for the merged one; remove the rest (each once).
    … …  
    252282                                        continue;
    253283                                }
    254                                 $spec = array( 'normal' => array(), 'italic' => array(), 'raw' => null );
    255                                 $vars = isset( $parts[1] ) ? explode( ',', $parts[1] ) : array( '400' );
    256                                 foreach ( $vars as $v ) {
    257                                         $v = strtolower( trim( $v ) );
    258                                         if ( '' === $v ) {
    259                                                 continue;
    260                                         }
    261                                         $v    = strtr( $v, array( 'regular' => '400', 'bold' => '700' ) );
    262                                         $ital = (bool) preg_match( '/(italic|i)$/', $v );
    263                                         $w    = (int) preg_replace( '/\D/', '', $v );
    264                                         $w    = $w ? $w : 400; // bare "italic".
    265                                         if ( $w < 100 || $w > 900 ) {
    266                                                 continue;
    267                                         }
    268                                         $spec[ $ital ? 'italic' : 'normal' ][ $w ] = 1;
    269                                 }
    270                                 if ( empty( $spec['normal'] ) && empty( $spec['italic'] ) ) {
    271                                         $spec['normal'][400] = 1;
    272                                 }
    273                                 $out[ $name ] = $spec;
     284                                $out[ $name ] = self::parse_variants( isset( $parts[1] ) ? $parts[1] : '400' );
    274285                        }
    275286                }
    276287                return $out ? $out : null;
     288        }
     289
     290        /**
     291         * Parse a CSS1-style variant list ("400,700i,bold,italic") into a spec.
     292         *
     293         * @param string $list Comma-separated variants.
     294         * @return array{normal:array,italic:array,raw:null}
     295         */
     296        private static function parse_variants( $list ) {
     297                $spec = array( 'normal' => array(), 'italic' => array(), 'raw' => null );
     298                foreach ( explode( ',', $list ) as $v ) {
     299                        $v = strtolower( trim( $v ) );
     300                        if ( '' === $v ) {
     301                                continue;
     302                        }
     303                        $v    = strtr( $v, array( 'regular' => '400', 'bold' => '700' ) );
     304                        $ital = (bool) preg_match( '/(italic|i)$/', $v );
     305                        $w    = (int) preg_replace( '/\D/', '', $v );
     306                        $w    = $w ? $w : 400; // bare "italic".
     307                        if ( $w < 100 || $w > 900 ) {
     308                                continue;
     309                        }
     310                        $spec[ $ital ? 'italic' : 'normal' ][ $w ] = 1;
     311                }
     312                if ( empty( $spec['normal'] ) && empty( $spec['italic'] ) ) {
     313                        $spec['normal'][400] = 1;
     314                }
     315                return $spec;
    277316        }
    278317
    … …  
    314353                                        $spec['normal'][ (int) $w ] = 1;
    315354                                }
     355                        } elseif ( preg_match( '/^(?:w?\d{3}i?|regular|bold|italic|bolditalic|\d{3}italic)(?:,(?:w?\d{3}i?|regular|bold|italic|bolditalic|\d{3}italic))*$/i', trim( $parts[1] ) ) ) {
     356                                // Old CSS1-style weights ("400,700", or the "w400,700" some themes
     357                                // print) sent to the CSS2 API. Google rejects these with HTTP 400, so
     358                                // the font never loads while the broken stylesheet still blocks
     359                                // rendering. Read them the CSS1 way so a valid request is built.
     360                                $spec           = self::parse_variants( str_ireplace( 'w', '', $parts[1] ) );
     361                                self::$repaired = true;
    316362                        } else {
    317363                                $spec['raw'] = $parts[1]; // variable ranges / other axes — keep verbatim.
Note: See TracChangeset for help on using the changeset viewer.