-
Notifications
You must be signed in to change notification settings - Fork 4.6k
WIP: Install a block from inserter #16524
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
Changes from all commits
1060588
8fc202a
ebd1148
e85b2a0
7dbdf01
673475e
069d796
a02a3c7
7824941
e08184b
b5e1756
810546b
78e7883
e363149
c67d4f3
bdda0cc
acca61d
049297f
512b099
4b8e27a
a258146
9c2ab35
53e6e57
d6cae04
0e4c81b
97326c8
c2d142a
4ddf8c7
95bcc09
3745493
6633c6d
c1f7b11
5a225d8
9041d62
1d77f85
7774547
01c311b
b9baa64
37a0080
16dfdfe
5882bde
2b930f0
d017ac0
52987f9
038c141
14c6d74
56b20fe
b99c417
92ac7cd
52eb638
9be2347
b26dbda
953d3df
19a2de9
c643d55
6449373
75cc8d0
b563c43
6ed9aaa
22c7854
fae82f8
37444c5
46dbf23
d9b0db5
7a4fb2b
4444710
bff4995
ac54237
89e5862
20e0e79
b23ba87
7a39b70
b3bd752
b2352ff
8a9603b
2ec1a96
762a726
64ece6c
4b3d836
e4cc959
822bcc1
d91f669
1ddab6c
01be3e0
7021e2e
56a790a
5df0ffc
e25c6c6
0d137f3
fde3dca
c270540
3544494
ed1bcb5
36dd5a3
22f6a3d
df46fdc
e90876f
765571b
c0d1738
9113882
bc3f77e
d5f1db8
e37c23d
f65b493
d766d67
b265d93
78e4566
e0772d0
345a1db
5b0b5c9
7840221
4b3c898
2e7889f
649982d
e47e214
e3bc38c
bebbb23
dad8d44
c877957
d1f86f5
d1faced
f2bd345
d184693
d0d832a
711d908
3174112
1f4ad26
54a891c
2bab650
8bb30b1
4a9c324
d1687ad
11978b1
868cd14
3f5804e
15e0012
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,311 @@ | ||
| <?php | ||
| /** | ||
| * Start: Include for phase 2 | ||
| * Block Directory REST API: WP_REST_Blocks_Controller class | ||
| * | ||
| * @package gutenberg | ||
| * @since 5.7.0 | ||
| */ | ||
|
|
||
| /** | ||
| * Controller which provides REST endpoint for the blocks. | ||
| * | ||
| * @since 5.2.0 | ||
| * | ||
| * @see WP_REST_Controller | ||
| */ | ||
| class WP_REST_Block_Directory_Controller extends WP_REST_Controller { | ||
|
|
||
| /** | ||
| * Constructs the controller. | ||
| * | ||
| * @access public | ||
| */ | ||
| public function __construct() { | ||
| $this->namespace = '__experimental'; | ||
| $this->rest_base = 'block-directory'; | ||
| } | ||
|
|
||
| /** | ||
| * Registers the necessary REST API routes. | ||
| * | ||
| * @access public | ||
| */ | ||
| public function register_routes() { | ||
| register_rest_route( | ||
| $this->namespace, | ||
| '/' . $this->rest_base . '/search', | ||
| array( | ||
| array( | ||
| 'methods' => WP_REST_Server::READABLE, | ||
| 'callback' => array( $this, 'get_items' ), | ||
| 'permission_callback' => array( $this, 'get_items_permissions_check' ), | ||
| ), | ||
| 'schema' => array( $this, 'get_item_schema' ), | ||
| ) | ||
| ); | ||
| register_rest_route( | ||
| $this->namespace, | ||
| '/' . $this->rest_base . '/install', | ||
| array( | ||
| array( | ||
| 'methods' => WP_REST_Server::CREATABLE, | ||
| 'callback' => array( $this, 'install_block' ), | ||
| 'permission_callback' => array( $this, 'get_items_permissions_check' ), | ||
noisysocks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ), | ||
| 'schema' => array( $this, 'get_item_schema' ), | ||
| ) | ||
| ); | ||
| register_rest_route( | ||
| $this->namespace, | ||
| '/' . $this->rest_base . '/uninstall', | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't feel very "restful" to use different URLs for the create and delete actions. Could "installation" be a resource? e.g. so
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's do this in a follow-up PR. |
||
| array( | ||
| array( | ||
| 'methods' => WP_REST_Server::DELETABLE, | ||
| 'callback' => array( $this, 'uninstall_block' ), | ||
| 'permission_callback' => array( $this, 'get_items_permissions_check' ), | ||
| ), | ||
| 'schema' => array( $this, 'get_item_schema' ), | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * Checks whether a given request has permission to install and activate plugins. | ||
| * | ||
| * @since 5.7.0 | ||
noisysocks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| * | ||
| * @param WP_REST_Request $request Full details about the request. | ||
| * @return WP_Error|bool True if the request has permission, WP_Error object otherwise. | ||
| */ | ||
| public function get_items_permissions_check( $request ) { | ||
| if ( ! current_user_can( 'install_plugins' ) || ! current_user_can( 'activate_plugins' ) ) { | ||
| return new WP_Error( | ||
| 'rest_user_cannot_view', | ||
| __( 'Sorry, you are not allowed to install blocks.', 'gutenberg' ) | ||
| ); | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| /** | ||
| * Installs and activates a plugin | ||
| * | ||
| * @since 5.7.0 | ||
| * | ||
| * @param WP_REST_Request $request Full details about the request. | ||
| * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. | ||
| */ | ||
| public function install_block( $request ) { | ||
|
|
||
| include_once( ABSPATH . 'wp-admin/includes/file.php' ); | ||
| include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); | ||
| include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' ); | ||
| include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' ); | ||
|
|
||
| $api = plugins_api( | ||
| 'plugin_information', | ||
| array( | ||
| 'slug' => $request->get_param( 'slug' ), | ||
| 'fields' => array( | ||
| 'sections' => false, | ||
| ), | ||
| ) | ||
| ); | ||
|
|
||
| if ( is_wp_error( $api ) ) { | ||
| return WP_Error( $api->get_error_code(), $api->get_error_message() ); | ||
| } | ||
|
|
||
| $skin = new WP_Ajax_Upgrader_Skin(); | ||
| $upgrader = new Plugin_Upgrader( $skin ); | ||
|
|
||
| $filesystem_method = get_filesystem_method(); | ||
|
|
||
| if ( 'direct' !== $filesystem_method ) { | ||
| return WP_Error( null, 'Only direct FS_METHOD is supported.' ); | ||
| } | ||
|
|
||
| $result = $upgrader->install( $api->download_link ); | ||
|
|
||
| if ( is_wp_error( $result ) ) { | ||
| return WP_Error( $result->get_error_code(), $result->get_error_message() ); | ||
| } | ||
|
|
||
| if ( is_wp_error( $skin->result ) ) { | ||
| return WP_Error( $skin->$result->get_error_code(), $skin->$result->get_error_message() ); | ||
| } | ||
|
|
||
| if ( $skin->get_errors()->has_errors() ) { | ||
| return WP_Error( $skin->$result->get_error_code(), $skin->$result->get_error_messages() ); | ||
| } | ||
|
|
||
| if ( is_null( $result ) ) { | ||
| global $wp_filesystem; | ||
| // Pass through the error from WP_Filesystem if one was raised. | ||
| if ( $wp_filesystem instanceof WP_Filesystem_Base && is_wp_error( $wp_filesystem->errors ) && $wp_filesystem->errors->has_errors() ) { | ||
| return WP_Error( 'unable_to_connect_to_filesystem', esc_html( $wp_filesystem->errors->get_error_message() ) ); | ||
| } | ||
| return WP_Error( 'unable_to_connect_to_filesystem', __( 'Unable to connect to the filesystem. Please confirm your credentials.', 'gutenberg' ) ); | ||
| } | ||
|
|
||
| $install_status = install_plugin_install_status( $api ); | ||
|
|
||
| $activate_result = activate_plugin( $install_status['file'] ); | ||
|
|
||
| if ( is_wp_error( $activate_result ) ) { | ||
| return WP_Error( $activate_result->get_error_code(), $activate_result->get_error_message() ); | ||
| } | ||
|
|
||
| return rest_ensure_response( true ); | ||
| } | ||
|
|
||
| /** | ||
| * Deactivates and deletes a plugin | ||
| * | ||
| * @since 5.7.0 | ||
| * | ||
| * @param WP_REST_Request $request Full details about the request. | ||
| * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. | ||
| */ | ||
| public function uninstall_block( $request ) { | ||
|
|
||
| include_once( ABSPATH . 'wp-admin/includes/file.php' ); | ||
| include_once( ABSPATH . 'wp-admin/includes/plugin.php' ); | ||
| include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' ); | ||
| include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' ); | ||
|
|
||
| $api = plugins_api( | ||
| 'plugin_information', | ||
| array( | ||
| 'slug' => $request->get_param( 'slug' ), | ||
| 'fields' => array( | ||
| 'sections' => false, | ||
| ), | ||
| ) | ||
| ); | ||
|
|
||
| if ( is_wp_error( $api ) ) { | ||
| return WP_Error( $api->get_error_code(), $api->get_error_message() ); | ||
| } | ||
|
|
||
| $install_status = install_plugin_install_status( $api ); | ||
|
|
||
| $deactivate_result = deactivate_plugins( $install_status['file'] ); | ||
|
|
||
| if ( is_wp_error( $deactivate_result ) ) { | ||
| return WP_Error( $deactivate_result->get_error_code(), $deactivate_result->get_error_message() ); | ||
| } | ||
|
|
||
| $delete_result = delete_plugins( array( $install_status['file'] ) ); | ||
|
|
||
| if ( is_wp_error( $delete_result ) ) { | ||
| return WP_Error( $delete_result->get_error_code(), $delete_result->get_error_message() ); | ||
| } | ||
|
|
||
| return rest_ensure_response( true ); | ||
| } | ||
|
|
||
| /** | ||
| * Search and retrieve blocks metadata | ||
| * | ||
| * @since 5.7.0 | ||
| * | ||
| * @param WP_REST_Request $request Full details about the request. | ||
| * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. | ||
| */ | ||
| public function get_items( $request ) { | ||
|
|
||
| $search_string = $request->get_param( 'term' ); | ||
|
|
||
| if ( empty( $search_string ) ) { | ||
| return rest_ensure_response( array() ); | ||
| } | ||
|
|
||
| include( ABSPATH . WPINC . '/version.php' ); | ||
|
|
||
| $url = 'http://api.wordpress.org/plugins/info/1.2/'; | ||
| $url = add_query_arg( | ||
| array( | ||
| 'action' => 'query_plugins', | ||
| 'request[block]' => $search_string, | ||
| 'request[wp_version]' => '5.3', | ||
| 'request[per_page]' => '3', | ||
| ), | ||
| $url | ||
| ); | ||
| $http_url = $url; | ||
| $ssl = wp_http_supports( array( 'ssl' ) ); | ||
| if ( $ssl ) { | ||
| $url = set_url_scheme( $url, 'https' ); | ||
| } | ||
| $http_args = array( | ||
| 'timeout' => 15, | ||
| 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url( '/' ), | ||
| ); | ||
|
|
||
| $request = wp_remote_get( $url, $http_args ); | ||
| $response = json_decode( wp_remote_retrieve_body( $request ), true ); | ||
|
|
||
| if ( ! function_exists( 'get_plugins' ) ) { | ||
| require_once ABSPATH . 'wp-admin/includes/plugin.php'; | ||
| } | ||
|
|
||
| $result = array(); | ||
|
|
||
| foreach ( $response['plugins'] as $plugin ) { | ||
| $installed_plugins = get_plugins( '/' . $plugin['slug'] ); | ||
|
|
||
| // Only show uninstalled blocks. | ||
| if ( empty( $installed_plugins ) ) { | ||
| $result[] = parse_block_metadata( $plugin ); | ||
| } | ||
| } | ||
|
|
||
| return rest_ensure_response( $result ); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Parse block metadata for a block | ||
| * | ||
| * @since 5.7.0 | ||
| * | ||
| * @param WP_Object $plugin The plugin metadata. | ||
| * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. | ||
| */ | ||
| function parse_block_metadata( $plugin ) { | ||
noisysocks marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| $block = new stdClass(); | ||
|
|
||
| // There might be multiple blocks in a plugin. Only the first block is mapped. | ||
| $block_data = reset( $plugin['blocks'] ); | ||
| $block->name = $block_data['name']; | ||
| $block->title = $block_data['title']; | ||
|
|
||
| // Plugin's description, not description in block.json. | ||
| $block->description = wp_trim_words( wp_strip_all_tags( $plugin['description'] ), 30, '...' ); | ||
|
|
||
| $block->id = $plugin['slug']; | ||
| $block->rating = $plugin['rating']; | ||
| $block->rating_count = $plugin['num_ratings']; | ||
| $block->active_installs = $plugin['active_installs']; | ||
| $block->author_block_rating = $plugin['author_block_rating']; | ||
| $block->author_block_count = $plugin['author_block_count']; | ||
|
|
||
| // Plugin's author, not author in block.json. | ||
| $block->author = wp_strip_all_tags( $plugin['author'] ); | ||
|
|
||
| // Plugin's icons or icon in block.json. | ||
| $block->icon = isset( $plugin['icons']['1x'] ) ? $plugin['icons']['1x'] : 'block-default'; | ||
|
|
||
| $block->assets = array(); | ||
|
|
||
| foreach ( $plugin['block_assets'] as $asset ) { | ||
| $block->assets[] = 'https://plugins.svn.wordpress.org/' . $plugin['slug'] . $asset; | ||
| } | ||
|
|
||
| $block->humanized_updated = human_time_diff( strtotime( $plugin['last_updated'] ), current_time( 'timestamp' ) ) . __( ' ago', 'gutenberg' ); | ||
|
|
||
| return $block; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.