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

Site global styles #50102

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
27ee2a3
adding site global styles post type in the backend
matiasbenedetto Apr 26, 2023
a32f1ee
Consuming site global styles from the client
matiasbenedetto Apr 26, 2023
2102a52
undo unwanted changes made merging from trunk
matiasbenedetto Apr 26, 2023
0ad0aa4
removing not needed variable
matiasbenedetto Apr 26, 2023
58fa7d9
post name as variable
matiasbenedetto Apr 26, 2023
f72324d
adding site to useGlobalStyle hook
matiasbenedetto Apr 28, 2023
1849eac
adding site to useGlobalSetting hook
matiasbenedetto Apr 28, 2023
f1be9f4
adding site to global styles context
matiasbenedetto Apr 28, 2023
82c3ef2
reset site styles when reset global styles to default is run
matiasbenedetto Apr 28, 2023
8158e3f
Make PHP linter happy
oandregal May 2, 2023
ed6b8fd
Enable site as a valid origin for data
oandregal May 2, 2023
c461e25
Add test for get_site_data_from_wp_global_styles
oandregal May 2, 2023
fc139bf
reverting unwanted change
matiasbenedetto May 2, 2023
ce3bb54
Adding PHPDoc for get_site_global_styles_post_id and get_site_data fu…
matiasbenedetto May 2, 2023
92206bf
get_merge_data: add support for site origin
oandregal May 2, 2023
844035b
get_site_data_from_wp_global_styles: add PHPDoc
oandregal May 2, 2023
f37bfb7
Update name of new filter
oandregal May 2, 2023
9e10570
add site global styles under 'site' key instead of 'custom' in global…
matiasbenedetto May 3, 2023
8f64434
REST controller: fix lint issue
oandregal May 4, 2023
f08658b
Add PHPDoc for get_site_item
oandregal May 4, 2023
79bb97f
Move every method after the properties
oandregal May 4, 2023
9e7c951
get_site_item: follow existing patterns
oandregal May 4, 2023
d4ba090
Remove unnecessary change
oandregal May 4, 2023
a45f8c4
Make linter happy
oandregal May 4, 2023
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
1 change: 1 addition & 0 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class WP_Theme_JSON_Gutenberg {
'default',
'blocks',
'theme',
'site',
'custom',
);

Expand Down
137 changes: 135 additions & 2 deletions lib/class-wp-theme-json-resolver-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class WP_Theme_JSON_Resolver_Gutenberg {
'core' => array(),
'blocks' => array(),
'theme' => array(),
'site' => array(),
'user' => array(),
);

Expand Down Expand Up @@ -64,6 +65,14 @@ class WP_Theme_JSON_Resolver_Gutenberg {
*/
protected static $user = null;

/**
* Container for data coming from the site.
*
* @since 6.3.0
* @var WP_Theme_JSON
*/
protected static $site = null;

/**
* Stores the ID of the custom post type
* that holds the user data.
Expand All @@ -73,6 +82,15 @@ class WP_Theme_JSON_Resolver_Gutenberg {
*/
protected static $user_custom_post_type_id = null;

/**
* Stores the ID of the custom post type
* that holds the site data.
*
* @since 6.3.0
* @var int
*/
protected static $site_custom_post_type_id = null;

/**
* Container to keep loaded i18n schema for `theme.json`.
*
Expand Down Expand Up @@ -478,6 +496,60 @@ public static function get_user_data_from_wp_global_styles( $theme, $create_post
return $user_cpt;
}

public static function get_site_data_from_wp_global_styles( $create_post = false, $post_status_filter = array( 'publish' ) ) {
$theme = wp_get_theme();

/*
* Bail early if the theme does not support a theme.json.
*
* Since wp_theme_has_theme_json only supports the active
* theme, the extra condition for whether $theme is the active theme is
* present here.
*/
if ( $theme->get_stylesheet() === get_stylesheet() && ! wp_theme_has_theme_json() ) {
return array();
}

$site_cpt = array();
$post_type_filter = 'wp_global_styles';
$post_name = 'wp-global-styles-site';
$args = array(
'posts_per_page' => 1,
'orderby' => 'date',
'order' => 'desc',
'post_type' => $post_type_filter,
'post_status' => $post_status_filter,
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'name' => $post_name,
);

$global_style_query = new WP_Query();
$recent_posts = $global_style_query->query( $args );
if ( count( $recent_posts ) === 1 ) {
$site_cpt = get_object_vars( $recent_posts[0] );
} elseif ( $create_post ) {
$cpt_post_id = wp_insert_post(
array(
'post_content' => '{"version": ' . WP_Theme_JSON_Gutenberg::LATEST_SCHEMA . ', "isGlobalStylesUserThemeJSON": true }',
'post_status' => 'publish',
'post_title' => 'Custom Styles Site', // Do not make string translatable, see https://core.trac.wordpress.org/ticket/54518.
'post_type' => $post_type_filter,
'post_name' => $post_name,
),
true
);
if ( ! is_wp_error( $cpt_post_id ) ) {
$site_cpt = get_object_vars( get_post( $cpt_post_id ) );
}
}

return $site_cpt;

}

/**
* Returns the user's origin config.
*
Expand Down Expand Up @@ -531,6 +603,52 @@ public static function get_user_data() {
return static::$user;
}

public static function get_site_data() {
matiasbenedetto marked this conversation as resolved.
Show resolved Hide resolved
if ( null !== static::$site && static::has_same_registered_blocks( 'site' ) ) {
return static::$site;
}

$config = array();
$site_cpt = static::get_site_data_from_wp_global_styles();

if ( array_key_exists( 'post_content', $site_cpt ) ) {
$decoded_data = json_decode( $site_cpt['post_content'], true );

$json_decoding_error = json_last_error();
if ( JSON_ERROR_NONE !== $json_decoding_error ) {
trigger_error( 'Error when decoding a theme.json schema for site data. ' . json_last_error_msg() );
/**
* Filters the data provided by the user for global styles & settings.
*
* @since 6.1.0
*
* @param WP_Theme_JSON_Data Class to access and update the underlying data.
*/
$theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'site' ) );
$config = $theme_json->get_data();
return new WP_Theme_JSON_Gutenberg( $config, 'site' );
}

// Very important to verify that the flag isGlobalStylesUserThemeJSON is true.
// If it's not true then the content was not escaped and is not safe.
if (
is_array( $decoded_data ) &&
isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) &&
$decoded_data['isGlobalStylesUserThemeJSON']
) {
unset( $decoded_data['isGlobalStylesUserThemeJSON'] );
$config = $decoded_data;
}
}

/** This filter is documented in wp-includes/class-wp-theme-json-resolver.php */
$theme_json = apply_filters( 'wp_theme_json_data_user', new WP_Theme_JSON_Data_Gutenberg( $config, 'site' ) );
$config = $theme_json->get_data();
static::$site = new WP_Theme_JSON_Gutenberg( $config, 'site' );

return static::$site;
}

/**
* Returns the data merged from multiple origins.
*
Expand Down Expand Up @@ -588,7 +706,7 @@ public static function get_merged_data( $origin = 'custom' ) {
$result->set_spacing_sizes();
return $result;
}

$result->merge( static::get_site_data() );
$result->merge( static::get_user_data() );
$result->set_spacing_sizes();
return $result;
Expand All @@ -607,7 +725,7 @@ public static function get_user_global_styles_post_id() {
return static::$user_custom_post_type_id;
}

$user_cpt = static::get_user_data_from_wp_global_styles( wp_get_theme(), true );
$user_cpt = static::get_user_data_from_wp_global_styles( wp_get_theme() );
matiasbenedetto marked this conversation as resolved.
Show resolved Hide resolved

if ( array_key_exists( 'ID', $user_cpt ) ) {
static::$user_custom_post_type_id = $user_cpt['ID'];
Expand All @@ -616,6 +734,20 @@ public static function get_user_global_styles_post_id() {
return static::$user_custom_post_type_id;
}

public static function get_site_global_styles_post_id() {
if ( null !== static::$site_custom_post_type_id ) {
return static::$site_custom_post_type_id;
}

$site_cpt = static::get_site_data_from_wp_global_styles( true );

if ( array_key_exists( 'ID', $site_cpt ) ) {
static::$site_custom_post_type_id = $site_cpt['ID'];
}

return static::$site_custom_post_type_id;
}

/**
* Determines whether the active theme has a theme.json file.
*
Expand Down Expand Up @@ -670,6 +802,7 @@ public static function clean_cached_data() {
);
static::$theme = null;
static::$user = null;
static::$site = null;
static::$user_custom_post_type_id = null;
static::$i18n_schema = null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,36 @@
* Base Global Styles REST API Controller.
*/
class Gutenberg_REST_Global_Styles_Controller_6_3 extends Gutenberg_REST_Global_Styles_Controller_6_2 {

/**
* Registers the controllers routes.
*
* @return void
*/
public function register_routes() {
parent::register_routes();

register_rest_route(
$this->namespace,
'/' . $this->rest_base,
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_site_item' ),
'permission_callback' => array( $this, 'get_theme_items_permissions_check' ),
),
)
);

}

public function get_site_item() {
$active_global_styles_site_id = WP_Theme_JSON_Resolver_Gutenberg::get_site_global_styles_post_id();
$active_global_styles_site = get_post( $active_global_styles_site_id );
$active_global_styles_site = $this->prepare_item_for_response( $active_global_styles_site, new WP_REST_Request() );
return $active_global_styles_site;
}

/**
* Revision controller.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ import { createContext } from '@wordpress/element';

export const DEFAULT_GLOBAL_STYLES_CONTEXT = {
user: {},
site: {},
base: {},
merged: {},
setUserConfig: () => {},
setSiteConfig: () => {},
};

export const GlobalStylesContext = createContext(
Expand Down
37 changes: 26 additions & 11 deletions packages/block-editor/src/components/global-styles/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,24 @@ const VALID_SETTINGS = [
];

export const useGlobalStylesReset = () => {
const { user: config, setUserConfig } = useContext( GlobalStylesContext );
const {
user: config,
setUserConfig,
setSiteConfig,
} = useContext( GlobalStylesContext );
const canReset = !! config && ! fastDeepEqual( config, EMPTY_CONFIG );
return [
canReset,
useCallback(
() => setUserConfig( () => EMPTY_CONFIG ),
[ setUserConfig ]
),
useCallback( () => {
setUserConfig( () => EMPTY_CONFIG );
setSiteConfig( () => EMPTY_CONFIG );
}, [ setUserConfig ] ),
];
};

export function useGlobalSetting( propertyPath, blockName, source = 'all' ) {
const { setUserConfig, ...configs } = useContext( GlobalStylesContext );
const { setUserConfig, setSiteConfig, ...configs } =
useContext( GlobalStylesContext );

const appendedBlockPath = blockName ? '.blocks.' + blockName : '';
const appendedPropertyPath = propertyPath ? '.' + propertyPath : '';
Expand Down Expand Up @@ -128,13 +133,14 @@ export function useGlobalSetting( propertyPath, blockName, source = 'all' ) {
appendedBlockPath,
] );

const setConfig = source === 'site' ? setSiteConfig : setUserConfig;
const setSetting = ( newValue ) => {
setUserConfig( ( currentConfig ) => {
setConfig( ( currentConfig ) => {
// Deep clone `currentConfig` to avoid mutating it later.
const newUserConfig = JSON.parse( JSON.stringify( currentConfig ) );
set( newUserConfig, contextualPath, newValue );
const newConfig = JSON.parse( JSON.stringify( currentConfig ) );
set( newConfig, contextualPath, newValue );

return newUserConfig;
return newConfig;
} );
};

Expand All @@ -151,15 +157,18 @@ export function useGlobalStyle(
merged: mergedConfig,
base: baseConfig,
user: userConfig,
site: siteConfig,
setUserConfig,
setSiteConfig,
} = useContext( GlobalStylesContext );
const appendedPath = path ? '.' + path : '';
const finalPath = ! blockName
? `styles${ appendedPath }`
: `styles.blocks.${ blockName }${ appendedPath }`;

const setStyle = ( newValue ) => {
setUserConfig( ( currentConfig ) => {
const setConfig = source === 'site' ? setSiteConfig : setUserConfig;
setConfig( ( currentConfig ) => {
// Deep clone `currentConfig` to avoid mutating it later.
const newUserConfig = JSON.parse( JSON.stringify( currentConfig ) );
set(
Expand Down Expand Up @@ -196,6 +205,12 @@ export function useGlobalStyle(
? getValueFromVariable( mergedConfig, blockName, rawResult )
: rawResult;
break;
case 'site':
rawResult = get( siteConfig, finalPath );
result = shouldDecodeEncode
? getValueFromVariable( mergedConfig, blockName, rawResult )
: rawResult;
break;
case 'base':
rawResult = get( baseConfig, finalPath );
result = shouldDecodeEncode
Expand Down
9 changes: 9 additions & 0 deletions packages/core-data/src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ export function __experimentalReceiveCurrentGlobalStylesId(
};
}

export function __experimentalReceiveCurrentSiteGlobalStylesId(
currentSiteGlobalStylesId
) {
return {
type: 'RECEIVE_CURRENT_SITE_GLOBAL_STYLES_ID',
id: currentSiteGlobalStylesId,
};
}

/**
* Returns an action object used in signalling that the theme base global styles have been received
* Ignored from documentation as it's internal to the data store.
Expand Down
8 changes: 8 additions & 0 deletions packages/core-data/src/entities.js
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ export const rootEntitiesConfig = [
plural: 'globalStylesVariations', // Should be different than name.
getTitle: ( record ) => record?.title?.rendered || record?.title,
},
{
label: __( 'Global Styles Site' ),
name: 'siteGlobalStyles',
kind: 'root',
baseURL: '/wp/v2/global-styles',
baseURLParams: { context: 'edit' },
getTitle: ( record ) => record?.title?.rendered || record?.title,
},
{
label: __( 'Themes' ),
name: 'theme',
Expand Down
10 changes: 10 additions & 0 deletions packages/core-data/src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,15 @@ export function themeBaseGlobalStyles( state = {}, action ) {
return state;
}

export function currentSiteGlobalStylesId( state = undefined, action ) {
switch ( action.type ) {
case 'RECEIVE_CURRENT_SITE_GLOBAL_STYLES_ID':
return action.id;
}

return state;
}

/**
* Reducer managing the theme global styles variations.
*
Expand Down Expand Up @@ -647,6 +656,7 @@ export default combineReducers( {
users,
currentTheme,
currentGlobalStylesId,
currentSiteGlobalStylesId,
currentUser,
themeGlobalStyleVariations,
themeBaseGlobalStyles,
Expand Down
Loading