PluginProbe ʕ •ᴥ•ʔ
Conditional Fields for Contact Form 7 / 1.7
Conditional Fields for Contact Form 7 v1.7
2.7.8 2.7.7 2.7.6 2.7.5 2.7.4 2.7.3 2.7.2 0.2.4 0.2.5 0.2.6 0.2.7 0.2.8 0.2.9 1.0 1.1 1.2 1.2.1 1.2.2 1.2.3 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.4 1.4.1 1.4.2 1.4.3 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.6.1 1.6.2 1.6.3 1.6.5 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.8 1.7.9 1.8 1.8.1 1.8.2 1.8.3 1.8.5 1.8.6 1.8.7 1.9 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2 2.2.1 2.2.10 2.2.11 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3 2.3.1 2.3.10 2.3.11 2.3.12 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 2.4 2.4.1 2.4.10 2.4.11 2.4.12 2.4.13 2.4.14 2.4.15 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.14 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6 2.6.1 2.6.2 2.6.3 2.6.4 2.6.5 2.6.6 2.6.7 2.6.8 2.7 2.7.1 trunk 0.1 0.1.1 0.1.2 0.1.3 0.1.4 0.1.5 0.1.6 0.1.7 0.2 0.2.1 0.2.2 0.2.3
cf7-conditional-fields / cf7cf.php
cf7-conditional-fields Last commit date
js 6 years ago Wpcf7cfMailParser.php 6 years ago admin-style.css 6 years ago admin-style.css.map 6 years ago admin-style.scss 6 years ago admin.php 6 years ago cf7cf.php 6 years ago contact-form-7-conditional-fields.php 6 years ago init.php 6 years ago readme.txt 6 years ago style.css 6 years ago tg_pane_group.php 6 years ago wpcf7cf-options.php 6 years ago
cf7cf.php
477 lines
1 <?php
2
3 class CF7CF {
4 private $hidden_fields = array();
5 private $visible_groups = array();
6 private $hidden_groups = array();
7 private $repeaters = array();
8
9 function __construct() {
10
11 // can't use wpcf7_enqueue_scripts hook, because it's possible that people
12 // want to disable the CF7 scripts. but in this case Conditional fields should still work.
13 // add_action('wpcf7_enqueue_scripts', array(__CLASS__, 'enqueue_js')); // <-- don't use this
14
15 // Enqueue_scripts moved to function outside class.
16
17 // add_action('wp_enqueue_scripts', array(__CLASS__, 'enqueue_js'), 20);
18 // add_action('wpcf7_enqueue_styles', array(__CLASS__, 'enqueue_css'));
19
20 // Register shortcodes
21 add_action('wpcf7_init', array(__CLASS__, 'add_shortcodes'));
22
23 // Tag generator
24 add_action('admin_init', array(__CLASS__, 'tag_generator'), 590);
25
26 // compatibility with CF7 multi-step forms by Webhead LLC.
27 add_filter( 'wpcf7_posted_data', array($this,'cf7msm_merge_post_with_cookie'), 8, 1 );
28
29 // compatibility with CF7 Multi Step by NinjaTeam https://wordpress.org/plugins/cf7-multi-step/
30 add_action('wp_ajax_cf7mls_validation', array($this,'cf7mls_validation_callback'),9);
31 add_action('wp_ajax_nopriv_cf7mls_validation', array($this,'cf7mls_validation_callback'),9);
32
33 // check which fields are hidden during form submission and change some stuff accordingly
34 add_filter( 'wpcf7_posted_data', array($this, 'remove_hidden_post_data') );
35
36 add_filter( 'wpcf7_validate', array($this, 'skip_validation_for_hidden_fields'), 2, 2 );
37
38 // validation messages
39 add_action('wpcf7_config_validator_validate', array($this,'wpcf7cf_config_validator_validate'));
40
41
42 add_action("wpcf7_before_send_mail", [$this, 'hide_hidden_mail_fields'], 10, 3);
43
44 register_activation_hook(__FILE__, array($this, 'activate'));
45
46 if (is_admin()) {
47 require_once dirname(__FILE__) . '/admin.php';
48 }
49 }
50
51
52
53 /**
54 * Suppress invalid mailbox syntax errors on fields that contain existing conditional
55 */
56 function wpcf7cf_config_validator_validate(WPCF7_ConfigValidator $wpcf7_config_validator) {
57
58 // TODO: For now we kill every syntax error once a [groupname] tag is detected.
59 // Ideally, this function should check each string inside the group for invalid syntax.
60 // TODO 2: ajax validation not working yet, because $cf->scan_form_tags() does not seem to contain group tags if it's an ajax request. Need to investigate.
61
62 $cf = $wpcf7_config_validator->contact_form();
63 $all_group_tags = $cf->scan_form_tags();
64
65 foreach ($wpcf7_config_validator->collect_error_messages() as $err_type => $err) {
66
67 // print_r($err_type);
68
69 $parts = explode('.',$err_type);
70
71 $property = $parts[0];
72
73 if ($property == 'form') continue; // the 'form' field can be safely validated by CF7. No need to suppress it.
74
75 $sub_prop = $parts[1];
76 $prop_val = $cf->prop($property)[$sub_prop];
77
78
79 // TODO 2: Dirty hack. Because of TODO 2 we are just going to kill the error message if we detect the string '[/'
80 // Start removing here.
81 if (strpos($prop_val, '[/') !== false) {
82 $wpcf7_config_validator->remove_error($err_type, WPCF7_ConfigValidator::error_invalid_mailbox_syntax);
83 continue;
84 }
85 // TODO 2: Stop removing here. and uncomment code below.
86
87 // foreach ($all_group_tags as $form_tag) {
88 // if (strpos($prop_val, '['.$form_tag->name.']') !== false) {
89 // $wpcf7_config_validator->remove_error($err_type, WPCF7_ConfigValidator::error_invalid_mailbox_syntax);
90 // }
91 // }
92
93 }
94
95 return new WPCF7_ConfigValidator($wpcf7_config_validator->contact_form());
96 }
97
98 function activate() {
99 //add options with add_option and stuff
100 }
101
102 public static function add_shortcodes() {
103 if (function_exists('wpcf7_add_form_tag'))
104 wpcf7_add_form_tag('group', array(__CLASS__, 'shortcode_handler'), true);
105 else if (function_exists('wpcf7_add_shortcode')) {
106 wpcf7_add_shortcode('group', array(__CLASS__, 'shortcode_handler'), true);
107 } else {
108 throw new Exception('functions wpcf7_add_form_tag and wpcf7_add_shortcode not found.');
109 }
110 }
111
112 function group_shortcode_handler( $atts, $content = "" ) {
113 return $content;
114 }
115
116 public static function shortcode_handler($tag) {
117 //$tag = new WPCF7_Shortcode($tag);
118 $tag = new WPCF7_FormTag($tag);
119 //ob_start();
120 //print_r($tag);
121 //return print_r($tag, true);
122 return $tag->content;
123 }
124
125
126 public static function tag_generator() {
127 if (! function_exists( 'wpcf7_add_tag_generator'))
128 return;
129
130 wpcf7_add_tag_generator('group',
131 __('Conditional Fields Group', 'wpcf7cf'),
132 'wpcf7-tg-pane-group',
133 array(__CLASS__, 'tg_pane')
134 );
135
136 do_action('wpcf7cf_tag_generator');
137 }
138
139 static function tg_pane( $contact_form, $args = '' ) {
140 $args = wp_parse_args( $args, array() );
141 $type = 'group';
142
143 $description = __( "Generate a group tag to group form elements that can be shown conditionally.", 'cf7cf' );
144
145 include 'tg_pane_group.php';
146 }
147
148 /**
149 * Remove validation requirements for fields that are hidden at the time of form submission.
150 * Called using add_filter( 'wpcf7_validate_[tag_type]', array($this, 'skip_validation_for_hidden_fields'), 2, 2 );
151 * where the priority of 2 causes this to kill any validations with a priority higher than 2
152 *
153 * @param $result
154 * @param $tag
155 *
156 * @return mixed
157 */
158 function skip_validation_for_hidden_fields($result, $tags) {
159
160 if (count($this->hidden_fields) == 0) return $result;
161
162 $return_result = new WPCF7_Validation();
163
164 $invalid_fields = $result->get_invalid_fields();
165
166 if (!is_array($invalid_fields) || count($invalid_fields) == 0) return $result;
167
168 foreach ($invalid_fields as $invalid_field_key => $invalid_field_data) {
169 if (!in_array($invalid_field_key, $this->hidden_fields)) {
170 // the invalid field is not a hidden field, so we'll add it to the final validation result
171 $return_result->invalidate($invalid_field_key, $invalid_field_data['reason']);
172 }
173 }
174
175 return $return_result;
176 }
177
178
179 /**
180 * When a CF7 form is posted, check the form for hidden fields, then remove those fields from the post data
181 *
182 * @param $posted_data
183 *
184 * @return mixed
185 */
186 function remove_hidden_post_data($posted_data) {
187 $this->set_hidden_fields_arrays($posted_data);
188
189 // TODO: activating the code below will change the behaviour of the plugin, as all hidden fields will not be POSTed.
190 // We might consider activating this based on a setting in the future. But for now, we're not gonna use it.
191
192 // foreach( $this->hidden_fields as $name => $value ) {
193 // unset( $posted_data[$value] ); // Yes, it should be $value, not $name. https://github.com/pwkip/contact-form-7-conditional-fields/pull/17
194 // }
195
196 return $posted_data;
197 }
198
199 function cf7msm_merge_post_with_cookie($posted_data) {
200
201 if (!function_exists('cf7msm_get') || !key_exists('cf7msm_posted_data',$_COOKIE)) return $posted_data;
202
203 if (!$posted_data) {
204 $posted_data = WPCF7_Submission::get_instance()->get_posted_data();
205 }
206
207 // this will temporarily set the hidden fields data to the posted_data.
208 // later this function will be called again with the updated posted_data
209 $this->set_hidden_fields_arrays($posted_data);
210
211 // get cookie data
212 $cookie_data = cf7msm_get('cf7msm_posted_data');
213 $cookie_data_hidden_group_fields = json_decode(stripslashes($cookie_data['_wpcf7cf_hidden_group_fields']));
214 $cookie_data_hidden_groups = json_decode(stripslashes($cookie_data['_wpcf7cf_hidden_groups']));
215 $cookie_data_visible_groups = json_decode(stripslashes($cookie_data['_wpcf7cf_visible_groups']));
216
217 // remove all the currently posted data from the cookie data (we don't wanna add it twice)
218 $cookie_data_hidden_group_fields = array_diff($cookie_data_hidden_group_fields, array_keys($posted_data));
219 $cookie_data_hidden_groups = array_diff((array) $cookie_data_hidden_groups, $this->hidden_groups, $this->visible_groups);
220 $cookie_data_visible_groups = array_diff((array) $cookie_data_visible_groups, $this->hidden_groups, $this->visible_groups);
221
222 // update current post data with cookie data
223 $posted_data['_wpcf7cf_hidden_group_fields'] = addslashes(json_encode(array_merge((array) $cookie_data_hidden_group_fields, $this->hidden_fields)));
224 $posted_data['_wpcf7cf_hidden_groups'] = addslashes(json_encode(array_merge((array) $cookie_data_hidden_groups, $this->hidden_groups)));
225 $posted_data['_wpcf7cf_visible_groups'] = addslashes(json_encode(array_merge((array) $cookie_data_visible_groups, $this->visible_groups)));
226
227 return $posted_data;
228 }
229
230 // compatibility with CF7 Multi Step by NinjaTeam https://wordpress.org/plugins/cf7-multi-step/
231 function cf7mls_validation_callback() {
232 $this->set_hidden_fields_arrays($_POST);
233 }
234
235 /**
236 * Finds the currently submitted form and set the hidden_fields variables accoringly
237 *
238 * @param bool|array $posted_data
239 */
240 function set_hidden_fields_arrays($posted_data = false) {
241
242 if (!$posted_data) {
243 $posted_data = WPCF7_Submission::get_instance()->get_posted_data();
244 }
245
246 $hidden_fields = json_decode(stripslashes($posted_data['_wpcf7cf_hidden_group_fields']));
247 if (is_array($hidden_fields) && count($hidden_fields) > 0) {
248 foreach ($hidden_fields as $field) {
249 $this->hidden_fields[] = $field;
250 if (wpcf7cf_endswith($field, '[]')) {
251 $this->hidden_fields[] = substr($field,0,strlen($field)-2);
252 }
253 }
254 }
255 $this->hidden_groups = json_decode(stripslashes($posted_data['_wpcf7cf_hidden_groups']));
256 $this->visible_groups = json_decode(stripslashes($posted_data['_wpcf7cf_visible_groups']));
257 $this->repeaters = json_decode(stripslashes($posted_data['_wpcf7cf_repeaters']));
258 }
259
260 function hide_hidden_mail_fields($form,$abort,$submission) {
261 $props = $form->get_properties();
262 $mails = ['mail','mail_2','messages'];
263 foreach ($mails as $mail) {
264 foreach ($props[$mail] as $key=>$val) {
265
266 $parser = new Wpcf7cfMailParser($val, $this->visible_groups, $this->hidden_groups, $this->repeaters, $_POST);
267
268 // $props[$mail][$key] = preg_replace_callback(WPCF7CF_REGEX_MAIL_GROUP, array($this, 'hide_hidden_mail_fields_regex_callback'), $val );
269 $props[$mail][$key] = $parser->getParsedMail();
270 }
271 }
272 //$props['mail']['body'] = 'xxx';
273 $form->set_properties($props);
274 }
275
276 function hide_hidden_mail_fields_regex_callback ( $matches ) {
277 $name = $matches[1];
278 $content = $matches[2];
279 if ( in_array( $name, $this->hidden_groups ) ) {
280 // The tag name represents a hidden group, so replace everything from [tagname] to [/tagname] with nothing
281 return '';
282 } elseif ( in_array( $name, $this->visible_groups ) ) {
283 // The tag name represents a visible group, so remove the tags themselves, but return everything else
284 // instead of just returning the $content, return the preg_replaced content :)
285 return preg_replace_callback(WPCF7CF_REGEX_MAIL_GROUP, array($this, 'hide_hidden_mail_fields_regex_callback'), $content );
286 } else {
287 // The tag name doesn't represent a group that was used in the form. Leave it alone (return the entire match).
288 return $matches[0];
289 }
290 }
291
292 public static function parse_conditions($string, $format='array') {
293 // Parse stuff like "show [g1] if [field] equals 2" to Array
294
295 preg_match_all(WPCF7CF_REGEX_CONDITIONS, $string, $matches);
296
297 $conditions = [];
298
299 $prev_then_field = '';
300 foreach ($matches[0] as $i=>$line) {
301 $then_field = $matches[1][$i];
302 $if_field = $matches[2][$i];
303 $operator = $matches[3][$i];
304 $if_value = $matches[4][$i];
305
306 $index = count($conditions);
307
308 if ($then_field == '') {
309 $index = $index -1;
310 $then_field = $prev_then_field;
311 } else {
312 $conditions[$index]['then_field'] = $then_field;
313 }
314
315 $conditions[$index]['and_rules'][] = [
316 'if_field' => $if_field,
317 'operator' => $operator,
318 'if_value' => $if_value,
319 ];
320
321 $prev_then_field = $then_field;
322
323 }
324
325 $conditions = array_values($conditions);
326
327 if ($format == 'array') {
328 return $conditions;
329 } else if ($format == 'json') {
330 return json_encode($conditions);
331 }
332 }
333
334 /**
335 * load the conditions from the form's post_meta
336 *
337 * @param string $form_id
338 * @return void
339 */
340 public static function getConditions($form_id) {
341 return get_post_meta($form_id,'wpcf7cf_options',true); // the meta key 'wpcf7cf_options' is a bit misleading at this point, because it only holds the form's conditions, no other options/settings
342 }
343
344
345 /**
346 * save the conditions to the form's post_meta
347 *
348 * @param string $form_id
349 * @return void
350 */
351 public static function setConditions($form_id, $conditions) {
352 return update_post_meta($form_id,'wpcf7cf_options',$conditions); // the meta key 'wpcf7cf_options' is a bit misleading at this point, because it only holds the form's conditions, no other options/settings
353 }
354 }
355
356 new CF7CF;
357
358 add_filter( 'wpcf7_contact_form_properties', 'wpcf7cf_properties', 10, 2 );
359
360 function wpcf7cf_properties($properties, $wpcf7form) {
361 // TODO: This function is called serveral times. The problem is that the filter is called each time we call get_properties() on a contact form.
362 // TODO: I haven't found a better way to solve this problem yet, any suggestions or push requests are welcome. (same problem in PRO/repeater.php)
363 if (!is_admin() || (defined('DOING_AJAX') && DOING_AJAX)) { // TODO: kind of hacky. maybe find a better solution. Needed because otherwise the group tags will be replaced in the editor as well.
364 $form = $properties['form'];
365
366 $form_parts = preg_split('/(\[\/?group(?:\]|\s.*?\]))/',$form, -1,PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
367
368 ob_start();
369
370 $stack = array();
371
372 foreach ($form_parts as $form_part) {
373 if (substr($form_part,0,7) == '[group ') {
374 $tag_parts = explode(' ',rtrim($form_part,']'));
375
376 array_shift($tag_parts);
377
378 $tag_id = $tag_parts[0];
379 $tag_html_type = 'div';
380 $tag_html_data = array();
381
382 foreach ($tag_parts as $i => $tag_part) {
383 if ($i==0) continue;
384 else if ($tag_part == 'inline') $tag_html_type = 'span';
385 else if ($tag_part == 'clear_on_hide') $tag_html_data[] = 'data-clear_on_hide';
386 }
387
388 array_push($stack,$tag_html_type);
389
390 echo '<'.$tag_html_type.' data-id="'.$tag_id.'" data-orig_data_id="'.$tag_id.'" '.implode(' ',$tag_html_data).' data-class="wpcf7cf_group">';
391 } else if ($form_part == '[/group]') {
392 echo '</'.array_pop($stack).'>';
393 } else {
394 echo $form_part;
395 }
396 }
397
398 $properties['form'] = ob_get_clean();
399 }
400 return $properties;
401 }
402
403 add_action('wpcf7_form_hidden_fields', 'wpcf7cf_form_hidden_fields',10,1);
404
405 function wpcf7cf_form_hidden_fields($hidden_fields) {
406
407 $current_form = wpcf7_get_current_contact_form();
408 $current_form_id = $current_form->id();
409
410 $options = array(
411 'form_id' => $current_form_id,
412 'conditions' => CF7CF::getConditions($current_form_id),
413 'settings' => get_option(WPCF7CF_OPTIONS)
414 );
415
416 unset($options['settings']['license_key']); // don't show license key in the source code duh.
417
418 return array_merge($hidden_fields, array(
419 '_wpcf7cf_hidden_group_fields' => '',
420 '_wpcf7cf_hidden_groups' => '',
421 '_wpcf7cf_visible_groups' => '',
422 '_wpcf7cf_repeaters' => '[]',
423 '_wpcf7cf_options' => ''.json_encode($options),
424 ));
425 }
426
427 function wpcf7cf_endswith($string, $test) {
428 $strlen = strlen($string);
429 $testlen = strlen($test);
430 if ($testlen > $strlen) return false;
431 return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
432 }
433
434 add_filter( 'wpcf7_form_tag_data_option', 'wpcf7cf_form_tag_data_option', 10, 3 );
435
436 function wpcf7cf_form_tag_data_option($output, $args, $nog) {
437 $data = array();
438 return $data;
439 }
440
441 /* Scripts & Styles */
442
443 function wpcf7cf_load_js() {
444 return apply_filters( 'wpcf7cf_load_js', WPCF7CF_LOAD_JS );
445 }
446
447 function wpcf7cf_load_css() {
448 return apply_filters( 'wpcf7cf_load_css', WPCF7CF_LOAD_CSS );
449 }
450
451 add_action( 'wp_enqueue_scripts', 'wpcf7cf_do_enqueue_scripts', 20, 0 );
452
453 function wpcf7cf_do_enqueue_scripts() {
454 if ( wpcf7cf_load_js() ) {
455 wpcf7cf_enqueue_scripts();
456 }
457
458 if ( wpcf7cf_load_css() ) {
459 wpcf7cf_enqueue_styles();
460 }
461 }
462
463 function wpcf7cf_enqueue_scripts() {
464 if (is_admin()) return;
465 wp_enqueue_script('wpcf7cf-scripts', plugins_url('js/scripts.js', __FILE__), array('jquery'), WPCF7CF_VERSION, true);
466 wp_localize_script('wpcf7cf-scripts', 'wpcf7cf_global_settings',
467 array(
468 'ajaxurl' => admin_url('admin-ajax.php'),
469 )
470 );
471
472 }
473
474 function wpcf7cf_enqueue_styles() {
475 if (is_admin()) return;
476 wp_enqueue_style('cf7cf-style', plugins_url('style.css', __FILE__), array(), WPCF7CF_VERSION);
477 }