Overview

Classes

  • GF_Personal_Data
  • GFAddOn
  • GFAddOnFeedsTable
  • GFAPI
  • GFFeedAddOn
  • GFPaymentAddOn
  • GFPaymentStatsTable
  • Overview
  • Class
   1: <?php
   2: 
   3: if ( ! class_exists( 'GFForms' ) ) {
   4:     die();
   5: }
   6: 
   7: /**
   8:  * Handles Integration with the WordPress personal data export and erase tools.
   9:  *
  10:  * @since 2.4
  11:  *
  12:  * Class GF_Personal_Data
  13:  */
  14: class GF_Personal_Data {
  15: 
  16:     /**
  17:      * The cached form array.
  18:      *
  19:      * @since 2.4
  20:      *
  21:      * @var array $form
  22:      */
  23:     private static $_form;
  24: 
  25:     /**
  26:      * The cached array of forms.
  27:      *
  28:      * @since 2.4
  29:      *
  30:      * @var array $forms
  31:      */
  32:     private static $_forms;
  33: 
  34:     /**
  35:      * Renders the form settings.
  36:      *
  37:      * @since 2.4
  38:      *
  39:      * @param $form_id
  40:      */
  41:     public static function form_settings( $form_id ) {
  42: 
  43:         $form = self::get_form( $form_id );
  44: 
  45:         $form_personal_data_settings = rgar( $form, 'personalData' );
  46: 
  47:         $action_url = admin_url( sprintf( 'admin.php?page=gf_edit_forms&view=settings&subview=personal-data&id=%d', $form_id ) );
  48: 
  49:         $enabled = (bool) rgars( $form_personal_data_settings, 'exportingAndErasing/enabled' );
  50: 
  51:         $prevent_ip = (bool) rgar( $form_personal_data_settings, 'preventIP' );
  52: 
  53:         $retention_policy = rgars( $form_personal_data_settings, 'retention/policy' );
  54: 
  55:         if ( empty( $retention_policy ) ) {
  56:             $retention_policy = 'retain';
  57:         }
  58: 
  59:         $retention_days = rgars( $form_personal_data_settings, 'retention/retain_entries_days' );
  60: 
  61:         if ( empty( $retention_days ) ) {
  62:             $retention_days = 1;
  63:         }
  64: 
  65:         ?>
  66:         <h3><span><i class="fa fa-lock"></i> <?php esc_html_e( 'Personal Data', 'gravityforms' ); ?>
  67:         </h3>
  68:         <div class="gform_panel gform_panel_form_settings" id="gf_personal_data_settings">
  69:             <form action="<?php esc_url( $action_url ); ?>" method="POST">
  70:                 <?php wp_nonce_field( 'gravityforms_personal_data' ); ?>
  71:                 <table class="gforms_form_settings" cellspacing="0" cellpadding="0">
  72:                     <tr>
  73:                         <td colspan="2">
  74:                             <h4 class="gf_settings_subgroup_title"><?php esc_html_e( 'General Settings', 'gravityforms' ); ?></h4>
  75:                         </td>
  76:                     </tr>
  77:                     <tr>
  78:                         <th>
  79:                             <?php esc_html_e( 'IP Addresses', 'gravityforms' ); ?>
  80:                             <?php gform_tooltip( 'personal_data_prevent_ip' ); ?>
  81:                         </th>
  82:                         <td>
  83:                             <label for="gf_personal_data_prevent_ip">
  84:                                 <input
  85:                                     id="gf_personal_data_prevent_ip"
  86:                                     type="checkbox"
  87:                                     name="prevent_ip"
  88:                                     <?php checked( true, $prevent_ip ); ?>
  89:                                 />
  90:                                 <?php esc_html_e( 'Prevent the storage of IP addresses during form submission.', 'gravityforms' ); ?>
  91:                             </label>
  92:                         </td>
  93:                     </tr>
  94:                     <tr>
  95:                         <th>
  96:                             <?php esc_html_e( 'Retention Policy', 'gravityforms' ); ?>
  97:                             <?php gform_tooltip( 'personal_data_retention_policy' ); ?>
  98:                         </th>
  99:                         <td>
 100:                             <label for="gf_personal_data_retention_do_not_delete">
 101:                                 <input
 102:                                     id="gf_personal_data_retention_do_not_delete"
 103:                                     type="radio"
 104:                                     name="retention"
 105:                                     value="retain"
 106:                                     <?php checked( 'retain', $retention_policy ); ?>
 107:                                 />
 108:                                 <?php esc_html_e( 'Retain entries indefinitely', 'gravityforms' ); ?>
 109:                             </label>
 110:                             <br/>
 111:                             <label for="gf_personal_data_retention_trash">
 112:                                 <input
 113:                                     id="gf_personal_data_retention_trash"
 114:                                     type="radio"
 115:                                     name="retention"
 116:                                     value="trash"
 117:                                     <?php checked( 'trash', $retention_policy ); ?>
 118:                                 />
 119:                                 <?php esc_html_e( 'Trash entries automatically', 'gravityforms' ); ?>
 120:                             </label>
 121:                             <br/>
 122:                             <label for="gf_personal_data_retention_delete">
 123:                                 <input
 124:                                     id="gf_personal_data_retention_delete"
 125:                                     type="radio"
 126:                                     name="retention"
 127:                                     value="delete"
 128:                                     <?php checked( 'delete', $retention_policy ); ?>
 129:                                 />
 130:                                 <?php esc_html_e( 'Delete entries permanently automatically', 'gravityforms' ); ?>
 131:                             </label>
 132:                             <div id="gf_personal_data_retain_entries_days_container" style="<?php echo( $retention_policy !== 'retain' ? '' : 'display:none' ) ?>">
 133:                                 <label for="gf_personal_data_retain_entries_days_container">
 134:                                     <?php esc_html_e( 'Number of days to retain entries before trashing/deleting:', 'gravityforms' ); ?>
 135:                                     <input
 136:                                         id="gf_personal_data_retain_entries_days"
 137:                                         type="text"
 138:                                         class="small-text"
 139:                                         name="retain_entries_days"
 140:                                         value="<?php echo absint( $retention_days ); ?>"
 141:                                     />
 142:                                 </label>
 143:                             </div>
 144:                         </td>
 145:                     </tr>
 146:                     <tr>
 147:                         <td colspan="2">
 148:                             <h4 class="gf_settings_subgroup_title"><?php esc_html_e( 'Exporting and Erasing Data', 'gravityforms' ); ?></h4>
 149:                         </td>
 150:                     </tr>
 151:                     <?php
 152:                     $identification_field_choices = array();
 153: 
 154:                     $email_fields = GFAPI::get_fields_by_type( $form, 'email' );
 155: 
 156:                     foreach ( $email_fields as $email_field ) {
 157:                         $identification_field_choices[ (string) $email_field->id ] = $email_field->label;
 158:                     }
 159: 
 160:                     /**
 161:                     * Allows the list of personal data identification field choices to be modified. Fields values
 162:                     * will be treated as user IDs.
 163:                     *
 164:                     * For example, add the created_by field by returning:
 165:                     * $identification_field_choices['created_by'] = 'Created By';
 166:                     *
 167:                     * @since 2.4
 168:                     *
 169:                     * @param array $identification_field_choices An associative array with the field id as the key and the value as the label.
 170:                     * @param array $form                         The current form.
 171:                     */
 172:                     $identification_field_choices = gf_apply_filters( array( 'gform_personal_data_identification_fields', $form['id'] ), $identification_field_choices, $form );
 173: 
 174:                     $no_id = empty( $identification_field_choices );
 175: 
 176:                     $lookup_field = rgars( $form, 'personalData/exportingAndErasing/identificationField' );
 177: 
 178:                     if ( $no_id ) {
 179:                         if ( $lookup_field == 'created_by' ) {
 180: 
 181:                             $no_id = false;
 182: 
 183:                             $identification_field_choices = array(
 184:                                 'created_by' => __( 'Created By', 'gravityforms' ),
 185:                             );
 186: 
 187:                         } elseif ( $selected_field = GFFormsModel::get_field( $form, $lookup_field ) ) {
 188: 
 189:                             $no_id = false;
 190: 
 191:                             $selected_field->set_context_property( 'use_admin_label', true );
 192: 
 193:                             $choice_label = GFFormsModel::get_label( $selected_field );
 194: 
 195:                             $identification_field_choices = array(
 196:                                 $lookup_field => $choice_label,
 197:                             );
 198: 
 199:                         } else {
 200:                             $enabled = false;
 201:                         }
 202:                     }
 203:                     ?>
 204:                     <tr>
 205:                         <th>
 206:                             <?php esc_html_e( 'Enable', 'gravityforms' ); ?>
 207:                             <?php gform_tooltip( 'personal_data_enable' ); ?>
 208:                         </th>
 209:                         <td>
 210:                             <label for="gf_personal_data_enable">
 211:                                 <input
 212:                                     id="gf_personal_data_enable"
 213:                                     type="checkbox"
 214:                                     name="exporting_and_erasing_enabled"
 215:                                     <?php checked( true, $enabled ); ?>
 216:                                     <?php disabled( true, $no_id ); ?>
 217:                                 />
 218:                                 <?php esc_html_e( 'Enable integration with the WordPress tools for exporting and erasing personal data.', 'gravityforms' ); ?>
 219:                             </label>
 220:                         </td>
 221:                     </tr>
 222:                     <?php
 223: 
 224:                     if ( ! $no_id ) {
 225:                         ?>
 226:                         <tr class="gf_personal_data_settings" style="<?php echo( $enabled ? '' : 'display:none;' ); ?>">
 227:                             <th>
 228:                                 <?php esc_html_e( 'Identification Field', 'gravityforms' ); ?>
 229:                                 <?php gform_tooltip( 'personal_data_identification' ); ?>
 230:                             </th>
 231:                             <td>
 232:                                 <select name="identification_field">
 233:                                     <?php
 234:                                     echo sprintf( '<option value="">%s</option>', esc_html__( 'Select a Field', 'gravityforms' ) );
 235:                                     foreach ( $identification_field_choices as $id => $label ) {
 236:                                         $selected = selected( $id, $lookup_field, false );
 237:                                         echo sprintf( '<option %s value="%s">%s</option>', $selected, $id, $label );
 238:                                     }
 239:                                     ?>
 240:                                 </select>
 241:                             </td>
 242:                         </tr>
 243: 
 244:                         <tr class="gf_personal_data_settings" style="<?php echo( $enabled ? '' : 'display:none;' ); ?>">
 245:                         <th>
 246:                             <?php esc_html_e( 'Personal Data', 'gravityforms' ); ?>
 247:                             <?php gform_tooltip( 'personal_data_field_settings' ); ?>
 248: 
 249:                         </th>
 250:                         <td>
 251:                             <table id="gf_personal_data_field_settings">
 252:                                 <thead>
 253:                                 <tr>
 254:                                     <th class="gf_personal_data_field_label_title"><?php esc_html_e( 'Fields', 'gravityforms' ); ?></th>
 255:                                     <th class="gf_personal_data_cb_title"><?php esc_html_e( 'Export', 'gravityforms' ); ?></th>
 256:                                     <th class="gf_personal_data_cb_title"><?php esc_html_e( 'Erase', 'gravityforms' ); ?></th>
 257:                                 </tr>
 258:                                 </thead>
 259:                                 <tbody>
 260:                                 <tr>
 261:                                     <td>
 262:                                         <?php esc_html_e( 'Select/Deselect All', 'gravityforms' ); ?>
 263:                                     </td>
 264:                                     <td class="gf_personal_data_cb_cell">
 265:                                         <input
 266:                                             id="gf_personal_data_export_all"
 267:                                             type="checkbox"
 268:                                         />
 269:                                     </td>
 270:                                     <td class="gf_personal_data_cb_cell">
 271:                                         <input
 272:                                             id="gf_personal_data_erase_all"
 273:                                             type="checkbox"
 274:                                         />
 275:                                     </td>
 276:                                 </tr>
 277:                                 <?php
 278: 
 279:                                 $columns = self::get_columns();
 280: 
 281:                                 $all_column_settings = rgars( $form_personal_data_settings, 'exportingAndErasing/columns' );
 282: 
 283:                                 foreach ( $columns as $key => $label ) {
 284:                                     $column_settings = rgar( $all_column_settings, $key );
 285:                                     ?>
 286:                                     <tr>
 287:                                         <td>
 288:                                             <?php echo esc_html( $label ); ?>
 289:                                         </td>
 290:                                         <td class="gf_personal_data_cb_cell">
 291:                                             <input
 292:                                                 class="gf_personal_data_cb_export"
 293:                                                 type="checkbox"
 294:                                                 name="export_fields[<?php echo esc_attr( $key ); ?>]"
 295:                                                 <?php checked( true, (bool) rgar( $column_settings, 'export' ) ); ?>
 296:                                             />
 297:                                         </td>
 298:                                         <td class="gf_personal_data_cb_cell">
 299:                                             <input
 300:                                                 class="gf_personal_data_cb_erase"
 301:                                                 type="checkbox"
 302:                                                 name="erase_fields[<?php echo esc_attr( $key ); ?>]"
 303:                                                 <?php checked( true, (bool) rgar( $column_settings, 'erase' ) ); ?>
 304:                                             />
 305:                                         </td>
 306:                                     </tr>
 307:                                     <?php
 308:                                 }
 309: 
 310:                                 /* @var GF_Field[] $fields */
 311:                                 $fields = $form['fields'];
 312: 
 313:                                 foreach ( $fields as $field ) {
 314: 
 315:                                     if ( $field->displayOnly ) {
 316:                                         // Skip display-only fields such as HTML, Section and Page fields.
 317:                                         continue;
 318:                                     }
 319: 
 320:                                     $field->set_context_property( 'use_admin_label', true );
 321: 
 322:                                     ?>
 323:                                     <tr>
 324:                                         <td>
 325:                                             <?php echo esc_html( GFFormsModel::get_label( $field ) ); ?>
 326:                                         </td>
 327:                                         <td class="gf_personal_data_cb_cell">
 328:                                             <input
 329:                                                 class="gf_personal_data_cb_export"
 330:                                                 type="checkbox"
 331:                                                 name="export_fields[<?php echo absint( $field->id ); ?>]"
 332:                                                 <?php checked( true, (bool) $field->personalDataExport ); ?>
 333:                                             />
 334:                                         </td>
 335:                                         <td class="gf_personal_data_cb_cell">
 336:                                             <input
 337:                                                 class="gf_personal_data_cb_erase"
 338:                                                 type="checkbox"
 339:                                                 name="erase_fields[<?php echo absint( $field->id ); ?>]"
 340:                                                 <?php checked( true, (bool) $field->personalDataErase ); ?>
 341:                                             />
 342:                                         </td>
 343:                                     </tr>
 344:                                     <?php
 345:                                 }
 346: 
 347:                                 $custom_items = self::get_custom_items( $form );
 348: 
 349:                                 if ( ! empty( $custom_items ) ) {
 350: 
 351:                                     ?>
 352:                                     <tr>
 353:                                         <th class="gf_personal_data_field_label_title" colspan="3">
 354:                                             <?php esc_html_e( 'Other Data', 'gravityforms' ) ?>
 355:                                         </th>
 356:                                     </tr>
 357:                                     <?php
 358: 
 359:                                     $custom_items_settings = rgars( $form_personal_data_settings, 'exportingAndErasing/custom' );
 360: 
 361:                                     foreach ( $custom_items as $key => $custom_item_details ) {
 362:                                         $custom_settings = rgar( $custom_items_settings, $key );
 363:                                         $label           = rgar( $custom_item_details, 'label' );
 364:                                         ?>
 365:                                         <tr>
 366:                                             <td>
 367:                                                 <?php echo esc_html( $label ); ?>
 368:                                             </td>
 369:                                             <td class="gf_personal_data_cb_cell">
 370:                                                 <?php
 371:                                                 if ( isset( $custom_item_details['exporter_callback'] ) && is_callable( $custom_item_details['exporter_callback'] ) ) {
 372:                                                     ?>
 373:                                                     <input
 374:                                                         class="gf_personal_data_cb_export"
 375:                                                         type="checkbox"
 376:                                                         name="export_fields[<?php echo esc_attr( $key ); ?>]"
 377:                                                         <?php checked( true, (bool) rgar( $custom_settings, 'export' ) ); ?>
 378:                                                     />
 379:                                                     <?php
 380:                                                 }
 381:                                                 ?>
 382:                                             </td>
 383:                                             <td class="gf_personal_data_cb_cell">
 384:                                                 <?php
 385:                                                 if ( isset( $custom_item_details['eraser_callback'] ) && is_callable( $custom_item_details['eraser_callback'] ) ) {
 386:                                                     ?>
 387:                                                     <input
 388:                                                         class="gf_personal_data_cb_erase"
 389:                                                         type="checkbox"
 390:                                                         name="erase_fields[<?php echo esc_attr( $key ); ?>]"
 391:                                                         <?php checked( true, (bool) rgar( $custom_settings, 'erase' ) ); ?>
 392:                                                     />
 393:                                                     <?php
 394:                                                 }
 395:                                                 ?>
 396:                                             </td>
 397:                                         </tr>
 398:                                         <?php
 399:                                     }
 400:                                 }
 401: 
 402:                                 ?>
 403:                                 </tbody>
 404:                             </table>
 405:                         </td>
 406:                     </tr>
 407: 
 408:                         <?php
 409:                     } else {
 410:                         ?>
 411:                         <tr>
 412:                             <th></th>
 413:                             <td>
 414:                                 <div class="alert_red" style="padding:15px;">
 415:                                     <?php esc_html_e( 'You must add an email address field to the form in order to enable this setting.', 'gravityforms' ); ?>
 416:                                 </div>
 417:                             </td>
 418:                         </tr>
 419:                         <?php
 420:                     }
 421:                     ?>
 422: 
 423:                 </table>
 424:                 <input
 425:                     class="button-primary"
 426:                     type="submit"
 427:                     name="save_personal_data_settings"
 428:                     value="<?php esc_attr_e( 'Save', 'gravityforms' ); ?>"
 429:                 />
 430:             </form>
 431:         </div>
 432:         <script>
 433:             jQuery(document).ready(function ($) {
 434:                 $('#gf_personal_data_enable').change(function () {
 435:                     if ($(this).is(":checked")) {
 436:                         $('.gf_personal_data_settings').show();
 437:                     } else {
 438:                         $('.gf_personal_data_settings').hide();
 439:                     }
 440:                 });
 441:                 $('#gf_personal_data_export_all').change(function () {
 442:                     if ($(this).is(":checked")) {
 443:                         $('.gf_personal_data_cb_export').prop('checked', true);
 444:                     } else {
 445:                         $('.gf_personal_data_cb_export').prop('checked', false);
 446:                     }
 447:                 });
 448:                 $('#gf_personal_data_erase_all').change(function () {
 449:                     if ($(this).is(":checked")) {
 450:                         $('.gf_personal_data_cb_erase').prop('checked', true);
 451:                     } else {
 452:                         $('.gf_personal_data_cb_erase').prop('checked', false);
 453:                     }
 454:                 });
 455:                 $("input[name='lookup']").change(function () {
 456:                     if ($(this).val() == 'identifying_email_field') {
 457:                         $('#gf_personal_data_email_field_select').fadeIn();
 458:                     } else {
 459:                         $('#gf_personal_data_email_field_select').hide();
 460:                     }
 461:                 });
 462:                 $("input[name='retention']").change(function () {
 463:                     if ($(this).val() == 'retain') {
 464:                         $('#gf_personal_data_retain_entries_days_container').hide();
 465:                     } else {
 466:                         alert( <?php echo json_encode( __( 'Warning: this will affect all entries that are older than the number of days specified.', 'gravityforms' ) ) ?> );
 467:                         $('#gf_personal_data_retain_entries_days_container').fadeIn();
 468:                     }
 469:                 });
 470: 
 471:             });
 472:         </script>
 473:         <?php
 474:     }
 475: 
 476:     /**
 477:      * Saves the form settings.
 478:      *
 479:      * @since 2.4
 480:      *
 481:      * @param $form_id
 482:      */
 483:     public static function process_form_settings( $form_id ) {
 484:         check_admin_referer( 'gravityforms_personal_data' );
 485: 
 486:         $form = self::get_form( $form_id );
 487: 
 488:         $posted_export_fields = rgpost( 'export_fields' );
 489: 
 490:         $posted_erase_fields = rgpost( 'erase_fields' );
 491: 
 492:         $columns = self::get_columns();
 493: 
 494:         if ( ! isset( $form['personalData'] ) ) {
 495:             $form['personalData'] = array();
 496:         }
 497: 
 498:         $form_personal_data_settings = $form['personalData'];
 499: 
 500:         $form_personal_data_settings['preventIP'] = (bool) rgpost( 'prevent_ip' );
 501: 
 502:         $retention_policy = rgpost( 'retention' );
 503: 
 504:         // Whitelist the policy
 505:         $retention_policy = in_array( $retention_policy, array(
 506:             'retain',
 507:             'trash',
 508:             'delete',
 509:         ) ) ? $retention_policy : 'retain';
 510: 
 511:         $retain_entries_days = absint( rgpost( 'retain_entries_days' ) );
 512: 
 513:         if ( empty( $retain_entries_days ) ) {
 514:             // Minimum to ensure the cron task doesn't delete the entry before all processing is complete.
 515:             $retain_entries_days = 1;
 516:         }
 517: 
 518: 
 519:         $form_personal_data_settings['retention'] = array(
 520:             'policy'              => $retention_policy,
 521:             'retain_entries_days' => $retain_entries_days,
 522:         );
 523: 
 524:         if ( ! isset( $form_personal_data_settings['exportingAndErasing'] ) ) {
 525:             $form_personal_data_settings['exportingAndErasing'] = array();
 526:         }
 527: 
 528:         $exporting_and_erasing = $form_personal_data_settings['exportingAndErasing'];
 529: 
 530:         if ( ! isset( $exporting_and_erasing['columns'] ) ) {
 531:             $exporting_and_erasing['columns'] = array();
 532:         }
 533: 
 534:         $exporting_and_erasing['enabled'] = (bool) rgpost( 'exporting_and_erasing_enabled' );
 535: 
 536:         if ( ! $exporting_and_erasing['enabled'] ) {
 537:             $exporting_and_erasing['identificationField'] = '';
 538:         } else {
 539:             $exporting_and_erasing['identificationField'] = sanitize_text_field( rgpost( 'identification_field' ) );
 540:         }
 541: 
 542:         $all_column_settings = $exporting_and_erasing['columns'];
 543: 
 544:         foreach ( $columns as $key => $label ) {
 545:             $column_settings = array(
 546:                 'export' => (bool) rgar( $posted_export_fields, $key ),
 547:                 'erase'  => (bool) rgar( $posted_erase_fields, $key ),
 548:             );
 549: 
 550:             $all_column_settings[ $key ] = $column_settings;
 551:         }
 552: 
 553:         $exporting_and_erasing['columns'] = $all_column_settings;
 554: 
 555: 
 556:         /* @var GF_Field[] $fields */
 557:         $fields = $form['fields'];
 558: 
 559:         foreach ( $fields as &$field ) {
 560:             $field->personalDataExport = (bool) rgar( $posted_export_fields, $field->id );
 561:             $field->personalDataErase  = (bool) rgar( $posted_erase_fields, $field->id );
 562:         }
 563: 
 564:         $custom_items = self::get_custom_items( $form );
 565: 
 566:         if ( ! empty( $custom_items ) ) {
 567:             $custom_items_settings = rgar( $exporting_and_erasing, 'custom' ) ? $exporting_and_erasing['custom'] : array();
 568: 
 569:             foreach ( array_keys( $custom_items ) as $custom_item_key ) {
 570:                 $custom_item_settings = array(
 571:                     'export' => (bool) rgar( $posted_export_fields, $custom_item_key ),
 572:                     'erase'  => (bool) rgar( $posted_erase_fields, $custom_item_key ),
 573:                 );
 574: 
 575:                 $custom_items_settings[ $custom_item_key ] = $custom_item_settings;
 576:             }
 577: 
 578:             $exporting_and_erasing['custom'] = $custom_items_settings;
 579:         }
 580: 
 581:         $form_personal_data_settings['exportingAndErasing'] = $exporting_and_erasing;
 582: 
 583:         $form['personalData'] = $form_personal_data_settings;
 584: 
 585:         GFAPI::update_form( $form );
 586:         self::$_form = $form;
 587:         ?>
 588:         <div class="updated below-h2" id="after_update_dialog">
 589:             <p>
 590:                 <strong><?php _e( 'Personal data settings updated successfully.', 'gravityforms' ); ?></strong>
 591:             </p>
 592:         </div>
 593:         <?php
 594:     }
 595: 
 596:     /**
 597:      * Returns the form array for use in the form settings.
 598:      *
 599:      * @since 2.4
 600:      *
 601:      * @param int $form_id
 602:      *
 603:      * @return array|mixed
 604:      */
 605:     public static function get_form( $form_id ) {
 606:         if ( empty( self::$_form ) ) {
 607:             self::$_form = GFAPI::get_form( $form_id );
 608:         }
 609: 
 610:         return self::$_form;
 611:     }
 612: 
 613:     /**
 614:      * Returns an assoiative array of the database columns that may contain personal data.
 615:      *
 616:      * @since 2.4
 617:      *
 618:      * @return array
 619:      */
 620:     public static function get_columns() {
 621:         $columns = array(
 622:             'ip'         => esc_html__( 'IP Address', 'gravityforms' ),
 623:             'source_url' => esc_html__( 'Embed URL', 'gravityforms' ),
 624:             'user_agent' => esc_html__( 'Browser details', 'gravityforms' ),
 625:         );
 626: 
 627:         return $columns;
 628:     }
 629: 
 630:     /**
 631:      * Returns an array with the custom personal data items configurations.
 632:      *
 633:      * @since 2.4
 634:      *
 635:      * @param array $form
 636:      *
 637:      * @return array
 638:      */
 639:     public static function get_custom_items( $form ) {
 640: 
 641:         $custom_items = array();
 642: 
 643:         /**
 644:          * Allows custom exporter and erasers to be registered.
 645:          *
 646:          * Example:
 647:          *
 648:          * add_filter( 'gform_personal_data', 'filter_gform_personal_data', 10, 2 );
 649:          * function filter_gform_personal_data( $items, $form ) {
 650:          *       $items['test'] = array(
 651:          *          'label'             => 'A custom item',
 652:          *          'exporter_callback' => 'gf_custom_data_exporter',
 653:          *          'eraser_callback'   => 'gf_custom_data_eraser',
 654:          *      );
 655:          *
 656:          *      return $items;
 657:          * }
 658:          *
 659:          * function gf_custom_data_exporter( $form, $entry ) {
 660:          *       $data = array(
 661:          *        'name'  => 'My Custom Value',
 662:          *          'value' => 'ABC123',
 663:          *      );
 664:          *      return $data;
 665:          * }
 666:          *
 667:          * function gf_custom_data_eraser( $form, $entry ) {
 668:          *      // Delete or anonymize some data
 669:          * }
 670:          *
 671:          * @since 2.4
 672:          *
 673:          * @param array $custom_items
 674:          * @param array $form
 675:          */
 676:         $custom_items = apply_filters( 'gform_personal_data', $custom_items, $form );
 677: 
 678:         return $custom_items;
 679:     }
 680: 
 681:     /**
 682:      * Returns an associative array of all the form metas with the form ID as the key.
 683:      *
 684:      * @since 2.4
 685:      *
 686:      * @return array|null
 687:      */
 688:     public static function get_forms() {
 689: 
 690:         if ( is_null( self::$_forms ) ) {
 691:             $form_ids = GFFormsModel::get_form_ids();
 692: 
 693:             if ( empty( $form_ids ) ) {
 694:                 return array(
 695:                     'data' => array(),
 696:                     'done' => true,
 697:                 );
 698:             }
 699: 
 700:             $forms_by_id = GFFormsModel::get_form_meta_by_id( $form_ids );
 701: 
 702:             self::$_forms = array();
 703:             foreach ( $forms_by_id as $form ) {
 704:                 self::$_forms[ $form['id'] ] = $form;
 705:             }
 706:         }
 707: 
 708:         return self::$_forms;
 709:     }
 710: 
 711:     /**
 712:      * Returns all the entries across all forms for the specified email address.
 713:      *
 714:      * @since 2.4
 715:      *
 716:      * @param string    $email_address
 717:      * @param int $page
 718:      * @param int $limit
 719:      *
 720:      * @return array
 721:      */
 722:     public static function get_entries( $email_address, $page = 1, $limit = 50 ) {
 723: 
 724:         $user = get_user_by( 'email', $email_address );
 725: 
 726:         $forms = self::get_forms();
 727: 
 728:         $form_ids = array();
 729: 
 730:         $query = new GF_Query();
 731: 
 732:         $conditions = array();
 733: 
 734:         foreach ( $forms as $form ) {
 735: 
 736:             if ( ! rgars( $form, 'personalData/exportingAndErasing/enabled' ) ) {
 737:                 continue;
 738:             }
 739: 
 740:             $form_ids[] = $form['id'];
 741: 
 742:             $identification_field = rgars( $form, 'personalData/exportingAndErasing/identificationField' );
 743: 
 744:             $field = GFAPI::get_field( $form, $identification_field );
 745: 
 746:             if ( $field && $field->get_input_type() == 'email' ) {
 747: 
 748:                 $conditions[] = new GF_Query_Condition(
 749:                     new GF_Query_Column( $identification_field, $form['id'] ),
 750:                     GF_Query_Condition::EQ,
 751:                     new GF_Query_Literal( $email_address )
 752:                 );
 753: 
 754:             } else {
 755: 
 756:                 if ( ! $field && $identification_field != 'created_by' ) {
 757:                     continue;
 758:                 }
 759: 
 760:                 if ( ! $user ) {
 761:                     continue;
 762:                 }
 763: 
 764:                 $conditions[] = new GF_Query_Condition(
 765:                     new GF_Query_Column( $identification_field, $form['id'] ),
 766:                     GF_Query_Condition::EQ,
 767:                     new GF_Query_Literal( $user->ID )
 768:                 );
 769:             }
 770:         }
 771: 
 772:         if ( empty( $conditions ) ) {
 773:             return array();
 774:         }
 775: 
 776:         $all_conditions = call_user_func_array( array( 'GF_Query_Condition', '_or' ), $conditions );
 777: 
 778:         $entries = $query->from( $form_ids )->where( $all_conditions )->limit( $limit )->page( $page )->get();
 779: 
 780:         return $entries;
 781:     }
 782: 
 783:     /**
 784:      * Exports personal data specified in the form settings.
 785:      *
 786:      * @since 2.4
 787:      *
 788:      * @param string    $email_address
 789:      * @param int $page
 790:      *
 791:      * @return array
 792:      */
 793:     public static function data_exporter( $email_address, $page = 1 ) {
 794: 
 795:         $export_items = array(
 796:             'done' => true,
 797:         );
 798: 
 799:         $export_data = array();
 800: 
 801:         if ( $page == 1 ) {
 802:             $export_data = self::get_draft_submissions_export_items( $email_address );
 803:         }
 804: 
 805:         $export_items['data'] = $export_data;
 806: 
 807:         $limit = 50;
 808: 
 809:         $columns = self::get_columns();
 810: 
 811:         $forms = self::get_forms();
 812: 
 813:         $entries = self::get_entries( $email_address, $page, $limit );
 814: 
 815:         if ( empty( $entries ) ) {
 816:             return $export_items;
 817:         }
 818: 
 819:         foreach ( $entries as $entry ) {
 820: 
 821:             $data = array();
 822: 
 823:             $form_id = $entry['form_id'];
 824: 
 825:             $form = $forms[ $form_id ];
 826: 
 827:             $item_id = "gf-entry-{$entry['id']}";
 828: 
 829:             $group_id = 'gravityforms-entries';
 830: 
 831:             $group_label = __( 'Forms', 'gravityforms' );
 832: 
 833:             $columns_settings = rgars( $forms, $form_id . '/personalData/exportingAndErasing/columns' );
 834: 
 835:             if ( is_array( $columns_settings ) ) {
 836:                 foreach ( $columns_settings as $column_key => $column_settings ) {
 837:                     if ( rgar( $column_settings, 'export' ) ) {
 838:                         $data[] = array(
 839:                             'name'  => $columns[ $column_key ],
 840:                             'value' => $entry[ $column_key ],
 841:                         );
 842:                     }
 843:                 }
 844:             }
 845: 
 846:             foreach ( $form['fields'] as $field ) {
 847:                 /* @var GF_Field $field */
 848:                 if ( $field->personalDataExport ) {
 849:                     $value  = GFFormsModel::get_lead_field_value( $entry, $field );
 850:                     $data[] = array(
 851:                         'name'  => $field->get_field_label( false, $value ),
 852:                         'value' => $field->get_value_entry_detail( $value, rgar( $entry, 'currency' ), true, 'text' ),
 853:                     );
 854:                 }
 855:             }
 856: 
 857:             $custom_items = self::get_custom_items( $form );
 858: 
 859:             if ( ! empty( $custom_items ) ) {
 860:                 $all_custom_settings = rgars( $forms, $form_id . '/personalData/exportingAndErasing/custom' );
 861:                 foreach ( $custom_items as $custom_item_key => $custom_item_details ) {
 862:                     $custom_settings = rgar( $all_custom_settings, $custom_item_key );
 863:                     if ( rgars( $custom_settings, 'export' ) && isset( $custom_item_details['exporter_callback'] ) && is_callable( $custom_item_details['exporter_callback'] ) ) {
 864:                         $data[] = call_user_func( $custom_item_details['exporter_callback'], $form, $entry );
 865:                     }
 866:                 }
 867:             }
 868: 
 869:             if ( ! empty( $data ) ) {
 870:                 $export_data[] = array(
 871:                     'group_id'    => $group_id,
 872:                     'group_label' => $group_label,
 873:                     'item_id'     => $item_id,
 874:                     'data'        => $data,
 875:                 );
 876:             }
 877:         }
 878: 
 879:         $done = count( $entries ) < $limit;
 880: 
 881:         $export_items = array(
 882:             'data' => $export_data,
 883:             'done' => $done,
 884:         );
 885: 
 886:         return $export_items;
 887:     }
 888: 
 889:     /**
 890:      * Returns the export items for draft submissions.
 891:      *
 892:      * @since 2.4
 893:      *
 894:      * @param $email_address
 895:      *
 896:      * @return array
 897:      */
 898:     public static function get_draft_submissions_export_items( $email_address ) {
 899:         $export_items = array();
 900: 
 901:         $forms = self::get_forms();
 902: 
 903:         $columns = self::get_columns();
 904: 
 905:         $draft_submissions = self::get_draft_submissions( $email_address );
 906: 
 907:         foreach ( $draft_submissions as $i => $draft_submission ) {
 908:             $data = array();
 909: 
 910:             $form_id = $draft_submission['form_id'];
 911: 
 912:             $form = $forms[ $form_id ];
 913: 
 914:             $submission_json = $draft_submission['submission'];
 915: 
 916:             $submission = json_decode( $submission_json, true );
 917: 
 918:             $entry = $submission['partial_entry'];
 919: 
 920:             $item_id = "gf-draft-submission-{$i}";
 921: 
 922:             $group_id = 'gravityforms-draft-submissions';
 923: 
 924:             $group_label = __( 'Draft Forms (Save and Continue Later)', 'gravityforms' );
 925: 
 926:             $columns_settings = rgars( $forms, $form_id . '/personalData/exportingAndErasing/columns' );
 927: 
 928:             if ( is_array( $columns_settings ) ) {
 929:                 foreach ( $columns_settings as $column_key => $column_settings ) {
 930:                     if ( rgar( $column_settings, 'export' ) && isset( $draft_submission[ $column_key ] ) ) {
 931:                         $data[] = array(
 932:                             'name'  => $columns[ $column_key ],
 933:                             'value' => $draft_submission[ $column_key ],
 934:                         );
 935:                     }
 936:                 }
 937:             }
 938: 
 939:             foreach ( $form['fields'] as $field ) {
 940:                 /* @var GF_Field $field */
 941:                 if ( $field->personalDataExport ) {
 942:                     $value  = GFFormsModel::get_lead_field_value( $entry, $field );
 943:                     $data[] = array(
 944:                         'name'  => $field->get_field_label( false, $value ),
 945:                         'value' => $field->get_value_entry_detail( $value, rgar( $entry, 'currency' ), true, 'text' ),
 946:                     );
 947:                 }
 948:             }
 949: 
 950:             if ( ! empty( $data ) ) {
 951:                 $export_items[] = array(
 952:                     'group_id'    => $group_id,
 953:                     'group_label' => $group_label,
 954:                     'item_id'     => $item_id,
 955:                     'data'        => $data,
 956:                 );
 957:             }
 958:         }
 959: 
 960:         return $export_items;
 961:     }
 962: 
 963:     /**
 964:      * Erases personal data specified in the form settings.
 965:      *
 966:      * @since 2.4
 967:      *
 968:      * @param string $email_address
 969:      * @param int    $page
 970:      *
 971:      * @return array
 972:      */
 973:     public static function data_eraser( $email_address, $page = 1 ) {
 974: 
 975:         $limit = 50;
 976: 
 977:         $items_removed = $page == 1 ? self::erase_draft_submissions_data( $email_address ) : false;
 978: 
 979:         $forms = self::get_forms();
 980: 
 981:         $entries = self::get_entries( $email_address, $page, $limit );
 982: 
 983:         foreach ( $entries as $entry ) {
 984: 
 985:             $form_id = $entry['form_id'];
 986: 
 987:             $form = $forms[ $form_id ];
 988: 
 989:             $columns_settings = rgars( $forms, $form_id . '/personalData/exportingAndErasing/columns' );
 990: 
 991:             if ( is_array( $columns_settings ) ) {
 992:                 foreach ( $columns_settings as $column_key => $column_settings ) {
 993:                     if ( rgar( $column_settings, 'erase' ) ) {
 994:                         GFAPI::update_entry_property( $entry['id'], $column_key, '' );
 995:                         $items_removed = true;
 996:                     }
 997:                 }
 998:             }
 999: 
1000:             $has_product_field = false;
1001: 
1002:             foreach ( $form['fields'] as $field ) {
1003:                 /* @var GF_Field $field */
1004: 
1005:                 if ( $field->personalDataErase ) {
1006: 
1007:                     $input_type = $field->get_input_type();
1008: 
1009:                     if ( $input_type == 'fileupload' ) {
1010:                         GFFormsModel::delete_files( $entry['id'] );
1011:                         GFAPI::update_entry_field( $entry['id'], $field->id, '' );
1012:                         continue;
1013:                     }
1014: 
1015:                     if ( $field->type == 'product' ) {
1016:                         $has_product_field = true;
1017:                     }
1018: 
1019:                     $value = GFFormsModel::get_lead_field_value( $entry, $field );
1020: 
1021:                     if ( is_array( $value ) ) {
1022:                         self::erase_field_values( $value, $entry['id'], $field->id );
1023:                         $items_removed = true;
1024:                     } else {
1025:                         switch ( $input_type ) {
1026:                             case 'email':
1027:                                 $anonymous = 'deleted@site.invalid';
1028:                                 break;
1029:                             case 'website':
1030:                                 $anonymous = 'https://site.invalid';
1031:                                 break;
1032:                             case 'date':
1033:                                 $anonymous = '0000-00-00';
1034:                                 break;
1035:                             case 'text':
1036:                             case 'textarea':
1037:                                 /* translators: deleted text */
1038:                                 $anonymous = __( '[deleted]' );
1039:                                 break;
1040:                             default:
1041:                                 $anonymous = '';
1042:                         }
1043:                         GFAPI::update_entry_field( $entry['id'], $field->id, $anonymous );
1044:                         $items_removed = true;
1045:                     }
1046:                 }
1047:             }
1048: 
1049:             if ( $has_product_field ) {
1050:                 GFFormsModel::refresh_product_cache( $form, $entry );
1051:             }
1052: 
1053:             $custom_items = self::get_custom_items( $form );
1054: 
1055:             if ( ! empty( $custom_items ) ) {
1056:                 $all_custom_settings = rgars( $forms, $form_id . '/personalData/exportingAndErasing/custom' );
1057:                 foreach ( $custom_items as $custom_item_key => $custom_item_details ) {
1058:                     $custom_settings = rgar( $all_custom_settings, $custom_item_key );
1059:                     if ( rgars( $custom_settings, 'erase' ) && isset( $custom_item_details['eraser_callback'] ) && is_callable( $custom_item_details['eraser_callback'] ) ) {
1060:                         call_user_func( $custom_item_details['eraser_callback'], $form, $entry );
1061:                         $items_removed = true;
1062:                     }
1063:                 }
1064:             }
1065:         }
1066: 
1067:         $done = count( $entries ) < $limit;
1068: 
1069:         return array(
1070:             'items_removed'  => $items_removed,
1071:             'items_retained' => false,
1072:             'messages'       => array(),
1073:             'done'           => $done,
1074:         );
1075:     }
1076: 
1077:     public static function erase_field_values( $value, $entry_id, $input_id, $item_index = '' ) {
1078:         if ( is_array( $value ) ) {
1079:             $i = 0;
1080:             foreach ( $value as $key => $val ) {
1081:                 if ( is_array( $val ) ) {
1082:                     foreach ( $val as $k => $v ) {
1083:                         $new_index = $item_index . '_' . $i;
1084:                         self::erase_field_values( $v, $entry_id, $k, $new_index );
1085:                     }
1086:                     $i++;
1087:                 } else {
1088:                     GFAPI::update_entry_field( $entry_id, $key, '', $item_index );
1089:                 }
1090:             }
1091:         } else {
1092:             GFAPI::update_entry_field( $entry_id, $input_id, '', $item_index );
1093:         }
1094: 
1095:     }
1096: 
1097:     /**
1098:      * Returns the draft submissions (save and continue) for the given email address.
1099:      *
1100:      * @since 2.4
1101:      *
1102:      * @param $email_address
1103:      *
1104:      * @return array
1105:      */
1106:     public static function get_draft_submissions( $email_address ) {
1107: 
1108:         $draft_submissions = GFFormsModel::get_draft_submissions();
1109: 
1110:         if ( empty( $draft_submissions ) ) {
1111:             return array();
1112:         }
1113: 
1114:         $user = get_user_by( 'email', $email_address );
1115: 
1116:         $return = array();
1117: 
1118:         $forms = self::get_forms();
1119: 
1120:         foreach ( $draft_submissions as $i => $draft_submission ) {
1121: 
1122:             $form_id = $draft_submission['form_id'];
1123: 
1124:             $form = $forms[ $form_id ];
1125: 
1126:             if ( ! rgars( $form, 'personalData/exportingAndErasing/enabled' ) ) {
1127:                 continue;
1128:             }
1129: 
1130:             $submission_json = $draft_submission['submission'];
1131: 
1132:             $submission = json_decode( $submission_json, true );
1133: 
1134:             $entry = $submission['partial_entry'];
1135: 
1136:             $identification_field = rgars( $form, 'personalData/exportingAndErasing/identificationField' );
1137: 
1138:             $field = GFAPI::get_field( $form, $identification_field );
1139: 
1140:             if ( ( $field && $field->get_input_type() == 'email' && $entry[ (string) $identification_field ] === $email_address )
1141:                  || ( $user && $user->ID == rgar( $entry, $identification_field ) )
1142:             ) {
1143:                 $return[] = $draft_submission;
1144:             }
1145:         }
1146: 
1147:         return $return;
1148:     }
1149: 
1150:     /**
1151:      * Erases the data in the draft submissions.
1152:      *
1153:      * @since 2.4
1154:      *
1155:      * @param $email_address
1156:      *
1157:      * @return bool
1158:      */
1159:     public static function erase_draft_submissions_data( $email_address ) {
1160:         $items_removed = false;
1161: 
1162:         $forms = self::get_forms();
1163: 
1164:         $draft_entries = self::get_draft_submissions( $email_address );
1165: 
1166:         foreach ( $draft_entries as $draft_entry ) {
1167: 
1168:             $entry_dirty = false;
1169: 
1170:             $form_id = $draft_entry['form_id'];
1171: 
1172:             $resume_token = $draft_entry['uuid'];
1173: 
1174:             $date_created = $draft_entry['date_created'];
1175: 
1176:             $form = $forms[ $form_id ];
1177: 
1178:             $columns_settings = rgars( $forms, $form_id . '/personalData/exportingAndErasing/columns' );
1179: 
1180:             $submission_json = $draft_entry['submission'];
1181: 
1182:             $submission = json_decode( $submission_json, true );
1183: 
1184:             $entry = $submission['partial_entry'];
1185: 
1186:             $submitted_values = $submission['submitted_values'];
1187: 
1188:             if ( is_array( $columns_settings ) ) {
1189:                 foreach ( $columns_settings as $column_key => $column_settings ) {
1190:                     if ( rgar( $column_settings, 'erase' ) ) {
1191:                         if ( isset( $draft_entry[ $column_key ] ) ) {
1192:                             $draft_entry[ $column_key ] = '';
1193:                         }
1194: 
1195:                         if ( isset( $entry[ $column_key ] ) ) {
1196:                             $entry[ $column_key ] = '';
1197:                         }
1198: 
1199:                         $entry_dirty = true;
1200:                     }
1201:                 }
1202:             }
1203: 
1204:             foreach ( $form['fields'] as $field ) {
1205:                 /* @var GF_Field $field */
1206: 
1207:                 if ( $field->personalDataErase ) {
1208: 
1209:                     $input_type = $field->get_input_type();
1210: 
1211:                     $value = GFFormsModel::get_lead_field_value( $entry, $field );
1212: 
1213:                     if ( is_array( $value ) ) {
1214:                         foreach ( $value as $k => $v ) {
1215:                             $entry[ $k ] = '';
1216:                             $submitted_values[ $field->id ][ $k ] = '';
1217:                         }
1218:                         $entry_dirty = true;
1219:                     } else {
1220:                         switch ( $input_type ) {
1221:                             case 'email':
1222:                                 $anonymous = 'deleted@site.invalid';
1223:                                 break;
1224:                             case 'website':
1225:                                 $anonymous = 'https://site.invalid';
1226:                                 break;
1227:                             case 'date':
1228:                                 $anonymous = '0000-00-00';
1229:                                 break;
1230:                             case 'text':
1231:                             case 'textarea':
1232:                                 /* translators: deleted text */
1233:                                 $anonymous = __( '[deleted]', 'gravityforms' );
1234:                                 break;
1235:                             default:
1236:                                 $anonymous = '';
1237:                         }
1238:                         $submitted_values[ (string) $field->id ] = $anonymous;
1239:                         $entry[ (string) $field->id ] = $anonymous;
1240:                         $entry_dirty = true;
1241:                     }
1242:                 }
1243:             }
1244: 
1245:             $custom_items = self::get_custom_items( $form );
1246: 
1247:             if ( ! empty( $custom_items ) ) {
1248:                 $all_custom_settings = rgars( $forms, $form_id . '/personalData/exportingAndErasing/custom' );
1249:                 foreach ( $custom_items as $custom_item_key => $custom_item_details ) {
1250:                     $custom_settings = rgar( $all_custom_settings, $custom_item_key );
1251:                     if ( rgars( $custom_settings, 'erase' ) && isset( $custom_item_details['eraser_callback'] ) && is_callable( $custom_item_details['eraser_callback'] ) ) {
1252:                         call_user_func( $custom_item_details['eraser_callback'], $form, $entry );
1253:                         $items_removed = true;
1254:                     }
1255:                 }
1256:             }
1257: 
1258:             if ( $entry_dirty ) {
1259:                 $submission['submitted_values'] = $submitted_values;
1260:                 $submission['partial_entry'] = $entry;
1261:                 $submission_json                = json_encode( $submission );
1262:                 GFFormsModel::update_draft_submission( $resume_token, $form, $date_created, $draft_entry['ip'], $draft_entry['source_url'], $submission_json );
1263:                 $items_removed = true;
1264:             }
1265:         }
1266: 
1267: 
1268:         return $items_removed;
1269:     }
1270: 
1271:     /**
1272:      * Deletes and trashes entries according to the retention policy in each of the form settings.
1273:      *
1274:      * @since 2.4
1275:      */
1276:     public static function cron_task() {
1277: 
1278:         self::log_debug( __METHOD__ . '(): starting personal data cron task' );
1279: 
1280:         $forms = self::get_forms();
1281: 
1282:         $trash_form_ids   = array();
1283:         $trash_conditions = array();
1284: 
1285:         $delete_form_ids   = array();
1286:         $delete_conditions = array();
1287: 
1288:         foreach ( $forms as $form ) {
1289: 
1290:             $retention_policy = rgars( $form, 'personalData/retention/policy', 'retain' );
1291: 
1292:             if ( $retention_policy == 'retain' ) {
1293:                 continue;
1294:             }
1295: 
1296:             $form_conditions = array();
1297: 
1298:             $retention_days = rgars( $form, 'personalData/retention/retain_entries_days' );
1299: 
1300:             $delete_timestamp = time() - ( DAY_IN_SECONDS * $retention_days );
1301: 
1302:             $delete_date = date( 'Y-m-d H:i:s', $delete_timestamp );
1303: 
1304:             $form_conditions[] = new GF_Query_Condition(
1305:                 new GF_Query_Column( 'date_created' ),
1306:                 GF_Query_Condition::LT,
1307:                 new GF_Query_Literal( $delete_date )
1308:             );
1309: 
1310:             $form_conditions[] = new GF_Query_Condition(
1311:                 new GF_Query_Column( 'form_id' ),
1312:                 GF_Query_Condition::EQ,
1313:                 new GF_Query_Literal( $form['id'] )
1314:             );
1315: 
1316:             if ( ! empty( $form_conditions ) ) {
1317:                 if ( $retention_policy == 'trash' ) {
1318:                     $trash_form_ids[] = $form['id'];
1319:                     $trash_conditions[] = call_user_func_array( array(
1320:                         'GF_Query_Condition',
1321:                         '_and',
1322:                     ), $form_conditions );
1323:                 } elseif ( $retention_policy == 'delete' ) {
1324:                     $delete_form_ids[] = $form['id'];
1325:                     $delete_conditions[] = call_user_func_array( array(
1326:                         'GF_Query_Condition',
1327:                         '_and',
1328:                     ), $form_conditions );
1329:                 }
1330:             }
1331:         }
1332: 
1333:         if ( ! empty( $trash_conditions ) ) {
1334: 
1335:             $query = new GF_Query();
1336: 
1337:             $all_trash_conditions = array();
1338: 
1339:             $all_trash_conditions[] = call_user_func_array( array( 'GF_Query_Condition', '_or' ), $trash_conditions );
1340: 
1341:             $all_trash_conditions[] = new GF_Query_Condition(
1342:                 new GF_Query_Column( 'status' ),
1343:                 GF_Query_Condition::NEQ,
1344:                 new GF_Query_Literal( 'trash' )
1345:             );
1346: 
1347:             $all_trash_conditions = call_user_func_array( array( 'GF_Query_Condition', '_and' ), $all_trash_conditions );
1348: 
1349:             $entry_ids = $query->from( $trash_form_ids )->where( $all_trash_conditions )->get_ids();
1350: 
1351:             self::log_debug( __METHOD__ . '(): trashing entries: ' . join( ', ', $entry_ids ) );
1352: 
1353:             foreach ( $entry_ids as $entry_id ) {
1354:                 GFAPI::update_entry_property( $entry_id, 'status', 'trash' );
1355:             }
1356:         }
1357: 
1358:         if ( ! empty( $delete_conditions ) ) {
1359: 
1360:             $query = new GF_Query();
1361: 
1362:             $all_delete_conditions = call_user_func_array( array( 'GF_Query_Condition', '_or' ), $delete_conditions );
1363: 
1364:             $entry_ids = $query->from( $delete_form_ids )->where( $all_delete_conditions )->get_ids();
1365: 
1366:             self::log_debug( __METHOD__ . '(): deleting entries: ' . join( ', ', $entry_ids ) );
1367: 
1368:             /**
1369:              * Allows the array of entry IDs to be modified before automatically deleting according to the
1370:              * personal data retention policy.
1371:              *
1372:              * @since 2.4
1373:              *
1374:              * @param int[] $entry_ids The array of entry IDs to delete.
1375:              */
1376:             $entry_ids = apply_filters( 'gform_entry_ids_automatic_deletion', $entry_ids );
1377: 
1378:             foreach ( $entry_ids as $entry_id ) {
1379:                 GFAPI::delete_entry( $entry_id );
1380:             }
1381:         }
1382: 
1383:         self::log_debug( __METHOD__ . '(): done' );
1384: 
1385:     }
1386: 
1387:     /**
1388:      * Writes a message to the debug log
1389:      *
1390:      * @since 2.4
1391:      *
1392:      * @param $message
1393:      */
1394:     public static function log_debug( $message ) {
1395:         GFCommon::log_debug( $message );
1396:     }
1397: 
1398:     /**
1399:      * Flushes the forms
1400:      *
1401:      * @since 2.4
1402:      */
1403:     public static function flush_current_forms() {
1404:         self::$_forms = null;
1405:     }
1406: }
1407: 
Gravity Forms API API documentation generated by ApiGen 2.8.0