Skip to content

Commit

Permalink
Backend resolution of theme file URIs for global styles.
Browse files Browse the repository at this point in the history
  • Loading branch information
ramonjd committed May 8, 2024
1 parent 444bbc6 commit 32906b9
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 18 deletions.
17 changes: 12 additions & 5 deletions lib/class-wp-rest-global-styles-controller-gutenberg.php
Expand Up @@ -607,17 +607,19 @@ public function get_theme_item( $request ) {
);
}

$theme = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( 'theme' );
$data = array();
$fields = $this->get_fields_for_response( $request );
$theme = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( 'theme' );
$data = array();
$fields = $this->get_fields_for_response( $request );
$resolved_theme_uris = array();

if ( rest_is_field_included( 'settings', $fields ) ) {
$data['settings'] = $theme->get_settings();
}

if ( rest_is_field_included( 'styles', $fields ) ) {
$raw_data = $theme->get_raw_data();
$data['styles'] = isset( $raw_data['styles'] ) ? $raw_data['styles'] : array();
$raw_data = $theme->get_raw_data();
$data['styles'] = isset( $raw_data['styles'] ) ? $raw_data['styles'] : array();
$resolved_theme_uris = WP_Theme_JSON_Resolver_Gutenberg::get_resolved_theme_uris( $theme );
}

$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
Expand All @@ -632,6 +634,11 @@ public function get_theme_item( $request ) {
'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ),
),
);

if ( ! empty( $resolved_theme_uris ) ) {
$links['theme_file_uris'] = $resolved_theme_uris;
}

$response->add_links( $links );
}

Expand Down
50 changes: 40 additions & 10 deletions lib/class-wp-theme-json-resolver-gutenberg.php
Expand Up @@ -604,7 +604,6 @@ public static function get_merged_data( $origin = 'custom' ) {
$result->merge( static::get_core_data() );
if ( 'default' === $origin ) {
$result->set_spacing_sizes();
$result = static::resolve_theme_file_uris( $result );
return $result;
}

Expand All @@ -616,13 +615,11 @@ public static function get_merged_data( $origin = 'custom' ) {
$result->merge( static::get_theme_data() );
if ( 'theme' === $origin ) {
$result->set_spacing_sizes();
$result = static::resolve_theme_file_uris( $result );
return $result;
}

$result->merge( static::get_user_data() );
$result->set_spacing_sizes();
$result = static::resolve_theme_file_uris( $result );
return $result;
}

Expand Down Expand Up @@ -753,12 +750,16 @@ public static function get_style_variations() {
foreach ( $variation_files as $path => $file ) {
$decoded_file = wp_json_file_decode( $path, array( 'associative' => true ) );
if ( is_array( $decoded_file ) ) {
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
$with_resolved_paths = static::resolve_theme_file_uris( new WP_Theme_JSON_Gutenberg( $translated ) );
$variation = $with_resolved_paths->get_raw_data();
$translated = static::translate( $decoded_file, wp_get_theme()->get( 'TextDomain' ) );
$variation_theme_json = new WP_Theme_JSON_Gutenberg( $translated );
$resolved_theme_uris = WP_Theme_JSON_Resolver_Gutenberg::get_resolved_theme_uris( $variation_theme_json );
$variation = $variation_theme_json->get_raw_data();
if ( empty( $variation['title'] ) ) {
$variation['title'] = basename( $path, '.json' );
}
if ( ! empty( $resolved_theme_uris ) ) {
$variation['_links']['theme_file_uris'] = $resolved_theme_uris;
}
$variations[] = $variation;
}
}
Expand All @@ -767,14 +768,43 @@ public static function get_style_variations() {


/**
* Resolves relative paths in theme.json styles to theme absolute paths.
* Resolves relative paths in theme.json styles to theme absolute paths
* and returns them in an array that can be embedded in a REST response.
*
* @since 6.6.0
*
* @param WP_Theme_JSON_Gutenberg $theme_json A theme json instance.
* @return WP_Theme_JSON_Gutenberg The theme json instance with merged resolved paths.
* @return array An array of resolved paths.
*/
protected static function resolve_theme_file_uris( $theme_json ) {
public static function get_resolved_theme_uris( $theme_json ) {
if ( ! $theme_json instanceof WP_Theme_JSON_Gutenberg ) {
return $theme_json;
}

$theme_json_data = $theme_json->get_raw_data();
$resolved_theme_uris = array();

/*
* Styles backgrounds.
* Where a URL is not absolute (has no host fragment), it is assumed to be relative to the theme directory.
* Blocks, elements, and block variations are not yet supported.
*/
if (
isset( $theme_json_data['styles']['background']['backgroundImage']['url'] ) &&
is_string( $theme_json_data['styles']['background']['backgroundImage']['url'] ) &&
! isset( wp_parse_url( $theme_json_data['styles']['background']['backgroundImage']['url'] )['host'] ) ) {
$resolved_theme_uris[] = array(
'file' => $theme_json_data['styles']['background']['backgroundImage']['url'],
'href' => esc_url( get_theme_file_uri( $theme_json_data['styles']['background']['backgroundImage']['url'] ) ),
);
}

return $resolved_theme_uris;
}

// @TODO used in gutenberg_get_global_stylesheet to ensure global stylesheet URIs are resolved.
// Try to harmonize with the above function
public static function resolve_theme_file_uris( $theme_json ) {
if ( ! $theme_json instanceof WP_Theme_JSON_Gutenberg ) {
return $theme_json;
}
Expand All @@ -793,7 +823,7 @@ protected static function resolve_theme_file_uris( $theme_json ) {
isset( $theme_json_data['styles']['background']['backgroundImage']['url'] ) &&
is_string( $theme_json_data['styles']['background']['backgroundImage']['url'] ) &&
! isset( wp_parse_url( $theme_json_data['styles']['background']['backgroundImage']['url'] )['host'] ) ) {
$resolved_theme_json_data['styles']['background']['backgroundImage']['url'] = esc_url( get_theme_file_uri( $theme_json_data['styles']['background']['backgroundImage']['url'] ) );
$resolved_theme_json_data['styles']['background']['backgroundImage']['url'] = esc_url( get_theme_file_uri( $theme_json_data['styles']['background']['backgroundImage']['url'] ) );
}

if ( ! empty( $resolved_theme_json_data ) ) {
Expand Down
1 change: 1 addition & 0 deletions lib/global-styles-and-settings.php
Expand Up @@ -28,6 +28,7 @@ function gutenberg_get_global_stylesheet( $types = array() ) {
}
}
$tree = WP_Theme_JSON_Resolver_Gutenberg::get_merged_data();
$tree = WP_Theme_JSON_Resolver_Gutenberg::resolve_theme_file_uris( $tree );

$supports_theme_json = wp_theme_has_theme_json();
if ( empty( $types ) && ! $supports_theme_json ) {
Expand Down
@@ -0,0 +1,38 @@
/**
* WordPress dependencies
*/
import { isURL, isValidPath } from '@wordpress/url';

function isRelativePath( url ) {
return isValidPath( url ) && ! isURL( url );
}

function getThemeFileURI( file, themeFileURIs = [] ) {
if ( ! isRelativePath( file ) ) {
return;
}

return themeFileURIs.find( ( themeFileUri ) => themeFileUri.file === file );
}

function setUnresolvedThemeFilePaths( config ) {
const themeFileURIs = config._links.theme_file_uris;
const backgroundImageUrl = getThemeFileURI(
config?.styles?.background?.backgroundImage?.url,
themeFileURIs
);

// Top level styles.
if ( !! backgroundImageUrl?.href ) {
config.styles.background.backgroundImage.url = backgroundImageUrl.href;
}

return config;
}

export default function useGetThemeFileURIs( mergedConfig ) {
if ( ! mergedConfig?.styles || ! mergedConfig?._links?.theme_file_uris ) {
return mergedConfig;
}
return setUnresolvedThemeFilePaths( mergedConfig );
}
Expand Up @@ -35,6 +35,7 @@ import { LAYOUT_DEFINITIONS } from '../../layouts/definitions';
import { getValueFromObjectPath, setImmutably } from '../../utils/object';
import BlockContext from '../block-context';
import { unlock } from '../../lock-unlock';
import useGetThemeFileUris from './use-get-theme-file-uris';

// List of block support features that can have their related styles
// generated under their own feature level selector rather than the block's.
Expand Down Expand Up @@ -1217,6 +1218,7 @@ export function processCSSNesting( css, blockSelector ) {
*/
export function useGlobalStylesOutputWithConfig( mergedConfig = {} ) {
const [ blockGap ] = useGlobalSetting( 'spacing.blockGap' );
const withResolvedThemeURIs = useGetThemeFileUris( mergedConfig );
const hasBlockGapSupport = blockGap !== null;
const hasFallbackGapSupport = ! hasBlockGapSupport; // This setting isn't useful yet: it exists as a placeholder for a future explicit fallback styles support.
const disableLayoutStyles = useSelect( ( select ) => {
Expand All @@ -1231,10 +1233,15 @@ export function useGlobalStylesOutputWithConfig( mergedConfig = {} ) {
const { getBlockStyles } = useSelect( blocksStore );

return useMemo( () => {
if ( ! mergedConfig?.styles || ! mergedConfig?.settings ) {
if (
! withResolvedThemeURIs?.styles ||
! withResolvedThemeURIs?.settings
) {
return [];
}
const updatedConfig = updateConfigWithSeparator( mergedConfig );
const updatedConfig = updateConfigWithSeparator(
withResolvedThemeURIs
);

const blockSelectors = getBlockSelectors(
getBlockTypes(),
Expand Down Expand Up @@ -1297,7 +1304,7 @@ export function useGlobalStylesOutputWithConfig( mergedConfig = {} ) {
}, [
hasBlockGapSupport,
hasFallbackGapSupport,
mergedConfig,
withResolvedThemeURIs,
disableLayoutStyles,
isTemplate,
getBlockStyles,
Expand Down
Expand Up @@ -22,6 +22,9 @@ const { GlobalStylesContext, areGlobalStyleConfigsEqual } = unlock(
);

export default function Variation( { variation, children, isPill } ) {
// @TODO _links need to be merged as well somehow so that
// they are always returned in "mergedConfig" in the global-styles-provider.
// console.log( 'variation', variation );
const [ isFocused, setIsFocused ] = useState( false );
const { base, user, setUserConfig } = useContext( GlobalStylesContext );
const context = useMemo(
Expand Down

0 comments on commit 32906b9

Please sign in to comment.