unction get_permission_callback( $request ) { $is_multi = (bool) $request->get_param( 'is_multi' ); $result = false; // The function is public since endpoint need to access it. // Utilize 'WP_REST_Controller' get_permission_check methods. switch ( $request->get_method() ) { case 'GET': $result = $is_multi ? $this->get_items_permissions_check( $request ) : $this->get_item_permissions_check( $request ); break; case 'POST': $result = $is_multi ? $this->create_items_permissions_check( $request ) : $this->create_item_permissions_check( $request ); break; case 'UPDATE': case 'PUT': case 'PATCH': $result = $is_multi ? $this->update_items_permissions_check( $request ) : $this->update_item_permissions_check( $request ); break; case 'DELETE': $result = $is_multi ? $this->delete_items_permissions_check( $request ) : $this->delete_item_permissions_check( $request ); break; } if ( $result instanceof \WP_Error ) { throw new WP_Error_Exception( $result ); } return $result; } /** * Checks if a given request has access to create items. ** * * @param \WP_REST_Request $request Full details about the request. * * @return true|\WP_Error True if the request has access to create items, WP_Error object otherwise. */ public function create_items_permissions_check( $request ) { return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] ); } /** * Checks if a given request has access to update items. * * @param \WP_REST_Request $request Full details about the request. * * @return true|\WP_Error True if the request has access to update the item, WP_Error object otherwise. */ public function update_items_permissions_check( $request ) { return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] ); } /** * Checks if a given request has access to delete items. * * @param \WP_REST_Request $request Full details about the request. * * @return true|\WP_Error True if the request has access to delete the item, WP_Error object otherwise. */ public function delete_items_permissions_check( $request ) { return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] ); } public function get_items( $request ) { return $this->get_controller_index(); } /** * Creates multiple items. * * @param \WP_REST_Request $request Full data about the request. * * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure. */ public function create_items( $request ) { return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] ); } /** * Updates multiple items. * * @param \WP_REST_Request $request Full data about the request. * * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure. */ public function update_items( $request ) { return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] ); } /** * Delete multiple items. * * @param \WP_REST_Request $request Full data about the request. * * @return \WP_Error|\WP_REST_Response Response object on success, or WP_Error object on failure. */ public function delete_items( $request ) { return new \WP_Error( 'invalid-method', sprintf( "Method '%s' not implemented. Must be overridden in subclass.", __METHOD__ ), [ 'status' => 405 ] ); } /** * Get the parent controller. * * @return \Elementor\Data\V2\Base\Controller|null */ public function get_parent() { return $this->parent; } /** * Get sub controller(s). * * @return \Elementor\Data\V2\Base\Controller[] */ public function get_sub_controllers() { return $this->sub_controllers; } /** * Get processors. * * @param string $command * * @return \Elementor\Data\V2\Base\Processor[] */ public function get_processors( $command ) { $result = []; if ( isset( $this->processors[ $command ] ) ) { $result = $this->processors[ $command ]; } return $result; } /** * Register processors. */ public function register_processors() { } /** * Register index endpoint. */ protected function register_index_endpoint() { if ( ! $this->parent ) { $this->register_endpoint( new Endpoint\Index( $this ) ); return; } $this->register_endpoint( new Endpoint\Index\Sub_Index_Endpoint( $this ) ); } /** * Register endpoint. * * @param \Elementor\Data\V2\Base\Endpoint $endpoint * * @return \Elementor\Data\V2\Base\Endpoint */ protected function register_endpoint( Endpoint $endpoint ) { $command = $endpoint->get_full_command(); if ( $endpoint instanceof Endpoint\Index ) { $this->index_endpoint = $endpoint; } else { $this->endpoints[ $command ] = $endpoint; } $format = $endpoint->get_format(); // `$e.data.registerFormat()`. Manager::instance()->register_endpoint_format( $command, $format ); return $endpoint; } /** * Register a processor. * * That will be later attached to the endpoint class. * * @param Processor $processor * * @return \Elementor\Data\V2\Base\Processor $processor_instance */ protected function register_processor( Processor $processor ) { $command = $processor->get_command(); if ( ! isset( $this->processors[ $command ] ) ) { $this->processors[ $command ] = []; } $this->processors[ $command ] [] = $processor; return $processor; } /** * Register. * * Endpoints & processors. */ protected function register() { $this->register_index_endpoint(); $this->register_endpoints(); // Aka hooks. $this->register_processors(); } /** * Get collection params by 'additionalProperties' context. * * @param string $context * * @return array */ protected function get_collection_params_by_additional_props_context( $context ) { $result = []; $collection_params = $this->get_collection_params(); foreach ( $collection_params as $collection_param_key => $collection_param ) { if ( isset( $collection_param['additionalProperties']['context'] ) && $context === $collection_param['additionalProperties']['context'] ) { $result[ $collection_param_key ] = $collection_param; } } return $result; } /** * When `$this->get_parent_name` is extended, the controller will have a parent, and will know to behave like a sub-controller. * * @param string $parent_name */ private function act_as_sub_controller( $parent_name ) { $this->parent = Manager::instance()->get_controller( $parent_name ); if ( ! $this->parent ) { trigger_error( "Cannot find parent controller: '$parent_name'", E_USER_ERROR ); // phpcs:ignore } $this->parent->sub_controllers [] = $this; } /** * Controller constructor. * * Register endpoints on 'rest_api_init'. */ public function __construct() { $this->namespace = static::get_default_namespace() . '/v' . static::get_default_version(); $this->rest_base = $this->get_name(); add_action( 'rest_api_init', function () { $this->register(); // Because 'register' is protected. } ); /** * Since all actions were removed for custom internal REST server. * Re-add the actions. */ add_action( 'elementor_rest_api_before_init', function () { add_action( 'rest_api_init', function () { $this->register(); } ); } ); $parent_name = $this->get_parent_name(); if ( $parent_name ) { $this->act_as_sub_controller( $parent_name ); } } }