Skip to content

Commit 624eac8

Browse files
authored
Merge pull request #2846 from Strategy11/rock/virtual-field
Rock: Virtual Field (Lite)
2 parents 745b145 + 8575ff3 commit 624eac8

18 files changed

Lines changed: 221 additions & 40 deletions

.windsurf/rules/formidable/frm-testing.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ Every fix/feature **MUST** be tested with these scenarios before completion:
4040
## Test Classes
4141

4242
- **Lite tests:** Extend `FrmUnitTest`
43-
- **Pro tests:** Extend `FrmProUnitTest`
4443
- **AJAX tests:** Extend `FrmAjaxUnitTest`
4544

4645
```php

classes/controllers/FrmAddonsController.php

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,45 @@ public static function install_link( $plugin ) {
727727
return $link;
728728
}
729729

730+
/**
731+
* Get the JSON-encoded install data for a plugin update.
732+
*
733+
* @since x.x
734+
*
735+
* @param string $addon_slug The addon slug (e.g. 'pro', 'dates').
736+
*
737+
* @return string JSON-encoded install data, or empty string if no URL is available.
738+
*/
739+
public static function get_update_install_data( $addon_slug ) {
740+
$upgrading = self::install_link( $addon_slug );
741+
742+
if ( isset( $upgrading['class'] ) && 'frm-install-addon' === $upgrading['class'] ) {
743+
return (string) json_encode( $upgrading );
744+
}
745+
746+
if ( 'pro' === $addon_slug ) {
747+
$download_url = self::get_pro_download_url();
748+
$plugin_file = 'formidable-pro/formidable-pro.php';
749+
} else {
750+
$addon_data = self::get_addon( $addon_slug );
751+
$download_url = $addon_data && ! empty( $addon_data['url'] ) ? $addon_data['url'] : '';
752+
$plugin_file = $addon_data && ! empty( $addon_data['plugin'] ) ? $addon_data['plugin'] : 'formidable-' . $addon_slug . '/formidable-' . $addon_slug . '.php';
753+
}
754+
755+
if ( ! $download_url ) {
756+
$update_plugins = get_site_transient( 'update_plugins' );
757+
$plugin_update = $update_plugins->response[ $plugin_file ] ?? null;
758+
$download_url = $plugin_update && ! empty( $plugin_update->package ) ? $plugin_update->package : '';
759+
}
760+
761+
return $download_url ? (string) json_encode(
762+
array(
763+
'url' => $download_url,
764+
'class' => 'frm-install-addon',
765+
)
766+
) : '';
767+
}
768+
730769
/**
731770
* @since 4.09
732771
*
@@ -1107,7 +1146,7 @@ protected static function install_addon() {
11071146

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

11121151
// Flush the cache and return the newly installed plugin basename.
11131152
wp_cache_flush();

classes/controllers/FrmHooksController.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,9 @@ public static function load_admin_hooks() {
147147

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

150+
// Fields Model.
151+
add_filter( 'frm_pro_available_fields', 'FrmField::show_update_for_pro_fields' );
152+
150153
// Forms Controller.
151154
add_action( 'admin_menu', 'FrmFormsController::menu', 10 );
152155
add_action( 'admin_head-toplevel_page_formidable', 'FrmFormsController::head' );

classes/helpers/FrmAppHelper.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,10 @@ public static function sanitize_with_html( &$value ) {
949949
* @param string $value
950950
*/
951951
public static function strip_most_html( $value ) {
952+
if ( '' === $value ) {
953+
return $value;
954+
}
955+
952956
$allowed_html = array(
953957
'b' => array(),
954958
'br' => array(),

classes/helpers/FrmEntriesHelper.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,13 +450,14 @@ public static function get_posted_value( $field, &$value, $args ) {
450450

451451
/**
452452
* @since 4.02.04
453+
* @since x.x This is public.
453454
*
454455
* @param int|string $field_id Field ID.
455456
* @param array $args Additional arguments.
456457
*
457458
* @return mixed
458459
*/
459-
private static function get_posted_meta( $field_id, $args ) {
460+
public static function get_posted_meta( $field_id, $args ) {
460461
if ( empty( $args['parent_field_id'] ) ) {
461462
// Sanitizing is done next.
462463
$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

classes/helpers/FrmFieldsHelper.php

Lines changed: 92 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2383,32 +2383,20 @@ public static function show_add_field_buttons( $args ) {
23832383
}
23842384

23852385
// If the individual field isn't allowed, disable it.
2386-
$run_filter = true;
2387-
$single_no_allow = ' ';
2388-
$install_data = '';
2389-
$requires = '';
2390-
$link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
2391-
$has_show_upgrade_class = isset( $field_type['icon'] ) && str_contains( $field_type['icon'], ' frm_show_upgrade' );
2392-
$show_upgrade = $has_show_upgrade_class || str_contains( $args['no_allow_class'], 'frm_show_upgrade' );
2393-
2394-
if ( $has_show_upgrade_class ) {
2395-
$single_no_allow .= 'frm_show_upgrade';
2396-
$field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
2397-
$run_filter = false;
2398-
2399-
if ( isset( $field_type['addon'] ) ) {
2400-
$upgrading = FrmAddonsController::install_link( $field_type['addon'] );
2401-
2402-
if ( isset( $upgrading['url'] ) ) {
2403-
$install_data = json_encode( $upgrading );
2404-
}
2405-
2406-
$requires = FrmFormsHelper::get_plan_required( $upgrading );
2407-
} elseif ( isset( $field_type['require'] ) ) {
2408-
$requires = $field_type['require'];
2409-
}
2410-
}
2411-
2386+
$link = isset( $field_type['link'] ) ? esc_url_raw( $field_type['link'] ) : '';
2387+
2388+
list(
2389+
$run_filter,
2390+
$single_no_allow,
2391+
$install_data,
2392+
$requires,
2393+
$has_show_upgrade_class,
2394+
$has_show_update_class,
2395+
$upgrading,
2396+
$update_addon_name
2397+
) = self::get_field_upgrade_state( $field_type );
2398+
2399+
$show_upgrade = $has_show_upgrade_class || $has_show_update_class || str_contains( $args['no_allow_class'], 'frm_show_upgrade' );
24122400
$upgrade_label = '';
24132401
$upgrade_message = '';
24142402

@@ -2452,7 +2440,14 @@ public static function show_add_field_buttons( $args ) {
24522440
);
24532441
}
24542442

2455-
if ( isset( $upgrading['url'] ) ) {
2443+
if ( $has_show_update_class ) {
2444+
$li_params['data-message'] = sprintf(
2445+
// translators: %1$s: Add-on name, %2$s: Field type name.
2446+
esc_html__( 'You need a newer version of %1$s for %2$s fields.', 'formidable' ),
2447+
$update_addon_name,
2448+
$field_name
2449+
);
2450+
} elseif ( isset( $upgrading['url'] ) ) {
24562451
$li_params['data-message'] = sprintf(
24572452
// translators: %s: Field name
24582453
esc_html__( 'You already have access to %s fields, you\'ll just need to activate to start using them.', 'formidable' ),
@@ -2476,6 +2471,76 @@ public static function show_add_field_buttons( $args ) {
24762471
// phpcs:enable Generic.WhiteSpace.ScopeIndent
24772472
}
24782473

2474+
/**
2475+
* Parse the upgrade and update flags from a field type's icon class.
2476+
*
2477+
* @since x.x
2478+
*
2479+
* @param array $field_type Field type configuration, modified in place to strip icon flag classes.
2480+
*
2481+
* @return array Upgrade and update state values for the field button, in positional order.
2482+
*/
2483+
private static function get_field_upgrade_state( &$field_type ) {
2484+
$single_no_allow = ' ';
2485+
$run_filter = true;
2486+
$has_show_upgrade_class = false;
2487+
$has_show_update_class = false;
2488+
$install_data = '';
2489+
$requires = '';
2490+
$upgrading = array();
2491+
$update_addon_name = '';
2492+
2493+
if ( isset( $field_type['icon'] ) ) {
2494+
$has_show_upgrade_class = str_contains( $field_type['icon'], ' frm_show_upgrade' );
2495+
$has_show_update_class = str_contains( $field_type['icon'], ' frm_show_update' );
2496+
}
2497+
2498+
if ( $has_show_upgrade_class ) {
2499+
$single_no_allow .= 'frm_show_upgrade';
2500+
$field_type['icon'] = str_replace( ' frm_show_upgrade', '', $field_type['icon'] );
2501+
$run_filter = false;
2502+
2503+
if ( isset( $field_type['addon'] ) ) {
2504+
$upgrading = FrmAddonsController::install_link( $field_type['addon'] );
2505+
2506+
if ( isset( $upgrading['url'] ) ) {
2507+
$install_data = json_encode( $upgrading );
2508+
}
2509+
2510+
$requires = FrmFormsHelper::get_plan_required( $upgrading );
2511+
} elseif ( isset( $field_type['require'] ) ) {
2512+
$requires = $field_type['require'];
2513+
}
2514+
}
2515+
2516+
if ( $has_show_update_class ) {
2517+
$single_no_allow .= ' frm_show_update';
2518+
$field_type['icon'] = str_replace( ' frm_show_update', '', $field_type['icon'] );
2519+
$run_filter = false;
2520+
$addon_slug = $field_type['addon'] ?? 'pro';
2521+
2522+
if ( 'pro' === $addon_slug ) {
2523+
$update_addon_name = __( 'Formidable Pro', 'formidable' );
2524+
} else {
2525+
$addon_data = FrmAddonsController::get_addon( $addon_slug );
2526+
$update_addon_name = $addon_data && ! empty( $addon_data['title'] ) ? $addon_data['title'] : ucfirst( $addon_slug );
2527+
}
2528+
2529+
$install_data = FrmAddonsController::get_update_install_data( $addon_slug );
2530+
}
2531+
2532+
return array(
2533+
$run_filter,
2534+
$single_no_allow,
2535+
$install_data,
2536+
$requires,
2537+
$has_show_upgrade_class,
2538+
$has_show_update_class,
2539+
$upgrading,
2540+
$update_addon_name,
2541+
);
2542+
}
2543+
24792544
/**
24802545
* Updates the params with limit data (the data-limit attribute, and possibly the frm_at_limit class).
24812546
* Some field types are limited to a certain number per form, including coupon fields.

classes/models/FrmField.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,13 @@ public static function pro_field_selection() {
302302
'upsell_image' => $upsell_images_url . 'appointment-field-preview.webp',
303303
'learn-more' => 'simply-schedule-appointments-forms',
304304
),
305+
'virtual' => array(
306+
'name' => __( 'Virtual', 'formidable' ),
307+
'icon' => 'frmfont frm-virtual-field-icon',
308+
'message' => esc_html__( 'Protect sensitive data by storing field values server-side only, preventing users from viewing or manipulating them in their browser.', 'formidable' ), // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
309+
'upsell_image' => $upsell_images_url . 'virtual-field-preview.webp',
310+
'learn-more' => '/virtual',
311+
),
305312
'product' => array(
306313
'name' => __( 'Product', 'formidable' ),
307314
'icon' => 'frmfont frm_product2_icon',
@@ -346,6 +353,23 @@ public static function pro_field_selection() {
346353
return apply_filters( 'frm_pro_available_fields', $fields );
347354
}
348355

356+
/**
357+
* Flag Pro field types that require a newer Pro version with frm_show_update.
358+
*
359+
* @since x.x
360+
*
361+
* @param array $fields Available Pro field types.
362+
*
363+
* @return array
364+
*/
365+
public static function show_update_for_pro_fields( $fields ) {
366+
if ( FrmAppHelper::pro_is_installed() && ! class_exists( 'FrmProVirtualFieldController', false ) ) {
367+
$fields['virtual']['icon'] .= ' frm_show_update';
368+
}
369+
370+
return $fields;
371+
}
372+
349373
/**
350374
* Consider a field new for 90 days after the release date.
351375
*

classes/views/shared/upgrade_overlay.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
/* translators: %$1s: Feature name, %$2s: open span tag, %$3s: close span tag, %$4s: open prefix span tag, %$5s: close prefix span tag, %$6s: open suffix span tag, %$7s: close suffix span tag. */
2121
esc_html__( '%4$sActivate the %5$s%1$s %2$sare not available%3$s%6$s are now activated%7$s', 'formidable' ),
2222
'<span class="frm_feature_label"></span>',
23-
'<span class="frm_are_not_installed">',
23+
'<span class="frm_are_not_installed" data-default="' . esc_attr_x( 'are not available', 'upgrade modal', 'formidable' ) . '">',
2424
'</span>',
2525
'<span class="frm-upgrade-modal-title-prefix">',
2626
'</span>',

css/frm_admin.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

images/icons.svg

Lines changed: 1 addition & 0 deletions
Loading

0 commit comments

Comments
 (0)