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

Behaviors: Extend Global Styles API to read/write behaviors config. #52370

Merged
merged 32 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
97375fc
Add behaviors to global styles API
cbravobernal Jul 6, 2023
e2b65f6
Add behaviors to global styles API endpoint
cbravobernal Jul 6, 2023
7a6798b
Fix coding standards warnings
cbravobernal Jul 6, 2023
82e1f1c
Add behavior selector to the site editor, should read for theme.json
cbravobernal Jul 6, 2023
358194d
Now the database saves global behaviors
cbravobernal Jul 6, 2023
234904d
Fix selector value according to behavior selected
cbravobernal Jul 7, 2023
8f2f1c2
Add animation to the selector
cbravobernal Jul 7, 2023
df3f027
Remove not needed themebehaviors
cbravobernal Jul 7, 2023
cdc2590
Use settings for the display
cbravobernal Jul 7, 2023
8f123a8
Show theme json default animation in selector
cbravobernal Jul 7, 2023
c439ff9
If all behaviors are disabled, prevent selector showing on site editor
cbravobernal Jul 7, 2023
0cc415c
Define set function
cbravobernal Jul 10, 2023
1101d4c
Fix if settings behaviors are undefined
cbravobernal Jul 10, 2023
fa10cbb
Add apply globally, not yet autosaving
cbravobernal Jul 11, 2023
4399194
Add apply globally, still need to work with styles too
cbravobernal Jul 11, 2023
d37247c
Update to work with new setImmutably function
cbravobernal Jul 11, 2023
db443a8
Make it work with global styles too
cbravobernal Jul 12, 2023
2280e67
Make default option work
cbravobernal Jul 12, 2023
8a63a69
Prevent behaviors ui showing if experimental setting is disabled
cbravobernal Jul 13, 2023
b5d7299
Make compatible with supports
cbravobernal Jul 13, 2023
eb88991
Move `__experimentalUseHasBehaviorsPanel` to hooks.js
michalczaplinski Jul 13, 2023
486199f
Rename `__experimentalUseGlobalBehaviors` to `useGlobalBehaviors` whe…
michalczaplinski Jul 13, 2023
8a1c16b
Remove `shouldDecodeEncode` because it's always true.
michalczaplinski Jul 13, 2023
b66943f
Add global revisions by extending 6.3 controller
cbravobernal Jul 18, 2023
bdc3cbe
Update php unit test
cbravobernal Jul 18, 2023
e0622d1
Add a default behaviors object to StyleVariationsContainer
michalczaplinski Jul 18, 2023
97a7048
Move all endpoints to 6.4 folder
cbravobernal Jul 19, 2023
cfa3c17
Remove `shouldEncodeDecode` parameter from __experimentalUseGlobalBeh…
michalczaplinski Jul 19, 2023
5aeaa8a
Remove `shouldReturnBehaviors` parameter from __experimentalUseGlobal…
michalczaplinski Jul 19, 2023
094ca12
Revert test change that sneaked in previous commit
michalczaplinski Jul 19, 2023
9480be5
Skip already existing in Core test that is interfering
cbravobernal Jul 20, 2023
d9048d2
Remove unrelated line that sneaked in thu rebase
michalczaplinski Jul 20, 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
23 changes: 0 additions & 23 deletions docs/reference-guides/data/data-core-block-editor.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,29 +168,6 @@ _Returns_

- `Array?`: The list of allowed block types.

### getBehaviors

Returns the behaviors registered with the editor.

Behaviors are named, reusable pieces of functionality that can be attached to blocks. They are registered with the editor using the `theme.json` file.

_Usage_

```js
const behaviors = select( blockEditorStore ).getBehaviors();
if ( behaviors?.lightbox ) {
// Do something with the lightbox.
}
```

_Parameters_

- _state_ `Object`: Editor state.

_Returns_

- `Object`: The editor behaviors object.

### getBlock

Returns a block given its client ID. This is a parsed copy of the block, containing its `blockName`, `clientId`, and current `attributes` state. This is not the block's registration settings, which must be retrieved from the blocks module registration store.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Gutenberg_REST_Global_Styles_Revisions_Controller_6_3 extends WP_REST_Cont
* @since 6.3.0
* @var string
*/
private $parent_post_type;
protected $parent_post_type;
michalczaplinski marked this conversation as resolved.
Show resolved Hide resolved

/**
* The base of the parent controller's route.
Expand Down Expand Up @@ -102,7 +102,7 @@ public function get_collection_params() {
* @param string $raw_json Encoded JSON from global styles custom post content.
* @return Array|WP_Error
*/
private function get_decoded_global_styles_json( $raw_json ) {
protected function get_decoded_global_styles_json( $raw_json ) {
$decoded_json = json_decode( $raw_json, true );

if ( is_array( $decoded_json ) && isset( $decoded_json['isGlobalStylesUserThemeJSON'] ) && true === $decoded_json['isGlobalStylesUserThemeJSON'] ) {
Expand Down
18 changes: 0 additions & 18 deletions lib/compat/wordpress-6.3/rest-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,6 @@ function gutenberg_update_templates_template_parts_rest_controller( $args, $post
}
add_filter( 'register_post_type_args', 'gutenberg_update_templates_template_parts_rest_controller', 10, 2 );

/**
* Registers the Global Styles Revisions REST API routes.
*/
function gutenberg_register_global_styles_revisions_endpoints() {
$global_styles_revisions_controller = new Gutenberg_REST_Global_Styles_Revisions_Controller_6_3();
$global_styles_revisions_controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_global_styles_revisions_endpoints' );

/**
* Registers the Global Styles REST API routes.
*/
function gutenberg_register_global_styles_endpoints() {
$global_styles_controller = new Gutenberg_REST_Global_Styles_Controller_6_3();
$global_styles_controller->register_routes();
}
add_action( 'rest_api_init', 'gutenberg_register_global_styles_endpoints' );

/**
* Add the `modified` value to the `wp_template` schema.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
<?php
/**
* REST API: Gutenberg_REST_Global_Styles_Controller class
*
* @package Gutenberg
* @subpackage REST_API
*/

/**
* Base Global Styles REST API Controller.
*/
class Gutenberg_REST_Global_Styles_Controller_6_4 extends Gutenberg_REST_Global_Styles_Controller_6_3 {

/**
* Retrieves the block pattern category schema, conforming to JSON Schema.
*
* @since 6.0.0
*
* @return array Item schema data.
*/
public function get_item_schema() {
if ( $this->schema ) {
return $this->add_additional_fields_schema( $this->schema );
}

$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => $this->post_type,
'type' => 'object',
'properties' => array(
'id' => array(
'description' => __( 'ID of global styles config.', 'default' ),
'type' => 'string',
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
'styles' => array(
'description' => __( 'Global styles.', 'default' ),
'type' => array( 'object' ),
'context' => array( 'view', 'edit' ),
),
'settings' => array(
'description' => __( 'Global settings.', 'default' ),
'type' => array( 'object' ),
'context' => array( 'view', 'edit' ),
),
'behaviors' => array(
'description' => __( 'Global behaviors.', 'default' ),
'type' => array( 'object' ),
'context' => array( 'view', 'edit' ),
),
'title' => array(
'description' => __( 'Title of the global styles variation.', 'default' ),
'type' => array( 'object', 'string' ),
'default' => '',
'context' => array( 'embed', 'view', 'edit' ),
'properties' => array(
'raw' => array(
'description' => __( 'Title for the global styles variation, as it exists in the database.', 'default' ),
'type' => 'string',
'context' => array( 'view', 'edit', 'embed' ),
),
'rendered' => array(
'description' => __( 'HTML title for the post, transformed for display.', 'default' ),
'type' => 'string',
'context' => array( 'view', 'edit', 'embed' ),
'readonly' => true,
),
),
),
),
);

$this->schema = $schema;

return $this->add_additional_fields_schema( $this->schema );
}

/**
* Prepare a global styles config output for response.
*
* @since 5.9.0
* @since 6.2 Handling of style.css was added to WP_Theme_JSON.
*
* @param WP_Post $post Global Styles post object.
* @param WP_REST_Request $request Request object.
* @return WP_REST_Response Response object.
*/
public function prepare_item_for_response( $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$raw_config = json_decode( $post->post_content, true );
$is_global_styles_user_theme_json = isset( $raw_config['isGlobalStylesUserThemeJSON'] ) && true === $raw_config['isGlobalStylesUserThemeJSON'];
$config = array();
if ( $is_global_styles_user_theme_json ) {
$config = ( new WP_Theme_JSON_Gutenberg( $raw_config, 'custom' ) )->get_raw_data();
}

// Base fields for every post.
$data = array();
$fields = $this->get_fields_for_response( $request );

if ( rest_is_field_included( 'id', $fields ) ) {
$data['id'] = $post->ID;
}

if ( rest_is_field_included( 'title', $fields ) ) {
$data['title'] = array();
}
if ( rest_is_field_included( 'title.raw', $fields ) ) {
$data['title']['raw'] = $post->post_title;
}
if ( rest_is_field_included( 'title.rendered', $fields ) ) {
add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );

$data['title']['rendered'] = get_the_title( $post->ID );

remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
}

if ( rest_is_field_included( 'settings', $fields ) ) {
$data['settings'] = ! empty( $config['settings'] ) && $is_global_styles_user_theme_json ? $config['settings'] : new stdClass();
}

if ( rest_is_field_included( 'styles', $fields ) ) {
$data['styles'] = ! empty( $config['styles'] ) && $is_global_styles_user_theme_json ? $config['styles'] : new stdClass();
}

if ( rest_is_field_included( 'behaviors', $fields ) ) {
$data['behaviors'] = ! empty( $config['behaviors'] ) && $is_global_styles_user_theme_json ? $config['behaviors'] : new stdClass();
}

$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );

// Wrap the data in a response object.
$response = rest_ensure_response( $data );

if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
$links = $this->prepare_links( $post->ID );
$response->add_links( $links );
if ( ! empty( $links['self']['href'] ) ) {
$actions = $this->get_available_actions();
$self = $links['self']['href'];
foreach ( $actions as $rel ) {
$response->add_link( $rel, $self );
}
}
}

return $response;
}

/**
* Returns the given theme global styles config.
* Duplicated from core.
* The only change is that we call WP_Theme_JSON_Resolver_Gutenberg::get_merged_data( 'theme' ) instead of WP_Theme_JSON_Resolver::get_merged_data( 'theme' ).
*
* @since 6.2.0
*
* @param WP_REST_Request $request The request instance.
* @return WP_REST_Response|WP_Error
*/
public function get_theme_item( $request ) {
if ( get_stylesheet() !== $request['stylesheet'] ) {
// This endpoint only supports the active theme for now.
return new WP_Error(
'rest_theme_not_found',
__( 'Theme not found.', 'default' ),
array( 'status' => 404 )
);
}

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

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();
}

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

$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );

$response = rest_ensure_response( $data );

if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
$links = array(
'self' => array(
'href' => rest_url( sprintf( '%s/%s/themes/%s', $this->namespace, $this->rest_base, $request['stylesheet'] ) ),
),
);
$response->add_links( $links );
}

return $response;
}

/**
* Prepares a single global styles config for update.
*
* @since 5.9.0
* @since 6.2.0 Added validation of styles.css property.
*
* @param WP_REST_Request $request Request object.
* @return stdClass Changes to pass to wp_update_post.
*/
protected function prepare_item_for_database( $request ) {
$changes = new stdClass();
$changes->ID = $request['id'];
$post = get_post( $request['id'] );
$existing_config = array();
if ( $post ) {
$existing_config = json_decode( $post->post_content, true );
$json_decoding_error = json_last_error();
if ( JSON_ERROR_NONE !== $json_decoding_error || ! isset( $existing_config['isGlobalStylesUserThemeJSON'] ) ||
! $existing_config['isGlobalStylesUserThemeJSON'] ) {
$existing_config = array();
}
}
if ( isset( $request['styles'] ) || isset( $request['settings'] ) || isset( $request['behaviors'] ) ) {
$config = array();
if ( isset( $request['styles'] ) ) {
$config['styles'] = $request['styles'];
if ( isset( $request['styles']['css'] ) ) {
$validate_custom_css = $this->validate_custom_css( $request['styles']['css'] );
if ( is_wp_error( $validate_custom_css ) ) {
return $validate_custom_css;
}
}
} elseif ( isset( $existing_config['styles'] ) ) {
$config['styles'] = $existing_config['styles'];
}
if ( isset( $request['settings'] ) ) {
$config['settings'] = $request['settings'];
} elseif ( isset( $existing_config['settings'] ) ) {
$config['settings'] = $existing_config['settings'];
}
if ( isset( $request['behaviors'] ) ) {
$config['behaviors'] = $request['behaviors'];
} elseif ( isset( $existing_config['behaviors'] ) ) {
$config['behaviors'] = $existing_config['behaviors'];
}
$config['isGlobalStylesUserThemeJSON'] = true;
$config['version'] = WP_Theme_JSON_Gutenberg::LATEST_SCHEMA;
$changes->post_content = wp_json_encode( $config );
}
// Post title.
if ( isset( $request['title'] ) ) {
if ( is_string( $request['title'] ) ) {
$changes->post_title = $request['title'];
} elseif ( ! empty( $request['title']['raw'] ) ) {
$changes->post_title = $request['title']['raw'];
}
}
return $changes;
}

}
Loading