| 1 |
<?php |
| 2 |
use voku\helper\HtmlDomParser; |
| 3 |
|
| 4 |
/** |
| 5 |
* The public-facing functionality of the plugin. |
| 6 |
* |
| 7 |
* @link http://syllogic.in |
| 8 |
* @since 1.0.0 |
| 9 |
* |
| 10 |
* @package Cf7_Grid_Layout |
| 11 |
* @subpackage Cf7_Grid_Layout/public |
| 12 |
*/ |
| 13 |
|
| 14 |
/** |
| 15 |
* The public-facing functionality of the plugin. |
| 16 |
* |
| 17 |
* Defines the plugin name, version, and two examples hooks for how to |
| 18 |
* enqueue the admin-specific stylesheet and JavaScript. |
| 19 |
* |
| 20 |
* @package Cf7_Grid_Layout |
| 21 |
* @subpackage Cf7_Grid_Layout/public |
| 22 |
* @author Aurovrata V. <vrata@syllogic.in> |
| 23 |
*/ |
| 24 |
class Cf7_Grid_Layout_Public { |
| 25 |
|
| 26 |
/** |
| 27 |
* The ID of this plugin. |
| 28 |
* |
| 29 |
* @since 1.0.0 |
| 30 |
* @access private |
| 31 |
* @var string $plugin_name The ID of this plugin. |
| 32 |
*/ |
| 33 |
private $plugin_name; |
| 34 |
private $registered = false; |
| 35 |
|
| 36 |
/** |
| 37 |
* The version of this plugin. |
| 38 |
* |
| 39 |
* @since 1.0.0 |
| 40 |
* @access private |
| 41 |
* @var string $version The current version of this plugin. |
| 42 |
*/ |
| 43 |
private $version; |
| 44 |
|
| 45 |
/** |
| 46 |
* The version of this plugin. |
| 47 |
* |
| 48 |
* @since 2.6.0 |
| 49 |
* @access private |
| 50 |
* @var string $form_id The current form id. |
| 51 |
*/ |
| 52 |
private $form_id=''; |
| 53 |
|
| 54 |
/** |
| 55 |
* The cf7 array fields. |
| 56 |
* |
| 57 |
* @since 1.0.0 |
| 58 |
* @access private |
| 59 |
* @var Array $array_grid_fields The form fields which were converted to arrays by the plugin. |
| 60 |
*/ |
| 61 |
static private $array_grid_fields = array(); |
| 62 |
|
| 63 |
/** |
| 64 |
* The cf7 array fields. |
| 65 |
* |
| 66 |
* @since 2.5.0 |
| 67 |
* @access private |
| 68 |
* @var Array $array_toggle_fields The form fields which are within toggle sections. |
| 69 |
*/ |
| 70 |
static private $array_toggle_fields = array(); |
| 71 |
|
| 72 |
/** |
| 73 |
* The cf7 array fields. |
| 74 |
* |
| 75 |
* @since 2.5.0 |
| 76 |
* @access private |
| 77 |
* @var Array $array_toggled_panels The form toggled sections used. |
| 78 |
*/ |
| 79 |
static private $array_toggled_panels = array(); |
| 80 |
|
| 81 |
/** |
| 82 |
* The cf7 array fields. |
| 83 |
* |
| 84 |
* @since 3.3.5 |
| 85 |
* @access private |
| 86 |
* @var Array $array_toggle_in_tabs The form toggle sections within tabs.. |
| 87 |
*/ |
| 88 |
static private $array_toggle_in_tabs = array(); |
| 89 |
/** |
| 90 |
* The cf7 array fields. |
| 91 |
* |
| 92 |
* @since 2.6.0 |
| 93 |
* @access private |
| 94 |
* @var Array $localised_data Localised data parameters. |
| 95 |
*/ |
| 96 |
private $localised_data = array(); |
| 97 |
|
| 98 |
/** |
| 99 |
* Initialize the class and set its properties. |
| 100 |
* |
| 101 |
* @since 1.0.0 |
| 102 |
* @param string $plugin_name The name of the plugin. |
| 103 |
* @param string $version The version of this plugin. |
| 104 |
*/ |
| 105 |
public function __construct( $plugin_name, $version ) { |
| 106 |
|
| 107 |
$this->plugin_name = $plugin_name; |
| 108 |
$this->version = $version; |
| 109 |
} |
| 110 |
/** |
| 111 |
* |
| 112 |
* |
| 113 |
* @since 1.0.0 |
| 114 |
* @param string $field field name to check |
| 115 |
* @param string $form_id form id for which to check the |
| 116 |
* @return string 'singular' for non-grid fields, 'tab' for tabbed fields, 'table' for tablled fields, 'both' for fields in tables in tabs. |
| 117 |
*/ |
| 118 |
static public function field_type($field, $form_id){ |
| 119 |
if(!isset(self::$array_grid_fields[$form_id])){ |
| 120 |
//try to load the fields. |
| 121 |
self::get_grid_fields($form_id); |
| 122 |
} |
| 123 |
$type = 'singular'; |
| 124 |
if(isset(self::$array_grid_fields[$form_id][$field])){ |
| 125 |
$type = self::$array_grid_fields[$form_id][$field]; |
| 126 |
switch(true){ /** @since 2.4.2 tables have unique id with time in milliseconds since 1/1/70 */ |
| 127 |
case preg_match('/^cf7-sg-table-[0-9]{3,13}$/', $type): |
| 128 |
$type = 'table'; |
| 129 |
break; |
| 130 |
case preg_match('/^cf7-sg-tab-[0-9]{3,13}$/', $type): |
| 131 |
$type = 'tab'; |
| 132 |
break; |
| 133 |
default: |
| 134 |
$type = 'both'; |
| 135 |
break; |
| 136 |
} |
| 137 |
} |
| 138 |
return $type; |
| 139 |
} |
| 140 |
|
| 141 |
/** |
| 142 |
* Check if a field is in a toggled section. |
| 143 |
* |
| 144 |
*@since 2.5.0 |
| 145 |
*@param string $field field nav_menu_link_attributes. |
| 146 |
*@return boolean check if the field is in a toggle section. |
| 147 |
*/ |
| 148 |
protected function get_toggle($field){ |
| 149 |
return isset(self::$array_toggle_fields[$this->form_id][$field]) ? self::$array_toggle_fields[$this->form_id][$field]: null; |
| 150 |
} |
| 151 |
/** |
| 152 |
* Check if a toggled section was used and its fields submitted. |
| 153 |
* |
| 154 |
*@since 2.5.0 |
| 155 |
*@param string $toggle toogle id |
| 156 |
*@return boolean was the toggle section submitted. |
| 157 |
*/ |
| 158 |
protected function is_submitted($toggle){ |
| 159 |
return isset(self::$array_toggled_panels[$this->form_id][$toggle]); |
| 160 |
} |
| 161 |
/** |
| 162 |
* Check if a toggled section was used and its fields submitted. |
| 163 |
* |
| 164 |
*@since 3.3.5 |
| 165 |
*@param string $toggle toogle id |
| 166 |
*@return boolean is the toggle within a tab. |
| 167 |
*/ |
| 168 |
protected function is_tabbed($toggle){ |
| 169 |
return isset(self::$array_toggle_in_tabs[$toggle]); |
| 170 |
} |
| 171 |
/** |
| 172 |
* Register the stylesheets for the public-facing side of the site. |
| 173 |
* |
| 174 |
* @since 1.0.0 |
| 175 |
*/ |
| 176 |
public function register_styles() { |
| 177 |
$airplane=false; |
| 178 |
if( class_exists( 'Airplane_Mode_Core' ) && Airplane_Mode_Core::getInstance()->enabled()){ |
| 179 |
$airplane=true; |
| 180 |
} |
| 181 |
$plugin_dir = plugin_dir_url( __DIR__ ); |
| 182 |
//default style for cf7 grid forms (row buttons and tables mainly). |
| 183 |
//others |
| 184 |
// get registered script object for jquery-ui |
| 185 |
global $wp_scripts; |
| 186 |
$ui = $wp_scripts->query('jquery-ui-core'); |
| 187 |
|
| 188 |
// tell WordPress to load the Smoothness theme from Google CDN |
| 189 |
if( !$airplane ){ |
| 190 |
$protocol = is_ssl() ? 'https' : 'http'; |
| 191 |
$url_path = "$protocol://cdnjs.cloudflare.com/ajax/libs/jqueryui/{$ui->ver}/"; |
| 192 |
wp_register_style('cf7-jquery-ui', $url_path . 'themes/smoothness/jquery-ui.min.css', array(), $ui->ver , 'all'); |
| 193 |
} |
| 194 |
|
| 195 |
wp_register_style( 'cf7-jquery-ui-theme', $url_path . 'jquery-ui.theme.min.css', array(), $ui->ver, 'all'); |
| 196 |
wp_register_style( 'cf7-jquery-ui-structure', $url_path . 'jquery-ui.structure.min.css', array(), $ui->ver, 'all'); |
| 197 |
/** @since 3.1,0 improve live loading of resources */ |
| 198 |
$ff = ''; |
| 199 |
$pf=''; |
| 200 |
if(!defined('WP_DEBUG') || !WP_DEBUG){ |
| 201 |
$ff = '.min'; |
| 202 |
$pf = '/min'; |
| 203 |
} |
| 204 |
wp_register_style( 'cf7-benchmark-css', $plugin_dir . "public/css{$pf}/cf7-benchmark.css", array(), $this->version, 'all' ); |
| 205 |
wp_register_style( $this->plugin_name, $plugin_dir . "public/css{$pf}/cf7-grid-layout-public.css", array(), $this->version, 'all' ); |
| 206 |
wp_register_style( 'smart-grid', $plugin_dir . "assets/css.gs/smart-grid{$ff}.css", array(), $this->version, 'all' ); |
| 207 |
wp_register_style('jquery-nice-select-css', $plugin_dir . "assets/jquery-nice-select/css/nice-select{$ff}.css", array(), $this->version, 'all' ); |
| 208 |
wp_register_style('jquery-toggles-css', $plugin_dir . "assets/jquery-toggles/css/toggles{$ff}.css", array(), $this->version, 'all' ); |
| 209 |
wp_register_style('jquery-toggles-light-css', $plugin_dir . "assets/jquery-toggles/css/themes/toggles-light{$ff}.css", array('jquery-toggles-css'), $this->version, 'all' ); |
| 210 |
/** @since 3.2.1 use cloudflare for live sites */ |
| 211 |
if( $airplane || (defined('WP_DEBUG') && WP_DEBUG) ){ |
| 212 |
wp_register_style('select2-style', $plugin_dir . 'assets/select2/css/select2.min.css', array(), '4.0.13', 'all' ); |
| 213 |
}else{ |
| 214 |
wp_register_style('select2-style', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/css/select2.min.css', array(), '4.0.13','all'); |
| 215 |
} |
| 216 |
|
| 217 |
//allow custom script registration |
| 218 |
do_action('smart_grid_register_styles'); |
| 219 |
} |
| 220 |
|
| 221 |
/** |
| 222 |
* Register the JavaScript for the public-facing side of the site. |
| 223 |
* |
| 224 |
* @since 1.0.0 |
| 225 |
*/ |
| 226 |
public function register_scripts() { |
| 227 |
$airplane=false; |
| 228 |
if( class_exists( 'Airplane_Mode_Core' ) && Airplane_Mode_Core::getInstance()->enabled()){ |
| 229 |
$airplane=true; |
| 230 |
} |
| 231 |
/** @since 3.1,0 improve live loading of resources */ |
| 232 |
$pf=''; |
| 233 |
if(!defined('WP_DEBUG') || !WP_DEBUG){ |
| 234 |
$pf = '/min'; |
| 235 |
} |
| 236 |
$plugin_dir = plugin_dir_url( __DIR__ ); |
| 237 |
wp_register_script( $this->plugin_name, $plugin_dir . "public/js{$pf}/cf7-grid-layout-public.js", array( 'jquery','contact-form-7' ), $this->version, true ); |
| 238 |
/** @since 3.2.1 use cloudflare for live sites */ |
| 239 |
if( $airplane || (defined('WP_DEBUG') && WP_DEBUG) ){ |
| 240 |
wp_register_script('jquery-select2', $plugin_dir . 'assets/select2/js/select2.min.js', array( 'jquery' ), '4.0.13', true ); |
| 241 |
}else{ |
| 242 |
wp_register_script('jquery-select2', '//cdnjs.cloudflare.com/ajax/libs/select2/4.0.13/js/select2.min.js', array( 'jquery' ), '4.0.13', true ); |
| 243 |
} |
| 244 |
wp_register_script('jquery-nice-select', $plugin_dir . 'assets/jquery-nice-select/js/jquery.nice-select.min.js', array( 'jquery' ), $this->version, true ); |
| 245 |
wp_register_script('jquery-toggles', $plugin_dir . 'assets/jquery-toggles/toggles.min.js', array( 'jquery' ), $this->version, true ); |
| 246 |
wp_register_script('js-cf7sg-benchmarking', $plugin_dir . "public/js{$pf}/cf7-benchmark.js", array( 'jquery' ), $this->version, true ); |
| 247 |
//allow custom script registration |
| 248 |
do_action('smart_grid_register_scripts'); |
| 249 |
} |
| 250 |
/** |
| 251 |
* Dequeue script 'contact-form-7' |
| 252 |
* hooked on 'wp_print_scripts', this canbe re-enqeued on specific cf7 shortcode calls |
| 253 |
* @since 1.0.0 |
| 254 |
**/ |
| 255 |
public function dequeue_cf7_scripts(){ |
| 256 |
wp_dequeue_script('contact-form-7'); |
| 257 |
} |
| 258 |
/** |
| 259 |
* Dequeue script 'contact-form-7' |
| 260 |
* hooked on 'wp_print_style', this canbe re-enqeued on specific cf7 shortcode calls |
| 261 |
* @since 1.0.0 |
| 262 |
**/ |
| 263 |
public function dequeue_cf7_styles(){ |
| 264 |
wp_dequeue_style('contact-form-7'); |
| 265 |
} |
| 266 |
/** |
| 267 |
* Add the cf7 key to the hidden fields so as not to have to load it after each submission. |
| 268 |
* Hooked to 'wpcf7_form_hidden_fields' |
| 269 |
* @since 1.0.0 |
| 270 |
* @param Array $hidden hidden fields to add to cf7 form. |
| 271 |
* @return Array hidden fields to add to cf7 form. |
| 272 |
**/ |
| 273 |
public function add_hidden_fields($hidden){ |
| 274 |
$form = wpcf7_get_current_contact_form(); |
| 275 |
$post = get_post($form->id()); |
| 276 |
$hidden['_wpcf7_key'] = $post->post_name; |
| 277 |
$hidden['_cf7sg_toggles'] = ''; |
| 278 |
$hidden['_cf7sg_version'] = $this->version; |
| 279 |
return $hidden; |
| 280 |
} |
| 281 |
/** |
| 282 |
* Enqueue scripts requried for cf7 shortcode |
| 283 |
* hooked on 'do_shortcode_tag', |
| 284 |
* @since 1.0.0 |
| 285 |
**/ |
| 286 |
public function cf7_shortcode_request($output, $tag, $attr){ |
| 287 |
//if not a cf7 shortcode, then exit. |
| 288 |
if('contact-form-7' !== $tag){ |
| 289 |
return $output; |
| 290 |
} |
| 291 |
//wp_enqueue_script('contact-form-7'); //default cf7 plugin script. |
| 292 |
wp_enqueue_script('contact-form-7'); //default cf7 plugin script. |
| 293 |
$cf7_id = $attr['id']; |
| 294 |
//get the key |
| 295 |
$cf7post = get_post($cf7_id); |
| 296 |
$cf7_key = $cf7post->post_name; |
| 297 |
//load custom css/js script from theme css folder. |
| 298 |
$themepath = get_stylesheet_directory(); |
| 299 |
$themeuri = get_stylesheet_directory_uri(); |
| 300 |
if( file_exists($themepath.'/css/'.$cf7_key.'.css') ){ |
| 301 |
wp_enqueue_style( $cf7_key.'-css' , $themeuri.'/css/'.$cf7_key.'.css', array($this->plugin_name), null, 'all'); |
| 302 |
} |
| 303 |
if( file_exists($themepath.'/js/'.$cf7_key.'.js') ){ |
| 304 |
wp_enqueue_script( $cf7_key.'-js' , $themeuri.'/js/'.$cf7_key.'.js', array($this->plugin_name), null, true); |
| 305 |
do_action('smart_grid_register_custom_script', $cf7_key); |
| 306 |
} |
| 307 |
/** @since 3.0.0 load scripts only for required classes */ |
| 308 |
$class = get_post_meta($cf7_id, '_cf7sg_script_classes', true); |
| 309 |
if(empty($class)){ |
| 310 |
$class = array(); |
| 311 |
} |
| 312 |
//check classes required for sub-forms. |
| 313 |
$sub_forms = array(); |
| 314 |
$sub_form_keys = get_post_meta($cf7_id, '_cf7sg_sub_forms', true); |
| 315 |
if(!empty($sub_form_keys)){ |
| 316 |
$args = array( |
| 317 |
'post_type' => 'wpcf7_contact_form', |
| 318 |
'post_name__in' => $sub_form_keys |
| 319 |
); |
| 320 |
$sub_forms = get_posts($args); |
| 321 |
foreach($sub_forms as $form){ |
| 322 |
$sub_class = get_post_meta($form->ID, '_cf7sg_script_classes', true); |
| 323 |
if(!empty($sub_class)) $class = array_unique(array_merge($class, $sub_class)); |
| 324 |
} |
| 325 |
} |
| 326 |
//select2 |
| 327 |
if(array_search('has-select2',$class, true)!==false){ |
| 328 |
wp_enqueue_script('jquery-select2'); |
| 329 |
wp_enqueue_style('select2-style'); |
| 330 |
} |
| 331 |
//nice-select |
| 332 |
if(array_search('has-nice-select',$class, true)!==false){ |
| 333 |
wp_enqueue_script('jquery-nice-select'); |
| 334 |
wp_enqueue_style('jquery-nice-select-css'); |
| 335 |
} |
| 336 |
//benchmark |
| 337 |
if(array_search('has-benchmark',$class, true)!==false){ |
| 338 |
wp_enqueue_script('js-cf7sg-benchmarking'); |
| 339 |
} |
| 340 |
if(array_search('has-date',$class, true)!==false){ |
| 341 |
wp_enqueue_script('jquery-ui-datepicker'); |
| 342 |
wp_enqueue_style('cf7-jquery-ui'); |
| 343 |
} |
| 344 |
//cf7 plugin styles |
| 345 |
wp_enqueue_style('contact-form-7'); |
| 346 |
//cf7sg script & style. |
| 347 |
wp_enqueue_style($this->plugin_name); |
| 348 |
wp_enqueue_script($this->plugin_name); |
| 349 |
/** @since 2.6.0 disabled button message*/ |
| 350 |
$form = WPCF7_ContactForm::get_instance($cf7post); |
| 351 |
$messages = $form->prop('messages'); |
| 352 |
$this->localised_data = array( |
| 353 |
'url' => admin_url( 'admin-ajax.php' ), |
| 354 |
'submit_disabled'=> isset($messages['submit_disabled']) ? $messages['submit_disabled']: __( "Disabled! To enable, check the acceptance field.", 'cf7-grid-layout' ), |
| 355 |
'max_table_rows' => isset($messages['max_table_rows']) ? $messages['max_table_rows']: __( "You have reached the maximum number of rows.", 'cf7-grid-layout' ) |
| 356 |
); |
| 357 |
wp_localize_script( $this->plugin_name, 'cf7sg', $this->localise_script() ); |
| 358 |
//setup classes and id for wrapper. |
| 359 |
$css_id = apply_filters('cf7_smart_grid_form_id', 'cf7sg-form-'.$cf7_key, $attr); |
| 360 |
/** |
| 361 |
* @since 1.2.3 disable cf7sg styling/js for non-cf7sg forms. |
| 362 |
*/ |
| 363 |
$is_form = get_post_meta($cf7_id, '_cf7sg_managed_form', true); |
| 364 |
if(''===$is_form || !$is_form){ |
| 365 |
wp_enqueue_style('contact-form-7'); //default cf7 plugin css. |
| 366 |
do_action('smart_grid_enqueue_scripts', $cf7_key, $attr); |
| 367 |
$classes = implode(' ', $class) .' key_'.$cf7_key; |
| 368 |
$output = '<div class="cf7sg-container"><div id="' . $css_id . '" class="cf7-smart-grid ' . $classes . '">' . $output . '</div></div>'; |
| 369 |
return $output; |
| 370 |
} |
| 371 |
//load required dependencies for grid form. |
| 372 |
wp_enqueue_style('smart-grid'); |
| 373 |
wp_enqueue_style('dashicons'); |
| 374 |
|
| 375 |
//jquery accordion for collapsible rows. |
| 376 |
$has_section = array_search('has-accordion',$class, true) !==false; |
| 377 |
if($has_section){ |
| 378 |
wp_enqueue_script('jquery-ui-accordion'); |
| 379 |
} |
| 380 |
$has_tabs = array_search('has-tabs',$class, true) !==false; |
| 381 |
$has_tables = array_search('has-table',$class, true) !==false; |
| 382 |
$has_toggles = array_search('has-toggles',$class, true) !==false; |
| 383 |
|
| 384 |
$form_time = strtotime($cf7post->post_modified); |
| 385 |
if(!empty($sub_forms)){ |
| 386 |
$cf7_form = $form_raw = ''; |
| 387 |
foreach($sub_forms as $post_obj){ |
| 388 |
//check form saved date, if sub-form is newer, we need to udpate it. |
| 389 |
if(strtotime($post_obj->post_modified ) > $form_time){ |
| 390 |
if(empty($cf7_form)){ |
| 391 |
$form = WPCF7_ContactForm::get_instance($cf7_id); |
| 392 |
$form_raw = $cf7_form->prop( 'form' ); |
| 393 |
} |
| 394 |
$form_raw = $this->update_sub_form($form_raw, $post_obj); |
| 395 |
} |
| 396 |
} |
| 397 |
if(!empty($cf7_form)){ //redraw the form. |
| 398 |
$cf7_form = wpcf7_save_contact_form(array('id'=>$cf7_id, 'form'=>$form_raw)); |
| 399 |
//reload the form |
| 400 |
//$cf7_form = wpcf7_contact_form($cf7_id); |
| 401 |
$output = $cf7_form->form_html($attr); |
| 402 |
$class[]= 'has-update'; |
| 403 |
//actino for other plugin notification. |
| 404 |
do_action('cf7sg_subform_uddate',$cf7_id, $cf7_form, $attr ); |
| 405 |
} |
| 406 |
} |
| 407 |
//required for tables/tabs/accordion |
| 408 |
if($has_tabs || $has_tables || $has_toggles || $has_section){ |
| 409 |
wp_enqueue_script('jquery-effects-core'); |
| 410 |
} |
| 411 |
|
| 412 |
if($has_tabs || $has_toggles || $has_section){ |
| 413 |
wp_enqueue_style('cf7-jquery-ui-theme'); |
| 414 |
wp_enqueue_style('cf7-jquery-ui-structure'); |
| 415 |
wp_enqueue_style('cf7-jquery-ui'); |
| 416 |
} |
| 417 |
if($has_tabs) wp_enqueue_script('jquery-ui-tabs'); |
| 418 |
if($has_toggles){ |
| 419 |
wp_enqueue_script('jquery-toggles'); |
| 420 |
wp_enqueue_style('jquery-toggles-css'); |
| 421 |
wp_enqueue_style('jquery-toggles-light-css'); |
| 422 |
} |
| 423 |
//$cf7_key = get_post_meta($cf7_id, '_smart_grid_cf7_form_key', true); |
| 424 |
//allow custom script print |
| 425 |
do_action('smart_grid_enqueue_scripts', $cf7_key, $attr); |
| 426 |
|
| 427 |
$classes = implode(' ', $class) .' key_'.$cf7_key; |
| 428 |
$output = '<div class="cf7sg-container"><div id="' . $css_id . '" class="cf7-smart-grid ' . $classes . '">' . $output . '</div></div>'; |
| 429 |
return $output; |
| 430 |
} |
| 431 |
/** |
| 432 |
* Function hooked on 'cf7_2_post_form_values' to load toggle status for saed submissions |
| 433 |
* |
| 434 |
*@since 1.1.0 |
| 435 |
*@param string $post_id saved submission post ID |
| 436 |
*/ |
| 437 |
public function load_saved_toggled_status($field_values){ |
| 438 |
if(!isset($field_values['map_post_id']) || empty($field_values['map_post_id'])){ |
| 439 |
return $field_values; |
| 440 |
} |
| 441 |
$post_id = $field_values['map_post_id']; |
| 442 |
$toggles = get_post_meta($post_id, 'cf7sg_toggles_status', true); |
| 443 |
//debug_msg($toggles, $post_id.' status '); |
| 444 |
if(empty($toggles)) $toggles = array(); |
| 445 |
wp_enqueue_script($this->plugin_name); |
| 446 |
wp_localize_script( $this->plugin_name, 'cf7sg', $this->localise_script( array('toggles_status' => $toggles)) ); |
| 447 |
return $field_values; |
| 448 |
} |
| 449 |
/** |
| 450 |
* Single source for localised script. |
| 451 |
* |
| 452 |
*@since 2.6.0 |
| 453 |
*@param array $params additional parameter to send. |
| 454 |
*@return array data array to localise |
| 455 |
*/ |
| 456 |
private function localise_script($params=array()){ |
| 457 |
$this->localised_data += $params; |
| 458 |
return $this->localised_data; |
| 459 |
} |
| 460 |
/** |
| 461 |
* Update sub-forms in cf7 forms |
| 462 |
* Hooked to 'do_shortcode' |
| 463 |
* @since 1.0.0 |
| 464 |
* @param String $form_raw HTML form. |
| 465 |
* @param WP_Post $sub_form_post CF7 sub-form post object. |
| 466 |
* @return String HTML for new form. |
| 467 |
**/ |
| 468 |
public function update_sub_form($form_raw, $sub_form_post){ |
| 469 |
//Create a new DOM document |
| 470 |
$cf7_key = $sub_form_post->post_name; |
| 471 |
$sub_form_raw = get_post_meta($sub_form_post->ID, '_form', true); |
| 472 |
//PHP DOM plugin. |
| 473 |
/** @since 3.2.0 use Simple HTML Dom library */ |
| 474 |
require_once plugin_dir_path( __DIR__ ) . 'assets/simple-html-dom/autoload.php'; |
| 475 |
|
| 476 |
$dom = HtmlDomParser::str_get_html($form_raw); |
| 477 |
//reset the inner form. |
| 478 |
$element = $dom->find('#cf7sg-form-'.$cf7_key); |
| 479 |
|
| 480 |
$element[0]->innertext = $sub_form_raw; |
| 481 |
|
| 482 |
return $dom->outertext; |
| 483 |
} |
| 484 |
/** |
| 485 |
* Function to load custom js script for Post My CF7 Form loading of form field values |
| 486 |
* Hooked to 'cf7_2_post_echo_field_mapping_script' |
| 487 |
* @since 1.0.0 |
| 488 |
* @param boolean $default_script whether to use the default script or not, default is true. |
| 489 |
* @param string $field cf7 form field name |
| 490 |
* @param string $type field type (number, text, select...) |
| 491 |
* @param string $json_value the json value loaded for this field in the form. |
| 492 |
* @param string $$js_form the javascript variable in which the form is loaded. |
| 493 |
* @return boolean false to print a custom script from the called function, true for the default script printed by this plugin. |
| 494 |
**/ |
| 495 |
public function load_tabs_table_field($default_script, $post_id, $field, $type, $json_value, $js_form){ |
| 496 |
$grid = self::field_type($field, $post_id); |
| 497 |
switch($grid){ |
| 498 |
case 'tab': |
| 499 |
case 'table': |
| 500 |
case 'both': |
| 501 |
include( plugin_dir_path( __FILE__ ) . '/partials/cf7sg-field-load-script.php'); |
| 502 |
$default_script = false; |
| 503 |
break; |
| 504 |
default: |
| 505 |
break; |
| 506 |
} |
| 507 |
return $default_script; |
| 508 |
} |
| 509 |
/** |
| 510 |
* Register a [save] shortcode with CF7. |
| 511 |
* Hooked on 'wpcf7_init' |
| 512 |
* This function registers a callback function to expand the shortcode for the save button field. |
| 513 |
* @since 2.0.0 |
| 514 |
*/ |
| 515 |
public function register_cf7_shortcode() { |
| 516 |
if( function_exists('wpcf7_add_form_tag') ) { |
| 517 |
//dynamic select |
| 518 |
wpcf7_add_form_tag( |
| 519 |
array( 'dynamic_select', 'dynamic_select*' ), |
| 520 |
array($this,'cf7_taxonomy_shortcode'), |
| 521 |
true //has name |
| 522 |
); |
| 523 |
//benchmark |
| 524 |
wpcf7_add_form_tag( |
| 525 |
array( 'benchmark', 'benchmark*' ), |
| 526 |
array($this,'cf7_benchmark_shortcode'), |
| 527 |
true //has name |
| 528 |
); |
| 529 |
} |
| 530 |
} |
| 531 |
/** |
| 532 |
* Register a [benchmark] shortcode with CF7. |
| 533 |
* called by funciton above |
| 534 |
* This function registers a callback function to expand the shortcode for the googleMap form fields. |
| 535 |
* @since 1.0.0 |
| 536 |
* @param strng $tag the tag name designated in the tag help screen |
| 537 |
* @return string a set of html fields to capture the googleMap information |
| 538 |
*/ |
| 539 |
|
| 540 |
public function cf7_benchmark_shortcode($tag){ |
| 541 |
$tag = new WPCF7_FormTag( $tag ); |
| 542 |
wp_enqueue_script('js-cf7sg-benchmarking'); |
| 543 |
wp_enqueue_style( 'cf7-benchmark-css' ); |
| 544 |
ob_start(); |
| 545 |
include( plugin_dir_path( __FILE__ ) . '/partials/cf7-benchmark-tag.php'); |
| 546 |
$html = ob_get_contents (); |
| 547 |
ob_end_clean(); |
| 548 |
$this->update_form_classes('has-benchmark'); |
| 549 |
return $html; |
| 550 |
} |
| 551 |
/** |
| 552 |
* Register a [dynamic_display] shortcode with CF7. |
| 553 |
* called by funciton above |
| 554 |
* This function registers a callback function to expand the shortcode for the googleMap form fields. |
| 555 |
* @since 1.0.0 |
| 556 |
* @param strng $tag the tag name designated in the tag help screen |
| 557 |
* @return string a set of html fields to capture the googleMap information |
| 558 |
*/ |
| 559 |
|
| 560 |
public function cf7_taxonomy_shortcode($tag){ |
| 561 |
$tag = new WPCF7_FormTag( $tag ); |
| 562 |
$source = self::get_dynamic_drodown_attributes($tag); |
| 563 |
ob_start(); |
| 564 |
include( plugin_dir_path( __FILE__ ) . '/partials/cf7-taxonomy-tag-display.php'); |
| 565 |
$html = ob_get_contents (); |
| 566 |
ob_end_clean(); |
| 567 |
return $html; |
| 568 |
} |
| 569 |
/** |
| 570 |
* |
| 571 |
* |
| 572 |
* @since 1.0.0 |
| 573 |
* @param mixed $class array of classes or string to set class for form and dependency loading . |
| 574 |
* @param Object $cf7_form cf7 post id against which set the c$lass . |
| 575 |
**/ |
| 576 |
public function update_form_classes($class, $cf7_id=null){ |
| 577 |
if(empty($cf7_id)){ |
| 578 |
//get latest form |
| 579 |
if(function_exists('wpcf7_get_current_contact_form')){ |
| 580 |
$cf7_form = wpcf7_get_current_contact_form(); |
| 581 |
if(!empty($cf7_form)) $cf7_id = $cf7_form->id(); |
| 582 |
} |
| 583 |
} |
| 584 |
if(empty($cf7_id)){ |
| 585 |
debug_msg('Unable to get Contact Form 7 ID to set class: '.$class); |
| 586 |
return; |
| 587 |
} |
| 588 |
$classes = get_post_meta($cf7_id, '_cf7sg_classes', true); |
| 589 |
if(empty($classes)){ |
| 590 |
$classes = array(); |
| 591 |
} |
| 592 |
if(is_array($class)){ |
| 593 |
foreach($class as $class_name){ |
| 594 |
$classes[$class_name] = true; |
| 595 |
} |
| 596 |
}else{ |
| 597 |
$classes[$class] = true; |
| 598 |
} |
| 599 |
update_post_meta($cf7_id, '_cf7sg_classes', $classes); |
| 600 |
return; |
| 601 |
} |
| 602 |
/** |
| 603 |
* Function to save ajax submitted grid fields, grid fields are any input/select fields used in the table/tabs constructs |
| 604 |
* hooked on wp_ajax_nopriv_save_grid_fields and wp_ajax_save_grid_fields. The ajax is only fired in case a sub-form has been updated. |
| 605 |
* @since 1.0.0 |
| 606 |
**/ |
| 607 |
public function save_grid_fields(){ |
| 608 |
if( !isset($_POST['nonce']) ){ |
| 609 |
wp_send_json_error(array('message'=>'nonce failed')); |
| 610 |
wp_die(); |
| 611 |
} |
| 612 |
$cf7_id = sanitize_text_field($_POST['id']); |
| 613 |
|
| 614 |
if(!wpcf7_verify_nonce($_POST['nonce'], $cf7_id)){ |
| 615 |
wp_send_json_error(array('message'=>'nonce failed')); |
| 616 |
wp_die(); |
| 617 |
} |
| 618 |
|
| 619 |
if(isset($_POST['tabs_fields']) && isset($_POST['table_fields'])){ |
| 620 |
$tabs_fields = json_decode(stripslashes($_POST['tabs_fields'])); |
| 621 |
if(empty($tabs_fields)) $tabs_fields = array(); |
| 622 |
if(!is_array($tabs_fields)) $tabs_fields = array($tabs_fields); |
| 623 |
//validate each field name as text, sanitize. |
| 624 |
$sanitised_tab_fields = array(); |
| 625 |
foreach($tabs_fields as $field){ |
| 626 |
$sanitised_tab_fields[] = sanitize_text_field($field); |
| 627 |
} |
| 628 |
$table_fields = json_decode(stripslashes($_POST['table_fields'])); |
| 629 |
if(empty($table_fields)) $table_fields = array(); |
| 630 |
if(!is_array($table_fields)) $table_fields = array($table_fields); |
| 631 |
$sanitised_table_fields = array(); |
| 632 |
foreach($table_fields as $field){ |
| 633 |
$sanitised_table_fields[] = sanitize_text_field($field); |
| 634 |
} |
| 635 |
//debug_msg($grid_fields, $cf7_id); |
| 636 |
update_post_meta($cf7_id, '_cf7sg_grid_tabs_names', $sanitised_tab_fields); |
| 637 |
update_post_meta($cf7_id, '_cf7sg_grid_table_names', $sanitised_table_fields); |
| 638 |
wp_send_json_success(array('message'=>'saved fields')); |
| 639 |
}else{ |
| 640 |
wp_send_json_error(array('message'=>'no data received')); |
| 641 |
} |
| 642 |
wp_die(); |
| 643 |
} |
| 644 |
/** |
| 645 |
* This function filters submitted data and consolidates grid field values into arrays. |
| 646 |
* Function hooked on 'wpcf7_posted_data' |
| 647 |
* @since 1.0.0 |
| 648 |
* @param Array $data unvalidated submitted data. |
| 649 |
* @return Array filtered submitted data. |
| 650 |
**/ |
| 651 |
public function setup_grid_values($data){ |
| 652 |
$cf7form = WPCF7_ContactForm::get_current(); |
| 653 |
if(empty($cf7form) ){ |
| 654 |
if(isset($_POST['_wpcf7']) ){ |
| 655 |
$cf7_id = $_POST['_wpcf7']; |
| 656 |
$cf7form = WPCF7_ContactForm::get_instance($cf7_id); |
| 657 |
if(empty($cf7form) ){ |
| 658 |
debug_msg("CF7SG ERROR: fn setup_grid_values() is unable to load submitted form"); |
| 659 |
return $data; |
| 660 |
} |
| 661 |
} |
| 662 |
} |
| 663 |
$cf7_id = $cf7form->id(); |
| 664 |
$this->form_id = $cf7_id; |
| 665 |
//debug_msg($grid_fields, 'grid fields...'); |
| 666 |
$tags = $cf7form->scan_form_tags(); |
| 667 |
foreach($tags as $tag){ |
| 668 |
$field_name = $tag['name']; |
| 669 |
$field_type = self::field_type($field_name, $cf7_id); |
| 670 |
switch($field_type){ |
| 671 |
case 'tab': |
| 672 |
case 'table': |
| 673 |
case 'both': |
| 674 |
// the $data array is passed by reference and will be consolidated. |
| 675 |
/** @since 2.5.0 */ |
| 676 |
if( isset($_POST['_cf7sg_version']) && version_compare($_POST['_cf7sg_version'],'2.5.0','>=') ){ |
| 677 |
$this->consolidate_grid_submissions_v2($tag, $field_type, $data); |
| 678 |
}else{ |
| 679 |
$this->consolidate_grid_submissions($field_name, $field_type, $data); |
| 680 |
} |
| 681 |
break; |
| 682 |
default: |
| 683 |
$toggle = $this->get_toggle($field_name); |
| 684 |
if('unit-contact' ==$field_name) debug_msg($toggle, 'unit contact toggle '); |
| 685 |
if(!empty($toggle)) $data[$field_name] = $this->is_submitted($toggle) ? $this->get_field_value($field_name,$field_type) : null; |
| 686 |
else $data[$field_name]= $this->get_field_value($field_name, $tag['basetype']); |
| 687 |
break; |
| 688 |
} |
| 689 |
} |
| 690 |
return $data; |
| 691 |
} |
| 692 |
/** |
| 693 |
* new function to consolidate submitted data for improved handling of optional toggled fields as well as special fields such as files and checkboxes in tabbed sectoins. |
| 694 |
* |
| 695 |
*@since 2.5.0 |
| 696 |
*@param array $field_tag a cf7 form field tag which is part of tabs or table grid section. |
| 697 |
*@param array $type field type, should be 'tab'/'table'/'both'. |
| 698 |
*@param array $data cf7 form submissed data passed by reference as consolidated grid values will be removed and the original field value replaced with an array. |
| 699 |
*@return array a filtered array of $index_suffix=>$value pairs for tabs or rows fields, The index suffix is '.row-<index>' for tables and '.tab-<index>' for tabs. This method returns a 2 dimensional array for fields which are both within rowns and tabs. The 2 dimensional array will list [<tab_suffix>][<row_suffix>]=>$value. The original field name that was submitted can be reconstructed as $field_name.$index_suffix. The first field will have an empty string as its $index_suffix. |
| 700 |
*/ |
| 701 |
private function consolidate_grid_submissions_v2($field_tag, $type, &$data){ |
| 702 |
//get_post_meta($post_id, '_cf7sg_has_tables', true); |
| 703 |
if(isset($_POST['_wpcf7']) ) $cf7_id = $_POST['_wpcf7']; |
| 704 |
else{ |
| 705 |
debug_msg("CF7SG ERROR: fn consolidate_grid_submissions_v2() is unable to load submitted form"); |
| 706 |
} |
| 707 |
$field_name = $field_tag['name']; |
| 708 |
$field_type = $field_tag['basetype']; |
| 709 |
$origin = self::$array_grid_fields[$cf7_id][$field_name]; |
| 710 |
$values = array(); |
| 711 |
$regex = ''; |
| 712 |
$submitted_fields=array(); |
| 713 |
$max_fields =0; |
| 714 |
$purge_fields=array(); |
| 715 |
$toggle = $this->get_toggle($field_name); |
| 716 |
switch($type){ |
| 717 |
case 'tab': |
| 718 |
case 'table': |
| 719 |
$index_suffix = ('table'==$type)?'_row-':'_tab-'; |
| 720 |
//find the number of rows submitted. |
| 721 |
$max_fields = isset($_POST[$origin]) ? $_POST[$origin]:0; |
| 722 |
if(!empty($toggle)){ //check if submitted. |
| 723 |
$values[''] = $this->is_submitted($toggle) ? $this->get_field_value($field_name,$field_type) : null; |
| 724 |
}else $values['']= $this->get_field_value($field_name,$field_type); |
| 725 |
|
| 726 |
for($idx=1;$idx<$max_fields;$idx++){ |
| 727 |
$fid=$index_suffix.$idx; |
| 728 |
if(!empty($toggle)){ //check if submitted. |
| 729 |
$toggle_id = $toggle; /** @since 3.3.5 track toggles in tabs*/ |
| 730 |
if($this->is_tabbed($toggle)) $toggle_id = $toggle.$fid; |
| 731 |
$values[$fid] = $this->is_submitted($toggle_id) ? $this->get_field_value($field_name.$fid,$field_type) : null; |
| 732 |
}else $values[$fid] = $this->get_field_value($field_name.$fid,$field_type); |
| 733 |
$purge_fields[$field_name.$fid] = true; |
| 734 |
} |
| 735 |
break; |
| 736 |
case 'both': |
| 737 |
$origins = explode(':', $origin); |
| 738 |
$table_origin = $origins[0]; |
| 739 |
$tab_origin = $origins[1]; |
| 740 |
$max_tabs = isset($_POST[$tab_origin])?$_POST[$tab_origin]:0; |
| 741 |
$values[''] = array(); //init multi-dimensional array |
| 742 |
if(!empty($toggle)){ //check if submitted, tab<-toggle<-table. |
| 743 |
$values[''][''] = $this->is_submitted($toggle) ? $this->get_field_value($field_name,$field_type) : null; |
| 744 |
}else $values[''][''] = $this->get_field_value($field_name,$field_type); |
| 745 |
|
| 746 |
for($idx=0;$idx<$max_tabs;$idx++){ //tables in other tabs. |
| 747 |
$max_fields = ($idx>0) ? $_POST[$table_origin.'_tab-'.$idx]:$_POST[$table_origin]; |
| 748 |
$tab_suffix= ($idx>0)? '_tab-'.$idx:''; |
| 749 |
for($jdx=0;$jdx<$max_fields;$jdx++){ |
| 750 |
$row_suffix= ($jdx>0)?'_row-'.$jdx:''; |
| 751 |
$fid = $tab_suffix.$row_suffix; |
| 752 |
if(!empty($toggle)){ //check if submitted, tab<-toggle<-table. |
| 753 |
$toggle_id = $toggle; /** @since 3.3.5 track toggles in tabs*/ |
| 754 |
if($this->is_tabbed($toggle)) $toggle_id = $toggle.$tab_suffix; |
| 755 |
$values[$tab_suffix][$row_suffix] = $this->is_submitted($toggle_id) ? $this->get_field_value( $field_name.$fid, $field_type):null; |
| 756 |
}else $values[$tab_suffix][$row_suffix] = $this->get_field_value($field_name.$fid, $field_type); |
| 757 |
$purge_fields[$field_name.$fid] = true; //remove from the origina $data. |
| 758 |
} |
| 759 |
} |
| 760 |
break; |
| 761 |
} |
| 762 |
//debug_msg($purge_fields, 'purging '); |
| 763 |
//debug_msg($data); |
| 764 |
$data = array_udiff_uassoc($data, $purge_fields, function($a, $b){return 0;}, function($a, $b){ |
| 765 |
if ($a === $b) return 0; |
| 766 |
return ($a > $b)? 1:-1; |
| 767 |
}); //this will remove all the surplus fields |
| 768 |
$data[$field_name] = $values; |
| 769 |
return $values; |
| 770 |
} |
| 771 |
/** |
| 772 |
* Extract either a file name or a field value |
| 773 |
* |
| 774 |
*@since 2.5.0 |
| 775 |
*@param array $data submitted data. |
| 776 |
*@return string text_description |
| 777 |
*/ |
| 778 |
private function get_field_value($field_name, $field_type){ |
| 779 |
$value = ''; |
| 780 |
if('file' == $field_type) { |
| 781 |
$value = isset($_FILES[$field_name]) ? $_FILES[$field_name]['name']:''; |
| 782 |
}else{ |
| 783 |
$value = isset($_POST[$field_name]) ? $_POST[$field_name]:''; |
| 784 |
} |
| 785 |
return $value; |
| 786 |
} |
| 787 |
/** |
| 788 |
* function returns an array of fields as keys and value which are eitehr 'tab' or 'table', or 'both'. |
| 789 |
* |
| 790 |
* @since 1.0.0 |
| 791 |
* @param string $form_id form id for which to return fields. |
| 792 |
* @return array empty array if no fields found.. |
| 793 |
**/ |
| 794 |
static public function get_grid_fields($form_id){ |
| 795 |
if(isset(self::$array_grid_fields[$form_id])){ |
| 796 |
return self::$array_grid_fields[$form_id]; |
| 797 |
} |
| 798 |
$grid_fields = array(); |
| 799 |
//tables |
| 800 |
$fields = get_post_meta($form_id , '_cf7sg_grid_table_names', true); |
| 801 |
if(!empty($fields)){ |
| 802 |
if( is_array( $fields[key($fields)] ) ){ |
| 803 |
foreach($fields as $table=>$table_fields) $grid_fields += array_fill_keys($table_fields, $table); |
| 804 |
}else $grid_fields += array_fill_keys($fields, 'cf7-sg-table-000'); |
| 805 |
} |
| 806 |
//tabs |
| 807 |
$fields = get_post_meta($form_id , '_cf7sg_grid_tabs_names', true); |
| 808 |
if(!empty($fields)){ |
| 809 |
if(is_array( $fields[key( $fields)] ) ){ /** @since 2.4.2 */ |
| 810 |
foreach($fields as $tab=>$tab_fields){ |
| 811 |
foreach($tab_fields as $field){ |
| 812 |
if(isset($grid_fields[$field])) $grid_fields[$field] = $grid_fields[$field].':'.$tab; |
| 813 |
else $grid_fields[$field] = $tab; |
| 814 |
} |
| 815 |
} |
| 816 |
}else{ |
| 817 |
foreach($fields as $field){ |
| 818 |
if(isset($grid_fields[$field])) $grid_fields[$field] = $grid_fields[$field].':'.$tab; |
| 819 |
else $grid_fields[$field] = 'cf7-sg-tab-000'; |
| 820 |
} |
| 821 |
} |
| 822 |
} |
| 823 |
$subform_keys = get_post_meta($form_id, '_cf7sg_sub_forms', true); |
| 824 |
if(!empty($subform_keys)){ |
| 825 |
foreach($subform_keys as $cf7Key){ |
| 826 |
$post_id = get_cf7form_id($cf7Key); |
| 827 |
$grid_fields += self::get_grid_fields($post_id); |
| 828 |
} |
| 829 |
} |
| 830 |
self::$array_grid_fields[$form_id]=$grid_fields; |
| 831 |
//load panel fields. |
| 832 |
self::$array_toggled_panels[$form_id]=array(); |
| 833 |
if( isset($_POST['_cf7sg_version']) && version_compare($_POST['_cf7sg_version'],'2.5.0','>=') ){ |
| 834 |
$toggled_panels = array(); |
| 835 |
if(isset($_POST['_cf7sg_toggles'])){ |
| 836 |
$toggled_panels = json_decode( stripslashes($_POST['_cf7sg_toggles'])); |
| 837 |
if(!empty($toggled_panels)) $toggled_panels = get_object_vars($toggled_panels); |
| 838 |
else $toggled_panels = array(); |
| 839 |
} |
| 840 |
self::$array_toggled_panels[$form_id]=$toggled_panels; |
| 841 |
|
| 842 |
$fields = get_post_meta($form_id, '_cf7sg_grid_toggled_names', true); |
| 843 |
self::$array_toggle_fields[$form_id]=array(); |
| 844 |
if(!empty($fields)){ |
| 845 |
foreach($fields as $panel=>$pfields){ |
| 846 |
foreach($pfields as $field) self::$array_toggle_fields[$form_id][$field]=$panel; |
| 847 |
} |
| 848 |
} |
| 849 |
} |
| 850 |
/** @since 3.3.5 tack toggle in tabs */ |
| 851 |
self::$array_toggle_in_tabs=array(); |
| 852 |
if( isset($_POST['_cf7sg_version']) && version_compare($_POST['_cf7sg_version'],'3.3.5','>=') ){ |
| 853 |
$toggles_in_tabs = get_post_meta($form_id, '_cf7sg_grid_toggle_in_tabs', true); |
| 854 |
if(!empty($toggles_in_tabs)) self::$array_toggle_in_tabs = array_fill_keys($toggles_in_tabs,true); |
| 855 |
} |
| 856 |
return $grid_fields; |
| 857 |
} |
| 858 |
/** |
| 859 |
* Consolidates submitted data from table and tab fields into arrays. |
| 860 |
* |
| 861 |
*@since 1.0.0 |
| 862 |
*@param string $field_name a cf7 form field name which is part of tabs or table grid section. |
| 863 |
*@param array $type field type, should be 'tab'/'table'/'both'. |
| 864 |
*@param array $data cf7 form submissed data passed by reference as consolidated grid values will be removed and the original field value replaced with an array. |
| 865 |
*@return array a filtered array of $index_suffix=>$value pairs for tabs or rows fields, The index suffix is '.row-<index>' for tables and '.tab-<index>' for tabs. This method returns a 2 dimensional array for fields which are both within rowns and tabs. The 2 dimensional array will list [<tab_suffix>][<row_suffix>]=>$value. The original field name that was submitted can be reconstructed as $field_name.$index_suffix. The first field will have an empty string as its $index_suffix. |
| 866 |
*/ |
| 867 |
private function consolidate_grid_submissions($field_name, $type, &$data){ |
| 868 |
$cf7_key = ''; |
| 869 |
if(isset($_POST['_wpcf7_key'])) $cf7_key = $_POST['_wpcf7_key']; |
| 870 |
$cf7_id = 0; |
| 871 |
if(isset($_POST['_wpcf7'])) $cf7_id = $_POST['_wpcf7']; |
| 872 |
$values = array(); |
| 873 |
$regex = ''; |
| 874 |
$submitted_fields=array(); |
| 875 |
$max_fields =0; |
| 876 |
$purge_fields=array(); |
| 877 |
switch($type){ |
| 878 |
case 'table': |
| 879 |
$index_suffix = '_row-'; |
| 880 |
$regex = '/^'.preg_quote($field_name).'_row-[0-9]+$/'; |
| 881 |
$values['']=$data[$field_name]; |
| 882 |
//extract all relevant fields |
| 883 |
$submitted_fields = preg_grep($regex, array_keys($data)); |
| 884 |
$max_fields = sizeof($submitted_fields); |
| 885 |
break; |
| 886 |
case 'tab': |
| 887 |
$index_suffix = '_tab-'; |
| 888 |
$regex = '/^'.preg_quote($field_name).'_tab-[0-9]+$/'; |
| 889 |
$values['']=$data[$field_name]; |
| 890 |
//extract all relevant fields |
| 891 |
$submitted_fields = preg_grep($regex, array_keys($data)); |
| 892 |
foreach($submitted_fields as $field){ |
| 893 |
$idx = 1.0 * str_replace($field_name.'_tab-', '', $field); |
| 894 |
if($max_fields < $idx) $max_fields = $idx; |
| 895 |
} |
| 896 |
break; |
| 897 |
case 'both': |
| 898 |
$regex = '/^'.preg_quote($field_name); |
| 899 |
$values[''] = array(); //init multi-dimensional array |
| 900 |
if(isset($data[$field_name])){ |
| 901 |
$values[''][''] = $data[$field_name]; |
| 902 |
}else{ |
| 903 |
$values[''][''] = null; |
| 904 |
} |
| 905 |
//extract all relevant fields |
| 906 |
$submitted_fields = preg_grep($regex.'_tab-[0-9]+_row-[0-9]+$/', array_keys($data)); |
| 907 |
//we also need the rows with tab index=0 |
| 908 |
$submitted_fields += preg_grep($regex.'_row-[0-9]+$/', array_keys($data)); |
| 909 |
//.. and tabs with row index=0 |
| 910 |
$submitted_fields += preg_grep($regex.'_tab-[0-9]+$/', array_keys($data)); |
| 911 |
//if('other-rm-qty'==$field_name){ |
| 912 |
// debug_msg($submitted_fields, 'Found fields '.$field_name); |
| 913 |
//} |
| 914 |
$max_fields = sizeof($submitted_fields); |
| 915 |
break; |
| 916 |
} |
| 917 |
|
| 918 |
$row_idx=1; //[0][0] already set above is this is tab table field |
| 919 |
$tab_idx=0; |
| 920 |
$error_loop=false; |
| 921 |
$loop_counter_limit = apply_filters('cf7sg_set_max_tabs_limit', 10, $cf7_key, $cf7_id); |
| 922 |
for($idx=1; ($idx <= $max_fields && !$error_loop); $idx++){ |
| 923 |
switch($type){ |
| 924 |
case 'table': |
| 925 |
case 'tab': |
| 926 |
if(!isset($data[$field_name.$index_suffix.$idx])){ |
| 927 |
/** |
| 928 |
*assuming this field was not submitted as it was disabled, hence set to null. |
| 929 |
* @since 1.0.0 |
| 930 |
*/ |
| 931 |
$values[$index_suffix.$idx] = null; |
| 932 |
}else{ |
| 933 |
$values[$index_suffix.$idx] = $data[$field_name.$index_suffix.$idx]; |
| 934 |
$purge_fields[$field_name.$index_suffix.$idx] = true; |
| 935 |
} |
| 936 |
break; |
| 937 |
case 'both': |
| 938 |
//first attempt to look for the frist tab rows |
| 939 |
$row_suffix = ($row_idx>0)?'_row-'.$row_idx:''; |
| 940 |
$tab_suffix = ($tab_idx>0)?'_tab-'.$tab_idx:''; |
| 941 |
//if('other-rm-qty'==$field_name){ |
| 942 |
// debug_msg($idx.'Looking for: '.$field_name.$tab_suffix.$row_suffix); |
| 943 |
//} |
| 944 |
if(isset($data[$field_name.$tab_suffix.$row_suffix])){ |
| 945 |
$values[$tab_suffix][$row_suffix] = $data[$field_name.$tab_suffix.$row_suffix]; |
| 946 |
$purge_fields[$field_name.$tab_suffix.$row_suffix] = true; |
| 947 |
//next loop, look for the next row within the same tab, |
| 948 |
$row_idx +=1; |
| 949 |
}else{ |
| 950 |
|
| 951 |
$loop_counter=$tab_idx; |
| 952 |
$loop = true; |
| 953 |
do{//move to next tab, and reset the row counter |
| 954 |
// debug_msg('loop:'.$loop_counter.', max: '.$loop_counter_limit); |
| 955 |
$loop_counter +=1; |
| 956 |
if($loop_counter > $loop_counter_limit) $error_loop=true; |
| 957 |
$tab_idx +=1; |
| 958 |
$row_idx = 0; |
| 959 |
$row_suffix = ''; |
| 960 |
$tab_suffix = '_tab-'.$tab_idx; |
| 961 |
//init new tab row values array |
| 962 |
$values[$tab_suffix] = array(); |
| 963 |
//keep looking for next tab if we don't find a value; |
| 964 |
/** |
| 965 |
*if the frist row is not submitted then this may be in a toggled section which has been disabled. |
| 966 |
* but we still need to keep looking for values in other tabs. |
| 967 |
*@since 1.1.0 |
| 968 |
*/ |
| 969 |
$values[$tab_suffix][$row_suffix] = null; |
| 970 |
$loop = !isset($data[$field_name.$tab_suffix.$row_suffix]) && !$error_loop; |
| 971 |
}while($loop); |
| 972 |
if(!$error_loop) { |
| 973 |
$values[$tab_suffix][$row_suffix] = $data[$field_name.$tab_suffix.$row_suffix]; |
| 974 |
$purge_fields[$field_name.$tab_suffix.$row_suffix] = true; |
| 975 |
$row_idx +=1; //next loop, keep searching in thsi tab. |
| 976 |
}else{ |
| 977 |
debug_msg($submitted_fields, 'CF7SG ERROR: Reached max tabs search loop for table field '.$field_name.' (cannot find any new rows above tab '.$tab_idx.' therefor abandoning search for remaining '.(sizeof($submitted_fields)-$idx).' regex match in preg_grep result array listed below)'); |
| 978 |
//for loop will end here |
| 979 |
} |
| 980 |
} |
| 981 |
break; |
| 982 |
}//end switch. |
| 983 |
}//end for loop preg_grep array. |
| 984 |
if(!$error_loop){ |
| 985 |
//debug_msg($purge_fields, 'purging '); |
| 986 |
//debug_msg($data); |
| 987 |
$data = array_udiff_uassoc($data, $purge_fields, function($a, $b){return 0;}, function($a, $b){ |
| 988 |
if ($a === $b) return 0; |
| 989 |
return ($a > $b)? 1:-1; |
| 990 |
}); //this will remove all the surplus fields |
| 991 |
$data[$field_name] = $values; |
| 992 |
} |
| 993 |
return $values; |
| 994 |
} |
| 995 |
/** |
| 996 |
* Validates required benchmark and dynamic_select tags |
| 997 |
* |
| 998 |
* @since 1.0.0 |
| 999 |
* @param WPCF7_Validation $result validation object |
| 1000 |
* @param Array $tag an array of cf7 tag attributes and values |
| 1001 |
* @return WPCF7_Validation validation result |
| 1002 |
**/ |
| 1003 |
public function validate_required($result, $tag){ |
| 1004 |
if(!isset( $_POST[$tag->name] ) ){ |
| 1005 |
return $result; //not submitted hence disabled. |
| 1006 |
} |
| 1007 |
$tag = new WPCF7_FormTag( $tag ); |
| 1008 |
|
| 1009 |
$name = $tag->name; |
| 1010 |
$value = isset( $_POST[$name] ) |
| 1011 |
? trim( strtr( (string) sanitize_text_field($_POST[$name]), "\n", " " ) ): ''; |
| 1012 |
|
| 1013 |
if ( $tag->is_required() && '' == $value ) { |
| 1014 |
$result->invalidate( $tag, wpcf7_get_message( 'invalid_required' ) ); |
| 1015 |
} |
| 1016 |
return $result; |
| 1017 |
} |
| 1018 |
|
| 1019 |
/** |
| 1020 |
* Final validation with all values submitted for inter dependent validation |
| 1021 |
* Hooked to filter 'wpcf7_validate', sets up the final $result object |
| 1022 |
* @since 1.0.0 |
| 1023 |
* @param WPCF7_Validation $result validation object |
| 1024 |
* @param Array $tags an array of cf7 tag used in this form |
| 1025 |
* @return WPCF7_Validation validation result |
| 1026 |
**/ |
| 1027 |
public function filter_wpcf7_validate($result, $tags){ |
| 1028 |
/** @since 3.3.3 fix for captch field validation*/ |
| 1029 |
$invalids = $result->get_invalid_fields(); |
| 1030 |
/** |
| 1031 |
*@since 1.1.0 |
| 1032 |
*reset the validation result. |
| 1033 |
* this is required to dynamically disable required form fields & stop their validation. |
| 1034 |
* Disabled fields are not submitted but CF7 forces their values to empty and therefore flags requried fields as invalid at submission even if they are disabled. |
| 1035 |
* this bug was reported in the cf7 support forum: |
| 1036 |
* https://wordpress.org/support/topic/bug-javascript-disabled-fields-flagged-as-invalid/ |
| 1037 |
**/ |
| 1038 |
$result = new WPCF7_Validation(); |
| 1039 |
|
| 1040 |
//rebuild the default validation result. |
| 1041 |
$cf7form = WPCF7_ContactForm::get_current(); |
| 1042 |
$tags = $cf7form->scan_form_tags(); |
| 1043 |
$submitted = WPCF7_Submission::get_instance(); |
| 1044 |
$data = $submitted->get_posted_data(); |
| 1045 |
$tag_types = array(); //store all form tags, including cloned tags for array fields. |
| 1046 |
|
| 1047 |
/** @since 3.1.3 allow validation of unvalidated data in custom validation filter */ |
| 1048 |
$validation = array(); //holds all the validation messages. |
| 1049 |
$validated = array(); |
| 1050 |
$submission = array(); |
| 1051 |
/** |
| 1052 |
*@since 2.1.0 fix issue with Conditional Field plugin. |
| 1053 |
*/ |
| 1054 |
$data = $this->remove_hidden_fields_from_conditional_plugin($data); |
| 1055 |
$toggle_status = ''; |
| 1056 |
if(isset($_POST['_cf7sg_toggles'])){ |
| 1057 |
$toggle_status = json_decode( stripslashes($_POST['_cf7sg_toggles'])); |
| 1058 |
} |
| 1059 |
/** @since 2.5.0 new data consolidation enables simpler validation */ |
| 1060 |
$deprecated = true; //check if the form being submitted was created with an older version of the plugin. |
| 1061 |
if( isset($_POST['_cf7sg_version']) && version_compare($_POST['_cf7sg_version'],'2.5.0','>=') ){ |
| 1062 |
$deprecated = false; |
| 1063 |
} |
| 1064 |
foreach ( $tags as $tag ) { |
| 1065 |
//debug_msg($data); |
| 1066 |
if($deprecated){ |
| 1067 |
/** |
| 1068 |
* @since 2.1.5 fix validation of non-toggled checkox/radio. Toggled fields are now tracked in the tag itself as a class. |
| 1069 |
*/ |
| 1070 |
if(!isset($_POST[$tag['name']])){ |
| 1071 |
$isRequired = false; |
| 1072 |
switch($tag['type']){ |
| 1073 |
case 'checkbox*': |
| 1074 |
case 'radio': |
| 1075 |
case 'file*': /** @since 2.3.1 fix as file field has no values in $_POST.*/ |
| 1076 |
$isRequired = true; |
| 1077 |
$tag_options = $tag->options; |
| 1078 |
if(empty($tag_options)) break; //break from switch, not toggled, we need to validate. |
| 1079 |
$toggle=''; |
| 1080 |
foreach($tag_options as $option){ |
| 1081 |
$match = array(); |
| 1082 |
preg_match('/class:cf7sg-toggle-(.[^\s]+)/i',$option, $match); |
| 1083 |
if(!empty($match)){ |
| 1084 |
$toggle=$match[1]; |
| 1085 |
break; //break fromeach loop. |
| 1086 |
} |
| 1087 |
} |
| 1088 |
if(empty($toggle)) break; //break from switch, not toggled, we need to validate. |
| 1089 |
//check if the toggle is open. only open toggles are registered. |
| 1090 |
if(!empty($toggle_status) && property_exists($toggle_status, $toggle)) break; //break from switch, is toggled and in use, we need to validate. |
| 1091 |
//if we reached here, then the checkbox/radio is toggled and not in use, so do not validate. |
| 1092 |
$isRequired = false; |
| 1093 |
break; |
| 1094 |
} |
| 1095 |
if(!$isRequired) continue;//not submitted==disabled, or not used. |
| 1096 |
} |
| 1097 |
} |
| 1098 |
/** |
| 1099 |
*@since 1.9.0 fix issue with Conditional Field plugin. |
| 1100 |
*/ |
| 1101 |
//validation for non-deprecated plugins (v2.5.0+). |
| 1102 |
if(!isset($data[$tag['name']])) continue; //it was removed by some plugin. |
| 1103 |
$type = $tag['type']; |
| 1104 |
//check to see if this field is an array (table or tab or both). |
| 1105 |
$tag_types[$tag['name']] = $tag['type']; |
| 1106 |
$field_type = self::field_type($tag['name'], $cf7form->id()); |
| 1107 |
switch($field_type){ |
| 1108 |
case 'tab': |
| 1109 |
case 'table': |
| 1110 |
case 'both': |
| 1111 |
// the $data array is passed by reference and will be consolidated. |
| 1112 |
$values = $data[$tag['name']]; |
| 1113 |
/** @since 3.1.3 track all validations */ |
| 1114 |
$validation[$tag['name']] = array(); |
| 1115 |
$validated[$tag['name']] = array(); |
| 1116 |
$submission[$tag['name']] = array(); |
| 1117 |
$idx = 0; |
| 1118 |
foreach($values as $index=>$value){ |
| 1119 |
if(is_array($value) && 'both'==$field_type){ |
| 1120 |
$validation[$tag['name']][$idx]=array(); |
| 1121 |
$validated[$tag['name']][$idx] = array(); |
| 1122 |
$submission[$tag['name']][$idx] = array(); |
| 1123 |
$rdx = 0; |
| 1124 |
foreach($value as $row=>$row_value){ |
| 1125 |
if($deprecated && !isset($_POST[$tag['name'].$index.$row])) continue; |
| 1126 |
elseif(!isset($row_value)) continue; |
| 1127 |
$sg_field_tag = clone $tag; |
| 1128 |
$sg_field_tag['name'] = $tag['name'].$index.$row; |
| 1129 |
$result = apply_filters("wpcf7_validate_{$tag['type']}", $result, $sg_field_tag); |
| 1130 |
/** @since 3.1.3 */ |
| 1131 |
$validation[$tag['name']][$idx][$rdx] = $this->strip_cf7_validation($result, $sg_field_tag->name); |
| 1132 |
$validated[$tag['name']][$idx][$rdx] = $sg_field_tag; |
| 1133 |
$submission[$tag['name']][$idx][$rdx] = $this->get_submitted_data($tag['name'], $type, $row_value); |
| 1134 |
$rdx++; |
| 1135 |
} |
| 1136 |
}else{ |
| 1137 |
if($deprecated && !isset($_POST[$tag['name'].$index])) continue; |
| 1138 |
elseif(!isset($value)) continue; |
| 1139 |
$sg_field_tag = clone $tag; |
| 1140 |
$sg_field_tag['name'] = $tag['name'].$index; |
| 1141 |
$result= apply_filters("wpcf7_validate_{$tag['type']}", $result, $sg_field_tag); |
| 1142 |
/** @since 3.1.3 */ |
| 1143 |
$validation[$tag['name']][$idx] = $this->strip_cf7_validation($result, $sg_field_tag->name); |
| 1144 |
$validated[$tag['name']][$idx] = $sg_field_tag; |
| 1145 |
$submission[$tag['name']][$idx] = $this->get_submitted_data($tag['name'], $type, $value); |
| 1146 |
} |
| 1147 |
$idx++; |
| 1148 |
} |
| 1149 |
// debug_msg($values, 'values '.$tag['name'].'....'); |
| 1150 |
// debug_msg($result, 'validation '.$tag['name'].'....'); |
| 1151 |
if($deprecated){ //if deprecated no need to bother with validation/validated arrays. |
| 1152 |
/** @since 2.3.1 fix the files tag validation for files in tabs/tables*/ |
| 1153 |
switch($type){ |
| 1154 |
case 'file': |
| 1155 |
case 'file*': |
| 1156 |
// Search for $_FILES where name match a tabbed file field |
| 1157 |
$regex = '/^'.preg_quote($tag['name']); |
| 1158 |
$submitted_fields = preg_grep($regex.'$/', array_keys($_FILES)); |
| 1159 |
//extract all relevant fields |
| 1160 |
$submitted_fields += preg_grep($regex.'_tab-[0-9]+_row-[0-9]+$/', array_keys($_FILES)); |
| 1161 |
//we also need the rows with tab index=0 |
| 1162 |
$row_fields = preg_grep($regex.'_row-[0-9]+$/', array_keys($_FILES)); |
| 1163 |
//.. and tabs with row index=0 |
| 1164 |
$submitted_fields += preg_grep($regex.'_tab-[0-9]+$/', array_keys($_FILES)); |
| 1165 |
foreach($submitted_fields as $index => $field){ |
| 1166 |
// For each tabbed file, call the filter validate to add uploaded_files |
| 1167 |
$sg_field_tag = clone $tag; |
| 1168 |
$sg_field_tag['name'] = $field; |
| 1169 |
$result = apply_filters("wpcf7_validate_{$sg_field_tag['type']}", $result, $sg_field_tag); |
| 1170 |
} |
| 1171 |
} |
| 1172 |
} |
| 1173 |
break; |
| 1174 |
default: |
| 1175 |
switch($type) { |
| 1176 |
case 'captchar': //cannot be called twice, hence see if already invalidated. |
| 1177 |
/** @since 3.3.3 check if invalidated previously */ |
| 1178 |
if( isset($invalids[$tag['name']]) ){ |
| 1179 |
$result->invalidate( $tag, $invalids[$tag['name']]['reason']); |
| 1180 |
$validation[$tag['name']] = $invalids[$tag['name']]['reason']; |
| 1181 |
$validated[$tag['name']] = $tag; |
| 1182 |
} |
| 1183 |
break; |
| 1184 |
default: |
| 1185 |
//if(!isset($data[$tag['name']])) continue 2; /*likely toggled and unused*/ |
| 1186 |
$result= apply_filters( "wpcf7_validate_{$type}", $result, $tag ); |
| 1187 |
/** @since 3.1.3 */ |
| 1188 |
$validation[$tag['name']] = $this->strip_cf7_validation($result, $tag['name']); |
| 1189 |
$validated[$tag['name']] = $tag; |
| 1190 |
$submission[$tag['name']] = $this->get_submitted_data($tag['name'], $type, $data[$tag['name']]); |
| 1191 |
break; |
| 1192 |
} |
| 1193 |
break; |
| 1194 |
} |
| 1195 |
} |
| 1196 |
|
| 1197 |
$form_key = ''; |
| 1198 |
if(isset($_POST['_wpcf7_key'])){ |
| 1199 |
$form_key = $_POST['_wpcf7_key']; |
| 1200 |
} |
| 1201 |
|
| 1202 |
//allow for more complex validation. |
| 1203 |
if(has_filter('cf7sg_validate_submission')){ |
| 1204 |
/** |
| 1205 |
* filter to validate the entire submission and check interdependency of fields |
| 1206 |
* @since 1.0.0 |
| 1207 |
* @param Array $validation an array of $field_name=>$validaton_message. |
| 1208 |
* @param Array $submission submitted data, $field_name => $value pairs ($value can be an array especially for fields in tables and tabs) null values are fields which have not been disabled and not submitted such as those in toggled sections. |
| 1209 |
* @param String $form_key unique form key to identify current form. |
| 1210 |
* @param int $form_id cf7 form post ID. |
| 1211 |
* @return Array an array of errors messages, $field_name => $error_msg for single values, and $field_name => [0=>$error_msg, 1=>$error_msg,...] for array values |
| 1212 |
*/ |
| 1213 |
$validation = apply_filters('cf7sg_validate_submission', $validation, $submission, $form_key, $_POST['_wpcf7']); |
| 1214 |
|
| 1215 |
$result = new WPCF7_Validation(); |
| 1216 |
|
| 1217 |
if(!empty($validation)){ |
| 1218 |
foreach($validation as $name=>$msg){ |
| 1219 |
switch(true){ |
| 1220 |
case is_array($msg): |
| 1221 |
foreach($msg as $idx=>$value){ |
| 1222 |
switch(true){ |
| 1223 |
case is_array($value): |
| 1224 |
foreach($value as $rdx=>$message){ |
| 1225 |
if(empty($message)) continue; |
| 1226 |
$result->invalidate($validated[$name][$idx][$rdx], $message); |
| 1227 |
} |
| 1228 |
break; |
| 1229 |
case is_array($validated[$name][$idx]): //error, expecting array.. |
| 1230 |
debug_msg('Filtered cf7sg_validate_submission validation ERROR, expecting array for table field within tab: '.$name.'['.$idx.']'); |
| 1231 |
break; |
| 1232 |
case empty($value): //no message, just continue. |
| 1233 |
break; |
| 1234 |
default: |
| 1235 |
$result->invalidate($validated[$name][$idx], $value); |
| 1236 |
break; |
| 1237 |
} |
| 1238 |
} |
| 1239 |
break; |
| 1240 |
case is_array($validated[$name]): //error, we should have an array. |
| 1241 |
debug_msg('Filtered cf7sg_validate_submission validation ERROR, expecting array for field '.$name); |
| 1242 |
break; |
| 1243 |
case empty($msg): //no message, just continue. |
| 1244 |
break; |
| 1245 |
default: |
| 1246 |
$result->invalidate($validated[$name], $msg); |
| 1247 |
break; |
| 1248 |
} |
| 1249 |
} |
| 1250 |
} |
| 1251 |
} |
| 1252 |
return $result; |
| 1253 |
} |
| 1254 |
/** |
| 1255 |
* Function to strip the submitted data for a given field. |
| 1256 |
* Handles base type files whose data is stored in the $_FILES global array. |
| 1257 |
*@since 3.1.3 |
| 1258 |
*@param string $name field name. |
| 1259 |
*@param string $type base type. |
| 1260 |
*@param mixed $data $_POST data. |
| 1261 |
*@return mixed value actually submitted. |
| 1262 |
*/ |
| 1263 |
public function get_submitted_data($name, $type, $data){ |
| 1264 |
$value = $data; |
| 1265 |
switch($type){ |
| 1266 |
case 'file': |
| 1267 |
case 'file*': |
| 1268 |
$value = array(); |
| 1269 |
if(isset($_FILES[$name])) $value = $_FILES[$name]; |
| 1270 |
break; |
| 1271 |
} |
| 1272 |
return $value; |
| 1273 |
} |
| 1274 |
/** |
| 1275 |
* This function strips the validation message from cf7 WPCF7_Validation object for storage and custom modification using the hook 'cf7sg_validate_submission'. |
| 1276 |
* |
| 1277 |
*@since 3.1.3 |
| 1278 |
*@param WPCF7_Validation $result cf7 validation object for the field being validated. |
| 1279 |
*@param WPCF7_FormTag $tag cf7 tag object for the field being validated. |
| 1280 |
*@return string text_description |
| 1281 |
*/ |
| 1282 |
protected function strip_cf7_validation($result, $name){ |
| 1283 |
$invalid = $result->get_invalid_fields(); |
| 1284 |
$msg = ''; |
| 1285 |
if( !empty($invalid) && isset($invalid[$name]['reason']) ){ |
| 1286 |
$msg = $invalid[$name]['reason']; |
| 1287 |
} |
| 1288 |
return $msg; |
| 1289 |
} |
| 1290 |
/** |
| 1291 |
* Function to save toggled collapsible sections status to open them up again for draft forms. |
| 1292 |
* Hooks action 'cf7_2_post_form_posted' |
| 1293 |
* @since 1.0.0 |
| 1294 |
* @param string $key form unique key. |
| 1295 |
* @param Array $submitted_data array of field-name=>value pairs submitted in form |
| 1296 |
*@since 1.1.0 |
| 1297 |
*@param string $param text_description |
| 1298 |
*@return string text_description |
| 1299 |
*/ |
| 1300 |
public function save_toggle_status($post_id, $key, $post_fields, $post_meta_fields, $submitted_data){ |
| 1301 |
if(isset($submitted_data['_cf7sg_toggles'])){ |
| 1302 |
$toggles = json_decode( stripslashes( $submitted_data['_cf7sg_toggles'] ) ); |
| 1303 |
$toggles_array = array(); |
| 1304 |
if(!empty($toggles)){ |
| 1305 |
foreach($toggles as $key=>$value){ |
| 1306 |
$toggles_array[$key] = sanitize_text_field($value); |
| 1307 |
} |
| 1308 |
} |
| 1309 |
//debug_msg($toggles_array, 'toggles status saved, '); |
| 1310 |
update_post_meta($post_id, 'cf7sg_toggles_status', $toggles_array); |
| 1311 |
} |
| 1312 |
} |
| 1313 |
/** |
| 1314 |
* Function to save custom options values added to tagged select2 fields. |
| 1315 |
* Hooks action 'cf7_2_post_form_posted' |
| 1316 |
* @since 1.0.0 |
| 1317 |
* @param string $key form unique key. |
| 1318 |
* @param Array $submitted_data array of field-name=>value pairs submitted in form |
| 1319 |
**/ |
| 1320 |
public function save_select2_custom_options($post_id, $key, $post_fields, $post_meta_fields, $submitted_data){ |
| 1321 |
$form_id = get_cf7form_id($key); |
| 1322 |
$tagged_fields = get_post_meta($form_id, '_cf7sg_select2_tagged_fields', true); |
| 1323 |
if(empty($tagged_fields)){ |
| 1324 |
return; |
| 1325 |
} |
| 1326 |
|
| 1327 |
foreach($tagged_fields as $field_name=>$source){ |
| 1328 |
$value = $submitted_data[$field_name]; |
| 1329 |
$is_array = true; |
| 1330 |
if(!is_array($value)){ |
| 1331 |
$value = array($value); |
| 1332 |
$is_array = false; |
| 1333 |
} |
| 1334 |
switch($source['source']){ |
| 1335 |
case 'taxonomy': |
| 1336 |
$taxonomy = $source['taxonomy']; |
| 1337 |
$idx=0; |
| 1338 |
foreach($value as $term){ |
| 1339 |
if(!term_exists($term, $taxonomy)){ |
| 1340 |
/** |
| 1341 |
* Filter custom options from tag enabled select2 dynamic-dropdown fields |
| 1342 |
* where the source of options come from taxonomy terms. Filter is fired when a new value is submitted. The pluign inserts a new term by default as per submitted value. |
| 1343 |
* @param string $term the new term submitted by the user. |
| 1344 |
* @param string $field_name the name of the form field. |
| 1345 |
* @param string $taxonomy the taxonomy to which this is added. |
| 1346 |
* @param array $submitted_data array of other submitted $field=>$value pairs. |
| 1347 |
* @param string $key the form unique key. |
| 1348 |
* @return string the new term name to insert. |
| 1349 |
* @since 2.0.0 |
| 1350 |
*/ |
| 1351 |
$term = apply_filters('cf7sg_dynamic_dropdown_new_term', $term, $field_name, $taxonomy, $submitted_data, $key); |
| 1352 |
$new_term = wp_insert_term($term, $taxonomy); |
| 1353 |
if(!is_wp_error($new_term)){ |
| 1354 |
$new_term = get_term($new_term['term_id'], $taxonomy); |
| 1355 |
$value[$idx] = $new_term->slug; |
| 1356 |
} |
| 1357 |
} |
| 1358 |
$idx++; |
| 1359 |
} |
| 1360 |
break; |
| 1361 |
case 'post': |
| 1362 |
$args = array( |
| 1363 |
'post_type' => $source['post'], |
| 1364 |
'post_status' => 'publish', |
| 1365 |
'posts_per_page' => -1 |
| 1366 |
); |
| 1367 |
if(!empty($source['taxonomy'])){ |
| 1368 |
$tax = array(); |
| 1369 |
if(sizeof($source['taxonomy']) > 1){ |
| 1370 |
$tax['relation'] = 'AND'; |
| 1371 |
} |
| 1372 |
foreach($source['taxonomy'] as $term => $taxonomy){ |
| 1373 |
$tax[]=array( |
| 1374 |
'taxonomy' => $taxonomy, |
| 1375 |
'field' => 'slug', |
| 1376 |
'terms' => $term |
| 1377 |
); |
| 1378 |
} |
| 1379 |
$args['tax_query'] = $tax; |
| 1380 |
} |
| 1381 |
$args = apply_filters('cf7sg_dynamic_dropdown_post_query', $args, $tag->name, $key); |
| 1382 |
$posts = get_posts($args); |
| 1383 |
$options = array(); |
| 1384 |
if(!empty($posts)){ |
| 1385 |
foreach($posts as $post){ |
| 1386 |
$options[$post->post_name] = $post->post_title; |
| 1387 |
} |
| 1388 |
} |
| 1389 |
$idx=0; |
| 1390 |
foreach($value as $slug){ |
| 1391 |
if(!isset($options[$slug])){ |
| 1392 |
$args = $source; |
| 1393 |
$post_type = $source['post']; |
| 1394 |
$title = $slug; |
| 1395 |
$post_name = ''; |
| 1396 |
/** |
| 1397 |
* Filter custom options from tag enabled select2 dynamic-dropdown fields |
| 1398 |
* where the source of options come from post titles. Filter is fired when a new value is submitted. |
| 1399 |
* This plugin does not take any further action, ie no post of $post_type will be created. It is upto you to do so and return the slug of the newly created post. |
| 1400 |
* @param string $post_name the new post slug. |
| 1401 |
* @param string $field_name the name of the form field. |
| 1402 |
* @param string $title new value being submitted for a new post title. |
| 1403 |
* @param string $post_type the post type from which this dropdown was built |
| 1404 |
* @param array $args an array of additional parameters that was set in the tag, for example the taxonomy and terms from which to filter the posts for the dynamic list. |
| 1405 |
* @param array $submitted_data array of other submitted $field=>$value pairs. |
| 1406 |
* @param string $key the form unique key. |
| 1407 |
*/ |
| 1408 |
$value[$idx] = apply_filters('cf7sg_dynamic_dropdown_new_post', $post_name, $field_name, $title, $post_type, $args, $submitted_data, $key); |
| 1409 |
} |
| 1410 |
$idx++; |
| 1411 |
} |
| 1412 |
break; |
| 1413 |
case 'filter': |
| 1414 |
$values = $value; |
| 1415 |
/** |
| 1416 |
* Filter custom otions from tag enabled select2 dynamic-dropdown fields |
| 1417 |
* where the source of options come from a filter. Filter is fired when values are submitted. |
| 1418 |
* Return updated values if any are custom values so that saved/draft submissions will reflect the correct value saved in the DB, |
| 1419 |
* @param array $values an array submitted values (several values can be submitted in the case of a tabbed/table input field). |
| 1420 |
* @param string $field_name the name of the form field. |
| 1421 |
* @param array $submitted_data array of other submitted $field=>$value pairs. |
| 1422 |
* @param string $key the form unique key. |
| 1423 |
*/ |
| 1424 |
$value = apply_filters('cf7sg_dynamic_dropdown_filter_select2_submission', $values, $field_name, $submitted_data, $key); |
| 1425 |
break; |
| 1426 |
} |
| 1427 |
//Save the modified value, find which post field the field is mapped to |
| 1428 |
if(!$is_array){ |
| 1429 |
$value = $value[0]; |
| 1430 |
} |
| 1431 |
if( isset($post_fields[$field_name]) ){ |
| 1432 |
$post_key = $post_fields[$field_name]; |
| 1433 |
switch($post_key){ |
| 1434 |
case 'title': |
| 1435 |
case 'author': |
| 1436 |
case 'excerpt': |
| 1437 |
$post_key = 'post_'.$post_key; |
| 1438 |
break; |
| 1439 |
case 'editor': |
| 1440 |
$post_key ='post_content'; |
| 1441 |
break; |
| 1442 |
case 'slug': |
| 1443 |
$post_key ='post_name'; |
| 1444 |
break; |
| 1445 |
} |
| 1446 |
wp_update_post(array( |
| 1447 |
'ID' => $post_id, |
| 1448 |
$post_key => $value |
| 1449 |
)); |
| 1450 |
}else if( isset($post_meta_fields[$field_name]) ){ |
| 1451 |
update_post_meta($post_id, $post_meta_fields[$field_name], $value); |
| 1452 |
} |
| 1453 |
} |
| 1454 |
} |
| 1455 |
/** |
| 1456 |
* Function to retrieve dynamic-dropdown attributes |
| 1457 |
* |
| 1458 |
* @since 1.0.0 |
| 1459 |
* @param WPCF7_FormTag $tag cf7 tag object of basetype dynamic_select. |
| 1460 |
* @return array an array of attributes with 'source'=>[post|taxonomy|filter], . |
| 1461 |
**/ |
| 1462 |
static public function get_dynamic_drodown_attributes($tag){ |
| 1463 |
if(is_array($tag) && isset($tag['basetype']) && 'dynamic_select' === $tag['basetype']){ |
| 1464 |
$tag = new WPCF7_FormTag($tag); |
| 1465 |
} |
| 1466 |
if( !($tag instanceof WPCF7_FormTag) || 'dynamic_select' !== $tag['basetype']){ |
| 1467 |
return false; |
| 1468 |
} |
| 1469 |
$source = array(); |
| 1470 |
foreach($tag->values as $values){ |
| 1471 |
if(0 === strpos($values, 'slug:') ){ |
| 1472 |
$source['source'] = "taxonomy"; |
| 1473 |
$source['taxonomy'] = str_replace('slug:', '', $values); |
| 1474 |
} |
| 1475 |
if(0 === strpos($values, 'source:post')){ |
| 1476 |
$source['source'] = "post"; |
| 1477 |
$source['post'] = str_replace('source:post:', '', $values); |
| 1478 |
} |
| 1479 |
if(0 === strpos($values, 'taxonomy:')){ |
| 1480 |
if(empty($source['taxonomy'])){ |
| 1481 |
$source['taxonomy'] = array(); |
| 1482 |
} |
| 1483 |
$values = str_replace('taxonomy:', '', $values); |
| 1484 |
$exp = explode(":", $values); |
| 1485 |
if(!empty($exp) && is_array($exp)){ |
| 1486 |
$source['taxonomy'][$exp[1]] = $exp[0]; |
| 1487 |
} |
| 1488 |
} |
| 1489 |
if(0 === strpos($values, 'source:filter')){ |
| 1490 |
$source['source'] = "filter"; |
| 1491 |
} |
| 1492 |
} |
| 1493 |
return $source; |
| 1494 |
} |
| 1495 |
/** |
| 1496 |
* Function to temporarily fix the conditional fields plugin issue. |
| 1497 |
* this is is called by the vlidation function 'filter_wpcf7_validate' above. |
| 1498 |
*@since 2.1 |
| 1499 |
*@param array $posted_data submitted data |
| 1500 |
*@return array submitted data without fields that remained hidden. |
| 1501 |
*/ |
| 1502 |
private function remove_hidden_fields_from_conditional_plugin($posted_data){ |
| 1503 |
/*code taken from cf7cf.php file in cf7-conditional-fields*/ |
| 1504 |
if(!isset($posted_data['_wpcf7cf_hidden_group_fields'])){ |
| 1505 |
return $posted_data; |
| 1506 |
} |
| 1507 |
$hidden_fields = json_decode(stripslashes($posted_data['_wpcf7cf_hidden_group_fields'])); |
| 1508 |
$conditonal_fields = array(); |
| 1509 |
if (is_array($hidden_fields) && count($hidden_fields) > 0) { |
| 1510 |
foreach ($hidden_fields as $field) { |
| 1511 |
if (wpcf7cf_endswith($field, '[]')) { |
| 1512 |
$field = substr($field,0,strlen($field)-2); |
| 1513 |
} |
| 1514 |
unset( $posted_data[$field] ); |
| 1515 |
} |
| 1516 |
} |
| 1517 |
return $posted_data; |
| 1518 |
} |
| 1519 |
/** |
| 1520 |
* Filter mail tags which are table or tab fields. |
| 1521 |
* Hooked on 'wpcf7_mail_tag_replaced'. |
| 1522 |
*@since 2.1 |
| 1523 |
*@param string $replaced mail tag string to replace. |
| 1524 |
*@param mixed $submitted value of submitted field from cf7 posted data.. |
| 1525 |
*@param boolea $html mail if mail body is using html. |
| 1526 |
*@param WPCF7_MailTag $mail_tag mail tag object of field being replaced. |
| 1527 |
*@return string replacement string. |
| 1528 |
*/ |
| 1529 |
public function filter_table_tab_mail_tag($replaced, $submitted, $html=false, $mail_tag=null ){ |
| 1530 |
$cf7form = WPCF7_ContactForm::get_current(); |
| 1531 |
$cf7form_key = get_cf7form_key($cf7form->id()); |
| 1532 |
|
| 1533 |
if(empty($mail_tag)) return $replaced; |
| 1534 |
$field_type = self::field_type($mail_tag->field_name(), $cf7form->id()); |
| 1535 |
$label = ''; |
| 1536 |
$build = false; |
| 1537 |
switch($field_type){ |
| 1538 |
case 'tab': |
| 1539 |
case 'table': |
| 1540 |
if($html){ |
| 1541 |
$filtered = apply_filters('cf7sg_mailtag_grid_fields', '', $mail_tag->field_name(), $submitted, $cf7form_key); |
| 1542 |
if(!empty($filtered)){ |
| 1543 |
$replaced = $filtered; |
| 1544 |
break; |
| 1545 |
} |
| 1546 |
} |
| 1547 |
$label=('table'==$field_type)?'row':$field_type; |
| 1548 |
if($html && is_array($submitted)) { |
| 1549 |
$idx=0; |
| 1550 |
$replaced=''; |
| 1551 |
foreach($submitted as $index=>$value){ |
| 1552 |
$idx++; |
| 1553 |
if(is_array($value)) $value = implode(' | ', $value); |
| 1554 |
$replaced .= '<div><label>'.$label.'('.$idx.'):</label><span>'.$value.'</span></div>'; |
| 1555 |
} |
| 1556 |
} |
| 1557 |
break; |
| 1558 |
case 'both': |
| 1559 |
if($html){ |
| 1560 |
$filtered = apply_filters('cf7sg_mailtag_grid_fields', '', $mail_tag->field_name(), $submitted, $cf7form_key); |
| 1561 |
if(!empty($filtered)){ |
| 1562 |
$replaced = $filtered; |
| 1563 |
break; |
| 1564 |
} |
| 1565 |
} |
| 1566 |
// build table. |
| 1567 |
$replaced = ''; |
| 1568 |
if( is_array($submitted)) { |
| 1569 |
$tab = 0; |
| 1570 |
foreach($submitted as $index=>$value){ |
| 1571 |
$tab++; |
| 1572 |
$idx=0; |
| 1573 |
if($html) $replaced .= '<div><span>tab('.$tab.')</span> '; |
| 1574 |
else $replaced .= 'tab('.$tab.') = '; |
| 1575 |
if(is_array($value)){ |
| 1576 |
foreach($value as $row=>$row_value){ |
| 1577 |
$idx++; |
| 1578 |
if(is_array($row_value)) $row_value = implode('|', $row_value); |
| 1579 |
if($html) $replaced .='<div><label>row('.$idx.'):</label><span>' . $row_value . '</span></div>'; |
| 1580 |
else $replaced .= $row_value.','; |
| 1581 |
} |
| 1582 |
} |
| 1583 |
if($html) $replaced .='</div>'; |
| 1584 |
else $replaced .= PHP_EOL; |
| 1585 |
} |
| 1586 |
} |
| 1587 |
break; |
| 1588 |
default: //general fix for cf7 mail tags. |
| 1589 |
$tag = $mail_tag->corresponding_form_tag(); |
| 1590 |
$submitted_cf7 = WPCF7_Submission::get_instance(); |
| 1591 |
$submitted_data = $submitted_cf7->get_posted_data(); |
| 1592 |
/** |
| 1593 |
* Filter the value inserted in the mail tag. |
| 1594 |
* @since 2.9.0. |
| 1595 |
* @param string $replaced value to filter. |
| 1596 |
* @param string $field_name name of the field being inserted in the mail. |
| 1597 |
* @param array $submitted submitted form data. |
| 1598 |
* @param string $form_key unique form key identifier. |
| 1599 |
* @return string a value to replace. |
| 1600 |
*/ |
| 1601 |
if($tag instanceof WPCF7_FormTag){ |
| 1602 |
$replaced = apply_filters('cf7sg_mailtag_'.$tag->basetype, $replaced, $mail_tag->field_name(), $submitted_data, $cf7form_key); |
| 1603 |
} |
| 1604 |
/** |
| 1605 |
* Filter the value inserted in the mail tag. |
| 1606 |
* @since 3.1.6. |
| 1607 |
* @param string $replaced value to filter. |
| 1608 |
* @param string $field_name name of the field being inserted in the mail. |
| 1609 |
* @param array $submitted submitted form data. |
| 1610 |
* @param string $form_key unique form key identifier. |
| 1611 |
* @return string a value to replace. |
| 1612 |
*/ |
| 1613 |
$replaced = apply_filters('cf7sg_mailtag_'.$mail_tag->field_name(), $replaced, $submitted_data, $cf7form_key); |
| 1614 |
break; |
| 1615 |
} |
| 1616 |
|
| 1617 |
return $replaced; |
| 1618 |
} |
| 1619 |
/** |
| 1620 |
* We need to add the missing attachments just before the mail is sent. |
| 1621 |
* Hooked to filter 'wpcf7_mail_components', sets up the final $components object |
| 1622 |
* @since 2.4.1 |
| 1623 |
* @param Array $components an array of mail parts |
| 1624 |
* @param WPCF7_ContactForm $cf7form cf7 form object |
| 1625 |
* @param WPCF7_Mail $cf7mail cf7 mail object |
| 1626 |
* @return Array an array of mail parts |
| 1627 |
*/ |
| 1628 |
public function wpcf7_mail_components($components, $cf7form, $cf7mail) { |
| 1629 |
//$tags = $cf7form->scan_form_tags(); |
| 1630 |
$submission = WPCF7_Submission::get_instance(); |
| 1631 |
$uploaded_files = $submission->uploaded_files(); |
| 1632 |
$cf7_mail = WPCF7_Mail::get_current(); |
| 1633 |
/** @since 2.5.6 fix issue with non-attached files */ |
| 1634 |
$template = $cf7_mail->get( 'attachments' ); |
| 1635 |
$row = $tab = null; |
| 1636 |
$idx = 0; |
| 1637 |
/** @since 2.8.1 fix for send pdf */ |
| 1638 |
$attachments = $components['attachments']; |
| 1639 |
foreach ( (array) $uploaded_files as $name => $path ) { |
| 1640 |
if ( false === strpos( $template, "[${name}]" ) ) continue; //not attached. |
| 1641 |
$field_type = self::field_type($name, $cf7form->id()); |
| 1642 |
$data = $submission->get_posted_data($name); |
| 1643 |
switch($field_type){ |
| 1644 |
case 'tab': |
| 1645 |
case 'table': |
| 1646 |
foreach($data as $field_idx=>$file_name){ |
| 1647 |
if(empty($file_name)) continue; |
| 1648 |
$idx++; |
| 1649 |
$row = ('table'==$field_type)? str_replace('_row-', '', $field_idx):null; |
| 1650 |
$row = (isset($row) && empty($row))? 1:1+(int)$row; |
| 1651 |
$tab = ('tab'==$field_type)? str_replace('_tab-', '', $field_idx):null; |
| 1652 |
$tab = (isset($tab) && empty($tab))? 1:1+(int)$tab; |
| 1653 |
$file = $uploaded_files[$name.$field_idx]; |
| 1654 |
if(!in_array($attachments,$file)) $attachments[] = $file; |
| 1655 |
$file = explode('/',$file); |
| 1656 |
$filename = $file[count($file)-1]; |
| 1657 |
$components['body'].= apply_filters('cf7sg_annotate_mail_attach_grid_files', '', $name, $row, $tab, $idx,$filename, $_POST['_wpcf7_key']); |
| 1658 |
} |
| 1659 |
break; |
| 1660 |
case 'both': |
| 1661 |
$row = $tab = 1; |
| 1662 |
foreach($data as $field_tab=>$tab_files){ |
| 1663 |
$tab = str_replace('_tab-', '', $field_tab); |
| 1664 |
$tab = empty($tab)?1:1+(int) $tab; |
| 1665 |
foreach($tab_files as $field_row=>$file_name){ |
| 1666 |
if(empty($file_name)) continue; |
| 1667 |
$idx++; |
| 1668 |
$row = str_replace('_row-', '', $field_row); |
| 1669 |
$file = $uploaded_files[$name.$field_tab.$field_row]; |
| 1670 |
if(!in_array($attachments,$file)) $attachments[] = $file; |
| 1671 |
$file = explode('/',$file); |
| 1672 |
$filename = $file[count($file)-1]; |
| 1673 |
$components['body'].= apply_filters('cf7sg_annotate_mail_attach_grid_files','', $name, $row, $tab, $idx,$filename, $_POST['_wpcf7_key']); |
| 1674 |
} |
| 1675 |
} |
| 1676 |
break; |
| 1677 |
default: //singular fields. |
| 1678 |
if(empty($path)) continue 2; |
| 1679 |
$idx++; |
| 1680 |
if(!in_array($path, $attachments)) $attachments[] = $path; |
| 1681 |
$path = explode('/',$path); |
| 1682 |
$filename = $path[count($path)-1]; |
| 1683 |
$components['body'].= apply_filters('cf7sg_annotate_mail_attach_grid_files','', $name, null, null, $idx,$filename, $_POST['_wpcf7_key']); |
| 1684 |
break; |
| 1685 |
} |
| 1686 |
} |
| 1687 |
$components['attachments'] = $attachments; |
| 1688 |
return $components; |
| 1689 |
} |
| 1690 |
} |
| 1691 |
|