| 1 |
<?php |
| 2 |
/** |
| 3 |
* Gets form configs in and out of the database |
| 4 |
* |
| 5 |
* @package Caldera_Forms Modified by QuantumCloud |
| 6 |
* @author Josh Pollock <Josh@CalderaWP.com> |
| 7 |
* @license GPL-2.0+ |
| 8 |
* @link |
| 9 |
* @copyright 2016 CalderaWP LLC |
| 10 |
*/ |
| 11 |
|
| 12 |
/** |
| 13 |
* Class Qcformbuilder_Forms_Forms |
| 14 |
* |
| 15 |
* @since 1.3.4 |
| 16 |
*/ |
| 17 |
class Qcformbuilder_Forms_Forms { |
| 18 |
|
| 19 |
/** |
| 20 |
* Holds registry of forms |
| 21 |
* |
| 22 |
* @since 1.3.4 |
| 23 |
* |
| 24 |
* @var array |
| 25 |
*/ |
| 26 |
protected static $registry_cache; |
| 27 |
|
| 28 |
/** |
| 29 |
* Cache key for storing form registry in |
| 30 |
* |
| 31 |
* @since 1.3.4 |
| 32 |
* |
| 33 |
* @var string |
| 34 |
*/ |
| 35 |
protected static $registry_cache_key = '_qcformbuilder_forms'; |
| 36 |
|
| 37 |
/** |
| 38 |
* Holds simple index of form IDs |
| 39 |
* |
| 40 |
* @since 1.3.4 |
| 41 |
* |
| 42 |
* @var array |
| 43 |
*/ |
| 44 |
protected static $index; |
| 45 |
|
| 46 |
/** |
| 47 |
* Holds stored forms |
| 48 |
* |
| 49 |
* @since 1.3.4 |
| 50 |
* |
| 51 |
* @var array |
| 52 |
*/ |
| 53 |
protected static $stored_forms; |
| 54 |
|
| 55 |
/** |
| 56 |
* Option key for storing registry in |
| 57 |
* |
| 58 |
* @since 1.3.4 |
| 59 |
* |
| 60 |
* @var string |
| 61 |
*/ |
| 62 |
protected static $registry_option_key = '_qcformbuilder_forms_forms'; |
| 63 |
|
| 64 |
/** |
| 65 |
* Fields used when converting flat registry to detailed registry |
| 66 |
* |
| 67 |
* @since 1.3.4 |
| 68 |
* |
| 69 |
* @var array |
| 70 |
*/ |
| 71 |
protected static $detail_fields = array( |
| 72 |
'ID', |
| 73 |
'name', |
| 74 |
'description', |
| 75 |
'success', |
| 76 |
'form_ajax', |
| 77 |
'hide_form', |
| 78 |
'db_support', |
| 79 |
'mailer', |
| 80 |
'pinned', |
| 81 |
'pin_roles', |
| 82 |
'hidden', |
| 83 |
'form_draft' |
| 84 |
); |
| 85 |
|
| 86 |
/** |
| 87 |
* Load a form by ID or name |
| 88 |
* |
| 89 |
* @since 1.3.4 |
| 90 |
* |
| 91 |
* @param string $id_name ID or name of form. |
| 92 |
* @param string $type Optional. Default is "primary" the main form. Can also be "revision" for getting a revision. |
| 93 |
* |
| 94 |
* @return array|null Form config array if found. If not null. |
| 95 |
*/ |
| 96 |
public static function get_form( $id_name, $type = 'primary' ){ |
| 97 |
$id_name = sanitize_text_field( $id_name ); |
| 98 |
|
| 99 |
$forms = self::get_forms(); |
| 100 |
$form = null; |
| 101 |
|
| 102 |
if ( self::is_internal_form( $id_name ) ) { |
| 103 |
if ( isset( $forms[ $id_name ] ) ) { |
| 104 |
$form = self::get_from_db( $id_name, $type ); |
| 105 |
if( empty( $form ) ){ |
| 106 |
$form = get_option( $forms[ $id_name ] ); |
| 107 |
if( ! empty( $form ) ){ |
| 108 |
$form = self::maybe_migrate( $form ); |
| 109 |
} |
| 110 |
|
| 111 |
} |
| 112 |
|
| 113 |
} else { |
| 114 |
$forms = self::get_forms( true ); |
| 115 |
foreach ( $forms as $form_id => $form_maybe ) { |
| 116 |
if ( trim( strtolower( $id_name ) ) == strtolower( $form_maybe[ 'name' ] ) && empty( $form_maybe[ '_external_form' ] ) ) { |
| 117 |
$form = self::get_from_db( $form_maybe[ 'ID' ], $type ); |
| 118 |
if( empty( $form ) ){ |
| 119 |
$form = get_option( $forms[ $id_name ] ); |
| 120 |
if( ! empty( $form ) ){ |
| 121 |
$form = self::maybe_migrate( $form ); |
| 122 |
} |
| 123 |
} |
| 124 |
} |
| 125 |
} |
| 126 |
} |
| 127 |
} |
| 128 |
|
| 129 |
if( empty( $form ) ){ |
| 130 |
$external = true; |
| 131 |
}else{ |
| 132 |
$form = self::db_to_return( $form ); |
| 133 |
} |
| 134 |
|
| 135 |
$form = self::filter_form( $id_name, $form ); |
| 136 |
|
| 137 |
if( is_array( $form ) && empty( $form['ID'] ) ){ |
| 138 |
$form['ID'] = $id_name; |
| 139 |
} |
| 140 |
|
| 141 |
if( ! empty( $form ) && ! empty( $external ) ){ |
| 142 |
$form['_external_form'] = true; |
| 143 |
} |
| 144 |
|
| 145 |
// remove submit on editing |
| 146 |
if( !empty( $_GET['modal'] ) && $_GET['modal'] == 'view_entry' && !empty( $_GET['group'] ) && $_GET['group'] == 'editentry' ){ |
| 147 |
if( !empty( $form['fields'] ) ){ |
| 148 |
foreach( $form['fields'] as $field_id=>$field ){ |
| 149 |
if( $field['type'] == 'button' && $field['config']['type'] == 'submit' ){ |
| 150 |
unset( $form['fields'][ $field_id ] ); |
| 151 |
} |
| 152 |
} |
| 153 |
} |
| 154 |
} |
| 155 |
|
| 156 |
return $form; |
| 157 |
} |
| 158 |
|
| 159 |
/** |
| 160 |
* Get registry of forms |
| 161 |
* |
| 162 |
* @since 1.3.4 |
| 163 |
* |
| 164 |
* @param bool|false $with_details Optional. If false, the default, just form IDs are returned. If true, basic details of each are returned. |
| 165 |
* @param bool|false $internal_only Optional. If false, the default, all forms -- in DB and in files system -- are returned -- If true, only those in DB are returned. |
| 166 |
* |
| 167 |
* @return array |
| 168 |
*/ |
| 169 |
public static function get_forms( $with_details = false, $internal_only = false, $orderby = false ){ |
| 170 |
if( isset( $_GET[ 'wfb-cache-clear' ] ) ){ |
| 171 |
self::clear_cache(); |
| 172 |
} |
| 173 |
|
| 174 |
if( empty( static::$index ) ){ |
| 175 |
static::$index = static::get_stored_forms(); |
| 176 |
} |
| 177 |
|
| 178 |
if ( false === $internal_only ) { |
| 179 |
/** |
| 180 |
* Runs after getting internal forms, use to add forms defined in file system |
| 181 |
* |
| 182 |
* @since unknown |
| 183 |
* |
| 184 |
* @param array $base_forms Forms saved in DB |
| 185 |
*/ |
| 186 |
$forms = apply_filters('qcformbuilder_forms_get_forms', static::$index); |
| 187 |
if (!empty($forms) && is_array($forms)) { |
| 188 |
foreach ($forms as $form_id => $form) { |
| 189 |
$forms[$form_id] = $form_id; |
| 190 |
} |
| 191 |
} |
| 192 |
} |
| 193 |
|
| 194 |
|
| 195 |
if( $with_details ){ |
| 196 |
$forms = self::add_details( static::$index ); |
| 197 |
}else{ |
| 198 |
$forms = static::$index; |
| 199 |
} |
| 200 |
|
| 201 |
if( $orderby && ! empty( $forms ) ){ |
| 202 |
$forms = self::order_forms( $forms, $orderby ); |
| 203 |
} |
| 204 |
|
| 205 |
return is_array($forms) ? $forms : []; |
| 206 |
|
| 207 |
} |
| 208 |
|
| 209 |
/** |
| 210 |
* Check if a form is a revision |
| 211 |
* |
| 212 |
* @since 1.5.4 |
| 213 |
* |
| 214 |
* @param array $form Form config |
| 215 |
* |
| 216 |
* @return bool |
| 217 |
*/ |
| 218 |
public static function is_revision( array $form ){ |
| 219 |
return isset( $form[ 'type' ] ) && 'revision' === $form[ 'type' ]; |
| 220 |
|
| 221 |
} |
| 222 |
|
| 223 |
/** |
| 224 |
* Make a reivison the primary form |
| 225 |
* |
| 226 |
* @since 1.5.3 |
| 227 |
* |
| 228 |
* @param int $revision_id Revision ID |
| 229 |
* |
| 230 |
* @return false|int |
| 231 |
*/ |
| 232 |
public static function restore_revision( $revision_id ){ |
| 233 |
return Qcformbuilder_Forms_DB_Form::get_instance( )->make_revision_primary( $revision_id ); |
| 234 |
} |
| 235 |
|
| 236 |
/** |
| 237 |
* Get forms stored in DB |
| 238 |
* |
| 239 |
* @since 1.3.4 |
| 240 |
* |
| 241 |
* @return array |
| 242 |
*/ |
| 243 |
protected static function get_stored_forms() { |
| 244 |
|
| 245 |
if ( empty( self::$stored_forms ) ) { |
| 246 |
$forms = Qcformbuilder_Forms_DB_Form::get_instance()->get_all(); |
| 247 |
if( ! empty( $forms ) ){ |
| 248 |
foreach( $forms as $form ){ |
| 249 |
if ( ! empty( $form[ 'config' ] ) ) { |
| 250 |
static::$stored_forms[$form['form_id']] = $form['form_id']; |
| 251 |
} |
| 252 |
} |
| 253 |
|
| 254 |
} |
| 255 |
} |
| 256 |
|
| 257 |
return is_array(self::$stored_forms ) ? self::$stored_forms : []; |
| 258 |
} |
| 259 |
|
| 260 |
/** |
| 261 |
* Import form |
| 262 |
* |
| 263 |
* @since 1.3.4 |
| 264 |
* |
| 265 |
* @param array $data Form config |
| 266 |
* @param bool $trusted Is import data trusted? Default is to trust. |
| 267 |
* |
| 268 |
* @return string Form ID |
| 269 |
*/ |
| 270 |
public static function import_form( $data, $trusted = true ){ |
| 271 |
$forms = self::get_forms(); |
| 272 |
if ( isset( $data[ 'ID' ] ) && array_key_exists( $data[ 'ID' ], $forms ) ) { |
| 273 |
// generate a new ID |
| 274 |
$data[ 'ID' ] = self::create_unique_form_id(); |
| 275 |
} |
| 276 |
|
| 277 |
if( isset( $data[ 'ID' ] ) ){ |
| 278 |
$id = $data[ 'ID' ]; |
| 279 |
}else{ |
| 280 |
$id = $data[ 'ID' ] = self::create_unique_form_id(); |
| 281 |
} |
| 282 |
|
| 283 |
$data[ 'ID' ] = trim( $id ); |
| 284 |
unset( $data[ 'db_id' ] ); |
| 285 |
|
| 286 |
$importer = new Qcformbuilder_Forms_Import_Form($data, $trusted ); |
| 287 |
$data = $importer->get_prepared_form(); |
| 288 |
$new_form = self::save_form( $data ); |
| 289 |
if( is_array( $new_form ) && isset( $new_form[ 'ID' ] ) ){ |
| 290 |
$new_form = $new_form[ 'ID' ]; |
| 291 |
} |
| 292 |
|
| 293 |
return $new_form; |
| 294 |
|
| 295 |
} |
| 296 |
|
| 297 |
/** |
| 298 |
* Apply qcformbuilder_forms_get_form filters |
| 299 |
* |
| 300 |
* @since 1.5.3 |
| 301 |
* |
| 302 |
* @param string $id_name Form ID or name |
| 303 |
* @param array $config Form config |
| 304 |
* @param bool $is_revision Optional. Is this a revision of a form? Default is false |
| 305 |
* |
| 306 |
* @return mixed|void |
| 307 |
*/ |
| 308 |
protected static function filter_form( $id_name, $config, $is_revision = false ){ |
| 309 |
|
| 310 |
if( ! isset( $config[ 'type' ] ) ){ |
| 311 |
if( $is_revision ){ |
| 312 |
$config[ 'type' ] = 'revision'; |
| 313 |
}else{ |
| 314 |
$config[ 'type' ] = 'primary'; |
| 315 |
} |
| 316 |
|
| 317 |
} |
| 318 |
|
| 319 |
/** |
| 320 |
* Filter settings of a form or all forms or use to define a form in file |
| 321 |
* |
| 322 |
* @since unknown |
| 323 |
* |
| 324 |
* @param array $config Form config |
| 325 |
* @param string $id_name ID or name of form |
| 326 |
* @param bool $is_revision Is this a revision of a form? @since 1.5.3 |
| 327 |
*/ |
| 328 |
$config = apply_filters( 'qcformbuilder_forms_get_form', $config, $id_name, $is_revision ); |
| 329 |
|
| 330 |
/** |
| 331 |
* Filter settings of a specific form or all forms or use to define a form in file |
| 332 |
* |
| 333 |
* @since unknown |
| 334 |
* |
| 335 |
* @param array $config Form config |
| 336 |
* @param string $id_name ID or name of form |
| 337 |
* @param bool $is_revision Is this a revision of a form? @since 1.5.3 |
| 338 |
*/ |
| 339 |
$config = apply_filters( 'qcformbuilder_forms_get_form-' . $id_name, $config, $id_name, $is_revision ); |
| 340 |
|
| 341 |
return $config; |
| 342 |
|
| 343 |
} |
| 344 |
|
| 345 |
/** |
| 346 |
* Convert array returned from database to form config array expected by admin and front-end and like everything |
| 347 |
* |
| 348 |
* @since 1.5.3 |
| 349 |
* |
| 350 |
* @param $form |
| 351 |
* |
| 352 |
* @return mixed |
| 353 |
*/ |
| 354 |
protected static function db_to_return( $form ){ |
| 355 |
$_form = $form[ 'config' ]; |
| 356 |
$_form[ 'db_id' ] = $form[ 'id' ]; |
| 357 |
$_form[ 'type' ] = $form[ 'type' ]; |
| 358 |
|
| 359 |
return $_form; |
| 360 |
|
| 361 |
} |
| 362 |
|
| 363 |
/** |
| 364 |
* Get the filter value for maximum revisions |
| 365 |
* |
| 366 |
* @since 1.5.3 |
| 367 |
* |
| 368 |
* @param array $form Form config |
| 369 |
* |
| 370 |
* @return int |
| 371 |
*/ |
| 372 |
protected static function max_revisions( array $form ){ |
| 373 |
/** |
| 374 |
* Change the number fo form revisions to store per form |
| 375 |
* |
| 376 |
* @since 1.5.3 |
| 377 |
* |
| 378 |
* @param int|bool Number of revisions to save. Set to false or 0 to disable form revisions. |
| 379 |
* @param array $form Form Config |
| 380 |
*/ |
| 381 |
$max_revisions = apply_filters( 'qcformbuilder_forms_max_form_revisions', 15, $form ); |
| 382 |
|
| 383 |
return (int) $max_revisions; |
| 384 |
} |
| 385 |
|
| 386 |
/** |
| 387 |
* Use to switch form arrays to ID strings |
| 388 |
* |
| 389 |
* @since 1.3.4 |
| 390 |
* |
| 391 |
* @param array|int $val Index to convert |
| 392 |
* |
| 393 |
* @return string |
| 394 |
*/ |
| 395 |
protected function force_string( $val ){ |
| 396 |
if( is_array( $val ) ){ |
| 397 |
$val = $val[ 'ID' ]; |
| 398 |
} |
| 399 |
|
| 400 |
return $val; |
| 401 |
} |
| 402 |
|
| 403 |
/** |
| 404 |
* Add details to form registry |
| 405 |
* |
| 406 |
* @since 1.3.4 |
| 407 |
* |
| 408 |
* @param array $forms |
| 409 |
* |
| 410 |
* @return array |
| 411 |
*/ |
| 412 |
protected static function add_details( $forms ){ |
| 413 |
if( empty( $forms ) ){ |
| 414 |
return []; |
| 415 |
} |
| 416 |
|
| 417 |
if( ! empty( $valid_forms = get_transient( self::$registry_cache_key ) ) ) { |
| 418 |
return $valid_forms; |
| 419 |
}else{ |
| 420 |
$valid_forms = []; |
| 421 |
} |
| 422 |
|
| 423 |
foreach( $forms as $id => $form ){ |
| 424 |
$_form = self::get_form( $id ); |
| 425 |
if( empty( $_form ) ){ |
| 426 |
//if its empty, there is no form. we can't just make up stuff. |
| 427 |
continue; |
| 428 |
} |
| 429 |
|
| 430 |
$valid_forms[ $id ] = array(); |
| 431 |
foreach( self::$detail_fields as $key ){ |
| 432 |
if ( isset( $_form[ $key ] ) ) { |
| 433 |
$valid_forms[ $id ][ $key ] = $_form[ $key ]; |
| 434 |
} elseif ( 'name' == $key ) { |
| 435 |
$valid_forms[ $id ][ $key ] = $id; |
| 436 |
} elseif ( 'mailer' == $key ) { |
| 437 |
$valid_forms[ $id ][ $key ] = array( 'on_insert' => 1 ); |
| 438 |
} elseif ( in_array( $key, array( 'form_ajax', 'check_honey', 'hide_form', 'db_support' ) ) ) { |
| 439 |
$valid_forms[ $id ][ $key ] = 1; |
| 440 |
} elseif( 'form_draft' == $key ) { |
| 441 |
$valid_forms[ $id ][ $key ] = 0; |
| 442 |
}else { |
| 443 |
$valid_forms[ $id ][ $key ] = ''; |
| 444 |
} |
| 445 |
|
| 446 |
|
| 447 |
|
| 448 |
} |
| 449 |
} |
| 450 |
|
| 451 |
$base_forms = self::get_stored_forms(); |
| 452 |
|
| 453 |
foreach ( $valid_forms as $form_id => $form ) { |
| 454 |
if ( ! isset( $base_forms[ $form_id ] ) ) { |
| 455 |
$valid_forms[ $form_id ][ '_external_form' ] = true; |
| 456 |
if ( empty( $forms[ $form_id ][ 'ID' ] ) ) { |
| 457 |
$valid_forms[ $form_id ][ 'ID' ] = $form_id; |
| 458 |
} |
| 459 |
|
| 460 |
} |
| 461 |
} |
| 462 |
|
| 463 |
if ( ! empty( $valid_forms ) ) { |
| 464 |
set_transient( self::$registry_cache_key, $valid_forms, HOUR_IN_SECONDS ); |
| 465 |
} |
| 466 |
|
| 467 |
self::$registry_cache = $valid_forms; |
| 468 |
return self::$registry_cache; |
| 469 |
|
| 470 |
} |
| 471 |
|
| 472 |
/** |
| 473 |
* Save a form |
| 474 |
* |
| 475 |
* @since 1.3.4 |
| 476 |
* |
| 477 |
* @param array $data Form config |
| 478 |
* @param string $type Optional. Default is "primary" the main form. Can also be "revision" for saving a revision. @since 1.5.3 |
| 479 |
|
| 480 |
* |
| 481 |
* @return string|bool Form ID if updated, false if not |
| 482 |
*/ |
| 483 |
public static function save_form( $data, $type = 'primary' ){ |
| 484 |
|
| 485 |
|
| 486 |
if(!empty($data['fields'])){ |
| 487 |
foreach($data['fields'] as &$field){ |
| 488 |
// option value labels |
| 489 |
if(!empty($field['config']['option']) && is_array($field['config']['option'])){ |
| 490 |
foreach($field['config']['option'] as &$option){ |
| 491 |
if(!isset($option['value'])){ |
| 492 |
$option['value'] = $option['label']; |
| 493 |
} |
| 494 |
} |
| 495 |
// trim manual calculations |
| 496 |
} else if(!empty($field["config"]["manual_formula"]) && is_string($field["config"]["manual_formula"])){ |
| 497 |
$field["config"]["manual_formula"] = Qcformbuilder_Forms_Sanitize::finish_trim( Qcformbuilder_Forms_Sanitize::sanitize_header( $field["config"]["manual_formula"] ) ); |
| 498 |
} |
| 499 |
} |
| 500 |
} |
| 501 |
|
| 502 |
// combine structure pages |
| 503 |
if ( isset( $data['layout_grid']['structure'] ) && is_array( $data['layout_grid']['structure'] ) ) { |
| 504 |
$data[ 'layout_grid' ][ 'structure' ] = implode( '#', $data[ 'layout_grid' ][ 'structure' ] ); |
| 505 |
} |
| 506 |
// remove fields from conditions |
| 507 |
if( !empty( $data['conditional_groups']['fields'] ) ){ |
| 508 |
unset( $data['conditional_groups']['fields'] ); |
| 509 |
} |
| 510 |
// remove magics ( yes, not used yet.) |
| 511 |
if( !empty( $data['conditional_groups']['magic'] ) ){ |
| 512 |
unset( $data['conditional_groups']['magic'] ); |
| 513 |
} |
| 514 |
// sanitize condition values |
| 515 |
if( !empty( $data['conditional_groups']['conditions'] ) ){ |
| 516 |
foreach( $data['conditional_groups']['conditions'] as $condition_id => &$condition ){ |
| 517 |
if( !empty( $condition['group'] ) ){ |
| 518 |
$condition['name'] = htmlentities( $condition['name'] ); |
| 519 |
foreach ($condition['group'] as $group_id => &$group) { |
| 520 |
foreach( $group as $case_id=>&$case ){ |
| 521 |
$case['value'] = htmlentities( $case['value'] ); |
| 522 |
} |
| 523 |
} |
| 524 |
} |
| 525 |
} |
| 526 |
} |
| 527 |
|
| 528 |
$data[ '_last_updated' ] = date('r'); |
| 529 |
$data[ 'version' ] = WFBCORE_VER; |
| 530 |
|
| 531 |
/** |
| 532 |
* Filter form config directly before saving |
| 533 |
* |
| 534 |
* @since 1.4.0 |
| 535 |
* |
| 536 |
* @param array $data Form config |
| 537 |
*/ |
| 538 |
$data = apply_filters( 'qcformbuilder_forms_presave_form', $data ); |
| 539 |
|
| 540 |
// add form to registry |
| 541 |
self::update_registry( $data[ "ID" ] ); |
| 542 |
|
| 543 |
|
| 544 |
self::save_to_db( $data, $type ); |
| 545 |
self::clear_cache(); |
| 546 |
/** |
| 547 |
* Fires after a form is saved |
| 548 |
* |
| 549 |
* @since unknown |
| 550 |
* |
| 551 |
* @param array $data The form data |
| 552 |
* @param string $from_id The form ID |
| 553 |
*/ |
| 554 |
do_action('qcformbuilder_forms_save_form', $data, $data['ID']); |
| 555 |
|
| 556 |
|
| 557 |
return $data[ 'ID' ]; |
| 558 |
} |
| 559 |
|
| 560 |
/** |
| 561 |
* Create a new form |
| 562 |
* |
| 563 |
* @since 1.3.4 |
| 564 |
* |
| 565 |
* @param array $newform Data for new form |
| 566 |
* |
| 567 |
* @return array|mixed|void |
| 568 |
*/ |
| 569 |
public static function create_form( $newform ){ |
| 570 |
require_once( WFBCORE_PATH . 'classes/admin.php' ); |
| 571 |
|
| 572 |
// get form templates (PROBABLY NEED TO MOVE METHOD INTO THIS CLASS) |
| 573 |
$form_templates = Qcformbuilder_Forms_Admin::internal_form_templates(); |
| 574 |
|
| 575 |
$original_function_args = $newform; |
| 576 |
if(!empty($newform['clone'])){ |
| 577 |
$clone = $newform['clone']; |
| 578 |
} |
| 579 |
|
| 580 |
// load template if any |
| 581 |
if( !empty( $newform['template'] ) ){ |
| 582 |
if( isset( $form_templates[ $newform['template'] ] ) && !empty( $form_templates[ $newform['template'] ]['template'] ) ){ |
| 583 |
$form_template = $form_templates[ $newform['template'] ]['template']; |
| 584 |
} |
| 585 |
} |
| 586 |
|
| 587 |
$forms = self::get_forms(); |
| 588 |
if( ! isset( $newform[ 'ID' ] ) || ( ! isset( $newform[ 'ID' ] ) && array_key_exists( $newform[ 'ID' ], $forms ) ) ) { |
| 589 |
$id = uniqid('CF'); |
| 590 |
}else{ |
| 591 |
$id = $newform[ 'ID' ]; |
| 592 |
} |
| 593 |
|
| 594 |
$id = trim( $id ); |
| 595 |
$defaults = array( |
| 596 |
"ID" => $id, |
| 597 |
"name" => '', |
| 598 |
"description" => '', |
| 599 |
"success" => __( 'Form has been successfully submitted. Thank you.', 'qcformbuilder-forms' ), |
| 600 |
"form_ajax" => 1, |
| 601 |
"hide_form" => 1, |
| 602 |
"check_honey" => 1, |
| 603 |
"db_support" => 1, |
| 604 |
'mailer' => array( 'on_insert' => 1 ) |
| 605 |
); |
| 606 |
|
| 607 |
$newform = wp_parse_args( $newform, $defaults ); |
| 608 |
|
| 609 |
// is template? |
| 610 |
if( !empty( $form_template ) && is_array( $form_template ) ){ |
| 611 |
$newform = array_merge( $form_template, $newform ); |
| 612 |
$newform[ 'ID' ] = $id; |
| 613 |
} |
| 614 |
|
| 615 |
/** |
| 616 |
* Filter newly created form before saving |
| 617 |
* |
| 618 |
* @since unknown |
| 619 |
* |
| 620 |
* @param array $newform New form config |
| 621 |
*/ |
| 622 |
$newform = apply_filters( 'qcformbuilder_forms_create_form', $newform); |
| 623 |
|
| 624 |
self::update_registry( $id ); |
| 625 |
|
| 626 |
if(!empty($clone)){ |
| 627 |
$clone_form = self::get_form( $clone ); |
| 628 |
if(!empty($clone_form['ID']) && $clone == $clone_form['ID']){ |
| 629 |
$newform = array_merge($clone_form, $original_function_args); |
| 630 |
unset( $newform[ 'db_id' ] ); |
| 631 |
$newform[ 'ID' ] = $id; |
| 632 |
} |
| 633 |
} |
| 634 |
|
| 635 |
// add form to db |
| 636 |
$added = self::save_to_db( $newform, 'primary' ); |
| 637 |
if( ! $added ){ |
| 638 |
return false; |
| 639 |
|
| 640 |
} |
| 641 |
|
| 642 |
/** |
| 643 |
* Runs after form is created |
| 644 |
* |
| 645 |
* @since unkown |
| 646 |
* |
| 647 |
* @param array $newform New form config |
| 648 |
*/ |
| 649 |
do_action('qcformbuilder_forms_create_form', $newform); |
| 650 |
return $newform; |
| 651 |
} |
| 652 |
|
| 653 |
/** |
| 654 |
* Delete a form |
| 655 |
* |
| 656 |
* Will delete all revisions |
| 657 |
* |
| 658 |
* @since 1.3.4 |
| 659 |
* |
| 660 |
* @param string $id Form ID |
| 661 |
* |
| 662 |
* @return bool |
| 663 |
*/ |
| 664 |
public static function delete_form( $id ){ |
| 665 |
$forms = self::get_forms(); |
| 666 |
if( ! isset( $forms[ $id ] ) ){ |
| 667 |
return false; |
| 668 |
} |
| 669 |
|
| 670 |
unset( $forms[ $id ] ); |
| 671 |
$deleted = Qcformbuilder_Forms_DB_Form::get_instance()->delete_by_form_id( $id ); |
| 672 |
if ( $deleted ) { |
| 673 |
self::update_registry( $forms ); |
| 674 |
|
| 675 |
return $deleted; |
| 676 |
} |
| 677 |
|
| 678 |
return false; |
| 679 |
} |
| 680 |
|
| 681 |
/** |
| 682 |
* Update form registry |
| 683 |
* |
| 684 |
* @since 1.3.4 |
| 685 |
* |
| 686 |
* @param string|array $new Depreacted argument |
| 687 |
* |
| 688 |
*/ |
| 689 |
protected static function update_registry( $new ){ |
| 690 |
|
| 691 |
self::clear_cache(); |
| 692 |
$forms = self::get_forms(false,true); |
| 693 |
|
| 694 |
/** |
| 695 |
* Fires after form registry is updated by saving a from |
| 696 |
* |
| 697 |
* @since unknown |
| 698 |
* |
| 699 |
* @param array $deprecated |
| 700 |
* @param array $forms Array of forms in registry |
| 701 |
*/ |
| 702 |
do_action('qcformbuilder_forms_save_form_register', array(), $forms ); |
| 703 |
|
| 704 |
} |
| 705 |
|
| 706 |
/** |
| 707 |
* Clear the caching performed by this class |
| 708 |
* |
| 709 |
* @since 1.3.4 |
| 710 |
*/ |
| 711 |
protected static function clear_cache(){ |
| 712 |
self::$index = array(); |
| 713 |
self::$registry_cache = array(); |
| 714 |
self::$stored_forms = array(); |
| 715 |
wp_cache_delete( '_qcformbuilder_forms_forms', 'options' ); |
| 716 |
delete_transient( self::$registry_cache_key ); |
| 717 |
} |
| 718 |
|
| 719 |
/** |
| 720 |
* Check if a form is stored in DB by name oir ID |
| 721 |
* |
| 722 |
* @since 1.3.4 |
| 723 |
* |
| 724 |
* @param string $id_name Form name or ID |
| 725 |
* |
| 726 |
* @return bool |
| 727 |
*/ |
| 728 |
public static function is_internal_form( $id_name ){ |
| 729 |
return ! empty(self::get_stored_forms() ) && in_array( $id_name, self::get_stored_forms() ); |
| 730 |
} |
| 731 |
|
| 732 |
/** |
| 733 |
* Change a form's state form enabled to disabled or vise vera |
| 734 |
* |
| 735 |
* @since 1.3.5 |
| 736 |
* |
| 737 |
* @param array $form Form config. |
| 738 |
* @param bool|true $enable Optional. If true, enable form, if false, disable form. |
| 739 |
*/ |
| 740 |
public static function form_state( $form, $enable = true ){ |
| 741 |
if( $enable ){ |
| 742 |
$form['form_draft'] = 0; |
| 743 |
|
| 744 |
}else{ |
| 745 |
$form['form_draft'] = 1; |
| 746 |
|
| 747 |
} |
| 748 |
|
| 749 |
if( is_array( self::$registry_cache ) && isset( self::$registry_cache[ $form[ 'ID' ] ] ) ){ |
| 750 |
delete_transient( self::$registry_cache_key ); |
| 751 |
self::$registry_cache[ $form[ 'ID' ] ][ 'form_draft' ] = $form['form_draft']; |
| 752 |
} |
| 753 |
|
| 754 |
self::save_form( $form ); |
| 755 |
|
| 756 |
} |
| 757 |
|
| 758 |
/** |
| 759 |
* Get all fields of a form |
| 760 |
* |
| 761 |
* @since 1.4.4 |
| 762 |
* |
| 763 |
* @param array $form The form config |
| 764 |
* @param bool $in_order Optional. Return in layout order, the default, or in stored order (false). |
| 765 |
* |
| 766 |
* @return array|mixed |
| 767 |
*/ |
| 768 |
public static function get_fields( array $form, $in_order = true ){ |
| 769 |
if( empty( $form[ 'fields' ] ) ){ |
| 770 |
return array(); |
| 771 |
} |
| 772 |
|
| 773 |
$fields = $form[ 'fields' ]; |
| 774 |
|
| 775 |
if ( $in_order ) { |
| 776 |
|
| 777 |
if( isset( $form[ 'layout_grid' ][ 'fields' ] ) ){ |
| 778 |
$order = array_keys( $form[ 'layout_grid' ][ 'fields' ] ); |
| 779 |
}else{ |
| 780 |
$order = array_keys( $fields ); |
| 781 |
} |
| 782 |
|
| 783 |
/** |
| 784 |
* Change order of fields |
| 785 |
* |
| 786 |
* Very useful for reordering fields outputted with {summary} magic tag |
| 787 |
* |
| 788 |
* @since 1.4.5 |
| 789 |
* |
| 790 |
* @param array $order Order -- array of field IDs |
| 791 |
* @param array $form Form config |
| 792 |
*/ |
| 793 |
$order = apply_filters( 'qcformbuilder_forms_get_field_order', $order, $form ); |
| 794 |
|
| 795 |
$ordered = array(); |
| 796 |
foreach ( $order as $key ) { |
| 797 |
if ( isset( $fields[ $key ] ) ) { |
| 798 |
$ordered[ $key ] = $fields[ $key ]; |
| 799 |
} |
| 800 |
|
| 801 |
} |
| 802 |
|
| 803 |
return $ordered; |
| 804 |
|
| 805 |
}else{ |
| 806 |
return $fields; |
| 807 |
} |
| 808 |
|
| 809 |
|
| 810 |
} |
| 811 |
|
| 812 |
/** |
| 813 |
* Get entry list fields of a form |
| 814 |
* |
| 815 |
* @since 1.5.0 |
| 816 |
* |
| 817 |
* @param array $form Form config |
| 818 |
* @param bool $configs Optional. If true, field config arrays are returned. If false, the default, field IDs are returned |
| 819 |
* |
| 820 |
* @return array |
| 821 |
*/ |
| 822 |
public static function entry_list_fields( array $form, $configs = false ){ |
| 823 |
$fields = self::get_fields( $form ); |
| 824 |
$entry_list_fields = array(); |
| 825 |
foreach ( $fields as $field_id => $field ){ |
| 826 |
if( ! empty( $field[ 'entry_list'])){ |
| 827 |
if ( $configs ) { |
| 828 |
$entry_list_fields[ $field_id ] = $field; |
| 829 |
}else{ |
| 830 |
$entry_list_fields[] = $field_id; |
| 831 |
} |
| 832 |
} |
| 833 |
} |
| 834 |
|
| 835 |
return $entry_list_fields; |
| 836 |
} |
| 837 |
|
| 838 |
/** |
| 839 |
* Get all fields of a form that provide personally identifying information |
| 840 |
* |
| 841 |
* @since 1.6.1 |
| 842 |
* |
| 843 |
* @param array $form Form config |
| 844 |
* @param bool $ids_only Optional. If true, indexed array of field IDs is returned. If false, the default, array of field configs, keyed by field ID is returned. |
| 845 |
* @return array |
| 846 |
*/ |
| 847 |
public static function personally_identifying_fields(array $form, $ids_only = false ){ |
| 848 |
$fields = self::get_fields( $form, false ); |
| 849 |
$personally_identifying_fields = array(); |
| 850 |
if( ! empty( $fields ) ){ |
| 851 |
foreach ( $fields as $field_id => $field ){ |
| 852 |
if( Qcformbuilder_Forms_Field_Util::is_personally_identifying( $field, $form ) ){ |
| 853 |
$personally_identifying_fields[ $field_id ] = $field; |
| 854 |
} |
| 855 |
} |
| 856 |
} |
| 857 |
|
| 858 |
if( $ids_only ){ |
| 859 |
return array_keys( $personally_identifying_fields ); |
| 860 |
} |
| 861 |
|
| 862 |
return $personally_identifying_fields; |
| 863 |
} |
| 864 |
|
| 865 |
/** |
| 866 |
* Get all fields of a form that represents the email of someone who's personal information is in the form submssion. |
| 867 |
* |
| 868 |
* @since 1.7.0 |
| 869 |
* |
| 870 |
* @param array $form Form config |
| 871 |
* @param bool $ids_only Optional. If true, indexed array of field IDs is returned. If false, the default, array of field configs, keyed by field ID is returned. |
| 872 |
* @return array |
| 873 |
*/ |
| 874 |
public static function email_identifying_fields( array $form, $ids_only = false ){ |
| 875 |
$fields = self::get_fields( $form, false ); |
| 876 |
$matching_fields = array(); |
| 877 |
if( ! empty( $fields ) ){ |
| 878 |
foreach ( $fields as $field_id => $field ){ |
| 879 |
if( Qcformbuilder_Forms_Field_Util::is_email_identifying_field( $field, $form ) ){ |
| 880 |
$matching_fields[ $field_id ] = $field; |
| 881 |
} |
| 882 |
} |
| 883 |
} |
| 884 |
|
| 885 |
if( $ids_only ){ |
| 886 |
return array_keys( $matching_fields ); |
| 887 |
} |
| 888 |
|
| 889 |
return $matching_fields; |
| 890 |
} |
| 891 |
|
| 892 |
/** |
| 893 |
* Discover if a form has GDPR/privacy exporter enabled |
| 894 |
* |
| 895 |
* @since 1.7.0 |
| 896 |
* |
| 897 |
* @param array $form Form config |
| 898 |
* @return bool |
| 899 |
*/ |
| 900 |
public static function is_privacy_export_enabled(array $form ) |
| 901 |
{ |
| 902 |
return ! empty( $form[ 'privacy_exporter_enabled' ] ); |
| 903 |
} |
| 904 |
|
| 905 |
/** |
| 906 |
* Toggle enabling of GDPR/privacy exporter enabled |
| 907 |
* |
| 908 |
* Note, does not save. Use Qcformbuilder_Forms_Forms::save_form( Qcformbuilder_Forms_Forms::update_privacy_export_enabled( $form, true ) ) ); |
| 909 |
* |
| 910 |
* @since 1.7.0 |
| 911 |
* |
| 912 |
* @param array $form Form config |
| 913 |
* @param bool $enabled Optional. To enable or not. Default is true |
| 914 |
* |
| 915 |
* @return array |
| 916 |
*/ |
| 917 |
public static function update_privacy_export_enabled(array $form, $enabled = true ) |
| 918 |
{ |
| 919 |
$form[ 'privacy_exporter_enabled' ] = (bool) $enabled; |
| 920 |
return $form; |
| 921 |
|
| 922 |
} |
| 923 |
|
| 924 |
/** |
| 925 |
* Get all revisions of a forms |
| 926 |
* |
| 927 |
* @since 1.5.3 |
| 928 |
* |
| 929 |
* @param string $form_id Form ID |
| 930 |
* |
| 931 |
* @return array |
| 932 |
*/ |
| 933 |
public static function get_revisions( $form_id, $simple = false ){ |
| 934 |
$forms = Qcformbuilder_Forms_DB_Form::get_instance()->get_by_form_id( $form_id, false ); |
| 935 |
$revisions = array(); |
| 936 |
if( ! empty( $forms ) ){ |
| 937 |
foreach ( $forms as $i => $form ){ |
| 938 |
if( 'revision' === $form[ 'type' ] ){ |
| 939 |
if( empty( $form ) || ! isset( $form[ 'id' ] ) ){ |
| 940 |
continue; |
| 941 |
} |
| 942 |
if( $simple ){ |
| 943 |
$revisions[] = $form[ 'id' ]; |
| 944 |
}else{ |
| 945 |
$form = self::db_to_return( $form ); |
| 946 |
$revisions[] = self::filter_form( $form[ 'ID' ], $form, true ); |
| 947 |
} |
| 948 |
|
| 949 |
} |
| 950 |
} |
| 951 |
} |
| 952 |
|
| 953 |
|
| 954 |
return $revisions; |
| 955 |
} |
| 956 |
|
| 957 |
/** |
| 958 |
* Get a revision of a form |
| 959 |
* |
| 960 |
* @since 1.5.3 |
| 961 |
* |
| 962 |
* @param int $id Revision ID |
| 963 |
* |
| 964 |
* @return array |
| 965 |
*/ |
| 966 |
public static function get_revision( $id ){ |
| 967 |
$form = Qcformbuilder_Forms_DB_Form::get_instance()->get_record( $id ); |
| 968 |
$form = self::db_to_return( $form ); |
| 969 |
$form = self::filter_form( $form[ 'ID' ], $form, true ); |
| 970 |
return $form; |
| 971 |
} |
| 972 |
|
| 973 |
/** |
| 974 |
* If necessary migrate to database table added in Qcformbuilder Forms 1.5.3 |
| 975 |
* |
| 976 |
* @since 1.5.3 |
| 977 |
* |
| 978 |
* @param array $form Form config |
| 979 |
* |
| 980 |
* @return array|bool |
| 981 |
*/ |
| 982 |
protected static function maybe_migrate( array $form ){ |
| 983 |
$in_db = Qcformbuilder_Forms_DB_Form::get_instance()->get_by_form_id( $form[ 'ID' ] ); |
| 984 |
if( empty( $in_db ) ){ |
| 985 |
self::save_to_db( $form, 'primary' ); |
| 986 |
} |
| 987 |
|
| 988 |
return self::get_from_db( $form[ 'ID' ] ); |
| 989 |
} |
| 990 |
|
| 991 |
/** |
| 992 |
* Save form to database |
| 993 |
* |
| 994 |
* @param array $form Form config |
| 995 |
* @param string $type Optional. What type of form state is "primary" or "revision". Default is primary. |
| 996 |
* |
| 997 |
* @return bool|false|int|null |
| 998 |
*/ |
| 999 |
protected static function save_to_db( array $form, $type = 'primary' ){ |
| 1000 |
if( 'primary' !== $type ){ |
| 1001 |
$max_revisions = self::max_revisions( $form ); |
| 1002 |
if( ! $max_revisions ){ |
| 1003 |
return false; |
| 1004 |
} |
| 1005 |
} |
| 1006 |
|
| 1007 |
$data = array( |
| 1008 |
'form_id' => $form[ 'ID' ], |
| 1009 |
'config' => $form, |
| 1010 |
'type' => $type |
| 1011 |
); |
| 1012 |
|
| 1013 |
if( isset( $form[ 'db_id' ] ) ){ |
| 1014 |
$data[ 'db_id' ] = $form[ 'db_id' ]; |
| 1015 |
$db_id = Qcformbuilder_Forms_DB_Form::get_instance()->update( $data ); |
| 1016 |
self::maybe_delete_old_revisions( $form ); |
| 1017 |
}else{ |
| 1018 |
$db_id = Qcformbuilder_Forms_DB_Form::get_instance()->create( $data ); |
| 1019 |
|
| 1020 |
} |
| 1021 |
|
| 1022 |
|
| 1023 |
return $db_id; |
| 1024 |
} |
| 1025 |
|
| 1026 |
/** |
| 1027 |
* Get a form or forms (IE revisions of form) from database |
| 1028 |
* |
| 1029 |
* @since 1.5.3 |
| 1030 |
* |
| 1031 |
* @param string $form_id Form ID |
| 1032 |
* @param bool $primary_only Optional. Default is true, to only return primary form. False to include all revisions. |
| 1033 |
* |
| 1034 |
* @return array|bool |
| 1035 |
*/ |
| 1036 |
protected static function get_from_db( $form_id, $primary_only = true ){ |
| 1037 |
return Qcformbuilder_Forms_DB_Form::get_instance()->get_by_form_id( $form_id, $primary_only ); |
| 1038 |
|
| 1039 |
} |
| 1040 |
|
| 1041 |
/** |
| 1042 |
* Delete form revisions if there are more than the max revisions |
| 1043 |
* |
| 1044 |
* |
| 1045 |
* @since 1.5.3 |
| 1046 |
* |
| 1047 |
* @param array $form Form config |
| 1048 |
*/ |
| 1049 |
protected static function maybe_delete_old_revisions( array $form ){ |
| 1050 |
$revisions = self::get_revisions( $form[ 'ID' ], true); |
| 1051 |
if( ! empty( $revisions ) ) { |
| 1052 |
$max_revisions = self::max_revisions( $form ); |
| 1053 |
|
| 1054 |
if( $max_revisions < count( $revisions ) ){ |
| 1055 |
sort( $revisions ); |
| 1056 |
$deletes = array(); |
| 1057 |
foreach ( $revisions as $key => $id ){ |
| 1058 |
if( $key + 1 < $max_revisions ){ |
| 1059 |
$deletes[] = $id; |
| 1060 |
} |
| 1061 |
} |
| 1062 |
Qcformbuilder_Forms_DB_Form::get_instance()->delete( $deletes ); |
| 1063 |
|
| 1064 |
} |
| 1065 |
|
| 1066 |
} |
| 1067 |
|
| 1068 |
} |
| 1069 |
|
| 1070 |
/** |
| 1071 |
* Order forms by a value |
| 1072 |
* |
| 1073 |
* @since 1.5.6 |
| 1074 |
* |
| 1075 |
* @param array $forms Forms to sort. |
| 1076 |
* @param string $by Optional. Default is "name" as of 1.5.6, no other values are allowed. |
| 1077 |
* |
| 1078 |
* @return array|mixed|void |
| 1079 |
*/ |
| 1080 |
protected static function order_forms( array $forms, $by = 'name' ){ |
| 1081 |
if( ! in_array( $by, array( |
| 1082 |
'name', |
| 1083 |
))){ |
| 1084 |
$by = 'name'; |
| 1085 |
} |
| 1086 |
|
| 1087 |
if( ! empty( $forms ) ){ |
| 1088 |
$values = array_values($forms); |
| 1089 |
|
| 1090 |
if( ! is_array( $values[0] ) ) { |
| 1091 |
$forms = self::get_forms( true ); |
| 1092 |
} |
| 1093 |
} |
| 1094 |
|
| 1095 |
if( empty( $forms ) ){ |
| 1096 |
return $forms; |
| 1097 |
} |
| 1098 |
|
| 1099 |
switch( $by ) { |
| 1100 |
case 'name' : |
| 1101 |
default : |
| 1102 |
$map = array_combine( wp_list_pluck( $forms, $by ), array_keys( $forms ) ); |
| 1103 |
|
| 1104 |
break; |
| 1105 |
} |
| 1106 |
|
| 1107 |
ksort( $map, SORT_ASC ); |
| 1108 |
$final = array(); |
| 1109 |
foreach( $map as $name => $id ){ |
| 1110 |
$final[ $id ] = $forms[ $id ]; |
| 1111 |
} |
| 1112 |
|
| 1113 |
return $final; |
| 1114 |
|
| 1115 |
|
| 1116 |
} |
| 1117 |
|
| 1118 |
/** |
| 1119 |
* Create a unique form ID |
| 1120 |
* |
| 1121 |
* @since 1.6.0 |
| 1122 |
* |
| 1123 |
* @return string |
| 1124 |
*/ |
| 1125 |
public static function create_unique_form_id(){ |
| 1126 |
return uniqid( 'CF' ); |
| 1127 |
} |
| 1128 |
} |
| 1129 |
|
| 1130 |
|
| 1131 |
|