Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
cd0f322
Add new upsells in Lite for missing Pro features
AbdiTolesa Oct 31, 2025
d64fb0c
Update upsell modal title for read only feature
AbdiTolesa Oct 31, 2025
2870c5b
Gray out upsell elements
AbdiTolesa Oct 31, 2025
ea5af86
Add before/after contents upsell
AbdiTolesa Oct 31, 2025
1ad7daa
Add check for field types before showing upsells for certain features
AbdiTolesa Nov 3, 2025
f5aafd2
Add field checks for upsell
AbdiTolesa Nov 3, 2025
ca859f4
Add upsell for autocomplete and visibility features
AbdiTolesa Nov 3, 2025
ca3ffd2
Add Upsell for Create with AI feature
AbdiTolesa Nov 3, 2025
d96ec8b
Update list of fields to show upsell modal
AbdiTolesa Nov 4, 2025
12263ff
Make phrase for create with ai upsell label plural
AbdiTolesa Nov 4, 2025
2904617
Rebuild files
AbdiTolesa Nov 19, 2025
6b6aa68
Merge master
AbdiTolesa Nov 19, 2025
501319c
Merge master
AbdiTolesa Dec 2, 2025
d069ca5
Fix unit test and workflow errors
AbdiTolesa Dec 2, 2025
446ef47
Refactor code
AbdiTolesa Dec 2, 2025
81cf3a2
Simplify code
AbdiTolesa Dec 2, 2025
e0583d7
Merge branch 'master' into issue-5873
Crabcyborg Dec 2, 2025
5c2f6fc
Clean up view files to have less PHP in them
AbdiTolesa Dec 3, 2025
0fd879e
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
AbdiTolesa Dec 3, 2025
b3060bd
Move out AI upseller markup to a separate view file
AbdiTolesa Dec 3, 2025
b2edc1d
Use to show conditional action button
AbdiTolesa Dec 3, 2025
1bb9741
Clean up code a bit
AbdiTolesa Dec 3, 2025
9b671ef
Merge branch 'master' into issue-5873
Crabcyborg Dec 10, 2025
14593b0
Try using render_ai_generate_options_button
AbdiTolesa Dec 11, 2025
c0104a2
Refactor render_ai_generate_options_button to make it versatile
AbdiTolesa Dec 11, 2025
e766a67
Fix merge conflict and merge master
AbdiTolesa Dec 11, 2025
8463a79
Add array element existense check
AbdiTolesa Dec 11, 2025
08746e3
Try fixing all PHPCS errors
AbdiTolesa Dec 11, 2025
f2e5ec5
Address more code quality issues
AbdiTolesa Dec 11, 2025
2c4de92
Make Create with AI upsell button style consistent with the real one
AbdiTolesa Dec 11, 2025
49c0b85
Merge branch 'master' into issue-5873
Crabcyborg Dec 11, 2025
6518900
Remove function param not needed
AbdiTolesa Dec 23, 2025
ac4cca7
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
AbdiTolesa Dec 23, 2025
3b6f310
Fix conflict with formidable_admin.js
AbdiTolesa Dec 23, 2025
e970eba
Remove unused var
AbdiTolesa Dec 23, 2025
cd24b74
Merge branch 'master' into issue-5873
Crabcyborg Jan 5, 2026
aad2427
Move files around and cut down functiona rgs
AbdiTolesa Jan 6, 2026
397ae34
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
AbdiTolesa Jan 6, 2026
76472f4
Shorten code
AbdiTolesa Jan 6, 2026
eb87c82
Fix copy paste error
AbdiTolesa Jan 6, 2026
e97e5d5
Apply ifelse to ternary operator
AbdiTolesa Jan 6, 2026
b287cdb
Fix potential bug
AbdiTolesa Jan 6, 2026
4b9b483
Merge branch 'master' into issue-5873
Crabcyborg Jan 6, 2026
e10ff02
Fix missing upgrade modal buttons attributes
AbdiTolesa Jan 12, 2026
b491da7
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
AbdiTolesa Jan 12, 2026
9a7f2d1
Merge master
AbdiTolesa Jan 12, 2026
70748ff
Fix PHPCS errors
AbdiTolesa Jan 12, 2026
2966a6f
Merge branch 'master' into issue-5873
Crabcyborg Jan 12, 2026
28fa3e1
Add unique kb links and make sure utm params are set properly for all…
AbdiTolesa Jan 12, 2026
821389c
Fix code style errors
AbdiTolesa Jan 12, 2026
56a3256
Merge branch 'master' into issue-5873
Crabcyborg Jan 23, 2026
479b498
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
Crabcyborg Jan 23, 2026
9e2ba34
Run phpcbf
Crabcyborg Jan 23, 2026
312f880
Move upsell elements html atts inside a Pro check
AbdiTolesa Jan 23, 2026
2710acf
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
AbdiTolesa Jan 23, 2026
fd39154
Merge branch 'master' into issue-5873
Crabcyborg Mar 25, 2026
c48b759
Add missing empty line before css rule
AbdiTolesa Mar 25, 2026
5ffc956
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
AbdiTolesa Mar 25, 2026
d14c009
Merge branch 'master' into issue-5873
Crabcyborg Mar 25, 2026
4e714dd
Merge branch 'master' into issue-5873
Crabcyborg Mar 26, 2026
ea21cca
Apply new sniff
Crabcyborg Mar 26, 2026
656970a
Fix merge conflicts and rebuild assets
AbdiTolesa Mar 30, 2026
dc2fde3
Merge branch 'issue-5873' of https://github.com/Strategy11/formidable…
AbdiTolesa Mar 30, 2026
901f090
Enable Before/After content based upsell in Quantity and Total fields
AbdiTolesa Mar 30, 2026
3a973c2
Shuffle order of upsell feature elements
AbdiTolesa Apr 1, 2026
cd40f6b
Merge branch 'master' into issue-5873
Crabcyborg Apr 2, 2026
49a3e23
Add typo exception
Crabcyborg Apr 2, 2026
9b9e2a0
Fix unique setting is always readonly
Crabcyborg Apr 2, 2026
49f23ab
Use an early exit and only check the unique setting if pro is installed
Crabcyborg Apr 2, 2026
52c479c
Go back to just calling the function
Crabcyborg Apr 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions _typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ Ags = "Ags"
unmergable = "unmergable"
# This is detected in our Stripe publishable key.
iz = "iz"
# This is used in a Sniff to reference a PHP function that does exist.
writeable = "writeable"

[default.extend-identifiers]
66afe9 = "66afe9"
Expand Down
71 changes: 71 additions & 0 deletions classes/controllers/FrmFieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,77 @@ public static function load_single_field_settings( $atts ) {
$field['placeholder'] = implode( ', ', $field['placeholder'] );
}

$pro_is_installed = FrmAppHelper::pro_is_installed();

$unique_values_label_atts = array(
'for' => 'frm_uniq_field_' . $field['id'],
'class' => 'frm_help frm-mb-0',
'title' => __(
'Unique: Do not allow the same response multiple times. For example, if one user enters \'Joe\', then no one else will be allowed to enter the same name.',
'formidable'
),
'data-trigger' => 'hover',
);

$read_only_label_atts = array(
'for' => 'frm_read_only_field_' . $field['id'],
'class' => 'frm_help frm-mb-0',
'title' => __( 'Read Only: Show this field but do not allow the field value to be edited from the front-end.', 'formidable' ),
'data-trigger' => 'hover',
);

if ( ! $pro_is_installed ) {
$visibility_upsell_atts = FrmSettingsUpsellHelper::add_upgrade_modal_atts(
array(
'id' => 'field_options_admin_only_' . $field['id'],
'readonly' => '1',
),
'field_visibility',
__( 'Visibility options', 'formidable' ),
'/field-options/#kb-visibility'
);

$autocomplete_upsell_atts = FrmSettingsUpsellHelper::add_upgrade_modal_atts(
array( 'id' => 'field_options_autocomplete_' . $field['id'] ),
'autocomplete',
__( 'Autocomplete options', 'formidable' ),
'/email-address/#kb-autocomplete-attribute'
);

$before_after_content_upsell_atts = FrmSettingsUpsellHelper::add_upgrade_modal_atts(
array(
'type' => 'text',
'readonly' => '1',
),
'before_after_contents',
__( 'Before and after field contents', 'formidable' ),
'/field-options/#kb-before-after-input'
);

$show_upsell_for_unique_value = in_array(
$field['type'],
array( 'address', 'checkbox', 'email', 'name', 'number', 'phone', 'radio', 'text', 'textarea', 'url' ),
true
);
$show_upsell_for_read_only = in_array( $field['type'], array( 'email', 'hidden', 'number', 'phone', 'radio', 'text', 'textarea', 'url' ), true );
$show_upsell_for_before_after_contents = in_array( $field['type'], array( 'email', 'number', 'phone', 'quantity', 'select', 'tag', 'text', 'total', 'url' ), true );
$show_upsell_for_autocomplete = in_array( $field['type'], array( 'text', 'email', 'number' ), true );
$show_upsell_for_visibility = $field['type'] !== 'hidden';

$unique_values_label_atts = FrmSettingsUpsellHelper::add_upgrade_modal_atts(
$unique_values_label_atts,
'unique_values',
__( 'Unique Values', 'formidable' ),
'/field-options/#kb-unique'
);
$read_only_label_atts = FrmSettingsUpsellHelper::add_upgrade_modal_atts(
$read_only_label_atts,
'read_only',
__( 'Read Only Values', 'formidable' ),
'/field-options/#kb-read-only'
);
}//end if

include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/settings.php';
}

Expand Down
7 changes: 4 additions & 3 deletions classes/helpers/FrmFieldsHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -2836,10 +2836,11 @@ public static function get_all_draft_field_ids( $form_id ) {
*/
public static function render_ai_generate_options_button( $args, $should_hide_bulk_edit = false ) {
$attributes = array(
'type' => 'button',
'class' => self::get_ai_generate_options_button_class(),
'type' => 'button',
);

$attributes['class'] = ! empty( $args['class'] ) ? $args['class'] : self::get_ai_generate_options_button_class();

if ( $should_hide_bulk_edit ) {
$attributes['class'] .= ' frm-force-hidden';
}
Expand All @@ -2848,7 +2849,7 @@ public static function render_ai_generate_options_button( $args, $should_hide_bu
'ai',
array(
'requires' => 'Business',
'upgrade' => __( 'Generate options with AI', 'formidable' ),
'upgrade' => $args['upgrade_text'] ?? __( 'Generate options with AI', 'formidable' ),
'medium' => 'builder',
'content' => 'generate-options-with-ai',
),
Expand Down
92 changes: 92 additions & 0 deletions classes/helpers/FrmSettingsUpsellHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
die( 'You are not allowed to call this page directly.' );
}

/**
* Helper class for displaying upsell controls.
*
* @since x.x
*/
class FrmSettingsUpsellHelper {
/**
* @since x.x
*
* @param array $field
*
* @return array
*/
public static function get_unique_element_atts( $field ) {
$unique_element_atts = array(
'type' => 'checkbox',
'name' => 'field_options[unique_' . $field['id'] . ']',
'id' => 'frm_uniq_field_' . $field['id'],
'value' => '1',
'class' => 'frm_mark_unique',
);

if ( FrmAppHelper::pro_is_installed() ) {
if ( ! empty( $field['unique'] ) ) {
$unique_element_atts['checked'] = 'checked';
}
return $unique_element_atts;
}

$unique_element_atts['data-upgrade'] = __( 'Unique fields', 'formidable' );
$unique_element_atts['disabled'] = '1';
$unique_element_atts['readonly'] = '1';

return $unique_element_atts;
}

/**
* @since x.x
*
* @param array $field
*
* @return array
*/
public static function get_read_only_element_atts( $field ) {
$read_only_element_atts = array(
'type' => 'checkbox',
'name' => 'field_options[read_only_' . $field['id'] . ']',
'id' => 'frm_read_only_field_' . $field['id'],
'value' => '1',
);

if ( ! empty( $field['read_only'] ) ) {
$read_only_element_atts['checked'] = 'checked';
}

if ( ! FrmAppHelper::pro_is_installed() ) {
$read_only_element_atts['data-upgrade'] = __( 'Read only fields', 'formidable' );
$read_only_element_atts['disabled'] = '1';
}

return $read_only_element_atts;
}

/**
* @since x.x
*
* @param array $atts
* @param string $utm_content
* @param string $upgrade_text
* @param string $kb_slug
*
* @return array
*/
public static function add_upgrade_modal_atts( $atts, $utm_content, $upgrade_text, $kb_slug = '' ) {
if ( empty( $atts['class'] ) ) {
$atts['class'] = '';
}

$atts['class'] .= ' frm_show_upgrade';
$atts['data-medium'] = 'lite';
$atts['data-content'] = $utm_content;
$atts['data-upgrade'] = $upgrade_text;
$atts['data-learn-more'] = 'https://formidableforms.com/knowledgebase' . $kb_slug;

return $atts;
}
}
2 changes: 1 addition & 1 deletion classes/models/fields/FrmFieldProduct.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ protected function field_settings_for_type() {
*/
protected function show_priority_field_choices( $args = array() ) {
$field = $args['field'];
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/separate-values.php';
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/upsell/separate-values.php';
}

/**
Expand Down
4 changes: 4 additions & 0 deletions classes/views/form-templates/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
* @since 6.10
*/
do_action( 'frm_after_create_blank_form_button' );

if ( ! class_exists( 'FrmAIAppHelper' ) ) {
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/upsell/ai-upsell-button.php';
}
?>
</div>
<span id="frm-form-templates-create-form-divider" class="frm-page-skeleton-divider frm-mt-xs frm-mb-xs"></span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,8 @@
?>
<button <?php FrmAppHelper::array_to_html_params( $attributes, true ); ?>>
<?php FrmAppHelper::icon_by_class( 'frmfont frm-ai-form-icon frm_svg15', array( 'aria-label' => __( 'Generate options with AI', 'formidable' ) ) ); ?>
<span><?php esc_html_e( 'Generate with AI', 'formidable' ); ?></span>
<span><?php echo esc_html( $args['button_text'] ?? __( 'Generate with AI', 'formidable' ) ); ?></span>
<?php if ( isset( $args['show_pill'] ) ) : ?>
<?php FrmAppHelper::show_pill_text( __( 'BETA', 'formidable' ) ); ?>
<?php endif; ?>
</button>
2 changes: 1 addition & 1 deletion classes/views/frm-fields/back-end/radio-images.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@

FrmFieldsHelper::show_radio_display_format( $args['field'] );

include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/separate-values.php';
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/upsell/separate-values.php';
19 changes: 0 additions & 19 deletions classes/views/frm-fields/back-end/separate-values.php

This file was deleted.

28 changes: 20 additions & 8 deletions classes/views/frm-fields/back-end/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,22 +103,22 @@
<?php
}

if ( $display['unique'] ) {
if ( $display['unique'] || ! empty( $show_upsell_for_unique_value ) ) {
?>
<div class="frm_form_field">
<label for="frm_uniq_field_<?php echo esc_attr( $field['id'] ); ?>" class="frm_help frm-mb-0" title="<?php esc_attr_e( 'Unique: Do not allow the same response multiple times. For example, if one user enters \'Joe\', then no one else will be allowed to enter the same name.', 'formidable' ); ?>" data-trigger="hover">
<input type="checkbox" name="field_options[unique_<?php echo esc_attr( $field['id'] ); ?>]" id="frm_uniq_field_<?php echo esc_attr( $field['id'] ); ?>" value="1" <?php checked( $field['unique'], 1 ); ?> class="frm_mark_unique" />
<label <?php FrmAppHelper::array_to_html_params( $unique_values_label_atts, true ); ?>>
<input <?php FrmAppHelper::array_to_html_params( FrmSettingsUpsellHelper::get_unique_element_atts( $field ), true ); ?> />
<?php esc_html_e( 'Unique', 'formidable' ); ?>
</label>
</div>
<?php
}

if ( $display['read_only'] ) {
if ( $display['read_only'] || ! empty( $show_upsell_for_read_only ) ) {
?>
<div class="frm_form_field">
<label for="frm_read_only_field_<?php echo esc_attr( $field['id'] ); ?>" class="frm_help frm-mb-0" title="<?php esc_attr_e( 'Read Only: Show this field but do not allow the field value to be edited from the front-end.', 'formidable' ); ?>" data-trigger="hover">
<input type="checkbox" id="frm_read_only_field_<?php echo esc_attr( $field['id'] ); ?>" name="field_options[read_only_<?php echo esc_attr( $field['id'] ); ?>]" value="1" <?php checked( $field['read_only'], 1 ); ?>/>
<label <?php FrmAppHelper::array_to_html_params( $read_only_label_atts, true ); ?>>
<input <?php FrmAppHelper::array_to_html_params( FrmSettingsUpsellHelper::get_read_only_element_atts( $field ), true ); ?> />
<?php esc_html_e( 'Read Only', 'formidable' ); ?>
</label>
</div>
Expand Down Expand Up @@ -331,9 +331,21 @@
$display_max = $display['max'];
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/pixels-wide.php';
}
?>

<?php if ( $display['show_image'] ) { ?>
if ( ! empty( $show_upsell_for_before_after_contents ) ) {
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/upsell/before-after-contents.php';
}

if ( ! empty( $show_upsell_for_autocomplete ) ) {
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/upsell/autocomplete.php';
}

if ( ! empty( $show_upsell_for_visibility ) ) {
include FrmAppHelper::plugin_path() . '/classes/views/frm-fields/back-end/upsell/visibility.php';
}

if ( $display['show_image'] ) {
?>
<p class="frm_form_field">
<label class="frm-force-flex frm-gap-xs" for="frm_show_image_<?php echo esc_attr( $field['id'] ); ?>">
<input class="frm-m-0" type="checkbox" id="frm_show_image_<?php echo esc_attr( $field['id'] ); ?>" name="field_options[show_image_<?php echo esc_attr( $field['id'] ); ?>]" value="1" <?php checked( $field['show_image'], 1 ); ?> />
Expand Down
15 changes: 15 additions & 0 deletions classes/views/frm-fields/back-end/upsell/ai-upsell-button.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
die( 'You are not allowed to call this page directly.' );
}
/**
* @since x.x
*/
FrmFieldsHelper::render_ai_generate_options_button(
array(
'show_pill' => true,
'button_text' => __( 'Create with AI', 'formidable' ),
'class' => 'frm-form-templates-create-button frm-flex-box frm-items-center frm_show_upgrade',
'upgrade_text' => __( 'Create with AI', 'formidable' ),
)
);
27 changes: 27 additions & 0 deletions classes/views/frm-fields/back-end/upsell/autocomplete.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
die( 'You are not allowed to call this page directly.' );
}
/**
* @since x.x
*
* @var array $field
*/
?>
<p class="frm6 frm_form_field frm_show_upgrade">
<label class="frm-h-stack-xs" id="for_field_options_autocomplete_<?php echo absint( $field['id'] ); ?>" for="field_options_autocomplete_<?php echo absint( $field['id'] ); ?>">
<span><?php esc_html_e( 'Autocomplete', 'formidable' ); ?></span>
<?php
FrmAppHelper::tooltip_icon(
__( 'The autocomplete attribute asks the browser to attempt autocompletion, based on user history.', 'formidable' ),
array(
'data-placement' => 'right',
'class' => 'frm-flex',
)
);
?>
</label>
<select <?php FrmAppHelper::array_to_html_params( $autocomplete_upsell_atts, true ); ?>>
<option value=""><?php esc_html_e( '&mdash; Select &mdash;' ); ?></option>
</select>
</p>
34 changes: 34 additions & 0 deletions classes/views/frm-fields/back-end/upsell/before-after-contents.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
die( 'You are not allowed to call this page directly.' );
}
/**
* @since x.x
*
* @var array $field
*/
?>
<p class="frm_form_field frm6">
<label class="frm-h-stack-xs frm_show_upgrade" for="prepend_<?php echo absint( $field['id'] ); ?>">
<span><?php esc_html_e( 'Before Input', 'formidable' ); ?></span>
<?php
FrmAppHelper::tooltip_icon(
__( 'A value entered here will show directly before the input box in the form.', 'formidable' ),
array(
'data-placement' => 'right',
'class' => 'frm-flex',
)
);
?>
</label>

<input id="prepend_<?php echo absint( $field['id'] ); ?>" <?php FrmAppHelper::array_to_html_params( $before_after_content_upsell_atts, true ); ?>/>
</p>

<p class="frm_form_field frm6">
<label for="append_<?php echo absint( $field['id'] ); ?>" class="frm_show_upgrade">
<?php esc_html_e( 'After Input', 'formidable' ); ?>
</label>

<input id="append_<?php echo absint( $field['id'] ); ?>" <?php FrmAppHelper::array_to_html_params( $before_after_content_upsell_atts, true ); ?>/>
</p>
Loading
Loading