Use CORE for Font Management (#518)

Co-authored-by: Vicente Canales <vicente.canales@automattic.com>
This commit is contained in:
Jason Crist 2024-03-22 06:48:47 -04:00 committed by GitHub
parent 1545d48b45
commit 99a35c5d99
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 399 additions and 5 deletions

View file

@ -81,5 +81,5 @@ jobs:
- name: Run PHP tests
run: |
mysql -uroot -h127.0.0.1 -e 'SELECT version()' \
&& ./bin/install-wp-tests.sh --recreate-db wordpress_test root '' > /dev/null \
&& ./bin/install-wp-tests.sh --wp-version=trunk --recreate-db wordpress_test root '' > /dev/null \
&& composer run-script test

View file

@ -13,6 +13,7 @@ require_once __DIR__ . '/create-theme/theme-utils.php';
require_once __DIR__ . '/create-theme/theme-readme.php';
require_once __DIR__ . '/create-theme/theme-form.php';
require_once __DIR__ . '/create-theme/form-messages.php';
require_once __DIR__ . '/create-theme/theme-fonts.php';

/**
* The admin-specific functionality of the plugin.

View file

@ -0,0 +1,136 @@
<?php


class Theme_Fonts {

/**
* Copy any ACTIVATED fonts from USER configuration to THEME configuration including any font face assets.
* Remove any DEACTIVATED fronts from the THEME configuration.
*/
public static function persist_font_settings() {
static::remove_deactivated_fonts_from_theme();
static::copy_activated_fonts_to_theme();
}

public static function copy_activated_fonts_to_theme() {

$user_settings = MY_Theme_JSON_Resolver::get_user_data()->get_settings();
$theme_json = MY_Theme_JSON_Resolver::get_theme_file_contents();

// If there are no custom fonts, bounce out
if ( ! isset( $user_settings['typography']['fontFamilies']['custom'] ) ) {
return;
}

$font_families_to_copy = $user_settings['typography']['fontFamilies']['custom'];

// copy font face assets to theme and change the src to the new location
require_once ABSPATH . 'wp-admin/includes/file.php';
$theme_font_asset_location = get_stylesheet_directory() . '/assets/fonts/';
if ( ! file_exists( $theme_font_asset_location ) ) {
mkdir( $theme_font_asset_location, 0777, true );
}
foreach ( $font_families_to_copy as &$font_family ) {
if ( ! isset( $font_family['fontFace'] ) ) {
continue;
}
foreach ( $font_family['fontFace'] as &$font_face ) {
$font_filename = basename( $font_face['src'] );
$font_dir = wp_get_font_dir();
if ( str_contains( $font_face['src'], $font_dir['url'] ) ) {
// If the file is hosted on this server then copy it to the theme
copy( $font_dir['path'] . '/' . $font_filename, $theme_font_asset_location . '/' . $font_filename );
} else {
// otherwise download it from wherever it is hosted
$tmp_file = download_url( $font_face['src'] );
copy( $tmp_file, $theme_font_asset_location . $font_filename );
unlink( $tmp_file );
}

$font_face['src'] = 'file:./assets/fonts/' . $font_filename;
}
}

// Copy user fonts to theme
if ( ! isset( $theme_json['settings']['typography']['fontFamilies'] ) ) {
$theme_json['settings']['typography']['fontFamilies'] = array();
}
$theme_json['settings']['typography']['fontFamilies'] = array_merge(
$theme_json['settings']['typography']['fontFamilies'],
$font_families_to_copy
);

// Remove user fonts
unset( $user_settings['typography']['fontFamilies']['custom'] );
if ( empty( $user_settings['typography']['fontFamilies'] ) ) {
unset( $user_settings['typography']['fontFamilies'] );
}
if ( empty( $user_settings['typography'] ) ) {
unset( $user_settings['typography'] );
}

// Update the user settings
MY_Theme_JSON_Resolver::write_user_settings( $user_settings );

// Update theme.json
MY_Theme_JSON_Resolver::write_theme_file_contents( $theme_json );

}

public static function remove_deactivated_fonts_from_theme() {

$user_settings = MY_Theme_JSON_Resolver::get_user_data()->get_settings();
$theme_json = MY_Theme_JSON_Resolver::get_theme_file_contents();

// If there are no deactivated theme fonts, bounce out
if ( ! isset( $user_settings['typography']['fontFamilies']['theme'] ) ) {
return;
}

$font_families_to_not_remove = $user_settings['typography']['fontFamilies']['theme'];

// Remove font assets from theme
$theme_font_asset_location = get_stylesheet_directory() . '/assets/fonts/';
$font_families_to_remove = array_values(
array_filter(
$theme_json['settings']['typography']['fontFamilies'],
function( $theme_font_family ) use ( $font_families_to_not_remove ) {
return ! in_array( $theme_font_family['slug'], array_column( $font_families_to_not_remove, 'slug' ), true );
}
)
);
foreach ( $font_families_to_remove as $font_family ) {
if ( isset( $font_family['fontFace'] ) ) {
foreach ( $font_family['fontFace'] as $font_face ) {
$font_filename = basename( $font_face['src'] );
if ( file_exists( $theme_font_asset_location . $font_filename ) ) {
unlink( $theme_font_asset_location . $font_filename );
}
}
}
}

// Remove user fonts from theme
$theme_json['settings']['typography']['fontFamilies'] = array_values(
array_filter(
$theme_json['settings']['typography']['fontFamilies'],
function( $theme_font_family ) use ( $font_families_to_not_remove ) {
return in_array( $theme_font_family['slug'], array_column( $font_families_to_not_remove, 'slug' ), true );
}
)
);
MY_Theme_JSON_Resolver::write_theme_file_contents( $theme_json );

// Remove user preferences for theme font activation
unset( $user_settings['typography']['fontFamilies']['theme'] );
if ( empty( $user_settings['typography']['fontFamilies'] ) ) {
unset( $user_settings['typography']['fontFamilies'] );
}
if ( empty( $user_settings['typography'] ) ) {
unset( $user_settings['typography'] );
}

MY_Theme_JSON_Resolver::write_user_settings( $user_settings );
}

}

View file

@ -64,6 +64,7 @@ function augment_resolver_with_utilities() {
$theme->merge( $theme_theme );
}

// Merge the User Data
if ( class_exists( 'WP_Theme_JSON_Resolver_Gutenberg' ) ) {
$theme->merge( WP_Theme_JSON_Resolver_Gutenberg::get_user_data() );
} else {
@ -97,6 +98,37 @@ function augment_resolver_with_utilities() {

}

public static function get_theme_file_contents() {
$theme_json_data = static::read_json_file( static::get_file_path_from_theme( 'theme.json' ) );
return $theme_json_data;
}

public static function write_theme_file_contents( $theme_json_data ) {
$theme_json = wp_json_encode( $theme_json_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
file_put_contents( static::get_file_path_from_theme( 'theme.json' ), $theme_json );
static::clean_cached_data();
}

public static function write_user_settings( $user_settings ) {
$global_styles_id = static::get_user_global_styles_post_id();
$request = new WP_REST_Request( 'POST', '/wp/v2/global-styles/' . $global_styles_id );
$request->set_param( 'settings', $user_settings );
rest_do_request( $request );
static::clean_cached_data();
}

public static function clean_cached_data() {
parent::clean_cached_data();

if ( class_exists( 'WP_Theme_JSON_Resolver_Gutenberg' ) ) {
WP_Theme_JSON_Resolver_Gutenberg::clean_cached_data();
}

//TODO: Clearing the cache should clear this too.
// Does this clear the Gutenberg equivalent?
static::$theme_json_file_cache = array();
}

}
}


View file

@ -1,9 +1,10 @@
# Forked from https://github.com/wp-cli/scaffold-command/blob/main/features/install-wp-tests.feature
# Function to display usage instructions
display_usage() {
echo "Usage: $0 [options] <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
echo "Usage: $0 [options] <db-name> <db-user> <db-pass> [db-host] [skip-database-creation]"
echo "Options:"
echo " --recreate-db Recreate the database"
echo " --wp-version The WordPress version to install. Default is 'latest'."
echo " --help Displays this help message"
}

@ -13,6 +14,10 @@ RECREATE_DB=0
for arg in "$@"
do
case $arg in
--wp-version=*)
WP_VERSION="${arg#*=}"
shift
;;
--recreate-db)
RECREATE_DB=1
shift
@ -40,7 +45,6 @@ DB_NAME=$1
DB_USER=$2
DB_PASS=$3
DB_HOST=${4-127.0.0.1}
WP_VERSION=${5-latest}
SKIP_DB_CREATE=${6-false}

TMPDIR=${TMPDIR-/tmp}

View file

@ -389,6 +389,9 @@ class Create_Block_Theme_API {
* Save the user changes to the theme and clear user changes.
*/
function rest_save_theme( $request ) {

Theme_Fonts::persist_font_settings();

if ( is_child_theme() ) {
Theme_Templates::add_templates_to_local( 'current' );
Theme_Json::add_theme_json_to_local( 'current' );
@ -471,6 +474,7 @@ class Create_Block_Theme_API {
);

function is_valid_screenshot( $file ) {
return 0;
$filetype = wp_check_filetype( $file['name'], self::ALLOWED_SCREENSHOT_TYPES );
if ( is_uploaded_file( $file['tmp_name'] ) && in_array( $filetype['type'], self::ALLOWED_SCREENSHOT_TYPES, true ) && $file['size'] < 2097152 ) {
return 1;

View file

@ -1,8 +1,8 @@
=== Create Block Theme ===
Contributors: wordpressdotorg, mikachan, onemaggie, pbking, scruffian, mmaattiiaass, jffng, madhudollu, egregor, vcanales, jeffikus, cwhitmore
Tags: themes, theme, block-theme
Requires at least: 6.0
Tested up to: 6.4
Requires at least: 6.5
Tested up to: 6.5
Stable tag: 1.13.8
Requires PHP: 7.4
License: GPLv2 or later

View file

@ -11,6 +11,8 @@ if ( ! $_tests_dir ) {
$_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib';
}

define( 'DIR_TESTDATA', __DIR__ . '/data' );

// Forward custom PHPUnit Polyfills configuration to PHPUnit bootstrap file.
$_phpunit_polyfills_path = getenv( 'WP_TESTS_PHPUNIT_POLYFILLS_PATH' );
if ( false !== $_phpunit_polyfills_path ) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

215
tests/test-theme-fonts.php Normal file
View file

@ -0,0 +1,215 @@
<?php
/**
* Class WP_Create_Block_Theme_Admin
*
* @package Create_Block_Theme
*/
class Create_Block_Theme_Fonts extends WP_UnitTestCase {

protected static $admin_id;
protected static $editor_id;

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
self::$admin_id = $factory->user->create(
array(
'role' => 'administrator',
)
);
self::$editor_id = $factory->user->create(
array(
'role' => 'editor',
)
);
}


public function test_copy_activated_fonts_to_theme() {

wp_set_current_user( self::$admin_id );

$user_data_begin = MY_Theme_JSON_Resolver::get_user_data()->get_settings();

$test_theme_slug = $this->create_blank_theme();

$this->activate_user_font();

$user_data_before = MY_Theme_JSON_Resolver::get_user_data()->get_settings();
$theme_data_before = MY_Theme_JSON_Resolver::get_theme_data()->get_settings();

$this->save_theme();

$user_data_after = MY_Theme_JSON_Resolver::get_user_data()->get_settings();
$theme_data_after = MY_Theme_JSON_Resolver::get_theme_data()->get_settings();

// ensure that the font was added and then removed from user space
$this->assertarraynothaskey( 'typography', $user_data_begin );
$this->assertequals( 'open-sans', $user_data_before['typography']['fontFamilies']['custom'][0]['slug'] );
$this->assertarraynothaskey( 'typography', $user_data_after );

// Ensure that the font was added to the theme
$this->assertCount( 1, $theme_data_before['typography']['fontFamilies']['theme'] );
$this->assertCount( 2, $theme_data_after['typography']['fontFamilies']['theme'] );
$this->assertEquals( 'open-sans', $theme_data_after['typography']['fontFamilies']['theme'][1]['slug'] );

// Ensure that the URL was changed to a local file and that it was copied to where it should be
$this->assertEquals( 'file:./assets/fonts/open-sans-normal-400.ttf', $theme_data_after['typography']['fontFamilies']['theme'][1]['fontFace'][0]['src'] );
$this->assertTrue( file_exists( get_stylesheet_directory() . '/assets/fonts/open-sans-normal-400.ttf' ) );

$this->uninstall_theme( $test_theme_slug );

}

public function test_remove_deactivated_fonts_from_theme() {
wp_set_current_user( self::$admin_id );

$test_theme_slug = $this->create_blank_theme();

$this->activate_font_in_theme_and_override_in_user();

$user_data_before = MY_Theme_JSON_Resolver::get_user_data()->get_settings();
$theme_data_before = MY_Theme_JSON_Resolver::get_theme_data()->get_settings();
$merged_data_before = MY_Theme_JSON_Resolver::get_merged_data()->get_settings();
$theme_file_exists_before = file_exists( get_stylesheet_directory() . '/assets/fonts/open-sans-normal-400.ttf' );

$this->save_theme();

$user_data_after = MY_Theme_JSON_Resolver::get_user_data()->get_settings();
$theme_data_after = MY_Theme_JSON_Resolver::get_theme_data()->get_settings();
$merged_data_after = MY_Theme_JSON_Resolver::get_merged_data()->get_settings();
$theme_file_exists_after = file_exists( get_stylesheet_directory() . '/assets/fonts/open-sans-normal-400.ttf' );

// ensure that the font was added to the theme settings and removed in user settings and therefore missing in merged settings
$this->assertCount( 2, $theme_data_before['typography']['fontFamilies']['theme'] );
$this->assertequals( 'open-sans', $theme_data_before['typography']['fontFamilies']['theme'][1]['slug'] );
$this->assertCount( 1, $user_data_before['typography']['fontFamilies']['theme'] );
$this->assertnotequals( 'open-sans', $user_data_before['typography']['fontFamilies']['theme'][0]['slug'] );
$this->assertCount( 1, $merged_data_before['typography']['fontFamilies']['theme'] );
$this->assertnotequals( 'open-sans', $merged_data_before['typography']['fontFamilies']['theme'][0]['slug'] );

// ensure that the font was removed from the user settings and removed from the theme settings and therefore missing in merged settings
$this->assertCount( 1, $theme_data_after['typography']['fontFamilies']['theme'] );
$this->assertnotequals( 'open-sans', $theme_data_after['typography']['fontFamilies']['theme'][0]['slug'] );
$this->assertarraynothaskey( 'typography', $user_data_after );
$this->assertnotequals( 'open-sans', $theme_data_after['typography']['fontFamilies']['theme'][0]['slug'] );
$this->assertCount( 1, $merged_data_after['typography']['fontFamilies']['theme'] );
$this->assertnotequals( 'open-sans', $merged_data_after['typography']['fontFamilies']['theme'][0]['slug'] );

// ensure that the file resource was removed
$this->assertTrue( $theme_file_exists_before );
$this->assertFalse( $theme_file_exists_after );

$this->uninstall_theme( $test_theme_slug );
}

private function save_theme() {
Theme_Fonts::persist_font_settings();
// Theme_Templates::add_templates_to_local( 'all' );
// Theme_Json::add_theme_json_to_local( 'all' );
// Theme_Styles::clear_user_styles_customizations();
// Theme_Templates::clear_user_templates_customizations();
}

private function create_blank_theme() {

$test_theme_slug = 'cbttesttheme';

delete_theme( $test_theme_slug );

$request = new WP_REST_Request( 'POST', '/create-block-theme/v1/create-blank' );
$request->set_param( 'name', $test_theme_slug );
$request->set_param( 'description', '' );
$request->set_param( 'uri', '' );
$request->set_param( 'author', '' );
$request->set_param( 'author_uri', '' );
$request->set_param( 'tags_custom', '' );
$request->set_param( 'subfolder', '' );

rest_do_request( $request );

MY_Theme_JSON_Resolver::clean_cached_data();

return $test_theme_slug;
}

private function uninstall_theme( $theme_slug ) {
MY_Theme_JSON_Resolver::write_user_settings( array() );
delete_theme( $theme_slug );
}

private function activate_user_font() {

$font_dir = wp_get_font_dir();
$font_test_url = $font_dir['url'] . '/open-sans-normal-400.ttf';
$font_test_source = __DIR__ . '/data/fonts/OpenSans-Regular.ttf';
$font_test_destination = $font_dir['path'] . '/open-sans-normal-400.ttf';

if ( ! file_exists( $font_dir['path'] ) ) {
mkdir( $font_dir['path'] );
}
copy( $font_test_source, $font_test_destination );

$settings = array();
$settings['typography']['fontFamilies']['custom'] = array(
array(
'slug' => 'open-sans',
'name' => 'Open Sans',
'fontFamily' => 'Open Sans',
'fontFace' => array(
array(
'fontFamily' => 'Open Sans',
'fontStyle' => 'normal',
'fontWeight' => '400',
'src' => $font_test_url,
),
),
),
);

MY_Theme_JSON_Resolver::write_user_settings( $settings );
}

private function activate_font_in_theme_and_override_in_user() {

// Copy the font asset
$font_dir = get_stylesheet_directory() . '/assets/fonts/';
$font_test_source = __DIR__ . '/data/fonts/OpenSans-Regular.ttf';
$font_test_destination = $font_dir . '/open-sans-normal-400.ttf';

if ( ! file_exists( get_stylesheet_directory() . '/assets/' ) ) {
mkdir( get_stylesheet_directory() . '/assets/' );
}
if ( ! file_exists( get_stylesheet_directory() . '/assets/fonts/' ) ) {
mkdir( get_stylesheet_directory() . '/assets/fonts/' );
}

copy( $font_test_source, $font_test_destination );

// Add the font to the theme
$theme_json = MY_Theme_JSON_Resolver::get_theme_file_contents();
$theme_original_font_families = $theme_json['settings']['typography']['fontFamilies'];
$theme_json['settings']['typography']['fontFamilies'][] = array(
'slug' => 'open-sans',
'name' => 'Open Sans',
'fontFamily' => 'Open Sans',
'fontFace' => array(
array(
'fontFamily' => 'Open Sans',
'fontStyle' => 'normal',
'fontWeight' => '400',
'src' => 'file:./assets/fonts/open-sans-normal-400.ttf',
),
),
);
MY_Theme_JSON_Resolver::write_theme_file_contents( $theme_json );

// Deactivate the test font in the theme. To do this the 'theme' collection
// is overwritten to declare the intention of having it gone.
// Here we're writing the font family settings as they existed BEFORE we added
// the test font family to the theme.
$settings = array();
$settings['typography']['fontFamilies']['theme'] = $theme_original_font_families;
MY_Theme_JSON_Resolver::write_user_settings( $settings );
}


}