GravityView  2.1.1
The best, easiest way to display Gravity Forms entries on your website.
class-edit-entry-render.php
Go to the documentation of this file.
1 <?php
2 /**
3  * GravityView Edit Entry - render frontend
4  *
5  * @package GravityView
6  * @license GPL2+
7  * @author Katz Web Services, Inc.
8  * @link http://gravityview.co
9  * @copyright Copyright 2014, Katz Web Services, Inc.
10  */
11 
12 if ( ! defined( 'WPINC' ) ) {
13  die;
14 }
15 
17 
18  /**
19  * @var GravityView_Edit_Entry
20  */
21  protected $loader;
22 
23  /**
24  * @var string String used to generate unique nonce for the entry/form/view combination. Allows access to edit page.
25  */
26  static $nonce_key;
27 
28  /**
29  * @since 1.9
30  * @var string String used for check valid edit entry form submission. Allows saving edit form values.
31  */
32  private static $nonce_field = 'is_gv_edit_entry';
33 
34  /**
35  * @since 1.9
36  * @var bool Whether to allow save and continue functionality
37  */
38  private static $supports_save_and_continue = false;
39 
40  /**
41  * Gravity Forms entry array
42  *
43  * @var array
44  */
45  public $entry;
46 
47  /**
48  * Gravity Forms entry array (it won't get changed during this class lifecycle)
49  * @since 1.17.2
50  * @var array
51  */
52  private static $original_entry = array();
53 
54  /**
55  * Gravity Forms form array (GravityView modifies the content through this class lifecycle)
56  *
57  * @var array
58  */
59  public $form;
60 
61  /**
62  * Gravity Forms form array (it won't get changed during this class lifecycle)
63  * @since 1.16.2.1
64  * @var array
65  */
66  private static $original_form;
67 
68  /**
69  * Gravity Forms form array after the form validation process
70  * @since 1.13
71  * @var array
72  */
73  public $form_after_validation = null;
74 
75  /**
76  * Hold an array of GF field objects that have calculation rules
77  * @var array
78  */
79  public $fields_with_calculation = array();
80 
81  /**
82  * Gravity Forms form id
83  *
84  * @var int
85  */
86  public $form_id;
87 
88  /**
89  * ID of the current view
90  *
91  * @var int
92  */
93  public $view_id;
94 
95  /**
96  * ID of the current post. May also be ID of the current View.
97  *
98  * @since 2.0.13
99  *
100  * @var int
101  */
102  public $post_id;
103 
104  /**
105  * Updated entry is valid (GF Validation object)
106  *
107  * @var array
108  */
109  public $is_valid = NULL;
110 
112  $this->loader = $loader;
113  }
114 
115  function load() {
116 
117  /** @define "GRAVITYVIEW_DIR" "../../../" */
118  include_once( GRAVITYVIEW_DIR .'includes/class-admin-approve-entries.php' );
119 
120  // Don't display an embedded form when editing an entry
121  add_action( 'wp_head', array( $this, 'prevent_render_form' ) );
122  add_action( 'wp_footer', array( $this, 'prevent_render_form' ) );
123 
124  // Stop Gravity Forms processing what is ours!
125  add_filter( 'wp', array( $this, 'prevent_maybe_process_form'), 8 );
126 
127  add_filter( 'gravityview_is_edit_entry', array( $this, 'is_edit_entry') );
128 
129  add_action( 'gravityview_edit_entry', array( $this, 'init' ) );
130 
131  // Disable conditional logic if needed (since 1.9)
132  add_filter( 'gform_has_conditional_logic', array( $this, 'manage_conditional_logic' ), 10, 2 );
133 
134  // Make sure GF doesn't validate max files (since 1.9)
135  add_filter( 'gform_plupload_settings', array( $this, 'modify_fileupload_settings' ), 10, 3 );
136 
137  // Add fields expected by GFFormDisplay::validate()
138  add_filter( 'gform_pre_validation', array( $this, 'gform_pre_validation') );
139 
140  // Fix multiselect value for GF 2.2
141  add_filter( 'gravityview/edit_entry/field_value_multiselect', array( $this, 'fix_multiselect_value_serialization' ), 10, 3 );
142  }
143 
144  /**
145  * Don't show any forms embedded on a page when GravityView is in Edit Entry mode
146  *
147  * Adds a `__return_empty_string` filter on the Gravity Forms shortcode on the `wp_head` action
148  * And then removes it on the `wp_footer` action
149  *
150  * @since 1.16.1
151  *
152  * @return void
153  */
154  public function prevent_render_form() {
155  if( $this->is_edit_entry() ) {
156  if( 'wp_head' === current_filter() ) {
157  add_filter( 'gform_shortcode_form', '__return_empty_string' );
158  } else {
159  remove_filter( 'gform_shortcode_form', '__return_empty_string' );
160  }
161  }
162  }
163 
164  /**
165  * Because we're mimicking being a front-end Gravity Forms form while using a Gravity Forms
166  * backend form, we need to prevent them from saving twice.
167  * @return void
168  */
169  public function prevent_maybe_process_form() {
170 
171  if( ! empty( $_POST ) ) {
172  gravityview()->log->debug( 'GravityView_Edit_Entry[prevent_maybe_process_form] $_POSTed data (sanitized): ', array( 'data' => esc_html( print_r( $_POST, true ) ) ) );
173  }
174 
175  if( $this->is_edit_entry_submission() ) {
176  remove_action( 'wp', array( 'RGForms', 'maybe_process_form'), 9 );
177  remove_action( 'wp', array( 'GFForms', 'maybe_process_form'), 9 );
178  }
179  }
180 
181  /**
182  * Is the current page an Edit Entry page?
183  * @return boolean
184  */
185  public function is_edit_entry() {
186 
187  $is_edit_entry = GravityView_frontend::is_single_entry() && ! empty( $_GET['edit'] );
188 
189  return ( $is_edit_entry || $this->is_edit_entry_submission() );
190  }
191 
192  /**
193  * Is the current page an Edit Entry page?
194  * @since 1.9
195  * @return boolean
196  */
197  public function is_edit_entry_submission() {
198  return !empty( $_POST[ self::$nonce_field ] );
199  }
200 
201  /**
202  * When Edit entry view is requested setup the vars
203  */
204  private function setup_vars() {
205  global $post;
206 
208 
209 
210  $entries = $gravityview_view->getEntries();
211  self::$original_entry = $entries[0];
212  $this->entry = $entries[0];
213 
214  self::$original_form = $gravityview_view->getForm();
215  $this->form = $gravityview_view->getForm();
216  $this->form_id = $gravityview_view->getFormId();
217  $this->view_id = $gravityview_view->getViewId();
218  $this->post_id = \GV\Utils::get( $post, 'ID', null );
219 
220  self::$nonce_key = GravityView_Edit_Entry::get_nonce_key( $this->view_id, $this->form_id, $this->entry['id'] );
221  }
222 
223 
224  /**
225  * Load required files and trigger edit flow
226  *
227  * Run when the is_edit_entry returns true.
228  *
229  * @param \GravityView_View_Data $gv_data GravityView Data object
230  * @return void
231  */
232  public function init( $gv_data = null ) {
233 
234  require_once( GFCommon::get_base_path() . '/form_display.php' );
235  require_once( GFCommon::get_base_path() . '/entry_detail.php' );
236 
237  $this->setup_vars();
238 
239  if ( ! $gv_data ) {
241  }
242 
243  // Multiple Views embedded, don't proceed if nonce fails
244  if ( $gv_data->has_multiple_views() && ! $this->verify_nonce() ) {
245  gravityview()->log->error( 'Nonce validation failed for the Edit Entry request; returning' );
246  return;
247  }
248 
249  // Sorry, you're not allowed here.
250  if ( false === $this->user_can_edit_entry( true ) ) {
251  gravityview()->log->error( 'User is not allowed to edit this entry; returning', array( 'data' => $this->entry ) );
252  return;
253  }
254 
255  $this->print_scripts();
256 
257  $this->process_save( $gv_data );
258 
259  $this->edit_entry_form();
260 
261  }
262 
263 
264  /**
265  * Force Gravity Forms to output scripts as if it were in the admin
266  * @return void
267  */
268  private function print_scripts() {
270 
271  wp_register_script( 'gform_gravityforms', GFCommon::get_base_url().'/js/gravityforms.js', array( 'jquery', 'gform_json', 'gform_placeholder', 'sack', 'plupload-all', 'gravityview-fe-view' ) );
272 
273  GFFormDisplay::enqueue_form_scripts( $gravityview_view->getForm(), false);
274 
275  wp_localize_script( 'gravityview-fe-view', 'gvGlobals', array( 'cookiepath' => COOKIEPATH ) );
276 
277  // Sack is required for images
278  wp_print_scripts( array( 'sack', 'gform_gravityforms', 'gravityview-fe-view' ) );
279  }
280 
281 
282  /**
283  * Process edit entry form save
284  *
285  * @param array $gv_data The View data.
286  */
287  private function process_save( $gv_data ) {
288 
289  if ( empty( $_POST ) || ! isset( $_POST['lid'] ) ) {
290  return;
291  }
292 
293  // Make sure the entry, view, and form IDs are all correct
294  $valid = $this->verify_nonce();
295 
296  if ( !$valid ) {
297  gravityview()->log->error( 'Nonce validation failed.' );
298  return;
299  }
300 
301  if ( $this->entry['id'] !== $_POST['lid'] ) {
302  gravityview()->log->error( 'Entry ID did not match posted entry ID.' );
303  return;
304  }
305 
306  gravityview()->log->debug( '$_POSTed data (sanitized): ', array( 'data' => esc_html( print_r( $_POST, true ) ) ) );
307 
308  $this->process_save_process_files( $this->form_id );
309 
310  $this->validate();
311 
312  if( $this->is_valid ) {
313 
314  gravityview()->log->debug( 'Submission is valid.' );
315 
316  /**
317  * @hack This step is needed to unset the adminOnly from form fields, to add the calculation fields
318  */
319  $form = $this->form_prepare_for_save();
320 
321  /**
322  * @hack to avoid the capability validation of the method save_lead for GF 1.9+
323  */
324  unset( $_GET['page'] );
325 
326  $date_created = $this->entry['date_created'];
327 
328  /**
329  * @hack to force Gravity Forms to use $read_value_from_post in GFFormsModel::save_lead()
330  * @since 1.17.2
331  */
332  unset( $this->entry['date_created'] );
333 
334  GFFormsModel::save_lead( $form, $this->entry );
335 
336  // Delete the values for hidden inputs
337  $this->unset_hidden_field_values();
338 
339  $this->entry['date_created'] = $date_created;
340 
341  // Process calculation fields
342  $this->update_calculation_fields();
343 
344  // Process Quiz fields
345  $this->update_quiz_fields();
346 
347  // Perform actions normally performed after updating a lead
348  $this->after_update();
349 
350  /**
351  * Must be AFTER after_update()!
352  * @see https://github.com/gravityview/GravityView/issues/764
353  */
355 
356  /**
357  * @action `gravityview/edit_entry/after_update` Perform an action after the entry has been updated using Edit Entry
358  * @since 2.1 Added $gv_data parameter
359  * @param array $form Gravity Forms form array
360  * @param string $entry_id Numeric ID of the entry that was updated
361  * @param GravityView_Edit_Entry_Render $this This object
362  * @param GravityView_View_Data $gv_data The View data
363  */
364  do_action( 'gravityview/edit_entry/after_update', $this->form, $this->entry['id'], $this, $gv_data );
365 
366  } else {
367  gravityview()->log->error( 'Submission is NOT valid.', array( 'entry' => $this->entry ) );
368  }
369 
370  } // process_save
371 
372  /**
373  * Delete the value of fields hidden by conditional logic when the entry is edited
374  *
375  * @uses GFFormsModel::update_lead_field_value()
376  *
377  * @since 1.17.4
378  *
379  * @return void
380  */
381  private function unset_hidden_field_values() {
382  global $wpdb;
383 
384  /**
385  * @filter `gravityview/edit_entry/unset_hidden_field_values` Whether to delete values of fields hidden by conditional logic
386  * @since 1.22.2
387  * @param bool $unset_hidden_field_values Default: true
388  * @param GravityView_Edit_Entry_Render $this This object
389  */
390  $unset_hidden_field_values = apply_filters( 'gravityview/edit_entry/unset_hidden_field_values', true, $this );
391 
392  if( ! $unset_hidden_field_values ) {
393  return;
394  }
395 
396  if ( version_compare( GravityView_GFFormsModel::get_database_version(), '2.3-dev-1', '>=' ) && method_exists( 'GFFormsModel', 'get_entry_meta_table_name' ) ) {
397  $entry_meta_table = GFFormsModel::get_entry_meta_table_name();
398  $current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value FROM $entry_meta_table WHERE entry_id=%d", $this->entry['id'] ) );
399  } else {
400  $lead_detail_table = GFFormsModel::get_lead_details_table_name();
401  $current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT id, field_number FROM $lead_detail_table WHERE lead_id=%d", $this->entry['id'] ) );
402  }
403 
404  foreach ( $this->entry as $input_id => $field_value ) {
405 
406  $field = RGFormsModel::get_field( $this->form, $input_id );
407 
408  // Reset fields that are hidden
409  // Don't pass $entry as fourth parameter; force using $_POST values to calculate conditional logic
410  if ( GFFormsModel::is_field_hidden( $this->form, $field, array(), NULL ) ) {
411 
412  // List fields are stored as empty arrays when empty
413  $empty_value = $this->is_field_json_encoded( $field ) ? '[]' : '';
414 
415  $lead_detail_id = GFFormsModel::get_lead_detail_id( $current_fields, $input_id );
416 
417  GFFormsModel::update_lead_field_value( $this->form, $this->entry, $field, $lead_detail_id, $input_id, $empty_value );
418 
419  // Prevent the $_POST values of hidden fields from being used as default values when rendering the form
420  // after submission
421  $post_input_id = 'input_' . str_replace( '.', '_', $input_id );
422  $_POST[ $post_input_id ] = '';
423  }
424  }
425  }
426 
427  /**
428  * Have GF handle file uploads
429  *
430  * Copy of code from GFFormDisplay::process_form()
431  *
432  * @param int $form_id
433  */
434  private function process_save_process_files( $form_id ) {
435 
436  //Loading files that have been uploaded to temp folder
437  $files = GFCommon::json_decode( stripslashes( RGForms::post( 'gform_uploaded_files' ) ) );
438  if ( ! is_array( $files ) ) {
439  $files = array();
440  }
441 
442  /**
443  * Make sure the fileuploads are not overwritten if no such request was done.
444  * @since 1.20.1
445  */
446  add_filter( "gform_save_field_value_$form_id", array( $this, 'save_field_value' ), 99, 5 );
447 
448  RGFormsModel::$uploaded_files[ $form_id ] = $files;
449  }
450 
451  /**
452  * Make sure the fileuploads are not overwritten if no such request was done.
453  *
454  * TO ONLY BE USED INTERNALLY; DO NOT DEVELOP ON; MAY BE REMOVED AT ANY TIME.
455  *
456  * @since 1.20.1
457  *
458  * @param string $value Field value
459  * @param array $entry GF entry array
460  * @param GF_Field_FileUpload $field
461  * @param array $form GF form array
462  * @param string $input_id ID of the input being saved
463  *
464  * @return string
465  */
466  public function save_field_value( $value = '', $entry = array(), $field = null, $form = array(), $input_id = '' ) {
467 
468  if ( ! $field || $field->type != 'fileupload' ) {
469  return $value;
470  }
471 
472  $input_name = 'input_' . str_replace( '.', '_', $input_id );
473 
474  if ( $field->multipleFiles ) {
475  if ( empty( $value ) ) {
476  return json_decode( $entry[ $input_id ], true );
477  }
478  return $value;
479  }
480 
481  /** No file is being uploaded. */
482  if ( empty( $_FILES[ $input_name ]['name'] ) ) {
483  /** So return the original upload */
484  return $entry[ $input_id ];
485  }
486 
487  return $value;
488  }
489 
490  /**
491  * Remove max_files validation (done on gravityforms.js) to avoid conflicts with GravityView
492  * Late validation done on self::custom_validation
493  *
494  * @param $plupload_init array Plupload settings
495  * @param $form_id
496  * @param $instance
497  * @return mixed
498  */
499  public function modify_fileupload_settings( $plupload_init, $form_id, $instance ) {
500  if( ! $this->is_edit_entry() ) {
501  return $plupload_init;
502  }
503 
504  $plupload_init['gf_vars']['max_files'] = 0;
505 
506  return $plupload_init;
507  }
508 
509 
510  /**
511  * Set visibility to visible and convert field input key to string
512  * @return array $form
513  */
514  private function form_prepare_for_save() {
515 
516  $form = $this->form;
517 
518  /** @var GF_Field $field */
519  foreach( $form['fields'] as $k => &$field ) {
520 
521  /**
522  * Remove the fields with calculation formulas before save to avoid conflicts with GF logic
523  * @since 1.16.3
524  * @var GF_Field $field
525  */
526  if( $field->has_calculation() ) {
527  unset( $form['fields'][ $k ] );
528  }
529 
530  $field->adminOnly = false;
531 
532  if( isset( $field->inputs ) && is_array( $field->inputs ) ) {
533  foreach( $field->inputs as $key => $input ) {
534  $field->inputs[ $key ][ 'id' ] = (string)$input['id'];
535  }
536  }
537  }
538 
539  $form['fields'] = array_values( $form['fields'] );
540 
541  return $form;
542  }
543 
544  private function update_calculation_fields() {
545  global $wpdb;
546 
547  $form = self::$original_form;
548  $update = false;
549 
550  // get the most up to date entry values
551  $entry = GFAPI::get_entry( $this->entry['id'] );
552 
553  if ( version_compare( GravityView_GFFormsModel::get_database_version(), '2.3-dev-1', '>=' ) && method_exists( 'GFFormsModel', 'get_entry_meta_table_name' ) ) {
554  $entry_meta_table = GFFormsModel::get_entry_meta_table_name();
555  $current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT id, meta_key FROM $entry_meta_table WHERE entry_id=%d", $entry['id'] ) );
556  } else {
557  $lead_detail_table = GFFormsModel::get_lead_details_table_name();
558  $current_fields = $wpdb->get_results( $wpdb->prepare( "SELECT id, field_number FROM $lead_detail_table WHERE lead_id=%d", $entry['id'] ) );
559  }
560 
561  if ( ! empty( $this->fields_with_calculation ) ) {
562  $update = true;
563  foreach ( $this->fields_with_calculation as $field ) {
564  $inputs = $field->get_entry_inputs();
565  if ( is_array( $inputs ) ) {
566  foreach ( $inputs as $input ) {
567  GFFormsModel::save_input( $form, $field, $entry, $current_fields, $input['id'] );
568  }
569  } else {
570  GFFormsModel::save_input( $form, $field, $entry, $current_fields, $field->id );
571  }
572  }
573 
574  if ( method_exists( 'GFFormsModel', 'commit_batch_field_operations' ) ) {
575  GFFormsModel::commit_batch_field_operations();
576  }
577  }
578  }
579 
580  /**
581  * Make sure the quiz is updated accordingly.
582  * https://github.com/gravityview/GravityView/issues/1166
583  */
584  private function update_quiz_fields() {
585  if ( ! class_exists( 'GFQuiz' ) ) {
586  return;
587  }
588 
589  $entry = GFAPI::get_entry( $this->entry['id'] );
590 
591  foreach ( array( 'score', 'percent', 'grade', 'is_pass' ) as $meta ) {
592  GFQuiz::get_instance()->update_entry_meta( "gfquiz_$meta", $entry, self::$original_form );
593  }
594  }
595 
596  /**
597  * Handle updating the Post Image field
598  *
599  * Sets a new Featured Image if configured in Gravity Forms; otherwise uploads/updates media
600  *
601  * @since 1.17
602  *
603  * @uses GFFormsModel::media_handle_upload
604  * @uses set_post_thumbnail
605  *
606  * @param array $form GF Form array
607  * @param GF_Field $field GF Field
608  * @param string $field_id Numeric ID of the field
609  * @param string $value
610  * @param array $entry GF Entry currently being edited
611  * @param int $post_id ID of the Post being edited
612  *
613  * @return mixed|string
614  */
616 
617  $input_name = 'input_' . $field_id;
618 
619  if ( !empty( $_FILES[ $input_name ]['name'] ) ) {
620 
621  // We have a new image
622 
623  $value = RGFormsModel::prepare_value( $form, $field, $value, $input_name, $entry['id'] );
624 
625  $ary = ! empty( $value ) ? explode( '|:|', $value ) : array();
626  $ary = stripslashes_deep( $ary );
627  $img_url = \GV\Utils::get( $ary, 0 );
628 
629  $img_title = count( $ary ) > 1 ? $ary[1] : '';
630  $img_caption = count( $ary ) > 2 ? $ary[2] : '';
631  $img_description = count( $ary ) > 3 ? $ary[3] : '';
632 
633  $image_meta = array(
634  'post_excerpt' => $img_caption,
635  'post_content' => $img_description,
636  );
637 
638  //adding title only if it is not empty. It will default to the file name if it is not in the array
639  if ( ! empty( $img_title ) ) {
640  $image_meta['post_title'] = $img_title;
641  }
642 
643  /**
644  * todo: As soon as \GFFormsModel::media_handle_upload becomes a public method, move this call to \GFFormsModel::media_handle_upload and remove the hack from this class.
645  * Note: the method became public in GF 1.9.17.7, but we don't require that version yet.
646  */
647  require_once GRAVITYVIEW_DIR . 'includes/class-gravityview-gfformsmodel.php';
649 
650  // is this field set as featured image?
651  if ( $media_id && $field->postFeaturedImage ) {
652  set_post_thumbnail( $post_id, $media_id );
653  }
654 
655  } elseif ( ! empty( $_POST[ $input_name ] ) && is_array( $value ) ) {
656 
657  $img_url = stripslashes_deep( $_POST[ $input_name ] );
658  $img_title = stripslashes_deep( \GV\Utils::_POST( $input_name . '_1' ) );
659  $img_caption = stripslashes_deep( \GV\Utils::_POST( $input_name . '_4' ) );
660  $img_description = stripslashes_deep( \GV\Utils::_POST( $input_name . '_7' ) );
661 
662  $value = ! empty( $img_url ) ? $img_url . "|:|" . $img_title . "|:|" . $img_caption . "|:|" . $img_description : '';
663 
664  if ( $field->postFeaturedImage ) {
665 
666  $image_meta = array(
667  'ID' => get_post_thumbnail_id( $post_id ),
668  'post_title' => $img_title,
669  'post_excerpt' => $img_caption,
670  'post_content' => $img_description,
671  );
672 
673  // update image title, caption or description
674  wp_update_post( $image_meta );
675  }
676  } else {
677 
678  // if we get here, image was removed or not set.
679  $value = '';
680 
681  if ( $field->postFeaturedImage ) {
682  delete_post_thumbnail( $post_id );
683  }
684  }
685 
686  return $value;
687  }
688 
689  /**
690  * Loop through the fields being edited and if they include Post fields, update the Entry's post object
691  *
692  * @param array $form Gravity Forms form
693  *
694  * @return void
695  */
696  private function maybe_update_post_fields( $form ) {
697 
698  if( empty( $this->entry['post_id'] ) ) {
699  gravityview()->log->debug( 'This entry has no post fields. Continuing...' );
700  return;
701  }
702 
703  $post_id = $this->entry['post_id'];
704 
705  // Security check
706  if( false === GVCommon::has_cap( 'edit_post', $post_id ) ) {
707  gravityview()->log->error( 'The current user does not have the ability to edit Post #{post_id}', array( 'post_id' => $post_id ) );
708  return;
709  }
710 
711  $update_entry = false;
712 
713  $updated_post = $original_post = get_post( $post_id );
714 
715  foreach ( $this->entry as $field_id => $value ) {
716 
717  $field = RGFormsModel::get_field( $form, $field_id );
718 
719  if( ! $field ) {
720  continue;
721  }
722 
723  if( GFCommon::is_post_field( $field ) && 'post_category' !== $field->type ) {
724 
725  // Get the value of the field, including $_POSTed value
726  $value = RGFormsModel::get_field_value( $field );
727 
728  // Use temporary entry variable, to make values available to fill_post_template() and update_post_image()
729  $entry_tmp = $this->entry;
730  $entry_tmp["{$field_id}"] = $value;
731 
732  switch( $field->type ) {
733 
734  case 'post_title':
735  $post_title = $value;
736  if ( \GV\Utils::get( $form, 'postTitleTemplateEnabled' ) ) {
737  $post_title = $this->fill_post_template( $form['postTitleTemplate'], $form, $entry_tmp );
738  }
739  $updated_post->post_title = $post_title;
740  $updated_post->post_name = $post_title;
741  unset( $post_title );
742  break;
743 
744  case 'post_content':
745  $post_content = $value;
746  if ( \GV\Utils::get( $form, 'postContentTemplateEnabled' ) ) {
747  $post_content = $this->fill_post_template( $form['postContentTemplate'], $form, $entry_tmp, true );
748  }
749  $updated_post->post_content = $post_content;
750  unset( $post_content );
751  break;
752  case 'post_excerpt':
753  $updated_post->post_excerpt = $value;
754  break;
755  case 'post_tags':
756  wp_set_post_tags( $post_id, $value, false );
757  break;
758  case 'post_category':
759  break;
760  case 'post_custom_field':
761  if ( is_array( $value ) && ( floatval( $field_id ) !== floatval( $field->id ) ) ) {
762  $value = $value[ $field_id ];
763  }
764 
765  if( ! empty( $field->customFieldTemplateEnabled ) ) {
766  $value = $this->fill_post_template( $field->customFieldTemplate, $form, $entry_tmp, true );
767  }
768 
769  if ( $this->is_field_json_encoded( $field ) && ! is_string( $value ) ) {
770  $value = wp_json_encode( $value );
771  }
772 
773  update_post_meta( $post_id, $field->postCustomFieldName, $value );
774  break;
775 
776  case 'post_image':
777  $value = $this->update_post_image( $form, $field, $field_id, $value, $this->entry, $post_id );
778  break;
779 
780  }
781 
782  // update entry after
783  $this->entry["{$field_id}"] = $value;
784 
785  $update_entry = true;
786 
787  unset( $entry_tmp );
788  }
789 
790  }
791 
792  if( $update_entry ) {
793 
794  $return_entry = GFAPI::update_entry( $this->entry );
795 
796  if( is_wp_error( $return_entry ) ) {
797  gravityview()->log->error( 'Updating the entry post fields failed', array( 'data' => array( '$this->entry' => $this->entry, '$return_entry' => $return_entry ) ) );
798  } else {
799  gravityview()->log->debug( 'Updating the entry post fields for post #{post_id} succeeded', array( 'post_id' => $post_id ) );
800  }
801 
802  }
803 
804  $return_post = wp_update_post( $updated_post, true );
805 
806  if( is_wp_error( $return_post ) ) {
807  $return_post->add_data( $updated_post, '$updated_post' );
808  gravityview()->log->error( 'Updating the post content failed', array( 'data' => compact( 'updated_post', 'return_post' ) ) );
809  } else {
810  gravityview()->log->debug( 'Updating the post content for post #{post_id} succeeded', array( 'post_id' => $post_id, 'data' => $updated_post ) );
811  }
812  }
813 
814  /**
815  * Is the field stored in a JSON-encoded manner?
816  *
817  * @param GF_Field $field
818  *
819  * @return bool True: stored in DB json_encode()'d; False: not encoded
820  */
821  private function is_field_json_encoded( $field ) {
822 
823  $json_encoded = false;
824 
825  $input_type = RGFormsModel::get_input_type( $field );
826 
827  // Only certain custom field types are supported
828  switch( $input_type ) {
829  case 'fileupload':
830  case 'list':
831  case 'multiselect':
832  $json_encoded = true;
833  break;
834  }
835 
836  return $json_encoded;
837  }
838 
839  /**
840  * Convert a field content template into prepared output
841  *
842  * @uses GravityView_GFFormsModel::get_post_field_images()
843  *
844  * @since 1.17
845  *
846  * @param string $template The content template for the field
847  * @param array $form Gravity Forms form
848  * @param bool $do_shortcode Whether to process shortcode inside content. In GF, only run on Custom Field and Post Content fields
849  *
850  * @return string
851  */
852  private function fill_post_template( $template, $form, $entry, $do_shortcode = false ) {
853 
854  require_once GRAVITYVIEW_DIR . 'includes/class-gravityview-gfformsmodel.php';
855 
857 
858  //replacing post image variables
859  $output = GFCommon::replace_variables_post_image( $template, $post_images, $entry );
860 
861  //replacing all other variables
862  $output = GFCommon::replace_variables( $output, $form, $entry, false, false, false );
863 
864  // replace conditional shortcodes
865  if( $do_shortcode ) {
866  $output = do_shortcode( $output );
867  }
868 
869  return $output;
870  }
871 
872 
873  /**
874  * Perform actions normally performed after updating a lead
875  *
876  * @since 1.8
877  *
878  * @see GFEntryDetail::lead_detail_page()
879  *
880  * @return void
881  */
882  private function after_update() {
883 
884  do_action( 'gform_after_update_entry', $this->form, $this->entry['id'], self::$original_entry );
885  do_action( "gform_after_update_entry_{$this->form['id']}", $this->form, $this->entry['id'], self::$original_entry );
886 
887  // Re-define the entry now that we've updated it.
888  $entry = RGFormsModel::get_lead( $this->entry['id'] );
889 
890  $entry = GFFormsModel::set_entry_meta( $entry, $this->form );
891 
892  if ( version_compare( GFFormsModel::get_database_version(), '2.3-dev-1', '<' ) ) {
893  // We need to clear the cache because Gravity Forms caches the field values, which
894  // we have just updated.
895  foreach ($this->form['fields'] as $key => $field) {
896  GFFormsModel::refresh_lead_field_value( $entry['id'], $field->id );
897  }
898  }
899 
900  $this->entry = $entry;
901  }
902 
903 
904  /**
905  * Display the Edit Entry form
906  *
907  * @return void
908  */
909  public function edit_entry_form() {
910 
911  ?>
912 
913  <div class="gv-edit-entry-wrapper"><?php
914 
915  $javascript = gravityview_ob_include( GravityView_Edit_Entry::$file .'/partials/inline-javascript.php', $this );
916 
917  /**
918  * Fixes weird wpautop() issue
919  * @see https://github.com/katzwebservices/GravityView/issues/451
920  */
921  echo gravityview_strip_whitespace( $javascript );
922 
923  ?><h2 class="gv-edit-entry-title">
924  <span><?php
925 
926  /**
927  * @filter `gravityview_edit_entry_title` Modify the edit entry title
928  * @param string $edit_entry_title Modify the "Edit Entry" title
929  * @param GravityView_Edit_Entry_Render $this This object
930  */
931  $edit_entry_title = apply_filters('gravityview_edit_entry_title', __('Edit Entry', 'gravityview'), $this );
932 
933  echo esc_attr( $edit_entry_title );
934  ?></span>
935  </h2>
936 
937  <?php $this->maybe_print_message(); ?>
938 
939  <?php // The ID of the form needs to be `gform_{form_id}` for the pluploader ?>
940 
941  <form method="post" id="gform_<?php echo $this->form_id; ?>" enctype="multipart/form-data">
942 
943  <?php
944 
945  wp_nonce_field( self::$nonce_key, self::$nonce_key );
946 
947  wp_nonce_field( self::$nonce_field, self::$nonce_field, false );
948 
949  // Print the actual form HTML
950  $this->render_edit_form();
951 
952  ?>
953  </form>
954 
955  <script>
956  gform.addFilter('gform_reset_pre_conditional_logic_field_action', function ( reset, formId, targetId, defaultValues, isInit ) {
957  return false;
958  });
959  </script>
960 
961  </div>
962 
963  <?php
964  }
965 
966  /**
967  * Display success or error message if the form has been submitted
968  *
969  * @uses GVCommon::generate_notice
970  *
971  * @since 1.16.2.2
972  *
973  * @return void
974  */
975  private function maybe_print_message() {
976 
977  if ( \GV\Utils::_POST( 'action' ) === 'update' ) {
978 
979  $back_link = remove_query_arg( array( 'page', 'view', 'edit' ) );
980 
981  if( ! $this->is_valid ){
982 
983  // Keeping this compatible with Gravity Forms.
984  $validation_message = "<div class='validation_error'>" . __('There was a problem with your submission.', 'gravityview') . " " . __('Errors have been highlighted below.', 'gravityview') . "</div>";
985  $message = apply_filters("gform_validation_message_{$this->form['id']}", apply_filters("gform_validation_message", $validation_message, $this->form), $this->form);
986 
987  echo GVCommon::generate_notice( $message , 'gv-error' );
988 
989  } else {
990  $entry_updated_message = sprintf( esc_attr__('Entry Updated. %sReturn to Entry%s', 'gravityview'), '<a href="'. esc_url( $back_link ) .'">', '</a>' );
991 
992  /**
993  * @filter `gravityview/edit_entry/success` Modify the edit entry success message (including the anchor link)
994  * @since 1.5.4
995  * @param string $entry_updated_message Existing message
996  * @param int $view_id View ID
997  * @param array $entry Gravity Forms entry array
998  * @param string $back_link URL to return to the original entry. @since 1.6
999  */
1000  $message = apply_filters( 'gravityview/edit_entry/success', $entry_updated_message , $this->view_id, $this->entry, $back_link );
1001 
1002  echo GVCommon::generate_notice( $message );
1003  }
1004 
1005  }
1006  }
1007 
1008  /**
1009  * Display the Edit Entry form in the original Gravity Forms format
1010  *
1011  * @since 1.9
1012  *
1013  * @return void
1014  */
1015  private function render_edit_form() {
1016 
1017  /**
1018  * @action `gravityview/edit-entry/render/before` Before rendering the Edit Entry form
1019  * @since 1.17
1020  * @param GravityView_Edit_Entry_Render $this
1021  */
1022  do_action( 'gravityview/edit-entry/render/before', $this );
1023 
1024  add_filter( 'gform_pre_render', array( $this, 'filter_modify_form_fields'), 5000, 3 );
1025  add_filter( 'gform_submit_button', array( $this, 'render_form_buttons') );
1026  add_filter( 'gform_disable_view_counter', '__return_true' );
1027 
1028  add_filter( 'gform_field_input', array( $this, 'verify_user_can_edit_post' ), 5, 5 );
1029  add_filter( 'gform_field_input', array( $this, 'modify_edit_field_input' ), 10, 5 );
1030 
1031  // We need to remove the fake $_GET['page'] arg to avoid rendering form as if in admin.
1032  unset( $_GET['page'] );
1033 
1034  // TODO: Verify multiple-page forms
1035 
1036  ob_start(); // Prevent PHP warnings possibly caused by prefilling list fields for conditional logic
1037 
1038  $html = GFFormDisplay::get_form( $this->form['id'], false, false, true, $this->entry );
1039 
1040  ob_get_clean();
1041 
1042  remove_filter( 'gform_pre_render', array( $this, 'filter_modify_form_fields' ), 5000 );
1043  remove_filter( 'gform_submit_button', array( $this, 'render_form_buttons' ) );
1044  remove_filter( 'gform_disable_view_counter', '__return_true' );
1045  remove_filter( 'gform_field_input', array( $this, 'verify_user_can_edit_post' ), 5 );
1046  remove_filter( 'gform_field_input', array( $this, 'modify_edit_field_input' ), 10 );
1047 
1048  echo $html;
1049 
1050  /**
1051  * @action `gravityview/edit-entry/render/after` After rendering the Edit Entry form
1052  * @since 1.17
1053  * @param GravityView_Edit_Entry_Render $this
1054  */
1055  do_action( 'gravityview/edit-entry/render/after', $this );
1056  }
1057 
1058  /**
1059  * Display the Update/Cancel/Delete buttons for the Edit Entry form
1060  * @since 1.8
1061  * @return string
1062  */
1063  public function render_form_buttons() {
1064  return gravityview_ob_include( GravityView_Edit_Entry::$file .'/partials/form-buttons.php', $this );
1065  }
1066 
1067 
1068  /**
1069  * Modify the form fields that are shown when using GFFormDisplay::get_form()
1070  *
1071  * By default, all fields will be shown. We only want the Edit Tab configured fields to be shown.
1072  *
1073  * @param array $form
1074  * @param boolean $ajax Whether in AJAX mode
1075  * @param array|string $field_values Passed parameters to the form
1076  *
1077  * @since 1.9
1078  *
1079  * @return array Modified form array
1080  */
1081  public function filter_modify_form_fields( $form, $ajax = false, $field_values = '' ) {
1082 
1083  // In case we have validated the form, use it to inject the validation results into the form render
1084  if( isset( $this->form_after_validation ) ) {
1086  } else {
1087  $form['fields'] = $this->get_configured_edit_fields( $form, $this->view_id );
1088  }
1089 
1090  $form = $this->filter_conditional_logic( $form );
1091 
1092  $form = $this->prefill_conditional_logic( $form );
1093 
1094  // for now we don't support Save and Continue feature.
1095  if( ! self::$supports_save_and_continue ) {
1096  unset( $form['save'] );
1097  }
1098 
1099  $form = $this->unselect_default_values( $form );
1100 
1101  return $form;
1102  }
1103 
1104  /**
1105  * When displaying a field, check if it's a Post Field, and if so, make sure the post exists and current user has edit rights.
1106  *
1107  * @since 1.16.2.2
1108  *
1109  * @param string $field_content Always empty. Returning not-empty overrides the input.
1110  * @param GF_Field $field
1111  * @param string|array $value If array, it's a field with multiple inputs. If string, single input.
1112  * @param int $lead_id Lead ID. Always 0 for the `gform_field_input` filter.
1113  * @param int $form_id Form ID
1114  *
1115  * @return string If error, the error message. If no error, blank string (modify_edit_field_input() runs next)
1116  */
1117  public function verify_user_can_edit_post( $field_content = '', $field, $value, $lead_id = 0, $form_id ) {
1118 
1119  if( ! GFCommon::is_post_field( $field ) ) {
1120  return $field_content;
1121  }
1122 
1123  $message = null;
1124 
1125  // First, make sure they have the capability to edit the post.
1126  if( false === current_user_can( 'edit_post', $this->entry['post_id'] ) ) {
1127 
1128  /**
1129  * @filter `gravityview/edit_entry/unsupported_post_field_text` Modify the message when someone isn't able to edit a post
1130  * @param string $message The existing "You don't have permission..." text
1131  */
1132  $message = apply_filters('gravityview/edit_entry/unsupported_post_field_text', __('You don&rsquo;t have permission to edit this post.', 'gravityview') );
1133 
1134  } elseif( null === get_post( $this->entry['post_id'] ) ) {
1135  /**
1136  * @filter `gravityview/edit_entry/no_post_text` Modify the message when someone is editing an entry attached to a post that no longer exists
1137  * @param string $message The existing "This field is not editable; the post no longer exists." text
1138  */
1139  $message = apply_filters('gravityview/edit_entry/no_post_text', __('This field is not editable; the post no longer exists.', 'gravityview' ) );
1140  }
1141 
1142  if( $message ) {
1143  $field_content = sprintf('<div class="ginput_container ginput_container_' . $field->type . '">%s</div>', wpautop( $message ) );
1144  }
1145 
1146  return $field_content;
1147  }
1148 
1149  /**
1150  *
1151  * Fill-in the saved values into the form inputs
1152  *
1153  * @param string $field_content Always empty. Returning not-empty overrides the input.
1154  * @param GF_Field $field
1155  * @param string|array $value If array, it's a field with multiple inputs. If string, single input.
1156  * @param int $lead_id Lead ID. Always 0 for the `gform_field_input` filter.
1157  * @param int $form_id Form ID
1158  *
1159  * @return mixed
1160  */
1161  public function modify_edit_field_input( $field_content = '', $field, $value, $lead_id = 0, $form_id ) {
1162 
1164 
1165  // If the form has been submitted, then we don't need to pre-fill the values,
1166  // Except for fileupload type and when a field input is overridden- run always!!
1167  if(
1168  ( $this->is_edit_entry_submission() && !in_array( $field->type, array( 'fileupload', 'post_image' ) ) )
1169  && false === ( $gv_field && is_callable( array( $gv_field, 'get_field_input' ) ) )
1170  && ! GFCommon::is_product_field( $field->type )
1171  || ! empty( $field_content )
1172  || in_array( $field->type, array( 'honeypot' ) )
1173  ) {
1174  return $field_content;
1175  }
1176 
1177  // SET SOME FIELD DEFAULTS TO PREVENT ISSUES
1178  $field->adminOnly = false; /** @see GFFormDisplay::get_counter_init_script() need to prevent adminOnly */
1179 
1180  $field_value = $this->get_field_value( $field );
1181 
1182  // Prevent any PHP warnings, like undefined index
1183  ob_start();
1184 
1185  $return = null;
1186 
1187  /** @var GravityView_Field $gv_field */
1188  if( $gv_field && is_callable( array( $gv_field, 'get_field_input' ) ) ) {
1189  $return = $gv_field->get_field_input( $this->form, $field_value, $this->entry, $field );
1190  } else {
1191  $return = $field->get_field_input( $this->form, $field_value, $this->entry );
1192  }
1193 
1194  // If there was output, it's an error
1195  $warnings = ob_get_clean();
1196 
1197  if( !empty( $warnings ) ) {
1198  gravityview()->log->error( '{warning}', array( 'warning' => $warnings, 'data' => $field_value ) );
1199  }
1200 
1201  return $return;
1202  }
1203 
1204  /**
1205  * Modify the value for the current field input
1206  *
1207  * @param GF_Field $field
1208  *
1209  * @return array|mixed|string
1210  */
1211  private function get_field_value( $field ) {
1212 
1213  /**
1214  * @filter `gravityview/edit_entry/pre_populate/override` Allow the pre-populated value to override saved value in Edit Entry form. By default, pre-populate mechanism only kicks on empty fields.
1215  * @param boolean True: override saved values; False: don't override (default)
1216  * @param $field GF_Field object Gravity Forms field object
1217  * @since 1.13
1218  */
1219  $override_saved_value = apply_filters( 'gravityview/edit_entry/pre_populate/override', false, $field );
1220 
1221  // We're dealing with multiple inputs (e.g. checkbox) but not time or date (as it doesn't store data in input IDs)
1222  if( isset( $field->inputs ) && is_array( $field->inputs ) && !in_array( $field->type, array( 'time', 'date' ) ) ) {
1223 
1224  $field_value = array();
1225 
1226  // only accept pre-populated values if the field doesn't have any choice selected.
1227  $allow_pre_populated = $field->allowsPrepopulate;
1228 
1229  foreach ( (array)$field->inputs as $input ) {
1230 
1231  $input_id = strval( $input['id'] );
1232 
1233  if ( isset( $this->entry[ $input_id ] ) && ! gv_empty( $this->entry[ $input_id ], false, false ) ) {
1234  $field_value[ $input_id ] = 'post_category' === $field->type ? GFCommon::format_post_category( $this->entry[ $input_id ], true ) : $this->entry[ $input_id ];
1235  $allow_pre_populated = false;
1236  }
1237 
1238  }
1239 
1240  $pre_value = $field->get_value_submission( array(), false );
1241 
1242  $field_value = ! $allow_pre_populated && ! ( $override_saved_value && !gv_empty( $pre_value, false, false ) ) ? $field_value : $pre_value;
1243 
1244  } else {
1245 
1246  $id = intval( $field->id );
1247 
1248  // get pre-populated value if exists
1249  $pre_value = $field->allowsPrepopulate ? GFFormsModel::get_parameter_value( $field->inputName, array(), $field ) : '';
1250 
1251  // saved field entry value (if empty, fallback to the pre-populated value, if exists)
1252  // or pre-populated value if not empty and set to override saved value
1253  $field_value = isset( $this->entry[ $id ] ) && ! gv_empty( $this->entry[ $id ], false, false ) && ! ( $override_saved_value && !gv_empty( $pre_value, false, false ) ) ? $this->entry[ $id ] : $pre_value;
1254 
1255  // in case field is post_category but inputType is select, multi-select or radio, convert value into array of category IDs.
1256  if ( 'post_category' === $field->type && !gv_empty( $field_value, false, false ) ) {
1257  $categories = array();
1258  foreach ( explode( ',', $field_value ) as $cat_string ) {
1259  $categories[] = GFCommon::format_post_category( $cat_string, true );
1260  }
1261  $field_value = 'multiselect' === $field->get_input_type() ? $categories : implode( '', $categories );
1262  }
1263 
1264  }
1265 
1266  // if value is empty get the default value if defined
1267  $field_value = $field->get_value_default_if_empty( $field_value );
1268 
1269  /**
1270  * @filter `gravityview/edit_entry/field_value` Change the value of an Edit Entry field, if needed
1271  * @since 1.11
1272  * @since 1.20 Added third param
1273  * @param mixed $field_value field value used to populate the input
1274  * @param object $field Gravity Forms field object ( Class GF_Field )
1275  * @param GravityView_Edit_Entry_Render $this Current object
1276  */
1277  $field_value = apply_filters( 'gravityview/edit_entry/field_value', $field_value, $field, $this );
1278 
1279  /**
1280  * @filter `gravityview/edit_entry/field_value_{field_type}` Change the value of an Edit Entry field for a specific field type
1281  * @since 1.17
1282  * @since 1.20 Added third param
1283  * @param mixed $field_value field value used to populate the input
1284  * @param GF_Field $field Gravity Forms field object
1285  * @param GravityView_Edit_Entry_Render $this Current object
1286  */
1287  $field_value = apply_filters( 'gravityview/edit_entry/field_value_' . $field->type , $field_value, $field, $this );
1288 
1289  return $field_value;
1290  }
1291 
1292 
1293  // ---- Entry validation
1294 
1295  /**
1296  * Add field keys that Gravity Forms expects.
1297  *
1298  * @see GFFormDisplay::validate()
1299  * @param array $form GF Form
1300  * @return array Modified GF Form
1301  */
1302  public function gform_pre_validation( $form ) {
1303 
1304  if( ! $this->verify_nonce() ) {
1305  return $form;
1306  }
1307 
1308  // Fix PHP warning regarding undefined index.
1309  foreach ( $form['fields'] as &$field) {
1310 
1311  // This is because we're doing admin form pretending to be front-end, so Gravity Forms
1312  // expects certain field array items to be set.
1313  foreach ( array( 'noDuplicates', 'adminOnly', 'inputType', 'isRequired', 'enablePrice', 'inputs', 'allowedExtensions' ) as $key ) {
1314  $field->{$key} = isset( $field->{$key} ) ? $field->{$key} : NULL;
1315  }
1316 
1317  switch( RGFormsModel::get_input_type( $field ) ) {
1318 
1319  /**
1320  * this whole fileupload hack is because in the admin, Gravity Forms simply doesn't update any fileupload field if it's empty, but it DOES in the frontend.
1321  *
1322  * What we have to do is set the value so that it doesn't get overwritten as empty on save and appears immediately in the Edit Entry screen again.
1323  *
1324  * @hack
1325  */
1326  case 'fileupload':
1327 
1328  // Set the previous value
1329  $entry = $this->get_entry();
1330 
1331  $input_name = 'input_'.$field->id;
1332  $form_id = $form['id'];
1333 
1334  $value = NULL;
1335 
1336  // Use the previous entry value as the default.
1337  if( isset( $entry[ $field->id ] ) ) {
1338  $value = $entry[ $field->id ];
1339  }
1340 
1341  // If this is a single upload file
1342  if( !empty( $_FILES[ $input_name ] ) && !empty( $_FILES[ $input_name ]['name'] ) ) {
1343  $file_path = GFFormsModel::get_file_upload_path( $form['id'], $_FILES[ $input_name ]['name'] );
1344  $value = $file_path['url'];
1345 
1346  } else {
1347 
1348  // Fix PHP warning on line 1498 of form_display.php for post_image fields
1349  // Fix PHP Notice: Undefined index: size in form_display.php on line 1511
1350  $_FILES[ $input_name ] = array('name' => '', 'size' => '' );
1351 
1352  }
1353 
1354  if ( \GV\Utils::get( $field, "multipleFiles" ) ) {
1355 
1356  // If there are fresh uploads, process and merge them.
1357  // Otherwise, use the passed values, which should be json-encoded array of URLs
1358  if( isset( GFFormsModel::$uploaded_files[$form_id][$input_name] ) ) {
1359  $value = empty( $value ) ? '[]' : $value;
1360  $value = stripslashes_deep( $value );
1361  $value = GFFormsModel::prepare_value( $form, $field, $value, $input_name, $entry['id'], array());
1362  }
1363 
1364  } else {
1365 
1366  // A file already exists when editing an entry
1367  // We set this to solve issue when file upload fields are required.
1368  GFFormsModel::$uploaded_files[ $form_id ][ $input_name ] = $value;
1369 
1370  }
1371 
1372  $this->entry[ $input_name ] = $value;
1373  $_POST[ $input_name ] = $value;
1374 
1375  break;
1376 
1377  case 'number':
1378  // Fix "undefined index" issue at line 1286 in form_display.php
1379  if( !isset( $_POST['input_'.$field->id ] ) ) {
1380  $_POST['input_'.$field->id ] = NULL;
1381  }
1382  break;
1383  }
1384 
1385  }
1386 
1387  return $form;
1388  }
1389 
1390 
1391  /**
1392  * Process validation for a edit entry submission
1393  *
1394  * Sets the `is_valid` object var
1395  *
1396  * @return void
1397  */
1398  private function validate() {
1399 
1400  /**
1401  * If using GF User Registration Add-on, remove the validation step, otherwise generates error when updating the entry
1402  * GF User Registration Add-on version > 3.x has a different class name
1403  * @since 1.16.2
1404  */
1405  if ( class_exists( 'GF_User_Registration' ) ) {
1406  remove_filter( 'gform_validation', array( GF_User_Registration::get_instance(), 'validate' ) );
1407  } else if ( class_exists( 'GFUser' ) ) {
1408  remove_filter( 'gform_validation', array( 'GFUser', 'user_registration_validation' ) );
1409  }
1410 
1411 
1412  /**
1413  * For some crazy reason, Gravity Forms doesn't validate Edit Entry form submissions.
1414  * You can enter whatever you want!
1415  * We try validating, and customize the results using `self::custom_validation()`
1416  */
1417  add_filter( 'gform_validation_'. $this->form_id, array( $this, 'custom_validation' ), 10, 4);
1418 
1419  // Needed by the validate funtion
1420  $failed_validation_page = NULL;
1421  $field_values = RGForms::post( 'gform_field_values' );
1422 
1423  // Prevent entry limit from running when editing an entry, also
1424  // prevent form scheduling from preventing editing
1425  unset( $this->form['limitEntries'], $this->form['scheduleForm'] );
1426 
1427  // Hide fields depending on Edit Entry settings
1428  $this->form['fields'] = $this->get_configured_edit_fields( $this->form, $this->view_id );
1429 
1430  $this->is_valid = GFFormDisplay::validate( $this->form, $field_values, 1, $failed_validation_page );
1431 
1432  remove_filter( 'gform_validation_'. $this->form_id, array( $this, 'custom_validation' ), 10 );
1433  }
1434 
1435 
1436  /**
1437  * Make validation work for Edit Entry
1438  *
1439  * Because we're calling the GFFormDisplay::validate() in an unusual way (as a front-end
1440  * form pretending to be a back-end form), validate() doesn't know we _can't_ edit post
1441  * fields. This goes through all the fields and if they're an invalid post field, we
1442  * set them as valid. If there are still issues, we'll return false.
1443  *
1444  * @param [type] $validation_results [description]
1445  * @return [type] [description]
1446  */
1447  public function custom_validation( $validation_results ) {
1448 
1449  gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Validation results: ', array( 'data' => $validation_results ) );
1450 
1451  gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] $_POSTed data (sanitized): ', array( 'data' => esc_html( print_r( $_POST, true ) ) ) );
1452 
1453  $gv_valid = true;
1454 
1455  foreach ( $validation_results['form']['fields'] as $key => &$field ) {
1456 
1457  $value = RGFormsModel::get_field_value( $field );
1458  $field_type = RGFormsModel::get_input_type( $field );
1459 
1460  // Validate always
1461  switch ( $field_type ) {
1462 
1463 
1464  case 'fileupload' :
1465  case 'post_image':
1466 
1467  // in case nothing is uploaded but there are already files saved
1468  if( !empty( $field->failed_validation ) && !empty( $field->isRequired ) && !empty( $value ) ) {
1469  $field->failed_validation = false;
1470  unset( $field->validation_message );
1471  }
1472 
1473  // validate if multi file upload reached max number of files [maxFiles] => 2
1474  if( \GV\Utils::get( $field, 'maxFiles') && \GV\Utils::get( $field, 'multipleFiles') ) {
1475 
1476  $input_name = 'input_' . $field->id;
1477  //uploaded
1478  $file_names = isset( GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ][ $input_name ] ) ? GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ][ $input_name ] : array();
1479 
1480  //existent
1481  $entry = $this->get_entry();
1482  $value = NULL;
1483  if( isset( $entry[ $field->id ] ) ) {
1484  $value = json_decode( $entry[ $field->id ], true );
1485  }
1486 
1487  // count uploaded files and existent entry files
1488  $count_files = count( $file_names ) + count( $value );
1489 
1490  if( $count_files > $field->maxFiles ) {
1491  $field->validation_message = __( 'Maximum number of files reached', 'gravityview' );
1492  $field->failed_validation = 1;
1493  $gv_valid = false;
1494 
1495  // in case of error make sure the newest upload files are removed from the upload input
1496  GFFormsModel::$uploaded_files[ $validation_results['form']['id'] ] = null;
1497  }
1498 
1499  }
1500 
1501 
1502  break;
1503 
1504  }
1505 
1506  // This field has failed validation.
1507  if( !empty( $field->failed_validation ) ) {
1508 
1509  gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Field is invalid.', array( 'data' => array( 'field' => $field, 'value' => $value ) ) );
1510 
1511  switch ( $field_type ) {
1512 
1513  // Captchas don't need to be re-entered.
1514  case 'captcha':
1515 
1516  // Post Image fields aren't editable, so we un-fail them.
1517  case 'post_image':
1518  $field->failed_validation = false;
1519  unset( $field->validation_message );
1520  break;
1521 
1522  }
1523 
1524  // You can't continue inside a switch, so we do it after.
1525  if( empty( $field->failed_validation ) ) {
1526  continue;
1527  }
1528 
1529  // checks if the No Duplicates option is not validating entry against itself, since
1530  // we're editing a stored entry, it would also assume it's a duplicate.
1531  if( !empty( $field->noDuplicates ) ) {
1532 
1533  $entry = $this->get_entry();
1534 
1535  // If the value of the entry is the same as the stored value
1536  // Then we can assume it's not a duplicate, it's the same.
1537  if( !empty( $entry ) && $value == $entry[ $field->id ] ) {
1538  //if value submitted was not changed, then don't validate
1539  $field->failed_validation = false;
1540 
1541  unset( $field->validation_message );
1542 
1543  gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Field not a duplicate; it is the same entry.', array( 'data' => $entry ) );
1544 
1545  continue;
1546  }
1547  }
1548 
1549  // if here then probably we are facing the validation 'At least one field must be filled out'
1550  if( GFFormDisplay::is_empty( $field, $this->form_id ) && empty( $field->isRequired ) ) {
1551  unset( $field->validation_message );
1552  $field->validation_message = false;
1553  continue;
1554  }
1555 
1556  $gv_valid = false;
1557 
1558  }
1559 
1560  }
1561 
1562  $validation_results['is_valid'] = $gv_valid;
1563 
1564  gravityview()->log->debug( 'GravityView_Edit_Entry[custom_validation] Validation results.', array( 'data' => $validation_results ) );
1565 
1566  // We'll need this result when rendering the form ( on GFFormDisplay::get_form )
1567  $this->form_after_validation = $validation_results['form'];
1568 
1569  return $validation_results;
1570  }
1571 
1572 
1573  /**
1574  * TODO: This seems to be hacky... we should remove it. Entry is set when updating the form using setup_vars()!
1575  * Get the current entry and set it if it's not yet set.
1576  * @return array Gravity Forms entry array
1577  */
1578  public function get_entry() {
1579 
1580  if( empty( $this->entry ) ) {
1581  // Get the database value of the entry that's being edited
1583  }
1584 
1585  return $this->entry;
1586  }
1587 
1588 
1589 
1590  // --- Filters
1591 
1592  /**
1593  * Get the Edit Entry fields as configured in the View
1594  *
1595  * @since 1.8
1596  *
1597  * @param int $view_id
1598  *
1599  * @return array Array of fields that are configured in the Edit tab in the Admin
1600  */
1602 
1603  // Get all fields for form
1604  if ( \GV\View::exists( $view_id ) ) {
1605  $view = \GV\View::by_id( $view_id );
1606  $properties = $view->fields ? $view->fields->as_configuration() : array();
1607  } else {
1608  $properties = null;
1609  }
1610 
1611  // If edit tab not yet configured, show all fields
1612  $edit_fields = !empty( $properties['edit_edit-fields'] ) ? $properties['edit_edit-fields'] : NULL;
1613 
1614  // Hide fields depending on admin settings
1615  $fields = $this->filter_fields( $form['fields'], $edit_fields );
1616 
1617  // If Edit Entry fields are configured, remove adminOnly field settings. Otherwise, don't.
1618  $fields = $this->filter_admin_only_fields( $fields, $edit_fields, $form, $view_id );
1619 
1620  /**
1621  * @filter `gravityview/edit_entry/form_fields` Modify the fields displayed in Edit Entry form
1622  * @since 1.17
1623  * @param GF_Field[] $fields Gravity Forms form fields
1624  * @param array|null $edit_fields Fields for the Edit Entry tab configured in the View Configuration
1625  * @param array $form GF Form array (`fields` key modified to have only fields configured to show in Edit Entry)
1626  * @param int $view_id View ID
1627  */
1628  $fields = apply_filters( 'gravityview/edit_entry/form_fields', $fields, $edit_fields, $form, $view_id );
1629 
1630  return $fields;
1631  }
1632 
1633 
1634  /**
1635  * Filter area fields based on specified conditions
1636  * - This filter removes the fields that have calculation configured
1637  *
1638  * @uses GravityView_Edit_Entry::user_can_edit_field() Check caps
1639  * @access private
1640  * @param GF_Field[] $fields
1641  * @param array $configured_fields
1642  * @since 1.5
1643  * @return array $fields
1644  */
1645  private function filter_fields( $fields, $configured_fields ) {
1646 
1647  if( empty( $fields ) || !is_array( $fields ) ) {
1648  return $fields;
1649  }
1650 
1651  $edit_fields = array();
1652 
1653  $field_type_blacklist = $this->loader->get_field_blacklist( $this->entry );
1654 
1655  // First, remove blacklist or calculation fields
1656  foreach ( $fields as $key => $field ) {
1657 
1658  // Remove the fields that have calculation properties and keep them to be used later
1659  // @since 1.16.2
1660  if( $field->has_calculation() ) {
1661  $this->fields_with_calculation[] = $field;
1662  // don't remove the calculation fields on form render.
1663  }
1664 
1665  if( in_array( $field->type, $field_type_blacklist ) ) {
1666  unset( $fields[ $key ] );
1667  }
1668  }
1669 
1670  // The Edit tab has not been configured, so we return all fields by default.
1671  if( empty( $configured_fields ) ) {
1672  return array_values( $fields );
1673  }
1674 
1675  // The edit tab has been configured, so we loop through to configured settings
1676  foreach ( $configured_fields as $configured_field ) {
1677 
1678  /** @var GF_Field $field */
1679  foreach ( $fields as $field ) {
1680  if( intval( $configured_field['id'] ) === intval( $field->id ) && $this->user_can_edit_field( $configured_field, false ) ) {
1681  $edit_fields[] = $this->merge_field_properties( $field, $configured_field );
1682  break;
1683  }
1684 
1685  }
1686 
1687  }
1688 
1689  return $edit_fields;
1690 
1691  }
1692 
1693  /**
1694  * Override GF Form field properties with the ones defined on the View
1695  * @param GF_Field $field GF Form field object
1696  * @param array $field_setting GV field options
1697  * @since 1.5
1698  * @return array|GF_Field
1699  */
1700  private function merge_field_properties( $field, $field_setting ) {
1701 
1702  $return_field = $field;
1703 
1704  if( empty( $field_setting['show_label'] ) ) {
1705  $return_field->label = '';
1706  } elseif ( !empty( $field_setting['custom_label'] ) ) {
1707  $return_field->label = $field_setting['custom_label'];
1708  }
1709 
1710  if( !empty( $field_setting['custom_class'] ) ) {
1711  $return_field->cssClass .= ' '. gravityview_sanitize_html_class( $field_setting['custom_class'] );
1712  }
1713 
1714  /**
1715  * Normalize page numbers - avoid conflicts with page validation
1716  * @since 1.6
1717  */
1718  $return_field->pageNumber = 1;
1719 
1720  return $return_field;
1721 
1722  }
1723 
1724  /**
1725  * Remove fields that shouldn't be visible based on the Gravity Forms adminOnly field property
1726  *
1727  * @since 1.9.1
1728  *
1729  * @param array|GF_Field[] $fields Gravity Forms form fields
1730  * @param array|null $edit_fields Fields for the Edit Entry tab configured in the View Configuration
1731  * @param array $form GF Form array
1732  * @param int $view_id View ID
1733  *
1734  * @return array Possibly modified form array
1735  */
1736  private function filter_admin_only_fields( $fields = array(), $edit_fields = null, $form = array(), $view_id = 0 ) {
1737 
1738  /**
1739  * @filter `gravityview/edit_entry/use_gf_admin_only_setting` When Edit tab isn't configured, should the Gravity Forms "Admin Only" field settings be used to control field display to non-admins? Default: true
1740  * If the Edit Entry tab is not configured, adminOnly fields will not be shown to non-administrators.
1741  * If the Edit Entry tab *is* configured, adminOnly fields will be shown to non-administrators, using the configured GV permissions
1742  * @since 1.9.1
1743  * @param boolean $use_gf_adminonly_setting True: Hide field if set to Admin Only in GF and the user is not an admin. False: show field based on GV permissions, ignoring GF permissions.
1744  * @param array $form GF Form array
1745  * @param int $view_id View ID
1746  */
1747  $use_gf_adminonly_setting = apply_filters( 'gravityview/edit_entry/use_gf_admin_only_setting', empty( $edit_fields ), $form, $view_id );
1748 
1749  if( $use_gf_adminonly_setting && false === GVCommon::has_cap( 'gravityforms_edit_entries', $this->entry['id'] ) ) {
1750  foreach( $fields as $k => $field ) {
1751  if( $field->adminOnly ) {
1752  unset( $fields[ $k ] );
1753  }
1754  }
1755  return array_values( $fields );
1756  }
1757 
1758  foreach( $fields as &$field ) {
1759  $field->adminOnly = false;
1760  }
1761 
1762  return $fields;
1763  }
1764 
1765  /**
1766  * Checkboxes and other checkbox-based controls should not
1767  * display default checks in edit mode.
1768  *
1769  * https://github.com/gravityview/GravityView/1149
1770  *
1771  * @since 2.1
1772  *
1773  * @param array $form Gravity Forms array object
1774  *
1775  * @return array $form, modified to default checkboxes, radios from showing up.
1776  */
1777  private function unselect_default_values( $form ) {
1778 
1779  foreach ( $form['fields'] as &$field ) {
1780 
1781  if ( empty( $field->choices ) ) {
1782  continue;
1783  }
1784 
1785  foreach ( $field->choices as &$choice ) {
1786  if ( \GV\Utils::get( $choice, 'isSelected' ) ) {
1787  $choice['isSelected'] = false;
1788  }
1789  }
1790  }
1791 
1792  return $form;
1793  }
1794 
1795  // --- Conditional Logic
1796 
1797  /**
1798  * Conditional logic isn't designed to work with forms that already have content. When switching input values,
1799  * the dependent fields will be blank.
1800  *
1801  * Note: This is because GF populates a JavaScript variable with the input values. This is tough to filter at the input level;
1802  * via the `gform_field_value` filter; it requires lots of legwork. Doing it at the form level is easier.
1803  *
1804  * @since 1.17.4
1805  *
1806  * @param array $form Gravity Forms array object
1807  *
1808  * @return array $form, modified to fix conditional
1809  */
1810  function prefill_conditional_logic( $form ) {
1811 
1812  if( ! GFFormDisplay::has_conditional_logic( $form ) ) {
1813  return $form;
1814  }
1815 
1816  // Have Conditional Logic pre-fill fields as if the data were default values
1817  /** @var GF_Field $field */
1818  foreach ( $form['fields'] as &$field ) {
1819 
1820  if( 'checkbox' === $field->type ) {
1821  foreach ( $field->get_entry_inputs() as $key => $input ) {
1822  $input_id = $input['id'];
1823  $choice = $field->choices[ $key ];
1824  $value = \GV\Utils::get( $this->entry, $input_id );
1825  $match = RGFormsModel::choice_value_match( $field, $choice, $value );
1826  if( $match ) {
1827  $field->choices[ $key ]['isSelected'] = true;
1828  }
1829  }
1830  } else {
1831 
1832  // We need to run through each field to set the default values
1833  foreach ( $this->entry as $field_id => $field_value ) {
1834 
1835  if( floatval( $field_id ) === floatval( $field->id ) ) {
1836 
1837  if( 'list' === $field->type ) {
1838  $list_rows = maybe_unserialize( $field_value );
1839 
1840  $list_field_value = array();
1841  foreach ( (array) $list_rows as $row ) {
1842  foreach ( (array) $row as $column ) {
1843  $list_field_value[] = $column;
1844  }
1845  }
1846 
1847  $field->defaultValue = serialize( $list_field_value );
1848  } else {
1849  $field->defaultValue = $field_value;
1850  }
1851  }
1852  }
1853  }
1854  }
1855 
1856  return $form;
1857  }
1858 
1859  /**
1860  * Remove the conditional logic rules from the form button and the form fields, if needed.
1861  *
1862  * @todo Merge with caller method
1863  * @since 1.9
1864  *
1865  * @param array $form Gravity Forms form
1866  * @return array Modified form, if not using Conditional Logic
1867  */
1868  private function filter_conditional_logic( $form ) {
1869 
1870  /**
1871  * @filter `gravityview/edit_entry/conditional_logic` Should the Edit Entry form use Gravity Forms conditional logic showing/hiding of fields?
1872  * @since 1.9
1873  * @param bool $use_conditional_logic True: Gravity Forms will show/hide fields just like in the original form; False: conditional logic will be disabled and fields will be shown based on configuration. Default: true
1874  * @param array $form Gravity Forms form
1875  */
1876  $use_conditional_logic = apply_filters( 'gravityview/edit_entry/conditional_logic', true, $form );
1877 
1878  if( $use_conditional_logic ) {
1879  return $form;
1880  }
1881 
1882  foreach( $form['fields'] as &$field ) {
1883  /* @var GF_Field $field */
1884  $field->conditionalLogic = null;
1885  }
1886 
1887  unset( $form['button']['conditionalLogic'] );
1888 
1889  return $form;
1890 
1891  }
1892 
1893  /**
1894  * Disable the Gravity Forms conditional logic script and features on the Edit Entry screen
1895  *
1896  * @since 1.9
1897  *
1898  * @param $has_conditional_logic
1899  * @param $form
1900  * @return mixed
1901  */
1902  public function manage_conditional_logic( $has_conditional_logic, $form ) {
1903 
1904  if( ! $this->is_edit_entry() ) {
1905  return $has_conditional_logic;
1906  }
1907 
1908  /** @see GravityView_Edit_Entry_Render::filter_conditional_logic for filter documentation */
1909  return apply_filters( 'gravityview/edit_entry/conditional_logic', $has_conditional_logic, $form );
1910  }
1911 
1912 
1913  // --- User checks and nonces
1914 
1915  /**
1916  * Check if the user can edit the entry
1917  *
1918  * - Is the nonce valid?
1919  * - Does the user have the right caps for the entry
1920  * - Is the entry in the trash?
1921  *
1922  * @todo Move to GVCommon
1923  *
1924  * @param boolean $echo Show error messages in the form?
1925  * @return boolean True: can edit form. False: nope.
1926  */
1927  private function user_can_edit_entry( $echo = false ) {
1928 
1929  $error = NULL;
1930 
1931  /**
1932  * 1. Permalinks are turned off
1933  * 2. There are two entries embedded using oEmbed
1934  * 3. One of the entries has just been saved
1935  */
1936  if( !empty( $_POST['lid'] ) && !empty( $_GET['entry'] ) && ( $_POST['lid'] !== $_GET['entry'] ) ) {
1937 
1938  $error = true;
1939 
1940  }
1941 
1942  if( !empty( $_GET['entry'] ) && (string)$this->entry['id'] !== $_GET['entry'] ) {
1943 
1944  $error = true;
1945 
1946  } elseif( ! $this->verify_nonce() ) {
1947 
1948  /**
1949  * If the Entry is embedded, there may be two entries on the same page.
1950  * If that's the case, and one is being edited, the other should fail gracefully and not display an error.
1951  */
1952  if( GravityView_oEmbed::getInstance()->get_entry_id() ) {
1953  $error = true;
1954  } else {
1955  $error = __( 'The link to edit this entry is not valid; it may have expired.', 'gravityview');
1956  }
1957 
1958  }
1959 
1960  if( ! GravityView_Edit_Entry::check_user_cap_edit_entry( $this->entry ) ) {
1961  $error = __( 'You do not have permission to edit this entry.', 'gravityview');
1962  }
1963 
1964  if( $this->entry['status'] === 'trash' ) {
1965  $error = __('You cannot edit the entry; it is in the trash.', 'gravityview' );
1966  }
1967 
1968  // No errors; everything's fine here!
1969  if( empty( $error ) ) {
1970  return true;
1971  }
1972 
1973  if( $echo && $error !== true ) {
1974 
1975  $error = esc_html( $error );
1976 
1977  /**
1978  * @since 1.9
1979  */
1980  if ( ! empty( $this->entry ) ) {
1981  $error .= ' ' . gravityview_get_link( '#', _x('Go back.', 'Link shown when invalid Edit Entry link is clicked', 'gravityview' ), array( 'onclick' => "window.history.go(-1); return false;" ) );
1982  }
1983 
1984  echo GVCommon::generate_notice( wpautop( $error ), 'gv-error error');
1985  }
1986 
1987  gravityview()->log->error( '{error}', array( 'error' => $error ) );
1988 
1989  return false;
1990  }
1991 
1992 
1993  /**
1994  * Check whether a field is editable by the current user, and optionally display an error message
1995  * @uses GravityView_Edit_Entry->check_user_cap_edit_field() Check user capabilities
1996  * @param array $field Field or field settings array
1997  * @param boolean $echo Whether to show error message telling user they aren't allowed
1998  * @return boolean True: user can edit the current field; False: nope, they can't.
1999  */
2000  private function user_can_edit_field( $field, $echo = false ) {
2001 
2002  $error = NULL;
2003 
2004  if( ! $this->check_user_cap_edit_field( $field ) ) {
2005  $error = __( 'You do not have permission to edit this field.', 'gravityview');
2006  }
2007 
2008  // No errors; everything's fine here!
2009  if( empty( $error ) ) {
2010  return true;
2011  }
2012 
2013  if( $echo ) {
2014  echo GVCommon::generate_notice( wpautop( esc_html( $error ) ), 'gv-error error');
2015  }
2016 
2017  gravityview()->log->error( '{error}', array( 'error' => $error ) );
2018 
2019  return false;
2020 
2021  }
2022 
2023 
2024  /**
2025  * checks if user has permissions to edit a specific field
2026  *
2027  * Needs to be used combined with GravityView_Edit_Entry::user_can_edit_field for maximum security!!
2028  *
2029  * @param [type] $field [description]
2030  * @return bool
2031  */
2032  private function check_user_cap_edit_field( $field ) {
2033 
2034  // If they can edit any entries (as defined in Gravity Forms), we're good.
2035  if( GVCommon::has_cap( array( 'gravityforms_edit_entries', 'gravityview_edit_others_entries' ) ) ) {
2036  return true;
2037  }
2038 
2039  $field_cap = isset( $field['allow_edit_cap'] ) ? $field['allow_edit_cap'] : false;
2040 
2041  if( $field_cap ) {
2042  return GVCommon::has_cap( $field['allow_edit_cap'] );
2043  }
2044 
2045  return false;
2046  }
2047 
2048 
2049  /**
2050  * Is the current nonce valid for editing the entry?
2051  * @return boolean
2052  */
2053  public function verify_nonce() {
2054 
2055  // Verify form submitted for editing single
2056  if( $this->is_edit_entry_submission() ) {
2057  $valid = wp_verify_nonce( $_POST[ self::$nonce_field ], self::$nonce_field );
2058  }
2059 
2060  // Verify
2061  else if( ! $this->is_edit_entry() ) {
2062  $valid = false;
2063  }
2064 
2065  else {
2066  $valid = wp_verify_nonce( $_GET['edit'], self::$nonce_key );
2067  }
2068 
2069  /**
2070  * @filter `gravityview/edit_entry/verify_nonce` Override Edit Entry nonce validation. Return true to declare nonce valid.
2071  * @since 1.13
2072  * @param int|boolean $valid False if invalid; 1 or 2 when nonce was generated
2073  * @param string $nonce_field Key used when validating submissions. Default: is_gv_edit_entry
2074  */
2075  $valid = apply_filters( 'gravityview/edit_entry/verify_nonce', $valid, self::$nonce_field );
2076 
2077  return $valid;
2078  }
2079 
2080 
2081  /**
2082  * Multiselect in GF 2.2 became a json_encoded value. Fix it.
2083  *
2084  * As a hack for now we'll implode it back.
2085  */
2087  if ( empty ( $field->storageType ) || $field->storageType != 'json' ) {
2088  return $field_value;
2089  }
2090 
2091  $maybe_json = @json_decode( $field_value, true );
2092 
2093  if ( $maybe_json ) {
2094  return implode( ',', $maybe_json );
2095  }
2096 
2097  return $field_value;
2098  }
2099 
2100 
2101 
2102 } //end class
get_configured_edit_fields( $form, $view_id)
Get the Edit Entry fields as configured in the View.
const GRAVITYVIEW_DIR
"GRAVITYVIEW_DIR" "./" The absolute path to the plugin directory, with trailing slash ...
Definition: gravityview.php:40
update_quiz_fields()
Make sure the quiz is updated accordingly.
$entry
static media_handle_upload( $url, $post_id, $post_data=array())
Copied function from Gravity Forms plugin ::media_handle_upload since the method is private...
static getInstance( $passed_post=NULL)
edit_entry_form()
Display the Edit Entry form.
$fields_with_calculation
$image_meta
Definition: post_image.php:106
static getInstance( $passed_post=NULL)
Definition: class-data.php:120
fill_post_template( $template, $form, $entry, $do_shortcode=false)
Convert a field content template into prepared output.
gravityview_get_entry( $entry_slug, $force_allow_ids=false, $check_entry_display=true)
Return a single entry object.
if(! function_exists( 'gravityview_sanitize_html_class')) gravityview_strip_whitespace( $string)
Replace multiple newlines, tabs, and spaces with a single space.
$back_link
load()
update_calculation_fields()
$is_valid
filter_conditional_logic( $form)
Remove the conditional logic rules from the form button and the form fields, if needed.
is_edit_entry()
Is the current page an Edit Entry page?
static check_user_cap_edit_entry( $entry, $view_id=0)
checks if user has permissions to edit a specific entry
static get_post_field_images( $form, $entry)
Given information provided in an entry, get array of media IDs.
$ary
Definition: post_image.php:24
is_field_json_encoded( $field)
Is the field stored in a JSON-encoded manner?
render_edit_form()
Display the Edit Entry form in the original Gravity Forms format.
static generate_notice( $notice, $class='', $cap='', $object_id=null)
Display updated/error notice.
process_save_process_files( $form_id)
Have GF handle file uploads.
$entries
gravityview_get_link( $href='', $anchor_text='', $atts=array())
Generate an HTML anchor tag with a list of supported attributes.
save_field_value( $value='', $entry=array(), $field=null, $form=array(), $input_id='')
Make sure the fileuploads are not overwritten if no such request was done.
after_update()
Perform actions normally performed after updating a lead.
gravityview()
Definition: _stubs.php:26
static $nonce_field
get( $key, $default=null)
Retrieve a setting.
maybe_print_message()
Display success or error message if the form has been submitted.
setup_vars()
When Edit entry view is requested setup the vars.
unset_hidden_field_values()
Delete the value of fields hidden by conditional logic when the entry is edited.
gravityview_ob_include( $file_path, $object=NULL)
Get the contents of a file using include() and ob_start()
$view_id
gform_pre_validation( $form)
Add field keys that Gravity Forms expects.
update_post_image( $form, $field, $field_id, $value, $entry, $post_id)
Handle updating the Post Image field.
static $nonce_key
process_save( $gv_data)
Process edit entry form save.
print_scripts()
Force Gravity Forms to output scripts as if it were in the admin.
manage_conditional_logic( $has_conditional_logic, $form)
Disable the Gravity Forms conditional logic script and features on the Edit Entry screen...
$form_id
check_user_cap_edit_field( $field)
checks if user has permissions to edit a specific field
$gv_field
Definition: time.php:11
__construct(GravityView_Edit_Entry $loader)
static get_associated_field( $gf_field)
Alias for get_instance()
user_can_edit_field( $field, $echo=false)
Check whether a field is editable by the current user, and optionally display an error message Gravi...
static by_id( $post_id)
Construct a instance from a post ID.
static get_nonce_key( $view_id, $form_id, $entry_id)
Return a well formatted nonce key according to GravityView Edit Entry protocol.
static $original_form
merge_field_properties( $field, $field_setting)
Override GF Form field properties with the ones defined on the View.
prevent_maybe_process_form()
Because we&#39;re mimicking being a front-end Gravity Forms form while using a Gravity Forms backend form...
static $file
get_field_value( $field)
Modify the value for the current field input.
init( $gv_data=null)
Load required files and trigger edit flow.
modify_fileupload_settings( $plupload_init, $form_id, $instance)
Remove max_files validation (done on gravityforms.js) to avoid conflicts with GravityView Late valida...
static is_single_entry()
Verify if user requested a single entry view.
$field_id
Definition: time.php:17
static $original_entry
static $supports_save_and_continue
validate()
Process validation for a edit entry submission.
verify_nonce()
Is the current nonce valid for editing the entry?
get_entry()
TODO: This seems to be hacky...
$template
The entry loop for the list output.
render_form_buttons()
Display the Update/Cancel/Delete buttons for the Edit Entry form.
filter_modify_form_fields( $form, $ajax=false, $field_values='')
Modify the form fields that are shown when using GFFormDisplay::get_form()
static get( $array, $key, $default=null)
Grab a value from an array or an object or default.
global $post
is_edit_entry_submission()
Is the current page an Edit Entry page?
static get_database_version()
Make sure the method exists, regardless of GF version.
$form_after_validation
gv_empty( $value, $zero_is_empty=true, $allow_string_booleans=true)
Is the value empty?
$post_id
static has_cap( $caps='', $object_id=null, $user_id=null)
Alias of GravityView_Roles_Capabilities::has_cap()
maybe_update_post_fields( $form)
Loop through the fields being edited and if they include Post fields, update the Entry&#39;s post object...
$loader
user_can_edit_entry( $echo=false)
Check if the user can edit the entry.
$form
verify_user_can_edit_post( $field_content='', $field, $value, $lead_id=0, $form_id)
When displaying a field, check if it&#39;s a Post Field, and if so, make sure the post exists and current...
custom_validation( $validation_results)
Make validation work for Edit Entry.
fix_multiselect_value_serialization( $field_value, $field, $_this)
Multiselect in GF 2.2 became a json_encoded value.
filter_admin_only_fields( $fields=array(), $edit_fields=null, $form=array(), $view_id=0)
Remove fields that shouldn&#39;t be visible based on the Gravity Forms adminOnly field property...
prevent_render_form()
Don&#39;t show any forms embedded on a page when GravityView is in Edit Entry mode.
$field_value
Definition: checkbox.php:24
$field
Definition: gquiz_grade.php:11
unselect_default_values( $form)
Checkboxes and other checkbox-based controls should not display default checks in edit mode...