Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copy font assets to the local theme folder when creating a style variation #713

Merged
merged 6 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion includes/class-create-block-theme-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,15 @@ function rest_create_child_theme( $request ) {
}

function rest_create_variation( $request ) {
$options = $request->get_params();

$save_fonts = isset( $options['saveFonts'] ) && true === $options['saveFonts'];

$response = CBT_Theme_JSON::add_theme_json_variation_to_local( 'variation', $this->sanitize_theme_data( $request->get_params() ) );
$response = CBT_Theme_JSON::add_theme_json_variation_to_local(
'variation',
$this->sanitize_theme_data( $options ),
$save_fonts
);

wp_cache_flush();

Expand Down
35 changes: 28 additions & 7 deletions includes/create-theme/resolver_additions.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,7 @@ public static function export_theme_data( $content, $extra_theme_data = null ) {
}

// Merge the User Data
if ( class_exists( 'WP_Theme_JSON_Resolver_Gutenberg' ) ) {
$theme->merge( WP_Theme_JSON_Resolver_Gutenberg::get_user_data() );
} else {
$theme->merge( static::get_user_data() );
}
$theme->merge( static::get_user_data() );

// Merge the extra theme data received as a parameter
if ( ! empty( $extra_theme_data ) ) {
Expand All @@ -93,8 +89,33 @@ public static function export_theme_data( $content, $extra_theme_data = null ) {
$schema = 'https://schemas.wp.org/' . $theme_json_version . '/theme.json';
}
$data['$schema'] = $schema;
$theme_json = wp_json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
return preg_replace( '~(?:^|\G)\h{4}~m', "\t", $theme_json );
return static::stringify( $data );
}

/**
* Get the user data.
*
* This is a copy of the parent function with the addition of the Gutenberg resolver.
*
* @return array
*/
public static function get_user_data() {
// Determine the correct method to retrieve user data
return class_exists( 'WP_Theme_JSON_Resolver_Gutenberg' )
? WP_Theme_JSON_Resolver_Gutenberg::get_user_data()
: parent::get_user_data();
}

/**
* Stringify the array data.
*
* $data is an array of data to be converted to a JSON string.
* @return string JSON string.
*/
public static function stringify( $data ) {
$data = wp_json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
// Convert spaces to tabs
return preg_replace( '~(?:^|\G)\h{4}~m', "\t", $data );
}

public static function get_theme_file_contents() {
Expand Down
36 changes: 26 additions & 10 deletions includes/create-theme/theme-fonts.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,19 +112,18 @@ public static function make_filename_from_fontface( $font_face, $src, $src_index
return $font_filename;
}

public static function copy_activated_fonts_to_theme() {
$font_families_to_copy = self::get_user_activated_fonts();

if ( is_null( $font_families_to_copy ) ) {
return;
}

$theme_json = CBT_Theme_JSON_Resolver::get_theme_file_contents();
/*
* Copy the font assets to the theme.
*
* @param array $font_families The font families to copy.
* @return array $font_families The font families with the font face src updated to the theme font asset location.
*/
public static function copy_font_assets_to_theme( $font_families ) {
$theme_font_asset_location = path_join( get_stylesheet_directory(), 'assets/fonts/' );
// Create the font asset directory if it does not exist.
wp_mkdir_p( $theme_font_asset_location );

foreach ( $font_families_to_copy as &$font_family ) {
foreach ( $font_families as &$font_family ) {
if ( ! isset( $font_family['fontFace'] ) ) {
continue;
}
Expand All @@ -139,6 +138,10 @@ public static function copy_activated_fonts_to_theme() {
// if it is a string, cast it to an array
$font_face['src'] = (array) $font_face['src'];
foreach ( $font_face['src'] as $font_src_index => &$font_src ) {
if ( str_starts_with( $font_src, 'file:' ) ) {
// If the font source starts with 'file:' then it's already a theme asset.
continue;
}
$font_filename = basename( $font_src );
$font_pretty_filename = self::make_filename_from_fontface( $font_face, $font_src, $font_src_index );
$font_face_path = path_join( $font_family_dir_path, $font_pretty_filename );
Expand All @@ -158,9 +161,22 @@ public static function copy_activated_fonts_to_theme() {
}
}

return $font_families;
}

public static function copy_activated_fonts_to_theme() {
$font_families_to_copy = self::get_user_activated_fonts();

if ( is_null( $font_families_to_copy ) ) {
return;
}

$theme_json = CBT_Theme_JSON_Resolver::get_theme_file_contents();
$copied_font_families = self::copy_font_assets_to_theme( $font_families_to_copy );

$theme_json['settings']['typography']['fontFamilies'] = array_merge(
$theme_json['settings']['typography']['fontFamilies'] ?? array(),
$font_families_to_copy
$copied_font_families
);

$user_settings = CBT_Theme_JSON_Resolver::get_user_data()->get_settings();
Expand Down
30 changes: 20 additions & 10 deletions includes/create-theme/theme-json.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static function add_theme_json_to_local( $export_type ) {
);
}

public static function add_theme_json_variation_to_local( $export_type, $theme ) {
public static function add_theme_json_variation_to_local( $export_type, $theme, $save_fonts = false ) {
$variation_path = get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'styles' . DIRECTORY_SEPARATOR;

if ( ! file_exists( $variation_path ) ) {
Expand All @@ -20,18 +20,28 @@ public static function add_theme_json_variation_to_local( $export_type, $theme )
return new WP_Error( 'variation_already_exists', __( 'Variation already exists.', 'create-block-theme' ) );
}

$_POST['theme']['variation_slug'] = $theme['slug'];

$extra_theme_data = array(
'version' => WP_Theme_JSON::LATEST_SCHEMA,
'title' => $theme['name'],
);

$variation_theme_json = CBT_Theme_JSON_Resolver::export_theme_data( $export_type, $extra_theme_data );
$theme_json = class_exists( 'WP_Theme_JSON_Gutenberg' ) ? new WP_Theme_JSON_Gutenberg() : new WP_Theme_JSON();
$user_data = CBT_Theme_JSON_Resolver::get_user_data();
$theme_json->merge( $user_data );
$variation = $theme_json->get_data();
$variation['title'] = $theme['name'];

if (
$save_fonts &&
isset( $variation['settings']['typography']['fontFamilies'] )
) {
$font_families = $variation['settings']['typography']['fontFamilies'];
// Copy the font assets to the theme assets folder.
$copied_font_families = CBT_Theme_Fonts::copy_font_assets_to_theme( $font_families );
// Update the the variation theme json with the font families with the new paths.
$variation['settings']['typography']['fontFamilies'] = $copied_font_families;
}

file_put_contents(
$variation_path . $theme['slug'] . '.json',
$variation_theme_json
CBT_Theme_JSON_Resolver::stringify( $variation )
);

return $variation;
}
}
99 changes: 80 additions & 19 deletions src/editor-sidebar/create-variation-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,67 @@
*/
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';
import { useDispatch } from '@wordpress/data';
import { useDispatch, useSelect } from '@wordpress/data';
import { store as noticesStore } from '@wordpress/notices';
import {
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalVStack as VStack,
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalText as Text,
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalSpacer as Spacer,
// eslint-disable-next-line @wordpress/no-unsafe-wp-apis
__experimentalView as View,
PanelBody,
Button,
TextControl,
CheckboxControl,
} from '@wordpress/components';
import { copy } from '@wordpress/icons';
import { store as preferencesStore } from '@wordpress/preferences';

/**
* Internal dependencies
*/
import { postCreateThemeVariation } from '../resolvers';
import ScreenHeader from './screen-header';

const PREFERENCE_SCOPE = 'create-block-theme';
const PREFERENCE_KEY = 'create-variation';

export const CreateVariationPanel = () => {
const { createErrorNotice } = useDispatch( noticesStore );

const [ theme, setTheme ] = useState( {
name: '',
} );

const preference = useSelect( ( select ) => {
const _preference = select( preferencesStore ).get(
PREFERENCE_SCOPE,
PREFERENCE_KEY
);
return {
saveFonts: _preference?.saveFonts ?? true,
};
}, [] );

const handleTogglePreference = ( key ) => {
setPreference( PREFERENCE_SCOPE, PREFERENCE_KEY, {
...preference,
[ key ]: ! preference[ key ],
} );
};

const { set: setPreference } = useDispatch( preferencesStore );

const handleCreateVariationClick = () => {
postCreateThemeVariation( theme.name )
const variationPreferences = {
name: theme.name,
...preference,
};

postCreateThemeVariation( variationPreferences )
.then( () => {
// eslint-disable-next-line no-alert
window.alert(
Expand All @@ -57,29 +90,57 @@ export const CreateVariationPanel = () => {
<ScreenHeader
title={ __( 'Create Variation', 'create-block-theme' ) }
/>

<VStack>
<Text>
<Text as="p">
{ __(
'Save the Global Styles changes as a theme variation.',
'create-block-theme'
) }
</Text>
<br />
<TextControl
label={ __( 'Variation name', 'create-block-theme' ) }
value={ theme.name }
onChange={ ( value ) =>
setTheme( { ...theme, name: value } )
}
/>
<br />
<Button
icon={ copy }
variant="primary"
onClick={ handleCreateVariationClick }
>
{ __( 'Create Theme Variation', 'create-block-theme' ) }
</Button>

<View>
<Spacer paddingY={ 4 }>
<VStack>
<TextControl
label={ __(
'Variation name',
'create-block-theme'
) }
value={ theme.name }
onChange={ ( value ) =>
setTheme( { ...theme, name: value } )
}
/>

<CheckboxControl
label={ __(
'Save Fonts',
'create-block-theme'
) }
help={ __(
'Copy the font assets to the theme folder.',
'create-block-theme'
) }
checked={ preference.saveFonts }
onChange={ () =>
handleTogglePreference( 'saveFonts' )
}
/>

<Button
icon={ copy }
variant="primary"
onClick={ handleCreateVariationClick }
>
{ __(
'Create Theme Variation',
'create-block-theme'
) }
</Button>
</VStack>
</Spacer>
</View>
</VStack>
</PanelBody>
);
Expand Down
4 changes: 2 additions & 2 deletions src/resolvers.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ export async function fetchReadmeData() {
} );
}

export async function postCreateThemeVariation( name ) {
export async function postCreateThemeVariation( preferences ) {
return apiFetch( {
path: '/create-block-theme/v1/create-variation',
method: 'POST',
data: { name },
data: preferences,
headers: {
'Content-Type': 'application/json',
},
Expand Down
Loading