Skip to content

Editor: Add the entity actions API - #14276

Draft
jorgefilipecosta wants to merge 1 commit into
WordPress:trunkfrom
jorgefilipecosta:add/entity-actions-api
Draft

jorgefilipecosta wants to merge 1 commit into
WordPress:trunkfrom
jorgefilipecosta:add/entity-actions-api

Conversation

@jorgefilipecosta

Copy link
Copy Markdown
Member

Backports the server side of the entity actions API from WordPress/gutenberg#84650, part of WordPress/gutenberg#83537.

Right now the actions DataViews shows for an entity, in the lists of the site editor and in the inspector of the editor, are only defined on the client. The editor computes the core ones, and plugins can only add or remove actions in JavaScript, with registerEntityAction() and unregisterEntityAction(), which only exist in the Gutenberg plugin. This PR lets them be registered on the server, the way the entity fields API (#13911) does for fields.

This PR:

  • Adds WP_Entity_Actions_Registry, the wp_entity_actions_api_init action, wp_register_entity_actions() and wp_unregister_entity_actions(), and the wp_get_registered_entity_actions(), wp_get_registered_entity_action_modules() and wp_get_all_registered_entity_action_modules() readers. The registry fires wp_entity_actions_api_init the first time it is read after init, only accepts registrations while that action fires, reports misuse with _doing_it_wrong(), and keeps who registered each action in its origin.
  • Makes an action definition the serializable part of a DataViews action (id, label, isPrimary, supportsBulk, context and the modal options). The JavaScript parts (callback, RenderModal, isEligible, icon, …) come from a script module registered with the actions: its default export maps the id of each action to its parts, and it only applies to the actions it was registered with. The registry reports a context or a modalSize that DataViews does not support, which would otherwise hide the action without a word, and removes a callback, RenderModal or isEligible set in PHP, which only a script module can provide.
  • Adds the GET /wp/v2/entity-actions?kind=<kind>&name=<name> route, which returns the actions of an entity and its script modules, each with the ids of the actions it applies to. It requires the same capabilities as the view config route. When a post type or taxonomy has its items on /wp/v2/entity-actions, the route is left to it, and that is reported.
  • Adds the script modules of the registered actions to the import map of the pages that load the editor script, as dynamic module_dependencies of wp-editor.

Some notes:

  • Nothing registers actions yet, so nothing changes on the screens: the route returns no actions and the import map stays the same. Core Actions: Register the core actions on the server gutenberg#84660 registers the core actions on the server and makes the editor read the route.
  • There is no wp_update_entity_actions(). To change an action, a plugin unregisters it and registers it again with the script module of the original, which keeps its JavaScript parts.
  • WP_Entity_Actions_Registry is not final and its members are protected, because the Gutenberg plugin replaces the registry with a subclass on init, as it does for the entity fields registry.
  • The labels registered in PHP are translated on the server. The strings of a plugin's script module need I18N: Print translations for the script modules that classic scripts depend on #14260: WordPress prints translations only for the enqueued script modules and their dependencies, not for the dynamic module dependencies of a classic script.

Testing Instructions

  1. Save this snippet as wp-content/mu-plugins/entity-actions-test.php (src/wp-content/mu-plugins/ in a wordpress-develop checkout):

    <?php
    add_action( 'init', function () {
    	wp_register_script_module( 'my-plugin/actions', '/my-plugin-actions.js' );
    } );
    add_action( 'wp_entity_actions_api_init', function () {
    	wp_register_entity_actions( 'my-plugin', 'postType', 'page', array( array( 'id' => 'my-plugin/feature', 'label' => 'Feature', 'supportsBulk' => true ) ), 'my-plugin/actions' );
    } );
    
  2. Open wp-admin/post-new.php?post_type=page. In the console, run await wp.apiFetch( { path: '/wp/v2/entity-actions?kind=postType&name=page' } ) and verify it returns the action, with origin set to { registeredBy: 'my-plugin' }, and the my-plugin/actions module with [ 'my-plugin/feature' ] as its actions.

  3. In the same console, run JSON.parse( document.querySelector( 'script[type=importmap]' ).textContent ).imports[ 'my-plugin/actions' ] and verify it returns the URL of the module.

  4. Run await wp.apiFetch( { path: '/wp/v2/entity-actions?kind=postType&name=missing' } ) and verify it fails with rest_entity_actions_invalid_entity.

  5. Move the wp_register_entity_actions() call into the init callback. With WP_DEBUG on, reload and verify a notice says actions can only be registered and unregistered on the wp_entity_actions_api_init action, and that the route no longer returns the action.

  6. Delete the snippet and run npm run test:php -- --group entity-actions.

Gutenberg PR: WordPress/gutenberg#84650

Trac ticket: TBD

Use of AI Tools

AI assistance: Yes
Used for: porting the code and the tests from the Gutenberg PR, and drafting this description; reviewed and edited by me.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

Adds a registry for the actions DataViews shows for an entity, so they can be registered on the server. An action definition is the serializable part of a DataViews action. Its JavaScript parts come from a script module registered along with the actions.

Actions are registered with `wp_register_entity_actions()` and unregistered with `wp_unregister_entity_actions()`, only on the `wp_entity_actions_api_init` action, which fires the first time the registry is read after `init`.

The `GET /wp/v2/entity-actions` route returns the actions of an entity and their script modules, and the script modules are added to the import map of the pages that load the editor script, as dynamic module dependencies of `wp-editor`.

Backports WordPress/gutenberg#84650.
@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant