diff --git a/includes/class-create-block-theme-api.php b/includes/class-create-block-theme-api.php index b6f6c241..a04a8b8f 100644 --- a/includes/class-create-block-theme-api.php +++ b/includes/class-create-block-theme-api.php @@ -157,6 +157,17 @@ public function register_rest_routes() { }, ), ); + register_rest_route( + 'create-block-theme/v1', + '/font-families', + array( + 'methods' => 'GET', + 'callback' => array( $this, 'rest_get_font_families' ), + 'permission_callback' => function () { + return current_user_can( 'edit_theme_options' ); + }, + ), + ); } function rest_get_theme_data( $request ) { @@ -497,6 +508,24 @@ function rest_save_theme( $request ) { ); } + /** + * Get a list of all the font families used in the theme. + * + * It includes the font families from the theme.json data (theme.json file + global styles) and the theme style variations. + * The font families with font faces containing src urls relative to the theme folder are converted to absolute urls. + */ + function rest_get_font_families( $request ) { + $font_families = CBT_Theme_Fonts::get_all_fonts(); + + return new WP_REST_Response( + array( + 'status' => 'SUCCESS', + 'message' => __( 'Font Families retrieved.', 'create-block-theme' ), + 'data' => $font_families, + ) + ); + } + private function sanitize_theme_data( $theme ) { $sanitized_theme['name'] = sanitize_text_field( $theme['name'] ); $sanitized_theme['description'] = sanitize_text_field( $theme['description'] ?? '' ); diff --git a/includes/create-theme/theme-fonts.php b/includes/create-theme/theme-fonts.php index adf30120..e2539c1d 100644 --- a/includes/create-theme/theme-fonts.php +++ b/includes/create-theme/theme-fonts.php @@ -3,6 +3,75 @@ class CBT_Theme_Fonts { + + /** + * Make the font face theme src urls absolute. + * + * It replaces the 'file:./' prefix with the theme directory uri. + * + * Example: 'file:./assets/fonts/my-font.ttf' -> 'http://example.com/wp-content/themes/my-theme/assets/fonts/my-font.ttf' + * Example: [ 'https://example.com/assets/fonts/my-font.ttf' ] -> [ 'https://example.com/assets/fonts/my-font.ttf' ] + * + * @param array|string $src + * @return array|string + */ + private static function make_theme_font_src_absolute( $src ) { + $make_absolute = function ( $url ) { + if ( str_starts_with( $url, 'file:./' ) ) { + return str_replace( 'file:./', get_stylesheet_directory_uri() . '/', $url ); + } + return $url; + }; + + if ( is_array( $src ) ) { + foreach ( $src as &$url ) { + $url = $make_absolute( $url ); + } + } else { + $src = $make_absolute( $src ); + } + + return $src; + } + + /** + * Get all fonts from the theme.json data + all the style variations. + * + * @return array + */ + public static function get_all_fonts() { + $font_families = array(); + $theme = CBT_Theme_JSON_Resolver::get_merged_data(); + $settings = $theme->get_settings(); + + if ( isset( $settings['typography']['fontFamilies']['theme'] ) ) { + $font_families = array_merge( $font_families, $settings['typography']['fontFamilies']['theme'] ); + } + + if ( isset( $settings['typography']['fontFamilies']['custom'] ) ) { + $font_families = array_merge( $font_families, $settings['typography']['fontFamilies']['custom'] ); + } + + $variations = CBT_Theme_JSON_Resolver::get_style_variations(); + + foreach ( $variations as $variation ) { + if ( isset( $variation['settings']['typography']['fontFamilies']['theme'] ) ) { + $font_families = array_merge( $font_families, $variation['settings']['typography']['fontFamilies']['theme'] ); + } + } + + // Iterates through the font families and makes the urls absolute to use in the frontend code. + foreach ( $font_families as &$font_family ) { + if ( isset( $font_family['fontFace'] ) ) { + foreach ( $font_family['fontFace'] as &$font_face ) { + $font_face['src'] = CBT_Theme_Fonts::make_theme_font_src_absolute( $font_face['src'] ); + } + } + } + + return $font_families; + } + /** * Copy any ACTIVATED fonts from USER configuration to THEME configuration including any font face assets. * Remove any DEACTIVATED fronts from the THEME configuration. diff --git a/tests/test-theme-fonts.php b/tests/test-theme-fonts.php index dee50090..e1a3aeff 100644 --- a/tests/test-theme-fonts.php +++ b/tests/test-theme-fonts.php @@ -101,12 +101,121 @@ public function test_remove_deactivated_fonts_from_theme() { $this->uninstall_theme( $test_theme_slug ); } + public function test_get_all_fonts_just_theme() { + + wp_set_current_user( self::$admin_id ); + + $test_theme_slug = $this->create_blank_theme(); + + $theme_json = CBT_Theme_JSON_Resolver::get_theme_file_contents(); + $theme_json['settings']['typography']['fontFamilies'] = array( + 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', + ), + ), + ), + array( + 'slug' => 'closed-sans', + 'name' => 'Closed Sans', + 'fontFamily' => 'Closed Sans', + 'fontFace' => array( + array( + 'fontFamily' => 'Closed Sans', + 'fontStyle' => 'normal', + 'fontWeight' => '400', + 'src' => 'http://example.com/closed-sans-normal-400.ttf', + ), + ), + ), + ); + CBT_Theme_JSON_Resolver::write_theme_file_contents( $theme_json ); + + $fonts = CBT_Theme_Fonts::get_all_fonts(); + + $this->assertCount( 2, $fonts ); + $this->assertEquals( 'open-sans', $fonts[0]['slug'] ); + $this->assertEquals( 'closed-sans', $fonts[1]['slug'] ); + $this->assertStringNotContainsString( 'file:.', $fonts[0]['fontFace'][0]['src'] ); + $this->assertStringNotContainsString( 'file:.', $fonts[1]['fontFace'][0]['src'] ); + + $this->uninstall_theme( $test_theme_slug ); + } + + public function test_get_all_fonts_from_theme_and_variation() { + + wp_set_current_user( self::$admin_id ); + + $test_theme_slug = $this->create_blank_theme(); + + $theme_json = CBT_Theme_JSON_Resolver::get_theme_file_contents(); + $theme_json['settings']['typography']['fontFamilies'] = array( + 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', + ), + ), + ), + ); + CBT_Theme_JSON_Resolver::write_theme_file_contents( $theme_json ); + + $variation_json = array( + 'version' => '2', + 'title' => 'Variation', + ); + $variation_json['settings']['typography']['fontFamilies'] = array( + array( + 'slug' => 'closed-sans', + 'name' => 'Closed Sans', + 'fontFamily' => 'Closed Sans', + 'fontFace' => array( + array( + 'fontFamily' => 'Closed Sans', + 'fontStyle' => 'normal', + 'fontWeight' => '400', + 'src' => 'http://example.com/closed-sans-normal-400.ttf', + ), + ), + ), + ); + + // Save the variation + $variation_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'styles' . DIRECTORY_SEPARATOR; + $variation_slug = 'variation'; + wp_mkdir_p( $variation_path ); + file_put_contents( + $variation_path . $variation_slug . '.json', + wp_json_encode( $variation_json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) + ); + + $fonts = CBT_Theme_Fonts::get_all_fonts(); + + $this->assertCount( 2, $fonts ); + $this->assertEquals( 'open-sans', $fonts[0]['slug'] ); + $this->assertEquals( 'closed-sans', $fonts[1]['slug'] ); + $this->assertStringNotContainsString( 'file:.', $fonts[0]['fontFace'][0]['src'] ); + $this->assertStringNotContainsString( 'file:.', $fonts[1]['fontFace'][0]['src'] ); + + $this->uninstall_theme( $test_theme_slug ); + + } + private function save_theme() { CBT_Theme_Fonts::persist_font_settings(); - // CBT_Theme_Templates::add_templates_to_local( 'all' ); - // CBT_Theme_JSON::add_theme_json_to_local( 'all' ); - // CBT_Theme_Styles::clear_user_styles_customizations(); - // CBT_Theme_Templates::clear_user_templates_customizations(); } private function create_blank_theme() {