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

Background image: add support for absolute theme path URLs #60578

Closed
wants to merge 15 commits into from
Closed
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
19 changes: 18 additions & 1 deletion lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -2196,7 +2196,7 @@ protected static function compute_style_properties( $styles, $settings = array()
}
}

// Processes background styles.
// Processes background styles in order to build any `url()` functions.
if ( 'background' === $value_path[0] && isset( $styles['background'] ) ) {
$background_styles = gutenberg_style_engine_get_styles( array( 'background' => $styles['background'] ) );
$value = $background_styles['declarations'][ $css_property ] ?? $value;
Expand Down Expand Up @@ -4085,4 +4085,21 @@ protected static function get_valid_block_style_variations() {

return $valid_variations;
}

// @TODO abstract and test this.
public function resolve_relative_paths() {
// Styles backgrounds.
/*
* "theme" source implies relative path to the theme directory
*/
if ( ! empty( $this->theme_json['styles']['background']['backgroundImage']['url'] ) && is_string( $this->theme_json['styles']['background']['backgroundImage']['url'] ) ) {
$background_image_source = ! empty( $this->theme_json['styles']['background']['backgroundImage']['source'] ) ? $this->theme_json['styles']['background']['backgroundImage']['source'] : null;
if ( 'theme' === $background_image_source ) {
$this->theme_json['styles']['background']['backgroundImage']['url'] = esc_url( get_theme_file_uri( $this->theme_json['styles']['background']['backgroundImage']['url'] ) );
}
}
// Elements... (backgrounds not yet supported)

// Block variations... (backgrounds not yet supported)
}
}
3 changes: 3 additions & 0 deletions lib/class-wp-theme-json-resolver-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ public static function get_theme_data( $deprecated = array(), $options = array()
$theme_support_data['settings']['appearanceTools'] = true;
}
}

$with_theme_supports = new WP_Theme_JSON_Gutenberg( $theme_support_data );
$with_theme_supports->merge( static::$theme );
return $with_theme_supports;
Expand Down Expand Up @@ -615,11 +616,13 @@ public static function get_merged_data( $origin = 'custom' ) {
$result->merge( static::get_theme_data() );
if ( 'theme' === $origin ) {
$result->set_spacing_sizes();
$result->resolve_relative_paths();
return $result;
}

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

Expand Down
73 changes: 73 additions & 0 deletions lib/compat/wordpress-6.6/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,76 @@ function wp_api_template_access_controller( $args, $post_type ) {
}
}
add_filter( 'register_post_type_args', 'wp_api_template_access_controller', 10, 2 );


if ( ! function_exists( 'gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field' ) ) {
/**
* Adds `stylesheet_uri` fields to WP_REST_Themes_Controller class.
* Core ticket: https://core.trac.wordpress.org/ticket/61021
*/
function gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field() {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this needs to match WordPress/wordpress-develop#6399

register_rest_field(
'theme',
'stylesheet_uri',
array(
'get_callback' => function ( $item ) {
if ( ! empty( $item['stylesheet'] ) ) {
$theme = wp_get_theme( $item['stylesheet'] );
$current_theme = wp_get_theme();
if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) {
return get_stylesheet_directory_uri();
} else {
return $theme->get_stylesheet_directory_uri();
}
}

return null;
},
'schema' => array(
'type' => 'string',
'description' => __( 'The uri for the theme\'s stylesheet directory.', 'gutenberg' ),
'format' => 'uri',
'readonly' => true,
'context' => array( 'view', 'edit', 'embed' ),
),
)
);
}
}
add_action( 'rest_api_init', 'gutenberg_register_wp_rest_themes_stylesheet_directory_uri_field' );

if ( ! function_exists( 'gutenberg_register_wp_rest_themes_template_directory_uri_field' ) ) {
/**
* Adds `template_uri` fields to WP_REST_Themes_Controller class.
* Core ticket: https://core.trac.wordpress.org/ticket/61021
*/
function gutenberg_register_wp_rest_themes_template_directory_uri_field() {
register_rest_field(
'theme',
'template_uri',
array(
'get_callback' => function ( $item ) {
if ( ! empty( $item['stylesheet'] ) ) {
$theme = wp_get_theme( $item['stylesheet'] );
$current_theme = wp_get_theme();
if ( $theme->get_stylesheet() === $current_theme->get_stylesheet() ) {
return get_template_directory_uri();
} else {
return $theme->get_template_directory_uri();
}
}

return null;
},
'schema' => array(
'type' => 'string',
'description' => __( 'The uri for the theme\'s template directory. If this is a child theme, this refers to the parent theme, otherwise this is the same as the theme\'s stylesheet directory.', 'gutenberg' ),
'format' => 'uri',
'readonly' => true,
'context' => array( 'view', 'edit', 'embed' ),
),
)
);
}
}
add_action( 'rest_api_init', 'gutenberg_register_wp_rest_themes_template_directory_uri_field' );
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { TOOLSPANEL_DROPDOWNMENU_PROPS } from './utils';
import { setImmutably } from '../../utils/object';
import MediaReplaceFlow from '../media-replace-flow';
import { store as blockEditorStore } from '../../store';
import { unlock } from '../../lock-unlock';

const IMAGE_BACKGROUND_TYPE = 'image';
const DEFAULT_CONTROLS = {
Expand Down Expand Up @@ -201,6 +202,23 @@ function BackgroundImageToolsPanelItem( {
...inheritedValue?.background?.backgroundImage,
};

const { backgroundImageURL } = useSelect(
( select ) => {
const { getThemeFileURI } = unlock( select( blockEditorStore ) );
let file = url;
if (
!! style?.background?.backgroundImage?.url &&
style?.background?.backgroundImage?.source === 'theme'
) {
file = getThemeFileURI( style.background.backgroundImage.url );
}
return {
backgroundImageURL: file,
};
},
[ url ]
);

const replaceContainerRef = useRef();

const { createErrorNotice } = useDispatch( noticesStore );
Expand Down Expand Up @@ -295,15 +313,15 @@ function BackgroundImageToolsPanelItem( {
>
<MediaReplaceFlow
mediaId={ id }
mediaURL={ url }
mediaURL={ backgroundImageURL }
allowedTypes={ [ IMAGE_BACKGROUND_TYPE ] }
accept="image/*"
onSelect={ onSelectMedia }
name={
<InspectorImagePreview
label={ title }
filename={ title || __( 'Untitled' ) }
url={ url }
url={ backgroundImageURL }
/>
}
variant="secondary"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,34 @@
'letter-spacing: 2px',
] );
} );

it( 'should process styles and set CSS default values', () => {
const styles = {
background: {
backgroundImage: {
url: 'image.jpg',
source: 'theme',
},
},
};
const editorSettings = {
themeDirURI: 'http://example.com/theme',
};

expect(
getStylesDeclarations(
styles,
'.wp-block',
false,
{},
false,
editorSettings
)
).toEqual( [

Check failure on line 1016 in packages/block-editor/src/components/global-styles/test/use-global-styles-output.js

View workflow job for this annotation

GitHub Actions / JavaScript (Node.js 20) 4/4

Error: expect(received).toEqual(expected) // deep equality - Expected - 1 + Received + 1 Array [ - "background-image: url( 'http://example.com/theme/image.jpg' )", + "background-image: url( 'image.jpg' )", "background-size: cover", ] at Object.toEqual (/home/runner/work/gutenberg/gutenberg/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js:1016:6) at Promise.then.completed (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/utils.js:300:28) at new Promise (<anonymous>) at callAsyncCircusFn (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/utils.js:233:10) at _callCircusTest (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:315:40) at processTicksAndRejections (node:internal/process/task_queues:95:5) at _runTest (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:251:3) at _runTestsForDescribeBlock (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:125:9) at _runTestsForDescribeBlock (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:120:9) at _runTestsForDescribeBlock (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:120:9) at run (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:70:3) at runAndTransformResultsToJestFormat (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21) at jestAdapter (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19) at runTestInternal (/home/runner/work/gutenberg/gutenberg/node_modules/jest-runner/build/runTest.js:367:16) at runTest (/home/runner/work/gutenberg/gutenberg/node_modules/jest-runner/build/runTest.js:444:34) at Object.worker (/home/runner/work/gutenberg/gutenberg/node_modules/jest-runner/build/testWorker.js:106:12)

Check failure on line 1016 in packages/block-editor/src/components/global-styles/test/use-global-styles-output.js

View workflow job for this annotation

GitHub Actions / JavaScript (Node.js 21) 4/4

Error: expect(received).toEqual(expected) // deep equality - Expected - 1 + Received + 1 Array [ - "background-image: url( 'http://example.com/theme/image.jpg' )", + "background-image: url( 'image.jpg' )", "background-size: cover", ] at Object.toEqual (/home/runner/work/gutenberg/gutenberg/packages/block-editor/src/components/global-styles/test/use-global-styles-output.js:1016:6) at Promise.then.completed (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/utils.js:300:28) at new Promise (<anonymous>) at callAsyncCircusFn (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/utils.js:233:10) at _callCircusTest (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:315:40) at processTicksAndRejections (node:internal/process/task_queues:95:5) at _runTest (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:251:3) at _runTestsForDescribeBlock (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:125:9) at _runTestsForDescribeBlock (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:120:9) at _runTestsForDescribeBlock (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:120:9) at run (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/run.js:70:3) at runAndTransformResultsToJestFormat (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21) at jestAdapter (/home/runner/work/gutenberg/gutenberg/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19) at runTestInternal (/home/runner/work/gutenberg/gutenberg/node_modules/jest-runner/build/runTest.js:367:16) at runTest (/home/runner/work/gutenberg/gutenberg/node_modules/jest-runner/build/runTest.js:444:34) at Object.worker (/home/runner/work/gutenberg/gutenberg/node_modules/jest-runner/build/testWorker.js:106:12)
"background-image: url( 'http://example.com/theme/image.jpg' )",
'background-size: cover',
] );
} );
} );

describe( 'processCSSNesting', () => {
Expand Down
Original file line number Diff line number Diff line change
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 { setBackgroundStyleDefaults } from '../../hooks/background';

// 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 @@ -314,6 +315,7 @@ const getFeatureDeclarations = ( selectors, styles ) => {
* @param {Object} tree A theme.json tree containing layout definitions.
*
* @param {boolean} isTemplate Whether the entity being edited is a full template or a pattern.
* @param {Object} editorSettings Current editor settings.
* @return {Array} An array of style declarations.
*/
export function getStylesDeclarations(
Expand Down Expand Up @@ -391,6 +393,17 @@ export function getStylesDeclarations(
[]
);

/*
* Set styles defaults.
* Applies default values to the style object based on the block settings.
* Only applies to background styles for now.
*/
if ( !! blockStyles?.background ) {
blockStyles = setBackgroundStyleDefaults( blockStyles, {
Copy link
Member Author

@ramonjd ramonjd Apr 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will also cater for #60405 and #60100

selector,
} );
}

// The goal is to move everything to server side generated engine styles
// This is temporary as we absorb more and more styles into the engine.
const extraRules = getCSSRules( blockStyles );
Expand Down Expand Up @@ -947,19 +960,19 @@ export const toStyles = (
} );
}

// Process the remaining block styles (they use either normal block class or __experimentalSelector).
const declarations = getStylesDeclarations(
styles,
selector,
useRootPaddingAlign,
tree,
isTemplate
);
if ( declarations?.length ) {
ruleset += `:where(${ selector }){${ declarations.join(
';'
) };}`;
}
// Process the remaining block styles (they use either normal block class or __experimentalSelector).
const declarations = getStylesDeclarations(
styles,
selector,
useRootPaddingAlign,
tree,
isTemplate
);
if ( declarations?.length ) {
ruleset += `:where(${ selector }){${ declarations.join(
';'
) };}`;
}

// Check for pseudo selector in `styles` and handle separately.
const pseudoSelectorStyles = Object.entries( styles ).filter(
Expand Down Expand Up @@ -1219,9 +1232,12 @@ export function useGlobalStylesOutputWithConfig( mergedConfig = {} ) {
const [ blockGap ] = useGlobalSetting( 'spacing.blockGap' );
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 ) => {
const { getSettings } = select( blockEditorStore );
return !! getSettings().disableLayoutStyles;

const { disableLayoutStyles } = useSelect( ( select ) => {
const _settings = select( blockEditorStore ).getSettings();
return {
disableLayoutStyles: !! _settings.disableLayoutStyles,
};
} );

const blockContext = useContext( BlockContext );
Expand Down
Loading
Loading