PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / 6.32
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More v6.32
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/controllers/FrmFormActionsController.php +720 -105 6.36.32 View file →
@@ -3,9 +3,17 @@
3 3 die( 'You are not allowed to call this page directly.' );
4 4 }
5 5
6 6 class FrmFormActionsController {
7 +
8 + /**
9 + * @var string
10 + */
7 11 public static $action_post_type = 'frm_form_actions';
12 +
13 + /**
14 + * @var Frm_Form_Action_Factory|null
15 + */
8 16 public static $registered_actions;
9 17
10 18 /**
11 19 * Variables saved in the post:
@@ -29,8 +37,9 @@
29 37 'has_archive' => false,
30 38 )
31 39 );
32 40
41 + self::maybe_setup_unlicensed_action_gate();
33 42 self::actions_init();
34 43 }
35 44
36 45 public static function actions_init() {
@@ -47,46 +56,118 @@
47 56 'on_submit' => 'FrmOnSubmitAction',
48 57 'email' => 'FrmEmailAction',
49 58 'wppost' => 'FrmDefPostAction',
50 59 'register' => 'FrmDefRegAction',
51 - 'paypal' => 'FrmDefPayPalAction',
52 - 'payment' => 'FrmDefHrsAction',
60 + 'stripe' => 'FrmStripeLiteAction',
61 + 'square' => 'FrmSquareAction',
62 + 'paypal' => 'FrmPayPalLiteAction',
63 + 'paypal-legacy' => 'FrmDefPayPalLegacyAction',
64 + 'payment' => 'FrmTransLiteAction',
53 65 'quiz' => 'FrmDefQuizAction',
54 66 'quiz_outcome' => 'FrmDefQuizOutcomeAction',
67 + 'api' => 'FrmDefApiAction',
55 68 'mailchimp' => 'FrmDefMlcmpAction',
56 - 'api' => 'FrmDefApiAction',
57 - 'salesforce' => 'FrmDefSalesforceAction',
58 69 'activecampaign' => 'FrmDefActiveCampaignAction',
59 70 'constantcontact' => 'FrmDefConstContactAction',
60 71 'getresponse' => 'FrmDefGetResponseAction',
72 + 'mailpoet' => 'FrmDefMailpoetAction',
73 + 'convertkit' => 'FrmDefConvertKitAction',
74 + 'aweber' => 'FrmDefAweberAction',
75 + 'twilio' => 'FrmDefTwilioAction',
76 + 'salesforce' => 'FrmDefSalesforceAction',
61 77 'hubspot' => 'FrmDefHubspotAction',
78 + 'highrise' => 'FrmDefHighriseAction',
62 79 'zapier' => 'FrmDefZapierAction',
63 - 'twilio' => 'FrmDefTwilioAction',
64 - 'highrise' => 'FrmDefHighriseAction',
65 - 'mailpoet' => 'FrmDefMailpoetAction',
66 - 'aweber' => 'FrmDefAweberAction',
67 80 'googlespreadsheet' => 'FrmDefGoogleSpreadsheetAction',
81 + 'n8n' => 'FrmDefN8NAction',
68 82 );
69 83
70 84 $action_classes = apply_filters( 'frm_registered_form_actions', $action_classes );
85 + $action_classes = self::maybe_unset_highrise( $action_classes );
71 86
72 87 include_once FrmAppHelper::plugin_path() . '/classes/views/frm-form-actions/email_action.php';
73 88 include_once FrmAppHelper::plugin_path() . '/classes/views/frm-form-actions/default_actions.php';
74 89
90 + // This needs to be called after we include default_actions.php or FrmDefPayPalLegacyAction will never exist.
91 + if ( 'FrmPayPalLiteAction' === $action_classes['paypal'] || ! class_exists( 'FrmPaymentAction' ) || ! class_exists( 'FrmDefPayPalLegacyAction' ) ) {
92 + unset( $action_classes['paypal-legacy'] );
93 + }
94 +
75 95 foreach ( $action_classes as $action_class ) {
76 96 self::$registered_actions->register( $action_class );
77 97 }
98 +
99 + self::apply_default_action_descriptions();
78 100 }
79 101
80 102 /**
103 + * Sets default descriptions on registered actions from a central list.
104 + *
105 + * Keeps the description when an add-on replaces a base action class without its own.
106 + *
107 + * @since 6.31
108 + *
109 + * @return void
110 + */
111 + private static function apply_default_action_descriptions() {
112 + $descriptions = array(
113 + 'on_submit' => __( 'Success messages', 'formidable' ),
114 + 'email' => __( 'Autoresponder alerts', 'formidable' ),
115 + 'wppost' => __( 'Content publishing', 'formidable' ),
116 + 'register' => __( 'Account creation', 'formidable' ),
117 + 'payment' => __( 'Transaction alerts', 'formidable' ),
118 + 'stripe' => __( 'Payment gateway', 'formidable' ),
119 + 'square' => __( 'Payment gateway', 'formidable' ),
120 + 'paypal' => __( 'Payment gateway', 'formidable' ),
121 + 'quiz' => __( 'Automated grading', 'formidable' ),
122 + 'quiz_outcome' => __( 'Result logic', 'formidable' ),
123 + 'aweber' => __( 'List triggers', 'formidable' ),
124 + 'mailchimp' => __( 'Subscription confirmation', 'formidable' ),
125 + 'zapier' => __( 'App automation', 'formidable' ),
126 + 'n8n' => __( 'Workflow automation', 'formidable' ),
127 + 'twilio' => __( 'Text notifications', 'formidable' ),
128 + 'activecampaign' => __( 'Contact automation', 'formidable' ),
129 + 'salesforce' => __( 'Lead automation', 'formidable' ),
130 + 'constantcontact' => __( 'Content distribution', 'formidable' ),
131 + 'getresponse' => __( 'Success notifications', 'formidable' ),
132 + 'hubspot' => __( 'CRM alerts', 'formidable' ),
133 + 'mailpoet' => __( 'Plugin automation', 'formidable' ),
134 + 'api' => __( 'System integration', 'formidable' ),
135 + 'googlespreadsheet' => __( 'Spreadsheet sync', 'formidable' ),
136 + 'convertkit' => __( 'Broadcast publishing', 'formidable' ),
137 + );
138 +
139 + foreach ( self::$registered_actions->actions as $action ) {
140 + if ( $action->action_options['description'] === '' && isset( $descriptions[ $action->id_base ] ) ) {
141 + $action->action_options['description'] = $descriptions[ $action->id_base ];
142 + }
143 + }
144 + }
145 +
146 + /**
147 + * Remove the Highrise action if it is not registered.
148 + *
149 + * @since 6.23
150 + *
151 + * @param array $action_classes
152 + *
153 + * @return array
154 + */
155 + private static function maybe_unset_highrise( $action_classes ) {
156 + if ( 'FrmDefHighriseAction' === ( $action_classes['highrise'] ?? '' ) ) {
157 + unset( $action_classes['highrise'] );
158 + }
159 + return $action_classes;
160 + }
161 +
162 + /**
81 163 * @since 4.0
82 164 *
83 165 * @param array $values
84 166 */
85 167 public static function email_settings( $values ) {
86 - $form = FrmForm::getOne( $values['id'] );
87 - $groups = self::form_action_groups();
88 -
168 + $form = FrmForm::getOne( $values['id'] );
169 + $groups = self::form_action_groups();
89 170 $action_controls = self::get_form_actions();
90 171 self::maybe_add_action_to_group( $action_controls, $groups );
91 172
92 173 $allowed = self::active_actions( $action_controls );
@@ -97,23 +178,41 @@
97 178 /**
98 179 * Add unknown actions to a group.
99 180 *
100 181 * @since 4.0
182 + *
183 + * @param array $action_controls
184 + * @param array $groups
185 + *
186 + * @return void
101 187 */
102 188 private static function maybe_add_action_to_group( $action_controls, &$groups ) {
103 189 $grouped = array();
190 +
104 191 foreach ( $groups as $group ) {
105 192 if ( isset( $group['actions'] ) ) {
106 193 $grouped = array_merge( $grouped, $group['actions'] );
107 194 }
195 +
196 + // Also collect actions from sections
197 + if ( ! isset( $group['sections'] ) ) {
198 + continue;
199 + }
200 +
201 + foreach ( $group['sections'] as $section ) {
202 + if ( isset( $section['actions'] ) ) {
203 + $grouped = array_merge( $grouped, $section['actions'] );
204 + }
205 + }
108 206 }
109 207
110 208 foreach ( $action_controls as $action ) {
111 - if ( isset( $groups[ $action->id_base ] ) || in_array( $action->id_base, $grouped ) ) {
209 + if ( isset( $groups[ $action->id_base ] ) || in_array( $action->id_base, $grouped, true ) ) {
112 210 continue;
113 211 }
114 212
115 213 $this_group = $action->action_options['group'];
214 +
116 215 if ( ! isset( $groups[ $this_group ] ) ) {
117 216 $this_group = 'misc';
118 217 }
119 218
@@ -131,32 +230,48 @@
131 230 *
132 231 * @return array
133 232 */
134 233 public static function form_action_groups() {
234 + // Get all action controls to check which are active
235 + $action_controls = self::get_form_actions();
236 +
237 + // Determine which actions are currently available
238 + $available_actions = self::get_available_my_actions( $action_controls );
239 +
240 + // Featured actions are add-ons that are NOT currently available
241 + $all_addon_actions = array(
242 + 'api',
243 + 'register',
244 + 'n8n',
245 + 'quiz',
246 + 'quiz_outcome',
247 + 'googlespreadsheet',
248 + );
249 + $featured_actions = array_diff( $all_addon_actions, $available_actions );
250 +
135 251 $groups = array(
136 - 'misc' => array(
137 - 'name' => '',
138 - 'icon' => 'frm_icon_font frm_shuffle_icon',
139 - 'actions' => array(
140 - 'email',
141 - 'wppost',
142 - 'register',
143 - 'quiz',
144 - 'quiz_outcome',
145 - 'twilio',
252 + 'my_actions' => array(
253 + 'name' => __( 'My Actions', 'formidable' ),
254 + 'icon' => 'frmfont frm_shuffle_icon',
255 + 'sections' => array(
256 + 'active' => array(
257 + 'name' => '',
258 + 'actions' => $available_actions,
259 + ),
260 + 'featured' => array(
261 + 'name' => __( 'Featured', 'formidable' ),
262 + 'actions' => array_values( $featured_actions ),
263 + ),
146 264 ),
147 265 ),
148 - 'payment' => array(
149 - 'name' => __( 'eCommerce', 'formidable' ),
150 - 'icon' => 'frm_icon_font frm_credit_card_alt_icon',
151 - 'actions' => array(
152 - 'paypal',
153 - 'payment',
154 - ),
266 + 'payment' => array(
267 + 'name' => __( 'E-Commerce', 'formidable' ),
268 + 'icon' => 'frmfont frm_credit_card_alt_icon',
269 + 'actions' => self::get_payment_actions( $action_controls ),
155 270 ),
156 - 'marketing' => array(
157 - 'name' => __( 'Email Marketing', 'formidable' ),
158 - 'icon' => 'frm_icon_font frm_mail_bulk_icon',
271 + 'marketing' => array(
272 + 'name' => __( 'Marketing', 'formidable' ),
273 + 'icon' => 'frmfont frm_mail_bulk_icon',
159 274 'actions' => array(
160 275 'mailchimp',
161 276 'activecampaign',
162 277 'constantcontact',
@@ -162,19 +277,22 @@
162 277 'constantcontact',
163 278 'getresponse',
164 279 'aweber',
165 280 'mailpoet',
281 + 'convertkit',
282 + 'twilio',
166 283 ),
167 284 ),
168 - 'crm' => array(
285 + 'crm' => array(
169 286 'name' => __( 'CRM', 'formidable' ),
170 - 'icon' => 'frm_icon_font frm_address_card_icon',
171 - 'actions' => array(
172 - 'salesforce',
173 - 'hubspot',
174 - 'highrise',
175 - ),
287 + 'icon' => 'frmfont frm_address_card_icon',
288 + 'actions' => self::get_crm_actions(),
176 289 ),
290 + 'misc' => array(
291 + 'name' => __( 'Misc', 'formidable' ),
292 + 'icon' => 'frmfont frm_shuffle_icon',
293 + 'actions' => self::get_misc_actions( $action_controls ),
294 + ),
177 295 );
178 296
179 297 return apply_filters( 'frm_action_groups', $groups );
180 298 }
@@ -179,21 +297,142 @@
179 297 return apply_filters( 'frm_action_groups', $groups );
180 298 }
181 299
182 300 /**
301 + * Get the actions that are currently available (active) for My Actions section.
302 + *
303 + * @since 6.31
304 + *
305 + * @param array $action_controls The registered action controls.
306 + *
307 + * @return array
308 + */
309 + private static function get_available_my_actions( $action_controls ) {
310 + $available = array(
311 + 'on_submit',
312 + 'email',
313 + 'stripe',
314 + 'square',
315 + 'paypal',
316 + );
317 +
318 + // Include all actions that are marked as active, including custom actions.
319 + // This ensures custom actions appear in "My Actions" when enabled.
320 + foreach ( $action_controls as $action_id => $action_control ) {
321 + if ( ! in_array( $action_id, $available, true ) && ! empty( $action_control->action_options['active'] ) ) {
322 + $available[] = $action_id;
323 + }
324 + }
325 +
326 + return $available;
327 + }
328 +
329 + /**
330 + * Get the actions to include in the Misc section.
331 + *
332 + * @since 6.31
333 + *
334 + * @param array $action_controls The registered action controls.
335 + *
336 + * @return array
337 + */
338 + private static function get_misc_actions( $action_controls ) {
339 + $misc_actions = array(
340 + 'on_submit',
341 + 'email',
342 + 'wppost',
343 + 'register',
344 + 'api',
345 + 'n8n',
346 + 'quiz',
347 + 'quiz_outcome',
348 + 'googlespreadsheet',
349 + );
350 +
351 + // Include all active actions that aren't in specific groups (payment, marketing, crm).
352 + // This ensures custom actions appear in "Misc" when enabled.
353 + $payment_actions = self::get_payment_actions( $action_controls );
354 + $marketing_actions = array( 'mailchimp', 'activecampaign', 'constantcontact', 'getresponse', 'aweber', 'mailpoet', 'convertkit', 'twilio' );
355 +
356 + $excluded_actions = array_merge( $payment_actions, $marketing_actions, self::get_crm_actions() );
357 +
358 + foreach ( $action_controls as $action_id => $action_control ) {
359 + if ( ! in_array( $action_id, $misc_actions, true ) && ! in_array( $action_id, $excluded_actions, true ) && ! empty( $action_control->action_options['active'] ) ) {
360 + $misc_actions[] = $action_id;
361 + }
362 + }
363 +
364 + return $misc_actions;
365 + }
366 +
367 + /**
368 + * Get the actions to include in the E-Commerce section.
369 + *
370 + * @since 6.33
371 + *
372 + * @param array $action_controls
373 + *
374 + * @return array
375 + */
376 + private static function get_payment_actions( $action_controls ) {
377 + $payment_actions = array(
378 + 'paypal',
379 + 'stripe',
380 + 'square',
381 + );
382 +
383 + if ( isset( $action_controls['paypal-legacy'] ) ) {
384 + $payment_actions[] = 'paypal-legacy';
385 + }
386 +
387 + if ( isset( $action_controls['payment'] ) ) {
388 + $payment_actions[] = 'payment';
389 + }
390 +
391 + return $payment_actions;
392 + }
393 +
394 + /**
395 + * Get the actions to include in the CRM section.
396 + *
397 + * @since 6.23
398 + *
399 + * @return array
400 + */
401 + private static function get_crm_actions() {
402 + $crm_actions = array(
403 + 'salesforce',
404 + 'hubspot',
405 + 'zapier',
406 + );
407 +
408 + // Only include Highrise when the add-on is active.
409 + // This is because Highrise is deprecated. We don't want to show it in Lite.
410 + if ( class_exists( 'FrmHrsSettings' ) ) {
411 + $crm_actions[] = 'highrise';
412 + }
413 +
414 + return $crm_actions;
415 + }
416 +
417 + /**
183 418 * Get the number of currently active form actions.
184 419 *
185 420 * @since 4.0
186 421 *
422 + * @param array $action_controls
423 + *
187 424 * @return array
188 425 */
189 426 private static function active_actions( $action_controls ) {
190 427 $allowed = array();
428 +
191 429 foreach ( $action_controls as $action_control ) {
192 - if ( isset( $action_control->action_options['active'] ) && $action_control->action_options['active'] ) {
430 + if ( ! empty( $action_control->action_options['active'] ) ) {
193 431 $allowed[] = $action_control->id_base;
194 432 }
195 433 }
434 +
196 435 return $allowed;
197 436 }
198 437
199 438 /**
@@ -199,15 +438,15 @@
199 438 /**
200 439 * For each add-on, add an li, class, and javascript function. If active, add an additional class.
201 440 *
202 441 * @since 4.0
442 + *
203 443 * @param object $action_control
204 444 * @param array $allowed
205 445 */
206 446 public static function show_action_icon_link( $action_control, $allowed ) {
207 - $data = array();
208 - $classes = ' frm_' . $action_control->id_base . '_action frm_single_action';
209 -
447 + $data = array();
448 + $classes = ' frm_' . $action_control->id_base . '_action frm_single_action';
210 449 $group_class = ' frm-group-' . $action_control->action_options['group'];
211 450
212 451 /* translators: %s: Name of form action */
213 452 $upgrade_label = sprintf( esc_html__( '%s form actions', 'formidable' ), $action_control->action_options['tooltip'] );
@@ -213,15 +452,20 @@
213 452 $upgrade_label = sprintf( esc_html__( '%s form actions', 'formidable' ), $action_control->action_options['tooltip'] );
214 453
215 454 $default_shown = array( 'wppost', 'register', 'payment', 'quiz', 'hubspot' );
216 455 $default_shown = array_values( array_diff( $default_shown, $allowed ) );
217 - $default_position = array_search( $action_control->id_base, $default_shown );
456 + $default_position = array_search( $action_control->id_base, $default_shown, true );
218 457 $allowed_count = count( $allowed );
219 458
220 - if ( isset( $action_control->action_options['active'] ) && $action_control->action_options['active'] ) {
459 + if ( ! empty( $action_control->action_options['active'] ) ) {
221 460 $classes .= ' frm_active_action';
222 461 } else {
223 462 $classes .= ' frm_inactive_action';
463 +
464 + if ( str_contains( $action_control->action_options['classes'], 'frm_show_expired_modal' ) ) {
465 + $classes .= ' frm_show_expired_modal';
466 + }
467 +
224 468 if ( $default_position !== false && ( $allowed_count + $default_position ) < 6 ) {
225 469 $group_class .= ' frm-default-show';
226 470 }
227 471
@@ -228,8 +472,9 @@
228 472 $data['data-upgrade'] = $upgrade_label;
229 473 $data['data-medium'] = 'settings-' . $action_control->id_base;
230 474
231 475 $upgrading = FrmAddonsController::install_link( $action_control->action_options['plugin'] );
476 +
232 477 if ( isset( $upgrading['url'] ) ) {
233 478 $data['data-oneclick'] = json_encode( $upgrading );
234 479 }
235 480
@@ -237,37 +482,67 @@
237 482 $data['data-message'] = $action_control->action_options['message'];
238 483 }
239 484
240 485 $requires = FrmFormsHelper::get_plan_required( $upgrading );
486 +
241 487 if ( $requires && 'free' !== $requires ) {
242 488 $data['data-requires'] = $requires;
243 489 }
244 - }
245 490
246 - // HTML to include on the icon.
247 - $icon_atts = array();
248 - if ( $action_control->action_options['color'] !== 'var(--primary-700)' ) {
249 - $icon_atts = array(
491 + $learn_more_slug = ! empty( $action_control->action_options['learn-more'] )
492 + ? $action_control->action_options['learn-more']
493 + : self::get_learn_more_slug( $action_control->id_base );
494 +
495 + if ( $learn_more_slug ) {
496 + $data['data-learn-more'] = FrmAppHelper::get_doc_url(
497 + $learn_more_slug,
498 + 'settings-' . $action_control->id_base,
499 + ! str_contains( $learn_more_slug, '/' )
500 + );
501 + }
502 + }//end if
503 +
504 + include FrmAppHelper::plugin_path() . '/classes/views/frm-form-actions/_action_icon.php';
505 + }
506 +
507 + /**
508 + * Get the HTML attributes for the action icon.
509 + *
510 + * @since 6.31
511 + *
512 + * @param object $action_control
513 + *
514 + * @return array
515 + */
516 + public static function get_action_icon_atts( $action_control ) {
517 + if ( 'var(--primary-700)' !== $action_control->action_options['color'] ) {
518 + return array(
250 519 'style' => '--primary-700:' . $action_control->action_options['color'],
251 520 );
252 521 }
253 522
254 - include FrmAppHelper::plugin_path() . '/classes/views/frm-form-actions/_action_icon.php';
523 + return array();
255 524 }
256 525
526 + /**
527 + * @param string $action
528 + *
529 + * @return array|FrmFormAction A single form action is returned when a specific $action value is requested.
530 + */
257 531 public static function get_form_actions( $action = 'all' ) {
258 532 $temp_actions = self::$registered_actions;
259 - if ( empty( $temp_actions ) ) {
533 +
534 + if ( $temp_actions ) {
535 + $temp_actions = $temp_actions->actions;
536 + } else {
260 537 self::actions_init();
261 538 $temp_actions = self::$registered_actions->actions;
262 - } else {
263 - $temp_actions = $temp_actions->actions;
264 539 }
265 540
266 541 $actions = array();
267 542
268 543 foreach ( $temp_actions as $a ) {
269 - if ( 'all' != $action && $a->id_base == $action ) {
544 + if ( 'all' !== $action && $a->id_base === $action ) {
270 545 return $a;
271 546 }
272 547
273 548 $actions[ $a->id_base ] = $a;
@@ -277,11 +552,16 @@
277 552 }
278 553
279 554 /**
280 555 * @since 2.0
556 + *
557 + * @param object $form
558 + * @param array $values
559 + *
560 + * @return void
281 561 */
282 562 public static function list_actions( $form, $values ) {
283 - if ( empty( $form ) ) {
563 + if ( ! $form ) {
284 564 return;
285 565 }
286 566
287 567 /**
@@ -295,8 +575,11 @@
295 575 'post_status' => 'all',
296 576 );
297 577 $form_actions = FrmFormAction::get_action_for_form( $form->id, 'all', $filters );
298 578
579 + /**
580 + * @var array
581 + */
299 582 $action_controls = self::get_form_actions();
300 583
301 584 $action_map = array();
302 585
@@ -303,11 +586,17 @@
303 586 foreach ( $action_controls as $key => $control ) {
304 587 $action_map[ $control->id_base ] = $key;
305 588 }
306 589
590 + self::maybe_show_limit_warning( $form->id, $form_actions );
591 +
592 + echo '<p class="frm-mb-lg frm-no-actions-message' . ( $form_actions ? ' frm_hidden' : '' ) . '"> '
593 + . esc_html__( 'No actions have been added yet. Select an action above to get started.', 'formidable' )
594 + . '</p>';
595 +
307 596 foreach ( $form_actions as $action ) {
308 597 if ( ! isset( $action_map[ $action->post_excerpt ] ) ) {
309 - // don't try and show settings if action no longer exists
598 + // Don't try and show settings if action no longer exists
310 599 continue;
311 600 }
312 601
313 602 self::action_control( $action, $form, $action->ID, $action_controls[ $action_map[ $action->post_excerpt ] ], $values );
@@ -313,8 +602,54 @@
313 602 self::action_control( $action, $form, $action->ID, $action_controls[ $action_map[ $action->post_excerpt ] ], $values );
314 603 }
315 604 }
316 605
606 + /**
607 + * Show a warning before the form actions list if there are 99 actions, and the limit is set to 99.
608 + * If it is filtered, the warning is still shown when applicable, just using the new limit.
609 + *
610 + * @since 6.17
611 + *
612 + * @param int|string $form_id
613 + * @param array $form_actions
614 + *
615 + * @return void
616 + */
617 + private static function maybe_show_limit_warning( $form_id, $form_actions ) {
618 + $count = count( $form_actions );
619 +
620 + if ( $count < 99 ) {
621 + return;
622 + }
623 +
624 + $limit = FrmFormAction::get_action_limit( $form_id );
625 +
626 + if ( $limit < 99 || $count < $limit ) {
627 + return;
628 + }
629 +
630 + $documentation_url = 'https://formidableforms.com/knowledgebase/frm_form_action_limit/#kb-increase-limit-of-form-actions';
631 +
632 + echo '<div class="frm_warning_style">';
633 + FrmAppHelper::icon_by_class( 'frmfont frm_alert_icon' );
634 + echo '&nbsp;';
635 + printf(
636 + // translators: %s: URL to documentation
637 + esc_html__( 'You have reached your form action limit. To increase this limit, you will require additional code. Visit our documentation at %s.', 'formidable' ),
638 + '<a href="' . esc_url( $documentation_url ) . '" target="_blank">' . esc_html( $documentation_url ) . '</a>'
639 + );
640 + echo '</div>';
641 + }
642 +
643 + /**
644 + * @param WP_Post $form_action
645 + * @param object $form
646 + * @param int $action_key Action ID.
647 + * @param FrmFormAction $action_control
648 + * @param array $values
649 + *
650 + * @return void
651 + */
317 652 public static function action_control( $form_action, $form, $action_key, $action_control, $values ) {
318 653 $action_control->_set( $action_key );
319 654
320 655 $use_logging = self::should_show_log_message( $form_action->post_excerpt );
@@ -325,45 +660,76 @@
325 660 public static function add_form_action() {
326 661 FrmAppHelper::permission_check( 'frm_edit_forms' );
327 662 check_ajax_referer( 'frm_ajax', 'nonce' );
328 663
664 + $action_key = FrmAppHelper::get_param( 'list_id', '', 'post', 'absint' );
665 + $action_type = FrmAppHelper::get_param( 'type', '', 'post', 'sanitize_text_field' );
666 + $lite_actions = array_fill_keys( self::get_lite_actions(), true );
667 +
668 + if ( ! FrmAppHelper::pro_is_connected() && ! isset( $lite_actions[ $action_type ] ) ) {
669 + wp_die();
670 + }
671 +
329 672 global $frm_vars;
330 673
331 - $action_key = FrmAppHelper::get_param( 'list_id', '', 'post', 'absint' );
332 - $action_type = FrmAppHelper::get_param( 'type', '', 'post', 'sanitize_text_field' );
333 -
674 + /**
675 + * @var FrmFormAction
676 + */
334 677 $action_control = self::get_form_actions( $action_type );
335 678 $action_control->_set( $action_key );
336 679
337 - $form_id = FrmAppHelper::get_param( 'form_id', '', 'post', 'absint' );
680 + $form_id = FrmAppHelper::get_param( 'form_id', '', 'post', 'absint' );
681 + $form_action = $action_control->prepare_new( $form_id );
682 + $existing_titles = (array) FrmAppHelper::get_post_param( 'existing_titles', array(), 'sanitize_text_field' );
338 683
339 - $form_action = $action_control->prepare_new( $form_id );
684 + if ( $existing_titles ) {
685 + $form_action->post_title = self::get_unique_action_title( $form_action->post_title, $existing_titles );
686 + }
687 +
340 688 $use_logging = self::should_show_log_message( $action_type );
689 + $values = array();
690 + $form = self::fields_to_values( $form_id, $values );
341 691
342 - $values = array();
343 - $form = self::fields_to_values( $form_id, $values );
344 -
345 692 include FrmAppHelper::plugin_path() . '/classes/views/frm-form-actions/form_action.php';
346 693 wp_die();
347 694 }
348 695
696 + /**
697 + * Returns the first available title not in $existing_titles, appending " (2)", " (3)", etc. if needed.
698 + *
699 + * @since 6.31
700 + *
701 + * @param string $base_title Default action title from the action type.
702 + * @param string[] $existing_titles Titles currently visible in the form editor.
703 + *
704 + * @return string
705 + */
706 + private static function get_unique_action_title( $base_title, array $existing_titles ) {
707 + $taken = array_flip( $existing_titles );
708 + $title = $base_title;
709 +
710 + for ( $n = 2; isset( $taken[ $title ] ); $n++ ) {
711 + $title = $base_title . ' (' . $n . ')';
712 + }
713 +
714 + return $title;
715 + }
716 +
349 717 public static function fill_action() {
350 718 FrmAppHelper::permission_check( 'frm_edit_forms' );
351 719 check_ajax_referer( 'frm_ajax', 'nonce' );
352 720
353 - $action_key = FrmAppHelper::get_param( 'action_id', '', 'post', 'absint' );
354 - $action_type = FrmAppHelper::get_param( 'action_type', '', 'post', 'sanitize_text_field' );
721 + $action_key = FrmAppHelper::get_param( 'action_id', '', 'post', 'absint' );
722 + $action_type = FrmAppHelper::get_param( 'action_type', '', 'post', 'sanitize_text_field' );
723 + $action_control = self::get_form_actions( $action_type );
355 724
356 - $action_control = self::get_form_actions( $action_type );
357 - if ( empty( $action_control ) ) {
725 + if ( ! $action_control ) {
358 726 wp_die();
359 727 }
360 728
361 729 $form_action = $action_control->get_single_action( $action_key );
362 -
363 - $values = array();
364 - $form = self::fields_to_values( $form_action->menu_order, $values );
365 -
730 + $values = array();
731 + $form = self::fields_to_values( $form_action->menu_order, $values );
366 732 $use_logging = self::should_show_log_message( $action_type );
367 733
368 734 include FrmAppHelper::plugin_path() . '/classes/views/frm-form-actions/_action_inside.php';
369 735 wp_die();
@@ -370,15 +736,40 @@
370 736 }
371 737
372 738 /**
373 739 * @since 3.06.04
740 + *
741 + * @param string $action_type
742 + *
374 743 * @return bool
375 744 */
376 745 private static function should_show_log_message( $action_type ) {
377 - $logging = array( 'api', 'salesforce', 'constantcontact', 'activecampaign' );
378 - return in_array( $action_type, $logging ) && ! function_exists( 'frm_log_autoloader' );
746 + $logging = array(
747 + 'activecampaign',
748 + 'api',
749 + 'aweber',
750 + 'campaignmonitor',
751 + 'constantcontact',
752 + 'convertkit',
753 + 'getresponse',
754 + 'googlespreadsheet',
755 + 'hubspot',
756 + 'mailchimp',
757 + 'mailpoet',
758 + 'n8n',
759 + 'salesforce',
760 + 'twilio',
761 + 'zapier',
762 + );
763 + return in_array( $action_type, $logging, true ) && ! function_exists( 'frm_log_autoloader' );
379 764 }
380 765
766 + /**
767 + * @param int|string $form_id
768 + * @param array $values
769 + *
770 + * @return object
771 + */
381 772 private static function fields_to_values( $form_id, array &$values ) {
382 773 $form = FrmForm::getOne( $form_id );
383 774
384 775 $values = array(
@@ -386,12 +777,14 @@
386 777 'id' => $form->id,
387 778 );
388 779
389 780 $fields = FrmField::get_all_for_form( $form->id );
781 +
390 782 foreach ( $fields as $k => $f ) {
391 783 $f = (array) $f;
392 784 $opts = (array) $f['field_options'];
393 785 $f = array_merge( $opts, $f );
786 +
394 787 if ( ! isset( $f['post_field'] ) ) {
395 788 $f['post_field'] = '';
396 789 }
397 790 $values['fields'][] = $f;
@@ -402,16 +795,31 @@
402 795 }
403 796
404 797 /**
405 798 * @param int $form_id
799 + *
406 800 * @return void
407 801 */
408 802 public static function update_settings( $form_id ) {
409 803 FrmAppHelper::permission_check( 'frm_edit_forms' );
410 804 $process_form = FrmAppHelper::get_post_param( 'process_form', '', 'sanitize_text_field' );
805 +
411 806 if ( ! wp_verify_nonce( $process_form, 'process_form_nonce' ) ) {
412 807 $frm_settings = FrmAppHelper::get_settings();
413 - wp_die( esc_html( $frm_settings->admin_permission ) );
808 + $error_args = array(
809 + 'title' => __( 'Verification failed', 'formidable' ),
810 + 'body' => $frm_settings->admin_permission,
811 + 'cancel_url' => add_query_arg(
812 + array(
813 + 'page' => 'formidable',
814 + 'frm_action' => 'settings',
815 + 'id' => $form_id,
816 + ),
817 + admin_url( 'admin.php?' )
818 + ),
819 + );
820 + FrmAppController::show_error_modal( $error_args );
821 + return;
414 822 }
415 823
416 824 global $wpdb;
417 825
@@ -428,17 +836,19 @@
428 836 $new_actions = array();
429 837
430 838 foreach ( $registered_actions as $registered_action ) {
431 839 $action_ids = $registered_action->update_callback( $form_id );
432 - if ( ! empty( $action_ids ) ) {
840 +
841 + if ( $action_ids ) {
433 842 $new_actions[] = $action_ids;
434 843 }
435 844 }
436 845
437 846 // Only use array_merge if there are new actions.
438 - if ( ! empty( $new_actions ) ) {
847 + if ( $new_actions ) {
439 848 $new_actions = call_user_func_array( 'array_merge', $new_actions );
440 849 }
850 +
441 851 $old_actions = array_diff( $old_actions, $new_actions );
442 852
443 853 self::delete_missing_actions( $old_actions );
444 854
@@ -444,44 +854,77 @@
444 854
445 855 FrmOnSubmitHelper::save_on_submit_settings( $form_id );
446 856 }
447 857
858 + /**
859 + * @param array $old_actions
860 + *
861 + * @return void
862 + */
448 863 public static function delete_missing_actions( $old_actions ) {
449 - if ( ! empty( $old_actions ) ) {
450 - foreach ( $old_actions as $old_id ) {
451 - wp_delete_post( $old_id );
452 - }
453 - FrmDb::cache_delete_group( 'frm_actions' );
864 + if ( ! $old_actions ) {
865 + return;
454 866 }
867 +
868 + foreach ( $old_actions as $old_id ) {
869 + wp_delete_post( $old_id );
870 + }
871 +
872 + FrmDb::cache_delete_group( 'frm_actions' );
455 873 }
456 874
875 + /**
876 + * @param int|string $entry_id
877 + * @param int|string $form_id
878 + * @param array $args
879 + *
880 + * @return void
881 + */
457 882 public static function trigger_create_actions( $entry_id, $form_id, $args = array() ) {
458 883 $filter_args = $args;
459 884 $filter_args['entry_id'] = $entry_id;
460 885 $filter_args['form_id'] = $form_id;
461 886
462 - $event = apply_filters( 'frm_trigger_create_action', 'create', $args );
887 + /**
888 + * @since 2.0.23
889 + * @since 6.11.2 $filter_args is now passed instead of $args. It includes additional ID data.
890 + *
891 + * @param string $event 'create' by default. Pro may filter this value to 'draft' instead.
892 + * @param array $filter_args
893 + */
894 + $event = apply_filters( 'frm_trigger_create_action', 'create', $filter_args );
463 895
464 896 self::trigger_actions( $event, $form_id, $entry_id, 'all', $args );
465 897 }
466 898
467 899 /**
468 - * @param string $event
900 + * @param string $event
901 + * @param int|object|string $form
902 + * @param int|object|string $entry
903 + * @param string $type
904 + * @param array $args
905 + *
906 + * @return void
469 907 */
470 - public static function trigger_actions( $event, $form, $entry, $type = 'all', $args = array() ) {
908 + public static function trigger_actions( $event, $form, $entry, $type = 'all', $args = array() ) { // phpcs:ignore SlevomatCodingStandard.Complexity.Cognitive.ComplexityTooHigh
471 909 $action_status = array(
472 910 'post_status' => 'publish',
473 911 );
474 - $form_actions = FrmFormAction::get_action_for_form( ( is_object( $form ) ? $form->id : $form ), $type, $action_status );
912 + $form_actions = FrmFormAction::get_action_for_form( is_object( $form ) ? $form->id : $form, $type, $action_status );
475 913
476 - if ( empty( $form_actions ) ) {
914 + if ( ! $form_actions ) {
477 915 return;
478 916 }
479 917
480 918 FrmForm::maybe_get_form( $form );
481 919
920 + if ( ! is_object( $form ) ) {
921 + return;
922 + }
923 +
482 924 $link_settings = self::get_form_actions( $type );
483 - if ( 'all' != $type ) {
925 +
926 + if ( 'all' !== $type ) {
484 927 $link_settings = array( $type => $link_settings );
485 928 }
486 929
487 930 $stored_actions = array();
@@ -486,9 +929,9 @@
486 929
487 930 $stored_actions = array();
488 931 $action_priority = array();
489 932
490 - if ( in_array( $event, array( 'create', 'update' ) ) && defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
933 + if ( in_array( $event, array( 'create', 'update' ), true ) && defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
491 934 $this_event = 'import';
492 935 } else {
493 936 $this_event = $event;
494 937 }
@@ -493,11 +936,11 @@
493 936 $this_event = $event;
494 937 }
495 938
496 939 foreach ( $form_actions as $action ) {
497 -
498 940 $skip_this_action = ! in_array( $this_event, $action->post_content['event'], true ) || FrmOnSubmitAction::$slug === $action->post_excerpt;
499 941 $skip_this_action = apply_filters( 'frm_skip_form_action', $skip_this_action, compact( 'action', 'entry', 'form', 'event' ) );
942 +
500 943 if ( $skip_this_action ) {
501 944 continue;
502 945 }
503 946
@@ -504,17 +947,18 @@
504 947 if ( ! is_object( $entry ) ) {
505 948 $entry = FrmEntry::getOne( $entry, true );
506 949 }
507 950
508 - if ( empty( $entry ) || ( $entry->is_draft && $event != 'draft' ) ) {
951 + if ( ! $entry || ( FrmEntriesHelper::DRAFT_ENTRY_STATUS === (int) $entry->is_draft && 'draft' !== $event ) ) {
509 952 continue;
510 953 }
511 954
512 - $child_entry = ( ( is_object( $form ) && is_numeric( $form->parent_form_id ) && $form->parent_form_id ) || ( $entry && ( $entry->form_id != $form->id || $entry->parent_item_id ) ) || ( isset( $args['is_child'] ) && $args['is_child'] ) );
955 + $child_entry = ( is_numeric( $form->parent_form_id ) && $form->parent_form_id ) || ( $entry && ( (int) $entry->form_id !== (int) $form->id || $entry->parent_item_id ) ) || ! empty( $args['is_child'] ); // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
513 956
514 957 if ( $child_entry ) {
515 - // maybe trigger actions for sub forms
958 + // Maybe trigger actions for sub forms
516 959 $trigger_children = apply_filters( 'frm_use_embedded_form_actions', false, compact( 'form', 'entry' ) );
960 +
517 961 if ( ! $trigger_children ) {
518 962 continue;
519 963 }
520 964 }
@@ -520,8 +964,9 @@
520 964 }
521 965
522 966 // Check conditional logic.
523 967 $stop = FrmFormAction::action_conditions_met( $action, $entry );
968 +
524 969 if ( $stop ) {
525 970 continue;
526 971 }
527 972
@@ -529,11 +974,11 @@
529 974 $stored_actions[ $action->ID ] = $action;
530 975 $action_priority[ $action->ID ] = $link_settings[ $action->post_excerpt ]->action_options['priority'];
531 976
532 977 unset( $action );
533 - }
978 + }//end foreach
534 979
535 - if ( ! empty( $stored_actions ) ) {
980 + if ( $stored_actions ) {
536 981 asort( $action_priority );
537 982
538 983 // Make sure hooks are loaded.
539 984 new FrmNotification();
@@ -539,25 +984,49 @@
539 984 new FrmNotification();
540 985
541 986 foreach ( $action_priority as $action_id => $priority ) {
542 987 $action = $stored_actions[ $action_id ];
543 - do_action( 'frm_trigger_' . $action->post_excerpt . '_action', $action, $entry, $form, $event );
544 - do_action( 'frm_trigger_' . $action->post_excerpt . '_' . $event . '_action', $action, $entry, $form );
545 988
989 + /**
990 + * Allows custom form action trigger.
991 + *
992 + * @since 6.10
993 + *
994 + * @param bool $skip Skip default trigger.
995 + * @param object $action Action object.
996 + * @param object $entry Entry object.
997 + * @param object $form Form object.
998 + * @param string $event Event ('create' or 'update').
999 + */
1000 + if ( false === apply_filters( 'frm_custom_trigger_action', false, $action, $entry, $form, $event ) ) {
1001 + do_action( 'frm_trigger_' . $action->post_excerpt . '_action', $action, $entry, $form, $event );
1002 + do_action( 'frm_trigger_' . $action->post_excerpt . '_' . $event . '_action', $action, $entry, $form );
1003 + }
1004 +
546 1005 // If post is created, get updated $entry object.
547 - if ( $action->post_excerpt == 'wppost' && $event == 'create' ) {
1006 + if ( $action->post_excerpt === 'wppost' && $event === 'create' ) {
548 1007 $entry = FrmEntry::getOne( $entry->id, true );
549 1008 }
550 - }
551 - }
1009 + }//end foreach
1010 + }//end if
552 1011 }
553 1012
1013 + /**
1014 + * @param int|string $form_id
1015 + * @param array $values
1016 + * @param array $args
1017 + *
1018 + * @return void
1019 + */
554 1020 public static function duplicate_form_actions( $form_id, $values, $args = array() ) {
555 - if ( ! isset( $args['old_id'] ) || empty( $args['old_id'] ) ) {
1021 + if ( empty( $args['old_id'] ) ) {
556 1022 // Continue if we know which actions to copy.
557 1023 return;
558 1024 }
559 1025
1026 + /**
1027 + * @var array
1028 + */
560 1029 $action_controls = self::get_form_actions();
561 1030
562 1031 foreach ( $action_controls as $action_control ) {
563 1032 $action_control->duplicate_form_actions( $form_id, $args['old_id'] );
@@ -564,8 +1033,13 @@
564 1033 unset( $action_control );
565 1034 }
566 1035 }
567 1036
1037 + /**
1038 + * @param string $where
1039 + *
1040 + * @return string
1041 + */
568 1042 public static function limit_by_type( $where ) {
569 1043 global $frm_vars, $wpdb;
570 1044
571 1045 if ( ! isset( $frm_vars['action_type'] ) ) {
@@ -571,15 +1045,146 @@
571 1045 if ( ! isset( $frm_vars['action_type'] ) ) {
572 1046 return $where;
573 1047 }
574 1048
575 - $where .= $wpdb->prepare( ' AND post_excerpt = %s ', $frm_vars['action_type'] );
1049 + return $where . $wpdb->prepare( ' AND post_excerpt = %s ', $frm_vars['action_type'] );
1050 + }
576 1051
577 - return $where;
1052 + /**
1053 + * Prevent WPML from filtering form actions based on the active language.
1054 + *
1055 + * @since 6.20
1056 + *
1057 + * @param bool|null $null
1058 + * @param string $post_type
1059 + *
1060 + * @return bool|null
1061 + */
1062 + public static function prevent_wpml_translations( $null, $post_type ) {
1063 + return self::$action_post_type === $post_type ? false : $null;
578 1064 }
1065 +
1066 + /**
1067 + * If Pro is not connected, hook a filter that will force all non-Lite
1068 + * actions to inactive so the upgrade popup is shown instead.
1069 + *
1070 + * @since 6.31
1071 + *
1072 + * @return void
1073 + */
1074 + private static function maybe_setup_unlicensed_action_gate() {
1075 + if ( FrmAppHelper::pro_is_connected() ) {
1076 + return;
1077 + }
1078 +
1079 + add_filter( 'frm_registered_form_actions', array( self::class, 'disable_unlicensed_actions' ), 100 );
1080 + }
1081 +
1082 + /**
1083 + * For every registered action that is not a Lite action, add a per-action
1084 + * options filter that forces it to inactive with the upgrade class.
1085 + *
1086 + * Runs inside apply_filters('frm_registered_form_actions') at priority 100,
1087 + * so the per-key option filters are in place before the class constructors
1088 + * run in the foreach loop that follows.
1089 + *
1090 + * @since 6.31
1091 + *
1092 + * @param array $actions Map of action_key => class_name.
1093 + *
1094 + * @return array
1095 + */
1096 + public static function disable_unlicensed_actions( $actions ) {
1097 + $lite_actions = array_fill_keys( self::get_lite_actions(), true );
1098 +
1099 + foreach ( array_keys( $actions ) as $key ) {
1100 + if ( isset( $lite_actions[ $key ] ) ) {
1101 + continue;
1102 + }
1103 +
1104 + add_filter(
1105 + 'frm_' . $key . '_action_options',
1106 + function ( $options ) {
1107 + $options['active'] = false;
1108 +
1109 + if ( ! str_contains( $options['classes'], 'frm_show_upgrade' ) ) {
1110 + $options['classes'] .= ' frm_show_upgrade';
1111 + }
1112 +
1113 + return $options;
1114 + }
1115 + );
1116 + }//end foreach
1117 +
1118 + return $actions;
1119 + }
1120 +
1121 + /**
1122 + * Get action keys that are available in Lite without a Pro license.
1123 + *
1124 + * @since 6.31
1125 + *
1126 + * @return string[]
1127 + */
1128 + public static function get_lite_actions() {
1129 + return apply_filters( 'frm_lite_form_actions', array( 'on_submit', 'email', 'payment', 'stripe', 'square', 'paypal' ) );
1130 + }
1131 +
1132 + /**
1133 + * Single source of truth for learn-more URL slugs used in
1134 + * upgrade modals for non-Lite form actions.
1135 + *
1136 + * Slugs without '/' are KB doc slugs (knowledgebase/ prefix is added).
1137 + * Slugs with '/' are direct paths (e.g. features/) used as-is.
1138 + *
1139 + * @since 6.31
1140 + *
1141 + * @return array<string,string> Map of action_key => URL slug.
1142 + */
1143 + public static function get_action_learn_more_links() {
1144 + return array(
1145 + 'wppost' => 'features/user-submitted-posts-wordpress-forms',
1146 + 'register' => 'user-registration',
1147 + 'paypal' => 'features/paypal-wordpress-payments',
1148 + 'quiz' => 'quiz-maker-forms',
1149 + 'quiz_outcome' => 'quiz-maker-forms',
1150 + 'aweber' => 'features/aweber-addon',
1151 + 'mailchimp' => 'features/mailchimp-addon',
1152 + 'zapier' => 'features/form-entry-routing-with-zapier',
1153 + 'twilio' => 'features/twilio-sms-form-notifications',
1154 + 'activecampaign' => 'features/entries-to-activecampaign',
1155 + 'salesforce' => 'features/form-entries-to-salesforce',
1156 + 'constantcontact' => 'features/entries-to-constant-contact',
1157 + 'getresponse' => 'features/form-entries-to-getresponse',
1158 + 'hubspot' => 'features/form-entries-to-hubspot',
1159 + 'mailpoet' => 'features/mailpoet-newsletters-addon',
1160 + 'api' => 'features/wordpress-form-api',
1161 + 'googlespreadsheet' => 'features/google-sheets',
1162 + 'n8n' => 'features/connect-your-forms-to-any-app-with-n8n',
1163 + 'convertkit' => 'features/convertkit',
1164 + );
1165 + }
1166 +
1167 + /**
1168 + * Look up the learn-more doc slug for a given action key.
1169 + *
1170 + * @since 6.31
1171 + *
1172 + * @param string $action_key Action identifier (e.g. 'register').
1173 + *
1174 + * @return string Doc slug or empty string.
1175 + */
1176 + private static function get_learn_more_slug( $action_key ) {
1177 + $links = self::get_action_learn_more_links();
1178 + return $links[ $action_key ] ?? '';
1179 + }
579 1180 }
580 1181
581 1182 class Frm_Form_Action_Factory {
1183 +
1184 + /**
1185 + * @var array
1186 + */
582 1187 public $actions = array();
583 1188
584 1189 public function __construct() {
585 1190 add_action( 'frm_form_actions_init', array( $this, '_register_actions' ), 100 );
@@ -584,12 +1189,22 @@
584 1189 public function __construct() {
585 1190 add_action( 'frm_form_actions_init', array( $this, '_register_actions' ), 100 );
586 1191 }
587 1192
1193 + /**
1194 + * @param string $action_class
1195 + *
1196 + * @return void
1197 + */
588 1198 public function register( $action_class ) {
589 1199 $this->actions[ $action_class ] = new $action_class();
590 1200 }
591 1201
1202 + /**
1203 + * @param string $action_class
1204 + *
1205 + * @return void
1206 + */
592 1207 public function unregister( $action_class ) {
593 1208 if ( isset( $this->actions[ $action_class ] ) ) {
594 1209 unset( $this->actions[ $action_class ] );
595 1210 }
@@ -598,9 +1213,9 @@
598 1213 public function _register_actions() {
599 1214 $keys = array_keys( $this->actions );
600 1215
601 1216 foreach ( $keys as $key ) {
602 - // don't register new action if old action with the same id is already registered
1217 + // Don't register new action if old action with the same id is already registered
603 1218 if ( ! isset( $this->actions[ $key ] ) ) {
604 1219 $this->actions[ $key ]->_register();
605 1220 }
606 1221 }