insert( $wpdb->prefix . 'woocommerce_api_keys', array( 'user_id' => $user_id, 'description' => self::DESCRIPTION, 'permissions' => 'read_write', 'consumer_key' => wc_api_hash( $consumer_key ), 'consumer_secret' => $consumer_secret, 'truncated_key' => substr( $consumer_key, -7 ), ), array( '%d', '%s', '%s', '%s', '%s', '%s' ) ); if ( false === $inserted ) { // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Exception message for logs/exceptions, not rendered output. throw new ConnectException( 'key_failed', (string) $wpdb->last_error ); } return array( 'key_id' => (int) $wpdb->insert_id, 'consumer_key' => $consumer_key, 'consumer_secret' => $consumer_secret, ); } /** * Deletes our key, by id alone like KeyScope and owner(): a merchant may rename it, and a renamed key that survived * would stay live with no scope, because the plugin forgets its id. Ids come only from what the plugin stored when * it minted the key. Uses $wpdb only, so it also works during deactivation after WooCommerce was switched off. */ public function revoke( int $key_id ): void { if ( $key_id <= 0 ) { return; } global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- no API; WooCommerce does the same. $deleted = $wpdb->delete( $wpdb->prefix . 'woocommerce_api_keys', array( 'key_id' => $key_id ), array( '%d' ) ); if ( false === $deleted ) { Log::warning( sprintf( 'Revoking API key %d failed: %s', $key_id, (string) $wpdb->last_error ) ); } } /** * Deletes the key of a connect attempt that never saved its connection, if there is one. */ public function revoke_pending(): void { $this->revoke( Options::pending_key_id() ); Options::clear_pending_key_id(); } /** * The user who owns our key (the admin who connected), or 0 when the key is gone. Read from the key row, so a * store connected by an earlier plugin version has an owner too. By id alone, like KeyScope: an admin may * rename the key in WooCommerce's settings. */ public function owner( int $key_id ): int { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- WooCommerce's keys table has no API; read once per sync run. $user_id = $wpdb->get_var( $wpdb->prepare( "SELECT user_id FROM {$wpdb->prefix}woocommerce_api_keys WHERE key_id = %d", $key_id ) ); return (int) $user_id; } public function exists( int $key_id ): bool { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- status check on WooCommerce's table. $found = $wpdb->get_var( $wpdb->prepare( "SELECT key_id FROM {$wpdb->prefix}woocommerce_api_keys WHERE key_id = %d", $key_id ) ); return null !== $found; } }