namespace, $this->base, array( array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'get_items_permissions_check', ), ), ) ); register_rest_route( $this->namespace, $this->base, array( array( 'methods' => \WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_item' ), 'permission_callback' => array( $this, 'update_item_permissions_check', ), ), ) ); } /** * Check if a given request has access to get items * * @param $request * * @return bool|\WP_Error */ public function get_items_permissions_check( $request ) { return current_user_can( 'manage_options' ); } /** * Get all extensions * * @param $request * * @return WP_HTTP_Response */ public function get_items( $request ) { $type = ! empty( $request['type'] ) ? sanitize_key( $request['type'] ) : 'addon'; $extensions = array_values( array_filter( Plugin_Manager::extensions(), function ( $extension ) use ( $type ) { return $extension['type'] === $type; } ) ); $extensions = array_map( function ( $extension ) { $extension['status'] = 'install'; if ( SdkPluginManager::is_installed( $extension['slug'] ) ) { $extension['status'] = 'activate'; } if ( SdkPluginManager::is_activated( $extension['slug'] ) ) { $extension['status'] = 'deactivate'; } return $extension; }, $extensions ); return $this->response( $extensions ); } /** * Check if a given request has access to get items * * @param $request * * @return bool|\WP_Error */ public function update_item_permissions_check( $request ) { return current_user_can( 'manage_options' ); } /** * Enable or disable extension * * @param $request * * @return WP_HTTP_Response */ public function update_item( $request ) { $input_data = json_decode( $request->get_body(), true ); $name = $input_data['name']; $status = $input_data['status']; $statuses = array( 'off', 'on', 'install', 'activate', 'deactivate' ); $extensions = Plugin_Manager::extensions(); if ( ! $name ) { return $this->error( __( 'Please enter extension name', 'booktics' ) ); } if ( ! $status ) { return $this->error( __( 'Please enter status', 'booktics' ) ); } if ( ! in_array( $status, $statuses ) ) { return $this->error( __( 'Please enter status on/off', 'booktics' ) ); } if ( ! isset( $extensions[ $name ] ) ) { return $this->error( __( 'Invalid extension', 'booktics' ) ); } $extension = $extensions[ $name ]; if ( 'addon' === $extension['type'] ) { $result = null; if ( in_array( $status, array( 'install', 'activate' ) ) ) { $result = Plugin_Manager::install_plugin( $extension['slug'] ); if ( $result ) { $result = Plugin_Manager::activate_plugin( $extension['slug'] ); } } if ( 'deactivate' === $status && Plugin_Manager::is_activated( $extension['slug'] ) ) { $result = Plugin_Manager::deactivate_plugin( $extension['slug'] ); } if ( is_wp_error( $result ) ) { return $this->error( __( 'Extension installation error', 'booktics' ) ); } if ( ! $result ) { // translators: %s is the action performed on the extension (install, activate, deactivate, etc.) return $this->error( sprintf( __( 'Extension couldn\'t %s', 'booktics' ), $status ) ); } } if ( 'plugin' === $extension['type'] ) { $result = null; if ( 'install' === $status ) { // Prefer the extension's own download_link (e.g. GitHub release) so a // non-wordpress.org URL is not shadowed by the SDK's hardcoded wp.org zip. $result = ! empty( $extension['download_link'] ) ? Plugin_Manager::install_plugin( $extension['slug'] ) : SdkPluginManager::install_plugin( $extension['slug'] ); if ( $result ) { $result = SdkPluginManager::activate_plugin( $extension['slug'] ); } } elseif ( 'activate' === $status ) { $result = SdkPluginManager::activate_plugin( $extension['slug'] ); } elseif ( 'deactivate' === $status ) { $result = SdkPluginManager::deactivate_plugin( $extension['slug'] ); } if ( is_wp_error( $result ) ) { return $this->error( __( 'Plugin operation error', 'booktics' ) ); } if ( false === $result ) { // translators: %s is the action performed on the plugin (install, activate, deactivate, etc.) return $this->error( sprintf( __( 'Plugin couldn\'t %s', 'booktics' ), $status ) ); } } $response = Plugin_Manager::extensions()[ $name ]; // Nothing reaches Aisentic's provider on activation alone. The handshake only // runs when the caller ticked the consent box and the plugin really is active. if ( 'aisentic' === $name && in_array( $status, array( 'install', 'activate' ), true ) && ! empty( $input_data['consent'] ) && SdkPluginManager::is_activated( $extension['slug'] ) ) { // Snapshot before the handshake so the caller can tell a fresh // registration (tokens just granted) from re-activating a site that // was already connected (no new tokens). $was_registered = booktics_aisentic_is_registered(); $this->register_aisentic_site(); $is_registered = booktics_aisentic_is_registered(); $response['aisentic_registered'] = $is_registered; // True only when this request is what connected the site, so the // "150K tokens added" message never fires on a plain re-activation. $response['aisentic_newly_registered'] = $is_registered && ! $was_registered; } $response['status'] = 'install'; if ( SdkPluginManager::is_installed( $response['slug'] ) ) { $response['status'] = 'activate'; } if ( SdkPluginManager::is_activated( $response['slug'] ) ) { $response['status'] = 'deactivate'; } return $this->response( $response, __( 'Successfully updated', 'booktics' ) ); } /** * Record consent and hand the site identity to Aisentic. * * Only ever called from behind the consent gate in update_item(). The action is * fire and forget: Aisentic owns the provider call, so a provider outage cannot * fail the activation the user actually asked for. * * @return void */ private function register_aisentic_site(): void { // Older Aisentic builds ship no listener, so the handshake would go nowhere. if ( ! class_exists( 'Aisentic\Api\Services\Registration_Service' ) ) { return; } $identity = booktics_aisentic_identity(); // Fail closed. An account cannot be minted without a real address. if ( empty( $identity['email'] ) ) { return; } update_option( 'booktics_aisentic_consent', array( 'agreed' => true, 'time' => gmdate( 'c' ), 'user_id' => get_current_user_id(), 'email' => $identity['email'], ) ); /** * Fires once the admin has opted in to sharing site details with Aisentic. * * @param string $name Business name, falling back to the site title. * @param string $email Business email, falling back to the admin email. * @param string $site_url Site URL. */ do_action( 'booktics/aisentic/register_site', $identity['name'], $identity['email'], $identity['site_url'] ); } }