namespace = 'ithemes-security/v1'; $this->rest_base = 'modules'; } public function register_routes() { register_rest_route( $this->namespace, $this->rest_base, [ [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [ $this, 'get_items' ], 'permission_callback' => [ $this, 'get_items_permissions_check' ], 'args' => $this->get_collection_params(), ], 'schema' => [ $this, 'get_public_item_schema' ], ] ); register_rest_route( $this->namespace, $this->rest_base . '/(?P[\w-]+)', [ [ 'methods' => \WP_REST_Server::READABLE, 'callback' => [ $this, 'get_item' ], 'permission_callback' => [ $this, 'get_item_permissions_check' ], 'args' => [ 'context' => $this->get_context_param( [ 'default' => 'view' ] ) ], ], [ 'methods' => 'PUT', 'callback' => [ $this, 'update_item' ], 'permission_callback' => [ $this, 'update_item_permissions_check' ], 'args' => $this->get_endpoint_args_for_item_schema( 'PUT' ), ], 'schema' => [ $this, 'get_public_item_schema' ], 'allow_batch' => [ 'v1' => true ], ] ); } public function get_items_permissions_check( $request ) { return \ITSEC_Core::current_user_can_manage(); } public function get_items( $request ) { $modules = \ITSEC_Modules::get_available_modules(); if ( $request['status'] ) { $modules = array_filter( $modules, function ( $module ) use ( $request ) { return $this->get_module_status( $module ) === $request['status']; } ); } $responses = []; foreach ( $modules as $module ) { if ( ( $config = \ITSEC_Modules::get_config( $module ) ) && ! $config->get_extends() ) { $responses[] = $this->prepare_response_for_collection( $this->prepare_item_for_response( $config, $request ) ); } } return new \WP_REST_Response( $responses ); } public function get_item_permissions_check( $request ) { return \ITSEC_Core::current_user_can_manage(); } public function get_item( $request ) { if ( ! $config = \ITSEC_Modules::get_config( $request['id'] ) ) { return new \WP_Error( 'rest_module_not_found', __( 'No module was found with that id.', 'it-l10n-ithemes-security-pro' ), [ 'status' => \WP_Http::NOT_FOUND ] ); } return $this->prepare_item_for_response( $config, $request ); } public function update_item_permissions_check( $request ) { return \ITSEC_Core::current_user_can_manage(); } public function update_item( $request ) { if ( ! $config = \ITSEC_Modules::get_config( $request['id'] ) ) { return new \WP_Error( 'rest_module_not_found', __( 'No module was found with that id.', 'it-l10n-ithemes-security-pro' ), [ 'status' => \WP_Http::NOT_FOUND ] ); } $status = $request['status']['selected'] ?? $this->get_module_status( $config->get_id() ); if ( $status !== $this->get_module_status( $config->get_id() ) ) { if ( 'active' === $status ) { $error = \ITSEC_Modules::activate( $config->get_id() ); } else { $error = \ITSEC_Modules::deactivate( $config->get_id() ); } if ( is_wp_error( $error ) ) { \ITSEC_Lib_REST::add_status_to_error( \WP_Http::BAD_REQUEST, $error ); return $error; } } $request['context'] = 'edit'; return $this->prepare_item_for_response( $config, $request ); } /** * Prepares an individual module for response. * * @param Module_Config $item * @param \WP_REST_Request $request * * @return \WP_REST_Response */ public function prepare_item_for_response( $item, $request ) { $item = $item->translate(); $data = [ 'id' => $item->get_id(), 'status' => [ 'selected' => $this->get_module_status( $item->get_id() ), 'default' => $item->get_status(), ], 'type' => $item->get_type(), 'onboard' => $item->is_onboard(), 'keywords' => $item->get_keywords(), 'title' => $item->get_title(), 'description' => $item->get_description(), 'help' => $item->get_help(), 'user_groups' => $item->get_user_groups(), 'password_requirements' => $item->get_password_requirements(), 'tools' => $item->get_tools() ?: new \stdClass(), ]; $fields = $this->get_fields_for_response( $request ); if ( $settings = \ITSEC_Modules::get_settings_obj( $item->get_id() ) ) { if ( rest_is_field_included( 'settings.schema', $fields ) ) { $data['settings']['schema'] = $settings->get_settings_schema(); foreach ( $settings->get_defaults() as $setting => $default ) { $data['settings']['schema']['properties'][ $setting ]['default'] = $default; } } if ( rest_is_field_included( 'settings.conditional', $fields ) ) { $data['settings']['conditional'] = []; foreach ( $settings->get_conditional_settings() as $setting ) { $data['settings']['conditional'][ $setting ] = $settings->get_conditional_setting_config( $setting ); } } if ( rest_is_field_included( 'settings.interactive', $fields ) ) { $data['settings']['interactive'] = array_values( array_filter( $settings->get_known_settings(), [ $settings, 'is_interactive_setting' ] ) ); } if ( rest_is_field_included( 'settings.removed', $fields ) ) { $data['settings']['removed'] = $item->get_removed_settings(); } if ( rest_is_field_included( 'settings.deprecated', $fields ) ) { $data['settings']['deprecated'] = $item->get_deprecated_settings(); } if ( rest_is_field_included( 'settings.onboard', $fields ) ) { $data['settings']['onboard'] = $item->get_onboard_settings(); } } $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $request['context'] ?: 'view' ); $response = new \WP_REST_Response( $data ); $response->add_links( $this->prepare_links( $item ) ); return $response; } /** * Gets the module's status. * * @param string $id The module id. * * @return string */ private function get_module_status( string $id ): string { return \ITSEC_Modules::is_active( $id ) ? 'active' : 'inactive'; } /** * Prepares the list of links to be attached to the module. * * @param Module_Config $config * * @return array[] */ private function prepare_links( Module_Config $config ): array { $links = [ 'self' => [ 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $config->get_id() ) ), ] ]; if ( $config->get_settings() ) { $links[ \ITSEC_Lib_REST::get_link_relation( 'settings' ) ] = [ 'href' => rest_url( sprintf( '%s/settings/%s', $this->namespace, $config->get_id() ) ), 'embeddable' => true, ]; } return $links; } public function get_item_schema() { if ( $this->schema ) { return $this->add_additional_fields_schema( $this->schema ); } $this->schema = [ 'title' => 'ithemes-security-module', '$schema' => 'http://json-schema.org/draft-04/schema#', 'type' => 'object', 'properties' => [ 'id' => [ 'title' => __( 'Module ID' ), 'type' => 'string', 'context' => [ 'view', 'edit', 'embed' ], 'readonly' => true, ], 'status' => [ 'title' => __( 'Module Status' ), 'type' => 'object', 'properties' => [ 'selected' => [ 'type' => 'string', 'enum' => [ 'active', 'inactive' ], 'context' => [ 'view', 'edit', 'embed' ], ], 'default' => [ 'type' => 'string', 'enum' => [ 'always-active', 'default-active', 'default-inactive' ], 'context' => [ 'edit' ], 'readonly' => true, ], ], 'context' => [ 'view', 'edit', 'embed' ], ], 'type' => [ 'title' => __( 'The Module Type' ), 'type' => 'string', 'enum' => [ 'recommended', 'advanced', 'tool' ], 'context' => [ 'view', 'edit', 'embed' ], 'readonly' => true, ], 'onboard' => [ 'title' => __( 'Show in Onboard' ), 'type' => 'boolean', 'context' => [ 'view', 'edit', 'embed' ], 'readonly' => true, ], 'keywords' => [ 'title' => __( 'Module Search Keywords', 'it-l10n-ithemes-security-pro' ), 'type' => 'array', 'items' => [ 'type' => 'string', ], 'context' => [ 'view', 'edit', 'embed' ], 'readonly' => true, ], 'title' => [ 'title' => __( 'Module Title' ), 'type' => 'string', 'context' => [ 'view', 'edit', 'embed' ], 'readonly' => true, ], 'description' => [ 'title' => __( 'Module Description' ), 'type' => 'string', 'context' => [ 'view', 'edit', 'embed' ], 'readonly' => true, ], 'help' => [ 'title' => __( 'Module Help' ), 'type' => 'string', 'context' => [ 'view', 'edit', 'embed' ], 'readonly' => true, ], 'user_groups' => [ 'title' => __( 'User Groups' ), 'type' => 'object', 'context' => [ 'edit' ], 'readonly' => true, ], 'password_requirements' => [ 'title' => __( 'Password Requirements' ), 'type' => 'object', 'context' => [ 'edit' ], 'readonly' => true, ], 'tools' => [ 'title' => __( 'Module Tools', 'it-l10n-ithemes-security-pro' ), 'type' => 'object', 'additionalProperties' => [ 'type' => 'object', ], ], 'settings' => [ 'title' => __( 'Module Settings Configuration' ), 'type' => 'object', 'properties' => [ 'schema' => [ 'description' => __( 'The schema describing the settings.' ), 'type' => 'object', ], 'conditional' => [ 'description' => __( 'Map of setting names to conditional setting definitions.' ), 'type' => 'object', ], 'interactive' => [ 'description' => __( 'List of interactive setting names.' ), 'type' => 'array', 'items' => [ 'type' => 'string', ], ], 'removed' => [ 'description' => __( 'List of removed setting names.' ), 'type' => 'array', 'items' => [ 'type' => 'string', ], ], 'deprecated' => [ 'description' => __( 'List of deprecated setting names.' ), 'type' => 'array', 'items' => [ 'type' => 'string', ], ], 'onboard' => [ 'description' => __( 'List of settings to onboard.' ), 'type' => 'array', 'items' => [ 'type' => 'string', ], ] ], 'context' => [ 'edit' ], 'readonly' => true, ], ], ]; return $this->add_additional_fields_schema( $this->schema ); } public function get_collection_params() { return [ 'context' => $this->get_context_param( [ 'default' => 'view' ] ), 'status' => [ 'type' => 'string', 'enum' => [ 'active', 'inactive', ], ], ]; } }