PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/models/FrmFormAction.php +369 -230 6.5.3 → trunk View file →
@@ -4,19 +4,71 @@
4 4 }
5 5
6 6 class FrmFormAction {
7 7
8 - public $id_base; // Root id for all actions of this type.
9 - public $name; // Name for this action type.
8 + /**
9 + * Root id for all actions of this type.
10 + *
11 + * @var string
12 + */
13 + public $id_base;
14 +
15 + /**
16 + * Name for this action type.
17 + *
18 + * @var string
19 + */
20 + public $name;
21 +
22 + /**
23 + * Name of the option used to store the settings for this action type.
24 + *
25 + * @var string
26 + */
10 27 public $option_name;
11 - public $action_options; // Option array passed to wp_register_sidebar_widget()
12 - public $control_options; // Option array passed to wp_register_widget_control()
13 28
14 - public $form_id; // The ID of the form to evaluate
15 - public $number = false; // Unique ID number of the current instance.
16 - public $id = ''; // Unique ID string of the current instance (id_base-number)
17 - public $updated = false; // Set true when we update the data after a POST submit - makes sure we don't do it twice.
29 + /**
30 + * Option array passed to wp_register_sidebar_widget().
31 + *
32 + * @var array
33 + */
34 + public $action_options;
18 35
36 + /**
37 + * Option array passed to wp_register_widget_control().
38 + *
39 + * @var array
40 + */
41 + public $control_options;
42 +
43 + /**
44 + * The ID of the form to evaluate.
45 + *
46 + * @var int
47 + */
48 + public $form_id;
49 +
50 + /**
51 + * Unique ID number of the current instance.
52 + *
53 + * @var int
54 + */
55 + public $number = false;
56 +
57 + /**
58 + * Unique ID string of the current instance (id_base-number).
59 + *
60 + * @var string
61 + */
62 + public $id = '';
63 +
64 + /**
65 + * Set true when we update the data after a POST submit - makes sure we don't do it twice.
66 + *
67 + * @var bool
68 + */
69 + public $updated = false;
70 +
19 71 // Member functions that you must over-ride.
20 72
21 73 /**
22 74 * This function should check that $new_instance is set correctly.
@@ -22,10 +74,10 @@
22 74 * This function should check that $new_instance is set correctly.
23 75 * The newly calculated value of $instance should be returned.
24 76 * If "false" is returned, the instance won't be saved/updated.
25 77 *
26 - * @param array $new_instance New settings for this instance as input by the user via form()
27 - * @param array $old_instance Old settings for this instance
78 + * @param array $new_instance New settings for this instance as input by the user via form().
79 + * @param array $old_instance Old settings for this instance.
28 80 *
29 81 * @return array Settings to save or bool false to cancel saving
30 82 */
31 83 public function update( $new_instance, $old_instance ) {
@@ -34,14 +86,15 @@
34 86
35 87 /**
36 88 * Echo the settings update form
37 89 *
38 - * @param WP_Post $instance Current settings
90 + * @param WP_Post $instance Current settings.
39 91 * @param array $args
92 + *
93 + * @return string
40 94 */
41 95 public function form( $instance, $args = array() ) {
42 96 echo '<p class="no-options-widget">' . esc_html__( 'There are no options for this action.', 'formidable' ) . '</p>';
43 -
44 97 return 'noform';
45 98 }
46 99
47 100 /**
@@ -57,8 +110,14 @@
57 110 public function get_switch_fields() {
58 111 return array();
59 112 }
60 113
114 + /**
115 + * @param object $action
116 + * @param object $form
117 + *
118 + * @return object
119 + */
61 120 public function migrate_values( $action, $form ) {
62 121 return $action;
63 122 }
64 123
@@ -69,14 +128,14 @@
69 128 *
70 129 * @param string $id_base Optional Base ID for the widget, lower case,
71 130 * if left empty a portion of the widget's class name will be used. Has to be unique.
72 131 * @param string $name Name for the widget displayed on the configuration page.
73 - * @param array $action_options Optional Passed to wp_register_sidebar_widget()
74 - * - description: shown on the configuration page
75 - * - classname
76 - * @param array $control_options Optional Passed to wp_register_widget_control()
77 - * - width: required if more than 250px
78 - * - height: currently not used but may be needed in the future
132 + * @param array $action_options Optional Passed to wp_register_sidebar_widget().
133 + * - description: shown on the configuration page.
134 + * - classname.
135 + * @param array $control_options Optional Passed to wp_register_widget_control().
136 + * - width: required if more than 250px.
137 + * - height: currently not used but may be needed in the future.
79 138 */
80 139 public function __construct( $id_base, $name, $action_options = array(), $control_options = array() ) {
81 140 if ( ! defined( 'ABSPATH' ) ) {
82 141 die( 'You are not allowed to call this page directly.' );
@@ -81,9 +140,17 @@
81 140 if ( ! defined( 'ABSPATH' ) ) {
82 141 die( 'You are not allowed to call this page directly.' );
83 142 }
84 143
85 - $this->id_base = strtolower( $id_base );
144 + $this->id_base = strtolower( $id_base );
145 +
146 + /**
147 + * @since 6.31
148 + *
149 + * @param string $name
150 + */
151 + $name = apply_filters( 'frm_' . $id_base . '_action_name', $name );
152 +
86 153 $this->name = $name;
87 154 $this->option_name = 'frm_' . $this->id_base . '_action';
88 155
89 156 $default_options = array(
@@ -98,8 +165,11 @@
98 165 'tooltip' => $name,
99 166 'group' => $id_base,
100 167 'color' => '',
101 168 'keywords' => '',
169 + 'description' => '',
170 + 'is_new' => false,
171 + 'is_beta' => false,
102 172 );
103 173
104 174 $action_options = apply_filters( 'frm_' . $id_base . '_action_options', $action_options );
105 175 $group = $this->get_group( $action_options );
@@ -105,18 +175,20 @@
105 175 $group = $this->get_group( $action_options );
106 176 $action_options['group'] = $group['id'];
107 177
108 178 if ( ! isset( $action_options['color'] ) ) {
109 - $colors = array( 'green', 'orange', 'purple' );
110 - shuffle( $colors );
111 - $action_options['color'] = 'var(--' . reset( $colors ) . ')';
179 + // Deterministic fallback so all instances of the same action type render with the same color across requests.
180 + $colors = array( 'green', 'orange', 'purple' );
181 + $index = abs( crc32( $id_base ) ) % count( $colors );
182 + $action_options['color'] = 'var(--' . $colors[ $index ] . ')';
112 183 }
113 184
114 185 $upgrade_class = isset( $action_options['classes'] ) && $action_options['classes'] === 'frm_show_upgrade';
186 +
115 187 if ( $action_options['group'] === $id_base ) {
116 - $upgrade_class = strpos( $action_options['classes'], 'frm_show_upgrade' ) !== false;
188 + $upgrade_class = str_contains( $action_options['classes'], 'frm_show_upgrade' );
117 189 $action_options['classes'] = $group['icon'];
118 - } elseif ( ! isset( $action_options['classes'] ) || empty( $action_options['classes'] ) || $upgrade_class ) {
190 + } elseif ( empty( $action_options['classes'] ) || $upgrade_class ) {
119 191 $action_options['classes'] = $group['icon'];
120 192 }
121 193
122 194 if ( $upgrade_class ) {
@@ -128,8 +200,13 @@
128 200 }
129 201
130 202 /**
131 203 * @param string $id_base
204 + * @param string $name
205 + * @param array $action_options
206 + * @param array $control_options
207 + *
208 + * @return void
132 209 */
133 210 public function FrmFormAction( $id_base, $name, $action_options = array(), $control_options = array() ) {
134 211 self::__construct( $id_base, $name, $action_options, $control_options );
135 212 }
@@ -136,22 +213,28 @@
136 213
137 214 /**
138 215 * Help to switch old field id by new field id for duplicate form
139 216 *
140 - * @param string $action id of the field that needs to be switched
217 + * @param string $action id of the field that needs to be switched.
141 218 *
142 219 * @return string
143 220 */
144 221 public function maybe_switch_field_ids( $action ) {
145 222 $updated_action = apply_filters( 'frm_maybe_switch_field_ids', $action );
223 +
146 224 if ( $updated_action === $action ) {
147 - $updated_action = FrmFieldsHelper::switch_field_ids( $action );
225 + return FrmFieldsHelper::switch_field_ids( $action );
148 226 }
227 +
149 228 return $updated_action;
150 229 }
151 230
152 231 /**
153 232 * @since 4.0
233 + *
234 + * @param array $action_options
235 + *
236 + * @return array
154 237 */
155 238 protected function get_group( $action_options ) {
156 239 $groups = FrmFormActionsController::form_action_groups();
157 240 $group = 'misc';
@@ -161,9 +244,9 @@
161 244 } elseif ( isset( $groups[ $this->id_base ] ) ) {
162 245 $group = $this->id_base;
163 246 } else {
164 247 foreach ( $groups as $name => $check_group ) {
165 - if ( isset( $check_group['actions'] ) && in_array( $this->id_base, $check_group['actions'] ) ) {
248 + if ( isset( $check_group['actions'] ) && in_array( $this->id_base, $check_group['actions'], true ) ) {
166 249 $group = $name;
167 250 break;
168 251 }
169 252 }
@@ -177,18 +260,18 @@
177 260 * Constructs name attributes for use in form() fields
178 261 *
179 262 * This function should be used in form() methods to create name attributes for fields to be saved by update()
180 263 *
181 - * @param string $field_name Field name
264 + * @param string $field_name Field name.
265 + * @param string $post_field
182 266 *
183 267 * @return string Name attribute for $field_name
184 268 */
185 269 public function get_field_name( $field_name, $post_field = 'post_content' ) {
186 - $name = $this->option_name . '[' . $this->number . ']';
187 - $name .= ( empty( $post_field ) ? '' : '[' . $post_field . ']' );
188 - $name .= '[' . $field_name . ']';
270 + $name = $this->option_name . '[' . $this->number . ']';
271 + $name .= $post_field ? '[' . $post_field . ']' : '';
189 272
190 - return $name;
273 + return $name . ( '[' . $field_name . ']' );
191 274 }
192 275
193 276 /**
194 277 * Constructs id attributes for use in form() fields
@@ -194,9 +277,9 @@
194 277 * Constructs id attributes for use in form() fields
195 278 *
196 279 * This function should be used in form() methods to create id attributes for fields to be saved by update()
197 280 *
198 - * @param string $field_name Field name
281 + * @param string $field_name Field name.
199 282 *
200 283 * @return string ID attribute for $field_name
201 284 */
202 285 public function get_field_id( $field_name ) {
@@ -204,8 +287,9 @@
204 287 }
205 288
206 289 /**
207 290 * @param int|string $number
291 + *
208 292 * @return void
209 293 */
210 294 public function _set( $number ) {
211 295 $this->number = $number;
@@ -212,8 +296,10 @@
212 296 $this->id = $this->id_base . '-' . $number;
213 297 }
214 298
215 299 /**
300 + * @param false|int|string $form_id
301 + *
216 302 * @return object
217 303 */
218 304 public function prepare_new( $form_id = false ) {
219 305 if ( $form_id ) {
@@ -222,9 +308,9 @@
222 308
223 309 $post_content = array();
224 310 $default_values = $this->get_global_defaults();
225 311
226 - // fill default values
312 + // Fill default values
227 313 $post_content = wp_parse_args( $post_content, $default_values );
228 314
229 315 if ( ! isset( $post_content['event'] ) && ! $this->action_options['force_event'] ) {
230 316 $post_content['event'] = array( reset( $this->action_options['event'] ) );
@@ -239,13 +325,17 @@
239 325 'post_type' => FrmFormActionsController::$action_post_type,
240 326 'post_name' => $this->form_id . '_' . $this->id_base . '_' . $this->number,
241 327 'menu_order' => $this->form_id,
242 328 );
243 - unset( $post_content );
244 329
245 330 return (object) $form_action;
246 331 }
247 332
333 + /**
334 + * @param int|string $form_id
335 + *
336 + * @return int|WP_Error
337 + */
248 338 public function create( $form_id ) {
249 339 $this->form_id = $form_id;
250 340
251 341 $action = $this->prepare_new();
@@ -253,13 +343,17 @@
253 343 return $this->save_settings( $action );
254 344 }
255 345
256 346 /**
347 + * @param int|string $form_id
348 + * @param int|string $old_id
349 + *
257 350 * @return void
258 351 */
259 352 public function duplicate_form_actions( $form_id, $old_id ) {
353 + // phpcs:ignore Universal.Operators.StrictComparisons
260 354 if ( $form_id == $old_id ) {
261 - // don't duplicate the actions if this is a template getting updated
355 + // Don't duplicate the actions if this is a template getting updated
262 356 return;
263 357 }
264 358
265 359 $this->form_id = $old_id;
@@ -265,8 +359,9 @@
265 359 $this->form_id = $old_id;
266 360 $actions = $this->get_all( $old_id );
267 361
268 362 $this->form_id = $form_id;
363 +
269 364 foreach ( $actions as $action ) {
270 365 $this->duplicate_one( $action, $form_id );
271 366 unset( $action );
272 367 }
@@ -271,31 +366,34 @@
271 366 unset( $action );
272 367 }
273 368 }
274 369
275 - /* Check if imported action should be created or updated
370 + /**
371 + * Check if imported action should be created or updated.
276 372 *
277 373 * @since 2.0
278 374 *
279 375 * @param array $action
280 - * @return integer $post_id
376 + * @param array $forms
377 + *
378 + * @return int Post ID.
281 379 */
282 380 public function maybe_create_action( $action, $forms ) {
283 - if ( isset( $action['ID'] ) && is_numeric( $action['ID'] ) && isset( $forms[ $action['menu_order'] ] ) && $forms[ $action['menu_order'] ] == 'updated' ) {
381 + if ( isset( $action['ID'] ) && is_numeric( $action['ID'] ) && isset( $forms[ $action['menu_order'] ] ) && $forms[ $action['menu_order'] ] === 'updated' ) {
284 382 // Update action only
285 383 $action['post_content'] = FrmAppHelper::maybe_json_decode( $action['post_content'] );
286 - $post_id = $this->save_settings( $action );
287 - } else {
288 - // Create action
289 - $action['post_content'] = FrmAppHelper::maybe_json_decode( $action['post_content'] );
290 - $post_id = $this->duplicate_one( (object) $action, $action['menu_order'] );
384 + return $this->save_settings( $action );
291 385 }
292 -
293 - return $post_id;
386 + // Create action
387 + $action['post_content'] = FrmAppHelper::maybe_json_decode( $action['post_content'] );
388 + return $this->duplicate_one( (object) $action, $action['menu_order'] );
294 389 }
295 390
296 391 /**
297 - * @param object $action
392 + * @param object $action
393 + * @param int|string $form_id
394 + *
395 + * @return int|WP_Error
298 396 */
299 397 public function duplicate_one( $action, $form_id ) {
300 398 global $frm_duplicate_ids;
301 399
@@ -307,9 +405,9 @@
307 405 $action->post_content[ $key ] = $frm_duplicate_ids[ $val ];
308 406 } elseif ( ! is_array( $val ) ) {
309 407 $action->post_content[ $key ] = FrmFieldsHelper::switch_field_ids( $val );
310 408 } elseif ( isset( $switch[ $key ] ) && is_array( $switch[ $key ] ) ) {
311 - // loop through each value if empty
409 + // Loop through each value if empty
312 410 if ( empty( $switch[ $key ] ) ) {
313 411 $switch[ $key ] = array_keys( $val );
314 412 }
315 413
@@ -324,8 +422,15 @@
324 422
325 423 return $this->save_settings( $action );
326 424 }
327 425
426 + /**
427 + * @param array $action
428 + * @param array|string $subkey
429 + * @param mixed $val
430 + *
431 + * @return array
432 + */
328 433 private function duplicate_array_walk( $action, $subkey, $val ) {
329 434 global $frm_duplicate_ids;
330 435
331 436 if ( is_array( $subkey ) ) {
@@ -341,15 +446,15 @@
341 446 } else {
342 447 foreach ( (array) $val as $ck => $cv ) {
343 448 if ( is_array( $cv ) ) {
344 449 $action[ $ck ] = $this->duplicate_array_walk( $action[ $ck ], $subkey, $cv );
345 - } elseif ( $ck == $subkey && isset( $frm_duplicate_ids[ $cv ] ) ) {
450 + } elseif ( $ck == $subkey && isset( $frm_duplicate_ids[ $cv ] ) ) { // phpcs:ignore Universal.Operators.StrictComparisons
346 451 $action[ $ck ] = $frm_duplicate_ids[ $cv ];
347 - } elseif ( $ck == $subkey ) {
452 + } elseif ( $ck == $subkey ) { // phpcs:ignore Universal.Operators.StrictComparisons
348 453 $action[ $ck ] = $this->maybe_switch_field_ids( $action[ $ck ] );
349 454 }
350 455 }
351 - }
456 + }//end if
352 457
353 458 return $action;
354 459 }
355 460
@@ -356,8 +461,12 @@
356 461 /**
357 462 * Deal with changed settings.
358 463 *
359 464 * Do NOT over-ride this function
465 + *
466 + * @param int|string $form_id
467 + *
468 + * @return array|null
360 469 */
361 470 public function update_callback( $form_id ) {
362 471 $this->form_id = $form_id;
363 472
@@ -364,32 +473,32 @@
364 473 $all_instances = $this->get_settings();
365 474
366 475 // We need to update the data
367 476 if ( $this->updated ) {
368 - return;
477 + return null;
369 478 }
370 479
371 480 // phpcs:ignore WordPress.Security.NonceVerification.Missing
372 - if ( isset( $_POST[ $this->option_name ] ) && is_array( $_POST[ $this->option_name ] ) ) {
373 - // Sanitizing removes scripts and <email> type of values.
374 - // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
375 - $settings = wp_unslash( $_POST[ $this->option_name ] );
376 - } else {
377 - return;
481 + if ( ! isset( $_POST[ $this->option_name ] ) || ! is_array( $_POST[ $this->option_name ] ) ) {
482 + return null;
378 483 }
379 484
485 + // Sanitizing removes scripts and <email> type of values.
486 + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
487 + $settings = wp_unslash( $_POST[ $this->option_name ] );
488 +
380 489 $action_ids = array();
381 490
382 491 foreach ( $settings as $number => $new_instance ) {
383 492 $this->_set( $number );
384 493
385 - $old_instance = isset( $all_instances[ $number ] ) ? $all_instances[ $number ] : array();
494 + $old_instance = $all_instances[ $number ] ?? array();
386 495
387 496 if ( ! isset( $new_instance['post_status'] ) ) {
388 497 $new_instance['post_status'] = 'draft';
389 498 }
390 499
391 - // settings were never opened, so don't update
500 + // Settings were never opened, so don't update
392 501 if ( ! isset( $new_instance['post_title'] ) ) {
393 502 $this->maybe_update_status( $new_instance, $old_instance );
394 503 $action_ids[] = $new_instance['ID'];
395 504 $this->updated = true;
@@ -398,10 +507,10 @@
398 507
399 508 $new_instance['post_type'] = FrmFormActionsController::$action_post_type;
400 509 $new_instance['post_name'] = $this->form_id . '_' . $this->id_base . '_' . $this->number;
401 510 $new_instance['menu_order'] = $this->form_id;
402 - $new_instance['post_date'] = isset( $old_instance->post_date ) ? $old_instance->post_date : '';
403 - $instance = $this->update( $new_instance, $old_instance );
511 + $new_instance['post_date'] = $old_instance->post_date ?? '';
512 + $instance = $this->update( $new_instance, $old_instance );
404 513
405 514 /**
406 515 * Filter an action's settings before saving.
407 516 *
@@ -409,12 +518,12 @@
409 518 * to update settings.
410 519 *
411 520 * @since 2.0
412 521 *
413 - * @param array $instance The current widget instance's settings.
414 - * @param array $new_instance Array of new widget settings.
415 - * @param array $old_instance Array of old widget settings.
416 - * @param WP_Widget $this The current widget instance.
522 + * @param array $instance The current widget instance's settings.
523 + * @param array $new_instance Array of new widget settings.
524 + * @param array $old_instance Array of old widget settings.
525 + * @param FrmFormAction $form_action FrmFormAction instance.
417 526 */
418 527 $instance = apply_filters( 'frm_action_update_callback', $instance, $new_instance, $old_instance, $this );
419 528
420 529 $instance['post_content'] = apply_filters( 'frm_before_save_action', $instance['post_content'], $instance, $new_instance, $old_instance, $this );
@@ -426,9 +535,9 @@
426 535
427 536 $action_ids[] = $this->save_settings( $instance );
428 537
429 538 $this->updated = true;
430 - }
539 + }//end foreach
431 540
432 541 return $action_ids;
433 542 }
434 543
@@ -437,9 +546,10 @@
437 546 *
438 547 * @since 3.04
439 548 *
440 549 * @param array $new_instance
441 - * @param stdClass|array $old_instance
550 + * @param array|stdClass $old_instance
551 + *
442 552 * @return void
443 553 */
444 554 protected function maybe_update_status( $new_instance, $old_instance ) {
445 555 if ( ! is_object( $old_instance ) || $new_instance['post_status'] === $old_instance->post_status ) {
@@ -454,16 +564,26 @@
454 564 )
455 565 );
456 566 }
457 567
568 + /**
569 + * @param array $settings
570 + *
571 + * @return int|WP_Error
572 + */
458 573 public function save_settings( $settings ) {
459 574 self::clear_cache();
460 -
461 575 return FrmDb::save_settings( $settings, 'frm_actions' );
462 576 }
463 577
578 + /**
579 + * @param int $id
580 + *
581 + * @return object|null
582 + */
464 583 public function get_single_action( $id ) {
465 584 $action = get_post( $id );
585 +
466 586 if ( $action ) {
467 587 $action = $this->prepare_action( $action );
468 588 $this->_set( $id );
469 589 }
@@ -470,27 +590,43 @@
470 590
471 591 return $action;
472 592 }
473 593
594 + /**
595 + * @param int|string $form_id
596 + *
597 + * @return array
598 + */
474 599 public function get_one( $form_id ) {
475 600 return $this->get_all( $form_id, 1 );
476 601 }
477 602
603 + /**
604 + * @param int|string $form_id
605 + * @param string $type
606 + * @param array $atts
607 + *
608 + * @return array
609 + */
478 610 public static function get_action_for_form( $form_id, $type = 'all', $atts = array() ) {
479 611 $action_controls = FrmFormActionsController::get_form_actions( $type );
480 - if ( empty( $action_controls ) ) {
481 - // don't continue if there are no available actions
612 +
613 + if ( ! $action_controls ) {
614 + // Don't continue if there are no available actions
482 615 return array();
483 616 }
484 617
485 - if ( 'all' != $type ) {
618 + if ( 'all' !== $type ) {
619 + if ( is_array( $action_controls ) ) {
620 + return array();
621 + }
622 +
486 623 return $action_controls->get_all( $form_id, $atts );
487 624 }
488 625
489 626 self::prepare_get_action( $atts );
490 627
491 - $limit = apply_filters( 'frm_form_action_limit', $atts['limit'], compact( 'type', 'form_id' ) );
492 -
628 + $limit = self::get_action_limit( $form_id, $atts['limit'] );
493 629 $args = self::action_args( $form_id, $limit );
494 630 $args['post_status'] = $atts['post_status'];
495 631 $actions = FrmDb::check_cache( json_encode( $args ), 'frm_actions', $args, 'get_posts' );
496 632
@@ -498,10 +634,11 @@
498 634 return array();
499 635 }
500 636
501 637 $settings = array();
638 +
502 639 foreach ( $actions as $action ) {
503 - // some plugins/themes are formatting the post_excerpt
640 + // Some plugins/themes are formatting the post_excerpt
504 641 $action->post_excerpt = sanitize_title( $action->post_excerpt );
505 642
506 643 if ( ! isset( $action_controls[ $action->post_excerpt ] ) ) {
507 644 continue;
@@ -514,30 +651,43 @@
514 651 break;
515 652 }
516 653 }
517 654
518 - if ( 1 === $limit ) {
519 - $settings = reset( $settings );
520 - }
655 + return 1 === $limit ? reset( $settings ) : $settings;
656 + }
521 657
522 - return $settings;
658 + /**
659 + * Get the limit for the number of actions for a single form. By default, this is 99, but
660 + * it can be modified with a code snippet.
661 + *
662 + * @since 6.17 This logic from moved from FrmFormAction::get_action_for_form.
663 + *
664 + * @param int|string $form_id
665 + * @param int|string $limit The unfiltered limit value.
666 + *
667 + * @return int The filtered limit value.
668 + */
669 + public static function get_action_limit( $form_id, $limit = 99 ) {
670 + $type = 'all';
671 + return (int) apply_filters( 'frm_form_action_limit', (int) $limit, compact( 'type', 'form_id' ) );
523 672 }
524 673
525 674 /**
526 675 * @since 3.04
527 676 *
528 - * @param array $args
529 - * @param string $default_status
677 + * @param array|string $args
678 + * @param string $default_status
530 679 *
531 680 * @return void
532 681 */
533 682 protected static function prepare_get_action( &$args, $default_status = 'publish' ) {
534 683 if ( is_numeric( $args ) ) {
535 - // for reverse compatibility. $limit was changed to $args
684 + // For reverse compatibility. $limit was changed to $args
536 685 $args = array(
537 686 'limit' => $args,
538 687 );
539 688 }
689 +
540 690 $defaults = array(
541 691 'limit' => 99,
542 692 'post_status' => $default_status,
543 693 );
@@ -544,14 +694,21 @@
544 694 $args = wp_parse_args( $args, $defaults );
545 695 }
546 696
547 697 /**
548 - * @param int $action_id
698 + * @param int $action_id
699 + * @param string $type
700 + *
701 + * @return bool|object
549 702 */
550 703 public static function get_single_action_type( $action_id, $type ) {
551 704 if ( ! $type ) {
552 705 return false;
553 706 }
707 +
708 + /**
709 + * @var FrmFormAction
710 + */
554 711 $action_control = FrmFormActionsController::get_form_actions( $type );
555 712
556 713 return $action_control->get_single_action( $action_id );
557 714 }
@@ -556,18 +713,24 @@
556 713 return $action_control->get_single_action( $action_id );
557 714 }
558 715
559 716 /**
560 - * @param int $form_id
717 + * @param int $form_id
718 + * @param string $type
561 719 *
562 720 * @return bool
563 721 */
564 722 public static function form_has_action_type( $form_id, $type ) {
565 - $payment_actions = self::get_action_for_form( $form_id, $type );
566 -
567 - return ! empty( $payment_actions );
723 + $actions = self::get_action_for_form( $form_id, $type );
724 + return ! empty( $actions );
568 725 }
569 726
727 + /**
728 + * @param false|int|string $form_id
729 + * @param array $atts
730 + *
731 + * @return array
732 + */
570 733 public function get_all( $form_id = false, $atts = array() ) {
571 734 if ( is_array( $atts ) && ! isset( $atts['limit'] ) && $this->action_options['limit'] > 99 ) {
572 735 $atts['limit'] = $this->action_options['limit'];
573 736 }
@@ -585,10 +748,10 @@
585 748 global $frm_vars;
586 749 $frm_vars['action_type'] = $type;
587 750
588 751 add_filter( 'posts_where', 'FrmFormActionsController::limit_by_type' );
589 - $query = self::action_args( $form_id, $limit );
590 - $query['post_status'] = $atts['post_status'];
752 + $query = self::action_args( $form_id, $limit );
753 + $query['post_status'] = $atts['post_status'];
591 754 $query['suppress_filters'] = false;
592 755
593 756 $actions = FrmDb::check_cache( json_encode( $query ) . '_type_' . $type, 'frm_actions', $query, 'get_posts' );
594 757 unset( $query );
@@ -594,31 +757,30 @@
594 757 unset( $query );
595 758
596 759 remove_filter( 'posts_where', 'FrmFormActionsController::limit_by_type' );
597 760
598 - if ( empty( $actions ) ) {
761 + if ( ! $actions ) {
599 762 return array();
600 763 }
601 764
602 765 $settings = array();
766 +
603 767 foreach ( $actions as $action ) {
604 768 if ( count( $settings ) >= $limit ) {
605 769 continue;
606 770 }
607 771
608 - $action = $this->prepare_action( $action );
609 -
772 + $action = $this->prepare_action( $action );
610 773 $settings[ $action->ID ] = $action;
611 774 }
612 775
613 - if ( 1 === $limit ) {
614 - $settings = reset( $settings );
615 - }
616 -
617 - return $settings;
776 + return 1 === $limit ? reset( $settings ) : $settings;
618 777 }
619 778
620 779 /**
780 + * @param int|string $form_id
781 + * @param int $limit
782 + *
621 783 * @return array
622 784 */
623 785 public static function action_args( $form_id = 0, $limit = 99 ) {
624 786 $args = array(
@@ -628,9 +790,9 @@
628 790 'orderby' => 'title',
629 791 'order' => 'ASC',
630 792 );
631 793
632 - if ( $form_id && $form_id != 'all' ) {
794 + if ( $form_id && $form_id !== 'all' ) {
633 795 $args['menu_order'] = $form_id;
634 796 }
635 797
636 798 return $args;
@@ -636,9 +798,11 @@
636 798 return $args;
637 799 }
638 800
639 801 /**
640 - * @param WP_Post|array $action
802 + * @param WP_Post $action
803 + *
804 + * @return WP_Post
641 805 */
642 806 public function prepare_action( $action ) {
643 807 $action->post_content = (array) FrmAppHelper::maybe_json_decode( $action->post_content );
644 808 $action->post_excerpt = sanitize_title( $action->post_excerpt );
@@ -644,18 +808,20 @@
644 808 $action->post_excerpt = sanitize_title( $action->post_excerpt );
645 809
646 810 $default_values = $this->get_global_defaults();
647 811
648 - // fill default values
812 + // Fill default values
649 813 $action->post_content += $default_values;
650 814
651 815 foreach ( $default_values as $k => $vals ) {
652 - if ( is_array( $vals ) && ! empty( $vals ) ) {
653 - if ( 'event' === $k && ! $this->action_options['force_event'] && ! empty( $action->post_content[ $k ] ) ) {
654 - continue;
655 - }
656 - $action->post_content[ $k ] = wp_parse_args( $action->post_content[ $k ], $vals );
816 + if ( ! is_array( $vals ) || ! $vals ) {
817 + continue;
657 818 }
819 +
820 + if ( 'event' === $k && ! $this->action_options['force_event'] && ! empty( $action->post_content[ $k ] ) ) {
821 + continue;
822 + }
823 + $action->post_content[ $k ] = wp_parse_args( $action->post_content[ $k ], $vals );
658 824 }
659 825
660 826 if ( ! is_array( $action->post_content['event'] ) ) {
661 827 $action->post_content['event'] = explode( ',', $action->post_content['event'] );
@@ -664,8 +830,11 @@
664 830 return $action;
665 831 }
666 832
667 833 /**
834 + * @param false|int|string $form_id
835 + * @param string $type
836 + *
668 837 * @return void
669 838 */
670 839 public function destroy( $form_id = false, $type = 'default' ) {
671 840 global $wpdb;
@@ -672,12 +841,14 @@
672 841
673 842 $this->form_id = $form_id;
674 843
675 844 $query = array( 'post_type' => FrmFormActionsController::$action_post_type );
845 +
676 846 if ( $form_id ) {
677 847 $query['menu_order'] = $form_id;
678 848 }
679 - if ( 'all' != $type ) {
849 +
850 + if ( 'all' !== $type ) {
680 851 $query['post_excerpt'] = $this->id_base;
681 852 }
682 853
683 854 $post_ids = FrmDb::get_col( $wpdb->posts, $query, 'ID' );
@@ -698,8 +869,11 @@
698 869 public static function clear_cache() {
699 870 FrmDb::cache_delete_group( 'frm_actions' );
700 871 }
701 872
873 + /**
874 + * @return array
875 + */
702 876 public function get_settings() {
703 877 return self::get_action_for_form( $this->form_id, $this->id_base );
704 878 }
705 879
@@ -722,35 +896,43 @@
722 896
723 897 return $defaults;
724 898 }
725 899
900 + /**
901 + * @return array
902 + */
726 903 public function get_global_switch_fields() {
727 904 $switch = $this->get_switch_fields();
728 905 $switch['conditions'] = array( 'hide_field' );
729 906
730 - $switch = apply_filters( 'frm_global_switch_fields', $switch );
731 -
732 - return $switch;
907 + return apply_filters( 'frm_global_switch_fields', $switch );
733 908 }
734 909
735 910 /**
736 911 * Migrate settings from form->options into new action.
912 + *
913 + * @param object $form
914 + * @param string $update
915 + *
916 + * @return int|WP_Error
737 917 */
738 918 public function migrate_to_2( $form, $update = 'update' ) {
739 - $action = $this->prepare_new( $form->id );
919 + $action = $this->prepare_new( $form->id );
740 920 FrmAppHelper::unserialize_or_decode( $form->options );
741 921
742 - // fill with existing options
922 + // Fill with existing options
743 923 foreach ( $action->post_content as $name => $val ) {
744 - if ( isset( $form->options[ $name ] ) ) {
745 - $action->post_content[ $name ] = $form->options[ $name ];
746 - unset( $form->options[ $name ] );
924 + if ( ! isset( $form->options[ $name ] ) ) {
925 + continue;
747 926 }
927 +
928 + $action->post_content[ $name ] = $form->options[ $name ];
929 + unset( $form->options[ $name ] );
748 930 }
749 931
750 932 $action = $this->migrate_values( $action, $form );
751 933
752 - // check if action already exists
934 + // Check if action already exists
753 935 $post_id = get_posts(
754 936 array(
755 937 'name' => $action->post_name,
756 938 'post_type' => FrmFormActionsController::$action_post_type,
@@ -758,130 +940,41 @@
758 940 'numberposts' => 1,
759 941 )
760 942 );
761 943
762 - if ( empty( $post_id ) ) {
763 - // create action now
944 + if ( ! $post_id ) {
945 + // Create action now
764 946 $post_id = $this->save_settings( $action );
765 947 }
766 948
767 - if ( $post_id && 'update' == $update ) {
768 - global $wpdb;
769 - $form->options = maybe_serialize( $form->options );
770 -
771 - // update form options
772 - $wpdb->update( $wpdb->prefix . 'frm_forms', array( 'options' => $form->options ), array( 'id' => $form->id ) );
773 - FrmForm::clear_form_cache();
949 + if ( ! $post_id || 'update' !== $update ) {
950 + return $post_id;
774 951 }
775 952
776 - return $post_id;
777 - }
953 + global $wpdb;
954 + $form->options = maybe_serialize( $form->options );
778 955
779 - public static function action_conditions_met( $action, $entry ) {
780 - if ( is_callable( 'FrmProFormActionsController::action_conditions_met' ) ) {
781 - return FrmProFormActionsController::action_conditions_met( $action, $entry );
782 - }
956 + // Update form options
957 + $wpdb->update( $wpdb->prefix . 'frm_forms', array( 'options' => $form->options ), array( 'id' => $form->id ) );
958 + FrmForm::clear_form_cache();
783 959
784 - // This is here for reverse compatibility.
785 - $notification = $action->post_content;
786 - $stop = false;
787 - $met = array();
788 -
789 - if ( ! isset( $notification['conditions'] ) || empty( $notification['conditions'] ) ) {
790 - return $stop;
791 - }
792 -
793 - foreach ( $notification['conditions'] as $k => $condition ) {
794 - if ( ! is_numeric( $k ) ) {
795 - continue;
796 - }
797 -
798 - if ( $stop && 'any' == $notification['conditions']['any_all'] && 'stop' == $notification['conditions']['send_stop'] ) {
799 - continue;
800 - }
801 -
802 - self::prepare_logic_value( $condition['hide_opt'], $action, $entry );
803 -
804 - $observed_value = self::get_value_from_entry( $entry, $condition['hide_field'] );
805 -
806 - $stop = FrmFieldsHelper::value_meets_condition( $observed_value, $condition['hide_field_cond'], $condition['hide_opt'] );
807 -
808 - if ( $notification['conditions']['send_stop'] == 'send' ) {
809 - $stop = $stop ? false : true;
810 - }
811 -
812 - $met[ $stop ] = $stop;
813 - }
814 -
815 - if ( $notification['conditions']['any_all'] == 'all' && ! empty( $met ) && isset( $met[0] ) && isset( $met[1] ) ) {
816 - $stop = ( $notification['conditions']['send_stop'] == 'send' );
817 - } elseif ( $notification['conditions']['any_all'] == 'any' && $notification['conditions']['send_stop'] == 'send' && isset( $met[0] ) ) {
818 - $stop = false;
819 - }
820 -
821 - return $stop;
960 + return $post_id;
822 961 }
823 962
824 963 /**
825 - * Prepare the logic value for comparison against the entered value
964 + * @param WP_Post $action
965 + * @param stdClass $entry
826 966 *
827 - * @since 2.01.02
828 - *
829 - * @deprecated 4.06.02
830 - *
831 - * @param array|string $logic_value
832 - *
833 - * @return void
967 + * @return bool
834 968 */
835 - private static function prepare_logic_value( &$logic_value, $action, $entry ) {
836 - if ( is_array( $logic_value ) ) {
837 - $logic_value = reset( $logic_value );
969 + public static function action_conditions_met( $action, $entry ) {
970 + if ( is_callable( 'FrmProFormActionsController::action_conditions_met' ) ) {
971 + return FrmProFormActionsController::action_conditions_met( $action, $entry );
838 972 }
839 -
840 - if ( $logic_value == 'current_user' ) {
841 - $logic_value = get_current_user_id();
842 - }
843 -
844 - $logic_value = apply_filters( 'frm_content', $logic_value, $action->menu_order, $entry );
845 -
846 - /**
847 - * @since 4.04.05
848 - */
849 - $logic_value = apply_filters( 'frm_action_logic_value', $logic_value );
973 + return false;
850 974 }
851 975
852 976 /**
853 - * Get the value from a specific field and entry
854 - *
855 - * @since 2.01.02
856 - * @deprecated 4.06.02
857 - *
858 - * @param object $entry
859 - * @param int $field_id
860 - *
861 - * @return array|bool|mixed|string
862 - */
863 - private static function get_value_from_entry( $entry, $field_id ) {
864 - $observed_value = '';
865 -
866 - if ( isset( $entry->metas[ $field_id ] ) ) {
867 - $observed_value = $entry->metas[ $field_id ];
868 - } elseif ( $entry->post_id && FrmAppHelper::pro_is_installed() ) {
869 - $field = FrmField::getOne( $field_id );
870 - $observed_value = FrmProEntryMetaHelper::get_post_or_meta_value(
871 - $entry,
872 - $field,
873 - array(
874 - 'links' => false,
875 - 'truncate' => false,
876 - )
877 - );
878 - }
879 -
880 - return $observed_value;
881 - }
882 -
883 - /**
884 977 * @param string $class
885 978 *
886 979 * @return array
887 980 */
@@ -886,14 +979,18 @@
886 979 * @return array
887 980 */
888 981 public static function default_action_opts( $class = '' ) {
889 982 return array(
890 - 'classes' => 'frm_icon_font ' . $class,
891 - 'active' => false,
892 - 'limit' => 0,
983 + 'classes' => 'frmfont ' . $class,
984 + 'active' => false,
985 + 'limit' => 0,
986 + 'description' => '',
893 987 );
894 988 }
895 989
990 + /**
991 + * @return array
992 + */
896 993 public static function trigger_labels() {
897 994 $triggers = array(
898 995 'draft' => __( 'Draft is saved', 'formidable' ),
899 996 'create' => __( 'Entry is created', 'formidable' ),
@@ -905,18 +1002,40 @@
905 1002 return apply_filters( 'frm_action_triggers', $triggers );
906 1003 }
907 1004
908 1005 /**
1006 + * @param string $action_key The unique key for this action instance.
1007 + *
909 1008 * @return void
910 1009 */
911 - public function render_conditional_logic_call_to_action() {
1010 + public function render_conditional_logic_call_to_action( $action_key = '' ) {
1011 + $params = array(
1012 + 'class' => 'frm-h-stack-xs frm-bt-200 frm-py-md frm_show_upgrade',
1013 + 'data-upgrade' => $this->get_upgrade_text(),
1014 + 'data-medium' => 'conditional-' . $this->id_base,
1015 + 'data-content' => 'conditional-logic',
1016 + );
1017 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
912 1018 ?>
913 - <h3>
914 - <a href="javascript:void(0)" class="frm_show_upgrade frm_noallow" data-upgrade="<?php echo esc_attr( $this->get_upgrade_text() ); ?>" data-medium="conditional-<?php echo esc_attr( $this->id_base ); ?>">
915 - <?php esc_html_e( 'Use Conditional Logic', 'formidable' ); ?>
916 - </a>
917 - </h3>
1019 + <div <?php FrmAppHelper::array_to_html_params( $params, true ); ?>>
1020 + <?php
1021 + FrmHtmlHelper::toggle(
1022 + 'frm_logic_cta_' . $action_key,
1023 + 'frm_logic_cta_' . $action_key,
1024 + array(
1025 + 'div_class' => 'with_frm_style frm_toggle',
1026 + 'checked' => false,
1027 + 'echo' => true,
1028 + 'disabled' => true,
1029 + )
1030 + );
1031 + ?>
1032 + <label for="frm_logic_cta_<?php echo esc_attr( $action_key ); ?>" class="frm_noallow">
1033 + <?php esc_html_e( 'Use Conditional Logic', 'formidable' ); ?>
1034 + </label>
1035 + </div>
918 1036 <?php
1037 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
919 1038 }
920 1039
921 1040 /**
922 1041 * @return string
@@ -922,6 +1041,26 @@
922 1041 * @return string
923 1042 */
924 1043 protected function get_upgrade_text() {
925 1044 return __( 'Conditional form actions', 'formidable' );
1045 + }
1046 +
1047 + /**
1048 + * Gets form fields for form action settings.
1049 + *
1050 + * @since 6.10
1051 + *
1052 + * @param int $form_id Form ID.
1053 + *
1054 + * @return object[]
1055 + */
1056 + protected function get_form_fields( $form_id ) {
1057 + // Get form fields, include embedded and repeater child fields.
1058 + $form_fields = FrmField::get_all_for_form( $form_id, '', 'include' );
1059 + return array_filter(
1060 + $form_fields,
1061 + function ( $form_field ) {
1062 + return ! FrmField::is_no_save_field( $form_field->type );
1063 + }
1064 + );
926 1065 }
927 1066 }