class-base.php
4 months ago
class-checkbox.php
6 months ago
class-email.php
8 months ago
class-gdpr-checkbox.php
8 months ago
class-internal-information.php
10 months ago
class-name.php
10 months ago
class-number-slider.php
1 year ago
class-number.php
1 year ago
class-radio.php
6 months ago
class-select.php
5 months ago
class-text.php
1 year ago
class-textarea.php
1 year ago
class-textarea.php
381 lines
| 1 | <?php |
| 2 | |
| 3 | if ( ! defined( 'ABSPATH' ) ) { |
| 4 | exit; |
| 5 | } |
| 6 | |
| 7 | /** |
| 8 | * Paragraph text field. |
| 9 | * |
| 10 | * @since 1.0.0 |
| 11 | */ |
| 12 | class WPForms_Field_Textarea extends WPForms_Field { |
| 13 | |
| 14 | /** |
| 15 | * Primary class constructor. |
| 16 | * |
| 17 | * @since 1.0.0 |
| 18 | */ |
| 19 | public function init() { |
| 20 | |
| 21 | // Define field type information. |
| 22 | $this->name = esc_html__( 'Paragraph Text', 'wpforms-lite' ); |
| 23 | $this->keywords = esc_html__( 'textarea', 'wpforms-lite' ); |
| 24 | $this->type = 'textarea'; |
| 25 | $this->icon = 'fa-paragraph'; |
| 26 | $this->order = 50; |
| 27 | |
| 28 | add_action( 'wpforms_frontend_js', [ $this, 'frontend_js' ] ); |
| 29 | } |
| 30 | |
| 31 | /** |
| 32 | * Get the value, that is used to prefill via dynamic or fallback population. |
| 33 | * Based on field data and current properties. |
| 34 | * |
| 35 | * @since 1.6.4 |
| 36 | * |
| 37 | * @param string $raw_value Value from a GET param, always a string. |
| 38 | * @param string $input Represent a subfield inside the field. May be empty. |
| 39 | * @param array $properties Field properties. |
| 40 | * @param array $field Current field specific data. |
| 41 | * |
| 42 | * @return array Modified field properties. |
| 43 | */ |
| 44 | protected function get_field_populated_single_property_value( $raw_value, $input, $properties, $field ) { |
| 45 | |
| 46 | if ( ! is_string( $raw_value ) ) { |
| 47 | return $properties; |
| 48 | } |
| 49 | |
| 50 | if ( |
| 51 | ! empty( $input ) && |
| 52 | isset( $properties['inputs'][ $input ] ) |
| 53 | ) { |
| 54 | $properties['inputs'][ $input ]['attr']['value'] = wpforms_sanitize_textarea_field( wp_unslash( $raw_value ) ); |
| 55 | } |
| 56 | |
| 57 | return $properties; |
| 58 | } |
| 59 | |
| 60 | /** |
| 61 | * Field options panel inside the builder. |
| 62 | * |
| 63 | * @since 1.0.0 |
| 64 | * |
| 65 | * @param array $field Field data and settings. |
| 66 | */ |
| 67 | public function field_options( $field ) { |
| 68 | /* |
| 69 | * Basic field options. |
| 70 | */ |
| 71 | |
| 72 | // Options open markup. |
| 73 | $this->field_option( |
| 74 | 'basic-options', |
| 75 | $field, |
| 76 | [ |
| 77 | 'markup' => 'open', |
| 78 | ] |
| 79 | ); |
| 80 | |
| 81 | // Label. |
| 82 | $this->field_option( 'label', $field ); |
| 83 | |
| 84 | // Description. |
| 85 | $this->field_option( 'description', $field ); |
| 86 | |
| 87 | // Required toggle. |
| 88 | $this->field_option( 'required', $field ); |
| 89 | |
| 90 | // Options close markup. |
| 91 | $this->field_option( |
| 92 | 'basic-options', |
| 93 | $field, |
| 94 | [ |
| 95 | 'markup' => 'close', |
| 96 | ] |
| 97 | ); |
| 98 | |
| 99 | /* |
| 100 | * Advanced field options. |
| 101 | */ |
| 102 | |
| 103 | // Options open markup. |
| 104 | $args = [ |
| 105 | 'markup' => 'open', |
| 106 | ]; |
| 107 | |
| 108 | $this->field_option( 'advanced-options', $field, $args ); |
| 109 | |
| 110 | // Size. |
| 111 | $this->field_option( 'size', $field ); |
| 112 | |
| 113 | // Placeholder. |
| 114 | $this->field_option( 'placeholder', $field ); |
| 115 | |
| 116 | // Limit length. |
| 117 | $args = [ |
| 118 | 'slug' => 'limit_enabled', |
| 119 | 'content' => $this->field_element( |
| 120 | 'toggle', |
| 121 | $field, |
| 122 | [ |
| 123 | 'slug' => 'limit_enabled', |
| 124 | 'value' => isset( $field['limit_enabled'] ) ? '1' : '0', |
| 125 | 'desc' => esc_html__( 'Limit Length', 'wpforms-lite' ), |
| 126 | 'tooltip' => esc_html__( 'Check this option to limit text length by characters or words count.', 'wpforms-lite' ), |
| 127 | ], |
| 128 | false |
| 129 | ), |
| 130 | ]; |
| 131 | |
| 132 | $this->field_element( 'row', $field, $args ); |
| 133 | |
| 134 | $count = $this->field_element( |
| 135 | 'text', |
| 136 | $field, |
| 137 | [ |
| 138 | 'type' => 'number', |
| 139 | 'slug' => 'limit_count', |
| 140 | 'attrs' => [ |
| 141 | 'min' => 1, |
| 142 | 'step' => 1, |
| 143 | 'pattern' => '[0-9]', |
| 144 | ], |
| 145 | 'value' => ! empty( $field['limit_count'] ) ? $field['limit_count'] : 1, |
| 146 | ], |
| 147 | false |
| 148 | ); |
| 149 | |
| 150 | $mode = $this->field_element( |
| 151 | 'select', |
| 152 | $field, |
| 153 | [ |
| 154 | 'slug' => 'limit_mode', |
| 155 | 'value' => ! empty( $field['limit_mode'] ) ? esc_attr( $field['limit_mode'] ) : 'characters', |
| 156 | 'options' => [ |
| 157 | 'characters' => esc_html__( 'Characters', 'wpforms-lite' ), |
| 158 | 'words' => esc_html__( 'Words', 'wpforms-lite' ), |
| 159 | ], |
| 160 | ], |
| 161 | false |
| 162 | ); |
| 163 | |
| 164 | $args = [ |
| 165 | 'slug' => 'limit_controls', |
| 166 | 'class' => ! isset( $field['limit_enabled'] ) ? 'wpforms-hide' : '', |
| 167 | 'content' => $count . $mode, |
| 168 | ]; |
| 169 | |
| 170 | $this->field_element( 'row', $field, $args ); |
| 171 | |
| 172 | // Default value. |
| 173 | $this->field_option( 'default_value', $field ); |
| 174 | |
| 175 | // Custom CSS classes. |
| 176 | $this->field_option( 'css', $field ); |
| 177 | |
| 178 | // Hide label. |
| 179 | $this->field_option( 'label_hide', $field ); |
| 180 | |
| 181 | // Options close markup. |
| 182 | $this->field_option( |
| 183 | 'advanced-options', |
| 184 | $field, |
| 185 | [ |
| 186 | 'markup' => 'close', |
| 187 | ] |
| 188 | ); |
| 189 | } |
| 190 | |
| 191 | /** |
| 192 | * Field preview inside the builder. |
| 193 | * |
| 194 | * @since 1.0.0 |
| 195 | * |
| 196 | * @param array $field Field data and settings. |
| 197 | */ |
| 198 | public function field_preview( $field ) { |
| 199 | |
| 200 | // Label. |
| 201 | $this->field_preview_option( 'label', $field ); |
| 202 | |
| 203 | // Primary input. |
| 204 | $placeholder = ! empty( $field['placeholder'] ) ? $field['placeholder'] : ''; |
| 205 | $default_value = ! empty( $field['default_value'] ) ? $field['default_value'] : ''; |
| 206 | |
| 207 | echo '<textarea placeholder="' . esc_attr( $placeholder ) . '" class="primary-input" readonly>' . esc_textarea( $default_value ) . '</textarea>'; |
| 208 | |
| 209 | // Description. |
| 210 | $this->field_preview_option( 'description', $field ); |
| 211 | } |
| 212 | |
| 213 | /** |
| 214 | * Field display on the form front-end. |
| 215 | * |
| 216 | * @since 1.0.0 |
| 217 | * |
| 218 | * @param array $field Field data and settings. |
| 219 | * @param array $deprecated Deprecated. |
| 220 | * @param array $form_data Form data and settings. |
| 221 | */ |
| 222 | public function field_display( $field, $deprecated, $form_data ) { |
| 223 | |
| 224 | // Define data. |
| 225 | $primary = $field['properties']['inputs']['primary']; |
| 226 | $value = ''; |
| 227 | |
| 228 | if ( isset( $primary['attr']['value'] ) ) { |
| 229 | $value = esc_textarea( html_entity_decode( $primary['attr']['value'] ) ); |
| 230 | |
| 231 | unset( $primary['attr']['value'] ); |
| 232 | } |
| 233 | |
| 234 | if ( isset( $field['limit_enabled'] ) ) { |
| 235 | $limit_count = isset( $field['limit_count'] ) ? absint( $field['limit_count'] ) : 0; |
| 236 | $limit_mode = isset( $field['limit_mode'] ) ? sanitize_key( $field['limit_mode'] ) : 'characters'; |
| 237 | |
| 238 | $primary['data']['form-id'] = $form_data['id']; |
| 239 | $primary['data']['field-id'] = $field['id']; |
| 240 | |
| 241 | if ( 'characters' === $limit_mode ) { |
| 242 | $primary['class'][] = 'wpforms-limit-characters-enabled'; |
| 243 | $primary['attr']['maxlength'] = $limit_count; |
| 244 | $primary['data']['text-limit'] = $limit_count; |
| 245 | } else { |
| 246 | $primary['class'][] = 'wpforms-limit-words-enabled'; |
| 247 | $primary['data']['text-limit'] = $limit_count; |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | // Primary field. |
| 252 | printf( |
| 253 | '<textarea %s %s>%s</textarea>', |
| 254 | wpforms_html_attributes( $primary['id'], $primary['class'], $primary['data'], $primary['attr'] ), |
| 255 | $primary['required'], // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 256 | $value // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 257 | ); |
| 258 | } |
| 259 | |
| 260 | /** |
| 261 | * Enqueue frontend limit option js. |
| 262 | * |
| 263 | * @since 1.5.6 |
| 264 | * |
| 265 | * @param array $forms Forms on the current page. |
| 266 | */ |
| 267 | public function frontend_js( $forms ) { |
| 268 | |
| 269 | // Get fields. |
| 270 | $fields = array_map( |
| 271 | function( $form ) { |
| 272 | return empty( $form['fields'] ) ? [] : $form['fields']; |
| 273 | }, |
| 274 | (array) $forms |
| 275 | ); |
| 276 | |
| 277 | // Make fields flat. |
| 278 | $fields = array_reduce( |
| 279 | $fields, |
| 280 | function( $accumulator, $current ) { |
| 281 | return array_merge( $accumulator, $current ); |
| 282 | }, |
| 283 | [] |
| 284 | ); |
| 285 | |
| 286 | // Leave only fields with limit. |
| 287 | $fields = array_filter( |
| 288 | $fields, |
| 289 | function( $field ) { |
| 290 | return $field['type'] === $this->type && isset( $field['limit_enabled'] ); |
| 291 | } |
| 292 | ); |
| 293 | |
| 294 | if ( count( $fields ) ) { |
| 295 | $min = wpforms_get_min_suffix(); |
| 296 | |
| 297 | wp_enqueue_script( |
| 298 | 'wpforms-text-limit', |
| 299 | WPFORMS_PLUGIN_URL . "assets/js/frontend/fields/text-limit.es5{$min}.js", |
| 300 | [], |
| 301 | WPFORMS_VERSION, |
| 302 | $this->load_script_in_footer() |
| 303 | ); |
| 304 | } |
| 305 | } |
| 306 | |
| 307 | /** |
| 308 | * Format and sanitize field. |
| 309 | * |
| 310 | * @since 1.5.6 |
| 311 | * |
| 312 | * @param int $field_id Field ID. |
| 313 | * @param mixed $field_submit Field value that was submitted. |
| 314 | * @param array $form_data Form data and settings. |
| 315 | */ |
| 316 | public function format( $field_id, $field_submit, $form_data ) { |
| 317 | |
| 318 | $field = $form_data['fields'][ $field_id ]; |
| 319 | if ( is_array( $field_submit ) ) { |
| 320 | $field_submit = implode( "\r\n", array_filter( $field_submit ) ); |
| 321 | } |
| 322 | |
| 323 | $name = ! empty( $field['label'] ) ? sanitize_text_field( $field['label'] ) : ''; |
| 324 | |
| 325 | // Sanitize but keep line breaks. |
| 326 | $value = wpforms_sanitize_textarea_field( $field_submit ); |
| 327 | |
| 328 | wpforms()->obj( 'process' )->fields[ $field_id ] = [ |
| 329 | 'name' => $name, |
| 330 | 'value' => $value, |
| 331 | 'id' => wpforms_validate_field_id( $field_id ), |
| 332 | 'type' => $this->type, |
| 333 | ]; |
| 334 | } |
| 335 | |
| 336 | /** |
| 337 | * Validate field on form submit. |
| 338 | * |
| 339 | * @since 1.6.2 |
| 340 | * |
| 341 | * @param int $field_id Field ID. |
| 342 | * @param mixed $field_submit Submitted field value (raw data). |
| 343 | * @param array $form_data Form data and settings. |
| 344 | */ |
| 345 | public function validate( $field_id, $field_submit, $form_data ) { |
| 346 | |
| 347 | parent::validate( $field_id, $field_submit, $form_data ); |
| 348 | |
| 349 | if ( empty( $form_data['fields'][ $field_id ] ) || empty( $form_data['fields'][ $field_id ]['limit_enabled'] ) ) { |
| 350 | return; |
| 351 | } |
| 352 | |
| 353 | if ( is_array( $field_submit ) ) { |
| 354 | $field_submit = implode( "\r\n", array_filter( $field_submit ) ); |
| 355 | } |
| 356 | |
| 357 | $field = $form_data['fields'][ $field_id ]; |
| 358 | $limit = absint( $field['limit_count'] ); |
| 359 | $mode = ! empty( $field['limit_mode'] ) ? sanitize_key( $field['limit_mode'] ) : 'characters'; |
| 360 | $value = wpforms_sanitize_textarea_field( $field_submit ); |
| 361 | |
| 362 | if ( 'characters' === $mode ) { |
| 363 | if ( mb_strlen( str_replace( "\r\n", "\n", $value ) ) > $limit ) { |
| 364 | /* translators: %s - limit characters number. */ |
| 365 | wpforms()->obj( 'process' )->errors[ $form_data['id'] ][ $field_id ] = sprintf( _n( 'Text can\'t exceed %d character.', 'Text can\'t exceed %d characters.', $limit, 'wpforms-lite' ), $limit ); |
| 366 | |
| 367 | return; |
| 368 | } |
| 369 | } else { |
| 370 | if ( wpforms_count_words( $value ) > $limit ) { |
| 371 | /* translators: %s - limit words number. */ |
| 372 | wpforms()->obj( 'process' )->errors[ $form_data['id'] ][ $field_id ] = sprintf( _n( 'Text can\'t exceed %d word.', 'Text can\'t exceed %d words.', $limit, 'wpforms-lite' ), $limit ); |
| 373 | |
| 374 | return; |
| 375 | } |
| 376 | } |
| 377 | } |
| 378 | } |
| 379 | |
| 380 | new WPForms_Field_Textarea(); |
| 381 |