Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion classes/controllers/FrmFieldsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ public static function load_field() {

// admin_footer never fires here, so the deferred tooltip text rides along with the html.
// Field ids are numeric, so this key can never collide with one.
$field_html['tooltips'] = FrmAppHelper::get_deferred_tooltips();
$field_html['tooltips'] = FrmAppHelper::get_deferred_tooltips();
$field_html['selectOptions'] = FrmBuilderSelectHelper::get_templates();

echo json_encode( $field_html );

Expand Down
1 change: 1 addition & 0 deletions classes/controllers/FrmHooksController.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ public static function load_admin_hooks() {
add_action( 'admin_init', 'FrmAppController::admin_init', 11 );
add_action( 'admin_enqueue_scripts', 'FrmAppController::admin_enqueue_scripts' );
add_action( 'admin_footer', 'FrmAppHelper::print_deferred_tooltips' );
add_action( 'admin_footer', 'FrmBuilderSelectHelper::print_templates' );
add_filter( 'plugin_action_links_' . FrmAppHelper::plugin_folder() . '/formidable.php', 'FrmAppController::settings_link' );
add_filter( 'admin_footer_text', 'FrmAppController::set_footer_text' );
add_action( 'admin_footer', 'FrmAppController::add_admin_footer_links' );
Expand Down
105 changes: 105 additions & 0 deletions classes/helpers/FrmBuilderSelectHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

if ( ! defined( 'ABSPATH' ) ) {
die( 'You are not allowed to call this page directly.' );
}

/**
* Shares repeated builder option lists while keeping saved selections in the form.
*
* @since x.x
*/
class FrmBuilderSelectHelper {

/**
* @var array<string,array>
*/
private static $templates = array();

/**
* Render a select, deferring unselected options only when its registry can be delivered.
*
* @since x.x
*
* @param array $attributes Select attributes.
* @param array $options Option labels keyed by value, in display order.
* @param array<int|string>|string $selected Selected values.
* @param array $option_attributes Additional option attributes keyed by value.
*
* @return void
*/
public static function render( $attributes, $options, $selected, $option_attributes = array() ) {
$records = array();

foreach ( $options as $value => $label ) {
$records[] = array(
'value' => (string) $value,
'label' => html_entity_decode( (string) $label, ENT_QUOTES, 'UTF-8' ),
'attributes' => $option_attributes[ $value ] ?? array(),
);
}

$selected = array_map( 'strval', (array) $selected );

if ( ! isset( $attributes['multiple'] ) && ! array_intersect( $selected, array_keys( $options ) ) ) {
// Match the browser's default selection when the saved value is no longer available.
foreach ( $records as $record ) {
if ( ! isset( $record['attributes']['disabled'] ) ) {
$selected = array( $record['value'] );
break;
}
}
}

$defer = wp_doing_ajax()
? 'frm_load_field' === FrmAppHelper::get_post_param( 'action', '', 'sanitize_text_field' )
: FrmAppHelper::is_form_builder_page( false );

if ( $defer && $records ) {
$key = md5( wp_json_encode( $records ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use of insecure md5() function found


Using md5(), sha1() function is not recommended to generate secure passwords. Due to its fast nature to compute passwords too quickly, these functions can become really easy to crack a password using brute force attack.

It is recommended to use PHP's password hashing function password_hash() to create a secure password hash.

self::$templates[ $key ] = $records;
$attributes['data-frm-options'] = $key;
}

echo '<select';
FrmAppHelper::array_to_html_params( $attributes, true );
echo '>';

foreach ( $records as $record ) {
$is_selected = in_array( $record['value'], $selected, true );

if ( $defer && ! $is_selected ) {
continue;
}

$params = $record['attributes'];
$params['value'] = $record['value'];
FrmHtmlHelper::echo_dropdown_option( $options[ $record['value'] ], $is_selected, $params );
}
echo '</select>';
}

/**
* Get option lists collected during this request, including AJAX field batches.
*
* @since x.x
*
* @return array<string,array>
*/
public static function get_templates() {
return self::$templates;
}

/**
* Deliver the initial page's shared options alongside the builder script.
*
* @since x.x
*
* @return void
*/
public static function print_templates() {
if ( self::$templates ) {
wp_add_inline_script( 'formidable_admin', 'frm_admin_js.selectOptions = ' . wp_json_encode( self::$templates ) . ';', 'before' );
}
}
}
19 changes: 10 additions & 9 deletions classes/views/frm-fields/back-end/autocomplete.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@
);
?>
</label>
<select name="field_options[autocomplete_<?php echo absint( $field['id'] ); ?>]" id="field_options_autocomplete_<?php echo absint( $field['id'] ); ?>">
<?php
FrmHtmlHelper::echo_dropdown_option( __( '&mdash; Select &mdash;', 'formidable' ), '' === $selected_value, array( 'value' => '' ) );

foreach ( $autocomplete_options as $value => $label ) {
FrmHtmlHelper::echo_dropdown_option( $label, $selected_value === (string) $value, array( 'value' => $value ) );
}
?>
</select>
<?php
FrmBuilderSelectHelper::render(
array(
'name' => 'field_options[autocomplete_' . $field['id'] . ']',
'id' => 'field_options_autocomplete_' . $field['id'],
),
array( '' => __( '&mdash; Select &mdash;', 'formidable' ) ) + $autocomplete_options,
$selected_value
);
?>
</p>
88 changes: 41 additions & 47 deletions classes/views/frm-fields/back-end/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -439,36 +439,28 @@
<?php if ( $display['label_position'] ) { ?>
<p class="frm6 frm_form_field">
<label for="field_options_label_<?php echo esc_attr( $field['id'] ); ?>"><?php esc_html_e( 'Label Position', 'formidable' ); ?></label>
<select id="field_options_label_<?php echo esc_attr( $field['id'] ); ?>" name="field_options[label_<?php echo esc_attr( $field['id'] ); ?>]">
<option value="" <?php selected( $field['label'], '' ); ?>>
<?php esc_html_e( 'Default', 'formidable' ); ?>
</option>
<?php
foreach ( FrmStylesHelper::get_single_label_positions( $field ) as $pos => $pos_label ) {
if ( ! $display['clear_on_focus'] && 'inside' === $pos ) {
// Don't allow inside labels for fields without placeholders.
continue;
}
FrmHtmlHelper::echo_dropdown_option(
$pos_label,
$pos === $field['label'],
array(
'value' => $pos,
)
);
}
<?php
$label_options = array( '' => __( 'Default', 'formidable' ) );

if ( $field['type'] === 'divider' ) {
FrmHtmlHelper::echo_dropdown_option(
__( 'Center', 'formidable' ),
'center' === $field['label'],
array(
'value' => 'center',
)
);
foreach ( FrmStylesHelper::get_single_label_positions( $field ) as $pos => $pos_label ) {
if ( ! $display['clear_on_focus'] && 'inside' === $pos ) {
continue;
}
?>
</select>
$label_options[ $pos ] = $pos_label;
}

if ( 'divider' === $field['type'] ) {
$label_options['center'] = __( 'Center', 'formidable' );
}
FrmBuilderSelectHelper::render(
array(
'id' => 'field_options_label_' . $field['id'],
'name' => 'field_options[label_' . $field['id'] . ']',
),
$label_options,
$field['label']
);
?>
</p>
<?php
}//end if
Expand All @@ -486,27 +478,29 @@
<label for="field_options_type_<?php echo esc_attr( $field['id'] ); ?>">
<?php esc_html_e( 'Field Type', 'formidable' ); ?>
</label>
<select name="field_options[type_<?php echo esc_attr( $field['id'] ); ?>]" id="field_options_type_<?php echo esc_attr( $field['id'] ); ?>">
<?php
foreach ( $field_types as $fkey => $ftype ) {
// We need to avoid the word "select" in POST requests.
// When "dropdown" is sent as a type value, we'll map it back to "select" with PHP.
$type_option_value = 'select' === $fkey ? 'dropdown' : $fkey;
$type_option_params = array( 'value' => $type_option_value );

if ( array_key_exists( $fkey, $disabled_fields ) ) {
$type_option_params['disabled'] = 'disabled';
}
<?php
$type_options = array();
$type_attributes = array();

FrmHtmlHelper::echo_dropdown_option(
is_array( $ftype ) ? $ftype['name'] : $ftype,
$fkey === $field['type'],
$type_option_params
);
unset( $fkey, $ftype, $type_option_value, $type_option_params );
foreach ( $field_types as $fkey => $ftype ) {
// Avoid the word "select" in POST requests. PHP maps "dropdown" back to "select".
$type_value = 'select' === $fkey ? 'dropdown' : $fkey;
$type_options[ $type_value ] = is_array( $ftype ) ? $ftype['name'] : $ftype;

if ( array_key_exists( $fkey, $disabled_fields ) ) {
$type_attributes[ $type_value ] = array( 'disabled' => 'disabled' );
}
?>
</select>
}
FrmBuilderSelectHelper::render(
array(
'name' => 'field_options[type_' . $field['id'] . ']',
'id' => 'field_options_type_' . $field['id'],
),
$type_options,
'select' === $field['type'] ? 'dropdown' : $field['type'],
$type_attributes
);
?>
</p>
<?php } else { ?>
<input type="hidden" id="field_options_type_<?php echo esc_attr( $field['id'] ); ?>" value="<?php echo esc_attr( $field['type'] ); ?>" />
Expand Down
2 changes: 1 addition & 1 deletion js/formidable-settings-components.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion js/formidable_admin.js

Large diffs are not rendered by default.

Loading
Loading