Skip to content

Commit

Permalink
Host google fonts locally (PR #7164)
Browse files Browse the repository at this point in the history
Co-authored-by: Gael Robin <[email protected]>
Co-authored-by: Rémy Perona <[email protected]>
Co-authored-by: Rémy Perona <[email protected]>
Co-authored-by: Opeyemi Ibrahim <[email protected]>
Co-authored-by: Michael Lee <[email protected]>
Co-authored-by: hanna-meda <[email protected]>
  • Loading branch information
7 people authored Jan 1, 2025
1 parent afb8cc2 commit 45d1e3a
Show file tree
Hide file tree
Showing 78 changed files with 3,271 additions and 181 deletions.
1 change: 1 addition & 0 deletions .github/workflows/lint_phpcs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- branch-*
- feature/*
- enhancement/*
- fix/*

jobs:
run:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/lint_phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- branch-*
- feature/*
- enhancement/*
- fix/*

jobs:
run:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test_wprocket.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- branch-*
- feature/*
- enhancement/*
- fix/*

jobs:
run:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- branch-*
- feature/*
- enhancement/*
- fix/*

jobs:
run:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test_wprocket_latest_specific.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- branch-*
- feature/*
- enhancement/*
- fix/*

jobs:
run:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/test_wprocket_php8.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ on:
- branch-*
- feature/*
- enhancement/*
- fix/*

jobs:
run:
Expand Down
10 changes: 10 additions & 0 deletions inc/Engine/Admin/Beacon/Beacon.php
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,16 @@ public function get_suggest( $doc_id ) {
'url' => 'https://fr.docs.wp-rocket.me/article/1836-rendu-differe-automatique/?utm_source=wp_plugin&utm_medium=wp_rocket',
],
],
'host_fonts_locally' => [
'en' => [
'id' => '673358b02ddbd952f6241b38',
'url' => 'https://docs.wp-rocket.me/article/1847-self-host-google-fonts?utm_source=wp_plugin&utm_medium=wp_rocket',
],
'fr' => [
'id' => '675ab51d46b8d26833b2af82',
'url' => 'https://fr.docs.wp-rocket.me/article/1852-auto-heberger-google-fonts?utm_source=wp_plugin&utm_medium=wp_rocket',
],
],
];

return isset( $suggest[ $doc_id ][ $this->get_user_locale() ] )
Expand Down
23 changes: 20 additions & 3 deletions inc/Engine/Admin/Settings/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -846,12 +846,13 @@ private function media_section() {
$lazyload_beacon = $this->beacon->get_suggest( 'lazyload' );
$exclude_lazyload = $this->beacon->get_suggest( 'exclude_lazyload' );
$dimensions = $this->beacon->get_suggest( 'image_dimensions' );
$fonts = $this->beacon->get_suggest( 'host_fonts_locally' );

$this->settings->add_page_section(
'media',
[
'title' => __( 'Media', 'rocket' ),
'menu_description' => __( 'LazyLoad, image dimensions', 'rocket' ),
'menu_description' => __( 'LazyLoad, image dimensions, font optimization', 'rocket' ),
]
);

Expand Down Expand Up @@ -913,7 +914,7 @@ private function media_section() {

$this->settings->add_settings_sections(
[
'lazyload_section' => [
'lazyload_section' => [
'title' => __( 'LazyLoad', 'rocket' ),
'type' => 'fields_container',
// translators: %1$s = opening <a> tag, %2$s = closing </a> tag.
Expand All @@ -926,14 +927,22 @@ private function media_section() {
// translators: %1$s = “WP Rocket”, %2$s = a list of plugin names.
'helper' => ! empty( $disable_lazyload ) ? sprintf( __( 'LazyLoad is currently activated in %2$s. If you want to use WP Rocket’s LazyLoad, disable this option in %2$s.', 'rocket' ), WP_ROCKET_PLUGIN_NAME, $disable_lazyload ) : '',
],
'dimensions_section' => [
'dimensions_section' => [
'title' => __( 'Image Dimensions', 'rocket' ),
'type' => 'fields_container',
// translators: %1$s = opening <a> tag, %2$s = closing </a> tag.
'description' => sprintf( __( 'Add missing width and height attributes to images. Helps prevent layout shifts and improve the reading experience for your visitors. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $dimensions['url'] ) . '" data-beacon-article="' . esc_attr( $dimensions['id'] ) . '" target="_blank" rel="noopener noreferrer">', '</a>' ),
'help' => $dimensions,
'page' => 'media',
],
'font_optimization_section' => [
'title' => __( 'Fonts', 'rocket' ),
'type' => 'fields_container',
// translators: %1$s = opening <a> tag, %2$s = closing </a> tag.
'description' => sprintf( __( 'Download and serve fonts directly from your server. Reduces connections to external servers and minimizes font shifts. %1$sMore info%2$s', 'rocket' ), '<a href="' . esc_url( $fonts['url'] ) . '" data-beacon-article="' . esc_attr( $fonts['id'] ) . '" target="_blank" rel="noopener noreferrer">', '</a>' ),
'help' => $fonts,
'page' => 'media',
],
]
);

Expand Down Expand Up @@ -1032,6 +1041,14 @@ private function media_section() {
'default' => 0,
'sanitize_callback' => 'sanitize_checkbox',
],
'host_fonts_locally' => [
'type' => 'checkbox',
'label' => __( 'Self-host Google Fonts', 'rocket' ),
'section' => 'font_optimization_section',
'page' => 'media',
'default' => 0,
'sanitize_callback' => 'sanitize_checkbox',
],
]
);
}
Expand Down
129 changes: 129 additions & 0 deletions inc/Engine/Common/AbstractFileSystem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);

namespace WP_Rocket\Engine\Common;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use WP_Filesystem_Direct;

abstract class AbstractFileSystem {
/**
* WP Filesystem instance.
*
* @var WP_Filesystem_Direct
*/
protected $filesystem;

/**
* Constructor method.
* Initializes a new instance of the Controller class.
*
* @param WP_Filesystem_Direct $filesystem Filesystem class.
*/
public function __construct( $filesystem = null ) {
$this->filesystem = $filesystem ?? rocket_direct_filesystem();
}

/**
* Write to file.
*
* @param string $file_path File path to store the file.
* @param string $content File content(data).
*
* @return bool
*/
protected function write_file( string $file_path, string $content ): bool {
return $this->filesystem->put_contents( $file_path, $content, rocket_get_filesystem_perms( 'file' ) );
}

/**
* Get the content of a file
*
* @param string $file The file content to get.
*
* @return string
*/
public function get_file_content( string $file ): string {
if ( ! $this->filesystem->exists( $file ) ) {
return '';
}

return $this->filesystem->get_contents( $file );
}

/**
* Delete file from a directory
*
* @param string $file_path Path to file that would be deleted.
*
* @return bool
*/
protected function delete_file( string $file_path ): bool {
return $this->filesystem->delete( $file_path, false, 'f' );
}

/**
* Checks if the dir path is writable and create dir if it doesn't exist.
*
* @param string $dir_path The directory to check.
*
* @return bool
*/
protected function is_folder_writable( string $dir_path ): bool {
if ( ! $this->filesystem->exists( $dir_path ) ) {
rocket_mkdir_p( $dir_path );
}

return $this->filesystem->is_writable( $dir_path );
}

/**
* Deletes all files in a given directory
*
* @param string $dir_path The directory path.
*
* @return void
*/
public function delete_all_files_from_directory( $dir_path ): void {
try {
$dir = new RecursiveDirectoryIterator( $dir_path, \FilesystemIterator::SKIP_DOTS );

$items = new RecursiveIteratorIterator( $dir, RecursiveIteratorIterator::CHILD_FIRST );

foreach ( $items as $item ) {
$this->filesystem->delete( $item );
}
} catch ( \Exception $e ) {
return;
}
}

/**
* Converts hash to path with filtered number of levels
*
* @since 3.11.4
*
* @param string $hash md5 hash string.
*
* @return string
*/
public function hash_to_path( string $hash ): string {
/**
* Filters the number of sub-folders level to create for used CSS storage
*
* @since 3.11.4
*
* @param int $levels Number of levels.
*/
$levels = wpm_apply_filters_typed( 'integer', 'rocket_used_css_dir_level', 3 );

$base = substr( $hash, 0, $levels );
$remain = substr( $hash, $levels );

$path_array = str_split( $base );
$path_array[] = $remain;

return implode( '/', $path_array );
}
}
2 changes: 1 addition & 1 deletion inc/Engine/Common/PerformanceHints/WarmUp/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ private function is_mobile(): bool {
* @return string
*/
public function add_wpr_imagedimensions_query_arg( string $url ): string {
if ( empty( $this->factories ) ) {
if ( empty( $this->factories ) && ! $this->options->get( 'remove_unused_css', 0 ) ) {
return $url;
}

Expand Down
119 changes: 119 additions & 0 deletions inc/Engine/Media/Fonts/Admin/Data.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php
declare( strict_types=1 );

namespace WP_Rocket\Engine\Media\Fonts\Admin;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use WP_Rocket\Admin\Options_Data;
use WP_Rocket\Engine\Common\Queue\AbstractASQueue;

class Data extends AbstractASQueue {
/**
* Options data instance.
*
* @var Options_Data
*/
private $options;

/**
* Base path.
*
* @var string
*/
private $base_path;

/**
* Constructor.
*
* @param Options_Data $options Options data instance.
*/
public function __construct( Options_Data $options ) {
$this->options = $options;
$this->base_path = rocket_get_constant( 'WP_ROCKET_CACHE_ROOT_PATH', '' ) . 'fonts/' . get_current_blog_id() . '/';
}

/**
* Schedule data collection.
*
* @return void
*/
public function schedule_data_collection() {
if ( ! $this->is_enabled() ) {
return;
}

$this->schedule_recurring( time(), WEEK_IN_SECONDS, 'rocket_fonts_data_collection' );
}

/**
* Unschedule data collection.
*
* @return void
*/
public function unschedule_data_collection() {
$this->cancel( 'rocket_fonts_data_collection' );
}

/**
* Collect data.
*
* @return void
*/
public function collect_data() {
if ( ! $this->is_enabled() ) {
return;
}

$fonts_data = get_transient( 'rocket_fonts_data_collection' );

// If data has been populated, bail out early.
if ( false !== $fonts_data ) {
return;
}

$fonts = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->base_path . 'google-fonts/fonts/' ) );

$allowed_extensions = [
'woff',
'woff2',
'ttf',
'otf',
];

$total_font_count = 0;
$total_font_size = 0;

foreach ( $fonts as $file ) {
// check file is not a directory.
if ( $file->isDir() ) {
continue;
}

$extension = strtolower( pathinfo( $file->getFilename(), PATHINFO_EXTENSION ) );

if ( in_array( $extension, $allowed_extensions, true ) ) {
++$total_font_count;
$total_font_size += $file->getSize();
}
}

set_transient(
'rocket_fonts_data_collection',
[
'fonts_total_number' => $total_font_count,
'fonts_total_size' => size_format( $total_font_size ),
],
WEEK_IN_SECONDS
);
}

/**
* Check if the feature & analytics are enabled.
*
* @return bool
*/
private function is_enabled(): bool {
return $this->options->get( 'host_fonts_locally', 0 ) && $this->options->get( 'analytics_enabled', 0 );
}
}
Loading

0 comments on commit 45d1e3a

Please sign in to comment.