File ManagerCurrent Directory: wp-content/plugins/wpforms/src/Pro/Integrations/LiteConnectLinux appserver-0d5e4f1e-php-cc8da225320a42ba9b7d66cba40b1f03 6.6.123+ #1 SMP PREEMPT_DYNAMIC Wed Mar 11 09:04:28 UTC 2026 x86_64Edit File: Integration.php <?php namespace WPForms\Pro\Integrations\LiteConnect; use WPForms\Emails\Mailer; use WPForms\Emails\Helpers as EmailHelpers; use WPForms\Helpers\Crypto; use WPForms\Helpers\Transient; /** * Class Integration. * * Integration between Lite Connect API and WPForms Pro. * * @since 1.7.4 */ class Integration extends \WPForms\Integrations\LiteConnect\Integration { /** * Number of tries to import before notify the user to reach out to support. * * @since 1.7.4 * * @var int */ const FAILS_LIMIT = 4; /** * ID of the forms that were already validated. * * @since 1.7.4 * * @var array */ private $form_ids = []; /** * Processed entry IDs. * Possible keys: `imported`, `failed`. * * @since 1.7.4 * * @var array */ private $entries = []; /** * Get the entries from Lite Connect API. * * @since 1.7.4 * * @param string $last_record_id The ID of the last imported entry. * * @return array|false */ private function get_entries( $last_record_id = null ) { // We have to start requesting site keys in ajax, turning on the LC functionality. // First, the request to the API server will be sent. // Second, the server will respond to our callback URL /wpforms/auth/key/nonce, and the site key will be stored in the DB. // Third, we have to get access via a separate HTTP request. $this->update_keys(); // Third request here. $response = ( new API() )->retrieve_site_entries( $this->auth['access_token'], $last_record_id ); if ( ! $response ) { $this->log_get_entries_error( $last_record_id, $response ); return false; } $response = json_decode( $response, true ); if ( ! isset( $response['entries'] ) || ! empty( $response['error'] ) ) { $this->log_get_entries_error( $last_record_id, $response ); return false; } return $response; } /** * Log get entries error. * * @since 1.7.4 * * @param mixed $last_record_id The ID of the last imported entry. * @param mixed $response Response data. */ private function log_get_entries_error( $last_record_id, $response ) { wpforms_log( 'Lite Connect: error retrieving site entries', [ 'response' => $response, 'request' => [ 'domain' => $this->domain, 'site_id' => $this->site_id, 'last_record' => $last_record_id, ], ], [ 'type' => [ 'error' ], ] ); } /** * Retrieve entries from Lite Connect API and decrypt them. * * @since 1.7.4 * * @param string $last_import_id The ID of the last imported entry. * * @return bool|void False on error. */ public function retrieve_and_decrypt( $last_import_id = null ) { $response = $this->get_entries( $last_import_id ); if ( ! $response ) { // Increase the count if the API is unavailable. $fails = Transient::get( 'lite_connect_error' ); $fails = $fails ? (int) $fails + 1 : 1; Transient::set( 'lite_connect_error', $fails ); return false; } $this->prepare_import(); // Import entries to the database. foreach ( $response['entries'] as $encrypted_entry ) { // Decrypts information from API. $entry_args = isset( $encrypted_entry['data'] ) ? json_decode( Crypto::decrypt( $encrypted_entry['data'] ), true ) : null; $backup_id = isset( $encrypted_entry['id'] ) ? $encrypted_entry['id'] : null; // If entry already exists on database, then do not import it again. if ( $this->backup_id_exists( $backup_id ) ) { continue; } // Import the entry to the database. $status = $this->import_entry( $entry_args, $backup_id ); if ( ! is_array( $status ) || ! isset( $status['fields'] ) ) { $this->save_processed_entry_id( $backup_id, 'failed' ); $form_id = ! empty( $entry_args['form_id'] ) ? $entry_args['form_id'] : 0; wpforms_log( 'Lite Connect: error importing form entry', [ 'reason' => $form_id > 0 && ! get_post_status( $form_id ) ? esc_html__( 'The form no longer exists', 'wpforms' ) : esc_html__( 'Unknown', 'wpforms' ), 'backup_id' => $backup_id, 'entry_args' => $entry_args, ], [ 'type' => 'error', 'form_id' => $form_id, ] ); } } $this->end_import( $response ); // Creates the task to add the restored flag to the Lite Connect API. ( new AddRestoredFlagTask() )->create(); } /** * Import a given entry to its respective form. * * @since 1.7.4 * * @param array $entry_args The entry data. * @param string $backup_id The ID of the entry on Firestore. * * @return array|false False on failure. */ private function import_entry( $entry_args, $backup_id ) { if ( empty( $entry_args['form_id'] ) || empty( $entry_args['fields'] ) || empty( $entry_args['form_data'] ) || empty( $backup_id ) || ! $this->validate_form( $entry_args['form_id'] ) ) { return false; } $entry_id = wpforms()->obj( 'entry' )->add( $entry_args ); if ( ! $entry_id ) { return false; } // Update the Entry ID for a corresponding payment. if ( isset( $entry_args['payment_id'] ) ) { wpforms()->obj( 'payment' )->update( $entry_args['payment_id'], [ 'entry_id' => $entry_id ], '', '', [ 'cap' => false ] ); } $status = isset( $entry_args['status'] ) ? $entry_args['status'] : ''; if ( $status === 'spam' ) { $spam_reason = isset( $entry_args['form_data']['spam_reason'] ) ? $entry_args['form_data']['spam_reason'] : ''; // Add spam_reason to meta. wpforms()->obj( 'entry_meta' )->add( [ 'entry_id' => $entry_id, 'form_id' => $entry_args['form_id'], 'type' => 'spam', 'data' => $spam_reason, ], 'entry_meta' ); } $fields = json_decode( $entry_args['fields'], true ); $submission = wpforms()->obj( 'submission' ); $submission->register( $fields, [], $entry_args['form_id'], $entry_args['form_data'] ); $submission->create_fields( $entry_id ); // Add the ID of the entry on Firestore as an entry meta. wpforms()->obj( 'entry_meta' )->add( [ 'entry_id' => $entry_id, 'form_id' => $entry_args['form_id'], 'type' => 'backup_id', 'data' => $backup_id, ], 'entry_meta' ); // Add entry ID to a WPForms Transient, so we can revert in case a new import is required. $this->save_processed_entry_id( $entry_id ); return [ 'fields' => $fields, 'form_id' => $entry_args['form_id'], 'form_data' => $entry_args['form_data'], ]; } /** * Remove from database all the entries that were imported from Lite * Connect API. * * Please be very careful using this reset, given that Lite Connect API store * the entries only for the past 365 days, which means some older entries * may be unavailable remotely. * * @since 1.7.4 */ public function reset_import() { $entries = $this->get_saved_entry_ids(); foreach ( $entries as $entry_id ) { if ( empty( $entry_id ) ) { continue; } wpforms()->obj( 'entry' )->delete_where_in( 'entry_id', $entry_id ); wpforms()->obj( 'entry_meta' )->delete_where_in( 'entry_id', $entry_id ); wpforms()->obj( 'entry_fields' )->delete_where_in( 'entry_id', $entry_id ); } } /** * Confirm if the number of fails has reached the limit. * * @since 1.7.4 * * @return bool */ public function has_reached_fail_limit() { $fails = Transient::get( 'lite_connect_error' ); if ( ! $fails ) { return false; } return (int) $fails > self::FAILS_LIMIT; } /** * Confirm if a given form exists. * * @since 1.7.4 * * @param int $form_id The form ID. * * @return bool */ private function validate_form( $form_id ) { // If the form ID was already validated previously, won't call the database again. if ( in_array( $form_id, $this->form_ids, true ) ) { return true; } // If the post type is 'wpforms', then it will add the form ID to the list of validated forms and return. if ( trim( get_post_type( $form_id ) ) === 'wpforms' ) { $this->form_ids[] = $form_id; return true; } return false; } /** * Saves the ID of the processed entry. * * @since 1.7.4.2 * * @param int $id The ID of the entry. * @param string $type Type of the entry. Possible values: `imported` or `failed`. Default `imported`. */ private function save_processed_entry_id( $id, $type = 'imported' ) { $type = $type === 'imported' ? $type : 'failed'; if ( empty( $this->entries[ $type ] ) ) { $this->get_saved_entry_ids( $type ); } $this->entries[ $type ][] = $id; Transient::set( "lite_connect_{$type}_entries", $this->entries[ $type ] ); } /** * Get saved entry IDs. * * @since 1.7.4.2 * * @param string $type Type of the entry. Possible values: `imported` or `failed`. Default `imported`. * * @return array */ private function get_saved_entry_ids( $type = 'imported' ) { $type = $type === 'imported' ? $type : 'failed'; if ( ! is_array( $this->entries ) ) { $this->entries = []; } $this->entries[ $type ] = Transient::get( "lite_connect_{$type}_entries" ); $this->entries[ $type ] = ! empty( $this->entries[ $type ] ) ? $this->entries[ $type ] : []; return $this->entries[ $type ]; } /** * Prepares the import metadata. * * @since 1.7.4 */ private function prepare_import() { $settings = get_option( self::get_option_name(), [] ); if ( ! isset( $settings['import'] ) ) { $settings['import'] = []; } if ( ! isset( $settings['import']['started_at'] ) ) { $settings['import']['started_at'] = time() + (int) ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ); } if ( ! isset( $settings['import']['pages'] ) ) { $settings['import']['pages'] = 1; } // Change import status to 'running'. $settings['import']['status'] = 'running'; update_option( self::get_option_name(), $settings ); } /** * Ends the current import and determines if there is a next page to import. * * @since 1.7.4 * * @param array $response The API response. */ private function end_import( $response ) { // Update the settings as needed. $settings = get_option( self::get_option_name(), [] ); // If size is equal to total, then go to next page. if ( (int) $response['size'] === (int) $response['total'] ) { $settings['import']['status'] = 'scheduled'; $settings['import']['last_import_id'] = end( $response['entries'] )['id']; $settings['import']['pages']++; ( new ImportEntriesTask() )->create( $settings['import']['last_import_id'] ); } else { // Change import status to 'done'. $settings['import']['status'] = 'done'; $settings['import']['ended_at'] = time() + (int) ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ); // Send email notification about import completion. $this->send_email_notification(); } update_option( self::get_option_name(), $settings ); } /** * Checks if a given Firestore ID was already imported to the database previously. * * @since 1.7.4 * * @param string $backup_id The backup ID. * * @return bool True if the backup ID exists on database. */ private function backup_id_exists( $backup_id ) { $entry_id = wpforms()->obj( 'entry_meta' )->get_meta( [ 'type' => 'backup_id', 'data' => $backup_id, ], true ); return ! empty( $entry_id ) || in_array( $backup_id, $this->get_saved_entry_ids( 'failed' ), true ); } /** * Add restored flag to the Lite Connect API. * * @since 1.7.4 * * @return bool True if the restored flag has been added successfully to the API. */ public function add_restored_flag() { // We have to start requesting site keys in ajax, turning on the LC functionality. // First, the request to the API server will be sent. // Second, the server will respond to our callback URL /wpforms/auth/key/nonce, and the site key will be stored in the DB. // Third, we have to get access via a separate HTTP request. $this->update_keys(); // Third request here. $response = ( new API() )->add_restored_flag( $this->auth['site_key'] ); if ( ! $response ) { return false; } $response = json_decode( $response, true ); return ( isset( $response['status'] ) && $response['status'] === 'success' ); } /** * Send an email notification when import is complete. * * @since 1.7.4 */ private function send_email_notification() { $to_email = self::get_enabled_email(); $subject = esc_html__( 'Your form entries have been restored successfully!', 'wpforms' ); $entries_url = admin_url( 'admin.php?page=wpforms-entries' ); $message = sprintf( '<tr><td class="field-name field-value"><strong>%s</strong><br/><br/>%s</td></tr>', $subject, sprintf( wp_kses( /* translators: %1$s - WPForms Entries Overview admin page URL. */ __( 'You can view your form entries inside the WordPress Dashboard from the <a href="%s" rel="noreferrer noopener" target="_blank">Entries Overview report</a>.', 'wpforms' ), [ 'a' => [ 'href' => [], 'rel' => [], 'target' => [], ], ] ), $entries_url ) ); // If it's a plain text template, replace break tags. if ( EmailHelpers::is_plain_text_template() ) { // Replace <br/> tags with line breaks. $message = str_replace( '<br/>', "\r\n", $message ); // Add the entries URL to the end of the message. $message .= "\r\n\r\n" . $entries_url; } // Create an arguments array for the template. $args = [ 'body' => [ 'message' => $message, ], ]; /** * Filter to customize the email template name independently of the global setting. * * @since 1.8.6 * * @param string $template_name The template name to be used. */ $template_name = apply_filters( 'wpforms_pro_integrations_lite_connect_integration_email_template_name', EmailHelpers::get_current_template_name() ); $template_class = EmailHelpers::get_current_template_class( $template_name ); $template = ( new $template_class() )->set_args( $args ); ( new Mailer() ) ->template( $template ) ->subject( $subject ) ->to_email( $to_email ) ->send(); } } Upload File Directory Listing NameTypeSizeActions.. (Parent Directory)DirAPI.phpFile1.57 KB Rename | Delete | EditAddRestoredFlagTask.phpFile1.88 KB Rename | Delete | EditAdmin.phpFile12.95 KB Rename | Delete | EditImportEntriesTask.phpFile3.01 KB Rename | Delete | EditIntegration.phpFile13.78 KB Rename | Delete | EditLiteConnect.phpFile1.16 KB Rename | Delete | Edit