├── .gitattributes ├── LICENSE ├── README.md └── wptt-webfont-loader.php /.gitattributes: -------------------------------------------------------------------------------- 1 | .editorconfig export-ignore 2 | .gitattibutes export-ignore 3 | .gitignore export-ignore 4 | composer.json export-ignore 5 | composer.lock export-ignore 6 | phpcs.xml.dist export-ignore 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 WPTT 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Webfonts Loader 2 | 3 | Downloads webfonts (like for example Google-Fonts), and hosts them locally on a WordPress site. 4 | 5 | This improves performance (fewer requests to multiple top-level domains) and increases privacy. Since fonts get hosted locally on the site, there are no pings to a 3rd-party server to get the webfonts and therefore no tracking. 6 | 7 | ## Usage 8 | 9 | A WordPress theme will typically enqueue assets using the [`wp_enqueue_style`](https://developer.wordpress.org/reference/functions/wp_enqueue_style/) function: 10 | 11 | ```php 12 | function my_theme_enqueue_assets() { 13 | // Load the theme stylesheet. 14 | wp_enqueue_style( 15 | 'my-theme', 16 | get_stylesheet_directory_uri() . '/style.css', 17 | array(), 18 | '1.0' 19 | ); 20 | // Load the webfont. 21 | wp_enqueue_style( 22 | 'literata', 23 | 'https://fonts.googleapis.com/css2?family=Literata&display=swap', 24 | array(), 25 | '1.0' 26 | ); 27 | } 28 | add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_assets' ); 29 | ``` 30 | 31 | To locally host the webfonts, you will first need to download the [`wptt-webfont-loader.php`](https://raw.githubusercontent.com/WPTT/font-loader/master/wptt-webfont-loader.php) file from this repository and copy it in your theme. Once you do that, the above code can be converted to this: 32 | ```php 33 | function my_theme_enqueue_assets() { 34 | // Include the file. 35 | require_once get_theme_file_path( 'inc/wptt-webfont-loader.php' ); 36 | // Load the theme stylesheet. 37 | wp_enqueue_style( 38 | 'my-theme', 39 | get_stylesheet_directory_uri() . '/style.css', 40 | array(), 41 | '1.0' 42 | ); 43 | // Load the webfont. 44 | wp_enqueue_style( 45 | 'literata', 46 | wptt_get_webfont_url( 'https://fonts.googleapis.com/css2?family=Literata&display=swap' ), 47 | array(), 48 | '1.0' 49 | ); 50 | } 51 | add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_assets' ); 52 | ``` 53 | 54 | ## Available functions 55 | 56 | ### `wptt_get_webfont_styles` 57 | ``` 58 | $remote_url = 'https://fonts.googleapis.com/css2?family=Literata&display=swap'; 59 | $contents = wptt_get_webfont_styles( $remote_url ); 60 | ``` 61 | Returns the stylesheet contents, using locally hosted webfonts. 62 | 63 | ### `wptt_get_webfont_url` 64 | ``` 65 | $remote_url = 'https://fonts.googleapis.com/css2?family=Literata&display=swap'; 66 | $contents = wptt_get_webfont_url( $remote_url ); 67 | ``` 68 | Returns a stylesheet URL, locally-hosted. 69 | 70 | ## Build url for multiple fonts 71 | ```php 72 | $font_families = array( 73 | 'Quicksand:wght@300;400;500;600;700', 74 | 'Work+Sans:wght@300;400;500;600;700' 75 | ); 76 | 77 | $fonts_url = add_query_arg( array( 78 | 'family' => implode( '&family=', $font_families ), 79 | 'display' => 'swap', 80 | ), 'https://fonts.googleapis.com/css2' ); 81 | 82 | $contents = wptt_get_webfont_url( esc_url_raw( $fonts_url ) ); 83 | ``` 84 | 85 | ## Supporting IE 86 | The `wptt_get_webfont_url` will - by default - download `.woff2` files. However, if you need to support IE you will need to use `.woff` files instead. To do that, you can pass `woff` as the 2nd argument in the `wptt_get_webfont_url` function: 87 | ```php 88 | wptt_get_webfont_url( 'https://fonts.googleapis.com/css2?family=Literata&display=swap', 'woff' ); 89 | ``` 90 | 91 | ## Storing In A Custom Directory 92 | If you have the need to store font files in a custom directory you can pass a custom path and URL using filters. Be sure you add these filters **BEFORE** the file containing the `WPTT_WebFont_Loader` class is called. 93 | 94 | ```php 95 | /** 96 | * Change the base path. 97 | * This is by default WP_CONTENT_DIR. 98 | * 99 | * NOTE: Do not include trailing slash. 100 | */ 101 | add_filter( 'wptt_get_local_fonts_base_path', function( $path ) { 102 | return WP_CONTENT_DIR; 103 | } ); 104 | 105 | /** 106 | * Change the base URL. 107 | * This is by default the content_url(). 108 | * 109 | * NOTE: Do not include trailing slash. 110 | */ 111 | add_filter( 'wptt_get_local_fonts_base_url', function( $url ) { 112 | return content_url(); 113 | } ); 114 | 115 | /** 116 | * Change the subfolder name. 117 | * This is by default "fonts". 118 | * 119 | * Return empty string or false to not use a subfolder. 120 | */ 121 | add_filter( 'wptt_get_local_fonts_subfolder_name', function( $subfolder_name ) { 122 | return 'fonts'; 123 | } ); 124 | ``` 125 | -------------------------------------------------------------------------------- /wptt-webfont-loader.php: -------------------------------------------------------------------------------- 1 | remote_url = $url; 125 | 126 | // Add a cleanup routine. 127 | $this->schedule_cleanup(); 128 | add_action( 'delete_fonts_folder', array( $this, 'delete_fonts_folder' ) ); 129 | } 130 | 131 | /** 132 | * Get the local URL which contains the styles. 133 | * 134 | * Fallback to the remote URL if we were unable to write the file locally. 135 | * 136 | * @access public 137 | * @since 1.1.0 138 | * @return string 139 | */ 140 | public function get_url() { 141 | 142 | // If remote URL is empty just return itself. 143 | if ( empty( $this->remote_url ) ) { 144 | return $this->remote_url; 145 | } 146 | 147 | // Check if the local stylesheet exists. 148 | if ( $this->local_file_exists() ) { 149 | 150 | // Attempt to update the stylesheet. Return the local URL on success. 151 | if ( $this->write_stylesheet() ) { 152 | return $this->get_local_stylesheet_url(); 153 | } 154 | } 155 | 156 | // If the local file exists, return its URL, with a fallback to the remote URL. 157 | return file_exists( $this->get_local_stylesheet_path() ) 158 | ? $this->get_local_stylesheet_url() 159 | : $this->remote_url; 160 | } 161 | 162 | /** 163 | * Get the local stylesheet URL. 164 | * 165 | * @access public 166 | * @since 1.1.0 167 | * @return string 168 | */ 169 | public function get_local_stylesheet_url() { 170 | if ( ! $this->local_stylesheet_url ) { 171 | $this->local_stylesheet_url = str_replace( 172 | $this->get_base_path(), 173 | $this->get_base_url(), 174 | $this->get_local_stylesheet_path() 175 | ); 176 | } 177 | return $this->local_stylesheet_url; 178 | } 179 | 180 | /** 181 | * Get styles with fonts downloaded locally. 182 | * 183 | * @access public 184 | * @since 1.0.0 185 | * @return string 186 | */ 187 | public function get_styles() { 188 | 189 | // If remote URL is empty, set empty string. 190 | if ( empty( $this->remote_url ) ) { 191 | $this->css = ''; 192 | } 193 | 194 | // If the CSS is set already, return it. 195 | if ( is_string( $this->css ) ) { 196 | return $this->css; 197 | } 198 | 199 | // If we already have the local file, return its contents. 200 | $this->css = $this->get_local_stylesheet_contents(); 201 | if ( ! empty( $this->css ) ) { 202 | return $this->css; 203 | } 204 | 205 | // Get the remote URL contents. 206 | $this->remote_styles = $this->get_remote_url_contents(); 207 | 208 | // Get an array of locally-hosted files. 209 | $files = $this->get_local_files_from_css(); 210 | 211 | // Convert paths to URLs. 212 | foreach ( $files as $remote => $local ) { 213 | $files[ $remote ] = str_replace( 214 | $this->get_base_path(), 215 | $this->get_base_url(), 216 | $local 217 | ); 218 | } 219 | 220 | $this->css = str_replace( 221 | array_keys( $files ), 222 | array_values( $files ), 223 | $this->remote_styles 224 | ); 225 | 226 | $this->write_stylesheet(); 227 | 228 | return $this->css; 229 | } 230 | 231 | /** 232 | * Get local stylesheet contents. 233 | * 234 | * @access public 235 | * @since 1.1.0 236 | * @return string|false Returns the remote URL contents. 237 | */ 238 | public function get_local_stylesheet_contents() { 239 | 240 | // Check if the local stylesheet exists. 241 | if ( $this->local_file_exists() ) { 242 | 243 | // Attempt to update the stylesheet. Return false on fail. 244 | if ( ! $this->write_stylesheet() ) { 245 | return false; 246 | } 247 | } 248 | 249 | ob_start(); 250 | include $this->get_local_stylesheet_path(); 251 | return ob_get_clean(); 252 | } 253 | 254 | /** 255 | * Get remote file contents. 256 | * 257 | * @access public 258 | * @since 1.0.0 259 | * @return string Returns the remote URL contents. 260 | */ 261 | public function get_remote_url_contents() { 262 | 263 | /** 264 | * The user-agent we want to use. 265 | * 266 | * The default user-agent is the only one compatible with woff (not woff2) 267 | * which also supports unicode ranges. 268 | */ 269 | $user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/603.3.8 (KHTML, like Gecko) Version/10.1.2 Safari/603.3.8'; 270 | 271 | // Switch to a user-agent supporting woff2 if we don't need to support IE. 272 | if ( 'woff2' === $this->font_format ) { 273 | $user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:73.0) Gecko/20100101 Firefox/73.0'; 274 | } 275 | 276 | // Get the response. 277 | $response = wp_remote_get( $this->remote_url, array( 'user-agent' => $user_agent ) ); 278 | 279 | // Early exit if there was an error. 280 | if ( is_wp_error( $response ) ) { 281 | return ''; 282 | } 283 | 284 | // Get the CSS from our response. 285 | $contents = wp_remote_retrieve_body( $response ); 286 | 287 | return $contents; 288 | } 289 | 290 | /** 291 | * Download files mentioned in our CSS locally. 292 | * 293 | * @access public 294 | * @since 1.0.0 295 | * @return array Returns an array of remote URLs and their local counterparts. 296 | */ 297 | public function get_local_files_from_css() { 298 | $font_files = $this->get_remote_files_from_css(); 299 | $stored = get_site_option( 'downloaded_font_files', array() ); 300 | $change = false; // If in the end this is true, we need to update the cache option. 301 | 302 | if ( ! defined( 'FS_CHMOD_DIR' ) ) { 303 | define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) ); 304 | } 305 | 306 | // If the fonts folder don't exist, create it. 307 | if ( ! file_exists( $this->get_fonts_folder() ) ) { 308 | $this->get_filesystem()->mkdir( $this->get_fonts_folder(), FS_CHMOD_DIR ); 309 | } 310 | 311 | foreach ( $font_files as $font_family => $files ) { 312 | 313 | // The folder path for this font-family. 314 | $folder_path = $this->get_fonts_folder() . '/' . $font_family; 315 | 316 | // If the folder doesn't exist, create it. 317 | if ( ! file_exists( $folder_path ) ) { 318 | $this->get_filesystem()->mkdir( $folder_path, FS_CHMOD_DIR ); 319 | } 320 | 321 | foreach ( $files as $url ) { 322 | 323 | // Get the filename. 324 | $filename = basename( wp_parse_url( $url, PHP_URL_PATH ) ); 325 | $font_path = $folder_path . '/' . $filename; 326 | /** 327 | * In Typekit, the filename will always be the same. We also need to check for query vars in their URLs. 328 | * They provide this font variation description that we can use https://github.com/typekit/fvd 329 | */ 330 | $queries = parse_url( $url, PHP_URL_QUERY ); 331 | if ( ! empty( $queries ) ) { 332 | $query_args = array(); 333 | parse_str( $queries, $query_args ); 334 | if ( array_key_exists( 'fvd', $query_args ) ) { 335 | $font_path .= $query_args['fvd']; 336 | } 337 | } 338 | 339 | // Check if the file already exists. 340 | if ( file_exists( $font_path ) ) { 341 | 342 | // Skip if already cached. 343 | if ( isset( $stored[ $url ] ) ) { 344 | continue; 345 | } 346 | 347 | // Add file to the cache and change the $changed var to indicate we need to update the option. 348 | $stored[ $url ] = $font_path; 349 | $change = true; 350 | 351 | // Since the file exists we don't need to proceed with downloading it. 352 | continue; 353 | } 354 | 355 | /** 356 | * If we got this far, we need to download the file. 357 | */ 358 | 359 | // require file.php if the download_url function doesn't exist. 360 | if ( ! function_exists( 'download_url' ) ) { 361 | require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' ); 362 | } 363 | 364 | // Download file to temporary location. 365 | $tmp_path = download_url( $url ); 366 | 367 | // Make sure there were no errors. 368 | if ( is_wp_error( $tmp_path ) ) { 369 | continue; 370 | } 371 | 372 | // Move temp file to final destination. 373 | $success = $this->get_filesystem()->move( $tmp_path, $font_path, true ); 374 | if ( $success ) { 375 | $stored[ $url ] = $font_path; 376 | $change = true; 377 | } 378 | } 379 | } 380 | 381 | // If there were changes, update the option. 382 | if ( $change ) { 383 | 384 | // Cleanup the option and then save it. 385 | foreach ( $stored as $url => $path ) { 386 | if ( ! file_exists( $path ) ) { 387 | unset( $stored[ $url ] ); 388 | } 389 | } 390 | update_site_option( 'downloaded_font_files', $stored ); 391 | } 392 | 393 | return $stored; 394 | } 395 | 396 | /** 397 | * Get font files from the CSS. 398 | * 399 | * @access public 400 | * @since 1.0.0 401 | * @return array Returns an array of font-families and the font-files used. 402 | */ 403 | public function get_remote_files_from_css() { 404 | 405 | $font_faces = explode( '@font-face', $this->remote_styles ); 406 | 407 | $result = array(); 408 | 409 | // Loop all our font-face declarations. 410 | foreach ( $font_faces as $font_face ) { 411 | 412 | // Make sure we only process styles inside this declaration. 413 | $style = explode( '}', $font_face )[0]; 414 | 415 | // Sanity check. 416 | if ( false === strpos( $style, 'font-family' ) ) { 417 | continue; 418 | } 419 | 420 | // Get an array of our font-families. 421 | preg_match_all( '/font-family.*?\;/', $style, $matched_font_families ); 422 | 423 | // Get an array of our font-files. 424 | preg_match_all( '/url\(.*?\)/i', $style, $matched_font_files ); 425 | 426 | // Get the font-family name. 427 | $font_family = 'unknown'; 428 | if ( isset( $matched_font_families[0] ) && isset( $matched_font_families[0][0] ) ) { 429 | $font_family = rtrim( ltrim( $matched_font_families[0][0], 'font-family:' ), ';' ); 430 | $font_family = trim( str_replace( array( "'", ';' ), '', $font_family ) ); 431 | $font_family = sanitize_key( strtolower( str_replace( ' ', '-', $font_family ) ) ); 432 | } 433 | 434 | // Make sure the font-family is set in our array. 435 | if ( ! isset( $result[ $font_family ] ) ) { 436 | $result[ $font_family ] = array(); 437 | } 438 | 439 | // Get files for this font-family and add them to the array. 440 | foreach ( $matched_font_files as $match ) { 441 | 442 | // Sanity check. 443 | if ( ! isset( $match[0] ) ) { 444 | continue; 445 | } 446 | 447 | // Add the file URL. 448 | $font_family_url = rtrim( ltrim( $match[0], 'url(' ), ')' ); 449 | $font_family_url = str_replace( '"', '', $font_family_url ); 450 | 451 | // Make sure to convert relative URLs to absolute. 452 | $font_family_url = $this->get_absolute_path( $font_family_url ); 453 | 454 | $result[ $font_family ][] = $font_family_url; 455 | } 456 | 457 | // Make sure we have unique items. 458 | // We're using array_flip here instead of array_unique for improved performance. 459 | $result[ $font_family ] = array_flip( array_flip( $result[ $font_family ] ) ); 460 | } 461 | 462 | return $result; 463 | } 464 | 465 | /** 466 | * Write the CSS to the filesystem. 467 | * 468 | * @access protected 469 | * @since 1.1.0 470 | * @return string|false Returns the absolute path of the file on success, or false on fail. 471 | */ 472 | protected function write_stylesheet() { 473 | $file_path = $this->get_local_stylesheet_path(); 474 | $filesystem = $this->get_filesystem(); 475 | 476 | if ( ! defined( 'FS_CHMOD_DIR' ) ) { 477 | define( 'FS_CHMOD_DIR', ( 0755 & ~ umask() ) ); 478 | } 479 | 480 | // If the folder doesn't exist, create it. 481 | if ( ! file_exists( $this->get_fonts_folder() ) ) { 482 | $filesystem->mkdir( $this->get_fonts_folder(), FS_CHMOD_DIR ); 483 | } 484 | 485 | // If the file doesn't exist, create it. Return false if it can not be created. 486 | if ( ! $filesystem->exists( $file_path ) && ! $filesystem->touch( $file_path ) ) { 487 | return false; 488 | } 489 | 490 | // If we got this far, we need to write the file. 491 | // Get the CSS. 492 | if ( null === $this->css ) { 493 | $this->get_styles(); 494 | } 495 | 496 | // Put the contents in the file. Return false if that fails. 497 | if ( ! $filesystem->put_contents( $file_path, $this->css ) ) { 498 | return false; 499 | } 500 | 501 | return $file_path; 502 | } 503 | 504 | /** 505 | * Get the stylesheet path. 506 | * 507 | * @access public 508 | * @since 1.1.0 509 | * @return string 510 | */ 511 | public function get_local_stylesheet_path() { 512 | if ( ! $this->local_stylesheet_path ) { 513 | $this->local_stylesheet_path = $this->get_fonts_folder() . '/' . $this->get_local_stylesheet_filename() . '.css'; 514 | } 515 | return $this->local_stylesheet_path; 516 | } 517 | 518 | /** 519 | * Get the local stylesheet filename. 520 | * 521 | * This is a hash, generated from the site-URL, the wp-content path and the URL. 522 | * This way we can avoid issues with sites changing their URL, or the wp-content path etc. 523 | * 524 | * @access public 525 | * @since 1.1.0 526 | * @return string 527 | */ 528 | public function get_local_stylesheet_filename() { 529 | return md5( $this->get_base_url() . $this->get_base_path() . $this->remote_url . $this->font_format ); 530 | } 531 | 532 | /** 533 | * Set the font-format to be used. 534 | * 535 | * @access public 536 | * @since 1.0.0 537 | * @param string $format The format to be used. Use "woff" or "woff2". 538 | * @return void 539 | */ 540 | public function set_font_format( $format = 'woff2' ) { 541 | $this->font_format = $format; 542 | } 543 | 544 | /** 545 | * Check if the local stylesheet exists. 546 | * 547 | * The name of this method is wrong. Should be "no_local_file_exists()" 548 | * as it returns true if the file does NOT exist. 549 | * Keeping the original name not to break 3rd party scripts. 550 | * 551 | * @access public 552 | * @since 1.1.0 553 | * @return bool 554 | */ 555 | public function local_file_exists() { 556 | return ( ! file_exists( $this->get_local_stylesheet_path() ) ); 557 | } 558 | 559 | /** 560 | * Get the base path. 561 | * 562 | * @access public 563 | * @since 1.1.0 564 | * @return string 565 | */ 566 | public function get_base_path() { 567 | if ( ! $this->base_path ) { 568 | $this->base_path = apply_filters( 'wptt_get_local_fonts_base_path', $this->get_filesystem()->wp_content_dir() ); 569 | } 570 | return $this->base_path; 571 | } 572 | 573 | /** 574 | * Get the base URL. 575 | * 576 | * @access public 577 | * @since 1.1.0 578 | * @return string 579 | */ 580 | public function get_base_url() { 581 | if ( ! $this->base_url ) { 582 | $this->base_url = apply_filters( 'wptt_get_local_fonts_base_url', content_url() ); 583 | } 584 | return $this->base_url; 585 | } 586 | 587 | /** 588 | * Get the subfolder name. 589 | * 590 | * @access public 591 | * @since 1.1.0 592 | * @return string 593 | */ 594 | public function get_subfolder_name() { 595 | if ( ! $this->subfolder_name ) { 596 | $this->subfolder_name = apply_filters( 'wptt_get_local_fonts_subfolder_name', 'fonts' ); 597 | } 598 | return $this->subfolder_name; 599 | } 600 | 601 | /** 602 | * Get the folder for fonts. 603 | * 604 | * @access public 605 | * @return string 606 | */ 607 | public function get_fonts_folder() { 608 | if ( ! $this->fonts_folder ) { 609 | $this->fonts_folder = $this->get_base_path(); 610 | if ( $this->get_subfolder_name() ) { 611 | $this->fonts_folder .= '/' . $this->get_subfolder_name(); 612 | } 613 | } 614 | return $this->fonts_folder; 615 | } 616 | 617 | /** 618 | * Schedule a cleanup. 619 | * 620 | * Deletes the fonts files on a regular basis. 621 | * This way font files will get updated regularly, 622 | * and we avoid edge cases where unused files remain in the server. 623 | * 624 | * @access public 625 | * @since 1.1.0 626 | * @return void 627 | */ 628 | public function schedule_cleanup() { 629 | if ( ! is_multisite() || ( is_multisite() && is_main_site() ) ) { 630 | if ( ! wp_next_scheduled( 'delete_fonts_folder' ) && ! wp_installing() ) { 631 | wp_schedule_event( time(), self::CLEANUP_FREQUENCY, 'delete_fonts_folder' ); 632 | } 633 | } 634 | } 635 | 636 | /** 637 | * Delete the fonts folder. 638 | * 639 | * This runs as part of a cleanup routine. 640 | * 641 | * @access public 642 | * @since 1.1.0 643 | * @return bool 644 | */ 645 | public function delete_fonts_folder() { 646 | return $this->get_filesystem()->delete( $this->get_fonts_folder(), true ); 647 | } 648 | 649 | /** 650 | * Get the filesystem. 651 | * 652 | * @access protected 653 | * @since 1.0.0 654 | * @return \WP_Filesystem_Base 655 | */ 656 | protected function get_filesystem() { 657 | global $wp_filesystem; 658 | 659 | // If the filesystem has not been instantiated yet, do it here. 660 | if ( ! $wp_filesystem ) { 661 | if ( ! function_exists( 'WP_Filesystem' ) ) { 662 | require_once wp_normalize_path( ABSPATH . '/wp-admin/includes/file.php' ); 663 | } 664 | WP_Filesystem(); 665 | } 666 | return $wp_filesystem; 667 | } 668 | 669 | /** 670 | * Get an absolute URL from a relative URL. 671 | * 672 | * @access protected 673 | * 674 | * @param string $url The URL. 675 | * 676 | * @return string 677 | */ 678 | protected function get_absolute_path( $url ) { 679 | 680 | // If dealing with a root-relative URL. 681 | if ( 0 === stripos( $url, '/' ) ) { 682 | $parsed_url = parse_url( $this->remote_url ); 683 | return $parsed_url['scheme'] . '://' . $parsed_url['hostname'] . $url; 684 | } 685 | 686 | return $url; 687 | } 688 | } 689 | } 690 | 691 | if ( ! function_exists( 'wptt_get_webfont_styles' ) ) { 692 | /** 693 | * Get styles for a webfont. 694 | * 695 | * This will get the CSS from the remote API, 696 | * download any fonts it contains, 697 | * replace references to remote URLs with locally-downloaded assets, 698 | * and finally return the resulting CSS. 699 | * 700 | * @since 1.0.0 701 | * 702 | * @param string $url The URL of the remote webfont. 703 | * @param string $format The font-format. If you need to support IE, change this to "woff". 704 | * 705 | * @return string Returns the CSS. 706 | */ 707 | function wptt_get_webfont_styles( $url, $format = 'woff2' ) { 708 | $font = new WPTT_WebFont_Loader( $url ); 709 | $font->set_font_format( $format ); 710 | return $font->get_styles(); 711 | } 712 | } 713 | 714 | if ( ! function_exists( 'wptt_get_webfont_url' ) ) { 715 | /** 716 | * Get a stylesheet URL for a webfont. 717 | * 718 | * @since 1.1.0 719 | * 720 | * @param string $url The URL of the remote webfont. 721 | * @param string $format The font-format. If you need to support IE, change this to "woff". 722 | * 723 | * @return string Returns the CSS. 724 | */ 725 | function wptt_get_webfont_url( $url, $format = 'woff2' ) { 726 | $font = new WPTT_WebFont_Loader( $url ); 727 | $font->set_font_format( $format ); 728 | return $font->get_url(); 729 | } 730 | } 731 | --------------------------------------------------------------------------------